From d46bca6db0bd3d6e018eac89f18c2b24238677fe Mon Sep 17 00:00:00 2001 From: gornekich Date: Thu, 23 Mar 2023 16:40:11 +0400 Subject: [PATCH 001/149] nfc: rename structure in old application --- applications/main/application.fam | 20 ++++---- applications/main/nfc/nfc.h | 3 -- applications/main/nfc/{nfc.c => nfc_app.c} | 34 +++++++------- applications/main/nfc/nfc_app.h | 3 ++ .../main/nfc/{nfc_i.h => nfc_app_i.h} | 20 ++++---- applications/main/nfc/nfc_cli.c | 46 +++++++++++++++++++ .../main/nfc/scenes/nfc_scene_debug.c | 10 ++-- .../main/nfc/scenes/nfc_scene_delete.c | 10 ++-- .../nfc/scenes/nfc_scene_delete_success.c | 10 ++-- .../main/nfc/scenes/nfc_scene_detect_reader.c | 12 ++--- .../main/nfc/scenes/nfc_scene_device_info.c | 10 ++-- .../nfc/scenes/nfc_scene_dict_not_found.c | 10 ++-- .../scenes/nfc_scene_emulate_apdu_sequence.c | 6 +-- .../main/nfc/scenes/nfc_scene_emulate_uid.c | 16 +++---- .../main/nfc/scenes/nfc_scene_emv_menu.c | 10 ++-- .../nfc/scenes/nfc_scene_emv_read_success.c | 10 ++-- .../main/nfc/scenes/nfc_scene_exit_confirm.c | 10 ++-- .../main/nfc/scenes/nfc_scene_extra_actions.c | 10 ++-- .../main/nfc/scenes/nfc_scene_field.c | 6 +-- .../main/nfc/scenes/nfc_scene_file_select.c | 4 +- .../main/nfc/scenes/nfc_scene_generate_info.c | 10 ++-- .../nfc/scenes/nfc_scene_mf_classic_data.c | 6 +-- .../scenes/nfc_scene_mf_classic_dict_attack.c | 16 +++---- .../nfc/scenes/nfc_scene_mf_classic_emulate.c | 10 ++-- .../nfc/scenes/nfc_scene_mf_classic_keys.c | 10 ++-- .../scenes/nfc_scene_mf_classic_keys_add.c | 10 ++-- .../scenes/nfc_scene_mf_classic_keys_delete.c | 10 ++-- .../scenes/nfc_scene_mf_classic_keys_list.c | 14 +++--- ...nfc_scene_mf_classic_keys_warn_duplicate.c | 10 ++-- .../nfc/scenes/nfc_scene_mf_classic_menu.c | 10 ++-- .../nfc_scene_mf_classic_read_success.c | 10 ++-- .../nfc/scenes/nfc_scene_mf_classic_update.c | 12 ++--- .../nfc_scene_mf_classic_update_success.c | 10 ++-- .../nfc/scenes/nfc_scene_mf_classic_write.c | 12 ++--- .../scenes/nfc_scene_mf_classic_write_fail.c | 10 ++-- .../nfc_scene_mf_classic_write_success.c | 10 ++-- .../scenes/nfc_scene_mf_classic_wrong_card.c | 10 ++-- .../nfc/scenes/nfc_scene_mf_desfire_app.c | 14 +++--- .../nfc/scenes/nfc_scene_mf_desfire_data.c | 10 ++-- .../nfc/scenes/nfc_scene_mf_desfire_menu.c | 10 ++-- .../nfc_scene_mf_desfire_read_success.c | 10 ++-- .../nfc/scenes/nfc_scene_mf_ultralight_data.c | 6 +-- .../scenes/nfc_scene_mf_ultralight_emulate.c | 10 ++-- .../nfc_scene_mf_ultralight_key_input.c | 10 ++-- .../nfc/scenes/nfc_scene_mf_ultralight_menu.c | 10 ++-- .../nfc_scene_mf_ultralight_read_auth.c | 12 ++--- ...nfc_scene_mf_ultralight_read_auth_result.c | 10 ++-- .../nfc_scene_mf_ultralight_read_success.c | 10 ++-- .../nfc_scene_mf_ultralight_unlock_auto.c | 10 ++-- .../nfc_scene_mf_ultralight_unlock_menu.c | 10 ++-- .../nfc_scene_mf_ultralight_unlock_warn.c | 10 ++-- .../nfc/scenes/nfc_scene_mfkey_complete.c | 10 ++-- .../nfc/scenes/nfc_scene_mfkey_nonces_info.c | 10 ++-- .../main/nfc/scenes/nfc_scene_nfc_data_info.c | 10 ++-- .../main/nfc/scenes/nfc_scene_nfca_menu.c | 10 ++-- .../nfc/scenes/nfc_scene_nfca_read_success.c | 10 ++-- applications/main/nfc/scenes/nfc_scene_read.c | 12 ++--- .../nfc/scenes/nfc_scene_read_card_success.c | 10 ++-- .../nfc/scenes/nfc_scene_read_card_type.c | 10 ++-- .../nfc/scenes/nfc_scene_restore_original.c | 10 ++-- .../nfc_scene_restore_original_confirm.c | 10 ++-- .../main/nfc/scenes/nfc_scene_retry_confirm.c | 10 ++-- applications/main/nfc/scenes/nfc_scene_rpc.c | 10 ++-- .../main/nfc/scenes/nfc_scene_save_name.c | 10 ++-- .../main/nfc/scenes/nfc_scene_save_success.c | 10 ++-- .../main/nfc/scenes/nfc_scene_saved_menu.c | 10 ++-- .../main/nfc/scenes/nfc_scene_set_atqa.c | 10 ++-- .../main/nfc/scenes/nfc_scene_set_sak.c | 10 ++-- .../main/nfc/scenes/nfc_scene_set_type.c | 10 ++-- .../main/nfc/scenes/nfc_scene_set_uid.c | 10 ++-- .../main/nfc/scenes/nfc_scene_start.c | 10 ++-- 71 files changed, 415 insertions(+), 369 deletions(-) delete mode 100644 applications/main/nfc/nfc.h rename applications/main/nfc/{nfc.c => nfc_app.c} (94%) create mode 100644 applications/main/nfc/nfc_app.h rename applications/main/nfc/{nfc_i.h => nfc_app_i.h} (86%) diff --git a/applications/main/application.fam b/applications/main/application.fam index 5c2c21d37535..d74c004aaa33 100644 --- a/applications/main/application.fam +++ b/applications/main/application.fam @@ -3,16 +3,16 @@ App( name="Basic applications for main menu", apptype=FlipperAppType.METAPACKAGE, provides=[ - "gpio", - "onewire", - "ibutton", - "infrared", - "lfrfid", + # "gpio", + # "ibutton", + # "infrared", + # "lfrfid", "nfc", - "subghz", - "bad_usb", - "u2f", - "fap_loader", - "archive", + "nfc_rpc", + # "subghz", + # "bad_usb", + # "u2f", + # "fap_loader", + # "archive", ], ) diff --git a/applications/main/nfc/nfc.h b/applications/main/nfc/nfc.h deleted file mode 100644 index e08be6a3aa9d..000000000000 --- a/applications/main/nfc/nfc.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -typedef struct Nfc Nfc; diff --git a/applications/main/nfc/nfc.c b/applications/main/nfc/nfc_app.c similarity index 94% rename from applications/main/nfc/nfc.c rename to applications/main/nfc/nfc_app.c index 4540f5d9f061..5884f8852d03 100644 --- a/applications/main/nfc/nfc.c +++ b/applications/main/nfc/nfc_app.c @@ -1,22 +1,22 @@ -#include "nfc_i.h" +#include "nfc_app_i.h" #include #include bool nfc_custom_event_callback(void* context, uint32_t event) { furi_assert(context); - Nfc* nfc = context; + NfcApp* nfc = context; return scene_manager_handle_custom_event(nfc->scene_manager, event); } bool nfc_back_event_callback(void* context) { furi_assert(context); - Nfc* nfc = context; + NfcApp* nfc = context; return scene_manager_handle_back_event(nfc->scene_manager); } static void nfc_rpc_command_callback(RpcAppSystemEvent event, void* context) { furi_assert(context); - Nfc* nfc = context; + NfcApp* nfc = context; furi_assert(nfc->rpc_ctx); @@ -33,8 +33,8 @@ static void nfc_rpc_command_callback(RpcAppSystemEvent event, void* context) { } } -Nfc* nfc_alloc() { - Nfc* nfc = malloc(sizeof(Nfc)); +NfcApp* nfc_app_alloc() { + NfcApp* nfc = malloc(sizeof(NfcApp)); nfc->worker = nfc_worker_alloc(); nfc->view_dispatcher = view_dispatcher_alloc(); @@ -107,7 +107,7 @@ Nfc* nfc_alloc() { return nfc; } -void nfc_free(Nfc* nfc) { +void nfc_app_free(NfcApp* nfc) { furi_assert(nfc); if(nfc->rpc_state == NfcRpcStateEmulating) { @@ -192,7 +192,7 @@ void nfc_free(Nfc* nfc) { free(nfc); } -void nfc_text_store_set(Nfc* nfc, const char* text, ...) { +void nfc_text_store_set(NfcApp* nfc, const char* text, ...) { va_list args; va_start(args, text); @@ -201,27 +201,27 @@ void nfc_text_store_set(Nfc* nfc, const char* text, ...) { va_end(args); } -void nfc_text_store_clear(Nfc* nfc) { +void nfc_text_store_clear(NfcApp* nfc) { memset(nfc->text_store, 0, sizeof(nfc->text_store)); } -void nfc_blink_read_start(Nfc* nfc) { +void nfc_blink_read_start(NfcApp* nfc) { notification_message(nfc->notifications, &sequence_blink_start_cyan); } -void nfc_blink_emulate_start(Nfc* nfc) { +void nfc_blink_emulate_start(NfcApp* nfc) { notification_message(nfc->notifications, &sequence_blink_start_magenta); } -void nfc_blink_detect_start(Nfc* nfc) { +void nfc_blink_detect_start(NfcApp* nfc) { notification_message(nfc->notifications, &sequence_blink_start_yellow); } -void nfc_blink_stop(Nfc* nfc) { +void nfc_blink_stop(NfcApp* nfc) { notification_message(nfc->notifications, &sequence_blink_stop); } -bool nfc_save_file(Nfc* nfc) { +bool nfc_save_file(NfcApp* nfc) { furi_string_printf( nfc->dev->load_path, "%s/%s%s", NFC_APP_FOLDER, nfc->dev->dev_name, NFC_APP_EXTENSION); bool file_saved = nfc_device_save(nfc->dev, furi_string_get_cstr(nfc->dev->load_path)); @@ -229,7 +229,7 @@ bool nfc_save_file(Nfc* nfc) { } void nfc_show_loading_popup(void* context, bool show) { - Nfc* nfc = context; + NfcApp* nfc = context; TaskHandle_t timer_task = xTaskGetHandle(configTIMER_SERVICE_TASK_NAME); if(show) { @@ -266,7 +266,7 @@ static bool nfc_is_hal_ready() { int32_t nfc_app(void* p) { if(!nfc_is_hal_ready()) return 0; - Nfc* nfc = nfc_alloc(); + NfcApp* nfc = nfc_app_alloc(); char* args = p; // Check argument and run corresponding scene @@ -310,7 +310,7 @@ int32_t nfc_app(void* p) { view_dispatcher_run(nfc->view_dispatcher); - nfc_free(nfc); + nfc_app_free(nfc); return 0; } diff --git a/applications/main/nfc/nfc_app.h b/applications/main/nfc/nfc_app.h new file mode 100644 index 000000000000..0e456fd48b27 --- /dev/null +++ b/applications/main/nfc/nfc_app.h @@ -0,0 +1,3 @@ +#pragma once + +typedef struct NfcApp NfcApp; diff --git a/applications/main/nfc/nfc_i.h b/applications/main/nfc/nfc_app_i.h similarity index 86% rename from applications/main/nfc/nfc_i.h rename to applications/main/nfc/nfc_app_i.h index f7e489902921..c361a5fc81f1 100644 --- a/applications/main/nfc/nfc_i.h +++ b/applications/main/nfc/nfc_app_i.h @@ -1,6 +1,6 @@ #pragma once -#include "nfc.h" +#include "nfc_app.h" #include #include @@ -52,7 +52,7 @@ typedef enum { NfcRpcStateEmulated, } NfcRpcState; -struct Nfc { +struct NfcApp { NfcWorker* worker; ViewDispatcher* view_dispatcher; Gui* gui; @@ -97,22 +97,22 @@ typedef enum { NfcViewDetectReader, } NfcView; -Nfc* nfc_alloc(); +NfcApp* nfc_alloc(); int32_t nfc_task(void* p); -void nfc_text_store_set(Nfc* nfc, const char* text, ...); +void nfc_text_store_set(NfcApp* nfc, const char* text, ...); -void nfc_text_store_clear(Nfc* nfc); +void nfc_text_store_clear(NfcApp* nfc); -void nfc_blink_read_start(Nfc* nfc); +void nfc_blink_read_start(NfcApp* nfc); -void nfc_blink_emulate_start(Nfc* nfc); +void nfc_blink_emulate_start(NfcApp* nfc); -void nfc_blink_detect_start(Nfc* nfc); +void nfc_blink_detect_start(NfcApp* nfc); -void nfc_blink_stop(Nfc* nfc); +void nfc_blink_stop(NfcApp* nfc); -bool nfc_save_file(Nfc* nfc); +bool nfc_save_file(NfcApp* nfc); void nfc_show_loading_popup(void* context, bool show); diff --git a/applications/main/nfc/nfc_cli.c b/applications/main/nfc/nfc_cli.c index 6e6e04ca928b..0cb7b960f69a 100644 --- a/applications/main/nfc/nfc_cli.c +++ b/applications/main/nfc/nfc_cli.c @@ -7,6 +7,16 @@ #include #include +#include +#include + +#include + +#include +#include +#include +#include + static void nfc_cli_print_usage() { printf("Usage:\r\n"); printf("nfc \r\n"); @@ -19,6 +29,38 @@ static void nfc_cli_print_usage() { } } +static void nfc_cli_check(Cli* cli, FuriString* args) { + UNUSED(args); + + uint8_t uid[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}; + uint8_t atqa[2] = {0x44, 0x00}; + uint8_t sak = 0x08; + NfcaData data = {}; + data.uid_len = sizeof(uid); + memcpy(data.uid, uid, data.uid_len); + memcpy(data.atqa, atqa, sizeof(atqa)); + data.sak = sak; + + NfcaListener* instance = nfca_listener_alloc(&data); + NfcaError error = NfcaErrorNone; + uint8_t rx_data[100] = {}; + uint16_t rx_bits = 0; + + while(true) { + error = nfca_listener_rx(instance, rx_data, sizeof(rx_data), &rx_bits, 10000); + if(error == NfcaErrorNone) { + printf("Received %d bits\r\n", rx_bits); + for(size_t i = 0; i < rx_bits / 8; i++) { + printf("%02X ", rx_data[i]); + } + printf("\r\n"); + } + if(cli_cmd_interrupt_received(cli)) break; + } + + nfca_listener_free(instance); +} + static void nfc_cli_detect(Cli* cli, FuriString* args) { UNUSED(args); // Check if nfc worker is not busy @@ -171,6 +213,10 @@ static void nfc_cli(Cli* cli, FuriString* args, void* context) { nfc_cli_print_usage(); break; } + if(furi_string_cmp_str(cmd, "c") == 0) { + nfc_cli_check(cli, args); + break; + } if(furi_string_cmp_str(cmd, "detect") == 0) { nfc_cli_detect(cli, args); break; diff --git a/applications/main/nfc/scenes/nfc_scene_debug.c b/applications/main/nfc/scenes/nfc_scene_debug.c index ed079c2ed9aa..f6705c880f39 100644 --- a/applications/main/nfc/scenes/nfc_scene_debug.c +++ b/applications/main/nfc/scenes/nfc_scene_debug.c @@ -1,4 +1,4 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" enum SubmenuDebugIndex { SubmenuDebugIndexField, @@ -6,13 +6,13 @@ enum SubmenuDebugIndex { }; void nfc_scene_debug_submenu_callback(void* context, uint32_t index) { - Nfc* nfc = context; + NfcApp* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_debug_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; Submenu* submenu = nfc->submenu; submenu_add_item( @@ -28,7 +28,7 @@ void nfc_scene_debug_on_enter(void* context) { } bool nfc_scene_debug_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -48,7 +48,7 @@ bool nfc_scene_debug_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_debug_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; submenu_reset(nfc->submenu); } diff --git a/applications/main/nfc/scenes/nfc_scene_delete.c b/applications/main/nfc/scenes/nfc_scene_delete.c index cbb52bfd0f2b..a5debe5e1b47 100644 --- a/applications/main/nfc/scenes/nfc_scene_delete.c +++ b/applications/main/nfc/scenes/nfc_scene_delete.c @@ -1,14 +1,14 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" void nfc_scene_delete_widget_callback(GuiButtonType result, InputType type, void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } } void nfc_scene_delete_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data; // Setup Custom Widget view @@ -51,7 +51,7 @@ void nfc_scene_delete_on_enter(void* context) { } bool nfc_scene_delete_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -71,7 +71,7 @@ bool nfc_scene_delete_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_delete_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; widget_reset(nfc->widget); } diff --git a/applications/main/nfc/scenes/nfc_scene_delete_success.c b/applications/main/nfc/scenes/nfc_scene_delete_success.c index 795363527fcf..f0c22eec4d58 100644 --- a/applications/main/nfc/scenes/nfc_scene_delete_success.c +++ b/applications/main/nfc/scenes/nfc_scene_delete_success.c @@ -1,12 +1,12 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" void nfc_scene_delete_success_popup_callback(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); } void nfc_scene_delete_success_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Setup view Popup* popup = nfc->popup; @@ -20,7 +20,7 @@ void nfc_scene_delete_success_on_enter(void* context) { } bool nfc_scene_delete_success_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -38,7 +38,7 @@ bool nfc_scene_delete_success_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_delete_success_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Clear view popup_reset(nfc->popup); diff --git a/applications/main/nfc/scenes/nfc_scene_detect_reader.c b/applications/main/nfc/scenes/nfc_scene_detect_reader.c index 745946157b0d..85c698d05350 100644 --- a/applications/main/nfc/scenes/nfc_scene_detect_reader.c +++ b/applications/main/nfc/scenes/nfc_scene_detect_reader.c @@ -1,4 +1,4 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" #define NFC_SCENE_DETECT_READER_PAIR_NONCES_MAX (10U) @@ -12,19 +12,19 @@ static const NotificationSequence sequence_detect_reader = { bool nfc_detect_reader_worker_callback(NfcWorkerEvent event, void* context) { UNUSED(event); furi_assert(context); - Nfc* nfc = context; + NfcApp* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, event); return true; } void nfc_scene_detect_reader_callback(void* context) { furi_assert(context); - Nfc* nfc = context; + NfcApp* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); } void nfc_scene_detect_reader_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; detect_reader_set_callback(nfc->detect_reader, nfc_scene_detect_reader_callback, nfc); detect_reader_set_nonces_max(nfc->detect_reader, NFC_SCENE_DETECT_READER_PAIR_NONCES_MAX); @@ -48,7 +48,7 @@ void nfc_scene_detect_reader_on_enter(void* context) { } bool nfc_scene_detect_reader_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; uint32_t nonces_collected = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneDetectReader); @@ -89,7 +89,7 @@ bool nfc_scene_detect_reader_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_detect_reader_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Stop worker nfc_worker_stop(nfc->worker); diff --git a/applications/main/nfc/scenes/nfc_scene_device_info.c b/applications/main/nfc/scenes/nfc_scene_device_info.c index 9780ffe41d2b..6d1bc8b42381 100644 --- a/applications/main/nfc/scenes/nfc_scene_device_info.c +++ b/applications/main/nfc/scenes/nfc_scene_device_info.c @@ -1,15 +1,15 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" #include "../helpers/nfc_emv_parser.h" void nfc_scene_device_info_widget_callback(GuiButtonType result, InputType type, void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } } void nfc_scene_device_info_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; NfcDeviceData* dev_data = &nfc->dev->dev_data; FuriString* temp_str; @@ -66,7 +66,7 @@ void nfc_scene_device_info_on_enter(void* context) { } bool nfc_scene_device_info_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -79,7 +79,7 @@ bool nfc_scene_device_info_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_device_info_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Clear views widget_reset(nfc->widget); diff --git a/applications/main/nfc/scenes/nfc_scene_dict_not_found.c b/applications/main/nfc/scenes/nfc_scene_dict_not_found.c index 781c5a932544..3b525c17e84f 100644 --- a/applications/main/nfc/scenes/nfc_scene_dict_not_found.c +++ b/applications/main/nfc/scenes/nfc_scene_dict_not_found.c @@ -1,12 +1,12 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" void nfc_scene_dict_not_found_popup_callback(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); } void nfc_scene_dict_not_found_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Setup view Popup* popup = nfc->popup; @@ -26,7 +26,7 @@ void nfc_scene_dict_not_found_on_enter(void* context) { } bool nfc_scene_dict_not_found_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -47,6 +47,6 @@ bool nfc_scene_dict_not_found_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_dict_not_found_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; popup_reset(nfc->popup); } diff --git a/applications/main/nfc/scenes/nfc_scene_emulate_apdu_sequence.c b/applications/main/nfc/scenes/nfc_scene_emulate_apdu_sequence.c index 358ad2ab6f57..81d00aeffc2c 100644 --- a/applications/main/nfc/scenes/nfc_scene_emulate_apdu_sequence.c +++ b/applications/main/nfc/scenes/nfc_scene_emulate_apdu_sequence.c @@ -1,8 +1,8 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" #include void nfc_scene_emulate_apdu_sequence_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Setup view Popup* popup = nfc->popup; @@ -23,7 +23,7 @@ bool nfc_scene_emulate_apdu_sequence_on_event(void* context, SceneManagerEvent e } void nfc_scene_emulate_apdu_sequence_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Stop worker nfc_worker_stop(nfc->worker); diff --git a/applications/main/nfc/scenes/nfc_scene_emulate_uid.c b/applications/main/nfc/scenes/nfc_scene_emulate_uid.c index 7316eebe0150..10435d2c7550 100644 --- a/applications/main/nfc/scenes/nfc_scene_emulate_uid.c +++ b/applications/main/nfc/scenes/nfc_scene_emulate_uid.c @@ -1,4 +1,4 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" #define NFC_SCENE_EMULATE_UID_LOG_SIZE_MAX (200) @@ -10,14 +10,14 @@ enum { bool nfc_emulate_uid_worker_callback(NfcWorkerEvent event, void* context) { UNUSED(event); furi_assert(context); - Nfc* nfc = context; + NfcApp* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit); return true; } void nfc_scene_emulate_uid_widget_callback(GuiButtonType result, InputType type, void* context) { furi_assert(context); - Nfc* nfc = context; + NfcApp* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } @@ -25,12 +25,12 @@ void nfc_scene_emulate_uid_widget_callback(GuiButtonType result, InputType type, void nfc_emulate_uid_textbox_callback(void* context) { furi_assert(context); - Nfc* nfc = context; + NfcApp* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); } // Add widget with device name or inform that data received -static void nfc_scene_emulate_uid_widget_config(Nfc* nfc, bool data_received) { +static void nfc_scene_emulate_uid_widget_config(NfcApp* nfc, bool data_received) { FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; Widget* widget = nfc->widget; widget_reset(widget); @@ -57,7 +57,7 @@ static void nfc_scene_emulate_uid_widget_config(Nfc* nfc, bool data_received) { } void nfc_scene_emulate_uid_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Setup Widget nfc_scene_emulate_uid_widget_config(nfc, false); @@ -84,7 +84,7 @@ void nfc_scene_emulate_uid_on_enter(void* context) { } bool nfc_scene_emulate_uid_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; NfcReaderRequestData* reader_data = &nfc->dev->dev_data.reader_data; uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneEmulateUid); bool consumed = false; @@ -130,7 +130,7 @@ bool nfc_scene_emulate_uid_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_emulate_uid_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Stop worker nfc_worker_stop(nfc->worker); diff --git a/applications/main/nfc/scenes/nfc_scene_emv_menu.c b/applications/main/nfc/scenes/nfc_scene_emv_menu.c index eb1e10043bd9..88d3355a0b75 100644 --- a/applications/main/nfc/scenes/nfc_scene_emv_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_emv_menu.c @@ -1,17 +1,17 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" enum SubmenuIndex { SubmenuIndexInfo, }; void nfc_scene_emv_menu_submenu_callback(void* context, uint32_t index) { - Nfc* nfc = context; + NfcApp* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_emv_menu_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; Submenu* submenu = nfc->submenu; submenu_add_item(submenu, "Info", SubmenuIndexInfo, nfc_scene_emv_menu_submenu_callback, nfc); @@ -22,7 +22,7 @@ void nfc_scene_emv_menu_on_enter(void* context) { } bool nfc_scene_emv_menu_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -39,7 +39,7 @@ bool nfc_scene_emv_menu_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_emv_menu_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Clear view submenu_reset(nfc->submenu); diff --git a/applications/main/nfc/scenes/nfc_scene_emv_read_success.c b/applications/main/nfc/scenes/nfc_scene_emv_read_success.c index 005b76cb2112..00057a2ee4ab 100644 --- a/applications/main/nfc/scenes/nfc_scene_emv_read_success.c +++ b/applications/main/nfc/scenes/nfc_scene_emv_read_success.c @@ -1,18 +1,18 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" #include "../helpers/nfc_emv_parser.h" void nfc_scene_emv_read_success_widget_callback( GuiButtonType result, InputType type, void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } } void nfc_scene_emv_read_success_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; EmvData* emv_data = &nfc->dev->dev_data.emv_data; // Setup Custom Widget view @@ -85,7 +85,7 @@ void nfc_scene_emv_read_success_on_enter(void* context) { } bool nfc_scene_emv_read_success_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -104,7 +104,7 @@ bool nfc_scene_emv_read_success_on_event(void* context, SceneManagerEvent event) } void nfc_scene_emv_read_success_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; notification_message_block(nfc->notifications, &sequence_reset_green); diff --git a/applications/main/nfc/scenes/nfc_scene_exit_confirm.c b/applications/main/nfc/scenes/nfc_scene_exit_confirm.c index 3ce4f6de839b..92933556d2ad 100644 --- a/applications/main/nfc/scenes/nfc_scene_exit_confirm.c +++ b/applications/main/nfc/scenes/nfc_scene_exit_confirm.c @@ -1,13 +1,13 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" void nfc_scene_exit_confirm_dialog_callback(DialogExResult result, void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } void nfc_scene_exit_confirm_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; DialogEx* dialog_ex = nfc->dialog_ex; dialog_ex_set_left_button_text(dialog_ex, "Exit"); @@ -22,7 +22,7 @@ void nfc_scene_exit_confirm_on_enter(void* context) { } bool nfc_scene_exit_confirm_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -45,7 +45,7 @@ bool nfc_scene_exit_confirm_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_exit_confirm_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Clean view dialog_ex_reset(nfc->dialog_ex); diff --git a/applications/main/nfc/scenes/nfc_scene_extra_actions.c b/applications/main/nfc/scenes/nfc_scene_extra_actions.c index 66aaf5a26dc5..31106c76a4f3 100644 --- a/applications/main/nfc/scenes/nfc_scene_extra_actions.c +++ b/applications/main/nfc/scenes/nfc_scene_extra_actions.c @@ -1,4 +1,4 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" enum SubmenuIndex { SubmenuIndexReadCardType, @@ -7,13 +7,13 @@ enum SubmenuIndex { }; void nfc_scene_extra_actions_submenu_callback(void* context, uint32_t index) { - Nfc* nfc = context; + NfcApp* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_extra_actions_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; Submenu* submenu = nfc->submenu; submenu_add_item( @@ -40,7 +40,7 @@ void nfc_scene_extra_actions_on_enter(void* context) { } bool nfc_scene_extra_actions_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -66,7 +66,7 @@ bool nfc_scene_extra_actions_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_extra_actions_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; submenu_reset(nfc->submenu); } diff --git a/applications/main/nfc/scenes/nfc_scene_field.c b/applications/main/nfc/scenes/nfc_scene_field.c index e3eb6a7088b8..893f4d03ff91 100644 --- a/applications/main/nfc/scenes/nfc_scene_field.c +++ b/applications/main/nfc/scenes/nfc_scene_field.c @@ -1,7 +1,7 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" void nfc_scene_field_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; furi_hal_nfc_field_on(); @@ -25,7 +25,7 @@ bool nfc_scene_field_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_field_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; furi_hal_nfc_field_off(); notification_internal_message(nfc->notifications, &sequence_reset_blue); diff --git a/applications/main/nfc/scenes/nfc_scene_file_select.c b/applications/main/nfc/scenes/nfc_scene_file_select.c index 374a933d1c70..61ac593e0c4e 100644 --- a/applications/main/nfc/scenes/nfc_scene_file_select.c +++ b/applications/main/nfc/scenes/nfc_scene_file_select.c @@ -1,8 +1,8 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" #include "nfc/nfc_device.h" void nfc_scene_file_select_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Process file_select return nfc_device_set_loading_callback(nfc->dev, nfc_show_loading_popup, nfc); if(!furi_string_size(nfc->dev->load_path)) { diff --git a/applications/main/nfc/scenes/nfc_scene_generate_info.c b/applications/main/nfc/scenes/nfc_scene_generate_info.c index 7b84ae43b11f..e877d771a6f0 100644 --- a/applications/main/nfc/scenes/nfc_scene_generate_info.c +++ b/applications/main/nfc/scenes/nfc_scene_generate_info.c @@ -1,14 +1,14 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" #include "lib/nfc/helpers/nfc_generators.h" void nfc_scene_generate_info_dialog_callback(DialogExResult result, void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } void nfc_scene_generate_info_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Setup dialog view FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; @@ -34,7 +34,7 @@ void nfc_scene_generate_info_on_enter(void* context) { } bool nfc_scene_generate_info_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -53,7 +53,7 @@ bool nfc_scene_generate_info_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_generate_info_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Clean views dialog_ex_reset(nfc->dialog_ex); diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_data.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_data.c index dcb02d3645a5..83ba57f7cf7e 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_data.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_data.c @@ -1,7 +1,7 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" void nfc_scene_mf_classic_data_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; MfClassicType type = nfc->dev->dev_data.mf_classic_data.type; MfClassicData* data = &nfc->dev->dev_data.mf_classic_data; TextBox* text_box = nfc->text_box; @@ -98,7 +98,7 @@ bool nfc_scene_mf_classic_data_on_event(void* context, SceneManagerEvent event) } void nfc_scene_mf_classic_data_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Clean view text_box_reset(nfc->text_box); diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c index cb2f3a82d9e7..77d559367c1e 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c @@ -1,4 +1,4 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" #include #define TAG "NfcMfClassicDictAttack" @@ -11,18 +11,18 @@ typedef enum { bool nfc_dict_attack_worker_callback(NfcWorkerEvent event, void* context) { furi_assert(context); - Nfc* nfc = context; + NfcApp* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, event); return true; } void nfc_dict_attack_dict_attack_result_callback(void* context) { furi_assert(context); - Nfc* nfc = context; + NfcApp* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventDictAttackSkip); } -static void nfc_scene_mf_classic_dict_attack_update_view(Nfc* nfc) { +static void nfc_scene_mf_classic_dict_attack_update_view(NfcApp* nfc) { MfClassicData* data = &nfc->dev->dev_data.mf_classic_data; uint8_t sectors_read = 0; uint8_t keys_found = 0; @@ -33,7 +33,7 @@ static void nfc_scene_mf_classic_dict_attack_update_view(Nfc* nfc) { dict_attack_set_sector_read(nfc->dict_attack, sectors_read); } -static void nfc_scene_mf_classic_dict_attack_prepare_view(Nfc* nfc, DictAttackState state) { +static void nfc_scene_mf_classic_dict_attack_prepare_view(NfcApp* nfc, DictAttackState state) { MfClassicData* data = &nfc->dev->dev_data.mf_classic_data; NfcMfClassicDictAttackData* dict_attack_data = &nfc->dev->dev_data.mf_classic_dict_attack_data; NfcWorkerState worker_state = NfcWorkerStateReady; @@ -88,7 +88,7 @@ static void nfc_scene_mf_classic_dict_attack_prepare_view(Nfc* nfc, DictAttackSt } void nfc_scene_mf_classic_dict_attack_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; nfc_scene_mf_classic_dict_attack_prepare_view(nfc, DictAttackStateIdle); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDictAttack); nfc_blink_read_start(nfc); @@ -96,7 +96,7 @@ void nfc_scene_mf_classic_dict_attack_on_enter(void* context) { } bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; MfClassicData* data = &nfc->dev->dev_data.mf_classic_data; bool consumed = false; @@ -172,7 +172,7 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent } void nfc_scene_mf_classic_dict_attack_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; NfcMfClassicDictAttackData* dict_attack_data = &nfc->dev->dev_data.mf_classic_dict_attack_data; // Stop worker nfc_worker_stop(nfc->worker); diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_emulate.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_emulate.c index 8c0f493e12b4..6cf7689052c5 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_emulate.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_emulate.c @@ -1,11 +1,11 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" #define NFC_MF_CLASSIC_DATA_NOT_CHANGED (0UL) #define NFC_MF_CLASSIC_DATA_CHANGED (1UL) bool nfc_mf_classic_emulate_worker_callback(NfcWorkerEvent event, void* context) { UNUSED(event); - Nfc* nfc = context; + NfcApp* nfc = context; scene_manager_set_scene_state( nfc->scene_manager, NfcSceneMfClassicEmulate, NFC_MF_CLASSIC_DATA_CHANGED); @@ -13,7 +13,7 @@ bool nfc_mf_classic_emulate_worker_callback(NfcWorkerEvent event, void* context) } void nfc_scene_mf_classic_emulate_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Setup view Popup* popup = nfc->popup; @@ -38,7 +38,7 @@ void nfc_scene_mf_classic_emulate_on_enter(void* context) { } bool nfc_scene_mf_classic_emulate_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeBack) { @@ -60,7 +60,7 @@ bool nfc_scene_mf_classic_emulate_on_event(void* context, SceneManagerEvent even } void nfc_scene_mf_classic_emulate_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Clear view popup_reset(nfc->popup); diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_keys.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys.c index 8a7dc2c1839e..b7cc2f283450 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_keys.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys.c @@ -1,14 +1,14 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" void nfc_scene_mf_classic_keys_widget_callback(GuiButtonType result, InputType type, void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } } void nfc_scene_mf_classic_keys_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Load flipper dict keys total uint32_t flipper_dict_keys_total = 0; @@ -48,7 +48,7 @@ void nfc_scene_mf_classic_keys_on_enter(void* context) { } bool nfc_scene_mf_classic_keys_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -65,7 +65,7 @@ bool nfc_scene_mf_classic_keys_on_event(void* context, SceneManagerEvent event) } void nfc_scene_mf_classic_keys_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; widget_reset(nfc->widget); } diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_add.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_add.c index b122aa225b92..d2b89829bf94 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_add.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_add.c @@ -1,14 +1,14 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" #include void nfc_scene_mf_classic_keys_add_byte_input_callback(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); } void nfc_scene_mf_classic_keys_add_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Setup view ByteInput* byte_input = nfc->byte_input; @@ -24,7 +24,7 @@ void nfc_scene_mf_classic_keys_add_on_enter(void* context) { } bool nfc_scene_mf_classic_keys_add_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -52,7 +52,7 @@ bool nfc_scene_mf_classic_keys_add_on_event(void* context, SceneManagerEvent eve } void nfc_scene_mf_classic_keys_add_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Clear view byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0); diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_delete.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_delete.c index 0ea3f59a45ef..9f34c8eee0de 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_delete.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_delete.c @@ -1,17 +1,17 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" void nfc_scene_mf_classic_keys_delete_widget_callback( GuiButtonType result, InputType type, void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } } void nfc_scene_mf_classic_keys_delete_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; MfClassicDict* dict = mf_classic_dict_alloc(MfClassicDictTypeUser); uint32_t key_index = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicKeysDelete); @@ -51,7 +51,7 @@ void nfc_scene_mf_classic_keys_delete_on_enter(void* context) { } bool nfc_scene_mf_classic_keys_delete_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; uint32_t key_index = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicKeysDelete); @@ -77,7 +77,7 @@ bool nfc_scene_mf_classic_keys_delete_on_event(void* context, SceneManagerEvent } void nfc_scene_mf_classic_keys_delete_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; widget_reset(nfc->widget); } diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_list.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_list.c index 57f9fe656247..6a7be48a0bb3 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_list.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_list.c @@ -1,22 +1,22 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" #define NFC_SCENE_MF_CLASSIC_KEYS_LIST_MAX (100) void nfc_scene_mf_classic_keys_list_submenu_callback(void* context, uint32_t index) { furi_assert(context); - Nfc* nfc = context; + NfcApp* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_mf_classic_keys_list_popup_callback(void* context) { furi_assert(context); - Nfc* nfc = context; + NfcApp* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); } -void nfc_scene_mf_classic_keys_list_prepare(Nfc* nfc, MfClassicDict* dict) { +void nfc_scene_mf_classic_keys_list_prepare(NfcApp* nfc, MfClassicDict* dict) { Submenu* submenu = nfc->submenu; uint32_t index = 0; FuriString* temp_key; @@ -35,7 +35,7 @@ void nfc_scene_mf_classic_keys_list_prepare(Nfc* nfc, MfClassicDict* dict) { } void nfc_scene_mf_classic_keys_list_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; MfClassicDict* dict = mf_classic_dict_alloc(MfClassicDictTypeUser); MfClassicUserKeys_init(nfc->mfc_key_strs); if(dict) { @@ -71,7 +71,7 @@ void nfc_scene_mf_classic_keys_list_on_enter(void* context) { } bool nfc_scene_mf_classic_keys_list_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { if(event.event == NfcCustomEventViewExit) { @@ -87,7 +87,7 @@ bool nfc_scene_mf_classic_keys_list_on_event(void* context, SceneManagerEvent ev } void nfc_scene_mf_classic_keys_list_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; MfClassicUserKeys_it_t it; for(MfClassicUserKeys_it(it, nfc->mfc_key_strs); !MfClassicUserKeys_end_p(it); diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_warn_duplicate.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_warn_duplicate.c index ab41989b2c73..5cc1ba635399 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_warn_duplicate.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_warn_duplicate.c @@ -1,12 +1,12 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" void nfc_scene_mf_classic_keys_warn_duplicate_popup_callback(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); } void nfc_scene_mf_classic_keys_warn_duplicate_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Setup view Popup* popup = nfc->popup; @@ -28,7 +28,7 @@ void nfc_scene_mf_classic_keys_warn_duplicate_on_enter(void* context) { } bool nfc_scene_mf_classic_keys_warn_duplicate_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -41,7 +41,7 @@ bool nfc_scene_mf_classic_keys_warn_duplicate_on_event(void* context, SceneManag } void nfc_scene_mf_classic_keys_warn_duplicate_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; popup_reset(nfc->popup); } diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_menu.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_menu.c index 67b2a85309e4..207bb17edfbb 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_menu.c @@ -1,4 +1,4 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" #include enum SubmenuIndex { @@ -9,13 +9,13 @@ enum SubmenuIndex { }; void nfc_scene_mf_classic_menu_submenu_callback(void* context, uint32_t index) { - Nfc* nfc = context; + NfcApp* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_mf_classic_menu_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; Submenu* submenu = nfc->submenu; submenu_add_item( @@ -40,7 +40,7 @@ void nfc_scene_mf_classic_menu_on_enter(void* context) { } bool nfc_scene_mf_classic_menu_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -75,7 +75,7 @@ bool nfc_scene_mf_classic_menu_on_event(void* context, SceneManagerEvent event) } void nfc_scene_mf_classic_menu_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Clear view submenu_reset(nfc->submenu); diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_read_success.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_read_success.c index 444c9a540e7d..f0ab9397f5f7 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_read_success.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_read_success.c @@ -1,11 +1,11 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" void nfc_scene_mf_classic_read_success_widget_callback( GuiButtonType result, InputType type, void* context) { furi_assert(context); - Nfc* nfc = context; + NfcApp* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); @@ -13,7 +13,7 @@ void nfc_scene_mf_classic_read_success_widget_callback( } void nfc_scene_mf_classic_read_success_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; NfcDeviceData* dev_data = &nfc->dev->dev_data; MfClassicData* mf_data = &dev_data->mf_classic_data; @@ -51,7 +51,7 @@ void nfc_scene_mf_classic_read_success_on_enter(void* context) { } bool nfc_scene_mf_classic_read_success_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -73,7 +73,7 @@ bool nfc_scene_mf_classic_read_success_on_event(void* context, SceneManagerEvent } void nfc_scene_mf_classic_read_success_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; notification_message_block(nfc->notifications, &sequence_reset_green); diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_update.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_update.c index aacf77f773f0..3819e799bb4c 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_update.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_update.c @@ -1,4 +1,4 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" #include enum { @@ -9,13 +9,13 @@ enum { bool nfc_mf_classic_update_worker_callback(NfcWorkerEvent event, void* context) { furi_assert(context); - Nfc* nfc = context; + NfcApp* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, event); return true; } -static void nfc_scene_mf_classic_update_setup_view(Nfc* nfc) { +static void nfc_scene_mf_classic_update_setup_view(NfcApp* nfc) { Popup* popup = nfc->popup; popup_reset(popup); uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicUpdate); @@ -33,7 +33,7 @@ static void nfc_scene_mf_classic_update_setup_view(Nfc* nfc) { } void nfc_scene_mf_classic_update_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; DOLPHIN_DEED(DolphinDeedNfcEmulate); scene_manager_set_scene_state( @@ -51,7 +51,7 @@ void nfc_scene_mf_classic_update_on_enter(void* context) { } bool nfc_scene_mf_classic_update_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -87,7 +87,7 @@ bool nfc_scene_mf_classic_update_on_event(void* context, SceneManagerEvent event } void nfc_scene_mf_classic_update_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; nfc_worker_stop(nfc->worker); scene_manager_set_scene_state( nfc->scene_manager, NfcSceneMfClassicUpdate, NfcSceneMfClassicUpdateStateCardSearch); diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_update_success.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_update_success.c index fef8fd5e9320..f52114b161d9 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_update_success.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_update_success.c @@ -1,13 +1,13 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" #include void nfc_scene_mf_classic_update_success_popup_callback(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); } void nfc_scene_mf_classic_update_success_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; DOLPHIN_DEED(DolphinDeedNfcSave); notification_message(nfc->notifications, &sequence_success); @@ -24,7 +24,7 @@ void nfc_scene_mf_classic_update_success_on_enter(void* context) { } bool nfc_scene_mf_classic_update_success_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -37,7 +37,7 @@ bool nfc_scene_mf_classic_update_success_on_event(void* context, SceneManagerEve } void nfc_scene_mf_classic_update_success_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Clear view popup_reset(nfc->popup); diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_write.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_write.c index 3543cbc5889b..d33fbc4106a9 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_write.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_write.c @@ -1,4 +1,4 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" #include enum { @@ -9,13 +9,13 @@ enum { bool nfc_mf_classic_write_worker_callback(NfcWorkerEvent event, void* context) { furi_assert(context); - Nfc* nfc = context; + NfcApp* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, event); return true; } -static void nfc_scene_mf_classic_write_setup_view(Nfc* nfc) { +static void nfc_scene_mf_classic_write_setup_view(NfcApp* nfc) { Popup* popup = nfc->popup; popup_reset(popup); uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicWrite); @@ -33,7 +33,7 @@ static void nfc_scene_mf_classic_write_setup_view(Nfc* nfc) { } void nfc_scene_mf_classic_write_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; DOLPHIN_DEED(DolphinDeedNfcEmulate); scene_manager_set_scene_state( @@ -51,7 +51,7 @@ void nfc_scene_mf_classic_write_on_enter(void* context) { } bool nfc_scene_mf_classic_write_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -80,7 +80,7 @@ bool nfc_scene_mf_classic_write_on_event(void* context, SceneManagerEvent event) } void nfc_scene_mf_classic_write_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; nfc_worker_stop(nfc->worker); scene_manager_set_scene_state( diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_write_fail.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_write_fail.c index aeea6eef0692..695a3c4a7402 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_write_fail.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_write_fail.c @@ -1,17 +1,17 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" void nfc_scene_mf_classic_write_fail_widget_callback( GuiButtonType result, InputType type, void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } } void nfc_scene_mf_classic_write_fail_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; Widget* widget = nfc->widget; notification_message(nfc->notifications, &sequence_error); @@ -36,7 +36,7 @@ void nfc_scene_mf_classic_write_fail_on_enter(void* context) { } bool nfc_scene_mf_classic_write_fail_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -52,7 +52,7 @@ bool nfc_scene_mf_classic_write_fail_on_event(void* context, SceneManagerEvent e } void nfc_scene_mf_classic_write_fail_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; widget_reset(nfc->widget); } diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_write_success.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_write_success.c index 2f2a3beb119b..272d607dfb35 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_write_success.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_write_success.c @@ -1,13 +1,13 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" #include void nfc_scene_mf_classic_write_success_popup_callback(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); } void nfc_scene_mf_classic_write_success_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; DOLPHIN_DEED(DolphinDeedNfcSave); notification_message(nfc->notifications, &sequence_success); @@ -24,7 +24,7 @@ void nfc_scene_mf_classic_write_success_on_enter(void* context) { } bool nfc_scene_mf_classic_write_success_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -37,7 +37,7 @@ bool nfc_scene_mf_classic_write_success_on_event(void* context, SceneManagerEven } void nfc_scene_mf_classic_write_success_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Clear view popup_reset(nfc->popup); diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_wrong_card.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_wrong_card.c index 2c56270e36d2..ac7d6593470d 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_wrong_card.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_wrong_card.c @@ -1,17 +1,17 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" void nfc_scene_mf_classic_wrong_card_widget_callback( GuiButtonType result, InputType type, void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } } void nfc_scene_mf_classic_wrong_card_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; Widget* widget = nfc->widget; notification_message(nfc->notifications, &sequence_error); @@ -35,7 +35,7 @@ void nfc_scene_mf_classic_wrong_card_on_enter(void* context) { } bool nfc_scene_mf_classic_wrong_card_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -47,7 +47,7 @@ bool nfc_scene_mf_classic_wrong_card_on_event(void* context, SceneManagerEvent e } void nfc_scene_mf_classic_wrong_card_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; widget_reset(nfc->widget); } \ No newline at end of file diff --git a/applications/main/nfc/scenes/nfc_scene_mf_desfire_app.c b/applications/main/nfc/scenes/nfc_scene_mf_desfire_app.c index 882dc5fea8f2..2c856157270d 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_desfire_app.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_desfire_app.c @@ -1,4 +1,4 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" #define TAG "NfcSceneMfDesfireApp" @@ -10,11 +10,11 @@ enum SubmenuIndex { void nfc_scene_mf_desfire_popup_callback(void* context) { furi_assert(context); - Nfc* nfc = context; + NfcApp* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); } -MifareDesfireApplication* nfc_scene_mf_desfire_app_get_app(Nfc* nfc) { +MifareDesfireApplication* nfc_scene_mf_desfire_app_get_app(NfcApp* nfc) { uint32_t app_idx = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireApp) >> 1; MifareDesfireApplication* app = nfc->dev->dev_data.mf_df_data.app_head; @@ -25,13 +25,13 @@ MifareDesfireApplication* nfc_scene_mf_desfire_app_get_app(Nfc* nfc) { } void nfc_scene_mf_desfire_app_submenu_callback(void* context, uint32_t index) { - Nfc* nfc = context; + NfcApp* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_mf_desfire_app_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; MifareDesfireApplication* app = nfc_scene_mf_desfire_app_get_app(nfc); if(!app) { popup_set_icon(nfc->popup, 5, 5, &I_WarningDolphin_45x42); @@ -69,7 +69,7 @@ void nfc_scene_mf_desfire_app_on_enter(void* context) { } bool nfc_scene_mf_desfire_app_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireApp); @@ -110,7 +110,7 @@ bool nfc_scene_mf_desfire_app_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_mf_desfire_app_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Clear views popup_reset(nfc->popup); diff --git a/applications/main/nfc/scenes/nfc_scene_mf_desfire_data.c b/applications/main/nfc/scenes/nfc_scene_mf_desfire_data.c index c7caee8dc6d3..e9e529909dc5 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_desfire_data.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_desfire_data.c @@ -1,4 +1,4 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" #define TAG "NfcSceneMfDesfireData" @@ -13,13 +13,13 @@ enum SubmenuIndex { }; void nfc_scene_mf_desfire_data_submenu_callback(void* context, uint32_t index) { - Nfc* nfc = (Nfc*)context; + NfcApp* nfc = (NfcApp*)context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_mf_desfire_data_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; Submenu* submenu = nfc->submenu; uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireData); MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data; @@ -57,7 +57,7 @@ void nfc_scene_mf_desfire_data_on_enter(void* context) { } bool nfc_scene_mf_desfire_data_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireData); MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data; @@ -95,7 +95,7 @@ bool nfc_scene_mf_desfire_data_on_event(void* context, SceneManagerEvent event) } void nfc_scene_mf_desfire_data_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Clear views text_box_reset(nfc->text_box); diff --git a/applications/main/nfc/scenes/nfc_scene_mf_desfire_menu.c b/applications/main/nfc/scenes/nfc_scene_mf_desfire_menu.c index bee63d775bd5..b3ebe9a469a9 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_desfire_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_desfire_menu.c @@ -1,4 +1,4 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" #include enum SubmenuIndex { @@ -8,13 +8,13 @@ enum SubmenuIndex { }; void nfc_scene_mf_desfire_menu_submenu_callback(void* context, uint32_t index) { - Nfc* nfc = context; + NfcApp* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_mf_desfire_menu_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; Submenu* submenu = nfc->submenu; submenu_add_item( @@ -35,7 +35,7 @@ void nfc_scene_mf_desfire_menu_on_enter(void* context) { } bool nfc_scene_mf_desfire_menu_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -65,7 +65,7 @@ bool nfc_scene_mf_desfire_menu_on_event(void* context, SceneManagerEvent event) } void nfc_scene_mf_desfire_menu_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Clear view submenu_reset(nfc->submenu); diff --git a/applications/main/nfc/scenes/nfc_scene_mf_desfire_read_success.c b/applications/main/nfc/scenes/nfc_scene_mf_desfire_read_success.c index 39030397fc43..919070595dbe 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_desfire_read_success.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_desfire_read_success.c @@ -1,11 +1,11 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" #include void nfc_scene_mf_desfire_read_success_widget_callback( GuiButtonType result, InputType type, void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); @@ -13,7 +13,7 @@ void nfc_scene_mf_desfire_read_success_widget_callback( } void nfc_scene_mf_desfire_read_success_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data; MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data; @@ -67,7 +67,7 @@ void nfc_scene_mf_desfire_read_success_on_enter(void* context) { } bool nfc_scene_mf_desfire_read_success_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -87,7 +87,7 @@ bool nfc_scene_mf_desfire_read_success_on_event(void* context, SceneManagerEvent } void nfc_scene_mf_desfire_read_success_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; notification_message_block(nfc->notifications, &sequence_reset_green); diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_data.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_data.c index 8cd223ee64dd..7d56cb1483eb 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_data.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_data.c @@ -1,7 +1,7 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" void nfc_scene_mf_ultralight_data_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; MfUltralightData* data = &nfc->dev->dev_data.mf_ul_data; TextBox* text_box = nfc->text_box; @@ -24,7 +24,7 @@ bool nfc_scene_mf_ultralight_data_on_event(void* context, SceneManagerEvent even } void nfc_scene_mf_ultralight_data_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Clean view text_box_reset(nfc->text_box); diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_emulate.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_emulate.c index 9d8f17f9a2c0..192d67bef73e 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_emulate.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_emulate.c @@ -1,11 +1,11 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" #define NFC_MF_UL_DATA_NOT_CHANGED (0UL) #define NFC_MF_UL_DATA_CHANGED (1UL) bool nfc_mf_ultralight_emulate_worker_callback(NfcWorkerEvent event, void* context) { UNUSED(event); - Nfc* nfc = context; + NfcApp* nfc = context; scene_manager_set_scene_state( nfc->scene_manager, NfcSceneMfUltralightEmulate, NFC_MF_UL_DATA_CHANGED); @@ -13,7 +13,7 @@ bool nfc_mf_ultralight_emulate_worker_callback(NfcWorkerEvent event, void* conte } void nfc_scene_mf_ultralight_emulate_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Setup view MfUltralightType type = nfc->dev->dev_data.mf_ul_data.type; @@ -43,7 +43,7 @@ void nfc_scene_mf_ultralight_emulate_on_enter(void* context) { } bool nfc_scene_mf_ultralight_emulate_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeBack) { @@ -65,7 +65,7 @@ bool nfc_scene_mf_ultralight_emulate_on_event(void* context, SceneManagerEvent e } void nfc_scene_mf_ultralight_emulate_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Clear view popup_reset(nfc->popup); diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_key_input.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_key_input.c index 089187d5bc3a..e8c87693d462 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_key_input.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_key_input.c @@ -1,13 +1,13 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" void nfc_scene_mf_ultralight_key_input_byte_input_callback(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); } void nfc_scene_mf_ultralight_key_input_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Setup view ByteInput* byte_input = nfc->byte_input; @@ -23,7 +23,7 @@ void nfc_scene_mf_ultralight_key_input_on_enter(void* context) { } bool nfc_scene_mf_ultralight_key_input_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -36,7 +36,7 @@ bool nfc_scene_mf_ultralight_key_input_on_event(void* context, SceneManagerEvent } void nfc_scene_mf_ultralight_key_input_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Clear view byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0); diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c index c511e9dcbfe1..6069ed356c8f 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c @@ -1,4 +1,4 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" #include enum SubmenuIndex { @@ -9,13 +9,13 @@ enum SubmenuIndex { }; void nfc_scene_mf_ultralight_menu_submenu_callback(void* context, uint32_t index) { - Nfc* nfc = context; + NfcApp* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_mf_ultralight_menu_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; Submenu* submenu = nfc->submenu; MfUltralightData* data = &nfc->dev->dev_data.mf_ul_data; @@ -45,7 +45,7 @@ void nfc_scene_mf_ultralight_menu_on_enter(void* context) { } bool nfc_scene_mf_ultralight_menu_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -80,7 +80,7 @@ bool nfc_scene_mf_ultralight_menu_on_event(void* context, SceneManagerEvent even } void nfc_scene_mf_ultralight_menu_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Clear view submenu_reset(nfc->submenu); diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_auth.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_auth.c index 2ab5e3f3f441..4d549989ab4a 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_auth.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_auth.c @@ -1,4 +1,4 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" typedef enum { NfcSceneMfUlReadStateIdle, @@ -8,7 +8,7 @@ typedef enum { } NfcSceneMfUlReadState; bool nfc_scene_mf_ultralight_read_auth_worker_callback(NfcWorkerEvent event, void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; if(event == NfcWorkerEventMfUltralightPassKey) { memcpy(nfc->dev->dev_data.mf_ul_data.auth_key, nfc->byte_input_store, 4); @@ -18,7 +18,7 @@ bool nfc_scene_mf_ultralight_read_auth_worker_callback(NfcWorkerEvent event, voi return true; } -void nfc_scene_mf_ultralight_read_auth_set_state(Nfc* nfc, NfcSceneMfUlReadState state) { +void nfc_scene_mf_ultralight_read_auth_set_state(NfcApp* nfc, NfcSceneMfUlReadState state) { uint32_t curr_state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightReadAuth); if(curr_state != state) { @@ -53,7 +53,7 @@ void nfc_scene_mf_ultralight_read_auth_set_state(Nfc* nfc, NfcSceneMfUlReadState } void nfc_scene_mf_ultralight_read_auth_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; nfc_device_clear(nfc->dev); // Setup view @@ -69,7 +69,7 @@ void nfc_scene_mf_ultralight_read_auth_on_enter(void* context) { } bool nfc_scene_mf_ultralight_read_auth_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -104,7 +104,7 @@ bool nfc_scene_mf_ultralight_read_auth_on_event(void* context, SceneManagerEvent } void nfc_scene_mf_ultralight_read_auth_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Stop worker nfc_worker_stop(nfc->worker); diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_auth_result.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_auth_result.c index b125e999127e..c3ea1522fac3 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_auth_result.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_auth_result.c @@ -1,10 +1,10 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" void nfc_scene_mf_ultralight_read_auth_result_widget_callback( GuiButtonType result, InputType type, void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); @@ -12,7 +12,7 @@ void nfc_scene_mf_ultralight_read_auth_result_widget_callback( } void nfc_scene_mf_ultralight_read_auth_result_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Setup dialog view FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data; @@ -74,7 +74,7 @@ void nfc_scene_mf_ultralight_read_auth_result_on_enter(void* context) { } bool nfc_scene_mf_ultralight_read_auth_result_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -107,7 +107,7 @@ bool nfc_scene_mf_ultralight_read_auth_result_on_event(void* context, SceneManag } void nfc_scene_mf_ultralight_read_auth_result_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Clean views widget_reset(nfc->widget); diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_success.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_success.c index cb5ccd6e8268..60c8191e5a10 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_success.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_success.c @@ -1,10 +1,10 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" void nfc_scene_mf_ultralight_read_success_widget_callback( GuiButtonType result, InputType type, void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); @@ -12,7 +12,7 @@ void nfc_scene_mf_ultralight_read_success_widget_callback( } void nfc_scene_mf_ultralight_read_success_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Setup widget view FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; @@ -55,7 +55,7 @@ void nfc_scene_mf_ultralight_read_success_on_enter(void* context) { } bool nfc_scene_mf_ultralight_read_success_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -75,7 +75,7 @@ bool nfc_scene_mf_ultralight_read_success_on_event(void* context, SceneManagerEv } void nfc_scene_mf_ultralight_read_success_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; notification_message_block(nfc->notifications, &sequence_reset_green); diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_auto.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_auto.c index c59fe3a7d090..24f1703a28f5 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_auto.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_auto.c @@ -1,14 +1,14 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" bool nfc_scene_mf_ultralight_unlock_auto_worker_callback(NfcWorkerEvent event, void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, event); return true; } void nfc_scene_mf_ultralight_unlock_auto_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Setup view widget_add_string_multiline_element( @@ -35,7 +35,7 @@ void nfc_scene_mf_ultralight_unlock_auto_on_enter(void* context) { } bool nfc_scene_mf_ultralight_unlock_auto_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -53,7 +53,7 @@ bool nfc_scene_mf_ultralight_unlock_auto_on_event(void* context, SceneManagerEve } void nfc_scene_mf_ultralight_unlock_auto_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Stop worker nfc_worker_stop(nfc->worker); diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_menu.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_menu.c index 484629b0bbe1..5c0604d383c4 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_menu.c @@ -1,4 +1,4 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" enum SubmenuIndex { SubmenuIndexMfUlUnlockMenuAuto, @@ -8,13 +8,13 @@ enum SubmenuIndex { }; void nfc_scene_mf_ultralight_unlock_menu_submenu_callback(void* context, uint32_t index) { - Nfc* nfc = context; + NfcApp* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_mf_ultralight_unlock_menu_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; Submenu* submenu = nfc->submenu; uint32_t state = @@ -50,7 +50,7 @@ void nfc_scene_mf_ultralight_unlock_menu_on_enter(void* context) { } bool nfc_scene_mf_ultralight_unlock_menu_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -77,7 +77,7 @@ bool nfc_scene_mf_ultralight_unlock_menu_on_event(void* context, SceneManagerEve } void nfc_scene_mf_ultralight_unlock_menu_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; submenu_reset(nfc->submenu); } diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c index 16efae9deaeb..4c8a1c90ff93 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c @@ -1,14 +1,14 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" #include void nfc_scene_mf_ultralight_unlock_warn_dialog_callback(DialogExResult result, void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } void nfc_scene_mf_ultralight_unlock_warn_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; DialogEx* dialog_ex = nfc->dialog_ex; MfUltralightAuthMethod auth_method = nfc->dev->dev_data.mf_ul_data.auth_method; @@ -52,7 +52,7 @@ void nfc_scene_mf_ultralight_unlock_warn_on_enter(void* context) { } bool nfc_scene_mf_ultralight_unlock_warn_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; @@ -89,7 +89,7 @@ bool nfc_scene_mf_ultralight_unlock_warn_on_event(void* context, SceneManagerEve } void nfc_scene_mf_ultralight_unlock_warn_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; dialog_ex_reset(nfc->dialog_ex); nfc_text_store_clear(nfc); diff --git a/applications/main/nfc/scenes/nfc_scene_mfkey_complete.c b/applications/main/nfc/scenes/nfc_scene_mfkey_complete.c index 3c4f9dba19e5..2f4bba319218 100644 --- a/applications/main/nfc/scenes/nfc_scene_mfkey_complete.c +++ b/applications/main/nfc/scenes/nfc_scene_mfkey_complete.c @@ -1,14 +1,14 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" void nfc_scene_mfkey_complete_callback(GuiButtonType result, InputType type, void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } } void nfc_scene_mfkey_complete_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; widget_add_string_element(nfc->widget, 64, 0, AlignCenter, AlignTop, FontPrimary, "Complete!"); widget_add_string_multiline_element( @@ -26,7 +26,7 @@ void nfc_scene_mfkey_complete_on_enter(void* context) { } bool nfc_scene_mfkey_complete_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -43,7 +43,7 @@ bool nfc_scene_mfkey_complete_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_mfkey_complete_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; widget_reset(nfc->widget); } \ No newline at end of file diff --git a/applications/main/nfc/scenes/nfc_scene_mfkey_nonces_info.c b/applications/main/nfc/scenes/nfc_scene_mfkey_nonces_info.c index 6d9852f3e666..5e86f2376fdb 100644 --- a/applications/main/nfc/scenes/nfc_scene_mfkey_nonces_info.c +++ b/applications/main/nfc/scenes/nfc_scene_mfkey_nonces_info.c @@ -1,15 +1,15 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" #include void nfc_scene_mfkey_nonces_info_callback(GuiButtonType result, InputType type, void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } } void nfc_scene_mfkey_nonces_info_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; FuriString* temp_str; temp_str = furi_string_alloc(); @@ -31,7 +31,7 @@ void nfc_scene_mfkey_nonces_info_on_enter(void* context) { } bool nfc_scene_mfkey_nonces_info_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -48,7 +48,7 @@ bool nfc_scene_mfkey_nonces_info_on_event(void* context, SceneManagerEvent event } void nfc_scene_mfkey_nonces_info_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Clear view widget_reset(nfc->widget); 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 92ad7b56ef41..975117532aac 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c +++ b/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c @@ -1,14 +1,14 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" void nfc_scene_nfc_data_info_widget_callback(GuiButtonType result, InputType type, void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } } void nfc_scene_nfc_data_info_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; Widget* widget = nfc->widget; FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data; NfcDeviceData* dev_data = &nfc->dev->dev_data; @@ -125,7 +125,7 @@ void nfc_scene_nfc_data_info_on_enter(void* context) { } bool nfc_scene_nfc_data_info_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; NfcProtocol protocol = nfc->dev->dev_data.protocol; bool consumed = false; @@ -148,7 +148,7 @@ bool nfc_scene_nfc_data_info_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_nfc_data_info_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; widget_reset(nfc->widget); } diff --git a/applications/main/nfc/scenes/nfc_scene_nfca_menu.c b/applications/main/nfc/scenes/nfc_scene_nfca_menu.c index 30f63945c622..702325a782bb 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfca_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_nfca_menu.c @@ -1,4 +1,4 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" #include enum SubmenuIndex { @@ -8,13 +8,13 @@ enum SubmenuIndex { }; void nfc_scene_nfca_menu_submenu_callback(void* context, uint32_t index) { - Nfc* nfc = context; + NfcApp* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_nfca_menu_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; Submenu* submenu = nfc->submenu; submenu_add_item( @@ -30,7 +30,7 @@ void nfc_scene_nfca_menu_on_enter(void* context) { } bool nfc_scene_nfca_menu_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -61,7 +61,7 @@ bool nfc_scene_nfca_menu_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_nfca_menu_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Clear view submenu_reset(nfc->submenu); diff --git a/applications/main/nfc/scenes/nfc_scene_nfca_read_success.c b/applications/main/nfc/scenes/nfc_scene_nfca_read_success.c index a38f31a9813c..089ee067c11f 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfca_read_success.c +++ b/applications/main/nfc/scenes/nfc_scene_nfca_read_success.c @@ -1,11 +1,11 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" void nfc_scene_nfca_read_success_widget_callback( GuiButtonType result, InputType type, void* context) { furi_assert(context); - Nfc* nfc = context; + NfcApp* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); @@ -13,7 +13,7 @@ void nfc_scene_nfca_read_success_widget_callback( } void nfc_scene_nfca_read_success_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Setup view FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; @@ -45,7 +45,7 @@ void nfc_scene_nfca_read_success_on_enter(void* context) { } bool nfc_scene_nfca_read_success_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -64,7 +64,7 @@ bool nfc_scene_nfca_read_success_on_event(void* context, SceneManagerEvent event } void nfc_scene_nfca_read_success_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; notification_message_block(nfc->notifications, &sequence_reset_green); diff --git a/applications/main/nfc/scenes/nfc_scene_read.c b/applications/main/nfc/scenes/nfc_scene_read.c index 4252883b255f..ddb18706cbbc 100644 --- a/applications/main/nfc/scenes/nfc_scene_read.c +++ b/applications/main/nfc/scenes/nfc_scene_read.c @@ -1,4 +1,4 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" #include typedef enum { @@ -8,7 +8,7 @@ typedef enum { } NfcSceneReadState; bool nfc_scene_read_worker_callback(NfcWorkerEvent event, void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; if(event == NfcWorkerEventReadMfClassicLoadKeyCache) { consumed = nfc_device_load_key_cache(nfc->dev); @@ -19,7 +19,7 @@ bool nfc_scene_read_worker_callback(NfcWorkerEvent event, void* context) { return consumed; } -void nfc_scene_read_set_state(Nfc* nfc, NfcSceneReadState state) { +void nfc_scene_read_set_state(NfcApp* nfc, NfcSceneReadState state) { uint32_t curr_state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneRead); if(curr_state != state) { if(state == NfcSceneReadStateDetecting) { @@ -38,7 +38,7 @@ void nfc_scene_read_set_state(Nfc* nfc, NfcSceneReadState state) { } void nfc_scene_read_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; nfc_device_clear(nfc->dev); // Setup view @@ -52,7 +52,7 @@ void nfc_scene_read_on_enter(void* context) { } bool nfc_scene_read_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -111,7 +111,7 @@ bool nfc_scene_read_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_read_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Stop worker nfc_worker_stop(nfc->worker); diff --git a/applications/main/nfc/scenes/nfc_scene_read_card_success.c b/applications/main/nfc/scenes/nfc_scene_read_card_success.c index ee80ee768837..009de9c966fd 100644 --- a/applications/main/nfc/scenes/nfc_scene_read_card_success.c +++ b/applications/main/nfc/scenes/nfc_scene_read_card_success.c @@ -1,11 +1,11 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" void nfc_scene_read_card_success_widget_callback( GuiButtonType result, InputType type, void* context) { furi_assert(context); - Nfc* nfc = context; + NfcApp* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); @@ -13,7 +13,7 @@ void nfc_scene_read_card_success_widget_callback( } void nfc_scene_read_card_success_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; FuriString* temp_str; temp_str = furi_string_alloc(); @@ -39,7 +39,7 @@ void nfc_scene_read_card_success_on_enter(void* context) { } bool nfc_scene_read_card_success_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -54,7 +54,7 @@ bool nfc_scene_read_card_success_on_event(void* context, SceneManagerEvent event } void nfc_scene_read_card_success_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Clear view widget_reset(nfc->widget); diff --git a/applications/main/nfc/scenes/nfc_scene_read_card_type.c b/applications/main/nfc/scenes/nfc_scene_read_card_type.c index 94262aa1e045..d763f2f723df 100644 --- a/applications/main/nfc/scenes/nfc_scene_read_card_type.c +++ b/applications/main/nfc/scenes/nfc_scene_read_card_type.c @@ -1,4 +1,4 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" #include "nfc_worker_i.h" enum SubmenuIndex { @@ -10,13 +10,13 @@ enum SubmenuIndex { }; void nfc_scene_read_card_type_submenu_callback(void* context, uint32_t index) { - Nfc* nfc = context; + NfcApp* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_read_card_type_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; Submenu* submenu = nfc->submenu; submenu_add_item( @@ -56,7 +56,7 @@ void nfc_scene_read_card_type_on_enter(void* context) { } bool nfc_scene_read_card_type_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -91,7 +91,7 @@ bool nfc_scene_read_card_type_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_read_card_type_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; submenu_reset(nfc->submenu); } diff --git a/applications/main/nfc/scenes/nfc_scene_restore_original.c b/applications/main/nfc/scenes/nfc_scene_restore_original.c index 3ecf5c048e41..f059eeac497b 100644 --- a/applications/main/nfc/scenes/nfc_scene_restore_original.c +++ b/applications/main/nfc/scenes/nfc_scene_restore_original.c @@ -1,12 +1,12 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" void nfc_scene_restore_original_popup_callback(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); } void nfc_scene_restore_original_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Setup view Popup* popup = nfc->popup; @@ -20,7 +20,7 @@ void nfc_scene_restore_original_on_enter(void* context) { } bool nfc_scene_restore_original_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -38,7 +38,7 @@ bool nfc_scene_restore_original_on_event(void* context, SceneManagerEvent event) } void nfc_scene_restore_original_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Clear view popup_reset(nfc->popup); diff --git a/applications/main/nfc/scenes/nfc_scene_restore_original_confirm.c b/applications/main/nfc/scenes/nfc_scene_restore_original_confirm.c index 730dd41e858b..e396049aed90 100644 --- a/applications/main/nfc/scenes/nfc_scene_restore_original_confirm.c +++ b/applications/main/nfc/scenes/nfc_scene_restore_original_confirm.c @@ -1,13 +1,13 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" void nfc_scene_restore_original_confirm_dialog_callback(DialogExResult result, void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } void nfc_scene_restore_original_confirm_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; DialogEx* dialog_ex = nfc->dialog_ex; dialog_ex_set_header(dialog_ex, "Restore Card Data?", 64, 0, AlignCenter, AlignTop); @@ -23,7 +23,7 @@ void nfc_scene_restore_original_confirm_on_enter(void* context) { } bool nfc_scene_restore_original_confirm_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -46,7 +46,7 @@ bool nfc_scene_restore_original_confirm_on_event(void* context, SceneManagerEven } void nfc_scene_restore_original_confirm_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Clean view dialog_ex_reset(nfc->dialog_ex); diff --git a/applications/main/nfc/scenes/nfc_scene_retry_confirm.c b/applications/main/nfc/scenes/nfc_scene_retry_confirm.c index 5f4f7985e777..9f37c41588b5 100644 --- a/applications/main/nfc/scenes/nfc_scene_retry_confirm.c +++ b/applications/main/nfc/scenes/nfc_scene_retry_confirm.c @@ -1,13 +1,13 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" void nfc_scene_retry_confirm_dialog_callback(DialogExResult result, void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } void nfc_scene_retry_confirm_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; DialogEx* dialog_ex = nfc->dialog_ex; dialog_ex_set_left_button_text(dialog_ex, "Retry"); @@ -22,7 +22,7 @@ void nfc_scene_retry_confirm_on_enter(void* context) { } bool nfc_scene_retry_confirm_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -40,7 +40,7 @@ bool nfc_scene_retry_confirm_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_retry_confirm_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Clean view dialog_ex_reset(nfc->dialog_ex); diff --git a/applications/main/nfc/scenes/nfc_scene_rpc.c b/applications/main/nfc/scenes/nfc_scene_rpc.c index 60d01a30da66..ee6e8b990a9c 100644 --- a/applications/main/nfc/scenes/nfc_scene_rpc.c +++ b/applications/main/nfc/scenes/nfc_scene_rpc.c @@ -1,7 +1,7 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" void nfc_scene_rpc_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; Popup* popup = nfc->popup; popup_set_header(popup, "NFC", 89, 42, AlignCenter, AlignBottom); @@ -16,14 +16,14 @@ void nfc_scene_rpc_on_enter(void* context) { static bool nfc_scene_rpc_emulate_callback(NfcWorkerEvent event, void* context) { UNUSED(event); - Nfc* nfc = context; + NfcApp* nfc = context; nfc->rpc_state = NfcRpcStateEmulated; return true; } bool nfc_scene_rpc_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; Popup* popup = nfc->popup; bool consumed = false; @@ -75,7 +75,7 @@ bool nfc_scene_rpc_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_rpc_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; Popup* popup = nfc->popup; nfc_blink_stop(nfc); diff --git a/applications/main/nfc/scenes/nfc_scene_save_name.c b/applications/main/nfc/scenes/nfc_scene_save_name.c index 00727422676c..41fbb8833de3 100644 --- a/applications/main/nfc/scenes/nfc_scene_save_name.c +++ b/applications/main/nfc/scenes/nfc_scene_save_name.c @@ -1,17 +1,17 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" #include #include #include #include void nfc_scene_save_name_text_input_callback(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventTextInputDone); } void nfc_scene_save_name_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Setup view TextInput* text_input = nfc->text_input; @@ -50,7 +50,7 @@ void nfc_scene_save_name_on_enter(void* context) { } bool nfc_scene_save_name_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -82,7 +82,7 @@ bool nfc_scene_save_name_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_save_name_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Clear view void* validator_context = text_input_get_validator_callback_context(nfc->text_input); diff --git a/applications/main/nfc/scenes/nfc_scene_save_success.c b/applications/main/nfc/scenes/nfc_scene_save_success.c index 34919cbd863a..4c19f2f42e0f 100644 --- a/applications/main/nfc/scenes/nfc_scene_save_success.c +++ b/applications/main/nfc/scenes/nfc_scene_save_success.c @@ -1,12 +1,12 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" void nfc_scene_save_success_popup_callback(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); } void nfc_scene_save_success_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Setup view Popup* popup = nfc->popup; @@ -20,7 +20,7 @@ void nfc_scene_save_success_on_enter(void* context) { } bool nfc_scene_save_success_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -41,7 +41,7 @@ bool nfc_scene_save_success_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_save_success_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Clear view popup_reset(nfc->popup); diff --git a/applications/main/nfc/scenes/nfc_scene_saved_menu.c b/applications/main/nfc/scenes/nfc_scene_saved_menu.c index ba1f96539848..987911d79fff 100644 --- a/applications/main/nfc/scenes/nfc_scene_saved_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_saved_menu.c @@ -1,4 +1,4 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" #include enum SubmenuIndex { @@ -16,13 +16,13 @@ enum SubmenuIndex { }; void nfc_scene_saved_menu_submenu_callback(void* context, uint32_t index) { - Nfc* nfc = context; + NfcApp* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_saved_menu_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; Submenu* submenu = nfc->submenu; if(nfc->dev->format == NfcDeviceSaveFormatUid || @@ -105,7 +105,7 @@ void nfc_scene_saved_menu_on_enter(void* context) { } bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; NfcDeviceData* dev_data = &nfc->dev->dev_data; bool consumed = false; @@ -174,7 +174,7 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_saved_menu_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; submenu_reset(nfc->submenu); } diff --git a/applications/main/nfc/scenes/nfc_scene_set_atqa.c b/applications/main/nfc/scenes/nfc_scene_set_atqa.c index d079b3804754..4e0e11e7877c 100644 --- a/applications/main/nfc/scenes/nfc_scene_set_atqa.c +++ b/applications/main/nfc/scenes/nfc_scene_set_atqa.c @@ -1,13 +1,13 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" void nfc_scene_set_atqa_byte_input_callback(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); } void nfc_scene_set_atqa_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Setup view ByteInput* byte_input = nfc->byte_input; @@ -23,7 +23,7 @@ void nfc_scene_set_atqa_on_enter(void* context) { } bool nfc_scene_set_atqa_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -36,7 +36,7 @@ bool nfc_scene_set_atqa_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_set_atqa_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Clear view byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0); diff --git a/applications/main/nfc/scenes/nfc_scene_set_sak.c b/applications/main/nfc/scenes/nfc_scene_set_sak.c index 60a1e1494b84..2c4a230cc4f5 100644 --- a/applications/main/nfc/scenes/nfc_scene_set_sak.c +++ b/applications/main/nfc/scenes/nfc_scene_set_sak.c @@ -1,13 +1,13 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" void nfc_scene_set_sak_byte_input_callback(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); } void nfc_scene_set_sak_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Setup view ByteInput* byte_input = nfc->byte_input; @@ -23,7 +23,7 @@ void nfc_scene_set_sak_on_enter(void* context) { } bool nfc_scene_set_sak_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -36,7 +36,7 @@ bool nfc_scene_set_sak_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_set_sak_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Clear view byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0); diff --git a/applications/main/nfc/scenes/nfc_scene_set_type.c b/applications/main/nfc/scenes/nfc_scene_set_type.c index cadf2eb69ef3..9e417939d62f 100644 --- a/applications/main/nfc/scenes/nfc_scene_set_type.c +++ b/applications/main/nfc/scenes/nfc_scene_set_type.c @@ -1,4 +1,4 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" #include "lib/nfc/helpers/nfc_generators.h" enum SubmenuIndex { @@ -8,13 +8,13 @@ enum SubmenuIndex { }; void nfc_scene_set_type_submenu_callback(void* context, uint32_t index) { - Nfc* nfc = context; + NfcApp* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_set_type_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; Submenu* submenu = nfc->submenu; // Clear device name nfc_device_set_name(nfc->dev, ""); @@ -35,7 +35,7 @@ void nfc_scene_set_type_on_enter(void* context) { } bool nfc_scene_set_type_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -62,7 +62,7 @@ bool nfc_scene_set_type_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_set_type_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; submenu_reset(nfc->submenu); } diff --git a/applications/main/nfc/scenes/nfc_scene_set_uid.c b/applications/main/nfc/scenes/nfc_scene_set_uid.c index 54606b68eec7..4c2dc7d04931 100644 --- a/applications/main/nfc/scenes/nfc_scene_set_uid.c +++ b/applications/main/nfc/scenes/nfc_scene_set_uid.c @@ -1,13 +1,13 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" void nfc_scene_set_uid_byte_input_callback(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); } void nfc_scene_set_uid_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Setup view ByteInput* byte_input = nfc->byte_input; @@ -24,7 +24,7 @@ void nfc_scene_set_uid_on_enter(void* context) { } bool nfc_scene_set_uid_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = (Nfc*)context; + NfcApp* nfc = (NfcApp*)context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -46,7 +46,7 @@ bool nfc_scene_set_uid_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_set_uid_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; // Clear view byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0); diff --git a/applications/main/nfc/scenes/nfc_scene_start.c b/applications/main/nfc/scenes/nfc_scene_start.c index a01f871ab6ad..d528e2bb6801 100644 --- a/applications/main/nfc/scenes/nfc_scene_start.c +++ b/applications/main/nfc/scenes/nfc_scene_start.c @@ -1,4 +1,4 @@ -#include "../nfc_i.h" +#include "../nfc_app_i.h" #include "nfc_worker_i.h" #include @@ -12,13 +12,13 @@ enum SubmenuIndex { }; void nfc_scene_start_submenu_callback(void* context, uint32_t index) { - Nfc* nfc = context; + NfcApp* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_start_on_enter(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; Submenu* submenu = nfc->submenu; submenu_add_item(submenu, "Read", SubmenuIndexRead, nfc_scene_start_submenu_callback, nfc); @@ -43,7 +43,7 @@ void nfc_scene_start_on_enter(void* context) { } bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = context; + NfcApp* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -92,7 +92,7 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_start_on_exit(void* context) { - Nfc* nfc = context; + NfcApp* nfc = context; submenu_reset(nfc->submenu); } From 30ffca42a5646a3590b7f3fb370ebd0f4adeb075 Mon Sep 17 00:00:00 2001 From: gornekich Date: Thu, 23 Mar 2023 16:41:54 +0400 Subject: [PATCH 002/149] nfc: introduce new hal --- firmware/targets/f7/api_symbols.csv | 55 + firmware/targets/f7/furi_hal/f_hal_nfc.c | 437 +++++++ .../targets/f7/furi_hal/f_hal_nfc_event.c | 118 ++ firmware/targets/f7/furi_hal/f_hal_nfc_i.h | 51 + firmware/targets/f7/furi_hal/f_hal_nfc_irq.c | 27 + .../targets/f7/furi_hal/f_hal_nfc_timer.c | 143 +++ firmware/targets/f7/furi_hal/f_hal_nfca.c | 101 ++ firmware/targets/f7/furi_hal/furi_hal.c | 3 +- firmware/targets/f7/furi_hal/furi_hal_nfc.c | 4 +- .../targets/f7/furi_hal/furi_hal_target_hw.h | 2 +- firmware/targets/f7/target.json | 3 +- firmware/targets/furi_hal_include/f_hal_nfc.h | 143 +++ lib/drivers/st25r3916.c | 77 ++ lib/drivers/st25r3916.h | 102 ++ lib/drivers/st25r3916_reg.c | 258 ++++ lib/drivers/st25r3916_reg.h | 1087 +++++++++++++++++ 16 files changed, 2606 insertions(+), 5 deletions(-) create mode 100644 firmware/targets/f7/furi_hal/f_hal_nfc.c create mode 100644 firmware/targets/f7/furi_hal/f_hal_nfc_event.c create mode 100644 firmware/targets/f7/furi_hal/f_hal_nfc_i.h create mode 100644 firmware/targets/f7/furi_hal/f_hal_nfc_irq.c create mode 100644 firmware/targets/f7/furi_hal/f_hal_nfc_timer.c create mode 100644 firmware/targets/f7/furi_hal/f_hal_nfca.c create mode 100644 firmware/targets/furi_hal_include/f_hal_nfc.h create mode 100644 lib/drivers/st25r3916.c create mode 100644 lib/drivers/st25r3916.h create mode 100644 lib/drivers/st25r3916_reg.c create mode 100644 lib/drivers/st25r3916_reg.h diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 8b1d29b1ce43..88c449d87e7e 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -58,6 +58,7 @@ Header,+,firmware/targets/f7/furi_hal/furi_hal_target_hw.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_uart.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_usb_cdc.h,, Header,+,firmware/targets/f7/platform_specific/intrinsic_export.h,, +Header,+,firmware/targets/furi_hal_include/f_hal_nfc.h,, Header,+,firmware/targets/furi_hal_include/furi_hal.h,, Header,+,firmware/targets/furi_hal_include/furi_hal_bt.h,, Header,+,firmware/targets/furi_hal_include/furi_hal_bt_hid.h,, @@ -168,6 +169,9 @@ Header,+,lib/mlib/m-list.h,, Header,+,lib/mlib/m-rbtree.h,, Header,+,lib/mlib/m-tuple.h,, Header,+,lib/mlib/m-variant.h,, +Header,+,lib/nanopb/pb.h,, +Header,+,lib/nanopb/pb_decode.h,, +Header,+,lib/nanopb/pb_encode.h,, Header,+,lib/nfc/nfc_device.h,, Header,+,lib/one_wire/maxim_crc.h,, Header,+,lib/one_wire/one_wire_host.h,, @@ -811,6 +815,27 @@ Function,-,explicit_bzero,void,"void*, size_t" Function,-,expm1,double,double Function,-,expm1f,float,float Function,-,expm1l,long double,long double +Function,-,f_hal_nfc_init,FHalNfcError, +Function,-,f_hal_nfc_listen_start,FHalNfcError, +Function,-,f_hal_nfc_low_power_mode_start,FHalNfcError, +Function,-,f_hal_nfc_low_power_mode_stop,FHalNfcError, +Function,-,f_hal_nfc_poller_field_on,FHalNfcError, +Function,-,f_hal_nfc_poller_rx,FHalNfcError,"uint8_t*, uint16_t, uint16_t*" +Function,-,f_hal_nfc_poller_tx,FHalNfcError,"uint8_t*, uint16_t" +Function,-,f_hal_nfc_set_callback,void,"FHalNfcCallback, void*" +Function,-,f_hal_nfc_set_mask_receive_timer,void,uint32_t +Function,-,f_hal_nfc_set_mode,FHalNfcError,"FHalNfcMode, FHalNfcBitrate" +Function,-,f_hal_nfc_timer_block_tx_is_running,_Bool, +Function,-,f_hal_nfc_timer_block_tx_start,void,uint32_t +Function,-,f_hal_nfc_timer_block_tx_start_us,void,uint32_t +Function,-,f_hal_nfc_timer_block_tx_stop,void, +Function,-,f_hal_nfc_timer_fwt_start,void,uint32_t +Function,-,f_hal_nfc_timer_fwt_stop,void, +Function,-,f_hal_nfc_trx_reset,FHalNfcError, +Function,-,f_hal_nfc_wait_event,FHalNfcEvent,uint32_t +Function,-,f_hal_nfca_receive_sdd_frame,FHalNfcError,"uint8_t*, uint16_t, uint16_t*" +Function,-,f_hal_nfca_send_sdd_frame,FHalNfcError,"uint8_t*, uint16_t" +Function,-,f_hal_nfca_send_short_frame,FHalNfcError,FHalNfcaShortFrame Function,-,fabs,double,double Function,-,fabsf,float,float Function,-,fabsl,long double,long double @@ -1206,6 +1231,7 @@ Function,+,furi_hal_nfc_stop,void, Function,+,furi_hal_nfc_stop_cmd,void, Function,+,furi_hal_nfc_tx_rx,_Bool,"FuriHalNfcTxRxContext*, uint16_t" Function,+,furi_hal_nfc_tx_rx_full,_Bool,FuriHalNfcTxRxContext* +Function,-,furi_hal_nfca_set_col_res_data,FHalNfcError,"uint8_t*, uint8_t, uint8_t*, uint8_t" Function,-,furi_hal_os_init,void, Function,+,furi_hal_os_tick,void, Function,+,furi_hal_power_check_otg_status,void, @@ -2083,6 +2109,35 @@ Function,+,path_extract_dirname,void,"const char*, FuriString*" Function,+,path_extract_extension,void,"FuriString*, char*, size_t" Function,+,path_extract_filename,void,"FuriString*, FuriString*, _Bool" Function,+,path_extract_filename_no_ext,void,"const char*, FuriString*" +Function,+,pb_close_string_substream,_Bool,"pb_istream_t*, pb_istream_t*" +Function,+,pb_decode,_Bool,"pb_istream_t*, const pb_msgdesc_t*, void*" +Function,+,pb_decode_bool,_Bool,"pb_istream_t*, _Bool*" +Function,+,pb_decode_ex,_Bool,"pb_istream_t*, const pb_msgdesc_t*, void*, unsigned int" +Function,+,pb_decode_fixed32,_Bool,"pb_istream_t*, void*" +Function,+,pb_decode_fixed64,_Bool,"pb_istream_t*, void*" +Function,+,pb_decode_svarint,_Bool,"pb_istream_t*, int64_t*" +Function,+,pb_decode_tag,_Bool,"pb_istream_t*, pb_wire_type_t*, uint32_t*, _Bool*" +Function,+,pb_decode_varint,_Bool,"pb_istream_t*, uint64_t*" +Function,+,pb_decode_varint32,_Bool,"pb_istream_t*, uint32_t*" +Function,+,pb_default_field_callback,_Bool,"pb_istream_t*, pb_ostream_t*, const pb_field_t*" +Function,+,pb_encode,_Bool,"pb_ostream_t*, const pb_msgdesc_t*, const void*" +Function,+,pb_encode_ex,_Bool,"pb_ostream_t*, const pb_msgdesc_t*, const void*, unsigned int" +Function,+,pb_encode_fixed32,_Bool,"pb_ostream_t*, const void*" +Function,+,pb_encode_fixed64,_Bool,"pb_ostream_t*, const void*" +Function,+,pb_encode_string,_Bool,"pb_ostream_t*, const pb_byte_t*, size_t" +Function,+,pb_encode_submessage,_Bool,"pb_ostream_t*, const pb_msgdesc_t*, const void*" +Function,+,pb_encode_svarint,_Bool,"pb_ostream_t*, int64_t" +Function,+,pb_encode_tag,_Bool,"pb_ostream_t*, pb_wire_type_t, uint32_t" +Function,+,pb_encode_tag_for_field,_Bool,"pb_ostream_t*, const pb_field_iter_t*" +Function,+,pb_encode_varint,_Bool,"pb_ostream_t*, uint64_t" +Function,+,pb_get_encoded_size,_Bool,"size_t*, const pb_msgdesc_t*, const void*" +Function,+,pb_istream_from_buffer,pb_istream_t,"const pb_byte_t*, size_t" +Function,+,pb_make_string_substream,_Bool,"pb_istream_t*, pb_istream_t*" +Function,+,pb_ostream_from_buffer,pb_ostream_t,"pb_byte_t*, size_t" +Function,+,pb_read,_Bool,"pb_istream_t*, pb_byte_t*, size_t" +Function,+,pb_release,void,"const pb_msgdesc_t*, void*" +Function,+,pb_skip_field,_Bool,"pb_istream_t*, pb_wire_type_t" +Function,+,pb_write,_Bool,"pb_ostream_t*, const pb_byte_t*, size_t" Function,-,pcTaskGetName,char*,TaskHandle_t Function,-,pcTimerGetName,const char*,TimerHandle_t Function,-,pclose,int,FILE* diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc.c b/firmware/targets/f7/furi_hal/f_hal_nfc.c new file mode 100644 index 000000000000..0aacac2d56b6 --- /dev/null +++ b/firmware/targets/f7/furi_hal/f_hal_nfc.c @@ -0,0 +1,437 @@ +#include "f_hal_nfc_i.h" + +#include + +#include +#include + +#define TAG "FHalNfc" + +static FHalNfcError f_hal_nfc_turn_on_osc(FuriHalSpiBusHandle* handle) { + FHalNfcError error = FHalNfcErrorNone; + + if(!st25r3916_check_reg( + handle, + ST25R3916_REG_OP_CONTROL, + ST25R3916_REG_OP_CONTROL_en, + ST25R3916_REG_OP_CONTROL_en)) { + st25r3916_mask_irq(handle, ~ST25R3916_IRQ_MASK_OSC); + st25r3916_set_reg_bits(handle, ST25R3916_REG_OP_CONTROL, ST25R3916_REG_OP_CONTROL_en); + f_hal_nfc_event_wait_for_specific_irq(handle, ST25R3916_IRQ_MASK_OSC, 10); + } + // Disable IRQs + st25r3916_mask_irq(handle, ST25R3916_IRQ_MASK_ALL); + + bool osc_on = st25r3916_check_reg( + handle, + ST25R3916_REG_AUX_DISPLAY, + ST25R3916_REG_AUX_DISPLAY_osc_ok, + ST25R3916_REG_AUX_DISPLAY_osc_ok); + if(!osc_on) { + error = FHalNfcErrorOscillator; + } + + return error; +} + +FHalNfcError f_hal_nfc_init() { + FHalNfcError error = FHalNfcErrorNone; + f_hal_nfc_event_init(); + + FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; + furi_hal_spi_acquire(handle); + + do { + // Set default state + st25r3916_direct_cmd(handle, ST25R3916_CMD_SET_DEFAULT); + // Increase IO driver strength of MISO and IRQ + st25r3916_write_reg(handle, ST25R3916_REG_IO_CONF2, ST25R3916_REG_IO_CONF2_io_drv_lvl); + // Check chip ID + uint8_t chip_id = 0; + st25r3916_read_reg(handle, ST25R3916_REG_IC_IDENTITY, &chip_id); + if((chip_id & ST25R3916_REG_IC_IDENTITY_ic_type_mask) != + ST25R3916_REG_IC_IDENTITY_ic_type_st25r3916) { + FURI_LOG_E(TAG, "Wrong chip id"); + error = FHalNfcErrorCommunication; + } + // Clear interrupts + st25r3916_get_irq(handle); + // Mask all interrupts + st25r3916_mask_irq(handle, ST25R3916_IRQ_MASK_ALL); + // Enable interrupts + f_hal_nfc_init_gpio_isr(); + // Disable internal overheat protection + st25r3916_change_test_reg_bits(handle, 0x04, 0x10, 0x10); + + error = f_hal_nfc_turn_on_osc(handle); + if(error != FHalNfcErrorNone) break; + + // Measure voltage + // Set measure power supply voltage source + st25r3916_change_reg_bits( + handle, + ST25R3916_REG_REGULATOR_CONTROL, + ST25R3916_REG_REGULATOR_CONTROL_mpsv_mask, + ST25R3916_REG_REGULATOR_CONTROL_mpsv_vdd); + // Enable timer and interrupt register + st25r3916_mask_irq(handle, ~ST25R3916_IRQ_MASK_DCT); + st25r3916_direct_cmd(handle, ST25R3916_CMD_MEASURE_VDD); + f_hal_nfc_event_wait_for_specific_irq(handle, ST25R3916_IRQ_MASK_DCT, 100); + st25r3916_mask_irq(handle, ST25R3916_IRQ_MASK_ALL); + uint8_t ad_res = 0; + st25r3916_read_reg(handle, ST25R3916_REG_AD_RESULT, &ad_res); + uint16_t mV = ((uint16_t)ad_res) * 23U; + mV += (((((uint16_t)ad_res) * 4U) + 5U) / 10U); + + if(mV < 3600) { + st25r3916_change_reg_bits( + handle, + ST25R3916_REG_IO_CONF2, + ST25R3916_REG_IO_CONF2_sup3V, + ST25R3916_REG_IO_CONF2_sup3V_3V); + } else { + st25r3916_change_reg_bits( + handle, + ST25R3916_REG_IO_CONF2, + ST25R3916_REG_IO_CONF2_sup3V, + ST25R3916_REG_IO_CONF2_sup3V_5V); + } + + // Disable MCU CLK + st25r3916_change_reg_bits( + handle, + ST25R3916_REG_IO_CONF1, + ST25R3916_REG_IO_CONF1_out_cl_mask | ST25R3916_REG_IO_CONF1_lf_clk_off, + 0x07); + // Disable MISO pull-down + st25r3916_change_reg_bits( + handle, + ST25R3916_REG_IO_CONF2, + ST25R3916_REG_IO_CONF2_miso_pd1 | ST25R3916_REG_IO_CONF2_miso_pd2, + 0x00); + // Set tx driver resistance to 1 Om + st25r3916_change_reg_bits( + handle, ST25R3916_REG_TX_DRIVER, ST25R3916_REG_TX_DRIVER_d_res_mask, 0x00); + // Use minimum non-overlap + st25r3916_change_reg_bits( + handle, + ST25R3916_REG_RES_AM_MOD, + ST25R3916_REG_RES_AM_MOD_fa3_f, + ST25R3916_REG_RES_AM_MOD_fa3_f); + + // Set activation threashold + st25r3916_change_reg_bits( + handle, + ST25R3916_REG_FIELD_THRESHOLD_ACTV, + ST25R3916_REG_FIELD_THRESHOLD_ACTV_trg_mask, + ST25R3916_REG_FIELD_THRESHOLD_ACTV_trg_105mV); + st25r3916_change_reg_bits( + handle, + ST25R3916_REG_FIELD_THRESHOLD_ACTV, + ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_mask, + ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_105mV); + // Set deactivation threashold + st25r3916_change_reg_bits( + handle, + ST25R3916_REG_FIELD_THRESHOLD_DEACTV, + ST25R3916_REG_FIELD_THRESHOLD_DEACTV_trg_mask, + ST25R3916_REG_FIELD_THRESHOLD_DEACTV_trg_75mV); + st25r3916_change_reg_bits( + handle, + ST25R3916_REG_FIELD_THRESHOLD_DEACTV, + ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_mask, + ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_75mV); + // Enable external load modulation + st25r3916_change_reg_bits( + handle, + ST25R3916_REG_AUX_MOD, + ST25R3916_REG_AUX_MOD_lm_ext, + ST25R3916_REG_AUX_MOD_lm_ext); + // Enable internal load modulation + st25r3916_change_reg_bits( + handle, + ST25R3916_REG_AUX_MOD, + ST25R3916_REG_AUX_MOD_lm_dri, + ST25R3916_REG_AUX_MOD_lm_dri); + // Adjust FDT + st25r3916_change_reg_bits( + handle, + ST25R3916_REG_PASSIVE_TARGET, + ST25R3916_REG_PASSIVE_TARGET_fdel_mask, + (5U << ST25R3916_REG_PASSIVE_TARGET_fdel_shift)); + // Reduce RFO resistance in Modulated state + st25r3916_change_reg_bits( + handle, + ST25R3916_REG_PT_MOD, + ST25R3916_REG_PT_MOD_ptm_res_mask | ST25R3916_REG_PT_MOD_pt_res_mask, + 0x0f); + // Enable RX start on first 4 bits + st25r3916_change_reg_bits( + handle, + ST25R3916_REG_EMD_SUP_CONF, + ST25R3916_REG_EMD_SUP_CONF_rx_start_emv, + ST25R3916_REG_EMD_SUP_CONF_rx_start_emv_on); + // Set antena tunning + st25r3916_change_reg_bits(handle, ST25R3916_REG_ANT_TUNE_A, 0xff, 0x82); + st25r3916_change_reg_bits(handle, ST25R3916_REG_ANT_TUNE_B, 0xff, 0x82); + st25r3916_change_reg_bits( + handle, + ST25R3916_REG_OP_CONTROL, + ST25R3916_REG_OP_CONTROL_en_fd_mask, + ST25R3916_REG_OP_CONTROL_en_fd_auto_efd); + + // Perform calibration + if(st25r3916_check_reg( + handle, + ST25R3916_REG_REGULATOR_CONTROL, + ST25R3916_REG_REGULATOR_CONTROL_reg_s, + 0x00)) { + FURI_LOG_I(TAG, "Adjusting regulators"); + // Reset logic + st25r3916_set_reg_bits( + handle, ST25R3916_REG_REGULATOR_CONTROL, ST25R3916_REG_REGULATOR_CONTROL_reg_s); + st25r3916_clear_reg_bits( + handle, ST25R3916_REG_REGULATOR_CONTROL, ST25R3916_REG_REGULATOR_CONTROL_reg_s); + st25r3916_direct_cmd(handle, ST25R3916_CMD_ADJUST_REGULATORS); + furi_delay_ms(6); + } + + furi_hal_spi_release(&furi_hal_spi_bus_handle_nfc); + } while(false); + + f_hal_nfc_low_power_mode_start(); + + return error; +} + +void f_hal_nfc_set_callback(FHalNfcCallback callback, void* context) { + furi_assert(callback); + + f_hal_nfc_event_set_callback(callback, context); +} + +FHalNfcError f_hal_nfc_low_power_mode_start() { + FHalNfcError error = FHalNfcErrorNone; + FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; + furi_hal_spi_acquire(handle); + + st25r3916_direct_cmd(handle, ST25R3916_CMD_STOP); + st25r3916_clear_reg_bits( + handle, + ST25R3916_REG_OP_CONTROL, + (ST25R3916_REG_OP_CONTROL_en | ST25R3916_REG_OP_CONTROL_rx_en | + ST25R3916_REG_OP_CONTROL_wu | ST25R3916_REG_OP_CONTROL_tx_en | + ST25R3916_REG_OP_CONTROL_en_fd_mask)); + f_hal_nfc_deinit_gpio_isr(); + f_hal_nfc_timers_deinit(); + + furi_hal_spi_release(handle); + + return error; +} + +FHalNfcError f_hal_nfc_low_power_mode_stop() { + FHalNfcError error = FHalNfcErrorNone; + FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; + furi_hal_spi_acquire(handle); + + do { + f_hal_nfc_init_gpio_isr(); + f_hal_nfc_timers_init(); + error = f_hal_nfc_turn_on_osc(handle); + if(error != FHalNfcErrorNone) break; + st25r3916_change_reg_bits( + handle, + ST25R3916_REG_OP_CONTROL, + ST25R3916_REG_OP_CONTROL_en_fd_mask, + ST25R3916_REG_OP_CONTROL_en_fd_auto_efd); + + } while(false); + furi_hal_spi_release(handle); + + return error; +} + +static void f_hal_nfc_configure_poller_common(FuriHalSpiBusHandle* handle) { + st25r3916_change_reg_bits( + handle, ST25R3916_REG_MODE, ST25R3916_REG_MODE_tr_am, ST25R3916_REG_MODE_tr_am_am); + st25r3916_change_reg_bits( + handle, + ST25R3916_REG_TX_DRIVER, + ST25R3916_REG_TX_DRIVER_am_mod_mask, + ST25R3916_REG_TX_DRIVER_am_mod_12percent); + st25r3916_change_reg_bits( + handle, + ST25R3916_REG_AUX_MOD, + (ST25R3916_REG_AUX_MOD_dis_reg_am | ST25R3916_REG_AUX_MOD_res_am), + 0x00); + st25r3916_change_reg_bits(handle, ST25R3916_REG_ANT_TUNE_A, 0xff, 0x82); + st25r3916_change_reg_bits(handle, ST25R3916_REG_ANT_TUNE_B, 0xFF, 0x82); + st25r3916_change_reg_bits(handle, ST25R3916_REG_OVERSHOOT_CONF1, 0xff, 0x00); + st25r3916_change_reg_bits(handle, ST25R3916_REG_OVERSHOOT_CONF2, 0xff, 0x00); + st25r3916_change_reg_bits(handle, ST25R3916_REG_UNDERSHOOT_CONF1, 0xff, 0x00); + st25r3916_change_reg_bits(handle, ST25R3916_REG_UNDERSHOOT_CONF2, 0xff, 0x00); +} + +FHalNfcError f_hal_nfc_set_mode(FHalNfcMode mode, FHalNfcBitrate bitrate) { + FHalNfcError error = FHalNfcErrorNone; + FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; + furi_hal_spi_acquire(handle); + + if(mode == FHalNfcModeNfcaPoller) { + f_hal_nfc_configure_poller_common(handle); + // Disable wake up + st25r3916_clear_reg_bits(handle, ST25R3916_REG_OP_CONTROL, ST25R3916_REG_OP_CONTROL_wu); + // Enable ISO14443A mode + st25r3916_write_reg(handle, ST25R3916_REG_MODE, ST25R3916_REG_MODE_om_iso14443a); + st25r3916_change_reg_bits( + handle, + ST25R3916_REG_AUX, + ST25R3916_REG_AUX_dis_corr, + ST25R3916_REG_AUX_dis_corr_correlator); + st25r3916_change_reg_bits(handle, ST25R3916_REG_OVERSHOOT_CONF1, 0xff, 0x40); + st25r3916_change_reg_bits(handle, ST25R3916_REG_OVERSHOOT_CONF2, 0xff, 0x03); + st25r3916_change_reg_bits(handle, ST25R3916_REG_UNDERSHOOT_CONF1, 0xff, 0x40); + st25r3916_change_reg_bits(handle, ST25R3916_REG_UNDERSHOOT_CONF2, 0xff, 0x03); + } else if(mode == FHalNfcModeNfcaListener) { + st25r3916_write_reg( + handle, + ST25R3916_REG_OP_CONTROL, + ST25R3916_REG_OP_CONTROL_en | ST25R3916_REG_OP_CONTROL_rx_en | + ST25R3916_REG_OP_CONTROL_en_fd_auto_efd); + st25r3916_write_reg( + handle, + ST25R3916_REG_MODE, + ST25R3916_REG_MODE_targ_targ | ST25R3916_REG_MODE_om3 | ST25R3916_REG_MODE_om0); + st25r3916_write_reg( + handle, + ST25R3916_REG_PASSIVE_TARGET, + ST25R3916_REG_PASSIVE_TARGET_fdel_2 | ST25R3916_REG_PASSIVE_TARGET_fdel_0 | + ST25R3916_REG_PASSIVE_TARGET_d_ac_ap2p | + ST25R3916_REG_PASSIVE_TARGET_d_212_424_1r); + + st25r3916_write_reg(handle, ST25R3916_REG_MASK_RX_TIMER, 0x02); + } + + if(bitrate == FHalNfcBitrate106) { + st25r3916_change_reg_bits(handle, ST25R3916_REG_RX_CONF1, 0xff, 0x08); + st25r3916_change_reg_bits(handle, ST25R3916_REG_RX_CONF2, 0xff, 0x2d); + st25r3916_change_reg_bits(handle, ST25R3916_REG_RX_CONF3, 0xff, 0x00); + st25r3916_change_reg_bits(handle, ST25R3916_REG_RX_CONF4, 0xff, 0x00); + st25r3916_change_reg_bits(handle, ST25R3916_REG_CORR_CONF1, 0xff, 0x51); + st25r3916_change_reg_bits(handle, ST25R3916_REG_CORR_CONF2, 0xff, 0x00); + } + + furi_hal_spi_release(handle); + + return error; +} + +FHalNfcError f_hal_nfc_poller_field_on() { + FHalNfcError error = FHalNfcErrorNone; + FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; + furi_hal_spi_acquire(handle); + + if(!st25r3916_check_reg( + handle, + ST25R3916_REG_OP_CONTROL, + ST25R3916_REG_OP_CONTROL_tx_en, + ST25R3916_REG_OP_CONTROL_tx_en)) { + // Set min guard time + st25r3916_write_reg(handle, ST25R3916_REG_FIELD_ON_GT, 0); + // st25r3916_direct_cmd(handle, ST25R3916_CMD_INITIAL_RF_COLLISION); + // Enable tx rx + st25r3916_set_reg_bits( + handle, + ST25R3916_REG_OP_CONTROL, + (ST25R3916_REG_OP_CONTROL_rx_en | ST25R3916_REG_OP_CONTROL_tx_en)); + } + + furi_hal_spi_release(handle); + + return error; +} + +FHalNfcError f_hal_nfc_poller_tx(uint8_t* tx_data, uint16_t tx_bits) { + furi_assert(tx_data); + + FHalNfcError err = FHalNfcErrorNone; + FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; + furi_hal_spi_acquire(handle); + + // Prepare tx + st25r3916_direct_cmd(handle, ST25R3916_CMD_CLEAR_FIFO); + st25r3916_clear_reg_bits( + handle, ST25R3916_REG_TIMER_EMV_CONTROL, ST25R3916_REG_TIMER_EMV_CONTROL_nrt_emv); + uint32_t interrupts = + (ST25R3916_IRQ_MASK_FWL | ST25R3916_IRQ_MASK_TXE | ST25R3916_IRQ_MASK_RXS | + ST25R3916_IRQ_MASK_RXE | ST25R3916_IRQ_MASK_PAR | ST25R3916_IRQ_MASK_CRC | + ST25R3916_IRQ_MASK_ERR1 | ST25R3916_IRQ_MASK_ERR2 | ST25R3916_IRQ_MASK_NRE); + // Clear interrupts + st25r3916_get_irq(handle); + // Enable interrupts + st25r3916_mask_irq(handle, ~interrupts); + + st25r3916_write_fifo(handle, tx_data, tx_bits); + st25r3916_direct_cmd(handle, ST25R3916_CMD_TRANSMIT_WITHOUT_CRC); + furi_hal_spi_release(handle); + return err; +} + +FHalNfcError f_hal_nfc_poller_rx(uint8_t* rx_data, uint16_t rx_data_size, uint16_t* rx_bits) { + furi_assert(rx_data); + furi_assert(rx_bits); + + FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; + furi_hal_spi_acquire(handle); + + FHalNfcError error = FHalNfcErrorNone; + + if(!st25r3916_read_fifo(handle, rx_data, rx_data_size, rx_bits)) { + error = FHalNfcErrorBufferOverflow; + } + + furi_hal_spi_release(handle); + + return error; +} + +FHalNfcError f_hal_nfc_trx_reset() { + FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; + furi_hal_spi_acquire(handle); + + st25r3916_direct_cmd(handle, ST25R3916_CMD_STOP); + + furi_hal_spi_release(handle); + return FHalNfcErrorNone; +} + +FHalNfcError f_hal_nfc_listen_start() { + FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; + furi_hal_spi_acquire(handle); + + // f_hal_nfc_trx_reset(); + uint32_t interrupts = + (ST25R3916_IRQ_MASK_FWL | ST25R3916_IRQ_MASK_TXE | ST25R3916_IRQ_MASK_RXS | + ST25R3916_IRQ_MASK_RXE | ST25R3916_IRQ_MASK_PAR | ST25R3916_IRQ_MASK_CRC | + ST25R3916_IRQ_MASK_ERR1 | ST25R3916_IRQ_MASK_ERR2 | ST25R3916_IRQ_MASK_EON | + ST25R3916_IRQ_MASK_EOF | ST25R3916_IRQ_MASK_WU_A_X | ST25R3916_IRQ_MASK_WU_A); + // Clear interrupts + st25r3916_get_irq(handle); + // Enable interrupts + st25r3916_mask_irq(handle, ~interrupts); + st25r3916_direct_cmd(handle, ST25R3916_CMD_GOTO_SENSE); + // st25r3916_direct_cmd(handle, ST25R3916_CMD_UNMASK_RECEIVE_DATA); + + furi_hal_spi_release(handle); + return FHalNfcErrorNone; +} + +void f_hal_nfc_set_mask_receive_timer(uint32_t time_fc) { + FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; + furi_hal_spi_acquire(handle); + + st25r3916_write_reg(handle, ST25R3916_REG_MASK_RX_TIMER, time_fc); + + furi_hal_spi_release(handle); +} diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc_event.c b/firmware/targets/f7/furi_hal/f_hal_nfc_event.c new file mode 100644 index 000000000000..352e056cf186 --- /dev/null +++ b/firmware/targets/f7/furi_hal/f_hal_nfc_event.c @@ -0,0 +1,118 @@ +#include + +FHalNfcEventInternal* f_hal_nfc_event = NULL; + +void f_hal_nfc_event_init() { + f_hal_nfc_event = malloc(sizeof(FHalNfcEventInternal)); +} + +void f_hal_nfc_event_set_callback(FHalNfcCallback callback, void* context) { + furi_assert(f_hal_nfc_event); + furi_assert(callback); + + f_hal_nfc_event->callback = callback; + f_hal_nfc_event->context = context; +} + +void f_hal_nfc_set_event(FHalNfcEventInternalType event) { + furi_assert(f_hal_nfc_event); + furi_assert(f_hal_nfc_event->thread); + + furi_thread_flags_set(f_hal_nfc_event->thread, event); +} + +FHalNfcEvent f_hal_nfc_wait_event(uint32_t timeout_ms) { + furi_assert(f_hal_nfc_event); + + f_hal_nfc_event->thread = furi_thread_get_current_id(); + FuriThreadPriority thread_priority = furi_thread_get_current_priority(); + furi_thread_set_current_priority(FuriThreadPriorityHigh); + + FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; + furi_hal_spi_acquire(handle); + + FHalNfcEvent event = 0; + uint32_t event_timeout = timeout_ms == F_HAL_NFC_EVENT_WAIT_FOREVER ? FuriWaitForever : + timeout_ms; + uint32_t event_flag = furi_thread_flags_wait( + FHalNfcEventInternalAbort | FHalNfcEventInternalTypeIrq | + FHalNfcEventInternalTypeTimerFwtExpired | FHalNfcEventInternalTypeTimerBlockTxExpired, + FuriFlagWaitAny, + event_timeout); + if(event_flag != FuriFlagErrorTimeout) { + if(event_flag & FHalNfcEventInternalTypeIrq) { + furi_thread_flags_clear(FHalNfcEventInternalTypeIrq); + uint32_t irq = f_hal_nfc_get_irq(handle); + if(irq & ST25R3916_IRQ_MASK_OSC) { + event |= FHalNfcEventOscOn; + } + if(irq & ST25R3916_IRQ_MASK_TXE) { + event |= FHalNfcEventTxEnd; + } + if(irq & ST25R3916_IRQ_MASK_RXS) { + // FURI_LOG_I("TAG", "ST25R3916_IRQ_MASK_RXS"); + event |= FHalNfcEventRxStart; + } + if(irq & ST25R3916_IRQ_MASK_RXE) { + // FURI_LOG_I("TAG", "ST25R3916_IRQ_MASK_RXE"); + event |= FHalNfcEventRxEnd; + } + if(irq & ST25R3916_IRQ_MASK_COL) { + event |= FHalNfcEventCollision; + } + if(irq & ST25R3916_IRQ_MASK_EON) { + // FURI_LOG_I("TAG", "ST25R3916_IRQ_MASK_EON"); + event |= FHalNfcEventFieldOn; + } + if(irq & ST25R3916_IRQ_MASK_EOF) { + // FURI_LOG_I("TAG", "ST25R3916_IRQ_MASK_EOF"); + event |= FHalNfcEventFieldOff; + } + if(irq & ST25R3916_IRQ_MASK_WU_A) { + event |= FHalNfcEventListenerActive; + } + if(irq & ST25R3916_IRQ_MASK_WU_A_X) { + event |= FHalNfcEventListenerActiveA; + } + } + if(event_flag & FHalNfcEventInternalTypeTimerFwtExpired) { + event |= FHalNfcEventTimerFwtExpired; + furi_thread_flags_clear(FHalNfcEventInternalTypeTimerFwtExpired); + } + if(event_flag & FHalNfcEventInternalTypeTimerBlockTxExpired) { + event |= FHalNfcEventTimerBlockTxExpired; + furi_thread_flags_clear(FHalNfcEventInternalTypeTimerBlockTxExpired); + } + if(event_flag & FHalNfcEventInternalAbort) { + event |= FHalNfcEventAbortRequest; + furi_thread_flags_clear(FHalNfcEventInternalAbort); + } + } else { + event = FHalNfcEventTimeout; + } + + furi_hal_spi_release(handle); + furi_thread_set_current_priority(thread_priority); + f_hal_nfc_event->thread = NULL; + + return event; +} + +bool f_hal_nfc_event_wait_for_specific_irq( + FuriHalSpiBusHandle* handle, + uint32_t mask, + uint32_t timeout_ms) { + furi_assert(f_hal_nfc_event); + + bool irq_received = false; + f_hal_nfc_event->thread = furi_thread_get_current_id(); + uint32_t event_flag = + furi_thread_flags_wait(FHalNfcEventInternalTypeIrq, FuriFlagWaitAny, timeout_ms); + if(event_flag == FHalNfcEventInternalTypeIrq) { + uint32_t irq = f_hal_nfc_get_irq(handle); + irq_received = ((irq & mask) == mask); + } + f_hal_nfc_event->thread = NULL; + + return irq_received; +} diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc_i.h b/firmware/targets/f7/furi_hal/f_hal_nfc_i.h new file mode 100644 index 000000000000..3b0ce5ed135e --- /dev/null +++ b/firmware/targets/f7/furi_hal/f_hal_nfc_i.h @@ -0,0 +1,51 @@ +#pragma once + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + FHalNfcEventInternalAbort = (1U << 0), + FHalNfcEventInternalTypeIrq = (1U << 1), + FHalNfcEventInternalTypeTimerFwtExpired = (1U << 2), + FHalNfcEventInternalTypeTimerBlockTxExpired = (1U << 3), +} FHalNfcEventInternalType; + +typedef struct { + FuriThreadId thread; + FHalNfcCallback callback; + void* context; +} FHalNfcEventInternal; + +extern FHalNfcEventInternal* f_hal_nfc; + +void f_hal_nfc_event_init(); + +void f_hal_nfc_event_set_callback(FHalNfcCallback callback, void* context); + +void f_hal_nfc_set_event(FHalNfcEventInternalType event); + +void f_hal_nfc_init_gpio_isr(); + +void f_hal_nfc_deinit_gpio_isr(); + +void f_hal_nfc_timers_init(); + +void f_hal_nfc_timers_deinit(); + +uint32_t f_hal_nfc_get_irq(FuriHalSpiBusHandle* handle); + +bool f_hal_nfc_event_wait_for_specific_irq( + FuriHalSpiBusHandle* handle, + uint32_t mask, + uint32_t timeout_ms); + +#ifdef __cplusplus +} +#endif diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc_irq.c b/firmware/targets/f7/furi_hal/f_hal_nfc_irq.c new file mode 100644 index 000000000000..686675bb9967 --- /dev/null +++ b/firmware/targets/f7/furi_hal/f_hal_nfc_irq.c @@ -0,0 +1,27 @@ +#include "f_hal_nfc_i.h" + +#include +#include + +static void f_hal_nfc_int_callback() { + f_hal_nfc_set_event(FHalNfcEventInternalTypeIrq); +} + +uint32_t f_hal_nfc_get_irq(FuriHalSpiBusHandle* handle) { + uint32_t irq = 0; + while(furi_hal_gpio_read_port_pin(gpio_nfc_irq_rfid_pull.port, gpio_nfc_irq_rfid_pull.pin)) { + irq |= st25r3916_get_irq(handle); + } + return irq; +} + +void f_hal_nfc_init_gpio_isr() { + furi_hal_gpio_init(&gpio_nfc_irq_rfid_pull, GpioModeInterruptRise, GpioPullDown, GpioSpeedVeryHigh); + furi_hal_gpio_add_int_callback(&gpio_nfc_irq_rfid_pull, f_hal_nfc_int_callback, NULL); + furi_hal_gpio_enable_int_callback(&gpio_nfc_irq_rfid_pull); +} + +void f_hal_nfc_deinit_gpio_isr() { + furi_hal_gpio_init(&gpio_nfc_irq_rfid_pull, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_disable_int_callback(&gpio_nfc_irq_rfid_pull); +} diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc_timer.c b/firmware/targets/f7/furi_hal/f_hal_nfc_timer.c new file mode 100644 index 000000000000..114395dc3635 --- /dev/null +++ b/firmware/targets/f7/furi_hal/f_hal_nfc_timer.c @@ -0,0 +1,143 @@ +#include "f_hal_nfc_i.h" + +#include +#include +#include +#include + +#define F_HAL_NFC_FREQ_KHZ (13560U) + +typedef enum { + FHalNfcTimerFwt, + FHalNfcTimerBlockTx, + FHalNfcTimerCount, +} FHalNfcTimer; + +typedef struct { + TIM_TypeDef* timer; + uint32_t freq_khz; + FHalNfcEventInternalType event; + FuriHalInterruptId irq_id; + IRQn_Type irq_type; + bool is_configured; + const GpioPin* pin; +} FHalNfcTimerConfig; + +static FHalNfcTimerConfig f_hal_nfc_timers[FHalNfcTimerCount] = { + [FHalNfcTimerFwt] = + { + .pin = &gpio_ext_pa7, + .timer = TIM1, + .freq_khz = 64000U, + .event = FHalNfcEventInternalTypeTimerFwtExpired, + .irq_id = FuriHalInterruptIdTim1UpTim16, + .irq_type = TIM1_UP_TIM16_IRQn, + .is_configured = false, + }, + [FHalNfcTimerBlockTx] = { + .pin = &gpio_ext_pa6, + .timer = TIM2, + .freq_khz = 64000U, + .event = FHalNfcEventInternalTypeTimerBlockTxExpired, + .irq_id = FuriHalInterruptIdTIM2, + .irq_type = TIM2_IRQn, + .is_configured = false, + }}; + +static void f_hal_nfc_timer_irq_callback(void* context) { + FHalNfcTimerConfig* timer = context; + if(LL_TIM_IsActiveFlag_UPDATE(timer->timer)) { + LL_TIM_ClearFlag_UPDATE(timer->timer); + f_hal_nfc_set_event(timer->event); + furi_hal_gpio_write(timer->pin, false); + } +} + +static void f_hal_nfc_timer_init(FHalNfcTimer timer) { + LL_TIM_DeInit(f_hal_nfc_timers[timer].timer); + LL_TIM_EnableUpdateEvent(f_hal_nfc_timers[timer].timer); + LL_TIM_SetOnePulseMode(f_hal_nfc_timers[timer].timer, LL_TIM_ONEPULSEMODE_SINGLE); + LL_TIM_SetCounterMode(f_hal_nfc_timers[timer].timer, LL_TIM_COUNTERMODE_UP); + LL_TIM_SetClockDivision(f_hal_nfc_timers[timer].timer, LL_TIM_CLOCKDIVISION_DIV1); + LL_TIM_SetClockSource(f_hal_nfc_timers[timer].timer, LL_TIM_CLOCKSOURCE_INTERNAL); + LL_TIM_EnableIT_UPDATE(f_hal_nfc_timers[timer].timer); + + furi_hal_interrupt_set_isr( + f_hal_nfc_timers[timer].irq_id, f_hal_nfc_timer_irq_callback, &f_hal_nfc_timers[timer]); + NVIC_SetPriority( + f_hal_nfc_timers[timer].irq_type, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0)); + NVIC_EnableIRQ(f_hal_nfc_timers[timer].irq_type); + f_hal_nfc_timers[timer].is_configured = true; + furi_hal_gpio_init( + f_hal_nfc_timers[timer].pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); + furi_hal_gpio_write(f_hal_nfc_timers[timer].pin, false); +} + +static void f_hal_nfc_timer_deinit(FHalNfcTimer timer) { + LL_TIM_DeInit(f_hal_nfc_timers[timer].timer); + furi_hal_interrupt_set_isr(f_hal_nfc_timers[timer].irq_id, NULL, NULL); + NVIC_DisableIRQ(f_hal_nfc_timers[timer].irq_type); + f_hal_nfc_timers[timer].is_configured = false; +} + +static void f_hal_nfc_timer_start(FHalNfcTimer timer, uint32_t time_fc) { + uint32_t arr_reg = f_hal_nfc_timers[timer].freq_khz * time_fc / F_HAL_NFC_FREQ_KHZ; + LL_TIM_SetAutoReload(f_hal_nfc_timers[timer].timer, arr_reg); + LL_TIM_EnableCounter(f_hal_nfc_timers[timer].timer); + furi_hal_gpio_write(f_hal_nfc_timers[timer].pin, true); +} + +static void f_hal_nfc_timer_stop(FHalNfcTimer timer) { + LL_TIM_DisableCounter(f_hal_nfc_timers[timer].timer); + LL_TIM_SetCounter(f_hal_nfc_timers[timer].timer, 0); + LL_TIM_SetAutoReload(f_hal_nfc_timers[timer].timer, 0); + if(LL_TIM_IsActiveFlag_UPDATE(f_hal_nfc_timers[timer].timer)) { + LL_TIM_ClearFlag_UPDATE(f_hal_nfc_timers[timer].timer); + } + furi_hal_gpio_write(f_hal_nfc_timers[timer].pin, false); +} + +void f_hal_nfc_timers_init() { + for(size_t i = 0; i < FHalNfcTimerCount; i++) { + f_hal_nfc_timer_init(i); + } +} + +void f_hal_nfc_timers_deinit() { + for(size_t i = 0; i < FHalNfcTimerCount; i++) { + f_hal_nfc_timer_deinit(i); + } +} + +void f_hal_nfc_timer_fwt_start(uint32_t time_fc) { + furi_assert(f_hal_nfc_timers[FHalNfcTimerFwt].is_configured); + f_hal_nfc_timer_start(FHalNfcTimerFwt, time_fc); +} + +void f_hal_nfc_timer_fwt_stop() { + furi_assert(f_hal_nfc_timers[FHalNfcTimerFwt].is_configured); + f_hal_nfc_timer_stop(FHalNfcTimerFwt); +} + +void f_hal_nfc_timer_block_tx_start(uint32_t time_fc) { + furi_assert(f_hal_nfc_timers[FHalNfcTimerBlockTx].is_configured); + f_hal_nfc_timer_start(FHalNfcTimerBlockTx, time_fc); +} + +void f_hal_nfc_timer_block_tx_start_us(uint32_t time_us) { + furi_assert(f_hal_nfc_timers[FHalNfcTimerBlockTx].is_configured); + + uint32_t arr_reg = f_hal_nfc_timers[FHalNfcTimerBlockTx].freq_khz / 1000 * time_us; + LL_TIM_SetAutoReload(f_hal_nfc_timers[FHalNfcTimerBlockTx].timer, arr_reg); + LL_TIM_EnableCounter(f_hal_nfc_timers[FHalNfcTimerBlockTx].timer); + furi_hal_gpio_write(f_hal_nfc_timers[FHalNfcTimerBlockTx].pin, true); +} + +void f_hal_nfc_timer_block_tx_stop() { + furi_assert(f_hal_nfc_timers[FHalNfcTimerBlockTx].is_configured); + f_hal_nfc_timer_stop(FHalNfcTimerBlockTx); +} + +bool f_hal_nfc_timer_block_tx_is_running() { + return LL_TIM_IsEnabledCounter(f_hal_nfc_timers[FHalNfcTimerBlockTx].timer) == 1; +} diff --git a/firmware/targets/f7/furi_hal/f_hal_nfca.c b/firmware/targets/f7/furi_hal/f_hal_nfca.c new file mode 100644 index 000000000000..c35102bb4110 --- /dev/null +++ b/firmware/targets/f7/furi_hal/f_hal_nfca.c @@ -0,0 +1,101 @@ +#include + +#include +#include +#include + +#define TAG "FuriHalNfcA" + +FHalNfcError f_hal_nfca_send_short_frame(FHalNfcaShortFrame frame) { + FHalNfcError error = FHalNfcErrorNone; + + FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; + furi_hal_spi_acquire(handle); + + // Disable crc check + st25r3916_set_reg_bits(handle, ST25R3916_REG_AUX, ST25R3916_REG_AUX_no_crc_rx); + + st25r3916_write_reg(handle, ST25R3916_REG_NUM_TX_BYTES2, 0); + uint32_t interrupts = + (ST25R3916_IRQ_MASK_FWL | ST25R3916_IRQ_MASK_TXE | ST25R3916_IRQ_MASK_RXS | + ST25R3916_IRQ_MASK_RXE | ST25R3916_IRQ_MASK_PAR | ST25R3916_IRQ_MASK_CRC | + ST25R3916_IRQ_MASK_ERR1 | ST25R3916_IRQ_MASK_ERR2 | ST25R3916_IRQ_MASK_NRE); + // Clear interrupts + st25r3916_get_irq(handle); + // Enable interrupts + st25r3916_mask_irq(handle, ~interrupts); + if(frame == FHalNfcaShortFrameAllReq) { + st25r3916_direct_cmd(handle, ST25R3916_CMD_TRANSMIT_REQA); + } else { + st25r3916_direct_cmd(handle, ST25R3916_CMD_TRANSMIT_WUPA); + } + + furi_hal_spi_release(handle); + + return error; +} + +FHalNfcError f_hal_nfca_send_sdd_frame(uint8_t* tx_data, uint16_t tx_bits) { + FHalNfcError error = FHalNfcErrorNone; + // TODO Set anticollision parameters + error = f_hal_nfc_poller_tx(tx_data, tx_bits); + + return error; +} + +FHalNfcError + f_hal_nfca_receive_sdd_frame(uint8_t* rx_data, uint16_t rx_data_size, uint16_t* rx_bits) { + FHalNfcError error = FHalNfcErrorNone; + UNUSED(rx_data); + UNUSED(rx_bits); + UNUSED(rx_data_size); + + error = f_hal_nfc_poller_rx(rx_data, rx_data_size, rx_bits); + // TODO reset anticollision parameters here + + return error; +} + +FHalNfcError + furi_hal_nfca_set_col_res_data(uint8_t* uid, uint8_t uid_len, uint8_t* atqa, uint8_t sak) { + furi_assert(uid); + furi_assert(atqa); + UNUSED(uid_len); + UNUSED(sak); + FHalNfcError error = FHalNfcErrorNone; + + FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; + furi_hal_spi_acquire(handle); + + // Set 4 or 7 bytes UID + if(uid_len == 4) { + st25r3916_change_reg_bits( + handle, + ST25R3916_REG_AUX, + ST25R3916_REG_AUX_nfc_id_mask, + ST25R3916_REG_AUX_nfc_id_4bytes); + } else { + st25r3916_change_reg_bits( + handle, + ST25R3916_REG_AUX, + ST25R3916_REG_AUX_nfc_id_mask, + ST25R3916_REG_AUX_nfc_id_7bytes); + } + // Write PT Memory + uint8_t pt_memory[15] = {}; + memcpy(pt_memory, uid, uid_len); + pt_memory[10] = atqa[0]; + pt_memory[11] = atqa[1]; + if(uid_len == 4) { + pt_memory[12] = sak & ~0x04; + } else { + pt_memory[12] = 0x04; + } + pt_memory[13] = sak & ~0x04; + pt_memory[14] = sak & ~0x04; + + st25r3916_write_pta_mem(handle, pt_memory, sizeof(pt_memory)); + furi_hal_spi_release(handle); + + return error; +} diff --git a/firmware/targets/f7/furi_hal/furi_hal.c b/firmware/targets/f7/furi_hal/furi_hal.c index 1b710bb9637f..b2a940e9edd1 100644 --- a/firmware/targets/f7/furi_hal/furi_hal.c +++ b/firmware/targets/f7/furi_hal/furi_hal.c @@ -50,7 +50,8 @@ void furi_hal_init() { furi_hal_usb_init(); furi_hal_vibro_init(); furi_hal_subghz_init(); - furi_hal_nfc_init(); + // furi_hal_nfc_init(); + f_hal_nfc_init(); furi_hal_rfid_init(); #endif } diff --git a/firmware/targets/f7/furi_hal/furi_hal_nfc.c b/firmware/targets/f7/furi_hal/furi_hal_nfc.c index 8910d887bcb7..c5605c48708b 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_nfc.c +++ b/firmware/targets/f7/furi_hal/furi_hal_nfc.c @@ -1,6 +1,6 @@ #include -#include -#include +#include "furi_hal_nfc.h" +#include #include #include #include diff --git a/firmware/targets/f7/furi_hal/furi_hal_target_hw.h b/firmware/targets/f7/furi_hal/furi_hal_target_hw.h index 128122f84392..2d25a80c3e2b 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_target_hw.h +++ b/firmware/targets/f7/furi_hal/furi_hal_target_hw.h @@ -3,4 +3,4 @@ #include #include #include -#include +#include diff --git a/firmware/targets/f7/target.json b/firmware/targets/f7/target.json index 14bb1cd0c218..ea4ac6d47332 100644 --- a/firmware/targets/f7/target.json +++ b/firmware/targets/f7/target.json @@ -41,6 +41,7 @@ "lfrfid", "flipper_application", "flipperformat", - "toolbox" + "toolbox", + "flipper7" ] } diff --git a/firmware/targets/furi_hal_include/f_hal_nfc.h b/firmware/targets/furi_hal_include/f_hal_nfc.h new file mode 100644 index 000000000000..a4babe6a25c2 --- /dev/null +++ b/firmware/targets/furi_hal_include/f_hal_nfc.h @@ -0,0 +1,143 @@ +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define F_HAL_NFC_TIMER_OFFSET_FC (800) + +#define F_HAL_NFC_EVENT_WAIT_FOREVER (0xFFFFFFFFU) + +typedef enum { + FHalNfcEventOscOn = (1U << 0), + FHalNfcEventFieldOn = (1U << 1), + FHalNfcEventFieldOff = (1U << 2), + FHalNfcEventListenerActive = (1U << 3), + FHalNfcEventListenerActiveA = (1U << 4), + FHalNfcEventTxStart = (1U << 5), + FHalNfcEventTxEnd = (1U << 6), + FHalNfcEventRxStart = (1U << 7), + FHalNfcEventRxEnd = (1U << 8), + FHalNfcEventCollision = (1U << 9), + FHalNfcEventTimerFwtExpired = (1U << 10), + FHalNfcEventTimerBlockTxExpired = (1U << 11), + FHalNfcEventTimeout = (1U << 12), + FHalNfcEventAbortRequest = (1U << 13), +} FHalNfcEvent; + +typedef void (*FHalNfcCallback)(FHalNfcEvent event, void* context); + +typedef enum { + FHalNfcErrorNone, + FHalNfcErrorChipCommunication, + FHalNfcErrorCommunication, + FHalNfcErrorOscillator, + FHalNfcErrorIsrTimeout, + FHalNfcErrorCommunicationTimeout, + FHalNfcErrorBufferOverflow, +} FHalNfcError; + +typedef enum { + FHalNfcModeNfcaPoller, + FHalNfcModeNfcaListener, +} FHalNfcMode; + +typedef enum { + FHalNfcBitrate106, +} FHalNfcBitrate; + +typedef enum { + FHalNfcaShortFrameAllReq, + FHalNfcaShortFrameSensReq, +} FHalNfcaShortFrame; + +/** + * @brief Nfc HAL initialization + * + * @return FHalNfcError + */ +FHalNfcError f_hal_nfc_init(); + +/** + * @brief Set Nfc HAL event callback + * + * @param callback + * @param context + */ +void f_hal_nfc_set_callback(FHalNfcCallback callback, void* context); + +/** + * @brief Start Nfc hardware low power mode + * + * @return FHalNfcError + */ +FHalNfcError f_hal_nfc_low_power_mode_start(); + +/** + * @brief Stop Nfc hardware low power mode + * + * @return FHalNfcError + */ +FHalNfcError f_hal_nfc_low_power_mode_stop(); + +/** + * @brief Configure Nfc HAL mode + * + * @param mode FHalNfcMode instance + * @param bitrate FHalNfcBitrate instance + * + * @return FHalNfcError + */ +FHalNfcError f_hal_nfc_set_mode(FHalNfcMode mode, FHalNfcBitrate bitrate); + +// FHalNfcError f_hal_nfc_poller_configure + +/** + * @brief Turn on field in poller mode + * + * @return FHalNfcError + */ +FHalNfcError f_hal_nfc_poller_field_on(); + +FHalNfcError f_hal_nfc_poller_tx(uint8_t* tx_data, uint16_t tx_bits); + +FHalNfcError f_hal_nfc_poller_rx(uint8_t* rx_data, uint16_t rx_data_size, uint16_t* rx_bits); + +FHalNfcError f_hal_nfc_trx_reset(); + +FHalNfcError f_hal_nfc_listen_start(); + +FHalNfcEvent f_hal_nfc_wait_event(uint32_t timeout_ms); + +void f_hal_nfc_timer_fwt_start(uint32_t time_fc); + +void f_hal_nfc_timer_fwt_stop(); + +void f_hal_nfc_timer_block_tx_start(uint32_t time_fc); + +void f_hal_nfc_timer_block_tx_start_us(uint32_t time_us); + +void f_hal_nfc_timer_block_tx_stop(); + +bool f_hal_nfc_timer_block_tx_is_running(); + +void f_hal_nfc_set_mask_receive_timer(uint32_t time_fc); + +/******************* NFCA specific API *******************/ + +FHalNfcError f_hal_nfca_send_short_frame(FHalNfcaShortFrame frame); + +FHalNfcError f_hal_nfca_send_sdd_frame(uint8_t* tx_data, uint16_t tx_bits); + +FHalNfcError + f_hal_nfca_receive_sdd_frame(uint8_t* rx_data, uint16_t rx_data_size, uint16_t* rx_bits); + +FHalNfcError + furi_hal_nfca_set_col_res_data(uint8_t* uid, uint8_t uid_len, uint8_t* atqa, uint8_t sak); + +#ifdef __cplusplus +} +#endif diff --git a/lib/drivers/st25r3916.c b/lib/drivers/st25r3916.c new file mode 100644 index 000000000000..363e33a3e295 --- /dev/null +++ b/lib/drivers/st25r3916.c @@ -0,0 +1,77 @@ +#include "st25r3916.h" + +#include + +bool st25r3916_init(void) { + return true; +} + +void st25r3916_mask_irq(FuriHalSpiBusHandle* handle, uint32_t mask) { + furi_assert(handle); + + uint8_t irq_mask_regs[4] = { + mask & 0xff, + (mask >> 8) & 0xff, + (mask >> 16) & 0xff, + (mask >> 24) & 0xff, + }; + st25r3916_write_burst_regs(handle, ST25R3916_REG_IRQ_MASK_MAIN, irq_mask_regs, 4); +} + +uint32_t st25r3916_get_irq(FuriHalSpiBusHandle* handle) { + furi_assert(handle); + + uint8_t irq_regs[4] = {}; + uint32_t irq = 0; + st25r3916_read_burst_regs(handle, ST25R3916_REG_IRQ_MAIN, irq_regs, 4); + irq = (uint32_t)irq_regs[0]; + irq |= (uint32_t)irq_regs[1] << 8; + irq |= (uint32_t)irq_regs[2] << 16; + irq |= (uint32_t)irq_regs[3] << 24; + + return irq; +} + +void st25r3916_write_fifo(FuriHalSpiBusHandle* handle, uint8_t* buff, uint16_t bits) { + furi_assert(handle); + furi_assert(buff); + + uint16_t bytes = (bits + 7) / 8; + + st25r3916_write_reg(handle, ST25R3916_REG_NUM_TX_BYTES2, (uint8_t)(bits & 0xFFU)); + st25r3916_write_reg(handle, ST25R3916_REG_NUM_TX_BYTES1, (uint8_t)((bits >> 8) & 0xFFU)); + st25r3916_reg_write_fifo(handle, buff, bytes); +} + +bool st25r3916_read_fifo( + FuriHalSpiBusHandle* handle, + uint8_t* buff, + uint16_t buff_size, + uint16_t* buff_bits) { + furi_assert(handle); + furi_assert(buff); + + bool read_success = false; + + uint8_t fifo_status[2] = {}; + st25r3916_read_burst_regs(handle, ST25R3916_REG_FIFO_STATUS1, fifo_status, 2); + uint16_t bytes = ((fifo_status[1] & ST25R3916_REG_FIFO_STATUS2_fifo_b_mask) >> + ST25R3916_REG_FIFO_STATUS2_fifo_b_shift) | + fifo_status[0]; + uint8_t bits = + ((fifo_status[1] & ST25R3916_REG_FIFO_STATUS2_fifo_lb_mask) >> + ST25R3916_REG_FIFO_STATUS2_fifo_lb_shift); + + if(bytes <= buff_size) { + st25r3916_reg_read_fifo(handle, buff, bytes); + read_success = true; + } + + if(bits) { + *buff_bits = (bytes - 1) * 8 + bits; + } else { + *buff_bits = bytes * 8; + } + + return read_success; +} diff --git a/lib/drivers/st25r3916.h b/lib/drivers/st25r3916.h new file mode 100644 index 000000000000..cbb964b73eab --- /dev/null +++ b/lib/drivers/st25r3916.h @@ -0,0 +1,102 @@ +#pragma once + +#include "st25r3916_reg.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ST25R3916_IRQ_MASK_ALL \ + (uint32_t)(0xFFFFFFFFUL) /*!< All ST25R3916 interrupt sources */ +#define ST25R3916_IRQ_MASK_NONE \ + (uint32_t)(0x00000000UL) /*!< No ST25R3916 interrupt source */ + +/* Main interrupt register */ +#define ST25R3916_IRQ_MASK_OSC \ + (uint32_t)(0x00000080U) /*!< ST25R3916 oscillator stable interrupt */ +#define ST25R3916_IRQ_MASK_FWL \ + (uint32_t)(0x00000040U) /*!< ST25R3916 FIFO water level interrupt */ +#define ST25R3916_IRQ_MASK_RXS \ + (uint32_t)(0x00000020U) /*!< ST25R3916 start of receive interrupt */ +#define ST25R3916_IRQ_MASK_RXE \ + (uint32_t)(0x00000010U) /*!< ST25R3916 end of receive interrupt */ +#define ST25R3916_IRQ_MASK_TXE \ + (uint32_t)(0x00000008U) /*!< ST25R3916 end of transmission interrupt */ +#define ST25R3916_IRQ_MASK_COL \ + (uint32_t)(0x00000004U) /*!< ST25R3916 bit collision interrupt */ +#define ST25R3916_IRQ_MASK_RX_REST \ + (uint32_t)(0x00000002U) /*!< ST25R3916 automatic reception restart interrupt */ +#define ST25R3916_IRQ_MASK_RFU \ + (uint32_t)(0x00000001U) /*!< ST25R3916 RFU interrupt */ + +/* Timer and NFC interrupt register */ +#define ST25R3916_IRQ_MASK_DCT \ + (uint32_t)(0x00008000U) /*!< ST25R3916 termination of direct command interrupt. */ +#define ST25R3916_IRQ_MASK_NRE \ + (uint32_t)(0x00004000U) /*!< ST25R3916 no-response timer expired interrupt */ +#define ST25R3916_IRQ_MASK_GPE \ + (uint32_t)(0x00002000U) /*!< ST25R3916 general purpose timer expired interrupt */ +#define ST25R3916_IRQ_MASK_EON \ + (uint32_t)(0x00001000U) /*!< ST25R3916 external field on interrupt */ +#define ST25R3916_IRQ_MASK_EOF \ + (uint32_t)(0x00000800U) /*!< ST25R3916 external field off interrupt */ +#define ST25R3916_IRQ_MASK_CAC \ + (uint32_t)(0x00000400U) /*!< ST25R3916 collision during RF collision avoidance interrupt */ +#define ST25R3916_IRQ_MASK_CAT \ + (uint32_t)(0x00000200U) /*!< ST25R3916 minimum guard time expired interrupt */ +#define ST25R3916_IRQ_MASK_NFCT \ + (uint32_t)(0x00000100U) /*!< ST25R3916 initiator bit rate recognised interrupt */ + +/* Error and wake-up interrupt register */ +#define ST25R3916_IRQ_MASK_CRC \ + (uint32_t)(0x00800000U) /*!< ST25R3916 CRC error interrupt */ +#define ST25R3916_IRQ_MASK_PAR \ + (uint32_t)(0x00400000U) /*!< ST25R3916 parity error interrupt */ +#define ST25R3916_IRQ_MASK_ERR2 \ + (uint32_t)(0x00200000U) /*!< ST25R3916 soft framing error interrupt */ +#define ST25R3916_IRQ_MASK_ERR1 \ + (uint32_t)(0x00100000U) /*!< ST25R3916 hard framing error interrupt */ +#define ST25R3916_IRQ_MASK_WT \ + (uint32_t)(0x00080000U) /*!< ST25R3916 wake-up interrupt */ +#define ST25R3916_IRQ_MASK_WAM \ + (uint32_t)(0x00040000U) /*!< ST25R3916 wake-up due to amplitude interrupt */ +#define ST25R3916_IRQ_MASK_WPH \ + (uint32_t)(0x00020000U) /*!< ST25R3916 wake-up due to phase interrupt */ +#define ST25R3916_IRQ_MASK_WCAP \ + (uint32_t)(0x00010000U) /*!< ST25R3916 wake-up due to capacitance measurement */ + +/* Passive Target Interrupt Register */ +#define ST25R3916_IRQ_MASK_PPON2 \ + (uint32_t)(0x80000000U) /*!< ST25R3916 PPON2 Field on waiting Timer interrupt */ +#define ST25R3916_IRQ_MASK_SL_WL \ + (uint32_t)(0x40000000U) /*!< ST25R3916 Passive target slot number water level interrupt */ +#define ST25R3916_IRQ_MASK_APON \ + (uint32_t)(0x20000000U) /*!< ST25R3916 Anticollision done and Field On interrupt */ +#define ST25R3916_IRQ_MASK_RXE_PTA \ + (uint32_t)(0x10000000U) /*!< ST25R3916 RXE with an automatic response interrupt */ +#define ST25R3916_IRQ_MASK_WU_F \ + (uint32_t)(0x08000000U) /*!< ST25R3916 212/424b/s Passive target interrupt: Active */ +#define ST25R3916_IRQ_MASK_RFU2 \ + (uint32_t)(0x04000000U) /*!< ST25R3916 RFU2 interrupt */ +#define ST25R3916_IRQ_MASK_WU_A_X \ + (uint32_t)(0x02000000U) /*!< ST25R3916 106kb/s Passive target state interrupt: Active* */ +#define ST25R3916_IRQ_MASK_WU_A \ + (uint32_t)(0x01000000U) /*!< ST25R3916 106kb/s Passive target state interrupt: Active */ + +bool st25r3916_init(void); + +void st25r3916_mask_irq(FuriHalSpiBusHandle* handle, uint32_t mask); + +uint32_t st25r3916_get_irq(FuriHalSpiBusHandle* handle); + +void st25r3916_write_fifo(FuriHalSpiBusHandle* handle, uint8_t* buff, uint16_t bits); + +bool st25r3916_read_fifo( + FuriHalSpiBusHandle* handle, + uint8_t* buff, + uint16_t buff_size, + uint16_t* buff_bits); + +#ifdef __cplusplus +} +#endif diff --git a/lib/drivers/st25r3916_reg.c b/lib/drivers/st25r3916_reg.c new file mode 100644 index 000000000000..b3ddee849b09 --- /dev/null +++ b/lib/drivers/st25r3916_reg.c @@ -0,0 +1,258 @@ +#include "st25r3916_reg.h" + +#include + +#define ST25R3916_WRITE_MODE \ + (0U << 6) /*!< ST25R3916 Operation Mode: Write */ +#define ST25R3916_READ_MODE \ + (1U << 6) /*!< ST25R3916 Operation Mode: Read */ +#define ST25R3916_CMD_MODE \ + (3U << 6) /*!< ST25R3916 Operation Mode: Direct Command */ +#define ST25R3916_FIFO_LOAD \ + (0x80U) /*!< ST25R3916 Operation Mode: FIFO Load */ +#define ST25R3916_FIFO_READ \ + (0x9FU) /*!< ST25R3916 Operation Mode: FIFO Read */ +#define ST25R3916_PT_A_CONFIG_LOAD \ + (0xA0U) /*!< ST25R3916 Operation Mode: Passive Target Memory A-Config Load */ +#define ST25R3916_PT_F_CONFIG_LOAD \ + (0xA8U) /*!< ST25R3916 Operation Mode: Passive Target Memory F-Config Load */ +#define ST25R3916_PT_TSN_DATA_LOAD \ + (0xACU) /*!< ST25R3916 Operation Mode: Passive Target Memory TSN Load */ +#define ST25R3916_PT_MEM_READ \ + (0xBFU) /*!< ST25R3916 Operation Mode: Passive Target Memory Read */ + +#define ST25R3916_CMD_LEN \ + (1U) /*!< ST25R3916 CMD length */ +#define ST25R3916_FIFO_DEPTH (512U) +#define ST25R3916_BUF_LEN \ + (ST25R3916_CMD_LEN + \ + ST25R3916_FIFO_DEPTH) /*!< ST25R3916 communication buffer: CMD + FIFO length */ + +static void st25r3916_reg_tx_byte(FuriHalSpiBusHandle* handle, uint8_t byte) { + uint8_t val = byte; + furi_hal_spi_bus_tx(handle, &val, 1, 5); +} + +void st25r3916_read_reg(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t* val) { + furi_assert(handle); + st25r3916_read_burst_regs(handle, reg, val, 1); +} + +void st25r3916_read_burst_regs( + FuriHalSpiBusHandle* handle, + uint8_t reg_start, + uint8_t* values, + uint8_t length) { + furi_assert(handle); + furi_assert(values); + furi_assert(length); + + furi_hal_gpio_write(handle->cs, false); + + if(reg_start & ST25R3916_SPACE_B) { + // Send direct command first + st25r3916_reg_tx_byte(handle, ST25R3916_CMD_SPACE_B_ACCESS); + } + st25r3916_reg_tx_byte(handle, (reg_start & ~ST25R3916_SPACE_B) | ST25R3916_READ_MODE); + furi_hal_spi_bus_rx(handle, values, length, 5); + + furi_hal_gpio_write(handle->cs, true); +} + +void st25r3916_write_reg(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t val) { + furi_assert(handle); + uint8_t reg_val = val; + st25r3916_write_burst_regs(handle, reg, ®_val, 1); +} + +void st25r3916_write_burst_regs( + FuriHalSpiBusHandle* handle, + uint8_t reg_start, + uint8_t* values, + uint8_t length) { + furi_assert(handle); + furi_assert(values); + furi_assert(length); + + furi_hal_gpio_write(handle->cs, false); + + if(reg_start & ST25R3916_SPACE_B) { + // Send direct command first + st25r3916_reg_tx_byte(handle, ST25R3916_CMD_SPACE_B_ACCESS); + } + st25r3916_reg_tx_byte(handle, (reg_start & ~ST25R3916_SPACE_B) | ST25R3916_WRITE_MODE); + furi_hal_spi_bus_tx(handle, values, length, 5); + + furi_hal_gpio_write(handle->cs, true); +} + +void st25r3916_reg_write_fifo(FuriHalSpiBusHandle* handle, uint8_t* buff, uint16_t length) { + furi_assert(handle); + furi_assert(buff); + furi_assert(length); + furi_assert(length <= ST25R3916_FIFO_DEPTH); + + furi_hal_gpio_write(handle->cs, false); + st25r3916_reg_tx_byte(handle, ST25R3916_FIFO_LOAD); + furi_hal_spi_bus_tx(handle, buff, length, 200); + furi_hal_gpio_write(handle->cs, true); +} + +void st25r3916_reg_read_fifo(FuriHalSpiBusHandle* handle, uint8_t* buff, uint16_t length) { + furi_assert(handle); + furi_assert(buff); + furi_assert(length); + furi_assert(length <= ST25R3916_FIFO_DEPTH); + + furi_hal_gpio_write(handle->cs, false); + st25r3916_reg_tx_byte(handle, ST25R3916_FIFO_READ); + furi_hal_spi_bus_rx(handle, buff, length, 200); + furi_hal_gpio_write(handle->cs, true); +} + +void st25r3916_write_pta_mem(FuriHalSpiBusHandle* handle, uint8_t* buff, uint16_t length) { + furi_assert(handle); + furi_assert(buff); + furi_assert(length); + furi_assert(length <= ST25R3916_PTM_LEN); + + furi_hal_gpio_write(handle->cs, false); + st25r3916_reg_tx_byte(handle, ST25R3916_PT_A_CONFIG_LOAD); + furi_hal_spi_bus_tx(handle, buff, length, 200); + furi_hal_gpio_write(handle->cs, true); +} + +void st25r3916_read_pta_mem(FuriHalSpiBusHandle* handle, uint8_t* buff, uint16_t length) { + furi_assert(handle); + furi_assert(buff); + furi_assert(length); + furi_assert(length <= ST25R3916_PTM_LEN); + + uint8_t tmp_buff[ST25R3916_PTM_LEN + 1]; + furi_hal_gpio_write(handle->cs, false); + st25r3916_reg_tx_byte(handle, ST25R3916_PT_MEM_READ); + furi_hal_spi_bus_rx(handle, tmp_buff, length + 1, 200); + furi_hal_gpio_write(handle->cs, true); + furi_hal_gpio_write(handle->cs, true); + memcpy(buff, tmp_buff + 1, length); +} + +void st25r3916_write_ptf_mem(FuriHalSpiBusHandle* handle, uint8_t* buff, uint16_t length) { + furi_assert(handle); + furi_assert(buff); + + furi_hal_gpio_write(handle->cs, false); + st25r3916_reg_tx_byte(handle, ST25R3916_PT_F_CONFIG_LOAD); + furi_hal_spi_bus_tx(handle, buff, length, 200); + furi_hal_gpio_write(handle->cs, true); +} + +void st25r3916_write_pttsn_mem(FuriHalSpiBusHandle* handle, uint8_t* buff, uint16_t length) { + furi_assert(handle); + furi_assert(buff); + + furi_hal_gpio_write(handle->cs, false); + st25r3916_reg_tx_byte(handle, ST25R3916_PT_TSN_DATA_LOAD); + furi_hal_spi_bus_tx(handle, buff, length, 200); + furi_hal_gpio_write(handle->cs, true); +} + +void st25r3916_direct_cmd(FuriHalSpiBusHandle* handle, uint8_t cmd) { + furi_assert(handle); + + furi_hal_gpio_write(handle->cs, false); + st25r3916_reg_tx_byte(handle, cmd | ST25R3916_CMD_MODE); + furi_hal_gpio_write(handle->cs, true); +} + +void st25r3916_read_test_reg(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t* val) { + furi_assert(handle); + + furi_hal_gpio_write(handle->cs, false); + st25r3916_reg_tx_byte(handle, ST25R3916_CMD_TEST_ACCESS); + st25r3916_reg_tx_byte(handle, reg | ST25R3916_READ_MODE); + furi_hal_spi_bus_rx(handle, val, 1, 5); + furi_hal_gpio_write(handle->cs, true); +} + +void st25r3916_write_test_reg(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t val) { + furi_assert(handle); + + furi_hal_gpio_write(handle->cs, false); + st25r3916_reg_tx_byte(handle, ST25R3916_CMD_TEST_ACCESS); + st25r3916_reg_tx_byte(handle, reg | ST25R3916_WRITE_MODE); + furi_hal_spi_bus_tx(handle, &val, 1, 5); + furi_hal_gpio_write(handle->cs, true); +} + +void st25r3916_clear_reg_bits(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t clr_mask) { + furi_assert(handle); + + uint8_t reg_val = 0; + st25r3916_read_reg(handle, reg, ®_val); + if((reg_val & ~clr_mask) != reg_val) { + reg_val &= ~clr_mask; + st25r3916_write_reg(handle, reg, reg_val); + } +} + +void st25r3916_set_reg_bits(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t set_mask) { + furi_assert(handle); + + uint8_t reg_val = 0; + st25r3916_read_reg(handle, reg, ®_val); + if((reg_val | set_mask) != reg_val) { + reg_val |= set_mask; + st25r3916_write_reg(handle, reg, reg_val); + } +} + +void st25r3916_change_reg_bits( + FuriHalSpiBusHandle* handle, + uint8_t reg, + uint8_t mask, + uint8_t value) { + furi_assert(handle); + + st25r3916_modify_reg(handle, reg, mask, (mask & value)); +} + +void st25r3916_modify_reg( + FuriHalSpiBusHandle* handle, + uint8_t reg, + uint8_t clr_mask, + uint8_t set_mask) { + furi_assert(handle); + + uint8_t reg_val = 0; + uint8_t new_val = 0; + st25r3916_read_reg(handle, reg, ®_val); + new_val = (reg_val & ~clr_mask) | set_mask; + if(new_val != reg_val) { + st25r3916_write_reg(handle, reg, new_val); + } +} + +void st25r3916_change_test_reg_bits( + FuriHalSpiBusHandle* handle, + uint8_t reg, + uint8_t mask, + uint8_t value) { + furi_assert(handle); + + uint8_t reg_val = 0; + uint8_t new_val = 0; + st25r3916_read_test_reg(handle, reg, ®_val); + new_val = (reg_val & ~mask) | (mask & value); + if(new_val != reg_val) { + st25r3916_write_test_reg(handle, reg, new_val); + } +} + +bool st25r3916_check_reg(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t mask, uint8_t val) { + furi_assert(handle); + + uint8_t reg_val = 0; + st25r3916_read_reg(handle, reg, ®_val); + return ((reg_val & mask) == val); +} diff --git a/lib/drivers/st25r3916_reg.h b/lib/drivers/st25r3916_reg.h new file mode 100644 index 000000000000..a9b2a532838f --- /dev/null +++ b/lib/drivers/st25r3916_reg.h @@ -0,0 +1,1087 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ST25R3916 direct commands */ +#define ST25R3916_CMD_SET_DEFAULT \ + 0xC1U /*!< Puts the chip in default state (same as after power-up) */ +#define ST25R3916_CMD_STOP 0xC2U /*!< Stops all activities and clears FIFO */ +#define ST25R3916_CMD_TRANSMIT_WITH_CRC \ + 0xC4U /*!< Transmit with CRC */ +#define ST25R3916_CMD_TRANSMIT_WITHOUT_CRC \ + 0xC5U /*!< Transmit without CRC */ +#define ST25R3916_CMD_TRANSMIT_REQA \ + 0xC6U /*!< Transmit REQA */ +#define ST25R3916_CMD_TRANSMIT_WUPA \ + 0xC7U /*!< Transmit WUPA */ +#define ST25R3916_CMD_INITIAL_RF_COLLISION \ + 0xC8U /*!< NFC transmit with Initial RF Collision Avoidance */ +#define ST25R3916_CMD_RESPONSE_RF_COLLISION_N \ + 0xC9U /*!< NFC transmit with Response RF Collision Avoidance */ +#define ST25R3916_CMD_GOTO_SENSE \ + 0xCDU /*!< Passive target logic to Sense/Idle state */ +#define ST25R3916_CMD_GOTO_SLEEP \ + 0xCEU /*!< Passive target logic to Sleep/Halt state */ +#define ST25R3916_CMD_MASK_RECEIVE_DATA \ + 0xD0U /*!< Mask receive data */ +#define ST25R3916_CMD_UNMASK_RECEIVE_DATA \ + 0xD1U /*!< Unmask receive data */ +#define ST25R3916_CMD_AM_MOD_STATE_CHANGE \ + 0xD2U /*!< AM Modulation state change */ +#define ST25R3916_CMD_MEASURE_AMPLITUDE \ + 0xD3U /*!< Measure singal amplitude on RFI inputs */ +#define ST25R3916_CMD_RESET_RXGAIN \ + 0xD5U /*!< Reset RX Gain */ +#define ST25R3916_CMD_ADJUST_REGULATORS \ + 0xD6U /*!< Adjust regulators */ +#define ST25R3916_CMD_CALIBRATE_DRIVER_TIMING \ + 0xD8U /*!< Starts the sequence to adjust the driver timing */ +#define ST25R3916_CMD_MEASURE_PHASE \ + 0xD9U /*!< Measure phase between RFO and RFI signal */ +#define ST25R3916_CMD_CLEAR_RSSI \ + 0xDAU /*!< Clear RSSI bits and restart the measurement */ +#define ST25R3916_CMD_CLEAR_FIFO \ + 0xDBU /*!< Clears FIFO, Collision and IRQ status */ +#define ST25R3916_CMD_TRANSPARENT_MODE \ + 0xDCU /*!< Transparent mode */ +#define ST25R3916_CMD_CALIBRATE_C_SENSOR \ + 0xDDU /*!< Calibrate the capacitive sensor */ +#define ST25R3916_CMD_MEASURE_CAPACITANCE \ + 0xDEU /*!< Measure capacitance */ +#define ST25R3916_CMD_MEASURE_VDD \ + 0xDFU /*!< Measure power supply voltage */ +#define ST25R3916_CMD_START_GP_TIMER \ + 0xE0U /*!< Start the general purpose timer */ +#define ST25R3916_CMD_START_WUP_TIMER \ + 0xE1U /*!< Start the wake-up timer */ +#define ST25R3916_CMD_START_MASK_RECEIVE_TIMER \ + 0xE2U /*!< Start the mask-receive timer */ +#define ST25R3916_CMD_START_NO_RESPONSE_TIMER \ + 0xE3U /*!< Start the no-response timer */ +#define ST25R3916_CMD_START_PPON2_TIMER \ + 0xE4U /*!< Start PPon2 timer */ +#define ST25R3916_CMD_STOP_NRT \ + 0xE8U /*!< Stop No Response Timer */ +#define ST25R3916_CMD_SPACE_B_ACCESS \ + 0xFBU /*!< Enable R/W access to the test registers */ +#define ST25R3916_CMD_TEST_ACCESS \ + 0xFCU /*!< Enable R/W access to the test registers */ + +#define ST25R3916_SPACE_B 0x40U /*!< ST25R3916 Space-B indicator */ +#define ST25R3916_SPACE_B_REG_LEN 16U /*!< Number of register in the space B */ + +#define ST25R3916_FIFO_STATUS_LEN 2 /*!< Number of FIFO Status Register */ + +#define ST25R3916_PTM_A_LEN 15U /*!< Passive target memory A config length */ +#define ST25R3916_PTM_B_LEN 0U /*!< Passive target memory B config length */ +#define ST25R3916_PTM_F_LEN 21U /*!< Passive target memory F config length */ +#define ST25R3916_PTM_TSN_LEN 12U /*!< Passive target memory TSN data length */ + +/*! Full Passive target memory length */ +#define ST25R3916_PTM_LEN \ + (ST25R3916_PTM_A_LEN + ST25R3916_PTM_B_LEN + ST25R3916_PTM_F_LEN + ST25R3916_PTM_TSN_LEN) + +/* IO configuration registers */ +#define ST25R3916_REG_IO_CONF1 0x00U /*!< RW IO Configuration Register 1 */ +#define ST25R3916_REG_IO_CONF2 0x01U /*!< RW IO Configuration Register 2 */ + +/* Operation control and mode definition registers */ +#define ST25R3916_REG_OP_CONTROL 0x02U /*!< RW Operation Control Register */ +#define ST25R3916_REG_MODE 0x03U /*!< RW Mode Definition Register */ +#define ST25R3916_REG_BIT_RATE 0x04U /*!< RW Bit Rate Definition Register */ + +/* Protocol Configuration registers */ +#define ST25R3916_REG_ISO14443A_NFC \ + 0x05U /*!< RW ISO14443A and NFC 106 kBit/s Settings Register */ +#define ST25R3916_REG_EMD_SUP_CONF \ + (ST25R3916_SPACE_B | 0x05U) /*!< RW EMD Suppression Configuration Register */ +#define ST25R3916_REG_ISO14443B_1 \ + 0x06U /*!< RW ISO14443B Settings Register 1 */ +#define ST25R3916_REG_SUBC_START_TIME \ + (ST25R3916_SPACE_B | 0x06U) /*!< RW Subcarrier Start Time Register */ +#define ST25R3916_REG_ISO14443B_2 \ + 0x07U /*!< RW ISO14443B Settings Register 2 */ +#define ST25R3916_REG_PASSIVE_TARGET \ + 0x08U /*!< RW Passive Target Definition Register */ +#define ST25R3916_REG_STREAM_MODE \ + 0x09U /*!< RW Stream Mode Definition Register */ +#define ST25R3916_REG_AUX 0x0AU /*!< RW Auxiliary Definition Register */ + +/* Receiver Configuration registers */ +#define ST25R3916_REG_RX_CONF1 0x0BU /*!< RW Receiver Configuration Register 1 */ +#define ST25R3916_REG_RX_CONF2 0x0CU /*!< RW Receiver Configuration Register 2 */ +#define ST25R3916_REG_RX_CONF3 0x0DU /*!< RW Receiver Configuration Register 3 */ +#define ST25R3916_REG_RX_CONF4 0x0EU /*!< RW Receiver Configuration Register 4 */ +#define ST25R3916_REG_P2P_RX_CONF \ + (ST25R3916_SPACE_B | 0x0BU) /*!< RW P2P Receiver Configuration Register 1 */ +#define ST25R3916_REG_CORR_CONF1 \ + (ST25R3916_SPACE_B | 0x0CU) /*!< RW Correlator configuration register 1 */ +#define ST25R3916_REG_CORR_CONF2 \ + (ST25R3916_SPACE_B | 0x0DU) /*!< RW Correlator configuration register 2 */ + +/* Timer definition registers */ +#define ST25R3916_REG_MASK_RX_TIMER \ + 0x0FU /*!< RW Mask Receive Timer Register */ +#define ST25R3916_REG_NO_RESPONSE_TIMER1 \ + 0x10U /*!< RW No-response Timer Register 1 */ +#define ST25R3916_REG_NO_RESPONSE_TIMER2 \ + 0x11U /*!< RW No-response Timer Register 2 */ +#define ST25R3916_REG_TIMER_EMV_CONTROL \ + 0x12U /*!< RW Timer and EMV Control */ +#define ST25R3916_REG_GPT1 0x13U /*!< RW General Purpose Timer Register 1 */ +#define ST25R3916_REG_GPT2 0x14U /*!< RW General Purpose Timer Register 2 */ +#define ST25R3916_REG_PPON2 0x15U /*!< RW PPON2 Field waiting Timer Register */ +#define ST25R3916_REG_SQUELCH_TIMER \ + (ST25R3916_SPACE_B | 0x0FU) /*!< RW Squelch timeout Register */ +#define ST25R3916_REG_FIELD_ON_GT \ + (ST25R3916_SPACE_B | 0x15U) /*!< RW NFC Field on guard time */ + +/* Interrupt and associated reporting registers */ +#define ST25R3916_REG_IRQ_MASK_MAIN \ + 0x16U /*!< RW Mask Main Interrupt Register */ +#define ST25R3916_REG_IRQ_MASK_TIMER_NFC \ + 0x17U /*!< RW Mask Timer and NFC Interrupt Register */ +#define ST25R3916_REG_IRQ_MASK_ERROR_WUP \ + 0x18U /*!< RW Mask Error and Wake-up Interrupt Register */ +#define ST25R3916_REG_IRQ_MASK_TARGET \ + 0x19U /*!< RW Mask 3916 Target Interrupt Register */ +#define ST25R3916_REG_IRQ_MAIN 0x1AU /*!< R Main Interrupt Register */ +#define ST25R3916_REG_IRQ_TIMER_NFC \ + 0x1BU /*!< R Timer and NFC Interrupt Register */ +#define ST25R3916_REG_IRQ_ERROR_WUP \ + 0x1CU /*!< R Error and Wake-up Interrupt Register */ +#define ST25R3916_REG_IRQ_TARGET 0x1DU /*!< R ST25R3916 Target Interrupt Register */ +#define ST25R3916_REG_FIFO_STATUS1 \ + 0x1EU /*!< R FIFO Status Register 1 */ +#define ST25R3916_REG_FIFO_STATUS2 \ + 0x1FU /*!< R FIFO Status Register 2 */ +#define ST25R3916_REG_COLLISION_STATUS \ + 0x20U /*!< R Collision Display Register */ +#define ST25R3916_REG_PASSIVE_TARGET_STATUS \ + 0x21U /*!< R Passive target state status */ + +/* Definition of number of transmitted bytes */ +#define ST25R3916_REG_NUM_TX_BYTES1 \ + 0x22U /*!< RW Number of Transmitted Bytes Register 1 */ +#define ST25R3916_REG_NUM_TX_BYTES2 \ + 0x23U /*!< RW Number of Transmitted Bytes Register 2 */ + +/* NFCIP Bit Rate Display Register */ +#define ST25R3916_REG_NFCIP1_BIT_RATE \ + 0x24U /*!< R NFCIP Bit Rate Detection Display Register */ + +/* A/D Converter Output Register */ +#define ST25R3916_REG_AD_RESULT 0x25U /*!< R A/D Converter Output Register */ + +/* Antenna tuning registers */ +#define ST25R3916_REG_ANT_TUNE_A 0x26U /*!< RW Antenna Tuning Control (AAT-A) Register 1 */ +#define ST25R3916_REG_ANT_TUNE_B 0x27U /*!< RW Antenna Tuning Control (AAT-B) Register 2 */ + +/* Antenna Driver and Modulation registers */ +#define ST25R3916_REG_TX_DRIVER 0x28U /*!< RW TX driver register */ +#define ST25R3916_REG_PT_MOD 0x29U /*!< RW PT modulation Register */ +#define ST25R3916_REG_AUX_MOD \ + (ST25R3916_SPACE_B | 0x28U) /*!< RW Aux Modulation setting Register */ +#define ST25R3916_REG_TX_DRIVER_TIMING \ + (ST25R3916_SPACE_B | 0x29U) /*!< RW TX driver timing Register */ +#define ST25R3916_REG_RES_AM_MOD \ + (ST25R3916_SPACE_B | 0x2AU) /*!< RW Resistive AM modulation register */ +#define ST25R3916_REG_TX_DRIVER_STATUS \ + (ST25R3916_SPACE_B | 0x2BU) /*!< R TX driver timing readout Register */ + +/* External Field Detector Threshold Registers */ +#define ST25R3916_REG_FIELD_THRESHOLD_ACTV \ + 0x2AU /*!< RW External Field Detector Activation Threshold Reg */ +#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV \ + 0x2BU /*!< RW External Field Detector Deactivation Threshold Reg*/ + +/* Regulator registers */ +#define ST25R3916_REG_REGULATOR_CONTROL \ + 0x2CU /*!< RW Regulated Voltage Control Register */ +#define ST25R3916_REG_REGULATOR_RESULT \ + (ST25R3916_SPACE_B | 0x2CU) /*!< R Regulator Display Register */ + +/* Receiver State Display Register */ +#define ST25R3916_REG_RSSI_RESULT \ + 0x2DU /*!< R RSSI Display Register */ +#define ST25R3916_REG_GAIN_RED_STATE \ + 0x2EU /*!< R Gain Reduction State Register */ +#define ST25R3916_REG_CAP_SENSOR_CONTROL \ + 0x2FU /*!< RW Capacitive Sensor Control Register */ +#define ST25R3916_REG_CAP_SENSOR_RESULT \ + 0x30U /*!< R Capacitive Sensor Display Register */ +#define ST25R3916_REG_AUX_DISPLAY \ + 0x31U /*!< R Auxiliary Display Register */ + +/* Over/Undershoot Protection Configuration Registers */ +#define ST25R3916_REG_OVERSHOOT_CONF1 \ + (ST25R3916_SPACE_B | 0x30U) /*!< RW Overshoot Protection Configuration Register 1 */ +#define ST25R3916_REG_OVERSHOOT_CONF2 \ + (ST25R3916_SPACE_B | 0x31U) /*!< RW Overshoot Protection Configuration Register 2 */ +#define ST25R3916_REG_UNDERSHOOT_CONF1 \ + (ST25R3916_SPACE_B | 0x32U) /*!< RW Undershoot Protection Configuration Register 1 */ +#define ST25R3916_REG_UNDERSHOOT_CONF2 \ + (ST25R3916_SPACE_B | 0x33U) /*!< RW Undershoot Protection Configuration Register 2 */ + +/* Detection of card presence */ +#define ST25R3916_REG_WUP_TIMER_CONTROL \ + 0x32U /*!< RW Wake-up Timer Control Register */ +#define ST25R3916_REG_AMPLITUDE_MEASURE_CONF \ + 0x33U /*!< RW Amplitude Measurement Configuration Register */ +#define ST25R3916_REG_AMPLITUDE_MEASURE_REF \ + 0x34U /*!< RW Amplitude Measurement Reference Register */ +#define ST25R3916_REG_AMPLITUDE_MEASURE_AA_RESULT \ + 0x35U /*!< R Amplitude Measurement Auto Averaging Display Reg */ +#define ST25R3916_REG_AMPLITUDE_MEASURE_RESULT \ + 0x36U /*!< R Amplitude Measurement Display Register */ +#define ST25R3916_REG_PHASE_MEASURE_CONF \ + 0x37U /*!< RW Phase Measurement Configuration Register */ +#define ST25R3916_REG_PHASE_MEASURE_REF \ + 0x38U /*!< RW Phase Measurement Reference Register */ +#define ST25R3916_REG_PHASE_MEASURE_AA_RESULT \ + 0x39U /*!< R Phase Measurement Auto Averaging Display Register */ +#define ST25R3916_REG_PHASE_MEASURE_RESULT \ + 0x3AU /*!< R Phase Measurement Display Register */ +#define ST25R3916_REG_CAPACITANCE_MEASURE_CONF \ + 0x3BU /*!< RW Capacitance Measurement Configuration Register */ +#define ST25R3916_REG_CAPACITANCE_MEASURE_REF \ + 0x3CU /*!< RW Capacitance Measurement Reference Register */ +#define ST25R3916_REG_CAPACITANCE_MEASURE_AA_RESULT \ + 0x3DU /*!< R Capacitance Measurement Auto Averaging Display Reg*/ +#define ST25R3916_REG_CAPACITANCE_MEASURE_RESULT \ + 0x3EU /*!< R Capacitance Measurement Display Register */ + +/* IC identity */ +#define ST25R3916_REG_IC_IDENTITY \ + 0x3FU /*!< R Chip Id: 0 for old silicon, v2 silicon: 0x09 */ + +/*! Register bit definitions \cond DOXYGEN_SUPRESS */ + +#define ST25R3916_REG_IO_CONF1_single (1U << 7) +#define ST25R3916_REG_IO_CONF1_rfo2 (1U << 6) +#define ST25R3916_REG_IO_CONF1_i2c_thd1 (1U << 5) +#define ST25R3916_REG_IO_CONF1_i2c_thd0 (1U << 4) +#define ST25R3916_REG_IO_CONF1_i2c_thd_mask (3U << 4) +#define ST25R3916_REG_IO_CONF1_i2c_thd_shift (4U) +#define ST25R3916_REG_IO_CONF1_rfu (1U << 3) +#define ST25R3916_REG_IO_CONF1_out_cl1 (1U << 2) +#define ST25R3916_REG_IO_CONF1_out_cl0 (1U << 1) +#define ST25R3916_REG_IO_CONF1_out_cl_disabled (3U << 1) +#define ST25R3916_REG_IO_CONF1_out_cl_13_56MHZ (2U << 1) +#define ST25R3916_REG_IO_CONF1_out_cl_4_78MHZ (1U << 1) +#define ST25R3916_REG_IO_CONF1_out_cl_3_39MHZ (0U << 1) +#define ST25R3916_REG_IO_CONF1_out_cl_mask (3U << 1) +#define ST25R3916_REG_IO_CONF1_out_cl_shift (1U) +#define ST25R3916_REG_IO_CONF1_lf_clk_off (1U << 0) +#define ST25R3916_REG_IO_CONF1_lf_clk_off_on (1U << 0) +#define ST25R3916_REG_IO_CONF1_lf_clk_off_off (0U << 0) + +#define ST25R3916_REG_IO_CONF2_sup3V (1U << 7) +#define ST25R3916_REG_IO_CONF2_sup3V_3V (1U << 7) +#define ST25R3916_REG_IO_CONF2_sup3V_5V (0U << 7) +#define ST25R3916_REG_IO_CONF2_vspd_off (1U << 6) +#define ST25R3916_REG_IO_CONF2_aat_en (1U << 5) +#define ST25R3916_REG_IO_CONF2_miso_pd2 (1U << 4) +#define ST25R3916_REG_IO_CONF2_miso_pd1 (1U << 3) +#define ST25R3916_REG_IO_CONF2_io_drv_lvl (1U << 2) +#define ST25R3916_REG_IO_CONF2_slow_up (1U << 0) + +#define ST25R3916_REG_OP_CONTROL_en (1U << 7) +#define ST25R3916_REG_OP_CONTROL_rx_en (1U << 6) +#define ST25R3916_REG_OP_CONTROL_rx_chn (1U << 5) +#define ST25R3916_REG_OP_CONTROL_rx_man (1U << 4) +#define ST25R3916_REG_OP_CONTROL_tx_en (1U << 3) +#define ST25R3916_REG_OP_CONTROL_wu (1U << 2) +#define ST25R3916_REG_OP_CONTROL_en_fd_c1 (1U << 1) +#define ST25R3916_REG_OP_CONTROL_en_fd_c0 (1U << 0) +#define ST25R3916_REG_OP_CONTROL_en_fd_efd_off (0U << 0) +#define ST25R3916_REG_OP_CONTROL_en_fd_manual_efd_ca (1U << 0) +#define ST25R3916_REG_OP_CONTROL_en_fd_manual_efd_pdt (2U << 0) +#define ST25R3916_REG_OP_CONTROL_en_fd_auto_efd (3U << 0) +#define ST25R3916_REG_OP_CONTROL_en_fd_shift (0U) +#define ST25R3916_REG_OP_CONTROL_en_fd_mask (3U << 0) + +#define ST25R3916_REG_MODE_targ (1U << 7) +#define ST25R3916_REG_MODE_targ_targ (1U << 7) +#define ST25R3916_REG_MODE_targ_init (0U << 7) +#define ST25R3916_REG_MODE_om3 (1U << 6) +#define ST25R3916_REG_MODE_om2 (1U << 5) +#define ST25R3916_REG_MODE_om1 (1U << 4) +#define ST25R3916_REG_MODE_om0 (1U << 3) +#define ST25R3916_REG_MODE_om_bpsk_stream (0xfU << 3) +#define ST25R3916_REG_MODE_om_subcarrier_stream (0xeU << 3) +#define ST25R3916_REG_MODE_om_topaz (0x4U << 3) +#define ST25R3916_REG_MODE_om_felica (0x3U << 3) +#define ST25R3916_REG_MODE_om_iso14443b (0x2U << 3) +#define ST25R3916_REG_MODE_om_iso14443a (0x1U << 3) +#define ST25R3916_REG_MODE_om_targ_nfca (0x1U << 3) +#define ST25R3916_REG_MODE_om_targ_nfcb (0x2U << 3) +#define ST25R3916_REG_MODE_om_targ_nfcf (0x4U << 3) +#define ST25R3916_REG_MODE_om_targ_nfcip (0x7U << 3) +#define ST25R3916_REG_MODE_om_nfc (0x0U << 3) +#define ST25R3916_REG_MODE_om_mask (0xfU << 3) +#define ST25R3916_REG_MODE_om_shift (3U) +#define ST25R3916_REG_MODE_tr_am (1U << 2) +#define ST25R3916_REG_MODE_tr_am_ook (0U << 2) +#define ST25R3916_REG_MODE_tr_am_am (1U << 2) +#define ST25R3916_REG_MODE_nfc_ar1 (1U << 1) +#define ST25R3916_REG_MODE_nfc_ar0 (1U << 0) +#define ST25R3916_REG_MODE_nfc_ar_off (0U << 0) +#define ST25R3916_REG_MODE_nfc_ar_auto_rx (1U << 0) +#define ST25R3916_REG_MODE_nfc_ar_eof (2U << 0) +#define ST25R3916_REG_MODE_nfc_ar_rfu (3U << 0) +#define ST25R3916_REG_MODE_nfc_ar_mask (3U << 0) +#define ST25R3916_REG_MODE_nfc_ar_shift (0U) + +#define ST25R3916_REG_BIT_RATE_txrate_106 (0x0U << 4) +#define ST25R3916_REG_BIT_RATE_txrate_212 (0x1U << 4) +#define ST25R3916_REG_BIT_RATE_txrate_424 (0x2U << 4) +#define ST25R3916_REG_BIT_RATE_txrate_848 (0x3U << 4) +#define ST25R3916_REG_BIT_RATE_txrate_mask (0x3U << 4) +#define ST25R3916_REG_BIT_RATE_txrate_shift (4U) +#define ST25R3916_REG_BIT_RATE_rxrate_106 (0x0U << 0) +#define ST25R3916_REG_BIT_RATE_rxrate_212 (0x1U << 0) +#define ST25R3916_REG_BIT_RATE_rxrate_424 (0x2U << 0) +#define ST25R3916_REG_BIT_RATE_rxrate_848 (0x3U << 0) +#define ST25R3916_REG_BIT_RATE_rxrate_mask (0x3U << 0) +#define ST25R3916_REG_BIT_RATE_rxrate_shift (0U) + +#define ST25R3916_REG_ISO14443A_NFC_no_tx_par (1U << 7) +#define ST25R3916_REG_ISO14443A_NFC_no_tx_par_off (0U << 7) +#define ST25R3916_REG_ISO14443A_NFC_no_rx_par (1U << 6) +#define ST25R3916_REG_ISO14443A_NFC_no_rx_par_off (0U << 6) +#define ST25R3916_REG_ISO14443A_NFC_nfc_f0 (1U << 5) +#define ST25R3916_REG_ISO14443A_NFC_nfc_f0_off (0U << 5) +#define ST25R3916_REG_ISO14443A_NFC_p_len3 (1U << 4) +#define ST25R3916_REG_ISO14443A_NFC_p_len2 (1U << 3) +#define ST25R3916_REG_ISO14443A_NFC_p_len1 (1U << 2) +#define ST25R3916_REG_ISO14443A_NFC_p_len0 (1U << 1) +#define ST25R3916_REG_ISO14443A_NFC_p_len_mask (0xfU << 1) +#define ST25R3916_REG_ISO14443A_NFC_p_len_shift (1U) +#define ST25R3916_REG_ISO14443A_NFC_antcl (1U << 0) + +#define ST25R3916_REG_EMD_SUP_CONF_emd_emv (1U << 7) +#define ST25R3916_REG_EMD_SUP_CONF_emd_emv_on (1U << 7) +#define ST25R3916_REG_EMD_SUP_CONF_emd_emv_off (0U << 7) +#define ST25R3916_REG_EMD_SUP_CONF_rx_start_emv (1U << 6) +#define ST25R3916_REG_EMD_SUP_CONF_rx_start_emv_on (1U << 6) +#define ST25R3916_REG_EMD_SUP_CONF_rx_start_emv_off (0U << 6) +#define ST25R3916_REG_EMD_SUP_CONF_rfu1 (1U << 5) +#define ST25R3916_REG_EMD_SUP_CONF_rfu0 (1U << 4) +#define ST25R3916_REG_EMD_SUP_CONF_emd_thld3 (1U << 3) +#define ST25R3916_REG_EMD_SUP_CONF_emd_thld2 (1U << 2) +#define ST25R3916_REG_EMD_SUP_CONF_emd_thld1 (1U << 1) +#define ST25R3916_REG_EMD_SUP_CONF_emd_thld0 (1U << 0) +#define ST25R3916_REG_EMD_SUP_CONF_emd_thld_mask (0xfU << 0) +#define ST25R3916_REG_EMD_SUP_CONF_emd_thld_shift (0U) + +#define ST25R3916_REG_SUBC_START_TIME_rfu2 (1U << 7) +#define ST25R3916_REG_SUBC_START_TIME_rfu1 (1U << 6) +#define ST25R3916_REG_SUBC_START_TIME_rfu0 (1U << 5) +#define ST25R3916_REG_SUBC_START_TIME_sst4 (1U << 4) +#define ST25R3916_REG_SUBC_START_TIME_sst3 (1U << 3) +#define ST25R3916_REG_SUBC_START_TIME_sst2 (1U << 2) +#define ST25R3916_REG_SUBC_START_TIME_sst1 (1U << 1) +#define ST25R3916_REG_SUBC_START_TIME_sst0 (1U << 0) +#define ST25R3916_REG_SUBC_START_TIME_sst_mask (0x1fU << 0) +#define ST25R3916_REG_SUBC_START_TIME_sst_shift (0U) + +#define ST25R3916_REG_ISO14443B_1_egt2 (1U << 7) +#define ST25R3916_REG_ISO14443B_1_egt1 (1U << 6) +#define ST25R3916_REG_ISO14443B_1_egt0 (1U << 5) +#define ST25R3916_REG_ISO14443B_1_egt_shift (5U) +#define ST25R3916_REG_ISO14443B_1_egt_mask (7U << 5) +#define ST25R3916_REG_ISO14443B_1_sof_1 (1U << 3) +#define ST25R3916_REG_ISO14443B_1_sof_1_3etu (1U << 3) +#define ST25R3916_REG_ISO14443B_1_sof_1_2etu (0U << 3) +#define ST25R3916_REG_ISO14443B_1_sof_0 (1U << 4) +#define ST25R3916_REG_ISO14443B_1_sof_0_11etu (1U << 4) +#define ST25R3916_REG_ISO14443B_1_sof_0_10etu (0U << 4) +#define ST25R3916_REG_ISO14443B_1_sof_mask (3U << 3) +#define ST25R3916_REG_ISO14443B_1_eof (1U << 2) +#define ST25R3916_REG_ISO14443B_1_eof_11etu (1U << 2) +#define ST25R3916_REG_ISO14443B_1_eof_10etu (0U << 2) +#define ST25R3916_REG_ISO14443B_1_half (1U << 1) +#define ST25R3916_REG_ISO14443B_1_rx_st_om (1U << 0) + +#define ST25R3916_REG_ISO14443B_2_tr1_1 (1U << 7) +#define ST25R3916_REG_ISO14443B_2_tr1_0 (1U << 6) +#define ST25R3916_REG_ISO14443B_2_tr1_64fs32fs (1U << 6) +#define ST25R3916_REG_ISO14443B_2_tr1_80fs80fs (0U << 6) +#define ST25R3916_REG_ISO14443B_2_tr1_mask (3U << 6) +#define ST25R3916_REG_ISO14443B_2_tr1_shift (6U) +#define ST25R3916_REG_ISO14443B_2_no_sof (1U << 5) +#define ST25R3916_REG_ISO14443B_2_no_eof (1U << 4) +#define ST25R3916_REG_ISO14443B_rfu1 (1U << 3) +#define ST25R3916_REG_ISO14443B_rfu0 (1U << 2) +#define ST25R3916_REG_ISO14443B_2_f_p1 (1U << 1) +#define ST25R3916_REG_ISO14443B_2_f_p0 (1U << 0) +#define ST25R3916_REG_ISO14443B_2_f_p_96 (3U << 0) +#define ST25R3916_REG_ISO14443B_2_f_p_80 (2U << 0) +#define ST25R3916_REG_ISO14443B_2_f_p_64 (1U << 0) +#define ST25R3916_REG_ISO14443B_2_f_p_48 (0U << 0) +#define ST25R3916_REG_ISO14443B_2_f_p_mask (3U << 0) +#define ST25R3916_REG_ISO14443B_2_f_p_shift (0U) + +#define ST25R3916_REG_PASSIVE_TARGET_fdel_3 (1U << 7) +#define ST25R3916_REG_PASSIVE_TARGET_fdel_2 (1U << 6) +#define ST25R3916_REG_PASSIVE_TARGET_fdel_1 (1U << 5) +#define ST25R3916_REG_PASSIVE_TARGET_fdel_0 (1U << 4) +#define ST25R3916_REG_PASSIVE_TARGET_fdel_mask (0xfU << 4) +#define ST25R3916_REG_PASSIVE_TARGET_fdel_shift (4U) +#define ST25R3916_REG_PASSIVE_TARGET_d_ac_ap2p (1U << 3) +#define ST25R3916_REG_PASSIVE_TARGET_d_212_424_1r (1U << 2) +#define ST25R3916_REG_PASSIVE_TARGET_rfu (1U << 1) +#define ST25R3916_REG_PASSIVE_TARGET_d_106_ac_a (1U << 0) + +#define ST25R3916_REG_STREAM_MODE_rfu (1U << 7) +#define ST25R3916_REG_STREAM_MODE_scf1 (1U << 6) +#define ST25R3916_REG_STREAM_MODE_scf0 (1U << 5) +#define ST25R3916_REG_STREAM_MODE_scf_sc212 (0U << 5) +#define ST25R3916_REG_STREAM_MODE_scf_sc424 (1U << 5) +#define ST25R3916_REG_STREAM_MODE_scf_sc848 (2U << 5) +#define ST25R3916_REG_STREAM_MODE_scf_sc1695 (3U << 5) +#define ST25R3916_REG_STREAM_MODE_scf_bpsk848 (0U << 5) +#define ST25R3916_REG_STREAM_MODE_scf_bpsk1695 (1U << 5) +#define ST25R3916_REG_STREAM_MODE_scf_bpsk3390 (2U << 5) +#define ST25R3916_REG_STREAM_MODE_scf_bpsk106 (3U << 5) +#define ST25R3916_REG_STREAM_MODE_scf_mask (3U << 5) +#define ST25R3916_REG_STREAM_MODE_scf_shift (5U) +#define ST25R3916_REG_STREAM_MODE_scp1 (1U << 4) +#define ST25R3916_REG_STREAM_MODE_scp0 (1U << 3) +#define ST25R3916_REG_STREAM_MODE_scp_1pulse (0U << 3) +#define ST25R3916_REG_STREAM_MODE_scp_2pulses (1U << 3) +#define ST25R3916_REG_STREAM_MODE_scp_4pulses (2U << 3) +#define ST25R3916_REG_STREAM_MODE_scp_8pulses (3U << 3) +#define ST25R3916_REG_STREAM_MODE_scp_mask (3U << 3) +#define ST25R3916_REG_STREAM_MODE_scp_shift (3U) +#define ST25R3916_REG_STREAM_MODE_stx2 (1U << 2) +#define ST25R3916_REG_STREAM_MODE_stx1 (1U << 1) +#define ST25R3916_REG_STREAM_MODE_stx0 (1U << 0) +#define ST25R3916_REG_STREAM_MODE_stx_106 (0U << 0) +#define ST25R3916_REG_STREAM_MODE_stx_212 (1U << 0) +#define ST25R3916_REG_STREAM_MODE_stx_424 (2U << 0) +#define ST25R3916_REG_STREAM_MODE_stx_848 (3U << 0) +#define ST25R3916_REG_STREAM_MODE_stx_mask (7U << 0) +#define ST25R3916_REG_STREAM_MODE_stx_shift (0U) + +#define ST25R3916_REG_AUX_no_crc_rx (1U << 7) +#define ST25R3916_REG_AUX_rfu (1U << 6) +#define ST25R3916_REG_AUX_nfc_id1 (1U << 5) +#define ST25R3916_REG_AUX_nfc_id0 (1U << 4) +#define ST25R3916_REG_AUX_nfc_id_7bytes (1U << 4) +#define ST25R3916_REG_AUX_nfc_id_4bytes (0U << 4) +#define ST25R3916_REG_AUX_nfc_id_mask (3U << 4) +#define ST25R3916_REG_AUX_nfc_id_shift (4U) +#define ST25R3916_REG_AUX_mfaz_cl90 (1U << 3) +#define ST25R3916_REG_AUX_dis_corr (1U << 2) +#define ST25R3916_REG_AUX_dis_corr_coherent (1U << 2) +#define ST25R3916_REG_AUX_dis_corr_correlator (0U << 2) +#define ST25R3916_REG_AUX_nfc_n1 (1U << 1) +#define ST25R3916_REG_AUX_nfc_n0 (1U << 0) +#define ST25R3916_REG_AUX_nfc_n_mask (3U << 0) +#define ST25R3916_REG_AUX_nfc_n_shift (0U) + +#define ST25R3916_REG_RX_CONF1_ch_sel (1U << 7) +#define ST25R3916_REG_RX_CONF1_ch_sel_PM (1U << 7) +#define ST25R3916_REG_RX_CONF1_ch_sel_AM (0U << 7) +#define ST25R3916_REG_RX_CONF1_lp2 (1U << 6) +#define ST25R3916_REG_RX_CONF1_lp1 (1U << 5) +#define ST25R3916_REG_RX_CONF1_lp0 (1U << 4) +#define ST25R3916_REG_RX_CONF1_lp_1200khz (0U << 4) +#define ST25R3916_REG_RX_CONF1_lp_600khz (1U << 4) +#define ST25R3916_REG_RX_CONF1_lp_300khz (2U << 4) +#define ST25R3916_REG_RX_CONF1_lp_2000khz (4U << 4) +#define ST25R3916_REG_RX_CONF1_lp_7000khz (5U << 4) +#define ST25R3916_REG_RX_CONF1_lp_mask (7U << 4) +#define ST25R3916_REG_RX_CONF1_lp_shift (4U) +#define ST25R3916_REG_RX_CONF1_z600k (1U << 3) +#define ST25R3916_REG_RX_CONF1_h200 (1U << 2) +#define ST25R3916_REG_RX_CONF1_h80 (1U << 1) +#define ST25R3916_REG_RX_CONF1_z12k (1U << 0) +#define ST25R3916_REG_RX_CONF1_hz_60_400khz (0U << 0) +#define ST25R3916_REG_RX_CONF1_hz_60_200khz (4U << 0) +#define ST25R3916_REG_RX_CONF1_hz_40_80khz (2U << 0) +#define ST25R3916_REG_RX_CONF1_hz_12_200khz (1U << 0) +#define ST25R3916_REG_RX_CONF1_hz_12_80khz (3U << 0) +#define ST25R3916_REG_RX_CONF1_hz_12_200khz_alt (5U << 0) +#define ST25R3916_REG_RX_CONF1_hz_600_400khz (8U << 0) +#define ST25R3916_REG_RX_CONF1_hz_600_200khz (12U << 0) +#define ST25R3916_REG_RX_CONF1_hz_mask (0xfU << 0) +#define ST25R3916_REG_RX_CONF1_hz_shift (0U) + +#define ST25R3916_REG_RX_CONF2_demod_mode (1U << 7) +#define ST25R3916_REG_RX_CONF2_amd_sel (1U << 6) +#define ST25R3916_REG_RX_CONF2_amd_sel_mixer (1U << 6) +#define ST25R3916_REG_RX_CONF2_amd_sel_peak (0U << 6) +#define ST25R3916_REG_RX_CONF2_sqm_dyn (1U << 5) +#define ST25R3916_REG_RX_CONF2_pulz_61 (1U << 4) +#define ST25R3916_REG_RX_CONF2_agc_en (1U << 3) +#define ST25R3916_REG_RX_CONF2_agc_m (1U << 2) +#define ST25R3916_REG_RX_CONF2_agc_alg (1U << 1) +#define ST25R3916_REG_RX_CONF2_agc6_3 (1U << 0) + +#define ST25R3916_REG_RX_CONF3_rg1_am2 (1U << 7) +#define ST25R3916_REG_RX_CONF3_rg1_am1 (1U << 6) +#define ST25R3916_REG_RX_CONF3_rg1_am0 (1U << 5) +#define ST25R3916_REG_RX_CONF3_rg1_am_mask (0x7U << 5) +#define ST25R3916_REG_RX_CONF3_rg1_am_shift (5U) +#define ST25R3916_REG_RX_CONF3_rg1_pm2 (1U << 4) +#define ST25R3916_REG_RX_CONF3_rg1_pm1 (1U << 3) +#define ST25R3916_REG_RX_CONF3_rg1_pm0 (1U << 2) +#define ST25R3916_REG_RX_CONF3_rg1_pm_mask (0x7U << 2) +#define ST25R3916_REG_RX_CONF3_rg1_pm_shift (2U) +#define ST25R3916_REG_RX_CONF3_lf_en (1U << 1) +#define ST25R3916_REG_RX_CONF3_lf_op (1U << 0) + +#define ST25R3916_REG_RX_CONF4_rg2_am3 (1U << 7) +#define ST25R3916_REG_RX_CONF4_rg2_am2 (1U << 6) +#define ST25R3916_REG_RX_CONF4_rg2_am1 (1U << 5) +#define ST25R3916_REG_RX_CONF4_rg2_am0 (1U << 4) +#define ST25R3916_REG_RX_CONF4_rg2_am_mask (0xfU << 4) +#define ST25R3916_REG_RX_CONF4_rg2_am_shift (4U) +#define ST25R3916_REG_RX_CONF4_rg2_pm3 (1U << 3) +#define ST25R3916_REG_RX_CONF4_rg2_pm2 (1U << 2) +#define ST25R3916_REG_RX_CONF4_rg2_pm1 (1U << 1) +#define ST25R3916_REG_RX_CONF4_rg2_pm0 (1U << 0) +#define ST25R3916_REG_RX_CONF4_rg2_pm_mask (0xfU << 0) +#define ST25R3916_REG_RX_CONF4_rg2_pm_shift (0U) + +#define ST25R3916_REG_P2P_RX_CONF_ook_fd (1U << 7) +#define ST25R3916_REG_P2P_RX_CONF_ook_rc1 (1U << 6) +#define ST25R3916_REG_P2P_RX_CONF_ook_rc0 (1U << 5) +#define ST25R3916_REG_P2P_RX_CONF_ook_thd1 (1U << 4) +#define ST25R3916_REG_P2P_RX_CONF_ook_thd0 (1U << 3) +#define ST25R3916_REG_P2P_RX_CONF_ask_rc1 (1U << 2) +#define ST25R3916_REG_P2P_RX_CONF_ask_rc0 (1U << 1) +#define ST25R3916_REG_P2P_RX_CONF_ask_thd (1U << 0) + +#define ST25R3916_REG_CORR_CONF1_corr_s7 (1U << 7) +#define ST25R3916_REG_CORR_CONF1_corr_s6 (1U << 6) +#define ST25R3916_REG_CORR_CONF1_corr_s5 (1U << 5) +#define ST25R3916_REG_CORR_CONF1_corr_s4 (1U << 4) +#define ST25R3916_REG_CORR_CONF1_corr_s3 (1U << 3) +#define ST25R3916_REG_CORR_CONF1_corr_s2 (1U << 2) +#define ST25R3916_REG_CORR_CONF1_corr_s1 (1U << 1) +#define ST25R3916_REG_CORR_CONF1_corr_s0 (1U << 0) + +#define ST25R3916_REG_CORR_CONF2_rfu5 (1U << 7) +#define ST25R3916_REG_CORR_CONF2_rfu4 (1U << 6) +#define ST25R3916_REG_CORR_CONF2_rfu3 (1U << 5) +#define ST25R3916_REG_CORR_CONF2_rfu2 (1U << 4) +#define ST25R3916_REG_CORR_CONF2_rfu1 (1U << 3) +#define ST25R3916_REG_CORR_CONF2_rfu0 (1U << 2) +#define ST25R3916_REG_CORR_CONF2_corr_s9 (1U << 1) +#define ST25R3916_REG_CORR_CONF2_corr_s8 (1U << 0) + +#define ST25R3916_REG_TIMER_EMV_CONTROL_gptc2 (1U << 7) +#define ST25R3916_REG_TIMER_EMV_CONTROL_gptc1 (1U << 6) +#define ST25R3916_REG_TIMER_EMV_CONTROL_gptc0 (1U << 5) +#define ST25R3916_REG_TIMER_EMV_CONTROL_gptc_no_trigger (0U << 5) +#define ST25R3916_REG_TIMER_EMV_CONTROL_gptc_erx (1U << 5) +#define ST25R3916_REG_TIMER_EMV_CONTROL_gptc_srx (2U << 5) +#define ST25R3916_REG_TIMER_EMV_CONTROL_gptc_etx_nfc (3U << 5) +#define ST25R3916_REG_TIMER_EMV_CONTROL_gptc_mask (7U << 5) +#define ST25R3916_REG_TIMER_EMV_CONTROL_gptc_shift (5U) +#define ST25R3916_REG_TIMER_EMV_CONTROL_rfu (1U << 4) +#define ST25R3916_REG_TIMER_EMV_CONTROL_mrt_step (1U << 3) +#define ST25R3916_REG_TIMER_EMV_CONTROL_mrt_step_512 (1U << 3) +#define ST25R3916_REG_TIMER_EMV_CONTROL_mrt_step_64 (0U << 3) +#define ST25R3916_REG_TIMER_EMV_CONTROL_nrt_nfc (1U << 2) +#define ST25R3916_REG_TIMER_EMV_CONTROL_nrt_nfc_on (1U << 2) +#define ST25R3916_REG_TIMER_EMV_CONTROL_nrt_nfc_off (0U << 2) +#define ST25R3916_REG_TIMER_EMV_CONTROL_nrt_emv (1U << 1) +#define ST25R3916_REG_TIMER_EMV_CONTROL_nrt_emv_on (1U << 1) +#define ST25R3916_REG_TIMER_EMV_CONTROL_nrt_emv_off (0U << 1) +#define ST25R3916_REG_TIMER_EMV_CONTROL_nrt_step (1U << 0) +#define ST25R3916_REG_TIMER_EMV_CONTROL_nrt_step_64fc (0U << 0) +#define ST25R3916_REG_TIMER_EMV_CONTROL_nrt_step_4096_fc (1U << 0) + +#define ST25R3916_REG_FIFO_STATUS2_fifo_b9 (1U << 7) +#define ST25R3916_REG_FIFO_STATUS2_fifo_b8 (1U << 6) +#define ST25R3916_REG_FIFO_STATUS2_fifo_b_mask (3U << 6) +#define ST25R3916_REG_FIFO_STATUS2_fifo_b_shift (6U) +#define ST25R3916_REG_FIFO_STATUS2_fifo_unf (1U << 5) +#define ST25R3916_REG_FIFO_STATUS2_fifo_ovr (1U << 4) +#define ST25R3916_REG_FIFO_STATUS2_fifo_lb2 (1U << 3) +#define ST25R3916_REG_FIFO_STATUS2_fifo_lb1 (1U << 2) +#define ST25R3916_REG_FIFO_STATUS2_fifo_lb0 (1U << 1) +#define ST25R3916_REG_FIFO_STATUS2_fifo_lb_mask (7U << 1) +#define ST25R3916_REG_FIFO_STATUS2_fifo_lb_shift (1U) +#define ST25R3916_REG_FIFO_STATUS2_np_lb (1U << 0) + +#define ST25R3916_REG_COLLISION_STATUS_c_byte3 (1U << 7) +#define ST25R3916_REG_COLLISION_STATUS_c_byte2 (1U << 6) +#define ST25R3916_REG_COLLISION_STATUS_c_byte1 (1U << 5) +#define ST25R3916_REG_COLLISION_STATUS_c_byte0 (1U << 4) +#define ST25R3916_REG_COLLISION_STATUS_c_byte_mask (0xfU << 4) +#define ST25R3916_REG_COLLISION_STATUS_c_byte_shift (4U) +#define ST25R3916_REG_COLLISION_STATUS_c_bit2 (1U << 3) +#define ST25R3916_REG_COLLISION_STATUS_c_bit1 (1U << 2) +#define ST25R3916_REG_COLLISION_STATUS_c_bit0 (1U << 1) +#define ST25R3916_REG_COLLISION_STATUS_c_pb (1U << 0) +#define ST25R3916_REG_COLLISION_STATUS_c_bit_mask (3U << 1) +#define ST25R3916_REG_COLLISION_STATUS_c_bit_shift (1U) + +#define ST25R3916_REG_PASSIVE_TARGET_STATUS_rfu (1U << 7) +#define ST25R3916_REG_PASSIVE_TARGET_STATUS_rfu1 (1U << 6) +#define ST25R3916_REG_PASSIVE_TARGET_STATUS_rfu2 (1U << 5) +#define ST25R3916_REG_PASSIVE_TARGET_STATUS_rfu3 (1U << 4) +#define ST25R3916_REG_PASSIVE_TARGET_STATUS_pta_state3 (1U << 3) +#define ST25R3916_REG_PASSIVE_TARGET_STATUS_pta_state2 (1U << 2) +#define ST25R3916_REG_PASSIVE_TARGET_STATUS_pta_state1 (1U << 1) +#define ST25R3916_REG_PASSIVE_TARGET_STATUS_pta_state0 (1U << 0) +#define ST25R3916_REG_PASSIVE_TARGET_STATUS_pta_st_power_off (0x0U << 0) +#define ST25R3916_REG_PASSIVE_TARGET_STATUS_pta_st_idle (0x1U << 0) +#define ST25R3916_REG_PASSIVE_TARGET_STATUS_pta_st_ready_l1 (0x2U << 0) +#define ST25R3916_REG_PASSIVE_TARGET_STATUS_pta_st_ready_l2 (0x3U << 0) +#define ST25R3916_REG_PASSIVE_TARGET_STATUS_pta_st_rfu4 (0x4U << 0) +#define ST25R3916_REG_PASSIVE_TARGET_STATUS_pta_st_active (0x5U << 0) +#define ST25R3916_REG_PASSIVE_TARGET_STATUS_pta_st_rfu6 (0x6U << 0) +#define ST25R3916_REG_PASSIVE_TARGET_STATUS_pta_st_rfu7 (0x7U << 0) +#define ST25R3916_REG_PASSIVE_TARGET_STATUS_pta_st_rfu8 (0x8U << 0) +#define ST25R3916_REG_PASSIVE_TARGET_STATUS_pta_st_halt (0x9U << 0) +#define ST25R3916_REG_PASSIVE_TARGET_STATUS_pta_st_ready_l1_x (0xaU << 0) +#define ST25R3916_REG_PASSIVE_TARGET_STATUS_pta_st_ready_l2_x (0xbU << 0) +#define ST25R3916_REG_PASSIVE_TARGET_STATUS_pta_st_rfu12 (0xcU << 0) +#define ST25R3916_REG_PASSIVE_TARGET_STATUS_pta_st_active_x (0xdU << 0) +#define ST25R3916_REG_PASSIVE_TARGET_STATUS_pta_state_mask (0xfU << 0) +#define ST25R3916_REG_PASSIVE_TARGET_STATUS_pta_state_shift (0U) + +#define ST25R3916_REG_NUM_TX_BYTES2_ntx4 (1U << 7) +#define ST25R3916_REG_NUM_TX_BYTES2_ntx3 (1U << 6) +#define ST25R3916_REG_NUM_TX_BYTES2_ntx2 (1U << 5) +#define ST25R3916_REG_NUM_TX_BYTES2_ntx1 (1U << 4) +#define ST25R3916_REG_NUM_TX_BYTES2_ntx0 (1U << 3) +#define ST25R3916_REG_NUM_TX_BYTES2_ntx_mask (0x1fU << 3) +#define ST25R3916_REG_NUM_TX_BYTES2_ntx_shift (3U) +#define ST25R3916_REG_NUM_TX_BYTES2_nbtx2 (1U << 2) +#define ST25R3916_REG_NUM_TX_BYTES2_nbtx1 (1U << 1) +#define ST25R3916_REG_NUM_TX_BYTES2_nbtx0 (1U << 0) +#define ST25R3916_REG_NUM_TX_BYTES2_nbtx_mask (7U << 0) +#define ST25R3916_REG_NUM_TX_BYTES2_nbtx_shift (0U) + +#define ST25R3916_REG_NFCIP1_BIT_RATE_nfc_rfu1 (1U << 7) +#define ST25R3916_REG_NFCIP1_BIT_RATE_nfc_rfu0 (1U << 6) +#define ST25R3916_REG_NFCIP1_BIT_RATE_nfc_rate1 (1U << 5) +#define ST25R3916_REG_NFCIP1_BIT_RATE_nfc_rate0 (1U << 4) +#define ST25R3916_REG_NFCIP1_BIT_RATE_nfc_rate_mask (0x3U << 4) +#define ST25R3916_REG_NFCIP1_BIT_RATE_nfc_rate_shift (4U) +#define ST25R3916_REG_NFCIP1_BIT_RATE_ppt2_on (1U << 3) +#define ST25R3916_REG_NFCIP1_BIT_RATE_gpt_on (1U << 2) +#define ST25R3916_REG_NFCIP1_BIT_RATE_nrt_on (1U << 1) +#define ST25R3916_REG_NFCIP1_BIT_RATE_mrt_on (1U << 0) + +#define ST25R3916_REG_TX_DRIVER_am_mod3 (1U << 7) +#define ST25R3916_REG_TX_DRIVER_am_mod2 (1U << 6) +#define ST25R3916_REG_TX_DRIVER_am_mod1 (1U << 5) +#define ST25R3916_REG_TX_DRIVER_am_mod0 (1U << 4) +#define ST25R3916_REG_TX_DRIVER_am_mod_5percent (0x0U << 4) +#define ST25R3916_REG_TX_DRIVER_am_mod_6percent (0x1U << 4) +#define ST25R3916_REG_TX_DRIVER_am_mod_7percent (0x2U << 4) +#define ST25R3916_REG_TX_DRIVER_am_mod_8percent (0x3U << 4) +#define ST25R3916_REG_TX_DRIVER_am_mod_9percent (0x4U << 4) +#define ST25R3916_REG_TX_DRIVER_am_mod_10percent (0x5U << 4) +#define ST25R3916_REG_TX_DRIVER_am_mod_11percent (0x6U << 4) +#define ST25R3916_REG_TX_DRIVER_am_mod_12percent (0x7U << 4) +#define ST25R3916_REG_TX_DRIVER_am_mod_13percent (0x8U << 4) +#define ST25R3916_REG_TX_DRIVER_am_mod_14percent (0x9U << 4) +#define ST25R3916_REG_TX_DRIVER_am_mod_15percent (0xaU << 4) +#define ST25R3916_REG_TX_DRIVER_am_mod_17percent (0xbU << 4) +#define ST25R3916_REG_TX_DRIVER_am_mod_19percent (0xcU << 4) +#define ST25R3916_REG_TX_DRIVER_am_mod_22percent (0xdU << 4) +#define ST25R3916_REG_TX_DRIVER_am_mod_26percent (0xeU << 4) +#define ST25R3916_REG_TX_DRIVER_am_mod_40percent (0xfU << 4) +#define ST25R3916_REG_TX_DRIVER_am_mod_mask (0xfU << 4) +#define ST25R3916_REG_TX_DRIVER_am_mod_shift (4U) +#define ST25R3916_REG_TX_DRIVER_d_res3 (1U << 3) +#define ST25R3916_REG_TX_DRIVER_d_res2 (1U << 2) +#define ST25R3916_REG_TX_DRIVER_d_res1 (1U << 1) +#define ST25R3916_REG_TX_DRIVER_d_res0 (1U << 0) +#define ST25R3916_REG_TX_DRIVER_d_res_mask (0xfU << 0) +#define ST25R3916_REG_TX_DRIVER_d_res_shift (0U) + +#define ST25R3916_REG_PT_MOD_ptm_res3 (1U << 7) +#define ST25R3916_REG_PT_MOD_ptm_res2 (1U << 6) +#define ST25R3916_REG_PT_MOD_ptm_res1 (1U << 5) +#define ST25R3916_REG_PT_MOD_ptm_res0 (1U << 4) +#define ST25R3916_REG_PT_MOD_ptm_res_mask (0xfU << 4) +#define ST25R3916_REG_PT_MOD_ptm_res_shift (4U) +#define ST25R3916_REG_PT_MOD_pt_res3 (1U << 3) +#define ST25R3916_REG_PT_MOD_pt_res2 (1U << 2) +#define ST25R3916_REG_PT_MOD_pt_res1 (1U << 1) +#define ST25R3916_REG_PT_MOD_pt_res0 (1U << 0) +#define ST25R3916_REG_PT_MOD_pt_res_mask (0xfU << 0) +#define ST25R3916_REG_PT_MOD_pt_res_shift (0U) + +#define ST25R3916_REG_AUX_MOD_dis_reg_am (1U << 7) +#define ST25R3916_REG_AUX_MOD_lm_ext_pol (1U << 6) +#define ST25R3916_REG_AUX_MOD_lm_ext (1U << 5) +#define ST25R3916_REG_AUX_MOD_lm_dri (1U << 4) +#define ST25R3916_REG_AUX_MOD_res_am (1U << 3) +#define ST25R3916_REG_AUX_MOD_rfu2 (1U << 2) +#define ST25R3916_REG_AUX_MOD_rfu1 (1U << 1) +#define ST25R3916_REG_AUX_MOD_rfu0 (1U << 0) + +#define ST25R3916_REG_TX_DRIVER_TIMING_d_rat_t3 (1U << 7) +#define ST25R3916_REG_TX_DRIVER_TIMING_d_rat_t2 (1U << 6) +#define ST25R3916_REG_TX_DRIVER_TIMING_d_rat_t1 (1U << 5) +#define ST25R3916_REG_TX_DRIVER_TIMING_d_rat_t0 (1U << 4) +#define ST25R3916_REG_TX_DRIVER_TIMING_d_rat_mask (0xfU << 4) +#define ST25R3916_REG_TX_DRIVER_TIMING_d_rat_shift (4U) +#define ST25R3916_REG_TX_DRIVER_TIMING_rfu (1U << 3) +#define ST25R3916_REG_TX_DRIVER_TIMING_d_tim_m2 (1U << 2) +#define ST25R3916_REG_TX_DRIVER_TIMING_d_tim_m1 (1U << 1) +#define ST25R3916_REG_TX_DRIVER_TIMING_d_tim_m0 (1U << 0) +#define ST25R3916_REG_TX_DRIVER_TIMING_d_tim_m_mask (0x7U << 0) +#define ST25R3916_REG_TX_DRIVER_TIMING_d_tim_m_shift (0U) + +#define ST25R3916_REG_RES_AM_MOD_fa3_f (1U << 7) +#define ST25R3916_REG_RES_AM_MOD_md_res6 (1U << 6) +#define ST25R3916_REG_RES_AM_MOD_md_res5 (1U << 5) +#define ST25R3916_REG_RES_AM_MOD_md_res4 (1U << 4) +#define ST25R3916_REG_RES_AM_MOD_md_res3 (1U << 3) +#define ST25R3916_REG_RES_AM_MOD_md_res2 (1U << 2) +#define ST25R3916_REG_RES_AM_MOD_md_res1 (1U << 1) +#define ST25R3916_REG_RES_AM_MOD_md_res0 (1U << 0) +#define ST25R3916_REG_RES_AM_MOD_md_res_mask (0x7FU << 0) +#define ST25R3916_REG_RES_AM_MOD_md_res_shift (0U) + +#define ST25R3916_REG_TX_DRIVER_STATUS_d_rat_r3 (1U << 7) +#define ST25R3916_REG_TX_DRIVER_STATUS_d_rat_r2 (1U << 6) +#define ST25R3916_REG_TX_DRIVER_STATUS_d_rat_r1 (1U << 5) +#define ST25R3916_REG_TX_DRIVER_STATUS_d_rat_r0 (1U << 4) +#define ST25R3916_REG_TX_DRIVER_STATUS_d_rat_mask (0xfU << 4) +#define ST25R3916_REG_TX_DRIVER_STATUS_d_rat_shift (4U) +#define ST25R3916_REG_TX_DRIVER_STATUS_rfu (1U << 3) +#define ST25R3916_REG_TX_DRIVER_STATUS_d_tim_r2 (1U << 2) +#define ST25R3916_REG_TX_DRIVER_STATUS_d_tim_r1 (1U << 1) +#define ST25R3916_REG_TX_DRIVER_STATUS_d_tim_r0 (1U << 0) +#define ST25R3916_REG_TX_DRIVER_STATUS_d_tim_mask (0x7U << 0) +#define ST25R3916_REG_TX_DRIVER_STATUS_d_tim_shift (0U) + +#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_trg_l2a (1U << 6) +#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_trg_l1a (1U << 5) +#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_trg_l0a (1U << 4) +#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_trg_75mV (0x0U << 4) +#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_trg_105mV (0x1U << 4) +#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_trg_150mV (0x2U << 4) +#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_trg_205mV (0x3U << 4) +#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_trg_290mV (0x4U << 4) +#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_trg_400mV (0x5U << 4) +#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_trg_560mV (0x6U << 4) +#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_trg_800mV (0x7U << 4) +#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_trg_mask (7U << 4) +#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_trg_shift (4U) +#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_t3a (1U << 3) +#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_t2a (1U << 2) +#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_t1a (1U << 1) +#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_t0a (1U << 0) +#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_75mV (0x0U << 0) +#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_105mV (0x1U << 0) +#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_150mV (0x2U << 0) +#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_205mV (0x3U << 0) +#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_290mV (0x4U << 0) +#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_400mV (0x5U << 0) +#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_560mV (0x6U << 0) +#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_800mV (0x7U << 0) +#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_25mV (0x8U << 0) +#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_33mV (0x9U << 0) +#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_47mV (0xAU << 0) +#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_64mV (0xBU << 0) +#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_90mV (0xCU << 0) +#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_125mV (0xDU << 0) +#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_175mV (0xEU << 0) +#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_250mV (0xFU << 0) +#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_mask (0xfU << 0) +#define ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_shift (0U) + +#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_trg_l2d (1U << 6) +#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_trg_l1d (1U << 5) +#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_trg_l0d (1U << 4) +#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_trg_75mV (0x0U << 4) +#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_trg_105mV (0x1U << 4) +#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_trg_150mV (0x2U << 4) +#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_trg_205mV (0x3U << 4) +#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_trg_290mV (0x4U << 4) +#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_trg_400mV (0x5U << 4) +#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_trg_560mV (0x6U << 4) +#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_trg_800mV (0x7U << 4) +#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_trg_mask (7U << 4) +#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_trg_shift (4U) +#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_t3d (1U << 3) +#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_t2d (1U << 2) +#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_t1d (1U << 1) +#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_t0d (1U << 0) +#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_75mV (0x0U << 0) +#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_105mV (0x1U << 0) +#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_150mV (0x2U << 0) +#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_205mV (0x3U << 0) +#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_290mV (0x4U << 0) +#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_400mV (0x5U << 0) +#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_560mV (0x6U << 0) +#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_800mV (0x7U << 0) +#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_25mV (0x8U << 0) +#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_33mV (0x9U << 0) +#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_47mV (0xAU << 0) +#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_64mV (0xBU << 0) +#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_90mV (0xCU << 0) +#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_125mV (0xDU << 0) +#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_175mV (0xEU << 0) +#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_250mV (0xFU << 0) +#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_mask (0xfU << 0) +#define ST25R3916_REG_FIELD_THRESHOLD_DEACTV_rfe_shift (0U) + +#define ST25R3916_REG_REGULATOR_CONTROL_reg_s (1U << 7) +#define ST25R3916_REG_REGULATOR_CONTROL_rege_3 (1U << 6) +#define ST25R3916_REG_REGULATOR_CONTROL_rege_2 (1U << 5) +#define ST25R3916_REG_REGULATOR_CONTROL_rege_1 (1U << 4) +#define ST25R3916_REG_REGULATOR_CONTROL_rege_0 (1U << 3) +#define ST25R3916_REG_REGULATOR_CONTROL_rege_mask (0xfU << 3) +#define ST25R3916_REG_REGULATOR_CONTROL_rege_shift (3U) +#define ST25R3916_REG_REGULATOR_CONTROL_mpsv2 (2U << 2) +#define ST25R3916_REG_REGULATOR_CONTROL_mpsv1 (1U << 1) +#define ST25R3916_REG_REGULATOR_CONTROL_mpsv0 (1U << 0) +#define ST25R3916_REG_REGULATOR_CONTROL_mpsv_vdd (0U) +#define ST25R3916_REG_REGULATOR_CONTROL_mpsv_vdd_a (1U) +#define ST25R3916_REG_REGULATOR_CONTROL_mpsv_vdd_d (2U) +#define ST25R3916_REG_REGULATOR_CONTROL_mpsv_vdd_rf (3U) +#define ST25R3916_REG_REGULATOR_CONTROL_mpsv_vdd_am (4U) +#define ST25R3916_REG_REGULATOR_CONTROL_rfu (5U) +#define ST25R3916_REG_REGULATOR_CONTROL_rfu1 (6U) +#define ST25R3916_REG_REGULATOR_CONTROL_rfu2 (7U) +#define ST25R3916_REG_REGULATOR_CONTROL_mpsv_mask (7U) +#define ST25R3916_REG_REGULATOR_CONTROL_mpsv_shift (0U) + +#define ST25R3916_REG_REGULATOR_RESULT_reg_3 (1U << 7) +#define ST25R3916_REG_REGULATOR_RESULT_reg_2 (1U << 6) +#define ST25R3916_REG_REGULATOR_RESULT_reg_1 (1U << 5) +#define ST25R3916_REG_REGULATOR_RESULT_reg_0 (1U << 4) +#define ST25R3916_REG_REGULATOR_RESULT_reg_mask (0xfU << 4) +#define ST25R3916_REG_REGULATOR_RESULT_reg_shift (4U) +#define ST25R3916_REG_REGULATOR_RESULT_i_lim (1U << 0) + +#define ST25R3916_REG_RSSI_RESULT_rssi_am_3 (1U << 7) +#define ST25R3916_REG_RSSI_RESULT_rssi_am_2 (1U << 6) +#define ST25R3916_REG_RSSI_RESULT_rssi_am_1 (1U << 5) +#define ST25R3916_REG_RSSI_RESULT_rssi_am_0 (1U << 4) +#define ST25R3916_REG_RSSI_RESULT_rssi_am_mask (0xfU << 4) +#define ST25R3916_REG_RSSI_RESULT_rssi_am_shift (4U) +#define ST25R3916_REG_RSSI_RESULT_rssi_pm3 (1U << 3) +#define ST25R3916_REG_RSSI_RESULT_rssi_pm2 (1U << 2) +#define ST25R3916_REG_RSSI_RESULT_rssi_pm1 (1U << 1) +#define ST25R3916_REG_RSSI_RESULT_rssi_pm0 (1U << 0) +#define ST25R3916_REG_RSSI_RESULT_rssi_pm_mask (0xfU << 0) +#define ST25R3916_REG_RSSI_RESULT_rssi_pm_shift (0U) + +#define ST25R3916_REG_GAIN_RED_STATE_gs_am_3 (1U << 7) +#define ST25R3916_REG_GAIN_RED_STATE_gs_am_2 (1U << 6) +#define ST25R3916_REG_GAIN_RED_STATE_gs_am_1 (1U << 5) +#define ST25R3916_REG_GAIN_RED_STATE_gs_am_0 (1U << 4) +#define ST25R3916_REG_GAIN_RED_STATE_gs_am_mask (0xfU << 4) +#define ST25R3916_REG_GAIN_RED_STATE_gs_am_shift (4U) +#define ST25R3916_REG_GAIN_RED_STATE_gs_pm_3 (1U << 3) +#define ST25R3916_REG_GAIN_RED_STATE_gs_pm_2 (1U << 2) +#define ST25R3916_REG_GAIN_RED_STATE_gs_pm_1 (1U << 1) +#define ST25R3916_REG_GAIN_RED_STATE_gs_pm_0 (1U << 0) +#define ST25R3916_REG_GAIN_RED_STATE_gs_pm_mask (0xfU << 0) +#define ST25R3916_REG_GAIN_RED_STATE_gs_pm_shift (0U) + +#define ST25R3916_REG_CAP_SENSOR_CONTROL_cs_mcal4 (1U << 7) +#define ST25R3916_REG_CAP_SENSOR_CONTROL_cs_mcal3 (1U << 6) +#define ST25R3916_REG_CAP_SENSOR_CONTROL_cs_mcal2 (1U << 5) +#define ST25R3916_REG_CAP_SENSOR_CONTROL_cs_mcal1 (1U << 4) +#define ST25R3916_REG_CAP_SENSOR_CONTROL_cs_mcal0 (1U << 3) +#define ST25R3916_REG_CAP_SENSOR_CONTROL_cs_mcal_mask (0x1fU << 3) +#define ST25R3916_REG_CAP_SENSOR_CONTROL_cs_mcal_shift (3U) +#define ST25R3916_REG_CAP_SENSOR_CONTROL_cs_g2 (1U << 2) +#define ST25R3916_REG_CAP_SENSOR_CONTROL_cs_g1 (1U << 1) +#define ST25R3916_REG_CAP_SENSOR_CONTROL_cs_g0 (1U << 0) +#define ST25R3916_REG_CAP_SENSOR_CONTROL_cs_g_mask (7U << 0) +#define ST25R3916_REG_CAP_SENSOR_CONTROL_cs_g_shift (0U) + +#define ST25R3916_REG_CAP_SENSOR_RESULT_cs_cal4 (1U << 7) +#define ST25R3916_REG_CAP_SENSOR_RESULT_cs_cal3 (1U << 6) +#define ST25R3916_REG_CAP_SENSOR_RESULT_cs_cal2 (1U << 5) +#define ST25R3916_REG_CAP_SENSOR_RESULT_cs_cal1 (1U << 4) +#define ST25R3916_REG_CAP_SENSOR_RESULT_cs_cal0 (1U << 3) +#define ST25R3916_REG_CAP_SENSOR_RESULT_cs_cal_mask (0x1fU << 3) +#define ST25R3916_REG_CAP_SENSOR_RESULT_cs_cal_shift (3U) +#define ST25R3916_REG_CAP_SENSOR_RESULT_cs_cal_end (1U << 2) +#define ST25R3916_REG_CAP_SENSOR_RESULT_cs_cal_err (1U << 1) + +#define ST25R3916_REG_AUX_DISPLAY_a_cha (1U << 7) +#define ST25R3916_REG_AUX_DISPLAY_efd_o (1U << 6) +#define ST25R3916_REG_AUX_DISPLAY_tx_on (1U << 5) +#define ST25R3916_REG_AUX_DISPLAY_osc_ok (1U << 4) +#define ST25R3916_REG_AUX_DISPLAY_rx_on (1U << 3) +#define ST25R3916_REG_AUX_DISPLAY_rx_act (1U << 2) +#define ST25R3916_REG_AUX_DISPLAY_en_peer (1U << 1) +#define ST25R3916_REG_AUX_DISPLAY_en_ac (1U << 0) + +#define ST25R3916_REG_OVERSHOOT_CONF1_ov_tx_mode1 (1U << 7) +#define ST25R3916_REG_OVERSHOOT_CONF1_ov_tx_mode0 (1U << 6) +#define ST25R3916_REG_OVERSHOOT_CONF1_ov_pattern13 (1U << 5) +#define ST25R3916_REG_OVERSHOOT_CONF1_ov_pattern12 (1U << 4) +#define ST25R3916_REG_OVERSHOOT_CONF1_ov_pattern11 (1U << 3) +#define ST25R3916_REG_OVERSHOOT_CONF1_ov_pattern10 (1U << 2) +#define ST25R3916_REG_OVERSHOOT_CONF1_ov_pattern9 (1U << 1) +#define ST25R3916_REG_OVERSHOOT_CONF1_ov_pattern8 (1U << 0) + +#define ST25R3916_REG_OVERSHOOT_CONF2_ov_pattern7 (1U << 7) +#define ST25R3916_REG_OVERSHOOT_CONF2_ov_pattern6 (1U << 6) +#define ST25R3916_REG_OVERSHOOT_CONF2_ov_pattern5 (1U << 5) +#define ST25R3916_REG_OVERSHOOT_CONF2_ov_pattern4 (1U << 4) +#define ST25R3916_REG_OVERSHOOT_CONF2_ov_pattern3 (1U << 3) +#define ST25R3916_REG_OVERSHOOT_CONF2_ov_pattern2 (1U << 2) +#define ST25R3916_REG_OVERSHOOT_CONF2_ov_pattern1 (1U << 1) +#define ST25R3916_REG_OVERSHOOT_CONF2_ov_pattern0 (1U << 0) + +#define ST25R3916_REG_UNDERSHOOT_CONF1_un_tx_mode1 (1U << 7) +#define ST25R3916_REG_UNDERSHOOT_CONF1_un_tx_mode0 (1U << 6) +#define ST25R3916_REG_UNDERSHOOT_CONF1_un_pattern13 (1U << 5) +#define ST25R3916_REG_UNDERSHOOT_CONF1_un_pattern12 (1U << 4) +#define ST25R3916_REG_UNDERSHOOT_CONF1_un_pattern11 (1U << 3) +#define ST25R3916_REG_UNDERSHOOT_CONF1_un_pattern10 (1U << 2) +#define ST25R3916_REG_UNDERSHOOT_CONF1_un_pattern9 (1U << 1) +#define ST25R3916_REG_UNDERSHOOT_CONF1_un_pattern8 (1U << 0) + +#define ST25R3916_REG_UNDERSHOOT_CONF2_un_pattern7 (1U << 7) +#define ST25R3916_REG_UNDERSHOOT_CONF2_un_pattern6 (1U << 6) +#define ST25R3916_REG_UNDERSHOOT_CONF2_un_pattern5 (1U << 5) +#define ST25R3916_REG_UNDERSHOOT_CONF2_un_pattern4 (1U << 4) +#define ST25R3916_REG_UNDERSHOOT_CONF2_un_pattern3 (1U << 3) +#define ST25R3916_REG_UNDERSHOOT_CONF2_un_pattern2 (1U << 2) +#define ST25R3916_REG_UNDERSHOOT_CONF2_un_pattern1 (1U << 1) +#define ST25R3916_REG_UNDERSHOOT_CONF2_un_pattern0 (1U << 0) + +#define ST25R3916_REG_WUP_TIMER_CONTROL_wur (1U << 7) +#define ST25R3916_REG_WUP_TIMER_CONTROL_wut2 (1U << 6) +#define ST25R3916_REG_WUP_TIMER_CONTROL_wut1 (1U << 5) +#define ST25R3916_REG_WUP_TIMER_CONTROL_wut0 (1U << 4) +#define ST25R3916_REG_WUP_TIMER_CONTROL_wut_mask (7U << 4) +#define ST25R3916_REG_WUP_TIMER_CONTROL_wut_shift (4U) +#define ST25R3916_REG_WUP_TIMER_CONTROL_wto (1U << 3) +#define ST25R3916_REG_WUP_TIMER_CONTROL_wam (1U << 2) +#define ST25R3916_REG_WUP_TIMER_CONTROL_wph (1U << 1) +#define ST25R3916_REG_WUP_TIMER_CONTROL_wcap (1U << 0) + +#define ST25R3916_REG_AMPLITUDE_MEASURE_CONF_am_d3 (1U << 7) +#define ST25R3916_REG_AMPLITUDE_MEASURE_CONF_am_d2 (1U << 6) +#define ST25R3916_REG_AMPLITUDE_MEASURE_CONF_am_d1 (1U << 5) +#define ST25R3916_REG_AMPLITUDE_MEASURE_CONF_am_d0 (1U << 4) +#define ST25R3916_REG_AMPLITUDE_MEASURE_CONF_am_d_mask (0xfU << 4) +#define ST25R3916_REG_AMPLITUDE_MEASURE_CONF_am_d_shift (4U) +#define ST25R3916_REG_AMPLITUDE_MEASURE_CONF_am_aam (1U << 3) +#define ST25R3916_REG_AMPLITUDE_MEASURE_CONF_am_aew1 (1U << 2) +#define ST25R3916_REG_AMPLITUDE_MEASURE_CONF_am_aew0 (1U << 1) +#define ST25R3916_REG_AMPLITUDE_MEASURE_CONF_am_aew_mask (0x3U << 1) +#define ST25R3916_REG_AMPLITUDE_MEASURE_CONF_am_aew_shift (1U) +#define ST25R3916_REG_AMPLITUDE_MEASURE_CONF_am_ae (1U << 0) + +#define ST25R3916_REG_PHASE_MEASURE_CONF_pm_d3 (1U << 7) +#define ST25R3916_REG_PHASE_MEASURE_CONF_pm_d2 (1U << 6) +#define ST25R3916_REG_PHASE_MEASURE_CONF_pm_d1 (1U << 5) +#define ST25R3916_REG_PHASE_MEASURE_CONF_pm_d0 (1U << 4) +#define ST25R3916_REG_PHASE_MEASURE_CONF_pm_d_mask (0xfU << 4) +#define ST25R3916_REG_PHASE_MEASURE_CONF_pm_d_shift (4U) +#define ST25R3916_REG_PHASE_MEASURE_CONF_pm_aam (1U << 3) +#define ST25R3916_REG_PHASE_MEASURE_CONF_pm_aew1 (1U << 2) +#define ST25R3916_REG_PHASE_MEASURE_CONF_pm_aew0 (1U << 1) +#define ST25R3916_REG_PHASE_MEASURE_CONF_pm_aew_mask (0x3U << 1) +#define ST25R3916_REG_PHASE_MEASURE_CONF_pm_aew_shift (1U) +#define ST25R3916_REG_PHASE_MEASURE_CONF_pm_ae (1U << 0) + +#define ST25R3916_REG_CAPACITANCE_MEASURE_CONF_cm_d3 (1U << 7) +#define ST25R3916_REG_CAPACITANCE_MEASURE_CONF_cm_d2 (1U << 6) +#define ST25R3916_REG_CAPACITANCE_MEASURE_CONF_cm_d1 (1U << 5) +#define ST25R3916_REG_CAPACITANCE_MEASURE_CONF_cm_d0 (1U << 4) +#define ST25R3916_REG_CAPACITANCE_MEASURE_CONF_cm_d_mask (0xfU << 4) +#define ST25R3916_REG_CAPACITANCE_MEASURE_CONF_cm_d_shift (4U) +#define ST25R3916_REG_CAPACITANCE_MEASURE_CONF_cm_aam (1U << 3) +#define ST25R3916_REG_CAPACITANCE_MEASURE_CONF_cm_aew1 (1U << 2) +#define ST25R3916_REG_CAPACITANCE_MEASURE_CONF_cm_aew0 (1U << 1) +#define ST25R3916_REG_CAPACITANCE_MEASURE_CONF_cm_aew_mask (0x3U << 1) +#define ST25R3916_REG_CAPACITANCE_MEASURE_CONF_cm_aew_shift (1U) +#define ST25R3916_REG_CAPACITANCE_MEASURE_CONF_cm_ae (1U << 0) + +#define ST25R3916_REG_IC_IDENTITY_ic_type4 (1U << 7) +#define ST25R3916_REG_IC_IDENTITY_ic_type3 (1U << 6) +#define ST25R3916_REG_IC_IDENTITY_ic_type2 (1U << 5) +#define ST25R3916_REG_IC_IDENTITY_ic_type1 (1U << 4) +#define ST25R3916_REG_IC_IDENTITY_ic_type0 (1U << 3) +#define ST25R3916_REG_IC_IDENTITY_ic_type_st25r3916 (5U << 3) +#define ST25R3916_REG_IC_IDENTITY_ic_type_mask (0x1fU << 3) +#define ST25R3916_REG_IC_IDENTITY_ic_type_shift (3U) +#define ST25R3916_REG_IC_IDENTITY_ic_rev2 (1U << 2) +#define ST25R3916_REG_IC_IDENTITY_ic_rev1 (1U << 1) +#define ST25R3916_REG_IC_IDENTITY_ic_rev0 (1U << 0) +#define ST25R3916_REG_IC_IDENTITY_ic_rev_v0 (0U << 0) +#define ST25R3916_REG_IC_IDENTITY_ic_rev_mask (7U << 0) +#define ST25R3916_REG_IC_IDENTITY_ic_rev_shift (0U) + +void st25r3916_read_reg(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t* val); + +void st25r3916_read_burst_regs( + FuriHalSpiBusHandle* handle, + uint8_t reg_start, + uint8_t* values, + uint8_t length); + +void st25r3916_write_reg(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t val); + +void st25r3916_write_burst_regs( + FuriHalSpiBusHandle* handle, + uint8_t reg_start, + uint8_t* values, + uint8_t length); + +void st25r3916_reg_write_fifo(FuriHalSpiBusHandle* handle, uint8_t* buff, uint16_t length); + +void st25r3916_reg_read_fifo(FuriHalSpiBusHandle* handle, uint8_t* buff, uint16_t length); + +void st25r3916_write_pta_mem(FuriHalSpiBusHandle* handle, uint8_t* values, uint16_t length); + +void st25r3916_read_pta_mem(FuriHalSpiBusHandle* handle, uint8_t* values, uint16_t length); + +void st25r3916_write_ptf_mem(FuriHalSpiBusHandle* handle, uint8_t* values, uint16_t length); + +void st25r3916_write_pttsn_mem(FuriHalSpiBusHandle* handle, uint8_t* values, uint16_t length); + +void st25r3916_direct_cmd(FuriHalSpiBusHandle* handle, uint8_t cmd); + +void st25r3916_read_test_reg(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t* val); + +void st25r3916_write_test_reg(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t val); + +void st25r3916_clear_reg_bits(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t clr_mask); + +void st25r3916_set_reg_bits(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t set_mask); + +void st25r3916_change_reg_bits( + FuriHalSpiBusHandle* handle, + uint8_t reg, + uint8_t mask, + uint8_t value); + +void st25r3916_modify_reg( + FuriHalSpiBusHandle* handle, + uint8_t reg, + uint8_t clr_mask, + uint8_t set_mask); + +void st25r3916_change_test_reg_bits( + FuriHalSpiBusHandle* handle, + uint8_t reg, + uint8_t mask, + uint8_t value); + +bool st25r3916_check_reg(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t mask, uint8_t val); + +#ifdef __cplusplus +} +#endif From cc224408e5fcd54eeb46831405ac9cc44af6ebee Mon Sep 17 00:00:00 2001 From: gornekich Date: Thu, 23 Mar 2023 16:42:52 +0400 Subject: [PATCH 003/149] nfc: introduce new parsers --- lib/misc.scons | 3 + lib/nfc/nfc.c | 442 +++++++++++++++++++++ lib/nfc/nfc.h | 106 +++++ lib/nfc/protocols/mf_ultralight_common.h | 71 ++++ lib/nfc/protocols/mf_ultralight_listener.c | 24 ++ lib/nfc/protocols/mf_ultralight_listener.h | 17 + lib/nfc/protocols/mf_ultralight_poller.c | 286 +++++++++++++ lib/nfc/protocols/mf_ultralight_poller.h | 43 ++ lib/nfc/protocols/nfca_common.h | 63 +++ lib/nfc/protocols/nfca_listener.c | 87 ++++ lib/nfc/protocols/nfca_listener.h | 26 ++ lib/nfc/protocols/nfca_poller.c | 402 +++++++++++++++++++ lib/nfc/protocols/nfca_poller.h | 43 ++ 13 files changed, 1613 insertions(+) create mode 100644 lib/nfc/nfc.c create mode 100644 lib/nfc/nfc.h create mode 100644 lib/nfc/protocols/mf_ultralight_common.h create mode 100644 lib/nfc/protocols/mf_ultralight_listener.c create mode 100644 lib/nfc/protocols/mf_ultralight_listener.h create mode 100644 lib/nfc/protocols/mf_ultralight_poller.c create mode 100644 lib/nfc/protocols/mf_ultralight_poller.h create mode 100644 lib/nfc/protocols/nfca_common.h create mode 100644 lib/nfc/protocols/nfca_listener.c create mode 100644 lib/nfc/protocols/nfca_listener.h create mode 100644 lib/nfc/protocols/nfca_poller.c create mode 100644 lib/nfc/protocols/nfca_poller.h diff --git a/lib/misc.scons b/lib/misc.scons index b479851b126c..25be449b89ed 100644 --- a/lib/misc.scons +++ b/lib/misc.scons @@ -16,6 +16,9 @@ env.Append( ], SDK_HEADERS=[ File("micro-ecc/uECC.h"), + File("nanopb/pb.h"), + File("nanopb/pb_decode.h"), + File("nanopb/pb_encode.h"), ], ) diff --git a/lib/nfc/nfc.c b/lib/nfc/nfc.c new file mode 100644 index 000000000000..cf2e13d01269 --- /dev/null +++ b/lib/nfc/nfc.c @@ -0,0 +1,442 @@ +#include "nfc.h" + +#include +#include + +#define TAG "Nfc" + +typedef enum { + NfcStateIdle, + NfcStateConfigured, + NfcStateChipSleep, + NfcStateChipActive, + NfcStateFieldOn, + NfcStateFieldOff, +} NfcState; + +typedef enum { + NfcCommStateIdle, + NfcCommStateWaitBlockTxTimer, + NfcCommStateReadyTx, + NfcCommStateWaitTxEnd, + NfcCommStateWaitRxStart, + NfcCommStateWaitRxEnd, + NfcCommStateFailed, +} NfcCommState; + +struct Nfc { + NfcState state; + NfcCommState comm_state; + uint32_t fdt_listen_fc; + uint32_t mask_rx_time_fc; + uint32_t fdt_poll_fc; + uint32_t fdt_poll_poll_us; + uint32_t guard_time_us; + NfcEventCallback callback; + void* context; +}; + +static NfcError nfc_process_hal_error(FHalNfcError error) { + NfcError err = NfcErrorNone; + + if(error == FHalNfcErrorNone) { + err = NfcErrorNone; + } else if(error == FHalNfcErrorChipCommunication) { + err = NfcErrorInternal; + } + + return err; +} + +static void nfc_hal_event_handler(FHalNfcEvent event, void* context) { + furi_assert(context); + Nfc* instance = context; + + if(instance->callback) { + if(event == FHalNfcEventFieldOn) { + instance->callback(NfcEventFieldOn, instance->context); + } else if(event == FHalNfcEventTxStart) { + instance->callback(NfcEventTxStart, instance->context); + } else if(event == FHalNfcEventTxEnd) { + instance->callback(NfcEventTxEnd, instance->context); + } else if(event == FHalNfcEventRxStart) { + instance->callback(NfcEventRxStart, instance->context); + } else if(event == FHalNfcEventRxEnd) { + instance->callback(NfcEventRxEnd, instance->context); + } + } +} + +Nfc* nfc_alloc() { + Nfc* instance = malloc(sizeof(Nfc)); + instance->state = NfcStateIdle; + f_hal_nfc_set_callback(nfc_hal_event_handler, instance); + f_hal_nfc_low_power_mode_stop(); + instance->state = NfcStateChipActive; + + return instance; +} + +void nfc_free(Nfc* instance) { + furi_assert(instance); + f_hal_nfc_low_power_mode_start(); + f_hal_nfc_set_callback(NULL, NULL); + + free(instance); +} + +void nfc_set_event_callback(Nfc* instance, NfcEventCallback callback, void* context) { + furi_assert(instance); + furi_assert(callback); + + instance->callback = callback; + instance->context = context; +} + +void nfc_config(Nfc* instance, NfcMode mode) { + furi_assert(instance); + if(mode == NfcModeNfcaPoller) { + f_hal_nfc_set_mode(FHalNfcModeNfcaPoller, FHalNfcBitrate106); + instance->state = NfcStateConfigured; + } else if(mode == NfcModeNfcaListener) { + f_hal_nfc_set_mode(FHalNfcModeNfcaListener, FHalNfcBitrate106); + instance->state = NfcStateConfigured; + } +} + +NfcError nfc_listener_set_col_res_data( + Nfc* instance, + uint8_t* uid, + uint8_t uid_len, + uint8_t* atqa, + uint8_t sak) { + furi_assert(instance); + furi_assert(instance->state == NfcStateConfigured); + + FHalNfcError error = furi_hal_nfca_set_col_res_data(uid, uid_len, atqa, sak); + instance->comm_state = NfcCommStateIdle; + return nfc_process_hal_error(error); +} + +void nfc_set_fdt_poll_fc(Nfc* instance, uint32_t fdt_poll_fc) { + furi_assert(instance); + instance->fdt_poll_fc = fdt_poll_fc; +} + +void nfc_set_fdt_listen_fc(Nfc* instance, uint32_t fdt_listen_fc) { + furi_assert(instance); + instance->fdt_listen_fc = fdt_listen_fc; +} + +void nfc_set_fdt_poll_poll_us(Nfc* instance, uint32_t fdt_poll_poll_us) { + furi_assert(instance); + instance->fdt_poll_poll_us = fdt_poll_poll_us; +} + +void nfc_set_guard_time_us(Nfc* instance, uint32_t guard_time_us) { + furi_assert(instance); + instance->guard_time_us = guard_time_us; +} + +void nfc_set_mask_receive_time_fc(Nfc* instance, uint32_t mask_rx_time_fc) { + furi_assert(instance); + instance->mask_rx_time_fc = mask_rx_time_fc; +} + +static NfcError nfc_poller_trx_state_machine(Nfc* instance, uint32_t fwt_fc) { + FHalNfcEvent event = 0; + NfcError error = NfcErrorNone; + + while(true) { + event = f_hal_nfc_wait_event(F_HAL_NFC_EVENT_WAIT_FOREVER); + if(event & FHalNfcEventTimerBlockTxExpired) { + if(instance->comm_state == NfcCommStateWaitBlockTxTimer) { + instance->comm_state = NfcCommStateReadyTx; + } + } + if(event & FHalNfcEventTxEnd) { + if(instance->comm_state == NfcCommStateWaitTxEnd) { + if(fwt_fc) { + f_hal_nfc_timer_fwt_start(fwt_fc + F_HAL_NFC_TIMER_OFFSET_FC); + } + f_hal_nfc_timer_block_tx_start_us(instance->fdt_poll_poll_us); + instance->comm_state = NfcCommStateWaitRxStart; + } + } + if(event & FHalNfcEventRxStart) { + if(instance->comm_state == NfcCommStateWaitRxStart) { + f_hal_nfc_timer_block_tx_stop(); + f_hal_nfc_timer_fwt_stop(); + instance->comm_state = NfcCommStateWaitRxEnd; + } + } + if(event & FHalNfcEventRxEnd) { + f_hal_nfc_timer_block_tx_start(instance->fdt_poll_fc); + instance->comm_state = NfcCommStateWaitBlockTxTimer; + break; + } + if(event & FHalNfcEventTimerFwtExpired) { + error = NfcErrorTimeout; + FURI_LOG_W(TAG, "FWT Timeout"); + if(f_hal_nfc_timer_block_tx_is_running()) { + instance->comm_state = NfcCommStateWaitBlockTxTimer; + } else { + instance->comm_state = NfcCommStateReadyTx; + } + break; + } + } + + return error; +} + +static NfcError nfc_poller_prepare_trx(Nfc* instance) { + furi_assert(instance); + furi_assert(instance->state == NfcStateIdle); + + FHalNfcError error = FHalNfcErrorNone; + NfcError ret = NfcErrorNone; + FHalNfcEvent event = 0; + do { + if(instance->state == NfcStateConfigured) { + error = f_hal_nfc_low_power_mode_stop(); + if(error != FHalNfcErrorNone) break; + instance->state = NfcStateChipActive; + } + if(instance->state == NfcStateChipActive) { + error = f_hal_nfc_poller_field_on(); + if(error != FHalNfcErrorNone) break; + instance->state = NfcStateFieldOn; + if(instance->fdt_poll_poll_us) { + f_hal_nfc_timer_block_tx_start_us(instance->guard_time_us); + instance->comm_state = NfcCommStateWaitBlockTxTimer; + event = f_hal_nfc_wait_event(F_HAL_NFC_EVENT_WAIT_FOREVER); + if(event & FHalNfcEventTimerBlockTxExpired) { + f_hal_nfc_set_mask_receive_timer(instance->mask_rx_time_fc); + instance->comm_state = NfcCommStateReadyTx; + } else { + FURI_LOG_D(TAG, "Unexpected event in tx rx prepare %d", event); + instance->comm_state = NfcCommStateFailed; + } + } + } + } while(false); + ret = nfc_process_hal_error(error); + // Reset FIFO, prepare TX, setup Mask rx timer + f_hal_nfc_trx_reset(); + return ret; +} + +NfcError nfc_trx( + Nfc* instance, + uint8_t* tx_data, + uint16_t tx_bits, + uint8_t* rx_data, + uint16_t rx_data_size, + uint16_t* rx_bits, + uint32_t fwt) { + furi_assert(instance); + furi_assert(rx_data); + furi_assert(rx_bits); + + furi_assert(instance->state == NfcStateFieldOn); + + NfcError ret = NfcErrorNone; + FHalNfcError error = FHalNfcErrorNone; + do { + ret = nfc_poller_prepare_trx(instance); + if(ret != NfcErrorNone) { + FURI_LOG_E(TAG, "Failed in prepare tx rx"); + break; + } + error = f_hal_nfc_poller_tx(tx_data, tx_bits); + if(error != FHalNfcErrorNone) { + FURI_LOG_E(TAG, "Failed in poller TX"); + ret = nfc_process_hal_error(error); + break; + } + instance->comm_state = NfcCommStateWaitTxEnd; + ret = nfc_poller_trx_state_machine(instance, fwt); + if(ret != NfcErrorNone) { + FURI_LOG_E(TAG, "Failed TRX state machine"); + break; + } + error = f_hal_nfc_poller_rx(rx_data, rx_data_size, rx_bits); + if(error != FHalNfcErrorNone) { + FURI_LOG_E(TAG, "Failed in poller RX"); + ret = nfc_process_hal_error(error); + break; + } + } while(false); + + return ret; +} + +NfcError nfc_iso13444a_short_frame( + Nfc* instance, + NfcIso14443aShortFrame frame, + uint8_t* rx_data, + uint16_t rx_data_size, + uint16_t* rx_bits, + uint32_t fwt) { + furi_assert(instance); + furi_assert(rx_data); + furi_assert(rx_bits); + + FHalNfcaShortFrame short_frame = (frame == NfcIso14443aShortFrameAllReqa) ? + FHalNfcaShortFrameAllReq : + FHalNfcaShortFrameSensReq; + + furi_assert(instance->state == NfcStateFieldOn); + + NfcError ret = NfcErrorNone; + FHalNfcError error = FHalNfcErrorNone; + do { + ret = nfc_poller_prepare_trx(instance); + if(ret != NfcErrorNone) { + FURI_LOG_E(TAG, "Failed in prepare tx rx"); + break; + } + error = f_hal_nfca_send_short_frame(short_frame); + if(error != FHalNfcErrorNone) { + FURI_LOG_E(TAG, "Failed in poller TX"); + ret = nfc_process_hal_error(error); + break; + } + instance->comm_state = NfcCommStateWaitTxEnd; + ret = nfc_poller_trx_state_machine(instance, fwt); + if(ret != NfcErrorNone) { + FURI_LOG_E(TAG, "Failed TRX state machine"); + break; + } + error = f_hal_nfc_poller_rx(rx_data, rx_data_size, rx_bits); + if(error != FHalNfcErrorNone) { + FURI_LOG_E(TAG, "Failed in poller RX"); + ret = nfc_process_hal_error(error); + break; + } + } while(false); + + return ret; +} + +NfcError nfc_iso13444a_sdd_frame( + Nfc* instance, + uint8_t* tx_data, + uint16_t tx_bits, + uint8_t* rx_data, + uint16_t rx_data_size, + uint16_t* rx_bits, + uint32_t fwt) { + furi_assert(instance); + furi_assert(instance->state == NfcStateFieldOn); + + NfcError ret = NfcErrorNone; + FHalNfcError error = FHalNfcErrorNone; + do { + ret = nfc_poller_prepare_trx(instance); + if(ret != NfcErrorNone) { + FURI_LOG_E(TAG, "Failed in prepare tx rx"); + break; + } + error = f_hal_nfca_send_sdd_frame(tx_data, tx_bits); + if(error != FHalNfcErrorNone) { + FURI_LOG_E(TAG, "Failed in poller TX"); + ret = nfc_process_hal_error(error); + break; + } + instance->comm_state = NfcCommStateWaitTxEnd; + ret = nfc_poller_trx_state_machine(instance, fwt); + if(ret != NfcErrorNone) { + FURI_LOG_E(TAG, "Failed TRX state machine"); + break; + } + error = f_hal_nfca_receive_sdd_frame(rx_data, rx_data_size, rx_bits); + if(error != FHalNfcErrorNone) { + FURI_LOG_E(TAG, "Failed in poller RX"); + ret = nfc_process_hal_error(error); + break; + } + } while(false); + + return ret; +} + +NfcError nfc_listener_rx( + Nfc* instance, + uint8_t* rx_data, + uint16_t rx_data_size, + uint16_t* rx_bits, + uint32_t timeout) { + furi_assert(instance); + furi_assert(instance->state == NfcStateConfigured); + furi_assert(rx_data); + furi_assert(rx_bits); + + NfcError ret = NfcErrorNone; + if(instance->comm_state == NfcCommStateIdle) { + f_hal_nfc_listen_start(); + instance->comm_state = NfcCommStateWaitRxStart; + } + do { + FHalNfcEvent event = f_hal_nfc_wait_event(timeout); + if(event & FHalNfcEventFieldOn) { + FURI_LOG_D(TAG, "FieldOn"); + } + if(event & FHalNfcEventListenerActive) { + FURI_LOG_D(TAG, "Activated"); + f_hal_nfc_listen_start(); + } + if(event & FHalNfcEventRxEnd) { + FURI_LOG_D(TAG, "Received data"); + f_hal_nfc_poller_rx(rx_data, rx_data_size, rx_bits); + break; + } + if(event & FHalNfcEventFieldOff) { + FURI_LOG_D(TAG, "Field off"); + ret = NfcErrorLinkLoss; + break; + } + if(event & FHalNfcEventTimeout) { + ret = NfcErrorTimeout; + FURI_LOG_D(TAG, "Timeout"); + break; + } + if(event & FHalNfcEventAbortRequest) { + ret = NfcErrorAbortRequest; + FURI_LOG_D(TAG, "Abirt request"); + break; + } + + // if(event & FHalNfcEventRxStart) { + // FURI_LOG_I(TAG, "Listener RxStart"); + // instance->comm_state = NfcCommStateWaitRxEnd; + // } else if(event == FHalNfcEventTimeout) { + // FURI_LOG_W(TAG, "Listener Timeout"); + // ret = NfcErrorTimeout; + // break; + // } + // event = f_hal_nfc_wait_event(timeout); + // if(event & FHalNfcEventRxEnd) { + // FURI_LOG_I(TAG, "Listener Rx end"); + // } + // FHalNfcError error = f_hal_nfc_poller_rx(rx_data, rx_data_size, rx_bits); + // if(error != FHalNfcErrorNone) { + // ret = nfc_process_hal_error(error); + // break; + // } + // f_hal_nfc_timer_block_tx_start(instance->fdt_listen_fc); + // instance->comm_state = NfcCommStateWaitBlockTxTimer; + // break; + } while(true); + + return ret; +} + +NfcError nfc_listener_tx(Nfc* instance, uint8_t* tx_data, uint16_t tx_bits) { + furi_assert(instance); + furi_assert(tx_data); + UNUSED(tx_bits); + + return NfcErrorNone; +} diff --git a/lib/nfc/nfc.h b/lib/nfc/nfc.h new file mode 100644 index 000000000000..e4cc01b5c774 --- /dev/null +++ b/lib/nfc/nfc.h @@ -0,0 +1,106 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct Nfc Nfc; + +typedef enum { + NfcEventFieldOn, + NfcEventTxStart, + NfcEventTxEnd, + NfcEventRxStart, + NfcEventRxEnd, + NfcEventRxTimeout, +} NfcEvent; + +typedef void (*NfcEventCallback)(NfcEvent event, void* context); + +typedef enum { + NfcModeNfcaPoller, + NfcModeNfcaListener, +} NfcMode; + +typedef enum { + NfcErrorNone, + NfcErrorInternal, + NfcErrorTimeout, + NfcErrorWrongState, + NfcErrorCollision, + NfcErrorLinkLoss, + NfcErrorAbortRequest, +} NfcError; + +typedef enum { + NfcIso14443aShortFrameSensReq, + NfcIso14443aShortFrameAllReqa, +} NfcIso14443aShortFrame; + +Nfc* nfc_alloc(); + +void nfc_free(Nfc* instance); + +void nfc_set_event_callback(Nfc* instance, NfcEventCallback callback, void* context); + +void nfc_config(Nfc* instance, NfcMode mode); + +void nfc_set_fdt_poll_fc(Nfc* instance, uint32_t fdt_poll_fc); + +void nfc_set_fdt_listen_fc(Nfc* instance, uint32_t fdt_listen_fc); + +void nfc_set_mask_receive_time_fc(Nfc* instance, uint32_t mask_rx_time_fc); + +void nfc_set_fdt_poll_poll_us(Nfc* instance, uint32_t fdt_poll_poll_us); + +void nfc_set_guard_time_us(Nfc* instance, uint32_t guard_time_us); + +NfcError nfc_listener_set_col_res_data( + Nfc* instance, + uint8_t* uid, + uint8_t uid_len, + uint8_t* atqa, + uint8_t sak); + +NfcError nfc_listener_rx( + Nfc* instance, + uint8_t* rx_data, + uint16_t rx_data_size, + uint16_t* rx_bits, + uint32_t timeout); + +NfcError nfc_listener_tx(Nfc* instance, uint8_t* tx_data, uint16_t tx_bits); + +NfcError nfc_trx( + Nfc* instance, + uint8_t* tx_data, + uint16_t tx_bits, + uint8_t* rx_data, + uint16_t rx_data_size, + uint16_t* rx_bits, + uint32_t fwt); + +// Technology specific API + +NfcError nfc_iso13444a_short_frame( + Nfc* instance, + NfcIso14443aShortFrame frame, + uint8_t* rx_data, + uint16_t rx_data_size, + uint16_t* rx_bits, + uint32_t fwt); + +NfcError nfc_iso13444a_sdd_frame( + Nfc* instance, + uint8_t* tx_data, + uint16_t tx_bits, + uint8_t* rx_data, + uint16_t rx_data_size, + uint16_t* rx_bits, + uint32_t fwt); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/mf_ultralight_common.h b/lib/nfc/protocols/mf_ultralight_common.h new file mode 100644 index 000000000000..edc98d615c57 --- /dev/null +++ b/lib/nfc/protocols/mf_ultralight_common.h @@ -0,0 +1,71 @@ +#pragma once + +#include "nfca_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define MF_ULTRALIGHT_CMD_GET_VERSION (0x60) +#define MF_ULTRALIGHT_CMD_READ_PAGE (0x30) +#define MF_ULTRALIGHT_CMD_WRITE_PAGE (0xA2) +#define MF_ULTRALIGHT_CMD_ACK (0x0A) +#define MF_ULTRALIGTH_CMD_READ_SIG (0x3C) +#define MF_ULTRALIGHT_CMD_READ_CNT (0x39) +#define MF_ULTRALIGHT_CMD_CHECK_TEARING (0x3E) + +#define MF_ULTRALIGHT_MAX_PAGE_NUM (510) +#define MF_ULTRALIGHT_PAGE_SIZE (4U) +#define MF_ULTRALIGHT_SIGNATURE_SIZE (32) +#define MF_ULTRALIGHT_COUNTER_SIZE (3) +#define MF_ULTRALIGHT_COUNTER_NUM (3) +#define MF_ULTRALIGHT_TEARING_FLAG_SIZE (1) +#define MF_ULTRALIGHT_TEARING_FLAG_NUM (3) + +typedef enum { + MfUltralightErrorNone, + MfUltralightErrorNotPresent, + MfUltralightErrorProtocol, + MfUltralightErrorAuth, + MfUltralightErrorTimeout, +} MfUltralightError; + +typedef struct { + uint8_t data[MF_ULTRALIGHT_PAGE_SIZE]; +} MfUltralightPage; + +typedef struct { + uint8_t header; + uint8_t vendor_id; + uint8_t prod_type; + uint8_t prod_subtype; + uint8_t prod_ver_major; + uint8_t prod_ver_minor; + uint8_t storage_size; + uint8_t protocol_type; +} MfUltralightVersion; + +typedef struct { + uint8_t data[MF_ULTRALIGHT_SIGNATURE_SIZE]; +} MfUltralightSignature; + +typedef struct { + uint8_t data[MF_ULTRALIGHT_COUNTER_SIZE]; +} MfUltralightCounter; + +typedef struct { + uint8_t data[MF_ULTRALIGHT_TEARING_FLAG_SIZE]; +} MfUltralightTearingFlag; + +typedef struct { + NfcaData nfca_data; + MfUltralightVersion version; + MfUltralightSignature signature; + MfUltralightCounter counter[MF_ULTRALIGHT_COUNTER_NUM]; + MfUltralightTearingFlag tearing_flag[MF_ULTRALIGHT_TEARING_FLAG_NUM]; + MfUltralightPage page[MF_ULTRALIGHT_MAX_PAGE_NUM]; +} MfUltralightData; + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/mf_ultralight_listener.c b/lib/nfc/protocols/mf_ultralight_listener.c new file mode 100644 index 000000000000..35e485e9b5d8 --- /dev/null +++ b/lib/nfc/protocols/mf_ultralight_listener.c @@ -0,0 +1,24 @@ +#include "mf_ultralight_listener.h" +#include "nfca_listener.h" + +#include + +struct MfUltralightListener { + NfcaListener* nfca_listener; +}; + +MfUltralightListener* mf_ultralight_listener_alloc(MfUltralightData* data) { + furi_assert(data); + + MfUltralightListener* instance = malloc(sizeof(MfUltralightData)); + instance->nfca_listener = nfca_listener_alloc(&data->nfca_data); + + return instance; +} + +void mf_ultralight_listener_free(MfUltralightListener* instance) { + furi_assert(instance); + + nfca_listener_free(instance->nfca_listener); + free(instance); +} diff --git a/lib/nfc/protocols/mf_ultralight_listener.h b/lib/nfc/protocols/mf_ultralight_listener.h new file mode 100644 index 000000000000..6ca848dffcff --- /dev/null +++ b/lib/nfc/protocols/mf_ultralight_listener.h @@ -0,0 +1,17 @@ +#pragma once + +#include "mf_ultralight_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct MfUltralightListener MfUltralightListener; + +MfUltralightListener* mf_ultralight_listener_alloc(MfUltralightData* data); + +void mf_ultralight_listener_free(MfUltralightListener* instance); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/mf_ultralight_poller.c b/lib/nfc/protocols/mf_ultralight_poller.c new file mode 100644 index 000000000000..e24b51bb83fb --- /dev/null +++ b/lib/nfc/protocols/mf_ultralight_poller.c @@ -0,0 +1,286 @@ +#include "mf_ultralight_poller.h" + +#include +#include "nfca_poller.h" + +#define TAG "MfUltralightPoller" + +#define MF_ULTRALIGHT_MAX_BUFF_SIZE (128) + +#define MF_ULTRALIGHT_POLLER_STANDART_FWT_FC (12000) + +struct MfUltralightPoller { + NfcaPoller* nfca_poller; + NfcaData nfca_data; +}; + +MfUltralightPoller* mf_ultralight_poller_alloc() { + MfUltralightPoller* instance = malloc(sizeof(MfUltralightPoller)); + instance->nfca_poller = nfca_poller_alloc(); + + return instance; +} + +void mf_ultralight_poller_free(MfUltralightPoller* instance) { + furi_assert(instance); + furi_assert(instance->nfca_poller); + + nfca_poller_free(instance->nfca_poller); + free(instance); +} + +static MfUltralightError mf_ultralight_process_error(NfcaError error) { + MfUltralightError ret = MfUltralightErrorNone; + + switch(error) { + case NfcaErrorNone: + ret = MfUltralightErrorNone; + break; + case NfcaErrorNotPresent: + ret = MfUltralightErrorNotPresent; + break; + case NfcaErrorColResFailed: + case NfcaErrorCommunication: + case NfcaErrorWrongCrc: + ret = MfUltralightErrorProtocol; + break; + case NfcaErrorTimeout: + ret = MfUltralightErrorTimeout; + break; + default: + ret = MfUltralightErrorProtocol; + break; + } + + return ret; +} + +MfUltralightError mf_ultralight_poller_read_page( + MfUltralightPoller* instance, + uint16_t page, + MfUltralightPage* data) { + furi_assert(instance); + furi_assert(data); + + uint8_t tx_data[] = {MF_ULTRALIGHT_CMD_READ_PAGE, page}; + uint16_t tx_bits = sizeof(tx_data) * 8; + uint8_t rx_data[MF_ULTRALIGHT_MAX_BUFF_SIZE] = {}; + uint16_t rx_bits = 0; + MfUltralightError ret = MfUltralightErrorNone; + NfcaError error = NfcaErrorNone; + + do { + error = nfca_poller_send_standart_frame( + instance->nfca_poller, + tx_data, + tx_bits, + rx_data, + sizeof(rx_data), + &rx_bits, + MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); + if(error != NfcaErrorNone) { + ret = mf_ultralight_process_error(error); + break; + } + if(rx_bits != (MF_ULTRALIGHT_PAGE_SIZE * 4) * 8) { + FURI_LOG_E( + TAG, "Received %d bits. Expected %d bits", rx_bits, (MF_ULTRALIGHT_PAGE_SIZE)*8); + ret = MfUltralightErrorProtocol; + break; + } + memcpy(data, rx_data, MF_ULTRALIGHT_PAGE_SIZE); + } while(false); + + return ret; +} + +MfUltralightError mf_ultralight_poller_write_page( + MfUltralightPoller* instance, + uint16_t page, + MfUltralightPage* data) { + furi_assert(instance); + furi_assert(data); + + uint8_t tx_data[MF_ULTRALIGHT_PAGE_SIZE + 2] = {MF_ULTRALIGHT_CMD_WRITE_PAGE, page}; + memcpy(&tx_data[2], data, MF_ULTRALIGHT_PAGE_SIZE); + uint16_t tx_bits = (MF_ULTRALIGHT_PAGE_SIZE + 2) * 8; + uint8_t rx_data[MF_ULTRALIGHT_MAX_BUFF_SIZE] = {}; + uint16_t rx_bits = 0; + NfcaError error = NfcaErrorNone; + MfUltralightError ret = MfUltralightErrorNone; + + do { + error = nfca_poller_send_standart_frame( + instance->nfca_poller, + tx_data, + tx_bits, + rx_data, + sizeof(rx_data), + &rx_bits, + MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); + if(!(error == NfcaErrorNone || error == NfcaErrorWrongCrc)) { + ret = mf_ultralight_process_error(error); + break; + } + if(rx_bits != 4) { + ret = MfUltralightErrorProtocol; + FURI_LOG_E(TAG, "Received %d bits. Expected %d bits", rx_bits, 4); + break; + } + if(rx_data[0] != MF_ULTRALIGHT_CMD_ACK) { + ret = MfUltralightErrorProtocol; + FURI_LOG_E(TAG, "Nack received"); + break; + } + } while(false); + + return ret; +} + +MfUltralightError + mf_ultralight_poller_read_version(MfUltralightPoller* instance, MfUltralightVersion* data) { + furi_assert(instance); + furi_assert(data); + + uint8_t tx_data[] = {MF_ULTRALIGHT_CMD_GET_VERSION}; + uint16_t tx_bits = sizeof(tx_data) * 8; + uint8_t rx_data[MF_ULTRALIGHT_MAX_BUFF_SIZE] = {}; + uint16_t rx_bits = 0; + NfcaError error = NfcaErrorNone; + MfUltralightError ret = MfUltralightErrorNone; + + do { + error = nfca_poller_send_standart_frame( + instance->nfca_poller, + tx_data, + tx_bits, + rx_data, + sizeof(rx_data), + &rx_bits, + MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); + if(error != NfcaErrorNone) { + ret = mf_ultralight_process_error(error); + break; + } + if(rx_bits != 8 * 8) { + ret = MfUltralightErrorProtocol; + FURI_LOG_E(TAG, "Received %d bits. Expected %d bits", rx_bits, 8 * 8); + break; + } + memcpy(data, rx_data, sizeof(MfUltralightVersion)); + } while(false); + + return ret; +} + +MfUltralightError + mf_ultralight_poller_read_signature(MfUltralightPoller* instance, MfUltralightSignature* data) { + furi_assert(instance); + furi_assert(data); + + uint8_t tx_data[] = {MF_ULTRALIGTH_CMD_READ_SIG, 0x00}; + uint16_t tx_bits = sizeof(tx_data) * 8; + uint8_t rx_data[MF_ULTRALIGHT_MAX_BUFF_SIZE] = {}; + uint16_t rx_bits = 0; + NfcaError error = NfcaErrorNone; + MfUltralightError ret = MfUltralightErrorNone; + + do { + error = nfca_poller_send_standart_frame( + instance->nfca_poller, + tx_data, + tx_bits, + rx_data, + sizeof(rx_data), + &rx_bits, + MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); + if(error != NfcaErrorNone) { + ret = mf_ultralight_process_error(error); + break; + } + if(rx_bits != 32 * 8) { + ret = MfUltralightErrorProtocol; + FURI_LOG_E(TAG, "Received %d bits. Expected %d bits", rx_bits, 32 * 8); + break; + } + memcpy(data, rx_data, sizeof(MfUltralightSignature)); + } while(false); + + return ret; +} + +MfUltralightError mf_ultralight_poller_read_counter( + MfUltralightPoller* instance, + uint8_t counter_num, + MfUltralightCounter* data) { + furi_assert(instance); + furi_assert(data); + + uint8_t tx_data[] = {MF_ULTRALIGHT_CMD_READ_CNT, counter_num}; + uint16_t tx_bits = sizeof(tx_data) * 8; + uint8_t rx_data[MF_ULTRALIGHT_MAX_BUFF_SIZE] = {}; + uint16_t rx_bits = 0; + NfcaError error = NfcaErrorNone; + MfUltralightError ret = MfUltralightErrorNone; + + do { + error = nfca_poller_send_standart_frame( + instance->nfca_poller, + tx_data, + tx_bits, + rx_data, + sizeof(rx_data), + &rx_bits, + MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); + if(error != NfcaErrorNone) { + ret = mf_ultralight_process_error(error); + break; + } + if(rx_bits != 3 * 8) { + ret = MfUltralightErrorProtocol; + FURI_LOG_E(TAG, "Received %d bits. Expected %d bits", rx_bits, 32 * 8); + break; + } + memcpy(data, rx_data, sizeof(MfUltralightCounter)); + } while(false); + + return ret; +} + +MfUltralightError mf_ultralight_poller_read_tearing_flag( + MfUltralightPoller* instance, + uint8_t flag_num, + MfUltralightTearingFlag* data) { + furi_assert(instance); + furi_assert(data); + + uint8_t tx_data[] = {MF_ULTRALIGHT_CMD_CHECK_TEARING, flag_num}; + uint16_t tx_bits = sizeof(tx_data) * 8; + uint8_t rx_data[MF_ULTRALIGHT_MAX_BUFF_SIZE] = {}; + uint16_t rx_bits = 0; + NfcaError error = NfcaErrorNone; + MfUltralightError ret = MfUltralightErrorNone; + + do { + error = nfca_poller_send_standart_frame( + instance->nfca_poller, + tx_data, + tx_bits, + rx_data, + sizeof(rx_data), + &rx_bits, + MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); + if(error != NfcaErrorNone) { + ret = mf_ultralight_process_error(error); + break; + } + if(rx_bits != 8) { + ret = MfUltralightErrorProtocol; + FURI_LOG_E(TAG, "Received %d bits. Expected %d bits", rx_bits, 8); + break; + } + memcpy(data, rx_data, sizeof(MfUltralightTearingFlag)); + } while(false); + + return ret; +} diff --git a/lib/nfc/protocols/mf_ultralight_poller.h b/lib/nfc/protocols/mf_ultralight_poller.h new file mode 100644 index 000000000000..ac2fa8ec4dfa --- /dev/null +++ b/lib/nfc/protocols/mf_ultralight_poller.h @@ -0,0 +1,43 @@ +#pragma once + +#include "mf_ultralight_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct MfUltralightPoller MfUltralightPoller; + +MfUltralightPoller* mf_ultralight_poller_alloc(); + +void mf_ultralight_poller_free(MfUltralightPoller* instance); + +MfUltralightError mf_ultralight_poller_read_page( + MfUltralightPoller* instance, + uint16_t page, + MfUltralightPage* data); + +MfUltralightError mf_ultralight_poller_write_page( + MfUltralightPoller* instance, + uint16_t page, + MfUltralightPage* data); + +MfUltralightError + mf_ultralight_poller_read_version(MfUltralightPoller* instance, MfUltralightVersion* data); + +MfUltralightError + mf_ultralight_poller_read_signature(MfUltralightPoller* instance, MfUltralightSignature* data); + +MfUltralightError mf_ultralight_poller_read_counter( + MfUltralightPoller* instance, + uint8_t counter_num, + MfUltralightCounter* data); + +MfUltralightError mf_ultralight_poller_read_tearing_flag( + MfUltralightPoller* instance, + uint8_t flag_num, + MfUltralightTearingFlag* data); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/nfca_common.h b/lib/nfc/protocols/nfca_common.h new file mode 100644 index 000000000000..b225f0cccbff --- /dev/null +++ b/lib/nfc/protocols/nfca_common.h @@ -0,0 +1,63 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define NFCA_MAX_UID_SIZE (10U) + +#define NFCA_GUARD_TIME_US (5000) +#define NFCA_FDT_POLL_FC (1620) +#define NFCA_FDT_LISTEN_FC (1172) +#define NFCA_POLLER_MASK_RX_FS ((NFCA_FDT_LISTEN_FC) / 2) +#define NFCA_POLL_POLL_MIN_US (1100) + +typedef enum { + NfcaErrorNone, + NfcaErrorNotPresent, + NfcaErrorColResFailed, + NfcaErrorBufferOverflow, + NfcaErrorCommunication, + NfcaErrorFieldOff, + NfcaErrorWrongCrc, + NfcaErrorTimeout, +} NfcaError; + +typedef struct { + uint8_t sens_resp[2]; +} NfcaSensResp; + +typedef struct { + uint8_t sel_cmd; + uint8_t sel_par; + uint8_t data[4]; // max data bit is 32 +} NfcaSddReq; + +typedef struct { + uint8_t nfcid[4]; + uint8_t bss; +} NfcaSddResp; + +typedef struct { + uint8_t sel_cmd; + uint8_t sel_par; + uint8_t nfcid[4]; + uint8_t bcc; +} NfcaSelReq; + +typedef struct { + uint8_t sak; +} NfcaSelResp; + +typedef struct { + uint8_t uid[NFCA_MAX_UID_SIZE]; + uint8_t uid_len; + uint8_t atqa[2]; + uint8_t sak; +} NfcaData; + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/nfca_listener.c b/lib/nfc/protocols/nfca_listener.c new file mode 100644 index 000000000000..1db99bca1a1e --- /dev/null +++ b/lib/nfc/protocols/nfca_listener.c @@ -0,0 +1,87 @@ +#include "nfca_listener.h" + +#include +#include + +#define TAG "NfcaListener" + +typedef enum { + NfcaListenerStateIdle, + NfcaListenerStateColResInProgress, + NfcaListenerStateActive, +} NfcaListenerState; + +struct NfcaListener { + Nfc* nfc; + NfcaData data; + NfcaListenerState state; +}; + +static NfcaError nfca_listener_process_nfc_error(NfcError error) { + NfcaError ret = NfcaErrorNone; + + if(error == NfcErrorNone) { + ret = NfcaErrorNone; + } else if(error == NfcErrorTimeout) { + ret = NfcaErrorTimeout; + } else { + ret = NfcaErrorFieldOff; + } + + return ret; +} + +NfcaListener* nfca_listener_alloc(NfcaData* data) { + NfcaListener* instance = malloc(sizeof(NfcaListener)); + instance->data = *data; + instance->nfc = nfc_alloc(); + nfc_set_fdt_listen_fc(instance->nfc, NFCA_FDT_LISTEN_FC); + nfc_config(instance->nfc, NfcModeNfcaListener); + nfc_listener_set_col_res_data( + instance->nfc, + instance->data.uid, + instance->data.uid_len, + instance->data.atqa, + instance->data.sak); + + return instance; +} + +void nfca_listener_free(NfcaListener* instance) { + furi_assert(instance); + nfc_free(instance->nfc); + free(instance); +} + +NfcaError nfca_listener_rx( + NfcaListener* instance, + uint8_t* rx_data, + uint16_t rx_data_size, + uint16_t* rx_bits, + uint32_t timeout_ms) { + furi_assert(instance); + furi_assert(instance->nfc); + furi_assert(rx_data); + furi_assert(rx_bits); + + NfcaError ret = NfcaErrorNone; + NfcError error = nfc_listener_rx(instance->nfc, rx_data, rx_data_size, rx_bits, timeout_ms); + if(error != NfcErrorNone) { + FURI_LOG_W(TAG, "Rx error: %d", error); + ret = nfca_listener_process_nfc_error(error); + } + return ret; +} + +NfcaError nfca_listener_tx(NfcaListener* instance, uint8_t* tx_data, uint16_t tx_bits) { + furi_assert(instance); + furi_assert(tx_data); + + NfcaError ret = NfcaErrorNone; + NfcError error = nfc_listener_tx(instance->nfc, tx_data, tx_bits); + if(error != NfcErrorNone) { + FURI_LOG_W(TAG, "Tx error: %d", error); + ret = nfca_listener_process_nfc_error(error); + } + return ret; +} diff --git a/lib/nfc/protocols/nfca_listener.h b/lib/nfc/protocols/nfca_listener.h new file mode 100644 index 000000000000..c1097b2c1fa6 --- /dev/null +++ b/lib/nfc/protocols/nfca_listener.h @@ -0,0 +1,26 @@ +#pragma once + +#include "nfca_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct NfcaListener NfcaListener; + +NfcaListener* nfca_listener_alloc(NfcaData* data); + +void nfca_listener_free(NfcaListener* instance); + +NfcaError nfca_listener_rx( + NfcaListener* instance, + uint8_t* rx_data, + uint16_t rx_data_size, + uint16_t* rx_bits, + uint32_t timeout_ms); + +NfcaError nfca_listener_tx(NfcaListener* instance, uint8_t* tx_data, uint16_t tx_bits); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/nfca_poller.c b/lib/nfc/protocols/nfca_poller.c new file mode 100644 index 000000000000..106e76502726 --- /dev/null +++ b/lib/nfc/protocols/nfca_poller.c @@ -0,0 +1,402 @@ +#include "nfca_poller.h" +#include "nfca_common.h" + +#include +#include + +#define TAG "NFCA" + +#define NFCA_CRC_INIT (0x6363) +#define NFCA_POLLER_MAX_TX_BUFFER_SIZE (512U) + +#define NFCA_POLLER_SEL_CMD(cascade_lvl) (0x93 + 2 * (cascade_lvl)) +#define NFCA_POLLER_SEL_PAR(bytes, bits) (((bytes) << 4 & 0xf0U) | ((bits)&0x0fU)) +#define NFCA_POLLER_SDD_CL (0x88U) + +typedef enum { + NfcaPollerColResStateStateIdle, + NfcaPollerColResStateStateNewCascade, + NfcaPollerColResStateStateSelectCascade, + NfcaPollerColResStateStateSuccess, + NfcaPollerColResStateStateFail, +} NfcaPollerColResState; + +typedef struct { + NfcaPollerColResState state; + NfcaSensResp sens_resp; + NfcaSddReq sdd_req; + NfcaSddResp sdd_resp; + NfcaSelReq sel_req; + NfcaSelResp sel_resp; + uint8_t cascade_level; +} NfcaPollerColRes; + +typedef enum { + NfcaPollerStateIdle, + NfcaPollerColResInProgress, + NfcaPollerColResFailed, + NfcaPollerActivated, +} NfcaPollerState; + +struct NfcaPoller { + Nfc* nfc; + NfcaPollerState state; + NfcaPollerColRes col_res; + NfcaData data; +}; + +static NfcaError nfca_poller_process_error(NfcError error) { + NfcaError ret = NfcaErrorNone; + if(error == NfcErrorNone) { + ret = NfcaErrorNone; + } else if(error == NfcErrorTimeout) { + ret = NfcaErrorTimeout; + } else { + ret = NfcaErrorNotPresent; + } + return ret; +} + +static uint16_t nfca_poller_get_crc16(uint8_t* buff, uint16_t len) { + uint16_t crc = NFCA_CRC_INIT; + uint8_t byte = 0; + + for(uint8_t i = 0; i < len; i++) { + byte = buff[i]; + byte ^= (uint8_t)(crc & 0xff); + byte ^= byte << 4; + crc = (crc >> 8) ^ (((uint16_t)byte) << 8) ^ (((uint16_t)byte) << 3) ^ + (((uint16_t)byte) >> 4); + } + + return crc; +} + +static void nfca_poller_append_crc16(uint8_t* buff, uint16_t len) { + uint16_t crc = nfca_poller_get_crc16(buff, len); + buff[len] = (uint8_t)crc; + buff[len + 1] = (uint8_t)(crc >> 8); +} + +static NfcaError nfca_poller_standart_frame_exchange( + NfcaPoller* instance, + uint8_t* tx_data, + uint16_t tx_bits, + uint8_t* rx_data, + uint16_t rx_data_size, + uint16_t* rx_bits, + uint32_t fwt) { + furi_assert(instance); + furi_assert(tx_data); + furi_assert(rx_data); + furi_assert(rx_bits); + furi_assert(tx_bits >= 8); + + uint16_t tx_bytes = tx_bits / 8; + furi_assert(tx_bytes <= NFCA_POLLER_MAX_TX_BUFFER_SIZE - 2); + uint16_t rx_buff_bits = 0; + uint8_t rx_buff[NFCA_POLLER_MAX_TX_BUFFER_SIZE] = {}; + uint8_t tx_buff[NFCA_POLLER_MAX_TX_BUFFER_SIZE] = {}; + + memcpy(tx_buff, tx_data, tx_bytes); + nfca_poller_append_crc16(tx_buff, tx_bytes); + NfcaError ret = NfcaErrorNone; + + do { + NfcError error = nfc_trx( + instance->nfc, tx_buff, tx_bits + 16, rx_buff, sizeof(rx_buff), &rx_buff_bits, fwt); + if(error != NfcErrorNone) { + ret = nfca_poller_process_error(error); + break; + } + if(rx_buff_bits < 8) { + rx_data[0] = rx_buff[0]; + *rx_bits = rx_buff_bits; + ret = NfcaErrorWrongCrc; + break; + } else if(rx_buff_bits < 3 * 8) { + uint16_t rx_bytes = rx_buff_bits / 8; + memcpy(rx_data, rx_buff, rx_bytes); + *rx_bits = rx_buff_bits; + ret = NfcaErrorWrongCrc; + break; + } else { + uint16_t rx_bytes = rx_buff_bits / 8; + if(rx_bytes - 2 > rx_data_size) { + ret = NfcaErrorBufferOverflow; + break; + } + uint16_t crc_calc = nfca_poller_get_crc16(rx_buff, rx_bytes - 2); + uint16_t crc_received = (rx_buff[rx_bytes - 1] << 8) | rx_buff[rx_bytes - 2]; + if(crc_calc != crc_received) { + FURI_LOG_W(TAG, "CRC error: received %04X, expected %04X", crc_received, crc_calc); + ret = NfcaErrorWrongCrc; + break; + } + memcpy(rx_data, rx_buff, rx_bytes - 2); + *rx_bits = (rx_bytes - 2) * 8; + } + } while(false); + + return ret; +} + +static NfcaError nfca_poller_prepare_trx(NfcaPoller* instance) { + NfcaError ret = NfcaErrorNone; + + if(instance->state == NfcaPollerStateIdle) { + ret = nfca_poller_activate(instance, NULL); + } + + return ret; +} + +NfcaPoller* nfca_poller_alloc() { + NfcaPoller* instance = malloc(sizeof(NfcaPoller)); + instance->nfc = nfc_alloc(); + nfc_config(instance->nfc, NfcModeNfcaPoller); + nfc_set_guard_time_us(instance->nfc, NFCA_GUARD_TIME_US); + nfc_set_fdt_poll_fc(instance->nfc, NFCA_FDT_POLL_FC); + nfc_set_fdt_poll_poll_us(instance->nfc, NFCA_POLL_POLL_MIN_US); + + return instance; +} + +void nfca_poller_free(NfcaPoller* instance) { + furi_assert(instance); + furi_assert(instance->nfc); + + nfc_free(instance->nfc); + free(instance); +} + +NfcaError nfca_poller_check_presence(NfcaPoller* instance) { + furi_assert(instance); + furi_assert(instance->nfc); + + uint16_t rx_bits = 0; + NfcError error = NfcErrorNone; + NfcaError ret = 0; + do { + error = nfc_iso13444a_short_frame( + instance->nfc, + NfcIso14443aShortFrameSensReq, + (uint8_t*)&instance->col_res.sens_resp, + sizeof(instance->col_res.sens_resp), + &rx_bits, + NFCA_FDT_LISTEN_FC); + if(error != NfcErrorNone) { + ret = nfca_poller_process_error(error); + } + if(rx_bits != 8 * sizeof(instance->col_res.sens_resp)) { + ret = NfcaErrorCommunication; + break; + } + } while(false); + + return ret; +} + +NfcaError nfca_poller_halt(NfcaPoller* instance) { + furi_assert(instance); + furi_assert(instance->nfc); + + // Halt + // Set Idle state + instance->state = NfcaPollerStateIdle; + return NfcaErrorNone; +} + +NfcaError nfca_poller_activate(NfcaPoller* instance, NfcaData* nfca_data) { + furi_assert(instance); + furi_assert(instance->nfc); + + // Reset Nfca poller state + memset(&instance->col_res, 0, sizeof(instance->col_res)); + memset(&instance->data, 0, sizeof(instance->data)); + + // Halt if necessary + if(instance->state != NfcaPollerStateIdle) { + nfca_poller_halt(instance); + instance->state = NfcaPollerStateIdle; + } + + NfcError error = NfcErrorNone; + NfcaError ret = NfcaErrorNone; + uint16_t rx_bits = 0; + uint16_t tx_bits = 0; + + bool activated = false; + do { + error = nfc_iso13444a_short_frame( + instance->nfc, + NfcIso14443aShortFrameSensReq, + (uint8_t*)&instance->col_res.sens_resp, + sizeof(instance->col_res.sens_resp), + &rx_bits, + NFCA_FDT_LISTEN_FC); + if(error != NfcErrorNone) { + ret = NfcaErrorNotPresent; + break; + } + if(rx_bits != 8 * sizeof(instance->col_res.sens_resp)) { + FURI_LOG_W(TAG, "Wrong response: %d", rx_bits); + ret = NfcaErrorCommunication; + break; + } + memcpy( + instance->data.atqa, &instance->col_res.sens_resp, sizeof(instance->col_res.sel_resp)); + + instance->state = NfcaPollerColResInProgress; + instance->col_res.cascade_level = 0; + instance->col_res.state = NfcaPollerColResStateStateNewCascade; + + while(instance->state == NfcaPollerColResInProgress) { + if(instance->col_res.state == NfcaPollerColResStateStateNewCascade) { + instance->col_res.sdd_req.sel_cmd = + NFCA_POLLER_SEL_CMD(instance->col_res.cascade_level); + instance->col_res.sdd_req.sel_par = NFCA_POLLER_SEL_PAR(2, 0); + tx_bits = 16; + error = nfc_iso13444a_sdd_frame( + instance->nfc, + (uint8_t*)&instance->col_res.sdd_req, + tx_bits, + (uint8_t*)&instance->col_res.sdd_resp, + sizeof(instance->col_res.sdd_resp), + &rx_bits, + NFCA_FDT_LISTEN_FC); + if(error != NfcErrorNone) { + FURI_LOG_E(TAG, "Sdd request failed: %d", error); + instance->state = NfcaPollerColResFailed; + ret = NfcaErrorColResFailed; + break; + } + if(rx_bits != 5 * 8) { + FURI_LOG_E(TAG, "Sdd response wrong length: %d bits", rx_bits); + instance->state = NfcaPollerColResFailed; + ret = NfcaErrorColResFailed; + break; + } + // TODO BCC check here + instance->col_res.state = NfcaPollerColResStateStateSelectCascade; + } else if(instance->col_res.state == NfcaPollerColResStateStateSelectCascade) { + instance->col_res.sel_req.sel_cmd = + NFCA_POLLER_SEL_CMD(instance->col_res.cascade_level); + instance->col_res.sel_req.sel_par = NFCA_POLLER_SEL_PAR(7, 0); + memcpy( + instance->col_res.sel_req.nfcid, + instance->col_res.sdd_resp.nfcid, + sizeof(instance->col_res.sdd_resp.nfcid)); + instance->col_res.sel_req.bcc = instance->col_res.sdd_resp.bss; + // Todo remove after Nfc handles timings + furi_delay_ms(10); + ret = nfca_poller_send_standart_frame( + instance, + (uint8_t*)&instance->col_res.sel_req, + 8 * sizeof(instance->col_res.sel_req), + (uint8_t*)&instance->col_res.sel_resp, + sizeof(NfcaSelResp), + &rx_bits, + NFCA_FDT_LISTEN_FC); + if(ret != NfcaErrorNone) { + FURI_LOG_E(TAG, "Sel request failed: %d", error); + instance->state = NfcaPollerColResFailed; + ret = NfcaErrorColResFailed; + break; + } + if(rx_bits != 8 * sizeof(instance->col_res.sel_resp)) { + FURI_LOG_E(TAG, "Sel response wrong length: %d bits", rx_bits); + instance->state = NfcaPollerColResFailed; + ret = NfcaErrorColResFailed; + break; + } + FURI_LOG_T(TAG, "Sel resp: %02X", instance->col_res.sel_resp.sak); + if(instance->col_res.sel_req.nfcid[0] == NFCA_POLLER_SDD_CL) { + // Copy part of UID + memcpy( + &instance->data.uid[instance->data.uid_len], + &instance->col_res.sel_req.nfcid[1], + 3); + instance->data.uid_len += 3; + instance->col_res.cascade_level++; + instance->col_res.state = NfcaPollerColResStateStateNewCascade; + } else { + FURI_LOG_T(TAG, "Col resolution complete"); + instance->data.sak = instance->col_res.sel_resp.sak; + memcpy( + &instance->data.uid[instance->data.uid_len], + &instance->col_res.sel_req.nfcid[0], + 4); + instance->data.uid_len += 4; + instance->col_res.state = NfcaPollerColResStateStateSuccess; + instance->state = NfcaPollerActivated; + } + } + } + activated = (instance->state == NfcaPollerActivated); + } while(false); + + if(activated && nfca_data) { + *nfca_data = instance->data; + } + + return ret; +} + +NfcaError nfca_poller_txrx( + NfcaPoller* instance, + uint8_t* tx_buff, + uint16_t tx_bits, + uint8_t* rx_buff, + uint16_t rx_buff_size, + uint16_t* rx_bits, + uint32_t fwt) { + furi_assert(instance); + furi_assert(tx_buff); + furi_assert(rx_buff); + furi_assert(rx_bits); + + NfcaError ret = NfcaErrorNone; + NfcError error = NfcErrorNone; + + do { + ret = nfca_poller_prepare_trx(instance); + if(ret != NfcaErrorNone) break; + + error = nfc_trx(instance->nfc, tx_buff, tx_bits, rx_buff, rx_buff_size, rx_bits, fwt); + if(error != NfcErrorNone) { + ret = nfca_poller_process_error(error); + break; + } + } while(false); + + return ret; +} + +NfcaError nfca_poller_send_standart_frame( + NfcaPoller* instance, + uint8_t* tx_data, + uint16_t tx_bits, + uint8_t* rx_data, + uint16_t rx_data_size, + uint16_t* rx_bits, + uint32_t fwt) { + furi_assert(instance); + furi_assert(tx_data); + furi_assert(rx_data); + furi_assert(rx_bits); + furi_assert(tx_bits >= 8); + + NfcaError ret = NfcaErrorNone; + + do { + ret = nfca_poller_prepare_trx(instance); + if(ret != NfcaErrorNone) break; + + ret = nfca_poller_standart_frame_exchange( + instance, tx_data, tx_bits, rx_data, rx_data_size, rx_bits, fwt); + if(ret != NfcaErrorNone) break; + } while(false); + + return ret; +} diff --git a/lib/nfc/protocols/nfca_poller.h b/lib/nfc/protocols/nfca_poller.h new file mode 100644 index 000000000000..7bed605dbb15 --- /dev/null +++ b/lib/nfc/protocols/nfca_poller.h @@ -0,0 +1,43 @@ +#pragma once + +#include "nfca_common.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct NfcaPoller NfcaPoller; + +NfcaPoller* nfca_poller_alloc(); + +void nfca_poller_free(NfcaPoller* instance); + +NfcaError nfca_poller_check_presence(NfcaPoller* instance); + +NfcaError nfca_poller_activate(NfcaPoller* instance, NfcaData* nfca_data); + +NfcaError nfca_poller_halt(NfcaPoller* instance); + +NfcaError nfca_poller_txrx( + NfcaPoller* instance, + uint8_t* tx_buff, + uint16_t tx_bits, + uint8_t* rx_buff, + uint16_t rx_buff_size, + uint16_t* rx_bits, + uint32_t fwt); + +NfcaError nfca_poller_send_standart_frame( + NfcaPoller* instance, + uint8_t* tx_data, + uint16_t tx_bits, + uint8_t* rx_data, + uint16_t rx_data_size, + uint16_t* rx_bits, + uint32_t fwt); + +#ifdef __cplusplus +} +#endif From 6663843aa7e92f9f36cc02c1510315c696162d3d Mon Sep 17 00:00:00 2001 From: gornekich Date: Thu, 23 Mar 2023 16:43:08 +0400 Subject: [PATCH 004/149] nfc: introduce nfc rpc app --- applications/main/nfc_rpc/application.fam | 13 + .../main/nfc_rpc/assets/compiled/main.pb.c | 16 + .../main/nfc_rpc/assets/compiled/main.pb.h | 145 +++++++++ .../assets/compiled/mf_ultralight.pb.c | 46 +++ .../assets/compiled/mf_ultralight.pb.h | 299 ++++++++++++++++++ .../main/nfc_rpc/assets/compiled/nfca.pb.c | 16 + .../main/nfc_rpc/assets/compiled/nfca.pb.h | 97 ++++++ .../main/nfc_rpc/assets/protobuf/main.options | 1 + .../main/nfc_rpc/assets/protobuf/main.proto | 39 +++ .../assets/protobuf/mf_ultralight.options | 8 + .../assets/protobuf/mf_ultralight.proto | 67 ++++ .../main/nfc_rpc/assets/protobuf/nfca.options | 3 + .../main/nfc_rpc/assets/protobuf/nfca.proto | 25 ++ applications/main/nfc_rpc/nfc_rpc.c | 249 +++++++++++++++ applications/main/nfc_rpc/nfc_rpc.h | 3 + applications/main/nfc_rpc/nfc_rpc_i.h | 22 ++ .../main/nfc_rpc/nfc_rpc_mf_ultralight.c | 208 ++++++++++++ applications/main/nfc_rpc/nfc_rpc_nfca.c | 75 +++++ 18 files changed, 1332 insertions(+) create mode 100644 applications/main/nfc_rpc/application.fam create mode 100644 applications/main/nfc_rpc/assets/compiled/main.pb.c create mode 100644 applications/main/nfc_rpc/assets/compiled/main.pb.h create mode 100644 applications/main/nfc_rpc/assets/compiled/mf_ultralight.pb.c create mode 100644 applications/main/nfc_rpc/assets/compiled/mf_ultralight.pb.h create mode 100644 applications/main/nfc_rpc/assets/compiled/nfca.pb.c create mode 100644 applications/main/nfc_rpc/assets/compiled/nfca.pb.h create mode 100644 applications/main/nfc_rpc/assets/protobuf/main.options create mode 100644 applications/main/nfc_rpc/assets/protobuf/main.proto create mode 100644 applications/main/nfc_rpc/assets/protobuf/mf_ultralight.options create mode 100644 applications/main/nfc_rpc/assets/protobuf/mf_ultralight.proto create mode 100644 applications/main/nfc_rpc/assets/protobuf/nfca.options create mode 100644 applications/main/nfc_rpc/assets/protobuf/nfca.proto create mode 100644 applications/main/nfc_rpc/nfc_rpc.c create mode 100644 applications/main/nfc_rpc/nfc_rpc.h create mode 100644 applications/main/nfc_rpc/nfc_rpc_i.h create mode 100644 applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c create mode 100644 applications/main/nfc_rpc/nfc_rpc_nfca.c diff --git a/applications/main/nfc_rpc/application.fam b/applications/main/nfc_rpc/application.fam new file mode 100644 index 000000000000..e28b18a98fe0 --- /dev/null +++ b/applications/main/nfc_rpc/application.fam @@ -0,0 +1,13 @@ +App( + appid="nfc_rpc", + name="NfcRpc", + apptype=FlipperAppType.APP, + targets=["f7"], + entry_point="nfc_rpc_app", + requires=[ + "gui", + ], + stack_size=8 * 1024, + order=30, + icon="A_NFC_14", +) diff --git a/applications/main/nfc_rpc/assets/compiled/main.pb.c b/applications/main/nfc_rpc/assets/compiled/main.pb.c new file mode 100644 index 000000000000..0d01259546ff --- /dev/null +++ b/applications/main/nfc_rpc/assets/compiled/main.pb.c @@ -0,0 +1,16 @@ +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-0.4.8-dev */ + +#include "main.pb.h" +#if PB_PROTO_HEADER_VERSION != 40 +#error Regenerate this file with the current version of nanopb generator. +#endif + +PB_BIND(Nfc_Empty, Nfc_Empty, AUTO) + + +PB_BIND(Nfc_Main, Nfc_Main, AUTO) + + + + diff --git a/applications/main/nfc_rpc/assets/compiled/main.pb.h b/applications/main/nfc_rpc/assets/compiled/main.pb.h new file mode 100644 index 000000000000..f35276f57743 --- /dev/null +++ b/applications/main/nfc_rpc/assets/compiled/main.pb.h @@ -0,0 +1,145 @@ +/* Automatically generated nanopb header */ +/* Generated by nanopb-0.4.8-dev */ + +#ifndef PB_NFC_MAIN_PB_H_INCLUDED +#define PB_NFC_MAIN_PB_H_INCLUDED +#include +#include "nfca.pb.h" +#include "mf_ultralight.pb.h" + +#if PB_PROTO_HEADER_VERSION != 40 +#error Regenerate this file with the current version of nanopb generator. +#endif + +/* Enum definitions */ +typedef enum _Nfc_CommandStatus { + Nfc_CommandStatus_OK = 0, + Nfc_CommandStatus_ERROR = 1, /* *< Unknown error */ + Nfc_CommandStatus_ERROR_NOT_IMPLEMENTED = 3, /* *< Command succesfully decoded, but not +implemented (deprecated or not yet implemented) */ + Nfc_CommandStatus_ERROR_BUSY = 4 /* *< Somebody took global lock, so not all commands are available */ +} Nfc_CommandStatus; + +/* Struct definitions */ +typedef struct _Nfc_Empty { + char dummy_field; +} Nfc_Empty; + +typedef struct _Nfc_Main { + Nfc_CommandStatus command_status; + pb_callback_t cb_content; + pb_size_t which_content; + union { + Nfc_Empty empty; + PB_Nfca_ReadRequest nfca_read_req; + PB_Nfca_ReadResponse nfca_read_resp; + PB_MfUltralight_ReadPageRequest mf_ultralight_read_page_req; + PB_MfUltralight_ReadPageResponse mf_ultralight_read_page_resp; + PB_MfUltralight_ReadVersionRequest mf_ultralight_read_version_req; + PB_MfUltralight_ReadVersionResponse mf_ultralight_read_version_resp; + PB_MfUltralight_WritePageRequest mf_ultralight_write_page_req; + PB_MfUltralight_WritePageResponse mf_ultralight_write_page_resp; + PB_MfUltralight_ReadSignatureRequest mf_ultralight_read_signature_req; + PB_MfUltralight_ReadSignatureResponse mf_ultralight_read_signature_resp; + PB_MfUltralight_ReadCounterRequest mf_ultralight_read_counter_req; + PB_MfUltralight_ReadCounterResponse mf_ultralight_read_counter_resp; + PB_MfUltralight_ReadTearingFlagRequest mf_ultralight_read_tearing_flag_req; + PB_MfUltralight_ReadTearingFlagResponse mf_ultralight_read_tearing_flag_resp; + } content; +} Nfc_Main; + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Helper constants for enums */ +#define _Nfc_CommandStatus_MIN Nfc_CommandStatus_OK +#define _Nfc_CommandStatus_MAX Nfc_CommandStatus_ERROR_BUSY +#define _Nfc_CommandStatus_ARRAYSIZE ((Nfc_CommandStatus)(Nfc_CommandStatus_ERROR_BUSY+1)) + + +#define Nfc_Main_command_status_ENUMTYPE Nfc_CommandStatus + + +/* Initializer values for message structs */ +#define Nfc_Empty_init_default {0} +#define Nfc_Main_init_default {_Nfc_CommandStatus_MIN, {{NULL}, NULL}, 0, {Nfc_Empty_init_default}} +#define Nfc_Empty_init_zero {0} +#define Nfc_Main_init_zero {_Nfc_CommandStatus_MIN, {{NULL}, NULL}, 0, {Nfc_Empty_init_zero}} + +/* Field tags (for use in manual encoding/decoding) */ +#define Nfc_Main_command_status_tag 1 +#define Nfc_Main_empty_tag 2 +#define Nfc_Main_nfca_read_req_tag 3 +#define Nfc_Main_nfca_read_resp_tag 4 +#define Nfc_Main_mf_ultralight_read_page_req_tag 5 +#define Nfc_Main_mf_ultralight_read_page_resp_tag 6 +#define Nfc_Main_mf_ultralight_read_version_req_tag 7 +#define Nfc_Main_mf_ultralight_read_version_resp_tag 8 +#define Nfc_Main_mf_ultralight_write_page_req_tag 9 +#define Nfc_Main_mf_ultralight_write_page_resp_tag 10 +#define Nfc_Main_mf_ultralight_read_signature_req_tag 11 +#define Nfc_Main_mf_ultralight_read_signature_resp_tag 12 +#define Nfc_Main_mf_ultralight_read_counter_req_tag 13 +#define Nfc_Main_mf_ultralight_read_counter_resp_tag 14 +#define Nfc_Main_mf_ultralight_read_tearing_flag_req_tag 15 +#define Nfc_Main_mf_ultralight_read_tearing_flag_resp_tag 16 + +/* Struct field encoding specification for nanopb */ +#define Nfc_Empty_FIELDLIST(X, a) \ + +#define Nfc_Empty_CALLBACK NULL +#define Nfc_Empty_DEFAULT NULL + +#define Nfc_Main_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UENUM, command_status, 1) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,empty,content.empty), 2) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,nfca_read_req,content.nfca_read_req), 3) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,nfca_read_resp,content.nfca_read_resp), 4) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_page_req,content.mf_ultralight_read_page_req), 5) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_page_resp,content.mf_ultralight_read_page_resp), 6) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_version_req,content.mf_ultralight_read_version_req), 7) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_version_resp,content.mf_ultralight_read_version_resp), 8) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_write_page_req,content.mf_ultralight_write_page_req), 9) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_write_page_resp,content.mf_ultralight_write_page_resp), 10) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_signature_req,content.mf_ultralight_read_signature_req), 11) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_signature_resp,content.mf_ultralight_read_signature_resp), 12) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_counter_req,content.mf_ultralight_read_counter_req), 13) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_counter_resp,content.mf_ultralight_read_counter_resp), 14) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_tearing_flag_req,content.mf_ultralight_read_tearing_flag_req), 15) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_tearing_flag_resp,content.mf_ultralight_read_tearing_flag_resp), 16) +#define Nfc_Main_CALLBACK NULL +#define Nfc_Main_DEFAULT NULL +#define Nfc_Main_content_empty_MSGTYPE Nfc_Empty +#define Nfc_Main_content_nfca_read_req_MSGTYPE PB_Nfca_ReadRequest +#define Nfc_Main_content_nfca_read_resp_MSGTYPE PB_Nfca_ReadResponse +#define Nfc_Main_content_mf_ultralight_read_page_req_MSGTYPE PB_MfUltralight_ReadPageRequest +#define Nfc_Main_content_mf_ultralight_read_page_resp_MSGTYPE PB_MfUltralight_ReadPageResponse +#define Nfc_Main_content_mf_ultralight_read_version_req_MSGTYPE PB_MfUltralight_ReadVersionRequest +#define Nfc_Main_content_mf_ultralight_read_version_resp_MSGTYPE PB_MfUltralight_ReadVersionResponse +#define Nfc_Main_content_mf_ultralight_write_page_req_MSGTYPE PB_MfUltralight_WritePageRequest +#define Nfc_Main_content_mf_ultralight_write_page_resp_MSGTYPE PB_MfUltralight_WritePageResponse +#define Nfc_Main_content_mf_ultralight_read_signature_req_MSGTYPE PB_MfUltralight_ReadSignatureRequest +#define Nfc_Main_content_mf_ultralight_read_signature_resp_MSGTYPE PB_MfUltralight_ReadSignatureResponse +#define Nfc_Main_content_mf_ultralight_read_counter_req_MSGTYPE PB_MfUltralight_ReadCounterRequest +#define Nfc_Main_content_mf_ultralight_read_counter_resp_MSGTYPE PB_MfUltralight_ReadCounterResponse +#define Nfc_Main_content_mf_ultralight_read_tearing_flag_req_MSGTYPE PB_MfUltralight_ReadTearingFlagRequest +#define Nfc_Main_content_mf_ultralight_read_tearing_flag_resp_MSGTYPE PB_MfUltralight_ReadTearingFlagResponse + +extern const pb_msgdesc_t Nfc_Empty_msg; +extern const pb_msgdesc_t Nfc_Main_msg; + +/* Defines for backwards compatibility with code written before nanopb-0.4.0 */ +#define Nfc_Empty_fields &Nfc_Empty_msg +#define Nfc_Main_fields &Nfc_Main_msg + +/* Maximum encoded size of messages (where known) */ +#define Nfc_Empty_size 0 +#define Nfc_Main_size 54 + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/applications/main/nfc_rpc/assets/compiled/mf_ultralight.pb.c b/applications/main/nfc_rpc/assets/compiled/mf_ultralight.pb.c new file mode 100644 index 000000000000..1a8e0f1ae71f --- /dev/null +++ b/applications/main/nfc_rpc/assets/compiled/mf_ultralight.pb.c @@ -0,0 +1,46 @@ +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-0.4.8-dev */ + +#include "mf_ultralight.pb.h" +#if PB_PROTO_HEADER_VERSION != 40 +#error Regenerate this file with the current version of nanopb generator. +#endif + +PB_BIND(PB_MfUltralight_ReadPageRequest, PB_MfUltralight_ReadPageRequest, AUTO) + + +PB_BIND(PB_MfUltralight_ReadPageResponse, PB_MfUltralight_ReadPageResponse, AUTO) + + +PB_BIND(PB_MfUltralight_ReadVersionRequest, PB_MfUltralight_ReadVersionRequest, AUTO) + + +PB_BIND(PB_MfUltralight_ReadVersionResponse, PB_MfUltralight_ReadVersionResponse, AUTO) + + +PB_BIND(PB_MfUltralight_WritePageRequest, PB_MfUltralight_WritePageRequest, AUTO) + + +PB_BIND(PB_MfUltralight_WritePageResponse, PB_MfUltralight_WritePageResponse, AUTO) + + +PB_BIND(PB_MfUltralight_ReadSignatureRequest, PB_MfUltralight_ReadSignatureRequest, AUTO) + + +PB_BIND(PB_MfUltralight_ReadSignatureResponse, PB_MfUltralight_ReadSignatureResponse, AUTO) + + +PB_BIND(PB_MfUltralight_ReadCounterRequest, PB_MfUltralight_ReadCounterRequest, AUTO) + + +PB_BIND(PB_MfUltralight_ReadCounterResponse, PB_MfUltralight_ReadCounterResponse, AUTO) + + +PB_BIND(PB_MfUltralight_ReadTearingFlagRequest, PB_MfUltralight_ReadTearingFlagRequest, AUTO) + + +PB_BIND(PB_MfUltralight_ReadTearingFlagResponse, PB_MfUltralight_ReadTearingFlagResponse, AUTO) + + + + diff --git a/applications/main/nfc_rpc/assets/compiled/mf_ultralight.pb.h b/applications/main/nfc_rpc/assets/compiled/mf_ultralight.pb.h new file mode 100644 index 000000000000..6dc2673bac97 --- /dev/null +++ b/applications/main/nfc_rpc/assets/compiled/mf_ultralight.pb.h @@ -0,0 +1,299 @@ +/* Automatically generated nanopb header */ +/* Generated by nanopb-0.4.8-dev */ + +#ifndef PB_PB_MFULTRALIGHT_MF_ULTRALIGHT_PB_H_INCLUDED +#define PB_PB_MFULTRALIGHT_MF_ULTRALIGHT_PB_H_INCLUDED +#include + +#if PB_PROTO_HEADER_VERSION != 40 +#error Regenerate this file with the current version of nanopb generator. +#endif + +/* Enum definitions */ +typedef enum _PB_MfUltralight_Error { + PB_MfUltralight_Error_None = 0, + PB_MfUltralight_Error_NotPresent = 1, + PB_MfUltralight_Error_Protocol = 2, + PB_MfUltralight_Error_Auth = 3, + PB_MfUltralight_Error_Timeout = 4 +} PB_MfUltralight_Error; + +/* Struct definitions */ +typedef struct _PB_MfUltralight_ReadPageRequest { + uint16_t page; +} PB_MfUltralight_ReadPageRequest; + +typedef PB_BYTES_ARRAY_T(4) PB_MfUltralight_ReadPageResponse_data_t; +typedef struct _PB_MfUltralight_ReadPageResponse { + PB_MfUltralight_Error error; + uint16_t page; + PB_MfUltralight_ReadPageResponse_data_t data; +} PB_MfUltralight_ReadPageResponse; + +typedef struct _PB_MfUltralight_ReadVersionRequest { + char dummy_field; +} PB_MfUltralight_ReadVersionRequest; + +typedef struct _PB_MfUltralight_ReadVersionResponse { + PB_MfUltralight_Error error; + uint32_t header; + uint32_t vendor_id; + uint32_t prod_type; + uint32_t prod_subtype; + uint32_t prod_ver_major; + uint32_t prod_ver_minor; + uint32_t storage_size; + uint32_t protocol_type; +} PB_MfUltralight_ReadVersionResponse; + +typedef PB_BYTES_ARRAY_T(4) PB_MfUltralight_WritePageRequest_data_t; +typedef struct _PB_MfUltralight_WritePageRequest { + uint16_t page; + PB_MfUltralight_WritePageRequest_data_t data; +} PB_MfUltralight_WritePageRequest; + +typedef struct _PB_MfUltralight_WritePageResponse { + PB_MfUltralight_Error error; + bool result; +} PB_MfUltralight_WritePageResponse; + +typedef struct _PB_MfUltralight_ReadSignatureRequest { + char dummy_field; +} PB_MfUltralight_ReadSignatureRequest; + +typedef PB_BYTES_ARRAY_T(32) PB_MfUltralight_ReadSignatureResponse_data_t; +typedef struct _PB_MfUltralight_ReadSignatureResponse { + PB_MfUltralight_Error error; + PB_MfUltralight_ReadSignatureResponse_data_t data; +} PB_MfUltralight_ReadSignatureResponse; + +typedef struct _PB_MfUltralight_ReadCounterRequest { + uint32_t counter_num; +} PB_MfUltralight_ReadCounterRequest; + +typedef PB_BYTES_ARRAY_T(3) PB_MfUltralight_ReadCounterResponse_data_t; +typedef struct _PB_MfUltralight_ReadCounterResponse { + PB_MfUltralight_Error error; + uint32_t counter_num; + PB_MfUltralight_ReadCounterResponse_data_t data; +} PB_MfUltralight_ReadCounterResponse; + +typedef struct _PB_MfUltralight_ReadTearingFlagRequest { + uint32_t flag_num; +} PB_MfUltralight_ReadTearingFlagRequest; + +typedef PB_BYTES_ARRAY_T(1) PB_MfUltralight_ReadTearingFlagResponse_data_t; +typedef struct _PB_MfUltralight_ReadTearingFlagResponse { + PB_MfUltralight_Error error; + uint32_t flag_num; + PB_MfUltralight_ReadTearingFlagResponse_data_t data; +} PB_MfUltralight_ReadTearingFlagResponse; + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Helper constants for enums */ +#define _PB_MfUltralight_Error_MIN PB_MfUltralight_Error_None +#define _PB_MfUltralight_Error_MAX PB_MfUltralight_Error_Timeout +#define _PB_MfUltralight_Error_ARRAYSIZE ((PB_MfUltralight_Error)(PB_MfUltralight_Error_Timeout+1)) + + +#define PB_MfUltralight_ReadPageResponse_error_ENUMTYPE PB_MfUltralight_Error + + +#define PB_MfUltralight_ReadVersionResponse_error_ENUMTYPE PB_MfUltralight_Error + + +#define PB_MfUltralight_WritePageResponse_error_ENUMTYPE PB_MfUltralight_Error + + +#define PB_MfUltralight_ReadSignatureResponse_error_ENUMTYPE PB_MfUltralight_Error + + +#define PB_MfUltralight_ReadCounterResponse_error_ENUMTYPE PB_MfUltralight_Error + + +#define PB_MfUltralight_ReadTearingFlagResponse_error_ENUMTYPE PB_MfUltralight_Error + + +/* Initializer values for message structs */ +#define PB_MfUltralight_ReadPageRequest_init_default {0} +#define PB_MfUltralight_ReadPageResponse_init_default {_PB_MfUltralight_Error_MIN, 0, {0, {0}}} +#define PB_MfUltralight_ReadVersionRequest_init_default {0} +#define PB_MfUltralight_ReadVersionResponse_init_default {_PB_MfUltralight_Error_MIN, 0, 0, 0, 0, 0, 0, 0, 0} +#define PB_MfUltralight_WritePageRequest_init_default {0, {0, {0}}} +#define PB_MfUltralight_WritePageResponse_init_default {_PB_MfUltralight_Error_MIN, 0} +#define PB_MfUltralight_ReadSignatureRequest_init_default {0} +#define PB_MfUltralight_ReadSignatureResponse_init_default {_PB_MfUltralight_Error_MIN, {0, {0}}} +#define PB_MfUltralight_ReadCounterRequest_init_default {0} +#define PB_MfUltralight_ReadCounterResponse_init_default {_PB_MfUltralight_Error_MIN, 0, {0, {0}}} +#define PB_MfUltralight_ReadTearingFlagRequest_init_default {0} +#define PB_MfUltralight_ReadTearingFlagResponse_init_default {_PB_MfUltralight_Error_MIN, 0, {0, {0}}} +#define PB_MfUltralight_ReadPageRequest_init_zero {0} +#define PB_MfUltralight_ReadPageResponse_init_zero {_PB_MfUltralight_Error_MIN, 0, {0, {0}}} +#define PB_MfUltralight_ReadVersionRequest_init_zero {0} +#define PB_MfUltralight_ReadVersionResponse_init_zero {_PB_MfUltralight_Error_MIN, 0, 0, 0, 0, 0, 0, 0, 0} +#define PB_MfUltralight_WritePageRequest_init_zero {0, {0, {0}}} +#define PB_MfUltralight_WritePageResponse_init_zero {_PB_MfUltralight_Error_MIN, 0} +#define PB_MfUltralight_ReadSignatureRequest_init_zero {0} +#define PB_MfUltralight_ReadSignatureResponse_init_zero {_PB_MfUltralight_Error_MIN, {0, {0}}} +#define PB_MfUltralight_ReadCounterRequest_init_zero {0} +#define PB_MfUltralight_ReadCounterResponse_init_zero {_PB_MfUltralight_Error_MIN, 0, {0, {0}}} +#define PB_MfUltralight_ReadTearingFlagRequest_init_zero {0} +#define PB_MfUltralight_ReadTearingFlagResponse_init_zero {_PB_MfUltralight_Error_MIN, 0, {0, {0}}} + +/* Field tags (for use in manual encoding/decoding) */ +#define PB_MfUltralight_ReadPageRequest_page_tag 1 +#define PB_MfUltralight_ReadPageResponse_error_tag 1 +#define PB_MfUltralight_ReadPageResponse_page_tag 2 +#define PB_MfUltralight_ReadPageResponse_data_tag 3 +#define PB_MfUltralight_ReadVersionResponse_error_tag 1 +#define PB_MfUltralight_ReadVersionResponse_header_tag 2 +#define PB_MfUltralight_ReadVersionResponse_vendor_id_tag 3 +#define PB_MfUltralight_ReadVersionResponse_prod_type_tag 4 +#define PB_MfUltralight_ReadVersionResponse_prod_subtype_tag 5 +#define PB_MfUltralight_ReadVersionResponse_prod_ver_major_tag 6 +#define PB_MfUltralight_ReadVersionResponse_prod_ver_minor_tag 7 +#define PB_MfUltralight_ReadVersionResponse_storage_size_tag 8 +#define PB_MfUltralight_ReadVersionResponse_protocol_type_tag 9 +#define PB_MfUltralight_WritePageRequest_page_tag 1 +#define PB_MfUltralight_WritePageRequest_data_tag 2 +#define PB_MfUltralight_WritePageResponse_error_tag 1 +#define PB_MfUltralight_WritePageResponse_result_tag 2 +#define PB_MfUltralight_ReadSignatureResponse_error_tag 1 +#define PB_MfUltralight_ReadSignatureResponse_data_tag 2 +#define PB_MfUltralight_ReadCounterRequest_counter_num_tag 1 +#define PB_MfUltralight_ReadCounterResponse_error_tag 1 +#define PB_MfUltralight_ReadCounterResponse_counter_num_tag 2 +#define PB_MfUltralight_ReadCounterResponse_data_tag 3 +#define PB_MfUltralight_ReadTearingFlagRequest_flag_num_tag 1 +#define PB_MfUltralight_ReadTearingFlagResponse_error_tag 1 +#define PB_MfUltralight_ReadTearingFlagResponse_flag_num_tag 2 +#define PB_MfUltralight_ReadTearingFlagResponse_data_tag 3 + +/* Struct field encoding specification for nanopb */ +#define PB_MfUltralight_ReadPageRequest_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UINT32, page, 1) +#define PB_MfUltralight_ReadPageRequest_CALLBACK NULL +#define PB_MfUltralight_ReadPageRequest_DEFAULT NULL + +#define PB_MfUltralight_ReadPageResponse_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UENUM, error, 1) \ +X(a, STATIC, SINGULAR, UINT32, page, 2) \ +X(a, STATIC, SINGULAR, BYTES, data, 3) +#define PB_MfUltralight_ReadPageResponse_CALLBACK NULL +#define PB_MfUltralight_ReadPageResponse_DEFAULT NULL + +#define PB_MfUltralight_ReadVersionRequest_FIELDLIST(X, a) \ + +#define PB_MfUltralight_ReadVersionRequest_CALLBACK NULL +#define PB_MfUltralight_ReadVersionRequest_DEFAULT NULL + +#define PB_MfUltralight_ReadVersionResponse_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UENUM, error, 1) \ +X(a, STATIC, SINGULAR, UINT32, header, 2) \ +X(a, STATIC, SINGULAR, UINT32, vendor_id, 3) \ +X(a, STATIC, SINGULAR, UINT32, prod_type, 4) \ +X(a, STATIC, SINGULAR, UINT32, prod_subtype, 5) \ +X(a, STATIC, SINGULAR, UINT32, prod_ver_major, 6) \ +X(a, STATIC, SINGULAR, UINT32, prod_ver_minor, 7) \ +X(a, STATIC, SINGULAR, UINT32, storage_size, 8) \ +X(a, STATIC, SINGULAR, UINT32, protocol_type, 9) +#define PB_MfUltralight_ReadVersionResponse_CALLBACK NULL +#define PB_MfUltralight_ReadVersionResponse_DEFAULT NULL + +#define PB_MfUltralight_WritePageRequest_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UINT32, page, 1) \ +X(a, STATIC, SINGULAR, BYTES, data, 2) +#define PB_MfUltralight_WritePageRequest_CALLBACK NULL +#define PB_MfUltralight_WritePageRequest_DEFAULT NULL + +#define PB_MfUltralight_WritePageResponse_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UENUM, error, 1) \ +X(a, STATIC, SINGULAR, BOOL, result, 2) +#define PB_MfUltralight_WritePageResponse_CALLBACK NULL +#define PB_MfUltralight_WritePageResponse_DEFAULT NULL + +#define PB_MfUltralight_ReadSignatureRequest_FIELDLIST(X, a) \ + +#define PB_MfUltralight_ReadSignatureRequest_CALLBACK NULL +#define PB_MfUltralight_ReadSignatureRequest_DEFAULT NULL + +#define PB_MfUltralight_ReadSignatureResponse_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UENUM, error, 1) \ +X(a, STATIC, SINGULAR, BYTES, data, 2) +#define PB_MfUltralight_ReadSignatureResponse_CALLBACK NULL +#define PB_MfUltralight_ReadSignatureResponse_DEFAULT NULL + +#define PB_MfUltralight_ReadCounterRequest_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UINT32, counter_num, 1) +#define PB_MfUltralight_ReadCounterRequest_CALLBACK NULL +#define PB_MfUltralight_ReadCounterRequest_DEFAULT NULL + +#define PB_MfUltralight_ReadCounterResponse_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UENUM, error, 1) \ +X(a, STATIC, SINGULAR, UINT32, counter_num, 2) \ +X(a, STATIC, SINGULAR, BYTES, data, 3) +#define PB_MfUltralight_ReadCounterResponse_CALLBACK NULL +#define PB_MfUltralight_ReadCounterResponse_DEFAULT NULL + +#define PB_MfUltralight_ReadTearingFlagRequest_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UINT32, flag_num, 1) +#define PB_MfUltralight_ReadTearingFlagRequest_CALLBACK NULL +#define PB_MfUltralight_ReadTearingFlagRequest_DEFAULT NULL + +#define PB_MfUltralight_ReadTearingFlagResponse_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UENUM, error, 1) \ +X(a, STATIC, SINGULAR, UINT32, flag_num, 2) \ +X(a, STATIC, SINGULAR, BYTES, data, 3) +#define PB_MfUltralight_ReadTearingFlagResponse_CALLBACK NULL +#define PB_MfUltralight_ReadTearingFlagResponse_DEFAULT NULL + +extern const pb_msgdesc_t PB_MfUltralight_ReadPageRequest_msg; +extern const pb_msgdesc_t PB_MfUltralight_ReadPageResponse_msg; +extern const pb_msgdesc_t PB_MfUltralight_ReadVersionRequest_msg; +extern const pb_msgdesc_t PB_MfUltralight_ReadVersionResponse_msg; +extern const pb_msgdesc_t PB_MfUltralight_WritePageRequest_msg; +extern const pb_msgdesc_t PB_MfUltralight_WritePageResponse_msg; +extern const pb_msgdesc_t PB_MfUltralight_ReadSignatureRequest_msg; +extern const pb_msgdesc_t PB_MfUltralight_ReadSignatureResponse_msg; +extern const pb_msgdesc_t PB_MfUltralight_ReadCounterRequest_msg; +extern const pb_msgdesc_t PB_MfUltralight_ReadCounterResponse_msg; +extern const pb_msgdesc_t PB_MfUltralight_ReadTearingFlagRequest_msg; +extern const pb_msgdesc_t PB_MfUltralight_ReadTearingFlagResponse_msg; + +/* Defines for backwards compatibility with code written before nanopb-0.4.0 */ +#define PB_MfUltralight_ReadPageRequest_fields &PB_MfUltralight_ReadPageRequest_msg +#define PB_MfUltralight_ReadPageResponse_fields &PB_MfUltralight_ReadPageResponse_msg +#define PB_MfUltralight_ReadVersionRequest_fields &PB_MfUltralight_ReadVersionRequest_msg +#define PB_MfUltralight_ReadVersionResponse_fields &PB_MfUltralight_ReadVersionResponse_msg +#define PB_MfUltralight_WritePageRequest_fields &PB_MfUltralight_WritePageRequest_msg +#define PB_MfUltralight_WritePageResponse_fields &PB_MfUltralight_WritePageResponse_msg +#define PB_MfUltralight_ReadSignatureRequest_fields &PB_MfUltralight_ReadSignatureRequest_msg +#define PB_MfUltralight_ReadSignatureResponse_fields &PB_MfUltralight_ReadSignatureResponse_msg +#define PB_MfUltralight_ReadCounterRequest_fields &PB_MfUltralight_ReadCounterRequest_msg +#define PB_MfUltralight_ReadCounterResponse_fields &PB_MfUltralight_ReadCounterResponse_msg +#define PB_MfUltralight_ReadTearingFlagRequest_fields &PB_MfUltralight_ReadTearingFlagRequest_msg +#define PB_MfUltralight_ReadTearingFlagResponse_fields &PB_MfUltralight_ReadTearingFlagResponse_msg + +/* Maximum encoded size of messages (where known) */ +#define PB_MfUltralight_ReadCounterRequest_size 6 +#define PB_MfUltralight_ReadCounterResponse_size 13 +#define PB_MfUltralight_ReadPageRequest_size 4 +#define PB_MfUltralight_ReadPageResponse_size 12 +#define PB_MfUltralight_ReadSignatureRequest_size 0 +#define PB_MfUltralight_ReadSignatureResponse_size 36 +#define PB_MfUltralight_ReadTearingFlagRequest_size 6 +#define PB_MfUltralight_ReadTearingFlagResponse_size 11 +#define PB_MfUltralight_ReadVersionRequest_size 0 +#define PB_MfUltralight_ReadVersionResponse_size 50 +#define PB_MfUltralight_WritePageRequest_size 10 +#define PB_MfUltralight_WritePageResponse_size 4 + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/applications/main/nfc_rpc/assets/compiled/nfca.pb.c b/applications/main/nfc_rpc/assets/compiled/nfca.pb.c new file mode 100644 index 000000000000..076751611760 --- /dev/null +++ b/applications/main/nfc_rpc/assets/compiled/nfca.pb.c @@ -0,0 +1,16 @@ +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-0.4.8-dev */ + +#include "nfca.pb.h" +#if PB_PROTO_HEADER_VERSION != 40 +#error Regenerate this file with the current version of nanopb generator. +#endif + +PB_BIND(PB_Nfca_ReadRequest, PB_Nfca_ReadRequest, AUTO) + + +PB_BIND(PB_Nfca_ReadResponse, PB_Nfca_ReadResponse, AUTO) + + + + diff --git a/applications/main/nfc_rpc/assets/compiled/nfca.pb.h b/applications/main/nfc_rpc/assets/compiled/nfca.pb.h new file mode 100644 index 000000000000..a65a32218c29 --- /dev/null +++ b/applications/main/nfc_rpc/assets/compiled/nfca.pb.h @@ -0,0 +1,97 @@ +/* Automatically generated nanopb header */ +/* Generated by nanopb-0.4.8-dev */ + +#ifndef PB_PB_NFCA_NFCA_PB_H_INCLUDED +#define PB_PB_NFCA_NFCA_PB_H_INCLUDED +#include + +#if PB_PROTO_HEADER_VERSION != 40 +#error Regenerate this file with the current version of nanopb generator. +#endif + +/* Enum definitions */ +typedef enum _PB_Nfca_Error { + PB_Nfca_Error_None = 0, + PB_Nfca_Error_NotPresent = 1, + PB_Nfca_Error_ColResFailed = 2, + PB_Nfca_Error_BufferOverflow = 3, + PB_Nfca_Error_Communication = 4, + PB_Nfca_Error_FieldOff = 5, + PB_Nfca_Error_WrongCrc = 6, + PB_Nfca_Error_Timeout = 7 +} PB_Nfca_Error; + +/* Struct definitions */ +typedef struct _PB_Nfca_ReadRequest { + char dummy_field; +} PB_Nfca_ReadRequest; + +typedef PB_BYTES_ARRAY_T(10) PB_Nfca_ReadResponse_uid_t; +typedef PB_BYTES_ARRAY_T(1) PB_Nfca_ReadResponse_sak_t; +typedef PB_BYTES_ARRAY_T(2) PB_Nfca_ReadResponse_atqa_t; +typedef struct _PB_Nfca_ReadResponse { + PB_Nfca_Error error; + uint32_t uid_len; + PB_Nfca_ReadResponse_uid_t uid; + PB_Nfca_ReadResponse_sak_t sak; + PB_Nfca_ReadResponse_atqa_t atqa; +} PB_Nfca_ReadResponse; + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Helper constants for enums */ +#define _PB_Nfca_Error_MIN PB_Nfca_Error_None +#define _PB_Nfca_Error_MAX PB_Nfca_Error_Timeout +#define _PB_Nfca_Error_ARRAYSIZE ((PB_Nfca_Error)(PB_Nfca_Error_Timeout+1)) + + +#define PB_Nfca_ReadResponse_error_ENUMTYPE PB_Nfca_Error + + +/* Initializer values for message structs */ +#define PB_Nfca_ReadRequest_init_default {0} +#define PB_Nfca_ReadResponse_init_default {_PB_Nfca_Error_MIN, 0, {0, {0}}, {0, {0}}, {0, {0}}} +#define PB_Nfca_ReadRequest_init_zero {0} +#define PB_Nfca_ReadResponse_init_zero {_PB_Nfca_Error_MIN, 0, {0, {0}}, {0, {0}}, {0, {0}}} + +/* Field tags (for use in manual encoding/decoding) */ +#define PB_Nfca_ReadResponse_error_tag 1 +#define PB_Nfca_ReadResponse_uid_len_tag 2 +#define PB_Nfca_ReadResponse_uid_tag 3 +#define PB_Nfca_ReadResponse_sak_tag 4 +#define PB_Nfca_ReadResponse_atqa_tag 5 + +/* Struct field encoding specification for nanopb */ +#define PB_Nfca_ReadRequest_FIELDLIST(X, a) \ + +#define PB_Nfca_ReadRequest_CALLBACK NULL +#define PB_Nfca_ReadRequest_DEFAULT NULL + +#define PB_Nfca_ReadResponse_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UENUM, error, 1) \ +X(a, STATIC, SINGULAR, UINT32, uid_len, 2) \ +X(a, STATIC, SINGULAR, BYTES, uid, 3) \ +X(a, STATIC, SINGULAR, BYTES, sak, 4) \ +X(a, STATIC, SINGULAR, BYTES, atqa, 5) +#define PB_Nfca_ReadResponse_CALLBACK NULL +#define PB_Nfca_ReadResponse_DEFAULT NULL + +extern const pb_msgdesc_t PB_Nfca_ReadRequest_msg; +extern const pb_msgdesc_t PB_Nfca_ReadResponse_msg; + +/* Defines for backwards compatibility with code written before nanopb-0.4.0 */ +#define PB_Nfca_ReadRequest_fields &PB_Nfca_ReadRequest_msg +#define PB_Nfca_ReadResponse_fields &PB_Nfca_ReadResponse_msg + +/* Maximum encoded size of messages (where known) */ +#define PB_Nfca_ReadRequest_size 0 +#define PB_Nfca_ReadResponse_size 27 + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/applications/main/nfc_rpc/assets/protobuf/main.options b/applications/main/nfc_rpc/assets/protobuf/main.options new file mode 100644 index 000000000000..1a401050e8a2 --- /dev/null +++ b/applications/main/nfc_rpc/assets/protobuf/main.options @@ -0,0 +1 @@ +Nfc.Main submsg_callback:true \ No newline at end of file diff --git a/applications/main/nfc_rpc/assets/protobuf/main.proto b/applications/main/nfc_rpc/assets/protobuf/main.proto new file mode 100644 index 000000000000..5a12ff644f3f --- /dev/null +++ b/applications/main/nfc_rpc/assets/protobuf/main.proto @@ -0,0 +1,39 @@ +syntax = "proto3"; +import "nfca.proto"; +import "mf_ultralight.proto"; + +package Nfc; +option java_package = "com.flipperdevices.nfc.protobuf"; + +enum CommandStatus { + OK = 0; + + ERROR = 1; /**< Unknown error */ + ERROR_NOT_IMPLEMENTED = 3; /**< Command succesfully decoded, but not + implemented (deprecated or not yet implemented) */ + ERROR_BUSY = + 4; /**< Somebody took global lock, so not all commands are available */ +} + +message Empty {} + +message Main { + CommandStatus command_status = 1; + oneof content { + Empty empty = 2; + .PB_Nfca.ReadRequest nfca_read_req = 3; + .PB_Nfca.ReadResponse nfca_read_resp = 4; + .PB_MfUltralight.ReadPageRequest mf_ultralight_read_page_req = 5; + .PB_MfUltralight.ReadPageResponse mf_ultralight_read_page_resp = 6; + .PB_MfUltralight.ReadVersionRequest mf_ultralight_read_version_req = 7; + .PB_MfUltralight.ReadVersionResponse mf_ultralight_read_version_resp = 8; + .PB_MfUltralight.WritePageRequest mf_ultralight_write_page_req = 9; + .PB_MfUltralight.WritePageResponse mf_ultralight_write_page_resp = 10; + .PB_MfUltralight.ReadSignatureRequest mf_ultralight_read_signature_req = 11; + .PB_MfUltralight.ReadSignatureResponse mf_ultralight_read_signature_resp = 12; + .PB_MfUltralight.ReadCounterRequest mf_ultralight_read_counter_req = 13; + .PB_MfUltralight.ReadCounterResponse mf_ultralight_read_counter_resp = 14; + .PB_MfUltralight.ReadTearingFlagRequest mf_ultralight_read_tearing_flag_req = 15; + .PB_MfUltralight.ReadTearingFlagResponse mf_ultralight_read_tearing_flag_resp = 16; + } +} diff --git a/applications/main/nfc_rpc/assets/protobuf/mf_ultralight.options b/applications/main/nfc_rpc/assets/protobuf/mf_ultralight.options new file mode 100644 index 000000000000..97e52c0cd345 --- /dev/null +++ b/applications/main/nfc_rpc/assets/protobuf/mf_ultralight.options @@ -0,0 +1,8 @@ +PB_MfUltralight.ReadPageRequest.page int_size:IS_16 +PB_MfUltralight.ReadPageResponse.page int_size:IS_16 +PB_MfUltralight.ReadPageResponse.data max_size: 4 +PB_MfUltralight.WritePageRequest.page int_size:IS_16 +PB_MfUltralight.WritePageRequest.data max_size: 4 +PB_MfUltralight.ReadSignatureResponse.data max_size: 32 +PB_MfUltralight.ReadCounterResponse.data max_size: 3 +PB_MfUltralight.ReadTearingFlagResponse.data max_size: 1 diff --git a/applications/main/nfc_rpc/assets/protobuf/mf_ultralight.proto b/applications/main/nfc_rpc/assets/protobuf/mf_ultralight.proto new file mode 100644 index 000000000000..f333fc1b06bd --- /dev/null +++ b/applications/main/nfc_rpc/assets/protobuf/mf_ultralight.proto @@ -0,0 +1,67 @@ +syntax = "proto3"; + +package PB_MfUltralight; +option java_package = "com.flipperdevices.nfc.protobuf"; + +enum Error { + None = 0; + NotPresent = 1; + Protocol = 2; + Auth = 3; + Timeout = 4; +} + +message ReadPageRequest { uint32 page = 1; } + +message ReadPageResponse { + Error error = 1; + uint32 page = 2; + bytes data = 3; +} + +message ReadVersionRequest {} + +message ReadVersionResponse { + Error error = 1; + uint32 header = 2; + uint32 vendor_id = 3; + uint32 prod_type = 4; + uint32 prod_subtype = 5; + uint32 prod_ver_major = 6; + uint32 prod_ver_minor = 7; + uint32 storage_size = 8; + uint32 protocol_type = 9; +} + +message WritePageRequest { + uint32 page = 1; + bytes data = 2; +} + +message WritePageResponse { + Error error = 1; + bool result = 2; +} + +message ReadSignatureRequest {} + +message ReadSignatureResponse { + Error error = 1; + bytes data = 2; +} + +message ReadCounterRequest { uint32 counter_num = 1; } + +message ReadCounterResponse { + Error error = 1; + uint32 counter_num = 2; + bytes data = 3; +} + +message ReadTearingFlagRequest { uint32 flag_num = 1; } + +message ReadTearingFlagResponse { + Error error = 1; + uint32 flag_num = 2; + bytes data = 3; +} diff --git a/applications/main/nfc_rpc/assets/protobuf/nfca.options b/applications/main/nfc_rpc/assets/protobuf/nfca.options new file mode 100644 index 000000000000..582beb50ae4e --- /dev/null +++ b/applications/main/nfc_rpc/assets/protobuf/nfca.options @@ -0,0 +1,3 @@ +PB_Nfca.ReadResponse.uid max_size: 10 +PB_Nfca.ReadResponse.sak max_size: 1 +PB_Nfca.ReadResponse.atqa max_size: 2 \ No newline at end of file diff --git a/applications/main/nfc_rpc/assets/protobuf/nfca.proto b/applications/main/nfc_rpc/assets/protobuf/nfca.proto new file mode 100644 index 000000000000..183eae0b106b --- /dev/null +++ b/applications/main/nfc_rpc/assets/protobuf/nfca.proto @@ -0,0 +1,25 @@ +syntax = "proto3"; + +package PB_Nfca; +option java_package = "com.flipperdevices.nfc.protobuf"; + +enum Error { + None = 0; + NotPresent = 1; + ColResFailed = 2; + BufferOverflow = 3; + Communication = 4; + FieldOff = 5; + WrongCrc = 6; + Timeout = 7; +} + +message ReadRequest {} + +message ReadResponse { + Error error = 1; + uint32 uid_len = 2; + bytes uid = 3; + bytes sak = 4; + bytes atqa = 5; +} \ No newline at end of file diff --git a/applications/main/nfc_rpc/nfc_rpc.c b/applications/main/nfc_rpc/nfc_rpc.c new file mode 100644 index 000000000000..a1f01d2b654f --- /dev/null +++ b/applications/main/nfc_rpc/nfc_rpc.c @@ -0,0 +1,249 @@ +#include "nfc_rpc_i.h" +#include +#include + +#include "assets/compiled/main.pb.h" + +#define TAG "NfcRpc" + +DICT_DEF2(NfcRpcHandlerDict, pb_size_t, M_DEFAULT_OPLIST, NfcRpcHandler, M_POD_OPLIST) + +typedef void (*NfcRpcHandlersAlloc)(void* context); +typedef void (*NfcRpcHandlersFree)(void* context); + +typedef enum { + NfcRpcViewMain, +} NfcRpcView; + +typedef enum { + NfcRpcCustomEventMessageReceived, +} NfcRpcCustomEvent; + +typedef enum { + NfcRpcEventDataExchange, +} NfcRpcEventType; + +typedef struct { + NfcRpcEventType type; + const uint8_t* data; + size_t data_size; +} NfcRpcEvent; + +struct NfcRpc { + Gui* gui; + RpcAppSystem* rpc; + FuriMessageQueue* queue; + ViewDispatcher* view_dispatcher; + View* view; + + NfcRpcHandlerDict_t handlers; +}; + +typedef struct { + NfcRpcHandlersAlloc alloc; + NfcRpcHandlersFree free; +} NfcRpcCallbacks; + +static const NfcRpcCallbacks nfc_rpc_callbacks[] = { + { + .alloc = nfc_rpc_nfca_alloc, + .free = NULL, + }, + { + .alloc = nfc_rpc_mf_ultralight_alloc, + .free = NULL, + }, +}; + +uint32_t nfc_rpc_exit_callback(void* context) { + UNUSED(context); + return VIEW_NONE; +} + +void nfc_rpc_draw_callback(Canvas* canvas, void* context) { + UNUSED(context); + canvas_clear(canvas); + canvas_set_color(canvas, ColorBlack); + canvas_set_font(canvas, FontPrimary); + canvas_draw_str(canvas, 32, 0, "NFC RPC Actor running..."); +} + +bool nfc_rpc_input_callback(InputEvent* event, void* context) { + UNUSED(context); + UNUSED(event); + return false; +} + +static void + nfc_rpc_receive_data_exchange_callback(const uint8_t* data, size_t data_size, void* context) { + NfcRpc* app = context; + NfcRpcEvent event; + FURI_LOG_I(TAG, "Received %d bytes", data_size); + event.type = NfcRpcEventDataExchange; + event.data = data; + event.data_size = data_size; + furi_message_queue_put(app->queue, &event, FuriWaitForever); + view_dispatcher_send_custom_event(app->view_dispatcher, NfcRpcCustomEventMessageReceived); +} + +static void nfc_rpc_rpc_command_callback(RpcAppSystemEvent event, void* context) { + furi_assert(context); + NfcRpc* app = context; + + if(event == RpcAppEventSessionClose) { + rpc_system_app_set_callback(app->rpc, NULL, NULL); + rpc_system_app_set_data_exchange_callback(app->rpc, NULL, NULL); + view_dispatcher_switch_to_view(app->view_dispatcher, VIEW_NONE); + view_dispatcher_stop(app->view_dispatcher); + app->rpc = NULL; + } + if(event == RpcAppEventAppExit) { + view_dispatcher_switch_to_view(app->view_dispatcher, VIEW_NONE); + view_dispatcher_stop(app->view_dispatcher); + rpc_system_app_confirm(app->rpc, RpcAppEventAppExit, true); + } +} + +static bool nfc_rpc_init_rpc(NfcRpc* app, const char* args) { + bool ret = false; + if(args && strlen(args)) { + uint32_t rpc = 0; + if(sscanf(args, "RPC %lX", &rpc) == 1) { + app->rpc = (RpcAppSystem*)rpc; + rpc_system_app_set_callback(app->rpc, nfc_rpc_rpc_command_callback, app); + rpc_system_app_send_started(app->rpc); + ret = true; + } + } + return ret; +} + +void nfc_rpc_add_handler(NfcRpc* instance, pb_size_t message_tag, NfcRpcHandler handler) { + furi_assert(instance); + furi_assert(instance->handlers); + furi_assert(handler); + furi_assert(NfcRpcHandlerDict_get(instance->handlers, message_tag) == NULL); + + NfcRpcHandlerDict_set_at(instance->handlers, message_tag, handler); +} + +static void nfc_rpc_message_receive_handler(NfcRpc* instance) { + furi_assert(instance); + furi_assert(instance->queue); + furi_assert(instance->rpc); + NfcRpcEvent event; + pb_istream_t istream; + pb_ostream_t ostream; + uint8_t response_buffer[512] = {}; + + if(furi_message_queue_get(instance->queue, &event, FuriWaitForever) == FuriStatusOk) { + Nfc_Main cmd = Nfc_Main_init_default; + istream = pb_istream_from_buffer(event.data, event.data_size); + if(pb_decode(&istream, Nfc_Main_fields, &cmd)) { + FURI_LOG_I(TAG, "Which: %d", cmd.which_content); + NfcRpcHandler handler = *NfcRpcHandlerDict_get(instance->handlers, cmd.which_content); + if(handler) { + handler(&cmd, instance); + } else { + cmd.command_status = Nfc_CommandStatus_ERROR_NOT_IMPLEMENTED; + } + ostream = pb_ostream_from_buffer(response_buffer, sizeof(response_buffer)); + pb_encode(&ostream, Nfc_Main_fields, &cmd); + FURI_LOG_D("NfcRpc", "Sending %d bytes", ostream.bytes_written); + rpc_system_app_exchange_data(instance->rpc, response_buffer, ostream.bytes_written); + } else { + FURI_LOG_E(TAG, "Failed to decode message: %s", istream.errmsg); + Nfc_Main cmd = Nfc_Main_init_default; + cmd.command_status = Nfc_CommandStatus_ERROR; + ostream = pb_ostream_from_buffer(response_buffer, sizeof(response_buffer)); + pb_encode(&ostream, Nfc_Main_fields, &cmd); + rpc_system_app_exchange_data(instance->rpc, response_buffer, ostream.bytes_written); + } + } +} + +bool nfc_rpc_custom_event_callback(void* context, uint32_t event) { + NfcRpc* instance = context; + if(event == NfcRpcCustomEventMessageReceived) { + nfc_rpc_message_receive_handler(instance); + } + + return true; +} + +static NfcRpc* nfc_rpc_app_alloc() { + NfcRpc* instance = malloc(sizeof(NfcRpc)); + + NfcRpcHandlerDict_init(instance->handlers); + for(size_t i = 0; i < COUNT_OF(nfc_rpc_callbacks); i++) { + if(nfc_rpc_callbacks[i].alloc) { + nfc_rpc_callbacks[i].alloc(instance); + } + } + + instance->gui = furi_record_open(RECORD_GUI); + instance->view_dispatcher = view_dispatcher_alloc(); + instance->view = view_alloc(); + + view_set_previous_callback(instance->view, nfc_rpc_exit_callback); + view_set_input_callback(instance->view, nfc_rpc_input_callback); + view_set_context(instance->view, instance); + view_set_draw_callback(instance->view, nfc_rpc_draw_callback); + + view_dispatcher_enable_queue(instance->view_dispatcher); + view_dispatcher_attach_to_gui( + instance->view_dispatcher, instance->gui, ViewDispatcherTypeFullscreen); + view_dispatcher_add_view(instance->view_dispatcher, NfcRpcViewMain, instance->view); + + view_dispatcher_set_event_callback_context(instance->view_dispatcher, instance); + view_dispatcher_set_custom_event_callback( + instance->view_dispatcher, nfc_rpc_custom_event_callback); + + instance->queue = furi_message_queue_alloc(8, sizeof(NfcRpcEvent)); + + return instance; +} + +void nfc_rpc_app_free(NfcRpc* instance) { + furi_assert(instance); + + for(size_t i = 0; i < COUNT_OF(nfc_rpc_callbacks); i++) { + if(nfc_rpc_callbacks[i].free) { + nfc_rpc_callbacks[i].free(instance); + } + } + NfcRpcHandlerDict_clear(instance->handlers); + + view_dispatcher_remove_view(instance->view_dispatcher, NfcRpcViewMain); + view_free(instance->view); + view_dispatcher_free(instance->view_dispatcher); + furi_message_queue_free(instance->queue); + furi_record_close(RECORD_GUI); + instance->gui = NULL; + instance->view_dispatcher = NULL; + + if(instance->rpc) { + rpc_system_app_set_callback(instance->rpc, NULL, NULL); + rpc_system_app_send_exited(instance->rpc); + instance->rpc = NULL; + } + + free(instance); +} + +int32_t nfc_rpc_app(void* p) { + UNUSED(p); + NfcRpc* app = nfc_rpc_app_alloc(); + + nfc_rpc_init_rpc(app, p); + + rpc_system_app_set_data_exchange_callback( + app->rpc, nfc_rpc_receive_data_exchange_callback, app); + + view_dispatcher_switch_to_view(app->view_dispatcher, NfcRpcViewMain); + view_dispatcher_run(app->view_dispatcher); + + nfc_rpc_app_free(app); + + return 0; +} diff --git a/applications/main/nfc_rpc/nfc_rpc.h b/applications/main/nfc_rpc/nfc_rpc.h new file mode 100644 index 000000000000..39969837eff6 --- /dev/null +++ b/applications/main/nfc_rpc/nfc_rpc.h @@ -0,0 +1,3 @@ +#pragma once + +typedef struct NfcRpc NfcRpc; diff --git a/applications/main/nfc_rpc/nfc_rpc_i.h b/applications/main/nfc_rpc/nfc_rpc_i.h new file mode 100644 index 000000000000..aa7e94293855 --- /dev/null +++ b/applications/main/nfc_rpc/nfc_rpc_i.h @@ -0,0 +1,22 @@ +#pragma once + +#include "nfc_rpc.h" + +#include "furi.h" +#include "furi_hal.h" +#include +#include +#include +#include + +#include +#include + +#include "assets/compiled/main.pb.h" + +typedef void (*NfcRpcHandler)(Nfc_Main* cmd, void* context); + +void nfc_rpc_add_handler(NfcRpc* instance, pb_size_t message_tag, NfcRpcHandler handler); + +void nfc_rpc_nfca_alloc(void* context); +void nfc_rpc_mf_ultralight_alloc(void* context); diff --git a/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c b/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c new file mode 100644 index 000000000000..531566e4553e --- /dev/null +++ b/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c @@ -0,0 +1,208 @@ +#include "nfc_rpc_i.h" + +#include "assets/compiled/mf_ultralight.pb.h" +#include + +#define TAG "NfcRpcMfUltralight" + +static PB_MfUltralight_Error nfc_rpc_mf_ultralight_process_error(MfUltralightError error) { + PB_MfUltralight_Error ret = PB_MfUltralight_Error_None; + + switch(error) { + case MfUltralightErrorNone: + ret = PB_MfUltralight_Error_None; + break; + case MfUltralightErrorNotPresent: + ret = PB_MfUltralight_Error_NotPresent; + break; + case MfUltralightErrorProtocol: + ret = PB_MfUltralight_Error_Protocol; + break; + case MfUltralightErrorAuth: + ret = PB_MfUltralight_Error_Auth; + break; + case MfUltralightErrorTimeout: + ret = PB_MfUltralight_Error_Timeout; + break; + + default: + ret = PB_MfUltralight_Error_Timeout; + break; + } + + return ret; +} + +static void nfc_rpc_mf_ultralight_read_page(Nfc_Main* cmd, void* context) { + furi_assert(cmd); + furi_assert(context); + PB_MfUltralight_ReadPageResponse pb_mf_ul_read_page_resp = + PB_MfUltralight_ReadPageResponse_init_default; + + MfUltralightPoller* poller = mf_ultralight_poller_alloc(); + MfUltralightPage page = {}; + MfUltralightError error = mf_ultralight_poller_read_page( + poller, cmd->content.mf_ultralight_read_page_req.page, &page); + + cmd->command_status = Nfc_CommandStatus_OK; + cmd->which_content = Nfc_Main_mf_ultralight_read_page_resp_tag; + pb_mf_ul_read_page_resp.error = nfc_rpc_mf_ultralight_process_error(error); + if(pb_mf_ul_read_page_resp.error == PB_MfUltralight_Error_None) { + pb_mf_ul_read_page_resp.page = cmd->content.mf_ultralight_read_page_req.page; + memcpy(pb_mf_ul_read_page_resp.data.bytes, &page, sizeof(MfUltralightPage)); + pb_mf_ul_read_page_resp.data.size = sizeof(MfUltralightPage); + } + cmd->content.mf_ultralight_read_page_resp = pb_mf_ul_read_page_resp; + + mf_ultralight_poller_free(poller); +} + +static void nfc_rpc_mf_ultralight_write_page(Nfc_Main* cmd, void* context) { + furi_assert(cmd); + furi_assert(context); + PB_MfUltralight_WritePageResponse pb_mf_ul_write_page_resp = + PB_MfUltralight_WritePageResponse_init_default; + + MfUltralightPoller* poller = mf_ultralight_poller_alloc(); + MfUltralightPage data = {}; + memcpy(&data, cmd->content.mf_ultralight_write_page_req.data.bytes, sizeof(MfUltralightPage)); + uint16_t page = cmd->content.mf_ultralight_write_page_req.page; + MfUltralightError error = mf_ultralight_poller_write_page(poller, page, &data); + + cmd->which_content = Nfc_Main_mf_ultralight_write_page_resp_tag; + cmd->command_status = Nfc_CommandStatus_OK; + pb_mf_ul_write_page_resp.error = nfc_rpc_mf_ultralight_process_error(error); + cmd->content.mf_ultralight_write_page_resp = pb_mf_ul_write_page_resp; + + mf_ultralight_poller_free(poller); +} + +static void nfc_rpc_mf_ultralight_read_version(Nfc_Main* cmd, void* context) { + furi_assert(cmd); + furi_assert(context); + PB_MfUltralight_ReadVersionResponse pb_mf_ul_version = + PB_MfUltralight_ReadVersionResponse_init_default; + + MfUltralightPoller* poller = mf_ultralight_poller_alloc(); + MfUltralightVersion data = {}; + MfUltralightError error = mf_ultralight_poller_read_version(poller, &data); + + cmd->command_status = Nfc_CommandStatus_OK; + cmd->which_content = Nfc_Main_mf_ultralight_read_version_resp_tag; + pb_mf_ul_version.error = nfc_rpc_mf_ultralight_process_error(error); + if(pb_mf_ul_version.error == PB_MfUltralight_Error_None) { + pb_mf_ul_version.header = data.header; + pb_mf_ul_version.prod_subtype = data.prod_subtype; + pb_mf_ul_version.prod_type = data.prod_type; + pb_mf_ul_version.prod_ver_major = data.prod_ver_major; + pb_mf_ul_version.prod_ver_minor = data.prod_ver_minor; + pb_mf_ul_version.protocol_type = data.protocol_type; + pb_mf_ul_version.storage_size = data.storage_size; + pb_mf_ul_version.vendor_id = data.vendor_id; + } + cmd->content.mf_ultralight_read_version_resp = pb_mf_ul_version; + + mf_ultralight_poller_free(poller); +} + +static void nfc_rpc_mf_ultralight_read_signature(Nfc_Main* cmd, void* context) { + furi_assert(cmd); + furi_assert(context); + PB_MfUltralight_ReadSignatureResponse pb_mf_ul_signature = + PB_MfUltralight_ReadSignatureResponse_init_default; + + MfUltralightPoller* poller = mf_ultralight_poller_alloc(); + MfUltralightSignature data = {}; + MfUltralightError error = mf_ultralight_poller_read_signature(poller, &data); + + cmd->command_status = Nfc_CommandStatus_OK; + cmd->which_content = Nfc_Main_mf_ultralight_read_signature_resp_tag; + pb_mf_ul_signature.error = nfc_rpc_mf_ultralight_process_error(error); + if(pb_mf_ul_signature.error == PB_MfUltralight_Error_None) { + memcpy(pb_mf_ul_signature.data.bytes, data.data, sizeof(MfUltralightSignature)); + pb_mf_ul_signature.data.size = sizeof(MfUltralightSignature); + } + cmd->content.mf_ultralight_read_signature_resp = pb_mf_ul_signature; + + mf_ultralight_poller_free(poller); +} + +static void nfc_rpc_mf_ultralight_read_counter(Nfc_Main* cmd, void* context) { + furi_assert(cmd); + furi_assert(context); + PB_MfUltralight_ReadCounterResponse pb_mf_ul_read_counter_resp = + PB_MfUltralight_ReadPageResponse_init_default; + + MfUltralightPoller* poller = mf_ultralight_poller_alloc(); + MfUltralightCounter data = {}; + MfUltralightError error = mf_ultralight_poller_read_counter( + poller, cmd->content.mf_ultralight_read_counter_req.counter_num, &data); + + cmd->command_status = Nfc_CommandStatus_OK; + cmd->which_content = Nfc_Main_mf_ultralight_read_counter_resp_tag; + pb_mf_ul_read_counter_resp.error = nfc_rpc_mf_ultralight_process_error(error); + if(pb_mf_ul_read_counter_resp.error == PB_MfUltralight_Error_None) { + pb_mf_ul_read_counter_resp.counter_num = + cmd->content.mf_ultralight_read_counter_req.counter_num; + memcpy(pb_mf_ul_read_counter_resp.data.bytes, data.data, sizeof(MfUltralightCounter)); + pb_mf_ul_read_counter_resp.data.size = sizeof(MfUltralightCounter); + } + cmd->content.mf_ultralight_read_counter_resp = pb_mf_ul_read_counter_resp; + + mf_ultralight_poller_free(poller); +} + +static void nfc_rpc_mf_ultralight_read_tearing_flag(Nfc_Main* cmd, void* context) { + furi_assert(cmd); + furi_assert(context); + PB_MfUltralight_ReadTearingFlagResponse pb_mf_ul_read_tearing_flag_resp = + PB_MfUltralight_ReadTearingFlagResponse_init_default; + + MfUltralightPoller* poller = mf_ultralight_poller_alloc(); + MfUltralightTearingFlag data = {}; + MfUltralightError error = mf_ultralight_poller_read_tearing_flag( + poller, cmd->content.mf_ultralight_read_tearing_flag_req.flag_num, &data); + + cmd->command_status = Nfc_CommandStatus_OK; + cmd->which_content = Nfc_Main_mf_ultralight_read_tearing_flag_resp_tag; + pb_mf_ul_read_tearing_flag_resp.error = nfc_rpc_mf_ultralight_process_error(error); + if(pb_mf_ul_read_tearing_flag_resp.error == PB_MfUltralight_Error_None) { + pb_mf_ul_read_tearing_flag_resp.flag_num = + cmd->content.mf_ultralight_read_tearing_flag_req.flag_num; + memcpy( + pb_mf_ul_read_tearing_flag_resp.data.bytes, + data.data, + sizeof(MfUltralightTearingFlag)); + pb_mf_ul_read_tearing_flag_resp.data.size = sizeof(MfUltralightTearingFlag); + } + cmd->content.mf_ultralight_read_tearing_flag_resp = pb_mf_ul_read_tearing_flag_resp; + FURI_LOG_D( + TAG, + "Tearing flag %ld: %02X", + pb_mf_ul_read_tearing_flag_resp.flag_num, + data.data[0]); + + mf_ultralight_poller_free(poller); +} + +void nfc_rpc_mf_ultralight_alloc(void* context) { + furi_assert(context); + + NfcRpc* instance = context; + nfc_rpc_add_handler( + instance, Nfc_Main_mf_ultralight_read_page_req_tag, nfc_rpc_mf_ultralight_read_page); + nfc_rpc_add_handler( + instance, Nfc_Main_mf_ultralight_read_version_req_tag, nfc_rpc_mf_ultralight_read_version); + nfc_rpc_add_handler( + instance, Nfc_Main_mf_ultralight_write_page_req_tag, nfc_rpc_mf_ultralight_write_page); + nfc_rpc_add_handler( + instance, + Nfc_Main_mf_ultralight_read_signature_req_tag, + nfc_rpc_mf_ultralight_read_signature); + nfc_rpc_add_handler( + instance, Nfc_Main_mf_ultralight_read_counter_req_tag, nfc_rpc_mf_ultralight_read_counter); + nfc_rpc_add_handler( + instance, + Nfc_Main_mf_ultralight_read_tearing_flag_req_tag, + nfc_rpc_mf_ultralight_read_tearing_flag); +} diff --git a/applications/main/nfc_rpc/nfc_rpc_nfca.c b/applications/main/nfc_rpc/nfc_rpc_nfca.c new file mode 100644 index 000000000000..6dd232f893ac --- /dev/null +++ b/applications/main/nfc_rpc/nfc_rpc_nfca.c @@ -0,0 +1,75 @@ +#include "nfc_rpc_i.h" + +#include "assets/compiled/nfca.pb.h" +#include + +#define TAG "NfcRpcNfca" + +static PB_Nfca_Error nfc_rpc_nfca_process_error(NfcaError error) { + PB_Nfca_Error ret = PB_Nfca_Error_None; + switch(error) { + case NfcaErrorNone: + ret = PB_Nfca_Error_None; + break; + case NfcaErrorNotPresent: + ret = PB_Nfca_Error_NotPresent; + break; + case NfcaErrorColResFailed: + ret = PB_Nfca_Error_ColResFailed; + break; + case NfcaErrorBufferOverflow: + ret = PB_Nfca_Error_BufferOverflow; + break; + case NfcaErrorCommunication: + ret = PB_Nfca_Error_Communication; + break; + case NfcaErrorFieldOff: + ret = PB_Nfca_Error_FieldOff; + break; + case NfcaErrorWrongCrc: + ret = PB_Nfca_Error_WrongCrc; + break; + case NfcaErrorTimeout: + ret = PB_Nfca_Error_Timeout; + break; + + default: + ret = PB_Nfca_Error_Timeout; + break; + } + + return ret; +} + +static void nfc_rpc_nfca_read(Nfc_Main* cmd, void* context) { + furi_assert(cmd); + furi_assert(context); + PB_Nfca_ReadResponse pb_nfca_read_resp = PB_Nfca_ReadResponse_init_default; + + NfcaData nfca_data = {}; + NfcaPoller* nfca_poller = nfca_poller_alloc(); + NfcaError error = nfca_poller_activate(nfca_poller, &nfca_data); + + cmd->command_status = Nfc_CommandStatus_OK; + cmd->which_content = Nfc_Main_nfca_read_resp_tag; + pb_nfca_read_resp.error = nfc_rpc_nfca_process_error(error); + if(pb_nfca_read_resp.error == PB_Nfca_Error_None) { + pb_nfca_read_resp.uid_len = nfca_data.uid_len; + memcpy(pb_nfca_read_resp.uid.bytes, nfca_data.uid, nfca_data.uid_len); + pb_nfca_read_resp.uid.size = nfca_data.uid_len; + memcpy(pb_nfca_read_resp.sak.bytes, &nfca_data.sak, sizeof(nfca_data.sak)); + pb_nfca_read_resp.sak.size = sizeof(nfca_data.sak); + memcpy(pb_nfca_read_resp.atqa.bytes, nfca_data.atqa, sizeof(nfca_data.atqa)); + pb_nfca_read_resp.atqa.size = sizeof(nfca_data.atqa); + } + cmd->content.nfca_read_resp = pb_nfca_read_resp; + + nfca_poller_free(nfca_poller); +} + +void nfc_rpc_nfca_alloc(void* context) { + furi_assert(context); + + NfcRpc* instance = context; + nfc_rpc_add_handler(instance, Nfc_Main_nfca_read_req_tag, nfc_rpc_nfca_read); +} From 0c5fab4ba4d44859ed9f6ddfe4a3366aaaaf86e4 Mon Sep 17 00:00:00 2001 From: gornekich Date: Thu, 23 Mar 2023 16:43:48 +0400 Subject: [PATCH 005/149] subghz: temporary build fix --- lib/subghz/protocols/bin_raw.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/subghz/protocols/bin_raw.c b/lib/subghz/protocols/bin_raw.c index 123a4ba9d31f..717d7a0c9aa5 100644 --- a/lib/subghz/protocols/bin_raw.c +++ b/lib/subghz/protocols/bin_raw.c @@ -9,6 +9,8 @@ #include #include +#include + #define TAG "SubGhzProtocolBinRAW" //change very carefully, RAM ends at the most inopportune moment From af4857e0bebbdd887c46db5848a379361f4a3770 Mon Sep 17 00:00:00 2001 From: gornekich Date: Fri, 24 Mar 2023 14:52:05 +0400 Subject: [PATCH 006/149] nfc: fix timings --- lib/nfc/nfc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/nfc/nfc.c b/lib/nfc/nfc.c index cf2e13d01269..c15437d43eb2 100644 --- a/lib/nfc/nfc.c +++ b/lib/nfc/nfc.c @@ -207,7 +207,7 @@ static NfcError nfc_poller_prepare_trx(Nfc* instance) { error = f_hal_nfc_poller_field_on(); if(error != FHalNfcErrorNone) break; instance->state = NfcStateFieldOn; - if(instance->fdt_poll_poll_us) { + if(instance->guard_time_us) { f_hal_nfc_timer_block_tx_start_us(instance->guard_time_us); instance->comm_state = NfcCommStateWaitBlockTxTimer; event = f_hal_nfc_wait_event(F_HAL_NFC_EVENT_WAIT_FOREVER); From 0d97f4df3766d95f1b0ef92a8424abb294b1b216 Mon Sep 17 00:00:00 2001 From: gornekich Date: Tue, 28 Mar 2023 14:03:03 +0400 Subject: [PATCH 007/149] nfc: fix listener events --- applications/main/nfc/nfc_cli.c | 12 +++++++----- firmware/targets/f7/furi_hal/f_hal_nfc.c | 7 ++++--- lib/drivers/st25r3916.c | 4 ++++ lib/nfc/nfc.c | 23 ++++++++++++++--------- 4 files changed, 29 insertions(+), 17 deletions(-) diff --git a/applications/main/nfc/nfc_cli.c b/applications/main/nfc/nfc_cli.c index 0cb7b960f69a..956b8c77dfc9 100644 --- a/applications/main/nfc/nfc_cli.c +++ b/applications/main/nfc/nfc_cli.c @@ -45,15 +45,17 @@ static void nfc_cli_check(Cli* cli, FuriString* args) { NfcaError error = NfcaErrorNone; uint8_t rx_data[100] = {}; uint16_t rx_bits = 0; + uint8_t nt[4] = {0x01, 0x02, 0x03, 0x04}; while(true) { error = nfca_listener_rx(instance, rx_data, sizeof(rx_data), &rx_bits, 10000); if(error == NfcaErrorNone) { - printf("Received %d bits\r\n", rx_bits); - for(size_t i = 0; i < rx_bits / 8; i++) { - printf("%02X ", rx_data[i]); - } - printf("\r\n"); + // printf("Received %d bits\r\n", rx_bits); + // for(size_t i = 0; i < rx_bits / 8; i++) { + // printf("%02X ", rx_data[i]); + // } + // printf("\r\n"); + nfca_listener_tx(instance, nt, sizeof(nt) * 8); } if(cli_cmd_interrupt_received(cli)) break; } diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc.c b/firmware/targets/f7/furi_hal/f_hal_nfc.c index 0aacac2d56b6..afd8c1f23c7c 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfc.c +++ b/firmware/targets/f7/furi_hal/f_hal_nfc.c @@ -412,14 +412,15 @@ FHalNfcError f_hal_nfc_listen_start() { // f_hal_nfc_trx_reset(); uint32_t interrupts = - (ST25R3916_IRQ_MASK_FWL | ST25R3916_IRQ_MASK_TXE | ST25R3916_IRQ_MASK_RXS | + (/*ST25R3916_IRQ_MASK_FWL | ST25R3916_IRQ_MASK_TXE |*/ ST25R3916_IRQ_MASK_RXS /*| ST25R3916_IRQ_MASK_RXE | ST25R3916_IRQ_MASK_PAR | ST25R3916_IRQ_MASK_CRC | ST25R3916_IRQ_MASK_ERR1 | ST25R3916_IRQ_MASK_ERR2 | ST25R3916_IRQ_MASK_EON | - ST25R3916_IRQ_MASK_EOF | ST25R3916_IRQ_MASK_WU_A_X | ST25R3916_IRQ_MASK_WU_A); + ST25R3916_IRQ_MASK_EOF | ST25R3916_IRQ_MASK_WU_A_X | ST25R3916_IRQ_MASK_WU_A*/); // Clear interrupts + // FURI_LOG_I("LISTEN START", "%lX", interrupts); st25r3916_get_irq(handle); // Enable interrupts - st25r3916_mask_irq(handle, ~interrupts); + st25r3916_mask_irq(handle, interrupts); st25r3916_direct_cmd(handle, ST25R3916_CMD_GOTO_SENSE); // st25r3916_direct_cmd(handle, ST25R3916_CMD_UNMASK_RECEIVE_DATA); diff --git a/lib/drivers/st25r3916.c b/lib/drivers/st25r3916.c index 363e33a3e295..c148da08c8f7 100644 --- a/lib/drivers/st25r3916.c +++ b/lib/drivers/st25r3916.c @@ -23,11 +23,15 @@ uint32_t st25r3916_get_irq(FuriHalSpiBusHandle* handle) { uint8_t irq_regs[4] = {}; uint32_t irq = 0; + st25r3916_read_burst_regs(handle, ST25R3916_REG_IRQ_MASK_MAIN, irq_regs, 4); + // FURI_LOG_I( + // "Mask Irq", "%02X %02X %02X %02X", irq_regs[0], irq_regs[1], irq_regs[2], irq_regs[3]); st25r3916_read_burst_regs(handle, ST25R3916_REG_IRQ_MAIN, irq_regs, 4); irq = (uint32_t)irq_regs[0]; irq |= (uint32_t)irq_regs[1] << 8; irq |= (uint32_t)irq_regs[2] << 16; irq |= (uint32_t)irq_regs[3] << 24; + // FURI_LOG_I("iRQ", "%02X %02X %02X %02X", irq_regs[0], irq_regs[1], irq_regs[2], irq_regs[3]); return irq; } diff --git a/lib/nfc/nfc.c b/lib/nfc/nfc.c index c15437d43eb2..3ec05ed812c9 100644 --- a/lib/nfc/nfc.c +++ b/lib/nfc/nfc.c @@ -381,30 +381,29 @@ NfcError nfc_listener_rx( do { FHalNfcEvent event = f_hal_nfc_wait_event(timeout); if(event & FHalNfcEventFieldOn) { - FURI_LOG_D(TAG, "FieldOn"); + // FURI_LOG_D(TAG, "FieldOn"); } if(event & FHalNfcEventListenerActive) { - FURI_LOG_D(TAG, "Activated"); - f_hal_nfc_listen_start(); + // FURI_LOG_D(TAG, "Activated"); } if(event & FHalNfcEventRxEnd) { - FURI_LOG_D(TAG, "Received data"); + // FURI_LOG_D(TAG, "Received data"); f_hal_nfc_poller_rx(rx_data, rx_data_size, rx_bits); break; } if(event & FHalNfcEventFieldOff) { - FURI_LOG_D(TAG, "Field off"); + // FURI_LOG_D(TAG, "Field off"); ret = NfcErrorLinkLoss; break; } if(event & FHalNfcEventTimeout) { ret = NfcErrorTimeout; - FURI_LOG_D(TAG, "Timeout"); + // FURI_LOG_D(TAG, "Timeout"); break; } if(event & FHalNfcEventAbortRequest) { ret = NfcErrorAbortRequest; - FURI_LOG_D(TAG, "Abirt request"); + // FURI_LOG_D(TAG, "Abirt request"); break; } @@ -436,7 +435,13 @@ NfcError nfc_listener_rx( NfcError nfc_listener_tx(Nfc* instance, uint8_t* tx_data, uint16_t tx_bits) { furi_assert(instance); furi_assert(tx_data); - UNUSED(tx_bits); - return NfcErrorNone; + NfcError ret = NfcErrorNone; + FHalNfcError error = f_hal_nfc_poller_tx(tx_data, tx_bits); + if(error != FHalNfcErrorNone) { + FURI_LOG_E(TAG, "Failed in listener TX"); + ret = nfc_process_hal_error(error); + } + + return ret; } From bf311e7bd12cf2dddcfd0ca4b5e86de30e291cc7 Mon Sep 17 00:00:00 2001 From: gornekich Date: Tue, 28 Mar 2023 16:09:37 +0400 Subject: [PATCH 008/149] nfc: add nfca emulation --- .../main/nfc_rpc/assets/compiled/main.pb.c | 2 +- .../main/nfc_rpc/assets/compiled/main.pb.h | 82 +++++++++++++------ .../assets/compiled/mf_ultralight.pb.c | 12 +++ .../assets/compiled/mf_ultralight.pb.h | 66 +++++++++++++++ .../main/nfc_rpc/assets/compiled/nfca.pb.c | 12 +++ .../main/nfc_rpc/assets/compiled/nfca.pb.h | 77 +++++++++++++++++ .../main/nfc_rpc/assets/protobuf/main.proto | 36 +++++--- .../assets/protobuf/mf_ultralight.options | 1 + .../assets/protobuf/mf_ultralight.proto | 8 ++ .../main/nfc_rpc/assets/protobuf/nfca.options | 9 +- .../main/nfc_rpc/assets/protobuf/nfca.proto | 15 +++- applications/main/nfc_rpc/nfc_rpc.c | 42 ---------- applications/main/nfc_rpc/nfc_rpc_i.h | 43 ++++++++++ applications/main/nfc_rpc/nfc_rpc_nfca.c | 47 +++++++++++ 14 files changed, 368 insertions(+), 84 deletions(-) diff --git a/applications/main/nfc_rpc/assets/compiled/main.pb.c b/applications/main/nfc_rpc/assets/compiled/main.pb.c index 0d01259546ff..9b574c9d6f71 100644 --- a/applications/main/nfc_rpc/assets/compiled/main.pb.c +++ b/applications/main/nfc_rpc/assets/compiled/main.pb.c @@ -9,7 +9,7 @@ PB_BIND(Nfc_Empty, Nfc_Empty, AUTO) -PB_BIND(Nfc_Main, Nfc_Main, AUTO) +PB_BIND(Nfc_Main, Nfc_Main, 2) diff --git a/applications/main/nfc_rpc/assets/compiled/main.pb.h b/applications/main/nfc_rpc/assets/compiled/main.pb.h index f35276f57743..e7b812844993 100644 --- a/applications/main/nfc_rpc/assets/compiled/main.pb.h +++ b/applications/main/nfc_rpc/assets/compiled/main.pb.h @@ -33,6 +33,10 @@ typedef struct _Nfc_Main { Nfc_Empty empty; PB_Nfca_ReadRequest nfca_read_req; PB_Nfca_ReadResponse nfca_read_resp; + PB_Nfca_EmulateStartRequest nfca_emulate_start_req; + PB_Nfca_EmulateStartResponse nfca_emulate_start_resp; + PB_Nfca_EmulateStopRequest nfca_emulate_stop_req; + PB_Nfca_EmulateStopResponse nfca_emulate_stop_resp; PB_MfUltralight_ReadPageRequest mf_ultralight_read_page_req; PB_MfUltralight_ReadPageResponse mf_ultralight_read_page_resp; PB_MfUltralight_ReadVersionRequest mf_ultralight_read_version_req; @@ -45,6 +49,10 @@ typedef struct _Nfc_Main { PB_MfUltralight_ReadCounterResponse mf_ultralight_read_counter_resp; PB_MfUltralight_ReadTearingFlagRequest mf_ultralight_read_tearing_flag_req; PB_MfUltralight_ReadTearingFlagResponse mf_ultralight_read_tearing_flag_resp; + PB_MfUltralight_EmulateStartRequest mf_ultralight_emulate_start_req; + PB_MfUltralight_EmulateStartResponse mf_ultralight_emulate_start_resp; + PB_MfUltralight_EmulationStopRequest mf_ultralight_emulate_stop_req; + PB_MfUltralight_EmulationStopResponse mf_ultralight_emulate_stop_resp; } content; } Nfc_Main; @@ -73,18 +81,26 @@ extern "C" { #define Nfc_Main_empty_tag 2 #define Nfc_Main_nfca_read_req_tag 3 #define Nfc_Main_nfca_read_resp_tag 4 -#define Nfc_Main_mf_ultralight_read_page_req_tag 5 -#define Nfc_Main_mf_ultralight_read_page_resp_tag 6 -#define Nfc_Main_mf_ultralight_read_version_req_tag 7 -#define Nfc_Main_mf_ultralight_read_version_resp_tag 8 -#define Nfc_Main_mf_ultralight_write_page_req_tag 9 -#define Nfc_Main_mf_ultralight_write_page_resp_tag 10 -#define Nfc_Main_mf_ultralight_read_signature_req_tag 11 -#define Nfc_Main_mf_ultralight_read_signature_resp_tag 12 -#define Nfc_Main_mf_ultralight_read_counter_req_tag 13 -#define Nfc_Main_mf_ultralight_read_counter_resp_tag 14 -#define Nfc_Main_mf_ultralight_read_tearing_flag_req_tag 15 -#define Nfc_Main_mf_ultralight_read_tearing_flag_resp_tag 16 +#define Nfc_Main_nfca_emulate_start_req_tag 5 +#define Nfc_Main_nfca_emulate_start_resp_tag 6 +#define Nfc_Main_nfca_emulate_stop_req_tag 7 +#define Nfc_Main_nfca_emulate_stop_resp_tag 8 +#define Nfc_Main_mf_ultralight_read_page_req_tag 9 +#define Nfc_Main_mf_ultralight_read_page_resp_tag 10 +#define Nfc_Main_mf_ultralight_read_version_req_tag 11 +#define Nfc_Main_mf_ultralight_read_version_resp_tag 12 +#define Nfc_Main_mf_ultralight_write_page_req_tag 13 +#define Nfc_Main_mf_ultralight_write_page_resp_tag 14 +#define Nfc_Main_mf_ultralight_read_signature_req_tag 15 +#define Nfc_Main_mf_ultralight_read_signature_resp_tag 16 +#define Nfc_Main_mf_ultralight_read_counter_req_tag 17 +#define Nfc_Main_mf_ultralight_read_counter_resp_tag 18 +#define Nfc_Main_mf_ultralight_read_tearing_flag_req_tag 19 +#define Nfc_Main_mf_ultralight_read_tearing_flag_resp_tag 20 +#define Nfc_Main_mf_ultralight_emulate_start_req_tag 21 +#define Nfc_Main_mf_ultralight_emulate_start_resp_tag 22 +#define Nfc_Main_mf_ultralight_emulate_stop_req_tag 23 +#define Nfc_Main_mf_ultralight_emulate_stop_resp_tag 24 /* Struct field encoding specification for nanopb */ #define Nfc_Empty_FIELDLIST(X, a) \ @@ -97,23 +113,35 @@ X(a, STATIC, SINGULAR, UENUM, command_status, 1) \ X(a, STATIC, ONEOF, MSG_W_CB, (content,empty,content.empty), 2) \ X(a, STATIC, ONEOF, MSG_W_CB, (content,nfca_read_req,content.nfca_read_req), 3) \ X(a, STATIC, ONEOF, MSG_W_CB, (content,nfca_read_resp,content.nfca_read_resp), 4) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_page_req,content.mf_ultralight_read_page_req), 5) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_page_resp,content.mf_ultralight_read_page_resp), 6) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_version_req,content.mf_ultralight_read_version_req), 7) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_version_resp,content.mf_ultralight_read_version_resp), 8) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_write_page_req,content.mf_ultralight_write_page_req), 9) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_write_page_resp,content.mf_ultralight_write_page_resp), 10) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_signature_req,content.mf_ultralight_read_signature_req), 11) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_signature_resp,content.mf_ultralight_read_signature_resp), 12) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_counter_req,content.mf_ultralight_read_counter_req), 13) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_counter_resp,content.mf_ultralight_read_counter_resp), 14) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_tearing_flag_req,content.mf_ultralight_read_tearing_flag_req), 15) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_tearing_flag_resp,content.mf_ultralight_read_tearing_flag_resp), 16) +X(a, STATIC, ONEOF, MSG_W_CB, (content,nfca_emulate_start_req,content.nfca_emulate_start_req), 5) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,nfca_emulate_start_resp,content.nfca_emulate_start_resp), 6) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,nfca_emulate_stop_req,content.nfca_emulate_stop_req), 7) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,nfca_emulate_stop_resp,content.nfca_emulate_stop_resp), 8) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_page_req,content.mf_ultralight_read_page_req), 9) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_page_resp,content.mf_ultralight_read_page_resp), 10) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_version_req,content.mf_ultralight_read_version_req), 11) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_version_resp,content.mf_ultralight_read_version_resp), 12) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_write_page_req,content.mf_ultralight_write_page_req), 13) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_write_page_resp,content.mf_ultralight_write_page_resp), 14) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_signature_req,content.mf_ultralight_read_signature_req), 15) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_signature_resp,content.mf_ultralight_read_signature_resp), 16) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_counter_req,content.mf_ultralight_read_counter_req), 17) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_counter_resp,content.mf_ultralight_read_counter_resp), 18) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_tearing_flag_req,content.mf_ultralight_read_tearing_flag_req), 19) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_tearing_flag_resp,content.mf_ultralight_read_tearing_flag_resp), 20) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_emulate_start_req,content.mf_ultralight_emulate_start_req), 21) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_emulate_start_resp,content.mf_ultralight_emulate_start_resp), 22) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_emulate_stop_req,content.mf_ultralight_emulate_stop_req), 23) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_emulate_stop_resp,content.mf_ultralight_emulate_stop_resp), 24) #define Nfc_Main_CALLBACK NULL #define Nfc_Main_DEFAULT NULL #define Nfc_Main_content_empty_MSGTYPE Nfc_Empty #define Nfc_Main_content_nfca_read_req_MSGTYPE PB_Nfca_ReadRequest #define Nfc_Main_content_nfca_read_resp_MSGTYPE PB_Nfca_ReadResponse +#define Nfc_Main_content_nfca_emulate_start_req_MSGTYPE PB_Nfca_EmulateStartRequest +#define Nfc_Main_content_nfca_emulate_start_resp_MSGTYPE PB_Nfca_EmulateStartResponse +#define Nfc_Main_content_nfca_emulate_stop_req_MSGTYPE PB_Nfca_EmulateStopRequest +#define Nfc_Main_content_nfca_emulate_stop_resp_MSGTYPE PB_Nfca_EmulateStopResponse #define Nfc_Main_content_mf_ultralight_read_page_req_MSGTYPE PB_MfUltralight_ReadPageRequest #define Nfc_Main_content_mf_ultralight_read_page_resp_MSGTYPE PB_MfUltralight_ReadPageResponse #define Nfc_Main_content_mf_ultralight_read_version_req_MSGTYPE PB_MfUltralight_ReadVersionRequest @@ -126,6 +154,10 @@ X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_tearing_flag_resp #define Nfc_Main_content_mf_ultralight_read_counter_resp_MSGTYPE PB_MfUltralight_ReadCounterResponse #define Nfc_Main_content_mf_ultralight_read_tearing_flag_req_MSGTYPE PB_MfUltralight_ReadTearingFlagRequest #define Nfc_Main_content_mf_ultralight_read_tearing_flag_resp_MSGTYPE PB_MfUltralight_ReadTearingFlagResponse +#define Nfc_Main_content_mf_ultralight_emulate_start_req_MSGTYPE PB_MfUltralight_EmulateStartRequest +#define Nfc_Main_content_mf_ultralight_emulate_start_resp_MSGTYPE PB_MfUltralight_EmulateStartResponse +#define Nfc_Main_content_mf_ultralight_emulate_stop_req_MSGTYPE PB_MfUltralight_EmulationStopRequest +#define Nfc_Main_content_mf_ultralight_emulate_stop_resp_MSGTYPE PB_MfUltralight_EmulationStopResponse extern const pb_msgdesc_t Nfc_Empty_msg; extern const pb_msgdesc_t Nfc_Main_msg; @@ -136,7 +168,7 @@ extern const pb_msgdesc_t Nfc_Main_msg; /* Maximum encoded size of messages (where known) */ #define Nfc_Empty_size 0 -#define Nfc_Main_size 54 +#define Nfc_Main_size 2057 #ifdef __cplusplus } /* extern "C" */ diff --git a/applications/main/nfc_rpc/assets/compiled/mf_ultralight.pb.c b/applications/main/nfc_rpc/assets/compiled/mf_ultralight.pb.c index 1a8e0f1ae71f..146685d328fe 100644 --- a/applications/main/nfc_rpc/assets/compiled/mf_ultralight.pb.c +++ b/applications/main/nfc_rpc/assets/compiled/mf_ultralight.pb.c @@ -42,5 +42,17 @@ PB_BIND(PB_MfUltralight_ReadTearingFlagRequest, PB_MfUltralight_ReadTearingFlagR PB_BIND(PB_MfUltralight_ReadTearingFlagResponse, PB_MfUltralight_ReadTearingFlagResponse, AUTO) +PB_BIND(PB_MfUltralight_EmulateStartRequest, PB_MfUltralight_EmulateStartRequest, 2) + + +PB_BIND(PB_MfUltralight_EmulateStartResponse, PB_MfUltralight_EmulateStartResponse, AUTO) + + +PB_BIND(PB_MfUltralight_EmulationStopRequest, PB_MfUltralight_EmulationStopRequest, AUTO) + + +PB_BIND(PB_MfUltralight_EmulationStopResponse, PB_MfUltralight_EmulationStopResponse, AUTO) + + diff --git a/applications/main/nfc_rpc/assets/compiled/mf_ultralight.pb.h b/applications/main/nfc_rpc/assets/compiled/mf_ultralight.pb.h index 6dc2673bac97..56e89726df47 100644 --- a/applications/main/nfc_rpc/assets/compiled/mf_ultralight.pb.h +++ b/applications/main/nfc_rpc/assets/compiled/mf_ultralight.pb.h @@ -89,6 +89,23 @@ typedef struct _PB_MfUltralight_ReadTearingFlagResponse { PB_MfUltralight_ReadTearingFlagResponse_data_t data; } PB_MfUltralight_ReadTearingFlagResponse; +typedef PB_BYTES_ARRAY_T(2048) PB_MfUltralight_EmulateStartRequest_data_t; +typedef struct _PB_MfUltralight_EmulateStartRequest { + PB_MfUltralight_EmulateStartRequest_data_t data; +} PB_MfUltralight_EmulateStartRequest; + +typedef struct _PB_MfUltralight_EmulateStartResponse { + PB_MfUltralight_Error error; +} PB_MfUltralight_EmulateStartResponse; + +typedef struct _PB_MfUltralight_EmulationStopRequest { + char dummy_field; +} PB_MfUltralight_EmulationStopRequest; + +typedef struct _PB_MfUltralight_EmulationStopResponse { + PB_MfUltralight_Error error; +} PB_MfUltralight_EmulationStopResponse; + #ifdef __cplusplus extern "C" { @@ -118,6 +135,12 @@ extern "C" { #define PB_MfUltralight_ReadTearingFlagResponse_error_ENUMTYPE PB_MfUltralight_Error +#define PB_MfUltralight_EmulateStartResponse_error_ENUMTYPE PB_MfUltralight_Error + + +#define PB_MfUltralight_EmulationStopResponse_error_ENUMTYPE PB_MfUltralight_Error + + /* Initializer values for message structs */ #define PB_MfUltralight_ReadPageRequest_init_default {0} #define PB_MfUltralight_ReadPageResponse_init_default {_PB_MfUltralight_Error_MIN, 0, {0, {0}}} @@ -131,6 +154,10 @@ extern "C" { #define PB_MfUltralight_ReadCounterResponse_init_default {_PB_MfUltralight_Error_MIN, 0, {0, {0}}} #define PB_MfUltralight_ReadTearingFlagRequest_init_default {0} #define PB_MfUltralight_ReadTearingFlagResponse_init_default {_PB_MfUltralight_Error_MIN, 0, {0, {0}}} +#define PB_MfUltralight_EmulateStartRequest_init_default {{0, {0}}} +#define PB_MfUltralight_EmulateStartResponse_init_default {_PB_MfUltralight_Error_MIN} +#define PB_MfUltralight_EmulationStopRequest_init_default {0} +#define PB_MfUltralight_EmulationStopResponse_init_default {_PB_MfUltralight_Error_MIN} #define PB_MfUltralight_ReadPageRequest_init_zero {0} #define PB_MfUltralight_ReadPageResponse_init_zero {_PB_MfUltralight_Error_MIN, 0, {0, {0}}} #define PB_MfUltralight_ReadVersionRequest_init_zero {0} @@ -143,6 +170,10 @@ extern "C" { #define PB_MfUltralight_ReadCounterResponse_init_zero {_PB_MfUltralight_Error_MIN, 0, {0, {0}}} #define PB_MfUltralight_ReadTearingFlagRequest_init_zero {0} #define PB_MfUltralight_ReadTearingFlagResponse_init_zero {_PB_MfUltralight_Error_MIN, 0, {0, {0}}} +#define PB_MfUltralight_EmulateStartRequest_init_zero {{0, {0}}} +#define PB_MfUltralight_EmulateStartResponse_init_zero {_PB_MfUltralight_Error_MIN} +#define PB_MfUltralight_EmulationStopRequest_init_zero {0} +#define PB_MfUltralight_EmulationStopResponse_init_zero {_PB_MfUltralight_Error_MIN} /* Field tags (for use in manual encoding/decoding) */ #define PB_MfUltralight_ReadPageRequest_page_tag 1 @@ -172,6 +203,9 @@ extern "C" { #define PB_MfUltralight_ReadTearingFlagResponse_error_tag 1 #define PB_MfUltralight_ReadTearingFlagResponse_flag_num_tag 2 #define PB_MfUltralight_ReadTearingFlagResponse_data_tag 3 +#define PB_MfUltralight_EmulateStartRequest_data_tag 1 +#define PB_MfUltralight_EmulateStartResponse_error_tag 1 +#define PB_MfUltralight_EmulationStopResponse_error_tag 1 /* Struct field encoding specification for nanopb */ #define PB_MfUltralight_ReadPageRequest_FIELDLIST(X, a) \ @@ -251,6 +285,26 @@ X(a, STATIC, SINGULAR, BYTES, data, 3) #define PB_MfUltralight_ReadTearingFlagResponse_CALLBACK NULL #define PB_MfUltralight_ReadTearingFlagResponse_DEFAULT NULL +#define PB_MfUltralight_EmulateStartRequest_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, BYTES, data, 1) +#define PB_MfUltralight_EmulateStartRequest_CALLBACK NULL +#define PB_MfUltralight_EmulateStartRequest_DEFAULT NULL + +#define PB_MfUltralight_EmulateStartResponse_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UENUM, error, 1) +#define PB_MfUltralight_EmulateStartResponse_CALLBACK NULL +#define PB_MfUltralight_EmulateStartResponse_DEFAULT NULL + +#define PB_MfUltralight_EmulationStopRequest_FIELDLIST(X, a) \ + +#define PB_MfUltralight_EmulationStopRequest_CALLBACK NULL +#define PB_MfUltralight_EmulationStopRequest_DEFAULT NULL + +#define PB_MfUltralight_EmulationStopResponse_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UENUM, error, 1) +#define PB_MfUltralight_EmulationStopResponse_CALLBACK NULL +#define PB_MfUltralight_EmulationStopResponse_DEFAULT NULL + extern const pb_msgdesc_t PB_MfUltralight_ReadPageRequest_msg; extern const pb_msgdesc_t PB_MfUltralight_ReadPageResponse_msg; extern const pb_msgdesc_t PB_MfUltralight_ReadVersionRequest_msg; @@ -263,6 +317,10 @@ extern const pb_msgdesc_t PB_MfUltralight_ReadCounterRequest_msg; extern const pb_msgdesc_t PB_MfUltralight_ReadCounterResponse_msg; extern const pb_msgdesc_t PB_MfUltralight_ReadTearingFlagRequest_msg; extern const pb_msgdesc_t PB_MfUltralight_ReadTearingFlagResponse_msg; +extern const pb_msgdesc_t PB_MfUltralight_EmulateStartRequest_msg; +extern const pb_msgdesc_t PB_MfUltralight_EmulateStartResponse_msg; +extern const pb_msgdesc_t PB_MfUltralight_EmulationStopRequest_msg; +extern const pb_msgdesc_t PB_MfUltralight_EmulationStopResponse_msg; /* Defines for backwards compatibility with code written before nanopb-0.4.0 */ #define PB_MfUltralight_ReadPageRequest_fields &PB_MfUltralight_ReadPageRequest_msg @@ -277,8 +335,16 @@ extern const pb_msgdesc_t PB_MfUltralight_ReadTearingFlagResponse_msg; #define PB_MfUltralight_ReadCounterResponse_fields &PB_MfUltralight_ReadCounterResponse_msg #define PB_MfUltralight_ReadTearingFlagRequest_fields &PB_MfUltralight_ReadTearingFlagRequest_msg #define PB_MfUltralight_ReadTearingFlagResponse_fields &PB_MfUltralight_ReadTearingFlagResponse_msg +#define PB_MfUltralight_EmulateStartRequest_fields &PB_MfUltralight_EmulateStartRequest_msg +#define PB_MfUltralight_EmulateStartResponse_fields &PB_MfUltralight_EmulateStartResponse_msg +#define PB_MfUltralight_EmulationStopRequest_fields &PB_MfUltralight_EmulationStopRequest_msg +#define PB_MfUltralight_EmulationStopResponse_fields &PB_MfUltralight_EmulationStopResponse_msg /* Maximum encoded size of messages (where known) */ +#define PB_MfUltralight_EmulateStartRequest_size 2051 +#define PB_MfUltralight_EmulateStartResponse_size 2 +#define PB_MfUltralight_EmulationStopRequest_size 0 +#define PB_MfUltralight_EmulationStopResponse_size 2 #define PB_MfUltralight_ReadCounterRequest_size 6 #define PB_MfUltralight_ReadCounterResponse_size 13 #define PB_MfUltralight_ReadPageRequest_size 4 diff --git a/applications/main/nfc_rpc/assets/compiled/nfca.pb.c b/applications/main/nfc_rpc/assets/compiled/nfca.pb.c index 076751611760..44e2f02579da 100644 --- a/applications/main/nfc_rpc/assets/compiled/nfca.pb.c +++ b/applications/main/nfc_rpc/assets/compiled/nfca.pb.c @@ -12,5 +12,17 @@ PB_BIND(PB_Nfca_ReadRequest, PB_Nfca_ReadRequest, AUTO) PB_BIND(PB_Nfca_ReadResponse, PB_Nfca_ReadResponse, AUTO) +PB_BIND(PB_Nfca_EmulateStartRequest, PB_Nfca_EmulateStartRequest, AUTO) + + +PB_BIND(PB_Nfca_EmulateStartResponse, PB_Nfca_EmulateStartResponse, AUTO) + + +PB_BIND(PB_Nfca_EmulateStopRequest, PB_Nfca_EmulateStopRequest, AUTO) + + +PB_BIND(PB_Nfca_EmulateStopResponse, PB_Nfca_EmulateStopResponse, AUTO) + + diff --git a/applications/main/nfc_rpc/assets/compiled/nfca.pb.h b/applications/main/nfc_rpc/assets/compiled/nfca.pb.h index a65a32218c29..df751cbd0c92 100644 --- a/applications/main/nfc_rpc/assets/compiled/nfca.pb.h +++ b/applications/main/nfc_rpc/assets/compiled/nfca.pb.h @@ -37,6 +37,28 @@ typedef struct _PB_Nfca_ReadResponse { PB_Nfca_ReadResponse_atqa_t atqa; } PB_Nfca_ReadResponse; +typedef PB_BYTES_ARRAY_T(10) PB_Nfca_EmulateStartRequest_uid_t; +typedef PB_BYTES_ARRAY_T(1) PB_Nfca_EmulateStartRequest_sak_t; +typedef PB_BYTES_ARRAY_T(2) PB_Nfca_EmulateStartRequest_atqa_t; +typedef struct _PB_Nfca_EmulateStartRequest { + uint32_t uid_len; + PB_Nfca_EmulateStartRequest_uid_t uid; + PB_Nfca_EmulateStartRequest_sak_t sak; + PB_Nfca_EmulateStartRequest_atqa_t atqa; +} PB_Nfca_EmulateStartRequest; + +typedef struct _PB_Nfca_EmulateStartResponse { + PB_Nfca_Error error; +} PB_Nfca_EmulateStartResponse; + +typedef struct _PB_Nfca_EmulateStopRequest { + char dummy_field; +} PB_Nfca_EmulateStopRequest; + +typedef struct _PB_Nfca_EmulateStopResponse { + PB_Nfca_Error error; +} PB_Nfca_EmulateStopResponse; + #ifdef __cplusplus extern "C" { @@ -51,11 +73,25 @@ extern "C" { #define PB_Nfca_ReadResponse_error_ENUMTYPE PB_Nfca_Error +#define PB_Nfca_EmulateStartResponse_error_ENUMTYPE PB_Nfca_Error + + +#define PB_Nfca_EmulateStopResponse_error_ENUMTYPE PB_Nfca_Error + + /* Initializer values for message structs */ #define PB_Nfca_ReadRequest_init_default {0} #define PB_Nfca_ReadResponse_init_default {_PB_Nfca_Error_MIN, 0, {0, {0}}, {0, {0}}, {0, {0}}} +#define PB_Nfca_EmulateStartRequest_init_default {0, {0, {0}}, {0, {0}}, {0, {0}}} +#define PB_Nfca_EmulateStartResponse_init_default {_PB_Nfca_Error_MIN} +#define PB_Nfca_EmulateStopRequest_init_default {0} +#define PB_Nfca_EmulateStopResponse_init_default {_PB_Nfca_Error_MIN} #define PB_Nfca_ReadRequest_init_zero {0} #define PB_Nfca_ReadResponse_init_zero {_PB_Nfca_Error_MIN, 0, {0, {0}}, {0, {0}}, {0, {0}}} +#define PB_Nfca_EmulateStartRequest_init_zero {0, {0, {0}}, {0, {0}}, {0, {0}}} +#define PB_Nfca_EmulateStartResponse_init_zero {_PB_Nfca_Error_MIN} +#define PB_Nfca_EmulateStopRequest_init_zero {0} +#define PB_Nfca_EmulateStopResponse_init_zero {_PB_Nfca_Error_MIN} /* Field tags (for use in manual encoding/decoding) */ #define PB_Nfca_ReadResponse_error_tag 1 @@ -63,6 +99,12 @@ extern "C" { #define PB_Nfca_ReadResponse_uid_tag 3 #define PB_Nfca_ReadResponse_sak_tag 4 #define PB_Nfca_ReadResponse_atqa_tag 5 +#define PB_Nfca_EmulateStartRequest_uid_len_tag 1 +#define PB_Nfca_EmulateStartRequest_uid_tag 2 +#define PB_Nfca_EmulateStartRequest_sak_tag 3 +#define PB_Nfca_EmulateStartRequest_atqa_tag 4 +#define PB_Nfca_EmulateStartResponse_error_tag 1 +#define PB_Nfca_EmulateStopResponse_error_tag 1 /* Struct field encoding specification for nanopb */ #define PB_Nfca_ReadRequest_FIELDLIST(X, a) \ @@ -79,14 +121,49 @@ X(a, STATIC, SINGULAR, BYTES, atqa, 5) #define PB_Nfca_ReadResponse_CALLBACK NULL #define PB_Nfca_ReadResponse_DEFAULT NULL +#define PB_Nfca_EmulateStartRequest_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UINT32, uid_len, 1) \ +X(a, STATIC, SINGULAR, BYTES, uid, 2) \ +X(a, STATIC, SINGULAR, BYTES, sak, 3) \ +X(a, STATIC, SINGULAR, BYTES, atqa, 4) +#define PB_Nfca_EmulateStartRequest_CALLBACK NULL +#define PB_Nfca_EmulateStartRequest_DEFAULT NULL + +#define PB_Nfca_EmulateStartResponse_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UENUM, error, 1) +#define PB_Nfca_EmulateStartResponse_CALLBACK NULL +#define PB_Nfca_EmulateStartResponse_DEFAULT NULL + +#define PB_Nfca_EmulateStopRequest_FIELDLIST(X, a) \ + +#define PB_Nfca_EmulateStopRequest_CALLBACK NULL +#define PB_Nfca_EmulateStopRequest_DEFAULT NULL + +#define PB_Nfca_EmulateStopResponse_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UENUM, error, 1) +#define PB_Nfca_EmulateStopResponse_CALLBACK NULL +#define PB_Nfca_EmulateStopResponse_DEFAULT NULL + extern const pb_msgdesc_t PB_Nfca_ReadRequest_msg; extern const pb_msgdesc_t PB_Nfca_ReadResponse_msg; +extern const pb_msgdesc_t PB_Nfca_EmulateStartRequest_msg; +extern const pb_msgdesc_t PB_Nfca_EmulateStartResponse_msg; +extern const pb_msgdesc_t PB_Nfca_EmulateStopRequest_msg; +extern const pb_msgdesc_t PB_Nfca_EmulateStopResponse_msg; /* Defines for backwards compatibility with code written before nanopb-0.4.0 */ #define PB_Nfca_ReadRequest_fields &PB_Nfca_ReadRequest_msg #define PB_Nfca_ReadResponse_fields &PB_Nfca_ReadResponse_msg +#define PB_Nfca_EmulateStartRequest_fields &PB_Nfca_EmulateStartRequest_msg +#define PB_Nfca_EmulateStartResponse_fields &PB_Nfca_EmulateStartResponse_msg +#define PB_Nfca_EmulateStopRequest_fields &PB_Nfca_EmulateStopRequest_msg +#define PB_Nfca_EmulateStopResponse_fields &PB_Nfca_EmulateStopResponse_msg /* Maximum encoded size of messages (where known) */ +#define PB_Nfca_EmulateStartRequest_size 25 +#define PB_Nfca_EmulateStartResponse_size 2 +#define PB_Nfca_EmulateStopRequest_size 0 +#define PB_Nfca_EmulateStopResponse_size 2 #define PB_Nfca_ReadRequest_size 0 #define PB_Nfca_ReadResponse_size 27 diff --git a/applications/main/nfc_rpc/assets/protobuf/main.proto b/applications/main/nfc_rpc/assets/protobuf/main.proto index 5a12ff644f3f..e0ecdc2351c7 100644 --- a/applications/main/nfc_rpc/assets/protobuf/main.proto +++ b/applications/main/nfc_rpc/assets/protobuf/main.proto @@ -23,17 +23,29 @@ message Main { Empty empty = 2; .PB_Nfca.ReadRequest nfca_read_req = 3; .PB_Nfca.ReadResponse nfca_read_resp = 4; - .PB_MfUltralight.ReadPageRequest mf_ultralight_read_page_req = 5; - .PB_MfUltralight.ReadPageResponse mf_ultralight_read_page_resp = 6; - .PB_MfUltralight.ReadVersionRequest mf_ultralight_read_version_req = 7; - .PB_MfUltralight.ReadVersionResponse mf_ultralight_read_version_resp = 8; - .PB_MfUltralight.WritePageRequest mf_ultralight_write_page_req = 9; - .PB_MfUltralight.WritePageResponse mf_ultralight_write_page_resp = 10; - .PB_MfUltralight.ReadSignatureRequest mf_ultralight_read_signature_req = 11; - .PB_MfUltralight.ReadSignatureResponse mf_ultralight_read_signature_resp = 12; - .PB_MfUltralight.ReadCounterRequest mf_ultralight_read_counter_req = 13; - .PB_MfUltralight.ReadCounterResponse mf_ultralight_read_counter_resp = 14; - .PB_MfUltralight.ReadTearingFlagRequest mf_ultralight_read_tearing_flag_req = 15; - .PB_MfUltralight.ReadTearingFlagResponse mf_ultralight_read_tearing_flag_resp = 16; + .PB_Nfca.EmulateStartRequest nfca_emulate_start_req = 5; + .PB_Nfca.EmulateStartResponse nfca_emulate_start_resp = 6; + .PB_Nfca.EmulateStopRequest nfca_emulate_stop_req = 7; + .PB_Nfca.EmulateStopResponse nfca_emulate_stop_resp = 8; + + .PB_MfUltralight.ReadPageRequest mf_ultralight_read_page_req = 9; + .PB_MfUltralight.ReadPageResponse mf_ultralight_read_page_resp = 10; + .PB_MfUltralight.ReadVersionRequest mf_ultralight_read_version_req = 11; + .PB_MfUltralight.ReadVersionResponse mf_ultralight_read_version_resp = 12; + .PB_MfUltralight.WritePageRequest mf_ultralight_write_page_req = 13; + .PB_MfUltralight.WritePageResponse mf_ultralight_write_page_resp = 14; + .PB_MfUltralight.ReadSignatureRequest mf_ultralight_read_signature_req = 15; + .PB_MfUltralight.ReadSignatureResponse mf_ultralight_read_signature_resp = + 16; + .PB_MfUltralight.ReadCounterRequest mf_ultralight_read_counter_req = 17; + .PB_MfUltralight.ReadCounterResponse mf_ultralight_read_counter_resp = 18; + .PB_MfUltralight.ReadTearingFlagRequest + mf_ultralight_read_tearing_flag_req = 19; + .PB_MfUltralight.ReadTearingFlagResponse + mf_ultralight_read_tearing_flag_resp = 20; + .PB_MfUltralight.EmulateStartRequest mf_ultralight_emulate_start_req = 21; + .PB_MfUltralight.EmulateStartResponse mf_ultralight_emulate_start_resp = 22; + .PB_MfUltralight.EmulationStopRequest mf_ultralight_emulate_stop_req = 23; + .PB_MfUltralight.EmulationStopResponse mf_ultralight_emulate_stop_resp = 24; } } diff --git a/applications/main/nfc_rpc/assets/protobuf/mf_ultralight.options b/applications/main/nfc_rpc/assets/protobuf/mf_ultralight.options index 97e52c0cd345..a7b4fab9a8b4 100644 --- a/applications/main/nfc_rpc/assets/protobuf/mf_ultralight.options +++ b/applications/main/nfc_rpc/assets/protobuf/mf_ultralight.options @@ -6,3 +6,4 @@ PB_MfUltralight.WritePageRequest.data max_size: 4 PB_MfUltralight.ReadSignatureResponse.data max_size: 32 PB_MfUltralight.ReadCounterResponse.data max_size: 3 PB_MfUltralight.ReadTearingFlagResponse.data max_size: 1 +PB_MfUltralight.EmulateStartRequest.data max_size: 2048 \ No newline at end of file diff --git a/applications/main/nfc_rpc/assets/protobuf/mf_ultralight.proto b/applications/main/nfc_rpc/assets/protobuf/mf_ultralight.proto index f333fc1b06bd..367b77996dab 100644 --- a/applications/main/nfc_rpc/assets/protobuf/mf_ultralight.proto +++ b/applications/main/nfc_rpc/assets/protobuf/mf_ultralight.proto @@ -65,3 +65,11 @@ message ReadTearingFlagResponse { uint32 flag_num = 2; bytes data = 3; } + +message EmulateStartRequest { bytes data = 1; } + +message EmulateStartResponse { Error error = 1; } + +message EmulationStopRequest {} + +message EmulationStopResponse { Error error = 1; } diff --git a/applications/main/nfc_rpc/assets/protobuf/nfca.options b/applications/main/nfc_rpc/assets/protobuf/nfca.options index 582beb50ae4e..5da79e05678c 100644 --- a/applications/main/nfc_rpc/assets/protobuf/nfca.options +++ b/applications/main/nfc_rpc/assets/protobuf/nfca.options @@ -1,3 +1,6 @@ -PB_Nfca.ReadResponse.uid max_size: 10 -PB_Nfca.ReadResponse.sak max_size: 1 -PB_Nfca.ReadResponse.atqa max_size: 2 \ No newline at end of file +PB_Nfca.ReadResponse.uid max_size: 10 +PB_Nfca.ReadResponse.sak max_size: 1 +PB_Nfca.ReadResponse.atqa max_size: 2 +PB_Nfca.EmulateStartRequest.uid max_size: 10 +PB_Nfca.EmulateStartRequest.sak max_size: 1 +PB_Nfca.EmulateStartRequest.atqa max_size: 2 \ No newline at end of file diff --git a/applications/main/nfc_rpc/assets/protobuf/nfca.proto b/applications/main/nfc_rpc/assets/protobuf/nfca.proto index 183eae0b106b..96a540c306a1 100644 --- a/applications/main/nfc_rpc/assets/protobuf/nfca.proto +++ b/applications/main/nfc_rpc/assets/protobuf/nfca.proto @@ -22,4 +22,17 @@ message ReadResponse { bytes uid = 3; bytes sak = 4; bytes atqa = 5; -} \ No newline at end of file +} + +message EmulateStartRequest { + uint32 uid_len = 1; + bytes uid = 2; + bytes sak = 3; + bytes atqa = 4; +} + +message EmulateStartResponse { Error error = 1; } + +message EmulateStopRequest {} + +message EmulateStopResponse { Error error = 1; } \ No newline at end of file diff --git a/applications/main/nfc_rpc/nfc_rpc.c b/applications/main/nfc_rpc/nfc_rpc.c index a1f01d2b654f..57d48ea30406 100644 --- a/applications/main/nfc_rpc/nfc_rpc.c +++ b/applications/main/nfc_rpc/nfc_rpc.c @@ -1,49 +1,7 @@ #include "nfc_rpc_i.h" -#include -#include - -#include "assets/compiled/main.pb.h" #define TAG "NfcRpc" -DICT_DEF2(NfcRpcHandlerDict, pb_size_t, M_DEFAULT_OPLIST, NfcRpcHandler, M_POD_OPLIST) - -typedef void (*NfcRpcHandlersAlloc)(void* context); -typedef void (*NfcRpcHandlersFree)(void* context); - -typedef enum { - NfcRpcViewMain, -} NfcRpcView; - -typedef enum { - NfcRpcCustomEventMessageReceived, -} NfcRpcCustomEvent; - -typedef enum { - NfcRpcEventDataExchange, -} NfcRpcEventType; - -typedef struct { - NfcRpcEventType type; - const uint8_t* data; - size_t data_size; -} NfcRpcEvent; - -struct NfcRpc { - Gui* gui; - RpcAppSystem* rpc; - FuriMessageQueue* queue; - ViewDispatcher* view_dispatcher; - View* view; - - NfcRpcHandlerDict_t handlers; -}; - -typedef struct { - NfcRpcHandlersAlloc alloc; - NfcRpcHandlersFree free; -} NfcRpcCallbacks; - static const NfcRpcCallbacks nfc_rpc_callbacks[] = { { .alloc = nfc_rpc_nfca_alloc, diff --git a/applications/main/nfc_rpc/nfc_rpc_i.h b/applications/main/nfc_rpc/nfc_rpc_i.h index aa7e94293855..c89dc4a6dd24 100644 --- a/applications/main/nfc_rpc/nfc_rpc_i.h +++ b/applications/main/nfc_rpc/nfc_rpc_i.h @@ -13,9 +13,52 @@ #include #include "assets/compiled/main.pb.h" +#include + +#include +#include typedef void (*NfcRpcHandler)(Nfc_Main* cmd, void* context); +DICT_DEF2(NfcRpcHandlerDict, pb_size_t, M_DEFAULT_OPLIST, NfcRpcHandler, M_POD_OPLIST) + +typedef void (*NfcRpcHandlersAlloc)(void* context); +typedef void (*NfcRpcHandlersFree)(void* context); + +typedef enum { + NfcRpcViewMain, +} NfcRpcView; + +typedef enum { + NfcRpcCustomEventMessageReceived, +} NfcRpcCustomEvent; + +typedef enum { + NfcRpcEventDataExchange, +} NfcRpcEventType; + +typedef struct { + NfcRpcEventType type; + const uint8_t* data; + size_t data_size; +} NfcRpcEvent; + +struct NfcRpc { + Gui* gui; + RpcAppSystem* rpc; + FuriMessageQueue* queue; + ViewDispatcher* view_dispatcher; + View* view; + NfcaListener* nfca_listener; + + NfcRpcHandlerDict_t handlers; +}; + +typedef struct { + NfcRpcHandlersAlloc alloc; + NfcRpcHandlersFree free; +} NfcRpcCallbacks; + void nfc_rpc_add_handler(NfcRpc* instance, pb_size_t message_tag, NfcRpcHandler handler); void nfc_rpc_nfca_alloc(void* context); diff --git a/applications/main/nfc_rpc/nfc_rpc_nfca.c b/applications/main/nfc_rpc/nfc_rpc_nfca.c index 6dd232f893ac..a323bda4a380 100644 --- a/applications/main/nfc_rpc/nfc_rpc_nfca.c +++ b/applications/main/nfc_rpc/nfc_rpc_nfca.c @@ -67,9 +67,56 @@ static void nfc_rpc_nfca_read(Nfc_Main* cmd, void* context) { nfca_poller_free(nfca_poller); } +static void nfc_rpc_nfca_emulate_start(Nfc_Main* cmd, void* context) { + furi_assert(cmd); + furi_assert(context); + + NfcRpc* instance = context; + PB_Nfca_EmulateStartResponse pb_nfca_emulate_start_resp = + PB_Nfca_EmulateStartResponse_init_default; + cmd->command_status = Nfc_CommandStatus_OK; + cmd->which_content = Nfc_Main_nfca_emulate_start_resp_tag; + if(instance->nfca_listener == NULL) { + NfcaData nfca_data = {}; + nfca_data.uid_len = cmd->content.nfca_emulate_start_req.uid_len; + memcpy(nfca_data.uid, cmd->content.nfca_emulate_start_req.uid.bytes, nfca_data.uid_len); + memcpy(nfca_data.atqa, cmd->content.nfca_emulate_start_req.atqa.bytes, 2); + memcpy(&nfca_data.sak, cmd->content.nfca_emulate_start_req.sak.bytes, 1); + + instance->nfca_listener = nfca_listener_alloc(&nfca_data); + pb_nfca_emulate_start_resp.error = PB_Nfca_Error_None; + } else { + // TODO add Busy error + pb_nfca_emulate_start_resp.error = PB_Nfca_Error_NotPresent; + } + cmd->content.nfca_emulate_start_resp = pb_nfca_emulate_start_resp; +} + +static void nfc_rpc_nfca_emulate_stop(Nfc_Main* cmd, void* context) { + furi_assert(cmd); + furi_assert(context); + + NfcRpc* instance = context; + PB_Nfca_EmulateStopResponse pb_nfca_emulate_stop_resp = + PB_Nfca_EmulateStopResponse_init_default; + cmd->command_status = Nfc_CommandStatus_OK; + cmd->which_content = Nfc_Main_nfca_emulate_stop_resp_tag; + if(instance->nfca_listener) { + nfca_listener_free(instance->nfca_listener); + instance->nfca_listener = NULL; + pb_nfca_emulate_stop_resp.error = PB_Nfca_Error_None; + } else { + // TODO add Busy error + pb_nfca_emulate_stop_resp.error = PB_Nfca_Error_NotPresent; + } + cmd->content.nfca_emulate_stop_resp = pb_nfca_emulate_stop_resp; +} + void nfc_rpc_nfca_alloc(void* context) { furi_assert(context); NfcRpc* instance = context; nfc_rpc_add_handler(instance, Nfc_Main_nfca_read_req_tag, nfc_rpc_nfca_read); + nfc_rpc_add_handler(instance, Nfc_Main_nfca_emulate_start_req_tag, nfc_rpc_nfca_emulate_start); + nfc_rpc_add_handler(instance, Nfc_Main_nfca_emulate_stop_req_tag, nfc_rpc_nfca_emulate_stop); } From 3aef20fc806212f0e10bbaec0fb27fa19d63934a Mon Sep 17 00:00:00 2001 From: gornekich Date: Wed, 29 Mar 2023 17:36:25 +0400 Subject: [PATCH 009/149] nfc rpc: add mf ultralight emulation handlers --- .../main/nfc_rpc/assets/compiled/main.pb.h | 8 +-- .../assets/compiled/mf_ultralight.pb.c | 4 +- .../assets/compiled/mf_ultralight.pb.h | 44 +++++++-------- .../main/nfc_rpc/assets/protobuf/main.proto | 4 +- .../assets/protobuf/mf_ultralight.proto | 4 +- applications/main/nfc_rpc/nfc_rpc_i.h | 3 ++ .../main/nfc_rpc/nfc_rpc_mf_ultralight.c | 53 +++++++++++++++++-- 7 files changed, 84 insertions(+), 36 deletions(-) diff --git a/applications/main/nfc_rpc/assets/compiled/main.pb.h b/applications/main/nfc_rpc/assets/compiled/main.pb.h index e7b812844993..c956c2badb01 100644 --- a/applications/main/nfc_rpc/assets/compiled/main.pb.h +++ b/applications/main/nfc_rpc/assets/compiled/main.pb.h @@ -51,8 +51,8 @@ typedef struct _Nfc_Main { PB_MfUltralight_ReadTearingFlagResponse mf_ultralight_read_tearing_flag_resp; PB_MfUltralight_EmulateStartRequest mf_ultralight_emulate_start_req; PB_MfUltralight_EmulateStartResponse mf_ultralight_emulate_start_resp; - PB_MfUltralight_EmulationStopRequest mf_ultralight_emulate_stop_req; - PB_MfUltralight_EmulationStopResponse mf_ultralight_emulate_stop_resp; + PB_MfUltralight_EmulateStopRequest mf_ultralight_emulate_stop_req; + PB_MfUltralight_EmulateStopResponse mf_ultralight_emulate_stop_resp; } content; } Nfc_Main; @@ -156,8 +156,8 @@ X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_emulate_stop_resp,cont #define Nfc_Main_content_mf_ultralight_read_tearing_flag_resp_MSGTYPE PB_MfUltralight_ReadTearingFlagResponse #define Nfc_Main_content_mf_ultralight_emulate_start_req_MSGTYPE PB_MfUltralight_EmulateStartRequest #define Nfc_Main_content_mf_ultralight_emulate_start_resp_MSGTYPE PB_MfUltralight_EmulateStartResponse -#define Nfc_Main_content_mf_ultralight_emulate_stop_req_MSGTYPE PB_MfUltralight_EmulationStopRequest -#define Nfc_Main_content_mf_ultralight_emulate_stop_resp_MSGTYPE PB_MfUltralight_EmulationStopResponse +#define Nfc_Main_content_mf_ultralight_emulate_stop_req_MSGTYPE PB_MfUltralight_EmulateStopRequest +#define Nfc_Main_content_mf_ultralight_emulate_stop_resp_MSGTYPE PB_MfUltralight_EmulateStopResponse extern const pb_msgdesc_t Nfc_Empty_msg; extern const pb_msgdesc_t Nfc_Main_msg; diff --git a/applications/main/nfc_rpc/assets/compiled/mf_ultralight.pb.c b/applications/main/nfc_rpc/assets/compiled/mf_ultralight.pb.c index 146685d328fe..a16a9020aaf3 100644 --- a/applications/main/nfc_rpc/assets/compiled/mf_ultralight.pb.c +++ b/applications/main/nfc_rpc/assets/compiled/mf_ultralight.pb.c @@ -48,10 +48,10 @@ PB_BIND(PB_MfUltralight_EmulateStartRequest, PB_MfUltralight_EmulateStartRequest PB_BIND(PB_MfUltralight_EmulateStartResponse, PB_MfUltralight_EmulateStartResponse, AUTO) -PB_BIND(PB_MfUltralight_EmulationStopRequest, PB_MfUltralight_EmulationStopRequest, AUTO) +PB_BIND(PB_MfUltralight_EmulateStopRequest, PB_MfUltralight_EmulateStopRequest, AUTO) -PB_BIND(PB_MfUltralight_EmulationStopResponse, PB_MfUltralight_EmulationStopResponse, AUTO) +PB_BIND(PB_MfUltralight_EmulateStopResponse, PB_MfUltralight_EmulateStopResponse, AUTO) diff --git a/applications/main/nfc_rpc/assets/compiled/mf_ultralight.pb.h b/applications/main/nfc_rpc/assets/compiled/mf_ultralight.pb.h index 56e89726df47..087ff3819553 100644 --- a/applications/main/nfc_rpc/assets/compiled/mf_ultralight.pb.h +++ b/applications/main/nfc_rpc/assets/compiled/mf_ultralight.pb.h @@ -98,13 +98,13 @@ typedef struct _PB_MfUltralight_EmulateStartResponse { PB_MfUltralight_Error error; } PB_MfUltralight_EmulateStartResponse; -typedef struct _PB_MfUltralight_EmulationStopRequest { +typedef struct _PB_MfUltralight_EmulateStopRequest { char dummy_field; -} PB_MfUltralight_EmulationStopRequest; +} PB_MfUltralight_EmulateStopRequest; -typedef struct _PB_MfUltralight_EmulationStopResponse { +typedef struct _PB_MfUltralight_EmulateStopResponse { PB_MfUltralight_Error error; -} PB_MfUltralight_EmulationStopResponse; +} PB_MfUltralight_EmulateStopResponse; #ifdef __cplusplus @@ -138,7 +138,7 @@ extern "C" { #define PB_MfUltralight_EmulateStartResponse_error_ENUMTYPE PB_MfUltralight_Error -#define PB_MfUltralight_EmulationStopResponse_error_ENUMTYPE PB_MfUltralight_Error +#define PB_MfUltralight_EmulateStopResponse_error_ENUMTYPE PB_MfUltralight_Error /* Initializer values for message structs */ @@ -156,8 +156,8 @@ extern "C" { #define PB_MfUltralight_ReadTearingFlagResponse_init_default {_PB_MfUltralight_Error_MIN, 0, {0, {0}}} #define PB_MfUltralight_EmulateStartRequest_init_default {{0, {0}}} #define PB_MfUltralight_EmulateStartResponse_init_default {_PB_MfUltralight_Error_MIN} -#define PB_MfUltralight_EmulationStopRequest_init_default {0} -#define PB_MfUltralight_EmulationStopResponse_init_default {_PB_MfUltralight_Error_MIN} +#define PB_MfUltralight_EmulateStopRequest_init_default {0} +#define PB_MfUltralight_EmulateStopResponse_init_default {_PB_MfUltralight_Error_MIN} #define PB_MfUltralight_ReadPageRequest_init_zero {0} #define PB_MfUltralight_ReadPageResponse_init_zero {_PB_MfUltralight_Error_MIN, 0, {0, {0}}} #define PB_MfUltralight_ReadVersionRequest_init_zero {0} @@ -172,8 +172,8 @@ extern "C" { #define PB_MfUltralight_ReadTearingFlagResponse_init_zero {_PB_MfUltralight_Error_MIN, 0, {0, {0}}} #define PB_MfUltralight_EmulateStartRequest_init_zero {{0, {0}}} #define PB_MfUltralight_EmulateStartResponse_init_zero {_PB_MfUltralight_Error_MIN} -#define PB_MfUltralight_EmulationStopRequest_init_zero {0} -#define PB_MfUltralight_EmulationStopResponse_init_zero {_PB_MfUltralight_Error_MIN} +#define PB_MfUltralight_EmulateStopRequest_init_zero {0} +#define PB_MfUltralight_EmulateStopResponse_init_zero {_PB_MfUltralight_Error_MIN} /* Field tags (for use in manual encoding/decoding) */ #define PB_MfUltralight_ReadPageRequest_page_tag 1 @@ -205,7 +205,7 @@ extern "C" { #define PB_MfUltralight_ReadTearingFlagResponse_data_tag 3 #define PB_MfUltralight_EmulateStartRequest_data_tag 1 #define PB_MfUltralight_EmulateStartResponse_error_tag 1 -#define PB_MfUltralight_EmulationStopResponse_error_tag 1 +#define PB_MfUltralight_EmulateStopResponse_error_tag 1 /* Struct field encoding specification for nanopb */ #define PB_MfUltralight_ReadPageRequest_FIELDLIST(X, a) \ @@ -295,15 +295,15 @@ X(a, STATIC, SINGULAR, UENUM, error, 1) #define PB_MfUltralight_EmulateStartResponse_CALLBACK NULL #define PB_MfUltralight_EmulateStartResponse_DEFAULT NULL -#define PB_MfUltralight_EmulationStopRequest_FIELDLIST(X, a) \ +#define PB_MfUltralight_EmulateStopRequest_FIELDLIST(X, a) \ -#define PB_MfUltralight_EmulationStopRequest_CALLBACK NULL -#define PB_MfUltralight_EmulationStopRequest_DEFAULT NULL +#define PB_MfUltralight_EmulateStopRequest_CALLBACK NULL +#define PB_MfUltralight_EmulateStopRequest_DEFAULT NULL -#define PB_MfUltralight_EmulationStopResponse_FIELDLIST(X, a) \ +#define PB_MfUltralight_EmulateStopResponse_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, UENUM, error, 1) -#define PB_MfUltralight_EmulationStopResponse_CALLBACK NULL -#define PB_MfUltralight_EmulationStopResponse_DEFAULT NULL +#define PB_MfUltralight_EmulateStopResponse_CALLBACK NULL +#define PB_MfUltralight_EmulateStopResponse_DEFAULT NULL extern const pb_msgdesc_t PB_MfUltralight_ReadPageRequest_msg; extern const pb_msgdesc_t PB_MfUltralight_ReadPageResponse_msg; @@ -319,8 +319,8 @@ extern const pb_msgdesc_t PB_MfUltralight_ReadTearingFlagRequest_msg; extern const pb_msgdesc_t PB_MfUltralight_ReadTearingFlagResponse_msg; extern const pb_msgdesc_t PB_MfUltralight_EmulateStartRequest_msg; extern const pb_msgdesc_t PB_MfUltralight_EmulateStartResponse_msg; -extern const pb_msgdesc_t PB_MfUltralight_EmulationStopRequest_msg; -extern const pb_msgdesc_t PB_MfUltralight_EmulationStopResponse_msg; +extern const pb_msgdesc_t PB_MfUltralight_EmulateStopRequest_msg; +extern const pb_msgdesc_t PB_MfUltralight_EmulateStopResponse_msg; /* Defines for backwards compatibility with code written before nanopb-0.4.0 */ #define PB_MfUltralight_ReadPageRequest_fields &PB_MfUltralight_ReadPageRequest_msg @@ -337,14 +337,14 @@ extern const pb_msgdesc_t PB_MfUltralight_EmulationStopResponse_msg; #define PB_MfUltralight_ReadTearingFlagResponse_fields &PB_MfUltralight_ReadTearingFlagResponse_msg #define PB_MfUltralight_EmulateStartRequest_fields &PB_MfUltralight_EmulateStartRequest_msg #define PB_MfUltralight_EmulateStartResponse_fields &PB_MfUltralight_EmulateStartResponse_msg -#define PB_MfUltralight_EmulationStopRequest_fields &PB_MfUltralight_EmulationStopRequest_msg -#define PB_MfUltralight_EmulationStopResponse_fields &PB_MfUltralight_EmulationStopResponse_msg +#define PB_MfUltralight_EmulateStopRequest_fields &PB_MfUltralight_EmulateStopRequest_msg +#define PB_MfUltralight_EmulateStopResponse_fields &PB_MfUltralight_EmulateStopResponse_msg /* Maximum encoded size of messages (where known) */ #define PB_MfUltralight_EmulateStartRequest_size 2051 #define PB_MfUltralight_EmulateStartResponse_size 2 -#define PB_MfUltralight_EmulationStopRequest_size 0 -#define PB_MfUltralight_EmulationStopResponse_size 2 +#define PB_MfUltralight_EmulateStopRequest_size 0 +#define PB_MfUltralight_EmulateStopResponse_size 2 #define PB_MfUltralight_ReadCounterRequest_size 6 #define PB_MfUltralight_ReadCounterResponse_size 13 #define PB_MfUltralight_ReadPageRequest_size 4 diff --git a/applications/main/nfc_rpc/assets/protobuf/main.proto b/applications/main/nfc_rpc/assets/protobuf/main.proto index e0ecdc2351c7..2ba8d16540ee 100644 --- a/applications/main/nfc_rpc/assets/protobuf/main.proto +++ b/applications/main/nfc_rpc/assets/protobuf/main.proto @@ -45,7 +45,7 @@ message Main { mf_ultralight_read_tearing_flag_resp = 20; .PB_MfUltralight.EmulateStartRequest mf_ultralight_emulate_start_req = 21; .PB_MfUltralight.EmulateStartResponse mf_ultralight_emulate_start_resp = 22; - .PB_MfUltralight.EmulationStopRequest mf_ultralight_emulate_stop_req = 23; - .PB_MfUltralight.EmulationStopResponse mf_ultralight_emulate_stop_resp = 24; + .PB_MfUltralight.EmulateStopRequest mf_ultralight_emulate_stop_req = 23; + .PB_MfUltralight.EmulateStopResponse mf_ultralight_emulate_stop_resp = 24; } } diff --git a/applications/main/nfc_rpc/assets/protobuf/mf_ultralight.proto b/applications/main/nfc_rpc/assets/protobuf/mf_ultralight.proto index 367b77996dab..959dd5be7c6b 100644 --- a/applications/main/nfc_rpc/assets/protobuf/mf_ultralight.proto +++ b/applications/main/nfc_rpc/assets/protobuf/mf_ultralight.proto @@ -70,6 +70,6 @@ message EmulateStartRequest { bytes data = 1; } message EmulateStartResponse { Error error = 1; } -message EmulationStopRequest {} +message EmulateStopRequest {} -message EmulationStopResponse { Error error = 1; } +message EmulateStopResponse { Error error = 1; } diff --git a/applications/main/nfc_rpc/nfc_rpc_i.h b/applications/main/nfc_rpc/nfc_rpc_i.h index c89dc4a6dd24..a06a18a722de 100644 --- a/applications/main/nfc_rpc/nfc_rpc_i.h +++ b/applications/main/nfc_rpc/nfc_rpc_i.h @@ -17,6 +17,8 @@ #include #include +#include +#include typedef void (*NfcRpcHandler)(Nfc_Main* cmd, void* context); @@ -50,6 +52,7 @@ struct NfcRpc { ViewDispatcher* view_dispatcher; View* view; NfcaListener* nfca_listener; + MfUltralightListener* mf_ul_listener; NfcRpcHandlerDict_t handlers; }; diff --git a/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c b/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c index 531566e4553e..80b9c2dcf05f 100644 --- a/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c +++ b/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c @@ -177,14 +177,53 @@ static void nfc_rpc_mf_ultralight_read_tearing_flag(Nfc_Main* cmd, void* context } cmd->content.mf_ultralight_read_tearing_flag_resp = pb_mf_ul_read_tearing_flag_resp; FURI_LOG_D( - TAG, - "Tearing flag %ld: %02X", - pb_mf_ul_read_tearing_flag_resp.flag_num, - data.data[0]); + TAG, "Tearing flag %ld: %02X", pb_mf_ul_read_tearing_flag_resp.flag_num, data.data[0]); mf_ultralight_poller_free(poller); } +void nfc_rpc_mf_ultralight_emulate_start(Nfc_Main* cmd, void* context) { + furi_assert(cmd); + furi_assert(context); + + FURI_LOG_I(TAG, "Mf Ultralight Emulation Started"); + NfcRpc* instance = context; + PB_MfUltralight_EmulateStartResponse pb_mf_ultralight_emulate_start_resp = + PB_MfUltralight_EmulateStartResponse_init_default; + cmd->command_status = Nfc_CommandStatus_OK; + cmd->which_content = Nfc_Main_mf_ultralight_emulate_start_resp_tag; + if(instance->mf_ul_listener == NULL) { + MfUltralightData mf_ul_data = {}; + instance->mf_ul_listener = mf_ultralight_listener_alloc(&mf_ul_data); + pb_mf_ultralight_emulate_start_resp.error = PB_MfUltralight_Error_None; + } else { + // TODO add Busy error + pb_mf_ultralight_emulate_start_resp.error = PB_MfUltralight_Error_NotPresent; + } + cmd->content.mf_ultralight_emulate_start_resp = pb_mf_ultralight_emulate_start_resp; +} + +void nfc_rpc_mf_ultralight_emulate_stop(Nfc_Main* cmd, void* context) { + furi_assert(cmd); + furi_assert(context); + + NfcRpc* instance = context; + PB_MfUltralight_EmulateStopResponse pb_mf_ultralight_emulate_stop_resp = + PB_MfUltralight_EmulateStopResponse_init_default; + cmd->command_status = Nfc_CommandStatus_OK; + cmd->which_content = Nfc_Main_mf_ultralight_emulate_stop_resp_tag; + if(instance->mf_ul_listener) { + // Stop before free + mf_ultralight_listener_free(instance->mf_ul_listener); + instance->mf_ul_listener = NULL; + pb_mf_ultralight_emulate_stop_resp.error = PB_MfUltralight_Error_None; + } else { + // TODO emulation not started error + pb_mf_ultralight_emulate_stop_resp.error = PB_MfUltralight_Error_NotPresent; + } + cmd->content.mf_ultralight_emulate_stop_resp = pb_mf_ultralight_emulate_stop_resp; +} + void nfc_rpc_mf_ultralight_alloc(void* context) { furi_assert(context); @@ -205,4 +244,10 @@ void nfc_rpc_mf_ultralight_alloc(void* context) { instance, Nfc_Main_mf_ultralight_read_tearing_flag_req_tag, nfc_rpc_mf_ultralight_read_tearing_flag); + nfc_rpc_add_handler( + instance, + Nfc_Main_mf_ultralight_emulate_start_req_tag, + nfc_rpc_mf_ultralight_emulate_start); + nfc_rpc_add_handler( + instance, Nfc_Main_mf_ultralight_emulate_stop_req_tag, nfc_rpc_mf_ultralight_emulate_stop); } From 2ebd7f39c156a6cb2b914287c556bfd98de82ef3 Mon Sep 17 00:00:00 2001 From: gornekich Date: Wed, 29 Mar 2023 20:00:56 +0400 Subject: [PATCH 010/149] nfc: fix rpc max size --- .../main/nfc_rpc/nfc_rpc_mf_ultralight.c | 1 - applications/services/rpc/rpc.c | 2 +- lib/nfc/protocols/mf_ultralight_common.h | 21 +++++++++++++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c b/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c index 80b9c2dcf05f..ba83460b7abd 100644 --- a/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c +++ b/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c @@ -186,7 +186,6 @@ void nfc_rpc_mf_ultralight_emulate_start(Nfc_Main* cmd, void* context) { furi_assert(cmd); furi_assert(context); - FURI_LOG_I(TAG, "Mf Ultralight Emulation Started"); NfcRpc* instance = context; PB_MfUltralight_EmulateStartResponse pb_mf_ultralight_emulate_start_resp = PB_MfUltralight_EmulateStartResponse_init_default; diff --git a/applications/services/rpc/rpc.c b/applications/services/rpc/rpc.c index 63a71ad06d69..c083e4ed4a29 100644 --- a/applications/services/rpc/rpc.c +++ b/applications/services/rpc/rpc.c @@ -244,7 +244,7 @@ static int32_t rpc_session_worker(void* context) { .callback = rpc_pb_stream_read, .state = session, .errmsg = NULL, - .bytes_left = RPC_MAX_MESSAGE_SIZE, /* max incoming message size */ + .bytes_left = SIZE_MAX, /* max incoming message size */ }; bool message_decode_failed = false; diff --git a/lib/nfc/protocols/mf_ultralight_common.h b/lib/nfc/protocols/mf_ultralight_common.h index edc98d615c57..fe1e065411e4 100644 --- a/lib/nfc/protocols/mf_ultralight_common.h +++ b/lib/nfc/protocols/mf_ultralight_common.h @@ -30,6 +30,27 @@ typedef enum { MfUltralightErrorTimeout, } MfUltralightError; +typedef enum { + MfUltralightTypeUnknown, + MfUltralightTypeNTAG203, + // Below have config pages and GET_VERSION support + MfUltralightTypeUL11, + MfUltralightTypeUL21, + MfUltralightTypeNTAG213, + MfUltralightTypeNTAG215, + MfUltralightTypeNTAG216, + // Below also have sector select + // NTAG I2C's *does not* have regular config pages, so it's a bit of an odd duck + MfUltralightTypeNTAGI2C1K, + MfUltralightTypeNTAGI2C2K, + // NTAG I2C Plus has stucture expected from NTAG21x + MfUltralightTypeNTAGI2CPlus1K, + MfUltralightTypeNTAGI2CPlus2K, + + // Keep last for number of types calculation + MfUltralightTypeNum, +} MfUltralightType; + typedef struct { uint8_t data[MF_ULTRALIGHT_PAGE_SIZE]; } MfUltralightPage; From e5f620ba47096d0fbd8e70119015bfe520a0eb0b Mon Sep 17 00:00:00 2001 From: gornekich Date: Thu, 30 Mar 2023 20:14:32 +0400 Subject: [PATCH 011/149] nfc: introduce emulation worker --- firmware/targets/f7/api_symbols.csv | 4 +- firmware/targets/f7/furi_hal/f_hal_nfc.c | 16 +- .../targets/f7/furi_hal/f_hal_nfc_event.c | 21 ++- firmware/targets/f7/furi_hal/f_hal_nfc_i.h | 5 +- firmware/targets/f7/furi_hal/furi_hal_nfc.h | 2 +- firmware/targets/furi_hal_include/f_hal_nfc.h | 14 +- lib/nfc/nfc.c | 88 +++++++++-- lib/nfc/nfc.h | 29 +++- lib/nfc/protocols/mf_ultralight_common.h | 2 +- lib/nfc/protocols/mifare_classic.c | 2 +- lib/nfc/protocols/nfca.c | 128 ++-------------- lib/nfc/protocols/nfca.h | 72 +++++++-- lib/nfc/protocols/nfca_common.h | 63 -------- lib/nfc/protocols/nfca_listener.c | 69 ++++++++- lib/nfc/protocols/nfca_listener.h | 30 +++- lib/nfc/protocols/nfca_poller.c | 31 +--- lib/nfc/protocols/nfca_poller.h | 2 +- lib/nfc/protocols/nfca_utils.c | 142 ++++++++++++++++++ lib/nfc/protocols/nfca_utils.h | 28 ++++ 19 files changed, 469 insertions(+), 279 deletions(-) delete mode 100644 lib/nfc/protocols/nfca_common.h create mode 100644 lib/nfc/protocols/nfca_utils.c create mode 100644 lib/nfc/protocols/nfca_utils.h diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 88c449d87e7e..614027622a50 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,+,20.0,, +Version,+,20.1,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -815,7 +815,9 @@ Function,-,explicit_bzero,void,"void*, size_t" Function,-,expm1,double,double Function,-,expm1f,float,float Function,-,expm1l,long double,long double +Function,-,f_hal_nfc_abort,FHalNfcError, Function,-,f_hal_nfc_init,FHalNfcError, +Function,-,f_hal_nfc_listener_sleep,FHalNfcError, Function,-,f_hal_nfc_listen_start,FHalNfcError, Function,-,f_hal_nfc_low_power_mode_start,FHalNfcError, Function,-,f_hal_nfc_low_power_mode_stop,FHalNfcError, diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc.c b/firmware/targets/f7/furi_hal/f_hal_nfc.c index afd8c1f23c7c..430024bf37c9 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfc.c +++ b/firmware/targets/f7/furi_hal/f_hal_nfc.c @@ -204,12 +204,6 @@ FHalNfcError f_hal_nfc_init() { return error; } -void f_hal_nfc_set_callback(FHalNfcCallback callback, void* context) { - furi_assert(callback); - - f_hal_nfc_event_set_callback(callback, context); -} - FHalNfcError f_hal_nfc_low_power_mode_start() { FHalNfcError error = FHalNfcErrorNone; FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; @@ -428,6 +422,16 @@ FHalNfcError f_hal_nfc_listen_start() { return FHalNfcErrorNone; } +FHalNfcError f_hal_nfc_listener_sleep() { + FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; + furi_hal_spi_acquire(handle); + + st25r3916_direct_cmd(handle, ST25R3916_CMD_GOTO_SLEEP); + + furi_hal_spi_release(handle); + return FHalNfcErrorNone; +} + void f_hal_nfc_set_mask_receive_timer(uint32_t time_fc) { FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; furi_hal_spi_acquire(handle); diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc_event.c b/firmware/targets/f7/furi_hal/f_hal_nfc_event.c index 352e056cf186..fa5d47fa68f5 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfc_event.c +++ b/firmware/targets/f7/furi_hal/f_hal_nfc_event.c @@ -6,14 +6,6 @@ void f_hal_nfc_event_init() { f_hal_nfc_event = malloc(sizeof(FHalNfcEventInternal)); } -void f_hal_nfc_event_set_callback(FHalNfcCallback callback, void* context) { - furi_assert(f_hal_nfc_event); - furi_assert(callback); - - f_hal_nfc_event->callback = callback; - f_hal_nfc_event->context = context; -} - void f_hal_nfc_set_event(FHalNfcEventInternalType event) { furi_assert(f_hal_nfc_event); furi_assert(f_hal_nfc_event->thread); @@ -21,6 +13,11 @@ void f_hal_nfc_set_event(FHalNfcEventInternalType event) { furi_thread_flags_set(f_hal_nfc_event->thread, event); } +FHalNfcError f_hal_nfc_abort() { + f_hal_nfc_set_event(FHalNfcEventInternalTypeAbort); + return FHalNfcErrorNone; +} + FHalNfcEvent f_hal_nfc_wait_event(uint32_t timeout_ms) { furi_assert(f_hal_nfc_event); @@ -35,7 +32,7 @@ FHalNfcEvent f_hal_nfc_wait_event(uint32_t timeout_ms) { uint32_t event_timeout = timeout_ms == F_HAL_NFC_EVENT_WAIT_FOREVER ? FuriWaitForever : timeout_ms; uint32_t event_flag = furi_thread_flags_wait( - FHalNfcEventInternalAbort | FHalNfcEventInternalTypeIrq | + FHalNfcEventInternalTypeAbort | FHalNfcEventInternalTypeIrq | FHalNfcEventInternalTypeTimerFwtExpired | FHalNfcEventInternalTypeTimerBlockTxExpired, FuriFlagWaitAny, event_timeout); @@ -74,7 +71,7 @@ FHalNfcEvent f_hal_nfc_wait_event(uint32_t timeout_ms) { if(irq & ST25R3916_IRQ_MASK_WU_A_X) { event |= FHalNfcEventListenerActiveA; } - } + } if(event_flag & FHalNfcEventInternalTypeTimerFwtExpired) { event |= FHalNfcEventTimerFwtExpired; furi_thread_flags_clear(FHalNfcEventInternalTypeTimerFwtExpired); @@ -83,9 +80,9 @@ FHalNfcEvent f_hal_nfc_wait_event(uint32_t timeout_ms) { event |= FHalNfcEventTimerBlockTxExpired; furi_thread_flags_clear(FHalNfcEventInternalTypeTimerBlockTxExpired); } - if(event_flag & FHalNfcEventInternalAbort) { + if(event_flag & FHalNfcEventInternalTypeAbort) { event |= FHalNfcEventAbortRequest; - furi_thread_flags_clear(FHalNfcEventInternalAbort); + furi_thread_flags_clear(FHalNfcEventInternalTypeAbort); } } else { event = FHalNfcEventTimeout; diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc_i.h b/firmware/targets/f7/furi_hal/f_hal_nfc_i.h index 3b0ce5ed135e..737ab7ba0e41 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfc_i.h +++ b/firmware/targets/f7/furi_hal/f_hal_nfc_i.h @@ -11,7 +11,7 @@ extern "C" { #endif typedef enum { - FHalNfcEventInternalAbort = (1U << 0), + FHalNfcEventInternalTypeAbort = (1U << 0), FHalNfcEventInternalTypeIrq = (1U << 1), FHalNfcEventInternalTypeTimerFwtExpired = (1U << 2), FHalNfcEventInternalTypeTimerBlockTxExpired = (1U << 3), @@ -19,7 +19,6 @@ typedef enum { typedef struct { FuriThreadId thread; - FHalNfcCallback callback; void* context; } FHalNfcEventInternal; @@ -27,8 +26,6 @@ extern FHalNfcEventInternal* f_hal_nfc; void f_hal_nfc_event_init(); -void f_hal_nfc_event_set_callback(FHalNfcCallback callback, void* context); - void f_hal_nfc_set_event(FHalNfcEventInternalType event); void f_hal_nfc_init_gpio_isr(); diff --git a/firmware/targets/f7/furi_hal/furi_hal_nfc.h b/firmware/targets/f7/furi_hal/furi_hal_nfc.h index dc3f873f3460..69f3c47b4e8c 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_nfc.h +++ b/firmware/targets/f7/furi_hal/furi_hal_nfc.h @@ -13,7 +13,7 @@ extern "C" { #endif #include -#include +#include #define FURI_HAL_NFC_UID_MAX_LEN 10 #define FURI_HAL_NFC_DATA_BUFF_SIZE (512) diff --git a/firmware/targets/furi_hal_include/f_hal_nfc.h b/firmware/targets/furi_hal_include/f_hal_nfc.h index a4babe6a25c2..5c612039ce7e 100644 --- a/firmware/targets/furi_hal_include/f_hal_nfc.h +++ b/firmware/targets/furi_hal_include/f_hal_nfc.h @@ -28,8 +28,6 @@ typedef enum { FHalNfcEventAbortRequest = (1U << 13), } FHalNfcEvent; -typedef void (*FHalNfcCallback)(FHalNfcEvent event, void* context); - typedef enum { FHalNfcErrorNone, FHalNfcErrorChipCommunication, @@ -61,14 +59,6 @@ typedef enum { */ FHalNfcError f_hal_nfc_init(); -/** - * @brief Set Nfc HAL event callback - * - * @param callback - * @param context - */ -void f_hal_nfc_set_callback(FHalNfcCallback callback, void* context); - /** * @brief Start Nfc hardware low power mode * @@ -110,6 +100,10 @@ FHalNfcError f_hal_nfc_trx_reset(); FHalNfcError f_hal_nfc_listen_start(); +FHalNfcError f_hal_nfc_listener_sleep(); + +FHalNfcError f_hal_nfc_abort(); + FHalNfcEvent f_hal_nfc_wait_event(uint32_t timeout_ms); void f_hal_nfc_timer_fwt_start(uint32_t time_fc); diff --git a/lib/nfc/nfc.c b/lib/nfc/nfc.c index 3ec05ed812c9..ed63b36cb8e9 100644 --- a/lib/nfc/nfc.c +++ b/lib/nfc/nfc.c @@ -12,6 +12,8 @@ typedef enum { NfcStateChipActive, NfcStateFieldOn, NfcStateFieldOff, + + NfcStateListenStarted, } NfcState; typedef enum { @@ -34,6 +36,8 @@ struct Nfc { uint32_t guard_time_us; NfcEventCallback callback; void* context; + + FuriThread* worker_thread; }; static NfcError nfc_process_hal_error(FHalNfcError error) { @@ -48,39 +52,73 @@ static NfcError nfc_process_hal_error(FHalNfcError error) { return err; } -static void nfc_hal_event_handler(FHalNfcEvent event, void* context) { +static int32_t nfc_worker(void* context) { furi_assert(context); Nfc* instance = context; + uint8_t rx_data[256]; + uint16_t rx_bits = 0; - if(instance->callback) { - if(event == FHalNfcEventFieldOn) { - instance->callback(NfcEventFieldOn, instance->context); - } else if(event == FHalNfcEventTxStart) { - instance->callback(NfcEventTxStart, instance->context); - } else if(event == FHalNfcEventTxEnd) { - instance->callback(NfcEventTxEnd, instance->context); - } else if(event == FHalNfcEventRxStart) { - instance->callback(NfcEventRxStart, instance->context); - } else if(event == FHalNfcEventRxEnd) { - instance->callback(NfcEventRxEnd, instance->context); + f_hal_nfc_listen_start(); + NfcEvent nfc_event = {}; + while(true) { + FHalNfcEvent event = f_hal_nfc_wait_event(F_HAL_NFC_EVENT_WAIT_FOREVER); + if(event & FHalNfcEventAbortRequest) { + FURI_LOG_D(TAG, "Abort request received"); + nfc_event.type = NfcEventTypeUserAbort; + instance->callback(nfc_event, instance->context); + break; + } + if(event & FHalNfcEventFieldOn) { + nfc_event.type = NfcEventTypeFieldOn; + instance->callback(nfc_event, instance->context); + } + if(event & FHalNfcEventFieldOff) { + FURI_LOG_D(TAG, "Field off"); + nfc_event.type = NfcEventTypeFieldOff; + instance->callback(nfc_event, instance->context); + f_hal_nfc_listener_sleep(); + } + if(event & FHalNfcEventListenerActive) { + nfc_event.type = NfcEventTypeListenerActivated; + instance->callback(nfc_event, instance->context); + } + if(event & FHalNfcEventRxEnd) { + nfc_event.type = NfcEventTypeRxEnd; + f_hal_nfc_poller_rx(rx_data, sizeof(rx_data), &rx_bits); + nfc_event.data.rx_data = rx_data; + nfc_event.data.rx_bits = rx_bits; + // TODO start block TX timer + instance->callback(nfc_event, instance->context); } } + + return 0; } Nfc* nfc_alloc() { Nfc* instance = malloc(sizeof(Nfc)); instance->state = NfcStateIdle; - f_hal_nfc_set_callback(nfc_hal_event_handler, instance); f_hal_nfc_low_power_mode_stop(); instance->state = NfcStateChipActive; + instance->worker_thread = furi_thread_alloc(); + furi_thread_set_name(instance->worker_thread, "NfcWorker"); + furi_thread_set_callback(instance->worker_thread, nfc_worker); + furi_thread_set_context(instance->worker_thread, instance); + furi_thread_set_priority(instance->worker_thread, FuriThreadPriorityHighest); + furi_thread_set_stack_size(instance->worker_thread, 2048); + return instance; } void nfc_free(Nfc* instance) { furi_assert(instance); + if(instance->state == NfcStateListenStarted) { + f_hal_nfc_abort(); + furi_thread_join(instance->worker_thread); + } + furi_thread_free(instance->worker_thread); f_hal_nfc_low_power_mode_start(); - f_hal_nfc_set_callback(NULL, NULL); free(instance); } @@ -362,6 +400,28 @@ NfcError nfc_iso13444a_sdd_frame( return ret; } +void nfc_listener_start(Nfc* instance, NfcEventCallback callback, void* context) { + furi_assert(instance); + furi_assert(instance->state == NfcStateConfigured); + furi_assert(instance->worker_thread); + furi_assert(callback); + + instance->callback = callback; + instance->context = context; + furi_thread_start(instance->worker_thread); + instance->state = NfcStateListenStarted; + instance->comm_state = NfcCommStateIdle; +} + +NfcError nfc_listener_sleep(Nfc* instance) { + furi_assert(instance); + furi_assert(instance->state == NfcStateListenStarted); + + f_hal_nfc_listener_sleep(); + + return NfcErrorNone; +} + NfcError nfc_listener_rx( Nfc* instance, uint8_t* rx_data, diff --git a/lib/nfc/nfc.h b/lib/nfc/nfc.h index e4cc01b5c774..93503737b34d 100644 --- a/lib/nfc/nfc.h +++ b/lib/nfc/nfc.h @@ -9,12 +9,25 @@ extern "C" { typedef struct Nfc Nfc; typedef enum { - NfcEventFieldOn, - NfcEventTxStart, - NfcEventTxEnd, - NfcEventRxStart, - NfcEventRxEnd, - NfcEventRxTimeout, + NfcEventTypeUserAbort, + NfcEventTypeFieldOn, + NfcEventTypeFieldOff, + NfcEventTypeTxStart, + NfcEventTypeTxEnd, + NfcEventTypeRxStart, + NfcEventTypeRxEnd, + + NfcEventTypeListenerActivated, +} NfcEventType; + +typedef struct { + uint8_t* rx_data; + uint16_t rx_bits; +} NfcEventData; + +typedef struct { + NfcEventType type; + NfcEventData data; } NfcEvent; typedef void (*NfcEventCallback)(NfcEvent event, void* context); @@ -64,6 +77,10 @@ NfcError nfc_listener_set_col_res_data( uint8_t* atqa, uint8_t sak); +void nfc_listener_start(Nfc* instance, NfcEventCallback callback, void* context); + +NfcError nfc_listener_sleep(Nfc* instance); + NfcError nfc_listener_rx( Nfc* instance, uint8_t* rx_data, diff --git a/lib/nfc/protocols/mf_ultralight_common.h b/lib/nfc/protocols/mf_ultralight_common.h index fe1e065411e4..3d54263b8105 100644 --- a/lib/nfc/protocols/mf_ultralight_common.h +++ b/lib/nfc/protocols/mf_ultralight_common.h @@ -1,6 +1,6 @@ #pragma once -#include "nfca_common.h" +#include "nfca.h" #ifdef __cplusplus extern "C" { diff --git a/lib/nfc/protocols/mifare_classic.c b/lib/nfc/protocols/mifare_classic.c index d2d7467dce09..4975a78b9718 100644 --- a/lib/nfc/protocols/mifare_classic.c +++ b/lib/nfc/protocols/mifare_classic.c @@ -1,5 +1,5 @@ #include "mifare_classic.h" -#include "nfca.h" +#include "nfca_utils.h" #include "nfc_util.h" #include diff --git a/lib/nfc/protocols/nfca.c b/lib/nfc/protocols/nfca.c index c401f8cc5872..9e1e5513e6f0 100644 --- a/lib/nfc/protocols/nfca.c +++ b/lib/nfc/protocols/nfca.c @@ -1,30 +1,12 @@ #include "nfca.h" -#include -#include -#include -#define NFCA_CMD_RATS (0xE0U) +#include #define NFCA_CRC_INIT (0x6363) -#define NFCA_F_SIG (13560000.0) -#define T_SIG 7374 //73.746ns*100 -#define T_SIG_x8 58992 //T_SIG*8 -#define T_SIG_x8_x8 471936 //T_SIG*8*8 -#define T_SIG_x8_x9 530928 //T_SIG*8*9 - -#define NFCA_SIGNAL_MAX_EDGES (1350) - -typedef struct { - uint8_t cmd; - uint8_t param; -} nfca_cmd_rats; +uint16_t nfca_get_crc(uint8_t* buff, uint16_t len) { + furi_assert(buff); -static uint8_t nfca_default_ats[] = {0x05, 0x78, 0x80, 0x80, 0x00}; - -static uint8_t nfca_sleep_req[] = {0x50, 0x00}; - -uint16_t nfca_get_crc16(uint8_t* buff, uint16_t len) { uint16_t crc = NFCA_CRC_INIT; uint8_t byte = 0; @@ -39,104 +21,22 @@ uint16_t nfca_get_crc16(uint8_t* buff, uint16_t len) { return crc; } -void nfca_append_crc16(uint8_t* buff, uint16_t len) { - uint16_t crc = nfca_get_crc16(buff, len); +void nfca_append_crc(uint8_t* buff, uint16_t len) { + furi_assert(buff); + + uint16_t crc = nfca_get_crc(buff, len); buff[len] = (uint8_t)crc; buff[len + 1] = (uint8_t)(crc >> 8); } -bool nfca_emulation_handler( - uint8_t* buff_rx, - uint16_t buff_rx_len, - uint8_t* buff_tx, - uint16_t* buff_tx_len) { - bool sleep = false; - uint8_t rx_bytes = buff_rx_len / 8; +bool nfca_check_crc(uint8_t* buff, uint16_t len) { + bool crc_ok = false; - if(rx_bytes == sizeof(nfca_sleep_req) && !memcmp(buff_rx, nfca_sleep_req, rx_bytes)) { - sleep = true; - } else if(rx_bytes == sizeof(nfca_cmd_rats) && buff_rx[0] == NFCA_CMD_RATS) { - memcpy(buff_tx, nfca_default_ats, sizeof(nfca_default_ats)); - *buff_tx_len = sizeof(nfca_default_ats) * 8; + if(len > 2) { + uint16_t crc_calc = nfca_get_crc(buff, len - 2); + uint16_t crc_received = (buff[len - 1] << 8) | buff[len - 2]; + crc_ok = (crc_calc == crc_received); } - return sleep; -} - -static void nfca_add_bit(DigitalSignal* signal, bool bit) { - if(bit) { - signal->start_level = true; - for(size_t i = 0; i < 7; i++) { - signal->edge_timings[i] = T_SIG_x8; - } - signal->edge_timings[7] = T_SIG_x8_x9; - signal->edge_cnt = 8; - } else { - signal->start_level = false; - signal->edge_timings[0] = T_SIG_x8_x8; - for(size_t i = 1; i < 9; i++) { - signal->edge_timings[i] = T_SIG_x8; - } - signal->edge_cnt = 9; - } -} - -static void nfca_add_byte(NfcaSignal* nfca_signal, uint8_t byte, bool parity) { - for(uint8_t i = 0; i < 8; i++) { - if(byte & (1 << i)) { - digital_signal_append(nfca_signal->tx_signal, nfca_signal->one); - } else { - digital_signal_append(nfca_signal->tx_signal, nfca_signal->zero); - } - } - if(parity) { - digital_signal_append(nfca_signal->tx_signal, nfca_signal->one); - } else { - digital_signal_append(nfca_signal->tx_signal, nfca_signal->zero); - } -} - -NfcaSignal* nfca_signal_alloc() { - NfcaSignal* nfca_signal = malloc(sizeof(NfcaSignal)); - nfca_signal->one = digital_signal_alloc(10); - nfca_signal->zero = digital_signal_alloc(10); - nfca_add_bit(nfca_signal->one, true); - nfca_add_bit(nfca_signal->zero, false); - nfca_signal->tx_signal = digital_signal_alloc(NFCA_SIGNAL_MAX_EDGES); - - return nfca_signal; -} - -void nfca_signal_free(NfcaSignal* nfca_signal) { - furi_assert(nfca_signal); - - digital_signal_free(nfca_signal->one); - digital_signal_free(nfca_signal->zero); - digital_signal_free(nfca_signal->tx_signal); - free(nfca_signal); -} - -void nfca_signal_encode(NfcaSignal* nfca_signal, uint8_t* data, uint16_t bits, uint8_t* parity) { - furi_assert(nfca_signal); - furi_assert(data); - furi_assert(parity); - - nfca_signal->tx_signal->edge_cnt = 0; - nfca_signal->tx_signal->start_level = true; - // Start of frame - digital_signal_append(nfca_signal->tx_signal, nfca_signal->one); - - if(bits < 8) { - for(size_t i = 0; i < bits; i++) { - if(FURI_BIT(data[0], i)) { - digital_signal_append(nfca_signal->tx_signal, nfca_signal->one); - } else { - digital_signal_append(nfca_signal->tx_signal, nfca_signal->zero); - } - } - } else { - for(size_t i = 0; i < bits / 8; i++) { - nfca_add_byte(nfca_signal, data[i], parity[i / 8] & (1 << (7 - (i & 0x07)))); - } - } + return crc_ok; } diff --git a/lib/nfc/protocols/nfca.h b/lib/nfc/protocols/nfca.h index 498ef28431c2..18d07102b2e1 100644 --- a/lib/nfc/protocols/nfca.h +++ b/lib/nfc/protocols/nfca.h @@ -3,26 +3,68 @@ #include #include -#include +#ifdef __cplusplus +extern "C" { +#endif + +#define NFCA_MAX_UID_SIZE (10U) + +#define NFCA_GUARD_TIME_US (5000) +#define NFCA_FDT_POLL_FC (1620) +#define NFCA_FDT_LISTEN_FC (1172) +#define NFCA_POLLER_MASK_RX_FS ((NFCA_FDT_LISTEN_FC) / 2) +#define NFCA_POLL_POLL_MIN_US (1100) + +typedef enum { + NfcaErrorNone, + NfcaErrorNotPresent, + NfcaErrorColResFailed, + NfcaErrorBufferOverflow, + NfcaErrorCommunication, + NfcaErrorFieldOff, + NfcaErrorWrongCrc, + NfcaErrorTimeout, +} NfcaError; typedef struct { - DigitalSignal* one; - DigitalSignal* zero; - DigitalSignal* tx_signal; -} NfcaSignal; + uint8_t sens_resp[2]; +} NfcaSensResp; -uint16_t nfca_get_crc16(uint8_t* buff, uint16_t len); +typedef struct { + uint8_t sel_cmd; + uint8_t sel_par; + uint8_t data[4]; // max data bit is 32 +} NfcaSddReq; + +typedef struct { + uint8_t nfcid[4]; + uint8_t bss; +} NfcaSddResp; -void nfca_append_crc16(uint8_t* buff, uint16_t len); +typedef struct { + uint8_t sel_cmd; + uint8_t sel_par; + uint8_t nfcid[4]; + uint8_t bcc; +} NfcaSelReq; + +typedef struct { + uint8_t sak; +} NfcaSelResp; + +typedef struct { + uint8_t uid[NFCA_MAX_UID_SIZE]; + uint8_t uid_len; + uint8_t atqa[2]; + uint8_t sak; +} NfcaData; -bool nfca_emulation_handler( - uint8_t* buff_rx, - uint16_t buff_rx_len, - uint8_t* buff_tx, - uint16_t* buff_tx_len); +uint16_t nfca_get_crc(uint8_t* buff, uint16_t len); -NfcaSignal* nfca_signal_alloc(); +void nfca_append_crc(uint8_t* buff, uint16_t len); -void nfca_signal_free(NfcaSignal* nfca_signal); +bool nfca_check_crc(uint8_t* buff, uint16_t len); -void nfca_signal_encode(NfcaSignal* nfca_signal, uint8_t* data, uint16_t bits, uint8_t* parity); +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/nfca_common.h b/lib/nfc/protocols/nfca_common.h deleted file mode 100644 index b225f0cccbff..000000000000 --- a/lib/nfc/protocols/nfca_common.h +++ /dev/null @@ -1,63 +0,0 @@ -#pragma once - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define NFCA_MAX_UID_SIZE (10U) - -#define NFCA_GUARD_TIME_US (5000) -#define NFCA_FDT_POLL_FC (1620) -#define NFCA_FDT_LISTEN_FC (1172) -#define NFCA_POLLER_MASK_RX_FS ((NFCA_FDT_LISTEN_FC) / 2) -#define NFCA_POLL_POLL_MIN_US (1100) - -typedef enum { - NfcaErrorNone, - NfcaErrorNotPresent, - NfcaErrorColResFailed, - NfcaErrorBufferOverflow, - NfcaErrorCommunication, - NfcaErrorFieldOff, - NfcaErrorWrongCrc, - NfcaErrorTimeout, -} NfcaError; - -typedef struct { - uint8_t sens_resp[2]; -} NfcaSensResp; - -typedef struct { - uint8_t sel_cmd; - uint8_t sel_par; - uint8_t data[4]; // max data bit is 32 -} NfcaSddReq; - -typedef struct { - uint8_t nfcid[4]; - uint8_t bss; -} NfcaSddResp; - -typedef struct { - uint8_t sel_cmd; - uint8_t sel_par; - uint8_t nfcid[4]; - uint8_t bcc; -} NfcaSelReq; - -typedef struct { - uint8_t sak; -} NfcaSelResp; - -typedef struct { - uint8_t uid[NFCA_MAX_UID_SIZE]; - uint8_t uid_len; - uint8_t atqa[2]; - uint8_t sak; -} NfcaData; - -#ifdef __cplusplus -} -#endif diff --git a/lib/nfc/protocols/nfca_listener.c b/lib/nfc/protocols/nfca_listener.c index 1db99bca1a1e..cf69af9e82cd 100644 --- a/lib/nfc/protocols/nfca_listener.c +++ b/lib/nfc/protocols/nfca_listener.c @@ -7,7 +7,6 @@ typedef enum { NfcaListenerStateIdle, - NfcaListenerStateColResInProgress, NfcaListenerStateActive, } NfcaListenerState; @@ -15,6 +14,8 @@ struct NfcaListener { Nfc* nfc; NfcaData data; NfcaListenerState state; + NfcaListenerCallback callback; + void* context; }; static NfcaError nfca_listener_process_nfc_error(NfcError error) { @@ -31,6 +32,50 @@ static NfcaError nfca_listener_process_nfc_error(NfcError error) { return ret; } +static bool nfca_listener_halt_received(uint8_t* rx_data, uint16_t rx_bits) { + bool halt_cmd_received = false; + + do { + if(rx_bits != 4 * 8) break; + uint16_t rx_bytes = rx_bits / 8; + if(!nfca_check_crc(rx_data, rx_bytes)) break; + if(!((rx_data[0] == 0x50) && (rx_data[1] == 0x00))) break; + halt_cmd_received = true; + } while(false); + + return halt_cmd_received; +} + +static void nfca_listener_event_handler(NfcEvent event, void* context) { + furi_assert(context); + + NfcaListener* instance = context; + NfcEventType event_type = event.type; + NfcaListenerEvent nfca_listener_event = {}; + if(event_type == NfcEventTypeListenerActivated) { + instance->state = NfcaListenerStateActive; + } else if(event_type == NfcEventTypeRxEnd) { + if(nfca_listener_halt_received(event.data.rx_data, event.data.rx_bits)) { + nfca_listener_sleep(instance); + instance->state = NfcaListenerStateIdle; + if(instance->callback) { + nfca_listener_event.type = NfcaListenerEventTypeHalted; + instance->callback(nfca_listener_event, instance->context); + } + } else if(instance->callback) { + nfca_listener_event.data.rx_data = event.data.rx_data; + if(nfca_check_crc(event.data.rx_data, event.data.rx_bits / 8)) { + nfca_listener_event.type = NfcaListenerEventTypeReceivedStandartFrame; + nfca_listener_event.data.rx_bits = event.data.rx_bits - 16; + } else { + nfca_listener_event.type = NfcaListenerEventTypeReceivedData; + nfca_listener_event.data.rx_bits = event.data.rx_bits; + } + instance->callback(nfca_listener_event, instance->context); + } + } +} + NfcaListener* nfca_listener_alloc(NfcaData* data) { NfcaListener* instance = malloc(sizeof(NfcaListener)); instance->data = *data; @@ -43,6 +88,7 @@ NfcaListener* nfca_listener_alloc(NfcaData* data) { instance->data.uid_len, instance->data.atqa, instance->data.sak); + nfc_listener_start(instance->nfc, nfca_listener_event_handler, instance); return instance; } @@ -53,6 +99,27 @@ void nfca_listener_free(NfcaListener* instance) { free(instance); } +NfcaError nfca_listener_set_callback( + NfcaListener* instance, + NfcaListenerCallback callback, + void* context) { + furi_assert(instance); + furi_assert(callback); + + instance->callback = callback; + instance->context = context; + + return NfcaErrorNone; +} + +NfcaError nfca_listener_sleep(NfcaListener* instance) { + furi_assert(instance); + + NfcError error = nfc_listener_sleep(instance->nfc); + + return nfca_listener_process_nfc_error(error); +} + NfcaError nfca_listener_rx( NfcaListener* instance, uint8_t* rx_data, diff --git a/lib/nfc/protocols/nfca_listener.h b/lib/nfc/protocols/nfca_listener.h index c1097b2c1fa6..5efec973781a 100644 --- a/lib/nfc/protocols/nfca_listener.h +++ b/lib/nfc/protocols/nfca_listener.h @@ -1,6 +1,6 @@ #pragma once -#include "nfca_common.h" +#include "nfca.h" #ifdef __cplusplus extern "C" { @@ -8,10 +8,38 @@ extern "C" { typedef struct NfcaListener NfcaListener; +typedef enum { + NfcaListenerEventTypeAbort, + NfcaListenerEventTypeFieldOn, + NfcaListenerEventTypeFieldOff, + NfcaListenerEventTypeHalted, + NfcaListenerEventTypeReceivedStandartFrame, + NfcaListenerEventTypeReceivedData, +} NfcaListenerEventType; + +typedef struct { + uint8_t* rx_data; + uint16_t rx_bits; +} NfcaListenerEventData; + +typedef struct { + NfcaListenerEventType type; + NfcaListenerEventData data; +} NfcaListenerEvent; + +typedef void (*NfcaListenerCallback)(NfcaListenerEvent event, void* context); + NfcaListener* nfca_listener_alloc(NfcaData* data); void nfca_listener_free(NfcaListener* instance); +NfcaError nfca_listener_set_callback( + NfcaListener* instance, + NfcaListenerCallback callback, + void* context); + +NfcaError nfca_listener_sleep(NfcaListener* instance); + NfcaError nfca_listener_rx( NfcaListener* instance, uint8_t* rx_data, diff --git a/lib/nfc/protocols/nfca_poller.c b/lib/nfc/protocols/nfca_poller.c index 106e76502726..7e8ed0689695 100644 --- a/lib/nfc/protocols/nfca_poller.c +++ b/lib/nfc/protocols/nfca_poller.c @@ -1,12 +1,11 @@ #include "nfca_poller.h" -#include "nfca_common.h" +#include "nfca.h" #include #include #define TAG "NFCA" -#define NFCA_CRC_INIT (0x6363) #define NFCA_POLLER_MAX_TX_BUFFER_SIZE (512U) #define NFCA_POLLER_SEL_CMD(cascade_lvl) (0x93 + 2 * (cascade_lvl)) @@ -57,27 +56,6 @@ static NfcaError nfca_poller_process_error(NfcError error) { return ret; } -static uint16_t nfca_poller_get_crc16(uint8_t* buff, uint16_t len) { - uint16_t crc = NFCA_CRC_INIT; - uint8_t byte = 0; - - for(uint8_t i = 0; i < len; i++) { - byte = buff[i]; - byte ^= (uint8_t)(crc & 0xff); - byte ^= byte << 4; - crc = (crc >> 8) ^ (((uint16_t)byte) << 8) ^ (((uint16_t)byte) << 3) ^ - (((uint16_t)byte) >> 4); - } - - return crc; -} - -static void nfca_poller_append_crc16(uint8_t* buff, uint16_t len) { - uint16_t crc = nfca_poller_get_crc16(buff, len); - buff[len] = (uint8_t)crc; - buff[len + 1] = (uint8_t)(crc >> 8); -} - static NfcaError nfca_poller_standart_frame_exchange( NfcaPoller* instance, uint8_t* tx_data, @@ -99,7 +77,7 @@ static NfcaError nfca_poller_standart_frame_exchange( uint8_t tx_buff[NFCA_POLLER_MAX_TX_BUFFER_SIZE] = {}; memcpy(tx_buff, tx_data, tx_bytes); - nfca_poller_append_crc16(tx_buff, tx_bytes); + nfca_append_crc(tx_buff, tx_bytes); NfcaError ret = NfcaErrorNone; do { @@ -126,10 +104,7 @@ static NfcaError nfca_poller_standart_frame_exchange( ret = NfcaErrorBufferOverflow; break; } - uint16_t crc_calc = nfca_poller_get_crc16(rx_buff, rx_bytes - 2); - uint16_t crc_received = (rx_buff[rx_bytes - 1] << 8) | rx_buff[rx_bytes - 2]; - if(crc_calc != crc_received) { - FURI_LOG_W(TAG, "CRC error: received %04X, expected %04X", crc_received, crc_calc); + if(!nfca_check_crc(rx_buff, rx_bytes)) { ret = NfcaErrorWrongCrc; break; } diff --git a/lib/nfc/protocols/nfca_poller.h b/lib/nfc/protocols/nfca_poller.h index 7bed605dbb15..bea7a02951c4 100644 --- a/lib/nfc/protocols/nfca_poller.h +++ b/lib/nfc/protocols/nfca_poller.h @@ -1,6 +1,6 @@ #pragma once -#include "nfca_common.h" +#include "nfca.h" #include diff --git a/lib/nfc/protocols/nfca_utils.c b/lib/nfc/protocols/nfca_utils.c new file mode 100644 index 000000000000..d5b3fb1a846e --- /dev/null +++ b/lib/nfc/protocols/nfca_utils.c @@ -0,0 +1,142 @@ +#include "nfca_utils.h" +#include +#include +#include + +#define NFCA_CMD_RATS (0xE0U) + +#define NFCA_CRC_INIT (0x6363) + +#define NFCA_F_SIG (13560000.0) +#define T_SIG 7374 //73.746ns*100 +#define T_SIG_x8 58992 //T_SIG*8 +#define T_SIG_x8_x8 471936 //T_SIG*8*8 +#define T_SIG_x8_x9 530928 //T_SIG*8*9 + +#define NFCA_SIGNAL_MAX_EDGES (1350) + +typedef struct { + uint8_t cmd; + uint8_t param; +} nfca_cmd_rats; + +static uint8_t nfca_default_ats[] = {0x05, 0x78, 0x80, 0x80, 0x00}; + +static uint8_t nfca_sleep_req[] = {0x50, 0x00}; + +uint16_t nfca_get_crc16(uint8_t* buff, uint16_t len) { + uint16_t crc = NFCA_CRC_INIT; + uint8_t byte = 0; + + for(uint8_t i = 0; i < len; i++) { + byte = buff[i]; + byte ^= (uint8_t)(crc & 0xff); + byte ^= byte << 4; + crc = (crc >> 8) ^ (((uint16_t)byte) << 8) ^ (((uint16_t)byte) << 3) ^ + (((uint16_t)byte) >> 4); + } + + return crc; +} + +void nfca_append_crc16(uint8_t* buff, uint16_t len) { + uint16_t crc = nfca_get_crc16(buff, len); + buff[len] = (uint8_t)crc; + buff[len + 1] = (uint8_t)(crc >> 8); +} + +bool nfca_emulation_handler( + uint8_t* buff_rx, + uint16_t buff_rx_len, + uint8_t* buff_tx, + uint16_t* buff_tx_len) { + bool sleep = false; + uint8_t rx_bytes = buff_rx_len / 8; + + if(rx_bytes == sizeof(nfca_sleep_req) && !memcmp(buff_rx, nfca_sleep_req, rx_bytes)) { + sleep = true; + } else if(rx_bytes == sizeof(nfca_cmd_rats) && buff_rx[0] == NFCA_CMD_RATS) { + memcpy(buff_tx, nfca_default_ats, sizeof(nfca_default_ats)); + *buff_tx_len = sizeof(nfca_default_ats) * 8; + } + + return sleep; +} + +static void nfca_add_bit(DigitalSignal* signal, bool bit) { + if(bit) { + signal->start_level = true; + for(size_t i = 0; i < 7; i++) { + signal->edge_timings[i] = T_SIG_x8; + } + signal->edge_timings[7] = T_SIG_x8_x9; + signal->edge_cnt = 8; + } else { + signal->start_level = false; + signal->edge_timings[0] = T_SIG_x8_x8; + for(size_t i = 1; i < 9; i++) { + signal->edge_timings[i] = T_SIG_x8; + } + signal->edge_cnt = 9; + } +} + +static void nfca_add_byte(NfcaSignal* nfca_signal, uint8_t byte, bool parity) { + for(uint8_t i = 0; i < 8; i++) { + if(byte & (1 << i)) { + digital_signal_append(nfca_signal->tx_signal, nfca_signal->one); + } else { + digital_signal_append(nfca_signal->tx_signal, nfca_signal->zero); + } + } + if(parity) { + digital_signal_append(nfca_signal->tx_signal, nfca_signal->one); + } else { + digital_signal_append(nfca_signal->tx_signal, nfca_signal->zero); + } +} + +NfcaSignal* nfca_signal_alloc() { + NfcaSignal* nfca_signal = malloc(sizeof(NfcaSignal)); + nfca_signal->one = digital_signal_alloc(10); + nfca_signal->zero = digital_signal_alloc(10); + nfca_add_bit(nfca_signal->one, true); + nfca_add_bit(nfca_signal->zero, false); + nfca_signal->tx_signal = digital_signal_alloc(NFCA_SIGNAL_MAX_EDGES); + + return nfca_signal; +} + +void nfca_signal_free(NfcaSignal* nfca_signal) { + furi_assert(nfca_signal); + + digital_signal_free(nfca_signal->one); + digital_signal_free(nfca_signal->zero); + digital_signal_free(nfca_signal->tx_signal); + free(nfca_signal); +} + +void nfca_signal_encode(NfcaSignal* nfca_signal, uint8_t* data, uint16_t bits, uint8_t* parity) { + furi_assert(nfca_signal); + furi_assert(data); + furi_assert(parity); + + nfca_signal->tx_signal->edge_cnt = 0; + nfca_signal->tx_signal->start_level = true; + // Start of frame + digital_signal_append(nfca_signal->tx_signal, nfca_signal->one); + + if(bits < 8) { + for(size_t i = 0; i < bits; i++) { + if(FURI_BIT(data[0], i)) { + digital_signal_append(nfca_signal->tx_signal, nfca_signal->one); + } else { + digital_signal_append(nfca_signal->tx_signal, nfca_signal->zero); + } + } + } else { + for(size_t i = 0; i < bits / 8; i++) { + nfca_add_byte(nfca_signal, data[i], parity[i / 8] & (1 << (7 - (i & 0x07)))); + } + } +} diff --git a/lib/nfc/protocols/nfca_utils.h b/lib/nfc/protocols/nfca_utils.h new file mode 100644 index 000000000000..498ef28431c2 --- /dev/null +++ b/lib/nfc/protocols/nfca_utils.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include + +#include + +typedef struct { + DigitalSignal* one; + DigitalSignal* zero; + DigitalSignal* tx_signal; +} NfcaSignal; + +uint16_t nfca_get_crc16(uint8_t* buff, uint16_t len); + +void nfca_append_crc16(uint8_t* buff, uint16_t len); + +bool nfca_emulation_handler( + uint8_t* buff_rx, + uint16_t buff_rx_len, + uint8_t* buff_tx, + uint16_t* buff_tx_len); + +NfcaSignal* nfca_signal_alloc(); + +void nfca_signal_free(NfcaSignal* nfca_signal); + +void nfca_signal_encode(NfcaSignal* nfca_signal, uint8_t* data, uint16_t bits, uint8_t* parity); From 2b77f98d23957e7036d76998445a2806a8b8e80b Mon Sep 17 00:00:00 2001 From: gornekich Date: Thu, 30 Mar 2023 22:14:16 +0400 Subject: [PATCH 012/149] nfc: support mfu commands --- .../main/nfc_rpc/nfc_rpc_mf_ultralight.c | 25 ++++++ firmware/targets/f7/api_symbols.csv | 6 +- firmware/targets/f7/furi_hal/f_hal_nfc.c | 16 ++++ firmware/targets/furi_hal_include/f_hal_nfc.h | 2 + lib/nfc/nfc.c | 2 +- lib/nfc/protocols/mf_ultralight_common.h | 1 + lib/nfc/protocols/mf_ultralight_listener.c | 80 ++++++++++++++++++- lib/nfc/protocols/nfca_listener.c | 30 +++++++ lib/nfc/protocols/nfca_listener.h | 3 + 9 files changed, 160 insertions(+), 5 deletions(-) diff --git a/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c b/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c index ba83460b7abd..adf2d8e72c20 100644 --- a/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c +++ b/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c @@ -182,6 +182,29 @@ static void nfc_rpc_mf_ultralight_read_tearing_flag(Nfc_Main* cmd, void* context mf_ultralight_poller_free(poller); } +// TODO DELETE! +static void init_mf_ul_data(MfUltralightData* data) { + NfcaData* nfca_data = &data->nfca_data; + uint8_t uid[7] = {0x44, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05}; + uint8_t atqa[2] = {0x44, 0x00}; + nfca_data->uid_len = sizeof(uid); + memcpy(nfca_data->uid, uid, sizeof(uid)); + memcpy(nfca_data->atqa, atqa, sizeof(atqa)); + nfca_data->sak = 0x00; + + data->type = MfUltralightTypeUnknown; + MfUltralightVersion version = { + .header = 1, + .protocol_type = 228, + }; + data->version = version; + MfUltralightSignature sig = {.data = {0x01, 0x02, 0x03}}; + data->signature = sig; + for(size_t i = 0; i < 16; i++) { + data->page[i].data[0] = i; + } +} + void nfc_rpc_mf_ultralight_emulate_start(Nfc_Main* cmd, void* context) { furi_assert(cmd); furi_assert(context); @@ -193,6 +216,8 @@ void nfc_rpc_mf_ultralight_emulate_start(Nfc_Main* cmd, void* context) { cmd->which_content = Nfc_Main_mf_ultralight_emulate_start_resp_tag; if(instance->mf_ul_listener == NULL) { MfUltralightData mf_ul_data = {}; + // TODO initialize data from rpc message + init_mf_ul_data(&mf_ul_data); instance->mf_ul_listener = mf_ultralight_listener_alloc(&mf_ul_data); pb_mf_ultralight_emulate_start_resp.error = PB_MfUltralight_Error_None; } else { diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 614027622a50..3f807303280e 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,+,20.1,, +Version,+,20.2,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -817,14 +817,14 @@ Function,-,expm1f,float,float Function,-,expm1l,long double,long double Function,-,f_hal_nfc_abort,FHalNfcError, Function,-,f_hal_nfc_init,FHalNfcError, -Function,-,f_hal_nfc_listener_sleep,FHalNfcError, Function,-,f_hal_nfc_listen_start,FHalNfcError, +Function,-,f_hal_nfc_listener_sleep,FHalNfcError, +Function,-,f_hal_nfc_listener_tx,FHalNfcError,"uint8_t*, uint16_t" Function,-,f_hal_nfc_low_power_mode_start,FHalNfcError, Function,-,f_hal_nfc_low_power_mode_stop,FHalNfcError, Function,-,f_hal_nfc_poller_field_on,FHalNfcError, Function,-,f_hal_nfc_poller_rx,FHalNfcError,"uint8_t*, uint16_t, uint16_t*" Function,-,f_hal_nfc_poller_tx,FHalNfcError,"uint8_t*, uint16_t" -Function,-,f_hal_nfc_set_callback,void,"FHalNfcCallback, void*" Function,-,f_hal_nfc_set_mask_receive_timer,void,uint32_t Function,-,f_hal_nfc_set_mode,FHalNfcError,"FHalNfcMode, FHalNfcBitrate" Function,-,f_hal_nfc_timer_block_tx_is_running,_Bool, diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc.c b/firmware/targets/f7/furi_hal/f_hal_nfc.c index 430024bf37c9..3c489fa29df4 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfc.c +++ b/firmware/targets/f7/furi_hal/f_hal_nfc.c @@ -372,6 +372,22 @@ FHalNfcError f_hal_nfc_poller_tx(uint8_t* tx_data, uint16_t tx_bits) { return err; } +FHalNfcError f_hal_nfc_listener_tx(uint8_t* tx_data, uint16_t tx_bits) { + furi_assert(tx_data); + + FHalNfcError err = FHalNfcErrorNone; + FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; + furi_hal_spi_acquire(handle); + + // Prepare tx + st25r3916_direct_cmd(handle, ST25R3916_CMD_CLEAR_FIFO); + + st25r3916_write_fifo(handle, tx_data, tx_bits); + st25r3916_direct_cmd(handle, ST25R3916_CMD_TRANSMIT_WITHOUT_CRC); + furi_hal_spi_release(handle); + return err; +} + FHalNfcError f_hal_nfc_poller_rx(uint8_t* rx_data, uint16_t rx_data_size, uint16_t* rx_bits) { furi_assert(rx_data); furi_assert(rx_bits); diff --git a/firmware/targets/furi_hal_include/f_hal_nfc.h b/firmware/targets/furi_hal_include/f_hal_nfc.h index 5c612039ce7e..cc1179436cac 100644 --- a/firmware/targets/furi_hal_include/f_hal_nfc.h +++ b/firmware/targets/furi_hal_include/f_hal_nfc.h @@ -96,6 +96,8 @@ FHalNfcError f_hal_nfc_poller_tx(uint8_t* tx_data, uint16_t tx_bits); FHalNfcError f_hal_nfc_poller_rx(uint8_t* rx_data, uint16_t rx_data_size, uint16_t* rx_bits); +FHalNfcError f_hal_nfc_listener_tx(uint8_t* tx_data, uint16_t tx_bits); + FHalNfcError f_hal_nfc_trx_reset(); FHalNfcError f_hal_nfc_listen_start(); diff --git a/lib/nfc/nfc.c b/lib/nfc/nfc.c index ed63b36cb8e9..a80e7412c0a6 100644 --- a/lib/nfc/nfc.c +++ b/lib/nfc/nfc.c @@ -497,7 +497,7 @@ NfcError nfc_listener_tx(Nfc* instance, uint8_t* tx_data, uint16_t tx_bits) { furi_assert(tx_data); NfcError ret = NfcErrorNone; - FHalNfcError error = f_hal_nfc_poller_tx(tx_data, tx_bits); + FHalNfcError error = f_hal_nfc_listener_tx(tx_data, tx_bits); if(error != FHalNfcErrorNone) { FURI_LOG_E(TAG, "Failed in listener TX"); ret = nfc_process_hal_error(error); diff --git a/lib/nfc/protocols/mf_ultralight_common.h b/lib/nfc/protocols/mf_ultralight_common.h index 3d54263b8105..3f3eaaff3626 100644 --- a/lib/nfc/protocols/mf_ultralight_common.h +++ b/lib/nfc/protocols/mf_ultralight_common.h @@ -80,6 +80,7 @@ typedef struct { typedef struct { NfcaData nfca_data; + MfUltralightType type; MfUltralightVersion version; MfUltralightSignature signature; MfUltralightCounter counter[MF_ULTRALIGHT_COUNTER_NUM]; diff --git a/lib/nfc/protocols/mf_ultralight_listener.c b/lib/nfc/protocols/mf_ultralight_listener.c index 35e485e9b5d8..6910e6be61d9 100644 --- a/lib/nfc/protocols/mf_ultralight_listener.c +++ b/lib/nfc/protocols/mf_ultralight_listener.c @@ -3,15 +3,93 @@ #include +#define TAG "MfUltralightListener" + +typedef enum { + MfUltraligthListenerStateIdle, + MfUltraligthListenerStateAuthSuccess, +} MfUltraligthListenerState; + +typedef enum { + MfUltralightListenerFeatureSupportReadVersion = (1U << 0), + MfUltralightListenerFeatureSupportReadSignature = (1U << 1), + MfUltralightListenerFeatureSupportReadCounter = (1U << 2), + MfUltralightListenerFeatureSupportCheckTearingFlag = (1U << 3), +} MfUltralightListenerFeatureSupport; + struct MfUltralightListener { NfcaListener* nfca_listener; + MfUltralightData data; + MfUltraligthListenerState state; + uint16_t pages_total; + MfUltralightListenerFeatureSupport features; }; +static void mf_ultralight_listener_event_handler(NfcaListenerEvent event, void* context) { + furi_assert(context); + + MfUltralightListener* instance = context; + uint8_t* rx_data = event.data.rx_data; + uint16_t rx_bits = event.data.rx_bits; + // TODO WHO own bufer??????? + // TODO implement rollback + uint8_t tx_data[64] = {}; + uint16_t tx_bits = 0; + if(event.type == NfcaListenerEventTypeReceivedStandartFrame) { + if((rx_bits == 16) && (rx_data[0] == MF_ULTRALIGHT_CMD_READ_PAGE)) { + uint8_t start_page = rx_data[1]; + if(instance->pages_total < start_page) { + FURI_LOG_T(TAG, "Read page cmd: %d", start_page); + instance->state = MfUltraligthListenerStateIdle; + tx_data[0] = 0x00; + tx_bits = 8; + nfca_listener_tx(instance->nfca_listener, tx_data, tx_bits); + } else { + memcpy(tx_data, instance->data.page[start_page].data, 16); + tx_bits = 16 * 8; + nfca_listener_send_standart_frame(instance->nfca_listener, tx_data, tx_bits); + } + } else if((rx_bits == 8) && (rx_data[0] == MF_ULTRALIGHT_CMD_GET_VERSION)) { + if(instance->features & MfUltralightListenerFeatureSupportReadVersion) { + memcpy(tx_data, &instance->data.version, sizeof(instance->data.version)); + tx_bits = sizeof(instance->data.version) * 8; + nfca_listener_send_standart_frame(instance->nfca_listener, tx_data, tx_bits); + } else { + instance->state = MfUltraligthListenerStateIdle; + nfca_listener_sleep(instance->nfca_listener); + } + } else if((rx_bits == 16) && (rx_data[0] == MF_ULTRALIGTH_CMD_READ_SIG)) { + if(instance->features & MfUltralightListenerFeatureSupportReadSignature) { + // TODO implement rollback + memcpy(tx_data, &instance->data.signature, sizeof(instance->data.signature)); + tx_bits = sizeof(instance->data.signature) * 8; + nfca_listener_send_standart_frame(instance->nfca_listener, tx_data, tx_bits); + } else { + instance->state = MfUltraligthListenerStateIdle; + nfca_listener_sleep(instance->nfca_listener); + } + } + } +} + +static void mf_ultralight_listener_prepare_emulation(MfUltralightListener* instance) { + MfUltralightData* data = &instance->data; + if(data->type == MfUltralightTypeUnknown) { + instance->features = MfUltralightListenerFeatureSupportReadVersion | + MfUltralightListenerFeatureSupportReadSignature; + instance->pages_total = 16; + } +} + MfUltralightListener* mf_ultralight_listener_alloc(MfUltralightData* data) { furi_assert(data); - MfUltralightListener* instance = malloc(sizeof(MfUltralightData)); + MfUltralightListener* instance = malloc(sizeof(MfUltralightListener)); + instance->data = *data; + mf_ultralight_listener_prepare_emulation(instance); instance->nfca_listener = nfca_listener_alloc(&data->nfca_data); + nfca_listener_set_callback( + instance->nfca_listener, mf_ultralight_listener_event_handler, instance); return instance; } diff --git a/lib/nfc/protocols/nfca_listener.c b/lib/nfc/protocols/nfca_listener.c index cf69af9e82cd..8549da5c40b8 100644 --- a/lib/nfc/protocols/nfca_listener.c +++ b/lib/nfc/protocols/nfca_listener.c @@ -116,6 +116,7 @@ NfcaError nfca_listener_sleep(NfcaListener* instance) { furi_assert(instance); NfcError error = nfc_listener_sleep(instance->nfc); + instance->state = NfcaListenerStateIdle; return nfca_listener_process_nfc_error(error); } @@ -152,3 +153,32 @@ NfcaError nfca_listener_tx(NfcaListener* instance, uint8_t* tx_data, uint16_t tx } return ret; } + +NfcaError + nfca_listener_send_standart_frame(NfcaListener* instance, uint8_t* tx_data, uint16_t tx_bits) { + furi_assert(instance); + furi_assert(tx_data); + + NfcaError ret = NfcaErrorNone; + // TODO another buffer ... + uint8_t tx_buff[64]; + uint16_t tx_bytes = tx_bits / 8; + + do { + if(tx_bytes > sizeof(tx_buff) - 2) { + ret = NfcaErrorBufferOverflow; + break; + } + memcpy(tx_buff, tx_data, tx_bytes); + nfca_append_crc(tx_buff, tx_bytes); + + NfcError error = nfc_listener_tx(instance->nfc, tx_buff, tx_bits + 16); + if(error != NfcErrorNone) { + FURI_LOG_W(TAG, "Tx error: %d", error); + ret = nfca_listener_process_nfc_error(error); + break; + } + } while(false); + + return ret; +} diff --git a/lib/nfc/protocols/nfca_listener.h b/lib/nfc/protocols/nfca_listener.h index 5efec973781a..47e128fc17a7 100644 --- a/lib/nfc/protocols/nfca_listener.h +++ b/lib/nfc/protocols/nfca_listener.h @@ -49,6 +49,9 @@ NfcaError nfca_listener_rx( NfcaError nfca_listener_tx(NfcaListener* instance, uint8_t* tx_data, uint16_t tx_bits); +NfcaError + nfca_listener_send_standart_frame(NfcaListener* instance, uint8_t* tx_data, uint16_t tx_bits); + #ifdef __cplusplus } #endif From d83a05ccf655d7fc869c934ce13b11d635cb969d Mon Sep 17 00:00:00 2001 From: gornekich Date: Mon, 3 Apr 2023 13:26:22 +0400 Subject: [PATCH 013/149] nfc: rename mf_ultralight_common -> mf_ultralight --- lib/nfc/protocols/mf_ultralight.c | 1 + lib/nfc/protocols/{mf_ultralight_common.h => mf_ultralight.h} | 0 lib/nfc/protocols/mf_ultralight_listener.h | 2 +- lib/nfc/protocols/mf_ultralight_poller.h | 2 +- 4 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 lib/nfc/protocols/mf_ultralight.c rename lib/nfc/protocols/{mf_ultralight_common.h => mf_ultralight.h} (100%) diff --git a/lib/nfc/protocols/mf_ultralight.c b/lib/nfc/protocols/mf_ultralight.c new file mode 100644 index 000000000000..0751cdd72d40 --- /dev/null +++ b/lib/nfc/protocols/mf_ultralight.c @@ -0,0 +1 @@ +#include "mf_ultralight.h" \ No newline at end of file diff --git a/lib/nfc/protocols/mf_ultralight_common.h b/lib/nfc/protocols/mf_ultralight.h similarity index 100% rename from lib/nfc/protocols/mf_ultralight_common.h rename to lib/nfc/protocols/mf_ultralight.h diff --git a/lib/nfc/protocols/mf_ultralight_listener.h b/lib/nfc/protocols/mf_ultralight_listener.h index 6ca848dffcff..1dd9659deb2b 100644 --- a/lib/nfc/protocols/mf_ultralight_listener.h +++ b/lib/nfc/protocols/mf_ultralight_listener.h @@ -1,6 +1,6 @@ #pragma once -#include "mf_ultralight_common.h" +#include "mf_ultralight.h" #ifdef __cplusplus extern "C" { diff --git a/lib/nfc/protocols/mf_ultralight_poller.h b/lib/nfc/protocols/mf_ultralight_poller.h index ac2fa8ec4dfa..35a973520681 100644 --- a/lib/nfc/protocols/mf_ultralight_poller.h +++ b/lib/nfc/protocols/mf_ultralight_poller.h @@ -1,6 +1,6 @@ #pragma once -#include "mf_ultralight_common.h" +#include "mf_ultralight.h" #ifdef __cplusplus extern "C" { From 2d5649a29a2d10824a2a67fb8c01bacacb56a3a9 Mon Sep 17 00:00:00 2001 From: gornekich Date: Mon, 3 Apr 2023 17:30:58 +0400 Subject: [PATCH 014/149] nfc: fix incomplete frame tx --- firmware/targets/f7/api_symbols.csv | 3 ++- firmware/targets/f7/furi_hal/f_hal_nfc.c | 24 +++++++++++++++---- firmware/targets/furi_hal_include/f_hal_nfc.h | 2 ++ lib/drivers/st25r3916.c | 3 ++- lib/nfc/nfc.c | 3 ++- lib/nfc/protocols/mf_ultralight_listener.c | 2 +- 6 files changed, 28 insertions(+), 9 deletions(-) diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 3f807303280e..7806084fee36 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,+,20.2,, +Version,+,20.3,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -818,6 +818,7 @@ Function,-,expm1l,long double,long double Function,-,f_hal_nfc_abort,FHalNfcError, Function,-,f_hal_nfc_init,FHalNfcError, Function,-,f_hal_nfc_listen_start,FHalNfcError, +Function,-,f_hal_nfc_listener_disable_auto_col_res,FHalNfcError, Function,-,f_hal_nfc_listener_sleep,FHalNfcError, Function,-,f_hal_nfc_listener_tx,FHalNfcError,"uint8_t*, uint16_t" Function,-,f_hal_nfc_low_power_mode_start,FHalNfcError, diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc.c b/firmware/targets/f7/furi_hal/f_hal_nfc.c index 3c489fa29df4..c2122f9e961e 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfc.c +++ b/firmware/targets/f7/furi_hal/f_hal_nfc.c @@ -294,9 +294,7 @@ FHalNfcError f_hal_nfc_set_mode(FHalNfcMode mode, FHalNfcBitrate bitrate) { ST25R3916_REG_OP_CONTROL_en | ST25R3916_REG_OP_CONTROL_rx_en | ST25R3916_REG_OP_CONTROL_en_fd_auto_efd); st25r3916_write_reg( - handle, - ST25R3916_REG_MODE, - ST25R3916_REG_MODE_targ_targ | ST25R3916_REG_MODE_om3 | ST25R3916_REG_MODE_om0); + handle, ST25R3916_REG_MODE, ST25R3916_REG_MODE_targ_targ | ST25R3916_REG_MODE_om0); st25r3916_write_reg( handle, ST25R3916_REG_PASSIVE_TARGET, @@ -379,7 +377,6 @@ FHalNfcError f_hal_nfc_listener_tx(uint8_t* tx_data, uint16_t tx_bits) { FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; furi_hal_spi_acquire(handle); - // Prepare tx st25r3916_direct_cmd(handle, ST25R3916_CMD_CLEAR_FIFO); st25r3916_write_fifo(handle, tx_data, tx_bits); @@ -431,8 +428,10 @@ FHalNfcError f_hal_nfc_listen_start() { st25r3916_get_irq(handle); // Enable interrupts st25r3916_mask_irq(handle, interrupts); + // Enable auto collision resolution + st25r3916_clear_reg_bits( + handle, ST25R3916_REG_PASSIVE_TARGET, ST25R3916_REG_PASSIVE_TARGET_d_106_ac_a); st25r3916_direct_cmd(handle, ST25R3916_CMD_GOTO_SENSE); - // st25r3916_direct_cmd(handle, ST25R3916_CMD_UNMASK_RECEIVE_DATA); furi_hal_spi_release(handle); return FHalNfcErrorNone; @@ -442,12 +441,27 @@ FHalNfcError f_hal_nfc_listener_sleep() { FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; furi_hal_spi_acquire(handle); + // Enable auto collision resolution + st25r3916_clear_reg_bits( + handle, ST25R3916_REG_PASSIVE_TARGET, ST25R3916_REG_PASSIVE_TARGET_d_106_ac_a); + st25r3916_direct_cmd(handle, ST25R3916_CMD_STOP); st25r3916_direct_cmd(handle, ST25R3916_CMD_GOTO_SLEEP); furi_hal_spi_release(handle); return FHalNfcErrorNone; } +FHalNfcError f_hal_nfc_listener_disable_auto_col_res() { + FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; + furi_hal_spi_acquire(handle); + + st25r3916_set_reg_bits( + handle, ST25R3916_REG_PASSIVE_TARGET, ST25R3916_REG_PASSIVE_TARGET_d_106_ac_a); + + furi_hal_spi_release(handle); + return FHalNfcErrorNone; +} + void f_hal_nfc_set_mask_receive_timer(uint32_t time_fc) { FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; furi_hal_spi_acquire(handle); diff --git a/firmware/targets/furi_hal_include/f_hal_nfc.h b/firmware/targets/furi_hal_include/f_hal_nfc.h index cc1179436cac..3e42411b852b 100644 --- a/firmware/targets/furi_hal_include/f_hal_nfc.h +++ b/firmware/targets/furi_hal_include/f_hal_nfc.h @@ -104,6 +104,8 @@ FHalNfcError f_hal_nfc_listen_start(); FHalNfcError f_hal_nfc_listener_sleep(); +FHalNfcError f_hal_nfc_listener_disable_auto_col_res(); + FHalNfcError f_hal_nfc_abort(); FHalNfcEvent f_hal_nfc_wait_event(uint32_t timeout_ms); diff --git a/lib/drivers/st25r3916.c b/lib/drivers/st25r3916.c index c148da08c8f7..5a7e5e770acd 100644 --- a/lib/drivers/st25r3916.c +++ b/lib/drivers/st25r3916.c @@ -41,9 +41,10 @@ void st25r3916_write_fifo(FuriHalSpiBusHandle* handle, uint8_t* buff, uint16_t b furi_assert(buff); uint16_t bytes = (bits + 7) / 8; - + st25r3916_write_reg(handle, ST25R3916_REG_NUM_TX_BYTES2, (uint8_t)(bits & 0xFFU)); st25r3916_write_reg(handle, ST25R3916_REG_NUM_TX_BYTES1, (uint8_t)((bits >> 8) & 0xFFU)); + st25r3916_reg_write_fifo(handle, buff, bytes); } diff --git a/lib/nfc/nfc.c b/lib/nfc/nfc.c index a80e7412c0a6..634674bbf54a 100644 --- a/lib/nfc/nfc.c +++ b/lib/nfc/nfc.c @@ -73,12 +73,13 @@ static int32_t nfc_worker(void* context) { instance->callback(nfc_event, instance->context); } if(event & FHalNfcEventFieldOff) { - FURI_LOG_D(TAG, "Field off"); + FURI_LOG_T(TAG, "Field off"); nfc_event.type = NfcEventTypeFieldOff; instance->callback(nfc_event, instance->context); f_hal_nfc_listener_sleep(); } if(event & FHalNfcEventListenerActive) { + f_hal_nfc_listener_disable_auto_col_res(); nfc_event.type = NfcEventTypeListenerActivated; instance->callback(nfc_event, instance->context); } diff --git a/lib/nfc/protocols/mf_ultralight_listener.c b/lib/nfc/protocols/mf_ultralight_listener.c index 6910e6be61d9..43221166b509 100644 --- a/lib/nfc/protocols/mf_ultralight_listener.c +++ b/lib/nfc/protocols/mf_ultralight_listener.c @@ -42,7 +42,7 @@ static void mf_ultralight_listener_event_handler(NfcaListenerEvent event, void* FURI_LOG_T(TAG, "Read page cmd: %d", start_page); instance->state = MfUltraligthListenerStateIdle; tx_data[0] = 0x00; - tx_bits = 8; + tx_bits = 4; nfca_listener_tx(instance->nfca_listener, tx_data, tx_bits); } else { memcpy(tx_data, instance->data.page[start_page].data, 16); From dfd729b3ca86a398653491ee93a357e2ec19cf0f Mon Sep 17 00:00:00 2001 From: gornekich Date: Tue, 4 Apr 2023 20:49:06 +0400 Subject: [PATCH 015/149] mfu: introduce command handlers --- firmware/targets/f7/furi_hal/f_hal_nfc_irq.c | 3 +- firmware/targets/furi_hal_include/f_hal_nfc.h | 2 +- lib/drivers/st25r3916.c | 2 +- lib/nfc/protocols/mf_ultralight.h | 3 +- lib/nfc/protocols/mf_ultralight_listener.c | 145 +++++++++++++----- 5 files changed, 115 insertions(+), 40 deletions(-) diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc_irq.c b/firmware/targets/f7/furi_hal/f_hal_nfc_irq.c index 686675bb9967..e5e276fd588e 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfc_irq.c +++ b/firmware/targets/f7/furi_hal/f_hal_nfc_irq.c @@ -16,7 +16,8 @@ uint32_t f_hal_nfc_get_irq(FuriHalSpiBusHandle* handle) { } void f_hal_nfc_init_gpio_isr() { - furi_hal_gpio_init(&gpio_nfc_irq_rfid_pull, GpioModeInterruptRise, GpioPullDown, GpioSpeedVeryHigh); + furi_hal_gpio_init( + &gpio_nfc_irq_rfid_pull, GpioModeInterruptRise, GpioPullDown, GpioSpeedVeryHigh); furi_hal_gpio_add_int_callback(&gpio_nfc_irq_rfid_pull, f_hal_nfc_int_callback, NULL); furi_hal_gpio_enable_int_callback(&gpio_nfc_irq_rfid_pull); } diff --git a/firmware/targets/furi_hal_include/f_hal_nfc.h b/firmware/targets/furi_hal_include/f_hal_nfc.h index 3e42411b852b..3adf78ac266b 100644 --- a/firmware/targets/furi_hal_include/f_hal_nfc.h +++ b/firmware/targets/furi_hal_include/f_hal_nfc.h @@ -16,7 +16,7 @@ typedef enum { FHalNfcEventFieldOn = (1U << 1), FHalNfcEventFieldOff = (1U << 2), FHalNfcEventListenerActive = (1U << 3), - FHalNfcEventListenerActiveA = (1U << 4), + FHalNfcEventListenerActiveA = (1U << 4), FHalNfcEventTxStart = (1U << 5), FHalNfcEventTxEnd = (1U << 6), FHalNfcEventRxStart = (1U << 7), diff --git a/lib/drivers/st25r3916.c b/lib/drivers/st25r3916.c index 5a7e5e770acd..4d3e39f4e060 100644 --- a/lib/drivers/st25r3916.c +++ b/lib/drivers/st25r3916.c @@ -41,7 +41,7 @@ void st25r3916_write_fifo(FuriHalSpiBusHandle* handle, uint8_t* buff, uint16_t b furi_assert(buff); uint16_t bytes = (bits + 7) / 8; - + st25r3916_write_reg(handle, ST25R3916_REG_NUM_TX_BYTES2, (uint8_t)(bits & 0xFFU)); st25r3916_write_reg(handle, ST25R3916_REG_NUM_TX_BYTES1, (uint8_t)((bits >> 8) & 0xFFU)); diff --git a/lib/nfc/protocols/mf_ultralight.h b/lib/nfc/protocols/mf_ultralight.h index 3f3eaaff3626..26501ec29ed9 100644 --- a/lib/nfc/protocols/mf_ultralight.h +++ b/lib/nfc/protocols/mf_ultralight.h @@ -9,10 +9,11 @@ extern "C" { #define MF_ULTRALIGHT_CMD_GET_VERSION (0x60) #define MF_ULTRALIGHT_CMD_READ_PAGE (0x30) #define MF_ULTRALIGHT_CMD_WRITE_PAGE (0xA2) -#define MF_ULTRALIGHT_CMD_ACK (0x0A) #define MF_ULTRALIGTH_CMD_READ_SIG (0x3C) #define MF_ULTRALIGHT_CMD_READ_CNT (0x39) #define MF_ULTRALIGHT_CMD_CHECK_TEARING (0x3E) +#define MF_ULTRALIGHT_CMD_ACK (0x0A) +#define MF_ULTRALIGHT_CMD_NACK (0x00) #define MF_ULTRALIGHT_MAX_PAGE_NUM (510) #define MF_ULTRALIGHT_PAGE_SIZE (4U) diff --git a/lib/nfc/protocols/mf_ultralight_listener.c b/lib/nfc/protocols/mf_ultralight_listener.c index 43221166b509..b097266109ff 100644 --- a/lib/nfc/protocols/mf_ultralight_listener.c +++ b/lib/nfc/protocols/mf_ultralight_listener.c @@ -5,6 +5,8 @@ #define TAG "MfUltralightListener" +#define MF_ULTRALIGHT_LISTENER_MAX_TX_BUFF_SIZE (32) + typedef enum { MfUltraligthListenerStateIdle, MfUltraligthListenerStateAuthSuccess, @@ -20,54 +22,125 @@ typedef enum { struct MfUltralightListener { NfcaListener* nfca_listener; MfUltralightData data; + uint8_t tx_data[MF_ULTRALIGHT_LISTENER_MAX_TX_BUFF_SIZE]; + uint16_t tx_bits; MfUltraligthListenerState state; uint16_t pages_total; MfUltralightListenerFeatureSupport features; }; +typedef bool (*MfUltralightListenerCommandCallback)( + MfUltralightListener* instance, + uint8_t* rx_data, + uint16_t rx_bits); + +typedef struct { + uint8_t cmd; + uint16_t cmd_len_bits; + MfUltralightListenerCommandCallback callback; +} MfUltralightListenerCommand; + +static void mf_ultralight_listener_send_short_resp(MfUltralightListener* instance, uint8_t data) { + nfca_listener_tx(instance->nfca_listener, &data, 4); +}; + +static bool mf_ultralight_listener_read_page_handler( + MfUltralightListener* instance, + uint8_t* rx_data, + uint16_t rx_bits) { + UNUSED(rx_bits); + bool command_processed = false; + uint8_t start_page = rx_data[1]; + if(instance->pages_total < start_page) { + mf_ultralight_listener_send_short_resp(instance, MF_ULTRALIGHT_CMD_NACK); + instance->state = MfUltraligthListenerStateIdle; + } else { + memcpy(instance->tx_data, instance->data.page[start_page].data, 16); + instance->tx_bits = 16 * 8; + nfca_listener_send_standart_frame( + instance->nfca_listener, instance->tx_data, instance->tx_bits); + } + command_processed = true; + + return command_processed; +} + +static bool mf_ultralight_listener_read_version_handler( + MfUltralightListener* instance, + uint8_t* rx_data, + uint16_t rx_bits) { + UNUSED(rx_bits); + UNUSED(rx_data); + bool command_processed = false; + if((instance->features & MfUltralightListenerFeatureSupportReadVersion)) { + memcpy(instance->tx_data, &instance->data.version, sizeof(instance->data.version)); + instance->tx_bits = sizeof(instance->data.version) * 8; + nfca_listener_send_standart_frame( + instance->nfca_listener, instance->tx_data, instance->tx_bits); + } else { + nfca_listener_sleep(instance->nfca_listener); + instance->state = MfUltraligthListenerStateIdle; + } + command_processed = true; + + return command_processed; +} + +static bool mf_ultralight_listener_read_signature_handler( + MfUltralightListener* instance, + uint8_t* rx_data, + uint16_t rx_bits) { + UNUSED(rx_bits); + UNUSED(rx_data); + bool command_processed = false; + if((instance->features & MfUltralightListenerFeatureSupportReadSignature)) { + memcpy(instance->tx_data, &instance->data.signature, sizeof(instance->data.signature)); + instance->tx_bits = sizeof(instance->data.signature) * 8; + nfca_listener_send_standart_frame( + instance->nfca_listener, instance->tx_data, instance->tx_bits); + } else { + nfca_listener_sleep(instance->nfca_listener); + instance->state = MfUltraligthListenerStateIdle; + } + command_processed = true; + + return command_processed; +} + +static const MfUltralightListenerCommand mf_ultralight_command[] = { + { + .cmd = MF_ULTRALIGHT_CMD_READ_PAGE, + .cmd_len_bits = 16, + .callback = mf_ultralight_listener_read_page_handler, + }, + { + .cmd = MF_ULTRALIGHT_CMD_GET_VERSION, + .cmd_len_bits = 8, + .callback = mf_ultralight_listener_read_version_handler, + }, + { + .cmd = MF_ULTRALIGTH_CMD_READ_SIG, + .cmd_len_bits = 16, + .callback = mf_ultralight_listener_read_signature_handler, + }, +}; + static void mf_ultralight_listener_event_handler(NfcaListenerEvent event, void* context) { furi_assert(context); MfUltralightListener* instance = context; uint8_t* rx_data = event.data.rx_data; uint16_t rx_bits = event.data.rx_bits; - // TODO WHO own bufer??????? - // TODO implement rollback - uint8_t tx_data[64] = {}; - uint16_t tx_bits = 0; if(event.type == NfcaListenerEventTypeReceivedStandartFrame) { - if((rx_bits == 16) && (rx_data[0] == MF_ULTRALIGHT_CMD_READ_PAGE)) { - uint8_t start_page = rx_data[1]; - if(instance->pages_total < start_page) { - FURI_LOG_T(TAG, "Read page cmd: %d", start_page); - instance->state = MfUltraligthListenerStateIdle; - tx_data[0] = 0x00; - tx_bits = 4; - nfca_listener_tx(instance->nfca_listener, tx_data, tx_bits); - } else { - memcpy(tx_data, instance->data.page[start_page].data, 16); - tx_bits = 16 * 8; - nfca_listener_send_standart_frame(instance->nfca_listener, tx_data, tx_bits); - } - } else if((rx_bits == 8) && (rx_data[0] == MF_ULTRALIGHT_CMD_GET_VERSION)) { - if(instance->features & MfUltralightListenerFeatureSupportReadVersion) { - memcpy(tx_data, &instance->data.version, sizeof(instance->data.version)); - tx_bits = sizeof(instance->data.version) * 8; - nfca_listener_send_standart_frame(instance->nfca_listener, tx_data, tx_bits); - } else { - instance->state = MfUltraligthListenerStateIdle; - nfca_listener_sleep(instance->nfca_listener); - } - } else if((rx_bits == 16) && (rx_data[0] == MF_ULTRALIGTH_CMD_READ_SIG)) { - if(instance->features & MfUltralightListenerFeatureSupportReadSignature) { - // TODO implement rollback - memcpy(tx_data, &instance->data.signature, sizeof(instance->data.signature)); - tx_bits = sizeof(instance->data.signature) * 8; - nfca_listener_send_standart_frame(instance->nfca_listener, tx_data, tx_bits); - } else { - instance->state = MfUltraligthListenerStateIdle; - nfca_listener_sleep(instance->nfca_listener); - } + bool cmd_processed = false; + for(size_t i = 0; i < COUNT_OF(mf_ultralight_command); i++) { + if(rx_bits != mf_ultralight_command[i].cmd_len_bits) continue; + if(rx_data[0] != mf_ultralight_command[i].cmd) continue; + cmd_processed = mf_ultralight_command[i].callback(instance, rx_data, rx_bits); + if(cmd_processed) break; + } + if(!cmd_processed) { + mf_ultralight_listener_send_short_resp(instance, MF_ULTRALIGHT_CMD_NACK); } } } From c15ae5185ef894f6457ba479ff3dbcb0f56fb4be Mon Sep 17 00:00:00 2001 From: gornekich Date: Wed, 5 Apr 2023 13:27:49 +0400 Subject: [PATCH 016/149] nfc: remove listener rx API --- applications/main/nfc/nfc_cli.c | 31 +------------- lib/nfc/nfc.c | 70 ------------------------------- lib/nfc/nfc.h | 7 ---- lib/nfc/protocols/nfca_listener.c | 20 --------- lib/nfc/protocols/nfca_listener.h | 7 ---- 5 files changed, 1 insertion(+), 134 deletions(-) diff --git a/applications/main/nfc/nfc_cli.c b/applications/main/nfc/nfc_cli.c index 956b8c77dfc9..da9e24cb9a74 100644 --- a/applications/main/nfc/nfc_cli.c +++ b/applications/main/nfc/nfc_cli.c @@ -31,36 +31,7 @@ static void nfc_cli_print_usage() { static void nfc_cli_check(Cli* cli, FuriString* args) { UNUSED(args); - - uint8_t uid[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}; - uint8_t atqa[2] = {0x44, 0x00}; - uint8_t sak = 0x08; - NfcaData data = {}; - data.uid_len = sizeof(uid); - memcpy(data.uid, uid, data.uid_len); - memcpy(data.atqa, atqa, sizeof(atqa)); - data.sak = sak; - - NfcaListener* instance = nfca_listener_alloc(&data); - NfcaError error = NfcaErrorNone; - uint8_t rx_data[100] = {}; - uint16_t rx_bits = 0; - uint8_t nt[4] = {0x01, 0x02, 0x03, 0x04}; - - while(true) { - error = nfca_listener_rx(instance, rx_data, sizeof(rx_data), &rx_bits, 10000); - if(error == NfcaErrorNone) { - // printf("Received %d bits\r\n", rx_bits); - // for(size_t i = 0; i < rx_bits / 8; i++) { - // printf("%02X ", rx_data[i]); - // } - // printf("\r\n"); - nfca_listener_tx(instance, nt, sizeof(nt) * 8); - } - if(cli_cmd_interrupt_received(cli)) break; - } - - nfca_listener_free(instance); + UNUSED(cli); } static void nfc_cli_detect(Cli* cli, FuriString* args) { diff --git a/lib/nfc/nfc.c b/lib/nfc/nfc.c index 634674bbf54a..b09709fed6fe 100644 --- a/lib/nfc/nfc.c +++ b/lib/nfc/nfc.c @@ -423,76 +423,6 @@ NfcError nfc_listener_sleep(Nfc* instance) { return NfcErrorNone; } -NfcError nfc_listener_rx( - Nfc* instance, - uint8_t* rx_data, - uint16_t rx_data_size, - uint16_t* rx_bits, - uint32_t timeout) { - furi_assert(instance); - furi_assert(instance->state == NfcStateConfigured); - furi_assert(rx_data); - furi_assert(rx_bits); - - NfcError ret = NfcErrorNone; - if(instance->comm_state == NfcCommStateIdle) { - f_hal_nfc_listen_start(); - instance->comm_state = NfcCommStateWaitRxStart; - } - do { - FHalNfcEvent event = f_hal_nfc_wait_event(timeout); - if(event & FHalNfcEventFieldOn) { - // FURI_LOG_D(TAG, "FieldOn"); - } - if(event & FHalNfcEventListenerActive) { - // FURI_LOG_D(TAG, "Activated"); - } - if(event & FHalNfcEventRxEnd) { - // FURI_LOG_D(TAG, "Received data"); - f_hal_nfc_poller_rx(rx_data, rx_data_size, rx_bits); - break; - } - if(event & FHalNfcEventFieldOff) { - // FURI_LOG_D(TAG, "Field off"); - ret = NfcErrorLinkLoss; - break; - } - if(event & FHalNfcEventTimeout) { - ret = NfcErrorTimeout; - // FURI_LOG_D(TAG, "Timeout"); - break; - } - if(event & FHalNfcEventAbortRequest) { - ret = NfcErrorAbortRequest; - // FURI_LOG_D(TAG, "Abirt request"); - break; - } - - // if(event & FHalNfcEventRxStart) { - // FURI_LOG_I(TAG, "Listener RxStart"); - // instance->comm_state = NfcCommStateWaitRxEnd; - // } else if(event == FHalNfcEventTimeout) { - // FURI_LOG_W(TAG, "Listener Timeout"); - // ret = NfcErrorTimeout; - // break; - // } - // event = f_hal_nfc_wait_event(timeout); - // if(event & FHalNfcEventRxEnd) { - // FURI_LOG_I(TAG, "Listener Rx end"); - // } - // FHalNfcError error = f_hal_nfc_poller_rx(rx_data, rx_data_size, rx_bits); - // if(error != FHalNfcErrorNone) { - // ret = nfc_process_hal_error(error); - // break; - // } - // f_hal_nfc_timer_block_tx_start(instance->fdt_listen_fc); - // instance->comm_state = NfcCommStateWaitBlockTxTimer; - // break; - } while(true); - - return ret; -} - NfcError nfc_listener_tx(Nfc* instance, uint8_t* tx_data, uint16_t tx_bits) { furi_assert(instance); furi_assert(tx_data); diff --git a/lib/nfc/nfc.h b/lib/nfc/nfc.h index 93503737b34d..e039675f69ab 100644 --- a/lib/nfc/nfc.h +++ b/lib/nfc/nfc.h @@ -81,13 +81,6 @@ void nfc_listener_start(Nfc* instance, NfcEventCallback callback, void* context) NfcError nfc_listener_sleep(Nfc* instance); -NfcError nfc_listener_rx( - Nfc* instance, - uint8_t* rx_data, - uint16_t rx_data_size, - uint16_t* rx_bits, - uint32_t timeout); - NfcError nfc_listener_tx(Nfc* instance, uint8_t* tx_data, uint16_t tx_bits); NfcError nfc_trx( diff --git a/lib/nfc/protocols/nfca_listener.c b/lib/nfc/protocols/nfca_listener.c index 8549da5c40b8..81aa1c25f450 100644 --- a/lib/nfc/protocols/nfca_listener.c +++ b/lib/nfc/protocols/nfca_listener.c @@ -121,26 +121,6 @@ NfcaError nfca_listener_sleep(NfcaListener* instance) { return nfca_listener_process_nfc_error(error); } -NfcaError nfca_listener_rx( - NfcaListener* instance, - uint8_t* rx_data, - uint16_t rx_data_size, - uint16_t* rx_bits, - uint32_t timeout_ms) { - furi_assert(instance); - furi_assert(instance->nfc); - furi_assert(rx_data); - furi_assert(rx_bits); - - NfcaError ret = NfcaErrorNone; - NfcError error = nfc_listener_rx(instance->nfc, rx_data, rx_data_size, rx_bits, timeout_ms); - if(error != NfcErrorNone) { - FURI_LOG_W(TAG, "Rx error: %d", error); - ret = nfca_listener_process_nfc_error(error); - } - return ret; -} - NfcaError nfca_listener_tx(NfcaListener* instance, uint8_t* tx_data, uint16_t tx_bits) { furi_assert(instance); furi_assert(tx_data); diff --git a/lib/nfc/protocols/nfca_listener.h b/lib/nfc/protocols/nfca_listener.h index 47e128fc17a7..ceedcceccbbe 100644 --- a/lib/nfc/protocols/nfca_listener.h +++ b/lib/nfc/protocols/nfca_listener.h @@ -40,13 +40,6 @@ NfcaError nfca_listener_set_callback( NfcaError nfca_listener_sleep(NfcaListener* instance); -NfcaError nfca_listener_rx( - NfcaListener* instance, - uint8_t* rx_data, - uint16_t rx_data_size, - uint16_t* rx_bits, - uint32_t timeout_ms); - NfcaError nfca_listener_tx(NfcaListener* instance, uint8_t* tx_data, uint16_t tx_bits); NfcaError From 602a01eddbffe8ff5d72fe9297284581793938c8 Mon Sep 17 00:00:00 2001 From: gornekich Date: Wed, 5 Apr 2023 16:32:30 +0400 Subject: [PATCH 017/149] nfc: start reworking poller --- applications/main/nfc_rpc/nfc_rpc_nfca.c | 2 +- lib/nfc/nfc.c | 135 +++++++++++++++-------- lib/nfc/nfc.h | 15 ++- lib/nfc/protocols/nfca_listener.c | 2 +- lib/nfc/protocols/nfca_poller.c | 76 +++++++++++++ lib/nfc/protocols/nfca_poller.h | 26 +++++ 6 files changed, 205 insertions(+), 51 deletions(-) diff --git a/applications/main/nfc_rpc/nfc_rpc_nfca.c b/applications/main/nfc_rpc/nfc_rpc_nfca.c index a323bda4a380..7ca0c757d007 100644 --- a/applications/main/nfc_rpc/nfc_rpc_nfca.c +++ b/applications/main/nfc_rpc/nfc_rpc_nfca.c @@ -48,7 +48,7 @@ static void nfc_rpc_nfca_read(Nfc_Main* cmd, void* context) { NfcaData nfca_data = {}; NfcaPoller* nfca_poller = nfca_poller_alloc(); - NfcaError error = nfca_poller_activate(nfca_poller, &nfca_data); + NfcaError error = nfca_poller_activate_sync(nfca_poller, &nfca_data); cmd->command_status = Nfc_CommandStatus_OK; cmd->which_content = Nfc_Main_nfca_read_resp_tag; diff --git a/lib/nfc/nfc.c b/lib/nfc/nfc.c index b09709fed6fe..7d23a7a1b532 100644 --- a/lib/nfc/nfc.c +++ b/lib/nfc/nfc.c @@ -14,6 +14,9 @@ typedef enum { NfcStateFieldOff, NfcStateListenStarted, + NfcStatePollerReady, + NfcStateStopRequested, + NfcStateStopped, } NfcState; typedef enum { @@ -26,7 +29,13 @@ typedef enum { NfcCommStateFailed, } NfcCommState; +typedef enum { + NfcGenericModePoller, + NfcGenericModeListener, +} NfcGenericMode; + struct Nfc { + NfcGenericMode mode; NfcState state; NfcCommState comm_state; uint32_t fdt_listen_fc; @@ -52,8 +61,9 @@ static NfcError nfc_process_hal_error(FHalNfcError error) { return err; } -static int32_t nfc_worker(void* context) { +static int32_t nfc_worker_listener(void* context) { furi_assert(context); + Nfc* instance = context; uint8_t rx_data[256]; uint16_t rx_bits = 0; @@ -96,6 +106,31 @@ static int32_t nfc_worker(void* context) { return 0; } +static int32_t nfc_worker_poller(void* context) { + furi_assert(context); + + Nfc* instance = context; + furi_assert(instance->state == NfcStateConfigured); + furi_assert(instance->callback); + + f_hal_nfc_poller_field_on(); + if(instance->guard_time_us) { + f_hal_nfc_timer_block_tx_start_us(instance->guard_time_us); + FHalNfcEvent event = f_hal_nfc_wait_event(F_HAL_NFC_EVENT_WAIT_FOREVER); + furi_assert(event & FHalNfcEventTimerBlockTxExpired); + } + + instance->state = NfcStatePollerReady; + + while(instance->state == NfcStatePollerReady) { + NfcEvent event = {.type = NfcEventTypePollerReady}; + instance->callback(event, instance->context); + furi_delay_ms(1); + } + + return 0; +} + Nfc* nfc_alloc() { Nfc* instance = malloc(sizeof(Nfc)); instance->state = NfcStateIdle; @@ -104,7 +139,6 @@ Nfc* nfc_alloc() { instance->worker_thread = furi_thread_alloc(); furi_thread_set_name(instance->worker_thread, "NfcWorker"); - furi_thread_set_callback(instance->worker_thread, nfc_worker); furi_thread_set_context(instance->worker_thread, instance); furi_thread_set_priority(instance->worker_thread, FuriThreadPriorityHighest); furi_thread_set_stack_size(instance->worker_thread, 2048); @@ -114,9 +148,12 @@ Nfc* nfc_alloc() { void nfc_free(Nfc* instance) { furi_assert(instance); + // TODO REWORK!!! if(instance->state == NfcStateListenStarted) { f_hal_nfc_abort(); furi_thread_join(instance->worker_thread); + } else if(instance->state == NfcStatePollerReady) { + nfc_poller_stop(instance); } furi_thread_free(instance->worker_thread); f_hal_nfc_low_power_mode_start(); @@ -124,20 +161,14 @@ void nfc_free(Nfc* instance) { free(instance); } -void nfc_set_event_callback(Nfc* instance, NfcEventCallback callback, void* context) { - furi_assert(instance); - furi_assert(callback); - - instance->callback = callback; - instance->context = context; -} - void nfc_config(Nfc* instance, NfcMode mode) { furi_assert(instance); if(mode == NfcModeNfcaPoller) { f_hal_nfc_set_mode(FHalNfcModeNfcaPoller, FHalNfcBitrate106); + instance->mode = NfcGenericModePoller; instance->state = NfcStateConfigured; } else if(mode == NfcModeNfcaListener) { + instance->mode = NfcGenericModeListener; f_hal_nfc_set_mode(FHalNfcModeNfcaListener, FHalNfcBitrate106); instance->state = NfcStateConfigured; } @@ -182,6 +213,54 @@ void nfc_set_mask_receive_time_fc(Nfc* instance, uint32_t mask_rx_time_fc) { instance->mask_rx_time_fc = mask_rx_time_fc; } +void nfc_start_worker(Nfc* instance, NfcEventCallback callback, void* context) { + furi_assert(instance); + furi_assert(instance->state == NfcStateConfigured); + furi_assert(instance->worker_thread); + furi_assert(callback); + + instance->callback = callback; + instance->context = context; + if(instance->mode == NfcGenericModePoller) { + furi_thread_set_callback(instance->worker_thread, nfc_worker_poller); + } else { + furi_thread_set_callback(instance->worker_thread, nfc_worker_listener); + } + furi_thread_start(instance->worker_thread); + instance->state = NfcStateListenStarted; + instance->comm_state = NfcCommStateIdle; +} + +void nfc_poller_stop(Nfc* instance) { + furi_assert(instance); + // TODO add Mutex for nfc state + instance->state = NfcStateStopRequested; + furi_thread_join(instance->worker_thread); +} + +NfcError nfc_listener_sleep(Nfc* instance) { + furi_assert(instance); + furi_assert(instance->state == NfcStateListenStarted); + + f_hal_nfc_listener_sleep(); + + return NfcErrorNone; +} + +NfcError nfc_listener_tx(Nfc* instance, uint8_t* tx_data, uint16_t tx_bits) { + furi_assert(instance); + furi_assert(tx_data); + + NfcError ret = NfcErrorNone; + FHalNfcError error = f_hal_nfc_listener_tx(tx_data, tx_bits); + if(error != FHalNfcErrorNone) { + FURI_LOG_E(TAG, "Failed in listener TX"); + ret = nfc_process_hal_error(error); + } + + return ret; +} + static NfcError nfc_poller_trx_state_machine(Nfc* instance, uint32_t fwt_fc) { FHalNfcEvent event = 0; NfcError error = NfcErrorNone; @@ -400,39 +479,3 @@ NfcError nfc_iso13444a_sdd_frame( return ret; } - -void nfc_listener_start(Nfc* instance, NfcEventCallback callback, void* context) { - furi_assert(instance); - furi_assert(instance->state == NfcStateConfigured); - furi_assert(instance->worker_thread); - furi_assert(callback); - - instance->callback = callback; - instance->context = context; - furi_thread_start(instance->worker_thread); - instance->state = NfcStateListenStarted; - instance->comm_state = NfcCommStateIdle; -} - -NfcError nfc_listener_sleep(Nfc* instance) { - furi_assert(instance); - furi_assert(instance->state == NfcStateListenStarted); - - f_hal_nfc_listener_sleep(); - - return NfcErrorNone; -} - -NfcError nfc_listener_tx(Nfc* instance, uint8_t* tx_data, uint16_t tx_bits) { - furi_assert(instance); - furi_assert(tx_data); - - NfcError ret = NfcErrorNone; - FHalNfcError error = f_hal_nfc_listener_tx(tx_data, tx_bits); - if(error != FHalNfcErrorNone) { - FURI_LOG_E(TAG, "Failed in listener TX"); - ret = nfc_process_hal_error(error); - } - - return ret; -} diff --git a/lib/nfc/nfc.h b/lib/nfc/nfc.h index e039675f69ab..f4eb75460a7c 100644 --- a/lib/nfc/nfc.h +++ b/lib/nfc/nfc.h @@ -18,6 +18,7 @@ typedef enum { NfcEventTypeRxEnd, NfcEventTypeListenerActivated, + NfcEventTypePollerReady, } NfcEventType; typedef struct { @@ -35,6 +36,12 @@ typedef void (*NfcEventCallback)(NfcEvent event, void* context); typedef enum { NfcModeNfcaPoller, NfcModeNfcaListener, + NfcModeNfcbPoller, + NfcModeNfcbListener, + NfcModeNfcfPoller, + NfcModeNfcfListener, + NfcModeNfcvPoller, + NfcModeNfcvListener, } NfcMode; typedef enum { @@ -56,8 +63,6 @@ Nfc* nfc_alloc(); void nfc_free(Nfc* instance); -void nfc_set_event_callback(Nfc* instance, NfcEventCallback callback, void* context); - void nfc_config(Nfc* instance, NfcMode mode); void nfc_set_fdt_poll_fc(Nfc* instance, uint32_t fdt_poll_fc); @@ -77,10 +82,14 @@ NfcError nfc_listener_set_col_res_data( uint8_t* atqa, uint8_t sak); -void nfc_listener_start(Nfc* instance, NfcEventCallback callback, void* context); +void nfc_start_worker(Nfc* instance, NfcEventCallback callback, void* context); NfcError nfc_listener_sleep(Nfc* instance); +void nfc_poller_stop(Nfc* instance); + +// Called from worker thread + NfcError nfc_listener_tx(Nfc* instance, uint8_t* tx_data, uint16_t tx_bits); NfcError nfc_trx( diff --git a/lib/nfc/protocols/nfca_listener.c b/lib/nfc/protocols/nfca_listener.c index 81aa1c25f450..8b75fbfd1ab3 100644 --- a/lib/nfc/protocols/nfca_listener.c +++ b/lib/nfc/protocols/nfca_listener.c @@ -88,7 +88,7 @@ NfcaListener* nfca_listener_alloc(NfcaData* data) { instance->data.uid_len, instance->data.atqa, instance->data.sak); - nfc_listener_start(instance->nfc, nfca_listener_event_handler, instance); + nfc_start_worker(instance->nfc, nfca_listener_event_handler, instance); return instance; } diff --git a/lib/nfc/protocols/nfca_poller.c b/lib/nfc/protocols/nfca_poller.c index 7e8ed0689695..329c2299f2f6 100644 --- a/lib/nfc/protocols/nfca_poller.c +++ b/lib/nfc/protocols/nfca_poller.c @@ -42,6 +42,8 @@ struct NfcaPoller { NfcaPollerState state; NfcaPollerColRes col_res; NfcaData data; + NfcaPollerEventCallback callback; + void* context; }; static NfcaError nfca_poller_process_error(NfcError error) { @@ -141,10 +143,59 @@ void nfca_poller_free(NfcaPoller* instance) { furi_assert(instance); furi_assert(instance->nfc); + nfc_poller_stop(instance->nfc); nfc_free(instance->nfc); free(instance); } +static void nfca_poller_event_callback(NfcEvent event, void* context) { + furi_assert(context); + + NfcaPoller* instance = context; + furi_assert(instance->callback); + + NfcaPollerEvent nfca_poller_event = {}; + if(event.type == NfcEventTypePollerReady) { + if(instance->state != NfcaPollerActivated) { + FURI_LOG_I(TAG, "nfca_poller_event_callback, NfcEventTypePollerReady event"); + NfcaData data = {}; + NfcaError error = nfca_poller_activate(instance, &data); + if(error == NfcaErrorNone) { + nfca_poller_event.type = NfcaPollerEventTypeActivated; + } else { + nfca_poller_event.type = NfcaPollerEventTypeError; + } + nfca_poller_event.data.error = error; + instance->callback(nfca_poller_event, instance->context); + } else { + nfca_poller_event.type = NfcaPollerEventTypeReady; + nfca_poller_event.data.error = NfcaErrorNone; + instance->callback(nfca_poller_event, instance->context); + } + } +} + +NfcaError + nfca_poller_start(NfcaPoller* instance, NfcaPollerEventCallback callback, void* context) { + furi_assert(instance); + furi_assert(callback); + + instance->callback = callback; + instance->context = context; + nfc_start_worker(instance->nfc, nfca_poller_event_callback, instance); + + return NfcaErrorNone; +} + +NfcaError nfca_poller_get_data(NfcaPoller* instance, NfcaData* data) { + furi_assert(instance); + furi_assert(data); + + *data = instance->data; + + return NfcaErrorNone; +} + NfcaError nfca_poller_check_presence(NfcaPoller* instance) { furi_assert(instance); furi_assert(instance->nfc); @@ -318,6 +369,31 @@ NfcaError nfca_poller_activate(NfcaPoller* instance, NfcaData* nfca_data) { return ret; } +typedef struct { + FuriThreadId thread_id; + NfcaError error; +} NfcaPollerContext; + +static void nfca_poller_activate_sync_callback(NfcaPollerEvent event, void* context) { + FURI_LOG_W(TAG, "nfca_poller_activate_sync_callback: %d event", event.type); + NfcaPollerContext* nfca_poller_context = context; + nfca_poller_context->error = event.data.error; + furi_thread_flags_set(nfca_poller_context->thread_id, 1); +} + +NfcaError nfca_poller_activate_sync(NfcaPoller* instance, NfcaData* nfca_data) { + furi_assert(instance); + NfcaPollerContext context = {}; + context.thread_id = furi_thread_get_current_id(); + nfca_poller_start(instance, nfca_poller_activate_sync_callback, &context); + furi_thread_flags_wait(1, FuriFlagWaitAny, FuriWaitForever); + furi_thread_flags_clear(1); + if(context.error == NfcaErrorNone) { + *nfca_data = instance->data; + } + return context.error; +} + NfcaError nfca_poller_txrx( NfcaPoller* instance, uint8_t* tx_buff, diff --git a/lib/nfc/protocols/nfca_poller.h b/lib/nfc/protocols/nfca_poller.h index bea7a02951c4..07e208179f9e 100644 --- a/lib/nfc/protocols/nfca_poller.h +++ b/lib/nfc/protocols/nfca_poller.h @@ -10,14 +10,40 @@ extern "C" { typedef struct NfcaPoller NfcaPoller; +typedef enum { + NfcaPollerEventTypeError, + NfcaPollerEventTypeActivated, + NfcaPollerEventTypeReady, +} NfcaPollerEventType; + +typedef struct { + NfcaError error; +} NfcaPollerEventData; + +typedef struct { + NfcaPollerEventType type; + NfcaPollerEventData data; +} NfcaPollerEvent; + +typedef void (*NfcaPollerEventCallback)(NfcaPollerEvent event, void* context); + NfcaPoller* nfca_poller_alloc(); void nfca_poller_free(NfcaPoller* instance); +NfcaError + nfca_poller_start(NfcaPoller* instance, NfcaPollerEventCallback callback, void* context); + +NfcaError nfca_poller_get_data(NfcaPoller* instance, NfcaData* data); + +// Syncronous API + NfcaError nfca_poller_check_presence(NfcaPoller* instance); NfcaError nfca_poller_activate(NfcaPoller* instance, NfcaData* nfca_data); +NfcaError nfca_poller_activate_sync(NfcaPoller* instance, NfcaData* nfca_data); + NfcaError nfca_poller_halt(NfcaPoller* instance); NfcaError nfca_poller_txrx( From f8506f264c3ed8f6dfd80fb82e4f1a7624f3b5b1 Mon Sep 17 00:00:00 2001 From: gornekich Date: Thu, 6 Apr 2023 17:46:43 +0400 Subject: [PATCH 018/149] nfc app: copy old nfc app --- applications/main/nfc_old/application.fam | 24 ++ .../main/nfc_old/helpers/nfc_custom_event.h | 15 + .../main/nfc_old/helpers/nfc_emv_parser.c | 82 +++++ .../main/nfc_old/helpers/nfc_emv_parser.h | 40 +++ applications/main/nfc_old/nfc_app.c | 316 ++++++++++++++++++ applications/main/nfc_old/nfc_app.h | 3 + applications/main/nfc_old/nfc_app_i.h | 118 +++++++ applications/main/nfc_old/nfc_cli.c | 228 +++++++++++++ applications/main/nfc_old/scenes/nfc_scene.c | 30 ++ applications/main/nfc_old/scenes/nfc_scene.h | 29 ++ .../main/nfc_old/scenes/nfc_scene_config.h | 65 ++++ .../main/nfc_old/scenes/nfc_scene_debug.c | 54 +++ .../main/nfc_old/scenes/nfc_scene_delete.c | 77 +++++ .../nfc_old/scenes/nfc_scene_delete_success.c | 45 +++ .../nfc_old/scenes/nfc_scene_detect_reader.c | 103 ++++++ .../nfc_old/scenes/nfc_scene_device_info.c | 86 +++++ .../nfc_old/scenes/nfc_scene_dict_not_found.c | 52 +++ .../scenes/nfc_scene_emulate_apdu_sequence.c | 34 ++ .../nfc_old/scenes/nfc_scene_emulate_uid.c | 144 ++++++++ .../main/nfc_old/scenes/nfc_scene_emv_menu.c | 46 +++ .../scenes/nfc_scene_emv_read_success.c | 113 +++++++ .../nfc_old/scenes/nfc_scene_exit_confirm.c | 52 +++ .../nfc_old/scenes/nfc_scene_extra_actions.c | 72 ++++ .../main/nfc_old/scenes/nfc_scene_field.c | 33 ++ .../nfc_old/scenes/nfc_scene_file_select.c | 28 ++ .../nfc_old/scenes/nfc_scene_generate_info.c | 60 ++++ .../scenes/nfc_scene_mf_classic_data.c | 106 ++++++ .../scenes/nfc_scene_mf_classic_dict_attack.c | 186 +++++++++++ .../scenes/nfc_scene_mf_classic_emulate.c | 69 ++++ .../scenes/nfc_scene_mf_classic_keys.c | 71 ++++ .../scenes/nfc_scene_mf_classic_keys_add.c | 60 ++++ .../scenes/nfc_scene_mf_classic_keys_delete.c | 83 +++++ .../scenes/nfc_scene_mf_classic_keys_list.c | 100 ++++++ ...nfc_scene_mf_classic_keys_warn_duplicate.c | 47 +++ .../scenes/nfc_scene_mf_classic_menu.c | 82 +++++ .../nfc_scene_mf_classic_read_success.c | 82 +++++ .../scenes/nfc_scene_mf_classic_update.c | 98 ++++++ .../nfc_scene_mf_classic_update_success.c | 44 +++ .../scenes/nfc_scene_mf_classic_write.c | 92 +++++ .../scenes/nfc_scene_mf_classic_write_fail.c | 58 ++++ .../nfc_scene_mf_classic_write_success.c | 44 +++ .../scenes/nfc_scene_mf_classic_wrong_card.c | 53 +++ .../nfc_old/scenes/nfc_scene_mf_desfire_app.c | 120 +++++++ .../scenes/nfc_scene_mf_desfire_data.c | 104 ++++++ .../scenes/nfc_scene_mf_desfire_menu.c | 72 ++++ .../nfc_scene_mf_desfire_read_success.c | 96 ++++++ .../scenes/nfc_scene_mf_ultralight_data.c | 32 ++ .../scenes/nfc_scene_mf_ultralight_emulate.c | 74 ++++ .../nfc_scene_mf_ultralight_key_input.c | 44 +++ .../scenes/nfc_scene_mf_ultralight_menu.c | 87 +++++ .../nfc_scene_mf_ultralight_read_auth.c | 116 +++++++ ...nfc_scene_mf_ultralight_read_auth_result.c | 116 +++++++ .../nfc_scene_mf_ultralight_read_success.c | 84 +++++ .../nfc_scene_mf_ultralight_unlock_auto.c | 64 ++++ .../nfc_scene_mf_ultralight_unlock_menu.c | 83 +++++ .../nfc_scene_mf_ultralight_unlock_warn.c | 98 ++++++ .../nfc_old/scenes/nfc_scene_mfkey_complete.c | 49 +++ .../scenes/nfc_scene_mfkey_nonces_info.c | 55 +++ .../nfc_old/scenes/nfc_scene_nfc_data_info.c | 154 +++++++++ .../main/nfc_old/scenes/nfc_scene_nfca_menu.c | 68 ++++ .../scenes/nfc_scene_nfca_read_success.c | 73 ++++ .../main/nfc_old/scenes/nfc_scene_read.c | 123 +++++++ .../scenes/nfc_scene_read_card_success.c | 61 ++++ .../nfc_old/scenes/nfc_scene_read_card_type.c | 97 ++++++ .../scenes/nfc_scene_restore_original.c | 45 +++ .../nfc_scene_restore_original_confirm.c | 53 +++ .../nfc_old/scenes/nfc_scene_retry_confirm.c | 47 +++ .../main/nfc_old/scenes/nfc_scene_rpc.c | 86 +++++ .../main/nfc_old/scenes/nfc_scene_save_name.c | 93 ++++++ .../nfc_old/scenes/nfc_scene_save_success.c | 48 +++ .../nfc_old/scenes/nfc_scene_saved_menu.c | 180 ++++++++++ .../main/nfc_old/scenes/nfc_scene_set_atqa.c | 44 +++ .../main/nfc_old/scenes/nfc_scene_set_sak.c | 44 +++ .../main/nfc_old/scenes/nfc_scene_set_type.c | 68 ++++ .../main/nfc_old/scenes/nfc_scene_set_uid.c | 54 +++ .../main/nfc_old/scenes/nfc_scene_start.c | 98 ++++++ .../main/nfc_old/views/detect_reader.c | 190 +++++++++++ .../main/nfc_old/views/detect_reader.h | 36 ++ applications/main/nfc_old/views/dict_attack.c | 289 ++++++++++++++++ applications/main/nfc_old/views/dict_attack.h | 46 +++ 80 files changed, 6515 insertions(+) create mode 100644 applications/main/nfc_old/application.fam create mode 100644 applications/main/nfc_old/helpers/nfc_custom_event.h create mode 100644 applications/main/nfc_old/helpers/nfc_emv_parser.c create mode 100644 applications/main/nfc_old/helpers/nfc_emv_parser.h create mode 100644 applications/main/nfc_old/nfc_app.c create mode 100644 applications/main/nfc_old/nfc_app.h create mode 100644 applications/main/nfc_old/nfc_app_i.h create mode 100644 applications/main/nfc_old/nfc_cli.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene.h create mode 100644 applications/main/nfc_old/scenes/nfc_scene_config.h create mode 100644 applications/main/nfc_old/scenes/nfc_scene_debug.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_delete.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_delete_success.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_detect_reader.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_device_info.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_dict_not_found.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_emulate_apdu_sequence.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_emulate_uid.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_emv_menu.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_emv_read_success.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_exit_confirm.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_extra_actions.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_field.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_file_select.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_generate_info.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_mf_classic_data.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_mf_classic_dict_attack.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_mf_classic_emulate.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_add.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_delete.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_list.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_warn_duplicate.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_mf_classic_menu.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_mf_classic_read_success.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_mf_classic_update.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_mf_classic_update_success.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_mf_classic_write.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_mf_classic_write_fail.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_mf_classic_write_success.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_mf_classic_wrong_card.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_mf_desfire_app.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_mf_desfire_data.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_mf_desfire_menu.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_mf_desfire_read_success.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_data.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_emulate.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_key_input.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_menu.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_read_auth.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_read_auth_result.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_read_success.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_unlock_auto.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_unlock_menu.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_unlock_warn.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_mfkey_complete.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_mfkey_nonces_info.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_nfc_data_info.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_nfca_menu.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_nfca_read_success.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_read.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_read_card_success.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_read_card_type.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_restore_original.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_restore_original_confirm.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_retry_confirm.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_rpc.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_save_name.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_save_success.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_saved_menu.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_set_atqa.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_set_sak.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_set_type.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_set_uid.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_start.c create mode 100644 applications/main/nfc_old/views/detect_reader.c create mode 100644 applications/main/nfc_old/views/detect_reader.h create mode 100644 applications/main/nfc_old/views/dict_attack.c create mode 100644 applications/main/nfc_old/views/dict_attack.h diff --git a/applications/main/nfc_old/application.fam b/applications/main/nfc_old/application.fam new file mode 100644 index 000000000000..b67b8e6b2d1f --- /dev/null +++ b/applications/main/nfc_old/application.fam @@ -0,0 +1,24 @@ +App( + appid="nfc_old", + name="NFC", + apptype=FlipperAppType.APP, + targets=["f7"], + entry_point="nfc_app", + cdefines=["APP_NFC"], + requires=[ + "gui", + "dialogs", + ], + provides=["nfc_start"], + icon="A_NFC_14", + stack_size=5 * 1024, + order=30, +) + +App( + appid="nfc_old_start", + apptype=FlipperAppType.STARTUP, + entry_point="nfc_on_system_start", + requires=["nfc"], + order=30, +) diff --git a/applications/main/nfc_old/helpers/nfc_custom_event.h b/applications/main/nfc_old/helpers/nfc_custom_event.h new file mode 100644 index 000000000000..4227a5b14e33 --- /dev/null +++ b/applications/main/nfc_old/helpers/nfc_custom_event.h @@ -0,0 +1,15 @@ +#pragma once + +enum NfcCustomEvent { + // Reserve first 100 events for button types and indexes, starting from 0 + NfcCustomEventReserved = 100, + + NfcCustomEventViewExit, + NfcCustomEventWorkerExit, + NfcCustomEventByteInputDone, + NfcCustomEventTextInputDone, + NfcCustomEventDictAttackDone, + NfcCustomEventDictAttackSkip, + NfcCustomEventRpcLoad, + NfcCustomEventRpcSessionClose, +}; diff --git a/applications/main/nfc_old/helpers/nfc_emv_parser.c b/applications/main/nfc_old/helpers/nfc_emv_parser.c new file mode 100644 index 000000000000..30e102405e07 --- /dev/null +++ b/applications/main/nfc_old/helpers/nfc_emv_parser.c @@ -0,0 +1,82 @@ +#include "nfc_emv_parser.h" +#include + +static const char* nfc_resources_header = "Flipper EMV resources"; +static const uint32_t nfc_resources_file_version = 1; + +static bool nfc_emv_parser_search_data( + Storage* storage, + const char* file_name, + FuriString* key, + FuriString* data) { + bool parsed = false; + FlipperFormat* file = flipper_format_file_alloc(storage); + FuriString* temp_str; + temp_str = furi_string_alloc(); + + do { + // Open file + if(!flipper_format_file_open_existing(file, file_name)) break; + // Read file header and version + uint32_t version = 0; + if(!flipper_format_read_header(file, temp_str, &version)) break; + if(furi_string_cmp_str(temp_str, nfc_resources_header) || + (version != nfc_resources_file_version)) + break; + if(!flipper_format_read_string(file, furi_string_get_cstr(key), data)) break; + parsed = true; + } while(false); + + furi_string_free(temp_str); + flipper_format_free(file); + return parsed; +} + +bool nfc_emv_parser_get_aid_name( + Storage* storage, + uint8_t* aid, + uint8_t aid_len, + FuriString* aid_name) { + furi_assert(storage); + bool parsed = false; + FuriString* key; + key = furi_string_alloc(); + for(uint8_t i = 0; i < aid_len; i++) { + furi_string_cat_printf(key, "%02X", aid[i]); + } + if(nfc_emv_parser_search_data(storage, EXT_PATH("nfc/assets/aid.nfc"), key, aid_name)) { + parsed = true; + } + furi_string_free(key); + return parsed; +} + +bool nfc_emv_parser_get_country_name( + Storage* storage, + uint16_t country_code, + FuriString* country_name) { + bool parsed = false; + FuriString* key; + key = furi_string_alloc_printf("%04X", country_code); + if(nfc_emv_parser_search_data( + storage, EXT_PATH("nfc/assets/country_code.nfc"), key, country_name)) { + parsed = true; + } + furi_string_free(key); + return parsed; +} + +bool nfc_emv_parser_get_currency_name( + Storage* storage, + uint16_t currency_code, + FuriString* currency_name) { + bool parsed = false; + FuriString* key; + key = furi_string_alloc_printf("%04X", currency_code); + if(nfc_emv_parser_search_data( + storage, EXT_PATH("nfc/assets/currency_code.nfc"), key, currency_name)) { + parsed = true; + } + furi_string_free(key); + return parsed; +} diff --git a/applications/main/nfc_old/helpers/nfc_emv_parser.h b/applications/main/nfc_old/helpers/nfc_emv_parser.h new file mode 100644 index 000000000000..abe57f470fd1 --- /dev/null +++ b/applications/main/nfc_old/helpers/nfc_emv_parser.h @@ -0,0 +1,40 @@ +#pragma once + +#include +#include +#include + +/** Get EMV application name by number + * @param storage Storage instance + * @param aid - AID number array + * @param aid_len - AID length + * @param aid_name - string to keep AID name + * @return - true if AID found, false otherwies + */ +bool nfc_emv_parser_get_aid_name( + Storage* storage, + uint8_t* aid, + uint8_t aid_len, + FuriString* aid_name); + +/** Get country name by country code + * @param storage Storage instance + * @param country_code - ISO 3166 country code + * @param country_name - string to keep country name + * @return - true if country found, false otherwies + */ +bool nfc_emv_parser_get_country_name( + Storage* storage, + uint16_t country_code, + FuriString* country_name); + +/** Get currency name by currency code + * @param storage Storage instance + * @param currency_code - ISO 3166 currency code + * @param currency_name - string to keep currency name + * @return - true if currency found, false otherwies + */ +bool nfc_emv_parser_get_currency_name( + Storage* storage, + uint16_t currency_code, + FuriString* currency_name); diff --git a/applications/main/nfc_old/nfc_app.c b/applications/main/nfc_old/nfc_app.c new file mode 100644 index 000000000000..5884f8852d03 --- /dev/null +++ b/applications/main/nfc_old/nfc_app.c @@ -0,0 +1,316 @@ +#include "nfc_app_i.h" +#include +#include + +bool nfc_custom_event_callback(void* context, uint32_t event) { + furi_assert(context); + NfcApp* nfc = context; + return scene_manager_handle_custom_event(nfc->scene_manager, event); +} + +bool nfc_back_event_callback(void* context) { + furi_assert(context); + NfcApp* nfc = context; + return scene_manager_handle_back_event(nfc->scene_manager); +} + +static void nfc_rpc_command_callback(RpcAppSystemEvent event, void* context) { + furi_assert(context); + NfcApp* nfc = context; + + furi_assert(nfc->rpc_ctx); + + if(event == RpcAppEventSessionClose) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventRpcSessionClose); + rpc_system_app_set_callback(nfc->rpc_ctx, NULL, NULL); + nfc->rpc_ctx = NULL; + } else if(event == RpcAppEventAppExit) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); + } else if(event == RpcAppEventLoadFile) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventRpcLoad); + } else { + rpc_system_app_confirm(nfc->rpc_ctx, event, false); + } +} + +NfcApp* nfc_app_alloc() { + NfcApp* nfc = malloc(sizeof(NfcApp)); + + nfc->worker = nfc_worker_alloc(); + nfc->view_dispatcher = view_dispatcher_alloc(); + nfc->scene_manager = scene_manager_alloc(&nfc_scene_handlers, nfc); + view_dispatcher_enable_queue(nfc->view_dispatcher); + view_dispatcher_set_event_callback_context(nfc->view_dispatcher, nfc); + view_dispatcher_set_custom_event_callback(nfc->view_dispatcher, nfc_custom_event_callback); + view_dispatcher_set_navigation_event_callback(nfc->view_dispatcher, nfc_back_event_callback); + + // Nfc device + nfc->dev = nfc_device_alloc(); + furi_string_set(nfc->dev->folder, NFC_APP_FOLDER); + + // Open GUI record + nfc->gui = furi_record_open(RECORD_GUI); + + // Open Notification record + nfc->notifications = furi_record_open(RECORD_NOTIFICATION); + + // Submenu + nfc->submenu = submenu_alloc(); + view_dispatcher_add_view(nfc->view_dispatcher, NfcViewMenu, submenu_get_view(nfc->submenu)); + + // Dialog + nfc->dialog_ex = dialog_ex_alloc(); + view_dispatcher_add_view( + nfc->view_dispatcher, NfcViewDialogEx, dialog_ex_get_view(nfc->dialog_ex)); + + // Popup + nfc->popup = popup_alloc(); + view_dispatcher_add_view(nfc->view_dispatcher, NfcViewPopup, popup_get_view(nfc->popup)); + + // Loading + nfc->loading = loading_alloc(); + view_dispatcher_add_view(nfc->view_dispatcher, NfcViewLoading, loading_get_view(nfc->loading)); + + // Text Input + nfc->text_input = text_input_alloc(); + view_dispatcher_add_view( + nfc->view_dispatcher, NfcViewTextInput, text_input_get_view(nfc->text_input)); + + // Byte Input + nfc->byte_input = byte_input_alloc(); + view_dispatcher_add_view( + nfc->view_dispatcher, NfcViewByteInput, byte_input_get_view(nfc->byte_input)); + + // TextBox + nfc->text_box = text_box_alloc(); + view_dispatcher_add_view( + nfc->view_dispatcher, NfcViewTextBox, text_box_get_view(nfc->text_box)); + nfc->text_box_store = furi_string_alloc(); + + // Custom Widget + nfc->widget = widget_alloc(); + view_dispatcher_add_view(nfc->view_dispatcher, NfcViewWidget, widget_get_view(nfc->widget)); + + // Mifare Classic Dict Attack + nfc->dict_attack = dict_attack_alloc(); + view_dispatcher_add_view( + nfc->view_dispatcher, NfcViewDictAttack, dict_attack_get_view(nfc->dict_attack)); + + // Detect Reader + nfc->detect_reader = detect_reader_alloc(); + view_dispatcher_add_view( + nfc->view_dispatcher, NfcViewDetectReader, detect_reader_get_view(nfc->detect_reader)); + + // Generator + nfc->generator = NULL; + + return nfc; +} + +void nfc_app_free(NfcApp* nfc) { + furi_assert(nfc); + + if(nfc->rpc_state == NfcRpcStateEmulating) { + // Stop worker + nfc_worker_stop(nfc->worker); + } else if(nfc->rpc_state == NfcRpcStateEmulated) { + // Stop worker + nfc_worker_stop(nfc->worker); + // Save data in shadow file + if(furi_string_size(nfc->dev->load_path)) { + nfc_device_save_shadow(nfc->dev, furi_string_get_cstr(nfc->dev->load_path)); + } + } + if(nfc->rpc_ctx) { + rpc_system_app_send_exited(nfc->rpc_ctx); + rpc_system_app_set_callback(nfc->rpc_ctx, NULL, NULL); + nfc->rpc_ctx = NULL; + } + + // Nfc device + nfc_device_free(nfc->dev); + + // Submenu + view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewMenu); + submenu_free(nfc->submenu); + + // DialogEx + view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewDialogEx); + dialog_ex_free(nfc->dialog_ex); + + // Popup + view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewPopup); + popup_free(nfc->popup); + + // Loading + view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewLoading); + loading_free(nfc->loading); + + // TextInput + view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewTextInput); + text_input_free(nfc->text_input); + + // ByteInput + view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewByteInput); + byte_input_free(nfc->byte_input); + + // TextBox + view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewTextBox); + text_box_free(nfc->text_box); + furi_string_free(nfc->text_box_store); + + // Custom Widget + view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewWidget); + widget_free(nfc->widget); + + // Mifare Classic Dict Attack + view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewDictAttack); + dict_attack_free(nfc->dict_attack); + + // Detect Reader + view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewDetectReader); + detect_reader_free(nfc->detect_reader); + + // Worker + nfc_worker_stop(nfc->worker); + nfc_worker_free(nfc->worker); + + // View Dispatcher + view_dispatcher_free(nfc->view_dispatcher); + + // Scene Manager + scene_manager_free(nfc->scene_manager); + + // GUI + furi_record_close(RECORD_GUI); + nfc->gui = NULL; + + // Notifications + furi_record_close(RECORD_NOTIFICATION); + nfc->notifications = NULL; + + free(nfc); +} + +void nfc_text_store_set(NfcApp* nfc, const char* text, ...) { + va_list args; + va_start(args, text); + + vsnprintf(nfc->text_store, sizeof(nfc->text_store), text, args); + + va_end(args); +} + +void nfc_text_store_clear(NfcApp* nfc) { + memset(nfc->text_store, 0, sizeof(nfc->text_store)); +} + +void nfc_blink_read_start(NfcApp* nfc) { + notification_message(nfc->notifications, &sequence_blink_start_cyan); +} + +void nfc_blink_emulate_start(NfcApp* nfc) { + notification_message(nfc->notifications, &sequence_blink_start_magenta); +} + +void nfc_blink_detect_start(NfcApp* nfc) { + notification_message(nfc->notifications, &sequence_blink_start_yellow); +} + +void nfc_blink_stop(NfcApp* nfc) { + notification_message(nfc->notifications, &sequence_blink_stop); +} + +bool nfc_save_file(NfcApp* nfc) { + furi_string_printf( + nfc->dev->load_path, "%s/%s%s", NFC_APP_FOLDER, nfc->dev->dev_name, NFC_APP_EXTENSION); + bool file_saved = nfc_device_save(nfc->dev, furi_string_get_cstr(nfc->dev->load_path)); + return file_saved; +} + +void nfc_show_loading_popup(void* context, bool show) { + NfcApp* nfc = context; + TaskHandle_t timer_task = xTaskGetHandle(configTIMER_SERVICE_TASK_NAME); + + if(show) { + // Raise timer priority so that animations can play + vTaskPrioritySet(timer_task, configMAX_PRIORITIES - 1); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewLoading); + } else { + // Restore default timer priority + vTaskPrioritySet(timer_task, configTIMER_TASK_PRIORITY); + } +} + +static bool nfc_is_hal_ready() { + if(!furi_hal_nfc_is_init()) { + // No connection to the chip, show an error screen + DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS); + DialogMessage* message = dialog_message_alloc(); + dialog_message_set_text( + message, + "Error!\nNFC chip failed to start\n\n\nSend a photo of this to:\nsupport@flipperzero.one", + 0, + 0, + AlignLeft, + AlignTop); + dialog_message_show(dialogs, message); + dialog_message_free(message); + furi_record_close(RECORD_DIALOGS); + return false; + } else { + return true; + } +} + +int32_t nfc_app(void* p) { + if(!nfc_is_hal_ready()) return 0; + + NfcApp* nfc = nfc_app_alloc(); + char* args = p; + + // Check argument and run corresponding scene + if(args && strlen(args)) { + nfc_device_set_loading_callback(nfc->dev, nfc_show_loading_popup, nfc); + uint32_t rpc_ctx = 0; + if(sscanf(p, "RPC %lX", &rpc_ctx) == 1) { + nfc->rpc_ctx = (void*)rpc_ctx; + rpc_system_app_set_callback(nfc->rpc_ctx, nfc_rpc_command_callback, nfc); + rpc_system_app_send_started(nfc->rpc_ctx); + view_dispatcher_attach_to_gui( + nfc->view_dispatcher, nfc->gui, ViewDispatcherTypeDesktop); + scene_manager_next_scene(nfc->scene_manager, NfcSceneRpc); + } else { + view_dispatcher_attach_to_gui( + nfc->view_dispatcher, nfc->gui, ViewDispatcherTypeFullscreen); + if(nfc_device_load(nfc->dev, p, true)) { + if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate); + DOLPHIN_DEED(DolphinDeedNfcEmulate); + } else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate); + DOLPHIN_DEED(DolphinDeedNfcEmulate); + } else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneDeviceInfo); + } else { + scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); + DOLPHIN_DEED(DolphinDeedNfcEmulate); + } + } else { + // Exit app + view_dispatcher_stop(nfc->view_dispatcher); + } + } + nfc_device_set_loading_callback(nfc->dev, NULL, nfc); + } else { + view_dispatcher_attach_to_gui( + nfc->view_dispatcher, nfc->gui, ViewDispatcherTypeFullscreen); + scene_manager_next_scene(nfc->scene_manager, NfcSceneStart); + } + + view_dispatcher_run(nfc->view_dispatcher); + + nfc_app_free(nfc); + + return 0; +} diff --git a/applications/main/nfc_old/nfc_app.h b/applications/main/nfc_old/nfc_app.h new file mode 100644 index 000000000000..0e456fd48b27 --- /dev/null +++ b/applications/main/nfc_old/nfc_app.h @@ -0,0 +1,3 @@ +#pragma once + +typedef struct NfcApp NfcApp; diff --git a/applications/main/nfc_old/nfc_app_i.h b/applications/main/nfc_old/nfc_app_i.h new file mode 100644 index 000000000000..c361a5fc81f1 --- /dev/null +++ b/applications/main/nfc_old/nfc_app_i.h @@ -0,0 +1,118 @@ +#pragma once + +#include "nfc_app.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "views/dict_attack.h" +#include "views/detect_reader.h" + +#include +#include + +#include + +#include "rpc/rpc_app.h" + +#include + +ARRAY_DEF(MfClassicUserKeys, char*, M_PTR_OPLIST); + +#define NFC_TEXT_STORE_SIZE 128 +#define NFC_APP_FOLDER ANY_PATH("nfc") + +typedef enum { + NfcRpcStateIdle, + NfcRpcStateEmulating, + NfcRpcStateEmulated, +} NfcRpcState; + +struct NfcApp { + NfcWorker* worker; + ViewDispatcher* view_dispatcher; + Gui* gui; + NotificationApp* notifications; + SceneManager* scene_manager; + NfcDevice* dev; + FuriHalNfcDevData dev_edit_data; + + char text_store[NFC_TEXT_STORE_SIZE + 1]; + FuriString* text_box_store; + uint8_t byte_input_store[6]; + MfClassicUserKeys_t mfc_key_strs; // Used in MFC key listing + + void* rpc_ctx; + NfcRpcState rpc_state; + + // Common Views + Submenu* submenu; + DialogEx* dialog_ex; + Popup* popup; + Loading* loading; + TextInput* text_input; + ByteInput* byte_input; + TextBox* text_box; + Widget* widget; + DictAttack* dict_attack; + DetectReader* detect_reader; + + const NfcGenerator* generator; +}; + +typedef enum { + NfcViewMenu, + NfcViewDialogEx, + NfcViewPopup, + NfcViewLoading, + NfcViewTextInput, + NfcViewByteInput, + NfcViewTextBox, + NfcViewWidget, + NfcViewDictAttack, + NfcViewDetectReader, +} NfcView; + +NfcApp* nfc_alloc(); + +int32_t nfc_task(void* p); + +void nfc_text_store_set(NfcApp* nfc, const char* text, ...); + +void nfc_text_store_clear(NfcApp* nfc); + +void nfc_blink_read_start(NfcApp* nfc); + +void nfc_blink_emulate_start(NfcApp* nfc); + +void nfc_blink_detect_start(NfcApp* nfc); + +void nfc_blink_stop(NfcApp* nfc); + +bool nfc_save_file(NfcApp* nfc); + +void nfc_show_loading_popup(void* context, bool show); diff --git a/applications/main/nfc_old/nfc_cli.c b/applications/main/nfc_old/nfc_cli.c new file mode 100644 index 000000000000..da9e24cb9a74 --- /dev/null +++ b/applications/main/nfc_old/nfc_cli.c @@ -0,0 +1,228 @@ +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include + +static void nfc_cli_print_usage() { + printf("Usage:\r\n"); + printf("nfc \r\n"); + printf("Cmd list:\r\n"); + printf("\tdetect\t - detect nfc device\r\n"); + printf("\temulate\t - emulate predefined nfca card\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"); + } +} + +static void nfc_cli_check(Cli* cli, FuriString* args) { + UNUSED(args); + UNUSED(cli); +} + +static void nfc_cli_detect(Cli* cli, FuriString* args) { + UNUSED(args); + // Check if nfc worker is not busy + if(furi_hal_nfc_is_busy()) { + printf("Nfc is busy\r\n"); + return; + } + + FuriHalNfcDevData dev_data = {}; + bool cmd_exit = false; + furi_hal_nfc_exit_sleep(); + printf("Detecting nfc...\r\nPress Ctrl+C to abort\r\n"); + while(!cmd_exit) { + cmd_exit |= cli_cmd_interrupt_received(cli); + if(furi_hal_nfc_detect(&dev_data, 400)) { + printf("Found: %s ", nfc_get_dev_type(dev_data.type)); + printf("UID length: %d, UID:", dev_data.uid_len); + for(size_t i = 0; i < dev_data.uid_len; i++) { + printf("%02X", dev_data.uid[i]); + } + printf("\r\n"); + break; + } + furi_hal_nfc_sleep(); + furi_delay_ms(50); + } + furi_hal_nfc_sleep(); +} + +static void nfc_cli_emulate(Cli* cli, FuriString* args) { + UNUSED(args); + // Check if nfc worker is not busy + if(furi_hal_nfc_is_busy()) { + printf("Nfc is busy\r\n"); + return; + } + + furi_hal_nfc_exit_sleep(); + printf("Emulating NFC-A Type: T2T UID: 36 9C E7 B1 0A C1 34 SAK: 00 ATQA: 00/44\r\n"); + printf("Press Ctrl+C to abort\r\n"); + + FuriHalNfcDevData params = { + .uid = {0x36, 0x9C, 0xe7, 0xb1, 0x0A, 0xC1, 0x34}, + .uid_len = 7, + .atqa = {0x44, 0x00}, + .sak = 0x00, + .type = FuriHalNfcTypeA, + }; + + while(!cli_cmd_interrupt_received(cli)) { + if(furi_hal_nfc_listen(params.uid, params.uid_len, params.atqa, params.sak, false, 100)) { + printf("Reader detected\r\n"); + furi_hal_nfc_sleep(); + } + furi_delay_ms(50); + } + furi_hal_nfc_sleep(); +} + +static void nfc_cli_field(Cli* cli, FuriString* args) { + UNUSED(args); + // Check if nfc worker is not busy + if(furi_hal_nfc_is_busy()) { + printf("Nfc is busy\r\n"); + return; + } + + furi_hal_nfc_exit_sleep(); + furi_hal_nfc_field_on(); + + printf("Field is on. Don't leave device in this mode for too long.\r\n"); + printf("Press Ctrl+C to abort\r\n"); + + while(!cli_cmd_interrupt_received(cli)) { + furi_delay_ms(50); + } + + furi_hal_nfc_field_off(); + furi_hal_nfc_sleep(); +} + +static void nfc_cli_apdu(Cli* cli, FuriString* args) { + UNUSED(cli); + if(furi_hal_nfc_is_busy()) { + printf("Nfc is busy\r\n"); + return; + } + + furi_hal_nfc_exit_sleep(); + FuriString* data = NULL; + data = furi_string_alloc(); + FuriHalNfcTxRxContext tx_rx = {}; + FuriHalNfcDevData dev_data = {}; + uint8_t* req_buffer = NULL; + uint8_t* resp_buffer = NULL; + size_t apdu_size = 0; + size_t resp_size = 0; + + do { + if(!args_read_string_and_trim(args, data)) { + printf( + "Use like `nfc apdu 00a404000e325041592e5359532e444446303100 00a4040008a0000003010102` \r\n"); + break; + } + + printf("detecting tag\r\n"); + if(!furi_hal_nfc_detect(&dev_data, 300)) { + printf("Failed to detect tag\r\n"); + break; + } + do { + apdu_size = furi_string_size(data) / 2; + req_buffer = malloc(apdu_size); + hex_chars_to_uint8(furi_string_get_cstr(data), req_buffer); + + memcpy(tx_rx.tx_data, req_buffer, apdu_size); + tx_rx.tx_bits = apdu_size * 8; + tx_rx.tx_rx_type = FuriHalNfcTxRxTypeDefault; + + printf("Sending APDU:%s to Tag\r\n", furi_string_get_cstr(data)); + if(!furi_hal_nfc_tx_rx(&tx_rx, 300)) { + printf("Failed to tx_rx\r\n"); + break; + } + resp_size = (tx_rx.rx_bits / 8) * 2; + resp_buffer = malloc(resp_size); + uint8_to_hex_chars(tx_rx.rx_data, resp_buffer, resp_size); + resp_buffer[resp_size] = 0; + printf("Response: %s\r\n", resp_buffer); + free(req_buffer); + free(resp_buffer); + req_buffer = NULL; + resp_buffer = NULL; + } while(args_read_string_and_trim(args, data)); + } while(false); + + free(req_buffer); + free(resp_buffer); + furi_string_free(data); + furi_hal_nfc_sleep(); +} + +static void nfc_cli(Cli* cli, FuriString* args, void* context) { + UNUSED(context); + FuriString* cmd; + cmd = furi_string_alloc(); + + do { + if(!args_read_string_and_trim(args, cmd)) { + nfc_cli_print_usage(); + break; + } + if(furi_string_cmp_str(cmd, "c") == 0) { + nfc_cli_check(cli, args); + break; + } + if(furi_string_cmp_str(cmd, "detect") == 0) { + nfc_cli_detect(cli, args); + break; + } + if(furi_string_cmp_str(cmd, "emulate") == 0) { + nfc_cli_emulate(cli, args); + 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); + break; + } + } + + nfc_cli_print_usage(); + } while(false); + + furi_string_free(cmd); +} + +void nfc_on_system_start() { +#ifdef SRV_CLI + Cli* cli = furi_record_open(RECORD_CLI); + cli_add_command(cli, "nfc", CliCommandFlagDefault, nfc_cli, NULL); + furi_record_close(RECORD_CLI); +#else + UNUSED(nfc_cli); +#endif +} diff --git a/applications/main/nfc_old/scenes/nfc_scene.c b/applications/main/nfc_old/scenes/nfc_scene.c new file mode 100644 index 000000000000..652c8f8cc65c --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene.c @@ -0,0 +1,30 @@ +#include "nfc_scene.h" + +// Generate scene on_enter handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter, +void (*const nfc_on_enter_handlers[])(void*) = { +#include "nfc_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_event handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event, +bool (*const nfc_on_event_handlers[])(void* context, SceneManagerEvent event) = { +#include "nfc_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_exit handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit, +void (*const nfc_on_exit_handlers[])(void* context) = { +#include "nfc_scene_config.h" +}; +#undef ADD_SCENE + +// Initialize scene handlers configuration structure +const SceneManagerHandlers nfc_scene_handlers = { + .on_enter_handlers = nfc_on_enter_handlers, + .on_event_handlers = nfc_on_event_handlers, + .on_exit_handlers = nfc_on_exit_handlers, + .scene_num = NfcSceneNum, +}; diff --git a/applications/main/nfc_old/scenes/nfc_scene.h b/applications/main/nfc_old/scenes/nfc_scene.h new file mode 100644 index 000000000000..3e32224183ca --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +// Generate scene id and total number +#define ADD_SCENE(prefix, name, id) NfcScene##id, +typedef enum { +#include "nfc_scene_config.h" + NfcSceneNum, +} NfcScene; +#undef ADD_SCENE + +extern const SceneManagerHandlers nfc_scene_handlers; + +// Generate scene on_enter handlers declaration +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*); +#include "nfc_scene_config.h" +#undef ADD_SCENE + +// Generate scene on_event handlers declaration +#define ADD_SCENE(prefix, name, id) \ + bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event); +#include "nfc_scene_config.h" +#undef ADD_SCENE + +// Generate scene on_exit handlers declaration +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context); +#include "nfc_scene_config.h" +#undef ADD_SCENE diff --git a/applications/main/nfc_old/scenes/nfc_scene_config.h b/applications/main/nfc_old/scenes/nfc_scene_config.h new file mode 100644 index 000000000000..a9da07dfda00 --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_config.h @@ -0,0 +1,65 @@ +ADD_SCENE(nfc, start, Start) +ADD_SCENE(nfc, read, Read) +ADD_SCENE(nfc, saved_menu, SavedMenu) +ADD_SCENE(nfc, extra_actions, ExtraActions) +ADD_SCENE(nfc, set_type, SetType) +ADD_SCENE(nfc, set_sak, SetSak) +ADD_SCENE(nfc, set_atqa, SetAtqa) +ADD_SCENE(nfc, set_uid, SetUid) +ADD_SCENE(nfc, generate_info, GenerateInfo) +ADD_SCENE(nfc, read_card_success, ReadCardSuccess) +ADD_SCENE(nfc, save_name, SaveName) +ADD_SCENE(nfc, save_success, SaveSuccess) +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, mf_ultralight_read_success, MfUltralightReadSuccess) +ADD_SCENE(nfc, mf_ultralight_data, MfUltralightData) +ADD_SCENE(nfc, mf_ultralight_menu, MfUltralightMenu) +ADD_SCENE(nfc, mf_ultralight_emulate, MfUltralightEmulate) +ADD_SCENE(nfc, mf_ultralight_read_auth, MfUltralightReadAuth) +ADD_SCENE(nfc, mf_ultralight_read_auth_result, MfUltralightReadAuthResult) +ADD_SCENE(nfc, mf_ultralight_key_input, MfUltralightKeyInput) +ADD_SCENE(nfc, mf_ultralight_unlock_auto, MfUltralightUnlockAuto) +ADD_SCENE(nfc, mf_ultralight_unlock_menu, MfUltralightUnlockMenu) +ADD_SCENE(nfc, mf_ultralight_unlock_warn, MfUltralightUnlockWarn) +ADD_SCENE(nfc, mf_desfire_read_success, MfDesfireReadSuccess) +ADD_SCENE(nfc, mf_desfire_menu, MfDesfireMenu) +ADD_SCENE(nfc, mf_desfire_data, MfDesfireData) +ADD_SCENE(nfc, mf_desfire_app, MfDesfireApp) +ADD_SCENE(nfc, mf_classic_read_success, MfClassicReadSuccess) +ADD_SCENE(nfc, mf_classic_data, MfClassicData) +ADD_SCENE(nfc, mf_classic_menu, MfClassicMenu) +ADD_SCENE(nfc, mf_classic_emulate, MfClassicEmulate) +ADD_SCENE(nfc, mf_classic_keys, MfClassicKeys) +ADD_SCENE(nfc, mf_classic_keys_add, MfClassicKeysAdd) +ADD_SCENE(nfc, mf_classic_keys_list, MfClassicKeysList) +ADD_SCENE(nfc, mf_classic_keys_delete, MfClassicKeysDelete) +ADD_SCENE(nfc, mf_classic_keys_warn_duplicate, MfClassicKeysWarnDuplicate) +ADD_SCENE(nfc, mf_classic_dict_attack, MfClassicDictAttack) +ADD_SCENE(nfc, mf_classic_write, MfClassicWrite) +ADD_SCENE(nfc, mf_classic_write_success, MfClassicWriteSuccess) +ADD_SCENE(nfc, mf_classic_write_fail, MfClassicWriteFail) +ADD_SCENE(nfc, mf_classic_update, MfClassicUpdate) +ADD_SCENE(nfc, mf_classic_update_success, MfClassicUpdateSuccess) +ADD_SCENE(nfc, mf_classic_wrong_card, MfClassicWrongCard) +ADD_SCENE(nfc, emv_read_success, EmvReadSuccess) +ADD_SCENE(nfc, emv_menu, EmvMenu) +ADD_SCENE(nfc, emulate_apdu_sequence, EmulateApduSequence) +ADD_SCENE(nfc, device_info, DeviceInfo) +ADD_SCENE(nfc, delete, Delete) +ADD_SCENE(nfc, delete_success, DeleteSuccess) +ADD_SCENE(nfc, restore_original_confirm, RestoreOriginalConfirm) +ADD_SCENE(nfc, restore_original, RestoreOriginal) +ADD_SCENE(nfc, debug, Debug) +ADD_SCENE(nfc, field, Field) +ADD_SCENE(nfc, dict_not_found, DictNotFound) +ADD_SCENE(nfc, rpc, Rpc) +ADD_SCENE(nfc, exit_confirm, ExitConfirm) +ADD_SCENE(nfc, retry_confirm, RetryConfirm) +ADD_SCENE(nfc, detect_reader, DetectReader) +ADD_SCENE(nfc, mfkey_nonces_info, MfkeyNoncesInfo) +ADD_SCENE(nfc, mfkey_complete, MfkeyComplete) +ADD_SCENE(nfc, nfc_data_info, NfcDataInfo) +ADD_SCENE(nfc, read_card_type, ReadCardType) diff --git a/applications/main/nfc_old/scenes/nfc_scene_debug.c b/applications/main/nfc_old/scenes/nfc_scene_debug.c new file mode 100644 index 000000000000..f6705c880f39 --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_debug.c @@ -0,0 +1,54 @@ +#include "../nfc_app_i.h" + +enum SubmenuDebugIndex { + SubmenuDebugIndexField, + SubmenuDebugIndexApdu, +}; + +void nfc_scene_debug_submenu_callback(void* context, uint32_t index) { + NfcApp* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, index); +} + +void nfc_scene_debug_on_enter(void* context) { + NfcApp* nfc = context; + Submenu* submenu = nfc->submenu; + + submenu_add_item( + submenu, "Field", SubmenuDebugIndexField, nfc_scene_debug_submenu_callback, nfc); + submenu_add_item( + submenu, "Apdu", SubmenuDebugIndexApdu, nfc_scene_debug_submenu_callback, nfc); + + submenu_set_selected_item( + submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneDebug)); + + nfc_device_clear(nfc->dev); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); +} + +bool nfc_scene_debug_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuDebugIndexField) { + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneDebug, SubmenuDebugIndexField); + scene_manager_next_scene(nfc->scene_manager, NfcSceneField); + consumed = true; + } else if(event.event == SubmenuDebugIndexApdu) { + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneDebug, SubmenuDebugIndexApdu); + scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateApduSequence); + consumed = true; + } + } + return consumed; +} + +void nfc_scene_debug_on_exit(void* context) { + NfcApp* nfc = context; + + submenu_reset(nfc->submenu); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_delete.c b/applications/main/nfc_old/scenes/nfc_scene_delete.c new file mode 100644 index 000000000000..a5debe5e1b47 --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_delete.c @@ -0,0 +1,77 @@ +#include "../nfc_app_i.h" + +void nfc_scene_delete_widget_callback(GuiButtonType result, InputType type, void* context) { + NfcApp* nfc = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); + } +} + +void nfc_scene_delete_on_enter(void* context) { + NfcApp* nfc = context; + FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data; + + // Setup Custom Widget view + FuriString* temp_str; + temp_str = furi_string_alloc(); + + furi_string_printf(temp_str, "\e#Delete %s?\e#", nfc->dev->dev_name); + widget_add_text_box_element( + nfc->widget, 0, 0, 128, 23, AlignCenter, AlignCenter, furi_string_get_cstr(temp_str), false); + widget_add_button_element( + nfc->widget, GuiButtonTypeLeft, "Cancel", nfc_scene_delete_widget_callback, nfc); + widget_add_button_element( + nfc->widget, GuiButtonTypeRight, "Delete", nfc_scene_delete_widget_callback, nfc); + + furi_string_set(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]); + } + widget_add_string_element( + nfc->widget, 64, 24, AlignCenter, AlignTop, FontSecondary, furi_string_get_cstr(temp_str)); + + NfcProtocol protocol = nfc->dev->dev_data.protocol; + if(protocol == NfcDeviceProtocolEMV) { + furi_string_set(temp_str, "EMV bank card"); + } else if(protocol == NfcDeviceProtocolMifareUl) { + furi_string_set(temp_str, nfc_mf_ul_type(nfc->dev->dev_data.mf_ul_data.type, true)); + } else if(protocol == NfcDeviceProtocolMifareClassic) { + furi_string_set(temp_str, nfc_mf_classic_type(nfc->dev->dev_data.mf_classic_data.type)); + } else if(protocol == NfcDeviceProtocolMifareDesfire) { + furi_string_set(temp_str, "MIFARE DESFire"); + } else { + furi_string_set(temp_str, "Unknown ISO tag"); + } + widget_add_string_element( + nfc->widget, 64, 34, AlignCenter, AlignTop, FontSecondary, furi_string_get_cstr(temp_str)); + widget_add_string_element(nfc->widget, 64, 44, AlignCenter, AlignTop, FontSecondary, "NFC-A"); + furi_string_free(temp_str); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); +} + +bool nfc_scene_delete_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeLeft) { + consumed = scene_manager_previous_scene(nfc->scene_manager); + } else if(event.event == GuiButtonTypeRight) { + if(nfc_device_delete(nfc->dev, true)) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneDeleteSuccess); + } else { + scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneStart); + } + consumed = true; + } + } + return consumed; +} + +void nfc_scene_delete_on_exit(void* context) { + NfcApp* nfc = context; + + widget_reset(nfc->widget); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_delete_success.c b/applications/main/nfc_old/scenes/nfc_scene_delete_success.c new file mode 100644 index 000000000000..f0c22eec4d58 --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_delete_success.c @@ -0,0 +1,45 @@ +#include "../nfc_app_i.h" + +void nfc_scene_delete_success_popup_callback(void* context) { + NfcApp* nfc = context; + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); +} + +void nfc_scene_delete_success_on_enter(void* context) { + NfcApp* nfc = context; + + // Setup view + Popup* popup = nfc->popup; + popup_set_icon(popup, 0, 2, &I_DolphinMafia_115x62); + popup_set_header(popup, "Deleted", 83, 19, AlignLeft, AlignBottom); + popup_set_timeout(popup, 1500); + popup_set_context(popup, nfc); + popup_set_callback(popup, nfc_scene_delete_success_popup_callback); + popup_enable_timeout(popup); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); +} + +bool nfc_scene_delete_success_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventViewExit) { + if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneMfClassicKeys)) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneMfClassicKeys); + } else { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneFileSelect); + } + } + } + return consumed; +} + +void nfc_scene_delete_success_on_exit(void* context) { + NfcApp* nfc = context; + + // Clear view + popup_reset(nfc->popup); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_detect_reader.c b/applications/main/nfc_old/scenes/nfc_scene_detect_reader.c new file mode 100644 index 000000000000..85c698d05350 --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_detect_reader.c @@ -0,0 +1,103 @@ +#include "../nfc_app_i.h" + +#define NFC_SCENE_DETECT_READER_PAIR_NONCES_MAX (10U) + +static const NotificationSequence sequence_detect_reader = { + &message_green_255, + &message_blue_255, + &message_do_not_reset, + NULL, +}; + +bool nfc_detect_reader_worker_callback(NfcWorkerEvent event, void* context) { + UNUSED(event); + furi_assert(context); + NfcApp* nfc = context; + view_dispatcher_send_custom_event(nfc->view_dispatcher, event); + return true; +} + +void nfc_scene_detect_reader_callback(void* context) { + furi_assert(context); + NfcApp* nfc = context; + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); +} + +void nfc_scene_detect_reader_on_enter(void* context) { + NfcApp* nfc = context; + + detect_reader_set_callback(nfc->detect_reader, nfc_scene_detect_reader_callback, nfc); + detect_reader_set_nonces_max(nfc->detect_reader, NFC_SCENE_DETECT_READER_PAIR_NONCES_MAX); + NfcDeviceData* dev_data = &nfc->dev->dev_data; + if(dev_data->nfc_data.uid_len) { + detect_reader_set_uid( + nfc->detect_reader, dev_data->nfc_data.uid, dev_data->nfc_data.uid_len); + } + + // Store number of collected nonces in scene state + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneDetectReader, 0); + notification_message(nfc->notifications, &sequence_detect_reader); + + nfc_worker_start( + nfc->worker, + NfcWorkerStateAnalyzeReader, + &nfc->dev->dev_data, + nfc_detect_reader_worker_callback, + nfc); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDetectReader); +} + +bool nfc_scene_detect_reader_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + uint32_t nonces_collected = + scene_manager_get_scene_state(nfc->scene_manager, NfcSceneDetectReader); + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventViewExit) { + nfc_worker_stop(nfc->worker); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfkeyNoncesInfo); + consumed = true; + } else if(event.event == NfcWorkerEventDetectReaderMfkeyCollected) { + nonces_collected += 2; + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneDetectReader, nonces_collected); + detect_reader_set_nonces_collected(nfc->detect_reader, nonces_collected); + if(nonces_collected >= NFC_SCENE_DETECT_READER_PAIR_NONCES_MAX) { + detect_reader_set_state(nfc->detect_reader, DetectReaderStateDone); + nfc_blink_stop(nfc); + notification_message(nfc->notifications, &sequence_single_vibro); + notification_message(nfc->notifications, &sequence_set_green_255); + nfc_worker_stop(nfc->worker); + } + consumed = true; + } else if(event.event == NfcWorkerEventDetectReaderDetected) { + if(nonces_collected < NFC_SCENE_DETECT_READER_PAIR_NONCES_MAX) { + notification_message(nfc->notifications, &sequence_blink_start_cyan); + detect_reader_set_state(nfc->detect_reader, DetectReaderStateReaderDetected); + } + } else if(event.event == NfcWorkerEventDetectReaderLost) { + if(nonces_collected < NFC_SCENE_DETECT_READER_PAIR_NONCES_MAX) { + nfc_blink_stop(nfc); + notification_message(nfc->notifications, &sequence_detect_reader); + detect_reader_set_state(nfc->detect_reader, DetectReaderStateReaderLost); + } + } + } + + return consumed; +} + +void nfc_scene_detect_reader_on_exit(void* context) { + NfcApp* nfc = context; + + // Stop worker + nfc_worker_stop(nfc->worker); + + // Clear view + detect_reader_reset(nfc->detect_reader); + + // Stop notifications + nfc_blink_stop(nfc); + notification_message(nfc->notifications, &sequence_reset_green); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_device_info.c b/applications/main/nfc_old/scenes/nfc_scene_device_info.c new file mode 100644 index 000000000000..6d1bc8b42381 --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_device_info.c @@ -0,0 +1,86 @@ +#include "../nfc_app_i.h" +#include "../helpers/nfc_emv_parser.h" + +void nfc_scene_device_info_widget_callback(GuiButtonType result, InputType type, void* context) { + NfcApp* nfc = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); + } +} + +void nfc_scene_device_info_on_enter(void* context) { + NfcApp* nfc = context; + NfcDeviceData* dev_data = &nfc->dev->dev_data; + + FuriString* temp_str; + temp_str = furi_string_alloc(); + + if(dev_data->protocol == NfcDeviceProtocolEMV) { + EmvData* emv_data = &dev_data->emv_data; + furi_string_printf(temp_str, "\e#%s\n", emv_data->name); + for(uint8_t i = 0; i < emv_data->number_len; i += 2) { + furi_string_cat_printf( + temp_str, "%02X%02X ", emv_data->number[i], emv_data->number[i + 1]); + } + furi_string_trim(temp_str); + + // Add expiration date + if(emv_data->exp_mon) { + furi_string_cat_printf( + temp_str, "\nExp: %02X/%02X", emv_data->exp_mon, emv_data->exp_year); + } + // Parse currency code + if((emv_data->currency_code)) { + FuriString* currency_name; + currency_name = furi_string_alloc(); + if(nfc_emv_parser_get_currency_name( + nfc->dev->storage, emv_data->currency_code, currency_name)) { + furi_string_cat_printf( + temp_str, "\nCur: %s ", furi_string_get_cstr(currency_name)); + } + furi_string_free(currency_name); + } + // Parse country code + if((emv_data->country_code)) { + FuriString* country_name; + country_name = furi_string_alloc(); + if(nfc_emv_parser_get_country_name( + nfc->dev->storage, emv_data->country_code, country_name)) { + furi_string_cat_printf(temp_str, "Reg: %s", furi_string_get_cstr(country_name)); + } + furi_string_free(country_name); + } + } else if( + dev_data->protocol == NfcDeviceProtocolMifareClassic || + dev_data->protocol == NfcDeviceProtocolMifareUl) { + furi_string_set(temp_str, nfc->dev->dev_data.parsed_data); + } + + widget_add_text_scroll_element(nfc->widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); + furi_string_free(temp_str); + + widget_add_button_element( + nfc->widget, GuiButtonTypeRight, "More", nfc_scene_device_info_widget_callback, nfc); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); +} + +bool nfc_scene_device_info_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeRight) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); + consumed = true; + } + } + return consumed; +} + +void nfc_scene_device_info_on_exit(void* context) { + NfcApp* nfc = context; + + // Clear views + widget_reset(nfc->widget); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_dict_not_found.c b/applications/main/nfc_old/scenes/nfc_scene_dict_not_found.c new file mode 100644 index 000000000000..3b525c17e84f --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_dict_not_found.c @@ -0,0 +1,52 @@ +#include "../nfc_app_i.h" + +void nfc_scene_dict_not_found_popup_callback(void* context) { + NfcApp* nfc = context; + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); +} + +void nfc_scene_dict_not_found_on_enter(void* context) { + NfcApp* nfc = context; + + // Setup view + Popup* popup = nfc->popup; + popup_set_text( + popup, + "Function requires\nan SD card with\nfresh databases.", + 82, + 24, + AlignCenter, + AlignCenter); + popup_set_icon(popup, 6, 10, &I_SDQuestion_35x43); + popup_set_timeout(popup, 2500); + popup_set_context(popup, nfc); + popup_set_callback(popup, nfc_scene_dict_not_found_popup_callback); + popup_enable_timeout(popup); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); +} + +bool nfc_scene_dict_not_found_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventViewExit) { + if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneMfClassicKeys)) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneMfClassicKeys); + } else if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneExtraActions)) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneExtraActions); + } else { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneStart); + } + } + } + return consumed; +} + +void nfc_scene_dict_not_found_on_exit(void* context) { + NfcApp* nfc = context; + popup_reset(nfc->popup); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_emulate_apdu_sequence.c b/applications/main/nfc_old/scenes/nfc_scene_emulate_apdu_sequence.c new file mode 100644 index 000000000000..81d00aeffc2c --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_emulate_apdu_sequence.c @@ -0,0 +1,34 @@ +#include "../nfc_app_i.h" +#include + +void nfc_scene_emulate_apdu_sequence_on_enter(void* context) { + NfcApp* nfc = context; + + // Setup view + Popup* popup = nfc->popup; + popup_set_header(popup, "Run APDU reader", 64, 31, AlignCenter, AlignTop); + + // Setup and start worker + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); + nfc_worker_start(nfc->worker, NfcWorkerStateEmulateApdu, &nfc->dev->dev_data, NULL, nfc); + + nfc_blink_emulate_start(nfc); +} + +bool nfc_scene_emulate_apdu_sequence_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + UNUSED(event); + bool consumed = false; + return consumed; +} + +void nfc_scene_emulate_apdu_sequence_on_exit(void* context) { + NfcApp* nfc = context; + + // Stop worker + nfc_worker_stop(nfc->worker); + // Clear view + popup_reset(nfc->popup); + + nfc_blink_stop(nfc); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_emulate_uid.c b/applications/main/nfc_old/scenes/nfc_scene_emulate_uid.c new file mode 100644 index 000000000000..10435d2c7550 --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_emulate_uid.c @@ -0,0 +1,144 @@ +#include "../nfc_app_i.h" + +#define NFC_SCENE_EMULATE_UID_LOG_SIZE_MAX (200) + +enum { + NfcSceneEmulateUidStateWidget, + NfcSceneEmulateUidStateTextBox, +}; + +bool nfc_emulate_uid_worker_callback(NfcWorkerEvent event, void* context) { + UNUSED(event); + furi_assert(context); + NfcApp* nfc = context; + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit); + return true; +} + +void nfc_scene_emulate_uid_widget_callback(GuiButtonType result, InputType type, void* context) { + furi_assert(context); + NfcApp* nfc = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); + } +} + +void nfc_emulate_uid_textbox_callback(void* context) { + furi_assert(context); + NfcApp* nfc = context; + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); +} + +// Add widget with device name or inform that data received +static void nfc_scene_emulate_uid_widget_config(NfcApp* nfc, bool data_received) { + FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; + Widget* widget = nfc->widget; + widget_reset(widget); + FuriString* info_str; + info_str = furi_string_alloc(); + + widget_add_icon_element(widget, 0, 3, &I_NFC_dolphin_emulation_47x61); + widget_add_string_element(widget, 57, 13, AlignLeft, AlignTop, FontPrimary, "Emulating UID"); + if(strcmp(nfc->dev->dev_name, "") != 0) { + furi_string_printf(info_str, "%s", nfc->dev->dev_name); + } else { + for(uint8_t i = 0; i < data->uid_len; i++) { + furi_string_cat_printf(info_str, "%02X ", data->uid[i]); + } + } + furi_string_trim(info_str); + widget_add_text_box_element( + widget, 57, 28, 67, 25, AlignCenter, AlignTop, furi_string_get_cstr(info_str), true); + furi_string_free(info_str); + if(data_received) { + widget_add_button_element( + widget, GuiButtonTypeCenter, "Log", nfc_scene_emulate_uid_widget_callback, nfc); + } +} + +void nfc_scene_emulate_uid_on_enter(void* context) { + NfcApp* nfc = context; + + // Setup Widget + nfc_scene_emulate_uid_widget_config(nfc, false); + // Setup TextBox + TextBox* text_box = nfc->text_box; + text_box_set_font(text_box, TextBoxFontHex); + text_box_set_focus(text_box, TextBoxFocusEnd); + furi_string_reset(nfc->text_box_store); + + // Set Widget state and view + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneEmulateUid, NfcSceneEmulateUidStateWidget); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); + // Start worker + memset(&nfc->dev->dev_data.reader_data, 0, sizeof(NfcReaderRequestData)); + nfc_worker_start( + nfc->worker, + NfcWorkerStateUidEmulate, + &nfc->dev->dev_data, + nfc_emulate_uid_worker_callback, + nfc); + + nfc_blink_emulate_start(nfc); +} + +bool nfc_scene_emulate_uid_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + NfcReaderRequestData* reader_data = &nfc->dev->dev_data.reader_data; + uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneEmulateUid); + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventWorkerExit) { + // Add data button to widget if data is received for the first time + if(!furi_string_size(nfc->text_box_store)) { + nfc_scene_emulate_uid_widget_config(nfc, true); + } + // Update TextBox data + if(furi_string_size(nfc->text_box_store) < NFC_SCENE_EMULATE_UID_LOG_SIZE_MAX) { + furi_string_cat_printf(nfc->text_box_store, "R:"); + for(uint16_t i = 0; i < reader_data->size; i++) { + furi_string_cat_printf(nfc->text_box_store, " %02X", reader_data->data[i]); + } + furi_string_push_back(nfc->text_box_store, '\n'); + text_box_set_text(nfc->text_box, furi_string_get_cstr(nfc->text_box_store)); + } + memset(reader_data, 0, sizeof(NfcReaderRequestData)); + consumed = true; + } else if(event.event == GuiButtonTypeCenter && state == NfcSceneEmulateUidStateWidget) { + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneEmulateUid, NfcSceneEmulateUidStateTextBox); + consumed = true; + } else if(event.event == NfcCustomEventViewExit && state == NfcSceneEmulateUidStateTextBox) { + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneEmulateUid, NfcSceneEmulateUidStateWidget); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeBack) { + if(state == NfcSceneEmulateUidStateTextBox) { + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneEmulateUid, NfcSceneEmulateUidStateWidget); + consumed = true; + } + } + + return consumed; +} + +void nfc_scene_emulate_uid_on_exit(void* context) { + NfcApp* nfc = context; + + // Stop worker + nfc_worker_stop(nfc->worker); + + // Clear view + widget_reset(nfc->widget); + text_box_reset(nfc->text_box); + furi_string_reset(nfc->text_box_store); + + nfc_blink_stop(nfc); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_emv_menu.c b/applications/main/nfc_old/scenes/nfc_scene_emv_menu.c new file mode 100644 index 000000000000..88d3355a0b75 --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_emv_menu.c @@ -0,0 +1,46 @@ +#include "../nfc_app_i.h" + +enum SubmenuIndex { + SubmenuIndexInfo, +}; + +void nfc_scene_emv_menu_submenu_callback(void* context, uint32_t index) { + NfcApp* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, index); +} + +void nfc_scene_emv_menu_on_enter(void* context) { + NfcApp* nfc = context; + Submenu* submenu = nfc->submenu; + + submenu_add_item(submenu, "Info", SubmenuIndexInfo, nfc_scene_emv_menu_submenu_callback, nfc); + submenu_set_selected_item( + nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneEmvMenu)); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); +} + +bool nfc_scene_emv_menu_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexInfo) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); + consumed = true; + } + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneEmvMenu, event.event); + } else if(event.type == SceneManagerEventTypeBack) { + consumed = scene_manager_previous_scene(nfc->scene_manager); + } + + return consumed; +} + +void nfc_scene_emv_menu_on_exit(void* context) { + NfcApp* nfc = context; + + // Clear view + submenu_reset(nfc->submenu); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_emv_read_success.c b/applications/main/nfc_old/scenes/nfc_scene_emv_read_success.c new file mode 100644 index 000000000000..00057a2ee4ab --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_emv_read_success.c @@ -0,0 +1,113 @@ +#include "../nfc_app_i.h" +#include "../helpers/nfc_emv_parser.h" + +void nfc_scene_emv_read_success_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + NfcApp* nfc = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); + } +} + +void nfc_scene_emv_read_success_on_enter(void* context) { + NfcApp* nfc = context; + EmvData* emv_data = &nfc->dev->dev_data.emv_data; + + // Setup Custom Widget view + widget_add_button_element( + nfc->widget, GuiButtonTypeLeft, "Retry", nfc_scene_emv_read_success_widget_callback, nfc); + widget_add_button_element( + nfc->widget, GuiButtonTypeRight, "More", nfc_scene_emv_read_success_widget_callback, nfc); + + FuriString* temp_str; + if(emv_data->name[0] != '\0') { + temp_str = furi_string_alloc_printf("\e#%s\n", emv_data->name); + } else { + temp_str = furi_string_alloc_printf("\e#Unknown Bank Card\n"); + } + if(emv_data->number_len) { + for(uint8_t i = 0; i < emv_data->number_len; i += 2) { + furi_string_cat_printf( + temp_str, "%02X%02X ", emv_data->number[i], emv_data->number[i + 1]); + } + furi_string_trim(temp_str); + } else if(emv_data->aid_len) { + furi_string_cat_printf(temp_str, "Can't parse data from app\n"); + // Parse AID name + FuriString* aid_name; + aid_name = furi_string_alloc(); + if(nfc_emv_parser_get_aid_name( + nfc->dev->storage, emv_data->aid, emv_data->aid_len, aid_name)) { + furi_string_cat_printf(temp_str, "AID: %s", furi_string_get_cstr(aid_name)); + } else { + furi_string_cat_printf(temp_str, "AID: "); + for(uint8_t i = 0; i < emv_data->aid_len; i++) { + furi_string_cat_printf(temp_str, "%02X", emv_data->aid[i]); + } + } + furi_string_free(aid_name); + } + + // Add expiration date + if(emv_data->exp_mon) { + furi_string_cat_printf( + temp_str, "\nExp: %02X/%02X", emv_data->exp_mon, emv_data->exp_year); + } + // Parse currency code + if((emv_data->currency_code)) { + FuriString* currency_name; + currency_name = furi_string_alloc(); + if(nfc_emv_parser_get_currency_name( + nfc->dev->storage, emv_data->currency_code, currency_name)) { + furi_string_cat_printf(temp_str, "\nCur: %s ", furi_string_get_cstr(currency_name)); + } + furi_string_free(currency_name); + } + // Parse country code + if((emv_data->country_code)) { + FuriString* country_name; + country_name = furi_string_alloc(); + if(nfc_emv_parser_get_country_name( + nfc->dev->storage, emv_data->country_code, country_name)) { + furi_string_cat_printf(temp_str, "Reg: %s", furi_string_get_cstr(country_name)); + } + furi_string_free(country_name); + } + + notification_message_block(nfc->notifications, &sequence_set_green_255); + + widget_add_text_scroll_element(nfc->widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); + furi_string_free(temp_str); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); +} + +bool nfc_scene_emv_read_success_on_event(void* context, SceneManagerEvent event) { + NfcApp* 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, NfcSceneEmvMenu); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeBack) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); + consumed = true; + } + return consumed; +} + +void nfc_scene_emv_read_success_on_exit(void* context) { + NfcApp* nfc = context; + + notification_message_block(nfc->notifications, &sequence_reset_green); + + // Clear view + widget_reset(nfc->widget); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_exit_confirm.c b/applications/main/nfc_old/scenes/nfc_scene_exit_confirm.c new file mode 100644 index 000000000000..92933556d2ad --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_exit_confirm.c @@ -0,0 +1,52 @@ +#include "../nfc_app_i.h" + +void nfc_scene_exit_confirm_dialog_callback(DialogExResult result, void* context) { + NfcApp* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); +} + +void nfc_scene_exit_confirm_on_enter(void* context) { + NfcApp* nfc = context; + DialogEx* dialog_ex = nfc->dialog_ex; + + dialog_ex_set_left_button_text(dialog_ex, "Exit"); + dialog_ex_set_right_button_text(dialog_ex, "Stay"); + dialog_ex_set_header(dialog_ex, "Exit to NFC Menu?", 64, 11, AlignCenter, AlignTop); + dialog_ex_set_text( + dialog_ex, "All unsaved data\nwill be lost!", 64, 25, AlignCenter, AlignTop); + dialog_ex_set_context(dialog_ex, nfc); + dialog_ex_set_result_callback(dialog_ex, nfc_scene_exit_confirm_dialog_callback); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); +} + +bool nfc_scene_exit_confirm_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == DialogExResultRight) { + consumed = scene_manager_previous_scene(nfc->scene_manager); + } else if(event.event == DialogExResultLeft) { + if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneReadCardType)) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneReadCardType); + } else { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneStart); + } + } + } else if(event.type == SceneManagerEventTypeBack) { + consumed = true; + } + + return consumed; +} + +void nfc_scene_exit_confirm_on_exit(void* context) { + NfcApp* nfc = context; + + // Clean view + dialog_ex_reset(nfc->dialog_ex); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_extra_actions.c b/applications/main/nfc_old/scenes/nfc_scene_extra_actions.c new file mode 100644 index 000000000000..31106c76a4f3 --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_extra_actions.c @@ -0,0 +1,72 @@ +#include "../nfc_app_i.h" + +enum SubmenuIndex { + SubmenuIndexReadCardType, + SubmenuIndexMfClassicKeys, + SubmenuIndexMfUltralightUnlock, +}; + +void nfc_scene_extra_actions_submenu_callback(void* context, uint32_t index) { + NfcApp* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, index); +} + +void nfc_scene_extra_actions_on_enter(void* context) { + NfcApp* nfc = context; + Submenu* submenu = nfc->submenu; + + submenu_add_item( + submenu, + "Read Specific Card Type", + SubmenuIndexReadCardType, + nfc_scene_extra_actions_submenu_callback, + nfc); + submenu_add_item( + submenu, + "Mifare Classic Keys", + SubmenuIndexMfClassicKeys, + nfc_scene_extra_actions_submenu_callback, + nfc); + submenu_add_item( + submenu, + "Unlock NTAG/Ultralight", + SubmenuIndexMfUltralightUnlock, + nfc_scene_extra_actions_submenu_callback, + nfc); + submenu_set_selected_item( + submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneExtraActions)); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); +} + +bool nfc_scene_extra_actions_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexMfClassicKeys) { + if(mf_classic_dict_check_presence(MfClassicDictTypeSystem)) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicKeys); + } else { + scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound); + } + consumed = true; + } else if(event.event == SubmenuIndexMfUltralightUnlock) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockMenu); + consumed = true; + } else if(event.event == SubmenuIndexReadCardType) { + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneReadCardType, 0); + scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardType); + consumed = true; + } + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneExtraActions, event.event); + } + + return consumed; +} + +void nfc_scene_extra_actions_on_exit(void* context) { + NfcApp* nfc = context; + + submenu_reset(nfc->submenu); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_field.c b/applications/main/nfc_old/scenes/nfc_scene_field.c new file mode 100644 index 000000000000..893f4d03ff91 --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_field.c @@ -0,0 +1,33 @@ +#include "../nfc_app_i.h" + +void nfc_scene_field_on_enter(void* context) { + NfcApp* nfc = context; + + furi_hal_nfc_field_on(); + + Popup* popup = nfc->popup; + popup_set_header( + popup, + "Field is on\nDon't leave device\nin this mode for too long.", + 64, + 11, + AlignCenter, + AlignTop); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); + + notification_internal_message(nfc->notifications, &sequence_set_blue_255); +} + +bool nfc_scene_field_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + UNUSED(event); + return false; +} + +void nfc_scene_field_on_exit(void* context) { + NfcApp* nfc = context; + + furi_hal_nfc_field_off(); + notification_internal_message(nfc->notifications, &sequence_reset_blue); + popup_reset(nfc->popup); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_file_select.c b/applications/main/nfc_old/scenes/nfc_scene_file_select.c new file mode 100644 index 000000000000..61ac593e0c4e --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_file_select.c @@ -0,0 +1,28 @@ +#include "../nfc_app_i.h" +#include "nfc/nfc_device.h" + +void nfc_scene_file_select_on_enter(void* context) { + NfcApp* nfc = context; + // Process file_select return + nfc_device_set_loading_callback(nfc->dev, nfc_show_loading_popup, nfc); + if(!furi_string_size(nfc->dev->load_path)) { + furi_string_set_str(nfc->dev->load_path, NFC_APP_FOLDER); + } + if(nfc_file_select(nfc->dev)) { + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneSavedMenu, 0); + scene_manager_next_scene(nfc->scene_manager, NfcSceneSavedMenu); + } else { + scene_manager_search_and_switch_to_previous_scene(nfc->scene_manager, NfcSceneStart); + } + nfc_device_set_loading_callback(nfc->dev, NULL, nfc); +} + +bool nfc_scene_file_select_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + UNUSED(event); + return false; +} + +void nfc_scene_file_select_on_exit(void* context) { + UNUSED(context); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_generate_info.c b/applications/main/nfc_old/scenes/nfc_scene_generate_info.c new file mode 100644 index 000000000000..e877d771a6f0 --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_generate_info.c @@ -0,0 +1,60 @@ +#include "../nfc_app_i.h" +#include "lib/nfc/helpers/nfc_generators.h" + +void nfc_scene_generate_info_dialog_callback(DialogExResult result, void* context) { + NfcApp* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); +} + +void nfc_scene_generate_info_on_enter(void* context) { + NfcApp* nfc = context; + + // Setup dialog view + FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; + DialogEx* dialog_ex = nfc->dialog_ex; + dialog_ex_set_right_button_text(dialog_ex, "More"); + + // Create info text + FuriString* info_str = furi_string_alloc_printf( + "%s\n%s\nUID:", nfc->generator->name, nfc_get_dev_type(data->type)); + + // Append UID + for(int i = 0; i < data->uid_len; ++i) { + furi_string_cat_printf(info_str, " %02X", data->uid[i]); + } + nfc_text_store_set(nfc, furi_string_get_cstr(info_str)); + furi_string_free(info_str); + + dialog_ex_set_text(dialog_ex, nfc->text_store, 0, 0, AlignLeft, AlignTop); + dialog_ex_set_context(dialog_ex, nfc); + dialog_ex_set_result_callback(dialog_ex, nfc_scene_generate_info_dialog_callback); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); +} + +bool nfc_scene_generate_info_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == DialogExResultRight) { + // Switch either to NfcSceneMfClassicMenu or NfcSceneMfUltralightMenu + if(nfc->dev->dev_data.protocol == NfcDeviceProtocolMifareClassic) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicMenu); + } else if(nfc->dev->dev_data.protocol == NfcDeviceProtocolMifareUl) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightMenu); + } + consumed = true; + } + } + + return consumed; +} + +void nfc_scene_generate_info_on_exit(void* context) { + NfcApp* nfc = context; + + // Clean views + dialog_ex_reset(nfc->dialog_ex); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_data.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_data.c new file mode 100644 index 000000000000..83ba57f7cf7e --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_data.c @@ -0,0 +1,106 @@ +#include "../nfc_app_i.h" + +void nfc_scene_mf_classic_data_on_enter(void* context) { + NfcApp* nfc = context; + MfClassicType type = nfc->dev->dev_data.mf_classic_data.type; + MfClassicData* data = &nfc->dev->dev_data.mf_classic_data; + TextBox* text_box = nfc->text_box; + + text_box_set_font(text_box, TextBoxFontHex); + + int card_blocks = 0; + if(type == MfClassicType1k) { + card_blocks = MF_CLASSIC_1K_TOTAL_SECTORS_NUM * 4; + } else if(type == MfClassicType4k) { + // 16 sectors of 4 blocks each plus 8 sectors of 16 blocks each + card_blocks = MF_CLASSIC_1K_TOTAL_SECTORS_NUM * 4 + 8 * 16; + } else if(type == MfClassicTypeMini) { + card_blocks = MF_MINI_TOTAL_SECTORS_NUM * 4; + } + + int bytes_written = 0; + for(int block_num = 0; block_num < card_blocks; block_num++) { + bool is_sec_trailer = mf_classic_is_sector_trailer(block_num); + if(is_sec_trailer) { + uint8_t sector_num = mf_classic_get_sector_by_block(block_num); + MfClassicSectorTrailer* sec_tr = + mf_classic_get_sector_trailer_by_sector(data, sector_num); + // Key A + for(size_t i = 0; i < sizeof(sec_tr->key_a); i += 2) { + if((bytes_written % 8 == 0) && (bytes_written != 0)) { + furi_string_push_back(nfc->text_box_store, '\n'); + } + if(mf_classic_is_key_found(data, sector_num, MfClassicKeyA)) { + furi_string_cat_printf( + nfc->text_box_store, "%02X%02X ", sec_tr->key_a[i], sec_tr->key_a[i + 1]); + } else { + furi_string_cat_printf(nfc->text_box_store, "???? "); + } + bytes_written += 2; + } + // Access bytes + for(size_t i = 0; i < MF_CLASSIC_ACCESS_BYTES_SIZE; i += 2) { + if((bytes_written % 8 == 0) && (bytes_written != 0)) { + furi_string_push_back(nfc->text_box_store, '\n'); + } + if(mf_classic_is_block_read(data, block_num)) { + furi_string_cat_printf( + nfc->text_box_store, + "%02X%02X ", + sec_tr->access_bits[i], + sec_tr->access_bits[i + 1]); + } else { + furi_string_cat_printf(nfc->text_box_store, "???? "); + } + bytes_written += 2; + } + // Key B + for(size_t i = 0; i < sizeof(sec_tr->key_b); i += 2) { + if((bytes_written % 8 == 0) && (bytes_written != 0)) { + furi_string_push_back(nfc->text_box_store, '\n'); + } + if(mf_classic_is_key_found(data, sector_num, MfClassicKeyB)) { + furi_string_cat_printf( + nfc->text_box_store, "%02X%02X ", sec_tr->key_b[i], sec_tr->key_b[i + 1]); + } else { + furi_string_cat_printf(nfc->text_box_store, "???? "); + } + bytes_written += 2; + } + } else { + // Write data block + for(size_t i = 0; i < MF_CLASSIC_BLOCK_SIZE; i += 2) { + if((bytes_written % 8 == 0) && (bytes_written != 0)) { + furi_string_push_back(nfc->text_box_store, '\n'); + } + if(mf_classic_is_block_read(data, block_num)) { + furi_string_cat_printf( + nfc->text_box_store, + "%02X%02X ", + data->block[block_num].value[i], + data->block[block_num].value[i + 1]); + } else { + furi_string_cat_printf(nfc->text_box_store, "???? "); + } + bytes_written += 2; + } + } + } + text_box_set_text(text_box, furi_string_get_cstr(nfc->text_box_store)); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); +} + +bool nfc_scene_mf_classic_data_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + UNUSED(event); + return false; +} + +void nfc_scene_mf_classic_data_on_exit(void* context) { + NfcApp* nfc = context; + + // Clean view + text_box_reset(nfc->text_box); + furi_string_reset(nfc->text_box_store); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_dict_attack.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_dict_attack.c new file mode 100644 index 000000000000..77d559367c1e --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_dict_attack.c @@ -0,0 +1,186 @@ +#include "../nfc_app_i.h" +#include + +#define TAG "NfcMfClassicDictAttack" + +typedef enum { + DictAttackStateIdle, + DictAttackStateUserDictInProgress, + DictAttackStateFlipperDictInProgress, +} DictAttackState; + +bool nfc_dict_attack_worker_callback(NfcWorkerEvent event, void* context) { + furi_assert(context); + NfcApp* nfc = context; + view_dispatcher_send_custom_event(nfc->view_dispatcher, event); + return true; +} + +void nfc_dict_attack_dict_attack_result_callback(void* context) { + furi_assert(context); + NfcApp* nfc = context; + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventDictAttackSkip); +} + +static void nfc_scene_mf_classic_dict_attack_update_view(NfcApp* nfc) { + MfClassicData* data = &nfc->dev->dev_data.mf_classic_data; + uint8_t sectors_read = 0; + uint8_t keys_found = 0; + + // Calculate found keys and read sectors + mf_classic_get_read_sectors_and_keys(data, §ors_read, &keys_found); + dict_attack_set_keys_found(nfc->dict_attack, keys_found); + dict_attack_set_sector_read(nfc->dict_attack, sectors_read); +} + +static void nfc_scene_mf_classic_dict_attack_prepare_view(NfcApp* nfc, DictAttackState state) { + MfClassicData* data = &nfc->dev->dev_data.mf_classic_data; + NfcMfClassicDictAttackData* dict_attack_data = &nfc->dev->dev_data.mf_classic_dict_attack_data; + NfcWorkerState worker_state = NfcWorkerStateReady; + MfClassicDict* dict = NULL; + + // Identify scene state + if(state == DictAttackStateIdle) { + if(mf_classic_dict_check_presence(MfClassicDictTypeUser)) { + state = DictAttackStateUserDictInProgress; + } else { + state = DictAttackStateFlipperDictInProgress; + } + } else if(state == DictAttackStateUserDictInProgress) { + state = DictAttackStateFlipperDictInProgress; + } + + // Setup view + if(state == DictAttackStateUserDictInProgress) { + worker_state = NfcWorkerStateMfClassicDictAttack; + dict_attack_set_header(nfc->dict_attack, "MF Classic User Dictionary"); + dict = mf_classic_dict_alloc(MfClassicDictTypeUser); + + // If failed to load user dictionary - try the system dictionary + if(!dict) { + FURI_LOG_E(TAG, "User dictionary not found"); + state = DictAttackStateFlipperDictInProgress; + } + } + if(state == DictAttackStateFlipperDictInProgress) { + worker_state = NfcWorkerStateMfClassicDictAttack; + dict_attack_set_header(nfc->dict_attack, "MF Classic System Dictionary"); + dict = mf_classic_dict_alloc(MfClassicDictTypeSystem); + if(!dict) { + FURI_LOG_E(TAG, "Flipper dictionary not found"); + // Pass through to let the worker handle the failure + } + } + // Free previous dictionary + if(dict_attack_data->dict) { + mf_classic_dict_free(dict_attack_data->dict); + } + dict_attack_data->dict = dict; + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfClassicDictAttack, state); + dict_attack_set_callback(nfc->dict_attack, nfc_dict_attack_dict_attack_result_callback, nfc); + dict_attack_set_current_sector(nfc->dict_attack, 0); + dict_attack_set_card_detected(nfc->dict_attack, data->type); + dict_attack_set_total_dict_keys( + nfc->dict_attack, dict ? mf_classic_dict_get_total_keys(dict) : 0); + nfc_scene_mf_classic_dict_attack_update_view(nfc); + nfc_worker_start( + nfc->worker, worker_state, &nfc->dev->dev_data, nfc_dict_attack_worker_callback, nfc); +} + +void nfc_scene_mf_classic_dict_attack_on_enter(void* context) { + NfcApp* nfc = context; + nfc_scene_mf_classic_dict_attack_prepare_view(nfc, DictAttackStateIdle); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDictAttack); + nfc_blink_read_start(nfc); + notification_message(nfc->notifications, &sequence_display_backlight_enforce_on); +} + +bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + MfClassicData* data = &nfc->dev->dev_data.mf_classic_data; + bool consumed = false; + + uint32_t state = + scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicDictAttack); + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcWorkerEventSuccess) { + if(state == DictAttackStateUserDictInProgress) { + nfc_worker_stop(nfc->worker); + nfc_scene_mf_classic_dict_attack_prepare_view(nfc, state); + consumed = true; + } else { + notification_message(nfc->notifications, &sequence_success); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSuccess); + DOLPHIN_DEED(DolphinDeedNfcReadSuccess); + consumed = true; + } + } else if(event.event == NfcWorkerEventAborted) { + if(state == DictAttackStateUserDictInProgress && + dict_attack_get_card_state(nfc->dict_attack)) { + nfc_scene_mf_classic_dict_attack_prepare_view(nfc, state); + consumed = true; + } else { + notification_message(nfc->notifications, &sequence_success); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSuccess); + // Counting failed attempts too + DOLPHIN_DEED(DolphinDeedNfcReadSuccess); + consumed = true; + } + } else if(event.event == NfcWorkerEventCardDetected) { + dict_attack_set_card_detected(nfc->dict_attack, data->type); + consumed = true; + } else if(event.event == NfcWorkerEventNoCardDetected) { + dict_attack_set_card_removed(nfc->dict_attack); + consumed = true; + } else if(event.event == NfcWorkerEventFoundKeyA) { + dict_attack_inc_keys_found(nfc->dict_attack); + consumed = true; + } else if(event.event == NfcWorkerEventFoundKeyB) { + dict_attack_inc_keys_found(nfc->dict_attack); + consumed = true; + } else if(event.event == NfcWorkerEventNewSector) { + nfc_scene_mf_classic_dict_attack_update_view(nfc); + dict_attack_inc_current_sector(nfc->dict_attack); + consumed = true; + } else if(event.event == NfcWorkerEventNewDictKeyBatch) { + nfc_scene_mf_classic_dict_attack_update_view(nfc); + dict_attack_inc_current_dict_key(nfc->dict_attack, NFC_DICT_KEY_BATCH_SIZE); + consumed = true; + } else if(event.event == NfcCustomEventDictAttackSkip) { + if(state == DictAttackStateUserDictInProgress) { + nfc_worker_stop(nfc->worker); + consumed = true; + } else if(state == DictAttackStateFlipperDictInProgress) { + nfc_worker_stop(nfc->worker); + consumed = true; + } + } else if(event.event == NfcWorkerEventKeyAttackStart) { + dict_attack_set_key_attack( + nfc->dict_attack, + true, + nfc->dev->dev_data.mf_classic_dict_attack_data.current_sector); + } else if(event.event == NfcWorkerEventKeyAttackStop) { + dict_attack_set_key_attack(nfc->dict_attack, false, 0); + } else if(event.event == NfcWorkerEventKeyAttackNextSector) { + dict_attack_inc_key_attack_current_sector(nfc->dict_attack); + } + } else if(event.type == SceneManagerEventTypeBack) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); + consumed = true; + } + return consumed; +} + +void nfc_scene_mf_classic_dict_attack_on_exit(void* context) { + NfcApp* nfc = context; + NfcMfClassicDictAttackData* dict_attack_data = &nfc->dev->dev_data.mf_classic_dict_attack_data; + // Stop worker + nfc_worker_stop(nfc->worker); + if(dict_attack_data->dict) { + mf_classic_dict_free(dict_attack_data->dict); + dict_attack_data->dict = NULL; + } + dict_attack_reset(nfc->dict_attack); + nfc_blink_stop(nfc); + notification_message(nfc->notifications, &sequence_display_backlight_enforce_auto); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_emulate.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_emulate.c new file mode 100644 index 000000000000..6cf7689052c5 --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_emulate.c @@ -0,0 +1,69 @@ +#include "../nfc_app_i.h" + +#define NFC_MF_CLASSIC_DATA_NOT_CHANGED (0UL) +#define NFC_MF_CLASSIC_DATA_CHANGED (1UL) + +bool nfc_mf_classic_emulate_worker_callback(NfcWorkerEvent event, void* context) { + UNUSED(event); + NfcApp* nfc = context; + + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneMfClassicEmulate, NFC_MF_CLASSIC_DATA_CHANGED); + return true; +} + +void nfc_scene_mf_classic_emulate_on_enter(void* context) { + NfcApp* nfc = context; + + // Setup view + Popup* popup = nfc->popup; + popup_set_header(popup, "Emulating", 67, 13, AlignLeft, AlignTop); + if(strcmp(nfc->dev->dev_name, "") != 0) { + nfc_text_store_set(nfc, "%s", nfc->dev->dev_name); + } else { + nfc_text_store_set(nfc, "MIFARE\nClassic"); + } + popup_set_icon(popup, 0, 3, &I_NFC_dolphin_emulation_47x61); + popup_set_text(popup, nfc->text_store, 90, 28, AlignCenter, AlignTop); + + // Setup and start worker + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); + nfc_worker_start( + nfc->worker, + NfcWorkerStateMfClassicEmulate, + &nfc->dev->dev_data, + nfc_mf_classic_emulate_worker_callback, + nfc); + nfc_blink_emulate_start(nfc); +} + +bool nfc_scene_mf_classic_emulate_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeBack) { + // Stop worker + nfc_worker_stop(nfc->worker); + // Check if data changed and save in shadow file + if(scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicEmulate) == + NFC_MF_CLASSIC_DATA_CHANGED) { + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneMfClassicEmulate, NFC_MF_CLASSIC_DATA_NOT_CHANGED); + // Save shadow file + if(furi_string_size(nfc->dev->load_path)) { + nfc_device_save_shadow(nfc->dev, furi_string_get_cstr(nfc->dev->load_path)); + } + } + consumed = false; + } + return consumed; +} + +void nfc_scene_mf_classic_emulate_on_exit(void* context) { + NfcApp* nfc = context; + + // Clear view + popup_reset(nfc->popup); + + nfc_blink_stop(nfc); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys.c new file mode 100644 index 000000000000..b7cc2f283450 --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys.c @@ -0,0 +1,71 @@ +#include "../nfc_app_i.h" + +void nfc_scene_mf_classic_keys_widget_callback(GuiButtonType result, InputType type, void* context) { + NfcApp* nfc = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); + } +} + +void nfc_scene_mf_classic_keys_on_enter(void* context) { + NfcApp* nfc = context; + + // Load flipper dict keys total + uint32_t flipper_dict_keys_total = 0; + MfClassicDict* dict = mf_classic_dict_alloc(MfClassicDictTypeSystem); + if(dict) { + flipper_dict_keys_total = mf_classic_dict_get_total_keys(dict); + mf_classic_dict_free(dict); + } + // Load user dict keys total + uint32_t user_dict_keys_total = 0; + dict = mf_classic_dict_alloc(MfClassicDictTypeUser); + if(dict) { + user_dict_keys_total = mf_classic_dict_get_total_keys(dict); + mf_classic_dict_free(dict); + } + + widget_add_string_element( + nfc->widget, 0, 0, AlignLeft, AlignTop, FontPrimary, "MIFARE Classic Keys"); + char temp_str[32]; + snprintf(temp_str, sizeof(temp_str), "System dict: %lu", flipper_dict_keys_total); + widget_add_string_element(nfc->widget, 0, 20, AlignLeft, AlignTop, FontSecondary, temp_str); + snprintf(temp_str, sizeof(temp_str), "User dict: %lu", user_dict_keys_total); + widget_add_string_element(nfc->widget, 0, 32, AlignLeft, AlignTop, FontSecondary, temp_str); + widget_add_button_element( + nfc->widget, GuiButtonTypeCenter, "Add", nfc_scene_mf_classic_keys_widget_callback, nfc); + widget_add_icon_element(nfc->widget, 87, 13, &I_Keychain_39x36); + if(user_dict_keys_total > 0) { + widget_add_button_element( + nfc->widget, + GuiButtonTypeRight, + "List", + nfc_scene_mf_classic_keys_widget_callback, + nfc); + } + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); +} + +bool nfc_scene_mf_classic_keys_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeCenter) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicKeysAdd); + consumed = true; + } else if(event.event == GuiButtonTypeRight) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicKeysList); + consumed = true; + } + } + + return consumed; +} + +void nfc_scene_mf_classic_keys_on_exit(void* context) { + NfcApp* nfc = context; + + widget_reset(nfc->widget); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_add.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_add.c new file mode 100644 index 000000000000..d2b89829bf94 --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_add.c @@ -0,0 +1,60 @@ +#include "../nfc_app_i.h" +#include + +void nfc_scene_mf_classic_keys_add_byte_input_callback(void* context) { + NfcApp* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); +} + +void nfc_scene_mf_classic_keys_add_on_enter(void* context) { + NfcApp* nfc = context; + + // Setup view + ByteInput* byte_input = nfc->byte_input; + byte_input_set_header_text(byte_input, "Enter the key in hex"); + byte_input_set_result_callback( + byte_input, + nfc_scene_mf_classic_keys_add_byte_input_callback, + NULL, + nfc, + nfc->byte_input_store, + 6); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewByteInput); +} + +bool nfc_scene_mf_classic_keys_add_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventByteInputDone) { + // Add key to dict + MfClassicDict* dict = mf_classic_dict_alloc(MfClassicDictTypeUser); + if(dict) { + if(mf_classic_dict_is_key_present(dict, nfc->byte_input_store)) { + scene_manager_next_scene( + nfc->scene_manager, NfcSceneMfClassicKeysWarnDuplicate); + } else if(mf_classic_dict_add_key(dict, nfc->byte_input_store)) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess); + DOLPHIN_DEED(DolphinDeedNfcMfcAdd); + } else { + scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound); + } + } else { + scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound); + } + mf_classic_dict_free(dict); + consumed = true; + } + } + return consumed; +} + +void nfc_scene_mf_classic_keys_add_on_exit(void* context) { + NfcApp* nfc = context; + + // Clear view + byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0); + byte_input_set_header_text(nfc->byte_input, ""); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_delete.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_delete.c new file mode 100644 index 000000000000..9f34c8eee0de --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_delete.c @@ -0,0 +1,83 @@ +#include "../nfc_app_i.h" + +void nfc_scene_mf_classic_keys_delete_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + NfcApp* nfc = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); + } +} + +void nfc_scene_mf_classic_keys_delete_on_enter(void* context) { + NfcApp* nfc = context; + MfClassicDict* dict = mf_classic_dict_alloc(MfClassicDictTypeUser); + uint32_t key_index = + scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicKeysDelete); + // Setup Custom Widget view + FuriString* key_str; + key_str = furi_string_alloc(); + + widget_add_string_element( + nfc->widget, 64, 0, AlignCenter, AlignTop, FontPrimary, "Delete this key?"); + widget_add_button_element( + nfc->widget, + GuiButtonTypeLeft, + "Cancel", + nfc_scene_mf_classic_keys_delete_widget_callback, + nfc); + widget_add_button_element( + nfc->widget, + GuiButtonTypeRight, + "Delete", + nfc_scene_mf_classic_keys_delete_widget_callback, + nfc); + + mf_classic_dict_get_key_at_index_str(dict, key_str, key_index); + widget_add_string_element( + nfc->widget, + 64, + 32, + AlignCenter, + AlignCenter, + FontSecondary, + furi_string_get_cstr(key_str)); + + furi_string_free(key_str); + mf_classic_dict_free(dict); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); +} + +bool nfc_scene_mf_classic_keys_delete_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + uint32_t key_index = + scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicKeysDelete); + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeLeft) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneMfClassicKeys); + } else if(event.event == GuiButtonTypeRight) { + MfClassicDict* dict = mf_classic_dict_alloc(MfClassicDictTypeUser); + if(mf_classic_dict_delete_index(dict, key_index)) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneDeleteSuccess); + } else { + scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneMfClassicKeys); + } + mf_classic_dict_free(dict); + consumed = true; + } + } + + return consumed; +} + +void nfc_scene_mf_classic_keys_delete_on_exit(void* context) { + NfcApp* nfc = context; + + widget_reset(nfc->widget); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_list.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_list.c new file mode 100644 index 000000000000..6a7be48a0bb3 --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_list.c @@ -0,0 +1,100 @@ +#include "../nfc_app_i.h" + +#define NFC_SCENE_MF_CLASSIC_KEYS_LIST_MAX (100) + +void nfc_scene_mf_classic_keys_list_submenu_callback(void* context, uint32_t index) { + furi_assert(context); + + NfcApp* nfc = context; + view_dispatcher_send_custom_event(nfc->view_dispatcher, index); +} + +void nfc_scene_mf_classic_keys_list_popup_callback(void* context) { + furi_assert(context); + + NfcApp* nfc = context; + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); +} + +void nfc_scene_mf_classic_keys_list_prepare(NfcApp* nfc, MfClassicDict* dict) { + Submenu* submenu = nfc->submenu; + uint32_t index = 0; + FuriString* temp_key; + temp_key = furi_string_alloc(); + + submenu_set_header(submenu, "Select key to delete:"); + while(mf_classic_dict_get_next_key_str(dict, temp_key)) { + char* current_key = (char*)malloc(sizeof(char) * 13); + strncpy(current_key, furi_string_get_cstr(temp_key), 12); + MfClassicUserKeys_push_back(nfc->mfc_key_strs, current_key); + FURI_LOG_D("ListKeys", "Key %lu: %s", index, current_key); + submenu_add_item( + submenu, current_key, index++, nfc_scene_mf_classic_keys_list_submenu_callback, nfc); + } + furi_string_free(temp_key); +} + +void nfc_scene_mf_classic_keys_list_on_enter(void* context) { + NfcApp* nfc = context; + MfClassicDict* dict = mf_classic_dict_alloc(MfClassicDictTypeUser); + MfClassicUserKeys_init(nfc->mfc_key_strs); + if(dict) { + uint32_t total_user_keys = mf_classic_dict_get_total_keys(dict); + if(total_user_keys < NFC_SCENE_MF_CLASSIC_KEYS_LIST_MAX) { + nfc_scene_mf_classic_keys_list_prepare(nfc, dict); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); + } else { + popup_set_header(nfc->popup, "Too many keys!", 64, 0, AlignCenter, AlignTop); + popup_set_text( + nfc->popup, + "Edit user dictionary\nwith file browser", + 64, + 12, + AlignCenter, + AlignTop); + popup_set_callback(nfc->popup, nfc_scene_mf_classic_keys_list_popup_callback); + popup_set_context(nfc->popup, nfc); + popup_set_timeout(nfc->popup, 3000); + popup_enable_timeout(nfc->popup); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); + } + mf_classic_dict_free(dict); + } else { + popup_set_header( + nfc->popup, "Failed to load dictionary", 64, 32, AlignCenter, AlignCenter); + popup_set_callback(nfc->popup, nfc_scene_mf_classic_keys_list_popup_callback); + popup_set_context(nfc->popup, nfc); + popup_set_timeout(nfc->popup, 3000); + popup_enable_timeout(nfc->popup); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); + } +} + +bool nfc_scene_mf_classic_keys_list_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventViewExit) { + consumed = scene_manager_previous_scene(nfc->scene_manager); + } else { + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneMfClassicKeysDelete, event.event); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicKeysDelete); + consumed = true; + } + } + return consumed; +} + +void nfc_scene_mf_classic_keys_list_on_exit(void* context) { + NfcApp* nfc = context; + + MfClassicUserKeys_it_t it; + for(MfClassicUserKeys_it(it, nfc->mfc_key_strs); !MfClassicUserKeys_end_p(it); + MfClassicUserKeys_next(it)) { + free(*MfClassicUserKeys_ref(it)); + } + MfClassicUserKeys_clear(nfc->mfc_key_strs); + submenu_reset(nfc->submenu); + popup_reset(nfc->popup); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_warn_duplicate.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_warn_duplicate.c new file mode 100644 index 000000000000..5cc1ba635399 --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_warn_duplicate.c @@ -0,0 +1,47 @@ +#include "../nfc_app_i.h" + +void nfc_scene_mf_classic_keys_warn_duplicate_popup_callback(void* context) { + NfcApp* nfc = context; + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); +} + +void nfc_scene_mf_classic_keys_warn_duplicate_on_enter(void* context) { + NfcApp* nfc = context; + + // Setup view + Popup* popup = nfc->popup; + popup_set_icon(popup, 72, 16, &I_DolphinCommon_56x48); + popup_set_header(popup, "Key already exists!", 64, 3, AlignCenter, AlignTop); + popup_set_text( + popup, + "Please enter a\n" + "different key.", + 4, + 24, + AlignLeft, + AlignTop); + popup_set_timeout(popup, 5000); + popup_set_context(popup, nfc); + popup_set_callback(popup, nfc_scene_mf_classic_keys_warn_duplicate_popup_callback); + popup_enable_timeout(popup); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); +} + +bool nfc_scene_mf_classic_keys_warn_duplicate_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventViewExit) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneMfClassicKeysAdd); + } + } + return consumed; +} + +void nfc_scene_mf_classic_keys_warn_duplicate_on_exit(void* context) { + NfcApp* nfc = context; + + popup_reset(nfc->popup); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_menu.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_menu.c new file mode 100644 index 000000000000..207bb17edfbb --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_menu.c @@ -0,0 +1,82 @@ +#include "../nfc_app_i.h" +#include + +enum SubmenuIndex { + SubmenuIndexSave, + SubmenuIndexEmulate, + SubmenuIndexDetectReader, + SubmenuIndexInfo, +}; + +void nfc_scene_mf_classic_menu_submenu_callback(void* context, uint32_t index) { + NfcApp* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, index); +} + +void nfc_scene_mf_classic_menu_on_enter(void* context) { + NfcApp* nfc = context; + Submenu* submenu = nfc->submenu; + + submenu_add_item( + submenu, "Save", SubmenuIndexSave, nfc_scene_mf_classic_menu_submenu_callback, nfc); + submenu_add_item( + submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_mf_classic_menu_submenu_callback, nfc); + if(!mf_classic_is_card_read(&nfc->dev->dev_data.mf_classic_data)) { + submenu_add_item( + submenu, + "Detect Reader", + SubmenuIndexDetectReader, + nfc_scene_mf_classic_menu_submenu_callback, + nfc); + } + submenu_add_item( + submenu, "Info", SubmenuIndexInfo, nfc_scene_mf_classic_menu_submenu_callback, nfc); + + submenu_set_selected_item( + nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicMenu)); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); +} + +bool nfc_scene_mf_classic_menu_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfClassicMenu, event.event); + if(event.event == SubmenuIndexSave) { + nfc->dev->format = NfcDeviceSaveFormatMifareClassic; + // 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, NfcSceneMfClassicEmulate); + if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) { + DOLPHIN_DEED(DolphinDeedNfcAddEmulate); + } else { + DOLPHIN_DEED(DolphinDeedNfcEmulate); + } + consumed = true; + } else if(event.event == SubmenuIndexDetectReader) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneDetectReader); + DOLPHIN_DEED(DolphinDeedNfcDetectReader); + consumed = true; + } else if(event.event == SubmenuIndexInfo) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeBack) { + consumed = scene_manager_previous_scene(nfc->scene_manager); + } + + return consumed; +} + +void nfc_scene_mf_classic_menu_on_exit(void* context) { + NfcApp* nfc = context; + + // Clear view + submenu_reset(nfc->submenu); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_read_success.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_read_success.c new file mode 100644 index 000000000000..f0ab9397f5f7 --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_read_success.c @@ -0,0 +1,82 @@ +#include "../nfc_app_i.h" + +void nfc_scene_mf_classic_read_success_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + furi_assert(context); + NfcApp* nfc = context; + + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); + } +} + +void nfc_scene_mf_classic_read_success_on_enter(void* context) { + NfcApp* nfc = context; + NfcDeviceData* dev_data = &nfc->dev->dev_data; + MfClassicData* mf_data = &dev_data->mf_classic_data; + + // Setup view + Widget* widget = nfc->widget; + widget_add_button_element( + widget, GuiButtonTypeLeft, "Retry", nfc_scene_mf_classic_read_success_widget_callback, nfc); + widget_add_button_element( + widget, GuiButtonTypeRight, "More", nfc_scene_mf_classic_read_success_widget_callback, nfc); + + FuriString* temp_str = NULL; + if(furi_string_size(nfc->dev->dev_data.parsed_data)) { + temp_str = furi_string_alloc_set(nfc->dev->dev_data.parsed_data); + } else { + temp_str = furi_string_alloc_printf("\e#%s\n", nfc_mf_classic_type(mf_data->type)); + furi_string_cat_printf(temp_str, "UID:"); + for(size_t i = 0; i < dev_data->nfc_data.uid_len; i++) { + furi_string_cat_printf(temp_str, " %02X", dev_data->nfc_data.uid[i]); + } + uint8_t sectors_total = mf_classic_get_total_sectors_num(mf_data->type); + uint8_t keys_total = sectors_total * 2; + uint8_t keys_found = 0; + uint8_t sectors_read = 0; + mf_classic_get_read_sectors_and_keys(mf_data, §ors_read, &keys_found); + furi_string_cat_printf(temp_str, "\nKeys Found: %d/%d", keys_found, keys_total); + furi_string_cat_printf(temp_str, "\nSectors Read: %d/%d", sectors_read, sectors_total); + } + + 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_mf_classic_read_success_on_event(void* context, SceneManagerEvent event) { + NfcApp* 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) { + // Clear device name + nfc_device_set_name(nfc->dev, ""); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicMenu); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeBack) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); + consumed = true; + } + + return consumed; +} + +void nfc_scene_mf_classic_read_success_on_exit(void* context) { + NfcApp* nfc = context; + + notification_message_block(nfc->notifications, &sequence_reset_green); + + // Clear view + widget_reset(nfc->widget); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_update.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_update.c new file mode 100644 index 000000000000..3819e799bb4c --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_update.c @@ -0,0 +1,98 @@ +#include "../nfc_app_i.h" +#include + +enum { + NfcSceneMfClassicUpdateStateCardSearch, + NfcSceneMfClassicUpdateStateCardFound, +}; + +bool nfc_mf_classic_update_worker_callback(NfcWorkerEvent event, void* context) { + furi_assert(context); + + NfcApp* nfc = context; + view_dispatcher_send_custom_event(nfc->view_dispatcher, event); + + return true; +} + +static void nfc_scene_mf_classic_update_setup_view(NfcApp* nfc) { + Popup* popup = nfc->popup; + popup_reset(popup); + uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicUpdate); + + if(state == NfcSceneMfClassicUpdateStateCardSearch) { + popup_set_text( + nfc->popup, "Apply the initial\ncard only", 128, 32, AlignRight, AlignCenter); + popup_set_icon(nfc->popup, 0, 8, &I_NFC_manual_60x50); + } else { + popup_set_header(popup, "Updating\nDon't move...", 52, 32, AlignLeft, AlignCenter); + popup_set_icon(popup, 12, 23, &A_Loading_24); + } + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); +} + +void nfc_scene_mf_classic_update_on_enter(void* context) { + NfcApp* nfc = context; + DOLPHIN_DEED(DolphinDeedNfcEmulate); + + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneMfClassicUpdate, NfcSceneMfClassicUpdateStateCardSearch); + nfc_scene_mf_classic_update_setup_view(nfc); + + // Setup and start worker + nfc_worker_start( + nfc->worker, + NfcWorkerStateMfClassicUpdate, + &nfc->dev->dev_data, + nfc_mf_classic_update_worker_callback, + nfc); + nfc_blink_emulate_start(nfc); +} + +bool nfc_scene_mf_classic_update_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcWorkerEventSuccess) { + nfc_worker_stop(nfc->worker); + if(nfc_device_save_shadow(nfc->dev, furi_string_get_cstr(nfc->dev->load_path))) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicUpdateSuccess); + } else { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicWrongCard); + } + consumed = true; + } else if(event.event == NfcWorkerEventWrongCard) { + nfc_worker_stop(nfc->worker); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicWrongCard); + consumed = true; + } else if(event.event == NfcWorkerEventCardDetected) { + scene_manager_set_scene_state( + nfc->scene_manager, + NfcSceneMfClassicUpdate, + NfcSceneMfClassicUpdateStateCardFound); + nfc_scene_mf_classic_update_setup_view(nfc); + consumed = true; + } else if(event.event == NfcWorkerEventNoCardDetected) { + scene_manager_set_scene_state( + nfc->scene_manager, + NfcSceneMfClassicUpdate, + NfcSceneMfClassicUpdateStateCardSearch); + nfc_scene_mf_classic_update_setup_view(nfc); + consumed = true; + } + } + return consumed; +} + +void nfc_scene_mf_classic_update_on_exit(void* context) { + NfcApp* nfc = context; + nfc_worker_stop(nfc->worker); + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneMfClassicUpdate, NfcSceneMfClassicUpdateStateCardSearch); + // Clear view + popup_reset(nfc->popup); + + nfc_blink_stop(nfc); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_update_success.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_update_success.c new file mode 100644 index 000000000000..f52114b161d9 --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_update_success.c @@ -0,0 +1,44 @@ +#include "../nfc_app_i.h" +#include + +void nfc_scene_mf_classic_update_success_popup_callback(void* context) { + NfcApp* nfc = context; + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); +} + +void nfc_scene_mf_classic_update_success_on_enter(void* context) { + NfcApp* nfc = context; + DOLPHIN_DEED(DolphinDeedNfcSave); + + notification_message(nfc->notifications, &sequence_success); + + Popup* popup = nfc->popup; + popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); + popup_set_header(popup, "Updated!", 11, 20, AlignLeft, AlignBottom); + popup_set_timeout(popup, 1500); + popup_set_context(popup, nfc); + popup_set_callback(popup, nfc_scene_mf_classic_update_success_popup_callback); + popup_enable_timeout(popup); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); +} + +bool nfc_scene_mf_classic_update_success_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventViewExit) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneFileSelect); + } + } + return consumed; +} + +void nfc_scene_mf_classic_update_success_on_exit(void* context) { + NfcApp* nfc = context; + + // Clear view + popup_reset(nfc->popup); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_write.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_write.c new file mode 100644 index 000000000000..d33fbc4106a9 --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_write.c @@ -0,0 +1,92 @@ +#include "../nfc_app_i.h" +#include + +enum { + NfcSceneMfClassicWriteStateCardSearch, + NfcSceneMfClassicWriteStateCardFound, +}; + +bool nfc_mf_classic_write_worker_callback(NfcWorkerEvent event, void* context) { + furi_assert(context); + + NfcApp* nfc = context; + view_dispatcher_send_custom_event(nfc->view_dispatcher, event); + + return true; +} + +static void nfc_scene_mf_classic_write_setup_view(NfcApp* nfc) { + Popup* popup = nfc->popup; + popup_reset(popup); + uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicWrite); + + if(state == NfcSceneMfClassicWriteStateCardSearch) { + popup_set_text( + nfc->popup, "Apply the initial\ncard only", 128, 32, AlignRight, AlignCenter); + popup_set_icon(nfc->popup, 0, 8, &I_NFC_manual_60x50); + } else { + popup_set_header(popup, "Writing\nDon't move...", 52, 32, AlignLeft, AlignCenter); + popup_set_icon(popup, 12, 23, &A_Loading_24); + } + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); +} + +void nfc_scene_mf_classic_write_on_enter(void* context) { + NfcApp* nfc = context; + DOLPHIN_DEED(DolphinDeedNfcEmulate); + + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneMfClassicWrite, NfcSceneMfClassicWriteStateCardSearch); + nfc_scene_mf_classic_write_setup_view(nfc); + + // Setup and start worker + nfc_worker_start( + nfc->worker, + NfcWorkerStateMfClassicWrite, + &nfc->dev->dev_data, + nfc_mf_classic_write_worker_callback, + nfc); + nfc_blink_emulate_start(nfc); +} + +bool nfc_scene_mf_classic_write_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcWorkerEventSuccess) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicWriteSuccess); + consumed = true; + } else if(event.event == NfcWorkerEventFail) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicWriteFail); + consumed = true; + } else if(event.event == NfcWorkerEventWrongCard) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicWrongCard); + consumed = true; + } else if(event.event == NfcWorkerEventCardDetected) { + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneMfClassicWrite, NfcSceneMfClassicWriteStateCardFound); + nfc_scene_mf_classic_write_setup_view(nfc); + consumed = true; + } else if(event.event == NfcWorkerEventNoCardDetected) { + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneMfClassicWrite, NfcSceneMfClassicWriteStateCardSearch); + nfc_scene_mf_classic_write_setup_view(nfc); + consumed = true; + } + } + return consumed; +} + +void nfc_scene_mf_classic_write_on_exit(void* context) { + NfcApp* nfc = context; + + nfc_worker_stop(nfc->worker); + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneMfClassicWrite, NfcSceneMfClassicWriteStateCardSearch); + // Clear view + popup_reset(nfc->popup); + + nfc_blink_stop(nfc); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_write_fail.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_write_fail.c new file mode 100644 index 000000000000..695a3c4a7402 --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_write_fail.c @@ -0,0 +1,58 @@ +#include "../nfc_app_i.h" + +void nfc_scene_mf_classic_write_fail_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + NfcApp* nfc = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); + } +} + +void nfc_scene_mf_classic_write_fail_on_enter(void* context) { + NfcApp* nfc = context; + Widget* widget = nfc->widget; + + notification_message(nfc->notifications, &sequence_error); + + widget_add_icon_element(widget, 72, 17, &I_DolphinCommon_56x48); + widget_add_string_element( + widget, 7, 4, AlignLeft, AlignTop, FontPrimary, "Writing gone wrong!"); + widget_add_string_multiline_element( + widget, + 7, + 17, + AlignLeft, + AlignTop, + FontSecondary, + "Not all sectors\nwere written\ncorrectly."); + + widget_add_button_element( + widget, GuiButtonTypeLeft, "Finish", nfc_scene_mf_classic_write_fail_widget_callback, nfc); + + // Setup and start worker + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); +} + +bool nfc_scene_mf_classic_write_fail_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeLeft) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneFileSelect); + } + } else if(event.type == SceneManagerEventTypeBack) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneSavedMenu); + } + return consumed; +} + +void nfc_scene_mf_classic_write_fail_on_exit(void* context) { + NfcApp* nfc = context; + + widget_reset(nfc->widget); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_write_success.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_write_success.c new file mode 100644 index 000000000000..272d607dfb35 --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_write_success.c @@ -0,0 +1,44 @@ +#include "../nfc_app_i.h" +#include + +void nfc_scene_mf_classic_write_success_popup_callback(void* context) { + NfcApp* nfc = context; + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); +} + +void nfc_scene_mf_classic_write_success_on_enter(void* context) { + NfcApp* nfc = context; + DOLPHIN_DEED(DolphinDeedNfcSave); + + notification_message(nfc->notifications, &sequence_success); + + Popup* popup = nfc->popup; + popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); + popup_set_header(popup, "Successfully\nwritten", 13, 22, AlignLeft, AlignBottom); + popup_set_timeout(popup, 1500); + popup_set_context(popup, nfc); + popup_set_callback(popup, nfc_scene_mf_classic_write_success_popup_callback); + popup_enable_timeout(popup); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); +} + +bool nfc_scene_mf_classic_write_success_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventViewExit) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneFileSelect); + } + } + return consumed; +} + +void nfc_scene_mf_classic_write_success_on_exit(void* context) { + NfcApp* nfc = context; + + // Clear view + popup_reset(nfc->popup); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_wrong_card.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_wrong_card.c new file mode 100644 index 000000000000..ac7d6593470d --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_wrong_card.c @@ -0,0 +1,53 @@ +#include "../nfc_app_i.h" + +void nfc_scene_mf_classic_wrong_card_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + NfcApp* nfc = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); + } +} + +void nfc_scene_mf_classic_wrong_card_on_enter(void* context) { + NfcApp* nfc = context; + Widget* widget = nfc->widget; + + notification_message(nfc->notifications, &sequence_error); + + widget_add_icon_element(widget, 73, 17, &I_DolphinCommon_56x48); + widget_add_string_element( + widget, 3, 4, AlignLeft, AlignTop, FontPrimary, "This is wrong card"); + widget_add_string_multiline_element( + widget, + 4, + 17, + AlignLeft, + AlignTop, + FontSecondary, + "Data management\nis only possible\nwith initial card"); + widget_add_button_element( + widget, GuiButtonTypeLeft, "Retry", nfc_scene_mf_classic_wrong_card_widget_callback, nfc); + + // Setup and start worker + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); +} + +bool nfc_scene_mf_classic_wrong_card_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeLeft) { + consumed = scene_manager_previous_scene(nfc->scene_manager); + } + } + return consumed; +} + +void nfc_scene_mf_classic_wrong_card_on_exit(void* context) { + NfcApp* nfc = context; + + widget_reset(nfc->widget); +} \ No newline at end of file diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_desfire_app.c b/applications/main/nfc_old/scenes/nfc_scene_mf_desfire_app.c new file mode 100644 index 000000000000..2c856157270d --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_desfire_app.c @@ -0,0 +1,120 @@ +#include "../nfc_app_i.h" + +#define TAG "NfcSceneMfDesfireApp" + +enum SubmenuIndex { + SubmenuIndexAppInfo, + SubmenuIndexDynamic, // dynamic indexes start here +}; + +void nfc_scene_mf_desfire_popup_callback(void* context) { + furi_assert(context); + + NfcApp* nfc = context; + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); +} + +MifareDesfireApplication* nfc_scene_mf_desfire_app_get_app(NfcApp* nfc) { + uint32_t app_idx = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireApp) >> + 1; + MifareDesfireApplication* app = nfc->dev->dev_data.mf_df_data.app_head; + for(uint32_t i = 0; i < app_idx && app; i++) { + app = app->next; + } + return app; +} + +void nfc_scene_mf_desfire_app_submenu_callback(void* context, uint32_t index) { + NfcApp* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, index); +} + +void nfc_scene_mf_desfire_app_on_enter(void* context) { + NfcApp* nfc = context; + MifareDesfireApplication* app = nfc_scene_mf_desfire_app_get_app(nfc); + if(!app) { + popup_set_icon(nfc->popup, 5, 5, &I_WarningDolphin_45x42); + popup_set_header(nfc->popup, "Empty card!", 55, 12, AlignLeft, AlignBottom); + popup_set_callback(nfc->popup, nfc_scene_mf_desfire_popup_callback); + popup_set_context(nfc->popup, nfc); + popup_set_timeout(nfc->popup, 3000); + popup_enable_timeout(nfc->popup); + popup_set_text(nfc->popup, "No application\nfound.", 55, 15, AlignLeft, AlignTop); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); + } else { + text_box_set_font(nfc->text_box, TextBoxFontHex); + submenu_add_item( + nfc->submenu, + "App info", + SubmenuIndexAppInfo, + nfc_scene_mf_desfire_app_submenu_callback, + nfc); + + FuriString* label = furi_string_alloc(); + int idx = SubmenuIndexDynamic; + for(MifareDesfireFile* file = app->file_head; file; file = file->next) { + furi_string_printf(label, "File %d", file->id); + submenu_add_item( + nfc->submenu, + furi_string_get_cstr(label), + idx++, + nfc_scene_mf_desfire_app_submenu_callback, + nfc); + } + furi_string_free(label); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); + } +} + +bool nfc_scene_mf_desfire_app_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireApp); + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventViewExit) { + consumed = scene_manager_previous_scene(nfc->scene_manager); + } else { + MifareDesfireApplication* app = nfc_scene_mf_desfire_app_get_app(nfc); + TextBox* text_box = nfc->text_box; + furi_string_reset(nfc->text_box_store); + if(event.event == SubmenuIndexAppInfo) { + mf_df_cat_application_info(app, nfc->text_box_store); + } else { + uint16_t index = event.event - SubmenuIndexDynamic; + MifareDesfireFile* file = app->file_head; + for(int i = 0; file && i < index; i++) { + file = file->next; + } + if(!file) { + return false; + } + mf_df_cat_file(file, nfc->text_box_store); + } + text_box_set_text(text_box, furi_string_get_cstr(nfc->text_box_store)); + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfDesfireApp, state | 1); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); + 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, NfcSceneMfDesfireApp, state & ~1); + consumed = true; + } + } + + return consumed; +} + +void nfc_scene_mf_desfire_app_on_exit(void* context) { + NfcApp* nfc = context; + + // Clear views + popup_reset(nfc->popup); + text_box_reset(nfc->text_box); + furi_string_reset(nfc->text_box_store); + submenu_reset(nfc->submenu); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_desfire_data.c b/applications/main/nfc_old/scenes/nfc_scene_mf_desfire_data.c new file mode 100644 index 000000000000..e9e529909dc5 --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_desfire_data.c @@ -0,0 +1,104 @@ +#include "../nfc_app_i.h" + +#define TAG "NfcSceneMfDesfireData" + +enum { + MifareDesfireDataStateMenu, + MifareDesfireDataStateItem, // MUST be last, states >= this correspond with submenu index +}; + +enum SubmenuIndex { + SubmenuIndexCardInfo, + SubmenuIndexDynamic, // dynamic indexes start here +}; + +void nfc_scene_mf_desfire_data_submenu_callback(void* context, uint32_t index) { + NfcApp* nfc = (NfcApp*)context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, index); +} + +void nfc_scene_mf_desfire_data_on_enter(void* context) { + NfcApp* nfc = context; + Submenu* submenu = nfc->submenu; + uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireData); + MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data; + + text_box_set_font(nfc->text_box, TextBoxFontHex); + + submenu_add_item( + submenu, + "Card info", + SubmenuIndexCardInfo, + nfc_scene_mf_desfire_data_submenu_callback, + nfc); + + FuriString* label = furi_string_alloc(); + int idx = SubmenuIndexDynamic; + for(MifareDesfireApplication* app = data->app_head; app; app = app->next) { + furi_string_printf(label, "App %02x%02x%02x", app->id[0], app->id[1], app->id[2]); + submenu_add_item( + submenu, + furi_string_get_cstr(label), + idx++, + nfc_scene_mf_desfire_data_submenu_callback, + nfc); + } + furi_string_free(label); + + if(state >= MifareDesfireDataStateItem) { + submenu_set_selected_item( + nfc->submenu, state - MifareDesfireDataStateItem + SubmenuIndexDynamic); + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneMfDesfireData, MifareDesfireDataStateMenu); + } + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); +} + +bool nfc_scene_mf_desfire_data_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireData); + MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data; + + if(event.type == SceneManagerEventTypeCustom) { + TextBox* text_box = nfc->text_box; + furi_string_reset(nfc->text_box_store); + if(event.event == SubmenuIndexCardInfo) { + mf_df_cat_card_info(data, nfc->text_box_store); + text_box_set_text(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, + NfcSceneMfDesfireData, + MifareDesfireDataStateItem + SubmenuIndexCardInfo); + consumed = true; + } else { + uint16_t index = event.event - SubmenuIndexDynamic; + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneMfDesfireData, MifareDesfireDataStateItem + index); + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfDesfireApp, index << 1); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireApp); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeBack) { + if(state >= MifareDesfireDataStateItem) { + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneMfDesfireData, MifareDesfireDataStateMenu); + consumed = true; + } + } + + return consumed; +} + +void nfc_scene_mf_desfire_data_on_exit(void* context) { + NfcApp* nfc = context; + + // Clear views + text_box_reset(nfc->text_box); + furi_string_reset(nfc->text_box_store); + submenu_reset(nfc->submenu); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_desfire_menu.c b/applications/main/nfc_old/scenes/nfc_scene_mf_desfire_menu.c new file mode 100644 index 000000000000..b3ebe9a469a9 --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_desfire_menu.c @@ -0,0 +1,72 @@ +#include "../nfc_app_i.h" +#include + +enum SubmenuIndex { + SubmenuIndexSave, + SubmenuIndexEmulateUid, + SubmenuIndexInfo, +}; + +void nfc_scene_mf_desfire_menu_submenu_callback(void* context, uint32_t index) { + NfcApp* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, index); +} + +void nfc_scene_mf_desfire_menu_on_enter(void* context) { + NfcApp* nfc = context; + Submenu* submenu = nfc->submenu; + + submenu_add_item( + submenu, "Save", SubmenuIndexSave, nfc_scene_mf_desfire_menu_submenu_callback, nfc); + submenu_add_item( + submenu, + "Emulate UID", + SubmenuIndexEmulateUid, + nfc_scene_mf_desfire_menu_submenu_callback, + nfc); + submenu_add_item( + submenu, "Info", SubmenuIndexInfo, nfc_scene_mf_desfire_menu_submenu_callback, nfc); + + submenu_set_selected_item( + nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireMenu)); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); +} + +bool nfc_scene_mf_desfire_menu_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexSave) { + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneMfDesfireMenu, SubmenuIndexSave); + nfc->dev->format = NfcDeviceSaveFormatMifareDesfire; + // Clear device name + nfc_device_set_name(nfc->dev, ""); + scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); + consumed = true; + } else if(event.event == SubmenuIndexEmulateUid) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); + if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) { + DOLPHIN_DEED(DolphinDeedNfcAddEmulate); + } else { + DOLPHIN_DEED(DolphinDeedNfcEmulate); + } + consumed = true; + } else if(event.event == SubmenuIndexInfo) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); + consumed = true; + } + } + + return consumed; +} + +void nfc_scene_mf_desfire_menu_on_exit(void* context) { + NfcApp* nfc = context; + + // Clear view + submenu_reset(nfc->submenu); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_desfire_read_success.c b/applications/main/nfc_old/scenes/nfc_scene_mf_desfire_read_success.c new file mode 100644 index 000000000000..919070595dbe --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_desfire_read_success.c @@ -0,0 +1,96 @@ +#include "../nfc_app_i.h" +#include + +void nfc_scene_mf_desfire_read_success_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + NfcApp* nfc = context; + + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); + } +} + +void nfc_scene_mf_desfire_read_success_on_enter(void* context) { + NfcApp* nfc = context; + + FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data; + MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data; + Widget* widget = nfc->widget; + + // Prepare string for data display + FuriString* temp_str = furi_string_alloc_printf("\e#MIFARE DESfire\n"); + 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]); + } + + uint32_t bytes_total = 1UL << (data->version.sw_storage >> 1); + uint32_t bytes_free = data->free_memory ? data->free_memory->bytes : 0; + furi_string_cat_printf(temp_str, "\n%lu", bytes_total); + if(data->version.sw_storage & 1) { + furi_string_push_back(temp_str, '+'); + } + furi_string_cat_printf(temp_str, " bytes, %lu bytes free\n", bytes_free); + + uint16_t n_apps = 0; + uint16_t n_files = 0; + for(MifareDesfireApplication* app = data->app_head; app; app = app->next) { + n_apps++; + for(MifareDesfireFile* file = app->file_head; file; file = file->next) { + n_files++; + } + } + furi_string_cat_printf(temp_str, "%d Application", n_apps); + if(n_apps != 1) { + furi_string_push_back(temp_str, 's'); + } + furi_string_cat_printf(temp_str, ", %d file", n_files); + if(n_files != 1) { + furi_string_push_back(temp_str, 's'); + } + + notification_message_block(nfc->notifications, &sequence_set_green_255); + + // Add text scroll element + widget_add_text_scroll_element(widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); + furi_string_free(temp_str); + + // Add button elements + widget_add_button_element( + widget, GuiButtonTypeLeft, "Retry", nfc_scene_mf_desfire_read_success_widget_callback, nfc); + widget_add_button_element( + widget, GuiButtonTypeRight, "More", nfc_scene_mf_desfire_read_success_widget_callback, nfc); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); +} + +bool nfc_scene_mf_desfire_read_success_on_event(void* context, SceneManagerEvent event) { + NfcApp* 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, NfcSceneMfDesfireMenu); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeBack) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); + consumed = true; + } + + return consumed; +} + +void nfc_scene_mf_desfire_read_success_on_exit(void* context) { + NfcApp* nfc = context; + + notification_message_block(nfc->notifications, &sequence_reset_green); + + // Clean dialog + widget_reset(nfc->widget); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_data.c b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_data.c new file mode 100644 index 000000000000..7d56cb1483eb --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_data.c @@ -0,0 +1,32 @@ +#include "../nfc_app_i.h" + +void nfc_scene_mf_ultralight_data_on_enter(void* context) { + NfcApp* nfc = context; + MfUltralightData* data = &nfc->dev->dev_data.mf_ul_data; + TextBox* text_box = nfc->text_box; + + text_box_set_font(text_box, TextBoxFontHex); + for(uint16_t i = 0; i < data->data_size; i += 2) { + if(!(i % 8) && i) { + furi_string_push_back(nfc->text_box_store, '\n'); + } + furi_string_cat_printf(nfc->text_box_store, "%02X%02X ", data->data[i], data->data[i + 1]); + } + text_box_set_text(text_box, furi_string_get_cstr(nfc->text_box_store)); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); +} + +bool nfc_scene_mf_ultralight_data_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + UNUSED(event); + return false; +} + +void nfc_scene_mf_ultralight_data_on_exit(void* context) { + NfcApp* nfc = context; + + // Clean view + text_box_reset(nfc->text_box); + furi_string_reset(nfc->text_box_store); +} \ No newline at end of file diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_emulate.c b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_emulate.c new file mode 100644 index 000000000000..192d67bef73e --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_emulate.c @@ -0,0 +1,74 @@ +#include "../nfc_app_i.h" + +#define NFC_MF_UL_DATA_NOT_CHANGED (0UL) +#define NFC_MF_UL_DATA_CHANGED (1UL) + +bool nfc_mf_ultralight_emulate_worker_callback(NfcWorkerEvent event, void* context) { + UNUSED(event); + NfcApp* nfc = context; + + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneMfUltralightEmulate, NFC_MF_UL_DATA_CHANGED); + return true; +} + +void nfc_scene_mf_ultralight_emulate_on_enter(void* context) { + NfcApp* nfc = context; + + // Setup view + MfUltralightType type = nfc->dev->dev_data.mf_ul_data.type; + bool is_ultralight = (type == MfUltralightTypeUL11) || (type == MfUltralightTypeUL21) || + (type == MfUltralightTypeUnknown); + Popup* popup = nfc->popup; + popup_set_header(popup, "Emulating", 67, 13, AlignLeft, AlignTop); + if(strcmp(nfc->dev->dev_name, "") != 0) { + nfc_text_store_set(nfc, "%s", nfc->dev->dev_name); + } else if(is_ultralight) { + nfc_text_store_set(nfc, "MIFARE\nUltralight"); + } else { + nfc_text_store_set(nfc, "MIFARE\nNTAG"); + } + popup_set_icon(popup, 0, 3, &I_NFC_dolphin_emulation_47x61); + popup_set_text(popup, nfc->text_store, 90, 28, AlignCenter, AlignTop); + + // Setup and start worker + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); + nfc_worker_start( + nfc->worker, + NfcWorkerStateMfUltralightEmulate, + &nfc->dev->dev_data, + nfc_mf_ultralight_emulate_worker_callback, + nfc); + nfc_blink_emulate_start(nfc); +} + +bool nfc_scene_mf_ultralight_emulate_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeBack) { + // Stop worker + nfc_worker_stop(nfc->worker); + // Check if data changed and save in shadow file + if(scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightEmulate) == + NFC_MF_UL_DATA_CHANGED) { + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneMfUltralightEmulate, NFC_MF_UL_DATA_NOT_CHANGED); + // Save shadow file + if(furi_string_size(nfc->dev->load_path)) { + nfc_device_save_shadow(nfc->dev, furi_string_get_cstr(nfc->dev->load_path)); + } + } + consumed = false; + } + return consumed; +} + +void nfc_scene_mf_ultralight_emulate_on_exit(void* context) { + NfcApp* nfc = context; + + // Clear view + popup_reset(nfc->popup); + + nfc_blink_stop(nfc); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_key_input.c b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_key_input.c new file mode 100644 index 000000000000..e8c87693d462 --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_key_input.c @@ -0,0 +1,44 @@ +#include "../nfc_app_i.h" + +void nfc_scene_mf_ultralight_key_input_byte_input_callback(void* context) { + NfcApp* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); +} + +void nfc_scene_mf_ultralight_key_input_on_enter(void* context) { + NfcApp* nfc = context; + + // Setup view + ByteInput* byte_input = nfc->byte_input; + byte_input_set_header_text(byte_input, "Enter the password in hex"); + byte_input_set_result_callback( + byte_input, + nfc_scene_mf_ultralight_key_input_byte_input_callback, + NULL, + nfc, + nfc->byte_input_store, + 4); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewByteInput); +} + +bool nfc_scene_mf_ultralight_key_input_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventByteInputDone) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockWarn); + consumed = true; + } + } + return consumed; +} + +void nfc_scene_mf_ultralight_key_input_on_exit(void* context) { + NfcApp* nfc = context; + + // Clear view + byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0); + byte_input_set_header_text(nfc->byte_input, ""); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_menu.c b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_menu.c new file mode 100644 index 000000000000..6069ed356c8f --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_menu.c @@ -0,0 +1,87 @@ +#include "../nfc_app_i.h" +#include + +enum SubmenuIndex { + SubmenuIndexUnlock, + SubmenuIndexSave, + SubmenuIndexEmulate, + SubmenuIndexInfo, +}; + +void nfc_scene_mf_ultralight_menu_submenu_callback(void* context, uint32_t index) { + NfcApp* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, index); +} + +void nfc_scene_mf_ultralight_menu_on_enter(void* context) { + NfcApp* nfc = context; + Submenu* submenu = nfc->submenu; + MfUltralightData* data = &nfc->dev->dev_data.mf_ul_data; + + if(!mf_ul_is_full_capture(data)) { + submenu_add_item( + submenu, + "Unlock", + SubmenuIndexUnlock, + nfc_scene_mf_ultralight_menu_submenu_callback, + nfc); + } + submenu_add_item( + submenu, "Save", SubmenuIndexSave, nfc_scene_mf_ultralight_menu_submenu_callback, nfc); + submenu_add_item( + submenu, + "Emulate", + SubmenuIndexEmulate, + nfc_scene_mf_ultralight_menu_submenu_callback, + nfc); + submenu_add_item( + submenu, "Info", SubmenuIndexInfo, nfc_scene_mf_ultralight_menu_submenu_callback, nfc); + + submenu_set_selected_item( + nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightMenu)); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); +} + +bool nfc_scene_mf_ultralight_menu_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexSave) { + nfc->dev->format = NfcDeviceSaveFormatMifareUl; + // 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, NfcSceneMfUltralightEmulate); + 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, NfcSceneMfUltralightUnlockMenu); + 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, NfcSceneMfUltralightMenu, event.event); + + } else if(event.type == SceneManagerEventTypeBack) { + consumed = scene_manager_previous_scene(nfc->scene_manager); + } + + return consumed; +} + +void nfc_scene_mf_ultralight_menu_on_exit(void* context) { + NfcApp* nfc = context; + + // Clear view + submenu_reset(nfc->submenu); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_read_auth.c b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_read_auth.c new file mode 100644 index 000000000000..4d549989ab4a --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_read_auth.c @@ -0,0 +1,116 @@ +#include "../nfc_app_i.h" + +typedef enum { + NfcSceneMfUlReadStateIdle, + NfcSceneMfUlReadStateDetecting, + NfcSceneMfUlReadStateReading, + NfcSceneMfUlReadStateNotSupportedCard, +} NfcSceneMfUlReadState; + +bool nfc_scene_mf_ultralight_read_auth_worker_callback(NfcWorkerEvent event, void* context) { + NfcApp* nfc = context; + + if(event == NfcWorkerEventMfUltralightPassKey) { + memcpy(nfc->dev->dev_data.mf_ul_data.auth_key, nfc->byte_input_store, 4); + } else { + view_dispatcher_send_custom_event(nfc->view_dispatcher, event); + } + return true; +} + +void nfc_scene_mf_ultralight_read_auth_set_state(NfcApp* nfc, NfcSceneMfUlReadState state) { + uint32_t curr_state = + scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightReadAuth); + if(curr_state != state) { + if(state == NfcSceneMfUlReadStateDetecting) { + popup_reset(nfc->popup); + popup_set_text(nfc->popup, "Apply the\ntarget card", 97, 24, AlignCenter, AlignTop); + popup_set_icon(nfc->popup, 0, 8, &I_NFC_manual_60x50); + nfc_blink_read_start(nfc); + } else if(state == NfcSceneMfUlReadStateReading) { + popup_reset(nfc->popup); + popup_set_header( + nfc->popup, "Reading card\nDon't move...", 85, 24, AlignCenter, AlignTop); + popup_set_icon(nfc->popup, 12, 23, &A_Loading_24); + nfc_blink_detect_start(nfc); + } else if(state == NfcSceneMfUlReadStateNotSupportedCard) { + popup_reset(nfc->popup); + popup_set_header(nfc->popup, "Wrong type of card!", 64, 3, AlignCenter, AlignTop); + popup_set_text( + nfc->popup, + "Only MIFARE\nUltralight & NTAG\nare supported", + 4, + 22, + AlignLeft, + AlignTop); + popup_set_icon(nfc->popup, 73, 20, &I_DolphinCommon_56x48); + nfc_blink_stop(nfc); + notification_message(nfc->notifications, &sequence_error); + notification_message(nfc->notifications, &sequence_set_red_255); + } + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfUltralightReadAuth, state); + } +} + +void nfc_scene_mf_ultralight_read_auth_on_enter(void* context) { + NfcApp* nfc = context; + + nfc_device_clear(nfc->dev); + // Setup view + nfc_scene_mf_ultralight_read_auth_set_state(nfc, NfcSceneMfUlReadStateDetecting); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); + // Start worker + nfc_worker_start( + nfc->worker, + NfcWorkerStateReadMfUltralightReadAuth, + &nfc->dev->dev_data, + nfc_scene_mf_ultralight_read_auth_worker_callback, + nfc); +} + +bool nfc_scene_mf_ultralight_read_auth_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if((event.event == NfcWorkerEventSuccess) || (event.event == NfcWorkerEventFail)) { + notification_message(nfc->notifications, &sequence_success); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadAuthResult); + consumed = true; + } else if(event.event == NfcWorkerEventCardDetected) { + nfc_scene_mf_ultralight_read_auth_set_state(nfc, NfcSceneMfUlReadStateReading); + consumed = true; + } else if(event.event == NfcWorkerEventNoCardDetected) { + nfc_scene_mf_ultralight_read_auth_set_state(nfc, NfcSceneMfUlReadStateDetecting); + consumed = true; + } else if(event.event == NfcWorkerEventWrongCardDetected) { + nfc_scene_mf_ultralight_read_auth_set_state( + nfc, NfcSceneMfUlReadStateNotSupportedCard); + } + } else if(event.type == SceneManagerEventTypeBack) { + MfUltralightData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data; + NfcScene next_scene; + if(mf_ul_data->auth_method == MfUltralightAuthMethodManual) { + next_scene = NfcSceneMfUltralightKeyInput; + } else if(mf_ul_data->auth_method == MfUltralightAuthMethodAuto) { + next_scene = NfcSceneMfUltralightUnlockAuto; + } else { + next_scene = NfcSceneMfUltralightUnlockMenu; + } + consumed = + scene_manager_search_and_switch_to_previous_scene(nfc->scene_manager, next_scene); + } + return consumed; +} + +void nfc_scene_mf_ultralight_read_auth_on_exit(void* context) { + NfcApp* nfc = context; + + // Stop worker + nfc_worker_stop(nfc->worker); + // Clear view + popup_reset(nfc->popup); + nfc_blink_stop(nfc); + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneMfUltralightReadAuth, NfcSceneMfUlReadStateIdle); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_read_auth_result.c b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_read_auth_result.c new file mode 100644 index 000000000000..c3ea1522fac3 --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_read_auth_result.c @@ -0,0 +1,116 @@ +#include "../nfc_app_i.h" + +void nfc_scene_mf_ultralight_read_auth_result_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + NfcApp* nfc = context; + + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); + } +} + +void nfc_scene_mf_ultralight_read_auth_result_on_enter(void* context) { + NfcApp* nfc = context; + + // Setup dialog view + FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data; + MfUltralightData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data; + MfUltralightConfigPages* config_pages = mf_ultralight_get_config_pages(mf_ul_data); + Widget* widget = nfc->widget; + const char* title; + FuriString* temp_str; + temp_str = furi_string_alloc(); + + if((mf_ul_data->data_read == mf_ul_data->data_size) && (mf_ul_data->data_read > 0)) { + if(mf_ul_data->auth_success) { + title = "All pages are unlocked!"; + } else { + title = "All unlocked but failed auth!"; + } + } else { + title = "Not all pages unlocked!"; + } + widget_add_string_element(widget, 64, 0, AlignCenter, AlignTop, FontPrimary, title); + furi_string_set(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]); + } + widget_add_string_element( + widget, 0, 17, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(temp_str)); + if(mf_ul_data->auth_success) { + furi_string_printf( + temp_str, + "Password: %02X %02X %02X %02X", + config_pages->auth_data.pwd.raw[0], + config_pages->auth_data.pwd.raw[1], + config_pages->auth_data.pwd.raw[2], + config_pages->auth_data.pwd.raw[3]); + widget_add_string_element( + widget, 0, 28, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(temp_str)); + furi_string_printf( + temp_str, + "PACK: %02X %02X", + config_pages->auth_data.pack.raw[0], + config_pages->auth_data.pack.raw[1]); + widget_add_string_element( + widget, 0, 39, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(temp_str)); + } + furi_string_printf( + temp_str, "Pages Read: %d/%d", mf_ul_data->data_read / 4, mf_ul_data->data_size / 4); + widget_add_string_element( + widget, 0, 50, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(temp_str)); + widget_add_button_element( + widget, + GuiButtonTypeRight, + "Save", + nfc_scene_mf_ultralight_read_auth_result_widget_callback, + nfc); + + furi_string_free(temp_str); + notification_message(nfc->notifications, &sequence_set_green_255); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); +} + +bool nfc_scene_mf_ultralight_read_auth_result_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeRight) { + nfc->dev->format = NfcDeviceSaveFormatMifareUl; + // Clear device name + nfc_device_set_name(nfc->dev, ""); + scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeBack) { + MfUltralightData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data; + if(mf_ul_data->auth_method == MfUltralightAuthMethodManual || + mf_ul_data->auth_method == MfUltralightAuthMethodAuto) { + consumed = scene_manager_previous_scene(nfc->scene_manager); + } else { + NfcScene next_scene; + if((mf_ul_data->data_read == mf_ul_data->data_size) && (mf_ul_data->data_read > 0)) { + next_scene = NfcSceneMfUltralightMenu; + } else { + next_scene = NfcSceneMfUltralightUnlockMenu; + } + + consumed = + scene_manager_search_and_switch_to_previous_scene(nfc->scene_manager, next_scene); + } + } + + return consumed; +} + +void nfc_scene_mf_ultralight_read_auth_result_on_exit(void* context) { + NfcApp* nfc = context; + + // Clean views + widget_reset(nfc->widget); + + notification_message_block(nfc->notifications, &sequence_reset_green); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_read_success.c b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_read_success.c new file mode 100644 index 000000000000..60c8191e5a10 --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_read_success.c @@ -0,0 +1,84 @@ +#include "../nfc_app_i.h" + +void nfc_scene_mf_ultralight_read_success_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + NfcApp* nfc = context; + + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); + } +} + +void nfc_scene_mf_ultralight_read_success_on_enter(void* context) { + NfcApp* nfc = context; + + // Setup widget view + FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; + MfUltralightData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data; + Widget* widget = nfc->widget; + widget_add_button_element( + widget, + GuiButtonTypeLeft, + "Retry", + nfc_scene_mf_ultralight_read_success_widget_callback, + nfc); + widget_add_button_element( + widget, + GuiButtonTypeRight, + "More", + nfc_scene_mf_ultralight_read_success_widget_callback, + nfc); + + FuriString* temp_str = NULL; + if(furi_string_size(nfc->dev->dev_data.parsed_data)) { + temp_str = furi_string_alloc_set(nfc->dev->dev_data.parsed_data); + } else { + temp_str = furi_string_alloc_printf("\e#%s\n", nfc_mf_ul_type(mf_ul_data->type, true)); + furi_string_cat_printf(temp_str, "UID:"); + for(size_t i = 0; i < data->uid_len; i++) { + furi_string_cat_printf(temp_str, " %02X", data->uid[i]); + } + furi_string_cat_printf( + temp_str, "\nPages Read: %d/%d", mf_ul_data->data_read / 4, mf_ul_data->data_size / 4); + if(mf_ul_data->data_read != mf_ul_data->data_size) { + furi_string_cat_printf(temp_str, "\nPassword-protected pages!"); + } + } + 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_mf_ultralight_read_success_on_event(void* context, SceneManagerEvent event) { + NfcApp* 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, NfcSceneMfUltralightMenu); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeBack) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); + consumed = true; + } + + return consumed; +} + +void nfc_scene_mf_ultralight_read_success_on_exit(void* context) { + NfcApp* nfc = context; + + notification_message_block(nfc->notifications, &sequence_reset_green); + + // Clean view + widget_reset(nfc->widget); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_unlock_auto.c b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_unlock_auto.c new file mode 100644 index 000000000000..24f1703a28f5 --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_unlock_auto.c @@ -0,0 +1,64 @@ +#include "../nfc_app_i.h" + +bool nfc_scene_mf_ultralight_unlock_auto_worker_callback(NfcWorkerEvent event, void* context) { + NfcApp* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, event); + return true; +} + +void nfc_scene_mf_ultralight_unlock_auto_on_enter(void* context) { + NfcApp* nfc = context; + + // Setup view + widget_add_string_multiline_element( + nfc->widget, + 54, + 30, + AlignLeft, + AlignCenter, + FontPrimary, + "Touch the\nreader to get\npassword..."); + widget_add_icon_element(nfc->widget, 0, 15, &I_Modern_reader_18x34); + widget_add_icon_element(nfc->widget, 20, 12, &I_Move_flipper_26x39); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); + + // Start worker + nfc_worker_start( + nfc->worker, + NfcWorkerStateMfUltralightEmulate, + &nfc->dev->dev_data, + nfc_scene_mf_ultralight_unlock_auto_worker_callback, + nfc); + + nfc_blink_read_start(nfc); +} + +bool nfc_scene_mf_ultralight_unlock_auto_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if((event.event == NfcWorkerEventMfUltralightPwdAuth)) { + MfUltralightAuth* auth = &nfc->dev->dev_data.mf_ul_auth; + memcpy(nfc->byte_input_store, auth->pwd.raw, sizeof(auth->pwd.raw)); + nfc->dev->dev_data.mf_ul_data.auth_method = MfUltralightAuthMethodAuto; + nfc_worker_stop(nfc->worker); + notification_message(nfc->notifications, &sequence_success); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockWarn); + consumed = true; + } + } + return consumed; +} + +void nfc_scene_mf_ultralight_unlock_auto_on_exit(void* context) { + NfcApp* nfc = context; + + // Stop worker + nfc_worker_stop(nfc->worker); + // Clear view + widget_reset(nfc->widget); + + nfc_blink_stop(nfc); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_unlock_menu.c b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_unlock_menu.c new file mode 100644 index 000000000000..5c0604d383c4 --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_unlock_menu.c @@ -0,0 +1,83 @@ +#include "../nfc_app_i.h" + +enum SubmenuIndex { + SubmenuIndexMfUlUnlockMenuAuto, + SubmenuIndexMfUlUnlockMenuAmeebo, + SubmenuIndexMfUlUnlockMenuXiaomi, + SubmenuIndexMfUlUnlockMenuManual, +}; + +void nfc_scene_mf_ultralight_unlock_menu_submenu_callback(void* context, uint32_t index) { + NfcApp* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, index); +} + +void nfc_scene_mf_ultralight_unlock_menu_on_enter(void* context) { + NfcApp* nfc = context; + Submenu* submenu = nfc->submenu; + + uint32_t state = + scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightUnlockMenu); + if(nfc->dev->dev_data.protocol == NfcDeviceProtocolMifareUl) { + submenu_add_item( + submenu, + "Unlock With Reader", + SubmenuIndexMfUlUnlockMenuAuto, + nfc_scene_mf_ultralight_unlock_menu_submenu_callback, + nfc); + } + submenu_add_item( + submenu, + "Auth As Ameebo", + SubmenuIndexMfUlUnlockMenuAmeebo, + nfc_scene_mf_ultralight_unlock_menu_submenu_callback, + nfc); + submenu_add_item( + submenu, + "Auth As Xiaomi Air Purifier", + SubmenuIndexMfUlUnlockMenuXiaomi, + nfc_scene_mf_ultralight_unlock_menu_submenu_callback, + nfc); + submenu_add_item( + submenu, + "Enter Password Manually", + SubmenuIndexMfUlUnlockMenuManual, + nfc_scene_mf_ultralight_unlock_menu_submenu_callback, + nfc); + submenu_set_selected_item(submenu, state); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); +} + +bool nfc_scene_mf_ultralight_unlock_menu_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexMfUlUnlockMenuManual) { + nfc->dev->dev_data.mf_ul_data.auth_method = MfUltralightAuthMethodManual; + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightKeyInput); + consumed = true; + } else if(event.event == SubmenuIndexMfUlUnlockMenuAmeebo) { + nfc->dev->dev_data.mf_ul_data.auth_method = MfUltralightAuthMethodAmeebo; + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockWarn); + consumed = true; + } else if(event.event == SubmenuIndexMfUlUnlockMenuXiaomi) { + nfc->dev->dev_data.mf_ul_data.auth_method = MfUltralightAuthMethodXiaomi; + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockWarn); + consumed = true; + } else if(event.event == SubmenuIndexMfUlUnlockMenuAuto) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockAuto); + consumed = true; + } + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneMfUltralightUnlockMenu, event.event); + } + return consumed; +} + +void nfc_scene_mf_ultralight_unlock_menu_on_exit(void* context) { + NfcApp* nfc = context; + + submenu_reset(nfc->submenu); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_unlock_warn.c b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_unlock_warn.c new file mode 100644 index 000000000000..4c8a1c90ff93 --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_unlock_warn.c @@ -0,0 +1,98 @@ +#include "../nfc_app_i.h" +#include + +void nfc_scene_mf_ultralight_unlock_warn_dialog_callback(DialogExResult result, void* context) { + NfcApp* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); +} + +void nfc_scene_mf_ultralight_unlock_warn_on_enter(void* context) { + NfcApp* nfc = context; + DialogEx* dialog_ex = nfc->dialog_ex; + MfUltralightAuthMethod auth_method = nfc->dev->dev_data.mf_ul_data.auth_method; + + dialog_ex_set_context(dialog_ex, nfc); + dialog_ex_set_result_callback(dialog_ex, nfc_scene_mf_ultralight_unlock_warn_dialog_callback); + + if(auth_method == MfUltralightAuthMethodManual || auth_method == MfUltralightAuthMethodAuto) { + // Build dialog text + MfUltralightAuth* auth = &nfc->dev->dev_data.mf_ul_auth; + FuriString* password_str = + furi_string_alloc_set_str("Try to unlock the card with\npassword: "); + for(size_t i = 0; i < sizeof(auth->pwd.raw); ++i) { + furi_string_cat_printf(password_str, "%02X ", nfc->byte_input_store[i]); + } + furi_string_cat_str(password_str, "?\nCaution, a wrong password\ncan block the card!"); + nfc_text_store_set(nfc, furi_string_get_cstr(password_str)); + furi_string_free(password_str); + + dialog_ex_set_header( + dialog_ex, + auth_method == MfUltralightAuthMethodAuto ? "Password captured!" : "Risky function!", + 64, + 0, + AlignCenter, + AlignTop); + dialog_ex_set_text(dialog_ex, nfc->text_store, 64, 12, AlignCenter, AlignTop); + dialog_ex_set_left_button_text(dialog_ex, "Cancel"); + dialog_ex_set_right_button_text(dialog_ex, "Continue"); + + if(auth_method == MfUltralightAuthMethodAuto) + notification_message(nfc->notifications, &sequence_set_green_255); + } else { + dialog_ex_set_header(dialog_ex, "Risky function!", 64, 4, AlignCenter, AlignTop); + dialog_ex_set_text( + dialog_ex, "Wrong password\ncan block your\ncard.", 4, 18, AlignLeft, AlignTop); + dialog_ex_set_icon(dialog_ex, 73, 20, &I_DolphinCommon_56x48); + dialog_ex_set_center_button_text(dialog_ex, "OK"); + } + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); +} + +bool nfc_scene_mf_ultralight_unlock_warn_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + + bool consumed = false; + + MfUltralightAuthMethod auth_method = nfc->dev->dev_data.mf_ul_data.auth_method; + if(auth_method == MfUltralightAuthMethodManual || auth_method == MfUltralightAuthMethodAuto) { + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == DialogExResultRight) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadAuth); + DOLPHIN_DEED(DolphinDeedNfcRead); + consumed = true; + } else if(event.event == DialogExResultLeft) { + if(auth_method == MfUltralightAuthMethodAuto) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneMfUltralightUnlockMenu); + } else { + consumed = scene_manager_previous_scene(nfc->scene_manager); + } + } + } else if(event.type == SceneManagerEventTypeBack) { + // Cannot press back + consumed = true; + } + } else { + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == DialogExResultCenter) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadAuth); + DOLPHIN_DEED(DolphinDeedNfcRead); + consumed = true; + } + } + } + + return consumed; +} + +void nfc_scene_mf_ultralight_unlock_warn_on_exit(void* context) { + NfcApp* nfc = context; + + dialog_ex_reset(nfc->dialog_ex); + nfc_text_store_clear(nfc); + + notification_message_block(nfc->notifications, &sequence_reset_green); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_mfkey_complete.c b/applications/main/nfc_old/scenes/nfc_scene_mfkey_complete.c new file mode 100644 index 000000000000..2f4bba319218 --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_mfkey_complete.c @@ -0,0 +1,49 @@ +#include "../nfc_app_i.h" + +void nfc_scene_mfkey_complete_callback(GuiButtonType result, InputType type, void* context) { + NfcApp* nfc = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); + } +} + +void nfc_scene_mfkey_complete_on_enter(void* context) { + NfcApp* nfc = context; + + widget_add_string_element(nfc->widget, 64, 0, AlignCenter, AlignTop, FontPrimary, "Complete!"); + widget_add_string_multiline_element( + nfc->widget, + 64, + 32, + AlignCenter, + AlignCenter, + FontSecondary, + "Now use mfkey32v2\nto extract keys"); + widget_add_button_element( + nfc->widget, GuiButtonTypeCenter, "OK", nfc_scene_mfkey_complete_callback, nfc); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); +} + +bool nfc_scene_mfkey_complete_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeCenter) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneStart); + } + } else if(event.event == SceneManagerEventTypeBack) { + consumed = + scene_manager_search_and_switch_to_previous_scene(nfc->scene_manager, NfcSceneStart); + } + + return consumed; +} + +void nfc_scene_mfkey_complete_on_exit(void* context) { + NfcApp* nfc = context; + + widget_reset(nfc->widget); +} \ No newline at end of file diff --git a/applications/main/nfc_old/scenes/nfc_scene_mfkey_nonces_info.c b/applications/main/nfc_old/scenes/nfc_scene_mfkey_nonces_info.c new file mode 100644 index 000000000000..5e86f2376fdb --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_mfkey_nonces_info.c @@ -0,0 +1,55 @@ +#include "../nfc_app_i.h" +#include + +void nfc_scene_mfkey_nonces_info_callback(GuiButtonType result, InputType type, void* context) { + NfcApp* nfc = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); + } +} + +void nfc_scene_mfkey_nonces_info_on_enter(void* context) { + NfcApp* nfc = context; + + FuriString* temp_str; + temp_str = furi_string_alloc(); + + uint16_t nonces_saved = mfkey32_get_auth_sectors(temp_str); + widget_add_text_scroll_element(nfc->widget, 0, 22, 128, 42, furi_string_get_cstr(temp_str)); + furi_string_printf(temp_str, "Nonce pairs saved: %d", nonces_saved); + widget_add_string_element( + nfc->widget, 0, 0, AlignLeft, AlignTop, FontPrimary, furi_string_get_cstr(temp_str)); + widget_add_string_element( + nfc->widget, 0, 12, AlignLeft, AlignTop, FontSecondary, "Authenticated sectors:"); + + widget_add_button_element( + nfc->widget, GuiButtonTypeCenter, "OK", nfc_scene_mfkey_nonces_info_callback, nfc); + + furi_string_free(temp_str); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); +} + +bool nfc_scene_mfkey_nonces_info_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeCenter) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfkeyComplete); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeBack) { + consumed = + scene_manager_search_and_switch_to_previous_scene(nfc->scene_manager, NfcSceneStart); + } + + return consumed; +} + +void nfc_scene_mfkey_nonces_info_on_exit(void* context) { + NfcApp* nfc = context; + + // Clear view + widget_reset(nfc->widget); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_nfc_data_info.c b/applications/main/nfc_old/scenes/nfc_scene_nfc_data_info.c new file mode 100644 index 000000000000..975117532aac --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_nfc_data_info.c @@ -0,0 +1,154 @@ +#include "../nfc_app_i.h" + +void nfc_scene_nfc_data_info_widget_callback(GuiButtonType result, InputType type, void* context) { + NfcApp* nfc = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); + } +} + +void nfc_scene_nfc_data_info_on_enter(void* context) { + NfcApp* nfc = context; + Widget* widget = nfc->widget; + FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data; + NfcDeviceData* dev_data = &nfc->dev->dev_data; + NfcProtocol protocol = dev_data->protocol; + uint8_t text_scroll_height = 0; + if((protocol == NfcDeviceProtocolMifareDesfire) || (protocol == NfcDeviceProtocolMifareUl) || + (protocol == NfcDeviceProtocolMifareClassic)) { + widget_add_button_element( + widget, GuiButtonTypeRight, "More", nfc_scene_nfc_data_info_widget_callback, nfc); + text_scroll_height = 52; + } else { + text_scroll_height = 64; + } + + FuriString* temp_str; + temp_str = furi_string_alloc(); + // Set name if present + if(nfc->dev->dev_name[0] != '\0') { + furi_string_printf(temp_str, "\ec%s\n", nfc->dev->dev_name); + } + + // Set tag type + if(protocol == NfcDeviceProtocolEMV) { + furi_string_cat_printf(temp_str, "\e#EMV Bank Card\n"); + } else if(protocol == NfcDeviceProtocolMifareUl) { + furi_string_cat_printf( + temp_str, "\e#%s\n", nfc_mf_ul_type(dev_data->mf_ul_data.type, true)); + } else if(protocol == NfcDeviceProtocolMifareClassic) { + furi_string_cat_printf( + 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 { + furi_string_cat_printf(temp_str, "\e#Unknown ISO tag\n"); + } + + // Set tag iso data + char iso_type = FURI_BIT(nfc_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->atqa[1], nfc_data->atqa[0]); + furi_string_cat_printf(temp_str, " SAK: %02X", nfc_data->sak); + + // Set application specific data + if(protocol == NfcDeviceProtocolMifareDesfire) { + MifareDesfireData* data = &dev_data->mf_df_data; + uint32_t bytes_total = 1UL << (data->version.sw_storage >> 1); + uint32_t bytes_free = data->free_memory ? data->free_memory->bytes : 0; + furi_string_cat_printf(temp_str, "\n%lu", bytes_total); + if(data->version.sw_storage & 1) { + furi_string_push_back(temp_str, '+'); + } + furi_string_cat_printf(temp_str, " bytes, %lu bytes free\n", bytes_free); + + uint16_t n_apps = 0; + uint16_t n_files = 0; + for(MifareDesfireApplication* app = data->app_head; app; app = app->next) { + n_apps++; + for(MifareDesfireFile* file = app->file_head; file; file = file->next) { + n_files++; + } + } + furi_string_cat_printf(temp_str, "%d Application", n_apps); + if(n_apps != 1) { + furi_string_push_back(temp_str, 's'); + } + furi_string_cat_printf(temp_str, ", %d file", n_files); + if(n_files != 1) { + furi_string_push_back(temp_str, 's'); + } + } else if(protocol == NfcDeviceProtocolMifareUl) { + MfUltralightData* data = &dev_data->mf_ul_data; + furi_string_cat_printf( + temp_str, "\nPages Read %d/%d", data->data_read / 4, data->data_size / 4); + if(data->data_size > data->data_read) { + furi_string_cat_printf(temp_str, "\nPassword-protected"); + } else if(data->auth_success) { + MfUltralightConfigPages* config_pages = mf_ultralight_get_config_pages(data); + if(config_pages) { + furi_string_cat_printf( + temp_str, + "\nPassword: %02X %02X %02X %02X", + config_pages->auth_data.pwd.raw[0], + config_pages->auth_data.pwd.raw[1], + config_pages->auth_data.pwd.raw[2], + config_pages->auth_data.pwd.raw[3]); + furi_string_cat_printf( + temp_str, + "\nPACK: %02X %02X", + config_pages->auth_data.pack.raw[0], + config_pages->auth_data.pack.raw[1]); + } + } + } else if(protocol == NfcDeviceProtocolMifareClassic) { + MfClassicData* data = &dev_data->mf_classic_data; + uint8_t sectors_total = mf_classic_get_total_sectors_num(data->type); + uint8_t keys_total = sectors_total * 2; + uint8_t keys_found = 0; + uint8_t sectors_read = 0; + mf_classic_get_read_sectors_and_keys(data, §ors_read, &keys_found); + furi_string_cat_printf(temp_str, "\nKeys Found %d/%d", keys_found, keys_total); + furi_string_cat_printf(temp_str, "\nSectors Read %d/%d", sectors_read, sectors_total); + } + + // Add text scroll widget + widget_add_text_scroll_element( + widget, 0, 0, 128, text_scroll_height, furi_string_get_cstr(temp_str)); + furi_string_free(temp_str); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); +} + +bool nfc_scene_nfc_data_info_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + NfcProtocol protocol = nfc->dev->dev_data.protocol; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeRight) { + if(protocol == NfcDeviceProtocolMifareDesfire) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireData); + consumed = true; + } else if(protocol == NfcDeviceProtocolMifareUl) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightData); + consumed = true; + } else if(protocol == NfcDeviceProtocolMifareClassic) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicData); + consumed = true; + } + } + } + + return consumed; +} + +void nfc_scene_nfc_data_info_on_exit(void* context) { + NfcApp* nfc = context; + + widget_reset(nfc->widget); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_nfca_menu.c b/applications/main/nfc_old/scenes/nfc_scene_nfca_menu.c new file mode 100644 index 000000000000..702325a782bb --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_nfca_menu.c @@ -0,0 +1,68 @@ +#include "../nfc_app_i.h" +#include + +enum SubmenuIndex { + SubmenuIndexSaveUid, + SubmenuIndexEmulateUid, + SubmenuIndexInfo, +}; + +void nfc_scene_nfca_menu_submenu_callback(void* context, uint32_t index) { + NfcApp* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, index); +} + +void nfc_scene_nfca_menu_on_enter(void* context) { + NfcApp* nfc = context; + Submenu* submenu = nfc->submenu; + + submenu_add_item( + submenu, "Save UID", SubmenuIndexSaveUid, nfc_scene_nfca_menu_submenu_callback, nfc); + submenu_add_item( + submenu, "Emulate UID", SubmenuIndexEmulateUid, nfc_scene_nfca_menu_submenu_callback, nfc); + submenu_add_item(submenu, "Info", SubmenuIndexInfo, nfc_scene_nfca_menu_submenu_callback, nfc); + + submenu_set_selected_item( + nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneNfcaMenu)); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); +} + +bool nfc_scene_nfca_menu_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexSaveUid) { + nfc->dev->format = NfcDeviceSaveFormatUid; + // Clear device name + nfc_device_set_name(nfc->dev, ""); + scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); + consumed = true; + } else if(event.event == SubmenuIndexEmulateUid) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); + if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) { + DOLPHIN_DEED(DolphinDeedNfcAddEmulate); + } else { + DOLPHIN_DEED(DolphinDeedNfcEmulate); + } + 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, NfcSceneNfcaMenu, event.event); + } else if(event.type == SceneManagerEventTypeBack) { + consumed = scene_manager_previous_scene(nfc->scene_manager); + } + + return consumed; +} + +void nfc_scene_nfca_menu_on_exit(void* context) { + NfcApp* nfc = context; + + // Clear view + submenu_reset(nfc->submenu); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_nfca_read_success.c b/applications/main/nfc_old/scenes/nfc_scene_nfca_read_success.c new file mode 100644 index 000000000000..089ee067c11f --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_nfca_read_success.c @@ -0,0 +1,73 @@ +#include "../nfc_app_i.h" + +void nfc_scene_nfca_read_success_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + furi_assert(context); + NfcApp* nfc = context; + + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); + } +} + +void nfc_scene_nfca_read_success_on_enter(void* context) { + NfcApp* nfc = context; + + // Setup view + FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; + Widget* widget = nfc->widget; + + FuriString* temp_str; + temp_str = furi_string_alloc_set("\e#Unknown ISO tag\n"); + + notification_message_block(nfc->notifications, &sequence_set_green_255); + + char iso_type = FURI_BIT(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 < data->uid_len; i++) { + furi_string_cat_printf(temp_str, " %02X", data->uid[i]); + } + furi_string_cat_printf(temp_str, "\nATQA: %02X %02X ", data->atqa[1], data->atqa[0]); + furi_string_cat_printf(temp_str, " SAK: %02X", data->sak); + + widget_add_text_scroll_element(widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); + furi_string_free(temp_str); + + widget_add_button_element( + widget, GuiButtonTypeLeft, "Retry", nfc_scene_nfca_read_success_widget_callback, nfc); + widget_add_button_element( + widget, GuiButtonTypeRight, "More", nfc_scene_nfca_read_success_widget_callback, nfc); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); +} + +bool nfc_scene_nfca_read_success_on_event(void* context, SceneManagerEvent event) { + NfcApp* 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, NfcSceneNfcaMenu); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeBack) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); + consumed = true; + } + return consumed; +} + +void nfc_scene_nfca_read_success_on_exit(void* context) { + NfcApp* nfc = context; + + notification_message_block(nfc->notifications, &sequence_reset_green); + + // Clear view + widget_reset(nfc->widget); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_read.c b/applications/main/nfc_old/scenes/nfc_scene_read.c new file mode 100644 index 000000000000..ddb18706cbbc --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_read.c @@ -0,0 +1,123 @@ +#include "../nfc_app_i.h" +#include + +typedef enum { + NfcSceneReadStateIdle, + NfcSceneReadStateDetecting, + NfcSceneReadStateReading, +} NfcSceneReadState; + +bool nfc_scene_read_worker_callback(NfcWorkerEvent event, void* context) { + NfcApp* nfc = context; + bool consumed = false; + if(event == NfcWorkerEventReadMfClassicLoadKeyCache) { + consumed = nfc_device_load_key_cache(nfc->dev); + } else { + view_dispatcher_send_custom_event(nfc->view_dispatcher, event); + consumed = true; + } + return consumed; +} + +void nfc_scene_read_set_state(NfcApp* nfc, NfcSceneReadState state) { + uint32_t curr_state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneRead); + if(curr_state != state) { + if(state == NfcSceneReadStateDetecting) { + popup_reset(nfc->popup); + popup_set_text( + nfc->popup, "Apply card to\nFlipper's back", 97, 24, AlignCenter, AlignTop); + popup_set_icon(nfc->popup, 0, 8, &I_NFC_manual_60x50); + } else if(state == NfcSceneReadStateReading) { + popup_reset(nfc->popup); + popup_set_header( + nfc->popup, "Reading card\nDon't move...", 85, 24, AlignCenter, AlignTop); + popup_set_icon(nfc->popup, 12, 23, &A_Loading_24); + } + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneRead, state); + } +} + +void nfc_scene_read_on_enter(void* context) { + NfcApp* nfc = context; + + nfc_device_clear(nfc->dev); + // Setup view + nfc_scene_read_set_state(nfc, NfcSceneReadStateDetecting); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); + // Start worker + nfc_worker_start( + nfc->worker, NfcWorkerStateRead, &nfc->dev->dev_data, nfc_scene_read_worker_callback, nfc); + + nfc_blink_read_start(nfc); +} + +bool nfc_scene_read_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + 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); + DOLPHIN_DEED(DolphinDeedNfcReadSuccess); + consumed = true; + } else if(event.event == NfcWorkerEventReadUidNfcA) { + notification_message(nfc->notifications, &sequence_success); + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcaReadSuccess); + DOLPHIN_DEED(DolphinDeedNfcReadSuccess); + consumed = true; + } else if(event.event == NfcWorkerEventReadMfUltralight) { + notification_message(nfc->notifications, &sequence_success); + // Set unlock password input to 0xFFFFFFFF only on fresh read + memset(nfc->byte_input_store, 0xFF, sizeof(nfc->byte_input_store)); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadSuccess); + DOLPHIN_DEED(DolphinDeedNfcReadSuccess); + consumed = true; + } else if(event.event == NfcWorkerEventReadMfClassicDone) { + notification_message(nfc->notifications, &sequence_success); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSuccess); + DOLPHIN_DEED(DolphinDeedNfcReadSuccess); + consumed = true; + } else if(event.event == NfcWorkerEventReadMfDesfire) { + notification_message(nfc->notifications, &sequence_success); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireReadSuccess); + DOLPHIN_DEED(DolphinDeedNfcReadSuccess); + consumed = true; + } else if(event.event == NfcWorkerEventReadBankCard) { + notification_message(nfc->notifications, &sequence_success); + scene_manager_next_scene(nfc->scene_manager, NfcSceneEmvReadSuccess); + DOLPHIN_DEED(DolphinDeedNfcReadSuccess); + consumed = true; + } else if(event.event == NfcWorkerEventReadMfClassicDictAttackRequired) { + if(mf_classic_dict_check_presence(MfClassicDictTypeSystem)) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicDictAttack); + } else { + scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound); + } + consumed = true; + } else if(event.event == NfcWorkerEventCardDetected) { + nfc_scene_read_set_state(nfc, NfcSceneReadStateReading); + nfc_blink_detect_start(nfc); + consumed = true; + } else if(event.event == NfcWorkerEventNoCardDetected) { + nfc_scene_read_set_state(nfc, NfcSceneReadStateDetecting); + nfc_blink_read_start(nfc); + consumed = true; + } + } + return consumed; +} + +void nfc_scene_read_on_exit(void* context) { + NfcApp* nfc = context; + + // Stop worker + nfc_worker_stop(nfc->worker); + // Clear view + popup_reset(nfc->popup); + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneRead, NfcSceneReadStateIdle); + + nfc_blink_stop(nfc); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_read_card_success.c b/applications/main/nfc_old/scenes/nfc_scene_read_card_success.c new file mode 100644 index 000000000000..009de9c966fd --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_read_card_success.c @@ -0,0 +1,61 @@ +#include "../nfc_app_i.h" + +void nfc_scene_read_card_success_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + furi_assert(context); + NfcApp* nfc = context; + + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); + } +} + +void nfc_scene_read_card_success_on_enter(void* context) { + NfcApp* nfc = context; + + FuriString* temp_str; + temp_str = furi_string_alloc(); + + // Setup view + FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; + Widget* widget = nfc->widget; + furi_string_set(temp_str, nfc_get_dev_type(data->type)); + widget_add_string_element( + widget, 64, 12, AlignCenter, AlignBottom, FontPrimary, furi_string_get_cstr(temp_str)); + furi_string_set(temp_str, "UID:"); + for(uint8_t i = 0; i < data->uid_len; i++) { + furi_string_cat_printf(temp_str, " %02X", data->uid[i]); + } + widget_add_string_element( + widget, 64, 32, AlignCenter, AlignCenter, FontSecondary, furi_string_get_cstr(temp_str)); + widget_add_button_element( + widget, GuiButtonTypeLeft, "Retry", nfc_scene_read_card_success_widget_callback, nfc); + + furi_string_free(temp_str); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); +} + +bool nfc_scene_read_card_success_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeLeft) { + consumed = scene_manager_previous_scene(nfc->scene_manager); + } + } else if(event.type == SceneManagerEventTypeBack) { + consumed = + scene_manager_search_and_switch_to_previous_scene(nfc->scene_manager, NfcSceneStart); + } + return consumed; +} + +void nfc_scene_read_card_success_on_exit(void* context) { + NfcApp* nfc = context; + + // Clear view + widget_reset(nfc->widget); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_read_card_type.c b/applications/main/nfc_old/scenes/nfc_scene_read_card_type.c new file mode 100644 index 000000000000..d763f2f723df --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_read_card_type.c @@ -0,0 +1,97 @@ +#include "../nfc_app_i.h" +#include "nfc_worker_i.h" + +enum SubmenuIndex { + SubmenuIndexReadMifareClassic, + SubmenuIndexReadMifareDesfire, + SubmenuIndexReadMfUltralight, + SubmenuIndexReadEMV, + SubmenuIndexReadNFCA, +}; + +void nfc_scene_read_card_type_submenu_callback(void* context, uint32_t index) { + NfcApp* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, index); +} + +void nfc_scene_read_card_type_on_enter(void* context) { + NfcApp* nfc = context; + Submenu* submenu = nfc->submenu; + + submenu_add_item( + submenu, + "Read Mifare Classic", + SubmenuIndexReadMifareClassic, + nfc_scene_read_card_type_submenu_callback, + nfc); + submenu_add_item( + submenu, + "Read Mifare DESFire", + SubmenuIndexReadMifareDesfire, + nfc_scene_read_card_type_submenu_callback, + nfc); + submenu_add_item( + submenu, + "Read NTAG/Ultralight", + SubmenuIndexReadMfUltralight, + nfc_scene_read_card_type_submenu_callback, + nfc); + submenu_add_item( + submenu, + "Read EMV card", + SubmenuIndexReadEMV, + nfc_scene_read_card_type_submenu_callback, + nfc); + submenu_add_item( + submenu, + "Read NFC-A data", + SubmenuIndexReadNFCA, + nfc_scene_read_card_type_submenu_callback, + nfc); + uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadCardType); + submenu_set_selected_item(submenu, state); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); +} + +bool nfc_scene_read_card_type_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexReadMifareClassic) { + nfc->dev->dev_data.read_mode = NfcReadModeMfClassic; + scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); + consumed = true; + } + if(event.event == SubmenuIndexReadMifareDesfire) { + nfc->dev->dev_data.read_mode = NfcReadModeMfDesfire; + scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); + consumed = true; + } + if(event.event == SubmenuIndexReadMfUltralight) { + nfc->dev->dev_data.read_mode = NfcReadModeMfUltralight; + scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); + consumed = true; + } + if(event.event == SubmenuIndexReadEMV) { + nfc->dev->dev_data.read_mode = NfcReadModeEMV; + scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); + consumed = true; + } + if(event.event == SubmenuIndexReadNFCA) { + nfc->dev->dev_data.read_mode = NfcReadModeNFCA; + scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); + consumed = true; + } + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneReadCardType, event.event); + } + return consumed; +} + +void nfc_scene_read_card_type_on_exit(void* context) { + NfcApp* nfc = context; + + submenu_reset(nfc->submenu); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_restore_original.c b/applications/main/nfc_old/scenes/nfc_scene_restore_original.c new file mode 100644 index 000000000000..f059eeac497b --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_restore_original.c @@ -0,0 +1,45 @@ +#include "../nfc_app_i.h" + +void nfc_scene_restore_original_popup_callback(void* context) { + NfcApp* nfc = context; + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); +} + +void nfc_scene_restore_original_on_enter(void* context) { + NfcApp* nfc = context; + + // Setup view + Popup* popup = nfc->popup; + popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); + popup_set_header(popup, "Original file\nrestored", 13, 22, AlignLeft, AlignBottom); + popup_set_timeout(popup, 1500); + popup_set_context(popup, nfc); + popup_set_callback(popup, nfc_scene_restore_original_popup_callback); + popup_enable_timeout(popup); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); +} + +bool nfc_scene_restore_original_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventViewExit) { + if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSavedMenu)) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneSavedMenu); + } else { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneStart); + } + } + } + return consumed; +} + +void nfc_scene_restore_original_on_exit(void* context) { + NfcApp* nfc = context; + + // Clear view + popup_reset(nfc->popup); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_restore_original_confirm.c b/applications/main/nfc_old/scenes/nfc_scene_restore_original_confirm.c new file mode 100644 index 000000000000..e396049aed90 --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_restore_original_confirm.c @@ -0,0 +1,53 @@ +#include "../nfc_app_i.h" + +void nfc_scene_restore_original_confirm_dialog_callback(DialogExResult result, void* context) { + NfcApp* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); +} + +void nfc_scene_restore_original_confirm_on_enter(void* context) { + NfcApp* nfc = context; + DialogEx* dialog_ex = nfc->dialog_ex; + + dialog_ex_set_header(dialog_ex, "Restore Card Data?", 64, 0, AlignCenter, AlignTop); + dialog_ex_set_icon(dialog_ex, 5, 15, &I_Restoring_38x32); + dialog_ex_set_text( + dialog_ex, "It will be returned\nto its original state.", 47, 21, AlignLeft, AlignTop); + dialog_ex_set_left_button_text(dialog_ex, "Cancel"); + dialog_ex_set_right_button_text(dialog_ex, "Restore"); + dialog_ex_set_context(dialog_ex, nfc); + dialog_ex_set_result_callback(dialog_ex, nfc_scene_restore_original_confirm_dialog_callback); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); +} + +bool nfc_scene_restore_original_confirm_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == DialogExResultRight) { + if(!nfc_device_restore(nfc->dev, true)) { + scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneStart); + } else { + scene_manager_next_scene(nfc->scene_manager, NfcSceneRestoreOriginal); + } + consumed = true; + } else if(event.event == DialogExResultLeft) { + consumed = scene_manager_previous_scene(nfc->scene_manager); + } + } else if(event.type == SceneManagerEventTypeBack) { + consumed = true; + } + + return consumed; +} + +void nfc_scene_restore_original_confirm_on_exit(void* context) { + NfcApp* nfc = context; + + // Clean view + dialog_ex_reset(nfc->dialog_ex); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_retry_confirm.c b/applications/main/nfc_old/scenes/nfc_scene_retry_confirm.c new file mode 100644 index 000000000000..9f37c41588b5 --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_retry_confirm.c @@ -0,0 +1,47 @@ +#include "../nfc_app_i.h" + +void nfc_scene_retry_confirm_dialog_callback(DialogExResult result, void* context) { + NfcApp* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); +} + +void nfc_scene_retry_confirm_on_enter(void* context) { + NfcApp* nfc = context; + DialogEx* dialog_ex = nfc->dialog_ex; + + dialog_ex_set_left_button_text(dialog_ex, "Retry"); + dialog_ex_set_right_button_text(dialog_ex, "Stay"); + dialog_ex_set_header(dialog_ex, "Retry Reading?", 64, 11, AlignCenter, AlignTop); + dialog_ex_set_text( + dialog_ex, "All unsaved data\nwill be lost!", 64, 25, AlignCenter, AlignTop); + dialog_ex_set_context(dialog_ex, nfc); + dialog_ex_set_result_callback(dialog_ex, nfc_scene_retry_confirm_dialog_callback); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); +} + +bool nfc_scene_retry_confirm_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == DialogExResultRight) { + consumed = scene_manager_previous_scene(nfc->scene_manager); + } else if(event.event == DialogExResultLeft) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneRead); + } + } else if(event.type == SceneManagerEventTypeBack) { + consumed = true; + } + + return consumed; +} + +void nfc_scene_retry_confirm_on_exit(void* context) { + NfcApp* nfc = context; + + // Clean view + dialog_ex_reset(nfc->dialog_ex); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_rpc.c b/applications/main/nfc_old/scenes/nfc_scene_rpc.c new file mode 100644 index 000000000000..ee6e8b990a9c --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_rpc.c @@ -0,0 +1,86 @@ +#include "../nfc_app_i.h" + +void nfc_scene_rpc_on_enter(void* context) { + NfcApp* nfc = context; + Popup* popup = nfc->popup; + + popup_set_header(popup, "NFC", 89, 42, AlignCenter, AlignBottom); + popup_set_text(popup, "RPC mode", 89, 44, AlignCenter, AlignTop); + + popup_set_icon(popup, 0, 12, &I_NFC_dolphin_emulation_47x61); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); + + notification_message(nfc->notifications, &sequence_display_backlight_on); +} + +static bool nfc_scene_rpc_emulate_callback(NfcWorkerEvent event, void* context) { + UNUSED(event); + NfcApp* nfc = context; + + nfc->rpc_state = NfcRpcStateEmulated; + return true; +} + +bool nfc_scene_rpc_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + Popup* popup = nfc->popup; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + consumed = true; + if(event.event == NfcCustomEventViewExit) { + rpc_system_app_confirm(nfc->rpc_ctx, RpcAppEventAppExit, true); + scene_manager_stop(nfc->scene_manager); + view_dispatcher_stop(nfc->view_dispatcher); + } else if(event.event == NfcCustomEventRpcSessionClose) { + scene_manager_stop(nfc->scene_manager); + view_dispatcher_stop(nfc->view_dispatcher); + } else if(event.event == NfcCustomEventRpcLoad) { + bool result = false; + const char* arg = rpc_system_app_get_data(nfc->rpc_ctx); + if((arg) && (nfc->rpc_state == NfcRpcStateIdle)) { + if(nfc_device_load(nfc->dev, arg, false)) { + if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { + nfc_worker_start( + nfc->worker, + NfcWorkerStateMfUltralightEmulate, + &nfc->dev->dev_data, + nfc_scene_rpc_emulate_callback, + nfc); + } else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) { + nfc_worker_start( + nfc->worker, + NfcWorkerStateMfClassicEmulate, + &nfc->dev->dev_data, + nfc_scene_rpc_emulate_callback, + nfc); + } else { + nfc_worker_start( + nfc->worker, NfcWorkerStateUidEmulate, &nfc->dev->dev_data, NULL, nfc); + } + nfc->rpc_state = NfcRpcStateEmulating; + result = true; + + nfc_blink_emulate_start(nfc); + nfc_text_store_set(nfc, "emulating\n%s", nfc->dev->dev_name); + popup_set_text(popup, nfc->text_store, 89, 44, AlignCenter, AlignTop); + } + } + + rpc_system_app_confirm(nfc->rpc_ctx, RpcAppEventLoadFile, result); + } + } + return consumed; +} + +void nfc_scene_rpc_on_exit(void* context) { + NfcApp* nfc = context; + Popup* popup = nfc->popup; + + nfc_blink_stop(nfc); + + popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom); + popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop); + popup_set_icon(popup, 0, 0, NULL); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_save_name.c b/applications/main/nfc_old/scenes/nfc_scene_save_name.c new file mode 100644 index 000000000000..41fbb8833de3 --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_save_name.c @@ -0,0 +1,93 @@ +#include "../nfc_app_i.h" +#include +#include +#include +#include + +void nfc_scene_save_name_text_input_callback(void* context) { + NfcApp* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventTextInputDone); +} + +void nfc_scene_save_name_on_enter(void* context) { + NfcApp* nfc = context; + + // Setup view + TextInput* text_input = nfc->text_input; + bool dev_name_empty = false; + if(!strcmp(nfc->dev->dev_name, "")) { + set_random_name(nfc->text_store, sizeof(nfc->text_store)); + dev_name_empty = true; + } else { + nfc_text_store_set(nfc, nfc->dev->dev_name); + } + text_input_set_header_text(text_input, "Name the card"); + text_input_set_result_callback( + text_input, + nfc_scene_save_name_text_input_callback, + nfc, + nfc->text_store, + NFC_DEV_NAME_MAX_LEN, + dev_name_empty); + + FuriString* folder_path; + folder_path = furi_string_alloc(); + + if(furi_string_end_with(nfc->dev->load_path, NFC_APP_EXTENSION)) { + path_extract_dirname(furi_string_get_cstr(nfc->dev->load_path), folder_path); + } else { + furi_string_set(folder_path, NFC_APP_FOLDER); + } + + ValidatorIsFile* validator_is_file = validator_is_file_alloc_init( + furi_string_get_cstr(folder_path), NFC_APP_EXTENSION, nfc->dev->dev_name); + text_input_set_validator(text_input, validator_is_file_callback, validator_is_file); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextInput); + + furi_string_free(folder_path); +} + +bool nfc_scene_save_name_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventTextInputDone) { + if(strcmp(nfc->dev->dev_name, "") != 0) { + nfc_device_delete(nfc->dev, true); + } + if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetUid)) { + nfc->dev->dev_data.nfc_data = nfc->dev_edit_data; + } + strlcpy(nfc->dev->dev_name, nfc->text_store, strlen(nfc->text_store) + 1); + if(nfc_save_file(nfc)) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess); + if(!scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSavedMenu)) { + // Nothing, do not count editing as saving + } else if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) { + DOLPHIN_DEED(DolphinDeedNfcAddSave); + } else { + DOLPHIN_DEED(DolphinDeedNfcSave); + } + consumed = true; + } else { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneStart); + } + } + } + return consumed; +} + +void nfc_scene_save_name_on_exit(void* context) { + NfcApp* nfc = context; + + // Clear view + void* validator_context = text_input_get_validator_callback_context(nfc->text_input); + text_input_set_validator(nfc->text_input, NULL, NULL); + validator_is_file_free(validator_context); + + text_input_reset(nfc->text_input); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_save_success.c b/applications/main/nfc_old/scenes/nfc_scene_save_success.c new file mode 100644 index 000000000000..4c19f2f42e0f --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_save_success.c @@ -0,0 +1,48 @@ +#include "../nfc_app_i.h" + +void nfc_scene_save_success_popup_callback(void* context) { + NfcApp* nfc = context; + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); +} + +void nfc_scene_save_success_on_enter(void* context) { + NfcApp* nfc = context; + + // Setup view + Popup* popup = nfc->popup; + popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); + popup_set_header(popup, "Saved!", 13, 22, AlignLeft, AlignBottom); + popup_set_timeout(popup, 1500); + popup_set_context(popup, nfc); + popup_set_callback(popup, nfc_scene_save_success_popup_callback); + popup_enable_timeout(popup); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); +} + +bool nfc_scene_save_success_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventViewExit) { + if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneMfClassicKeys)) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneMfClassicKeys); + } else if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSavedMenu)) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneSavedMenu); + } else { + consumed = scene_manager_search_and_switch_to_another_scene( + nfc->scene_manager, NfcSceneFileSelect); + } + } + } + return consumed; +} + +void nfc_scene_save_success_on_exit(void* context) { + NfcApp* nfc = context; + + // Clear view + popup_reset(nfc->popup); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_saved_menu.c b/applications/main/nfc_old/scenes/nfc_scene_saved_menu.c new file mode 100644 index 000000000000..987911d79fff --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_saved_menu.c @@ -0,0 +1,180 @@ +#include "../nfc_app_i.h" +#include + +enum SubmenuIndex { + SubmenuIndexEmulate, + SubmenuIndexEditUid, + SubmenuIndexDetectReader, + SubmenuIndexWrite, + SubmenuIndexUpdate, + SubmenuIndexRename, + SubmenuIndexDelete, + SubmenuIndexInfo, + SubmenuIndexRestoreOriginal, + SubmenuIndexMfUlUnlockByReader, + SubmenuIndexMfUlUnlockByPassword, +}; + +void nfc_scene_saved_menu_submenu_callback(void* context, uint32_t index) { + NfcApp* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, index); +} + +void nfc_scene_saved_menu_on_enter(void* context) { + NfcApp* nfc = context; + Submenu* submenu = nfc->submenu; + + if(nfc->dev->format == NfcDeviceSaveFormatUid || + nfc->dev->format == NfcDeviceSaveFormatMifareDesfire) { + submenu_add_item( + submenu, + "Emulate UID", + SubmenuIndexEmulate, + nfc_scene_saved_menu_submenu_callback, + nfc); + if(nfc->dev->dev_data.protocol == NfcDeviceProtocolUnknown) { + submenu_add_item( + submenu, + "Edit UID", + SubmenuIndexEditUid, + nfc_scene_saved_menu_submenu_callback, + nfc); + } + } else if( + nfc->dev->format == NfcDeviceSaveFormatMifareUl || + nfc->dev->format == NfcDeviceSaveFormatMifareClassic) { + submenu_add_item( + submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_saved_menu_submenu_callback, nfc); + } + if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) { + if(!mf_classic_is_card_read(&nfc->dev->dev_data.mf_classic_data)) { + submenu_add_item( + submenu, + "Detect Reader", + SubmenuIndexDetectReader, + nfc_scene_saved_menu_submenu_callback, + nfc); + } + submenu_add_item( + submenu, + "Write to Initial Card", + SubmenuIndexWrite, + nfc_scene_saved_menu_submenu_callback, + nfc); + submenu_add_item( + submenu, + "Update from Initial Card", + SubmenuIndexUpdate, + nfc_scene_saved_menu_submenu_callback, + nfc); + } + submenu_add_item( + submenu, "Info", SubmenuIndexInfo, nfc_scene_saved_menu_submenu_callback, nfc); + if(nfc->dev->format == NfcDeviceSaveFormatMifareUl && + !mf_ul_is_full_capture(&nfc->dev->dev_data.mf_ul_data)) { + submenu_add_item( + submenu, + "Unlock with Reader", + SubmenuIndexMfUlUnlockByReader, + nfc_scene_saved_menu_submenu_callback, + nfc); + submenu_add_item( + submenu, + "Unlock with Password", + SubmenuIndexMfUlUnlockByPassword, + nfc_scene_saved_menu_submenu_callback, + nfc); + } + if(nfc->dev->shadow_file_exist) { + submenu_add_item( + submenu, + "Restore to original", + SubmenuIndexRestoreOriginal, + nfc_scene_saved_menu_submenu_callback, + nfc); + } + submenu_add_item( + submenu, "Rename", SubmenuIndexRename, nfc_scene_saved_menu_submenu_callback, nfc); + submenu_add_item( + submenu, "Delete", SubmenuIndexDelete, nfc_scene_saved_menu_submenu_callback, nfc); + submenu_set_selected_item( + nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneSavedMenu)); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); +} + +bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + NfcDeviceData* dev_data = &nfc->dev->dev_data; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneSavedMenu, event.event); + if(event.event == SubmenuIndexEmulate) { + if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate); + } else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate); + } else { + scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); + } + DOLPHIN_DEED(DolphinDeedNfcEmulate); + consumed = true; + } else if(event.event == SubmenuIndexDetectReader) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneDetectReader); + DOLPHIN_DEED(DolphinDeedNfcDetectReader); + consumed = true; + } else if(event.event == SubmenuIndexWrite) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicWrite); + consumed = true; + } else if(event.event == SubmenuIndexUpdate) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicUpdate); + consumed = true; + } else if(event.event == SubmenuIndexRename) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); + consumed = true; + } else if(event.event == SubmenuIndexEditUid) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneSetUid); + consumed = true; + } else if(event.event == SubmenuIndexDelete) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneDelete); + consumed = true; + } else if(event.event == SubmenuIndexInfo) { + bool application_info_present = false; + if(dev_data->protocol == NfcDeviceProtocolEMV) { + application_info_present = true; + } else if( + dev_data->protocol == NfcDeviceProtocolMifareClassic || + dev_data->protocol == NfcDeviceProtocolMifareUl) { + application_info_present = nfc_supported_card_verify_and_parse(dev_data); + } + + FURI_LOG_I("nfc", "application_info_present: %d", application_info_present); + + if(application_info_present) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneDeviceInfo); + } else { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); + } + consumed = true; + } else if(event.event == SubmenuIndexRestoreOriginal) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneRestoreOriginalConfirm); + consumed = true; + } else if(event.event == SubmenuIndexMfUlUnlockByReader) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockAuto); + consumed = true; + } else if(event.event == SubmenuIndexMfUlUnlockByPassword) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockMenu); + consumed = true; + } + } + + return consumed; +} + +void nfc_scene_saved_menu_on_exit(void* context) { + NfcApp* nfc = context; + + submenu_reset(nfc->submenu); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_set_atqa.c b/applications/main/nfc_old/scenes/nfc_scene_set_atqa.c new file mode 100644 index 000000000000..4e0e11e7877c --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_set_atqa.c @@ -0,0 +1,44 @@ +#include "../nfc_app_i.h" + +void nfc_scene_set_atqa_byte_input_callback(void* context) { + NfcApp* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); +} + +void nfc_scene_set_atqa_on_enter(void* context) { + NfcApp* nfc = context; + + // Setup view + ByteInput* byte_input = nfc->byte_input; + byte_input_set_header_text(byte_input, "Enter ATQA in hex"); + byte_input_set_result_callback( + byte_input, + nfc_scene_set_atqa_byte_input_callback, + NULL, + nfc, + nfc->dev->dev_data.nfc_data.atqa, + 2); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewByteInput); +} + +bool nfc_scene_set_atqa_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventByteInputDone) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneSetUid); + consumed = true; + } + } + return consumed; +} + +void nfc_scene_set_atqa_on_exit(void* context) { + NfcApp* nfc = context; + + // Clear view + byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0); + byte_input_set_header_text(nfc->byte_input, ""); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_set_sak.c b/applications/main/nfc_old/scenes/nfc_scene_set_sak.c new file mode 100644 index 000000000000..2c4a230cc4f5 --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_set_sak.c @@ -0,0 +1,44 @@ +#include "../nfc_app_i.h" + +void nfc_scene_set_sak_byte_input_callback(void* context) { + NfcApp* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); +} + +void nfc_scene_set_sak_on_enter(void* context) { + NfcApp* nfc = context; + + // Setup view + ByteInput* byte_input = nfc->byte_input; + byte_input_set_header_text(byte_input, "Enter SAK in hex"); + byte_input_set_result_callback( + byte_input, + nfc_scene_set_sak_byte_input_callback, + NULL, + nfc, + &nfc->dev->dev_data.nfc_data.sak, + 1); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewByteInput); +} + +bool nfc_scene_set_sak_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventByteInputDone) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneSetAtqa); + consumed = true; + } + } + return consumed; +} + +void nfc_scene_set_sak_on_exit(void* context) { + NfcApp* nfc = context; + + // Clear view + byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0); + byte_input_set_header_text(nfc->byte_input, ""); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_set_type.c b/applications/main/nfc_old/scenes/nfc_scene_set_type.c new file mode 100644 index 000000000000..9e417939d62f --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_set_type.c @@ -0,0 +1,68 @@ +#include "../nfc_app_i.h" +#include "lib/nfc/helpers/nfc_generators.h" + +enum SubmenuIndex { + SubmenuIndexNFCA4, + SubmenuIndexNFCA7, + SubmenuIndexGeneratorsStart, +}; + +void nfc_scene_set_type_submenu_callback(void* context, uint32_t index) { + NfcApp* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, index); +} + +void nfc_scene_set_type_on_enter(void* context) { + NfcApp* nfc = context; + Submenu* submenu = nfc->submenu; + // Clear device name + nfc_device_set_name(nfc->dev, ""); + furi_string_set(nfc->dev->load_path, ""); + submenu_add_item( + submenu, "NFC-A 7-bytes UID", SubmenuIndexNFCA7, nfc_scene_set_type_submenu_callback, nfc); + submenu_add_item( + submenu, "NFC-A 4-bytes UID", SubmenuIndexNFCA4, nfc_scene_set_type_submenu_callback, nfc); + + // Generators + int i = SubmenuIndexGeneratorsStart; + for(const NfcGenerator* const* generator = nfc_generators; *generator != NULL; + ++generator, ++i) { + submenu_add_item(submenu, (*generator)->name, i, nfc_scene_set_type_submenu_callback, nfc); + } + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); +} + +bool nfc_scene_set_type_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexNFCA7) { + nfc->dev->dev_data.nfc_data.uid_len = 7; + nfc->dev->format = NfcDeviceSaveFormatUid; + scene_manager_next_scene(nfc->scene_manager, NfcSceneSetSak); + consumed = true; + } else if(event.event == SubmenuIndexNFCA4) { + nfc->dev->dev_data.nfc_data.uid_len = 4; + nfc->dev->format = NfcDeviceSaveFormatUid; + scene_manager_next_scene(nfc->scene_manager, NfcSceneSetSak); + consumed = true; + } else { + nfc_device_clear(nfc->dev); + nfc->generator = nfc_generators[event.event - SubmenuIndexGeneratorsStart]; + nfc->generator->generator_func(&nfc->dev->dev_data); + + scene_manager_next_scene(nfc->scene_manager, NfcSceneGenerateInfo); + consumed = true; + } + } + return consumed; +} + +void nfc_scene_set_type_on_exit(void* context) { + NfcApp* nfc = context; + + submenu_reset(nfc->submenu); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_set_uid.c b/applications/main/nfc_old/scenes/nfc_scene_set_uid.c new file mode 100644 index 000000000000..4c2dc7d04931 --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_set_uid.c @@ -0,0 +1,54 @@ +#include "../nfc_app_i.h" + +void nfc_scene_set_uid_byte_input_callback(void* context) { + NfcApp* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); +} + +void nfc_scene_set_uid_on_enter(void* context) { + NfcApp* nfc = context; + + // Setup view + ByteInput* byte_input = nfc->byte_input; + byte_input_set_header_text(byte_input, "Enter UID in hex"); + nfc->dev_edit_data = nfc->dev->dev_data.nfc_data; + byte_input_set_result_callback( + byte_input, + nfc_scene_set_uid_byte_input_callback, + NULL, + nfc, + nfc->dev_edit_data.uid, + nfc->dev_edit_data.uid_len); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewByteInput); +} + +bool nfc_scene_set_uid_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = (NfcApp*)context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventByteInputDone) { + if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSavedMenu)) { + nfc->dev->dev_data.nfc_data = nfc->dev_edit_data; + if(nfc_save_file(nfc)) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess); + consumed = true; + } + } else { + scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); + consumed = true; + } + } + } + + return consumed; +} + +void nfc_scene_set_uid_on_exit(void* context) { + NfcApp* nfc = context; + + // Clear view + byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0); + byte_input_set_header_text(nfc->byte_input, ""); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_start.c b/applications/main/nfc_old/scenes/nfc_scene_start.c new file mode 100644 index 000000000000..d528e2bb6801 --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_start.c @@ -0,0 +1,98 @@ +#include "../nfc_app_i.h" +#include "nfc_worker_i.h" +#include + +enum SubmenuIndex { + SubmenuIndexRead, + SubmenuIndexDetectReader, + SubmenuIndexSaved, + SubmenuIndexExtraAction, + SubmenuIndexAddManually, + SubmenuIndexDebug, +}; + +void nfc_scene_start_submenu_callback(void* context, uint32_t index) { + NfcApp* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, index); +} + +void nfc_scene_start_on_enter(void* context) { + NfcApp* nfc = context; + Submenu* submenu = nfc->submenu; + + submenu_add_item(submenu, "Read", SubmenuIndexRead, nfc_scene_start_submenu_callback, nfc); + submenu_add_item( + submenu, "Detect Reader", SubmenuIndexDetectReader, nfc_scene_start_submenu_callback, nfc); + submenu_add_item(submenu, "Saved", SubmenuIndexSaved, nfc_scene_start_submenu_callback, nfc); + submenu_add_item( + submenu, "Extra Actions", SubmenuIndexExtraAction, nfc_scene_start_submenu_callback, nfc); + submenu_add_item( + submenu, "Add Manually", SubmenuIndexAddManually, nfc_scene_start_submenu_callback, nfc); + + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + submenu_add_item( + submenu, "Debug", SubmenuIndexDebug, nfc_scene_start_submenu_callback, nfc); + } + + submenu_set_selected_item( + submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneStart)); + + nfc_device_clear(nfc->dev); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); +} + +bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexRead) { + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneStart, SubmenuIndexRead); + nfc->dev->dev_data.read_mode = NfcReadModeAuto; + scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); + DOLPHIN_DEED(DolphinDeedNfcRead); + consumed = true; + } else if(event.event == SubmenuIndexDetectReader) { + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneStart, SubmenuIndexDetectReader); + bool sd_exist = storage_sd_status(nfc->dev->storage) == FSE_OK; + if(sd_exist) { + nfc_device_data_clear(&nfc->dev->dev_data); + scene_manager_next_scene(nfc->scene_manager, NfcSceneDetectReader); + DOLPHIN_DEED(DolphinDeedNfcDetectReader); + } else { + scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound); + } + consumed = true; + } else if(event.event == SubmenuIndexSaved) { + // Save the scene state explicitly in each branch, so that + // if the user cancels loading a file, the Saved menu item + // is properly reselected. + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneStart, SubmenuIndexSaved); + scene_manager_next_scene(nfc->scene_manager, NfcSceneFileSelect); + consumed = true; + } else if(event.event == SubmenuIndexExtraAction) { + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneStart, SubmenuIndexExtraAction); + scene_manager_next_scene(nfc->scene_manager, NfcSceneExtraActions); + consumed = true; + } else if(event.event == SubmenuIndexAddManually) { + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneStart, SubmenuIndexAddManually); + scene_manager_next_scene(nfc->scene_manager, NfcSceneSetType); + consumed = true; + } else if(event.event == SubmenuIndexDebug) { + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneStart, SubmenuIndexDebug); + scene_manager_next_scene(nfc->scene_manager, NfcSceneDebug); + consumed = true; + } + } + return consumed; +} + +void nfc_scene_start_on_exit(void* context) { + NfcApp* nfc = context; + + submenu_reset(nfc->submenu); +} diff --git a/applications/main/nfc_old/views/detect_reader.c b/applications/main/nfc_old/views/detect_reader.c new file mode 100644 index 000000000000..e5951beb2674 --- /dev/null +++ b/applications/main/nfc_old/views/detect_reader.c @@ -0,0 +1,190 @@ +#include "detect_reader.h" +#include +#include + +#define DETECT_READER_UID_MAX_LEN (10) + +struct DetectReader { + View* view; + DetectReaderDoneCallback callback; + void* context; +}; + +typedef struct { + uint16_t nonces; + uint16_t nonces_max; + DetectReaderState state; + FuriString* uid_str; +} DetectReaderViewModel; + +static void detect_reader_draw_callback(Canvas* canvas, void* model) { + DetectReaderViewModel* m = model; + char text[32] = {}; + + // Draw header and icon + canvas_draw_icon(canvas, 0, 16, &I_Modern_reader_18x34); + if(m->state == DetectReaderStateStart) { + snprintf(text, sizeof(text), "Touch the reader"); + canvas_draw_icon(canvas, 21, 13, &I_Move_flipper_26x39); + if(furi_string_size(m->uid_str)) { + elements_multiline_text_aligned( + canvas, 64, 64, AlignCenter, AlignBottom, furi_string_get_cstr(m->uid_str)); + } + } else if(m->state == DetectReaderStateReaderDetected) { + snprintf(text, sizeof(text), "Move the Flipper away"); + canvas_draw_icon(canvas, 24, 25, &I_Release_arrow_18x15); + } else if(m->state == DetectReaderStateReaderLost) { + snprintf(text, sizeof(text), "Touch the reader again"); + canvas_draw_icon(canvas, 21, 13, &I_Move_flipper_26x39); + } + + canvas_draw_str_aligned(canvas, 64, 0, AlignCenter, AlignTop, text); + + // Draw collected nonces + if(m->state == DetectReaderStateStart) { + canvas_set_font(canvas, FontPrimary); + canvas_draw_str_aligned(canvas, 51, 22, AlignLeft, AlignTop, "Emulating..."); + canvas_set_font(canvas, FontSecondary); + canvas_draw_str_aligned(canvas, 51, 35, AlignLeft, AlignTop, "MIFARE MFkey32"); + } else { + if(m->state == DetectReaderStateDone) { + canvas_set_font(canvas, FontPrimary); + canvas_draw_str_aligned(canvas, 51, 22, AlignLeft, AlignTop, "Completed!"); + } else { + canvas_set_font(canvas, FontPrimary); + canvas_draw_str_aligned(canvas, 51, 22, AlignLeft, AlignTop, "Collecting..."); + } + canvas_set_font(canvas, FontSecondary); + snprintf(text, sizeof(text), "Nonce pairs: %d/%d", m->nonces, m->nonces_max); + canvas_draw_str_aligned(canvas, 51, 35, AlignLeft, AlignTop, text); + } + // Draw button + if(m->nonces > 0) { + elements_button_center(canvas, "Done"); + } +} + +static bool detect_reader_input_callback(InputEvent* event, void* context) { + DetectReader* detect_reader = context; + furi_assert(detect_reader->callback); + bool consumed = false; + + uint8_t nonces = 0; + with_view_model( + detect_reader->view, DetectReaderViewModel * model, { nonces = model->nonces; }, false); + + if(event->type == InputTypeShort) { + if(event->key == InputKeyOk) { + if(nonces > 0) { + detect_reader->callback(detect_reader->context); + consumed = true; + } + } + } + + return consumed; +} + +DetectReader* detect_reader_alloc() { + DetectReader* detect_reader = malloc(sizeof(DetectReader)); + detect_reader->view = view_alloc(); + view_allocate_model(detect_reader->view, ViewModelTypeLocking, sizeof(DetectReaderViewModel)); + view_set_draw_callback(detect_reader->view, detect_reader_draw_callback); + view_set_input_callback(detect_reader->view, detect_reader_input_callback); + view_set_context(detect_reader->view, detect_reader); + + with_view_model( + detect_reader->view, + DetectReaderViewModel * model, + { model->uid_str = furi_string_alloc(); }, + false); + + return detect_reader; +} + +void detect_reader_free(DetectReader* detect_reader) { + furi_assert(detect_reader); + + with_view_model( + detect_reader->view, + DetectReaderViewModel * model, + { furi_string_free(model->uid_str); }, + false); + + view_free(detect_reader->view); + free(detect_reader); +} + +void detect_reader_reset(DetectReader* detect_reader) { + furi_assert(detect_reader); + + with_view_model( + detect_reader->view, + DetectReaderViewModel * model, + { + model->nonces = 0; + model->nonces_max = 0; + model->state = DetectReaderStateStart; + furi_string_reset(model->uid_str); + }, + false); +} + +View* detect_reader_get_view(DetectReader* detect_reader) { + furi_assert(detect_reader); + + return detect_reader->view; +} + +void detect_reader_set_callback( + DetectReader* detect_reader, + DetectReaderDoneCallback callback, + void* context) { + furi_assert(detect_reader); + furi_assert(callback); + + detect_reader->callback = callback; + detect_reader->context = context; +} + +void detect_reader_set_nonces_max(DetectReader* detect_reader, uint16_t nonces_max) { + furi_assert(detect_reader); + + with_view_model( + detect_reader->view, + DetectReaderViewModel * model, + { model->nonces_max = nonces_max; }, + false); +} + +void detect_reader_set_nonces_collected(DetectReader* detect_reader, uint16_t nonces_collected) { + furi_assert(detect_reader); + + with_view_model( + detect_reader->view, + DetectReaderViewModel * model, + { model->nonces = nonces_collected; }, + false); +} + +void detect_reader_set_state(DetectReader* detect_reader, DetectReaderState state) { + furi_assert(detect_reader); + with_view_model( + detect_reader->view, DetectReaderViewModel * model, { model->state = state; }, true); +} + +void detect_reader_set_uid(DetectReader* detect_reader, uint8_t* uid, uint8_t uid_len) { + furi_assert(detect_reader); + furi_assert(uid); + furi_assert(uid_len < DETECT_READER_UID_MAX_LEN); + with_view_model( + detect_reader->view, + DetectReaderViewModel * model, + { + furi_string_set_str(model->uid_str, "UID:"); + for(size_t i = 0; i < uid_len; i++) { + furi_string_cat_printf(model->uid_str, " %02X", uid[i]); + } + }, + true); +} diff --git a/applications/main/nfc_old/views/detect_reader.h b/applications/main/nfc_old/views/detect_reader.h new file mode 100644 index 000000000000..6481216b4cf4 --- /dev/null +++ b/applications/main/nfc_old/views/detect_reader.h @@ -0,0 +1,36 @@ +#pragma once +#include +#include +#include + +typedef struct DetectReader DetectReader; + +typedef enum { + DetectReaderStateStart, + DetectReaderStateReaderDetected, + DetectReaderStateReaderLost, + DetectReaderStateDone, +} DetectReaderState; + +typedef void (*DetectReaderDoneCallback)(void* context); + +DetectReader* detect_reader_alloc(); + +void detect_reader_free(DetectReader* detect_reader); + +void detect_reader_reset(DetectReader* detect_reader); + +View* detect_reader_get_view(DetectReader* detect_reader); + +void detect_reader_set_callback( + DetectReader* detect_reader, + DetectReaderDoneCallback callback, + void* context); + +void detect_reader_set_nonces_max(DetectReader* detect_reader, uint16_t nonces_max); + +void detect_reader_set_nonces_collected(DetectReader* detect_reader, uint16_t nonces_collected); + +void detect_reader_set_state(DetectReader* detect_reader, DetectReaderState state); + +void detect_reader_set_uid(DetectReader* detect_reader, uint8_t* uid, uint8_t uid_len); diff --git a/applications/main/nfc_old/views/dict_attack.c b/applications/main/nfc_old/views/dict_attack.c new file mode 100644 index 000000000000..8f4bd063e8b8 --- /dev/null +++ b/applications/main/nfc_old/views/dict_attack.c @@ -0,0 +1,289 @@ +#include "dict_attack.h" + +#include + +typedef enum { + DictAttackStateRead, + DictAttackStateCardRemoved, +} DictAttackState; + +struct DictAttack { + View* view; + DictAttackCallback callback; + void* context; + bool card_present; +}; + +typedef struct { + DictAttackState state; + MfClassicType type; + FuriString* header; + uint8_t sectors_total; + uint8_t sectors_read; + uint8_t sector_current; + uint8_t keys_total; + uint8_t keys_found; + uint16_t dict_keys_total; + uint16_t dict_keys_current; + bool is_key_attack; + uint8_t key_attack_current_sector; +} DictAttackViewModel; + +static void dict_attack_draw_callback(Canvas* canvas, void* model) { + DictAttackViewModel* m = model; + if(m->state == DictAttackStateCardRemoved) { + canvas_set_font(canvas, FontPrimary); + canvas_draw_str_aligned(canvas, 64, 4, AlignCenter, AlignTop, "Lost the tag!"); + canvas_set_font(canvas, FontSecondary); + elements_multiline_text_aligned( + canvas, 64, 23, AlignCenter, AlignTop, "Make sure the tag is\npositioned correctly."); + } else if(m->state == DictAttackStateRead) { + char draw_str[32] = {}; + canvas_set_font(canvas, FontSecondary); + canvas_draw_str_aligned( + canvas, 64, 0, AlignCenter, AlignTop, furi_string_get_cstr(m->header)); + if(m->is_key_attack) { + snprintf( + draw_str, + sizeof(draw_str), + "Reuse key check for sector: %d", + m->key_attack_current_sector); + } else { + snprintf(draw_str, sizeof(draw_str), "Unlocking sector: %d", m->sector_current); + } + canvas_draw_str_aligned(canvas, 0, 10, AlignLeft, AlignTop, draw_str); + float dict_progress = m->dict_keys_total == 0 ? + 0 : + (float)(m->dict_keys_current) / (float)(m->dict_keys_total); + float progress = m->sectors_total == 0 ? 0 : + ((float)(m->sector_current) + dict_progress) / + (float)(m->sectors_total); + if(progress > 1.0) { + progress = 1.0; + } + if(m->dict_keys_current == 0) { + // Cause when people see 0 they think it's broken + snprintf(draw_str, sizeof(draw_str), "%d/%d", 1, m->dict_keys_total); + } else { + snprintf( + draw_str, sizeof(draw_str), "%d/%d", m->dict_keys_current, m->dict_keys_total); + } + elements_progress_bar_with_text(canvas, 0, 20, 128, dict_progress, draw_str); + canvas_set_font(canvas, FontSecondary); + snprintf(draw_str, sizeof(draw_str), "Keys found: %d/%d", m->keys_found, m->keys_total); + canvas_draw_str_aligned(canvas, 0, 33, AlignLeft, AlignTop, draw_str); + snprintf( + draw_str, sizeof(draw_str), "Sectors Read: %d/%d", m->sectors_read, m->sectors_total); + canvas_draw_str_aligned(canvas, 0, 43, AlignLeft, AlignTop, draw_str); + } + elements_button_center(canvas, "Skip"); +} + +static bool dict_attack_input_callback(InputEvent* event, void* context) { + DictAttack* dict_attack = context; + bool consumed = false; + if(event->type == InputTypeShort && event->key == InputKeyOk) { + if(dict_attack->callback) { + dict_attack->callback(dict_attack->context); + } + consumed = true; + } + return consumed; +} + +DictAttack* dict_attack_alloc() { + DictAttack* dict_attack = malloc(sizeof(DictAttack)); + dict_attack->view = view_alloc(); + view_allocate_model(dict_attack->view, ViewModelTypeLocking, sizeof(DictAttackViewModel)); + view_set_draw_callback(dict_attack->view, dict_attack_draw_callback); + view_set_input_callback(dict_attack->view, dict_attack_input_callback); + view_set_context(dict_attack->view, dict_attack); + with_view_model( + dict_attack->view, + DictAttackViewModel * model, + { model->header = furi_string_alloc(); }, + false); + return dict_attack; +} + +void dict_attack_free(DictAttack* dict_attack) { + furi_assert(dict_attack); + with_view_model( + dict_attack->view, + DictAttackViewModel * model, + { furi_string_free(model->header); }, + false); + view_free(dict_attack->view); + free(dict_attack); +} + +void dict_attack_reset(DictAttack* dict_attack) { + furi_assert(dict_attack); + with_view_model( + dict_attack->view, + DictAttackViewModel * model, + { + model->state = DictAttackStateRead; + model->type = MfClassicType1k; + model->sectors_total = 0; + model->sectors_read = 0; + model->sector_current = 0; + model->keys_total = 0; + model->keys_found = 0; + model->dict_keys_total = 0; + model->dict_keys_current = 0; + model->is_key_attack = false; + furi_string_reset(model->header); + }, + false); +} + +View* dict_attack_get_view(DictAttack* dict_attack) { + furi_assert(dict_attack); + return dict_attack->view; +} + +void dict_attack_set_callback(DictAttack* dict_attack, DictAttackCallback callback, void* context) { + furi_assert(dict_attack); + furi_assert(callback); + dict_attack->callback = callback; + dict_attack->context = context; +} + +void dict_attack_set_header(DictAttack* dict_attack, const char* header) { + furi_assert(dict_attack); + furi_assert(header); + + with_view_model( + dict_attack->view, + DictAttackViewModel * model, + { furi_string_set(model->header, header); }, + true); +} + +void dict_attack_set_card_detected(DictAttack* dict_attack, MfClassicType type) { + furi_assert(dict_attack); + dict_attack->card_present = true; + with_view_model( + dict_attack->view, + DictAttackViewModel * model, + { + model->state = DictAttackStateRead; + model->sectors_total = mf_classic_get_total_sectors_num(type); + model->keys_total = model->sectors_total * 2; + }, + true); +} + +void dict_attack_set_card_removed(DictAttack* dict_attack) { + furi_assert(dict_attack); + dict_attack->card_present = false; + with_view_model( + dict_attack->view, + DictAttackViewModel * model, + { model->state = DictAttackStateCardRemoved; }, + true); +} + +bool dict_attack_get_card_state(DictAttack* dict_attack) { + furi_assert(dict_attack); + return dict_attack->card_present; +} + +void dict_attack_set_sector_read(DictAttack* dict_attack, uint8_t sec_read) { + furi_assert(dict_attack); + with_view_model( + dict_attack->view, DictAttackViewModel * model, { model->sectors_read = sec_read; }, true); +} + +void dict_attack_set_keys_found(DictAttack* dict_attack, uint8_t keys_found) { + furi_assert(dict_attack); + with_view_model( + dict_attack->view, DictAttackViewModel * model, { model->keys_found = keys_found; }, true); +} + +void dict_attack_set_current_sector(DictAttack* dict_attack, uint8_t curr_sec) { + furi_assert(dict_attack); + with_view_model( + dict_attack->view, + DictAttackViewModel * model, + { + model->sector_current = curr_sec; + model->dict_keys_current = 0; + }, + true); +} + +void dict_attack_inc_current_sector(DictAttack* dict_attack) { + furi_assert(dict_attack); + with_view_model( + dict_attack->view, + DictAttackViewModel * model, + { + if(model->sector_current < model->sectors_total) { + model->sector_current++; + model->dict_keys_current = 0; + } + }, + true); +} + +void dict_attack_inc_keys_found(DictAttack* dict_attack) { + furi_assert(dict_attack); + with_view_model( + dict_attack->view, + DictAttackViewModel * model, + { + if(model->keys_found < model->keys_total) { + model->keys_found++; + } + }, + true); +} + +void dict_attack_set_total_dict_keys(DictAttack* dict_attack, uint16_t dict_keys_total) { + furi_assert(dict_attack); + with_view_model( + dict_attack->view, + DictAttackViewModel * model, + { model->dict_keys_total = dict_keys_total; }, + true); +} + +void dict_attack_inc_current_dict_key(DictAttack* dict_attack, uint16_t keys_tried) { + furi_assert(dict_attack); + with_view_model( + dict_attack->view, + DictAttackViewModel * model, + { + if(model->dict_keys_current + keys_tried < model->dict_keys_total) { + model->dict_keys_current += keys_tried; + } + }, + true); +} + +void dict_attack_set_key_attack(DictAttack* dict_attack, bool is_key_attack, uint8_t sector) { + furi_assert(dict_attack); + with_view_model( + dict_attack->view, + DictAttackViewModel * model, + { + model->is_key_attack = is_key_attack; + model->key_attack_current_sector = sector; + }, + true); +} + +void dict_attack_inc_key_attack_current_sector(DictAttack* dict_attack) { + furi_assert(dict_attack); + with_view_model( + dict_attack->view, + DictAttackViewModel * model, + { + if(model->key_attack_current_sector < model->sectors_total) { + model->key_attack_current_sector++; + } + }, + true); +} diff --git a/applications/main/nfc_old/views/dict_attack.h b/applications/main/nfc_old/views/dict_attack.h new file mode 100644 index 000000000000..73b98a1b827b --- /dev/null +++ b/applications/main/nfc_old/views/dict_attack.h @@ -0,0 +1,46 @@ +#pragma once +#include +#include +#include + +#include + +typedef struct DictAttack DictAttack; + +typedef void (*DictAttackCallback)(void* context); + +DictAttack* dict_attack_alloc(); + +void dict_attack_free(DictAttack* dict_attack); + +void dict_attack_reset(DictAttack* dict_attack); + +View* dict_attack_get_view(DictAttack* dict_attack); + +void dict_attack_set_callback(DictAttack* dict_attack, DictAttackCallback callback, void* context); + +void dict_attack_set_header(DictAttack* dict_attack, const char* header); + +void dict_attack_set_card_detected(DictAttack* dict_attack, MfClassicType type); + +void dict_attack_set_card_removed(DictAttack* dict_attack); + +bool dict_attack_get_card_state(DictAttack* dict_attack); + +void dict_attack_set_sector_read(DictAttack* dict_attack, uint8_t sec_read); + +void dict_attack_set_keys_found(DictAttack* dict_attack, uint8_t keys_found); + +void dict_attack_set_current_sector(DictAttack* dict_attack, uint8_t curr_sec); + +void dict_attack_inc_current_sector(DictAttack* dict_attack); + +void dict_attack_inc_keys_found(DictAttack* dict_attack); + +void dict_attack_set_total_dict_keys(DictAttack* dict_attack, uint16_t dict_keys_total); + +void dict_attack_inc_current_dict_key(DictAttack* dict_attack, uint16_t keys_tried); + +void dict_attack_set_key_attack(DictAttack* dict_attack, bool is_key_attack, uint8_t sector); + +void dict_attack_inc_key_attack_current_sector(DictAttack* dict_attack); \ No newline at end of file From 2e58cd265727dfb68331896f8dd6c74565092a87 Mon Sep 17 00:00:00 2001 From: gornekich Date: Fri, 7 Apr 2023 15:09:02 +0400 Subject: [PATCH 019/149] nfc app: start reworking read --- applications/main/nfc/nfc_app.c | 33 +++++++--------- .../main/nfc/scenes/nfc_scene_config.h | 1 + .../main/nfc/scenes/nfc_scene_extra_actions.c | 6 +-- .../nfc/scenes/nfc_scene_not_implemented.c | 38 +++++++++++++++++++ applications/main/nfc/scenes/nfc_scene_read.c | 4 +- .../nfc/scenes/nfc_scene_read_card_type.c | 30 +++++++-------- .../main/nfc/scenes/nfc_scene_start.c | 15 ++++---- firmware/targets/f7/api_symbols.csv | 3 +- firmware/targets/f7/furi_hal/f_hal_nfc.c | 17 +++++++++ firmware/targets/furi_hal_include/f_hal_nfc.h | 2 + 10 files changed, 101 insertions(+), 48 deletions(-) create mode 100644 applications/main/nfc/scenes/nfc_scene_not_implemented.c diff --git a/applications/main/nfc/nfc_app.c b/applications/main/nfc/nfc_app.c index 5884f8852d03..3ba6c3d5cb46 100644 --- a/applications/main/nfc/nfc_app.c +++ b/applications/main/nfc/nfc_app.c @@ -1,5 +1,5 @@ #include "nfc_app_i.h" -#include +#include #include bool nfc_custom_event_callback(void* context, uint32_t event) { @@ -36,7 +36,6 @@ static void nfc_rpc_command_callback(RpcAppSystemEvent event, void* context) { NfcApp* nfc_app_alloc() { NfcApp* nfc = malloc(sizeof(NfcApp)); - nfc->worker = nfc_worker_alloc(); nfc->view_dispatcher = view_dispatcher_alloc(); nfc->scene_manager = scene_manager_alloc(&nfc_scene_handlers, nfc); view_dispatcher_enable_queue(nfc->view_dispatcher); @@ -110,17 +109,17 @@ NfcApp* nfc_app_alloc() { void nfc_app_free(NfcApp* nfc) { furi_assert(nfc); - if(nfc->rpc_state == NfcRpcStateEmulating) { - // Stop worker - nfc_worker_stop(nfc->worker); - } else if(nfc->rpc_state == NfcRpcStateEmulated) { - // Stop worker - nfc_worker_stop(nfc->worker); - // Save data in shadow file - if(furi_string_size(nfc->dev->load_path)) { - nfc_device_save_shadow(nfc->dev, furi_string_get_cstr(nfc->dev->load_path)); - } - } + // if(nfc->rpc_state == NfcRpcStateEmulating) { + // // Stop worker + // nfc_worker_stop(nfc->worker); + // } else if(nfc->rpc_state == NfcRpcStateEmulated) { + // // Stop worker + // nfc_worker_stop(nfc->worker); + // // Save data in shadow file + // if(furi_string_size(nfc->dev->load_path)) { + // nfc_device_save_shadow(nfc->dev, furi_string_get_cstr(nfc->dev->load_path)); + // } + // } if(nfc->rpc_ctx) { rpc_system_app_send_exited(nfc->rpc_ctx); rpc_system_app_set_callback(nfc->rpc_ctx, NULL, NULL); @@ -171,10 +170,6 @@ void nfc_app_free(NfcApp* nfc) { view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewDetectReader); detect_reader_free(nfc->detect_reader); - // Worker - nfc_worker_stop(nfc->worker); - nfc_worker_free(nfc->worker); - // View Dispatcher view_dispatcher_free(nfc->view_dispatcher); @@ -243,7 +238,7 @@ void nfc_show_loading_popup(void* context, bool show) { } static bool nfc_is_hal_ready() { - if(!furi_hal_nfc_is_init()) { + if(f_hal_nfc_is_hal_ready() != FHalNfcErrorNone) { // No connection to the chip, show an error screen DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS); DialogMessage* message = dialog_message_alloc(); @@ -305,7 +300,7 @@ int32_t nfc_app(void* p) { } else { view_dispatcher_attach_to_gui( nfc->view_dispatcher, nfc->gui, ViewDispatcherTypeFullscreen); - scene_manager_next_scene(nfc->scene_manager, NfcSceneStart); + scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardType); } view_dispatcher_run(nfc->view_dispatcher); diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index a9da07dfda00..a34b670d896d 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -63,3 +63,4 @@ ADD_SCENE(nfc, mfkey_nonces_info, MfkeyNoncesInfo) ADD_SCENE(nfc, mfkey_complete, MfkeyComplete) ADD_SCENE(nfc, nfc_data_info, NfcDataInfo) ADD_SCENE(nfc, read_card_type, ReadCardType) +ADD_SCENE(nfc, not_implemented, NotImplemented) diff --git a/applications/main/nfc/scenes/nfc_scene_extra_actions.c b/applications/main/nfc/scenes/nfc_scene_extra_actions.c index 31106c76a4f3..9282a34c96a5 100644 --- a/applications/main/nfc/scenes/nfc_scene_extra_actions.c +++ b/applications/main/nfc/scenes/nfc_scene_extra_actions.c @@ -46,13 +46,13 @@ bool nfc_scene_extra_actions_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubmenuIndexMfClassicKeys) { if(mf_classic_dict_check_presence(MfClassicDictTypeSystem)) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicKeys); + scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); } else { - scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound); + scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); } consumed = true; } else if(event.event == SubmenuIndexMfUltralightUnlock) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockMenu); + scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); consumed = true; } else if(event.event == SubmenuIndexReadCardType) { scene_manager_set_scene_state(nfc->scene_manager, NfcSceneReadCardType, 0); diff --git a/applications/main/nfc/scenes/nfc_scene_not_implemented.c b/applications/main/nfc/scenes/nfc_scene_not_implemented.c new file mode 100644 index 000000000000..35ae3b8149e6 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_not_implemented.c @@ -0,0 +1,38 @@ +#include "../nfc_app_i.h" + +void nfc_scene_not_implemented_popup_callback(void* context) { + NfcApp* nfc = context; + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); +} + +void nfc_scene_not_implemented_on_enter(void* context) { + NfcApp* nfc = context; + + // Setup view + Popup* popup = nfc->popup; + popup_set_header(popup, "Not implemented!", 64, 32, AlignCenter, AlignCenter); + popup_set_timeout(popup, 1500); + popup_set_context(popup, nfc); + popup_set_callback(popup, nfc_scene_not_implemented_popup_callback); + popup_enable_timeout(popup); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); +} + +bool nfc_scene_not_implemented_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventViewExit) { + consumed = scene_manager_previous_scene(nfc->scene_manager); + } + } + return consumed; +} + +void nfc_scene_not_implemented_on_exit(void* context) { + NfcApp* nfc = context; + + // Clear view + popup_reset(nfc->popup); +} diff --git a/applications/main/nfc/scenes/nfc_scene_read.c b/applications/main/nfc/scenes/nfc_scene_read.c index ddb18706cbbc..4ef2c416d2a4 100644 --- a/applications/main/nfc/scenes/nfc_scene_read.c +++ b/applications/main/nfc/scenes/nfc_scene_read.c @@ -44,9 +44,7 @@ void nfc_scene_read_on_enter(void* context) { // Setup view nfc_scene_read_set_state(nfc, NfcSceneReadStateDetecting); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); - // Start worker - nfc_worker_start( - nfc->worker, NfcWorkerStateRead, &nfc->dev->dev_data, nfc_scene_read_worker_callback, nfc); + nfc_blink_read_start(nfc); } diff --git a/applications/main/nfc/scenes/nfc_scene_read_card_type.c b/applications/main/nfc/scenes/nfc_scene_read_card_type.c index d763f2f723df..e9fad6d0c286 100644 --- a/applications/main/nfc/scenes/nfc_scene_read_card_type.c +++ b/applications/main/nfc/scenes/nfc_scene_read_card_type.c @@ -2,11 +2,11 @@ #include "nfc_worker_i.h" enum SubmenuIndex { + SubmenuIndexReadNFCA, + SubmenuIndexReadMfUltralight, SubmenuIndexReadMifareClassic, SubmenuIndexReadMifareDesfire, - SubmenuIndexReadMfUltralight, SubmenuIndexReadEMV, - SubmenuIndexReadNFCA, }; void nfc_scene_read_card_type_submenu_callback(void* context, uint32_t index) { @@ -21,32 +21,32 @@ void nfc_scene_read_card_type_on_enter(void* context) { submenu_add_item( submenu, - "Read Mifare Classic", - SubmenuIndexReadMifareClassic, + "Read NFC-A data", + SubmenuIndexReadNFCA, nfc_scene_read_card_type_submenu_callback, nfc); submenu_add_item( submenu, - "Read Mifare DESFire", - SubmenuIndexReadMifareDesfire, + "Read NTAG/Ultralight", + SubmenuIndexReadMfUltralight, nfc_scene_read_card_type_submenu_callback, nfc); submenu_add_item( submenu, - "Read NTAG/Ultralight", - SubmenuIndexReadMfUltralight, + "Read Mifare Classic", + SubmenuIndexReadMifareClassic, nfc_scene_read_card_type_submenu_callback, nfc); submenu_add_item( submenu, - "Read EMV card", - SubmenuIndexReadEMV, + "Read Mifare DESFire", + SubmenuIndexReadMifareDesfire, nfc_scene_read_card_type_submenu_callback, nfc); submenu_add_item( submenu, - "Read NFC-A data", - SubmenuIndexReadNFCA, + "Read EMV card", + SubmenuIndexReadEMV, nfc_scene_read_card_type_submenu_callback, nfc); uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadCardType); @@ -62,12 +62,12 @@ bool nfc_scene_read_card_type_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubmenuIndexReadMifareClassic) { nfc->dev->dev_data.read_mode = NfcReadModeMfClassic; - scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); + scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); consumed = true; } if(event.event == SubmenuIndexReadMifareDesfire) { nfc->dev->dev_data.read_mode = NfcReadModeMfDesfire; - scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); + scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); consumed = true; } if(event.event == SubmenuIndexReadMfUltralight) { @@ -77,7 +77,7 @@ bool nfc_scene_read_card_type_on_event(void* context, SceneManagerEvent event) { } if(event.event == SubmenuIndexReadEMV) { nfc->dev->dev_data.read_mode = NfcReadModeEMV; - scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); + scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); consumed = true; } if(event.event == SubmenuIndexReadNFCA) { diff --git a/applications/main/nfc/scenes/nfc_scene_start.c b/applications/main/nfc/scenes/nfc_scene_start.c index d528e2bb6801..393cdeb843f4 100644 --- a/applications/main/nfc/scenes/nfc_scene_start.c +++ b/applications/main/nfc/scenes/nfc_scene_start.c @@ -50,7 +50,7 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) { if(event.event == SubmenuIndexRead) { scene_manager_set_scene_state(nfc->scene_manager, NfcSceneStart, SubmenuIndexRead); nfc->dev->dev_data.read_mode = NfcReadModeAuto; - scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); + scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); DOLPHIN_DEED(DolphinDeedNfcRead); consumed = true; } else if(event.event == SubmenuIndexDetectReader) { @@ -59,7 +59,7 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) { bool sd_exist = storage_sd_status(nfc->dev->storage) == FSE_OK; if(sd_exist) { nfc_device_data_clear(&nfc->dev->dev_data); - scene_manager_next_scene(nfc->scene_manager, NfcSceneDetectReader); + scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); DOLPHIN_DEED(DolphinDeedNfcDetectReader); } else { scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound); @@ -70,7 +70,7 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) { // if the user cancels loading a file, the Saved menu item // is properly reselected. scene_manager_set_scene_state(nfc->scene_manager, NfcSceneStart, SubmenuIndexSaved); - scene_manager_next_scene(nfc->scene_manager, NfcSceneFileSelect); + scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); consumed = true; } else if(event.event == SubmenuIndexExtraAction) { scene_manager_set_scene_state( @@ -79,12 +79,13 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) { consumed = true; } else if(event.event == SubmenuIndexAddManually) { scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneStart, SubmenuIndexAddManually); - scene_manager_next_scene(nfc->scene_manager, NfcSceneSetType); + nfc->scene_manager, NfcSceneStart, NfcSceneNotImplemented); + scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); consumed = true; } else if(event.event == SubmenuIndexDebug) { - scene_manager_set_scene_state(nfc->scene_manager, NfcSceneStart, SubmenuIndexDebug); - scene_manager_next_scene(nfc->scene_manager, NfcSceneDebug); + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneStart, NfcSceneNotImplemented); + scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); consumed = true; } } diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 7806084fee36..169d08640afa 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,+,20.3,, +Version,+,20.4,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -817,6 +817,7 @@ Function,-,expm1f,float,float Function,-,expm1l,long double,long double Function,-,f_hal_nfc_abort,FHalNfcError, Function,-,f_hal_nfc_init,FHalNfcError, +Function,-,f_hal_nfc_is_hal_ready,FHalNfcError, Function,-,f_hal_nfc_listen_start,FHalNfcError, Function,-,f_hal_nfc_listener_disable_auto_col_res,FHalNfcError, Function,-,f_hal_nfc_listener_sleep,FHalNfcError, diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc.c b/firmware/targets/f7/furi_hal/f_hal_nfc.c index c2122f9e961e..54dee2207887 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfc.c +++ b/firmware/targets/f7/furi_hal/f_hal_nfc.c @@ -34,6 +34,23 @@ static FHalNfcError f_hal_nfc_turn_on_osc(FuriHalSpiBusHandle* handle) { return error; } +FHalNfcError f_hal_nfc_is_hal_ready() { + FHalNfcError error = FHalNfcErrorNone; + FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; + furi_hal_spi_acquire(handle); + + uint8_t chip_id = 0; + st25r3916_read_reg(handle, ST25R3916_REG_IC_IDENTITY, &chip_id); + if((chip_id & ST25R3916_REG_IC_IDENTITY_ic_type_mask) != + ST25R3916_REG_IC_IDENTITY_ic_type_st25r3916) { + FURI_LOG_E(TAG, "Wrong chip id"); + error = FHalNfcErrorCommunication; + } + furi_hal_spi_release(handle); + + return error; +} + FHalNfcError f_hal_nfc_init() { FHalNfcError error = FHalNfcErrorNone; f_hal_nfc_event_init(); diff --git a/firmware/targets/furi_hal_include/f_hal_nfc.h b/firmware/targets/furi_hal_include/f_hal_nfc.h index 3adf78ac266b..146c98ef9904 100644 --- a/firmware/targets/furi_hal_include/f_hal_nfc.h +++ b/firmware/targets/furi_hal_include/f_hal_nfc.h @@ -59,6 +59,8 @@ typedef enum { */ FHalNfcError f_hal_nfc_init(); +FHalNfcError f_hal_nfc_is_hal_ready(); + /** * @brief Start Nfc hardware low power mode * From 65b8cab7c601f63bc1abc21285eaf147e65e31f2 Mon Sep 17 00:00:00 2001 From: gornekich Date: Fri, 7 Apr 2023 20:09:07 +0400 Subject: [PATCH 020/149] nfc: new nfca read scene --- applications/main/nfc/nfc_app_i.h | 4 ++ .../main/nfc/scenes/nfc_scene_config.h | 2 + .../main/nfc/scenes/nfc_scene_nfca_read.c | 51 +++++++++++++++++++ .../nfc/scenes/nfc_scene_nfca_read_success.c | 2 +- applications/main/nfc/scenes/nfc_scene_read.c | 20 ++++---- lib/nfc/nfc.c | 10 ++-- lib/nfc/nfc.h | 4 +- lib/nfc/nfc_device.h | 1 + lib/nfc/protocols/nfca_poller.c | 14 ++++- lib/nfc/protocols/nfca_poller.h | 2 + 10 files changed, 94 insertions(+), 16 deletions(-) create mode 100644 applications/main/nfc/scenes/nfc_scene_nfca_read.c diff --git a/applications/main/nfc/nfc_app_i.h b/applications/main/nfc/nfc_app_i.h index c361a5fc81f1..a08e9897c9e5 100644 --- a/applications/main/nfc/nfc_app_i.h +++ b/applications/main/nfc/nfc_app_i.h @@ -41,6 +41,8 @@ #include +#include + ARRAY_DEF(MfClassicUserKeys, char*, M_PTR_OPLIST); #define NFC_TEXT_STORE_SIZE 128 @@ -82,6 +84,8 @@ struct NfcApp { DetectReader* detect_reader; const NfcGenerator* generator; + + NfcaPoller* nfca_poller; }; typedef enum { diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index a34b670d896d..c6badf384547 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -63,4 +63,6 @@ ADD_SCENE(nfc, mfkey_nonces_info, MfkeyNoncesInfo) ADD_SCENE(nfc, mfkey_complete, MfkeyComplete) ADD_SCENE(nfc, nfc_data_info, NfcDataInfo) ADD_SCENE(nfc, read_card_type, ReadCardType) + ADD_SCENE(nfc, not_implemented, NotImplemented) +ADD_SCENE(nfc, read_nfca, ReadNfca) diff --git a/applications/main/nfc/scenes/nfc_scene_nfca_read.c b/applications/main/nfc/scenes/nfc_scene_nfca_read.c new file mode 100644 index 000000000000..5b14a44e406c --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_nfca_read.c @@ -0,0 +1,51 @@ +#include "../nfc_app_i.h" +#include + +void nfc_scene_nfca_read_worker_callback(NfcaPollerEvent event, void* context) { + NfcApp* nfc = context; + + if(event.type == NfcaPollerEventTypeActivated) { + nfca_poller_stop(nfc->nfca_poller); + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcWorkerEventReadUidNfcA); + } +} + +void nfc_scene_nfca_read_on_enter(void* context) { + NfcApp* nfc = context; + + // Setup view + nfc_scene_nfca_read_set_state(nfc, NfcSceneReadStateDetecting); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); + + nfc->nfca_poller = nfca_poller_alloc(); + nfca_poller_start(nfc->nfca_poller, nfc_scene_nfca_read_worker_callback, nfc); + + nfc_blink_read_start(nfc); +} + +bool nfc_scene_nfca_read_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcWorkerEventReadUidNfcA) { + notification_message(nfc->notifications, &sequence_success); + nfca_poller_get_data(nfc->nfca_poller, &nfc->nfca_data); + nfca_poller_free(nfc->nfca_poller); + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcaReadSuccess); + DOLPHIN_DEED(DolphinDeedNfcReadSuccess); + consumed = true; + } + } + return consumed; +} + +void nfc_scene_nfca_read_on_exit(void* context) { + NfcApp* nfc = context; + + // Clear view + popup_reset(nfc->popup); + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneRead, NfcSceneReadStateIdle); + + nfc_blink_stop(nfc); +} diff --git a/applications/main/nfc/scenes/nfc_scene_nfca_read_success.c b/applications/main/nfc/scenes/nfc_scene_nfca_read_success.c index 089ee067c11f..d1d399391082 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfca_read_success.c +++ b/applications/main/nfc/scenes/nfc_scene_nfca_read_success.c @@ -16,7 +16,7 @@ void nfc_scene_nfca_read_success_on_enter(void* context) { NfcApp* nfc = context; // Setup view - FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; + NfcaData* data = &nfc->nfca_data; Widget* widget = nfc->widget; FuriString* temp_str; diff --git a/applications/main/nfc/scenes/nfc_scene_read.c b/applications/main/nfc/scenes/nfc_scene_read.c index 4ef2c416d2a4..68e8559ecd14 100644 --- a/applications/main/nfc/scenes/nfc_scene_read.c +++ b/applications/main/nfc/scenes/nfc_scene_read.c @@ -7,16 +7,14 @@ typedef enum { NfcSceneReadStateReading, } NfcSceneReadState; -bool nfc_scene_read_worker_callback(NfcWorkerEvent event, void* context) { +void nfc_scene_read_worker_callback(NfcaPollerEvent event, void* context) { NfcApp* nfc = context; - bool consumed = false; - if(event == NfcWorkerEventReadMfClassicLoadKeyCache) { - consumed = nfc_device_load_key_cache(nfc->dev); - } else { - view_dispatcher_send_custom_event(nfc->view_dispatcher, event); - consumed = true; + + if(event.type == NfcaPollerEventTypeActivated) { + nfca_poller_stop(nfc->nfca_poller); + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcWorkerEventReadUidNfcA); } - return consumed; + } void nfc_scene_read_set_state(NfcApp* nfc, NfcSceneReadState state) { @@ -45,6 +43,8 @@ void nfc_scene_read_on_enter(void* context) { nfc_scene_read_set_state(nfc, NfcSceneReadStateDetecting); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); + nfc->nfca_poller = nfca_poller_alloc(); + nfca_poller_start(nfc->nfca_poller, nfc_scene_read_worker_callback, nfc); nfc_blink_read_start(nfc); } @@ -63,6 +63,8 @@ bool nfc_scene_read_on_event(void* context, SceneManagerEvent event) { consumed = true; } else if(event.event == NfcWorkerEventReadUidNfcA) { notification_message(nfc->notifications, &sequence_success); + nfca_poller_get_data(nfc->nfca_poller, &nfc->nfca_data); + nfca_poller_free(nfc->nfca_poller); scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcaReadSuccess); DOLPHIN_DEED(DolphinDeedNfcReadSuccess); consumed = true; @@ -111,8 +113,6 @@ bool nfc_scene_read_on_event(void* context, SceneManagerEvent event) { void nfc_scene_read_on_exit(void* context) { NfcApp* nfc = context; - // Stop worker - nfc_worker_stop(nfc->worker); // Clear view popup_reset(nfc->popup); scene_manager_set_scene_state(nfc->scene_manager, NfcSceneRead, NfcSceneReadStateIdle); diff --git a/lib/nfc/nfc.c b/lib/nfc/nfc.c index 7d23a7a1b532..afe8b60e1983 100644 --- a/lib/nfc/nfc.c +++ b/lib/nfc/nfc.c @@ -125,7 +125,6 @@ static int32_t nfc_worker_poller(void* context) { while(instance->state == NfcStatePollerReady) { NfcEvent event = {.type = NfcEventTypePollerReady}; instance->callback(event, instance->context); - furi_delay_ms(1); } return 0; @@ -153,7 +152,7 @@ void nfc_free(Nfc* instance) { f_hal_nfc_abort(); furi_thread_join(instance->worker_thread); } else if(instance->state == NfcStatePollerReady) { - nfc_poller_stop(instance); + nfc_poller_abort(instance); } furi_thread_free(instance->worker_thread); f_hal_nfc_low_power_mode_start(); @@ -231,13 +230,18 @@ void nfc_start_worker(Nfc* instance, NfcEventCallback callback, void* context) { instance->comm_state = NfcCommStateIdle; } -void nfc_poller_stop(Nfc* instance) { +void nfc_poller_abort(Nfc* instance) { furi_assert(instance); // TODO add Mutex for nfc state instance->state = NfcStateStopRequested; furi_thread_join(instance->worker_thread); } +void nfc_poller_stop(Nfc* instance) { + furi_assert(instance); + instance->state = NfcStateStopRequested; +} + NfcError nfc_listener_sleep(Nfc* instance) { furi_assert(instance); furi_assert(instance->state == NfcStateListenStarted); diff --git a/lib/nfc/nfc.h b/lib/nfc/nfc.h index f4eb75460a7c..8277bec68944 100644 --- a/lib/nfc/nfc.h +++ b/lib/nfc/nfc.h @@ -86,10 +86,12 @@ void nfc_start_worker(Nfc* instance, NfcEventCallback callback, void* context); NfcError nfc_listener_sleep(Nfc* instance); -void nfc_poller_stop(Nfc* instance); +void nfc_poller_abort(Nfc* instance); // Called from worker thread +void nfc_poller_stop(Nfc* instance); + NfcError nfc_listener_tx(Nfc* instance, uint8_t* tx_data, uint16_t tx_bits); NfcError nfc_trx( diff --git a/lib/nfc/nfc_device.h b/lib/nfc/nfc_device.h index 8b2e6e5ba308..197e864ee96d 100644 --- a/lib/nfc/nfc_device.h +++ b/lib/nfc/nfc_device.h @@ -70,6 +70,7 @@ typedef struct { MfUltralightAuth mf_ul_auth; }; union { + NfcaData nfca_data; EmvData emv_data; MfUltralightData mf_ul_data; MfClassicData mf_classic_data; diff --git a/lib/nfc/protocols/nfca_poller.c b/lib/nfc/protocols/nfca_poller.c index 329c2299f2f6..3006c9598160 100644 --- a/lib/nfc/protocols/nfca_poller.c +++ b/lib/nfc/protocols/nfca_poller.c @@ -143,7 +143,7 @@ void nfca_poller_free(NfcaPoller* instance) { furi_assert(instance); furi_assert(instance->nfc); - nfc_poller_stop(instance->nfc); + nfc_poller_abort(instance->nfc); nfc_free(instance->nfc); free(instance); } @@ -369,7 +369,17 @@ NfcaError nfca_poller_activate(NfcaPoller* instance, NfcaData* nfca_data) { return ret; } +NfcaError nfca_poller_stop(NfcaPoller* instance) { + furi_assert(instance); + furi_assert(instance->nfc); + + nfc_poller_stop(instance->nfc); + + return NfcaErrorNone; +} + typedef struct { + NfcaPoller* instance; FuriThreadId thread_id; NfcaError error; } NfcaPollerContext; @@ -377,6 +387,7 @@ typedef struct { static void nfca_poller_activate_sync_callback(NfcaPollerEvent event, void* context) { FURI_LOG_W(TAG, "nfca_poller_activate_sync_callback: %d event", event.type); NfcaPollerContext* nfca_poller_context = context; + nfca_poller_stop(nfca_poller_context->instance); nfca_poller_context->error = event.data.error; furi_thread_flags_set(nfca_poller_context->thread_id, 1); } @@ -384,6 +395,7 @@ static void nfca_poller_activate_sync_callback(NfcaPollerEvent event, void* cont NfcaError nfca_poller_activate_sync(NfcaPoller* instance, NfcaData* nfca_data) { furi_assert(instance); NfcaPollerContext context = {}; + context.instance = instance; context.thread_id = furi_thread_get_current_id(); nfca_poller_start(instance, nfca_poller_activate_sync_callback, &context); furi_thread_flags_wait(1, FuriFlagWaitAny, FuriWaitForever); diff --git a/lib/nfc/protocols/nfca_poller.h b/lib/nfc/protocols/nfca_poller.h index 07e208179f9e..8248faa4f80b 100644 --- a/lib/nfc/protocols/nfca_poller.h +++ b/lib/nfc/protocols/nfca_poller.h @@ -36,6 +36,8 @@ NfcaError NfcaError nfca_poller_get_data(NfcaPoller* instance, NfcaData* data); +NfcaError nfca_poller_stop(NfcaPoller* instance); + // Syncronous API NfcaError nfca_poller_check_presence(NfcaPoller* instance); From c4f6130796e6d71150bbd5cb59598382a58957de Mon Sep 17 00:00:00 2001 From: gornekich Date: Mon, 10 Apr 2023 21:50:07 +0400 Subject: [PATCH 021/149] nfc: rework nfc app --- applications/main/nfc/nfc_app.c | 76 +++---- applications/main/nfc/nfc_app_i.h | 24 +-- .../main/nfc/scenes/nfc_scene_config.h | 66 +------ .../main/nfc/scenes/nfc_scene_debug.c | 5 +- .../main/nfc/scenes/nfc_scene_delete.c | 77 -------- .../nfc/scenes/nfc_scene_delete_success.c | 45 ----- .../main/nfc/scenes/nfc_scene_detect_reader.c | 103 ---------- .../main/nfc/scenes/nfc_scene_device_info.c | 86 -------- .../nfc/scenes/nfc_scene_dict_not_found.c | 52 ----- .../scenes/nfc_scene_emulate_apdu_sequence.c | 34 ---- .../main/nfc/scenes/nfc_scene_emulate_uid.c | 144 -------------- .../main/nfc/scenes/nfc_scene_emv_menu.c | 46 ----- .../nfc/scenes/nfc_scene_emv_read_success.c | 113 ----------- .../main/nfc/scenes/nfc_scene_exit_confirm.c | 9 +- .../main/nfc/scenes/nfc_scene_extra_actions.c | 7 +- .../main/nfc/scenes/nfc_scene_field.c | 33 ---- .../main/nfc/scenes/nfc_scene_file_select.c | 28 --- .../main/nfc/scenes/nfc_scene_generate_info.c | 60 ------ .../nfc/scenes/nfc_scene_mf_classic_data.c | 106 ---------- .../scenes/nfc_scene_mf_classic_dict_attack.c | 186 ------------------ .../nfc/scenes/nfc_scene_mf_classic_emulate.c | 69 ------- .../nfc/scenes/nfc_scene_mf_classic_keys.c | 71 ------- .../scenes/nfc_scene_mf_classic_keys_add.c | 60 ------ .../scenes/nfc_scene_mf_classic_keys_delete.c | 83 -------- .../scenes/nfc_scene_mf_classic_keys_list.c | 100 ---------- ...nfc_scene_mf_classic_keys_warn_duplicate.c | 47 ----- .../nfc/scenes/nfc_scene_mf_classic_menu.c | 82 -------- .../nfc_scene_mf_classic_read_success.c | 82 -------- .../nfc/scenes/nfc_scene_mf_classic_update.c | 98 --------- .../nfc_scene_mf_classic_update_success.c | 44 ----- .../nfc/scenes/nfc_scene_mf_classic_write.c | 92 --------- .../scenes/nfc_scene_mf_classic_write_fail.c | 58 ------ .../nfc_scene_mf_classic_write_success.c | 44 ----- .../scenes/nfc_scene_mf_classic_wrong_card.c | 53 ----- .../nfc/scenes/nfc_scene_mf_desfire_app.c | 120 ----------- .../nfc/scenes/nfc_scene_mf_desfire_data.c | 104 ---------- .../nfc/scenes/nfc_scene_mf_desfire_menu.c | 72 ------- .../nfc_scene_mf_desfire_read_success.c | 96 --------- .../nfc/scenes/nfc_scene_mf_ultralight_data.c | 32 --- .../scenes/nfc_scene_mf_ultralight_emulate.c | 74 ------- .../nfc_scene_mf_ultralight_key_input.c | 44 ----- .../nfc/scenes/nfc_scene_mf_ultralight_menu.c | 87 -------- .../nfc_scene_mf_ultralight_read_auth.c | 116 ----------- ...nfc_scene_mf_ultralight_read_auth_result.c | 116 ----------- .../nfc_scene_mf_ultralight_read_success.c | 84 -------- .../nfc_scene_mf_ultralight_unlock_auto.c | 64 ------ .../nfc_scene_mf_ultralight_unlock_menu.c | 83 -------- .../nfc_scene_mf_ultralight_unlock_warn.c | 98 --------- .../nfc/scenes/nfc_scene_mfkey_complete.c | 49 ----- .../nfc/scenes/nfc_scene_mfkey_nonces_info.c | 55 ------ .../main/nfc/scenes/nfc_scene_nfc_data_info.c | 154 --------------- .../main/nfc/scenes/nfc_scene_nfca_menu.c | 11 +- .../main/nfc/scenes/nfc_scene_nfca_read.c | 8 +- .../nfc/scenes/nfc_scene_nfca_read_success.c | 2 +- applications/main/nfc/scenes/nfc_scene_read.c | 83 +------- .../nfc/scenes/nfc_scene_read_card_success.c | 61 ------ .../nfc/scenes/nfc_scene_read_card_type.c | 6 - .../nfc/scenes/nfc_scene_restore_original.c | 45 ----- .../nfc_scene_restore_original_confirm.c | 53 ----- applications/main/nfc/scenes/nfc_scene_rpc.c | 86 -------- .../main/nfc/scenes/nfc_scene_save_name.c | 93 --------- .../main/nfc/scenes/nfc_scene_save_success.c | 48 ----- .../main/nfc/scenes/nfc_scene_saved_menu.c | 180 ----------------- .../main/nfc/scenes/nfc_scene_set_atqa.c | 44 ----- .../main/nfc/scenes/nfc_scene_set_sak.c | 44 ----- .../main/nfc/scenes/nfc_scene_set_type.c | 68 ------- .../main/nfc/scenes/nfc_scene_set_uid.c | 54 ----- .../main/nfc/scenes/nfc_scene_start.c | 12 +- firmware/targets/furi_hal_include/f_hal_nfc.h | 9 + lib/nfc/nfc.c | 38 ++-- lib/nfc/nfc_dev.c | 47 +++++ lib/nfc/nfc_dev.h | 21 ++ lib/nfc/nfc_device.h | 1 - lib/nfc/nfc_device_data.h | 31 +++ lib/nfc/nfc_poller.c | 39 ++++ lib/nfc/nfc_poller.h | 26 +++ lib/nfc/protocols/nfca_poller.h | 4 +- 77 files changed, 258 insertions(+), 4587 deletions(-) delete mode 100644 applications/main/nfc/scenes/nfc_scene_delete.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_delete_success.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_detect_reader.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_device_info.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_dict_not_found.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_emulate_apdu_sequence.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_emulate_uid.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_emv_menu.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_emv_read_success.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_field.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_file_select.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_generate_info.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_mf_classic_data.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_mf_classic_emulate.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_mf_classic_keys.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_mf_classic_keys_add.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_mf_classic_keys_delete.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_mf_classic_keys_list.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_mf_classic_keys_warn_duplicate.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_mf_classic_menu.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_mf_classic_read_success.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_mf_classic_update.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_mf_classic_update_success.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_mf_classic_write.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_mf_classic_write_fail.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_mf_classic_write_success.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_mf_classic_wrong_card.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_mf_desfire_app.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_mf_desfire_data.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_mf_desfire_menu.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_mf_desfire_read_success.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_mf_ultralight_data.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_mf_ultralight_emulate.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_mf_ultralight_key_input.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_auth.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_auth_result.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_success.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_auto.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_menu.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_mfkey_complete.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_mfkey_nonces_info.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_nfc_data_info.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_read_card_success.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_restore_original.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_restore_original_confirm.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_rpc.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_save_name.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_save_success.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_saved_menu.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_set_atqa.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_set_sak.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_set_type.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_set_uid.c create mode 100644 lib/nfc/nfc_dev.c create mode 100644 lib/nfc/nfc_dev.h create mode 100644 lib/nfc/nfc_device_data.h create mode 100644 lib/nfc/nfc_poller.c create mode 100644 lib/nfc/nfc_poller.h diff --git a/applications/main/nfc/nfc_app.c b/applications/main/nfc/nfc_app.c index 3ba6c3d5cb46..fa5fdc1a0f82 100644 --- a/applications/main/nfc/nfc_app.c +++ b/applications/main/nfc/nfc_app.c @@ -1,5 +1,5 @@ #include "nfc_app_i.h" -#include + #include bool nfc_custom_event_callback(void* context, uint32_t event) { @@ -44,8 +44,7 @@ NfcApp* nfc_app_alloc() { view_dispatcher_set_navigation_event_callback(nfc->view_dispatcher, nfc_back_event_callback); // Nfc device - nfc->dev = nfc_device_alloc(); - furi_string_set(nfc->dev->folder, NFC_APP_FOLDER); + nfc->nfc_dev = nfc_dev_alloc(); // Open GUI record nfc->gui = furi_record_open(RECORD_GUI); @@ -90,19 +89,6 @@ NfcApp* nfc_app_alloc() { nfc->widget = widget_alloc(); view_dispatcher_add_view(nfc->view_dispatcher, NfcViewWidget, widget_get_view(nfc->widget)); - // Mifare Classic Dict Attack - nfc->dict_attack = dict_attack_alloc(); - view_dispatcher_add_view( - nfc->view_dispatcher, NfcViewDictAttack, dict_attack_get_view(nfc->dict_attack)); - - // Detect Reader - nfc->detect_reader = detect_reader_alloc(); - view_dispatcher_add_view( - nfc->view_dispatcher, NfcViewDetectReader, detect_reader_get_view(nfc->detect_reader)); - - // Generator - nfc->generator = NULL; - return nfc; } @@ -127,7 +113,7 @@ void nfc_app_free(NfcApp* nfc) { } // Nfc device - nfc_device_free(nfc->dev); + nfc_dev_free(nfc->nfc_dev); // Submenu view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewMenu); @@ -162,14 +148,6 @@ void nfc_app_free(NfcApp* nfc) { view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewWidget); widget_free(nfc->widget); - // Mifare Classic Dict Attack - view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewDictAttack); - dict_attack_free(nfc->dict_attack); - - // Detect Reader - view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewDetectReader); - detect_reader_free(nfc->detect_reader); - // View Dispatcher view_dispatcher_free(nfc->view_dispatcher); @@ -217,10 +195,8 @@ void nfc_blink_stop(NfcApp* nfc) { } bool nfc_save_file(NfcApp* nfc) { - furi_string_printf( - nfc->dev->load_path, "%s/%s%s", NFC_APP_FOLDER, nfc->dev->dev_name, NFC_APP_EXTENSION); - bool file_saved = nfc_device_save(nfc->dev, furi_string_get_cstr(nfc->dev->load_path)); - return file_saved; + furi_assert(nfc); + return true; } void nfc_show_loading_popup(void* context, bool show) { @@ -266,7 +242,7 @@ int32_t nfc_app(void* p) { // Check argument and run corresponding scene if(args && strlen(args)) { - nfc_device_set_loading_callback(nfc->dev, nfc_show_loading_popup, nfc); + // nfc_device_set_loading_callback(nfc->dev, nfc_show_loading_popup, nfc); uint32_t rpc_ctx = 0; if(sscanf(p, "RPC %lX", &rpc_ctx) == 1) { nfc->rpc_ctx = (void*)rpc_ctx; @@ -274,33 +250,33 @@ int32_t nfc_app(void* p) { rpc_system_app_send_started(nfc->rpc_ctx); view_dispatcher_attach_to_gui( nfc->view_dispatcher, nfc->gui, ViewDispatcherTypeDesktop); - scene_manager_next_scene(nfc->scene_manager, NfcSceneRpc); + scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); } else { view_dispatcher_attach_to_gui( nfc->view_dispatcher, nfc->gui, ViewDispatcherTypeFullscreen); - if(nfc_device_load(nfc->dev, p, true)) { - if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate); - DOLPHIN_DEED(DolphinDeedNfcEmulate); - } else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate); - DOLPHIN_DEED(DolphinDeedNfcEmulate); - } else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneDeviceInfo); - } else { - scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); - DOLPHIN_DEED(DolphinDeedNfcEmulate); - } - } else { - // Exit app - view_dispatcher_stop(nfc->view_dispatcher); - } + // if(nfc_device_load(nfc->dev, p, true)) { + // if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { + // scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate); + // DOLPHIN_DEED(DolphinDeedNfcEmulate); + // } else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) { + // scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate); + // DOLPHIN_DEED(DolphinDeedNfcEmulate); + // } else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) { + // scene_manager_next_scene(nfc->scene_manager, NfcSceneDeviceInfo); + // } else { + // scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); + // DOLPHIN_DEED(DolphinDeedNfcEmulate); + // } + // } else { + // // Exit app + // view_dispatcher_stop(nfc->view_dispatcher); + // } } - nfc_device_set_loading_callback(nfc->dev, NULL, nfc); + // nfc_device_set_loading_callback(nfc->dev, NULL, nfc); } else { view_dispatcher_attach_to_gui( nfc->view_dispatcher, nfc->gui, ViewDispatcherTypeFullscreen); - scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardType); + scene_manager_next_scene(nfc->scene_manager, NfcSceneStart); } view_dispatcher_run(nfc->view_dispatcher); diff --git a/applications/main/nfc/nfc_app_i.h b/applications/main/nfc/nfc_app_i.h index a08e9897c9e5..6825321b579a 100644 --- a/applications/main/nfc/nfc_app_i.h +++ b/applications/main/nfc/nfc_app_i.h @@ -22,16 +22,6 @@ #include #include -#include -#include -#include -#include -#include -#include - -#include "views/dict_attack.h" -#include "views/detect_reader.h" - #include #include @@ -42,8 +32,7 @@ #include #include - -ARRAY_DEF(MfClassicUserKeys, char*, M_PTR_OPLIST); +#include #define NFC_TEXT_STORE_SIZE 128 #define NFC_APP_FOLDER ANY_PATH("nfc") @@ -55,18 +44,14 @@ typedef enum { } NfcRpcState; struct NfcApp { - NfcWorker* worker; ViewDispatcher* view_dispatcher; Gui* gui; NotificationApp* notifications; SceneManager* scene_manager; - NfcDevice* dev; - FuriHalNfcDevData dev_edit_data; char text_store[NFC_TEXT_STORE_SIZE + 1]; FuriString* text_box_store; uint8_t byte_input_store[6]; - MfClassicUserKeys_t mfc_key_strs; // Used in MFC key listing void* rpc_ctx; NfcRpcState rpc_state; @@ -80,12 +65,11 @@ struct NfcApp { ByteInput* byte_input; TextBox* text_box; Widget* widget; - DictAttack* dict_attack; - DetectReader* detect_reader; - - const NfcGenerator* generator; NfcaPoller* nfca_poller; + + NfcDev* nfc_dev; + NfcDevData nfc_dev_data; }; typedef enum { diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index c6badf384547..236869887f63 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -1,68 +1,12 @@ ADD_SCENE(nfc, start, Start) ADD_SCENE(nfc, read, Read) -ADD_SCENE(nfc, saved_menu, SavedMenu) -ADD_SCENE(nfc, extra_actions, ExtraActions) -ADD_SCENE(nfc, set_type, SetType) -ADD_SCENE(nfc, set_sak, SetSak) -ADD_SCENE(nfc, set_atqa, SetAtqa) -ADD_SCENE(nfc, set_uid, SetUid) -ADD_SCENE(nfc, generate_info, GenerateInfo) -ADD_SCENE(nfc, read_card_success, ReadCardSuccess) -ADD_SCENE(nfc, save_name, SaveName) -ADD_SCENE(nfc, save_success, SaveSuccess) -ADD_SCENE(nfc, file_select, FileSelect) -ADD_SCENE(nfc, emulate_uid, EmulateUid) +ADD_SCENE(nfc, read_card_type, ReadCardType) +ADD_SCENE(nfc, nfca_read, ReadNfca) ADD_SCENE(nfc, nfca_read_success, NfcaReadSuccess) ADD_SCENE(nfc, nfca_menu, NfcaMenu) -ADD_SCENE(nfc, mf_ultralight_read_success, MfUltralightReadSuccess) -ADD_SCENE(nfc, mf_ultralight_data, MfUltralightData) -ADD_SCENE(nfc, mf_ultralight_menu, MfUltralightMenu) -ADD_SCENE(nfc, mf_ultralight_emulate, MfUltralightEmulate) -ADD_SCENE(nfc, mf_ultralight_read_auth, MfUltralightReadAuth) -ADD_SCENE(nfc, mf_ultralight_read_auth_result, MfUltralightReadAuthResult) -ADD_SCENE(nfc, mf_ultralight_key_input, MfUltralightKeyInput) -ADD_SCENE(nfc, mf_ultralight_unlock_auto, MfUltralightUnlockAuto) -ADD_SCENE(nfc, mf_ultralight_unlock_menu, MfUltralightUnlockMenu) -ADD_SCENE(nfc, mf_ultralight_unlock_warn, MfUltralightUnlockWarn) -ADD_SCENE(nfc, mf_desfire_read_success, MfDesfireReadSuccess) -ADD_SCENE(nfc, mf_desfire_menu, MfDesfireMenu) -ADD_SCENE(nfc, mf_desfire_data, MfDesfireData) -ADD_SCENE(nfc, mf_desfire_app, MfDesfireApp) -ADD_SCENE(nfc, mf_classic_read_success, MfClassicReadSuccess) -ADD_SCENE(nfc, mf_classic_data, MfClassicData) -ADD_SCENE(nfc, mf_classic_menu, MfClassicMenu) -ADD_SCENE(nfc, mf_classic_emulate, MfClassicEmulate) -ADD_SCENE(nfc, mf_classic_keys, MfClassicKeys) -ADD_SCENE(nfc, mf_classic_keys_add, MfClassicKeysAdd) -ADD_SCENE(nfc, mf_classic_keys_list, MfClassicKeysList) -ADD_SCENE(nfc, mf_classic_keys_delete, MfClassicKeysDelete) -ADD_SCENE(nfc, mf_classic_keys_warn_duplicate, MfClassicKeysWarnDuplicate) -ADD_SCENE(nfc, mf_classic_dict_attack, MfClassicDictAttack) -ADD_SCENE(nfc, mf_classic_write, MfClassicWrite) -ADD_SCENE(nfc, mf_classic_write_success, MfClassicWriteSuccess) -ADD_SCENE(nfc, mf_classic_write_fail, MfClassicWriteFail) -ADD_SCENE(nfc, mf_classic_update, MfClassicUpdate) -ADD_SCENE(nfc, mf_classic_update_success, MfClassicUpdateSuccess) -ADD_SCENE(nfc, mf_classic_wrong_card, MfClassicWrongCard) -ADD_SCENE(nfc, emv_read_success, EmvReadSuccess) -ADD_SCENE(nfc, emv_menu, EmvMenu) -ADD_SCENE(nfc, emulate_apdu_sequence, EmulateApduSequence) -ADD_SCENE(nfc, device_info, DeviceInfo) -ADD_SCENE(nfc, delete, Delete) -ADD_SCENE(nfc, delete_success, DeleteSuccess) -ADD_SCENE(nfc, restore_original_confirm, RestoreOriginalConfirm) -ADD_SCENE(nfc, restore_original, RestoreOriginal) +ADD_SCENE(nfc, extra_actions, ExtraActions) ADD_SCENE(nfc, debug, Debug) -ADD_SCENE(nfc, field, Field) -ADD_SCENE(nfc, dict_not_found, DictNotFound) -ADD_SCENE(nfc, rpc, Rpc) -ADD_SCENE(nfc, exit_confirm, ExitConfirm) ADD_SCENE(nfc, retry_confirm, RetryConfirm) -ADD_SCENE(nfc, detect_reader, DetectReader) -ADD_SCENE(nfc, mfkey_nonces_info, MfkeyNoncesInfo) -ADD_SCENE(nfc, mfkey_complete, MfkeyComplete) -ADD_SCENE(nfc, nfc_data_info, NfcDataInfo) -ADD_SCENE(nfc, read_card_type, ReadCardType) +ADD_SCENE(nfc, exit_confirm, ExitConfirm) -ADD_SCENE(nfc, not_implemented, NotImplemented) -ADD_SCENE(nfc, read_nfca, ReadNfca) +ADD_SCENE(nfc, not_implemented, NotImplemented) \ No newline at end of file diff --git a/applications/main/nfc/scenes/nfc_scene_debug.c b/applications/main/nfc/scenes/nfc_scene_debug.c index f6705c880f39..85bc901a3429 100644 --- a/applications/main/nfc/scenes/nfc_scene_debug.c +++ b/applications/main/nfc/scenes/nfc_scene_debug.c @@ -23,7 +23,6 @@ void nfc_scene_debug_on_enter(void* context) { submenu_set_selected_item( submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneDebug)); - nfc_device_clear(nfc->dev); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); } @@ -35,12 +34,12 @@ bool nfc_scene_debug_on_event(void* context, SceneManagerEvent event) { if(event.event == SubmenuDebugIndexField) { scene_manager_set_scene_state( nfc->scene_manager, NfcSceneDebug, SubmenuDebugIndexField); - scene_manager_next_scene(nfc->scene_manager, NfcSceneField); + scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); consumed = true; } else if(event.event == SubmenuDebugIndexApdu) { scene_manager_set_scene_state( nfc->scene_manager, NfcSceneDebug, SubmenuDebugIndexApdu); - scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateApduSequence); + scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); consumed = true; } } diff --git a/applications/main/nfc/scenes/nfc_scene_delete.c b/applications/main/nfc/scenes/nfc_scene_delete.c deleted file mode 100644 index a5debe5e1b47..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_delete.c +++ /dev/null @@ -1,77 +0,0 @@ -#include "../nfc_app_i.h" - -void nfc_scene_delete_widget_callback(GuiButtonType result, InputType type, void* context) { - NfcApp* nfc = context; - if(type == InputTypeShort) { - view_dispatcher_send_custom_event(nfc->view_dispatcher, result); - } -} - -void nfc_scene_delete_on_enter(void* context) { - NfcApp* nfc = context; - FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data; - - // Setup Custom Widget view - FuriString* temp_str; - temp_str = furi_string_alloc(); - - furi_string_printf(temp_str, "\e#Delete %s?\e#", nfc->dev->dev_name); - widget_add_text_box_element( - nfc->widget, 0, 0, 128, 23, AlignCenter, AlignCenter, furi_string_get_cstr(temp_str), false); - widget_add_button_element( - nfc->widget, GuiButtonTypeLeft, "Cancel", nfc_scene_delete_widget_callback, nfc); - widget_add_button_element( - nfc->widget, GuiButtonTypeRight, "Delete", nfc_scene_delete_widget_callback, nfc); - - furi_string_set(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]); - } - widget_add_string_element( - nfc->widget, 64, 24, AlignCenter, AlignTop, FontSecondary, furi_string_get_cstr(temp_str)); - - NfcProtocol protocol = nfc->dev->dev_data.protocol; - if(protocol == NfcDeviceProtocolEMV) { - furi_string_set(temp_str, "EMV bank card"); - } else if(protocol == NfcDeviceProtocolMifareUl) { - furi_string_set(temp_str, nfc_mf_ul_type(nfc->dev->dev_data.mf_ul_data.type, true)); - } else if(protocol == NfcDeviceProtocolMifareClassic) { - furi_string_set(temp_str, nfc_mf_classic_type(nfc->dev->dev_data.mf_classic_data.type)); - } else if(protocol == NfcDeviceProtocolMifareDesfire) { - furi_string_set(temp_str, "MIFARE DESFire"); - } else { - furi_string_set(temp_str, "Unknown ISO tag"); - } - widget_add_string_element( - nfc->widget, 64, 34, AlignCenter, AlignTop, FontSecondary, furi_string_get_cstr(temp_str)); - widget_add_string_element(nfc->widget, 64, 44, AlignCenter, AlignTop, FontSecondary, "NFC-A"); - furi_string_free(temp_str); - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); -} - -bool nfc_scene_delete_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == GuiButtonTypeLeft) { - consumed = scene_manager_previous_scene(nfc->scene_manager); - } else if(event.event == GuiButtonTypeRight) { - if(nfc_device_delete(nfc->dev, true)) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneDeleteSuccess); - } else { - scene_manager_search_and_switch_to_previous_scene( - nfc->scene_manager, NfcSceneStart); - } - consumed = true; - } - } - return consumed; -} - -void nfc_scene_delete_on_exit(void* context) { - NfcApp* nfc = context; - - widget_reset(nfc->widget); -} diff --git a/applications/main/nfc/scenes/nfc_scene_delete_success.c b/applications/main/nfc/scenes/nfc_scene_delete_success.c deleted file mode 100644 index f0c22eec4d58..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_delete_success.c +++ /dev/null @@ -1,45 +0,0 @@ -#include "../nfc_app_i.h" - -void nfc_scene_delete_success_popup_callback(void* context) { - NfcApp* nfc = context; - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); -} - -void nfc_scene_delete_success_on_enter(void* context) { - NfcApp* nfc = context; - - // Setup view - Popup* popup = nfc->popup; - popup_set_icon(popup, 0, 2, &I_DolphinMafia_115x62); - popup_set_header(popup, "Deleted", 83, 19, AlignLeft, AlignBottom); - popup_set_timeout(popup, 1500); - popup_set_context(popup, nfc); - popup_set_callback(popup, nfc_scene_delete_success_popup_callback); - popup_enable_timeout(popup); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); -} - -bool nfc_scene_delete_success_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == NfcCustomEventViewExit) { - if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneMfClassicKeys)) { - consumed = scene_manager_search_and_switch_to_previous_scene( - nfc->scene_manager, NfcSceneMfClassicKeys); - } else { - consumed = scene_manager_search_and_switch_to_previous_scene( - nfc->scene_manager, NfcSceneFileSelect); - } - } - } - return consumed; -} - -void nfc_scene_delete_success_on_exit(void* context) { - NfcApp* nfc = context; - - // Clear view - popup_reset(nfc->popup); -} diff --git a/applications/main/nfc/scenes/nfc_scene_detect_reader.c b/applications/main/nfc/scenes/nfc_scene_detect_reader.c deleted file mode 100644 index 85c698d05350..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_detect_reader.c +++ /dev/null @@ -1,103 +0,0 @@ -#include "../nfc_app_i.h" - -#define NFC_SCENE_DETECT_READER_PAIR_NONCES_MAX (10U) - -static const NotificationSequence sequence_detect_reader = { - &message_green_255, - &message_blue_255, - &message_do_not_reset, - NULL, -}; - -bool nfc_detect_reader_worker_callback(NfcWorkerEvent event, void* context) { - UNUSED(event); - furi_assert(context); - NfcApp* nfc = context; - view_dispatcher_send_custom_event(nfc->view_dispatcher, event); - return true; -} - -void nfc_scene_detect_reader_callback(void* context) { - furi_assert(context); - NfcApp* nfc = context; - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); -} - -void nfc_scene_detect_reader_on_enter(void* context) { - NfcApp* nfc = context; - - detect_reader_set_callback(nfc->detect_reader, nfc_scene_detect_reader_callback, nfc); - detect_reader_set_nonces_max(nfc->detect_reader, NFC_SCENE_DETECT_READER_PAIR_NONCES_MAX); - NfcDeviceData* dev_data = &nfc->dev->dev_data; - if(dev_data->nfc_data.uid_len) { - detect_reader_set_uid( - nfc->detect_reader, dev_data->nfc_data.uid, dev_data->nfc_data.uid_len); - } - - // Store number of collected nonces in scene state - scene_manager_set_scene_state(nfc->scene_manager, NfcSceneDetectReader, 0); - notification_message(nfc->notifications, &sequence_detect_reader); - - nfc_worker_start( - nfc->worker, - NfcWorkerStateAnalyzeReader, - &nfc->dev->dev_data, - nfc_detect_reader_worker_callback, - nfc); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDetectReader); -} - -bool nfc_scene_detect_reader_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - bool consumed = false; - uint32_t nonces_collected = - scene_manager_get_scene_state(nfc->scene_manager, NfcSceneDetectReader); - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == NfcCustomEventViewExit) { - nfc_worker_stop(nfc->worker); - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfkeyNoncesInfo); - consumed = true; - } else if(event.event == NfcWorkerEventDetectReaderMfkeyCollected) { - nonces_collected += 2; - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneDetectReader, nonces_collected); - detect_reader_set_nonces_collected(nfc->detect_reader, nonces_collected); - if(nonces_collected >= NFC_SCENE_DETECT_READER_PAIR_NONCES_MAX) { - detect_reader_set_state(nfc->detect_reader, DetectReaderStateDone); - nfc_blink_stop(nfc); - notification_message(nfc->notifications, &sequence_single_vibro); - notification_message(nfc->notifications, &sequence_set_green_255); - nfc_worker_stop(nfc->worker); - } - consumed = true; - } else if(event.event == NfcWorkerEventDetectReaderDetected) { - if(nonces_collected < NFC_SCENE_DETECT_READER_PAIR_NONCES_MAX) { - notification_message(nfc->notifications, &sequence_blink_start_cyan); - detect_reader_set_state(nfc->detect_reader, DetectReaderStateReaderDetected); - } - } else if(event.event == NfcWorkerEventDetectReaderLost) { - if(nonces_collected < NFC_SCENE_DETECT_READER_PAIR_NONCES_MAX) { - nfc_blink_stop(nfc); - notification_message(nfc->notifications, &sequence_detect_reader); - detect_reader_set_state(nfc->detect_reader, DetectReaderStateReaderLost); - } - } - } - - return consumed; -} - -void nfc_scene_detect_reader_on_exit(void* context) { - NfcApp* nfc = context; - - // Stop worker - nfc_worker_stop(nfc->worker); - - // Clear view - detect_reader_reset(nfc->detect_reader); - - // Stop notifications - nfc_blink_stop(nfc); - notification_message(nfc->notifications, &sequence_reset_green); -} diff --git a/applications/main/nfc/scenes/nfc_scene_device_info.c b/applications/main/nfc/scenes/nfc_scene_device_info.c deleted file mode 100644 index 6d1bc8b42381..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_device_info.c +++ /dev/null @@ -1,86 +0,0 @@ -#include "../nfc_app_i.h" -#include "../helpers/nfc_emv_parser.h" - -void nfc_scene_device_info_widget_callback(GuiButtonType result, InputType type, void* context) { - NfcApp* nfc = context; - if(type == InputTypeShort) { - view_dispatcher_send_custom_event(nfc->view_dispatcher, result); - } -} - -void nfc_scene_device_info_on_enter(void* context) { - NfcApp* nfc = context; - NfcDeviceData* dev_data = &nfc->dev->dev_data; - - FuriString* temp_str; - temp_str = furi_string_alloc(); - - if(dev_data->protocol == NfcDeviceProtocolEMV) { - EmvData* emv_data = &dev_data->emv_data; - furi_string_printf(temp_str, "\e#%s\n", emv_data->name); - for(uint8_t i = 0; i < emv_data->number_len; i += 2) { - furi_string_cat_printf( - temp_str, "%02X%02X ", emv_data->number[i], emv_data->number[i + 1]); - } - furi_string_trim(temp_str); - - // Add expiration date - if(emv_data->exp_mon) { - furi_string_cat_printf( - temp_str, "\nExp: %02X/%02X", emv_data->exp_mon, emv_data->exp_year); - } - // Parse currency code - if((emv_data->currency_code)) { - FuriString* currency_name; - currency_name = furi_string_alloc(); - if(nfc_emv_parser_get_currency_name( - nfc->dev->storage, emv_data->currency_code, currency_name)) { - furi_string_cat_printf( - temp_str, "\nCur: %s ", furi_string_get_cstr(currency_name)); - } - furi_string_free(currency_name); - } - // Parse country code - if((emv_data->country_code)) { - FuriString* country_name; - country_name = furi_string_alloc(); - if(nfc_emv_parser_get_country_name( - nfc->dev->storage, emv_data->country_code, country_name)) { - furi_string_cat_printf(temp_str, "Reg: %s", furi_string_get_cstr(country_name)); - } - furi_string_free(country_name); - } - } else if( - dev_data->protocol == NfcDeviceProtocolMifareClassic || - dev_data->protocol == NfcDeviceProtocolMifareUl) { - furi_string_set(temp_str, nfc->dev->dev_data.parsed_data); - } - - widget_add_text_scroll_element(nfc->widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); - furi_string_free(temp_str); - - widget_add_button_element( - nfc->widget, GuiButtonTypeRight, "More", nfc_scene_device_info_widget_callback, nfc); - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); -} - -bool nfc_scene_device_info_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == GuiButtonTypeRight) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); - consumed = true; - } - } - return consumed; -} - -void nfc_scene_device_info_on_exit(void* context) { - NfcApp* nfc = context; - - // Clear views - widget_reset(nfc->widget); -} diff --git a/applications/main/nfc/scenes/nfc_scene_dict_not_found.c b/applications/main/nfc/scenes/nfc_scene_dict_not_found.c deleted file mode 100644 index 3b525c17e84f..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_dict_not_found.c +++ /dev/null @@ -1,52 +0,0 @@ -#include "../nfc_app_i.h" - -void nfc_scene_dict_not_found_popup_callback(void* context) { - NfcApp* nfc = context; - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); -} - -void nfc_scene_dict_not_found_on_enter(void* context) { - NfcApp* nfc = context; - - // Setup view - Popup* popup = nfc->popup; - popup_set_text( - popup, - "Function requires\nan SD card with\nfresh databases.", - 82, - 24, - AlignCenter, - AlignCenter); - popup_set_icon(popup, 6, 10, &I_SDQuestion_35x43); - popup_set_timeout(popup, 2500); - popup_set_context(popup, nfc); - popup_set_callback(popup, nfc_scene_dict_not_found_popup_callback); - popup_enable_timeout(popup); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); -} - -bool nfc_scene_dict_not_found_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == NfcCustomEventViewExit) { - if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneMfClassicKeys)) { - consumed = scene_manager_search_and_switch_to_previous_scene( - nfc->scene_manager, NfcSceneMfClassicKeys); - } else if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneExtraActions)) { - consumed = scene_manager_search_and_switch_to_previous_scene( - nfc->scene_manager, NfcSceneExtraActions); - } else { - consumed = scene_manager_search_and_switch_to_previous_scene( - nfc->scene_manager, NfcSceneStart); - } - } - } - return consumed; -} - -void nfc_scene_dict_not_found_on_exit(void* context) { - NfcApp* nfc = context; - popup_reset(nfc->popup); -} diff --git a/applications/main/nfc/scenes/nfc_scene_emulate_apdu_sequence.c b/applications/main/nfc/scenes/nfc_scene_emulate_apdu_sequence.c deleted file mode 100644 index 81d00aeffc2c..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_emulate_apdu_sequence.c +++ /dev/null @@ -1,34 +0,0 @@ -#include "../nfc_app_i.h" -#include - -void nfc_scene_emulate_apdu_sequence_on_enter(void* context) { - NfcApp* nfc = context; - - // Setup view - Popup* popup = nfc->popup; - popup_set_header(popup, "Run APDU reader", 64, 31, AlignCenter, AlignTop); - - // Setup and start worker - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); - nfc_worker_start(nfc->worker, NfcWorkerStateEmulateApdu, &nfc->dev->dev_data, NULL, nfc); - - nfc_blink_emulate_start(nfc); -} - -bool nfc_scene_emulate_apdu_sequence_on_event(void* context, SceneManagerEvent event) { - UNUSED(context); - UNUSED(event); - bool consumed = false; - return consumed; -} - -void nfc_scene_emulate_apdu_sequence_on_exit(void* context) { - NfcApp* nfc = context; - - // Stop worker - nfc_worker_stop(nfc->worker); - // Clear view - popup_reset(nfc->popup); - - nfc_blink_stop(nfc); -} diff --git a/applications/main/nfc/scenes/nfc_scene_emulate_uid.c b/applications/main/nfc/scenes/nfc_scene_emulate_uid.c deleted file mode 100644 index 10435d2c7550..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_emulate_uid.c +++ /dev/null @@ -1,144 +0,0 @@ -#include "../nfc_app_i.h" - -#define NFC_SCENE_EMULATE_UID_LOG_SIZE_MAX (200) - -enum { - NfcSceneEmulateUidStateWidget, - NfcSceneEmulateUidStateTextBox, -}; - -bool nfc_emulate_uid_worker_callback(NfcWorkerEvent event, void* context) { - UNUSED(event); - furi_assert(context); - NfcApp* nfc = context; - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit); - return true; -} - -void nfc_scene_emulate_uid_widget_callback(GuiButtonType result, InputType type, void* context) { - furi_assert(context); - NfcApp* nfc = context; - if(type == InputTypeShort) { - view_dispatcher_send_custom_event(nfc->view_dispatcher, result); - } -} - -void nfc_emulate_uid_textbox_callback(void* context) { - furi_assert(context); - NfcApp* nfc = context; - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); -} - -// Add widget with device name or inform that data received -static void nfc_scene_emulate_uid_widget_config(NfcApp* nfc, bool data_received) { - FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; - Widget* widget = nfc->widget; - widget_reset(widget); - FuriString* info_str; - info_str = furi_string_alloc(); - - widget_add_icon_element(widget, 0, 3, &I_NFC_dolphin_emulation_47x61); - widget_add_string_element(widget, 57, 13, AlignLeft, AlignTop, FontPrimary, "Emulating UID"); - if(strcmp(nfc->dev->dev_name, "") != 0) { - furi_string_printf(info_str, "%s", nfc->dev->dev_name); - } else { - for(uint8_t i = 0; i < data->uid_len; i++) { - furi_string_cat_printf(info_str, "%02X ", data->uid[i]); - } - } - furi_string_trim(info_str); - widget_add_text_box_element( - widget, 57, 28, 67, 25, AlignCenter, AlignTop, furi_string_get_cstr(info_str), true); - furi_string_free(info_str); - if(data_received) { - widget_add_button_element( - widget, GuiButtonTypeCenter, "Log", nfc_scene_emulate_uid_widget_callback, nfc); - } -} - -void nfc_scene_emulate_uid_on_enter(void* context) { - NfcApp* nfc = context; - - // Setup Widget - nfc_scene_emulate_uid_widget_config(nfc, false); - // Setup TextBox - TextBox* text_box = nfc->text_box; - text_box_set_font(text_box, TextBoxFontHex); - text_box_set_focus(text_box, TextBoxFocusEnd); - furi_string_reset(nfc->text_box_store); - - // Set Widget state and view - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneEmulateUid, NfcSceneEmulateUidStateWidget); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); - // Start worker - memset(&nfc->dev->dev_data.reader_data, 0, sizeof(NfcReaderRequestData)); - nfc_worker_start( - nfc->worker, - NfcWorkerStateUidEmulate, - &nfc->dev->dev_data, - nfc_emulate_uid_worker_callback, - nfc); - - nfc_blink_emulate_start(nfc); -} - -bool nfc_scene_emulate_uid_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - NfcReaderRequestData* reader_data = &nfc->dev->dev_data.reader_data; - uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneEmulateUid); - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == NfcCustomEventWorkerExit) { - // Add data button to widget if data is received for the first time - if(!furi_string_size(nfc->text_box_store)) { - nfc_scene_emulate_uid_widget_config(nfc, true); - } - // Update TextBox data - if(furi_string_size(nfc->text_box_store) < NFC_SCENE_EMULATE_UID_LOG_SIZE_MAX) { - furi_string_cat_printf(nfc->text_box_store, "R:"); - for(uint16_t i = 0; i < reader_data->size; i++) { - furi_string_cat_printf(nfc->text_box_store, " %02X", reader_data->data[i]); - } - furi_string_push_back(nfc->text_box_store, '\n'); - text_box_set_text(nfc->text_box, furi_string_get_cstr(nfc->text_box_store)); - } - memset(reader_data, 0, sizeof(NfcReaderRequestData)); - consumed = true; - } else if(event.event == GuiButtonTypeCenter && state == NfcSceneEmulateUidStateWidget) { - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneEmulateUid, NfcSceneEmulateUidStateTextBox); - consumed = true; - } else if(event.event == NfcCustomEventViewExit && state == NfcSceneEmulateUidStateTextBox) { - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneEmulateUid, NfcSceneEmulateUidStateWidget); - consumed = true; - } - } else if(event.type == SceneManagerEventTypeBack) { - if(state == NfcSceneEmulateUidStateTextBox) { - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneEmulateUid, NfcSceneEmulateUidStateWidget); - consumed = true; - } - } - - return consumed; -} - -void nfc_scene_emulate_uid_on_exit(void* context) { - NfcApp* nfc = context; - - // Stop worker - nfc_worker_stop(nfc->worker); - - // Clear view - widget_reset(nfc->widget); - text_box_reset(nfc->text_box); - furi_string_reset(nfc->text_box_store); - - nfc_blink_stop(nfc); -} diff --git a/applications/main/nfc/scenes/nfc_scene_emv_menu.c b/applications/main/nfc/scenes/nfc_scene_emv_menu.c deleted file mode 100644 index 88d3355a0b75..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_emv_menu.c +++ /dev/null @@ -1,46 +0,0 @@ -#include "../nfc_app_i.h" - -enum SubmenuIndex { - SubmenuIndexInfo, -}; - -void nfc_scene_emv_menu_submenu_callback(void* context, uint32_t index) { - NfcApp* nfc = context; - - view_dispatcher_send_custom_event(nfc->view_dispatcher, index); -} - -void nfc_scene_emv_menu_on_enter(void* context) { - NfcApp* nfc = context; - Submenu* submenu = nfc->submenu; - - submenu_add_item(submenu, "Info", SubmenuIndexInfo, nfc_scene_emv_menu_submenu_callback, nfc); - submenu_set_selected_item( - nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneEmvMenu)); - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); -} - -bool nfc_scene_emv_menu_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == SubmenuIndexInfo) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); - consumed = true; - } - scene_manager_set_scene_state(nfc->scene_manager, NfcSceneEmvMenu, event.event); - } else if(event.type == SceneManagerEventTypeBack) { - consumed = scene_manager_previous_scene(nfc->scene_manager); - } - - return consumed; -} - -void nfc_scene_emv_menu_on_exit(void* context) { - NfcApp* nfc = context; - - // Clear view - submenu_reset(nfc->submenu); -} diff --git a/applications/main/nfc/scenes/nfc_scene_emv_read_success.c b/applications/main/nfc/scenes/nfc_scene_emv_read_success.c deleted file mode 100644 index 00057a2ee4ab..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_emv_read_success.c +++ /dev/null @@ -1,113 +0,0 @@ -#include "../nfc_app_i.h" -#include "../helpers/nfc_emv_parser.h" - -void nfc_scene_emv_read_success_widget_callback( - GuiButtonType result, - InputType type, - void* context) { - NfcApp* nfc = context; - if(type == InputTypeShort) { - view_dispatcher_send_custom_event(nfc->view_dispatcher, result); - } -} - -void nfc_scene_emv_read_success_on_enter(void* context) { - NfcApp* nfc = context; - EmvData* emv_data = &nfc->dev->dev_data.emv_data; - - // Setup Custom Widget view - widget_add_button_element( - nfc->widget, GuiButtonTypeLeft, "Retry", nfc_scene_emv_read_success_widget_callback, nfc); - widget_add_button_element( - nfc->widget, GuiButtonTypeRight, "More", nfc_scene_emv_read_success_widget_callback, nfc); - - FuriString* temp_str; - if(emv_data->name[0] != '\0') { - temp_str = furi_string_alloc_printf("\e#%s\n", emv_data->name); - } else { - temp_str = furi_string_alloc_printf("\e#Unknown Bank Card\n"); - } - if(emv_data->number_len) { - for(uint8_t i = 0; i < emv_data->number_len; i += 2) { - furi_string_cat_printf( - temp_str, "%02X%02X ", emv_data->number[i], emv_data->number[i + 1]); - } - furi_string_trim(temp_str); - } else if(emv_data->aid_len) { - furi_string_cat_printf(temp_str, "Can't parse data from app\n"); - // Parse AID name - FuriString* aid_name; - aid_name = furi_string_alloc(); - if(nfc_emv_parser_get_aid_name( - nfc->dev->storage, emv_data->aid, emv_data->aid_len, aid_name)) { - furi_string_cat_printf(temp_str, "AID: %s", furi_string_get_cstr(aid_name)); - } else { - furi_string_cat_printf(temp_str, "AID: "); - for(uint8_t i = 0; i < emv_data->aid_len; i++) { - furi_string_cat_printf(temp_str, "%02X", emv_data->aid[i]); - } - } - furi_string_free(aid_name); - } - - // Add expiration date - if(emv_data->exp_mon) { - furi_string_cat_printf( - temp_str, "\nExp: %02X/%02X", emv_data->exp_mon, emv_data->exp_year); - } - // Parse currency code - if((emv_data->currency_code)) { - FuriString* currency_name; - currency_name = furi_string_alloc(); - if(nfc_emv_parser_get_currency_name( - nfc->dev->storage, emv_data->currency_code, currency_name)) { - furi_string_cat_printf(temp_str, "\nCur: %s ", furi_string_get_cstr(currency_name)); - } - furi_string_free(currency_name); - } - // Parse country code - if((emv_data->country_code)) { - FuriString* country_name; - country_name = furi_string_alloc(); - if(nfc_emv_parser_get_country_name( - nfc->dev->storage, emv_data->country_code, country_name)) { - furi_string_cat_printf(temp_str, "Reg: %s", furi_string_get_cstr(country_name)); - } - furi_string_free(country_name); - } - - notification_message_block(nfc->notifications, &sequence_set_green_255); - - widget_add_text_scroll_element(nfc->widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); - furi_string_free(temp_str); - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); -} - -bool nfc_scene_emv_read_success_on_event(void* context, SceneManagerEvent event) { - NfcApp* 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, NfcSceneEmvMenu); - consumed = true; - } - } else if(event.type == SceneManagerEventTypeBack) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); - consumed = true; - } - return consumed; -} - -void nfc_scene_emv_read_success_on_exit(void* context) { - NfcApp* 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_exit_confirm.c b/applications/main/nfc/scenes/nfc_scene_exit_confirm.c index 92933556d2ad..3b2e73f97e70 100644 --- a/applications/main/nfc/scenes/nfc_scene_exit_confirm.c +++ b/applications/main/nfc/scenes/nfc_scene_exit_confirm.c @@ -29,13 +29,8 @@ bool nfc_scene_exit_confirm_on_event(void* context, SceneManagerEvent event) { if(event.event == DialogExResultRight) { consumed = scene_manager_previous_scene(nfc->scene_manager); } else if(event.event == DialogExResultLeft) { - if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneReadCardType)) { - consumed = scene_manager_search_and_switch_to_previous_scene( - nfc->scene_manager, NfcSceneReadCardType); - } else { - consumed = scene_manager_search_and_switch_to_previous_scene( - nfc->scene_manager, NfcSceneStart); - } + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneStart); } } else if(event.type == SceneManagerEventTypeBack) { consumed = true; diff --git a/applications/main/nfc/scenes/nfc_scene_extra_actions.c b/applications/main/nfc/scenes/nfc_scene_extra_actions.c index 9282a34c96a5..effd38f60c66 100644 --- a/applications/main/nfc/scenes/nfc_scene_extra_actions.c +++ b/applications/main/nfc/scenes/nfc_scene_extra_actions.c @@ -45,17 +45,12 @@ bool nfc_scene_extra_actions_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubmenuIndexMfClassicKeys) { - if(mf_classic_dict_check_presence(MfClassicDictTypeSystem)) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); - } else { - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); - } + scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); consumed = true; } else if(event.event == SubmenuIndexMfUltralightUnlock) { scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); consumed = true; } else if(event.event == SubmenuIndexReadCardType) { - scene_manager_set_scene_state(nfc->scene_manager, NfcSceneReadCardType, 0); scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardType); consumed = true; } diff --git a/applications/main/nfc/scenes/nfc_scene_field.c b/applications/main/nfc/scenes/nfc_scene_field.c deleted file mode 100644 index 893f4d03ff91..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_field.c +++ /dev/null @@ -1,33 +0,0 @@ -#include "../nfc_app_i.h" - -void nfc_scene_field_on_enter(void* context) { - NfcApp* nfc = context; - - furi_hal_nfc_field_on(); - - Popup* popup = nfc->popup; - popup_set_header( - popup, - "Field is on\nDon't leave device\nin this mode for too long.", - 64, - 11, - AlignCenter, - AlignTop); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); - - notification_internal_message(nfc->notifications, &sequence_set_blue_255); -} - -bool nfc_scene_field_on_event(void* context, SceneManagerEvent event) { - UNUSED(context); - UNUSED(event); - return false; -} - -void nfc_scene_field_on_exit(void* context) { - NfcApp* nfc = context; - - furi_hal_nfc_field_off(); - notification_internal_message(nfc->notifications, &sequence_reset_blue); - popup_reset(nfc->popup); -} diff --git a/applications/main/nfc/scenes/nfc_scene_file_select.c b/applications/main/nfc/scenes/nfc_scene_file_select.c deleted file mode 100644 index 61ac593e0c4e..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_file_select.c +++ /dev/null @@ -1,28 +0,0 @@ -#include "../nfc_app_i.h" -#include "nfc/nfc_device.h" - -void nfc_scene_file_select_on_enter(void* context) { - NfcApp* nfc = context; - // Process file_select return - nfc_device_set_loading_callback(nfc->dev, nfc_show_loading_popup, nfc); - if(!furi_string_size(nfc->dev->load_path)) { - furi_string_set_str(nfc->dev->load_path, NFC_APP_FOLDER); - } - if(nfc_file_select(nfc->dev)) { - scene_manager_set_scene_state(nfc->scene_manager, NfcSceneSavedMenu, 0); - scene_manager_next_scene(nfc->scene_manager, NfcSceneSavedMenu); - } else { - scene_manager_search_and_switch_to_previous_scene(nfc->scene_manager, NfcSceneStart); - } - nfc_device_set_loading_callback(nfc->dev, NULL, nfc); -} - -bool nfc_scene_file_select_on_event(void* context, SceneManagerEvent event) { - UNUSED(context); - UNUSED(event); - return false; -} - -void nfc_scene_file_select_on_exit(void* context) { - UNUSED(context); -} diff --git a/applications/main/nfc/scenes/nfc_scene_generate_info.c b/applications/main/nfc/scenes/nfc_scene_generate_info.c deleted file mode 100644 index e877d771a6f0..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_generate_info.c +++ /dev/null @@ -1,60 +0,0 @@ -#include "../nfc_app_i.h" -#include "lib/nfc/helpers/nfc_generators.h" - -void nfc_scene_generate_info_dialog_callback(DialogExResult result, void* context) { - NfcApp* nfc = context; - - view_dispatcher_send_custom_event(nfc->view_dispatcher, result); -} - -void nfc_scene_generate_info_on_enter(void* context) { - NfcApp* nfc = context; - - // Setup dialog view - FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; - DialogEx* dialog_ex = nfc->dialog_ex; - dialog_ex_set_right_button_text(dialog_ex, "More"); - - // Create info text - FuriString* info_str = furi_string_alloc_printf( - "%s\n%s\nUID:", nfc->generator->name, nfc_get_dev_type(data->type)); - - // Append UID - for(int i = 0; i < data->uid_len; ++i) { - furi_string_cat_printf(info_str, " %02X", data->uid[i]); - } - nfc_text_store_set(nfc, furi_string_get_cstr(info_str)); - furi_string_free(info_str); - - dialog_ex_set_text(dialog_ex, nfc->text_store, 0, 0, AlignLeft, AlignTop); - dialog_ex_set_context(dialog_ex, nfc); - dialog_ex_set_result_callback(dialog_ex, nfc_scene_generate_info_dialog_callback); - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); -} - -bool nfc_scene_generate_info_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == DialogExResultRight) { - // Switch either to NfcSceneMfClassicMenu or NfcSceneMfUltralightMenu - if(nfc->dev->dev_data.protocol == NfcDeviceProtocolMifareClassic) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicMenu); - } else if(nfc->dev->dev_data.protocol == NfcDeviceProtocolMifareUl) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightMenu); - } - consumed = true; - } - } - - return consumed; -} - -void nfc_scene_generate_info_on_exit(void* context) { - NfcApp* nfc = context; - - // Clean views - dialog_ex_reset(nfc->dialog_ex); -} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_data.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_data.c deleted file mode 100644 index 83ba57f7cf7e..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_data.c +++ /dev/null @@ -1,106 +0,0 @@ -#include "../nfc_app_i.h" - -void nfc_scene_mf_classic_data_on_enter(void* context) { - NfcApp* nfc = context; - MfClassicType type = nfc->dev->dev_data.mf_classic_data.type; - MfClassicData* data = &nfc->dev->dev_data.mf_classic_data; - TextBox* text_box = nfc->text_box; - - text_box_set_font(text_box, TextBoxFontHex); - - int card_blocks = 0; - if(type == MfClassicType1k) { - card_blocks = MF_CLASSIC_1K_TOTAL_SECTORS_NUM * 4; - } else if(type == MfClassicType4k) { - // 16 sectors of 4 blocks each plus 8 sectors of 16 blocks each - card_blocks = MF_CLASSIC_1K_TOTAL_SECTORS_NUM * 4 + 8 * 16; - } else if(type == MfClassicTypeMini) { - card_blocks = MF_MINI_TOTAL_SECTORS_NUM * 4; - } - - int bytes_written = 0; - for(int block_num = 0; block_num < card_blocks; block_num++) { - bool is_sec_trailer = mf_classic_is_sector_trailer(block_num); - if(is_sec_trailer) { - uint8_t sector_num = mf_classic_get_sector_by_block(block_num); - MfClassicSectorTrailer* sec_tr = - mf_classic_get_sector_trailer_by_sector(data, sector_num); - // Key A - for(size_t i = 0; i < sizeof(sec_tr->key_a); i += 2) { - if((bytes_written % 8 == 0) && (bytes_written != 0)) { - furi_string_push_back(nfc->text_box_store, '\n'); - } - if(mf_classic_is_key_found(data, sector_num, MfClassicKeyA)) { - furi_string_cat_printf( - nfc->text_box_store, "%02X%02X ", sec_tr->key_a[i], sec_tr->key_a[i + 1]); - } else { - furi_string_cat_printf(nfc->text_box_store, "???? "); - } - bytes_written += 2; - } - // Access bytes - for(size_t i = 0; i < MF_CLASSIC_ACCESS_BYTES_SIZE; i += 2) { - if((bytes_written % 8 == 0) && (bytes_written != 0)) { - furi_string_push_back(nfc->text_box_store, '\n'); - } - if(mf_classic_is_block_read(data, block_num)) { - furi_string_cat_printf( - nfc->text_box_store, - "%02X%02X ", - sec_tr->access_bits[i], - sec_tr->access_bits[i + 1]); - } else { - furi_string_cat_printf(nfc->text_box_store, "???? "); - } - bytes_written += 2; - } - // Key B - for(size_t i = 0; i < sizeof(sec_tr->key_b); i += 2) { - if((bytes_written % 8 == 0) && (bytes_written != 0)) { - furi_string_push_back(nfc->text_box_store, '\n'); - } - if(mf_classic_is_key_found(data, sector_num, MfClassicKeyB)) { - furi_string_cat_printf( - nfc->text_box_store, "%02X%02X ", sec_tr->key_b[i], sec_tr->key_b[i + 1]); - } else { - furi_string_cat_printf(nfc->text_box_store, "???? "); - } - bytes_written += 2; - } - } else { - // Write data block - for(size_t i = 0; i < MF_CLASSIC_BLOCK_SIZE; i += 2) { - if((bytes_written % 8 == 0) && (bytes_written != 0)) { - furi_string_push_back(nfc->text_box_store, '\n'); - } - if(mf_classic_is_block_read(data, block_num)) { - furi_string_cat_printf( - nfc->text_box_store, - "%02X%02X ", - data->block[block_num].value[i], - data->block[block_num].value[i + 1]); - } else { - furi_string_cat_printf(nfc->text_box_store, "???? "); - } - bytes_written += 2; - } - } - } - text_box_set_text(text_box, furi_string_get_cstr(nfc->text_box_store)); - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); -} - -bool nfc_scene_mf_classic_data_on_event(void* context, SceneManagerEvent event) { - UNUSED(context); - UNUSED(event); - return false; -} - -void nfc_scene_mf_classic_data_on_exit(void* context) { - NfcApp* nfc = context; - - // Clean view - text_box_reset(nfc->text_box); - furi_string_reset(nfc->text_box_store); -} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c deleted file mode 100644 index 77d559367c1e..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c +++ /dev/null @@ -1,186 +0,0 @@ -#include "../nfc_app_i.h" -#include - -#define TAG "NfcMfClassicDictAttack" - -typedef enum { - DictAttackStateIdle, - DictAttackStateUserDictInProgress, - DictAttackStateFlipperDictInProgress, -} DictAttackState; - -bool nfc_dict_attack_worker_callback(NfcWorkerEvent event, void* context) { - furi_assert(context); - NfcApp* nfc = context; - view_dispatcher_send_custom_event(nfc->view_dispatcher, event); - return true; -} - -void nfc_dict_attack_dict_attack_result_callback(void* context) { - furi_assert(context); - NfcApp* nfc = context; - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventDictAttackSkip); -} - -static void nfc_scene_mf_classic_dict_attack_update_view(NfcApp* nfc) { - MfClassicData* data = &nfc->dev->dev_data.mf_classic_data; - uint8_t sectors_read = 0; - uint8_t keys_found = 0; - - // Calculate found keys and read sectors - mf_classic_get_read_sectors_and_keys(data, §ors_read, &keys_found); - dict_attack_set_keys_found(nfc->dict_attack, keys_found); - dict_attack_set_sector_read(nfc->dict_attack, sectors_read); -} - -static void nfc_scene_mf_classic_dict_attack_prepare_view(NfcApp* nfc, DictAttackState state) { - MfClassicData* data = &nfc->dev->dev_data.mf_classic_data; - NfcMfClassicDictAttackData* dict_attack_data = &nfc->dev->dev_data.mf_classic_dict_attack_data; - NfcWorkerState worker_state = NfcWorkerStateReady; - MfClassicDict* dict = NULL; - - // Identify scene state - if(state == DictAttackStateIdle) { - if(mf_classic_dict_check_presence(MfClassicDictTypeUser)) { - state = DictAttackStateUserDictInProgress; - } else { - state = DictAttackStateFlipperDictInProgress; - } - } else if(state == DictAttackStateUserDictInProgress) { - state = DictAttackStateFlipperDictInProgress; - } - - // Setup view - if(state == DictAttackStateUserDictInProgress) { - worker_state = NfcWorkerStateMfClassicDictAttack; - dict_attack_set_header(nfc->dict_attack, "MF Classic User Dictionary"); - dict = mf_classic_dict_alloc(MfClassicDictTypeUser); - - // If failed to load user dictionary - try the system dictionary - if(!dict) { - FURI_LOG_E(TAG, "User dictionary not found"); - state = DictAttackStateFlipperDictInProgress; - } - } - if(state == DictAttackStateFlipperDictInProgress) { - worker_state = NfcWorkerStateMfClassicDictAttack; - dict_attack_set_header(nfc->dict_attack, "MF Classic System Dictionary"); - dict = mf_classic_dict_alloc(MfClassicDictTypeSystem); - if(!dict) { - FURI_LOG_E(TAG, "Flipper dictionary not found"); - // Pass through to let the worker handle the failure - } - } - // Free previous dictionary - if(dict_attack_data->dict) { - mf_classic_dict_free(dict_attack_data->dict); - } - dict_attack_data->dict = dict; - scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfClassicDictAttack, state); - dict_attack_set_callback(nfc->dict_attack, nfc_dict_attack_dict_attack_result_callback, nfc); - dict_attack_set_current_sector(nfc->dict_attack, 0); - dict_attack_set_card_detected(nfc->dict_attack, data->type); - dict_attack_set_total_dict_keys( - nfc->dict_attack, dict ? mf_classic_dict_get_total_keys(dict) : 0); - nfc_scene_mf_classic_dict_attack_update_view(nfc); - nfc_worker_start( - nfc->worker, worker_state, &nfc->dev->dev_data, nfc_dict_attack_worker_callback, nfc); -} - -void nfc_scene_mf_classic_dict_attack_on_enter(void* context) { - NfcApp* nfc = context; - nfc_scene_mf_classic_dict_attack_prepare_view(nfc, DictAttackStateIdle); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDictAttack); - nfc_blink_read_start(nfc); - notification_message(nfc->notifications, &sequence_display_backlight_enforce_on); -} - -bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - MfClassicData* data = &nfc->dev->dev_data.mf_classic_data; - bool consumed = false; - - uint32_t state = - scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicDictAttack); - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == NfcWorkerEventSuccess) { - if(state == DictAttackStateUserDictInProgress) { - nfc_worker_stop(nfc->worker); - nfc_scene_mf_classic_dict_attack_prepare_view(nfc, state); - consumed = true; - } else { - notification_message(nfc->notifications, &sequence_success); - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSuccess); - DOLPHIN_DEED(DolphinDeedNfcReadSuccess); - consumed = true; - } - } else if(event.event == NfcWorkerEventAborted) { - if(state == DictAttackStateUserDictInProgress && - dict_attack_get_card_state(nfc->dict_attack)) { - nfc_scene_mf_classic_dict_attack_prepare_view(nfc, state); - consumed = true; - } else { - notification_message(nfc->notifications, &sequence_success); - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSuccess); - // Counting failed attempts too - DOLPHIN_DEED(DolphinDeedNfcReadSuccess); - consumed = true; - } - } else if(event.event == NfcWorkerEventCardDetected) { - dict_attack_set_card_detected(nfc->dict_attack, data->type); - consumed = true; - } else if(event.event == NfcWorkerEventNoCardDetected) { - dict_attack_set_card_removed(nfc->dict_attack); - consumed = true; - } else if(event.event == NfcWorkerEventFoundKeyA) { - dict_attack_inc_keys_found(nfc->dict_attack); - consumed = true; - } else if(event.event == NfcWorkerEventFoundKeyB) { - dict_attack_inc_keys_found(nfc->dict_attack); - consumed = true; - } else if(event.event == NfcWorkerEventNewSector) { - nfc_scene_mf_classic_dict_attack_update_view(nfc); - dict_attack_inc_current_sector(nfc->dict_attack); - consumed = true; - } else if(event.event == NfcWorkerEventNewDictKeyBatch) { - nfc_scene_mf_classic_dict_attack_update_view(nfc); - dict_attack_inc_current_dict_key(nfc->dict_attack, NFC_DICT_KEY_BATCH_SIZE); - consumed = true; - } else if(event.event == NfcCustomEventDictAttackSkip) { - if(state == DictAttackStateUserDictInProgress) { - nfc_worker_stop(nfc->worker); - consumed = true; - } else if(state == DictAttackStateFlipperDictInProgress) { - nfc_worker_stop(nfc->worker); - consumed = true; - } - } else if(event.event == NfcWorkerEventKeyAttackStart) { - dict_attack_set_key_attack( - nfc->dict_attack, - true, - nfc->dev->dev_data.mf_classic_dict_attack_data.current_sector); - } else if(event.event == NfcWorkerEventKeyAttackStop) { - dict_attack_set_key_attack(nfc->dict_attack, false, 0); - } else if(event.event == NfcWorkerEventKeyAttackNextSector) { - dict_attack_inc_key_attack_current_sector(nfc->dict_attack); - } - } else if(event.type == SceneManagerEventTypeBack) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); - consumed = true; - } - return consumed; -} - -void nfc_scene_mf_classic_dict_attack_on_exit(void* context) { - NfcApp* nfc = context; - NfcMfClassicDictAttackData* dict_attack_data = &nfc->dev->dev_data.mf_classic_dict_attack_data; - // Stop worker - nfc_worker_stop(nfc->worker); - if(dict_attack_data->dict) { - mf_classic_dict_free(dict_attack_data->dict); - dict_attack_data->dict = NULL; - } - dict_attack_reset(nfc->dict_attack); - nfc_blink_stop(nfc); - notification_message(nfc->notifications, &sequence_display_backlight_enforce_auto); -} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_emulate.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_emulate.c deleted file mode 100644 index 6cf7689052c5..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_emulate.c +++ /dev/null @@ -1,69 +0,0 @@ -#include "../nfc_app_i.h" - -#define NFC_MF_CLASSIC_DATA_NOT_CHANGED (0UL) -#define NFC_MF_CLASSIC_DATA_CHANGED (1UL) - -bool nfc_mf_classic_emulate_worker_callback(NfcWorkerEvent event, void* context) { - UNUSED(event); - NfcApp* nfc = context; - - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneMfClassicEmulate, NFC_MF_CLASSIC_DATA_CHANGED); - return true; -} - -void nfc_scene_mf_classic_emulate_on_enter(void* context) { - NfcApp* nfc = context; - - // Setup view - Popup* popup = nfc->popup; - popup_set_header(popup, "Emulating", 67, 13, AlignLeft, AlignTop); - if(strcmp(nfc->dev->dev_name, "") != 0) { - nfc_text_store_set(nfc, "%s", nfc->dev->dev_name); - } else { - nfc_text_store_set(nfc, "MIFARE\nClassic"); - } - popup_set_icon(popup, 0, 3, &I_NFC_dolphin_emulation_47x61); - popup_set_text(popup, nfc->text_store, 90, 28, AlignCenter, AlignTop); - - // Setup and start worker - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); - nfc_worker_start( - nfc->worker, - NfcWorkerStateMfClassicEmulate, - &nfc->dev->dev_data, - nfc_mf_classic_emulate_worker_callback, - nfc); - nfc_blink_emulate_start(nfc); -} - -bool nfc_scene_mf_classic_emulate_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeBack) { - // Stop worker - nfc_worker_stop(nfc->worker); - // Check if data changed and save in shadow file - if(scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicEmulate) == - NFC_MF_CLASSIC_DATA_CHANGED) { - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneMfClassicEmulate, NFC_MF_CLASSIC_DATA_NOT_CHANGED); - // Save shadow file - if(furi_string_size(nfc->dev->load_path)) { - nfc_device_save_shadow(nfc->dev, furi_string_get_cstr(nfc->dev->load_path)); - } - } - consumed = false; - } - return consumed; -} - -void nfc_scene_mf_classic_emulate_on_exit(void* context) { - NfcApp* nfc = context; - - // Clear view - popup_reset(nfc->popup); - - nfc_blink_stop(nfc); -} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_keys.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys.c deleted file mode 100644 index b7cc2f283450..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_keys.c +++ /dev/null @@ -1,71 +0,0 @@ -#include "../nfc_app_i.h" - -void nfc_scene_mf_classic_keys_widget_callback(GuiButtonType result, InputType type, void* context) { - NfcApp* nfc = context; - if(type == InputTypeShort) { - view_dispatcher_send_custom_event(nfc->view_dispatcher, result); - } -} - -void nfc_scene_mf_classic_keys_on_enter(void* context) { - NfcApp* nfc = context; - - // Load flipper dict keys total - uint32_t flipper_dict_keys_total = 0; - MfClassicDict* dict = mf_classic_dict_alloc(MfClassicDictTypeSystem); - if(dict) { - flipper_dict_keys_total = mf_classic_dict_get_total_keys(dict); - mf_classic_dict_free(dict); - } - // Load user dict keys total - uint32_t user_dict_keys_total = 0; - dict = mf_classic_dict_alloc(MfClassicDictTypeUser); - if(dict) { - user_dict_keys_total = mf_classic_dict_get_total_keys(dict); - mf_classic_dict_free(dict); - } - - widget_add_string_element( - nfc->widget, 0, 0, AlignLeft, AlignTop, FontPrimary, "MIFARE Classic Keys"); - char temp_str[32]; - snprintf(temp_str, sizeof(temp_str), "System dict: %lu", flipper_dict_keys_total); - widget_add_string_element(nfc->widget, 0, 20, AlignLeft, AlignTop, FontSecondary, temp_str); - snprintf(temp_str, sizeof(temp_str), "User dict: %lu", user_dict_keys_total); - widget_add_string_element(nfc->widget, 0, 32, AlignLeft, AlignTop, FontSecondary, temp_str); - widget_add_button_element( - nfc->widget, GuiButtonTypeCenter, "Add", nfc_scene_mf_classic_keys_widget_callback, nfc); - widget_add_icon_element(nfc->widget, 87, 13, &I_Keychain_39x36); - if(user_dict_keys_total > 0) { - widget_add_button_element( - nfc->widget, - GuiButtonTypeRight, - "List", - nfc_scene_mf_classic_keys_widget_callback, - nfc); - } - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); -} - -bool nfc_scene_mf_classic_keys_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == GuiButtonTypeCenter) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicKeysAdd); - consumed = true; - } else if(event.event == GuiButtonTypeRight) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicKeysList); - consumed = true; - } - } - - return consumed; -} - -void nfc_scene_mf_classic_keys_on_exit(void* context) { - NfcApp* nfc = context; - - widget_reset(nfc->widget); -} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_add.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_add.c deleted file mode 100644 index d2b89829bf94..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_add.c +++ /dev/null @@ -1,60 +0,0 @@ -#include "../nfc_app_i.h" -#include - -void nfc_scene_mf_classic_keys_add_byte_input_callback(void* context) { - NfcApp* nfc = context; - - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); -} - -void nfc_scene_mf_classic_keys_add_on_enter(void* context) { - NfcApp* nfc = context; - - // Setup view - ByteInput* byte_input = nfc->byte_input; - byte_input_set_header_text(byte_input, "Enter the key in hex"); - byte_input_set_result_callback( - byte_input, - nfc_scene_mf_classic_keys_add_byte_input_callback, - NULL, - nfc, - nfc->byte_input_store, - 6); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewByteInput); -} - -bool nfc_scene_mf_classic_keys_add_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == NfcCustomEventByteInputDone) { - // Add key to dict - MfClassicDict* dict = mf_classic_dict_alloc(MfClassicDictTypeUser); - if(dict) { - if(mf_classic_dict_is_key_present(dict, nfc->byte_input_store)) { - scene_manager_next_scene( - nfc->scene_manager, NfcSceneMfClassicKeysWarnDuplicate); - } else if(mf_classic_dict_add_key(dict, nfc->byte_input_store)) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess); - DOLPHIN_DEED(DolphinDeedNfcMfcAdd); - } else { - scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound); - } - } else { - scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound); - } - mf_classic_dict_free(dict); - consumed = true; - } - } - return consumed; -} - -void nfc_scene_mf_classic_keys_add_on_exit(void* context) { - NfcApp* nfc = context; - - // Clear view - byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0); - byte_input_set_header_text(nfc->byte_input, ""); -} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_delete.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_delete.c deleted file mode 100644 index 9f34c8eee0de..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_delete.c +++ /dev/null @@ -1,83 +0,0 @@ -#include "../nfc_app_i.h" - -void nfc_scene_mf_classic_keys_delete_widget_callback( - GuiButtonType result, - InputType type, - void* context) { - NfcApp* nfc = context; - if(type == InputTypeShort) { - view_dispatcher_send_custom_event(nfc->view_dispatcher, result); - } -} - -void nfc_scene_mf_classic_keys_delete_on_enter(void* context) { - NfcApp* nfc = context; - MfClassicDict* dict = mf_classic_dict_alloc(MfClassicDictTypeUser); - uint32_t key_index = - scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicKeysDelete); - // Setup Custom Widget view - FuriString* key_str; - key_str = furi_string_alloc(); - - widget_add_string_element( - nfc->widget, 64, 0, AlignCenter, AlignTop, FontPrimary, "Delete this key?"); - widget_add_button_element( - nfc->widget, - GuiButtonTypeLeft, - "Cancel", - nfc_scene_mf_classic_keys_delete_widget_callback, - nfc); - widget_add_button_element( - nfc->widget, - GuiButtonTypeRight, - "Delete", - nfc_scene_mf_classic_keys_delete_widget_callback, - nfc); - - mf_classic_dict_get_key_at_index_str(dict, key_str, key_index); - widget_add_string_element( - nfc->widget, - 64, - 32, - AlignCenter, - AlignCenter, - FontSecondary, - furi_string_get_cstr(key_str)); - - furi_string_free(key_str); - mf_classic_dict_free(dict); - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); -} - -bool nfc_scene_mf_classic_keys_delete_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - bool consumed = false; - uint32_t key_index = - scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicKeysDelete); - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == GuiButtonTypeLeft) { - consumed = scene_manager_search_and_switch_to_previous_scene( - nfc->scene_manager, NfcSceneMfClassicKeys); - } else if(event.event == GuiButtonTypeRight) { - MfClassicDict* dict = mf_classic_dict_alloc(MfClassicDictTypeUser); - if(mf_classic_dict_delete_index(dict, key_index)) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneDeleteSuccess); - } else { - scene_manager_search_and_switch_to_previous_scene( - nfc->scene_manager, NfcSceneMfClassicKeys); - } - mf_classic_dict_free(dict); - consumed = true; - } - } - - return consumed; -} - -void nfc_scene_mf_classic_keys_delete_on_exit(void* context) { - NfcApp* nfc = context; - - widget_reset(nfc->widget); -} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_list.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_list.c deleted file mode 100644 index 6a7be48a0bb3..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_list.c +++ /dev/null @@ -1,100 +0,0 @@ -#include "../nfc_app_i.h" - -#define NFC_SCENE_MF_CLASSIC_KEYS_LIST_MAX (100) - -void nfc_scene_mf_classic_keys_list_submenu_callback(void* context, uint32_t index) { - furi_assert(context); - - NfcApp* nfc = context; - view_dispatcher_send_custom_event(nfc->view_dispatcher, index); -} - -void nfc_scene_mf_classic_keys_list_popup_callback(void* context) { - furi_assert(context); - - NfcApp* nfc = context; - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); -} - -void nfc_scene_mf_classic_keys_list_prepare(NfcApp* nfc, MfClassicDict* dict) { - Submenu* submenu = nfc->submenu; - uint32_t index = 0; - FuriString* temp_key; - temp_key = furi_string_alloc(); - - submenu_set_header(submenu, "Select key to delete:"); - while(mf_classic_dict_get_next_key_str(dict, temp_key)) { - char* current_key = (char*)malloc(sizeof(char) * 13); - strncpy(current_key, furi_string_get_cstr(temp_key), 12); - MfClassicUserKeys_push_back(nfc->mfc_key_strs, current_key); - FURI_LOG_D("ListKeys", "Key %lu: %s", index, current_key); - submenu_add_item( - submenu, current_key, index++, nfc_scene_mf_classic_keys_list_submenu_callback, nfc); - } - furi_string_free(temp_key); -} - -void nfc_scene_mf_classic_keys_list_on_enter(void* context) { - NfcApp* nfc = context; - MfClassicDict* dict = mf_classic_dict_alloc(MfClassicDictTypeUser); - MfClassicUserKeys_init(nfc->mfc_key_strs); - if(dict) { - uint32_t total_user_keys = mf_classic_dict_get_total_keys(dict); - if(total_user_keys < NFC_SCENE_MF_CLASSIC_KEYS_LIST_MAX) { - nfc_scene_mf_classic_keys_list_prepare(nfc, dict); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); - } else { - popup_set_header(nfc->popup, "Too many keys!", 64, 0, AlignCenter, AlignTop); - popup_set_text( - nfc->popup, - "Edit user dictionary\nwith file browser", - 64, - 12, - AlignCenter, - AlignTop); - popup_set_callback(nfc->popup, nfc_scene_mf_classic_keys_list_popup_callback); - popup_set_context(nfc->popup, nfc); - popup_set_timeout(nfc->popup, 3000); - popup_enable_timeout(nfc->popup); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); - } - mf_classic_dict_free(dict); - } else { - popup_set_header( - nfc->popup, "Failed to load dictionary", 64, 32, AlignCenter, AlignCenter); - popup_set_callback(nfc->popup, nfc_scene_mf_classic_keys_list_popup_callback); - popup_set_context(nfc->popup, nfc); - popup_set_timeout(nfc->popup, 3000); - popup_enable_timeout(nfc->popup); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); - } -} - -bool nfc_scene_mf_classic_keys_list_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - bool consumed = false; - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == NfcCustomEventViewExit) { - consumed = scene_manager_previous_scene(nfc->scene_manager); - } else { - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneMfClassicKeysDelete, event.event); - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicKeysDelete); - consumed = true; - } - } - return consumed; -} - -void nfc_scene_mf_classic_keys_list_on_exit(void* context) { - NfcApp* nfc = context; - - MfClassicUserKeys_it_t it; - for(MfClassicUserKeys_it(it, nfc->mfc_key_strs); !MfClassicUserKeys_end_p(it); - MfClassicUserKeys_next(it)) { - free(*MfClassicUserKeys_ref(it)); - } - MfClassicUserKeys_clear(nfc->mfc_key_strs); - submenu_reset(nfc->submenu); - popup_reset(nfc->popup); -} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_warn_duplicate.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_warn_duplicate.c deleted file mode 100644 index 5cc1ba635399..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_warn_duplicate.c +++ /dev/null @@ -1,47 +0,0 @@ -#include "../nfc_app_i.h" - -void nfc_scene_mf_classic_keys_warn_duplicate_popup_callback(void* context) { - NfcApp* nfc = context; - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); -} - -void nfc_scene_mf_classic_keys_warn_duplicate_on_enter(void* context) { - NfcApp* nfc = context; - - // Setup view - Popup* popup = nfc->popup; - popup_set_icon(popup, 72, 16, &I_DolphinCommon_56x48); - popup_set_header(popup, "Key already exists!", 64, 3, AlignCenter, AlignTop); - popup_set_text( - popup, - "Please enter a\n" - "different key.", - 4, - 24, - AlignLeft, - AlignTop); - popup_set_timeout(popup, 5000); - popup_set_context(popup, nfc); - popup_set_callback(popup, nfc_scene_mf_classic_keys_warn_duplicate_popup_callback); - popup_enable_timeout(popup); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); -} - -bool nfc_scene_mf_classic_keys_warn_duplicate_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == NfcCustomEventViewExit) { - consumed = scene_manager_search_and_switch_to_previous_scene( - nfc->scene_manager, NfcSceneMfClassicKeysAdd); - } - } - return consumed; -} - -void nfc_scene_mf_classic_keys_warn_duplicate_on_exit(void* context) { - NfcApp* nfc = context; - - popup_reset(nfc->popup); -} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_menu.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_menu.c deleted file mode 100644 index 207bb17edfbb..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_menu.c +++ /dev/null @@ -1,82 +0,0 @@ -#include "../nfc_app_i.h" -#include - -enum SubmenuIndex { - SubmenuIndexSave, - SubmenuIndexEmulate, - SubmenuIndexDetectReader, - SubmenuIndexInfo, -}; - -void nfc_scene_mf_classic_menu_submenu_callback(void* context, uint32_t index) { - NfcApp* nfc = context; - - view_dispatcher_send_custom_event(nfc->view_dispatcher, index); -} - -void nfc_scene_mf_classic_menu_on_enter(void* context) { - NfcApp* nfc = context; - Submenu* submenu = nfc->submenu; - - submenu_add_item( - submenu, "Save", SubmenuIndexSave, nfc_scene_mf_classic_menu_submenu_callback, nfc); - submenu_add_item( - submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_mf_classic_menu_submenu_callback, nfc); - if(!mf_classic_is_card_read(&nfc->dev->dev_data.mf_classic_data)) { - submenu_add_item( - submenu, - "Detect Reader", - SubmenuIndexDetectReader, - nfc_scene_mf_classic_menu_submenu_callback, - nfc); - } - submenu_add_item( - submenu, "Info", SubmenuIndexInfo, nfc_scene_mf_classic_menu_submenu_callback, nfc); - - submenu_set_selected_item( - nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicMenu)); - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); -} - -bool nfc_scene_mf_classic_menu_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfClassicMenu, event.event); - if(event.event == SubmenuIndexSave) { - nfc->dev->format = NfcDeviceSaveFormatMifareClassic; - // 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, NfcSceneMfClassicEmulate); - if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) { - DOLPHIN_DEED(DolphinDeedNfcAddEmulate); - } else { - DOLPHIN_DEED(DolphinDeedNfcEmulate); - } - consumed = true; - } else if(event.event == SubmenuIndexDetectReader) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneDetectReader); - DOLPHIN_DEED(DolphinDeedNfcDetectReader); - consumed = true; - } else if(event.event == SubmenuIndexInfo) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); - consumed = true; - } - } else if(event.type == SceneManagerEventTypeBack) { - consumed = scene_manager_previous_scene(nfc->scene_manager); - } - - return consumed; -} - -void nfc_scene_mf_classic_menu_on_exit(void* context) { - NfcApp* nfc = context; - - // Clear view - submenu_reset(nfc->submenu); -} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_read_success.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_read_success.c deleted file mode 100644 index f0ab9397f5f7..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_read_success.c +++ /dev/null @@ -1,82 +0,0 @@ -#include "../nfc_app_i.h" - -void nfc_scene_mf_classic_read_success_widget_callback( - GuiButtonType result, - InputType type, - void* context) { - furi_assert(context); - NfcApp* nfc = context; - - if(type == InputTypeShort) { - view_dispatcher_send_custom_event(nfc->view_dispatcher, result); - } -} - -void nfc_scene_mf_classic_read_success_on_enter(void* context) { - NfcApp* nfc = context; - NfcDeviceData* dev_data = &nfc->dev->dev_data; - MfClassicData* mf_data = &dev_data->mf_classic_data; - - // Setup view - Widget* widget = nfc->widget; - widget_add_button_element( - widget, GuiButtonTypeLeft, "Retry", nfc_scene_mf_classic_read_success_widget_callback, nfc); - widget_add_button_element( - widget, GuiButtonTypeRight, "More", nfc_scene_mf_classic_read_success_widget_callback, nfc); - - FuriString* temp_str = NULL; - if(furi_string_size(nfc->dev->dev_data.parsed_data)) { - temp_str = furi_string_alloc_set(nfc->dev->dev_data.parsed_data); - } else { - temp_str = furi_string_alloc_printf("\e#%s\n", nfc_mf_classic_type(mf_data->type)); - furi_string_cat_printf(temp_str, "UID:"); - for(size_t i = 0; i < dev_data->nfc_data.uid_len; i++) { - furi_string_cat_printf(temp_str, " %02X", dev_data->nfc_data.uid[i]); - } - uint8_t sectors_total = mf_classic_get_total_sectors_num(mf_data->type); - uint8_t keys_total = sectors_total * 2; - uint8_t keys_found = 0; - uint8_t sectors_read = 0; - mf_classic_get_read_sectors_and_keys(mf_data, §ors_read, &keys_found); - furi_string_cat_printf(temp_str, "\nKeys Found: %d/%d", keys_found, keys_total); - furi_string_cat_printf(temp_str, "\nSectors Read: %d/%d", sectors_read, sectors_total); - } - - 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_mf_classic_read_success_on_event(void* context, SceneManagerEvent event) { - NfcApp* 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) { - // Clear device name - nfc_device_set_name(nfc->dev, ""); - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicMenu); - consumed = true; - } - } else if(event.type == SceneManagerEventTypeBack) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); - consumed = true; - } - - return consumed; -} - -void nfc_scene_mf_classic_read_success_on_exit(void* context) { - NfcApp* 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_mf_classic_update.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_update.c deleted file mode 100644 index 3819e799bb4c..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_update.c +++ /dev/null @@ -1,98 +0,0 @@ -#include "../nfc_app_i.h" -#include - -enum { - NfcSceneMfClassicUpdateStateCardSearch, - NfcSceneMfClassicUpdateStateCardFound, -}; - -bool nfc_mf_classic_update_worker_callback(NfcWorkerEvent event, void* context) { - furi_assert(context); - - NfcApp* nfc = context; - view_dispatcher_send_custom_event(nfc->view_dispatcher, event); - - return true; -} - -static void nfc_scene_mf_classic_update_setup_view(NfcApp* nfc) { - Popup* popup = nfc->popup; - popup_reset(popup); - uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicUpdate); - - if(state == NfcSceneMfClassicUpdateStateCardSearch) { - popup_set_text( - nfc->popup, "Apply the initial\ncard only", 128, 32, AlignRight, AlignCenter); - popup_set_icon(nfc->popup, 0, 8, &I_NFC_manual_60x50); - } else { - popup_set_header(popup, "Updating\nDon't move...", 52, 32, AlignLeft, AlignCenter); - popup_set_icon(popup, 12, 23, &A_Loading_24); - } - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); -} - -void nfc_scene_mf_classic_update_on_enter(void* context) { - NfcApp* nfc = context; - DOLPHIN_DEED(DolphinDeedNfcEmulate); - - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneMfClassicUpdate, NfcSceneMfClassicUpdateStateCardSearch); - nfc_scene_mf_classic_update_setup_view(nfc); - - // Setup and start worker - nfc_worker_start( - nfc->worker, - NfcWorkerStateMfClassicUpdate, - &nfc->dev->dev_data, - nfc_mf_classic_update_worker_callback, - nfc); - nfc_blink_emulate_start(nfc); -} - -bool nfc_scene_mf_classic_update_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == NfcWorkerEventSuccess) { - nfc_worker_stop(nfc->worker); - if(nfc_device_save_shadow(nfc->dev, furi_string_get_cstr(nfc->dev->load_path))) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicUpdateSuccess); - } else { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicWrongCard); - } - consumed = true; - } else if(event.event == NfcWorkerEventWrongCard) { - nfc_worker_stop(nfc->worker); - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicWrongCard); - consumed = true; - } else if(event.event == NfcWorkerEventCardDetected) { - scene_manager_set_scene_state( - nfc->scene_manager, - NfcSceneMfClassicUpdate, - NfcSceneMfClassicUpdateStateCardFound); - nfc_scene_mf_classic_update_setup_view(nfc); - consumed = true; - } else if(event.event == NfcWorkerEventNoCardDetected) { - scene_manager_set_scene_state( - nfc->scene_manager, - NfcSceneMfClassicUpdate, - NfcSceneMfClassicUpdateStateCardSearch); - nfc_scene_mf_classic_update_setup_view(nfc); - consumed = true; - } - } - return consumed; -} - -void nfc_scene_mf_classic_update_on_exit(void* context) { - NfcApp* nfc = context; - nfc_worker_stop(nfc->worker); - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneMfClassicUpdate, NfcSceneMfClassicUpdateStateCardSearch); - // Clear view - popup_reset(nfc->popup); - - nfc_blink_stop(nfc); -} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_update_success.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_update_success.c deleted file mode 100644 index f52114b161d9..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_update_success.c +++ /dev/null @@ -1,44 +0,0 @@ -#include "../nfc_app_i.h" -#include - -void nfc_scene_mf_classic_update_success_popup_callback(void* context) { - NfcApp* nfc = context; - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); -} - -void nfc_scene_mf_classic_update_success_on_enter(void* context) { - NfcApp* nfc = context; - DOLPHIN_DEED(DolphinDeedNfcSave); - - notification_message(nfc->notifications, &sequence_success); - - Popup* popup = nfc->popup; - popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); - popup_set_header(popup, "Updated!", 11, 20, AlignLeft, AlignBottom); - popup_set_timeout(popup, 1500); - popup_set_context(popup, nfc); - popup_set_callback(popup, nfc_scene_mf_classic_update_success_popup_callback); - popup_enable_timeout(popup); - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); -} - -bool nfc_scene_mf_classic_update_success_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == NfcCustomEventViewExit) { - consumed = scene_manager_search_and_switch_to_previous_scene( - nfc->scene_manager, NfcSceneFileSelect); - } - } - return consumed; -} - -void nfc_scene_mf_classic_update_success_on_exit(void* context) { - NfcApp* nfc = context; - - // Clear view - popup_reset(nfc->popup); -} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_write.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_write.c deleted file mode 100644 index d33fbc4106a9..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_write.c +++ /dev/null @@ -1,92 +0,0 @@ -#include "../nfc_app_i.h" -#include - -enum { - NfcSceneMfClassicWriteStateCardSearch, - NfcSceneMfClassicWriteStateCardFound, -}; - -bool nfc_mf_classic_write_worker_callback(NfcWorkerEvent event, void* context) { - furi_assert(context); - - NfcApp* nfc = context; - view_dispatcher_send_custom_event(nfc->view_dispatcher, event); - - return true; -} - -static void nfc_scene_mf_classic_write_setup_view(NfcApp* nfc) { - Popup* popup = nfc->popup; - popup_reset(popup); - uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicWrite); - - if(state == NfcSceneMfClassicWriteStateCardSearch) { - popup_set_text( - nfc->popup, "Apply the initial\ncard only", 128, 32, AlignRight, AlignCenter); - popup_set_icon(nfc->popup, 0, 8, &I_NFC_manual_60x50); - } else { - popup_set_header(popup, "Writing\nDon't move...", 52, 32, AlignLeft, AlignCenter); - popup_set_icon(popup, 12, 23, &A_Loading_24); - } - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); -} - -void nfc_scene_mf_classic_write_on_enter(void* context) { - NfcApp* nfc = context; - DOLPHIN_DEED(DolphinDeedNfcEmulate); - - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneMfClassicWrite, NfcSceneMfClassicWriteStateCardSearch); - nfc_scene_mf_classic_write_setup_view(nfc); - - // Setup and start worker - nfc_worker_start( - nfc->worker, - NfcWorkerStateMfClassicWrite, - &nfc->dev->dev_data, - nfc_mf_classic_write_worker_callback, - nfc); - nfc_blink_emulate_start(nfc); -} - -bool nfc_scene_mf_classic_write_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == NfcWorkerEventSuccess) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicWriteSuccess); - consumed = true; - } else if(event.event == NfcWorkerEventFail) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicWriteFail); - consumed = true; - } else if(event.event == NfcWorkerEventWrongCard) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicWrongCard); - consumed = true; - } else if(event.event == NfcWorkerEventCardDetected) { - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneMfClassicWrite, NfcSceneMfClassicWriteStateCardFound); - nfc_scene_mf_classic_write_setup_view(nfc); - consumed = true; - } else if(event.event == NfcWorkerEventNoCardDetected) { - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneMfClassicWrite, NfcSceneMfClassicWriteStateCardSearch); - nfc_scene_mf_classic_write_setup_view(nfc); - consumed = true; - } - } - return consumed; -} - -void nfc_scene_mf_classic_write_on_exit(void* context) { - NfcApp* nfc = context; - - nfc_worker_stop(nfc->worker); - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneMfClassicWrite, NfcSceneMfClassicWriteStateCardSearch); - // Clear view - popup_reset(nfc->popup); - - nfc_blink_stop(nfc); -} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_write_fail.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_write_fail.c deleted file mode 100644 index 695a3c4a7402..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_write_fail.c +++ /dev/null @@ -1,58 +0,0 @@ -#include "../nfc_app_i.h" - -void nfc_scene_mf_classic_write_fail_widget_callback( - GuiButtonType result, - InputType type, - void* context) { - NfcApp* nfc = context; - if(type == InputTypeShort) { - view_dispatcher_send_custom_event(nfc->view_dispatcher, result); - } -} - -void nfc_scene_mf_classic_write_fail_on_enter(void* context) { - NfcApp* nfc = context; - Widget* widget = nfc->widget; - - notification_message(nfc->notifications, &sequence_error); - - widget_add_icon_element(widget, 72, 17, &I_DolphinCommon_56x48); - widget_add_string_element( - widget, 7, 4, AlignLeft, AlignTop, FontPrimary, "Writing gone wrong!"); - widget_add_string_multiline_element( - widget, - 7, - 17, - AlignLeft, - AlignTop, - FontSecondary, - "Not all sectors\nwere written\ncorrectly."); - - widget_add_button_element( - widget, GuiButtonTypeLeft, "Finish", nfc_scene_mf_classic_write_fail_widget_callback, nfc); - - // Setup and start worker - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); -} - -bool nfc_scene_mf_classic_write_fail_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == GuiButtonTypeLeft) { - consumed = scene_manager_search_and_switch_to_previous_scene( - nfc->scene_manager, NfcSceneFileSelect); - } - } else if(event.type == SceneManagerEventTypeBack) { - consumed = scene_manager_search_and_switch_to_previous_scene( - nfc->scene_manager, NfcSceneSavedMenu); - } - return consumed; -} - -void nfc_scene_mf_classic_write_fail_on_exit(void* context) { - NfcApp* nfc = context; - - widget_reset(nfc->widget); -} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_write_success.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_write_success.c deleted file mode 100644 index 272d607dfb35..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_write_success.c +++ /dev/null @@ -1,44 +0,0 @@ -#include "../nfc_app_i.h" -#include - -void nfc_scene_mf_classic_write_success_popup_callback(void* context) { - NfcApp* nfc = context; - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); -} - -void nfc_scene_mf_classic_write_success_on_enter(void* context) { - NfcApp* nfc = context; - DOLPHIN_DEED(DolphinDeedNfcSave); - - notification_message(nfc->notifications, &sequence_success); - - Popup* popup = nfc->popup; - popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); - popup_set_header(popup, "Successfully\nwritten", 13, 22, AlignLeft, AlignBottom); - popup_set_timeout(popup, 1500); - popup_set_context(popup, nfc); - popup_set_callback(popup, nfc_scene_mf_classic_write_success_popup_callback); - popup_enable_timeout(popup); - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); -} - -bool nfc_scene_mf_classic_write_success_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == NfcCustomEventViewExit) { - consumed = scene_manager_search_and_switch_to_previous_scene( - nfc->scene_manager, NfcSceneFileSelect); - } - } - return consumed; -} - -void nfc_scene_mf_classic_write_success_on_exit(void* context) { - NfcApp* nfc = context; - - // Clear view - popup_reset(nfc->popup); -} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_wrong_card.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_wrong_card.c deleted file mode 100644 index ac7d6593470d..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_wrong_card.c +++ /dev/null @@ -1,53 +0,0 @@ -#include "../nfc_app_i.h" - -void nfc_scene_mf_classic_wrong_card_widget_callback( - GuiButtonType result, - InputType type, - void* context) { - NfcApp* nfc = context; - if(type == InputTypeShort) { - view_dispatcher_send_custom_event(nfc->view_dispatcher, result); - } -} - -void nfc_scene_mf_classic_wrong_card_on_enter(void* context) { - NfcApp* nfc = context; - Widget* widget = nfc->widget; - - notification_message(nfc->notifications, &sequence_error); - - widget_add_icon_element(widget, 73, 17, &I_DolphinCommon_56x48); - widget_add_string_element( - widget, 3, 4, AlignLeft, AlignTop, FontPrimary, "This is wrong card"); - widget_add_string_multiline_element( - widget, - 4, - 17, - AlignLeft, - AlignTop, - FontSecondary, - "Data management\nis only possible\nwith initial card"); - widget_add_button_element( - widget, GuiButtonTypeLeft, "Retry", nfc_scene_mf_classic_wrong_card_widget_callback, nfc); - - // Setup and start worker - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); -} - -bool nfc_scene_mf_classic_wrong_card_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == GuiButtonTypeLeft) { - consumed = scene_manager_previous_scene(nfc->scene_manager); - } - } - return consumed; -} - -void nfc_scene_mf_classic_wrong_card_on_exit(void* context) { - NfcApp* nfc = context; - - widget_reset(nfc->widget); -} \ No newline at end of file diff --git a/applications/main/nfc/scenes/nfc_scene_mf_desfire_app.c b/applications/main/nfc/scenes/nfc_scene_mf_desfire_app.c deleted file mode 100644 index 2c856157270d..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_mf_desfire_app.c +++ /dev/null @@ -1,120 +0,0 @@ -#include "../nfc_app_i.h" - -#define TAG "NfcSceneMfDesfireApp" - -enum SubmenuIndex { - SubmenuIndexAppInfo, - SubmenuIndexDynamic, // dynamic indexes start here -}; - -void nfc_scene_mf_desfire_popup_callback(void* context) { - furi_assert(context); - - NfcApp* nfc = context; - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); -} - -MifareDesfireApplication* nfc_scene_mf_desfire_app_get_app(NfcApp* nfc) { - uint32_t app_idx = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireApp) >> - 1; - MifareDesfireApplication* app = nfc->dev->dev_data.mf_df_data.app_head; - for(uint32_t i = 0; i < app_idx && app; i++) { - app = app->next; - } - return app; -} - -void nfc_scene_mf_desfire_app_submenu_callback(void* context, uint32_t index) { - NfcApp* nfc = context; - - view_dispatcher_send_custom_event(nfc->view_dispatcher, index); -} - -void nfc_scene_mf_desfire_app_on_enter(void* context) { - NfcApp* nfc = context; - MifareDesfireApplication* app = nfc_scene_mf_desfire_app_get_app(nfc); - if(!app) { - popup_set_icon(nfc->popup, 5, 5, &I_WarningDolphin_45x42); - popup_set_header(nfc->popup, "Empty card!", 55, 12, AlignLeft, AlignBottom); - popup_set_callback(nfc->popup, nfc_scene_mf_desfire_popup_callback); - popup_set_context(nfc->popup, nfc); - popup_set_timeout(nfc->popup, 3000); - popup_enable_timeout(nfc->popup); - popup_set_text(nfc->popup, "No application\nfound.", 55, 15, AlignLeft, AlignTop); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); - } else { - text_box_set_font(nfc->text_box, TextBoxFontHex); - submenu_add_item( - nfc->submenu, - "App info", - SubmenuIndexAppInfo, - nfc_scene_mf_desfire_app_submenu_callback, - nfc); - - FuriString* label = furi_string_alloc(); - int idx = SubmenuIndexDynamic; - for(MifareDesfireFile* file = app->file_head; file; file = file->next) { - furi_string_printf(label, "File %d", file->id); - submenu_add_item( - nfc->submenu, - furi_string_get_cstr(label), - idx++, - nfc_scene_mf_desfire_app_submenu_callback, - nfc); - } - furi_string_free(label); - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); - } -} - -bool nfc_scene_mf_desfire_app_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - bool consumed = false; - uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireApp); - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == NfcCustomEventViewExit) { - consumed = scene_manager_previous_scene(nfc->scene_manager); - } else { - MifareDesfireApplication* app = nfc_scene_mf_desfire_app_get_app(nfc); - TextBox* text_box = nfc->text_box; - furi_string_reset(nfc->text_box_store); - if(event.event == SubmenuIndexAppInfo) { - mf_df_cat_application_info(app, nfc->text_box_store); - } else { - uint16_t index = event.event - SubmenuIndexDynamic; - MifareDesfireFile* file = app->file_head; - for(int i = 0; file && i < index; i++) { - file = file->next; - } - if(!file) { - return false; - } - mf_df_cat_file(file, nfc->text_box_store); - } - text_box_set_text(text_box, furi_string_get_cstr(nfc->text_box_store)); - scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfDesfireApp, state | 1); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); - 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, NfcSceneMfDesfireApp, state & ~1); - consumed = true; - } - } - - return consumed; -} - -void nfc_scene_mf_desfire_app_on_exit(void* context) { - NfcApp* nfc = context; - - // Clear views - popup_reset(nfc->popup); - text_box_reset(nfc->text_box); - furi_string_reset(nfc->text_box_store); - submenu_reset(nfc->submenu); -} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_desfire_data.c b/applications/main/nfc/scenes/nfc_scene_mf_desfire_data.c deleted file mode 100644 index e9e529909dc5..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_mf_desfire_data.c +++ /dev/null @@ -1,104 +0,0 @@ -#include "../nfc_app_i.h" - -#define TAG "NfcSceneMfDesfireData" - -enum { - MifareDesfireDataStateMenu, - MifareDesfireDataStateItem, // MUST be last, states >= this correspond with submenu index -}; - -enum SubmenuIndex { - SubmenuIndexCardInfo, - SubmenuIndexDynamic, // dynamic indexes start here -}; - -void nfc_scene_mf_desfire_data_submenu_callback(void* context, uint32_t index) { - NfcApp* nfc = (NfcApp*)context; - - view_dispatcher_send_custom_event(nfc->view_dispatcher, index); -} - -void nfc_scene_mf_desfire_data_on_enter(void* context) { - NfcApp* nfc = context; - Submenu* submenu = nfc->submenu; - uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireData); - MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data; - - text_box_set_font(nfc->text_box, TextBoxFontHex); - - submenu_add_item( - submenu, - "Card info", - SubmenuIndexCardInfo, - nfc_scene_mf_desfire_data_submenu_callback, - nfc); - - FuriString* label = furi_string_alloc(); - int idx = SubmenuIndexDynamic; - for(MifareDesfireApplication* app = data->app_head; app; app = app->next) { - furi_string_printf(label, "App %02x%02x%02x", app->id[0], app->id[1], app->id[2]); - submenu_add_item( - submenu, - furi_string_get_cstr(label), - idx++, - nfc_scene_mf_desfire_data_submenu_callback, - nfc); - } - furi_string_free(label); - - if(state >= MifareDesfireDataStateItem) { - submenu_set_selected_item( - nfc->submenu, state - MifareDesfireDataStateItem + SubmenuIndexDynamic); - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneMfDesfireData, MifareDesfireDataStateMenu); - } - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); -} - -bool nfc_scene_mf_desfire_data_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - bool consumed = false; - uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireData); - MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data; - - if(event.type == SceneManagerEventTypeCustom) { - TextBox* text_box = nfc->text_box; - furi_string_reset(nfc->text_box_store); - if(event.event == SubmenuIndexCardInfo) { - mf_df_cat_card_info(data, nfc->text_box_store); - text_box_set_text(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, - NfcSceneMfDesfireData, - MifareDesfireDataStateItem + SubmenuIndexCardInfo); - consumed = true; - } else { - uint16_t index = event.event - SubmenuIndexDynamic; - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneMfDesfireData, MifareDesfireDataStateItem + index); - scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfDesfireApp, index << 1); - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireApp); - consumed = true; - } - } else if(event.type == SceneManagerEventTypeBack) { - if(state >= MifareDesfireDataStateItem) { - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneMfDesfireData, MifareDesfireDataStateMenu); - consumed = true; - } - } - - return consumed; -} - -void nfc_scene_mf_desfire_data_on_exit(void* context) { - NfcApp* nfc = context; - - // Clear views - text_box_reset(nfc->text_box); - furi_string_reset(nfc->text_box_store); - submenu_reset(nfc->submenu); -} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_desfire_menu.c b/applications/main/nfc/scenes/nfc_scene_mf_desfire_menu.c deleted file mode 100644 index b3ebe9a469a9..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_mf_desfire_menu.c +++ /dev/null @@ -1,72 +0,0 @@ -#include "../nfc_app_i.h" -#include - -enum SubmenuIndex { - SubmenuIndexSave, - SubmenuIndexEmulateUid, - SubmenuIndexInfo, -}; - -void nfc_scene_mf_desfire_menu_submenu_callback(void* context, uint32_t index) { - NfcApp* nfc = context; - - view_dispatcher_send_custom_event(nfc->view_dispatcher, index); -} - -void nfc_scene_mf_desfire_menu_on_enter(void* context) { - NfcApp* nfc = context; - Submenu* submenu = nfc->submenu; - - submenu_add_item( - submenu, "Save", SubmenuIndexSave, nfc_scene_mf_desfire_menu_submenu_callback, nfc); - submenu_add_item( - submenu, - "Emulate UID", - SubmenuIndexEmulateUid, - nfc_scene_mf_desfire_menu_submenu_callback, - nfc); - submenu_add_item( - submenu, "Info", SubmenuIndexInfo, nfc_scene_mf_desfire_menu_submenu_callback, nfc); - - submenu_set_selected_item( - nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireMenu)); - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); -} - -bool nfc_scene_mf_desfire_menu_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == SubmenuIndexSave) { - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneMfDesfireMenu, SubmenuIndexSave); - nfc->dev->format = NfcDeviceSaveFormatMifareDesfire; - // Clear device name - nfc_device_set_name(nfc->dev, ""); - scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); - consumed = true; - } else if(event.event == SubmenuIndexEmulateUid) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); - if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) { - DOLPHIN_DEED(DolphinDeedNfcAddEmulate); - } else { - DOLPHIN_DEED(DolphinDeedNfcEmulate); - } - consumed = true; - } else if(event.event == SubmenuIndexInfo) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); - consumed = true; - } - } - - return consumed; -} - -void nfc_scene_mf_desfire_menu_on_exit(void* context) { - NfcApp* nfc = context; - - // Clear view - submenu_reset(nfc->submenu); -} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_desfire_read_success.c b/applications/main/nfc/scenes/nfc_scene_mf_desfire_read_success.c deleted file mode 100644 index 919070595dbe..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_mf_desfire_read_success.c +++ /dev/null @@ -1,96 +0,0 @@ -#include "../nfc_app_i.h" -#include - -void nfc_scene_mf_desfire_read_success_widget_callback( - GuiButtonType result, - InputType type, - void* context) { - NfcApp* nfc = context; - - if(type == InputTypeShort) { - view_dispatcher_send_custom_event(nfc->view_dispatcher, result); - } -} - -void nfc_scene_mf_desfire_read_success_on_enter(void* context) { - NfcApp* nfc = context; - - FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data; - MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data; - Widget* widget = nfc->widget; - - // Prepare string for data display - FuriString* temp_str = furi_string_alloc_printf("\e#MIFARE DESfire\n"); - 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]); - } - - uint32_t bytes_total = 1UL << (data->version.sw_storage >> 1); - uint32_t bytes_free = data->free_memory ? data->free_memory->bytes : 0; - furi_string_cat_printf(temp_str, "\n%lu", bytes_total); - if(data->version.sw_storage & 1) { - furi_string_push_back(temp_str, '+'); - } - furi_string_cat_printf(temp_str, " bytes, %lu bytes free\n", bytes_free); - - uint16_t n_apps = 0; - uint16_t n_files = 0; - for(MifareDesfireApplication* app = data->app_head; app; app = app->next) { - n_apps++; - for(MifareDesfireFile* file = app->file_head; file; file = file->next) { - n_files++; - } - } - furi_string_cat_printf(temp_str, "%d Application", n_apps); - if(n_apps != 1) { - furi_string_push_back(temp_str, 's'); - } - furi_string_cat_printf(temp_str, ", %d file", n_files); - if(n_files != 1) { - furi_string_push_back(temp_str, 's'); - } - - notification_message_block(nfc->notifications, &sequence_set_green_255); - - // Add text scroll element - widget_add_text_scroll_element(widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); - furi_string_free(temp_str); - - // Add button elements - widget_add_button_element( - widget, GuiButtonTypeLeft, "Retry", nfc_scene_mf_desfire_read_success_widget_callback, nfc); - widget_add_button_element( - widget, GuiButtonTypeRight, "More", nfc_scene_mf_desfire_read_success_widget_callback, nfc); - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); -} - -bool nfc_scene_mf_desfire_read_success_on_event(void* context, SceneManagerEvent event) { - NfcApp* 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, NfcSceneMfDesfireMenu); - consumed = true; - } - } else if(event.type == SceneManagerEventTypeBack) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); - consumed = true; - } - - return consumed; -} - -void nfc_scene_mf_desfire_read_success_on_exit(void* context) { - NfcApp* nfc = context; - - notification_message_block(nfc->notifications, &sequence_reset_green); - - // Clean dialog - widget_reset(nfc->widget); -} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_data.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_data.c deleted file mode 100644 index 7d56cb1483eb..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_data.c +++ /dev/null @@ -1,32 +0,0 @@ -#include "../nfc_app_i.h" - -void nfc_scene_mf_ultralight_data_on_enter(void* context) { - NfcApp* nfc = context; - MfUltralightData* data = &nfc->dev->dev_data.mf_ul_data; - TextBox* text_box = nfc->text_box; - - text_box_set_font(text_box, TextBoxFontHex); - for(uint16_t i = 0; i < data->data_size; i += 2) { - if(!(i % 8) && i) { - furi_string_push_back(nfc->text_box_store, '\n'); - } - furi_string_cat_printf(nfc->text_box_store, "%02X%02X ", data->data[i], data->data[i + 1]); - } - text_box_set_text(text_box, furi_string_get_cstr(nfc->text_box_store)); - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); -} - -bool nfc_scene_mf_ultralight_data_on_event(void* context, SceneManagerEvent event) { - UNUSED(context); - UNUSED(event); - return false; -} - -void nfc_scene_mf_ultralight_data_on_exit(void* context) { - NfcApp* nfc = context; - - // Clean view - text_box_reset(nfc->text_box); - furi_string_reset(nfc->text_box_store); -} \ No newline at end of file diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_emulate.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_emulate.c deleted file mode 100644 index 192d67bef73e..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_emulate.c +++ /dev/null @@ -1,74 +0,0 @@ -#include "../nfc_app_i.h" - -#define NFC_MF_UL_DATA_NOT_CHANGED (0UL) -#define NFC_MF_UL_DATA_CHANGED (1UL) - -bool nfc_mf_ultralight_emulate_worker_callback(NfcWorkerEvent event, void* context) { - UNUSED(event); - NfcApp* nfc = context; - - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneMfUltralightEmulate, NFC_MF_UL_DATA_CHANGED); - return true; -} - -void nfc_scene_mf_ultralight_emulate_on_enter(void* context) { - NfcApp* nfc = context; - - // Setup view - MfUltralightType type = nfc->dev->dev_data.mf_ul_data.type; - bool is_ultralight = (type == MfUltralightTypeUL11) || (type == MfUltralightTypeUL21) || - (type == MfUltralightTypeUnknown); - Popup* popup = nfc->popup; - popup_set_header(popup, "Emulating", 67, 13, AlignLeft, AlignTop); - if(strcmp(nfc->dev->dev_name, "") != 0) { - nfc_text_store_set(nfc, "%s", nfc->dev->dev_name); - } else if(is_ultralight) { - nfc_text_store_set(nfc, "MIFARE\nUltralight"); - } else { - nfc_text_store_set(nfc, "MIFARE\nNTAG"); - } - popup_set_icon(popup, 0, 3, &I_NFC_dolphin_emulation_47x61); - popup_set_text(popup, nfc->text_store, 90, 28, AlignCenter, AlignTop); - - // Setup and start worker - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); - nfc_worker_start( - nfc->worker, - NfcWorkerStateMfUltralightEmulate, - &nfc->dev->dev_data, - nfc_mf_ultralight_emulate_worker_callback, - nfc); - nfc_blink_emulate_start(nfc); -} - -bool nfc_scene_mf_ultralight_emulate_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeBack) { - // Stop worker - nfc_worker_stop(nfc->worker); - // Check if data changed and save in shadow file - if(scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightEmulate) == - NFC_MF_UL_DATA_CHANGED) { - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneMfUltralightEmulate, NFC_MF_UL_DATA_NOT_CHANGED); - // Save shadow file - if(furi_string_size(nfc->dev->load_path)) { - nfc_device_save_shadow(nfc->dev, furi_string_get_cstr(nfc->dev->load_path)); - } - } - consumed = false; - } - return consumed; -} - -void nfc_scene_mf_ultralight_emulate_on_exit(void* context) { - NfcApp* nfc = context; - - // Clear view - popup_reset(nfc->popup); - - nfc_blink_stop(nfc); -} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_key_input.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_key_input.c deleted file mode 100644 index e8c87693d462..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_key_input.c +++ /dev/null @@ -1,44 +0,0 @@ -#include "../nfc_app_i.h" - -void nfc_scene_mf_ultralight_key_input_byte_input_callback(void* context) { - NfcApp* nfc = context; - - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); -} - -void nfc_scene_mf_ultralight_key_input_on_enter(void* context) { - NfcApp* nfc = context; - - // Setup view - ByteInput* byte_input = nfc->byte_input; - byte_input_set_header_text(byte_input, "Enter the password in hex"); - byte_input_set_result_callback( - byte_input, - nfc_scene_mf_ultralight_key_input_byte_input_callback, - NULL, - nfc, - nfc->byte_input_store, - 4); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewByteInput); -} - -bool nfc_scene_mf_ultralight_key_input_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == NfcCustomEventByteInputDone) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockWarn); - consumed = true; - } - } - return consumed; -} - -void nfc_scene_mf_ultralight_key_input_on_exit(void* context) { - NfcApp* nfc = context; - - // Clear view - byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0); - byte_input_set_header_text(nfc->byte_input, ""); -} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c deleted file mode 100644 index 6069ed356c8f..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c +++ /dev/null @@ -1,87 +0,0 @@ -#include "../nfc_app_i.h" -#include - -enum SubmenuIndex { - SubmenuIndexUnlock, - SubmenuIndexSave, - SubmenuIndexEmulate, - SubmenuIndexInfo, -}; - -void nfc_scene_mf_ultralight_menu_submenu_callback(void* context, uint32_t index) { - NfcApp* nfc = context; - - view_dispatcher_send_custom_event(nfc->view_dispatcher, index); -} - -void nfc_scene_mf_ultralight_menu_on_enter(void* context) { - NfcApp* nfc = context; - Submenu* submenu = nfc->submenu; - MfUltralightData* data = &nfc->dev->dev_data.mf_ul_data; - - if(!mf_ul_is_full_capture(data)) { - submenu_add_item( - submenu, - "Unlock", - SubmenuIndexUnlock, - nfc_scene_mf_ultralight_menu_submenu_callback, - nfc); - } - submenu_add_item( - submenu, "Save", SubmenuIndexSave, nfc_scene_mf_ultralight_menu_submenu_callback, nfc); - submenu_add_item( - submenu, - "Emulate", - SubmenuIndexEmulate, - nfc_scene_mf_ultralight_menu_submenu_callback, - nfc); - submenu_add_item( - submenu, "Info", SubmenuIndexInfo, nfc_scene_mf_ultralight_menu_submenu_callback, nfc); - - submenu_set_selected_item( - nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightMenu)); - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); -} - -bool nfc_scene_mf_ultralight_menu_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == SubmenuIndexSave) { - nfc->dev->format = NfcDeviceSaveFormatMifareUl; - // 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, NfcSceneMfUltralightEmulate); - 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, NfcSceneMfUltralightUnlockMenu); - 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, NfcSceneMfUltralightMenu, event.event); - - } else if(event.type == SceneManagerEventTypeBack) { - consumed = scene_manager_previous_scene(nfc->scene_manager); - } - - return consumed; -} - -void nfc_scene_mf_ultralight_menu_on_exit(void* context) { - NfcApp* nfc = context; - - // Clear view - submenu_reset(nfc->submenu); -} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_auth.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_auth.c deleted file mode 100644 index 4d549989ab4a..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_auth.c +++ /dev/null @@ -1,116 +0,0 @@ -#include "../nfc_app_i.h" - -typedef enum { - NfcSceneMfUlReadStateIdle, - NfcSceneMfUlReadStateDetecting, - NfcSceneMfUlReadStateReading, - NfcSceneMfUlReadStateNotSupportedCard, -} NfcSceneMfUlReadState; - -bool nfc_scene_mf_ultralight_read_auth_worker_callback(NfcWorkerEvent event, void* context) { - NfcApp* nfc = context; - - if(event == NfcWorkerEventMfUltralightPassKey) { - memcpy(nfc->dev->dev_data.mf_ul_data.auth_key, nfc->byte_input_store, 4); - } else { - view_dispatcher_send_custom_event(nfc->view_dispatcher, event); - } - return true; -} - -void nfc_scene_mf_ultralight_read_auth_set_state(NfcApp* nfc, NfcSceneMfUlReadState state) { - uint32_t curr_state = - scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightReadAuth); - if(curr_state != state) { - if(state == NfcSceneMfUlReadStateDetecting) { - popup_reset(nfc->popup); - popup_set_text(nfc->popup, "Apply the\ntarget card", 97, 24, AlignCenter, AlignTop); - popup_set_icon(nfc->popup, 0, 8, &I_NFC_manual_60x50); - nfc_blink_read_start(nfc); - } else if(state == NfcSceneMfUlReadStateReading) { - popup_reset(nfc->popup); - popup_set_header( - nfc->popup, "Reading card\nDon't move...", 85, 24, AlignCenter, AlignTop); - popup_set_icon(nfc->popup, 12, 23, &A_Loading_24); - nfc_blink_detect_start(nfc); - } else if(state == NfcSceneMfUlReadStateNotSupportedCard) { - popup_reset(nfc->popup); - popup_set_header(nfc->popup, "Wrong type of card!", 64, 3, AlignCenter, AlignTop); - popup_set_text( - nfc->popup, - "Only MIFARE\nUltralight & NTAG\nare supported", - 4, - 22, - AlignLeft, - AlignTop); - popup_set_icon(nfc->popup, 73, 20, &I_DolphinCommon_56x48); - nfc_blink_stop(nfc); - notification_message(nfc->notifications, &sequence_error); - notification_message(nfc->notifications, &sequence_set_red_255); - } - scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfUltralightReadAuth, state); - } -} - -void nfc_scene_mf_ultralight_read_auth_on_enter(void* context) { - NfcApp* nfc = context; - - nfc_device_clear(nfc->dev); - // Setup view - nfc_scene_mf_ultralight_read_auth_set_state(nfc, NfcSceneMfUlReadStateDetecting); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); - // Start worker - nfc_worker_start( - nfc->worker, - NfcWorkerStateReadMfUltralightReadAuth, - &nfc->dev->dev_data, - nfc_scene_mf_ultralight_read_auth_worker_callback, - nfc); -} - -bool nfc_scene_mf_ultralight_read_auth_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if((event.event == NfcWorkerEventSuccess) || (event.event == NfcWorkerEventFail)) { - notification_message(nfc->notifications, &sequence_success); - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadAuthResult); - consumed = true; - } else if(event.event == NfcWorkerEventCardDetected) { - nfc_scene_mf_ultralight_read_auth_set_state(nfc, NfcSceneMfUlReadStateReading); - consumed = true; - } else if(event.event == NfcWorkerEventNoCardDetected) { - nfc_scene_mf_ultralight_read_auth_set_state(nfc, NfcSceneMfUlReadStateDetecting); - consumed = true; - } else if(event.event == NfcWorkerEventWrongCardDetected) { - nfc_scene_mf_ultralight_read_auth_set_state( - nfc, NfcSceneMfUlReadStateNotSupportedCard); - } - } else if(event.type == SceneManagerEventTypeBack) { - MfUltralightData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data; - NfcScene next_scene; - if(mf_ul_data->auth_method == MfUltralightAuthMethodManual) { - next_scene = NfcSceneMfUltralightKeyInput; - } else if(mf_ul_data->auth_method == MfUltralightAuthMethodAuto) { - next_scene = NfcSceneMfUltralightUnlockAuto; - } else { - next_scene = NfcSceneMfUltralightUnlockMenu; - } - consumed = - scene_manager_search_and_switch_to_previous_scene(nfc->scene_manager, next_scene); - } - return consumed; -} - -void nfc_scene_mf_ultralight_read_auth_on_exit(void* context) { - NfcApp* nfc = context; - - // Stop worker - nfc_worker_stop(nfc->worker); - // Clear view - popup_reset(nfc->popup); - nfc_blink_stop(nfc); - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneMfUltralightReadAuth, NfcSceneMfUlReadStateIdle); -} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_auth_result.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_auth_result.c deleted file mode 100644 index c3ea1522fac3..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_auth_result.c +++ /dev/null @@ -1,116 +0,0 @@ -#include "../nfc_app_i.h" - -void nfc_scene_mf_ultralight_read_auth_result_widget_callback( - GuiButtonType result, - InputType type, - void* context) { - NfcApp* nfc = context; - - if(type == InputTypeShort) { - view_dispatcher_send_custom_event(nfc->view_dispatcher, result); - } -} - -void nfc_scene_mf_ultralight_read_auth_result_on_enter(void* context) { - NfcApp* nfc = context; - - // Setup dialog view - FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data; - MfUltralightData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data; - MfUltralightConfigPages* config_pages = mf_ultralight_get_config_pages(mf_ul_data); - Widget* widget = nfc->widget; - const char* title; - FuriString* temp_str; - temp_str = furi_string_alloc(); - - if((mf_ul_data->data_read == mf_ul_data->data_size) && (mf_ul_data->data_read > 0)) { - if(mf_ul_data->auth_success) { - title = "All pages are unlocked!"; - } else { - title = "All unlocked but failed auth!"; - } - } else { - title = "Not all pages unlocked!"; - } - widget_add_string_element(widget, 64, 0, AlignCenter, AlignTop, FontPrimary, title); - furi_string_set(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]); - } - widget_add_string_element( - widget, 0, 17, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(temp_str)); - if(mf_ul_data->auth_success) { - furi_string_printf( - temp_str, - "Password: %02X %02X %02X %02X", - config_pages->auth_data.pwd.raw[0], - config_pages->auth_data.pwd.raw[1], - config_pages->auth_data.pwd.raw[2], - config_pages->auth_data.pwd.raw[3]); - widget_add_string_element( - widget, 0, 28, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(temp_str)); - furi_string_printf( - temp_str, - "PACK: %02X %02X", - config_pages->auth_data.pack.raw[0], - config_pages->auth_data.pack.raw[1]); - widget_add_string_element( - widget, 0, 39, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(temp_str)); - } - furi_string_printf( - temp_str, "Pages Read: %d/%d", mf_ul_data->data_read / 4, mf_ul_data->data_size / 4); - widget_add_string_element( - widget, 0, 50, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(temp_str)); - widget_add_button_element( - widget, - GuiButtonTypeRight, - "Save", - nfc_scene_mf_ultralight_read_auth_result_widget_callback, - nfc); - - furi_string_free(temp_str); - notification_message(nfc->notifications, &sequence_set_green_255); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); -} - -bool nfc_scene_mf_ultralight_read_auth_result_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == GuiButtonTypeRight) { - nfc->dev->format = NfcDeviceSaveFormatMifareUl; - // Clear device name - nfc_device_set_name(nfc->dev, ""); - scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); - consumed = true; - } - } else if(event.type == SceneManagerEventTypeBack) { - MfUltralightData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data; - if(mf_ul_data->auth_method == MfUltralightAuthMethodManual || - mf_ul_data->auth_method == MfUltralightAuthMethodAuto) { - consumed = scene_manager_previous_scene(nfc->scene_manager); - } else { - NfcScene next_scene; - if((mf_ul_data->data_read == mf_ul_data->data_size) && (mf_ul_data->data_read > 0)) { - next_scene = NfcSceneMfUltralightMenu; - } else { - next_scene = NfcSceneMfUltralightUnlockMenu; - } - - consumed = - scene_manager_search_and_switch_to_previous_scene(nfc->scene_manager, next_scene); - } - } - - return consumed; -} - -void nfc_scene_mf_ultralight_read_auth_result_on_exit(void* context) { - NfcApp* nfc = context; - - // Clean views - widget_reset(nfc->widget); - - notification_message_block(nfc->notifications, &sequence_reset_green); -} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_success.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_success.c deleted file mode 100644 index 60c8191e5a10..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_success.c +++ /dev/null @@ -1,84 +0,0 @@ -#include "../nfc_app_i.h" - -void nfc_scene_mf_ultralight_read_success_widget_callback( - GuiButtonType result, - InputType type, - void* context) { - NfcApp* nfc = context; - - if(type == InputTypeShort) { - view_dispatcher_send_custom_event(nfc->view_dispatcher, result); - } -} - -void nfc_scene_mf_ultralight_read_success_on_enter(void* context) { - NfcApp* nfc = context; - - // Setup widget view - FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; - MfUltralightData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data; - Widget* widget = nfc->widget; - widget_add_button_element( - widget, - GuiButtonTypeLeft, - "Retry", - nfc_scene_mf_ultralight_read_success_widget_callback, - nfc); - widget_add_button_element( - widget, - GuiButtonTypeRight, - "More", - nfc_scene_mf_ultralight_read_success_widget_callback, - nfc); - - FuriString* temp_str = NULL; - if(furi_string_size(nfc->dev->dev_data.parsed_data)) { - temp_str = furi_string_alloc_set(nfc->dev->dev_data.parsed_data); - } else { - temp_str = furi_string_alloc_printf("\e#%s\n", nfc_mf_ul_type(mf_ul_data->type, true)); - furi_string_cat_printf(temp_str, "UID:"); - for(size_t i = 0; i < data->uid_len; i++) { - furi_string_cat_printf(temp_str, " %02X", data->uid[i]); - } - furi_string_cat_printf( - temp_str, "\nPages Read: %d/%d", mf_ul_data->data_read / 4, mf_ul_data->data_size / 4); - if(mf_ul_data->data_read != mf_ul_data->data_size) { - furi_string_cat_printf(temp_str, "\nPassword-protected pages!"); - } - } - 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_mf_ultralight_read_success_on_event(void* context, SceneManagerEvent event) { - NfcApp* 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, NfcSceneMfUltralightMenu); - consumed = true; - } - } else if(event.type == SceneManagerEventTypeBack) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); - consumed = true; - } - - return consumed; -} - -void nfc_scene_mf_ultralight_read_success_on_exit(void* context) { - NfcApp* nfc = context; - - notification_message_block(nfc->notifications, &sequence_reset_green); - - // Clean view - widget_reset(nfc->widget); -} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_auto.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_auto.c deleted file mode 100644 index 24f1703a28f5..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_auto.c +++ /dev/null @@ -1,64 +0,0 @@ -#include "../nfc_app_i.h" - -bool nfc_scene_mf_ultralight_unlock_auto_worker_callback(NfcWorkerEvent event, void* context) { - NfcApp* nfc = context; - - view_dispatcher_send_custom_event(nfc->view_dispatcher, event); - return true; -} - -void nfc_scene_mf_ultralight_unlock_auto_on_enter(void* context) { - NfcApp* nfc = context; - - // Setup view - widget_add_string_multiline_element( - nfc->widget, - 54, - 30, - AlignLeft, - AlignCenter, - FontPrimary, - "Touch the\nreader to get\npassword..."); - widget_add_icon_element(nfc->widget, 0, 15, &I_Modern_reader_18x34); - widget_add_icon_element(nfc->widget, 20, 12, &I_Move_flipper_26x39); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); - - // Start worker - nfc_worker_start( - nfc->worker, - NfcWorkerStateMfUltralightEmulate, - &nfc->dev->dev_data, - nfc_scene_mf_ultralight_unlock_auto_worker_callback, - nfc); - - nfc_blink_read_start(nfc); -} - -bool nfc_scene_mf_ultralight_unlock_auto_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if((event.event == NfcWorkerEventMfUltralightPwdAuth)) { - MfUltralightAuth* auth = &nfc->dev->dev_data.mf_ul_auth; - memcpy(nfc->byte_input_store, auth->pwd.raw, sizeof(auth->pwd.raw)); - nfc->dev->dev_data.mf_ul_data.auth_method = MfUltralightAuthMethodAuto; - nfc_worker_stop(nfc->worker); - notification_message(nfc->notifications, &sequence_success); - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockWarn); - consumed = true; - } - } - return consumed; -} - -void nfc_scene_mf_ultralight_unlock_auto_on_exit(void* context) { - NfcApp* nfc = context; - - // Stop worker - nfc_worker_stop(nfc->worker); - // Clear view - widget_reset(nfc->widget); - - nfc_blink_stop(nfc); -} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_menu.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_menu.c deleted file mode 100644 index 5c0604d383c4..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_menu.c +++ /dev/null @@ -1,83 +0,0 @@ -#include "../nfc_app_i.h" - -enum SubmenuIndex { - SubmenuIndexMfUlUnlockMenuAuto, - SubmenuIndexMfUlUnlockMenuAmeebo, - SubmenuIndexMfUlUnlockMenuXiaomi, - SubmenuIndexMfUlUnlockMenuManual, -}; - -void nfc_scene_mf_ultralight_unlock_menu_submenu_callback(void* context, uint32_t index) { - NfcApp* nfc = context; - - view_dispatcher_send_custom_event(nfc->view_dispatcher, index); -} - -void nfc_scene_mf_ultralight_unlock_menu_on_enter(void* context) { - NfcApp* nfc = context; - Submenu* submenu = nfc->submenu; - - uint32_t state = - scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightUnlockMenu); - if(nfc->dev->dev_data.protocol == NfcDeviceProtocolMifareUl) { - submenu_add_item( - submenu, - "Unlock With Reader", - SubmenuIndexMfUlUnlockMenuAuto, - nfc_scene_mf_ultralight_unlock_menu_submenu_callback, - nfc); - } - submenu_add_item( - submenu, - "Auth As Ameebo", - SubmenuIndexMfUlUnlockMenuAmeebo, - nfc_scene_mf_ultralight_unlock_menu_submenu_callback, - nfc); - submenu_add_item( - submenu, - "Auth As Xiaomi Air Purifier", - SubmenuIndexMfUlUnlockMenuXiaomi, - nfc_scene_mf_ultralight_unlock_menu_submenu_callback, - nfc); - submenu_add_item( - submenu, - "Enter Password Manually", - SubmenuIndexMfUlUnlockMenuManual, - nfc_scene_mf_ultralight_unlock_menu_submenu_callback, - nfc); - submenu_set_selected_item(submenu, state); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); -} - -bool nfc_scene_mf_ultralight_unlock_menu_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == SubmenuIndexMfUlUnlockMenuManual) { - nfc->dev->dev_data.mf_ul_data.auth_method = MfUltralightAuthMethodManual; - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightKeyInput); - consumed = true; - } else if(event.event == SubmenuIndexMfUlUnlockMenuAmeebo) { - nfc->dev->dev_data.mf_ul_data.auth_method = MfUltralightAuthMethodAmeebo; - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockWarn); - consumed = true; - } else if(event.event == SubmenuIndexMfUlUnlockMenuXiaomi) { - nfc->dev->dev_data.mf_ul_data.auth_method = MfUltralightAuthMethodXiaomi; - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockWarn); - consumed = true; - } else if(event.event == SubmenuIndexMfUlUnlockMenuAuto) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockAuto); - consumed = true; - } - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneMfUltralightUnlockMenu, event.event); - } - return consumed; -} - -void nfc_scene_mf_ultralight_unlock_menu_on_exit(void* context) { - NfcApp* nfc = context; - - submenu_reset(nfc->submenu); -} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c deleted file mode 100644 index 4c8a1c90ff93..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c +++ /dev/null @@ -1,98 +0,0 @@ -#include "../nfc_app_i.h" -#include - -void nfc_scene_mf_ultralight_unlock_warn_dialog_callback(DialogExResult result, void* context) { - NfcApp* nfc = context; - - view_dispatcher_send_custom_event(nfc->view_dispatcher, result); -} - -void nfc_scene_mf_ultralight_unlock_warn_on_enter(void* context) { - NfcApp* nfc = context; - DialogEx* dialog_ex = nfc->dialog_ex; - MfUltralightAuthMethod auth_method = nfc->dev->dev_data.mf_ul_data.auth_method; - - dialog_ex_set_context(dialog_ex, nfc); - dialog_ex_set_result_callback(dialog_ex, nfc_scene_mf_ultralight_unlock_warn_dialog_callback); - - if(auth_method == MfUltralightAuthMethodManual || auth_method == MfUltralightAuthMethodAuto) { - // Build dialog text - MfUltralightAuth* auth = &nfc->dev->dev_data.mf_ul_auth; - FuriString* password_str = - furi_string_alloc_set_str("Try to unlock the card with\npassword: "); - for(size_t i = 0; i < sizeof(auth->pwd.raw); ++i) { - furi_string_cat_printf(password_str, "%02X ", nfc->byte_input_store[i]); - } - furi_string_cat_str(password_str, "?\nCaution, a wrong password\ncan block the card!"); - nfc_text_store_set(nfc, furi_string_get_cstr(password_str)); - furi_string_free(password_str); - - dialog_ex_set_header( - dialog_ex, - auth_method == MfUltralightAuthMethodAuto ? "Password captured!" : "Risky function!", - 64, - 0, - AlignCenter, - AlignTop); - dialog_ex_set_text(dialog_ex, nfc->text_store, 64, 12, AlignCenter, AlignTop); - dialog_ex_set_left_button_text(dialog_ex, "Cancel"); - dialog_ex_set_right_button_text(dialog_ex, "Continue"); - - if(auth_method == MfUltralightAuthMethodAuto) - notification_message(nfc->notifications, &sequence_set_green_255); - } else { - dialog_ex_set_header(dialog_ex, "Risky function!", 64, 4, AlignCenter, AlignTop); - dialog_ex_set_text( - dialog_ex, "Wrong password\ncan block your\ncard.", 4, 18, AlignLeft, AlignTop); - dialog_ex_set_icon(dialog_ex, 73, 20, &I_DolphinCommon_56x48); - dialog_ex_set_center_button_text(dialog_ex, "OK"); - } - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); -} - -bool nfc_scene_mf_ultralight_unlock_warn_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - - bool consumed = false; - - MfUltralightAuthMethod auth_method = nfc->dev->dev_data.mf_ul_data.auth_method; - if(auth_method == MfUltralightAuthMethodManual || auth_method == MfUltralightAuthMethodAuto) { - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == DialogExResultRight) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadAuth); - DOLPHIN_DEED(DolphinDeedNfcRead); - consumed = true; - } else if(event.event == DialogExResultLeft) { - if(auth_method == MfUltralightAuthMethodAuto) { - consumed = scene_manager_search_and_switch_to_previous_scene( - nfc->scene_manager, NfcSceneMfUltralightUnlockMenu); - } else { - consumed = scene_manager_previous_scene(nfc->scene_manager); - } - } - } else if(event.type == SceneManagerEventTypeBack) { - // Cannot press back - consumed = true; - } - } else { - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == DialogExResultCenter) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadAuth); - DOLPHIN_DEED(DolphinDeedNfcRead); - consumed = true; - } - } - } - - return consumed; -} - -void nfc_scene_mf_ultralight_unlock_warn_on_exit(void* context) { - NfcApp* nfc = context; - - dialog_ex_reset(nfc->dialog_ex); - nfc_text_store_clear(nfc); - - notification_message_block(nfc->notifications, &sequence_reset_green); -} diff --git a/applications/main/nfc/scenes/nfc_scene_mfkey_complete.c b/applications/main/nfc/scenes/nfc_scene_mfkey_complete.c deleted file mode 100644 index 2f4bba319218..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_mfkey_complete.c +++ /dev/null @@ -1,49 +0,0 @@ -#include "../nfc_app_i.h" - -void nfc_scene_mfkey_complete_callback(GuiButtonType result, InputType type, void* context) { - NfcApp* nfc = context; - if(type == InputTypeShort) { - view_dispatcher_send_custom_event(nfc->view_dispatcher, result); - } -} - -void nfc_scene_mfkey_complete_on_enter(void* context) { - NfcApp* nfc = context; - - widget_add_string_element(nfc->widget, 64, 0, AlignCenter, AlignTop, FontPrimary, "Complete!"); - widget_add_string_multiline_element( - nfc->widget, - 64, - 32, - AlignCenter, - AlignCenter, - FontSecondary, - "Now use mfkey32v2\nto extract keys"); - widget_add_button_element( - nfc->widget, GuiButtonTypeCenter, "OK", nfc_scene_mfkey_complete_callback, nfc); - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); -} - -bool nfc_scene_mfkey_complete_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == GuiButtonTypeCenter) { - consumed = scene_manager_search_and_switch_to_previous_scene( - nfc->scene_manager, NfcSceneStart); - } - } else if(event.event == SceneManagerEventTypeBack) { - consumed = - scene_manager_search_and_switch_to_previous_scene(nfc->scene_manager, NfcSceneStart); - } - - return consumed; -} - -void nfc_scene_mfkey_complete_on_exit(void* context) { - NfcApp* nfc = context; - - widget_reset(nfc->widget); -} \ No newline at end of file diff --git a/applications/main/nfc/scenes/nfc_scene_mfkey_nonces_info.c b/applications/main/nfc/scenes/nfc_scene_mfkey_nonces_info.c deleted file mode 100644 index 5e86f2376fdb..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_mfkey_nonces_info.c +++ /dev/null @@ -1,55 +0,0 @@ -#include "../nfc_app_i.h" -#include - -void nfc_scene_mfkey_nonces_info_callback(GuiButtonType result, InputType type, void* context) { - NfcApp* nfc = context; - if(type == InputTypeShort) { - view_dispatcher_send_custom_event(nfc->view_dispatcher, result); - } -} - -void nfc_scene_mfkey_nonces_info_on_enter(void* context) { - NfcApp* nfc = context; - - FuriString* temp_str; - temp_str = furi_string_alloc(); - - uint16_t nonces_saved = mfkey32_get_auth_sectors(temp_str); - widget_add_text_scroll_element(nfc->widget, 0, 22, 128, 42, furi_string_get_cstr(temp_str)); - furi_string_printf(temp_str, "Nonce pairs saved: %d", nonces_saved); - widget_add_string_element( - nfc->widget, 0, 0, AlignLeft, AlignTop, FontPrimary, furi_string_get_cstr(temp_str)); - widget_add_string_element( - nfc->widget, 0, 12, AlignLeft, AlignTop, FontSecondary, "Authenticated sectors:"); - - widget_add_button_element( - nfc->widget, GuiButtonTypeCenter, "OK", nfc_scene_mfkey_nonces_info_callback, nfc); - - furi_string_free(temp_str); - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); -} - -bool nfc_scene_mfkey_nonces_info_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == GuiButtonTypeCenter) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfkeyComplete); - consumed = true; - } - } else if(event.type == SceneManagerEventTypeBack) { - consumed = - scene_manager_search_and_switch_to_previous_scene(nfc->scene_manager, NfcSceneStart); - } - - return consumed; -} - -void nfc_scene_mfkey_nonces_info_on_exit(void* context) { - NfcApp* nfc = context; - - // Clear view - widget_reset(nfc->widget); -} diff --git a/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c b/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c deleted file mode 100644 index 975117532aac..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c +++ /dev/null @@ -1,154 +0,0 @@ -#include "../nfc_app_i.h" - -void nfc_scene_nfc_data_info_widget_callback(GuiButtonType result, InputType type, void* context) { - NfcApp* nfc = context; - if(type == InputTypeShort) { - view_dispatcher_send_custom_event(nfc->view_dispatcher, result); - } -} - -void nfc_scene_nfc_data_info_on_enter(void* context) { - NfcApp* nfc = context; - Widget* widget = nfc->widget; - FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data; - NfcDeviceData* dev_data = &nfc->dev->dev_data; - NfcProtocol protocol = dev_data->protocol; - uint8_t text_scroll_height = 0; - if((protocol == NfcDeviceProtocolMifareDesfire) || (protocol == NfcDeviceProtocolMifareUl) || - (protocol == NfcDeviceProtocolMifareClassic)) { - widget_add_button_element( - widget, GuiButtonTypeRight, "More", nfc_scene_nfc_data_info_widget_callback, nfc); - text_scroll_height = 52; - } else { - text_scroll_height = 64; - } - - FuriString* temp_str; - temp_str = furi_string_alloc(); - // Set name if present - if(nfc->dev->dev_name[0] != '\0') { - furi_string_printf(temp_str, "\ec%s\n", nfc->dev->dev_name); - } - - // Set tag type - if(protocol == NfcDeviceProtocolEMV) { - furi_string_cat_printf(temp_str, "\e#EMV Bank Card\n"); - } else if(protocol == NfcDeviceProtocolMifareUl) { - furi_string_cat_printf( - temp_str, "\e#%s\n", nfc_mf_ul_type(dev_data->mf_ul_data.type, true)); - } else if(protocol == NfcDeviceProtocolMifareClassic) { - furi_string_cat_printf( - 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 { - furi_string_cat_printf(temp_str, "\e#Unknown ISO tag\n"); - } - - // Set tag iso data - char iso_type = FURI_BIT(nfc_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->atqa[1], nfc_data->atqa[0]); - furi_string_cat_printf(temp_str, " SAK: %02X", nfc_data->sak); - - // Set application specific data - if(protocol == NfcDeviceProtocolMifareDesfire) { - MifareDesfireData* data = &dev_data->mf_df_data; - uint32_t bytes_total = 1UL << (data->version.sw_storage >> 1); - uint32_t bytes_free = data->free_memory ? data->free_memory->bytes : 0; - furi_string_cat_printf(temp_str, "\n%lu", bytes_total); - if(data->version.sw_storage & 1) { - furi_string_push_back(temp_str, '+'); - } - furi_string_cat_printf(temp_str, " bytes, %lu bytes free\n", bytes_free); - - uint16_t n_apps = 0; - uint16_t n_files = 0; - for(MifareDesfireApplication* app = data->app_head; app; app = app->next) { - n_apps++; - for(MifareDesfireFile* file = app->file_head; file; file = file->next) { - n_files++; - } - } - furi_string_cat_printf(temp_str, "%d Application", n_apps); - if(n_apps != 1) { - furi_string_push_back(temp_str, 's'); - } - furi_string_cat_printf(temp_str, ", %d file", n_files); - if(n_files != 1) { - furi_string_push_back(temp_str, 's'); - } - } else if(protocol == NfcDeviceProtocolMifareUl) { - MfUltralightData* data = &dev_data->mf_ul_data; - furi_string_cat_printf( - temp_str, "\nPages Read %d/%d", data->data_read / 4, data->data_size / 4); - if(data->data_size > data->data_read) { - furi_string_cat_printf(temp_str, "\nPassword-protected"); - } else if(data->auth_success) { - MfUltralightConfigPages* config_pages = mf_ultralight_get_config_pages(data); - if(config_pages) { - furi_string_cat_printf( - temp_str, - "\nPassword: %02X %02X %02X %02X", - config_pages->auth_data.pwd.raw[0], - config_pages->auth_data.pwd.raw[1], - config_pages->auth_data.pwd.raw[2], - config_pages->auth_data.pwd.raw[3]); - furi_string_cat_printf( - temp_str, - "\nPACK: %02X %02X", - config_pages->auth_data.pack.raw[0], - config_pages->auth_data.pack.raw[1]); - } - } - } else if(protocol == NfcDeviceProtocolMifareClassic) { - MfClassicData* data = &dev_data->mf_classic_data; - uint8_t sectors_total = mf_classic_get_total_sectors_num(data->type); - uint8_t keys_total = sectors_total * 2; - uint8_t keys_found = 0; - uint8_t sectors_read = 0; - mf_classic_get_read_sectors_and_keys(data, §ors_read, &keys_found); - furi_string_cat_printf(temp_str, "\nKeys Found %d/%d", keys_found, keys_total); - furi_string_cat_printf(temp_str, "\nSectors Read %d/%d", sectors_read, sectors_total); - } - - // Add text scroll widget - widget_add_text_scroll_element( - widget, 0, 0, 128, text_scroll_height, furi_string_get_cstr(temp_str)); - furi_string_free(temp_str); - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); -} - -bool nfc_scene_nfc_data_info_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - NfcProtocol protocol = nfc->dev->dev_data.protocol; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == GuiButtonTypeRight) { - if(protocol == NfcDeviceProtocolMifareDesfire) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireData); - consumed = true; - } else if(protocol == NfcDeviceProtocolMifareUl) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightData); - consumed = true; - } else if(protocol == NfcDeviceProtocolMifareClassic) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicData); - consumed = true; - } - } - } - - return consumed; -} - -void nfc_scene_nfc_data_info_on_exit(void* context) { - NfcApp* nfc = context; - - widget_reset(nfc->widget); -} diff --git a/applications/main/nfc/scenes/nfc_scene_nfca_menu.c b/applications/main/nfc/scenes/nfc_scene_nfca_menu.c index 702325a782bb..81e868dd2563 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfca_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_nfca_menu.c @@ -35,21 +35,18 @@ bool nfc_scene_nfca_menu_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubmenuIndexSaveUid) { - nfc->dev->format = NfcDeviceSaveFormatUid; - // Clear device name - nfc_device_set_name(nfc->dev, ""); - scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); + scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); consumed = true; } else if(event.event == SubmenuIndexEmulateUid) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); - if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneNotImplemented)) { DOLPHIN_DEED(DolphinDeedNfcAddEmulate); } else { DOLPHIN_DEED(DolphinDeedNfcEmulate); } consumed = true; } else if(event.event == SubmenuIndexInfo) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); + scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); consumed = true; } scene_manager_set_scene_state(nfc->scene_manager, NfcSceneNfcaMenu, event.event); diff --git a/applications/main/nfc/scenes/nfc_scene_nfca_read.c b/applications/main/nfc/scenes/nfc_scene_nfca_read.c index 5b14a44e406c..781ba2262152 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfca_read.c +++ b/applications/main/nfc/scenes/nfc_scene_nfca_read.c @@ -1,6 +1,10 @@ #include "../nfc_app_i.h" #include +enum { + NfcWorkerEventReadUidNfcA, +}; + void nfc_scene_nfca_read_worker_callback(NfcaPollerEvent event, void* context) { NfcApp* nfc = context; @@ -14,7 +18,6 @@ void nfc_scene_nfca_read_on_enter(void* context) { NfcApp* nfc = context; // Setup view - nfc_scene_nfca_read_set_state(nfc, NfcSceneReadStateDetecting); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); nfc->nfca_poller = nfca_poller_alloc(); @@ -30,7 +33,7 @@ bool nfc_scene_nfca_read_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == NfcWorkerEventReadUidNfcA) { notification_message(nfc->notifications, &sequence_success); - nfca_poller_get_data(nfc->nfca_poller, &nfc->nfca_data); + nfca_poller_get_data(nfc->nfca_poller, &nfc->nfc_dev_data.nfca_data); nfca_poller_free(nfc->nfca_poller); scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcaReadSuccess); DOLPHIN_DEED(DolphinDeedNfcReadSuccess); @@ -45,7 +48,6 @@ void nfc_scene_nfca_read_on_exit(void* context) { // Clear view popup_reset(nfc->popup); - scene_manager_set_scene_state(nfc->scene_manager, NfcSceneRead, NfcSceneReadStateIdle); nfc_blink_stop(nfc); } diff --git a/applications/main/nfc/scenes/nfc_scene_nfca_read_success.c b/applications/main/nfc/scenes/nfc_scene_nfca_read_success.c index d1d399391082..b0a6e533f9bd 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfca_read_success.c +++ b/applications/main/nfc/scenes/nfc_scene_nfca_read_success.c @@ -16,7 +16,7 @@ void nfc_scene_nfca_read_success_on_enter(void* context) { NfcApp* nfc = context; // Setup view - NfcaData* data = &nfc->nfca_data; + NfcaData* data = &nfc->nfc_dev_data.nfca_data; Widget* widget = nfc->widget; FuriString* temp_str; diff --git a/applications/main/nfc/scenes/nfc_scene_read.c b/applications/main/nfc/scenes/nfc_scene_read.c index 68e8559ecd14..51d2f98167e3 100644 --- a/applications/main/nfc/scenes/nfc_scene_read.c +++ b/applications/main/nfc/scenes/nfc_scene_read.c @@ -1,11 +1,9 @@ #include "../nfc_app_i.h" #include -typedef enum { - NfcSceneReadStateIdle, - NfcSceneReadStateDetecting, - NfcSceneReadStateReading, -} NfcSceneReadState; +enum { + NfcWorkerEventReadUidNfcA, +}; void nfc_scene_read_worker_callback(NfcaPollerEvent event, void* context) { NfcApp* nfc = context; @@ -14,35 +12,17 @@ void nfc_scene_read_worker_callback(NfcaPollerEvent event, void* context) { nfca_poller_stop(nfc->nfca_poller); view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcWorkerEventReadUidNfcA); } - -} - -void nfc_scene_read_set_state(NfcApp* nfc, NfcSceneReadState state) { - uint32_t curr_state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneRead); - if(curr_state != state) { - if(state == NfcSceneReadStateDetecting) { - popup_reset(nfc->popup); - popup_set_text( - nfc->popup, "Apply card to\nFlipper's back", 97, 24, AlignCenter, AlignTop); - popup_set_icon(nfc->popup, 0, 8, &I_NFC_manual_60x50); - } else if(state == NfcSceneReadStateReading) { - popup_reset(nfc->popup); - popup_set_header( - nfc->popup, "Reading card\nDon't move...", 85, 24, AlignCenter, AlignTop); - popup_set_icon(nfc->popup, 12, 23, &A_Loading_24); - } - scene_manager_set_scene_state(nfc->scene_manager, NfcSceneRead, state); - } } void nfc_scene_read_on_enter(void* context) { NfcApp* nfc = context; - nfc_device_clear(nfc->dev); // Setup view - nfc_scene_read_set_state(nfc, NfcSceneReadStateDetecting); + popup_reset(nfc->popup); + popup_set_text(nfc->popup, "Apply card to\nFlipper's back", 97, 24, AlignCenter, AlignTop); + popup_set_icon(nfc->popup, 0, 8, &I_NFC_manual_60x50); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); - + nfc->nfca_poller = nfca_poller_alloc(); nfca_poller_start(nfc->nfca_poller, nfc_scene_read_worker_callback, nfc); @@ -54,57 +34,13 @@ bool nfc_scene_read_on_event(void* context, SceneManagerEvent event) { bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { - if((event.event == NfcWorkerEventReadUidNfcB) || - (event.event == NfcWorkerEventReadUidNfcF) || - (event.event == NfcWorkerEventReadUidNfcV)) { + if(event.event == NfcWorkerEventReadUidNfcA) { notification_message(nfc->notifications, &sequence_success); - scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardSuccess); - DOLPHIN_DEED(DolphinDeedNfcReadSuccess); - consumed = true; - } else if(event.event == NfcWorkerEventReadUidNfcA) { - notification_message(nfc->notifications, &sequence_success); - nfca_poller_get_data(nfc->nfca_poller, &nfc->nfca_data); + nfca_poller_get_data(nfc->nfca_poller, &nfc->nfc_dev_data.nfca_data); nfca_poller_free(nfc->nfca_poller); scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcaReadSuccess); DOLPHIN_DEED(DolphinDeedNfcReadSuccess); consumed = true; - } else if(event.event == NfcWorkerEventReadMfUltralight) { - notification_message(nfc->notifications, &sequence_success); - // Set unlock password input to 0xFFFFFFFF only on fresh read - memset(nfc->byte_input_store, 0xFF, sizeof(nfc->byte_input_store)); - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadSuccess); - DOLPHIN_DEED(DolphinDeedNfcReadSuccess); - consumed = true; - } else if(event.event == NfcWorkerEventReadMfClassicDone) { - notification_message(nfc->notifications, &sequence_success); - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSuccess); - DOLPHIN_DEED(DolphinDeedNfcReadSuccess); - consumed = true; - } else if(event.event == NfcWorkerEventReadMfDesfire) { - notification_message(nfc->notifications, &sequence_success); - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireReadSuccess); - DOLPHIN_DEED(DolphinDeedNfcReadSuccess); - consumed = true; - } else if(event.event == NfcWorkerEventReadBankCard) { - notification_message(nfc->notifications, &sequence_success); - scene_manager_next_scene(nfc->scene_manager, NfcSceneEmvReadSuccess); - DOLPHIN_DEED(DolphinDeedNfcReadSuccess); - consumed = true; - } else if(event.event == NfcWorkerEventReadMfClassicDictAttackRequired) { - if(mf_classic_dict_check_presence(MfClassicDictTypeSystem)) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicDictAttack); - } else { - scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound); - } - consumed = true; - } else if(event.event == NfcWorkerEventCardDetected) { - nfc_scene_read_set_state(nfc, NfcSceneReadStateReading); - nfc_blink_detect_start(nfc); - consumed = true; - } else if(event.event == NfcWorkerEventNoCardDetected) { - nfc_scene_read_set_state(nfc, NfcSceneReadStateDetecting); - nfc_blink_read_start(nfc); - consumed = true; } } return consumed; @@ -115,7 +51,6 @@ void nfc_scene_read_on_exit(void* context) { // Clear view popup_reset(nfc->popup); - scene_manager_set_scene_state(nfc->scene_manager, NfcSceneRead, NfcSceneReadStateIdle); nfc_blink_stop(nfc); } diff --git a/applications/main/nfc/scenes/nfc_scene_read_card_success.c b/applications/main/nfc/scenes/nfc_scene_read_card_success.c deleted file mode 100644 index 009de9c966fd..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_read_card_success.c +++ /dev/null @@ -1,61 +0,0 @@ -#include "../nfc_app_i.h" - -void nfc_scene_read_card_success_widget_callback( - GuiButtonType result, - InputType type, - void* context) { - furi_assert(context); - NfcApp* nfc = context; - - if(type == InputTypeShort) { - view_dispatcher_send_custom_event(nfc->view_dispatcher, result); - } -} - -void nfc_scene_read_card_success_on_enter(void* context) { - NfcApp* nfc = context; - - FuriString* temp_str; - temp_str = furi_string_alloc(); - - // Setup view - FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; - Widget* widget = nfc->widget; - furi_string_set(temp_str, nfc_get_dev_type(data->type)); - widget_add_string_element( - widget, 64, 12, AlignCenter, AlignBottom, FontPrimary, furi_string_get_cstr(temp_str)); - furi_string_set(temp_str, "UID:"); - for(uint8_t i = 0; i < data->uid_len; i++) { - furi_string_cat_printf(temp_str, " %02X", data->uid[i]); - } - widget_add_string_element( - widget, 64, 32, AlignCenter, AlignCenter, FontSecondary, furi_string_get_cstr(temp_str)); - widget_add_button_element( - widget, GuiButtonTypeLeft, "Retry", nfc_scene_read_card_success_widget_callback, nfc); - - furi_string_free(temp_str); - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); -} - -bool nfc_scene_read_card_success_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == GuiButtonTypeLeft) { - consumed = scene_manager_previous_scene(nfc->scene_manager); - } - } else if(event.type == SceneManagerEventTypeBack) { - consumed = - scene_manager_search_and_switch_to_previous_scene(nfc->scene_manager, NfcSceneStart); - } - return consumed; -} - -void nfc_scene_read_card_success_on_exit(void* context) { - NfcApp* nfc = context; - - // Clear view - widget_reset(nfc->widget); -} diff --git a/applications/main/nfc/scenes/nfc_scene_read_card_type.c b/applications/main/nfc/scenes/nfc_scene_read_card_type.c index e9fad6d0c286..79c9297e57e0 100644 --- a/applications/main/nfc/scenes/nfc_scene_read_card_type.c +++ b/applications/main/nfc/scenes/nfc_scene_read_card_type.c @@ -1,5 +1,4 @@ #include "../nfc_app_i.h" -#include "nfc_worker_i.h" enum SubmenuIndex { SubmenuIndexReadNFCA, @@ -61,27 +60,22 @@ bool nfc_scene_read_card_type_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubmenuIndexReadMifareClassic) { - nfc->dev->dev_data.read_mode = NfcReadModeMfClassic; scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); consumed = true; } if(event.event == SubmenuIndexReadMifareDesfire) { - nfc->dev->dev_data.read_mode = NfcReadModeMfDesfire; scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); consumed = true; } if(event.event == SubmenuIndexReadMfUltralight) { - nfc->dev->dev_data.read_mode = NfcReadModeMfUltralight; scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); consumed = true; } if(event.event == SubmenuIndexReadEMV) { - nfc->dev->dev_data.read_mode = NfcReadModeEMV; scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); consumed = true; } if(event.event == SubmenuIndexReadNFCA) { - nfc->dev->dev_data.read_mode = NfcReadModeNFCA; scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); consumed = true; } diff --git a/applications/main/nfc/scenes/nfc_scene_restore_original.c b/applications/main/nfc/scenes/nfc_scene_restore_original.c deleted file mode 100644 index f059eeac497b..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_restore_original.c +++ /dev/null @@ -1,45 +0,0 @@ -#include "../nfc_app_i.h" - -void nfc_scene_restore_original_popup_callback(void* context) { - NfcApp* nfc = context; - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); -} - -void nfc_scene_restore_original_on_enter(void* context) { - NfcApp* nfc = context; - - // Setup view - Popup* popup = nfc->popup; - popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); - popup_set_header(popup, "Original file\nrestored", 13, 22, AlignLeft, AlignBottom); - popup_set_timeout(popup, 1500); - popup_set_context(popup, nfc); - popup_set_callback(popup, nfc_scene_restore_original_popup_callback); - popup_enable_timeout(popup); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); -} - -bool nfc_scene_restore_original_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == NfcCustomEventViewExit) { - if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSavedMenu)) { - consumed = scene_manager_search_and_switch_to_previous_scene( - nfc->scene_manager, NfcSceneSavedMenu); - } else { - consumed = scene_manager_search_and_switch_to_previous_scene( - nfc->scene_manager, NfcSceneStart); - } - } - } - return consumed; -} - -void nfc_scene_restore_original_on_exit(void* context) { - NfcApp* nfc = context; - - // Clear view - popup_reset(nfc->popup); -} diff --git a/applications/main/nfc/scenes/nfc_scene_restore_original_confirm.c b/applications/main/nfc/scenes/nfc_scene_restore_original_confirm.c deleted file mode 100644 index e396049aed90..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_restore_original_confirm.c +++ /dev/null @@ -1,53 +0,0 @@ -#include "../nfc_app_i.h" - -void nfc_scene_restore_original_confirm_dialog_callback(DialogExResult result, void* context) { - NfcApp* nfc = context; - - view_dispatcher_send_custom_event(nfc->view_dispatcher, result); -} - -void nfc_scene_restore_original_confirm_on_enter(void* context) { - NfcApp* nfc = context; - DialogEx* dialog_ex = nfc->dialog_ex; - - dialog_ex_set_header(dialog_ex, "Restore Card Data?", 64, 0, AlignCenter, AlignTop); - dialog_ex_set_icon(dialog_ex, 5, 15, &I_Restoring_38x32); - dialog_ex_set_text( - dialog_ex, "It will be returned\nto its original state.", 47, 21, AlignLeft, AlignTop); - dialog_ex_set_left_button_text(dialog_ex, "Cancel"); - dialog_ex_set_right_button_text(dialog_ex, "Restore"); - dialog_ex_set_context(dialog_ex, nfc); - dialog_ex_set_result_callback(dialog_ex, nfc_scene_restore_original_confirm_dialog_callback); - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); -} - -bool nfc_scene_restore_original_confirm_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == DialogExResultRight) { - if(!nfc_device_restore(nfc->dev, true)) { - scene_manager_search_and_switch_to_previous_scene( - nfc->scene_manager, NfcSceneStart); - } else { - scene_manager_next_scene(nfc->scene_manager, NfcSceneRestoreOriginal); - } - consumed = true; - } else if(event.event == DialogExResultLeft) { - consumed = scene_manager_previous_scene(nfc->scene_manager); - } - } else if(event.type == SceneManagerEventTypeBack) { - consumed = true; - } - - return consumed; -} - -void nfc_scene_restore_original_confirm_on_exit(void* context) { - NfcApp* nfc = context; - - // Clean view - dialog_ex_reset(nfc->dialog_ex); -} diff --git a/applications/main/nfc/scenes/nfc_scene_rpc.c b/applications/main/nfc/scenes/nfc_scene_rpc.c deleted file mode 100644 index ee6e8b990a9c..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_rpc.c +++ /dev/null @@ -1,86 +0,0 @@ -#include "../nfc_app_i.h" - -void nfc_scene_rpc_on_enter(void* context) { - NfcApp* nfc = context; - Popup* popup = nfc->popup; - - popup_set_header(popup, "NFC", 89, 42, AlignCenter, AlignBottom); - popup_set_text(popup, "RPC mode", 89, 44, AlignCenter, AlignTop); - - popup_set_icon(popup, 0, 12, &I_NFC_dolphin_emulation_47x61); - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); - - notification_message(nfc->notifications, &sequence_display_backlight_on); -} - -static bool nfc_scene_rpc_emulate_callback(NfcWorkerEvent event, void* context) { - UNUSED(event); - NfcApp* nfc = context; - - nfc->rpc_state = NfcRpcStateEmulated; - return true; -} - -bool nfc_scene_rpc_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - Popup* popup = nfc->popup; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - consumed = true; - if(event.event == NfcCustomEventViewExit) { - rpc_system_app_confirm(nfc->rpc_ctx, RpcAppEventAppExit, true); - scene_manager_stop(nfc->scene_manager); - view_dispatcher_stop(nfc->view_dispatcher); - } else if(event.event == NfcCustomEventRpcSessionClose) { - scene_manager_stop(nfc->scene_manager); - view_dispatcher_stop(nfc->view_dispatcher); - } else if(event.event == NfcCustomEventRpcLoad) { - bool result = false; - const char* arg = rpc_system_app_get_data(nfc->rpc_ctx); - if((arg) && (nfc->rpc_state == NfcRpcStateIdle)) { - if(nfc_device_load(nfc->dev, arg, false)) { - if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { - nfc_worker_start( - nfc->worker, - NfcWorkerStateMfUltralightEmulate, - &nfc->dev->dev_data, - nfc_scene_rpc_emulate_callback, - nfc); - } else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) { - nfc_worker_start( - nfc->worker, - NfcWorkerStateMfClassicEmulate, - &nfc->dev->dev_data, - nfc_scene_rpc_emulate_callback, - nfc); - } else { - nfc_worker_start( - nfc->worker, NfcWorkerStateUidEmulate, &nfc->dev->dev_data, NULL, nfc); - } - nfc->rpc_state = NfcRpcStateEmulating; - result = true; - - nfc_blink_emulate_start(nfc); - nfc_text_store_set(nfc, "emulating\n%s", nfc->dev->dev_name); - popup_set_text(popup, nfc->text_store, 89, 44, AlignCenter, AlignTop); - } - } - - rpc_system_app_confirm(nfc->rpc_ctx, RpcAppEventLoadFile, result); - } - } - return consumed; -} - -void nfc_scene_rpc_on_exit(void* context) { - NfcApp* nfc = context; - Popup* popup = nfc->popup; - - nfc_blink_stop(nfc); - - popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom); - popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop); - popup_set_icon(popup, 0, 0, NULL); -} diff --git a/applications/main/nfc/scenes/nfc_scene_save_name.c b/applications/main/nfc/scenes/nfc_scene_save_name.c deleted file mode 100644 index 41fbb8833de3..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_save_name.c +++ /dev/null @@ -1,93 +0,0 @@ -#include "../nfc_app_i.h" -#include -#include -#include -#include - -void nfc_scene_save_name_text_input_callback(void* context) { - NfcApp* nfc = context; - - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventTextInputDone); -} - -void nfc_scene_save_name_on_enter(void* context) { - NfcApp* nfc = context; - - // Setup view - TextInput* text_input = nfc->text_input; - bool dev_name_empty = false; - if(!strcmp(nfc->dev->dev_name, "")) { - set_random_name(nfc->text_store, sizeof(nfc->text_store)); - dev_name_empty = true; - } else { - nfc_text_store_set(nfc, nfc->dev->dev_name); - } - text_input_set_header_text(text_input, "Name the card"); - text_input_set_result_callback( - text_input, - nfc_scene_save_name_text_input_callback, - nfc, - nfc->text_store, - NFC_DEV_NAME_MAX_LEN, - dev_name_empty); - - FuriString* folder_path; - folder_path = furi_string_alloc(); - - if(furi_string_end_with(nfc->dev->load_path, NFC_APP_EXTENSION)) { - path_extract_dirname(furi_string_get_cstr(nfc->dev->load_path), folder_path); - } else { - furi_string_set(folder_path, NFC_APP_FOLDER); - } - - ValidatorIsFile* validator_is_file = validator_is_file_alloc_init( - furi_string_get_cstr(folder_path), NFC_APP_EXTENSION, nfc->dev->dev_name); - text_input_set_validator(text_input, validator_is_file_callback, validator_is_file); - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextInput); - - furi_string_free(folder_path); -} - -bool nfc_scene_save_name_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == NfcCustomEventTextInputDone) { - if(strcmp(nfc->dev->dev_name, "") != 0) { - nfc_device_delete(nfc->dev, true); - } - if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetUid)) { - nfc->dev->dev_data.nfc_data = nfc->dev_edit_data; - } - strlcpy(nfc->dev->dev_name, nfc->text_store, strlen(nfc->text_store) + 1); - if(nfc_save_file(nfc)) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess); - if(!scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSavedMenu)) { - // Nothing, do not count editing as saving - } else if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) { - DOLPHIN_DEED(DolphinDeedNfcAddSave); - } else { - DOLPHIN_DEED(DolphinDeedNfcSave); - } - consumed = true; - } else { - consumed = scene_manager_search_and_switch_to_previous_scene( - nfc->scene_manager, NfcSceneStart); - } - } - } - return consumed; -} - -void nfc_scene_save_name_on_exit(void* context) { - NfcApp* nfc = context; - - // Clear view - void* validator_context = text_input_get_validator_callback_context(nfc->text_input); - text_input_set_validator(nfc->text_input, NULL, NULL); - validator_is_file_free(validator_context); - - text_input_reset(nfc->text_input); -} diff --git a/applications/main/nfc/scenes/nfc_scene_save_success.c b/applications/main/nfc/scenes/nfc_scene_save_success.c deleted file mode 100644 index 4c19f2f42e0f..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_save_success.c +++ /dev/null @@ -1,48 +0,0 @@ -#include "../nfc_app_i.h" - -void nfc_scene_save_success_popup_callback(void* context) { - NfcApp* nfc = context; - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); -} - -void nfc_scene_save_success_on_enter(void* context) { - NfcApp* nfc = context; - - // Setup view - Popup* popup = nfc->popup; - popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); - popup_set_header(popup, "Saved!", 13, 22, AlignLeft, AlignBottom); - popup_set_timeout(popup, 1500); - popup_set_context(popup, nfc); - popup_set_callback(popup, nfc_scene_save_success_popup_callback); - popup_enable_timeout(popup); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); -} - -bool nfc_scene_save_success_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == NfcCustomEventViewExit) { - if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneMfClassicKeys)) { - consumed = scene_manager_search_and_switch_to_previous_scene( - nfc->scene_manager, NfcSceneMfClassicKeys); - } else if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSavedMenu)) { - consumed = scene_manager_search_and_switch_to_previous_scene( - nfc->scene_manager, NfcSceneSavedMenu); - } else { - consumed = scene_manager_search_and_switch_to_another_scene( - nfc->scene_manager, NfcSceneFileSelect); - } - } - } - return consumed; -} - -void nfc_scene_save_success_on_exit(void* context) { - NfcApp* nfc = context; - - // Clear view - popup_reset(nfc->popup); -} diff --git a/applications/main/nfc/scenes/nfc_scene_saved_menu.c b/applications/main/nfc/scenes/nfc_scene_saved_menu.c deleted file mode 100644 index 987911d79fff..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_saved_menu.c +++ /dev/null @@ -1,180 +0,0 @@ -#include "../nfc_app_i.h" -#include - -enum SubmenuIndex { - SubmenuIndexEmulate, - SubmenuIndexEditUid, - SubmenuIndexDetectReader, - SubmenuIndexWrite, - SubmenuIndexUpdate, - SubmenuIndexRename, - SubmenuIndexDelete, - SubmenuIndexInfo, - SubmenuIndexRestoreOriginal, - SubmenuIndexMfUlUnlockByReader, - SubmenuIndexMfUlUnlockByPassword, -}; - -void nfc_scene_saved_menu_submenu_callback(void* context, uint32_t index) { - NfcApp* nfc = context; - - view_dispatcher_send_custom_event(nfc->view_dispatcher, index); -} - -void nfc_scene_saved_menu_on_enter(void* context) { - NfcApp* nfc = context; - Submenu* submenu = nfc->submenu; - - if(nfc->dev->format == NfcDeviceSaveFormatUid || - nfc->dev->format == NfcDeviceSaveFormatMifareDesfire) { - submenu_add_item( - submenu, - "Emulate UID", - SubmenuIndexEmulate, - nfc_scene_saved_menu_submenu_callback, - nfc); - if(nfc->dev->dev_data.protocol == NfcDeviceProtocolUnknown) { - submenu_add_item( - submenu, - "Edit UID", - SubmenuIndexEditUid, - nfc_scene_saved_menu_submenu_callback, - nfc); - } - } else if( - nfc->dev->format == NfcDeviceSaveFormatMifareUl || - nfc->dev->format == NfcDeviceSaveFormatMifareClassic) { - submenu_add_item( - submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_saved_menu_submenu_callback, nfc); - } - if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) { - if(!mf_classic_is_card_read(&nfc->dev->dev_data.mf_classic_data)) { - submenu_add_item( - submenu, - "Detect Reader", - SubmenuIndexDetectReader, - nfc_scene_saved_menu_submenu_callback, - nfc); - } - submenu_add_item( - submenu, - "Write to Initial Card", - SubmenuIndexWrite, - nfc_scene_saved_menu_submenu_callback, - nfc); - submenu_add_item( - submenu, - "Update from Initial Card", - SubmenuIndexUpdate, - nfc_scene_saved_menu_submenu_callback, - nfc); - } - submenu_add_item( - submenu, "Info", SubmenuIndexInfo, nfc_scene_saved_menu_submenu_callback, nfc); - if(nfc->dev->format == NfcDeviceSaveFormatMifareUl && - !mf_ul_is_full_capture(&nfc->dev->dev_data.mf_ul_data)) { - submenu_add_item( - submenu, - "Unlock with Reader", - SubmenuIndexMfUlUnlockByReader, - nfc_scene_saved_menu_submenu_callback, - nfc); - submenu_add_item( - submenu, - "Unlock with Password", - SubmenuIndexMfUlUnlockByPassword, - nfc_scene_saved_menu_submenu_callback, - nfc); - } - if(nfc->dev->shadow_file_exist) { - submenu_add_item( - submenu, - "Restore to original", - SubmenuIndexRestoreOriginal, - nfc_scene_saved_menu_submenu_callback, - nfc); - } - submenu_add_item( - submenu, "Rename", SubmenuIndexRename, nfc_scene_saved_menu_submenu_callback, nfc); - submenu_add_item( - submenu, "Delete", SubmenuIndexDelete, nfc_scene_saved_menu_submenu_callback, nfc); - submenu_set_selected_item( - nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneSavedMenu)); - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); -} - -bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - NfcDeviceData* dev_data = &nfc->dev->dev_data; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - scene_manager_set_scene_state(nfc->scene_manager, NfcSceneSavedMenu, event.event); - if(event.event == SubmenuIndexEmulate) { - if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate); - } else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate); - } else { - scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); - } - DOLPHIN_DEED(DolphinDeedNfcEmulate); - consumed = true; - } else if(event.event == SubmenuIndexDetectReader) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneDetectReader); - DOLPHIN_DEED(DolphinDeedNfcDetectReader); - consumed = true; - } else if(event.event == SubmenuIndexWrite) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicWrite); - consumed = true; - } else if(event.event == SubmenuIndexUpdate) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicUpdate); - consumed = true; - } else if(event.event == SubmenuIndexRename) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); - consumed = true; - } else if(event.event == SubmenuIndexEditUid) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneSetUid); - consumed = true; - } else if(event.event == SubmenuIndexDelete) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneDelete); - consumed = true; - } else if(event.event == SubmenuIndexInfo) { - bool application_info_present = false; - if(dev_data->protocol == NfcDeviceProtocolEMV) { - application_info_present = true; - } else if( - dev_data->protocol == NfcDeviceProtocolMifareClassic || - dev_data->protocol == NfcDeviceProtocolMifareUl) { - application_info_present = nfc_supported_card_verify_and_parse(dev_data); - } - - FURI_LOG_I("nfc", "application_info_present: %d", application_info_present); - - if(application_info_present) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneDeviceInfo); - } else { - scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); - } - consumed = true; - } else if(event.event == SubmenuIndexRestoreOriginal) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneRestoreOriginalConfirm); - consumed = true; - } else if(event.event == SubmenuIndexMfUlUnlockByReader) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockAuto); - consumed = true; - } else if(event.event == SubmenuIndexMfUlUnlockByPassword) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockMenu); - consumed = true; - } - } - - return consumed; -} - -void nfc_scene_saved_menu_on_exit(void* context) { - NfcApp* nfc = context; - - submenu_reset(nfc->submenu); -} diff --git a/applications/main/nfc/scenes/nfc_scene_set_atqa.c b/applications/main/nfc/scenes/nfc_scene_set_atqa.c deleted file mode 100644 index 4e0e11e7877c..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_set_atqa.c +++ /dev/null @@ -1,44 +0,0 @@ -#include "../nfc_app_i.h" - -void nfc_scene_set_atqa_byte_input_callback(void* context) { - NfcApp* nfc = context; - - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); -} - -void nfc_scene_set_atqa_on_enter(void* context) { - NfcApp* nfc = context; - - // Setup view - ByteInput* byte_input = nfc->byte_input; - byte_input_set_header_text(byte_input, "Enter ATQA in hex"); - byte_input_set_result_callback( - byte_input, - nfc_scene_set_atqa_byte_input_callback, - NULL, - nfc, - nfc->dev->dev_data.nfc_data.atqa, - 2); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewByteInput); -} - -bool nfc_scene_set_atqa_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == NfcCustomEventByteInputDone) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneSetUid); - consumed = true; - } - } - return consumed; -} - -void nfc_scene_set_atqa_on_exit(void* context) { - NfcApp* nfc = context; - - // Clear view - byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0); - byte_input_set_header_text(nfc->byte_input, ""); -} diff --git a/applications/main/nfc/scenes/nfc_scene_set_sak.c b/applications/main/nfc/scenes/nfc_scene_set_sak.c deleted file mode 100644 index 2c4a230cc4f5..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_set_sak.c +++ /dev/null @@ -1,44 +0,0 @@ -#include "../nfc_app_i.h" - -void nfc_scene_set_sak_byte_input_callback(void* context) { - NfcApp* nfc = context; - - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); -} - -void nfc_scene_set_sak_on_enter(void* context) { - NfcApp* nfc = context; - - // Setup view - ByteInput* byte_input = nfc->byte_input; - byte_input_set_header_text(byte_input, "Enter SAK in hex"); - byte_input_set_result_callback( - byte_input, - nfc_scene_set_sak_byte_input_callback, - NULL, - nfc, - &nfc->dev->dev_data.nfc_data.sak, - 1); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewByteInput); -} - -bool nfc_scene_set_sak_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == NfcCustomEventByteInputDone) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneSetAtqa); - consumed = true; - } - } - return consumed; -} - -void nfc_scene_set_sak_on_exit(void* context) { - NfcApp* nfc = context; - - // Clear view - byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0); - byte_input_set_header_text(nfc->byte_input, ""); -} diff --git a/applications/main/nfc/scenes/nfc_scene_set_type.c b/applications/main/nfc/scenes/nfc_scene_set_type.c deleted file mode 100644 index 9e417939d62f..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_set_type.c +++ /dev/null @@ -1,68 +0,0 @@ -#include "../nfc_app_i.h" -#include "lib/nfc/helpers/nfc_generators.h" - -enum SubmenuIndex { - SubmenuIndexNFCA4, - SubmenuIndexNFCA7, - SubmenuIndexGeneratorsStart, -}; - -void nfc_scene_set_type_submenu_callback(void* context, uint32_t index) { - NfcApp* nfc = context; - - view_dispatcher_send_custom_event(nfc->view_dispatcher, index); -} - -void nfc_scene_set_type_on_enter(void* context) { - NfcApp* nfc = context; - Submenu* submenu = nfc->submenu; - // Clear device name - nfc_device_set_name(nfc->dev, ""); - furi_string_set(nfc->dev->load_path, ""); - submenu_add_item( - submenu, "NFC-A 7-bytes UID", SubmenuIndexNFCA7, nfc_scene_set_type_submenu_callback, nfc); - submenu_add_item( - submenu, "NFC-A 4-bytes UID", SubmenuIndexNFCA4, nfc_scene_set_type_submenu_callback, nfc); - - // Generators - int i = SubmenuIndexGeneratorsStart; - for(const NfcGenerator* const* generator = nfc_generators; *generator != NULL; - ++generator, ++i) { - submenu_add_item(submenu, (*generator)->name, i, nfc_scene_set_type_submenu_callback, nfc); - } - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); -} - -bool nfc_scene_set_type_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == SubmenuIndexNFCA7) { - nfc->dev->dev_data.nfc_data.uid_len = 7; - nfc->dev->format = NfcDeviceSaveFormatUid; - scene_manager_next_scene(nfc->scene_manager, NfcSceneSetSak); - consumed = true; - } else if(event.event == SubmenuIndexNFCA4) { - nfc->dev->dev_data.nfc_data.uid_len = 4; - nfc->dev->format = NfcDeviceSaveFormatUid; - scene_manager_next_scene(nfc->scene_manager, NfcSceneSetSak); - consumed = true; - } else { - nfc_device_clear(nfc->dev); - nfc->generator = nfc_generators[event.event - SubmenuIndexGeneratorsStart]; - nfc->generator->generator_func(&nfc->dev->dev_data); - - scene_manager_next_scene(nfc->scene_manager, NfcSceneGenerateInfo); - consumed = true; - } - } - return consumed; -} - -void nfc_scene_set_type_on_exit(void* context) { - NfcApp* nfc = context; - - submenu_reset(nfc->submenu); -} diff --git a/applications/main/nfc/scenes/nfc_scene_set_uid.c b/applications/main/nfc/scenes/nfc_scene_set_uid.c deleted file mode 100644 index 4c2dc7d04931..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_set_uid.c +++ /dev/null @@ -1,54 +0,0 @@ -#include "../nfc_app_i.h" - -void nfc_scene_set_uid_byte_input_callback(void* context) { - NfcApp* nfc = context; - - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); -} - -void nfc_scene_set_uid_on_enter(void* context) { - NfcApp* nfc = context; - - // Setup view - ByteInput* byte_input = nfc->byte_input; - byte_input_set_header_text(byte_input, "Enter UID in hex"); - nfc->dev_edit_data = nfc->dev->dev_data.nfc_data; - byte_input_set_result_callback( - byte_input, - nfc_scene_set_uid_byte_input_callback, - NULL, - nfc, - nfc->dev_edit_data.uid, - nfc->dev_edit_data.uid_len); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewByteInput); -} - -bool nfc_scene_set_uid_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = (NfcApp*)context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == NfcCustomEventByteInputDone) { - if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSavedMenu)) { - nfc->dev->dev_data.nfc_data = nfc->dev_edit_data; - if(nfc_save_file(nfc)) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess); - consumed = true; - } - } else { - scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); - consumed = true; - } - } - } - - return consumed; -} - -void nfc_scene_set_uid_on_exit(void* context) { - NfcApp* nfc = context; - - // Clear view - byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0); - byte_input_set_header_text(nfc->byte_input, ""); -} diff --git a/applications/main/nfc/scenes/nfc_scene_start.c b/applications/main/nfc/scenes/nfc_scene_start.c index 393cdeb843f4..57f43658182f 100644 --- a/applications/main/nfc/scenes/nfc_scene_start.c +++ b/applications/main/nfc/scenes/nfc_scene_start.c @@ -1,5 +1,4 @@ #include "../nfc_app_i.h" -#include "nfc_worker_i.h" #include enum SubmenuIndex { @@ -38,7 +37,6 @@ void nfc_scene_start_on_enter(void* context) { submenu_set_selected_item( submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneStart)); - nfc_device_clear(nfc->dev); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); } @@ -49,21 +47,13 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubmenuIndexRead) { scene_manager_set_scene_state(nfc->scene_manager, NfcSceneStart, SubmenuIndexRead); - nfc->dev->dev_data.read_mode = NfcReadModeAuto; scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); DOLPHIN_DEED(DolphinDeedNfcRead); consumed = true; } else if(event.event == SubmenuIndexDetectReader) { scene_manager_set_scene_state( nfc->scene_manager, NfcSceneStart, SubmenuIndexDetectReader); - bool sd_exist = storage_sd_status(nfc->dev->storage) == FSE_OK; - if(sd_exist) { - nfc_device_data_clear(&nfc->dev->dev_data); - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); - DOLPHIN_DEED(DolphinDeedNfcDetectReader); - } else { - scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound); - } + scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); consumed = true; } else if(event.event == SubmenuIndexSaved) { // Save the scene state explicitly in each branch, so that diff --git a/firmware/targets/furi_hal_include/f_hal_nfc.h b/firmware/targets/furi_hal_include/f_hal_nfc.h index 146c98ef9904..68045a7ee226 100644 --- a/firmware/targets/furi_hal_include/f_hal_nfc.h +++ b/firmware/targets/furi_hal_include/f_hal_nfc.h @@ -41,6 +41,15 @@ typedef enum { typedef enum { FHalNfcModeNfcaPoller, FHalNfcModeNfcaListener, + + FHalNfcModeNfcbPoller, + FHalNfcModeNfcbListener, + + FHalNfcModeNfcfPoller, + FHalNfcModeNfcfListener, + + FHalNfcModeNfcvPoller, + FHalNfcModeNfcvListener, } FHalNfcMode; typedef enum { diff --git a/lib/nfc/nfc.c b/lib/nfc/nfc.c index afe8b60e1983..48b4c87dac26 100644 --- a/lib/nfc/nfc.c +++ b/lib/nfc/nfc.c @@ -7,14 +7,15 @@ typedef enum { NfcStateIdle, - NfcStateConfigured, NfcStateChipSleep, NfcStateChipActive, + NfcStateConfigured, NfcStateFieldOn, NfcStateFieldOff, NfcStateListenStarted, NfcStatePollerReady, + NfcStatePollerReset, NfcStateStopRequested, NfcStateStopped, } NfcState; @@ -110,22 +111,29 @@ static int32_t nfc_worker_poller(void* context) { furi_assert(context); Nfc* instance = context; - furi_assert(instance->state == NfcStateConfigured); + if(instance->state) furi_assert(instance->state == NfcStateConfigured); furi_assert(instance->callback); - f_hal_nfc_poller_field_on(); - if(instance->guard_time_us) { - f_hal_nfc_timer_block_tx_start_us(instance->guard_time_us); - FHalNfcEvent event = f_hal_nfc_wait_event(F_HAL_NFC_EVENT_WAIT_FOREVER); - furi_assert(event & FHalNfcEventTimerBlockTxExpired); - } - - instance->state = NfcStatePollerReady; - - while(instance->state == NfcStatePollerReady) { - NfcEvent event = {.type = NfcEventTypePollerReady}; - instance->callback(event, instance->context); + while(true) { + if(instance->state == NfcStateConfigured) { + f_hal_nfc_poller_field_on(); + instance->state = NfcStateFieldOn; + if(instance->guard_time_us) { + f_hal_nfc_timer_block_tx_start_us(instance->guard_time_us); + FHalNfcEvent event = f_hal_nfc_wait_event(F_HAL_NFC_EVENT_WAIT_FOREVER); + furi_assert(event & FHalNfcEventTimerBlockTxExpired); + } + instance->state = NfcStatePollerReady; + } + if(instance->state == NfcStatePollerReady) { + NfcEvent event = {.type = NfcEventTypePollerReady}; + instance->callback(event, instance->context); + } + if(instance->state == NfcStateStopRequested) { + break; + } } + instance->state = NfcStateStopped; return 0; } @@ -234,7 +242,7 @@ void nfc_poller_abort(Nfc* instance) { furi_assert(instance); // TODO add Mutex for nfc state instance->state = NfcStateStopRequested; - furi_thread_join(instance->worker_thread); + furi_thread_join(instance->worker_thread); } void nfc_poller_stop(Nfc* instance) { diff --git a/lib/nfc/nfc_dev.c b/lib/nfc/nfc_dev.c new file mode 100644 index 000000000000..967870f1d168 --- /dev/null +++ b/lib/nfc/nfc_dev.c @@ -0,0 +1,47 @@ +#include "nfc_dev.h" + +#include + +struct NfcDev { + Storage* storage; + // DialogsApp* dialogs; + // NfcDeviceData dev_data; + // char dev_name[NFC_DEV_NAME_MAX_LEN + 1]; + // FuriString* load_path; + // FuriString* folder; + // NfcDeviceSaveFormat format; + // bool shadow_file_exist; + + // NfcLoadingCallback loading_cb; + // void* loading_cb_ctx; +}; + +NfcDev* nfc_dev_alloc() { + NfcDev* instance = malloc(sizeof(NfcDev)); + + return instance; +} + +void nfc_dev_free(NfcDev* instance) { + furi_assert(instance); +} + +bool nfc_dev_save(NfcDev* instance, NfcDevData* data, const char* path) { + furi_assert(instance); + furi_assert(data); + furi_assert(path); + + bool saved = false; + + return saved; +} + +bool nfc_dev_load(NfcDev* instance, NfcDevData* data, const char* path) { + furi_assert(instance); + furi_assert(data); + furi_assert(path); + + bool loaded = false; + + return loaded; +} diff --git a/lib/nfc/nfc_dev.h b/lib/nfc/nfc_dev.h new file mode 100644 index 000000000000..2385b6ed2281 --- /dev/null +++ b/lib/nfc/nfc_dev.h @@ -0,0 +1,21 @@ +#pragma once + +#include "nfc_device_data.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct NfcDev NfcDev; + +NfcDev* nfc_dev_alloc(); + +void nfc_dev_free(NfcDev* instance); + +bool nfc_dev_save(NfcDev* instance, NfcDevData* data, const char* path); + +bool nfc_dev_load(NfcDev* instance, NfcDevData* data, const char* path); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/nfc_device.h b/lib/nfc/nfc_device.h index 197e864ee96d..8b2e6e5ba308 100644 --- a/lib/nfc/nfc_device.h +++ b/lib/nfc/nfc_device.h @@ -70,7 +70,6 @@ typedef struct { MfUltralightAuth mf_ul_auth; }; union { - NfcaData nfca_data; EmvData emv_data; MfUltralightData mf_ul_data; MfClassicData mf_classic_data; diff --git a/lib/nfc/nfc_device_data.h b/lib/nfc/nfc_device_data.h new file mode 100644 index 000000000000..7c79a208f06d --- /dev/null +++ b/lib/nfc/nfc_device_data.h @@ -0,0 +1,31 @@ +#pragma once + +#include "protocols/nfca.h" +#include "protocols/mf_ultralight.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + NfcDevProtocolNfca, + NfcDevProtocolNfcb, + NfcDevProtocolNfcf, + NfcDevProtocolNfcv, + NfcDevProtocolMfUltralight, + NfcDevProtocolMfClassic, + NfcDevProtocolMfDesfire, +} NfcDevProtocol; + +typedef struct { + NfcDevProtocol protocol; + union { + NfcaData nfca_data; + MfUltralightData mf_ul_data; + }; +} NfcDevData; + +#ifdef __cplusplus +} +#endif + diff --git a/lib/nfc/nfc_poller.c b/lib/nfc/nfc_poller.c new file mode 100644 index 000000000000..8a08ff0df034 --- /dev/null +++ b/lib/nfc/nfc_poller.c @@ -0,0 +1,39 @@ +#include "nfc_poller.h" + +#include + +#include "nfc.h" +#include "protocols/nfca_poller.h" +#include "protocols/mf_ultralight.h" + +typedef enum { + NfcPollerStateIdle, + NfcPollerStateCheckPresenceNfca, + NfcPollerStateCheckPresenceNfcb, + NfcPollerStateCheckPresenceNfcf, + NfcPollerStateCheckPresenceNfcv, +} NfcPollerState; + +struct NfcPoller { + Nfc* nfc; + NfcPollerState state; + NfcPollerEventCallback callback; + void* context; +}; + +NfcPoller* nfc_poller_alloc() { + NfcPoller* instance = malloc(sizeof(NfcPoller)); + return instance; +} + +void nfc_poller_free(NfcPoller* instance) { + furi_assert(instance); +} + +void nfc_poller_start(NfcPoller* instance, NfcPollerEventCallback callback, void* context) { + furi_assert(instance); + furi_assert(callback); + + instance->callback = callback; + instance->context = context; +} diff --git a/lib/nfc/nfc_poller.h b/lib/nfc/nfc_poller.h new file mode 100644 index 000000000000..b1e981105cc1 --- /dev/null +++ b/lib/nfc/nfc_poller.h @@ -0,0 +1,26 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct NfcPoller NfcPoller; + +typedef enum { + NfcPollerEventNfcaDetected, + NfcPollerEventNfcbDetected, + NfcPollerEventNfcfDetected, + NfcPollerEventNfcvDetected, +} NfcPollerEvent; + +typedef void (*NfcPollerEventCallback)(NfcPollerEvent event, void* context); + +NfcPoller* nfc_poller_alloc(); + +void nfc_poller_free(NfcPoller* instance); + +void nfc_poller_start(NfcPoller* instance, NfcPollerEventCallback callback, void* context); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/nfca_poller.h b/lib/nfc/protocols/nfca_poller.h index 8248faa4f80b..c68e491f596c 100644 --- a/lib/nfc/protocols/nfca_poller.h +++ b/lib/nfc/protocols/nfca_poller.h @@ -38,12 +38,12 @@ NfcaError nfca_poller_get_data(NfcaPoller* instance, NfcaData* data); NfcaError nfca_poller_stop(NfcaPoller* instance); -// Syncronous API - NfcaError nfca_poller_check_presence(NfcaPoller* instance); NfcaError nfca_poller_activate(NfcaPoller* instance, NfcaData* nfca_data); +// Syncronous API + NfcaError nfca_poller_activate_sync(NfcaPoller* instance, NfcaData* nfca_data); NfcaError nfca_poller_halt(NfcaPoller* instance); From 27ed14e7252dbecf1da907af9845e38c27fad4ae Mon Sep 17 00:00:00 2001 From: gornekich Date: Wed, 12 Apr 2023 16:02:45 +0400 Subject: [PATCH 022/149] nfc: add uid emultaion --- .../main/nfc/helpers/nfc_custom_event.h | 1 + applications/main/nfc/nfc_app.c | 5 + applications/main/nfc/nfc_app_i.h | 7 + .../main/nfc/scenes/nfc_scene_config.h | 3 +- .../main/nfc/scenes/nfc_scene_nfca_emulate.c | 131 ++++++++++++++++++ .../main/nfc/scenes/nfc_scene_nfca_menu.c | 2 +- .../main/nfc/scenes/nfc_scene_nfca_read.c | 2 + .../main/nfc/scenes/nfc_scene_start.c | 10 +- firmware/targets/f7/furi_hal/f_hal_nfc.c | 2 +- lib/nfc/nfc.c | 4 +- lib/nfc/nfc_poller.c | 1 + lib/nfc/protocols/mf_ultralight.h | 1 + lib/nfc/protocols/nfca_listener.c | 2 +- lib/nfc/protocols/nfca_poller.c | 64 +++++---- lib/nfc/protocols/nfca_poller.h | 10 +- 15 files changed, 204 insertions(+), 41 deletions(-) create mode 100644 applications/main/nfc/scenes/nfc_scene_nfca_emulate.c diff --git a/applications/main/nfc/helpers/nfc_custom_event.h b/applications/main/nfc/helpers/nfc_custom_event.h index 4227a5b14e33..58546c3dd480 100644 --- a/applications/main/nfc/helpers/nfc_custom_event.h +++ b/applications/main/nfc/helpers/nfc_custom_event.h @@ -6,6 +6,7 @@ enum NfcCustomEvent { NfcCustomEventViewExit, NfcCustomEventWorkerExit, + NfcCustomEventWorkerUpdate, NfcCustomEventByteInputDone, NfcCustomEventTextInputDone, NfcCustomEventDictAttackDone, diff --git a/applications/main/nfc/nfc_app.c b/applications/main/nfc/nfc_app.c index fa5fdc1a0f82..d0d934475947 100644 --- a/applications/main/nfc/nfc_app.c +++ b/applications/main/nfc/nfc_app.c @@ -43,6 +43,11 @@ NfcApp* nfc_app_alloc() { view_dispatcher_set_custom_event_callback(nfc->view_dispatcher, nfc_custom_event_callback); view_dispatcher_set_navigation_event_callback(nfc->view_dispatcher, nfc_back_event_callback); + // instance->nfc = nfc_alloc(); + // instance->nfca_poller = nfca_poller_alloc(instance->nfc); + // instance->mf_ul_poller = + + // Nfc device nfc->nfc_dev = nfc_dev_alloc(); diff --git a/applications/main/nfc/nfc_app_i.h b/applications/main/nfc/nfc_app_i.h index 6825321b579a..501fa2a77a4c 100644 --- a/applications/main/nfc/nfc_app_i.h +++ b/applications/main/nfc/nfc_app_i.h @@ -32,6 +32,10 @@ #include #include +#include +#include +#include + #include #define NFC_TEXT_STORE_SIZE 128 @@ -67,6 +71,9 @@ struct NfcApp { Widget* widget; NfcaPoller* nfca_poller; + NfcaListener* nfca_listener; + MfUltralightPoller* mf_ul_poller; + MfUltralightListener* mf_ul_listener; NfcDev* nfc_dev; NfcDevData nfc_dev_data; diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index 236869887f63..cf20ff52fd4f 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -1,7 +1,8 @@ ADD_SCENE(nfc, start, Start) ADD_SCENE(nfc, read, Read) ADD_SCENE(nfc, read_card_type, ReadCardType) -ADD_SCENE(nfc, nfca_read, ReadNfca) +ADD_SCENE(nfc, nfca_read, NfcaRead) +ADD_SCENE(nfc, nfca_emulate, NfcaEmulate) ADD_SCENE(nfc, nfca_read_success, NfcaReadSuccess) ADD_SCENE(nfc, nfca_menu, NfcaMenu) ADD_SCENE(nfc, extra_actions, ExtraActions) diff --git a/applications/main/nfc/scenes/nfc_scene_nfca_emulate.c b/applications/main/nfc/scenes/nfc_scene_nfca_emulate.c new file mode 100644 index 000000000000..6c658b25b350 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_nfca_emulate.c @@ -0,0 +1,131 @@ +#include "../nfc_app_i.h" + +#define NFC_SCENE_NFCA_EMULATE_LOG_SIZE_MAX (200) + +enum { + NfcSceneNfcaEmulateStateWidget, + NfcSceneNfcaEmulateStateTextBox, +}; + +void nfc_scene_nfca_emulate_worker_callback(NfcaListenerEvent event, void* context) { + furi_assert(context); + + NfcApp* nfc = context; + if(event.type == NfcaListenerEventTypeReceivedStandartFrame) { + furi_string_cat_printf(nfc->text_box_store, "R:"); + for(size_t i = 0; i < event.data.rx_bits / 8; i++) { + furi_string_cat_printf(nfc->text_box_store, " %02X", event.data.rx_data[i]); + } + furi_string_cat_printf(nfc->text_box_store, "\n"); + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerUpdate); + } +} + +void nfc_scene_nfca_emulate_widget_callback(GuiButtonType result, InputType type, void* context) { + furi_assert(context); + NfcApp* nfc = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); + } +} + +void nfc_nfca_emulate_textbox_callback(void* context) { + furi_assert(context); + NfcApp* nfc = context; + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); +} + +// Add widget with device name or inform that data received +static void nfc_scene_nfca_emulate_widget_config(NfcApp* nfc, bool data_received) { + NfcaData* data = &nfc->nfc_dev_data.nfca_data; + Widget* widget = nfc->widget; + widget_reset(widget); + FuriString* info_str; + info_str = furi_string_alloc(); + + widget_add_icon_element(widget, 0, 3, &I_NFC_dolphin_emulation_47x61); + widget_add_string_element(widget, 57, 13, AlignLeft, AlignTop, FontPrimary, "Emulating UID"); + for(uint8_t i = 0; i < data->uid_len; i++) { + furi_string_cat_printf(info_str, "%02X ", data->uid[i]); + } + furi_string_trim(info_str); + widget_add_text_box_element( + widget, 57, 28, 67, 25, AlignCenter, AlignTop, furi_string_get_cstr(info_str), true); + furi_string_free(info_str); + if(data_received) { + widget_add_button_element( + widget, GuiButtonTypeCenter, "Log", nfc_scene_nfca_emulate_widget_callback, nfc); + } +} + +void nfc_scene_nfca_emulate_on_enter(void* context) { + NfcApp* nfc = context; + + // Setup Widget + nfc_scene_nfca_emulate_widget_config(nfc, false); + // Setup TextBox + TextBox* text_box = nfc->text_box; + text_box_set_font(text_box, TextBoxFontHex); + text_box_set_focus(text_box, TextBoxFocusEnd); + furi_string_reset(nfc->text_box_store); + + nfc->nfca_listener = nfca_listener_alloc(&nfc->nfc_dev_data.nfca_data); + nfca_listener_set_callback(nfc->nfca_listener, nfc_scene_nfca_emulate_worker_callback, nfc); + + // Set Widget state and view + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneNfcaEmulate, NfcSceneNfcaEmulateStateWidget); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); + + nfc_blink_emulate_start(nfc); +} + +bool nfc_scene_nfca_emulate_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneNfcaEmulate); + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventWorkerUpdate) { + // Add data button to widget if data is received for the first time + if(furi_string_size(nfc->text_box_store)) { + nfc_scene_nfca_emulate_widget_config(nfc, true); + } + // Update TextBox data + text_box_set_text(nfc->text_box, furi_string_get_cstr(nfc->text_box_store)); + consumed = true; + } else if(event.event == GuiButtonTypeCenter && state == NfcSceneNfcaEmulateStateWidget) { + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneNfcaEmulate, NfcSceneNfcaEmulateStateTextBox); + consumed = true; + } else if(event.event == NfcCustomEventViewExit && state == NfcSceneNfcaEmulateStateTextBox) { + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneNfcaEmulate, NfcSceneNfcaEmulateStateWidget); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeBack) { + if(state == NfcSceneNfcaEmulateStateTextBox) { + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneNfcaEmulate, NfcSceneNfcaEmulateStateWidget); + consumed = true; + } + } + + return consumed; +} + +void nfc_scene_nfca_emulate_on_exit(void* context) { + NfcApp* nfc = context; + + nfca_listener_free(nfc->nfca_listener); + + // Clear view + widget_reset(nfc->widget); + text_box_reset(nfc->text_box); + furi_string_reset(nfc->text_box_store); + + nfc_blink_stop(nfc); +} diff --git a/applications/main/nfc/scenes/nfc_scene_nfca_menu.c b/applications/main/nfc/scenes/nfc_scene_nfca_menu.c index 81e868dd2563..abe34caab2a4 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfca_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_nfca_menu.c @@ -38,7 +38,7 @@ bool nfc_scene_nfca_menu_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); consumed = true; } else if(event.event == SubmenuIndexEmulateUid) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcaEmulate); if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneNotImplemented)) { DOLPHIN_DEED(DolphinDeedNfcAddEmulate); } else { diff --git a/applications/main/nfc/scenes/nfc_scene_nfca_read.c b/applications/main/nfc/scenes/nfc_scene_nfca_read.c index 781ba2262152..ac9852c7c6d1 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfca_read.c +++ b/applications/main/nfc/scenes/nfc_scene_nfca_read.c @@ -11,6 +11,8 @@ void nfc_scene_nfca_read_worker_callback(NfcaPollerEvent event, void* context) { if(event.type == NfcaPollerEventTypeActivated) { nfca_poller_stop(nfc->nfca_poller); view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcWorkerEventReadUidNfcA); + } else { + furi_delay_ms(100); } } diff --git a/applications/main/nfc/scenes/nfc_scene_start.c b/applications/main/nfc/scenes/nfc_scene_start.c index 57f43658182f..8f1aa25824d9 100644 --- a/applications/main/nfc/scenes/nfc_scene_start.c +++ b/applications/main/nfc/scenes/nfc_scene_start.c @@ -47,7 +47,15 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubmenuIndexRead) { scene_manager_set_scene_state(nfc->scene_manager, NfcSceneStart, SubmenuIndexRead); - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + // TEST + uint8_t uid[7] = {0x44, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06}; + uint8_t atqa[2] = {0x44, 0x00}; + nfc->nfc_dev_data.nfca_data.sak = 0x00; + nfc->nfc_dev_data.nfca_data.uid_len = 7; + memcpy(nfc->nfc_dev_data.nfca_data.uid, uid, 7); + memcpy(nfc->nfc_dev_data.nfca_data.atqa, atqa, 2); + + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcaEmulate); DOLPHIN_DEED(DolphinDeedNfcRead); consumed = true; } else if(event.event == SubmenuIndexDetectReader) { diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc.c b/firmware/targets/f7/furi_hal/f_hal_nfc.c index 54dee2207887..7e024fc3b9a9 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfc.c +++ b/firmware/targets/f7/furi_hal/f_hal_nfc.c @@ -434,7 +434,7 @@ FHalNfcError f_hal_nfc_listen_start() { FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; furi_hal_spi_acquire(handle); - // f_hal_nfc_trx_reset(); + st25r3916_direct_cmd(handle, ST25R3916_CMD_STOP); uint32_t interrupts = (/*ST25R3916_IRQ_MASK_FWL | ST25R3916_IRQ_MASK_TXE |*/ ST25R3916_IRQ_MASK_RXS /*| ST25R3916_IRQ_MASK_RXE | ST25R3916_IRQ_MASK_PAR | ST25R3916_IRQ_MASK_CRC | diff --git a/lib/nfc/nfc.c b/lib/nfc/nfc.c index 48b4c87dac26..d6c2149b6566 100644 --- a/lib/nfc/nfc.c +++ b/lib/nfc/nfc.c @@ -70,6 +70,7 @@ static int32_t nfc_worker_listener(void* context) { uint16_t rx_bits = 0; f_hal_nfc_listen_start(); + instance->state = NfcStateListenStarted; NfcEvent nfc_event = {}; while(true) { FHalNfcEvent event = f_hal_nfc_wait_event(F_HAL_NFC_EVENT_WAIT_FOREVER); @@ -111,7 +112,7 @@ static int32_t nfc_worker_poller(void* context) { furi_assert(context); Nfc* instance = context; - if(instance->state) furi_assert(instance->state == NfcStateConfigured); + furi_assert(instance->state == NfcStateConfigured); furi_assert(instance->callback); while(true) { @@ -234,7 +235,6 @@ void nfc_start_worker(Nfc* instance, NfcEventCallback callback, void* context) { furi_thread_set_callback(instance->worker_thread, nfc_worker_listener); } furi_thread_start(instance->worker_thread); - instance->state = NfcStateListenStarted; instance->comm_state = NfcCommStateIdle; } diff --git a/lib/nfc/nfc_poller.c b/lib/nfc/nfc_poller.c index 8a08ff0df034..c5c208febae6 100644 --- a/lib/nfc/nfc_poller.c +++ b/lib/nfc/nfc_poller.c @@ -23,6 +23,7 @@ struct NfcPoller { NfcPoller* nfc_poller_alloc() { NfcPoller* instance = malloc(sizeof(NfcPoller)); + return instance; } diff --git a/lib/nfc/protocols/mf_ultralight.h b/lib/nfc/protocols/mf_ultralight.h index 26501ec29ed9..9c5c97cd82e6 100644 --- a/lib/nfc/protocols/mf_ultralight.h +++ b/lib/nfc/protocols/mf_ultralight.h @@ -87,6 +87,7 @@ typedef struct { MfUltralightCounter counter[MF_ULTRALIGHT_COUNTER_NUM]; MfUltralightTearingFlag tearing_flag[MF_ULTRALIGHT_TEARING_FLAG_NUM]; MfUltralightPage page[MF_ULTRALIGHT_MAX_PAGE_NUM]; + uint32_t paged_read; } MfUltralightData; #ifdef __cplusplus diff --git a/lib/nfc/protocols/nfca_listener.c b/lib/nfc/protocols/nfca_listener.c index 8b75fbfd1ab3..091771a11356 100644 --- a/lib/nfc/protocols/nfca_listener.c +++ b/lib/nfc/protocols/nfca_listener.c @@ -54,7 +54,7 @@ static void nfca_listener_event_handler(NfcEvent event, void* context) { NfcaListenerEvent nfca_listener_event = {}; if(event_type == NfcEventTypeListenerActivated) { instance->state = NfcaListenerStateActive; - } else if(event_type == NfcEventTypeRxEnd) { + } else if((event_type == NfcEventTypeRxEnd) && (instance->state == NfcaListenerStateActive)) { if(nfca_listener_halt_received(event.data.rx_data, event.data.rx_bits)) { nfca_listener_sleep(instance); instance->state = NfcaListenerStateIdle; diff --git a/lib/nfc/protocols/nfca_poller.c b/lib/nfc/protocols/nfca_poller.c index 3006c9598160..60882a84d4bb 100644 --- a/lib/nfc/protocols/nfca_poller.c +++ b/lib/nfc/protocols/nfca_poller.c @@ -6,6 +6,8 @@ #define TAG "NFCA" +#define NFCA_POLLER_FLAG_COMMAND_COMPLETE (1UL << 0) + #define NFCA_POLLER_MAX_TX_BUFFER_SIZE (512U) #define NFCA_POLLER_SEL_CMD(cascade_lvl) (0x93 + 2 * (cascade_lvl)) @@ -46,6 +48,12 @@ struct NfcaPoller { void* context; }; +typedef struct { + NfcaPoller* instance; + FuriThreadId thread_id; + NfcaError error; +} NfcaPollerContext; + static NfcaError nfca_poller_process_error(NfcError error) { NfcaError ret = NfcaErrorNone; if(error == NfcErrorNone) { @@ -157,11 +165,11 @@ static void nfca_poller_event_callback(NfcEvent event, void* context) { NfcaPollerEvent nfca_poller_event = {}; if(event.type == NfcEventTypePollerReady) { if(instance->state != NfcaPollerActivated) { - FURI_LOG_I(TAG, "nfca_poller_event_callback, NfcEventTypePollerReady event"); NfcaData data = {}; NfcaError error = nfca_poller_activate(instance, &data); if(error == NfcaErrorNone) { nfca_poller_event.type = NfcaPollerEventTypeActivated; + instance->state = NfcaPollerActivated; } else { nfca_poller_event.type = NfcaPollerEventTypeError; } @@ -202,7 +210,7 @@ NfcaError nfca_poller_check_presence(NfcaPoller* instance) { uint16_t rx_bits = 0; NfcError error = NfcErrorNone; - NfcaError ret = 0; + NfcaError ret = NfcaErrorNone; do { error = nfc_iso13444a_short_frame( instance->nfc, @@ -213,6 +221,7 @@ NfcaError nfca_poller_check_presence(NfcaPoller* instance) { NFCA_FDT_LISTEN_FC); if(error != NfcErrorNone) { ret = nfca_poller_process_error(error); + break; } if(rx_bits != 8 * sizeof(instance->col_res.sens_resp)) { ret = NfcaErrorCommunication; @@ -378,34 +387,6 @@ NfcaError nfca_poller_stop(NfcaPoller* instance) { return NfcaErrorNone; } -typedef struct { - NfcaPoller* instance; - FuriThreadId thread_id; - NfcaError error; -} NfcaPollerContext; - -static void nfca_poller_activate_sync_callback(NfcaPollerEvent event, void* context) { - FURI_LOG_W(TAG, "nfca_poller_activate_sync_callback: %d event", event.type); - NfcaPollerContext* nfca_poller_context = context; - nfca_poller_stop(nfca_poller_context->instance); - nfca_poller_context->error = event.data.error; - furi_thread_flags_set(nfca_poller_context->thread_id, 1); -} - -NfcaError nfca_poller_activate_sync(NfcaPoller* instance, NfcaData* nfca_data) { - furi_assert(instance); - NfcaPollerContext context = {}; - context.instance = instance; - context.thread_id = furi_thread_get_current_id(); - nfca_poller_start(instance, nfca_poller_activate_sync_callback, &context); - furi_thread_flags_wait(1, FuriFlagWaitAny, FuriWaitForever); - furi_thread_flags_clear(1); - if(context.error == NfcaErrorNone) { - *nfca_data = instance->data; - } - return context.error; -} - NfcaError nfca_poller_txrx( NfcaPoller* instance, uint8_t* tx_buff, @@ -463,3 +444,26 @@ NfcaError nfca_poller_send_standart_frame( return ret; } + +static void nfca_poller_sync_callback(NfcaPollerEvent event, void* context) { + NfcaPollerContext* nfca_poller_context = context; + nfca_poller_stop(nfca_poller_context->instance); + nfca_poller_context->error = event.data.error; + furi_thread_flags_set(nfca_poller_context->thread_id, NFCA_POLLER_FLAG_COMMAND_COMPLETE); +} + +NfcaError nfca_poller_activate_sync(NfcaPoller* instance, NfcaData* nfca_data) { + furi_assert(instance); + + NfcaPollerContext context = {}; + context.instance = instance; + context.thread_id = furi_thread_get_current_id(); + nfca_poller_start(instance, nfca_poller_sync_callback, &context); + furi_thread_flags_wait(NFCA_POLLER_FLAG_COMMAND_COMPLETE, FuriFlagWaitAny, FuriWaitForever); + furi_thread_flags_clear(NFCA_POLLER_FLAG_COMMAND_COMPLETE); + if(context.error == NfcaErrorNone) { + *nfca_data = instance->data; + } + + return context.error; +} diff --git a/lib/nfc/protocols/nfca_poller.h b/lib/nfc/protocols/nfca_poller.h index c68e491f596c..41f8abe0cf1f 100644 --- a/lib/nfc/protocols/nfca_poller.h +++ b/lib/nfc/protocols/nfca_poller.h @@ -12,6 +12,7 @@ typedef struct NfcaPoller NfcaPoller; typedef enum { NfcaPollerEventTypeError, + NfcaPollerEventDetected, NfcaPollerEventTypeActivated, NfcaPollerEventTypeReady, } NfcaPollerEventType; @@ -42,10 +43,6 @@ NfcaError nfca_poller_check_presence(NfcaPoller* instance); NfcaError nfca_poller_activate(NfcaPoller* instance, NfcaData* nfca_data); -// Syncronous API - -NfcaError nfca_poller_activate_sync(NfcaPoller* instance, NfcaData* nfca_data); - NfcaError nfca_poller_halt(NfcaPoller* instance); NfcaError nfca_poller_txrx( @@ -66,6 +63,11 @@ NfcaError nfca_poller_send_standart_frame( uint16_t* rx_bits, uint32_t fwt); +// Syncronous API +NfcaError nfca_poller_activate_sync(NfcaPoller* instance, NfcaData* nfca_data); + +NfcaError nfca_poller_check_presence_sync(NfcaPoller* instance); + #ifdef __cplusplus } #endif From b9be7908bf65e34dbf6e6787a046ab7b3bc605af Mon Sep 17 00:00:00 2001 From: gornekich Date: Wed, 12 Apr 2023 18:23:44 +0400 Subject: [PATCH 023/149] nfc: add nfc acquire and release --- firmware/targets/f7/api_symbols.csv | 4 ++- firmware/targets/f7/furi_hal/f_hal_nfc.c | 27 +++++++++++++++++++ firmware/targets/furi_hal_include/f_hal_nfc.h | 5 ++++ lib/nfc/nfc.c | 3 +++ 4 files changed, 38 insertions(+), 1 deletion(-) diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 169d08640afa..b9ccf92d2442 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,+,20.4,, +Version,+,20.5,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -816,6 +816,7 @@ Function,-,expm1,double,double Function,-,expm1f,float,float Function,-,expm1l,long double,long double Function,-,f_hal_nfc_abort,FHalNfcError, +Function,-,f_hal_nfc_acquire,FHalNfcError, Function,-,f_hal_nfc_init,FHalNfcError, Function,-,f_hal_nfc_is_hal_ready,FHalNfcError, Function,-,f_hal_nfc_listen_start,FHalNfcError, @@ -827,6 +828,7 @@ Function,-,f_hal_nfc_low_power_mode_stop,FHalNfcError, Function,-,f_hal_nfc_poller_field_on,FHalNfcError, Function,-,f_hal_nfc_poller_rx,FHalNfcError,"uint8_t*, uint16_t, uint16_t*" Function,-,f_hal_nfc_poller_tx,FHalNfcError,"uint8_t*, uint16_t" +Function,-,f_hal_nfc_release,FHalNfcError, Function,-,f_hal_nfc_set_mask_receive_timer,void,uint32_t Function,-,f_hal_nfc_set_mode,FHalNfcError,"FHalNfcMode, FHalNfcBitrate" Function,-,f_hal_nfc_timer_block_tx_is_running,_Bool, diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc.c b/firmware/targets/f7/furi_hal/f_hal_nfc.c index 7e024fc3b9a9..c849d3c3c87b 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfc.c +++ b/firmware/targets/f7/furi_hal/f_hal_nfc.c @@ -7,6 +7,8 @@ #define TAG "FHalNfc" +static FuriMutex* f_hal_nfc_mutex = NULL; + static FHalNfcError f_hal_nfc_turn_on_osc(FuriHalSpiBusHandle* handle) { FHalNfcError error = FHalNfcErrorNone; @@ -52,6 +54,8 @@ FHalNfcError f_hal_nfc_is_hal_ready() { } FHalNfcError f_hal_nfc_init() { + furi_assert(f_hal_nfc_mutex == NULL); + f_hal_nfc_mutex = furi_mutex_alloc(FuriMutexTypeNormal); FHalNfcError error = FHalNfcErrorNone; f_hal_nfc_event_init(); @@ -221,6 +225,29 @@ FHalNfcError f_hal_nfc_init() { return error; } +static bool f_hal_nfc_is_mine() { + return (furi_mutex_get_owner(f_hal_nfc_mutex) == furi_thread_get_current_id()); +} + +FHalNfcError f_hal_nfc_acquire() { + furi_check(f_hal_nfc_mutex); + + FHalNfcError error = FHalNfcErrorNone; + if(furi_mutex_acquire(f_hal_nfc_mutex, 100) != FuriStatusOk) { + error = FHalNfcErrorBusy; + } + + return error; +} + +FHalNfcError f_hal_nfc_release() { + furi_check(f_hal_nfc_mutex); + furi_check(f_hal_nfc_is_mine()); + furi_check(furi_mutex_release(f_hal_nfc_mutex) == FuriStatusOk); + + return FHalNfcErrorNone; +} + FHalNfcError f_hal_nfc_low_power_mode_start() { FHalNfcError error = FHalNfcErrorNone; FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; diff --git a/firmware/targets/furi_hal_include/f_hal_nfc.h b/firmware/targets/furi_hal_include/f_hal_nfc.h index 68045a7ee226..1a748c064b28 100644 --- a/firmware/targets/furi_hal_include/f_hal_nfc.h +++ b/firmware/targets/furi_hal_include/f_hal_nfc.h @@ -30,6 +30,7 @@ typedef enum { typedef enum { FHalNfcErrorNone, + FHalNfcErrorBusy, FHalNfcErrorChipCommunication, FHalNfcErrorCommunication, FHalNfcErrorOscillator, @@ -103,6 +104,10 @@ FHalNfcError f_hal_nfc_set_mode(FHalNfcMode mode, FHalNfcBitrate bitrate); */ FHalNfcError f_hal_nfc_poller_field_on(); +FHalNfcError f_hal_nfc_acquire(); + +FHalNfcError f_hal_nfc_release(); + FHalNfcError f_hal_nfc_poller_tx(uint8_t* tx_data, uint16_t tx_bits); FHalNfcError f_hal_nfc_poller_rx(uint8_t* rx_data, uint16_t rx_data_size, uint16_t* rx_bits); diff --git a/lib/nfc/nfc.c b/lib/nfc/nfc.c index d6c2149b6566..44db9d5da720 100644 --- a/lib/nfc/nfc.c +++ b/lib/nfc/nfc.c @@ -140,6 +140,8 @@ static int32_t nfc_worker_poller(void* context) { } Nfc* nfc_alloc() { + furi_assert(f_hal_nfc_acquire() == FHalNfcErrorNone); + Nfc* instance = malloc(sizeof(Nfc)); instance->state = NfcStateIdle; f_hal_nfc_low_power_mode_stop(); @@ -167,6 +169,7 @@ void nfc_free(Nfc* instance) { f_hal_nfc_low_power_mode_start(); free(instance); + f_hal_nfc_release(); } void nfc_config(Nfc* instance, NfcMode mode) { From 8c37cf66f77d49cecb07cc2dbf0f7da3a654ec67 Mon Sep 17 00:00:00 2001 From: gornekich Date: Fri, 14 Apr 2023 16:23:21 +0400 Subject: [PATCH 024/149] nfc: rework with new pollers --- applications/main/nfc/nfc_app.c | 140 +++++++++--------- applications/main/nfc/nfc_app_i.h | 4 +- .../main/nfc/scenes/nfc_scene_nfca_emulate.c | 9 +- .../main/nfc/scenes/nfc_scene_nfca_read.c | 3 +- applications/main/nfc/scenes/nfc_scene_read.c | 3 +- .../nfc/scenes/nfc_scene_read_card_type.c | 2 +- applications/main/nfc_rpc/nfc_rpc.c | 12 ++ applications/main/nfc_rpc/nfc_rpc_i.h | 8 +- .../main/nfc_rpc/nfc_rpc_mf_ultralight.c | 46 +++--- applications/main/nfc_rpc/nfc_rpc_nfca.c | 11 +- lib/nfc/helpers/nfc_poller_buffer.c | 34 +++++ lib/nfc/helpers/nfc_poller_buffer.h | 26 ++++ lib/nfc/nfc.c | 6 + lib/nfc/nfc.h | 2 + lib/nfc/protocols/mf_ultralight.h | 10 ++ lib/nfc/protocols/mf_ultralight_listener.c | 89 +++++++++-- lib/nfc/protocols/mf_ultralight_listener.h | 28 +++- lib/nfc/protocols/mf_ultralight_poller.c | 123 ++++++++++++--- lib/nfc/protocols/mf_ultralight_poller.h | 47 +++++- lib/nfc/protocols/nfca_listener.c | 68 ++++++--- lib/nfc/protocols/nfca_listener.h | 16 +- lib/nfc/protocols/nfca_poller.c | 60 +++++--- lib/nfc/protocols/nfca_poller.h | 9 +- 23 files changed, 573 insertions(+), 183 deletions(-) create mode 100644 lib/nfc/helpers/nfc_poller_buffer.c create mode 100644 lib/nfc/helpers/nfc_poller_buffer.h diff --git a/applications/main/nfc/nfc_app.c b/applications/main/nfc/nfc_app.c index d0d934475947..4474c3cec27e 100644 --- a/applications/main/nfc/nfc_app.c +++ b/applications/main/nfc/nfc_app.c @@ -34,140 +34,148 @@ static void nfc_rpc_command_callback(RpcAppSystemEvent event, void* context) { } NfcApp* nfc_app_alloc() { - NfcApp* nfc = malloc(sizeof(NfcApp)); + NfcApp* instance = malloc(sizeof(NfcApp)); - nfc->view_dispatcher = view_dispatcher_alloc(); - nfc->scene_manager = scene_manager_alloc(&nfc_scene_handlers, nfc); - view_dispatcher_enable_queue(nfc->view_dispatcher); - view_dispatcher_set_event_callback_context(nfc->view_dispatcher, nfc); - view_dispatcher_set_custom_event_callback(nfc->view_dispatcher, nfc_custom_event_callback); - view_dispatcher_set_navigation_event_callback(nfc->view_dispatcher, nfc_back_event_callback); + instance->view_dispatcher = view_dispatcher_alloc(); + instance->scene_manager = scene_manager_alloc(&nfc_scene_handlers, instance); + view_dispatcher_enable_queue(instance->view_dispatcher); + view_dispatcher_set_event_callback_context(instance->view_dispatcher, instance); + view_dispatcher_set_custom_event_callback(instance->view_dispatcher, nfc_custom_event_callback); + view_dispatcher_set_navigation_event_callback(instance->view_dispatcher, nfc_back_event_callback); - // instance->nfc = nfc_alloc(); - // instance->nfca_poller = nfca_poller_alloc(instance->nfc); - // instance->mf_ul_poller = + instance->nfc = nfc_alloc(); + instance->nfca_poller = nfca_poller_alloc(instance->nfc); + instance->mf_ul_poller = mf_ultralight_poller_alloc(instance->nfca_poller); + instance->nfca_listener = nfca_listener_alloc(instance->nfc); + instance->mf_ul_listener = mf_ultralight_listener_alloc(instance->nfca_listener); // Nfc device - nfc->nfc_dev = nfc_dev_alloc(); + instance->nfc_dev = nfc_dev_alloc(); // Open GUI record - nfc->gui = furi_record_open(RECORD_GUI); + instance->gui = furi_record_open(RECORD_GUI); // Open Notification record - nfc->notifications = furi_record_open(RECORD_NOTIFICATION); + instance->notifications = furi_record_open(RECORD_NOTIFICATION); // Submenu - nfc->submenu = submenu_alloc(); - view_dispatcher_add_view(nfc->view_dispatcher, NfcViewMenu, submenu_get_view(nfc->submenu)); + instance->submenu = submenu_alloc(); + view_dispatcher_add_view(instance->view_dispatcher, NfcViewMenu, submenu_get_view(instance->submenu)); // Dialog - nfc->dialog_ex = dialog_ex_alloc(); + instance->dialog_ex = dialog_ex_alloc(); view_dispatcher_add_view( - nfc->view_dispatcher, NfcViewDialogEx, dialog_ex_get_view(nfc->dialog_ex)); + instance->view_dispatcher, NfcViewDialogEx, dialog_ex_get_view(instance->dialog_ex)); // Popup - nfc->popup = popup_alloc(); - view_dispatcher_add_view(nfc->view_dispatcher, NfcViewPopup, popup_get_view(nfc->popup)); + instance->popup = popup_alloc(); + view_dispatcher_add_view(instance->view_dispatcher, NfcViewPopup, popup_get_view(instance->popup)); // Loading - nfc->loading = loading_alloc(); - view_dispatcher_add_view(nfc->view_dispatcher, NfcViewLoading, loading_get_view(nfc->loading)); + instance->loading = loading_alloc(); + view_dispatcher_add_view(instance->view_dispatcher, NfcViewLoading, loading_get_view(instance->loading)); // Text Input - nfc->text_input = text_input_alloc(); + instance->text_input = text_input_alloc(); view_dispatcher_add_view( - nfc->view_dispatcher, NfcViewTextInput, text_input_get_view(nfc->text_input)); + instance->view_dispatcher, NfcViewTextInput, text_input_get_view(instance->text_input)); // Byte Input - nfc->byte_input = byte_input_alloc(); + instance->byte_input = byte_input_alloc(); view_dispatcher_add_view( - nfc->view_dispatcher, NfcViewByteInput, byte_input_get_view(nfc->byte_input)); + instance->view_dispatcher, NfcViewByteInput, byte_input_get_view(instance->byte_input)); // TextBox - nfc->text_box = text_box_alloc(); + instance->text_box = text_box_alloc(); view_dispatcher_add_view( - nfc->view_dispatcher, NfcViewTextBox, text_box_get_view(nfc->text_box)); - nfc->text_box_store = furi_string_alloc(); + instance->view_dispatcher, NfcViewTextBox, text_box_get_view(instance->text_box)); + instance->text_box_store = furi_string_alloc(); // Custom Widget - nfc->widget = widget_alloc(); - view_dispatcher_add_view(nfc->view_dispatcher, NfcViewWidget, widget_get_view(nfc->widget)); + instance->widget = widget_alloc(); + view_dispatcher_add_view(instance->view_dispatcher, NfcViewWidget, widget_get_view(instance->widget)); - return nfc; + return instance; } -void nfc_app_free(NfcApp* nfc) { - furi_assert(nfc); +void nfc_app_free(NfcApp* instance) { + furi_assert(instance); - // if(nfc->rpc_state == NfcRpcStateEmulating) { + // if(instance->rpc_state == NfcRpcStateEmulating) { // // Stop worker - // nfc_worker_stop(nfc->worker); - // } else if(nfc->rpc_state == NfcRpcStateEmulated) { + // nfc_worker_stop(instance->worker); + // } else if(instance->rpc_state == NfcRpcStateEmulated) { // // Stop worker - // nfc_worker_stop(nfc->worker); + // nfc_worker_stop(instance->worker); // // Save data in shadow file - // if(furi_string_size(nfc->dev->load_path)) { - // nfc_device_save_shadow(nfc->dev, furi_string_get_cstr(nfc->dev->load_path)); + // if(furi_string_size(instance->dev->load_path)) { + // nfc_device_save_shadow(instance->dev, furi_string_get_cstr(instance->dev->load_path)); // } // } - if(nfc->rpc_ctx) { - rpc_system_app_send_exited(nfc->rpc_ctx); - rpc_system_app_set_callback(nfc->rpc_ctx, NULL, NULL); - nfc->rpc_ctx = NULL; + if(instance->rpc_ctx) { + rpc_system_app_send_exited(instance->rpc_ctx); + rpc_system_app_set_callback(instance->rpc_ctx, NULL, NULL); + instance->rpc_ctx = NULL; } + mf_ultralight_listener_free(instance->mf_ul_listener); + mf_ultralight_poller_free(instance->mf_ul_poller); + nfca_listener_free(instance->nfca_listener); + nfca_poller_free(instance->nfca_poller); + nfc_free(instance->nfc); + // Nfc device - nfc_dev_free(nfc->nfc_dev); + nfc_dev_free(instance->nfc_dev); // Submenu - view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewMenu); - submenu_free(nfc->submenu); + view_dispatcher_remove_view(instance->view_dispatcher, NfcViewMenu); + submenu_free(instance->submenu); // DialogEx - view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewDialogEx); - dialog_ex_free(nfc->dialog_ex); + view_dispatcher_remove_view(instance->view_dispatcher, NfcViewDialogEx); + dialog_ex_free(instance->dialog_ex); // Popup - view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewPopup); - popup_free(nfc->popup); + view_dispatcher_remove_view(instance->view_dispatcher, NfcViewPopup); + popup_free(instance->popup); // Loading - view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewLoading); - loading_free(nfc->loading); + view_dispatcher_remove_view(instance->view_dispatcher, NfcViewLoading); + loading_free(instance->loading); // TextInput - view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewTextInput); - text_input_free(nfc->text_input); + view_dispatcher_remove_view(instance->view_dispatcher, NfcViewTextInput); + text_input_free(instance->text_input); // ByteInput - view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewByteInput); - byte_input_free(nfc->byte_input); + view_dispatcher_remove_view(instance->view_dispatcher, NfcViewByteInput); + byte_input_free(instance->byte_input); // TextBox - view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewTextBox); - text_box_free(nfc->text_box); - furi_string_free(nfc->text_box_store); + view_dispatcher_remove_view(instance->view_dispatcher, NfcViewTextBox); + text_box_free(instance->text_box); + furi_string_free(instance->text_box_store); // Custom Widget - view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewWidget); - widget_free(nfc->widget); + view_dispatcher_remove_view(instance->view_dispatcher, NfcViewWidget); + widget_free(instance->widget); // View Dispatcher - view_dispatcher_free(nfc->view_dispatcher); + view_dispatcher_free(instance->view_dispatcher); // Scene Manager - scene_manager_free(nfc->scene_manager); + scene_manager_free(instance->scene_manager); // GUI furi_record_close(RECORD_GUI); - nfc->gui = NULL; + instance->gui = NULL; // Notifications furi_record_close(RECORD_NOTIFICATION); - nfc->notifications = NULL; + instance->notifications = NULL; - free(nfc); + free(instance); } void nfc_text_store_set(NfcApp* nfc, const char* text, ...) { diff --git a/applications/main/nfc/nfc_app_i.h b/applications/main/nfc/nfc_app_i.h index 501fa2a77a4c..48fe483ccc30 100644 --- a/applications/main/nfc/nfc_app_i.h +++ b/applications/main/nfc/nfc_app_i.h @@ -31,6 +31,7 @@ #include +#include #include #include #include @@ -70,6 +71,7 @@ struct NfcApp { TextBox* text_box; Widget* widget; + Nfc* nfc; NfcaPoller* nfca_poller; NfcaListener* nfca_listener; MfUltralightPoller* mf_ul_poller; @@ -92,8 +94,6 @@ typedef enum { NfcViewDetectReader, } NfcView; -NfcApp* nfc_alloc(); - int32_t nfc_task(void* p); void nfc_text_store_set(NfcApp* nfc, const char* text, ...); diff --git a/applications/main/nfc/scenes/nfc_scene_nfca_emulate.c b/applications/main/nfc/scenes/nfc_scene_nfca_emulate.c index 6c658b25b350..fd674e8739d0 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfca_emulate.c +++ b/applications/main/nfc/scenes/nfc_scene_nfca_emulate.c @@ -69,8 +69,11 @@ void nfc_scene_nfca_emulate_on_enter(void* context) { text_box_set_focus(text_box, TextBoxFocusEnd); furi_string_reset(nfc->text_box_store); - nfc->nfca_listener = nfca_listener_alloc(&nfc->nfc_dev_data.nfca_data); - nfca_listener_set_callback(nfc->nfca_listener, nfc_scene_nfca_emulate_worker_callback, nfc); + nfca_listener_start( + nfc->nfca_listener, + &nfc->nfc_dev_data.nfca_data, + nfc_scene_nfca_emulate_worker_callback, + nfc); // Set Widget state and view scene_manager_set_scene_state( @@ -120,7 +123,7 @@ bool nfc_scene_nfca_emulate_on_event(void* context, SceneManagerEvent event) { void nfc_scene_nfca_emulate_on_exit(void* context) { NfcApp* nfc = context; - nfca_listener_free(nfc->nfca_listener); + nfca_listener_reset(nfc->nfca_listener); // Clear view widget_reset(nfc->widget); diff --git a/applications/main/nfc/scenes/nfc_scene_nfca_read.c b/applications/main/nfc/scenes/nfc_scene_nfca_read.c index ac9852c7c6d1..80229106540c 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfca_read.c +++ b/applications/main/nfc/scenes/nfc_scene_nfca_read.c @@ -22,7 +22,6 @@ void nfc_scene_nfca_read_on_enter(void* context) { // Setup view view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); - nfc->nfca_poller = nfca_poller_alloc(); nfca_poller_start(nfc->nfca_poller, nfc_scene_nfca_read_worker_callback, nfc); nfc_blink_read_start(nfc); @@ -36,7 +35,6 @@ bool nfc_scene_nfca_read_on_event(void* context, SceneManagerEvent event) { if(event.event == NfcWorkerEventReadUidNfcA) { notification_message(nfc->notifications, &sequence_success); nfca_poller_get_data(nfc->nfca_poller, &nfc->nfc_dev_data.nfca_data); - nfca_poller_free(nfc->nfca_poller); scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcaReadSuccess); DOLPHIN_DEED(DolphinDeedNfcReadSuccess); consumed = true; @@ -48,6 +46,7 @@ bool nfc_scene_nfca_read_on_event(void* context, SceneManagerEvent event) { void nfc_scene_nfca_read_on_exit(void* context) { NfcApp* nfc = context; + nfca_poller_reset(nfc->nfca_poller); // Clear view popup_reset(nfc->popup); diff --git a/applications/main/nfc/scenes/nfc_scene_read.c b/applications/main/nfc/scenes/nfc_scene_read.c index 51d2f98167e3..5e089934229a 100644 --- a/applications/main/nfc/scenes/nfc_scene_read.c +++ b/applications/main/nfc/scenes/nfc_scene_read.c @@ -23,7 +23,6 @@ void nfc_scene_read_on_enter(void* context) { popup_set_icon(nfc->popup, 0, 8, &I_NFC_manual_60x50); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); - nfc->nfca_poller = nfca_poller_alloc(); nfca_poller_start(nfc->nfca_poller, nfc_scene_read_worker_callback, nfc); nfc_blink_read_start(nfc); @@ -37,7 +36,6 @@ bool nfc_scene_read_on_event(void* context, SceneManagerEvent event) { if(event.event == NfcWorkerEventReadUidNfcA) { notification_message(nfc->notifications, &sequence_success); nfca_poller_get_data(nfc->nfca_poller, &nfc->nfc_dev_data.nfca_data); - nfca_poller_free(nfc->nfca_poller); scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcaReadSuccess); DOLPHIN_DEED(DolphinDeedNfcReadSuccess); consumed = true; @@ -49,6 +47,7 @@ bool nfc_scene_read_on_event(void* context, SceneManagerEvent event) { void nfc_scene_read_on_exit(void* context) { NfcApp* nfc = context; + nfca_poller_reset(nfc->nfca_poller); // Clear view popup_reset(nfc->popup); diff --git a/applications/main/nfc/scenes/nfc_scene_read_card_type.c b/applications/main/nfc/scenes/nfc_scene_read_card_type.c index 79c9297e57e0..3d079dc8a71c 100644 --- a/applications/main/nfc/scenes/nfc_scene_read_card_type.c +++ b/applications/main/nfc/scenes/nfc_scene_read_card_type.c @@ -76,7 +76,7 @@ bool nfc_scene_read_card_type_on_event(void* context, SceneManagerEvent event) { consumed = true; } if(event.event == SubmenuIndexReadNFCA) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcaRead); consumed = true; } scene_manager_set_scene_state(nfc->scene_manager, NfcSceneReadCardType, event.event); diff --git a/applications/main/nfc_rpc/nfc_rpc.c b/applications/main/nfc_rpc/nfc_rpc.c index 57d48ea30406..852875b05385 100644 --- a/applications/main/nfc_rpc/nfc_rpc.c +++ b/applications/main/nfc_rpc/nfc_rpc.c @@ -132,6 +132,12 @@ bool nfc_rpc_custom_event_callback(void* context, uint32_t event) { static NfcRpc* nfc_rpc_app_alloc() { NfcRpc* instance = malloc(sizeof(NfcRpc)); + instance->nfc = nfc_alloc(); + instance->nfca_poller = nfca_poller_alloc(instance->nfc); + instance->mf_ul_poller = mf_ultralight_poller_alloc(instance->nfca_poller); + instance->nfca_listener = nfca_listener_alloc(instance->nfc); + instance->mf_ul_listener = mf_ultralight_listener_alloc(instance->nfca_listener); + NfcRpcHandlerDict_init(instance->handlers); for(size_t i = 0; i < COUNT_OF(nfc_rpc_callbacks); i++) { if(nfc_rpc_callbacks[i].alloc) { @@ -165,6 +171,12 @@ static NfcRpc* nfc_rpc_app_alloc() { void nfc_rpc_app_free(NfcRpc* instance) { furi_assert(instance); + mf_ultralight_listener_free(instance->mf_ul_listener); + mf_ultralight_poller_free(instance->mf_ul_poller); + nfca_listener_free(instance->nfca_listener); + nfca_poller_free(instance->nfca_poller); + nfc_free(instance->nfc); + for(size_t i = 0; i < COUNT_OF(nfc_rpc_callbacks); i++) { if(nfc_rpc_callbacks[i].free) { nfc_rpc_callbacks[i].free(instance); diff --git a/applications/main/nfc_rpc/nfc_rpc_i.h b/applications/main/nfc_rpc/nfc_rpc_i.h index a06a18a722de..795d2336df30 100644 --- a/applications/main/nfc_rpc/nfc_rpc_i.h +++ b/applications/main/nfc_rpc/nfc_rpc_i.h @@ -15,6 +15,7 @@ #include "assets/compiled/main.pb.h" #include +#include #include #include #include @@ -51,10 +52,13 @@ struct NfcRpc { FuriMessageQueue* queue; ViewDispatcher* view_dispatcher; View* view; + NfcRpcHandlerDict_t handlers; + + Nfc* nfc; + NfcaPoller* nfca_poller; NfcaListener* nfca_listener; + MfUltralightPoller* mf_ul_poller; MfUltralightListener* mf_ul_listener; - - NfcRpcHandlerDict_t handlers; }; typedef struct { diff --git a/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c b/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c index adf2d8e72c20..b3cc0f1e02a2 100644 --- a/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c +++ b/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c @@ -36,13 +36,14 @@ static PB_MfUltralight_Error nfc_rpc_mf_ultralight_process_error(MfUltralightErr static void nfc_rpc_mf_ultralight_read_page(Nfc_Main* cmd, void* context) { furi_assert(cmd); furi_assert(context); + + NfcRpc* instance = context; PB_MfUltralight_ReadPageResponse pb_mf_ul_read_page_resp = PB_MfUltralight_ReadPageResponse_init_default; - MfUltralightPoller* poller = mf_ultralight_poller_alloc(); MfUltralightPage page = {}; MfUltralightError error = mf_ultralight_poller_read_page( - poller, cmd->content.mf_ultralight_read_page_req.page, &page); + instance->mf_ul_poller, cmd->content.mf_ultralight_read_page_req.page, &page); cmd->command_status = Nfc_CommandStatus_OK; cmd->which_content = Nfc_Main_mf_ultralight_read_page_resp_tag; @@ -54,38 +55,40 @@ static void nfc_rpc_mf_ultralight_read_page(Nfc_Main* cmd, void* context) { } cmd->content.mf_ultralight_read_page_resp = pb_mf_ul_read_page_resp; - mf_ultralight_poller_free(poller); + mf_ultralight_poller_reset(instance->mf_ul_poller); } static void nfc_rpc_mf_ultralight_write_page(Nfc_Main* cmd, void* context) { furi_assert(cmd); furi_assert(context); + + NfcRpc* instance = context; PB_MfUltralight_WritePageResponse pb_mf_ul_write_page_resp = PB_MfUltralight_WritePageResponse_init_default; - MfUltralightPoller* poller = mf_ultralight_poller_alloc(); MfUltralightPage data = {}; memcpy(&data, cmd->content.mf_ultralight_write_page_req.data.bytes, sizeof(MfUltralightPage)); uint16_t page = cmd->content.mf_ultralight_write_page_req.page; - MfUltralightError error = mf_ultralight_poller_write_page(poller, page, &data); + MfUltralightError error = mf_ultralight_poller_write_page(instance->mf_ul_poller, page, &data); cmd->which_content = Nfc_Main_mf_ultralight_write_page_resp_tag; cmd->command_status = Nfc_CommandStatus_OK; pb_mf_ul_write_page_resp.error = nfc_rpc_mf_ultralight_process_error(error); cmd->content.mf_ultralight_write_page_resp = pb_mf_ul_write_page_resp; - mf_ultralight_poller_free(poller); + mf_ultralight_poller_reset(instance->mf_ul_poller); } static void nfc_rpc_mf_ultralight_read_version(Nfc_Main* cmd, void* context) { furi_assert(cmd); furi_assert(context); + + NfcRpc* instance = context; PB_MfUltralight_ReadVersionResponse pb_mf_ul_version = PB_MfUltralight_ReadVersionResponse_init_default; - MfUltralightPoller* poller = mf_ultralight_poller_alloc(); MfUltralightVersion data = {}; - MfUltralightError error = mf_ultralight_poller_read_version(poller, &data); + MfUltralightError error = mf_ultralight_poller_read_version(instance->mf_ul_poller, &data); cmd->command_status = Nfc_CommandStatus_OK; cmd->which_content = Nfc_Main_mf_ultralight_read_version_resp_tag; @@ -102,18 +105,19 @@ static void nfc_rpc_mf_ultralight_read_version(Nfc_Main* cmd, void* context) { } cmd->content.mf_ultralight_read_version_resp = pb_mf_ul_version; - mf_ultralight_poller_free(poller); + mf_ultralight_poller_reset(instance->mf_ul_poller); } static void nfc_rpc_mf_ultralight_read_signature(Nfc_Main* cmd, void* context) { furi_assert(cmd); furi_assert(context); + + NfcRpc* instance = context; PB_MfUltralight_ReadSignatureResponse pb_mf_ul_signature = PB_MfUltralight_ReadSignatureResponse_init_default; - MfUltralightPoller* poller = mf_ultralight_poller_alloc(); MfUltralightSignature data = {}; - MfUltralightError error = mf_ultralight_poller_read_signature(poller, &data); + MfUltralightError error = mf_ultralight_poller_read_signature(instance->mf_ul_poller, &data); cmd->command_status = Nfc_CommandStatus_OK; cmd->which_content = Nfc_Main_mf_ultralight_read_signature_resp_tag; @@ -124,19 +128,20 @@ static void nfc_rpc_mf_ultralight_read_signature(Nfc_Main* cmd, void* context) { } cmd->content.mf_ultralight_read_signature_resp = pb_mf_ul_signature; - mf_ultralight_poller_free(poller); + mf_ultralight_poller_reset(instance->mf_ul_poller); } static void nfc_rpc_mf_ultralight_read_counter(Nfc_Main* cmd, void* context) { furi_assert(cmd); furi_assert(context); + + NfcRpc* instance = context; PB_MfUltralight_ReadCounterResponse pb_mf_ul_read_counter_resp = PB_MfUltralight_ReadPageResponse_init_default; - MfUltralightPoller* poller = mf_ultralight_poller_alloc(); MfUltralightCounter data = {}; MfUltralightError error = mf_ultralight_poller_read_counter( - poller, cmd->content.mf_ultralight_read_counter_req.counter_num, &data); + instance->mf_ul_poller, cmd->content.mf_ultralight_read_counter_req.counter_num, &data); cmd->command_status = Nfc_CommandStatus_OK; cmd->which_content = Nfc_Main_mf_ultralight_read_counter_resp_tag; @@ -149,19 +154,20 @@ static void nfc_rpc_mf_ultralight_read_counter(Nfc_Main* cmd, void* context) { } cmd->content.mf_ultralight_read_counter_resp = pb_mf_ul_read_counter_resp; - mf_ultralight_poller_free(poller); + mf_ultralight_poller_reset(instance->mf_ul_poller); } static void nfc_rpc_mf_ultralight_read_tearing_flag(Nfc_Main* cmd, void* context) { furi_assert(cmd); furi_assert(context); + + NfcRpc* instance = context; PB_MfUltralight_ReadTearingFlagResponse pb_mf_ul_read_tearing_flag_resp = PB_MfUltralight_ReadTearingFlagResponse_init_default; - MfUltralightPoller* poller = mf_ultralight_poller_alloc(); MfUltralightTearingFlag data = {}; MfUltralightError error = mf_ultralight_poller_read_tearing_flag( - poller, cmd->content.mf_ultralight_read_tearing_flag_req.flag_num, &data); + instance->mf_ul_poller, cmd->content.mf_ultralight_read_tearing_flag_req.flag_num, &data); cmd->command_status = Nfc_CommandStatus_OK; cmd->which_content = Nfc_Main_mf_ultralight_read_tearing_flag_resp_tag; @@ -179,7 +185,7 @@ static void nfc_rpc_mf_ultralight_read_tearing_flag(Nfc_Main* cmd, void* context FURI_LOG_D( TAG, "Tearing flag %ld: %02X", pb_mf_ul_read_tearing_flag_resp.flag_num, data.data[0]); - mf_ultralight_poller_free(poller); + mf_ultralight_poller_reset(instance->mf_ul_poller); } // TODO DELETE! @@ -218,7 +224,7 @@ void nfc_rpc_mf_ultralight_emulate_start(Nfc_Main* cmd, void* context) { MfUltralightData mf_ul_data = {}; // TODO initialize data from rpc message init_mf_ul_data(&mf_ul_data); - instance->mf_ul_listener = mf_ultralight_listener_alloc(&mf_ul_data); + mf_ultralight_listener_start(instance->mf_ul_listener, &mf_ul_data, NULL, NULL); pb_mf_ultralight_emulate_start_resp.error = PB_MfUltralight_Error_None; } else { // TODO add Busy error @@ -238,7 +244,7 @@ void nfc_rpc_mf_ultralight_emulate_stop(Nfc_Main* cmd, void* context) { cmd->which_content = Nfc_Main_mf_ultralight_emulate_stop_resp_tag; if(instance->mf_ul_listener) { // Stop before free - mf_ultralight_listener_free(instance->mf_ul_listener); + mf_ultralight_listener_reset(instance->mf_ul_listener); instance->mf_ul_listener = NULL; pb_mf_ultralight_emulate_stop_resp.error = PB_MfUltralight_Error_None; } else { diff --git a/applications/main/nfc_rpc/nfc_rpc_nfca.c b/applications/main/nfc_rpc/nfc_rpc_nfca.c index 7ca0c757d007..42a75685588e 100644 --- a/applications/main/nfc_rpc/nfc_rpc_nfca.c +++ b/applications/main/nfc_rpc/nfc_rpc_nfca.c @@ -44,11 +44,12 @@ static PB_Nfca_Error nfc_rpc_nfca_process_error(NfcaError error) { static void nfc_rpc_nfca_read(Nfc_Main* cmd, void* context) { furi_assert(cmd); furi_assert(context); + + NfcRpc* instance = context; PB_Nfca_ReadResponse pb_nfca_read_resp = PB_Nfca_ReadResponse_init_default; NfcaData nfca_data = {}; - NfcaPoller* nfca_poller = nfca_poller_alloc(); - NfcaError error = nfca_poller_activate_sync(nfca_poller, &nfca_data); + NfcaError error = nfca_poller_activate_sync(instance->nfca_poller, &nfca_data); cmd->command_status = Nfc_CommandStatus_OK; cmd->which_content = Nfc_Main_nfca_read_resp_tag; @@ -64,7 +65,7 @@ static void nfc_rpc_nfca_read(Nfc_Main* cmd, void* context) { } cmd->content.nfca_read_resp = pb_nfca_read_resp; - nfca_poller_free(nfca_poller); + nfca_poller_reset(instance->nfca_poller); } static void nfc_rpc_nfca_emulate_start(Nfc_Main* cmd, void* context) { @@ -83,7 +84,7 @@ static void nfc_rpc_nfca_emulate_start(Nfc_Main* cmd, void* context) { memcpy(nfca_data.atqa, cmd->content.nfca_emulate_start_req.atqa.bytes, 2); memcpy(&nfca_data.sak, cmd->content.nfca_emulate_start_req.sak.bytes, 1); - instance->nfca_listener = nfca_listener_alloc(&nfca_data); + nfca_listener_start(instance->nfca_listener, &nfca_data, NULL, NULL); pb_nfca_emulate_start_resp.error = PB_Nfca_Error_None; } else { // TODO add Busy error @@ -102,7 +103,7 @@ static void nfc_rpc_nfca_emulate_stop(Nfc_Main* cmd, void* context) { cmd->command_status = Nfc_CommandStatus_OK; cmd->which_content = Nfc_Main_nfca_emulate_stop_resp_tag; if(instance->nfca_listener) { - nfca_listener_free(instance->nfca_listener); + nfca_listener_reset(instance->nfca_listener); instance->nfca_listener = NULL; pb_nfca_emulate_stop_resp.error = PB_Nfca_Error_None; } else { diff --git a/lib/nfc/helpers/nfc_poller_buffer.c b/lib/nfc/helpers/nfc_poller_buffer.c new file mode 100644 index 000000000000..ea0bb251deb5 --- /dev/null +++ b/lib/nfc/helpers/nfc_poller_buffer.c @@ -0,0 +1,34 @@ +#include "nfc_poller_buffer.h" + +#include + +NfcPollerBuffer* nfc_poller_buffer_alloc(uint16_t tx_bytes_max, uint16_t rx_bytes_max) { + NfcPollerBuffer* instance = malloc(sizeof(NfcPollerBuffer)); + instance->tx_data = malloc(tx_bytes_max); + instance->tx_data_size = tx_bytes_max; + instance->rx_data = malloc(rx_bytes_max); + instance->rx_data_size = rx_bytes_max; + + return instance; +} + +void nfc_poller_buffer_free(NfcPollerBuffer* instance) { + furi_assert(instance); + furi_assert(instance->tx_data); + furi_assert(instance->rx_data); + + free(instance->tx_data); + free(instance->rx_data); + free(instance); +} + +void nfc_poller_buffer_reset(NfcPollerBuffer* instance) { + furi_assert(instance); + furi_assert(instance->tx_data); + furi_assert(instance->rx_data); + + memset(instance->tx_data, 0, instance->tx_data_size); + memset(instance->rx_data, 0, instance->rx_data_size); + instance->tx_bits = 0; + instance->rx_bits = 0; +} diff --git a/lib/nfc/helpers/nfc_poller_buffer.h b/lib/nfc/helpers/nfc_poller_buffer.h new file mode 100644 index 000000000000..3f7e245053f8 --- /dev/null +++ b/lib/nfc/helpers/nfc_poller_buffer.h @@ -0,0 +1,26 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + uint8_t* tx_data; + uint16_t tx_data_size; + uint16_t tx_bits; + uint8_t* rx_data; + uint16_t rx_data_size; + uint16_t rx_bits; +} NfcPollerBuffer; + +NfcPollerBuffer* nfc_poller_buffer_alloc(uint16_t tx_bytes_max, uint16_t rx_bytes_max); + +void nfc_poller_buffer_free(NfcPollerBuffer* instance); + +void nfc_poller_buffer_reset(NfcPollerBuffer* instance); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/nfc.c b/lib/nfc/nfc.c index 44db9d5da720..f37607369072 100644 --- a/lib/nfc/nfc.c +++ b/lib/nfc/nfc.c @@ -248,6 +248,12 @@ void nfc_poller_abort(Nfc* instance) { furi_thread_join(instance->worker_thread); } +void nfc_listener_abort(Nfc* instance) { + furi_assert(instance); + f_hal_nfc_abort(); + furi_thread_join(instance->worker_thread); +} + void nfc_poller_stop(Nfc* instance) { furi_assert(instance); instance->state = NfcStateStopRequested; diff --git a/lib/nfc/nfc.h b/lib/nfc/nfc.h index 8277bec68944..f61c6c981eb3 100644 --- a/lib/nfc/nfc.h +++ b/lib/nfc/nfc.h @@ -88,6 +88,8 @@ NfcError nfc_listener_sleep(Nfc* instance); void nfc_poller_abort(Nfc* instance); +void nfc_listener_abort(Nfc* instance); + // Called from worker thread void nfc_poller_stop(Nfc* instance); diff --git a/lib/nfc/protocols/mf_ultralight.h b/lib/nfc/protocols/mf_ultralight.h index 9c5c97cd82e6..1807896d0680 100644 --- a/lib/nfc/protocols/mf_ultralight.h +++ b/lib/nfc/protocols/mf_ultralight.h @@ -22,6 +22,8 @@ extern "C" { #define MF_ULTRALIGHT_COUNTER_NUM (3) #define MF_ULTRALIGHT_TEARING_FLAG_SIZE (1) #define MF_ULTRALIGHT_TEARING_FLAG_NUM (3) +#define MF_ULTRALIGHT_AUTH_PASSWORD_SIZE (4) +#define MF_ULTRALIGHT_AUTH_PACK_SIZE (2) typedef enum { MfUltralightErrorNone, @@ -79,6 +81,14 @@ typedef struct { uint8_t data[MF_ULTRALIGHT_TEARING_FLAG_SIZE]; } MfUltralightTearingFlag; +typedef struct { + uint8_t data[MF_ULTRALIGHT_AUTH_PASSWORD_SIZE]; +} MfUltralightAuthPassword; + +typedef struct { + uint8_t data[MF_ULTRALIGHT_AUTH_PACK_SIZE]; +} MfUltralightAuthPack; + typedef struct { NfcaData nfca_data; MfUltralightType type; diff --git a/lib/nfc/protocols/mf_ultralight_listener.c b/lib/nfc/protocols/mf_ultralight_listener.c index b097266109ff..b3b3d08daae2 100644 --- a/lib/nfc/protocols/mf_ultralight_listener.c +++ b/lib/nfc/protocols/mf_ultralight_listener.c @@ -21,12 +21,14 @@ typedef enum { struct MfUltralightListener { NfcaListener* nfca_listener; - MfUltralightData data; + MfUltraligthListenerState state; + MfUltralightData* data; uint8_t tx_data[MF_ULTRALIGHT_LISTENER_MAX_TX_BUFF_SIZE]; uint16_t tx_bits; - MfUltraligthListenerState state; uint16_t pages_total; MfUltralightListenerFeatureSupport features; + MfUltralightListenerEventcallback callback; + void* context; }; typedef bool (*MfUltralightListenerCommandCallback)( @@ -40,6 +42,32 @@ typedef struct { MfUltralightListenerCommandCallback callback; } MfUltralightListenerCommand; +static MfUltralightError mf_ultralight_process_error(NfcaError error) { + MfUltralightError ret = MfUltralightErrorNone; + + switch(error) { + case NfcaErrorNone: + ret = MfUltralightErrorNone; + break; + case NfcaErrorNotPresent: + ret = MfUltralightErrorNotPresent; + break; + case NfcaErrorColResFailed: + case NfcaErrorCommunication: + case NfcaErrorWrongCrc: + ret = MfUltralightErrorProtocol; + break; + case NfcaErrorTimeout: + ret = MfUltralightErrorTimeout; + break; + default: + ret = MfUltralightErrorProtocol; + break; + } + + return ret; +} + static void mf_ultralight_listener_send_short_resp(MfUltralightListener* instance, uint8_t data) { nfca_listener_tx(instance->nfca_listener, &data, 4); }; @@ -55,7 +83,7 @@ static bool mf_ultralight_listener_read_page_handler( mf_ultralight_listener_send_short_resp(instance, MF_ULTRALIGHT_CMD_NACK); instance->state = MfUltraligthListenerStateIdle; } else { - memcpy(instance->tx_data, instance->data.page[start_page].data, 16); + memcpy(instance->tx_data, instance->data->page[start_page].data, 16); instance->tx_bits = 16 * 8; nfca_listener_send_standart_frame( instance->nfca_listener, instance->tx_data, instance->tx_bits); @@ -73,8 +101,8 @@ static bool mf_ultralight_listener_read_version_handler( UNUSED(rx_data); bool command_processed = false; if((instance->features & MfUltralightListenerFeatureSupportReadVersion)) { - memcpy(instance->tx_data, &instance->data.version, sizeof(instance->data.version)); - instance->tx_bits = sizeof(instance->data.version) * 8; + memcpy(instance->tx_data, &instance->data->version, sizeof(instance->data->version)); + instance->tx_bits = sizeof(instance->data->version) * 8; nfca_listener_send_standart_frame( instance->nfca_listener, instance->tx_data, instance->tx_bits); } else { @@ -94,8 +122,8 @@ static bool mf_ultralight_listener_read_signature_handler( UNUSED(rx_data); bool command_processed = false; if((instance->features & MfUltralightListenerFeatureSupportReadSignature)) { - memcpy(instance->tx_data, &instance->data.signature, sizeof(instance->data.signature)); - instance->tx_bits = sizeof(instance->data.signature) * 8; + memcpy(instance->tx_data, &instance->data->signature, sizeof(instance->data->signature)); + instance->tx_bits = sizeof(instance->data->signature) * 8; nfca_listener_send_standart_frame( instance->nfca_listener, instance->tx_data, instance->tx_bits); } else { @@ -146,7 +174,7 @@ static void mf_ultralight_listener_event_handler(NfcaListenerEvent event, void* } static void mf_ultralight_listener_prepare_emulation(MfUltralightListener* instance) { - MfUltralightData* data = &instance->data; + MfUltralightData* data = instance->data; if(data->type == MfUltralightTypeUnknown) { instance->features = MfUltralightListenerFeatureSupportReadVersion | MfUltralightListenerFeatureSupportReadSignature; @@ -154,22 +182,51 @@ static void mf_ultralight_listener_prepare_emulation(MfUltralightListener* insta } } -MfUltralightListener* mf_ultralight_listener_alloc(MfUltralightData* data) { - furi_assert(data); +MfUltralightListener* mf_ultralight_listener_alloc(NfcaListener* nfca_listener) { + furi_assert(nfca_listener); MfUltralightListener* instance = malloc(sizeof(MfUltralightListener)); - instance->data = *data; - mf_ultralight_listener_prepare_emulation(instance); - instance->nfca_listener = nfca_listener_alloc(&data->nfca_data); - nfca_listener_set_callback( - instance->nfca_listener, mf_ultralight_listener_event_handler, instance); return instance; } +MfUltralightError mf_ultralight_listener_start( + MfUltralightListener* instance, + MfUltralightData* data, + MfUltralightListenerEventcallback callback, + void* context) { + furi_assert(instance); + furi_assert(data); + + instance->data = malloc(sizeof(MfUltralightData)); + *instance->data = *data; + mf_ultralight_listener_prepare_emulation(instance); + + instance->callback = callback; + instance->context = context; + + NfcaError error = nfca_listener_start( + instance->nfca_listener, + &instance->data->nfca_data, + mf_ultralight_listener_event_handler, + instance); + + return mf_ultralight_process_error(error); +} + void mf_ultralight_listener_free(MfUltralightListener* instance) { furi_assert(instance); - nfca_listener_free(instance->nfca_listener); free(instance); } + +MfUltralightError mf_ultralight_listener_reset(MfUltralightListener* instance) { + furi_assert(instance); + furi_assert(instance->data); + + NfcaError error = nfca_listener_reset(instance->nfca_listener); + instance->state = MfUltraligthListenerStateIdle; + free(instance->data); + + return mf_ultralight_process_error(error); +} diff --git a/lib/nfc/protocols/mf_ultralight_listener.h b/lib/nfc/protocols/mf_ultralight_listener.h index 1dd9659deb2b..224437b08848 100644 --- a/lib/nfc/protocols/mf_ultralight_listener.h +++ b/lib/nfc/protocols/mf_ultralight_listener.h @@ -1,6 +1,7 @@ #pragma once #include "mf_ultralight.h" +#include "nfca_listener.h" #ifdef __cplusplus extern "C" { @@ -8,10 +9,35 @@ extern "C" { typedef struct MfUltralightListener MfUltralightListener; -MfUltralightListener* mf_ultralight_listener_alloc(MfUltralightData* data); +typedef enum { + MfUltralightListenerEventTypeAuth, +} MfUltralightListenerEventType; + +typedef struct { + union { + MfUltralightAuthPassword password; + }; +} MfUltralightListenerEventData; + +typedef struct { + MfUltralightListenerEventType type; + MfUltralightListenerEventData data; +} MfUltralightListenerEvent; + +typedef void (*MfUltralightListenerEventcallback)(MfUltralightListenerEvent event, void* context); + +MfUltralightListener* mf_ultralight_listener_alloc(NfcaListener* nfca_listener); void mf_ultralight_listener_free(MfUltralightListener* instance); +MfUltralightError mf_ultralight_listener_start( + MfUltralightListener* instance, + MfUltralightData* data, + MfUltralightListenerEventcallback callback, + void* context); + +MfUltralightError mf_ultralight_listener_reset(MfUltralightListener* instance); + #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/mf_ultralight_poller.c b/lib/nfc/protocols/mf_ultralight_poller.c index e24b51bb83fb..f3b58b46c5ca 100644 --- a/lib/nfc/protocols/mf_ultralight_poller.c +++ b/lib/nfc/protocols/mf_ultralight_poller.c @@ -2,33 +2,27 @@ #include #include "nfca_poller.h" +#include #define TAG "MfUltralightPoller" -#define MF_ULTRALIGHT_MAX_BUFF_SIZE (128) +#define MF_ULTRALIGHT_MAX_BUFF_SIZE (64) #define MF_ULTRALIGHT_POLLER_STANDART_FWT_FC (12000) +typedef enum { + MfUltralightPollerStateIdle, +} MfUltralightPollerState; + struct MfUltralightPoller { NfcaPoller* nfca_poller; - NfcaData nfca_data; + MfUltralightPollerState state; + NfcPollerBuffer* buffer; + MfUltralightData* data; + MfUltralightPollerCallback callback; + void* context; }; -MfUltralightPoller* mf_ultralight_poller_alloc() { - MfUltralightPoller* instance = malloc(sizeof(MfUltralightPoller)); - instance->nfca_poller = nfca_poller_alloc(); - - return instance; -} - -void mf_ultralight_poller_free(MfUltralightPoller* instance) { - furi_assert(instance); - furi_assert(instance->nfca_poller); - - nfca_poller_free(instance->nfca_poller); - free(instance); -} - static MfUltralightError mf_ultralight_process_error(NfcaError error) { MfUltralightError ret = MfUltralightErrorNone; @@ -55,6 +49,101 @@ static MfUltralightError mf_ultralight_process_error(NfcaError error) { return ret; } +MfUltralightPoller* mf_ultralight_poller_alloc(NfcaPoller* nfca_poller) { + MfUltralightPoller* instance = malloc(sizeof(MfUltralightPoller)); + instance->nfca_poller = nfca_poller; + + return instance; +} + +void mf_ultralight_poller_free(MfUltralightPoller* instance) { + furi_assert(instance); + + free(instance); +} + +static void mf_ultralight_nfca_poller_event_callback(NfcaPollerEvent event, void* context) { + furi_assert(context); + + MfUltralightPoller* instance = context; + MfUltralightPollerEvent mf_ul_poller_event = {}; + NfcaError error = NfcaErrorNone; + + if(event.type == NfcaPollerEventTypeReady) { + // Test: read 0 page + NfcPollerBuffer* buff = instance->buffer; + nfc_poller_buffer_reset(buff); + buff->tx_data[0] = MF_ULTRALIGHT_CMD_READ_PAGE; + buff->tx_data[1] = 0; + buff->tx_bits = 16; + error = nfca_poller_send_standart_frame( + instance->nfca_poller, + buff->tx_data, + buff->tx_bits, + buff->rx_data, + buff->rx_data_size, + &buff->rx_bits, + MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); + if(error == NfcaErrorNone) { + FURI_LOG_T(TAG, "Read page 0 success"); + memcpy(&instance->data->page[0], buff->rx_data, buff->rx_bits / 8); + } else { + FURI_LOG_E(TAG, "Error reading 0 page"); + } + mf_ul_poller_event.type = MfUltralightPollerEventTypeReadComplete; + instance->callback(mf_ul_poller_event, instance->context); + } +} + +MfUltralightError mf_ultralight_poller_start( + MfUltralightPoller* instance, + MfUltralightPollerCallback callback, + void* context) { + furi_assert(instance); + furi_assert(instance->state == MfUltralightPollerStateIdle); + furi_assert(instance->nfca_poller); + furi_assert(callback); + + instance->data = malloc(sizeof(MfUltralightData)); + instance->buffer = + nfc_poller_buffer_alloc(MF_ULTRALIGHT_MAX_BUFF_SIZE, MF_ULTRALIGHT_MAX_BUFF_SIZE); + + instance->callback = callback; + instance->context = context; + + nfca_poller_start(instance->nfca_poller, mf_ultralight_nfca_poller_event_callback, instance); + + return MfUltralightErrorNone; +} + +MfUltralightError mf_ultralight_poller_reset(MfUltralightPoller* instance) { + furi_assert(instance); + furi_assert(instance->data); + furi_assert(instance->buffer); + furi_assert(instance->nfca_poller); + + NfcaError error = nfca_poller_reset(instance->nfca_poller); + + nfc_poller_buffer_free(instance->buffer); + instance->callback = NULL; + instance->context = NULL; + free(instance->data); + instance->state = MfUltralightPollerStateIdle; + + return mf_ultralight_process_error(error); +} + +// Called from NfcWorker thread + +MfUltralightError mf_ultralight_poller_stop(MfUltralightPoller* instance) { + furi_assert(instance); + furi_assert(instance->nfca_poller); + + nfca_poller_stop(instance->nfca_poller); + + return MfUltralightErrorNone; +} + MfUltralightError mf_ultralight_poller_read_page( MfUltralightPoller* instance, uint16_t page, diff --git a/lib/nfc/protocols/mf_ultralight_poller.h b/lib/nfc/protocols/mf_ultralight_poller.h index 35a973520681..8a94437ecb34 100644 --- a/lib/nfc/protocols/mf_ultralight_poller.h +++ b/lib/nfc/protocols/mf_ultralight_poller.h @@ -1,6 +1,7 @@ #pragma once #include "mf_ultralight.h" +#include "nfca_poller.h" #ifdef __cplusplus extern "C" { @@ -8,10 +9,54 @@ extern "C" { typedef struct MfUltralightPoller MfUltralightPoller; -MfUltralightPoller* mf_ultralight_poller_alloc(); +typedef enum { + MfUltralightPollerEventTypeReadVersion, + MfUltralightPollerEventTypeReadSignature, + MfUltralightPollerEventTypeReadCounters, + MfUltralightPollerEventTypeReadTearingFlags, + MfUltralightPollerEventTypeAuthRequest, + MfUltralightPollerEventTypeAuthSuccess, + MfUltralightPollerEventTypeAuthFailed, + MfUltralightPollerEventTypeReadPages, + MfUltralightPollerEventTypeReadComplete, +} MfUltralightPollerEventType; + +typedef struct { + bool skip_auth; + MfUltralightAuthPassword password; +} MfUltralightPollerAuthContext; + +typedef struct { + union { + MfUltralightPollerAuthContext auth_context; + MfUltralightAuthPack pack; + }; +} MfUltralightPollerEventData; + +typedef struct { + MfUltralightPollerEventType type; + MfUltralightPollerEventData data; +} MfUltralightPollerEvent; + +typedef void (*MfUltralightPollerCallback)(MfUltralightPollerEvent event, void* context); + +MfUltralightPoller* mf_ultralight_poller_alloc(NfcaPoller* nfca_poller); void mf_ultralight_poller_free(MfUltralightPoller* instance); +MfUltralightError mf_ultralight_poller_start( + MfUltralightPoller* instance, + MfUltralightPollerCallback callback, + void* context); + +MfUltralightError mf_ultralight_poller_reset(MfUltralightPoller* instance); + +// Called from NfcWorker thread + +MfUltralightError mf_ultralight_poller_stop(MfUltralightPoller* instance); + +// Sync API + MfUltralightError mf_ultralight_poller_read_page( MfUltralightPoller* instance, uint16_t page, diff --git a/lib/nfc/protocols/nfca_listener.c b/lib/nfc/protocols/nfca_listener.c index 091771a11356..c6990ef65721 100644 --- a/lib/nfc/protocols/nfca_listener.c +++ b/lib/nfc/protocols/nfca_listener.c @@ -12,9 +12,9 @@ typedef enum { struct NfcaListener { Nfc* nfc; - NfcaData data; + NfcaData* data; NfcaListenerState state; - NfcaListenerCallback callback; + NfcaListenerEventCallback callback; void* context; }; @@ -71,44 +71,74 @@ static void nfca_listener_event_handler(NfcEvent event, void* context) { nfca_listener_event.type = NfcaListenerEventTypeReceivedData; nfca_listener_event.data.rx_bits = event.data.rx_bits; } - instance->callback(nfca_listener_event, instance->context); + if(instance->callback) { + instance->callback(nfca_listener_event, instance->context); + } } } } -NfcaListener* nfca_listener_alloc(NfcaData* data) { +NfcaListener* nfca_listener_alloc(Nfc* nfc) { + furi_assert(nfc); + NfcaListener* instance = malloc(sizeof(NfcaListener)); - instance->data = *data; - instance->nfc = nfc_alloc(); - nfc_set_fdt_listen_fc(instance->nfc, NFCA_FDT_LISTEN_FC); - nfc_config(instance->nfc, NfcModeNfcaListener); - nfc_listener_set_col_res_data( - instance->nfc, - instance->data.uid, - instance->data.uid_len, - instance->data.atqa, - instance->data.sak); - nfc_start_worker(instance->nfc, nfca_listener_event_handler, instance); + instance->nfc = nfc; return instance; } void nfca_listener_free(NfcaListener* instance) { furi_assert(instance); - nfc_free(instance->nfc); free(instance); } -NfcaError nfca_listener_set_callback( +NfcaError nfca_listener_start( NfcaListener* instance, - NfcaListenerCallback callback, + NfcaData* data, + NfcaListenerEventCallback callback, void* context) { furi_assert(instance); - furi_assert(callback); instance->callback = callback; instance->context = context; + instance->data = malloc(sizeof(NfcaData)); + *instance->data = *data; + + nfc_set_fdt_listen_fc(instance->nfc, NFCA_FDT_LISTEN_FC); + nfc_config(instance->nfc, NfcModeNfcaListener); + nfc_listener_set_col_res_data( + instance->nfc, + instance->data->uid, + instance->data->uid_len, + instance->data->atqa, + instance->data->sak); + nfc_start_worker(instance->nfc, nfca_listener_event_handler, instance); + + return NfcaErrorNone; +} + +NfcaError nfca_listener_reset(NfcaListener* instance) { + furi_assert(instance); + furi_assert(instance->nfc); + furi_assert(instance->data); + + nfc_listener_abort(instance->nfc); + free(instance->data); + instance->callback = NULL; + instance->context = NULL; + instance->state = NfcaListenerStateIdle; + + return NfcaErrorNone; +} + +NfcaError nfca_listener_get_data(NfcaListener* instance, NfcaData* data) { + furi_assert(instance); + furi_assert(data); + furi_assert(instance->data); + + *data = *instance->data; + return NfcaErrorNone; } diff --git a/lib/nfc/protocols/nfca_listener.h b/lib/nfc/protocols/nfca_listener.h index ceedcceccbbe..d274235a5fe1 100644 --- a/lib/nfc/protocols/nfca_listener.h +++ b/lib/nfc/protocols/nfca_listener.h @@ -1,6 +1,7 @@ #pragma once #include "nfca.h" +#include #ifdef __cplusplus extern "C" { @@ -27,17 +28,24 @@ typedef struct { NfcaListenerEventData data; } NfcaListenerEvent; -typedef void (*NfcaListenerCallback)(NfcaListenerEvent event, void* context); +typedef void (*NfcaListenerEventCallback)(NfcaListenerEvent event, void* context); -NfcaListener* nfca_listener_alloc(NfcaData* data); +NfcaListener* nfca_listener_alloc(Nfc* nfc); void nfca_listener_free(NfcaListener* instance); -NfcaError nfca_listener_set_callback( +NfcaError nfca_listener_start( NfcaListener* instance, - NfcaListenerCallback callback, + NfcaData* data, + NfcaListenerEventCallback callback, void* context); +NfcaError nfca_listener_get_data(NfcaListener* instance, NfcaData* data); + +NfcaError nfca_listener_reset(NfcaListener* instance); + +// Called from NfcWorker thread + NfcaError nfca_listener_sleep(NfcaListener* instance); NfcaError nfca_listener_tx(NfcaListener* instance, uint8_t* tx_data, uint16_t tx_bits); diff --git a/lib/nfc/protocols/nfca_poller.c b/lib/nfc/protocols/nfca_poller.c index 60882a84d4bb..fe08c3fff279 100644 --- a/lib/nfc/protocols/nfca_poller.c +++ b/lib/nfc/protocols/nfca_poller.c @@ -43,7 +43,7 @@ struct NfcaPoller { Nfc* nfc; NfcaPollerState state; NfcaPollerColRes col_res; - NfcaData data; + NfcaData* data; NfcaPollerEventCallback callback; void* context; }; @@ -136,13 +136,11 @@ static NfcaError nfca_poller_prepare_trx(NfcaPoller* instance) { return ret; } -NfcaPoller* nfca_poller_alloc() { +NfcaPoller* nfca_poller_alloc(Nfc* nfc) { + furi_assert(nfc); + NfcaPoller* instance = malloc(sizeof(NfcaPoller)); - instance->nfc = nfc_alloc(); - nfc_config(instance->nfc, NfcModeNfcaPoller); - nfc_set_guard_time_us(instance->nfc, NFCA_GUARD_TIME_US); - nfc_set_fdt_poll_fc(instance->nfc, NFCA_FDT_POLL_FC); - nfc_set_fdt_poll_poll_us(instance->nfc, NFCA_POLL_POLL_MIN_US); + instance->nfc = nfc; return instance; } @@ -152,7 +150,6 @@ void nfca_poller_free(NfcaPoller* instance) { furi_assert(instance->nfc); nfc_poller_abort(instance->nfc); - nfc_free(instance->nfc); free(instance); } @@ -187,9 +184,17 @@ NfcaError nfca_poller_start(NfcaPoller* instance, NfcaPollerEventCallback callback, void* context) { furi_assert(instance); furi_assert(callback); + furi_assert(instance->nfc); instance->callback = callback; instance->context = context; + + instance->data = malloc(sizeof(NfcaData)); + nfc_config(instance->nfc, NfcModeNfcaPoller); + nfc_set_guard_time_us(instance->nfc, NFCA_GUARD_TIME_US); + nfc_set_fdt_poll_fc(instance->nfc, NFCA_FDT_POLL_FC); + nfc_set_fdt_poll_poll_us(instance->nfc, NFCA_POLL_POLL_MIN_US); + nfc_start_worker(instance->nfc, nfca_poller_event_callback, instance); return NfcaErrorNone; @@ -197,13 +202,31 @@ NfcaError NfcaError nfca_poller_get_data(NfcaPoller* instance, NfcaData* data) { furi_assert(instance); + furi_assert(instance->data); furi_assert(data); - *data = instance->data; + *data = *instance->data; return NfcaErrorNone; } +NfcaError nfca_poller_reset(NfcaPoller* instance) { + furi_assert(instance); + furi_assert(instance->data); + + nfc_poller_abort(instance->nfc); + + instance->callback = NULL; + instance->context = NULL; + memset(&instance->col_res, 0, sizeof(NfcaPollerColRes)); + instance->state = NfcaPollerStateIdle; + free(instance->data); + instance->data = NULL; + + return NfcaErrorNone; +} + + NfcaError nfca_poller_check_presence(NfcaPoller* instance) { furi_assert(instance); furi_assert(instance->nfc); @@ -248,7 +271,7 @@ NfcaError nfca_poller_activate(NfcaPoller* instance, NfcaData* nfca_data) { // Reset Nfca poller state memset(&instance->col_res, 0, sizeof(instance->col_res)); - memset(&instance->data, 0, sizeof(instance->data)); + memset(instance->data, 0, sizeof(NfcaData)); // Halt if necessary if(instance->state != NfcaPollerStateIdle) { @@ -280,7 +303,7 @@ NfcaError nfca_poller_activate(NfcaPoller* instance, NfcaData* nfca_data) { break; } memcpy( - instance->data.atqa, &instance->col_res.sens_resp, sizeof(instance->col_res.sel_resp)); + instance->data->atqa, &instance->col_res.sens_resp, sizeof(instance->col_res.sel_resp)); instance->state = NfcaPollerColResInProgress; instance->col_res.cascade_level = 0; @@ -349,20 +372,20 @@ NfcaError nfca_poller_activate(NfcaPoller* instance, NfcaData* nfca_data) { if(instance->col_res.sel_req.nfcid[0] == NFCA_POLLER_SDD_CL) { // Copy part of UID memcpy( - &instance->data.uid[instance->data.uid_len], + &instance->data->uid[instance->data->uid_len], &instance->col_res.sel_req.nfcid[1], 3); - instance->data.uid_len += 3; + instance->data->uid_len += 3; instance->col_res.cascade_level++; instance->col_res.state = NfcaPollerColResStateStateNewCascade; } else { FURI_LOG_T(TAG, "Col resolution complete"); - instance->data.sak = instance->col_res.sel_resp.sak; + instance->data->sak = instance->col_res.sel_resp.sak; memcpy( - &instance->data.uid[instance->data.uid_len], + &instance->data->uid[instance->data->uid_len], &instance->col_res.sel_req.nfcid[0], 4); - instance->data.uid_len += 4; + instance->data->uid_len += 4; instance->col_res.state = NfcaPollerColResStateStateSuccess; instance->state = NfcaPollerActivated; } @@ -372,7 +395,7 @@ NfcaError nfca_poller_activate(NfcaPoller* instance, NfcaData* nfca_data) { } while(false); if(activated && nfca_data) { - *nfca_data = instance->data; + *nfca_data = *instance->data; } return ret; @@ -383,7 +406,6 @@ NfcaError nfca_poller_stop(NfcaPoller* instance) { furi_assert(instance->nfc); nfc_poller_stop(instance->nfc); - return NfcaErrorNone; } @@ -462,7 +484,7 @@ NfcaError nfca_poller_activate_sync(NfcaPoller* instance, NfcaData* nfca_data) { furi_thread_flags_wait(NFCA_POLLER_FLAG_COMMAND_COMPLETE, FuriFlagWaitAny, FuriWaitForever); furi_thread_flags_clear(NFCA_POLLER_FLAG_COMMAND_COMPLETE); if(context.error == NfcaErrorNone) { - *nfca_data = instance->data; + *nfca_data = *instance->data; } return context.error; diff --git a/lib/nfc/protocols/nfca_poller.h b/lib/nfc/protocols/nfca_poller.h index 41f8abe0cf1f..287c18ef17ef 100644 --- a/lib/nfc/protocols/nfca_poller.h +++ b/lib/nfc/protocols/nfca_poller.h @@ -1,8 +1,7 @@ #pragma once #include "nfca.h" - -#include +#include "nfc.h" #ifdef __cplusplus extern "C" { @@ -28,7 +27,7 @@ typedef struct { typedef void (*NfcaPollerEventCallback)(NfcaPollerEvent event, void* context); -NfcaPoller* nfca_poller_alloc(); +NfcaPoller* nfca_poller_alloc(Nfc* nfc); void nfca_poller_free(NfcaPoller* instance); @@ -37,6 +36,10 @@ NfcaError NfcaError nfca_poller_get_data(NfcaPoller* instance, NfcaData* data); +NfcaError nfca_poller_reset(NfcaPoller* instance); + +// Called from NfcWorker thread + NfcaError nfca_poller_stop(NfcaPoller* instance); NfcaError nfca_poller_check_presence(NfcaPoller* instance); From 4194fbe5b6e84f714ebb4841ca55d260a88d7c14 Mon Sep 17 00:00:00 2001 From: gornekich Date: Mon, 17 Apr 2023 17:21:46 +0400 Subject: [PATCH 025/149] nfc: mf ultralight support --- .../main/nfc/scenes/nfc_scene_config.h | 2 + .../nfc/scenes/nfc_scene_mf_ultralight_read.c | 56 +++++++++++++ .../nfc_scene_mf_ultralight_read_success.c | 79 +++++++++++++++++++ .../nfc/scenes/nfc_scene_read_card_type.c | 2 +- .../main/nfc/scenes/nfc_scene_retry_confirm.c | 2 +- lib/nfc/protocols/mf_ultralight_poller.c | 10 +++ lib/nfc/protocols/mf_ultralight_poller.h | 2 + 7 files changed, 151 insertions(+), 2 deletions(-) create mode 100644 applications/main/nfc/scenes/nfc_scene_mf_ultralight_read.c create mode 100644 applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_success.c diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index cf20ff52fd4f..bf226d1695a4 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -9,5 +9,7 @@ ADD_SCENE(nfc, extra_actions, ExtraActions) ADD_SCENE(nfc, debug, Debug) ADD_SCENE(nfc, retry_confirm, RetryConfirm) ADD_SCENE(nfc, exit_confirm, ExitConfirm) +ADD_SCENE(nfc, mf_ultralight_read, MfUltralightRead) +ADD_SCENE(nfc, mf_ultralight_read_success, MfUltralightReadSuccess) ADD_SCENE(nfc, not_implemented, NotImplemented) \ No newline at end of file diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read.c new file mode 100644 index 000000000000..2d94c5b9f707 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read.c @@ -0,0 +1,56 @@ +#include "../nfc_app_i.h" +#include + +enum { + NfcWorkerEventMfUltralightReadSuccess, +}; + +void nfc_scene_mf_ultralight_read_worker_callback(MfUltralightPollerEvent event, void* context) { + NfcApp* nfc = context; + + if(event.type == MfUltralightPollerEventTypeReadComplete) { + nfca_poller_stop(nfc->nfca_poller); + view_dispatcher_send_custom_event( + nfc->view_dispatcher, NfcWorkerEventMfUltralightReadSuccess); + } else { + furi_delay_ms(100); + } +} + +void nfc_scene_mf_ultralight_read_on_enter(void* context) { + NfcApp* nfc = context; + + // Setup view + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); + + mf_ultralight_poller_start( + nfc->mf_ul_poller, nfc_scene_mf_ultralight_read_worker_callback, nfc); + + nfc_blink_read_start(nfc); +} + +bool nfc_scene_mf_ultralight_read_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcWorkerEventMfUltralightReadSuccess) { + notification_message(nfc->notifications, &sequence_success); + mf_ultralight_poller_get_data(nfc->mf_ul_poller, &nfc->nfc_dev_data.mf_ul_data); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadSuccess); + DOLPHIN_DEED(DolphinDeedNfcReadSuccess); + consumed = true; + } + } + return consumed; +} + +void nfc_scene_mf_ultralight_read_on_exit(void* context) { + NfcApp* nfc = context; + + mf_ultralight_poller_reset(nfc->mf_ul_poller); + // Clear view + popup_reset(nfc->popup); + + nfc_blink_stop(nfc); +} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_success.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_success.c new file mode 100644 index 000000000000..327335b6076b --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_success.c @@ -0,0 +1,79 @@ +#include "../nfc_app_i.h" + +void nfc_scene_mf_ultralight_read_success_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + furi_assert(context); + NfcApp* nfc = context; + + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); + } +} + +void nfc_scene_mf_ultralight_read_success_on_enter(void* context) { + NfcApp* nfc = context; + + // Setup view + MfUltralightData* data = &nfc->nfc_dev_data.mf_ul_data; + Widget* widget = nfc->widget; + + FuriString* temp_str; + temp_str = furi_string_alloc_set("\e#Mf Ultralight\n"); + + notification_message_block(nfc->notifications, &sequence_set_green_255); + + widget_add_text_scroll_element(widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); + furi_string_free(temp_str); + + FURI_LOG_I("MfUlReadSuccess", "Read success"); + for(size_t i = 0; i < 4; i++) { + printf("%02X ", data->page->data[i]); + } + printf("\r\n"); + + widget_add_button_element( + widget, + GuiButtonTypeLeft, + "Retry", + nfc_scene_mf_ultralight_read_success_widget_callback, + nfc); + widget_add_button_element( + widget, + GuiButtonTypeRight, + "More", + nfc_scene_mf_ultralight_read_success_widget_callback, + nfc); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); +} + +bool nfc_scene_mf_ultralight_read_success_on_event(void* context, SceneManagerEvent event) { + NfcApp* 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, NfcSceneNfcaMenu); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeBack) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); + consumed = true; + } + + return consumed; +} + +void nfc_scene_mf_ultralight_read_success_on_exit(void* context) { + NfcApp* 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_card_type.c b/applications/main/nfc/scenes/nfc_scene_read_card_type.c index 3d079dc8a71c..97c11a32493f 100644 --- a/applications/main/nfc/scenes/nfc_scene_read_card_type.c +++ b/applications/main/nfc/scenes/nfc_scene_read_card_type.c @@ -68,7 +68,7 @@ bool nfc_scene_read_card_type_on_event(void* context, SceneManagerEvent event) { consumed = true; } if(event.event == SubmenuIndexReadMfUltralight) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightRead); consumed = true; } if(event.event == SubmenuIndexReadEMV) { diff --git a/applications/main/nfc/scenes/nfc_scene_retry_confirm.c b/applications/main/nfc/scenes/nfc_scene_retry_confirm.c index 9f37c41588b5..54aa62a0f22c 100644 --- a/applications/main/nfc/scenes/nfc_scene_retry_confirm.c +++ b/applications/main/nfc/scenes/nfc_scene_retry_confirm.c @@ -30,7 +30,7 @@ bool nfc_scene_retry_confirm_on_event(void* context, SceneManagerEvent event) { consumed = scene_manager_previous_scene(nfc->scene_manager); } else if(event.event == DialogExResultLeft) { consumed = scene_manager_search_and_switch_to_previous_scene( - nfc->scene_manager, NfcSceneRead); + nfc->scene_manager, NfcSceneNfcaRead); } } else if(event.type == SceneManagerEventTypeBack) { consumed = true; diff --git a/lib/nfc/protocols/mf_ultralight_poller.c b/lib/nfc/protocols/mf_ultralight_poller.c index f3b58b46c5ca..d2af85e3bb08 100644 --- a/lib/nfc/protocols/mf_ultralight_poller.c +++ b/lib/nfc/protocols/mf_ultralight_poller.c @@ -116,6 +116,16 @@ MfUltralightError mf_ultralight_poller_start( return MfUltralightErrorNone; } +MfUltralightError mf_ultralight_poller_get_data(MfUltralightPoller* instance, MfUltralightData* data) { + furi_assert(instance); + furi_assert(instance->data); + furi_assert(data); + + *data = *instance->data; + + return MfUltralightErrorNone; +} + MfUltralightError mf_ultralight_poller_reset(MfUltralightPoller* instance) { furi_assert(instance); furi_assert(instance->data); diff --git a/lib/nfc/protocols/mf_ultralight_poller.h b/lib/nfc/protocols/mf_ultralight_poller.h index 8a94437ecb34..ca74f6c6c115 100644 --- a/lib/nfc/protocols/mf_ultralight_poller.h +++ b/lib/nfc/protocols/mf_ultralight_poller.h @@ -49,6 +49,8 @@ MfUltralightError mf_ultralight_poller_start( MfUltralightPollerCallback callback, void* context); +MfUltralightError mf_ultralight_poller_get_data(MfUltralightPoller* instance, MfUltralightData* data); + MfUltralightError mf_ultralight_poller_reset(MfUltralightPoller* instance); // Called from NfcWorker thread From e9faf3a3ff4e764027089e21ddde1c9613750648 Mon Sep 17 00:00:00 2001 From: gornekich Date: Mon, 17 Apr 2023 20:21:50 +0400 Subject: [PATCH 026/149] nfc: mf ultralight read state machine --- lib/nfc/protocols/mf_ultralight.c | 38 +++++++++++++++++++++++- lib/nfc/protocols/mf_ultralight.h | 2 ++ lib/nfc/protocols/mf_ultralight_poller.c | 31 +++++++++++++++++-- 3 files changed, 68 insertions(+), 3 deletions(-) diff --git a/lib/nfc/protocols/mf_ultralight.c b/lib/nfc/protocols/mf_ultralight.c index 0751cdd72d40..4aa4f611f1ee 100644 --- a/lib/nfc/protocols/mf_ultralight.c +++ b/lib/nfc/protocols/mf_ultralight.c @@ -1 +1,37 @@ -#include "mf_ultralight.h" \ No newline at end of file +#include "mf_ultralight.h" + +#include + +MfUltralightType mf_ultralight_get_type_by_version(MfUltralightVersion* version) { + furi_assert(version); + + MfUltralightType type = MfUltralightTypeUnknown; + + if(version->storage_size == 0x0B || version->storage_size == 0x00) { + type = MfUltralightTypeUL11; + } else if(version->storage_size == 0x0E) { + type = MfUltralightTypeUL21; + } else if(version->storage_size == 0x0F) { + type = MfUltralightTypeNTAG213; + } else if(version->storage_size == 0x11) { + type = MfUltralightTypeNTAG215; + } else if(version->prod_subtype == 5 && version->prod_ver_major == 2) { + if(version->prod_ver_minor == 1) { + if(version->storage_size == 0x13) { + type = MfUltralightTypeNTAGI2C1K; + } else if(version->storage_size == 0x15) { + type = MfUltralightTypeNTAGI2C2K; + } + } else if(version->prod_ver_minor == 2) { + if(version->storage_size == 0x13) { + type = MfUltralightTypeNTAGI2CPlus1K; + } else if(version->storage_size == 0x15) { + type = MfUltralightTypeNTAGI2CPlus2K; + } + } + } else if(version->storage_size == 0x13) { + type = MfUltralightTypeNTAG216; + } + + return type; +} diff --git a/lib/nfc/protocols/mf_ultralight.h b/lib/nfc/protocols/mf_ultralight.h index 1807896d0680..26870c3f5ac8 100644 --- a/lib/nfc/protocols/mf_ultralight.h +++ b/lib/nfc/protocols/mf_ultralight.h @@ -100,6 +100,8 @@ typedef struct { uint32_t paged_read; } MfUltralightData; +MfUltralightType mf_ultralight_get_type_by_version(MfUltralightVersion* version); + #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/mf_ultralight_poller.c b/lib/nfc/protocols/mf_ultralight_poller.c index d2af85e3bb08..fbcced5ace4b 100644 --- a/lib/nfc/protocols/mf_ultralight_poller.c +++ b/lib/nfc/protocols/mf_ultralight_poller.c @@ -12,6 +12,10 @@ typedef enum { MfUltralightPollerStateIdle, + MfUltralightPollerStateReadVersion, + MfUltralightPollerStateDetectNtag203, + MfUltralightPollerStateReadSignature, + MfUltralightPollerStateRead } MfUltralightPollerState; struct MfUltralightPoller { @@ -62,6 +66,24 @@ void mf_ultralight_poller_free(MfUltralightPoller* instance) { free(instance); } +static void mf_ultralight_poller_get_version(MfUltralightPoller* instance) { + NfcPollerBuffer* buff = instance->buffer; + buff->tx_data[0] = MF_ULTRALIGHT_CMD_GET_VERSION; + buff->rx_bits = 8; + NfcaError error = nfca_poller_send_standart_frame( + instance->nfca_poller, + buff->tx_data, + buff->tx_bits, + buff->rx_data, + buff->rx_data_size, + &buff->rx_bits, + MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); + if(error == NfcaErrorNone) { + memcpy(&instance->data->version, buff->rx_data, sizeof(MfUltralightVersion)); + instance->data->type = mf_ultralight_get_type_by_version(&instance->data->version); + } +} + static void mf_ultralight_nfca_poller_event_callback(NfcaPollerEvent event, void* context) { furi_assert(context); @@ -70,9 +92,13 @@ static void mf_ultralight_nfca_poller_event_callback(NfcaPollerEvent event, void NfcaError error = NfcaErrorNone; if(event.type == NfcaPollerEventTypeReady) { - // Test: read 0 page NfcPollerBuffer* buff = instance->buffer; nfc_poller_buffer_reset(buff); + + if(instance->state == MfUltralightPollerStateReadVersion) { + mf_ultralight_poller_get_version(instance); + } + // Test: read 0 page buff->tx_data[0] = MF_ULTRALIGHT_CMD_READ_PAGE; buff->tx_data[1] = 0; buff->tx_bits = 16; @@ -116,7 +142,8 @@ MfUltralightError mf_ultralight_poller_start( return MfUltralightErrorNone; } -MfUltralightError mf_ultralight_poller_get_data(MfUltralightPoller* instance, MfUltralightData* data) { +MfUltralightError + mf_ultralight_poller_get_data(MfUltralightPoller* instance, MfUltralightData* data) { furi_assert(instance); furi_assert(instance->data); furi_assert(data); From 6178b18f242eac29364b66fe09f0bd0065a422b9 Mon Sep 17 00:00:00 2001 From: gornekich Date: Wed, 19 Apr 2023 16:14:04 +0400 Subject: [PATCH 027/149] nfc: start adding sync API --- .../nfc/scenes/nfc_scene_mf_ultralight_read.c | 2 +- .../main/nfc/scenes/nfc_scene_nfca_read.c | 2 +- applications/main/nfc/scenes/nfc_scene_read.c | 2 +- .../main/nfc_rpc/nfc_rpc_mf_ultralight.c | 2 - lib/nfc/nfc.c | 2 +- lib/nfc/protocols/mf_ultralight_poller.c | 117 +++++++++++------- lib/nfc/protocols/mf_ultralight_poller.h | 5 + lib/nfc/protocols/nfca_poller.c | 10 +- lib/nfc/protocols/nfca_poller.h | 3 - 9 files changed, 88 insertions(+), 57 deletions(-) diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read.c index 2d94c5b9f707..867d44fb5b6f 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read.c @@ -23,7 +23,7 @@ void nfc_scene_mf_ultralight_read_on_enter(void* context) { // Setup view view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); - mf_ultralight_poller_start( + mf_ultralight_poller_read( nfc->mf_ul_poller, nfc_scene_mf_ultralight_read_worker_callback, nfc); nfc_blink_read_start(nfc); diff --git a/applications/main/nfc/scenes/nfc_scene_nfca_read.c b/applications/main/nfc/scenes/nfc_scene_nfca_read.c index 80229106540c..e18d2398fe92 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfca_read.c +++ b/applications/main/nfc/scenes/nfc_scene_nfca_read.c @@ -8,7 +8,7 @@ enum { void nfc_scene_nfca_read_worker_callback(NfcaPollerEvent event, void* context) { NfcApp* nfc = context; - if(event.type == NfcaPollerEventTypeActivated) { + if(event.type == NfcaPollerEventTypeReady) { nfca_poller_stop(nfc->nfca_poller); view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcWorkerEventReadUidNfcA); } else { diff --git a/applications/main/nfc/scenes/nfc_scene_read.c b/applications/main/nfc/scenes/nfc_scene_read.c index 5e089934229a..a53a91fb54de 100644 --- a/applications/main/nfc/scenes/nfc_scene_read.c +++ b/applications/main/nfc/scenes/nfc_scene_read.c @@ -8,7 +8,7 @@ enum { void nfc_scene_read_worker_callback(NfcaPollerEvent event, void* context) { NfcApp* nfc = context; - if(event.type == NfcaPollerEventTypeActivated) { + if(event.type == NfcaPollerEventTypeReady) { nfca_poller_stop(nfc->nfca_poller); view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcWorkerEventReadUidNfcA); } diff --git a/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c b/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c index b3cc0f1e02a2..a67dc1965e4d 100644 --- a/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c +++ b/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c @@ -104,8 +104,6 @@ static void nfc_rpc_mf_ultralight_read_version(Nfc_Main* cmd, void* context) { pb_mf_ul_version.vendor_id = data.vendor_id; } cmd->content.mf_ultralight_read_version_resp = pb_mf_ul_version; - - mf_ultralight_poller_reset(instance->mf_ul_poller); } static void nfc_rpc_mf_ultralight_read_signature(Nfc_Main* cmd, void* context) { diff --git a/lib/nfc/nfc.c b/lib/nfc/nfc.c index f37607369072..4cd20e4ebb99 100644 --- a/lib/nfc/nfc.c +++ b/lib/nfc/nfc.c @@ -151,7 +151,7 @@ Nfc* nfc_alloc() { furi_thread_set_name(instance->worker_thread, "NfcWorker"); furi_thread_set_context(instance->worker_thread, instance); furi_thread_set_priority(instance->worker_thread, FuriThreadPriorityHighest); - furi_thread_set_stack_size(instance->worker_thread, 2048); + furi_thread_set_stack_size(instance->worker_thread, 4 * 1024); return instance; } diff --git a/lib/nfc/protocols/mf_ultralight_poller.c b/lib/nfc/protocols/mf_ultralight_poller.c index fbcced5ace4b..23c98878d559 100644 --- a/lib/nfc/protocols/mf_ultralight_poller.c +++ b/lib/nfc/protocols/mf_ultralight_poller.c @@ -10,6 +10,14 @@ #define MF_ULTRALIGHT_POLLER_STANDART_FWT_FC (12000) +#define MF_ULTRALIGHT_POLLER_COMPLETE_EVENT (1UL << 0) + +typedef struct { + MfUltralightPoller* instance; + FuriThreadId thread_id; + MfUltralightError error; +} MfUltralightPollerContext; + typedef enum { MfUltralightPollerStateIdle, MfUltralightPollerStateReadVersion, @@ -66,22 +74,34 @@ void mf_ultralight_poller_free(MfUltralightPoller* instance) { free(instance); } -static void mf_ultralight_poller_get_version(MfUltralightPoller* instance) { +static MfUltralightError mf_ultralight_poller_get_version(MfUltralightPoller* instance) { NfcPollerBuffer* buff = instance->buffer; buff->tx_data[0] = MF_ULTRALIGHT_CMD_GET_VERSION; - buff->rx_bits = 8; - NfcaError error = nfca_poller_send_standart_frame( - instance->nfca_poller, - buff->tx_data, - buff->tx_bits, - buff->rx_data, - buff->rx_data_size, - &buff->rx_bits, - MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); - if(error == NfcaErrorNone) { + buff->tx_bits = 8; + + MfUltralightError ret = MfUltralightErrorNone; + NfcaError error = NfcaErrorNone; + do { + error = nfca_poller_send_standart_frame( + instance->nfca_poller, + buff->tx_data, + buff->tx_bits, + buff->rx_data, + buff->rx_data_size, + &buff->rx_bits, + MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); + if(error != NfcaErrorNone) { + ret = mf_ultralight_process_error(error); + break; + } + if(buff->rx_bits != 8 * 8) { + ret = MfUltralightErrorProtocol; + break; + } memcpy(&instance->data->version, buff->rx_data, sizeof(MfUltralightVersion)); - instance->data->type = mf_ultralight_get_type_by_version(&instance->data->version); - } + } while(false); + + return ret; } static void mf_ultralight_nfca_poller_event_callback(NfcaPollerEvent event, void* context) { @@ -123,7 +143,7 @@ static void mf_ultralight_nfca_poller_event_callback(NfcaPollerEvent event, void MfUltralightError mf_ultralight_poller_start( MfUltralightPoller* instance, - MfUltralightPollerCallback callback, + NfcaPollerEventCallback callback, void* context) { furi_assert(instance); furi_assert(instance->state == MfUltralightPollerStateIdle); @@ -134,12 +154,25 @@ MfUltralightError mf_ultralight_poller_start( instance->buffer = nfc_poller_buffer_alloc(MF_ULTRALIGHT_MAX_BUFF_SIZE, MF_ULTRALIGHT_MAX_BUFF_SIZE); + nfca_poller_start(instance->nfca_poller, callback, context); + + return MfUltralightErrorNone; +} + +MfUltralightError mf_ultralight_poller_read( + MfUltralightPoller* instance, + MfUltralightPollerCallback callback, + void* context) { + furi_assert(instance); + furi_assert(instance->state == MfUltralightPollerStateIdle); + furi_assert(instance->nfca_poller); + furi_assert(callback); + instance->callback = callback; instance->context = context; - nfca_poller_start(instance->nfca_poller, mf_ultralight_nfca_poller_event_callback, instance); - - return MfUltralightErrorNone; + return mf_ultralight_poller_start( + instance, mf_ultralight_nfca_poller_event_callback, instance); } MfUltralightError @@ -263,40 +296,34 @@ MfUltralightError mf_ultralight_poller_write_page( return ret; } +static void mf_ultraight_read_version_callback(NfcaPollerEvent event, void* context) { + furi_assert(context); + + MfUltralightPollerContext* poller_context = context; + if(event.type == NfcaPollerEventTypeReady) { + poller_context->error = mf_ultralight_poller_get_version(poller_context->instance); + nfca_poller_halt(poller_context->instance->nfca_poller); + } else if(event.type == NfcaPollerEventTypeError) { + poller_context->error = mf_ultralight_process_error(event.data.error); + } + mf_ultralight_poller_stop(poller_context->instance); + furi_thread_flags_set(poller_context->thread_id, MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); +} + MfUltralightError mf_ultralight_poller_read_version(MfUltralightPoller* instance, MfUltralightVersion* data) { furi_assert(instance); furi_assert(data); + MfUltralightPollerContext poller_context = {}; + poller_context.instance = instance; + poller_context.thread_id = furi_thread_get_current_id(); - uint8_t tx_data[] = {MF_ULTRALIGHT_CMD_GET_VERSION}; - uint16_t tx_bits = sizeof(tx_data) * 8; - uint8_t rx_data[MF_ULTRALIGHT_MAX_BUFF_SIZE] = {}; - uint16_t rx_bits = 0; - NfcaError error = NfcaErrorNone; - MfUltralightError ret = MfUltralightErrorNone; + mf_ultralight_poller_start(instance, mf_ultraight_read_version_callback, &poller_context); + furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); + *data = instance->data->version; + mf_ultralight_poller_reset(instance); - do { - error = nfca_poller_send_standart_frame( - instance->nfca_poller, - tx_data, - tx_bits, - rx_data, - sizeof(rx_data), - &rx_bits, - MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); - if(error != NfcaErrorNone) { - ret = mf_ultralight_process_error(error); - break; - } - if(rx_bits != 8 * 8) { - ret = MfUltralightErrorProtocol; - FURI_LOG_E(TAG, "Received %d bits. Expected %d bits", rx_bits, 8 * 8); - break; - } - memcpy(data, rx_data, sizeof(MfUltralightVersion)); - } while(false); - - return ret; + return poller_context.error; } MfUltralightError diff --git a/lib/nfc/protocols/mf_ultralight_poller.h b/lib/nfc/protocols/mf_ultralight_poller.h index ca74f6c6c115..5dac97753a57 100644 --- a/lib/nfc/protocols/mf_ultralight_poller.h +++ b/lib/nfc/protocols/mf_ultralight_poller.h @@ -45,6 +45,11 @@ MfUltralightPoller* mf_ultralight_poller_alloc(NfcaPoller* nfca_poller); void mf_ultralight_poller_free(MfUltralightPoller* instance); MfUltralightError mf_ultralight_poller_start( + MfUltralightPoller* instance, + NfcaPollerEventCallback callback, + void* context); + +MfUltralightError mf_ultralight_poller_read( MfUltralightPoller* instance, MfUltralightPollerCallback callback, void* context); diff --git a/lib/nfc/protocols/nfca_poller.c b/lib/nfc/protocols/nfca_poller.c index fe08c3fff279..c73233d3eb14 100644 --- a/lib/nfc/protocols/nfca_poller.c +++ b/lib/nfc/protocols/nfca_poller.c @@ -165,7 +165,7 @@ static void nfca_poller_event_callback(NfcEvent event, void* context) { NfcaData data = {}; NfcaError error = nfca_poller_activate(instance, &data); if(error == NfcaErrorNone) { - nfca_poller_event.type = NfcaPollerEventTypeActivated; + nfca_poller_event.type = NfcaPollerEventTypeReady; instance->state = NfcaPollerActivated; } else { nfca_poller_event.type = NfcaPollerEventTypeError; @@ -259,8 +259,12 @@ NfcaError nfca_poller_halt(NfcaPoller* instance) { furi_assert(instance); furi_assert(instance->nfc); - // Halt - // Set Idle state + uint8_t tx_data[2] = {0x50, 0x00}; + uint16_t tx_bits = 16; + // Rework + uint8_t rx_data[2] = {}; + uint16_t rx_bits = 0; + nfca_poller_standart_frame_exchange(instance, tx_data, tx_bits, rx_data, 2, &rx_bits, 1000); instance->state = NfcaPollerStateIdle; return NfcaErrorNone; } diff --git a/lib/nfc/protocols/nfca_poller.h b/lib/nfc/protocols/nfca_poller.h index 287c18ef17ef..7cd83db243bf 100644 --- a/lib/nfc/protocols/nfca_poller.h +++ b/lib/nfc/protocols/nfca_poller.h @@ -12,7 +12,6 @@ typedef struct NfcaPoller NfcaPoller; typedef enum { NfcaPollerEventTypeError, NfcaPollerEventDetected, - NfcaPollerEventTypeActivated, NfcaPollerEventTypeReady, } NfcaPollerEventType; @@ -69,8 +68,6 @@ NfcaError nfca_poller_send_standart_frame( // Syncronous API NfcaError nfca_poller_activate_sync(NfcaPoller* instance, NfcaData* nfca_data); -NfcaError nfca_poller_check_presence_sync(NfcaPoller* instance); - #ifdef __cplusplus } #endif From 6b17f475b50de4efa0804a7260e912f9c7408fd7 Mon Sep 17 00:00:00 2001 From: gornekich Date: Wed, 19 Apr 2023 19:16:30 +0400 Subject: [PATCH 028/149] mf ultralight: add all sync api --- .../main/nfc_rpc/nfc_rpc_mf_ultralight.c | 4 - lib/nfc/protocols/mf_ultralight_poller.c | 450 ++++++++++++------ 2 files changed, 305 insertions(+), 149 deletions(-) diff --git a/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c b/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c index a67dc1965e4d..834eec1bd1e6 100644 --- a/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c +++ b/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c @@ -54,8 +54,6 @@ static void nfc_rpc_mf_ultralight_read_page(Nfc_Main* cmd, void* context) { pb_mf_ul_read_page_resp.data.size = sizeof(MfUltralightPage); } cmd->content.mf_ultralight_read_page_resp = pb_mf_ul_read_page_resp; - - mf_ultralight_poller_reset(instance->mf_ul_poller); } static void nfc_rpc_mf_ultralight_write_page(Nfc_Main* cmd, void* context) { @@ -125,8 +123,6 @@ static void nfc_rpc_mf_ultralight_read_signature(Nfc_Main* cmd, void* context) { pb_mf_ul_signature.data.size = sizeof(MfUltralightSignature); } cmd->content.mf_ultralight_read_signature_resp = pb_mf_ul_signature; - - mf_ultralight_poller_reset(instance->mf_ul_poller); } static void nfc_rpc_mf_ultralight_read_counter(Nfc_Main* cmd, void* context) { diff --git a/lib/nfc/protocols/mf_ultralight_poller.c b/lib/nfc/protocols/mf_ultralight_poller.c index 23c98878d559..fddc85d340df 100644 --- a/lib/nfc/protocols/mf_ultralight_poller.c +++ b/lib/nfc/protocols/mf_ultralight_poller.c @@ -8,14 +8,27 @@ #define MF_ULTRALIGHT_MAX_BUFF_SIZE (64) -#define MF_ULTRALIGHT_POLLER_STANDART_FWT_FC (12000) +#define MF_ULTRALIGHT_POLLER_STANDART_FWT_FC (120000) #define MF_ULTRALIGHT_POLLER_COMPLETE_EVENT (1UL << 0) +typedef struct { + MfUltralightPage page; + uint8_t page_to_write; +} MfUltralightPollerWritePageCommand; + +typedef union { + uint8_t page_to_read; + uint8_t counter_to_read; + uint8_t tearing_flag_to_read; + MfUltralightPollerWritePageCommand write_cmd; +} MfUltralightPollerContextData; + typedef struct { MfUltralightPoller* instance; FuriThreadId thread_id; MfUltralightError error; + MfUltralightPollerContextData data; } MfUltralightPollerContext; typedef enum { @@ -74,7 +87,75 @@ void mf_ultralight_poller_free(MfUltralightPoller* instance) { free(instance); } -static MfUltralightError mf_ultralight_poller_get_version(MfUltralightPoller* instance) { +static MfUltralightError + mf_ultralight_poller_async_read_page(MfUltralightPoller* instance, uint8_t page) { + NfcPollerBuffer* buff = instance->buffer; + buff->tx_data[0] = MF_ULTRALIGHT_CMD_READ_PAGE; + buff->tx_data[1] = page; + buff->tx_bits = 16; + + MfUltralightError ret = MfUltralightErrorNone; + NfcaError error = NfcaErrorNone; + do { + error = nfca_poller_send_standart_frame( + instance->nfca_poller, + buff->tx_data, + buff->tx_bits, + buff->rx_data, + buff->rx_data_size, + &buff->rx_bits, + MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); + if(error != NfcaErrorNone) { + ret = mf_ultralight_process_error(error); + break; + } + if(buff->rx_bits != (MF_ULTRALIGHT_PAGE_SIZE * 4) * 8) { + ret = MfUltralightErrorProtocol; + break; + } + memcpy(&instance->data->page[page], buff->rx_data, MF_ULTRALIGHT_PAGE_SIZE); + } while(false); + + return ret; +} + +static MfUltralightError mf_ultralight_poller_async_write_page( + MfUltralightPoller* instance, + uint8_t page, + MfUltralightPage* data) { + NfcPollerBuffer* buff = instance->buffer; + buff->tx_data[0] = MF_ULTRALIGHT_CMD_WRITE_PAGE; + buff->tx_data[1] = page; + memcpy(&buff->tx_data[2], data, MF_ULTRALIGHT_PAGE_SIZE); + buff->tx_bits = (2 + MF_ULTRALIGHT_PAGE_SIZE) * 8; + + MfUltralightError ret = MfUltralightErrorNone; + NfcaError error = NfcaErrorNone; + do { + error = nfca_poller_send_standart_frame( + instance->nfca_poller, + buff->tx_data, + buff->tx_bits, + buff->rx_data, + buff->rx_data_size, + &buff->rx_bits, + MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); + FURI_LOG_I(TAG, "Rx bits: %d", buff->rx_bits); + if(error != NfcaErrorNone) { + ret = mf_ultralight_process_error(error); + break; + } + if(buff->rx_bits != 4) { + ret = MfUltralightErrorProtocol; + break; + } + memcpy(&instance->data->page[page], buff->rx_data, MF_ULTRALIGHT_PAGE_SIZE); + } while(false); + + return ret; +} + +static MfUltralightError mf_ultralight_poller_async_read_version(MfUltralightPoller* instance) { NfcPollerBuffer* buff = instance->buffer; buff->tx_data[0] = MF_ULTRALIGHT_CMD_GET_VERSION; buff->tx_bits = 8; @@ -104,6 +185,105 @@ static MfUltralightError mf_ultralight_poller_get_version(MfUltralightPoller* in return ret; } +static MfUltralightError mf_ultralight_poller_async_read_signature(MfUltralightPoller* instance) { + NfcPollerBuffer* buff = instance->buffer; + buff->tx_data[0] = MF_ULTRALIGTH_CMD_READ_SIG; + buff->rx_data[1] = 0x00; + buff->tx_bits = 16; + + MfUltralightError ret = MfUltralightErrorNone; + NfcaError error = NfcaErrorNone; + do { + error = nfca_poller_send_standart_frame( + instance->nfca_poller, + buff->tx_data, + buff->tx_bits, + buff->rx_data, + buff->rx_data_size, + &buff->rx_bits, + MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); + if(error != NfcaErrorNone) { + ret = mf_ultralight_process_error(error); + break; + } + if(buff->rx_bits != 32 * 8) { + ret = MfUltralightErrorProtocol; + break; + } + memcpy(&instance->data->signature, buff->rx_data, sizeof(MfUltralightSignature)); + } while(false); + + return ret; +} + +static MfUltralightError + mf_ultralight_poller_async_read_counter(MfUltralightPoller* instance, uint8_t counter_num) { + NfcPollerBuffer* buff = instance->buffer; + buff->tx_data[0] = MF_ULTRALIGHT_CMD_READ_CNT; + buff->tx_data[1] = counter_num; + buff->tx_bits = 2 * 8; + + MfUltralightError ret = MfUltralightErrorNone; + NfcaError error = NfcaErrorNone; + do { + error = nfca_poller_send_standart_frame( + instance->nfca_poller, + buff->tx_data, + buff->tx_bits, + buff->rx_data, + buff->rx_data_size, + &buff->rx_bits, + MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); + if(error != NfcaErrorNone) { + ret = mf_ultralight_process_error(error); + break; + } + if(buff->rx_bits != 3 * 8) { + ret = MfUltralightErrorProtocol; + break; + } + memcpy(&instance->data->counter[counter_num], buff->rx_data, MF_ULTRALIGHT_COUNTER_SIZE); + } while(false); + + return ret; +} + +static MfUltralightError mf_ultralight_poller_async_read_tearing_flag( + MfUltralightPoller* instance, + uint8_t tearing_falg_num) { + NfcPollerBuffer* buff = instance->buffer; + buff->tx_data[0] = MF_ULTRALIGHT_CMD_CHECK_TEARING; + buff->tx_data[1] = tearing_falg_num; + buff->tx_bits = 2 * 8; + + MfUltralightError ret = MfUltralightErrorNone; + NfcaError error = NfcaErrorNone; + do { + error = nfca_poller_send_standart_frame( + instance->nfca_poller, + buff->tx_data, + buff->tx_bits, + buff->rx_data, + buff->rx_data_size, + &buff->rx_bits, + MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); + if(error != NfcaErrorNone) { + ret = mf_ultralight_process_error(error); + break; + } + if(buff->rx_bits != 8) { + ret = MfUltralightErrorProtocol; + break; + } + memcpy( + &instance->data->tearing_flag[tearing_falg_num], + buff->rx_data, + MF_ULTRALIGHT_TEARING_FLAG_SIZE); + } while(false); + + return ret; +} + static void mf_ultralight_nfca_poller_event_callback(NfcaPollerEvent event, void* context) { furi_assert(context); @@ -116,7 +296,7 @@ static void mf_ultralight_nfca_poller_event_callback(NfcaPollerEvent event, void nfc_poller_buffer_reset(buff); if(instance->state == MfUltralightPollerStateReadVersion) { - mf_ultralight_poller_get_version(instance); + mf_ultralight_poller_async_read_version(instance); } // Test: read 0 page buff->tx_data[0] = MF_ULTRALIGHT_CMD_READ_PAGE; @@ -214,6 +394,21 @@ MfUltralightError mf_ultralight_poller_stop(MfUltralightPoller* instance) { return MfUltralightErrorNone; } +static void mf_ultraight_read_page_callback(NfcaPollerEvent event, void* context) { + furi_assert(context); + + MfUltralightPollerContext* poller_context = context; + if(event.type == NfcaPollerEventTypeReady) { + poller_context->error = mf_ultralight_poller_async_read_page( + poller_context->instance, poller_context->data.page_to_read); + nfca_poller_halt(poller_context->instance->nfca_poller); + } else if(event.type == NfcaPollerEventTypeError) { + poller_context->error = mf_ultralight_process_error(event.data.error); + } + mf_ultralight_poller_stop(poller_context->instance); + furi_thread_flags_set(poller_context->thread_id, MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); +} + MfUltralightError mf_ultralight_poller_read_page( MfUltralightPoller* instance, uint16_t page, @@ -221,36 +416,34 @@ MfUltralightError mf_ultralight_poller_read_page( furi_assert(instance); furi_assert(data); - uint8_t tx_data[] = {MF_ULTRALIGHT_CMD_READ_PAGE, page}; - uint16_t tx_bits = sizeof(tx_data) * 8; - uint8_t rx_data[MF_ULTRALIGHT_MAX_BUFF_SIZE] = {}; - uint16_t rx_bits = 0; - MfUltralightError ret = MfUltralightErrorNone; - NfcaError error = NfcaErrorNone; + MfUltralightPollerContext poller_context = {}; + poller_context.data.page_to_read = page; + poller_context.instance = instance; + poller_context.thread_id = furi_thread_get_current_id(); - do { - error = nfca_poller_send_standart_frame( - instance->nfca_poller, - tx_data, - tx_bits, - rx_data, - sizeof(rx_data), - &rx_bits, - MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); - if(error != NfcaErrorNone) { - ret = mf_ultralight_process_error(error); - break; - } - if(rx_bits != (MF_ULTRALIGHT_PAGE_SIZE * 4) * 8) { - FURI_LOG_E( - TAG, "Received %d bits. Expected %d bits", rx_bits, (MF_ULTRALIGHT_PAGE_SIZE)*8); - ret = MfUltralightErrorProtocol; - break; - } - memcpy(data, rx_data, MF_ULTRALIGHT_PAGE_SIZE); - } while(false); + mf_ultralight_poller_start(instance, mf_ultraight_read_page_callback, &poller_context); + furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); + *data = instance->data->page[page]; + mf_ultralight_poller_reset(instance); - return ret; + return poller_context.error; +} + +static void mf_ultraight_write_page_callback(NfcaPollerEvent event, void* context) { + furi_assert(context); + + MfUltralightPollerContext* poller_context = context; + if(event.type == NfcaPollerEventTypeReady) { + poller_context->error = mf_ultralight_poller_async_write_page( + poller_context->instance, + poller_context->data.write_cmd.page_to_write, + &poller_context->data.write_cmd.page); + nfca_poller_halt(poller_context->instance->nfca_poller); + } else if(event.type == NfcaPollerEventTypeError) { + poller_context->error = mf_ultralight_process_error(event.data.error); + } + mf_ultralight_poller_stop(poller_context->instance); + furi_thread_flags_set(poller_context->thread_id, MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); } MfUltralightError mf_ultralight_poller_write_page( @@ -260,40 +453,17 @@ MfUltralightError mf_ultralight_poller_write_page( furi_assert(instance); furi_assert(data); - uint8_t tx_data[MF_ULTRALIGHT_PAGE_SIZE + 2] = {MF_ULTRALIGHT_CMD_WRITE_PAGE, page}; - memcpy(&tx_data[2], data, MF_ULTRALIGHT_PAGE_SIZE); - uint16_t tx_bits = (MF_ULTRALIGHT_PAGE_SIZE + 2) * 8; - uint8_t rx_data[MF_ULTRALIGHT_MAX_BUFF_SIZE] = {}; - uint16_t rx_bits = 0; - NfcaError error = NfcaErrorNone; - MfUltralightError ret = MfUltralightErrorNone; + MfUltralightPollerContext poller_context = {}; + poller_context.data.write_cmd.page_to_write = page; + poller_context.data.write_cmd.page = *data; + poller_context.instance = instance; + poller_context.thread_id = furi_thread_get_current_id(); - do { - error = nfca_poller_send_standart_frame( - instance->nfca_poller, - tx_data, - tx_bits, - rx_data, - sizeof(rx_data), - &rx_bits, - MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); - if(!(error == NfcaErrorNone || error == NfcaErrorWrongCrc)) { - ret = mf_ultralight_process_error(error); - break; - } - if(rx_bits != 4) { - ret = MfUltralightErrorProtocol; - FURI_LOG_E(TAG, "Received %d bits. Expected %d bits", rx_bits, 4); - break; - } - if(rx_data[0] != MF_ULTRALIGHT_CMD_ACK) { - ret = MfUltralightErrorProtocol; - FURI_LOG_E(TAG, "Nack received"); - break; - } - } while(false); + mf_ultralight_poller_start(instance, mf_ultraight_write_page_callback, &poller_context); + furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); + mf_ultralight_poller_reset(instance); - return ret; + return poller_context.error; } static void mf_ultraight_read_version_callback(NfcaPollerEvent event, void* context) { @@ -301,7 +471,7 @@ static void mf_ultraight_read_version_callback(NfcaPollerEvent event, void* cont MfUltralightPollerContext* poller_context = context; if(event.type == NfcaPollerEventTypeReady) { - poller_context->error = mf_ultralight_poller_get_version(poller_context->instance); + poller_context->error = mf_ultralight_poller_async_read_version(poller_context->instance); nfca_poller_halt(poller_context->instance->nfca_poller); } else if(event.type == NfcaPollerEventTypeError) { poller_context->error = mf_ultralight_process_error(event.data.error); @@ -326,40 +496,51 @@ MfUltralightError return poller_context.error; } +static void mf_ultraight_read_signature_callback(NfcaPollerEvent event, void* context) { + furi_assert(context); + + MfUltralightPollerContext* poller_context = context; + if(event.type == NfcaPollerEventTypeReady) { + poller_context->error = + mf_ultralight_poller_async_read_signature(poller_context->instance); + nfca_poller_halt(poller_context->instance->nfca_poller); + } else if(event.type == NfcaPollerEventTypeError) { + poller_context->error = mf_ultralight_process_error(event.data.error); + } + mf_ultralight_poller_stop(poller_context->instance); + furi_thread_flags_set(poller_context->thread_id, MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); +} + MfUltralightError mf_ultralight_poller_read_signature(MfUltralightPoller* instance, MfUltralightSignature* data) { furi_assert(instance); furi_assert(data); - uint8_t tx_data[] = {MF_ULTRALIGTH_CMD_READ_SIG, 0x00}; - uint16_t tx_bits = sizeof(tx_data) * 8; - uint8_t rx_data[MF_ULTRALIGHT_MAX_BUFF_SIZE] = {}; - uint16_t rx_bits = 0; - NfcaError error = NfcaErrorNone; - MfUltralightError ret = MfUltralightErrorNone; + MfUltralightPollerContext poller_context = {}; + poller_context.instance = instance; + poller_context.thread_id = furi_thread_get_current_id(); - do { - error = nfca_poller_send_standart_frame( - instance->nfca_poller, - tx_data, - tx_bits, - rx_data, - sizeof(rx_data), - &rx_bits, - MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); - if(error != NfcaErrorNone) { - ret = mf_ultralight_process_error(error); - break; - } - if(rx_bits != 32 * 8) { - ret = MfUltralightErrorProtocol; - FURI_LOG_E(TAG, "Received %d bits. Expected %d bits", rx_bits, 32 * 8); - break; - } - memcpy(data, rx_data, sizeof(MfUltralightSignature)); - } while(false); + mf_ultralight_poller_start(instance, mf_ultraight_read_signature_callback, &poller_context); + furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); + *data = instance->data->signature; + mf_ultralight_poller_reset(instance); - return ret; + return poller_context.error; +} + +static void mf_ultraight_read_counter_callback(NfcaPollerEvent event, void* context) { + furi_assert(context); + + MfUltralightPollerContext* poller_context = context; + if(event.type == NfcaPollerEventTypeReady) { + poller_context->error = mf_ultralight_poller_async_read_counter( + poller_context->instance, poller_context->data.counter_to_read); + nfca_poller_halt(poller_context->instance->nfca_poller); + } else if(event.type == NfcaPollerEventTypeError) { + poller_context->error = mf_ultralight_process_error(event.data.error); + } + mf_ultralight_poller_stop(poller_context->instance); + furi_thread_flags_set(poller_context->thread_id, MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); } MfUltralightError mf_ultralight_poller_read_counter( @@ -369,35 +550,32 @@ MfUltralightError mf_ultralight_poller_read_counter( furi_assert(instance); furi_assert(data); - uint8_t tx_data[] = {MF_ULTRALIGHT_CMD_READ_CNT, counter_num}; - uint16_t tx_bits = sizeof(tx_data) * 8; - uint8_t rx_data[MF_ULTRALIGHT_MAX_BUFF_SIZE] = {}; - uint16_t rx_bits = 0; - NfcaError error = NfcaErrorNone; - MfUltralightError ret = MfUltralightErrorNone; + MfUltralightPollerContext poller_context = {}; + poller_context.data.counter_to_read = counter_num; + poller_context.instance = instance; + poller_context.thread_id = furi_thread_get_current_id(); - do { - error = nfca_poller_send_standart_frame( - instance->nfca_poller, - tx_data, - tx_bits, - rx_data, - sizeof(rx_data), - &rx_bits, - MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); - if(error != NfcaErrorNone) { - ret = mf_ultralight_process_error(error); - break; - } - if(rx_bits != 3 * 8) { - ret = MfUltralightErrorProtocol; - FURI_LOG_E(TAG, "Received %d bits. Expected %d bits", rx_bits, 32 * 8); - break; - } - memcpy(data, rx_data, sizeof(MfUltralightCounter)); - } while(false); + mf_ultralight_poller_start(instance, mf_ultraight_read_counter_callback, &poller_context); + furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); + *data = instance->data->counter[counter_num]; + mf_ultralight_poller_reset(instance); - return ret; + return poller_context.error; +} + +static void mf_ultraight_read_tering_flag_callback(NfcaPollerEvent event, void* context) { + furi_assert(context); + + MfUltralightPollerContext* poller_context = context; + if(event.type == NfcaPollerEventTypeReady) { + poller_context->error = mf_ultralight_poller_async_read_tearing_flag( + poller_context->instance, poller_context->data.tearing_flag_to_read); + nfca_poller_halt(poller_context->instance->nfca_poller); + } else if(event.type == NfcaPollerEventTypeError) { + poller_context->error = mf_ultralight_process_error(event.data.error); + } + mf_ultralight_poller_stop(poller_context->instance); + furi_thread_flags_set(poller_context->thread_id, MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); } MfUltralightError mf_ultralight_poller_read_tearing_flag( @@ -407,33 +585,15 @@ MfUltralightError mf_ultralight_poller_read_tearing_flag( furi_assert(instance); furi_assert(data); - uint8_t tx_data[] = {MF_ULTRALIGHT_CMD_CHECK_TEARING, flag_num}; - uint16_t tx_bits = sizeof(tx_data) * 8; - uint8_t rx_data[MF_ULTRALIGHT_MAX_BUFF_SIZE] = {}; - uint16_t rx_bits = 0; - NfcaError error = NfcaErrorNone; - MfUltralightError ret = MfUltralightErrorNone; + MfUltralightPollerContext poller_context = {}; + poller_context.data.tearing_flag_to_read = flag_num; + poller_context.instance = instance; + poller_context.thread_id = furi_thread_get_current_id(); - do { - error = nfca_poller_send_standart_frame( - instance->nfca_poller, - tx_data, - tx_bits, - rx_data, - sizeof(rx_data), - &rx_bits, - MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); - if(error != NfcaErrorNone) { - ret = mf_ultralight_process_error(error); - break; - } - if(rx_bits != 8) { - ret = MfUltralightErrorProtocol; - FURI_LOG_E(TAG, "Received %d bits. Expected %d bits", rx_bits, 8); - break; - } - memcpy(data, rx_data, sizeof(MfUltralightTearingFlag)); - } while(false); + mf_ultralight_poller_start(instance, mf_ultraight_read_tering_flag_callback, &poller_context); + furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); + *data = instance->data->tearing_flag[flag_num]; + mf_ultralight_poller_reset(instance); - return ret; + return poller_context.error; } From 82aa39c83980fcc3bd920cbe19a588da2a0548f5 Mon Sep 17 00:00:00 2001 From: gornekich Date: Thu, 20 Apr 2023 16:54:00 +0400 Subject: [PATCH 029/149] mf ultralight: read state machine --- .../nfc/scenes/nfc_scene_mf_ultralight_read.c | 4 +- .../nfc_scene_mf_ultralight_read_success.c | 19 +- .../main/nfc/scenes/nfc_scene_retry_confirm.c | 13 +- lib/nfc/protocols/mf_ultralight.c | 95 +++++++++ lib/nfc/protocols/mf_ultralight.h | 33 ++- lib/nfc/protocols/mf_ultralight_listener.c | 17 +- lib/nfc/protocols/mf_ultralight_poller.c | 189 +++++++++++++++--- lib/nfc/protocols/mf_ultralight_poller.h | 8 +- 8 files changed, 317 insertions(+), 61 deletions(-) diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read.c index 867d44fb5b6f..699cd86b8d9e 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read.c @@ -8,8 +8,8 @@ enum { void nfc_scene_mf_ultralight_read_worker_callback(MfUltralightPollerEvent event, void* context) { NfcApp* nfc = context; - if(event.type == MfUltralightPollerEventTypeReadComplete) { - nfca_poller_stop(nfc->nfca_poller); + if(event.type == MfUltralightPollerEventTypeReadSuccess) { + mf_ultralight_poller_stop(nfc->mf_ul_poller); view_dispatcher_send_custom_event( nfc->view_dispatcher, NfcWorkerEventMfUltralightReadSuccess); } else { diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_success.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_success.c index 327335b6076b..f8b0d0a61f64 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_success.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_success.c @@ -20,19 +20,21 @@ void nfc_scene_mf_ultralight_read_success_on_enter(void* context) { Widget* widget = nfc->widget; FuriString* temp_str; - temp_str = furi_string_alloc_set("\e#Mf Ultralight\n"); - notification_message_block(nfc->notifications, &sequence_set_green_255); + temp_str = furi_string_alloc_printf("\e#%s\n", mf_ultralight_get_name(data->type, true)); + furi_string_cat_printf(temp_str, "UID:"); + for(size_t i = 0; i < data->nfca_data.uid_len; i++) { + furi_string_cat_printf(temp_str, " %02X", data->nfca_data.uid[i]); + } + furi_string_cat_printf( + temp_str, "\nPages Read: %d/%d", data->pages_read, data->pages_total); + if(data->pages_read != data->pages_total) { + furi_string_cat_printf(temp_str, "\nPassword-protected pages!"); + } widget_add_text_scroll_element(widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); furi_string_free(temp_str); - FURI_LOG_I("MfUlReadSuccess", "Read success"); - for(size_t i = 0; i < 4; i++) { - printf("%02X ", data->page->data[i]); - } - printf("\r\n"); - widget_add_button_element( widget, GuiButtonTypeLeft, @@ -46,6 +48,7 @@ void nfc_scene_mf_ultralight_read_success_on_enter(void* context) { nfc_scene_mf_ultralight_read_success_widget_callback, nfc); + notification_message_block(nfc->notifications, &sequence_set_green_255); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); } diff --git a/applications/main/nfc/scenes/nfc_scene_retry_confirm.c b/applications/main/nfc/scenes/nfc_scene_retry_confirm.c index 54aa62a0f22c..ba27051c45b8 100644 --- a/applications/main/nfc/scenes/nfc_scene_retry_confirm.c +++ b/applications/main/nfc/scenes/nfc_scene_retry_confirm.c @@ -29,8 +29,17 @@ bool nfc_scene_retry_confirm_on_event(void* context, SceneManagerEvent event) { if(event.event == DialogExResultRight) { consumed = scene_manager_previous_scene(nfc->scene_manager); } else if(event.event == DialogExResultLeft) { - consumed = scene_manager_search_and_switch_to_previous_scene( - nfc->scene_manager, NfcSceneNfcaRead); + if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneRead)) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneRead); + } else if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneNfcaRead)) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneNfcaRead); + } else if(scene_manager_has_previous_scene( + nfc->scene_manager, NfcSceneMfUltralightRead)) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneMfUltralightRead); + } } } else if(event.type == SceneManagerEventTypeBack) { consumed = true; diff --git a/lib/nfc/protocols/mf_ultralight.c b/lib/nfc/protocols/mf_ultralight.c index 4aa4f611f1ee..f7a62bd424e9 100644 --- a/lib/nfc/protocols/mf_ultralight.c +++ b/lib/nfc/protocols/mf_ultralight.c @@ -2,6 +2,67 @@ #include +static const uint16_t mf_ultralight_total_pages[MfUltralightTypeNum] = { + [MfUltralightTypeUnknown] = 16, + [MfUltralightTypeNTAG203] = 42, + [MfUltralightTypeUL11] = 20, + [MfUltralightTypeUL21] = 41, + [MfUltralightTypeNTAG213] = 45, + [MfUltralightTypeNTAG215] = 135, + [MfUltralightTypeNTAG216] = 231, + [MfUltralightTypeNTAGI2C1K] = 231, + [MfUltralightTypeNTAGI2C2K] = 485, + [MfUltralightTypeNTAGI2CPlus1K] = 236, + [MfUltralightTypeNTAGI2CPlus2K] = 492, +}; + +static const uint32_t mf_ultarlight_feature_sets[MfUltralightTypeNum] = { + [MfUltralightTypeUnknown] = MfUltralightFeatureSupportCompatibleWrite, + [MfUltralightTypeNTAG203] = MfUltralightFeatureSupportCompatibleWrite | + MfUltralightFeatureSupportCounterInMemory, + [MfUltralightTypeUL11] = + MfUltralightFeatureSupportReadVersion | MfUltralightFeatureSupportReadSignature | + MfUltralightFeatureSupportReadCounter | MfUltralightFeatureSupportCheckTearingFlag | + MfUltralightFeatureSupportFastRead | MfUltralightFeatureSupportIncCounter | + MfUltralightFeatureSupportCompatibleWrite | MfUltralightFeatureSupportAuthentication | + MfUltralightFeatureSupportVcsl, + [MfUltralightTypeUL21] = + MfUltralightFeatureSupportReadVersion | MfUltralightFeatureSupportReadSignature | + MfUltralightFeatureSupportReadCounter | MfUltralightFeatureSupportCheckTearingFlag | + MfUltralightFeatureSupportFastRead | MfUltralightFeatureSupportIncCounter | + MfUltralightFeatureSupportCompatibleWrite | MfUltralightFeatureSupportAuthentication | + MfUltralightFeatureSupportVcsl, + [MfUltralightTypeNTAG213] = + MfUltralightFeatureSupportReadVersion | MfUltralightFeatureSupportReadSignature | + MfUltralightFeatureSupportReadCounter | MfUltralightFeatureSupportFastRead | + MfUltralightFeatureSupportCompatibleWrite | MfUltralightFeatureSupportAuthentication | + MfUltralightFeatureSupportSingleCounter | MfUltralightFeatureSupportAsciiMirror, + [MfUltralightTypeNTAG215] = + MfUltralightFeatureSupportReadVersion | MfUltralightFeatureSupportReadSignature | + MfUltralightFeatureSupportReadCounter | MfUltralightFeatureSupportFastRead | + MfUltralightFeatureSupportCompatibleWrite | MfUltralightFeatureSupportAuthentication | + MfUltralightFeatureSupportSingleCounter | MfUltralightFeatureSupportAsciiMirror, + [MfUltralightTypeNTAG216] = + MfUltralightFeatureSupportReadVersion | MfUltralightFeatureSupportReadSignature | + MfUltralightFeatureSupportReadCounter | MfUltralightFeatureSupportFastRead | + MfUltralightFeatureSupportCompatibleWrite | MfUltralightFeatureSupportAuthentication | + MfUltralightFeatureSupportSingleCounter | MfUltralightFeatureSupportAsciiMirror, + [MfUltralightTypeNTAGI2C1K] = + MfUltralightFeatureSupportReadVersion | MfUltralightFeatureSupportFastRead | + MfUltralightFeatureSupportFastWrite | MfUltralightFeatureSupportSectorSelect, + [MfUltralightTypeNTAGI2C2K] = + MfUltralightFeatureSupportReadVersion | MfUltralightFeatureSupportFastRead | + MfUltralightFeatureSupportFastWrite | MfUltralightFeatureSupportSectorSelect, + [MfUltralightTypeNTAGI2CPlus1K] = + MfUltralightFeatureSupportReadVersion | MfUltralightFeatureSupportReadSignature | + MfUltralightFeatureSupportFastRead | MfUltralightFeatureSupportAuthentication | + MfUltralightFeatureSupportSectorSelect, + [MfUltralightTypeNTAGI2CPlus2K] = + MfUltralightFeatureSupportReadVersion | MfUltralightFeatureSupportReadSignature | + MfUltralightFeatureSupportFastRead | MfUltralightFeatureSupportAuthentication | + MfUltralightFeatureSupportSectorSelect, +}; + MfUltralightType mf_ultralight_get_type_by_version(MfUltralightVersion* version) { furi_assert(version); @@ -35,3 +96,37 @@ MfUltralightType mf_ultralight_get_type_by_version(MfUltralightVersion* version) return type; } + +uint16_t mf_ultralight_get_pages_total(MfUltralightType type) { + return mf_ultralight_total_pages[type]; +} + +uint32_t mf_ultralight_get_feature_support_set(MfUltralightType type) { + return mf_ultarlight_feature_sets[type]; +} + +const char* mf_ultralight_get_name(MfUltralightType type, bool full_name) { + if(type == MfUltralightTypeNTAG213) { + return "NTAG213"; + } else if(type == MfUltralightTypeNTAG215) { + return "NTAG215"; + } else if(type == MfUltralightTypeNTAG216) { + return "NTAG216"; + } else if(type == MfUltralightTypeNTAGI2C1K) { + return "NTAG I2C 1K"; + } else if(type == MfUltralightTypeNTAGI2C2K) { + return "NTAG I2C 2K"; + } else if(type == MfUltralightTypeNTAGI2CPlus1K) { + return "NTAG I2C Plus 1K"; + } else if(type == MfUltralightTypeNTAGI2CPlus2K) { + return "NTAG I2C Plus 2K"; + } else if(type == MfUltralightTypeNTAG203) { + return "NTAG203"; + } else if(type == MfUltralightTypeUL11 && full_name) { + return "Mifare Ultralight 11"; + } else if(type == MfUltralightTypeUL21 && full_name) { + return "Mifare Ultralight 21"; + } else { + return "Mifare Ultralight"; + } +} diff --git a/lib/nfc/protocols/mf_ultralight.h b/lib/nfc/protocols/mf_ultralight.h index 26870c3f5ac8..ef31632e24c7 100644 --- a/lib/nfc/protocols/mf_ultralight.h +++ b/lib/nfc/protocols/mf_ultralight.h @@ -12,6 +12,8 @@ extern "C" { #define MF_ULTRALIGTH_CMD_READ_SIG (0x3C) #define MF_ULTRALIGHT_CMD_READ_CNT (0x39) #define MF_ULTRALIGHT_CMD_CHECK_TEARING (0x3E) +#define MF_ULTRALIGHT_CMD_AUTH (0x1B) + #define MF_ULTRALIGHT_CMD_ACK (0x0A) #define MF_ULTRALIGHT_CMD_NACK (0x00) @@ -36,24 +38,36 @@ typedef enum { typedef enum { MfUltralightTypeUnknown, MfUltralightTypeNTAG203, - // Below have config pages and GET_VERSION support MfUltralightTypeUL11, MfUltralightTypeUL21, MfUltralightTypeNTAG213, MfUltralightTypeNTAG215, MfUltralightTypeNTAG216, - // Below also have sector select - // NTAG I2C's *does not* have regular config pages, so it's a bit of an odd duck MfUltralightTypeNTAGI2C1K, MfUltralightTypeNTAGI2C2K, - // NTAG I2C Plus has stucture expected from NTAG21x MfUltralightTypeNTAGI2CPlus1K, MfUltralightTypeNTAGI2CPlus2K, - // Keep last for number of types calculation MfUltralightTypeNum, } MfUltralightType; +typedef enum { + MfUltralightFeatureSupportReadVersion = (1U << 0), + MfUltralightFeatureSupportReadSignature = (1U << 1), + MfUltralightFeatureSupportReadCounter = (1U << 2), + MfUltralightFeatureSupportCheckTearingFlag = (1U << 3), + MfUltralightFeatureSupportFastRead = (1U << 4), + MfUltralightFeatureSupportIncCounter = (1U << 5), + MfUltralightFeatureSupportFastWrite = (1U << 6), + MfUltralightFeatureSupportCompatibleWrite = (1U << 7), + MfUltralightFeatureSupportAuthentication = (1U << 8), + MfUltralightFeatureSupportVcsl = (1U << 9), + MfUltralightFeatureSupportSectorSelect = (1U << 10), + MfUltralightFeatureSupportSingleCounter = (1U << 11), + MfUltralightFeatureSupportAsciiMirror = (1U << 12), + MfUltralightFeatureSupportCounterInMemory = (1U << 13), +} MfUltralightFeatureSupport; + typedef struct { uint8_t data[MF_ULTRALIGHT_PAGE_SIZE]; } MfUltralightPage; @@ -97,11 +111,18 @@ typedef struct { MfUltralightCounter counter[MF_ULTRALIGHT_COUNTER_NUM]; MfUltralightTearingFlag tearing_flag[MF_ULTRALIGHT_TEARING_FLAG_NUM]; MfUltralightPage page[MF_ULTRALIGHT_MAX_PAGE_NUM]; - uint32_t paged_read; + uint16_t pages_read; + uint16_t pages_total; } MfUltralightData; MfUltralightType mf_ultralight_get_type_by_version(MfUltralightVersion* version); +uint16_t mf_ultralight_get_pages_total(MfUltralightType type); + +uint32_t mf_ultralight_get_feature_support_set(MfUltralightType type); + +const char* mf_ultralight_get_name(MfUltralightType type, bool full_name); + #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/mf_ultralight_listener.c b/lib/nfc/protocols/mf_ultralight_listener.c index b3b3d08daae2..f0275daeae48 100644 --- a/lib/nfc/protocols/mf_ultralight_listener.c +++ b/lib/nfc/protocols/mf_ultralight_listener.c @@ -12,13 +12,6 @@ typedef enum { MfUltraligthListenerStateAuthSuccess, } MfUltraligthListenerState; -typedef enum { - MfUltralightListenerFeatureSupportReadVersion = (1U << 0), - MfUltralightListenerFeatureSupportReadSignature = (1U << 1), - MfUltralightListenerFeatureSupportReadCounter = (1U << 2), - MfUltralightListenerFeatureSupportCheckTearingFlag = (1U << 3), -} MfUltralightListenerFeatureSupport; - struct MfUltralightListener { NfcaListener* nfca_listener; MfUltraligthListenerState state; @@ -26,7 +19,7 @@ struct MfUltralightListener { uint8_t tx_data[MF_ULTRALIGHT_LISTENER_MAX_TX_BUFF_SIZE]; uint16_t tx_bits; uint16_t pages_total; - MfUltralightListenerFeatureSupport features; + MfUltralightFeatureSupport features; MfUltralightListenerEventcallback callback; void* context; }; @@ -100,7 +93,7 @@ static bool mf_ultralight_listener_read_version_handler( UNUSED(rx_bits); UNUSED(rx_data); bool command_processed = false; - if((instance->features & MfUltralightListenerFeatureSupportReadVersion)) { + if((instance->features & MfUltralightFeatureSupportReadVersion)) { memcpy(instance->tx_data, &instance->data->version, sizeof(instance->data->version)); instance->tx_bits = sizeof(instance->data->version) * 8; nfca_listener_send_standart_frame( @@ -121,7 +114,7 @@ static bool mf_ultralight_listener_read_signature_handler( UNUSED(rx_bits); UNUSED(rx_data); bool command_processed = false; - if((instance->features & MfUltralightListenerFeatureSupportReadSignature)) { + if((instance->features & MfUltralightFeatureSupportReadSignature)) { memcpy(instance->tx_data, &instance->data->signature, sizeof(instance->data->signature)); instance->tx_bits = sizeof(instance->data->signature) * 8; nfca_listener_send_standart_frame( @@ -176,8 +169,8 @@ static void mf_ultralight_listener_event_handler(NfcaListenerEvent event, void* static void mf_ultralight_listener_prepare_emulation(MfUltralightListener* instance) { MfUltralightData* data = instance->data; if(data->type == MfUltralightTypeUnknown) { - instance->features = MfUltralightListenerFeatureSupportReadVersion | - MfUltralightListenerFeatureSupportReadSignature; + instance->features = MfUltralightFeatureSupportReadVersion | + MfUltralightFeatureSupportReadSignature; instance->pages_total = 16; } } diff --git a/lib/nfc/protocols/mf_ultralight_poller.c b/lib/nfc/protocols/mf_ultralight_poller.c index fddc85d340df..06aa4ea7dbf4 100644 --- a/lib/nfc/protocols/mf_ultralight_poller.c +++ b/lib/nfc/protocols/mf_ultralight_poller.c @@ -35,8 +35,14 @@ typedef enum { MfUltralightPollerStateIdle, MfUltralightPollerStateReadVersion, MfUltralightPollerStateDetectNtag203, + MfUltralightPollerStateGetFeatureSet, MfUltralightPollerStateReadSignature, - MfUltralightPollerStateRead + MfUltralightPollerStateReadCounters, + MfUltralightPollerStateReadTearingFlags, + MfUltralightPollerStateAuth, + MfUltralightPollerStateReadPages, + MfUltralightPollerStateReadFailed, + MfUltralightPollerStateReadSuccess, } MfUltralightPollerState; struct MfUltralightPoller { @@ -45,6 +51,10 @@ struct MfUltralightPoller { NfcPollerBuffer* buffer; MfUltralightData* data; MfUltralightPollerCallback callback; + MfUltralightAuthPassword auth_password; + uint32_t feature_set; + uint16_t pages_read; + uint16_t pages_total; void* context; }; @@ -87,6 +97,47 @@ void mf_ultralight_poller_free(MfUltralightPoller* instance) { free(instance); } +static MfUltralightError + mf_ultralight_poller_async_auth(MfUltralightPoller* instance, MfUltralightAuthPassword* data) { + NfcPollerBuffer* buff = instance->buffer; + buff->tx_data[0] = MF_ULTRALIGHT_CMD_AUTH; + memcpy(&buff->rx_data[1], data, MF_ULTRALIGHT_AUTH_PASSWORD_SIZE); + buff->tx_bits = (MF_ULTRALIGHT_AUTH_PASSWORD_SIZE + 1) * 8; + + MfUltralightError ret = MfUltralightErrorNone; + NfcaError error = NfcaErrorNone; + do { + error = nfca_poller_send_standart_frame( + instance->nfca_poller, + buff->tx_data, + buff->tx_bits, + buff->rx_data, + buff->rx_data_size, + &buff->rx_bits, + MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); + if(error != NfcaErrorNone) { + ret = mf_ultralight_process_error(error); + break; + } + if(buff->rx_bits != (MF_ULTRALIGHT_AUTH_PACK_SIZE * 8)) { + ret = MfUltralightErrorAuth; + break; + } + if(instance->pages_total != 0) { + memcpy( + &instance->data->page[instance->pages_total - 2], + data, + MF_ULTRALIGHT_AUTH_PASSWORD_SIZE); + memcpy( + &instance->data->page[instance->pages_total - 1], + buff->rx_data, + MF_ULTRALIGHT_AUTH_PACK_SIZE); + } + } while(false); + + return ret; +} + static MfUltralightError mf_ultralight_poller_async_read_page(MfUltralightPoller* instance, uint8_t page) { NfcPollerBuffer* buff = instance->buffer; @@ -284,40 +335,128 @@ static MfUltralightError mf_ultralight_poller_async_read_tearing_flag( return ret; } -static void mf_ultralight_nfca_poller_event_callback(NfcaPollerEvent event, void* context) { +static void mf_ultralight_poller_read_callback(NfcaPollerEvent event, void* context) { furi_assert(context); MfUltralightPoller* instance = context; MfUltralightPollerEvent mf_ul_poller_event = {}; - NfcaError error = NfcaErrorNone; + MfUltralightError error = MfUltralightErrorNone; if(event.type == NfcaPollerEventTypeReady) { NfcPollerBuffer* buff = instance->buffer; nfc_poller_buffer_reset(buff); if(instance->state == MfUltralightPollerStateReadVersion) { - mf_ultralight_poller_async_read_version(instance); + error = mf_ultralight_poller_async_read_version(instance); + if(error == MfUltralightErrorNone) { + FURI_LOG_I(TAG, "Read version success"); + instance->data->type = mf_ultralight_get_type_by_version(&instance->data->version); + instance->state = MfUltralightPollerStateGetFeatureSet; + } else { + FURI_LOG_W(TAG, "Didn't response. Check NTAG 203"); + nfca_poller_halt(instance->nfca_poller); + instance->state = MfUltralightPollerStateDetectNtag203; + } + } else if(instance->state == MfUltralightPollerStateDetectNtag203) { + error = mf_ultralight_poller_async_read_page(instance, 41); + if(error == MfUltralightErrorNone) { + FURI_LOG_I(TAG, "NTAG203 detected"); + instance->data->type = MfUltralightTypeNTAG203; + instance->state = MfUltralightPollerStateGetFeatureSet; + } else { + FURI_LOG_I(TAG, "Original Ultralight detected"); + nfca_poller_halt(instance->nfca_poller); + instance->data->type = MfUltralightTypeUnknown; + instance->state = MfUltralightPollerStateGetFeatureSet; + } + } else if(instance->state == MfUltralightPollerStateGetFeatureSet) { + instance->feature_set = mf_ultralight_get_feature_support_set(instance->data->type); + instance->pages_total = mf_ultralight_get_pages_total(instance->data->type); + instance->pages_read = 0; + instance->data->pages_total = instance->pages_total; + FURI_LOG_I( + TAG, + "%s detected. Total pages: %d", + mf_ultralight_get_name(instance->data->type, true), + instance->pages_total); + if((instance->callback) && + (instance->feature_set & MfUltralightFeatureSupportAuthentication)) { + mf_ul_poller_event.type = MfUltralightPollerEventTypeAuthRequest; + instance->callback(mf_ul_poller_event, instance->callback); + if(!mf_ul_poller_event.data.auth_context.skip_auth) { + instance->auth_password = mf_ul_poller_event.data.auth_context.password; + instance->state = MfUltralightPollerStateAuth; + } else { + instance->state = MfUltralightPollerStateReadPages; + } + } else { + instance->state = MfUltralightPollerStateReadPages; + } + } else if(instance->state == MfUltralightPollerStateAuth) { + error = mf_ultralight_poller_async_auth(instance, &instance->auth_password); + if(error == MfUltralightErrorNone) { + if(instance->callback) { + mf_ul_poller_event.type = MfUltralightPollerEventTypeAuthSuccess; + memcpy( + &mf_ul_poller_event.data.pack, + &instance->data->page[instance->data->pages_read - 1], + MF_ULTRALIGHT_AUTH_PACK_SIZE); + instance->callback(mf_ul_poller_event, instance->context); + } + } else { + if(instance->callback) { + mf_ul_poller_event.type = MfUltralightPollerEventTypeAuthFailed; + instance->callback(mf_ul_poller_event, instance->context); + } + nfca_poller_halt(instance->nfca_poller); + } + instance->state = MfUltralightPollerStateReadPages; + } else if(instance->state == MfUltralightPollerStateReadPages) { + error = mf_ultralight_poller_async_read_page(instance, instance->pages_read); + if(error == MfUltralightErrorNone) { + FURI_LOG_I(TAG, "Read page %d success", instance->pages_read); + instance->pages_read++; + instance->data->pages_read = instance->pages_read; + if(instance->pages_read == instance->pages_total - 2) { + instance->state = MfUltralightPollerStateReadSuccess; + } + } else { + FURI_LOG_E(TAG, "Read page %d failed", instance->pages_read); + if(instance->pages_read) { + instance->state = MfUltralightPollerStateReadSuccess; + } else { + instance->state = MfUltralightPollerStateReadFailed; + } + } + } else if(instance->state == MfUltralightPollerStateReadSignature) { + error = mf_ultralight_poller_async_read_signature(instance); + if(error == MfUltralightErrorNone) { + FURI_LOG_I(TAG, "Read signature success"); + if(instance->feature_set & MfUltralightFeatureSupportReadCounter) { + instance->state = MfUltralightPollerStateReadCounters; + } + } else { + FURI_LOG_E(TAG, "Read signature failed"); + instance->state = MfUltralightPollerStateReadFailed; + } + } else if(instance->state == MfUltralightPollerStateReadCounters) { + } else if(instance->state == MfUltralightPollerStateReadSuccess) { + nfca_poller_get_data(instance->nfca_poller, &instance->data->nfca_data); + if(instance->callback) { + mf_ul_poller_event.type = MfUltralightPollerEventTypeReadSuccess; + instance->callback(mf_ul_poller_event, instance->context); + } + } else if(instance->state == MfUltralightPollerStateReadFailed) { + if(instance->callback) { + mf_ul_poller_event.type = MfUltralightPollerEventTypeReadFailed; + instance->callback(mf_ul_poller_event, instance->context); + } } - // Test: read 0 page - buff->tx_data[0] = MF_ULTRALIGHT_CMD_READ_PAGE; - buff->tx_data[1] = 0; - buff->tx_bits = 16; - error = nfca_poller_send_standart_frame( - instance->nfca_poller, - buff->tx_data, - buff->tx_bits, - buff->rx_data, - buff->rx_data_size, - &buff->rx_bits, - MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); - if(error == NfcaErrorNone) { - FURI_LOG_T(TAG, "Read page 0 success"); - memcpy(&instance->data->page[0], buff->rx_data, buff->rx_bits / 8); - } else { - FURI_LOG_E(TAG, "Error reading 0 page"); + } else if(event.type == NfcaPollerEventTypeError) { + if(instance->callback) { + mf_ul_poller_event.type = MfUltralightPollerEventTypeReadFailed; + instance->callback(mf_ul_poller_event, instance->context); } - mf_ul_poller_event.type = MfUltralightPollerEventTypeReadComplete; - instance->callback(mf_ul_poller_event, instance->context); } } @@ -351,8 +490,8 @@ MfUltralightError mf_ultralight_poller_read( instance->callback = callback; instance->context = context; - return mf_ultralight_poller_start( - instance, mf_ultralight_nfca_poller_event_callback, instance); + instance->state = MfUltralightPollerStateReadVersion; + return mf_ultralight_poller_start(instance, mf_ultralight_poller_read_callback, instance); } MfUltralightError diff --git a/lib/nfc/protocols/mf_ultralight_poller.h b/lib/nfc/protocols/mf_ultralight_poller.h index 5dac97753a57..a8e8a4403378 100644 --- a/lib/nfc/protocols/mf_ultralight_poller.h +++ b/lib/nfc/protocols/mf_ultralight_poller.h @@ -10,15 +10,11 @@ extern "C" { typedef struct MfUltralightPoller MfUltralightPoller; typedef enum { - MfUltralightPollerEventTypeReadVersion, - MfUltralightPollerEventTypeReadSignature, - MfUltralightPollerEventTypeReadCounters, - MfUltralightPollerEventTypeReadTearingFlags, MfUltralightPollerEventTypeAuthRequest, MfUltralightPollerEventTypeAuthSuccess, MfUltralightPollerEventTypeAuthFailed, - MfUltralightPollerEventTypeReadPages, - MfUltralightPollerEventTypeReadComplete, + MfUltralightPollerEventTypeReadSuccess, + MfUltralightPollerEventTypeReadFailed, } MfUltralightPollerEventType; typedef struct { From 22be7d45e9b2b34e65e339cacadd5999baca33f5 Mon Sep 17 00:00:00 2001 From: gornekich Date: Thu, 20 Apr 2023 20:36:12 +0400 Subject: [PATCH 030/149] nfc: add unlock scenes --- .../main/nfc/scenes/nfc_scene_config.h | 3 + .../main/nfc/scenes/nfc_scene_extra_actions.c | 2 +- .../nfc_scene_mf_ultralight_unlock_menu.c | 80 +++++++++++++++++++ .../nfc_scene_mf_ultralight_unlock_warn.c | 49 ++++++++++++ 4 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_menu.c create mode 100644 applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index bf226d1695a4..9bb57976a11f 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -11,5 +11,8 @@ ADD_SCENE(nfc, retry_confirm, RetryConfirm) ADD_SCENE(nfc, exit_confirm, ExitConfirm) ADD_SCENE(nfc, mf_ultralight_read, MfUltralightRead) ADD_SCENE(nfc, mf_ultralight_read_success, MfUltralightReadSuccess) +ADD_SCENE(nfc, mf_ultralight_unlock_menu, MfUltralightUnlockMenu) +ADD_SCENE(nfc, mf_ultralight_unlock_warn, MfUltralightUnlockWarn) + ADD_SCENE(nfc, not_implemented, NotImplemented) \ No newline at end of file diff --git a/applications/main/nfc/scenes/nfc_scene_extra_actions.c b/applications/main/nfc/scenes/nfc_scene_extra_actions.c index effd38f60c66..94365b163b55 100644 --- a/applications/main/nfc/scenes/nfc_scene_extra_actions.c +++ b/applications/main/nfc/scenes/nfc_scene_extra_actions.c @@ -48,7 +48,7 @@ bool nfc_scene_extra_actions_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); consumed = true; } else if(event.event == SubmenuIndexMfUltralightUnlock) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockMenu); consumed = true; } else if(event.event == SubmenuIndexReadCardType) { scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardType); diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_menu.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_menu.c new file mode 100644 index 000000000000..50a18cef061c --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_menu.c @@ -0,0 +1,80 @@ +#include "../nfc_app_i.h" + +enum SubmenuIndex { + SubmenuIndexMfUlUnlockMenuReader, + SubmenuIndexMfUlUnlockMenuAmeebo, + SubmenuIndexMfUlUnlockMenuXiaomi, + SubmenuIndexMfUlUnlockMenuManual, +}; + +void nfc_scene_mf_ultralight_unlock_menu_submenu_callback(void* context, uint32_t index) { + NfcApp* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, index); +} + +void nfc_scene_mf_ultralight_unlock_menu_on_enter(void* context) { + NfcApp* nfc = context; + Submenu* submenu = nfc->submenu; + + uint32_t state = + scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightUnlockMenu); + if(nfc->nfc_dev_data.protocol == NfcDevProtocolMfUltralight) { + submenu_add_item( + submenu, + "Unlock With Reader", + SubmenuIndexMfUlUnlockMenuReader, + nfc_scene_mf_ultralight_unlock_menu_submenu_callback, + nfc); + } + submenu_add_item( + submenu, + "Auth As Ameebo", + SubmenuIndexMfUlUnlockMenuAmeebo, + nfc_scene_mf_ultralight_unlock_menu_submenu_callback, + nfc); + submenu_add_item( + submenu, + "Auth As Xiaomi Air Purifier", + SubmenuIndexMfUlUnlockMenuXiaomi, + nfc_scene_mf_ultralight_unlock_menu_submenu_callback, + nfc); + submenu_add_item( + submenu, + "Enter Password Manually", + SubmenuIndexMfUlUnlockMenuManual, + nfc_scene_mf_ultralight_unlock_menu_submenu_callback, + nfc); + submenu_set_selected_item(submenu, state); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); +} + +bool nfc_scene_mf_ultralight_unlock_menu_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexMfUlUnlockMenuManual) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + consumed = true; + } else if(event.event == SubmenuIndexMfUlUnlockMenuAmeebo) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockWarn); + consumed = true; + } else if(event.event == SubmenuIndexMfUlUnlockMenuXiaomi) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockWarn); + consumed = true; + } else if(event.event == SubmenuIndexMfUlUnlockMenuReader) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + consumed = true; + } + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneMfUltralightUnlockMenu, event.event); + } + return consumed; +} + +void nfc_scene_mf_ultralight_unlock_menu_on_exit(void* context) { + NfcApp* nfc = context; + + submenu_reset(nfc->submenu); +} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c new file mode 100644 index 000000000000..1628e179b2b0 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c @@ -0,0 +1,49 @@ +#include "../nfc_app_i.h" +#include + +void nfc_scene_mf_ultralight_unlock_warn_dialog_callback(DialogExResult result, void* context) { + NfcApp* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); +} + +void nfc_scene_mf_ultralight_unlock_warn_on_enter(void* context) { + NfcApp* nfc = context; + DialogEx* dialog_ex = nfc->dialog_ex; + + dialog_ex_set_context(dialog_ex, nfc); + dialog_ex_set_result_callback(dialog_ex, nfc_scene_mf_ultralight_unlock_warn_dialog_callback); + + dialog_ex_set_header(dialog_ex, "Risky function!", 64, 4, AlignCenter, AlignTop); + dialog_ex_set_text( + dialog_ex, "Wrong password\ncan block your\ncard.", 4, 18, AlignLeft, AlignTop); + dialog_ex_set_icon(dialog_ex, 73, 20, &I_DolphinCommon_56x48); + dialog_ex_set_center_button_text(dialog_ex, "OK"); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); +} + +bool nfc_scene_mf_ultralight_unlock_warn_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == DialogExResultCenter) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + DOLPHIN_DEED(DolphinDeedNfcRead); + consumed = true; + } + } + + return consumed; +} + +void nfc_scene_mf_ultralight_unlock_warn_on_exit(void* context) { + NfcApp* nfc = context; + + dialog_ex_reset(nfc->dialog_ex); + nfc_text_store_clear(nfc); + + notification_message_block(nfc->notifications, &sequence_reset_green); +} From 343964664f60914fd02015d1ae4e35ac1e7f57e0 Mon Sep 17 00:00:00 2001 From: gornekich Date: Thu, 20 Apr 2023 21:06:49 +0400 Subject: [PATCH 031/149] nfc: add mf ultralight menu --- .../main/nfc/scenes/nfc_scene_config.h | 1 + .../nfc/scenes/nfc_scene_mf_ultralight_menu.c | 84 +++++++++++++++++++ .../nfc_scene_mf_ultralight_read_success.c | 3 +- lib/nfc/protocols/mf_ultralight.c | 6 ++ lib/nfc/protocols/mf_ultralight.h | 2 + 5 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index 9bb57976a11f..7097e9aeebe0 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -11,6 +11,7 @@ ADD_SCENE(nfc, retry_confirm, RetryConfirm) ADD_SCENE(nfc, exit_confirm, ExitConfirm) ADD_SCENE(nfc, mf_ultralight_read, MfUltralightRead) ADD_SCENE(nfc, mf_ultralight_read_success, MfUltralightReadSuccess) +ADD_SCENE(nfc, mf_ultralight_menu, MfUltralightMenu) ADD_SCENE(nfc, mf_ultralight_unlock_menu, MfUltralightUnlockMenu) ADD_SCENE(nfc, mf_ultralight_unlock_warn, MfUltralightUnlockWarn) diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c new file mode 100644 index 000000000000..6a22bf2e1d68 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c @@ -0,0 +1,84 @@ +#include "../nfc_app_i.h" +#include + +enum SubmenuIndex { + SubmenuIndexUnlock, + SubmenuIndexSave, + SubmenuIndexEmulate, + SubmenuIndexInfo, +}; + +void nfc_scene_mf_ultralight_menu_submenu_callback(void* context, uint32_t index) { + NfcApp* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, index); +} + +void nfc_scene_mf_ultralight_menu_on_enter(void* context) { + NfcApp* nfc = context; + Submenu* submenu = nfc->submenu; + MfUltralightData* data = &nfc->nfc_dev_data.mf_ul_data; + + if(!mf_ultralight_is_all_data_read(data)) { + submenu_add_item( + submenu, + "Unlock", + SubmenuIndexUnlock, + nfc_scene_mf_ultralight_menu_submenu_callback, + nfc); + } + submenu_add_item( + submenu, "Save", SubmenuIndexSave, nfc_scene_mf_ultralight_menu_submenu_callback, nfc); + submenu_add_item( + submenu, + "Emulate", + SubmenuIndexEmulate, + nfc_scene_mf_ultralight_menu_submenu_callback, + nfc); + submenu_add_item( + submenu, "Info", SubmenuIndexInfo, nfc_scene_mf_ultralight_menu_submenu_callback, nfc); + + submenu_set_selected_item( + nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightMenu)); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); +} + +bool nfc_scene_mf_ultralight_menu_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexSave) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + consumed = true; + } else if(event.event == SubmenuIndexEmulate) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + // 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, NfcSceneMfUltralightUnlockMenu); + consumed = true; + } else if(event.event == SubmenuIndexInfo) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + consumed = true; + } + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfUltralightMenu, event.event); + + } else if(event.type == SceneManagerEventTypeBack) { + consumed = scene_manager_previous_scene(nfc->scene_manager); + } + + return consumed; +} + +void nfc_scene_mf_ultralight_menu_on_exit(void* context) { + NfcApp* nfc = context; + + // Clear view + submenu_reset(nfc->submenu); +} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_success.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_success.c index f8b0d0a61f64..f53619832dd1 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_success.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_success.c @@ -16,6 +16,7 @@ void nfc_scene_mf_ultralight_read_success_on_enter(void* context) { NfcApp* nfc = context; // Setup view + nfc->nfc_dev_data.protocol = NfcDevProtocolMfUltralight; MfUltralightData* data = &nfc->nfc_dev_data.mf_ul_data; Widget* widget = nfc->widget; @@ -61,7 +62,7 @@ bool nfc_scene_mf_ultralight_read_success_on_event(void* context, SceneManagerEv scene_manager_next_scene(nfc->scene_manager, NfcSceneRetryConfirm); consumed = true; } else if(event.event == GuiButtonTypeRight) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcaMenu); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightMenu); consumed = true; } } else if(event.type == SceneManagerEventTypeBack) { diff --git a/lib/nfc/protocols/mf_ultralight.c b/lib/nfc/protocols/mf_ultralight.c index f7a62bd424e9..5362e89bb812 100644 --- a/lib/nfc/protocols/mf_ultralight.c +++ b/lib/nfc/protocols/mf_ultralight.c @@ -130,3 +130,9 @@ const char* mf_ultralight_get_name(MfUltralightType type, bool full_name) { return "Mifare Ultralight"; } } + +bool mf_ultralight_is_all_data_read(MfUltralightData* data) { + furi_assert(data); + // TODO add logic + return false; +} diff --git a/lib/nfc/protocols/mf_ultralight.h b/lib/nfc/protocols/mf_ultralight.h index ef31632e24c7..10991c422337 100644 --- a/lib/nfc/protocols/mf_ultralight.h +++ b/lib/nfc/protocols/mf_ultralight.h @@ -123,6 +123,8 @@ uint32_t mf_ultralight_get_feature_support_set(MfUltralightType type); const char* mf_ultralight_get_name(MfUltralightType type, bool full_name); +bool mf_ultralight_is_all_data_read(MfUltralightData* data); + #ifdef __cplusplus } #endif From 79bdc92db29be6a5b51859770300f34478923389 Mon Sep 17 00:00:00 2001 From: gornekich Date: Thu, 20 Apr 2023 22:08:58 +0400 Subject: [PATCH 032/149] nfc app: introduce mifare ultralight auth --- .../main/nfc/helpers/mf_ultralight_auth.c | 23 ++++++++++++++ .../main/nfc/helpers/mf_ultralight_auth.h | 31 +++++++++++++++++++ applications/main/nfc/nfc_app.c | 21 +++++++++---- applications/main/nfc/nfc_app_i.h | 3 ++ 4 files changed, 72 insertions(+), 6 deletions(-) create mode 100644 applications/main/nfc/helpers/mf_ultralight_auth.c create mode 100644 applications/main/nfc/helpers/mf_ultralight_auth.h diff --git a/applications/main/nfc/helpers/mf_ultralight_auth.c b/applications/main/nfc/helpers/mf_ultralight_auth.c new file mode 100644 index 000000000000..3766efa23dd1 --- /dev/null +++ b/applications/main/nfc/helpers/mf_ultralight_auth.c @@ -0,0 +1,23 @@ +#include "mf_ultralight_auth.h" + +#include + +MfUltralightAuth* mf_ultralight_auth_alloc() { + MfUltralightAuth* instance = malloc(sizeof(MfUltralightAuth)); + + return instance; +} + +void mf_ultralight_auth_free(MfUltralightAuth* instance) { + furi_assert(instance); + + free(instance); +} + +void mf_ultralight_auth_reset(MfUltralightAuth* instance) { + furi_assert(instance); + + instance->type = MfUltralightAuthTypeNone; + memset(&instance->password, 0, sizeof(MfUltralightAuthPassword)); + memset(&instance->pack, 0, sizeof(MfUltralightAuthPack)); +} \ No newline at end of file diff --git a/applications/main/nfc/helpers/mf_ultralight_auth.h b/applications/main/nfc/helpers/mf_ultralight_auth.h new file mode 100644 index 000000000000..dc5de279dbc4 --- /dev/null +++ b/applications/main/nfc/helpers/mf_ultralight_auth.h @@ -0,0 +1,31 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + MfUltralightAuthTypeNone, + MfUltralightAuthTypeReader, + MfUltralightAuthTypeManual, + MfUltralightAuthTypeXiaomii, + MfUltralightAuthTypeAmiibo, +} MfUltralightAuthType; + +typedef struct { + MfUltralightAuthType type; + MfUltralightAuthPassword password; + MfUltralightAuthPack pack; +} MfUltralightAuth; + +MfUltralightAuth* mf_ultralight_auth_alloc(); + +void mf_ultralight_auth_free(MfUltralightAuth* instance); + +void mf_ultralight_auth_reset(MfUltralightAuth* instance); + +#ifdef __cplusplus +} +#endif diff --git a/applications/main/nfc/nfc_app.c b/applications/main/nfc/nfc_app.c index 4474c3cec27e..b3994b1b753d 100644 --- a/applications/main/nfc/nfc_app.c +++ b/applications/main/nfc/nfc_app.c @@ -40,8 +40,10 @@ NfcApp* nfc_app_alloc() { instance->scene_manager = scene_manager_alloc(&nfc_scene_handlers, instance); view_dispatcher_enable_queue(instance->view_dispatcher); view_dispatcher_set_event_callback_context(instance->view_dispatcher, instance); - view_dispatcher_set_custom_event_callback(instance->view_dispatcher, nfc_custom_event_callback); - view_dispatcher_set_navigation_event_callback(instance->view_dispatcher, nfc_back_event_callback); + view_dispatcher_set_custom_event_callback( + instance->view_dispatcher, nfc_custom_event_callback); + view_dispatcher_set_navigation_event_callback( + instance->view_dispatcher, nfc_back_event_callback); instance->nfc = nfc_alloc(); instance->nfca_poller = nfca_poller_alloc(instance->nfc); @@ -49,6 +51,7 @@ NfcApp* nfc_app_alloc() { instance->nfca_listener = nfca_listener_alloc(instance->nfc); instance->mf_ul_listener = mf_ultralight_listener_alloc(instance->nfca_listener); + instance->mf_ul_auth = mf_ultralight_auth_alloc(); // Nfc device instance->nfc_dev = nfc_dev_alloc(); @@ -61,7 +64,8 @@ NfcApp* nfc_app_alloc() { // Submenu instance->submenu = submenu_alloc(); - view_dispatcher_add_view(instance->view_dispatcher, NfcViewMenu, submenu_get_view(instance->submenu)); + view_dispatcher_add_view( + instance->view_dispatcher, NfcViewMenu, submenu_get_view(instance->submenu)); // Dialog instance->dialog_ex = dialog_ex_alloc(); @@ -70,11 +74,13 @@ NfcApp* nfc_app_alloc() { // Popup instance->popup = popup_alloc(); - view_dispatcher_add_view(instance->view_dispatcher, NfcViewPopup, popup_get_view(instance->popup)); + view_dispatcher_add_view( + instance->view_dispatcher, NfcViewPopup, popup_get_view(instance->popup)); // Loading instance->loading = loading_alloc(); - view_dispatcher_add_view(instance->view_dispatcher, NfcViewLoading, loading_get_view(instance->loading)); + view_dispatcher_add_view( + instance->view_dispatcher, NfcViewLoading, loading_get_view(instance->loading)); // Text Input instance->text_input = text_input_alloc(); @@ -94,7 +100,8 @@ NfcApp* nfc_app_alloc() { // Custom Widget instance->widget = widget_alloc(); - view_dispatcher_add_view(instance->view_dispatcher, NfcViewWidget, widget_get_view(instance->widget)); + view_dispatcher_add_view( + instance->view_dispatcher, NfcViewWidget, widget_get_view(instance->widget)); return instance; } @@ -125,6 +132,8 @@ void nfc_app_free(NfcApp* instance) { nfca_poller_free(instance->nfca_poller); nfc_free(instance->nfc); + mf_ultralight_auth_free(instance->mf_ul_auth); + // Nfc device nfc_dev_free(instance->nfc_dev); diff --git a/applications/main/nfc/nfc_app_i.h b/applications/main/nfc/nfc_app_i.h index 48fe483ccc30..821ca775f936 100644 --- a/applications/main/nfc/nfc_app_i.h +++ b/applications/main/nfc/nfc_app_i.h @@ -24,6 +24,7 @@ #include #include +#include "helpers/mf_ultralight_auth.h" #include @@ -77,6 +78,8 @@ struct NfcApp { MfUltralightPoller* mf_ul_poller; MfUltralightListener* mf_ul_listener; + MfUltralightAuth* mf_ul_auth; + NfcDev* nfc_dev; NfcDevData nfc_dev_data; }; From 789a37fa6fdc1dccae2be97263f90f5025a17445 Mon Sep 17 00:00:00 2001 From: gornekich Date: Thu, 20 Apr 2023 23:49:54 +0400 Subject: [PATCH 033/149] nfc app: add unlock scripts --- .../main/nfc/helpers/mf_ultralight_auth.c | 39 ++++++++++++ .../main/nfc/helpers/mf_ultralight_auth.h | 4 ++ .../main/nfc/scenes/nfc_scene_config.h | 1 + .../main/nfc/scenes/nfc_scene_extra_actions.c | 1 + .../nfc_scene_mf_ultralight_key_input.c | 44 +++++++++++++ .../nfc/scenes/nfc_scene_mf_ultralight_read.c | 21 +++++++ .../nfc_scene_mf_ultralight_unlock_menu.c | 6 +- .../nfc_scene_mf_ultralight_unlock_warn.c | 63 ++++++++++++++++--- lib/nfc/nfc.c | 2 +- lib/nfc/protocols/mf_ultralight.h | 6 +- lib/nfc/protocols/mf_ultralight_poller.c | 19 +++--- lib/nfc/protocols/mf_ultralight_poller.h | 2 +- 12 files changed, 187 insertions(+), 21 deletions(-) create mode 100644 applications/main/nfc/scenes/nfc_scene_mf_ultralight_key_input.c diff --git a/applications/main/nfc/helpers/mf_ultralight_auth.c b/applications/main/nfc/helpers/mf_ultralight_auth.c index 3766efa23dd1..683ff47d4463 100644 --- a/applications/main/nfc/helpers/mf_ultralight_auth.c +++ b/applications/main/nfc/helpers/mf_ultralight_auth.c @@ -1,6 +1,7 @@ #include "mf_ultralight_auth.h" #include +#include MfUltralightAuth* mf_ultralight_auth_alloc() { MfUltralightAuth* instance = malloc(sizeof(MfUltralightAuth)); @@ -20,4 +21,42 @@ void mf_ultralight_auth_reset(MfUltralightAuth* instance) { instance->type = MfUltralightAuthTypeNone; memset(&instance->password, 0, sizeof(MfUltralightAuthPassword)); memset(&instance->pack, 0, sizeof(MfUltralightAuthPack)); +} + +bool mf_ultralight_generate_amiibo_pass(MfUltralightAuth* instance, uint8_t* uid, uint16_t uid_len) { + furi_assert(instance); + furi_assert(uid); + + uint32_t pwd = 0; + bool generated = false; + if(uid_len == 7) { + pwd |= (uid[1] ^ uid[3] ^ 0xAA) << 24; + pwd |= (uid[2] ^ uid[4] ^ 0x55) << 16; + pwd |= (uid[3] ^ uid[5] ^ 0xAA) << 8; + pwd |= uid[4] ^ uid[6] ^ 0x55; + instance->password.pass = pwd; + generated = true; + } + + return generated; +} + +bool mf_ultralight_generate_xiaomi_pass(MfUltralightAuth* instance, uint8_t* uid, uint16_t uid_len) { + furi_assert(instance); + furi_assert(uid); + + uint32_t pwd = 0; + uint8_t hash[20]; + bool generated = false; + if(uid_len == 7) { + mbedtls_sha1(uid, uid_len, hash); + pwd |= (hash[hash[0] % 20]) << 24; + pwd |= (hash[(hash[0] + 5) % 20]) << 16; + pwd |= (hash[(hash[0] + 13) % 20]) << 8; + pwd |= (hash[(hash[0] + 17) % 20]); + instance->password.pass = pwd; + generated = true; + } + + return generated; } \ No newline at end of file diff --git a/applications/main/nfc/helpers/mf_ultralight_auth.h b/applications/main/nfc/helpers/mf_ultralight_auth.h index dc5de279dbc4..237e3b8ac07a 100644 --- a/applications/main/nfc/helpers/mf_ultralight_auth.h +++ b/applications/main/nfc/helpers/mf_ultralight_auth.h @@ -26,6 +26,10 @@ void mf_ultralight_auth_free(MfUltralightAuth* instance); void mf_ultralight_auth_reset(MfUltralightAuth* instance); +bool mf_ultralight_generate_amiibo_pass(MfUltralightAuth* instance, uint8_t* uid, uint16_t uid_len); + +bool mf_ultralight_generate_xiaomi_pass(MfUltralightAuth* instance, uint8_t* uid, uint16_t uid_len); + #ifdef __cplusplus } #endif diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index 7097e9aeebe0..241d6d1bc029 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -14,6 +14,7 @@ ADD_SCENE(nfc, mf_ultralight_read_success, MfUltralightReadSuccess) ADD_SCENE(nfc, mf_ultralight_menu, MfUltralightMenu) ADD_SCENE(nfc, mf_ultralight_unlock_menu, MfUltralightUnlockMenu) ADD_SCENE(nfc, mf_ultralight_unlock_warn, MfUltralightUnlockWarn) +ADD_SCENE(nfc, mf_ultralight_key_input, MfUltralightKeyInput) ADD_SCENE(nfc, not_implemented, NotImplemented) \ No newline at end of file diff --git a/applications/main/nfc/scenes/nfc_scene_extra_actions.c b/applications/main/nfc/scenes/nfc_scene_extra_actions.c index 94365b163b55..35c8a9cea8c9 100644 --- a/applications/main/nfc/scenes/nfc_scene_extra_actions.c +++ b/applications/main/nfc/scenes/nfc_scene_extra_actions.c @@ -48,6 +48,7 @@ bool nfc_scene_extra_actions_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); consumed = true; } else if(event.event == SubmenuIndexMfUltralightUnlock) { + mf_ultralight_auth_reset(nfc->mf_ul_auth); scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockMenu); consumed = true; } else if(event.event == SubmenuIndexReadCardType) { diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_key_input.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_key_input.c new file mode 100644 index 000000000000..6db6023d274a --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_key_input.c @@ -0,0 +1,44 @@ +#include "../nfc_app_i.h" + +void nfc_scene_mf_ultralight_key_input_byte_input_callback(void* context) { + NfcApp* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); +} + +void nfc_scene_mf_ultralight_key_input_on_enter(void* context) { + NfcApp* nfc = context; + + // Setup view + ByteInput* byte_input = nfc->byte_input; + byte_input_set_header_text(byte_input, "Enter the password in hex"); + byte_input_set_result_callback( + byte_input, + nfc_scene_mf_ultralight_key_input_byte_input_callback, + NULL, + nfc, + nfc->mf_ul_auth->password.data, + 4); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewByteInput); +} + +bool nfc_scene_mf_ultralight_key_input_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventByteInputDone) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockWarn); + consumed = true; + } + } + return consumed; +} + +void nfc_scene_mf_ultralight_key_input_on_exit(void* context) { + NfcApp* nfc = context; + + // Clear view + byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0); + byte_input_set_header_text(nfc->byte_input, ""); +} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read.c index 699cd86b8d9e..19038675932c 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read.c @@ -12,6 +12,27 @@ void nfc_scene_mf_ultralight_read_worker_callback(MfUltralightPollerEvent event, mf_ultralight_poller_stop(nfc->mf_ul_poller); view_dispatcher_send_custom_event( nfc->view_dispatcher, NfcWorkerEventMfUltralightReadSuccess); + } else if(event.type == MfUltralightPollerEventTypeAuthRequest) { + MfUltralightData* data = &nfc->nfc_dev_data.mf_ul_data; + mf_ultralight_poller_get_data(nfc->mf_ul_poller, data); + if(nfc->mf_ul_auth->type == MfUltralightAuthTypeXiaomii) { + if(mf_ultralight_generate_xiaomi_pass( + nfc->mf_ul_auth, data->nfca_data.uid, data->nfca_data.uid_len)) { + event.data->auth_context.skip_auth = false; + } + } else if(nfc->mf_ul_auth->type == MfUltralightAuthTypeAmiibo) { + if(mf_ultralight_generate_amiibo_pass( + nfc->mf_ul_auth, data->nfca_data.uid, data->nfca_data.uid_len)) { + event.data->auth_context.skip_auth = false; + } + } else if(nfc->mf_ul_auth->type == MfUltralightAuthTypeManual) { + event.data->auth_context.skip_auth = false; + } + if(!event.data->auth_context.skip_auth) { + event.data->auth_context.password = nfc->mf_ul_auth->password; + } + } else if(event.type == MfUltralightPollerEventTypeAuthSuccess) { + nfc->mf_ul_auth->pack = event.data->pack; } else { furi_delay_ms(100); } diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_menu.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_menu.c index 50a18cef061c..db4b9d156460 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_menu.c @@ -55,15 +55,19 @@ bool nfc_scene_mf_ultralight_unlock_menu_on_event(void* context, SceneManagerEve if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubmenuIndexMfUlUnlockMenuManual) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + nfc->mf_ul_auth->type = MfUltralightAuthTypeManual; + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightKeyInput); consumed = true; } else if(event.event == SubmenuIndexMfUlUnlockMenuAmeebo) { + nfc->mf_ul_auth->type = MfUltralightAuthTypeAmiibo; scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockWarn); consumed = true; } else if(event.event == SubmenuIndexMfUlUnlockMenuXiaomi) { + nfc->mf_ul_auth->type = MfUltralightAuthTypeXiaomii; scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockWarn); consumed = true; } else if(event.event == SubmenuIndexMfUlUnlockMenuReader) { + nfc->mf_ul_auth->type = MfUltralightAuthTypeReader; scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); consumed = true; } diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c index 1628e179b2b0..659dcfb606fd 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c @@ -14,11 +14,35 @@ void nfc_scene_mf_ultralight_unlock_warn_on_enter(void* context) { dialog_ex_set_context(dialog_ex, nfc); dialog_ex_set_result_callback(dialog_ex, nfc_scene_mf_ultralight_unlock_warn_dialog_callback); - dialog_ex_set_header(dialog_ex, "Risky function!", 64, 4, AlignCenter, AlignTop); - dialog_ex_set_text( - dialog_ex, "Wrong password\ncan block your\ncard.", 4, 18, AlignLeft, AlignTop); - dialog_ex_set_icon(dialog_ex, 73, 20, &I_DolphinCommon_56x48); - dialog_ex_set_center_button_text(dialog_ex, "OK"); + MfUltralightAuthType type = nfc->mf_ul_auth->type; + if((type == MfUltralightAuthTypeReader) || (type == MfUltralightAuthTypeManual)) { + // Build dialog text + FuriString* password_str = + furi_string_alloc_set_str("Try to unlock the card with\npassword: "); + for(size_t i = 0; i < sizeof(nfc->mf_ul_auth->password); i++) { + furi_string_cat_printf(password_str, "%02X ", nfc->mf_ul_auth->password.data[i]); + } + furi_string_cat_str(password_str, "?\nCaution, a wrong password\ncan block the card!"); + nfc_text_store_set(nfc, furi_string_get_cstr(password_str)); + furi_string_free(password_str); + + const char* message = (type == MfUltralightAuthTypeReader) ? "Password captured!" : + "Risky function!"; + dialog_ex_set_header(dialog_ex, message, 64, 0, AlignCenter, AlignTop); + dialog_ex_set_text(dialog_ex, nfc->text_store, 64, 12, AlignCenter, AlignTop); + dialog_ex_set_left_button_text(dialog_ex, "Cancel"); + dialog_ex_set_right_button_text(dialog_ex, "Continue"); + + if(type == MfUltralightAuthTypeReader) { + notification_message(nfc->notifications, &sequence_set_green_255); + } + } else { + dialog_ex_set_header(dialog_ex, "Risky function!", 64, 4, AlignCenter, AlignTop); + dialog_ex_set_text( + dialog_ex, "Wrong password\ncan block your\ncard.", 4, 18, AlignLeft, AlignTop); + dialog_ex_set_icon(dialog_ex, 73, 20, &I_DolphinCommon_56x48); + dialog_ex_set_center_button_text(dialog_ex, "OK"); + } view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); } @@ -28,12 +52,33 @@ bool nfc_scene_mf_ultralight_unlock_warn_on_event(void* context, SceneManagerEve bool consumed = false; - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == DialogExResultCenter) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); - DOLPHIN_DEED(DolphinDeedNfcRead); + MfUltralightAuthType type = nfc->mf_ul_auth->type; + if((type == MfUltralightAuthTypeReader) || (type == MfUltralightAuthTypeManual)) { + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == DialogExResultRight) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightRead); + DOLPHIN_DEED(DolphinDeedNfcRead); + consumed = true; + } else if(event.event == DialogExResultLeft) { + if(type == MfUltralightAuthTypeReader) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneMfUltralightUnlockMenu); + } else { + consumed = scene_manager_previous_scene(nfc->scene_manager); + } + } + } else if(event.type == SceneManagerEventTypeBack) { + // Cannot press back consumed = true; } + } else { + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == DialogExResultCenter) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightRead); + DOLPHIN_DEED(DolphinDeedNfcRead); + consumed = true; + } + } } return consumed; diff --git a/lib/nfc/nfc.c b/lib/nfc/nfc.c index 4cd20e4ebb99..098c93271502 100644 --- a/lib/nfc/nfc.c +++ b/lib/nfc/nfc.c @@ -151,7 +151,7 @@ Nfc* nfc_alloc() { furi_thread_set_name(instance->worker_thread, "NfcWorker"); furi_thread_set_context(instance->worker_thread, instance); furi_thread_set_priority(instance->worker_thread, FuriThreadPriorityHighest); - furi_thread_set_stack_size(instance->worker_thread, 4 * 1024); + furi_thread_set_stack_size(instance->worker_thread, 8 * 1024); return instance; } diff --git a/lib/nfc/protocols/mf_ultralight.h b/lib/nfc/protocols/mf_ultralight.h index 10991c422337..394013e5217a 100644 --- a/lib/nfc/protocols/mf_ultralight.h +++ b/lib/nfc/protocols/mf_ultralight.h @@ -95,12 +95,14 @@ typedef struct { uint8_t data[MF_ULTRALIGHT_TEARING_FLAG_SIZE]; } MfUltralightTearingFlag; -typedef struct { +typedef union { uint8_t data[MF_ULTRALIGHT_AUTH_PASSWORD_SIZE]; + uint32_t pass; } MfUltralightAuthPassword; -typedef struct { +typedef union { uint8_t data[MF_ULTRALIGHT_AUTH_PACK_SIZE]; + uint16_t pack; } MfUltralightAuthPack; typedef struct { diff --git a/lib/nfc/protocols/mf_ultralight_poller.c b/lib/nfc/protocols/mf_ultralight_poller.c index 06aa4ea7dbf4..81b8425f05a9 100644 --- a/lib/nfc/protocols/mf_ultralight_poller.c +++ b/lib/nfc/protocols/mf_ultralight_poller.c @@ -3,6 +3,7 @@ #include #include "nfca_poller.h" #include +#include "nfc_util.h" #define TAG "MfUltralightPoller" @@ -101,7 +102,8 @@ static MfUltralightError mf_ultralight_poller_async_auth(MfUltralightPoller* instance, MfUltralightAuthPassword* data) { NfcPollerBuffer* buff = instance->buffer; buff->tx_data[0] = MF_ULTRALIGHT_CMD_AUTH; - memcpy(&buff->rx_data[1], data, MF_ULTRALIGHT_AUTH_PASSWORD_SIZE); + // fill password in lsb + nfc_util_num2bytes(data->pass, MF_ULTRALIGHT_AUTH_PASSWORD_SIZE, &buff->tx_data[1]); buff->tx_bits = (MF_ULTRALIGHT_AUTH_PASSWORD_SIZE + 1) * 8; MfUltralightError ret = MfUltralightErrorNone; @@ -339,12 +341,14 @@ static void mf_ultralight_poller_read_callback(NfcaPollerEvent event, void* cont furi_assert(context); MfUltralightPoller* instance = context; - MfUltralightPollerEvent mf_ul_poller_event = {}; + MfUltralightPollerEventData event_data = {}; + MfUltralightPollerEvent mf_ul_poller_event = {.data = &event_data}; MfUltralightError error = MfUltralightErrorNone; if(event.type == NfcaPollerEventTypeReady) { NfcPollerBuffer* buff = instance->buffer; nfc_poller_buffer_reset(buff); + nfca_poller_get_data(instance->nfca_poller, &instance->data->nfca_data); if(instance->state == MfUltralightPollerStateReadVersion) { error = mf_ultralight_poller_async_read_version(instance); @@ -382,9 +386,9 @@ static void mf_ultralight_poller_read_callback(NfcaPollerEvent event, void* cont if((instance->callback) && (instance->feature_set & MfUltralightFeatureSupportAuthentication)) { mf_ul_poller_event.type = MfUltralightPollerEventTypeAuthRequest; - instance->callback(mf_ul_poller_event, instance->callback); - if(!mf_ul_poller_event.data.auth_context.skip_auth) { - instance->auth_password = mf_ul_poller_event.data.auth_context.password; + instance->callback(mf_ul_poller_event, instance->context); + if(!mf_ul_poller_event.data->auth_context.skip_auth) { + instance->auth_password = mf_ul_poller_event.data->auth_context.password; instance->state = MfUltralightPollerStateAuth; } else { instance->state = MfUltralightPollerStateReadPages; @@ -395,15 +399,17 @@ static void mf_ultralight_poller_read_callback(NfcaPollerEvent event, void* cont } else if(instance->state == MfUltralightPollerStateAuth) { error = mf_ultralight_poller_async_auth(instance, &instance->auth_password); if(error == MfUltralightErrorNone) { + FURI_LOG_I(TAG, "Auth success"); if(instance->callback) { mf_ul_poller_event.type = MfUltralightPollerEventTypeAuthSuccess; memcpy( - &mf_ul_poller_event.data.pack, + &mf_ul_poller_event.data->pack, &instance->data->page[instance->data->pages_read - 1], MF_ULTRALIGHT_AUTH_PACK_SIZE); instance->callback(mf_ul_poller_event, instance->context); } } else { + FURI_LOG_W(TAG, "Auth failed"); if(instance->callback) { mf_ul_poller_event.type = MfUltralightPollerEventTypeAuthFailed; instance->callback(mf_ul_poller_event, instance->context); @@ -441,7 +447,6 @@ static void mf_ultralight_poller_read_callback(NfcaPollerEvent event, void* cont } } else if(instance->state == MfUltralightPollerStateReadCounters) { } else if(instance->state == MfUltralightPollerStateReadSuccess) { - nfca_poller_get_data(instance->nfca_poller, &instance->data->nfca_data); if(instance->callback) { mf_ul_poller_event.type = MfUltralightPollerEventTypeReadSuccess; instance->callback(mf_ul_poller_event, instance->context); diff --git a/lib/nfc/protocols/mf_ultralight_poller.h b/lib/nfc/protocols/mf_ultralight_poller.h index a8e8a4403378..2a7de6568e15 100644 --- a/lib/nfc/protocols/mf_ultralight_poller.h +++ b/lib/nfc/protocols/mf_ultralight_poller.h @@ -31,7 +31,7 @@ typedef struct { typedef struct { MfUltralightPollerEventType type; - MfUltralightPollerEventData data; + MfUltralightPollerEventData* data; } MfUltralightPollerEvent; typedef void (*MfUltralightPollerCallback)(MfUltralightPollerEvent event, void* context); From 0d86bbfacbf47ac0fb257c64070480965d9929c4 Mon Sep 17 00:00:00 2001 From: gornekich Date: Fri, 21 Apr 2023 00:58:26 +0400 Subject: [PATCH 034/149] nfca: rework with nfc poller buffer --- lib/nfc/protocols/nfca_poller.c | 75 +++++++++++++++++++++------------ 1 file changed, 48 insertions(+), 27 deletions(-) diff --git a/lib/nfc/protocols/nfca_poller.c b/lib/nfc/protocols/nfca_poller.c index c73233d3eb14..23ec959ee044 100644 --- a/lib/nfc/protocols/nfca_poller.c +++ b/lib/nfc/protocols/nfca_poller.c @@ -1,6 +1,8 @@ #include "nfca_poller.h" #include "nfca.h" +#include + #include #include @@ -8,7 +10,7 @@ #define NFCA_POLLER_FLAG_COMMAND_COMPLETE (1UL << 0) -#define NFCA_POLLER_MAX_TX_BUFFER_SIZE (512U) +#define NFCA_POLLER_MAX_BUFFER_SIZE (512U) #define NFCA_POLLER_SEL_CMD(cascade_lvl) (0x93 + 2 * (cascade_lvl)) #define NFCA_POLLER_SEL_PAR(bytes, bits) (((bytes) << 4 & 0xf0U) | ((bits)&0x0fU)) @@ -44,6 +46,7 @@ struct NfcaPoller { NfcaPollerState state; NfcaPollerColRes col_res; NfcaData* data; + NfcPollerBuffer* buff; NfcaPollerEventCallback callback; void* context; }; @@ -79,46 +82,51 @@ static NfcaError nfca_poller_standart_frame_exchange( furi_assert(rx_data); furi_assert(rx_bits); furi_assert(tx_bits >= 8); + furi_assert(instance->buff); + NfcPollerBuffer* buff = instance->buff; uint16_t tx_bytes = tx_bits / 8; - furi_assert(tx_bytes <= NFCA_POLLER_MAX_TX_BUFFER_SIZE - 2); - uint16_t rx_buff_bits = 0; - uint8_t rx_buff[NFCA_POLLER_MAX_TX_BUFFER_SIZE] = {}; - uint8_t tx_buff[NFCA_POLLER_MAX_TX_BUFFER_SIZE] = {}; + furi_assert(tx_bytes <= buff->tx_data_size - 2); - memcpy(tx_buff, tx_data, tx_bytes); - nfca_append_crc(tx_buff, tx_bytes); + memcpy(buff->tx_data, tx_data, tx_bytes); + nfca_append_crc(buff->tx_data, tx_bytes); NfcaError ret = NfcaErrorNone; do { NfcError error = nfc_trx( - instance->nfc, tx_buff, tx_bits + 16, rx_buff, sizeof(rx_buff), &rx_buff_bits, fwt); + instance->nfc, + buff->tx_data, + tx_bits + 16, + buff->rx_data, + buff->rx_data_size, + &buff->rx_bits, + fwt); if(error != NfcErrorNone) { ret = nfca_poller_process_error(error); break; } - if(rx_buff_bits < 8) { - rx_data[0] = rx_buff[0]; - *rx_bits = rx_buff_bits; + if(buff->rx_bits < 8) { + rx_data[0] = buff->rx_data[0]; + *rx_bits = buff->rx_bits; ret = NfcaErrorWrongCrc; break; - } else if(rx_buff_bits < 3 * 8) { - uint16_t rx_bytes = rx_buff_bits / 8; - memcpy(rx_data, rx_buff, rx_bytes); - *rx_bits = rx_buff_bits; + } else if(buff->rx_bits < 3 * 8) { + uint16_t rx_bytes = buff->rx_bits / 8; + memcpy(rx_data, buff->rx_data, rx_bytes); + *rx_bits = buff->rx_bits; ret = NfcaErrorWrongCrc; break; } else { - uint16_t rx_bytes = rx_buff_bits / 8; + uint16_t rx_bytes = buff->rx_bits / 8; if(rx_bytes - 2 > rx_data_size) { ret = NfcaErrorBufferOverflow; break; } - if(!nfca_check_crc(rx_buff, rx_bytes)) { + if(!nfca_check_crc(buff->rx_data, rx_bytes)) { ret = NfcaErrorWrongCrc; break; } - memcpy(rx_data, rx_buff, rx_bytes - 2); + memcpy(rx_data, buff->rx_data, rx_bytes - 2); *rx_bits = (rx_bytes - 2) * 8; } } while(false); @@ -190,6 +198,8 @@ NfcaError instance->context = context; instance->data = malloc(sizeof(NfcaData)); + instance->buff = + nfc_poller_buffer_alloc(NFCA_POLLER_MAX_BUFFER_SIZE, NFCA_POLLER_MAX_BUFFER_SIZE); nfc_config(instance->nfc, NfcModeNfcaPoller); nfc_set_guard_time_us(instance->nfc, NFCA_GUARD_TIME_US); nfc_set_fdt_poll_fc(instance->nfc, NFCA_FDT_POLL_FC); @@ -222,11 +232,12 @@ NfcaError nfca_poller_reset(NfcaPoller* instance) { instance->state = NfcaPollerStateIdle; free(instance->data); instance->data = NULL; + free(instance->buff); + instance->buff = NULL; return NfcaErrorNone; } - NfcaError nfca_poller_check_presence(NfcaPoller* instance) { furi_assert(instance); furi_assert(instance->nfc); @@ -258,13 +269,21 @@ NfcaError nfca_poller_check_presence(NfcaPoller* instance) { NfcaError nfca_poller_halt(NfcaPoller* instance) { furi_assert(instance); furi_assert(instance->nfc); - - uint8_t tx_data[2] = {0x50, 0x00}; - uint16_t tx_bits = 16; - // Rework - uint8_t rx_data[2] = {}; - uint16_t rx_bits = 0; - nfca_poller_standart_frame_exchange(instance, tx_data, tx_bits, rx_data, 2, &rx_bits, 1000); + furi_assert(instance->buff); + + NfcPollerBuffer* buff = instance->buff; + buff->tx_data[0] = 0x50; + buff->tx_data[1] = 0x00; + buff->tx_bits = 16; + + nfca_poller_standart_frame_exchange( + instance, + buff->tx_data, + buff->tx_bits, + buff->rx_data, + buff->rx_data_size, + &buff->rx_bits, + NFCA_FDT_LISTEN_FC); instance->state = NfcaPollerStateIdle; return NfcaErrorNone; } @@ -307,7 +326,9 @@ NfcaError nfca_poller_activate(NfcaPoller* instance, NfcaData* nfca_data) { break; } memcpy( - instance->data->atqa, &instance->col_res.sens_resp, sizeof(instance->col_res.sel_resp)); + instance->data->atqa, + &instance->col_res.sens_resp, + sizeof(instance->col_res.sel_resp)); instance->state = NfcaPollerColResInProgress; instance->col_res.cascade_level = 0; From 147c875127c72b2cfd855c02ec17259eb2ced241 Mon Sep 17 00:00:00 2001 From: gornekich Date: Fri, 21 Apr 2023 01:24:38 +0400 Subject: [PATCH 035/149] nfc: rework configuration --- firmware/targets/f7/api_symbols.csv | 3 +- firmware/targets/f7/furi_hal/f_hal_nfc.c | 12 +++++ firmware/targets/furi_hal_include/f_hal_nfc.h | 2 +- lib/nfc/nfc.c | 44 ++++++++++++------- lib/nfc/nfc.h | 5 +++ lib/nfc/protocols/nfca_poller.c | 11 ++--- 6 files changed, 55 insertions(+), 22 deletions(-) diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index b9ccf92d2442..4bba65317536 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,+,20.5,, +Version,+,20.6,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -829,6 +829,7 @@ Function,-,f_hal_nfc_poller_field_on,FHalNfcError, Function,-,f_hal_nfc_poller_rx,FHalNfcError,"uint8_t*, uint16_t, uint16_t*" Function,-,f_hal_nfc_poller_tx,FHalNfcError,"uint8_t*, uint16_t" Function,-,f_hal_nfc_release,FHalNfcError, +Function,-,f_hal_nfc_reset_mode,FHalNfcError, Function,-,f_hal_nfc_set_mask_receive_timer,void,uint32_t Function,-,f_hal_nfc_set_mode,FHalNfcError,"FHalNfcMode, FHalNfcBitrate" Function,-,f_hal_nfc_timer_block_tx_is_running,_Bool, diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc.c b/firmware/targets/f7/furi_hal/f_hal_nfc.c index c849d3c3c87b..065a911911a4 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfc.c +++ b/firmware/targets/f7/furi_hal/f_hal_nfc.c @@ -363,6 +363,18 @@ FHalNfcError f_hal_nfc_set_mode(FHalNfcMode mode, FHalNfcBitrate bitrate) { return error; } +FHalNfcError f_hal_nfc_reset_mode() { + FHalNfcError error = FHalNfcErrorNone; + FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; + furi_hal_spi_acquire(handle); + + st25r3916_direct_cmd(handle, ST25R3916_CMD_STOP); + + furi_hal_spi_release(handle); + + return error; +} + FHalNfcError f_hal_nfc_poller_field_on() { FHalNfcError error = FHalNfcErrorNone; FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; diff --git a/firmware/targets/furi_hal_include/f_hal_nfc.h b/firmware/targets/furi_hal_include/f_hal_nfc.h index 1a748c064b28..3ac581726995 100644 --- a/firmware/targets/furi_hal_include/f_hal_nfc.h +++ b/firmware/targets/furi_hal_include/f_hal_nfc.h @@ -95,7 +95,7 @@ FHalNfcError f_hal_nfc_low_power_mode_stop(); */ FHalNfcError f_hal_nfc_set_mode(FHalNfcMode mode, FHalNfcBitrate bitrate); -// FHalNfcError f_hal_nfc_poller_configure +FHalNfcError f_hal_nfc_reset_mode(); /** * @brief Turn on field in poller mode diff --git a/lib/nfc/nfc.c b/lib/nfc/nfc.c index 098c93271502..54425edf46d2 100644 --- a/lib/nfc/nfc.c +++ b/lib/nfc/nfc.c @@ -12,12 +12,10 @@ typedef enum { NfcStateConfigured, NfcStateFieldOn, NfcStateFieldOff, - NfcStateListenStarted, NfcStatePollerReady, NfcStatePollerReset, NfcStateStopRequested, - NfcStateStopped, } NfcState; typedef enum { @@ -114,9 +112,21 @@ static int32_t nfc_worker_poller(void* context) { Nfc* instance = context; furi_assert(instance->state == NfcStateConfigured); furi_assert(instance->callback); + instance->state = NfcStateIdle; + NfcEvent nfc_event = {}; while(true) { - if(instance->state == NfcStateConfigured) { + if(instance->state == NfcStateIdle) { + f_hal_nfc_low_power_mode_stop(); + instance->state = NfcStateChipActive; + } else if(instance->state == NfcStateChipSleep) { + f_hal_nfc_low_power_mode_stop(); + instance->state = NfcStateChipActive; + } else if(instance->state == NfcStateChipActive) { + nfc_event.type = NfcEventTypeConfigureRequest; + instance->callback(nfc_event, instance->context); + instance->state = NfcStateConfigured; + } else if(instance->state == NfcStateConfigured) { f_hal_nfc_poller_field_on(); instance->state = NfcStateFieldOn; if(instance->guard_time_us) { @@ -125,16 +135,19 @@ static int32_t nfc_worker_poller(void* context) { furi_assert(event & FHalNfcEventTimerBlockTxExpired); } instance->state = NfcStatePollerReady; - } - if(instance->state == NfcStatePollerReady) { + } else if(instance->state == NfcStatePollerReady) { NfcEvent event = {.type = NfcEventTypePollerReady}; instance->callback(event, instance->context); - } - if(instance->state == NfcStateStopRequested) { + } else if(instance->state == NfcStatePollerReset) { + nfc_config(instance, NfcModeIdle); + f_hal_nfc_low_power_mode_start(); + instance->state = NfcStateChipSleep; + } else if(instance->state == NfcStateStopRequested) { break; } } - instance->state = NfcStateStopped; + f_hal_nfc_low_power_mode_start(); + instance->state = NfcStateChipSleep; return 0; } @@ -144,8 +157,6 @@ Nfc* nfc_alloc() { Nfc* instance = malloc(sizeof(Nfc)); instance->state = NfcStateIdle; - f_hal_nfc_low_power_mode_stop(); - instance->state = NfcStateChipActive; instance->worker_thread = furi_thread_alloc(); furi_thread_set_name(instance->worker_thread, "NfcWorker"); @@ -174,14 +185,14 @@ void nfc_free(Nfc* instance) { void nfc_config(Nfc* instance, NfcMode mode) { furi_assert(instance); - if(mode == NfcModeNfcaPoller) { + if(mode == NfcModeIdle) { + f_hal_nfc_reset_mode(); + } else if(mode == NfcModeNfcaPoller) { f_hal_nfc_set_mode(FHalNfcModeNfcaPoller, FHalNfcBitrate106); instance->mode = NfcGenericModePoller; - instance->state = NfcStateConfigured; } else if(mode == NfcModeNfcaListener) { instance->mode = NfcGenericModeListener; f_hal_nfc_set_mode(FHalNfcModeNfcaListener, FHalNfcBitrate106); - instance->state = NfcStateConfigured; } } @@ -192,7 +203,6 @@ NfcError nfc_listener_set_col_res_data( uint8_t* atqa, uint8_t sak) { furi_assert(instance); - furi_assert(instance->state == NfcStateConfigured); FHalNfcError error = furi_hal_nfca_set_col_res_data(uid, uid_len, atqa, sak); instance->comm_state = NfcCommStateIdle; @@ -226,7 +236,6 @@ void nfc_set_mask_receive_time_fc(Nfc* instance, uint32_t mask_rx_time_fc) { void nfc_start_worker(Nfc* instance, NfcEventCallback callback, void* context) { furi_assert(instance); - furi_assert(instance->state == NfcStateConfigured); furi_assert(instance->worker_thread); furi_assert(callback); @@ -259,6 +268,11 @@ void nfc_poller_stop(Nfc* instance) { instance->state = NfcStateStopRequested; } +void nfc_poller_reset(Nfc* instance) { + furi_assert(instance); + instance->state = NfcStatePollerReset; +} + NfcError nfc_listener_sleep(Nfc* instance) { furi_assert(instance); furi_assert(instance->state == NfcStateListenStarted); diff --git a/lib/nfc/nfc.h b/lib/nfc/nfc.h index f61c6c981eb3..15acde31ae96 100644 --- a/lib/nfc/nfc.h +++ b/lib/nfc/nfc.h @@ -17,6 +17,8 @@ typedef enum { NfcEventTypeRxStart, NfcEventTypeRxEnd, + NfcEventTypeConfigureRequest, + NfcEventTypeListenerActivated, NfcEventTypePollerReady, } NfcEventType; @@ -34,6 +36,7 @@ typedef struct { typedef void (*NfcEventCallback)(NfcEvent event, void* context); typedef enum { + NfcModeIdle, NfcModeNfcaPoller, NfcModeNfcaListener, NfcModeNfcbPoller, @@ -94,6 +97,8 @@ void nfc_listener_abort(Nfc* instance); void nfc_poller_stop(Nfc* instance); +void nfc_poller_reset(Nfc* instance); + NfcError nfc_listener_tx(Nfc* instance, uint8_t* tx_data, uint16_t tx_bits); NfcError nfc_trx( diff --git a/lib/nfc/protocols/nfca_poller.c b/lib/nfc/protocols/nfca_poller.c index 23ec959ee044..07352c119ee7 100644 --- a/lib/nfc/protocols/nfca_poller.c +++ b/lib/nfc/protocols/nfca_poller.c @@ -168,7 +168,12 @@ static void nfca_poller_event_callback(NfcEvent event, void* context) { furi_assert(instance->callback); NfcaPollerEvent nfca_poller_event = {}; - if(event.type == NfcEventTypePollerReady) { + if(event.type == NfcEventTypeConfigureRequest) { + nfc_config(instance->nfc, NfcModeNfcaPoller); + nfc_set_guard_time_us(instance->nfc, NFCA_GUARD_TIME_US); + nfc_set_fdt_poll_fc(instance->nfc, NFCA_FDT_POLL_FC); + nfc_set_fdt_poll_poll_us(instance->nfc, NFCA_POLL_POLL_MIN_US); + } else if(event.type == NfcEventTypePollerReady) { if(instance->state != NfcaPollerActivated) { NfcaData data = {}; NfcaError error = nfca_poller_activate(instance, &data); @@ -200,10 +205,6 @@ NfcaError instance->data = malloc(sizeof(NfcaData)); instance->buff = nfc_poller_buffer_alloc(NFCA_POLLER_MAX_BUFFER_SIZE, NFCA_POLLER_MAX_BUFFER_SIZE); - nfc_config(instance->nfc, NfcModeNfcaPoller); - nfc_set_guard_time_us(instance->nfc, NFCA_GUARD_TIME_US); - nfc_set_fdt_poll_fc(instance->nfc, NFCA_FDT_POLL_FC); - nfc_set_fdt_poll_poll_us(instance->nfc, NFCA_POLL_POLL_MIN_US); nfc_start_worker(instance->nfc, nfca_poller_event_callback, instance); From 40109bc24337c8b9dcc1b7eaa09c30960092cce7 Mon Sep 17 00:00:00 2001 From: gornekich Date: Fri, 21 Apr 2023 13:27:04 +0400 Subject: [PATCH 036/149] nfc: introduce nfcb poller --- lib/nfc/nfc_poller.c | 1 + lib/nfc/nfc_poller.h | 11 ++++ lib/nfc/protocols/nfcb.h | 28 ++++++++++ lib/nfc/protocols/nfcb_poller.c | 95 +++++++++++++++++++++++++++++++++ lib/nfc/protocols/nfcb_poller.h | 43 +++++++++++++++ 5 files changed, 178 insertions(+) create mode 100644 lib/nfc/protocols/nfcb.h create mode 100644 lib/nfc/protocols/nfcb_poller.c create mode 100644 lib/nfc/protocols/nfcb_poller.h diff --git a/lib/nfc/nfc_poller.c b/lib/nfc/nfc_poller.c index c5c208febae6..ffbd0da29425 100644 --- a/lib/nfc/nfc_poller.c +++ b/lib/nfc/nfc_poller.c @@ -37,4 +37,5 @@ void nfc_poller_start(NfcPoller* instance, NfcPollerEventCallback callback, void instance->callback = callback; instance->context = context; + } diff --git a/lib/nfc/nfc_poller.h b/lib/nfc/nfc_poller.h index b1e981105cc1..d79020155870 100644 --- a/lib/nfc/nfc_poller.h +++ b/lib/nfc/nfc_poller.h @@ -4,13 +4,24 @@ extern "C" { #endif +#include "protocols/nfca_poller.h" +#include "protocols/nfcb_poller.h" +#include "protocols/mf_ultralight.h" + typedef struct NfcPoller NfcPoller; +typedef struct { + Nfc* nfc; + NfcaPoller* nfca_poller; +} NfcPollerCollection; + typedef enum { NfcPollerEventNfcaDetected, NfcPollerEventNfcbDetected, NfcPollerEventNfcfDetected, NfcPollerEventNfcvDetected, + NfcPollerEventMfUltralightDetected, + NfcPollerEventMfClassicDetected, } NfcPollerEvent; typedef void (*NfcPollerEventCallback)(NfcPollerEvent event, void* context); diff --git a/lib/nfc/protocols/nfcb.h b/lib/nfc/protocols/nfcb.h new file mode 100644 index 000000000000..5f10b1aac372 --- /dev/null +++ b/lib/nfc/protocols/nfcb.h @@ -0,0 +1,28 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#define NFCB_UID_MAX_SIZE (7) + +// TODO change values +#define NFCB_GUARD_TIME_US (5000) +#define NFCB_FDT_POLL_FC (1620) +#define NFCB_FDT_LISTEN_FC (1172) +#define NFCB_POLLER_MASK_RX_FS ((NFCA_FDT_LISTEN_FC) / 2) +#define NFCB_POLL_POLL_MIN_US (1100) + +typedef enum { + NfcbErrorNone, + NfcbErrorTimeout, +} NfcbError; + +typedef struct { + uint8_t uid[NFCB_UID_MAX_SIZE]; + uint16_t uid_len; +} NfcbData; + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/nfcb_poller.c b/lib/nfc/protocols/nfcb_poller.c new file mode 100644 index 000000000000..449d3a8235b9 --- /dev/null +++ b/lib/nfc/protocols/nfcb_poller.c @@ -0,0 +1,95 @@ +#include "nfcb_poller.h" +#include + +#include + +#define NFCB_POLLER_BUFER_MAX_SIZE (512) + +typedef enum { + NfcbPollerStateIdle, + NfcbPollerColResInProgress, + NfcbPollerColResFailed, + NfcbPollerActivated, +} NfcbPollerState; + +struct NfcbPoller { + Nfc* nfc; + NfcbPollerState state; + NfcbData* data; + NfcPollerBuffer* buff; + NfcbPollerEventCallback callback; + void* context; +}; + +NfcbPoller* nfcb_poller_alloc(Nfc* nfc) { + NfcbPoller* instance = malloc(sizeof(NfcbPoller)); + instance->nfc = nfc; + + return instance; +} + +void nfcb_poller_free(NfcbPoller* instance) { + furi_assert(instance); + + free(instance); +} + +static void nfcb_poller_event_callback(NfcEvent event, void* context) { + furi_assert(context); + + NfcbPoller* instance = context; + furi_assert(instance->callback); + if(event.type == NfcEventTypeConfigureRequest) { + nfc_config(instance->nfc, NfcModeNfcbPoller); + nfc_set_guard_time_us(instance->nfc, NFCB_GUARD_TIME_US); + nfc_set_fdt_poll_fc(instance->nfc, NFCB_FDT_POLL_FC); + nfc_set_fdt_poll_poll_us(instance->nfc, NFCB_POLL_POLL_MIN_US); + } +} + +NfcbError + nfcb_poller_start(NfcbPoller* instance, NfcbPollerEventCallback callback, void* context) { + furi_assert(instance); + + instance->callback = callback; + instance->context = context; + + instance->data = malloc(sizeof(NfcbData)); + instance->buff = + nfc_poller_buffer_alloc(NFCB_POLLER_BUFER_MAX_SIZE, NFCB_POLLER_BUFER_MAX_SIZE); + + nfc_start_worker(instance->nfc, nfcb_poller_event_callback, instance); + return NfcbErrorNone; +} + +NfcbError nfcb_poller_get_data(NfcbPoller* instance, NfcbData* data) { + furi_assert(instance); + furi_assert(instance->data); + + *data = *instance->data; + return NfcbErrorNone; +} + +NfcbError nfcb_poller_reset(NfcbPoller* instance) { + furi_assert(instance); + furi_assert(instance->nfc); + furi_assert(instance->data); + + nfc_poller_abort(instance->nfc); + + instance->callback = NULL; + instance->context = NULL; + free(instance->data); + instance->data = NULL; + nfc_poller_buffer_free(instance->buff); + instance->buff = NULL; + + return NfcbErrorNone; +} + +NfcbError nfcb_poller_activate(NfcbPoller* instance, NfcbData* data) { + furi_assert(instance); + furi_assert(data); + + return NfcbErrorTimeout; +} diff --git a/lib/nfc/protocols/nfcb_poller.h b/lib/nfc/protocols/nfcb_poller.h new file mode 100644 index 000000000000..0dfeb96e94ff --- /dev/null +++ b/lib/nfc/protocols/nfcb_poller.h @@ -0,0 +1,43 @@ +#pragma once + +#include +#include "nfcb.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct NfcbPoller NfcbPoller; + +typedef enum { + NfcbPollerEventTypeError, + NfcbPollerEventDetected, + NfcbPollerEventTypeReady, +} NfcbPollerEventType; + +typedef struct { + NfcbError error; +} NfcbPollerEventData; + +typedef struct { + NfcbPollerEventType type; + NfcbPollerEventData data; +} NfcbPollerEvent; + +typedef void (*NfcbPollerEventCallback)(NfcbPollerEvent* event, void* context); + +NfcbPoller* nfcb_poller_alloc(Nfc* nfc); + +void nfcb_poller_free(NfcbPoller* instance); + +NfcbError nfcb_poller_start(NfcbPoller* instance, NfcbPollerEventCallback callback, void* context); + +NfcbError nfcb_poller_get_data(NfcbPoller* instance, NfcbData* data); + +NfcbError nfcb_poller_reset(NfcbPoller* instance); + +NfcbError nfcb_poller_activate(NfcbPoller* instance, NfcbData* data); + +#ifdef __cplusplus +} +#endif From 6be1fdc252913c70732a4ac4491001f009e0a68f Mon Sep 17 00:00:00 2001 From: gornekich Date: Fri, 21 Apr 2023 17:09:12 +0400 Subject: [PATCH 037/149] nfc: generic poller rework --- applications/main/nfc/nfc_app.c | 10 +++ applications/main/nfc/nfc_app_i.h | 4 + .../nfc/scenes/nfc_scene_mf_ultralight_read.c | 2 + .../main/nfc/scenes/nfc_scene_nfca_read.c | 2 +- applications/main/nfc/scenes/nfc_scene_read.c | 34 ++++++--- .../main/nfc/scenes/nfc_scene_start.c | 20 ++--- lib/nfc/nfc.c | 2 +- lib/nfc/nfc.h | 2 +- lib/nfc/nfc_poller.c | 73 ++++++++++++++++++- lib/nfc/nfc_poller.h | 5 +- lib/nfc/protocols/mf_ultralight.c | 9 +++ lib/nfc/protocols/mf_ultralight.h | 2 + lib/nfc/protocols/mf_ultralight_poller.c | 2 +- lib/nfc/protocols/nfca_poller.c | 24 ++++-- lib/nfc/protocols/nfca_poller.h | 2 + lib/nfc/protocols/nfcb_poller.c | 16 +++- lib/nfc/protocols/nfcb_poller.h | 2 + 17 files changed, 169 insertions(+), 42 deletions(-) diff --git a/applications/main/nfc/nfc_app.c b/applications/main/nfc/nfc_app.c index b3994b1b753d..a1615392ad88 100644 --- a/applications/main/nfc/nfc_app.c +++ b/applications/main/nfc/nfc_app.c @@ -50,6 +50,14 @@ NfcApp* nfc_app_alloc() { instance->mf_ul_poller = mf_ultralight_poller_alloc(instance->nfca_poller); instance->nfca_listener = nfca_listener_alloc(instance->nfc); instance->mf_ul_listener = mf_ultralight_listener_alloc(instance->nfca_listener); + instance->nfcb_poller = nfcb_poller_alloc(instance->nfc); + + NfcPollerCollection collection = { + .nfc = instance->nfc, + .nfca_poller = instance->nfca_poller, + .nfcb_poller = instance->nfcb_poller, + }; + instance->nfc_poller = nfc_poller_alloc(&collection); instance->mf_ul_auth = mf_ultralight_auth_alloc(); @@ -130,6 +138,8 @@ void nfc_app_free(NfcApp* instance) { mf_ultralight_poller_free(instance->mf_ul_poller); nfca_listener_free(instance->nfca_listener); nfca_poller_free(instance->nfca_poller); + nfcb_poller_free(instance->nfcb_poller); + nfc_poller_free(instance->nfc_poller); nfc_free(instance->nfc); mf_ultralight_auth_free(instance->mf_ul_auth); diff --git a/applications/main/nfc/nfc_app_i.h b/applications/main/nfc/nfc_app_i.h index 821ca775f936..16696bb9b9f3 100644 --- a/applications/main/nfc/nfc_app_i.h +++ b/applications/main/nfc/nfc_app_i.h @@ -33,7 +33,9 @@ #include #include +#include #include +#include #include #include #include @@ -77,6 +79,8 @@ struct NfcApp { NfcaListener* nfca_listener; MfUltralightPoller* mf_ul_poller; MfUltralightListener* mf_ul_listener; + NfcbPoller* nfcb_poller; + NfcPoller* nfc_poller; MfUltralightAuth* mf_ul_auth; diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read.c index 19038675932c..f73839de060f 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read.c @@ -27,6 +27,8 @@ void nfc_scene_mf_ultralight_read_worker_callback(MfUltralightPollerEvent event, } } else if(nfc->mf_ul_auth->type == MfUltralightAuthTypeManual) { event.data->auth_context.skip_auth = false; + } else { + event.data->auth_context.skip_auth = true; } if(!event.data->auth_context.skip_auth) { event.data->auth_context.password = nfc->mf_ul_auth->password; diff --git a/applications/main/nfc/scenes/nfc_scene_nfca_read.c b/applications/main/nfc/scenes/nfc_scene_nfca_read.c index e18d2398fe92..5415e7cc5192 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfca_read.c +++ b/applications/main/nfc/scenes/nfc_scene_nfca_read.c @@ -2,7 +2,7 @@ #include enum { - NfcWorkerEventReadUidNfcA, + NfcWorkerEventReadUidNfcA = 100, }; void nfc_scene_nfca_read_worker_callback(NfcaPollerEvent event, void* context) { diff --git a/applications/main/nfc/scenes/nfc_scene_read.c b/applications/main/nfc/scenes/nfc_scene_read.c index a53a91fb54de..14cb93029b3e 100644 --- a/applications/main/nfc/scenes/nfc_scene_read.c +++ b/applications/main/nfc/scenes/nfc_scene_read.c @@ -2,15 +2,21 @@ #include enum { - NfcWorkerEventReadUidNfcA, + NfcSceneReadEventNfcaDetected = 100, + NfcSceneReadEventNfcbDetected, + NfcSceneReadEventMfUltralightDetected, }; -void nfc_scene_read_worker_callback(NfcaPollerEvent event, void* context) { +void nfc_scene_read_worker_callback(NfcPollerEvent event, void* context) { NfcApp* nfc = context; - if(event.type == NfcaPollerEventTypeReady) { - nfca_poller_stop(nfc->nfca_poller); - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcWorkerEventReadUidNfcA); + if(event == NfcPollerEventNfcaDetected) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcSceneReadEventNfcaDetected); + } else if(event == NfcPollerEventNfcbDetected) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcSceneReadEventNfcbDetected); + } else if(event == NfcPollerEventMfUltralightDetected) { + view_dispatcher_send_custom_event( + nfc->view_dispatcher, NfcSceneReadEventMfUltralightDetected); } } @@ -23,7 +29,7 @@ void nfc_scene_read_on_enter(void* context) { popup_set_icon(nfc->popup, 0, 8, &I_NFC_manual_60x50); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); - nfca_poller_start(nfc->nfca_poller, nfc_scene_read_worker_callback, nfc); + nfc_poller_start(nfc->nfc_poller, nfc_scene_read_worker_callback, nfc); nfc_blink_read_start(nfc); } @@ -33,11 +39,15 @@ bool nfc_scene_read_on_event(void* context, SceneManagerEvent event) { bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { - if(event.event == NfcWorkerEventReadUidNfcA) { - notification_message(nfc->notifications, &sequence_success); - nfca_poller_get_data(nfc->nfca_poller, &nfc->nfc_dev_data.nfca_data); - scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcaReadSuccess); - DOLPHIN_DEED(DolphinDeedNfcReadSuccess); + if(event.event == NfcSceneReadEventNfcaDetected) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcaRead); + consumed = true; + } else if(event.event == NfcSceneReadEventNfcbDetected) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + consumed = true; + } else if(event.event == NfcSceneReadEventMfUltralightDetected) { + mf_ultralight_auth_reset(nfc->mf_ul_auth); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightRead); consumed = true; } } @@ -47,7 +57,7 @@ bool nfc_scene_read_on_event(void* context, SceneManagerEvent event) { void nfc_scene_read_on_exit(void* context) { NfcApp* nfc = context; - nfca_poller_reset(nfc->nfca_poller); + nfc_poller_reset(nfc->nfc_poller); // Clear view popup_reset(nfc->popup); diff --git a/applications/main/nfc/scenes/nfc_scene_start.c b/applications/main/nfc/scenes/nfc_scene_start.c index 8f1aa25824d9..b72a6036765c 100644 --- a/applications/main/nfc/scenes/nfc_scene_start.c +++ b/applications/main/nfc/scenes/nfc_scene_start.c @@ -47,15 +47,7 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubmenuIndexRead) { scene_manager_set_scene_state(nfc->scene_manager, NfcSceneStart, SubmenuIndexRead); - // TEST - uint8_t uid[7] = {0x44, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06}; - uint8_t atqa[2] = {0x44, 0x00}; - nfc->nfc_dev_data.nfca_data.sak = 0x00; - nfc->nfc_dev_data.nfca_data.uid_len = 7; - memcpy(nfc->nfc_dev_data.nfca_data.uid, uid, 7); - memcpy(nfc->nfc_dev_data.nfca_data.atqa, atqa, 2); - - scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcaEmulate); + scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); DOLPHIN_DEED(DolphinDeedNfcRead); consumed = true; } else if(event.event == SubmenuIndexDetectReader) { @@ -68,7 +60,15 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) { // if the user cancels loading a file, the Saved menu item // is properly reselected. scene_manager_set_scene_state(nfc->scene_manager, NfcSceneStart, SubmenuIndexSaved); - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + // TEST + uint8_t uid[7] = {0x44, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06}; + uint8_t atqa[2] = {0x44, 0x00}; + nfc->nfc_dev_data.nfca_data.sak = 0x00; + nfc->nfc_dev_data.nfca_data.uid_len = 7; + memcpy(nfc->nfc_dev_data.nfca_data.uid, uid, 7); + memcpy(nfc->nfc_dev_data.nfca_data.atqa, atqa, 2); + + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcaEmulate); consumed = true; } else if(event.event == SubmenuIndexExtraAction) { scene_manager_set_scene_state( diff --git a/lib/nfc/nfc.c b/lib/nfc/nfc.c index 54425edf46d2..1397c557461d 100644 --- a/lib/nfc/nfc.c +++ b/lib/nfc/nfc.c @@ -268,7 +268,7 @@ void nfc_poller_stop(Nfc* instance) { instance->state = NfcStateStopRequested; } -void nfc_poller_reset(Nfc* instance) { +void nfc_reset(Nfc* instance) { furi_assert(instance); instance->state = NfcStatePollerReset; } diff --git a/lib/nfc/nfc.h b/lib/nfc/nfc.h index 15acde31ae96..df0a7544ec4f 100644 --- a/lib/nfc/nfc.h +++ b/lib/nfc/nfc.h @@ -97,7 +97,7 @@ void nfc_listener_abort(Nfc* instance); void nfc_poller_stop(Nfc* instance); -void nfc_poller_reset(Nfc* instance); +void nfc_reset(Nfc* instance); NfcError nfc_listener_tx(Nfc* instance, uint8_t* tx_data, uint16_t tx_bits); diff --git a/lib/nfc/nfc_poller.c b/lib/nfc/nfc_poller.c index ffbd0da29425..e37bb4fbd550 100644 --- a/lib/nfc/nfc_poller.c +++ b/lib/nfc/nfc_poller.c @@ -16,14 +16,26 @@ typedef enum { struct NfcPoller { Nfc* nfc; + NfcaPoller* nfca_poller; + NfcaData nfca_data; + NfcbPoller* nfcb_poller; + NfcbData nfcb_data; NfcPollerState state; NfcPollerEventCallback callback; void* context; }; -NfcPoller* nfc_poller_alloc() { +NfcPoller* nfc_poller_alloc(NfcPollerCollection* pollers) { + furi_assert(pollers); + furi_assert(pollers->nfc); + furi_assert(pollers->nfca_poller); + furi_assert(pollers->nfcb_poller); + NfcPoller* instance = malloc(sizeof(NfcPoller)); - + instance->nfc = pollers->nfc; + instance->nfca_poller = pollers->nfca_poller; + instance->nfcb_poller = pollers->nfcb_poller; + return instance; } @@ -31,11 +43,66 @@ void nfc_poller_free(NfcPoller* instance) { furi_assert(instance); } +static void nfc_poller_event_callback(NfcEvent event, void* context) { + furi_assert(context); + + NfcPoller* instance = context; + NfcPollerEvent poller_event; + if(event.type == NfcEventTypeConfigureRequest) { + if(instance->state == NfcPollerStateCheckPresenceNfca) { + nfca_poller_config(instance->nfca_poller); + } else if(instance->state == NfcPollerStateCheckPresenceNfcb) { + nfcb_poller_config(instance->nfcb_poller); + } + } else if(event.type == NfcEventTypePollerReady) { + if(instance->state == NfcPollerStateCheckPresenceNfca) { + NfcaError error = nfca_poller_activate(instance->nfca_poller, &instance->nfca_data); + if(error == NfcaErrorNone) { + if(mf_ultralight_detect_protocol(&instance->nfca_data)) { + poller_event = NfcPollerEventMfUltralightDetected; + } else { + poller_event = NfcPollerEventNfcaDetected; + } + instance->callback(poller_event, instance->context); + } else { + // Nfca not present + furi_delay_ms(100); + nfc_reset(instance->nfc); + instance->state = NfcPollerStateCheckPresenceNfcb; + } + } else if(instance->state == NfcPollerStateCheckPresenceNfcb) { + NfcbError error = nfcb_poller_activate(instance->nfcb_poller, &instance->nfcb_data); + if(error == NfcbErrorNone) { + poller_event = NfcPollerEventNfcbDetected; + instance->callback(poller_event, instance->context); + } else { + // Nfcb not present + furi_delay_ms(100); + nfc_reset(instance->nfc); + instance->state = NfcPollerStateCheckPresenceNfca; + } + } + } +} + void nfc_poller_start(NfcPoller* instance, NfcPollerEventCallback callback, void* context) { furi_assert(instance); furi_assert(callback); instance->callback = callback; instance->context = context; - + instance->state = NfcPollerStateCheckPresenceNfca; + + nfc_start_worker(instance->nfc, nfc_poller_event_callback, instance); +} + +void nfc_poller_reset(NfcPoller* instance) { + furi_assert(instance); + furi_assert(instance->nfc); + + nfc_poller_abort(instance->nfc); + + instance->callback = NULL; + instance->context = NULL; + instance->state = NfcPollerStateIdle; } diff --git a/lib/nfc/nfc_poller.h b/lib/nfc/nfc_poller.h index d79020155870..f9aa0fc31d72 100644 --- a/lib/nfc/nfc_poller.h +++ b/lib/nfc/nfc_poller.h @@ -13,6 +13,7 @@ typedef struct NfcPoller NfcPoller; typedef struct { Nfc* nfc; NfcaPoller* nfca_poller; + NfcbPoller* nfcb_poller; } NfcPollerCollection; typedef enum { @@ -26,12 +27,14 @@ typedef enum { typedef void (*NfcPollerEventCallback)(NfcPollerEvent event, void* context); -NfcPoller* nfc_poller_alloc(); +NfcPoller* nfc_poller_alloc(NfcPollerCollection* pollers); void nfc_poller_free(NfcPoller* instance); void nfc_poller_start(NfcPoller* instance, NfcPollerEventCallback callback, void* context); +void nfc_poller_reset(NfcPoller* instance); + #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/mf_ultralight.c b/lib/nfc/protocols/mf_ultralight.c index 5362e89bb812..0fc647573071 100644 --- a/lib/nfc/protocols/mf_ultralight.c +++ b/lib/nfc/protocols/mf_ultralight.c @@ -131,6 +131,15 @@ const char* mf_ultralight_get_name(MfUltralightType type, bool full_name) { } } +bool mf_ultralight_detect_protocol(NfcaData* nfca_data) { + furi_assert(nfca_data); + + bool mfu_detected = (nfca_data->atqa[0] == 0x44) && (nfca_data->atqa[1] == 0x00) && + (nfca_data->sak == 0x00); + + return mfu_detected; +} + bool mf_ultralight_is_all_data_read(MfUltralightData* data) { furi_assert(data); // TODO add logic diff --git a/lib/nfc/protocols/mf_ultralight.h b/lib/nfc/protocols/mf_ultralight.h index 394013e5217a..c5c88946c81d 100644 --- a/lib/nfc/protocols/mf_ultralight.h +++ b/lib/nfc/protocols/mf_ultralight.h @@ -127,6 +127,8 @@ const char* mf_ultralight_get_name(MfUltralightType type, bool full_name); bool mf_ultralight_is_all_data_read(MfUltralightData* data); +bool mf_ultralight_detect_protocol(NfcaData* nfca_data); + #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/mf_ultralight_poller.c b/lib/nfc/protocols/mf_ultralight_poller.c index 81b8425f05a9..ec9d10241040 100644 --- a/lib/nfc/protocols/mf_ultralight_poller.c +++ b/lib/nfc/protocols/mf_ultralight_poller.c @@ -9,7 +9,7 @@ #define MF_ULTRALIGHT_MAX_BUFF_SIZE (64) -#define MF_ULTRALIGHT_POLLER_STANDART_FWT_FC (120000) +#define MF_ULTRALIGHT_POLLER_STANDART_FWT_FC (12500) #define MF_ULTRALIGHT_POLLER_COMPLETE_EVENT (1UL << 0) diff --git a/lib/nfc/protocols/nfca_poller.c b/lib/nfc/protocols/nfca_poller.c index 07352c119ee7..17669a2d7b82 100644 --- a/lib/nfc/protocols/nfca_poller.c +++ b/lib/nfc/protocols/nfca_poller.c @@ -169,10 +169,7 @@ static void nfca_poller_event_callback(NfcEvent event, void* context) { NfcaPollerEvent nfca_poller_event = {}; if(event.type == NfcEventTypeConfigureRequest) { - nfc_config(instance->nfc, NfcModeNfcaPoller); - nfc_set_guard_time_us(instance->nfc, NFCA_GUARD_TIME_US); - nfc_set_fdt_poll_fc(instance->nfc, NFCA_FDT_POLL_FC); - nfc_set_fdt_poll_poll_us(instance->nfc, NFCA_POLL_POLL_MIN_US); + nfca_poller_config(instance); } else if(event.type == NfcEventTypePollerReady) { if(instance->state != NfcaPollerActivated) { NfcaData data = {}; @@ -202,10 +199,6 @@ NfcaError instance->callback = callback; instance->context = context; - instance->data = malloc(sizeof(NfcaData)); - instance->buff = - nfc_poller_buffer_alloc(NFCA_POLLER_MAX_BUFFER_SIZE, NFCA_POLLER_MAX_BUFFER_SIZE); - nfc_start_worker(instance->nfc, nfca_poller_event_callback, instance); return NfcaErrorNone; @@ -221,6 +214,21 @@ NfcaError nfca_poller_get_data(NfcaPoller* instance, NfcaData* data) { return NfcaErrorNone; } +NfcaError nfca_poller_config(NfcaPoller* instance) { + furi_assert(instance); + + instance->data = malloc(sizeof(NfcaData)); + instance->buff = + nfc_poller_buffer_alloc(NFCA_POLLER_MAX_BUFFER_SIZE, NFCA_POLLER_MAX_BUFFER_SIZE); + + nfc_config(instance->nfc, NfcModeNfcaPoller); + nfc_set_guard_time_us(instance->nfc, NFCA_GUARD_TIME_US); + nfc_set_fdt_poll_fc(instance->nfc, NFCA_FDT_POLL_FC); + nfc_set_fdt_poll_poll_us(instance->nfc, NFCA_POLL_POLL_MIN_US); + + return NfcaErrorNone; +} + NfcaError nfca_poller_reset(NfcaPoller* instance) { furi_assert(instance); furi_assert(instance->data); diff --git a/lib/nfc/protocols/nfca_poller.h b/lib/nfc/protocols/nfca_poller.h index 7cd83db243bf..ac08861601b6 100644 --- a/lib/nfc/protocols/nfca_poller.h +++ b/lib/nfc/protocols/nfca_poller.h @@ -43,6 +43,8 @@ NfcaError nfca_poller_stop(NfcaPoller* instance); NfcaError nfca_poller_check_presence(NfcaPoller* instance); +NfcaError nfca_poller_config(NfcaPoller* instance); + NfcaError nfca_poller_activate(NfcaPoller* instance, NfcaData* nfca_data); NfcaError nfca_poller_halt(NfcaPoller* instance); diff --git a/lib/nfc/protocols/nfcb_poller.c b/lib/nfc/protocols/nfcb_poller.c index 449d3a8235b9..3ec834489892 100644 --- a/lib/nfc/protocols/nfcb_poller.c +++ b/lib/nfc/protocols/nfcb_poller.c @@ -40,10 +40,7 @@ static void nfcb_poller_event_callback(NfcEvent event, void* context) { NfcbPoller* instance = context; furi_assert(instance->callback); if(event.type == NfcEventTypeConfigureRequest) { - nfc_config(instance->nfc, NfcModeNfcbPoller); - nfc_set_guard_time_us(instance->nfc, NFCB_GUARD_TIME_US); - nfc_set_fdt_poll_fc(instance->nfc, NFCB_FDT_POLL_FC); - nfc_set_fdt_poll_poll_us(instance->nfc, NFCB_POLL_POLL_MIN_US); + nfcb_poller_config(instance); } } @@ -87,6 +84,17 @@ NfcbError nfcb_poller_reset(NfcbPoller* instance) { return NfcbErrorNone; } +NfcbError nfcb_poller_config(NfcbPoller* instance) { + furi_assert(instance); + + nfc_config(instance->nfc, NfcModeNfcbPoller); + nfc_set_guard_time_us(instance->nfc, NFCB_GUARD_TIME_US); + nfc_set_fdt_poll_fc(instance->nfc, NFCB_FDT_POLL_FC); + nfc_set_fdt_poll_poll_us(instance->nfc, NFCB_POLL_POLL_MIN_US); + + return NfcbErrorNone; +} + NfcbError nfcb_poller_activate(NfcbPoller* instance, NfcbData* data) { furi_assert(instance); furi_assert(data); diff --git a/lib/nfc/protocols/nfcb_poller.h b/lib/nfc/protocols/nfcb_poller.h index 0dfeb96e94ff..d1fa9a269a35 100644 --- a/lib/nfc/protocols/nfcb_poller.h +++ b/lib/nfc/protocols/nfcb_poller.h @@ -36,6 +36,8 @@ NfcbError nfcb_poller_get_data(NfcbPoller* instance, NfcbData* data); NfcbError nfcb_poller_reset(NfcbPoller* instance); +NfcbError nfcb_poller_config(NfcbPoller* instance); + NfcbError nfcb_poller_activate(NfcbPoller* instance, NfcbData* data); #ifdef __cplusplus From e29d778327689b7606036eb57e90dda25184811b Mon Sep 17 00:00:00 2001 From: gornekich Date: Sun, 23 Apr 2023 14:29:17 +0400 Subject: [PATCH 038/149] hal nfc: config timer div --- .../targets/f7/furi_hal/f_hal_nfc_timer.c | 27 +++++++++++-------- lib/nfc/nfc.h | 5 ++++ lib/nfc/protocols/nfca_poller.c | 7 +++-- 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc_timer.c b/firmware/targets/f7/furi_hal/f_hal_nfc_timer.c index 114395dc3635..15190c0d9c55 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfc_timer.c +++ b/firmware/targets/f7/furi_hal/f_hal_nfc_timer.c @@ -15,6 +15,7 @@ typedef enum { typedef struct { TIM_TypeDef* timer; + uint32_t timer_div; uint32_t freq_khz; FHalNfcEventInternalType event; FuriHalInterruptId irq_id; @@ -28,21 +29,25 @@ static FHalNfcTimerConfig f_hal_nfc_timers[FHalNfcTimerCount] = { { .pin = &gpio_ext_pa7, .timer = TIM1, - .freq_khz = 64000U, + .timer_div = LL_TIM_CLOCKDIVISION_DIV2, + .freq_khz = 32000U, .event = FHalNfcEventInternalTypeTimerFwtExpired, .irq_id = FuriHalInterruptIdTim1UpTim16, .irq_type = TIM1_UP_TIM16_IRQn, .is_configured = false, }, - [FHalNfcTimerBlockTx] = { - .pin = &gpio_ext_pa6, - .timer = TIM2, - .freq_khz = 64000U, - .event = FHalNfcEventInternalTypeTimerBlockTxExpired, - .irq_id = FuriHalInterruptIdTIM2, - .irq_type = TIM2_IRQn, - .is_configured = false, - }}; + [FHalNfcTimerBlockTx] = + { + .pin = &gpio_ext_pa6, + .timer = TIM2, + .timer_div = LL_TIM_CLOCKDIVISION_DIV1, + .freq_khz = 64000U, + .event = FHalNfcEventInternalTypeTimerBlockTxExpired, + .irq_id = FuriHalInterruptIdTIM2, + .irq_type = TIM2_IRQn, + .is_configured = false, + }, +}; static void f_hal_nfc_timer_irq_callback(void* context) { FHalNfcTimerConfig* timer = context; @@ -58,7 +63,7 @@ static void f_hal_nfc_timer_init(FHalNfcTimer timer) { LL_TIM_EnableUpdateEvent(f_hal_nfc_timers[timer].timer); LL_TIM_SetOnePulseMode(f_hal_nfc_timers[timer].timer, LL_TIM_ONEPULSEMODE_SINGLE); LL_TIM_SetCounterMode(f_hal_nfc_timers[timer].timer, LL_TIM_COUNTERMODE_UP); - LL_TIM_SetClockDivision(f_hal_nfc_timers[timer].timer, LL_TIM_CLOCKDIVISION_DIV1); + LL_TIM_SetClockDivision(f_hal_nfc_timers[timer].timer, f_hal_nfc_timers[timer].timer_div); LL_TIM_SetClockSource(f_hal_nfc_timers[timer].timer, LL_TIM_CLOCKSOURCE_INTERNAL); LL_TIM_EnableIT_UPDATE(f_hal_nfc_timers[timer].timer); diff --git a/lib/nfc/nfc.h b/lib/nfc/nfc.h index df0a7544ec4f..27261941fa27 100644 --- a/lib/nfc/nfc.h +++ b/lib/nfc/nfc.h @@ -33,6 +33,11 @@ typedef struct { NfcEventData data; } NfcEvent; +typedef enum { + NfcCommandContinue, + NfcCommandAbort, +} NfcCommand; + typedef void (*NfcEventCallback)(NfcEvent event, void* context); typedef enum { diff --git a/lib/nfc/protocols/nfca_poller.c b/lib/nfc/protocols/nfca_poller.c index 17669a2d7b82..4a12d1055529 100644 --- a/lib/nfc/protocols/nfca_poller.c +++ b/lib/nfc/protocols/nfca_poller.c @@ -177,11 +177,14 @@ static void nfca_poller_event_callback(NfcEvent event, void* context) { if(error == NfcaErrorNone) { nfca_poller_event.type = NfcaPollerEventTypeReady; instance->state = NfcaPollerActivated; + nfca_poller_event.data.error = error; + instance->callback(nfca_poller_event, instance->context); } else { nfca_poller_event.type = NfcaPollerEventTypeError; + nfca_poller_event.data.error = error; + instance->callback(nfca_poller_event, instance->context); + furi_delay_ms(100); } - nfca_poller_event.data.error = error; - instance->callback(nfca_poller_event, instance->context); } else { nfca_poller_event.type = NfcaPollerEventTypeReady; nfca_poller_event.data.error = NfcaErrorNone; From 6bc1f3dbf31491ca4ad8b2c25dd806f515bb4152 Mon Sep 17 00:00:00 2001 From: gornekich Date: Mon, 24 Apr 2023 19:50:45 +0400 Subject: [PATCH 039/149] nfc: introduce nfc commands --- .../nfc/scenes/nfc_scene_mf_ultralight_read.c | 13 +- .../main/nfc/scenes/nfc_scene_nfca_emulate.c | 4 +- .../main/nfc/scenes/nfc_scene_nfca_read.c | 14 +- applications/main/nfc/scenes/nfc_scene_read.c | 2 +- applications/main/nfc_rpc/nfc_rpc_nfca.c | 2 +- .../targets/f7/furi_hal/f_hal_nfc_timer.c | 10 +- firmware/targets/furi_hal_include/f_hal_nfc.h | 2 +- lib/nfc/nfc.c | 44 ++- lib/nfc/nfc.h | 11 +- lib/nfc/nfc_poller.c | 87 ++++-- lib/nfc/nfc_poller.h | 2 +- lib/nfc/protocols/mf_ultralight_listener.c | 14 +- lib/nfc/protocols/mf_ultralight_listener.h | 10 +- lib/nfc/protocols/mf_ultralight_poller.c | 282 ++++++++++-------- lib/nfc/protocols/mf_ultralight_poller.h | 12 +- lib/nfc/protocols/nfca_listener.c | 7 +- lib/nfc/protocols/nfca_listener.h | 7 +- lib/nfc/protocols/nfca_poller.c | 110 ++++--- lib/nfc/protocols/nfca_poller.h | 30 +- lib/nfc/protocols/nfcb_poller.c | 14 +- lib/nfc/protocols/nfcb_poller.h | 8 +- 21 files changed, 418 insertions(+), 267 deletions(-) diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read.c index f73839de060f..9e4abed520dd 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read.c @@ -5,13 +5,16 @@ enum { NfcWorkerEventMfUltralightReadSuccess, }; -void nfc_scene_mf_ultralight_read_worker_callback(MfUltralightPollerEvent event, void* context) { +MfUltralightPollerCommand + nfc_scene_mf_ultralight_read_worker_callback(MfUltralightPollerEvent event, void* context) { NfcApp* nfc = context; + MfUltralightPollerCommand command = MfUltralightPollerCommandContinue; + if(event.type == MfUltralightPollerEventTypeReadSuccess) { - mf_ultralight_poller_stop(nfc->mf_ul_poller); view_dispatcher_send_custom_event( nfc->view_dispatcher, NfcWorkerEventMfUltralightReadSuccess); + command = MfUltralightPollerCommandStop; } else if(event.type == MfUltralightPollerEventTypeAuthRequest) { MfUltralightData* data = &nfc->nfc_dev_data.mf_ul_data; mf_ultralight_poller_get_data(nfc->mf_ul_poller, data); @@ -35,9 +38,9 @@ void nfc_scene_mf_ultralight_read_worker_callback(MfUltralightPollerEvent event, } } else if(event.type == MfUltralightPollerEventTypeAuthSuccess) { nfc->mf_ul_auth->pack = event.data->pack; - } else { - furi_delay_ms(100); } + + return command; } void nfc_scene_mf_ultralight_read_on_enter(void* context) { @@ -71,7 +74,7 @@ bool nfc_scene_mf_ultralight_read_on_event(void* context, SceneManagerEvent even void nfc_scene_mf_ultralight_read_on_exit(void* context) { NfcApp* nfc = context; - mf_ultralight_poller_reset(nfc->mf_ul_poller); + mf_ultralight_poller_stop(nfc->mf_ul_poller); // Clear view popup_reset(nfc->popup); diff --git a/applications/main/nfc/scenes/nfc_scene_nfca_emulate.c b/applications/main/nfc/scenes/nfc_scene_nfca_emulate.c index fd674e8739d0..b01dfa881cb8 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfca_emulate.c +++ b/applications/main/nfc/scenes/nfc_scene_nfca_emulate.c @@ -7,7 +7,7 @@ enum { NfcSceneNfcaEmulateStateTextBox, }; -void nfc_scene_nfca_emulate_worker_callback(NfcaListenerEvent event, void* context) { +NfcaListenerCommand nfc_scene_nfca_emulate_worker_callback(NfcaListenerEvent event, void* context) { furi_assert(context); NfcApp* nfc = context; @@ -19,6 +19,8 @@ void nfc_scene_nfca_emulate_worker_callback(NfcaListenerEvent event, void* conte furi_string_cat_printf(nfc->text_box_store, "\n"); view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerUpdate); } + + return NfcaListenerCommandContinue; } void nfc_scene_nfca_emulate_widget_callback(GuiButtonType result, InputType type, void* context) { diff --git a/applications/main/nfc/scenes/nfc_scene_nfca_read.c b/applications/main/nfc/scenes/nfc_scene_nfca_read.c index 5415e7cc5192..2f99050286d7 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfca_read.c +++ b/applications/main/nfc/scenes/nfc_scene_nfca_read.c @@ -5,15 +5,17 @@ enum { NfcWorkerEventReadUidNfcA = 100, }; -void nfc_scene_nfca_read_worker_callback(NfcaPollerEvent event, void* context) { +NfcaPollerCommand nfc_scene_nfca_read_worker_callback(NfcaPollerEvent event, void* context) { NfcApp* nfc = context; + NfcaPollerCommand command = NfcaPollerCommandContinue; + if(event.type == NfcaPollerEventTypeReady) { - nfca_poller_stop(nfc->nfca_poller); view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcWorkerEventReadUidNfcA); - } else { - furi_delay_ms(100); + command = NfcaPollerCommandStop; } + + return command; } void nfc_scene_nfca_read_on_enter(void* context) { @@ -21,7 +23,7 @@ void nfc_scene_nfca_read_on_enter(void* context) { // Setup view view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); - + nfca_poller_start(nfc->nfca_poller, nfc_scene_nfca_read_worker_callback, nfc); nfc_blink_read_start(nfc); @@ -46,7 +48,7 @@ bool nfc_scene_nfca_read_on_event(void* context, SceneManagerEvent event) { void nfc_scene_nfca_read_on_exit(void* context) { NfcApp* nfc = context; - nfca_poller_reset(nfc->nfca_poller); + nfca_poller_stop(nfc->nfca_poller); // Clear view popup_reset(nfc->popup); diff --git a/applications/main/nfc/scenes/nfc_scene_read.c b/applications/main/nfc/scenes/nfc_scene_read.c index 14cb93029b3e..5fb17a5d9364 100644 --- a/applications/main/nfc/scenes/nfc_scene_read.c +++ b/applications/main/nfc/scenes/nfc_scene_read.c @@ -57,7 +57,7 @@ bool nfc_scene_read_on_event(void* context, SceneManagerEvent event) { void nfc_scene_read_on_exit(void* context) { NfcApp* nfc = context; - nfc_poller_reset(nfc->nfc_poller); + nfc_poller_stop(nfc->nfc_poller); // Clear view popup_reset(nfc->popup); diff --git a/applications/main/nfc_rpc/nfc_rpc_nfca.c b/applications/main/nfc_rpc/nfc_rpc_nfca.c index 42a75685588e..eb86e950aee8 100644 --- a/applications/main/nfc_rpc/nfc_rpc_nfca.c +++ b/applications/main/nfc_rpc/nfc_rpc_nfca.c @@ -49,7 +49,7 @@ static void nfc_rpc_nfca_read(Nfc_Main* cmd, void* context) { PB_Nfca_ReadResponse pb_nfca_read_resp = PB_Nfca_ReadResponse_init_default; NfcaData nfca_data = {}; - NfcaError error = nfca_poller_activate_sync(instance->nfca_poller, &nfca_data); + NfcaError error = nfca_poller_activate(instance->nfca_poller, &nfca_data); cmd->command_status = Nfc_CommandStatus_OK; cmd->which_content = Nfc_Main_nfca_read_resp_tag; diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc_timer.c b/firmware/targets/f7/furi_hal/f_hal_nfc_timer.c index 15190c0d9c55..cd47642d6d61 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfc_timer.c +++ b/firmware/targets/f7/furi_hal/f_hal_nfc_timer.c @@ -15,7 +15,7 @@ typedef enum { typedef struct { TIM_TypeDef* timer; - uint32_t timer_div; + uint32_t prescaler; uint32_t freq_khz; FHalNfcEventInternalType event; FuriHalInterruptId irq_id; @@ -29,8 +29,8 @@ static FHalNfcTimerConfig f_hal_nfc_timers[FHalNfcTimerCount] = { { .pin = &gpio_ext_pa7, .timer = TIM1, - .timer_div = LL_TIM_CLOCKDIVISION_DIV2, - .freq_khz = 32000U, + .prescaler = 7, + .freq_khz = 8000U, .event = FHalNfcEventInternalTypeTimerFwtExpired, .irq_id = FuriHalInterruptIdTim1UpTim16, .irq_type = TIM1_UP_TIM16_IRQn, @@ -40,7 +40,7 @@ static FHalNfcTimerConfig f_hal_nfc_timers[FHalNfcTimerCount] = { { .pin = &gpio_ext_pa6, .timer = TIM2, - .timer_div = LL_TIM_CLOCKDIVISION_DIV1, + .prescaler = 0, .freq_khz = 64000U, .event = FHalNfcEventInternalTypeTimerBlockTxExpired, .irq_id = FuriHalInterruptIdTIM2, @@ -63,7 +63,7 @@ static void f_hal_nfc_timer_init(FHalNfcTimer timer) { LL_TIM_EnableUpdateEvent(f_hal_nfc_timers[timer].timer); LL_TIM_SetOnePulseMode(f_hal_nfc_timers[timer].timer, LL_TIM_ONEPULSEMODE_SINGLE); LL_TIM_SetCounterMode(f_hal_nfc_timers[timer].timer, LL_TIM_COUNTERMODE_UP); - LL_TIM_SetClockDivision(f_hal_nfc_timers[timer].timer, f_hal_nfc_timers[timer].timer_div); + LL_TIM_SetPrescaler(f_hal_nfc_timers[timer].timer, f_hal_nfc_timers[timer].prescaler); LL_TIM_SetClockSource(f_hal_nfc_timers[timer].timer, LL_TIM_CLOCKSOURCE_INTERNAL); LL_TIM_EnableIT_UPDATE(f_hal_nfc_timers[timer].timer); diff --git a/firmware/targets/furi_hal_include/f_hal_nfc.h b/firmware/targets/furi_hal_include/f_hal_nfc.h index 3ac581726995..a41ab9543573 100644 --- a/firmware/targets/furi_hal_include/f_hal_nfc.h +++ b/firmware/targets/furi_hal_include/f_hal_nfc.h @@ -7,7 +7,7 @@ extern "C" { #endif -#define F_HAL_NFC_TIMER_OFFSET_FC (800) +#define F_HAL_NFC_TIMER_OFFSET_FC (500) #define F_HAL_NFC_EVENT_WAIT_FOREVER (0xFFFFFFFFU) diff --git a/lib/nfc/nfc.c b/lib/nfc/nfc.c index 1397c557461d..65a63a3471d5 100644 --- a/lib/nfc/nfc.c +++ b/lib/nfc/nfc.c @@ -15,7 +15,6 @@ typedef enum { NfcStateListenStarted, NfcStatePollerReady, NfcStatePollerReset, - NfcStateStopRequested, } NfcState; typedef enum { @@ -70,6 +69,8 @@ static int32_t nfc_worker_listener(void* context) { f_hal_nfc_listen_start(); instance->state = NfcStateListenStarted; NfcEvent nfc_event = {}; + // NfcCommand cmd = NfcCommandContinue; + while(true) { FHalNfcEvent event = f_hal_nfc_wait_event(F_HAL_NFC_EVENT_WAIT_FOREVER); if(event & FHalNfcEventAbortRequest) { @@ -115,6 +116,8 @@ static int32_t nfc_worker_poller(void* context) { instance->state = NfcStateIdle; NfcEvent nfc_event = {}; + NfcCommand cmd = NfcCommandContinue; + while(true) { if(instance->state == NfcStateIdle) { f_hal_nfc_low_power_mode_stop(); @@ -124,8 +127,14 @@ static int32_t nfc_worker_poller(void* context) { instance->state = NfcStateChipActive; } else if(instance->state == NfcStateChipActive) { nfc_event.type = NfcEventTypeConfigureRequest; - instance->callback(nfc_event, instance->context); - instance->state = NfcStateConfigured; + cmd = instance->callback(nfc_event, instance->context); + if(cmd == NfcCommandReset) { + instance->state = NfcStatePollerReset; + } else if(cmd == NfcCommandStop) { + break; + } else { + instance->state = NfcStateConfigured; + } } else if(instance->state == NfcStateConfigured) { f_hal_nfc_poller_field_on(); instance->state = NfcStateFieldOn; @@ -136,14 +145,17 @@ static int32_t nfc_worker_poller(void* context) { } instance->state = NfcStatePollerReady; } else if(instance->state == NfcStatePollerReady) { - NfcEvent event = {.type = NfcEventTypePollerReady}; - instance->callback(event, instance->context); + nfc_event.type = NfcEventTypePollerReady; + cmd = instance->callback(nfc_event, instance->context); + if(cmd == NfcCommandReset) { + instance->state = NfcStatePollerReset; + } else if(cmd == NfcCommandStop) { + break; + } } else if(instance->state == NfcStatePollerReset) { nfc_config(instance, NfcModeIdle); f_hal_nfc_low_power_mode_start(); instance->state = NfcStateChipSleep; - } else if(instance->state == NfcStateStopRequested) { - break; } } f_hal_nfc_low_power_mode_start(); @@ -173,8 +185,6 @@ void nfc_free(Nfc* instance) { if(instance->state == NfcStateListenStarted) { f_hal_nfc_abort(); furi_thread_join(instance->worker_thread); - } else if(instance->state == NfcStatePollerReady) { - nfc_poller_abort(instance); } furi_thread_free(instance->worker_thread); f_hal_nfc_low_power_mode_start(); @@ -250,27 +260,15 @@ void nfc_start_worker(Nfc* instance, NfcEventCallback callback, void* context) { instance->comm_state = NfcCommStateIdle; } -void nfc_poller_abort(Nfc* instance) { - furi_assert(instance); - // TODO add Mutex for nfc state - instance->state = NfcStateStopRequested; - furi_thread_join(instance->worker_thread); -} - void nfc_listener_abort(Nfc* instance) { furi_assert(instance); f_hal_nfc_abort(); furi_thread_join(instance->worker_thread); } -void nfc_poller_stop(Nfc* instance) { +void nfc_stop(Nfc* instance) { furi_assert(instance); - instance->state = NfcStateStopRequested; -} - -void nfc_reset(Nfc* instance) { - furi_assert(instance); - instance->state = NfcStatePollerReset; + furi_thread_join(instance->worker_thread); } NfcError nfc_listener_sleep(Nfc* instance) { diff --git a/lib/nfc/nfc.h b/lib/nfc/nfc.h index 27261941fa27..d2cab6f83425 100644 --- a/lib/nfc/nfc.h +++ b/lib/nfc/nfc.h @@ -35,10 +35,11 @@ typedef struct { typedef enum { NfcCommandContinue, - NfcCommandAbort, + NfcCommandReset, + NfcCommandStop, } NfcCommand; -typedef void (*NfcEventCallback)(NfcEvent event, void* context); +typedef NfcCommand (*NfcEventCallback)(NfcEvent event, void* context); typedef enum { NfcModeIdle, @@ -94,15 +95,11 @@ void nfc_start_worker(Nfc* instance, NfcEventCallback callback, void* context); NfcError nfc_listener_sleep(Nfc* instance); -void nfc_poller_abort(Nfc* instance); - void nfc_listener_abort(Nfc* instance); // Called from worker thread -void nfc_poller_stop(Nfc* instance); - -void nfc_reset(Nfc* instance); +void nfc_stop(Nfc* instance); NfcError nfc_listener_tx(Nfc* instance, uint8_t* tx_data, uint16_t tx_bits); diff --git a/lib/nfc/nfc_poller.c b/lib/nfc/nfc_poller.c index e37bb4fbd550..fd4ccf0a9dd8 100644 --- a/lib/nfc/nfc_poller.c +++ b/lib/nfc/nfc_poller.c @@ -14,8 +14,15 @@ typedef enum { NfcPollerStateCheckPresenceNfcv, } NfcPollerState; +typedef enum { + NfcPollerSessionStateIdle, + NfcPollerSessionStateActive, + NfcPollerSessionStateStopRequest, +} NfcPollerSessionState; + struct NfcPoller { Nfc* nfc; + NfcPollerSessionState session_state; NfcaPoller* nfca_poller; NfcaData nfca_data; NfcbPoller* nfcb_poller; @@ -43,64 +50,78 @@ void nfc_poller_free(NfcPoller* instance) { furi_assert(instance); } -static void nfc_poller_event_callback(NfcEvent event, void* context) { +static NfcCommand nfc_poller_event_callback(NfcEvent event, void* context) { furi_assert(context); NfcPoller* instance = context; NfcPollerEvent poller_event; - if(event.type == NfcEventTypeConfigureRequest) { - if(instance->state == NfcPollerStateCheckPresenceNfca) { - nfca_poller_config(instance->nfca_poller); - } else if(instance->state == NfcPollerStateCheckPresenceNfcb) { - nfcb_poller_config(instance->nfcb_poller); - } - } else if(event.type == NfcEventTypePollerReady) { - if(instance->state == NfcPollerStateCheckPresenceNfca) { - NfcaError error = nfca_poller_activate(instance->nfca_poller, &instance->nfca_data); - if(error == NfcaErrorNone) { - if(mf_ultralight_detect_protocol(&instance->nfca_data)) { - poller_event = NfcPollerEventMfUltralightDetected; + NfcCommand command = NfcCommandContinue; + + if(instance->session_state == NfcPollerSessionStateStopRequest) { + command = NfcCommandStop; + } else { + if(event.type == NfcEventTypeConfigureRequest) { + if(instance->state == NfcPollerStateCheckPresenceNfca) { + nfca_poller_config(instance->nfca_poller); + } else if(instance->state == NfcPollerStateCheckPresenceNfcb) { + nfcb_poller_config(instance->nfcb_poller); + } + } else if(event.type == NfcEventTypePollerReady) { + if(instance->state == NfcPollerStateCheckPresenceNfca) { + NfcaError error = + nfca_poller_async_activate(instance->nfca_poller, &instance->nfca_data); + if(error == NfcaErrorNone) { + if(mf_ultralight_detect_protocol(&instance->nfca_data)) { + poller_event = NfcPollerEventMfUltralightDetected; + } else { + poller_event = NfcPollerEventNfcaDetected; + } + instance->callback(poller_event, instance->context); } else { - poller_event = NfcPollerEventNfcaDetected; + // Nfca not present + furi_delay_ms(100); + instance->state = NfcPollerStateCheckPresenceNfcb; + command = NfcCommandReset; + } + } else if(instance->state == NfcPollerStateCheckPresenceNfcb) { + NfcbError error = + nfcb_poller_activate(instance->nfcb_poller, &instance->nfcb_data); + if(error == NfcbErrorNone) { + poller_event = NfcPollerEventNfcbDetected; + instance->callback(poller_event, instance->context); + } else { + // Nfcb not present + furi_delay_ms(100); + instance->state = NfcPollerStateCheckPresenceNfca; + command = NfcCommandReset; } - instance->callback(poller_event, instance->context); - } else { - // Nfca not present - furi_delay_ms(100); - nfc_reset(instance->nfc); - instance->state = NfcPollerStateCheckPresenceNfcb; - } - } else if(instance->state == NfcPollerStateCheckPresenceNfcb) { - NfcbError error = nfcb_poller_activate(instance->nfcb_poller, &instance->nfcb_data); - if(error == NfcbErrorNone) { - poller_event = NfcPollerEventNfcbDetected; - instance->callback(poller_event, instance->context); - } else { - // Nfcb not present - furi_delay_ms(100); - nfc_reset(instance->nfc); - instance->state = NfcPollerStateCheckPresenceNfca; } } } + + return command; } void nfc_poller_start(NfcPoller* instance, NfcPollerEventCallback callback, void* context) { furi_assert(instance); furi_assert(callback); + furi_assert(instance->session_state == NfcPollerSessionStateIdle); instance->callback = callback; instance->context = context; instance->state = NfcPollerStateCheckPresenceNfca; + instance->session_state = NfcPollerSessionStateActive; nfc_start_worker(instance->nfc, nfc_poller_event_callback, instance); } -void nfc_poller_reset(NfcPoller* instance) { +void nfc_poller_stop(NfcPoller* instance) { furi_assert(instance); furi_assert(instance->nfc); - nfc_poller_abort(instance->nfc); + instance->session_state = NfcPollerSessionStateStopRequest; + nfc_stop(instance->nfc); + instance->session_state = NfcPollerSessionStateIdle; instance->callback = NULL; instance->context = NULL; diff --git a/lib/nfc/nfc_poller.h b/lib/nfc/nfc_poller.h index f9aa0fc31d72..f5ee9e92d45b 100644 --- a/lib/nfc/nfc_poller.h +++ b/lib/nfc/nfc_poller.h @@ -33,7 +33,7 @@ void nfc_poller_free(NfcPoller* instance); void nfc_poller_start(NfcPoller* instance, NfcPollerEventCallback callback, void* context); -void nfc_poller_reset(NfcPoller* instance); +void nfc_poller_stop(NfcPoller* instance); #ifdef __cplusplus } diff --git a/lib/nfc/protocols/mf_ultralight_listener.c b/lib/nfc/protocols/mf_ultralight_listener.c index f0275daeae48..e8724431cd3a 100644 --- a/lib/nfc/protocols/mf_ultralight_listener.c +++ b/lib/nfc/protocols/mf_ultralight_listener.c @@ -20,7 +20,7 @@ struct MfUltralightListener { uint16_t tx_bits; uint16_t pages_total; MfUltralightFeatureSupport features; - MfUltralightListenerEventcallback callback; + MfUltralightListenerEventCallback callback; void* context; }; @@ -33,7 +33,7 @@ typedef struct { uint8_t cmd; uint16_t cmd_len_bits; MfUltralightListenerCommandCallback callback; -} MfUltralightListenerCommand; +} MfUltralightListenerCmdHandler; static MfUltralightError mf_ultralight_process_error(NfcaError error) { MfUltralightError ret = MfUltralightErrorNone; @@ -128,7 +128,7 @@ static bool mf_ultralight_listener_read_signature_handler( return command_processed; } -static const MfUltralightListenerCommand mf_ultralight_command[] = { +static const MfUltralightListenerCmdHandler mf_ultralight_command[] = { { .cmd = MF_ULTRALIGHT_CMD_READ_PAGE, .cmd_len_bits = 16, @@ -146,12 +146,14 @@ static const MfUltralightListenerCommand mf_ultralight_command[] = { }, }; -static void mf_ultralight_listener_event_handler(NfcaListenerEvent event, void* context) { +static NfcaListenerCommand mf_ultralight_listener_event_handler(NfcaListenerEvent event, void* context) { furi_assert(context); MfUltralightListener* instance = context; uint8_t* rx_data = event.data.rx_data; uint16_t rx_bits = event.data.rx_bits; + + NfcaListenerCommand command = NfcaListenerCommandContinue; if(event.type == NfcaListenerEventTypeReceivedStandartFrame) { bool cmd_processed = false; for(size_t i = 0; i < COUNT_OF(mf_ultralight_command); i++) { @@ -164,6 +166,8 @@ static void mf_ultralight_listener_event_handler(NfcaListenerEvent event, void* mf_ultralight_listener_send_short_resp(instance, MF_ULTRALIGHT_CMD_NACK); } } + + return command; } static void mf_ultralight_listener_prepare_emulation(MfUltralightListener* instance) { @@ -186,7 +190,7 @@ MfUltralightListener* mf_ultralight_listener_alloc(NfcaListener* nfca_listener) MfUltralightError mf_ultralight_listener_start( MfUltralightListener* instance, MfUltralightData* data, - MfUltralightListenerEventcallback callback, + MfUltralightListenerEventCallback callback, void* context) { furi_assert(instance); furi_assert(data); diff --git a/lib/nfc/protocols/mf_ultralight_listener.h b/lib/nfc/protocols/mf_ultralight_listener.h index 224437b08848..7321fc2b7cf6 100644 --- a/lib/nfc/protocols/mf_ultralight_listener.h +++ b/lib/nfc/protocols/mf_ultralight_listener.h @@ -24,7 +24,13 @@ typedef struct { MfUltralightListenerEventData data; } MfUltralightListenerEvent; -typedef void (*MfUltralightListenerEventcallback)(MfUltralightListenerEvent event, void* context); +typedef enum { + MfUltralightListenerCommandContinue = NfcaListenerCommandContinue, + MfUltralightListenerCommandReset = NfcaListenerCommandReset, +} MfUltralightListenerCommand; + +typedef MfUltralightListenerCommand ( + *MfUltralightListenerEventCallback)(MfUltralightListenerEvent event, void* context); MfUltralightListener* mf_ultralight_listener_alloc(NfcaListener* nfca_listener); @@ -33,7 +39,7 @@ void mf_ultralight_listener_free(MfUltralightListener* instance); MfUltralightError mf_ultralight_listener_start( MfUltralightListener* instance, MfUltralightData* data, - MfUltralightListenerEventcallback callback, + MfUltralightListenerEventCallback callback, void* context); MfUltralightError mf_ultralight_listener_reset(MfUltralightListener* instance); diff --git a/lib/nfc/protocols/mf_ultralight_poller.c b/lib/nfc/protocols/mf_ultralight_poller.c index ec9d10241040..392e2a447217 100644 --- a/lib/nfc/protocols/mf_ultralight_poller.c +++ b/lib/nfc/protocols/mf_ultralight_poller.c @@ -9,7 +9,7 @@ #define MF_ULTRALIGHT_MAX_BUFF_SIZE (64) -#define MF_ULTRALIGHT_POLLER_STANDART_FWT_FC (12500) +#define MF_ULTRALIGHT_POLLER_STANDART_FWT_FC (60000) #define MF_ULTRALIGHT_POLLER_COMPLETE_EVENT (1UL << 0) @@ -46,8 +46,15 @@ typedef enum { MfUltralightPollerStateReadSuccess, } MfUltralightPollerState; +typedef enum { + MfUltralightPollerSessionStateIdle, + MfUltralightPollerSessionStateActive, + MfUltralightPollerSessionStateStopRequest, +} MfUltralightPollerSessionState; + struct MfUltralightPoller { NfcaPoller* nfca_poller; + MfUltralightPollerSessionState session_state; MfUltralightPollerState state; NfcPollerBuffer* buffer; MfUltralightData* data; @@ -85,6 +92,22 @@ static MfUltralightError mf_ultralight_process_error(NfcaError error) { return ret; } +static NfcaPollerCommand mf_ultralight_process_command(MfUltralightPollerCommand command) { + NfcaPollerCommand ret = NfcaPollerCommandContinue; + + if(command == MfUltralightPollerCommandContinue) { + ret = NfcaPollerCommandContinue; + } else if(command == MfUltralightPollerCommandReset) { + ret = NfcaPollerCommandReset; + } else if(command == MfUltralightPollerCommandStop) { + ret = NfcaPollerCommandStop; + } else { + furi_crash("Unknown command"); + } + + return ret; +} + MfUltralightPoller* mf_ultralight_poller_alloc(NfcaPoller* nfca_poller) { MfUltralightPoller* instance = malloc(sizeof(MfUltralightPoller)); instance->nfca_poller = nfca_poller; @@ -337,132 +360,142 @@ static MfUltralightError mf_ultralight_poller_async_read_tearing_flag( return ret; } -static void mf_ultralight_poller_read_callback(NfcaPollerEvent event, void* context) { +static NfcaPollerCommand mf_ultralight_poller_read_callback(NfcaPollerEvent event, void* context) { furi_assert(context); MfUltralightPoller* instance = context; MfUltralightPollerEventData event_data = {}; MfUltralightPollerEvent mf_ul_poller_event = {.data = &event_data}; MfUltralightError error = MfUltralightErrorNone; - - if(event.type == NfcaPollerEventTypeReady) { - NfcPollerBuffer* buff = instance->buffer; - nfc_poller_buffer_reset(buff); - nfca_poller_get_data(instance->nfca_poller, &instance->data->nfca_data); - - if(instance->state == MfUltralightPollerStateReadVersion) { - error = mf_ultralight_poller_async_read_version(instance); - if(error == MfUltralightErrorNone) { - FURI_LOG_I(TAG, "Read version success"); - instance->data->type = mf_ultralight_get_type_by_version(&instance->data->version); - instance->state = MfUltralightPollerStateGetFeatureSet; - } else { - FURI_LOG_W(TAG, "Didn't response. Check NTAG 203"); - nfca_poller_halt(instance->nfca_poller); - instance->state = MfUltralightPollerStateDetectNtag203; - } - } else if(instance->state == MfUltralightPollerStateDetectNtag203) { - error = mf_ultralight_poller_async_read_page(instance, 41); - if(error == MfUltralightErrorNone) { - FURI_LOG_I(TAG, "NTAG203 detected"); - instance->data->type = MfUltralightTypeNTAG203; - instance->state = MfUltralightPollerStateGetFeatureSet; - } else { - FURI_LOG_I(TAG, "Original Ultralight detected"); - nfca_poller_halt(instance->nfca_poller); - instance->data->type = MfUltralightTypeUnknown; - instance->state = MfUltralightPollerStateGetFeatureSet; - } - } else if(instance->state == MfUltralightPollerStateGetFeatureSet) { - instance->feature_set = mf_ultralight_get_feature_support_set(instance->data->type); - instance->pages_total = mf_ultralight_get_pages_total(instance->data->type); - instance->pages_read = 0; - instance->data->pages_total = instance->pages_total; - FURI_LOG_I( - TAG, - "%s detected. Total pages: %d", - mf_ultralight_get_name(instance->data->type, true), - instance->pages_total); - if((instance->callback) && - (instance->feature_set & MfUltralightFeatureSupportAuthentication)) { - mf_ul_poller_event.type = MfUltralightPollerEventTypeAuthRequest; - instance->callback(mf_ul_poller_event, instance->context); - if(!mf_ul_poller_event.data->auth_context.skip_auth) { - instance->auth_password = mf_ul_poller_event.data->auth_context.password; - instance->state = MfUltralightPollerStateAuth; + MfUltralightPollerCommand command = MfUltralightPollerCommandContinue; + + furi_assert(instance->session_state != MfUltralightPollerSessionStateIdle); + if(instance->session_state == MfUltralightPollerSessionStateStopRequest) { + command = MfUltralightPollerCommandStop; + } else { + if(event.type == NfcaPollerEventTypeReady) { + NfcPollerBuffer* buff = instance->buffer; + nfc_poller_buffer_reset(buff); + nfca_poller_get_data(instance->nfca_poller, &instance->data->nfca_data); + + if(instance->state == MfUltralightPollerStateReadVersion) { + error = mf_ultralight_poller_async_read_version(instance); + if(error == MfUltralightErrorNone) { + FURI_LOG_I(TAG, "Read version success"); + instance->data->type = + mf_ultralight_get_type_by_version(&instance->data->version); + instance->state = MfUltralightPollerStateGetFeatureSet; } else { - instance->state = MfUltralightPollerStateReadPages; + FURI_LOG_W(TAG, "Didn't response. Check NTAG 203"); + nfca_poller_halt(instance->nfca_poller); + instance->state = MfUltralightPollerStateDetectNtag203; } - } else { - instance->state = MfUltralightPollerStateReadPages; - } - } else if(instance->state == MfUltralightPollerStateAuth) { - error = mf_ultralight_poller_async_auth(instance, &instance->auth_password); - if(error == MfUltralightErrorNone) { - FURI_LOG_I(TAG, "Auth success"); - if(instance->callback) { - mf_ul_poller_event.type = MfUltralightPollerEventTypeAuthSuccess; - memcpy( - &mf_ul_poller_event.data->pack, - &instance->data->page[instance->data->pages_read - 1], - MF_ULTRALIGHT_AUTH_PACK_SIZE); - instance->callback(mf_ul_poller_event, instance->context); + } else if(instance->state == MfUltralightPollerStateDetectNtag203) { + error = mf_ultralight_poller_async_read_page(instance, 41); + if(error == MfUltralightErrorNone) { + FURI_LOG_I(TAG, "NTAG203 detected"); + instance->data->type = MfUltralightTypeNTAG203; + instance->state = MfUltralightPollerStateGetFeatureSet; + } else { + FURI_LOG_I(TAG, "Original Ultralight detected"); + nfca_poller_halt(instance->nfca_poller); + instance->data->type = MfUltralightTypeUnknown; + instance->state = MfUltralightPollerStateGetFeatureSet; } - } else { - FURI_LOG_W(TAG, "Auth failed"); - if(instance->callback) { - mf_ul_poller_event.type = MfUltralightPollerEventTypeAuthFailed; - instance->callback(mf_ul_poller_event, instance->context); + } else if(instance->state == MfUltralightPollerStateGetFeatureSet) { + instance->feature_set = + mf_ultralight_get_feature_support_set(instance->data->type); + instance->pages_total = mf_ultralight_get_pages_total(instance->data->type); + instance->pages_read = 0; + instance->data->pages_total = instance->pages_total; + FURI_LOG_I( + TAG, + "%s detected. Total pages: %d", + mf_ultralight_get_name(instance->data->type, true), + instance->pages_total); + if((instance->callback) && + (instance->feature_set & MfUltralightFeatureSupportAuthentication)) { + mf_ul_poller_event.type = MfUltralightPollerEventTypeAuthRequest; + command = instance->callback(mf_ul_poller_event, instance->context); + if(!mf_ul_poller_event.data->auth_context.skip_auth) { + instance->auth_password = mf_ul_poller_event.data->auth_context.password; + instance->state = MfUltralightPollerStateAuth; + } else { + instance->state = MfUltralightPollerStateReadPages; + } + } else { + instance->state = MfUltralightPollerStateReadPages; } - nfca_poller_halt(instance->nfca_poller); - } - instance->state = MfUltralightPollerStateReadPages; - } else if(instance->state == MfUltralightPollerStateReadPages) { - error = mf_ultralight_poller_async_read_page(instance, instance->pages_read); - if(error == MfUltralightErrorNone) { - FURI_LOG_I(TAG, "Read page %d success", instance->pages_read); - instance->pages_read++; - instance->data->pages_read = instance->pages_read; - if(instance->pages_read == instance->pages_total - 2) { - instance->state = MfUltralightPollerStateReadSuccess; + } else if(instance->state == MfUltralightPollerStateAuth) { + error = mf_ultralight_poller_async_auth(instance, &instance->auth_password); + if(error == MfUltralightErrorNone) { + FURI_LOG_I(TAG, "Auth success"); + if(instance->callback) { + mf_ul_poller_event.type = MfUltralightPollerEventTypeAuthSuccess; + memcpy( + &mf_ul_poller_event.data->pack, + &instance->data->page[instance->data->pages_read - 1], + MF_ULTRALIGHT_AUTH_PACK_SIZE); + command = instance->callback(mf_ul_poller_event, instance->context); + } + } else { + FURI_LOG_W(TAG, "Auth failed"); + if(instance->callback) { + mf_ul_poller_event.type = MfUltralightPollerEventTypeAuthFailed; + command = instance->callback(mf_ul_poller_event, instance->context); + } + nfca_poller_halt(instance->nfca_poller); } - } else { - FURI_LOG_E(TAG, "Read page %d failed", instance->pages_read); - if(instance->pages_read) { - instance->state = MfUltralightPollerStateReadSuccess; + instance->state = MfUltralightPollerStateReadPages; + } else if(instance->state == MfUltralightPollerStateReadPages) { + error = mf_ultralight_poller_async_read_page(instance, instance->pages_read); + if(error == MfUltralightErrorNone) { + FURI_LOG_I(TAG, "Read page %d success", instance->pages_read); + instance->pages_read++; + instance->data->pages_read = instance->pages_read; + if(instance->pages_read == instance->pages_total - 2) { + instance->state = MfUltralightPollerStateReadSuccess; + } } else { + FURI_LOG_E(TAG, "Read page %d failed", instance->pages_read); + if(instance->pages_read) { + instance->state = MfUltralightPollerStateReadSuccess; + } else { + instance->state = MfUltralightPollerStateReadFailed; + } + } + } else if(instance->state == MfUltralightPollerStateReadSignature) { + error = mf_ultralight_poller_async_read_signature(instance); + if(error == MfUltralightErrorNone) { + FURI_LOG_I(TAG, "Read signature success"); + if(instance->feature_set & MfUltralightFeatureSupportReadCounter) { + instance->state = MfUltralightPollerStateReadCounters; + } + } else { + FURI_LOG_E(TAG, "Read signature failed"); instance->state = MfUltralightPollerStateReadFailed; } - } - } else if(instance->state == MfUltralightPollerStateReadSignature) { - error = mf_ultralight_poller_async_read_signature(instance); - if(error == MfUltralightErrorNone) { - FURI_LOG_I(TAG, "Read signature success"); - if(instance->feature_set & MfUltralightFeatureSupportReadCounter) { - instance->state = MfUltralightPollerStateReadCounters; + } else if(instance->state == MfUltralightPollerStateReadCounters) { + } else if(instance->state == MfUltralightPollerStateReadSuccess) { + if(instance->callback) { + mf_ul_poller_event.type = MfUltralightPollerEventTypeReadSuccess; + command = instance->callback(mf_ul_poller_event, instance->context); + } + } else if(instance->state == MfUltralightPollerStateReadFailed) { + if(instance->callback) { + mf_ul_poller_event.type = MfUltralightPollerEventTypeReadFailed; + command = instance->callback(mf_ul_poller_event, instance->context); } - } else { - FURI_LOG_E(TAG, "Read signature failed"); - instance->state = MfUltralightPollerStateReadFailed; - } - } else if(instance->state == MfUltralightPollerStateReadCounters) { - } else if(instance->state == MfUltralightPollerStateReadSuccess) { - if(instance->callback) { - mf_ul_poller_event.type = MfUltralightPollerEventTypeReadSuccess; - instance->callback(mf_ul_poller_event, instance->context); } - } else if(instance->state == MfUltralightPollerStateReadFailed) { + } else if(event.type == NfcaPollerEventTypeError) { if(instance->callback) { mf_ul_poller_event.type = MfUltralightPollerEventTypeReadFailed; - instance->callback(mf_ul_poller_event, instance->context); + command = instance->callback(mf_ul_poller_event, instance->context); } } - } else if(event.type == NfcaPollerEventTypeError) { - if(instance->callback) { - mf_ul_poller_event.type = MfUltralightPollerEventTypeReadFailed; - instance->callback(mf_ul_poller_event, instance->context); - } } + + return mf_ultralight_process_command(command); } MfUltralightError mf_ultralight_poller_start( @@ -473,11 +506,13 @@ MfUltralightError mf_ultralight_poller_start( furi_assert(instance->state == MfUltralightPollerStateIdle); furi_assert(instance->nfca_poller); furi_assert(callback); + furi_assert(instance->session_state == MfUltralightPollerSessionStateIdle); instance->data = malloc(sizeof(MfUltralightData)); instance->buffer = nfc_poller_buffer_alloc(MF_ULTRALIGHT_MAX_BUFF_SIZE, MF_ULTRALIGHT_MAX_BUFF_SIZE); + instance->session_state = MfUltralightPollerSessionStateActive; nfca_poller_start(instance->nfca_poller, callback, context); return MfUltralightErrorNone; @@ -516,15 +551,13 @@ MfUltralightError mf_ultralight_poller_reset(MfUltralightPoller* instance) { furi_assert(instance->buffer); furi_assert(instance->nfca_poller); - NfcaError error = nfca_poller_reset(instance->nfca_poller); - nfc_poller_buffer_free(instance->buffer); instance->callback = NULL; instance->context = NULL; free(instance->data); instance->state = MfUltralightPollerStateIdle; - return mf_ultralight_process_error(error); + return MfUltralightErrorNone; } // Called from NfcWorker thread @@ -533,12 +566,14 @@ MfUltralightError mf_ultralight_poller_stop(MfUltralightPoller* instance) { furi_assert(instance); furi_assert(instance->nfca_poller); + instance->session_state = MfUltralightPollerSessionStateStopRequest; nfca_poller_stop(instance->nfca_poller); + instance->session_state = MfUltralightPollerSessionStateIdle; - return MfUltralightErrorNone; + return mf_ultralight_poller_reset(instance); } -static void mf_ultraight_read_page_callback(NfcaPollerEvent event, void* context) { +static NfcaPollerCommand mf_ultraight_read_page_callback(NfcaPollerEvent event, void* context) { furi_assert(context); MfUltralightPollerContext* poller_context = context; @@ -549,8 +584,9 @@ static void mf_ultraight_read_page_callback(NfcaPollerEvent event, void* context } else if(event.type == NfcaPollerEventTypeError) { poller_context->error = mf_ultralight_process_error(event.data.error); } - mf_ultralight_poller_stop(poller_context->instance); furi_thread_flags_set(poller_context->thread_id, MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); + + return NfcaPollerCommandStop; } MfUltralightError mf_ultralight_poller_read_page( @@ -573,7 +609,7 @@ MfUltralightError mf_ultralight_poller_read_page( return poller_context.error; } -static void mf_ultraight_write_page_callback(NfcaPollerEvent event, void* context) { +static NfcaPollerCommand mf_ultraight_write_page_callback(NfcaPollerEvent event, void* context) { furi_assert(context); MfUltralightPollerContext* poller_context = context; @@ -588,6 +624,8 @@ static void mf_ultraight_write_page_callback(NfcaPollerEvent event, void* contex } mf_ultralight_poller_stop(poller_context->instance); furi_thread_flags_set(poller_context->thread_id, MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); + + return NfcaPollerCommandStop; } MfUltralightError mf_ultralight_poller_write_page( @@ -610,7 +648,7 @@ MfUltralightError mf_ultralight_poller_write_page( return poller_context.error; } -static void mf_ultraight_read_version_callback(NfcaPollerEvent event, void* context) { +static NfcaPollerCommand mf_ultraight_read_version_callback(NfcaPollerEvent event, void* context) { furi_assert(context); MfUltralightPollerContext* poller_context = context; @@ -622,6 +660,8 @@ static void mf_ultraight_read_version_callback(NfcaPollerEvent event, void* cont } mf_ultralight_poller_stop(poller_context->instance); furi_thread_flags_set(poller_context->thread_id, MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); + + return NfcaPollerCommandStop; } MfUltralightError @@ -640,7 +680,8 @@ MfUltralightError return poller_context.error; } -static void mf_ultraight_read_signature_callback(NfcaPollerEvent event, void* context) { +static NfcaPollerCommand + mf_ultraight_read_signature_callback(NfcaPollerEvent event, void* context) { furi_assert(context); MfUltralightPollerContext* poller_context = context; @@ -653,6 +694,8 @@ static void mf_ultraight_read_signature_callback(NfcaPollerEvent event, void* co } mf_ultralight_poller_stop(poller_context->instance); furi_thread_flags_set(poller_context->thread_id, MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); + + return NfcaPollerCommandStop; } MfUltralightError @@ -672,7 +715,7 @@ MfUltralightError return poller_context.error; } -static void mf_ultraight_read_counter_callback(NfcaPollerEvent event, void* context) { +static NfcaPollerCommand mf_ultraight_read_counter_callback(NfcaPollerEvent event, void* context) { furi_assert(context); MfUltralightPollerContext* poller_context = context; @@ -685,6 +728,8 @@ static void mf_ultraight_read_counter_callback(NfcaPollerEvent event, void* cont } mf_ultralight_poller_stop(poller_context->instance); furi_thread_flags_set(poller_context->thread_id, MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); + + return NfcaPollerCommandStop; } MfUltralightError mf_ultralight_poller_read_counter( @@ -707,7 +752,8 @@ MfUltralightError mf_ultralight_poller_read_counter( return poller_context.error; } -static void mf_ultraight_read_tering_flag_callback(NfcaPollerEvent event, void* context) { +static NfcaPollerCommand + mf_ultraight_read_tering_flag_callback(NfcaPollerEvent event, void* context) { furi_assert(context); MfUltralightPollerContext* poller_context = context; @@ -720,6 +766,8 @@ static void mf_ultraight_read_tering_flag_callback(NfcaPollerEvent event, void* } mf_ultralight_poller_stop(poller_context->instance); furi_thread_flags_set(poller_context->thread_id, MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); + + return NfcaPollerCommandStop; } MfUltralightError mf_ultralight_poller_read_tearing_flag( diff --git a/lib/nfc/protocols/mf_ultralight_poller.h b/lib/nfc/protocols/mf_ultralight_poller.h index 2a7de6568e15..7837bc946c6f 100644 --- a/lib/nfc/protocols/mf_ultralight_poller.h +++ b/lib/nfc/protocols/mf_ultralight_poller.h @@ -34,7 +34,14 @@ typedef struct { MfUltralightPollerEventData* data; } MfUltralightPollerEvent; -typedef void (*MfUltralightPollerCallback)(MfUltralightPollerEvent event, void* context); +typedef enum { + MfUltralightPollerCommandContinue = NfcaPollerCommandContinue, + MfUltralightPollerCommandReset = NfcaPollerCommandReset, + MfUltralightPollerCommandStop = NfcaPollerCommandStop, +} MfUltralightPollerCommand; + +typedef MfUltralightPollerCommand ( + *MfUltralightPollerCallback)(MfUltralightPollerEvent event, void* context); MfUltralightPoller* mf_ultralight_poller_alloc(NfcaPoller* nfca_poller); @@ -50,7 +57,8 @@ MfUltralightError mf_ultralight_poller_read( MfUltralightPollerCallback callback, void* context); -MfUltralightError mf_ultralight_poller_get_data(MfUltralightPoller* instance, MfUltralightData* data); +MfUltralightError + mf_ultralight_poller_get_data(MfUltralightPoller* instance, MfUltralightData* data); MfUltralightError mf_ultralight_poller_reset(MfUltralightPoller* instance); diff --git a/lib/nfc/protocols/nfca_listener.c b/lib/nfc/protocols/nfca_listener.c index c6990ef65721..8540af503fa9 100644 --- a/lib/nfc/protocols/nfca_listener.c +++ b/lib/nfc/protocols/nfca_listener.c @@ -46,16 +46,19 @@ static bool nfca_listener_halt_received(uint8_t* rx_data, uint16_t rx_bits) { return halt_cmd_received; } -static void nfca_listener_event_handler(NfcEvent event, void* context) { +static NfcCommand nfca_listener_event_handler(NfcEvent event, void* context) { furi_assert(context); NfcaListener* instance = context; NfcEventType event_type = event.type; NfcaListenerEvent nfca_listener_event = {}; + NfcCommand command = NfcCommandContinue; + if(event_type == NfcEventTypeListenerActivated) { instance->state = NfcaListenerStateActive; } else if((event_type == NfcEventTypeRxEnd) && (instance->state == NfcaListenerStateActive)) { if(nfca_listener_halt_received(event.data.rx_data, event.data.rx_bits)) { + // TODO rework with commands nfca_listener_sleep(instance); instance->state = NfcaListenerStateIdle; if(instance->callback) { @@ -76,6 +79,8 @@ static void nfca_listener_event_handler(NfcEvent event, void* context) { } } } + + return command; } NfcaListener* nfca_listener_alloc(Nfc* nfc) { diff --git a/lib/nfc/protocols/nfca_listener.h b/lib/nfc/protocols/nfca_listener.h index d274235a5fe1..f2bb8b608955 100644 --- a/lib/nfc/protocols/nfca_listener.h +++ b/lib/nfc/protocols/nfca_listener.h @@ -28,7 +28,12 @@ typedef struct { NfcaListenerEventData data; } NfcaListenerEvent; -typedef void (*NfcaListenerEventCallback)(NfcaListenerEvent event, void* context); +typedef enum { + NfcaListenerCommandContinue = NfcCommandContinue, + NfcaListenerCommandReset = NfcCommandReset, +} NfcaListenerCommand; + +typedef NfcaListenerCommand (*NfcaListenerEventCallback)(NfcaListenerEvent event, void* context); NfcaListener* nfca_listener_alloc(Nfc* nfc); diff --git a/lib/nfc/protocols/nfca_poller.c b/lib/nfc/protocols/nfca_poller.c index 4a12d1055529..f9722aa5f0c7 100644 --- a/lib/nfc/protocols/nfca_poller.c +++ b/lib/nfc/protocols/nfca_poller.c @@ -41,9 +41,16 @@ typedef enum { NfcaPollerActivated, } NfcaPollerState; +typedef enum { + NfcaPollerSessionStateIdle, + NfcaPollerSessionStateActive, + NfcaPollerSessionStateStopRequest, +} NfcaPollerSessionState; + struct NfcaPoller { Nfc* nfc; NfcaPollerState state; + NfcaPollerSessionState session_state; NfcaPollerColRes col_res; NfcaData* data; NfcPollerBuffer* buff; @@ -138,7 +145,7 @@ static NfcaError nfca_poller_prepare_trx(NfcaPoller* instance) { NfcaError ret = NfcaErrorNone; if(instance->state == NfcaPollerStateIdle) { - ret = nfca_poller_activate(instance, NULL); + ret = nfca_poller_async_activate(instance, NULL); } return ret; @@ -157,40 +164,65 @@ void nfca_poller_free(NfcaPoller* instance) { furi_assert(instance); furi_assert(instance->nfc); - nfc_poller_abort(instance->nfc); free(instance); } -static void nfca_poller_event_callback(NfcEvent event, void* context) { +static NfcCommand nfca_poller_process_command(NfcaPollerCommand command) { + NfcCommand ret = NfcCommandContinue; + + if(command == NfcaPollerCommandContinue) { + ret = NfcCommandContinue; + } else if(command == NfcaPollerCommandReset) { + ret = NfcCommandReset; + } else if(command == NfcaPollerCommandStop) { + ret = NfcCommandStop; + } else { + furi_crash("Unknown command"); + } + + return ret; +} + +static NfcCommand nfca_poller_event_callback(NfcEvent event, void* context) { furi_assert(context); NfcaPoller* instance = context; furi_assert(instance->callback); NfcaPollerEvent nfca_poller_event = {}; - if(event.type == NfcEventTypeConfigureRequest) { - nfca_poller_config(instance); - } else if(event.type == NfcEventTypePollerReady) { - if(instance->state != NfcaPollerActivated) { - NfcaData data = {}; - NfcaError error = nfca_poller_activate(instance, &data); - if(error == NfcaErrorNone) { - nfca_poller_event.type = NfcaPollerEventTypeReady; - instance->state = NfcaPollerActivated; - nfca_poller_event.data.error = error; - instance->callback(nfca_poller_event, instance->context); + NfcaPollerCommand command = NfcaPollerCommandContinue; + + furi_assert(instance->session_state != NfcaPollerSessionStateIdle); + if(instance->session_state == NfcaPollerSessionStateStopRequest) { + command = NfcaPollerCommandStop; + } else { + if(event.type == NfcEventTypeConfigureRequest) { + nfca_poller_config(instance); + } else if(event.type == NfcEventTypePollerReady) { + if(instance->state != NfcaPollerActivated) { + NfcaData data = {}; + NfcaError error = nfca_poller_async_activate(instance, &data); + if(error == NfcaErrorNone) { + nfca_poller_event.type = NfcaPollerEventTypeReady; + instance->state = NfcaPollerActivated; + nfca_poller_event.data.error = error; + command = instance->callback(nfca_poller_event, instance->context); + } else { + nfca_poller_event.type = NfcaPollerEventTypeError; + nfca_poller_event.data.error = error; + command = instance->callback(nfca_poller_event, instance->context); + // Add delay to switch context + furi_delay_ms(100); + } } else { - nfca_poller_event.type = NfcaPollerEventTypeError; - nfca_poller_event.data.error = error; - instance->callback(nfca_poller_event, instance->context); - furi_delay_ms(100); + nfca_poller_event.type = NfcaPollerEventTypeReady; + nfca_poller_event.data.error = NfcaErrorNone; + command = instance->callback(nfca_poller_event, instance->context); } - } else { - nfca_poller_event.type = NfcaPollerEventTypeReady; - nfca_poller_event.data.error = NfcaErrorNone; - instance->callback(nfca_poller_event, instance->context); } } + + return nfca_poller_process_command(command); } NfcaError @@ -198,10 +230,12 @@ NfcaError furi_assert(instance); furi_assert(callback); furi_assert(instance->nfc); + furi_assert(instance->session_state == NfcaPollerSessionStateIdle); instance->callback = callback; instance->context = context; + instance->session_state = NfcaPollerSessionStateActive; nfc_start_worker(instance->nfc, nfca_poller_event_callback, instance); return NfcaErrorNone; @@ -234,9 +268,6 @@ NfcaError nfca_poller_config(NfcaPoller* instance) { NfcaError nfca_poller_reset(NfcaPoller* instance) { furi_assert(instance); - furi_assert(instance->data); - - nfc_poller_abort(instance->nfc); instance->callback = NULL; instance->context = NULL; @@ -250,6 +281,17 @@ NfcaError nfca_poller_reset(NfcaPoller* instance) { return NfcaErrorNone; } +NfcaError nfca_poller_stop(NfcaPoller* instance) { + furi_assert(instance); + furi_assert(instance->data); + + instance->session_state = NfcaPollerSessionStateStopRequest; + nfc_stop(instance->nfc); + instance->session_state = NfcaPollerSessionStateIdle; + + return nfca_poller_reset(instance); +} + NfcaError nfca_poller_check_presence(NfcaPoller* instance) { furi_assert(instance); furi_assert(instance->nfc); @@ -300,7 +342,7 @@ NfcaError nfca_poller_halt(NfcaPoller* instance) { return NfcaErrorNone; } -NfcaError nfca_poller_activate(NfcaPoller* instance, NfcaData* nfca_data) { +NfcaError nfca_poller_async_activate(NfcaPoller* instance, NfcaData* nfca_data) { furi_assert(instance); furi_assert(instance->nfc); @@ -438,14 +480,6 @@ NfcaError nfca_poller_activate(NfcaPoller* instance, NfcaData* nfca_data) { return ret; } -NfcaError nfca_poller_stop(NfcaPoller* instance) { - furi_assert(instance); - furi_assert(instance->nfc); - - nfc_poller_stop(instance->nfc); - return NfcaErrorNone; -} - NfcaError nfca_poller_txrx( NfcaPoller* instance, uint8_t* tx_buff, @@ -504,14 +538,16 @@ NfcaError nfca_poller_send_standart_frame( return ret; } -static void nfca_poller_sync_callback(NfcaPollerEvent event, void* context) { +static NfcaPollerCommand nfca_poller_sync_callback(NfcaPollerEvent event, void* context) { NfcaPollerContext* nfca_poller_context = context; nfca_poller_stop(nfca_poller_context->instance); nfca_poller_context->error = event.data.error; furi_thread_flags_set(nfca_poller_context->thread_id, NFCA_POLLER_FLAG_COMMAND_COMPLETE); + + return NfcaPollerCommandStop; } -NfcaError nfca_poller_activate_sync(NfcaPoller* instance, NfcaData* nfca_data) { +NfcaError nfca_poller_activate(NfcaPoller* instance, NfcaData* nfca_data) { furi_assert(instance); NfcaPollerContext context = {}; @@ -520,9 +556,11 @@ NfcaError nfca_poller_activate_sync(NfcaPoller* instance, NfcaData* nfca_data) { nfca_poller_start(instance, nfca_poller_sync_callback, &context); furi_thread_flags_wait(NFCA_POLLER_FLAG_COMMAND_COMPLETE, FuriFlagWaitAny, FuriWaitForever); furi_thread_flags_clear(NFCA_POLLER_FLAG_COMMAND_COMPLETE); + nfc_stop(instance->nfc); if(context.error == NfcaErrorNone) { *nfca_data = *instance->data; } + nfca_poller_reset(instance); return context.error; } diff --git a/lib/nfc/protocols/nfca_poller.h b/lib/nfc/protocols/nfca_poller.h index ac08861601b6..309a9ddca68e 100644 --- a/lib/nfc/protocols/nfca_poller.h +++ b/lib/nfc/protocols/nfca_poller.h @@ -11,7 +11,6 @@ typedef struct NfcaPoller NfcaPoller; typedef enum { NfcaPollerEventTypeError, - NfcaPollerEventDetected, NfcaPollerEventTypeReady, } NfcaPollerEventType; @@ -24,28 +23,38 @@ typedef struct { NfcaPollerEventData data; } NfcaPollerEvent; -typedef void (*NfcaPollerEventCallback)(NfcaPollerEvent event, void* context); +typedef enum { + NfcaPollerCommandContinue = NfcCommandContinue, + NfcaPollerCommandReset = NfcCommandReset, + NfcaPollerCommandStop = NfcCommandStop, +} NfcaPollerCommand; + +typedef NfcaPollerCommand (*NfcaPollerEventCallback)(NfcaPollerEvent event, void* context); NfcaPoller* nfca_poller_alloc(Nfc* nfc); void nfca_poller_free(NfcaPoller* instance); -NfcaError - nfca_poller_start(NfcaPoller* instance, NfcaPollerEventCallback callback, void* context); +NfcaError nfca_poller_start(NfcaPoller* instance, NfcaPollerEventCallback callback, void* context); + +NfcaError nfca_poller_stop(NfcaPoller* instance); NfcaError nfca_poller_get_data(NfcaPoller* instance, NfcaData* data); +// Private API + +NfcaError nfca_poller_config(NfcaPoller* instance); + NfcaError nfca_poller_reset(NfcaPoller* instance); -// Called from NfcWorker thread +// Syncronous API +NfcaError nfca_poller_activate(NfcaPoller* instance, NfcaData* nfca_data); -NfcaError nfca_poller_stop(NfcaPoller* instance); +// Called from NfcWorker thread NfcaError nfca_poller_check_presence(NfcaPoller* instance); -NfcaError nfca_poller_config(NfcaPoller* instance); - -NfcaError nfca_poller_activate(NfcaPoller* instance, NfcaData* nfca_data); +NfcaError nfca_poller_async_activate(NfcaPoller* instance, NfcaData* nfca_data); NfcaError nfca_poller_halt(NfcaPoller* instance); @@ -67,9 +76,6 @@ NfcaError nfca_poller_send_standart_frame( uint16_t* rx_bits, uint32_t fwt); -// Syncronous API -NfcaError nfca_poller_activate_sync(NfcaPoller* instance, NfcaData* nfca_data); - #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/nfcb_poller.c b/lib/nfc/protocols/nfcb_poller.c index 3ec834489892..7defdb07f52e 100644 --- a/lib/nfc/protocols/nfcb_poller.c +++ b/lib/nfc/protocols/nfcb_poller.c @@ -34,7 +34,7 @@ void nfcb_poller_free(NfcbPoller* instance) { free(instance); } -static void nfcb_poller_event_callback(NfcEvent event, void* context) { +static NfcCommand nfcb_poller_event_callback(NfcEvent event, void* context) { furi_assert(context); NfcbPoller* instance = context; @@ -42,6 +42,8 @@ static void nfcb_poller_event_callback(NfcEvent event, void* context) { if(event.type == NfcEventTypeConfigureRequest) { nfcb_poller_config(instance); } + + return NfcCommandContinue; } NfcbError @@ -51,10 +53,6 @@ NfcbError instance->callback = callback; instance->context = context; - instance->data = malloc(sizeof(NfcbData)); - instance->buff = - nfc_poller_buffer_alloc(NFCB_POLLER_BUFER_MAX_SIZE, NFCB_POLLER_BUFER_MAX_SIZE); - nfc_start_worker(instance->nfc, nfcb_poller_event_callback, instance); return NfcbErrorNone; } @@ -72,7 +70,7 @@ NfcbError nfcb_poller_reset(NfcbPoller* instance) { furi_assert(instance->nfc); furi_assert(instance->data); - nfc_poller_abort(instance->nfc); + nfc_stop(instance->nfc); instance->callback = NULL; instance->context = NULL; @@ -87,6 +85,10 @@ NfcbError nfcb_poller_reset(NfcbPoller* instance) { NfcbError nfcb_poller_config(NfcbPoller* instance) { furi_assert(instance); + instance->data = malloc(sizeof(NfcbData)); + instance->buff = + nfc_poller_buffer_alloc(NFCB_POLLER_BUFER_MAX_SIZE, NFCB_POLLER_BUFER_MAX_SIZE); + nfc_config(instance->nfc, NfcModeNfcbPoller); nfc_set_guard_time_us(instance->nfc, NFCB_GUARD_TIME_US); nfc_set_fdt_poll_fc(instance->nfc, NFCB_FDT_POLL_FC); diff --git a/lib/nfc/protocols/nfcb_poller.h b/lib/nfc/protocols/nfcb_poller.h index d1fa9a269a35..cd71df783967 100644 --- a/lib/nfc/protocols/nfcb_poller.h +++ b/lib/nfc/protocols/nfcb_poller.h @@ -24,7 +24,13 @@ typedef struct { NfcbPollerEventData data; } NfcbPollerEvent; -typedef void (*NfcbPollerEventCallback)(NfcbPollerEvent* event, void* context); +typedef enum { + NfcbPollerCommandContinue = NfcCommandContinue, + NfcbPollerCommandReset = NfcCommandReset, + NfcbPollerCommandStop = NfcCommandStop, +} NfcbPollerCommand; + +typedef NfcbPollerCommand (*NfcbPollerEventCallback)(NfcbPollerEvent* event, void* context); NfcbPoller* nfcb_poller_alloc(Nfc* nfc); From c9628ec6048144cec82914c8dccad381902dae70 Mon Sep 17 00:00:00 2001 From: gornekich Date: Tue, 25 Apr 2023 01:05:36 +0400 Subject: [PATCH 040/149] nfc: separate public and private API --- .../main/nfc/helpers/mf_ultralight_auth.h | 2 +- applications/main/nfc/nfc_app_i.h | 10 +- applications/main/nfc/nfc_cli.c | 10 - applications/main/nfc_rpc/nfc_rpc_i.h | 8 +- .../main/nfc_rpc/nfc_rpc_mf_ultralight.c | 2 +- applications/main/nfc_rpc/nfc_rpc_nfca.c | 4 +- lib/nfc/nfc_device_data.h | 5 +- lib/nfc/nfc_poller.c | 4 +- lib/nfc/nfc_poller.h | 6 +- lib/nfc/nfc_worker_i.h | 2 +- .../{ => mf_ultralight}/mf_ultralight.c | 0 .../{ => mf_ultralight}/mf_ultralight.h | 2 +- .../mf_ultralight_listener.c | 1 - .../mf_ultralight_listener.h | 2 +- .../mf_ultralight_poller.c | 5 +- .../mf_ultralight_poller.h | 2 +- lib/nfc/protocols/{ => nfca}/nfca.c | 0 lib/nfc/protocols/{ => nfca}/nfca.h | 0 lib/nfc/protocols/{ => nfca}/nfca_listener.c | 0 lib/nfc/protocols/{ => nfca}/nfca_listener.h | 0 lib/nfc/protocols/nfca/nfca_poller.c | 151 ++++++++++++ lib/nfc/protocols/{ => nfca}/nfca_poller.h | 36 +-- .../{nfca_poller.c => nfca/nfca_poller_i.c} | 220 +----------------- lib/nfc/protocols/nfca/nfca_poller_i.h | 88 +++++++ lib/nfc/protocols/{ => nfcb}/nfcb.h | 0 lib/nfc/protocols/{ => nfcb}/nfcb_poller.c | 0 lib/nfc/protocols/{ => nfcb}/nfcb_poller.h | 0 27 files changed, 280 insertions(+), 280 deletions(-) rename lib/nfc/protocols/{ => mf_ultralight}/mf_ultralight.c (100%) rename lib/nfc/protocols/{ => mf_ultralight}/mf_ultralight.h (98%) rename lib/nfc/protocols/{ => mf_ultralight}/mf_ultralight_listener.c (99%) rename lib/nfc/protocols/{ => mf_ultralight}/mf_ultralight_listener.h (96%) rename lib/nfc/protocols/{ => mf_ultralight}/mf_ultralight_poller.c (99%) rename lib/nfc/protocols/{ => mf_ultralight}/mf_ultralight_poller.h (98%) rename lib/nfc/protocols/{ => nfca}/nfca.c (100%) rename lib/nfc/protocols/{ => nfca}/nfca.h (100%) rename lib/nfc/protocols/{ => nfca}/nfca_listener.c (100%) rename lib/nfc/protocols/{ => nfca}/nfca_listener.h (100%) create mode 100644 lib/nfc/protocols/nfca/nfca_poller.c rename lib/nfc/protocols/{ => nfca}/nfca_poller.h (57%) rename lib/nfc/protocols/{nfca_poller.c => nfca/nfca_poller_i.c} (66%) create mode 100644 lib/nfc/protocols/nfca/nfca_poller_i.h rename lib/nfc/protocols/{ => nfcb}/nfcb.h (100%) rename lib/nfc/protocols/{ => nfcb}/nfcb_poller.c (100%) rename lib/nfc/protocols/{ => nfcb}/nfcb_poller.h (100%) diff --git a/applications/main/nfc/helpers/mf_ultralight_auth.h b/applications/main/nfc/helpers/mf_ultralight_auth.h index 237e3b8ac07a..ea55fe0f77bd 100644 --- a/applications/main/nfc/helpers/mf_ultralight_auth.h +++ b/applications/main/nfc/helpers/mf_ultralight_auth.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #ifdef __cplusplus extern "C" { diff --git a/applications/main/nfc/nfc_app_i.h b/applications/main/nfc/nfc_app_i.h index 16696bb9b9f3..2e403d2143b9 100644 --- a/applications/main/nfc/nfc_app_i.h +++ b/applications/main/nfc/nfc_app_i.h @@ -34,11 +34,11 @@ #include #include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include diff --git a/applications/main/nfc/nfc_cli.c b/applications/main/nfc/nfc_cli.c index da9e24cb9a74..b1f2a48490ad 100644 --- a/applications/main/nfc/nfc_cli.c +++ b/applications/main/nfc/nfc_cli.c @@ -7,16 +7,6 @@ #include #include -#include -#include - -#include - -#include -#include -#include -#include - static void nfc_cli_print_usage() { printf("Usage:\r\n"); printf("nfc \r\n"); diff --git a/applications/main/nfc_rpc/nfc_rpc_i.h b/applications/main/nfc_rpc/nfc_rpc_i.h index 795d2336df30..2c3f0e058487 100644 --- a/applications/main/nfc_rpc/nfc_rpc_i.h +++ b/applications/main/nfc_rpc/nfc_rpc_i.h @@ -16,10 +16,10 @@ #include #include -#include -#include -#include -#include +#include +#include +#include +#include typedef void (*NfcRpcHandler)(Nfc_Main* cmd, void* context); diff --git a/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c b/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c index 834eec1bd1e6..8e1d5763d509 100644 --- a/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c +++ b/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c @@ -1,7 +1,7 @@ #include "nfc_rpc_i.h" #include "assets/compiled/mf_ultralight.pb.h" -#include +#include #define TAG "NfcRpcMfUltralight" diff --git a/applications/main/nfc_rpc/nfc_rpc_nfca.c b/applications/main/nfc_rpc/nfc_rpc_nfca.c index eb86e950aee8..ac03d2c0310c 100644 --- a/applications/main/nfc_rpc/nfc_rpc_nfca.c +++ b/applications/main/nfc_rpc/nfc_rpc_nfca.c @@ -1,7 +1,7 @@ #include "nfc_rpc_i.h" #include "assets/compiled/nfca.pb.h" -#include +#include #define TAG "NfcRpcNfca" @@ -65,7 +65,7 @@ static void nfc_rpc_nfca_read(Nfc_Main* cmd, void* context) { } cmd->content.nfca_read_resp = pb_nfca_read_resp; - nfca_poller_reset(instance->nfca_poller); + nfca_poller_stop(instance->nfca_poller); } static void nfc_rpc_nfca_emulate_start(Nfc_Main* cmd, void* context) { diff --git a/lib/nfc/nfc_device_data.h b/lib/nfc/nfc_device_data.h index 7c79a208f06d..e8650a848c27 100644 --- a/lib/nfc/nfc_device_data.h +++ b/lib/nfc/nfc_device_data.h @@ -1,7 +1,8 @@ #pragma once -#include "protocols/nfca.h" -#include "protocols/mf_ultralight.h" +#include +#include +#include #ifdef __cplusplus extern "C" { diff --git a/lib/nfc/nfc_poller.c b/lib/nfc/nfc_poller.c index fd4ccf0a9dd8..402dd4a5996d 100644 --- a/lib/nfc/nfc_poller.c +++ b/lib/nfc/nfc_poller.c @@ -3,8 +3,8 @@ #include #include "nfc.h" -#include "protocols/nfca_poller.h" -#include "protocols/mf_ultralight.h" +#include +#include typedef enum { NfcPollerStateIdle, diff --git a/lib/nfc/nfc_poller.h b/lib/nfc/nfc_poller.h index f5ee9e92d45b..903805961efb 100644 --- a/lib/nfc/nfc_poller.h +++ b/lib/nfc/nfc_poller.h @@ -4,9 +4,9 @@ extern "C" { #endif -#include "protocols/nfca_poller.h" -#include "protocols/nfcb_poller.h" -#include "protocols/mf_ultralight.h" +#include +#include +#include typedef struct NfcPoller NfcPoller; diff --git a/lib/nfc/nfc_worker_i.h b/lib/nfc/nfc_worker_i.h index 9733426abf28..e84c32388364 100644 --- a/lib/nfc/nfc_worker_i.h +++ b/lib/nfc/nfc_worker_i.h @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include struct NfcWorker { diff --git a/lib/nfc/protocols/mf_ultralight.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight.c similarity index 100% rename from lib/nfc/protocols/mf_ultralight.c rename to lib/nfc/protocols/mf_ultralight/mf_ultralight.c diff --git a/lib/nfc/protocols/mf_ultralight.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h similarity index 98% rename from lib/nfc/protocols/mf_ultralight.h rename to lib/nfc/protocols/mf_ultralight/mf_ultralight.h index c5c88946c81d..979574083965 100644 --- a/lib/nfc/protocols/mf_ultralight.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h @@ -1,6 +1,6 @@ #pragma once -#include "nfca.h" +#include #ifdef __cplusplus extern "C" { diff --git a/lib/nfc/protocols/mf_ultralight_listener.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c similarity index 99% rename from lib/nfc/protocols/mf_ultralight_listener.c rename to lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c index e8724431cd3a..7308edcc6cbc 100644 --- a/lib/nfc/protocols/mf_ultralight_listener.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c @@ -1,5 +1,4 @@ #include "mf_ultralight_listener.h" -#include "nfca_listener.h" #include diff --git a/lib/nfc/protocols/mf_ultralight_listener.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.h similarity index 96% rename from lib/nfc/protocols/mf_ultralight_listener.h rename to lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.h index 7321fc2b7cf6..d793032127d9 100644 --- a/lib/nfc/protocols/mf_ultralight_listener.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.h @@ -1,7 +1,7 @@ #pragma once #include "mf_ultralight.h" -#include "nfca_listener.h" +#include #ifdef __cplusplus extern "C" { diff --git a/lib/nfc/protocols/mf_ultralight_poller.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c similarity index 99% rename from lib/nfc/protocols/mf_ultralight_poller.c rename to lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c index 392e2a447217..898e66029e21 100644 --- a/lib/nfc/protocols/mf_ultralight_poller.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c @@ -1,9 +1,10 @@ #include "mf_ultralight_poller.h" +#include + #include -#include "nfca_poller.h" #include -#include "nfc_util.h" +#include #define TAG "MfUltralightPoller" diff --git a/lib/nfc/protocols/mf_ultralight_poller.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h similarity index 98% rename from lib/nfc/protocols/mf_ultralight_poller.h rename to lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h index 7837bc946c6f..14e11fdca801 100644 --- a/lib/nfc/protocols/mf_ultralight_poller.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h @@ -1,7 +1,7 @@ #pragma once +#include #include "mf_ultralight.h" -#include "nfca_poller.h" #ifdef __cplusplus extern "C" { diff --git a/lib/nfc/protocols/nfca.c b/lib/nfc/protocols/nfca/nfca.c similarity index 100% rename from lib/nfc/protocols/nfca.c rename to lib/nfc/protocols/nfca/nfca.c diff --git a/lib/nfc/protocols/nfca.h b/lib/nfc/protocols/nfca/nfca.h similarity index 100% rename from lib/nfc/protocols/nfca.h rename to lib/nfc/protocols/nfca/nfca.h diff --git a/lib/nfc/protocols/nfca_listener.c b/lib/nfc/protocols/nfca/nfca_listener.c similarity index 100% rename from lib/nfc/protocols/nfca_listener.c rename to lib/nfc/protocols/nfca/nfca_listener.c diff --git a/lib/nfc/protocols/nfca_listener.h b/lib/nfc/protocols/nfca/nfca_listener.h similarity index 100% rename from lib/nfc/protocols/nfca_listener.h rename to lib/nfc/protocols/nfca/nfca_listener.h diff --git a/lib/nfc/protocols/nfca/nfca_poller.c b/lib/nfc/protocols/nfca/nfca_poller.c new file mode 100644 index 000000000000..b245d2abb3b3 --- /dev/null +++ b/lib/nfc/protocols/nfca/nfca_poller.c @@ -0,0 +1,151 @@ +#include "nfca_poller_i.h" + +#include + +#define TAG "NFCA" + +#define NFCA_POLLER_FLAG_COMMAND_COMPLETE (1UL << 0) + +typedef struct { + NfcaPoller* instance; + FuriThreadId thread_id; + NfcaError error; +} NfcaPollerContext; + +NfcaPoller* nfca_poller_alloc(Nfc* nfc) { + furi_assert(nfc); + + NfcaPoller* instance = malloc(sizeof(NfcaPoller)); + instance->nfc = nfc; + + return instance; +} + +void nfca_poller_free(NfcaPoller* instance) { + furi_assert(instance); + furi_assert(instance->nfc); + + free(instance); +} + +static NfcCommand nfca_poller_process_command(NfcaPollerCommand command) { + NfcCommand ret = NfcCommandContinue; + + if(command == NfcaPollerCommandContinue) { + ret = NfcCommandContinue; + } else if(command == NfcaPollerCommandReset) { + ret = NfcCommandReset; + } else if(command == NfcaPollerCommandStop) { + ret = NfcCommandStop; + } else { + furi_crash("Unknown command"); + } + + return ret; +} + +static NfcCommand nfca_poller_event_callback(NfcEvent event, void* context) { + furi_assert(context); + + NfcaPoller* instance = context; + furi_assert(instance->callback); + + NfcaPollerEvent nfca_poller_event = {}; + NfcaPollerCommand command = NfcaPollerCommandContinue; + + furi_assert(instance->session_state != NfcaPollerSessionStateIdle); + if(instance->session_state == NfcaPollerSessionStateStopRequest) { + command = NfcaPollerCommandStop; + } else { + if(event.type == NfcEventTypeConfigureRequest) { + nfca_poller_config(instance); + } else if(event.type == NfcEventTypePollerReady) { + if(instance->state != NfcaPollerActivated) { + NfcaData data = {}; + NfcaError error = nfca_poller_async_activate(instance, &data); + if(error == NfcaErrorNone) { + nfca_poller_event.type = NfcaPollerEventTypeReady; + instance->state = NfcaPollerActivated; + nfca_poller_event.data.error = error; + command = instance->callback(nfca_poller_event, instance->context); + } else { + nfca_poller_event.type = NfcaPollerEventTypeError; + nfca_poller_event.data.error = error; + command = instance->callback(nfca_poller_event, instance->context); + // Add delay to switch context + furi_delay_ms(100); + } + } else { + nfca_poller_event.type = NfcaPollerEventTypeReady; + nfca_poller_event.data.error = NfcaErrorNone; + command = instance->callback(nfca_poller_event, instance->context); + } + } + } + + return nfca_poller_process_command(command); +} + +NfcaError + nfca_poller_start(NfcaPoller* instance, NfcaPollerEventCallback callback, void* context) { + furi_assert(instance); + furi_assert(callback); + furi_assert(instance->nfc); + furi_assert(instance->session_state == NfcaPollerSessionStateIdle); + + instance->callback = callback; + instance->context = context; + + instance->session_state = NfcaPollerSessionStateActive; + nfc_start_worker(instance->nfc, nfca_poller_event_callback, instance); + + return NfcaErrorNone; +} + +NfcaError nfca_poller_get_data(NfcaPoller* instance, NfcaData* data) { + furi_assert(instance); + furi_assert(instance->data); + furi_assert(data); + + *data = *instance->data; + + return NfcaErrorNone; +} + +NfcaError nfca_poller_stop(NfcaPoller* instance) { + furi_assert(instance); + furi_assert(instance->data); + + instance->session_state = NfcaPollerSessionStateStopRequest; + nfc_stop(instance->nfc); + instance->session_state = NfcaPollerSessionStateIdle; + + return nfca_poller_reset(instance); +} + +static NfcaPollerCommand nfca_poller_sync_callback(NfcaPollerEvent event, void* context) { + NfcaPollerContext* nfca_poller_context = context; + nfca_poller_stop(nfca_poller_context->instance); + nfca_poller_context->error = event.data.error; + furi_thread_flags_set(nfca_poller_context->thread_id, NFCA_POLLER_FLAG_COMMAND_COMPLETE); + + return NfcaPollerCommandStop; +} + +NfcaError nfca_poller_activate(NfcaPoller* instance, NfcaData* nfca_data) { + furi_assert(instance); + + NfcaPollerContext context = {}; + context.instance = instance; + context.thread_id = furi_thread_get_current_id(); + nfca_poller_start(instance, nfca_poller_sync_callback, &context); + furi_thread_flags_wait(NFCA_POLLER_FLAG_COMMAND_COMPLETE, FuriFlagWaitAny, FuriWaitForever); + furi_thread_flags_clear(NFCA_POLLER_FLAG_COMMAND_COMPLETE); + nfc_stop(instance->nfc); + if(context.error == NfcaErrorNone) { + *nfca_data = *instance->data; + } + nfca_poller_reset(instance); + + return context.error; +} diff --git a/lib/nfc/protocols/nfca_poller.h b/lib/nfc/protocols/nfca/nfca_poller.h similarity index 57% rename from lib/nfc/protocols/nfca_poller.h rename to lib/nfc/protocols/nfca/nfca_poller.h index 309a9ddca68e..82195a616d95 100644 --- a/lib/nfc/protocols/nfca_poller.h +++ b/lib/nfc/protocols/nfca/nfca_poller.h @@ -1,7 +1,7 @@ #pragma once #include "nfca.h" -#include "nfc.h" +#include #ifdef __cplusplus extern "C" { @@ -41,41 +41,9 @@ NfcaError nfca_poller_stop(NfcaPoller* instance); NfcaError nfca_poller_get_data(NfcaPoller* instance, NfcaData* data); -// Private API - -NfcaError nfca_poller_config(NfcaPoller* instance); - -NfcaError nfca_poller_reset(NfcaPoller* instance); - -// Syncronous API +// Sync call NfcaError nfca_poller_activate(NfcaPoller* instance, NfcaData* nfca_data); -// Called from NfcWorker thread - -NfcaError nfca_poller_check_presence(NfcaPoller* instance); - -NfcaError nfca_poller_async_activate(NfcaPoller* instance, NfcaData* nfca_data); - -NfcaError nfca_poller_halt(NfcaPoller* instance); - -NfcaError nfca_poller_txrx( - NfcaPoller* instance, - uint8_t* tx_buff, - uint16_t tx_bits, - uint8_t* rx_buff, - uint16_t rx_buff_size, - uint16_t* rx_bits, - uint32_t fwt); - -NfcaError nfca_poller_send_standart_frame( - NfcaPoller* instance, - uint8_t* tx_data, - uint16_t tx_bits, - uint8_t* rx_data, - uint16_t rx_data_size, - uint16_t* rx_bits, - uint32_t fwt); - #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/nfca_poller.c b/lib/nfc/protocols/nfca/nfca_poller_i.c similarity index 66% rename from lib/nfc/protocols/nfca_poller.c rename to lib/nfc/protocols/nfca/nfca_poller_i.c index f9722aa5f0c7..e49380544fc6 100644 --- a/lib/nfc/protocols/nfca_poller.c +++ b/lib/nfc/protocols/nfca/nfca_poller_i.c @@ -1,69 +1,9 @@ -#include "nfca_poller.h" -#include "nfca.h" +#include "nfca_poller_i.h" -#include - -#include #include #define TAG "NFCA" -#define NFCA_POLLER_FLAG_COMMAND_COMPLETE (1UL << 0) - -#define NFCA_POLLER_MAX_BUFFER_SIZE (512U) - -#define NFCA_POLLER_SEL_CMD(cascade_lvl) (0x93 + 2 * (cascade_lvl)) -#define NFCA_POLLER_SEL_PAR(bytes, bits) (((bytes) << 4 & 0xf0U) | ((bits)&0x0fU)) -#define NFCA_POLLER_SDD_CL (0x88U) - -typedef enum { - NfcaPollerColResStateStateIdle, - NfcaPollerColResStateStateNewCascade, - NfcaPollerColResStateStateSelectCascade, - NfcaPollerColResStateStateSuccess, - NfcaPollerColResStateStateFail, -} NfcaPollerColResState; - -typedef struct { - NfcaPollerColResState state; - NfcaSensResp sens_resp; - NfcaSddReq sdd_req; - NfcaSddResp sdd_resp; - NfcaSelReq sel_req; - NfcaSelResp sel_resp; - uint8_t cascade_level; -} NfcaPollerColRes; - -typedef enum { - NfcaPollerStateIdle, - NfcaPollerColResInProgress, - NfcaPollerColResFailed, - NfcaPollerActivated, -} NfcaPollerState; - -typedef enum { - NfcaPollerSessionStateIdle, - NfcaPollerSessionStateActive, - NfcaPollerSessionStateStopRequest, -} NfcaPollerSessionState; - -struct NfcaPoller { - Nfc* nfc; - NfcaPollerState state; - NfcaPollerSessionState session_state; - NfcaPollerColRes col_res; - NfcaData* data; - NfcPollerBuffer* buff; - NfcaPollerEventCallback callback; - void* context; -}; - -typedef struct { - NfcaPoller* instance; - FuriThreadId thread_id; - NfcaError error; -} NfcaPollerContext; - static NfcaError nfca_poller_process_error(NfcError error) { NfcaError ret = NfcaErrorNone; if(error == NfcErrorNone) { @@ -76,6 +16,16 @@ static NfcaError nfca_poller_process_error(NfcError error) { return ret; } +static NfcaError nfca_poller_prepare_trx(NfcaPoller* instance) { + NfcaError ret = NfcaErrorNone; + + if(instance->state == NfcaPollerStateIdle) { + ret = nfca_poller_async_activate(instance, NULL); + } + + return ret; +} + static NfcaError nfca_poller_standart_frame_exchange( NfcaPoller* instance, uint8_t* tx_data, @@ -141,116 +91,6 @@ static NfcaError nfca_poller_standart_frame_exchange( return ret; } -static NfcaError nfca_poller_prepare_trx(NfcaPoller* instance) { - NfcaError ret = NfcaErrorNone; - - if(instance->state == NfcaPollerStateIdle) { - ret = nfca_poller_async_activate(instance, NULL); - } - - return ret; -} - -NfcaPoller* nfca_poller_alloc(Nfc* nfc) { - furi_assert(nfc); - - NfcaPoller* instance = malloc(sizeof(NfcaPoller)); - instance->nfc = nfc; - - return instance; -} - -void nfca_poller_free(NfcaPoller* instance) { - furi_assert(instance); - furi_assert(instance->nfc); - - free(instance); -} - -static NfcCommand nfca_poller_process_command(NfcaPollerCommand command) { - NfcCommand ret = NfcCommandContinue; - - if(command == NfcaPollerCommandContinue) { - ret = NfcCommandContinue; - } else if(command == NfcaPollerCommandReset) { - ret = NfcCommandReset; - } else if(command == NfcaPollerCommandStop) { - ret = NfcCommandStop; - } else { - furi_crash("Unknown command"); - } - - return ret; -} - -static NfcCommand nfca_poller_event_callback(NfcEvent event, void* context) { - furi_assert(context); - - NfcaPoller* instance = context; - furi_assert(instance->callback); - - NfcaPollerEvent nfca_poller_event = {}; - NfcaPollerCommand command = NfcaPollerCommandContinue; - - furi_assert(instance->session_state != NfcaPollerSessionStateIdle); - if(instance->session_state == NfcaPollerSessionStateStopRequest) { - command = NfcaPollerCommandStop; - } else { - if(event.type == NfcEventTypeConfigureRequest) { - nfca_poller_config(instance); - } else if(event.type == NfcEventTypePollerReady) { - if(instance->state != NfcaPollerActivated) { - NfcaData data = {}; - NfcaError error = nfca_poller_async_activate(instance, &data); - if(error == NfcaErrorNone) { - nfca_poller_event.type = NfcaPollerEventTypeReady; - instance->state = NfcaPollerActivated; - nfca_poller_event.data.error = error; - command = instance->callback(nfca_poller_event, instance->context); - } else { - nfca_poller_event.type = NfcaPollerEventTypeError; - nfca_poller_event.data.error = error; - command = instance->callback(nfca_poller_event, instance->context); - // Add delay to switch context - furi_delay_ms(100); - } - } else { - nfca_poller_event.type = NfcaPollerEventTypeReady; - nfca_poller_event.data.error = NfcaErrorNone; - command = instance->callback(nfca_poller_event, instance->context); - } - } - } - - return nfca_poller_process_command(command); -} - -NfcaError - nfca_poller_start(NfcaPoller* instance, NfcaPollerEventCallback callback, void* context) { - furi_assert(instance); - furi_assert(callback); - furi_assert(instance->nfc); - furi_assert(instance->session_state == NfcaPollerSessionStateIdle); - - instance->callback = callback; - instance->context = context; - - instance->session_state = NfcaPollerSessionStateActive; - nfc_start_worker(instance->nfc, nfca_poller_event_callback, instance); - - return NfcaErrorNone; -} - -NfcaError nfca_poller_get_data(NfcaPoller* instance, NfcaData* data) { - furi_assert(instance); - furi_assert(instance->data); - furi_assert(data); - - *data = *instance->data; - - return NfcaErrorNone; -} - NfcaError nfca_poller_config(NfcaPoller* instance) { furi_assert(instance); @@ -281,17 +121,6 @@ NfcaError nfca_poller_reset(NfcaPoller* instance) { return NfcaErrorNone; } -NfcaError nfca_poller_stop(NfcaPoller* instance) { - furi_assert(instance); - furi_assert(instance->data); - - instance->session_state = NfcaPollerSessionStateStopRequest; - nfc_stop(instance->nfc); - instance->session_state = NfcaPollerSessionStateIdle; - - return nfca_poller_reset(instance); -} - NfcaError nfca_poller_check_presence(NfcaPoller* instance) { furi_assert(instance); furi_assert(instance->nfc); @@ -537,30 +366,3 @@ NfcaError nfca_poller_send_standart_frame( return ret; } - -static NfcaPollerCommand nfca_poller_sync_callback(NfcaPollerEvent event, void* context) { - NfcaPollerContext* nfca_poller_context = context; - nfca_poller_stop(nfca_poller_context->instance); - nfca_poller_context->error = event.data.error; - furi_thread_flags_set(nfca_poller_context->thread_id, NFCA_POLLER_FLAG_COMMAND_COMPLETE); - - return NfcaPollerCommandStop; -} - -NfcaError nfca_poller_activate(NfcaPoller* instance, NfcaData* nfca_data) { - furi_assert(instance); - - NfcaPollerContext context = {}; - context.instance = instance; - context.thread_id = furi_thread_get_current_id(); - nfca_poller_start(instance, nfca_poller_sync_callback, &context); - furi_thread_flags_wait(NFCA_POLLER_FLAG_COMMAND_COMPLETE, FuriFlagWaitAny, FuriWaitForever); - furi_thread_flags_clear(NFCA_POLLER_FLAG_COMMAND_COMPLETE); - nfc_stop(instance->nfc); - if(context.error == NfcaErrorNone) { - *nfca_data = *instance->data; - } - nfca_poller_reset(instance); - - return context.error; -} diff --git a/lib/nfc/protocols/nfca/nfca_poller_i.h b/lib/nfc/protocols/nfca/nfca_poller_i.h new file mode 100644 index 000000000000..8e6f078108d4 --- /dev/null +++ b/lib/nfc/protocols/nfca/nfca_poller_i.h @@ -0,0 +1,88 @@ +#pragma once + +#include "nfca_poller.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define NFCA_POLLER_MAX_BUFFER_SIZE (512U) + +#define NFCA_POLLER_SEL_CMD(cascade_lvl) (0x93 + 2 * (cascade_lvl)) +#define NFCA_POLLER_SEL_PAR(bytes, bits) (((bytes) << 4 & 0xf0U) | ((bits)&0x0fU)) +#define NFCA_POLLER_SDD_CL (0x88U) + +typedef enum { + NfcaPollerColResStateStateIdle, + NfcaPollerColResStateStateNewCascade, + NfcaPollerColResStateStateSelectCascade, + NfcaPollerColResStateStateSuccess, + NfcaPollerColResStateStateFail, +} NfcaPollerColResState; + +typedef struct { + NfcaPollerColResState state; + NfcaSensResp sens_resp; + NfcaSddReq sdd_req; + NfcaSddResp sdd_resp; + NfcaSelReq sel_req; + NfcaSelResp sel_resp; + uint8_t cascade_level; +} NfcaPollerColRes; + +typedef enum { + NfcaPollerStateIdle, + NfcaPollerColResInProgress, + NfcaPollerColResFailed, + NfcaPollerActivated, +} NfcaPollerState; + +typedef enum { + NfcaPollerSessionStateIdle, + NfcaPollerSessionStateActive, + NfcaPollerSessionStateStopRequest, +} NfcaPollerSessionState; + +struct NfcaPoller { + Nfc* nfc; + NfcaPollerState state; + NfcaPollerSessionState session_state; + NfcaPollerColRes col_res; + NfcaData* data; + NfcPollerBuffer* buff; + NfcaPollerEventCallback callback; + void* context; +}; + +NfcaError nfca_poller_config(NfcaPoller* instance); + +NfcaError nfca_poller_reset(NfcaPoller* instance); + +NfcaError nfca_poller_check_presence(NfcaPoller* instance); + +NfcaError nfca_poller_async_activate(NfcaPoller* instance, NfcaData* nfca_data); + +NfcaError nfca_poller_halt(NfcaPoller* instance); + +NfcaError nfca_poller_txrx( + NfcaPoller* instance, + uint8_t* tx_buff, + uint16_t tx_bits, + uint8_t* rx_buff, + uint16_t rx_buff_size, + uint16_t* rx_bits, + uint32_t fwt); + +NfcaError nfca_poller_send_standart_frame( + NfcaPoller* instance, + uint8_t* tx_data, + uint16_t tx_bits, + uint8_t* rx_data, + uint16_t rx_data_size, + uint16_t* rx_bits, + uint32_t fwt); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/nfcb.h b/lib/nfc/protocols/nfcb/nfcb.h similarity index 100% rename from lib/nfc/protocols/nfcb.h rename to lib/nfc/protocols/nfcb/nfcb.h diff --git a/lib/nfc/protocols/nfcb_poller.c b/lib/nfc/protocols/nfcb/nfcb_poller.c similarity index 100% rename from lib/nfc/protocols/nfcb_poller.c rename to lib/nfc/protocols/nfcb/nfcb_poller.c diff --git a/lib/nfc/protocols/nfcb_poller.h b/lib/nfc/protocols/nfcb/nfcb_poller.h similarity index 100% rename from lib/nfc/protocols/nfcb_poller.h rename to lib/nfc/protocols/nfcb/nfcb_poller.h From 81ba6641ef29db41b8104bf97f48bf521b65825b Mon Sep 17 00:00:00 2001 From: gornekich Date: Tue, 25 Apr 2023 13:05:47 +0400 Subject: [PATCH 041/149] mf ultralight: neat state handlers --- lib/nfc/nfc.h | 4 +- .../mf_ultralight/mf_ultralight_poller.c | 301 +++++++++++------- 2 files changed, 186 insertions(+), 119 deletions(-) diff --git a/lib/nfc/nfc.h b/lib/nfc/nfc.h index d2cab6f83425..540eae6b4e18 100644 --- a/lib/nfc/nfc.h +++ b/lib/nfc/nfc.h @@ -97,10 +97,10 @@ NfcError nfc_listener_sleep(Nfc* instance); void nfc_listener_abort(Nfc* instance); -// Called from worker thread - void nfc_stop(Nfc* instance); +// Called from worker thread + NfcError nfc_listener_tx(Nfc* instance, uint8_t* tx_data, uint16_t tx_bits); NfcError nfc_trx( diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c index 898e66029e21..ef291f9d1583 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c @@ -45,6 +45,8 @@ typedef enum { MfUltralightPollerStateReadPages, MfUltralightPollerStateReadFailed, MfUltralightPollerStateReadSuccess, + + MfUltralightPollerStateNum, } MfUltralightPollerState; typedef enum { @@ -361,13 +363,193 @@ static MfUltralightError mf_ultralight_poller_async_read_tearing_flag( return ret; } +static MfUltralightPollerCommand mf_ultralight_poller_handler_idle(MfUltralightPoller* instance) { + nfc_poller_buffer_reset(instance->buffer); + nfca_poller_get_data(instance->nfca_poller, &instance->data->nfca_data); + instance->state = MfUltralightPollerStateReadVersion; + + return MfUltralightPollerCommandContinue; +} + +static MfUltralightPollerCommand + mf_ultralight_poller_handler_read_version(MfUltralightPoller* instance) { + MfUltralightError error = mf_ultralight_poller_async_read_version(instance); + if(error == MfUltralightErrorNone) { + FURI_LOG_I(TAG, "Read version success"); + instance->data->type = mf_ultralight_get_type_by_version(&instance->data->version); + instance->state = MfUltralightPollerStateGetFeatureSet; + } else { + FURI_LOG_W(TAG, "Didn't response. Check NTAG 203"); + nfca_poller_halt(instance->nfca_poller); + instance->state = MfUltralightPollerStateDetectNtag203; + } + + return MfUltralightPollerCommandContinue; +} + +static MfUltralightPollerCommand + mf_ultralight_poller_handler_check_ntag_203(MfUltralightPoller* instance) { + MfUltralightError error = mf_ultralight_poller_async_read_page(instance, 41); + if(error == MfUltralightErrorNone) { + FURI_LOG_I(TAG, "NTAG203 detected"); + instance->data->type = MfUltralightTypeNTAG203; + } else { + FURI_LOG_I(TAG, "Original Ultralight detected"); + nfca_poller_halt(instance->nfca_poller); + instance->data->type = MfUltralightTypeUnknown; + } + instance->state = MfUltralightPollerStateGetFeatureSet; + + return MfUltralightPollerCommandContinue; +} + +static MfUltralightPollerCommand + mf_ultralight_poller_handler_get_feature_set(MfUltralightPoller* instance) { + MfUltralightPollerCommand command = MfUltralightPollerCommandContinue; + + instance->feature_set = mf_ultralight_get_feature_support_set(instance->data->type); + instance->pages_total = mf_ultralight_get_pages_total(instance->data->type); + instance->pages_read = 0; + instance->data->pages_total = instance->pages_total; + FURI_LOG_I( + TAG, + "%s detected. Total pages: %d", + mf_ultralight_get_name(instance->data->type, true), + instance->pages_total); + + if(instance->feature_set & MfUltralightFeatureSupportAuthentication) { + MfUltralightPollerEventData event_data = {}; + MfUltralightPollerEvent event = { + .type = MfUltralightPollerEventTypeAuthRequest, + .data = &event_data, + }; + + command = instance->callback(event, instance->context); + if(!event.data->auth_context.skip_auth) { + instance->auth_password = event.data->auth_context.password; + instance->state = MfUltralightPollerStateAuth; + } else { + instance->state = MfUltralightPollerStateReadPages; + } + } else { + instance->state = MfUltralightPollerStateReadPages; + } + + return command; +} + +static MfUltralightPollerCommand + mf_ultralight_poller_handler_read_signature(MfUltralightPoller* instance) { + FURI_LOG_D(TAG, "Reading signature"); + instance->state = MfUltralightPollerStateReadCounters; + + return MfUltralightPollerCommandContinue; +} + +static MfUltralightPollerCommand + mf_ultralight_poller_handler_read_counters(MfUltralightPoller* instance) { + FURI_LOG_D(TAG, "Reading counters"); + instance->state = MfUltralightPollerStateReadTearingFlags; + + return MfUltralightPollerCommandContinue; +} + +static MfUltralightPollerCommand + mf_ultralight_poller_handler_read_traring_flags(MfUltralightPoller* instance) { + FURI_LOG_D(TAG, "Reading tearing flags"); + instance->state = MfUltralightPollerStateReadTearingFlags; + + return MfUltralightPollerCommandContinue; +} + +static MfUltralightPollerCommand mf_ultralight_poller_handler_auth(MfUltralightPoller* instance) { + FURI_LOG_D(TAG, "Trying to authenticate with password %08lX", instance->auth_password.pass); + MfUltralightPollerCommand command = MfUltralightPollerCommandContinue; + + MfUltralightError error = mf_ultralight_poller_async_auth(instance, &instance->auth_password); + if(error == MfUltralightErrorNone) { + FURI_LOG_D(TAG, "Auth success"); + // TODO fill PACK in event + MfUltralightPollerEventData data = {.pack.pack = 0x8080}; + MfUltralightPollerEvent event = { + .type = MfUltralightPollerEventTypeAuthSuccess, .data = &data}; + command = instance->callback(event, instance->context); + } else { + FURI_LOG_W(TAG, "Auth failed"); + MfUltralightPollerEvent event = {.type = MfUltralightPollerEventTypeAuthFailed}; + command = instance->callback(event, instance->context); + // TODO rework with HALT cmd + nfca_poller_halt(instance->nfca_poller); + } + instance->state = MfUltralightPollerStateReadPages; + + return command; +} + +static MfUltralightPollerCommand + mf_ultralight_poller_handler_read_pages(MfUltralightPoller* instance) { + MfUltralightError error = mf_ultralight_poller_async_read_page(instance, instance->pages_read); + if(error == MfUltralightErrorNone) { + FURI_LOG_I(TAG, "Read page %d success", instance->pages_read); + instance->pages_read++; + instance->data->pages_read = instance->pages_read; + if(instance->pages_read == instance->pages_total - 2) { + instance->state = MfUltralightPollerStateReadSuccess; + } + } else { + FURI_LOG_E(TAG, "Read page %d failed", instance->pages_read); + if(instance->pages_read) { + instance->state = MfUltralightPollerStateReadSuccess; + } else { + instance->state = MfUltralightPollerStateReadFailed; + } + } + + return MfUltralightPollerCommandContinue; +} + +static MfUltralightPollerCommand + mf_ultralight_poller_handler_read_fail(MfUltralightPoller* instance) { + FURI_LOG_W(TAG, "Read Failed"); + MfUltralightPollerEvent event = {.type = MfUltralightPollerEventTypeReadFailed}; + MfUltralightPollerCommand command = instance->callback(event, instance->context); + instance->state = MfUltralightPollerStateIdle; + return command; +} + +static MfUltralightPollerCommand + mf_ultralight_poller_handler_read_success(MfUltralightPoller* instance) { + FURI_LOG_D(TAG, "Read success."); + MfUltralightPollerEvent event = {.type = MfUltralightPollerEventTypeReadSuccess}; + MfUltralightPollerCommand command = instance->callback(event, instance->context); + return command; +} + +typedef MfUltralightPollerCommand (*MfUltralightPollerReadHandler)(MfUltralightPoller* instance); + +static const MfUltralightPollerReadHandler + mf_ultralight_poller_read_handler[MfUltralightPollerStateNum] = { + [MfUltralightPollerStateIdle] = mf_ultralight_poller_handler_idle, + [MfUltralightPollerStateReadVersion] = mf_ultralight_poller_handler_read_version, + [MfUltralightPollerStateDetectNtag203] = mf_ultralight_poller_handler_check_ntag_203, + [MfUltralightPollerStateGetFeatureSet] = mf_ultralight_poller_handler_get_feature_set, + [MfUltralightPollerStateReadSignature] = mf_ultralight_poller_handler_read_signature, + [MfUltralightPollerStateReadCounters] = mf_ultralight_poller_handler_read_counters, + [MfUltralightPollerStateReadTearingFlags] = + mf_ultralight_poller_handler_read_traring_flags, + [MfUltralightPollerStateAuth] = mf_ultralight_poller_handler_auth, + [MfUltralightPollerStateReadPages] = mf_ultralight_poller_handler_read_pages, + [MfUltralightPollerStateReadFailed] = mf_ultralight_poller_handler_read_fail, + [MfUltralightPollerStateReadSuccess] = mf_ultralight_poller_handler_read_success, + +}; + static NfcaPollerCommand mf_ultralight_poller_read_callback(NfcaPollerEvent event, void* context) { furi_assert(context); MfUltralightPoller* instance = context; MfUltralightPollerEventData event_data = {}; MfUltralightPollerEvent mf_ul_poller_event = {.data = &event_data}; - MfUltralightError error = MfUltralightErrorNone; MfUltralightPollerCommand command = MfUltralightPollerCommandContinue; furi_assert(instance->session_state != MfUltralightPollerSessionStateIdle); @@ -375,119 +557,7 @@ static NfcaPollerCommand mf_ultralight_poller_read_callback(NfcaPollerEvent even command = MfUltralightPollerCommandStop; } else { if(event.type == NfcaPollerEventTypeReady) { - NfcPollerBuffer* buff = instance->buffer; - nfc_poller_buffer_reset(buff); - nfca_poller_get_data(instance->nfca_poller, &instance->data->nfca_data); - - if(instance->state == MfUltralightPollerStateReadVersion) { - error = mf_ultralight_poller_async_read_version(instance); - if(error == MfUltralightErrorNone) { - FURI_LOG_I(TAG, "Read version success"); - instance->data->type = - mf_ultralight_get_type_by_version(&instance->data->version); - instance->state = MfUltralightPollerStateGetFeatureSet; - } else { - FURI_LOG_W(TAG, "Didn't response. Check NTAG 203"); - nfca_poller_halt(instance->nfca_poller); - instance->state = MfUltralightPollerStateDetectNtag203; - } - } else if(instance->state == MfUltralightPollerStateDetectNtag203) { - error = mf_ultralight_poller_async_read_page(instance, 41); - if(error == MfUltralightErrorNone) { - FURI_LOG_I(TAG, "NTAG203 detected"); - instance->data->type = MfUltralightTypeNTAG203; - instance->state = MfUltralightPollerStateGetFeatureSet; - } else { - FURI_LOG_I(TAG, "Original Ultralight detected"); - nfca_poller_halt(instance->nfca_poller); - instance->data->type = MfUltralightTypeUnknown; - instance->state = MfUltralightPollerStateGetFeatureSet; - } - } else if(instance->state == MfUltralightPollerStateGetFeatureSet) { - instance->feature_set = - mf_ultralight_get_feature_support_set(instance->data->type); - instance->pages_total = mf_ultralight_get_pages_total(instance->data->type); - instance->pages_read = 0; - instance->data->pages_total = instance->pages_total; - FURI_LOG_I( - TAG, - "%s detected. Total pages: %d", - mf_ultralight_get_name(instance->data->type, true), - instance->pages_total); - if((instance->callback) && - (instance->feature_set & MfUltralightFeatureSupportAuthentication)) { - mf_ul_poller_event.type = MfUltralightPollerEventTypeAuthRequest; - command = instance->callback(mf_ul_poller_event, instance->context); - if(!mf_ul_poller_event.data->auth_context.skip_auth) { - instance->auth_password = mf_ul_poller_event.data->auth_context.password; - instance->state = MfUltralightPollerStateAuth; - } else { - instance->state = MfUltralightPollerStateReadPages; - } - } else { - instance->state = MfUltralightPollerStateReadPages; - } - } else if(instance->state == MfUltralightPollerStateAuth) { - error = mf_ultralight_poller_async_auth(instance, &instance->auth_password); - if(error == MfUltralightErrorNone) { - FURI_LOG_I(TAG, "Auth success"); - if(instance->callback) { - mf_ul_poller_event.type = MfUltralightPollerEventTypeAuthSuccess; - memcpy( - &mf_ul_poller_event.data->pack, - &instance->data->page[instance->data->pages_read - 1], - MF_ULTRALIGHT_AUTH_PACK_SIZE); - command = instance->callback(mf_ul_poller_event, instance->context); - } - } else { - FURI_LOG_W(TAG, "Auth failed"); - if(instance->callback) { - mf_ul_poller_event.type = MfUltralightPollerEventTypeAuthFailed; - command = instance->callback(mf_ul_poller_event, instance->context); - } - nfca_poller_halt(instance->nfca_poller); - } - instance->state = MfUltralightPollerStateReadPages; - } else if(instance->state == MfUltralightPollerStateReadPages) { - error = mf_ultralight_poller_async_read_page(instance, instance->pages_read); - if(error == MfUltralightErrorNone) { - FURI_LOG_I(TAG, "Read page %d success", instance->pages_read); - instance->pages_read++; - instance->data->pages_read = instance->pages_read; - if(instance->pages_read == instance->pages_total - 2) { - instance->state = MfUltralightPollerStateReadSuccess; - } - } else { - FURI_LOG_E(TAG, "Read page %d failed", instance->pages_read); - if(instance->pages_read) { - instance->state = MfUltralightPollerStateReadSuccess; - } else { - instance->state = MfUltralightPollerStateReadFailed; - } - } - } else if(instance->state == MfUltralightPollerStateReadSignature) { - error = mf_ultralight_poller_async_read_signature(instance); - if(error == MfUltralightErrorNone) { - FURI_LOG_I(TAG, "Read signature success"); - if(instance->feature_set & MfUltralightFeatureSupportReadCounter) { - instance->state = MfUltralightPollerStateReadCounters; - } - } else { - FURI_LOG_E(TAG, "Read signature failed"); - instance->state = MfUltralightPollerStateReadFailed; - } - } else if(instance->state == MfUltralightPollerStateReadCounters) { - } else if(instance->state == MfUltralightPollerStateReadSuccess) { - if(instance->callback) { - mf_ul_poller_event.type = MfUltralightPollerEventTypeReadSuccess; - command = instance->callback(mf_ul_poller_event, instance->context); - } - } else if(instance->state == MfUltralightPollerStateReadFailed) { - if(instance->callback) { - mf_ul_poller_event.type = MfUltralightPollerEventTypeReadFailed; - command = instance->callback(mf_ul_poller_event, instance->context); - } - } + command = mf_ultralight_poller_read_handler[instance->state](instance); } else if(event.type == NfcaPollerEventTypeError) { if(instance->callback) { mf_ul_poller_event.type = MfUltralightPollerEventTypeReadFailed; @@ -531,7 +601,6 @@ MfUltralightError mf_ultralight_poller_read( instance->callback = callback; instance->context = context; - instance->state = MfUltralightPollerStateReadVersion; return mf_ultralight_poller_start(instance, mf_ultralight_poller_read_callback, instance); } @@ -561,8 +630,6 @@ MfUltralightError mf_ultralight_poller_reset(MfUltralightPoller* instance) { return MfUltralightErrorNone; } -// Called from NfcWorker thread - MfUltralightError mf_ultralight_poller_stop(MfUltralightPoller* instance) { furi_assert(instance); furi_assert(instance->nfca_poller); From b36dceef2ade83719362c850d21c3aee40be8d53 Mon Sep 17 00:00:00 2001 From: gornekich Date: Tue, 25 Apr 2023 14:37:48 +0400 Subject: [PATCH 042/149] mf ultralight: separate private and public api --- .../mf_ultralight/mf_ultralight_poller.c | 549 +----------------- .../mf_ultralight/mf_ultralight_poller_i.c | 270 +++++++++ .../mf_ultralight/mf_ultralight_poller_i.h | 87 +++ .../mf_ultralight_poller_sync_api.c | 229 ++++++++ 4 files changed, 588 insertions(+), 547 deletions(-) create mode 100644 lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c create mode 100644 lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h create mode 100644 lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c index ef291f9d1583..0aee5d04b04e 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c @@ -1,99 +1,12 @@ -#include "mf_ultralight_poller.h" - -#include +#include "mf_ultralight_poller_i.h" #include -#include -#include #define TAG "MfUltralightPoller" #define MF_ULTRALIGHT_MAX_BUFF_SIZE (64) -#define MF_ULTRALIGHT_POLLER_STANDART_FWT_FC (60000) - -#define MF_ULTRALIGHT_POLLER_COMPLETE_EVENT (1UL << 0) - -typedef struct { - MfUltralightPage page; - uint8_t page_to_write; -} MfUltralightPollerWritePageCommand; - -typedef union { - uint8_t page_to_read; - uint8_t counter_to_read; - uint8_t tearing_flag_to_read; - MfUltralightPollerWritePageCommand write_cmd; -} MfUltralightPollerContextData; - -typedef struct { - MfUltralightPoller* instance; - FuriThreadId thread_id; - MfUltralightError error; - MfUltralightPollerContextData data; -} MfUltralightPollerContext; - -typedef enum { - MfUltralightPollerStateIdle, - MfUltralightPollerStateReadVersion, - MfUltralightPollerStateDetectNtag203, - MfUltralightPollerStateGetFeatureSet, - MfUltralightPollerStateReadSignature, - MfUltralightPollerStateReadCounters, - MfUltralightPollerStateReadTearingFlags, - MfUltralightPollerStateAuth, - MfUltralightPollerStateReadPages, - MfUltralightPollerStateReadFailed, - MfUltralightPollerStateReadSuccess, - - MfUltralightPollerStateNum, -} MfUltralightPollerState; - -typedef enum { - MfUltralightPollerSessionStateIdle, - MfUltralightPollerSessionStateActive, - MfUltralightPollerSessionStateStopRequest, -} MfUltralightPollerSessionState; - -struct MfUltralightPoller { - NfcaPoller* nfca_poller; - MfUltralightPollerSessionState session_state; - MfUltralightPollerState state; - NfcPollerBuffer* buffer; - MfUltralightData* data; - MfUltralightPollerCallback callback; - MfUltralightAuthPassword auth_password; - uint32_t feature_set; - uint16_t pages_read; - uint16_t pages_total; - void* context; -}; - -static MfUltralightError mf_ultralight_process_error(NfcaError error) { - MfUltralightError ret = MfUltralightErrorNone; - - switch(error) { - case NfcaErrorNone: - ret = MfUltralightErrorNone; - break; - case NfcaErrorNotPresent: - ret = MfUltralightErrorNotPresent; - break; - case NfcaErrorColResFailed: - case NfcaErrorCommunication: - case NfcaErrorWrongCrc: - ret = MfUltralightErrorProtocol; - break; - case NfcaErrorTimeout: - ret = MfUltralightErrorTimeout; - break; - default: - ret = MfUltralightErrorProtocol; - break; - } - - return ret; -} +typedef MfUltralightPollerCommand (*MfUltralightPollerReadHandler)(MfUltralightPoller* instance); static NfcaPollerCommand mf_ultralight_process_command(MfUltralightPollerCommand command) { NfcaPollerCommand ret = NfcaPollerCommandContinue; @@ -124,245 +37,6 @@ void mf_ultralight_poller_free(MfUltralightPoller* instance) { free(instance); } -static MfUltralightError - mf_ultralight_poller_async_auth(MfUltralightPoller* instance, MfUltralightAuthPassword* data) { - NfcPollerBuffer* buff = instance->buffer; - buff->tx_data[0] = MF_ULTRALIGHT_CMD_AUTH; - // fill password in lsb - nfc_util_num2bytes(data->pass, MF_ULTRALIGHT_AUTH_PASSWORD_SIZE, &buff->tx_data[1]); - buff->tx_bits = (MF_ULTRALIGHT_AUTH_PASSWORD_SIZE + 1) * 8; - - MfUltralightError ret = MfUltralightErrorNone; - NfcaError error = NfcaErrorNone; - do { - error = nfca_poller_send_standart_frame( - instance->nfca_poller, - buff->tx_data, - buff->tx_bits, - buff->rx_data, - buff->rx_data_size, - &buff->rx_bits, - MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); - if(error != NfcaErrorNone) { - ret = mf_ultralight_process_error(error); - break; - } - if(buff->rx_bits != (MF_ULTRALIGHT_AUTH_PACK_SIZE * 8)) { - ret = MfUltralightErrorAuth; - break; - } - if(instance->pages_total != 0) { - memcpy( - &instance->data->page[instance->pages_total - 2], - data, - MF_ULTRALIGHT_AUTH_PASSWORD_SIZE); - memcpy( - &instance->data->page[instance->pages_total - 1], - buff->rx_data, - MF_ULTRALIGHT_AUTH_PACK_SIZE); - } - } while(false); - - return ret; -} - -static MfUltralightError - mf_ultralight_poller_async_read_page(MfUltralightPoller* instance, uint8_t page) { - NfcPollerBuffer* buff = instance->buffer; - buff->tx_data[0] = MF_ULTRALIGHT_CMD_READ_PAGE; - buff->tx_data[1] = page; - buff->tx_bits = 16; - - MfUltralightError ret = MfUltralightErrorNone; - NfcaError error = NfcaErrorNone; - do { - error = nfca_poller_send_standart_frame( - instance->nfca_poller, - buff->tx_data, - buff->tx_bits, - buff->rx_data, - buff->rx_data_size, - &buff->rx_bits, - MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); - if(error != NfcaErrorNone) { - ret = mf_ultralight_process_error(error); - break; - } - if(buff->rx_bits != (MF_ULTRALIGHT_PAGE_SIZE * 4) * 8) { - ret = MfUltralightErrorProtocol; - break; - } - memcpy(&instance->data->page[page], buff->rx_data, MF_ULTRALIGHT_PAGE_SIZE); - } while(false); - - return ret; -} - -static MfUltralightError mf_ultralight_poller_async_write_page( - MfUltralightPoller* instance, - uint8_t page, - MfUltralightPage* data) { - NfcPollerBuffer* buff = instance->buffer; - buff->tx_data[0] = MF_ULTRALIGHT_CMD_WRITE_PAGE; - buff->tx_data[1] = page; - memcpy(&buff->tx_data[2], data, MF_ULTRALIGHT_PAGE_SIZE); - buff->tx_bits = (2 + MF_ULTRALIGHT_PAGE_SIZE) * 8; - - MfUltralightError ret = MfUltralightErrorNone; - NfcaError error = NfcaErrorNone; - do { - error = nfca_poller_send_standart_frame( - instance->nfca_poller, - buff->tx_data, - buff->tx_bits, - buff->rx_data, - buff->rx_data_size, - &buff->rx_bits, - MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); - FURI_LOG_I(TAG, "Rx bits: %d", buff->rx_bits); - if(error != NfcaErrorNone) { - ret = mf_ultralight_process_error(error); - break; - } - if(buff->rx_bits != 4) { - ret = MfUltralightErrorProtocol; - break; - } - memcpy(&instance->data->page[page], buff->rx_data, MF_ULTRALIGHT_PAGE_SIZE); - } while(false); - - return ret; -} - -static MfUltralightError mf_ultralight_poller_async_read_version(MfUltralightPoller* instance) { - NfcPollerBuffer* buff = instance->buffer; - buff->tx_data[0] = MF_ULTRALIGHT_CMD_GET_VERSION; - buff->tx_bits = 8; - - MfUltralightError ret = MfUltralightErrorNone; - NfcaError error = NfcaErrorNone; - do { - error = nfca_poller_send_standart_frame( - instance->nfca_poller, - buff->tx_data, - buff->tx_bits, - buff->rx_data, - buff->rx_data_size, - &buff->rx_bits, - MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); - if(error != NfcaErrorNone) { - ret = mf_ultralight_process_error(error); - break; - } - if(buff->rx_bits != 8 * 8) { - ret = MfUltralightErrorProtocol; - break; - } - memcpy(&instance->data->version, buff->rx_data, sizeof(MfUltralightVersion)); - } while(false); - - return ret; -} - -static MfUltralightError mf_ultralight_poller_async_read_signature(MfUltralightPoller* instance) { - NfcPollerBuffer* buff = instance->buffer; - buff->tx_data[0] = MF_ULTRALIGTH_CMD_READ_SIG; - buff->rx_data[1] = 0x00; - buff->tx_bits = 16; - - MfUltralightError ret = MfUltralightErrorNone; - NfcaError error = NfcaErrorNone; - do { - error = nfca_poller_send_standart_frame( - instance->nfca_poller, - buff->tx_data, - buff->tx_bits, - buff->rx_data, - buff->rx_data_size, - &buff->rx_bits, - MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); - if(error != NfcaErrorNone) { - ret = mf_ultralight_process_error(error); - break; - } - if(buff->rx_bits != 32 * 8) { - ret = MfUltralightErrorProtocol; - break; - } - memcpy(&instance->data->signature, buff->rx_data, sizeof(MfUltralightSignature)); - } while(false); - - return ret; -} - -static MfUltralightError - mf_ultralight_poller_async_read_counter(MfUltralightPoller* instance, uint8_t counter_num) { - NfcPollerBuffer* buff = instance->buffer; - buff->tx_data[0] = MF_ULTRALIGHT_CMD_READ_CNT; - buff->tx_data[1] = counter_num; - buff->tx_bits = 2 * 8; - - MfUltralightError ret = MfUltralightErrorNone; - NfcaError error = NfcaErrorNone; - do { - error = nfca_poller_send_standart_frame( - instance->nfca_poller, - buff->tx_data, - buff->tx_bits, - buff->rx_data, - buff->rx_data_size, - &buff->rx_bits, - MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); - if(error != NfcaErrorNone) { - ret = mf_ultralight_process_error(error); - break; - } - if(buff->rx_bits != 3 * 8) { - ret = MfUltralightErrorProtocol; - break; - } - memcpy(&instance->data->counter[counter_num], buff->rx_data, MF_ULTRALIGHT_COUNTER_SIZE); - } while(false); - - return ret; -} - -static MfUltralightError mf_ultralight_poller_async_read_tearing_flag( - MfUltralightPoller* instance, - uint8_t tearing_falg_num) { - NfcPollerBuffer* buff = instance->buffer; - buff->tx_data[0] = MF_ULTRALIGHT_CMD_CHECK_TEARING; - buff->tx_data[1] = tearing_falg_num; - buff->tx_bits = 2 * 8; - - MfUltralightError ret = MfUltralightErrorNone; - NfcaError error = NfcaErrorNone; - do { - error = nfca_poller_send_standart_frame( - instance->nfca_poller, - buff->tx_data, - buff->tx_bits, - buff->rx_data, - buff->rx_data_size, - &buff->rx_bits, - MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); - if(error != NfcaErrorNone) { - ret = mf_ultralight_process_error(error); - break; - } - if(buff->rx_bits != 8) { - ret = MfUltralightErrorProtocol; - break; - } - memcpy( - &instance->data->tearing_flag[tearing_falg_num], - buff->rx_data, - MF_ULTRALIGHT_TEARING_FLAG_SIZE); - } while(false); - - return ret; -} - static MfUltralightPollerCommand mf_ultralight_poller_handler_idle(MfUltralightPoller* instance) { nfc_poller_buffer_reset(instance->buffer); nfca_poller_get_data(instance->nfca_poller, &instance->data->nfca_data); @@ -525,8 +199,6 @@ static MfUltralightPollerCommand return command; } -typedef MfUltralightPollerCommand (*MfUltralightPollerReadHandler)(MfUltralightPoller* instance); - static const MfUltralightPollerReadHandler mf_ultralight_poller_read_handler[MfUltralightPollerStateNum] = { [MfUltralightPollerStateIdle] = mf_ultralight_poller_handler_idle, @@ -640,220 +312,3 @@ MfUltralightError mf_ultralight_poller_stop(MfUltralightPoller* instance) { return mf_ultralight_poller_reset(instance); } - -static NfcaPollerCommand mf_ultraight_read_page_callback(NfcaPollerEvent event, void* context) { - furi_assert(context); - - MfUltralightPollerContext* poller_context = context; - if(event.type == NfcaPollerEventTypeReady) { - poller_context->error = mf_ultralight_poller_async_read_page( - poller_context->instance, poller_context->data.page_to_read); - nfca_poller_halt(poller_context->instance->nfca_poller); - } else if(event.type == NfcaPollerEventTypeError) { - poller_context->error = mf_ultralight_process_error(event.data.error); - } - furi_thread_flags_set(poller_context->thread_id, MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); - - return NfcaPollerCommandStop; -} - -MfUltralightError mf_ultralight_poller_read_page( - MfUltralightPoller* instance, - uint16_t page, - MfUltralightPage* data) { - furi_assert(instance); - furi_assert(data); - - MfUltralightPollerContext poller_context = {}; - poller_context.data.page_to_read = page; - poller_context.instance = instance; - poller_context.thread_id = furi_thread_get_current_id(); - - mf_ultralight_poller_start(instance, mf_ultraight_read_page_callback, &poller_context); - furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); - *data = instance->data->page[page]; - mf_ultralight_poller_reset(instance); - - return poller_context.error; -} - -static NfcaPollerCommand mf_ultraight_write_page_callback(NfcaPollerEvent event, void* context) { - furi_assert(context); - - MfUltralightPollerContext* poller_context = context; - if(event.type == NfcaPollerEventTypeReady) { - poller_context->error = mf_ultralight_poller_async_write_page( - poller_context->instance, - poller_context->data.write_cmd.page_to_write, - &poller_context->data.write_cmd.page); - nfca_poller_halt(poller_context->instance->nfca_poller); - } else if(event.type == NfcaPollerEventTypeError) { - poller_context->error = mf_ultralight_process_error(event.data.error); - } - mf_ultralight_poller_stop(poller_context->instance); - furi_thread_flags_set(poller_context->thread_id, MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); - - return NfcaPollerCommandStop; -} - -MfUltralightError mf_ultralight_poller_write_page( - MfUltralightPoller* instance, - uint16_t page, - MfUltralightPage* data) { - furi_assert(instance); - furi_assert(data); - - MfUltralightPollerContext poller_context = {}; - poller_context.data.write_cmd.page_to_write = page; - poller_context.data.write_cmd.page = *data; - poller_context.instance = instance; - poller_context.thread_id = furi_thread_get_current_id(); - - mf_ultralight_poller_start(instance, mf_ultraight_write_page_callback, &poller_context); - furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); - mf_ultralight_poller_reset(instance); - - return poller_context.error; -} - -static NfcaPollerCommand mf_ultraight_read_version_callback(NfcaPollerEvent event, void* context) { - furi_assert(context); - - MfUltralightPollerContext* poller_context = context; - if(event.type == NfcaPollerEventTypeReady) { - poller_context->error = mf_ultralight_poller_async_read_version(poller_context->instance); - nfca_poller_halt(poller_context->instance->nfca_poller); - } else if(event.type == NfcaPollerEventTypeError) { - poller_context->error = mf_ultralight_process_error(event.data.error); - } - mf_ultralight_poller_stop(poller_context->instance); - furi_thread_flags_set(poller_context->thread_id, MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); - - return NfcaPollerCommandStop; -} - -MfUltralightError - mf_ultralight_poller_read_version(MfUltralightPoller* instance, MfUltralightVersion* data) { - furi_assert(instance); - furi_assert(data); - MfUltralightPollerContext poller_context = {}; - poller_context.instance = instance; - poller_context.thread_id = furi_thread_get_current_id(); - - mf_ultralight_poller_start(instance, mf_ultraight_read_version_callback, &poller_context); - furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); - *data = instance->data->version; - mf_ultralight_poller_reset(instance); - - return poller_context.error; -} - -static NfcaPollerCommand - mf_ultraight_read_signature_callback(NfcaPollerEvent event, void* context) { - furi_assert(context); - - MfUltralightPollerContext* poller_context = context; - if(event.type == NfcaPollerEventTypeReady) { - poller_context->error = - mf_ultralight_poller_async_read_signature(poller_context->instance); - nfca_poller_halt(poller_context->instance->nfca_poller); - } else if(event.type == NfcaPollerEventTypeError) { - poller_context->error = mf_ultralight_process_error(event.data.error); - } - mf_ultralight_poller_stop(poller_context->instance); - furi_thread_flags_set(poller_context->thread_id, MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); - - return NfcaPollerCommandStop; -} - -MfUltralightError - mf_ultralight_poller_read_signature(MfUltralightPoller* instance, MfUltralightSignature* data) { - furi_assert(instance); - furi_assert(data); - - MfUltralightPollerContext poller_context = {}; - poller_context.instance = instance; - poller_context.thread_id = furi_thread_get_current_id(); - - mf_ultralight_poller_start(instance, mf_ultraight_read_signature_callback, &poller_context); - furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); - *data = instance->data->signature; - mf_ultralight_poller_reset(instance); - - return poller_context.error; -} - -static NfcaPollerCommand mf_ultraight_read_counter_callback(NfcaPollerEvent event, void* context) { - furi_assert(context); - - MfUltralightPollerContext* poller_context = context; - if(event.type == NfcaPollerEventTypeReady) { - poller_context->error = mf_ultralight_poller_async_read_counter( - poller_context->instance, poller_context->data.counter_to_read); - nfca_poller_halt(poller_context->instance->nfca_poller); - } else if(event.type == NfcaPollerEventTypeError) { - poller_context->error = mf_ultralight_process_error(event.data.error); - } - mf_ultralight_poller_stop(poller_context->instance); - furi_thread_flags_set(poller_context->thread_id, MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); - - return NfcaPollerCommandStop; -} - -MfUltralightError mf_ultralight_poller_read_counter( - MfUltralightPoller* instance, - uint8_t counter_num, - MfUltralightCounter* data) { - furi_assert(instance); - furi_assert(data); - - MfUltralightPollerContext poller_context = {}; - poller_context.data.counter_to_read = counter_num; - poller_context.instance = instance; - poller_context.thread_id = furi_thread_get_current_id(); - - mf_ultralight_poller_start(instance, mf_ultraight_read_counter_callback, &poller_context); - furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); - *data = instance->data->counter[counter_num]; - mf_ultralight_poller_reset(instance); - - return poller_context.error; -} - -static NfcaPollerCommand - mf_ultraight_read_tering_flag_callback(NfcaPollerEvent event, void* context) { - furi_assert(context); - - MfUltralightPollerContext* poller_context = context; - if(event.type == NfcaPollerEventTypeReady) { - poller_context->error = mf_ultralight_poller_async_read_tearing_flag( - poller_context->instance, poller_context->data.tearing_flag_to_read); - nfca_poller_halt(poller_context->instance->nfca_poller); - } else if(event.type == NfcaPollerEventTypeError) { - poller_context->error = mf_ultralight_process_error(event.data.error); - } - mf_ultralight_poller_stop(poller_context->instance); - furi_thread_flags_set(poller_context->thread_id, MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); - - return NfcaPollerCommandStop; -} - -MfUltralightError mf_ultralight_poller_read_tearing_flag( - MfUltralightPoller* instance, - uint8_t flag_num, - MfUltralightTearingFlag* data) { - furi_assert(instance); - furi_assert(data); - - MfUltralightPollerContext poller_context = {}; - poller_context.data.tearing_flag_to_read = flag_num; - poller_context.instance = instance; - poller_context.thread_id = furi_thread_get_current_id(); - - mf_ultralight_poller_start(instance, mf_ultraight_read_tering_flag_callback, &poller_context); - furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); - *data = instance->data->tearing_flag[flag_num]; - mf_ultralight_poller_reset(instance); - - return poller_context.error; -} diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c new file mode 100644 index 000000000000..65088b12cb58 --- /dev/null +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c @@ -0,0 +1,270 @@ +#include "mf_ultralight_poller_i.h" + +#include + +#define TAG "MfUltralightPoller" + +MfUltralightError mf_ultralight_process_error(NfcaError error) { + MfUltralightError ret = MfUltralightErrorNone; + + switch(error) { + case NfcaErrorNone: + ret = MfUltralightErrorNone; + break; + case NfcaErrorNotPresent: + ret = MfUltralightErrorNotPresent; + break; + case NfcaErrorColResFailed: + case NfcaErrorCommunication: + case NfcaErrorWrongCrc: + ret = MfUltralightErrorProtocol; + break; + case NfcaErrorTimeout: + ret = MfUltralightErrorTimeout; + break; + default: + ret = MfUltralightErrorProtocol; + break; + } + + return ret; +} + +MfUltralightError + mf_ultralight_poller_async_auth(MfUltralightPoller* instance, MfUltralightAuthPassword* data) { + NfcPollerBuffer* buff = instance->buffer; + buff->tx_data[0] = MF_ULTRALIGHT_CMD_AUTH; + // fill password in lsb + nfc_util_num2bytes(data->pass, MF_ULTRALIGHT_AUTH_PASSWORD_SIZE, &buff->tx_data[1]); + buff->tx_bits = (MF_ULTRALIGHT_AUTH_PASSWORD_SIZE + 1) * 8; + + MfUltralightError ret = MfUltralightErrorNone; + NfcaError error = NfcaErrorNone; + do { + error = nfca_poller_send_standart_frame( + instance->nfca_poller, + buff->tx_data, + buff->tx_bits, + buff->rx_data, + buff->rx_data_size, + &buff->rx_bits, + MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); + if(error != NfcaErrorNone) { + ret = mf_ultralight_process_error(error); + break; + } + if(buff->rx_bits != (MF_ULTRALIGHT_AUTH_PACK_SIZE * 8)) { + ret = MfUltralightErrorAuth; + break; + } + if(instance->pages_total != 0) { + memcpy( + &instance->data->page[instance->pages_total - 2], + data, + MF_ULTRALIGHT_AUTH_PASSWORD_SIZE); + memcpy( + &instance->data->page[instance->pages_total - 1], + buff->rx_data, + MF_ULTRALIGHT_AUTH_PACK_SIZE); + } + } while(false); + + return ret; +} + +MfUltralightError + mf_ultralight_poller_async_read_page(MfUltralightPoller* instance, uint8_t page) { + NfcPollerBuffer* buff = instance->buffer; + buff->tx_data[0] = MF_ULTRALIGHT_CMD_READ_PAGE; + buff->tx_data[1] = page; + buff->tx_bits = 16; + + MfUltralightError ret = MfUltralightErrorNone; + NfcaError error = NfcaErrorNone; + do { + error = nfca_poller_send_standart_frame( + instance->nfca_poller, + buff->tx_data, + buff->tx_bits, + buff->rx_data, + buff->rx_data_size, + &buff->rx_bits, + MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); + if(error != NfcaErrorNone) { + ret = mf_ultralight_process_error(error); + break; + } + if(buff->rx_bits != (MF_ULTRALIGHT_PAGE_SIZE * 4) * 8) { + ret = MfUltralightErrorProtocol; + break; + } + memcpy(&instance->data->page[page], buff->rx_data, MF_ULTRALIGHT_PAGE_SIZE); + } while(false); + + return ret; +} + +MfUltralightError mf_ultralight_poller_async_write_page( + MfUltralightPoller* instance, + uint8_t page, + MfUltralightPage* data) { + NfcPollerBuffer* buff = instance->buffer; + buff->tx_data[0] = MF_ULTRALIGHT_CMD_WRITE_PAGE; + buff->tx_data[1] = page; + memcpy(&buff->tx_data[2], data, MF_ULTRALIGHT_PAGE_SIZE); + buff->tx_bits = (2 + MF_ULTRALIGHT_PAGE_SIZE) * 8; + + MfUltralightError ret = MfUltralightErrorNone; + NfcaError error = NfcaErrorNone; + do { + error = nfca_poller_send_standart_frame( + instance->nfca_poller, + buff->tx_data, + buff->tx_bits, + buff->rx_data, + buff->rx_data_size, + &buff->rx_bits, + MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); + FURI_LOG_I(TAG, "Rx bits: %d", buff->rx_bits); + if(error != NfcaErrorNone) { + ret = mf_ultralight_process_error(error); + break; + } + if(buff->rx_bits != 4) { + ret = MfUltralightErrorProtocol; + break; + } + memcpy(&instance->data->page[page], buff->rx_data, MF_ULTRALIGHT_PAGE_SIZE); + } while(false); + + return ret; +} + +MfUltralightError mf_ultralight_poller_async_read_version(MfUltralightPoller* instance) { + NfcPollerBuffer* buff = instance->buffer; + buff->tx_data[0] = MF_ULTRALIGHT_CMD_GET_VERSION; + buff->tx_bits = 8; + + MfUltralightError ret = MfUltralightErrorNone; + NfcaError error = NfcaErrorNone; + do { + error = nfca_poller_send_standart_frame( + instance->nfca_poller, + buff->tx_data, + buff->tx_bits, + buff->rx_data, + buff->rx_data_size, + &buff->rx_bits, + MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); + if(error != NfcaErrorNone) { + ret = mf_ultralight_process_error(error); + break; + } + if(buff->rx_bits != 8 * 8) { + ret = MfUltralightErrorProtocol; + break; + } + memcpy(&instance->data->version, buff->rx_data, sizeof(MfUltralightVersion)); + } while(false); + + return ret; +} + +MfUltralightError mf_ultralight_poller_async_read_signature(MfUltralightPoller* instance) { + NfcPollerBuffer* buff = instance->buffer; + buff->tx_data[0] = MF_ULTRALIGTH_CMD_READ_SIG; + buff->rx_data[1] = 0x00; + buff->tx_bits = 16; + + MfUltralightError ret = MfUltralightErrorNone; + NfcaError error = NfcaErrorNone; + do { + error = nfca_poller_send_standart_frame( + instance->nfca_poller, + buff->tx_data, + buff->tx_bits, + buff->rx_data, + buff->rx_data_size, + &buff->rx_bits, + MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); + if(error != NfcaErrorNone) { + ret = mf_ultralight_process_error(error); + break; + } + if(buff->rx_bits != 32 * 8) { + ret = MfUltralightErrorProtocol; + break; + } + memcpy(&instance->data->signature, buff->rx_data, sizeof(MfUltralightSignature)); + } while(false); + + return ret; +} + +MfUltralightError + mf_ultralight_poller_async_read_counter(MfUltralightPoller* instance, uint8_t counter_num) { + NfcPollerBuffer* buff = instance->buffer; + buff->tx_data[0] = MF_ULTRALIGHT_CMD_READ_CNT; + buff->tx_data[1] = counter_num; + buff->tx_bits = 2 * 8; + + MfUltralightError ret = MfUltralightErrorNone; + NfcaError error = NfcaErrorNone; + do { + error = nfca_poller_send_standart_frame( + instance->nfca_poller, + buff->tx_data, + buff->tx_bits, + buff->rx_data, + buff->rx_data_size, + &buff->rx_bits, + MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); + if(error != NfcaErrorNone) { + ret = mf_ultralight_process_error(error); + break; + } + if(buff->rx_bits != 3 * 8) { + ret = MfUltralightErrorProtocol; + break; + } + memcpy(&instance->data->counter[counter_num], buff->rx_data, MF_ULTRALIGHT_COUNTER_SIZE); + } while(false); + + return ret; +} + +MfUltralightError mf_ultralight_poller_async_read_tearing_flag( + MfUltralightPoller* instance, + uint8_t tearing_falg_num) { + NfcPollerBuffer* buff = instance->buffer; + buff->tx_data[0] = MF_ULTRALIGHT_CMD_CHECK_TEARING; + buff->tx_data[1] = tearing_falg_num; + buff->tx_bits = 2 * 8; + + MfUltralightError ret = MfUltralightErrorNone; + NfcaError error = NfcaErrorNone; + do { + error = nfca_poller_send_standart_frame( + instance->nfca_poller, + buff->tx_data, + buff->tx_bits, + buff->rx_data, + buff->rx_data_size, + &buff->rx_bits, + MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); + if(error != NfcaErrorNone) { + ret = mf_ultralight_process_error(error); + break; + } + if(buff->rx_bits != 8) { + ret = MfUltralightErrorProtocol; + break; + } + memcpy( + &instance->data->tearing_flag[tearing_falg_num], + buff->rx_data, + MF_ULTRALIGHT_TEARING_FLAG_SIZE); + } while(false); + + return ret; +} diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h new file mode 100644 index 000000000000..3ed603cc720e --- /dev/null +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h @@ -0,0 +1,87 @@ +#pragma once + +#include "mf_ultralight_poller.h" +#include +#include +#include + +#define MF_ULTRALIGHT_POLLER_STANDART_FWT_FC (60000) + +typedef struct { + MfUltralightPage page; + uint8_t page_to_write; +} MfUltralightPollerWritePageCommand; + +typedef union { + uint8_t page_to_read; + uint8_t counter_to_read; + uint8_t tearing_flag_to_read; + MfUltralightPollerWritePageCommand write_cmd; +} MfUltralightPollerContextData; + +typedef enum { + MfUltralightPollerStateIdle, + MfUltralightPollerStateReadVersion, + MfUltralightPollerStateDetectNtag203, + MfUltralightPollerStateGetFeatureSet, + MfUltralightPollerStateReadSignature, + MfUltralightPollerStateReadCounters, + MfUltralightPollerStateReadTearingFlags, + MfUltralightPollerStateAuth, + MfUltralightPollerStateReadPages, + MfUltralightPollerStateReadFailed, + MfUltralightPollerStateReadSuccess, + + MfUltralightPollerStateNum, +} MfUltralightPollerState; + +typedef enum { + MfUltralightPollerSessionStateIdle, + MfUltralightPollerSessionStateActive, + MfUltralightPollerSessionStateStopRequest, +} MfUltralightPollerSessionState; + +struct MfUltralightPoller { + NfcaPoller* nfca_poller; + MfUltralightPollerSessionState session_state; + MfUltralightPollerState state; + NfcPollerBuffer* buffer; + MfUltralightData* data; + MfUltralightPollerCallback callback; + MfUltralightAuthPassword auth_password; + uint32_t feature_set; + uint16_t pages_read; + uint16_t pages_total; + void* context; +}; + +MfUltralightError mf_ultralight_process_error(NfcaError error); + +MfUltralightError + mf_ultralight_poller_async_auth(MfUltralightPoller* instance, MfUltralightAuthPassword* data); + +MfUltralightError mf_ultralight_poller_async_read_page(MfUltralightPoller* instance, uint8_t page); + +MfUltralightError mf_ultralight_poller_async_write_page( + MfUltralightPoller* instance, + uint8_t page, + MfUltralightPage* data); + +MfUltralightError mf_ultralight_poller_async_read_version(MfUltralightPoller* instance); + +MfUltralightError mf_ultralight_poller_async_read_signature(MfUltralightPoller* instance); + +MfUltralightError + mf_ultralight_poller_async_read_counter(MfUltralightPoller* instance, uint8_t counter_num); + +MfUltralightError mf_ultralight_poller_async_read_tearing_flag( + MfUltralightPoller* instance, + uint8_t tearing_falg_num); + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c new file mode 100644 index 000000000000..e9138b413c3b --- /dev/null +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c @@ -0,0 +1,229 @@ +#include "mf_ultralight_poller_i.h" + +#include + +#define MF_ULTRALIGHT_POLLER_COMPLETE_EVENT (1UL << 0) + +typedef struct { + MfUltralightPoller* instance; + FuriThreadId thread_id; + MfUltralightError error; + MfUltralightPollerContextData data; +} MfUltralightPollerContext; + +static NfcaPollerCommand mf_ultraight_read_page_callback(NfcaPollerEvent event, void* context) { + furi_assert(context); + + MfUltralightPollerContext* poller_context = context; + if(event.type == NfcaPollerEventTypeReady) { + poller_context->error = mf_ultralight_poller_async_read_page( + poller_context->instance, poller_context->data.page_to_read); + nfca_poller_halt(poller_context->instance->nfca_poller); + } else if(event.type == NfcaPollerEventTypeError) { + poller_context->error = mf_ultralight_process_error(event.data.error); + } + furi_thread_flags_set(poller_context->thread_id, MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); + + return NfcaPollerCommandStop; +} + +MfUltralightError mf_ultralight_poller_read_page( + MfUltralightPoller* instance, + uint16_t page, + MfUltralightPage* data) { + furi_assert(instance); + furi_assert(data); + + MfUltralightPollerContext poller_context = {}; + poller_context.data.page_to_read = page; + poller_context.instance = instance; + poller_context.thread_id = furi_thread_get_current_id(); + + mf_ultralight_poller_start(instance, mf_ultraight_read_page_callback, &poller_context); + furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); + *data = instance->data->page[page]; + mf_ultralight_poller_reset(instance); + + return poller_context.error; +} + +static NfcaPollerCommand mf_ultraight_write_page_callback(NfcaPollerEvent event, void* context) { + furi_assert(context); + + MfUltralightPollerContext* poller_context = context; + if(event.type == NfcaPollerEventTypeReady) { + poller_context->error = mf_ultralight_poller_async_write_page( + poller_context->instance, + poller_context->data.write_cmd.page_to_write, + &poller_context->data.write_cmd.page); + nfca_poller_halt(poller_context->instance->nfca_poller); + } else if(event.type == NfcaPollerEventTypeError) { + poller_context->error = mf_ultralight_process_error(event.data.error); + } + mf_ultralight_poller_stop(poller_context->instance); + furi_thread_flags_set(poller_context->thread_id, MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); + + return NfcaPollerCommandStop; +} + +MfUltralightError mf_ultralight_poller_write_page( + MfUltralightPoller* instance, + uint16_t page, + MfUltralightPage* data) { + furi_assert(instance); + furi_assert(data); + + MfUltralightPollerContext poller_context = {}; + poller_context.data.write_cmd.page_to_write = page; + poller_context.data.write_cmd.page = *data; + poller_context.instance = instance; + poller_context.thread_id = furi_thread_get_current_id(); + + mf_ultralight_poller_start(instance, mf_ultraight_write_page_callback, &poller_context); + furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); + mf_ultralight_poller_reset(instance); + + return poller_context.error; +} + +static NfcaPollerCommand mf_ultraight_read_version_callback(NfcaPollerEvent event, void* context) { + furi_assert(context); + + MfUltralightPollerContext* poller_context = context; + if(event.type == NfcaPollerEventTypeReady) { + poller_context->error = mf_ultralight_poller_async_read_version(poller_context->instance); + nfca_poller_halt(poller_context->instance->nfca_poller); + } else if(event.type == NfcaPollerEventTypeError) { + poller_context->error = mf_ultralight_process_error(event.data.error); + } + mf_ultralight_poller_stop(poller_context->instance); + furi_thread_flags_set(poller_context->thread_id, MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); + + return NfcaPollerCommandStop; +} + +MfUltralightError + mf_ultralight_poller_read_version(MfUltralightPoller* instance, MfUltralightVersion* data) { + furi_assert(instance); + furi_assert(data); + MfUltralightPollerContext poller_context = {}; + poller_context.instance = instance; + poller_context.thread_id = furi_thread_get_current_id(); + + mf_ultralight_poller_start(instance, mf_ultraight_read_version_callback, &poller_context); + furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); + *data = instance->data->version; + mf_ultralight_poller_reset(instance); + + return poller_context.error; +} + +static NfcaPollerCommand + mf_ultraight_read_signature_callback(NfcaPollerEvent event, void* context) { + furi_assert(context); + + MfUltralightPollerContext* poller_context = context; + if(event.type == NfcaPollerEventTypeReady) { + poller_context->error = + mf_ultralight_poller_async_read_signature(poller_context->instance); + nfca_poller_halt(poller_context->instance->nfca_poller); + } else if(event.type == NfcaPollerEventTypeError) { + poller_context->error = mf_ultralight_process_error(event.data.error); + } + mf_ultralight_poller_stop(poller_context->instance); + furi_thread_flags_set(poller_context->thread_id, MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); + + return NfcaPollerCommandStop; +} + +MfUltralightError + mf_ultralight_poller_read_signature(MfUltralightPoller* instance, MfUltralightSignature* data) { + furi_assert(instance); + furi_assert(data); + + MfUltralightPollerContext poller_context = {}; + poller_context.instance = instance; + poller_context.thread_id = furi_thread_get_current_id(); + + mf_ultralight_poller_start(instance, mf_ultraight_read_signature_callback, &poller_context); + furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); + *data = instance->data->signature; + mf_ultralight_poller_reset(instance); + + return poller_context.error; +} + +static NfcaPollerCommand mf_ultraight_read_counter_callback(NfcaPollerEvent event, void* context) { + furi_assert(context); + + MfUltralightPollerContext* poller_context = context; + if(event.type == NfcaPollerEventTypeReady) { + poller_context->error = mf_ultralight_poller_async_read_counter( + poller_context->instance, poller_context->data.counter_to_read); + nfca_poller_halt(poller_context->instance->nfca_poller); + } else if(event.type == NfcaPollerEventTypeError) { + poller_context->error = mf_ultralight_process_error(event.data.error); + } + mf_ultralight_poller_stop(poller_context->instance); + furi_thread_flags_set(poller_context->thread_id, MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); + + return NfcaPollerCommandStop; +} + +MfUltralightError mf_ultralight_poller_read_counter( + MfUltralightPoller* instance, + uint8_t counter_num, + MfUltralightCounter* data) { + furi_assert(instance); + furi_assert(data); + + MfUltralightPollerContext poller_context = {}; + poller_context.data.counter_to_read = counter_num; + poller_context.instance = instance; + poller_context.thread_id = furi_thread_get_current_id(); + + mf_ultralight_poller_start(instance, mf_ultraight_read_counter_callback, &poller_context); + furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); + *data = instance->data->counter[counter_num]; + mf_ultralight_poller_reset(instance); + + return poller_context.error; +} + +static NfcaPollerCommand + mf_ultraight_read_tering_flag_callback(NfcaPollerEvent event, void* context) { + furi_assert(context); + + MfUltralightPollerContext* poller_context = context; + if(event.type == NfcaPollerEventTypeReady) { + poller_context->error = mf_ultralight_poller_async_read_tearing_flag( + poller_context->instance, poller_context->data.tearing_flag_to_read); + nfca_poller_halt(poller_context->instance->nfca_poller); + } else if(event.type == NfcaPollerEventTypeError) { + poller_context->error = mf_ultralight_process_error(event.data.error); + } + mf_ultralight_poller_stop(poller_context->instance); + furi_thread_flags_set(poller_context->thread_id, MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); + + return NfcaPollerCommandStop; +} + +MfUltralightError mf_ultralight_poller_read_tearing_flag( + MfUltralightPoller* instance, + uint8_t flag_num, + MfUltralightTearingFlag* data) { + furi_assert(instance); + furi_assert(data); + + MfUltralightPollerContext poller_context = {}; + poller_context.data.tearing_flag_to_read = flag_num; + poller_context.instance = instance; + poller_context.thread_id = furi_thread_get_current_id(); + + mf_ultralight_poller_start(instance, mf_ultraight_read_tering_flag_callback, &poller_context); + furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); + *data = instance->data->tearing_flag[flag_num]; + mf_ultralight_poller_reset(instance); + + return poller_context.error; +} From 8c9cd1ce563a52e73ac47afd0c30a747f9fa2bbe Mon Sep 17 00:00:00 2001 From: gornekich Date: Tue, 25 Apr 2023 19:58:23 +0400 Subject: [PATCH 043/149] mf ultralight: add configuration pages --- .../protocols/mf_ultralight/mf_ultralight.h | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h index 979574083965..569836154bf7 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h @@ -105,6 +105,43 @@ typedef union { uint16_t pack; } MfUltralightAuthPack; +typedef struct __attribute__((packed)) { + union { + uint8_t value; + struct { + uint8_t rfui1 : 2; + bool strg_mod_en : 1; + bool rfui2 : 1; + uint8_t mirror_byte : 2; + MfUltralightMirrorConf mirror_conf : 2; + }; + } mirror; + uint8_t rfui1; + uint8_t mirror_page; + uint8_t auth0; + union { + uint8_t value; + struct { + uint8_t authlim : 3; + bool nfc_cnt_pwd_prot : 1; + bool nfc_cnt_en : 1; + bool nfc_dis_sec1 : 1; // NTAG I2C Plus only + bool cfglck : 1; + bool prot : 1; + }; + } access; + uint8_t vctid; + uint8_t rfui2[2]; + MfUltralightAuthPassword password; + MfUltralightAuthPack pack; + uint8_t rfui3[2]; +} MfUltralightConfigPages; + + +typedef struct { + +} MfUltralightConfigPages; + typedef struct { NfcaData nfca_data; MfUltralightType type; From 9cd685d4009dedb5ffe8ccea39f0bc09b2e9902e Mon Sep 17 00:00:00 2001 From: gornekich Date: Fri, 28 Apr 2023 17:53:18 +0400 Subject: [PATCH 044/149] mf ultralight: fix reading state machine --- .../protocols/mf_ultralight/mf_ultralight.c | 6 + .../protocols/mf_ultralight/mf_ultralight.h | 14 +- .../mf_ultralight/mf_ultralight_poller.c | 143 ++++++++++++------ .../mf_ultralight/mf_ultralight_poller_i.h | 5 + 4 files changed, 119 insertions(+), 49 deletions(-) diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight.c index 0fc647573071..ebab42f12305 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight.c @@ -145,3 +145,9 @@ bool mf_ultralight_is_all_data_read(MfUltralightData* data) { // TODO add logic return false; } + +bool mf_ultralight_is_counter_configured(MfUltralightData* data) { + furi_assert(data); + + return false; +} diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h index 569836154bf7..e956a5e121ae 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h @@ -105,6 +105,13 @@ typedef union { uint16_t pack; } MfUltralightAuthPack; +typedef enum { + MfUltralightMirrorNone, + MfUltralightMirrorUid, + MfUltralightMirrorCounter, + MfUltralightMirrorUidCounter, +} MfUltralightMirrorConf; + typedef struct __attribute__((packed)) { union { uint8_t value; @@ -137,11 +144,6 @@ typedef struct __attribute__((packed)) { uint8_t rfui3[2]; } MfUltralightConfigPages; - -typedef struct { - -} MfUltralightConfigPages; - typedef struct { NfcaData nfca_data; MfUltralightType type; @@ -166,6 +168,8 @@ bool mf_ultralight_is_all_data_read(MfUltralightData* data); bool mf_ultralight_detect_protocol(NfcaData* nfca_data); +bool mf_ultralight_is_counter_configured(MfUltralightData* data); + #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c index 0aee5d04b04e..cf26b97b9773 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c @@ -40,6 +40,11 @@ void mf_ultralight_poller_free(MfUltralightPoller* instance) { static MfUltralightPollerCommand mf_ultralight_poller_handler_idle(MfUltralightPoller* instance) { nfc_poller_buffer_reset(instance->buffer); nfca_poller_get_data(instance->nfca_poller, &instance->data->nfca_data); + instance->counters_read = 0; + instance->counters_total = 3; + instance->tearing_flag_read = 0; + instance->tearing_flag_total = 3; + instance->pages_read = 0; instance->state = MfUltralightPollerStateReadVersion; return MfUltralightPollerCommandContinue; @@ -83,7 +88,6 @@ static MfUltralightPollerCommand instance->feature_set = mf_ultralight_get_feature_support_set(instance->data->type); instance->pages_total = mf_ultralight_get_pages_total(instance->data->type); - instance->pages_read = 0; instance->data->pages_total = instance->pages_total; FURI_LOG_I( TAG, @@ -91,69 +95,113 @@ static MfUltralightPollerCommand mf_ultralight_get_name(instance->data->type, true), instance->pages_total); - if(instance->feature_set & MfUltralightFeatureSupportAuthentication) { - MfUltralightPollerEventData event_data = {}; - MfUltralightPollerEvent event = { - .type = MfUltralightPollerEventTypeAuthRequest, - .data = &event_data, - }; - - command = instance->callback(event, instance->context); - if(!event.data->auth_context.skip_auth) { - instance->auth_password = event.data->auth_context.password; - instance->state = MfUltralightPollerStateAuth; - } else { - instance->state = MfUltralightPollerStateReadPages; - } - } else { - instance->state = MfUltralightPollerStateReadPages; - } - + instance->state = MfUltralightPollerStateReadSignature; return command; } static MfUltralightPollerCommand mf_ultralight_poller_handler_read_signature(MfUltralightPoller* instance) { - FURI_LOG_D(TAG, "Reading signature"); - instance->state = MfUltralightPollerStateReadCounters; + MfUltralightPollerState next_state = MfUltralightPollerStateAuth; + if(instance->feature_set & MfUltralightFeatureSupportReadSignature) { + FURI_LOG_D(TAG, "Reading signature"); + MfUltralightError error = mf_ultralight_poller_async_read_signature(instance); + if(error != MfUltralightErrorNone) { + FURI_LOG_E(TAG, "Read signature failed"); + next_state = MfUltralightPollerStateReadFailed; + } + } else { + FURI_LOG_D(TAG, "Skip reading signature"); + } + instance->state = next_state; return MfUltralightPollerCommandContinue; } static MfUltralightPollerCommand mf_ultralight_poller_handler_read_counters(MfUltralightPoller* instance) { - FURI_LOG_D(TAG, "Reading counters"); - instance->state = MfUltralightPollerStateReadTearingFlags; + if(instance->feature_set & MfUltralightFeatureSupportReadCounter) { + if(mf_ultralight_is_counter_configured(instance->data)) { + if(instance->feature_set & MfUltralightFeatureSupportSingleCounter) { + instance->counters_read = 2; + } + if(instance->counters_read == instance->counters_total) { + instance->state = MfUltralightPollerStateReadTearingFlags; + } else { + FURI_LOG_D(TAG, "Reading counter %d", instance->counters_read); + MfUltralightError error = + mf_ultralight_poller_async_read_counter(instance, instance->counters_read); + if(error != MfUltralightErrorNone) { + FURI_LOG_E(TAG, "Failed to read %d counter", instance->counters_read); + instance->state = MfUltralightPollerStateReadFailed; + } else { + instance->counters_read++; + } + } + } else { + instance->state = MfUltralightPollerStateReadTearingFlags; + } + } else { + FURI_LOG_D(TAG, "Skip reading counters"); + instance->state = MfUltralightPollerStateReadTearingFlags; + } return MfUltralightPollerCommandContinue; } static MfUltralightPollerCommand - mf_ultralight_poller_handler_read_traring_flags(MfUltralightPoller* instance) { - FURI_LOG_D(TAG, "Reading tearing flags"); - instance->state = MfUltralightPollerStateReadTearingFlags; + mf_ultralight_poller_handler_read_tearing_flags(MfUltralightPoller* instance) { + if(instance->feature_set & MfUltralightFeatureSupportCheckTearingFlag) { + if(instance->tearing_flag_read == instance->tearing_flag_total) { + instance->state = MfUltralightPollerStateTryDefaultPass; + } else { + FURI_LOG_D(TAG, "Reading tearing flag %d", instance->tearing_flag_read); + MfUltralightError error = mf_ultralight_poller_async_read_tearing_flag( + instance, instance->tearing_flag_read); + if(error != MfUltralightErrorNone) { + FURI_LOG_E(TAG, "Reading tearing flag %d failed", instance->tearing_flag_read); + instance->state = MfUltralightPollerStateReadFailed; + } else { + instance->tearing_flag_read++; + } + } + } else { + instance->state = MfUltralightPollerStateTryDefaultPass; + } return MfUltralightPollerCommandContinue; } static MfUltralightPollerCommand mf_ultralight_poller_handler_auth(MfUltralightPoller* instance) { - FURI_LOG_D(TAG, "Trying to authenticate with password %08lX", instance->auth_password.pass); MfUltralightPollerCommand command = MfUltralightPollerCommandContinue; - - MfUltralightError error = mf_ultralight_poller_async_auth(instance, &instance->auth_password); - if(error == MfUltralightErrorNone) { - FURI_LOG_D(TAG, "Auth success"); - // TODO fill PACK in event - MfUltralightPollerEventData data = {.pack.pack = 0x8080}; + if(instance->feature_set & MfUltralightFeatureSupportAuthentication) { + MfUltralightPollerEventData event_data = {}; MfUltralightPollerEvent event = { - .type = MfUltralightPollerEventTypeAuthSuccess, .data = &data}; - command = instance->callback(event, instance->context); - } else { - FURI_LOG_W(TAG, "Auth failed"); - MfUltralightPollerEvent event = {.type = MfUltralightPollerEventTypeAuthFailed}; + .type = MfUltralightPollerEventTypeAuthRequest, + .data = &event_data, + }; + command = instance->callback(event, instance->context); - // TODO rework with HALT cmd - nfca_poller_halt(instance->nfca_poller); + if(!event.data->auth_context.skip_auth) { + instance->auth_password = event.data->auth_context.password; + FURI_LOG_D( + TAG, "Trying to authenticate with password %08lX", instance->auth_password.pass); + MfUltralightError error = + mf_ultralight_poller_async_auth(instance, &instance->auth_password); + if(error == MfUltralightErrorNone) { + FURI_LOG_D(TAG, "Auth success"); + // TODO fill PACK in event + MfUltralightPollerEventData data = {.pack.pack = 0x8080}; + MfUltralightPollerEvent event = { + .type = MfUltralightPollerEventTypeAuthSuccess, .data = &data}; + command = instance->callback(event, instance->context); + } else { + FURI_LOG_W(TAG, "Auth failed"); + MfUltralightPollerEvent event = {.type = MfUltralightPollerEventTypeAuthFailed}; + command = instance->callback(event, instance->context); + // TODO rework with HALT cmd + nfca_poller_halt(instance->nfca_poller); + } + } } instance->state = MfUltralightPollerStateReadPages; @@ -167,13 +215,13 @@ static MfUltralightPollerCommand FURI_LOG_I(TAG, "Read page %d success", instance->pages_read); instance->pages_read++; instance->data->pages_read = instance->pages_read; - if(instance->pages_read == instance->pages_total - 2) { - instance->state = MfUltralightPollerStateReadSuccess; + if(instance->pages_read == instance->pages_total) { + instance->state = MfUltralightPollerStateReadCounters; } } else { FURI_LOG_E(TAG, "Read page %d failed", instance->pages_read); if(instance->pages_read) { - instance->state = MfUltralightPollerStateReadSuccess; + instance->state = MfUltralightPollerStateReadCounters; } else { instance->state = MfUltralightPollerStateReadFailed; } @@ -182,6 +230,12 @@ static MfUltralightPollerCommand return MfUltralightPollerCommandContinue; } +static MfUltralightPollerCommand + mf_ultralight_poller_handler_try_default_pass(MfUltralightPoller* instance) { + instance->state = MfUltralightPollerStateReadSuccess; + return MfUltralightPollerCommandContinue; +} + static MfUltralightPollerCommand mf_ultralight_poller_handler_read_fail(MfUltralightPoller* instance) { FURI_LOG_W(TAG, "Read Failed"); @@ -208,8 +262,9 @@ static const MfUltralightPollerReadHandler [MfUltralightPollerStateReadSignature] = mf_ultralight_poller_handler_read_signature, [MfUltralightPollerStateReadCounters] = mf_ultralight_poller_handler_read_counters, [MfUltralightPollerStateReadTearingFlags] = - mf_ultralight_poller_handler_read_traring_flags, + mf_ultralight_poller_handler_read_tearing_flags, [MfUltralightPollerStateAuth] = mf_ultralight_poller_handler_auth, + [MfUltralightPollerStateTryDefaultPass] = mf_ultralight_poller_handler_try_default_pass, [MfUltralightPollerStateReadPages] = mf_ultralight_poller_handler_read_pages, [MfUltralightPollerStateReadFailed] = mf_ultralight_poller_handler_read_fail, [MfUltralightPollerStateReadSuccess] = mf_ultralight_poller_handler_read_success, diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h index 3ed603cc720e..413776d9f561 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h @@ -29,6 +29,7 @@ typedef enum { MfUltralightPollerStateReadTearingFlags, MfUltralightPollerStateAuth, MfUltralightPollerStateReadPages, + MfUltralightPollerStateTryDefaultPass, MfUltralightPollerStateReadFailed, MfUltralightPollerStateReadSuccess, @@ -52,6 +53,10 @@ struct MfUltralightPoller { uint32_t feature_set; uint16_t pages_read; uint16_t pages_total; + uint8_t counters_read; + uint8_t counters_total; + uint8_t tearing_flag_read; + uint8_t tearing_flag_total; void* context; }; From cc6e6dd2c979896125ab2a122a1402acb5d171ff Mon Sep 17 00:00:00 2001 From: gornekich Date: Mon, 1 May 2023 17:42:12 +0400 Subject: [PATCH 045/149] nfc app: add file select --- applications/main/nfc/nfc_app.c | 102 +++++++++++++++++- applications/main/nfc/nfc_app_i.h | 23 +++- .../main/nfc/scenes/nfc_scene_config.h | 1 + .../main/nfc/scenes/nfc_scene_file_select.c | 22 ++++ .../main/nfc/scenes/nfc_scene_start.c | 10 +- lib/nfc/nfc_dev.c | 9 +- 6 files changed, 142 insertions(+), 25 deletions(-) create mode 100644 applications/main/nfc/scenes/nfc_scene_file_select.c diff --git a/applications/main/nfc/nfc_app.c b/applications/main/nfc/nfc_app.c index a1615392ad88..1a58237e8e4a 100644 --- a/applications/main/nfc/nfc_app.c +++ b/applications/main/nfc/nfc_app.c @@ -70,6 +70,12 @@ NfcApp* nfc_app_alloc() { // Open Notification record instance->notifications = furi_record_open(RECORD_NOTIFICATION); + // Open Storage record + instance->storage = furi_record_open(RECORD_STORAGE); + + // Open Dialogs record + instance->dialogs = furi_record_open(RECORD_DIALOGS); + // Submenu instance->submenu = submenu_alloc(); view_dispatcher_add_view( @@ -110,6 +116,9 @@ NfcApp* nfc_app_alloc() { instance->widget = widget_alloc(); view_dispatcher_add_view( instance->view_dispatcher, NfcViewWidget, widget_get_view(instance->widget)); + + instance->file_path = furi_string_alloc_set(NFC_APP_FOLDER); + instance->file_name = furi_string_alloc(); return instance; } @@ -186,14 +195,18 @@ void nfc_app_free(NfcApp* instance) { // Scene Manager scene_manager_free(instance->scene_manager); + furi_record_close(RECORD_DIALOGS); + furi_record_close(RECORD_STORAGE); + furi_record_close(RECORD_NOTIFICATION); // GUI furi_record_close(RECORD_GUI); instance->gui = NULL; - // Notifications - furi_record_close(RECORD_NOTIFICATION); instance->notifications = NULL; + furi_string_free(instance->file_path); + furi_string_free(instance->file_name); + free(instance); } @@ -226,9 +239,88 @@ void nfc_blink_stop(NfcApp* nfc) { notification_message(nfc->notifications, &sequence_blink_stop); } -bool nfc_save_file(NfcApp* nfc) { - furi_assert(nfc); - return true; +void nfc_make_app_folder(NfcApp* instance) { + furi_assert(instance); + + if(!storage_simply_mkdir(instance->storage, NFC_APP_FOLDER)) { + dialog_message_show_storage_error(instance->dialogs, "Cannot create\napp folder"); + } +} + +bool nfc_save_file(NfcApp* instance, FuriString* path) { + furi_assert(instance); + furi_assert(path); + + bool result = nfc_dev_save( + instance->nfc_dev, &instance->nfc_dev_data, furi_string_get_cstr(instance->file_path)); + + if(!result) { + dialog_message_show_storage_error(instance->dialogs, "Cannot save\nkey file"); + } + + return result; +} + +bool nfc_save(NfcApp* instance) { + furi_assert(instance); + + bool result = false; + + nfc_make_app_folder(instance); + + if(furi_string_end_with(instance->file_path, NFC_APP_EXTENSION)) { + size_t filename_start = furi_string_search_rchar(instance->file_path, '/'); + furi_string_left(instance->file_path, filename_start); + } + + furi_string_cat_printf( + instance->file_path, "/%s%s", furi_string_get_cstr(instance->file_name), NFC_APP_EXTENSION); + + result = nfc_save_file(instance, instance->file_path); + return result; +} + +bool nfc_load_file(NfcApp* instance, FuriString* path, bool show_dialog) { + furi_assert(instance); + furi_assert(path); + bool result = false; + + result = nfc_dev_load(instance->nfc_dev, &instance->nfc_dev_data, furi_string_get_cstr(path)); + if(result) { + path_extract_filename(path, instance->file_name, true); + } + + if((!result) && (show_dialog)) { + dialog_message_show_storage_error(instance->dialogs, "Cannot load\nkey file"); + } + + return result; +} + +bool nfc_delete(NfcApp* instance) { + furi_assert(instance); + + return storage_simply_remove(instance->storage, furi_string_get_cstr(instance->file_path)); +} + +bool nfc_load_from_file_select(NfcApp* instance) { + furi_assert(instance); + + DialogsFileBrowserOptions browser_options; + dialog_file_browser_set_basic_options(&browser_options, NFC_APP_EXTENSION, &I_Nfc_10px); + browser_options.base_path = NFC_APP_FOLDER; + browser_options.hide_dot_files = true; + + + // Input events and views are managed by file_browser + bool result = dialog_file_browser_show( + instance->dialogs, instance->file_path, instance->file_path, &browser_options); + + if(result) { + result = nfc_load_file(instance, instance->file_path, true); + } + + return result; } void nfc_show_loading_popup(void* context, bool show) { diff --git a/applications/main/nfc/nfc_app_i.h b/applications/main/nfc/nfc_app_i.h index 2e403d2143b9..71e4c2df62ee 100644 --- a/applications/main/nfc/nfc_app_i.h +++ b/applications/main/nfc/nfc_app_i.h @@ -27,6 +27,8 @@ #include "helpers/mf_ultralight_auth.h" #include +#include +#include #include "rpc/rpc_app.h" @@ -44,6 +46,7 @@ #define NFC_TEXT_STORE_SIZE 128 #define NFC_APP_FOLDER ANY_PATH("nfc") +#define NFC_APP_EXTENSION ".nfc" typedef enum { NfcRpcStateIdle, @@ -52,8 +55,10 @@ typedef enum { } NfcRpcState; struct NfcApp { - ViewDispatcher* view_dispatcher; + DialogsApp* dialogs; + Storage* storage; Gui* gui; + ViewDispatcher* view_dispatcher; NotificationApp* notifications; SceneManager* scene_manager; @@ -86,6 +91,8 @@ struct NfcApp { NfcDev* nfc_dev; NfcDevData nfc_dev_data; + FuriString* file_path; + FuriString* file_name; }; typedef enum { @@ -115,6 +122,16 @@ void nfc_blink_detect_start(NfcApp* nfc); void nfc_blink_stop(NfcApp* nfc); -bool nfc_save_file(NfcApp* nfc); - void nfc_show_loading_popup(void* context, bool show); + +bool nfc_save(NfcApp* instance); + +bool nfc_delete(NfcApp* instance); + +bool nfc_load_from_file_select(NfcApp* instance); + +bool nfc_load_file(NfcApp* instance, FuriString* path, bool show_dialog); + +bool nfc_save_file(NfcApp* instance, FuriString* path); + +void nfc_make_app_folder(NfcApp* instance); diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index 241d6d1bc029..a84fe726fab8 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -1,4 +1,5 @@ ADD_SCENE(nfc, start, Start) +ADD_SCENE(nfc, file_select, FileSelect) ADD_SCENE(nfc, read, Read) ADD_SCENE(nfc, read_card_type, ReadCardType) ADD_SCENE(nfc, nfca_read, NfcaRead) diff --git a/applications/main/nfc/scenes/nfc_scene_file_select.c b/applications/main/nfc/scenes/nfc_scene_file_select.c new file mode 100644 index 000000000000..ffdd2e0785a8 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_file_select.c @@ -0,0 +1,22 @@ +#include "../nfc_app_i.h" + +void nfc_scene_file_select_on_enter(void* context) { + NfcApp* instance = context; + + if(nfc_load_from_file_select(instance)) { + scene_manager_next_scene(instance->scene_manager, NfcSceneNotImplemented); + } else { + scene_manager_previous_scene(instance->scene_manager); + } +} + +bool nfc_scene_file_select_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + UNUSED(event); + bool consumed = false; + return consumed; +} + +void nfc_scene_file_select_on_exit(void* context) { + UNUSED(context); +} diff --git a/applications/main/nfc/scenes/nfc_scene_start.c b/applications/main/nfc/scenes/nfc_scene_start.c index b72a6036765c..a6fea9e5a014 100644 --- a/applications/main/nfc/scenes/nfc_scene_start.c +++ b/applications/main/nfc/scenes/nfc_scene_start.c @@ -60,15 +60,7 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) { // if the user cancels loading a file, the Saved menu item // is properly reselected. scene_manager_set_scene_state(nfc->scene_manager, NfcSceneStart, SubmenuIndexSaved); - // TEST - uint8_t uid[7] = {0x44, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06}; - uint8_t atqa[2] = {0x44, 0x00}; - nfc->nfc_dev_data.nfca_data.sak = 0x00; - nfc->nfc_dev_data.nfca_data.uid_len = 7; - memcpy(nfc->nfc_dev_data.nfca_data.uid, uid, 7); - memcpy(nfc->nfc_dev_data.nfca_data.atqa, atqa, 2); - - scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcaEmulate); + scene_manager_next_scene(nfc->scene_manager, NfcSceneFileSelect); consumed = true; } else if(event.event == SubmenuIndexExtraAction) { scene_manager_set_scene_state( diff --git a/lib/nfc/nfc_dev.c b/lib/nfc/nfc_dev.c index 967870f1d168..7bf04315e328 100644 --- a/lib/nfc/nfc_dev.c +++ b/lib/nfc/nfc_dev.c @@ -3,14 +3,7 @@ #include struct NfcDev { - Storage* storage; - // DialogsApp* dialogs; - // NfcDeviceData dev_data; - // char dev_name[NFC_DEV_NAME_MAX_LEN + 1]; - // FuriString* load_path; - // FuriString* folder; - // NfcDeviceSaveFormat format; - // bool shadow_file_exist; + bool shadow_file_exist; // NfcLoadingCallback loading_cb; // void* loading_cb_ctx; From 2cde9864d3762a599f15115662a33d3de915ba3f Mon Sep 17 00:00:00 2001 From: gornekich Date: Tue, 2 May 2023 13:58:12 +0400 Subject: [PATCH 046/149] nfc app: add saved menu scene --- applications/main/nfc/nfc_app.c | 1 + .../main/nfc/scenes/nfc_scene_config.h | 1 + .../main/nfc/scenes/nfc_scene_file_select.c | 2 +- .../main/nfc/scenes/nfc_scene_saved_menu.c | 189 +++++++ lib/nfc/nfc_dev.c | 474 +++++++++++++++++- lib/nfc/nfc_dev.h | 4 + lib/nfc/nfc_device_data.h | 8 +- .../protocols/mf_ultralight/mf_ultralight.h | 4 +- 8 files changed, 676 insertions(+), 7 deletions(-) create mode 100644 applications/main/nfc/scenes/nfc_scene_saved_menu.c diff --git a/applications/main/nfc/nfc_app.c b/applications/main/nfc/nfc_app.c index 1a58237e8e4a..e68b6b9def8c 100644 --- a/applications/main/nfc/nfc_app.c +++ b/applications/main/nfc/nfc_app.c @@ -63,6 +63,7 @@ NfcApp* nfc_app_alloc() { // Nfc device instance->nfc_dev = nfc_dev_alloc(); + nfc_dev_set_loading_callback(instance->nfc_dev, nfc_show_loading_popup, instance); // Open GUI record instance->gui = furi_record_open(RECORD_GUI); diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index a84fe726fab8..810387ca36bc 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -1,5 +1,6 @@ ADD_SCENE(nfc, start, Start) ADD_SCENE(nfc, file_select, FileSelect) +ADD_SCENE(nfc, saved_menu, SavedMenu) ADD_SCENE(nfc, read, Read) ADD_SCENE(nfc, read_card_type, ReadCardType) ADD_SCENE(nfc, nfca_read, NfcaRead) diff --git a/applications/main/nfc/scenes/nfc_scene_file_select.c b/applications/main/nfc/scenes/nfc_scene_file_select.c index ffdd2e0785a8..e1edcadb1be0 100644 --- a/applications/main/nfc/scenes/nfc_scene_file_select.c +++ b/applications/main/nfc/scenes/nfc_scene_file_select.c @@ -4,7 +4,7 @@ void nfc_scene_file_select_on_enter(void* context) { NfcApp* instance = context; if(nfc_load_from_file_select(instance)) { - scene_manager_next_scene(instance->scene_manager, NfcSceneNotImplemented); + scene_manager_next_scene(instance->scene_manager, NfcSceneSavedMenu); } else { scene_manager_previous_scene(instance->scene_manager); } diff --git a/applications/main/nfc/scenes/nfc_scene_saved_menu.c b/applications/main/nfc/scenes/nfc_scene_saved_menu.c new file mode 100644 index 000000000000..b955121dbda4 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_saved_menu.c @@ -0,0 +1,189 @@ +#include "../nfc_app_i.h" +#include + +enum SubmenuIndex { + SubmenuIndexEmulate, + SubmenuIndexEditUid, + SubmenuIndexDetectReader, + SubmenuIndexWrite, + SubmenuIndexUpdate, + SubmenuIndexRename, + SubmenuIndexDelete, + SubmenuIndexInfo, + SubmenuIndexRestoreOriginal, + SubmenuIndexMfUlUnlockByReader, + SubmenuIndexMfUlUnlockByPassword, +}; + +void nfc_scene_saved_menu_submenu_callback(void* context, uint32_t index) { + NfcApp* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, index); +} + +void nfc_scene_saved_menu_on_enter(void* context) { + NfcApp* nfc = context; + Submenu* submenu = nfc->submenu; + + NfcDevData* data = &nfc->nfc_dev_data; + + if(data->protocol == NfcDevProtocolNfca) { + submenu_add_item( + submenu, + "Emulate UID", + SubmenuIndexEmulate, + nfc_scene_saved_menu_submenu_callback, + nfc); + submenu_add_item( + submenu, "Edit UID", SubmenuIndexEditUid, nfc_scene_saved_menu_submenu_callback, nfc); + } + + if(data->protocol == NfcDevProtocolMfDesfire) { + submenu_add_item( + submenu, + "Emulate UID", + SubmenuIndexEmulate, + nfc_scene_saved_menu_submenu_callback, + nfc); + } + + if((data->protocol == NfcDevProtocolMfUltralight) || + (data->protocol == NfcDevProtocolMfClassic)) { + submenu_add_item( + submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_saved_menu_submenu_callback, nfc); + } + + if(data->protocol == NfcDevProtocolMfClassic) { + // TODO + // if(!mf_classic_is_card_read(&nfc->dev->dev_data.mf_classic_data)) + submenu_add_item( + submenu, + "Detect Reader", + SubmenuIndexDetectReader, + nfc_scene_saved_menu_submenu_callback, + nfc); + submenu_add_item( + submenu, + "Write to Initial Card", + SubmenuIndexWrite, + nfc_scene_saved_menu_submenu_callback, + nfc); + submenu_add_item( + submenu, + "Update from Initial Card", + SubmenuIndexUpdate, + nfc_scene_saved_menu_submenu_callback, + nfc); + } + + submenu_add_item( + submenu, "Info", SubmenuIndexInfo, nfc_scene_saved_menu_submenu_callback, nfc); + + if(data->protocol == NfcDevProtocolMfUltralight) { + if(!mf_ultralight_is_all_data_read(&data->mf_ul_data)) { + submenu_add_item( + submenu, + "Unlock with Reader", + SubmenuIndexMfUlUnlockByReader, + nfc_scene_saved_menu_submenu_callback, + nfc); + submenu_add_item( + submenu, + "Unlock with Password", + SubmenuIndexMfUlUnlockByPassword, + nfc_scene_saved_menu_submenu_callback, + nfc); + } + } + // TODO + // if(nfc_is_shadow_file_exist) + submenu_add_item( + submenu, + "Restore to original", + SubmenuIndexRestoreOriginal, + nfc_scene_saved_menu_submenu_callback, + nfc); + + submenu_add_item( + submenu, "Rename", SubmenuIndexRename, nfc_scene_saved_menu_submenu_callback, nfc); + submenu_add_item( + submenu, "Delete", SubmenuIndexDelete, nfc_scene_saved_menu_submenu_callback, nfc); + submenu_set_selected_item( + nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneSavedMenu)); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); +} + +bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + + NfcDevData* data = &nfc->nfc_dev_data; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneSavedMenu, event.event); + if(event.event == SubmenuIndexEmulate) { + if(data->protocol == NfcDevProtocolMfUltralight) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + } else if(data->protocol == NfcDevProtocolMfClassic) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + } else { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcaEmulate); + } + DOLPHIN_DEED(DolphinDeedNfcEmulate); + consumed = true; + } else if(event.event == SubmenuIndexDetectReader) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + DOLPHIN_DEED(DolphinDeedNfcDetectReader); + consumed = true; + } else if(event.event == SubmenuIndexWrite) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + consumed = true; + } else if(event.event == SubmenuIndexUpdate) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + consumed = true; + } else if(event.event == SubmenuIndexRename) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + consumed = true; + } else if(event.event == SubmenuIndexEditUid) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + consumed = true; + } else if(event.event == SubmenuIndexDelete) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + consumed = true; + } else if(event.event == SubmenuIndexInfo) { + // bool application_info_present = false; + // if( + // dev_data->protocol == NfcDeviceProtocolMifareClassic || + // dev_data->protocol == NfcDeviceProtocolMifareUl) { + // application_info_present = nfc_supported_card_verify_and_parse(dev_data); + // } + + // FURI_LOG_I("nfc", "application_info_present: %d", application_info_present); + + // if(application_info_present) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + // } else { + // scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); + // } + consumed = true; + } else if(event.event == SubmenuIndexRestoreOriginal) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + consumed = true; + } else if(event.event == SubmenuIndexMfUlUnlockByReader) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + consumed = true; + } else if(event.event == SubmenuIndexMfUlUnlockByPassword) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockMenu); + consumed = true; + } + } + + return consumed; +} + +void nfc_scene_saved_menu_on_exit(void* context) { + NfcApp* nfc = context; + + submenu_reset(nfc->submenu); +} diff --git a/lib/nfc/nfc_dev.c b/lib/nfc/nfc_dev.c index 7bf04315e328..7bbcaf61e8bd 100644 --- a/lib/nfc/nfc_dev.c +++ b/lib/nfc/nfc_dev.c @@ -1,12 +1,400 @@ #include "nfc_dev.h" #include +#include + +static const char* nfc_file_header = "Flipper NFC device"; +static const uint32_t nfc_file_version = 3; +static const uint32_t nfc_file_version_with_lsb_atqa = 2; + +// static const char* nfc_keys_file_header = "Flipper NFC keys"; +// static const uint32_t nfc_keys_file_version = 1; + +// // Protocols format versions +// static const uint32_t nfc_mifare_classic_data_format_version = 2; +static const uint32_t nfc_mifare_ultralight_data_format_version = 1; struct NfcDev { bool shadow_file_exist; - // NfcLoadingCallback loading_cb; - // void* loading_cb_ctx; + NfcLoadingCallback loading_callback; + void* loading_callback_context; +}; + +typedef bool (*NfcDevVerifyProtocol)(FuriString* device_type, NfcDevData* data); +typedef bool (*NfcDevDataHandler)(FlipperFormat* file, uint32_t version, NfcDevData* data); + +typedef struct { + NfcDevVerifyProtocol verify_handler; + NfcDevDataHandler load_handler; + NfcDevDataHandler save_handler; +} NfcDevDataParser; + +static bool nfc_dev_nfca_load_data(FlipperFormat* file, uint32_t version, NfcaData* data) { + furi_assert(file); + furi_assert(data); + + uint32_t data_cnt = 0; + bool parsed = false; + + do { + if(!flipper_format_get_value_count(file, "UID", &data_cnt)) break; + if(!(data_cnt == 4 || data_cnt == 7)) break; + data->uid_len = data_cnt; + if(!flipper_format_read_hex(file, "UID", data->uid, data->uid_len)) break; + if(version == nfc_file_version_with_lsb_atqa) { + if(!flipper_format_read_hex(file, "ATQA", data->atqa, 2)) break; + } else { + uint8_t atqa[2] = {}; + if(!flipper_format_read_hex(file, "ATQA", atqa, 2)) break; + data->atqa[0] = atqa[1]; + data->atqa[1] = atqa[0]; + } + if(!flipper_format_read_hex(file, "SAK", &data->sak, 1)) break; + + parsed = true; + } while(false); + + return parsed; +} + +static bool nfc_dev_nfca_save_data(FlipperFormat* file, NfcaData* data) { + furi_assert(file); + furi_assert(data); + + bool saved = false; + do { + // Write UID, ATQA, SAK + if(!flipper_format_write_comment_cstr(file, "UID, ATQA and SAK are common for all formats")) + break; + if(!flipper_format_write_hex(file, "UID", data->uid, data->uid_len)) break; + // Save ATQA in MSB order for correct companion apps display + uint8_t atqa[2] = {data->atqa[1], data->atqa[0]}; + if(!flipper_format_write_hex(file, "ATQA", atqa, 2)) break; + if(!flipper_format_write_hex(file, "SAK", &data->sak, 1)) break; + saved = true; + } while(false); + + return saved; +} + +static bool nfc_dev_nfca_verify_handler(FuriString* device_type, NfcDevData* data) { + furi_assert(device_type); + furi_assert(data); + + bool verified = (furi_string_cmp_str(device_type, "UID") == 0); + if(verified) { + data->protocol = NfcDevProtocolNfca; + } + + return verified; +} + +static bool nfc_dev_nfca_save_handler(FlipperFormat* file, uint32_t version, NfcDevData* data) { + furi_assert(file); + furi_assert(data); + UNUSED(version); + + bool saved = false; + do { + if(!flipper_format_write_string_cstr(file, "Device type", "UID")) break; + if(!nfc_dev_nfca_save_data(file, &data->nfca_data)) break; + saved = true; + } while(false); + + return saved; +} + +static bool nfc_dev_nfca_load_handler(FlipperFormat* file, uint32_t version, NfcDevData* data) { + furi_assert(file); + furi_assert(data); + UNUSED(version); + + return nfc_dev_nfca_load_data(file, version, &data->nfca_data); +} + +static bool nfc_dev_mf_ultralight_verify_handler(FuriString* device_type, NfcDevData* data) { + furi_assert(device_type); + furi_assert(data); + + bool verified = false; + for(size_t i = 0; i < MfUltralightTypeNum; i++) { + const char* name = mf_ultralight_get_name(i, true); + verified = furi_string_equal_str(device_type, name); + if(verified) { + data->mf_ul_data.type = i; + break; + } + } + + return verified; +} + +static bool + nfc_dev_mf_ultralight_save_handler(FlipperFormat* file, uint32_t version, NfcDevData* data) { + furi_assert(file); + furi_assert(data); + UNUSED(version); + + FuriString* temp_str = furi_string_alloc(); + MfUltralightData* mfu_data = &data->mf_ul_data; + bool saved = false; + do { + if(!nfc_dev_nfca_save_data(file, &data->nfca_data)) break; + if(!flipper_format_write_comment_cstr(file, "Mifare Ultralight specific data")) break; + if(!flipper_format_write_uint32( + file, "Data format version", &nfc_mifare_ultralight_data_format_version, 1)) + break; + if(!flipper_format_write_hex( + file, "Signature", mfu_data->signature.data, sizeof(MfUltralightSignature))) + break; + if(!flipper_format_write_hex( + file, "Mifare version", (uint8_t*)&mfu_data->version, sizeof(MfUltralightVersion))) + break; + + // Write conters and tearing flags data + bool counters_saved = true; + for(size_t i = 0; i < 3; i++) { + furi_string_printf(temp_str, "Counter %d", i); + if(!flipper_format_write_uint32( + file, furi_string_get_cstr(temp_str), &mfu_data->counter[i].counter, 1)) { + counters_saved = false; + break; + } + furi_string_printf(temp_str, "Tearing %d", i); + if(!flipper_format_write_hex( + file, furi_string_get_cstr(temp_str), mfu_data->tearing_flag->data, 1)) { + counters_saved = false; + break; + } + } + if(!counters_saved) break; + + // Write pages data + if(!flipper_format_write_uint32(file, "Pages total", (uint32_t*)&mfu_data->pages_total, 1)) + break; + if(!flipper_format_write_uint32(file, "Pages read", (uint32_t*)&mfu_data->pages_read, 1)) + break; + bool pages_saved = true; + for(size_t i = 0; i < mfu_data->pages_total; i++) { + furi_string_printf(temp_str, "Page %d", i); + if(!flipper_format_write_hex( + file, + furi_string_get_cstr(temp_str), + mfu_data->page[i].data, + sizeof(MfUltralightPage))) { + pages_saved = false; + break; + } + } + if(!pages_saved) break; + + // Write authentication counter + if(!flipper_format_write_uint32( + file, "Failed authentication attempts", &mfu_data->auth_attempts, 1)) + break; + + saved = true; + } while(false); + + furi_string_free(temp_str); + + return saved; +} + +static bool + nfc_dev_mf_ultralight_load_handler(FlipperFormat* file, uint32_t version, NfcDevData* data) { + furi_assert(file); + furi_assert(data); + + FuriString* temp_str = furi_string_alloc(); + bool parsed = false; + do { + // Read NFCA data + if(!nfc_dev_nfca_load_data(file, version, &data->mf_ul_data.nfca_data)) break; + + // Read Ultralight specific data + // Read Mifare Ultralight format version + uint32_t data_format_version = 0; + if(!flipper_format_read_uint32(file, "Data format version", &data_format_version, 1)) { + if(!flipper_format_rewind(file)) break; + } + + // Read signature + MfUltralightData* mfu_data = &data->mf_ul_data; + if(!flipper_format_read_hex( + file, "Signature", mfu_data->signature.data, sizeof(MfUltralightSignature))) + break; + // Read Mifare version + if(!flipper_format_read_hex( + file, "Mifare version", (uint8_t*)&mfu_data->version, sizeof(MfUltralightVersion))) + break; + // Read counters and tearing flags + bool counters_parsed = true; + for(size_t i = 0; i < 3; i++) { + furi_string_printf(temp_str, "Counter %d", i); + if(!flipper_format_read_uint32( + file, furi_string_get_cstr(temp_str), &mfu_data->counter[i].counter, 1)) { + counters_parsed = false; + break; + } + furi_string_printf(temp_str, "Tearing %d", i); + if(!flipper_format_read_hex( + file, furi_string_get_cstr(temp_str), mfu_data->tearing_flag[i].data, 1)) { + counters_parsed = false; + break; + } + } + if(!counters_parsed) break; + // Read pages + uint32_t pages_total = 0; + if(!flipper_format_read_uint32(file, "Pages total", &pages_total, 1)) break; + uint32_t pages_read = 0; + if(data_format_version < nfc_mifare_ultralight_data_format_version) { + pages_read = pages_total; + } else { + if(!flipper_format_read_uint32(file, "Pages read", &pages_read, 1)) break; + } + mfu_data->pages_total = pages_total; + mfu_data->pages_read = pages_read; + + // data->data_size = pages_total * 4; + // data->data_read = pages_read * 4; + if((pages_read > MF_ULTRALIGHT_MAX_PAGE_NUM) || (pages_total > MF_ULTRALIGHT_MAX_PAGE_NUM)) + break; + + bool pages_parsed = true; + for(size_t i = 0; i < pages_total; i++) { + furi_string_printf(temp_str, "Page %d", i); + if(!flipper_format_read_hex( + file, + furi_string_get_cstr(temp_str), + mfu_data->page[i].data, + sizeof(MfUltralightPage))) { + pages_parsed = false; + break; + } + } + if(!pages_parsed) break; + + // Read authentication counter + if(!flipper_format_read_uint32( + file, "Failed authentication attempts", &mfu_data->auth_attempts, 1)) { + mfu_data->auth_attempts = 0; + } + + parsed = true; + } while(false); + + furi_string_free(temp_str); + + return parsed; +} + +static bool nfc_dev_mf_classic_verify_handler(FuriString* device_type, NfcDevData* data) { + furi_assert(device_type); + furi_assert(data); + + return furi_string_start_with_str(device_type, "Mifare Classic"); +} + +static bool + nfc_dev_mf_classic_save_handler(FlipperFormat* file, uint32_t version, NfcDevData* data) { + furi_assert(file); + furi_assert(data); + UNUSED(version); + + bool saved = false; + + do { + if(!nfc_dev_nfca_save_data(file, &data->nfca_data)) break; + saved = true; + } while(false); + + return saved; +} + +static bool + nfc_dev_mf_classic_load_handler(FlipperFormat* file, uint32_t version, NfcDevData* data) { + furi_assert(file); + furi_assert(data); + + bool parsed = false; + do { + // Read NFCA data + if(!nfc_dev_nfca_load_data(file, version, &data->mf_ul_data.nfca_data)) break; + + parsed = true; + } while(false); + + return parsed; +} + +static bool nfc_dev_mf_desfire_verify_handler(FuriString* device_type, NfcDevData* data) { + furi_assert(device_type); + furi_assert(data); + + return furi_string_start_with_str(device_type, "Mifare Desfire"); +} + +static bool + nfc_dev_mf_desfire_save_handler(FlipperFormat* file, uint32_t version, NfcDevData* data) { + furi_assert(file); + furi_assert(data); + UNUSED(version); + + bool saved = false; + + do { + if(!nfc_dev_nfca_save_data(file, &data->nfca_data)) break; + saved = true; + } while(false); + + return saved; +} + +static bool + nfc_dev_mf_desfire_load_handler(FlipperFormat* file, uint32_t version, NfcDevData* data) { + furi_assert(file); + furi_assert(data); + + bool parsed = false; + do { + // Read NFCA data + if(!nfc_dev_nfca_load_data(file, version, &data->mf_ul_data.nfca_data)) break; + + parsed = true; + } while(false); + + return parsed; +} + +static const NfcDevDataParser nfc_dev_data_parser[NfcDevProtocolNum] = { + [NfcDevProtocolNfca] = + { + .verify_handler = nfc_dev_nfca_verify_handler, + .save_handler = nfc_dev_nfca_save_handler, + .load_handler = nfc_dev_nfca_load_handler, + }, + [NfcDevProtocolMfUltralight] = + { + .verify_handler = nfc_dev_mf_ultralight_verify_handler, + .save_handler = nfc_dev_mf_ultralight_save_handler, + .load_handler = nfc_dev_mf_ultralight_load_handler, + }, + [NfcDevProtocolMfClassic] = + { + .verify_handler = nfc_dev_mf_classic_verify_handler, + .save_handler = nfc_dev_mf_classic_save_handler, + .load_handler = nfc_dev_mf_classic_load_handler, + }, + [NfcDevProtocolMfDesfire] = + { + .verify_handler = nfc_dev_mf_desfire_verify_handler, + .save_handler = nfc_dev_mf_desfire_save_handler, + .load_handler = nfc_dev_mf_desfire_load_handler, + }, + }; NfcDev* nfc_dev_alloc() { @@ -19,12 +407,57 @@ void nfc_dev_free(NfcDev* instance) { furi_assert(instance); } +void nfc_dev_set_loading_callback(NfcDev* instance, NfcLoadingCallback callback, void* context) { + furi_assert(instance); + furi_assert(callback); + + instance->loading_callback = callback; + instance->loading_callback_context = context; +} + bool nfc_dev_save(NfcDev* instance, NfcDevData* data, const char* path) { furi_assert(instance); furi_assert(data); furi_assert(path); bool saved = false; + Storage* storage = furi_record_open(RECORD_STORAGE); + FlipperFormat* file = flipper_format_file_alloc(storage); + + FuriString* temp_str; + temp_str = furi_string_alloc(); + + if(instance->loading_callback) { + instance->loading_callback(instance->loading_callback_context, true); + } + + do { + // Open file + if(!flipper_format_file_open_always(file, path)) break; + + // Write header + if(!flipper_format_write_header_cstr(file, nfc_file_header, nfc_file_version)) break; + + // Write nfc device type + if(!flipper_format_write_comment_cstr( + file, "Nfc device type can be UID, Mifare Ultralight, Mifare Classic")) + break; + + for(size_t i = 0; i < COUNT_OF(nfc_dev_data_parser); i++) { + if(data->protocol == i) { + saved = nfc_dev_data_parser[i].save_handler(file, nfc_file_version, data); + } + if(saved) break; + } + } while(false); + + if(instance->loading_callback) { + instance->loading_callback(instance->loading_callback_context, false); + } + + furi_string_free(temp_str); + flipper_format_free(file); + furi_record_close(RECORD_STORAGE); return saved; } @@ -35,6 +468,43 @@ bool nfc_dev_load(NfcDev* instance, NfcDevData* data, const char* path) { furi_assert(path); bool loaded = false; + Storage* storage = furi_record_open(RECORD_STORAGE); + FlipperFormat* file = flipper_format_file_alloc(storage); + + FuriString* temp_str; + temp_str = furi_string_alloc(); + + if(instance->loading_callback) { + instance->loading_callback(instance->loading_callback_context, true); + } + + do { + if(!flipper_format_file_open_existing(file, path)) break; + + // Read and verify file header + uint32_t version = 0; + if(!flipper_format_read_header(file, temp_str, &version)) break; + if(furi_string_cmp_str(temp_str, nfc_file_header)) break; + if(version < nfc_file_version_with_lsb_atqa) break; + + // Read Nfc device type + if(!flipper_format_read_string(file, "Device type", temp_str)) break; + + for(size_t i = 0; i < COUNT_OF(nfc_dev_data_parser); i++) { + if(nfc_dev_data_parser[i].verify_handler(temp_str, data)) { + loaded = nfc_dev_data_parser[i].load_handler(file, version, data); + } + if(loaded) break; + } + } while(false); + + if(instance->loading_callback) { + instance->loading_callback(instance->loading_callback_context, false); + } + + furi_string_free(temp_str); + flipper_format_free(file); + furi_record_close(RECORD_STORAGE); return loaded; } diff --git a/lib/nfc/nfc_dev.h b/lib/nfc/nfc_dev.h index 2385b6ed2281..c8f45e176f03 100644 --- a/lib/nfc/nfc_dev.h +++ b/lib/nfc/nfc_dev.h @@ -8,10 +8,14 @@ extern "C" { typedef struct NfcDev NfcDev; +typedef void (*NfcLoadingCallback)(void* context, bool state); + NfcDev* nfc_dev_alloc(); void nfc_dev_free(NfcDev* instance); +void nfc_dev_set_loading_callback(NfcDev* instance, NfcLoadingCallback callback, void* context); + bool nfc_dev_save(NfcDev* instance, NfcDevData* data, const char* path); bool nfc_dev_load(NfcDev* instance, NfcDevData* data, const char* path); diff --git a/lib/nfc/nfc_device_data.h b/lib/nfc/nfc_device_data.h index e8650a848c27..ede9a544412d 100644 --- a/lib/nfc/nfc_device_data.h +++ b/lib/nfc/nfc_device_data.h @@ -10,12 +10,14 @@ extern "C" { typedef enum { NfcDevProtocolNfca, - NfcDevProtocolNfcb, - NfcDevProtocolNfcf, - NfcDevProtocolNfcv, + // NfcDevProtocolNfcb, + // NfcDevProtocolNfcf, + // NfcDevProtocolNfcv, NfcDevProtocolMfUltralight, NfcDevProtocolMfClassic, NfcDevProtocolMfDesfire, + + NfcDevProtocolNum, } NfcDevProtocol; typedef struct { diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h index e956a5e121ae..26940d9573b4 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h @@ -87,7 +87,8 @@ typedef struct { uint8_t data[MF_ULTRALIGHT_SIGNATURE_SIZE]; } MfUltralightSignature; -typedef struct { +typedef union { + uint32_t counter; uint8_t data[MF_ULTRALIGHT_COUNTER_SIZE]; } MfUltralightCounter; @@ -154,6 +155,7 @@ typedef struct { MfUltralightPage page[MF_ULTRALIGHT_MAX_PAGE_NUM]; uint16_t pages_read; uint16_t pages_total; + uint32_t auth_attempts; } MfUltralightData; MfUltralightType mf_ultralight_get_type_by_version(MfUltralightVersion* version); From a40a4a6abe41bab5818128769903ff99b5339c7c Mon Sep 17 00:00:00 2001 From: gornekich Date: Tue, 2 May 2023 16:55:21 +0400 Subject: [PATCH 047/149] nfc app: add saving --- applications/main/nfc/nfc_app_i.h | 6 ++ .../main/nfc/scenes/nfc_scene_config.h | 2 + .../nfc/scenes/nfc_scene_mf_ultralight_menu.c | 2 +- .../main/nfc/scenes/nfc_scene_save_name.c | 88 +++++++++++++++++++ .../main/nfc/scenes/nfc_scene_save_success.c | 48 ++++++++++ 5 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 applications/main/nfc/scenes/nfc_scene_save_name.c create mode 100644 applications/main/nfc/scenes/nfc_scene_save_success.c diff --git a/applications/main/nfc/nfc_app_i.h b/applications/main/nfc/nfc_app_i.h index 71e4c2df62ee..6913bb4ef97b 100644 --- a/applications/main/nfc/nfc_app_i.h +++ b/applications/main/nfc/nfc_app_i.h @@ -44,6 +44,11 @@ #include +#include +#include +#include + +#define NFC_NAME_SIZE 22 #define NFC_TEXT_STORE_SIZE 128 #define NFC_APP_FOLDER ANY_PATH("nfc") #define NFC_APP_EXTENSION ".nfc" @@ -91,6 +96,7 @@ struct NfcApp { NfcDev* nfc_dev; NfcDevData nfc_dev_data; + NfcaData nfca_edit_data; FuriString* file_path; FuriString* file_name; }; diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index 810387ca36bc..15919915b795 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -1,6 +1,8 @@ ADD_SCENE(nfc, start, Start) ADD_SCENE(nfc, file_select, FileSelect) ADD_SCENE(nfc, saved_menu, SavedMenu) +ADD_SCENE(nfc, save_name, SaveName) +ADD_SCENE(nfc, save_success, SaveSuccess) ADD_SCENE(nfc, read, Read) ADD_SCENE(nfc, read_card_type, ReadCardType) ADD_SCENE(nfc, nfca_read, NfcaRead) diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c index 6a22bf2e1d68..4525fab97a7c 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c @@ -50,7 +50,7 @@ bool nfc_scene_mf_ultralight_menu_on_event(void* context, SceneManagerEvent even if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubmenuIndexSave) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); consumed = true; } else if(event.event == SubmenuIndexEmulate) { scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); diff --git a/applications/main/nfc/scenes/nfc_scene_save_name.c b/applications/main/nfc/scenes/nfc_scene_save_name.c new file mode 100644 index 000000000000..5e0e47306396 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_save_name.c @@ -0,0 +1,88 @@ +#include "../nfc_app_i.h" +#include + +void nfc_scene_save_name_text_input_callback(void* context) { + NfcApp* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventTextInputDone); +} + +void nfc_scene_save_name_on_enter(void* context) { + NfcApp* nfc = context; + FuriString* folder_path = furi_string_alloc(); + TextInput* text_input = nfc->text_input; + + bool name_is_empty = furi_string_empty(nfc->file_name); + if(name_is_empty) { + furi_string_set(nfc->file_path, NFC_APP_FOLDER); + set_random_name(nfc->text_store, NFC_TEXT_STORE_SIZE); + furi_string_set(folder_path, NFC_APP_FOLDER); + } else { + nfc_text_store_set(nfc, "%s", furi_string_get_cstr(nfc->file_name)); + path_extract_dirname(furi_string_get_cstr(nfc->file_path), folder_path); + } + + text_input_set_header_text(text_input, "Name the card"); + text_input_set_result_callback( + text_input, + nfc_scene_save_name_text_input_callback, + nfc, + nfc->text_store, + NFC_NAME_SIZE, + name_is_empty); + + ValidatorIsFile* validator_is_file = validator_is_file_alloc_init( + furi_string_get_cstr(folder_path), + NFC_APP_EXTENSION, + furi_string_get_cstr(nfc->file_name)); + text_input_set_validator(text_input, validator_is_file_callback, validator_is_file); + + furi_string_free(folder_path); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextInput); +} + +bool nfc_scene_save_name_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventTextInputDone) { + if(!furi_string_empty(nfc->file_name)) { + nfc_delete(nfc); + } + furi_string_set(nfc->file_name, nfc->text_store); + + // TODO uncoment + // if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetUid)) { + // nfc->dev->dev_data.nfc_data = nfc->dev_edit_data; + // } + + if(nfc_save(nfc)) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess); + // if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) { + // DOLPHIN_DEED(DolphinDeedNfcAddSave); + // } else { + DOLPHIN_DEED(DolphinDeedNfcSave); + // } + consumed = true; + } else { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneStart); + } + } + } + + return consumed; +} + +void nfc_scene_save_name_on_exit(void* context) { + NfcApp* nfc = context; + + // Clear view + void* validator_context = text_input_get_validator_callback_context(nfc->text_input); + text_input_set_validator(nfc->text_input, NULL, NULL); + validator_is_file_free(validator_context); + + text_input_reset(nfc->text_input); +} diff --git a/applications/main/nfc/scenes/nfc_scene_save_success.c b/applications/main/nfc/scenes/nfc_scene_save_success.c new file mode 100644 index 000000000000..106bcf94ffd7 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_save_success.c @@ -0,0 +1,48 @@ +#include "../nfc_app_i.h" + +void nfc_scene_save_success_popup_callback(void* context) { + NfcApp* nfc = context; + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); +} + +void nfc_scene_save_success_on_enter(void* context) { + NfcApp* nfc = context; + + // Setup view + Popup* popup = nfc->popup; + popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); + popup_set_header(popup, "Saved!", 13, 22, AlignLeft, AlignBottom); + popup_set_timeout(popup, 1500); + popup_set_context(popup, nfc); + popup_set_callback(popup, nfc_scene_save_success_popup_callback); + popup_enable_timeout(popup); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); +} + +bool nfc_scene_save_success_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventViewExit) { + // if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneMfClassicKeys)) { + // consumed = scene_manager_search_and_switch_to_previous_scene( + // nfc->scene_manager, NfcSceneMfClassicKeys); + // } else if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSavedMenu)) { + // consumed = scene_manager_search_and_switch_to_previous_scene( + // nfc->scene_manager, NfcSceneSavedMenu); + // } else { + consumed = scene_manager_search_and_switch_to_another_scene( + nfc->scene_manager, NfcSceneFileSelect); + // } + } + } + return consumed; +} + +void nfc_scene_save_success_on_exit(void* context) { + NfcApp* nfc = context; + + // Clear view + popup_reset(nfc->popup); +} From 8cb631d85e062f2914ed66b06dc91acb979d6257 Mon Sep 17 00:00:00 2001 From: gornekich Date: Tue, 2 May 2023 23:35:00 +0400 Subject: [PATCH 048/149] nfc: rework nfc data generators --- lib/nfc/helpers/nfc_data_generator.c | 381 ++++++++++++++++++ lib/nfc/helpers/nfc_data_generator.h | 40 ++ lib/nfc/nfc_device_data.h | 2 +- .../protocols/mf_ultralight/mf_ultralight.h | 2 + 4 files changed, 424 insertions(+), 1 deletion(-) create mode 100644 lib/nfc/helpers/nfc_data_generator.c create mode 100644 lib/nfc/helpers/nfc_data_generator.h diff --git a/lib/nfc/helpers/nfc_data_generator.c b/lib/nfc/helpers/nfc_data_generator.c new file mode 100644 index 000000000000..4408b7ee3970 --- /dev/null +++ b/lib/nfc/helpers/nfc_data_generator.c @@ -0,0 +1,381 @@ +#include "nfc_data_generator.h" + +#include +#include + +#define NXP_MANUFACTURER_ID (0x04) + +typedef void (*NfcDataGeneratorHandler)(NfcDevData* data); + +typedef struct { + const char* name; + NfcDataGeneratorHandler handler; +} NfcDataGenerator; + +static const uint8_t version_bytes_mf0ulx1[] = {0x00, 0x04, 0x03, 0x00, 0x01, 0x00, 0x00, 0x03}; +static const uint8_t version_bytes_ntag21x[] = {0x00, 0x04, 0x04, 0x02, 0x01, 0x00, 0x00, 0x03}; +static const uint8_t version_bytes_ntag_i2c[] = {0x00, 0x04, 0x04, 0x05, 0x02, 0x00, 0x00, 0x03}; +static const uint8_t default_data_ntag203[] = + {0xE1, 0x10, 0x12, 0x00, 0x01, 0x03, 0xA0, 0x10, 0x44, 0x03, 0x00, 0xFE}; +static const uint8_t default_data_ntag213[] = {0x01, 0x03, 0xA0, 0x0C, 0x34, 0x03, 0x00, 0xFE}; +static const uint8_t default_data_ntag215_216[] = {0x03, 0x00, 0xFE}; +static const uint8_t default_data_ntag_i2c[] = {0xE1, 0x10, 0x00, 0x00, 0x03, 0x00, 0xFE}; +static const uint8_t default_config_ntag_i2c[] = {0x01, 0x00, 0xF8, 0x48, 0x08, 0x01, 0x00, 0x00}; + +static void nfc_generate_common_start(NfcDevData* data) { + memset(data, 0, sizeof(NfcDevData)); +} + +static void nfc_generate_mf_ul_uid(uint8_t* uid) { + uid[0] = NXP_MANUFACTURER_ID; + furi_hal_random_fill_buf(&uid[1], 6); + // I'm not sure how this is generated, but the upper nybble always seems to be 8 + uid[6] &= 0x0F; + uid[6] |= 0x80; +} + +static void nfc_generate_mf_ul_common(NfcDevData* data) { + MfUltralightData* mfu_data = &data->mf_ul_data; + mfu_data->nfca_data.uid_len = 7; + nfc_generate_mf_ul_uid(mfu_data->nfca_data.uid); + mfu_data->nfca_data.atqa[0] = 0x44; + mfu_data->nfca_data.atqa[1] = 0x00; + mfu_data->nfca_data.sak = 0x00; + data->protocol = NfcDevProtocolMfUltralight; +} + +static void nfc_generate_calc_bcc(uint8_t* uid, uint8_t* bcc0, uint8_t* bcc1) { + *bcc0 = 0x88 ^ uid[0] ^ uid[1] ^ uid[2]; + *bcc1 = uid[3] ^ uid[4] ^ uid[5] ^ uid[6]; +} + +static void nfc_generate_mf_ul_copy_uid_with_bcc(NfcDevData* data) { + MfUltralightData* mfu_data = &data->mf_ul_data; + memcpy(mfu_data->page[0].data, mfu_data->nfca_data.uid, 3); + memcpy(mfu_data->page[1].data, &mfu_data->nfca_data.uid[3], 4); + + nfc_generate_calc_bcc( + mfu_data->nfca_data.uid, &mfu_data->page[0].data[3], &mfu_data->page[2].data[0]); +} + +static void nfc_generate_mf_ul_orig(NfcDevData* data) { + nfc_generate_common_start(data); + nfc_generate_mf_ul_common(data); + + MfUltralightData* mfu_data = &data->mf_ul_data; + mfu_data->type = MfUltralightTypeUnknown; + mfu_data->pages_total = 16; + mfu_data->pages_read = 16; + nfc_generate_mf_ul_copy_uid_with_bcc(data); + // TODO: what's internal byte on page 2? + memset(&mfu_data->page[4], 0xff, sizeof(MfUltralightPage)); +} + +static void nfc_generate_mf_ul_with_config_common(NfcDevData* data, uint8_t num_pages) { + nfc_generate_common_start(data); + nfc_generate_mf_ul_common(data); + + MfUltralightData* mfu_data = &data->mf_ul_data; + mfu_data->pages_total = num_pages; + mfu_data->pages_read = num_pages; + nfc_generate_mf_ul_copy_uid_with_bcc(data); + uint16_t config_index = (num_pages - 4); + mfu_data->page[config_index].data[0] = 0x04; // STRG_MOD_EN + mfu_data->page[config_index].data[3] = 0xff; // AUTH0 + mfu_data->page[config_index + 1].data[1] = 0x05; // VCTID + memset(&mfu_data->page[config_index + 2], 0xff, sizeof(MfUltralightPage)); // Default PWD + if(num_pages > 20) { + mfu_data->page[config_index - 1].data[3] = MF_ULTRALIGHT_TEARING_FLAG_DEFAULT; + } +} + +static void nfc_generate_mf_ul_ev1_common(NfcDevData* data, uint8_t num_pages) { + nfc_generate_mf_ul_with_config_common(data, num_pages); + MfUltralightData* mfu_data = &data->mf_ul_data; + memcpy(&mfu_data->version, version_bytes_mf0ulx1, sizeof(MfUltralightVersion)); + for(size_t i = 0; i < 3; ++i) { + mfu_data->tearing_flag[i].data[0] = MF_ULTRALIGHT_TEARING_FLAG_DEFAULT; + } + // TODO: what's internal byte on page 2? +} + +static void nfc_generate_mf_ul_11(NfcDevData* data) { + nfc_generate_mf_ul_ev1_common(data, 20); + MfUltralightData* mfu_data = &data->mf_ul_data; + mfu_data->type = MfUltralightTypeUL11; + mfu_data->version.prod_subtype = 0x01; + mfu_data->version.storage_size = 0x0B; + mfu_data->page[16].data[0] = 0x00; // Low capacitance version does not have STRG_MOD_EN +} + +static void nfc_generate_mf_ul_h11(NfcDevData* data) { + nfc_generate_mf_ul_ev1_common(data, 20); + MfUltralightData* mfu_data = &data->mf_ul_data; + mfu_data->type = MfUltralightTypeUL11; + mfu_data->version.prod_subtype = 0x02; + mfu_data->version.storage_size = 0x0B; +} + +static void nfc_generate_mf_ul_21(NfcDevData* data) { + nfc_generate_mf_ul_ev1_common(data, 41); + MfUltralightData* mfu_data = &data->mf_ul_data; + mfu_data->type = MfUltralightTypeUL21; + mfu_data->version.prod_subtype = 0x01; + mfu_data->version.storage_size = 0x0E; + mfu_data->page[37].data[0] = 0x00; // Low capacitance version does not have STRG_MOD_EN +} + +static void nfc_generate_mf_ul_h21(NfcDevData* data) { + nfc_generate_mf_ul_ev1_common(data, 41); + MfUltralightData* mfu_data = &data->mf_ul_data; + mfu_data->type = MfUltralightTypeUL21; + mfu_data->version.prod_subtype = 0x02; + mfu_data->version.storage_size = 0x0E; +} + +static void nfc_generate_ntag203(NfcDevData* data) { + nfc_generate_common_start(data); + nfc_generate_mf_ul_common(data); + + MfUltralightData* mfu_data = &data->mf_ul_data; + mfu_data->type = MfUltralightTypeNTAG203; + mfu_data->pages_total = 42; + mfu_data->pages_read = 42; + nfc_generate_mf_ul_copy_uid_with_bcc(data); + mfu_data->page[2].data[1] = 0x48; // Internal byte + memcpy(&mfu_data->page[3], default_data_ntag203, sizeof(MfUltralightPage)); +} + +static void nfc_generate_ntag21x_common(NfcDevData* data, uint8_t num_pages) { + nfc_generate_mf_ul_with_config_common(data, num_pages); + MfUltralightData* mfu_data = &data->mf_ul_data; + memcpy(&mfu_data->version, version_bytes_ntag21x, sizeof(MfUltralightVersion)); + mfu_data->page[2].data[1] = 0x48; // Internal byte + // Capability container + mfu_data->page[3].data[0] = 0xE1; + mfu_data->page[3].data[1] = 0x10; +} + +static void nfc_generate_ntag213(NfcDevData* data) { + nfc_generate_ntag21x_common(data, 45); + MfUltralightData* mfu_data = &data->mf_ul_data; + mfu_data->type = MfUltralightTypeNTAG213; + mfu_data->version.storage_size = 0x0F; + mfu_data->page[3].data[2] = 0x12; + // Default contents + memcpy(&mfu_data->page[4], default_data_ntag213, sizeof(default_data_ntag213)); +} + +static void nfc_generate_ntag215(NfcDevData* data) { + nfc_generate_ntag21x_common(data, 135); + MfUltralightData* mfu_data = &data->mf_ul_data; + mfu_data->type = MfUltralightTypeNTAG215; + mfu_data->version.storage_size = 0x11; + mfu_data->page[3].data[2] = 0x3E; + // Default contents + memcpy(&mfu_data->page[4], default_data_ntag215_216, sizeof(default_data_ntag215_216)); +} + +static void nfc_generate_ntag216(NfcDevData* data) { + nfc_generate_ntag21x_common(data, 231); + MfUltralightData* mfu_data = &data->mf_ul_data; + mfu_data->type = MfUltralightTypeNTAG216; + mfu_data->version.storage_size = 0x13; + mfu_data->page[3].data[2] = 0x6D; + // Default contents + memcpy(&mfu_data->page[4], default_data_ntag215_216, sizeof(default_data_ntag215_216)); +} + +static void + nfc_generate_ntag_i2c_common(NfcDevData* data, MfUltralightType type, uint16_t num_pages) { + nfc_generate_common_start(data); + nfc_generate_mf_ul_common(data); + + MfUltralightData* mfu_data = &data->mf_ul_data; + mfu_data->type = type; + memcpy(&mfu_data->version, version_bytes_ntag_i2c, sizeof(version_bytes_ntag_i2c)); + mfu_data->pages_total = num_pages; + mfu_data->pages_read = num_pages; + memcpy(mfu_data->page[0].data, mfu_data->nfca_data.uid, mfu_data->nfca_data.uid_len); + mfu_data->page[1].data[3] = mfu_data->nfca_data.sak; + mfu_data->page[2].data[0] = mfu_data->nfca_data.atqa[0]; + mfu_data->page[2].data[1] = mfu_data->nfca_data.atqa[1]; + + uint16_t config_register_page = 0; + uint16_t session_register_page = 0; + + // Sync with mifare_ultralight.c + switch(type) { + case MfUltralightTypeNTAGI2C1K: + config_register_page = 227; + session_register_page = 229; + break; + case MfUltralightTypeNTAGI2C2K: + config_register_page = 481; + session_register_page = 483; + break; + case MfUltralightTypeNTAGI2CPlus1K: + case MfUltralightTypeNTAGI2CPlus2K: + config_register_page = 232; + session_register_page = 234; + break; + default: + furi_crash("Unknown MFUL"); + break; + } + + memcpy( + &mfu_data->page[config_register_page], + default_config_ntag_i2c, + sizeof(default_config_ntag_i2c)); + memcpy( + &mfu_data->page[session_register_page], + default_config_ntag_i2c, + sizeof(default_config_ntag_i2c)); +} + +static void nfc_generate_ntag_i2c_1k(NfcDevData* data) { + nfc_generate_ntag_i2c_common(data, MfUltralightTypeNTAGI2C1K, 231); + MfUltralightData* mfu_data = &data->mf_ul_data; + mfu_data->version.prod_ver_minor = 0x01; + mfu_data->version.storage_size = 0x13; + + memcpy(&mfu_data->page[3], default_data_ntag_i2c, sizeof(default_data_ntag_i2c)); + mfu_data->page[3].data[2] = 0x6D; // Size of tag in CC +} + +static void nfc_generate_ntag_i2c_2k(NfcDevData* data) { + nfc_generate_ntag_i2c_common(data, MfUltralightTypeNTAGI2C2K, 485); + MfUltralightData* mfu_data = &data->mf_ul_data; + mfu_data->version.prod_ver_minor = 0x01; + mfu_data->version.storage_size = 0x15; + + memcpy(&mfu_data->page[3], default_data_ntag_i2c, sizeof(default_data_ntag_i2c)); + mfu_data->page[3].data[2] = 0xEA; // Size of tag in CC +} + +static void + nfc_generate_ntag_i2c_plus_common(NfcDevData* data, MfUltralightType type, uint16_t num_pages) { + nfc_generate_ntag_i2c_common(data, type, num_pages); + + MfUltralightData* mfu_data = &data->mf_ul_data; + uint16_t config_index = 227; + mfu_data->page[config_index].data[3] = 0xff; // AUTH0 + + memset(&mfu_data->page[config_index + 2], 0xFF, sizeof(MfUltralightPage)); // Default PWD +} + +static void nfc_generate_ntag_i2c_plus_1k(NfcDevData* data) { + nfc_generate_ntag_i2c_plus_common(data, MfUltralightTypeNTAGI2CPlus1K, 236); + MfUltralightData* mfu_data = &data->mf_ul_data; + mfu_data->version.prod_ver_minor = 0x02; + mfu_data->version.storage_size = 0x13; +} + +static void nfc_generate_ntag_i2c_plus_2k(NfcDevData* data) { + nfc_generate_ntag_i2c_plus_common(data, MfUltralightTypeNTAGI2CPlus2K, 492); + MfUltralightData* mfu_data = &data->mf_ul_data; + mfu_data->version.prod_ver_minor = 0x02; + mfu_data->version.storage_size = 0x15; +} + +static const NfcDataGenerator nfc_data_generator[NfcDataGeneratorTypeNum] = { + [NfcDataGeneratorTypeMfUltralight] = + { + .name = "Mifare Ultralight", + .handler = nfc_generate_mf_ul_orig, + }, + [NfcDataGeneratorTypeMfUltralightEV1_11] = + { + .name = "Mifare Ultralight EV1 11", + .handler = nfc_generate_mf_ul_11, + }, + [NfcDataGeneratorTypeMfUltralightEV1_H11] = + { + .name = "Mifare Ultralight EV1 H11", + .handler = nfc_generate_mf_ul_h11, + }, + [NfcDataGeneratorTypeMfUltralightEV1_21] = + { + .name = "Mifare Ultralight EV1 21", + .handler = nfc_generate_mf_ul_21, + }, + [NfcDataGeneratorTypeMfUltralightEV1_H21] = + { + .name = "Mifare Ultralight EV1 H21", + .handler = nfc_generate_mf_ul_h21, + }, + [NfcDataGeneratorTypeNTAG203] = + { + .name = "NTAG203", + .handler = nfc_generate_ntag203, + }, + [NfcDataGeneratorTypeNTAG213] = + { + .name = "NTAG213", + .handler = nfc_generate_ntag213, + }, + [NfcDataGeneratorTypeNTAG215] = + { + .name = "NTAG215", + .handler = nfc_generate_ntag215, + }, + [NfcDataGeneratorTypeNTAG216] = + { + .name = "NTAG216", + .handler = nfc_generate_ntag216, + }, + [NfcDataGeneratorTypeNTAGI2C1k] = + { + .name = "NTAG I2C 1k", + .handler = nfc_generate_ntag_i2c_1k, + }, + [NfcDataGeneratorTypeNTAGI2C2k] = + { + .name = "NTAG I2C 2k", + .handler = nfc_generate_ntag_i2c_2k, + }, + [NfcDataGeneratorTypeNTAGI2CPlus1k] = + { + .name = "NTAG I2C Plus 1k", + .handler = nfc_generate_ntag_i2c_plus_1k, + }, + [NfcDataGeneratorTypeNTAGI2CPlus2k] = + { + .name = "NTAG I2C Plus 2k", + .handler = nfc_generate_ntag_i2c_plus_2k, + }, + // [NfcDataGeneratorTypeMfClassicMini] = + // { + // .name = "", + // .handler =, + // }, + // [NfcDataGeneratorTypeMfClassic1k_4b] = + // { + // .name = "", + // .handler =, + // }, + // [NfcDataGeneratorTypeMfClassic1k_7b] = + // { + // .name = "", + // .handler =, + // }, + // [NfcDataGeneratorTypeMfClassic2k_4b] = + // { + // .name = "", + // .handler =, + // }, + // [NfcDataGeneratorTypeMfClassic2k_7b] = + // { + // .name = "", + // .handler =, + // }, +}; + +const char* nfc_data_generator_get_name(NfcDataGeneratorType type) { + return nfc_data_generator[type].name; +} + +void nfc_data_generator_fill_data(NfcDataGeneratorType type, NfcDevData* data) { + nfc_data_generator[type].handler(data); +} diff --git a/lib/nfc/helpers/nfc_data_generator.h b/lib/nfc/helpers/nfc_data_generator.h new file mode 100644 index 000000000000..80f975bec33b --- /dev/null +++ b/lib/nfc/helpers/nfc_data_generator.h @@ -0,0 +1,40 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + NfcDataGeneratorTypeMfUltralight, + NfcDataGeneratorTypeMfUltralightEV1_11, + NfcDataGeneratorTypeMfUltralightEV1_H11, + NfcDataGeneratorTypeMfUltralightEV1_21, + NfcDataGeneratorTypeMfUltralightEV1_H21, + NfcDataGeneratorTypeNTAG203, + NfcDataGeneratorTypeNTAG213, + NfcDataGeneratorTypeNTAG215, + NfcDataGeneratorTypeNTAG216, + NfcDataGeneratorTypeNTAGI2C1k, + NfcDataGeneratorTypeNTAGI2C2k, + NfcDataGeneratorTypeNTAGI2CPlus1k, + NfcDataGeneratorTypeNTAGI2CPlus2k, + + // NfcDataGeneratorTypeMfClassicMini, + // NfcDataGeneratorTypeMfClassic1k_4b, + // NfcDataGeneratorTypeMfClassic1k_7b, + // NfcDataGeneratorTypeMfClassic2k_4b, + // NfcDataGeneratorTypeMfClassic2k_7b, + + NfcDataGeneratorTypeNum, + +} NfcDataGeneratorType; + +const char* nfc_data_generator_get_name(NfcDataGeneratorType type); + +void nfc_data_generator_fill_data(NfcDataGeneratorType type, NfcDevData* data); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/nfc_device_data.h b/lib/nfc/nfc_device_data.h index ede9a544412d..2033a5f20953 100644 --- a/lib/nfc/nfc_device_data.h +++ b/lib/nfc/nfc_device_data.h @@ -20,6 +20,7 @@ typedef enum { NfcDevProtocolNum, } NfcDevProtocol; +// TODO rename to NfcData? typedef struct { NfcDevProtocol protocol; union { @@ -31,4 +32,3 @@ typedef struct { #ifdef __cplusplus } #endif - diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h index 26940d9573b4..0ed13e9758ed 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h @@ -6,6 +6,8 @@ extern "C" { #endif +#define MF_ULTRALIGHT_TEARING_FLAG_DEFAULT (0xBD) + #define MF_ULTRALIGHT_CMD_GET_VERSION (0x60) #define MF_ULTRALIGHT_CMD_READ_PAGE (0x30) #define MF_ULTRALIGHT_CMD_WRITE_PAGE (0xA2) From 9964fb659c93a2c7a774cfa727907b87c3677839 Mon Sep 17 00:00:00 2001 From: gornekich Date: Wed, 3 May 2023 00:27:47 +0400 Subject: [PATCH 049/149] nfc app: add generator scenes --- applications/main/nfc/nfc_app_i.h | 1 + .../main/nfc/scenes/nfc_scene_config.h | 3 + .../main/nfc/scenes/nfc_scene_generate_info.c | 72 +++++++++++++++++++ .../main/nfc/scenes/nfc_scene_set_type.c | 62 ++++++++++++++++ .../main/nfc/scenes/nfc_scene_start.c | 4 +- 5 files changed, 140 insertions(+), 2 deletions(-) create mode 100644 applications/main/nfc/scenes/nfc_scene_generate_info.c create mode 100644 applications/main/nfc/scenes/nfc_scene_set_type.c diff --git a/applications/main/nfc/nfc_app_i.h b/applications/main/nfc/nfc_app_i.h index 6913bb4ef97b..c41ac4ace93a 100644 --- a/applications/main/nfc/nfc_app_i.h +++ b/applications/main/nfc/nfc_app_i.h @@ -43,6 +43,7 @@ #include #include +#include #include #include diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index 15919915b795..d48dda229a4b 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -21,4 +21,7 @@ ADD_SCENE(nfc, mf_ultralight_unlock_warn, MfUltralightUnlockWarn) ADD_SCENE(nfc, mf_ultralight_key_input, MfUltralightKeyInput) +ADD_SCENE(nfc, set_type, SetType) +ADD_SCENE(nfc, generate_info, GenerateInfo) + ADD_SCENE(nfc, not_implemented, NotImplemented) \ No newline at end of file diff --git a/applications/main/nfc/scenes/nfc_scene_generate_info.c b/applications/main/nfc/scenes/nfc_scene_generate_info.c new file mode 100644 index 000000000000..1d875bf623b5 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_generate_info.c @@ -0,0 +1,72 @@ +#include "../nfc_app_i.h" + +void nfc_scene_generate_info_widget_callback(GuiButtonType result, InputType type, void* context) { + NfcApp* nfc = context; + + if(type == InputTypeShort) { + if(result == GuiButtonTypeRight) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); + } + } +} + +void nfc_scene_generate_info_on_enter(void* context) { + NfcApp* nfc = context; + + NfcaData* nfca_data = NULL; + if(nfc->nfc_dev_data.protocol == NfcDevProtocolMfUltralight) { + nfca_data = &nfc->nfc_dev_data.mf_ul_data.nfca_data; + } else { + // TODO add Mf Classic + furi_crash("Not supported protocol"); + } + + // Setup dialog view + Widget* widget = nfc->widget; + widget_add_button_element( + widget, GuiButtonTypeRight, "More", nfc_scene_generate_info_widget_callback, nfc); + + // Create info text + NfcDataGeneratorType type = + scene_manager_get_scene_state(nfc->scene_manager, NfcSceneGenerateInfo); + const char* name = nfc_data_generator_get_name(type); + widget_add_string_element(widget, 0, 0, AlignLeft, AlignTop, FontPrimary, name); + widget_add_string_element(widget, 0, 13, AlignLeft, AlignTop, FontSecondary, "NFC-A"); + + FuriString* temp_str = furi_string_alloc_printf("UID:"); + // Append UID + for(int i = 0; i < nfca_data->uid_len; i++) { + furi_string_cat_printf(temp_str, " %02X", nfca_data->uid[i]); + } + widget_add_string_element( + widget, 0, 25, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(temp_str)); + furi_string_free(temp_str); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); +} + +bool nfc_scene_generate_info_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeRight) { + // Switch either to NfcSceneMfClassicMenu or NfcSceneMfUltralightMenu + if(nfc->nfc_dev_data.protocol == NfcDevProtocolMfUltralight) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightMenu); + } else { + // TODO add classic + } + consumed = true; + } + } + + return consumed; +} + +void nfc_scene_generate_info_on_exit(void* context) { + NfcApp* nfc = context; + + // Clean views + widget_reset(nfc->widget); +} diff --git a/applications/main/nfc/scenes/nfc_scene_set_type.c b/applications/main/nfc/scenes/nfc_scene_set_type.c new file mode 100644 index 000000000000..d040afea29bf --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_set_type.c @@ -0,0 +1,62 @@ +#include "../nfc_app_i.h" + +enum SubmenuIndex { + SubmenuIndexGeneratorsStart, + SubmenuIndexNFCA4 = NfcDataGeneratorTypeNum, + SubmenuIndexNFCA7, +}; + +void nfc_scene_set_type_submenu_callback(void* context, uint32_t index) { + NfcApp* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, index); +} + +void nfc_scene_set_type_on_enter(void* context) { + NfcApp* nfc = context; + Submenu* submenu = nfc->submenu; + // Clear device name + furi_string_reset(nfc->file_name); + submenu_add_item( + submenu, "NFC-A 7-bytes UID", SubmenuIndexNFCA7, nfc_scene_set_type_submenu_callback, nfc); + submenu_add_item( + submenu, "NFC-A 4-bytes UID", SubmenuIndexNFCA4, nfc_scene_set_type_submenu_callback, nfc); + + for(size_t i = 0; i < NfcDataGeneratorTypeNum; i++) { + const char* name = nfc_data_generator_get_name(i); + submenu_add_item(submenu, name, i, nfc_scene_set_type_submenu_callback, nfc); + } + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); +} + +bool nfc_scene_set_type_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexNFCA7) { + nfc->nfc_dev_data.protocol = NfcDevProtocolNfca; + nfc->nfc_dev_data.nfca_data.uid_len = 7; + scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + consumed = true; + } else if(event.event == SubmenuIndexNFCA4) { + nfc->nfc_dev_data.protocol = NfcDevProtocolNfca; + nfc->nfc_dev_data.nfca_data.uid_len = 4; + scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + consumed = true; + } else { + nfc_data_generator_fill_data(event.event, &nfc->nfc_dev_data); + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneGenerateInfo, event.event); + scene_manager_next_scene(nfc->scene_manager, NfcSceneGenerateInfo); + consumed = true; + } + } + return consumed; +} + +void nfc_scene_set_type_on_exit(void* context) { + NfcApp* nfc = context; + + submenu_reset(nfc->submenu); +} diff --git a/applications/main/nfc/scenes/nfc_scene_start.c b/applications/main/nfc/scenes/nfc_scene_start.c index a6fea9e5a014..fd083aad55f8 100644 --- a/applications/main/nfc/scenes/nfc_scene_start.c +++ b/applications/main/nfc/scenes/nfc_scene_start.c @@ -69,8 +69,8 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) { consumed = true; } else if(event.event == SubmenuIndexAddManually) { scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneStart, NfcSceneNotImplemented); - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + nfc->scene_manager, NfcSceneStart, NfcSceneSetType); + scene_manager_next_scene(nfc->scene_manager, NfcSceneSetType); consumed = true; } else if(event.event == SubmenuIndexDebug) { scene_manager_set_scene_state( From e40f45ef2e240378d737fb54b2c2f53fce77536b Mon Sep 17 00:00:00 2001 From: gornekich Date: Wed, 3 May 2023 00:30:11 +0400 Subject: [PATCH 050/149] nfc: dix memory leak --- lib/nfc/nfc_dev.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/nfc/nfc_dev.c b/lib/nfc/nfc_dev.c index 7bbcaf61e8bd..0091f8368e29 100644 --- a/lib/nfc/nfc_dev.c +++ b/lib/nfc/nfc_dev.c @@ -405,6 +405,7 @@ NfcDev* nfc_dev_alloc() { void nfc_dev_free(NfcDev* instance) { furi_assert(instance); + free(instance); } void nfc_dev_set_loading_callback(NfcDev* instance, NfcLoadingCallback callback, void* context) { From 8a8a260bcec9418728ec1ac21f0bed3e5713bccf Mon Sep 17 00:00:00 2001 From: gornekich Date: Wed, 3 May 2023 00:58:43 +0400 Subject: [PATCH 051/149] nfc app: nfca add manual --- .../main/nfc/scenes/nfc_scene_config.h | 4 ++ .../main/nfc/scenes/nfc_scene_save_name.c | 15 ++---- .../main/nfc/scenes/nfc_scene_saved_menu.c | 2 +- .../main/nfc/scenes/nfc_scene_set_atqa.c | 44 +++++++++++++++ .../main/nfc/scenes/nfc_scene_set_sak.c | 44 +++++++++++++++ .../main/nfc/scenes/nfc_scene_set_type.c | 4 +- .../main/nfc/scenes/nfc_scene_set_uid.c | 54 +++++++++++++++++++ 7 files changed, 154 insertions(+), 13 deletions(-) create mode 100644 applications/main/nfc/scenes/nfc_scene_set_atqa.c create mode 100644 applications/main/nfc/scenes/nfc_scene_set_sak.c create mode 100644 applications/main/nfc/scenes/nfc_scene_set_uid.c diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index d48dda229a4b..ce71f2cf8f33 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -22,6 +22,10 @@ ADD_SCENE(nfc, mf_ultralight_key_input, MfUltralightKeyInput) ADD_SCENE(nfc, set_type, SetType) +ADD_SCENE(nfc, set_sak, SetSak) +ADD_SCENE(nfc, set_atqa, SetAtqa) +ADD_SCENE(nfc, set_uid, SetUid) + ADD_SCENE(nfc, generate_info, GenerateInfo) ADD_SCENE(nfc, not_implemented, NotImplemented) \ No newline at end of file diff --git a/applications/main/nfc/scenes/nfc_scene_save_name.c b/applications/main/nfc/scenes/nfc_scene_save_name.c index 5e0e47306396..e1e90d260a61 100644 --- a/applications/main/nfc/scenes/nfc_scene_save_name.c +++ b/applications/main/nfc/scenes/nfc_scene_save_name.c @@ -53,18 +53,13 @@ bool nfc_scene_save_name_on_event(void* context, SceneManagerEvent event) { } furi_string_set(nfc->file_name, nfc->text_store); - // TODO uncoment - // if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetUid)) { - // nfc->dev->dev_data.nfc_data = nfc->dev_edit_data; - // } - if(nfc_save(nfc)) { scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess); - // if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) { - // DOLPHIN_DEED(DolphinDeedNfcAddSave); - // } else { - DOLPHIN_DEED(DolphinDeedNfcSave); - // } + if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) { + DOLPHIN_DEED(DolphinDeedNfcAddSave); + } else { + DOLPHIN_DEED(DolphinDeedNfcSave); + } consumed = true; } else { consumed = scene_manager_search_and_switch_to_previous_scene( diff --git a/applications/main/nfc/scenes/nfc_scene_saved_menu.c b/applications/main/nfc/scenes/nfc_scene_saved_menu.c index b955121dbda4..ddb3e5b4419c 100644 --- a/applications/main/nfc/scenes/nfc_scene_saved_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_saved_menu.c @@ -146,7 +146,7 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); consumed = true; } else if(event.event == SubmenuIndexEditUid) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + scene_manager_next_scene(nfc->scene_manager, NfcSceneSetUid); consumed = true; } else if(event.event == SubmenuIndexDelete) { scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); diff --git a/applications/main/nfc/scenes/nfc_scene_set_atqa.c b/applications/main/nfc/scenes/nfc_scene_set_atqa.c new file mode 100644 index 000000000000..7aa776fc9610 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_set_atqa.c @@ -0,0 +1,44 @@ +#include "../nfc_app_i.h" + +void nfc_scene_set_atqa_byte_input_callback(void* context) { + NfcApp* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); +} + +void nfc_scene_set_atqa_on_enter(void* context) { + NfcApp* nfc = context; + + // Setup view + ByteInput* byte_input = nfc->byte_input; + byte_input_set_header_text(byte_input, "Enter ATQA in hex"); + byte_input_set_result_callback( + byte_input, + nfc_scene_set_atqa_byte_input_callback, + NULL, + nfc, + nfc->nfc_dev_data.nfca_data.atqa, + 2); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewByteInput); +} + +bool nfc_scene_set_atqa_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventByteInputDone) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneSetUid); + consumed = true; + } + } + return consumed; +} + +void nfc_scene_set_atqa_on_exit(void* context) { + NfcApp* nfc = context; + + // Clear view + byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0); + byte_input_set_header_text(nfc->byte_input, ""); +} diff --git a/applications/main/nfc/scenes/nfc_scene_set_sak.c b/applications/main/nfc/scenes/nfc_scene_set_sak.c new file mode 100644 index 000000000000..6e693d792299 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_set_sak.c @@ -0,0 +1,44 @@ +#include "../nfc_app_i.h" + +void nfc_scene_set_sak_byte_input_callback(void* context) { + NfcApp* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); +} + +void nfc_scene_set_sak_on_enter(void* context) { + NfcApp* nfc = context; + + // Setup view + ByteInput* byte_input = nfc->byte_input; + byte_input_set_header_text(byte_input, "Enter SAK in hex"); + byte_input_set_result_callback( + byte_input, + nfc_scene_set_sak_byte_input_callback, + NULL, + nfc, + &nfc->nfc_dev_data.nfca_data.sak, + 1); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewByteInput); +} + +bool nfc_scene_set_sak_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventByteInputDone) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneSetAtqa); + consumed = true; + } + } + return consumed; +} + +void nfc_scene_set_sak_on_exit(void* context) { + NfcApp* nfc = context; + + // Clear view + byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0); + byte_input_set_header_text(nfc->byte_input, ""); +} diff --git a/applications/main/nfc/scenes/nfc_scene_set_type.c b/applications/main/nfc/scenes/nfc_scene_set_type.c index d040afea29bf..b59f5724f47e 100644 --- a/applications/main/nfc/scenes/nfc_scene_set_type.c +++ b/applications/main/nfc/scenes/nfc_scene_set_type.c @@ -38,12 +38,12 @@ bool nfc_scene_set_type_on_event(void* context, SceneManagerEvent event) { if(event.event == SubmenuIndexNFCA7) { nfc->nfc_dev_data.protocol = NfcDevProtocolNfca; nfc->nfc_dev_data.nfca_data.uid_len = 7; - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + scene_manager_next_scene(nfc->scene_manager, NfcSceneSetSak); consumed = true; } else if(event.event == SubmenuIndexNFCA4) { nfc->nfc_dev_data.protocol = NfcDevProtocolNfca; nfc->nfc_dev_data.nfca_data.uid_len = 4; - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + scene_manager_next_scene(nfc->scene_manager, NfcSceneSetSak); consumed = true; } else { nfc_data_generator_fill_data(event.event, &nfc->nfc_dev_data); diff --git a/applications/main/nfc/scenes/nfc_scene_set_uid.c b/applications/main/nfc/scenes/nfc_scene_set_uid.c new file mode 100644 index 000000000000..8232806b8108 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_set_uid.c @@ -0,0 +1,54 @@ +#include "../nfc_app_i.h" + +void nfc_scene_set_uid_byte_input_callback(void* context) { + NfcApp* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); +} + +void nfc_scene_set_uid_on_enter(void* context) { + NfcApp* nfc = context; + + // Setup view + ByteInput* byte_input = nfc->byte_input; + byte_input_set_header_text(byte_input, "Enter UID in hex"); + nfc->nfca_edit_data = nfc->nfc_dev_data.nfca_data; + byte_input_set_result_callback( + byte_input, + nfc_scene_set_uid_byte_input_callback, + NULL, + nfc, + nfc->nfca_edit_data.uid, + nfc->nfca_edit_data.uid_len); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewByteInput); +} + +bool nfc_scene_set_uid_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventByteInputDone) { + nfc->nfc_dev_data.nfca_data = nfc->nfca_edit_data; + if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSavedMenu)) { + if(nfc_save(nfc)) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess); + consumed = true; + } + } else { + scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); + consumed = true; + } + } + } + + return consumed; +} + +void nfc_scene_set_uid_on_exit(void* context) { + NfcApp* nfc = context; + + // Clear view + byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0); + byte_input_set_header_text(nfc->byte_input, ""); +} From eb776413b0f2bcf1a7b3f023b07da154d6bc9483 Mon Sep 17 00:00:00 2001 From: gornekich Date: Wed, 3 May 2023 14:44:10 +0400 Subject: [PATCH 052/149] nfc dev: fix save and load bugs --- lib/nfc/nfc_dev.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/lib/nfc/nfc_dev.c b/lib/nfc/nfc_dev.c index 0091f8368e29..ffdc52add0bd 100644 --- a/lib/nfc/nfc_dev.c +++ b/lib/nfc/nfc_dev.c @@ -122,6 +122,7 @@ static bool nfc_dev_mf_ultralight_verify_handler(FuriString* device_type, NfcDev const char* name = mf_ultralight_get_name(i, true); verified = furi_string_equal_str(device_type, name); if(verified) { + data->protocol = NfcDevProtocolMfUltralight; data->mf_ul_data.type = i; break; } @@ -140,6 +141,8 @@ static bool MfUltralightData* mfu_data = &data->mf_ul_data; bool saved = false; do { + const char* device_type_name = mf_ultralight_get_name(mfu_data->type, true); + if(!flipper_format_write_string_cstr(file, "Device type", device_type_name)) break; if(!nfc_dev_nfca_save_data(file, &data->nfca_data)) break; if(!flipper_format_write_comment_cstr(file, "Mifare Ultralight specific data")) break; if(!flipper_format_write_uint32( @@ -171,10 +174,10 @@ static bool if(!counters_saved) break; // Write pages data - if(!flipper_format_write_uint32(file, "Pages total", (uint32_t*)&mfu_data->pages_total, 1)) - break; - if(!flipper_format_write_uint32(file, "Pages read", (uint32_t*)&mfu_data->pages_read, 1)) - break; + uint32_t pages_total = mfu_data->pages_total; + uint32_t pages_read = mfu_data->pages_read; + if(!flipper_format_write_uint32(file, "Pages total", &pages_total, 1)) break; + if(!flipper_format_write_uint32(file, "Pages read", &pages_read, 1)) break; bool pages_saved = true; for(size_t i = 0; i < mfu_data->pages_total; i++) { furi_string_printf(temp_str, "Page %d", i); @@ -258,8 +261,6 @@ static bool mfu_data->pages_total = pages_total; mfu_data->pages_read = pages_read; - // data->data_size = pages_total * 4; - // data->data_read = pages_read * 4; if((pages_read > MF_ULTRALIGHT_MAX_PAGE_NUM) || (pages_total > MF_ULTRALIGHT_MAX_PAGE_NUM)) break; @@ -295,7 +296,13 @@ static bool nfc_dev_mf_classic_verify_handler(FuriString* device_type, NfcDevDat furi_assert(device_type); furi_assert(data); - return furi_string_start_with_str(device_type, "Mifare Classic"); + // TODO set mfc type here + bool verified = furi_string_start_with_str(device_type, "Mifare Classic"); + if(verified) { + data->protocol = NfcDevProtocolMfClassic; + } + + return verified; } static bool @@ -334,7 +341,12 @@ static bool nfc_dev_mf_desfire_verify_handler(FuriString* device_type, NfcDevDat furi_assert(device_type); furi_assert(data); - return furi_string_start_with_str(device_type, "Mifare Desfire"); + bool verified = furi_string_start_with_str(device_type, "Mifare Desfire"); + if(verified) { + data->protocol = NfcDevProtocolMfDesfire; + } + + return verified; } static bool From 2dcdce6ec6f1ff84b2fc5f31d8c58a6c3e6b7770 Mon Sep 17 00:00:00 2001 From: gornekich Date: Wed, 3 May 2023 14:44:28 +0400 Subject: [PATCH 053/149] unit tests: rework nfc unit tests --- applications/debug/unit_tests/nfc/nfc_test.c | 537 +++--------------- .../debug/unit_tests/nfc/nfc_test_old.c | 532 +++++++++++++++++ 2 files changed, 620 insertions(+), 449 deletions(-) create mode 100644 applications/debug/unit_tests/nfc/nfc_test_old.c diff --git a/applications/debug/unit_tests/nfc/nfc_test.c b/applications/debug/unit_tests/nfc/nfc_test.c index 54bdd59097e9..70d53ad6c96d 100644 --- a/applications/debug/unit_tests/nfc/nfc_test.c +++ b/applications/debug/unit_tests/nfc/nfc_test.c @@ -1,46 +1,25 @@ #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include #include "../minunit.h" #define TAG "NfcTest" -#define NFC_TEST_RESOURCES_DIR EXT_PATH("unit_tests/nfc/") -#define NFC_TEST_SIGNAL_SHORT_FILE "nfc_nfca_signal_short.nfc" -#define NFC_TEST_SIGNAL_LONG_FILE "nfc_nfca_signal_long.nfc" -#define NFC_TEST_DICT_PATH EXT_PATH("unit_tests/mf_classic_dict.nfc") #define NFC_TEST_NFC_DEV_PATH EXT_PATH("unit_tests/nfc/nfc_dev_test.nfc") -static const char* nfc_test_file_type = "Flipper NFC test"; -static const uint32_t nfc_test_file_version = 1; - -#define NFC_TEST_DATA_MAX_LEN 18 -#define NFC_TETS_TIMINGS_MAX_LEN 1350 - typedef struct { Storage* storage; - NfcaSignal* signal; - uint32_t test_data_len; - uint8_t test_data[NFC_TEST_DATA_MAX_LEN]; - uint32_t test_timings_len; - uint32_t test_timings[NFC_TETS_TIMINGS_MAX_LEN]; } NfcTest; static NfcTest* nfc_test = NULL; static void nfc_test_alloc() { nfc_test = malloc(sizeof(NfcTest)); - nfc_test->signal = nfca_signal_alloc(); nfc_test->storage = furi_record_open(RECORD_STORAGE); } @@ -48,480 +27,140 @@ static void nfc_test_free() { furi_assert(nfc_test); furi_record_close(RECORD_STORAGE); - nfca_signal_free(nfc_test->signal); free(nfc_test); nfc_test = NULL; } -static bool nfc_test_read_signal_from_file(const char* file_name) { - bool success = false; - - FlipperFormat* file = flipper_format_file_alloc(nfc_test->storage); - FuriString* file_type; - file_type = furi_string_alloc(); - uint32_t file_version = 0; - - do { - if(!flipper_format_file_open_existing(file, file_name)) break; - if(!flipper_format_read_header(file, file_type, &file_version)) break; - if(furi_string_cmp_str(file_type, nfc_test_file_type) || - file_version != nfc_test_file_version) - break; - if(!flipper_format_read_uint32(file, "Data length", &nfc_test->test_data_len, 1)) break; - if(nfc_test->test_data_len > NFC_TEST_DATA_MAX_LEN) break; - if(!flipper_format_read_hex( - file, "Plain data", nfc_test->test_data, nfc_test->test_data_len)) - break; - if(!flipper_format_read_uint32(file, "Timings length", &nfc_test->test_timings_len, 1)) - break; - if(nfc_test->test_timings_len > NFC_TETS_TIMINGS_MAX_LEN) break; - if(!flipper_format_read_uint32( - file, "Timings", nfc_test->test_timings, nfc_test->test_timings_len)) - break; - success = true; - } while(false); - - furi_string_free(file_type); - flipper_format_free(file); - - return success; -} - -static bool nfc_test_digital_signal_test_encode( - const char* file_name, - uint32_t encode_max_time, - uint32_t timing_tolerance, - uint32_t timings_sum_tolerance) { - furi_assert(nfc_test); - - bool success = false; - uint32_t time = 0; - uint32_t dut_timings_sum = 0; - uint32_t ref_timings_sum = 0; - uint8_t parity[10] = {}; - - do { - // Read test data - if(!nfc_test_read_signal_from_file(file_name)) { - FURI_LOG_E(TAG, "Failed to read signal from file"); - break; - } - - // Encode signal - FURI_CRITICAL_ENTER(); - time = DWT->CYCCNT; - nfca_signal_encode( - nfc_test->signal, nfc_test->test_data, nfc_test->test_data_len * 8, parity); - digital_signal_prepare_arr(nfc_test->signal->tx_signal); - time = (DWT->CYCCNT - time) / furi_hal_cortex_instructions_per_microsecond(); - FURI_CRITICAL_EXIT(); - - // Check timings - if(time > encode_max_time) { - FURI_LOG_E( - TAG, "Encoding time: %ld us while accepted value: %ld us", time, encode_max_time); - break; - } - - // Check data - if(nfc_test->signal->tx_signal->edge_cnt != nfc_test->test_timings_len) { - FURI_LOG_E(TAG, "Not equal timings buffers length"); - break; - } - - uint32_t timings_diff = 0; - uint32_t* ref = nfc_test->test_timings; - uint32_t* dut = nfc_test->signal->tx_signal->reload_reg_buff; - bool timing_check_success = true; - for(size_t i = 0; i < nfc_test->test_timings_len; i++) { - timings_diff = dut[i] > ref[i] ? dut[i] - ref[i] : ref[i] - dut[i]; - dut_timings_sum += dut[i]; - ref_timings_sum += ref[i]; - if(timings_diff > timing_tolerance) { - FURI_LOG_E( - TAG, "Too big difference in %d timings. Ref: %ld, DUT: %ld", i, ref[i], dut[i]); - timing_check_success = false; - break; - } - } - if(!timing_check_success) break; - uint32_t sum_diff = dut_timings_sum > ref_timings_sum ? dut_timings_sum - ref_timings_sum : - ref_timings_sum - dut_timings_sum; - if(sum_diff > timings_sum_tolerance) { - FURI_LOG_E( - TAG, - "Too big difference in timings sum. Ref: %ld, DUT: %ld", - ref_timings_sum, - dut_timings_sum); - break; - } - - FURI_LOG_I(TAG, "Encoding time: %ld us. Acceptable time: %ld us", time, encode_max_time); - FURI_LOG_I( - TAG, - "Timings sum difference: %ld [1/64MHZ]. Acceptable difference: %ld [1/64MHz]", - sum_diff, - timings_sum_tolerance); - success = true; - } while(false); - - return success; -} - -MU_TEST(nfc_digital_signal_test) { - mu_assert( - nfc_test_digital_signal_test_encode( - NFC_TEST_RESOURCES_DIR NFC_TEST_SIGNAL_SHORT_FILE, 500, 1, 37), - "NFC short digital signal test failed\r\n"); - mu_assert( - nfc_test_digital_signal_test_encode( - NFC_TEST_RESOURCES_DIR NFC_TEST_SIGNAL_LONG_FILE, 2000, 1, 37), - "NFC long digital signal test failed\r\n"); -} - -MU_TEST(mf_classic_dict_test) { - MfClassicDict* instance = NULL; - uint64_t key = 0; - FuriString* temp_str; - temp_str = furi_string_alloc(); - - instance = mf_classic_dict_alloc(MfClassicDictTypeUnitTest); - mu_assert(instance != NULL, "mf_classic_dict_alloc\r\n"); - - mu_assert( - mf_classic_dict_get_total_keys(instance) == 0, - "mf_classic_dict_get_total_keys == 0 assert failed\r\n"); - - furi_string_set(temp_str, "2196FAD8115B"); - mu_assert( - mf_classic_dict_add_key_str(instance, temp_str), - "mf_classic_dict_add_key == true assert failed\r\n"); +static void nfc_test_save_and_load(NfcDevData* data) { + NfcDev* nfc_dev = nfc_dev_alloc(); + mu_assert(nfc_dev != NULL, "nfc_dev_alloc() failed\r\n"); - mu_assert( - mf_classic_dict_get_total_keys(instance) == 1, - "mf_classic_dict_get_total_keys == 1 assert failed\r\n"); + NfcDevData* nfc_dev_data_dut = malloc(sizeof(NfcDevData)); + mu_assert(nfc_dev_data_dut != NULL, "malloc() failed\r\n"); - mu_assert(mf_classic_dict_rewind(instance), "mf_classic_dict_rewind == 1 assert failed\r\n"); + mu_assert(nfc_dev_save(nfc_dev, data, NFC_TEST_NFC_DEV_PATH), "nfc_dev_save() failed\r\n"); mu_assert( - mf_classic_dict_get_key_at_index_str(instance, temp_str, 0), - "mf_classic_dict_get_key_at_index_str == true assert failed\r\n"); - mu_assert( - furi_string_cmp(temp_str, "2196FAD8115B") == 0, - "string_cmp(temp_str, \"2196FAD8115B\") == 0 assert failed\r\n"); - - mu_assert(mf_classic_dict_rewind(instance), "mf_classic_dict_rewind == 1 assert failed\r\n"); + nfc_dev_load(nfc_dev, nfc_dev_data_dut, NFC_TEST_NFC_DEV_PATH), + "nfc_dev_load() failed\r\n"); mu_assert( - mf_classic_dict_get_key_at_index(instance, &key, 0), - "mf_classic_dict_get_key_at_index == true assert failed\r\n"); - mu_assert(key == 0x2196FAD8115B, "key == 0x2196FAD8115B assert failed\r\n"); - - mu_assert(mf_classic_dict_rewind(instance), "mf_classic_dict_rewind == 1 assert failed\r\n"); + memcmp(nfc_dev_data_dut, data, sizeof(NfcDevData)) == 0, + "nfc_dev_data_dut != nfc_dev_data_ref\r\n"); mu_assert( - mf_classic_dict_delete_index(instance, 0), - "mf_classic_dict_delete_index == true assert failed\r\n"); + storage_simply_remove(nfc_test->storage, NFC_TEST_NFC_DEV_PATH), + "storage_simply_remove() failed\r\n"); - mf_classic_dict_free(instance); - furi_string_free(temp_str); + free(nfc_dev_data_dut); + nfc_dev_free(nfc_dev); } -MU_TEST(mf_classic_dict_load_test) { - Storage* storage = furi_record_open(RECORD_STORAGE); - mu_assert(storage != NULL, "storage != NULL assert failed\r\n"); +static void nfca_file_test(uint8_t uid_len) { + NfcDevData* nfc_dev_data_ref = malloc(sizeof(NfcDevData)); + mu_assert(nfc_dev_data_ref != NULL, "malloc() failed\r\n"); - // Delete unit test dict file if exists - if(storage_file_exists(storage, NFC_TEST_DICT_PATH)) { - mu_assert( - storage_simply_remove(storage, NFC_TEST_DICT_PATH), - "remove == true assert failed\r\n"); - } + NfcaData* data = &nfc_dev_data_ref->nfca_data; - // Create unit test dict file - Stream* file_stream = file_stream_alloc(storage); - mu_assert(file_stream != NULL, "file_stream != NULL assert failed\r\n"); - mu_assert( - file_stream_open(file_stream, NFC_TEST_DICT_PATH, FSAM_WRITE, FSOM_OPEN_ALWAYS), - "file_stream_open == true assert failed\r\n"); + data->uid_len = uid_len; + furi_hal_random_fill_buf(data->uid, uid_len); + furi_hal_random_fill_buf(data->atqa, 2); + furi_hal_random_fill_buf(&data->sak, 1); - // Write unit test dict file - char key_str[] = "a0a1a2a3a4a5"; - mu_assert( - stream_write_cstring(file_stream, key_str) == strlen(key_str), - "write == true assert failed\r\n"); - // Close unit test dict file - mu_assert(file_stream_close(file_stream), "file_stream_close == true assert failed\r\n"); - - // Load unit test dict file - MfClassicDict* instance = NULL; - instance = mf_classic_dict_alloc(MfClassicDictTypeUnitTest); - mu_assert(instance != NULL, "mf_classic_dict_alloc\r\n"); - uint32_t total_keys = mf_classic_dict_get_total_keys(instance); - mu_assert(total_keys == 1, "total_keys == 1 assert failed\r\n"); - - // Read key - uint64_t key_ref = 0xa0a1a2a3a4a5; - uint64_t key_dut = 0; - FuriString* temp_str = furi_string_alloc(); - mu_assert( - mf_classic_dict_get_next_key_str(instance, temp_str), - "get_next_key_str == true assert failed\r\n"); - mu_assert(furi_string_cmp_str(temp_str, key_str) == 0, "invalid key loaded\r\n"); - mu_assert(mf_classic_dict_rewind(instance), "mf_classic_dict_rewind == 1 assert failed\r\n"); - mu_assert( - mf_classic_dict_get_next_key(instance, &key_dut), - "get_next_key == true assert failed\r\n"); - mu_assert(key_dut == key_ref, "invalid key loaded\r\n"); - furi_string_free(temp_str); - mf_classic_dict_free(instance); + nfc_test_save_and_load(nfc_dev_data_ref); - // Check that MfClassicDict added new line to the end of the file - mu_assert( - file_stream_open(file_stream, NFC_TEST_DICT_PATH, FSAM_READ, FSOM_OPEN_EXISTING), - "file_stream_open == true assert failed\r\n"); - mu_assert(stream_seek(file_stream, -1, StreamOffsetFromEnd), "seek == true assert failed\r\n"); - uint8_t last_char = 0; - mu_assert(stream_read(file_stream, &last_char, 1) == 1, "read == true assert failed\r\n"); - mu_assert(last_char == '\n', "last_char == '\\n' assert failed\r\n"); - mu_assert(file_stream_close(file_stream), "file_stream_close == true assert failed\r\n"); - - // Delete unit test dict file - mu_assert( - storage_simply_remove(storage, NFC_TEST_DICT_PATH), "remove == true assert failed\r\n"); - stream_free(file_stream); - furi_record_close(RECORD_STORAGE); + free(nfc_dev_data_ref); } -MU_TEST(nfca_file_test) { - NfcDevice* nfc = nfc_device_alloc(); - mu_assert(nfc != NULL, "nfc_device_data != NULL assert failed\r\n"); - nfc->format = NfcDeviceSaveFormatUid; +static void mf_ultralight_file_test_with_generator(NfcDataGeneratorType type) { + NfcDevData* nfc_dev_data_ref = malloc(sizeof(NfcDevData)); + mu_assert(nfc_dev_data_ref != NULL, "malloc() failed\r\n"); - // Fill the UID, sak, ATQA and type - uint8_t uid[7] = {0x04, 0x01, 0x23, 0x45, 0x67, 0x89, 0x00}; - memcpy(nfc->dev_data.nfc_data.uid, uid, 7); - nfc->dev_data.nfc_data.uid_len = 7; + nfc_data_generator_fill_data(type, nfc_dev_data_ref); + nfc_test_save_and_load(nfc_dev_data_ref); - nfc->dev_data.nfc_data.sak = 0x08; - nfc->dev_data.nfc_data.atqa[0] = 0x00; - nfc->dev_data.nfc_data.atqa[1] = 0x04; - nfc->dev_data.nfc_data.type = FuriHalNfcTypeA; - - // Save the NFC device data to the file - mu_assert( - nfc_device_save(nfc, NFC_TEST_NFC_DEV_PATH), "nfc_device_save == true assert failed\r\n"); - nfc_device_free(nfc); - - // Load the NFC device data from the file - NfcDevice* nfc_validate = nfc_device_alloc(); - mu_assert( - nfc_device_load(nfc_validate, NFC_TEST_NFC_DEV_PATH, true), - "nfc_device_load == true assert failed\r\n"); - - // Check the UID, sak, ATQA and type - mu_assert(memcmp(nfc_validate->dev_data.nfc_data.uid, uid, 7) == 0, "uid assert failed\r\n"); - mu_assert(nfc_validate->dev_data.nfc_data.sak == 0x08, "sak == 0x08 assert failed\r\n"); - mu_assert( - nfc_validate->dev_data.nfc_data.atqa[0] == 0x00, "atqa[0] == 0x00 assert failed\r\n"); - mu_assert( - nfc_validate->dev_data.nfc_data.atqa[1] == 0x04, "atqa[1] == 0x04 assert failed\r\n"); - mu_assert( - nfc_validate->dev_data.nfc_data.type == FuriHalNfcTypeA, - "type == FuriHalNfcTypeA assert failed\r\n"); - nfc_device_free(nfc_validate); + free(nfc_dev_data_ref); } -static void mf_classic_generator_test(uint8_t uid_len, MfClassicType type) { - NfcDevice* nfc_dev = nfc_device_alloc(); - mu_assert(nfc_dev != NULL, "nfc_device_data != NULL assert failed\r\n"); - nfc_dev->format = NfcDeviceSaveFormatMifareClassic; - - // Create a test file - nfc_generate_mf_classic(&nfc_dev->dev_data, uid_len, type); - - // Get the uid from generated MFC - uint8_t uid[7] = {0}; - memcpy(uid, nfc_dev->dev_data.nfc_data.uid, uid_len); - uint8_t sak = nfc_dev->dev_data.nfc_data.sak; - uint8_t atqa[2] = {}; - memcpy(atqa, nfc_dev->dev_data.nfc_data.atqa, 2); - - MfClassicData* mf_data = &nfc_dev->dev_data.mf_classic_data; - // Check the manufacturer block (should be uid[uid_len] + BCC (for 4byte only) + SAK + ATQA0 + ATQA1 + 0xFF[rest]) - uint8_t manufacturer_block[16] = {0}; - memcpy(manufacturer_block, nfc_dev->dev_data.mf_classic_data.block[0].value, 16); - mu_assert( - memcmp(manufacturer_block, uid, uid_len) == 0, - "manufacturer_block uid doesn't match the file\r\n"); +MU_TEST(nfca_4b_file_test) { + nfca_file_test(4); +} - uint8_t position = 0; - if(uid_len == 4) { - position = uid_len; +MU_TEST(nfca_7b_file_test) { + nfca_file_test(7); +} - uint8_t bcc = 0; +MU_TEST(mf_ultralight_file_test) { + mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeMfUltralight); +} - for(int i = 0; i < uid_len; i++) { - bcc ^= uid[i]; - } +MU_TEST(mf_ultralight_ev1_11_file_test) { + mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeMfUltralightEV1_11); +} - mu_assert(manufacturer_block[position] == bcc, "manufacturer_block bcc assert failed\r\n"); - } else { - position = uid_len - 1; - } +MU_TEST(mf_ultralight_ev1_h11_file_test) { + mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeMfUltralightEV1_H11); +} - mu_assert(manufacturer_block[position + 1] == sak, "manufacturer_block sak assert failed\r\n"); +MU_TEST(mf_ultralight_ev1_21_file_test) { + mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeMfUltralightEV1_21); +} - mu_assert( - manufacturer_block[position + 2] == atqa[0], "manufacturer_block atqa0 assert failed\r\n"); +MU_TEST(mf_ultralight_ev1_h21_file_test) { + mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeMfUltralightEV1_H21); +} - mu_assert( - manufacturer_block[position + 3] == atqa[1], "manufacturer_block atqa1 assert failed\r\n"); - - for(uint8_t i = position + 4; i < 16; i++) { - mu_assert( - manufacturer_block[i] == 0xFF, "manufacturer_block[i] == 0xFF assert failed\r\n"); - } - - // Reference sector trailers (should be 0xFF[6] + 0xFF + 0x07 + 0x80 + 0x69 + 0xFF[6]) - uint8_t sector_trailer[16] = { - 0xFF, - 0xFF, - 0xFF, - 0xFF, - 0xFF, - 0xFF, - 0xFF, - 0x07, - 0x80, - 0x69, - 0xFF, - 0xFF, - 0xFF, - 0xFF, - 0xFF, - 0xFF}; - // Reference block data - uint8_t block_data[16] = {}; - memset(block_data, 0xff, sizeof(block_data)); - uint16_t total_blocks = mf_classic_get_total_block_num(type); - for(size_t i = 1; i < total_blocks; i++) { - if(mf_classic_is_sector_trailer(i)) { - mu_assert( - memcmp(mf_data->block[i].value, sector_trailer, 16) == 0, - "Failed sector trailer compare"); - } else { - mu_assert(memcmp(mf_data->block[i].value, block_data, 16) == 0, "Failed data compare"); - } - } - // Save the NFC device data to the file - mu_assert( - nfc_device_save(nfc_dev, NFC_TEST_NFC_DEV_PATH), - "nfc_device_save == true assert failed\r\n"); - // Verify that key cache is saved - FuriString* key_cache_name = furi_string_alloc(); - furi_string_set_str(key_cache_name, "/ext/nfc/.cache/"); - for(size_t i = 0; i < uid_len; i++) { - furi_string_cat_printf(key_cache_name, "%02X", uid[i]); - } - furi_string_cat_printf(key_cache_name, ".keys"); - mu_assert( - storage_common_stat(nfc_dev->storage, furi_string_get_cstr(key_cache_name), NULL) == - FSE_OK, - "Key cache file save failed"); - nfc_device_free(nfc_dev); - - // Load the NFC device data from the file - NfcDevice* nfc_validate = nfc_device_alloc(); - mu_assert(nfc_validate, "Nfc device alloc assert"); - mu_assert( - nfc_device_load(nfc_validate, NFC_TEST_NFC_DEV_PATH, false), - "nfc_device_load == true assert failed\r\n"); +MU_TEST(mf_ultralight_ntag_203_file_test) { + mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeNTAG203); +} - // Check the UID, sak, ATQA and type - mu_assert( - memcmp(nfc_validate->dev_data.nfc_data.uid, uid, uid_len) == 0, - "uid compare assert failed\r\n"); - mu_assert(nfc_validate->dev_data.nfc_data.sak == sak, "sak compare assert failed\r\n"); - mu_assert( - memcmp(nfc_validate->dev_data.nfc_data.atqa, atqa, 2) == 0, - "atqa compare assert failed\r\n"); - mu_assert( - nfc_validate->dev_data.nfc_data.type == FuriHalNfcTypeA, - "type == FuriHalNfcTypeA assert failed\r\n"); +MU_TEST(mf_ultralight_ntag_213_file_test) { + mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeNTAG213); +} - // Check the manufacturer block - mu_assert( - memcmp(nfc_validate->dev_data.mf_classic_data.block[0].value, manufacturer_block, 16) == 0, - "manufacturer_block assert failed\r\n"); - // Check other blocks - for(size_t i = 1; i < total_blocks; i++) { - if(mf_classic_is_sector_trailer(i)) { - mu_assert( - memcmp(mf_data->block[i].value, sector_trailer, 16) == 0, - "Failed sector trailer compare"); - } else { - mu_assert(memcmp(mf_data->block[i].value, block_data, 16) == 0, "Failed data compare"); - } - } - nfc_device_free(nfc_validate); - - // Check saved key cache - NfcDevice* nfc_keys = nfc_device_alloc(); - mu_assert(nfc_validate, "Nfc device alloc assert"); - nfc_keys->dev_data.nfc_data.uid_len = uid_len; - memcpy(nfc_keys->dev_data.nfc_data.uid, uid, uid_len); - mu_assert(nfc_device_load_key_cache(nfc_keys), "Failed to load key cache"); - uint8_t total_sec = mf_classic_get_total_sectors_num(type); - uint8_t default_key[6] = {}; - memset(default_key, 0xff, 6); - for(size_t i = 0; i < total_sec; i++) { - MfClassicSectorTrailer* sec_tr = - mf_classic_get_sector_trailer_by_sector(&nfc_keys->dev_data.mf_classic_data, i); - mu_assert(memcmp(sec_tr->key_a, default_key, 6) == 0, "Failed key compare"); - mu_assert(memcmp(sec_tr->key_b, default_key, 6) == 0, "Failed key compare"); - } - - // Delete key cache file - mu_assert( - storage_common_remove(nfc_keys->storage, furi_string_get_cstr(key_cache_name)) == FSE_OK, - "Failed to remove key cache file"); - furi_string_free(key_cache_name); - nfc_device_free(nfc_keys); +MU_TEST(mf_ultralight_ntag_215_file_test) { + mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeNTAG215); } -MU_TEST(mf_mini_file_test) { - mf_classic_generator_test(4, MfClassicTypeMini); +MU_TEST(mf_ultralight_ntag_216_file_test) { + mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeNTAG216); } -MU_TEST(mf_classic_1k_4b_file_test) { - mf_classic_generator_test(4, MfClassicType1k); +MU_TEST(mf_ultralight_ntag_i2c_1k_file_test) { + mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeNTAGI2C1k); } -MU_TEST(mf_classic_4k_4b_file_test) { - mf_classic_generator_test(4, MfClassicType4k); +MU_TEST(mf_ultralight_ntag_i2c_2k_file_test) { + mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeNTAGI2C2k); } -MU_TEST(mf_classic_1k_7b_file_test) { - mf_classic_generator_test(7, MfClassicType1k); +MU_TEST(mf_ultralight_ntag_i2c_plus_1k_file_test) { + mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeNTAGI2CPlus1k); } -MU_TEST(mf_classic_4k_7b_file_test) { - mf_classic_generator_test(7, MfClassicType4k); +MU_TEST(mf_ultralight_ntag_i2c_plus_2k_file_test) { + mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeNTAGI2CPlus2k); } MU_TEST_SUITE(nfc) { nfc_test_alloc(); - MU_RUN_TEST(nfca_file_test); - MU_RUN_TEST(mf_mini_file_test); - MU_RUN_TEST(mf_classic_1k_4b_file_test); - MU_RUN_TEST(mf_classic_4k_4b_file_test); - MU_RUN_TEST(mf_classic_1k_7b_file_test); - MU_RUN_TEST(mf_classic_4k_7b_file_test); - MU_RUN_TEST(nfc_digital_signal_test); - MU_RUN_TEST(mf_classic_dict_test); - MU_RUN_TEST(mf_classic_dict_load_test); + MU_RUN_TEST(nfca_4b_file_test); + MU_RUN_TEST(nfca_7b_file_test); + + MU_RUN_TEST(mf_ultralight_file_test); + MU_RUN_TEST(mf_ultralight_ev1_11_file_test); + MU_RUN_TEST(mf_ultralight_ev1_h11_file_test); + MU_RUN_TEST(mf_ultralight_ev1_21_file_test); + MU_RUN_TEST(mf_ultralight_ev1_h21_file_test); + MU_RUN_TEST(mf_ultralight_ntag_203_file_test); + MU_RUN_TEST(mf_ultralight_ntag_213_file_test); + MU_RUN_TEST(mf_ultralight_ntag_215_file_test); + MU_RUN_TEST(mf_ultralight_ntag_216_file_test); + MU_RUN_TEST(mf_ultralight_ntag_i2c_1k_file_test); + MU_RUN_TEST(mf_ultralight_ntag_i2c_2k_file_test); + MU_RUN_TEST(mf_ultralight_ntag_i2c_plus_1k_file_test); + MU_RUN_TEST(mf_ultralight_ntag_i2c_plus_2k_file_test); nfc_test_free(); } diff --git a/applications/debug/unit_tests/nfc/nfc_test_old.c b/applications/debug/unit_tests/nfc/nfc_test_old.c new file mode 100644 index 000000000000..e606ff5d78d8 --- /dev/null +++ b/applications/debug/unit_tests/nfc/nfc_test_old.c @@ -0,0 +1,532 @@ +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include + +// #include +// #include + +// #include "../minunit.h" + +// #define TAG "NfcTest" + +// #define NFC_TEST_RESOURCES_DIR EXT_PATH("unit_tests/nfc/") +// #define NFC_TEST_SIGNAL_SHORT_FILE "nfc_nfca_signal_short.nfc" +// #define NFC_TEST_SIGNAL_LONG_FILE "nfc_nfca_signal_long.nfc" +// #define NFC_TEST_DICT_PATH EXT_PATH("unit_tests/mf_classic_dict.nfc") +// #define NFC_TEST_NFC_DEV_PATH EXT_PATH("unit_tests/nfc/nfc_dev_test.nfc") + +// static const char* nfc_test_file_type = "Flipper NFC test"; +// static const uint32_t nfc_test_file_version = 1; + +// #define NFC_TEST_DATA_MAX_LEN 18 +// #define NFC_TETS_TIMINGS_MAX_LEN 1350 + +// typedef struct { +// Storage* storage; +// NfcaSignal* signal; +// uint32_t test_data_len; +// uint8_t test_data[NFC_TEST_DATA_MAX_LEN]; +// uint32_t test_timings_len; +// uint32_t test_timings[NFC_TETS_TIMINGS_MAX_LEN]; +// } NfcTest; + +// static NfcTest* nfc_test = NULL; + +// static void nfc_test_alloc() { +// nfc_test = malloc(sizeof(NfcTest)); +// nfc_test->signal = nfca_signal_alloc(); +// nfc_test->storage = furi_record_open(RECORD_STORAGE); +// } + +// static void nfc_test_free() { +// furi_assert(nfc_test); + +// furi_record_close(RECORD_STORAGE); +// nfca_signal_free(nfc_test->signal); +// free(nfc_test); +// nfc_test = NULL; +// } + +// static bool nfc_test_read_signal_from_file(const char* file_name) { +// bool success = false; + +// FlipperFormat* file = flipper_format_file_alloc(nfc_test->storage); +// FuriString* file_type; +// file_type = furi_string_alloc(); +// uint32_t file_version = 0; + +// do { +// if(!flipper_format_file_open_existing(file, file_name)) break; +// if(!flipper_format_read_header(file, file_type, &file_version)) break; +// if(furi_string_cmp_str(file_type, nfc_test_file_type) || +// file_version != nfc_test_file_version) +// break; +// if(!flipper_format_read_uint32(file, "Data length", &nfc_test->test_data_len, 1)) break; +// if(nfc_test->test_data_len > NFC_TEST_DATA_MAX_LEN) break; +// if(!flipper_format_read_hex( +// file, "Plain data", nfc_test->test_data, nfc_test->test_data_len)) +// break; +// if(!flipper_format_read_uint32(file, "Timings length", &nfc_test->test_timings_len, 1)) +// break; +// if(nfc_test->test_timings_len > NFC_TETS_TIMINGS_MAX_LEN) break; +// if(!flipper_format_read_uint32( +// file, "Timings", nfc_test->test_timings, nfc_test->test_timings_len)) +// break; +// success = true; +// } while(false); + +// furi_string_free(file_type); +// flipper_format_free(file); + +// return success; +// } + +// static bool nfc_test_digital_signal_test_encode( +// const char* file_name, +// uint32_t encode_max_time, +// uint32_t timing_tolerance, +// uint32_t timings_sum_tolerance) { +// furi_assert(nfc_test); + +// bool success = false; +// uint32_t time = 0; +// uint32_t dut_timings_sum = 0; +// uint32_t ref_timings_sum = 0; +// uint8_t parity[10] = {}; + +// do { +// // Read test data +// if(!nfc_test_read_signal_from_file(file_name)) { +// FURI_LOG_E(TAG, "Failed to read signal from file"); +// break; +// } + +// // Encode signal +// FURI_CRITICAL_ENTER(); +// time = DWT->CYCCNT; +// nfca_signal_encode( +// nfc_test->signal, nfc_test->test_data, nfc_test->test_data_len * 8, parity); +// digital_signal_prepare_arr(nfc_test->signal->tx_signal); +// time = (DWT->CYCCNT - time) / furi_hal_cortex_instructions_per_microsecond(); +// FURI_CRITICAL_EXIT(); + +// // Check timings +// if(time > encode_max_time) { +// FURI_LOG_E( +// TAG, "Encoding time: %ld us while accepted value: %ld us", time, encode_max_time); +// break; +// } + +// // Check data +// if(nfc_test->signal->tx_signal->edge_cnt != nfc_test->test_timings_len) { +// FURI_LOG_E(TAG, "Not equal timings buffers length"); +// break; +// } + +// uint32_t timings_diff = 0; +// uint32_t* ref = nfc_test->test_timings; +// uint32_t* dut = nfc_test->signal->tx_signal->reload_reg_buff; +// bool timing_check_success = true; +// for(size_t i = 0; i < nfc_test->test_timings_len; i++) { +// timings_diff = dut[i] > ref[i] ? dut[i] - ref[i] : ref[i] - dut[i]; +// dut_timings_sum += dut[i]; +// ref_timings_sum += ref[i]; +// if(timings_diff > timing_tolerance) { +// FURI_LOG_E( +// TAG, "Too big difference in %d timings. Ref: %ld, DUT: %ld", i, ref[i], dut[i]); +// timing_check_success = false; +// break; +// } +// } +// if(!timing_check_success) break; +// uint32_t sum_diff = dut_timings_sum > ref_timings_sum ? dut_timings_sum - ref_timings_sum : +// ref_timings_sum - dut_timings_sum; +// if(sum_diff > timings_sum_tolerance) { +// FURI_LOG_E( +// TAG, +// "Too big difference in timings sum. Ref: %ld, DUT: %ld", +// ref_timings_sum, +// dut_timings_sum); +// break; +// } + +// FURI_LOG_I(TAG, "Encoding time: %ld us. Acceptable time: %ld us", time, encode_max_time); +// FURI_LOG_I( +// TAG, +// "Timings sum difference: %ld [1/64MHZ]. Acceptable difference: %ld [1/64MHz]", +// sum_diff, +// timings_sum_tolerance); +// success = true; +// } while(false); + +// return success; +// } + +// MU_TEST(nfc_digital_signal_test) { +// mu_assert( +// nfc_test_digital_signal_test_encode( +// NFC_TEST_RESOURCES_DIR NFC_TEST_SIGNAL_SHORT_FILE, 500, 1, 37), +// "NFC short digital signal test failed\r\n"); +// mu_assert( +// nfc_test_digital_signal_test_encode( +// NFC_TEST_RESOURCES_DIR NFC_TEST_SIGNAL_LONG_FILE, 2000, 1, 37), +// "NFC long digital signal test failed\r\n"); +// } + +// MU_TEST(mf_classic_dict_test) { +// MfClassicDict* instance = NULL; +// uint64_t key = 0; +// FuriString* temp_str; +// temp_str = furi_string_alloc(); + +// instance = mf_classic_dict_alloc(MfClassicDictTypeUnitTest); +// mu_assert(instance != NULL, "mf_classic_dict_alloc\r\n"); + +// mu_assert( +// mf_classic_dict_get_total_keys(instance) == 0, +// "mf_classic_dict_get_total_keys == 0 assert failed\r\n"); + +// furi_string_set(temp_str, "2196FAD8115B"); +// mu_assert( +// mf_classic_dict_add_key_str(instance, temp_str), +// "mf_classic_dict_add_key == true assert failed\r\n"); + +// mu_assert( +// mf_classic_dict_get_total_keys(instance) == 1, +// "mf_classic_dict_get_total_keys == 1 assert failed\r\n"); + +// mu_assert(mf_classic_dict_rewind(instance), "mf_classic_dict_rewind == 1 assert failed\r\n"); + +// mu_assert( +// mf_classic_dict_get_key_at_index_str(instance, temp_str, 0), +// "mf_classic_dict_get_key_at_index_str == true assert failed\r\n"); +// mu_assert( +// furi_string_cmp(temp_str, "2196FAD8115B") == 0, +// "string_cmp(temp_str, \"2196FAD8115B\") == 0 assert failed\r\n"); + +// mu_assert(mf_classic_dict_rewind(instance), "mf_classic_dict_rewind == 1 assert failed\r\n"); + +// mu_assert( +// mf_classic_dict_get_key_at_index(instance, &key, 0), +// "mf_classic_dict_get_key_at_index == true assert failed\r\n"); +// mu_assert(key == 0x2196FAD8115B, "key == 0x2196FAD8115B assert failed\r\n"); + +// mu_assert(mf_classic_dict_rewind(instance), "mf_classic_dict_rewind == 1 assert failed\r\n"); + +// mu_assert( +// mf_classic_dict_delete_index(instance, 0), +// "mf_classic_dict_delete_index == true assert failed\r\n"); + +// mf_classic_dict_free(instance); +// furi_string_free(temp_str); +// } + +// MU_TEST(mf_classic_dict_load_test) { +// Storage* storage = furi_record_open(RECORD_STORAGE); +// mu_assert(storage != NULL, "storage != NULL assert failed\r\n"); + +// // Delete unit test dict file if exists +// if(storage_file_exists(storage, NFC_TEST_DICT_PATH)) { +// mu_assert( +// storage_simply_remove(storage, NFC_TEST_DICT_PATH), +// "remove == true assert failed\r\n"); +// } + +// // Create unit test dict file +// Stream* file_stream = file_stream_alloc(storage); +// mu_assert(file_stream != NULL, "file_stream != NULL assert failed\r\n"); +// mu_assert( +// file_stream_open(file_stream, NFC_TEST_DICT_PATH, FSAM_WRITE, FSOM_OPEN_ALWAYS), +// "file_stream_open == true assert failed\r\n"); + +// // Write unit test dict file +// char key_str[] = "a0a1a2a3a4a5"; +// mu_assert( +// stream_write_cstring(file_stream, key_str) == strlen(key_str), +// "write == true assert failed\r\n"); +// // Close unit test dict file +// mu_assert(file_stream_close(file_stream), "file_stream_close == true assert failed\r\n"); + +// // Load unit test dict file +// MfClassicDict* instance = NULL; +// instance = mf_classic_dict_alloc(MfClassicDictTypeUnitTest); +// mu_assert(instance != NULL, "mf_classic_dict_alloc\r\n"); +// uint32_t total_keys = mf_classic_dict_get_total_keys(instance); +// mu_assert(total_keys == 1, "total_keys == 1 assert failed\r\n"); + +// // Read key +// uint64_t key_ref = 0xa0a1a2a3a4a5; +// uint64_t key_dut = 0; +// FuriString* temp_str = furi_string_alloc(); +// mu_assert( +// mf_classic_dict_get_next_key_str(instance, temp_str), +// "get_next_key_str == true assert failed\r\n"); +// mu_assert(furi_string_cmp_str(temp_str, key_str) == 0, "invalid key loaded\r\n"); +// mu_assert(mf_classic_dict_rewind(instance), "mf_classic_dict_rewind == 1 assert failed\r\n"); +// mu_assert( +// mf_classic_dict_get_next_key(instance, &key_dut), +// "get_next_key == true assert failed\r\n"); +// mu_assert(key_dut == key_ref, "invalid key loaded\r\n"); +// furi_string_free(temp_str); +// mf_classic_dict_free(instance); + +// // Check that MfClassicDict added new line to the end of the file +// mu_assert( +// file_stream_open(file_stream, NFC_TEST_DICT_PATH, FSAM_READ, FSOM_OPEN_EXISTING), +// "file_stream_open == true assert failed\r\n"); +// mu_assert(stream_seek(file_stream, -1, StreamOffsetFromEnd), "seek == true assert failed\r\n"); +// uint8_t last_char = 0; +// mu_assert(stream_read(file_stream, &last_char, 1) == 1, "read == true assert failed\r\n"); +// mu_assert(last_char == '\n', "last_char == '\\n' assert failed\r\n"); +// mu_assert(file_stream_close(file_stream), "file_stream_close == true assert failed\r\n"); + +// // Delete unit test dict file +// mu_assert( +// storage_simply_remove(storage, NFC_TEST_DICT_PATH), "remove == true assert failed\r\n"); +// stream_free(file_stream); +// furi_record_close(RECORD_STORAGE); +// } + +// MU_TEST(nfca_file_test) { +// NfcDevice* nfc = nfc_device_alloc(); +// mu_assert(nfc != NULL, "nfc_device_data != NULL assert failed\r\n"); +// nfc->format = NfcDeviceSaveFormatUid; + +// // Fill the UID, sak, ATQA and type +// uint8_t uid[7] = {0x04, 0x01, 0x23, 0x45, 0x67, 0x89, 0x00}; +// memcpy(nfc->dev_data.nfc_data.uid, uid, 7); +// nfc->dev_data.nfc_data.uid_len = 7; + +// nfc->dev_data.nfc_data.sak = 0x08; +// nfc->dev_data.nfc_data.atqa[0] = 0x00; +// nfc->dev_data.nfc_data.atqa[1] = 0x04; +// nfc->dev_data.nfc_data.type = FuriHalNfcTypeA; + +// // Save the NFC device data to the file +// mu_assert( +// nfc_device_save(nfc, NFC_TEST_NFC_DEV_PATH), "nfc_device_save == true assert failed\r\n"); +// nfc_device_free(nfc); + +// // Load the NFC device data from the file +// NfcDevice* nfc_validate = nfc_device_alloc(); +// mu_assert( +// nfc_device_load(nfc_validate, NFC_TEST_NFC_DEV_PATH, true), +// "nfc_device_load == true assert failed\r\n"); + +// // Check the UID, sak, ATQA and type +// mu_assert(memcmp(nfc_validate->dev_data.nfc_data.uid, uid, 7) == 0, "uid assert failed\r\n"); +// mu_assert(nfc_validate->dev_data.nfc_data.sak == 0x08, "sak == 0x08 assert failed\r\n"); +// mu_assert( +// nfc_validate->dev_data.nfc_data.atqa[0] == 0x00, "atqa[0] == 0x00 assert failed\r\n"); +// mu_assert( +// nfc_validate->dev_data.nfc_data.atqa[1] == 0x04, "atqa[1] == 0x04 assert failed\r\n"); +// mu_assert( +// nfc_validate->dev_data.nfc_data.type == FuriHalNfcTypeA, +// "type == FuriHalNfcTypeA assert failed\r\n"); +// nfc_device_free(nfc_validate); +// } + +// static void mf_classic_generator_test(uint8_t uid_len, MfClassicType type) { +// NfcDevice* nfc_dev = nfc_device_alloc(); +// mu_assert(nfc_dev != NULL, "nfc_device_data != NULL assert failed\r\n"); +// nfc_dev->format = NfcDeviceSaveFormatMifareClassic; + +// // Create a test file +// nfc_generate_mf_classic(&nfc_dev->dev_data, uid_len, type); + +// // Get the uid from generated MFC +// uint8_t uid[7] = {0}; +// memcpy(uid, nfc_dev->dev_data.nfc_data.uid, uid_len); +// uint8_t sak = nfc_dev->dev_data.nfc_data.sak; +// uint8_t atqa[2] = {}; +// memcpy(atqa, nfc_dev->dev_data.nfc_data.atqa, 2); + +// MfClassicData* mf_data = &nfc_dev->dev_data.mf_classic_data; +// // Check the manufacturer block (should be uid[uid_len] + BCC (for 4byte only) + SAK + ATQA0 + ATQA1 + 0xFF[rest]) +// uint8_t manufacturer_block[16] = {0}; +// memcpy(manufacturer_block, nfc_dev->dev_data.mf_classic_data.block[0].value, 16); +// mu_assert( +// memcmp(manufacturer_block, uid, uid_len) == 0, +// "manufacturer_block uid doesn't match the file\r\n"); + +// uint8_t position = 0; +// if(uid_len == 4) { +// position = uid_len; + +// uint8_t bcc = 0; + +// for(int i = 0; i < uid_len; i++) { +// bcc ^= uid[i]; +// } + +// mu_assert(manufacturer_block[position] == bcc, "manufacturer_block bcc assert failed\r\n"); +// } else { +// position = uid_len - 1; +// } + +// mu_assert(manufacturer_block[position + 1] == sak, "manufacturer_block sak assert failed\r\n"); + +// mu_assert( +// manufacturer_block[position + 2] == atqa[0], "manufacturer_block atqa0 assert failed\r\n"); + +// mu_assert( +// manufacturer_block[position + 3] == atqa[1], "manufacturer_block atqa1 assert failed\r\n"); + +// for(uint8_t i = position + 4; i < 16; i++) { +// mu_assert( +// manufacturer_block[i] == 0xFF, "manufacturer_block[i] == 0xFF assert failed\r\n"); +// } + +// // Reference sector trailers (should be 0xFF[6] + 0xFF + 0x07 + 0x80 + 0x69 + 0xFF[6]) +// uint8_t sector_trailer[16] = { +// 0xFF, +// 0xFF, +// 0xFF, +// 0xFF, +// 0xFF, +// 0xFF, +// 0xFF, +// 0x07, +// 0x80, +// 0x69, +// 0xFF, +// 0xFF, +// 0xFF, +// 0xFF, +// 0xFF, +// 0xFF}; +// // Reference block data +// uint8_t block_data[16] = {}; +// memset(block_data, 0xff, sizeof(block_data)); +// uint16_t total_blocks = mf_classic_get_total_block_num(type); +// for(size_t i = 1; i < total_blocks; i++) { +// if(mf_classic_is_sector_trailer(i)) { +// mu_assert( +// memcmp(mf_data->block[i].value, sector_trailer, 16) == 0, +// "Failed sector trailer compare"); +// } else { +// mu_assert(memcmp(mf_data->block[i].value, block_data, 16) == 0, "Failed data compare"); +// } +// } +// // Save the NFC device data to the file +// mu_assert( +// nfc_device_save(nfc_dev, NFC_TEST_NFC_DEV_PATH), +// "nfc_device_save == true assert failed\r\n"); +// // Verify that key cache is saved +// FuriString* key_cache_name = furi_string_alloc(); +// furi_string_set_str(key_cache_name, "/ext/nfc/.cache/"); +// for(size_t i = 0; i < uid_len; i++) { +// furi_string_cat_printf(key_cache_name, "%02X", uid[i]); +// } +// furi_string_cat_printf(key_cache_name, ".keys"); +// mu_assert( +// storage_common_stat(nfc_dev->storage, furi_string_get_cstr(key_cache_name), NULL) == +// FSE_OK, +// "Key cache file save failed"); +// nfc_device_free(nfc_dev); + +// // Load the NFC device data from the file +// NfcDevice* nfc_validate = nfc_device_alloc(); +// mu_assert(nfc_validate, "Nfc device alloc assert"); +// mu_assert( +// nfc_device_load(nfc_validate, NFC_TEST_NFC_DEV_PATH, false), +// "nfc_device_load == true assert failed\r\n"); + +// // Check the UID, sak, ATQA and type +// mu_assert( +// memcmp(nfc_validate->dev_data.nfc_data.uid, uid, uid_len) == 0, +// "uid compare assert failed\r\n"); +// mu_assert(nfc_validate->dev_data.nfc_data.sak == sak, "sak compare assert failed\r\n"); +// mu_assert( +// memcmp(nfc_validate->dev_data.nfc_data.atqa, atqa, 2) == 0, +// "atqa compare assert failed\r\n"); +// mu_assert( +// nfc_validate->dev_data.nfc_data.type == FuriHalNfcTypeA, +// "type == FuriHalNfcTypeA assert failed\r\n"); + +// // Check the manufacturer block +// mu_assert( +// memcmp(nfc_validate->dev_data.mf_classic_data.block[0].value, manufacturer_block, 16) == 0, +// "manufacturer_block assert failed\r\n"); +// // Check other blocks +// for(size_t i = 1; i < total_blocks; i++) { +// if(mf_classic_is_sector_trailer(i)) { +// mu_assert( +// memcmp(mf_data->block[i].value, sector_trailer, 16) == 0, +// "Failed sector trailer compare"); +// } else { +// mu_assert(memcmp(mf_data->block[i].value, block_data, 16) == 0, "Failed data compare"); +// } +// } +// nfc_device_free(nfc_validate); + +// // Check saved key cache +// NfcDevice* nfc_keys = nfc_device_alloc(); +// mu_assert(nfc_validate, "Nfc device alloc assert"); +// nfc_keys->dev_data.nfc_data.uid_len = uid_len; +// memcpy(nfc_keys->dev_data.nfc_data.uid, uid, uid_len); +// mu_assert(nfc_device_load_key_cache(nfc_keys), "Failed to load key cache"); +// uint8_t total_sec = mf_classic_get_total_sectors_num(type); +// uint8_t default_key[6] = {}; +// memset(default_key, 0xff, 6); +// for(size_t i = 0; i < total_sec; i++) { +// MfClassicSectorTrailer* sec_tr = +// mf_classic_get_sector_trailer_by_sector(&nfc_keys->dev_data.mf_classic_data, i); +// mu_assert(memcmp(sec_tr->key_a, default_key, 6) == 0, "Failed key compare"); +// mu_assert(memcmp(sec_tr->key_b, default_key, 6) == 0, "Failed key compare"); +// } + +// // Delete key cache file +// mu_assert( +// storage_common_remove(nfc_keys->storage, furi_string_get_cstr(key_cache_name)) == FSE_OK, +// "Failed to remove key cache file"); +// furi_string_free(key_cache_name); +// nfc_device_free(nfc_keys); +// } + +// MU_TEST(mf_mini_file_test) { +// mf_classic_generator_test(4, MfClassicTypeMini); +// } + +// MU_TEST(mf_classic_1k_4b_file_test) { +// mf_classic_generator_test(4, MfClassicType1k); +// } + +// MU_TEST(mf_classic_4k_4b_file_test) { +// mf_classic_generator_test(4, MfClassicType4k); +// } + +// MU_TEST(mf_classic_1k_7b_file_test) { +// mf_classic_generator_test(7, MfClassicType1k); +// } + +// MU_TEST(mf_classic_4k_7b_file_test) { +// mf_classic_generator_test(7, MfClassicType4k); +// } + +// MU_TEST_SUITE(nfc) { +// nfc_test_alloc(); + +// MU_RUN_TEST(nfca_file_test); +// MU_RUN_TEST(mf_mini_file_test); +// MU_RUN_TEST(mf_classic_1k_4b_file_test); +// MU_RUN_TEST(mf_classic_4k_4b_file_test); +// MU_RUN_TEST(mf_classic_1k_7b_file_test); +// MU_RUN_TEST(mf_classic_4k_7b_file_test); +// MU_RUN_TEST(nfc_digital_signal_test); +// MU_RUN_TEST(mf_classic_dict_test); +// MU_RUN_TEST(mf_classic_dict_load_test); + +// nfc_test_free(); +// } + +// int run_minunit_test_nfc() { +// MU_RUN_SUITE(nfc); +// return MU_EXIT_CODE; +// } From 1c0f2b29a6f7f197df5b550dbeb44e7b3b7e7b14 Mon Sep 17 00:00:00 2001 From: gornekich Date: Wed, 3 May 2023 20:12:08 +0400 Subject: [PATCH 054/149] nfc: fix false positive fwt timeout --- .../main/nfc/scenes/nfc_scene_nfca_read.c | 2 +- firmware/targets/f7/api_symbols.csv | 3 +- firmware/targets/f7/furi_hal/f_hal_nfc.c | 1 + .../targets/f7/furi_hal/f_hal_nfc_event.c | 39 ++++++++----------- firmware/targets/f7/furi_hal/f_hal_nfc_i.h | 4 ++ firmware/targets/furi_hal_include/f_hal_nfc.h | 2 + lib/nfc/nfc.c | 39 ++++++++++++++----- lib/nfc/nfc.h | 1 + lib/nfc/nfc_poller.c | 26 +++++++------ lib/nfc/protocols/nfca/nfca_poller.c | 11 ++++-- lib/nfc/protocols/nfcb/nfcb_poller.c | 6 +-- 11 files changed, 84 insertions(+), 50 deletions(-) diff --git a/applications/main/nfc/scenes/nfc_scene_nfca_read.c b/applications/main/nfc/scenes/nfc_scene_nfca_read.c index 2f99050286d7..a9d432e7a25b 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfca_read.c +++ b/applications/main/nfc/scenes/nfc_scene_nfca_read.c @@ -11,6 +11,7 @@ NfcaPollerCommand nfc_scene_nfca_read_worker_callback(NfcaPollerEvent event, voi NfcaPollerCommand command = NfcaPollerCommandContinue; if(event.type == NfcaPollerEventTypeReady) { + nfca_poller_get_data(nfc->nfca_poller, &nfc->nfc_dev_data.nfca_data); view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcWorkerEventReadUidNfcA); command = NfcaPollerCommandStop; } @@ -36,7 +37,6 @@ bool nfc_scene_nfca_read_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == NfcWorkerEventReadUidNfcA) { notification_message(nfc->notifications, &sequence_success); - nfca_poller_get_data(nfc->nfca_poller, &nfc->nfc_dev_data.nfca_data); scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcaReadSuccess); DOLPHIN_DEED(DolphinDeedNfcReadSuccess); consumed = true; diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 4bba65317536..7ae291dc3cd8 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,+,20.6,, +Version,+,20.7,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -817,6 +817,7 @@ Function,-,expm1f,float,float Function,-,expm1l,long double,long double Function,-,f_hal_nfc_abort,FHalNfcError, Function,-,f_hal_nfc_acquire,FHalNfcError, +Function,-,f_hal_nfc_event_start,FHalNfcError, Function,-,f_hal_nfc_init,FHalNfcError, Function,-,f_hal_nfc_is_hal_ready,FHalNfcError, Function,-,f_hal_nfc_listen_start,FHalNfcError, diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc.c b/firmware/targets/f7/furi_hal/f_hal_nfc.c index 065a911911a4..58d9e996f24f 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfc.c +++ b/firmware/targets/f7/furi_hal/f_hal_nfc.c @@ -58,6 +58,7 @@ FHalNfcError f_hal_nfc_init() { f_hal_nfc_mutex = furi_mutex_alloc(FuriMutexTypeNormal); FHalNfcError error = FHalNfcErrorNone; f_hal_nfc_event_init(); + f_hal_nfc_event_start(); FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; furi_hal_spi_acquire(handle); diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc_event.c b/firmware/targets/f7/furi_hal/f_hal_nfc_event.c index fa5d47fa68f5..23e100371228 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfc_event.c +++ b/firmware/targets/f7/furi_hal/f_hal_nfc_event.c @@ -6,6 +6,15 @@ void f_hal_nfc_event_init() { f_hal_nfc_event = malloc(sizeof(FHalNfcEventInternal)); } +FHalNfcError f_hal_nfc_event_start() { + furi_assert(f_hal_nfc_event); + + f_hal_nfc_event->thread = furi_thread_get_current_id(); + furi_thread_flags_clear(F_HAL_NFC_EVENT_INTERNAL_ALL); + + return FHalNfcErrorNone; +} + void f_hal_nfc_set_event(FHalNfcEventInternalType event) { furi_assert(f_hal_nfc_event); furi_assert(f_hal_nfc_event->thread); @@ -20,26 +29,20 @@ FHalNfcError f_hal_nfc_abort() { FHalNfcEvent f_hal_nfc_wait_event(uint32_t timeout_ms) { furi_assert(f_hal_nfc_event); - - f_hal_nfc_event->thread = furi_thread_get_current_id(); - FuriThreadPriority thread_priority = furi_thread_get_current_priority(); - furi_thread_set_current_priority(FuriThreadPriorityHigh); - - FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; - furi_hal_spi_acquire(handle); + furi_assert(f_hal_nfc_event->thread); FHalNfcEvent event = 0; uint32_t event_timeout = timeout_ms == F_HAL_NFC_EVENT_WAIT_FOREVER ? FuriWaitForever : timeout_ms; - uint32_t event_flag = furi_thread_flags_wait( - FHalNfcEventInternalTypeAbort | FHalNfcEventInternalTypeIrq | - FHalNfcEventInternalTypeTimerFwtExpired | FHalNfcEventInternalTypeTimerBlockTxExpired, - FuriFlagWaitAny, - event_timeout); + uint32_t event_flag = + furi_thread_flags_wait(F_HAL_NFC_EVENT_INTERNAL_ALL, FuriFlagWaitAny, event_timeout); if(event_flag != FuriFlagErrorTimeout) { if(event_flag & FHalNfcEventInternalTypeIrq) { furi_thread_flags_clear(FHalNfcEventInternalTypeIrq); + FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; + furi_hal_spi_acquire(handle); uint32_t irq = f_hal_nfc_get_irq(handle); + furi_hal_spi_release(handle); if(irq & ST25R3916_IRQ_MASK_OSC) { event |= FHalNfcEventOscOn; } @@ -47,22 +50,18 @@ FHalNfcEvent f_hal_nfc_wait_event(uint32_t timeout_ms) { event |= FHalNfcEventTxEnd; } if(irq & ST25R3916_IRQ_MASK_RXS) { - // FURI_LOG_I("TAG", "ST25R3916_IRQ_MASK_RXS"); event |= FHalNfcEventRxStart; } if(irq & ST25R3916_IRQ_MASK_RXE) { - // FURI_LOG_I("TAG", "ST25R3916_IRQ_MASK_RXE"); event |= FHalNfcEventRxEnd; } if(irq & ST25R3916_IRQ_MASK_COL) { event |= FHalNfcEventCollision; } if(irq & ST25R3916_IRQ_MASK_EON) { - // FURI_LOG_I("TAG", "ST25R3916_IRQ_MASK_EON"); event |= FHalNfcEventFieldOn; } if(irq & ST25R3916_IRQ_MASK_EOF) { - // FURI_LOG_I("TAG", "ST25R3916_IRQ_MASK_EOF"); event |= FHalNfcEventFieldOff; } if(irq & ST25R3916_IRQ_MASK_WU_A) { @@ -88,10 +87,6 @@ FHalNfcEvent f_hal_nfc_wait_event(uint32_t timeout_ms) { event = FHalNfcEventTimeout; } - furi_hal_spi_release(handle); - furi_thread_set_current_priority(thread_priority); - f_hal_nfc_event->thread = NULL; - return event; } @@ -100,16 +95,16 @@ bool f_hal_nfc_event_wait_for_specific_irq( uint32_t mask, uint32_t timeout_ms) { furi_assert(f_hal_nfc_event); + furi_assert(f_hal_nfc_event->thread); bool irq_received = false; - f_hal_nfc_event->thread = furi_thread_get_current_id(); uint32_t event_flag = furi_thread_flags_wait(FHalNfcEventInternalTypeIrq, FuriFlagWaitAny, timeout_ms); if(event_flag == FHalNfcEventInternalTypeIrq) { uint32_t irq = f_hal_nfc_get_irq(handle); irq_received = ((irq & mask) == mask); + furi_thread_flags_clear(FHalNfcEventInternalTypeIrq); } - f_hal_nfc_event->thread = NULL; return irq_received; } diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc_i.h b/firmware/targets/f7/furi_hal/f_hal_nfc_i.h index 737ab7ba0e41..ed06e4c9b8bd 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfc_i.h +++ b/firmware/targets/f7/furi_hal/f_hal_nfc_i.h @@ -17,6 +17,10 @@ typedef enum { FHalNfcEventInternalTypeTimerBlockTxExpired = (1U << 3), } FHalNfcEventInternalType; +#define F_HAL_NFC_EVENT_INTERNAL_ALL \ + ((FHalNfcEventInternalTypeAbort | FHalNfcEventInternalTypeIrq | \ + FHalNfcEventInternalTypeTimerFwtExpired | FHalNfcEventInternalTypeTimerBlockTxExpired)) + typedef struct { FuriThreadId thread; void* context; diff --git a/firmware/targets/furi_hal_include/f_hal_nfc.h b/firmware/targets/furi_hal_include/f_hal_nfc.h index a41ab9543573..912b84ffc898 100644 --- a/firmware/targets/furi_hal_include/f_hal_nfc.h +++ b/firmware/targets/furi_hal_include/f_hal_nfc.h @@ -108,6 +108,8 @@ FHalNfcError f_hal_nfc_acquire(); FHalNfcError f_hal_nfc_release(); +FHalNfcError f_hal_nfc_event_start(); + FHalNfcError f_hal_nfc_poller_tx(uint8_t* tx_data, uint16_t tx_bits); FHalNfcError f_hal_nfc_poller_rx(uint8_t* rx_data, uint16_t rx_data_size, uint16_t* rx_bits); diff --git a/lib/nfc/nfc.c b/lib/nfc/nfc.c index 65a63a3471d5..477fc387aa7a 100644 --- a/lib/nfc/nfc.c +++ b/lib/nfc/nfc.c @@ -71,6 +71,8 @@ static int32_t nfc_worker_listener(void* context) { NfcEvent nfc_event = {}; // NfcCommand cmd = NfcCommandContinue; + f_hal_nfc_event_start(); + while(true) { FHalNfcEvent event = f_hal_nfc_wait_event(F_HAL_NFC_EVENT_WAIT_FOREVER); if(event & FHalNfcEventAbortRequest) { @@ -118,6 +120,8 @@ static int32_t nfc_worker_poller(void* context) { NfcEvent nfc_event = {}; NfcCommand cmd = NfcCommandContinue; + f_hal_nfc_event_start(); + while(true) { if(instance->state == NfcStateIdle) { f_hal_nfc_low_power_mode_stop(); @@ -131,6 +135,10 @@ static int32_t nfc_worker_poller(void* context) { if(cmd == NfcCommandReset) { instance->state = NfcStatePollerReset; } else if(cmd == NfcCommandStop) { + nfc_config(instance, NfcModeIdle); + nfc_event.type = NfcEventTypeReset; + instance->callback(nfc_event, instance->context); + f_hal_nfc_low_power_mode_start(); break; } else { instance->state = NfcStateConfigured; @@ -150,15 +158,25 @@ static int32_t nfc_worker_poller(void* context) { if(cmd == NfcCommandReset) { instance->state = NfcStatePollerReset; } else if(cmd == NfcCommandStop) { + nfc_config(instance, NfcModeIdle); + nfc_event.type = NfcEventTypeReset; + instance->callback(nfc_event, instance->context); + f_hal_nfc_low_power_mode_start(); break; } } else if(instance->state == NfcStatePollerReset) { nfc_config(instance, NfcModeIdle); + nfc_event.type = NfcEventTypeReset; + cmd = instance->callback(nfc_event, instance->context); f_hal_nfc_low_power_mode_start(); + if(cmd == NfcCommandStop) { + break; + } + // Delay to power off target nfc device + furi_delay_ms(200); instance->state = NfcStateChipSleep; } } - f_hal_nfc_low_power_mode_start(); instance->state = NfcStateChipSleep; return 0; @@ -308,7 +326,7 @@ static NfcError nfc_poller_trx_state_machine(Nfc* instance, uint32_t fwt_fc) { if(event & FHalNfcEventTxEnd) { if(instance->comm_state == NfcCommStateWaitTxEnd) { if(fwt_fc) { - f_hal_nfc_timer_fwt_start(fwt_fc + F_HAL_NFC_TIMER_OFFSET_FC); + f_hal_nfc_timer_fwt_start(fwt_fc); } f_hal_nfc_timer_block_tx_start_us(instance->fdt_poll_poll_us); instance->comm_state = NfcCommStateWaitRxStart; @@ -323,18 +341,21 @@ static NfcError nfc_poller_trx_state_machine(Nfc* instance, uint32_t fwt_fc) { } if(event & FHalNfcEventRxEnd) { f_hal_nfc_timer_block_tx_start(instance->fdt_poll_fc); + f_hal_nfc_timer_fwt_stop(); instance->comm_state = NfcCommStateWaitBlockTxTimer; break; } if(event & FHalNfcEventTimerFwtExpired) { - error = NfcErrorTimeout; - FURI_LOG_W(TAG, "FWT Timeout"); - if(f_hal_nfc_timer_block_tx_is_running()) { - instance->comm_state = NfcCommStateWaitBlockTxTimer; - } else { - instance->comm_state = NfcCommStateReadyTx; + if(instance->comm_state == NfcCommStateWaitRxStart) { + error = NfcErrorTimeout; + FURI_LOG_W(TAG, "FWT Timeout"); + if(f_hal_nfc_timer_block_tx_is_running()) { + instance->comm_state = NfcCommStateWaitBlockTxTimer; + } else { + instance->comm_state = NfcCommStateReadyTx; + } + break; } - break; } } diff --git a/lib/nfc/nfc.h b/lib/nfc/nfc.h index 540eae6b4e18..46c8da1d13cc 100644 --- a/lib/nfc/nfc.h +++ b/lib/nfc/nfc.h @@ -21,6 +21,7 @@ typedef enum { NfcEventTypeListenerActivated, NfcEventTypePollerReady, + NfcEventTypeReset, } NfcEventType; typedef struct { diff --git a/lib/nfc/nfc_poller.c b/lib/nfc/nfc_poller.c index 402dd4a5996d..02facd439613 100644 --- a/lib/nfc/nfc_poller.c +++ b/lib/nfc/nfc_poller.c @@ -54,6 +54,9 @@ static NfcCommand nfc_poller_event_callback(NfcEvent event, void* context) { furi_assert(context); NfcPoller* instance = context; + furi_assert(instance->callback); + furi_assert(instance->session_state != NfcPollerSessionStateIdle); + NfcPollerEvent poller_event; NfcCommand command = NfcCommandContinue; @@ -64,7 +67,7 @@ static NfcCommand nfc_poller_event_callback(NfcEvent event, void* context) { if(instance->state == NfcPollerStateCheckPresenceNfca) { nfca_poller_config(instance->nfca_poller); } else if(instance->state == NfcPollerStateCheckPresenceNfcb) { - nfcb_poller_config(instance->nfcb_poller); + // nfcb_poller_config(instance->nfcb_poller); } } else if(event.type == NfcEventTypePollerReady) { if(instance->state == NfcPollerStateCheckPresenceNfca) { @@ -79,22 +82,23 @@ static NfcCommand nfc_poller_event_callback(NfcEvent event, void* context) { instance->callback(poller_event, instance->context); } else { // Nfca not present + FURI_LOG_E("TAG", "NOT PRESENT"); furi_delay_ms(100); instance->state = NfcPollerStateCheckPresenceNfcb; command = NfcCommandReset; } } else if(instance->state == NfcPollerStateCheckPresenceNfcb) { - NfcbError error = - nfcb_poller_activate(instance->nfcb_poller, &instance->nfcb_data); - if(error == NfcbErrorNone) { - poller_event = NfcPollerEventNfcbDetected; - instance->callback(poller_event, instance->context); - } else { - // Nfcb not present - furi_delay_ms(100); + // NfcbError error = + // nfcb_poller_activate(instance->nfcb_poller, &instance->nfcb_data); + // if(error == NfcbErrorNone) { + // poller_event = NfcPollerEventNfcbDetected; + // instance->callback(poller_event, instance->context); + // } else { + // // Nfcb not present + // furi_delay_ms(100); instance->state = NfcPollerStateCheckPresenceNfca; - command = NfcCommandReset; - } + // command = NfcCommandReset; + // } } } } diff --git a/lib/nfc/protocols/nfca/nfca_poller.c b/lib/nfc/protocols/nfca/nfca_poller.c index b245d2abb3b3..a201a2ca06f1 100644 --- a/lib/nfc/protocols/nfca/nfca_poller.c +++ b/lib/nfc/protocols/nfca/nfca_poller.c @@ -49,11 +49,11 @@ static NfcCommand nfca_poller_event_callback(NfcEvent event, void* context) { NfcaPoller* instance = context; furi_assert(instance->callback); + furi_assert(instance->session_state != NfcaPollerSessionStateIdle); NfcaPollerEvent nfca_poller_event = {}; NfcaPollerCommand command = NfcaPollerCommandContinue; - furi_assert(instance->session_state != NfcaPollerSessionStateIdle); if(instance->session_state == NfcaPollerSessionStateStopRequest) { command = NfcaPollerCommandStop; } else { @@ -80,6 +80,8 @@ static NfcCommand nfca_poller_event_callback(NfcEvent event, void* context) { nfca_poller_event.data.error = NfcaErrorNone; command = instance->callback(nfca_poller_event, instance->context); } + } else if(event.type == NfcEventTypeReset) { + nfca_poller_reset(instance); } } @@ -120,7 +122,11 @@ NfcaError nfca_poller_stop(NfcaPoller* instance) { nfc_stop(instance->nfc); instance->session_state = NfcaPollerSessionStateIdle; - return nfca_poller_reset(instance); + // Check that data is freed + furi_assert(instance->data != NULL); + furi_assert(instance->buff != NULL); + + return NfcaErrorNone; } static NfcaPollerCommand nfca_poller_sync_callback(NfcaPollerEvent event, void* context) { @@ -145,7 +151,6 @@ NfcaError nfca_poller_activate(NfcaPoller* instance, NfcaData* nfca_data) { if(context.error == NfcaErrorNone) { *nfca_data = *instance->data; } - nfca_poller_reset(instance); return context.error; } diff --git a/lib/nfc/protocols/nfcb/nfcb_poller.c b/lib/nfc/protocols/nfcb/nfcb_poller.c index 7defdb07f52e..0365149b27f0 100644 --- a/lib/nfc/protocols/nfcb/nfcb_poller.c +++ b/lib/nfc/protocols/nfcb/nfcb_poller.c @@ -85,9 +85,9 @@ NfcbError nfcb_poller_reset(NfcbPoller* instance) { NfcbError nfcb_poller_config(NfcbPoller* instance) { furi_assert(instance); - instance->data = malloc(sizeof(NfcbData)); - instance->buff = - nfc_poller_buffer_alloc(NFCB_POLLER_BUFER_MAX_SIZE, NFCB_POLLER_BUFER_MAX_SIZE); + // instance->data = malloc(sizeof(NfcbData)); + // instance->buff = + // nfc_poller_buffer_alloc(NFCB_POLLER_BUFER_MAX_SIZE, NFCB_POLLER_BUFER_MAX_SIZE); nfc_config(instance->nfc, NfcModeNfcbPoller); nfc_set_guard_time_us(instance->nfc, NFCB_GUARD_TIME_US); From 39cb8caeeb2892ff0a6e2388c3f32dad26b40403 Mon Sep 17 00:00:00 2001 From: gornekich Date: Thu, 4 May 2023 11:46:58 +0400 Subject: [PATCH 055/149] nfc: add reset in generic poller --- lib/nfc/nfc.c | 2 +- lib/nfc/nfc_poller.c | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/nfc/nfc.c b/lib/nfc/nfc.c index 477fc387aa7a..7332c6d51bc3 100644 --- a/lib/nfc/nfc.c +++ b/lib/nfc/nfc.c @@ -173,7 +173,7 @@ static int32_t nfc_worker_poller(void* context) { break; } // Delay to power off target nfc device - furi_delay_ms(200); + furi_delay_ms(100); instance->state = NfcStateChipSleep; } } diff --git a/lib/nfc/nfc_poller.c b/lib/nfc/nfc_poller.c index 02facd439613..a1acacb5cb46 100644 --- a/lib/nfc/nfc_poller.c +++ b/lib/nfc/nfc_poller.c @@ -100,6 +100,12 @@ static NfcCommand nfc_poller_event_callback(NfcEvent event, void* context) { // command = NfcCommandReset; // } } + } else if(event.type == NfcEventTypeReset) { + if(instance->state == NfcPollerStateCheckPresenceNfca) { + nfca_poller_reset(instance->nfca_poller); + } else if(instance->state == NfcPollerStateCheckPresenceNfcb) { + // nfcb_poller_reset(instance->nfcb_poller); + } } } From a1f5d2c86cf75d814efdf892ca9ba6d580798f9a Mon Sep 17 00:00:00 2001 From: gornekich Date: Thu, 4 May 2023 19:38:56 +0400 Subject: [PATCH 056/149] nfc: fix reset in generic poller --- applications/main/nfc/scenes/nfc_scene_read.c | 9 ++++++- lib/nfc/nfc_poller.c | 26 +++++++++++++++---- lib/nfc/nfc_poller.h | 8 +++++- 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/applications/main/nfc/scenes/nfc_scene_read.c b/applications/main/nfc/scenes/nfc_scene_read.c index 5fb17a5d9364..39c6b1d46b12 100644 --- a/applications/main/nfc/scenes/nfc_scene_read.c +++ b/applications/main/nfc/scenes/nfc_scene_read.c @@ -7,17 +7,24 @@ enum { NfcSceneReadEventMfUltralightDetected, }; -void nfc_scene_read_worker_callback(NfcPollerEvent event, void* context) { +NfcPollerCommand nfc_scene_read_worker_callback(NfcPollerEvent event, void* context) { NfcApp* nfc = context; + NfcPollerCommand command = NfcPollerCommandContinue; + if(event == NfcPollerEventNfcaDetected) { view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcSceneReadEventNfcaDetected); + command = NfcPollerCommandStop; } else if(event == NfcPollerEventNfcbDetected) { view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcSceneReadEventNfcbDetected); + command = NfcPollerCommandStop; } else if(event == NfcPollerEventMfUltralightDetected) { view_dispatcher_send_custom_event( nfc->view_dispatcher, NfcSceneReadEventMfUltralightDetected); + command = NfcPollerCommandStop; } + + return command; } void nfc_scene_read_on_enter(void* context) { diff --git a/lib/nfc/nfc_poller.c b/lib/nfc/nfc_poller.c index a1acacb5cb46..6fb54f994252 100644 --- a/lib/nfc/nfc_poller.c +++ b/lib/nfc/nfc_poller.c @@ -50,6 +50,22 @@ void nfc_poller_free(NfcPoller* instance) { furi_assert(instance); } +static NfcCommand nfc_poller_process_command(NfcPollerCommand command) { + NfcCommand ret = NfcCommandContinue; + + if(command == NfcPollerCommandContinue) { + ret = NfcCommandContinue; + } else if(command == NfcPollerCommandReset) { + ret = NfcCommandReset; + } else if(command == NfcPollerCommandStop) { + ret = NfcCommandStop; + } else { + furi_crash("Unknown command"); + } + + return ret; +} + static NfcCommand nfc_poller_event_callback(NfcEvent event, void* context) { furi_assert(context); @@ -58,10 +74,10 @@ static NfcCommand nfc_poller_event_callback(NfcEvent event, void* context) { furi_assert(instance->session_state != NfcPollerSessionStateIdle); NfcPollerEvent poller_event; - NfcCommand command = NfcCommandContinue; + NfcPollerCommand command = NfcPollerCommandContinue; if(instance->session_state == NfcPollerSessionStateStopRequest) { - command = NfcCommandStop; + command = NfcPollerCommandStop; } else { if(event.type == NfcEventTypeConfigureRequest) { if(instance->state == NfcPollerStateCheckPresenceNfca) { @@ -79,13 +95,13 @@ static NfcCommand nfc_poller_event_callback(NfcEvent event, void* context) { } else { poller_event = NfcPollerEventNfcaDetected; } - instance->callback(poller_event, instance->context); + command = instance->callback(poller_event, instance->context); } else { // Nfca not present FURI_LOG_E("TAG", "NOT PRESENT"); furi_delay_ms(100); instance->state = NfcPollerStateCheckPresenceNfcb; - command = NfcCommandReset; + command = NfcPollerCommandReset; } } else if(instance->state == NfcPollerStateCheckPresenceNfcb) { // NfcbError error = @@ -109,7 +125,7 @@ static NfcCommand nfc_poller_event_callback(NfcEvent event, void* context) { } } - return command; + return nfc_poller_process_command(command); } void nfc_poller_start(NfcPoller* instance, NfcPollerEventCallback callback, void* context) { diff --git a/lib/nfc/nfc_poller.h b/lib/nfc/nfc_poller.h index 903805961efb..95aa6e8e663b 100644 --- a/lib/nfc/nfc_poller.h +++ b/lib/nfc/nfc_poller.h @@ -25,7 +25,13 @@ typedef enum { NfcPollerEventMfClassicDetected, } NfcPollerEvent; -typedef void (*NfcPollerEventCallback)(NfcPollerEvent event, void* context); +typedef enum { + NfcPollerCommandContinue = NfcCommandContinue, + NfcPollerCommandReset = NfcCommandReset, + NfcPollerCommandStop = NfcCommandStop, +} NfcPollerCommand; + +typedef NfcPollerCommand (*NfcPollerEventCallback)(NfcPollerEvent event, void* context); NfcPoller* nfc_poller_alloc(NfcPollerCollection* pollers); From ff6f27a32fb6545b1582ddfa711cbea6805f151d Mon Sep 17 00:00:00 2001 From: gornekich Date: Thu, 4 May 2023 21:49:37 +0400 Subject: [PATCH 057/149] nfc: correct reset --- .../main/nfc/scenes/nfc_scene_nfca_emulate.c | 2 +- .../main/nfc_rpc/nfc_rpc_mf_ultralight.c | 2 +- applications/main/nfc_rpc/nfc_rpc_nfca.c | 2 +- firmware/targets/f7/furi_hal/f_hal_nfc.c | 3 + lib/nfc/nfc.c | 47 ++++++++----- lib/nfc/nfc.h | 4 +- lib/nfc/nfc_poller.c | 2 +- .../mf_ultralight/mf_ultralight_listener.c | 4 +- .../mf_ultralight/mf_ultralight_listener.h | 2 +- lib/nfc/protocols/nfca/nfca_listener.c | 67 ++++++++++++++----- lib/nfc/protocols/nfca/nfca_listener.h | 4 +- lib/nfc/protocols/nfca/nfca_poller.c | 2 +- lib/nfc/protocols/nfcb/nfcb_poller.c | 2 +- 13 files changed, 98 insertions(+), 45 deletions(-) diff --git a/applications/main/nfc/scenes/nfc_scene_nfca_emulate.c b/applications/main/nfc/scenes/nfc_scene_nfca_emulate.c index b01dfa881cb8..21e243c6855e 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfca_emulate.c +++ b/applications/main/nfc/scenes/nfc_scene_nfca_emulate.c @@ -125,7 +125,7 @@ bool nfc_scene_nfca_emulate_on_event(void* context, SceneManagerEvent event) { void nfc_scene_nfca_emulate_on_exit(void* context) { NfcApp* nfc = context; - nfca_listener_reset(nfc->nfca_listener); + nfca_listener_stop(nfc->nfca_listener); // Clear view widget_reset(nfc->widget); diff --git a/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c b/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c index 8e1d5763d509..574ae6b8a1f0 100644 --- a/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c +++ b/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c @@ -238,7 +238,7 @@ void nfc_rpc_mf_ultralight_emulate_stop(Nfc_Main* cmd, void* context) { cmd->which_content = Nfc_Main_mf_ultralight_emulate_stop_resp_tag; if(instance->mf_ul_listener) { // Stop before free - mf_ultralight_listener_reset(instance->mf_ul_listener); + mf_ultralight_listener_stop(instance->mf_ul_listener); instance->mf_ul_listener = NULL; pb_mf_ultralight_emulate_stop_resp.error = PB_MfUltralight_Error_None; } else { diff --git a/applications/main/nfc_rpc/nfc_rpc_nfca.c b/applications/main/nfc_rpc/nfc_rpc_nfca.c index ac03d2c0310c..4ce3fbf51639 100644 --- a/applications/main/nfc_rpc/nfc_rpc_nfca.c +++ b/applications/main/nfc_rpc/nfc_rpc_nfca.c @@ -103,7 +103,7 @@ static void nfc_rpc_nfca_emulate_stop(Nfc_Main* cmd, void* context) { cmd->command_status = Nfc_CommandStatus_OK; cmd->which_content = Nfc_Main_nfca_emulate_stop_resp_tag; if(instance->nfca_listener) { - nfca_listener_reset(instance->nfca_listener); + nfca_listener_stop(instance->nfca_listener); instance->nfca_listener = NULL; pb_nfca_emulate_stop_resp.error = PB_Nfca_Error_None; } else { diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc.c b/firmware/targets/f7/furi_hal/f_hal_nfc.c index 58d9e996f24f..3d05d46cfcf4 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfc.c +++ b/firmware/targets/f7/furi_hal/f_hal_nfc.c @@ -370,6 +370,9 @@ FHalNfcError f_hal_nfc_reset_mode() { furi_hal_spi_acquire(handle); st25r3916_direct_cmd(handle, ST25R3916_CMD_STOP); + // Set default value in mode register + st25r3916_write_reg(handle, ST25R3916_REG_MODE, ST25R3916_REG_MODE_om0); + st25r3916_clear_reg_bits(handle, ST25R3916_REG_AUX, ST25R3916_REG_AUX_no_crc_rx); furi_hal_spi_release(handle); diff --git a/lib/nfc/nfc.c b/lib/nfc/nfc.c index 7332c6d51bc3..7271331f96a7 100644 --- a/lib/nfc/nfc.c +++ b/lib/nfc/nfc.c @@ -5,6 +5,8 @@ #define TAG "Nfc" +#define NFC_MAX_BUFFER_SIZE (256) + typedef enum { NfcStateIdle, NfcStateChipSleep, @@ -27,13 +29,7 @@ typedef enum { NfcCommStateFailed, } NfcCommState; -typedef enum { - NfcGenericModePoller, - NfcGenericModeListener, -} NfcGenericMode; - struct Nfc { - NfcGenericMode mode; NfcState state; NfcCommState comm_state; uint32_t fdt_listen_fc; @@ -63,13 +59,18 @@ static int32_t nfc_worker_listener(void* context) { furi_assert(context); Nfc* instance = context; - uint8_t rx_data[256]; + furi_assert(instance->callback); + + uint8_t* rx_data = malloc(NFC_MAX_BUFFER_SIZE); uint16_t rx_bits = 0; + f_hal_nfc_low_power_mode_stop(); + + NfcEvent nfc_event = {.type = NfcEventTypeConfigureRequest}; + instance->callback(nfc_event, instance->context); + f_hal_nfc_listen_start(); instance->state = NfcStateListenStarted; - NfcEvent nfc_event = {}; - // NfcCommand cmd = NfcCommandContinue; f_hal_nfc_event_start(); @@ -106,6 +107,12 @@ static int32_t nfc_worker_listener(void* context) { } } + nfc_event.type = NfcEventTypeReset; + instance->callback(nfc_event, instance->context); + nfc_config(instance, NfcModeIdle); + f_hal_nfc_low_power_mode_start(); + free(rx_data); + return 0; } @@ -217,9 +224,7 @@ void nfc_config(Nfc* instance, NfcMode mode) { f_hal_nfc_reset_mode(); } else if(mode == NfcModeNfcaPoller) { f_hal_nfc_set_mode(FHalNfcModeNfcaPoller, FHalNfcBitrate106); - instance->mode = NfcGenericModePoller; } else if(mode == NfcModeNfcaListener) { - instance->mode = NfcGenericModeListener; f_hal_nfc_set_mode(FHalNfcModeNfcaListener, FHalNfcBitrate106); } } @@ -262,18 +267,26 @@ void nfc_set_mask_receive_time_fc(Nfc* instance, uint32_t mask_rx_time_fc) { instance->mask_rx_time_fc = mask_rx_time_fc; } -void nfc_start_worker(Nfc* instance, NfcEventCallback callback, void* context) { +void nfc_start_poller(Nfc* instance, NfcEventCallback callback, void* context) { furi_assert(instance); furi_assert(instance->worker_thread); furi_assert(callback); instance->callback = callback; instance->context = context; - if(instance->mode == NfcGenericModePoller) { - furi_thread_set_callback(instance->worker_thread, nfc_worker_poller); - } else { - furi_thread_set_callback(instance->worker_thread, nfc_worker_listener); - } + furi_thread_set_callback(instance->worker_thread, nfc_worker_poller); + furi_thread_start(instance->worker_thread); + instance->comm_state = NfcCommStateIdle; +} + +void nfc_start_listener(Nfc* instance, NfcEventCallback callback, void* context) { + furi_assert(instance); + furi_assert(instance->worker_thread); + furi_assert(callback); + + instance->callback = callback; + instance->context = context; + furi_thread_set_callback(instance->worker_thread, nfc_worker_listener); furi_thread_start(instance->worker_thread); instance->comm_state = NfcCommStateIdle; } diff --git a/lib/nfc/nfc.h b/lib/nfc/nfc.h index 46c8da1d13cc..94b982999f1b 100644 --- a/lib/nfc/nfc.h +++ b/lib/nfc/nfc.h @@ -92,7 +92,9 @@ NfcError nfc_listener_set_col_res_data( uint8_t* atqa, uint8_t sak); -void nfc_start_worker(Nfc* instance, NfcEventCallback callback, void* context); +void nfc_start_poller(Nfc* instance, NfcEventCallback callback, void* context); + +void nfc_start_listener(Nfc* instance, NfcEventCallback callback, void* context); NfcError nfc_listener_sleep(Nfc* instance); diff --git a/lib/nfc/nfc_poller.c b/lib/nfc/nfc_poller.c index 6fb54f994252..655554fb2ba0 100644 --- a/lib/nfc/nfc_poller.c +++ b/lib/nfc/nfc_poller.c @@ -138,7 +138,7 @@ void nfc_poller_start(NfcPoller* instance, NfcPollerEventCallback callback, void instance->state = NfcPollerStateCheckPresenceNfca; instance->session_state = NfcPollerSessionStateActive; - nfc_start_worker(instance->nfc, nfc_poller_event_callback, instance); + nfc_start_poller(instance->nfc, nfc_poller_event_callback, instance); } void nfc_poller_stop(NfcPoller* instance) { diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c index 7308edcc6cbc..290b1d5ebf82 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c @@ -216,11 +216,11 @@ void mf_ultralight_listener_free(MfUltralightListener* instance) { free(instance); } -MfUltralightError mf_ultralight_listener_reset(MfUltralightListener* instance) { +MfUltralightError mf_ultralight_listener_stop(MfUltralightListener* instance) { furi_assert(instance); furi_assert(instance->data); - NfcaError error = nfca_listener_reset(instance->nfca_listener); + NfcaError error = nfca_listener_stop(instance->nfca_listener); instance->state = MfUltraligthListenerStateIdle; free(instance->data); diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.h index d793032127d9..df673029fc2e 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.h @@ -42,7 +42,7 @@ MfUltralightError mf_ultralight_listener_start( MfUltralightListenerEventCallback callback, void* context); -MfUltralightError mf_ultralight_listener_reset(MfUltralightListener* instance); +MfUltralightError mf_ultralight_listener_stop(MfUltralightListener* instance); #ifdef __cplusplus } diff --git a/lib/nfc/protocols/nfca/nfca_listener.c b/lib/nfc/protocols/nfca/nfca_listener.c index 8540af503fa9..4f59d3e2a511 100644 --- a/lib/nfc/protocols/nfca/nfca_listener.c +++ b/lib/nfc/protocols/nfca/nfca_listener.c @@ -5,6 +5,8 @@ #define TAG "NfcaListener" +#define NFCA_LISTENER_MAX_BUFFER_SIZE (256) + typedef enum { NfcaListenerStateIdle, NfcaListenerStateActive, @@ -15,6 +17,9 @@ struct NfcaListener { NfcaData* data; NfcaListenerState state; NfcaListenerEventCallback callback; + + uint8_t* tx_data; + uint16_t tx_bits; void* context; }; @@ -32,6 +37,30 @@ static NfcaError nfca_listener_process_nfc_error(NfcError error) { return ret; } +static void nfca_listener_config(NfcaListener* instance) { + furi_assert(instance); + + instance->tx_data = malloc(NFCA_LISTENER_MAX_BUFFER_SIZE); + instance->tx_bits = 0; + + nfc_set_fdt_listen_fc(instance->nfc, NFCA_FDT_LISTEN_FC); + nfc_config(instance->nfc, NfcModeNfcaListener); + nfc_listener_set_col_res_data( + instance->nfc, + instance->data->uid, + instance->data->uid_len, + instance->data->atqa, + instance->data->sak); +} + +static void nfca_listener_reset(NfcaListener* instance) { + furi_assert(instance); + furi_assert(instance->tx_data); + + free(instance->tx_data); + instance->tx_bits = 0; +} + static bool nfca_listener_halt_received(uint8_t* rx_data, uint16_t rx_bits) { bool halt_cmd_received = false; @@ -54,7 +83,13 @@ static NfcCommand nfca_listener_event_handler(NfcEvent event, void* context) { NfcaListenerEvent nfca_listener_event = {}; NfcCommand command = NfcCommandContinue; - if(event_type == NfcEventTypeListenerActivated) { + if(event_type == NfcEventTypeConfigureRequest) { + nfca_listener_config(instance); + if(instance->callback) { + nfca_listener_event.type = NfcaListenerEventConfigRequest; + instance->callback(nfca_listener_event, instance->context); + } + } else if(event_type == NfcEventTypeListenerActivated) { instance->state = NfcaListenerStateActive; } else if((event_type == NfcEventTypeRxEnd) && (instance->state == NfcaListenerStateActive)) { if(nfca_listener_halt_received(event.data.rx_data, event.data.rx_bits)) { @@ -78,6 +113,12 @@ static NfcCommand nfca_listener_event_handler(NfcEvent event, void* context) { instance->callback(nfca_listener_event, instance->context); } } + } else if(event_type == NfcEventTypeReset) { + nfca_listener_reset(instance); + if(instance->callback) { + nfca_listener_event.type = NfcaListenerEventTypeReset; + instance->callback(nfca_listener_event, instance->context); + } } return command; @@ -110,26 +151,19 @@ NfcaError nfca_listener_start( instance->data = malloc(sizeof(NfcaData)); *instance->data = *data; - nfc_set_fdt_listen_fc(instance->nfc, NFCA_FDT_LISTEN_FC); - nfc_config(instance->nfc, NfcModeNfcaListener); - nfc_listener_set_col_res_data( - instance->nfc, - instance->data->uid, - instance->data->uid_len, - instance->data->atqa, - instance->data->sak); - nfc_start_worker(instance->nfc, nfca_listener_event_handler, instance); + nfc_start_listener(instance->nfc, nfca_listener_event_handler, instance); return NfcaErrorNone; } -NfcaError nfca_listener_reset(NfcaListener* instance) { +NfcaError nfca_listener_stop(NfcaListener* instance) { furi_assert(instance); furi_assert(instance->nfc); furi_assert(instance->data); nfc_listener_abort(instance->nfc); free(instance->data); + instance->callback = NULL; instance->context = NULL; instance->state = NfcaListenerStateIdle; @@ -173,21 +207,20 @@ NfcaError nfca_listener_send_standart_frame(NfcaListener* instance, uint8_t* tx_data, uint16_t tx_bits) { furi_assert(instance); furi_assert(tx_data); + furi_assert(instance->tx_data); NfcaError ret = NfcaErrorNone; - // TODO another buffer ... - uint8_t tx_buff[64]; uint16_t tx_bytes = tx_bits / 8; do { - if(tx_bytes > sizeof(tx_buff) - 2) { + if(tx_bytes > NFCA_LISTENER_MAX_BUFFER_SIZE - 2) { ret = NfcaErrorBufferOverflow; break; } - memcpy(tx_buff, tx_data, tx_bytes); - nfca_append_crc(tx_buff, tx_bytes); + memcpy(instance->tx_data, tx_data, tx_bytes); + nfca_append_crc(instance->tx_data, tx_bytes); - NfcError error = nfc_listener_tx(instance->nfc, tx_buff, tx_bits + 16); + NfcError error = nfc_listener_tx(instance->nfc, instance->tx_data, tx_bits + 16); if(error != NfcErrorNone) { FURI_LOG_W(TAG, "Tx error: %d", error); ret = nfca_listener_process_nfc_error(error); diff --git a/lib/nfc/protocols/nfca/nfca_listener.h b/lib/nfc/protocols/nfca/nfca_listener.h index f2bb8b608955..ddd0dfe63d1f 100644 --- a/lib/nfc/protocols/nfca/nfca_listener.h +++ b/lib/nfc/protocols/nfca/nfca_listener.h @@ -10,12 +10,14 @@ extern "C" { typedef struct NfcaListener NfcaListener; typedef enum { + NfcaListenerEventConfigRequest, NfcaListenerEventTypeAbort, NfcaListenerEventTypeFieldOn, NfcaListenerEventTypeFieldOff, NfcaListenerEventTypeHalted, NfcaListenerEventTypeReceivedStandartFrame, NfcaListenerEventTypeReceivedData, + NfcaListenerEventTypeReset, } NfcaListenerEventType; typedef struct { @@ -47,7 +49,7 @@ NfcaError nfca_listener_start( NfcaError nfca_listener_get_data(NfcaListener* instance, NfcaData* data); -NfcaError nfca_listener_reset(NfcaListener* instance); +NfcaError nfca_listener_stop(NfcaListener* instance); // Called from NfcWorker thread diff --git a/lib/nfc/protocols/nfca/nfca_poller.c b/lib/nfc/protocols/nfca/nfca_poller.c index a201a2ca06f1..4ef62ab86642 100644 --- a/lib/nfc/protocols/nfca/nfca_poller.c +++ b/lib/nfc/protocols/nfca/nfca_poller.c @@ -99,7 +99,7 @@ NfcaError instance->context = context; instance->session_state = NfcaPollerSessionStateActive; - nfc_start_worker(instance->nfc, nfca_poller_event_callback, instance); + nfc_start_poller(instance->nfc, nfca_poller_event_callback, instance); return NfcaErrorNone; } diff --git a/lib/nfc/protocols/nfcb/nfcb_poller.c b/lib/nfc/protocols/nfcb/nfcb_poller.c index 0365149b27f0..466656a0bdaf 100644 --- a/lib/nfc/protocols/nfcb/nfcb_poller.c +++ b/lib/nfc/protocols/nfcb/nfcb_poller.c @@ -53,7 +53,7 @@ NfcbError instance->callback = callback; instance->context = context; - nfc_start_worker(instance->nfc, nfcb_poller_event_callback, instance); + nfc_start_poller(instance->nfc, nfcb_poller_event_callback, instance); return NfcbErrorNone; } From e996dc61bf5023891f16469835e126f76d90cbea Mon Sep 17 00:00:00 2001 From: gornekich Date: Sat, 6 May 2023 02:59:59 +0400 Subject: [PATCH 058/149] nfc: introduce poller and listener unit tests --- applications/debug/unit_tests/nfc/nfc_test.c | 47 ++ .../debug/unit_tests/nfc/nfc_transport.c | 449 ++++++++++++++++++ lib/nfc/nfc.c | 4 + lib/nfc/protocols/nfca/nfca_poller.c | 4 +- lib/nfc/protocols/nfca/nfca_poller_i.c | 3 - 5 files changed, 502 insertions(+), 5 deletions(-) create mode 100644 applications/debug/unit_tests/nfc/nfc_transport.c diff --git a/applications/debug/unit_tests/nfc/nfc_test.c b/applications/debug/unit_tests/nfc/nfc_test.c index 70d53ad6c96d..55316d75f4c4 100644 --- a/applications/debug/unit_tests/nfc/nfc_test.c +++ b/applications/debug/unit_tests/nfc/nfc_test.c @@ -6,6 +6,10 @@ #include #include +#include +#include +#include + #include "../minunit.h" #define TAG "NfcTest" @@ -142,9 +146,52 @@ MU_TEST(mf_ultralight_ntag_i2c_plus_2k_file_test) { mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeNTAGI2CPlus2k); } +MU_TEST(nfca_read) { + Nfc* poller = nfc_alloc(); + mu_assert(poller != NULL, "nfc_alloc() poller failed"); + Nfc* listener = nfc_alloc(); + mu_assert(listener != NULL, "nfc_alloc() listener failed"); + + NfcaPoller* nfca_poller = nfca_poller_alloc(poller); + mu_assert(nfca_poller != NULL, "nfca_poller_alloc() poller failed"); + NfcaListener* nfca_listener = nfca_listener_alloc(listener); + mu_assert(nfca_listener != NULL, "nfca_listener_alloc() listener failed"); + + NfcaData nfca_listener_data = { + .uid_len = 7, + .uid = {0x04, 0x51, 0x5C, 0xFA, 0x6F, 0x73, 0x81}, + .atqa = {0x44, 0x00}, + .sak = 0x00, + }; + // nfca_listener_data.uid_len = 7; + // furi_hal_random_fill_buf(nfca_listener_data.uid, 7); + // furi_hal_random_fill_buf(nfca_listener_data.atqa, 2); + // furi_hal_random_fill_buf(&nfca_listener_data.sak, 1); + NfcaData nfca_poller_data = {}; + + mu_assert( + nfca_listener_start(nfca_listener, &nfca_listener_data, NULL, NULL) == NfcaErrorNone, + "nfca_listener_start() failed"); + + mu_assert( + nfca_poller_activate(nfca_poller, &nfca_poller_data) == NfcaErrorNone, + "nfca_poller_activate() failed"); + mu_assert(nfca_listener_stop(nfca_listener) == NfcaErrorNone, "nfca_listener_stop() failed"); + + mu_assert( + memcmp(&nfca_poller_data, &nfca_listener_data, sizeof(NfcaData)) == 0, "Data not matches"); + + nfca_listener_free(nfca_listener); + nfc_free(listener); + nfca_poller_free(nfca_poller); + nfc_free(poller); +} + MU_TEST_SUITE(nfc) { nfc_test_alloc(); + MU_RUN_TEST(nfca_read); + MU_RUN_TEST(nfca_4b_file_test); MU_RUN_TEST(nfca_7b_file_test); diff --git a/applications/debug/unit_tests/nfc/nfc_transport.c b/applications/debug/unit_tests/nfc/nfc_transport.c new file mode 100644 index 000000000000..e56411b6ffd3 --- /dev/null +++ b/applications/debug/unit_tests/nfc/nfc_transport.c @@ -0,0 +1,449 @@ +#ifdef APP_UNIT_TESTS + +#include +#include + +#include + +#define NFC_MAX_DATA_SIZE (128) + +FuriMessageQueue* poller_queue = NULL; +FuriMessageQueue* listener_queue = NULL; + +typedef enum { + NfcMessageTypeTx, + NfcMessageTypeTimeout, + NfcMessageTypeAbort, +} NfcMessageType; + +typedef struct { + uint16_t data_bits; + uint8_t data[NFC_MAX_DATA_SIZE]; +} NfcMessageData; + +typedef struct { + NfcMessageType type; + NfcMessageData data; +} NfcMessage; + +typedef enum { + NfcStateIdle, + NfcStateStarted, + NfcStateReady, + NfcStateReset, +} NfcState; + +typedef enum { + NfcaColResStatusIdle, + NfcaColResStatusInProgress, + NfcaColResStatusDone, +} NfcaColResStatus; + +typedef struct { + NfcaSensResp sens_resp; + NfcaSddResp sdd_resp[2]; + NfcaSelResp sel_resp[2]; +} NfcaColResData; + +struct Nfc { + NfcState state; + + NfcaColResStatus col_res_status; + NfcaColResData col_res_data; + + NfcEventCallback callback; + void* context; + + FuriThread* worker_thread; +}; + +static void nfc_test_print(const char* message, uint8_t* buffer, uint16_t bits) { + FuriString* str = furi_string_alloc(); + size_t bytes = (bits + 7) / 8; + + for(size_t i = 0; i < bytes; i++) { + furi_string_cat_printf(str, " %02X", buffer[i]); + } + FURI_LOG_I(message, "%s", furi_string_get_cstr(str)); + + furi_string_free(str); +} + +static void nfc_prepare_col_res_data( + Nfc* instance, + uint8_t* uid, + uint8_t uid_len, + uint8_t* atqa, + uint8_t sak) { + memcpy(instance->col_res_data.sens_resp.sens_resp, atqa, 2); + + if(uid_len == 7) { + instance->col_res_data.sdd_resp[0].nfcid[0] = 0x88; + memcpy(&instance->col_res_data.sdd_resp[0].nfcid[1], uid, 3); + uint8_t bss = 0; + for(size_t i = 0; i < 4; i++) { + bss ^= instance->col_res_data.sdd_resp[0].nfcid[i]; + } + instance->col_res_data.sdd_resp[0].bss = bss; + instance->col_res_data.sel_resp[0].sak = 0x04; + + memcpy(instance->col_res_data.sdd_resp[1].nfcid, &uid[3], 4); + bss = 0; + for(size_t i = 0; i < 4; i++) { + bss ^= instance->col_res_data.sdd_resp[1].nfcid[i]; + } + instance->col_res_data.sdd_resp[1].bss = bss; + instance->col_res_data.sel_resp[1].sak = sak; + + } else { + furi_crash("Not supporting not 7 bytes"); + } +} + +Nfc* nfc_alloc() { + Nfc* instance = malloc(sizeof(Nfc)); + + return instance; +} + +void nfc_free(Nfc* instance) { + furi_assert(instance); + + free(instance); +} + +void nfc_config(Nfc* instance, NfcMode mode) { + UNUSED(instance); + UNUSED(mode); +} + +void nfc_set_fdt_poll_fc(Nfc* instance, uint32_t fdt_poll_fc) { + UNUSED(instance); + UNUSED(fdt_poll_fc); +} + +void nfc_set_fdt_listen_fc(Nfc* instance, uint32_t fdt_listen_fc) { + UNUSED(instance); + UNUSED(fdt_listen_fc); +} + +void nfc_set_mask_receive_time_fc(Nfc* instance, uint32_t mask_rx_time_fc) { + UNUSED(instance); + UNUSED(mask_rx_time_fc); +} + +void nfc_set_fdt_poll_poll_us(Nfc* instance, uint32_t fdt_poll_poll_us) { + UNUSED(instance); + UNUSED(fdt_poll_poll_us); +} + +void nfc_set_guard_time_us(Nfc* instance, uint32_t guard_time_us) { + UNUSED(instance); + UNUSED(guard_time_us); +} + +NfcError nfc_listener_set_col_res_data( + Nfc* instance, + uint8_t* uid, + uint8_t uid_len, + uint8_t* atqa, + uint8_t sak) { + furi_assert(instance); + furi_assert(uid); + furi_assert(atqa); + + nfc_prepare_col_res_data(instance, uid, uid_len, atqa, sak); + + return NfcErrorNone; +} + +static int32_t nfc_worker_poller(void* context) { + Nfc* instance = context; + furi_assert(instance->callback); + + instance->state = NfcStateStarted; + NfcCommand command = NfcCommandContinue; + NfcEvent event = {}; + + while(true) { + if(instance->state == NfcStateStarted) { + event.type = NfcEventTypeConfigureRequest; + instance->callback(event, instance->context); + instance->state = NfcStateReady; + } else if(instance->state == NfcStateReady) { + event.type = NfcEventTypePollerReady; + command = instance->callback(event, instance->context); + if(command == NfcCommandReset) { + event.type = NfcEventTypeReset; + instance->callback(event, instance->context); + instance->state = NfcStateStarted; + } else if(command == NfcCommandStop) { + event.type = NfcEventTypeReset; + instance->callback(event, instance->context); + break; + } + } + } + + instance->state = NfcStateIdle; + + return 0; +} + +void nfc_start_poller(Nfc* instance, NfcEventCallback callback, void* context) { + furi_assert(instance); + furi_assert(instance->worker_thread == NULL); + + furi_assert(poller_queue == NULL); + // Check that poller is started after listener + furi_assert(listener_queue); + + instance->callback = callback; + instance->context = context; + + poller_queue = furi_message_queue_alloc(4, sizeof(NfcMessage)); + + instance->worker_thread = furi_thread_alloc(); + furi_thread_set_name(instance->worker_thread, "NfcWorkerPoller"); + furi_thread_set_context(instance->worker_thread, instance); + furi_thread_set_priority(instance->worker_thread, FuriThreadPriorityHigh); + furi_thread_set_stack_size(instance->worker_thread, 8 * 1024); + furi_thread_set_callback(instance->worker_thread, nfc_worker_poller); + furi_thread_start(instance->worker_thread); +} + +static void nfc_worker_listener_pass_col_res(Nfc* instance, uint8_t* rx_data, uint16_t rx_bits) { + furi_assert(instance->col_res_status != NfcaColResStatusDone); + + bool processed = false; + + if((rx_bits == 7) && (rx_data[0] == 0x52)) { + instance->col_res_status = NfcaColResStatusInProgress; + nfc_listener_tx(instance, instance->col_res_data.sens_resp.sens_resp, 16); + processed = true; + } else if(rx_bits == 2 * 8) { + if((rx_data[0] == 0x93) && (rx_data[1] == 0x20)) { + nfc_listener_tx( + instance, (uint8_t*)&instance->col_res_data.sdd_resp[0], sizeof(NfcaSddResp) * 8); + processed = true; + } else if((rx_data[0] == 0x95) && (rx_data[1] == 0x20)) { + nfc_listener_tx( + instance, (uint8_t*)&instance->col_res_data.sdd_resp[1], sizeof(NfcaSddResp) * 8); + processed = true; + } + } else if(rx_bits == 9 * 8) { + if((rx_data[0] == 0x93) && (rx_data[1] == 0x70)) { + uint8_t sak_with_crc[3] = {instance->col_res_data.sel_resp[0].sak}; + nfca_append_crc(sak_with_crc, 1); + nfc_listener_tx(instance, sak_with_crc, 3 * 8); + processed = true; + } else if((rx_data[0] == 0x95) && (rx_data[1] == 0x70)) { + uint8_t sak_with_crc[3] = {instance->col_res_data.sel_resp[1].sak}; + nfca_append_crc(sak_with_crc, 1); + nfc_listener_tx(instance, sak_with_crc, 3 * 8); + + instance->col_res_status = NfcaColResStatusDone; + NfcEvent event = {.type = NfcEventTypeListenerActivated}; + instance->callback(event, instance->context); + + processed = true; + } + } + + if(!processed) { + NfcMessage message = {.type = NfcMessageTypeTimeout}; + furi_message_queue_put(poller_queue, &message, FuriWaitForever); + } +} + +static int32_t nfc_worker_listener(void* context) { + Nfc* instance = context; + furi_assert(instance->callback); + + instance->state = NfcStateStarted; + NfcEvent event = {}; + NfcMessage message = {}; + + uint8_t* rx_data = malloc(NFC_MAX_DATA_SIZE); + + event.type = NfcEventTypeConfigureRequest; + instance->callback(event, instance->context); + + while(true) { + furi_message_queue_get(listener_queue, &message, FuriWaitForever); + if(message.type == NfcMessageTypeAbort) { + event.type = NfcEventTypeUserAbort; + instance->callback(event, instance->context); + break; + } else if(message.type == NfcMessageTypeTx) { + nfc_test_print("RDR", message.data.data, message.data.data_bits); + if(instance->col_res_status != NfcaColResStatusDone) { + nfc_worker_listener_pass_col_res( + instance, message.data.data, message.data.data_bits); + } else { + instance->state = NfcStateReady; + event.type = NfcEventTypeRxEnd; + memcpy(rx_data, message.data.data, (message.data.data_bits + 7) / 8); + event.data.rx_data = rx_data; + event.data.rx_bits = message.data.data_bits; + instance->callback(event, instance->context); + } + } + } + + event.type = NfcEventTypeReset; + instance->callback(event, instance->context); + + instance->state = NfcStateIdle; + instance->col_res_status = NfcaColResStatusIdle; + memset(&instance->col_res_data, 0, sizeof(instance->col_res_data)); + + free(rx_data); + + return 0; +} + +void nfc_start_listener(Nfc* instance, NfcEventCallback callback, void* context) { + furi_assert(instance); + furi_assert(instance->worker_thread == NULL); + + furi_assert(listener_queue == NULL); + // Check that poller didn't start + furi_assert(poller_queue == NULL); + + instance->callback = callback; + instance->context = context; + + listener_queue = furi_message_queue_alloc(4, sizeof(NfcMessage)); + + instance->worker_thread = furi_thread_alloc(); + furi_thread_set_name(instance->worker_thread, "NfcWorkerListener"); + furi_thread_set_context(instance->worker_thread, instance); + furi_thread_set_priority(instance->worker_thread, FuriThreadPriorityHigh); + furi_thread_set_stack_size(instance->worker_thread, 8 * 1024); + furi_thread_set_callback(instance->worker_thread, nfc_worker_listener); + furi_thread_start(instance->worker_thread); +} + +NfcError nfc_listener_sleep(Nfc* instance) { + furi_assert(instance); + furi_assert(poller_queue); + + instance->col_res_status = NfcaColResStatusIdle; + NfcMessage message = {.type = NfcMessageTypeTimeout}; + furi_message_queue_put(poller_queue, &message, FuriWaitForever); + + return NfcErrorNone; +} + +void nfc_listener_abort(Nfc* instance) { + furi_assert(instance); + + NfcMessage message = {.type = NfcMessageTypeAbort}; + furi_message_queue_put(listener_queue, &message, FuriWaitForever); + + furi_thread_join(instance->worker_thread); + furi_message_queue_free(listener_queue); + listener_queue = NULL; + instance->worker_thread = NULL; +} + +void nfc_stop(Nfc* instance) { + furi_assert(instance); + furi_assert(instance->worker_thread); + + furi_thread_join(instance->worker_thread); + + furi_message_queue_free(poller_queue); + poller_queue = NULL; + instance->worker_thread = NULL; +} + +// Called from worker thread + +NfcError nfc_listener_tx(Nfc* instance, uint8_t* tx_data, uint16_t tx_bits) { + furi_assert(instance); + furi_assert(poller_queue); + furi_assert(listener_queue); + furi_assert(tx_data); + furi_assert(tx_bits / 8 < NFC_MAX_DATA_SIZE); + + NfcMessage message = {}; + message.type = NfcMessageTypeTx; + message.data.data_bits = tx_bits; + memcpy(message.data.data, tx_data, (tx_bits + 7) / 8); + + furi_message_queue_put(poller_queue, &message, FuriWaitForever); + + return NfcErrorNone; +} + +NfcError nfc_trx( + Nfc* instance, + uint8_t* tx_data, + uint16_t tx_bits, + uint8_t* rx_data, + uint16_t rx_data_size, + uint16_t* rx_bits, + uint32_t fwt) { + furi_assert(instance); + furi_assert(tx_data); + furi_assert(rx_data); + furi_assert(rx_bits); + furi_assert(poller_queue); + furi_assert(listener_queue); + furi_assert(tx_bits / 8 < NFC_MAX_DATA_SIZE); + UNUSED(fwt); + + NfcError error = NfcErrorNone; + + NfcMessage message = {}; + message.type = NfcMessageTypeTx; + message.data.data_bits = tx_bits; + memcpy(message.data.data, tx_data, (tx_bits + 7) / 8); + // Tx + furi_assert(furi_message_queue_put(listener_queue, &message, FuriWaitForever) == FuriStatusOk); + // Rx + furi_assert(furi_message_queue_get(poller_queue, &message, FuriWaitForever) == FuriStatusOk); + + if(message.type == NfcMessageTypeTx) { + furi_assert(message.data.data_bits / 8 <= rx_data_size); + *rx_bits = message.data.data_bits; + memcpy(rx_data, message.data.data, (message.data.data_bits + 7) / 8); + nfc_test_print("TAG", rx_data, *rx_bits); + } else if(message.type == NfcMessageTypeTimeout) { + error = NfcErrorTimeout; + } + + return error; +} + +// Technology specific API + +NfcError nfc_iso13444a_short_frame( + Nfc* instance, + NfcIso14443aShortFrame frame, + uint8_t* rx_data, + uint16_t rx_data_size, + uint16_t* rx_bits, + uint32_t fwt) { + UNUSED(frame); + + uint8_t tx_data[1] = {0x52}; + uint16_t tx_bits = 7; + + return nfc_trx(instance, tx_data, tx_bits, rx_data, rx_data_size, rx_bits, fwt); +} + +NfcError nfc_iso13444a_sdd_frame( + Nfc* instance, + uint8_t* tx_data, + uint16_t tx_bits, + uint8_t* rx_data, + uint16_t rx_data_size, + uint16_t* rx_bits, + uint32_t fwt) { + return nfc_trx(instance, tx_data, tx_bits, rx_data, rx_data_size, rx_bits, fwt); +} + +#endif \ No newline at end of file diff --git a/lib/nfc/nfc.c b/lib/nfc/nfc.c index 7271331f96a7..73ae2b439669 100644 --- a/lib/nfc/nfc.c +++ b/lib/nfc/nfc.c @@ -1,3 +1,5 @@ +#ifndef APP_UNIT_TESTS + #include "nfc.h" #include @@ -546,3 +548,5 @@ NfcError nfc_iso13444a_sdd_frame( return ret; } + +#endif // APP_UNIT_TESTS diff --git a/lib/nfc/protocols/nfca/nfca_poller.c b/lib/nfc/protocols/nfca/nfca_poller.c index 4ef62ab86642..963e34996388 100644 --- a/lib/nfc/protocols/nfca/nfca_poller.c +++ b/lib/nfc/protocols/nfca/nfca_poller.c @@ -16,6 +16,7 @@ NfcaPoller* nfca_poller_alloc(Nfc* nfc) { furi_assert(nfc); NfcaPoller* instance = malloc(sizeof(NfcaPoller)); + instance->data = malloc(sizeof(NfcaData)); instance->nfc = nfc; return instance; @@ -25,6 +26,7 @@ void nfca_poller_free(NfcaPoller* instance) { furi_assert(instance); furi_assert(instance->nfc); + free(instance->data); free(instance); } @@ -123,7 +125,6 @@ NfcaError nfca_poller_stop(NfcaPoller* instance) { instance->session_state = NfcaPollerSessionStateIdle; // Check that data is freed - furi_assert(instance->data != NULL); furi_assert(instance->buff != NULL); return NfcaErrorNone; @@ -131,7 +132,6 @@ NfcaError nfca_poller_stop(NfcaPoller* instance) { static NfcaPollerCommand nfca_poller_sync_callback(NfcaPollerEvent event, void* context) { NfcaPollerContext* nfca_poller_context = context; - nfca_poller_stop(nfca_poller_context->instance); nfca_poller_context->error = event.data.error; furi_thread_flags_set(nfca_poller_context->thread_id, NFCA_POLLER_FLAG_COMMAND_COMPLETE); diff --git a/lib/nfc/protocols/nfca/nfca_poller_i.c b/lib/nfc/protocols/nfca/nfca_poller_i.c index e49380544fc6..5e20a63220df 100644 --- a/lib/nfc/protocols/nfca/nfca_poller_i.c +++ b/lib/nfc/protocols/nfca/nfca_poller_i.c @@ -94,7 +94,6 @@ static NfcaError nfca_poller_standart_frame_exchange( NfcaError nfca_poller_config(NfcaPoller* instance) { furi_assert(instance); - instance->data = malloc(sizeof(NfcaData)); instance->buff = nfc_poller_buffer_alloc(NFCA_POLLER_MAX_BUFFER_SIZE, NFCA_POLLER_MAX_BUFFER_SIZE); @@ -113,8 +112,6 @@ NfcaError nfca_poller_reset(NfcaPoller* instance) { instance->context = NULL; memset(&instance->col_res, 0, sizeof(NfcaPollerColRes)); instance->state = NfcaPollerStateIdle; - free(instance->data); - instance->data = NULL; free(instance->buff); instance->buff = NULL; From 0413e4348190805eb801878008cdeb775bd9735d Mon Sep 17 00:00:00 2001 From: gornekich Date: Sat, 6 May 2023 19:29:26 +0400 Subject: [PATCH 059/149] mf ultralight: rework read paged --- .../mf_ultralight/mf_ultralight_poller.c | 19 ++++++++++++++----- .../mf_ultralight/mf_ultralight_poller_i.c | 12 +++++++----- .../mf_ultralight/mf_ultralight_poller_i.h | 16 ++++++++++++++-- .../mf_ultralight_poller_sync_api.c | 8 +++++--- 4 files changed, 40 insertions(+), 15 deletions(-) diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c index cf26b97b9773..135c890bc734 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c @@ -68,7 +68,8 @@ static MfUltralightPollerCommand static MfUltralightPollerCommand mf_ultralight_poller_handler_check_ntag_203(MfUltralightPoller* instance) { - MfUltralightError error = mf_ultralight_poller_async_read_page(instance, 41); + MfUltralightPagedCommandData data = {}; + MfUltralightError error = mf_ultralight_poller_async_read_page(instance, 41, &data); if(error == MfUltralightErrorNone) { FURI_LOG_I(TAG, "NTAG203 detected"); instance->data->type = MfUltralightTypeNTAG203; @@ -210,11 +211,19 @@ static MfUltralightPollerCommand mf_ultralight_poller_handler_auth(MfUltralightP static MfUltralightPollerCommand mf_ultralight_poller_handler_read_pages(MfUltralightPoller* instance) { - MfUltralightError error = mf_ultralight_poller_async_read_page(instance, instance->pages_read); + MfUltralightPagedCommandData data = {}; + uint8_t start_page = instance->pages_read; + MfUltralightError error = + mf_ultralight_poller_async_read_page(instance, start_page, &data); if(error == MfUltralightErrorNone) { - FURI_LOG_I(TAG, "Read page %d success", instance->pages_read); - instance->pages_read++; - instance->data->pages_read = instance->pages_read; + for(size_t i = 0; i < 4; i++) { + if(start_page + i < instance->pages_total) { + FURI_LOG_I(TAG, "Read page %d success", start_page + i); + instance->data->page[start_page + i] = data.page[i]; + instance->pages_read++; + instance->data->pages_read = instance->pages_read; + } + } if(instance->pages_read == instance->pages_total) { instance->state = MfUltralightPollerStateReadCounters; } diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c index 65088b12cb58..2ea7595d6e7c 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c @@ -72,11 +72,13 @@ MfUltralightError return ret; } -MfUltralightError - mf_ultralight_poller_async_read_page(MfUltralightPoller* instance, uint8_t page) { +MfUltralightError mf_ultralight_poller_async_read_page( + MfUltralightPoller* instance, + uint8_t start_page, + MfUltralightPagedCommandData* data) { NfcPollerBuffer* buff = instance->buffer; buff->tx_data[0] = MF_ULTRALIGHT_CMD_READ_PAGE; - buff->tx_data[1] = page; + buff->tx_data[1] = start_page; buff->tx_bits = 16; MfUltralightError ret = MfUltralightErrorNone; @@ -94,11 +96,11 @@ MfUltralightError ret = mf_ultralight_process_error(error); break; } - if(buff->rx_bits != (MF_ULTRALIGHT_PAGE_SIZE * 4) * 8) { + if(buff->rx_bits != sizeof(MfUltralightPagedCommandData) * 8) { ret = MfUltralightErrorProtocol; break; } - memcpy(&instance->data->page[page], buff->rx_data, MF_ULTRALIGHT_PAGE_SIZE); + memcpy(data, buff->rx_data, sizeof(MfUltralightPagedCommandData)); } while(false); return ret; diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h index 413776d9f561..1fc3794268ab 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h @@ -12,11 +12,20 @@ typedef struct { uint8_t page_to_write; } MfUltralightPollerWritePageCommand; +typedef struct { + MfUltralightPage page[4]; +} MfUltralightPagedCommandData; + +typedef struct { + MfUltralightPagedCommandData data; + uint8_t start_page; +} MfUltralightPollerReadPageCommand; + typedef union { - uint8_t page_to_read; uint8_t counter_to_read; uint8_t tearing_flag_to_read; MfUltralightPollerWritePageCommand write_cmd; + MfUltralightPollerReadPageCommand read_cmd; } MfUltralightPollerContextData; typedef enum { @@ -65,7 +74,10 @@ MfUltralightError mf_ultralight_process_error(NfcaError error); MfUltralightError mf_ultralight_poller_async_auth(MfUltralightPoller* instance, MfUltralightAuthPassword* data); -MfUltralightError mf_ultralight_poller_async_read_page(MfUltralightPoller* instance, uint8_t page); +MfUltralightError mf_ultralight_poller_async_read_page( + MfUltralightPoller* instance, + uint8_t start_page, + MfUltralightPagedCommandData* data); MfUltralightError mf_ultralight_poller_async_write_page( MfUltralightPoller* instance, diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c index e9138b413c3b..8c17ca4119ac 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c @@ -17,7 +17,7 @@ static NfcaPollerCommand mf_ultraight_read_page_callback(NfcaPollerEvent event, MfUltralightPollerContext* poller_context = context; if(event.type == NfcaPollerEventTypeReady) { poller_context->error = mf_ultralight_poller_async_read_page( - poller_context->instance, poller_context->data.page_to_read); + poller_context->instance, poller_context->data.read_cmd.start_page, &poller_context->data.read_cmd.data); nfca_poller_halt(poller_context->instance->nfca_poller); } else if(event.type == NfcaPollerEventTypeError) { poller_context->error = mf_ultralight_process_error(event.data.error); @@ -35,13 +35,15 @@ MfUltralightError mf_ultralight_poller_read_page( furi_assert(data); MfUltralightPollerContext poller_context = {}; - poller_context.data.page_to_read = page; + poller_context.data.read_cmd.start_page = page; poller_context.instance = instance; poller_context.thread_id = furi_thread_get_current_id(); mf_ultralight_poller_start(instance, mf_ultraight_read_page_callback, &poller_context); furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); - *data = instance->data->page[page]; + if(poller_context.error == MfUltralightErrorNone) { + *data = poller_context.data.read_cmd.data.page[0]; + } mf_ultralight_poller_reset(instance); return poller_context.error; From 8a9d5019a492ed060db3c39af60300449a37fb29 Mon Sep 17 00:00:00 2001 From: gornekich Date: Sat, 6 May 2023 19:43:51 +0400 Subject: [PATCH 060/149] unit test: add ntag 215 for unit tests --- assets/unit_tests/nfc/Ntag215.nfc | 156 ++++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 assets/unit_tests/nfc/Ntag215.nfc diff --git a/assets/unit_tests/nfc/Ntag215.nfc b/assets/unit_tests/nfc/Ntag215.nfc new file mode 100644 index 000000000000..c134b512b0f1 --- /dev/null +++ b/assets/unit_tests/nfc/Ntag215.nfc @@ -0,0 +1,156 @@ +Filetype: Flipper NFC device +Version: 3 +# Nfc device type can be UID, Mifare Ultralight, Mifare Classic +Device type: NTAG215 +# UID, ATQA and SAK are common for all formats +UID: 04 51 5C FA 6F 73 81 +ATQA: 00 44 +SAK: 00 +# Mifare Ultralight specific data +Data format version: 1 +Signature: 42 21 E4 6C 79 6A 81 5E EA 0D 93 6D 85 EE 4B 0C 2A 00 D5 77 F1 C5 67 F3 63 75 F8 EB 86 48 5E 6B +Mifare version: 00 04 04 02 01 00 11 03 +Counter 0: 0 +Tearing 0: 00 +Counter 1: 0 +Tearing 1: 00 +Counter 2: 95 +Tearing 2: 00 +Pages total: 135 +Pages read: 135 +Page 0: 04 51 5C 81 +Page 1: FA 6F 73 81 +Page 2: 67 48 0F E0 +Page 3: F1 10 FF EE +Page 4: A5 00 00 00 +Page 5: 90 42 74 71 +Page 6: FD 8F 50 61 +Page 7: C5 65 1B 54 +Page 8: EF 68 D0 8E +Page 9: 3D 35 DB 83 +Page 10: D3 00 29 F6 +Page 11: 42 2A A5 5C +Page 12: F1 69 0A FC +Page 13: B6 44 E9 6B +Page 14: 77 41 88 81 +Page 15: 86 31 CB AD +Page 16: B1 DE F1 AB +Page 17: DF 96 C2 C5 +Page 18: C1 26 99 96 +Page 19: 85 AF 9F 0E +Page 20: 58 FE ED DC +Page 21: 0A 0A 00 01 +Page 22: 03 C1 05 02 +Page 23: 38 39 34 33 +Page 24: 49 2D 4E 5C +Page 25: 5B 21 0F 44 +Page 26: 3F 3F 76 69 +Page 27: B4 72 D8 38 +Page 28: A0 35 53 51 +Page 29: 53 EB A6 7C +Page 30: 3E 8B 97 C0 +Page 31: 00 7A 45 13 +Page 32: 3A 8B D4 0F +Page 33: 31 C2 32 CC +Page 34: B4 24 A6 1B +Page 35: D3 F5 4A 1F +Page 36: CD 8F 1D 64 +Page 37: 01 F4 DF C2 +Page 38: 11 16 C2 C5 +Page 39: 30 6D 49 AF +Page 40: 10 D4 7C 3C +Page 41: 6E 36 4E 08 +Page 42: 95 76 BC 84 +Page 43: 35 50 DD F0 +Page 44: 21 0F EE D9 +Page 45: 85 19 54 5F +Page 46: 3E A9 04 20 +Page 47: 1B 97 E4 39 +Page 48: FF 0A 45 F6 +Page 49: 13 D4 3E DD +Page 50: 97 42 FC 67 +Page 51: 6A AC 78 96 +Page 52: D1 DA 25 23 +Page 53: BF 4D B3 76 +Page 54: F1 21 ED 15 +Page 55: BD 55 11 C4 +Page 56: 4E 8C E9 23 +Page 57: C0 C4 6D 5A +Page 58: 58 25 FF 95 +Page 59: 3C 2B 7A 57 +Page 60: 66 BE A0 61 +Page 61: BC FC 4A 31 +Page 62: 4D AC EE 81 +Page 63: BE 1A 86 04 +Page 64: F6 D7 5E B3 +Page 65: E7 A8 A2 86 +Page 66: E9 40 AB 47 +Page 67: C8 36 E4 3E +Page 68: A7 4D D3 EA +Page 69: 83 9A 64 F7 +Page 70: 96 6B 5D BF +Page 71: 4E A2 A6 0F +Page 72: BD 3D BE 7C +Page 73: 22 0C 68 51 +Page 74: 0F 9A B8 AE +Page 75: 38 2C C4 CD +Page 76: 53 D8 DD 18 +Page 77: A6 5D 35 87 +Page 78: C9 6D 99 59 +Page 79: 61 9F B6 DC +Page 80: E6 22 0F 99 +Page 81: 39 82 79 60 +Page 82: 58 2E BE F7 +Page 83: EF F7 95 62 +Page 84: D5 06 1B 58 +Page 85: 65 05 A9 08 +Page 86: 75 ED 5D 90 +Page 87: 5A E1 7E C9 +Page 88: 35 D6 29 BB +Page 89: D0 67 6C F9 +Page 90: A0 FF 0B 93 +Page 91: 22 EA A3 3F +Page 92: E2 BD BD 58 +Page 93: BE 93 D9 94 +Page 94: 41 CC 7E 40 +Page 95: E6 8C 5A 43 +Page 96: 65 C1 24 94 +Page 97: B9 97 61 13 +Page 98: AD 74 FF 21 +Page 99: 0F EC F6 03 +Page 100: 89 5D 89 E5 +Page 101: 8D 11 F8 D7 +Page 102: 33 43 79 2E +Page 103: 23 E5 29 B5 +Page 104: 53 98 13 FF +Page 105: E8 79 8B 33 +Page 106: 45 6C 34 38 +Page 107: 3B 69 28 D7 +Page 108: D2 80 B0 2F +Page 109: D0 18 D5 DD +Page 110: 6C 2D D9 97 +Page 111: CA 78 B4 A2 +Page 112: B7 3E B8 79 +Page 113: A2 BE 54 E4 +Page 114: C8 28 0C 4A +Page 115: 81 E7 EC 1C +Page 116: 39 93 6F 70 +Page 117: 75 77 5C FC +Page 118: 66 58 0C 1C +Page 119: 9F 70 2E C8 +Page 120: 52 4A 52 BD +Page 121: 56 D5 6A 15 +Page 122: 54 1B 33 90 +Page 123: 44 11 C1 07 +Page 124: 11 5C BA 80 +Page 125: 10 14 20 9A +Page 126: 4A D8 E6 36 +Page 127: DA B8 59 E5 +Page 128: 5E 48 95 DA +Page 129: 96 6A 26 85 +Page 130: 01 00 0F BD +Page 131: 00 00 00 04 +Page 132: 5F 00 00 00 +Page 133: 00 00 00 00 +Page 134: 00 00 00 00 +Failed authentication attempts: 0 From 27903f0027fa8aef198717bbfecf945bad1b4ca1 Mon Sep 17 00:00:00 2001 From: gornekich Date: Sun, 7 May 2023 00:44:39 +0400 Subject: [PATCH 061/149] nfc: ultralight tests --- applications/debug/unit_tests/nfc/nfc_test.c | 88 ++++++++++++++----- .../debug/unit_tests/nfc/nfc_transport.c | 5 ++ .../protocols/mf_ultralight/mf_ultralight.h | 4 + .../mf_ultralight/mf_ultralight_listener.c | 27 +++--- .../mf_ultralight/mf_ultralight_poller_i.h | 4 - .../mf_ultralight_poller_sync_api.c | 3 +- 6 files changed, 92 insertions(+), 39 deletions(-) diff --git a/applications/debug/unit_tests/nfc/nfc_test.c b/applications/debug/unit_tests/nfc/nfc_test.c index 55316d75f4c4..4afa899fa9b9 100644 --- a/applications/debug/unit_tests/nfc/nfc_test.c +++ b/applications/debug/unit_tests/nfc/nfc_test.c @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include "../minunit.h" @@ -146,7 +148,48 @@ MU_TEST(mf_ultralight_ntag_i2c_plus_2k_file_test) { mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeNTAGI2CPlus2k); } -MU_TEST(nfca_read) { +// MU_TEST(nfca_reader) { +// Nfc* poller = nfc_alloc(); +// mu_assert(poller != NULL, "nfc_alloc() poller failed"); +// Nfc* listener = nfc_alloc(); +// mu_assert(listener != NULL, "nfc_alloc() listener failed"); + +// NfcaPoller* nfca_poller = nfca_poller_alloc(poller); +// mu_assert(nfca_poller != NULL, "nfca_poller_alloc() poller failed"); +// NfcaListener* nfca_listener = nfca_listener_alloc(listener); +// mu_assert(nfca_listener != NULL, "nfca_listener_alloc() listener failed"); + +// NfcaData nfca_listener_data = { +// .uid_len = 7, +// .uid = {0x04, 0x51, 0x5C, 0xFA, 0x6F, 0x73, 0x81}, +// .atqa = {0x44, 0x00}, +// .sak = 0x00, +// }; +// // nfca_listener_data.uid_len = 7; +// // furi_hal_random_fill_buf(nfca_listener_data.uid, 7); +// // furi_hal_random_fill_buf(nfca_listener_data.atqa, 2); +// // furi_hal_random_fill_buf(&nfca_listener_data.sak, 1); +// NfcaData nfca_poller_data = {}; + +// mu_assert( +// nfca_listener_start(nfca_listener, &nfca_listener_data, NULL, NULL) == NfcaErrorNone, +// "nfca_listener_start() failed"); + +// mu_assert( +// nfca_poller_activate(nfca_poller, &nfca_poller_data) == NfcaErrorNone, +// "nfca_poller_activate() failed"); +// mu_assert(nfca_listener_stop(nfca_listener) == NfcaErrorNone, "nfca_listener_stop() failed"); + +// mu_assert( +// memcmp(&nfca_poller_data, &nfca_listener_data, sizeof(NfcaData)) == 0, "Data not matches"); + +// nfca_listener_free(nfca_listener); +// nfc_free(listener); +// nfca_poller_free(nfca_poller); +// nfc_free(poller); +// } + +MU_TEST(mf_ultralight_reader) { Nfc* poller = nfc_alloc(); mu_assert(poller != NULL, "nfc_alloc() poller failed"); Nfc* listener = nfc_alloc(); @@ -157,30 +200,30 @@ MU_TEST(nfca_read) { NfcaListener* nfca_listener = nfca_listener_alloc(listener); mu_assert(nfca_listener != NULL, "nfca_listener_alloc() listener failed"); - NfcaData nfca_listener_data = { - .uid_len = 7, - .uid = {0x04, 0x51, 0x5C, 0xFA, 0x6F, 0x73, 0x81}, - .atqa = {0x44, 0x00}, - .sak = 0x00, - }; - // nfca_listener_data.uid_len = 7; - // furi_hal_random_fill_buf(nfca_listener_data.uid, 7); - // furi_hal_random_fill_buf(nfca_listener_data.atqa, 2); - // furi_hal_random_fill_buf(&nfca_listener_data.sak, 1); - NfcaData nfca_poller_data = {}; + MfUltralightPoller* mfu_poller = mf_ultralight_poller_alloc(nfca_poller); + mu_assert(mfu_poller != NULL, "mf_ultralight_poller_alloc() poller failed"); + MfUltralightListener* mfu_listener = mf_ultralight_listener_alloc(nfca_listener); + mu_assert(mfu_listener != NULL, "mf_ultralight_listener_alloc() listener failed"); - mu_assert( - nfca_listener_start(nfca_listener, &nfca_listener_data, NULL, NULL) == NfcaErrorNone, - "nfca_listener_start() failed"); + MfUltralightError error = MfUltralightErrorNone; + NfcDevData* dev_data = malloc(sizeof(NfcDevData)); + nfc_data_generator_fill_data(NfcDataGeneratorTypeNTAG216, dev_data); - mu_assert( - nfca_poller_activate(nfca_poller, &nfca_poller_data) == NfcaErrorNone, - "nfca_poller_activate() failed"); - mu_assert(nfca_listener_stop(nfca_listener) == NfcaErrorNone, "nfca_listener_stop() failed"); + error = mf_ultralight_listener_start(mfu_listener, &dev_data->mf_ul_data, NULL, NULL); + mu_assert(error == MfUltralightErrorNone, "mf_ultralight_listener_start() failed"); - mu_assert( - memcmp(&nfca_poller_data, &nfca_listener_data, sizeof(NfcaData)) == 0, "Data not matches"); + MfUltralightPage page = {}; + for(size_t i = 0; i < dev_data->mf_ul_data.pages_total; i++) { + error = mf_ultralight_poller_read_page(mfu_poller, i, &page); + mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_read_page() failed"); + } + + error = mf_ultralight_listener_stop(mfu_listener); + mu_assert(error == MfUltralightErrorNone, "mf_ultralight_listener_stop() failed"); + free(dev_data); + mf_ultralight_listener_free(mfu_listener); + mf_ultralight_poller_free(mfu_poller); nfca_listener_free(nfca_listener); nfc_free(listener); nfca_poller_free(nfca_poller); @@ -190,7 +233,8 @@ MU_TEST(nfca_read) { MU_TEST_SUITE(nfc) { nfc_test_alloc(); - MU_RUN_TEST(nfca_read); + // MU_RUN_TEST(nfca_reader); + MU_RUN_TEST(mf_ultralight_reader); MU_RUN_TEST(nfca_4b_file_test); MU_RUN_TEST(nfca_7b_file_test); diff --git a/applications/debug/unit_tests/nfc/nfc_transport.c b/applications/debug/unit_tests/nfc/nfc_transport.c index e56411b6ffd3..c806df96f710 100644 --- a/applications/debug/unit_tests/nfc/nfc_transport.c +++ b/applications/debug/unit_tests/nfc/nfc_transport.c @@ -343,8 +343,11 @@ void nfc_listener_abort(Nfc* instance) { furi_message_queue_put(listener_queue, &message, FuriWaitForever); furi_thread_join(instance->worker_thread); + furi_message_queue_free(listener_queue); listener_queue = NULL; + + furi_thread_free(instance->worker_thread); instance->worker_thread = NULL; } @@ -356,6 +359,8 @@ void nfc_stop(Nfc* instance) { furi_message_queue_free(poller_queue); poller_queue = NULL; + + furi_thread_free(instance->worker_thread); instance->worker_thread = NULL; } diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h index 0ed13e9758ed..876a374ada92 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h @@ -74,6 +74,10 @@ typedef struct { uint8_t data[MF_ULTRALIGHT_PAGE_SIZE]; } MfUltralightPage; +typedef struct { + MfUltralightPage page[4]; +} MfUltralightPagedCommandData; + typedef struct { uint8_t header; uint8_t vendor_id; diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c index 290b1d5ebf82..0b2388ffe695 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c @@ -17,8 +17,8 @@ struct MfUltralightListener { MfUltralightData* data; uint8_t tx_data[MF_ULTRALIGHT_LISTENER_MAX_TX_BUFF_SIZE]; uint16_t tx_bits; - uint16_t pages_total; MfUltralightFeatureSupport features; + MfUltralightListenerEventCallback callback; void* context; }; @@ -71,14 +71,19 @@ static bool mf_ultralight_listener_read_page_handler( UNUSED(rx_bits); bool command_processed = false; uint8_t start_page = rx_data[1]; - if(instance->pages_total < start_page) { + uint16_t pages_total = instance->data->pages_total; + MfUltralightPagedCommandData read_cmd_data = {}; + + if(pages_total < start_page) { mf_ultralight_listener_send_short_resp(instance, MF_ULTRALIGHT_CMD_NACK); instance->state = MfUltraligthListenerStateIdle; } else { - memcpy(instance->tx_data, instance->data->page[start_page].data, 16); - instance->tx_bits = 16 * 8; + for(size_t i = 0; i < 4; i++) { + read_cmd_data.page[i] = instance->data->page[(start_page + i) % pages_total]; + } + instance->tx_bits = sizeof(MfUltralightPagedCommandData) * 8; nfca_listener_send_standart_frame( - instance->nfca_listener, instance->tx_data, instance->tx_bits); + instance->nfca_listener, (uint8_t*)&read_cmd_data, instance->tx_bits); } command_processed = true; @@ -145,7 +150,8 @@ static const MfUltralightListenerCmdHandler mf_ultralight_command[] = { }, }; -static NfcaListenerCommand mf_ultralight_listener_event_handler(NfcaListenerEvent event, void* context) { +static NfcaListenerCommand + mf_ultralight_listener_event_handler(NfcaListenerEvent event, void* context) { furi_assert(context); MfUltralightListener* instance = context; @@ -171,17 +177,14 @@ static NfcaListenerCommand mf_ultralight_listener_event_handler(NfcaListenerEven static void mf_ultralight_listener_prepare_emulation(MfUltralightListener* instance) { MfUltralightData* data = instance->data; - if(data->type == MfUltralightTypeUnknown) { - instance->features = MfUltralightFeatureSupportReadVersion | - MfUltralightFeatureSupportReadSignature; - instance->pages_total = 16; - } + instance->features = mf_ultralight_get_feature_support_set(data->type); } MfUltralightListener* mf_ultralight_listener_alloc(NfcaListener* nfca_listener) { furi_assert(nfca_listener); MfUltralightListener* instance = malloc(sizeof(MfUltralightListener)); + instance->nfca_listener = nfca_listener; return instance; } @@ -206,7 +209,7 @@ MfUltralightError mf_ultralight_listener_start( &instance->data->nfca_data, mf_ultralight_listener_event_handler, instance); - + return mf_ultralight_process_error(error); } diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h index 1fc3794268ab..327f58873c3b 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h @@ -12,10 +12,6 @@ typedef struct { uint8_t page_to_write; } MfUltralightPollerWritePageCommand; -typedef struct { - MfUltralightPage page[4]; -} MfUltralightPagedCommandData; - typedef struct { MfUltralightPagedCommandData data; uint8_t start_page; diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c index 8c17ca4119ac..8b8650d491d2 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c @@ -44,7 +44,8 @@ MfUltralightError mf_ultralight_poller_read_page( if(poller_context.error == MfUltralightErrorNone) { *data = poller_context.data.read_cmd.data.page[0]; } - mf_ultralight_poller_reset(instance); + mf_ultralight_poller_stop(instance); + // mf_ultralight_poller_reset(instance); return poller_context.error; } From 2bcea0e7e5d212efc7bb756cf8fad26211a4f536 Mon Sep 17 00:00:00 2001 From: gornekich Date: Mon, 8 May 2023 00:14:50 +0400 Subject: [PATCH 062/149] mf ultralight: fix async api --- applications/debug/unit_tests/nfc/nfc_test.c | 8 ---- .../protocols/mf_ultralight/mf_ultralight.h | 2 +- .../mf_ultralight/mf_ultralight_listener.c | 4 +- .../mf_ultralight/mf_ultralight_poller.c | 23 ++++++----- .../mf_ultralight/mf_ultralight_poller_i.c | 40 ++++++++++--------- .../mf_ultralight/mf_ultralight_poller_i.h | 37 ++++++++++++----- .../mf_ultralight_poller_sync_api.c | 31 ++++++++------ 7 files changed, 86 insertions(+), 59 deletions(-) diff --git a/applications/debug/unit_tests/nfc/nfc_test.c b/applications/debug/unit_tests/nfc/nfc_test.c index 4afa899fa9b9..bcdbb74b3d8f 100644 --- a/applications/debug/unit_tests/nfc/nfc_test.c +++ b/applications/debug/unit_tests/nfc/nfc_test.c @@ -39,10 +39,8 @@ static void nfc_test_free() { static void nfc_test_save_and_load(NfcDevData* data) { NfcDev* nfc_dev = nfc_dev_alloc(); - mu_assert(nfc_dev != NULL, "nfc_dev_alloc() failed\r\n"); NfcDevData* nfc_dev_data_dut = malloc(sizeof(NfcDevData)); - mu_assert(nfc_dev_data_dut != NULL, "malloc() failed\r\n"); mu_assert(nfc_dev_save(nfc_dev, data, NFC_TEST_NFC_DEV_PATH), "nfc_dev_save() failed\r\n"); @@ -191,19 +189,13 @@ MU_TEST(mf_ultralight_ntag_i2c_plus_2k_file_test) { MU_TEST(mf_ultralight_reader) { Nfc* poller = nfc_alloc(); - mu_assert(poller != NULL, "nfc_alloc() poller failed"); Nfc* listener = nfc_alloc(); - mu_assert(listener != NULL, "nfc_alloc() listener failed"); NfcaPoller* nfca_poller = nfca_poller_alloc(poller); - mu_assert(nfca_poller != NULL, "nfca_poller_alloc() poller failed"); NfcaListener* nfca_listener = nfca_listener_alloc(listener); - mu_assert(nfca_listener != NULL, "nfca_listener_alloc() listener failed"); MfUltralightPoller* mfu_poller = mf_ultralight_poller_alloc(nfca_poller); - mu_assert(mfu_poller != NULL, "mf_ultralight_poller_alloc() poller failed"); MfUltralightListener* mfu_listener = mf_ultralight_listener_alloc(nfca_listener); - mu_assert(mfu_listener != NULL, "mf_ultralight_listener_alloc() listener failed"); MfUltralightError error = MfUltralightErrorNone; NfcDevData* dev_data = malloc(sizeof(NfcDevData)); diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h index 876a374ada92..b7ab521d77e3 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h @@ -76,7 +76,7 @@ typedef struct { typedef struct { MfUltralightPage page[4]; -} MfUltralightPagedCommandData; +} MfUltralightPageReadCommandData; typedef struct { uint8_t header; diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c index 0b2388ffe695..8c63531b8160 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c @@ -72,7 +72,7 @@ static bool mf_ultralight_listener_read_page_handler( bool command_processed = false; uint8_t start_page = rx_data[1]; uint16_t pages_total = instance->data->pages_total; - MfUltralightPagedCommandData read_cmd_data = {}; + MfUltralightPageReadCommandData read_cmd_data = {}; if(pages_total < start_page) { mf_ultralight_listener_send_short_resp(instance, MF_ULTRALIGHT_CMD_NACK); @@ -81,7 +81,7 @@ static bool mf_ultralight_listener_read_page_handler( for(size_t i = 0; i < 4; i++) { read_cmd_data.page[i] = instance->data->page[(start_page + i) % pages_total]; } - instance->tx_bits = sizeof(MfUltralightPagedCommandData) * 8; + instance->tx_bits = sizeof(MfUltralightPageReadCommandData) * 8; nfca_listener_send_standart_frame( instance->nfca_listener, (uint8_t*)&read_cmd_data, instance->tx_bits); } diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c index 135c890bc734..bb32ade23288 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c @@ -52,7 +52,8 @@ static MfUltralightPollerCommand mf_ultralight_poller_handler_idle(MfUltralightP static MfUltralightPollerCommand mf_ultralight_poller_handler_read_version(MfUltralightPoller* instance) { - MfUltralightError error = mf_ultralight_poller_async_read_version(instance); + MfUltralightError error = + mf_ultralight_poller_async_read_version(instance, &instance->data->version); if(error == MfUltralightErrorNone) { FURI_LOG_I(TAG, "Read version success"); instance->data->type = mf_ultralight_get_type_by_version(&instance->data->version); @@ -68,7 +69,7 @@ static MfUltralightPollerCommand static MfUltralightPollerCommand mf_ultralight_poller_handler_check_ntag_203(MfUltralightPoller* instance) { - MfUltralightPagedCommandData data = {}; + MfUltralightPageReadCommandData data = {}; MfUltralightError error = mf_ultralight_poller_async_read_page(instance, 41, &data); if(error == MfUltralightErrorNone) { FURI_LOG_I(TAG, "NTAG203 detected"); @@ -105,7 +106,8 @@ static MfUltralightPollerCommand MfUltralightPollerState next_state = MfUltralightPollerStateAuth; if(instance->feature_set & MfUltralightFeatureSupportReadSignature) { FURI_LOG_D(TAG, "Reading signature"); - MfUltralightError error = mf_ultralight_poller_async_read_signature(instance); + MfUltralightError error = + mf_ultralight_poller_async_read_signature(instance, &instance->data->signature); if(error != MfUltralightErrorNone) { FURI_LOG_E(TAG, "Read signature failed"); next_state = MfUltralightPollerStateReadFailed; @@ -129,8 +131,10 @@ static MfUltralightPollerCommand instance->state = MfUltralightPollerStateReadTearingFlags; } else { FURI_LOG_D(TAG, "Reading counter %d", instance->counters_read); - MfUltralightError error = - mf_ultralight_poller_async_read_counter(instance, instance->counters_read); + MfUltralightError error = mf_ultralight_poller_async_read_counter( + instance, + instance->counters_read, + &instance->data->counter[instance->counters_read]); if(error != MfUltralightErrorNone) { FURI_LOG_E(TAG, "Failed to read %d counter", instance->counters_read); instance->state = MfUltralightPollerStateReadFailed; @@ -157,7 +161,9 @@ static MfUltralightPollerCommand } else { FURI_LOG_D(TAG, "Reading tearing flag %d", instance->tearing_flag_read); MfUltralightError error = mf_ultralight_poller_async_read_tearing_flag( - instance, instance->tearing_flag_read); + instance, + instance->tearing_flag_read, + &instance->data->tearing_flag[instance->tearing_flag_read]); if(error != MfUltralightErrorNone) { FURI_LOG_E(TAG, "Reading tearing flag %d failed", instance->tearing_flag_read); instance->state = MfUltralightPollerStateReadFailed; @@ -211,10 +217,9 @@ static MfUltralightPollerCommand mf_ultralight_poller_handler_auth(MfUltralightP static MfUltralightPollerCommand mf_ultralight_poller_handler_read_pages(MfUltralightPoller* instance) { - MfUltralightPagedCommandData data = {}; + MfUltralightPageReadCommandData data = {}; uint8_t start_page = instance->pages_read; - MfUltralightError error = - mf_ultralight_poller_async_read_page(instance, start_page, &data); + MfUltralightError error = mf_ultralight_poller_async_read_page(instance, start_page, &data); if(error == MfUltralightErrorNone) { for(size_t i = 0; i < 4; i++) { if(start_page + i < instance->pages_total) { diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c index 2ea7595d6e7c..809af0bc5fb5 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c @@ -75,7 +75,7 @@ MfUltralightError MfUltralightError mf_ultralight_poller_async_read_page( MfUltralightPoller* instance, uint8_t start_page, - MfUltralightPagedCommandData* data) { + MfUltralightPageReadCommandData* data) { NfcPollerBuffer* buff = instance->buffer; buff->tx_data[0] = MF_ULTRALIGHT_CMD_READ_PAGE; buff->tx_data[1] = start_page; @@ -96,11 +96,11 @@ MfUltralightError mf_ultralight_poller_async_read_page( ret = mf_ultralight_process_error(error); break; } - if(buff->rx_bits != sizeof(MfUltralightPagedCommandData) * 8) { + if(buff->rx_bits != sizeof(MfUltralightPageReadCommandData) * 8) { ret = MfUltralightErrorProtocol; break; } - memcpy(data, buff->rx_data, sizeof(MfUltralightPagedCommandData)); + memcpy(data, buff->rx_data, sizeof(MfUltralightPageReadCommandData)); } while(false); return ret; @@ -142,7 +142,9 @@ MfUltralightError mf_ultralight_poller_async_write_page( return ret; } -MfUltralightError mf_ultralight_poller_async_read_version(MfUltralightPoller* instance) { +MfUltralightError mf_ultralight_poller_async_read_version( + MfUltralightPoller* instance, + MfUltralightVersion* data) { NfcPollerBuffer* buff = instance->buffer; buff->tx_data[0] = MF_ULTRALIGHT_CMD_GET_VERSION; buff->tx_bits = 8; @@ -162,17 +164,19 @@ MfUltralightError mf_ultralight_poller_async_read_version(MfUltralightPoller* in ret = mf_ultralight_process_error(error); break; } - if(buff->rx_bits != 8 * 8) { + if(buff->rx_bits != sizeof(MfUltralightVersion) * 8) { ret = MfUltralightErrorProtocol; break; } - memcpy(&instance->data->version, buff->rx_data, sizeof(MfUltralightVersion)); + memcpy(&data, buff->rx_data, sizeof(MfUltralightVersion)); } while(false); return ret; } -MfUltralightError mf_ultralight_poller_async_read_signature(MfUltralightPoller* instance) { +MfUltralightError mf_ultralight_poller_async_read_signature( + MfUltralightPoller* instance, + MfUltralightSignature* data) { NfcPollerBuffer* buff = instance->buffer; buff->tx_data[0] = MF_ULTRALIGTH_CMD_READ_SIG; buff->rx_data[1] = 0x00; @@ -193,18 +197,20 @@ MfUltralightError mf_ultralight_poller_async_read_signature(MfUltralightPoller* ret = mf_ultralight_process_error(error); break; } - if(buff->rx_bits != 32 * 8) { + if(buff->rx_bits != sizeof(MfUltralightSignature) * 8) { ret = MfUltralightErrorProtocol; break; } - memcpy(&instance->data->signature, buff->rx_data, sizeof(MfUltralightSignature)); + memcpy(data, buff->rx_data, sizeof(MfUltralightSignature)); } while(false); return ret; } -MfUltralightError - mf_ultralight_poller_async_read_counter(MfUltralightPoller* instance, uint8_t counter_num) { +MfUltralightError mf_ultralight_poller_async_read_counter( + MfUltralightPoller* instance, + uint8_t counter_num, + MfUltralightCounter* data) { NfcPollerBuffer* buff = instance->buffer; buff->tx_data[0] = MF_ULTRALIGHT_CMD_READ_CNT; buff->tx_data[1] = counter_num; @@ -229,7 +235,7 @@ MfUltralightError ret = MfUltralightErrorProtocol; break; } - memcpy(&instance->data->counter[counter_num], buff->rx_data, MF_ULTRALIGHT_COUNTER_SIZE); + memcpy(data, buff->rx_data, MF_ULTRALIGHT_COUNTER_SIZE); } while(false); return ret; @@ -237,7 +243,8 @@ MfUltralightError MfUltralightError mf_ultralight_poller_async_read_tearing_flag( MfUltralightPoller* instance, - uint8_t tearing_falg_num) { + uint8_t tearing_falg_num, + MfUltralightTearingFlag* data) { NfcPollerBuffer* buff = instance->buffer; buff->tx_data[0] = MF_ULTRALIGHT_CMD_CHECK_TEARING; buff->tx_data[1] = tearing_falg_num; @@ -258,14 +265,11 @@ MfUltralightError mf_ultralight_poller_async_read_tearing_flag( ret = mf_ultralight_process_error(error); break; } - if(buff->rx_bits != 8) { + if(buff->rx_bits != sizeof(MfUltralightTearingFlag) * 8) { ret = MfUltralightErrorProtocol; break; } - memcpy( - &instance->data->tearing_flag[tearing_falg_num], - buff->rx_data, - MF_ULTRALIGHT_TEARING_FLAG_SIZE); + memcpy(data, buff->rx_data, MF_ULTRALIGHT_TEARING_FLAG_SIZE); } while(false); return ret; diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h index 327f58873c3b..d60433ac27fe 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h @@ -13,15 +13,27 @@ typedef struct { } MfUltralightPollerWritePageCommand; typedef struct { - MfUltralightPagedCommandData data; + MfUltralightPageReadCommandData data; uint8_t start_page; } MfUltralightPollerReadPageCommand; +typedef struct { + MfUltralightCounter data; + uint8_t counter_num; +} MfUltralightPollerReadCounterCommand; + +typedef struct { + MfUltralightTearingFlag data; + uint8_t tearing_flag_num; +} MfUltralightPollerReadTearingFlagCommand; + typedef union { - uint8_t counter_to_read; - uint8_t tearing_flag_to_read; MfUltralightPollerWritePageCommand write_cmd; MfUltralightPollerReadPageCommand read_cmd; + MfUltralightVersion version; + MfUltralightSignature signature; + MfUltralightPollerReadCounterCommand counter_cmd; + MfUltralightPollerReadTearingFlagCommand tearing_flag_cmd; } MfUltralightPollerContextData; typedef enum { @@ -73,23 +85,30 @@ MfUltralightError MfUltralightError mf_ultralight_poller_async_read_page( MfUltralightPoller* instance, uint8_t start_page, - MfUltralightPagedCommandData* data); + MfUltralightPageReadCommandData* data); MfUltralightError mf_ultralight_poller_async_write_page( MfUltralightPoller* instance, uint8_t page, MfUltralightPage* data); -MfUltralightError mf_ultralight_poller_async_read_version(MfUltralightPoller* instance); +MfUltralightError mf_ultralight_poller_async_read_version( + MfUltralightPoller* instance, + MfUltralightVersion* data); -MfUltralightError mf_ultralight_poller_async_read_signature(MfUltralightPoller* instance); +MfUltralightError mf_ultralight_poller_async_read_signature( + MfUltralightPoller* instance, + MfUltralightSignature* data); -MfUltralightError - mf_ultralight_poller_async_read_counter(MfUltralightPoller* instance, uint8_t counter_num); +MfUltralightError mf_ultralight_poller_async_read_counter( + MfUltralightPoller* instance, + uint8_t counter_num, + MfUltralightCounter* data); MfUltralightError mf_ultralight_poller_async_read_tearing_flag( MfUltralightPoller* instance, - uint8_t tearing_falg_num); + uint8_t tearing_falg_num, + MfUltralightTearingFlag* data); #ifdef __cplusplus extern "C" { diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c index 8b8650d491d2..17b50904bffd 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c @@ -17,7 +17,9 @@ static NfcaPollerCommand mf_ultraight_read_page_callback(NfcaPollerEvent event, MfUltralightPollerContext* poller_context = context; if(event.type == NfcaPollerEventTypeReady) { poller_context->error = mf_ultralight_poller_async_read_page( - poller_context->instance, poller_context->data.read_cmd.start_page, &poller_context->data.read_cmd.data); + poller_context->instance, + poller_context->data.read_cmd.start_page, + &poller_context->data.read_cmd.data); nfca_poller_halt(poller_context->instance->nfca_poller); } else if(event.type == NfcaPollerEventTypeError) { poller_context->error = mf_ultralight_process_error(event.data.error); @@ -94,7 +96,8 @@ static NfcaPollerCommand mf_ultraight_read_version_callback(NfcaPollerEvent even MfUltralightPollerContext* poller_context = context; if(event.type == NfcaPollerEventTypeReady) { - poller_context->error = mf_ultralight_poller_async_read_version(poller_context->instance); + poller_context->error = mf_ultralight_poller_async_read_version( + poller_context->instance, &poller_context->data.version); nfca_poller_halt(poller_context->instance->nfca_poller); } else if(event.type == NfcaPollerEventTypeError) { poller_context->error = mf_ultralight_process_error(event.data.error); @@ -115,7 +118,7 @@ MfUltralightError mf_ultralight_poller_start(instance, mf_ultraight_read_version_callback, &poller_context); furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); - *data = instance->data->version; + *data = poller_context.data.version; mf_ultralight_poller_reset(instance); return poller_context.error; @@ -127,8 +130,8 @@ static NfcaPollerCommand MfUltralightPollerContext* poller_context = context; if(event.type == NfcaPollerEventTypeReady) { - poller_context->error = - mf_ultralight_poller_async_read_signature(poller_context->instance); + poller_context->error = mf_ultralight_poller_async_read_signature( + poller_context->instance, &poller_context->data.signature); nfca_poller_halt(poller_context->instance->nfca_poller); } else if(event.type == NfcaPollerEventTypeError) { poller_context->error = mf_ultralight_process_error(event.data.error); @@ -150,7 +153,7 @@ MfUltralightError mf_ultralight_poller_start(instance, mf_ultraight_read_signature_callback, &poller_context); furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); - *data = instance->data->signature; + *data = poller_context.data.signature; mf_ultralight_poller_reset(instance); return poller_context.error; @@ -162,7 +165,9 @@ static NfcaPollerCommand mf_ultraight_read_counter_callback(NfcaPollerEvent even MfUltralightPollerContext* poller_context = context; if(event.type == NfcaPollerEventTypeReady) { poller_context->error = mf_ultralight_poller_async_read_counter( - poller_context->instance, poller_context->data.counter_to_read); + poller_context->instance, + poller_context->data.counter_cmd.counter_num, + &poller_context->data.counter_cmd.data); nfca_poller_halt(poller_context->instance->nfca_poller); } else if(event.type == NfcaPollerEventTypeError) { poller_context->error = mf_ultralight_process_error(event.data.error); @@ -181,13 +186,13 @@ MfUltralightError mf_ultralight_poller_read_counter( furi_assert(data); MfUltralightPollerContext poller_context = {}; - poller_context.data.counter_to_read = counter_num; + poller_context.data.counter_cmd.counter_num = counter_num; poller_context.instance = instance; poller_context.thread_id = furi_thread_get_current_id(); mf_ultralight_poller_start(instance, mf_ultraight_read_counter_callback, &poller_context); furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); - *data = instance->data->counter[counter_num]; + *data = poller_context.data.counter_cmd.data; mf_ultralight_poller_reset(instance); return poller_context.error; @@ -200,7 +205,9 @@ static NfcaPollerCommand MfUltralightPollerContext* poller_context = context; if(event.type == NfcaPollerEventTypeReady) { poller_context->error = mf_ultralight_poller_async_read_tearing_flag( - poller_context->instance, poller_context->data.tearing_flag_to_read); + poller_context->instance, + poller_context->data.tearing_flag_cmd.tearing_flag_num, + &poller_context->data.tearing_flag_cmd.data); nfca_poller_halt(poller_context->instance->nfca_poller); } else if(event.type == NfcaPollerEventTypeError) { poller_context->error = mf_ultralight_process_error(event.data.error); @@ -219,13 +226,13 @@ MfUltralightError mf_ultralight_poller_read_tearing_flag( furi_assert(data); MfUltralightPollerContext poller_context = {}; - poller_context.data.tearing_flag_to_read = flag_num; + poller_context.data.tearing_flag_cmd.tearing_flag_num = flag_num; poller_context.instance = instance; poller_context.thread_id = furi_thread_get_current_id(); mf_ultralight_poller_start(instance, mf_ultraight_read_tering_flag_callback, &poller_context); furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); - *data = instance->data->tearing_flag[flag_num]; + *data = poller_context.data.tearing_flag_cmd.data; mf_ultralight_poller_reset(instance); return poller_context.error; From eea41aa3db6819e35a48c8a8de9fcbff34c123da Mon Sep 17 00:00:00 2001 From: gornekich Date: Mon, 8 May 2023 14:48:49 +0400 Subject: [PATCH 063/149] nfc: rework allocation order --- applications/debug/unit_tests/nfc/nfc_test.c | 260 +++++++++--------- .../debug/unit_tests/nfc/nfc_transport.c | 22 +- applications/main/nfc_rpc/nfc_rpc_nfca.c | 2 +- .../mf_ultralight/mf_ultralight_poller.c | 2 +- .../mf_ultralight_poller_sync_api.c | 16 +- lib/nfc/protocols/nfca/nfca_poller.c | 10 +- lib/nfc/protocols/nfca/nfca_poller.h | 2 +- lib/nfc/protocols/nfca/nfca_poller_i.c | 2 +- 8 files changed, 161 insertions(+), 155 deletions(-) diff --git a/applications/debug/unit_tests/nfc/nfc_test.c b/applications/debug/unit_tests/nfc/nfc_test.c index bcdbb74b3d8f..958f47478293 100644 --- a/applications/debug/unit_tests/nfc/nfc_test.c +++ b/applications/debug/unit_tests/nfc/nfc_test.c @@ -37,155 +37,151 @@ static void nfc_test_free() { nfc_test = NULL; } -static void nfc_test_save_and_load(NfcDevData* data) { - NfcDev* nfc_dev = nfc_dev_alloc(); +// static void nfc_test_save_and_load(NfcDevData* data) { +// NfcDev* nfc_dev = nfc_dev_alloc(); - NfcDevData* nfc_dev_data_dut = malloc(sizeof(NfcDevData)); +// NfcDevData* nfc_dev_data_dut = malloc(sizeof(NfcDevData)); - mu_assert(nfc_dev_save(nfc_dev, data, NFC_TEST_NFC_DEV_PATH), "nfc_dev_save() failed\r\n"); +// mu_assert(nfc_dev_save(nfc_dev, data, NFC_TEST_NFC_DEV_PATH), "nfc_dev_save() failed\r\n"); - mu_assert( - nfc_dev_load(nfc_dev, nfc_dev_data_dut, NFC_TEST_NFC_DEV_PATH), - "nfc_dev_load() failed\r\n"); +// mu_assert( +// nfc_dev_load(nfc_dev, nfc_dev_data_dut, NFC_TEST_NFC_DEV_PATH), +// "nfc_dev_load() failed\r\n"); - mu_assert( - memcmp(nfc_dev_data_dut, data, sizeof(NfcDevData)) == 0, - "nfc_dev_data_dut != nfc_dev_data_ref\r\n"); +// mu_assert( +// memcmp(nfc_dev_data_dut, data, sizeof(NfcDevData)) == 0, +// "nfc_dev_data_dut != nfc_dev_data_ref\r\n"); - mu_assert( - storage_simply_remove(nfc_test->storage, NFC_TEST_NFC_DEV_PATH), - "storage_simply_remove() failed\r\n"); +// mu_assert( +// storage_simply_remove(nfc_test->storage, NFC_TEST_NFC_DEV_PATH), +// "storage_simply_remove() failed\r\n"); - free(nfc_dev_data_dut); - nfc_dev_free(nfc_dev); -} +// free(nfc_dev_data_dut); +// nfc_dev_free(nfc_dev); +// } -static void nfca_file_test(uint8_t uid_len) { - NfcDevData* nfc_dev_data_ref = malloc(sizeof(NfcDevData)); - mu_assert(nfc_dev_data_ref != NULL, "malloc() failed\r\n"); +// static void nfca_file_test(uint8_t uid_len) { +// NfcDevData* nfc_dev_data_ref = malloc(sizeof(NfcDevData)); +// mu_assert(nfc_dev_data_ref != NULL, "malloc() failed\r\n"); - NfcaData* data = &nfc_dev_data_ref->nfca_data; +// NfcaData* data = &nfc_dev_data_ref->nfca_data; - data->uid_len = uid_len; - furi_hal_random_fill_buf(data->uid, uid_len); - furi_hal_random_fill_buf(data->atqa, 2); - furi_hal_random_fill_buf(&data->sak, 1); +// data->uid_len = uid_len; +// furi_hal_random_fill_buf(data->uid, uid_len); +// furi_hal_random_fill_buf(data->atqa, 2); +// furi_hal_random_fill_buf(&data->sak, 1); - nfc_test_save_and_load(nfc_dev_data_ref); +// nfc_test_save_and_load(nfc_dev_data_ref); - free(nfc_dev_data_ref); -} +// free(nfc_dev_data_ref); +// } -static void mf_ultralight_file_test_with_generator(NfcDataGeneratorType type) { - NfcDevData* nfc_dev_data_ref = malloc(sizeof(NfcDevData)); - mu_assert(nfc_dev_data_ref != NULL, "malloc() failed\r\n"); +// static void mf_ultralight_file_test_with_generator(NfcDataGeneratorType type) { +// NfcDevData* nfc_dev_data_ref = malloc(sizeof(NfcDevData)); +// mu_assert(nfc_dev_data_ref != NULL, "malloc() failed\r\n"); - nfc_data_generator_fill_data(type, nfc_dev_data_ref); - nfc_test_save_and_load(nfc_dev_data_ref); +// nfc_data_generator_fill_data(type, nfc_dev_data_ref); +// nfc_test_save_and_load(nfc_dev_data_ref); - free(nfc_dev_data_ref); -} +// free(nfc_dev_data_ref); +// } -MU_TEST(nfca_4b_file_test) { - nfca_file_test(4); -} +// MU_TEST(nfca_4b_file_test) { +// nfca_file_test(4); +// } -MU_TEST(nfca_7b_file_test) { - nfca_file_test(7); -} +// MU_TEST(nfca_7b_file_test) { +// nfca_file_test(7); +// } -MU_TEST(mf_ultralight_file_test) { - mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeMfUltralight); -} +// MU_TEST(mf_ultralight_file_test) { +// mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeMfUltralight); +// } -MU_TEST(mf_ultralight_ev1_11_file_test) { - mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeMfUltralightEV1_11); -} +// MU_TEST(mf_ultralight_ev1_11_file_test) { +// mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeMfUltralightEV1_11); +// } -MU_TEST(mf_ultralight_ev1_h11_file_test) { - mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeMfUltralightEV1_H11); -} +// MU_TEST(mf_ultralight_ev1_h11_file_test) { +// mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeMfUltralightEV1_H11); +// } -MU_TEST(mf_ultralight_ev1_21_file_test) { - mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeMfUltralightEV1_21); -} +// MU_TEST(mf_ultralight_ev1_21_file_test) { +// mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeMfUltralightEV1_21); +// } -MU_TEST(mf_ultralight_ev1_h21_file_test) { - mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeMfUltralightEV1_H21); -} +// MU_TEST(mf_ultralight_ev1_h21_file_test) { +// mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeMfUltralightEV1_H21); +// } -MU_TEST(mf_ultralight_ntag_203_file_test) { - mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeNTAG203); -} +// MU_TEST(mf_ultralight_ntag_203_file_test) { +// mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeNTAG203); +// } -MU_TEST(mf_ultralight_ntag_213_file_test) { - mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeNTAG213); -} +// MU_TEST(mf_ultralight_ntag_213_file_test) { +// mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeNTAG213); +// } -MU_TEST(mf_ultralight_ntag_215_file_test) { - mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeNTAG215); -} +// MU_TEST(mf_ultralight_ntag_215_file_test) { +// mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeNTAG215); +// } -MU_TEST(mf_ultralight_ntag_216_file_test) { - mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeNTAG216); -} +// MU_TEST(mf_ultralight_ntag_216_file_test) { +// mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeNTAG216); +// } -MU_TEST(mf_ultralight_ntag_i2c_1k_file_test) { - mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeNTAGI2C1k); -} +// MU_TEST(mf_ultralight_ntag_i2c_1k_file_test) { +// mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeNTAGI2C1k); +// } -MU_TEST(mf_ultralight_ntag_i2c_2k_file_test) { - mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeNTAGI2C2k); -} +// MU_TEST(mf_ultralight_ntag_i2c_2k_file_test) { +// mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeNTAGI2C2k); +// } -MU_TEST(mf_ultralight_ntag_i2c_plus_1k_file_test) { - mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeNTAGI2CPlus1k); -} +// MU_TEST(mf_ultralight_ntag_i2c_plus_1k_file_test) { +// mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeNTAGI2CPlus1k); +// } -MU_TEST(mf_ultralight_ntag_i2c_plus_2k_file_test) { - mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeNTAGI2CPlus2k); -} +// MU_TEST(mf_ultralight_ntag_i2c_plus_2k_file_test) { +// mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeNTAGI2CPlus2k); +// } -// MU_TEST(nfca_reader) { -// Nfc* poller = nfc_alloc(); -// mu_assert(poller != NULL, "nfc_alloc() poller failed"); -// Nfc* listener = nfc_alloc(); -// mu_assert(listener != NULL, "nfc_alloc() listener failed"); - -// NfcaPoller* nfca_poller = nfca_poller_alloc(poller); -// mu_assert(nfca_poller != NULL, "nfca_poller_alloc() poller failed"); -// NfcaListener* nfca_listener = nfca_listener_alloc(listener); -// mu_assert(nfca_listener != NULL, "nfca_listener_alloc() listener failed"); - -// NfcaData nfca_listener_data = { -// .uid_len = 7, -// .uid = {0x04, 0x51, 0x5C, 0xFA, 0x6F, 0x73, 0x81}, -// .atqa = {0x44, 0x00}, -// .sak = 0x00, -// }; -// // nfca_listener_data.uid_len = 7; -// // furi_hal_random_fill_buf(nfca_listener_data.uid, 7); -// // furi_hal_random_fill_buf(nfca_listener_data.atqa, 2); -// // furi_hal_random_fill_buf(&nfca_listener_data.sak, 1); -// NfcaData nfca_poller_data = {}; +MU_TEST(nfca_reader) { + Nfc* poller = nfc_alloc(); + Nfc* listener = nfc_alloc(); -// mu_assert( -// nfca_listener_start(nfca_listener, &nfca_listener_data, NULL, NULL) == NfcaErrorNone, -// "nfca_listener_start() failed"); + NfcaPoller* nfca_poller = nfca_poller_alloc(poller); + NfcaListener* nfca_listener = nfca_listener_alloc(listener); -// mu_assert( -// nfca_poller_activate(nfca_poller, &nfca_poller_data) == NfcaErrorNone, -// "nfca_poller_activate() failed"); -// mu_assert(nfca_listener_stop(nfca_listener) == NfcaErrorNone, "nfca_listener_stop() failed"); + NfcaData nfca_listener_data = { + .uid_len = 7, + .uid = {0x04, 0x51, 0x5C, 0xFA, 0x6F, 0x73, 0x81}, + .atqa = {0x44, 0x00}, + .sak = 0x00, + }; + // nfca_listener_data.uid_len = 7; + // furi_hal_random_fill_buf(nfca_listener_data.uid, 7); + // furi_hal_random_fill_buf(nfca_listener_data.atqa, 2); + // furi_hal_random_fill_buf(&nfca_listener_data.sak, 1); + NfcaData nfca_poller_data = {}; -// mu_assert( -// memcmp(&nfca_poller_data, &nfca_listener_data, sizeof(NfcaData)) == 0, "Data not matches"); + mu_assert( + nfca_listener_start(nfca_listener, &nfca_listener_data, NULL, NULL) == NfcaErrorNone, + "nfca_listener_start() failed"); -// nfca_listener_free(nfca_listener); -// nfc_free(listener); -// nfca_poller_free(nfca_poller); -// nfc_free(poller); -// } + mu_assert( + nfca_poller_read(nfca_poller, &nfca_poller_data) == NfcaErrorNone, + "nfca_poller_read() failed"); + mu_assert(nfca_listener_stop(nfca_listener) == NfcaErrorNone, "nfca_listener_stop() failed"); + + mu_assert( + memcmp(&nfca_poller_data, &nfca_listener_data, sizeof(NfcaData)) == 0, "Data not matches"); + + nfca_listener_free(nfca_listener); + nfc_free(listener); + nfca_poller_free(nfca_poller); + nfc_free(poller); +} MU_TEST(mf_ultralight_reader) { Nfc* poller = nfc_alloc(); @@ -225,25 +221,25 @@ MU_TEST(mf_ultralight_reader) { MU_TEST_SUITE(nfc) { nfc_test_alloc(); - // MU_RUN_TEST(nfca_reader); + MU_RUN_TEST(nfca_reader); MU_RUN_TEST(mf_ultralight_reader); - MU_RUN_TEST(nfca_4b_file_test); - MU_RUN_TEST(nfca_7b_file_test); - - MU_RUN_TEST(mf_ultralight_file_test); - MU_RUN_TEST(mf_ultralight_ev1_11_file_test); - MU_RUN_TEST(mf_ultralight_ev1_h11_file_test); - MU_RUN_TEST(mf_ultralight_ev1_21_file_test); - MU_RUN_TEST(mf_ultralight_ev1_h21_file_test); - MU_RUN_TEST(mf_ultralight_ntag_203_file_test); - MU_RUN_TEST(mf_ultralight_ntag_213_file_test); - MU_RUN_TEST(mf_ultralight_ntag_215_file_test); - MU_RUN_TEST(mf_ultralight_ntag_216_file_test); - MU_RUN_TEST(mf_ultralight_ntag_i2c_1k_file_test); - MU_RUN_TEST(mf_ultralight_ntag_i2c_2k_file_test); - MU_RUN_TEST(mf_ultralight_ntag_i2c_plus_1k_file_test); - MU_RUN_TEST(mf_ultralight_ntag_i2c_plus_2k_file_test); + // MU_RUN_TEST(nfca_4b_file_test); + // MU_RUN_TEST(nfca_7b_file_test); + + // MU_RUN_TEST(mf_ultralight_file_test); + // MU_RUN_TEST(mf_ultralight_ev1_11_file_test); + // MU_RUN_TEST(mf_ultralight_ev1_h11_file_test); + // MU_RUN_TEST(mf_ultralight_ev1_21_file_test); + // MU_RUN_TEST(mf_ultralight_ev1_h21_file_test); + // MU_RUN_TEST(mf_ultralight_ntag_203_file_test); + // MU_RUN_TEST(mf_ultralight_ntag_213_file_test); + // MU_RUN_TEST(mf_ultralight_ntag_215_file_test); + // MU_RUN_TEST(mf_ultralight_ntag_216_file_test); + // MU_RUN_TEST(mf_ultralight_ntag_i2c_1k_file_test); + // MU_RUN_TEST(mf_ultralight_ntag_i2c_2k_file_test); + // MU_RUN_TEST(mf_ultralight_ntag_i2c_plus_1k_file_test); + // MU_RUN_TEST(mf_ultralight_ntag_i2c_plus_2k_file_test); nfc_test_free(); } diff --git a/applications/debug/unit_tests/nfc/nfc_transport.c b/applications/debug/unit_tests/nfc/nfc_transport.c index c806df96f710..ed582576b5f4 100644 --- a/applications/debug/unit_tests/nfc/nfc_transport.c +++ b/applications/debug/unit_tests/nfc/nfc_transport.c @@ -7,6 +7,11 @@ #define NFC_MAX_DATA_SIZE (128) +typedef enum { + NfcTransportLogLevelWarning, + NfcTransportLogLevelInfo, +} NfcTransportLogLevel; + FuriMessageQueue* poller_queue = NULL; FuriMessageQueue* listener_queue = NULL; @@ -57,14 +62,22 @@ struct Nfc { FuriThread* worker_thread; }; -static void nfc_test_print(const char* message, uint8_t* buffer, uint16_t bits) { +static void nfc_test_print( + NfcTransportLogLevel log_level, + const char* message, + uint8_t* buffer, + uint16_t bits) { FuriString* str = furi_string_alloc(); size_t bytes = (bits + 7) / 8; for(size_t i = 0; i < bytes; i++) { furi_string_cat_printf(str, " %02X", buffer[i]); } - FURI_LOG_I(message, "%s", furi_string_get_cstr(str)); + if(log_level == NfcTransportLogLevelWarning) { + FURI_LOG_W(message, "%s", furi_string_get_cstr(str)); + } else { + FURI_LOG_I(message, "%s", furi_string_get_cstr(str)); + } furi_string_free(str); } @@ -276,7 +289,8 @@ static int32_t nfc_worker_listener(void* context) { instance->callback(event, instance->context); break; } else if(message.type == NfcMessageTypeTx) { - nfc_test_print("RDR", message.data.data, message.data.data_bits); + nfc_test_print( + NfcTransportLogLevelInfo, "RDR", message.data.data, message.data.data_bits); if(instance->col_res_status != NfcaColResStatusDone) { nfc_worker_listener_pass_col_res( instance, message.data.data, message.data.data_bits); @@ -415,7 +429,7 @@ NfcError nfc_trx( furi_assert(message.data.data_bits / 8 <= rx_data_size); *rx_bits = message.data.data_bits; memcpy(rx_data, message.data.data, (message.data.data_bits + 7) / 8); - nfc_test_print("TAG", rx_data, *rx_bits); + nfc_test_print(NfcTransportLogLevelWarning, "TAG", rx_data, *rx_bits); } else if(message.type == NfcMessageTypeTimeout) { error = NfcErrorTimeout; } diff --git a/applications/main/nfc_rpc/nfc_rpc_nfca.c b/applications/main/nfc_rpc/nfc_rpc_nfca.c index 4ce3fbf51639..d7454b9c5d55 100644 --- a/applications/main/nfc_rpc/nfc_rpc_nfca.c +++ b/applications/main/nfc_rpc/nfc_rpc_nfca.c @@ -49,7 +49,7 @@ static void nfc_rpc_nfca_read(Nfc_Main* cmd, void* context) { PB_Nfca_ReadResponse pb_nfca_read_resp = PB_Nfca_ReadResponse_init_default; NfcaData nfca_data = {}; - NfcaError error = nfca_poller_activate(instance->nfca_poller, &nfca_data); + NfcaError error = nfca_poller_read(instance->nfca_poller, &nfca_data); cmd->command_status = Nfc_CommandStatus_OK; cmd->which_content = Nfc_Main_nfca_read_resp_tag; diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c index bb32ade23288..12faaaa43667 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c @@ -365,7 +365,6 @@ MfUltralightError mf_ultralight_poller_reset(MfUltralightPoller* instance) { nfc_poller_buffer_free(instance->buffer); instance->callback = NULL; instance->context = NULL; - free(instance->data); instance->state = MfUltralightPollerStateIdle; return MfUltralightErrorNone; @@ -378,6 +377,7 @@ MfUltralightError mf_ultralight_poller_stop(MfUltralightPoller* instance) { instance->session_state = MfUltralightPollerSessionStateStopRequest; nfca_poller_stop(instance->nfca_poller); instance->session_state = MfUltralightPollerSessionStateIdle; + free(instance->data); return mf_ultralight_poller_reset(instance); } diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c index 17b50904bffd..ad9fe82e8b38 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c @@ -47,7 +47,6 @@ MfUltralightError mf_ultralight_poller_read_page( *data = poller_context.data.read_cmd.data.page[0]; } mf_ultralight_poller_stop(instance); - // mf_ultralight_poller_reset(instance); return poller_context.error; } @@ -65,7 +64,6 @@ static NfcaPollerCommand mf_ultraight_write_page_callback(NfcaPollerEvent event, } else if(event.type == NfcaPollerEventTypeError) { poller_context->error = mf_ultralight_process_error(event.data.error); } - mf_ultralight_poller_stop(poller_context->instance); furi_thread_flags_set(poller_context->thread_id, MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); return NfcaPollerCommandStop; @@ -86,7 +84,7 @@ MfUltralightError mf_ultralight_poller_write_page( mf_ultralight_poller_start(instance, mf_ultraight_write_page_callback, &poller_context); furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); - mf_ultralight_poller_reset(instance); + mf_ultralight_poller_stop(instance); return poller_context.error; } @@ -102,7 +100,6 @@ static NfcaPollerCommand mf_ultraight_read_version_callback(NfcaPollerEvent even } else if(event.type == NfcaPollerEventTypeError) { poller_context->error = mf_ultralight_process_error(event.data.error); } - mf_ultralight_poller_stop(poller_context->instance); furi_thread_flags_set(poller_context->thread_id, MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); return NfcaPollerCommandStop; @@ -119,7 +116,7 @@ MfUltralightError mf_ultralight_poller_start(instance, mf_ultraight_read_version_callback, &poller_context); furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); *data = poller_context.data.version; - mf_ultralight_poller_reset(instance); + mf_ultralight_poller_stop(instance); return poller_context.error; } @@ -136,7 +133,6 @@ static NfcaPollerCommand } else if(event.type == NfcaPollerEventTypeError) { poller_context->error = mf_ultralight_process_error(event.data.error); } - mf_ultralight_poller_stop(poller_context->instance); furi_thread_flags_set(poller_context->thread_id, MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); return NfcaPollerCommandStop; @@ -154,7 +150,7 @@ MfUltralightError mf_ultralight_poller_start(instance, mf_ultraight_read_signature_callback, &poller_context); furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); *data = poller_context.data.signature; - mf_ultralight_poller_reset(instance); + mf_ultralight_poller_stop(instance); return poller_context.error; } @@ -172,7 +168,6 @@ static NfcaPollerCommand mf_ultraight_read_counter_callback(NfcaPollerEvent even } else if(event.type == NfcaPollerEventTypeError) { poller_context->error = mf_ultralight_process_error(event.data.error); } - mf_ultralight_poller_stop(poller_context->instance); furi_thread_flags_set(poller_context->thread_id, MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); return NfcaPollerCommandStop; @@ -193,7 +188,7 @@ MfUltralightError mf_ultralight_poller_read_counter( mf_ultralight_poller_start(instance, mf_ultraight_read_counter_callback, &poller_context); furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); *data = poller_context.data.counter_cmd.data; - mf_ultralight_poller_reset(instance); + mf_ultralight_poller_stop(instance); return poller_context.error; } @@ -212,7 +207,6 @@ static NfcaPollerCommand } else if(event.type == NfcaPollerEventTypeError) { poller_context->error = mf_ultralight_process_error(event.data.error); } - mf_ultralight_poller_stop(poller_context->instance); furi_thread_flags_set(poller_context->thread_id, MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); return NfcaPollerCommandStop; @@ -233,7 +227,7 @@ MfUltralightError mf_ultralight_poller_read_tearing_flag( mf_ultralight_poller_start(instance, mf_ultraight_read_tering_flag_callback, &poller_context); furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); *data = poller_context.data.tearing_flag_cmd.data; - mf_ultralight_poller_reset(instance); + mf_ultralight_poller_stop(instance); return poller_context.error; } diff --git a/lib/nfc/protocols/nfca/nfca_poller.c b/lib/nfc/protocols/nfca/nfca_poller.c index 963e34996388..3271a14c6b3a 100644 --- a/lib/nfc/protocols/nfca/nfca_poller.c +++ b/lib/nfc/protocols/nfca/nfca_poller.c @@ -16,7 +16,6 @@ NfcaPoller* nfca_poller_alloc(Nfc* nfc) { furi_assert(nfc); NfcaPoller* instance = malloc(sizeof(NfcaPoller)); - instance->data = malloc(sizeof(NfcaData)); instance->nfc = nfc; return instance; @@ -26,7 +25,6 @@ void nfca_poller_free(NfcaPoller* instance) { furi_assert(instance); furi_assert(instance->nfc); - free(instance->data); free(instance); } @@ -100,6 +98,8 @@ NfcaError instance->callback = callback; instance->context = context; + instance->data = malloc(sizeof(NfcaData)); + instance->session_state = NfcaPollerSessionStateActive; nfc_start_poller(instance->nfc, nfca_poller_event_callback, instance); @@ -127,6 +127,8 @@ NfcaError nfca_poller_stop(NfcaPoller* instance) { // Check that data is freed furi_assert(instance->buff != NULL); + free(instance->data); + return NfcaErrorNone; } @@ -138,7 +140,7 @@ static NfcaPollerCommand nfca_poller_sync_callback(NfcaPollerEvent event, void* return NfcaPollerCommandStop; } -NfcaError nfca_poller_activate(NfcaPoller* instance, NfcaData* nfca_data) { +NfcaError nfca_poller_read(NfcaPoller* instance, NfcaData* nfca_data) { furi_assert(instance); NfcaPollerContext context = {}; @@ -147,10 +149,10 @@ NfcaError nfca_poller_activate(NfcaPoller* instance, NfcaData* nfca_data) { nfca_poller_start(instance, nfca_poller_sync_callback, &context); furi_thread_flags_wait(NFCA_POLLER_FLAG_COMMAND_COMPLETE, FuriFlagWaitAny, FuriWaitForever); furi_thread_flags_clear(NFCA_POLLER_FLAG_COMMAND_COMPLETE); - nfc_stop(instance->nfc); if(context.error == NfcaErrorNone) { *nfca_data = *instance->data; } + nfc_stop(instance->nfc); return context.error; } diff --git a/lib/nfc/protocols/nfca/nfca_poller.h b/lib/nfc/protocols/nfca/nfca_poller.h index 82195a616d95..25931fac9c44 100644 --- a/lib/nfc/protocols/nfca/nfca_poller.h +++ b/lib/nfc/protocols/nfca/nfca_poller.h @@ -42,7 +42,7 @@ NfcaError nfca_poller_stop(NfcaPoller* instance); NfcaError nfca_poller_get_data(NfcaPoller* instance, NfcaData* data); // Sync call -NfcaError nfca_poller_activate(NfcaPoller* instance, NfcaData* nfca_data); +NfcaError nfca_poller_read(NfcaPoller* instance, NfcaData* nfca_data); #ifdef __cplusplus } diff --git a/lib/nfc/protocols/nfca/nfca_poller_i.c b/lib/nfc/protocols/nfca/nfca_poller_i.c index 5e20a63220df..39ed01bc64b9 100644 --- a/lib/nfc/protocols/nfca/nfca_poller_i.c +++ b/lib/nfc/protocols/nfca/nfca_poller_i.c @@ -112,7 +112,7 @@ NfcaError nfca_poller_reset(NfcaPoller* instance) { instance->context = NULL; memset(&instance->col_res, 0, sizeof(NfcaPollerColRes)); instance->state = NfcaPollerStateIdle; - free(instance->buff); + nfc_poller_buffer_free(instance->buff); instance->buff = NULL; return NfcaErrorNone; From 5137100e5dc8bcd958ee3f256710f60da07e3e0b Mon Sep 17 00:00:00 2001 From: gornekich Date: Mon, 8 May 2023 15:16:14 +0400 Subject: [PATCH 064/149] nfc: add test for original ultralight --- applications/debug/unit_tests/nfc/nfc_test.c | 15 +++-- .../mf_ultralight/mf_ultralight_poller.c | 34 +++++----- .../mf_ultralight/mf_ultralight_poller.h | 4 ++ .../mf_ultralight/mf_ultralight_poller_i.h | 2 + .../mf_ultralight_poller_sync_api.c | 64 +++++++++++++++++-- 5 files changed, 92 insertions(+), 27 deletions(-) diff --git a/applications/debug/unit_tests/nfc/nfc_test.c b/applications/debug/unit_tests/nfc/nfc_test.c index 958f47478293..697fe77a98c1 100644 --- a/applications/debug/unit_tests/nfc/nfc_test.c +++ b/applications/debug/unit_tests/nfc/nfc_test.c @@ -195,20 +195,23 @@ MU_TEST(mf_ultralight_reader) { MfUltralightError error = MfUltralightErrorNone; NfcDevData* dev_data = malloc(sizeof(NfcDevData)); - nfc_data_generator_fill_data(NfcDataGeneratorTypeNTAG216, dev_data); + nfc_data_generator_fill_data(NfcDataGeneratorTypeMfUltralight, dev_data); error = mf_ultralight_listener_start(mfu_listener, &dev_data->mf_ul_data, NULL, NULL); mu_assert(error == MfUltralightErrorNone, "mf_ultralight_listener_start() failed"); - MfUltralightPage page = {}; - for(size_t i = 0; i < dev_data->mf_ul_data.pages_total; i++) { - error = mf_ultralight_poller_read_page(mfu_poller, i, &page); - mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_read_page() failed"); - } + MfUltralightData* mfu_data = malloc(sizeof(MfUltralightData)); + error = mf_ultralight_poller_read_card(mfu_poller, mfu_data); + mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_read_card() failed"); error = mf_ultralight_listener_stop(mfu_listener); mu_assert(error == MfUltralightErrorNone, "mf_ultralight_listener_stop() failed"); + mu_assert( + memcmp(mfu_data, &dev_data->mf_ul_data, sizeof(MfUltralightData)) == 0, + "Data not matches"); + + free(mfu_data); free(dev_data); mf_ultralight_listener_free(mfu_listener); mf_ultralight_poller_free(mfu_poller); diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c index 12faaaa43667..10a423a9e3e6 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c @@ -52,9 +52,8 @@ static MfUltralightPollerCommand mf_ultralight_poller_handler_idle(MfUltralightP static MfUltralightPollerCommand mf_ultralight_poller_handler_read_version(MfUltralightPoller* instance) { - MfUltralightError error = - mf_ultralight_poller_async_read_version(instance, &instance->data->version); - if(error == MfUltralightErrorNone) { + instance->error = mf_ultralight_poller_async_read_version(instance, &instance->data->version); + if(instance->error == MfUltralightErrorNone) { FURI_LOG_I(TAG, "Read version success"); instance->data->type = mf_ultralight_get_type_by_version(&instance->data->version); instance->state = MfUltralightPollerStateGetFeatureSet; @@ -70,8 +69,8 @@ static MfUltralightPollerCommand static MfUltralightPollerCommand mf_ultralight_poller_handler_check_ntag_203(MfUltralightPoller* instance) { MfUltralightPageReadCommandData data = {}; - MfUltralightError error = mf_ultralight_poller_async_read_page(instance, 41, &data); - if(error == MfUltralightErrorNone) { + instance->error = mf_ultralight_poller_async_read_page(instance, 41, &data); + if(instance->error == MfUltralightErrorNone) { FURI_LOG_I(TAG, "NTAG203 detected"); instance->data->type = MfUltralightTypeNTAG203; } else { @@ -106,9 +105,9 @@ static MfUltralightPollerCommand MfUltralightPollerState next_state = MfUltralightPollerStateAuth; if(instance->feature_set & MfUltralightFeatureSupportReadSignature) { FURI_LOG_D(TAG, "Reading signature"); - MfUltralightError error = + instance->error = mf_ultralight_poller_async_read_signature(instance, &instance->data->signature); - if(error != MfUltralightErrorNone) { + if(instance->error != MfUltralightErrorNone) { FURI_LOG_E(TAG, "Read signature failed"); next_state = MfUltralightPollerStateReadFailed; } @@ -131,11 +130,11 @@ static MfUltralightPollerCommand instance->state = MfUltralightPollerStateReadTearingFlags; } else { FURI_LOG_D(TAG, "Reading counter %d", instance->counters_read); - MfUltralightError error = mf_ultralight_poller_async_read_counter( + instance->error = mf_ultralight_poller_async_read_counter( instance, instance->counters_read, &instance->data->counter[instance->counters_read]); - if(error != MfUltralightErrorNone) { + if(instance->error != MfUltralightErrorNone) { FURI_LOG_E(TAG, "Failed to read %d counter", instance->counters_read); instance->state = MfUltralightPollerStateReadFailed; } else { @@ -160,11 +159,11 @@ static MfUltralightPollerCommand instance->state = MfUltralightPollerStateTryDefaultPass; } else { FURI_LOG_D(TAG, "Reading tearing flag %d", instance->tearing_flag_read); - MfUltralightError error = mf_ultralight_poller_async_read_tearing_flag( + instance->error = mf_ultralight_poller_async_read_tearing_flag( instance, instance->tearing_flag_read, &instance->data->tearing_flag[instance->tearing_flag_read]); - if(error != MfUltralightErrorNone) { + if(instance->error != MfUltralightErrorNone) { FURI_LOG_E(TAG, "Reading tearing flag %d failed", instance->tearing_flag_read); instance->state = MfUltralightPollerStateReadFailed; } else { @@ -192,9 +191,8 @@ static MfUltralightPollerCommand mf_ultralight_poller_handler_auth(MfUltralightP instance->auth_password = event.data->auth_context.password; FURI_LOG_D( TAG, "Trying to authenticate with password %08lX", instance->auth_password.pass); - MfUltralightError error = - mf_ultralight_poller_async_auth(instance, &instance->auth_password); - if(error == MfUltralightErrorNone) { + instance->error = mf_ultralight_poller_async_auth(instance, &instance->auth_password); + if(instance->error == MfUltralightErrorNone) { FURI_LOG_D(TAG, "Auth success"); // TODO fill PACK in event MfUltralightPollerEventData data = {.pack.pack = 0x8080}; @@ -219,8 +217,8 @@ static MfUltralightPollerCommand mf_ultralight_poller_handler_read_pages(MfUltralightPoller* instance) { MfUltralightPageReadCommandData data = {}; uint8_t start_page = instance->pages_read; - MfUltralightError error = mf_ultralight_poller_async_read_page(instance, start_page, &data); - if(error == MfUltralightErrorNone) { + instance->error = mf_ultralight_poller_async_read_page(instance, start_page, &data); + if(instance->error == MfUltralightErrorNone) { for(size_t i = 0; i < 4; i++) { if(start_page + i < instance->pages_total) { FURI_LOG_I(TAG, "Read page %d success", start_page + i); @@ -253,7 +251,9 @@ static MfUltralightPollerCommand static MfUltralightPollerCommand mf_ultralight_poller_handler_read_fail(MfUltralightPoller* instance) { FURI_LOG_W(TAG, "Read Failed"); - MfUltralightPollerEvent event = {.type = MfUltralightPollerEventTypeReadFailed}; + MfUltralightPollerEventData event_data = {.error = instance->error}; + MfUltralightPollerEvent event = { + .type = MfUltralightPollerEventTypeReadFailed, .data = &event_data}; MfUltralightPollerCommand command = instance->callback(event, instance->context); instance->state = MfUltralightPollerStateIdle; return command; diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h index 14e11fdca801..c72fddab737a 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h @@ -26,6 +26,7 @@ typedef struct { union { MfUltralightPollerAuthContext auth_context; MfUltralightAuthPack pack; + MfUltralightError error; }; } MfUltralightPollerEventData; @@ -94,6 +95,9 @@ MfUltralightError mf_ultralight_poller_read_tearing_flag( uint8_t flag_num, MfUltralightTearingFlag* data); +MfUltralightError + mf_ultralight_poller_read_card(MfUltralightPoller* instance, MfUltralightData* data); + #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h index d60433ac27fe..75af6b077870 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h @@ -34,6 +34,7 @@ typedef union { MfUltralightSignature signature; MfUltralightPollerReadCounterCommand counter_cmd; MfUltralightPollerReadTearingFlagCommand tearing_flag_cmd; + MfUltralightData data; } MfUltralightPollerContextData; typedef enum { @@ -74,6 +75,7 @@ struct MfUltralightPoller { uint8_t counters_total; uint8_t tearing_flag_read; uint8_t tearing_flag_total; + MfUltralightError error; void* context; }; diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c index ad9fe82e8b38..1799e9b36b5b 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c @@ -43,6 +43,7 @@ MfUltralightError mf_ultralight_poller_read_page( mf_ultralight_poller_start(instance, mf_ultraight_read_page_callback, &poller_context); furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); + if(poller_context.error == MfUltralightErrorNone) { *data = poller_context.data.read_cmd.data.page[0]; } @@ -115,7 +116,10 @@ MfUltralightError mf_ultralight_poller_start(instance, mf_ultraight_read_version_callback, &poller_context); furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); - *data = poller_context.data.version; + + if(poller_context.error == MfUltralightErrorNone) { + *data = poller_context.data.version; + } mf_ultralight_poller_stop(instance); return poller_context.error; @@ -149,7 +153,10 @@ MfUltralightError mf_ultralight_poller_start(instance, mf_ultraight_read_signature_callback, &poller_context); furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); - *data = poller_context.data.signature; + + if(poller_context.error == MfUltralightErrorNone) { + *data = poller_context.data.signature; + } mf_ultralight_poller_stop(instance); return poller_context.error; @@ -187,7 +194,10 @@ MfUltralightError mf_ultralight_poller_read_counter( mf_ultralight_poller_start(instance, mf_ultraight_read_counter_callback, &poller_context); furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); - *data = poller_context.data.counter_cmd.data; + + if(poller_context.error == MfUltralightErrorNone) { + *data = poller_context.data.counter_cmd.data; + } mf_ultralight_poller_stop(instance); return poller_context.error; @@ -226,7 +236,53 @@ MfUltralightError mf_ultralight_poller_read_tearing_flag( mf_ultralight_poller_start(instance, mf_ultraight_read_tering_flag_callback, &poller_context); furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); - *data = poller_context.data.tearing_flag_cmd.data; + + if(poller_context.error == MfUltralightErrorNone) { + *data = poller_context.data.tearing_flag_cmd.data; + } + mf_ultralight_poller_stop(instance); + + return poller_context.error; +} + +static MfUltralightPollerCommand + mf_ultralight_poller_read_callback(MfUltralightPollerEvent event, void* context) { + furi_assert(context); + + MfUltralightPollerContext* poller_context = context; + MfUltralightPollerCommand command = MfUltralightPollerCommandContinue; + + if(event.type == MfUltralightPollerEventTypeReadSuccess) { + mf_ultralight_poller_get_data(poller_context->instance, &poller_context->data.data); + poller_context->error = MfUltralightErrorNone; + command = MfUltralightPollerCommandStop; + } else if(event.type == MfUltralightPollerEventTypeReadFailed) { + poller_context->error = event.data->error; + command = MfUltralightPollerCommandStop; + } + + if(command == MfUltralightPollerCommandStop) { + furi_thread_flags_set(poller_context->thread_id, MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); + } + + return command; +} + +MfUltralightError + mf_ultralight_poller_read_card(MfUltralightPoller* instance, MfUltralightData* data) { + furi_assert(instance); + furi_assert(data); + + MfUltralightPollerContext poller_context = {}; + poller_context.instance = instance; + poller_context.thread_id = furi_thread_get_current_id(); + + mf_ultralight_poller_read(instance, mf_ultralight_poller_read_callback, &poller_context); + furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); + + if(poller_context.error == MfUltralightErrorNone) { + *data = poller_context.data.data; + } mf_ultralight_poller_stop(instance); return poller_context.error; From 779ab87c1af4f4b7bdd93a42113c59a5cccba279 Mon Sep 17 00:00:00 2001 From: gornekich Date: Mon, 8 May 2023 17:50:29 +0400 Subject: [PATCH 065/149] unit tests: add nfc test files --- assets/unit_tests/nfc/Ntag213_locked.nfc | 66 ++++++++++++++++++++++++ assets/unit_tests/nfc/Ultralight_11.nfc | 41 +++++++++++++++ assets/unit_tests/nfc/Ultralight_21.nfc | 62 ++++++++++++++++++++++ 3 files changed, 169 insertions(+) create mode 100644 assets/unit_tests/nfc/Ntag213_locked.nfc create mode 100644 assets/unit_tests/nfc/Ultralight_11.nfc create mode 100644 assets/unit_tests/nfc/Ultralight_21.nfc diff --git a/assets/unit_tests/nfc/Ntag213_locked.nfc b/assets/unit_tests/nfc/Ntag213_locked.nfc new file mode 100644 index 000000000000..32f7771165f6 --- /dev/null +++ b/assets/unit_tests/nfc/Ntag213_locked.nfc @@ -0,0 +1,66 @@ +Filetype: Flipper NFC device +Version: 3 +# Nfc device type can be UID, Mifare Ultralight, Mifare Classic +Device type: NTAG213 +# UID, ATQA and SAK are common for all formats +UID: 04 AC 6B 72 BA 6C 80 +ATQA: 00 44 +SAK: 00 +# Mifare Ultralight specific data +Data format version: 1 +Signature: 2D AE BC AF 84 B8 85 87 C2 FB FE 76 13 58 86 72 8E 1D 3C B5 DA 24 23 44 E5 63 4D 4C 82 FB D7 18 +Mifare version: 00 04 04 02 01 00 0F 03 +Counter 0: 0 +Tearing 0: 00 +Counter 1: 0 +Tearing 1: 00 +Counter 2: 0 +Tearing 2: 00 +Pages total: 45 +Pages read: 45 +Page 0: 04 AC 6B 4B +Page 1: 72 BA 6C 80 +Page 2: 24 48 00 00 +Page 3: E1 10 12 00 +Page 4: 00 00 41 50 +Page 5: 00 00 31 31 +Page 6: 00 20 09 28 +Page 7: 00 03 31 59 +Page 8: 91 DF D3 00 +Page 9: 00 00 00 00 +Page 10: 00 00 00 00 +Page 11: 00 00 00 00 +Page 12: 00 00 00 00 +Page 13: 00 00 00 00 +Page 14: 00 00 00 00 +Page 15: 00 00 00 00 +Page 16: 00 00 00 00 +Page 17: 00 00 00 00 +Page 18: 00 00 00 00 +Page 19: 00 00 00 00 +Page 20: 00 00 00 00 +Page 21: 00 00 00 00 +Page 22: 00 00 00 00 +Page 23: 00 00 00 00 +Page 24: 00 00 00 00 +Page 25: 00 00 00 00 +Page 26: 00 00 00 00 +Page 27: 00 00 00 00 +Page 28: 00 00 00 00 +Page 29: 00 00 00 00 +Page 30: 00 00 00 00 +Page 31: 00 00 00 00 +Page 32: 00 00 00 00 +Page 33: 00 00 00 00 +Page 34: 00 00 00 00 +Page 35: 00 00 00 00 +Page 36: 00 00 00 00 +Page 37: 00 00 00 00 +Page 38: 00 00 00 00 +Page 39: 00 00 00 00 +Page 40: 00 00 00 BD +Page 41: 04 00 00 04 +Page 42: C0 05 00 00 +Page 43: 95 3F 52 FF +Page 44: 00 00 00 00 +Failed authentication attempts: 0 diff --git a/assets/unit_tests/nfc/Ultralight_11.nfc b/assets/unit_tests/nfc/Ultralight_11.nfc new file mode 100644 index 000000000000..22441289dd08 --- /dev/null +++ b/assets/unit_tests/nfc/Ultralight_11.nfc @@ -0,0 +1,41 @@ +Filetype: Flipper NFC device +Version: 3 +# Nfc device type can be UID, Mifare Ultralight, Mifare Classic +Device type: Mifare Ultralight 11 +# UID, ATQA and SAK are common for all formats +UID: 04 15 74 F2 B0 5E 81 +ATQA: 00 44 +SAK: 00 +# Mifare Ultralight specific data +Data format version: 1 +Signature: A4 37 7D E5 8C 2F 88 D8 04 60 41 6E 3A C8 CD DB 19 94 26 12 C5 D0 12 B0 EB 88 05 72 89 F2 A5 61 +Mifare version: 00 04 03 01 01 00 0B 03 +Counter 0: 0 +Tearing 0: BD +Counter 1: 0 +Tearing 1: BD +Counter 2: 0 +Tearing 2: BD +Pages total: 20 +Pages read: 20 +Page 0: 04 15 74 ED +Page 1: F2 B0 5E 81 +Page 2: 9D 48 F8 FF +Page 3: C1 31 3E 3F +Page 4: B0 00 F0 02 +Page 5: 2F B3 45 A0 +Page 6: D4 9C 02 F2 +Page 7: 4A B1 ED FF +Page 8: C8 01 00 02 +Page 9: 4F B3 46 70 +Page 10: EE F6 60 B0 +Page 11: B6 C6 12 1B +Page 12: B9 1E 49 C3 +Page 13: 49 DF 7A 57 +Page 14: 08 52 2A 11 +Page 15: 28 0A 28 59 +Page 16: 00 00 00 FF +Page 17: 00 05 00 00 +Page 18: FF FF FF FF +Page 19: 00 00 00 00 +Failed authentication attempts: 0 diff --git a/assets/unit_tests/nfc/Ultralight_21.nfc b/assets/unit_tests/nfc/Ultralight_21.nfc new file mode 100644 index 000000000000..dc01e93a6027 --- /dev/null +++ b/assets/unit_tests/nfc/Ultralight_21.nfc @@ -0,0 +1,62 @@ +Filetype: Flipper NFC device +Version: 3 +# Nfc device type can be UID, Mifare Ultralight, Mifare Classic +Device type: Mifare Ultralight 21 +# UID, ATQA and SAK are common for all formats +UID: 34 BF AB B1 AE 73 D6 +ATQA: 00 44 +SAK: 00 +# Mifare Ultralight specific data +Data format version: 1 +Signature: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Mifare version: 00 34 21 01 01 00 0E 03 +Counter 0: 0 +Tearing 0: 00 +Counter 1: 0 +Tearing 1: 00 +Counter 2: 0 +Tearing 2: 00 +Pages total: 41 +Pages read: 41 +Page 0: 34 BF AB A8 +Page 1: B1 AE 73 D6 +Page 2: BA 00 70 08 +Page 3: FF FF FF FC +Page 4: 45 D9 BB A0 +Page 5: 5D 9D FA 00 +Page 6: 80 70 38 40 +Page 7: 12 30 02 00 +Page 8: 00 00 00 00 +Page 9: 00 00 00 00 +Page 10: AC A1 0D E4 +Page 11: 80 70 38 40 +Page 12: 00 57 A0 01 +Page 13: 00 08 C1 40 +Page 14: 00 00 00 00 +Page 15: AC A1 0D E4 +Page 16: 00 00 00 00 +Page 17: 00 00 00 00 +Page 18: 00 00 00 00 +Page 19: 00 00 00 00 +Page 20: 00 00 00 00 +Page 21: 00 00 00 00 +Page 22: 00 00 00 00 +Page 23: 00 00 00 00 +Page 24: 00 00 00 00 +Page 25: 00 00 00 00 +Page 26: 00 00 00 00 +Page 27: 00 00 00 00 +Page 28: 00 00 00 00 +Page 29: 00 00 00 00 +Page 30: 00 00 00 00 +Page 31: 00 00 00 00 +Page 32: 00 00 00 00 +Page 33: 00 00 00 00 +Page 34: 00 00 00 00 +Page 35: 00 00 00 00 +Page 36: 00 00 00 BD +Page 37: 00 00 00 FF +Page 38: 00 05 00 00 +Page 39: FF FF FF FF +Page 40: 00 00 00 00 +Failed authentication attempts: 0 From d9c1faac68436700e39ddc601e6613d8ad031358 Mon Sep 17 00:00:00 2001 From: gornekich Date: Mon, 8 May 2023 19:46:04 +0400 Subject: [PATCH 066/149] mf ultralight fixes --- .../nfc/scenes/nfc_scene_mf_ultralight_read.c | 2 +- lib/nfc/nfc_poller.c | 6 +- .../protocols/mf_ultralight/mf_ultralight.c | 67 ++++++++++++++++++- .../protocols/mf_ultralight/mf_ultralight.h | 2 + .../mf_ultralight/mf_ultralight_poller.c | 20 +++--- .../mf_ultralight/mf_ultralight_poller.h | 5 +- .../mf_ultralight/mf_ultralight_poller_i.c | 19 ++---- .../mf_ultralight/mf_ultralight_poller_i.h | 7 +- 8 files changed, 96 insertions(+), 32 deletions(-) diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read.c index 9e4abed520dd..8520d8c9b950 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read.c @@ -37,7 +37,7 @@ MfUltralightPollerCommand event.data->auth_context.password = nfc->mf_ul_auth->password; } } else if(event.type == MfUltralightPollerEventTypeAuthSuccess) { - nfc->mf_ul_auth->pack = event.data->pack; + nfc->mf_ul_auth->pack = event.data->auth_context.pack; } return command; diff --git a/lib/nfc/nfc_poller.c b/lib/nfc/nfc_poller.c index 655554fb2ba0..e5d62586da79 100644 --- a/lib/nfc/nfc_poller.c +++ b/lib/nfc/nfc_poller.c @@ -112,7 +112,7 @@ static NfcCommand nfc_poller_event_callback(NfcEvent event, void* context) { // } else { // // Nfcb not present // furi_delay_ms(100); - instance->state = NfcPollerStateCheckPresenceNfca; + instance->state = NfcPollerStateCheckPresenceNfca; // command = NfcCommandReset; // } } @@ -138,6 +138,8 @@ void nfc_poller_start(NfcPoller* instance, NfcPollerEventCallback callback, void instance->state = NfcPollerStateCheckPresenceNfca; instance->session_state = NfcPollerSessionStateActive; + instance->nfca_poller->data = malloc(sizeof(NfcaData)); + nfc_start_poller(instance->nfc, nfc_poller_event_callback, instance); } @@ -149,6 +151,8 @@ void nfc_poller_stop(NfcPoller* instance) { nfc_stop(instance->nfc); instance->session_state = NfcPollerSessionStateIdle; + free(instance->nfca_poller->data); + instance->callback = NULL; instance->context = NULL; instance->state = NfcPollerStateIdle; diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight.c index ebab42f12305..22639c539d9c 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight.c @@ -140,14 +140,75 @@ bool mf_ultralight_detect_protocol(NfcaData* nfca_data) { return mfu_detected; } +bool mf_ultralight_get_config_page(MfUltralightData* data, MfUltralightConfigPages* config) { + furi_assert(data); + furi_assert(config); + + bool config_pages_found = false; + switch(data->type) { + case MfUltralightTypeUL11: + case MfUltralightTypeUL21: + case MfUltralightTypeNTAG213: + case MfUltralightTypeNTAG215: + case MfUltralightTypeNTAG216: + config = (MfUltralightConfigPages*)&data->page[data->pages_total - 4]; + config_pages_found = true; + break; + + case MfUltralightTypeNTAGI2CPlus1K: + case MfUltralightTypeNTAGI2CPlus2K: + config = (MfUltralightConfigPages*)&data->page[227]; + config_pages_found = true; + break; + + default: + break; + } + + return config_pages_found; +} + bool mf_ultralight_is_all_data_read(MfUltralightData* data) { furi_assert(data); - // TODO add logic - return false; + + bool all_read = false; + if(data->pages_read == data->pages_total) { + // Having read all the pages doesn't mean that we've got everything. + // By default PWD is 0xFFFFFFFF, but if read back it is always 0x00000000, + // so a default read on an auth-supported NTAG is never complete. + uint32_t feature_set = mf_ultralight_get_feature_support_set(data->type); + if(feature_set & MfUltralightFeatureSupportAuthentication) { + all_read = true; + } else { + MfUltralightConfigPages* config = NULL; + if(mf_ultralight_get_config_page(data, config)) { + all_read = ((config->password.pass != 0) || (config->pack.pack != 0)); + } + } + } + + return all_read; } bool mf_ultralight_is_counter_configured(MfUltralightData* data) { furi_assert(data); - return false; + MfUltralightConfigPages* config = NULL; + bool configured = false; + + switch(data->type) { + case MfUltralightTypeNTAG213: + case MfUltralightTypeNTAG215: + case MfUltralightTypeNTAG216: + configured = true; + break; + + default: + if(mf_ultralight_get_config_page(data, config)) { + configured = config->access.nfc_cnt_en; + } + break; + } + + return configured; } diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h index b7ab521d77e3..a4497adae3aa 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h @@ -172,6 +172,8 @@ uint32_t mf_ultralight_get_feature_support_set(MfUltralightType type); const char* mf_ultralight_get_name(MfUltralightType type, bool full_name); +bool mf_ultralight_get_config_page(MfUltralightData* data, MfUltralightConfigPages* config); + bool mf_ultralight_is_all_data_read(MfUltralightData* data); bool mf_ultralight_detect_protocol(NfcaData* nfca_data); diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c index 10a423a9e3e6..d00259e0154f 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c @@ -136,7 +136,7 @@ static MfUltralightPollerCommand &instance->data->counter[instance->counters_read]); if(instance->error != MfUltralightErrorNone) { FURI_LOG_E(TAG, "Failed to read %d counter", instance->counters_read); - instance->state = MfUltralightPollerStateReadFailed; + instance->state = MfUltralightPollerStateReadTearingFlags; } else { instance->counters_read++; } @@ -171,6 +171,7 @@ static MfUltralightPollerCommand } } } else { + FURI_LOG_D(TAG, "Skip reading tearing flags"); instance->state = MfUltralightPollerStateTryDefaultPass; } @@ -188,22 +189,23 @@ static MfUltralightPollerCommand mf_ultralight_poller_handler_auth(MfUltralightP command = instance->callback(event, instance->context); if(!event.data->auth_context.skip_auth) { - instance->auth_password = event.data->auth_context.password; + instance->auth_context.password = event.data->auth_context.password; FURI_LOG_D( - TAG, "Trying to authenticate with password %08lX", instance->auth_password.pass); - instance->error = mf_ultralight_poller_async_auth(instance, &instance->auth_password); + TAG, + "Trying to authenticate with password %08lX", + instance->auth_context.password.pass); + instance->error = mf_ultralight_poller_async_auth(instance, &instance->auth_context); if(instance->error == MfUltralightErrorNone) { FURI_LOG_D(TAG, "Auth success"); - // TODO fill PACK in event - MfUltralightPollerEventData data = {.pack.pack = 0x8080}; - MfUltralightPollerEvent event = { - .type = MfUltralightPollerEventTypeAuthSuccess, .data = &data}; + instance->auth_context.auth_success = true; + event.data->auth_context = instance->auth_context; + event.type = MfUltralightPollerEventTypeAuthSuccess; command = instance->callback(event, instance->context); } else { FURI_LOG_W(TAG, "Auth failed"); + instance->auth_context.auth_success = false; MfUltralightPollerEvent event = {.type = MfUltralightPollerEventTypeAuthFailed}; command = instance->callback(event, instance->context); - // TODO rework with HALT cmd nfca_poller_halt(instance->nfca_poller); } } diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h index c72fddab737a..f2fc21378e35 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h @@ -18,14 +18,15 @@ typedef enum { } MfUltralightPollerEventType; typedef struct { - bool skip_auth; MfUltralightAuthPassword password; + MfUltralightAuthPack pack; + bool auth_success; + bool skip_auth; } MfUltralightPollerAuthContext; typedef struct { union { MfUltralightPollerAuthContext auth_context; - MfUltralightAuthPack pack; MfUltralightError error; }; } MfUltralightPollerEventData; diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c index 809af0bc5fb5..fd6559d1894e 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c @@ -30,12 +30,13 @@ MfUltralightError mf_ultralight_process_error(NfcaError error) { return ret; } -MfUltralightError - mf_ultralight_poller_async_auth(MfUltralightPoller* instance, MfUltralightAuthPassword* data) { +MfUltralightError mf_ultralight_poller_async_auth( + MfUltralightPoller* instance, + MfUltralightPollerAuthContext* data) { NfcPollerBuffer* buff = instance->buffer; buff->tx_data[0] = MF_ULTRALIGHT_CMD_AUTH; // fill password in lsb - nfc_util_num2bytes(data->pass, MF_ULTRALIGHT_AUTH_PASSWORD_SIZE, &buff->tx_data[1]); + nfc_util_num2bytes(data->password.pass, MF_ULTRALIGHT_AUTH_PASSWORD_SIZE, &buff->tx_data[1]); buff->tx_bits = (MF_ULTRALIGHT_AUTH_PASSWORD_SIZE + 1) * 8; MfUltralightError ret = MfUltralightErrorNone; @@ -57,16 +58,8 @@ MfUltralightError ret = MfUltralightErrorAuth; break; } - if(instance->pages_total != 0) { - memcpy( - &instance->data->page[instance->pages_total - 2], - data, - MF_ULTRALIGHT_AUTH_PASSWORD_SIZE); - memcpy( - &instance->data->page[instance->pages_total - 1], - buff->rx_data, - MF_ULTRALIGHT_AUTH_PACK_SIZE); - } + data->pack.data[0] = buff->rx_data[0]; + data->pack.data[1] = buff->rx_data[1]; } while(false); return ret; diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h index 75af6b077870..e25316e6e25f 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h @@ -67,7 +67,7 @@ struct MfUltralightPoller { NfcPollerBuffer* buffer; MfUltralightData* data; MfUltralightPollerCallback callback; - MfUltralightAuthPassword auth_password; + MfUltralightPollerAuthContext auth_context; uint32_t feature_set; uint16_t pages_read; uint16_t pages_total; @@ -81,8 +81,9 @@ struct MfUltralightPoller { MfUltralightError mf_ultralight_process_error(NfcaError error); -MfUltralightError - mf_ultralight_poller_async_auth(MfUltralightPoller* instance, MfUltralightAuthPassword* data); +MfUltralightError mf_ultralight_poller_async_auth( + MfUltralightPoller* instance, + MfUltralightPollerAuthContext* data); MfUltralightError mf_ultralight_poller_async_read_page( MfUltralightPoller* instance, From 74e3a285cced499a2e3d88c4fa8f1be1f3946fa2 Mon Sep 17 00:00:00 2001 From: gornekich Date: Thu, 11 May 2023 13:52:49 +0400 Subject: [PATCH 067/149] nfc app: rework unlock with reader ultralight --- .../main/nfc/scenes/nfc_scene_config.h | 2 +- .../nfc_scene_mf_ultralight_capture_pass.c | 65 +++++++++++++++++++ .../nfc_scene_mf_ultralight_unlock_menu.c | 2 +- 3 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 applications/main/nfc/scenes/nfc_scene_mf_ultralight_capture_pass.c diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index ce71f2cf8f33..e2b0042b09dd 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -19,7 +19,7 @@ ADD_SCENE(nfc, mf_ultralight_menu, MfUltralightMenu) ADD_SCENE(nfc, mf_ultralight_unlock_menu, MfUltralightUnlockMenu) ADD_SCENE(nfc, mf_ultralight_unlock_warn, MfUltralightUnlockWarn) ADD_SCENE(nfc, mf_ultralight_key_input, MfUltralightKeyInput) - +ADD_SCENE(nfc, mf_ultralight_capture_pass, MfUltralightCapturePass) ADD_SCENE(nfc, set_type, SetType) ADD_SCENE(nfc, set_sak, SetSak) diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_capture_pass.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_capture_pass.c new file mode 100644 index 000000000000..3c594a4e17f6 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_capture_pass.c @@ -0,0 +1,65 @@ +#include "../nfc_app_i.h" + +MfUltralightListenerCommand nfc_scene_mf_ultralight_capture_pass_worker_callback( + MfUltralightListenerEvent event, + void* context) { + NfcApp* nfc = context; + + if(event.type == MfUltralightListenerEventTypeAuth) { + nfc->mf_ul_auth->password = event.data->password; + view_dispatcher_send_custom_event(nfc->view_dispatcher, MfUltralightListenerEventTypeAuth); + } + + return MfUltralightListenerCommandContinue; +} + +void nfc_scene_mf_ultralight_capture_pass_on_enter(void* context) { + NfcApp* nfc = context; + + // Setup view + widget_add_string_multiline_element( + nfc->widget, + 54, + 30, + AlignLeft, + AlignCenter, + FontPrimary, + "Touch the\nreader to get\npassword..."); + widget_add_icon_element(nfc->widget, 0, 15, &I_Modern_reader_18x34); + widget_add_icon_element(nfc->widget, 20, 12, &I_Move_flipper_26x39); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); + + // Start worker + mf_ultralight_listener_start( + nfc->mf_ul_listener, + &nfc->nfc_dev_data.mf_ul_data, + nfc_scene_mf_ultralight_capture_pass_worker_callback, + nfc); + + nfc_blink_read_start(nfc); +} + +bool nfc_scene_mf_ultralight_capture_pass_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if((event.event == MfUltralightListenerEventTypeAuth)) { + notification_message(nfc->notifications, &sequence_success); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockWarn); + consumed = true; + } + } + return consumed; +} + +void nfc_scene_mf_ultralight_capture_pass_on_exit(void* context) { + NfcApp* nfc = context; + + // Stop worker + mf_ultralight_listener_stop(nfc->mf_ul_listener); + // Clear view + widget_reset(nfc->widget); + + nfc_blink_stop(nfc); +} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_menu.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_menu.c index db4b9d156460..db3a3dc718d7 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_menu.c @@ -68,7 +68,7 @@ bool nfc_scene_mf_ultralight_unlock_menu_on_event(void* context, SceneManagerEve consumed = true; } else if(event.event == SubmenuIndexMfUlUnlockMenuReader) { nfc->mf_ul_auth->type = MfUltralightAuthTypeReader; - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightCapturePass); consumed = true; } scene_manager_set_scene_state( From 53235845a1413029a7cd5f48d0c93f9aca8cef65 Mon Sep 17 00:00:00 2001 From: gornekich Date: Mon, 8 May 2023 21:35:31 +0400 Subject: [PATCH 068/149] mf ultralight: default password support --- .../protocols/mf_ultralight/mf_ultralight.c | 10 +++---- .../protocols/mf_ultralight/mf_ultralight.h | 2 +- .../mf_ultralight/mf_ultralight_poller.c | 27 +++++++++++++++++++ 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight.c index 22639c539d9c..47f846b3dacd 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight.c @@ -140,7 +140,7 @@ bool mf_ultralight_detect_protocol(NfcaData* nfca_data) { return mfu_detected; } -bool mf_ultralight_get_config_page(MfUltralightData* data, MfUltralightConfigPages* config) { +bool mf_ultralight_get_config_page(MfUltralightData* data, MfUltralightConfigPages** config) { furi_assert(data); furi_assert(config); @@ -151,13 +151,13 @@ bool mf_ultralight_get_config_page(MfUltralightData* data, MfUltralightConfigPag case MfUltralightTypeNTAG213: case MfUltralightTypeNTAG215: case MfUltralightTypeNTAG216: - config = (MfUltralightConfigPages*)&data->page[data->pages_total - 4]; + *config = (MfUltralightConfigPages*)&data->page[data->pages_total - 4]; config_pages_found = true; break; case MfUltralightTypeNTAGI2CPlus1K: case MfUltralightTypeNTAGI2CPlus2K: - config = (MfUltralightConfigPages*)&data->page[227]; + *config = (MfUltralightConfigPages*)&data->page[227]; config_pages_found = true; break; @@ -181,7 +181,7 @@ bool mf_ultralight_is_all_data_read(MfUltralightData* data) { all_read = true; } else { MfUltralightConfigPages* config = NULL; - if(mf_ultralight_get_config_page(data, config)) { + if(mf_ultralight_get_config_page(data, &config)) { all_read = ((config->password.pass != 0) || (config->pack.pack != 0)); } } @@ -204,7 +204,7 @@ bool mf_ultralight_is_counter_configured(MfUltralightData* data) { break; default: - if(mf_ultralight_get_config_page(data, config)) { + if(mf_ultralight_get_config_page(data, &config)) { configured = config->access.nfc_cnt_en; } break; diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h index a4497adae3aa..8b62df1f599a 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h @@ -172,7 +172,7 @@ uint32_t mf_ultralight_get_feature_support_set(MfUltralightType type); const char* mf_ultralight_get_name(MfUltralightType type, bool full_name); -bool mf_ultralight_get_config_page(MfUltralightData* data, MfUltralightConfigPages* config); +bool mf_ultralight_get_config_page(MfUltralightData* data, MfUltralightConfigPages** config); bool mf_ultralight_is_all_data_read(MfUltralightData* data); diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c index d00259e0154f..f51224f28b36 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c @@ -5,6 +5,7 @@ #define TAG "MfUltralightPoller" #define MF_ULTRALIGHT_MAX_BUFF_SIZE (64) +#define MF_ULTRALIGHT_DEFAULT_PASSWORD (0xffffffffUL) typedef MfUltralightPollerCommand (*MfUltralightPollerReadHandler)(MfUltralightPoller* instance); @@ -246,6 +247,32 @@ static MfUltralightPollerCommand static MfUltralightPollerCommand mf_ultralight_poller_handler_try_default_pass(MfUltralightPoller* instance) { + if(instance->feature_set & MfUltralightFeatureSupportAuthentication) { + MfUltralightConfigPages* config = NULL; + mf_ultralight_get_config_page(instance->data, &config); + if(instance->auth_context.auth_success) { + config->password = instance->auth_context.password; + config->pack = instance->auth_context.pack; + } else if(config->access.authlim == 0) { + FURI_LOG_D(TAG, "No limits in authentication. Trying default password"); + instance->auth_context.password.pass = MF_ULTRALIGHT_DEFAULT_PASSWORD; + instance->error = mf_ultralight_poller_async_auth(instance, &instance->auth_context); + if(instance->error == MfUltralightErrorNone) { + FURI_LOG_D(TAG, "Default password detected"); + config->password.pass = MF_ULTRALIGHT_DEFAULT_PASSWORD; + config->pack = instance->auth_context.pack; + } + } + + if(instance->pages_read != instance->pages_total) { + // Probably password protected, fix AUTH0 and PROT so before AUTH0 + // can be written and since AUTH0 won't be readable, like on the + // original card + config->auth0 = instance->pages_read; + config->access.prot = true; + } + } + instance->state = MfUltralightPollerStateReadSuccess; return MfUltralightPollerCommandContinue; } From 7cec8b3880aa824104a26b4547f932cb5b5d08c3 Mon Sep 17 00:00:00 2001 From: gornekich Date: Mon, 8 May 2023 22:34:43 +0400 Subject: [PATCH 069/149] mf ultralight: listener fixes --- applications/debug/unit_tests/nfc/nfc_test.c | 90 +++++++------ .../protocols/mf_ultralight/mf_ultralight.c | 8 +- .../mf_ultralight/mf_ultralight_listener.c | 118 +++++++++++++++++- .../mf_ultralight/mf_ultralight_listener.h | 2 +- .../mf_ultralight/mf_ultralight_poller.c | 24 ++-- .../mf_ultralight/mf_ultralight_poller_i.c | 4 +- .../mf_ultralight_poller_sync_api.c | 2 + 7 files changed, 190 insertions(+), 58 deletions(-) diff --git a/applications/debug/unit_tests/nfc/nfc_test.c b/applications/debug/unit_tests/nfc/nfc_test.c index 697fe77a98c1..dd0b5d4bafc2 100644 --- a/applications/debug/unit_tests/nfc/nfc_test.c +++ b/applications/debug/unit_tests/nfc/nfc_test.c @@ -146,44 +146,46 @@ static void nfc_test_free() { // mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeNTAGI2CPlus2k); // } -MU_TEST(nfca_reader) { - Nfc* poller = nfc_alloc(); - Nfc* listener = nfc_alloc(); +// MU_TEST(nfca_reader) { +// Nfc* poller = nfc_alloc(); +// Nfc* listener = nfc_alloc(); + +// NfcaPoller* nfca_poller = nfca_poller_alloc(poller); +// NfcaListener* nfca_listener = nfca_listener_alloc(listener); + +// NfcaData nfca_listener_data = { +// .uid_len = 7, +// .uid = {0x04, 0x51, 0x5C, 0xFA, 0x6F, 0x73, 0x81}, +// .atqa = {0x44, 0x00}, +// .sak = 0x00, +// }; +// // nfca_listener_data.uid_len = 7; +// // furi_hal_random_fill_buf(nfca_listener_data.uid, 7); +// // furi_hal_random_fill_buf(nfca_listener_data.atqa, 2); +// // furi_hal_random_fill_buf(&nfca_listener_data.sak, 1); +// NfcaData nfca_poller_data = {}; - NfcaPoller* nfca_poller = nfca_poller_alloc(poller); - NfcaListener* nfca_listener = nfca_listener_alloc(listener); - - NfcaData nfca_listener_data = { - .uid_len = 7, - .uid = {0x04, 0x51, 0x5C, 0xFA, 0x6F, 0x73, 0x81}, - .atqa = {0x44, 0x00}, - .sak = 0x00, - }; - // nfca_listener_data.uid_len = 7; - // furi_hal_random_fill_buf(nfca_listener_data.uid, 7); - // furi_hal_random_fill_buf(nfca_listener_data.atqa, 2); - // furi_hal_random_fill_buf(&nfca_listener_data.sak, 1); - NfcaData nfca_poller_data = {}; - - mu_assert( - nfca_listener_start(nfca_listener, &nfca_listener_data, NULL, NULL) == NfcaErrorNone, - "nfca_listener_start() failed"); +// mu_assert( +// nfca_listener_start(nfca_listener, &nfca_listener_data, NULL, NULL) == NfcaErrorNone, +// "nfca_listener_start() failed"); - mu_assert( - nfca_poller_read(nfca_poller, &nfca_poller_data) == NfcaErrorNone, - "nfca_poller_read() failed"); - mu_assert(nfca_listener_stop(nfca_listener) == NfcaErrorNone, "nfca_listener_stop() failed"); +// mu_assert( +// nfca_poller_read(nfca_poller, &nfca_poller_data) == NfcaErrorNone, +// "nfca_poller_read() failed"); +// mu_assert(nfca_listener_stop(nfca_listener) == NfcaErrorNone, "nfca_listener_stop() failed"); - mu_assert( - memcmp(&nfca_poller_data, &nfca_listener_data, sizeof(NfcaData)) == 0, "Data not matches"); +// mu_assert( +// memcmp(&nfca_poller_data, &nfca_listener_data, sizeof(NfcaData)) == 0, "Data not matches"); - nfca_listener_free(nfca_listener); - nfc_free(listener); - nfca_poller_free(nfca_poller); - nfc_free(poller); -} +// nfca_listener_free(nfca_listener); +// nfc_free(listener); +// nfca_poller_free(nfca_poller); +// nfc_free(poller); +// } -MU_TEST(mf_ultralight_reader) { +static void mf_ultralight_reader_test(const char* path) { + FURI_LOG_I(TAG, "Testing file: %s", path); + NfcDev* nfc_dev = nfc_dev_alloc(); Nfc* poller = nfc_alloc(); Nfc* listener = nfc_alloc(); @@ -195,7 +197,8 @@ MU_TEST(mf_ultralight_reader) { MfUltralightError error = MfUltralightErrorNone; NfcDevData* dev_data = malloc(sizeof(NfcDevData)); - nfc_data_generator_fill_data(NfcDataGeneratorTypeMfUltralight, dev_data); + + mu_assert(nfc_dev_load(nfc_dev, dev_data, path), "nfc_dev_load() failed\r\n"); error = mf_ultralight_listener_start(mfu_listener, &dev_data->mf_ul_data, NULL, NULL); mu_assert(error == MfUltralightErrorNone, "mf_ultralight_listener_start() failed"); @@ -219,13 +222,28 @@ MU_TEST(mf_ultralight_reader) { nfc_free(listener); nfca_poller_free(nfca_poller); nfc_free(poller); + nfc_dev_free(nfc_dev); +} + +MU_TEST(mf_ultralight_11_reader) { + mf_ultralight_reader_test(EXT_PATH("unit_tests/nfc/Ultralight_11.nfc")); +} + +MU_TEST(mf_ultralight_21_reader) { + mf_ultralight_reader_test(EXT_PATH("unit_tests/nfc/Ultralight_21.nfc")); +} + +MU_TEST(ntag_215_reader) { + mf_ultralight_reader_test(EXT_PATH("unit_tests/nfc/Ntag215.nfc")); } MU_TEST_SUITE(nfc) { nfc_test_alloc(); - MU_RUN_TEST(nfca_reader); - MU_RUN_TEST(mf_ultralight_reader); + // MU_RUN_TEST(nfca_reader); + UNUSED(mf_ultralight_11_reader); + UNUSED(mf_ultralight_21_reader); + MU_RUN_TEST(ntag_215_reader); // MU_RUN_TEST(nfca_4b_file_test); // MU_RUN_TEST(nfca_7b_file_test); diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight.c index 47f846b3dacd..57ef8f6a6706 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight.c @@ -200,14 +200,14 @@ bool mf_ultralight_is_counter_configured(MfUltralightData* data) { case MfUltralightTypeNTAG213: case MfUltralightTypeNTAG215: case MfUltralightTypeNTAG216: - configured = true; - break; - - default: if(mf_ultralight_get_config_page(data, &config)) { configured = config->access.nfc_cnt_en; } break; + + default: + configured = true; + break; } return configured; diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c index 8c63531b8160..2b6fde10b54d 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c @@ -18,6 +18,7 @@ struct MfUltralightListener { uint8_t tx_data[MF_ULTRALIGHT_LISTENER_MAX_TX_BUFF_SIZE]; uint16_t tx_bits; MfUltralightFeatureSupport features; + MfUltralightConfigPages* config; MfUltralightListenerEventCallback callback; void* context; @@ -117,6 +118,7 @@ static bool mf_ultralight_listener_read_signature_handler( uint16_t rx_bits) { UNUSED(rx_bits); UNUSED(rx_data); + bool command_processed = false; if((instance->features & MfUltralightFeatureSupportReadSignature)) { memcpy(instance->tx_data, &instance->data->signature, sizeof(instance->data->signature)); @@ -132,10 +134,104 @@ static bool mf_ultralight_listener_read_signature_handler( return command_processed; } +static bool mf_ultralight_listener_read_counter_handler( + MfUltralightListener* instance, + uint8_t* rx_data, + uint16_t rx_bits) { + UNUSED(rx_bits); + + bool command_processed = false; + + do { + uint8_t counter_num = rx_data[1]; + if((instance->features & MfUltralightFeatureSupportReadCounter) == 0) break; + if(instance->features & MfUltralightFeatureSupportSingleCounter) { + if(counter_num != 2) { + break; + } + } + if(instance->config) { + if(!instance->config->access.nfc_cnt_en) { + break; + } + if(instance->config->access.nfc_cnt_pwd_prot) { + if(instance->state != MfUltraligthListenerStateAuthSuccess) { + break; + } + } + } + if(counter_num > 2) break; + instance->tx_data[0] = (instance->data->counter[counter_num].counter >> 0) & 0xff; + instance->tx_data[1] = (instance->data->counter[counter_num].counter >> 8) & 0xff; + instance->tx_data[2] = (instance->data->counter[counter_num].counter >> 16) & 0xff; + instance->tx_bits = 3 * 8; + nfca_listener_send_standart_frame( + instance->nfca_listener, instance->tx_data, instance->tx_bits); + command_processed = true; + } while(false); + + return command_processed; +} + +static bool mf_ultralight_listener_check_tearing_handler( + MfUltralightListener* instance, + uint8_t* rx_data, + uint16_t rx_bits) { + UNUSED(rx_bits); + + bool command_processed = false; + + do { + uint8_t tearing_flag_num = rx_data[1]; + if((instance->features & MfUltralightFeatureSupportCheckTearingFlag) == 0) break; + if(tearing_flag_num > 2) break; + instance->tx_data[0] = instance->data->tearing_flag->data[0]; + instance->tx_bits = 8; + nfca_listener_send_standart_frame( + instance->nfca_listener, instance->tx_data, instance->tx_bits); + command_processed = true; + } while(false); + + return command_processed; +} + +static bool mf_ultralight_listener_auth_handler( + MfUltralightListener* instance, + uint8_t* rx_data, + uint16_t rx_bits) { + UNUSED(rx_bits); + + bool command_processed = false; + + do { + if((instance->features & MfUltralightFeatureSupportAuthentication) == 0) break; + MfUltralightAuthPassword password = {}; + memcpy(password.data, &rx_data[1], sizeof(MfUltralightAuthPassword)); + if(instance->callback) { + MfUltralightListenerEventData data = {.password = password}; + MfUltralightListenerEvent event = { + .type = MfUltralightListenerEventTypeAuth, + .data = &data, + }; + instance->callback(event, instance->context); + } + if(password.pass != instance->config->password.pass) break; + memcpy(instance->tx_data, instance->config->pack.data, sizeof(MfUltralightAuthPack)); + instance->tx_bits = sizeof(MfUltralightAuthPack) * 8; + instance->state = MfUltraligthListenerStateAuthSuccess; + nfca_listener_send_standart_frame( + instance->nfca_listener, instance->tx_data, instance->tx_bits); + + command_processed = true; + } while(false); + + return command_processed; +} + static const MfUltralightListenerCmdHandler mf_ultralight_command[] = { { .cmd = MF_ULTRALIGHT_CMD_READ_PAGE, - .cmd_len_bits = 16, + .cmd_len_bits = 2 * 8, .callback = mf_ultralight_listener_read_page_handler, }, { @@ -145,10 +241,24 @@ static const MfUltralightListenerCmdHandler mf_ultralight_command[] = { }, { .cmd = MF_ULTRALIGTH_CMD_READ_SIG, - .cmd_len_bits = 16, + .cmd_len_bits = 2 * 8, .callback = mf_ultralight_listener_read_signature_handler, }, -}; + { + .cmd = MF_ULTRALIGHT_CMD_READ_CNT, + .cmd_len_bits = 2 * 8, + .callback = mf_ultralight_listener_read_counter_handler, + }, + { + .cmd = MF_ULTRALIGHT_CMD_CHECK_TEARING, + .cmd_len_bits = 2 * 8, + .callback = mf_ultralight_listener_check_tearing_handler, + }, + { + .cmd = MF_ULTRALIGHT_CMD_AUTH, + .cmd_len_bits = 5 * 8, + .callback = mf_ultralight_listener_auth_handler, + }}; static NfcaListenerCommand mf_ultralight_listener_event_handler(NfcaListenerEvent event, void* context) { @@ -169,6 +279,7 @@ static NfcaListenerCommand } if(!cmd_processed) { mf_ultralight_listener_send_short_resp(instance, MF_ULTRALIGHT_CMD_NACK); + instance->state = MfUltraligthListenerStateIdle; } } @@ -178,6 +289,7 @@ static NfcaListenerCommand static void mf_ultralight_listener_prepare_emulation(MfUltralightListener* instance) { MfUltralightData* data = instance->data; instance->features = mf_ultralight_get_feature_support_set(data->type); + mf_ultralight_get_config_page(data, &instance->config); } MfUltralightListener* mf_ultralight_listener_alloc(NfcaListener* nfca_listener) { diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.h index df673029fc2e..ec0d126beea3 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.h @@ -21,7 +21,7 @@ typedef struct { typedef struct { MfUltralightListenerEventType type; - MfUltralightListenerEventData data; + MfUltralightListenerEventData* data; } MfUltralightListenerEvent; typedef enum { diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c index f51224f28b36..0ee344ab930c 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c @@ -55,11 +55,11 @@ static MfUltralightPollerCommand mf_ultralight_poller_handler_read_version(MfUltralightPoller* instance) { instance->error = mf_ultralight_poller_async_read_version(instance, &instance->data->version); if(instance->error == MfUltralightErrorNone) { - FURI_LOG_I(TAG, "Read version success"); + FURI_LOG_D(TAG, "Read version success"); instance->data->type = mf_ultralight_get_type_by_version(&instance->data->version); instance->state = MfUltralightPollerStateGetFeatureSet; } else { - FURI_LOG_W(TAG, "Didn't response. Check NTAG 203"); + FURI_LOG_D(TAG, "Didn't response. Check NTAG 203"); nfca_poller_halt(instance->nfca_poller); instance->state = MfUltralightPollerStateDetectNtag203; } @@ -72,10 +72,10 @@ static MfUltralightPollerCommand MfUltralightPageReadCommandData data = {}; instance->error = mf_ultralight_poller_async_read_page(instance, 41, &data); if(instance->error == MfUltralightErrorNone) { - FURI_LOG_I(TAG, "NTAG203 detected"); + FURI_LOG_D(TAG, "NTAG203 detected"); instance->data->type = MfUltralightTypeNTAG203; } else { - FURI_LOG_I(TAG, "Original Ultralight detected"); + FURI_LOG_D(TAG, "Original Ultralight detected"); nfca_poller_halt(instance->nfca_poller); instance->data->type = MfUltralightTypeUnknown; } @@ -91,7 +91,7 @@ static MfUltralightPollerCommand instance->feature_set = mf_ultralight_get_feature_support_set(instance->data->type); instance->pages_total = mf_ultralight_get_pages_total(instance->data->type); instance->data->pages_total = instance->pages_total; - FURI_LOG_I( + FURI_LOG_D( TAG, "%s detected. Total pages: %d", mf_ultralight_get_name(instance->data->type, true), @@ -109,7 +109,7 @@ static MfUltralightPollerCommand instance->error = mf_ultralight_poller_async_read_signature(instance, &instance->data->signature); if(instance->error != MfUltralightErrorNone) { - FURI_LOG_E(TAG, "Read signature failed"); + FURI_LOG_D(TAG, "Read signature failed"); next_state = MfUltralightPollerStateReadFailed; } } else { @@ -136,7 +136,7 @@ static MfUltralightPollerCommand instance->counters_read, &instance->data->counter[instance->counters_read]); if(instance->error != MfUltralightErrorNone) { - FURI_LOG_E(TAG, "Failed to read %d counter", instance->counters_read); + FURI_LOG_D(TAG, "Failed to read %d counter", instance->counters_read); instance->state = MfUltralightPollerStateReadTearingFlags; } else { instance->counters_read++; @@ -165,7 +165,7 @@ static MfUltralightPollerCommand instance->tearing_flag_read, &instance->data->tearing_flag[instance->tearing_flag_read]); if(instance->error != MfUltralightErrorNone) { - FURI_LOG_E(TAG, "Reading tearing flag %d failed", instance->tearing_flag_read); + FURI_LOG_D(TAG, "Reading tearing flag %d failed", instance->tearing_flag_read); instance->state = MfUltralightPollerStateReadFailed; } else { instance->tearing_flag_read++; @@ -203,7 +203,7 @@ static MfUltralightPollerCommand mf_ultralight_poller_handler_auth(MfUltralightP event.type = MfUltralightPollerEventTypeAuthSuccess; command = instance->callback(event, instance->context); } else { - FURI_LOG_W(TAG, "Auth failed"); + FURI_LOG_D(TAG, "Auth failed"); instance->auth_context.auth_success = false; MfUltralightPollerEvent event = {.type = MfUltralightPollerEventTypeAuthFailed}; command = instance->callback(event, instance->context); @@ -224,7 +224,7 @@ static MfUltralightPollerCommand if(instance->error == MfUltralightErrorNone) { for(size_t i = 0; i < 4; i++) { if(start_page + i < instance->pages_total) { - FURI_LOG_I(TAG, "Read page %d success", start_page + i); + FURI_LOG_D(TAG, "Read page %d success", start_page + i); instance->data->page[start_page + i] = data.page[i]; instance->pages_read++; instance->data->pages_read = instance->pages_read; @@ -234,7 +234,7 @@ static MfUltralightPollerCommand instance->state = MfUltralightPollerStateReadCounters; } } else { - FURI_LOG_E(TAG, "Read page %d failed", instance->pages_read); + FURI_LOG_D(TAG, "Read page %d failed", instance->pages_read); if(instance->pages_read) { instance->state = MfUltralightPollerStateReadCounters; } else { @@ -279,7 +279,7 @@ static MfUltralightPollerCommand static MfUltralightPollerCommand mf_ultralight_poller_handler_read_fail(MfUltralightPoller* instance) { - FURI_LOG_W(TAG, "Read Failed"); + FURI_LOG_D(TAG, "Read Failed"); MfUltralightPollerEventData event_data = {.error = instance->error}; MfUltralightPollerEvent event = { .type = MfUltralightPollerEventTypeReadFailed, .data = &event_data}; diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c index fd6559d1894e..b861e8aeab08 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c @@ -120,7 +120,7 @@ MfUltralightError mf_ultralight_poller_async_write_page( buff->rx_data_size, &buff->rx_bits, MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); - FURI_LOG_I(TAG, "Rx bits: %d", buff->rx_bits); + FURI_LOG_D(TAG, "Rx bits: %d", buff->rx_bits); if(error != NfcaErrorNone) { ret = mf_ultralight_process_error(error); break; @@ -161,7 +161,7 @@ MfUltralightError mf_ultralight_poller_async_read_version( ret = MfUltralightErrorProtocol; break; } - memcpy(&data, buff->rx_data, sizeof(MfUltralightVersion)); + memcpy(data, buff->rx_data, sizeof(MfUltralightVersion)); } while(false); return ret; diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c index 1799e9b36b5b..7074d96c649e 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c @@ -259,6 +259,8 @@ static MfUltralightPollerCommand } else if(event.type == MfUltralightPollerEventTypeReadFailed) { poller_context->error = event.data->error; command = MfUltralightPollerCommandStop; + } else if(event.type == MfUltralightPollerEventTypeAuthRequest) { + event.data->auth_context.skip_auth = true; } if(command == MfUltralightPollerCommandStop) { From e13a0bb355142c191008684817c08f31117c2188 Mon Sep 17 00:00:00 2001 From: gornekich Date: Wed, 10 May 2023 15:57:40 +0400 Subject: [PATCH 070/149] mf ultralight: fix ntag i2c reading --- applications/debug/unit_tests/nfc/nfc_test.c | 51 ++++- .../protocols/mf_ultralight/mf_ultralight.h | 1 + .../mf_ultralight/mf_ultralight_poller.c | 19 +- .../mf_ultralight/mf_ultralight_poller.h | 2 - .../mf_ultralight/mf_ultralight_poller_i.c | 211 ++++++++++++++++++ .../mf_ultralight/mf_ultralight_poller_i.h | 17 ++ 6 files changed, 296 insertions(+), 5 deletions(-) diff --git a/applications/debug/unit_tests/nfc/nfc_test.c b/applications/debug/unit_tests/nfc/nfc_test.c index dd0b5d4bafc2..8ed68bb08117 100644 --- a/applications/debug/unit_tests/nfc/nfc_test.c +++ b/applications/debug/unit_tests/nfc/nfc_test.c @@ -237,13 +237,62 @@ MU_TEST(ntag_215_reader) { mf_ultralight_reader_test(EXT_PATH("unit_tests/nfc/Ntag215.nfc")); } +MU_TEST(ntag_213_locked_reader) { + FURI_LOG_I(TAG, "Testing Ntag215 locked file"); + NfcDev* nfc_dev = nfc_dev_alloc(); + Nfc* poller = nfc_alloc(); + Nfc* listener = nfc_alloc(); + + NfcaPoller* nfca_poller = nfca_poller_alloc(poller); + NfcaListener* nfca_listener = nfca_listener_alloc(listener); + + MfUltralightPoller* mfu_poller = mf_ultralight_poller_alloc(nfca_poller); + MfUltralightListener* mfu_listener = mf_ultralight_listener_alloc(nfca_listener); + + MfUltralightError error = MfUltralightErrorNone; + NfcDevData* dev_data = malloc(sizeof(NfcDevData)); + + mu_assert( + nfc_dev_load(nfc_dev, dev_data, EXT_PATH("unit_tests/nfc/Ntag213_locked.nfc")), + "nfc_dev_load() failed\r\n"); + + error = mf_ultralight_listener_start(mfu_listener, &dev_data->mf_ul_data, NULL, NULL); + mu_assert(error == MfUltralightErrorNone, "mf_ultralight_listener_start() failed"); + + MfUltralightData* mfu_data = malloc(sizeof(MfUltralightData)); + error = mf_ultralight_poller_read_card(mfu_poller, mfu_data); + mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_read_card() failed"); + + error = mf_ultralight_listener_stop(mfu_listener); + mu_assert(error == MfUltralightErrorNone, "mf_ultralight_listener_stop() failed"); + + MfUltralightConfigPages* config = NULL; + mu_assert( + mf_ultralight_get_config_page(&dev_data->mf_ul_data, &config), + "mf_ultralight_get_config_page() failed"); + uint16_t pages_locked = config->auth0; + + mu_assert(mfu_data->pages_read == pages_locked, "Unexpected pages read"); + + free(mfu_data); + free(dev_data); + mf_ultralight_listener_free(mfu_listener); + mf_ultralight_poller_free(mfu_poller); + nfca_listener_free(nfca_listener); + nfc_free(listener); + nfca_poller_free(nfca_poller); + nfc_free(poller); + nfc_dev_free(nfc_dev); +} + MU_TEST_SUITE(nfc) { nfc_test_alloc(); // MU_RUN_TEST(nfca_reader); UNUSED(mf_ultralight_11_reader); UNUSED(mf_ultralight_21_reader); - MU_RUN_TEST(ntag_215_reader); + UNUSED(ntag_215_reader); + MU_RUN_TEST(ntag_213_locked_reader); // MU_RUN_TEST(nfca_4b_file_test); // MU_RUN_TEST(nfca_7b_file_test); diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h index 8b62df1f599a..2a460dd0211c 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h @@ -10,6 +10,7 @@ extern "C" { #define MF_ULTRALIGHT_CMD_GET_VERSION (0x60) #define MF_ULTRALIGHT_CMD_READ_PAGE (0x30) +#define MF_ULTRALIGHT_CMD_SECTOR_SELECT (0xC2) #define MF_ULTRALIGHT_CMD_WRITE_PAGE (0xA2) #define MF_ULTRALIGTH_CMD_READ_SIG (0x3C) #define MF_ULTRALIGHT_CMD_READ_CNT (0x39) diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c index 0ee344ab930c..c870960aca47 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c @@ -219,8 +219,23 @@ static MfUltralightPollerCommand mf_ultralight_poller_handler_auth(MfUltralightP static MfUltralightPollerCommand mf_ultralight_poller_handler_read_pages(MfUltralightPoller* instance) { MfUltralightPageReadCommandData data = {}; - uint8_t start_page = instance->pages_read; - instance->error = mf_ultralight_poller_async_read_page(instance, start_page, &data); + uint16_t start_page = instance->pages_read; + if(MF_ULTRALIGHT_IS_NTAG_I2C(instance->data->type)) { + uint8_t tag = 0; + uint8_t sector = 0; + uint8_t pages_left = 0; + if(mf_ultralight_poller_ntag_i2c_addr_lin_to_tag( + instance, start_page, §or, &tag, &pages_left)) { + instance->error = + mf_ultralight_poller_async_read_page_from_sector(instance, sector, tag, &data); + } else { + FURI_LOG_D(TAG, "Failed to calculate sector and tag from %d page", start_page); + instance->error = MfUltralightErrorProtocol; + } + } else { + instance->error = mf_ultralight_poller_async_read_page(instance, start_page, &data); + } + if(instance->error == MfUltralightErrorNone) { for(size_t i = 0; i < 4; i++) { if(start_page + i < instance->pages_total) { diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h index f2fc21378e35..f446ce301652 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h @@ -64,8 +64,6 @@ MfUltralightError MfUltralightError mf_ultralight_poller_reset(MfUltralightPoller* instance); -// Called from NfcWorker thread - MfUltralightError mf_ultralight_poller_stop(MfUltralightPoller* instance); // Sync API diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c index b861e8aeab08..45aca68941d0 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c @@ -30,6 +30,164 @@ MfUltralightError mf_ultralight_process_error(NfcaError error) { return ret; } +static bool mf_ultralight_poller_ntag_i2c_addr_lin_to_tag_ntag_i2c_1k( + uint16_t lin_addr, + uint8_t* sector, + uint8_t* tag, + uint8_t* pages_left) { + bool tag_calculated = false; + // 0 - 226: sector 0 + // 227 - 228: config registers + // 229 - 230: session registers + + if(lin_addr > 230) { + *pages_left = 0; + } else if(lin_addr >= 229) { + *sector = 3; + *pages_left = 2 - (lin_addr - 229); + *tag = lin_addr - 229 + 248; + tag_calculated = true; + } else if(lin_addr >= 227) { + *sector = 0; + *pages_left = 2 - (lin_addr - 227); + *tag = lin_addr - 227 + 232; + tag_calculated = true; + } else { + *sector = 0; + *pages_left = 227 - lin_addr; + *tag = lin_addr; + tag_calculated = true; + } + + return tag_calculated; +} + +static bool mf_ultralight_poller_ntag_i2c_addr_lin_to_tag_ntag_i2c_2k( + uint16_t lin_addr, + uint8_t* sector, + uint8_t* tag, + uint8_t* pages_left) { + bool tag_calculated = false; + // 0 - 255: sector 0 + // 256 - 480: sector 1 + // 481 - 482: config registers + // 483 - 484: session registers + + if(lin_addr > 484) { + *pages_left = 0; + } else if(lin_addr >= 483) { + *sector = 3; + *pages_left = 2 - (lin_addr - 483); + *tag = lin_addr - 483 + 248; + tag_calculated = true; + } else if(lin_addr >= 481) { + *sector = 1; + *pages_left = 2 - (lin_addr - 481); + *tag = lin_addr - 481 + 232; + tag_calculated = true; + } else if(lin_addr >= 256) { + *sector = 1; + *pages_left = 225 - (lin_addr - 256); + *tag = lin_addr - 256; + tag_calculated = true; + } else { + *sector = 0; + *pages_left = 256 - lin_addr; + *tag = lin_addr; + tag_calculated = true; + } + + return tag_calculated; +} + +static bool mf_ultralight_poller_ntag_i2c_addr_lin_to_tag_ntag_i2c_plus_1k( + uint16_t lin_addr, + uint8_t* sector, + uint8_t* tag, + uint8_t* pages_left) { + bool tag_calculated = false; + // 0 - 233: sector 0 + registers + // 234 - 235: session registers + + if(lin_addr > 235) { + *pages_left = 0; + } else if(lin_addr >= 234) { + *sector = 0; + *pages_left = 2 - (lin_addr - 234); + *tag = lin_addr - 234 + 236; + tag_calculated = true; + } else { + *sector = 0; + *pages_left = 234 - lin_addr; + *tag = lin_addr; + tag_calculated = true; + } + + return tag_calculated; +} + +static bool mf_ultralight_poller_ntag_i2c_addr_lin_to_tag_ntag_i2c_plus_2k( + uint16_t lin_addr, + uint8_t* sector, + uint8_t* tag, + uint8_t* pages_left) { + bool tag_calculated = false; + // 0 - 233: sector 0 + registers + // 234 - 235: session registers + // 236 - 491: sector 1 + + if(lin_addr > 491) { + *pages_left = 0; + } else if(lin_addr >= 236) { + *sector = 1; + *pages_left = 256 - (lin_addr - 236); + *tag = lin_addr - 236; + tag_calculated = true; + } else if(lin_addr >= 234) { + *sector = 0; + *pages_left = 2 - (lin_addr - 234); + *tag = lin_addr - 234 + 236; + tag_calculated = true; + } else { + *sector = 0; + *pages_left = 234 - lin_addr; + *tag = lin_addr; + tag_calculated = true; + } + + return tag_calculated; +} + +bool mf_ultralight_poller_ntag_i2c_addr_lin_to_tag( + MfUltralightPoller* instance, + uint16_t lin_addr, + uint8_t* sector, + uint8_t* tag, + uint8_t* pages_left) { + furi_assert(instance); + furi_assert(sector); + furi_assert(tag); + furi_assert(pages_left); + + bool tag_calculated = false; + + if(instance->data->type == MfUltralightTypeNTAGI2C1K) { + tag_calculated = mf_ultralight_poller_ntag_i2c_addr_lin_to_tag_ntag_i2c_1k( + lin_addr, sector, tag, pages_left); + } else if(instance->data->type == MfUltralightTypeNTAGI2C2K) { + tag_calculated = mf_ultralight_poller_ntag_i2c_addr_lin_to_tag_ntag_i2c_2k( + lin_addr, sector, tag, pages_left); + } else if(instance->data->type == MfUltralightTypeNTAGI2CPlus1K) { + tag_calculated = mf_ultralight_poller_ntag_i2c_addr_lin_to_tag_ntag_i2c_plus_1k( + lin_addr, sector, tag, pages_left); + } else if(instance->data->type == MfUltralightTypeNTAGI2CPlus2K) { + tag_calculated = mf_ultralight_poller_ntag_i2c_addr_lin_to_tag_ntag_i2c_plus_2k( + lin_addr, sector, tag, pages_left); + } + + return tag_calculated; +} + MfUltralightError mf_ultralight_poller_async_auth( MfUltralightPoller* instance, MfUltralightPollerAuthContext* data) { @@ -65,6 +223,59 @@ MfUltralightError mf_ultralight_poller_async_auth( return ret; } +MfUltralightError mf_ultralight_poller_async_read_page_from_sector( + MfUltralightPoller* instance, + uint8_t sector, + uint8_t tag, + MfUltralightPageReadCommandData* data) { + NfcPollerBuffer* buff = instance->buffer; + MfUltralightError ret = MfUltralightErrorNone; + NfcaError error = NfcaErrorNone; + + do { + buff->tx_data[0] = MF_ULTRALIGHT_CMD_SECTOR_SELECT; + buff->tx_data[1] = 0xff; + buff->tx_bits = 16; + error = nfca_poller_send_standart_frame( + instance->nfca_poller, + buff->tx_data, + buff->tx_bits, + buff->rx_data, + buff->rx_data_size, + &buff->rx_bits, + MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); + if(error != NfcaErrorNone) { + FURI_LOG_D(TAG, "Failed to issue sector select command"); + ret = mf_ultralight_process_error(error); + break; + } + + buff->tx_data[0] = sector; + buff->tx_data[1] = 0x00; + buff->tx_data[2] = 0x00; + buff->tx_data[3] = 0x00; + buff->tx_bits = 32; + error = nfca_poller_send_standart_frame( + instance->nfca_poller, + buff->tx_data, + buff->tx_bits, + buff->rx_data, + buff->rx_data_size, + &buff->rx_bits, + MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); + if(error != NfcaErrorTimeout) { + // This is NOT a typo! The tag ACKs by not sending a response within 1ms. + FURI_LOG_D(TAG, "Sector %u select NAK'd", sector); + ret = MfUltralightErrorProtocol; + break; + } + + ret = mf_ultralight_poller_async_read_page(instance, tag, data); + } while(false); + + return ret; +} + MfUltralightError mf_ultralight_poller_async_read_page( MfUltralightPoller* instance, uint8_t start_page, diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h index e25316e6e25f..fe1606e8450e 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h @@ -7,6 +7,10 @@ #define MF_ULTRALIGHT_POLLER_STANDART_FWT_FC (60000) +#define MF_ULTRALIGHT_IS_NTAG_I2C(type) \ + (((type) == MfUltralightTypeNTAGI2C1K) || ((type) == MfUltralightTypeNTAGI2C2K) || \ + ((type) == MfUltralightTypeNTAGI2CPlus1K) || ((type) == MfUltralightTypeNTAGI2CPlus2K)) + typedef struct { MfUltralightPage page; uint8_t page_to_write; @@ -81,6 +85,13 @@ struct MfUltralightPoller { MfUltralightError mf_ultralight_process_error(NfcaError error); +bool mf_ultralight_poller_ntag_i2c_addr_lin_to_tag( + MfUltralightPoller* instance, + uint16_t lin_addr, + uint8_t* sector, + uint8_t* tag, + uint8_t* pages_left); + MfUltralightError mf_ultralight_poller_async_auth( MfUltralightPoller* instance, MfUltralightPollerAuthContext* data); @@ -90,6 +101,12 @@ MfUltralightError mf_ultralight_poller_async_read_page( uint8_t start_page, MfUltralightPageReadCommandData* data); +MfUltralightError mf_ultralight_poller_async_read_page_from_sector( + MfUltralightPoller* instnace, + uint8_t sector, + uint8_t tag, + MfUltralightPageReadCommandData* data); + MfUltralightError mf_ultralight_poller_async_write_page( MfUltralightPoller* instance, uint8_t page, From 9d63f9749867251b1786c357a0eba16580ae1f13 Mon Sep 17 00:00:00 2001 From: gornekich Date: Wed, 10 May 2023 17:00:59 +0400 Subject: [PATCH 071/149] mf ultralight: fix feature sets --- .../protocols/mf_ultralight/mf_ultralight.c | 177 +++++++++++------- .../protocols/mf_ultralight/mf_ultralight.h | 2 + .../mf_ultralight/mf_ultralight_listener.c | 65 ++++++- 3 files changed, 171 insertions(+), 73 deletions(-) diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight.c index 57ef8f6a6706..2037ee7710bc 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight.c @@ -2,65 +2,115 @@ #include -static const uint16_t mf_ultralight_total_pages[MfUltralightTypeNum] = { - [MfUltralightTypeUnknown] = 16, - [MfUltralightTypeNTAG203] = 42, - [MfUltralightTypeUL11] = 20, - [MfUltralightTypeUL21] = 41, - [MfUltralightTypeNTAG213] = 45, - [MfUltralightTypeNTAG215] = 135, - [MfUltralightTypeNTAG216] = 231, - [MfUltralightTypeNTAGI2C1K] = 231, - [MfUltralightTypeNTAGI2C2K] = 485, - [MfUltralightTypeNTAGI2CPlus1K] = 236, - [MfUltralightTypeNTAGI2CPlus2K] = 492, -}; - -static const uint32_t mf_ultarlight_feature_sets[MfUltralightTypeNum] = { - [MfUltralightTypeUnknown] = MfUltralightFeatureSupportCompatibleWrite, - [MfUltralightTypeNTAG203] = MfUltralightFeatureSupportCompatibleWrite | - MfUltralightFeatureSupportCounterInMemory, +typedef struct { + uint16_t total_pages; + uint16_t config_page; + uint32_t feature_set; +} MfUltralightFeatures; + +static const MfUltralightFeatures mf_ultralight_features[MfUltralightTypeNum] = { + [MfUltralightTypeUnknown] = + { + .total_pages = 16, + .config_page = 0, + .feature_set = MfUltralightFeatureSupportCompatibleWrite, + }, + [MfUltralightTypeNTAG203] = + { + .total_pages = 42, + .config_page = 0, + .feature_set = MfUltralightFeatureSupportCompatibleWrite | + MfUltralightFeatureSupportCounterInMemory, + }, [MfUltralightTypeUL11] = - MfUltralightFeatureSupportReadVersion | MfUltralightFeatureSupportReadSignature | - MfUltralightFeatureSupportReadCounter | MfUltralightFeatureSupportCheckTearingFlag | - MfUltralightFeatureSupportFastRead | MfUltralightFeatureSupportIncCounter | - MfUltralightFeatureSupportCompatibleWrite | MfUltralightFeatureSupportAuthentication | - MfUltralightFeatureSupportVcsl, + { + .total_pages = 20, + .config_page = 16, + .feature_set = + MfUltralightFeatureSupportReadVersion | MfUltralightFeatureSupportReadSignature | + MfUltralightFeatureSupportReadCounter | + MfUltralightFeatureSupportCheckTearingFlag | MfUltralightFeatureSupportFastRead | + MfUltralightFeatureSupportIncCounter | MfUltralightFeatureSupportCompatibleWrite | + MfUltralightFeatureSupportAuthentication | MfUltralightFeatureSupportVcsl, + }, [MfUltralightTypeUL21] = - MfUltralightFeatureSupportReadVersion | MfUltralightFeatureSupportReadSignature | - MfUltralightFeatureSupportReadCounter | MfUltralightFeatureSupportCheckTearingFlag | - MfUltralightFeatureSupportFastRead | MfUltralightFeatureSupportIncCounter | - MfUltralightFeatureSupportCompatibleWrite | MfUltralightFeatureSupportAuthentication | - MfUltralightFeatureSupportVcsl, + { + .total_pages = 41, + .config_page = 37, + .feature_set = + MfUltralightFeatureSupportReadVersion | MfUltralightFeatureSupportReadSignature | + MfUltralightFeatureSupportReadCounter | + MfUltralightFeatureSupportCheckTearingFlag | MfUltralightFeatureSupportFastRead | + MfUltralightFeatureSupportIncCounter | MfUltralightFeatureSupportCompatibleWrite | + MfUltralightFeatureSupportAuthentication | MfUltralightFeatureSupportVcsl, + }, [MfUltralightTypeNTAG213] = - MfUltralightFeatureSupportReadVersion | MfUltralightFeatureSupportReadSignature | - MfUltralightFeatureSupportReadCounter | MfUltralightFeatureSupportFastRead | - MfUltralightFeatureSupportCompatibleWrite | MfUltralightFeatureSupportAuthentication | - MfUltralightFeatureSupportSingleCounter | MfUltralightFeatureSupportAsciiMirror, + { + .total_pages = 45, + .config_page = 41, + .feature_set = + MfUltralightFeatureSupportReadVersion | MfUltralightFeatureSupportReadSignature | + MfUltralightFeatureSupportReadCounter | MfUltralightFeatureSupportFastRead | + MfUltralightFeatureSupportCompatibleWrite | + MfUltralightFeatureSupportAuthentication | + MfUltralightFeatureSupportSingleCounter | MfUltralightFeatureSupportAsciiMirror, + }, [MfUltralightTypeNTAG215] = - MfUltralightFeatureSupportReadVersion | MfUltralightFeatureSupportReadSignature | - MfUltralightFeatureSupportReadCounter | MfUltralightFeatureSupportFastRead | - MfUltralightFeatureSupportCompatibleWrite | MfUltralightFeatureSupportAuthentication | - MfUltralightFeatureSupportSingleCounter | MfUltralightFeatureSupportAsciiMirror, + { + .total_pages = 135, + .config_page = 131, + .feature_set = + MfUltralightFeatureSupportReadVersion | MfUltralightFeatureSupportReadSignature | + MfUltralightFeatureSupportReadCounter | MfUltralightFeatureSupportFastRead | + MfUltralightFeatureSupportCompatibleWrite | + MfUltralightFeatureSupportAuthentication | + MfUltralightFeatureSupportSingleCounter | MfUltralightFeatureSupportAsciiMirror, + }, [MfUltralightTypeNTAG216] = - MfUltralightFeatureSupportReadVersion | MfUltralightFeatureSupportReadSignature | - MfUltralightFeatureSupportReadCounter | MfUltralightFeatureSupportFastRead | - MfUltralightFeatureSupportCompatibleWrite | MfUltralightFeatureSupportAuthentication | - MfUltralightFeatureSupportSingleCounter | MfUltralightFeatureSupportAsciiMirror, + { + .total_pages = 231, + .config_page = 227, + .feature_set = + MfUltralightFeatureSupportReadVersion | MfUltralightFeatureSupportReadSignature | + MfUltralightFeatureSupportReadCounter | MfUltralightFeatureSupportFastRead | + MfUltralightFeatureSupportCompatibleWrite | + MfUltralightFeatureSupportAuthentication | + MfUltralightFeatureSupportSingleCounter | MfUltralightFeatureSupportAsciiMirror, + }, [MfUltralightTypeNTAGI2C1K] = - MfUltralightFeatureSupportReadVersion | MfUltralightFeatureSupportFastRead | - MfUltralightFeatureSupportFastWrite | MfUltralightFeatureSupportSectorSelect, + { + .total_pages = 231, + .config_page = 0, + .feature_set = + MfUltralightFeatureSupportReadVersion | MfUltralightFeatureSupportFastRead | + MfUltralightFeatureSupportFastWrite | MfUltralightFeatureSupportSectorSelect, + }, [MfUltralightTypeNTAGI2C2K] = - MfUltralightFeatureSupportReadVersion | MfUltralightFeatureSupportFastRead | - MfUltralightFeatureSupportFastWrite | MfUltralightFeatureSupportSectorSelect, + { + .total_pages = 485, + .config_page = 0, + .feature_set = + MfUltralightFeatureSupportReadVersion | MfUltralightFeatureSupportFastRead | + MfUltralightFeatureSupportFastWrite | MfUltralightFeatureSupportSectorSelect, + }, [MfUltralightTypeNTAGI2CPlus1K] = - MfUltralightFeatureSupportReadVersion | MfUltralightFeatureSupportReadSignature | - MfUltralightFeatureSupportFastRead | MfUltralightFeatureSupportAuthentication | - MfUltralightFeatureSupportSectorSelect, + { + .total_pages = 236, + .config_page = 227, + .feature_set = + MfUltralightFeatureSupportReadVersion | MfUltralightFeatureSupportReadSignature | + MfUltralightFeatureSupportFastRead | MfUltralightFeatureSupportAuthentication | + MfUltralightFeatureSupportSectorSelect, + }, [MfUltralightTypeNTAGI2CPlus2K] = - MfUltralightFeatureSupportReadVersion | MfUltralightFeatureSupportReadSignature | - MfUltralightFeatureSupportFastRead | MfUltralightFeatureSupportAuthentication | - MfUltralightFeatureSupportSectorSelect, + { + .total_pages = 492, + .config_page = 227, + .feature_set = + MfUltralightFeatureSupportReadVersion | MfUltralightFeatureSupportReadSignature | + MfUltralightFeatureSupportFastRead | MfUltralightFeatureSupportAuthentication | + MfUltralightFeatureSupportSectorSelect, + }, }; MfUltralightType mf_ultralight_get_type_by_version(MfUltralightVersion* version) { @@ -98,11 +148,11 @@ MfUltralightType mf_ultralight_get_type_by_version(MfUltralightVersion* version) } uint16_t mf_ultralight_get_pages_total(MfUltralightType type) { - return mf_ultralight_total_pages[type]; + return mf_ultralight_features[type].total_pages; } uint32_t mf_ultralight_get_feature_support_set(MfUltralightType type) { - return mf_ultarlight_feature_sets[type]; + return mf_ultralight_features[type].feature_set; } const char* mf_ultralight_get_name(MfUltralightType type, bool full_name) { @@ -140,29 +190,20 @@ bool mf_ultralight_detect_protocol(NfcaData* nfca_data) { return mfu_detected; } +uint16_t mf_ultralight_get_config_page_num(MfUltralightType type) { + return mf_ultralight_features[type].config_page; +} + bool mf_ultralight_get_config_page(MfUltralightData* data, MfUltralightConfigPages** config) { furi_assert(data); furi_assert(config); bool config_pages_found = false; - switch(data->type) { - case MfUltralightTypeUL11: - case MfUltralightTypeUL21: - case MfUltralightTypeNTAG213: - case MfUltralightTypeNTAG215: - case MfUltralightTypeNTAG216: - *config = (MfUltralightConfigPages*)&data->page[data->pages_total - 4]; - config_pages_found = true; - break; - case MfUltralightTypeNTAGI2CPlus1K: - case MfUltralightTypeNTAGI2CPlus2K: - *config = (MfUltralightConfigPages*)&data->page[227]; + uint16_t config_page = mf_ultralight_features[data->type].config_page; + if(config_page != 0) { + *config = (MfUltralightConfigPages*)&data->page[config_page]; config_pages_found = true; - break; - - default: - break; } return config_pages_found; diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h index 2a460dd0211c..1bb52847c54d 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h @@ -173,6 +173,8 @@ uint32_t mf_ultralight_get_feature_support_set(MfUltralightType type); const char* mf_ultralight_get_name(MfUltralightType type, bool full_name); +uint16_t mf_ultralight_get_config_page_num(MfUltralightType type); + bool mf_ultralight_get_config_page(MfUltralightData* data, MfUltralightConfigPages** config); bool mf_ultralight_is_all_data_read(MfUltralightData* data); diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c index 2b6fde10b54d..61600a41b516 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c @@ -6,13 +6,23 @@ #define MF_ULTRALIGHT_LISTENER_MAX_TX_BUFF_SIZE (32) +typedef enum { + MfUltralightListenerAccessTypeRead, + MfUltralightListenerAccessTypeWrite, +} MfUltralightListenerAccessType; + +typedef enum { + MfUltralightListenerAuthStateIdle, + MfUltralightListenerAuthStateSuccess, +} MfUltralightListenerAuthState; + typedef enum { MfUltraligthListenerStateIdle, - MfUltraligthListenerStateAuthSuccess, } MfUltraligthListenerState; struct MfUltralightListener { NfcaListener* nfca_listener; + MfUltralightListenerAuthState auth_state; MfUltraligthListenerState state; MfUltralightData* data; uint8_t tx_data[MF_ULTRALIGHT_LISTENER_MAX_TX_BUFF_SIZE]; @@ -61,6 +71,37 @@ static MfUltralightError mf_ultralight_process_error(NfcaError error) { return ret; } +static bool mf_ultralight_listener_check_access( + MfUltralightListener* instance, + uint8_t start_page, + MfUltralightListenerAccessType access_type) { + bool access_success = false; + bool is_write_op = (access_type == MfUltralightListenerAccessTypeWrite); + + do { + if((instance->features & MfUltralightFeatureSupportAuthentication) == 0) { + access_success = true; + break; + } + if(instance->auth_state != MfUltralightListenerAuthStateSuccess) { + if((instance->config->auth0 <= start_page) && + (instance->config->access.prot || is_write_op)) { + break; + } + } + if(instance->config->access.cfglck && is_write_op) { + uint16_t config_page_start = instance->data->pages_total - 4; + if((start_page == config_page_start) || (start_page == config_page_start + 1)) { + break; + } + } + + access_success = true; + } while(false); + + return access_success; +} + static void mf_ultralight_listener_send_short_resp(MfUltralightListener* instance, uint8_t data) { nfca_listener_tx(instance->nfca_listener, &data, 4); }; @@ -78,9 +119,22 @@ static bool mf_ultralight_listener_read_page_handler( if(pages_total < start_page) { mf_ultralight_listener_send_short_resp(instance, MF_ULTRALIGHT_CMD_NACK); instance->state = MfUltraligthListenerStateIdle; + instance->auth_state = MfUltralightListenerAuthStateIdle; + } else if(!mf_ultralight_listener_check_access( + instance, start_page, MfUltralightListenerAccessTypeRead)) { + mf_ultralight_listener_send_short_resp(instance, MF_ULTRALIGHT_CMD_NACK); + instance->state = MfUltraligthListenerStateIdle; + instance->auth_state = MfUltralightListenerAuthStateIdle; } else { + uint16_t config_page = mf_ultralight_get_config_page_num(instance->data->type); for(size_t i = 0; i < 4; i++) { - read_cmd_data.page[i] = instance->data->page[(start_page + i) % pages_total]; + bool hide_data = + ((config_page != 0) && ((i == config_page + 1U) || (i == config_page + 2U))); + if(hide_data) { + memset(read_cmd_data.page[i].data, 0, sizeof(MfUltralightPage)); + } else { + read_cmd_data.page[i] = instance->data->page[(start_page + i) % pages_total]; + } } instance->tx_bits = sizeof(MfUltralightPageReadCommandData) * 8; nfca_listener_send_standart_frame( @@ -155,7 +209,7 @@ static bool mf_ultralight_listener_read_counter_handler( break; } if(instance->config->access.nfc_cnt_pwd_prot) { - if(instance->state != MfUltraligthListenerStateAuthSuccess) { + if(instance->auth_state != MfUltralightListenerAuthStateSuccess) { break; } } @@ -218,10 +272,10 @@ static bool mf_ultralight_listener_auth_handler( if(password.pass != instance->config->password.pass) break; memcpy(instance->tx_data, instance->config->pack.data, sizeof(MfUltralightAuthPack)); instance->tx_bits = sizeof(MfUltralightAuthPack) * 8; - instance->state = MfUltraligthListenerStateAuthSuccess; + instance->auth_state = MfUltralightListenerAuthStateSuccess; nfca_listener_send_standart_frame( instance->nfca_listener, instance->tx_data, instance->tx_bits); - + command_processed = true; } while(false); @@ -280,6 +334,7 @@ static NfcaListenerCommand if(!cmd_processed) { mf_ultralight_listener_send_short_resp(instance, MF_ULTRALIGHT_CMD_NACK); instance->state = MfUltraligthListenerStateIdle; + instance->auth_state = MfUltralightListenerAuthStateIdle; } } From d13b7414d226911040b52a5d61baa5beecb25e21 Mon Sep 17 00:00:00 2001 From: gornekich Date: Wed, 10 May 2023 17:24:08 +0400 Subject: [PATCH 072/149] nfc tests: add ntag216 --- applications/debug/unit_tests/nfc/nfc_test.c | 11 +- assets/unit_tests/nfc/Ntag215.nfc | 2 +- assets/unit_tests/nfc/Ntag216.nfc | 252 +++++++++++++++++++ 3 files changed, 261 insertions(+), 4 deletions(-) create mode 100644 assets/unit_tests/nfc/Ntag216.nfc diff --git a/applications/debug/unit_tests/nfc/nfc_test.c b/applications/debug/unit_tests/nfc/nfc_test.c index 8ed68bb08117..25434ef428fd 100644 --- a/applications/debug/unit_tests/nfc/nfc_test.c +++ b/applications/debug/unit_tests/nfc/nfc_test.c @@ -237,6 +237,10 @@ MU_TEST(ntag_215_reader) { mf_ultralight_reader_test(EXT_PATH("unit_tests/nfc/Ntag215.nfc")); } +MU_TEST(ntag_216_reader) { + mf_ultralight_reader_test(EXT_PATH("unit_tests/nfc/Ntag216.nfc")); +} + MU_TEST(ntag_213_locked_reader) { FURI_LOG_I(TAG, "Testing Ntag215 locked file"); NfcDev* nfc_dev = nfc_dev_alloc(); @@ -289,9 +293,10 @@ MU_TEST_SUITE(nfc) { nfc_test_alloc(); // MU_RUN_TEST(nfca_reader); - UNUSED(mf_ultralight_11_reader); - UNUSED(mf_ultralight_21_reader); - UNUSED(ntag_215_reader); + MU_RUN_TEST(mf_ultralight_11_reader); + MU_RUN_TEST(mf_ultralight_21_reader); + MU_RUN_TEST(ntag_215_reader); + MU_RUN_TEST(ntag_216_reader); MU_RUN_TEST(ntag_213_locked_reader); // MU_RUN_TEST(nfca_4b_file_test); diff --git a/assets/unit_tests/nfc/Ntag215.nfc b/assets/unit_tests/nfc/Ntag215.nfc index c134b512b0f1..420af08a66d2 100644 --- a/assets/unit_tests/nfc/Ntag215.nfc +++ b/assets/unit_tests/nfc/Ntag215.nfc @@ -14,7 +14,7 @@ Counter 0: 0 Tearing 0: 00 Counter 1: 0 Tearing 1: 00 -Counter 2: 95 +Counter 2: 00 Tearing 2: 00 Pages total: 135 Pages read: 135 diff --git a/assets/unit_tests/nfc/Ntag216.nfc b/assets/unit_tests/nfc/Ntag216.nfc new file mode 100644 index 000000000000..debe43858fd7 --- /dev/null +++ b/assets/unit_tests/nfc/Ntag216.nfc @@ -0,0 +1,252 @@ +Filetype: Flipper NFC device +Version: 2 +# Nfc device type can be UID, Mifare Ultralight, Mifare Classic, Bank card +Device type: NTAG216 +# UID, ATQA and SAK are common for all formats +UID: 04 D9 65 0A 32 5E 80 +ATQA: 44 00 +SAK: 00 +# Mifare Ultralight specific data +Data format version: 1 +Signature: 48 2A F2 01 0F F2 F5 A7 9A D5 79 6E CB 14 54 48 98 D1 57 5D 8A 23 A9 B0 E8 20 02 3E CD C8 16 DB +Mifare version: 00 04 04 02 01 00 13 03 +Counter 0: 0 +Tearing 0: 00 +Counter 1: 0 +Tearing 1: 00 +Counter 2: 0 +Tearing 2: 00 +Pages total: 231 +Pages read: 231 +Page 0: 04 D9 65 30 +Page 1: 0A 32 5E 80 +Page 2: E6 48 00 00 +Page 3: E1 10 6D 00 +Page 4: 03 37 D1 01 +Page 5: 33 55 04 6D +Page 6: 2E 79 6F 75 +Page 7: 74 75 62 65 +Page 8: 2E 63 6F 6D +Page 9: 2F 77 61 74 +Page 10: 63 68 3F 76 +Page 11: 3D 62 78 71 +Page 12: 4C 73 72 6C +Page 13: 61 6B 4B 38 +Page 14: 26 66 65 61 +Page 15: 74 75 72 65 +Page 16: 3D 79 6F 75 +Page 17: 74 75 2E 62 +Page 18: 65 FE 00 00 +Page 19: 00 00 00 00 +Page 20: 00 00 00 00 +Page 21: 00 00 00 00 +Page 22: 00 00 00 00 +Page 23: 00 00 00 00 +Page 24: 00 00 00 00 +Page 25: 00 00 00 00 +Page 26: 00 00 00 00 +Page 27: 00 00 00 00 +Page 28: 00 00 00 00 +Page 29: 00 00 00 00 +Page 30: 00 00 00 00 +Page 31: 00 00 00 00 +Page 32: 00 00 00 00 +Page 33: 00 00 00 00 +Page 34: 00 00 00 00 +Page 35: 00 00 00 00 +Page 36: 00 00 00 00 +Page 37: 00 00 00 00 +Page 38: 00 00 00 00 +Page 39: 00 00 00 00 +Page 40: 00 00 00 00 +Page 41: 00 00 00 00 +Page 42: 00 00 00 00 +Page 43: 00 00 00 00 +Page 44: 00 00 00 00 +Page 45: 00 00 00 00 +Page 46: 00 00 00 00 +Page 47: 00 00 00 00 +Page 48: 00 00 00 00 +Page 49: 00 00 00 00 +Page 50: 00 00 00 00 +Page 51: 00 00 00 00 +Page 52: 00 00 00 00 +Page 53: 00 00 00 00 +Page 54: 00 00 00 00 +Page 55: 00 00 00 00 +Page 56: 00 00 00 00 +Page 57: 00 00 00 00 +Page 58: 00 00 00 00 +Page 59: 00 00 00 00 +Page 60: 00 00 00 00 +Page 61: 00 00 00 00 +Page 62: 00 00 00 00 +Page 63: 00 00 00 00 +Page 64: 00 00 00 00 +Page 65: 00 00 00 00 +Page 66: 00 00 00 00 +Page 67: 00 00 00 00 +Page 68: 00 00 00 00 +Page 69: 00 00 00 00 +Page 70: 00 00 00 00 +Page 71: 00 00 00 00 +Page 72: 00 00 00 00 +Page 73: 00 00 00 00 +Page 74: 00 00 00 00 +Page 75: 00 00 00 00 +Page 76: 00 00 00 00 +Page 77: 00 00 00 00 +Page 78: 00 00 00 00 +Page 79: 00 00 00 00 +Page 80: 00 00 00 00 +Page 81: 00 00 00 00 +Page 82: 00 00 00 00 +Page 83: 00 00 00 00 +Page 84: 00 00 00 00 +Page 85: 00 00 00 00 +Page 86: 00 00 00 00 +Page 87: 00 00 00 00 +Page 88: 00 00 00 00 +Page 89: 00 00 00 00 +Page 90: 00 00 00 00 +Page 91: 00 00 00 00 +Page 92: 00 00 00 00 +Page 93: 00 00 00 00 +Page 94: 00 00 00 00 +Page 95: 00 00 00 00 +Page 96: 00 00 00 00 +Page 97: 00 00 00 00 +Page 98: 00 00 00 00 +Page 99: 00 00 00 00 +Page 100: 00 00 00 00 +Page 101: 00 00 00 00 +Page 102: 00 00 00 00 +Page 103: 00 00 00 00 +Page 104: 00 00 00 00 +Page 105: 00 00 00 00 +Page 106: 00 00 00 00 +Page 107: 00 00 00 00 +Page 108: 00 00 00 00 +Page 109: 00 00 00 00 +Page 110: 00 00 00 00 +Page 111: 00 00 00 00 +Page 112: 00 00 00 00 +Page 113: 00 00 00 00 +Page 114: 00 00 00 00 +Page 115: 00 00 00 00 +Page 116: 00 00 00 00 +Page 117: 00 00 00 00 +Page 118: 00 00 00 00 +Page 119: 00 00 00 00 +Page 120: 00 00 00 00 +Page 121: 00 00 00 00 +Page 122: 00 00 00 00 +Page 123: 00 00 00 00 +Page 124: 00 00 00 00 +Page 125: 00 00 00 00 +Page 126: 00 00 00 00 +Page 127: 00 00 00 00 +Page 128: 00 00 00 00 +Page 129: 00 00 00 00 +Page 130: 00 00 00 00 +Page 131: 00 00 00 00 +Page 132: 00 00 00 00 +Page 133: 00 00 00 00 +Page 134: 00 00 00 00 +Page 135: 00 00 00 00 +Page 136: 00 00 00 00 +Page 137: 00 00 00 00 +Page 138: 00 00 00 00 +Page 139: 00 00 00 00 +Page 140: 00 00 00 00 +Page 141: 00 00 00 00 +Page 142: 00 00 00 00 +Page 143: 00 00 00 00 +Page 144: 00 00 00 00 +Page 145: 00 00 00 00 +Page 146: 00 00 00 00 +Page 147: 00 00 00 00 +Page 148: 00 00 00 00 +Page 149: 00 00 00 00 +Page 150: 00 00 00 00 +Page 151: 00 00 00 00 +Page 152: 00 00 00 00 +Page 153: 00 00 00 00 +Page 154: 00 00 00 00 +Page 155: 00 00 00 00 +Page 156: 00 00 00 00 +Page 157: 00 00 00 00 +Page 158: 00 00 00 00 +Page 159: 00 00 00 00 +Page 160: 00 00 00 00 +Page 161: 00 00 00 00 +Page 162: 00 00 00 00 +Page 163: 00 00 00 00 +Page 164: 00 00 00 00 +Page 165: 00 00 00 00 +Page 166: 00 00 00 00 +Page 167: 00 00 00 00 +Page 168: 00 00 00 00 +Page 169: 00 00 00 00 +Page 170: 00 00 00 00 +Page 171: 00 00 00 00 +Page 172: 00 00 00 00 +Page 173: 00 00 00 00 +Page 174: 00 00 00 00 +Page 175: 00 00 00 00 +Page 176: 00 00 00 00 +Page 177: 00 00 00 00 +Page 178: 00 00 00 00 +Page 179: 00 00 00 00 +Page 180: 00 00 00 00 +Page 181: 00 00 00 00 +Page 182: 00 00 00 00 +Page 183: 00 00 00 00 +Page 184: 00 00 00 00 +Page 185: 00 00 00 00 +Page 186: 00 00 00 00 +Page 187: 00 00 00 00 +Page 188: 00 00 00 00 +Page 189: 00 00 00 00 +Page 190: 00 00 00 00 +Page 191: 00 00 00 00 +Page 192: 00 00 00 00 +Page 193: 00 00 00 00 +Page 194: 00 00 00 00 +Page 195: 00 00 00 00 +Page 196: 00 00 00 00 +Page 197: 00 00 00 00 +Page 198: 00 00 00 00 +Page 199: 00 00 00 00 +Page 200: 00 00 00 00 +Page 201: 00 00 00 00 +Page 202: 00 00 00 00 +Page 203: 00 00 00 00 +Page 204: 00 00 00 00 +Page 205: 00 00 00 00 +Page 206: 00 00 00 00 +Page 207: 00 00 00 00 +Page 208: 00 00 00 00 +Page 209: 00 00 00 00 +Page 210: 00 00 00 00 +Page 211: 00 00 00 00 +Page 212: 00 00 00 00 +Page 213: 00 00 00 00 +Page 214: 00 00 00 00 +Page 215: 00 00 00 00 +Page 216: 00 00 00 00 +Page 217: 00 00 00 00 +Page 218: 00 00 00 00 +Page 219: 00 00 00 00 +Page 220: 00 00 00 00 +Page 221: 00 00 00 00 +Page 222: 00 00 00 00 +Page 223: 00 00 00 00 +Page 224: 00 00 00 00 +Page 225: 00 00 00 00 +Page 226: 00 00 00 BD +Page 227: 04 00 00 FF +Page 228: 00 05 00 00 +Page 229: 00 00 00 00 +Page 230: 00 00 00 00 +Failed authentication attempts: 0 From 4bbdadeaff4bb6adbb1bbe157dacd0a5d0590e17 Mon Sep 17 00:00:00 2001 From: gornekich Date: Wed, 10 May 2023 19:33:00 +0400 Subject: [PATCH 073/149] nfc tests: add write test --- applications/debug/unit_tests/nfc/nfc_test.c | 332 +++++++++++------- .../mf_ultralight/mf_ultralight_listener.c | 43 +++ .../mf_ultralight/mf_ultralight_listener.h | 3 + .../mf_ultralight/mf_ultralight_poller.c | 2 + .../mf_ultralight/mf_ultralight_poller_i.c | 7 +- 5 files changed, 251 insertions(+), 136 deletions(-) diff --git a/applications/debug/unit_tests/nfc/nfc_test.c b/applications/debug/unit_tests/nfc/nfc_test.c index 25434ef428fd..8986796cbd87 100644 --- a/applications/debug/unit_tests/nfc/nfc_test.c +++ b/applications/debug/unit_tests/nfc/nfc_test.c @@ -37,151 +37,151 @@ static void nfc_test_free() { nfc_test = NULL; } -// static void nfc_test_save_and_load(NfcDevData* data) { -// NfcDev* nfc_dev = nfc_dev_alloc(); +static void nfc_test_save_and_load(NfcDevData* data) { + NfcDev* nfc_dev = nfc_dev_alloc(); -// NfcDevData* nfc_dev_data_dut = malloc(sizeof(NfcDevData)); + NfcDevData* nfc_dev_data_dut = malloc(sizeof(NfcDevData)); -// mu_assert(nfc_dev_save(nfc_dev, data, NFC_TEST_NFC_DEV_PATH), "nfc_dev_save() failed\r\n"); + mu_assert(nfc_dev_save(nfc_dev, data, NFC_TEST_NFC_DEV_PATH), "nfc_dev_save() failed\r\n"); -// mu_assert( -// nfc_dev_load(nfc_dev, nfc_dev_data_dut, NFC_TEST_NFC_DEV_PATH), -// "nfc_dev_load() failed\r\n"); + mu_assert( + nfc_dev_load(nfc_dev, nfc_dev_data_dut, NFC_TEST_NFC_DEV_PATH), + "nfc_dev_load() failed\r\n"); -// mu_assert( -// memcmp(nfc_dev_data_dut, data, sizeof(NfcDevData)) == 0, -// "nfc_dev_data_dut != nfc_dev_data_ref\r\n"); + mu_assert( + memcmp(nfc_dev_data_dut, data, sizeof(NfcDevData)) == 0, + "nfc_dev_data_dut != nfc_dev_data_ref\r\n"); -// mu_assert( -// storage_simply_remove(nfc_test->storage, NFC_TEST_NFC_DEV_PATH), -// "storage_simply_remove() failed\r\n"); + mu_assert( + storage_simply_remove(nfc_test->storage, NFC_TEST_NFC_DEV_PATH), + "storage_simply_remove() failed\r\n"); -// free(nfc_dev_data_dut); -// nfc_dev_free(nfc_dev); -// } + free(nfc_dev_data_dut); + nfc_dev_free(nfc_dev); +} -// static void nfca_file_test(uint8_t uid_len) { -// NfcDevData* nfc_dev_data_ref = malloc(sizeof(NfcDevData)); -// mu_assert(nfc_dev_data_ref != NULL, "malloc() failed\r\n"); +static void nfca_file_test(uint8_t uid_len) { + NfcDevData* nfc_dev_data_ref = malloc(sizeof(NfcDevData)); + mu_assert(nfc_dev_data_ref != NULL, "malloc() failed\r\n"); -// NfcaData* data = &nfc_dev_data_ref->nfca_data; + NfcaData* data = &nfc_dev_data_ref->nfca_data; -// data->uid_len = uid_len; -// furi_hal_random_fill_buf(data->uid, uid_len); -// furi_hal_random_fill_buf(data->atqa, 2); -// furi_hal_random_fill_buf(&data->sak, 1); + data->uid_len = uid_len; + furi_hal_random_fill_buf(data->uid, uid_len); + furi_hal_random_fill_buf(data->atqa, 2); + furi_hal_random_fill_buf(&data->sak, 1); -// nfc_test_save_and_load(nfc_dev_data_ref); + nfc_test_save_and_load(nfc_dev_data_ref); -// free(nfc_dev_data_ref); -// } + free(nfc_dev_data_ref); +} -// static void mf_ultralight_file_test_with_generator(NfcDataGeneratorType type) { -// NfcDevData* nfc_dev_data_ref = malloc(sizeof(NfcDevData)); -// mu_assert(nfc_dev_data_ref != NULL, "malloc() failed\r\n"); +static void mf_ultralight_file_test_with_generator(NfcDataGeneratorType type) { + NfcDevData* nfc_dev_data_ref = malloc(sizeof(NfcDevData)); + mu_assert(nfc_dev_data_ref != NULL, "malloc() failed\r\n"); -// nfc_data_generator_fill_data(type, nfc_dev_data_ref); -// nfc_test_save_and_load(nfc_dev_data_ref); + nfc_data_generator_fill_data(type, nfc_dev_data_ref); + nfc_test_save_and_load(nfc_dev_data_ref); -// free(nfc_dev_data_ref); -// } + free(nfc_dev_data_ref); +} -// MU_TEST(nfca_4b_file_test) { -// nfca_file_test(4); -// } +MU_TEST(nfca_4b_file_test) { + nfca_file_test(4); +} -// MU_TEST(nfca_7b_file_test) { -// nfca_file_test(7); -// } +MU_TEST(nfca_7b_file_test) { + nfca_file_test(7); +} -// MU_TEST(mf_ultralight_file_test) { -// mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeMfUltralight); -// } +MU_TEST(mf_ultralight_file_test) { + mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeMfUltralight); +} -// MU_TEST(mf_ultralight_ev1_11_file_test) { -// mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeMfUltralightEV1_11); -// } +MU_TEST(mf_ultralight_ev1_11_file_test) { + mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeMfUltralightEV1_11); +} -// MU_TEST(mf_ultralight_ev1_h11_file_test) { -// mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeMfUltralightEV1_H11); -// } +MU_TEST(mf_ultralight_ev1_h11_file_test) { + mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeMfUltralightEV1_H11); +} -// MU_TEST(mf_ultralight_ev1_21_file_test) { -// mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeMfUltralightEV1_21); -// } +MU_TEST(mf_ultralight_ev1_21_file_test) { + mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeMfUltralightEV1_21); +} -// MU_TEST(mf_ultralight_ev1_h21_file_test) { -// mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeMfUltralightEV1_H21); -// } +MU_TEST(mf_ultralight_ev1_h21_file_test) { + mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeMfUltralightEV1_H21); +} -// MU_TEST(mf_ultralight_ntag_203_file_test) { -// mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeNTAG203); -// } +MU_TEST(mf_ultralight_ntag_203_file_test) { + mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeNTAG203); +} -// MU_TEST(mf_ultralight_ntag_213_file_test) { -// mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeNTAG213); -// } +MU_TEST(mf_ultralight_ntag_213_file_test) { + mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeNTAG213); +} -// MU_TEST(mf_ultralight_ntag_215_file_test) { -// mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeNTAG215); -// } +MU_TEST(mf_ultralight_ntag_215_file_test) { + mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeNTAG215); +} -// MU_TEST(mf_ultralight_ntag_216_file_test) { -// mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeNTAG216); -// } +MU_TEST(mf_ultralight_ntag_216_file_test) { + mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeNTAG216); +} -// MU_TEST(mf_ultralight_ntag_i2c_1k_file_test) { -// mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeNTAGI2C1k); -// } +MU_TEST(mf_ultralight_ntag_i2c_1k_file_test) { + mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeNTAGI2C1k); +} -// MU_TEST(mf_ultralight_ntag_i2c_2k_file_test) { -// mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeNTAGI2C2k); -// } +MU_TEST(mf_ultralight_ntag_i2c_2k_file_test) { + mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeNTAGI2C2k); +} -// MU_TEST(mf_ultralight_ntag_i2c_plus_1k_file_test) { -// mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeNTAGI2CPlus1k); -// } +MU_TEST(mf_ultralight_ntag_i2c_plus_1k_file_test) { + mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeNTAGI2CPlus1k); +} -// MU_TEST(mf_ultralight_ntag_i2c_plus_2k_file_test) { -// mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeNTAGI2CPlus2k); -// } +MU_TEST(mf_ultralight_ntag_i2c_plus_2k_file_test) { + mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeNTAGI2CPlus2k); +} -// MU_TEST(nfca_reader) { -// Nfc* poller = nfc_alloc(); -// Nfc* listener = nfc_alloc(); +MU_TEST(nfca_reader) { + Nfc* poller = nfc_alloc(); + Nfc* listener = nfc_alloc(); -// NfcaPoller* nfca_poller = nfca_poller_alloc(poller); -// NfcaListener* nfca_listener = nfca_listener_alloc(listener); + NfcaPoller* nfca_poller = nfca_poller_alloc(poller); + NfcaListener* nfca_listener = nfca_listener_alloc(listener); -// NfcaData nfca_listener_data = { -// .uid_len = 7, -// .uid = {0x04, 0x51, 0x5C, 0xFA, 0x6F, 0x73, 0x81}, -// .atqa = {0x44, 0x00}, -// .sak = 0x00, -// }; -// // nfca_listener_data.uid_len = 7; -// // furi_hal_random_fill_buf(nfca_listener_data.uid, 7); -// // furi_hal_random_fill_buf(nfca_listener_data.atqa, 2); -// // furi_hal_random_fill_buf(&nfca_listener_data.sak, 1); -// NfcaData nfca_poller_data = {}; + NfcaData nfca_listener_data = { + .uid_len = 7, + .uid = {0x04, 0x51, 0x5C, 0xFA, 0x6F, 0x73, 0x81}, + .atqa = {0x44, 0x00}, + .sak = 0x00, + }; + // nfca_listener_data.uid_len = 7; + // furi_hal_random_fill_buf(nfca_listener_data.uid, 7); + // furi_hal_random_fill_buf(nfca_listener_data.atqa, 2); + // furi_hal_random_fill_buf(&nfca_listener_data.sak, 1); + NfcaData nfca_poller_data = {}; -// mu_assert( -// nfca_listener_start(nfca_listener, &nfca_listener_data, NULL, NULL) == NfcaErrorNone, -// "nfca_listener_start() failed"); + mu_assert( + nfca_listener_start(nfca_listener, &nfca_listener_data, NULL, NULL) == NfcaErrorNone, + "nfca_listener_start() failed"); -// mu_assert( -// nfca_poller_read(nfca_poller, &nfca_poller_data) == NfcaErrorNone, -// "nfca_poller_read() failed"); -// mu_assert(nfca_listener_stop(nfca_listener) == NfcaErrorNone, "nfca_listener_stop() failed"); - -// mu_assert( -// memcmp(&nfca_poller_data, &nfca_listener_data, sizeof(NfcaData)) == 0, "Data not matches"); - -// nfca_listener_free(nfca_listener); -// nfc_free(listener); -// nfca_poller_free(nfca_poller); -// nfc_free(poller); -// } + mu_assert( + nfca_poller_read(nfca_poller, &nfca_poller_data) == NfcaErrorNone, + "nfca_poller_read() failed"); + mu_assert(nfca_listener_stop(nfca_listener) == NfcaErrorNone, "nfca_listener_stop() failed"); + + mu_assert( + memcmp(&nfca_poller_data, &nfca_listener_data, sizeof(NfcaData)) == 0, "Data not matches"); + + nfca_listener_free(nfca_listener); + nfc_free(listener); + nfca_poller_free(nfca_poller); + nfc_free(poller); +} static void mf_ultralight_reader_test(const char* path) { FURI_LOG_I(TAG, "Testing file: %s", path); @@ -289,32 +289,96 @@ MU_TEST(ntag_213_locked_reader) { nfc_dev_free(nfc_dev); } +static void mf_ultralight_write() { + NfcDev* nfc_dev = nfc_dev_alloc(); + Nfc* poller = nfc_alloc(); + Nfc* listener = nfc_alloc(); + + NfcaPoller* nfca_poller = nfca_poller_alloc(poller); + NfcaListener* nfca_listener = nfca_listener_alloc(listener); + + MfUltralightPoller* mfu_poller = mf_ultralight_poller_alloc(nfca_poller); + MfUltralightListener* mfu_listener = mf_ultralight_listener_alloc(nfca_listener); + + MfUltralightError error = MfUltralightErrorNone; + NfcDevData* dev_data = malloc(sizeof(NfcDevData)); + nfc_data_generator_fill_data(NfcDataGeneratorTypeMfUltralightEV1_21, dev_data); + + error = mf_ultralight_listener_start(mfu_listener, &dev_data->mf_ul_data, NULL, NULL); + mu_assert(error == MfUltralightErrorNone, "mf_ultralight_listener_start() failed"); + + MfUltralightData* mfu_data = malloc(sizeof(MfUltralightData)); + + // Initial read + error = mf_ultralight_poller_read_card(mfu_poller, mfu_data); + mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_read_card() failed"); + + mu_assert( + memcmp(mfu_data, &dev_data->mf_ul_data, sizeof(MfUltralightData)) == 0, + "Data not matches"); + + // Write random data + for(size_t i = 5; i < 15; i++) { + MfUltralightPage page = {}; + FURI_LOG_D(TAG, "Writing page %d", i); + furi_hal_random_fill_buf(page.data, sizeof(MfUltralightPage)); + mfu_data->page[i] = page; + error = mf_ultralight_poller_write_page(mfu_poller, i, &page); + mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_read_card() failed"); + } + + // Verification read + error = mf_ultralight_poller_read_card(mfu_poller, mfu_data); + mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_read_card() failed"); + + mf_ultralight_listener_get_data(mfu_listener, &dev_data->mf_ul_data); + error = mf_ultralight_listener_stop(mfu_listener); + + mu_assert(error == MfUltralightErrorNone, "mf_ultralight_listener_stop() failed"); + + mu_assert( + memcmp(mfu_data, &dev_data->mf_ul_data, sizeof(MfUltralightData)) == 0, + "Data not matches"); + + free(mfu_data); + free(dev_data); + mf_ultralight_listener_free(mfu_listener); + mf_ultralight_poller_free(mfu_poller); + nfca_listener_free(nfca_listener); + nfc_free(listener); + nfca_poller_free(nfca_poller); + nfc_free(poller); + nfc_dev_free(nfc_dev); +} + MU_TEST_SUITE(nfc) { nfc_test_alloc(); - // MU_RUN_TEST(nfca_reader); - MU_RUN_TEST(mf_ultralight_11_reader); - MU_RUN_TEST(mf_ultralight_21_reader); - MU_RUN_TEST(ntag_215_reader); - MU_RUN_TEST(ntag_216_reader); - MU_RUN_TEST(ntag_213_locked_reader); - - // MU_RUN_TEST(nfca_4b_file_test); - // MU_RUN_TEST(nfca_7b_file_test); - - // MU_RUN_TEST(mf_ultralight_file_test); - // MU_RUN_TEST(mf_ultralight_ev1_11_file_test); - // MU_RUN_TEST(mf_ultralight_ev1_h11_file_test); - // MU_RUN_TEST(mf_ultralight_ev1_21_file_test); - // MU_RUN_TEST(mf_ultralight_ev1_h21_file_test); - // MU_RUN_TEST(mf_ultralight_ntag_203_file_test); - // MU_RUN_TEST(mf_ultralight_ntag_213_file_test); - // MU_RUN_TEST(mf_ultralight_ntag_215_file_test); - // MU_RUN_TEST(mf_ultralight_ntag_216_file_test); - // MU_RUN_TEST(mf_ultralight_ntag_i2c_1k_file_test); - // MU_RUN_TEST(mf_ultralight_ntag_i2c_2k_file_test); - // MU_RUN_TEST(mf_ultralight_ntag_i2c_plus_1k_file_test); - // MU_RUN_TEST(mf_ultralight_ntag_i2c_plus_2k_file_test); + UNUSED(nfca_reader); + UNUSED(mf_ultralight_11_reader); + UNUSED(mf_ultralight_21_reader); + UNUSED(ntag_215_reader); + UNUSED(ntag_216_reader); + UNUSED(ntag_213_locked_reader); + + MU_RUN_TEST(mf_ultralight_write); + + UNUSED(nfca_4b_file_test); + UNUSED(nfca_7b_file_test); + + UNUSED(mf_ultralight_file_test); + UNUSED(mf_ultralight_ev1_11_file_test); + UNUSED(mf_ultralight_ev1_h11_file_test); + UNUSED(mf_ultralight_ev1_21_file_test); + UNUSED(mf_ultralight_ev1_h21_file_test); + UNUSED(mf_ultralight_ntag_203_file_test); + UNUSED(mf_ultralight_ntag_213_file_test); + UNUSED(mf_ultralight_ntag_215_file_test); + UNUSED(mf_ultralight_ntag_216_file_test); + UNUSED(mf_ultralight_ntag_i2c_1k_file_test); + UNUSED(mf_ultralight_ntag_i2c_2k_file_test); + UNUSED(mf_ultralight_ntag_i2c_plus_1k_file_test); + UNUSED(mf_ultralight_ntag_i2c_plus_2k_file_test); nfc_test_free(); } diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c index 61600a41b516..16d8611aa39b 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c @@ -145,6 +145,33 @@ static bool mf_ultralight_listener_read_page_handler( return command_processed; } +static bool mf_ultralight_listener_write_page_handler( + MfUltralightListener* instance, + uint8_t* rx_data, + uint16_t rx_bits) { + UNUSED(rx_bits); + bool command_processed = false; + uint8_t start_page = rx_data[1]; + uint16_t pages_total = instance->data->pages_total; + + if(pages_total < start_page) { + mf_ultralight_listener_send_short_resp(instance, MF_ULTRALIGHT_CMD_NACK); + instance->state = MfUltraligthListenerStateIdle; + instance->auth_state = MfUltralightListenerAuthStateIdle; + } else if(!mf_ultralight_listener_check_access( + instance, start_page, MfUltralightListenerAccessTypeWrite)) { + mf_ultralight_listener_send_short_resp(instance, MF_ULTRALIGHT_CMD_NACK); + instance->state = MfUltraligthListenerStateIdle; + instance->auth_state = MfUltralightListenerAuthStateIdle; + } else { + memcpy(instance->data->page[start_page].data, &rx_data[2], sizeof(MfUltralightPage)); + mf_ultralight_listener_send_short_resp(instance, MF_ULTRALIGHT_CMD_ACK); + } + command_processed = true; + + return command_processed; +} + static bool mf_ultralight_listener_read_version_handler( MfUltralightListener* instance, uint8_t* rx_data, @@ -288,6 +315,11 @@ static const MfUltralightListenerCmdHandler mf_ultralight_command[] = { .cmd_len_bits = 2 * 8, .callback = mf_ultralight_listener_read_page_handler, }, + { + .cmd = MF_ULTRALIGHT_CMD_WRITE_PAGE, + .cmd_len_bits = 6 * 8, + .callback = mf_ultralight_listener_write_page_handler, + }, { .cmd = MF_ULTRALIGHT_CMD_GET_VERSION, .cmd_len_bits = 8, @@ -386,6 +418,17 @@ void mf_ultralight_listener_free(MfUltralightListener* instance) { free(instance); } +MfUltralightError + mf_ultralight_listener_get_data(MfUltralightListener* instance, MfUltralightData* data) { + furi_assert(instance); + furi_assert(instance->data); + furi_assert(data); + + *data = *instance->data; + + return MfUltralightErrorNone; +} + MfUltralightError mf_ultralight_listener_stop(MfUltralightListener* instance) { furi_assert(instance); furi_assert(instance->data); diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.h index ec0d126beea3..6858b4657db0 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.h @@ -42,6 +42,9 @@ MfUltralightError mf_ultralight_listener_start( MfUltralightListenerEventCallback callback, void* context); +MfUltralightError + mf_ultralight_listener_get_data(MfUltralightListener* instance, MfUltralightData* data); + MfUltralightError mf_ultralight_listener_stop(MfUltralightListener* instance); #ifdef __cplusplus diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c index c870960aca47..df5fb693a8ec 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c @@ -295,6 +295,7 @@ static MfUltralightPollerCommand static MfUltralightPollerCommand mf_ultralight_poller_handler_read_fail(MfUltralightPoller* instance) { FURI_LOG_D(TAG, "Read Failed"); + nfca_poller_halt(instance->nfca_poller); MfUltralightPollerEventData event_data = {.error = instance->error}; MfUltralightPollerEvent event = { .type = MfUltralightPollerEventTypeReadFailed, .data = &event_data}; @@ -306,6 +307,7 @@ static MfUltralightPollerCommand static MfUltralightPollerCommand mf_ultralight_poller_handler_read_success(MfUltralightPoller* instance) { FURI_LOG_D(TAG, "Read success."); + nfca_poller_halt(instance->nfca_poller); MfUltralightPollerEvent event = {.type = MfUltralightPollerEventTypeReadSuccess}; MfUltralightPollerCommand command = instance->callback(event, instance->context); return command; diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c index 45aca68941d0..4f4fdd64c504 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c @@ -331,8 +331,7 @@ MfUltralightError mf_ultralight_poller_async_write_page( buff->rx_data_size, &buff->rx_bits, MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); - FURI_LOG_D(TAG, "Rx bits: %d", buff->rx_bits); - if(error != NfcaErrorNone) { + if(error != NfcaErrorWrongCrc) { ret = mf_ultralight_process_error(error); break; } @@ -340,6 +339,10 @@ MfUltralightError mf_ultralight_poller_async_write_page( ret = MfUltralightErrorProtocol; break; } + if(buff->rx_data[0] != MF_ULTRALIGHT_CMD_ACK) { + ret = MfUltralightErrorProtocol; + break; + } memcpy(&instance->data->page[page], buff->rx_data, MF_ULTRALIGHT_PAGE_SIZE); } while(false); From 5a29f7c393ab6baa4f5e6fa5a5b88151619ff62c Mon Sep 17 00:00:00 2001 From: gornekich Date: Thu, 11 May 2023 01:03:38 +0400 Subject: [PATCH 074/149] nfc app: rework shadow files --- applications/main/nfc/nfc_app.c | 88 +++++++++++++++++-- applications/main/nfc/nfc_app_i.h | 6 ++ .../main/nfc/scenes/nfc_scene_config.h | 1 + .../scenes/nfc_scene_mf_ultralight_emulate.c | 61 +++++++++++++ .../nfc/scenes/nfc_scene_mf_ultralight_menu.c | 2 +- 5 files changed, 150 insertions(+), 8 deletions(-) create mode 100644 applications/main/nfc/scenes/nfc_scene_mf_ultralight_emulate.c diff --git a/applications/main/nfc/nfc_app.c b/applications/main/nfc/nfc_app.c index e68b6b9def8c..e1f2753b9768 100644 --- a/applications/main/nfc/nfc_app.c +++ b/applications/main/nfc/nfc_app.c @@ -117,7 +117,7 @@ NfcApp* nfc_app_alloc() { instance->widget = widget_alloc(); view_dispatcher_add_view( instance->view_dispatcher, NfcViewWidget, widget_get_view(instance->widget)); - + instance->file_path = furi_string_alloc_set(NFC_APP_FOLDER); instance->file_name = furi_string_alloc(); @@ -262,9 +262,49 @@ bool nfc_save_file(NfcApp* instance, FuriString* path) { return result; } -bool nfc_save(NfcApp* instance) { +static bool nfc_set_shadow_file_path(FuriString* file_path, FuriString* shadow_file_path) { + furi_assert(file_path); + furi_assert(shadow_file_path); + + bool shadow_file_path_set = false; + if(furi_string_end_with(file_path, NFC_APP_EXTENSION)) { + size_t path_len = furi_string_size(file_path); + // Cut .nfc + furi_string_set_n(shadow_file_path, file_path, 0, path_len - 4); + furi_string_cat_printf(shadow_file_path, "%s", NFC_APP_SHADOW_EXTENSION); + shadow_file_path_set = true; + } + + return shadow_file_path_set; +} + +static bool nfc_has_shadow_file_internal(NfcApp* instance, FuriString* path) { + furi_assert(path); + + bool has_shadow_file = false; + FuriString* shadow_file_path = furi_string_alloc(); + do { + if(furi_string_empty(path)) break; + if(!nfc_set_shadow_file_path(path, shadow_file_path)) break; + has_shadow_file = + storage_common_exists(instance->storage, furi_string_get_cstr(shadow_file_path)); + } while(false); + + furi_string_free(shadow_file_path); + + return has_shadow_file; +} + +bool nfc_has_shadow_file(NfcApp* instance) { furi_assert(instance); + return nfc_has_shadow_file_internal(instance, instance->file_path); +} + +static bool nfc_save_internal(NfcApp* instance, const char* extension) { + furi_assert(instance); + furi_assert(extension); + bool result = false; nfc_make_app_folder(instance); @@ -275,33 +315,68 @@ bool nfc_save(NfcApp* instance) { } furi_string_cat_printf( - instance->file_path, "/%s%s", furi_string_get_cstr(instance->file_name), NFC_APP_EXTENSION); + instance->file_path, "/%s%s", furi_string_get_cstr(instance->file_name), extension); result = nfc_save_file(instance, instance->file_path); + return result; } +bool nfc_save_shadow_file(NfcApp* instance) { + furi_assert(instance); + + return nfc_save_internal(instance, NFC_APP_EXTENSION); +} + +bool nfc_save(NfcApp* instance) { + furi_assert(instance); + + return nfc_save_internal(instance, NFC_APP_SHADOW_EXTENSION); +} + bool nfc_load_file(NfcApp* instance, FuriString* path, bool show_dialog) { furi_assert(instance); furi_assert(path); bool result = false; - result = nfc_dev_load(instance->nfc_dev, &instance->nfc_dev_data, furi_string_get_cstr(path)); + FuriString* load_path = furi_string_alloc(); + if(nfc_has_shadow_file_internal(instance, path)) { + nfc_set_shadow_file_path(path, load_path); + } else { + furi_string_set(load_path, path); + } + + result = + nfc_dev_load(instance->nfc_dev, &instance->nfc_dev_data, furi_string_get_cstr(load_path)); if(result) { - path_extract_filename(path, instance->file_name, true); + path_extract_filename(load_path, instance->file_name, true); } if((!result) && (show_dialog)) { dialog_message_show_storage_error(instance->dialogs, "Cannot load\nkey file"); } + furi_string_free(load_path); + return result; } bool nfc_delete(NfcApp* instance) { furi_assert(instance); - return storage_simply_remove(instance->storage, furi_string_get_cstr(instance->file_path)); + bool result = false; + FuriString* shadow_file_path = furi_string_alloc(); + + if(nfc_has_shadow_file(instance)) { + nfc_set_shadow_file_path(instance->file_path, shadow_file_path); + storage_simply_remove(instance->storage, furi_string_get_cstr(shadow_file_path)); + } + + result = storage_simply_remove(instance->storage, furi_string_get_cstr(instance->file_path)); + + furi_string_free(shadow_file_path); + + return result; } bool nfc_load_from_file_select(NfcApp* instance) { @@ -312,7 +387,6 @@ bool nfc_load_from_file_select(NfcApp* instance) { browser_options.base_path = NFC_APP_FOLDER; browser_options.hide_dot_files = true; - // Input events and views are managed by file_browser bool result = dialog_file_browser_show( instance->dialogs, instance->file_path, instance->file_path, &browser_options); diff --git a/applications/main/nfc/nfc_app_i.h b/applications/main/nfc/nfc_app_i.h index c41ac4ace93a..bb28dce43366 100644 --- a/applications/main/nfc/nfc_app_i.h +++ b/applications/main/nfc/nfc_app_i.h @@ -53,6 +53,8 @@ #define NFC_TEXT_STORE_SIZE 128 #define NFC_APP_FOLDER ANY_PATH("nfc") #define NFC_APP_EXTENSION ".nfc" +#define NFC_APP_SHADOW_EXTENSION ".shd" + typedef enum { NfcRpcStateIdle, @@ -131,6 +133,10 @@ void nfc_blink_stop(NfcApp* nfc); void nfc_show_loading_popup(void* context, bool show); +bool nfc_has_shadow_file(NfcApp* instance); + +bool nfc_save_shadow_file(NfcApp* instance); + bool nfc_save(NfcApp* instance); bool nfc_delete(NfcApp* instance); diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index e2b0042b09dd..a64fa5a84849 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -15,6 +15,7 @@ ADD_SCENE(nfc, retry_confirm, RetryConfirm) ADD_SCENE(nfc, exit_confirm, ExitConfirm) ADD_SCENE(nfc, mf_ultralight_read, MfUltralightRead) ADD_SCENE(nfc, mf_ultralight_read_success, MfUltralightReadSuccess) +ADD_SCENE(nfc, mf_ultralight_emulate, MfUltralightEmulate) ADD_SCENE(nfc, mf_ultralight_menu, MfUltralightMenu) ADD_SCENE(nfc, mf_ultralight_unlock_menu, MfUltralightUnlockMenu) ADD_SCENE(nfc, mf_ultralight_unlock_warn, MfUltralightUnlockWarn) diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_emulate.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_emulate.c new file mode 100644 index 000000000000..024f050a1a4e --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_emulate.c @@ -0,0 +1,61 @@ +#include "../nfc_app_i.h" + +void nfc_scene_mf_ultralight_emulate_on_enter(void* context) { + NfcApp* nfc = context; + + // Setup view + MfUltralightData* data = &nfc->nfc_dev_data.mf_ul_data; + MfUltralightType type = data->type; + bool is_ultralight = (type == MfUltralightTypeUL11) || (type == MfUltralightTypeUL21) || + (type == MfUltralightTypeUnknown); + Popup* popup = nfc->popup; + popup_set_header(popup, "Emulating", 67, 13, AlignLeft, AlignTop); + if(!furi_string_empty(nfc->file_name)) { + nfc_text_store_set(nfc, "%s", furi_string_get_cstr(nfc->file_name)); + } else if(is_ultralight) { + nfc_text_store_set(nfc, "MIFARE\nUltralight"); + } else { + nfc_text_store_set(nfc, "MIFARE\nNTAG"); + } + popup_set_icon(popup, 0, 3, &I_NFC_dolphin_emulation_47x61); + popup_set_text(popup, nfc->text_store, 90, 28, AlignCenter, AlignTop); + + // Setup and start worker + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); + mf_ultralight_listener_start(nfc->mf_ul_listener, data, NULL, NULL); + + nfc_blink_emulate_start(nfc); +} + +bool nfc_scene_mf_ultralight_emulate_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeBack) { + MfUltralightData* mfu_data_after_emulation = malloc(sizeof(MfUltralightData)); + mf_ultralight_listener_get_data(nfc->mf_ul_listener, mfu_data_after_emulation); + mf_ultralight_listener_stop(nfc->mf_ul_listener); + // Check if data changed and save in shadow file + if(memcmp( + mfu_data_after_emulation, + &nfc->nfc_dev_data.mf_ul_data, + sizeof(MfUltralightData)) != 0) { + // Save shadow file + if(!furi_string_empty(nfc->file_name)) { + nfc_save_shadow_file(nfc); + } + } + free(mfu_data_after_emulation); + consumed = false; + } + return consumed; +} + +void nfc_scene_mf_ultralight_emulate_on_exit(void* context) { + NfcApp* nfc = context; + + // Clear view + popup_reset(nfc->popup); + + nfc_blink_stop(nfc); +} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c index 4525fab97a7c..cd3e29bdc11c 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c @@ -53,7 +53,7 @@ bool nfc_scene_mf_ultralight_menu_on_event(void* context, SceneManagerEvent even scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); consumed = true; } else if(event.event == SubmenuIndexEmulate) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate); // if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) { // DOLPHIN_DEED(DolphinDeedNfcAddEmulate); // } else { From 2d57b09ee63b3f910ef282a67cb071a034291992 Mon Sep 17 00:00:00 2001 From: gornekich Date: Thu, 11 May 2023 13:24:33 +0400 Subject: [PATCH 075/149] nfc app: add delete scenes --- .../main/nfc/scenes/nfc_scene_config.h | 3 + .../main/nfc/scenes/nfc_scene_delete.c | 77 +++++++++++++++++++ .../nfc/scenes/nfc_scene_delete_success.c | 45 +++++++++++ .../main/nfc/scenes/nfc_scene_saved_menu.c | 6 +- 4 files changed, 128 insertions(+), 3 deletions(-) create mode 100644 applications/main/nfc/scenes/nfc_scene_delete.c create mode 100644 applications/main/nfc/scenes/nfc_scene_delete_success.c diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index a64fa5a84849..d6037f85b239 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -3,6 +3,9 @@ ADD_SCENE(nfc, file_select, FileSelect) ADD_SCENE(nfc, saved_menu, SavedMenu) ADD_SCENE(nfc, save_name, SaveName) ADD_SCENE(nfc, save_success, SaveSuccess) +ADD_SCENE(nfc, delete, Delete) +ADD_SCENE(nfc, delete_success, DeleteSuccess) + ADD_SCENE(nfc, read, Read) ADD_SCENE(nfc, read_card_type, ReadCardType) ADD_SCENE(nfc, nfca_read, NfcaRead) diff --git a/applications/main/nfc/scenes/nfc_scene_delete.c b/applications/main/nfc/scenes/nfc_scene_delete.c new file mode 100644 index 000000000000..5cb872d897a5 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_delete.c @@ -0,0 +1,77 @@ +#include "../nfc_app_i.h" + +void nfc_scene_delete_widget_callback(GuiButtonType result, InputType type, void* context) { + NfcApp* nfc = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); + } +} + +void nfc_scene_delete_on_enter(void* context) { + NfcApp* nfc = context; + + // Setup Custom Widget view + FuriString* temp_str; + temp_str = furi_string_alloc(); + + furi_string_printf(temp_str, "\e#Delete %s?\e#", furi_string_get_cstr(nfc->file_name)); + widget_add_text_box_element( + nfc->widget, 0, 0, 128, 23, AlignCenter, AlignCenter, furi_string_get_cstr(temp_str), false); + widget_add_button_element( + nfc->widget, GuiButtonTypeLeft, "Cancel", nfc_scene_delete_widget_callback, nfc); + widget_add_button_element( + nfc->widget, GuiButtonTypeRight, "Delete", nfc_scene_delete_widget_callback, nfc); + + NfcaData* nfca_data = &nfc->nfc_dev_data.nfca_data; + furi_string_set(temp_str, "UID:"); + for(size_t i = 0; i < nfca_data->uid_len; i++) { + furi_string_cat_printf(temp_str, " %02X", nfca_data->uid[i]); + } + widget_add_string_element( + nfc->widget, 64, 24, AlignCenter, AlignTop, FontSecondary, furi_string_get_cstr(temp_str)); + + NfcDevProtocol protocol = nfc->nfc_dev_data.protocol; + if(protocol == NfcDevProtocolMfUltralight) { + furi_string_set_str( + temp_str, mf_ultralight_get_name(nfc->nfc_dev_data.mf_ul_data.type, true)); + } else if(protocol == NfcDevProtocolMfClassic) { + furi_string_set(temp_str, "Mifare Classic"); + // furi_string_set(temp_str, nfc_mf_classic_type(nfc->dev->dev_data.mf_classic_data.type)); + } else if(protocol == NfcDevProtocolMfDesfire) { + furi_string_set(temp_str, "MIFARE DESFire"); + } else { + furi_string_set(temp_str, "Unknown ISO tag"); + } + widget_add_string_element( + nfc->widget, 64, 34, AlignCenter, AlignTop, FontSecondary, furi_string_get_cstr(temp_str)); + widget_add_string_element(nfc->widget, 64, 44, AlignCenter, AlignTop, FontSecondary, "NFC-A"); + furi_string_free(temp_str); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); +} + +bool nfc_scene_delete_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeLeft) { + consumed = scene_manager_previous_scene(nfc->scene_manager); + } else if(event.event == GuiButtonTypeRight) { + if(nfc_delete(nfc)) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneDeleteSuccess); + } else { + scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneStart); + } + consumed = true; + } + } + return consumed; +} + +void nfc_scene_delete_on_exit(void* context) { + NfcApp* nfc = context; + + widget_reset(nfc->widget); +} diff --git a/applications/main/nfc/scenes/nfc_scene_delete_success.c b/applications/main/nfc/scenes/nfc_scene_delete_success.c new file mode 100644 index 000000000000..934e53bf1637 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_delete_success.c @@ -0,0 +1,45 @@ +#include "../nfc_app_i.h" + +void nfc_scene_delete_success_popup_callback(void* context) { + NfcApp* nfc = context; + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); +} + +void nfc_scene_delete_success_on_enter(void* context) { + NfcApp* nfc = context; + + // Setup view + Popup* popup = nfc->popup; + popup_set_icon(popup, 0, 2, &I_DolphinMafia_115x62); + popup_set_header(popup, "Deleted", 83, 19, AlignLeft, AlignBottom); + popup_set_timeout(popup, 1500); + popup_set_context(popup, nfc); + popup_set_callback(popup, nfc_scene_delete_success_popup_callback); + popup_enable_timeout(popup); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); +} + +bool nfc_scene_delete_success_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventViewExit) { + // if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneMfClassicKeys)) { + // consumed = scene_manager_search_and_switch_to_previous_scene( + // nfc->scene_manager, NfcSceneMfClassicKeys); + // } else { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneFileSelect); + // } + } + } + return consumed; +} + +void nfc_scene_delete_success_on_exit(void* context) { + NfcApp* nfc = context; + + // Clear view + popup_reset(nfc->popup); +} diff --git a/applications/main/nfc/scenes/nfc_scene_saved_menu.c b/applications/main/nfc/scenes/nfc_scene_saved_menu.c index ddb3e5b4419c..08a37da88a81 100644 --- a/applications/main/nfc/scenes/nfc_scene_saved_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_saved_menu.c @@ -124,7 +124,7 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { scene_manager_set_scene_state(nfc->scene_manager, NfcSceneSavedMenu, event.event); if(event.event == SubmenuIndexEmulate) { if(data->protocol == NfcDevProtocolMfUltralight) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate); } else if(data->protocol == NfcDevProtocolMfClassic) { scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); } else { @@ -143,13 +143,13 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); consumed = true; } else if(event.event == SubmenuIndexRename) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); consumed = true; } else if(event.event == SubmenuIndexEditUid) { scene_manager_next_scene(nfc->scene_manager, NfcSceneSetUid); consumed = true; } else if(event.event == SubmenuIndexDelete) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + scene_manager_next_scene(nfc->scene_manager, NfcSceneDelete); consumed = true; } else if(event.event == SubmenuIndexInfo) { // bool application_info_present = false; From 39b3eaf713098c6bd5e6f7d10f04d2e6436766ee Mon Sep 17 00:00:00 2001 From: gornekich Date: Thu, 11 May 2023 14:00:17 +0400 Subject: [PATCH 076/149] nfc tests: turn on unit tests --- applications/debug/unit_tests/nfc/nfc_test.c | 44 ++++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/applications/debug/unit_tests/nfc/nfc_test.c b/applications/debug/unit_tests/nfc/nfc_test.c index 8986796cbd87..cf52c6b7c6c1 100644 --- a/applications/debug/unit_tests/nfc/nfc_test.c +++ b/applications/debug/unit_tests/nfc/nfc_test.c @@ -354,31 +354,31 @@ static void mf_ultralight_write() { MU_TEST_SUITE(nfc) { nfc_test_alloc(); - UNUSED(nfca_reader); - UNUSED(mf_ultralight_11_reader); - UNUSED(mf_ultralight_21_reader); - UNUSED(ntag_215_reader); - UNUSED(ntag_216_reader); - UNUSED(ntag_213_locked_reader); + MU_RUN_TEST(nfca_reader); + MU_RUN_TEST(mf_ultralight_11_reader); + MU_RUN_TEST(mf_ultralight_21_reader); + MU_RUN_TEST(ntag_215_reader); + MU_RUN_TEST(ntag_216_reader); + MU_RUN_TEST(ntag_213_locked_reader); MU_RUN_TEST(mf_ultralight_write); - UNUSED(nfca_4b_file_test); - UNUSED(nfca_7b_file_test); - - UNUSED(mf_ultralight_file_test); - UNUSED(mf_ultralight_ev1_11_file_test); - UNUSED(mf_ultralight_ev1_h11_file_test); - UNUSED(mf_ultralight_ev1_21_file_test); - UNUSED(mf_ultralight_ev1_h21_file_test); - UNUSED(mf_ultralight_ntag_203_file_test); - UNUSED(mf_ultralight_ntag_213_file_test); - UNUSED(mf_ultralight_ntag_215_file_test); - UNUSED(mf_ultralight_ntag_216_file_test); - UNUSED(mf_ultralight_ntag_i2c_1k_file_test); - UNUSED(mf_ultralight_ntag_i2c_2k_file_test); - UNUSED(mf_ultralight_ntag_i2c_plus_1k_file_test); - UNUSED(mf_ultralight_ntag_i2c_plus_2k_file_test); + MU_RUN_TEST(nfca_4b_file_test); + MU_RUN_TEST(nfca_7b_file_test); + + MU_RUN_TEST(mf_ultralight_file_test); + MU_RUN_TEST(mf_ultralight_ev1_11_file_test); + MU_RUN_TEST(mf_ultralight_ev1_h11_file_test); + MU_RUN_TEST(mf_ultralight_ev1_21_file_test); + MU_RUN_TEST(mf_ultralight_ev1_h21_file_test); + MU_RUN_TEST(mf_ultralight_ntag_203_file_test); + MU_RUN_TEST(mf_ultralight_ntag_213_file_test); + MU_RUN_TEST(mf_ultralight_ntag_215_file_test); + MU_RUN_TEST(mf_ultralight_ntag_216_file_test); + MU_RUN_TEST(mf_ultralight_ntag_i2c_1k_file_test); + MU_RUN_TEST(mf_ultralight_ntag_i2c_2k_file_test); + MU_RUN_TEST(mf_ultralight_ntag_i2c_plus_1k_file_test); + MU_RUN_TEST(mf_ultralight_ntag_i2c_plus_2k_file_test); nfc_test_free(); } From 8f0de1320f6136f5fb742b24ed308706fbc71ad4 Mon Sep 17 00:00:00 2001 From: gornekich Date: Sun, 14 May 2023 17:46:54 +0400 Subject: [PATCH 077/149] nfc: introduce mifare classic --- lib/nfc/protocols/mf_classic/mf_classic.c | 145 ++++++++++++++++++ lib/nfc/protocols/mf_classic/mf_classic.h | 96 ++++++++++++ .../protocols/mf_classic/mf_classic_poller.c | 0 .../protocols/mf_classic/mf_classic_poller.h | 0 4 files changed, 241 insertions(+) create mode 100644 lib/nfc/protocols/mf_classic/mf_classic.c create mode 100644 lib/nfc/protocols/mf_classic/mf_classic.h create mode 100644 lib/nfc/protocols/mf_classic/mf_classic_poller.c create mode 100644 lib/nfc/protocols/mf_classic/mf_classic_poller.h diff --git a/lib/nfc/protocols/mf_classic/mf_classic.c b/lib/nfc/protocols/mf_classic/mf_classic.c new file mode 100644 index 000000000000..f6878a060549 --- /dev/null +++ b/lib/nfc/protocols/mf_classic/mf_classic.c @@ -0,0 +1,145 @@ +#include "mf_classic.h" + +#include +#include + +typedef struct { + uint8_t sectors_total; + uint16_t blocks_total; + const char* full_name; + const char* type_name; +} MfClassicFeatures; + +MfClassicFeatures mf_classic_features[MfClassicTypeNum] = { + [MfClassicTypeMini] = + { + .sectors_total = 5, + .blocks_total = 20, + .full_name = "Mifare Classic Mini 0.3K", + .type_name = "MINI", + }, + [MfClassicType1k] = + { + .sectors_total = 16, + .blocks_total = 64, + .full_name = "Mifare Classic 1K", + .type_name = "1K", + }, + [MfClassicType4k] = + { + .sectors_total = 40, + .blocks_total = 256, + .full_name = "Mifare Classic 4K", + .type_name = "4K", + }, +}; + +uint8_t mf_classic_get_total_sectors_num(MfClassicType type) { + return mf_classic_features[type].sectors_total; +} + +uint16_t mf_classic_get_total_block_num(MfClassicType type) { + return mf_classic_features[type].blocks_total; +} + +uint8_t mf_classic_get_sector_trailer_block_num_by_sector(uint8_t sector) { + uint8_t block_num = 0; + + if(sector < 32) { + block_num = sector * 4 + 3; + } else if(sector < 40) { + block_num = 32 * 4 + (sector - 32) * 16 + 15; + } else { + furi_crash("Wrong sector num"); + } + + return block_num; +} + +uint8_t mf_classic_get_sector_trailer_num_by_block(uint8_t block) { + uint8_t sec_tr_block_num = 0; + + if(block < 128) { + sec_tr_block_num = block | 0x03; + } else { + sec_tr_block_num = block | 0x0f; + } + + return sec_tr_block_num; +} + +bool mf_classic_is_sector_trailer(uint8_t block) { + return block == mf_classic_get_sector_trailer_num_by_block(block); +} + +uint8_t mf_classic_get_sector_by_block(uint8_t block) { + uint8_t sector = 0; + + if(block < 128) { + sector = (block | 0x03) / 4; + } else { + sector = 32 + ((block | 0x0f) - 32 * 4) / 16; + } + + return sector; +} + +bool mf_classic_is_key_found(MfClassicData* data, uint8_t sector_num, MfClassicKey key_type) { + furi_assert(data); + + bool key_found = false; + if(key_type == MfClassicKeyA) { + key_found = (FURI_BIT(data->key_a_mask, sector_num) == 1); + } else if(key_type == MfClassicKeyB) { + key_found = (FURI_BIT(data->key_b_mask, sector_num) == 1); + } + + return key_found; +} + +void mf_classic_set_key_found( + MfClassicData* data, + uint8_t sector_num, + MfClassicKey key_type, + uint64_t key) { + furi_assert(data); + + uint8_t key_arr[6] = {}; + uint8_t sec_tr_block = mf_classic_get_sector_trailer_block_num_by_sector(sector_num); + MfClassicSectorTrailer* sec_trailer = (MfClassicSectorTrailer*)&data->block[sec_tr_block]; + nfc_util_num2bytes(key, 6, key_arr); + if(key_type == MfClassicKeyA) { + memcpy(sec_trailer->key_a, key_arr, sizeof(sec_trailer->key_a)); + FURI_BIT_SET(data->key_a_mask, sector_num); + } else if(key_type == MfClassicKeyB) { + memcpy(sec_trailer->key_b, key_arr, sizeof(sec_trailer->key_b)); + FURI_BIT_SET(data->key_b_mask, sector_num); + } +} + +void mf_classic_set_key_not_found(MfClassicData* data, uint8_t sector_num, MfClassicKey key_type) { + furi_assert(data); + + if(key_type == MfClassicKeyA) { + FURI_BIT_CLEAR(data->key_a_mask, sector_num); + } else if(key_type == MfClassicKeyB) { + FURI_BIT_CLEAR(data->key_b_mask, sector_num); + } +} + +bool mf_classic_is_block_read(MfClassicData* data, uint8_t block_num) { + furi_assert(data); + + return (FURI_BIT(data->block_read_mask[block_num / 32], block_num % 32) == 1); +} + +void mf_classic_set_block_read(MfClassicData* data, uint8_t block_num, MfClassicBlock* block_data) { + furi_assert(data); + + if(mf_classic_is_sector_trailer(block_num)) { + memcpy(&data->block[block_num].value[6], &block_data->value[6], 4); + } else { + memcpy(data->block[block_num].value, block_data->value, MF_CLASSIC_BLOCK_SIZE); + } + FURI_BIT_SET(data->block_read_mask[block_num / 32], block_num % 32); +} diff --git a/lib/nfc/protocols/mf_classic/mf_classic.h b/lib/nfc/protocols/mf_classic/mf_classic.h new file mode 100644 index 000000000000..87b5416b1955 --- /dev/null +++ b/lib/nfc/protocols/mf_classic/mf_classic.h @@ -0,0 +1,96 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define MF_CLASSIC_BLOCK_SIZE (16) +#define MF_CLASSIC_TOTAL_BLOCKS_MAX (256) +#define MF_CLASSIC_KEY_SIZE (6) +#define MF_CLASSIC_ACCESS_BYTES_SIZE (4) + +typedef enum { + MfClassicErrorNone, + MfClassicErrorNotPresent, + MfClassicErrorProtocol, + MfClassicErrorAuth, + MfClassicErrorTimeout, +} MfClassicError; + +typedef enum { + MfClassicTypeMini, + MfClassicType1k, + MfClassicType4k, + + MfClassicTypeNum, +} MfClassicType; + +typedef enum { + MfClassicKeyA, + MfClassicKeyB, +} MfClassicKey; + +typedef enum { + MfClassicActionDataRead, + MfClassicActionDataWrite, + MfClassicActionDataInc, + MfClassicActionDataDec, + + MfClassicActionKeyARead, + MfClassicActionKeyAWrite, + MfClassicActionKeyBRead, + MfClassicActionKeyBWrite, + MfClassicActionACRead, + MfClassicActionACWrite, +} MfClassicAction; + +typedef struct { + uint8_t value[MF_CLASSIC_BLOCK_SIZE]; +} MfClassicBlock; + +typedef struct { + uint8_t key_a[MF_CLASSIC_KEY_SIZE]; + uint8_t access_bits[MF_CLASSIC_ACCESS_BYTES_SIZE]; + uint8_t key_b[MF_CLASSIC_KEY_SIZE]; +} MfClassicSectorTrailer; + +typedef struct { + NfcaData nfca_data; + MfClassicType type; + uint32_t block_read_mask[MF_CLASSIC_TOTAL_BLOCKS_MAX / 32]; + uint64_t key_a_mask; + uint64_t key_b_mask; + MfClassicBlock block[MF_CLASSIC_TOTAL_BLOCKS_MAX]; +} MfClassicData; + +uint8_t mf_classic_get_total_sectors_num(MfClassicType type); + +uint16_t mf_classic_get_total_block_num(MfClassicType type); + +uint8_t mf_classic_get_sector_trailer_block_num_by_sector(uint8_t sector); + +uint8_t mf_classic_get_sector_trailer_num_by_block(uint8_t block); + +bool mf_classic_is_sector_trailer(uint8_t block); + +uint8_t mf_classic_get_sector_by_block(uint8_t block); + +bool mf_classic_is_key_found(MfClassicData* data, uint8_t sector_num, MfClassicKey key_type); + +void mf_classic_set_key_found( + MfClassicData* data, + uint8_t sector_num, + MfClassicKey key_type, + uint64_t key); + +void mf_classic_set_key_not_found(MfClassicData* data, uint8_t sector_num, MfClassicKey key_type); + +bool mf_classic_is_block_read(MfClassicData* data, uint8_t block_num); + +void mf_classic_set_block_read(MfClassicData* data, uint8_t block_num, MfClassicBlock* block_data); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller.c b/lib/nfc/protocols/mf_classic/mf_classic_poller.c new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller.h b/lib/nfc/protocols/mf_classic/mf_classic_poller.h new file mode 100644 index 000000000000..e69de29bb2d1 From 3bea05c0c35ab9f52c751471e5746c340f095498 Mon Sep 17 00:00:00 2001 From: gornekich Date: Sun, 14 May 2023 17:47:37 +0400 Subject: [PATCH 078/149] nfc: add mifare classic generators --- lib/nfc/helpers/nfc_data_generator.c | 193 +++++++++++++++++++++++---- lib/nfc/helpers/nfc_data_generator.h | 10 +- 2 files changed, 173 insertions(+), 30 deletions(-) diff --git a/lib/nfc/helpers/nfc_data_generator.c b/lib/nfc/helpers/nfc_data_generator.c index 4408b7ee3970..bf5ee599b310 100644 --- a/lib/nfc/helpers/nfc_data_generator.c +++ b/lib/nfc/helpers/nfc_data_generator.c @@ -279,6 +279,149 @@ static void nfc_generate_ntag_i2c_plus_2k(NfcDevData* data) { mfu_data->version.storage_size = 0x15; } +static void nfc_generate_mf_classic_uid(uint8_t* uid, uint8_t length) { + uid[0] = NXP_MANUFACTURER_ID; + furi_hal_random_fill_buf(&uid[1], length - 1); +} + +static void + nfc_generate_mf_classic_common(MfClassicData* data, uint8_t uid_len, MfClassicType type) { + data->nfca_data.uid_len = uid_len; + data->nfca_data.atqa[0] = 0x44; + data->nfca_data.atqa[1] = 0x00; + data->nfca_data.sak = 0x08; + data->type = type; +} + +static void nfc_generate_mf_classic_sector_trailer(MfClassicData* data, uint8_t block) { + // All keys are set to FFFF FFFF FFFFh at chip delivery and the bytes 6, 7 and 8 are set to FF0780h. + MfClassicSectorTrailer* sec_tr = (MfClassicSectorTrailer*)data->block[block].value; + sec_tr->access_bits[0] = 0xFF; + sec_tr->access_bits[1] = 0x07; + sec_tr->access_bits[2] = 0x80; + sec_tr->access_bits[3] = 0x69; // Nice + + mf_classic_set_block_read(data, block, &data->block[block]); + mf_classic_set_key_found( + data, mf_classic_get_sector_by_block(block), MfClassicKeyA, 0xFFFFFFFFFFFF); + mf_classic_set_key_found( + data, mf_classic_get_sector_by_block(block), MfClassicKeyB, 0xFFFFFFFFFFFF); +} + +static void nfc_generate_mf_classic_block_0( + uint8_t* block, + uint8_t uid_len, + uint8_t sak, + uint8_t atqa0, + uint8_t atqa1) { + // Block length is always 16 bytes, and the UID can be either 4 or 7 bytes + furi_assert(uid_len == 4 || uid_len == 7); + furi_assert(block); + + if(uid_len == 4) { + // Calculate BCC + block[uid_len] = 0; + + for(int i = 0; i < uid_len; i++) { + block[uid_len] ^= block[i]; + } + } else { + uid_len -= 1; + } + + block[uid_len + 1] = sak; + block[uid_len + 2] = atqa0; + block[uid_len + 3] = atqa1; + + for(int i = uid_len + 4; i < 16; i++) { + block[i] = 0xFF; + } +} + +static void nfc_generate_mf_classic(NfcDevData* data, uint8_t uid_len, MfClassicType type) { + nfc_generate_common_start(data); + data->protocol = NfcDevProtocolMfClassic; + MfClassicData* mfc_data = &data->mf_classic_data; + nfc_generate_mf_classic_uid(mfc_data->block[0].value, uid_len); + nfc_generate_mf_classic_common(mfc_data, uid_len, type); + + // Set the UID + mfc_data->nfca_data.uid[0] = NXP_MANUFACTURER_ID; + for(int i = 1; i < uid_len; i++) { + mfc_data->nfca_data.uid[i] = mfc_data->block[0].value[i]; + } + + mf_classic_set_block_read(mfc_data, 0, &mfc_data->block[0]); + + uint16_t block_num = mf_classic_get_total_block_num(type); + if(type == MfClassicType4k) { + // Set every block to 0xFF + for(uint16_t i = 1; i < block_num; i += 1) { + if(mf_classic_is_sector_trailer(i)) { + nfc_generate_mf_classic_sector_trailer(mfc_data, i); + } else { + memset(&mfc_data->block[i].value, 0xFF, 16); + } + mf_classic_set_block_read(mfc_data, i, &mfc_data->block[i]); + } + // Set SAK to 18 + data->nfca_data.sak = 0x18; + } else if(type == MfClassicType1k) { + // Set every block to 0xFF + for(uint16_t i = 1; i < block_num * 4; i += 1) { + if(mf_classic_is_sector_trailer(i)) { + nfc_generate_mf_classic_sector_trailer(mfc_data, i); + } else { + memset(&mfc_data->block[i].value, 0xFF, 16); + } + mf_classic_set_block_read(mfc_data, i, &mfc_data->block[i]); + } + // Set SAK to 08 + data->nfca_data.sak = 0x08; + } else if(type == MfClassicTypeMini) { + // Set every block to 0xFF + for(uint16_t i = 1; i < block_num * 4; i += 1) { + if(mf_classic_is_sector_trailer(i)) { + nfc_generate_mf_classic_sector_trailer(mfc_data, i); + } else { + memset(&mfc_data->block[i].value, 0xFF, 16); + } + mf_classic_set_block_read(mfc_data, i, &mfc_data->block[i]); + } + // Set SAK to 09 + data->nfca_data.sak = 0x09; + } + + nfc_generate_mf_classic_block_0( + data->mf_classic_data.block[0].value, + uid_len, + data->nfca_data.sak, + data->nfca_data.atqa[0], + data->nfca_data.atqa[1]); + + mfc_data->type = type; +} + +static void nfc_generate_mf_classic_mini(NfcDevData* data) { + nfc_generate_mf_classic(data, 4, MfClassicTypeMini); +} + +static void nfc_generate_mf_classic_1k_4b_uid(NfcDevData* data) { + nfc_generate_mf_classic(data, 4, MfClassicType1k); +} + +static void nfc_generate_mf_classic_1k_7b_uid(NfcDevData* data) { + nfc_generate_mf_classic(data, 7, MfClassicType1k); +} + +static void nfc_generate_mf_classic_4k_4b_uid(NfcDevData* data) { + nfc_generate_mf_classic(data, 4, MfClassicType4k); +} + +static void nfc_generate_mf_classic_4k_7b_uid(NfcDevData* data) { + nfc_generate_mf_classic(data, 7, MfClassicType4k); +} + static const NfcDataGenerator nfc_data_generator[NfcDataGeneratorTypeNum] = { [NfcDataGeneratorTypeMfUltralight] = { @@ -345,31 +488,31 @@ static const NfcDataGenerator nfc_data_generator[NfcDataGeneratorTypeNum] = { .name = "NTAG I2C Plus 2k", .handler = nfc_generate_ntag_i2c_plus_2k, }, - // [NfcDataGeneratorTypeMfClassicMini] = - // { - // .name = "", - // .handler =, - // }, - // [NfcDataGeneratorTypeMfClassic1k_4b] = - // { - // .name = "", - // .handler =, - // }, - // [NfcDataGeneratorTypeMfClassic1k_7b] = - // { - // .name = "", - // .handler =, - // }, - // [NfcDataGeneratorTypeMfClassic2k_4b] = - // { - // .name = "", - // .handler =, - // }, - // [NfcDataGeneratorTypeMfClassic2k_7b] = - // { - // .name = "", - // .handler =, - // }, + [NfcDataGeneratorTypeMfClassicMini] = + { + .name = "Mifare Mini", + .handler = nfc_generate_mf_classic_mini, + }, + [NfcDataGeneratorTypeMfClassic1k_4b] = + { + .name = "Mifare Classic 1k 4byte UID", + .handler = nfc_generate_mf_classic_1k_4b_uid, + }, + [NfcDataGeneratorTypeMfClassic1k_7b] = + { + .name = "Mifare Classic 1k 7byte UID", + .handler = nfc_generate_mf_classic_1k_7b_uid, + }, + [NfcDataGeneratorTypeMfClassic2k_4b] = + { + .name = "Mifare Classic 4k 4byte UID", + .handler = nfc_generate_mf_classic_4k_4b_uid, + }, + [NfcDataGeneratorTypeMfClassic2k_7b] = + { + .name = "Mifare Classic 4k 7byte UID", + .handler = nfc_generate_mf_classic_4k_7b_uid, + }, }; const char* nfc_data_generator_get_name(NfcDataGeneratorType type) { diff --git a/lib/nfc/helpers/nfc_data_generator.h b/lib/nfc/helpers/nfc_data_generator.h index 80f975bec33b..ae405e1513a4 100644 --- a/lib/nfc/helpers/nfc_data_generator.h +++ b/lib/nfc/helpers/nfc_data_generator.h @@ -21,11 +21,11 @@ typedef enum { NfcDataGeneratorTypeNTAGI2CPlus1k, NfcDataGeneratorTypeNTAGI2CPlus2k, - // NfcDataGeneratorTypeMfClassicMini, - // NfcDataGeneratorTypeMfClassic1k_4b, - // NfcDataGeneratorTypeMfClassic1k_7b, - // NfcDataGeneratorTypeMfClassic2k_4b, - // NfcDataGeneratorTypeMfClassic2k_7b, + NfcDataGeneratorTypeMfClassicMini, + NfcDataGeneratorTypeMfClassic1k_4b, + NfcDataGeneratorTypeMfClassic1k_7b, + NfcDataGeneratorTypeMfClassic2k_4b, + NfcDataGeneratorTypeMfClassic2k_7b, NfcDataGeneratorTypeNum, From 8f76169a3f37a2905db5e5ae4c72cbf971b12eac Mon Sep 17 00:00:00 2001 From: gornekich Date: Sun, 14 May 2023 17:47:50 +0400 Subject: [PATCH 079/149] nfc: rename old API --- .../debug/unit_tests/nfc/nfc_test_old.c | 10 +- .../main/nfc/scenes/nfc_scene_saved_menu.c | 2 +- applications/main/nfc/views/dict_attack.c | 2 +- .../scenes/nfc_scene_mf_classic_data.c | 14 +- .../scenes/nfc_scene_mf_classic_dict_attack.c | 2 +- .../scenes/nfc_scene_mf_classic_menu.c | 2 +- .../nfc_scene_mf_classic_read_success.c | 4 +- .../nfc_old/scenes/nfc_scene_nfc_data_info.c | 4 +- .../nfc_old/scenes/nfc_scene_saved_menu.c | 2 +- applications/main/nfc_old/views/dict_attack.c | 2 +- firmware/targets/f7/api_symbols.csv | 80 +++--- lib/nfc/helpers/mfkey32.c | 2 +- lib/nfc/helpers/nfc_generators.c | 24 +- lib/nfc/nfc_device.c | 34 +-- lib/nfc/nfc_device_data.h | 2 + lib/nfc/nfc_worker.c | 106 +++---- lib/nfc/parsers/plantain_4k_parser.c | 12 +- lib/nfc/parsers/plantain_parser.c | 12 +- lib/nfc/parsers/troika_4k_parser.c | 12 +- lib/nfc/parsers/troika_parser.c | 12 +- lib/nfc/parsers/two_cities.c | 12 +- lib/nfc/protocols/mifare_classic.c | 260 +++++++++--------- lib/nfc/protocols/mifare_classic.h | 80 +++--- 23 files changed, 347 insertions(+), 345 deletions(-) diff --git a/applications/debug/unit_tests/nfc/nfc_test_old.c b/applications/debug/unit_tests/nfc/nfc_test_old.c index e606ff5d78d8..22c2c9798bd3 100644 --- a/applications/debug/unit_tests/nfc/nfc_test_old.c +++ b/applications/debug/unit_tests/nfc/nfc_test_old.c @@ -404,9 +404,9 @@ // // Reference block data // uint8_t block_data[16] = {}; // memset(block_data, 0xff, sizeof(block_data)); -// uint16_t total_blocks = mf_classic_get_total_block_num(type); +// uint16_t total_blocks = mifare_classic_get_total_block_num(type); // for(size_t i = 1; i < total_blocks; i++) { -// if(mf_classic_is_sector_trailer(i)) { +// if(mifare_classic_is_sector_trailer(i)) { // mu_assert( // memcmp(mf_data->block[i].value, sector_trailer, 16) == 0, // "Failed sector trailer compare"); @@ -456,7 +456,7 @@ // "manufacturer_block assert failed\r\n"); // // Check other blocks // for(size_t i = 1; i < total_blocks; i++) { -// if(mf_classic_is_sector_trailer(i)) { +// if(mifare_classic_is_sector_trailer(i)) { // mu_assert( // memcmp(mf_data->block[i].value, sector_trailer, 16) == 0, // "Failed sector trailer compare"); @@ -472,12 +472,12 @@ // nfc_keys->dev_data.nfc_data.uid_len = uid_len; // memcpy(nfc_keys->dev_data.nfc_data.uid, uid, uid_len); // mu_assert(nfc_device_load_key_cache(nfc_keys), "Failed to load key cache"); -// uint8_t total_sec = mf_classic_get_total_sectors_num(type); +// uint8_t total_sec = mifare_classic_get_total_sectors_num(type); // uint8_t default_key[6] = {}; // memset(default_key, 0xff, 6); // for(size_t i = 0; i < total_sec; i++) { // MfClassicSectorTrailer* sec_tr = -// mf_classic_get_sector_trailer_by_sector(&nfc_keys->dev_data.mf_classic_data, i); +// mifare_classic_get_sector_trailer_by_sector(&nfc_keys->dev_data.mf_classic_data, i); // mu_assert(memcmp(sec_tr->key_a, default_key, 6) == 0, "Failed key compare"); // mu_assert(memcmp(sec_tr->key_b, default_key, 6) == 0, "Failed key compare"); // } diff --git a/applications/main/nfc/scenes/nfc_scene_saved_menu.c b/applications/main/nfc/scenes/nfc_scene_saved_menu.c index 08a37da88a81..3ff05729eb75 100644 --- a/applications/main/nfc/scenes/nfc_scene_saved_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_saved_menu.c @@ -55,7 +55,7 @@ void nfc_scene_saved_menu_on_enter(void* context) { if(data->protocol == NfcDevProtocolMfClassic) { // TODO - // if(!mf_classic_is_card_read(&nfc->dev->dev_data.mf_classic_data)) + // if(!mifare_classic_is_card_read(&nfc->dev->dev_data.mf_classic_data)) submenu_add_item( submenu, "Detect Reader", diff --git a/applications/main/nfc/views/dict_attack.c b/applications/main/nfc/views/dict_attack.c index 8f4bd063e8b8..dd6b919f0899 100644 --- a/applications/main/nfc/views/dict_attack.c +++ b/applications/main/nfc/views/dict_attack.c @@ -169,7 +169,7 @@ void dict_attack_set_card_detected(DictAttack* dict_attack, MfClassicType type) DictAttackViewModel * model, { model->state = DictAttackStateRead; - model->sectors_total = mf_classic_get_total_sectors_num(type); + model->sectors_total = mifare_classic_get_total_sectors_num(type); model->keys_total = model->sectors_total * 2; }, true); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_data.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_data.c index 83ba57f7cf7e..b2be2f53a66e 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_data.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_data.c @@ -20,17 +20,17 @@ void nfc_scene_mf_classic_data_on_enter(void* context) { int bytes_written = 0; for(int block_num = 0; block_num < card_blocks; block_num++) { - bool is_sec_trailer = mf_classic_is_sector_trailer(block_num); + bool is_sec_trailer = mifare_classic_is_sector_trailer(block_num); if(is_sec_trailer) { - uint8_t sector_num = mf_classic_get_sector_by_block(block_num); + uint8_t sector_num = mifare_classic_get_sector_by_block(block_num); MfClassicSectorTrailer* sec_tr = - mf_classic_get_sector_trailer_by_sector(data, sector_num); + mifare_classic_get_sector_trailer_by_sector(data, sector_num); // Key A for(size_t i = 0; i < sizeof(sec_tr->key_a); i += 2) { if((bytes_written % 8 == 0) && (bytes_written != 0)) { furi_string_push_back(nfc->text_box_store, '\n'); } - if(mf_classic_is_key_found(data, sector_num, MfClassicKeyA)) { + if(mifare_classic_is_key_found(data, sector_num, MfClassicKeyA)) { furi_string_cat_printf( nfc->text_box_store, "%02X%02X ", sec_tr->key_a[i], sec_tr->key_a[i + 1]); } else { @@ -43,7 +43,7 @@ void nfc_scene_mf_classic_data_on_enter(void* context) { if((bytes_written % 8 == 0) && (bytes_written != 0)) { furi_string_push_back(nfc->text_box_store, '\n'); } - if(mf_classic_is_block_read(data, block_num)) { + if(mifare_classic_is_block_read(data, block_num)) { furi_string_cat_printf( nfc->text_box_store, "%02X%02X ", @@ -59,7 +59,7 @@ void nfc_scene_mf_classic_data_on_enter(void* context) { if((bytes_written % 8 == 0) && (bytes_written != 0)) { furi_string_push_back(nfc->text_box_store, '\n'); } - if(mf_classic_is_key_found(data, sector_num, MfClassicKeyB)) { + if(mifare_classic_is_key_found(data, sector_num, MfClassicKeyB)) { furi_string_cat_printf( nfc->text_box_store, "%02X%02X ", sec_tr->key_b[i], sec_tr->key_b[i + 1]); } else { @@ -73,7 +73,7 @@ void nfc_scene_mf_classic_data_on_enter(void* context) { if((bytes_written % 8 == 0) && (bytes_written != 0)) { furi_string_push_back(nfc->text_box_store, '\n'); } - if(mf_classic_is_block_read(data, block_num)) { + if(mifare_classic_is_block_read(data, block_num)) { furi_string_cat_printf( nfc->text_box_store, "%02X%02X ", diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_dict_attack.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_dict_attack.c index 77d559367c1e..dd27b6c1b322 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_dict_attack.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_dict_attack.c @@ -28,7 +28,7 @@ static void nfc_scene_mf_classic_dict_attack_update_view(NfcApp* nfc) { uint8_t keys_found = 0; // Calculate found keys and read sectors - mf_classic_get_read_sectors_and_keys(data, §ors_read, &keys_found); + mifare_classic_get_read_sectors_and_keys(data, §ors_read, &keys_found); dict_attack_set_keys_found(nfc->dict_attack, keys_found); dict_attack_set_sector_read(nfc->dict_attack, sectors_read); } diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_menu.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_menu.c index 207bb17edfbb..18e1a78aa80b 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_menu.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_menu.c @@ -22,7 +22,7 @@ void nfc_scene_mf_classic_menu_on_enter(void* context) { submenu, "Save", SubmenuIndexSave, nfc_scene_mf_classic_menu_submenu_callback, nfc); submenu_add_item( submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_mf_classic_menu_submenu_callback, nfc); - if(!mf_classic_is_card_read(&nfc->dev->dev_data.mf_classic_data)) { + if(!mifare_classic_is_card_read(&nfc->dev->dev_data.mf_classic_data)) { submenu_add_item( submenu, "Detect Reader", diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_read_success.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_read_success.c index f0ab9397f5f7..bdc3b137eb23 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_read_success.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_read_success.c @@ -33,11 +33,11 @@ void nfc_scene_mf_classic_read_success_on_enter(void* context) { for(size_t i = 0; i < dev_data->nfc_data.uid_len; i++) { furi_string_cat_printf(temp_str, " %02X", dev_data->nfc_data.uid[i]); } - uint8_t sectors_total = mf_classic_get_total_sectors_num(mf_data->type); + uint8_t sectors_total = mifare_classic_get_total_sectors_num(mf_data->type); uint8_t keys_total = sectors_total * 2; uint8_t keys_found = 0; uint8_t sectors_read = 0; - mf_classic_get_read_sectors_and_keys(mf_data, §ors_read, &keys_found); + mifare_classic_get_read_sectors_and_keys(mf_data, §ors_read, &keys_found); furi_string_cat_printf(temp_str, "\nKeys Found: %d/%d", keys_found, keys_total); furi_string_cat_printf(temp_str, "\nSectors Read: %d/%d", sectors_read, sectors_total); } diff --git a/applications/main/nfc_old/scenes/nfc_scene_nfc_data_info.c b/applications/main/nfc_old/scenes/nfc_scene_nfc_data_info.c index 975117532aac..8f66b85ce435 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_nfc_data_info.c +++ b/applications/main/nfc_old/scenes/nfc_scene_nfc_data_info.c @@ -107,11 +107,11 @@ void nfc_scene_nfc_data_info_on_enter(void* context) { } } else if(protocol == NfcDeviceProtocolMifareClassic) { MfClassicData* data = &dev_data->mf_classic_data; - uint8_t sectors_total = mf_classic_get_total_sectors_num(data->type); + uint8_t sectors_total = mifare_classic_get_total_sectors_num(data->type); uint8_t keys_total = sectors_total * 2; uint8_t keys_found = 0; uint8_t sectors_read = 0; - mf_classic_get_read_sectors_and_keys(data, §ors_read, &keys_found); + mifare_classic_get_read_sectors_and_keys(data, §ors_read, &keys_found); furi_string_cat_printf(temp_str, "\nKeys Found %d/%d", keys_found, keys_total); furi_string_cat_printf(temp_str, "\nSectors Read %d/%d", sectors_read, sectors_total); } diff --git a/applications/main/nfc_old/scenes/nfc_scene_saved_menu.c b/applications/main/nfc_old/scenes/nfc_scene_saved_menu.c index 987911d79fff..045760338581 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_saved_menu.c +++ b/applications/main/nfc_old/scenes/nfc_scene_saved_menu.c @@ -48,7 +48,7 @@ void nfc_scene_saved_menu_on_enter(void* context) { submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_saved_menu_submenu_callback, nfc); } if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) { - if(!mf_classic_is_card_read(&nfc->dev->dev_data.mf_classic_data)) { + if(!mifare_classic_is_card_read(&nfc->dev->dev_data.mf_classic_data)) { submenu_add_item( submenu, "Detect Reader", diff --git a/applications/main/nfc_old/views/dict_attack.c b/applications/main/nfc_old/views/dict_attack.c index 8f4bd063e8b8..dd6b919f0899 100644 --- a/applications/main/nfc_old/views/dict_attack.c +++ b/applications/main/nfc_old/views/dict_attack.c @@ -169,7 +169,7 @@ void dict_attack_set_card_detected(DictAttack* dict_attack, MfClassicType type) DictAttackViewModel * model, { model->state = DictAttackStateRead; - model->sectors_total = mf_classic_get_total_sectors_num(type); + model->sectors_total = mifare_classic_get_total_sectors_num(type); model->keys_total = model->sectors_total * 2; }, true); diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 6868027ed6d9..6376f4037473 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1956,13 +1956,13 @@ Function,+,menu_free,void,Menu* Function,+,menu_get_view,View*,Menu* Function,+,menu_reset,void,Menu* Function,+,menu_set_selected_item,void,"Menu*, uint32_t" -Function,-,mf_classic_auth_attempt,_Bool,"FuriHalNfcTxRxContext*, Crypto1*, MfClassicAuthContext*, uint64_t" -Function,-,mf_classic_auth_init_context,void,"MfClassicAuthContext*, uint8_t" -Function,-,mf_classic_auth_write_block,_Bool,"FuriHalNfcTxRxContext*, MfClassicBlock*, uint8_t, MfClassicKey, uint64_t" -Function,-,mf_classic_authenticate,_Bool,"FuriHalNfcTxRxContext*, uint8_t, uint64_t, MfClassicKey" -Function,-,mf_classic_authenticate_skip_activate,_Bool,"FuriHalNfcTxRxContext*, uint8_t, uint64_t, MfClassicKey, _Bool, uint32_t" -Function,-,mf_classic_block_to_value,_Bool,"const uint8_t*, int32_t*, uint8_t*" -Function,-,mf_classic_check_card_type,_Bool,"uint8_t, uint8_t, uint8_t" +Function,-,mifare_classic_auth_attempt,_Bool,"FuriHalNfcTxRxContext*, Crypto1*, MfClassicAuthContext*, uint64_t" +Function,-,mifare_classic_auth_init_context,void,"MfClassicAuthContext*, uint8_t" +Function,-,mifare_classic_auth_write_block,_Bool,"FuriHalNfcTxRxContext*, MfClassicBlock*, uint8_t, MfClassicKey, uint64_t" +Function,-,mifare_classic_authenticate,_Bool,"FuriHalNfcTxRxContext*, uint8_t, uint64_t, MfClassicKey" +Function,-,mifare_classic_authenticate_skip_activate,_Bool,"FuriHalNfcTxRxContext*, uint8_t, uint64_t, MfClassicKey, _Bool, uint32_t" +Function,-,mifare_classic_block_to_value,_Bool,"const uint8_t*, int32_t*, uint8_t*" +Function,-,mifare_classic_check_card_type,_Bool,"uint8_t, uint8_t, uint8_t" Function,-,mf_classic_dict_add_key,_Bool,"MfClassicDict*, uint8_t*" Function,-,mf_classic_dict_add_key_str,_Bool,"MfClassicDict*, FuriString*" Function,-,mf_classic_dict_alloc,MfClassicDict*,MfClassicDictType @@ -1979,40 +1979,40 @@ Function,-,mf_classic_dict_get_total_keys,uint32_t,MfClassicDict* Function,-,mf_classic_dict_is_key_present,_Bool,"MfClassicDict*, uint8_t*" Function,-,mf_classic_dict_is_key_present_str,_Bool,"MfClassicDict*, FuriString*" Function,-,mf_classic_dict_rewind,_Bool,MfClassicDict* -Function,-,mf_classic_emulator,_Bool,"MfClassicEmulator*, FuriHalNfcTxRxContext*" -Function,-,mf_classic_get_classic_type,MfClassicType,"uint8_t, uint8_t, uint8_t" -Function,-,mf_classic_get_read_sectors_and_keys,void,"MfClassicData*, uint8_t*, uint8_t*" -Function,-,mf_classic_get_sector_by_block,uint8_t,uint8_t -Function,-,mf_classic_get_sector_trailer_block_num_by_sector,uint8_t,uint8_t -Function,-,mf_classic_get_sector_trailer_by_sector,MfClassicSectorTrailer*,"MfClassicData*, uint8_t" -Function,-,mf_classic_get_total_block_num,uint16_t,MfClassicType -Function,-,mf_classic_get_total_sectors_num,uint8_t,MfClassicType -Function,-,mf_classic_get_type_str,const char*,MfClassicType -Function,-,mf_classic_halt,void,"FuriHalNfcTxRxContext*, Crypto1*" -Function,-,mf_classic_is_allowed_access_data_block,_Bool,"MfClassicData*, uint8_t, MfClassicKey, MfClassicAction" +Function,-,mifare_classic_emulator,_Bool,"MfClassicEmulator*, FuriHalNfcTxRxContext*" +Function,-,mifare_classic_get_classic_type,MfClassicType,"uint8_t, uint8_t, uint8_t" +Function,-,mifare_classic_get_read_sectors_and_keys,void,"MfClassicData*, uint8_t*, uint8_t*" +Function,-,mifare_classic_get_sector_by_block,uint8_t,uint8_t +Function,-,mifare_classic_get_sector_trailer_block_num_by_sector,uint8_t,uint8_t +Function,-,mifare_classic_get_sector_trailer_by_sector,MfClassicSectorTrailer*,"MfClassicData*, uint8_t" +Function,-,mifare_classic_get_total_block_num,uint16_t,MfClassicType +Function,-,mifare_classic_get_total_sectors_num,uint8_t,MfClassicType +Function,-,mifare_classic_get_type_str,const char*,MfClassicType +Function,-,mifare_classic_halt,void,"FuriHalNfcTxRxContext*, Crypto1*" +Function,-,mifare_classic_is_allowed_access_data_block,_Bool,"MfClassicData*, uint8_t, MfClassicKey, MfClassicAction" Function,-,mf_classic_is_allowed_access_sector_trailer,_Bool,"MfClassicData*, uint8_t, MfClassicKey, MfClassicAction" -Function,-,mf_classic_is_block_read,_Bool,"MfClassicData*, uint8_t" -Function,-,mf_classic_is_card_read,_Bool,MfClassicData* -Function,-,mf_classic_is_key_found,_Bool,"MfClassicData*, uint8_t, MfClassicKey" -Function,-,mf_classic_is_sector_data_read,_Bool,"MfClassicData*, uint8_t" -Function,-,mf_classic_is_sector_read,_Bool,"MfClassicData*, uint8_t" -Function,-,mf_classic_is_sector_trailer,_Bool,uint8_t -Function,-,mf_classic_is_value_block,_Bool,"MfClassicData*, uint8_t" -Function,-,mf_classic_read_block,_Bool,"FuriHalNfcTxRxContext*, Crypto1*, uint8_t, MfClassicBlock*" -Function,-,mf_classic_read_card,uint8_t,"FuriHalNfcTxRxContext*, MfClassicReader*, MfClassicData*" -Function,-,mf_classic_read_sector,void,"FuriHalNfcTxRxContext*, MfClassicData*, uint8_t" -Function,-,mf_classic_reader_add_sector,void,"MfClassicReader*, uint8_t, uint64_t, uint64_t" -Function,-,mf_classic_set_block_read,void,"MfClassicData*, uint8_t, MfClassicBlock*" -Function,-,mf_classic_set_key_found,void,"MfClassicData*, uint8_t, MfClassicKey, uint64_t" -Function,-,mf_classic_set_key_not_found,void,"MfClassicData*, uint8_t, MfClassicKey" -Function,-,mf_classic_set_sector_data_not_read,void,MfClassicData* -Function,-,mf_classic_transfer,_Bool,"FuriHalNfcTxRxContext*, Crypto1*, uint8_t" -Function,-,mf_classic_update_card,uint8_t,"FuriHalNfcTxRxContext*, MfClassicData*" -Function,-,mf_classic_value_cmd,_Bool,"FuriHalNfcTxRxContext*, Crypto1*, uint8_t, uint8_t, int32_t" -Function,-,mf_classic_value_cmd_full,_Bool,"FuriHalNfcTxRxContext*, MfClassicBlock*, uint8_t, MfClassicKey, uint64_t, int32_t" -Function,-,mf_classic_value_to_block,void,"int32_t, uint8_t, uint8_t*" -Function,-,mf_classic_write_block,_Bool,"FuriHalNfcTxRxContext*, Crypto1*, uint8_t, MfClassicBlock*" -Function,-,mf_classic_write_sector,_Bool,"FuriHalNfcTxRxContext*, MfClassicData*, MfClassicData*, uint8_t" +Function,-,mifare_classic_is_block_read,_Bool,"MfClassicData*, uint8_t" +Function,-,mifare_classic_is_card_read,_Bool,MfClassicData* +Function,-,mifare_classic_is_key_found,_Bool,"MfClassicData*, uint8_t, MfClassicKey" +Function,-,mifare_classic_is_sector_data_read,_Bool,"MfClassicData*, uint8_t" +Function,-,mifare_classic_is_sector_read,_Bool,"MfClassicData*, uint8_t" +Function,-,mifare_classic_is_sector_trailer,_Bool,uint8_t +Function,-,mifare_classic_is_value_block,_Bool,"MfClassicData*, uint8_t" +Function,-,mifare_classic_read_block,_Bool,"FuriHalNfcTxRxContext*, Crypto1*, uint8_t, MfClassicBlock*" +Function,-,mifare_classic_read_card,uint8_t,"FuriHalNfcTxRxContext*, MfClassicReader*, MfClassicData*" +Function,-,mifare_classic_read_sector,void,"FuriHalNfcTxRxContext*, MfClassicData*, uint8_t" +Function,-,mifare_classic_reader_add_sector,void,"MfClassicReader*, uint8_t, uint64_t, uint64_t" +Function,-,mifare_classic_set_block_read,void,"MfClassicData*, uint8_t, MfClassicBlock*" +Function,-,mifare_classic_set_key_found,void,"MfClassicData*, uint8_t, MfClassicKey, uint64_t" +Function,-,mifare_classic_set_key_not_found,void,"MfClassicData*, uint8_t, MfClassicKey" +Function,-,mifare_classic_set_sector_data_not_read,void,MfClassicData* +Function,-,mifare_classic_transfer,_Bool,"FuriHalNfcTxRxContext*, Crypto1*, uint8_t" +Function,-,mifare_classic_update_card,uint8_t,"FuriHalNfcTxRxContext*, MfClassicData*" +Function,-,mifare_classic_value_cmd,_Bool,"FuriHalNfcTxRxContext*, Crypto1*, uint8_t, uint8_t, int32_t" +Function,-,mifare_classic_value_cmd_full,_Bool,"FuriHalNfcTxRxContext*, MfClassicBlock*, uint8_t, MfClassicKey, uint64_t, int32_t" +Function,-,mifare_classic_value_to_block,void,"int32_t, uint8_t, uint8_t*" +Function,-,mifare_classic_write_block,_Bool,"FuriHalNfcTxRxContext*, Crypto1*, uint8_t, MfClassicBlock*" +Function,-,mifare_classic_write_sector,_Bool,"FuriHalNfcTxRxContext*, MfClassicData*, MfClassicData*, uint8_t" Function,-,mf_df_cat_application,void,"MifareDesfireApplication*, FuriString*" Function,-,mf_df_cat_application_info,void,"MifareDesfireApplication*, FuriString*" Function,-,mf_df_cat_card_info,void,"MifareDesfireData*, FuriString*" diff --git a/lib/nfc/helpers/mfkey32.c b/lib/nfc/helpers/mfkey32.c index 47e7e9f6b39b..81aa3c930711 100644 --- a/lib/nfc/helpers/mfkey32.c +++ b/lib/nfc/helpers/mfkey32.c @@ -169,7 +169,7 @@ void mfkey32_process_data( if(reader_to_tag) { if((data[0] == 0x60) || (data[0] == 0x61)) { nonce->key = data[0] == 0x60 ? MfClassicKeyA : MfClassicKeyB; - nonce->sector = mf_classic_get_sector_by_block(data[1]); + nonce->sector = mifare_classic_get_sector_by_block(data[1]); instance->state = Mfkey32StateAuthReceived; data_processed = true; } diff --git a/lib/nfc/helpers/nfc_generators.c b/lib/nfc/helpers/nfc_generators.c index 50c89aba85c9..06056a8e24f0 100644 --- a/lib/nfc/helpers/nfc_generators.c +++ b/lib/nfc/helpers/nfc_generators.c @@ -71,11 +71,11 @@ static void nfc_generate_mf_classic_sector_trailer(MfClassicData* data, uint8_t memset(sec_tr->key_a, 0xff, sizeof(sec_tr->key_a)); memset(sec_tr->key_b, 0xff, sizeof(sec_tr->key_b)); - mf_classic_set_block_read(data, block, &data->block[block]); - mf_classic_set_key_found( - data, mf_classic_get_sector_by_block(block), MfClassicKeyA, 0xFFFFFFFFFFFF); - mf_classic_set_key_found( - data, mf_classic_get_sector_by_block(block), MfClassicKeyB, 0xFFFFFFFFFFFF); + mifare_classic_set_block_read(data, block, &data->block[block]); + mifare_classic_set_key_found( + data, mifare_classic_get_sector_by_block(block), MfClassicKeyA, 0xFFFFFFFFFFFF); + mifare_classic_set_key_found( + data, mifare_classic_get_sector_by_block(block), MfClassicKeyB, 0xFFFFFFFFFFFF); } static void nfc_generate_mf_ul_common(NfcDeviceData* data) { @@ -345,41 +345,41 @@ void nfc_generate_mf_classic(NfcDeviceData* data, uint8_t uid_len, MfClassicType } MfClassicData* mfc = &data->mf_classic_data; - mf_classic_set_block_read(mfc, 0, &mfc->block[0]); + mifare_classic_set_block_read(mfc, 0, &mfc->block[0]); if(type == MfClassicType4k) { // Set every block to 0xFF for(uint16_t i = 1; i < 256; i += 1) { - if(mf_classic_is_sector_trailer(i)) { + if(mifare_classic_is_sector_trailer(i)) { nfc_generate_mf_classic_sector_trailer(mfc, i); } else { memset(&mfc->block[i].value, 0xFF, 16); } - mf_classic_set_block_read(mfc, i, &mfc->block[i]); + mifare_classic_set_block_read(mfc, i, &mfc->block[i]); } // Set SAK to 18 data->nfc_data.sak = 0x18; } else if(type == MfClassicType1k) { // Set every block to 0xFF for(uint16_t i = 1; i < MF_CLASSIC_1K_TOTAL_SECTORS_NUM * 4; i += 1) { - if(mf_classic_is_sector_trailer(i)) { + if(mifare_classic_is_sector_trailer(i)) { nfc_generate_mf_classic_sector_trailer(mfc, i); } else { memset(&mfc->block[i].value, 0xFF, 16); } - mf_classic_set_block_read(mfc, i, &mfc->block[i]); + mifare_classic_set_block_read(mfc, i, &mfc->block[i]); } // Set SAK to 08 data->nfc_data.sak = 0x08; } else if(type == MfClassicTypeMini) { // Set every block to 0xFF for(uint16_t i = 1; i < MF_MINI_TOTAL_SECTORS_NUM * 4; i += 1) { - if(mf_classic_is_sector_trailer(i)) { + if(mifare_classic_is_sector_trailer(i)) { nfc_generate_mf_classic_sector_trailer(mfc, i); } else { memset(&mfc->block[i].value, 0xFF, 16); } - mf_classic_set_block_read(mfc, i, &mfc->block[i]); + mifare_classic_set_block_read(mfc, i, &mfc->block[i]); } // Set SAK to 09 data->nfc_data.sak = 0x09; diff --git a/lib/nfc/nfc_device.c b/lib/nfc/nfc_device.c index 5179130702d8..6791963142fc 100644 --- a/lib/nfc/nfc_device.c +++ b/lib/nfc/nfc_device.c @@ -693,13 +693,13 @@ static void nfc_device_write_mifare_classic_block( MfClassicData* data, uint8_t block_num) { furi_string_reset(block_str); - bool is_sec_trailer = mf_classic_is_sector_trailer(block_num); + bool is_sec_trailer = mifare_classic_is_sector_trailer(block_num); if(is_sec_trailer) { - uint8_t sector_num = mf_classic_get_sector_by_block(block_num); - MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(data, sector_num); + uint8_t sector_num = mifare_classic_get_sector_by_block(block_num); + MfClassicSectorTrailer* sec_tr = mifare_classic_get_sector_trailer_by_sector(data, sector_num); // Write key A for(size_t i = 0; i < sizeof(sec_tr->key_a); i++) { - if(mf_classic_is_key_found(data, sector_num, MfClassicKeyA)) { + if(mifare_classic_is_key_found(data, sector_num, MfClassicKeyA)) { furi_string_cat_printf(block_str, "%02X ", sec_tr->key_a[i]); } else { furi_string_cat_printf(block_str, "?? "); @@ -707,7 +707,7 @@ static void nfc_device_write_mifare_classic_block( } // Write Access bytes for(size_t i = 0; i < MF_CLASSIC_ACCESS_BYTES_SIZE; i++) { - if(mf_classic_is_block_read(data, block_num)) { + if(mifare_classic_is_block_read(data, block_num)) { furi_string_cat_printf(block_str, "%02X ", sec_tr->access_bits[i]); } else { furi_string_cat_printf(block_str, "?? "); @@ -715,7 +715,7 @@ static void nfc_device_write_mifare_classic_block( } // Write key B for(size_t i = 0; i < sizeof(sec_tr->key_b); i++) { - if(mf_classic_is_key_found(data, sector_num, MfClassicKeyB)) { + if(mifare_classic_is_key_found(data, sector_num, MfClassicKeyB)) { furi_string_cat_printf(block_str, "%02X ", sec_tr->key_b[i]); } else { furi_string_cat_printf(block_str, "?? "); @@ -724,7 +724,7 @@ static void nfc_device_write_mifare_classic_block( } else { // Write data block for(size_t i = 0; i < MF_CLASSIC_BLOCK_SIZE; i++) { - if(mf_classic_is_block_read(data, block_num)) { + if(mifare_classic_is_block_read(data, block_num)) { furi_string_cat_printf(block_str, "%02X ", data->block[block_num].value[i]); } else { furi_string_cat_printf(block_str, "?? "); @@ -787,8 +787,8 @@ static void nfc_device_load_mifare_classic_block( uint8_t block_num) { furi_string_trim(block_str); MfClassicBlock block_tmp = {}; - bool is_sector_trailer = mf_classic_is_sector_trailer(block_num); - uint8_t sector_num = mf_classic_get_sector_by_block(block_num); + bool is_sector_trailer = mifare_classic_is_sector_trailer(block_num); + uint8_t sector_num = mifare_classic_get_sector_by_block(block_num); uint16_t block_unknown_bytes_mask = 0; furi_string_trim(block_str); @@ -814,22 +814,22 @@ static void nfc_device_load_mifare_classic_block( // Key A mask 0b0000000000111111 = 0x003f if((block_unknown_bytes_mask & 0x003f) == 0) { uint64_t key = nfc_util_bytes2num(sec_tr_tmp->key_a, sizeof(sec_tr_tmp->key_a)); - mf_classic_set_key_found(data, sector_num, MfClassicKeyA, key); + mifare_classic_set_key_found(data, sector_num, MfClassicKeyA, key); } // Load Access Bits // Access bits mask 0b0000001111000000 = 0x03c0 if((block_unknown_bytes_mask & 0x03c0) == 0) { - mf_classic_set_block_read(data, block_num, &block_tmp); + mifare_classic_set_block_read(data, block_num, &block_tmp); } // Load Key B // Key B mask 0b1111110000000000 = 0xfc00 if((block_unknown_bytes_mask & 0xfc00) == 0) { uint64_t key = nfc_util_bytes2num(sec_tr_tmp->key_b, sizeof(sec_tr_tmp->key_b)); - mf_classic_set_key_found(data, sector_num, MfClassicKeyB, key); + mifare_classic_set_key_found(data, sector_num, MfClassicKeyB, key); } } else { if(block_unknown_bytes_mask == 0) { - mf_classic_set_block_read(data, block_num, &block_tmp); + mifare_classic_set_block_read(data, block_num, &block_tmp); } } } @@ -933,10 +933,10 @@ static bool nfc_device_save_mifare_classic_keys(NfcDevice* dev) { } if(!flipper_format_write_hex_uint64(file, "Key A map", &data->key_a_mask, 1)) break; if(!flipper_format_write_hex_uint64(file, "Key B map", &data->key_b_mask, 1)) break; - uint8_t sector_num = mf_classic_get_total_sectors_num(data->type); + uint8_t sector_num = mifare_classic_get_total_sectors_num(data->type); bool key_save_success = true; for(size_t i = 0; (i < sector_num) && (key_save_success); i++) { - MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(data, i); + MfClassicSectorTrailer* sec_tr = mifare_classic_get_sector_trailer_by_sector(data, i); if(FURI_BIT(data->key_a_mask, i)) { furi_string_printf(temp_str, "Key A sector %d", i); key_save_success = flipper_format_write_hex( @@ -987,10 +987,10 @@ bool nfc_device_load_key_cache(NfcDevice* dev) { } if(!flipper_format_read_hex_uint64(file, "Key A map", &data->key_a_mask, 1)) break; if(!flipper_format_read_hex_uint64(file, "Key B map", &data->key_b_mask, 1)) break; - uint8_t sectors = mf_classic_get_total_sectors_num(data->type); + uint8_t sectors = mifare_classic_get_total_sectors_num(data->type); bool key_read_success = true; for(size_t i = 0; (i < sectors) && (key_read_success); i++) { - MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(data, i); + MfClassicSectorTrailer* sec_tr = mifare_classic_get_sector_trailer_by_sector(data, i); if(FURI_BIT(data->key_a_mask, i)) { furi_string_printf(temp_str, "Key A sector %d", i); key_read_success = flipper_format_read_hex( diff --git a/lib/nfc/nfc_device_data.h b/lib/nfc/nfc_device_data.h index 2033a5f20953..253f5f4c1eb4 100644 --- a/lib/nfc/nfc_device_data.h +++ b/lib/nfc/nfc_device_data.h @@ -2,6 +2,7 @@ #include #include +#include #include #ifdef __cplusplus @@ -26,6 +27,7 @@ typedef struct { union { NfcaData nfca_data; MfUltralightData mf_ul_data; + MfClassicData mf_classic_data; }; } NfcDevData; diff --git a/lib/nfc/nfc_worker.c b/lib/nfc/nfc_worker.c index 28a1f6827977..0d625142883d 100644 --- a/lib/nfc/nfc_worker.c +++ b/lib/nfc/nfc_worker.c @@ -193,11 +193,11 @@ static bool nfc_worker_read_mf_classic(NfcWorker* nfc_worker, FuriHalNfcTxRxCont if(nfc_worker->callback(NfcWorkerEventReadMfClassicLoadKeyCache, nfc_worker->context)) { FURI_LOG_I(TAG, "Load keys cache success. Start reading"); uint8_t sectors_read = - mf_classic_update_card(tx_rx, &nfc_worker->dev_data->mf_classic_data); + mifare_classic_update_card(tx_rx, &nfc_worker->dev_data->mf_classic_data); uint8_t sectors_total = - mf_classic_get_total_sectors_num(nfc_worker->dev_data->mf_classic_data.type); + mifare_classic_get_total_sectors_num(nfc_worker->dev_data->mf_classic_data.type); FURI_LOG_I(TAG, "Read %d sectors out of %d total", sectors_read, sectors_total); - read_success = mf_classic_is_card_read(&nfc_worker->dev_data->mf_classic_data); + read_success = mifare_classic_is_card_read(&nfc_worker->dev_data->mf_classic_data); } } while(false); @@ -238,11 +238,11 @@ static bool nfc_worker_read_nfca(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* t FURI_LOG_I(TAG, "Mifare Ultralight / NTAG detected"); nfc_worker->dev_data->protocol = NfcDeviceProtocolMifareUl; card_read = nfc_worker_read_mf_ultralight(nfc_worker, tx_rx); - } else if(mf_classic_check_card_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) { + } else if(mifare_classic_check_card_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) { FURI_LOG_I(TAG, "Mifare Classic detected"); nfc_worker->dev_data->protocol = NfcDeviceProtocolMifareClassic; nfc_worker->dev_data->mf_classic_data.type = - mf_classic_get_classic_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak); + mifare_classic_get_classic_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak); card_read = nfc_worker_read_mf_classic(nfc_worker, tx_rx); } else if(mf_df_check_card_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) { FURI_LOG_I(TAG, "Mifare DESFire detected"); @@ -344,7 +344,7 @@ void nfc_worker_read_type(NfcWorker* nfc_worker) { if(nfc_data->type == FuriHalNfcTypeA) { if(read_mode == NfcReadModeMfClassic) { nfc_worker->dev_data->protocol = NfcDeviceProtocolMifareClassic; - nfc_worker->dev_data->mf_classic_data.type = mf_classic_get_classic_type( + nfc_worker->dev_data->mf_classic_data.type = mifare_classic_get_classic_type( nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak); if(nfc_worker_read_mf_classic(nfc_worker, &tx_rx)) { FURI_LOG_D(TAG, "Card read"); @@ -496,7 +496,7 @@ static bool nfc_worker_mf_get_b_key_from_sector_trailer( uint64_t* found_key) { // Some access conditions allow reading B key via A key - uint8_t block = mf_classic_get_sector_trailer_block_num_by_sector(sector); + uint8_t block = mifare_classic_get_sector_trailer_block_num_by_sector(sector); Crypto1 crypto = {}; MfClassicBlock block_tmp = {}; @@ -504,8 +504,8 @@ static bool nfc_worker_mf_get_b_key_from_sector_trailer( furi_hal_nfc_sleep(); - if(mf_classic_auth_attempt(tx_rx, &crypto, &auth_context, key)) { - if(mf_classic_read_block(tx_rx, &crypto, block, &block_tmp)) { + if(mifare_classic_auth_attempt(tx_rx, &crypto, &auth_context, key)) { + if(mifare_classic_read_block(tx_rx, &crypto, block, &block_tmp)) { *found_key = nfc_util_bytes2num(&block_tmp.value[10], sizeof(uint8_t) * 6); return *found_key; @@ -529,7 +529,7 @@ static void nfc_worker_mf_classic_key_attack( MfClassicData* data = &nfc_worker->dev_data->mf_classic_data; NfcMfClassicDictAttackData* dict_attack_data = &nfc_worker->dev_data->mf_classic_dict_attack_data; - uint32_t total_sectors = mf_classic_get_total_sectors_num(data->type); + uint32_t total_sectors = mifare_classic_get_total_sectors_num(data->type); furi_assert(start_sector < total_sectors); @@ -547,17 +547,17 @@ static void nfc_worker_mf_classic_key_attack( card_found_notified = true; card_removed_notified = false; } - uint8_t block_num = mf_classic_get_sector_trailer_block_num_by_sector(i); - if(mf_classic_is_sector_read(data, i)) continue; - if(!mf_classic_is_key_found(data, i, MfClassicKeyA)) { + uint8_t block_num = mifare_classic_get_sector_trailer_block_num_by_sector(i); + if(mifare_classic_is_sector_read(data, i)) continue; + if(!mifare_classic_is_key_found(data, i, MfClassicKeyA)) { FURI_LOG_D( TAG, "Trying A key for sector %d, key: %04lx%08lx", i, (uint32_t)(key >> 32), (uint32_t)key); - if(mf_classic_authenticate(tx_rx, block_num, key, MfClassicKeyA)) { - mf_classic_set_key_found(data, i, MfClassicKeyA, key); + if(mifare_classic_authenticate(tx_rx, block_num, key, MfClassicKeyA)) { + mifare_classic_set_key_found(data, i, MfClassicKeyA, key); FURI_LOG_D( TAG, "Key A found: %04lx%08lx", (uint32_t)(key >> 32), (uint32_t)key); nfc_worker->callback(NfcWorkerEventFoundKeyA, nfc_worker->context); @@ -565,7 +565,7 @@ static void nfc_worker_mf_classic_key_attack( uint64_t found_key; if(nfc_worker_mf_get_b_key_from_sector_trailer(tx_rx, i, key, &found_key)) { FURI_LOG_D(TAG, "Found B key via reading sector %d", i); - mf_classic_set_key_found(data, i, MfClassicKeyB, found_key); + mifare_classic_set_key_found(data, i, MfClassicKeyB, found_key); if(nfc_worker->state == NfcWorkerStateMfClassicDictAttack) { nfc_worker->callback(NfcWorkerEventFoundKeyB, nfc_worker->context); @@ -573,23 +573,23 @@ static void nfc_worker_mf_classic_key_attack( } } } - if(!mf_classic_is_key_found(data, i, MfClassicKeyB)) { + if(!mifare_classic_is_key_found(data, i, MfClassicKeyB)) { FURI_LOG_D( TAG, "Trying B key for sector %d, key: %04lx%08lx", i, (uint32_t)(key >> 32), (uint32_t)key); - if(mf_classic_authenticate(tx_rx, block_num, key, MfClassicKeyB)) { - mf_classic_set_key_found(data, i, MfClassicKeyB, key); + if(mifare_classic_authenticate(tx_rx, block_num, key, MfClassicKeyB)) { + mifare_classic_set_key_found(data, i, MfClassicKeyB, key); FURI_LOG_D( TAG, "Key B found: %04lx%08lx", (uint32_t)(key >> 32), (uint32_t)key); nfc_worker->callback(NfcWorkerEventFoundKeyB, nfc_worker->context); } } - if(mf_classic_is_sector_read(data, i)) continue; - mf_classic_read_sector(tx_rx, data, i); + if(mifare_classic_is_sector_read(data, i)) continue; + mifare_classic_read_sector(tx_rx, data, i); } else { if(!card_removed_notified) { nfc_worker->callback(NfcWorkerEventNoCardDetected, nfc_worker->context); @@ -609,7 +609,7 @@ void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker) { MfClassicData* data = &nfc_worker->dev_data->mf_classic_data; NfcMfClassicDictAttackData* dict_attack_data = &nfc_worker->dev_data->mf_classic_dict_attack_data; - uint32_t total_sectors = mf_classic_get_total_sectors_num(data->type); + uint32_t total_sectors = mifare_classic_get_total_sectors_num(data->type); uint64_t key = 0; uint64_t prev_key = 0; FuriHalNfcTxRxContext tx_rx = {}; @@ -629,10 +629,10 @@ void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker) { for(size_t i = 0; i < total_sectors; i++) { FURI_LOG_I(TAG, "Sector %d", i); nfc_worker->callback(NfcWorkerEventNewSector, nfc_worker->context); - uint8_t block_num = mf_classic_get_sector_trailer_block_num_by_sector(i); - if(mf_classic_is_sector_read(data, i)) continue; - bool is_key_a_found = mf_classic_is_key_found(data, i, MfClassicKeyA); - bool is_key_b_found = mf_classic_is_key_found(data, i, MfClassicKeyB); + uint8_t block_num = mifare_classic_get_sector_trailer_block_num_by_sector(i); + if(mifare_classic_is_sector_read(data, i)) continue; + bool is_key_a_found = mifare_classic_is_key_found(data, i, MfClassicKeyA); + bool is_key_b_found = mifare_classic_is_key_found(data, i, MfClassicKeyB); uint16_t key_index = 0; while(mf_classic_dict_get_next_key(dict, &key)) { FURI_LOG_T(TAG, "Key %d", key_index); @@ -657,10 +657,10 @@ void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker) { (uint32_t)(key >> 32), (uint32_t)key); if(!is_key_a_found) { - is_key_a_found = mf_classic_is_key_found(data, i, MfClassicKeyA); - if(mf_classic_authenticate_skip_activate( + is_key_a_found = mifare_classic_is_key_found(data, i, MfClassicKeyA); + if(mifare_classic_authenticate_skip_activate( &tx_rx, block_num, key, MfClassicKeyA, !deactivated, cuid)) { - mf_classic_set_key_found(data, i, MfClassicKeyA, key); + mifare_classic_set_key_found(data, i, MfClassicKeyA, key); FURI_LOG_D(TAG, "Key A found"); nfc_worker->callback(NfcWorkerEventFoundKeyA, nfc_worker->context); @@ -668,7 +668,7 @@ void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker) { if(nfc_worker_mf_get_b_key_from_sector_trailer( &tx_rx, i, key, &found_key)) { FURI_LOG_D(TAG, "Found B key via reading sector %d", i); - mf_classic_set_key_found(data, i, MfClassicKeyB, found_key); + mifare_classic_set_key_found(data, i, MfClassicKeyB, found_key); if(nfc_worker->state == NfcWorkerStateMfClassicDictAttack) { nfc_worker->callback(NfcWorkerEventFoundKeyB, nfc_worker->context); @@ -683,28 +683,28 @@ void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker) { deactivated = true; } else { // If the key A is marked as found and matches the searching key, invalidate it - if(mf_classic_is_key_found(data, i, MfClassicKeyA) && + if(mifare_classic_is_key_found(data, i, MfClassicKeyA) && data->block[i].value[0] == key) { - mf_classic_set_key_not_found(data, i, MfClassicKeyA); + mifare_classic_set_key_not_found(data, i, MfClassicKeyA); is_key_a_found = false; FURI_LOG_D(TAG, "Key %dA not found in attack", i); } } if(!is_key_b_found) { - is_key_b_found = mf_classic_is_key_found(data, i, MfClassicKeyB); - if(mf_classic_authenticate_skip_activate( + is_key_b_found = mifare_classic_is_key_found(data, i, MfClassicKeyB); + if(mifare_classic_authenticate_skip_activate( &tx_rx, block_num, key, MfClassicKeyB, !deactivated, cuid)) { FURI_LOG_D(TAG, "Key B found"); - mf_classic_set_key_found(data, i, MfClassicKeyB, key); + mifare_classic_set_key_found(data, i, MfClassicKeyB, key); nfc_worker->callback(NfcWorkerEventFoundKeyB, nfc_worker->context); nfc_worker_mf_classic_key_attack(nfc_worker, key, &tx_rx, i + 1); } deactivated = true; } else { // If the key B is marked as found and matches the searching key, invalidate it - if(mf_classic_is_key_found(data, i, MfClassicKeyB) && + if(mifare_classic_is_key_found(data, i, MfClassicKeyB) && data->block[i].value[10] == key) { - mf_classic_set_key_not_found(data, i, MfClassicKeyB); + mifare_classic_set_key_not_found(data, i, MfClassicKeyB); is_key_b_found = false; FURI_LOG_D(TAG, "Key %dB not found in attack", i); } @@ -722,7 +722,7 @@ void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker) { memcpy(&prev_key, &key, sizeof(key)); } if(nfc_worker->state != NfcWorkerStateMfClassicDictAttack) break; - mf_classic_read_sector(&tx_rx, data, i); + mifare_classic_read_sector(&tx_rx, data, i); mf_classic_dict_rewind(dict); } if(nfc_worker->state == NfcWorkerStateMfClassicDictAttack) { @@ -748,7 +748,7 @@ void nfc_worker_emulate_mf_classic(NfcWorker* nfc_worker) { furi_hal_nfc_listen_start(nfc_data); while(nfc_worker->state == NfcWorkerStateMfClassicEmulate) { //-V1044 if(furi_hal_nfc_listen_rx(&tx_rx, 300)) { - mf_classic_emulator(&emulator, &tx_rx); + mifare_classic_emulator(&emulator, &tx_rx); } } if(emulator.data_changed) { @@ -789,7 +789,7 @@ void nfc_worker_write_mf_classic(NfcWorker* nfc_worker) { FURI_LOG_I(TAG, "Check mf classic type"); MfClassicType type = - mf_classic_get_classic_type(nfc_data.atqa[0], nfc_data.atqa[1], nfc_data.sak); + mifare_classic_get_classic_type(nfc_data.atqa[0], nfc_data.atqa[1], nfc_data.sak); if(type != nfc_worker->dev_data->mf_classic_data.type) { FURI_LOG_E(TAG, "Wrong mf classic type"); nfc_worker->callback(NfcWorkerEventWrongCard, nfc_worker->context); @@ -797,22 +797,22 @@ void nfc_worker_write_mf_classic(NfcWorker* nfc_worker) { } // Set blocks not read - mf_classic_set_sector_data_not_read(&dest_data); + mifare_classic_set_sector_data_not_read(&dest_data); FURI_LOG_I(TAG, "Updating card sectors"); - uint8_t total_sectors = mf_classic_get_total_sectors_num(type); + uint8_t total_sectors = mifare_classic_get_total_sectors_num(type); bool write_success = true; for(uint8_t i = 0; i < total_sectors; i++) { FURI_LOG_I(TAG, "Reading sector %d", i); - mf_classic_read_sector(&tx_rx, &dest_data, i); - bool old_data_read = mf_classic_is_sector_data_read(src_data, i); - bool new_data_read = mf_classic_is_sector_data_read(&dest_data, i); + mifare_classic_read_sector(&tx_rx, &dest_data, i); + bool old_data_read = mifare_classic_is_sector_data_read(src_data, i); + bool new_data_read = mifare_classic_is_sector_data_read(&dest_data, i); if(old_data_read != new_data_read) { FURI_LOG_E(TAG, "Failed to update sector %d", i); write_success = false; break; } if(nfc_worker->state != NfcWorkerStateMfClassicWrite) break; - if(!mf_classic_write_sector(&tx_rx, &dest_data, src_data, i)) { + if(!mifare_classic_write_sector(&tx_rx, &dest_data, src_data, i)) { FURI_LOG_E(TAG, "Failed to write %d sector", i); write_success = false; break; @@ -862,7 +862,7 @@ void nfc_worker_update_mf_classic(NfcWorker* nfc_worker) { FURI_LOG_I(TAG, "Check MF classic type"); MfClassicType type = - mf_classic_get_classic_type(nfc_data.atqa[0], nfc_data.atqa[1], nfc_data.sak); + mifare_classic_get_classic_type(nfc_data.atqa[0], nfc_data.atqa[1], nfc_data.sak); if(type != nfc_worker->dev_data->mf_classic_data.type) { FURI_LOG_E(TAG, "MF classic type mismatch"); nfc_worker->callback(NfcWorkerEventWrongCard, nfc_worker->context); @@ -870,15 +870,15 @@ void nfc_worker_update_mf_classic(NfcWorker* nfc_worker) { } // Set blocks not read - mf_classic_set_sector_data_not_read(&new_data); + mifare_classic_set_sector_data_not_read(&new_data); FURI_LOG_I(TAG, "Updating card sectors"); - uint8_t total_sectors = mf_classic_get_total_sectors_num(type); + uint8_t total_sectors = mifare_classic_get_total_sectors_num(type); bool update_success = true; for(uint8_t i = 0; i < total_sectors; i++) { FURI_LOG_I(TAG, "Reading sector %d", i); - mf_classic_read_sector(&tx_rx, &new_data, i); - bool old_data_read = mf_classic_is_sector_data_read(old_data, i); - bool new_data_read = mf_classic_is_sector_data_read(&new_data, i); + mifare_classic_read_sector(&tx_rx, &new_data, i); + bool old_data_read = mifare_classic_is_sector_data_read(old_data, i); + bool new_data_read = mifare_classic_is_sector_data_read(&new_data, i); if(old_data_read != new_data_read) { FURI_LOG_E(TAG, "Failed to update sector %d", i); update_success = false; @@ -1035,7 +1035,7 @@ void nfc_worker_analyze_reader(NfcWorker* nfc_worker) { NfcProtocol protocol = reader_analyzer_guess_protocol(reader_analyzer, tx_rx.rx_data, tx_rx.rx_bits / 8); if(protocol == NfcDeviceProtocolMifareClassic) { - mf_classic_emulator(&emulator, &tx_rx); + mifare_classic_emulator(&emulator, &tx_rx); } } else { reader_no_data_received_cnt++; diff --git a/lib/nfc/parsers/plantain_4k_parser.c b/lib/nfc/parsers/plantain_4k_parser.c index 19da0b5ebb3c..a4320471c90b 100644 --- a/lib/nfc/parsers/plantain_4k_parser.c +++ b/lib/nfc/parsers/plantain_4k_parser.c @@ -57,9 +57,9 @@ bool plantain_4k_parser_verify(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_ } uint8_t sector = 8; - uint8_t block = mf_classic_get_sector_trailer_block_num_by_sector(sector); + uint8_t block = mifare_classic_get_sector_trailer_block_num_by_sector(sector); FURI_LOG_D("Plant4K", "Verifying sector %d", sector); - if(mf_classic_authenticate(tx_rx, block, 0x26973ea74321, MfClassicKeyA)) { + if(mifare_classic_authenticate(tx_rx, block, 0x26973ea74321, MfClassicKeyA)) { FURI_LOG_D("Plant4K", "Sector %d verified", sector); return true; } @@ -71,9 +71,9 @@ bool plantain_4k_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx MfClassicReader reader = {}; FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; - reader.type = mf_classic_get_classic_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak); + reader.type = mifare_classic_get_classic_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak); for(size_t i = 0; i < COUNT_OF(plantain_keys_4k); i++) { - mf_classic_reader_add_sector( + mifare_classic_reader_add_sector( &reader, plantain_keys_4k[i].sector, plantain_keys_4k[i].key_a, @@ -81,7 +81,7 @@ bool plantain_4k_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx FURI_LOG_T("plant4k", "Added sector %d", plantain_keys_4k[i].sector); } for(int i = 0; i < 5; i++) { - if(mf_classic_read_card(tx_rx, &reader, &nfc_worker->dev_data->mf_classic_data) == 40) { + if(mifare_classic_read_card(tx_rx, &reader, &nfc_worker->dev_data->mf_classic_data) == 40) { return true; } } @@ -92,7 +92,7 @@ bool plantain_4k_parser_parse(NfcDeviceData* dev_data) { MfClassicData* data = &dev_data->mf_classic_data; // Verify key - MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(data, 8); + MfClassicSectorTrailer* sec_tr = mifare_classic_get_sector_trailer_by_sector(data, 8); uint64_t key = nfc_util_bytes2num(sec_tr->key_a, 6); if(key != plantain_keys_4k[8].key_a) return false; diff --git a/lib/nfc/parsers/plantain_parser.c b/lib/nfc/parsers/plantain_parser.c index 2e4091dda10e..5f1a9c1377f8 100644 --- a/lib/nfc/parsers/plantain_parser.c +++ b/lib/nfc/parsers/plantain_parser.c @@ -32,9 +32,9 @@ bool plantain_parser_verify(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) } uint8_t sector = 8; - uint8_t block = mf_classic_get_sector_trailer_block_num_by_sector(sector); + uint8_t block = mifare_classic_get_sector_trailer_block_num_by_sector(sector); FURI_LOG_D("Plant", "Verifying sector %d", sector); - if(mf_classic_authenticate(tx_rx, block, 0x26973ea74321, MfClassicKeyA)) { + if(mifare_classic_authenticate(tx_rx, block, 0x26973ea74321, MfClassicKeyA)) { FURI_LOG_D("Plant", "Sector %d verified", sector); return true; } @@ -46,13 +46,13 @@ bool plantain_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) { MfClassicReader reader = {}; FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; - reader.type = mf_classic_get_classic_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak); + reader.type = mifare_classic_get_classic_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak); for(size_t i = 0; i < COUNT_OF(plantain_keys); i++) { - mf_classic_reader_add_sector( + mifare_classic_reader_add_sector( &reader, plantain_keys[i].sector, plantain_keys[i].key_a, plantain_keys[i].key_b); } - return mf_classic_read_card(tx_rx, &reader, &nfc_worker->dev_data->mf_classic_data) == 16; + return mifare_classic_read_card(tx_rx, &reader, &nfc_worker->dev_data->mf_classic_data) == 16; } uint8_t plantain_calculate_luhn(uint64_t number) { @@ -65,7 +65,7 @@ bool plantain_parser_parse(NfcDeviceData* dev_data) { MfClassicData* data = &dev_data->mf_classic_data; // Verify key - MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(data, 8); + MfClassicSectorTrailer* sec_tr = mifare_classic_get_sector_trailer_by_sector(data, 8); uint64_t key = nfc_util_bytes2num(sec_tr->key_a, 6); if(key != plantain_keys[8].key_a) return false; diff --git a/lib/nfc/parsers/troika_4k_parser.c b/lib/nfc/parsers/troika_4k_parser.c index d248feb17c35..ca969db06512 100644 --- a/lib/nfc/parsers/troika_4k_parser.c +++ b/lib/nfc/parsers/troika_4k_parser.c @@ -54,9 +54,9 @@ bool troika_4k_parser_verify(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx } uint8_t sector = 11; - uint8_t block = mf_classic_get_sector_trailer_block_num_by_sector(sector); + uint8_t block = mifare_classic_get_sector_trailer_block_num_by_sector(sector); FURI_LOG_D("Troika", "Verifying sector %d", sector); - if(mf_classic_authenticate(tx_rx, block, 0x08b386463229, MfClassicKeyA)) { + if(mifare_classic_authenticate(tx_rx, block, 0x08b386463229, MfClassicKeyA)) { FURI_LOG_D("Troika", "Sector %d verified", sector); return true; } @@ -68,20 +68,20 @@ bool troika_4k_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) MfClassicReader reader = {}; FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; - reader.type = mf_classic_get_classic_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak); + reader.type = mifare_classic_get_classic_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak); for(size_t i = 0; i < COUNT_OF(troika_4k_keys); i++) { - mf_classic_reader_add_sector( + mifare_classic_reader_add_sector( &reader, troika_4k_keys[i].sector, troika_4k_keys[i].key_a, troika_4k_keys[i].key_b); } - return mf_classic_read_card(tx_rx, &reader, &nfc_worker->dev_data->mf_classic_data) == 40; + return mifare_classic_read_card(tx_rx, &reader, &nfc_worker->dev_data->mf_classic_data) == 40; } bool troika_4k_parser_parse(NfcDeviceData* dev_data) { MfClassicData* data = &dev_data->mf_classic_data; // Verify key - MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(data, 4); + MfClassicSectorTrailer* sec_tr = mifare_classic_get_sector_trailer_by_sector(data, 4); uint64_t key = nfc_util_bytes2num(sec_tr->key_a, 6); if(key != troika_4k_keys[4].key_a) return false; diff --git a/lib/nfc/parsers/troika_parser.c b/lib/nfc/parsers/troika_parser.c index 6d8ae98f3cbc..e003d4161b6a 100644 --- a/lib/nfc/parsers/troika_parser.c +++ b/lib/nfc/parsers/troika_parser.c @@ -30,9 +30,9 @@ bool troika_parser_verify(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) { } uint8_t sector = 11; - uint8_t block = mf_classic_get_sector_trailer_block_num_by_sector(sector); + uint8_t block = mifare_classic_get_sector_trailer_block_num_by_sector(sector); FURI_LOG_D("Troika", "Verifying sector %d", sector); - if(mf_classic_authenticate(tx_rx, block, 0x08b386463229, MfClassicKeyA)) { + if(mifare_classic_authenticate(tx_rx, block, 0x08b386463229, MfClassicKeyA)) { FURI_LOG_D("Troika", "Sector %d verified", sector); return true; } @@ -44,14 +44,14 @@ bool troika_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) { MfClassicReader reader = {}; FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; - reader.type = mf_classic_get_classic_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak); + reader.type = mifare_classic_get_classic_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak); for(size_t i = 0; i < COUNT_OF(troika_keys); i++) { - mf_classic_reader_add_sector( + mifare_classic_reader_add_sector( &reader, troika_keys[i].sector, troika_keys[i].key_a, troika_keys[i].key_b); } - return mf_classic_read_card(tx_rx, &reader, &nfc_worker->dev_data->mf_classic_data) == 16; + return mifare_classic_read_card(tx_rx, &reader, &nfc_worker->dev_data->mf_classic_data) == 16; } bool troika_parser_parse(NfcDeviceData* dev_data) { @@ -60,7 +60,7 @@ bool troika_parser_parse(NfcDeviceData* dev_data) { do { // Verify key - MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(data, 8); + MfClassicSectorTrailer* sec_tr = mifare_classic_get_sector_trailer_by_sector(data, 8); uint64_t key = nfc_util_bytes2num(sec_tr->key_a, 6); if(key != troika_keys[8].key_a) break; diff --git a/lib/nfc/parsers/two_cities.c b/lib/nfc/parsers/two_cities.c index d6d4279ddd0f..6409a5754f43 100644 --- a/lib/nfc/parsers/two_cities.c +++ b/lib/nfc/parsers/two_cities.c @@ -58,9 +58,9 @@ bool two_cities_parser_verify(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_r } uint8_t sector = 4; - uint8_t block = mf_classic_get_sector_trailer_block_num_by_sector(sector); + uint8_t block = mifare_classic_get_sector_trailer_block_num_by_sector(sector); FURI_LOG_D("2cities", "Verifying sector %d", sector); - if(mf_classic_authenticate(tx_rx, block, 0xe56ac127dd45, MfClassicKeyA)) { + if(mifare_classic_authenticate(tx_rx, block, 0xe56ac127dd45, MfClassicKeyA)) { FURI_LOG_D("2cities", "Sector %d verified", sector); return true; } @@ -72,9 +72,9 @@ bool two_cities_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) MfClassicReader reader = {}; FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; - reader.type = mf_classic_get_classic_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak); + reader.type = mifare_classic_get_classic_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak); for(size_t i = 0; i < COUNT_OF(two_cities_keys_4k); i++) { - mf_classic_reader_add_sector( + mifare_classic_reader_add_sector( &reader, two_cities_keys_4k[i].sector, two_cities_keys_4k[i].key_a, @@ -82,14 +82,14 @@ bool two_cities_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) FURI_LOG_T("2cities", "Added sector %d", two_cities_keys_4k[i].sector); } - return mf_classic_read_card(tx_rx, &reader, &nfc_worker->dev_data->mf_classic_data) == 40; + return mifare_classic_read_card(tx_rx, &reader, &nfc_worker->dev_data->mf_classic_data) == 40; } bool two_cities_parser_parse(NfcDeviceData* dev_data) { MfClassicData* data = &dev_data->mf_classic_data; // Verify key - MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(data, 4); + MfClassicSectorTrailer* sec_tr = mifare_classic_get_sector_trailer_by_sector(data, 4); uint64_t key = nfc_util_bytes2num(sec_tr->key_a, 6); if(key != two_cities_keys_4k[4].key_a) return false; diff --git a/lib/nfc/protocols/mifare_classic.c b/lib/nfc/protocols/mifare_classic.c index 4975a78b9718..307b9c75e6bf 100644 --- a/lib/nfc/protocols/mifare_classic.c +++ b/lib/nfc/protocols/mifare_classic.c @@ -12,14 +12,14 @@ #define MF_CLASSIC_NACK_BUF_INVALID_CMD 0x4U #define MF_CLASSIC_AUTH_KEY_A_CMD 0x60U #define MF_CLASSIC_AUTH_KEY_B_CMD 0x61U -#define MF_CLASSIC_READ_BLOCK_CMD 0x30U -#define MF_CLASSIC_WRITE_BLOCK_CMD 0xA0U -#define MF_CLASSIC_TRANSFER_CMD 0xB0U +#define mifare_classic_read_block_CMD 0x30U +#define mifare_classic_write_block_CMD 0xA0U +#define mifare_classic_transfer_CMD 0xB0U #define MF_CLASSIC_DECREMENT_CMD 0xC0U #define MF_CLASSIC_INCREMENT_CMD 0xC1U #define MF_CLASSIC_RESTORE_CMD 0xC2U -const char* mf_classic_get_type_str(MfClassicType type) { +const char* mifare_classic_get_type_str(MfClassicType type) { if(type == MfClassicTypeMini) { return "MIFARE Mini 0.3K"; } else if(type == MfClassicType1k) { @@ -40,7 +40,7 @@ static uint8_t mf_classic_get_first_block_num_of_sector(uint8_t sector) { } } -uint8_t mf_classic_get_sector_trailer_block_num_by_sector(uint8_t sector) { +uint8_t mifare_classic_get_sector_trailer_block_num_by_sector(uint8_t sector) { furi_assert(sector < 40); if(sector < 32) { return sector * 4 + 3; @@ -49,7 +49,7 @@ uint8_t mf_classic_get_sector_trailer_block_num_by_sector(uint8_t sector) { } } -uint8_t mf_classic_get_sector_by_block(uint8_t block) { +uint8_t mifare_classic_get_sector_by_block(uint8_t block) { if(block < 128) { return (block | 0x03) / 4; } else { @@ -62,7 +62,7 @@ static uint8_t mf_classic_get_blocks_num_in_sector(uint8_t sector) { return sector < 32 ? 4 : 16; } -uint8_t mf_classic_get_sector_trailer_num_by_block(uint8_t block) { +uint8_t mifare_classic_get_sector_trailer_num_by_block(uint8_t block) { if(block < 128) { return block | 0x03; } else { @@ -70,18 +70,18 @@ uint8_t mf_classic_get_sector_trailer_num_by_block(uint8_t block) { } } -bool mf_classic_is_sector_trailer(uint8_t block) { - return block == mf_classic_get_sector_trailer_num_by_block(block); +bool mifare_classic_is_sector_trailer(uint8_t block) { + return block == mifare_classic_get_sector_trailer_num_by_block(block); } MfClassicSectorTrailer* - mf_classic_get_sector_trailer_by_sector(MfClassicData* data, uint8_t sector) { + mifare_classic_get_sector_trailer_by_sector(MfClassicData* data, uint8_t sector) { furi_assert(data); - uint8_t sec_tr_block_num = mf_classic_get_sector_trailer_block_num_by_sector(sector); + uint8_t sec_tr_block_num = mifare_classic_get_sector_trailer_block_num_by_sector(sector); return (MfClassicSectorTrailer*)data->block[sec_tr_block_num].value; } -uint8_t mf_classic_get_total_sectors_num(MfClassicType type) { +uint8_t mifare_classic_get_total_sectors_num(MfClassicType type) { if(type == MfClassicTypeMini) { return MF_MINI_TOTAL_SECTORS_NUM; } else if(type == MfClassicType1k) { @@ -93,7 +93,7 @@ uint8_t mf_classic_get_total_sectors_num(MfClassicType type) { } } -uint16_t mf_classic_get_total_block_num(MfClassicType type) { +uint16_t mifare_classic_get_total_block_num(MfClassicType type) { if(type == MfClassicTypeMini) { return 20; } else if(type == MfClassicType1k) { @@ -105,16 +105,16 @@ uint16_t mf_classic_get_total_block_num(MfClassicType type) { } } -bool mf_classic_is_block_read(MfClassicData* data, uint8_t block_num) { +bool mifare_classic_is_block_read(MfClassicData* data, uint8_t block_num) { furi_assert(data); return (FURI_BIT(data->block_read_mask[block_num / 32], block_num % 32) == 1); } -void mf_classic_set_block_read(MfClassicData* data, uint8_t block_num, MfClassicBlock* block_data) { +void mifare_classic_set_block_read(MfClassicData* data, uint8_t block_num, MfClassicBlock* block_data) { furi_assert(data); - if(mf_classic_is_sector_trailer(block_num)) { + if(mifare_classic_is_sector_trailer(block_num)) { memcpy(&data->block[block_num].value[6], &block_data->value[6], 4); } else { memcpy(data->block[block_num].value, block_data->value, MF_CLASSIC_BLOCK_SIZE); @@ -122,25 +122,25 @@ void mf_classic_set_block_read(MfClassicData* data, uint8_t block_num, MfClassic FURI_BIT_SET(data->block_read_mask[block_num / 32], block_num % 32); } -bool mf_classic_is_sector_data_read(MfClassicData* data, uint8_t sector_num) { +bool mifare_classic_is_sector_data_read(MfClassicData* data, uint8_t sector_num) { furi_assert(data); uint8_t first_block = mf_classic_get_first_block_num_of_sector(sector_num); uint8_t total_blocks = mf_classic_get_blocks_num_in_sector(sector_num); bool data_read = true; for(size_t i = first_block; i < first_block + total_blocks; i++) { - data_read &= mf_classic_is_block_read(data, i); + data_read &= mifare_classic_is_block_read(data, i); } return data_read; } -void mf_classic_set_sector_data_not_read(MfClassicData* data) { +void mifare_classic_set_sector_data_not_read(MfClassicData* data) { furi_assert(data); memset(data->block_read_mask, 0, sizeof(data->block_read_mask)); } -bool mf_classic_is_key_found(MfClassicData* data, uint8_t sector_num, MfClassicKey key_type) { +bool mifare_classic_is_key_found(MfClassicData* data, uint8_t sector_num, MfClassicKey key_type) { furi_assert(data); bool key_found = false; @@ -153,7 +153,7 @@ bool mf_classic_is_key_found(MfClassicData* data, uint8_t sector_num, MfClassicK return key_found; } -void mf_classic_set_key_found( +void mifare_classic_set_key_found( MfClassicData* data, uint8_t sector_num, MfClassicKey key_type, @@ -162,7 +162,7 @@ void mf_classic_set_key_found( uint8_t key_arr[6] = {}; MfClassicSectorTrailer* sec_trailer = - mf_classic_get_sector_trailer_by_sector(data, sector_num); + mifare_classic_get_sector_trailer_by_sector(data, sector_num); nfc_util_num2bytes(key, 6, key_arr); if(key_type == MfClassicKeyA) { memcpy(sec_trailer->key_a, key_arr, sizeof(sec_trailer->key_a)); @@ -173,7 +173,7 @@ void mf_classic_set_key_found( } } -void mf_classic_set_key_not_found(MfClassicData* data, uint8_t sector_num, MfClassicKey key_type) { +void mifare_classic_set_key_not_found(MfClassicData* data, uint8_t sector_num, MfClassicKey key_type) { furi_assert(data); if(key_type == MfClassicKeyA) { @@ -183,18 +183,18 @@ void mf_classic_set_key_not_found(MfClassicData* data, uint8_t sector_num, MfCla } } -bool mf_classic_is_sector_read(MfClassicData* data, uint8_t sector_num) { +bool mifare_classic_is_sector_read(MfClassicData* data, uint8_t sector_num) { furi_assert(data); bool sector_read = false; do { - if(!mf_classic_is_key_found(data, sector_num, MfClassicKeyA)) break; - if(!mf_classic_is_key_found(data, sector_num, MfClassicKeyB)) break; + if(!mifare_classic_is_key_found(data, sector_num, MfClassicKeyA)) break; + if(!mifare_classic_is_key_found(data, sector_num, MfClassicKeyB)) break; uint8_t start_block = mf_classic_get_first_block_num_of_sector(sector_num); uint8_t total_blocks = mf_classic_get_blocks_num_in_sector(sector_num); uint8_t block_read = true; for(size_t i = start_block; i < start_block + total_blocks; i++) { - block_read = mf_classic_is_block_read(data, i); + block_read = mifare_classic_is_block_read(data, i); if(!block_read) break; } sector_read = block_read; @@ -203,7 +203,7 @@ bool mf_classic_is_sector_read(MfClassicData* data, uint8_t sector_num) { return sector_read; } -void mf_classic_get_read_sectors_and_keys( +void mifare_classic_get_read_sectors_and_keys( MfClassicData* data, uint8_t* sectors_read, uint8_t* keys_found) { @@ -213,19 +213,19 @@ void mf_classic_get_read_sectors_and_keys( *sectors_read = 0; *keys_found = 0; - uint8_t sectors_total = mf_classic_get_total_sectors_num(data->type); + uint8_t sectors_total = mifare_classic_get_total_sectors_num(data->type); for(size_t i = 0; i < sectors_total; i++) { - if(mf_classic_is_key_found(data, i, MfClassicKeyA)) { + if(mifare_classic_is_key_found(data, i, MfClassicKeyA)) { *keys_found += 1; } - if(mf_classic_is_key_found(data, i, MfClassicKeyB)) { + if(mifare_classic_is_key_found(data, i, MfClassicKeyB)) { *keys_found += 1; } uint8_t first_block = mf_classic_get_first_block_num_of_sector(i); uint8_t total_blocks_in_sec = mf_classic_get_blocks_num_in_sector(i); bool blocks_read = true; for(size_t j = first_block; j < first_block + total_blocks_in_sec; j++) { - blocks_read = mf_classic_is_block_read(data, j); + blocks_read = mifare_classic_is_block_read(data, j); if(!blocks_read) break; } if(blocks_read) { @@ -234,13 +234,13 @@ void mf_classic_get_read_sectors_and_keys( } } -bool mf_classic_is_card_read(MfClassicData* data) { +bool mifare_classic_is_card_read(MfClassicData* data) { furi_assert(data); - uint8_t sectors_total = mf_classic_get_total_sectors_num(data->type); + uint8_t sectors_total = mifare_classic_get_total_sectors_num(data->type); uint8_t sectors_read = 0; uint8_t keys_found = 0; - mf_classic_get_read_sectors_and_keys(data, §ors_read, &keys_found); + mifare_classic_get_read_sectors_and_keys(data, §ors_read, &keys_found); bool card_read = (sectors_read == sectors_total) && (keys_found == sectors_total * 2); return card_read; @@ -283,13 +283,13 @@ bool mf_classic_is_allowed_access_sector_trailer( return true; } -bool mf_classic_is_allowed_access_data_block( +bool mifare_classic_is_allowed_access_data_block( MfClassicData* data, uint8_t block_num, MfClassicKey key, MfClassicAction action) { uint8_t* sector_trailer = - data->block[mf_classic_get_sector_trailer_num_by_block(block_num)].value; + data->block[mifare_classic_get_sector_trailer_num_by_block(block_num)].value; if(block_num == 0 && action == MfClassicActionDataWrite) { return false; @@ -356,25 +356,25 @@ static bool mf_classic_is_allowed_access( uint8_t block_num, MfClassicKey key, MfClassicAction action) { - if(mf_classic_is_sector_trailer(block_num)) { + if(mifare_classic_is_sector_trailer(block_num)) { return mf_classic_is_allowed_access_sector_trailer( &emulator->data, block_num, key, action); } else { - return mf_classic_is_allowed_access_data_block(&emulator->data, block_num, key, action); + return mifare_classic_is_allowed_access_data_block(&emulator->data, block_num, key, action); } } -bool mf_classic_is_value_block(MfClassicData* data, uint8_t block_num) { +bool mifare_classic_is_value_block(MfClassicData* data, uint8_t block_num) { // Check if key A can write, if it can, it's transport configuration, not data block - return !mf_classic_is_allowed_access_data_block( + return !mifare_classic_is_allowed_access_data_block( data, block_num, MfClassicKeyA, MfClassicActionDataWrite) && - (mf_classic_is_allowed_access_data_block( + (mifare_classic_is_allowed_access_data_block( data, block_num, MfClassicKeyB, MfClassicActionDataInc) || - mf_classic_is_allowed_access_data_block( + mifare_classic_is_allowed_access_data_block( data, block_num, MfClassicKeyB, MfClassicActionDataDec)); } -bool mf_classic_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK) { +bool mifare_classic_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK) { UNUSED(ATQA1); if((ATQA0 == 0x44 || ATQA0 == 0x04) && (SAK == 0x08 || SAK == 0x88 || SAK == 0x09)) { return true; @@ -388,7 +388,7 @@ bool mf_classic_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK) { } } -MfClassicType mf_classic_get_classic_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK) { +MfClassicType mifare_classic_get_classic_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK) { UNUSED(ATQA1); if((ATQA0 == 0x44 || ATQA0 == 0x04)) { if((SAK == 0x08 || SAK == 0x88)) { @@ -405,7 +405,7 @@ MfClassicType mf_classic_get_classic_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t return MfClassicType1k; } -void mf_classic_reader_add_sector( +void mifare_classic_reader_add_sector( MfClassicReader* reader, uint8_t sector, uint64_t key_a, @@ -422,7 +422,7 @@ void mf_classic_reader_add_sector( } } -bool mf_classic_block_to_value(const uint8_t* block, int32_t* value, uint8_t* addr) { +bool mifare_classic_block_to_value(const uint8_t* block, int32_t* value, uint8_t* addr) { uint32_t v = *(uint32_t*)&block[0]; uint32_t v_inv = *(uint32_t*)&block[4]; uint32_t v1 = *(uint32_t*)&block[8]; @@ -439,7 +439,7 @@ bool mf_classic_block_to_value(const uint8_t* block, int32_t* value, uint8_t* ad return val_checks; } -void mf_classic_value_to_block(int32_t value, uint8_t addr, uint8_t* block) { +void mifare_classic_value_to_block(int32_t value, uint8_t addr, uint8_t* block) { uint32_t v_inv = ~((uint32_t)value); memcpy(block, &value, 4); //-V1086 @@ -452,7 +452,7 @@ void mf_classic_value_to_block(int32_t value, uint8_t addr, uint8_t* block) { block[15] = ~addr & 0xFF; } -void mf_classic_auth_init_context(MfClassicAuthContext* auth_ctx, uint8_t sector) { +void mifare_classic_auth_init_context(MfClassicAuthContext* auth_ctx, uint8_t sector) { furi_assert(auth_ctx); auth_ctx->sector = sector; auth_ctx->key_a = MF_CLASSIC_NO_KEY; @@ -514,7 +514,7 @@ static bool mf_classic_auth( return auth_success; } -bool mf_classic_authenticate( +bool mifare_classic_authenticate( FuriHalNfcTxRxContext* tx_rx, uint8_t block_num, uint64_t key, @@ -527,7 +527,7 @@ bool mf_classic_authenticate( return key_found; } -bool mf_classic_authenticate_skip_activate( +bool mifare_classic_authenticate_skip_activate( FuriHalNfcTxRxContext* tx_rx, uint8_t block_num, uint64_t key, @@ -543,7 +543,7 @@ bool mf_classic_authenticate_skip_activate( return key_found; } -bool mf_classic_auth_attempt( +bool mifare_classic_auth_attempt( FuriHalNfcTxRxContext* tx_rx, Crypto1* crypto, MfClassicAuthContext* auth_ctx, @@ -558,7 +558,7 @@ bool mf_classic_auth_attempt( // Try AUTH with key A if(mf_classic_auth( tx_rx, - mf_classic_get_sector_trailer_block_num_by_sector(auth_ctx->sector), + mifare_classic_get_sector_trailer_block_num_by_sector(auth_ctx->sector), key, MfClassicKeyA, crypto, @@ -577,7 +577,7 @@ bool mf_classic_auth_attempt( // Try AUTH with key B if(mf_classic_auth( tx_rx, - mf_classic_get_sector_trailer_block_num_by_sector(auth_ctx->sector), + mifare_classic_get_sector_trailer_block_num_by_sector(auth_ctx->sector), key, MfClassicKeyB, crypto, @@ -591,7 +591,7 @@ bool mf_classic_auth_attempt( return found_key; } -bool mf_classic_read_block( +bool mifare_classic_read_block( FuriHalNfcTxRxContext* tx_rx, Crypto1* crypto, uint8_t block_num, @@ -601,7 +601,7 @@ bool mf_classic_read_block( furi_assert(block); bool read_block_success = false; - uint8_t plain_cmd[4] = {MF_CLASSIC_READ_BLOCK_CMD, block_num, 0x00, 0x00}; + uint8_t plain_cmd[4] = {mifare_classic_read_block_CMD, block_num, 0x00, 0x00}; nfca_append_crc16(plain_cmd, 2); crypto1_encrypt( @@ -632,18 +632,18 @@ bool mf_classic_read_block( return read_block_success; } -void mf_classic_read_sector(FuriHalNfcTxRxContext* tx_rx, MfClassicData* data, uint8_t sec_num) { +void mifare_classic_read_sector(FuriHalNfcTxRxContext* tx_rx, MfClassicData* data, uint8_t sec_num) { furi_assert(tx_rx); furi_assert(data); furi_hal_nfc_sleep(); - bool key_a_found = mf_classic_is_key_found(data, sec_num, MfClassicKeyA); - bool key_b_found = mf_classic_is_key_found(data, sec_num, MfClassicKeyB); + bool key_a_found = mifare_classic_is_key_found(data, sec_num, MfClassicKeyA); + bool key_b_found = mifare_classic_is_key_found(data, sec_num, MfClassicKeyB); uint8_t start_block = mf_classic_get_first_block_num_of_sector(sec_num); uint8_t total_blocks = mf_classic_get_blocks_num_in_sector(sec_num); MfClassicBlock block_tmp = {}; uint64_t key = 0; - MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(data, sec_num); + MfClassicSectorTrailer* sec_tr = mifare_classic_get_sector_trailer_by_sector(data, sec_num); Crypto1 crypto = {}; uint8_t blocks_read = 0; @@ -652,26 +652,26 @@ void mf_classic_read_sector(FuriHalNfcTxRxContext* tx_rx, MfClassicData* data, u FURI_LOG_D(TAG, "Try to read blocks with key A"); key = nfc_util_bytes2num(sec_tr->key_a, sizeof(sec_tr->key_a)); if(!mf_classic_auth(tx_rx, start_block, key, MfClassicKeyA, &crypto, false, 0)) { - mf_classic_set_key_not_found(data, sec_num, MfClassicKeyA); + mifare_classic_set_key_not_found(data, sec_num, MfClassicKeyA); FURI_LOG_D(TAG, "Key %dA not found in read", sec_num); break; } for(size_t i = start_block; i < start_block + total_blocks; i++) { - if(!mf_classic_is_block_read(data, i)) { - if(mf_classic_read_block(tx_rx, &crypto, i, &block_tmp)) { - mf_classic_set_block_read(data, i, &block_tmp); + if(!mifare_classic_is_block_read(data, i)) { + if(mifare_classic_read_block(tx_rx, &crypto, i, &block_tmp)) { + mifare_classic_set_block_read(data, i, &block_tmp); blocks_read++; } else if(i > start_block) { // Try to re-auth to read block in case prevous block was protected from read furi_hal_nfc_sleep(); if(!mf_classic_auth(tx_rx, i, key, MfClassicKeyA, &crypto, false, 0)) { - mf_classic_set_key_not_found(data, sec_num, MfClassicKeyA); + mifare_classic_set_key_not_found(data, sec_num, MfClassicKeyA); FURI_LOG_D(TAG, "Key %dA not found in read", sec_num); break; } - if(mf_classic_read_block(tx_rx, &crypto, i, &block_tmp)) { - mf_classic_set_block_read(data, i, &block_tmp); + if(mifare_classic_read_block(tx_rx, &crypto, i, &block_tmp)) { + mifare_classic_set_block_read(data, i, &block_tmp); blocks_read++; } } @@ -690,26 +690,26 @@ void mf_classic_read_sector(FuriHalNfcTxRxContext* tx_rx, MfClassicData* data, u FURI_LOG_D(TAG, "Try to read blocks with key B"); key = nfc_util_bytes2num(sec_tr->key_b, sizeof(sec_tr->key_b)); if(!mf_classic_auth(tx_rx, start_block, key, MfClassicKeyB, &crypto, false, 0)) { - mf_classic_set_key_not_found(data, sec_num, MfClassicKeyB); + mifare_classic_set_key_not_found(data, sec_num, MfClassicKeyB); FURI_LOG_D(TAG, "Key %dB not found in read", sec_num); break; } for(size_t i = start_block; i < start_block + total_blocks; i++) { - if(!mf_classic_is_block_read(data, i)) { - if(mf_classic_read_block(tx_rx, &crypto, i, &block_tmp)) { - mf_classic_set_block_read(data, i, &block_tmp); + if(!mifare_classic_is_block_read(data, i)) { + if(mifare_classic_read_block(tx_rx, &crypto, i, &block_tmp)) { + mifare_classic_set_block_read(data, i, &block_tmp); blocks_read++; } else if(i > start_block) { // Try to re-auth to read block in case prevous block was protected from read furi_hal_nfc_sleep(); if(!mf_classic_auth(tx_rx, i, key, MfClassicKeyB, &crypto, false, 0)) { - mf_classic_set_key_not_found(data, sec_num, MfClassicKeyB); + mifare_classic_set_key_not_found(data, sec_num, MfClassicKeyB); FURI_LOG_D(TAG, "Key %dB not found in read", sec_num); break; } - if(mf_classic_read_block(tx_rx, &crypto, i, &block_tmp)) { - mf_classic_set_block_read(data, i, &block_tmp); + if(mifare_classic_read_block(tx_rx, &crypto, i, &block_tmp)) { + mifare_classic_set_block_read(data, i, &block_tmp); blocks_read++; } } @@ -721,7 +721,7 @@ void mf_classic_read_sector(FuriHalNfcTxRxContext* tx_rx, MfClassicData* data, u } while(false); } -static bool mf_classic_read_sector_with_reader( +static bool mifare_classic_read_sector_with_reader( FuriHalNfcTxRxContext* tx_rx, Crypto1* crypto, MfClassicSectorReader* sector_reader, @@ -763,12 +763,12 @@ static bool mf_classic_read_sector_with_reader( // Read blocks for(uint8_t i = 0; i < sector->total_blocks; i++) { - if(mf_classic_read_block(tx_rx, crypto, first_block + i, §or->block[i])) continue; + if(mifare_classic_read_block(tx_rx, crypto, first_block + i, §or->block[i])) continue; if(i == 0) continue; // Try to auth to read next block in case previous is locked furi_hal_nfc_sleep(); if(!mf_classic_auth(tx_rx, first_block + i, key, key_type, crypto, false, 0)) continue; - mf_classic_read_block(tx_rx, crypto, first_block + i, §or->block[i]); + mifare_classic_read_block(tx_rx, crypto, first_block + i, §or->block[i]); } // Save sector keys in last block if(sector_reader->key_a != MF_CLASSIC_NO_KEY) { @@ -786,7 +786,7 @@ static bool mf_classic_read_sector_with_reader( return sector_read; } -uint8_t mf_classic_read_card( +uint8_t mifare_classic_read_card( FuriHalNfcTxRxContext* tx_rx, MfClassicReader* reader, MfClassicData* data) { @@ -800,22 +800,22 @@ uint8_t mf_classic_read_card( data->key_b_mask = 0; MfClassicSector temp_sector = {}; for(uint8_t i = 0; i < reader->sectors_to_read; i++) { - if(mf_classic_read_sector_with_reader( + if(mifare_classic_read_sector_with_reader( tx_rx, &reader->crypto, &reader->sector_reader[i], &temp_sector)) { uint8_t first_block = mf_classic_get_first_block_num_of_sector(reader->sector_reader[i].sector_num); for(uint8_t j = 0; j < temp_sector.total_blocks; j++) { - mf_classic_set_block_read(data, first_block + j, &temp_sector.block[j]); + mifare_classic_set_block_read(data, first_block + j, &temp_sector.block[j]); } if(reader->sector_reader[i].key_a != MF_CLASSIC_NO_KEY) { - mf_classic_set_key_found( + mifare_classic_set_key_found( data, reader->sector_reader[i].sector_num, MfClassicKeyA, reader->sector_reader[i].key_a); } if(reader->sector_reader[i].key_b != MF_CLASSIC_NO_KEY) { - mf_classic_set_key_found( + mifare_classic_set_key_found( data, reader->sector_reader[i].sector_num, MfClassicKeyB, @@ -828,24 +828,24 @@ uint8_t mf_classic_read_card( return sectors_read; } -uint8_t mf_classic_update_card(FuriHalNfcTxRxContext* tx_rx, MfClassicData* data) { +uint8_t mifare_classic_update_card(FuriHalNfcTxRxContext* tx_rx, MfClassicData* data) { furi_assert(tx_rx); furi_assert(data); - uint8_t total_sectors = mf_classic_get_total_sectors_num(data->type); + uint8_t total_sectors = mifare_classic_get_total_sectors_num(data->type); for(size_t i = 0; i < total_sectors; i++) { - mf_classic_read_sector(tx_rx, data, i); + mifare_classic_read_sector(tx_rx, data, i); } uint8_t sectors_read = 0; uint8_t keys_found = 0; - mf_classic_get_read_sectors_and_keys(data, §ors_read, &keys_found); + mifare_classic_get_read_sectors_and_keys(data, §ors_read, &keys_found); FURI_LOG_D(TAG, "Read %d sectors and %d keys", sectors_read, keys_found); return sectors_read; } -bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_rx) { +bool mifare_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_rx) { furi_assert(emulator); furi_assert(tx_rx); bool command_processed = false; @@ -875,7 +875,7 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_ // After increment, decrement or restore the only allowed command is transfer uint8_t cmd = plain_data[0]; - if(transfer_buf_valid && cmd != MF_CLASSIC_TRANSFER_CMD) { + if(transfer_buf_valid && cmd != mifare_classic_transfer_CMD) { break; } @@ -888,7 +888,7 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_ if(cmd == MF_CLASSIC_AUTH_KEY_A_CMD || cmd == MF_CLASSIC_AUTH_KEY_B_CMD) { uint8_t block = plain_data[1]; uint64_t key = 0; - uint8_t sector_trailer_block = mf_classic_get_sector_trailer_num_by_block(block); + uint8_t sector_trailer_block = mifare_classic_get_sector_trailer_num_by_block(block); MfClassicSectorTrailer* sector_trailer = (MfClassicSectorTrailer*)emulator->data.block[sector_trailer_block].value; if(cmd == MF_CLASSIC_AUTH_KEY_A_CMD) { @@ -969,11 +969,11 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_ break; } - if(cmd == MF_CLASSIC_READ_BLOCK_CMD) { + if(cmd == mifare_classic_read_block_CMD) { uint8_t block = plain_data[1]; uint8_t block_data[MF_CLASSIC_BLOCK_SIZE + 2] = {}; memcpy(block_data, emulator->data.block[block].value, MF_CLASSIC_BLOCK_SIZE); - if(mf_classic_is_sector_trailer(block)) { + if(mifare_classic_is_sector_trailer(block)) { if(!mf_classic_is_allowed_access( emulator, block, access_key, MfClassicActionKeyARead)) { memset(block_data, 0, 6); //-V1086 @@ -1008,9 +1008,9 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_ tx_rx->tx_parity); tx_rx->tx_bits = (MF_CLASSIC_BLOCK_SIZE + 2) * 8; tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent; - } else if(cmd == MF_CLASSIC_WRITE_BLOCK_CMD) { + } else if(cmd == mifare_classic_write_block_CMD) { uint8_t block = plain_data[1]; - if(block > mf_classic_get_total_block_num(emulator->data.type)) { + if(block > mifare_classic_get_total_block_num(emulator->data.type)) { break; } // Send ACK @@ -1025,7 +1025,7 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_ crypto1_decrypt(&emulator->crypto, tx_rx->rx_data, tx_rx->rx_bits, plain_data); uint8_t block_data[MF_CLASSIC_BLOCK_SIZE] = {}; memcpy(block_data, emulator->data.block[block].value, MF_CLASSIC_BLOCK_SIZE); - if(mf_classic_is_sector_trailer(block)) { + if(mifare_classic_is_sector_trailer(block)) { if(mf_classic_is_allowed_access( emulator, block, access_key, MfClassicActionKeyAWrite)) { memcpy(block_data, plain_data, 6); //-V1086 @@ -1060,7 +1060,7 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_ cmd == MF_CLASSIC_RESTORE_CMD) { uint8_t block = plain_data[1]; - if(block > mf_classic_get_total_block_num(emulator->data.type)) { + if(block > mifare_classic_get_total_block_num(emulator->data.type)) { break; } @@ -1074,7 +1074,7 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_ int32_t prev_value; uint8_t addr; - if(!mf_classic_block_to_value(emulator->data.block[block].value, &prev_value, &addr)) { + if(!mifare_classic_block_to_value(emulator->data.block[block].value, &prev_value, &addr)) { break; } @@ -1098,11 +1098,11 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_ value = 0; } - mf_classic_value_to_block(prev_value + value, addr, transfer_buf); + mifare_classic_value_to_block(prev_value + value, addr, transfer_buf); transfer_buf_valid = true; // Commands do not ACK tx_rx->tx_bits = 0; - } else if(cmd == MF_CLASSIC_TRANSFER_CMD) { + } else if(cmd == mifare_classic_transfer_CMD) { uint8_t block = plain_data[1]; if(!mf_classic_is_allowed_access(emulator, block, access_key, MfClassicActionDataDec)) { break; @@ -1141,7 +1141,7 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_ return true; } -void mf_classic_halt(FuriHalNfcTxRxContext* tx_rx, Crypto1* crypto) { +void mifare_classic_halt(FuriHalNfcTxRxContext* tx_rx, Crypto1* crypto) { furi_assert(tx_rx); uint8_t plain_data[4] = {0x50, 0x00, 0x00, 0x00}; @@ -1160,7 +1160,7 @@ void mf_classic_halt(FuriHalNfcTxRxContext* tx_rx, Crypto1* crypto) { furi_hal_nfc_tx_rx(tx_rx, 50); } -bool mf_classic_write_block( +bool mifare_classic_write_block( FuriHalNfcTxRxContext* tx_rx, Crypto1* crypto, uint8_t block_num, @@ -1175,7 +1175,7 @@ bool mf_classic_write_block( do { // Send write command - plain_data[0] = MF_CLASSIC_WRITE_BLOCK_CMD; + plain_data[0] = mifare_classic_write_block_CMD; plain_data[1] = block_num; nfca_append_crc16(plain_data, 2); crypto1_encrypt(crypto, NULL, plain_data, 4 * 8, tx_rx->tx_data, tx_rx->tx_parity); @@ -1232,7 +1232,7 @@ bool mf_classic_write_block( return write_success; } -bool mf_classic_auth_write_block( +bool mifare_classic_auth_write_block( FuriHalNfcTxRxContext* tx_rx, MfClassicBlock* src_block, uint8_t block_num, @@ -1251,24 +1251,24 @@ bool mf_classic_auth_write_block( break; } - if(!mf_classic_write_block(tx_rx, &crypto, block_num, src_block)) { + if(!mifare_classic_write_block(tx_rx, &crypto, block_num, src_block)) { FURI_LOG_D(TAG, "Write fail"); break; } write_success = true; - mf_classic_halt(tx_rx, &crypto); + mifare_classic_halt(tx_rx, &crypto); } while(false); return write_success; } -bool mf_classic_transfer(FuriHalNfcTxRxContext* tx_rx, Crypto1* crypto, uint8_t block_num) { +bool mifare_classic_transfer(FuriHalNfcTxRxContext* tx_rx, Crypto1* crypto, uint8_t block_num) { furi_assert(tx_rx); furi_assert(crypto); // Send transfer command - uint8_t plain_data[4] = {MF_CLASSIC_TRANSFER_CMD, block_num, 0, 0}; + uint8_t plain_data[4] = {mifare_classic_transfer_CMD, block_num, 0, 0}; uint8_t resp = 0; bool transfer_success = false; @@ -1301,7 +1301,7 @@ bool mf_classic_transfer(FuriHalNfcTxRxContext* tx_rx, Crypto1* crypto, uint8_t return transfer_success; } -bool mf_classic_value_cmd( +bool mifare_classic_value_cmd( FuriHalNfcTxRxContext* tx_rx, Crypto1* crypto, uint8_t block_num, @@ -1371,7 +1371,7 @@ bool mf_classic_value_cmd( return success; } -bool mf_classic_value_cmd_full( +bool mifare_classic_value_cmd_full( FuriHalNfcTxRxContext* tx_rx, MfClassicBlock* src_block, uint8_t block_num, @@ -1400,12 +1400,12 @@ bool mf_classic_value_cmd_full( FURI_LOG_D(TAG, "Value cmd auth fail"); break; } - if(!mf_classic_value_cmd(tx_rx, &crypto, block_num, cmd, d_value)) { + if(!mifare_classic_value_cmd(tx_rx, &crypto, block_num, cmd, d_value)) { FURI_LOG_D(TAG, "Value cmd inc/dec/res fail"); break; } - if(!mf_classic_transfer(tx_rx, &crypto, block_num)) { + if(!mifare_classic_transfer(tx_rx, &crypto, block_num)) { FURI_LOG_D(TAG, "Value cmd transfer fail"); break; } @@ -1413,13 +1413,13 @@ bool mf_classic_value_cmd_full( success = true; // Send Halt - mf_classic_halt(tx_rx, &crypto); + mifare_classic_halt(tx_rx, &crypto); } while(false); return success; } -bool mf_classic_write_sector( +bool mifare_classic_write_sector( FuriHalNfcTxRxContext* tx_rx, MfClassicData* dest_data, MfClassicData* src_data, @@ -1430,29 +1430,29 @@ bool mf_classic_write_sector( uint8_t first_block = mf_classic_get_first_block_num_of_sector(sec_num); uint8_t total_blocks = mf_classic_get_blocks_num_in_sector(sec_num); - MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(dest_data, sec_num); - bool key_a_found = mf_classic_is_key_found(dest_data, sec_num, MfClassicKeyA); - bool key_b_found = mf_classic_is_key_found(dest_data, sec_num, MfClassicKeyB); + MfClassicSectorTrailer* sec_tr = mifare_classic_get_sector_trailer_by_sector(dest_data, sec_num); + bool key_a_found = mifare_classic_is_key_found(dest_data, sec_num, MfClassicKeyA); + bool key_b_found = mifare_classic_is_key_found(dest_data, sec_num, MfClassicKeyB); bool write_success = true; for(size_t i = first_block; i < first_block + total_blocks; i++) { // Compare blocks if(memcmp(dest_data->block[i].value, src_data->block[i].value, MF_CLASSIC_BLOCK_SIZE) != 0) { - if(mf_classic_is_value_block(dest_data, i)) { - bool key_a_inc_allowed = mf_classic_is_allowed_access_data_block( + if(mifare_classic_is_value_block(dest_data, i)) { + bool key_a_inc_allowed = mifare_classic_is_allowed_access_data_block( dest_data, i, MfClassicKeyA, MfClassicActionDataInc); - bool key_b_inc_allowed = mf_classic_is_allowed_access_data_block( + bool key_b_inc_allowed = mifare_classic_is_allowed_access_data_block( dest_data, i, MfClassicKeyB, MfClassicActionDataInc); - bool key_a_dec_allowed = mf_classic_is_allowed_access_data_block( + bool key_a_dec_allowed = mifare_classic_is_allowed_access_data_block( dest_data, i, MfClassicKeyA, MfClassicActionDataDec); - bool key_b_dec_allowed = mf_classic_is_allowed_access_data_block( + bool key_b_dec_allowed = mifare_classic_is_allowed_access_data_block( dest_data, i, MfClassicKeyB, MfClassicActionDataDec); int32_t src_value, dst_value; - mf_classic_block_to_value(src_data->block[i].value, &src_value, NULL); - mf_classic_block_to_value(dest_data->block[i].value, &dst_value, NULL); + mifare_classic_block_to_value(src_data->block[i].value, &src_value, NULL); + mifare_classic_block_to_value(dest_data->block[i].value, &dst_value, NULL); int32_t diff = src_value - dst_value; @@ -1460,7 +1460,7 @@ bool mf_classic_write_sector( if(key_a_found && key_a_inc_allowed) { FURI_LOG_I(TAG, "Incrementing block %d with key A by %ld", i, diff); uint64_t key = nfc_util_bytes2num(sec_tr->key_a, 6); - if(!mf_classic_value_cmd_full( + if(!mifare_classic_value_cmd_full( tx_rx, &src_data->block[i], i, MfClassicKeyA, key, diff)) { FURI_LOG_E(TAG, "Failed to increment block %d", i); write_success = false; @@ -1469,7 +1469,7 @@ bool mf_classic_write_sector( } else if(key_b_found && key_b_inc_allowed) { FURI_LOG_I(TAG, "Incrementing block %d with key B by %ld", i, diff); uint64_t key = nfc_util_bytes2num(sec_tr->key_b, 6); - if(!mf_classic_value_cmd_full( + if(!mifare_classic_value_cmd_full( tx_rx, &src_data->block[i], i, MfClassicKeyB, key, diff)) { FURI_LOG_E(TAG, "Failed to increment block %d", i); write_success = false; @@ -1482,7 +1482,7 @@ bool mf_classic_write_sector( if(key_a_found && key_a_dec_allowed) { FURI_LOG_I(TAG, "Decrementing block %d with key A by %ld", i, -diff); uint64_t key = nfc_util_bytes2num(sec_tr->key_a, 6); - if(!mf_classic_value_cmd_full( + if(!mifare_classic_value_cmd_full( tx_rx, &src_data->block[i], i, MfClassicKeyA, key, diff)) { FURI_LOG_E(TAG, "Failed to decrement block %d", i); write_success = false; @@ -1491,7 +1491,7 @@ bool mf_classic_write_sector( } else if(key_b_found && key_b_dec_allowed) { FURI_LOG_I(TAG, "Decrementing block %d with key B by %ld", i, diff); uint64_t key = nfc_util_bytes2num(sec_tr->key_b, 6); - if(!mf_classic_value_cmd_full( + if(!mifare_classic_value_cmd_full( tx_rx, &src_data->block[i], i, MfClassicKeyB, key, diff)) { FURI_LOG_E(TAG, "Failed to decrement block %d", i); write_success = false; @@ -1504,15 +1504,15 @@ bool mf_classic_write_sector( FURI_LOG_E(TAG, "Value block %d address changed, cannot write it", i); } } else { - bool key_a_write_allowed = mf_classic_is_allowed_access_data_block( + bool key_a_write_allowed = mifare_classic_is_allowed_access_data_block( dest_data, i, MfClassicKeyA, MfClassicActionDataWrite); - bool key_b_write_allowed = mf_classic_is_allowed_access_data_block( + bool key_b_write_allowed = mifare_classic_is_allowed_access_data_block( dest_data, i, MfClassicKeyB, MfClassicActionDataWrite); if(key_a_found && key_a_write_allowed) { FURI_LOG_I(TAG, "Writing block %d with key A", i); uint64_t key = nfc_util_bytes2num(sec_tr->key_a, 6); - if(!mf_classic_auth_write_block( + if(!mifare_classic_auth_write_block( tx_rx, &src_data->block[i], i, MfClassicKeyA, key)) { FURI_LOG_E(TAG, "Failed to write block %d", i); write_success = false; @@ -1521,7 +1521,7 @@ bool mf_classic_write_sector( } else if(key_b_found && key_b_write_allowed) { FURI_LOG_I(TAG, "Writing block %d with key A", i); uint64_t key = nfc_util_bytes2num(sec_tr->key_b, 6); - if(!mf_classic_auth_write_block( + if(!mifare_classic_auth_write_block( tx_rx, &src_data->block[i], i, MfClassicKeyB, key)) { FURI_LOG_E(TAG, "Failed to write block %d", i); write_success = false; diff --git a/lib/nfc/protocols/mifare_classic.h b/lib/nfc/protocols/mifare_classic.h index c03350f2e938..269ef9f1a866 100644 --- a/lib/nfc/protocols/mifare_classic.h +++ b/lib/nfc/protocols/mifare_classic.h @@ -92,21 +92,21 @@ typedef struct { bool data_changed; } MfClassicEmulator; -const char* mf_classic_get_type_str(MfClassicType type); +const char* mifare_classic_get_type_str(MfClassicType type); -bool mf_classic_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK); +bool mifare_classic_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK); -MfClassicType mf_classic_get_classic_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK); +MfClassicType mifare_classic_get_classic_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK); -uint8_t mf_classic_get_total_sectors_num(MfClassicType type); +uint8_t mifare_classic_get_total_sectors_num(MfClassicType type); -uint16_t mf_classic_get_total_block_num(MfClassicType type); +uint16_t mifare_classic_get_total_block_num(MfClassicType type); -uint8_t mf_classic_get_sector_trailer_block_num_by_sector(uint8_t sector); +uint8_t mifare_classic_get_sector_trailer_block_num_by_sector(uint8_t sector); -bool mf_classic_is_sector_trailer(uint8_t block); +bool mifare_classic_is_sector_trailer(uint8_t block); -uint8_t mf_classic_get_sector_by_block(uint8_t block); +uint8_t mifare_classic_get_sector_by_block(uint8_t block); bool mf_classic_is_allowed_access_sector_trailer( MfClassicData* data, @@ -114,57 +114,57 @@ bool mf_classic_is_allowed_access_sector_trailer( MfClassicKey key, MfClassicAction action); -bool mf_classic_is_allowed_access_data_block( +bool mifare_classic_is_allowed_access_data_block( MfClassicData* data, uint8_t block_num, MfClassicKey key, MfClassicAction action); -bool mf_classic_is_value_block(MfClassicData* data, uint8_t block_num); +bool mifare_classic_is_value_block(MfClassicData* data, uint8_t block_num); -bool mf_classic_block_to_value(const uint8_t* block, int32_t* value, uint8_t* addr); +bool mifare_classic_block_to_value(const uint8_t* block, int32_t* value, uint8_t* addr); -void mf_classic_value_to_block(int32_t value, uint8_t addr, uint8_t* block); +void mifare_classic_value_to_block(int32_t value, uint8_t addr, uint8_t* block); -bool mf_classic_is_key_found(MfClassicData* data, uint8_t sector_num, MfClassicKey key_type); +bool mifare_classic_is_key_found(MfClassicData* data, uint8_t sector_num, MfClassicKey key_type); -void mf_classic_set_key_found( +void mifare_classic_set_key_found( MfClassicData* data, uint8_t sector_num, MfClassicKey key_type, uint64_t key); -void mf_classic_set_key_not_found(MfClassicData* data, uint8_t sector_num, MfClassicKey key_type); +void mifare_classic_set_key_not_found(MfClassicData* data, uint8_t sector_num, MfClassicKey key_type); -bool mf_classic_is_block_read(MfClassicData* data, uint8_t block_num); +bool mifare_classic_is_block_read(MfClassicData* data, uint8_t block_num); -void mf_classic_set_block_read(MfClassicData* data, uint8_t block_num, MfClassicBlock* block_data); +void mifare_classic_set_block_read(MfClassicData* data, uint8_t block_num, MfClassicBlock* block_data); -bool mf_classic_is_sector_data_read(MfClassicData* data, uint8_t sector_num); +bool mifare_classic_is_sector_data_read(MfClassicData* data, uint8_t sector_num); -void mf_classic_set_sector_data_not_read(MfClassicData* data); +void mifare_classic_set_sector_data_not_read(MfClassicData* data); -bool mf_classic_is_sector_read(MfClassicData* data, uint8_t sector_num); +bool mifare_classic_is_sector_read(MfClassicData* data, uint8_t sector_num); -bool mf_classic_is_card_read(MfClassicData* data); +bool mifare_classic_is_card_read(MfClassicData* data); -void mf_classic_get_read_sectors_and_keys( +void mifare_classic_get_read_sectors_and_keys( MfClassicData* data, uint8_t* sectors_read, uint8_t* keys_found); MfClassicSectorTrailer* - mf_classic_get_sector_trailer_by_sector(MfClassicData* data, uint8_t sector); + mifare_classic_get_sector_trailer_by_sector(MfClassicData* data, uint8_t sector); -void mf_classic_auth_init_context(MfClassicAuthContext* auth_ctx, uint8_t sector); +void mifare_classic_auth_init_context(MfClassicAuthContext* auth_ctx, uint8_t sector); -bool mf_classic_authenticate( +bool mifare_classic_authenticate( FuriHalNfcTxRxContext* tx_rx, uint8_t block_num, uint64_t key, MfClassicKey key_type); -bool mf_classic_authenticate_skip_activate( +bool mifare_classic_authenticate_skip_activate( FuriHalNfcTxRxContext* tx_rx, uint8_t block_num, uint64_t key, @@ -172,60 +172,60 @@ bool mf_classic_authenticate_skip_activate( bool skip_activate, uint32_t cuid); -bool mf_classic_auth_attempt( +bool mifare_classic_auth_attempt( FuriHalNfcTxRxContext* tx_rx, Crypto1* crypto, MfClassicAuthContext* auth_ctx, uint64_t key); -void mf_classic_reader_add_sector( +void mifare_classic_reader_add_sector( MfClassicReader* reader, uint8_t sector, uint64_t key_a, uint64_t key_b); -bool mf_classic_read_block( +bool mifare_classic_read_block( FuriHalNfcTxRxContext* tx_rx, Crypto1* crypto, uint8_t block_num, MfClassicBlock* block); -void mf_classic_read_sector(FuriHalNfcTxRxContext* tx_rx, MfClassicData* data, uint8_t sec_num); +void mifare_classic_read_sector(FuriHalNfcTxRxContext* tx_rx, MfClassicData* data, uint8_t sec_num); -uint8_t mf_classic_read_card( +uint8_t mifare_classic_read_card( FuriHalNfcTxRxContext* tx_rx, MfClassicReader* reader, MfClassicData* data); -uint8_t mf_classic_update_card(FuriHalNfcTxRxContext* tx_rx, MfClassicData* data); +uint8_t mifare_classic_update_card(FuriHalNfcTxRxContext* tx_rx, MfClassicData* data); -bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_rx); +bool mifare_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_rx); -void mf_classic_halt(FuriHalNfcTxRxContext* tx_rx, Crypto1* crypto); +void mifare_classic_halt(FuriHalNfcTxRxContext* tx_rx, Crypto1* crypto); -bool mf_classic_write_block( +bool mifare_classic_write_block( FuriHalNfcTxRxContext* tx_rx, Crypto1* crypto, uint8_t block_num, MfClassicBlock* src_block); -bool mf_classic_auth_write_block( +bool mifare_classic_auth_write_block( FuriHalNfcTxRxContext* tx_rx, MfClassicBlock* src_block, uint8_t block_num, MfClassicKey key_type, uint64_t key); -bool mf_classic_transfer(FuriHalNfcTxRxContext* tx_rx, Crypto1* crypto, uint8_t block_num); +bool mifare_classic_transfer(FuriHalNfcTxRxContext* tx_rx, Crypto1* crypto, uint8_t block_num); -bool mf_classic_value_cmd( +bool mifare_classic_value_cmd( FuriHalNfcTxRxContext* tx_rx, Crypto1* crypto, uint8_t block_num, uint8_t cmd, int32_t d_value); -bool mf_classic_value_cmd_full( +bool mifare_classic_value_cmd_full( FuriHalNfcTxRxContext* tx_rx, MfClassicBlock* src_block, uint8_t block_num, @@ -233,7 +233,7 @@ bool mf_classic_value_cmd_full( uint64_t key, int32_t d_value); -bool mf_classic_write_sector( +bool mifare_classic_write_sector( FuriHalNfcTxRxContext* tx_rx, MfClassicData* dest_data, MfClassicData* src_data, From 80d7e50b72aa21a6716f64bebcf1e06a3c32722f Mon Sep 17 00:00:00 2001 From: gornekich Date: Sun, 14 May 2023 19:27:00 +0400 Subject: [PATCH 080/149] mf classic: add load and save file --- lib/nfc/nfc_dev.c | 187 +++++++++++++++++++++- lib/nfc/nfc_device.c | 2 +- lib/nfc/protocols/mf_classic/mf_classic.c | 28 +++- lib/nfc/protocols/mf_classic/mf_classic.h | 7 +- 4 files changed, 214 insertions(+), 10 deletions(-) diff --git a/lib/nfc/nfc_dev.c b/lib/nfc/nfc_dev.c index ffdc52add0bd..b909b91134e2 100644 --- a/lib/nfc/nfc_dev.c +++ b/lib/nfc/nfc_dev.c @@ -3,6 +3,9 @@ #include #include +#include "protocols/nfc_util.h" +#include + static const char* nfc_file_header = "Flipper NFC device"; static const uint32_t nfc_file_version = 3; static const uint32_t nfc_file_version_with_lsb_atqa = 2; @@ -10,8 +13,8 @@ static const uint32_t nfc_file_version_with_lsb_atqa = 2; // static const char* nfc_keys_file_header = "Flipper NFC keys"; // static const uint32_t nfc_keys_file_version = 1; -// // Protocols format versions -// static const uint32_t nfc_mifare_classic_data_format_version = 2; +// Protocols format versions +static const uint32_t nfc_mifare_classic_data_format_version = 2; static const uint32_t nfc_mifare_ultralight_data_format_version = 1; struct NfcDev { @@ -296,8 +299,7 @@ static bool nfc_dev_mf_classic_verify_handler(FuriString* device_type, NfcDevDat furi_assert(device_type); furi_assert(data); - // TODO set mfc type here - bool verified = furi_string_start_with_str(device_type, "Mifare Classic"); + bool verified = furi_string_equal_str(device_type, "Mifare Classic"); if(verified) { data->protocol = NfcDevProtocolMfClassic; } @@ -305,35 +307,210 @@ static bool nfc_dev_mf_classic_verify_handler(FuriString* device_type, NfcDevDat return verified; } +static void nfc_dev_set_mf_classic_block_str( + FuriString* block_str, + MfClassicData* data, + uint8_t block_num) { + furi_string_reset(block_str); + bool is_sec_trailer = mf_classic_is_sector_trailer(block_num); + if(is_sec_trailer) { + uint8_t sector_num = mf_classic_get_sector_by_block(block_num); + MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(data, sector_num); + // Write key A + for(size_t i = 0; i < sizeof(sec_tr->key_a); i++) { + if(mf_classic_is_key_found(data, sector_num, MfClassicKeyA)) { + furi_string_cat_printf(block_str, "%02X ", sec_tr->key_a[i]); + } else { + furi_string_cat_printf(block_str, "?? "); + } + } + // Write Access bytes + for(size_t i = 0; i < MF_CLASSIC_ACCESS_BYTES_SIZE; i++) { + if(mf_classic_is_block_read(data, block_num)) { + furi_string_cat_printf(block_str, "%02X ", sec_tr->access_bits[i]); + } else { + furi_string_cat_printf(block_str, "?? "); + } + } + // Write key B + for(size_t i = 0; i < sizeof(sec_tr->key_b); i++) { + if(mf_classic_is_key_found(data, sector_num, MfClassicKeyB)) { + furi_string_cat_printf(block_str, "%02X ", sec_tr->key_b[i]); + } else { + furi_string_cat_printf(block_str, "?? "); + } + } + } else { + // Write data block + for(size_t i = 0; i < MF_CLASSIC_BLOCK_SIZE; i++) { + if(mf_classic_is_block_read(data, block_num)) { + furi_string_cat_printf(block_str, "%02X ", data->block[block_num].value[i]); + } else { + furi_string_cat_printf(block_str, "?? "); + } + } + } + furi_string_trim(block_str); +} + static bool nfc_dev_mf_classic_save_handler(FlipperFormat* file, uint32_t version, NfcDevData* data) { furi_assert(file); furi_assert(data); UNUSED(version); + FuriString* temp_str = furi_string_alloc(); + MfClassicData* mfc_data = &data->mf_classic_data; bool saved = false; do { if(!nfc_dev_nfca_save_data(file, &data->nfca_data)) break; + if(!flipper_format_write_comment_cstr(file, "Mifare Classic specific data")) break; + const char* type_name = mf_classic_get_name(mfc_data->type, false); + if(!flipper_format_write_string_cstr(file, "Mifare Classic type", type_name)) break; + if(!flipper_format_write_uint32( + file, "Data format version", &nfc_mifare_classic_data_format_version, 1)) + break; + if(!flipper_format_write_comment_cstr( + file, "Mifare Classic blocks, \'??\' means unknown data")) + break; + + uint16_t blocks_total = mf_classic_get_total_block_num(mfc_data->type); + FuriString* block_str = furi_string_alloc(); + bool block_saved = true; + for(size_t i = 0; i < blocks_total; i++) { + furi_string_printf(temp_str, "Block %d", i); + nfc_dev_set_mf_classic_block_str(block_str, mfc_data, i); + if(!flipper_format_write_string(file, furi_string_get_cstr(temp_str), block_str)) { + block_saved = false; + break; + } + } + furi_string_free(block_str); + if(!block_saved) break; + saved = true; } while(false); return saved; } +static void nfc_device_parse_mifare_classic_block( + FuriString* block_str, + MfClassicData* data, + uint8_t block_num) { + furi_string_trim(block_str); + MfClassicBlock block_tmp = {}; + bool is_sector_trailer = mf_classic_is_sector_trailer(block_num); + uint8_t sector_num = mf_classic_get_sector_by_block(block_num); + uint16_t block_unknown_bytes_mask = 0; + + furi_string_trim(block_str); + for(size_t i = 0; i < MF_CLASSIC_BLOCK_SIZE; i++) { + char hi = furi_string_get_char(block_str, 3 * i); + char low = furi_string_get_char(block_str, 3 * i + 1); + uint8_t byte = 0; + if(hex_char_to_uint8(hi, low, &byte)) { + block_tmp.value[i] = byte; + } else { + FURI_BIT_SET(block_unknown_bytes_mask, i); + } + } + + if(block_unknown_bytes_mask != 0xffff) { + if(is_sector_trailer) { + MfClassicSectorTrailer* sec_tr_tmp = (MfClassicSectorTrailer*)&block_tmp; + // Load Key A + // Key A mask 0b0000000000111111 = 0x003f + if((block_unknown_bytes_mask & 0x003f) == 0) { + uint64_t key = nfc_util_bytes2num(sec_tr_tmp->key_a, sizeof(sec_tr_tmp->key_a)); + mf_classic_set_key_found(data, sector_num, MfClassicKeyA, key); + } + // Load Access Bits + // Access bits mask 0b0000001111000000 = 0x03c0 + if((block_unknown_bytes_mask & 0x03c0) == 0) { + mf_classic_set_block_read(data, block_num, &block_tmp); + } + // Load Key B + // Key B mask 0b1111110000000000 = 0xfc00 + if((block_unknown_bytes_mask & 0xfc00) == 0) { + uint64_t key = nfc_util_bytes2num(sec_tr_tmp->key_b, sizeof(sec_tr_tmp->key_b)); + mf_classic_set_key_found(data, sector_num, MfClassicKeyB, key); + } + } else { + if(block_unknown_bytes_mask == 0) { + mf_classic_set_block_read(data, block_num, &block_tmp); + } + } + } +} + static bool nfc_dev_mf_classic_load_handler(FlipperFormat* file, uint32_t version, NfcDevData* data) { furi_assert(file); furi_assert(data); + MfClassicData* mfc_data = &data->mf_classic_data; + FuriString* temp_str = furi_string_alloc(); bool parsed = false; + do { // Read NFCA data if(!nfc_dev_nfca_load_data(file, version, &data->mf_ul_data.nfca_data)) break; + // Read Mifare Classic type + if(!flipper_format_read_string(file, "Mifare Classic type", temp_str)) break; + bool type_parsed = false; + for(size_t i = 0; i < MfClassicTypeNum; i++) { + const char* type_name = mf_classic_get_name(i, false); + if(furi_string_equal_str(temp_str, type_name)) { + mfc_data->type = i; + type_parsed = true; + } + } + if(!type_parsed) break; + + // Read format version + uint32_t data_format_version = 0; + bool old_format = false; + // Read Mifare Classic format version + if(!flipper_format_read_uint32(file, "Data format version", &data_format_version, 1)) { + // Load unread sectors with zero keys access for backward compatibility + if(!flipper_format_rewind(file)) break; + old_format = true; + } else { + if(data_format_version < nfc_mifare_classic_data_format_version) { + old_format = true; + } + } + + // Read Mifare Classic blocks + bool block_read = true; + FuriString* block_str = furi_string_alloc(); + uint16_t blocks_total = mf_classic_get_total_block_num(mfc_data->type); + for(size_t i = 0; i < blocks_total; i++) { + furi_string_printf(temp_str, "Block %d", i); + if(!flipper_format_read_string(file, furi_string_get_cstr(temp_str), block_str)) { + block_read = false; + break; + } + nfc_device_parse_mifare_classic_block(block_str, mfc_data, i); + } + furi_string_free(block_str); + if(!block_read) break; + + // Set keys and blocks as unknown for backward compatibility + if(old_format) { + mfc_data->key_a_mask = 0ULL; + mfc_data->key_b_mask = 0ULL; + memset(mfc_data->block_read_mask, 0, sizeof(mfc_data->block_read_mask)); + } + parsed = true; } while(false); + furi_string_free(temp_str); + return parsed; } @@ -341,7 +518,7 @@ static bool nfc_dev_mf_desfire_verify_handler(FuriString* device_type, NfcDevDat furi_assert(device_type); furi_assert(data); - bool verified = furi_string_start_with_str(device_type, "Mifare Desfire"); + bool verified = furi_string_equal_str(device_type, "Mifare Desfire"); if(verified) { data->protocol = NfcDevProtocolMfDesfire; } diff --git a/lib/nfc/nfc_device.c b/lib/nfc/nfc_device.c index 6791963142fc..c94e48c9eb3c 100644 --- a/lib/nfc/nfc_device.c +++ b/lib/nfc/nfc_device.c @@ -803,7 +803,7 @@ static void nfc_device_load_mifare_classic_block( } } - if(block_unknown_bytes_mask == 0xffff) { + if(block_unknown_bytes_mask != 0xffff) { // All data is unknown, exit return; } diff --git a/lib/nfc/protocols/mf_classic/mf_classic.c b/lib/nfc/protocols/mf_classic/mf_classic.c index f6878a060549..57274485f5dd 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic.c +++ b/lib/nfc/protocols/mf_classic/mf_classic.c @@ -42,7 +42,19 @@ uint16_t mf_classic_get_total_block_num(MfClassicType type) { return mf_classic_features[type].blocks_total; } -uint8_t mf_classic_get_sector_trailer_block_num_by_sector(uint8_t sector) { +const char* mf_classic_get_name(MfClassicType type, bool full_name) { + const char* ret = NULL; + + if(full_name) { + ret = mf_classic_features[type].full_name; + } else { + ret = mf_classic_features[type].type_name; + } + + return ret; +} + +uint8_t mf_classic_get_sector_trailer_num_by_sector(uint8_t sector) { uint8_t block_num = 0; if(sector < 32) { @@ -68,6 +80,16 @@ uint8_t mf_classic_get_sector_trailer_num_by_block(uint8_t block) { return sec_tr_block_num; } +MfClassicSectorTrailer* + mf_classic_get_sector_trailer_by_sector(MfClassicData* data, uint8_t sector_num) { + furi_assert(data); + + uint8_t sec_tr_block = mf_classic_get_sector_trailer_num_by_sector(sector_num); + MfClassicSectorTrailer* sec_trailer = (MfClassicSectorTrailer*)&data->block[sec_tr_block]; + + return sec_trailer; +} + bool mf_classic_is_sector_trailer(uint8_t block) { return block == mf_classic_get_sector_trailer_num_by_block(block); } @@ -105,8 +127,8 @@ void mf_classic_set_key_found( furi_assert(data); uint8_t key_arr[6] = {}; - uint8_t sec_tr_block = mf_classic_get_sector_trailer_block_num_by_sector(sector_num); - MfClassicSectorTrailer* sec_trailer = (MfClassicSectorTrailer*)&data->block[sec_tr_block]; + MfClassicSectorTrailer* sec_trailer = + mf_classic_get_sector_trailer_by_sector(data, sector_num); nfc_util_num2bytes(key, 6, key_arr); if(key_type == MfClassicKeyA) { memcpy(sec_trailer->key_a, key_arr, sizeof(sec_trailer->key_a)); diff --git a/lib/nfc/protocols/mf_classic/mf_classic.h b/lib/nfc/protocols/mf_classic/mf_classic.h index 87b5416b1955..61c298aa4c9a 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic.h +++ b/lib/nfc/protocols/mf_classic/mf_classic.h @@ -69,10 +69,15 @@ uint8_t mf_classic_get_total_sectors_num(MfClassicType type); uint16_t mf_classic_get_total_block_num(MfClassicType type); -uint8_t mf_classic_get_sector_trailer_block_num_by_sector(uint8_t sector); +const char* mf_classic_get_name(MfClassicType type, bool full_name); + +uint8_t mf_classic_get_sector_trailer_num_by_sector(uint8_t sector); uint8_t mf_classic_get_sector_trailer_num_by_block(uint8_t block); +MfClassicSectorTrailer* + mf_classic_get_sector_trailer_by_sector(MfClassicData* data, uint8_t sector_num); + bool mf_classic_is_sector_trailer(uint8_t block); uint8_t mf_classic_get_sector_by_block(uint8_t block); From 46ce9f6642812bc63892317f89442a835ab43204 Mon Sep 17 00:00:00 2001 From: gornekich Date: Sun, 14 May 2023 21:42:24 +0400 Subject: [PATCH 081/149] nfc test: add mf classic file tests --- applications/debug/unit_tests/nfc/nfc_test.c | 104 ++++++++++++------- lib/nfc/helpers/nfc_data_generator.c | 4 +- lib/nfc/helpers/nfc_data_generator.h | 4 +- 3 files changed, 69 insertions(+), 43 deletions(-) diff --git a/applications/debug/unit_tests/nfc/nfc_test.c b/applications/debug/unit_tests/nfc/nfc_test.c index cf52c6b7c6c1..a8eb6f589a58 100644 --- a/applications/debug/unit_tests/nfc/nfc_test.c +++ b/applications/debug/unit_tests/nfc/nfc_test.c @@ -76,7 +76,7 @@ static void nfca_file_test(uint8_t uid_len) { free(nfc_dev_data_ref); } -static void mf_ultralight_file_test_with_generator(NfcDataGeneratorType type) { +static void nfc_file_test_with_generator(NfcDataGeneratorType type) { NfcDevData* nfc_dev_data_ref = malloc(sizeof(NfcDevData)); mu_assert(nfc_dev_data_ref != NULL, "malloc() failed\r\n"); @@ -95,55 +95,75 @@ MU_TEST(nfca_7b_file_test) { } MU_TEST(mf_ultralight_file_test) { - mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeMfUltralight); + nfc_file_test_with_generator(NfcDataGeneratorTypeMfUltralight); } MU_TEST(mf_ultralight_ev1_11_file_test) { - mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeMfUltralightEV1_11); + nfc_file_test_with_generator(NfcDataGeneratorTypeMfUltralightEV1_11); } MU_TEST(mf_ultralight_ev1_h11_file_test) { - mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeMfUltralightEV1_H11); + nfc_file_test_with_generator(NfcDataGeneratorTypeMfUltralightEV1_H11); } MU_TEST(mf_ultralight_ev1_21_file_test) { - mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeMfUltralightEV1_21); + nfc_file_test_with_generator(NfcDataGeneratorTypeMfUltralightEV1_21); } MU_TEST(mf_ultralight_ev1_h21_file_test) { - mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeMfUltralightEV1_H21); + nfc_file_test_with_generator(NfcDataGeneratorTypeMfUltralightEV1_H21); } MU_TEST(mf_ultralight_ntag_203_file_test) { - mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeNTAG203); + nfc_file_test_with_generator(NfcDataGeneratorTypeNTAG203); } MU_TEST(mf_ultralight_ntag_213_file_test) { - mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeNTAG213); + nfc_file_test_with_generator(NfcDataGeneratorTypeNTAG213); } MU_TEST(mf_ultralight_ntag_215_file_test) { - mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeNTAG215); + nfc_file_test_with_generator(NfcDataGeneratorTypeNTAG215); } MU_TEST(mf_ultralight_ntag_216_file_test) { - mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeNTAG216); + nfc_file_test_with_generator(NfcDataGeneratorTypeNTAG216); } MU_TEST(mf_ultralight_ntag_i2c_1k_file_test) { - mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeNTAGI2C1k); + nfc_file_test_with_generator(NfcDataGeneratorTypeNTAGI2C1k); } MU_TEST(mf_ultralight_ntag_i2c_2k_file_test) { - mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeNTAGI2C2k); + nfc_file_test_with_generator(NfcDataGeneratorTypeNTAGI2C2k); } MU_TEST(mf_ultralight_ntag_i2c_plus_1k_file_test) { - mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeNTAGI2CPlus1k); + nfc_file_test_with_generator(NfcDataGeneratorTypeNTAGI2CPlus1k); } MU_TEST(mf_ultralight_ntag_i2c_plus_2k_file_test) { - mf_ultralight_file_test_with_generator(NfcDataGeneratorTypeNTAGI2CPlus2k); + nfc_file_test_with_generator(NfcDataGeneratorTypeNTAGI2CPlus2k); +} + +MU_TEST(mf_classic_mini_file_test) { + nfc_file_test_with_generator(NfcDataGeneratorTypeMfClassicMini); +} + +MU_TEST(mf_classic_1k_4b_file_test) { + nfc_file_test_with_generator(NfcDataGeneratorTypeMfClassic1k_4b); +} + +MU_TEST(mf_classic_1k_7b_file_test) { + nfc_file_test_with_generator(NfcDataGeneratorTypeMfClassic1k_7b); +} + +MU_TEST(mf_classic_4k_4b_file_test) { + nfc_file_test_with_generator(NfcDataGeneratorTypeMfClassic4k_4b); +} + +MU_TEST(mf_classic_4k_7b_file_test) { + nfc_file_test_with_generator(NfcDataGeneratorTypeMfClassic4k_7b); } MU_TEST(nfca_reader) { @@ -354,31 +374,37 @@ static void mf_ultralight_write() { MU_TEST_SUITE(nfc) { nfc_test_alloc(); - MU_RUN_TEST(nfca_reader); - MU_RUN_TEST(mf_ultralight_11_reader); - MU_RUN_TEST(mf_ultralight_21_reader); - MU_RUN_TEST(ntag_215_reader); - MU_RUN_TEST(ntag_216_reader); - MU_RUN_TEST(ntag_213_locked_reader); - - MU_RUN_TEST(mf_ultralight_write); - - MU_RUN_TEST(nfca_4b_file_test); - MU_RUN_TEST(nfca_7b_file_test); - - MU_RUN_TEST(mf_ultralight_file_test); - MU_RUN_TEST(mf_ultralight_ev1_11_file_test); - MU_RUN_TEST(mf_ultralight_ev1_h11_file_test); - MU_RUN_TEST(mf_ultralight_ev1_21_file_test); - MU_RUN_TEST(mf_ultralight_ev1_h21_file_test); - MU_RUN_TEST(mf_ultralight_ntag_203_file_test); - MU_RUN_TEST(mf_ultralight_ntag_213_file_test); - MU_RUN_TEST(mf_ultralight_ntag_215_file_test); - MU_RUN_TEST(mf_ultralight_ntag_216_file_test); - MU_RUN_TEST(mf_ultralight_ntag_i2c_1k_file_test); - MU_RUN_TEST(mf_ultralight_ntag_i2c_2k_file_test); - MU_RUN_TEST(mf_ultralight_ntag_i2c_plus_1k_file_test); - MU_RUN_TEST(mf_ultralight_ntag_i2c_plus_2k_file_test); + UNUSED(nfca_reader); + UNUSED(mf_ultralight_11_reader); + UNUSED(mf_ultralight_21_reader); + UNUSED(ntag_215_reader); + UNUSED(ntag_216_reader); + UNUSED(ntag_213_locked_reader); + + UNUSED(mf_ultralight_write); + + UNUSED(nfca_4b_file_test); + UNUSED(nfca_7b_file_test); + + UNUSED(mf_ultralight_file_test); + UNUSED(mf_ultralight_ev1_11_file_test); + UNUSED(mf_ultralight_ev1_h11_file_test); + UNUSED(mf_ultralight_ev1_21_file_test); + UNUSED(mf_ultralight_ev1_h21_file_test); + UNUSED(mf_ultralight_ntag_203_file_test); + UNUSED(mf_ultralight_ntag_213_file_test); + UNUSED(mf_ultralight_ntag_215_file_test); + UNUSED(mf_ultralight_ntag_216_file_test); + UNUSED(mf_ultralight_ntag_i2c_1k_file_test); + UNUSED(mf_ultralight_ntag_i2c_2k_file_test); + UNUSED(mf_ultralight_ntag_i2c_plus_1k_file_test); + UNUSED(mf_ultralight_ntag_i2c_plus_2k_file_test); + + MU_RUN_TEST(mf_classic_mini_file_test); + MU_RUN_TEST(mf_classic_1k_4b_file_test); + MU_RUN_TEST(mf_classic_1k_7b_file_test); + MU_RUN_TEST(mf_classic_4k_4b_file_test); + MU_RUN_TEST(mf_classic_4k_7b_file_test); nfc_test_free(); } diff --git a/lib/nfc/helpers/nfc_data_generator.c b/lib/nfc/helpers/nfc_data_generator.c index bf5ee599b310..b375e5e0eb61 100644 --- a/lib/nfc/helpers/nfc_data_generator.c +++ b/lib/nfc/helpers/nfc_data_generator.c @@ -503,12 +503,12 @@ static const NfcDataGenerator nfc_data_generator[NfcDataGeneratorTypeNum] = { .name = "Mifare Classic 1k 7byte UID", .handler = nfc_generate_mf_classic_1k_7b_uid, }, - [NfcDataGeneratorTypeMfClassic2k_4b] = + [NfcDataGeneratorTypeMfClassic4k_4b] = { .name = "Mifare Classic 4k 4byte UID", .handler = nfc_generate_mf_classic_4k_4b_uid, }, - [NfcDataGeneratorTypeMfClassic2k_7b] = + [NfcDataGeneratorTypeMfClassic4k_7b] = { .name = "Mifare Classic 4k 7byte UID", .handler = nfc_generate_mf_classic_4k_7b_uid, diff --git a/lib/nfc/helpers/nfc_data_generator.h b/lib/nfc/helpers/nfc_data_generator.h index ae405e1513a4..81e179b7cfba 100644 --- a/lib/nfc/helpers/nfc_data_generator.h +++ b/lib/nfc/helpers/nfc_data_generator.h @@ -24,8 +24,8 @@ typedef enum { NfcDataGeneratorTypeMfClassicMini, NfcDataGeneratorTypeMfClassic1k_4b, NfcDataGeneratorTypeMfClassic1k_7b, - NfcDataGeneratorTypeMfClassic2k_4b, - NfcDataGeneratorTypeMfClassic2k_7b, + NfcDataGeneratorTypeMfClassic4k_4b, + NfcDataGeneratorTypeMfClassic4k_7b, NfcDataGeneratorTypeNum, From 60950d9b113ecb8c3a8eaadcfef2ed3b632e3db5 Mon Sep 17 00:00:00 2001 From: gornekich Date: Sun, 14 May 2023 22:08:05 +0400 Subject: [PATCH 082/149] nfc: fix errors --- applications/debug/unit_tests/nfc/nfc_test.c | 51 ++++++++++---------- lib/nfc/helpers/nfc_data_generator.c | 4 +- lib/nfc/nfc_dev.c | 4 ++ 3 files changed, 31 insertions(+), 28 deletions(-) diff --git a/applications/debug/unit_tests/nfc/nfc_test.c b/applications/debug/unit_tests/nfc/nfc_test.c index a8eb6f589a58..2e3bdedaa5b9 100644 --- a/applications/debug/unit_tests/nfc/nfc_test.c +++ b/applications/debug/unit_tests/nfc/nfc_test.c @@ -78,7 +78,6 @@ static void nfca_file_test(uint8_t uid_len) { static void nfc_file_test_with_generator(NfcDataGeneratorType type) { NfcDevData* nfc_dev_data_ref = malloc(sizeof(NfcDevData)); - mu_assert(nfc_dev_data_ref != NULL, "malloc() failed\r\n"); nfc_data_generator_fill_data(type, nfc_dev_data_ref); nfc_test_save_and_load(nfc_dev_data_ref); @@ -374,31 +373,31 @@ static void mf_ultralight_write() { MU_TEST_SUITE(nfc) { nfc_test_alloc(); - UNUSED(nfca_reader); - UNUSED(mf_ultralight_11_reader); - UNUSED(mf_ultralight_21_reader); - UNUSED(ntag_215_reader); - UNUSED(ntag_216_reader); - UNUSED(ntag_213_locked_reader); - - UNUSED(mf_ultralight_write); - - UNUSED(nfca_4b_file_test); - UNUSED(nfca_7b_file_test); - - UNUSED(mf_ultralight_file_test); - UNUSED(mf_ultralight_ev1_11_file_test); - UNUSED(mf_ultralight_ev1_h11_file_test); - UNUSED(mf_ultralight_ev1_21_file_test); - UNUSED(mf_ultralight_ev1_h21_file_test); - UNUSED(mf_ultralight_ntag_203_file_test); - UNUSED(mf_ultralight_ntag_213_file_test); - UNUSED(mf_ultralight_ntag_215_file_test); - UNUSED(mf_ultralight_ntag_216_file_test); - UNUSED(mf_ultralight_ntag_i2c_1k_file_test); - UNUSED(mf_ultralight_ntag_i2c_2k_file_test); - UNUSED(mf_ultralight_ntag_i2c_plus_1k_file_test); - UNUSED(mf_ultralight_ntag_i2c_plus_2k_file_test); + MU_RUN_TEST(nfca_reader); + MU_RUN_TEST(mf_ultralight_11_reader); + MU_RUN_TEST(mf_ultralight_21_reader); + MU_RUN_TEST(ntag_215_reader); + MU_RUN_TEST(ntag_216_reader); + MU_RUN_TEST(ntag_213_locked_reader); + + MU_RUN_TEST(mf_ultralight_write); + + MU_RUN_TEST(nfca_4b_file_test); + MU_RUN_TEST(nfca_7b_file_test); + + MU_RUN_TEST(mf_ultralight_file_test); + MU_RUN_TEST(mf_ultralight_ev1_11_file_test); + MU_RUN_TEST(mf_ultralight_ev1_h11_file_test); + MU_RUN_TEST(mf_ultralight_ev1_21_file_test); + MU_RUN_TEST(mf_ultralight_ev1_h21_file_test); + MU_RUN_TEST(mf_ultralight_ntag_203_file_test); + MU_RUN_TEST(mf_ultralight_ntag_213_file_test); + MU_RUN_TEST(mf_ultralight_ntag_215_file_test); + MU_RUN_TEST(mf_ultralight_ntag_216_file_test); + MU_RUN_TEST(mf_ultralight_ntag_i2c_1k_file_test); + MU_RUN_TEST(mf_ultralight_ntag_i2c_2k_file_test); + MU_RUN_TEST(mf_ultralight_ntag_i2c_plus_1k_file_test); + MU_RUN_TEST(mf_ultralight_ntag_i2c_plus_2k_file_test); MU_RUN_TEST(mf_classic_mini_file_test); MU_RUN_TEST(mf_classic_1k_4b_file_test); diff --git a/lib/nfc/helpers/nfc_data_generator.c b/lib/nfc/helpers/nfc_data_generator.c index b375e5e0eb61..0606f7c4a030 100644 --- a/lib/nfc/helpers/nfc_data_generator.c +++ b/lib/nfc/helpers/nfc_data_generator.c @@ -368,7 +368,7 @@ static void nfc_generate_mf_classic(NfcDevData* data, uint8_t uid_len, MfClassic data->nfca_data.sak = 0x18; } else if(type == MfClassicType1k) { // Set every block to 0xFF - for(uint16_t i = 1; i < block_num * 4; i += 1) { + for(uint16_t i = 1; i < block_num; i += 1) { if(mf_classic_is_sector_trailer(i)) { nfc_generate_mf_classic_sector_trailer(mfc_data, i); } else { @@ -380,7 +380,7 @@ static void nfc_generate_mf_classic(NfcDevData* data, uint8_t uid_len, MfClassic data->nfca_data.sak = 0x08; } else if(type == MfClassicTypeMini) { // Set every block to 0xFF - for(uint16_t i = 1; i < block_num * 4; i += 1) { + for(uint16_t i = 1; i < block_num; i += 1) { if(mf_classic_is_sector_trailer(i)) { nfc_generate_mf_classic_sector_trailer(mfc_data, i); } else { diff --git a/lib/nfc/nfc_dev.c b/lib/nfc/nfc_dev.c index b909b91134e2..9e6de71d29e8 100644 --- a/lib/nfc/nfc_dev.c +++ b/lib/nfc/nfc_dev.c @@ -364,7 +364,9 @@ static bool bool saved = false; do { + if(!flipper_format_write_string_cstr(file, "Device type", "Mifare Classic")) break; if(!nfc_dev_nfca_save_data(file, &data->nfca_data)) break; + if(!flipper_format_write_string_cstr(file, "Device type", "")) break; if(!flipper_format_write_comment_cstr(file, "Mifare Classic specific data")) break; const char* type_name = mf_classic_get_name(mfc_data->type, false); if(!flipper_format_write_string_cstr(file, "Mifare Classic type", type_name)) break; @@ -392,6 +394,8 @@ static bool saved = true; } while(false); + furi_string_free(temp_str); + return saved; } From e40bf54d49a9a4878240e120c35c2d61b25dca8c Mon Sep 17 00:00:00 2001 From: gornekich Date: Mon, 15 May 2023 16:14:52 +0400 Subject: [PATCH 083/149] nfc: rename crypto to old_crypto for symbol reslution --- applications/external/mfkey32/mfkey32.c | 8 +- firmware/targets/f7/api_symbols.csv | 18 ++-- lib/nfc/helpers/nfc_data_generator.c | 26 +++--- lib/nfc/nfc_dev.c | 22 ++--- lib/nfc/protocols/crypto1.c | 40 ++++----- lib/nfc/protocols/crypto1.h | 18 ++-- lib/nfc/protocols/mf_classic/crypto.h | 11 +++ lib/nfc/protocols/mf_classic/mf_classic.c | 29 +++--- lib/nfc/protocols/mf_classic/mf_classic.h | 37 +++++--- .../protocols/mf_classic/mf_classic_poller.c | 86 ++++++++++++++++++ .../protocols/mf_classic/mf_classic_poller.h | 72 +++++++++++++++ .../mf_classic/mf_classic_poller_i.c | 0 .../mf_classic/mf_classic_poller_i.h | 42 +++++++++ .../mf_classic/mf_classic_poller_sync_api.c | 27 ++++++ .../mf_ultralight/mf_ultralight_poller.h | 2 +- lib/nfc/protocols/mifare_classic.c | 88 +++++++++---------- 16 files changed, 389 insertions(+), 137 deletions(-) create mode 100644 lib/nfc/protocols/mf_classic/crypto.h create mode 100644 lib/nfc/protocols/mf_classic/mf_classic_poller_i.c create mode 100644 lib/nfc/protocols/mf_classic/mf_classic_poller_i.h create mode 100644 lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.c diff --git a/applications/external/mfkey32/mfkey32.c b/applications/external/mfkey32/mfkey32.c index d4b2d3e4ab00..24bd0ff86d7f 100644 --- a/applications/external/mfkey32/mfkey32.c +++ b/applications/external/mfkey32/mfkey32.c @@ -161,7 +161,7 @@ static const uint8_t lookup2[256] = { 2, 6, 6, 6, 6, 2, 2, 6, 6, 2, 6, 2, 2, 2, 6, 2, 2, 6, 6, 6, 6, 2, 2, 6, 6, 2, 6, 2, 2, 2, 6, 2, 2, 6, 6, 6, 6, 2, 2, 6, 6, 2, 6, 2, 2, 2, 6, 2, 2, 6, 6, 6, 6}; -uint32_t prng_successor(uint32_t x, uint32_t n) { +uint32_t old_prng_successor(uint32_t x, uint32_t n) { SWAPENDIAN(x); while(n--) x = x >> 1 | (x >> 16 ^ x >> 18 ^ x >> 19 ^ x >> 21) << 31; return SWAPENDIAN(x); @@ -945,7 +945,7 @@ MfClassicNonceArray* napi_mf_classic_nonce_array_alloc( next_line_cstr = endptr; } (program_state->total)++; - uint32_t p64b = prng_successor(res.nt1, 64); + uint32_t p64b = old_prng_successor(res.nt1, 64); if((system_dict_exists && napi_key_already_found_for_nonce( system_dict, res.uid ^ res.nt1, res.nr1_enc, p64b, res.ar1_enc)) || @@ -1051,8 +1051,8 @@ void mfkey32(ProgramState* program_state) { // TODO: Work backwards on this array and free memory for(i = 0; i < nonce_arr->total_nonces; i++) { MfClassicNonce next_nonce = nonce_arr->remaining_nonce_array[i]; - uint32_t p64 = prng_successor(next_nonce.nt0, 64); - uint32_t p64b = prng_successor(next_nonce.nt1, 64); + uint32_t p64 = old_prng_successor(next_nonce.nt0, 64); + uint32_t p64b = old_prng_successor(next_nonce.nt1, 64); if(key_already_found_for_nonce( keyarray, keyarray_size, diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 6376f4037473..7e8a6d64c1ed 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -706,14 +706,14 @@ Function,-,coshl,long double,long double Function,-,cosl,long double,long double Function,+,crc32_calc_buffer,uint32_t,"uint32_t, const void*, size_t" Function,+,crc32_calc_file,uint32_t,"File*, const FileCrcProgressCb, void*" -Function,-,crypto1_bit,uint8_t,"Crypto1*, uint8_t, int" -Function,-,crypto1_byte,uint8_t,"Crypto1*, uint8_t, int" -Function,-,crypto1_decrypt,void,"Crypto1*, uint8_t*, uint16_t, uint8_t*" -Function,-,crypto1_encrypt,void,"Crypto1*, uint8_t*, uint8_t*, uint16_t, uint8_t*, uint8_t*" -Function,-,crypto1_filter,uint32_t,uint32_t -Function,-,crypto1_init,void,"Crypto1*, uint64_t" -Function,-,crypto1_reset,void,Crypto1* -Function,-,crypto1_word,uint32_t,"Crypto1*, uint32_t, int" +Function,-,old_crypto1_bit,uint8_t,"Crypto1*, uint8_t, int" +Function,-,old_crypto1_byte,uint8_t,"Crypto1*, uint8_t, int" +Function,-,old_crypto1_decrypt,void,"Crypto1*, uint8_t*, uint16_t, uint8_t*" +Function,-,old_crypto1_encrypt,void,"Crypto1*, uint8_t*, uint8_t*, uint16_t, uint8_t*, uint8_t*" +Function,-,old_crypto1_filter,uint32_t,uint32_t +Function,-,old_crypto1_init,void,"Crypto1*, uint64_t" +Function,-,old_crypto1_reset,void,Crypto1* +Function,-,old_crypto1_word,uint32_t,"Crypto1*, uint32_t, int" Function,-,ctermid,char*,char* Function,-,ctime,char*,const time_t* Function,-,ctime_r,char*,"const time_t*, char*" @@ -2219,7 +2219,7 @@ Function,+,powf,float,"float, float" Function,-,powl,long double,"long double, long double" Function,+,pretty_format_bytes_hex_canonical,void,"FuriString*, size_t, const char*, const uint8_t*, size_t" Function,-,printf,int,"const char*, ..." -Function,-,prng_successor,uint32_t,"uint32_t, uint32_t" +Function,-,old_prng_successor,uint32_t,"uint32_t, uint32_t" Function,+,property_value_out,void,"PropertyValueContext*, const char*, unsigned int, ..." Function,+,protocol_dict_alloc,ProtocolDict*,"const ProtocolBase**, size_t" Function,+,protocol_dict_decoders_feed,ProtocolId,"ProtocolDict*, _Bool, uint32_t" diff --git a/lib/nfc/helpers/nfc_data_generator.c b/lib/nfc/helpers/nfc_data_generator.c index 0606f7c4a030..3657fd2f56ae 100644 --- a/lib/nfc/helpers/nfc_data_generator.c +++ b/lib/nfc/helpers/nfc_data_generator.c @@ -295,17 +295,17 @@ static void static void nfc_generate_mf_classic_sector_trailer(MfClassicData* data, uint8_t block) { // All keys are set to FFFF FFFF FFFFh at chip delivery and the bytes 6, 7 and 8 are set to FF0780h. - MfClassicSectorTrailer* sec_tr = (MfClassicSectorTrailer*)data->block[block].value; - sec_tr->access_bits[0] = 0xFF; - sec_tr->access_bits[1] = 0x07; - sec_tr->access_bits[2] = 0x80; - sec_tr->access_bits[3] = 0x69; // Nice + MfClassicSectorTrailer* sec_tr = (MfClassicSectorTrailer*)data->block[block].data; + sec_tr->access_bits.data[0] = 0xFF; + sec_tr->access_bits.data[1] = 0x07; + sec_tr->access_bits.data[2] = 0x80; + sec_tr->access_bits.data[3] = 0x69; // Nice mf_classic_set_block_read(data, block, &data->block[block]); mf_classic_set_key_found( - data, mf_classic_get_sector_by_block(block), MfClassicKeyA, 0xFFFFFFFFFFFF); + data, mf_classic_get_sector_by_block(block), MfClassicKeyTypeA, 0xFFFFFFFFFFFF); mf_classic_set_key_found( - data, mf_classic_get_sector_by_block(block), MfClassicKeyB, 0xFFFFFFFFFFFF); + data, mf_classic_get_sector_by_block(block), MfClassicKeyTypeB, 0xFFFFFFFFFFFF); } static void nfc_generate_mf_classic_block_0( @@ -342,13 +342,13 @@ static void nfc_generate_mf_classic(NfcDevData* data, uint8_t uid_len, MfClassic nfc_generate_common_start(data); data->protocol = NfcDevProtocolMfClassic; MfClassicData* mfc_data = &data->mf_classic_data; - nfc_generate_mf_classic_uid(mfc_data->block[0].value, uid_len); + nfc_generate_mf_classic_uid(mfc_data->block[0].data, uid_len); nfc_generate_mf_classic_common(mfc_data, uid_len, type); // Set the UID mfc_data->nfca_data.uid[0] = NXP_MANUFACTURER_ID; for(int i = 1; i < uid_len; i++) { - mfc_data->nfca_data.uid[i] = mfc_data->block[0].value[i]; + mfc_data->nfca_data.uid[i] = mfc_data->block[0].data[i]; } mf_classic_set_block_read(mfc_data, 0, &mfc_data->block[0]); @@ -360,7 +360,7 @@ static void nfc_generate_mf_classic(NfcDevData* data, uint8_t uid_len, MfClassic if(mf_classic_is_sector_trailer(i)) { nfc_generate_mf_classic_sector_trailer(mfc_data, i); } else { - memset(&mfc_data->block[i].value, 0xFF, 16); + memset(&mfc_data->block[i].data, 0xFF, 16); } mf_classic_set_block_read(mfc_data, i, &mfc_data->block[i]); } @@ -372,7 +372,7 @@ static void nfc_generate_mf_classic(NfcDevData* data, uint8_t uid_len, MfClassic if(mf_classic_is_sector_trailer(i)) { nfc_generate_mf_classic_sector_trailer(mfc_data, i); } else { - memset(&mfc_data->block[i].value, 0xFF, 16); + memset(&mfc_data->block[i].data, 0xFF, 16); } mf_classic_set_block_read(mfc_data, i, &mfc_data->block[i]); } @@ -384,7 +384,7 @@ static void nfc_generate_mf_classic(NfcDevData* data, uint8_t uid_len, MfClassic if(mf_classic_is_sector_trailer(i)) { nfc_generate_mf_classic_sector_trailer(mfc_data, i); } else { - memset(&mfc_data->block[i].value, 0xFF, 16); + memset(&mfc_data->block[i].data, 0xFF, 16); } mf_classic_set_block_read(mfc_data, i, &mfc_data->block[i]); } @@ -393,7 +393,7 @@ static void nfc_generate_mf_classic(NfcDevData* data, uint8_t uid_len, MfClassic } nfc_generate_mf_classic_block_0( - data->mf_classic_data.block[0].value, + data->mf_classic_data.block[0].data, uid_len, data->nfca_data.sak, data->nfca_data.atqa[0], diff --git a/lib/nfc/nfc_dev.c b/lib/nfc/nfc_dev.c index 9e6de71d29e8..bed58250201e 100644 --- a/lib/nfc/nfc_dev.c +++ b/lib/nfc/nfc_dev.c @@ -318,8 +318,8 @@ static void nfc_dev_set_mf_classic_block_str( MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(data, sector_num); // Write key A for(size_t i = 0; i < sizeof(sec_tr->key_a); i++) { - if(mf_classic_is_key_found(data, sector_num, MfClassicKeyA)) { - furi_string_cat_printf(block_str, "%02X ", sec_tr->key_a[i]); + if(mf_classic_is_key_found(data, sector_num, MfClassicKeyTypeA)) { + furi_string_cat_printf(block_str, "%02X ", sec_tr->key_a.data[i]); } else { furi_string_cat_printf(block_str, "?? "); } @@ -327,15 +327,15 @@ static void nfc_dev_set_mf_classic_block_str( // Write Access bytes for(size_t i = 0; i < MF_CLASSIC_ACCESS_BYTES_SIZE; i++) { if(mf_classic_is_block_read(data, block_num)) { - furi_string_cat_printf(block_str, "%02X ", sec_tr->access_bits[i]); + furi_string_cat_printf(block_str, "%02X ", sec_tr->access_bits.data[i]); } else { furi_string_cat_printf(block_str, "?? "); } } // Write key B for(size_t i = 0; i < sizeof(sec_tr->key_b); i++) { - if(mf_classic_is_key_found(data, sector_num, MfClassicKeyB)) { - furi_string_cat_printf(block_str, "%02X ", sec_tr->key_b[i]); + if(mf_classic_is_key_found(data, sector_num, MfClassicKeyTypeB)) { + furi_string_cat_printf(block_str, "%02X ", sec_tr->key_b.data[i]); } else { furi_string_cat_printf(block_str, "?? "); } @@ -344,7 +344,7 @@ static void nfc_dev_set_mf_classic_block_str( // Write data block for(size_t i = 0; i < MF_CLASSIC_BLOCK_SIZE; i++) { if(mf_classic_is_block_read(data, block_num)) { - furi_string_cat_printf(block_str, "%02X ", data->block[block_num].value[i]); + furi_string_cat_printf(block_str, "%02X ", data->block[block_num].data[i]); } else { furi_string_cat_printf(block_str, "?? "); } @@ -415,7 +415,7 @@ static void nfc_device_parse_mifare_classic_block( char low = furi_string_get_char(block_str, 3 * i + 1); uint8_t byte = 0; if(hex_char_to_uint8(hi, low, &byte)) { - block_tmp.value[i] = byte; + block_tmp.data[i] = byte; } else { FURI_BIT_SET(block_unknown_bytes_mask, i); } @@ -427,8 +427,8 @@ static void nfc_device_parse_mifare_classic_block( // Load Key A // Key A mask 0b0000000000111111 = 0x003f if((block_unknown_bytes_mask & 0x003f) == 0) { - uint64_t key = nfc_util_bytes2num(sec_tr_tmp->key_a, sizeof(sec_tr_tmp->key_a)); - mf_classic_set_key_found(data, sector_num, MfClassicKeyA, key); + uint64_t key = nfc_util_bytes2num(sec_tr_tmp->key_a.data, sizeof(MfClassicKey)); + mf_classic_set_key_found(data, sector_num, MfClassicKeyTypeA, key); } // Load Access Bits // Access bits mask 0b0000001111000000 = 0x03c0 @@ -438,8 +438,8 @@ static void nfc_device_parse_mifare_classic_block( // Load Key B // Key B mask 0b1111110000000000 = 0xfc00 if((block_unknown_bytes_mask & 0xfc00) == 0) { - uint64_t key = nfc_util_bytes2num(sec_tr_tmp->key_b, sizeof(sec_tr_tmp->key_b)); - mf_classic_set_key_found(data, sector_num, MfClassicKeyB, key); + uint64_t key = nfc_util_bytes2num(sec_tr_tmp->key_b.data, sizeof(MfClassicKey)); + mf_classic_set_key_found(data, sector_num, MfClassicKeyTypeB, key); } } else { if(block_unknown_bytes_mask == 0) { diff --git a/lib/nfc/protocols/crypto1.c b/lib/nfc/protocols/crypto1.c index f59651cf45f6..15c3724533c4 100644 --- a/lib/nfc/protocols/crypto1.c +++ b/lib/nfc/protocols/crypto1.c @@ -11,13 +11,13 @@ #define BEBIT(x, n) FURI_BIT(x, (n) ^ 24) -void crypto1_reset(Crypto1* crypto1) { +void old_crypto1_reset(Crypto1* crypto1) { furi_assert(crypto1); crypto1->even = 0; crypto1->odd = 0; } -void crypto1_init(Crypto1* crypto1, uint64_t key) { +void old_crypto1_init(Crypto1* crypto1, uint64_t key) { furi_assert(crypto1); crypto1->even = 0; crypto1->odd = 0; @@ -27,7 +27,7 @@ void crypto1_init(Crypto1* crypto1, uint64_t key) { } } -uint32_t crypto1_filter(uint32_t in) { +uint32_t old_crypto1_filter(uint32_t in) { uint32_t out = 0; out = 0xf22c0 >> (in & 0xf) & 16; out |= 0x6c9c0 >> (in >> 4 & 0xf) & 8; @@ -37,9 +37,9 @@ uint32_t crypto1_filter(uint32_t in) { return FURI_BIT(0xEC57E80A, out); } -uint8_t crypto1_bit(Crypto1* crypto1, uint8_t in, int is_encrypted) { +uint8_t old_crypto1_bit(Crypto1* crypto1, uint8_t in, int is_encrypted) { furi_assert(crypto1); - uint8_t out = crypto1_filter(crypto1->odd); + uint8_t out = old_crypto1_filter(crypto1->odd); uint32_t feed = out & (!!is_encrypted); feed ^= !!in; feed ^= LF_POLY_ODD & crypto1->odd; @@ -50,32 +50,32 @@ uint8_t crypto1_bit(Crypto1* crypto1, uint8_t in, int is_encrypted) { return out; } -uint8_t crypto1_byte(Crypto1* crypto1, uint8_t in, int is_encrypted) { +uint8_t old_crypto1_byte(Crypto1* crypto1, uint8_t in, int is_encrypted) { furi_assert(crypto1); uint8_t out = 0; for(uint8_t i = 0; i < 8; i++) { - out |= crypto1_bit(crypto1, FURI_BIT(in, i), is_encrypted) << i; + out |= old_crypto1_bit(crypto1, FURI_BIT(in, i), is_encrypted) << i; } return out; } -uint32_t crypto1_word(Crypto1* crypto1, uint32_t in, int is_encrypted) { +uint32_t old_crypto1_word(Crypto1* crypto1, uint32_t in, int is_encrypted) { furi_assert(crypto1); uint32_t out = 0; for(uint8_t i = 0; i < 32; i++) { - out |= crypto1_bit(crypto1, BEBIT(in, i), is_encrypted) << (24 ^ i); + out |= old_crypto1_bit(crypto1, BEBIT(in, i), is_encrypted) << (24 ^ i); } return out; } -uint32_t prng_successor(uint32_t x, uint32_t n) { +uint32_t old_prng_successor(uint32_t x, uint32_t n) { SWAPENDIAN(x); while(n--) x = x >> 1 | (x >> 16 ^ x >> 18 ^ x >> 19 ^ x >> 21) << 31; return SWAPENDIAN(x); } -void crypto1_decrypt( +void old_crypto1_decrypt( Crypto1* crypto, uint8_t* encrypted_data, uint16_t encrypted_data_bits, @@ -86,19 +86,19 @@ void crypto1_decrypt( if(encrypted_data_bits < 8) { uint8_t decrypted_byte = 0; - decrypted_byte |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(encrypted_data[0], 0)) << 0; - decrypted_byte |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(encrypted_data[0], 1)) << 1; - decrypted_byte |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(encrypted_data[0], 2)) << 2; - decrypted_byte |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(encrypted_data[0], 3)) << 3; + decrypted_byte |= (old_crypto1_bit(crypto, 0, 0) ^ FURI_BIT(encrypted_data[0], 0)) << 0; + decrypted_byte |= (old_crypto1_bit(crypto, 0, 0) ^ FURI_BIT(encrypted_data[0], 1)) << 1; + decrypted_byte |= (old_crypto1_bit(crypto, 0, 0) ^ FURI_BIT(encrypted_data[0], 2)) << 2; + decrypted_byte |= (old_crypto1_bit(crypto, 0, 0) ^ FURI_BIT(encrypted_data[0], 3)) << 3; decrypted_data[0] = decrypted_byte; } else { for(size_t i = 0; i < encrypted_data_bits / 8; i++) { - decrypted_data[i] = crypto1_byte(crypto, 0, 0) ^ encrypted_data[i]; + decrypted_data[i] = old_crypto1_byte(crypto, 0, 0) ^ encrypted_data[i]; } } } -void crypto1_encrypt( +void old_crypto1_encrypt( Crypto1* crypto, uint8_t* keystream, uint8_t* plain_data, @@ -113,15 +113,15 @@ void crypto1_encrypt( if(plain_data_bits < 8) { encrypted_data[0] = 0; for(size_t i = 0; i < plain_data_bits; i++) { - encrypted_data[0] |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(plain_data[0], i)) << i; + encrypted_data[0] |= (old_crypto1_bit(crypto, 0, 0) ^ FURI_BIT(plain_data[0], i)) << i; } } else { memset(encrypted_parity, 0, plain_data_bits / 8 + 1); for(uint8_t i = 0; i < plain_data_bits / 8; i++) { - encrypted_data[i] = crypto1_byte(crypto, keystream ? keystream[i] : 0, 0) ^ + encrypted_data[i] = old_crypto1_byte(crypto, keystream ? keystream[i] : 0, 0) ^ plain_data[i]; encrypted_parity[i / 8] |= - (((crypto1_filter(crypto->odd) ^ nfc_util_odd_parity8(plain_data[i])) & 0x01) + (((old_crypto1_filter(crypto->odd) ^ nfc_util_odd_parity8(plain_data[i])) & 0x01) << (7 - (i & 0x0007))); } } diff --git a/lib/nfc/protocols/crypto1.h b/lib/nfc/protocols/crypto1.h index 450d1534e320..e152f9b38099 100644 --- a/lib/nfc/protocols/crypto1.h +++ b/lib/nfc/protocols/crypto1.h @@ -8,27 +8,27 @@ typedef struct { uint32_t even; } Crypto1; -void crypto1_reset(Crypto1* crypto1); +void old_crypto1_reset(Crypto1* crypto1); -void crypto1_init(Crypto1* crypto1, uint64_t key); +void old_crypto1_init(Crypto1* crypto1, uint64_t key); -uint8_t crypto1_bit(Crypto1* crypto1, uint8_t in, int is_encrypted); +uint8_t old_crypto1_bit(Crypto1* crypto1, uint8_t in, int is_encrypted); -uint8_t crypto1_byte(Crypto1* crypto1, uint8_t in, int is_encrypted); +uint8_t old_crypto1_byte(Crypto1* crypto1, uint8_t in, int is_encrypted); -uint32_t crypto1_word(Crypto1* crypto1, uint32_t in, int is_encrypted); +uint32_t old_crypto1_word(Crypto1* crypto1, uint32_t in, int is_encrypted); -uint32_t crypto1_filter(uint32_t in); +uint32_t old_crypto1_filter(uint32_t in); -uint32_t prng_successor(uint32_t x, uint32_t n); +uint32_t old_prng_successor(uint32_t x, uint32_t n); -void crypto1_decrypt( +void old_crypto1_decrypt( Crypto1* crypto, uint8_t* encrypted_data, uint16_t encrypted_data_bits, uint8_t* decrypted_data); -void crypto1_encrypt( +void old_crypto1_encrypt( Crypto1* crypto, uint8_t* keystream, uint8_t* plain_data, diff --git a/lib/nfc/protocols/mf_classic/crypto.h b/lib/nfc/protocols/mf_classic/crypto.h new file mode 100644 index 000000000000..b9363460d11b --- /dev/null +++ b/lib/nfc/protocols/mf_classic/crypto.h @@ -0,0 +1,11 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + + + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/mf_classic/mf_classic.c b/lib/nfc/protocols/mf_classic/mf_classic.c index 57274485f5dd..cec14694932e 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic.c +++ b/lib/nfc/protocols/mf_classic/mf_classic.c @@ -106,13 +106,13 @@ uint8_t mf_classic_get_sector_by_block(uint8_t block) { return sector; } -bool mf_classic_is_key_found(MfClassicData* data, uint8_t sector_num, MfClassicKey key_type) { +bool mf_classic_is_key_found(MfClassicData* data, uint8_t sector_num, MfClassicKeyType key_type) { furi_assert(data); bool key_found = false; - if(key_type == MfClassicKeyA) { + if(key_type == MfClassicKeyTypeA) { key_found = (FURI_BIT(data->key_a_mask, sector_num) == 1); - } else if(key_type == MfClassicKeyB) { + } else if(key_type == MfClassicKeyTypeB) { key_found = (FURI_BIT(data->key_b_mask, sector_num) == 1); } @@ -122,7 +122,7 @@ bool mf_classic_is_key_found(MfClassicData* data, uint8_t sector_num, MfClassicK void mf_classic_set_key_found( MfClassicData* data, uint8_t sector_num, - MfClassicKey key_type, + MfClassicKeyType key_type, uint64_t key) { furi_assert(data); @@ -130,21 +130,24 @@ void mf_classic_set_key_found( MfClassicSectorTrailer* sec_trailer = mf_classic_get_sector_trailer_by_sector(data, sector_num); nfc_util_num2bytes(key, 6, key_arr); - if(key_type == MfClassicKeyA) { - memcpy(sec_trailer->key_a, key_arr, sizeof(sec_trailer->key_a)); + if(key_type == MfClassicKeyTypeA) { + memcpy(sec_trailer->key_a.data, key_arr, sizeof(MfClassicKey)); FURI_BIT_SET(data->key_a_mask, sector_num); - } else if(key_type == MfClassicKeyB) { - memcpy(sec_trailer->key_b, key_arr, sizeof(sec_trailer->key_b)); + } else if(key_type == MfClassicKeyTypeB) { + memcpy(sec_trailer->key_b.data, key_arr, sizeof(MfClassicKey)); FURI_BIT_SET(data->key_b_mask, sector_num); } } -void mf_classic_set_key_not_found(MfClassicData* data, uint8_t sector_num, MfClassicKey key_type) { +void mf_classic_set_key_not_found( + MfClassicData* data, + uint8_t sector_num, + MfClassicKeyType key_type) { furi_assert(data); - if(key_type == MfClassicKeyA) { + if(key_type == MfClassicKeyTypeA) { FURI_BIT_CLEAR(data->key_a_mask, sector_num); - } else if(key_type == MfClassicKeyB) { + } else if(key_type == MfClassicKeyTypeB) { FURI_BIT_CLEAR(data->key_b_mask, sector_num); } } @@ -159,9 +162,9 @@ void mf_classic_set_block_read(MfClassicData* data, uint8_t block_num, MfClassic furi_assert(data); if(mf_classic_is_sector_trailer(block_num)) { - memcpy(&data->block[block_num].value[6], &block_data->value[6], 4); + memcpy(&data->block[block_num].data[6], &block_data->data[6], 4); } else { - memcpy(data->block[block_num].value, block_data->value, MF_CLASSIC_BLOCK_SIZE); + memcpy(data->block[block_num].data, block_data->data, MF_CLASSIC_BLOCK_SIZE); } FURI_BIT_SET(data->block_read_mask[block_num / 32], block_num % 32); } diff --git a/lib/nfc/protocols/mf_classic/mf_classic.h b/lib/nfc/protocols/mf_classic/mf_classic.h index 61c298aa4c9a..fa23fa0b4e35 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic.h +++ b/lib/nfc/protocols/mf_classic/mf_classic.h @@ -6,8 +6,8 @@ extern "C" { #endif -#define MF_CLASSIC_BLOCK_SIZE (16) #define MF_CLASSIC_TOTAL_BLOCKS_MAX (256) +#define MF_CLASSIC_BLOCK_SIZE (16) #define MF_CLASSIC_KEY_SIZE (6) #define MF_CLASSIC_ACCESS_BYTES_SIZE (4) @@ -27,11 +27,6 @@ typedef enum { MfClassicTypeNum, } MfClassicType; -typedef enum { - MfClassicKeyA, - MfClassicKeyB, -} MfClassicKey; - typedef enum { MfClassicActionDataRead, MfClassicActionDataWrite, @@ -47,13 +42,26 @@ typedef enum { } MfClassicAction; typedef struct { - uint8_t value[MF_CLASSIC_BLOCK_SIZE]; + uint8_t data[MF_CLASSIC_BLOCK_SIZE]; } MfClassicBlock; +typedef enum { + MfClassicKeyTypeA, + MfClassicKeyTypeB, +} MfClassicKeyType; + typedef struct { - uint8_t key_a[MF_CLASSIC_KEY_SIZE]; - uint8_t access_bits[MF_CLASSIC_ACCESS_BYTES_SIZE]; - uint8_t key_b[MF_CLASSIC_KEY_SIZE]; + uint8_t data[MF_CLASSIC_KEY_SIZE]; +} MfClassicKey; + +typedef struct { + uint8_t data[MF_CLASSIC_ACCESS_BYTES_SIZE]; +} MfClassicAccessBits; + +typedef struct { + MfClassicKey key_a; + MfClassicAccessBits access_bits; + MfClassicKey key_b; } MfClassicSectorTrailer; typedef struct { @@ -82,15 +90,18 @@ bool mf_classic_is_sector_trailer(uint8_t block); uint8_t mf_classic_get_sector_by_block(uint8_t block); -bool mf_classic_is_key_found(MfClassicData* data, uint8_t sector_num, MfClassicKey key_type); +bool mf_classic_is_key_found(MfClassicData* data, uint8_t sector_num, MfClassicKeyType key_type); void mf_classic_set_key_found( MfClassicData* data, uint8_t sector_num, - MfClassicKey key_type, + MfClassicKeyType key_type, uint64_t key); -void mf_classic_set_key_not_found(MfClassicData* data, uint8_t sector_num, MfClassicKey key_type); +void mf_classic_set_key_not_found( + MfClassicData* data, + uint8_t sector_num, + MfClassicKeyType key_type); bool mf_classic_is_block_read(MfClassicData* data, uint8_t block_num); diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller.c b/lib/nfc/protocols/mf_classic/mf_classic_poller.c index e69de29bb2d1..5b66f3aabf2a 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller.c @@ -0,0 +1,86 @@ +#include "mf_classic_poller_i.h" + +#include + +#define MF_CLASSIC_MAX_BUFF_SIZE (64) + +MfClassicPoller* mf_classic_poller_alloc(NfcaPoller* nfca_poller) { + furi_assert(nfca_poller); + + MfClassicPoller* instance = malloc(sizeof(MfClassicPoller)); + instance->nfca_poller = nfca_poller; + + return instance; +} + +void mf_classic_poller_free(MfClassicPoller* instance) { + furi_assert(instance); + + free(instance); +} + +MfClassicError mf_classic_poller_start( + MfClassicPoller* instance, + NfcaPollerEventCallback callback, + void* context) { + furi_assert(instance); + furi_assert(callback); + furi_assert(instance->nfca_poller); + furi_assert(instance->session_state == MfClassicPollerSessionStateIdle); + + instance->data = malloc(sizeof(MfClassicData)); + instance->buffer = nfc_poller_buffer_alloc(MF_CLASSIC_MAX_BUFF_SIZE, MF_CLASSIC_MAX_BUFF_SIZE); + + instance->session_state = MfClassicPollerSessionStateActive; + nfca_poller_start(instance->nfca_poller, callback, context); + + return MfClassicErrorNone; +} + +MfClassicError mf_classic_poller_read( + MfClassicPoller* instance, + MfClassicPollerCallback callback, + void* context) { + furi_assert(instance); + furi_assert(callback); + + instance->callback = callback; + instance->context = context; + + return MfClassicErrorNone; +} + +MfClassicError mf_classic_poller_get_data(MfClassicPoller* instance, MfClassicData* data) { + furi_assert(instance); + furi_assert(instance->data); + furi_assert(data); + + *data = *instance->data; + + return MfClassicErrorNone; +} + +MfClassicError mf_classic_poller_reset(MfClassicPoller* instance) { + furi_assert(instance); + furi_assert(instance->data); + furi_assert(instance->buffer); + furi_assert(instance->nfca_poller); + + nfc_poller_buffer_free(instance->buffer); + instance->callback = NULL; + instance->context = NULL; + + return MfClassicErrorNone; +} + +MfClassicError mf_classic_poller_stop(MfClassicPoller* instance) { + furi_assert(instance); + furi_assert(instance->nfca_poller); + + instance->session_state = MfClassicPollerSessionStateStopRequest; + nfca_poller_stop(instance->nfca_poller); + instance->session_state = MfClassicPollerSessionStateIdle; + free(instance->data); + + return mf_classic_poller_reset(instance); +} diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller.h b/lib/nfc/protocols/mf_classic/mf_classic_poller.h index e69de29bb2d1..18dababb127c 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller.h +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller.h @@ -0,0 +1,72 @@ +#pragma once + +#include "mf_classic.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct MfClassicPoller MfClassicPoller; + +typedef enum { + MfClassicPollerEventTypeAuthRequest, + MfClassicPollerEventTypeAuthSuccess, + MfClassicPollerEventTypeAuthFailed, + MfClassicPollerEventTypeReadSuccess, + MfClassicPollerEventTypeReadFailed, +} MfClassicPollerEventType; + +typedef struct { + MfClassicError error; +} MfClassicPollerEventData; + +typedef struct { + MfClassicPollerEventType type; + MfClassicPollerEventData data; +} MfClassicPollerEvent; + +typedef enum { + MfClassicPollerCommandContinue = NfcaPollerCommandContinue, + MfClassicPollerCommandReset = NfcaPollerCommandReset, + MfClassicPollerCommandStop = NfcaPollerCommandStop, +} MfClassicPollerCommand; + +typedef MfClassicPollerCommand ( + *MfClassicPollerCallback)(MfClassicPollerEvent event, void* context); + +MfClassicPoller* mf_classic_poller_alloc(NfcaPoller* nfca_poller); + +void mf_classic_poller_free(MfClassicPoller* instance); + +MfClassicError mf_classic_poller_start( + MfClassicPoller* instance, + NfcaPollerEventCallback callback, + void* context); + +MfClassicError mf_classic_poller_read( + MfClassicPoller* instance, + MfClassicPollerCallback callback, + void* context); + +MfClassicError mf_classic_poller_get_data(MfClassicPoller* instance, MfClassicData* data); + +MfClassicError mf_classic_poller_reset(MfClassicPoller* instance); + +MfClassicError mf_classic_poller_stop(MfClassicPoller* instance); + +// Sync api + +MfClassicError + mf_classic_poller_auth(MfClassicPoller* instance, uint8_t block_num, MfClassicKey* key); + +MfClassicError mf_classic_poller_read_block( + MfClassicPoller* instance, + uint8_t block_num, + MfClassicKey* key, + MfClassicKeyType key_type, + MfClassicBlock* data); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h new file mode 100644 index 000000000000..c522b18397fb --- /dev/null +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h @@ -0,0 +1,42 @@ +#pragma once + +#include "mf_classic_poller.h" +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + MfClassicPollerSessionStateIdle, + MfClassicPollerSessionStateActive, + MfClassicPollerSessionStateStopRequest, +} MfClassicPollerSessionState; + +typedef enum { + MfClassicAuthStateIdle, + MfClassicAuthStateWaitNt, + MfClassicAuthStateWaitAt, + MfClassicAuthStateSuccess, + MfClassicAuthStateFail, +} MfClassicAuthState; + +typedef enum { + MfClassicPollerStateIdle, +} MfClassicPollerState; + +struct MfClassicPoller { + NfcaPoller* nfca_poller; + MfClassicPollerSessionState session_state; + MfClassicAuthState auth_state; + NfcPollerBuffer* buffer; + MfClassicData* data; + MfClassicPollerCallback callback; + void* context; +}; + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.c b/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.c new file mode 100644 index 000000000000..ad3709f71d55 --- /dev/null +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.c @@ -0,0 +1,27 @@ +#include "mf_classic_poller_i.h" + +#include + +MfClassicError + mf_classic_poller_auth(MfClassicPoller* instance, uint8_t block_num, MfClassicKey* key) { + furi_assert(instance); + furi_assert(key); + UNUSED(block_num); + + return MfClassicErrorNone; +} + +MfClassicError mf_classic_poller_read_block( + MfClassicPoller* instance, + uint8_t block_num, + MfClassicKey* key, + MfClassicKeyType key_type, + MfClassicBlock* data) { + furi_assert(instance); + furi_assert(key); + furi_assert(data); + UNUSED(block_num); + UNUSED(key_type); + + return MfClassicErrorNone; +} \ No newline at end of file diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h index f446ce301652..cf059b2a0ea9 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h @@ -1,7 +1,7 @@ #pragma once -#include #include "mf_ultralight.h" +#include #ifdef __cplusplus extern "C" { diff --git a/lib/nfc/protocols/mifare_classic.c b/lib/nfc/protocols/mifare_classic.c index 307b9c75e6bf..356b145f66a9 100644 --- a/lib/nfc/protocols/mifare_classic.c +++ b/lib/nfc/protocols/mifare_classic.c @@ -485,28 +485,28 @@ static bool mf_classic_auth( if(!furi_hal_nfc_tx_rx(tx_rx, 6)) break; uint32_t nt = (uint32_t)nfc_util_bytes2num(tx_rx->rx_data, 4); - crypto1_init(crypto, key); - crypto1_word(crypto, nt ^ cuid, 0); + old_crypto1_init(crypto, key); + old_crypto1_word(crypto, nt ^ cuid, 0); uint8_t nr[4] = {}; - nfc_util_num2bytes(prng_successor(DWT->CYCCNT, 32), 4, nr); + nfc_util_num2bytes(old_prng_successor(DWT->CYCCNT, 32), 4, nr); for(uint8_t i = 0; i < 4; i++) { - tx_rx->tx_data[i] = crypto1_byte(crypto, nr[i], 0) ^ nr[i]; + tx_rx->tx_data[i] = old_crypto1_byte(crypto, nr[i], 0) ^ nr[i]; tx_rx->tx_parity[0] |= - (((crypto1_filter(crypto->odd) ^ nfc_util_odd_parity8(nr[i])) & 0x01) << (7 - i)); + (((old_crypto1_filter(crypto->odd) ^ nfc_util_odd_parity8(nr[i])) & 0x01) << (7 - i)); } - nt = prng_successor(nt, 32); + nt = old_prng_successor(nt, 32); for(uint8_t i = 4; i < 8; i++) { - nt = prng_successor(nt, 8); - tx_rx->tx_data[i] = crypto1_byte(crypto, 0x00, 0) ^ (nt & 0xff); + nt = old_prng_successor(nt, 8); + tx_rx->tx_data[i] = old_crypto1_byte(crypto, 0x00, 0) ^ (nt & 0xff); tx_rx->tx_parity[0] |= - (((crypto1_filter(crypto->odd) ^ nfc_util_odd_parity8(nt & 0xff)) & 0x01) + (((old_crypto1_filter(crypto->odd) ^ nfc_util_odd_parity8(nt & 0xff)) & 0x01) << (7 - i)); } tx_rx->tx_rx_type = FuriHalNfcTxRxTypeRaw; tx_rx->tx_bits = 8 * 8; if(!furi_hal_nfc_tx_rx(tx_rx, 6)) break; if(tx_rx->rx_bits == 32) { - crypto1_word(crypto, 0, 0); + old_crypto1_word(crypto, 0, 0); auth_success = true; } } while(false); @@ -604,7 +604,7 @@ bool mifare_classic_read_block( uint8_t plain_cmd[4] = {mifare_classic_read_block_CMD, block_num, 0x00, 0x00}; nfca_append_crc16(plain_cmd, 2); - crypto1_encrypt( + old_crypto1_encrypt( crypto, NULL, plain_cmd, sizeof(plain_cmd) * 8, tx_rx->tx_data, tx_rx->tx_parity); tx_rx->tx_bits = sizeof(plain_cmd) * 8; tx_rx->tx_rx_type = FuriHalNfcTxRxTypeRaw; @@ -612,7 +612,7 @@ bool mifare_classic_read_block( if(furi_hal_nfc_tx_rx(tx_rx, 50)) { if(tx_rx->rx_bits == 8 * (MF_CLASSIC_BLOCK_SIZE + 2)) { uint8_t block_received[MF_CLASSIC_BLOCK_SIZE + 2]; - crypto1_decrypt(crypto, tx_rx->rx_data, tx_rx->rx_bits, block_received); + old_crypto1_decrypt(crypto, tx_rx->rx_data, tx_rx->rx_bits, block_received); uint16_t crc_calc = nfca_get_crc16(block_received, MF_CLASSIC_BLOCK_SIZE); uint16_t crc_received = (block_received[MF_CLASSIC_BLOCK_SIZE + 1] << 8) | block_received[MF_CLASSIC_BLOCK_SIZE]; @@ -859,7 +859,7 @@ bool mifare_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* // Read command while(!command_processed) { //-V654 if(!is_encrypted) { - crypto1_reset(&emulator->crypto); + old_crypto1_reset(&emulator->crypto); memcpy(plain_data, tx_rx->rx_data, tx_rx->rx_bits / 8); } else { if(!furi_hal_nfc_tx_rx(tx_rx, 300)) { @@ -870,7 +870,7 @@ bool mifare_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_rx->rx_bits); break; } - crypto1_decrypt(&emulator->crypto, tx_rx->rx_data, tx_rx->rx_bits, plain_data); + old_crypto1_decrypt(&emulator->crypto, tx_rx->rx_data, tx_rx->rx_bits, plain_data); } // After increment, decrement or restore the only allowed command is transfer @@ -899,21 +899,21 @@ bool mifare_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* access_key = MfClassicKeyB; } - uint32_t nonce = prng_successor(DWT->CYCCNT, 32) ^ 0xAA; + uint32_t nonce = old_prng_successor(DWT->CYCCNT, 32) ^ 0xAA; uint8_t nt[4]; uint8_t nt_keystream[4]; nfc_util_num2bytes(nonce, 4, nt); nfc_util_num2bytes(nonce ^ emulator->cuid, 4, nt_keystream); - crypto1_init(&emulator->crypto, key); + old_crypto1_init(&emulator->crypto, key); if(!is_encrypted) { - crypto1_word(&emulator->crypto, emulator->cuid ^ nonce, 0); + old_crypto1_word(&emulator->crypto, emulator->cuid ^ nonce, 0); memcpy(tx_rx->tx_data, nt, sizeof(nt)); tx_rx->tx_parity[0] = 0; nfc_util_odd_parity(tx_rx->tx_data, tx_rx->tx_parity, sizeof(nt)); tx_rx->tx_bits = sizeof(nt) * 8; tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent; } else { - crypto1_encrypt( + old_crypto1_encrypt( &emulator->crypto, nt_keystream, nt, @@ -938,19 +938,19 @@ bool mifare_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* uint32_t nr = nfc_util_bytes2num(tx_rx->rx_data, 4); uint32_t ar = nfc_util_bytes2num(&tx_rx->rx_data[4], 4); - crypto1_word(&emulator->crypto, nr, 1); - uint32_t cardRr = ar ^ crypto1_word(&emulator->crypto, 0, 0); - if(cardRr != prng_successor(nonce, 64)) { - FURI_LOG_T(TAG, "Wrong AUTH! %08lX != %08lX", cardRr, prng_successor(nonce, 64)); + old_crypto1_word(&emulator->crypto, nr, 1); + uint32_t cardRr = ar ^ old_crypto1_word(&emulator->crypto, 0, 0); + if(cardRr != old_prng_successor(nonce, 64)) { + FURI_LOG_T(TAG, "Wrong AUTH! %08lX != %08lX", cardRr, old_prng_successor(nonce, 64)); // Don't send NACK, as the tag doesn't send it command_processed = true; break; } - uint32_t ans = prng_successor(nonce, 96); + uint32_t ans = old_prng_successor(nonce, 96); uint8_t response[4] = {}; nfc_util_num2bytes(ans, 4, response); - crypto1_encrypt( + old_crypto1_encrypt( &emulator->crypto, NULL, response, @@ -990,7 +990,7 @@ bool mifare_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* emulator, block, access_key, MfClassicActionDataRead)) { // Send NACK uint8_t nack = 0x04; - crypto1_encrypt( + old_crypto1_encrypt( &emulator->crypto, NULL, &nack, 4, tx_rx->tx_data, tx_rx->tx_parity); tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent; tx_rx->tx_bits = 4; @@ -999,7 +999,7 @@ bool mifare_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* } nfca_append_crc16(block_data, 16); - crypto1_encrypt( + old_crypto1_encrypt( &emulator->crypto, NULL, block_data, @@ -1015,14 +1015,14 @@ bool mifare_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* } // Send ACK uint8_t ack = MF_CLASSIC_ACK_CMD; - crypto1_encrypt(&emulator->crypto, NULL, &ack, 4, tx_rx->tx_data, tx_rx->tx_parity); + old_crypto1_encrypt(&emulator->crypto, NULL, &ack, 4, tx_rx->tx_data, tx_rx->tx_parity); tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent; tx_rx->tx_bits = 4; if(!furi_hal_nfc_tx_rx(tx_rx, 300)) break; if(tx_rx->rx_bits != (MF_CLASSIC_BLOCK_SIZE + 2) * 8) break; - crypto1_decrypt(&emulator->crypto, tx_rx->rx_data, tx_rx->rx_bits, plain_data); + old_crypto1_decrypt(&emulator->crypto, tx_rx->rx_data, tx_rx->rx_bits, plain_data); uint8_t block_data[MF_CLASSIC_BLOCK_SIZE] = {}; memcpy(block_data, emulator->data.block[block].value, MF_CLASSIC_BLOCK_SIZE); if(mifare_classic_is_sector_trailer(block)) { @@ -1052,7 +1052,7 @@ bool mifare_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* } // Send ACK ack = MF_CLASSIC_ACK_CMD; - crypto1_encrypt(&emulator->crypto, NULL, &ack, 4, tx_rx->tx_data, tx_rx->tx_parity); + old_crypto1_encrypt(&emulator->crypto, NULL, &ack, 4, tx_rx->tx_data, tx_rx->tx_parity); tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent; tx_rx->tx_bits = 4; } else if( @@ -1080,14 +1080,14 @@ bool mifare_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* // Send ACK uint8_t ack = MF_CLASSIC_ACK_CMD; - crypto1_encrypt(&emulator->crypto, NULL, &ack, 4, tx_rx->tx_data, tx_rx->tx_parity); + old_crypto1_encrypt(&emulator->crypto, NULL, &ack, 4, tx_rx->tx_data, tx_rx->tx_parity); tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent; tx_rx->tx_bits = 4; if(!furi_hal_nfc_tx_rx(tx_rx, 300)) break; if(tx_rx->rx_bits != (sizeof(int32_t) + 2) * 8) break; - crypto1_decrypt(&emulator->crypto, tx_rx->rx_data, tx_rx->rx_bits, plain_data); + old_crypto1_decrypt(&emulator->crypto, tx_rx->rx_data, tx_rx->rx_bits, plain_data); int32_t value = *(int32_t*)&plain_data[0]; if(value < 0) { value = -value; @@ -1115,7 +1115,7 @@ bool mifare_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* transfer_buf_valid = false; uint8_t ack = MF_CLASSIC_ACK_CMD; - crypto1_encrypt(&emulator->crypto, NULL, &ack, 4, tx_rx->tx_data, tx_rx->tx_parity); + old_crypto1_encrypt(&emulator->crypto, NULL, &ack, 4, tx_rx->tx_data, tx_rx->tx_parity); tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent; tx_rx->tx_bits = 4; } else { @@ -1129,7 +1129,7 @@ bool mifare_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* uint8_t nack = transfer_buf_valid ? MF_CLASSIC_NACK_BUF_VALID_CMD : MF_CLASSIC_NACK_BUF_INVALID_CMD; if(is_encrypted) { - crypto1_encrypt(&emulator->crypto, NULL, &nack, 4, tx_rx->tx_data, tx_rx->tx_parity); + old_crypto1_encrypt(&emulator->crypto, NULL, &nack, 4, tx_rx->tx_data, tx_rx->tx_parity); } else { tx_rx->tx_data[0] = nack; } @@ -1148,7 +1148,7 @@ void mifare_classic_halt(FuriHalNfcTxRxContext* tx_rx, Crypto1* crypto) { nfca_append_crc16(plain_data, 2); if(crypto) { - crypto1_encrypt( + old_crypto1_encrypt( crypto, NULL, plain_data, sizeof(plain_data) * 8, tx_rx->tx_data, tx_rx->tx_parity); } else { memcpy(tx_rx->tx_data, plain_data, sizeof(plain_data)); @@ -1178,13 +1178,13 @@ bool mifare_classic_write_block( plain_data[0] = mifare_classic_write_block_CMD; plain_data[1] = block_num; nfca_append_crc16(plain_data, 2); - crypto1_encrypt(crypto, NULL, plain_data, 4 * 8, tx_rx->tx_data, tx_rx->tx_parity); + old_crypto1_encrypt(crypto, NULL, plain_data, 4 * 8, tx_rx->tx_data, tx_rx->tx_parity); tx_rx->tx_bits = 4 * 8; tx_rx->tx_rx_type = FuriHalNfcTxRxTypeRaw; if(furi_hal_nfc_tx_rx(tx_rx, 50)) { if(tx_rx->rx_bits == 4) { - crypto1_decrypt(crypto, tx_rx->rx_data, 4, &resp); + old_crypto1_decrypt(crypto, tx_rx->rx_data, 4, &resp); if(resp != 0x0A) { FURI_LOG_D(TAG, "NACK received on write cmd: %02X", resp); break; @@ -1201,7 +1201,7 @@ bool mifare_classic_write_block( // Send data memcpy(plain_data, src_block->value, MF_CLASSIC_BLOCK_SIZE); nfca_append_crc16(plain_data, MF_CLASSIC_BLOCK_SIZE); - crypto1_encrypt( + old_crypto1_encrypt( crypto, NULL, plain_data, @@ -1212,7 +1212,7 @@ bool mifare_classic_write_block( tx_rx->tx_rx_type = FuriHalNfcTxRxTypeRaw; if(furi_hal_nfc_tx_rx(tx_rx, 50)) { if(tx_rx->rx_bits == 4) { - crypto1_decrypt(crypto, tx_rx->rx_data, 4, &resp); + old_crypto1_decrypt(crypto, tx_rx->rx_data, 4, &resp); if(resp != MF_CLASSIC_ACK_CMD) { FURI_LOG_D(TAG, "NACK received on sending data"); break; @@ -1273,7 +1273,7 @@ bool mifare_classic_transfer(FuriHalNfcTxRxContext* tx_rx, Crypto1* crypto, uint bool transfer_success = false; nfca_append_crc16(plain_data, 2); - crypto1_encrypt( + old_crypto1_encrypt( crypto, NULL, plain_data, sizeof(plain_data) * 8, tx_rx->tx_data, tx_rx->tx_parity); tx_rx->tx_bits = sizeof(plain_data) * 8; tx_rx->tx_rx_type = FuriHalNfcTxRxTypeRaw; @@ -1281,7 +1281,7 @@ bool mifare_classic_transfer(FuriHalNfcTxRxContext* tx_rx, Crypto1* crypto, uint do { if(furi_hal_nfc_tx_rx(tx_rx, 50)) { if(tx_rx->rx_bits == 4) { - crypto1_decrypt(crypto, tx_rx->rx_data, 4, &resp); + old_crypto1_decrypt(crypto, tx_rx->rx_data, 4, &resp); if(resp != 0x0A) { FURI_LOG_D(TAG, "NACK received on transfer cmd: %02X", resp); break; @@ -1323,13 +1323,13 @@ bool mifare_classic_value_cmd( plain_data[0] = cmd; plain_data[1] = block_num; nfca_append_crc16(plain_data, 2); - crypto1_encrypt(crypto, NULL, plain_data, 4 * 8, tx_rx->tx_data, tx_rx->tx_parity); + old_crypto1_encrypt(crypto, NULL, plain_data, 4 * 8, tx_rx->tx_data, tx_rx->tx_parity); tx_rx->tx_bits = 4 * 8; tx_rx->tx_rx_type = FuriHalNfcTxRxTypeRaw; if(furi_hal_nfc_tx_rx(tx_rx, 50)) { if(tx_rx->rx_bits == 4) { - crypto1_decrypt(crypto, tx_rx->rx_data, 4, &resp); + old_crypto1_decrypt(crypto, tx_rx->rx_data, 4, &resp); if(resp != 0x0A) { FURI_LOG_D(TAG, "NACK received on write cmd: %02X", resp); break; @@ -1346,14 +1346,14 @@ bool mifare_classic_value_cmd( // Send data memcpy(plain_data, &d_value, sizeof(d_value)); nfca_append_crc16(plain_data, sizeof(d_value)); - crypto1_encrypt( + old_crypto1_encrypt( crypto, NULL, plain_data, (sizeof(d_value) + 2) * 8, tx_rx->tx_data, tx_rx->tx_parity); tx_rx->tx_bits = (sizeof(d_value) + 2) * 8; tx_rx->tx_rx_type = FuriHalNfcTxRxTypeRaw; // inc, dec, restore do not ACK, but they do NACK if(furi_hal_nfc_tx_rx(tx_rx, 50)) { if(tx_rx->rx_bits == 4) { - crypto1_decrypt(crypto, tx_rx->rx_data, 4, &resp); + old_crypto1_decrypt(crypto, tx_rx->rx_data, 4, &resp); if(resp != 0x0A) { FURI_LOG_D(TAG, "NACK received on transfer cmd: %02X", resp); break; From 96a70a0e237a1f639ebc9d774fa9d020a1da20de Mon Sep 17 00:00:00 2001 From: gornekich Date: Mon, 15 May 2023 16:51:57 +0400 Subject: [PATCH 084/149] mf classic: introduce auth context --- lib/nfc/protocols/mf_classic/mf_classic.h | 31 +++++++++++++++++++ .../protocols/mf_classic/mf_classic_poller.h | 8 +++-- .../mf_classic/mf_classic_poller_sync_api.c | 10 ++++-- 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/lib/nfc/protocols/mf_classic/mf_classic.h b/lib/nfc/protocols/mf_classic/mf_classic.h index fa23fa0b4e35..91bb3db7cfcb 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic.h +++ b/lib/nfc/protocols/mf_classic/mf_classic.h @@ -11,6 +11,11 @@ extern "C" { #define MF_CLASSIC_KEY_SIZE (6) #define MF_CLASSIC_ACCESS_BYTES_SIZE (4) +#define MF_CLASSIC_NT_SIZE (4) +#define MF_CLASSIC_NR_SIZE (4) +#define MF_CLASSIC_AR_SIZE (4) +#define MF_CLASSIC_AT_SIZE (4) + typedef enum { MfClassicErrorNone, MfClassicErrorNotPresent, @@ -58,6 +63,32 @@ typedef struct { uint8_t data[MF_CLASSIC_ACCESS_BYTES_SIZE]; } MfClassicAccessBits; +typedef struct { + uint8_t data[MF_CLASSIC_NT_SIZE]; +} MfClassicNt; + +typedef struct { + uint8_t data[MF_CLASSIC_AT_SIZE]; +} MfClassicAt; + +typedef struct { + uint8_t data[MF_CLASSIC_NR_SIZE]; +} MfClassicNr; + +typedef struct { + uint8_t data[MF_CLASSIC_AR_SIZE]; +} MfClassicAr; + +typedef struct { + uint8_t sector_num; + MfClassicKey key; + MfClassicKeyType key_type; + MfClassicNt nt; + MfClassicNr nr; + MfClassicAr ar; + MfClassicAt at; +} MfClassicAuthContext; + typedef struct { MfClassicKey key_a; MfClassicAccessBits access_bits; diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller.h b/lib/nfc/protocols/mf_classic/mf_classic_poller.h index 18dababb127c..d7c6180e159c 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller.h +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller.h @@ -57,8 +57,12 @@ MfClassicError mf_classic_poller_stop(MfClassicPoller* instance); // Sync api -MfClassicError - mf_classic_poller_auth(MfClassicPoller* instance, uint8_t block_num, MfClassicKey* key); +MfClassicError mf_classic_poller_auth( + MfClassicPoller* instance, + uint8_t block_num, + MfClassicKey* key, + MfClassicKeyType key_type, + MfClassicAuthContext* data); MfClassicError mf_classic_poller_read_block( MfClassicPoller* instance, diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.c b/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.c index ad3709f71d55..9b9bceef0964 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.c @@ -2,11 +2,17 @@ #include -MfClassicError - mf_classic_poller_auth(MfClassicPoller* instance, uint8_t block_num, MfClassicKey* key) { +MfClassicError mf_classic_poller_auth( + MfClassicPoller* instance, + uint8_t block_num, + MfClassicKey* key, + MfClassicKeyType key_type, + MfClassicAuthContext* data) { furi_assert(instance); furi_assert(key); UNUSED(block_num); + UNUSED(key_type); + UNUSED(data); return MfClassicErrorNone; } From 3fc60295aad0b99ca4c65cb325fc7f39d8626e17 Mon Sep 17 00:00:00 2001 From: gornekich Date: Mon, 15 May 2023 17:01:56 +0400 Subject: [PATCH 085/149] nfc hal: remove interrupt instead of disabling --- firmware/targets/f7/furi_hal/f_hal_nfc_irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc_irq.c b/firmware/targets/f7/furi_hal/f_hal_nfc_irq.c index e5e276fd588e..f51d1370ffce 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfc_irq.c +++ b/firmware/targets/f7/furi_hal/f_hal_nfc_irq.c @@ -24,5 +24,5 @@ void f_hal_nfc_init_gpio_isr() { void f_hal_nfc_deinit_gpio_isr() { furi_hal_gpio_init(&gpio_nfc_irq_rfid_pull, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow); - furi_hal_gpio_disable_int_callback(&gpio_nfc_irq_rfid_pull); + furi_hal_gpio_remove_int_callback(&gpio_nfc_irq_rfid_pull); } From 6bf995c5a2e2fcb064c8555021f07c05295f5382 Mon Sep 17 00:00:00 2001 From: gornekich Date: Wed, 17 May 2023 11:09:18 +0400 Subject: [PATCH 086/149] nfc rpc: add mf classic auth and read block --- .../main/nfc_rpc/assets/compiled/main.pb.h | 19 +- .../nfc_rpc/assets/compiled/mf_classic.pb.c | 23 +++ .../nfc_rpc/assets/compiled/mf_classic.pb.h | 169 ++++++++++++++++++ .../main/nfc_rpc/assets/protobuf/main.proto | 7 + .../assets/protobuf/mf_classic.options | 11 ++ .../nfc_rpc/assets/protobuf/mf_classic.proto | 45 +++++ applications/main/nfc_rpc/nfc_rpc.c | 7 +- applications/main/nfc_rpc/nfc_rpc_i.h | 3 + .../main/nfc_rpc/nfc_rpc_mf_classic.c | 109 +++++++++++ .../main/nfc_rpc/nfc_rpc_mf_ultralight.c | 1 - lib/nfc/protocols/mf_classic/mf_classic.h | 2 +- .../mf_classic/mf_classic_poller_sync_api.c | 21 ++- 12 files changed, 410 insertions(+), 7 deletions(-) create mode 100644 applications/main/nfc_rpc/assets/compiled/mf_classic.pb.c create mode 100644 applications/main/nfc_rpc/assets/compiled/mf_classic.pb.h create mode 100644 applications/main/nfc_rpc/assets/protobuf/mf_classic.options create mode 100644 applications/main/nfc_rpc/assets/protobuf/mf_classic.proto create mode 100644 applications/main/nfc_rpc/nfc_rpc_mf_classic.c diff --git a/applications/main/nfc_rpc/assets/compiled/main.pb.h b/applications/main/nfc_rpc/assets/compiled/main.pb.h index c956c2badb01..0c25a8855ded 100644 --- a/applications/main/nfc_rpc/assets/compiled/main.pb.h +++ b/applications/main/nfc_rpc/assets/compiled/main.pb.h @@ -6,6 +6,7 @@ #include #include "nfca.pb.h" #include "mf_ultralight.pb.h" +#include "mf_classic.pb.h" #if PB_PROTO_HEADER_VERSION != 40 #error Regenerate this file with the current version of nanopb generator. @@ -53,6 +54,10 @@ typedef struct _Nfc_Main { PB_MfUltralight_EmulateStartResponse mf_ultralight_emulate_start_resp; PB_MfUltralight_EmulateStopRequest mf_ultralight_emulate_stop_req; PB_MfUltralight_EmulateStopResponse mf_ultralight_emulate_stop_resp; + PB_MfClassic_AuthRequest mf_classic_auth_req; + PB_MfClassic_AuthResponse mf_classic_auth_resp; + PB_MfClassic_ReadBlockRequest mf_classic_read_block_req; + PB_MfClassic_ReadBlockResponse mf_classic_read_block_resp; } content; } Nfc_Main; @@ -101,6 +106,10 @@ extern "C" { #define Nfc_Main_mf_ultralight_emulate_start_resp_tag 22 #define Nfc_Main_mf_ultralight_emulate_stop_req_tag 23 #define Nfc_Main_mf_ultralight_emulate_stop_resp_tag 24 +#define Nfc_Main_mf_classic_auth_req_tag 25 +#define Nfc_Main_mf_classic_auth_resp_tag 26 +#define Nfc_Main_mf_classic_read_block_req_tag 27 +#define Nfc_Main_mf_classic_read_block_resp_tag 28 /* Struct field encoding specification for nanopb */ #define Nfc_Empty_FIELDLIST(X, a) \ @@ -132,7 +141,11 @@ X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_tearing_flag_resp X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_emulate_start_req,content.mf_ultralight_emulate_start_req), 21) \ X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_emulate_start_resp,content.mf_ultralight_emulate_start_resp), 22) \ X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_emulate_stop_req,content.mf_ultralight_emulate_stop_req), 23) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_emulate_stop_resp,content.mf_ultralight_emulate_stop_resp), 24) +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_emulate_stop_resp,content.mf_ultralight_emulate_stop_resp), 24) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_classic_auth_req,content.mf_classic_auth_req), 25) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_classic_auth_resp,content.mf_classic_auth_resp), 26) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_classic_read_block_req,content.mf_classic_read_block_req), 27) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_classic_read_block_resp,content.mf_classic_read_block_resp), 28) #define Nfc_Main_CALLBACK NULL #define Nfc_Main_DEFAULT NULL #define Nfc_Main_content_empty_MSGTYPE Nfc_Empty @@ -158,6 +171,10 @@ X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_emulate_stop_resp,cont #define Nfc_Main_content_mf_ultralight_emulate_start_resp_MSGTYPE PB_MfUltralight_EmulateStartResponse #define Nfc_Main_content_mf_ultralight_emulate_stop_req_MSGTYPE PB_MfUltralight_EmulateStopRequest #define Nfc_Main_content_mf_ultralight_emulate_stop_resp_MSGTYPE PB_MfUltralight_EmulateStopResponse +#define Nfc_Main_content_mf_classic_auth_req_MSGTYPE PB_MfClassic_AuthRequest +#define Nfc_Main_content_mf_classic_auth_resp_MSGTYPE PB_MfClassic_AuthResponse +#define Nfc_Main_content_mf_classic_read_block_req_MSGTYPE PB_MfClassic_ReadBlockRequest +#define Nfc_Main_content_mf_classic_read_block_resp_MSGTYPE PB_MfClassic_ReadBlockResponse extern const pb_msgdesc_t Nfc_Empty_msg; extern const pb_msgdesc_t Nfc_Main_msg; diff --git a/applications/main/nfc_rpc/assets/compiled/mf_classic.pb.c b/applications/main/nfc_rpc/assets/compiled/mf_classic.pb.c new file mode 100644 index 000000000000..114429ee891e --- /dev/null +++ b/applications/main/nfc_rpc/assets/compiled/mf_classic.pb.c @@ -0,0 +1,23 @@ +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-0.4.8-dev */ + +#include "mf_classic.pb.h" +#if PB_PROTO_HEADER_VERSION != 40 +#error Regenerate this file with the current version of nanopb generator. +#endif + +PB_BIND(PB_MfClassic_AuthRequest, PB_MfClassic_AuthRequest, AUTO) + + +PB_BIND(PB_MfClassic_AuthResponse, PB_MfClassic_AuthResponse, AUTO) + + +PB_BIND(PB_MfClassic_ReadBlockRequest, PB_MfClassic_ReadBlockRequest, AUTO) + + +PB_BIND(PB_MfClassic_ReadBlockResponse, PB_MfClassic_ReadBlockResponse, AUTO) + + + + + diff --git a/applications/main/nfc_rpc/assets/compiled/mf_classic.pb.h b/applications/main/nfc_rpc/assets/compiled/mf_classic.pb.h new file mode 100644 index 000000000000..3d9c2d6da27b --- /dev/null +++ b/applications/main/nfc_rpc/assets/compiled/mf_classic.pb.h @@ -0,0 +1,169 @@ +/* Automatically generated nanopb header */ +/* Generated by nanopb-0.4.8-dev */ + +#ifndef PB_PB_MFCLASSIC_MF_CLASSIC_PB_H_INCLUDED +#define PB_PB_MFCLASSIC_MF_CLASSIC_PB_H_INCLUDED +#include + +#if PB_PROTO_HEADER_VERSION != 40 +#error Regenerate this file with the current version of nanopb generator. +#endif + +/* Enum definitions */ +typedef enum _PB_MfClassic_Error { + PB_MfClassic_Error_None = 0, + PB_MfClassic_Error_NotPresent = 1, + PB_MfClassic_Error_Protocol = 2, + PB_MfClassic_Error_Auth = 3, + PB_MfClassic_Error_Timeout = 4 +} PB_MfClassic_Error; + +typedef enum _PB_MfClassic_KeyType { + PB_MfClassic_KeyType_KeyTypeA = 0, + PB_MfClassic_KeyType_KeyTypeB = 1 +} PB_MfClassic_KeyType; + +/* Struct definitions */ +typedef PB_BYTES_ARRAY_T(6) PB_MfClassic_AuthRequest_key_t; +typedef struct _PB_MfClassic_AuthRequest { + uint8_t block; + PB_MfClassic_AuthRequest_key_t key; + PB_MfClassic_KeyType key_type; +} PB_MfClassic_AuthRequest; + +typedef PB_BYTES_ARRAY_T(6) PB_MfClassic_AuthResponse_key_t; +typedef PB_BYTES_ARRAY_T(4) PB_MfClassic_AuthResponse_nt_t; +typedef PB_BYTES_ARRAY_T(4) PB_MfClassic_AuthResponse_nr_t; +typedef PB_BYTES_ARRAY_T(4) PB_MfClassic_AuthResponse_ar_t; +typedef PB_BYTES_ARRAY_T(4) PB_MfClassic_AuthResponse_at_t; +typedef struct _PB_MfClassic_AuthResponse { + PB_MfClassic_Error error; + uint8_t block; + PB_MfClassic_AuthResponse_key_t key; + PB_MfClassic_KeyType key_type; + PB_MfClassic_AuthResponse_nt_t nt; + PB_MfClassic_AuthResponse_nr_t nr; + PB_MfClassic_AuthResponse_ar_t ar; + PB_MfClassic_AuthResponse_at_t at; +} PB_MfClassic_AuthResponse; + +typedef PB_BYTES_ARRAY_T(6) PB_MfClassic_ReadBlockRequest_key_t; +typedef struct _PB_MfClassic_ReadBlockRequest { + uint8_t block; + PB_MfClassic_ReadBlockRequest_key_t key; + PB_MfClassic_KeyType key_type; +} PB_MfClassic_ReadBlockRequest; + +typedef PB_BYTES_ARRAY_T(16) PB_MfClassic_ReadBlockResponse_data_t; +typedef struct _PB_MfClassic_ReadBlockResponse { + PB_MfClassic_Error error; + PB_MfClassic_ReadBlockResponse_data_t data; +} PB_MfClassic_ReadBlockResponse; + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Helper constants for enums */ +#define _PB_MfClassic_Error_MIN PB_MfClassic_Error_None +#define _PB_MfClassic_Error_MAX PB_MfClassic_Error_Timeout +#define _PB_MfClassic_Error_ARRAYSIZE ((PB_MfClassic_Error)(PB_MfClassic_Error_Timeout+1)) + +#define _PB_MfClassic_KeyType_MIN PB_MfClassic_KeyType_KeyTypeA +#define _PB_MfClassic_KeyType_MAX PB_MfClassic_KeyType_KeyTypeB +#define _PB_MfClassic_KeyType_ARRAYSIZE ((PB_MfClassic_KeyType)(PB_MfClassic_KeyType_KeyTypeB+1)) + +#define PB_MfClassic_AuthRequest_key_type_ENUMTYPE PB_MfClassic_KeyType + +#define PB_MfClassic_AuthResponse_error_ENUMTYPE PB_MfClassic_Error +#define PB_MfClassic_AuthResponse_key_type_ENUMTYPE PB_MfClassic_KeyType + +#define PB_MfClassic_ReadBlockRequest_key_type_ENUMTYPE PB_MfClassic_KeyType + +#define PB_MfClassic_ReadBlockResponse_error_ENUMTYPE PB_MfClassic_Error + + +/* Initializer values for message structs */ +#define PB_MfClassic_AuthRequest_init_default {0, {0, {0}}, _PB_MfClassic_KeyType_MIN} +#define PB_MfClassic_AuthResponse_init_default {_PB_MfClassic_Error_MIN, 0, {0, {0}}, _PB_MfClassic_KeyType_MIN, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}} +#define PB_MfClassic_ReadBlockRequest_init_default {0, {0, {0}}, _PB_MfClassic_KeyType_MIN} +#define PB_MfClassic_ReadBlockResponse_init_default {_PB_MfClassic_Error_MIN, {0, {0}}} +#define PB_MfClassic_AuthRequest_init_zero {0, {0, {0}}, _PB_MfClassic_KeyType_MIN} +#define PB_MfClassic_AuthResponse_init_zero {_PB_MfClassic_Error_MIN, 0, {0, {0}}, _PB_MfClassic_KeyType_MIN, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}} +#define PB_MfClassic_ReadBlockRequest_init_zero {0, {0, {0}}, _PB_MfClassic_KeyType_MIN} +#define PB_MfClassic_ReadBlockResponse_init_zero {_PB_MfClassic_Error_MIN, {0, {0}}} + +/* Field tags (for use in manual encoding/decoding) */ +#define PB_MfClassic_AuthRequest_block_tag 1 +#define PB_MfClassic_AuthRequest_key_tag 2 +#define PB_MfClassic_AuthRequest_key_type_tag 3 +#define PB_MfClassic_AuthResponse_error_tag 1 +#define PB_MfClassic_AuthResponse_block_tag 2 +#define PB_MfClassic_AuthResponse_key_tag 3 +#define PB_MfClassic_AuthResponse_key_type_tag 4 +#define PB_MfClassic_AuthResponse_nt_tag 5 +#define PB_MfClassic_AuthResponse_nr_tag 6 +#define PB_MfClassic_AuthResponse_ar_tag 7 +#define PB_MfClassic_AuthResponse_at_tag 8 +#define PB_MfClassic_ReadBlockRequest_block_tag 1 +#define PB_MfClassic_ReadBlockRequest_key_tag 2 +#define PB_MfClassic_ReadBlockRequest_key_type_tag 3 +#define PB_MfClassic_ReadBlockResponse_error_tag 1 +#define PB_MfClassic_ReadBlockResponse_data_tag 2 + +/* Struct field encoding specification for nanopb */ +#define PB_MfClassic_AuthRequest_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UINT32, block, 1) \ +X(a, STATIC, SINGULAR, BYTES, key, 2) \ +X(a, STATIC, SINGULAR, UENUM, key_type, 3) +#define PB_MfClassic_AuthRequest_CALLBACK NULL +#define PB_MfClassic_AuthRequest_DEFAULT NULL + +#define PB_MfClassic_AuthResponse_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UENUM, error, 1) \ +X(a, STATIC, SINGULAR, UINT32, block, 2) \ +X(a, STATIC, SINGULAR, BYTES, key, 3) \ +X(a, STATIC, SINGULAR, UENUM, key_type, 4) \ +X(a, STATIC, SINGULAR, BYTES, nt, 5) \ +X(a, STATIC, SINGULAR, BYTES, nr, 6) \ +X(a, STATIC, SINGULAR, BYTES, ar, 7) \ +X(a, STATIC, SINGULAR, BYTES, at, 8) +#define PB_MfClassic_AuthResponse_CALLBACK NULL +#define PB_MfClassic_AuthResponse_DEFAULT NULL + +#define PB_MfClassic_ReadBlockRequest_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UINT32, block, 1) \ +X(a, STATIC, SINGULAR, BYTES, key, 2) \ +X(a, STATIC, SINGULAR, UENUM, key_type, 3) +#define PB_MfClassic_ReadBlockRequest_CALLBACK NULL +#define PB_MfClassic_ReadBlockRequest_DEFAULT NULL + +#define PB_MfClassic_ReadBlockResponse_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UENUM, error, 1) \ +X(a, STATIC, SINGULAR, BYTES, data, 2) +#define PB_MfClassic_ReadBlockResponse_CALLBACK NULL +#define PB_MfClassic_ReadBlockResponse_DEFAULT NULL + +extern const pb_msgdesc_t PB_MfClassic_AuthRequest_msg; +extern const pb_msgdesc_t PB_MfClassic_AuthResponse_msg; +extern const pb_msgdesc_t PB_MfClassic_ReadBlockRequest_msg; +extern const pb_msgdesc_t PB_MfClassic_ReadBlockResponse_msg; + +/* Defines for backwards compatibility with code written before nanopb-0.4.0 */ +#define PB_MfClassic_AuthRequest_fields &PB_MfClassic_AuthRequest_msg +#define PB_MfClassic_AuthResponse_fields &PB_MfClassic_AuthResponse_msg +#define PB_MfClassic_ReadBlockRequest_fields &PB_MfClassic_ReadBlockRequest_msg +#define PB_MfClassic_ReadBlockResponse_fields &PB_MfClassic_ReadBlockResponse_msg + +/* Maximum encoded size of messages (where known) */ +#define PB_MfClassic_AuthRequest_size 13 +#define PB_MfClassic_AuthResponse_size 39 +#define PB_MfClassic_ReadBlockRequest_size 13 +#define PB_MfClassic_ReadBlockResponse_size 20 + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/applications/main/nfc_rpc/assets/protobuf/main.proto b/applications/main/nfc_rpc/assets/protobuf/main.proto index 2ba8d16540ee..115b7f40a654 100644 --- a/applications/main/nfc_rpc/assets/protobuf/main.proto +++ b/applications/main/nfc_rpc/assets/protobuf/main.proto @@ -1,6 +1,8 @@ syntax = "proto3"; import "nfca.proto"; import "mf_ultralight.proto"; +import "mf_classic.proto"; + package Nfc; option java_package = "com.flipperdevices.nfc.protobuf"; @@ -47,5 +49,10 @@ message Main { .PB_MfUltralight.EmulateStartResponse mf_ultralight_emulate_start_resp = 22; .PB_MfUltralight.EmulateStopRequest mf_ultralight_emulate_stop_req = 23; .PB_MfUltralight.EmulateStopResponse mf_ultralight_emulate_stop_resp = 24; + + .PB_MfClassic.AuthRequest mf_classic_auth_req = 25; + .PB_MfClassic.AuthResponse mf_classic_auth_resp = 26; + .PB_MfClassic.ReadBlockRequest mf_classic_read_block_req = 27; + .PB_MfClassic.ReadBlockResponse mf_classic_read_block_resp = 28; } } diff --git a/applications/main/nfc_rpc/assets/protobuf/mf_classic.options b/applications/main/nfc_rpc/assets/protobuf/mf_classic.options new file mode 100644 index 000000000000..d6cd11ef9438 --- /dev/null +++ b/applications/main/nfc_rpc/assets/protobuf/mf_classic.options @@ -0,0 +1,11 @@ +PB_MfClassic.AuthRequest.block int_size:IS_8 +PB_MfClassic.AuthRequest.key max_size: 6 +PB_MfClassic.AuthResponse.block int_size:IS_8 +PB_MfClassic.AuthResponse.key max_size: 6 +PB_MfClassic.AuthResponse.nt max_size: 4 +PB_MfClassic.AuthResponse.nr max_size: 4 +PB_MfClassic.AuthResponse.ar max_size: 4 +PB_MfClassic.AuthResponse.at max_size: 4 +PB_MfClassic.ReadBlockRequest.block int_size:IS_8 +PB_MfClassic.ReadBlockRequest.key max_size: 6 +PB_MfClassic.ReadBlockResponse.data max_size: 16 diff --git a/applications/main/nfc_rpc/assets/protobuf/mf_classic.proto b/applications/main/nfc_rpc/assets/protobuf/mf_classic.proto new file mode 100644 index 000000000000..cce98380cfbc --- /dev/null +++ b/applications/main/nfc_rpc/assets/protobuf/mf_classic.proto @@ -0,0 +1,45 @@ +syntax = "proto3"; + +package PB_MfClassic; +option java_package = "com.flipperdevices.nfc.protobuf"; + +enum Error { + None = 0; + NotPresent = 1; + Protocol = 2; + Auth = 3; + Timeout = 4; +} + +enum KeyType { + KeyTypeA = 0; + KeyTypeB = 1; +} + +message AuthRequest { + uint32 block = 1; + bytes key = 2; + KeyType key_type = 3; +} + +message AuthResponse { + Error error = 1; + uint32 block = 2; + bytes key = 3; + KeyType key_type = 4; + bytes nt = 5; + bytes nr = 6; + bytes ar = 7; + bytes at = 8; +} + +message ReadBlockRequest { + uint32 block = 1; + bytes key = 2; + KeyType key_type = 3; +} + +message ReadBlockResponse { + Error error = 1; + bytes data = 2; +} diff --git a/applications/main/nfc_rpc/nfc_rpc.c b/applications/main/nfc_rpc/nfc_rpc.c index 852875b05385..1e526b4b57b6 100644 --- a/applications/main/nfc_rpc/nfc_rpc.c +++ b/applications/main/nfc_rpc/nfc_rpc.c @@ -11,6 +11,10 @@ static const NfcRpcCallbacks nfc_rpc_callbacks[] = { .alloc = nfc_rpc_mf_ultralight_alloc, .free = NULL, }, + { + .alloc = nfc_rpc_mf_classic_alloc, + .free = NULL, + } }; uint32_t nfc_rpc_exit_callback(void* context) { @@ -51,7 +55,6 @@ static void nfc_rpc_rpc_command_callback(RpcAppSystemEvent event, void* context) if(event == RpcAppEventSessionClose) { rpc_system_app_set_callback(app->rpc, NULL, NULL); rpc_system_app_set_data_exchange_callback(app->rpc, NULL, NULL); - view_dispatcher_switch_to_view(app->view_dispatcher, VIEW_NONE); view_dispatcher_stop(app->view_dispatcher); app->rpc = NULL; } @@ -137,6 +140,7 @@ static NfcRpc* nfc_rpc_app_alloc() { instance->mf_ul_poller = mf_ultralight_poller_alloc(instance->nfca_poller); instance->nfca_listener = nfca_listener_alloc(instance->nfc); instance->mf_ul_listener = mf_ultralight_listener_alloc(instance->nfca_listener); + instance->mf_classic_poller = mf_classic_poller_alloc(instance->nfca_poller); NfcRpcHandlerDict_init(instance->handlers); for(size_t i = 0; i < COUNT_OF(nfc_rpc_callbacks); i++) { @@ -171,6 +175,7 @@ static NfcRpc* nfc_rpc_app_alloc() { void nfc_rpc_app_free(NfcRpc* instance) { furi_assert(instance); + mf_classic_poller_free(instance->mf_classic_poller); mf_ultralight_listener_free(instance->mf_ul_listener); mf_ultralight_poller_free(instance->mf_ul_poller); nfca_listener_free(instance->nfca_listener); diff --git a/applications/main/nfc_rpc/nfc_rpc_i.h b/applications/main/nfc_rpc/nfc_rpc_i.h index 2c3f0e058487..a39b19a5383d 100644 --- a/applications/main/nfc_rpc/nfc_rpc_i.h +++ b/applications/main/nfc_rpc/nfc_rpc_i.h @@ -20,6 +20,7 @@ #include #include #include +#include typedef void (*NfcRpcHandler)(Nfc_Main* cmd, void* context); @@ -59,6 +60,7 @@ struct NfcRpc { NfcaListener* nfca_listener; MfUltralightPoller* mf_ul_poller; MfUltralightListener* mf_ul_listener; + MfClassicPoller* mf_classic_poller; }; typedef struct { @@ -70,3 +72,4 @@ void nfc_rpc_add_handler(NfcRpc* instance, pb_size_t message_tag, NfcRpcHandler void nfc_rpc_nfca_alloc(void* context); void nfc_rpc_mf_ultralight_alloc(void* context); +void nfc_rpc_mf_classic_alloc(void* context); diff --git a/applications/main/nfc_rpc/nfc_rpc_mf_classic.c b/applications/main/nfc_rpc/nfc_rpc_mf_classic.c new file mode 100644 index 000000000000..88bc0785f7d0 --- /dev/null +++ b/applications/main/nfc_rpc/nfc_rpc_mf_classic.c @@ -0,0 +1,109 @@ +#include "nfc_rpc_i.h" + +#include "assets/compiled/mf_classic.pb.h" + +#define TAG "NfcRpcMfClassic" + +static PB_MfClassic_Error nfc_rpc_mf_classic_process_error(MfClassicError error) { + PB_MfClassic_Error ret = PB_MfClassic_Error_None; + + switch(error) { + case MfClassicErrorNone: + ret = PB_MfClassic_Error_None; + break; + case MfClassicErrorNotPresent: + ret = PB_MfClassic_Error_NotPresent; + break; + case MfClassicErrorProtocol: + ret = PB_MfClassic_Error_Protocol; + break; + case MfClassicErrorAuth: + ret = PB_MfClassic_Error_Auth; + break; + case MfClassicErrorTimeout: + ret = PB_MfClassic_Error_Timeout; + break; + + default: + ret = PB_MfClassic_Error_Timeout; + break; + } + + return ret; +} + +static void nfc_rpc_mf_classic_auth(Nfc_Main* cmd, void* context) { + furi_assert(cmd); + furi_assert(context); + + NfcRpc* instance = context; + PB_MfClassic_AuthResponse pb_mf_classic_auth_resp = PB_MfClassic_AuthResponse_init_default; + + PB_MfClassic_AuthRequest* req = &cmd->content.mf_classic_auth_req; + MfClassicAuthContext auth_context = {}; + MfClassicKey key = {}; + memcpy(key.data, req->key.bytes, sizeof(MfClassicKey)); + MfClassicKeyType key_type = + (req->key_type == PB_MfClassic_KeyType_KeyTypeB) ? MfClassicKeyTypeB : MfClassicKeyTypeA; + MfClassicError error = mf_classic_poller_auth( + instance->mf_classic_poller, req->block, &key, key_type, &auth_context); + + cmd->command_status = Nfc_CommandStatus_OK; + cmd->which_content = Nfc_Main_mf_classic_auth_resp_tag; + + pb_mf_classic_auth_resp.error = nfc_rpc_mf_classic_process_error(error); + if(pb_mf_classic_auth_resp.error == PB_MfClassic_Error_None) { + pb_mf_classic_auth_resp.block = auth_context.block_num; + memcpy(pb_mf_classic_auth_resp.key.bytes, auth_context.key.data, sizeof(MfClassicKey)); + pb_mf_classic_auth_resp.key.size = sizeof(MfClassicKey); + pb_mf_classic_auth_resp.key_type = (auth_context.key_type == MfClassicKeyTypeB) ? + PB_MfClassic_KeyType_KeyTypeB : + PB_MfClassic_KeyType_KeyTypeA; + memcpy(pb_mf_classic_auth_resp.nt.bytes, auth_context.nt.data, sizeof(MfClassicNt)); + pb_mf_classic_auth_resp.nt.size = sizeof(MfClassicNt); + memcpy(pb_mf_classic_auth_resp.nr.bytes, auth_context.nr.data, sizeof(MfClassicNr)); + pb_mf_classic_auth_resp.nr.size = sizeof(MfClassicNr); + memcpy(pb_mf_classic_auth_resp.ar.bytes, auth_context.ar.data, sizeof(MfClassicAr)); + pb_mf_classic_auth_resp.ar.size = sizeof(MfClassicAr); + memcpy(pb_mf_classic_auth_resp.at.bytes, auth_context.at.data, sizeof(MfClassicAt)); + pb_mf_classic_auth_resp.at.size = sizeof(MfClassicAt); + } + cmd->content.mf_classic_auth_resp = pb_mf_classic_auth_resp; +} + +static void nfc_rpc_mf_classic_read_block(Nfc_Main* cmd, void* context) { + furi_assert(cmd); + furi_assert(context); + + NfcRpc* instance = context; + PB_MfClassic_ReadBlockResponse pb_mf_classic_read_block_resp = + PB_MfClassic_ReadBlockResponse_init_default; + + PB_MfClassic_ReadBlockRequest* req = &cmd->content.mf_classic_read_block_req; + MfClassicKey key = {}; + memcpy(key.data, req->key.bytes, sizeof(MfClassicKey)); + MfClassicKeyType key_type = + (req->key_type == PB_MfClassic_KeyType_KeyTypeB) ? MfClassicKeyTypeB : MfClassicKeyTypeA; + MfClassicBlock block = {}; + MfClassicError error = mf_classic_poller_read_block( + instance->mf_classic_poller, req->block, &key, key_type, &block); + + cmd->command_status = Nfc_CommandStatus_OK; + cmd->which_content = Nfc_Main_mf_classic_read_block_resp_tag; + + pb_mf_classic_read_block_resp.error = nfc_rpc_mf_classic_process_error(error); + if(pb_mf_classic_read_block_resp.error == PB_MfClassic_Error_None) { + memcpy(pb_mf_classic_read_block_resp.data.bytes, block.data, sizeof(MfClassicBlock)); + pb_mf_classic_read_block_resp.data.size = sizeof(MfClassicBlock); + } + cmd->content.mf_classic_read_block_resp = pb_mf_classic_read_block_resp; +} + +void nfc_rpc_mf_classic_alloc(void* context) { + furi_assert(context); + + NfcRpc* instance = context; + nfc_rpc_add_handler(instance, Nfc_Main_mf_classic_auth_req_tag, nfc_rpc_mf_classic_auth); + nfc_rpc_add_handler( + instance, Nfc_Main_mf_classic_read_block_req_tag, nfc_rpc_mf_classic_read_block); +} diff --git a/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c b/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c index 574ae6b8a1f0..efaca6245324 100644 --- a/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c +++ b/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c @@ -1,7 +1,6 @@ #include "nfc_rpc_i.h" #include "assets/compiled/mf_ultralight.pb.h" -#include #define TAG "NfcRpcMfUltralight" diff --git a/lib/nfc/protocols/mf_classic/mf_classic.h b/lib/nfc/protocols/mf_classic/mf_classic.h index 91bb3db7cfcb..e08f3c77c510 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic.h +++ b/lib/nfc/protocols/mf_classic/mf_classic.h @@ -80,7 +80,7 @@ typedef struct { } MfClassicAr; typedef struct { - uint8_t sector_num; + uint8_t block_num; MfClassicKey key; MfClassicKeyType key_type; MfClassicNt nt; diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.c b/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.c index 9b9bceef0964..5af46e27b4f9 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.c @@ -10,9 +10,18 @@ MfClassicError mf_classic_poller_auth( MfClassicAuthContext* data) { furi_assert(instance); furi_assert(key); - UNUSED(block_num); - UNUSED(key_type); - UNUSED(data); + + if(data) { + data->block_num = block_num; + data->key = *key; + data->key_type = key_type; + for(size_t i = 0; i < 4; i++) { + data->nt.data[i] = 1; + data->nr.data[i] = 2; + data->at.data[i] = 3; + data->ar.data[i] = 4; + } + } return MfClassicErrorNone; } @@ -29,5 +38,11 @@ MfClassicError mf_classic_poller_read_block( UNUSED(block_num); UNUSED(key_type); + if(data) { + for(size_t i = 0; i < 16; i++) { + data->data[i] = i; + } + } + return MfClassicErrorNone; } \ No newline at end of file From faf28a102e0b4e0ac34d01f305e95ed98335f7c5 Mon Sep 17 00:00:00 2001 From: gornekich Date: Wed, 17 May 2023 12:40:57 +0400 Subject: [PATCH 087/149] mf classic: start auth --- lib/nfc/protocols/mf_classic/mf_classic.h | 3 + .../mf_classic/mf_classic_poller_i.c | 74 +++++++++++++++++++ .../mf_classic/mf_classic_poller_i.h | 19 ++++- .../mf_classic/mf_classic_poller_sync_api.c | 55 +++++++++++--- lib/nfc/protocols/nfca/nfca_poller_i.c | 4 + 5 files changed, 143 insertions(+), 12 deletions(-) diff --git a/lib/nfc/protocols/mf_classic/mf_classic.h b/lib/nfc/protocols/mf_classic/mf_classic.h index e08f3c77c510..4192a4a362f7 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic.h +++ b/lib/nfc/protocols/mf_classic/mf_classic.h @@ -6,6 +6,9 @@ extern "C" { #endif +#define MF_CLASSIC_AUTH_KEY_A_CMD (0x60U) +#define MF_CLASSIC_AUTH_KEY_B_CMD (0x61U) + #define MF_CLASSIC_TOTAL_BLOCKS_MAX (256) #define MF_CLASSIC_BLOCK_SIZE (16) #define MF_CLASSIC_KEY_SIZE (6) diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c index e69de29bb2d1..0ff370bdb219 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c @@ -0,0 +1,74 @@ +#include "mf_classic_poller_i.h" + +#include + +#define MF_CLASSIC_FWT_FC (60000) + +MfClassicError mf_classic_process_error(NfcaError error) { + MfClassicError ret = MfClassicErrorNone; + + switch(error) { + case NfcaErrorNone: + ret = MfClassicErrorNone; + break; + case NfcaErrorNotPresent: + ret = MfClassicErrorNotPresent; + break; + case NfcaErrorColResFailed: + case NfcaErrorCommunication: + case NfcaErrorWrongCrc: + ret = MfClassicErrorProtocol; + break; + case NfcaErrorTimeout: + ret = MfClassicErrorTimeout; + break; + default: + ret = MfClassicErrorProtocol; + break; + } + + return ret; +} + +MfClassicError mf_classic_async_auth( + MfClassicPoller* instance, + uint8_t block_num, + MfClassicKey* key, + MfClassicKeyType key_type, + MfClassicAuthContext* data) { + UNUSED(key); + NfcPollerBuffer* buff = instance->buffer; + MfClassicError ret = MfClassicErrorNone; + NfcaError error = NfcaErrorNone; + + uint8_t auth_cmd = (key_type == MfClassicKeyTypeB) ? MF_CLASSIC_AUTH_KEY_B_CMD : + MF_CLASSIC_AUTH_KEY_A_CMD; + buff->tx_data[0] = auth_cmd; + buff->tx_data[1] = block_num; + buff->tx_bits = 2 * 8; + + do { + error = nfca_poller_send_standart_frame( + instance->nfca_poller, + buff->tx_data, + buff->tx_bits, + buff->rx_data, + buff->rx_data_size, + &buff->rx_bits, + MF_CLASSIC_FWT_FC); + if(error != NfcaErrorWrongCrc) { + ret = mf_classic_process_error(error); + break; + } + if(buff->rx_bits != sizeof(MfClassicNt) * 8) { + ret = MfClassicErrorProtocol; + break; + } + memcpy(data->nt.data, buff->rx_data, sizeof(MfClassicNt)); + } while(false); + + return ret; +} + +MfClassicError + mf_classic_async_read_block(MfClassicPoller* instance, uint8_t block_num, MfClassicBlock* data); diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h index c522b18397fb..245b4109cd04 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h @@ -24,7 +24,7 @@ typedef enum { } MfClassicAuthState; typedef enum { - MfClassicPollerStateIdle, + MfClassicPollerStateIdle, } MfClassicPollerState; struct MfClassicPoller { @@ -37,6 +37,23 @@ struct MfClassicPoller { void* context; }; +typedef union { + MfClassicAuthContext auth_context; +} MfClassicPollerContextData; + + +MfClassicError mf_classic_process_error(NfcaError error); + +MfClassicError mf_classic_async_auth( + MfClassicPoller* instance, + uint8_t block_num, + MfClassicKey* key, + MfClassicKeyType key_type, + MfClassicAuthContext* data); + +MfClassicError + mf_classic_async_read_block(MfClassicPoller* instance, uint8_t block_num, MfClassicBlock* data); + #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.c b/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.c index 5af46e27b4f9..f730514d4a04 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.c @@ -2,6 +2,35 @@ #include +#define MF_CLASSIC_POLLER_COMPLETE_EVENT (1UL << 0) + +typedef struct { + MfClassicPoller* instance; + FuriThreadId thread_id; + MfClassicError error; + MfClassicPollerContextData data; +} MfClassicPollerContext; + +NfcaPollerCommand mf_classic_auth_callback(NfcaPollerEvent event, void* context) { + furi_assert(context); + + MfClassicPollerContext* poller_context = context; + MfClassicAuthContext* auth_context = &poller_context->data.auth_context; + if(event.type == NfcaPollerEventTypeReady) { + poller_context->error = mf_classic_async_auth( + poller_context->instance, + auth_context->block_num, + &auth_context->key, + auth_context->key_type, + auth_context); + } else if(event.type == NfcaPollerEventTypeError) { + poller_context->error = mf_classic_process_error(event.data.error); + } + furi_thread_flags_set(poller_context->thread_id, MF_CLASSIC_POLLER_COMPLETE_EVENT); + + return NfcaPollerCommandStop; +} + MfClassicError mf_classic_poller_auth( MfClassicPoller* instance, uint8_t block_num, @@ -10,20 +39,24 @@ MfClassicError mf_classic_poller_auth( MfClassicAuthContext* data) { furi_assert(instance); furi_assert(key); + furi_assert(data); - if(data) { - data->block_num = block_num; - data->key = *key; - data->key_type = key_type; - for(size_t i = 0; i < 4; i++) { - data->nt.data[i] = 1; - data->nr.data[i] = 2; - data->at.data[i] = 3; - data->ar.data[i] = 4; - } + MfClassicPollerContext poller_context = {}; + poller_context.data.auth_context.block_num = block_num; + poller_context.data.auth_context.key = *key; + poller_context.data.auth_context.key_type = key_type; + poller_context.instance = instance; + poller_context.thread_id = furi_thread_get_current_id(); + + mf_classic_poller_start(instance, mf_classic_auth_callback, &poller_context); + furi_thread_flags_wait(MF_CLASSIC_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); + + if(poller_context.error == MfClassicErrorNone) { + *data = poller_context.data.auth_context; } + mf_classic_poller_stop(instance); - return MfClassicErrorNone; + return poller_context.error; } MfClassicError mf_classic_poller_read_block( diff --git a/lib/nfc/protocols/nfca/nfca_poller_i.c b/lib/nfc/protocols/nfca/nfca_poller_i.c index 39ed01bc64b9..aee9415bc3ae 100644 --- a/lib/nfc/protocols/nfca/nfca_poller_i.c +++ b/lib/nfc/protocols/nfca/nfca_poller_i.c @@ -79,10 +79,14 @@ static NfcaError nfca_poller_standart_frame_exchange( ret = NfcaErrorBufferOverflow; break; } + if(!nfca_check_crc(buff->rx_data, rx_bytes)) { + memcpy(rx_data, buff->rx_data, rx_bytes); + *rx_bits = rx_bytes * 8; ret = NfcaErrorWrongCrc; break; } + memcpy(rx_data, buff->rx_data, rx_bytes - 2); *rx_bits = (rx_bytes - 2) * 8; } From d8601c74177212c9f403261b38e1f3f8544a505b Mon Sep 17 00:00:00 2001 From: gornekich Date: Wed, 17 May 2023 16:27:40 +0400 Subject: [PATCH 088/149] mf classic: rework auth --- firmware/targets/f7/api_symbols.csv | 103 ++++++------- firmware/targets/f7/furi_hal/f_hal_nfc.c | 38 +++++ firmware/targets/f7/furi_hal/f_hal_nfca.c | 5 + firmware/targets/furi_hal_include/f_hal_nfc.h | 2 + lib/nfc/helpers/nfc_poller_buffer.c | 10 +- lib/nfc/helpers/nfc_poller_buffer.h | 2 + lib/nfc/nfc.c | 47 ++++++ lib/nfc/nfc.h | 9 ++ lib/nfc/protocols/mf_classic/crypto.h | 11 -- lib/nfc/protocols/mf_classic/crypto1.c | 141 ++++++++++++++++++ lib/nfc/protocols/mf_classic/crypto1.h | 49 ++++++ .../protocols/mf_classic/mf_classic_poller.c | 2 + .../mf_classic/mf_classic_poller_i.c | 60 ++++++++ .../mf_classic/mf_classic_poller_i.h | 7 +- lib/nfc/protocols/nfca/nfca_poller_i.c | 106 +++++++++++++ lib/nfc/protocols/nfca/nfca_poller_i.h | 11 ++ 16 files changed, 535 insertions(+), 68 deletions(-) delete mode 100644 lib/nfc/protocols/mf_classic/crypto.h create mode 100644 lib/nfc/protocols/mf_classic/crypto1.c create mode 100644 lib/nfc/protocols/mf_classic/crypto1.h diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 7e8a6d64c1ed..145af1dbd2d4 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,+,26.2,, +Version,+,26.3,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -152,6 +152,7 @@ Header,+,lib/one_wire/maxim_crc.h,, Header,+,lib/one_wire/one_wire_host.h,, Header,+,lib/one_wire/one_wire_slave.h,, Header,+,lib/print/wrappers.h,, +Header,+,lib/pulse_reader/pulse_reader.h,, Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_adc.h,, Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_bus.h,, Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_comp.h,, @@ -179,7 +180,6 @@ Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_tim.h,, Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_usart.h,, Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_utils.h,, Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_wwdg.h,, -Header,+,lib/pulse_reader/pulse_reader.h,, Header,+,lib/subghz/blocks/const.h,, Header,+,lib/subghz/blocks/decoder.h,, Header,+,lib/subghz/blocks/encoder.h,, @@ -706,14 +706,6 @@ Function,-,coshl,long double,long double Function,-,cosl,long double,long double Function,+,crc32_calc_buffer,uint32_t,"uint32_t, const void*, size_t" Function,+,crc32_calc_file,uint32_t,"File*, const FileCrcProgressCb, void*" -Function,-,old_crypto1_bit,uint8_t,"Crypto1*, uint8_t, int" -Function,-,old_crypto1_byte,uint8_t,"Crypto1*, uint8_t, int" -Function,-,old_crypto1_decrypt,void,"Crypto1*, uint8_t*, uint16_t, uint8_t*" -Function,-,old_crypto1_encrypt,void,"Crypto1*, uint8_t*, uint8_t*, uint16_t, uint8_t*, uint8_t*" -Function,-,old_crypto1_filter,uint32_t,uint32_t -Function,-,old_crypto1_init,void,"Crypto1*, uint64_t" -Function,-,old_crypto1_reset,void,Crypto1* -Function,-,old_crypto1_word,uint32_t,"Crypto1*, uint32_t, int" Function,-,ctermid,char*,char* Function,-,ctime,char*,const time_t* Function,-,ctime_r,char*,"const time_t*, char*" @@ -844,6 +836,7 @@ Function,-,f_hal_nfc_low_power_mode_stop,FHalNfcError, Function,-,f_hal_nfc_poller_field_on,FHalNfcError, Function,-,f_hal_nfc_poller_rx,FHalNfcError,"uint8_t*, uint16_t, uint16_t*" Function,-,f_hal_nfc_poller_tx,FHalNfcError,"uint8_t*, uint16_t" +Function,-,f_hal_nfc_poller_tx_custom_parity,FHalNfcError,"uint8_t*, uint16_t" Function,-,f_hal_nfc_release,FHalNfcError, Function,-,f_hal_nfc_reset_mode,FHalNfcError, Function,-,f_hal_nfc_set_mask_receive_timer,void,uint32_t @@ -1956,13 +1949,6 @@ Function,+,menu_free,void,Menu* Function,+,menu_get_view,View*,Menu* Function,+,menu_reset,void,Menu* Function,+,menu_set_selected_item,void,"Menu*, uint32_t" -Function,-,mifare_classic_auth_attempt,_Bool,"FuriHalNfcTxRxContext*, Crypto1*, MfClassicAuthContext*, uint64_t" -Function,-,mifare_classic_auth_init_context,void,"MfClassicAuthContext*, uint8_t" -Function,-,mifare_classic_auth_write_block,_Bool,"FuriHalNfcTxRxContext*, MfClassicBlock*, uint8_t, MfClassicKey, uint64_t" -Function,-,mifare_classic_authenticate,_Bool,"FuriHalNfcTxRxContext*, uint8_t, uint64_t, MfClassicKey" -Function,-,mifare_classic_authenticate_skip_activate,_Bool,"FuriHalNfcTxRxContext*, uint8_t, uint64_t, MfClassicKey, _Bool, uint32_t" -Function,-,mifare_classic_block_to_value,_Bool,"const uint8_t*, int32_t*, uint8_t*" -Function,-,mifare_classic_check_card_type,_Bool,"uint8_t, uint8_t, uint8_t" Function,-,mf_classic_dict_add_key,_Bool,"MfClassicDict*, uint8_t*" Function,-,mf_classic_dict_add_key_str,_Bool,"MfClassicDict*, FuriString*" Function,-,mf_classic_dict_alloc,MfClassicDict*,MfClassicDictType @@ -1979,40 +1965,7 @@ Function,-,mf_classic_dict_get_total_keys,uint32_t,MfClassicDict* Function,-,mf_classic_dict_is_key_present,_Bool,"MfClassicDict*, uint8_t*" Function,-,mf_classic_dict_is_key_present_str,_Bool,"MfClassicDict*, FuriString*" Function,-,mf_classic_dict_rewind,_Bool,MfClassicDict* -Function,-,mifare_classic_emulator,_Bool,"MfClassicEmulator*, FuriHalNfcTxRxContext*" -Function,-,mifare_classic_get_classic_type,MfClassicType,"uint8_t, uint8_t, uint8_t" -Function,-,mifare_classic_get_read_sectors_and_keys,void,"MfClassicData*, uint8_t*, uint8_t*" -Function,-,mifare_classic_get_sector_by_block,uint8_t,uint8_t -Function,-,mifare_classic_get_sector_trailer_block_num_by_sector,uint8_t,uint8_t -Function,-,mifare_classic_get_sector_trailer_by_sector,MfClassicSectorTrailer*,"MfClassicData*, uint8_t" -Function,-,mifare_classic_get_total_block_num,uint16_t,MfClassicType -Function,-,mifare_classic_get_total_sectors_num,uint8_t,MfClassicType -Function,-,mifare_classic_get_type_str,const char*,MfClassicType -Function,-,mifare_classic_halt,void,"FuriHalNfcTxRxContext*, Crypto1*" -Function,-,mifare_classic_is_allowed_access_data_block,_Bool,"MfClassicData*, uint8_t, MfClassicKey, MfClassicAction" Function,-,mf_classic_is_allowed_access_sector_trailer,_Bool,"MfClassicData*, uint8_t, MfClassicKey, MfClassicAction" -Function,-,mifare_classic_is_block_read,_Bool,"MfClassicData*, uint8_t" -Function,-,mifare_classic_is_card_read,_Bool,MfClassicData* -Function,-,mifare_classic_is_key_found,_Bool,"MfClassicData*, uint8_t, MfClassicKey" -Function,-,mifare_classic_is_sector_data_read,_Bool,"MfClassicData*, uint8_t" -Function,-,mifare_classic_is_sector_read,_Bool,"MfClassicData*, uint8_t" -Function,-,mifare_classic_is_sector_trailer,_Bool,uint8_t -Function,-,mifare_classic_is_value_block,_Bool,"MfClassicData*, uint8_t" -Function,-,mifare_classic_read_block,_Bool,"FuriHalNfcTxRxContext*, Crypto1*, uint8_t, MfClassicBlock*" -Function,-,mifare_classic_read_card,uint8_t,"FuriHalNfcTxRxContext*, MfClassicReader*, MfClassicData*" -Function,-,mifare_classic_read_sector,void,"FuriHalNfcTxRxContext*, MfClassicData*, uint8_t" -Function,-,mifare_classic_reader_add_sector,void,"MfClassicReader*, uint8_t, uint64_t, uint64_t" -Function,-,mifare_classic_set_block_read,void,"MfClassicData*, uint8_t, MfClassicBlock*" -Function,-,mifare_classic_set_key_found,void,"MfClassicData*, uint8_t, MfClassicKey, uint64_t" -Function,-,mifare_classic_set_key_not_found,void,"MfClassicData*, uint8_t, MfClassicKey" -Function,-,mifare_classic_set_sector_data_not_read,void,MfClassicData* -Function,-,mifare_classic_transfer,_Bool,"FuriHalNfcTxRxContext*, Crypto1*, uint8_t" -Function,-,mifare_classic_update_card,uint8_t,"FuriHalNfcTxRxContext*, MfClassicData*" -Function,-,mifare_classic_value_cmd,_Bool,"FuriHalNfcTxRxContext*, Crypto1*, uint8_t, uint8_t, int32_t" -Function,-,mifare_classic_value_cmd_full,_Bool,"FuriHalNfcTxRxContext*, MfClassicBlock*, uint8_t, MfClassicKey, uint64_t, int32_t" -Function,-,mifare_classic_value_to_block,void,"int32_t, uint8_t, uint8_t*" -Function,-,mifare_classic_write_block,_Bool,"FuriHalNfcTxRxContext*, Crypto1*, uint8_t, MfClassicBlock*" -Function,-,mifare_classic_write_sector,_Bool,"FuriHalNfcTxRxContext*, MfClassicData*, MfClassicData*, uint8_t" Function,-,mf_df_cat_application,void,"MifareDesfireApplication*, FuriString*" Function,-,mf_df_cat_application_info,void,"MifareDesfireApplication*, FuriString*" Function,-,mf_df_cat_card_info,void,"MifareDesfireData*, FuriString*" @@ -2062,6 +2015,46 @@ Function,-,mf_ultralight_read_pages_direct,_Bool,"FuriHalNfcTxRxContext*, uint8_ Function,-,mf_ultralight_read_signature,_Bool,"FuriHalNfcTxRxContext*, MfUltralightData*" Function,-,mf_ultralight_read_tearing_flags,_Bool,"FuriHalNfcTxRxContext*, MfUltralightData*" Function,-,mf_ultralight_read_version,_Bool,"FuriHalNfcTxRxContext*, MfUltralightReader*, MfUltralightData*" +Function,-,mifare_classic_auth_attempt,_Bool,"FuriHalNfcTxRxContext*, Crypto1*, MfClassicAuthContext*, uint64_t" +Function,-,mifare_classic_auth_init_context,void,"MfClassicAuthContext*, uint8_t" +Function,-,mifare_classic_auth_write_block,_Bool,"FuriHalNfcTxRxContext*, MfClassicBlock*, uint8_t, MfClassicKey, uint64_t" +Function,-,mifare_classic_authenticate,_Bool,"FuriHalNfcTxRxContext*, uint8_t, uint64_t, MfClassicKey" +Function,-,mifare_classic_authenticate_skip_activate,_Bool,"FuriHalNfcTxRxContext*, uint8_t, uint64_t, MfClassicKey, _Bool, uint32_t" +Function,-,mifare_classic_block_to_value,_Bool,"const uint8_t*, int32_t*, uint8_t*" +Function,-,mifare_classic_check_card_type,_Bool,"uint8_t, uint8_t, uint8_t" +Function,-,mifare_classic_emulator,_Bool,"MfClassicEmulator*, FuriHalNfcTxRxContext*" +Function,-,mifare_classic_get_classic_type,MfClassicType,"uint8_t, uint8_t, uint8_t" +Function,-,mifare_classic_get_read_sectors_and_keys,void,"MfClassicData*, uint8_t*, uint8_t*" +Function,-,mifare_classic_get_sector_by_block,uint8_t,uint8_t +Function,-,mifare_classic_get_sector_trailer_block_num_by_sector,uint8_t,uint8_t +Function,-,mifare_classic_get_sector_trailer_by_sector,MfClassicSectorTrailer*,"MfClassicData*, uint8_t" +Function,-,mifare_classic_get_total_block_num,uint16_t,MfClassicType +Function,-,mifare_classic_get_total_sectors_num,uint8_t,MfClassicType +Function,-,mifare_classic_get_type_str,const char*,MfClassicType +Function,-,mifare_classic_halt,void,"FuriHalNfcTxRxContext*, Crypto1*" +Function,-,mifare_classic_is_allowed_access_data_block,_Bool,"MfClassicData*, uint8_t, MfClassicKey, MfClassicAction" +Function,-,mifare_classic_is_block_read,_Bool,"MfClassicData*, uint8_t" +Function,-,mifare_classic_is_card_read,_Bool,MfClassicData* +Function,-,mifare_classic_is_key_found,_Bool,"MfClassicData*, uint8_t, MfClassicKey" +Function,-,mifare_classic_is_sector_data_read,_Bool,"MfClassicData*, uint8_t" +Function,-,mifare_classic_is_sector_read,_Bool,"MfClassicData*, uint8_t" +Function,-,mifare_classic_is_sector_trailer,_Bool,uint8_t +Function,-,mifare_classic_is_value_block,_Bool,"MfClassicData*, uint8_t" +Function,-,mifare_classic_read_block,_Bool,"FuriHalNfcTxRxContext*, Crypto1*, uint8_t, MfClassicBlock*" +Function,-,mifare_classic_read_card,uint8_t,"FuriHalNfcTxRxContext*, MfClassicReader*, MfClassicData*" +Function,-,mifare_classic_read_sector,void,"FuriHalNfcTxRxContext*, MfClassicData*, uint8_t" +Function,-,mifare_classic_reader_add_sector,void,"MfClassicReader*, uint8_t, uint64_t, uint64_t" +Function,-,mifare_classic_set_block_read,void,"MfClassicData*, uint8_t, MfClassicBlock*" +Function,-,mifare_classic_set_key_found,void,"MfClassicData*, uint8_t, MfClassicKey, uint64_t" +Function,-,mifare_classic_set_key_not_found,void,"MfClassicData*, uint8_t, MfClassicKey" +Function,-,mifare_classic_set_sector_data_not_read,void,MfClassicData* +Function,-,mifare_classic_transfer,_Bool,"FuriHalNfcTxRxContext*, Crypto1*, uint8_t" +Function,-,mifare_classic_update_card,uint8_t,"FuriHalNfcTxRxContext*, MfClassicData*" +Function,-,mifare_classic_value_cmd,_Bool,"FuriHalNfcTxRxContext*, Crypto1*, uint8_t, uint8_t, int32_t" +Function,-,mifare_classic_value_cmd_full,_Bool,"FuriHalNfcTxRxContext*, MfClassicBlock*, uint8_t, MfClassicKey, uint64_t, int32_t" +Function,-,mifare_classic_value_to_block,void,"int32_t, uint8_t, uint8_t*" +Function,-,mifare_classic_write_block,_Bool,"FuriHalNfcTxRxContext*, Crypto1*, uint8_t, MfClassicBlock*" +Function,-,mifare_classic_write_sector,_Bool,"FuriHalNfcTxRxContext*, MfClassicData*, MfClassicData*, uint8_t" Function,-,mkdtemp,char*,char* Function,-,mkostemp,int,"char*, int" Function,-,mkostemps,int,"char*, int, int" @@ -2109,6 +2102,15 @@ Function,+,notification_internal_message_block,void,"NotificationApp*, const Not Function,+,notification_message,void,"NotificationApp*, const NotificationSequence*" Function,+,notification_message_block,void,"NotificationApp*, const NotificationSequence*" Function,-,nrand48,long,unsigned short[3] +Function,-,old_crypto1_bit,uint8_t,"Crypto1*, uint8_t, int" +Function,-,old_crypto1_byte,uint8_t,"Crypto1*, uint8_t, int" +Function,-,old_crypto1_decrypt,void,"Crypto1*, uint8_t*, uint16_t, uint8_t*" +Function,-,old_crypto1_encrypt,void,"Crypto1*, uint8_t*, uint8_t*, uint16_t, uint8_t*, uint8_t*" +Function,-,old_crypto1_filter,uint32_t,uint32_t +Function,-,old_crypto1_init,void,"Crypto1*, uint64_t" +Function,-,old_crypto1_reset,void,Crypto1* +Function,-,old_crypto1_word,uint32_t,"Crypto1*, uint32_t, int" +Function,-,old_prng_successor,uint32_t,"uint32_t, uint32_t" Function,-,on_exit,int,"void (*)(int, void*), void*" Function,+,onewire_host_alloc,OneWireHost*,const GpioPin* Function,+,onewire_host_free,void,OneWireHost* @@ -2219,7 +2221,6 @@ Function,+,powf,float,"float, float" Function,-,powl,long double,"long double, long double" Function,+,pretty_format_bytes_hex_canonical,void,"FuriString*, size_t, const char*, const uint8_t*, size_t" Function,-,printf,int,"const char*, ..." -Function,-,old_prng_successor,uint32_t,"uint32_t, uint32_t" Function,+,property_value_out,void,"PropertyValueContext*, const char*, unsigned int, ..." Function,+,protocol_dict_alloc,ProtocolDict*,"const ProtocolBase**, size_t" Function,+,protocol_dict_decoders_feed,ProtocolId,"ProtocolDict*, _Bool, uint32_t" diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc.c b/firmware/targets/f7/furi_hal/f_hal_nfc.c index 3d05d46cfcf4..e2a79e92f3c1 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfc.c +++ b/firmware/targets/f7/furi_hal/f_hal_nfc.c @@ -404,6 +404,39 @@ FHalNfcError f_hal_nfc_poller_field_on() { return error; } +FHalNfcError f_hal_nfc_poller_tx_custom_parity(uint8_t* tx_data, uint16_t tx_bits) { + furi_assert(tx_data); + + // TODO common code for f_hal_nfc_poller_tx + + FHalNfcError err = FHalNfcErrorNone; + FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; + furi_hal_spi_acquire(handle); + + // Prepare tx + st25r3916_direct_cmd(handle, ST25R3916_CMD_CLEAR_FIFO); + st25r3916_clear_reg_bits( + handle, ST25R3916_REG_TIMER_EMV_CONTROL, ST25R3916_REG_TIMER_EMV_CONTROL_nrt_emv); + st25r3916_change_reg_bits( + handle, + ST25R3916_REG_ISO14443A_NFC, + (ST25R3916_REG_ISO14443A_NFC_no_tx_par | ST25R3916_REG_ISO14443A_NFC_no_rx_par), + (ST25R3916_REG_ISO14443A_NFC_no_tx_par | ST25R3916_REG_ISO14443A_NFC_no_rx_par)); + uint32_t interrupts = + (ST25R3916_IRQ_MASK_FWL | ST25R3916_IRQ_MASK_TXE | ST25R3916_IRQ_MASK_RXS | + ST25R3916_IRQ_MASK_RXE | ST25R3916_IRQ_MASK_PAR | ST25R3916_IRQ_MASK_CRC | + ST25R3916_IRQ_MASK_ERR1 | ST25R3916_IRQ_MASK_ERR2 | ST25R3916_IRQ_MASK_NRE); + // Clear interrupts + st25r3916_get_irq(handle); + // Enable interrupts + st25r3916_mask_irq(handle, ~interrupts); + + st25r3916_write_fifo(handle, tx_data, tx_bits); + st25r3916_direct_cmd(handle, ST25R3916_CMD_TRANSMIT_WITHOUT_CRC); + furi_hal_spi_release(handle); + return err; +} + FHalNfcError f_hal_nfc_poller_tx(uint8_t* tx_data, uint16_t tx_bits) { furi_assert(tx_data); @@ -415,6 +448,11 @@ FHalNfcError f_hal_nfc_poller_tx(uint8_t* tx_data, uint16_t tx_bits) { st25r3916_direct_cmd(handle, ST25R3916_CMD_CLEAR_FIFO); st25r3916_clear_reg_bits( handle, ST25R3916_REG_TIMER_EMV_CONTROL, ST25R3916_REG_TIMER_EMV_CONTROL_nrt_emv); + st25r3916_change_reg_bits( + handle, + ST25R3916_REG_ISO14443A_NFC, + (ST25R3916_REG_ISO14443A_NFC_no_tx_par | ST25R3916_REG_ISO14443A_NFC_no_rx_par), + (ST25R3916_REG_ISO14443A_NFC_no_tx_par_off | ST25R3916_REG_ISO14443A_NFC_no_rx_par_off)); uint32_t interrupts = (ST25R3916_IRQ_MASK_FWL | ST25R3916_IRQ_MASK_TXE | ST25R3916_IRQ_MASK_RXS | ST25R3916_IRQ_MASK_RXE | ST25R3916_IRQ_MASK_PAR | ST25R3916_IRQ_MASK_CRC | diff --git a/firmware/targets/f7/furi_hal/f_hal_nfca.c b/firmware/targets/f7/furi_hal/f_hal_nfca.c index c35102bb4110..fcd514ef0540 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfca.c +++ b/firmware/targets/f7/furi_hal/f_hal_nfca.c @@ -14,6 +14,11 @@ FHalNfcError f_hal_nfca_send_short_frame(FHalNfcaShortFrame frame) { // Disable crc check st25r3916_set_reg_bits(handle, ST25R3916_REG_AUX, ST25R3916_REG_AUX_no_crc_rx); + st25r3916_change_reg_bits( + handle, + ST25R3916_REG_ISO14443A_NFC, + (ST25R3916_REG_ISO14443A_NFC_no_tx_par | ST25R3916_REG_ISO14443A_NFC_no_rx_par), + (ST25R3916_REG_ISO14443A_NFC_no_tx_par_off | ST25R3916_REG_ISO14443A_NFC_no_rx_par_off)); st25r3916_write_reg(handle, ST25R3916_REG_NUM_TX_BYTES2, 0); uint32_t interrupts = diff --git a/firmware/targets/furi_hal_include/f_hal_nfc.h b/firmware/targets/furi_hal_include/f_hal_nfc.h index 912b84ffc898..4fa83dcfe52a 100644 --- a/firmware/targets/furi_hal_include/f_hal_nfc.h +++ b/firmware/targets/furi_hal_include/f_hal_nfc.h @@ -112,6 +112,8 @@ FHalNfcError f_hal_nfc_event_start(); FHalNfcError f_hal_nfc_poller_tx(uint8_t* tx_data, uint16_t tx_bits); +FHalNfcError f_hal_nfc_poller_tx_custom_parity(uint8_t* tx_data, uint16_t tx_bits); + FHalNfcError f_hal_nfc_poller_rx(uint8_t* rx_data, uint16_t rx_data_size, uint16_t* rx_bits); FHalNfcError f_hal_nfc_listener_tx(uint8_t* tx_data, uint16_t tx_bits); diff --git a/lib/nfc/helpers/nfc_poller_buffer.c b/lib/nfc/helpers/nfc_poller_buffer.c index ea0bb251deb5..9d2a5d46d74f 100644 --- a/lib/nfc/helpers/nfc_poller_buffer.c +++ b/lib/nfc/helpers/nfc_poller_buffer.c @@ -5,8 +5,10 @@ NfcPollerBuffer* nfc_poller_buffer_alloc(uint16_t tx_bytes_max, uint16_t rx_bytes_max) { NfcPollerBuffer* instance = malloc(sizeof(NfcPollerBuffer)); instance->tx_data = malloc(tx_bytes_max); + instance->tx_parity = malloc((tx_bytes_max + 7) / 8); instance->tx_data_size = tx_bytes_max; instance->rx_data = malloc(rx_bytes_max); + instance->rx_parity = malloc((rx_bytes_max + 7) / 8); instance->rx_data_size = rx_bytes_max; return instance; @@ -16,9 +18,11 @@ void nfc_poller_buffer_free(NfcPollerBuffer* instance) { furi_assert(instance); furi_assert(instance->tx_data); furi_assert(instance->rx_data); - + free(instance->tx_data); + free(instance->tx_parity); free(instance->rx_data); + free(instance->rx_parity); free(instance); } @@ -26,9 +30,11 @@ void nfc_poller_buffer_reset(NfcPollerBuffer* instance) { furi_assert(instance); furi_assert(instance->tx_data); furi_assert(instance->rx_data); - + memset(instance->tx_data, 0, instance->tx_data_size); + memset(instance->tx_parity, 0, (instance->tx_data_size + 7) / 8); memset(instance->rx_data, 0, instance->rx_data_size); + memset(instance->rx_parity, 0, (instance->rx_data_size + 7) / 8); instance->tx_bits = 0; instance->rx_bits = 0; } diff --git a/lib/nfc/helpers/nfc_poller_buffer.h b/lib/nfc/helpers/nfc_poller_buffer.h index 3f7e245053f8..5d2423fea4c6 100644 --- a/lib/nfc/helpers/nfc_poller_buffer.h +++ b/lib/nfc/helpers/nfc_poller_buffer.h @@ -8,9 +8,11 @@ extern "C" { typedef struct { uint8_t* tx_data; + uint8_t* tx_parity; uint16_t tx_data_size; uint16_t tx_bits; uint8_t* rx_data; + uint8_t* rx_parity; uint16_t rx_data_size; uint16_t rx_bits; } NfcPollerBuffer; diff --git a/lib/nfc/nfc.c b/lib/nfc/nfc.c index 73ae2b439669..4cb24764eb4e 100644 --- a/lib/nfc/nfc.c +++ b/lib/nfc/nfc.c @@ -414,6 +414,52 @@ static NfcError nfc_poller_prepare_trx(Nfc* instance) { return ret; } +NfcError nfc_trx_custom_parity( + Nfc* instance, + uint8_t* tx_data, + uint16_t tx_bits, + uint8_t* rx_data, + uint16_t rx_data_size, + uint16_t* rx_bits, + uint32_t fwt) { + furi_assert(instance); + furi_assert(tx_data); + furi_assert(rx_data); + furi_assert(rx_bits); + + furi_assert(instance->state == NfcStateFieldOn); + + NfcError ret = NfcErrorNone; + FHalNfcError error = FHalNfcErrorNone; + do { + ret = nfc_poller_prepare_trx(instance); + if(ret != NfcErrorNone) { + FURI_LOG_E(TAG, "Failed in prepare tx rx"); + break; + } + error = f_hal_nfc_poller_tx_custom_parity(tx_data, tx_bits); + if(error != FHalNfcErrorNone) { + FURI_LOG_E(TAG, "Failed in poller TX"); + ret = nfc_process_hal_error(error); + break; + } + instance->comm_state = NfcCommStateWaitTxEnd; + ret = nfc_poller_trx_state_machine(instance, fwt); + if(ret != NfcErrorNone) { + FURI_LOG_E(TAG, "Failed TRX state machine"); + break; + } + error = f_hal_nfc_poller_rx(rx_data, rx_data_size, rx_bits); + if(error != FHalNfcErrorNone) { + FURI_LOG_E(TAG, "Failed in poller RX"); + ret = nfc_process_hal_error(error); + break; + } + } while(false); + + return ret; +} + NfcError nfc_trx( Nfc* instance, uint8_t* tx_data, @@ -423,6 +469,7 @@ NfcError nfc_trx( uint16_t* rx_bits, uint32_t fwt) { furi_assert(instance); + furi_assert(tx_data); furi_assert(rx_data); furi_assert(rx_bits); diff --git a/lib/nfc/nfc.h b/lib/nfc/nfc.h index 94b982999f1b..69b144e16f53 100644 --- a/lib/nfc/nfc.h +++ b/lib/nfc/nfc.h @@ -106,6 +106,15 @@ void nfc_stop(Nfc* instance); NfcError nfc_listener_tx(Nfc* instance, uint8_t* tx_data, uint16_t tx_bits); +NfcError nfc_trx_custom_parity( + Nfc* instance, + uint8_t* tx_data, + uint16_t tx_bits, + uint8_t* rx_data, + uint16_t rx_data_size, + uint16_t* rx_bits, + uint32_t fwt); + NfcError nfc_trx( Nfc* instance, uint8_t* tx_data, diff --git a/lib/nfc/protocols/mf_classic/crypto.h b/lib/nfc/protocols/mf_classic/crypto.h deleted file mode 100644 index b9363460d11b..000000000000 --- a/lib/nfc/protocols/mf_classic/crypto.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - - - -#ifdef __cplusplus -} -#endif diff --git a/lib/nfc/protocols/mf_classic/crypto1.c b/lib/nfc/protocols/mf_classic/crypto1.c new file mode 100644 index 000000000000..77034c314467 --- /dev/null +++ b/lib/nfc/protocols/mf_classic/crypto1.c @@ -0,0 +1,141 @@ +#include "crypto1.h" + +#include +#include + +// Algorithm from https://github.com/RfidResearchGroup/proxmark3.git + +#define SWAPENDIAN(x) \ + ((x) = ((x) >> 8 & 0xff00ff) | ((x)&0xff00ff) << 8, (x) = (x) >> 16 | (x) << 16) +#define LF_POLY_ODD (0x29CE5C) +#define LF_POLY_EVEN (0x870804) + +#define BEBIT(x, n) FURI_BIT(x, (n) ^ 24) + +Crypto1* crypto1_alloc() { + Crypto1* instance = malloc(sizeof(Crypto1)); + + return instance; +} + +void crypto1_free(Crypto1* instance) { + furi_assert(instance); + + free(instance); +} + +void crypto1_reset(Crypto1* crypto1) { + furi_assert(crypto1); + crypto1->even = 0; + crypto1->odd = 0; +} + +void crypto1_init(Crypto1* crypto1, uint64_t key) { + furi_assert(crypto1); + crypto1->even = 0; + crypto1->odd = 0; + for(int8_t i = 47; i > 0; i -= 2) { + crypto1->odd = crypto1->odd << 1 | FURI_BIT(key, (i - 1) ^ 7); + crypto1->even = crypto1->even << 1 | FURI_BIT(key, i ^ 7); + } +} + +uint32_t crypto1_filter(uint32_t in) { + uint32_t out = 0; + out = 0xf22c0 >> (in & 0xf) & 16; + out |= 0x6c9c0 >> (in >> 4 & 0xf) & 8; + out |= 0x3c8b0 >> (in >> 8 & 0xf) & 4; + out |= 0x1e458 >> (in >> 12 & 0xf) & 2; + out |= 0x0d938 >> (in >> 16 & 0xf) & 1; + return FURI_BIT(0xEC57E80A, out); +} + +uint8_t crypto1_bit(Crypto1* crypto1, uint8_t in, int is_encrypted) { + furi_assert(crypto1); + uint8_t out = crypto1_filter(crypto1->odd); + uint32_t feed = out & (!!is_encrypted); + feed ^= !!in; + feed ^= LF_POLY_ODD & crypto1->odd; + feed ^= LF_POLY_EVEN & crypto1->even; + crypto1->even = crypto1->even << 1 | (nfc_util_even_parity32(feed)); + + FURI_SWAP(crypto1->odd, crypto1->even); + return out; +} + +uint8_t crypto1_byte(Crypto1* crypto1, uint8_t in, int is_encrypted) { + furi_assert(crypto1); + uint8_t out = 0; + for(uint8_t i = 0; i < 8; i++) { + out |= crypto1_bit(crypto1, FURI_BIT(in, i), is_encrypted) << i; + } + return out; +} + +uint32_t crypto1_word(Crypto1* crypto1, uint32_t in, int is_encrypted) { + furi_assert(crypto1); + uint32_t out = 0; + for(uint8_t i = 0; i < 32; i++) { + out |= crypto1_bit(crypto1, BEBIT(in, i), is_encrypted) << (24 ^ i); + } + return out; +} + +uint32_t prng_successor(uint32_t x, uint32_t n) { + SWAPENDIAN(x); + while(n--) x = x >> 1 | (x >> 16 ^ x >> 18 ^ x >> 19 ^ x >> 21) << 31; + + return SWAPENDIAN(x); +} + +void crypto1_decrypt( + Crypto1* crypto, + uint8_t* encrypted_data, + uint16_t encrypted_data_bits, + uint8_t* decrypted_data) { + furi_assert(crypto); + furi_assert(encrypted_data); + furi_assert(decrypted_data); + + if(encrypted_data_bits < 8) { + uint8_t decrypted_byte = 0; + decrypted_byte |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(encrypted_data[0], 0)) << 0; + decrypted_byte |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(encrypted_data[0], 1)) << 1; + decrypted_byte |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(encrypted_data[0], 2)) << 2; + decrypted_byte |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(encrypted_data[0], 3)) << 3; + decrypted_data[0] = decrypted_byte; + } else { + for(size_t i = 0; i < encrypted_data_bits / 8; i++) { + decrypted_data[i] = crypto1_byte(crypto, 0, 0) ^ encrypted_data[i]; + } + } +} + +void crypto1_encrypt( + Crypto1* crypto, + uint8_t* keystream, + uint8_t* plain_data, + uint16_t plain_data_bits, + uint8_t* encrypted_data, + uint8_t* encrypted_parity) { + furi_assert(crypto); + furi_assert(plain_data); + furi_assert(encrypted_data); + furi_assert(encrypted_parity); + + if(plain_data_bits < 8) { + encrypted_data[0] = 0; + for(size_t i = 0; i < plain_data_bits; i++) { + encrypted_data[0] |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(plain_data[0], i)) << i; + } + } else { + memset(encrypted_parity, 0, plain_data_bits / 8 + 1); + for(uint8_t i = 0; i < plain_data_bits / 8; i++) { + encrypted_data[i] = crypto1_byte(crypto, keystream ? keystream[i] : 0, 0) ^ + plain_data[i]; + encrypted_parity[i / 8] |= + (((crypto1_filter(crypto->odd) ^ nfc_util_odd_parity8(plain_data[i])) & 0x01) + << (7 - (i & 0x0007))); + } + } +} diff --git a/lib/nfc/protocols/mf_classic/crypto1.h b/lib/nfc/protocols/mf_classic/crypto1.h new file mode 100644 index 000000000000..eaa636f0cfb7 --- /dev/null +++ b/lib/nfc/protocols/mf_classic/crypto1.h @@ -0,0 +1,49 @@ +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + uint32_t odd; + uint32_t even; +} Crypto1; + +Crypto1* crypto1_alloc(); + +void crypto1_free(Crypto1* instance); + +void crypto1_reset(Crypto1* crypto1); + +void crypto1_init(Crypto1* crypto1, uint64_t key); + +uint8_t crypto1_bit(Crypto1* crypto1, uint8_t in, int is_encrypted); + +uint8_t crypto1_byte(Crypto1* crypto1, uint8_t in, int is_encrypted); + +uint32_t crypto1_word(Crypto1* crypto1, uint32_t in, int is_encrypted); + +uint32_t crypto1_filter(uint32_t in); + +uint32_t prng_successor(uint32_t x, uint32_t n); + +void crypto1_decrypt( + Crypto1* crypto, + uint8_t* encrypted_data, + uint16_t encrypted_data_bits, + uint8_t* decrypted_data); + +void crypto1_encrypt( + Crypto1* crypto, + uint8_t* keystream, + uint8_t* plain_data, + uint16_t plain_data_bits, + uint8_t* encrypted_data, + uint8_t* encrypted_parity); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller.c b/lib/nfc/protocols/mf_classic/mf_classic_poller.c index 5b66f3aabf2a..230991a04707 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller.c @@ -29,6 +29,7 @@ MfClassicError mf_classic_poller_start( furi_assert(instance->session_state == MfClassicPollerSessionStateIdle); instance->data = malloc(sizeof(MfClassicData)); + instance->crypto = crypto1_alloc(); instance->buffer = nfc_poller_buffer_alloc(MF_CLASSIC_MAX_BUFF_SIZE, MF_CLASSIC_MAX_BUFF_SIZE); instance->session_state = MfClassicPollerSessionStateActive; @@ -66,6 +67,7 @@ MfClassicError mf_classic_poller_reset(MfClassicPoller* instance) { furi_assert(instance->buffer); furi_assert(instance->nfca_poller); + crypto1_free(instance->crypto); nfc_poller_buffer_free(instance->buffer); instance->callback = NULL; instance->context = NULL; diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c index 0ff370bdb219..d5ce7168956c 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c @@ -1,6 +1,7 @@ #include "mf_classic_poller_i.h" #include +#include #define MF_CLASSIC_FWT_FC (60000) @@ -40,6 +41,7 @@ MfClassicError mf_classic_async_auth( NfcPollerBuffer* buff = instance->buffer; MfClassicError ret = MfClassicErrorNone; NfcaError error = NfcaErrorNone; + nfca_poller_get_data(instance->nfca_poller, &instance->data->nfca_data); uint8_t auth_cmd = (key_type == MfClassicKeyTypeB) ? MF_CLASSIC_AUTH_KEY_B_CMD : MF_CLASSIC_AUTH_KEY_A_CMD; @@ -65,6 +67,64 @@ MfClassicError mf_classic_async_auth( break; } memcpy(data->nt.data, buff->rx_data, sizeof(MfClassicNt)); + + uint8_t* cuid_start = instance->data->nfca_data.uid; + if(instance->data->nfca_data.uid_len == 7) { + cuid_start = &instance->data->nfca_data.uid[3]; + } + uint32_t cuid = (cuid_start[0] << 24) | (cuid_start[1] << 16) | (cuid_start[2] << 8) | + (cuid_start[3]); + + uint32_t nt = (uint32_t)nfc_util_bytes2num(buff->rx_data, sizeof(MfClassicNt)); + uint64_t key_num = nfc_util_bytes2num(key->data, sizeof(MfClassicKey)); + crypto1_init(instance->crypto, key_num); + crypto1_word(instance->crypto, nt ^ cuid, 0); + + MfClassicNr nr = {}; + furi_hal_random_fill_buf(nr.data, sizeof(MfClassicNr)); + // TODO rework! + for(size_t i = 0; i < sizeof(MfClassicNr); i++) { + buff->tx_data[i] = crypto1_byte(instance->crypto, nr.data[i], 0) ^ nr.data[i]; + buff->tx_parity[0] |= + (((crypto1_filter(instance->crypto->odd) ^ nfc_util_odd_parity8(nr.data[i])) & + 0x01) + << (7 - i)); + nr.data[i] = buff->tx_data[i]; + } + nt = prng_successor(nt, 32); + for(size_t i = 4; i < 8; i++) { + nt = prng_successor(nt, 8); + buff->tx_data[i] = crypto1_byte(instance->crypto, 0, 0) ^ (nt & 0xff); + buff->tx_parity[0] |= + (((crypto1_filter(instance->crypto->odd) ^ nfc_util_odd_parity8(nt & 0xff)) & 0x01) + << (7 - i)); + } + + buff->tx_bits = 8 * 8; + error = nfca_poller_txrx_custom_parity( + instance->nfca_poller, + buff->tx_data, + buff->tx_parity, + buff->tx_bits, + buff->rx_data, + buff->rx_parity, + buff->rx_data_size, + &buff->rx_bits, + MF_CLASSIC_FWT_FC); + if(error != NfcaErrorNone) { + ret = mf_classic_process_error(error); + break; + } + if(buff->rx_bits != 4 * 8) { + ret = MfClassicErrorAuth; + } + + crypto1_word(instance->crypto, 0, 0); + instance->auth_state = MfClassicAuthStatePassed; + + data->nr = nr; + memcpy(data->ar.data, &buff->tx_data[4], sizeof(MfClassicAr)); + memcpy(data->at.data, buff->rx_data, sizeof(MfClassicAt)); } while(false); return ret; diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h index 245b4109cd04..02ee9d59e561 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h @@ -4,6 +4,7 @@ #include #include #include +#include "crypto1.h" #ifdef __cplusplus extern "C" { @@ -17,10 +18,7 @@ typedef enum { typedef enum { MfClassicAuthStateIdle, - MfClassicAuthStateWaitNt, - MfClassicAuthStateWaitAt, - MfClassicAuthStateSuccess, - MfClassicAuthStateFail, + MfClassicAuthStatePassed, } MfClassicAuthState; typedef enum { @@ -31,6 +29,7 @@ struct MfClassicPoller { NfcaPoller* nfca_poller; MfClassicPollerSessionState session_state; MfClassicAuthState auth_state; + Crypto1* crypto; NfcPollerBuffer* buffer; MfClassicData* data; MfClassicPollerCallback callback; diff --git a/lib/nfc/protocols/nfca/nfca_poller_i.c b/lib/nfc/protocols/nfca/nfca_poller_i.c index aee9415bc3ae..43d6ff3ac43e 100644 --- a/lib/nfc/protocols/nfca/nfca_poller_i.c +++ b/lib/nfc/protocols/nfca/nfca_poller_i.c @@ -310,6 +310,112 @@ NfcaError nfca_poller_async_activate(NfcaPoller* instance, NfcaData* nfca_data) return ret; } +static uint16_t + nfca_data_to_bitstream(uint8_t* data, uint8_t* parity, uint16_t bits, uint8_t* bitstream) { + furi_assert(data); + furi_assert(parity); + furi_assert(bitstream); + + uint8_t next_par_bit = 0; + uint16_t curr_bit_pos = 0; + uint16_t bytes = bits / 8; + + for(size_t i = 0; i < bytes; i++) { + next_par_bit = FURI_BIT(parity[i / 8], 7 - (i % 8)); + if(curr_bit_pos % 8 == 0) { + bitstream[curr_bit_pos / 8] = data[i]; + curr_bit_pos += 8; + bitstream[curr_bit_pos / 8] = next_par_bit; + curr_bit_pos++; + } else { + bitstream[curr_bit_pos / 8] |= data[i] << (curr_bit_pos % 8); + bitstream[curr_bit_pos / 8 + 1] = data[i] >> (8 - curr_bit_pos % 8); + bitstream[curr_bit_pos / 8 + 1] |= next_par_bit << (curr_bit_pos % 8); + curr_bit_pos += 9; + } + } + return curr_bit_pos; +} + +static uint16_t + nfca_bitstream_to_data(uint8_t* bitstream, uint16_t bits, uint8_t* data, uint8_t* parity) { + uint32_t data_bits = 0; + uint8_t curr_byte = 0; + uint16_t bit_processed = 0; + + if(bits < 8) { + data[0] = bitstream[0]; + data_bits = bits; + } else if(bits % 9 != 0) { + data_bits = 0; + } else { + memset(parity, 0, bits / 9); + while(bit_processed < bits) { + data[curr_byte] = bitstream[bit_processed / 8] >> (bit_processed % 8); + data[curr_byte] |= bitstream[bit_processed / 8 + 1] << (8 - bit_processed % 8); + parity[curr_byte / 8] |= FURI_BIT(bitstream[bit_processed / 8 + 1], bit_processed % 8) + << (7 - curr_byte % 8); + bit_processed += 9; + curr_byte++; + } + data_bits = curr_byte * 8; + } + + return data_bits; +} + +NfcaError nfca_poller_txrx_custom_parity( + NfcaPoller* instance, + uint8_t* tx_data, + uint8_t* tx_parity, + uint16_t tx_bits, + uint8_t* rx_data, + uint8_t* rx_parity, + uint16_t rx_buff_size, + uint16_t* rx_bits, + uint32_t fwt) { + furi_assert(instance); + furi_assert(tx_data); + furi_assert(tx_parity); + furi_assert(rx_data); + furi_assert(rx_parity); + furi_assert(rx_bits); + + NfcaError ret = NfcaErrorNone; + NfcError error = NfcErrorNone; + NfcPollerBuffer* buff = instance->buff; + + do { + ret = nfca_poller_prepare_trx(instance); + if(ret != NfcaErrorNone) break; + + buff->tx_bits = nfca_data_to_bitstream(tx_data, tx_parity, tx_bits, buff->tx_data); + + error = nfc_trx_custom_parity( + instance->nfc, + buff->tx_data, + buff->tx_bits, + buff->rx_data, + buff->rx_data_size, + &buff->rx_bits, + fwt); + if(error != NfcErrorNone) { + ret = nfca_poller_process_error(error); + break; + } + + uint16_t rx_bytes = buff->rx_bits / 9; + if(rx_buff_size < rx_bytes) { + ret = NfcaErrorBufferOverflow; + break; + } + + *rx_bits = nfca_bitstream_to_data(buff->rx_data, buff->rx_bits, rx_data, rx_parity); + } while(false); + + return ret; +} + NfcaError nfca_poller_txrx( NfcaPoller* instance, uint8_t* tx_buff, diff --git a/lib/nfc/protocols/nfca/nfca_poller_i.h b/lib/nfc/protocols/nfca/nfca_poller_i.h index 8e6f078108d4..487f1c8e389f 100644 --- a/lib/nfc/protocols/nfca/nfca_poller_i.h +++ b/lib/nfc/protocols/nfca/nfca_poller_i.h @@ -65,6 +65,17 @@ NfcaError nfca_poller_async_activate(NfcaPoller* instance, NfcaData* nfca_data); NfcaError nfca_poller_halt(NfcaPoller* instance); +NfcaError nfca_poller_txrx_custom_parity( + NfcaPoller* instance, + uint8_t* tx_data, + uint8_t* tx_parity, + uint16_t tx_bits, + uint8_t* rx_data, + uint8_t* rx_parity, + uint16_t rx_buff_size, + uint16_t* rx_bits, + uint32_t fwt); + NfcaError nfca_poller_txrx( NfcaPoller* instance, uint8_t* tx_buff, From 51ced8afa155c20304f61c361d7b256c0449899c Mon Sep 17 00:00:00 2001 From: gornekich Date: Wed, 17 May 2023 18:13:37 +0400 Subject: [PATCH 089/149] nfc: add sync read block --- lib/nfc/protocols/mf_classic/mf_classic.h | 1 + .../protocols/mf_classic/mf_classic_poller.c | 12 ++- .../mf_classic/mf_classic_poller_i.c | 94 +++++++++++++++---- .../mf_classic/mf_classic_poller_i.h | 11 ++- .../mf_classic/mf_classic_poller_sync_api.c | 61 ++++++++++-- 5 files changed, 151 insertions(+), 28 deletions(-) diff --git a/lib/nfc/protocols/mf_classic/mf_classic.h b/lib/nfc/protocols/mf_classic/mf_classic.h index 4192a4a362f7..63f09886d668 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic.h +++ b/lib/nfc/protocols/mf_classic/mf_classic.h @@ -8,6 +8,7 @@ extern "C" { #define MF_CLASSIC_AUTH_KEY_A_CMD (0x60U) #define MF_CLASSIC_AUTH_KEY_B_CMD (0x61U) +#define MF_CLASSIC_READ_BLOCK_CMD (0x30U) #define MF_CLASSIC_TOTAL_BLOCKS_MAX (256) #define MF_CLASSIC_BLOCK_SIZE (16) diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller.c b/lib/nfc/protocols/mf_classic/mf_classic_poller.c index 230991a04707..670e4aff06d3 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller.c @@ -30,7 +30,10 @@ MfClassicError mf_classic_poller_start( instance->data = malloc(sizeof(MfClassicData)); instance->crypto = crypto1_alloc(); - instance->buffer = nfc_poller_buffer_alloc(MF_CLASSIC_MAX_BUFF_SIZE, MF_CLASSIC_MAX_BUFF_SIZE); + instance->plain_buff = + nfc_poller_buffer_alloc(MF_CLASSIC_MAX_BUFF_SIZE, MF_CLASSIC_MAX_BUFF_SIZE); + instance->encrypted_buff = + nfc_poller_buffer_alloc(MF_CLASSIC_MAX_BUFF_SIZE, MF_CLASSIC_MAX_BUFF_SIZE); instance->session_state = MfClassicPollerSessionStateActive; nfca_poller_start(instance->nfca_poller, callback, context); @@ -64,11 +67,14 @@ MfClassicError mf_classic_poller_get_data(MfClassicPoller* instance, MfClassicDa MfClassicError mf_classic_poller_reset(MfClassicPoller* instance) { furi_assert(instance); furi_assert(instance->data); - furi_assert(instance->buffer); + furi_assert(instance->plain_buff); + furi_assert(instance->encrypted_buff); furi_assert(instance->nfca_poller); + instance->auth_state = MfClassicAuthStateIdle; crypto1_free(instance->crypto); - nfc_poller_buffer_free(instance->buffer); + nfc_poller_buffer_free(instance->plain_buff); + nfc_poller_buffer_free(instance->encrypted_buff); instance->callback = NULL; instance->context = NULL; diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c index d5ce7168956c..061b08564179 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c @@ -3,6 +3,8 @@ #include #include +#define TAG "MfCLassicPoller" + #define MF_CLASSIC_FWT_FC (60000) MfClassicError mf_classic_process_error(NfcaError error) { @@ -37,19 +39,18 @@ MfClassicError mf_classic_async_auth( MfClassicKey* key, MfClassicKeyType key_type, MfClassicAuthContext* data) { - UNUSED(key); - NfcPollerBuffer* buff = instance->buffer; + NfcPollerBuffer* buff = instance->plain_buff; MfClassicError ret = MfClassicErrorNone; NfcaError error = NfcaErrorNone; - nfca_poller_get_data(instance->nfca_poller, &instance->data->nfca_data); - - uint8_t auth_cmd = (key_type == MfClassicKeyTypeB) ? MF_CLASSIC_AUTH_KEY_B_CMD : - MF_CLASSIC_AUTH_KEY_A_CMD; - buff->tx_data[0] = auth_cmd; - buff->tx_data[1] = block_num; - buff->tx_bits = 2 * 8; do { + nfca_poller_get_data(instance->nfca_poller, &instance->data->nfca_data); + uint8_t auth_cmd = (key_type == MfClassicKeyTypeB) ? MF_CLASSIC_AUTH_KEY_B_CMD : + MF_CLASSIC_AUTH_KEY_A_CMD; + buff->tx_data[0] = auth_cmd; + buff->tx_data[1] = block_num; + buff->tx_bits = 2 * 8; + error = nfca_poller_send_standart_frame( instance->nfca_poller, buff->tx_data, @@ -66,7 +67,9 @@ MfClassicError mf_classic_async_auth( ret = MfClassicErrorProtocol; break; } - memcpy(data->nt.data, buff->rx_data, sizeof(MfClassicNt)); + if(data) { + memcpy(data->nt.data, buff->rx_data, sizeof(MfClassicNt)); + } uint8_t* cuid_start = instance->data->nfca_data.uid; if(instance->data->nfca_data.uid_len == 7) { @@ -118,17 +121,76 @@ MfClassicError mf_classic_async_auth( if(buff->rx_bits != 4 * 8) { ret = MfClassicErrorAuth; } - + crypto1_word(instance->crypto, 0, 0); instance->auth_state = MfClassicAuthStatePassed; - data->nr = nr; - memcpy(data->ar.data, &buff->tx_data[4], sizeof(MfClassicAr)); - memcpy(data->at.data, buff->rx_data, sizeof(MfClassicAt)); + if(data) { + data->nr = nr; + memcpy(data->ar.data, &buff->tx_data[4], sizeof(MfClassicAr)); + memcpy(data->at.data, buff->rx_data, sizeof(MfClassicAt)); + } } while(false); return ret; } -MfClassicError - mf_classic_async_read_block(MfClassicPoller* instance, uint8_t block_num, MfClassicBlock* data); +MfClassicError mf_classic_async_read_block( + MfClassicPoller* instance, + uint8_t block_num, + MfClassicBlock* data) { + NfcPollerBuffer* plain_buff = instance->plain_buff; + NfcPollerBuffer* encrypted_buff = instance->encrypted_buff; + MfClassicError ret = MfClassicErrorNone; + NfcaError error = NfcaErrorNone; + + do { + plain_buff->tx_data[0] = MF_CLASSIC_READ_BLOCK_CMD; + plain_buff->tx_data[1] = block_num; + nfca_append_crc(plain_buff->tx_data, 2); + plain_buff->tx_bits = 4 * 8; + + encrypted_buff->tx_bits = plain_buff->tx_bits; + crypto1_encrypt( + instance->crypto, + NULL, + plain_buff->tx_data, + plain_buff->tx_bits, + encrypted_buff->tx_data, + encrypted_buff->tx_parity); + + error = nfca_poller_txrx_custom_parity( + instance->nfca_poller, + encrypted_buff->tx_data, + encrypted_buff->tx_parity, + encrypted_buff->tx_bits, + encrypted_buff->rx_data, + encrypted_buff->rx_parity, + encrypted_buff->rx_data_size, + &encrypted_buff->rx_bits, + MF_CLASSIC_FWT_FC); + if(error != NfcaErrorNone) { + ret = mf_classic_process_error(error); + break; + } + if(encrypted_buff->rx_bits != (sizeof(MfClassicBlock) + 2) * 8) { + ret = MfClassicErrorProtocol; + break; + } + + crypto1_decrypt( + instance->crypto, + encrypted_buff->rx_data, + encrypted_buff->rx_bits, + plain_buff->rx_data); + + if(!nfca_check_crc(plain_buff->rx_data, sizeof(MfClassicBlock) + 2)) { + FURI_LOG_D(TAG, "CRC error"); + ret = MfClassicErrorProtocol; + break; + } + memcpy(data->data, plain_buff->rx_data, sizeof(MfClassicBlock)); + } while(false); + + return ret; +} diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h index 02ee9d59e561..129885ebdcf4 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h @@ -30,14 +30,23 @@ struct MfClassicPoller { MfClassicPollerSessionState session_state; MfClassicAuthState auth_state; Crypto1* crypto; - NfcPollerBuffer* buffer; + NfcPollerBuffer* plain_buff; + NfcPollerBuffer* encrypted_buff; MfClassicData* data; MfClassicPollerCallback callback; void* context; }; +typedef struct { + uint8_t block_num; + MfClassicKey key; + MfClassicKeyType key_type; + MfClassicBlock block; +} MfClassicReadBlockContext; + typedef union { MfClassicAuthContext auth_context; + MfClassicReadBlockContext read_block_context; } MfClassicPollerContextData; diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.c b/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.c index f730514d4a04..76ed3baf0a8e 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.c @@ -50,6 +50,7 @@ MfClassicError mf_classic_poller_auth( mf_classic_poller_start(instance, mf_classic_auth_callback, &poller_context); furi_thread_flags_wait(MF_CLASSIC_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); + furi_thread_flags_clear(MF_CLASSIC_POLLER_COMPLETE_EVENT); if(poller_context.error == MfClassicErrorNone) { *data = poller_context.data.auth_context; @@ -59,6 +60,42 @@ MfClassicError mf_classic_poller_auth( return poller_context.error; } +NfcaPollerCommand mf_classic_read_block_callback(NfcaPollerEvent event, void* context) { + furi_assert(context); + + MfClassicPollerContext* poller_context = context; + MfClassicReadBlockContext* read_block_context = &poller_context->data.read_block_context; + NfcaPollerCommand command = NfcaPollerCommandContinue; + + if(event.type == NfcaPollerEventTypeReady) { + if(poller_context->instance->auth_state == MfClassicAuthStateIdle) { + poller_context->error = mf_classic_async_auth( + poller_context->instance, + read_block_context->block_num, + &read_block_context->key, + read_block_context->key_type, + NULL); + if(poller_context->error != MfClassicErrorNone) { + command = NfcaPollerCommandStop; + } + } else { + poller_context->error = mf_classic_async_read_block( + poller_context->instance, + read_block_context->block_num, + &read_block_context->block); + command = NfcaPollerCommandStop; + } + } else if(event.type == NfcaPollerEventTypeError) { + poller_context->error = mf_classic_process_error(event.data.error); + command = NfcaPollerCommandStop; + } + if(command == NfcaPollerCommandStop) { + furi_thread_flags_set(poller_context->thread_id, MF_CLASSIC_POLLER_COMPLETE_EVENT); + } + + return command; +} + MfClassicError mf_classic_poller_read_block( MfClassicPoller* instance, uint8_t block_num, @@ -68,14 +105,22 @@ MfClassicError mf_classic_poller_read_block( furi_assert(instance); furi_assert(key); furi_assert(data); - UNUSED(block_num); - UNUSED(key_type); - if(data) { - for(size_t i = 0; i < 16; i++) { - data->data[i] = i; - } + MfClassicPollerContext poller_context = {}; + poller_context.data.read_block_context.block_num = block_num; + poller_context.data.read_block_context.key = *key; + poller_context.data.read_block_context.key_type = key_type; + poller_context.instance = instance; + poller_context.thread_id = furi_thread_get_current_id(); + + mf_classic_poller_start(instance, mf_classic_read_block_callback, &poller_context); + furi_thread_flags_wait(MF_CLASSIC_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); + furi_thread_flags_clear(MF_CLASSIC_POLLER_COMPLETE_EVENT); + + if(poller_context.error == MfClassicErrorNone) { + *data = poller_context.data.read_block_context.block; } + mf_classic_poller_stop(instance); - return MfClassicErrorNone; -} \ No newline at end of file + return poller_context.error; +} From 29b05423ddec83c4d40854eb01274b369881015b Mon Sep 17 00:00:00 2001 From: gornekich Date: Fri, 2 Jun 2023 17:43:01 +0400 Subject: [PATCH 090/149] nfc: debug build, fix crashes --- firmware.scons | 9 +++++++++ lib/nfc/nfc.c | 10 ++++------ lib/nfc/protocols/nfca/nfca_poller.c | 2 +- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/firmware.scons b/firmware.scons index c46996899135..672401a31474 100644 --- a/firmware.scons +++ b/firmware.scons @@ -67,6 +67,15 @@ env = ENV.Clone( "FURI_DEBUG" if ENV["DEBUG"] else "FURI_NDEBUG", ], }, + "nfc": { + "CCFLAGS": [ + "-Og", + ], + "CPPDEFINES": [ + "NDEBUG", + "FURI_DEBUG", + ], + } }, FW_API_TABLE=None, _APP_ICONS=None, diff --git a/lib/nfc/nfc.c b/lib/nfc/nfc.c index 4cb24764eb4e..65e0b5f8ac48 100644 --- a/lib/nfc/nfc.c +++ b/lib/nfc/nfc.c @@ -122,7 +122,6 @@ static int32_t nfc_worker_poller(void* context) { furi_assert(context); Nfc* instance = context; - furi_assert(instance->state == NfcStateConfigured); furi_assert(instance->callback); instance->state = NfcStateIdle; @@ -379,7 +378,6 @@ static NfcError nfc_poller_trx_state_machine(Nfc* instance, uint32_t fwt_fc) { static NfcError nfc_poller_prepare_trx(Nfc* instance) { furi_assert(instance); - furi_assert(instance->state == NfcStateIdle); FHalNfcError error = FHalNfcErrorNone; NfcError ret = NfcErrorNone; @@ -427,7 +425,7 @@ NfcError nfc_trx_custom_parity( furi_assert(rx_data); furi_assert(rx_bits); - furi_assert(instance->state == NfcStateFieldOn); + furi_assert(instance->state == NfcStatePollerReady); NfcError ret = NfcErrorNone; FHalNfcError error = FHalNfcErrorNone; @@ -473,7 +471,7 @@ NfcError nfc_trx( furi_assert(rx_data); furi_assert(rx_bits); - furi_assert(instance->state == NfcStateFieldOn); + furi_assert(instance->state == NfcStatePollerReady); NfcError ret = NfcErrorNone; FHalNfcError error = FHalNfcErrorNone; @@ -521,7 +519,7 @@ NfcError nfc_iso13444a_short_frame( FHalNfcaShortFrameAllReq : FHalNfcaShortFrameSensReq; - furi_assert(instance->state == NfcStateFieldOn); + furi_assert(instance->state == NfcStatePollerReady); NfcError ret = NfcErrorNone; FHalNfcError error = FHalNfcErrorNone; @@ -563,7 +561,7 @@ NfcError nfc_iso13444a_sdd_frame( uint16_t* rx_bits, uint32_t fwt) { furi_assert(instance); - furi_assert(instance->state == NfcStateFieldOn); + furi_assert(instance->state == NfcStatePollerReady); NfcError ret = NfcErrorNone; FHalNfcError error = FHalNfcErrorNone; diff --git a/lib/nfc/protocols/nfca/nfca_poller.c b/lib/nfc/protocols/nfca/nfca_poller.c index 3271a14c6b3a..c70077a246b7 100644 --- a/lib/nfc/protocols/nfca/nfca_poller.c +++ b/lib/nfc/protocols/nfca/nfca_poller.c @@ -125,7 +125,7 @@ NfcaError nfca_poller_stop(NfcaPoller* instance) { instance->session_state = NfcaPollerSessionStateIdle; // Check that data is freed - furi_assert(instance->buff != NULL); + furi_assert(instance->buff == NULL); free(instance->data); From 64d5e0e214395ebbd622f5fc40e50824063bcf53 Mon Sep 17 00:00:00 2001 From: gornekich Date: Fri, 19 May 2023 18:50:48 +0400 Subject: [PATCH 091/149] nfc: start dict attack --- applications/main/nfc/helpers/mf_dict.c | 346 ++++++++++++++++++ applications/main/nfc/helpers/mf_dict.h | 99 +++++ applications/main/nfc/nfc_app.c | 22 ++ applications/main/nfc/nfc_app_i.h | 9 +- .../main/nfc/scenes/nfc_scene_config.h | 5 +- .../scenes/nfc_scene_mf_classic_dict_attack.c | 177 +++++++++ applications/main/nfc/views/dict_attack.h | 2 +- .../protocols/mf_classic/mf_classic_poller.c | 2 +- .../protocols/mf_classic/mf_classic_poller.h | 10 +- lib/nfc/protocols/nfca/nfca.h | 5 + 10 files changed, 670 insertions(+), 7 deletions(-) create mode 100644 applications/main/nfc/helpers/mf_dict.c create mode 100644 applications/main/nfc/helpers/mf_dict.h create mode 100644 applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c diff --git a/applications/main/nfc/helpers/mf_dict.c b/applications/main/nfc/helpers/mf_dict.c new file mode 100644 index 000000000000..4050b28ec782 --- /dev/null +++ b/applications/main/nfc/helpers/mf_dict.c @@ -0,0 +1,346 @@ +#include "mf_dict.h" + +#include +#include + +#define MF_CLASSIC_DICT_FLIPPER_PATH EXT_PATH("nfc/assets/mf_dict.nfc") +#define MF_CLASSIC_DICT_USER_PATH EXT_PATH("nfc/assets/mf_dict_user.nfc") +#define MF_CLASSIC_DICT_UNIT_TEST_PATH EXT_PATH("unit_tests/mf_dict.nfc") + +#define TAG "MfDict" + +#define NFC_MF_CLASSIC_KEY_LEN (13) + +struct MfDict { + Stream* stream; + uint32_t total_keys; +}; + +bool mf_dict_check_presence(MfDictType dict_type) { + Storage* storage = furi_record_open(RECORD_STORAGE); + + bool dict_present = false; + if(dict_type == MfDictTypeSystem) { + dict_present = storage_common_stat(storage, MF_CLASSIC_DICT_FLIPPER_PATH, NULL) == FSE_OK; + } else if(dict_type == MfDictTypeUser) { + dict_present = storage_common_stat(storage, MF_CLASSIC_DICT_USER_PATH, NULL) == FSE_OK; + } else if(dict_type == MfDictTypeUnitTest) { + dict_present = storage_common_stat(storage, MF_CLASSIC_DICT_UNIT_TEST_PATH, NULL) == + FSE_OK; + } + + furi_record_close(RECORD_STORAGE); + + return dict_present; +} + +MfDict* mf_dict_alloc(MfDictType dict_type) { + MfDict* dict = malloc(sizeof(MfDict)); + Storage* storage = furi_record_open(RECORD_STORAGE); + dict->stream = buffered_file_stream_alloc(storage); + furi_record_close(RECORD_STORAGE); + + bool dict_loaded = false; + do { + if(dict_type == MfDictTypeSystem) { + if(!buffered_file_stream_open( + dict->stream, + MF_CLASSIC_DICT_FLIPPER_PATH, + FSAM_READ_WRITE, + FSOM_OPEN_EXISTING)) { + buffered_file_stream_close(dict->stream); + break; + } + } else if(dict_type == MfDictTypeUser) { + if(!buffered_file_stream_open( + dict->stream, MF_CLASSIC_DICT_USER_PATH, FSAM_READ_WRITE, FSOM_OPEN_ALWAYS)) { + buffered_file_stream_close(dict->stream); + break; + } + } else if(dict_type == MfDictTypeUnitTest) { + if(!buffered_file_stream_open( + dict->stream, + MF_CLASSIC_DICT_UNIT_TEST_PATH, + FSAM_READ_WRITE, + FSOM_OPEN_ALWAYS)) { + buffered_file_stream_close(dict->stream); + break; + } + } + + // Check for new line ending + if(!stream_eof(dict->stream)) { + if(!stream_seek(dict->stream, -1, StreamOffsetFromEnd)) break; + uint8_t last_char = 0; + if(stream_read(dict->stream, &last_char, 1) != 1) break; + if(last_char != '\n') { + FURI_LOG_D(TAG, "Adding new line ending"); + if(stream_write_char(dict->stream, '\n') != 1) break; + } + if(!stream_rewind(dict->stream)) break; + } + + // Read total amount of keys + FuriString* next_line; + next_line = furi_string_alloc(); + while(true) { + if(!stream_read_line(dict->stream, next_line)) { + FURI_LOG_T(TAG, "No keys left in dict"); + break; + } + FURI_LOG_T( + TAG, + "Read line: %s, len: %zu", + furi_string_get_cstr(next_line), + furi_string_size(next_line)); + if(furi_string_get_char(next_line, 0) == '#') continue; + if(furi_string_size(next_line) != NFC_MF_CLASSIC_KEY_LEN) continue; + dict->total_keys++; + } + furi_string_free(next_line); + stream_rewind(dict->stream); + + dict_loaded = true; + FURI_LOG_I(TAG, "Loaded dictionary with %lu keys", dict->total_keys); + } while(false); + + if(!dict_loaded) { + buffered_file_stream_close(dict->stream); + free(dict); + dict = NULL; + } + + return dict; +} + +void mf_dict_free(MfDict* dict) { + furi_assert(dict); + furi_assert(dict->stream); + + buffered_file_stream_close(dict->stream); + stream_free(dict->stream); + free(dict); +} + +static void mf_dict_int_to_str(uint8_t* key_int, FuriString* key_str) { + furi_string_reset(key_str); + for(size_t i = 0; i < 6; i++) { + furi_string_cat_printf(key_str, "%02X", key_int[i]); + } +} + +static void mf_dict_str_to_int(FuriString* key_str, uint64_t* key_int) { + uint8_t key_byte_tmp; + + *key_int = 0ULL; + for(uint8_t i = 0; i < 12; i += 2) { + args_char_to_hex( + furi_string_get_char(key_str, i), furi_string_get_char(key_str, i + 1), &key_byte_tmp); + *key_int |= (uint64_t)key_byte_tmp << (8 * (5 - i / 2)); + } +} + +uint32_t mf_dict_get_total_keys(MfDict* dict) { + furi_assert(dict); + + return dict->total_keys; +} + +bool mf_dict_rewind(MfDict* dict) { + furi_assert(dict); + furi_assert(dict->stream); + + return stream_rewind(dict->stream); +} + +bool mf_dict_get_next_key_str(MfDict* dict, FuriString* key) { + furi_assert(dict); + furi_assert(dict->stream); + + bool key_read = false; + furi_string_reset(key); + while(!key_read) { + if(!stream_read_line(dict->stream, key)) break; + if(furi_string_get_char(key, 0) == '#') continue; + if(furi_string_size(key) != NFC_MF_CLASSIC_KEY_LEN) continue; + furi_string_left(key, 12); + key_read = true; + } + + return key_read; +} + +bool mf_dict_get_next_key(MfDict* dict, uint64_t* key) { + furi_assert(dict); + furi_assert(dict->stream); + + FuriString* temp_key; + temp_key = furi_string_alloc(); + bool key_read = mf_dict_get_next_key_str(dict, temp_key); + if(key_read) { + mf_dict_str_to_int(temp_key, key); + } + furi_string_free(temp_key); + return key_read; +} + +bool mf_dict_is_key_present_str(MfDict* dict, FuriString* key) { + furi_assert(dict); + furi_assert(dict->stream); + + FuriString* next_line; + next_line = furi_string_alloc(); + + bool key_found = false; + stream_rewind(dict->stream); + while(!key_found) { //-V654 + if(!stream_read_line(dict->stream, next_line)) break; + if(furi_string_get_char(next_line, 0) == '#') continue; + if(furi_string_size(next_line) != NFC_MF_CLASSIC_KEY_LEN) continue; + furi_string_left(next_line, 12); + if(!furi_string_equal(key, next_line)) continue; + key_found = true; + } + + furi_string_free(next_line); + return key_found; +} + +bool mf_dict_is_key_present(MfDict* dict, uint8_t* key) { + FuriString* temp_key; + + temp_key = furi_string_alloc(); + mf_dict_int_to_str(key, temp_key); + bool key_found = mf_dict_is_key_present_str(dict, temp_key); + furi_string_free(temp_key); + return key_found; +} + +bool mf_dict_add_key_str(MfDict* dict, FuriString* key) { + furi_assert(dict); + furi_assert(dict->stream); + + furi_string_cat_printf(key, "\n"); + + bool key_added = false; + do { + if(!stream_seek(dict->stream, 0, StreamOffsetFromEnd)) break; + if(!stream_insert_string(dict->stream, key)) break; + dict->total_keys++; + key_added = true; + } while(false); + + furi_string_left(key, 12); + return key_added; +} + +bool mf_dict_add_key(MfDict* dict, uint8_t* key) { + furi_assert(dict); + furi_assert(dict->stream); + + FuriString* temp_key; + temp_key = furi_string_alloc(); + mf_dict_int_to_str(key, temp_key); + bool key_added = mf_dict_add_key_str(dict, temp_key); + + furi_string_free(temp_key); + return key_added; +} + +bool mf_dict_get_key_at_index_str(MfDict* dict, FuriString* key, uint32_t target) { + furi_assert(dict); + furi_assert(dict->stream); + + FuriString* next_line; + uint32_t index = 0; + next_line = furi_string_alloc(); + furi_string_reset(key); + + bool key_found = false; + while(!key_found) { + if(!stream_read_line(dict->stream, next_line)) break; + if(furi_string_get_char(next_line, 0) == '#') continue; + if(furi_string_size(next_line) != NFC_MF_CLASSIC_KEY_LEN) continue; + if(index++ != target) continue; + furi_string_set_n(key, next_line, 0, 12); + key_found = true; + } + + furi_string_free(next_line); + return key_found; +} + +bool mf_dict_get_key_at_index(MfDict* dict, uint64_t* key, uint32_t target) { + furi_assert(dict); + furi_assert(dict->stream); + + FuriString* temp_key; + temp_key = furi_string_alloc(); + bool key_found = mf_dict_get_key_at_index_str(dict, temp_key, target); + if(key_found) { + mf_dict_str_to_int(temp_key, key); + } + furi_string_free(temp_key); + return key_found; +} + +bool mf_dict_find_index_str(MfDict* dict, FuriString* key, uint32_t* target) { + furi_assert(dict); + furi_assert(dict->stream); + + FuriString* next_line; + next_line = furi_string_alloc(); + + bool key_found = false; + uint32_t index = 0; + stream_rewind(dict->stream); + while(!key_found) { //-V654 + if(!stream_read_line(dict->stream, next_line)) break; + if(furi_string_get_char(next_line, 0) == '#') continue; + if(furi_string_size(next_line) != NFC_MF_CLASSIC_KEY_LEN) continue; + furi_string_left(next_line, 12); + if(!furi_string_equal(key, next_line)) continue; + key_found = true; + *target = index; + } + + furi_string_free(next_line); + return key_found; +} + +bool mf_dict_find_index(MfDict* dict, uint8_t* key, uint32_t* target) { + furi_assert(dict); + furi_assert(dict->stream); + + FuriString* temp_key; + temp_key = furi_string_alloc(); + mf_dict_int_to_str(key, temp_key); + bool key_found = mf_dict_find_index_str(dict, temp_key, target); + + furi_string_free(temp_key); + return key_found; +} + +bool mf_dict_delete_index(MfDict* dict, uint32_t target) { + furi_assert(dict); + furi_assert(dict->stream); + + FuriString* next_line; + next_line = furi_string_alloc(); + uint32_t index = 0; + + bool key_removed = false; + while(!key_removed) { + if(!stream_read_line(dict->stream, next_line)) break; + if(furi_string_get_char(next_line, 0) == '#') continue; + if(furi_string_size(next_line) != NFC_MF_CLASSIC_KEY_LEN) continue; + if(index++ != target) continue; + stream_seek(dict->stream, -NFC_MF_CLASSIC_KEY_LEN, StreamOffsetFromCurrent); + if(!stream_delete(dict->stream, NFC_MF_CLASSIC_KEY_LEN)) break; + dict->total_keys--; + key_removed = true; + } + + furi_string_free(next_line); + return key_removed; +} diff --git a/applications/main/nfc/helpers/mf_dict.h b/applications/main/nfc/helpers/mf_dict.h new file mode 100644 index 000000000000..730b6f9da2fa --- /dev/null +++ b/applications/main/nfc/helpers/mf_dict.h @@ -0,0 +1,99 @@ +#pragma once + +#include +#include +#include +#include +#include + +typedef enum { + MfDictTypeUser, + MfDictTypeSystem, + MfDictTypeUnitTest, +} MfDictType; + +typedef struct MfDict MfDict; + +bool mf_dict_check_presence(MfDictType dict_type); + +/** Allocate MfDict instance + * + * @param[in] dict_type The dictionary type + * + * @return MfDict instance + */ +MfDict* mf_dict_alloc(MfDictType dict_type); + +/** Free MfDict instance + * + * @param dict MfDict instance + */ +void mf_dict_free(MfDict* dict); + +/** Get total keys count + * + * @param dict MfDict instance + * + * @return total keys count + */ +uint32_t mf_dict_get_total_keys(MfDict* dict); + +/** Rewind to the beginning + * + * @param dict MfDict instance + * + * @return true on success + */ +bool mf_dict_rewind(MfDict* dict); + +bool mf_dict_is_key_present(MfDict* dict, uint8_t* key); + +bool mf_dict_is_key_present_str(MfDict* dict, FuriString* key); + +bool mf_dict_get_next_key(MfDict* dict, uint64_t* key); + +bool mf_dict_get_next_key_str(MfDict* dict, FuriString* key); + +/** Get key at target offset as uint64_t + * + * @param dict MfDict instance + * @param[out] key Pointer to the uint64_t key + * @param[in] target Target offset from current position + * + * @return true on success + */ +bool mf_dict_get_key_at_index(MfDict* dict, uint64_t* key, uint32_t target); + +/** Get key at target offset as string_t + * + * @param dict MfDict instance + * @param[out] key Found key destination buffer + * @param[in] target Target offset from current position + * + * @return true on success + */ +bool mf_dict_get_key_at_index_str(MfDict* dict, FuriString* key, uint32_t target); + +bool mf_dict_add_key(MfDict* dict, uint8_t* key); + +/** Add string representation of the key + * + * @param dict MfDict instance + * @param[in] key String representation of the key + * + * @return true on success + */ +bool mf_dict_add_key_str(MfDict* dict, FuriString* key); + +bool mf_dict_find_index(MfDict* dict, uint8_t* key, uint32_t* target); + +bool mf_dict_find_index_str(MfDict* dict, FuriString* key, uint32_t* target); + +/** Delete key at target offset + * + * @param dict MfDict instance + * @param[in] target Target offset from current position + * + * @return true on success + */ +bool mf_dict_delete_index(MfDict* dict, uint32_t target); diff --git a/applications/main/nfc/nfc_app.c b/applications/main/nfc/nfc_app.c index e1f2753b9768..c65bf1147e28 100644 --- a/applications/main/nfc/nfc_app.c +++ b/applications/main/nfc/nfc_app.c @@ -48,6 +48,7 @@ NfcApp* nfc_app_alloc() { instance->nfc = nfc_alloc(); instance->nfca_poller = nfca_poller_alloc(instance->nfc); instance->mf_ul_poller = mf_ultralight_poller_alloc(instance->nfca_poller); + instance->mf_classic_poller = mf_classic_poller_alloc(instance->nfca_poller); instance->nfca_listener = nfca_listener_alloc(instance->nfc); instance->mf_ul_listener = mf_ultralight_listener_alloc(instance->nfca_listener); instance->nfcb_poller = nfcb_poller_alloc(instance->nfc); @@ -118,6 +119,18 @@ NfcApp* nfc_app_alloc() { view_dispatcher_add_view( instance->view_dispatcher, NfcViewWidget, widget_get_view(instance->widget)); + // Dict attack + instance->dict_attack = dict_attack_alloc(); + view_dispatcher_add_view( + instance->view_dispatcher, NfcViewDictAttack, dict_attack_get_view(instance->dict_attack)); + + // Detect Reader + instance->detect_reader = detect_reader_alloc(); + view_dispatcher_add_view( + instance->view_dispatcher, + NfcViewDetectReader, + detect_reader_get_view(instance->detect_reader)); + instance->file_path = furi_string_alloc_set(NFC_APP_FOLDER); instance->file_name = furi_string_alloc(); @@ -144,6 +157,7 @@ void nfc_app_free(NfcApp* instance) { instance->rpc_ctx = NULL; } + mf_classic_poller_free(instance->mf_classic_poller); mf_ultralight_listener_free(instance->mf_ul_listener); mf_ultralight_poller_free(instance->mf_ul_poller); nfca_listener_free(instance->nfca_listener); @@ -190,6 +204,14 @@ void nfc_app_free(NfcApp* instance) { view_dispatcher_remove_view(instance->view_dispatcher, NfcViewWidget); widget_free(instance->widget); + // Dict attack + view_dispatcher_remove_view(instance->view_dispatcher, NfcViewDictAttack); + dict_attack_free(instance->dict_attack); + + // Detect reader + view_dispatcher_remove_view(instance->view_dispatcher, NfcViewDetectReader); + detect_reader_free(instance->detect_reader); + // View Dispatcher view_dispatcher_free(instance->view_dispatcher); diff --git a/applications/main/nfc/nfc_app_i.h b/applications/main/nfc/nfc_app_i.h index bb28dce43366..3ddb854b65ca 100644 --- a/applications/main/nfc/nfc_app_i.h +++ b/applications/main/nfc/nfc_app_i.h @@ -21,10 +21,13 @@ #include #include #include +#include "views/dict_attack.h" +#include "views/detect_reader.h" #include -#include +#include "helpers/nfc_custom_event.h" #include "helpers/mf_ultralight_auth.h" +#include "helpers/mf_dict.h" #include #include @@ -40,6 +43,7 @@ #include #include #include +#include #include #include @@ -86,12 +90,15 @@ struct NfcApp { ByteInput* byte_input; TextBox* text_box; Widget* widget; + DictAttack* dict_attack; + DetectReader* detect_reader; Nfc* nfc; NfcaPoller* nfca_poller; NfcaListener* nfca_listener; MfUltralightPoller* mf_ul_poller; MfUltralightListener* mf_ul_listener; + MfClassicPoller* mf_classic_poller; NfcbPoller* nfcb_poller; NfcPoller* nfc_poller; diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index d6037f85b239..5008819ab4a8 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -16,6 +16,7 @@ ADD_SCENE(nfc, extra_actions, ExtraActions) ADD_SCENE(nfc, debug, Debug) ADD_SCENE(nfc, retry_confirm, RetryConfirm) ADD_SCENE(nfc, exit_confirm, ExitConfirm) + ADD_SCENE(nfc, mf_ultralight_read, MfUltralightRead) ADD_SCENE(nfc, mf_ultralight_read_success, MfUltralightReadSuccess) ADD_SCENE(nfc, mf_ultralight_emulate, MfUltralightEmulate) @@ -25,6 +26,8 @@ ADD_SCENE(nfc, mf_ultralight_unlock_warn, MfUltralightUnlockWarn) ADD_SCENE(nfc, mf_ultralight_key_input, MfUltralightKeyInput) ADD_SCENE(nfc, mf_ultralight_capture_pass, MfUltralightCapturePass) +ADD_SCENE(nfc, mf_classic_dict_attack, MfClassicDictAttack) + ADD_SCENE(nfc, set_type, SetType) ADD_SCENE(nfc, set_sak, SetSak) ADD_SCENE(nfc, set_atqa, SetAtqa) @@ -32,4 +35,4 @@ ADD_SCENE(nfc, set_uid, SetUid) ADD_SCENE(nfc, generate_info, GenerateInfo) -ADD_SCENE(nfc, not_implemented, NotImplemented) \ No newline at end of file +ADD_SCENE(nfc, not_implemented, NotImplemented) diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c new file mode 100644 index 000000000000..e9b135749c7a --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c @@ -0,0 +1,177 @@ +#include "../nfc_app_i.h" +#include + +#define TAG "NfcMfClassicDictAttack" + +typedef enum { + DictAttackStateIdle, + DictAttackStateUserDictInProgress, + DictAttackStateFlipperDictInProgress, +} DictAttackState; + +MfClassicPollerCommand nfc_dict_attack_worker_callback(MfClassicPollerEvent event, void* context) { + furi_assert(context); + + NfcApp* nfc_app = context; +} + +void nfc_dict_attack_dict_attack_result_callback(void* context) { + furi_assert(context); + NfcApp* nfc = context; + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventDictAttackSkip); +} + +static void nfc_scene_mf_classic_dict_attack_update_view(NfcApp* nfc) { + MfClassicData* data = &nfc->nfc_dev_data.mf_classic_data; + uint8_t sectors_read = 0; + uint8_t keys_found = 0; + + // Calculate found keys and read sectors + mifare_classic_get_read_sectors_and_keys(data, §ors_read, &keys_found); + dict_attack_set_keys_found(nfc->dict_attack, keys_found); + dict_attack_set_sector_read(nfc->dict_attack, sectors_read); +} + +static void nfc_scene_mf_classic_dict_attack_prepare_view(NfcApp* nfc, DictAttackState state) { + MfClassicData* data = &nfc->nfc_dev_data.mf_classic_data; + MfDict* dict = NULL; + + // Identify scene state + if(state == DictAttackStateIdle) { + if(mf_classic_dict_check_presence(MfDictTypeUser)) { + state = DictAttackStateUserDictInProgress; + } else { + state = DictAttackStateFlipperDictInProgress; + } + } else if(state == DictAttackStateUserDictInProgress) { + state = DictAttackStateFlipperDictInProgress; + } + + // Setup view + if(state == DictAttackStateUserDictInProgress) { + dict_attack_set_header(nfc->dict_attack, "MF Classic User Dictionary"); + dict = mf_classic_dict_alloc(MfDictTypeUser); + + // If failed to load user dictionary - try the system dictionary + if(!dict) { + FURI_LOG_E(TAG, "User dictionary not found"); + state = DictAttackStateFlipperDictInProgress; + } + } + if(state == DictAttackStateFlipperDictInProgress) { + dict_attack_set_header(nfc->dict_attack, "MF Classic System Dictionary"); + dict = mf_classic_dict_alloc(MfDictTypeSystem); + if(!dict) { + FURI_LOG_E(TAG, "Flipper dictionary not found"); + // Pass through to let the worker handle the failure + } + } + + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfClassicDictAttack, state); + dict_attack_set_callback(nfc->dict_attack, nfc_dict_attack_dict_attack_result_callback, nfc); + dict_attack_set_current_sector(nfc->dict_attack, 0); + dict_attack_set_card_detected(nfc->dict_attack, data->type); + dict_attack_set_total_dict_keys( + nfc->dict_attack, dict ? mf_classic_dict_get_total_keys(dict) : 0); + nfc_scene_mf_classic_dict_attack_update_view(nfc); + +} + +void nfc_scene_mf_classic_dict_attack_on_enter(void* context) { + NfcApp* nfc = context; + nfc_scene_mf_classic_dict_attack_prepare_view(nfc, DictAttackStateIdle); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDictAttack); + nfc_blink_read_start(nfc); + notification_message(nfc->notifications, &sequence_display_backlight_enforce_on); + mf_classic_poller_dict_attack(nfc->mf_classic_poller, nfc_dict_attack_worker_callback, nfc); +} + +bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + MfClassicData* data = &nfc->nfc_dev_data.mf_classic_data; + bool consumed = false; + + uint32_t state = + scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicDictAttack); + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcWorkerEventSuccess) { + if(state == DictAttackStateUserDictInProgress) { + nfc_worker_stop(nfc->worker); + nfc_scene_mf_classic_dict_attack_prepare_view(nfc, state); + consumed = true; + } else { + notification_message(nfc->notifications, &sequence_success); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSuccess); + DOLPHIN_DEED(DolphinDeedNfcReadSuccess); + consumed = true; + } + } else if(event.event == NfcWorkerEventAborted) { + if(state == DictAttackStateUserDictInProgress && + dict_attack_get_card_state(nfc->dict_attack)) { + nfc_scene_mf_classic_dict_attack_prepare_view(nfc, state); + consumed = true; + } else { + notification_message(nfc->notifications, &sequence_success); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSuccess); + // Counting failed attempts too + DOLPHIN_DEED(DolphinDeedNfcReadSuccess); + consumed = true; + } + } else if(event.event == NfcWorkerEventCardDetected) { + dict_attack_set_card_detected(nfc->dict_attack, data->type); + consumed = true; + } else if(event.event == NfcWorkerEventNoCardDetected) { + dict_attack_set_card_removed(nfc->dict_attack); + consumed = true; + } else if(event.event == NfcWorkerEventFoundKeyA) { + dict_attack_inc_keys_found(nfc->dict_attack); + consumed = true; + } else if(event.event == NfcWorkerEventFoundKeyB) { + dict_attack_inc_keys_found(nfc->dict_attack); + consumed = true; + } else if(event.event == NfcWorkerEventNewSector) { + nfc_scene_mf_classic_dict_attack_update_view(nfc); + dict_attack_inc_current_sector(nfc->dict_attack); + consumed = true; + } else if(event.event == NfcWorkerEventNewDictKeyBatch) { + nfc_scene_mf_classic_dict_attack_update_view(nfc); + dict_attack_inc_current_dict_key(nfc->dict_attack, NFC_DICT_KEY_BATCH_SIZE); + consumed = true; + } else if(event.event == NfcCustomEventDictAttackSkip) { + if(state == DictAttackStateUserDictInProgress) { + nfc_worker_stop(nfc->worker); + consumed = true; + } else if(state == DictAttackStateFlipperDictInProgress) { + nfc_worker_stop(nfc->worker); + consumed = true; + } + } else if(event.event == NfcWorkerEventKeyAttackStart) { + dict_attack_set_key_attack( + nfc->dict_attack, + true, + nfc->dev->dev_data.mf_classic_dict_attack_data.current_sector); + } else if(event.event == NfcWorkerEventKeyAttackStop) { + dict_attack_set_key_attack(nfc->dict_attack, false, 0); + } else if(event.event == NfcWorkerEventKeyAttackNextSector) { + dict_attack_inc_key_attack_current_sector(nfc->dict_attack); + } + } else if(event.type == SceneManagerEventTypeBack) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); + consumed = true; + } + return consumed; +} + +void nfc_scene_mf_classic_dict_attack_on_exit(void* context) { + NfcApp* nfc = context; + NfcMfClassicDictAttackData* dict_attack_data = &nfc->dev->dev_data.mf_classic_dict_attack_data; + // Stop worker + nfc_worker_stop(nfc->worker); + if(dict_attack_data->dict) { + mf_classic_dict_free(dict_attack_data->dict); + dict_attack_data->dict = NULL; + } + dict_attack_reset(nfc->dict_attack); + nfc_blink_stop(nfc); + notification_message(nfc->notifications, &sequence_display_backlight_enforce_auto); +} diff --git a/applications/main/nfc/views/dict_attack.h b/applications/main/nfc/views/dict_attack.h index 73b98a1b827b..940fb74e9685 100644 --- a/applications/main/nfc/views/dict_attack.h +++ b/applications/main/nfc/views/dict_attack.h @@ -3,7 +3,7 @@ #include #include -#include +#include typedef struct DictAttack DictAttack; diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller.c b/lib/nfc/protocols/mf_classic/mf_classic_poller.c index 670e4aff06d3..327cc2724648 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller.c @@ -41,7 +41,7 @@ MfClassicError mf_classic_poller_start( return MfClassicErrorNone; } -MfClassicError mf_classic_poller_read( +MfClassicError mf_classic_poller_dict_attack( MfClassicPoller* instance, MfClassicPollerCallback callback, void* context) { diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller.h b/lib/nfc/protocols/mf_classic/mf_classic_poller.h index d7c6180e159c..216a0e84be56 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller.h +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller.h @@ -13,8 +13,12 @@ typedef enum { MfClassicPollerEventTypeAuthRequest, MfClassicPollerEventTypeAuthSuccess, MfClassicPollerEventTypeAuthFailed, - MfClassicPollerEventTypeReadSuccess, - MfClassicPollerEventTypeReadFailed, + + MfClassicPollerEventTypeNewSector, + MfClassicPollerEventTypeFoundKeyA, + MfClassicPollerEventTypeFoundKeyB, + + MfClassicPollerEventTypeReadComplete, } MfClassicPollerEventType; typedef struct { @@ -44,7 +48,7 @@ MfClassicError mf_classic_poller_start( NfcaPollerEventCallback callback, void* context); -MfClassicError mf_classic_poller_read( +MfClassicError mf_classic_poller_dict_attack( MfClassicPoller* instance, MfClassicPollerCallback callback, void* context); diff --git a/lib/nfc/protocols/nfca/nfca.h b/lib/nfc/protocols/nfca/nfca.h index 18d07102b2e1..306e43fd794a 100644 --- a/lib/nfc/protocols/nfca/nfca.h +++ b/lib/nfc/protocols/nfca/nfca.h @@ -52,11 +52,16 @@ typedef struct { uint8_t sak; } NfcaSelResp; +typedef struct { + uint8_t sak; +} NfcaRats; + typedef struct { uint8_t uid[NFCA_MAX_UID_SIZE]; uint8_t uid_len; uint8_t atqa[2]; uint8_t sak; + NfcaRats rats; } NfcaData; uint16_t nfca_get_crc(uint8_t* buff, uint16_t len); From ba19dd4b454cc44f8708c97144d3840477573652 Mon Sep 17 00:00:00 2001 From: gornekich Date: Tue, 23 May 2023 17:32:40 +0400 Subject: [PATCH 092/149] mf classic: continue dict attack --- .../main/nfc/helpers/nfc_custom_event.h | 14 +- .../main/nfc/scenes/nfc_scene_config.h | 1 + .../scenes/nfc_scene_mf_classic_dict_attack.c | 122 ++++++----- .../nfc_scene_mf_classic_read_success.c | 79 ++++++++ applications/main/nfc/views/dict_attack.c | 2 +- lib/nfc/protocols/mf_classic/mf_classic.c | 85 ++++++++ lib/nfc/protocols/mf_classic/mf_classic.h | 9 + .../protocols/mf_classic/mf_classic_poller.c | 189 +++++++++++++++++- .../protocols/mf_classic/mf_classic_poller.h | 26 ++- .../mf_classic/mf_classic_poller_i.c | 4 + .../mf_classic/mf_classic_poller_i.h | 21 ++ 11 files changed, 496 insertions(+), 56 deletions(-) create mode 100644 applications/main/nfc/scenes/nfc_scene_mf_classic_read_success.c diff --git a/applications/main/nfc/helpers/nfc_custom_event.h b/applications/main/nfc/helpers/nfc_custom_event.h index 58546c3dd480..78b204222a44 100644 --- a/applications/main/nfc/helpers/nfc_custom_event.h +++ b/applications/main/nfc/helpers/nfc_custom_event.h @@ -4,13 +4,25 @@ enum NfcCustomEvent { // Reserve first 100 events for button types and indexes, starting from 0 NfcCustomEventReserved = 100, + // Mf classic dict attack events + NfcCustomEventDictAttackComplete, + NfcCustomEventDictAttackSkip, + NfcCustomEventDictAttackCardDetected, + NfcCustomEventDictAttackCardNotDetected, + NfcCustomEventDictAttackFoundKeyA, + NfcCustomEventDictAttackFoundKeyB, + NfcCustomEventDictAttackNewSector, + NfcCustomEventDictAttackNewKeyBatch, + NfcCustomEventDictAttackKeyAttackStart, + NfcCustomEventDictAttackKeyAttackStop, + NfcCustomEventDictAttackKeyAttackNextSector, + NfcCustomEventViewExit, NfcCustomEventWorkerExit, NfcCustomEventWorkerUpdate, NfcCustomEventByteInputDone, NfcCustomEventTextInputDone, NfcCustomEventDictAttackDone, - NfcCustomEventDictAttackSkip, NfcCustomEventRpcLoad, NfcCustomEventRpcSessionClose, }; diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index 5008819ab4a8..bb0da4c388ee 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -27,6 +27,7 @@ ADD_SCENE(nfc, mf_ultralight_key_input, MfUltralightKeyInput) ADD_SCENE(nfc, mf_ultralight_capture_pass, MfUltralightCapturePass) ADD_SCENE(nfc, mf_classic_dict_attack, MfClassicDictAttack) +ADD_SCENE(nfc, mf_classic_read_success, MfClassicReadSuccess) ADD_SCENE(nfc, set_type, SetType) ADD_SCENE(nfc, set_sak, SetSak) diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c index e9b135749c7a..527cf2ea76b3 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c @@ -13,6 +13,35 @@ MfClassicPollerCommand nfc_dict_attack_worker_callback(MfClassicPollerEvent even furi_assert(context); NfcApp* nfc_app = context; + if(event.type == MfClassicPollerEventTypeCardDetected) { + view_dispatcher_send_custom_event( + nfc_app->view_dispatcher, NfcCustomEventDictAttackCardDetected); + } else if(event.type == MfClassicPollerEventTypeCardNotDetected) { + view_dispatcher_send_custom_event( + nfc_app->view_dispatcher, NfcCustomEventDictAttackCardNotDetected); + } else if(event.type == MfClassicPollerEventTypeRequestKey) { + MfClassicKey key = { + .data = {0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5}, + }; + event.data->key_request_context.key = key; + event.data->key_request_context.key_provided = true; + } else if(event.type == MfClassicPollerEventTypeNewSector) { + view_dispatcher_send_custom_event( + nfc_app->view_dispatcher, NfcCustomEventDictAttackNewSector); + } else if(event.type == MfClassicPollerEventTypeFoundKeyA) { + view_dispatcher_send_custom_event( + nfc_app->view_dispatcher, NfcCustomEventDictAttackFoundKeyA); + } else if(event.type == MfClassicPollerEventTypeFoundKeyB) { + view_dispatcher_send_custom_event( + nfc_app->view_dispatcher, NfcCustomEventDictAttackFoundKeyB); + } else if(event.type == MfClassicPollerEventTypeReadComplete) { + view_dispatcher_send_custom_event( + nfc_app->view_dispatcher, NfcCustomEventDictAttackComplete); + } else if(event.type == MfClassicPollerEventTypeReadFail) { + // TODO + } + + return MfClassicPollerCommandContinue; } void nfc_dict_attack_dict_attack_result_callback(void* context) { @@ -27,7 +56,7 @@ static void nfc_scene_mf_classic_dict_attack_update_view(NfcApp* nfc) { uint8_t keys_found = 0; // Calculate found keys and read sectors - mifare_classic_get_read_sectors_and_keys(data, §ors_read, &keys_found); + mf_classic_get_read_sectors_and_keys(data, §ors_read, &keys_found); dict_attack_set_keys_found(nfc->dict_attack, keys_found); dict_attack_set_sector_read(nfc->dict_attack, sectors_read); } @@ -38,7 +67,7 @@ static void nfc_scene_mf_classic_dict_attack_prepare_view(NfcApp* nfc, DictAttac // Identify scene state if(state == DictAttackStateIdle) { - if(mf_classic_dict_check_presence(MfDictTypeUser)) { + if(mf_dict_check_presence(MfDictTypeUser)) { state = DictAttackStateUserDictInProgress; } else { state = DictAttackStateFlipperDictInProgress; @@ -50,7 +79,7 @@ static void nfc_scene_mf_classic_dict_attack_prepare_view(NfcApp* nfc, DictAttac // Setup view if(state == DictAttackStateUserDictInProgress) { dict_attack_set_header(nfc->dict_attack, "MF Classic User Dictionary"); - dict = mf_classic_dict_alloc(MfDictTypeUser); + dict = mf_dict_alloc(MfDictTypeUser); // If failed to load user dictionary - try the system dictionary if(!dict) { @@ -60,7 +89,7 @@ static void nfc_scene_mf_classic_dict_attack_prepare_view(NfcApp* nfc, DictAttac } if(state == DictAttackStateFlipperDictInProgress) { dict_attack_set_header(nfc->dict_attack, "MF Classic System Dictionary"); - dict = mf_classic_dict_alloc(MfDictTypeSystem); + dict = mf_dict_alloc(MfDictTypeSystem); if(!dict) { FURI_LOG_E(TAG, "Flipper dictionary not found"); // Pass through to let the worker handle the failure @@ -72,9 +101,8 @@ static void nfc_scene_mf_classic_dict_attack_prepare_view(NfcApp* nfc, DictAttac dict_attack_set_current_sector(nfc->dict_attack, 0); dict_attack_set_card_detected(nfc->dict_attack, data->type); dict_attack_set_total_dict_keys( - nfc->dict_attack, dict ? mf_classic_dict_get_total_keys(dict) : 0); + nfc->dict_attack, dict ? mf_dict_get_total_keys(dict) : 0); nfc_scene_mf_classic_dict_attack_update_view(nfc); - } void nfc_scene_mf_classic_dict_attack_on_enter(void* context) { @@ -94,66 +122,65 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicDictAttack); if(event.type == SceneManagerEventTypeCustom) { - if(event.event == NfcWorkerEventSuccess) { + if(event.event == MfClassicPollerEventTypeReadComplete) { if(state == DictAttackStateUserDictInProgress) { - nfc_worker_stop(nfc->worker); - nfc_scene_mf_classic_dict_attack_prepare_view(nfc, state); - consumed = true; - } else { - notification_message(nfc->notifications, &sequence_success); - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSuccess); - DOLPHIN_DEED(DolphinDeedNfcReadSuccess); - consumed = true; - } - } else if(event.event == NfcWorkerEventAborted) { - if(state == DictAttackStateUserDictInProgress && - dict_attack_get_card_state(nfc->dict_attack)) { nfc_scene_mf_classic_dict_attack_prepare_view(nfc, state); consumed = true; } else { notification_message(nfc->notifications, &sequence_success); scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSuccess); - // Counting failed attempts too DOLPHIN_DEED(DolphinDeedNfcReadSuccess); consumed = true; } - } else if(event.event == NfcWorkerEventCardDetected) { + // } else if(event.event == NfcWorkerEventAborted) { + // if(state == DictAttackStateUserDictInProgress && + // dict_attack_get_card_state(nfc->dict_attack)) { + // nfc_scene_mf_classic_dict_attack_prepare_view(nfc, state); + // consumed = true; + // } else { + // notification_message(nfc->notifications, &sequence_success); + // scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSuccess); + // // Counting failed attempts too + // DOLPHIN_DEED(DolphinDeedNfcReadSuccess); + // consumed = true; + // } + } else if(event.event == NfcCustomEventDictAttackCardDetected) { dict_attack_set_card_detected(nfc->dict_attack, data->type); consumed = true; - } else if(event.event == NfcWorkerEventNoCardDetected) { + } else if(event.event == NfcCustomEventDictAttackCardNotDetected) { dict_attack_set_card_removed(nfc->dict_attack); consumed = true; - } else if(event.event == NfcWorkerEventFoundKeyA) { + } else if(event.event == NfcCustomEventDictAttackFoundKeyA) { dict_attack_inc_keys_found(nfc->dict_attack); consumed = true; - } else if(event.event == NfcWorkerEventFoundKeyB) { + } else if(event.event == NfcCustomEventDictAttackFoundKeyB) { dict_attack_inc_keys_found(nfc->dict_attack); consumed = true; - } else if(event.event == NfcWorkerEventNewSector) { + } else if(event.event == NfcCustomEventDictAttackNewSector) { nfc_scene_mf_classic_dict_attack_update_view(nfc); dict_attack_inc_current_sector(nfc->dict_attack); consumed = true; - } else if(event.event == NfcWorkerEventNewDictKeyBatch) { - nfc_scene_mf_classic_dict_attack_update_view(nfc); - dict_attack_inc_current_dict_key(nfc->dict_attack, NFC_DICT_KEY_BATCH_SIZE); - consumed = true; + // } else if(event.event == NfcWorkerEventNewDictKeyBatch) { + // nfc_scene_mf_classic_dict_attack_update_view(nfc); + // dict_attack_inc_current_dict_key(nfc->dict_attack, NFC_DICT_KEY_BATCH_SIZE); + // consumed = true; } else if(event.event == NfcCustomEventDictAttackSkip) { if(state == DictAttackStateUserDictInProgress) { - nfc_worker_stop(nfc->worker); + mf_classic_poller_stop(nfc->mf_classic_poller); consumed = true; } else if(state == DictAttackStateFlipperDictInProgress) { - nfc_worker_stop(nfc->worker); + mf_classic_poller_stop(nfc->mf_classic_poller); consumed = true; } - } else if(event.event == NfcWorkerEventKeyAttackStart) { - dict_attack_set_key_attack( - nfc->dict_attack, - true, - nfc->dev->dev_data.mf_classic_dict_attack_data.current_sector); - } else if(event.event == NfcWorkerEventKeyAttackStop) { - dict_attack_set_key_attack(nfc->dict_attack, false, 0); - } else if(event.event == NfcWorkerEventKeyAttackNextSector) { - dict_attack_inc_key_attack_current_sector(nfc->dict_attack); + // } else if(event.event == NfcWorkerEventKeyAttackStart) { + // dict_attack_set_key_attack( + // nfc->dict_attack, + // true, + // nfc->dev->dev_data.mf_classic_dict_attack_data.current_sector); + // } else if(event.event == NfcWorkerEventKeyAttackStop) { + // dict_attack_set_key_attack(nfc->dict_attack, false, 0); + // } else if(event.event == NfcWorkerEventKeyAttackNextSector) { + // dict_attack_inc_key_attack_current_sector(nfc->dict_attack); } } else if(event.type == SceneManagerEventTypeBack) { scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); @@ -164,14 +191,15 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent void nfc_scene_mf_classic_dict_attack_on_exit(void* context) { NfcApp* nfc = context; - NfcMfClassicDictAttackData* dict_attack_data = &nfc->dev->dev_data.mf_classic_dict_attack_data; + // NfcMfClassicDictAttackData* dict_attack_data = &nfc->dev->dev_data.mf_classic_dict_attack_data; // Stop worker - nfc_worker_stop(nfc->worker); - if(dict_attack_data->dict) { - mf_classic_dict_free(dict_attack_data->dict); - dict_attack_data->dict = NULL; - } - dict_attack_reset(nfc->dict_attack); + // nfc_worker_stop(nfc->worker); + // if(dict_attack_data->dict) { + // mf_classic_dict_free(dict_attack_data->dict); + // dict_attack_data->dict = NULL; + // } + // dict_attack_reset(nfc->dict_attack); + mf_classic_poller_stop(nfc->mf_classic_poller); nfc_blink_stop(nfc); notification_message(nfc->notifications, &sequence_display_backlight_enforce_auto); } diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_read_success.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_read_success.c new file mode 100644 index 000000000000..e627aabc7158 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_read_success.c @@ -0,0 +1,79 @@ +#include "../nfc_app_i.h" + +void nfc_scene_mf_classic_read_success_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + furi_assert(context); + NfcApp* nfc = context; + + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); + } +} + +void nfc_scene_mf_classic_read_success_on_enter(void* context) { + NfcApp* nfc = context; + MfClassicData* mfc_data = &nfc->nfc_dev_data.mf_classic_data; + + // Setup view + Widget* widget = nfc->widget; + widget_add_button_element( + widget, GuiButtonTypeLeft, "Retry", nfc_scene_mf_classic_read_success_widget_callback, nfc); + widget_add_button_element( + widget, GuiButtonTypeRight, "More", nfc_scene_mf_classic_read_success_widget_callback, nfc); + + FuriString* temp_str = NULL; + // if(furi_string_size(nfc->dev->dev_data.parsed_data)) { + // temp_str = furi_string_alloc_set(nfc->dev->dev_data.parsed_data); + // } else { + // temp_str = furi_string_alloc_printf("\e#%s\n", nfc_mf_classic_type(mfc_data->type)); + furi_string_cat_printf(temp_str, "UID:"); + for(size_t i = 0; i < mfc_data->nfca_data.uid_len; i++) { + furi_string_cat_printf(temp_str, " %02X", mfc_data->nfca_data.uid[i]); + } + uint8_t sectors_total = mf_classic_get_total_sectors_num(mfc_data->type); + uint8_t keys_total = sectors_total * 2; + uint8_t keys_found = 0; + uint8_t sectors_read = 0; + mf_classic_get_read_sectors_and_keys(mfc_data, §ors_read, &keys_found); + furi_string_cat_printf(temp_str, "\nKeys Found: %d/%d", keys_found, keys_total); + furi_string_cat_printf(temp_str, "\nSectors Read: %d/%d", sectors_read, sectors_total); + // } + + 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_mf_classic_read_success_on_event(void* context, SceneManagerEvent event) { + NfcApp* 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, NfcSceneNotImplemented); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeBack) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); + consumed = true; + } + + return consumed; +} + +void nfc_scene_mf_classic_read_success_on_exit(void* context) { + NfcApp* nfc = context; + + notification_message_block(nfc->notifications, &sequence_reset_green); + + // Clear view + widget_reset(nfc->widget); +} diff --git a/applications/main/nfc/views/dict_attack.c b/applications/main/nfc/views/dict_attack.c index dd6b919f0899..8f4bd063e8b8 100644 --- a/applications/main/nfc/views/dict_attack.c +++ b/applications/main/nfc/views/dict_attack.c @@ -169,7 +169,7 @@ void dict_attack_set_card_detected(DictAttack* dict_attack, MfClassicType type) DictAttackViewModel * model, { model->state = DictAttackStateRead; - model->sectors_total = mifare_classic_get_total_sectors_num(type); + model->sectors_total = mf_classic_get_total_sectors_num(type); model->keys_total = model->sectors_total * 2; }, true); diff --git a/lib/nfc/protocols/mf_classic/mf_classic.c b/lib/nfc/protocols/mf_classic/mf_classic.c index cec14694932e..3002bbabb0ff 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic.c +++ b/lib/nfc/protocols/mf_classic/mf_classic.c @@ -54,6 +54,42 @@ const char* mf_classic_get_name(MfClassicType type, bool full_name) { return ret; } +bool mf_classic_detect_protocol(NfcaData* data, MfClassicType* type) { + furi_assert(data); + + uint8_t atqa0 = data->atqa[0]; + uint8_t atqa1 = data->atqa[1]; + uint8_t sak = data->sak; + bool mf_classic_detected = false; + + if((atqa0 = 0x44) || (atqa0 = 0x44)) { + if((sak == 0x08) || (sak = 0x88)) { + if(type) { + *type = MfClassicType1k; + } + mf_classic_detected = true; + } else if(sak == 0x09) { + if(type) { + *type = MfClassicTypeMini; + } + mf_classic_detected = true; + } + } else if((atqa0 == 0x01) && (atqa1 == 0x0f) && (sak == 0x01)) { + // Skylender support + if(type) { + *type = MfClassicType1k; + } + mf_classic_detected = true; + } else if(((atqa0 == 0x42) || (atqa0 == 0x02)) && (sak == 0x18)) { + if(*type) { + *type = MfClassicType4k; + } + mf_classic_detected = true; + } + + return mf_classic_detected; +} + uint8_t mf_classic_get_sector_trailer_num_by_sector(uint8_t sector) { uint8_t block_num = 0; @@ -168,3 +204,52 @@ void mf_classic_set_block_read(MfClassicData* data, uint8_t block_num, MfClassic } FURI_BIT_SET(data->block_read_mask[block_num / 32], block_num % 32); } + +uint8_t mf_classic_get_first_block_num_of_sector(uint8_t sector) { + furi_assert(sector < 40); + + uint8_t block = 0; + if(sector < 32) { + block = sector * 4; + } else { + block = 32 * 4 + (sector - 32) * 16; + } + + return block; +} + +static uint8_t mf_classic_get_blocks_num_in_sector(uint8_t sector) { + furi_assert(sector < 40); + return sector < 32 ? 4 : 16; +} + +void mf_classic_get_read_sectors_and_keys( + MfClassicData* data, + uint8_t* sectors_read, + uint8_t* keys_found) { + furi_assert(data); + furi_assert(sectors_read); + furi_assert(keys_found); + + *sectors_read = 0; + *keys_found = 0; + uint8_t sectors_total = mf_classic_get_total_sectors_num(data->type); + for(size_t i = 0; i < sectors_total; i++) { + if(mf_classic_is_key_found(data, i, MfClassicKeyTypeA)) { + *keys_found += 1; + } + if(mf_classic_is_key_found(data, i, MfClassicKeyTypeB)) { + *keys_found += 1; + } + uint8_t first_block = mf_classic_get_first_block_num_of_sector(i); + uint8_t total_blocks_in_sec = mf_classic_get_blocks_num_in_sector(i); + bool blocks_read = true; + for(size_t j = first_block; j < first_block + total_blocks_in_sec; j++) { + blocks_read = mf_classic_is_block_read(data, j); + if(!blocks_read) break; + } + if(blocks_read) { + *sectors_read += 1; + } + } +} diff --git a/lib/nfc/protocols/mf_classic/mf_classic.h b/lib/nfc/protocols/mf_classic/mf_classic.h index 63f09886d668..deacee1d8874 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic.h +++ b/lib/nfc/protocols/mf_classic/mf_classic.h @@ -108,10 +108,14 @@ typedef struct { MfClassicBlock block[MF_CLASSIC_TOTAL_BLOCKS_MAX]; } MfClassicData; +bool mf_classic_detect_protocol(NfcaData* data, MfClassicType* type); + uint8_t mf_classic_get_total_sectors_num(MfClassicType type); uint16_t mf_classic_get_total_block_num(MfClassicType type); +uint8_t mf_classic_get_first_block_num_of_sector(uint8_t sector); + const char* mf_classic_get_name(MfClassicType type, bool full_name); uint8_t mf_classic_get_sector_trailer_num_by_sector(uint8_t sector); @@ -142,6 +146,11 @@ bool mf_classic_is_block_read(MfClassicData* data, uint8_t block_num); void mf_classic_set_block_read(MfClassicData* data, uint8_t block_num, MfClassicBlock* block_data); +void mf_classic_get_read_sectors_and_keys( + MfClassicData* data, + uint8_t* sectors_read, + uint8_t* keys_found); + #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller.c b/lib/nfc/protocols/mf_classic/mf_classic_poller.c index 327cc2724648..91ac68b205a1 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller.c @@ -2,8 +2,28 @@ #include +#define TAG "MfClassicPoller" + #define MF_CLASSIC_MAX_BUFF_SIZE (64) +typedef MfClassicPollerCommand (*MfClassicPollerReadHandler)(MfClassicPoller* instance); + +static NfcaPollerCommand mf_classic_process_command(MfClassicPollerCommand command) { + NfcaPollerCommand ret = NfcaPollerCommandContinue; + + if(command == MfClassicPollerCommandContinue) { + ret = NfcaPollerCommandContinue; + } else if(command == MfClassicPollerCommandReset) { + ret = NfcaPollerCommandReset; + } else if(command == MfClassicPollerCommandStop) { + ret = NfcaPollerCommandStop; + } else { + furi_crash("Unknown command"); + } + + return ret; +} + MfClassicPoller* mf_classic_poller_alloc(NfcaPoller* nfca_poller) { furi_assert(nfca_poller); @@ -41,6 +61,172 @@ MfClassicError mf_classic_poller_start( return MfClassicErrorNone; } +MfClassicPollerCommand mf_classic_poller_dict_attack_handler_idle(MfClassicPoller* instance) { + nfc_poller_buffer_reset(instance->plain_buff); + nfc_poller_buffer_reset(instance->encrypted_buff); + nfca_poller_get_data(instance->nfca_poller, &instance->data->nfca_data); + instance->sectors_read = 0; + MfClassicPollerCommand command = MfClassicPollerCommandContinue; + MfClassicPollerEvent event = {}; + + if(mf_classic_detect_protocol(&instance->data->nfca_data, &instance->data->type)) { + if(instance->card_state == MfClassicCardStateNotDetected) { + instance->card_state = MfClassicCardStateDetected; + instance->event_data.detect_context.type = instance->data->type; + event.type = MfClassicPollerEventTypeCardDetected; + event.data = &instance->event_data; + command = instance->callback(event, instance->context); + } + instance->sectors_total = mf_classic_get_total_sectors_num(instance->data->type); + instance->state = MfClassicPollerStateRequestKey; + } else { + instance->state = MfClassicPollerStateReadFail; + } + + return command; +} + +MfClassicPollerCommand + mf_classic_poller_dict_attack_handler_request_key(MfClassicPoller* instance) { + MfClassicPollerCommand command = MfClassicPollerCommandContinue; + MfClassicPollerEvent event = {}; + + FURI_LOG_D(TAG, "New key request"); + event.type = MfClassicPollerEventTypeRequestKey; + event.data = &instance->event_data; + instance->event_data.key_request_context.sector_num = instance->sectors_read; + command = instance->callback(event, instance->context); + if(instance->event_data.key_request_context.key_provided) { + instance->current_key = instance->event_data.key_request_context.key; + instance->state = MfClassicPollerStateAuthKeyA; + uint64_t key = nfc_util_bytes2num(instance->current_key.data, 6); + FURI_LOG_D(TAG, "Received key: %06llx", key); + } else { + instance->state = MfClassicPollerStateNextSector; + } + + return command; +} + +MfClassicPollerCommand + mf_classic_poller_dict_attack_handler_new_sector(MfClassicPoller* instance) { + MfClassicPollerCommand command = MfClassicPollerCommandContinue; + MfClassicPollerEvent event = {}; + + if(instance->sectors_read == instance->sectors_total) { + instance->state = MfClassicPollerStateReadSuccess; + } else { + instance->sectors_read++; + if(instance->sectors_read == instance->sectors_total) { + instance->state = MfClassicPollerStateReadSuccess; + } else { + event.type = MfClassicPollerEventTypeNewSector; + command = instance->callback(event, instance->context); + instance->state = MfClassicPollerStateRequestKey; + } + } + + return command; +} + +MfClassicPollerCommand mf_classic_poller_dict_attack_handler_auth_a(MfClassicPoller* instance) { + MfClassicPollerCommand command = MfClassicPollerCommandContinue; + MfClassicPollerEvent event = {}; + + uint8_t block = mf_classic_get_first_block_num_of_sector(instance->sectors_read); + MfClassicError error = + mf_classic_async_auth(instance, block, &instance->current_key, MfClassicKeyTypeA, NULL); + if(error == MfClassicErrorNone) { + FURI_LOG_D(TAG, "Key A found"); + event.type = MfClassicPollerEventTypeFoundKeyA; + command = instance->callback(event, instance->context); + // TODO read here + instance->state = MfClassicPollerStateRequestKey; + } else { + instance->state = MfClassicPollerStateAuthKeyB; + } + + return command; +} + +MfClassicPollerCommand mf_classic_poller_dict_attack_handler_auth_b(MfClassicPoller* instance) { + MfClassicPollerCommand command = MfClassicPollerCommandContinue; + MfClassicPollerEvent event = {}; + + uint8_t block = mf_classic_get_first_block_num_of_sector(instance->sectors_read); + MfClassicError error = + mf_classic_async_auth(instance, block, &instance->current_key, MfClassicKeyTypeB, NULL); + if(error == MfClassicErrorNone) { + FURI_LOG_D(TAG, "Key B found"); + event.type = MfClassicPollerEventTypeFoundKeyB; + command = instance->callback(event, instance->context); + // TODO read here + instance->state = MfClassicPollerStateRequestKey; + } else { + instance->state = MfClassicPollerStateRequestKey; + } + + return command; +} + +MfClassicPollerCommand mf_classic_poller_dict_attack_handler_read_fail(MfClassicPoller* instance) { + MfClassicPollerCommand command = MfClassicPollerCommandContinue; + MfClassicPollerEvent event = {.type = MfClassicPollerEventTypeReadFail}; + command = instance->callback(event, instance->context); + instance->state = MfClassicPollerStateIdle; + + return command; +} + +MfClassicPollerCommand + mf_classic_poller_dict_attack_handler_read_success(MfClassicPoller* instance) { + MfClassicPollerCommand command = MfClassicPollerCommandContinue; + MfClassicPollerEvent event = {.type = MfClassicPollerEventTypeReadComplete}; + command = instance->callback(event, instance->context); + instance->state = MfClassicPollerStateIdle; + + return command; +} + +static const MfClassicPollerReadHandler + mf_classic_poller_dict_attack_handler[MfClassicPollerStateNum] = { + [MfClassicPollerStateIdle] = mf_classic_poller_dict_attack_handler_idle, + [MfClassicPollerStateRequestKey] = mf_classic_poller_dict_attack_handler_request_key, + [MfClassicPollerStateNextSector] = mf_classic_poller_dict_attack_handler_new_sector, + [MfClassicPollerStateAuthKeyA] = mf_classic_poller_dict_attack_handler_auth_a, + [MfClassicPollerStateAuthKeyB] = mf_classic_poller_dict_attack_handler_auth_b, + [MfClassicPollerStateReadFail] = mf_classic_poller_dict_attack_handler_read_fail, + [MfClassicPollerStateReadSuccess] = mf_classic_poller_dict_attack_handler_read_success, +}; + +NfcaPollerCommand mf_classic_dict_attack_callback(NfcaPollerEvent event, void* context) { + furi_assert(context); + MfClassicPoller* instance = context; + furi_assert(instance->callback); + MfClassicPollerCommand command = MfClassicPollerCommandContinue; + MfClassicPollerEvent mfc_event = {}; + + furi_assert(instance->session_state != MfClassicPollerSessionStateIdle); + + if(instance->session_state == MfClassicPollerSessionStateStopRequest) { + command = MfClassicPollerCommandStop; + } else { + if(event.type == NfcaPollerEventTypeReady) { + command = mf_classic_poller_dict_attack_handler[instance->state](instance); + } else if(event.type == NfcaPollerEventTypeError) { + if(event.data.error == NfcaErrorNotPresent) { + if(instance->card_state == MfClassicCardStateDetected) { + instance->card_state = MfClassicCardStateNotDetected; + mfc_event.type = MfClassicPollerEventTypeCardNotDetected; + command = instance->callback(mfc_event, instance->context); + } + } + } + } + + return mf_classic_process_command(command); +} + MfClassicError mf_classic_poller_dict_attack( MfClassicPoller* instance, MfClassicPollerCallback callback, @@ -50,8 +236,9 @@ MfClassicError mf_classic_poller_dict_attack( instance->callback = callback; instance->context = context; + instance->state = MfClassicPollerStateIdle; - return MfClassicErrorNone; + return mf_classic_poller_start(instance, mf_classic_dict_attack_callback, instance); } MfClassicError mf_classic_poller_get_data(MfClassicPoller* instance, MfClassicData* data) { diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller.h b/lib/nfc/protocols/mf_classic/mf_classic_poller.h index 216a0e84be56..98c44822fcc3 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller.h +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller.h @@ -10,24 +10,38 @@ extern "C" { typedef struct MfClassicPoller MfClassicPoller; typedef enum { - MfClassicPollerEventTypeAuthRequest, - MfClassicPollerEventTypeAuthSuccess, - MfClassicPollerEventTypeAuthFailed, - + MfClassicPollerEventTypeRequestKey, MfClassicPollerEventTypeNewSector, MfClassicPollerEventTypeFoundKeyA, MfClassicPollerEventTypeFoundKeyB, - + MfClassicPollerEventTypeCardDetected, + MfClassicPollerEventTypeCardNotDetected, + MfClassicPollerEventTypeKeyAttackStart, + MfClassicPollerEventTypeKeyAttackStop, + MfClassicPollerEventTypeKeyAttackNextSector, MfClassicPollerEventTypeReadComplete, + MfClassicPollerEventTypeReadFail, } MfClassicPollerEventType; typedef struct { + uint8_t sector_num; + MfClassicKey key; + bool key_provided; +} MfClassicKeyRequestContext; + +typedef struct { + MfClassicType type; +} MfClassicDetectContext; + +typedef union { MfClassicError error; + MfClassicDetectContext detect_context; + MfClassicKeyRequestContext key_request_context; } MfClassicPollerEventData; typedef struct { MfClassicPollerEventType type; - MfClassicPollerEventData data; + MfClassicPollerEventData* data; } MfClassicPollerEvent; typedef enum { diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c index 061b08564179..ed109796b092 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c @@ -132,6 +132,10 @@ MfClassicError mf_classic_async_auth( } } while(false); + if(ret != MfClassicErrorNone) { + nfca_poller_halt(instance->nfca_poller); + } + return ret; } diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h index 129885ebdcf4..2f7565a19a87 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h @@ -21,14 +21,35 @@ typedef enum { MfClassicAuthStatePassed, } MfClassicAuthState; +typedef enum { + MfClassicCardStateNotDetected, + MfClassicCardStateDetected, +} MfClassicCardState; + typedef enum { MfClassicPollerStateIdle, + MfClassicPollerStateRequestKey, + MfClassicPollerStateAuthKeyA, + MfClassicPollerStateAuthKeyB, + MfClassicPollerStateReadSector, + MfClassicPollerStateNextSector, + + MfClassicPollerStateReadFail, + MfClassicPollerStateReadSuccess, + + MfClassicPollerStateNum, } MfClassicPollerState; struct MfClassicPoller { NfcaPoller* nfca_poller; + MfClassicPollerState state; MfClassicPollerSessionState session_state; MfClassicAuthState auth_state; + MfClassicCardState card_state; + MfClassicKey current_key; + MfClassicPollerEventData event_data; + uint8_t sectors_read; + uint8_t sectors_total; Crypto1* crypto; NfcPollerBuffer* plain_buff; NfcPollerBuffer* encrypted_buff; From bc6d12f5c0ebefe5dccfac96629f72d406ef8869 Mon Sep 17 00:00:00 2001 From: gornekich Date: Tue, 23 May 2023 18:46:04 +0400 Subject: [PATCH 093/149] mf classic: fix buffer reset --- .../main/nfc/helpers/mf_classic_dict_attack.c | 17 +++ .../main/nfc/helpers/mf_classic_dict_attack.h | 15 ++ applications/main/nfc/helpers/mf_dict.h | 8 + applications/main/nfc/nfc_app.c | 2 +- .../scenes/nfc_scene_mf_classic_dict_attack.c | 1 + .../nfc/scenes/nfc_scene_read_card_type.c | 16 +- lib/nfc/protocols/mf_classic/mf_classic.c | 20 +++ lib/nfc/protocols/mf_classic/mf_classic.h | 4 + .../protocols/mf_classic/mf_classic_poller.c | 139 ++++++++++-------- .../protocols/mf_classic/mf_classic_poller.h | 17 ++- .../mf_classic/mf_classic_poller_i.c | 43 ++++++ .../mf_classic/mf_classic_poller_i.h | 17 ++- 12 files changed, 217 insertions(+), 82 deletions(-) create mode 100644 applications/main/nfc/helpers/mf_classic_dict_attack.c create mode 100644 applications/main/nfc/helpers/mf_classic_dict_attack.h diff --git a/applications/main/nfc/helpers/mf_classic_dict_attack.c b/applications/main/nfc/helpers/mf_classic_dict_attack.c new file mode 100644 index 000000000000..39b18dbc1eef --- /dev/null +++ b/applications/main/nfc/helpers/mf_classic_dict_attack.c @@ -0,0 +1,17 @@ +#include "mf_classic_dict_attack.h" + +struct MfClassicDictAttack { + +}; + +MfClassicDictAttack* mf_classic_dict_attack_alloc() { + MfClassicDictAttack* instance = malloc(sizeof(MfClassicDictAttack)); + + return instance; +} + +void mf_classic_dict_attack_free(MfClassicDictAttack* instance) { + furi_assert(instance); + + free(instance); +} diff --git a/applications/main/nfc/helpers/mf_classic_dict_attack.h b/applications/main/nfc/helpers/mf_classic_dict_attack.h new file mode 100644 index 000000000000..af80668fa4b7 --- /dev/null +++ b/applications/main/nfc/helpers/mf_classic_dict_attack.h @@ -0,0 +1,15 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct MfClassicDictAttack MfClassicDictAttack; + +MfClassicDictAttack* mf_classic_dict_attack_alloc(); + +void mf_classic_dict_attack_free(MfClassicDictAttack* instance); + +#ifdef __cplusplus +} +#endif diff --git a/applications/main/nfc/helpers/mf_dict.h b/applications/main/nfc/helpers/mf_dict.h index 730b6f9da2fa..99ce31cf8ac5 100644 --- a/applications/main/nfc/helpers/mf_dict.h +++ b/applications/main/nfc/helpers/mf_dict.h @@ -6,6 +6,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + typedef enum { MfDictTypeUser, MfDictTypeSystem, @@ -97,3 +101,7 @@ bool mf_dict_find_index_str(MfDict* dict, FuriString* key, uint32_t* target); * @return true on success */ bool mf_dict_delete_index(MfDict* dict, uint32_t target); + +#ifdef __cplusplus +} +#endif diff --git a/applications/main/nfc/nfc_app.c b/applications/main/nfc/nfc_app.c index c65bf1147e28..fb177430a574 100644 --- a/applications/main/nfc/nfc_app.c +++ b/applications/main/nfc/nfc_app.c @@ -497,7 +497,7 @@ int32_t nfc_app(void* p) { } else { view_dispatcher_attach_to_gui( nfc->view_dispatcher, nfc->gui, ViewDispatcherTypeFullscreen); - scene_manager_next_scene(nfc->scene_manager, NfcSceneStart); + scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardType); } view_dispatcher_run(nfc->view_dispatcher); diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c index 527cf2ea76b3..a5cb57a204b0 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c @@ -20,6 +20,7 @@ MfClassicPollerCommand nfc_dict_attack_worker_callback(MfClassicPollerEvent even view_dispatcher_send_custom_event( nfc_app->view_dispatcher, NfcCustomEventDictAttackCardNotDetected); } else if(event.type == MfClassicPollerEventTypeRequestKey) { + MfClassicKey key = { .data = {0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5}, }; diff --git a/applications/main/nfc/scenes/nfc_scene_read_card_type.c b/applications/main/nfc/scenes/nfc_scene_read_card_type.c index 97c11a32493f..a07a502b5f08 100644 --- a/applications/main/nfc/scenes/nfc_scene_read_card_type.c +++ b/applications/main/nfc/scenes/nfc_scene_read_card_type.c @@ -1,9 +1,9 @@ #include "../nfc_app_i.h" enum SubmenuIndex { + SubmenuIndexReadMifareClassic, SubmenuIndexReadNFCA, SubmenuIndexReadMfUltralight, - SubmenuIndexReadMifareClassic, SubmenuIndexReadMifareDesfire, SubmenuIndexReadEMV, }; @@ -20,20 +20,20 @@ void nfc_scene_read_card_type_on_enter(void* context) { submenu_add_item( submenu, - "Read NFC-A data", - SubmenuIndexReadNFCA, + "Read Mifare Classic", + SubmenuIndexReadMifareClassic, nfc_scene_read_card_type_submenu_callback, nfc); submenu_add_item( submenu, - "Read NTAG/Ultralight", - SubmenuIndexReadMfUltralight, + "Read NFC-A data", + SubmenuIndexReadNFCA, nfc_scene_read_card_type_submenu_callback, nfc); submenu_add_item( submenu, - "Read Mifare Classic", - SubmenuIndexReadMifareClassic, + "Read NTAG/Ultralight", + SubmenuIndexReadMfUltralight, nfc_scene_read_card_type_submenu_callback, nfc); submenu_add_item( @@ -60,7 +60,7 @@ bool nfc_scene_read_card_type_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubmenuIndexReadMifareClassic) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicDictAttack); consumed = true; } if(event.event == SubmenuIndexReadMifareDesfire) { diff --git a/lib/nfc/protocols/mf_classic/mf_classic.c b/lib/nfc/protocols/mf_classic/mf_classic.c index 3002bbabb0ff..a5883aec24ae 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic.c +++ b/lib/nfc/protocols/mf_classic/mf_classic.c @@ -253,3 +253,23 @@ void mf_classic_get_read_sectors_and_keys( } } } + +bool mf_classic_is_sector_read(MfClassicData* data, uint8_t sector_num) { + furi_assert(data); + + bool sector_read = false; + do { + if(!mf_classic_is_key_found(data, sector_num, MfClassicKeyTypeA)) break; + if(!mf_classic_is_key_found(data, sector_num, MfClassicKeyTypeB)) break; + uint8_t start_block = mf_classic_get_first_block_num_of_sector(sector_num); + uint8_t total_blocks = mf_classic_get_blocks_num_in_sector(sector_num); + uint8_t block_read = true; + for(size_t i = start_block; i < start_block + total_blocks; i++) { + block_read = mifare_classic_is_block_read(data, i); + if(!block_read) break; + } + sector_read = block_read; + } while(false); + + return sector_read; +} diff --git a/lib/nfc/protocols/mf_classic/mf_classic.h b/lib/nfc/protocols/mf_classic/mf_classic.h index deacee1d8874..658d662d37ef 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic.h +++ b/lib/nfc/protocols/mf_classic/mf_classic.h @@ -9,6 +9,8 @@ extern "C" { #define MF_CLASSIC_AUTH_KEY_A_CMD (0x60U) #define MF_CLASSIC_AUTH_KEY_B_CMD (0x61U) #define MF_CLASSIC_READ_BLOCK_CMD (0x30U) +#define MF_CLASSIC_HALT_MSB_CMD (0x50) +#define MF_CLASSIC_HALT_LSB_CMD (0x00) #define MF_CLASSIC_TOTAL_BLOCKS_MAX (256) #define MF_CLASSIC_BLOCK_SIZE (16) @@ -146,6 +148,8 @@ bool mf_classic_is_block_read(MfClassicData* data, uint8_t block_num); void mf_classic_set_block_read(MfClassicData* data, uint8_t block_num, MfClassicBlock* block_data); +bool mf_classic_is_sector_read(MfClassicData* data, uint8_t sector_num); + void mf_classic_get_read_sectors_and_keys( MfClassicData* data, uint8_t* sectors_read, diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller.c b/lib/nfc/protocols/mf_classic/mf_classic_poller.c index 91ac68b205a1..194ead3f37a2 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller.c @@ -13,6 +13,8 @@ static NfcaPollerCommand mf_classic_process_command(MfClassicPollerCommand comma if(command == MfClassicPollerCommandContinue) { ret = NfcaPollerCommandContinue; + } else if(command == MfClassicPollerCommandContinue) { + ret = NfcaPollerCommandContinue; } else if(command == MfClassicPollerCommandReset) { ret = NfcaPollerCommandReset; } else if(command == MfClassicPollerCommandStop) { @@ -61,99 +63,112 @@ MfClassicError mf_classic_poller_start( return MfClassicErrorNone; } -MfClassicPollerCommand mf_classic_poller_dict_attack_handler_idle(MfClassicPoller* instance) { - nfc_poller_buffer_reset(instance->plain_buff); - nfc_poller_buffer_reset(instance->encrypted_buff); +MfClassicPollerCommand mf_classic_poller_handler_idle(MfClassicPoller* instance) { nfca_poller_get_data(instance->nfca_poller, &instance->data->nfca_data); - instance->sectors_read = 0; MfClassicPollerCommand command = MfClassicPollerCommandContinue; MfClassicPollerEvent event = {}; if(mf_classic_detect_protocol(&instance->data->nfca_data, &instance->data->type)) { if(instance->card_state == MfClassicCardStateNotDetected) { instance->card_state = MfClassicCardStateDetected; - instance->event_data.detect_context.type = instance->data->type; event.type = MfClassicPollerEventTypeCardDetected; - event.data = &instance->event_data; command = instance->callback(event, instance->context); } - instance->sectors_total = mf_classic_get_total_sectors_num(instance->data->type); - instance->state = MfClassicPollerStateRequestKey; - } else { - instance->state = MfClassicPollerStateReadFail; + instance->state = instance->prev_state; } return command; } -MfClassicPollerCommand - mf_classic_poller_dict_attack_handler_request_key(MfClassicPoller* instance) { +MfClassicPollerCommand mf_classic_poller_handler_start(MfClassicPoller* instance) { MfClassicPollerCommand command = MfClassicPollerCommandContinue; - MfClassicPollerEvent event = {}; - FURI_LOG_D(TAG, "New key request"); - event.type = MfClassicPollerEventTypeRequestKey; - event.data = &instance->event_data; - instance->event_data.key_request_context.sector_num = instance->sectors_read; + instance->sectors_read = 0; + instance->sectors_total = mf_classic_get_total_sectors_num(instance->data->type); + instance->event_data.start_data.total_sectors = instance->sectors_total; + MfClassicPollerEvent event = { + .type = MfClassicPollerEventTypeStart, + .data = &instance->event_data, + }; command = instance->callback(event, instance->context); - if(instance->event_data.key_request_context.key_provided) { - instance->current_key = instance->event_data.key_request_context.key; - instance->state = MfClassicPollerStateAuthKeyA; - uint64_t key = nfc_util_bytes2num(instance->current_key.data, 6); - FURI_LOG_D(TAG, "Received key: %06llx", key); - } else { - instance->state = MfClassicPollerStateNextSector; - } + instance->prev_state = MfClassicPollerStateStart; + instance->state = MfClassicPollerStateNewSector; return command; } -MfClassicPollerCommand - mf_classic_poller_dict_attack_handler_new_sector(MfClassicPoller* instance) { +MfClassicPollerCommand mf_classic_poller_handler_new_sector(MfClassicPoller* instance) { MfClassicPollerCommand command = MfClassicPollerCommandContinue; MfClassicPollerEvent event = {}; if(instance->sectors_read == instance->sectors_total) { - instance->state = MfClassicPollerStateReadSuccess; - } else { + instance->state = MfClassicPollerStateReadComplete; + } else if(mf_classic_is_sector_read(instance->data, instance->sectors_read)) { instance->sectors_read++; - if(instance->sectors_read == instance->sectors_total) { - instance->state = MfClassicPollerStateReadSuccess; - } else { - event.type = MfClassicPollerEventTypeNewSector; - command = instance->callback(event, instance->context); - instance->state = MfClassicPollerStateRequestKey; - } + event.type = MfClassicPollerEventTypeNewSector; + command = instance->callback(event, instance->context); + } else { + instance->state = MfClassicPollerStateRequestKey; } return command; } -MfClassicPollerCommand mf_classic_poller_dict_attack_handler_auth_a(MfClassicPoller* instance) { +MfClassicPollerCommand mf_classic_poller_handler_request_key(MfClassicPoller* instance) { MfClassicPollerCommand command = MfClassicPollerCommandContinue; - MfClassicPollerEvent event = {}; - uint8_t block = mf_classic_get_first_block_num_of_sector(instance->sectors_read); - MfClassicError error = - mf_classic_async_auth(instance, block, &instance->current_key, MfClassicKeyTypeA, NULL); - if(error == MfClassicErrorNone) { - FURI_LOG_D(TAG, "Key A found"); - event.type = MfClassicPollerEventTypeFoundKeyA; - command = instance->callback(event, instance->context); - // TODO read here - instance->state = MfClassicPollerStateRequestKey; + instance->event_data.key_request_data.sector_num = instance->sectors_read; + MfClassicPollerEvent event = { + .type = MfClassicPollerEventTypeRequestKey, + .data = &instance->event_data, + }; + command = instance->callback(event, instance->context); + if(instance->event_data.key_request_data.key_provided) { + instance->current_key = instance->event_data.key_request_data.key; + instance->state = MfClassicPollerStateAuthKeyA; } else { + instance->state = MfClassicPollerStateNewSector; + } + + return command; +} + +MfClassicPollerCommand mf_classic_poller_handler_auth_a(MfClassicPoller* instance) { + MfClassicPollerCommand command = MfClassicPollerCommandContinue; + MfClassicPollerEvent event = {}; + + if(mf_classic_is_key_found(instance->data, instance->sectors_read, MfClassicKeyTypeA)) { + instance->prev_state = instance->state; instance->state = MfClassicPollerStateAuthKeyB; + } else { + uint8_t block = mf_classic_get_first_block_num_of_sector(instance->sectors_read); + uint64_t key = nfc_util_bytes2num(instance->current_key.data, 6); + FURI_LOG_D(TAG, "Auth to block %d with key A: %06llx", block, key); + MfClassicError error = mf_classic_async_auth( + instance, block, &instance->current_key, MfClassicKeyTypeA, NULL); + if(error == MfClassicErrorNone) { + FURI_LOG_I(TAG, "Key A found"); + mf_classic_set_key_found( + instance->data, instance->sectors_read, MfClassicKeyTypeA, key); + event.type = MfClassicPollerEventTypeFoundKeyA; + command = instance->callback(event, instance->context); + instance->prev_state = instance->state; + instance->state = MfClassicPollerStateReadSector; + } else { + instance->state = MfClassicPollerStateAuthKeyB; + } } return command; } -MfClassicPollerCommand mf_classic_poller_dict_attack_handler_auth_b(MfClassicPoller* instance) { +MfClassicPollerCommand mf_classic_poller_handler_auth_b(MfClassicPoller* instance) { MfClassicPollerCommand command = MfClassicPollerCommandContinue; MfClassicPollerEvent event = {}; uint8_t block = mf_classic_get_first_block_num_of_sector(instance->sectors_read); + uint64_t key = nfc_util_bytes2num(instance->current_key.data, 6); + FURI_LOG_D(TAG, "Auth to block %d with key B: %06llx", block, key); MfClassicError error = mf_classic_async_auth(instance, block, &instance->current_key, MfClassicKeyTypeB, NULL); if(error == MfClassicErrorNone) { @@ -169,34 +184,36 @@ MfClassicPollerCommand mf_classic_poller_dict_attack_handler_auth_b(MfClassicPol return command; } -MfClassicPollerCommand mf_classic_poller_dict_attack_handler_read_fail(MfClassicPoller* instance) { +MfClassicPollerCommand mf_classic_poller_handler_read_sector(MfClassicPoller* instance) { MfClassicPollerCommand command = MfClassicPollerCommandContinue; - MfClassicPollerEvent event = {.type = MfClassicPollerEventTypeReadFail}; + MfClassicPollerEvent event = {.type = MfClassicPollerEventTypeReadComplete}; command = instance->callback(event, instance->context); instance->state = MfClassicPollerStateIdle; return command; } -MfClassicPollerCommand - mf_classic_poller_dict_attack_handler_read_success(MfClassicPoller* instance) { +MfClassicPollerCommand mf_classic_poller_handler_read_complete(MfClassicPoller* instance) { MfClassicPollerCommand command = MfClassicPollerCommandContinue; MfClassicPollerEvent event = {.type = MfClassicPollerEventTypeReadComplete}; command = instance->callback(event, instance->context); - instance->state = MfClassicPollerStateIdle; + if(command == MfClassicPollerCommandRestart) { + instance->state = MfClassicPollerStateStart; + } return command; } static const MfClassicPollerReadHandler mf_classic_poller_dict_attack_handler[MfClassicPollerStateNum] = { - [MfClassicPollerStateIdle] = mf_classic_poller_dict_attack_handler_idle, - [MfClassicPollerStateRequestKey] = mf_classic_poller_dict_attack_handler_request_key, - [MfClassicPollerStateNextSector] = mf_classic_poller_dict_attack_handler_new_sector, - [MfClassicPollerStateAuthKeyA] = mf_classic_poller_dict_attack_handler_auth_a, - [MfClassicPollerStateAuthKeyB] = mf_classic_poller_dict_attack_handler_auth_b, - [MfClassicPollerStateReadFail] = mf_classic_poller_dict_attack_handler_read_fail, - [MfClassicPollerStateReadSuccess] = mf_classic_poller_dict_attack_handler_read_success, + [MfClassicPollerStateIdle] = mf_classic_poller_handler_idle, + [MfClassicPollerStateStart] = mf_classic_poller_handler_start, + [MfClassicPollerStateNewSector] = mf_classic_poller_handler_new_sector, + [MfClassicPollerStateRequestKey] = mf_classic_poller_handler_request_key, + [MfClassicPollerStateAuthKeyA] = mf_classic_poller_handler_auth_a, + [MfClassicPollerStateAuthKeyB] = mf_classic_poller_handler_auth_b, + [MfClassicPollerStateReadSector] = mf_classic_poller_handler_read_sector, + [MfClassicPollerStateReadComplete] = mf_classic_poller_handler_read_complete, }; NfcaPollerCommand mf_classic_dict_attack_callback(NfcaPollerEvent event, void* context) { @@ -219,6 +236,7 @@ NfcaPollerCommand mf_classic_dict_attack_callback(NfcaPollerEvent event, void* c instance->card_state = MfClassicCardStateNotDetected; mfc_event.type = MfClassicPollerEventTypeCardNotDetected; command = instance->callback(mfc_event, instance->context); + instance->state = MfClassicPollerStateIdle; } } } @@ -236,6 +254,7 @@ MfClassicError mf_classic_poller_dict_attack( instance->callback = callback; instance->context = context; + instance->prev_state = MfClassicPollerStateStart; instance->state = MfClassicPollerStateIdle; return mf_classic_poller_start(instance, mf_classic_dict_attack_callback, instance); diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller.h b/lib/nfc/protocols/mf_classic/mf_classic_poller.h index 98c44822fcc3..6600d12e3b05 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller.h +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller.h @@ -10,6 +10,7 @@ extern "C" { typedef struct MfClassicPoller MfClassicPoller; typedef enum { + MfClassicPollerEventTypeStart, MfClassicPollerEventTypeRequestKey, MfClassicPollerEventTypeNewSector, MfClassicPollerEventTypeFoundKeyA, @@ -20,23 +21,22 @@ typedef enum { MfClassicPollerEventTypeKeyAttackStop, MfClassicPollerEventTypeKeyAttackNextSector, MfClassicPollerEventTypeReadComplete, - MfClassicPollerEventTypeReadFail, } MfClassicPollerEventType; +typedef struct { + uint8_t total_sectors; +} MfClassicPollerEventDataStart; + typedef struct { uint8_t sector_num; MfClassicKey key; bool key_provided; -} MfClassicKeyRequestContext; - -typedef struct { - MfClassicType type; -} MfClassicDetectContext; +} MfClassicPollerEventDataKeyRequest; typedef union { MfClassicError error; - MfClassicDetectContext detect_context; - MfClassicKeyRequestContext key_request_context; + MfClassicPollerEventDataStart start_data; + MfClassicPollerEventDataKeyRequest key_request_data; } MfClassicPollerEventData; typedef struct { @@ -48,6 +48,7 @@ typedef enum { MfClassicPollerCommandContinue = NfcaPollerCommandContinue, MfClassicPollerCommandReset = NfcaPollerCommandReset, MfClassicPollerCommandStop = NfcaPollerCommandStop, + MfClassicPollerCommandRestart, } MfClassicPollerCommand; typedef MfClassicPollerCommand ( diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c index ed109796b092..607b97bdf796 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c @@ -40,6 +40,7 @@ MfClassicError mf_classic_async_auth( MfClassicKeyType key_type, MfClassicAuthContext* data) { NfcPollerBuffer* buff = instance->plain_buff; + nfc_poller_buffer_reset(buff); MfClassicError ret = MfClassicErrorNone; NfcaError error = NfcaErrorNone; @@ -139,6 +140,48 @@ MfClassicError mf_classic_async_auth( return ret; } +MfClassicError mf_classic_aync_halt(MfClassicPoller* instance) { + NfcPollerBuffer* plain_buff = instance->plain_buff; + NfcPollerBuffer* encrypted_buff = instance->encrypted_buff; + MfClassicError ret = MfClassicErrorNone; + NfcaError error = NfcaErrorNone; + + do { + plain_buff->tx_data[0] = MF_CLASSIC_HALT_MSB_CMD; + plain_buff->tx_data[1] = MF_CLASSIC_HALT_LSB_CMD; + nfca_append_crc(plain_buff->tx_data, 2); + plain_buff->tx_bits = 4 * 8; + + encrypted_buff->tx_bits = plain_buff->tx_bits; + crypto1_encrypt( + instance->crypto, + NULL, + plain_buff->tx_data, + plain_buff->tx_bits, + encrypted_buff->tx_data, + encrypted_buff->tx_parity); + + error = nfca_poller_txrx_custom_parity( + instance->nfca_poller, + encrypted_buff->tx_data, + encrypted_buff->tx_parity, + encrypted_buff->tx_bits, + encrypted_buff->rx_data, + encrypted_buff->rx_parity, + encrypted_buff->rx_data_size, + &encrypted_buff->rx_bits, + MF_CLASSIC_FWT_FC); + if(error != NfcaErrorTimeout) { + ret = mf_classic_process_error(error); + break; + } + instance->auth_state = MfClassicAuthStateIdle; + instance->nfca_poller->state = NfcaPollerStateIdle; + } while(false); + + return ret; +} + MfClassicError mf_classic_async_read_block( MfClassicPoller* instance, uint8_t block_num, diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h index 2f7565a19a87..51306d4f293a 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h @@ -27,15 +27,19 @@ typedef enum { } MfClassicCardState; typedef enum { + MfClassicReadModeDictAttack, + MfClassicReadModeKeyReuse, +} MfClassicReadMode; + +typedef enum { + MfClassicPollerStateStart, MfClassicPollerStateIdle, + MfClassicPollerStateNewSector, MfClassicPollerStateRequestKey, MfClassicPollerStateAuthKeyA, MfClassicPollerStateAuthKeyB, MfClassicPollerStateReadSector, - MfClassicPollerStateNextSector, - - MfClassicPollerStateReadFail, - MfClassicPollerStateReadSuccess, + MfClassicPollerStateReadComplete, MfClassicPollerStateNum, } MfClassicPollerState; @@ -43,9 +47,11 @@ typedef enum { struct MfClassicPoller { NfcaPoller* nfca_poller; MfClassicPollerState state; + MfClassicPollerState prev_state; MfClassicPollerSessionState session_state; MfClassicAuthState auth_state; MfClassicCardState card_state; + MfClassicReadMode read_mode; MfClassicKey current_key; MfClassicPollerEventData event_data; uint8_t sectors_read; @@ -70,7 +76,6 @@ typedef union { MfClassicReadBlockContext read_block_context; } MfClassicPollerContextData; - MfClassicError mf_classic_process_error(NfcaError error); MfClassicError mf_classic_async_auth( @@ -80,6 +85,8 @@ MfClassicError mf_classic_async_auth( MfClassicKeyType key_type, MfClassicAuthContext* data); +MfClassicError mf_classic_aync_halt(MfClassicPoller* instance); + MfClassicError mf_classic_async_read_block(MfClassicPoller* instance, uint8_t block_num, MfClassicBlock* data); From 85fcb42550bbfb757c40de7bec4bf73951b6596e Mon Sep 17 00:00:00 2001 From: gornekich Date: Mon, 29 May 2023 13:27:35 +0400 Subject: [PATCH 094/149] mf classic: rework state machine --- .../scenes/nfc_scene_mf_classic_dict_attack.c | 2 - lib/nfc/protocols/mf_classic/mf_classic.c | 2 +- lib/nfc/protocols/mf_classic/mf_classic.h | 2 + .../protocols/mf_classic/mf_classic_poller.c | 70 ++++++++++++++----- .../mf_classic/mf_classic_poller_i.h | 1 + 5 files changed, 58 insertions(+), 19 deletions(-) diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c index a5cb57a204b0..6d796e2b7a69 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c @@ -38,8 +38,6 @@ MfClassicPollerCommand nfc_dict_attack_worker_callback(MfClassicPollerEvent even } else if(event.type == MfClassicPollerEventTypeReadComplete) { view_dispatcher_send_custom_event( nfc_app->view_dispatcher, NfcCustomEventDictAttackComplete); - } else if(event.type == MfClassicPollerEventTypeReadFail) { - // TODO } return MfClassicPollerCommandContinue; diff --git a/lib/nfc/protocols/mf_classic/mf_classic.c b/lib/nfc/protocols/mf_classic/mf_classic.c index a5883aec24ae..664a70869abc 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic.c +++ b/lib/nfc/protocols/mf_classic/mf_classic.c @@ -218,7 +218,7 @@ uint8_t mf_classic_get_first_block_num_of_sector(uint8_t sector) { return block; } -static uint8_t mf_classic_get_blocks_num_in_sector(uint8_t sector) { +uint8_t mf_classic_get_blocks_num_in_sector(uint8_t sector) { furi_assert(sector < 40); return sector < 32 ? 4 : 16; } diff --git a/lib/nfc/protocols/mf_classic/mf_classic.h b/lib/nfc/protocols/mf_classic/mf_classic.h index 658d662d37ef..b80ce62a7016 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic.h +++ b/lib/nfc/protocols/mf_classic/mf_classic.h @@ -118,6 +118,8 @@ uint16_t mf_classic_get_total_block_num(MfClassicType type); uint8_t mf_classic_get_first_block_num_of_sector(uint8_t sector); +uint8_t mf_classic_get_blocks_num_in_sector(uint8_t sector); + const char* mf_classic_get_name(MfClassicType type, bool full_name); uint8_t mf_classic_get_sector_trailer_num_by_sector(uint8_t sector); diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller.c b/lib/nfc/protocols/mf_classic/mf_classic_poller.c index 194ead3f37a2..d4064b5b20b2 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller.c @@ -102,7 +102,11 @@ MfClassicPollerCommand mf_classic_poller_handler_new_sector(MfClassicPoller* ins MfClassicPollerEvent event = {}; if(instance->sectors_read == instance->sectors_total) { - instance->state = MfClassicPollerStateReadComplete; + if(instance->read_mode == MfClassicReadModeKeyReuse) { + instance->read_mode = MfClassicReadModeDictAttack; + } else { + instance->state = MfClassicPollerStateReadComplete; + } } else if(mf_classic_is_sector_read(instance->data, instance->sectors_read)) { instance->sectors_read++; event.type = MfClassicPollerEventTypeNewSector; @@ -150,6 +154,10 @@ MfClassicPollerCommand mf_classic_poller_handler_auth_a(MfClassicPoller* instanc FURI_LOG_I(TAG, "Key A found"); mf_classic_set_key_found( instance->data, instance->sectors_read, MfClassicKeyTypeA, key); + if(instance->sectors_read < instance->sectors_total - 1) { + instance->read_mode = MfClassicReadModeKeyReuse; + instance->key_reuse_sector = instance->sectors_read; + } event.type = MfClassicPollerEventTypeFoundKeyA; command = instance->callback(event, instance->context); instance->prev_state = instance->state; @@ -166,19 +174,30 @@ MfClassicPollerCommand mf_classic_poller_handler_auth_b(MfClassicPoller* instanc MfClassicPollerCommand command = MfClassicPollerCommandContinue; MfClassicPollerEvent event = {}; - uint8_t block = mf_classic_get_first_block_num_of_sector(instance->sectors_read); - uint64_t key = nfc_util_bytes2num(instance->current_key.data, 6); - FURI_LOG_D(TAG, "Auth to block %d with key B: %06llx", block, key); - MfClassicError error = - mf_classic_async_auth(instance, block, &instance->current_key, MfClassicKeyTypeB, NULL); - if(error == MfClassicErrorNone) { - FURI_LOG_D(TAG, "Key B found"); - event.type = MfClassicPollerEventTypeFoundKeyB; - command = instance->callback(event, instance->context); - // TODO read here - instance->state = MfClassicPollerStateRequestKey; + if(mf_classic_is_key_found(instance->data, instance->sectors_read, MfClassicKeyTypeB)) { + instance->prev_state = instance->state; + instance->state = MfClassicPollerStateNewSector; } else { - instance->state = MfClassicPollerStateRequestKey; + uint8_t block = mf_classic_get_first_block_num_of_sector(instance->sectors_read); + uint64_t key = nfc_util_bytes2num(instance->current_key.data, 6); + FURI_LOG_D(TAG, "Auth to block %d with key B: %06llx", block, key); + MfClassicError error = mf_classic_async_auth( + instance, block, &instance->current_key, MfClassicKeyTypeB, NULL); + if(error == MfClassicErrorNone) { + FURI_LOG_D(TAG, "Key B found"); + event.type = MfClassicPollerEventTypeFoundKeyB; + mf_classic_set_key_found( + instance->data, instance->sectors_read, MfClassicKeyTypeB, key); + if(instance->sectors_read < instance->sectors_total - 1) { + instance->read_mode = MfClassicReadModeKeyReuse; + instance->key_reuse_sector = instance->sectors_read; + } + command = instance->callback(event, instance->context); + instance->prev_state = instance->state; + instance->state = MfClassicPollerStateReadSector; + } else { + instance->state = MfClassicPollerStateRequestKey; + } } return command; @@ -186,9 +205,28 @@ MfClassicPollerCommand mf_classic_poller_handler_auth_b(MfClassicPoller* instanc MfClassicPollerCommand mf_classic_poller_handler_read_sector(MfClassicPoller* instance) { MfClassicPollerCommand command = MfClassicPollerCommandContinue; - MfClassicPollerEvent event = {.type = MfClassicPollerEventTypeReadComplete}; - command = instance->callback(event, instance->context); - instance->state = MfClassicPollerStateIdle; + + uint8_t block_start = mf_classic_get_first_block_num_of_sector(instance->sectors_read); + uint8_t total_blocks = mf_classic_get_blocks_num_in_sector(instance->sectors_read); + MfClassicBlock block = {}; + + for(size_t i = block_start; i < block_start + total_blocks; i++) { + if(mf_classic_is_block_read(instance->data, i)) continue; + MfClassicError error = mf_classic_async_read_block(instance, i, &block); + if(error == MfClassicErrorNone) { + mf_classic_set_block_read(instance->data, i, &block); + } else { + FURI_LOG_D(TAG, "Failed to read %d block", i); + break; + } + } + + instance->prev_state = instance->state; + if(instance->prev_state == MfClassicPollerStateAuthKeyA) { + instance->state = MfClassicPollerStateAuthKeyB; + } else { + instance->state = MfClassicPollerStateNewSector; + } return command; } diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h index 51306d4f293a..c369707151c5 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h @@ -55,6 +55,7 @@ struct MfClassicPoller { MfClassicKey current_key; MfClassicPollerEventData event_data; uint8_t sectors_read; + uint8_t key_reuse_sector; uint8_t sectors_total; Crypto1* crypto; NfcPollerBuffer* plain_buff; From eaed19c38352670fa35837319277eae3a0e08133 Mon Sep 17 00:00:00 2001 From: gornekich Date: Wed, 31 May 2023 14:56:56 +0400 Subject: [PATCH 095/149] mf classic: add key reuse attack --- .../main/nfc/helpers/mf_classic_dict_attack.c | 17 --- .../main/nfc/helpers/mf_classic_dict_attack.h | 15 --- applications/main/nfc/helpers/mf_dict.c | 10 +- applications/main/nfc/helpers/mf_dict.h | 3 +- applications/main/nfc/nfc_app_i.h | 9 ++ .../scenes/nfc_scene_mf_classic_dict_attack.c | 115 +++++++++--------- .../nfc_scene_mf_classic_read_success.c | 38 +++--- lib/nfc/protocols/mf_classic/mf_classic.c | 2 +- .../protocols/mf_classic/mf_classic_poller.c | 103 ++++++++++++---- .../protocols/mf_classic/mf_classic_poller.h | 7 +- 10 files changed, 176 insertions(+), 143 deletions(-) delete mode 100644 applications/main/nfc/helpers/mf_classic_dict_attack.c delete mode 100644 applications/main/nfc/helpers/mf_classic_dict_attack.h diff --git a/applications/main/nfc/helpers/mf_classic_dict_attack.c b/applications/main/nfc/helpers/mf_classic_dict_attack.c deleted file mode 100644 index 39b18dbc1eef..000000000000 --- a/applications/main/nfc/helpers/mf_classic_dict_attack.c +++ /dev/null @@ -1,17 +0,0 @@ -#include "mf_classic_dict_attack.h" - -struct MfClassicDictAttack { - -}; - -MfClassicDictAttack* mf_classic_dict_attack_alloc() { - MfClassicDictAttack* instance = malloc(sizeof(MfClassicDictAttack)); - - return instance; -} - -void mf_classic_dict_attack_free(MfClassicDictAttack* instance) { - furi_assert(instance); - - free(instance); -} diff --git a/applications/main/nfc/helpers/mf_classic_dict_attack.h b/applications/main/nfc/helpers/mf_classic_dict_attack.h deleted file mode 100644 index af80668fa4b7..000000000000 --- a/applications/main/nfc/helpers/mf_classic_dict_attack.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct MfClassicDictAttack MfClassicDictAttack; - -MfClassicDictAttack* mf_classic_dict_attack_alloc(); - -void mf_classic_dict_attack_free(MfClassicDictAttack* instance); - -#ifdef __cplusplus -} -#endif diff --git a/applications/main/nfc/helpers/mf_dict.c b/applications/main/nfc/helpers/mf_dict.c index 4050b28ec782..9e66cca86e8c 100644 --- a/applications/main/nfc/helpers/mf_dict.c +++ b/applications/main/nfc/helpers/mf_dict.c @@ -3,7 +3,9 @@ #include #include -#define MF_CLASSIC_DICT_FLIPPER_PATH EXT_PATH("nfc/assets/mf_dict.nfc") +#include + +#define MF_CLASSIC_DICT_FLIPPER_PATH EXT_PATH("nfc/assets/mf_classic_dict.nfc") #define MF_CLASSIC_DICT_USER_PATH EXT_PATH("nfc/assets/mf_dict_user.nfc") #define MF_CLASSIC_DICT_UNIT_TEST_PATH EXT_PATH("unit_tests/mf_dict.nfc") @@ -170,15 +172,17 @@ bool mf_dict_get_next_key_str(MfDict* dict, FuriString* key) { return key_read; } -bool mf_dict_get_next_key(MfDict* dict, uint64_t* key) { +bool mf_dict_get_next_key(MfDict* dict, MfClassicKey* key) { furi_assert(dict); furi_assert(dict->stream); FuriString* temp_key; + uint64_t key_int = 0; temp_key = furi_string_alloc(); bool key_read = mf_dict_get_next_key_str(dict, temp_key); if(key_read) { - mf_dict_str_to_int(temp_key, key); + mf_dict_str_to_int(temp_key, &key_int); + nfc_util_num2bytes(key_int, 6, key->data); } furi_string_free(temp_key); return key_read; diff --git a/applications/main/nfc/helpers/mf_dict.h b/applications/main/nfc/helpers/mf_dict.h index 99ce31cf8ac5..b1725f549262 100644 --- a/applications/main/nfc/helpers/mf_dict.h +++ b/applications/main/nfc/helpers/mf_dict.h @@ -5,6 +5,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -54,7 +55,7 @@ bool mf_dict_is_key_present(MfDict* dict, uint8_t* key); bool mf_dict_is_key_present_str(MfDict* dict, FuriString* key); -bool mf_dict_get_next_key(MfDict* dict, uint64_t* key); +bool mf_dict_get_next_key(MfDict* dict, MfClassicKey* key); bool mf_dict_get_next_key_str(MfDict* dict, FuriString* key); diff --git a/applications/main/nfc/nfc_app_i.h b/applications/main/nfc/nfc_app_i.h index 3ddb854b65ca..3acf3ed2fe97 100644 --- a/applications/main/nfc/nfc_app_i.h +++ b/applications/main/nfc/nfc_app_i.h @@ -66,6 +66,14 @@ typedef enum { NfcRpcStateEmulated, } NfcRpcState; +typedef struct { + MfDict* dict; + uint32_t total_keys; + uint32_t current_key; + uint8_t current_sector; + MfClassicType type; +} NfcMfClassicDictAttackContext; + struct NfcApp { DialogsApp* dialogs; Storage* storage; @@ -103,6 +111,7 @@ struct NfcApp { NfcPoller* nfc_poller; MfUltralightAuth* mf_ul_auth; + NfcMfClassicDictAttackContext mf_dict_context; NfcDev* nfc_dev; NfcDevData nfc_dev_data; diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c index 6d796e2b7a69..48b5824d06d0 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c @@ -12,35 +12,62 @@ typedef enum { MfClassicPollerCommand nfc_dict_attack_worker_callback(MfClassicPollerEvent event, void* context) { furi_assert(context); + MfClassicPollerCommand command = MfClassicPollerCommandContinue; + NfcApp* nfc_app = context; - if(event.type == MfClassicPollerEventTypeCardDetected) { + if(event.type == MfClassicPollerEventTypeStart) { + nfc_app->mf_dict_context.type = event.data->start_data.type; + view_dispatcher_send_custom_event( + nfc_app->view_dispatcher, NfcCustomEventDictAttackCardDetected); + } else if(event.type == MfClassicPollerEventTypeCardDetected) { view_dispatcher_send_custom_event( nfc_app->view_dispatcher, NfcCustomEventDictAttackCardDetected); } else if(event.type == MfClassicPollerEventTypeCardNotDetected) { view_dispatcher_send_custom_event( nfc_app->view_dispatcher, NfcCustomEventDictAttackCardNotDetected); } else if(event.type == MfClassicPollerEventTypeRequestKey) { - - MfClassicKey key = { - .data = {0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5}, - }; - event.data->key_request_context.key = key; - event.data->key_request_context.key_provided = true; + MfClassicKey key = {}; + if(mf_dict_get_next_key(nfc_app->mf_dict_context.dict, &key)) { + event.data->key_request_data.key = key; + event.data->key_request_data.key_provided = true; + nfc_app->mf_dict_context.current_key++; + if(nfc_app->mf_dict_context.current_key % 10 == 0) { + view_dispatcher_send_custom_event( + nfc_app->view_dispatcher, NfcCustomEventDictAttackNewKeyBatch); + } + } else { + event.data->key_request_data.key_provided = false; + } } else if(event.type == MfClassicPollerEventTypeNewSector) { view_dispatcher_send_custom_event( nfc_app->view_dispatcher, NfcCustomEventDictAttackNewSector); + mf_dict_rewind(nfc_app->mf_dict_context.dict); + nfc_app->mf_dict_context.current_key = 0; } else if(event.type == MfClassicPollerEventTypeFoundKeyA) { view_dispatcher_send_custom_event( nfc_app->view_dispatcher, NfcCustomEventDictAttackFoundKeyA); } else if(event.type == MfClassicPollerEventTypeFoundKeyB) { view_dispatcher_send_custom_event( nfc_app->view_dispatcher, NfcCustomEventDictAttackFoundKeyB); + } else if(event.type == MfClassicPollerEventTypeKeyAttackStart) { + nfc_app->mf_dict_context.current_sector = event.data->key_attack_data.start_sector; + view_dispatcher_send_custom_event( + nfc_app->view_dispatcher, NfcCustomEventDictAttackKeyAttackStart); + } else if(event.type == MfClassicPollerEventTypeKeyAttackStop) { + mf_dict_rewind(nfc_app->mf_dict_context.dict); + nfc_app->mf_dict_context.current_key = 0; + view_dispatcher_send_custom_event( + nfc_app->view_dispatcher, NfcCustomEventDictAttackKeyAttackStop); + } else if(event.type == MfClassicPollerEventTypeKeyAttackNextSector) { + view_dispatcher_send_custom_event( + nfc_app->view_dispatcher, NfcCustomEventDictAttackKeyAttackNextSector); } else if(event.type == MfClassicPollerEventTypeReadComplete) { view_dispatcher_send_custom_event( nfc_app->view_dispatcher, NfcCustomEventDictAttackComplete); + command = MfClassicPollerCommandStop; } - return MfClassicPollerCommandContinue; + return command; } void nfc_dict_attack_dict_attack_result_callback(void* context) { @@ -62,15 +89,18 @@ static void nfc_scene_mf_classic_dict_attack_update_view(NfcApp* nfc) { static void nfc_scene_mf_classic_dict_attack_prepare_view(NfcApp* nfc, DictAttackState state) { MfClassicData* data = &nfc->nfc_dev_data.mf_classic_data; - MfDict* dict = NULL; // Identify scene state if(state == DictAttackStateIdle) { if(mf_dict_check_presence(MfDictTypeUser)) { state = DictAttackStateUserDictInProgress; + nfc->mf_dict_context.dict = mf_dict_alloc(MfDictTypeUser); } else { state = DictAttackStateFlipperDictInProgress; + nfc->mf_dict_context.dict = mf_dict_alloc(MfDictTypeSystem); } + nfc->mf_dict_context.total_keys = mf_dict_get_total_keys(nfc->mf_dict_context.dict); + nfc->mf_dict_context.current_key = 0; } else if(state == DictAttackStateUserDictInProgress) { state = DictAttackStateFlipperDictInProgress; } @@ -78,29 +108,16 @@ static void nfc_scene_mf_classic_dict_attack_prepare_view(NfcApp* nfc, DictAttac // Setup view if(state == DictAttackStateUserDictInProgress) { dict_attack_set_header(nfc->dict_attack, "MF Classic User Dictionary"); - dict = mf_dict_alloc(MfDictTypeUser); - - // If failed to load user dictionary - try the system dictionary - if(!dict) { - FURI_LOG_E(TAG, "User dictionary not found"); - state = DictAttackStateFlipperDictInProgress; - } } if(state == DictAttackStateFlipperDictInProgress) { dict_attack_set_header(nfc->dict_attack, "MF Classic System Dictionary"); - dict = mf_dict_alloc(MfDictTypeSystem); - if(!dict) { - FURI_LOG_E(TAG, "Flipper dictionary not found"); - // Pass through to let the worker handle the failure - } } scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfClassicDictAttack, state); dict_attack_set_callback(nfc->dict_attack, nfc_dict_attack_dict_attack_result_callback, nfc); dict_attack_set_current_sector(nfc->dict_attack, 0); dict_attack_set_card_detected(nfc->dict_attack, data->type); - dict_attack_set_total_dict_keys( - nfc->dict_attack, dict ? mf_dict_get_total_keys(dict) : 0); + dict_attack_set_total_dict_keys(nfc->dict_attack, nfc->mf_dict_context.total_keys); nfc_scene_mf_classic_dict_attack_update_view(nfc); } @@ -115,13 +132,13 @@ void nfc_scene_mf_classic_dict_attack_on_enter(void* context) { bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent event) { NfcApp* nfc = context; - MfClassicData* data = &nfc->nfc_dev_data.mf_classic_data; + // MfClassicData* data = &nfc->nfc_dev_data.mf_classic_data; bool consumed = false; uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicDictAttack); if(event.type == SceneManagerEventTypeCustom) { - if(event.event == MfClassicPollerEventTypeReadComplete) { + if(event.event == NfcCustomEventDictAttackComplete) { if(state == DictAttackStateUserDictInProgress) { nfc_scene_mf_classic_dict_attack_prepare_view(nfc, state); consumed = true; @@ -131,20 +148,8 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent DOLPHIN_DEED(DolphinDeedNfcReadSuccess); consumed = true; } - // } else if(event.event == NfcWorkerEventAborted) { - // if(state == DictAttackStateUserDictInProgress && - // dict_attack_get_card_state(nfc->dict_attack)) { - // nfc_scene_mf_classic_dict_attack_prepare_view(nfc, state); - // consumed = true; - // } else { - // notification_message(nfc->notifications, &sequence_success); - // scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSuccess); - // // Counting failed attempts too - // DOLPHIN_DEED(DolphinDeedNfcReadSuccess); - // consumed = true; - // } } else if(event.event == NfcCustomEventDictAttackCardDetected) { - dict_attack_set_card_detected(nfc->dict_attack, data->type); + dict_attack_set_card_detected(nfc->dict_attack, nfc->mf_dict_context.type); consumed = true; } else if(event.event == NfcCustomEventDictAttackCardNotDetected) { dict_attack_set_card_removed(nfc->dict_attack); @@ -156,13 +161,15 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent dict_attack_inc_keys_found(nfc->dict_attack); consumed = true; } else if(event.event == NfcCustomEventDictAttackNewSector) { + mf_classic_poller_get_data(nfc->mf_classic_poller, &nfc->nfc_dev_data.mf_classic_data); nfc_scene_mf_classic_dict_attack_update_view(nfc); dict_attack_inc_current_sector(nfc->dict_attack); consumed = true; - // } else if(event.event == NfcWorkerEventNewDictKeyBatch) { - // nfc_scene_mf_classic_dict_attack_update_view(nfc); - // dict_attack_inc_current_dict_key(nfc->dict_attack, NFC_DICT_KEY_BATCH_SIZE); - // consumed = true; + } else if(event.event == NfcCustomEventDictAttackNewKeyBatch) { + mf_classic_poller_get_data(nfc->mf_classic_poller, &nfc->nfc_dev_data.mf_classic_data); + nfc_scene_mf_classic_dict_attack_update_view(nfc); + dict_attack_inc_current_dict_key(nfc->dict_attack, 10); + consumed = true; } else if(event.event == NfcCustomEventDictAttackSkip) { if(state == DictAttackStateUserDictInProgress) { mf_classic_poller_stop(nfc->mf_classic_poller); @@ -171,15 +178,13 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent mf_classic_poller_stop(nfc->mf_classic_poller); consumed = true; } - // } else if(event.event == NfcWorkerEventKeyAttackStart) { - // dict_attack_set_key_attack( - // nfc->dict_attack, - // true, - // nfc->dev->dev_data.mf_classic_dict_attack_data.current_sector); - // } else if(event.event == NfcWorkerEventKeyAttackStop) { - // dict_attack_set_key_attack(nfc->dict_attack, false, 0); - // } else if(event.event == NfcWorkerEventKeyAttackNextSector) { - // dict_attack_inc_key_attack_current_sector(nfc->dict_attack); + } else if(event.event == NfcCustomEventDictAttackKeyAttackStart) { + dict_attack_set_key_attack( + nfc->dict_attack, true, nfc->mf_dict_context.current_sector); + } else if(event.event == NfcCustomEventDictAttackKeyAttackStop) { + dict_attack_set_key_attack(nfc->dict_attack, false, 0); + } else if(event.event == NfcCustomEventDictAttackKeyAttackNextSector) { + dict_attack_inc_key_attack_current_sector(nfc->dict_attack); } } else if(event.type == SceneManagerEventTypeBack) { scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); @@ -190,14 +195,6 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent void nfc_scene_mf_classic_dict_attack_on_exit(void* context) { NfcApp* nfc = context; - // NfcMfClassicDictAttackData* dict_attack_data = &nfc->dev->dev_data.mf_classic_dict_attack_data; - // Stop worker - // nfc_worker_stop(nfc->worker); - // if(dict_attack_data->dict) { - // mf_classic_dict_free(dict_attack_data->dict); - // dict_attack_data->dict = NULL; - // } - // dict_attack_reset(nfc->dict_attack); mf_classic_poller_stop(nfc->mf_classic_poller); nfc_blink_stop(nfc); notification_message(nfc->notifications, &sequence_display_backlight_enforce_auto); diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_read_success.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_read_success.c index e627aabc7158..73b7edee2b2d 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_read_success.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_read_success.c @@ -27,10 +27,10 @@ void nfc_scene_mf_classic_read_success_on_enter(void* context) { // if(furi_string_size(nfc->dev->dev_data.parsed_data)) { // temp_str = furi_string_alloc_set(nfc->dev->dev_data.parsed_data); // } else { - // temp_str = furi_string_alloc_printf("\e#%s\n", nfc_mf_classic_type(mfc_data->type)); + temp_str = furi_string_alloc_printf("\e#%s\n", mf_classic_get_name(mfc_data->type, true)); furi_string_cat_printf(temp_str, "UID:"); for(size_t i = 0; i < mfc_data->nfca_data.uid_len; i++) { - furi_string_cat_printf(temp_str, " %02X", mfc_data->nfca_data.uid[i]); + furi_string_cat_printf(temp_str, " %02X", mfc_data->nfca_data.uid[i]); } uint8_t sectors_total = mf_classic_get_total_sectors_num(mfc_data->type); uint8_t keys_total = sectors_total * 2; @@ -50,30 +50,30 @@ void nfc_scene_mf_classic_read_success_on_enter(void* context) { } bool nfc_scene_mf_classic_read_success_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - bool consumed = false; + NfcApp* 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, NfcSceneNotImplemented); + 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, NfcSceneNotImplemented); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeBack) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); consumed = true; } - } else if(event.type == SceneManagerEventTypeBack) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); - consumed = true; - } - return consumed; + return consumed; } void nfc_scene_mf_classic_read_success_on_exit(void* context) { - NfcApp* nfc = context; + NfcApp* nfc = context; - notification_message_block(nfc->notifications, &sequence_reset_green); + notification_message_block(nfc->notifications, &sequence_reset_green); - // Clear view - widget_reset(nfc->widget); + // Clear view + widget_reset(nfc->widget); } diff --git a/lib/nfc/protocols/mf_classic/mf_classic.c b/lib/nfc/protocols/mf_classic/mf_classic.c index 664a70869abc..089417d0fcc6 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic.c +++ b/lib/nfc/protocols/mf_classic/mf_classic.c @@ -265,7 +265,7 @@ bool mf_classic_is_sector_read(MfClassicData* data, uint8_t sector_num) { uint8_t total_blocks = mf_classic_get_blocks_num_in_sector(sector_num); uint8_t block_read = true; for(size_t i = start_block; i < start_block + total_blocks; i++) { - block_read = mifare_classic_is_block_read(data, i); + block_read = mf_classic_is_block_read(data, i); if(!block_read) break; } sector_read = block_read; diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller.c b/lib/nfc/protocols/mf_classic/mf_classic_poller.c index d4064b5b20b2..921b2b1dd891 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller.c @@ -85,7 +85,7 @@ MfClassicPollerCommand mf_classic_poller_handler_start(MfClassicPoller* instance instance->sectors_read = 0; instance->sectors_total = mf_classic_get_total_sectors_num(instance->data->type); - instance->event_data.start_data.total_sectors = instance->sectors_total; + instance->event_data.start_data.type = instance->data->type; MfClassicPollerEvent event = { .type = MfClassicPollerEventTypeStart, .data = &instance->event_data, @@ -101,19 +101,32 @@ MfClassicPollerCommand mf_classic_poller_handler_new_sector(MfClassicPoller* ins MfClassicPollerCommand command = MfClassicPollerCommandContinue; MfClassicPollerEvent event = {}; - if(instance->sectors_read == instance->sectors_total) { - if(instance->read_mode == MfClassicReadModeKeyReuse) { + if(instance->read_mode == MfClassicReadModeKeyReuse) { + instance->key_reuse_sector++; + if(instance->key_reuse_sector == instance->sectors_total) { instance->read_mode = MfClassicReadModeDictAttack; + event.type = MfClassicPollerEventTypeKeyAttackStop; + command = instance->callback(event, instance->context); + } else if(mf_classic_is_sector_read(instance->data, instance->sectors_read)) { + event.type = MfClassicPollerEventTypeKeyAttackNextSector; + command = instance->callback(event, instance->context); } else { - instance->state = MfClassicPollerStateReadComplete; + instance->state = MfClassicPollerStateAuthKeyA; + event.type = MfClassicPollerEventTypeKeyAttackNextSector; + command = instance->callback(event, instance->context); } - } else if(mf_classic_is_sector_read(instance->data, instance->sectors_read)) { - instance->sectors_read++; - event.type = MfClassicPollerEventTypeNewSector; - command = instance->callback(event, instance->context); } else { - instance->state = MfClassicPollerStateRequestKey; + if(instance->sectors_read == instance->sectors_total) { + instance->state = MfClassicPollerStateReadComplete; + } else if(mf_classic_is_sector_read(instance->data, instance->sectors_read)) { + instance->sectors_read++; + event.type = MfClassicPollerEventTypeNewSector; + command = instance->callback(event, instance->context); + } else { + instance->state = MfClassicPollerStateRequestKey; + } } + instance->prev_state = instance->state; return command; } @@ -141,29 +154,46 @@ MfClassicPollerCommand mf_classic_poller_handler_auth_a(MfClassicPoller* instanc MfClassicPollerCommand command = MfClassicPollerCommandContinue; MfClassicPollerEvent event = {}; - if(mf_classic_is_key_found(instance->data, instance->sectors_read, MfClassicKeyTypeA)) { + uint8_t sector = 0; + if(instance->read_mode == MfClassicReadModeKeyReuse) { + sector = instance->key_reuse_sector; + } else { + sector = instance->sectors_read; + } + + if(mf_classic_is_key_found(instance->data, sector, MfClassicKeyTypeA)) { instance->prev_state = instance->state; instance->state = MfClassicPollerStateAuthKeyB; } else { - uint8_t block = mf_classic_get_first_block_num_of_sector(instance->sectors_read); + uint8_t block = mf_classic_get_first_block_num_of_sector(sector); uint64_t key = nfc_util_bytes2num(instance->current_key.data, 6); FURI_LOG_D(TAG, "Auth to block %d with key A: %06llx", block, key); + MfClassicError error = mf_classic_async_auth( instance, block, &instance->current_key, MfClassicKeyTypeA, NULL); if(error == MfClassicErrorNone) { FURI_LOG_I(TAG, "Key A found"); - mf_classic_set_key_found( - instance->data, instance->sectors_read, MfClassicKeyTypeA, key); - if(instance->sectors_read < instance->sectors_total - 1) { - instance->read_mode = MfClassicReadModeKeyReuse; - instance->key_reuse_sector = instance->sectors_read; + mf_classic_set_key_found(instance->data, sector, MfClassicKeyTypeA, key); + if(instance->read_mode != MfClassicReadModeKeyReuse) { + if(sector < instance->sectors_total - 1) { + instance->read_mode = MfClassicReadModeKeyReuse; + instance->key_reuse_sector = sector; + event.type = MfClassicPollerEventTypeKeyAttackStart; + instance->event_data.key_attack_data.start_sector = instance->key_reuse_sector; + event.data = &instance->event_data; + command = instance->callback(event, instance->context); + } } event.type = MfClassicPollerEventTypeFoundKeyA; command = instance->callback(event, instance->context); instance->prev_state = instance->state; instance->state = MfClassicPollerStateReadSector; } else { - instance->state = MfClassicPollerStateAuthKeyB; + if(instance->read_mode == MfClassicReadModeKeyReuse) { + instance->state = MfClassicPollerStateAuthKeyB; + } else { + instance->state = MfClassicPollerStateRequestKey; + } } } @@ -174,31 +204,48 @@ MfClassicPollerCommand mf_classic_poller_handler_auth_b(MfClassicPoller* instanc MfClassicPollerCommand command = MfClassicPollerCommandContinue; MfClassicPollerEvent event = {}; - if(mf_classic_is_key_found(instance->data, instance->sectors_read, MfClassicKeyTypeB)) { - instance->prev_state = instance->state; + uint8_t sector = 0; + if(instance->read_mode == MfClassicReadModeKeyReuse) { + sector = instance->key_reuse_sector; + } else { + sector = instance->sectors_read; + } + + if(mf_classic_is_key_found(instance->data, sector, MfClassicKeyTypeB)) { instance->state = MfClassicPollerStateNewSector; } else { - uint8_t block = mf_classic_get_first_block_num_of_sector(instance->sectors_read); + uint8_t block = mf_classic_get_first_block_num_of_sector(sector); uint64_t key = nfc_util_bytes2num(instance->current_key.data, 6); FURI_LOG_D(TAG, "Auth to block %d with key B: %06llx", block, key); + MfClassicError error = mf_classic_async_auth( instance, block, &instance->current_key, MfClassicKeyTypeB, NULL); if(error == MfClassicErrorNone) { FURI_LOG_D(TAG, "Key B found"); event.type = MfClassicPollerEventTypeFoundKeyB; - mf_classic_set_key_found( - instance->data, instance->sectors_read, MfClassicKeyTypeB, key); - if(instance->sectors_read < instance->sectors_total - 1) { - instance->read_mode = MfClassicReadModeKeyReuse; - instance->key_reuse_sector = instance->sectors_read; + mf_classic_set_key_found(instance->data, sector, MfClassicKeyTypeB, key); + if(instance->read_mode != MfClassicReadModeKeyReuse) { + if(sector < instance->sectors_total - 1) { + instance->read_mode = MfClassicReadModeKeyReuse; + instance->key_reuse_sector = sector; + + event.type = MfClassicPollerEventTypeKeyAttackStart; + instance->event_data.key_attack_data.start_sector = instance->key_reuse_sector; + event.data = &instance->event_data; + command = instance->callback(event, instance->context); + } } command = instance->callback(event, instance->context); - instance->prev_state = instance->state; instance->state = MfClassicPollerStateReadSector; } else { - instance->state = MfClassicPollerStateRequestKey; + if(instance->read_mode == MfClassicReadModeKeyReuse) { + instance->state = MfClassicPollerStateNewSector; + } else { + instance->state = MfClassicPollerStateRequestKey; + } } } + instance->prev_state = instance->state; return command; } @@ -211,6 +258,7 @@ MfClassicPollerCommand mf_classic_poller_handler_read_sector(MfClassicPoller* in MfClassicBlock block = {}; for(size_t i = block_start; i < block_start + total_blocks; i++) { + FURI_LOG_D(TAG, "Reding block %d", i); if(mf_classic_is_block_read(instance->data, i)) continue; MfClassicError error = mf_classic_async_read_block(instance, i, &block); if(error == MfClassicErrorNone) { @@ -267,6 +315,7 @@ NfcaPollerCommand mf_classic_dict_attack_callback(NfcaPollerEvent event, void* c command = MfClassicPollerCommandStop; } else { if(event.type == NfcaPollerEventTypeReady) { + // furi_delay_ms(100); command = mf_classic_poller_dict_attack_handler[instance->state](instance); } else if(event.type == NfcaPollerEventTypeError) { if(event.data.error == NfcaErrorNotPresent) { diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller.h b/lib/nfc/protocols/mf_classic/mf_classic_poller.h index 6600d12e3b05..bf872be3c595 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller.h +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller.h @@ -24,7 +24,7 @@ typedef enum { } MfClassicPollerEventType; typedef struct { - uint8_t total_sectors; + MfClassicType type; } MfClassicPollerEventDataStart; typedef struct { @@ -33,10 +33,15 @@ typedef struct { bool key_provided; } MfClassicPollerEventDataKeyRequest; +typedef struct { + uint8_t start_sector; +} MfClassicPollerEventKeyAttackData; + typedef union { MfClassicError error; MfClassicPollerEventDataStart start_data; MfClassicPollerEventDataKeyRequest key_request_data; + MfClassicPollerEventKeyAttackData key_attack_data; } MfClassicPollerEventData; typedef struct { From 994670ae55d136ef7595d4666fc2ef6d14e7d912 Mon Sep 17 00:00:00 2001 From: gornekich Date: Thu, 1 Jun 2023 20:38:20 +0400 Subject: [PATCH 096/149] nfc: add mf classic menu scene --- .../main/nfc/scenes/nfc_scene_config.h | 1 + .../nfc/scenes/nfc_scene_mf_classic_menu.c | 79 +++++++++++++++++++ .../nfc_scene_mf_classic_read_success.c | 2 +- lib/nfc/protocols/mf_classic/mf_classic.c | 12 +++ lib/nfc/protocols/mf_classic/mf_classic.h | 2 + 5 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 applications/main/nfc/scenes/nfc_scene_mf_classic_menu.c diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index bb0da4c388ee..4155ca740440 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -28,6 +28,7 @@ ADD_SCENE(nfc, mf_ultralight_capture_pass, MfUltralightCapturePass) ADD_SCENE(nfc, mf_classic_dict_attack, MfClassicDictAttack) ADD_SCENE(nfc, mf_classic_read_success, MfClassicReadSuccess) +ADD_SCENE(nfc, mf_classic_menu, MfClassicMenu) ADD_SCENE(nfc, set_type, SetType) ADD_SCENE(nfc, set_sak, SetSak) diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_menu.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_menu.c new file mode 100644 index 000000000000..2412230010c8 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_menu.c @@ -0,0 +1,79 @@ +#include "../nfc_app_i.h" +#include + +enum SubmenuIndex { + SubmenuIndexSave, + SubmenuIndexEmulate, + SubmenuIndexDetectReader, + SubmenuIndexInfo, +}; + +void nfc_scene_mf_classic_menu_submenu_callback(void* context, uint32_t index) { + NfcApp* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, index); +} + +void nfc_scene_mf_classic_menu_on_enter(void* context) { + NfcApp* nfc = context; + Submenu* submenu = nfc->submenu; + + submenu_add_item( + submenu, "Save", SubmenuIndexSave, nfc_scene_mf_classic_menu_submenu_callback, nfc); + submenu_add_item( + submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_mf_classic_menu_submenu_callback, nfc); + if(!mf_classic_is_card_read(&nfc->nfc_dev_data.mf_classic_data)) { + submenu_add_item( + submenu, + "Detect Reader", + SubmenuIndexDetectReader, + nfc_scene_mf_classic_menu_submenu_callback, + nfc); + } + submenu_add_item( + submenu, "Info", SubmenuIndexInfo, nfc_scene_mf_classic_menu_submenu_callback, nfc); + + submenu_set_selected_item( + nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicMenu)); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); +} + +bool nfc_scene_mf_classic_menu_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfClassicMenu, event.event); + if(event.event == SubmenuIndexSave) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); + consumed = true; + } else if(event.event == SubmenuIndexEmulate) { + if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) { + DOLPHIN_DEED(DolphinDeedNfcAddEmulate); + } else { + DOLPHIN_DEED(DolphinDeedNfcEmulate); + } + scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + consumed = true; + } else if(event.event == SubmenuIndexDetectReader) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + DOLPHIN_DEED(DolphinDeedNfcDetectReader); + consumed = true; + } else if(event.event == SubmenuIndexInfo) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeBack) { + consumed = scene_manager_previous_scene(nfc->scene_manager); + } + + return consumed; +} + +void nfc_scene_mf_classic_menu_on_exit(void* context) { + NfcApp* nfc = context; + + // Clear view + submenu_reset(nfc->submenu); +} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_read_success.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_read_success.c index 73b7edee2b2d..81e4d2c715e7 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_read_success.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_read_success.c @@ -58,7 +58,7 @@ bool nfc_scene_mf_classic_read_success_on_event(void* context, SceneManagerEvent scene_manager_next_scene(nfc->scene_manager, NfcSceneRetryConfirm); consumed = true; } else if(event.event == GuiButtonTypeRight) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicMenu); consumed = true; } } else if(event.type == SceneManagerEventTypeBack) { diff --git a/lib/nfc/protocols/mf_classic/mf_classic.c b/lib/nfc/protocols/mf_classic/mf_classic.c index 089417d0fcc6..b8f07b6f84b9 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic.c +++ b/lib/nfc/protocols/mf_classic/mf_classic.c @@ -254,6 +254,18 @@ void mf_classic_get_read_sectors_and_keys( } } +bool mf_classic_is_card_read(MfClassicData* data) { + furi_assert(data); + + uint8_t sectors_total = mf_classic_get_total_sectors_num(data->type); + uint8_t sectors_read = 0; + uint8_t keys_found = 0; + mf_classic_get_read_sectors_and_keys(data, §ors_read, &keys_found); + bool card_read = (sectors_read == sectors_total) && (keys_found == sectors_total * 2); + + return card_read; +} + bool mf_classic_is_sector_read(MfClassicData* data, uint8_t sector_num) { furi_assert(data); diff --git a/lib/nfc/protocols/mf_classic/mf_classic.h b/lib/nfc/protocols/mf_classic/mf_classic.h index b80ce62a7016..bc4f1cc4c8de 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic.h +++ b/lib/nfc/protocols/mf_classic/mf_classic.h @@ -157,6 +157,8 @@ void mf_classic_get_read_sectors_and_keys( uint8_t* sectors_read, uint8_t* keys_found); +bool mf_classic_is_card_read(MfClassicData* data); + #ifdef __cplusplus } #endif From 82ee706e212e43194d63b272626743821254b65e Mon Sep 17 00:00:00 2001 From: gornekich Date: Fri, 2 Jun 2023 16:52:33 +0400 Subject: [PATCH 097/149] nfc: introduce supported cards --- .../main/nfc/plugins/nfc_supported_cards.c | 0 .../main/nfc/plugins/nfc_supported_cards.h | 0 .../main/nfc/scenes/nfc_scene_config.h | 2 ++ ...nfc_scene_mf_classic_read_supported_card.c | 32 +++++++++++++++++++ 4 files changed, 34 insertions(+) create mode 100644 applications/main/nfc/plugins/nfc_supported_cards.c create mode 100644 applications/main/nfc/plugins/nfc_supported_cards.h create mode 100644 applications/main/nfc/scenes/nfc_scene_mf_classic_read_supported_card.c diff --git a/applications/main/nfc/plugins/nfc_supported_cards.c b/applications/main/nfc/plugins/nfc_supported_cards.c new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/applications/main/nfc/plugins/nfc_supported_cards.h b/applications/main/nfc/plugins/nfc_supported_cards.h new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index 4155ca740440..99e5992fa796 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -26,6 +26,8 @@ ADD_SCENE(nfc, mf_ultralight_unlock_warn, MfUltralightUnlockWarn) ADD_SCENE(nfc, mf_ultralight_key_input, MfUltralightKeyInput) ADD_SCENE(nfc, mf_ultralight_capture_pass, MfUltralightCapturePass) + +ADD_SCENE(nfc, mf_classic_read_supported_card, MfClassicReadSupportedCard) ADD_SCENE(nfc, mf_classic_dict_attack, MfClassicDictAttack) ADD_SCENE(nfc, mf_classic_read_success, MfClassicReadSuccess) ADD_SCENE(nfc, mf_classic_menu, MfClassicMenu) diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_read_supported_card.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_read_supported_card.c new file mode 100644 index 000000000000..a5c65a1ca0c7 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_read_supported_card.c @@ -0,0 +1,32 @@ +#include "../nfc_app_i.h" +#include + +void nfc_scene_read_supported_card_on_enter(void* context) { + NfcApp* nfc = context; + + // Setup view + popup_reset(nfc->popup); + popup_set_text(nfc->popup, "Apply card to\nFlipper's back", 97, 24, AlignCenter, AlignTop); + popup_set_icon(nfc->popup, 0, 8, &I_NFC_manual_60x50); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); + + + + nfc_blink_read_start(nfc); +} + +bool nfc_scene_read_supported_card_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + UNUSED(event); + + return false; +} + +void nfc_scene_read_supported_card_on_exit(void* context) { + NfcApp* nfc = context; + + // Clear view + popup_reset(nfc->popup); + + nfc_blink_stop(nfc); +} From 4e54af1910049c0dbe9cee6be0f5221a6dfb8e68 Mon Sep 17 00:00:00 2001 From: gornekich Date: Tue, 6 Jun 2023 17:27:34 +0400 Subject: [PATCH 098/149] nfc: introduce nfc plugin --- applications/main/nfc/application.fam | 7 + .../main/nfc/helpers/nfc_supported_cards.c | 108 ++++++++++ .../main/nfc/helpers/nfc_supported_cards.h | 30 +++ applications/main/nfc/nfc_app.c | 6 +- applications/main/nfc/nfc_app_i.h | 4 +- .../nfc/plugins/nfc_supported_card_plugin.h | 20 ++ .../main/nfc/plugins/nfc_supported_cards.c | 0 .../main/nfc/plugins/nfc_supported_cards.h | 0 applications/main/nfc/plugins/troika.c | 82 ++++++++ .../nfc_scene_mf_classic_read_success.c | 44 ++-- ...nfc_scene_mf_classic_read_supported_card.c | 30 ++- .../nfc/scenes/nfc_scene_read_card_type.c | 22 +- firmware/targets/f7/api_symbols.csv | 192 ++++++------------ lib/nfc/SConscript | 3 +- lib/nfc/nfc_poller.h | 3 + lib/nfc/protocols/mf_classic/mf_classic.h | 8 + .../protocols/mf_classic/mf_classic_poller.h | 5 + lib/nfc/protocols/nfca/nfca_poller.c | 8 +- lib/nfc/protocols/nfca/nfca_poller_i.c | 2 + lib/nfc/protocols/nfca/nfca_poller_i.h | 6 + 20 files changed, 406 insertions(+), 174 deletions(-) create mode 100644 applications/main/nfc/helpers/nfc_supported_cards.c create mode 100644 applications/main/nfc/helpers/nfc_supported_cards.h create mode 100644 applications/main/nfc/plugins/nfc_supported_card_plugin.h delete mode 100644 applications/main/nfc/plugins/nfc_supported_cards.c delete mode 100644 applications/main/nfc/plugins/nfc_supported_cards.h create mode 100644 applications/main/nfc/plugins/troika.c diff --git a/applications/main/nfc/application.fam b/applications/main/nfc/application.fam index f091270455fb..fdc1e81bf60a 100644 --- a/applications/main/nfc/application.fam +++ b/applications/main/nfc/application.fam @@ -15,6 +15,13 @@ App( order=30, ) +App( + appid="troika_parser", + apptype=FlipperAppType.PLUGIN, + entry_point="troika_plugin_ep", + requires=["nfc"], +) + App( appid="nfc_start", apptype=FlipperAppType.STARTUP, diff --git a/applications/main/nfc/helpers/nfc_supported_cards.c b/applications/main/nfc/helpers/nfc_supported_cards.c new file mode 100644 index 000000000000..7a5aa3661e2e --- /dev/null +++ b/applications/main/nfc/helpers/nfc_supported_cards.c @@ -0,0 +1,108 @@ +#include "nfc_supported_cards.h" +#include "../plugins/nfc_supported_card_plugin.h" + +#include +#include +#include + +#include + +#define TAG "NfcSupportedCards" + +#define NFC_SUPPORTED_CARDS_PLUGINS_PATH EXT_PATH("nfc/plugins") + +typedef enum { + NfcSupportCardsStatusIdle, + NfcSupportCardsStatusLoadSuccess, + NfcSupportCardsStatusLoadFailed, +} NfcSupportCardsStatus; + +struct NfcSupportedCards { + PluginManager* manager; + uint32_t plugin_cnt; + NfcSupportCardsStatus status; +}; + +NfcSupportedCards* nfc_supported_cards_alloc() { + NfcSupportedCards* instance = malloc(sizeof(NfcSupportedCards)); + instance->manager = plugin_manager_alloc( + NFC_SUPPORTED_CARD_PLUGIN_APP_ID, + NFC_SUPPORTED_CARD_PLUGIN_API_VERSION, + firmware_api_interface); + if(plugin_manager_load_all(instance->manager, NFC_SUPPORTED_CARDS_PLUGINS_PATH) != + PluginManagerErrorNone) { + FURI_LOG_W(TAG, "Failed to load all libs"); + instance->status = NfcSupportCardsStatusLoadFailed; + } else { + instance->plugin_cnt = plugin_manager_get_count(instance->manager); + instance->status = NfcSupportCardsStatusLoadSuccess; + FURI_LOG_D(TAG, "Loaded %ld parsers", instance->plugin_cnt); + } + + return instance; +} + +void nfc_supported_cards_free(NfcSupportedCards* instance) { + furi_assert(instance); + + plugin_manager_free(instance->manager); + free(instance); +} + +bool nfc_supported_cards_read( + NfcSupportedCards* instance, + NfcDevProtocol protocol, + void* poller, + void* data) { + furi_assert(instance); + furi_assert(poller); + furi_assert(data); + + bool card_read = false; + bool verified = false; + + do { + if(instance->status != NfcSupportCardsStatusLoadSuccess) break; + + for(size_t i = 0; i < instance->plugin_cnt; i++) { + const NfcSupportedCardsPlugin* plugin = plugin_manager_get_ep(instance->manager, i); + if(plugin->protocol != protocol) continue; + if(plugin->verify) { + verified = plugin->verify(poller); + } + if(verified && (plugin->read)) { + card_read = plugin->read(poller, data); + } + if(card_read) break; + } + } while(false); + + return card_read; +} + +bool nfc_supported_cards_parse( + NfcSupportedCards* instance, + NfcDevProtocol protocol, + void* data, + FuriString* parsed_data) { + furi_assert(instance); + furi_assert(data); + furi_assert(parsed_data); + + bool parsed = false; + + do { + if(instance->status != NfcSupportCardsStatusLoadSuccess) break; + + for(size_t i = 0; i < instance->plugin_cnt; i++) { + const NfcSupportedCardsPlugin* plugin = plugin_manager_get_ep(instance->manager, i); + if(plugin->protocol != protocol) continue; + if(plugin->parse) { + parsed = plugin->parse(data, parsed_data); + } + if(parsed) break; + } + } while(false); + + return parsed; +} diff --git a/applications/main/nfc/helpers/nfc_supported_cards.h b/applications/main/nfc/helpers/nfc_supported_cards.h new file mode 100644 index 000000000000..856384f4aa9b --- /dev/null +++ b/applications/main/nfc/helpers/nfc_supported_cards.h @@ -0,0 +1,30 @@ +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct NfcSupportedCards NfcSupportedCards; + +NfcSupportedCards* nfc_supported_cards_alloc(); + +void nfc_supported_cards_free(NfcSupportedCards* instance); + +bool nfc_supported_cards_read( + NfcSupportedCards* instance, + NfcDevProtocol protocol, + void* poller, + void* data); + +bool nfc_supported_cards_parse( + NfcSupportedCards* instance, + NfcDevProtocol protocol, + void* data, + FuriString* parsed_data); + +#ifdef __cplusplus +} +#endif diff --git a/applications/main/nfc/nfc_app.c b/applications/main/nfc/nfc_app.c index fb177430a574..7a7f6ae95c4e 100644 --- a/applications/main/nfc/nfc_app.c +++ b/applications/main/nfc/nfc_app.c @@ -53,6 +53,8 @@ NfcApp* nfc_app_alloc() { instance->mf_ul_listener = mf_ultralight_listener_alloc(instance->nfca_listener); instance->nfcb_poller = nfcb_poller_alloc(instance->nfc); + instance->parsed_data = furi_string_alloc(); + NfcPollerCollection collection = { .nfc = instance->nfc, .nfca_poller = instance->nfca_poller, @@ -157,6 +159,8 @@ void nfc_app_free(NfcApp* instance) { instance->rpc_ctx = NULL; } + furi_string_free(instance->parsed_data); + mf_classic_poller_free(instance->mf_classic_poller); mf_ultralight_listener_free(instance->mf_ul_listener); mf_ultralight_poller_free(instance->mf_ul_poller); @@ -497,7 +501,7 @@ int32_t nfc_app(void* p) { } else { view_dispatcher_attach_to_gui( nfc->view_dispatcher, nfc->gui, ViewDispatcherTypeFullscreen); - scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardType); + scene_manager_next_scene(nfc->scene_manager, NfcSceneStart); } view_dispatcher_run(nfc->view_dispatcher); diff --git a/applications/main/nfc/nfc_app_i.h b/applications/main/nfc/nfc_app_i.h index 3acf3ed2fe97..0311cc60730c 100644 --- a/applications/main/nfc/nfc_app_i.h +++ b/applications/main/nfc/nfc_app_i.h @@ -28,6 +28,7 @@ #include "helpers/nfc_custom_event.h" #include "helpers/mf_ultralight_auth.h" #include "helpers/mf_dict.h" +#include "helpers/nfc_supported_cards.h" #include #include @@ -59,7 +60,6 @@ #define NFC_APP_EXTENSION ".nfc" #define NFC_APP_SHADOW_EXTENSION ".shd" - typedef enum { NfcRpcStateIdle, NfcRpcStateEmulating, @@ -112,6 +112,8 @@ struct NfcApp { MfUltralightAuth* mf_ul_auth; NfcMfClassicDictAttackContext mf_dict_context; + FuriString* parsed_data; + NfcSupportedCards* supported_cards; NfcDev* nfc_dev; NfcDevData nfc_dev_data; diff --git a/applications/main/nfc/plugins/nfc_supported_card_plugin.h b/applications/main/nfc/plugins/nfc_supported_card_plugin.h new file mode 100644 index 000000000000..e0554268c659 --- /dev/null +++ b/applications/main/nfc/plugins/nfc_supported_card_plugin.h @@ -0,0 +1,20 @@ +#pragma once + +#include +#include + +#define NFC_SUPPORTED_CARD_PLUGIN_APP_ID "NfcSupportedCardPlugin" +#define NFC_SUPPORTED_CARD_PLUGIN_API_VERSION 1 + +typedef bool (*NfcSupportedCardPluginVerify)(void* poller); + +typedef bool (*NfcSupportedCardPluginRead)(void* poller, void* data); + +typedef bool (*NfcSupportedCardPluginParse)(void* data, FuriString* parsed_data); + +typedef struct { + NfcDevProtocol protocol; + NfcSupportedCardPluginVerify verify; + NfcSupportedCardPluginRead read; + NfcSupportedCardPluginParse parse; +} NfcSupportedCardsPlugin; diff --git a/applications/main/nfc/plugins/nfc_supported_cards.c b/applications/main/nfc/plugins/nfc_supported_cards.c deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/applications/main/nfc/plugins/nfc_supported_cards.h b/applications/main/nfc/plugins/nfc_supported_cards.h deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/applications/main/nfc/plugins/troika.c b/applications/main/nfc/plugins/troika.c new file mode 100644 index 000000000000..84c5e0b7d03b --- /dev/null +++ b/applications/main/nfc/plugins/troika.c @@ -0,0 +1,82 @@ +#include "nfc_supported_card_plugin.h" + +#include + +#include +#include + +#define TAG "Troika" + +// static const MfClassicAuthContext troika_keys[] = { +// {.sector = 0, .key_a = 0xa0a1a2a3a4a5, .key_b = 0xfbf225dc5d58}, +// {.sector = 1, .key_a = 0xa82607b01c0d, .key_b = 0x2910989b6880}, +// {.sector = 2, .key_a = 0x2aa05ed1856f, .key_b = 0xeaac88e5dc99}, +// {.sector = 3, .key_a = 0x2aa05ed1856f, .key_b = 0xeaac88e5dc99}, +// {.sector = 4, .key_a = 0x73068f118c13, .key_b = 0x2b7f3253fac5}, +// {.sector = 5, .key_a = 0xfbc2793d540b, .key_b = 0xd3a297dc2698}, +// {.sector = 6, .key_a = 0x2aa05ed1856f, .key_b = 0xeaac88e5dc99}, +// {.sector = 7, .key_a = 0xae3d65a3dad4, .key_b = 0x0f1c63013dba}, +// {.sector = 8, .key_a = 0xa73f5dc1d333, .key_b = 0xe35173494a81}, +// {.sector = 9, .key_a = 0x69a32f1c2f19, .key_b = 0x6b8bd9860763}, +// {.sector = 10, .key_a = 0x9becdf3d9273, .key_b = 0xf8493407799d}, +// {.sector = 11, .key_a = 0x08b386463229, .key_b = 0x5efbaecef46b}, +// {.sector = 12, .key_a = 0xcd4c61c26e3d, .key_b = 0x31c7610de3b0}, +// {.sector = 13, .key_a = 0xa82607b01c0d, .key_b = 0x2910989b6880}, +// {.sector = 14, .key_a = 0x0e8f64340ba4, .key_b = 0x4acec1205d75}, +// {.sector = 15, .key_a = 0x2aa05ed1856f, .key_b = 0xeaac88e5dc99}, +// }; + +bool troika_verify(void* poller) { + furi_assert(poller); + + bool verified = false; + MfClassicPoller* mfc_poller = poller; + uint8_t sector = 11; + uint8_t block = mf_classic_get_sector_trailer_num_by_sector(sector); + MfClassicKey key = {.data = {0x08, 0xb3, 0x86, 0x46, 0x32, 0x29}}; + MfClassicAuthContext auth_context = {}; + + FURI_LOG_D("Troika", "Verifying sector %d", sector); + if(mf_classic_poller_auth(mfc_poller, block, &key, MfClassicKeyTypeA, &auth_context) == + MfClassicErrorNone) { + FURI_LOG_D(TAG, "Sector %d verified", sector); + verified = true; + } + + return verified; +} + +bool troika_read(void* poller, void* data) { + furi_assert(poller); + furi_assert(data); + + return true; +} + +bool troika_parse(void* data, FuriString* parsed_data) { + furi_assert(data); + + furi_string_printf(parsed_data, "%s", "Hello Troika"); + + return true; +} + +/* Actual implementation of app<>plugin interface */ +static const NfcSupportedCardsPlugin troika_plugin = { + .protocol = NfcDevProtocolMfClassic, + .verify = troika_verify, + .read = troika_read, + .parse = troika_parse, +}; + +/* Plugin descriptor to comply with basic plugin specification */ +static const FlipperAppPluginDescriptor troika_plugin_descriptor = { + .appid = NFC_SUPPORTED_CARD_PLUGIN_APP_ID, + .ep_api_version = NFC_SUPPORTED_CARD_PLUGIN_API_VERSION, + .entry_point = &troika_plugin, +}; + +/* Plugin entry point - must return a pointer to const descriptor */ +const FlipperAppPluginDescriptor* troika_plugin_ep() { + return &troika_plugin_descriptor; +} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_read_success.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_read_success.c index 81e4d2c715e7..dcb6e651f2aa 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_read_success.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_read_success.c @@ -24,13 +24,13 @@ void nfc_scene_mf_classic_read_success_on_enter(void* context) { widget, GuiButtonTypeRight, "More", nfc_scene_mf_classic_read_success_widget_callback, nfc); FuriString* temp_str = NULL; - // if(furi_string_size(nfc->dev->dev_data.parsed_data)) { - // temp_str = furi_string_alloc_set(nfc->dev->dev_data.parsed_data); - // } else { + if(furi_string_size(nfc->parsed_data)) { + temp_str = furi_string_alloc_set(nfc->parsed_data); + } else { temp_str = furi_string_alloc_printf("\e#%s\n", mf_classic_get_name(mfc_data->type, true)); furi_string_cat_printf(temp_str, "UID:"); for(size_t i = 0; i < mfc_data->nfca_data.uid_len; i++) { - furi_string_cat_printf(temp_str, " %02X", mfc_data->nfca_data.uid[i]); + furi_string_cat_printf(temp_str, " %02X", mfc_data->nfca_data.uid[i]); } uint8_t sectors_total = mf_classic_get_total_sectors_num(mfc_data->type); uint8_t keys_total = sectors_total * 2; @@ -39,7 +39,7 @@ void nfc_scene_mf_classic_read_success_on_enter(void* context) { mf_classic_get_read_sectors_and_keys(mfc_data, §ors_read, &keys_found); furi_string_cat_printf(temp_str, "\nKeys Found: %d/%d", keys_found, keys_total); furi_string_cat_printf(temp_str, "\nSectors Read: %d/%d", sectors_read, sectors_total); - // } + } widget_add_text_scroll_element(widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); furi_string_free(temp_str); @@ -50,30 +50,30 @@ void nfc_scene_mf_classic_read_success_on_enter(void* context) { } bool nfc_scene_mf_classic_read_success_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - bool consumed = false; + NfcApp* 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, NfcSceneMfClassicMenu); - consumed = true; - } - } else if(event.type == SceneManagerEventTypeBack) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); + 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, NfcSceneMfClassicMenu); consumed = true; } + } else if(event.type == SceneManagerEventTypeBack) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); + consumed = true; + } - return consumed; + return consumed; } void nfc_scene_mf_classic_read_success_on_exit(void* context) { - NfcApp* nfc = context; + NfcApp* nfc = context; - notification_message_block(nfc->notifications, &sequence_reset_green); + notification_message_block(nfc->notifications, &sequence_reset_green); - // Clear view - widget_reset(nfc->widget); + // Clear view + widget_reset(nfc->widget); } diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_read_supported_card.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_read_supported_card.c index a5c65a1ca0c7..050b00b72bcc 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_read_supported_card.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_read_supported_card.c @@ -1,7 +1,7 @@ #include "../nfc_app_i.h" #include -void nfc_scene_read_supported_card_on_enter(void* context) { +void nfc_scene_mf_classic_read_supported_card_on_enter(void* context) { NfcApp* nfc = context; // Setup view @@ -10,19 +10,39 @@ void nfc_scene_read_supported_card_on_enter(void* context) { popup_set_icon(nfc->popup, 0, 8, &I_NFC_manual_60x50); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); - - nfc_blink_read_start(nfc); + + bool supported = false; + nfc->supported_cards = nfc_supported_cards_alloc(); + if(nfc_supported_cards_read( + nfc->supported_cards, + NfcDevProtocolMfClassic, + nfc->mf_classic_poller, + &nfc->nfc_dev_data.mf_classic_data)) { + supported = nfc_supported_cards_parse( + nfc->supported_cards, + NfcDevProtocolMfClassic, + &nfc->nfc_dev_data.mf_classic_data, + nfc->parsed_data); + } + + if(supported) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSuccess); + } else { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicDictAttack); + } + + nfc_supported_cards_free(nfc->supported_cards); } -bool nfc_scene_read_supported_card_on_event(void* context, SceneManagerEvent event) { +bool nfc_scene_mf_classic_read_supported_card_on_event(void* context, SceneManagerEvent event) { UNUSED(context); UNUSED(event); return false; } -void nfc_scene_read_supported_card_on_exit(void* context) { +void nfc_scene_mf_classic_read_supported_card_on_exit(void* context) { NfcApp* nfc = context; // Clear view diff --git a/applications/main/nfc/scenes/nfc_scene_read_card_type.c b/applications/main/nfc/scenes/nfc_scene_read_card_type.c index a07a502b5f08..30daa20d7362 100644 --- a/applications/main/nfc/scenes/nfc_scene_read_card_type.c +++ b/applications/main/nfc/scenes/nfc_scene_read_card_type.c @@ -1,9 +1,9 @@ #include "../nfc_app_i.h" enum SubmenuIndex { - SubmenuIndexReadMifareClassic, SubmenuIndexReadNFCA, SubmenuIndexReadMfUltralight, + SubmenuIndexReadMifareClassic, SubmenuIndexReadMifareDesfire, SubmenuIndexReadEMV, }; @@ -18,12 +18,6 @@ void nfc_scene_read_card_type_on_enter(void* context) { NfcApp* nfc = context; Submenu* submenu = nfc->submenu; - submenu_add_item( - submenu, - "Read Mifare Classic", - SubmenuIndexReadMifareClassic, - nfc_scene_read_card_type_submenu_callback, - nfc); submenu_add_item( submenu, "Read NFC-A data", @@ -36,6 +30,12 @@ void nfc_scene_read_card_type_on_enter(void* context) { SubmenuIndexReadMfUltralight, nfc_scene_read_card_type_submenu_callback, nfc); + submenu_add_item( + submenu, + "Read Mifare Classic", + SubmenuIndexReadMifareClassic, + nfc_scene_read_card_type_submenu_callback, + nfc); submenu_add_item( submenu, "Read Mifare DESFire", @@ -59,10 +59,6 @@ bool nfc_scene_read_card_type_on_event(void* context, SceneManagerEvent event) { bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { - if(event.event == SubmenuIndexReadMifareClassic) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicDictAttack); - consumed = true; - } if(event.event == SubmenuIndexReadMifareDesfire) { scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); consumed = true; @@ -71,6 +67,10 @@ bool nfc_scene_read_card_type_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightRead); consumed = true; } + if(event.event == SubmenuIndexReadMifareClassic) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSupportedCard); + consumed = true; + } if(event.event == SubmenuIndexReadEMV) { scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); consumed = true; diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 145af1dbd2d4..8fd7f9674532 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,+,26.3,, +Version,+,27.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -147,7 +147,8 @@ Header,+,lib/mlib/m-variant.h,, Header,+,lib/nanopb/pb.h,, Header,+,lib/nanopb/pb_decode.h,, Header,+,lib/nanopb/pb_encode.h,, -Header,+,lib/nfc/nfc_device.h,, +Header,+,lib/nfc/protocols/mf_classic/mf_classic.h,, +Header,+,lib/nfc/protocols/mf_classic/mf_classic_poller.h,, Header,+,lib/one_wire/maxim_crc.h,, Header,+,lib/one_wire/one_wire_host.h,, Header,+,lib/one_wire/one_wire_slave.h,, @@ -800,8 +801,6 @@ Function,+,elf_resolve_from_hashtable,_Bool,"const ElfApiInterface*, const char* Function,+,empty_screen_alloc,EmptyScreen*, Function,+,empty_screen_free,void,EmptyScreen* Function,+,empty_screen_get_view,View*,EmptyScreen* -Function,-,emv_card_emulation,_Bool,FuriHalNfcTxRxContext* -Function,-,emv_read_bank_card,_Bool,"FuriHalNfcTxRxContext*, EmvApplication*" Function,-,erand48,double,unsigned short[3] Function,-,erf,double,double Function,-,erfc,double,double @@ -1949,112 +1948,35 @@ Function,+,menu_free,void,Menu* Function,+,menu_get_view,View*,Menu* Function,+,menu_reset,void,Menu* Function,+,menu_set_selected_item,void,"Menu*, uint32_t" -Function,-,mf_classic_dict_add_key,_Bool,"MfClassicDict*, uint8_t*" -Function,-,mf_classic_dict_add_key_str,_Bool,"MfClassicDict*, FuriString*" -Function,-,mf_classic_dict_alloc,MfClassicDict*,MfClassicDictType -Function,-,mf_classic_dict_check_presence,_Bool,MfClassicDictType -Function,-,mf_classic_dict_delete_index,_Bool,"MfClassicDict*, uint32_t" -Function,-,mf_classic_dict_find_index,_Bool,"MfClassicDict*, uint8_t*, uint32_t*" -Function,-,mf_classic_dict_find_index_str,_Bool,"MfClassicDict*, FuriString*, uint32_t*" -Function,-,mf_classic_dict_free,void,MfClassicDict* -Function,-,mf_classic_dict_get_key_at_index,_Bool,"MfClassicDict*, uint64_t*, uint32_t" -Function,-,mf_classic_dict_get_key_at_index_str,_Bool,"MfClassicDict*, FuriString*, uint32_t" -Function,-,mf_classic_dict_get_next_key,_Bool,"MfClassicDict*, uint64_t*" -Function,-,mf_classic_dict_get_next_key_str,_Bool,"MfClassicDict*, FuriString*" -Function,-,mf_classic_dict_get_total_keys,uint32_t,MfClassicDict* -Function,-,mf_classic_dict_is_key_present,_Bool,"MfClassicDict*, uint8_t*" -Function,-,mf_classic_dict_is_key_present_str,_Bool,"MfClassicDict*, FuriString*" -Function,-,mf_classic_dict_rewind,_Bool,MfClassicDict* -Function,-,mf_classic_is_allowed_access_sector_trailer,_Bool,"MfClassicData*, uint8_t, MfClassicKey, MfClassicAction" -Function,-,mf_df_cat_application,void,"MifareDesfireApplication*, FuriString*" -Function,-,mf_df_cat_application_info,void,"MifareDesfireApplication*, FuriString*" -Function,-,mf_df_cat_card_info,void,"MifareDesfireData*, FuriString*" -Function,-,mf_df_cat_data,void,"MifareDesfireData*, FuriString*" -Function,-,mf_df_cat_file,void,"MifareDesfireFile*, FuriString*" -Function,-,mf_df_cat_free_mem,void,"MifareDesfireFreeMemory*, FuriString*" -Function,-,mf_df_cat_key_settings,void,"MifareDesfireKeySettings*, FuriString*" -Function,-,mf_df_cat_version,void,"MifareDesfireVersion*, FuriString*" -Function,-,mf_df_check_card_type,_Bool,"uint8_t, uint8_t, uint8_t" -Function,-,mf_df_clear,void,MifareDesfireData* -Function,-,mf_df_parse_get_application_ids_response,_Bool,"uint8_t*, uint16_t, MifareDesfireApplication**" -Function,-,mf_df_parse_get_file_ids_response,_Bool,"uint8_t*, uint16_t, MifareDesfireFile**" -Function,-,mf_df_parse_get_file_settings_response,_Bool,"uint8_t*, uint16_t, MifareDesfireFile*" -Function,-,mf_df_parse_get_free_memory_response,_Bool,"uint8_t*, uint16_t, MifareDesfireFreeMemory*" -Function,-,mf_df_parse_get_key_settings_response,_Bool,"uint8_t*, uint16_t, MifareDesfireKeySettings*" -Function,-,mf_df_parse_get_key_version_response,_Bool,"uint8_t*, uint16_t, MifareDesfireKeyVersion*" -Function,-,mf_df_parse_get_version_response,_Bool,"uint8_t*, uint16_t, MifareDesfireVersion*" -Function,-,mf_df_parse_read_data_response,_Bool,"uint8_t*, uint16_t, MifareDesfireFile*" -Function,-,mf_df_parse_select_application_response,_Bool,"uint8_t*, uint16_t" -Function,-,mf_df_prepare_get_application_ids,uint16_t,uint8_t* -Function,-,mf_df_prepare_get_file_ids,uint16_t,uint8_t* -Function,-,mf_df_prepare_get_file_settings,uint16_t,"uint8_t*, uint8_t" -Function,-,mf_df_prepare_get_free_memory,uint16_t,uint8_t* -Function,-,mf_df_prepare_get_key_settings,uint16_t,uint8_t* -Function,-,mf_df_prepare_get_key_version,uint16_t,"uint8_t*, uint8_t" -Function,-,mf_df_prepare_get_value,uint16_t,"uint8_t*, uint8_t" -Function,-,mf_df_prepare_get_version,uint16_t,uint8_t* -Function,-,mf_df_prepare_read_data,uint16_t,"uint8_t*, uint8_t, uint32_t, uint32_t" -Function,-,mf_df_prepare_read_records,uint16_t,"uint8_t*, uint8_t, uint32_t, uint32_t" -Function,-,mf_df_prepare_select_application,uint16_t,"uint8_t*, uint8_t[3]" -Function,-,mf_df_read_card,_Bool,"FuriHalNfcTxRxContext*, MifareDesfireData*" -Function,-,mf_ul_check_card_type,_Bool,"uint8_t, uint8_t, uint8_t" -Function,-,mf_ul_is_full_capture,_Bool,MfUltralightData* -Function,-,mf_ul_prepare_emulation,void,"MfUltralightEmulator*, MfUltralightData*" -Function,-,mf_ul_prepare_emulation_response,_Bool,"uint8_t*, uint16_t, uint8_t*, uint16_t*, uint32_t*, void*" -Function,-,mf_ul_pwdgen_amiibo,uint32_t,FuriHalNfcDevData* -Function,-,mf_ul_pwdgen_xiaomi,uint32_t,FuriHalNfcDevData* -Function,-,mf_ul_read_card,_Bool,"FuriHalNfcTxRxContext*, MfUltralightReader*, MfUltralightData*" -Function,-,mf_ul_reset,void,MfUltralightData* -Function,-,mf_ul_reset_emulation,void,"MfUltralightEmulator*, _Bool" -Function,-,mf_ultralight_authenticate,_Bool,"FuriHalNfcTxRxContext*, uint32_t, uint16_t*" -Function,-,mf_ultralight_fast_read_pages,_Bool,"FuriHalNfcTxRxContext*, MfUltralightReader*, MfUltralightData*" -Function,-,mf_ultralight_get_config_pages,MfUltralightConfigPages*,MfUltralightData* -Function,-,mf_ultralight_read_counters,_Bool,"FuriHalNfcTxRxContext*, MfUltralightData*" -Function,-,mf_ultralight_read_pages,_Bool,"FuriHalNfcTxRxContext*, MfUltralightReader*, MfUltralightData*" -Function,-,mf_ultralight_read_pages_direct,_Bool,"FuriHalNfcTxRxContext*, uint8_t, uint8_t*" -Function,-,mf_ultralight_read_signature,_Bool,"FuriHalNfcTxRxContext*, MfUltralightData*" -Function,-,mf_ultralight_read_tearing_flags,_Bool,"FuriHalNfcTxRxContext*, MfUltralightData*" -Function,-,mf_ultralight_read_version,_Bool,"FuriHalNfcTxRxContext*, MfUltralightReader*, MfUltralightData*" -Function,-,mifare_classic_auth_attempt,_Bool,"FuriHalNfcTxRxContext*, Crypto1*, MfClassicAuthContext*, uint64_t" -Function,-,mifare_classic_auth_init_context,void,"MfClassicAuthContext*, uint8_t" -Function,-,mifare_classic_auth_write_block,_Bool,"FuriHalNfcTxRxContext*, MfClassicBlock*, uint8_t, MfClassicKey, uint64_t" -Function,-,mifare_classic_authenticate,_Bool,"FuriHalNfcTxRxContext*, uint8_t, uint64_t, MfClassicKey" -Function,-,mifare_classic_authenticate_skip_activate,_Bool,"FuriHalNfcTxRxContext*, uint8_t, uint64_t, MfClassicKey, _Bool, uint32_t" -Function,-,mifare_classic_block_to_value,_Bool,"const uint8_t*, int32_t*, uint8_t*" -Function,-,mifare_classic_check_card_type,_Bool,"uint8_t, uint8_t, uint8_t" -Function,-,mifare_classic_emulator,_Bool,"MfClassicEmulator*, FuriHalNfcTxRxContext*" -Function,-,mifare_classic_get_classic_type,MfClassicType,"uint8_t, uint8_t, uint8_t" -Function,-,mifare_classic_get_read_sectors_and_keys,void,"MfClassicData*, uint8_t*, uint8_t*" -Function,-,mifare_classic_get_sector_by_block,uint8_t,uint8_t -Function,-,mifare_classic_get_sector_trailer_block_num_by_sector,uint8_t,uint8_t -Function,-,mifare_classic_get_sector_trailer_by_sector,MfClassicSectorTrailer*,"MfClassicData*, uint8_t" -Function,-,mifare_classic_get_total_block_num,uint16_t,MfClassicType -Function,-,mifare_classic_get_total_sectors_num,uint8_t,MfClassicType -Function,-,mifare_classic_get_type_str,const char*,MfClassicType -Function,-,mifare_classic_halt,void,"FuriHalNfcTxRxContext*, Crypto1*" -Function,-,mifare_classic_is_allowed_access_data_block,_Bool,"MfClassicData*, uint8_t, MfClassicKey, MfClassicAction" -Function,-,mifare_classic_is_block_read,_Bool,"MfClassicData*, uint8_t" -Function,-,mifare_classic_is_card_read,_Bool,MfClassicData* -Function,-,mifare_classic_is_key_found,_Bool,"MfClassicData*, uint8_t, MfClassicKey" -Function,-,mifare_classic_is_sector_data_read,_Bool,"MfClassicData*, uint8_t" -Function,-,mifare_classic_is_sector_read,_Bool,"MfClassicData*, uint8_t" -Function,-,mifare_classic_is_sector_trailer,_Bool,uint8_t -Function,-,mifare_classic_is_value_block,_Bool,"MfClassicData*, uint8_t" -Function,-,mifare_classic_read_block,_Bool,"FuriHalNfcTxRxContext*, Crypto1*, uint8_t, MfClassicBlock*" -Function,-,mifare_classic_read_card,uint8_t,"FuriHalNfcTxRxContext*, MfClassicReader*, MfClassicData*" -Function,-,mifare_classic_read_sector,void,"FuriHalNfcTxRxContext*, MfClassicData*, uint8_t" -Function,-,mifare_classic_reader_add_sector,void,"MfClassicReader*, uint8_t, uint64_t, uint64_t" -Function,-,mifare_classic_set_block_read,void,"MfClassicData*, uint8_t, MfClassicBlock*" -Function,-,mifare_classic_set_key_found,void,"MfClassicData*, uint8_t, MfClassicKey, uint64_t" -Function,-,mifare_classic_set_key_not_found,void,"MfClassicData*, uint8_t, MfClassicKey" -Function,-,mifare_classic_set_sector_data_not_read,void,MfClassicData* -Function,-,mifare_classic_transfer,_Bool,"FuriHalNfcTxRxContext*, Crypto1*, uint8_t" -Function,-,mifare_classic_update_card,uint8_t,"FuriHalNfcTxRxContext*, MfClassicData*" -Function,-,mifare_classic_value_cmd,_Bool,"FuriHalNfcTxRxContext*, Crypto1*, uint8_t, uint8_t, int32_t" -Function,-,mifare_classic_value_cmd_full,_Bool,"FuriHalNfcTxRxContext*, MfClassicBlock*, uint8_t, MfClassicKey, uint64_t, int32_t" -Function,-,mifare_classic_value_to_block,void,"int32_t, uint8_t, uint8_t*" -Function,-,mifare_classic_write_block,_Bool,"FuriHalNfcTxRxContext*, Crypto1*, uint8_t, MfClassicBlock*" -Function,-,mifare_classic_write_sector,_Bool,"FuriHalNfcTxRxContext*, MfClassicData*, MfClassicData*, uint8_t" +Function,-,mf_classic_detect_protocol,_Bool,"NfcaData*, MfClassicType*" +Function,-,mf_classic_get_blocks_num_in_sector,uint8_t,uint8_t +Function,-,mf_classic_get_first_block_num_of_sector,uint8_t,uint8_t +Function,-,mf_classic_get_name,const char*,"MfClassicType, _Bool" +Function,-,mf_classic_get_read_sectors_and_keys,void,"MfClassicData*, uint8_t*, uint8_t*" +Function,-,mf_classic_get_sector_by_block,uint8_t,uint8_t +Function,-,mf_classic_get_sector_trailer_by_sector,MfClassicSectorTrailer*,"MfClassicData*, uint8_t" +Function,-,mf_classic_get_sector_trailer_num_by_block,uint8_t,uint8_t +Function,+,mf_classic_get_sector_trailer_num_by_sector,uint8_t,uint8_t +Function,-,mf_classic_get_total_block_num,uint16_t,MfClassicType +Function,-,mf_classic_get_total_sectors_num,uint8_t,MfClassicType +Function,-,mf_classic_is_block_read,_Bool,"MfClassicData*, uint8_t" +Function,-,mf_classic_is_card_read,_Bool,MfClassicData* +Function,-,mf_classic_is_key_found,_Bool,"MfClassicData*, uint8_t, MfClassicKeyType" +Function,-,mf_classic_is_sector_read,_Bool,"MfClassicData*, uint8_t" +Function,-,mf_classic_is_sector_trailer,_Bool,uint8_t +Function,-,mf_classic_poller_alloc,MfClassicPoller*,NfcaPoller* +Function,+,mf_classic_poller_auth,MfClassicError,"MfClassicPoller*, uint8_t, MfClassicKey*, MfClassicKeyType, MfClassicAuthContext*" +Function,-,mf_classic_poller_dict_attack,MfClassicError,"MfClassicPoller*, MfClassicPollerCallback, void*" +Function,-,mf_classic_poller_free,void,MfClassicPoller* +Function,-,mf_classic_poller_get_data,MfClassicError,"MfClassicPoller*, MfClassicData*" +Function,-,mf_classic_poller_read,MfClassicError,"MfClassicPoller*, MfClassicDeviceKeys*, MfClassicData*" +Function,-,mf_classic_poller_read_block,MfClassicError,"MfClassicPoller*, uint8_t, MfClassicKey*, MfClassicKeyType, MfClassicBlock*" +Function,-,mf_classic_poller_reset,MfClassicError,MfClassicPoller* +Function,-,mf_classic_poller_start,MfClassicError,"MfClassicPoller*, NfcaPollerEventCallback, void*" +Function,-,mf_classic_poller_stop,MfClassicError,MfClassicPoller* +Function,-,mf_classic_set_block_read,void,"MfClassicData*, uint8_t, MfClassicBlock*" +Function,-,mf_classic_set_key_found,void,"MfClassicData*, uint8_t, MfClassicKeyType, uint64_t" +Function,-,mf_classic_set_key_not_found,void,"MfClassicData*, uint8_t, MfClassicKeyType" Function,-,mkdtemp,char*,char* Function,-,mkostemp,int,"char*, int" Function,-,mkostemps,int,"char*, int, int" @@ -2078,22 +2000,37 @@ Function,-,nextafterl,long double,"long double, long double" Function,-,nexttoward,double,"double, long double" Function,-,nexttowardf,float,"float, long double" Function,-,nexttowardl,long double,"long double, long double" -Function,+,nfc_device_alloc,NfcDevice*, -Function,+,nfc_device_clear,void,NfcDevice* -Function,+,nfc_device_data_clear,void,NfcDeviceData* -Function,+,nfc_device_delete,_Bool,"NfcDevice*, _Bool" -Function,+,nfc_device_free,void,NfcDevice* -Function,+,nfc_device_load,_Bool,"NfcDevice*, const char*, _Bool" -Function,+,nfc_device_load_key_cache,_Bool,NfcDevice* -Function,+,nfc_device_restore,_Bool,"NfcDevice*, _Bool" -Function,+,nfc_device_save,_Bool,"NfcDevice*, const char*" -Function,+,nfc_device_save_shadow,_Bool,"NfcDevice*, const char*" -Function,+,nfc_device_set_loading_callback,void,"NfcDevice*, NfcLoadingCallback, void*" -Function,+,nfc_device_set_name,void,"NfcDevice*, const char*" -Function,+,nfc_file_select,_Bool,NfcDevice* +Function,-,nfc_alloc,Nfc*, +Function,-,nfc_config,void,"Nfc*, NfcMode" +Function,-,nfc_free,void,Nfc* +Function,-,nfc_iso13444a_sdd_frame,NfcError,"Nfc*, uint8_t*, uint16_t, uint8_t*, uint16_t, uint16_t*, uint32_t" +Function,-,nfc_iso13444a_short_frame,NfcError,"Nfc*, NfcIso14443aShortFrame, uint8_t*, uint16_t, uint16_t*, uint32_t" +Function,-,nfc_listener_abort,void,Nfc* +Function,-,nfc_listener_set_col_res_data,NfcError,"Nfc*, uint8_t*, uint8_t, uint8_t*, uint8_t" +Function,-,nfc_listener_sleep,NfcError,Nfc* +Function,-,nfc_listener_tx,NfcError,"Nfc*, uint8_t*, uint16_t" +Function,-,nfc_set_fdt_listen_fc,void,"Nfc*, uint32_t" +Function,-,nfc_set_fdt_poll_fc,void,"Nfc*, uint32_t" +Function,-,nfc_set_fdt_poll_poll_us,void,"Nfc*, uint32_t" +Function,-,nfc_set_guard_time_us,void,"Nfc*, uint32_t" +Function,-,nfc_set_mask_receive_time_fc,void,"Nfc*, uint32_t" +Function,-,nfc_start_listener,void,"Nfc*, NfcEventCallback, void*" +Function,-,nfc_start_poller,void,"Nfc*, NfcEventCallback, void*" +Function,-,nfc_stop,void,Nfc* +Function,-,nfc_trx,NfcError,"Nfc*, uint8_t*, uint16_t, uint8_t*, uint16_t, uint16_t*, uint32_t" +Function,-,nfc_trx_custom_parity,NfcError,"Nfc*, uint8_t*, uint16_t, uint8_t*, uint16_t, uint16_t*, uint32_t" +Function,-,nfca_append_crc,void,"uint8_t*, uint16_t" Function,-,nfca_append_crc16,void,"uint8_t*, uint16_t" +Function,-,nfca_check_crc,_Bool,"uint8_t*, uint16_t" Function,-,nfca_emulation_handler,_Bool,"uint8_t*, uint16_t, uint8_t*, uint16_t*" +Function,-,nfca_get_crc,uint16_t,"uint8_t*, uint16_t" Function,-,nfca_get_crc16,uint16_t,"uint8_t*, uint16_t" +Function,-,nfca_poller_alloc,NfcaPoller*,Nfc* +Function,-,nfca_poller_free,void,NfcaPoller* +Function,-,nfca_poller_get_data,NfcaError,"NfcaPoller*, NfcaData*" +Function,-,nfca_poller_read,NfcaError,"NfcaPoller*, NfcaData*" +Function,-,nfca_poller_start,NfcaError,"NfcaPoller*, NfcaPollerEventCallback, void*" +Function,-,nfca_poller_stop,NfcaError,NfcaPoller* Function,-,nfca_signal_alloc,NfcaSignal*, Function,-,nfca_signal_encode,void,"NfcaSignal*, uint8_t*, uint16_t, uint8_t*" Function,-,nfca_signal_free,void,NfcaSignal* @@ -2102,15 +2039,6 @@ Function,+,notification_internal_message_block,void,"NotificationApp*, const Not Function,+,notification_message,void,"NotificationApp*, const NotificationSequence*" Function,+,notification_message_block,void,"NotificationApp*, const NotificationSequence*" Function,-,nrand48,long,unsigned short[3] -Function,-,old_crypto1_bit,uint8_t,"Crypto1*, uint8_t, int" -Function,-,old_crypto1_byte,uint8_t,"Crypto1*, uint8_t, int" -Function,-,old_crypto1_decrypt,void,"Crypto1*, uint8_t*, uint16_t, uint8_t*" -Function,-,old_crypto1_encrypt,void,"Crypto1*, uint8_t*, uint8_t*, uint16_t, uint8_t*, uint8_t*" -Function,-,old_crypto1_filter,uint32_t,uint32_t -Function,-,old_crypto1_init,void,"Crypto1*, uint64_t" -Function,-,old_crypto1_reset,void,Crypto1* -Function,-,old_crypto1_word,uint32_t,"Crypto1*, uint32_t, int" -Function,-,old_prng_successor,uint32_t,"uint32_t, uint32_t" Function,-,on_exit,int,"void (*)(int, void*), void*" Function,+,onewire_host_alloc,OneWireHost*,const GpioPin* Function,+,onewire_host_free,void,OneWireHost* diff --git a/lib/nfc/SConscript b/lib/nfc/SConscript index b086298de2aa..7e2123b74614 100644 --- a/lib/nfc/SConscript +++ b/lib/nfc/SConscript @@ -5,7 +5,8 @@ env.Append( "#/lib/nfc", ], SDK_HEADERS=[ - File("nfc_device.h"), + File("protocols/mf_classic/mf_classic.h"), + File("protocols/mf_classic/mf_classic_poller.h"), ], ) diff --git a/lib/nfc/nfc_poller.h b/lib/nfc/nfc_poller.h index 95aa6e8e663b..864da9b62bdb 100644 --- a/lib/nfc/nfc_poller.h +++ b/lib/nfc/nfc_poller.h @@ -7,6 +7,7 @@ extern "C" { #include #include #include +#include typedef struct NfcPoller NfcPoller; @@ -14,6 +15,8 @@ typedef struct { Nfc* nfc; NfcaPoller* nfca_poller; NfcbPoller* nfcb_poller; + MfUltralightPoller* mfu_poller; + MfClassicPoller* mfc_poller; } NfcPollerCollection; typedef enum { diff --git a/lib/nfc/protocols/mf_classic/mf_classic.h b/lib/nfc/protocols/mf_classic/mf_classic.h index bc4f1cc4c8de..5e27d22f523d 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic.h +++ b/lib/nfc/protocols/mf_classic/mf_classic.h @@ -12,6 +12,7 @@ extern "C" { #define MF_CLASSIC_HALT_MSB_CMD (0x50) #define MF_CLASSIC_HALT_LSB_CMD (0x00) +#define MF_CLASSIC_TOTAL_SECTORS_MAX (40) #define MF_CLASSIC_TOTAL_BLOCKS_MAX (256) #define MF_CLASSIC_BLOCK_SIZE (16) #define MF_CLASSIC_KEY_SIZE (6) @@ -101,6 +102,13 @@ typedef struct { MfClassicKey key_b; } MfClassicSectorTrailer; +typedef struct { + MfClassicKey key_a[MF_CLASSIC_TOTAL_SECTORS_MAX]; + MfClassicKey key_b[MF_CLASSIC_TOTAL_SECTORS_MAX]; + uint64_t key_a_mask; + uint64_t key_b_mask; +} MfClassicDeviceKeys; + typedef struct { NfcaData nfca_data; MfClassicType type; diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller.h b/lib/nfc/protocols/mf_classic/mf_classic_poller.h index bf872be3c595..3bf55d1e0b84 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller.h +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller.h @@ -95,6 +95,11 @@ MfClassicError mf_classic_poller_read_block( MfClassicKeyType key_type, MfClassicBlock* data); +MfClassicError mf_classic_poller_read( + MfClassicPoller* instance, + MfClassicDeviceKeys* keys, + MfClassicData* data); + #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/nfca/nfca_poller.c b/lib/nfc/protocols/nfca/nfca_poller.c index c70077a246b7..0dbadeb0526c 100644 --- a/lib/nfc/protocols/nfca/nfca_poller.c +++ b/lib/nfc/protocols/nfca/nfca_poller.c @@ -120,16 +120,22 @@ NfcaError nfca_poller_stop(NfcaPoller* instance) { furi_assert(instance); furi_assert(instance->data); + NfcaError error = NfcaErrorNone; + instance->session_state = NfcaPollerSessionStateStopRequest; nfc_stop(instance->nfc); instance->session_state = NfcaPollerSessionStateIdle; + if(instance->config_state == NfcaPollerConfigStateDone) { + error = nfca_poller_reset(instance); + } + // Check that data is freed furi_assert(instance->buff == NULL); free(instance->data); - return NfcaErrorNone; + return error; } static NfcaPollerCommand nfca_poller_sync_callback(NfcaPollerEvent event, void* context) { diff --git a/lib/nfc/protocols/nfca/nfca_poller_i.c b/lib/nfc/protocols/nfca/nfca_poller_i.c index 43d6ff3ac43e..d6ad29bb73c7 100644 --- a/lib/nfc/protocols/nfca/nfca_poller_i.c +++ b/lib/nfc/protocols/nfca/nfca_poller_i.c @@ -105,6 +105,7 @@ NfcaError nfca_poller_config(NfcaPoller* instance) { nfc_set_guard_time_us(instance->nfc, NFCA_GUARD_TIME_US); nfc_set_fdt_poll_fc(instance->nfc, NFCA_FDT_POLL_FC); nfc_set_fdt_poll_poll_us(instance->nfc, NFCA_POLL_POLL_MIN_US); + instance->config_state = NfcaPollerConfigStateDone; return NfcaErrorNone; } @@ -118,6 +119,7 @@ NfcaError nfca_poller_reset(NfcaPoller* instance) { instance->state = NfcaPollerStateIdle; nfc_poller_buffer_free(instance->buff); instance->buff = NULL; + instance->config_state = NfcaPollerConfigStateIdle; return NfcaErrorNone; } diff --git a/lib/nfc/protocols/nfca/nfca_poller_i.h b/lib/nfc/protocols/nfca/nfca_poller_i.h index 487f1c8e389f..981f07dbf596 100644 --- a/lib/nfc/protocols/nfca/nfca_poller_i.h +++ b/lib/nfc/protocols/nfca/nfca_poller_i.h @@ -44,10 +44,16 @@ typedef enum { NfcaPollerSessionStateStopRequest, } NfcaPollerSessionState; +typedef enum { + NfcaPollerConfigStateIdle, + NfcaPollerConfigStateDone, +} NfcaPollerConfigState; + struct NfcaPoller { Nfc* nfc; NfcaPollerState state; NfcaPollerSessionState session_state; + NfcaPollerConfigState config_state; NfcaPollerColRes col_res; NfcaData* data; NfcPollerBuffer* buff; From cc4dd36dbfcbaba676099890895f0bb7ac13b9e8 Mon Sep 17 00:00:00 2001 From: gornekich Date: Tue, 6 Jun 2023 18:56:40 +0400 Subject: [PATCH 099/149] nfc: format sources --- .../main/nfc/scenes/nfc_scene_config.h | 1 - ...nfc_scene_mf_classic_read_supported_card.c | 2 +- .../nfc_scene_mf_ultralight_read_success.c | 3 +- .../main/nfc/scenes/nfc_scene_nfca_emulate.c | 3 +- .../main/nfc/scenes/nfc_scene_saved_menu.c | 4 +- .../main/nfc/scenes/nfc_scene_start.c | 3 +- .../main/nfc_rpc/assets/compiled/main.pb.c | 5 - .../main/nfc_rpc/assets/compiled/main.pb.h | 260 +++++++++++++---- .../nfc_rpc/assets/compiled/mf_classic.pb.c | 8 - .../nfc_rpc/assets/compiled/mf_classic.pb.h | 124 +++++--- .../assets/compiled/mf_ultralight.pb.c | 19 -- .../assets/compiled/mf_ultralight.pb.h | 264 ++++++++++++------ .../main/nfc_rpc/assets/compiled/nfca.pb.c | 9 - .../main/nfc_rpc/assets/compiled/nfca.pb.h | 131 +++++---- applications/main/nfc_rpc/nfc_rpc.c | 3 +- lib/nfc/nfc_device.c | 3 +- lib/nfc/parsers/plantain_4k_parser.c | 6 +- lib/nfc/parsers/plantain_parser.c | 3 +- lib/nfc/parsers/troika_4k_parser.c | 3 +- lib/nfc/parsers/troika_parser.c | 3 +- lib/nfc/parsers/two_cities.c | 3 +- lib/nfc/protocols/mifare_classic.c | 43 ++- lib/nfc/protocols/mifare_classic.h | 10 +- lib/nfc/protocols/nfcb/nfcb_poller.c | 2 +- 24 files changed, 595 insertions(+), 320 deletions(-) diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index 99e5992fa796..5def783f3f9b 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -26,7 +26,6 @@ ADD_SCENE(nfc, mf_ultralight_unlock_warn, MfUltralightUnlockWarn) ADD_SCENE(nfc, mf_ultralight_key_input, MfUltralightKeyInput) ADD_SCENE(nfc, mf_ultralight_capture_pass, MfUltralightCapturePass) - ADD_SCENE(nfc, mf_classic_read_supported_card, MfClassicReadSupportedCard) ADD_SCENE(nfc, mf_classic_dict_attack, MfClassicDictAttack) ADD_SCENE(nfc, mf_classic_read_success, MfClassicReadSuccess) diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_read_supported_card.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_read_supported_card.c index 050b00b72bcc..57352afb27ed 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_read_supported_card.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_read_supported_card.c @@ -25,7 +25,7 @@ void nfc_scene_mf_classic_read_supported_card_on_enter(void* context) { &nfc->nfc_dev_data.mf_classic_data, nfc->parsed_data); } - + if(supported) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSuccess); } else { diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_success.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_success.c index f53619832dd1..150d8d9fa724 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_success.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_success.c @@ -27,8 +27,7 @@ void nfc_scene_mf_ultralight_read_success_on_enter(void* context) { for(size_t i = 0; i < data->nfca_data.uid_len; i++) { furi_string_cat_printf(temp_str, " %02X", data->nfca_data.uid[i]); } - furi_string_cat_printf( - temp_str, "\nPages Read: %d/%d", data->pages_read, data->pages_total); + furi_string_cat_printf(temp_str, "\nPages Read: %d/%d", data->pages_read, data->pages_total); if(data->pages_read != data->pages_total) { furi_string_cat_printf(temp_str, "\nPassword-protected pages!"); } diff --git a/applications/main/nfc/scenes/nfc_scene_nfca_emulate.c b/applications/main/nfc/scenes/nfc_scene_nfca_emulate.c index 21e243c6855e..b39a7e75252d 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfca_emulate.c +++ b/applications/main/nfc/scenes/nfc_scene_nfca_emulate.c @@ -7,7 +7,8 @@ enum { NfcSceneNfcaEmulateStateTextBox, }; -NfcaListenerCommand nfc_scene_nfca_emulate_worker_callback(NfcaListenerEvent event, void* context) { +NfcaListenerCommand + nfc_scene_nfca_emulate_worker_callback(NfcaListenerEvent event, void* context) { furi_assert(context); NfcApp* nfc = context; diff --git a/applications/main/nfc/scenes/nfc_scene_saved_menu.c b/applications/main/nfc/scenes/nfc_scene_saved_menu.c index 3ff05729eb75..10651d1d48bf 100644 --- a/applications/main/nfc/scenes/nfc_scene_saved_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_saved_menu.c @@ -162,9 +162,9 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { // FURI_LOG_I("nfc", "application_info_present: %d", application_info_present); // if(application_info_present) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); // } else { - // scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); + // scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); // } consumed = true; } else if(event.event == SubmenuIndexRestoreOriginal) { diff --git a/applications/main/nfc/scenes/nfc_scene_start.c b/applications/main/nfc/scenes/nfc_scene_start.c index fd083aad55f8..1315f1036866 100644 --- a/applications/main/nfc/scenes/nfc_scene_start.c +++ b/applications/main/nfc/scenes/nfc_scene_start.c @@ -68,8 +68,7 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(nfc->scene_manager, NfcSceneExtraActions); consumed = true; } else if(event.event == SubmenuIndexAddManually) { - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneStart, NfcSceneSetType); + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneStart, NfcSceneSetType); scene_manager_next_scene(nfc->scene_manager, NfcSceneSetType); consumed = true; } else if(event.event == SubmenuIndexDebug) { diff --git a/applications/main/nfc_rpc/assets/compiled/main.pb.c b/applications/main/nfc_rpc/assets/compiled/main.pb.c index 9b574c9d6f71..a9c4d20613c5 100644 --- a/applications/main/nfc_rpc/assets/compiled/main.pb.c +++ b/applications/main/nfc_rpc/assets/compiled/main.pb.c @@ -8,9 +8,4 @@ PB_BIND(Nfc_Empty, Nfc_Empty, AUTO) - PB_BIND(Nfc_Main, Nfc_Main, 2) - - - - diff --git a/applications/main/nfc_rpc/assets/compiled/main.pb.h b/applications/main/nfc_rpc/assets/compiled/main.pb.h index 0c25a8855ded..6c85b126d8cb 100644 --- a/applications/main/nfc_rpc/assets/compiled/main.pb.h +++ b/applications/main/nfc_rpc/assets/compiled/main.pb.h @@ -18,7 +18,8 @@ typedef enum _Nfc_CommandStatus { Nfc_CommandStatus_ERROR = 1, /* *< Unknown error */ Nfc_CommandStatus_ERROR_NOT_IMPLEMENTED = 3, /* *< Command succesfully decoded, but not implemented (deprecated or not yet implemented) */ - Nfc_CommandStatus_ERROR_BUSY = 4 /* *< Somebody took global lock, so not all commands are available */ + Nfc_CommandStatus_ERROR_BUSY = + 4 /* *< Somebody took global lock, so not all commands are available */ } Nfc_CommandStatus; /* Struct definitions */ @@ -61,7 +62,6 @@ typedef struct _Nfc_Main { } content; } Nfc_Main; - #ifdef __cplusplus extern "C" { #endif @@ -69,27 +69,37 @@ extern "C" { /* Helper constants for enums */ #define _Nfc_CommandStatus_MIN Nfc_CommandStatus_OK #define _Nfc_CommandStatus_MAX Nfc_CommandStatus_ERROR_BUSY -#define _Nfc_CommandStatus_ARRAYSIZE ((Nfc_CommandStatus)(Nfc_CommandStatus_ERROR_BUSY+1)) - +#define _Nfc_CommandStatus_ARRAYSIZE ((Nfc_CommandStatus)(Nfc_CommandStatus_ERROR_BUSY + 1)) #define Nfc_Main_command_status_ENUMTYPE Nfc_CommandStatus - /* Initializer values for message structs */ -#define Nfc_Empty_init_default {0} -#define Nfc_Main_init_default {_Nfc_CommandStatus_MIN, {{NULL}, NULL}, 0, {Nfc_Empty_init_default}} -#define Nfc_Empty_init_zero {0} -#define Nfc_Main_init_zero {_Nfc_CommandStatus_MIN, {{NULL}, NULL}, 0, {Nfc_Empty_init_zero}} +#define Nfc_Empty_init_default \ + { 0 } +#define Nfc_Main_init_default \ + { \ + _Nfc_CommandStatus_MIN, {{NULL}, NULL}, 0, { \ + Nfc_Empty_init_default \ + } \ + } +#define Nfc_Empty_init_zero \ + { 0 } +#define Nfc_Main_init_zero \ + { \ + _Nfc_CommandStatus_MIN, {{NULL}, NULL}, 0, { \ + Nfc_Empty_init_zero \ + } \ + } /* Field tags (for use in manual encoding/decoding) */ -#define Nfc_Main_command_status_tag 1 -#define Nfc_Main_empty_tag 2 -#define Nfc_Main_nfca_read_req_tag 3 -#define Nfc_Main_nfca_read_resp_tag 4 -#define Nfc_Main_nfca_emulate_start_req_tag 5 -#define Nfc_Main_nfca_emulate_start_resp_tag 6 -#define Nfc_Main_nfca_emulate_stop_req_tag 7 -#define Nfc_Main_nfca_emulate_stop_resp_tag 8 +#define Nfc_Main_command_status_tag 1 +#define Nfc_Main_empty_tag 2 +#define Nfc_Main_nfca_read_req_tag 3 +#define Nfc_Main_nfca_read_resp_tag 4 +#define Nfc_Main_nfca_emulate_start_req_tag 5 +#define Nfc_Main_nfca_emulate_start_resp_tag 6 +#define Nfc_Main_nfca_emulate_stop_req_tag 7 +#define Nfc_Main_nfca_emulate_stop_resp_tag 8 #define Nfc_Main_mf_ultralight_read_page_req_tag 9 #define Nfc_Main_mf_ultralight_read_page_resp_tag 10 #define Nfc_Main_mf_ultralight_read_version_req_tag 11 @@ -106,46 +116,163 @@ extern "C" { #define Nfc_Main_mf_ultralight_emulate_start_resp_tag 22 #define Nfc_Main_mf_ultralight_emulate_stop_req_tag 23 #define Nfc_Main_mf_ultralight_emulate_stop_resp_tag 24 -#define Nfc_Main_mf_classic_auth_req_tag 25 -#define Nfc_Main_mf_classic_auth_resp_tag 26 -#define Nfc_Main_mf_classic_read_block_req_tag 27 -#define Nfc_Main_mf_classic_read_block_resp_tag 28 +#define Nfc_Main_mf_classic_auth_req_tag 25 +#define Nfc_Main_mf_classic_auth_resp_tag 26 +#define Nfc_Main_mf_classic_read_block_req_tag 27 +#define Nfc_Main_mf_classic_read_block_resp_tag 28 /* Struct field encoding specification for nanopb */ -#define Nfc_Empty_FIELDLIST(X, a) \ +#define Nfc_Empty_FIELDLIST(X, a) #define Nfc_Empty_CALLBACK NULL #define Nfc_Empty_DEFAULT NULL -#define Nfc_Main_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UENUM, command_status, 1) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,empty,content.empty), 2) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,nfca_read_req,content.nfca_read_req), 3) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,nfca_read_resp,content.nfca_read_resp), 4) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,nfca_emulate_start_req,content.nfca_emulate_start_req), 5) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,nfca_emulate_start_resp,content.nfca_emulate_start_resp), 6) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,nfca_emulate_stop_req,content.nfca_emulate_stop_req), 7) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,nfca_emulate_stop_resp,content.nfca_emulate_stop_resp), 8) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_page_req,content.mf_ultralight_read_page_req), 9) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_page_resp,content.mf_ultralight_read_page_resp), 10) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_version_req,content.mf_ultralight_read_version_req), 11) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_version_resp,content.mf_ultralight_read_version_resp), 12) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_write_page_req,content.mf_ultralight_write_page_req), 13) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_write_page_resp,content.mf_ultralight_write_page_resp), 14) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_signature_req,content.mf_ultralight_read_signature_req), 15) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_signature_resp,content.mf_ultralight_read_signature_resp), 16) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_counter_req,content.mf_ultralight_read_counter_req), 17) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_counter_resp,content.mf_ultralight_read_counter_resp), 18) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_tearing_flag_req,content.mf_ultralight_read_tearing_flag_req), 19) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_tearing_flag_resp,content.mf_ultralight_read_tearing_flag_resp), 20) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_emulate_start_req,content.mf_ultralight_emulate_start_req), 21) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_emulate_start_resp,content.mf_ultralight_emulate_start_resp), 22) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_emulate_stop_req,content.mf_ultralight_emulate_stop_req), 23) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_emulate_stop_resp,content.mf_ultralight_emulate_stop_resp), 24) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_classic_auth_req,content.mf_classic_auth_req), 25) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_classic_auth_resp,content.mf_classic_auth_resp), 26) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_classic_read_block_req,content.mf_classic_read_block_req), 27) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_classic_read_block_resp,content.mf_classic_read_block_resp), 28) +#define Nfc_Main_FIELDLIST(X, a) \ + X(a, STATIC, SINGULAR, UENUM, command_status, 1) \ + X(a, STATIC, ONEOF, MSG_W_CB, (content, empty, content.empty), 2) \ + X(a, STATIC, ONEOF, MSG_W_CB, (content, nfca_read_req, content.nfca_read_req), 3) \ + X(a, STATIC, ONEOF, MSG_W_CB, (content, nfca_read_resp, content.nfca_read_resp), 4) \ + X(a, \ + STATIC, \ + ONEOF, \ + MSG_W_CB, \ + (content, nfca_emulate_start_req, content.nfca_emulate_start_req), \ + 5) \ + X(a, \ + STATIC, \ + ONEOF, \ + MSG_W_CB, \ + (content, nfca_emulate_start_resp, content.nfca_emulate_start_resp), \ + 6) \ + X(a, \ + STATIC, \ + ONEOF, \ + MSG_W_CB, \ + (content, nfca_emulate_stop_req, content.nfca_emulate_stop_req), \ + 7) \ + X(a, \ + STATIC, \ + ONEOF, \ + MSG_W_CB, \ + (content, nfca_emulate_stop_resp, content.nfca_emulate_stop_resp), \ + 8) \ + X(a, \ + STATIC, \ + ONEOF, \ + MSG_W_CB, \ + (content, mf_ultralight_read_page_req, content.mf_ultralight_read_page_req), \ + 9) \ + X(a, \ + STATIC, \ + ONEOF, \ + MSG_W_CB, \ + (content, mf_ultralight_read_page_resp, content.mf_ultralight_read_page_resp), \ + 10) \ + X(a, \ + STATIC, \ + ONEOF, \ + MSG_W_CB, \ + (content, mf_ultralight_read_version_req, content.mf_ultralight_read_version_req), \ + 11) \ + X(a, \ + STATIC, \ + ONEOF, \ + MSG_W_CB, \ + (content, mf_ultralight_read_version_resp, content.mf_ultralight_read_version_resp), \ + 12) \ + X(a, \ + STATIC, \ + ONEOF, \ + MSG_W_CB, \ + (content, mf_ultralight_write_page_req, content.mf_ultralight_write_page_req), \ + 13) \ + X(a, \ + STATIC, \ + ONEOF, \ + MSG_W_CB, \ + (content, mf_ultralight_write_page_resp, content.mf_ultralight_write_page_resp), \ + 14) \ + X(a, \ + STATIC, \ + ONEOF, \ + MSG_W_CB, \ + (content, mf_ultralight_read_signature_req, content.mf_ultralight_read_signature_req), \ + 15) \ + X(a, \ + STATIC, \ + ONEOF, \ + MSG_W_CB, \ + (content, mf_ultralight_read_signature_resp, content.mf_ultralight_read_signature_resp), \ + 16) \ + X(a, \ + STATIC, \ + ONEOF, \ + MSG_W_CB, \ + (content, mf_ultralight_read_counter_req, content.mf_ultralight_read_counter_req), \ + 17) \ + X(a, \ + STATIC, \ + ONEOF, \ + MSG_W_CB, \ + (content, mf_ultralight_read_counter_resp, content.mf_ultralight_read_counter_resp), \ + 18) \ + X(a, \ + STATIC, \ + ONEOF, \ + MSG_W_CB, \ + (content, mf_ultralight_read_tearing_flag_req, content.mf_ultralight_read_tearing_flag_req), \ + 19) \ + X(a, \ + STATIC, \ + ONEOF, \ + MSG_W_CB, \ + (content, \ + mf_ultralight_read_tearing_flag_resp, \ + content.mf_ultralight_read_tearing_flag_resp), \ + 20) \ + X(a, \ + STATIC, \ + ONEOF, \ + MSG_W_CB, \ + (content, mf_ultralight_emulate_start_req, content.mf_ultralight_emulate_start_req), \ + 21) \ + X(a, \ + STATIC, \ + ONEOF, \ + MSG_W_CB, \ + (content, mf_ultralight_emulate_start_resp, content.mf_ultralight_emulate_start_resp), \ + 22) \ + X(a, \ + STATIC, \ + ONEOF, \ + MSG_W_CB, \ + (content, mf_ultralight_emulate_stop_req, content.mf_ultralight_emulate_stop_req), \ + 23) \ + X(a, \ + STATIC, \ + ONEOF, \ + MSG_W_CB, \ + (content, mf_ultralight_emulate_stop_resp, content.mf_ultralight_emulate_stop_resp), \ + 24) \ + X(a, STATIC, ONEOF, MSG_W_CB, (content, mf_classic_auth_req, content.mf_classic_auth_req), 25) \ + X(a, \ + STATIC, \ + ONEOF, \ + MSG_W_CB, \ + (content, mf_classic_auth_resp, content.mf_classic_auth_resp), \ + 26) \ + X(a, \ + STATIC, \ + ONEOF, \ + MSG_W_CB, \ + (content, mf_classic_read_block_req, content.mf_classic_read_block_req), \ + 27) \ + X(a, \ + STATIC, \ + ONEOF, \ + MSG_W_CB, \ + (content, mf_classic_read_block_resp, content.mf_classic_read_block_resp), \ + 28) #define Nfc_Main_CALLBACK NULL #define Nfc_Main_DEFAULT NULL #define Nfc_Main_content_empty_MSGTYPE Nfc_Empty @@ -158,19 +285,28 @@ X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_classic_read_block_resp,content.m #define Nfc_Main_content_mf_ultralight_read_page_req_MSGTYPE PB_MfUltralight_ReadPageRequest #define Nfc_Main_content_mf_ultralight_read_page_resp_MSGTYPE PB_MfUltralight_ReadPageResponse #define Nfc_Main_content_mf_ultralight_read_version_req_MSGTYPE PB_MfUltralight_ReadVersionRequest -#define Nfc_Main_content_mf_ultralight_read_version_resp_MSGTYPE PB_MfUltralight_ReadVersionResponse +#define Nfc_Main_content_mf_ultralight_read_version_resp_MSGTYPE \ + PB_MfUltralight_ReadVersionResponse #define Nfc_Main_content_mf_ultralight_write_page_req_MSGTYPE PB_MfUltralight_WritePageRequest #define Nfc_Main_content_mf_ultralight_write_page_resp_MSGTYPE PB_MfUltralight_WritePageResponse -#define Nfc_Main_content_mf_ultralight_read_signature_req_MSGTYPE PB_MfUltralight_ReadSignatureRequest -#define Nfc_Main_content_mf_ultralight_read_signature_resp_MSGTYPE PB_MfUltralight_ReadSignatureResponse +#define Nfc_Main_content_mf_ultralight_read_signature_req_MSGTYPE \ + PB_MfUltralight_ReadSignatureRequest +#define Nfc_Main_content_mf_ultralight_read_signature_resp_MSGTYPE \ + PB_MfUltralight_ReadSignatureResponse #define Nfc_Main_content_mf_ultralight_read_counter_req_MSGTYPE PB_MfUltralight_ReadCounterRequest -#define Nfc_Main_content_mf_ultralight_read_counter_resp_MSGTYPE PB_MfUltralight_ReadCounterResponse -#define Nfc_Main_content_mf_ultralight_read_tearing_flag_req_MSGTYPE PB_MfUltralight_ReadTearingFlagRequest -#define Nfc_Main_content_mf_ultralight_read_tearing_flag_resp_MSGTYPE PB_MfUltralight_ReadTearingFlagResponse -#define Nfc_Main_content_mf_ultralight_emulate_start_req_MSGTYPE PB_MfUltralight_EmulateStartRequest -#define Nfc_Main_content_mf_ultralight_emulate_start_resp_MSGTYPE PB_MfUltralight_EmulateStartResponse +#define Nfc_Main_content_mf_ultralight_read_counter_resp_MSGTYPE \ + PB_MfUltralight_ReadCounterResponse +#define Nfc_Main_content_mf_ultralight_read_tearing_flag_req_MSGTYPE \ + PB_MfUltralight_ReadTearingFlagRequest +#define Nfc_Main_content_mf_ultralight_read_tearing_flag_resp_MSGTYPE \ + PB_MfUltralight_ReadTearingFlagResponse +#define Nfc_Main_content_mf_ultralight_emulate_start_req_MSGTYPE \ + PB_MfUltralight_EmulateStartRequest +#define Nfc_Main_content_mf_ultralight_emulate_start_resp_MSGTYPE \ + PB_MfUltralight_EmulateStartResponse #define Nfc_Main_content_mf_ultralight_emulate_stop_req_MSGTYPE PB_MfUltralight_EmulateStopRequest -#define Nfc_Main_content_mf_ultralight_emulate_stop_resp_MSGTYPE PB_MfUltralight_EmulateStopResponse +#define Nfc_Main_content_mf_ultralight_emulate_stop_resp_MSGTYPE \ + PB_MfUltralight_EmulateStopResponse #define Nfc_Main_content_mf_classic_auth_req_MSGTYPE PB_MfClassic_AuthRequest #define Nfc_Main_content_mf_classic_auth_resp_MSGTYPE PB_MfClassic_AuthResponse #define Nfc_Main_content_mf_classic_read_block_req_MSGTYPE PB_MfClassic_ReadBlockRequest @@ -184,8 +320,8 @@ extern const pb_msgdesc_t Nfc_Main_msg; #define Nfc_Main_fields &Nfc_Main_msg /* Maximum encoded size of messages (where known) */ -#define Nfc_Empty_size 0 -#define Nfc_Main_size 2057 +#define Nfc_Empty_size 0 +#define Nfc_Main_size 2057 #ifdef __cplusplus } /* extern "C" */ diff --git a/applications/main/nfc_rpc/assets/compiled/mf_classic.pb.c b/applications/main/nfc_rpc/assets/compiled/mf_classic.pb.c index 114429ee891e..eb96ffe1657e 100644 --- a/applications/main/nfc_rpc/assets/compiled/mf_classic.pb.c +++ b/applications/main/nfc_rpc/assets/compiled/mf_classic.pb.c @@ -8,16 +8,8 @@ PB_BIND(PB_MfClassic_AuthRequest, PB_MfClassic_AuthRequest, AUTO) - PB_BIND(PB_MfClassic_AuthResponse, PB_MfClassic_AuthResponse, AUTO) - PB_BIND(PB_MfClassic_ReadBlockRequest, PB_MfClassic_ReadBlockRequest, AUTO) - PB_BIND(PB_MfClassic_ReadBlockResponse, PB_MfClassic_ReadBlockResponse, AUTO) - - - - - diff --git a/applications/main/nfc_rpc/assets/compiled/mf_classic.pb.h b/applications/main/nfc_rpc/assets/compiled/mf_classic.pb.h index 3d9c2d6da27b..dbc649cb0aa7 100644 --- a/applications/main/nfc_rpc/assets/compiled/mf_classic.pb.h +++ b/applications/main/nfc_rpc/assets/compiled/mf_classic.pb.h @@ -60,7 +60,6 @@ typedef struct _PB_MfClassic_ReadBlockResponse { PB_MfClassic_ReadBlockResponse_data_t data; } PB_MfClassic_ReadBlockResponse; - #ifdef __cplusplus extern "C" { #endif @@ -68,11 +67,11 @@ extern "C" { /* Helper constants for enums */ #define _PB_MfClassic_Error_MIN PB_MfClassic_Error_None #define _PB_MfClassic_Error_MAX PB_MfClassic_Error_Timeout -#define _PB_MfClassic_Error_ARRAYSIZE ((PB_MfClassic_Error)(PB_MfClassic_Error_Timeout+1)) +#define _PB_MfClassic_Error_ARRAYSIZE ((PB_MfClassic_Error)(PB_MfClassic_Error_Timeout + 1)) #define _PB_MfClassic_KeyType_MIN PB_MfClassic_KeyType_KeyTypeA #define _PB_MfClassic_KeyType_MAX PB_MfClassic_KeyType_KeyTypeB -#define _PB_MfClassic_KeyType_ARRAYSIZE ((PB_MfClassic_KeyType)(PB_MfClassic_KeyType_KeyTypeB+1)) +#define _PB_MfClassic_KeyType_ARRAYSIZE ((PB_MfClassic_KeyType)(PB_MfClassic_KeyType_KeyTypeB + 1)) #define PB_MfClassic_AuthRequest_key_type_ENUMTYPE PB_MfClassic_KeyType @@ -83,65 +82,98 @@ extern "C" { #define PB_MfClassic_ReadBlockResponse_error_ENUMTYPE PB_MfClassic_Error - /* Initializer values for message structs */ -#define PB_MfClassic_AuthRequest_init_default {0, {0, {0}}, _PB_MfClassic_KeyType_MIN} -#define PB_MfClassic_AuthResponse_init_default {_PB_MfClassic_Error_MIN, 0, {0, {0}}, _PB_MfClassic_KeyType_MIN, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}} -#define PB_MfClassic_ReadBlockRequest_init_default {0, {0, {0}}, _PB_MfClassic_KeyType_MIN} -#define PB_MfClassic_ReadBlockResponse_init_default {_PB_MfClassic_Error_MIN, {0, {0}}} -#define PB_MfClassic_AuthRequest_init_zero {0, {0, {0}}, _PB_MfClassic_KeyType_MIN} -#define PB_MfClassic_AuthResponse_init_zero {_PB_MfClassic_Error_MIN, 0, {0, {0}}, _PB_MfClassic_KeyType_MIN, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}} -#define PB_MfClassic_ReadBlockRequest_init_zero {0, {0, {0}}, _PB_MfClassic_KeyType_MIN} -#define PB_MfClassic_ReadBlockResponse_init_zero {_PB_MfClassic_Error_MIN, {0, {0}}} +#define PB_MfClassic_AuthRequest_init_default \ + { 0, {0, {0}}, _PB_MfClassic_KeyType_MIN } +#define PB_MfClassic_AuthResponse_init_default \ + { \ + _PB_MfClassic_Error_MIN, 0, {0, {0}}, _PB_MfClassic_KeyType_MIN, {0, {0}}, {0, {0}}, \ + {0, {0}}, { \ + 0, { \ + 0 \ + } \ + } \ + } +#define PB_MfClassic_ReadBlockRequest_init_default \ + { 0, {0, {0}}, _PB_MfClassic_KeyType_MIN } +#define PB_MfClassic_ReadBlockResponse_init_default \ + { \ + _PB_MfClassic_Error_MIN, { \ + 0, { \ + 0 \ + } \ + } \ + } +#define PB_MfClassic_AuthRequest_init_zero \ + { 0, {0, {0}}, _PB_MfClassic_KeyType_MIN } +#define PB_MfClassic_AuthResponse_init_zero \ + { \ + _PB_MfClassic_Error_MIN, 0, {0, {0}}, _PB_MfClassic_KeyType_MIN, {0, {0}}, {0, {0}}, \ + {0, {0}}, { \ + 0, { \ + 0 \ + } \ + } \ + } +#define PB_MfClassic_ReadBlockRequest_init_zero \ + { 0, {0, {0}}, _PB_MfClassic_KeyType_MIN } +#define PB_MfClassic_ReadBlockResponse_init_zero \ + { \ + _PB_MfClassic_Error_MIN, { \ + 0, { \ + 0 \ + } \ + } \ + } /* Field tags (for use in manual encoding/decoding) */ -#define PB_MfClassic_AuthRequest_block_tag 1 -#define PB_MfClassic_AuthRequest_key_tag 2 -#define PB_MfClassic_AuthRequest_key_type_tag 3 -#define PB_MfClassic_AuthResponse_error_tag 1 -#define PB_MfClassic_AuthResponse_block_tag 2 -#define PB_MfClassic_AuthResponse_key_tag 3 -#define PB_MfClassic_AuthResponse_key_type_tag 4 -#define PB_MfClassic_AuthResponse_nt_tag 5 -#define PB_MfClassic_AuthResponse_nr_tag 6 -#define PB_MfClassic_AuthResponse_ar_tag 7 -#define PB_MfClassic_AuthResponse_at_tag 8 -#define PB_MfClassic_ReadBlockRequest_block_tag 1 -#define PB_MfClassic_ReadBlockRequest_key_tag 2 +#define PB_MfClassic_AuthRequest_block_tag 1 +#define PB_MfClassic_AuthRequest_key_tag 2 +#define PB_MfClassic_AuthRequest_key_type_tag 3 +#define PB_MfClassic_AuthResponse_error_tag 1 +#define PB_MfClassic_AuthResponse_block_tag 2 +#define PB_MfClassic_AuthResponse_key_tag 3 +#define PB_MfClassic_AuthResponse_key_type_tag 4 +#define PB_MfClassic_AuthResponse_nt_tag 5 +#define PB_MfClassic_AuthResponse_nr_tag 6 +#define PB_MfClassic_AuthResponse_ar_tag 7 +#define PB_MfClassic_AuthResponse_at_tag 8 +#define PB_MfClassic_ReadBlockRequest_block_tag 1 +#define PB_MfClassic_ReadBlockRequest_key_tag 2 #define PB_MfClassic_ReadBlockRequest_key_type_tag 3 #define PB_MfClassic_ReadBlockResponse_error_tag 1 -#define PB_MfClassic_ReadBlockResponse_data_tag 2 +#define PB_MfClassic_ReadBlockResponse_data_tag 2 /* Struct field encoding specification for nanopb */ #define PB_MfClassic_AuthRequest_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UINT32, block, 1) \ -X(a, STATIC, SINGULAR, BYTES, key, 2) \ -X(a, STATIC, SINGULAR, UENUM, key_type, 3) + X(a, STATIC, SINGULAR, UINT32, block, 1) \ + X(a, STATIC, SINGULAR, BYTES, key, 2) \ + X(a, STATIC, SINGULAR, UENUM, key_type, 3) #define PB_MfClassic_AuthRequest_CALLBACK NULL #define PB_MfClassic_AuthRequest_DEFAULT NULL #define PB_MfClassic_AuthResponse_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UENUM, error, 1) \ -X(a, STATIC, SINGULAR, UINT32, block, 2) \ -X(a, STATIC, SINGULAR, BYTES, key, 3) \ -X(a, STATIC, SINGULAR, UENUM, key_type, 4) \ -X(a, STATIC, SINGULAR, BYTES, nt, 5) \ -X(a, STATIC, SINGULAR, BYTES, nr, 6) \ -X(a, STATIC, SINGULAR, BYTES, ar, 7) \ -X(a, STATIC, SINGULAR, BYTES, at, 8) + X(a, STATIC, SINGULAR, UENUM, error, 1) \ + X(a, STATIC, SINGULAR, UINT32, block, 2) \ + X(a, STATIC, SINGULAR, BYTES, key, 3) \ + X(a, STATIC, SINGULAR, UENUM, key_type, 4) \ + X(a, STATIC, SINGULAR, BYTES, nt, 5) \ + X(a, STATIC, SINGULAR, BYTES, nr, 6) \ + X(a, STATIC, SINGULAR, BYTES, ar, 7) \ + X(a, STATIC, SINGULAR, BYTES, at, 8) #define PB_MfClassic_AuthResponse_CALLBACK NULL #define PB_MfClassic_AuthResponse_DEFAULT NULL #define PB_MfClassic_ReadBlockRequest_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UINT32, block, 1) \ -X(a, STATIC, SINGULAR, BYTES, key, 2) \ -X(a, STATIC, SINGULAR, UENUM, key_type, 3) + X(a, STATIC, SINGULAR, UINT32, block, 1) \ + X(a, STATIC, SINGULAR, BYTES, key, 2) \ + X(a, STATIC, SINGULAR, UENUM, key_type, 3) #define PB_MfClassic_ReadBlockRequest_CALLBACK NULL #define PB_MfClassic_ReadBlockRequest_DEFAULT NULL #define PB_MfClassic_ReadBlockResponse_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UENUM, error, 1) \ -X(a, STATIC, SINGULAR, BYTES, data, 2) + X(a, STATIC, SINGULAR, UENUM, error, 1) \ + X(a, STATIC, SINGULAR, BYTES, data, 2) #define PB_MfClassic_ReadBlockResponse_CALLBACK NULL #define PB_MfClassic_ReadBlockResponse_DEFAULT NULL @@ -157,10 +189,10 @@ extern const pb_msgdesc_t PB_MfClassic_ReadBlockResponse_msg; #define PB_MfClassic_ReadBlockResponse_fields &PB_MfClassic_ReadBlockResponse_msg /* Maximum encoded size of messages (where known) */ -#define PB_MfClassic_AuthRequest_size 13 -#define PB_MfClassic_AuthResponse_size 39 -#define PB_MfClassic_ReadBlockRequest_size 13 -#define PB_MfClassic_ReadBlockResponse_size 20 +#define PB_MfClassic_AuthRequest_size 13 +#define PB_MfClassic_AuthResponse_size 39 +#define PB_MfClassic_ReadBlockRequest_size 13 +#define PB_MfClassic_ReadBlockResponse_size 20 #ifdef __cplusplus } /* extern "C" */ diff --git a/applications/main/nfc_rpc/assets/compiled/mf_ultralight.pb.c b/applications/main/nfc_rpc/assets/compiled/mf_ultralight.pb.c index a16a9020aaf3..d509af5ac47e 100644 --- a/applications/main/nfc_rpc/assets/compiled/mf_ultralight.pb.c +++ b/applications/main/nfc_rpc/assets/compiled/mf_ultralight.pb.c @@ -8,51 +8,32 @@ PB_BIND(PB_MfUltralight_ReadPageRequest, PB_MfUltralight_ReadPageRequest, AUTO) - PB_BIND(PB_MfUltralight_ReadPageResponse, PB_MfUltralight_ReadPageResponse, AUTO) - PB_BIND(PB_MfUltralight_ReadVersionRequest, PB_MfUltralight_ReadVersionRequest, AUTO) - PB_BIND(PB_MfUltralight_ReadVersionResponse, PB_MfUltralight_ReadVersionResponse, AUTO) - PB_BIND(PB_MfUltralight_WritePageRequest, PB_MfUltralight_WritePageRequest, AUTO) - PB_BIND(PB_MfUltralight_WritePageResponse, PB_MfUltralight_WritePageResponse, AUTO) - PB_BIND(PB_MfUltralight_ReadSignatureRequest, PB_MfUltralight_ReadSignatureRequest, AUTO) - PB_BIND(PB_MfUltralight_ReadSignatureResponse, PB_MfUltralight_ReadSignatureResponse, AUTO) - PB_BIND(PB_MfUltralight_ReadCounterRequest, PB_MfUltralight_ReadCounterRequest, AUTO) - PB_BIND(PB_MfUltralight_ReadCounterResponse, PB_MfUltralight_ReadCounterResponse, AUTO) - PB_BIND(PB_MfUltralight_ReadTearingFlagRequest, PB_MfUltralight_ReadTearingFlagRequest, AUTO) - PB_BIND(PB_MfUltralight_ReadTearingFlagResponse, PB_MfUltralight_ReadTearingFlagResponse, AUTO) - PB_BIND(PB_MfUltralight_EmulateStartRequest, PB_MfUltralight_EmulateStartRequest, 2) - PB_BIND(PB_MfUltralight_EmulateStartResponse, PB_MfUltralight_EmulateStartResponse, AUTO) - PB_BIND(PB_MfUltralight_EmulateStopRequest, PB_MfUltralight_EmulateStopRequest, AUTO) - PB_BIND(PB_MfUltralight_EmulateStopResponse, PB_MfUltralight_EmulateStopResponse, AUTO) - - - - diff --git a/applications/main/nfc_rpc/assets/compiled/mf_ultralight.pb.h b/applications/main/nfc_rpc/assets/compiled/mf_ultralight.pb.h index 087ff3819553..0754b98a5aa9 100644 --- a/applications/main/nfc_rpc/assets/compiled/mf_ultralight.pb.h +++ b/applications/main/nfc_rpc/assets/compiled/mf_ultralight.pb.h @@ -106,7 +106,6 @@ typedef struct _PB_MfUltralight_EmulateStopResponse { PB_MfUltralight_Error error; } PB_MfUltralight_EmulateStopResponse; - #ifdef __cplusplus extern "C" { #endif @@ -114,66 +113,162 @@ extern "C" { /* Helper constants for enums */ #define _PB_MfUltralight_Error_MIN PB_MfUltralight_Error_None #define _PB_MfUltralight_Error_MAX PB_MfUltralight_Error_Timeout -#define _PB_MfUltralight_Error_ARRAYSIZE ((PB_MfUltralight_Error)(PB_MfUltralight_Error_Timeout+1)) - +#define _PB_MfUltralight_Error_ARRAYSIZE \ + ((PB_MfUltralight_Error)(PB_MfUltralight_Error_Timeout + 1)) #define PB_MfUltralight_ReadPageResponse_error_ENUMTYPE PB_MfUltralight_Error - #define PB_MfUltralight_ReadVersionResponse_error_ENUMTYPE PB_MfUltralight_Error - #define PB_MfUltralight_WritePageResponse_error_ENUMTYPE PB_MfUltralight_Error - #define PB_MfUltralight_ReadSignatureResponse_error_ENUMTYPE PB_MfUltralight_Error - #define PB_MfUltralight_ReadCounterResponse_error_ENUMTYPE PB_MfUltralight_Error - #define PB_MfUltralight_ReadTearingFlagResponse_error_ENUMTYPE PB_MfUltralight_Error - #define PB_MfUltralight_EmulateStartResponse_error_ENUMTYPE PB_MfUltralight_Error - #define PB_MfUltralight_EmulateStopResponse_error_ENUMTYPE PB_MfUltralight_Error - /* Initializer values for message structs */ -#define PB_MfUltralight_ReadPageRequest_init_default {0} -#define PB_MfUltralight_ReadPageResponse_init_default {_PB_MfUltralight_Error_MIN, 0, {0, {0}}} -#define PB_MfUltralight_ReadVersionRequest_init_default {0} -#define PB_MfUltralight_ReadVersionResponse_init_default {_PB_MfUltralight_Error_MIN, 0, 0, 0, 0, 0, 0, 0, 0} -#define PB_MfUltralight_WritePageRequest_init_default {0, {0, {0}}} -#define PB_MfUltralight_WritePageResponse_init_default {_PB_MfUltralight_Error_MIN, 0} -#define PB_MfUltralight_ReadSignatureRequest_init_default {0} -#define PB_MfUltralight_ReadSignatureResponse_init_default {_PB_MfUltralight_Error_MIN, {0, {0}}} -#define PB_MfUltralight_ReadCounterRequest_init_default {0} -#define PB_MfUltralight_ReadCounterResponse_init_default {_PB_MfUltralight_Error_MIN, 0, {0, {0}}} -#define PB_MfUltralight_ReadTearingFlagRequest_init_default {0} -#define PB_MfUltralight_ReadTearingFlagResponse_init_default {_PB_MfUltralight_Error_MIN, 0, {0, {0}}} -#define PB_MfUltralight_EmulateStartRequest_init_default {{0, {0}}} -#define PB_MfUltralight_EmulateStartResponse_init_default {_PB_MfUltralight_Error_MIN} -#define PB_MfUltralight_EmulateStopRequest_init_default {0} -#define PB_MfUltralight_EmulateStopResponse_init_default {_PB_MfUltralight_Error_MIN} -#define PB_MfUltralight_ReadPageRequest_init_zero {0} -#define PB_MfUltralight_ReadPageResponse_init_zero {_PB_MfUltralight_Error_MIN, 0, {0, {0}}} -#define PB_MfUltralight_ReadVersionRequest_init_zero {0} -#define PB_MfUltralight_ReadVersionResponse_init_zero {_PB_MfUltralight_Error_MIN, 0, 0, 0, 0, 0, 0, 0, 0} -#define PB_MfUltralight_WritePageRequest_init_zero {0, {0, {0}}} -#define PB_MfUltralight_WritePageResponse_init_zero {_PB_MfUltralight_Error_MIN, 0} -#define PB_MfUltralight_ReadSignatureRequest_init_zero {0} -#define PB_MfUltralight_ReadSignatureResponse_init_zero {_PB_MfUltralight_Error_MIN, {0, {0}}} -#define PB_MfUltralight_ReadCounterRequest_init_zero {0} -#define PB_MfUltralight_ReadCounterResponse_init_zero {_PB_MfUltralight_Error_MIN, 0, {0, {0}}} -#define PB_MfUltralight_ReadTearingFlagRequest_init_zero {0} -#define PB_MfUltralight_ReadTearingFlagResponse_init_zero {_PB_MfUltralight_Error_MIN, 0, {0, {0}}} -#define PB_MfUltralight_EmulateStartRequest_init_zero {{0, {0}}} -#define PB_MfUltralight_EmulateStartResponse_init_zero {_PB_MfUltralight_Error_MIN} -#define PB_MfUltralight_EmulateStopRequest_init_zero {0} -#define PB_MfUltralight_EmulateStopResponse_init_zero {_PB_MfUltralight_Error_MIN} +#define PB_MfUltralight_ReadPageRequest_init_default \ + { 0 } +#define PB_MfUltralight_ReadPageResponse_init_default \ + { \ + _PB_MfUltralight_Error_MIN, 0, { \ + 0, { \ + 0 \ + } \ + } \ + } +#define PB_MfUltralight_ReadVersionRequest_init_default \ + { 0 } +#define PB_MfUltralight_ReadVersionResponse_init_default \ + { _PB_MfUltralight_Error_MIN, 0, 0, 0, 0, 0, 0, 0, 0 } +#define PB_MfUltralight_WritePageRequest_init_default \ + { \ + 0, { \ + 0, { \ + 0 \ + } \ + } \ + } +#define PB_MfUltralight_WritePageResponse_init_default \ + { _PB_MfUltralight_Error_MIN, 0 } +#define PB_MfUltralight_ReadSignatureRequest_init_default \ + { 0 } +#define PB_MfUltralight_ReadSignatureResponse_init_default \ + { \ + _PB_MfUltralight_Error_MIN, { \ + 0, { \ + 0 \ + } \ + } \ + } +#define PB_MfUltralight_ReadCounterRequest_init_default \ + { 0 } +#define PB_MfUltralight_ReadCounterResponse_init_default \ + { \ + _PB_MfUltralight_Error_MIN, 0, { \ + 0, { \ + 0 \ + } \ + } \ + } +#define PB_MfUltralight_ReadTearingFlagRequest_init_default \ + { 0 } +#define PB_MfUltralight_ReadTearingFlagResponse_init_default \ + { \ + _PB_MfUltralight_Error_MIN, 0, { \ + 0, { \ + 0 \ + } \ + } \ + } +#define PB_MfUltralight_EmulateStartRequest_init_default \ + { \ + { \ + 0, { \ + 0 \ + } \ + } \ + } +#define PB_MfUltralight_EmulateStartResponse_init_default \ + { _PB_MfUltralight_Error_MIN } +#define PB_MfUltralight_EmulateStopRequest_init_default \ + { 0 } +#define PB_MfUltralight_EmulateStopResponse_init_default \ + { _PB_MfUltralight_Error_MIN } +#define PB_MfUltralight_ReadPageRequest_init_zero \ + { 0 } +#define PB_MfUltralight_ReadPageResponse_init_zero \ + { \ + _PB_MfUltralight_Error_MIN, 0, { \ + 0, { \ + 0 \ + } \ + } \ + } +#define PB_MfUltralight_ReadVersionRequest_init_zero \ + { 0 } +#define PB_MfUltralight_ReadVersionResponse_init_zero \ + { _PB_MfUltralight_Error_MIN, 0, 0, 0, 0, 0, 0, 0, 0 } +#define PB_MfUltralight_WritePageRequest_init_zero \ + { \ + 0, { \ + 0, { \ + 0 \ + } \ + } \ + } +#define PB_MfUltralight_WritePageResponse_init_zero \ + { _PB_MfUltralight_Error_MIN, 0 } +#define PB_MfUltralight_ReadSignatureRequest_init_zero \ + { 0 } +#define PB_MfUltralight_ReadSignatureResponse_init_zero \ + { \ + _PB_MfUltralight_Error_MIN, { \ + 0, { \ + 0 \ + } \ + } \ + } +#define PB_MfUltralight_ReadCounterRequest_init_zero \ + { 0 } +#define PB_MfUltralight_ReadCounterResponse_init_zero \ + { \ + _PB_MfUltralight_Error_MIN, 0, { \ + 0, { \ + 0 \ + } \ + } \ + } +#define PB_MfUltralight_ReadTearingFlagRequest_init_zero \ + { 0 } +#define PB_MfUltralight_ReadTearingFlagResponse_init_zero \ + { \ + _PB_MfUltralight_Error_MIN, 0, { \ + 0, { \ + 0 \ + } \ + } \ + } +#define PB_MfUltralight_EmulateStartRequest_init_zero \ + { \ + { \ + 0, { \ + 0 \ + } \ + } \ + } +#define PB_MfUltralight_EmulateStartResponse_init_zero \ + { _PB_MfUltralight_Error_MIN } +#define PB_MfUltralight_EmulateStopRequest_init_zero \ + { 0 } +#define PB_MfUltralight_EmulateStopResponse_init_zero \ + { _PB_MfUltralight_Error_MIN } /* Field tags (for use in manual encoding/decoding) */ #define PB_MfUltralight_ReadPageRequest_page_tag 1 @@ -208,100 +303,97 @@ extern "C" { #define PB_MfUltralight_EmulateStopResponse_error_tag 1 /* Struct field encoding specification for nanopb */ -#define PB_MfUltralight_ReadPageRequest_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UINT32, page, 1) +#define PB_MfUltralight_ReadPageRequest_FIELDLIST(X, a) X(a, STATIC, SINGULAR, UINT32, page, 1) #define PB_MfUltralight_ReadPageRequest_CALLBACK NULL #define PB_MfUltralight_ReadPageRequest_DEFAULT NULL #define PB_MfUltralight_ReadPageResponse_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UENUM, error, 1) \ -X(a, STATIC, SINGULAR, UINT32, page, 2) \ -X(a, STATIC, SINGULAR, BYTES, data, 3) + X(a, STATIC, SINGULAR, UENUM, error, 1) \ + X(a, STATIC, SINGULAR, UINT32, page, 2) \ + X(a, STATIC, SINGULAR, BYTES, data, 3) #define PB_MfUltralight_ReadPageResponse_CALLBACK NULL #define PB_MfUltralight_ReadPageResponse_DEFAULT NULL -#define PB_MfUltralight_ReadVersionRequest_FIELDLIST(X, a) \ +#define PB_MfUltralight_ReadVersionRequest_FIELDLIST(X, a) #define PB_MfUltralight_ReadVersionRequest_CALLBACK NULL #define PB_MfUltralight_ReadVersionRequest_DEFAULT NULL #define PB_MfUltralight_ReadVersionResponse_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UENUM, error, 1) \ -X(a, STATIC, SINGULAR, UINT32, header, 2) \ -X(a, STATIC, SINGULAR, UINT32, vendor_id, 3) \ -X(a, STATIC, SINGULAR, UINT32, prod_type, 4) \ -X(a, STATIC, SINGULAR, UINT32, prod_subtype, 5) \ -X(a, STATIC, SINGULAR, UINT32, prod_ver_major, 6) \ -X(a, STATIC, SINGULAR, UINT32, prod_ver_minor, 7) \ -X(a, STATIC, SINGULAR, UINT32, storage_size, 8) \ -X(a, STATIC, SINGULAR, UINT32, protocol_type, 9) + X(a, STATIC, SINGULAR, UENUM, error, 1) \ + X(a, STATIC, SINGULAR, UINT32, header, 2) \ + X(a, STATIC, SINGULAR, UINT32, vendor_id, 3) \ + X(a, STATIC, SINGULAR, UINT32, prod_type, 4) \ + X(a, STATIC, SINGULAR, UINT32, prod_subtype, 5) \ + X(a, STATIC, SINGULAR, UINT32, prod_ver_major, 6) \ + X(a, STATIC, SINGULAR, UINT32, prod_ver_minor, 7) \ + X(a, STATIC, SINGULAR, UINT32, storage_size, 8) \ + X(a, STATIC, SINGULAR, UINT32, protocol_type, 9) #define PB_MfUltralight_ReadVersionResponse_CALLBACK NULL #define PB_MfUltralight_ReadVersionResponse_DEFAULT NULL #define PB_MfUltralight_WritePageRequest_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UINT32, page, 1) \ -X(a, STATIC, SINGULAR, BYTES, data, 2) + X(a, STATIC, SINGULAR, UINT32, page, 1) \ + X(a, STATIC, SINGULAR, BYTES, data, 2) #define PB_MfUltralight_WritePageRequest_CALLBACK NULL #define PB_MfUltralight_WritePageRequest_DEFAULT NULL #define PB_MfUltralight_WritePageResponse_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UENUM, error, 1) \ -X(a, STATIC, SINGULAR, BOOL, result, 2) + X(a, STATIC, SINGULAR, UENUM, error, 1) \ + X(a, STATIC, SINGULAR, BOOL, result, 2) #define PB_MfUltralight_WritePageResponse_CALLBACK NULL #define PB_MfUltralight_WritePageResponse_DEFAULT NULL -#define PB_MfUltralight_ReadSignatureRequest_FIELDLIST(X, a) \ +#define PB_MfUltralight_ReadSignatureRequest_FIELDLIST(X, a) #define PB_MfUltralight_ReadSignatureRequest_CALLBACK NULL #define PB_MfUltralight_ReadSignatureRequest_DEFAULT NULL #define PB_MfUltralight_ReadSignatureResponse_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UENUM, error, 1) \ -X(a, STATIC, SINGULAR, BYTES, data, 2) + X(a, STATIC, SINGULAR, UENUM, error, 1) \ + X(a, STATIC, SINGULAR, BYTES, data, 2) #define PB_MfUltralight_ReadSignatureResponse_CALLBACK NULL #define PB_MfUltralight_ReadSignatureResponse_DEFAULT NULL #define PB_MfUltralight_ReadCounterRequest_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UINT32, counter_num, 1) + X(a, STATIC, SINGULAR, UINT32, counter_num, 1) #define PB_MfUltralight_ReadCounterRequest_CALLBACK NULL #define PB_MfUltralight_ReadCounterRequest_DEFAULT NULL #define PB_MfUltralight_ReadCounterResponse_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UENUM, error, 1) \ -X(a, STATIC, SINGULAR, UINT32, counter_num, 2) \ -X(a, STATIC, SINGULAR, BYTES, data, 3) + X(a, STATIC, SINGULAR, UENUM, error, 1) \ + X(a, STATIC, SINGULAR, UINT32, counter_num, 2) \ + X(a, STATIC, SINGULAR, BYTES, data, 3) #define PB_MfUltralight_ReadCounterResponse_CALLBACK NULL #define PB_MfUltralight_ReadCounterResponse_DEFAULT NULL #define PB_MfUltralight_ReadTearingFlagRequest_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UINT32, flag_num, 1) + X(a, STATIC, SINGULAR, UINT32, flag_num, 1) #define PB_MfUltralight_ReadTearingFlagRequest_CALLBACK NULL #define PB_MfUltralight_ReadTearingFlagRequest_DEFAULT NULL #define PB_MfUltralight_ReadTearingFlagResponse_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UENUM, error, 1) \ -X(a, STATIC, SINGULAR, UINT32, flag_num, 2) \ -X(a, STATIC, SINGULAR, BYTES, data, 3) + X(a, STATIC, SINGULAR, UENUM, error, 1) \ + X(a, STATIC, SINGULAR, UINT32, flag_num, 2) \ + X(a, STATIC, SINGULAR, BYTES, data, 3) #define PB_MfUltralight_ReadTearingFlagResponse_CALLBACK NULL #define PB_MfUltralight_ReadTearingFlagResponse_DEFAULT NULL -#define PB_MfUltralight_EmulateStartRequest_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, BYTES, data, 1) +#define PB_MfUltralight_EmulateStartRequest_FIELDLIST(X, a) X(a, STATIC, SINGULAR, BYTES, data, 1) #define PB_MfUltralight_EmulateStartRequest_CALLBACK NULL #define PB_MfUltralight_EmulateStartRequest_DEFAULT NULL #define PB_MfUltralight_EmulateStartResponse_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UENUM, error, 1) + X(a, STATIC, SINGULAR, UENUM, error, 1) #define PB_MfUltralight_EmulateStartResponse_CALLBACK NULL #define PB_MfUltralight_EmulateStartResponse_DEFAULT NULL -#define PB_MfUltralight_EmulateStopRequest_FIELDLIST(X, a) \ +#define PB_MfUltralight_EmulateStopRequest_FIELDLIST(X, a) #define PB_MfUltralight_EmulateStopRequest_CALLBACK NULL #define PB_MfUltralight_EmulateStopRequest_DEFAULT NULL -#define PB_MfUltralight_EmulateStopResponse_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UENUM, error, 1) +#define PB_MfUltralight_EmulateStopResponse_FIELDLIST(X, a) X(a, STATIC, SINGULAR, UENUM, error, 1) #define PB_MfUltralight_EmulateStopResponse_CALLBACK NULL #define PB_MfUltralight_EmulateStopResponse_DEFAULT NULL @@ -343,20 +435,20 @@ extern const pb_msgdesc_t PB_MfUltralight_EmulateStopResponse_msg; /* Maximum encoded size of messages (where known) */ #define PB_MfUltralight_EmulateStartRequest_size 2051 #define PB_MfUltralight_EmulateStartResponse_size 2 -#define PB_MfUltralight_EmulateStopRequest_size 0 +#define PB_MfUltralight_EmulateStopRequest_size 0 #define PB_MfUltralight_EmulateStopResponse_size 2 -#define PB_MfUltralight_ReadCounterRequest_size 6 +#define PB_MfUltralight_ReadCounterRequest_size 6 #define PB_MfUltralight_ReadCounterResponse_size 13 -#define PB_MfUltralight_ReadPageRequest_size 4 -#define PB_MfUltralight_ReadPageResponse_size 12 +#define PB_MfUltralight_ReadPageRequest_size 4 +#define PB_MfUltralight_ReadPageResponse_size 12 #define PB_MfUltralight_ReadSignatureRequest_size 0 #define PB_MfUltralight_ReadSignatureResponse_size 36 #define PB_MfUltralight_ReadTearingFlagRequest_size 6 #define PB_MfUltralight_ReadTearingFlagResponse_size 11 -#define PB_MfUltralight_ReadVersionRequest_size 0 +#define PB_MfUltralight_ReadVersionRequest_size 0 #define PB_MfUltralight_ReadVersionResponse_size 50 -#define PB_MfUltralight_WritePageRequest_size 10 -#define PB_MfUltralight_WritePageResponse_size 4 +#define PB_MfUltralight_WritePageRequest_size 10 +#define PB_MfUltralight_WritePageResponse_size 4 #ifdef __cplusplus } /* extern "C" */ diff --git a/applications/main/nfc_rpc/assets/compiled/nfca.pb.c b/applications/main/nfc_rpc/assets/compiled/nfca.pb.c index 44e2f02579da..e7b784a5c25a 100644 --- a/applications/main/nfc_rpc/assets/compiled/nfca.pb.c +++ b/applications/main/nfc_rpc/assets/compiled/nfca.pb.c @@ -8,21 +8,12 @@ PB_BIND(PB_Nfca_ReadRequest, PB_Nfca_ReadRequest, AUTO) - PB_BIND(PB_Nfca_ReadResponse, PB_Nfca_ReadResponse, AUTO) - PB_BIND(PB_Nfca_EmulateStartRequest, PB_Nfca_EmulateStartRequest, AUTO) - PB_BIND(PB_Nfca_EmulateStartResponse, PB_Nfca_EmulateStartResponse, AUTO) - PB_BIND(PB_Nfca_EmulateStopRequest, PB_Nfca_EmulateStopRequest, AUTO) - PB_BIND(PB_Nfca_EmulateStopResponse, PB_Nfca_EmulateStopResponse, AUTO) - - - - diff --git a/applications/main/nfc_rpc/assets/compiled/nfca.pb.h b/applications/main/nfc_rpc/assets/compiled/nfca.pb.h index df751cbd0c92..349dab811cbe 100644 --- a/applications/main/nfc_rpc/assets/compiled/nfca.pb.h +++ b/applications/main/nfc_rpc/assets/compiled/nfca.pb.h @@ -59,7 +59,6 @@ typedef struct _PB_Nfca_EmulateStopResponse { PB_Nfca_Error error; } PB_Nfca_EmulateStopResponse; - #ifdef __cplusplus extern "C" { #endif @@ -67,80 +66,110 @@ extern "C" { /* Helper constants for enums */ #define _PB_Nfca_Error_MIN PB_Nfca_Error_None #define _PB_Nfca_Error_MAX PB_Nfca_Error_Timeout -#define _PB_Nfca_Error_ARRAYSIZE ((PB_Nfca_Error)(PB_Nfca_Error_Timeout+1)) - +#define _PB_Nfca_Error_ARRAYSIZE ((PB_Nfca_Error)(PB_Nfca_Error_Timeout + 1)) #define PB_Nfca_ReadResponse_error_ENUMTYPE PB_Nfca_Error - #define PB_Nfca_EmulateStartResponse_error_ENUMTYPE PB_Nfca_Error - #define PB_Nfca_EmulateStopResponse_error_ENUMTYPE PB_Nfca_Error - /* Initializer values for message structs */ -#define PB_Nfca_ReadRequest_init_default {0} -#define PB_Nfca_ReadResponse_init_default {_PB_Nfca_Error_MIN, 0, {0, {0}}, {0, {0}}, {0, {0}}} -#define PB_Nfca_EmulateStartRequest_init_default {0, {0, {0}}, {0, {0}}, {0, {0}}} -#define PB_Nfca_EmulateStartResponse_init_default {_PB_Nfca_Error_MIN} -#define PB_Nfca_EmulateStopRequest_init_default {0} -#define PB_Nfca_EmulateStopResponse_init_default {_PB_Nfca_Error_MIN} -#define PB_Nfca_ReadRequest_init_zero {0} -#define PB_Nfca_ReadResponse_init_zero {_PB_Nfca_Error_MIN, 0, {0, {0}}, {0, {0}}, {0, {0}}} -#define PB_Nfca_EmulateStartRequest_init_zero {0, {0, {0}}, {0, {0}}, {0, {0}}} -#define PB_Nfca_EmulateStartResponse_init_zero {_PB_Nfca_Error_MIN} -#define PB_Nfca_EmulateStopRequest_init_zero {0} -#define PB_Nfca_EmulateStopResponse_init_zero {_PB_Nfca_Error_MIN} +#define PB_Nfca_ReadRequest_init_default \ + { 0 } +#define PB_Nfca_ReadResponse_init_default \ + { \ + _PB_Nfca_Error_MIN, 0, {0, {0}}, {0, {0}}, { \ + 0, { \ + 0 \ + } \ + } \ + } +#define PB_Nfca_EmulateStartRequest_init_default \ + { \ + 0, {0, {0}}, {0, {0}}, { \ + 0, { \ + 0 \ + } \ + } \ + } +#define PB_Nfca_EmulateStartResponse_init_default \ + { _PB_Nfca_Error_MIN } +#define PB_Nfca_EmulateStopRequest_init_default \ + { 0 } +#define PB_Nfca_EmulateStopResponse_init_default \ + { _PB_Nfca_Error_MIN } +#define PB_Nfca_ReadRequest_init_zero \ + { 0 } +#define PB_Nfca_ReadResponse_init_zero \ + { \ + _PB_Nfca_Error_MIN, 0, {0, {0}}, {0, {0}}, { \ + 0, { \ + 0 \ + } \ + } \ + } +#define PB_Nfca_EmulateStartRequest_init_zero \ + { \ + 0, {0, {0}}, {0, {0}}, { \ + 0, { \ + 0 \ + } \ + } \ + } +#define PB_Nfca_EmulateStartResponse_init_zero \ + { _PB_Nfca_Error_MIN } +#define PB_Nfca_EmulateStopRequest_init_zero \ + { 0 } +#define PB_Nfca_EmulateStopResponse_init_zero \ + { _PB_Nfca_Error_MIN } /* Field tags (for use in manual encoding/decoding) */ -#define PB_Nfca_ReadResponse_error_tag 1 -#define PB_Nfca_ReadResponse_uid_len_tag 2 -#define PB_Nfca_ReadResponse_uid_tag 3 -#define PB_Nfca_ReadResponse_sak_tag 4 -#define PB_Nfca_ReadResponse_atqa_tag 5 -#define PB_Nfca_EmulateStartRequest_uid_len_tag 1 -#define PB_Nfca_EmulateStartRequest_uid_tag 2 -#define PB_Nfca_EmulateStartRequest_sak_tag 3 -#define PB_Nfca_EmulateStartRequest_atqa_tag 4 -#define PB_Nfca_EmulateStartResponse_error_tag 1 -#define PB_Nfca_EmulateStopResponse_error_tag 1 +#define PB_Nfca_ReadResponse_error_tag 1 +#define PB_Nfca_ReadResponse_uid_len_tag 2 +#define PB_Nfca_ReadResponse_uid_tag 3 +#define PB_Nfca_ReadResponse_sak_tag 4 +#define PB_Nfca_ReadResponse_atqa_tag 5 +#define PB_Nfca_EmulateStartRequest_uid_len_tag 1 +#define PB_Nfca_EmulateStartRequest_uid_tag 2 +#define PB_Nfca_EmulateStartRequest_sak_tag 3 +#define PB_Nfca_EmulateStartRequest_atqa_tag 4 +#define PB_Nfca_EmulateStartResponse_error_tag 1 +#define PB_Nfca_EmulateStopResponse_error_tag 1 /* Struct field encoding specification for nanopb */ -#define PB_Nfca_ReadRequest_FIELDLIST(X, a) \ +#define PB_Nfca_ReadRequest_FIELDLIST(X, a) #define PB_Nfca_ReadRequest_CALLBACK NULL #define PB_Nfca_ReadRequest_DEFAULT NULL -#define PB_Nfca_ReadResponse_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UENUM, error, 1) \ -X(a, STATIC, SINGULAR, UINT32, uid_len, 2) \ -X(a, STATIC, SINGULAR, BYTES, uid, 3) \ -X(a, STATIC, SINGULAR, BYTES, sak, 4) \ -X(a, STATIC, SINGULAR, BYTES, atqa, 5) +#define PB_Nfca_ReadResponse_FIELDLIST(X, a) \ + X(a, STATIC, SINGULAR, UENUM, error, 1) \ + X(a, STATIC, SINGULAR, UINT32, uid_len, 2) \ + X(a, STATIC, SINGULAR, BYTES, uid, 3) \ + X(a, STATIC, SINGULAR, BYTES, sak, 4) \ + X(a, STATIC, SINGULAR, BYTES, atqa, 5) #define PB_Nfca_ReadResponse_CALLBACK NULL #define PB_Nfca_ReadResponse_DEFAULT NULL #define PB_Nfca_EmulateStartRequest_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UINT32, uid_len, 1) \ -X(a, STATIC, SINGULAR, BYTES, uid, 2) \ -X(a, STATIC, SINGULAR, BYTES, sak, 3) \ -X(a, STATIC, SINGULAR, BYTES, atqa, 4) + X(a, STATIC, SINGULAR, UINT32, uid_len, 1) \ + X(a, STATIC, SINGULAR, BYTES, uid, 2) \ + X(a, STATIC, SINGULAR, BYTES, sak, 3) \ + X(a, STATIC, SINGULAR, BYTES, atqa, 4) #define PB_Nfca_EmulateStartRequest_CALLBACK NULL #define PB_Nfca_EmulateStartRequest_DEFAULT NULL -#define PB_Nfca_EmulateStartResponse_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UENUM, error, 1) +#define PB_Nfca_EmulateStartResponse_FIELDLIST(X, a) X(a, STATIC, SINGULAR, UENUM, error, 1) #define PB_Nfca_EmulateStartResponse_CALLBACK NULL #define PB_Nfca_EmulateStartResponse_DEFAULT NULL -#define PB_Nfca_EmulateStopRequest_FIELDLIST(X, a) \ +#define PB_Nfca_EmulateStopRequest_FIELDLIST(X, a) #define PB_Nfca_EmulateStopRequest_CALLBACK NULL #define PB_Nfca_EmulateStopRequest_DEFAULT NULL -#define PB_Nfca_EmulateStopResponse_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UENUM, error, 1) +#define PB_Nfca_EmulateStopResponse_FIELDLIST(X, a) X(a, STATIC, SINGULAR, UENUM, error, 1) #define PB_Nfca_EmulateStopResponse_CALLBACK NULL #define PB_Nfca_EmulateStopResponse_DEFAULT NULL @@ -160,12 +189,12 @@ extern const pb_msgdesc_t PB_Nfca_EmulateStopResponse_msg; #define PB_Nfca_EmulateStopResponse_fields &PB_Nfca_EmulateStopResponse_msg /* Maximum encoded size of messages (where known) */ -#define PB_Nfca_EmulateStartRequest_size 25 -#define PB_Nfca_EmulateStartResponse_size 2 -#define PB_Nfca_EmulateStopRequest_size 0 -#define PB_Nfca_EmulateStopResponse_size 2 -#define PB_Nfca_ReadRequest_size 0 -#define PB_Nfca_ReadResponse_size 27 +#define PB_Nfca_EmulateStartRequest_size 25 +#define PB_Nfca_EmulateStartResponse_size 2 +#define PB_Nfca_EmulateStopRequest_size 0 +#define PB_Nfca_EmulateStopResponse_size 2 +#define PB_Nfca_ReadRequest_size 0 +#define PB_Nfca_ReadResponse_size 27 #ifdef __cplusplus } /* extern "C" */ diff --git a/applications/main/nfc_rpc/nfc_rpc.c b/applications/main/nfc_rpc/nfc_rpc.c index 1e526b4b57b6..0c455aaf1266 100644 --- a/applications/main/nfc_rpc/nfc_rpc.c +++ b/applications/main/nfc_rpc/nfc_rpc.c @@ -14,8 +14,7 @@ static const NfcRpcCallbacks nfc_rpc_callbacks[] = { { .alloc = nfc_rpc_mf_classic_alloc, .free = NULL, - } -}; + }}; uint32_t nfc_rpc_exit_callback(void* context) { UNUSED(context); diff --git a/lib/nfc/nfc_device.c b/lib/nfc/nfc_device.c index c94e48c9eb3c..917f37861c0d 100644 --- a/lib/nfc/nfc_device.c +++ b/lib/nfc/nfc_device.c @@ -696,7 +696,8 @@ static void nfc_device_write_mifare_classic_block( bool is_sec_trailer = mifare_classic_is_sector_trailer(block_num); if(is_sec_trailer) { uint8_t sector_num = mifare_classic_get_sector_by_block(block_num); - MfClassicSectorTrailer* sec_tr = mifare_classic_get_sector_trailer_by_sector(data, sector_num); + MfClassicSectorTrailer* sec_tr = + mifare_classic_get_sector_trailer_by_sector(data, sector_num); // Write key A for(size_t i = 0; i < sizeof(sec_tr->key_a); i++) { if(mifare_classic_is_key_found(data, sector_num, MfClassicKeyA)) { diff --git a/lib/nfc/parsers/plantain_4k_parser.c b/lib/nfc/parsers/plantain_4k_parser.c index a4320471c90b..4063a7a868db 100644 --- a/lib/nfc/parsers/plantain_4k_parser.c +++ b/lib/nfc/parsers/plantain_4k_parser.c @@ -71,7 +71,8 @@ bool plantain_4k_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx MfClassicReader reader = {}; FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; - reader.type = mifare_classic_get_classic_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak); + reader.type = + mifare_classic_get_classic_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak); for(size_t i = 0; i < COUNT_OF(plantain_keys_4k); i++) { mifare_classic_reader_add_sector( &reader, @@ -81,7 +82,8 @@ bool plantain_4k_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx FURI_LOG_T("plant4k", "Added sector %d", plantain_keys_4k[i].sector); } for(int i = 0; i < 5; i++) { - if(mifare_classic_read_card(tx_rx, &reader, &nfc_worker->dev_data->mf_classic_data) == 40) { + if(mifare_classic_read_card(tx_rx, &reader, &nfc_worker->dev_data->mf_classic_data) == + 40) { return true; } } diff --git a/lib/nfc/parsers/plantain_parser.c b/lib/nfc/parsers/plantain_parser.c index 5f1a9c1377f8..46ed5a86d419 100644 --- a/lib/nfc/parsers/plantain_parser.c +++ b/lib/nfc/parsers/plantain_parser.c @@ -46,7 +46,8 @@ bool plantain_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) { MfClassicReader reader = {}; FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; - reader.type = mifare_classic_get_classic_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak); + reader.type = + mifare_classic_get_classic_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak); for(size_t i = 0; i < COUNT_OF(plantain_keys); i++) { mifare_classic_reader_add_sector( &reader, plantain_keys[i].sector, plantain_keys[i].key_a, plantain_keys[i].key_b); diff --git a/lib/nfc/parsers/troika_4k_parser.c b/lib/nfc/parsers/troika_4k_parser.c index ca969db06512..eead3dec25d3 100644 --- a/lib/nfc/parsers/troika_4k_parser.c +++ b/lib/nfc/parsers/troika_4k_parser.c @@ -68,7 +68,8 @@ bool troika_4k_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) MfClassicReader reader = {}; FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; - reader.type = mifare_classic_get_classic_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak); + reader.type = + mifare_classic_get_classic_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak); for(size_t i = 0; i < COUNT_OF(troika_4k_keys); i++) { mifare_classic_reader_add_sector( &reader, troika_4k_keys[i].sector, troika_4k_keys[i].key_a, troika_4k_keys[i].key_b); diff --git a/lib/nfc/parsers/troika_parser.c b/lib/nfc/parsers/troika_parser.c index e003d4161b6a..911bba18db98 100644 --- a/lib/nfc/parsers/troika_parser.c +++ b/lib/nfc/parsers/troika_parser.c @@ -44,7 +44,8 @@ bool troika_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) { MfClassicReader reader = {}; FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; - reader.type = mifare_classic_get_classic_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak); + reader.type = + mifare_classic_get_classic_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak); for(size_t i = 0; i < COUNT_OF(troika_keys); i++) { mifare_classic_reader_add_sector( diff --git a/lib/nfc/parsers/two_cities.c b/lib/nfc/parsers/two_cities.c index 6409a5754f43..54107964f24e 100644 --- a/lib/nfc/parsers/two_cities.c +++ b/lib/nfc/parsers/two_cities.c @@ -72,7 +72,8 @@ bool two_cities_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) MfClassicReader reader = {}; FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; - reader.type = mifare_classic_get_classic_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak); + reader.type = + mifare_classic_get_classic_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak); for(size_t i = 0; i < COUNT_OF(two_cities_keys_4k); i++) { mifare_classic_reader_add_sector( &reader, diff --git a/lib/nfc/protocols/mifare_classic.c b/lib/nfc/protocols/mifare_classic.c index 356b145f66a9..56d685f7615d 100644 --- a/lib/nfc/protocols/mifare_classic.c +++ b/lib/nfc/protocols/mifare_classic.c @@ -111,7 +111,10 @@ bool mifare_classic_is_block_read(MfClassicData* data, uint8_t block_num) { return (FURI_BIT(data->block_read_mask[block_num / 32], block_num % 32) == 1); } -void mifare_classic_set_block_read(MfClassicData* data, uint8_t block_num, MfClassicBlock* block_data) { +void mifare_classic_set_block_read( + MfClassicData* data, + uint8_t block_num, + MfClassicBlock* block_data) { furi_assert(data); if(mifare_classic_is_sector_trailer(block_num)) { @@ -173,7 +176,10 @@ void mifare_classic_set_key_found( } } -void mifare_classic_set_key_not_found(MfClassicData* data, uint8_t sector_num, MfClassicKey key_type) { +void mifare_classic_set_key_not_found( + MfClassicData* data, + uint8_t sector_num, + MfClassicKey key_type) { furi_assert(data); if(key_type == MfClassicKeyA) { @@ -360,7 +366,8 @@ static bool mf_classic_is_allowed_access( return mf_classic_is_allowed_access_sector_trailer( &emulator->data, block_num, key, action); } else { - return mifare_classic_is_allowed_access_data_block(&emulator->data, block_num, key, action); + return mifare_classic_is_allowed_access_data_block( + &emulator->data, block_num, key, action); } } @@ -492,7 +499,8 @@ static bool mf_classic_auth( for(uint8_t i = 0; i < 4; i++) { tx_rx->tx_data[i] = old_crypto1_byte(crypto, nr[i], 0) ^ nr[i]; tx_rx->tx_parity[0] |= - (((old_crypto1_filter(crypto->odd) ^ nfc_util_odd_parity8(nr[i])) & 0x01) << (7 - i)); + (((old_crypto1_filter(crypto->odd) ^ nfc_util_odd_parity8(nr[i])) & 0x01) + << (7 - i)); } nt = old_prng_successor(nt, 32); for(uint8_t i = 4; i < 8; i++) { @@ -763,7 +771,8 @@ static bool mifare_classic_read_sector_with_reader( // Read blocks for(uint8_t i = 0; i < sector->total_blocks; i++) { - if(mifare_classic_read_block(tx_rx, crypto, first_block + i, §or->block[i])) continue; + if(mifare_classic_read_block(tx_rx, crypto, first_block + i, §or->block[i])) + continue; if(i == 0) continue; // Try to auth to read next block in case previous is locked furi_hal_nfc_sleep(); @@ -941,7 +950,8 @@ bool mifare_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* old_crypto1_word(&emulator->crypto, nr, 1); uint32_t cardRr = ar ^ old_crypto1_word(&emulator->crypto, 0, 0); if(cardRr != old_prng_successor(nonce, 64)) { - FURI_LOG_T(TAG, "Wrong AUTH! %08lX != %08lX", cardRr, old_prng_successor(nonce, 64)); + FURI_LOG_T( + TAG, "Wrong AUTH! %08lX != %08lX", cardRr, old_prng_successor(nonce, 64)); // Don't send NACK, as the tag doesn't send it command_processed = true; break; @@ -1015,7 +1025,8 @@ bool mifare_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* } // Send ACK uint8_t ack = MF_CLASSIC_ACK_CMD; - old_crypto1_encrypt(&emulator->crypto, NULL, &ack, 4, tx_rx->tx_data, tx_rx->tx_parity); + old_crypto1_encrypt( + &emulator->crypto, NULL, &ack, 4, tx_rx->tx_data, tx_rx->tx_parity); tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent; tx_rx->tx_bits = 4; @@ -1052,7 +1063,8 @@ bool mifare_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* } // Send ACK ack = MF_CLASSIC_ACK_CMD; - old_crypto1_encrypt(&emulator->crypto, NULL, &ack, 4, tx_rx->tx_data, tx_rx->tx_parity); + old_crypto1_encrypt( + &emulator->crypto, NULL, &ack, 4, tx_rx->tx_data, tx_rx->tx_parity); tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent; tx_rx->tx_bits = 4; } else if( @@ -1074,13 +1086,15 @@ bool mifare_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* int32_t prev_value; uint8_t addr; - if(!mifare_classic_block_to_value(emulator->data.block[block].value, &prev_value, &addr)) { + if(!mifare_classic_block_to_value( + emulator->data.block[block].value, &prev_value, &addr)) { break; } // Send ACK uint8_t ack = MF_CLASSIC_ACK_CMD; - old_crypto1_encrypt(&emulator->crypto, NULL, &ack, 4, tx_rx->tx_data, tx_rx->tx_parity); + old_crypto1_encrypt( + &emulator->crypto, NULL, &ack, 4, tx_rx->tx_data, tx_rx->tx_parity); tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent; tx_rx->tx_bits = 4; @@ -1115,7 +1129,8 @@ bool mifare_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* transfer_buf_valid = false; uint8_t ack = MF_CLASSIC_ACK_CMD; - old_crypto1_encrypt(&emulator->crypto, NULL, &ack, 4, tx_rx->tx_data, tx_rx->tx_parity); + old_crypto1_encrypt( + &emulator->crypto, NULL, &ack, 4, tx_rx->tx_data, tx_rx->tx_parity); tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent; tx_rx->tx_bits = 4; } else { @@ -1129,7 +1144,8 @@ bool mifare_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* uint8_t nack = transfer_buf_valid ? MF_CLASSIC_NACK_BUF_VALID_CMD : MF_CLASSIC_NACK_BUF_INVALID_CMD; if(is_encrypted) { - old_crypto1_encrypt(&emulator->crypto, NULL, &nack, 4, tx_rx->tx_data, tx_rx->tx_parity); + old_crypto1_encrypt( + &emulator->crypto, NULL, &nack, 4, tx_rx->tx_data, tx_rx->tx_parity); } else { tx_rx->tx_data[0] = nack; } @@ -1430,7 +1446,8 @@ bool mifare_classic_write_sector( uint8_t first_block = mf_classic_get_first_block_num_of_sector(sec_num); uint8_t total_blocks = mf_classic_get_blocks_num_in_sector(sec_num); - MfClassicSectorTrailer* sec_tr = mifare_classic_get_sector_trailer_by_sector(dest_data, sec_num); + MfClassicSectorTrailer* sec_tr = + mifare_classic_get_sector_trailer_by_sector(dest_data, sec_num); bool key_a_found = mifare_classic_is_key_found(dest_data, sec_num, MfClassicKeyA); bool key_b_found = mifare_classic_is_key_found(dest_data, sec_num, MfClassicKeyB); diff --git a/lib/nfc/protocols/mifare_classic.h b/lib/nfc/protocols/mifare_classic.h index 269ef9f1a866..e6530e2dc849 100644 --- a/lib/nfc/protocols/mifare_classic.h +++ b/lib/nfc/protocols/mifare_classic.h @@ -134,11 +134,17 @@ void mifare_classic_set_key_found( MfClassicKey key_type, uint64_t key); -void mifare_classic_set_key_not_found(MfClassicData* data, uint8_t sector_num, MfClassicKey key_type); +void mifare_classic_set_key_not_found( + MfClassicData* data, + uint8_t sector_num, + MfClassicKey key_type); bool mifare_classic_is_block_read(MfClassicData* data, uint8_t block_num); -void mifare_classic_set_block_read(MfClassicData* data, uint8_t block_num, MfClassicBlock* block_data); +void mifare_classic_set_block_read( + MfClassicData* data, + uint8_t block_num, + MfClassicBlock* block_data); bool mifare_classic_is_sector_data_read(MfClassicData* data, uint8_t sector_num); diff --git a/lib/nfc/protocols/nfcb/nfcb_poller.c b/lib/nfc/protocols/nfcb/nfcb_poller.c index 466656a0bdaf..fb73c6b749f8 100644 --- a/lib/nfc/protocols/nfcb/nfcb_poller.c +++ b/lib/nfc/protocols/nfcb/nfcb_poller.c @@ -87,7 +87,7 @@ NfcbError nfcb_poller_config(NfcbPoller* instance) { // instance->data = malloc(sizeof(NfcbData)); // instance->buff = - // nfc_poller_buffer_alloc(NFCB_POLLER_BUFER_MAX_SIZE, NFCB_POLLER_BUFER_MAX_SIZE); + // nfc_poller_buffer_alloc(NFCB_POLLER_BUFER_MAX_SIZE, NFCB_POLLER_BUFER_MAX_SIZE); nfc_config(instance->nfc, NfcModeNfcbPoller); nfc_set_guard_time_us(instance->nfc, NFCB_GUARD_TIME_US); From c7c2119e85e518675196cd4dbbc15e1de0ab260f Mon Sep 17 00:00:00 2001 From: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Date: Tue, 6 Jun 2023 17:59:36 +0300 Subject: [PATCH 100/149] Gsurkov/3324 mf desfire (#2741) * Add basic skeleton for Desfire support * Make Read Mifare Desfire option work * Add more boilerplate code for MfDesfire * Add even more boilerplate code for MfDesfire * Add MfDesfireVersion data structure * Implement ISO14443-4 activation sequence for NFC-A * Implement some GUI for Mifare Desfire * Add read version method * Implement ISO14443-4a poller skeleton * Add Desfire read version skeleton code * Working Desfire get version * Working Desfire get free memory * Add BitBuffer type skeleton * Improve BitBuffer implementation * Get rid of NfcPollerBuffer in Iso14443_4aPoller * Port MfDesfirePoller and Iso14443_4aPoller to BitBuffer * Add more methods and comments for BitBuffer * Implement read key settings * Refactor MfDesfireData --- applications/main/nfc/nfc_app.c | 4 + applications/main/nfc/nfc_app_i.h | 4 +- .../main/nfc/scenes/nfc_scene_config.h | 7 +- .../nfc/scenes/nfc_scene_mf_desfire_app.c | 15 + .../nfc/scenes/nfc_scene_mf_desfire_data.c | 15 + .../nfc/scenes/nfc_scene_mf_desfire_menu.c | 69 +++++ .../nfc/scenes/nfc_scene_mf_desfire_read.c | 58 ++++ .../nfc_scene_mf_desfire_read_success.c | 94 +++++++ .../nfc_scene_mf_ultralight_read_success.c | 3 +- .../main/nfc/scenes/nfc_scene_nfca_emulate.c | 3 +- applications/main/nfc/scenes/nfc_scene_read.c | 8 + .../nfc/scenes/nfc_scene_read_card_type.c | 2 +- .../main/nfc/scenes/nfc_scene_retry_confirm.c | 3 + .../main/nfc/scenes/nfc_scene_saved_menu.c | 4 +- .../main/nfc/scenes/nfc_scene_start.c | 3 +- .../main/nfc_rpc/assets/compiled/main.pb.c | 5 - .../main/nfc_rpc/assets/compiled/main.pb.h | 260 +++++++++++++---- .../nfc_rpc/assets/compiled/mf_classic.pb.c | 8 - .../nfc_rpc/assets/compiled/mf_classic.pb.h | 124 +++++--- .../assets/compiled/mf_ultralight.pb.c | 19 -- .../assets/compiled/mf_ultralight.pb.h | 264 ++++++++++++------ .../main/nfc_rpc/assets/compiled/nfca.pb.c | 9 - .../main/nfc_rpc/assets/compiled/nfca.pb.h | 131 +++++---- applications/main/nfc_rpc/nfc_rpc.c | 3 +- lib/nfc/helpers/bit_buffer.c | 161 +++++++++++ lib/nfc/helpers/bit_buffer.h | 204 ++++++++++++++ lib/nfc/nfc_device.c | 3 +- lib/nfc/nfc_device_data.h | 2 + lib/nfc/nfc_poller.c | 3 + lib/nfc/nfc_poller.h | 2 + lib/nfc/parsers/plantain_4k_parser.c | 6 +- lib/nfc/parsers/plantain_parser.c | 3 +- lib/nfc/parsers/troika_4k_parser.c | 3 +- lib/nfc/parsers/troika_parser.c | 3 +- lib/nfc/parsers/two_cities.c | 3 +- lib/nfc/protocols/iso14443_4a/iso14443_4a.c | 1 + lib/nfc/protocols/iso14443_4a/iso14443_4a.h | 36 +++ .../iso14443_4a/iso14443_4a_poller.c | 182 ++++++++++++ .../iso14443_4a/iso14443_4a_poller.h | 56 ++++ .../iso14443_4a/iso14443_4a_poller_i.c | 131 +++++++++ .../iso14443_4a/iso14443_4a_poller_i.h | 59 ++++ .../mf_classic/mf_classic_poller_i.h | 1 - lib/nfc/protocols/mf_desfire/mf_desfire.c | 10 + lib/nfc/protocols/mf_desfire/mf_desfire.h | 145 ++++++++++ .../protocols/mf_desfire/mf_desfire_poller.c | 227 +++++++++++++++ .../protocols/mf_desfire/mf_desfire_poller.h | 58 ++++ .../mf_desfire/mf_desfire_poller_i.c | 182 ++++++++++++ .../mf_desfire/mf_desfire_poller_i.h | 73 +++++ lib/nfc/protocols/mifare_classic.c | 43 ++- lib/nfc/protocols/mifare_classic.h | 10 +- lib/nfc/protocols/nfca/nfca.h | 1 + lib/nfc/protocols/nfca/nfca_poller.c | 4 +- lib/nfc/protocols/nfca/nfca_poller_i.c | 17 +- lib/nfc/protocols/nfca/nfca_poller_i.h | 8 +- lib/nfc/protocols/nfcb/nfcb_poller.c | 2 +- 55 files changed, 2419 insertions(+), 335 deletions(-) create mode 100644 applications/main/nfc/scenes/nfc_scene_mf_desfire_app.c create mode 100644 applications/main/nfc/scenes/nfc_scene_mf_desfire_data.c create mode 100644 applications/main/nfc/scenes/nfc_scene_mf_desfire_menu.c create mode 100644 applications/main/nfc/scenes/nfc_scene_mf_desfire_read.c create mode 100644 applications/main/nfc/scenes/nfc_scene_mf_desfire_read_success.c create mode 100644 lib/nfc/helpers/bit_buffer.c create mode 100644 lib/nfc/helpers/bit_buffer.h create mode 100644 lib/nfc/protocols/iso14443_4a/iso14443_4a.c create mode 100644 lib/nfc/protocols/iso14443_4a/iso14443_4a.h create mode 100644 lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.c create mode 100644 lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.h create mode 100644 lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c create mode 100644 lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.h create mode 100644 lib/nfc/protocols/mf_desfire/mf_desfire.c create mode 100644 lib/nfc/protocols/mf_desfire/mf_desfire.h create mode 100644 lib/nfc/protocols/mf_desfire/mf_desfire_poller.c create mode 100644 lib/nfc/protocols/mf_desfire/mf_desfire_poller.h create mode 100644 lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c create mode 100644 lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.h diff --git a/applications/main/nfc/nfc_app.c b/applications/main/nfc/nfc_app.c index e1f2753b9768..fd7e057b30ec 100644 --- a/applications/main/nfc/nfc_app.c +++ b/applications/main/nfc/nfc_app.c @@ -47,7 +47,9 @@ NfcApp* nfc_app_alloc() { instance->nfc = nfc_alloc(); instance->nfca_poller = nfca_poller_alloc(instance->nfc); + instance->iso14443_4a_poller = iso14443_4a_poller_alloc(instance->nfca_poller); instance->mf_ul_poller = mf_ultralight_poller_alloc(instance->nfca_poller); + instance->mf_desfire_poller = mf_desfire_poller_alloc(instance->iso14443_4a_poller); instance->nfca_listener = nfca_listener_alloc(instance->nfc); instance->mf_ul_listener = mf_ultralight_listener_alloc(instance->nfca_listener); instance->nfcb_poller = nfcb_poller_alloc(instance->nfc); @@ -144,8 +146,10 @@ void nfc_app_free(NfcApp* instance) { instance->rpc_ctx = NULL; } + mf_desfire_poller_free(instance->mf_desfire_poller); mf_ultralight_listener_free(instance->mf_ul_listener); mf_ultralight_poller_free(instance->mf_ul_poller); + iso14443_4a_poller_free(instance->iso14443_4a_poller); nfca_listener_free(instance->nfca_listener); nfca_poller_free(instance->nfca_poller); nfcb_poller_free(instance->nfcb_poller); diff --git a/applications/main/nfc/nfc_app_i.h b/applications/main/nfc/nfc_app_i.h index bb28dce43366..a9f23cc6ad7e 100644 --- a/applications/main/nfc/nfc_app_i.h +++ b/applications/main/nfc/nfc_app_i.h @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -55,7 +56,6 @@ #define NFC_APP_EXTENSION ".nfc" #define NFC_APP_SHADOW_EXTENSION ".shd" - typedef enum { NfcRpcStateIdle, NfcRpcStateEmulating, @@ -90,8 +90,10 @@ struct NfcApp { Nfc* nfc; NfcaPoller* nfca_poller; NfcaListener* nfca_listener; + Iso14443_4aPoller* iso14443_4a_poller; MfUltralightPoller* mf_ul_poller; MfUltralightListener* mf_ul_listener; + MfDesfirePoller* mf_desfire_poller; NfcbPoller* nfcb_poller; NfcPoller* nfc_poller; diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index d6037f85b239..d4f4ae8b3875 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -24,6 +24,11 @@ ADD_SCENE(nfc, mf_ultralight_unlock_menu, MfUltralightUnlockMenu) ADD_SCENE(nfc, mf_ultralight_unlock_warn, MfUltralightUnlockWarn) ADD_SCENE(nfc, mf_ultralight_key_input, MfUltralightKeyInput) ADD_SCENE(nfc, mf_ultralight_capture_pass, MfUltralightCapturePass) +ADD_SCENE(nfc, mf_desfire_read, MfDesfireRead) +ADD_SCENE(nfc, mf_desfire_read_success, MfDesfireReadSuccess) +ADD_SCENE(nfc, mf_desfire_menu, MfDesfireMenu) +ADD_SCENE(nfc, mf_desfire_data, MfDesfireData) +ADD_SCENE(nfc, mf_desfire_app, MfDesfireApp) ADD_SCENE(nfc, set_type, SetType) ADD_SCENE(nfc, set_sak, SetSak) @@ -32,4 +37,4 @@ ADD_SCENE(nfc, set_uid, SetUid) ADD_SCENE(nfc, generate_info, GenerateInfo) -ADD_SCENE(nfc, not_implemented, NotImplemented) \ No newline at end of file +ADD_SCENE(nfc, not_implemented, NotImplemented) diff --git a/applications/main/nfc/scenes/nfc_scene_mf_desfire_app.c b/applications/main/nfc/scenes/nfc_scene_mf_desfire_app.c new file mode 100644 index 000000000000..6620576461e6 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_desfire_app.c @@ -0,0 +1,15 @@ +#include "../nfc_app_i.h" + +void nfc_scene_mf_desfire_app_on_enter(void* context) { + UNUSED(context); +} + +bool nfc_scene_mf_desfire_app_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + UNUSED(event); + return false; +} + +void nfc_scene_mf_desfire_app_on_exit(void* context) { + UNUSED(context); +} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_desfire_data.c b/applications/main/nfc/scenes/nfc_scene_mf_desfire_data.c new file mode 100644 index 000000000000..b0cf44f6878c --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_desfire_data.c @@ -0,0 +1,15 @@ +#include "../nfc_app_i.h" + +void nfc_scene_mf_desfire_data_on_enter(void* context) { + UNUSED(context); +} + +bool nfc_scene_mf_desfire_data_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + UNUSED(event); + return false; +} + +void nfc_scene_mf_desfire_data_on_exit(void* context) { + UNUSED(context); +} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_desfire_menu.c b/applications/main/nfc/scenes/nfc_scene_mf_desfire_menu.c new file mode 100644 index 000000000000..69697e073005 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_desfire_menu.c @@ -0,0 +1,69 @@ +#include "../nfc_app_i.h" +#include + +enum SubmenuIndex { + SubmenuIndexSave, + SubmenuIndexEmulateUid, + SubmenuIndexInfo, +}; + +void nfc_scene_mf_desfire_menu_submenu_callback(void* context, uint32_t index) { + NfcApp* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, index); +} + +void nfc_scene_mf_desfire_menu_on_enter(void* context) { + NfcApp* nfc = context; + Submenu* submenu = nfc->submenu; + + submenu_add_item( + submenu, "Save", SubmenuIndexSave, nfc_scene_mf_desfire_menu_submenu_callback, nfc); + submenu_add_item( + submenu, + "Emulate UID", + SubmenuIndexEmulateUid, + nfc_scene_mf_desfire_menu_submenu_callback, + nfc); + submenu_add_item( + submenu, "Info", SubmenuIndexInfo, nfc_scene_mf_desfire_menu_submenu_callback, nfc); + + submenu_set_selected_item( + nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireMenu)); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); +} + +bool nfc_scene_mf_desfire_menu_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexSave) { + // TODO: Implement saving + scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + consumed = true; + } else if(event.event == SubmenuIndexEmulateUid) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcaEmulate); + if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneNotImplemented)) { + DOLPHIN_DEED(DolphinDeedNfcAddEmulate); + } else { + DOLPHIN_DEED(DolphinDeedNfcEmulate); + } + consumed = true; + } else if(event.event == SubmenuIndexInfo) { + // TODO: Implement info + scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + consumed = true; + } + } + + return consumed; +} + +void nfc_scene_mf_desfire_menu_on_exit(void* context) { + NfcApp* nfc = context; + + // Clear view + submenu_reset(nfc->submenu); +} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_desfire_read.c b/applications/main/nfc/scenes/nfc_scene_mf_desfire_read.c new file mode 100644 index 000000000000..9e58c643c2e6 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_desfire_read.c @@ -0,0 +1,58 @@ +#include "../nfc_app_i.h" +#include + +enum { + NfcWorkerEventMfDesfireReadSuccess, +}; + +MfDesfirePollerCommand + nfc_scene_mf_desfire_read_worker_callback(MfDesfirePollerEvent event, void* context) { + NfcApp* nfc = context; + + MfDesfirePollerCommand command = MfDesfirePollerCommandContinue; + + if(event.type == MfDesfirePollerEventTypeReadSuccess) { + view_dispatcher_send_custom_event( + nfc->view_dispatcher, NfcWorkerEventMfDesfireReadSuccess); + command = MfDesfirePollerCommandStop; + } + + return command; +} + +void nfc_scene_mf_desfire_read_on_enter(void* context) { + NfcApp* nfc = context; + + // Setup view + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); + + mf_desfire_poller_read(nfc->mf_desfire_poller, nfc_scene_mf_desfire_read_worker_callback, nfc); + + nfc_blink_read_start(nfc); +} + +bool nfc_scene_mf_desfire_read_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcWorkerEventMfDesfireReadSuccess) { + notification_message(nfc->notifications, &sequence_success); + mf_desfire_poller_get_data(nfc->mf_desfire_poller, &nfc->nfc_dev_data.mf_desfire_data); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireReadSuccess); + DOLPHIN_DEED(DolphinDeedNfcReadSuccess); + consumed = true; + } + } + return consumed; +} + +void nfc_scene_mf_desfire_read_on_exit(void* context) { + NfcApp* nfc = context; + + mf_desfire_poller_stop(nfc->mf_desfire_poller); + // Clear view + popup_reset(nfc->popup); + + nfc_blink_stop(nfc); +} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_desfire_read_success.c b/applications/main/nfc/scenes/nfc_scene_mf_desfire_read_success.c new file mode 100644 index 000000000000..3caf5a4460ff --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_desfire_read_success.c @@ -0,0 +1,94 @@ +#include "../nfc_app_i.h" + +void nfc_scene_mf_desfire_read_success_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + furi_assert(context); + NfcApp* nfc = context; + + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); + } +} + +void nfc_scene_mf_desfire_read_success_on_enter(void* context) { + NfcApp* nfc = context; + + // Setup view + nfc->nfc_dev_data.protocol = NfcDevProtocolMfDesfire; + MfDesfireData* data = &nfc->nfc_dev_data.mf_desfire_data; + NfcaData* iso14443_3a_data = &data->iso14443_4a_data.iso14443_3a_data; + Widget* widget = nfc->widget; + + FuriString* temp_str; + + temp_str = furi_string_alloc_printf("\e#MIFARE DESfire\n"); + furi_string_cat_printf(temp_str, "UID:"); + for(size_t i = 0; i < iso14443_3a_data->uid_len; i++) { + furi_string_cat_printf(temp_str, " %02X", iso14443_3a_data->uid[i]); + } + + uint32_t bytes_total = 1UL << (data->version.sw_storage >> 1); + uint32_t bytes_free = data->free_memory.bytes_free; + furi_string_cat_printf(temp_str, "\n%lu", bytes_total); + if(data->version.sw_storage & 1) { + furi_string_push_back(temp_str, '+'); + } + furi_string_cat_printf(temp_str, " bytes, %lu bytes free\n", bytes_free); + + uint16_t n_files = 0; + uint16_t n_apps = data->applications.count; + + for(size_t i = 0; i < n_apps; ++i) { + n_files += data->applications.data[i].files.count; + } + furi_string_cat_printf(temp_str, "%d Application", n_apps); + if(n_apps != 1) { + furi_string_push_back(temp_str, 's'); + } + furi_string_cat_printf(temp_str, ", %d file", n_files); + if(n_files != 1) { + furi_string_push_back(temp_str, 's'); + } + + widget_add_text_scroll_element(widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); + furi_string_free(temp_str); + + widget_add_button_element( + widget, GuiButtonTypeLeft, "Retry", nfc_scene_mf_desfire_read_success_widget_callback, nfc); + widget_add_button_element( + widget, GuiButtonTypeRight, "More", nfc_scene_mf_desfire_read_success_widget_callback, nfc); + + notification_message_block(nfc->notifications, &sequence_set_green_255); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); +} + +bool nfc_scene_mf_desfire_read_success_on_event(void* context, SceneManagerEvent event) { + NfcApp* 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, NfcSceneMfDesfireMenu); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeBack) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); + consumed = true; + } + + return consumed; +} + +void nfc_scene_mf_desfire_read_success_on_exit(void* context) { + NfcApp* 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_mf_ultralight_read_success.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_success.c index f53619832dd1..150d8d9fa724 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_success.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_success.c @@ -27,8 +27,7 @@ void nfc_scene_mf_ultralight_read_success_on_enter(void* context) { for(size_t i = 0; i < data->nfca_data.uid_len; i++) { furi_string_cat_printf(temp_str, " %02X", data->nfca_data.uid[i]); } - furi_string_cat_printf( - temp_str, "\nPages Read: %d/%d", data->pages_read, data->pages_total); + furi_string_cat_printf(temp_str, "\nPages Read: %d/%d", data->pages_read, data->pages_total); if(data->pages_read != data->pages_total) { furi_string_cat_printf(temp_str, "\nPassword-protected pages!"); } diff --git a/applications/main/nfc/scenes/nfc_scene_nfca_emulate.c b/applications/main/nfc/scenes/nfc_scene_nfca_emulate.c index 21e243c6855e..b39a7e75252d 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfca_emulate.c +++ b/applications/main/nfc/scenes/nfc_scene_nfca_emulate.c @@ -7,7 +7,8 @@ enum { NfcSceneNfcaEmulateStateTextBox, }; -NfcaListenerCommand nfc_scene_nfca_emulate_worker_callback(NfcaListenerEvent event, void* context) { +NfcaListenerCommand + nfc_scene_nfca_emulate_worker_callback(NfcaListenerEvent event, void* context) { furi_assert(context); NfcApp* nfc = context; diff --git a/applications/main/nfc/scenes/nfc_scene_read.c b/applications/main/nfc/scenes/nfc_scene_read.c index 39c6b1d46b12..c18f36a89cc7 100644 --- a/applications/main/nfc/scenes/nfc_scene_read.c +++ b/applications/main/nfc/scenes/nfc_scene_read.c @@ -5,6 +5,7 @@ enum { NfcSceneReadEventNfcaDetected = 100, NfcSceneReadEventNfcbDetected, NfcSceneReadEventMfUltralightDetected, + NfcSceneReadEventMfDesfireDetected, }; NfcPollerCommand nfc_scene_read_worker_callback(NfcPollerEvent event, void* context) { @@ -22,6 +23,10 @@ NfcPollerCommand nfc_scene_read_worker_callback(NfcPollerEvent event, void* cont view_dispatcher_send_custom_event( nfc->view_dispatcher, NfcSceneReadEventMfUltralightDetected); command = NfcPollerCommandStop; + } else if(event == NfcPollerEventMfDesfireDetected) { + view_dispatcher_send_custom_event( + nfc->view_dispatcher, NfcSceneReadEventMfDesfireDetected); + command = NfcPollerCommandStop; } return command; @@ -56,6 +61,9 @@ bool nfc_scene_read_on_event(void* context, SceneManagerEvent event) { mf_ultralight_auth_reset(nfc->mf_ul_auth); scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightRead); consumed = true; + } else if(event.event == NfcSceneReadEventMfDesfireDetected) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireRead); + consumed = true; } } return consumed; diff --git a/applications/main/nfc/scenes/nfc_scene_read_card_type.c b/applications/main/nfc/scenes/nfc_scene_read_card_type.c index 97c11a32493f..2f1ca27dff69 100644 --- a/applications/main/nfc/scenes/nfc_scene_read_card_type.c +++ b/applications/main/nfc/scenes/nfc_scene_read_card_type.c @@ -64,7 +64,7 @@ bool nfc_scene_read_card_type_on_event(void* context, SceneManagerEvent event) { consumed = true; } if(event.event == SubmenuIndexReadMifareDesfire) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireRead); consumed = true; } if(event.event == SubmenuIndexReadMfUltralight) { diff --git a/applications/main/nfc/scenes/nfc_scene_retry_confirm.c b/applications/main/nfc/scenes/nfc_scene_retry_confirm.c index ba27051c45b8..9ddd7c8aa3a2 100644 --- a/applications/main/nfc/scenes/nfc_scene_retry_confirm.c +++ b/applications/main/nfc/scenes/nfc_scene_retry_confirm.c @@ -39,6 +39,9 @@ bool nfc_scene_retry_confirm_on_event(void* context, SceneManagerEvent event) { nfc->scene_manager, NfcSceneMfUltralightRead)) { consumed = scene_manager_search_and_switch_to_previous_scene( nfc->scene_manager, NfcSceneMfUltralightRead); + } else if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneMfDesfireRead)) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneMfDesfireRead); } } } else if(event.type == SceneManagerEventTypeBack) { diff --git a/applications/main/nfc/scenes/nfc_scene_saved_menu.c b/applications/main/nfc/scenes/nfc_scene_saved_menu.c index 3ff05729eb75..10651d1d48bf 100644 --- a/applications/main/nfc/scenes/nfc_scene_saved_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_saved_menu.c @@ -162,9 +162,9 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { // FURI_LOG_I("nfc", "application_info_present: %d", application_info_present); // if(application_info_present) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); // } else { - // scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); + // scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); // } consumed = true; } else if(event.event == SubmenuIndexRestoreOriginal) { diff --git a/applications/main/nfc/scenes/nfc_scene_start.c b/applications/main/nfc/scenes/nfc_scene_start.c index fd083aad55f8..1315f1036866 100644 --- a/applications/main/nfc/scenes/nfc_scene_start.c +++ b/applications/main/nfc/scenes/nfc_scene_start.c @@ -68,8 +68,7 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(nfc->scene_manager, NfcSceneExtraActions); consumed = true; } else if(event.event == SubmenuIndexAddManually) { - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneStart, NfcSceneSetType); + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneStart, NfcSceneSetType); scene_manager_next_scene(nfc->scene_manager, NfcSceneSetType); consumed = true; } else if(event.event == SubmenuIndexDebug) { diff --git a/applications/main/nfc_rpc/assets/compiled/main.pb.c b/applications/main/nfc_rpc/assets/compiled/main.pb.c index 9b574c9d6f71..a9c4d20613c5 100644 --- a/applications/main/nfc_rpc/assets/compiled/main.pb.c +++ b/applications/main/nfc_rpc/assets/compiled/main.pb.c @@ -8,9 +8,4 @@ PB_BIND(Nfc_Empty, Nfc_Empty, AUTO) - PB_BIND(Nfc_Main, Nfc_Main, 2) - - - - diff --git a/applications/main/nfc_rpc/assets/compiled/main.pb.h b/applications/main/nfc_rpc/assets/compiled/main.pb.h index 0c25a8855ded..6c85b126d8cb 100644 --- a/applications/main/nfc_rpc/assets/compiled/main.pb.h +++ b/applications/main/nfc_rpc/assets/compiled/main.pb.h @@ -18,7 +18,8 @@ typedef enum _Nfc_CommandStatus { Nfc_CommandStatus_ERROR = 1, /* *< Unknown error */ Nfc_CommandStatus_ERROR_NOT_IMPLEMENTED = 3, /* *< Command succesfully decoded, but not implemented (deprecated or not yet implemented) */ - Nfc_CommandStatus_ERROR_BUSY = 4 /* *< Somebody took global lock, so not all commands are available */ + Nfc_CommandStatus_ERROR_BUSY = + 4 /* *< Somebody took global lock, so not all commands are available */ } Nfc_CommandStatus; /* Struct definitions */ @@ -61,7 +62,6 @@ typedef struct _Nfc_Main { } content; } Nfc_Main; - #ifdef __cplusplus extern "C" { #endif @@ -69,27 +69,37 @@ extern "C" { /* Helper constants for enums */ #define _Nfc_CommandStatus_MIN Nfc_CommandStatus_OK #define _Nfc_CommandStatus_MAX Nfc_CommandStatus_ERROR_BUSY -#define _Nfc_CommandStatus_ARRAYSIZE ((Nfc_CommandStatus)(Nfc_CommandStatus_ERROR_BUSY+1)) - +#define _Nfc_CommandStatus_ARRAYSIZE ((Nfc_CommandStatus)(Nfc_CommandStatus_ERROR_BUSY + 1)) #define Nfc_Main_command_status_ENUMTYPE Nfc_CommandStatus - /* Initializer values for message structs */ -#define Nfc_Empty_init_default {0} -#define Nfc_Main_init_default {_Nfc_CommandStatus_MIN, {{NULL}, NULL}, 0, {Nfc_Empty_init_default}} -#define Nfc_Empty_init_zero {0} -#define Nfc_Main_init_zero {_Nfc_CommandStatus_MIN, {{NULL}, NULL}, 0, {Nfc_Empty_init_zero}} +#define Nfc_Empty_init_default \ + { 0 } +#define Nfc_Main_init_default \ + { \ + _Nfc_CommandStatus_MIN, {{NULL}, NULL}, 0, { \ + Nfc_Empty_init_default \ + } \ + } +#define Nfc_Empty_init_zero \ + { 0 } +#define Nfc_Main_init_zero \ + { \ + _Nfc_CommandStatus_MIN, {{NULL}, NULL}, 0, { \ + Nfc_Empty_init_zero \ + } \ + } /* Field tags (for use in manual encoding/decoding) */ -#define Nfc_Main_command_status_tag 1 -#define Nfc_Main_empty_tag 2 -#define Nfc_Main_nfca_read_req_tag 3 -#define Nfc_Main_nfca_read_resp_tag 4 -#define Nfc_Main_nfca_emulate_start_req_tag 5 -#define Nfc_Main_nfca_emulate_start_resp_tag 6 -#define Nfc_Main_nfca_emulate_stop_req_tag 7 -#define Nfc_Main_nfca_emulate_stop_resp_tag 8 +#define Nfc_Main_command_status_tag 1 +#define Nfc_Main_empty_tag 2 +#define Nfc_Main_nfca_read_req_tag 3 +#define Nfc_Main_nfca_read_resp_tag 4 +#define Nfc_Main_nfca_emulate_start_req_tag 5 +#define Nfc_Main_nfca_emulate_start_resp_tag 6 +#define Nfc_Main_nfca_emulate_stop_req_tag 7 +#define Nfc_Main_nfca_emulate_stop_resp_tag 8 #define Nfc_Main_mf_ultralight_read_page_req_tag 9 #define Nfc_Main_mf_ultralight_read_page_resp_tag 10 #define Nfc_Main_mf_ultralight_read_version_req_tag 11 @@ -106,46 +116,163 @@ extern "C" { #define Nfc_Main_mf_ultralight_emulate_start_resp_tag 22 #define Nfc_Main_mf_ultralight_emulate_stop_req_tag 23 #define Nfc_Main_mf_ultralight_emulate_stop_resp_tag 24 -#define Nfc_Main_mf_classic_auth_req_tag 25 -#define Nfc_Main_mf_classic_auth_resp_tag 26 -#define Nfc_Main_mf_classic_read_block_req_tag 27 -#define Nfc_Main_mf_classic_read_block_resp_tag 28 +#define Nfc_Main_mf_classic_auth_req_tag 25 +#define Nfc_Main_mf_classic_auth_resp_tag 26 +#define Nfc_Main_mf_classic_read_block_req_tag 27 +#define Nfc_Main_mf_classic_read_block_resp_tag 28 /* Struct field encoding specification for nanopb */ -#define Nfc_Empty_FIELDLIST(X, a) \ +#define Nfc_Empty_FIELDLIST(X, a) #define Nfc_Empty_CALLBACK NULL #define Nfc_Empty_DEFAULT NULL -#define Nfc_Main_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UENUM, command_status, 1) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,empty,content.empty), 2) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,nfca_read_req,content.nfca_read_req), 3) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,nfca_read_resp,content.nfca_read_resp), 4) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,nfca_emulate_start_req,content.nfca_emulate_start_req), 5) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,nfca_emulate_start_resp,content.nfca_emulate_start_resp), 6) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,nfca_emulate_stop_req,content.nfca_emulate_stop_req), 7) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,nfca_emulate_stop_resp,content.nfca_emulate_stop_resp), 8) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_page_req,content.mf_ultralight_read_page_req), 9) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_page_resp,content.mf_ultralight_read_page_resp), 10) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_version_req,content.mf_ultralight_read_version_req), 11) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_version_resp,content.mf_ultralight_read_version_resp), 12) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_write_page_req,content.mf_ultralight_write_page_req), 13) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_write_page_resp,content.mf_ultralight_write_page_resp), 14) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_signature_req,content.mf_ultralight_read_signature_req), 15) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_signature_resp,content.mf_ultralight_read_signature_resp), 16) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_counter_req,content.mf_ultralight_read_counter_req), 17) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_counter_resp,content.mf_ultralight_read_counter_resp), 18) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_tearing_flag_req,content.mf_ultralight_read_tearing_flag_req), 19) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_tearing_flag_resp,content.mf_ultralight_read_tearing_flag_resp), 20) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_emulate_start_req,content.mf_ultralight_emulate_start_req), 21) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_emulate_start_resp,content.mf_ultralight_emulate_start_resp), 22) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_emulate_stop_req,content.mf_ultralight_emulate_stop_req), 23) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_emulate_stop_resp,content.mf_ultralight_emulate_stop_resp), 24) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_classic_auth_req,content.mf_classic_auth_req), 25) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_classic_auth_resp,content.mf_classic_auth_resp), 26) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_classic_read_block_req,content.mf_classic_read_block_req), 27) \ -X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_classic_read_block_resp,content.mf_classic_read_block_resp), 28) +#define Nfc_Main_FIELDLIST(X, a) \ + X(a, STATIC, SINGULAR, UENUM, command_status, 1) \ + X(a, STATIC, ONEOF, MSG_W_CB, (content, empty, content.empty), 2) \ + X(a, STATIC, ONEOF, MSG_W_CB, (content, nfca_read_req, content.nfca_read_req), 3) \ + X(a, STATIC, ONEOF, MSG_W_CB, (content, nfca_read_resp, content.nfca_read_resp), 4) \ + X(a, \ + STATIC, \ + ONEOF, \ + MSG_W_CB, \ + (content, nfca_emulate_start_req, content.nfca_emulate_start_req), \ + 5) \ + X(a, \ + STATIC, \ + ONEOF, \ + MSG_W_CB, \ + (content, nfca_emulate_start_resp, content.nfca_emulate_start_resp), \ + 6) \ + X(a, \ + STATIC, \ + ONEOF, \ + MSG_W_CB, \ + (content, nfca_emulate_stop_req, content.nfca_emulate_stop_req), \ + 7) \ + X(a, \ + STATIC, \ + ONEOF, \ + MSG_W_CB, \ + (content, nfca_emulate_stop_resp, content.nfca_emulate_stop_resp), \ + 8) \ + X(a, \ + STATIC, \ + ONEOF, \ + MSG_W_CB, \ + (content, mf_ultralight_read_page_req, content.mf_ultralight_read_page_req), \ + 9) \ + X(a, \ + STATIC, \ + ONEOF, \ + MSG_W_CB, \ + (content, mf_ultralight_read_page_resp, content.mf_ultralight_read_page_resp), \ + 10) \ + X(a, \ + STATIC, \ + ONEOF, \ + MSG_W_CB, \ + (content, mf_ultralight_read_version_req, content.mf_ultralight_read_version_req), \ + 11) \ + X(a, \ + STATIC, \ + ONEOF, \ + MSG_W_CB, \ + (content, mf_ultralight_read_version_resp, content.mf_ultralight_read_version_resp), \ + 12) \ + X(a, \ + STATIC, \ + ONEOF, \ + MSG_W_CB, \ + (content, mf_ultralight_write_page_req, content.mf_ultralight_write_page_req), \ + 13) \ + X(a, \ + STATIC, \ + ONEOF, \ + MSG_W_CB, \ + (content, mf_ultralight_write_page_resp, content.mf_ultralight_write_page_resp), \ + 14) \ + X(a, \ + STATIC, \ + ONEOF, \ + MSG_W_CB, \ + (content, mf_ultralight_read_signature_req, content.mf_ultralight_read_signature_req), \ + 15) \ + X(a, \ + STATIC, \ + ONEOF, \ + MSG_W_CB, \ + (content, mf_ultralight_read_signature_resp, content.mf_ultralight_read_signature_resp), \ + 16) \ + X(a, \ + STATIC, \ + ONEOF, \ + MSG_W_CB, \ + (content, mf_ultralight_read_counter_req, content.mf_ultralight_read_counter_req), \ + 17) \ + X(a, \ + STATIC, \ + ONEOF, \ + MSG_W_CB, \ + (content, mf_ultralight_read_counter_resp, content.mf_ultralight_read_counter_resp), \ + 18) \ + X(a, \ + STATIC, \ + ONEOF, \ + MSG_W_CB, \ + (content, mf_ultralight_read_tearing_flag_req, content.mf_ultralight_read_tearing_flag_req), \ + 19) \ + X(a, \ + STATIC, \ + ONEOF, \ + MSG_W_CB, \ + (content, \ + mf_ultralight_read_tearing_flag_resp, \ + content.mf_ultralight_read_tearing_flag_resp), \ + 20) \ + X(a, \ + STATIC, \ + ONEOF, \ + MSG_W_CB, \ + (content, mf_ultralight_emulate_start_req, content.mf_ultralight_emulate_start_req), \ + 21) \ + X(a, \ + STATIC, \ + ONEOF, \ + MSG_W_CB, \ + (content, mf_ultralight_emulate_start_resp, content.mf_ultralight_emulate_start_resp), \ + 22) \ + X(a, \ + STATIC, \ + ONEOF, \ + MSG_W_CB, \ + (content, mf_ultralight_emulate_stop_req, content.mf_ultralight_emulate_stop_req), \ + 23) \ + X(a, \ + STATIC, \ + ONEOF, \ + MSG_W_CB, \ + (content, mf_ultralight_emulate_stop_resp, content.mf_ultralight_emulate_stop_resp), \ + 24) \ + X(a, STATIC, ONEOF, MSG_W_CB, (content, mf_classic_auth_req, content.mf_classic_auth_req), 25) \ + X(a, \ + STATIC, \ + ONEOF, \ + MSG_W_CB, \ + (content, mf_classic_auth_resp, content.mf_classic_auth_resp), \ + 26) \ + X(a, \ + STATIC, \ + ONEOF, \ + MSG_W_CB, \ + (content, mf_classic_read_block_req, content.mf_classic_read_block_req), \ + 27) \ + X(a, \ + STATIC, \ + ONEOF, \ + MSG_W_CB, \ + (content, mf_classic_read_block_resp, content.mf_classic_read_block_resp), \ + 28) #define Nfc_Main_CALLBACK NULL #define Nfc_Main_DEFAULT NULL #define Nfc_Main_content_empty_MSGTYPE Nfc_Empty @@ -158,19 +285,28 @@ X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_classic_read_block_resp,content.m #define Nfc_Main_content_mf_ultralight_read_page_req_MSGTYPE PB_MfUltralight_ReadPageRequest #define Nfc_Main_content_mf_ultralight_read_page_resp_MSGTYPE PB_MfUltralight_ReadPageResponse #define Nfc_Main_content_mf_ultralight_read_version_req_MSGTYPE PB_MfUltralight_ReadVersionRequest -#define Nfc_Main_content_mf_ultralight_read_version_resp_MSGTYPE PB_MfUltralight_ReadVersionResponse +#define Nfc_Main_content_mf_ultralight_read_version_resp_MSGTYPE \ + PB_MfUltralight_ReadVersionResponse #define Nfc_Main_content_mf_ultralight_write_page_req_MSGTYPE PB_MfUltralight_WritePageRequest #define Nfc_Main_content_mf_ultralight_write_page_resp_MSGTYPE PB_MfUltralight_WritePageResponse -#define Nfc_Main_content_mf_ultralight_read_signature_req_MSGTYPE PB_MfUltralight_ReadSignatureRequest -#define Nfc_Main_content_mf_ultralight_read_signature_resp_MSGTYPE PB_MfUltralight_ReadSignatureResponse +#define Nfc_Main_content_mf_ultralight_read_signature_req_MSGTYPE \ + PB_MfUltralight_ReadSignatureRequest +#define Nfc_Main_content_mf_ultralight_read_signature_resp_MSGTYPE \ + PB_MfUltralight_ReadSignatureResponse #define Nfc_Main_content_mf_ultralight_read_counter_req_MSGTYPE PB_MfUltralight_ReadCounterRequest -#define Nfc_Main_content_mf_ultralight_read_counter_resp_MSGTYPE PB_MfUltralight_ReadCounterResponse -#define Nfc_Main_content_mf_ultralight_read_tearing_flag_req_MSGTYPE PB_MfUltralight_ReadTearingFlagRequest -#define Nfc_Main_content_mf_ultralight_read_tearing_flag_resp_MSGTYPE PB_MfUltralight_ReadTearingFlagResponse -#define Nfc_Main_content_mf_ultralight_emulate_start_req_MSGTYPE PB_MfUltralight_EmulateStartRequest -#define Nfc_Main_content_mf_ultralight_emulate_start_resp_MSGTYPE PB_MfUltralight_EmulateStartResponse +#define Nfc_Main_content_mf_ultralight_read_counter_resp_MSGTYPE \ + PB_MfUltralight_ReadCounterResponse +#define Nfc_Main_content_mf_ultralight_read_tearing_flag_req_MSGTYPE \ + PB_MfUltralight_ReadTearingFlagRequest +#define Nfc_Main_content_mf_ultralight_read_tearing_flag_resp_MSGTYPE \ + PB_MfUltralight_ReadTearingFlagResponse +#define Nfc_Main_content_mf_ultralight_emulate_start_req_MSGTYPE \ + PB_MfUltralight_EmulateStartRequest +#define Nfc_Main_content_mf_ultralight_emulate_start_resp_MSGTYPE \ + PB_MfUltralight_EmulateStartResponse #define Nfc_Main_content_mf_ultralight_emulate_stop_req_MSGTYPE PB_MfUltralight_EmulateStopRequest -#define Nfc_Main_content_mf_ultralight_emulate_stop_resp_MSGTYPE PB_MfUltralight_EmulateStopResponse +#define Nfc_Main_content_mf_ultralight_emulate_stop_resp_MSGTYPE \ + PB_MfUltralight_EmulateStopResponse #define Nfc_Main_content_mf_classic_auth_req_MSGTYPE PB_MfClassic_AuthRequest #define Nfc_Main_content_mf_classic_auth_resp_MSGTYPE PB_MfClassic_AuthResponse #define Nfc_Main_content_mf_classic_read_block_req_MSGTYPE PB_MfClassic_ReadBlockRequest @@ -184,8 +320,8 @@ extern const pb_msgdesc_t Nfc_Main_msg; #define Nfc_Main_fields &Nfc_Main_msg /* Maximum encoded size of messages (where known) */ -#define Nfc_Empty_size 0 -#define Nfc_Main_size 2057 +#define Nfc_Empty_size 0 +#define Nfc_Main_size 2057 #ifdef __cplusplus } /* extern "C" */ diff --git a/applications/main/nfc_rpc/assets/compiled/mf_classic.pb.c b/applications/main/nfc_rpc/assets/compiled/mf_classic.pb.c index 114429ee891e..eb96ffe1657e 100644 --- a/applications/main/nfc_rpc/assets/compiled/mf_classic.pb.c +++ b/applications/main/nfc_rpc/assets/compiled/mf_classic.pb.c @@ -8,16 +8,8 @@ PB_BIND(PB_MfClassic_AuthRequest, PB_MfClassic_AuthRequest, AUTO) - PB_BIND(PB_MfClassic_AuthResponse, PB_MfClassic_AuthResponse, AUTO) - PB_BIND(PB_MfClassic_ReadBlockRequest, PB_MfClassic_ReadBlockRequest, AUTO) - PB_BIND(PB_MfClassic_ReadBlockResponse, PB_MfClassic_ReadBlockResponse, AUTO) - - - - - diff --git a/applications/main/nfc_rpc/assets/compiled/mf_classic.pb.h b/applications/main/nfc_rpc/assets/compiled/mf_classic.pb.h index 3d9c2d6da27b..dbc649cb0aa7 100644 --- a/applications/main/nfc_rpc/assets/compiled/mf_classic.pb.h +++ b/applications/main/nfc_rpc/assets/compiled/mf_classic.pb.h @@ -60,7 +60,6 @@ typedef struct _PB_MfClassic_ReadBlockResponse { PB_MfClassic_ReadBlockResponse_data_t data; } PB_MfClassic_ReadBlockResponse; - #ifdef __cplusplus extern "C" { #endif @@ -68,11 +67,11 @@ extern "C" { /* Helper constants for enums */ #define _PB_MfClassic_Error_MIN PB_MfClassic_Error_None #define _PB_MfClassic_Error_MAX PB_MfClassic_Error_Timeout -#define _PB_MfClassic_Error_ARRAYSIZE ((PB_MfClassic_Error)(PB_MfClassic_Error_Timeout+1)) +#define _PB_MfClassic_Error_ARRAYSIZE ((PB_MfClassic_Error)(PB_MfClassic_Error_Timeout + 1)) #define _PB_MfClassic_KeyType_MIN PB_MfClassic_KeyType_KeyTypeA #define _PB_MfClassic_KeyType_MAX PB_MfClassic_KeyType_KeyTypeB -#define _PB_MfClassic_KeyType_ARRAYSIZE ((PB_MfClassic_KeyType)(PB_MfClassic_KeyType_KeyTypeB+1)) +#define _PB_MfClassic_KeyType_ARRAYSIZE ((PB_MfClassic_KeyType)(PB_MfClassic_KeyType_KeyTypeB + 1)) #define PB_MfClassic_AuthRequest_key_type_ENUMTYPE PB_MfClassic_KeyType @@ -83,65 +82,98 @@ extern "C" { #define PB_MfClassic_ReadBlockResponse_error_ENUMTYPE PB_MfClassic_Error - /* Initializer values for message structs */ -#define PB_MfClassic_AuthRequest_init_default {0, {0, {0}}, _PB_MfClassic_KeyType_MIN} -#define PB_MfClassic_AuthResponse_init_default {_PB_MfClassic_Error_MIN, 0, {0, {0}}, _PB_MfClassic_KeyType_MIN, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}} -#define PB_MfClassic_ReadBlockRequest_init_default {0, {0, {0}}, _PB_MfClassic_KeyType_MIN} -#define PB_MfClassic_ReadBlockResponse_init_default {_PB_MfClassic_Error_MIN, {0, {0}}} -#define PB_MfClassic_AuthRequest_init_zero {0, {0, {0}}, _PB_MfClassic_KeyType_MIN} -#define PB_MfClassic_AuthResponse_init_zero {_PB_MfClassic_Error_MIN, 0, {0, {0}}, _PB_MfClassic_KeyType_MIN, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}} -#define PB_MfClassic_ReadBlockRequest_init_zero {0, {0, {0}}, _PB_MfClassic_KeyType_MIN} -#define PB_MfClassic_ReadBlockResponse_init_zero {_PB_MfClassic_Error_MIN, {0, {0}}} +#define PB_MfClassic_AuthRequest_init_default \ + { 0, {0, {0}}, _PB_MfClassic_KeyType_MIN } +#define PB_MfClassic_AuthResponse_init_default \ + { \ + _PB_MfClassic_Error_MIN, 0, {0, {0}}, _PB_MfClassic_KeyType_MIN, {0, {0}}, {0, {0}}, \ + {0, {0}}, { \ + 0, { \ + 0 \ + } \ + } \ + } +#define PB_MfClassic_ReadBlockRequest_init_default \ + { 0, {0, {0}}, _PB_MfClassic_KeyType_MIN } +#define PB_MfClassic_ReadBlockResponse_init_default \ + { \ + _PB_MfClassic_Error_MIN, { \ + 0, { \ + 0 \ + } \ + } \ + } +#define PB_MfClassic_AuthRequest_init_zero \ + { 0, {0, {0}}, _PB_MfClassic_KeyType_MIN } +#define PB_MfClassic_AuthResponse_init_zero \ + { \ + _PB_MfClassic_Error_MIN, 0, {0, {0}}, _PB_MfClassic_KeyType_MIN, {0, {0}}, {0, {0}}, \ + {0, {0}}, { \ + 0, { \ + 0 \ + } \ + } \ + } +#define PB_MfClassic_ReadBlockRequest_init_zero \ + { 0, {0, {0}}, _PB_MfClassic_KeyType_MIN } +#define PB_MfClassic_ReadBlockResponse_init_zero \ + { \ + _PB_MfClassic_Error_MIN, { \ + 0, { \ + 0 \ + } \ + } \ + } /* Field tags (for use in manual encoding/decoding) */ -#define PB_MfClassic_AuthRequest_block_tag 1 -#define PB_MfClassic_AuthRequest_key_tag 2 -#define PB_MfClassic_AuthRequest_key_type_tag 3 -#define PB_MfClassic_AuthResponse_error_tag 1 -#define PB_MfClassic_AuthResponse_block_tag 2 -#define PB_MfClassic_AuthResponse_key_tag 3 -#define PB_MfClassic_AuthResponse_key_type_tag 4 -#define PB_MfClassic_AuthResponse_nt_tag 5 -#define PB_MfClassic_AuthResponse_nr_tag 6 -#define PB_MfClassic_AuthResponse_ar_tag 7 -#define PB_MfClassic_AuthResponse_at_tag 8 -#define PB_MfClassic_ReadBlockRequest_block_tag 1 -#define PB_MfClassic_ReadBlockRequest_key_tag 2 +#define PB_MfClassic_AuthRequest_block_tag 1 +#define PB_MfClassic_AuthRequest_key_tag 2 +#define PB_MfClassic_AuthRequest_key_type_tag 3 +#define PB_MfClassic_AuthResponse_error_tag 1 +#define PB_MfClassic_AuthResponse_block_tag 2 +#define PB_MfClassic_AuthResponse_key_tag 3 +#define PB_MfClassic_AuthResponse_key_type_tag 4 +#define PB_MfClassic_AuthResponse_nt_tag 5 +#define PB_MfClassic_AuthResponse_nr_tag 6 +#define PB_MfClassic_AuthResponse_ar_tag 7 +#define PB_MfClassic_AuthResponse_at_tag 8 +#define PB_MfClassic_ReadBlockRequest_block_tag 1 +#define PB_MfClassic_ReadBlockRequest_key_tag 2 #define PB_MfClassic_ReadBlockRequest_key_type_tag 3 #define PB_MfClassic_ReadBlockResponse_error_tag 1 -#define PB_MfClassic_ReadBlockResponse_data_tag 2 +#define PB_MfClassic_ReadBlockResponse_data_tag 2 /* Struct field encoding specification for nanopb */ #define PB_MfClassic_AuthRequest_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UINT32, block, 1) \ -X(a, STATIC, SINGULAR, BYTES, key, 2) \ -X(a, STATIC, SINGULAR, UENUM, key_type, 3) + X(a, STATIC, SINGULAR, UINT32, block, 1) \ + X(a, STATIC, SINGULAR, BYTES, key, 2) \ + X(a, STATIC, SINGULAR, UENUM, key_type, 3) #define PB_MfClassic_AuthRequest_CALLBACK NULL #define PB_MfClassic_AuthRequest_DEFAULT NULL #define PB_MfClassic_AuthResponse_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UENUM, error, 1) \ -X(a, STATIC, SINGULAR, UINT32, block, 2) \ -X(a, STATIC, SINGULAR, BYTES, key, 3) \ -X(a, STATIC, SINGULAR, UENUM, key_type, 4) \ -X(a, STATIC, SINGULAR, BYTES, nt, 5) \ -X(a, STATIC, SINGULAR, BYTES, nr, 6) \ -X(a, STATIC, SINGULAR, BYTES, ar, 7) \ -X(a, STATIC, SINGULAR, BYTES, at, 8) + X(a, STATIC, SINGULAR, UENUM, error, 1) \ + X(a, STATIC, SINGULAR, UINT32, block, 2) \ + X(a, STATIC, SINGULAR, BYTES, key, 3) \ + X(a, STATIC, SINGULAR, UENUM, key_type, 4) \ + X(a, STATIC, SINGULAR, BYTES, nt, 5) \ + X(a, STATIC, SINGULAR, BYTES, nr, 6) \ + X(a, STATIC, SINGULAR, BYTES, ar, 7) \ + X(a, STATIC, SINGULAR, BYTES, at, 8) #define PB_MfClassic_AuthResponse_CALLBACK NULL #define PB_MfClassic_AuthResponse_DEFAULT NULL #define PB_MfClassic_ReadBlockRequest_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UINT32, block, 1) \ -X(a, STATIC, SINGULAR, BYTES, key, 2) \ -X(a, STATIC, SINGULAR, UENUM, key_type, 3) + X(a, STATIC, SINGULAR, UINT32, block, 1) \ + X(a, STATIC, SINGULAR, BYTES, key, 2) \ + X(a, STATIC, SINGULAR, UENUM, key_type, 3) #define PB_MfClassic_ReadBlockRequest_CALLBACK NULL #define PB_MfClassic_ReadBlockRequest_DEFAULT NULL #define PB_MfClassic_ReadBlockResponse_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UENUM, error, 1) \ -X(a, STATIC, SINGULAR, BYTES, data, 2) + X(a, STATIC, SINGULAR, UENUM, error, 1) \ + X(a, STATIC, SINGULAR, BYTES, data, 2) #define PB_MfClassic_ReadBlockResponse_CALLBACK NULL #define PB_MfClassic_ReadBlockResponse_DEFAULT NULL @@ -157,10 +189,10 @@ extern const pb_msgdesc_t PB_MfClassic_ReadBlockResponse_msg; #define PB_MfClassic_ReadBlockResponse_fields &PB_MfClassic_ReadBlockResponse_msg /* Maximum encoded size of messages (where known) */ -#define PB_MfClassic_AuthRequest_size 13 -#define PB_MfClassic_AuthResponse_size 39 -#define PB_MfClassic_ReadBlockRequest_size 13 -#define PB_MfClassic_ReadBlockResponse_size 20 +#define PB_MfClassic_AuthRequest_size 13 +#define PB_MfClassic_AuthResponse_size 39 +#define PB_MfClassic_ReadBlockRequest_size 13 +#define PB_MfClassic_ReadBlockResponse_size 20 #ifdef __cplusplus } /* extern "C" */ diff --git a/applications/main/nfc_rpc/assets/compiled/mf_ultralight.pb.c b/applications/main/nfc_rpc/assets/compiled/mf_ultralight.pb.c index a16a9020aaf3..d509af5ac47e 100644 --- a/applications/main/nfc_rpc/assets/compiled/mf_ultralight.pb.c +++ b/applications/main/nfc_rpc/assets/compiled/mf_ultralight.pb.c @@ -8,51 +8,32 @@ PB_BIND(PB_MfUltralight_ReadPageRequest, PB_MfUltralight_ReadPageRequest, AUTO) - PB_BIND(PB_MfUltralight_ReadPageResponse, PB_MfUltralight_ReadPageResponse, AUTO) - PB_BIND(PB_MfUltralight_ReadVersionRequest, PB_MfUltralight_ReadVersionRequest, AUTO) - PB_BIND(PB_MfUltralight_ReadVersionResponse, PB_MfUltralight_ReadVersionResponse, AUTO) - PB_BIND(PB_MfUltralight_WritePageRequest, PB_MfUltralight_WritePageRequest, AUTO) - PB_BIND(PB_MfUltralight_WritePageResponse, PB_MfUltralight_WritePageResponse, AUTO) - PB_BIND(PB_MfUltralight_ReadSignatureRequest, PB_MfUltralight_ReadSignatureRequest, AUTO) - PB_BIND(PB_MfUltralight_ReadSignatureResponse, PB_MfUltralight_ReadSignatureResponse, AUTO) - PB_BIND(PB_MfUltralight_ReadCounterRequest, PB_MfUltralight_ReadCounterRequest, AUTO) - PB_BIND(PB_MfUltralight_ReadCounterResponse, PB_MfUltralight_ReadCounterResponse, AUTO) - PB_BIND(PB_MfUltralight_ReadTearingFlagRequest, PB_MfUltralight_ReadTearingFlagRequest, AUTO) - PB_BIND(PB_MfUltralight_ReadTearingFlagResponse, PB_MfUltralight_ReadTearingFlagResponse, AUTO) - PB_BIND(PB_MfUltralight_EmulateStartRequest, PB_MfUltralight_EmulateStartRequest, 2) - PB_BIND(PB_MfUltralight_EmulateStartResponse, PB_MfUltralight_EmulateStartResponse, AUTO) - PB_BIND(PB_MfUltralight_EmulateStopRequest, PB_MfUltralight_EmulateStopRequest, AUTO) - PB_BIND(PB_MfUltralight_EmulateStopResponse, PB_MfUltralight_EmulateStopResponse, AUTO) - - - - diff --git a/applications/main/nfc_rpc/assets/compiled/mf_ultralight.pb.h b/applications/main/nfc_rpc/assets/compiled/mf_ultralight.pb.h index 087ff3819553..0754b98a5aa9 100644 --- a/applications/main/nfc_rpc/assets/compiled/mf_ultralight.pb.h +++ b/applications/main/nfc_rpc/assets/compiled/mf_ultralight.pb.h @@ -106,7 +106,6 @@ typedef struct _PB_MfUltralight_EmulateStopResponse { PB_MfUltralight_Error error; } PB_MfUltralight_EmulateStopResponse; - #ifdef __cplusplus extern "C" { #endif @@ -114,66 +113,162 @@ extern "C" { /* Helper constants for enums */ #define _PB_MfUltralight_Error_MIN PB_MfUltralight_Error_None #define _PB_MfUltralight_Error_MAX PB_MfUltralight_Error_Timeout -#define _PB_MfUltralight_Error_ARRAYSIZE ((PB_MfUltralight_Error)(PB_MfUltralight_Error_Timeout+1)) - +#define _PB_MfUltralight_Error_ARRAYSIZE \ + ((PB_MfUltralight_Error)(PB_MfUltralight_Error_Timeout + 1)) #define PB_MfUltralight_ReadPageResponse_error_ENUMTYPE PB_MfUltralight_Error - #define PB_MfUltralight_ReadVersionResponse_error_ENUMTYPE PB_MfUltralight_Error - #define PB_MfUltralight_WritePageResponse_error_ENUMTYPE PB_MfUltralight_Error - #define PB_MfUltralight_ReadSignatureResponse_error_ENUMTYPE PB_MfUltralight_Error - #define PB_MfUltralight_ReadCounterResponse_error_ENUMTYPE PB_MfUltralight_Error - #define PB_MfUltralight_ReadTearingFlagResponse_error_ENUMTYPE PB_MfUltralight_Error - #define PB_MfUltralight_EmulateStartResponse_error_ENUMTYPE PB_MfUltralight_Error - #define PB_MfUltralight_EmulateStopResponse_error_ENUMTYPE PB_MfUltralight_Error - /* Initializer values for message structs */ -#define PB_MfUltralight_ReadPageRequest_init_default {0} -#define PB_MfUltralight_ReadPageResponse_init_default {_PB_MfUltralight_Error_MIN, 0, {0, {0}}} -#define PB_MfUltralight_ReadVersionRequest_init_default {0} -#define PB_MfUltralight_ReadVersionResponse_init_default {_PB_MfUltralight_Error_MIN, 0, 0, 0, 0, 0, 0, 0, 0} -#define PB_MfUltralight_WritePageRequest_init_default {0, {0, {0}}} -#define PB_MfUltralight_WritePageResponse_init_default {_PB_MfUltralight_Error_MIN, 0} -#define PB_MfUltralight_ReadSignatureRequest_init_default {0} -#define PB_MfUltralight_ReadSignatureResponse_init_default {_PB_MfUltralight_Error_MIN, {0, {0}}} -#define PB_MfUltralight_ReadCounterRequest_init_default {0} -#define PB_MfUltralight_ReadCounterResponse_init_default {_PB_MfUltralight_Error_MIN, 0, {0, {0}}} -#define PB_MfUltralight_ReadTearingFlagRequest_init_default {0} -#define PB_MfUltralight_ReadTearingFlagResponse_init_default {_PB_MfUltralight_Error_MIN, 0, {0, {0}}} -#define PB_MfUltralight_EmulateStartRequest_init_default {{0, {0}}} -#define PB_MfUltralight_EmulateStartResponse_init_default {_PB_MfUltralight_Error_MIN} -#define PB_MfUltralight_EmulateStopRequest_init_default {0} -#define PB_MfUltralight_EmulateStopResponse_init_default {_PB_MfUltralight_Error_MIN} -#define PB_MfUltralight_ReadPageRequest_init_zero {0} -#define PB_MfUltralight_ReadPageResponse_init_zero {_PB_MfUltralight_Error_MIN, 0, {0, {0}}} -#define PB_MfUltralight_ReadVersionRequest_init_zero {0} -#define PB_MfUltralight_ReadVersionResponse_init_zero {_PB_MfUltralight_Error_MIN, 0, 0, 0, 0, 0, 0, 0, 0} -#define PB_MfUltralight_WritePageRequest_init_zero {0, {0, {0}}} -#define PB_MfUltralight_WritePageResponse_init_zero {_PB_MfUltralight_Error_MIN, 0} -#define PB_MfUltralight_ReadSignatureRequest_init_zero {0} -#define PB_MfUltralight_ReadSignatureResponse_init_zero {_PB_MfUltralight_Error_MIN, {0, {0}}} -#define PB_MfUltralight_ReadCounterRequest_init_zero {0} -#define PB_MfUltralight_ReadCounterResponse_init_zero {_PB_MfUltralight_Error_MIN, 0, {0, {0}}} -#define PB_MfUltralight_ReadTearingFlagRequest_init_zero {0} -#define PB_MfUltralight_ReadTearingFlagResponse_init_zero {_PB_MfUltralight_Error_MIN, 0, {0, {0}}} -#define PB_MfUltralight_EmulateStartRequest_init_zero {{0, {0}}} -#define PB_MfUltralight_EmulateStartResponse_init_zero {_PB_MfUltralight_Error_MIN} -#define PB_MfUltralight_EmulateStopRequest_init_zero {0} -#define PB_MfUltralight_EmulateStopResponse_init_zero {_PB_MfUltralight_Error_MIN} +#define PB_MfUltralight_ReadPageRequest_init_default \ + { 0 } +#define PB_MfUltralight_ReadPageResponse_init_default \ + { \ + _PB_MfUltralight_Error_MIN, 0, { \ + 0, { \ + 0 \ + } \ + } \ + } +#define PB_MfUltralight_ReadVersionRequest_init_default \ + { 0 } +#define PB_MfUltralight_ReadVersionResponse_init_default \ + { _PB_MfUltralight_Error_MIN, 0, 0, 0, 0, 0, 0, 0, 0 } +#define PB_MfUltralight_WritePageRequest_init_default \ + { \ + 0, { \ + 0, { \ + 0 \ + } \ + } \ + } +#define PB_MfUltralight_WritePageResponse_init_default \ + { _PB_MfUltralight_Error_MIN, 0 } +#define PB_MfUltralight_ReadSignatureRequest_init_default \ + { 0 } +#define PB_MfUltralight_ReadSignatureResponse_init_default \ + { \ + _PB_MfUltralight_Error_MIN, { \ + 0, { \ + 0 \ + } \ + } \ + } +#define PB_MfUltralight_ReadCounterRequest_init_default \ + { 0 } +#define PB_MfUltralight_ReadCounterResponse_init_default \ + { \ + _PB_MfUltralight_Error_MIN, 0, { \ + 0, { \ + 0 \ + } \ + } \ + } +#define PB_MfUltralight_ReadTearingFlagRequest_init_default \ + { 0 } +#define PB_MfUltralight_ReadTearingFlagResponse_init_default \ + { \ + _PB_MfUltralight_Error_MIN, 0, { \ + 0, { \ + 0 \ + } \ + } \ + } +#define PB_MfUltralight_EmulateStartRequest_init_default \ + { \ + { \ + 0, { \ + 0 \ + } \ + } \ + } +#define PB_MfUltralight_EmulateStartResponse_init_default \ + { _PB_MfUltralight_Error_MIN } +#define PB_MfUltralight_EmulateStopRequest_init_default \ + { 0 } +#define PB_MfUltralight_EmulateStopResponse_init_default \ + { _PB_MfUltralight_Error_MIN } +#define PB_MfUltralight_ReadPageRequest_init_zero \ + { 0 } +#define PB_MfUltralight_ReadPageResponse_init_zero \ + { \ + _PB_MfUltralight_Error_MIN, 0, { \ + 0, { \ + 0 \ + } \ + } \ + } +#define PB_MfUltralight_ReadVersionRequest_init_zero \ + { 0 } +#define PB_MfUltralight_ReadVersionResponse_init_zero \ + { _PB_MfUltralight_Error_MIN, 0, 0, 0, 0, 0, 0, 0, 0 } +#define PB_MfUltralight_WritePageRequest_init_zero \ + { \ + 0, { \ + 0, { \ + 0 \ + } \ + } \ + } +#define PB_MfUltralight_WritePageResponse_init_zero \ + { _PB_MfUltralight_Error_MIN, 0 } +#define PB_MfUltralight_ReadSignatureRequest_init_zero \ + { 0 } +#define PB_MfUltralight_ReadSignatureResponse_init_zero \ + { \ + _PB_MfUltralight_Error_MIN, { \ + 0, { \ + 0 \ + } \ + } \ + } +#define PB_MfUltralight_ReadCounterRequest_init_zero \ + { 0 } +#define PB_MfUltralight_ReadCounterResponse_init_zero \ + { \ + _PB_MfUltralight_Error_MIN, 0, { \ + 0, { \ + 0 \ + } \ + } \ + } +#define PB_MfUltralight_ReadTearingFlagRequest_init_zero \ + { 0 } +#define PB_MfUltralight_ReadTearingFlagResponse_init_zero \ + { \ + _PB_MfUltralight_Error_MIN, 0, { \ + 0, { \ + 0 \ + } \ + } \ + } +#define PB_MfUltralight_EmulateStartRequest_init_zero \ + { \ + { \ + 0, { \ + 0 \ + } \ + } \ + } +#define PB_MfUltralight_EmulateStartResponse_init_zero \ + { _PB_MfUltralight_Error_MIN } +#define PB_MfUltralight_EmulateStopRequest_init_zero \ + { 0 } +#define PB_MfUltralight_EmulateStopResponse_init_zero \ + { _PB_MfUltralight_Error_MIN } /* Field tags (for use in manual encoding/decoding) */ #define PB_MfUltralight_ReadPageRequest_page_tag 1 @@ -208,100 +303,97 @@ extern "C" { #define PB_MfUltralight_EmulateStopResponse_error_tag 1 /* Struct field encoding specification for nanopb */ -#define PB_MfUltralight_ReadPageRequest_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UINT32, page, 1) +#define PB_MfUltralight_ReadPageRequest_FIELDLIST(X, a) X(a, STATIC, SINGULAR, UINT32, page, 1) #define PB_MfUltralight_ReadPageRequest_CALLBACK NULL #define PB_MfUltralight_ReadPageRequest_DEFAULT NULL #define PB_MfUltralight_ReadPageResponse_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UENUM, error, 1) \ -X(a, STATIC, SINGULAR, UINT32, page, 2) \ -X(a, STATIC, SINGULAR, BYTES, data, 3) + X(a, STATIC, SINGULAR, UENUM, error, 1) \ + X(a, STATIC, SINGULAR, UINT32, page, 2) \ + X(a, STATIC, SINGULAR, BYTES, data, 3) #define PB_MfUltralight_ReadPageResponse_CALLBACK NULL #define PB_MfUltralight_ReadPageResponse_DEFAULT NULL -#define PB_MfUltralight_ReadVersionRequest_FIELDLIST(X, a) \ +#define PB_MfUltralight_ReadVersionRequest_FIELDLIST(X, a) #define PB_MfUltralight_ReadVersionRequest_CALLBACK NULL #define PB_MfUltralight_ReadVersionRequest_DEFAULT NULL #define PB_MfUltralight_ReadVersionResponse_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UENUM, error, 1) \ -X(a, STATIC, SINGULAR, UINT32, header, 2) \ -X(a, STATIC, SINGULAR, UINT32, vendor_id, 3) \ -X(a, STATIC, SINGULAR, UINT32, prod_type, 4) \ -X(a, STATIC, SINGULAR, UINT32, prod_subtype, 5) \ -X(a, STATIC, SINGULAR, UINT32, prod_ver_major, 6) \ -X(a, STATIC, SINGULAR, UINT32, prod_ver_minor, 7) \ -X(a, STATIC, SINGULAR, UINT32, storage_size, 8) \ -X(a, STATIC, SINGULAR, UINT32, protocol_type, 9) + X(a, STATIC, SINGULAR, UENUM, error, 1) \ + X(a, STATIC, SINGULAR, UINT32, header, 2) \ + X(a, STATIC, SINGULAR, UINT32, vendor_id, 3) \ + X(a, STATIC, SINGULAR, UINT32, prod_type, 4) \ + X(a, STATIC, SINGULAR, UINT32, prod_subtype, 5) \ + X(a, STATIC, SINGULAR, UINT32, prod_ver_major, 6) \ + X(a, STATIC, SINGULAR, UINT32, prod_ver_minor, 7) \ + X(a, STATIC, SINGULAR, UINT32, storage_size, 8) \ + X(a, STATIC, SINGULAR, UINT32, protocol_type, 9) #define PB_MfUltralight_ReadVersionResponse_CALLBACK NULL #define PB_MfUltralight_ReadVersionResponse_DEFAULT NULL #define PB_MfUltralight_WritePageRequest_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UINT32, page, 1) \ -X(a, STATIC, SINGULAR, BYTES, data, 2) + X(a, STATIC, SINGULAR, UINT32, page, 1) \ + X(a, STATIC, SINGULAR, BYTES, data, 2) #define PB_MfUltralight_WritePageRequest_CALLBACK NULL #define PB_MfUltralight_WritePageRequest_DEFAULT NULL #define PB_MfUltralight_WritePageResponse_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UENUM, error, 1) \ -X(a, STATIC, SINGULAR, BOOL, result, 2) + X(a, STATIC, SINGULAR, UENUM, error, 1) \ + X(a, STATIC, SINGULAR, BOOL, result, 2) #define PB_MfUltralight_WritePageResponse_CALLBACK NULL #define PB_MfUltralight_WritePageResponse_DEFAULT NULL -#define PB_MfUltralight_ReadSignatureRequest_FIELDLIST(X, a) \ +#define PB_MfUltralight_ReadSignatureRequest_FIELDLIST(X, a) #define PB_MfUltralight_ReadSignatureRequest_CALLBACK NULL #define PB_MfUltralight_ReadSignatureRequest_DEFAULT NULL #define PB_MfUltralight_ReadSignatureResponse_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UENUM, error, 1) \ -X(a, STATIC, SINGULAR, BYTES, data, 2) + X(a, STATIC, SINGULAR, UENUM, error, 1) \ + X(a, STATIC, SINGULAR, BYTES, data, 2) #define PB_MfUltralight_ReadSignatureResponse_CALLBACK NULL #define PB_MfUltralight_ReadSignatureResponse_DEFAULT NULL #define PB_MfUltralight_ReadCounterRequest_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UINT32, counter_num, 1) + X(a, STATIC, SINGULAR, UINT32, counter_num, 1) #define PB_MfUltralight_ReadCounterRequest_CALLBACK NULL #define PB_MfUltralight_ReadCounterRequest_DEFAULT NULL #define PB_MfUltralight_ReadCounterResponse_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UENUM, error, 1) \ -X(a, STATIC, SINGULAR, UINT32, counter_num, 2) \ -X(a, STATIC, SINGULAR, BYTES, data, 3) + X(a, STATIC, SINGULAR, UENUM, error, 1) \ + X(a, STATIC, SINGULAR, UINT32, counter_num, 2) \ + X(a, STATIC, SINGULAR, BYTES, data, 3) #define PB_MfUltralight_ReadCounterResponse_CALLBACK NULL #define PB_MfUltralight_ReadCounterResponse_DEFAULT NULL #define PB_MfUltralight_ReadTearingFlagRequest_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UINT32, flag_num, 1) + X(a, STATIC, SINGULAR, UINT32, flag_num, 1) #define PB_MfUltralight_ReadTearingFlagRequest_CALLBACK NULL #define PB_MfUltralight_ReadTearingFlagRequest_DEFAULT NULL #define PB_MfUltralight_ReadTearingFlagResponse_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UENUM, error, 1) \ -X(a, STATIC, SINGULAR, UINT32, flag_num, 2) \ -X(a, STATIC, SINGULAR, BYTES, data, 3) + X(a, STATIC, SINGULAR, UENUM, error, 1) \ + X(a, STATIC, SINGULAR, UINT32, flag_num, 2) \ + X(a, STATIC, SINGULAR, BYTES, data, 3) #define PB_MfUltralight_ReadTearingFlagResponse_CALLBACK NULL #define PB_MfUltralight_ReadTearingFlagResponse_DEFAULT NULL -#define PB_MfUltralight_EmulateStartRequest_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, BYTES, data, 1) +#define PB_MfUltralight_EmulateStartRequest_FIELDLIST(X, a) X(a, STATIC, SINGULAR, BYTES, data, 1) #define PB_MfUltralight_EmulateStartRequest_CALLBACK NULL #define PB_MfUltralight_EmulateStartRequest_DEFAULT NULL #define PB_MfUltralight_EmulateStartResponse_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UENUM, error, 1) + X(a, STATIC, SINGULAR, UENUM, error, 1) #define PB_MfUltralight_EmulateStartResponse_CALLBACK NULL #define PB_MfUltralight_EmulateStartResponse_DEFAULT NULL -#define PB_MfUltralight_EmulateStopRequest_FIELDLIST(X, a) \ +#define PB_MfUltralight_EmulateStopRequest_FIELDLIST(X, a) #define PB_MfUltralight_EmulateStopRequest_CALLBACK NULL #define PB_MfUltralight_EmulateStopRequest_DEFAULT NULL -#define PB_MfUltralight_EmulateStopResponse_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UENUM, error, 1) +#define PB_MfUltralight_EmulateStopResponse_FIELDLIST(X, a) X(a, STATIC, SINGULAR, UENUM, error, 1) #define PB_MfUltralight_EmulateStopResponse_CALLBACK NULL #define PB_MfUltralight_EmulateStopResponse_DEFAULT NULL @@ -343,20 +435,20 @@ extern const pb_msgdesc_t PB_MfUltralight_EmulateStopResponse_msg; /* Maximum encoded size of messages (where known) */ #define PB_MfUltralight_EmulateStartRequest_size 2051 #define PB_MfUltralight_EmulateStartResponse_size 2 -#define PB_MfUltralight_EmulateStopRequest_size 0 +#define PB_MfUltralight_EmulateStopRequest_size 0 #define PB_MfUltralight_EmulateStopResponse_size 2 -#define PB_MfUltralight_ReadCounterRequest_size 6 +#define PB_MfUltralight_ReadCounterRequest_size 6 #define PB_MfUltralight_ReadCounterResponse_size 13 -#define PB_MfUltralight_ReadPageRequest_size 4 -#define PB_MfUltralight_ReadPageResponse_size 12 +#define PB_MfUltralight_ReadPageRequest_size 4 +#define PB_MfUltralight_ReadPageResponse_size 12 #define PB_MfUltralight_ReadSignatureRequest_size 0 #define PB_MfUltralight_ReadSignatureResponse_size 36 #define PB_MfUltralight_ReadTearingFlagRequest_size 6 #define PB_MfUltralight_ReadTearingFlagResponse_size 11 -#define PB_MfUltralight_ReadVersionRequest_size 0 +#define PB_MfUltralight_ReadVersionRequest_size 0 #define PB_MfUltralight_ReadVersionResponse_size 50 -#define PB_MfUltralight_WritePageRequest_size 10 -#define PB_MfUltralight_WritePageResponse_size 4 +#define PB_MfUltralight_WritePageRequest_size 10 +#define PB_MfUltralight_WritePageResponse_size 4 #ifdef __cplusplus } /* extern "C" */ diff --git a/applications/main/nfc_rpc/assets/compiled/nfca.pb.c b/applications/main/nfc_rpc/assets/compiled/nfca.pb.c index 44e2f02579da..e7b784a5c25a 100644 --- a/applications/main/nfc_rpc/assets/compiled/nfca.pb.c +++ b/applications/main/nfc_rpc/assets/compiled/nfca.pb.c @@ -8,21 +8,12 @@ PB_BIND(PB_Nfca_ReadRequest, PB_Nfca_ReadRequest, AUTO) - PB_BIND(PB_Nfca_ReadResponse, PB_Nfca_ReadResponse, AUTO) - PB_BIND(PB_Nfca_EmulateStartRequest, PB_Nfca_EmulateStartRequest, AUTO) - PB_BIND(PB_Nfca_EmulateStartResponse, PB_Nfca_EmulateStartResponse, AUTO) - PB_BIND(PB_Nfca_EmulateStopRequest, PB_Nfca_EmulateStopRequest, AUTO) - PB_BIND(PB_Nfca_EmulateStopResponse, PB_Nfca_EmulateStopResponse, AUTO) - - - - diff --git a/applications/main/nfc_rpc/assets/compiled/nfca.pb.h b/applications/main/nfc_rpc/assets/compiled/nfca.pb.h index df751cbd0c92..349dab811cbe 100644 --- a/applications/main/nfc_rpc/assets/compiled/nfca.pb.h +++ b/applications/main/nfc_rpc/assets/compiled/nfca.pb.h @@ -59,7 +59,6 @@ typedef struct _PB_Nfca_EmulateStopResponse { PB_Nfca_Error error; } PB_Nfca_EmulateStopResponse; - #ifdef __cplusplus extern "C" { #endif @@ -67,80 +66,110 @@ extern "C" { /* Helper constants for enums */ #define _PB_Nfca_Error_MIN PB_Nfca_Error_None #define _PB_Nfca_Error_MAX PB_Nfca_Error_Timeout -#define _PB_Nfca_Error_ARRAYSIZE ((PB_Nfca_Error)(PB_Nfca_Error_Timeout+1)) - +#define _PB_Nfca_Error_ARRAYSIZE ((PB_Nfca_Error)(PB_Nfca_Error_Timeout + 1)) #define PB_Nfca_ReadResponse_error_ENUMTYPE PB_Nfca_Error - #define PB_Nfca_EmulateStartResponse_error_ENUMTYPE PB_Nfca_Error - #define PB_Nfca_EmulateStopResponse_error_ENUMTYPE PB_Nfca_Error - /* Initializer values for message structs */ -#define PB_Nfca_ReadRequest_init_default {0} -#define PB_Nfca_ReadResponse_init_default {_PB_Nfca_Error_MIN, 0, {0, {0}}, {0, {0}}, {0, {0}}} -#define PB_Nfca_EmulateStartRequest_init_default {0, {0, {0}}, {0, {0}}, {0, {0}}} -#define PB_Nfca_EmulateStartResponse_init_default {_PB_Nfca_Error_MIN} -#define PB_Nfca_EmulateStopRequest_init_default {0} -#define PB_Nfca_EmulateStopResponse_init_default {_PB_Nfca_Error_MIN} -#define PB_Nfca_ReadRequest_init_zero {0} -#define PB_Nfca_ReadResponse_init_zero {_PB_Nfca_Error_MIN, 0, {0, {0}}, {0, {0}}, {0, {0}}} -#define PB_Nfca_EmulateStartRequest_init_zero {0, {0, {0}}, {0, {0}}, {0, {0}}} -#define PB_Nfca_EmulateStartResponse_init_zero {_PB_Nfca_Error_MIN} -#define PB_Nfca_EmulateStopRequest_init_zero {0} -#define PB_Nfca_EmulateStopResponse_init_zero {_PB_Nfca_Error_MIN} +#define PB_Nfca_ReadRequest_init_default \ + { 0 } +#define PB_Nfca_ReadResponse_init_default \ + { \ + _PB_Nfca_Error_MIN, 0, {0, {0}}, {0, {0}}, { \ + 0, { \ + 0 \ + } \ + } \ + } +#define PB_Nfca_EmulateStartRequest_init_default \ + { \ + 0, {0, {0}}, {0, {0}}, { \ + 0, { \ + 0 \ + } \ + } \ + } +#define PB_Nfca_EmulateStartResponse_init_default \ + { _PB_Nfca_Error_MIN } +#define PB_Nfca_EmulateStopRequest_init_default \ + { 0 } +#define PB_Nfca_EmulateStopResponse_init_default \ + { _PB_Nfca_Error_MIN } +#define PB_Nfca_ReadRequest_init_zero \ + { 0 } +#define PB_Nfca_ReadResponse_init_zero \ + { \ + _PB_Nfca_Error_MIN, 0, {0, {0}}, {0, {0}}, { \ + 0, { \ + 0 \ + } \ + } \ + } +#define PB_Nfca_EmulateStartRequest_init_zero \ + { \ + 0, {0, {0}}, {0, {0}}, { \ + 0, { \ + 0 \ + } \ + } \ + } +#define PB_Nfca_EmulateStartResponse_init_zero \ + { _PB_Nfca_Error_MIN } +#define PB_Nfca_EmulateStopRequest_init_zero \ + { 0 } +#define PB_Nfca_EmulateStopResponse_init_zero \ + { _PB_Nfca_Error_MIN } /* Field tags (for use in manual encoding/decoding) */ -#define PB_Nfca_ReadResponse_error_tag 1 -#define PB_Nfca_ReadResponse_uid_len_tag 2 -#define PB_Nfca_ReadResponse_uid_tag 3 -#define PB_Nfca_ReadResponse_sak_tag 4 -#define PB_Nfca_ReadResponse_atqa_tag 5 -#define PB_Nfca_EmulateStartRequest_uid_len_tag 1 -#define PB_Nfca_EmulateStartRequest_uid_tag 2 -#define PB_Nfca_EmulateStartRequest_sak_tag 3 -#define PB_Nfca_EmulateStartRequest_atqa_tag 4 -#define PB_Nfca_EmulateStartResponse_error_tag 1 -#define PB_Nfca_EmulateStopResponse_error_tag 1 +#define PB_Nfca_ReadResponse_error_tag 1 +#define PB_Nfca_ReadResponse_uid_len_tag 2 +#define PB_Nfca_ReadResponse_uid_tag 3 +#define PB_Nfca_ReadResponse_sak_tag 4 +#define PB_Nfca_ReadResponse_atqa_tag 5 +#define PB_Nfca_EmulateStartRequest_uid_len_tag 1 +#define PB_Nfca_EmulateStartRequest_uid_tag 2 +#define PB_Nfca_EmulateStartRequest_sak_tag 3 +#define PB_Nfca_EmulateStartRequest_atqa_tag 4 +#define PB_Nfca_EmulateStartResponse_error_tag 1 +#define PB_Nfca_EmulateStopResponse_error_tag 1 /* Struct field encoding specification for nanopb */ -#define PB_Nfca_ReadRequest_FIELDLIST(X, a) \ +#define PB_Nfca_ReadRequest_FIELDLIST(X, a) #define PB_Nfca_ReadRequest_CALLBACK NULL #define PB_Nfca_ReadRequest_DEFAULT NULL -#define PB_Nfca_ReadResponse_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UENUM, error, 1) \ -X(a, STATIC, SINGULAR, UINT32, uid_len, 2) \ -X(a, STATIC, SINGULAR, BYTES, uid, 3) \ -X(a, STATIC, SINGULAR, BYTES, sak, 4) \ -X(a, STATIC, SINGULAR, BYTES, atqa, 5) +#define PB_Nfca_ReadResponse_FIELDLIST(X, a) \ + X(a, STATIC, SINGULAR, UENUM, error, 1) \ + X(a, STATIC, SINGULAR, UINT32, uid_len, 2) \ + X(a, STATIC, SINGULAR, BYTES, uid, 3) \ + X(a, STATIC, SINGULAR, BYTES, sak, 4) \ + X(a, STATIC, SINGULAR, BYTES, atqa, 5) #define PB_Nfca_ReadResponse_CALLBACK NULL #define PB_Nfca_ReadResponse_DEFAULT NULL #define PB_Nfca_EmulateStartRequest_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UINT32, uid_len, 1) \ -X(a, STATIC, SINGULAR, BYTES, uid, 2) \ -X(a, STATIC, SINGULAR, BYTES, sak, 3) \ -X(a, STATIC, SINGULAR, BYTES, atqa, 4) + X(a, STATIC, SINGULAR, UINT32, uid_len, 1) \ + X(a, STATIC, SINGULAR, BYTES, uid, 2) \ + X(a, STATIC, SINGULAR, BYTES, sak, 3) \ + X(a, STATIC, SINGULAR, BYTES, atqa, 4) #define PB_Nfca_EmulateStartRequest_CALLBACK NULL #define PB_Nfca_EmulateStartRequest_DEFAULT NULL -#define PB_Nfca_EmulateStartResponse_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UENUM, error, 1) +#define PB_Nfca_EmulateStartResponse_FIELDLIST(X, a) X(a, STATIC, SINGULAR, UENUM, error, 1) #define PB_Nfca_EmulateStartResponse_CALLBACK NULL #define PB_Nfca_EmulateStartResponse_DEFAULT NULL -#define PB_Nfca_EmulateStopRequest_FIELDLIST(X, a) \ +#define PB_Nfca_EmulateStopRequest_FIELDLIST(X, a) #define PB_Nfca_EmulateStopRequest_CALLBACK NULL #define PB_Nfca_EmulateStopRequest_DEFAULT NULL -#define PB_Nfca_EmulateStopResponse_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UENUM, error, 1) +#define PB_Nfca_EmulateStopResponse_FIELDLIST(X, a) X(a, STATIC, SINGULAR, UENUM, error, 1) #define PB_Nfca_EmulateStopResponse_CALLBACK NULL #define PB_Nfca_EmulateStopResponse_DEFAULT NULL @@ -160,12 +189,12 @@ extern const pb_msgdesc_t PB_Nfca_EmulateStopResponse_msg; #define PB_Nfca_EmulateStopResponse_fields &PB_Nfca_EmulateStopResponse_msg /* Maximum encoded size of messages (where known) */ -#define PB_Nfca_EmulateStartRequest_size 25 -#define PB_Nfca_EmulateStartResponse_size 2 -#define PB_Nfca_EmulateStopRequest_size 0 -#define PB_Nfca_EmulateStopResponse_size 2 -#define PB_Nfca_ReadRequest_size 0 -#define PB_Nfca_ReadResponse_size 27 +#define PB_Nfca_EmulateStartRequest_size 25 +#define PB_Nfca_EmulateStartResponse_size 2 +#define PB_Nfca_EmulateStopRequest_size 0 +#define PB_Nfca_EmulateStopResponse_size 2 +#define PB_Nfca_ReadRequest_size 0 +#define PB_Nfca_ReadResponse_size 27 #ifdef __cplusplus } /* extern "C" */ diff --git a/applications/main/nfc_rpc/nfc_rpc.c b/applications/main/nfc_rpc/nfc_rpc.c index 1e526b4b57b6..0c455aaf1266 100644 --- a/applications/main/nfc_rpc/nfc_rpc.c +++ b/applications/main/nfc_rpc/nfc_rpc.c @@ -14,8 +14,7 @@ static const NfcRpcCallbacks nfc_rpc_callbacks[] = { { .alloc = nfc_rpc_mf_classic_alloc, .free = NULL, - } -}; + }}; uint32_t nfc_rpc_exit_callback(void* context) { UNUSED(context); diff --git a/lib/nfc/helpers/bit_buffer.c b/lib/nfc/helpers/bit_buffer.c new file mode 100644 index 000000000000..86b8ffb9164b --- /dev/null +++ b/lib/nfc/helpers/bit_buffer.c @@ -0,0 +1,161 @@ +#include "bit_buffer.h" + +#include + +#define BITS_IN_BYTE (8) + +struct BitBuffer { + uint8_t* data; + uint8_t* parity; + size_t capacity_bytes; + size_t size_bits; +}; + +/* TODO: + * - Handle partial bytes + * - Calculate parity + * - Something else? + */ + +BitBuffer* bit_buffer_alloc(size_t capacity_bytes) { + furi_assert(capacity_bytes); + + BitBuffer* buf = malloc(sizeof(BitBuffer)); + + buf->data = malloc(capacity_bytes); + buf->parity = malloc((capacity_bytes + BITS_IN_BYTE - 1) / BITS_IN_BYTE); + buf->capacity_bytes = capacity_bytes; + buf->size_bits = 0; + + return buf; +} + +void bit_buffer_free(BitBuffer* buf) { + furi_assert(buf); + + free(buf->data); + free(buf->parity); + free(buf); +} + +void bit_buffer_reset(BitBuffer* buf) { + furi_assert(buf); + + buf->size_bits = 0; +} + +void bit_buffer_copy(BitBuffer* buf, const BitBuffer* other) { + furi_assert(buf); + furi_assert(other); + furi_assert(buf->capacity_bytes * BITS_IN_BYTE >= other->size_bits); + + memcpy(buf->data, other->data, bit_buffer_get_size_bytes(other)); + buf->size_bits = other->size_bits; +} + +void bit_buffer_copy_right(BitBuffer* buf, const BitBuffer* other, size_t start_index) { + furi_assert(buf); + furi_assert(other); + furi_assert(bit_buffer_get_size_bytes(other) > start_index); + furi_assert(buf->capacity_bytes >= bit_buffer_get_size_bytes(other) - start_index); + + memcpy(buf->data, other->data + start_index, bit_buffer_get_size_bytes(other) - start_index); + buf->size_bits = other->size_bits - start_index * BITS_IN_BYTE; +} + +void bit_buffer_copy_bytes(BitBuffer* buf, const uint8_t* data, size_t size_bytes) { + furi_assert(buf); + furi_assert(buf->capacity_bytes >= size_bytes); + + memcpy(buf->data, data, size_bytes); + buf->size_bits = size_bytes * BITS_IN_BYTE; +} + +void bit_buffer_write_bytes(const BitBuffer* buf, void* dest, size_t size_bytes) { + furi_assert(buf); + furi_assert(dest); + furi_assert(bit_buffer_get_size_bytes(buf) >= size_bytes); + + memcpy(dest, buf->data, size_bytes); +} + +bool bit_buffer_has_partial_byte(const BitBuffer* buf) { + furi_assert(buf); + + return (buf->size_bits % BITS_IN_BYTE) != 0; +} + +bool bit_buffer_starts_with_byte(const BitBuffer* buf, uint8_t byte) { + furi_assert(buf); + + return bit_buffer_get_size_bytes(buf) && (buf->data[0] == byte); +} + +size_t bit_buffer_get_capacity_bytes(const BitBuffer* buf) { + furi_assert(buf); + + return buf->capacity_bytes; +} + +size_t bit_buffer_get_size(const BitBuffer* buf) { + furi_assert(buf); + + return buf->size_bits; +} + +size_t bit_buffer_get_size_bytes(const BitBuffer* buf) { + furi_assert(buf); + + return (buf->size_bits / BITS_IN_BYTE) + (buf->size_bits % BITS_IN_BYTE ? 1 : 0); +} + +uint8_t bit_buffer_get_byte(const BitBuffer* buf, size_t index) { + furi_assert(buf); + furi_assert(buf->capacity_bytes > index); + + return buf->data[index]; +} + +uint8_t* bit_buffer_get_data(const BitBuffer* buf) { + furi_assert(buf); + + return buf->data; +} + +void bit_buffer_set_byte(BitBuffer* buf, size_t index, uint8_t byte) { + furi_assert(buf); + furi_assert(buf->size_bits / BITS_IN_BYTE > index); + + buf->data[index] = byte; +} + +void bit_buffer_append(BitBuffer* buf, const BitBuffer* other) { + bit_buffer_append_right(buf, other, 0); +} + +void bit_buffer_append_right(BitBuffer* buf, const BitBuffer* other, size_t start_index) { + furi_assert(buf); + furi_assert(other); + + const size_t size_bytes = bit_buffer_get_size_bytes(buf); + const size_t other_size_bytes = bit_buffer_get_size_bytes(other) - start_index; + + furi_assert(buf->capacity_bytes >= size_bytes + other_size_bytes); + + memcpy(buf->data + size_bytes, other->data + start_index, other_size_bytes); + buf->size_bits += other->size_bits - start_index * BITS_IN_BYTE; +} + +void bit_buffer_set_size(BitBuffer* buf, size_t new_size) { + furi_assert(buf); + furi_assert(buf->capacity_bytes * BITS_IN_BYTE >= new_size); + + buf->size_bits = new_size; +} + +void bit_buffer_set_size_bytes(BitBuffer* buf, size_t new_size_bytes) { + furi_assert(buf); + furi_assert(buf->capacity_bytes >= new_size_bytes); + + buf->size_bits = new_size_bytes * BITS_IN_BYTE; +} diff --git a/lib/nfc/helpers/bit_buffer.h b/lib/nfc/helpers/bit_buffer.h new file mode 100644 index 000000000000..086df727ecc7 --- /dev/null +++ b/lib/nfc/helpers/bit_buffer.h @@ -0,0 +1,204 @@ +#pragma once + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct BitBuffer BitBuffer; + +// Construction, deletion, reset + +/** + * Allocate a BitBuffer instance. + * + * @param [in] capacity_bytes maximum buffer capacity, in bytes + * @return pointer to the allocated BitBuffer instance + */ +BitBuffer* bit_buffer_alloc(size_t capacity_bytes); + +/** + * Delete a BitBuffer instance. + * + * @param [in,out] buf pointer to a BitBuffer instance + */ +void bit_buffer_free(BitBuffer* buf); + +/** + * Clear all data from a BitBuffer instance. + * + * @param [in,out] buf pointer to a BitBuffer instance + */ +void bit_buffer_reset(BitBuffer* buf); + +// Copy and write + +/** + * Copy another BitBuffer instance's contents to this one, replacing + * all of the original data. + * The destination capacity must be no less than the source data size. + * + * @param [in,out] buf pointer to a BitBuffer instance to copy into + * @param [in] other pointer to a BitBuffer instance to copy from + * @note + */ +void bit_buffer_copy(BitBuffer* buf, const BitBuffer* other); + +/** + * Copy all BitBuffer instance's contents to this one, starting from start_index, + * replacing all of the original data. + * The destination capacity must be no less than the source data size + * counting from start_index. + * + * @param [in,out] buf pointer to a BitBuffer instance to copy into + * @param [in] other pointer to a BitBuffer instance to copy from + * @param [in] start_index index to begin copying source data from + */ +void bit_buffer_copy_right(BitBuffer* buf, const BitBuffer* other, size_t start_index); + +/** + * Copy a byte array to a BitBuffer instance, replacing all of the original data. + * The destination capacity must be no less than the source data size. + * + * @param [in,out] buf pointer to a BitBuffer instance to copy into + * @param [in] data pointer to the byte array to be copied + * @param [in] size_bytes size of the data to be copied, in bytes + */ +void bit_buffer_copy_bytes(BitBuffer* buf, const uint8_t* data, size_t size_bytes); + +/** + * Write a BitBuffer instance's contents to an arbitrary memory location. + * The destination memory must be allocated. Additionally, the instance + * must contain at least the requested amount of data (for easier underflow detection). + * + * @param [in] buf pointer to a BitBuffer instance to write from + * @param [out] dest pointer to the destination memory location + * @param [in] size_bytes size of the data to be written, in bytes + */ +void bit_buffer_write_bytes(const BitBuffer* buf, void* dest, size_t size_bytes); + +// Checks + +/** + * Check whether a BitBuffer instance contains a partial byte (i.e. the bit count + * is not divisible by 8). + * + * @param [in] buf pointer to a BitBuffer instance to be checked + * @return true if the instance contains a partial byte, false otherwise + */ +bool bit_buffer_has_partial_byte(const BitBuffer* buf); + +/** + * Check whether a BitBuffer instance's contents start with the designated byte. + * + * @param [in] buf pointer to a BitBuffer instance to be checked + * @param [in] byte byte value to be checked against + * @return true if data starts with designated byte, false otherwise + */ +bool bit_buffer_starts_with_byte(const BitBuffer* buf, uint8_t byte); + +// Getters + +/** + * Get a BitBuffer instance's capacity (i.e. the maximum possible amount of data), in bytes. + * + * @param [in] buf pointer to a BitBuffer instance to be queried + * @return capacity, in bytes + */ +size_t bit_buffer_get_capacity_bytes(const BitBuffer* buf); + +/** + * Get a BitBuffer instance's data size (i.e. the amount of stored data), in bits. + * Might be not divisible by 8 (see bit_buffer_is_partial_byte). + * + * @param [in] buf pointer to a BitBuffer instance to be queried + * @return data size, in bits. + */ +size_t bit_buffer_get_size(const BitBuffer* buf); + +/** + * Get a BitBuffer instance's data size (i.e. the amount of stored data), in bytes. + * If a partial byte is present, it is also counted. + * + * @param [in] buf pointer to a BitBuffer instance to be queried + * @return data size, in bytes. + */ +size_t bit_buffer_get_size_bytes(const BitBuffer* buf); + +/** + * Get a byte value at a specified index in a BitBuffer instance. + * The index must be valid (i.e. less than the instance's data size in bytes). + * + * @param [in] buf pointer to a BitBuffer instance to be queried + * @param [in] index index of the byte in question + */ +uint8_t bit_buffer_get_byte(const BitBuffer* buf, size_t index); + +/** + * Get the pointer to a BitBuffer instance's underlying data. + * TODO: Make it return const uint8_t* after all compatibility problems + * will have been resolved. + * + * @param [in] buf pointer to a BitBuffer instance to be queried + * @return pointer to the underlying data + */ +uint8_t* bit_buffer_get_data(const BitBuffer* buf); + +// Setters + +/** + * Set byte value at a specified index in a BitBuffer instance. + * The index must be valid (i.e. less than the instance's data size in bytes). + * + * @param [in,out] buf pointer to a BitBuffer instance to be modified + * @param [in] index index of the byte in question + * @param [in] byte byte value to be set at index + */ +void bit_buffer_set_byte(BitBuffer* buf, size_t index, uint8_t byte); + +/** + * Resize a BitBuffer instance to a new size, in bits. + * @warning May cause bugs. Use only if absolutely necessary. + * + * @param [in,out] buf pointer to a BitBuffer instance to be resized + * @param [in] new_size the new size of the buffer, in bits + */ +void bit_buffer_set_size(BitBuffer* buf, size_t new_size); + +/** + * Resize a BitBuffer instance to a new size, in bytes. + * @warning May cause bugs. Use only if absolutely necessary. + * + * @param [in,out] buf pointer to a BitBuffer instance to be resized + * @param [in] new_size_bytes the new size of the buffer, in bytes + */ +void bit_buffer_set_size_bytes(BitBuffer* buf, size_t new_size_bytes); + +// Modification + +/** + * Append all BitBuffer's instance contents to this one. The destination capacity + * must be no less than its original data size plus source data size. + * + * @param [in,out] buf pointer to a BitBuffer instance to be appended to + * @param [in] other pointer to a BitBuffer instance to be appended + */ +void bit_buffer_append(BitBuffer* buf, const BitBuffer* other); + +/** + * Append a BitBuffer's instance contents to this one, starting from start_index. + * The destination capacity must be no less than the source data size + * counting from start_index. + * + * @param [in,out] buf pointer to a BitBuffer instance to be appended to + * @param [in] other pointer to a BitBuffer instance to be appended + * @param [in] start_index index to begin copying source data from + */ +void bit_buffer_append_right(BitBuffer* buf, const BitBuffer* other, size_t start_index); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/nfc_device.c b/lib/nfc/nfc_device.c index c94e48c9eb3c..917f37861c0d 100644 --- a/lib/nfc/nfc_device.c +++ b/lib/nfc/nfc_device.c @@ -696,7 +696,8 @@ static void nfc_device_write_mifare_classic_block( bool is_sec_trailer = mifare_classic_is_sector_trailer(block_num); if(is_sec_trailer) { uint8_t sector_num = mifare_classic_get_sector_by_block(block_num); - MfClassicSectorTrailer* sec_tr = mifare_classic_get_sector_trailer_by_sector(data, sector_num); + MfClassicSectorTrailer* sec_tr = + mifare_classic_get_sector_trailer_by_sector(data, sector_num); // Write key A for(size_t i = 0; i < sizeof(sec_tr->key_a); i++) { if(mifare_classic_is_key_found(data, sector_num, MfClassicKeyA)) { diff --git a/lib/nfc/nfc_device_data.h b/lib/nfc/nfc_device_data.h index 253f5f4c1eb4..8c6e7af2995e 100644 --- a/lib/nfc/nfc_device_data.h +++ b/lib/nfc/nfc_device_data.h @@ -3,6 +3,7 @@ #include #include #include +#include #include #ifdef __cplusplus @@ -28,6 +29,7 @@ typedef struct { NfcaData nfca_data; MfUltralightData mf_ul_data; MfClassicData mf_classic_data; + MfDesfireData mf_desfire_data; }; } NfcDevData; diff --git a/lib/nfc/nfc_poller.c b/lib/nfc/nfc_poller.c index e5d62586da79..850479f1d2c4 100644 --- a/lib/nfc/nfc_poller.c +++ b/lib/nfc/nfc_poller.c @@ -5,6 +5,7 @@ #include "nfc.h" #include #include +#include typedef enum { NfcPollerStateIdle, @@ -92,6 +93,8 @@ static NfcCommand nfc_poller_event_callback(NfcEvent event, void* context) { if(error == NfcaErrorNone) { if(mf_ultralight_detect_protocol(&instance->nfca_data)) { poller_event = NfcPollerEventMfUltralightDetected; + } else if(mf_desfire_detect_protocol(&instance->nfca_data)) { + poller_event = NfcPollerEventMfDesfireDetected; } else { poller_event = NfcPollerEventNfcaDetected; } diff --git a/lib/nfc/nfc_poller.h b/lib/nfc/nfc_poller.h index 95aa6e8e663b..39aa07063b84 100644 --- a/lib/nfc/nfc_poller.h +++ b/lib/nfc/nfc_poller.h @@ -7,6 +7,7 @@ extern "C" { #include #include #include +#include typedef struct NfcPoller NfcPoller; @@ -23,6 +24,7 @@ typedef enum { NfcPollerEventNfcvDetected, NfcPollerEventMfUltralightDetected, NfcPollerEventMfClassicDetected, + NfcPollerEventMfDesfireDetected, } NfcPollerEvent; typedef enum { diff --git a/lib/nfc/parsers/plantain_4k_parser.c b/lib/nfc/parsers/plantain_4k_parser.c index a4320471c90b..4063a7a868db 100644 --- a/lib/nfc/parsers/plantain_4k_parser.c +++ b/lib/nfc/parsers/plantain_4k_parser.c @@ -71,7 +71,8 @@ bool plantain_4k_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx MfClassicReader reader = {}; FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; - reader.type = mifare_classic_get_classic_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak); + reader.type = + mifare_classic_get_classic_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak); for(size_t i = 0; i < COUNT_OF(plantain_keys_4k); i++) { mifare_classic_reader_add_sector( &reader, @@ -81,7 +82,8 @@ bool plantain_4k_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx FURI_LOG_T("plant4k", "Added sector %d", plantain_keys_4k[i].sector); } for(int i = 0; i < 5; i++) { - if(mifare_classic_read_card(tx_rx, &reader, &nfc_worker->dev_data->mf_classic_data) == 40) { + if(mifare_classic_read_card(tx_rx, &reader, &nfc_worker->dev_data->mf_classic_data) == + 40) { return true; } } diff --git a/lib/nfc/parsers/plantain_parser.c b/lib/nfc/parsers/plantain_parser.c index 5f1a9c1377f8..46ed5a86d419 100644 --- a/lib/nfc/parsers/plantain_parser.c +++ b/lib/nfc/parsers/plantain_parser.c @@ -46,7 +46,8 @@ bool plantain_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) { MfClassicReader reader = {}; FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; - reader.type = mifare_classic_get_classic_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak); + reader.type = + mifare_classic_get_classic_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak); for(size_t i = 0; i < COUNT_OF(plantain_keys); i++) { mifare_classic_reader_add_sector( &reader, plantain_keys[i].sector, plantain_keys[i].key_a, plantain_keys[i].key_b); diff --git a/lib/nfc/parsers/troika_4k_parser.c b/lib/nfc/parsers/troika_4k_parser.c index ca969db06512..eead3dec25d3 100644 --- a/lib/nfc/parsers/troika_4k_parser.c +++ b/lib/nfc/parsers/troika_4k_parser.c @@ -68,7 +68,8 @@ bool troika_4k_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) MfClassicReader reader = {}; FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; - reader.type = mifare_classic_get_classic_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak); + reader.type = + mifare_classic_get_classic_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak); for(size_t i = 0; i < COUNT_OF(troika_4k_keys); i++) { mifare_classic_reader_add_sector( &reader, troika_4k_keys[i].sector, troika_4k_keys[i].key_a, troika_4k_keys[i].key_b); diff --git a/lib/nfc/parsers/troika_parser.c b/lib/nfc/parsers/troika_parser.c index e003d4161b6a..911bba18db98 100644 --- a/lib/nfc/parsers/troika_parser.c +++ b/lib/nfc/parsers/troika_parser.c @@ -44,7 +44,8 @@ bool troika_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) { MfClassicReader reader = {}; FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; - reader.type = mifare_classic_get_classic_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak); + reader.type = + mifare_classic_get_classic_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak); for(size_t i = 0; i < COUNT_OF(troika_keys); i++) { mifare_classic_reader_add_sector( diff --git a/lib/nfc/parsers/two_cities.c b/lib/nfc/parsers/two_cities.c index 6409a5754f43..54107964f24e 100644 --- a/lib/nfc/parsers/two_cities.c +++ b/lib/nfc/parsers/two_cities.c @@ -72,7 +72,8 @@ bool two_cities_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) MfClassicReader reader = {}; FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; - reader.type = mifare_classic_get_classic_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak); + reader.type = + mifare_classic_get_classic_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak); for(size_t i = 0; i < COUNT_OF(two_cities_keys_4k); i++) { mifare_classic_reader_add_sector( &reader, diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a.c b/lib/nfc/protocols/iso14443_4a/iso14443_4a.c new file mode 100644 index 000000000000..41b69df11566 --- /dev/null +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a.c @@ -0,0 +1 @@ +#include "iso14443_4a.h" diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a.h b/lib/nfc/protocols/iso14443_4a/iso14443_4a.h new file mode 100644 index 000000000000..11c97807495b --- /dev/null +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a.h @@ -0,0 +1,36 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + Iso14443_4aErrorNone, + Iso14443_4aErrorNotPresent, + Iso14443_4aErrorProtocol, + Iso14443_4aErrorTimeout, +} Iso14443_4aError; + +typedef struct { + uint8_t cmd; + uint8_t param; +} Iso14443_4aAtsRequest; + +typedef struct { + uint8_t tl; + uint8_t t0; + uint8_t ta_1; + uint8_t tb_1; + uint8_t tc_1; + uint8_t t1; +} Iso14443_4aAtsResponse; + +typedef struct { + NfcaData iso14443_3a_data; +} Iso14443_4aData; + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.c b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.c new file mode 100644 index 000000000000..c15ab93bf504 --- /dev/null +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.c @@ -0,0 +1,182 @@ +#include "iso14443_4a_poller_i.h" + +#include + +#define TAG "Iso14443_4aPoller" + +#define ISO14443_4A_BUF_SIZE_MAX (512U) + +typedef Iso14443_4aPollerCommand (*Iso14443_4aPollerStateHandler)(Iso14443_4aPoller* instance); + +static Iso14443_4aPollerCommand iso14443_4a_poller_handler_idle(Iso14443_4aPoller* instance); +static Iso14443_4aPollerCommand iso14443_4a_poller_handler_read_ats(Iso14443_4aPoller* instance); +static Iso14443_4aPollerCommand iso14443_4a_poller_handler_error(Iso14443_4aPoller* instance); +static Iso14443_4aPollerCommand iso14443_4a_poller_handler_ready(Iso14443_4aPoller* instance); + +static const Iso14443_4aPollerStateHandler + iso14443_4a_poller_state_handler[Iso14443_4aPollerStateNum] = { + [Iso14443_4aPollerStateIdle] = iso14443_4a_poller_handler_idle, + [Iso14443_4aPollerStateReadAts] = iso14443_4a_poller_handler_read_ats, + [Iso14443_4aPollerStateError] = iso14443_4a_poller_handler_error, + [Iso14443_4aPollerStateReady] = iso14443_4a_poller_handler_ready, +}; + +Iso14443_4aPoller* iso14443_4a_poller_alloc(NfcaPoller* iso14443_3a_poller) { + Iso14443_4aPoller* instance = malloc(sizeof(Iso14443_4aPoller)); + instance->iso14443_3a_poller = iso14443_3a_poller; + return instance; +} + +void iso14443_4a_poller_free(Iso14443_4aPoller* instance) { + furi_assert(instance); + free(instance); +} + +Iso14443_4aPollerCommand iso14443_4a_poller_handler_idle(Iso14443_4aPoller* instance) { + bit_buffer_reset(instance->tx_buffer); + bit_buffer_reset(instance->rx_buffer); + nfca_poller_get_data(instance->iso14443_3a_poller, &instance->data->iso14443_3a_data); + instance->state = Iso14443_4aPollerStateReadAts; + return Iso14443_4aPollerCommandContinue; +} + +Iso14443_4aPollerCommand iso14443_4a_poller_handler_read_ats(Iso14443_4aPoller* instance) { + Iso14443_4aError error = iso14443_4a_poller_async_read_ats(instance); + if(error == Iso14443_4aErrorNone) { + FURI_LOG_D(TAG, "Read ATS success"); + instance->state = Iso14443_4aPollerStateReady; + } else { + FURI_LOG_D(TAG, "Failed to read ATS"); + instance->state = Iso14443_4aPollerStateError; + } + + return Iso14443_4aPollerCommandContinue; +} + +Iso14443_4aPollerCommand iso14443_4a_poller_handler_error(Iso14443_4aPoller* instance) { + nfca_poller_halt(instance->iso14443_3a_poller); + Iso14443_4aPollerEventData event_data = {.error = instance->error}; + Iso14443_4aPollerEvent event = {.type = Iso14443_4aPollerEventTypeError, .data = &event_data}; + Iso14443_4aPollerCommand command = instance->callback(event, instance->context); + instance->state = Iso14443_4aPollerStateIdle; + return command; +} + +Iso14443_4aPollerCommand iso14443_4a_poller_handler_ready(Iso14443_4aPoller* instance) { + Iso14443_4aPollerEvent event = {.type = Iso14443_4aPollerEventTypeReady}; + Iso14443_4aPollerCommand command = instance->callback(event, instance->context); + return command; +} + +static NfcaPollerCommand iso14443_4a_poller_process_command(Iso14443_4aPollerCommand command) { + NfcaPollerCommand ret = NfcaPollerCommandContinue; + + if(command == Iso14443_4aPollerCommandContinue) { + ret = NfcaPollerCommandContinue; + } else if(command == Iso14443_4aPollerCommandReset) { + ret = NfcaPollerCommandReset; + } else if(command == Iso14443_4aPollerCommandStop) { + ret = NfcaPollerCommandStop; + } else { + furi_crash("Unknown command"); + } + + return ret; +} + +static NfcaPollerCommand iso14443_4a_poller_callback(NfcaPollerEvent event, void* context) { + furi_assert(context); + + Iso14443_4aPoller* instance = context; + Iso14443_4aPollerEventData event_data = {}; + Iso14443_4aPollerEvent iso14443_4a_event = {.data = &event_data}; + Iso14443_4aPollerCommand command = Iso14443_4aPollerCommandContinue; + + furi_assert(instance->session_state != Iso14443_4aPollerSessionStateIdle); + if(instance->session_state == Iso14443_4aPollerSessionStateStopRequest) { + command = Iso14443_4aPollerCommandStop; + } else { + if(event.type == NfcaPollerEventTypeReady) { + command = iso14443_4a_poller_state_handler[instance->state](instance); + } else if(event.type == NfcaPollerEventTypeError) { + iso14443_4a_event.type = Iso14443_4aPollerEventTypeError; + command = instance->callback(iso14443_4a_event, instance->context); + } + } + + return iso14443_4a_poller_process_command(command); +} + +Iso14443_4aError iso14443_4a_poller_start( + Iso14443_4aPoller* instance, + NfcaPollerEventCallback callback, + void* context) { + furi_assert(instance); + furi_assert(instance->iso14443_3a_poller); + furi_assert(instance->state == Iso14443_4aPollerStateIdle); + furi_assert(instance->session_state == Iso14443_4aPollerSessionStateIdle); + furi_assert(callback); + furi_assert(context); + + instance->data = malloc(sizeof(Iso14443_4aData)); + instance->tx_buffer = bit_buffer_alloc(ISO14443_4A_BUF_SIZE_MAX); + instance->rx_buffer = bit_buffer_alloc(ISO14443_4A_BUF_SIZE_MAX); + + instance->session_state = Iso14443_4aPollerSessionStateActive; + instance->protocol_data.block_number = 0; + + nfca_poller_start(instance->iso14443_3a_poller, callback, context); + + return Iso14443_4aErrorNone; +} + +Iso14443_4aError iso14443_4a_poller_read( + Iso14443_4aPoller* instance, + Iso14443_4aPollerCallback callback, + void* context) { + furi_assert(instance); + furi_assert(instance->iso14443_3a_poller); + furi_assert(instance->state == Iso14443_4aPollerStateIdle); + furi_assert(callback); + + instance->callback = callback; + instance->context = context; + + return iso14443_4a_poller_start(instance, iso14443_4a_poller_callback, instance); +} + +Iso14443_4aError iso14443_4a_poller_reset(Iso14443_4aPoller* instance) { + furi_assert(instance); + furi_assert(instance->data); + furi_assert(instance->iso14443_3a_poller); + + bit_buffer_free(instance->tx_buffer); + bit_buffer_free(instance->rx_buffer); + instance->callback = NULL; + instance->context = NULL; + instance->state = Iso14443_4aPollerStateIdle; + + return Iso14443_4aErrorNone; +} + +Iso14443_4aError iso14443_4a_poller_stop(Iso14443_4aPoller* instance) { + furi_assert(instance); + furi_assert(instance->iso14443_3a_poller); + + instance->session_state = Iso14443_4aPollerSessionStateStopRequest; + nfca_poller_stop(instance->iso14443_3a_poller); + instance->session_state = Iso14443_4aPollerSessionStateIdle; + free(instance->data); + + return iso14443_4a_poller_reset(instance); +} + +Iso14443_4aError iso14443_4a_poller_get_data(Iso14443_4aPoller* instance, Iso14443_4aData* data) { + furi_assert(instance); + furi_assert(instance->data); + furi_assert(data); + + *data = *instance->data; + + return Iso14443_4aErrorNone; +} diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.h b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.h new file mode 100644 index 000000000000..ee77477ee58c --- /dev/null +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.h @@ -0,0 +1,56 @@ +#pragma once + +#include + +#include "iso14443_4a.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct Iso14443_4aPoller Iso14443_4aPoller; + +typedef enum { + Iso14443_4aPollerEventTypeError, + Iso14443_4aPollerEventTypeReady, +} Iso14443_4aPollerEventType; + +typedef struct { + Iso14443_4aError error; +} Iso14443_4aPollerEventData; + +typedef struct { + Iso14443_4aPollerEventType type; + Iso14443_4aPollerEventData* data; +} Iso14443_4aPollerEvent; + +typedef enum { + Iso14443_4aPollerCommandContinue = NfcaPollerCommandContinue, + Iso14443_4aPollerCommandReset = NfcaPollerCommandReset, + Iso14443_4aPollerCommandStop = NfcaPollerCommandStop, +} Iso14443_4aPollerCommand; + +typedef Iso14443_4aPollerCommand ( + *Iso14443_4aPollerCallback)(Iso14443_4aPollerEvent event, void* context); + +Iso14443_4aPoller* iso14443_4a_poller_alloc(NfcaPoller* iso14443_3a_poller); + +void iso14443_4a_poller_free(Iso14443_4aPoller* instance); + +Iso14443_4aError iso14443_4a_poller_start( + Iso14443_4aPoller* instance, + NfcaPollerEventCallback callback, + void* context); + +Iso14443_4aError iso14443_4a_poller_read( + Iso14443_4aPoller* instance, + Iso14443_4aPollerCallback callback, + void* context); + +Iso14443_4aError iso14443_4a_poller_stop(Iso14443_4aPoller* instance); + +Iso14443_4aError iso14443_4a_poller_get_data(Iso14443_4aPoller* instance, Iso14443_4aData* data); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c new file mode 100644 index 000000000000..bb9bbb6c6a01 --- /dev/null +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c @@ -0,0 +1,131 @@ +#include "iso14443_4a_poller_i.h" + +#include + +#define TAG "Iso14443_4aPoller" + +#define BITS_IN_BYTE (8) + +#define ISO14443_4A_ATS_BIT (1 << 5) +#define ISO14443_4A_PCB_I (0x02) + +Iso14443_4aError iso14443_4a_poller_process_error(NfcaError error) { + switch(error) { + case NfcaErrorNone: + return Iso14443_4aErrorNone; + case NfcaErrorNotPresent: + return Iso14443_4aErrorNotPresent; + case NfcaErrorColResFailed: + case NfcaErrorCommunication: + case NfcaErrorWrongCrc: + return Iso14443_4aErrorProtocol; + case NfcaErrorTimeout: + return Iso14443_4aErrorTimeout; + default: + return Iso14443_4aErrorProtocol; + } +} + +Iso14443_4aError iso14443_4a_poller_halt(Iso14443_4aPoller* instance) { + furi_assert(instance); + furi_assert(instance->iso14443_3a_poller); + + nfca_poller_halt(instance->iso14443_3a_poller); + instance->state = Iso14443_4aPollerStateIdle; + + return Iso14443_4aErrorNone; +} + +Iso14443_4aError iso14443_4a_poller_async_read_ats(Iso14443_4aPoller* instance) { + furi_assert(instance); + furi_assert(instance->iso14443_3a_poller); + + Iso14443_4aError ret = Iso14443_4aErrorProtocol; + + do { + // Check whether ATS is available + if(!(instance->data->iso14443_3a_data.sak & ISO14443_4A_ATS_BIT)) { + FURI_LOG_E(TAG, "Ats not supported: not an ISO14443-4 card"); + break; + } + + // Send RATS & receive ATS + instance->protocol_data.ats_request.cmd = 0xe0; + instance->protocol_data.ats_request.param = 0x80; + + uint16_t rx_bits; + + // TODO: Adapt lower methods to use BitBuffers + NfcaError error = nfca_poller_send_standart_frame( + instance->iso14443_3a_poller, + (uint8_t*)&instance->protocol_data.ats_request, + BITS_IN_BYTE * sizeof(instance->protocol_data.ats_request), + (uint8_t*)&instance->protocol_data.ats_response, + BITS_IN_BYTE * sizeof(instance->protocol_data.ats_response), + &rx_bits, + NFCA_FDT_LISTEN_FC); + + if(error != NfcaErrorNone) { + FURI_LOG_E(TAG, "Ats request failed: %d", error); + break; + } else if(rx_bits != BITS_IN_BYTE * sizeof(instance->protocol_data.ats_response)) { + FURI_LOG_E(TAG, "Ats response wrong length: %d bits", rx_bits); + break; + } + + ret = Iso14443_4aErrorNone; + } while(false); + + return ret; +} + +Iso14443_4aError iso14443_4a_poller_send_block( + Iso14443_4aPoller* instance, + const BitBuffer* tx_buffer, + BitBuffer* rx_buffer, + uint32_t fwt) { + furi_assert(instance); + furi_assert(instance->iso14443_3a_poller); + furi_assert(tx_buffer); + furi_assert(rx_buffer); + + const uint8_t pcb = ISO14443_4A_PCB_I | instance->protocol_data.block_number; + instance->protocol_data.block_number ^= 1; + + bit_buffer_copy_bytes(instance->tx_buffer, &pcb, sizeof(pcb)); + bit_buffer_append(instance->tx_buffer, tx_buffer); + + Iso14443_4aError ret = Iso14443_4aErrorNone; + + do { + // TODO: Adapt lower methods to use BitBuffers + uint16_t rx_size_bits; + NfcaError error = nfca_poller_send_standart_frame( + instance->iso14443_3a_poller, + bit_buffer_get_data(instance->tx_buffer), + bit_buffer_get_size(instance->tx_buffer), + bit_buffer_get_data(instance->rx_buffer), + bit_buffer_get_capacity_bytes(instance->rx_buffer), + &rx_size_bits, + fwt); + + if(error != NfcaErrorNone) { + FURI_LOG_E(TAG, "Iso14443-3 error: %d", error); + ret = iso14443_4a_poller_process_error(error); + break; + } + + // TODO: Do not set the size directly + bit_buffer_set_size(instance->rx_buffer, rx_size_bits); + + if(!bit_buffer_starts_with_byte(instance->rx_buffer, pcb)) { + ret = Iso14443_4aErrorProtocol; + break; + } + + bit_buffer_copy_right(rx_buffer, instance->rx_buffer, sizeof(pcb)); + ret = Iso14443_4aErrorNone; + } while(false); + + return ret; +} diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.h b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.h new file mode 100644 index 000000000000..70879ff27d44 --- /dev/null +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.h @@ -0,0 +1,59 @@ +#pragma once + +#include + +#include "iso14443_4a_poller.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + Iso14443_4aPollerStateIdle, + Iso14443_4aPollerStateReadAts, + Iso14443_4aPollerStateError, + Iso14443_4aPollerStateReady, + + Iso14443_4aPollerStateNum, +} Iso14443_4aPollerState; + +typedef enum { + Iso14443_4aPollerSessionStateIdle, + Iso14443_4aPollerSessionStateActive, + Iso14443_4aPollerSessionStateStopRequest, +} Iso14443_4aPollerSessionState; + +typedef struct { + Iso14443_4aAtsRequest ats_request; + Iso14443_4aAtsResponse ats_response; + uint32_t block_number; +} Iso14443_4aPollerProtocolData; + +struct Iso14443_4aPoller { + NfcaPoller* iso14443_3a_poller; + Iso14443_4aPollerState state; + Iso14443_4aPollerSessionState session_state; + BitBuffer* tx_buffer; + BitBuffer* rx_buffer; + Iso14443_4aData* data; + Iso14443_4aPollerProtocolData protocol_data; + Iso14443_4aPollerCallback callback; + Iso14443_4aError error; + void* context; +}; + +Iso14443_4aError iso14443_4a_poller_process_error(NfcaError error); + +Iso14443_4aError iso14443_4a_poller_halt(Iso14443_4aPoller* instance); + +Iso14443_4aError iso14443_4a_poller_async_read_ats(Iso14443_4aPoller* instance); + +Iso14443_4aError iso14443_4a_poller_send_block( + Iso14443_4aPoller* instance, + const BitBuffer* tx_buffer, + BitBuffer* rx_buffer, + uint32_t fwt); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h index 129885ebdcf4..784e32ce2ab0 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h @@ -49,7 +49,6 @@ typedef union { MfClassicReadBlockContext read_block_context; } MfClassicPollerContextData; - MfClassicError mf_classic_process_error(NfcaError error); MfClassicError mf_classic_async_auth( diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire.c b/lib/nfc/protocols/mf_desfire/mf_desfire.c new file mode 100644 index 000000000000..78ff2dacf323 --- /dev/null +++ b/lib/nfc/protocols/mf_desfire/mf_desfire.c @@ -0,0 +1,10 @@ +#include "mf_desfire.h" + +#include + +bool mf_desfire_detect_protocol(NfcaData* nfca_data) { + furi_assert(nfca_data); + + bool mfu_detected = false; + return mfu_detected; +} diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire.h b/lib/nfc/protocols/mf_desfire/mf_desfire.h new file mode 100644 index 000000000000..d8dac7d3f302 --- /dev/null +++ b/lib/nfc/protocols/mf_desfire/mf_desfire.h @@ -0,0 +1,145 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define MF_DESFIRE_CMD_GET_VERSION (0x60) +#define MF_DESFIRE_CMD_GET_FREE_MEMORY (0x6E) +#define MF_DESFIRE_CMD_GET_KEY_SETTINGS (0x45) +#define MF_DESFIRE_CMD_GET_KEY_VERSION (0x64) +#define MF_DESFIRE_CMD_GET_APPLICATION_IDS (0x6A) +#define MF_DESFIRE_CMD_SELECT_APPLICATION (0x5A) +#define MF_DESFIRE_CMD_GET_FILE_IDS (0x6F) +#define MF_DESFIRE_CMD_GET_FILE_SETTINGS (0xF5) + +#define MF_DESFIRE_CMD_READ_DATA (0xBD) +#define MF_DESFIRE_CMD_GET_VALUE (0x6C) +#define MF_DESFIRE_CMD_READ_RECORDS (0xBB) + +#define MF_DESFIRE_FLAG_HAS_NEXT (0xAF) + +#define MF_DESFIRE_MAX_KEYS (14) +#define MF_DESFIRE_MAX_FILES (32) + +typedef struct { + uint8_t hw_vendor; + uint8_t hw_type; + uint8_t hw_subtype; + uint8_t hw_major; + uint8_t hw_minor; + uint8_t hw_storage; + uint8_t hw_proto; + + uint8_t sw_vendor; + uint8_t sw_type; + uint8_t sw_subtype; + uint8_t sw_major; + uint8_t sw_minor; + uint8_t sw_storage; + uint8_t sw_proto; + + uint8_t uid[7]; + uint8_t batch[5]; + uint8_t prod_week; + uint8_t prod_year; +} MfDesfireVersion; + +typedef struct { + uint32_t bytes_free; + bool is_present; +} MfDesfireFreeMemory; // EV1+ only + +typedef struct { + bool is_master_key_changeable : 1; + bool is_free_directory_list : 1; + bool is_free_create_delete : 1; + bool is_config_changeable : 1; + uint8_t change_key_id : 4; + uint8_t max_keys : 4; + uint8_t flags : 4; +} MfDesfireKeySettings; + +typedef uint8_t MfDesfireKeyVersion; + +typedef struct { + MfDesfireKeySettings key_settings; + MfDesfireKeyVersion* key_versions; +} MfDesfireKeyConfiguration; + +typedef enum { + MfDesfireFileTypeStandard = 0, + MfDesfireFileTypeBackup = 1, + MfDesfireFileTypeValue = 2, + MfDesfireFileTypeLinearRecord = 3, + MfDesfireFileTypeCyclicRecord = 4, +} MfDesfireFileType; + +typedef enum { + MfDesfireFileCommunicationSettingsPlaintext = 0, + MfDesfireFileCommunicationSettingsAuthenticated = 1, + MfDesfireFileCommunicationSettingsEnciphered = 3, +} MfDesfireFileCommunicationSettings; + +typedef struct MifareDesfireFile { + uint8_t id; + MfDesfireFileType type; + MfDesfireFileCommunicationSettings comm; + uint16_t access_rights; + union { + struct { + uint32_t size; + } data; + struct { + uint32_t lo_limit; + uint32_t hi_limit; + uint32_t limited_credit_value; + bool limited_credit_enabled; + } value; + struct { + uint32_t size; + uint32_t max; + uint32_t cur; + } record; + }; + uint8_t* contents; +} MfDesfireFile; + +typedef struct { + MfDesfireFile* data; + uint8_t count; +} MfDesfireFiles; + +typedef struct MfDesfireApplication { + uint8_t id[3]; + MfDesfireKeyConfiguration key_config; + MfDesfireFiles files; +} MfDesfireApplication; + +typedef struct { + MfDesfireApplication* data; + uint8_t count; +} MfDesfireApplications; + +typedef enum { + MfDesfireErrorNone, + MfDesfireErrorNotPresent, + MfDesfireErrorProtocol, + MfDesfireErrorTimeout, +} MfDesfireError; + +typedef struct { + Iso14443_4aData iso14443_4a_data; + MfDesfireVersion version; + MfDesfireFreeMemory free_memory; + MfDesfireKeyConfiguration master_key; + MfDesfireApplications applications; +} MfDesfireData; + +bool mf_desfire_detect_protocol(NfcaData* nfca_data); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c b/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c new file mode 100644 index 000000000000..c1cf5f7f5159 --- /dev/null +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c @@ -0,0 +1,227 @@ +#include "mf_desfire_poller_i.h" + +#include + +#define TAG "MfDesfirePoller" + +#define MF_DESFIRE_BUF_SIZE_MAX (64U) + +typedef MfDesfirePollerCommand (*MfDesfirePollerReadHandler)(MfDesfirePoller* instance); + +static Iso14443_4aPollerCommand mf_desfire_process_command(MfDesfirePollerCommand command) { + Iso14443_4aPollerCommand ret = Iso14443_4aPollerCommandContinue; + + if(command == MfDesfirePollerCommandContinue) { + ret = Iso14443_4aPollerCommandContinue; + } else if(command == MfDesfirePollerCommandReset) { + ret = Iso14443_4aPollerCommandReset; + } else if(command == MfDesfirePollerCommandStop) { + ret = Iso14443_4aPollerCommandStop; + } else { + furi_crash("Unknown command"); + } + + return ret; +} + +MfDesfirePoller* mf_desfire_poller_alloc(Iso14443_4aPoller* iso14443_4a_poller) { + MfDesfirePoller* instance = malloc(sizeof(MfDesfirePoller)); + instance->iso14443_4a_poller = iso14443_4a_poller; + + return instance; +} + +void mf_desfire_poller_free(MfDesfirePoller* instance) { + furi_assert(instance); + free(instance); +} + +static MfDesfirePollerCommand mf_desfire_poller_handler_idle(MfDesfirePoller* instance) { + bit_buffer_reset(instance->input_buffer); + bit_buffer_reset(instance->result_buffer); + bit_buffer_reset(instance->tx_buffer); + bit_buffer_reset(instance->rx_buffer); + iso14443_4a_poller_get_data(instance->iso14443_4a_poller, &instance->data->iso14443_4a_data); + + instance->state = MfDesfirePollerStateReadVersion; + return MfDesfirePollerCommandContinue; +} + +static MfDesfirePollerCommand mf_desfire_poller_handler_read_version(MfDesfirePoller* instance) { + instance->error = mf_desfire_poller_async_read_version(instance, &instance->data->version); + if(instance->error == MfDesfireErrorNone) { + FURI_LOG_D(TAG, "Read version success"); + instance->state = MfDesfirePollerStateReadFreeMemory; + } else { + FURI_LOG_E(TAG, "Failed to read version"); + iso14443_4a_poller_halt(instance->iso14443_4a_poller); + instance->state = MfDesfirePollerStateReadFailed; + } + + return MfDesfirePollerCommandContinue; +} + +static MfDesfirePollerCommand + mf_desfire_poller_handler_read_free_memory(MfDesfirePoller* instance) { + instance->error = + mf_desfire_poller_async_read_free_memory(instance, &instance->data->free_memory); + if(instance->error == MfDesfireErrorNone) { + FURI_LOG_D(TAG, "Read free memory success"); + instance->state = MfDesfirePollerStateReadMasterKey; + } else { + FURI_LOG_E(TAG, "Failed to read free memory"); + iso14443_4a_poller_halt(instance->iso14443_4a_poller); + instance->state = MfDesfirePollerStateReadFailed; + } + + return MfDesfirePollerCommandContinue; +} + +static MfDesfirePollerCommand + mf_desfire_poller_handler_read_master_key(MfDesfirePoller* instance) { + instance->error = + mf_desfire_poller_async_read_key_configuration(instance, &instance->data->master_key); + if(instance->error == MfDesfireErrorNone) { + FURI_LOG_D(TAG, "Read master key settings success"); + instance->state = MfDesfirePollerStateReadSuccess; + } else { + FURI_LOG_E(TAG, "Failed to read key settings"); + iso14443_4a_poller_halt(instance->iso14443_4a_poller); + instance->state = MfDesfirePollerStateReadFailed; + } + + return MfDesfirePollerCommandContinue; +} + +static MfDesfirePollerCommand mf_desfire_poller_handler_read_fail(MfDesfirePoller* instance) { + FURI_LOG_D(TAG, "Read Failed"); + iso14443_4a_poller_halt(instance->iso14443_4a_poller); + MfDesfirePollerEventData event_data = {.error = instance->error}; + MfDesfirePollerEvent event = {.type = MfDesfirePollerEventTypeReadFailed, .data = &event_data}; + MfDesfirePollerCommand command = instance->callback(event, instance->context); + instance->state = MfDesfirePollerStateIdle; + return command; +} + +static MfDesfirePollerCommand mf_desfire_poller_handler_read_success(MfDesfirePoller* instance) { + FURI_LOG_D(TAG, "Read success."); + iso14443_4a_poller_halt(instance->iso14443_4a_poller); + MfDesfirePollerEvent event = {.type = MfDesfirePollerEventTypeReadSuccess}; + MfDesfirePollerCommand command = instance->callback(event, instance->context); + return command; +} + +static const MfDesfirePollerReadHandler mf_desfire_poller_read_handler[MfDesfirePollerStateNum] = { + [MfDesfirePollerStateIdle] = mf_desfire_poller_handler_idle, + [MfDesfirePollerStateReadVersion] = mf_desfire_poller_handler_read_version, + [MfDesfirePollerStateReadFreeMemory] = mf_desfire_poller_handler_read_free_memory, + [MfDesfirePollerStateReadMasterKey] = mf_desfire_poller_handler_read_master_key, + [MfDesfirePollerStateReadFailed] = mf_desfire_poller_handler_read_fail, + [MfDesfirePollerStateReadSuccess] = mf_desfire_poller_handler_read_success, +}; + +static Iso14443_4aPollerCommand + mf_desfire_poller_read_callback(Iso14443_4aPollerEvent event, void* context) { + furi_assert(context); + + MfDesfirePoller* instance = context; + MfDesfirePollerEventData event_data = {}; + MfDesfirePollerEvent poller_event = {.data = &event_data}; + MfDesfirePollerCommand command = MfDesfirePollerCommandContinue; + + furi_assert(instance->session_state != MfDesfirePollerSessionStateIdle); + if(instance->session_state == MfDesfirePollerSessionStateStopRequest) { + command = MfDesfirePollerCommandStop; + } else { + if(event.type == Iso14443_4aPollerEventTypeReady) { + command = mf_desfire_poller_read_handler[instance->state](instance); + } else if(event.type == Iso14443_4aPollerEventTypeError) { + if(instance->callback) { + poller_event.type = MfDesfirePollerEventTypeReadFailed; + command = instance->callback(poller_event, instance->context); + } + } + } + + return mf_desfire_process_command(command); +} + +MfDesfireError mf_desfire_poller_start( + MfDesfirePoller* instance, + Iso14443_4aPollerCallback callback, + void* context) { + furi_assert(instance); + furi_assert(instance->state == MfDesfirePollerStateIdle); + furi_assert(instance->iso14443_4a_poller); + furi_assert(callback); + furi_assert(instance->session_state == MfDesfirePollerSessionStateIdle); + + instance->data = malloc(sizeof(MfDesfireData)); + instance->input_buffer = bit_buffer_alloc(MF_DESFIRE_BUF_SIZE_MAX); + instance->result_buffer = bit_buffer_alloc(MF_DESFIRE_BUF_SIZE_MAX); + instance->tx_buffer = bit_buffer_alloc(MF_DESFIRE_BUF_SIZE_MAX); + instance->rx_buffer = bit_buffer_alloc(MF_DESFIRE_BUF_SIZE_MAX); + + instance->session_state = MfDesfirePollerSessionStateActive; + iso14443_4a_poller_read(instance->iso14443_4a_poller, callback, context); + + return MfDesfireErrorNone; +} + +MfDesfireError mf_desfire_poller_read( + MfDesfirePoller* instance, + MfDesfirePollerCallback callback, + void* context) { + furi_assert(instance); + furi_assert(instance->state == MfDesfirePollerStateIdle); + furi_assert(instance->iso14443_4a_poller); + furi_assert(callback); + + instance->callback = callback; + instance->context = context; + + return mf_desfire_poller_start(instance, mf_desfire_poller_read_callback, instance); +} + +MfDesfireError mf_desfire_poller_get_data(MfDesfirePoller* instance, MfDesfireData* data) { + furi_assert(instance); + furi_assert(instance->data); + furi_assert(data); + + *data = *instance->data; + + return MfDesfireErrorNone; +} + +MfDesfireError mf_desfire_poller_reset(MfDesfirePoller* instance) { + furi_assert(instance); + furi_assert(instance->data); + + bit_buffer_free(instance->input_buffer); + bit_buffer_free(instance->result_buffer); + bit_buffer_free(instance->tx_buffer); + bit_buffer_free(instance->rx_buffer); + + instance->input_buffer = NULL; + instance->result_buffer = NULL; + instance->tx_buffer = NULL; + instance->rx_buffer = NULL; + + instance->callback = NULL; + instance->context = NULL; + instance->state = MfDesfirePollerStateIdle; + + return MfDesfireErrorNone; +} + +MfDesfireError mf_desfire_poller_stop(MfDesfirePoller* instance) { + furi_assert(instance); + furi_assert(instance->iso14443_4a_poller); + + instance->session_state = MfDesfirePollerSessionStateStopRequest; + iso14443_4a_poller_stop(instance->iso14443_4a_poller); + instance->session_state = MfDesfirePollerSessionStateIdle; + free(instance->data); + + return mf_desfire_poller_reset(instance); +} diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_poller.h b/lib/nfc/protocols/mf_desfire/mf_desfire_poller.h new file mode 100644 index 000000000000..00689e4152c1 --- /dev/null +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_poller.h @@ -0,0 +1,58 @@ +#pragma once + +#include "mf_desfire.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct MfDesfirePoller MfDesfirePoller; + +typedef enum { + MfDesfirePollerEventTypeReadSuccess, + MfDesfirePollerEventTypeReadFailed, +} MfDesfirePollerEventType; + +typedef struct { + union { + MfDesfireError error; + }; +} MfDesfirePollerEventData; + +typedef struct { + MfDesfirePollerEventType type; + MfDesfirePollerEventData* data; +} MfDesfirePollerEvent; + +typedef enum { + MfDesfirePollerCommandContinue = NfcaPollerCommandContinue, + MfDesfirePollerCommandReset = NfcaPollerCommandReset, + MfDesfirePollerCommandStop = NfcaPollerCommandStop, +} MfDesfirePollerCommand; + +typedef MfDesfirePollerCommand ( + *MfDesfirePollerCallback)(MfDesfirePollerEvent event, void* context); + +MfDesfirePoller* mf_desfire_poller_alloc(Iso14443_4aPoller* iso14443_4a_poller); + +void mf_desfire_poller_free(MfDesfirePoller* instance); + +MfDesfireError mf_desfire_poller_start( + MfDesfirePoller* instance, + Iso14443_4aPollerCallback callback, + void* context); + +MfDesfireError mf_desfire_poller_read( + MfDesfirePoller* instance, + MfDesfirePollerCallback callback, + void* context); + +MfDesfireError mf_desfire_poller_get_data(MfDesfirePoller* instance, MfDesfireData* data); + +MfDesfireError mf_desfire_poller_stop(MfDesfirePoller* instance); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c b/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c new file mode 100644 index 000000000000..5c8e8600d1d3 --- /dev/null +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c @@ -0,0 +1,182 @@ +#include "mf_desfire_poller_i.h" + +#include + +#define TAG "MfDesfirePoller" + +MfDesfireError mf_desfire_process_error(Iso14443_4aError error) { + switch(error) { + case Iso14443_4aErrorNone: + return MfDesfireErrorNone; + case Iso14443_4aErrorNotPresent: + return MfDesfireErrorNotPresent; + case Iso14443_4aErrorTimeout: + return MfDesfireErrorTimeout; + default: + return MfDesfireErrorProtocol; + } +} + +MfDesfireError mf_desfire_send_chunks( + MfDesfirePoller* instance, + const BitBuffer* tx_buffer, + BitBuffer* rx_buffer, + uint32_t fwt) { + furi_assert(instance); + furi_assert(instance->iso14443_4a_poller); + furi_assert(instance->tx_buffer); + furi_assert(instance->rx_buffer); + furi_assert(tx_buffer); + furi_assert(rx_buffer); + + MfDesfireError ret = MfDesfireErrorNone; + + do { + Iso14443_4aError error = iso14443_4a_poller_send_block( + instance->iso14443_4a_poller, tx_buffer, instance->rx_buffer, fwt); + + if(error != Iso14443_4aErrorNone) { + ret = mf_desfire_process_error(error); + break; + } + + const uint8_t flag_has_next = MF_DESFIRE_FLAG_HAS_NEXT; + + bit_buffer_copy_bytes(instance->tx_buffer, &flag_has_next, sizeof(flag_has_next)); + bit_buffer_copy_right(rx_buffer, instance->rx_buffer, sizeof(flag_has_next)); + + while(bit_buffer_starts_with_byte(instance->rx_buffer, flag_has_next)) { + Iso14443_4aError error = iso14443_4a_poller_send_block( + instance->iso14443_4a_poller, instance->tx_buffer, instance->rx_buffer, fwt); + + if(error != Iso14443_4aErrorNone) { + ret = mf_desfire_process_error(error); + break; + } + + bit_buffer_append_right(rx_buffer, instance->rx_buffer, sizeof(flag_has_next)); + } + } while(false); + + return ret; +} + +MfDesfireError + mf_desfire_poller_async_read_version(MfDesfirePoller* instance, MfDesfireVersion* data) { + furi_assert(instance); + + const uint8_t cmd = MF_DESFIRE_CMD_GET_VERSION; + bit_buffer_copy_bytes(instance->input_buffer, &cmd, sizeof(cmd)); + + MfDesfireError error = mf_desfire_send_chunks( + instance, + instance->input_buffer, + instance->result_buffer, + MF_DESFIRE_POLLER_STANDARD_FWT_FC); + + if(error == MfDesfireErrorNone) { + bit_buffer_write_bytes(instance->result_buffer, data, sizeof(*data)); + } + + return error; +} + +MfDesfireError + mf_desfire_poller_async_read_free_memory(MfDesfirePoller* instance, MfDesfireFreeMemory* data) { + furi_assert(instance); + + const uint8_t cmd = MF_DESFIRE_CMD_GET_FREE_MEMORY; + bit_buffer_copy_bytes(instance->input_buffer, &cmd, sizeof(cmd)); + + MfDesfireError error = mf_desfire_send_chunks( + instance, + instance->input_buffer, + instance->result_buffer, + MF_DESFIRE_POLLER_STANDARD_FWT_FC); + + if(error == MfDesfireErrorNone) { + bit_buffer_write_bytes( + instance->result_buffer, &data->bytes_free, sizeof(data->bytes_free) - 1); + data->bytes_free &= 0x00ffffff; + data->is_present = true; + } else { + data->is_present = false; + } + + return error; +} + +MfDesfireError mf_desfire_poller_async_read_key_settings( + MfDesfirePoller* instance, + MfDesfireKeySettings* data) { + furi_assert(instance); + furi_assert(data); + + bit_buffer_set_size_bytes(instance->input_buffer, sizeof(uint8_t)); + bit_buffer_set_byte(instance->input_buffer, 0, MF_DESFIRE_CMD_GET_KEY_SETTINGS); + + MfDesfireError error = mf_desfire_send_chunks( + instance, + instance->input_buffer, + instance->result_buffer, + MF_DESFIRE_POLLER_STANDARD_FWT_FC); + + if(error == MfDesfireErrorNone) { + bit_buffer_write_bytes(instance->result_buffer, data, sizeof(*data)); + } + + return error; +} + +MfDesfireError mf_desfire_poller_async_read_key_version( + MfDesfirePoller* instance, + MfDesfireKeyVersion* data, + size_t key_count) { + furi_assert(instance); + furi_assert(data); + + MfDesfireError error = MfDesfireErrorNone; + + bit_buffer_set_size_bytes(instance->input_buffer, sizeof(uint8_t) * 2); + bit_buffer_set_byte(instance->input_buffer, 0, MF_DESFIRE_CMD_GET_KEY_VERSION); + + for(size_t key_id = 0; key_id < key_count; ++key_id) { + bit_buffer_set_byte(instance->input_buffer, 1, key_id); + + error = mf_desfire_send_chunks( + instance, + instance->input_buffer, + instance->result_buffer, + MF_DESFIRE_POLLER_STANDARD_FWT_FC); + + if(error == MfDesfireErrorNone) { + data[key_id] = bit_buffer_get_byte(instance->result_buffer, 0); + } else { + break; + } + } + + return error; +} + +MfDesfireError mf_desfire_poller_async_read_key_configuration( + MfDesfirePoller* instance, + MfDesfireKeyConfiguration* data) { + furi_assert(instance); + furi_assert(data); + furi_assert(data->key_versions == NULL); + + MfDesfireError error = MfDesfireErrorNone; + + do { + error = mf_desfire_poller_async_read_key_settings(instance, &data->key_settings); + if(error != MfDesfireErrorNone) break; + + const uint8_t key_count = data->key_settings.max_keys; + data->key_versions = malloc(sizeof(MfDesfireKeyVersion) * key_count); + + error = mf_desfire_poller_async_read_key_version(instance, data->key_versions, key_count); + } while(false); + + return error; +} diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.h b/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.h new file mode 100644 index 000000000000..80aae51883fe --- /dev/null +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.h @@ -0,0 +1,73 @@ +#pragma once + +#include "mf_desfire_poller.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define MF_DESFIRE_POLLER_STANDARD_FWT_FC (60000) + +typedef enum { + MfDesfirePollerStateIdle, + MfDesfirePollerStateReadVersion, + MfDesfirePollerStateReadFreeMemory, + MfDesfirePollerStateReadMasterKey, + MfDesfirePollerStateReadFailed, + MfDesfirePollerStateReadSuccess, + + MfDesfirePollerStateNum, +} MfDesfirePollerState; + +typedef enum { + MfDesfirePollerSessionStateIdle, + MfDesfirePollerSessionStateActive, + MfDesfirePollerSessionStateStopRequest, +} MfDesfirePollerSessionState; + +struct MfDesfirePoller { + Iso14443_4aPoller* iso14443_4a_poller; + MfDesfirePollerSessionState session_state; + MfDesfirePollerState state; + BitBuffer* tx_buffer; + BitBuffer* rx_buffer; + BitBuffer* input_buffer; + BitBuffer* result_buffer; + MfDesfireData* data; + MfDesfirePollerCallback callback; + MfDesfireError error; + void* context; +}; + +MfDesfireError mf_desfire_process_error(Iso14443_4aError error); + +MfDesfireError mf_desfire_send_chunks( + MfDesfirePoller* instance, + const BitBuffer* tx_buffer, + BitBuffer* rx_buffer, + uint32_t fwt); + +MfDesfireError + mf_desfire_poller_async_read_version(MfDesfirePoller* instance, MfDesfireVersion* data); + +MfDesfireError + mf_desfire_poller_async_read_free_memory(MfDesfirePoller* instance, MfDesfireFreeMemory* data); + +MfDesfireError mf_desfire_poller_async_read_key_settings( + MfDesfirePoller* instance, + MfDesfireKeySettings* data); + +MfDesfireError mf_desfire_poller_async_read_key_version( + MfDesfirePoller* instance, + MfDesfireKeyVersion* data, + size_t key_count); + +MfDesfireError mf_desfire_poller_async_read_key_configuration( + MfDesfirePoller* instance, + MfDesfireKeyConfiguration* data); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/mifare_classic.c b/lib/nfc/protocols/mifare_classic.c index 356b145f66a9..56d685f7615d 100644 --- a/lib/nfc/protocols/mifare_classic.c +++ b/lib/nfc/protocols/mifare_classic.c @@ -111,7 +111,10 @@ bool mifare_classic_is_block_read(MfClassicData* data, uint8_t block_num) { return (FURI_BIT(data->block_read_mask[block_num / 32], block_num % 32) == 1); } -void mifare_classic_set_block_read(MfClassicData* data, uint8_t block_num, MfClassicBlock* block_data) { +void mifare_classic_set_block_read( + MfClassicData* data, + uint8_t block_num, + MfClassicBlock* block_data) { furi_assert(data); if(mifare_classic_is_sector_trailer(block_num)) { @@ -173,7 +176,10 @@ void mifare_classic_set_key_found( } } -void mifare_classic_set_key_not_found(MfClassicData* data, uint8_t sector_num, MfClassicKey key_type) { +void mifare_classic_set_key_not_found( + MfClassicData* data, + uint8_t sector_num, + MfClassicKey key_type) { furi_assert(data); if(key_type == MfClassicKeyA) { @@ -360,7 +366,8 @@ static bool mf_classic_is_allowed_access( return mf_classic_is_allowed_access_sector_trailer( &emulator->data, block_num, key, action); } else { - return mifare_classic_is_allowed_access_data_block(&emulator->data, block_num, key, action); + return mifare_classic_is_allowed_access_data_block( + &emulator->data, block_num, key, action); } } @@ -492,7 +499,8 @@ static bool mf_classic_auth( for(uint8_t i = 0; i < 4; i++) { tx_rx->tx_data[i] = old_crypto1_byte(crypto, nr[i], 0) ^ nr[i]; tx_rx->tx_parity[0] |= - (((old_crypto1_filter(crypto->odd) ^ nfc_util_odd_parity8(nr[i])) & 0x01) << (7 - i)); + (((old_crypto1_filter(crypto->odd) ^ nfc_util_odd_parity8(nr[i])) & 0x01) + << (7 - i)); } nt = old_prng_successor(nt, 32); for(uint8_t i = 4; i < 8; i++) { @@ -763,7 +771,8 @@ static bool mifare_classic_read_sector_with_reader( // Read blocks for(uint8_t i = 0; i < sector->total_blocks; i++) { - if(mifare_classic_read_block(tx_rx, crypto, first_block + i, §or->block[i])) continue; + if(mifare_classic_read_block(tx_rx, crypto, first_block + i, §or->block[i])) + continue; if(i == 0) continue; // Try to auth to read next block in case previous is locked furi_hal_nfc_sleep(); @@ -941,7 +950,8 @@ bool mifare_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* old_crypto1_word(&emulator->crypto, nr, 1); uint32_t cardRr = ar ^ old_crypto1_word(&emulator->crypto, 0, 0); if(cardRr != old_prng_successor(nonce, 64)) { - FURI_LOG_T(TAG, "Wrong AUTH! %08lX != %08lX", cardRr, old_prng_successor(nonce, 64)); + FURI_LOG_T( + TAG, "Wrong AUTH! %08lX != %08lX", cardRr, old_prng_successor(nonce, 64)); // Don't send NACK, as the tag doesn't send it command_processed = true; break; @@ -1015,7 +1025,8 @@ bool mifare_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* } // Send ACK uint8_t ack = MF_CLASSIC_ACK_CMD; - old_crypto1_encrypt(&emulator->crypto, NULL, &ack, 4, tx_rx->tx_data, tx_rx->tx_parity); + old_crypto1_encrypt( + &emulator->crypto, NULL, &ack, 4, tx_rx->tx_data, tx_rx->tx_parity); tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent; tx_rx->tx_bits = 4; @@ -1052,7 +1063,8 @@ bool mifare_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* } // Send ACK ack = MF_CLASSIC_ACK_CMD; - old_crypto1_encrypt(&emulator->crypto, NULL, &ack, 4, tx_rx->tx_data, tx_rx->tx_parity); + old_crypto1_encrypt( + &emulator->crypto, NULL, &ack, 4, tx_rx->tx_data, tx_rx->tx_parity); tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent; tx_rx->tx_bits = 4; } else if( @@ -1074,13 +1086,15 @@ bool mifare_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* int32_t prev_value; uint8_t addr; - if(!mifare_classic_block_to_value(emulator->data.block[block].value, &prev_value, &addr)) { + if(!mifare_classic_block_to_value( + emulator->data.block[block].value, &prev_value, &addr)) { break; } // Send ACK uint8_t ack = MF_CLASSIC_ACK_CMD; - old_crypto1_encrypt(&emulator->crypto, NULL, &ack, 4, tx_rx->tx_data, tx_rx->tx_parity); + old_crypto1_encrypt( + &emulator->crypto, NULL, &ack, 4, tx_rx->tx_data, tx_rx->tx_parity); tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent; tx_rx->tx_bits = 4; @@ -1115,7 +1129,8 @@ bool mifare_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* transfer_buf_valid = false; uint8_t ack = MF_CLASSIC_ACK_CMD; - old_crypto1_encrypt(&emulator->crypto, NULL, &ack, 4, tx_rx->tx_data, tx_rx->tx_parity); + old_crypto1_encrypt( + &emulator->crypto, NULL, &ack, 4, tx_rx->tx_data, tx_rx->tx_parity); tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent; tx_rx->tx_bits = 4; } else { @@ -1129,7 +1144,8 @@ bool mifare_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* uint8_t nack = transfer_buf_valid ? MF_CLASSIC_NACK_BUF_VALID_CMD : MF_CLASSIC_NACK_BUF_INVALID_CMD; if(is_encrypted) { - old_crypto1_encrypt(&emulator->crypto, NULL, &nack, 4, tx_rx->tx_data, tx_rx->tx_parity); + old_crypto1_encrypt( + &emulator->crypto, NULL, &nack, 4, tx_rx->tx_data, tx_rx->tx_parity); } else { tx_rx->tx_data[0] = nack; } @@ -1430,7 +1446,8 @@ bool mifare_classic_write_sector( uint8_t first_block = mf_classic_get_first_block_num_of_sector(sec_num); uint8_t total_blocks = mf_classic_get_blocks_num_in_sector(sec_num); - MfClassicSectorTrailer* sec_tr = mifare_classic_get_sector_trailer_by_sector(dest_data, sec_num); + MfClassicSectorTrailer* sec_tr = + mifare_classic_get_sector_trailer_by_sector(dest_data, sec_num); bool key_a_found = mifare_classic_is_key_found(dest_data, sec_num, MfClassicKeyA); bool key_b_found = mifare_classic_is_key_found(dest_data, sec_num, MfClassicKeyB); diff --git a/lib/nfc/protocols/mifare_classic.h b/lib/nfc/protocols/mifare_classic.h index 269ef9f1a866..e6530e2dc849 100644 --- a/lib/nfc/protocols/mifare_classic.h +++ b/lib/nfc/protocols/mifare_classic.h @@ -134,11 +134,17 @@ void mifare_classic_set_key_found( MfClassicKey key_type, uint64_t key); -void mifare_classic_set_key_not_found(MfClassicData* data, uint8_t sector_num, MfClassicKey key_type); +void mifare_classic_set_key_not_found( + MfClassicData* data, + uint8_t sector_num, + MfClassicKey key_type); bool mifare_classic_is_block_read(MfClassicData* data, uint8_t block_num); -void mifare_classic_set_block_read(MfClassicData* data, uint8_t block_num, MfClassicBlock* block_data); +void mifare_classic_set_block_read( + MfClassicData* data, + uint8_t block_num, + MfClassicBlock* block_data); bool mifare_classic_is_sector_data_read(MfClassicData* data, uint8_t sector_num); diff --git a/lib/nfc/protocols/nfca/nfca.h b/lib/nfc/protocols/nfca/nfca.h index 18d07102b2e1..4c2002decddd 100644 --- a/lib/nfc/protocols/nfca/nfca.h +++ b/lib/nfc/protocols/nfca/nfca.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include diff --git a/lib/nfc/protocols/nfca/nfca_poller.c b/lib/nfc/protocols/nfca/nfca_poller.c index c70077a246b7..1bb0a5681915 100644 --- a/lib/nfc/protocols/nfca/nfca_poller.c +++ b/lib/nfc/protocols/nfca/nfca_poller.c @@ -60,12 +60,12 @@ static NfcCommand nfca_poller_event_callback(NfcEvent event, void* context) { if(event.type == NfcEventTypeConfigureRequest) { nfca_poller_config(instance); } else if(event.type == NfcEventTypePollerReady) { - if(instance->state != NfcaPollerActivated) { + if(instance->state != NfcaPollerStateActivated) { NfcaData data = {}; NfcaError error = nfca_poller_async_activate(instance, &data); if(error == NfcaErrorNone) { nfca_poller_event.type = NfcaPollerEventTypeReady; - instance->state = NfcaPollerActivated; + instance->state = NfcaPollerStateActivated; nfca_poller_event.data.error = error; command = instance->callback(nfca_poller_event, instance->context); } else { diff --git a/lib/nfc/protocols/nfca/nfca_poller_i.c b/lib/nfc/protocols/nfca/nfca_poller_i.c index 43d6ff3ac43e..7efb88f6a230 100644 --- a/lib/nfc/protocols/nfca/nfca_poller_i.c +++ b/lib/nfc/protocols/nfca/nfca_poller_i.c @@ -214,11 +214,11 @@ NfcaError nfca_poller_async_activate(NfcaPoller* instance, NfcaData* nfca_data) &instance->col_res.sens_resp, sizeof(instance->col_res.sel_resp)); - instance->state = NfcaPollerColResInProgress; + instance->state = NfcaPollerStateColResInProgress; instance->col_res.cascade_level = 0; instance->col_res.state = NfcaPollerColResStateStateNewCascade; - while(instance->state == NfcaPollerColResInProgress) { + while(instance->state == NfcaPollerStateColResInProgress) { if(instance->col_res.state == NfcaPollerColResStateStateNewCascade) { instance->col_res.sdd_req.sel_cmd = NFCA_POLLER_SEL_CMD(instance->col_res.cascade_level); @@ -234,13 +234,13 @@ NfcaError nfca_poller_async_activate(NfcaPoller* instance, NfcaData* nfca_data) NFCA_FDT_LISTEN_FC); if(error != NfcErrorNone) { FURI_LOG_E(TAG, "Sdd request failed: %d", error); - instance->state = NfcaPollerColResFailed; + instance->state = NfcaPollerStateColResFailed; ret = NfcaErrorColResFailed; break; } if(rx_bits != 5 * 8) { FURI_LOG_E(TAG, "Sdd response wrong length: %d bits", rx_bits); - instance->state = NfcaPollerColResFailed; + instance->state = NfcaPollerStateColResFailed; ret = NfcaErrorColResFailed; break; } @@ -267,13 +267,13 @@ NfcaError nfca_poller_async_activate(NfcaPoller* instance, NfcaData* nfca_data) NFCA_FDT_LISTEN_FC); if(ret != NfcaErrorNone) { FURI_LOG_E(TAG, "Sel request failed: %d", error); - instance->state = NfcaPollerColResFailed; + instance->state = NfcaPollerStateColResFailed; ret = NfcaErrorColResFailed; break; } if(rx_bits != 8 * sizeof(instance->col_res.sel_resp)) { FURI_LOG_E(TAG, "Sel response wrong length: %d bits", rx_bits); - instance->state = NfcaPollerColResFailed; + instance->state = NfcaPollerStateColResFailed; ret = NfcaErrorColResFailed; break; } @@ -296,11 +296,12 @@ NfcaError nfca_poller_async_activate(NfcaPoller* instance, NfcaData* nfca_data) 4); instance->data->uid_len += 4; instance->col_res.state = NfcaPollerColResStateStateSuccess; - instance->state = NfcaPollerActivated; + instance->state = NfcaPollerStateActivated; } } } - activated = (instance->state == NfcaPollerActivated); + + activated = (instance->state == NfcaPollerStateActivated); } while(false); if(activated && nfca_data) { diff --git a/lib/nfc/protocols/nfca/nfca_poller_i.h b/lib/nfc/protocols/nfca/nfca_poller_i.h index 487f1c8e389f..71629d8ebd62 100644 --- a/lib/nfc/protocols/nfca/nfca_poller_i.h +++ b/lib/nfc/protocols/nfca/nfca_poller_i.h @@ -1,6 +1,8 @@ #pragma once #include "nfca_poller.h" + +#include #include #ifdef __cplusplus @@ -33,9 +35,9 @@ typedef struct { typedef enum { NfcaPollerStateIdle, - NfcaPollerColResInProgress, - NfcaPollerColResFailed, - NfcaPollerActivated, + NfcaPollerStateColResInProgress, + NfcaPollerStateColResFailed, + NfcaPollerStateActivated, } NfcaPollerState; typedef enum { diff --git a/lib/nfc/protocols/nfcb/nfcb_poller.c b/lib/nfc/protocols/nfcb/nfcb_poller.c index 466656a0bdaf..fb73c6b749f8 100644 --- a/lib/nfc/protocols/nfcb/nfcb_poller.c +++ b/lib/nfc/protocols/nfcb/nfcb_poller.c @@ -87,7 +87,7 @@ NfcbError nfcb_poller_config(NfcbPoller* instance) { // instance->data = malloc(sizeof(NfcbData)); // instance->buff = - // nfc_poller_buffer_alloc(NFCB_POLLER_BUFER_MAX_SIZE, NFCB_POLLER_BUFER_MAX_SIZE); + // nfc_poller_buffer_alloc(NFCB_POLLER_BUFER_MAX_SIZE, NFCB_POLLER_BUFER_MAX_SIZE); nfc_config(instance->nfc, NfcModeNfcbPoller); nfc_set_guard_time_us(instance->nfc, NFCB_GUARD_TIME_US); From a2cc5a91bb68fd6ec42ddca80717961b2d5a3387 Mon Sep 17 00:00:00 2001 From: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Date: Mon, 12 Jun 2023 11:37:20 +0300 Subject: [PATCH 101/149] Gsurkov/3324 mf desfire (#2761) * Massive refactoring within refactoring - WIP, doesnt compile * Massive refactoring within refactoring - WIP, compiles, untested * Force type check when getting protocol data * Add name protocol name type parameter * Basic DESfire reading * Implement copy and reset for MfDesfire * Simplify Desfire reset procedures * nfc dev: simplify save logic --------- Co-authored-by: gornekich --- applications/debug/unit_tests/nfc/nfc_test.c | 1 - .../main/nfc/helpers/nfc_supported_cards.c | 115 +-- .../main/nfc/helpers/nfc_supported_cards.h | 25 +- applications/main/nfc/nfc_app.c | 9 +- applications/main/nfc/nfc_app_i.h | 3 +- .../nfc/plugins/nfc_supported_card_plugin.h | 4 +- applications/main/nfc/plugins/troika.c | 2 +- .../main/nfc/scenes/nfc_scene_delete.c | 22 +- .../main/nfc/scenes/nfc_scene_generate_info.c | 8 +- .../scenes/nfc_scene_mf_classic_dict_attack.c | 15 +- .../nfc/scenes/nfc_scene_mf_classic_menu.c | 5 +- .../nfc_scene_mf_classic_read_success.c | 10 +- ...nfc_scene_mf_classic_read_supported_card.c | 23 +- .../nfc/scenes/nfc_scene_mf_desfire_read.c | 5 +- .../nfc_scene_mf_desfire_read_success.c | 16 +- .../nfc_scene_mf_ultralight_capture_pass.c | 13 +- .../scenes/nfc_scene_mf_ultralight_emulate.c | 29 +- .../nfc/scenes/nfc_scene_mf_ultralight_menu.c | 4 +- .../nfc/scenes/nfc_scene_mf_ultralight_read.c | 17 +- .../nfc_scene_mf_ultralight_read_success.c | 11 +- .../nfc_scene_mf_ultralight_unlock_menu.c | 2 +- .../main/nfc/scenes/nfc_scene_nfca_emulate.c | 4 +- .../main/nfc/scenes/nfc_scene_nfca_read.c | 3 +- .../nfc/scenes/nfc_scene_nfca_read_success.c | 2 +- .../main/nfc/scenes/nfc_scene_saved_menu.c | 26 +- .../main/nfc/scenes/nfc_scene_set_atqa.c | 27 +- .../main/nfc/scenes/nfc_scene_set_sak.c | 25 +- .../main/nfc/scenes/nfc_scene_set_type.c | 11 +- .../main/nfc/scenes/nfc_scene_set_uid.c | 9 +- .../main/nfc_rpc/nfc_rpc_mf_ultralight.c | 2 +- firmware/targets/f7/api_symbols.csv | 43 +- lib/nfc/helpers/nfc_data_generator.c | 841 +++++++++--------- lib/nfc/helpers/nfc_data_generator.h | 4 +- lib/nfc/nfc_common.h | 12 + lib/nfc/nfc_dev.c | 657 ++------------ lib/nfc/nfc_dev.h | 31 +- lib/nfc/nfc_device_data.h | 38 - lib/nfc/protocols/iso14443_4a/iso14443_4a.c | 84 ++ lib/nfc/protocols/iso14443_4a/iso14443_4a.h | 26 +- .../iso14443_4a/iso14443_4a_poller.c | 26 +- .../iso14443_4a/iso14443_4a_poller.h | 4 +- .../iso14443_4a/iso14443_4a_poller_i.c | 6 +- lib/nfc/protocols/mf_classic/mf_classic.c | 303 ++++++- lib/nfc/protocols/mf_classic/mf_classic.h | 44 +- .../protocols/mf_classic/mf_classic_poller.c | 24 +- .../protocols/mf_classic/mf_classic_poller.h | 4 +- .../mf_classic/mf_classic_poller_i.c | 8 +- lib/nfc/protocols/mf_desfire/mf_desfire.c | 219 +++++ lib/nfc/protocols/mf_desfire/mf_desfire.h | 24 +- .../protocols/mf_desfire/mf_desfire_poller.c | 25 +- .../protocols/mf_desfire/mf_desfire_poller.h | 4 +- .../protocols/mf_ultralight/mf_ultralight.c | 306 ++++++- .../protocols/mf_ultralight/mf_ultralight.h | 34 +- .../mf_ultralight/mf_ultralight_listener.c | 12 +- .../mf_ultralight/mf_ultralight_listener.h | 2 +- .../mf_ultralight/mf_ultralight_poller.c | 25 +- .../mf_ultralight/mf_ultralight_poller.h | 5 +- .../mf_ultralight_poller_sync_api.c | 5 +- lib/nfc/protocols/nfc_protocol_base.h | 43 + lib/nfc/protocols/nfc_protocol_defs.c | 16 + lib/nfc/protocols/nfc_protocol_defs.h | 24 + lib/nfc/protocols/nfca/nfca.c | 131 +++ lib/nfc/protocols/nfca/nfca.h | 30 +- lib/nfc/protocols/nfca/nfca_listener.c | 14 +- lib/nfc/protocols/nfca/nfca_listener.h | 2 +- lib/nfc/protocols/nfca/nfca_poller.c | 23 +- lib/nfc/protocols/nfca/nfca_poller.h | 4 +- 67 files changed, 2131 insertions(+), 1420 deletions(-) create mode 100644 lib/nfc/nfc_common.h delete mode 100644 lib/nfc/nfc_device_data.h create mode 100644 lib/nfc/protocols/nfc_protocol_base.h create mode 100644 lib/nfc/protocols/nfc_protocol_defs.c create mode 100644 lib/nfc/protocols/nfc_protocol_defs.h diff --git a/applications/debug/unit_tests/nfc/nfc_test.c b/applications/debug/unit_tests/nfc/nfc_test.c index 2e3bdedaa5b9..4cea6f6d841c 100644 --- a/applications/debug/unit_tests/nfc/nfc_test.c +++ b/applications/debug/unit_tests/nfc/nfc_test.c @@ -3,7 +3,6 @@ #include #include -#include #include #include diff --git a/applications/main/nfc/helpers/nfc_supported_cards.c b/applications/main/nfc/helpers/nfc_supported_cards.c index 7a5aa3661e2e..51133b15f5c5 100644 --- a/applications/main/nfc/helpers/nfc_supported_cards.c +++ b/applications/main/nfc/helpers/nfc_supported_cards.c @@ -49,60 +49,61 @@ void nfc_supported_cards_free(NfcSupportedCards* instance) { free(instance); } -bool nfc_supported_cards_read( - NfcSupportedCards* instance, - NfcDevProtocol protocol, - void* poller, - void* data) { - furi_assert(instance); - furi_assert(poller); - furi_assert(data); - - bool card_read = false; - bool verified = false; - - do { - if(instance->status != NfcSupportCardsStatusLoadSuccess) break; - - for(size_t i = 0; i < instance->plugin_cnt; i++) { - const NfcSupportedCardsPlugin* plugin = plugin_manager_get_ep(instance->manager, i); - if(plugin->protocol != protocol) continue; - if(plugin->verify) { - verified = plugin->verify(poller); - } - if(verified && (plugin->read)) { - card_read = plugin->read(poller, data); - } - if(card_read) break; - } - } while(false); - - return card_read; -} - -bool nfc_supported_cards_parse( - NfcSupportedCards* instance, - NfcDevProtocol protocol, - void* data, - FuriString* parsed_data) { - furi_assert(instance); - furi_assert(data); - furi_assert(parsed_data); - - bool parsed = false; - - do { - if(instance->status != NfcSupportCardsStatusLoadSuccess) break; - - for(size_t i = 0; i < instance->plugin_cnt; i++) { - const NfcSupportedCardsPlugin* plugin = plugin_manager_get_ep(instance->manager, i); - if(plugin->protocol != protocol) continue; - if(plugin->parse) { - parsed = plugin->parse(data, parsed_data); - } - if(parsed) break; - } - } while(false); - - return parsed; -} +//FIXME: Make it compile +// bool nfc_supported_cards_read( +// NfcSupportedCards* instance, +// NfcDevProtocol protocol, +// void* poller, +// void* data) { +// furi_assert(instance); +// furi_assert(poller); +// furi_assert(data); +// +// bool card_read = false; +// bool verified = false; +// +// do { +// if(instance->status != NfcSupportCardsStatusLoadSuccess) break; +// +// for(size_t i = 0; i < instance->plugin_cnt; i++) { +// const NfcSupportedCardsPlugin* plugin = plugin_manager_get_ep(instance->manager, i); +// if(plugin->protocol != protocol) continue; +// if(plugin->verify) { +// verified = plugin->verify(poller); +// } +// if(verified && (plugin->read)) { +// card_read = plugin->read(poller, data); +// } +// if(card_read) break; +// } +// } while(false); +// +// return card_read; +// } +// +// bool nfc_supported_cards_parse( +// NfcSupportedCards* instance, +// NfcDevProtocol protocol, +// void* data, +// FuriString* parsed_data) { +// furi_assert(instance); +// furi_assert(data); +// furi_assert(parsed_data); +// +// bool parsed = false; +// +// do { +// if(instance->status != NfcSupportCardsStatusLoadSuccess) break; +// +// for(size_t i = 0; i < instance->plugin_cnt; i++) { +// const NfcSupportedCardsPlugin* plugin = plugin_manager_get_ep(instance->manager, i); +// if(plugin->protocol != protocol) continue; +// if(plugin->parse) { +// parsed = plugin->parse(data, parsed_data); +// } +// if(parsed) break; +// } +// } while(false); +// +// return parsed; +// } diff --git a/applications/main/nfc/helpers/nfc_supported_cards.h b/applications/main/nfc/helpers/nfc_supported_cards.h index 856384f4aa9b..da2f79e93572 100644 --- a/applications/main/nfc/helpers/nfc_supported_cards.h +++ b/applications/main/nfc/helpers/nfc_supported_cards.h @@ -1,7 +1,7 @@ #pragma once -#include #include +#include #ifdef __cplusplus extern "C" { @@ -13,17 +13,18 @@ NfcSupportedCards* nfc_supported_cards_alloc(); void nfc_supported_cards_free(NfcSupportedCards* instance); -bool nfc_supported_cards_read( - NfcSupportedCards* instance, - NfcDevProtocol protocol, - void* poller, - void* data); - -bool nfc_supported_cards_parse( - NfcSupportedCards* instance, - NfcDevProtocol protocol, - void* data, - FuriString* parsed_data); +//FIXME: Make it compile +// bool nfc_supported_cards_read( +// NfcSupportedCards* instance, +// NfcProtocolType protocol, +// void* poller, +// void* data); +// +// bool nfc_supported_cards_parse( +// NfcSupportedCards* instance, +// NfcProtocolType protocol, +// void* data, +// FuriString* parsed_data); #ifdef __cplusplus } diff --git a/applications/main/nfc/nfc_app.c b/applications/main/nfc/nfc_app.c index 3ed1a79fc694..9c32dca5f63d 100644 --- a/applications/main/nfc/nfc_app.c +++ b/applications/main/nfc/nfc_app.c @@ -135,6 +135,7 @@ NfcApp* nfc_app_alloc() { NfcViewDetectReader, detect_reader_get_view(instance->detect_reader)); + instance->nfca_edit_data = nfca_alloc(); instance->file_path = furi_string_alloc_set(NFC_APP_FOLDER); instance->file_name = furi_string_alloc(); @@ -235,6 +236,7 @@ void nfc_app_free(NfcApp* instance) { instance->notifications = NULL; + nfca_free(instance->nfca_edit_data); furi_string_free(instance->file_path); furi_string_free(instance->file_name); @@ -282,8 +284,7 @@ bool nfc_save_file(NfcApp* instance, FuriString* path) { furi_assert(instance); furi_assert(path); - bool result = nfc_dev_save( - instance->nfc_dev, &instance->nfc_dev_data, furi_string_get_cstr(instance->file_path)); + bool result = nfc_dev_save(instance->nfc_dev, furi_string_get_cstr(instance->file_path)); if(!result) { dialog_message_show_storage_error(instance->dialogs, "Cannot save\nkey file"); @@ -376,8 +377,8 @@ bool nfc_load_file(NfcApp* instance, FuriString* path, bool show_dialog) { furi_string_set(load_path, path); } - result = - nfc_dev_load(instance->nfc_dev, &instance->nfc_dev_data, furi_string_get_cstr(load_path)); + result = nfc_dev_load(instance->nfc_dev, furi_string_get_cstr(load_path)); + if(result) { path_extract_filename(load_path, instance->file_name, true); } diff --git a/applications/main/nfc/nfc_app_i.h b/applications/main/nfc/nfc_app_i.h index 89de9462c4a0..ea4893bc8876 100644 --- a/applications/main/nfc/nfc_app_i.h +++ b/applications/main/nfc/nfc_app_i.h @@ -119,8 +119,7 @@ struct NfcApp { NfcSupportedCards* supported_cards; NfcDev* nfc_dev; - NfcDevData nfc_dev_data; - NfcaData nfca_edit_data; + NfcaData* nfca_edit_data; FuriString* file_path; FuriString* file_name; }; diff --git a/applications/main/nfc/plugins/nfc_supported_card_plugin.h b/applications/main/nfc/plugins/nfc_supported_card_plugin.h index e0554268c659..ebd2cf77b110 100644 --- a/applications/main/nfc/plugins/nfc_supported_card_plugin.h +++ b/applications/main/nfc/plugins/nfc_supported_card_plugin.h @@ -1,7 +1,7 @@ #pragma once -#include #include +#include #define NFC_SUPPORTED_CARD_PLUGIN_APP_ID "NfcSupportedCardPlugin" #define NFC_SUPPORTED_CARD_PLUGIN_API_VERSION 1 @@ -13,7 +13,7 @@ typedef bool (*NfcSupportedCardPluginRead)(void* poller, void* data); typedef bool (*NfcSupportedCardPluginParse)(void* data, FuriString* parsed_data); typedef struct { - NfcDevProtocol protocol; + NfcProtocolType protocol; NfcSupportedCardPluginVerify verify; NfcSupportedCardPluginRead read; NfcSupportedCardPluginParse parse; diff --git a/applications/main/nfc/plugins/troika.c b/applications/main/nfc/plugins/troika.c index 84c5e0b7d03b..0b4abdaf5506 100644 --- a/applications/main/nfc/plugins/troika.c +++ b/applications/main/nfc/plugins/troika.c @@ -63,7 +63,7 @@ bool troika_parse(void* data, FuriString* parsed_data) { /* Actual implementation of app<>plugin interface */ static const NfcSupportedCardsPlugin troika_plugin = { - .protocol = NfcDevProtocolMfClassic, + .protocol = NfcProtocolTypeMfClassic, .verify = troika_verify, .read = troika_read, .parse = troika_parse, diff --git a/applications/main/nfc/scenes/nfc_scene_delete.c b/applications/main/nfc/scenes/nfc_scene_delete.c index 5cb872d897a5..88fb834da43b 100644 --- a/applications/main/nfc/scenes/nfc_scene_delete.c +++ b/applications/main/nfc/scenes/nfc_scene_delete.c @@ -22,26 +22,18 @@ void nfc_scene_delete_on_enter(void* context) { widget_add_button_element( nfc->widget, GuiButtonTypeRight, "Delete", nfc_scene_delete_widget_callback, nfc); - NfcaData* nfca_data = &nfc->nfc_dev_data.nfca_data; + size_t uid_len; + const uint8_t* uid = nfc_dev_get_uid(nfc->nfc_dev, &uid_len); + furi_string_set(temp_str, "UID:"); - for(size_t i = 0; i < nfca_data->uid_len; i++) { - furi_string_cat_printf(temp_str, " %02X", nfca_data->uid[i]); + for(size_t i = 0; i < uid_len; i++) { + furi_string_cat_printf(temp_str, " %02X", uid[i]); } widget_add_string_element( nfc->widget, 64, 24, AlignCenter, AlignTop, FontSecondary, furi_string_get_cstr(temp_str)); - NfcDevProtocol protocol = nfc->nfc_dev_data.protocol; - if(protocol == NfcDevProtocolMfUltralight) { - furi_string_set_str( - temp_str, mf_ultralight_get_name(nfc->nfc_dev_data.mf_ul_data.type, true)); - } else if(protocol == NfcDevProtocolMfClassic) { - furi_string_set(temp_str, "Mifare Classic"); - // furi_string_set(temp_str, nfc_mf_classic_type(nfc->dev->dev_data.mf_classic_data.type)); - } else if(protocol == NfcDevProtocolMfDesfire) { - furi_string_set(temp_str, "MIFARE DESFire"); - } else { - furi_string_set(temp_str, "Unknown ISO tag"); - } + furi_string_set_str( + temp_str, nfc_dev_get_protocol_name(nfc->nfc_dev, NfcProtocolNameTypeFull)); widget_add_string_element( nfc->widget, 64, 34, AlignCenter, AlignTop, FontSecondary, furi_string_get_cstr(temp_str)); widget_add_string_element(nfc->widget, 64, 44, AlignCenter, AlignTop, FontSecondary, "NFC-A"); diff --git a/applications/main/nfc/scenes/nfc_scene_generate_info.c b/applications/main/nfc/scenes/nfc_scene_generate_info.c index 1d875bf623b5..396abc4602d8 100644 --- a/applications/main/nfc/scenes/nfc_scene_generate_info.c +++ b/applications/main/nfc/scenes/nfc_scene_generate_info.c @@ -14,8 +14,10 @@ void nfc_scene_generate_info_on_enter(void* context) { NfcApp* nfc = context; NfcaData* nfca_data = NULL; - if(nfc->nfc_dev_data.protocol == NfcDevProtocolMfUltralight) { - nfca_data = &nfc->nfc_dev_data.mf_ul_data.nfca_data; + if(nfc_dev_get_protocol_type(nfc->nfc_dev) == NfcProtocolTypeMfUltralight) { + const MfUltralightData* mfu_data = + nfc_dev_get_protocol_data(nfc->nfc_dev, NfcProtocolTypeMfUltralight); + nfca_data = mfu_data->nfca_data; } else { // TODO add Mf Classic furi_crash("Not supported protocol"); @@ -52,7 +54,7 @@ bool nfc_scene_generate_info_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == GuiButtonTypeRight) { // Switch either to NfcSceneMfClassicMenu or NfcSceneMfUltralightMenu - if(nfc->nfc_dev_data.protocol == NfcDevProtocolMfUltralight) { + if(nfc_dev_get_protocol_type(nfc->nfc_dev) == NfcProtocolTypeMfUltralight) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightMenu); } else { // TODO add classic diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c index 48b5824d06d0..adf0fedabf60 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c @@ -77,7 +77,7 @@ void nfc_dict_attack_dict_attack_result_callback(void* context) { } static void nfc_scene_mf_classic_dict_attack_update_view(NfcApp* nfc) { - MfClassicData* data = &nfc->nfc_dev_data.mf_classic_data; + const MfClassicData* data = nfc_dev_get_protocol_data(nfc->nfc_dev, NfcProtocolTypeMfClassic); uint8_t sectors_read = 0; uint8_t keys_found = 0; @@ -88,7 +88,7 @@ static void nfc_scene_mf_classic_dict_attack_update_view(NfcApp* nfc) { } static void nfc_scene_mf_classic_dict_attack_prepare_view(NfcApp* nfc, DictAttackState state) { - MfClassicData* data = &nfc->nfc_dev_data.mf_classic_data; + const MfClassicData* data = nfc_dev_get_protocol_data(nfc->nfc_dev, NfcProtocolTypeMfClassic); // Identify scene state if(state == DictAttackStateIdle) { @@ -132,7 +132,6 @@ void nfc_scene_mf_classic_dict_attack_on_enter(void* context) { bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent event) { NfcApp* nfc = context; - // MfClassicData* data = &nfc->nfc_dev_data.mf_classic_data; bool consumed = false; uint32_t state = @@ -161,12 +160,18 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent dict_attack_inc_keys_found(nfc->dict_attack); consumed = true; } else if(event.event == NfcCustomEventDictAttackNewSector) { - mf_classic_poller_get_data(nfc->mf_classic_poller, &nfc->nfc_dev_data.mf_classic_data); + nfc_dev_set_protocol_data( + nfc->nfc_dev, + NfcProtocolTypeMfClassic, + mf_classic_poller_get_data(nfc->mf_classic_poller)); nfc_scene_mf_classic_dict_attack_update_view(nfc); dict_attack_inc_current_sector(nfc->dict_attack); consumed = true; } else if(event.event == NfcCustomEventDictAttackNewKeyBatch) { - mf_classic_poller_get_data(nfc->mf_classic_poller, &nfc->nfc_dev_data.mf_classic_data); + nfc_dev_set_protocol_data( + nfc->nfc_dev, + NfcProtocolTypeMfClassic, + mf_classic_poller_get_data(nfc->mf_classic_poller)); nfc_scene_mf_classic_dict_attack_update_view(nfc); dict_attack_inc_current_dict_key(nfc->dict_attack, 10); consumed = true; diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_menu.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_menu.c index 2412230010c8..380d8e6e829b 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_menu.c @@ -22,7 +22,10 @@ void nfc_scene_mf_classic_menu_on_enter(void* context) { submenu, "Save", SubmenuIndexSave, nfc_scene_mf_classic_menu_submenu_callback, nfc); submenu_add_item( submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_mf_classic_menu_submenu_callback, nfc); - if(!mf_classic_is_card_read(&nfc->nfc_dev_data.mf_classic_data)) { + + const MfClassicData* mfc_data = + nfc_dev_get_protocol_data(nfc->nfc_dev, NfcProtocolTypeMfClassic); + if(!mf_classic_is_card_read(mfc_data)) { submenu_add_item( submenu, "Detect Reader", diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_read_success.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_read_success.c index dcb6e651f2aa..31310e08c58b 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_read_success.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_read_success.c @@ -14,7 +14,8 @@ void nfc_scene_mf_classic_read_success_widget_callback( void nfc_scene_mf_classic_read_success_on_enter(void* context) { NfcApp* nfc = context; - MfClassicData* mfc_data = &nfc->nfc_dev_data.mf_classic_data; + const MfClassicData* mfc_data = + nfc_dev_get_protocol_data(nfc->nfc_dev, NfcProtocolTypeMfClassic); // Setup view Widget* widget = nfc->widget; @@ -27,10 +28,11 @@ void nfc_scene_mf_classic_read_success_on_enter(void* context) { if(furi_string_size(nfc->parsed_data)) { temp_str = furi_string_alloc_set(nfc->parsed_data); } else { - temp_str = furi_string_alloc_printf("\e#%s\n", mf_classic_get_name(mfc_data->type, true)); + temp_str = furi_string_alloc_printf( + "\e#%s\n", nfc_dev_get_protocol_name(nfc->nfc_dev, NfcProtocolNameTypeFull)); furi_string_cat_printf(temp_str, "UID:"); - for(size_t i = 0; i < mfc_data->nfca_data.uid_len; i++) { - furi_string_cat_printf(temp_str, " %02X", mfc_data->nfca_data.uid[i]); + for(size_t i = 0; i < mfc_data->nfca_data->uid_len; i++) { + furi_string_cat_printf(temp_str, " %02X", mfc_data->nfca_data->uid[i]); } uint8_t sectors_total = mf_classic_get_total_sectors_num(mfc_data->type); uint8_t keys_total = sectors_total * 2; diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_read_supported_card.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_read_supported_card.c index 57352afb27ed..9b6b430d4231 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_read_supported_card.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_read_supported_card.c @@ -14,17 +14,18 @@ void nfc_scene_mf_classic_read_supported_card_on_enter(void* context) { bool supported = false; nfc->supported_cards = nfc_supported_cards_alloc(); - if(nfc_supported_cards_read( - nfc->supported_cards, - NfcDevProtocolMfClassic, - nfc->mf_classic_poller, - &nfc->nfc_dev_data.mf_classic_data)) { - supported = nfc_supported_cards_parse( - nfc->supported_cards, - NfcDevProtocolMfClassic, - &nfc->nfc_dev_data.mf_classic_data, - nfc->parsed_data); - } + // FIXME: Make it compile + // if(nfc_supported_cards_read( + // nfc->supported_cards, + // NfcDevProtocolMfClassic, + // nfc->mf_classic_poller, + // &nfc->nfc_dev_data.mf_classic_data)) { + // supported = nfc_supported_cards_parse( + // nfc->supported_cards, + // NfcDevProtocolMfClassic, + // &nfc->nfc_dev_data.mf_classic_data, + // nfc->parsed_data); + // } if(supported) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSuccess); diff --git a/applications/main/nfc/scenes/nfc_scene_mf_desfire_read.c b/applications/main/nfc/scenes/nfc_scene_mf_desfire_read.c index 9e58c643c2e6..133f8d0e1f0e 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_desfire_read.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_desfire_read.c @@ -38,7 +38,10 @@ bool nfc_scene_mf_desfire_read_on_event(void* context, SceneManagerEvent event) if(event.type == SceneManagerEventTypeCustom) { if(event.event == NfcWorkerEventMfDesfireReadSuccess) { notification_message(nfc->notifications, &sequence_success); - mf_desfire_poller_get_data(nfc->mf_desfire_poller, &nfc->nfc_dev_data.mf_desfire_data); + nfc_dev_set_protocol_data( + nfc->nfc_dev, + NfcProtocolTypeMfDesfire, + mf_desfire_poller_get_data(nfc->mf_desfire_poller)); scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireReadSuccess); DOLPHIN_DEED(DolphinDeedNfcReadSuccess); consumed = true; diff --git a/applications/main/nfc/scenes/nfc_scene_mf_desfire_read_success.c b/applications/main/nfc/scenes/nfc_scene_mf_desfire_read_success.c index 3caf5a4460ff..27d2611ee0ec 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_desfire_read_success.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_desfire_read_success.c @@ -16,17 +16,19 @@ void nfc_scene_mf_desfire_read_success_on_enter(void* context) { NfcApp* nfc = context; // Setup view - nfc->nfc_dev_data.protocol = NfcDevProtocolMfDesfire; - MfDesfireData* data = &nfc->nfc_dev_data.mf_desfire_data; - NfcaData* iso14443_3a_data = &data->iso14443_4a_data.iso14443_3a_data; - Widget* widget = nfc->widget; + const MfDesfireData* data = nfc_dev_get_protocol_data(nfc->nfc_dev, NfcProtocolTypeMfDesfire); + Widget* widget = nfc->widget; FuriString* temp_str; - temp_str = furi_string_alloc_printf("\e#MIFARE DESfire\n"); + temp_str = furi_string_alloc_printf( + "\e#%s\n", nfc_dev_get_protocol_name(nfc->nfc_dev, NfcProtocolNameTypeFull)); furi_string_cat_printf(temp_str, "UID:"); - for(size_t i = 0; i < iso14443_3a_data->uid_len; i++) { - furi_string_cat_printf(temp_str, " %02X", iso14443_3a_data->uid[i]); + + size_t uid_len; + const uint8_t* uid = nfc_dev_get_uid(nfc->nfc_dev, &uid_len); + for(size_t i = 0; i < uid_len; i++) { + furi_string_cat_printf(temp_str, " %02X", uid[i]); } uint32_t bytes_total = 1UL << (data->version.sw_storage >> 1); diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_capture_pass.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_capture_pass.c index 3c594a4e17f6..4ca3fd97051e 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_capture_pass.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_capture_pass.c @@ -30,11 +30,12 @@ void nfc_scene_mf_ultralight_capture_pass_on_enter(void* context) { view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); // Start worker - mf_ultralight_listener_start( - nfc->mf_ul_listener, - &nfc->nfc_dev_data.mf_ul_data, - nfc_scene_mf_ultralight_capture_pass_worker_callback, - nfc); + // FIXME: Make it compile + // mf_ultralight_listener_start( + // nfc->mf_ul_listener, + // nfc->nfc_dev_data.mf_ul_data, + // nfc_scene_mf_ultralight_capture_pass_worker_callback, + // nfc); nfc_blink_read_start(nfc); } @@ -44,7 +45,7 @@ bool nfc_scene_mf_ultralight_capture_pass_on_event(void* context, SceneManagerEv bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { - if((event.event == MfUltralightListenerEventTypeAuth)) { + if(event.event == MfUltralightListenerEventTypeAuth) { notification_message(nfc->notifications, &sequence_success); scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockWarn); consumed = true; diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_emulate.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_emulate.c index 024f050a1a4e..bd5eb11165e6 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_emulate.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_emulate.c @@ -4,8 +4,10 @@ void nfc_scene_mf_ultralight_emulate_on_enter(void* context) { NfcApp* nfc = context; // Setup view - MfUltralightData* data = &nfc->nfc_dev_data.mf_ul_data; - MfUltralightType type = data->type; + const MfUltralightData* data = + nfc_dev_get_protocol_data(nfc->nfc_dev, NfcProtocolTypeMfUltralight); + const MfUltralightType type = data->type; + bool is_ultralight = (type == MfUltralightTypeUL11) || (type == MfUltralightTypeUL21) || (type == MfUltralightTypeUnknown); Popup* popup = nfc->popup; @@ -32,20 +34,21 @@ bool nfc_scene_mf_ultralight_emulate_on_event(void* context, SceneManagerEvent e bool consumed = false; if(event.type == SceneManagerEventTypeBack) { - MfUltralightData* mfu_data_after_emulation = malloc(sizeof(MfUltralightData)); + MfUltralightData* mfu_data_after_emulation = mf_ultralight_alloc(); mf_ultralight_listener_get_data(nfc->mf_ul_listener, mfu_data_after_emulation); mf_ultralight_listener_stop(nfc->mf_ul_listener); // Check if data changed and save in shadow file - if(memcmp( - mfu_data_after_emulation, - &nfc->nfc_dev_data.mf_ul_data, - sizeof(MfUltralightData)) != 0) { - // Save shadow file - if(!furi_string_empty(nfc->file_name)) { - nfc_save_shadow_file(nfc); - } - } - free(mfu_data_after_emulation); + // FIXME: A comparison method? + // if(memcmp( + // mfu_data_after_emulation, + // &nfc->nfc_dev_data.mf_ul_data, + // sizeof(MfUltralightData)) != 0) { + // // Save shadow file + // if(!furi_string_empty(nfc->file_name)) { + // nfc_save_shadow_file(nfc); + // } + // } + mf_ultralight_free(mfu_data_after_emulation); consumed = false; } return consumed; diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c index cd3e29bdc11c..74355e404c82 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c @@ -17,7 +17,9 @@ void nfc_scene_mf_ultralight_menu_submenu_callback(void* context, uint32_t index void nfc_scene_mf_ultralight_menu_on_enter(void* context) { NfcApp* nfc = context; Submenu* submenu = nfc->submenu; - MfUltralightData* data = &nfc->nfc_dev_data.mf_ul_data; + + const MfUltralightData* data = + nfc_dev_get_protocol_data(nfc->nfc_dev, NfcProtocolTypeMfUltralight); if(!mf_ultralight_is_all_data_read(data)) { submenu_add_item( diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read.c index 8520d8c9b950..e9664d9fbf7a 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read.c @@ -16,16 +16,20 @@ MfUltralightPollerCommand nfc->view_dispatcher, NfcWorkerEventMfUltralightReadSuccess); command = MfUltralightPollerCommandStop; } else if(event.type == MfUltralightPollerEventTypeAuthRequest) { - MfUltralightData* data = &nfc->nfc_dev_data.mf_ul_data; - mf_ultralight_poller_get_data(nfc->mf_ul_poller, data); + nfc_dev_set_protocol_data( + nfc->nfc_dev, + NfcProtocolTypeMfUltralight, + mf_ultralight_poller_get_data(nfc->mf_ul_poller)); + const MfUltralightData* data = + nfc_dev_get_protocol_data(nfc->nfc_dev, NfcProtocolTypeMfUltralight); if(nfc->mf_ul_auth->type == MfUltralightAuthTypeXiaomii) { if(mf_ultralight_generate_xiaomi_pass( - nfc->mf_ul_auth, data->nfca_data.uid, data->nfca_data.uid_len)) { + nfc->mf_ul_auth, data->nfca_data->uid, data->nfca_data->uid_len)) { event.data->auth_context.skip_auth = false; } } else if(nfc->mf_ul_auth->type == MfUltralightAuthTypeAmiibo) { if(mf_ultralight_generate_amiibo_pass( - nfc->mf_ul_auth, data->nfca_data.uid, data->nfca_data.uid_len)) { + nfc->mf_ul_auth, data->nfca_data->uid, data->nfca_data->uid_len)) { event.data->auth_context.skip_auth = false; } } else if(nfc->mf_ul_auth->type == MfUltralightAuthTypeManual) { @@ -62,7 +66,10 @@ bool nfc_scene_mf_ultralight_read_on_event(void* context, SceneManagerEvent even if(event.type == SceneManagerEventTypeCustom) { if(event.event == NfcWorkerEventMfUltralightReadSuccess) { notification_message(nfc->notifications, &sequence_success); - mf_ultralight_poller_get_data(nfc->mf_ul_poller, &nfc->nfc_dev_data.mf_ul_data); + nfc_dev_set_protocol_data( + nfc->nfc_dev, + NfcProtocolTypeMfUltralight, + mf_ultralight_poller_get_data(nfc->mf_ul_poller)); scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadSuccess); DOLPHIN_DEED(DolphinDeedNfcReadSuccess); consumed = true; diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_success.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_success.c index 150d8d9fa724..3703bae9d659 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_success.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_success.c @@ -16,16 +16,17 @@ void nfc_scene_mf_ultralight_read_success_on_enter(void* context) { NfcApp* nfc = context; // Setup view - nfc->nfc_dev_data.protocol = NfcDevProtocolMfUltralight; - MfUltralightData* data = &nfc->nfc_dev_data.mf_ul_data; + const MfUltralightData* data = + nfc_dev_get_protocol_data(nfc->nfc_dev, NfcProtocolTypeMfUltralight); Widget* widget = nfc->widget; FuriString* temp_str; - temp_str = furi_string_alloc_printf("\e#%s\n", mf_ultralight_get_name(data->type, true)); + temp_str = furi_string_alloc_printf( + "\e#%s\n", nfc_dev_get_protocol_name(nfc->nfc_dev, NfcProtocolNameTypeFull)); furi_string_cat_printf(temp_str, "UID:"); - for(size_t i = 0; i < data->nfca_data.uid_len; i++) { - furi_string_cat_printf(temp_str, " %02X", data->nfca_data.uid[i]); + for(size_t i = 0; i < data->nfca_data->uid_len; i++) { + furi_string_cat_printf(temp_str, " %02X", data->nfca_data->uid[i]); } furi_string_cat_printf(temp_str, "\nPages Read: %d/%d", data->pages_read, data->pages_total); if(data->pages_read != data->pages_total) { diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_menu.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_menu.c index db3a3dc718d7..7304c72ead30 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_menu.c @@ -19,7 +19,7 @@ void nfc_scene_mf_ultralight_unlock_menu_on_enter(void* context) { uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightUnlockMenu); - if(nfc->nfc_dev_data.protocol == NfcDevProtocolMfUltralight) { + if(nfc_dev_get_protocol_type(nfc->nfc_dev) == NfcProtocolTypeMfUltralight) { submenu_add_item( submenu, "Unlock With Reader", diff --git a/applications/main/nfc/scenes/nfc_scene_nfca_emulate.c b/applications/main/nfc/scenes/nfc_scene_nfca_emulate.c index b39a7e75252d..a8c827aecd31 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfca_emulate.c +++ b/applications/main/nfc/scenes/nfc_scene_nfca_emulate.c @@ -40,7 +40,7 @@ void nfc_nfca_emulate_textbox_callback(void* context) { // Add widget with device name or inform that data received static void nfc_scene_nfca_emulate_widget_config(NfcApp* nfc, bool data_received) { - NfcaData* data = &nfc->nfc_dev_data.nfca_data; + const NfcaData* data = nfc_dev_get_protocol_data(nfc->nfc_dev, NfcProtocolTypeIso14443_3a); Widget* widget = nfc->widget; widget_reset(widget); FuriString* info_str; @@ -74,7 +74,7 @@ void nfc_scene_nfca_emulate_on_enter(void* context) { nfca_listener_start( nfc->nfca_listener, - &nfc->nfc_dev_data.nfca_data, + nfc_dev_get_protocol_data(nfc->nfc_dev, NfcProtocolTypeIso14443_3a), nfc_scene_nfca_emulate_worker_callback, nfc); diff --git a/applications/main/nfc/scenes/nfc_scene_nfca_read.c b/applications/main/nfc/scenes/nfc_scene_nfca_read.c index a9d432e7a25b..156e2edeeba9 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfca_read.c +++ b/applications/main/nfc/scenes/nfc_scene_nfca_read.c @@ -11,7 +11,8 @@ NfcaPollerCommand nfc_scene_nfca_read_worker_callback(NfcaPollerEvent event, voi NfcaPollerCommand command = NfcaPollerCommandContinue; if(event.type == NfcaPollerEventTypeReady) { - nfca_poller_get_data(nfc->nfca_poller, &nfc->nfc_dev_data.nfca_data); + nfc_dev_set_protocol_data( + nfc->nfc_dev, NfcProtocolTypeIso14443_3a, nfca_poller_get_data(nfc->nfca_poller)); view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcWorkerEventReadUidNfcA); command = NfcaPollerCommandStop; } diff --git a/applications/main/nfc/scenes/nfc_scene_nfca_read_success.c b/applications/main/nfc/scenes/nfc_scene_nfca_read_success.c index b0a6e533f9bd..488632088bd0 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfca_read_success.c +++ b/applications/main/nfc/scenes/nfc_scene_nfca_read_success.c @@ -16,7 +16,7 @@ void nfc_scene_nfca_read_success_on_enter(void* context) { NfcApp* nfc = context; // Setup view - NfcaData* data = &nfc->nfc_dev_data.nfca_data; + const NfcaData* data = nfc_dev_get_protocol_data(nfc->nfc_dev, NfcProtocolTypeIso14443_3a); Widget* widget = nfc->widget; FuriString* temp_str; diff --git a/applications/main/nfc/scenes/nfc_scene_saved_menu.c b/applications/main/nfc/scenes/nfc_scene_saved_menu.c index 10651d1d48bf..45a17f78f041 100644 --- a/applications/main/nfc/scenes/nfc_scene_saved_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_saved_menu.c @@ -25,9 +25,9 @@ void nfc_scene_saved_menu_on_enter(void* context) { NfcApp* nfc = context; Submenu* submenu = nfc->submenu; - NfcDevData* data = &nfc->nfc_dev_data; + const NfcProtocolType protocol = nfc_dev_get_protocol_type(nfc->nfc_dev); - if(data->protocol == NfcDevProtocolNfca) { + if(protocol == NfcProtocolTypeIso14443_3a) { submenu_add_item( submenu, "Emulate UID", @@ -36,24 +36,20 @@ void nfc_scene_saved_menu_on_enter(void* context) { nfc); submenu_add_item( submenu, "Edit UID", SubmenuIndexEditUid, nfc_scene_saved_menu_submenu_callback, nfc); - } - if(data->protocol == NfcDevProtocolMfDesfire) { + } else if(protocol == NfcProtocolTypeMfDesfire) { submenu_add_item( submenu, "Emulate UID", SubmenuIndexEmulate, nfc_scene_saved_menu_submenu_callback, nfc); - } - - if((data->protocol == NfcDevProtocolMfUltralight) || - (data->protocol == NfcDevProtocolMfClassic)) { + } else if((protocol == NfcProtocolTypeMfUltralight) || (protocol == NfcProtocolTypeMfClassic)) { submenu_add_item( submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_saved_menu_submenu_callback, nfc); } - if(data->protocol == NfcDevProtocolMfClassic) { + if(protocol == NfcProtocolTypeMfClassic) { // TODO // if(!mifare_classic_is_card_read(&nfc->dev->dev_data.mf_classic_data)) submenu_add_item( @@ -79,8 +75,10 @@ void nfc_scene_saved_menu_on_enter(void* context) { submenu_add_item( submenu, "Info", SubmenuIndexInfo, nfc_scene_saved_menu_submenu_callback, nfc); - if(data->protocol == NfcDevProtocolMfUltralight) { - if(!mf_ultralight_is_all_data_read(&data->mf_ul_data)) { + if(protocol == NfcProtocolTypeMfUltralight) { + const MfUltralightData* mfu_data = + nfc_dev_get_protocol_data(nfc->nfc_dev, NfcProtocolTypeMfUltralight); + if(!mf_ultralight_is_all_data_read(mfu_data)) { submenu_add_item( submenu, "Unlock with Reader", @@ -117,15 +115,15 @@ void nfc_scene_saved_menu_on_enter(void* context) { bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { NfcApp* nfc = context; - NfcDevData* data = &nfc->nfc_dev_data; + const NfcProtocolType protocol = nfc_dev_get_protocol_type(nfc->nfc_dev); bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { scene_manager_set_scene_state(nfc->scene_manager, NfcSceneSavedMenu, event.event); if(event.event == SubmenuIndexEmulate) { - if(data->protocol == NfcDevProtocolMfUltralight) { + if(protocol == NfcProtocolTypeMfUltralight) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate); - } else if(data->protocol == NfcDevProtocolMfClassic) { + } else if(protocol == NfcProtocolTypeMfClassic) { scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); } else { scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcaEmulate); diff --git a/applications/main/nfc/scenes/nfc_scene_set_atqa.c b/applications/main/nfc/scenes/nfc_scene_set_atqa.c index 7aa776fc9610..ffc0035b7822 100644 --- a/applications/main/nfc/scenes/nfc_scene_set_atqa.c +++ b/applications/main/nfc/scenes/nfc_scene_set_atqa.c @@ -1,10 +1,11 @@ #include "../nfc_app_i.h" -void nfc_scene_set_atqa_byte_input_callback(void* context) { - NfcApp* nfc = context; - - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); -} +// FIXME: Make it work +// void nfc_scene_set_atqa_byte_input_callback(void* context) { +// NfcApp* nfc = context; +// +// view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); +// } void nfc_scene_set_atqa_on_enter(void* context) { NfcApp* nfc = context; @@ -12,14 +13,14 @@ void nfc_scene_set_atqa_on_enter(void* context) { // Setup view ByteInput* byte_input = nfc->byte_input; byte_input_set_header_text(byte_input, "Enter ATQA in hex"); - byte_input_set_result_callback( - byte_input, - nfc_scene_set_atqa_byte_input_callback, - NULL, - nfc, - nfc->nfc_dev_data.nfca_data.atqa, - 2); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewByteInput); + // byte_input_set_result_callback( + // byte_input, + // nfc_scene_set_atqa_byte_input_callback, + // NULL, + // nfc, + // nfc->nfc_dev_data.nfca_data->atqa, + // 2); + // view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewByteInput); } bool nfc_scene_set_atqa_on_event(void* context, SceneManagerEvent event) { diff --git a/applications/main/nfc/scenes/nfc_scene_set_sak.c b/applications/main/nfc/scenes/nfc_scene_set_sak.c index 6e693d792299..cfeaa5167e26 100644 --- a/applications/main/nfc/scenes/nfc_scene_set_sak.c +++ b/applications/main/nfc/scenes/nfc_scene_set_sak.c @@ -1,10 +1,11 @@ #include "../nfc_app_i.h" -void nfc_scene_set_sak_byte_input_callback(void* context) { - NfcApp* nfc = context; - - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); -} +// FIXME: Make this work +// void nfc_scene_set_sak_byte_input_callback(void* context) { +// NfcApp* nfc = context; +// +// view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); +// } void nfc_scene_set_sak_on_enter(void* context) { NfcApp* nfc = context; @@ -12,13 +13,13 @@ void nfc_scene_set_sak_on_enter(void* context) { // Setup view ByteInput* byte_input = nfc->byte_input; byte_input_set_header_text(byte_input, "Enter SAK in hex"); - byte_input_set_result_callback( - byte_input, - nfc_scene_set_sak_byte_input_callback, - NULL, - nfc, - &nfc->nfc_dev_data.nfca_data.sak, - 1); + // byte_input_set_result_callback( + // byte_input, + // nfc_scene_set_sak_byte_input_callback, + // NULL, + // nfc, + // &nfc->nfc_dev_data.nfca_data->sak, + // 1); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewByteInput); } diff --git a/applications/main/nfc/scenes/nfc_scene_set_type.c b/applications/main/nfc/scenes/nfc_scene_set_type.c index b59f5724f47e..3a9fd755fccc 100644 --- a/applications/main/nfc/scenes/nfc_scene_set_type.c +++ b/applications/main/nfc/scenes/nfc_scene_set_type.c @@ -36,17 +36,18 @@ bool nfc_scene_set_type_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubmenuIndexNFCA7) { - nfc->nfc_dev_data.protocol = NfcDevProtocolNfca; - nfc->nfc_dev_data.nfca_data.uid_len = 7; + // FIXME: Make this work + // nfc->nfc_dev_data.protocol = NfcDevProtocolNfca; + // nfc->nfc_dev_data.nfca_data->uid_len = 7; scene_manager_next_scene(nfc->scene_manager, NfcSceneSetSak); consumed = true; } else if(event.event == SubmenuIndexNFCA4) { - nfc->nfc_dev_data.protocol = NfcDevProtocolNfca; - nfc->nfc_dev_data.nfca_data.uid_len = 4; + // nfc->nfc_dev_data.protocol = NfcDevProtocolNfca; + // nfc->nfc_dev_data.nfca_data->uid_len = 4; scene_manager_next_scene(nfc->scene_manager, NfcSceneSetSak); consumed = true; } else { - nfc_data_generator_fill_data(event.event, &nfc->nfc_dev_data); + // nfc_data_generator_fill_data(event.event, &nfc->nfc_dev_data); scene_manager_set_scene_state(nfc->scene_manager, NfcSceneGenerateInfo, event.event); scene_manager_next_scene(nfc->scene_manager, NfcSceneGenerateInfo); consumed = true; diff --git a/applications/main/nfc/scenes/nfc_scene_set_uid.c b/applications/main/nfc/scenes/nfc_scene_set_uid.c index 8232806b8108..cf50f0d1ec2e 100644 --- a/applications/main/nfc/scenes/nfc_scene_set_uid.c +++ b/applications/main/nfc/scenes/nfc_scene_set_uid.c @@ -12,14 +12,14 @@ void nfc_scene_set_uid_on_enter(void* context) { // Setup view ByteInput* byte_input = nfc->byte_input; byte_input_set_header_text(byte_input, "Enter UID in hex"); - nfc->nfca_edit_data = nfc->nfc_dev_data.nfca_data; + nfc_dev_copy_protocol_data(nfc->nfc_dev, NfcProtocolTypeIso14443_3a, nfc->nfca_edit_data); byte_input_set_result_callback( byte_input, nfc_scene_set_uid_byte_input_callback, NULL, nfc, - nfc->nfca_edit_data.uid, - nfc->nfca_edit_data.uid_len); + nfc->nfca_edit_data->uid, + nfc->nfca_edit_data->uid_len); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewByteInput); } @@ -29,7 +29,8 @@ bool nfc_scene_set_uid_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == NfcCustomEventByteInputDone) { - nfc->nfc_dev_data.nfca_data = nfc->nfca_edit_data; + nfc_dev_set_protocol_data( + nfc->nfc_dev, NfcProtocolTypeIso14443_3a, nfc->nfca_edit_data); if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSavedMenu)) { if(nfc_save(nfc)) { scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess); diff --git a/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c b/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c index efaca6245324..04de863ed05b 100644 --- a/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c +++ b/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c @@ -183,7 +183,7 @@ static void nfc_rpc_mf_ultralight_read_tearing_flag(Nfc_Main* cmd, void* context // TODO DELETE! static void init_mf_ul_data(MfUltralightData* data) { - NfcaData* nfca_data = &data->nfca_data; + NfcaData* nfca_data = data->nfca_data; uint8_t uid[7] = {0x44, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05}; uint8_t atqa[2] = {0x44, 0x00}; nfca_data->uid_len = sizeof(uid); diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 8fd7f9674532..1d08c6def619 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,+,27.0,, +Version,+,28.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -1948,35 +1948,44 @@ Function,+,menu_free,void,Menu* Function,+,menu_get_view,View*,Menu* Function,+,menu_reset,void,Menu* Function,+,menu_set_selected_item,void,"Menu*, uint32_t" +Function,+,mf_classic_alloc,MfClassicData*, +Function,+,mf_classic_copy,void,"MfClassicData*, const MfClassicData*" Function,-,mf_classic_detect_protocol,_Bool,"NfcaData*, MfClassicType*" +Function,+,mf_classic_free,void,MfClassicData* Function,-,mf_classic_get_blocks_num_in_sector,uint8_t,uint8_t Function,-,mf_classic_get_first_block_num_of_sector,uint8_t,uint8_t -Function,-,mf_classic_get_name,const char*,"MfClassicType, _Bool" -Function,-,mf_classic_get_read_sectors_and_keys,void,"MfClassicData*, uint8_t*, uint8_t*" +Function,+,mf_classic_get_name,const char*,"const MfClassicData*, NfcProtocolNameType" +Function,+,mf_classic_get_read_sectors_and_keys,void,"const MfClassicData*, uint8_t*, uint8_t*" Function,-,mf_classic_get_sector_by_block,uint8_t,uint8_t -Function,-,mf_classic_get_sector_trailer_by_sector,MfClassicSectorTrailer*,"MfClassicData*, uint8_t" +Function,+,mf_classic_get_sector_trailer_by_sector,MfClassicSectorTrailer*,"const MfClassicData*, uint8_t" Function,-,mf_classic_get_sector_trailer_num_by_block,uint8_t,uint8_t Function,+,mf_classic_get_sector_trailer_num_by_sector,uint8_t,uint8_t Function,-,mf_classic_get_total_block_num,uint16_t,MfClassicType Function,-,mf_classic_get_total_sectors_num,uint8_t,MfClassicType -Function,-,mf_classic_is_block_read,_Bool,"MfClassicData*, uint8_t" -Function,-,mf_classic_is_card_read,_Bool,MfClassicData* -Function,-,mf_classic_is_key_found,_Bool,"MfClassicData*, uint8_t, MfClassicKeyType" -Function,-,mf_classic_is_sector_read,_Bool,"MfClassicData*, uint8_t" +Function,+,mf_classic_get_uid,const uint8_t*,"const MfClassicData*, size_t*" +Function,+,mf_classic_is_block_read,_Bool,"const MfClassicData*, uint8_t" +Function,+,mf_classic_is_card_read,_Bool,const MfClassicData* +Function,+,mf_classic_is_equal,_Bool,"const MfClassicData*, const MfClassicData*" +Function,+,mf_classic_is_key_found,_Bool,"const MfClassicData*, uint8_t, MfClassicKeyType" +Function,+,mf_classic_is_sector_read,_Bool,"const MfClassicData*, uint8_t" Function,-,mf_classic_is_sector_trailer,_Bool,uint8_t +Function,+,mf_classic_load,_Bool,"MfClassicData*, FlipperFormat*, uint32_t" Function,-,mf_classic_poller_alloc,MfClassicPoller*,NfcaPoller* Function,+,mf_classic_poller_auth,MfClassicError,"MfClassicPoller*, uint8_t, MfClassicKey*, MfClassicKeyType, MfClassicAuthContext*" Function,-,mf_classic_poller_dict_attack,MfClassicError,"MfClassicPoller*, MfClassicPollerCallback, void*" Function,-,mf_classic_poller_free,void,MfClassicPoller* -Function,-,mf_classic_poller_get_data,MfClassicError,"MfClassicPoller*, MfClassicData*" +Function,+,mf_classic_poller_get_data,const MfClassicData*,MfClassicPoller* Function,-,mf_classic_poller_read,MfClassicError,"MfClassicPoller*, MfClassicDeviceKeys*, MfClassicData*" Function,-,mf_classic_poller_read_block,MfClassicError,"MfClassicPoller*, uint8_t, MfClassicKey*, MfClassicKeyType, MfClassicBlock*" Function,-,mf_classic_poller_reset,MfClassicError,MfClassicPoller* Function,-,mf_classic_poller_start,MfClassicError,"MfClassicPoller*, NfcaPollerEventCallback, void*" Function,-,mf_classic_poller_stop,MfClassicError,MfClassicPoller* +Function,+,mf_classic_reset,void,MfClassicData* +Function,+,mf_classic_save,_Bool,"const MfClassicData*, FlipperFormat*, uint32_t" Function,-,mf_classic_set_block_read,void,"MfClassicData*, uint8_t, MfClassicBlock*" Function,-,mf_classic_set_key_found,void,"MfClassicData*, uint8_t, MfClassicKeyType, uint64_t" Function,-,mf_classic_set_key_not_found,void,"MfClassicData*, uint8_t, MfClassicKeyType" +Function,+,mf_classic_verify,_Bool,"MfClassicData*, const FuriString*" Function,-,mkdtemp,char*,char* Function,-,mkostemp,int,"char*, int" Function,-,mkostemps,int,"char*, int, int" @@ -2019,21 +2028,33 @@ Function,-,nfc_start_poller,void,"Nfc*, NfcEventCallback, void*" Function,-,nfc_stop,void,Nfc* Function,-,nfc_trx,NfcError,"Nfc*, uint8_t*, uint16_t, uint8_t*, uint16_t, uint16_t*, uint32_t" Function,-,nfc_trx_custom_parity,NfcError,"Nfc*, uint8_t*, uint16_t, uint8_t*, uint16_t, uint16_t*, uint32_t" +Function,+,nfca_alloc,NfcaData*, Function,-,nfca_append_crc,void,"uint8_t*, uint16_t" Function,-,nfca_append_crc16,void,"uint8_t*, uint16_t" Function,-,nfca_check_crc,_Bool,"uint8_t*, uint16_t" +Function,+,nfca_copy,void,"NfcaData*, const NfcaData*" Function,-,nfca_emulation_handler,_Bool,"uint8_t*, uint16_t, uint8_t*, uint16_t*" +Function,+,nfca_free,void,NfcaData* Function,-,nfca_get_crc,uint16_t,"uint8_t*, uint16_t" Function,-,nfca_get_crc16,uint16_t,"uint8_t*, uint16_t" +Function,+,nfca_get_name,const char*,"const NfcaData*, NfcProtocolNameType" +Function,+,nfca_get_uid,const uint8_t*,"const NfcaData*, size_t*" +Function,+,nfca_is_equal,_Bool,"const NfcaData*, const NfcaData*" +Function,+,nfca_load,_Bool,"NfcaData*, FlipperFormat*, uint32_t" +Function,+,nfca_load_data,_Bool,"NfcaData*, FlipperFormat*, uint32_t" Function,-,nfca_poller_alloc,NfcaPoller*,Nfc* Function,-,nfca_poller_free,void,NfcaPoller* -Function,-,nfca_poller_get_data,NfcaError,"NfcaPoller*, NfcaData*" +Function,+,nfca_poller_get_data,const NfcaData*,NfcaPoller* Function,-,nfca_poller_read,NfcaError,"NfcaPoller*, NfcaData*" Function,-,nfca_poller_start,NfcaError,"NfcaPoller*, NfcaPollerEventCallback, void*" Function,-,nfca_poller_stop,NfcaError,NfcaPoller* +Function,+,nfca_reset,void,NfcaData* +Function,+,nfca_save,_Bool,"const NfcaData*, FlipperFormat*, uint32_t" +Function,+,nfca_save_data,_Bool,"const NfcaData*, FlipperFormat*, uint32_t" Function,-,nfca_signal_alloc,NfcaSignal*, Function,-,nfca_signal_encode,void,"NfcaSignal*, uint8_t*, uint16_t, uint8_t*" Function,-,nfca_signal_free,void,NfcaSignal* +Function,+,nfca_verify,_Bool,"NfcaData*, const FuriString*" Function,+,notification_internal_message,void,"NotificationApp*, const NotificationSequence*" Function,+,notification_internal_message_block,void,"NotificationApp*, const NotificationSequence*" Function,+,notification_message,void,"NotificationApp*, const NotificationSequence*" @@ -3278,6 +3299,8 @@ Variable,+,message_red_255,const NotificationMessage, Variable,+,message_sound_off,const NotificationMessage, Variable,+,message_vibro_off,const NotificationMessage, Variable,+,message_vibro_on,const NotificationMessage, +Variable,+,nfc_protocol_iso14443_3a,const NfcProtocolBase, +Variable,+,nfc_protocol_mf_classic,const NfcProtocolBase, Variable,+,sequence_audiovisual_alert,const NotificationSequence, Variable,+,sequence_blink_blue_10,const NotificationSequence, Variable,+,sequence_blink_blue_100,const NotificationSequence, diff --git a/lib/nfc/helpers/nfc_data_generator.c b/lib/nfc/helpers/nfc_data_generator.c index 3657fd2f56ae..7474634fbabf 100644 --- a/lib/nfc/helpers/nfc_data_generator.c +++ b/lib/nfc/helpers/nfc_data_generator.c @@ -3,423 +3,444 @@ #include #include +#include +#include + #define NXP_MANUFACTURER_ID (0x04) -typedef void (*NfcDataGeneratorHandler)(NfcDevData* data); +typedef void (*NfcDataGeneratorHandler)(NfcProtocolData* data); typedef struct { const char* name; NfcDataGeneratorHandler handler; } NfcDataGenerator; -static const uint8_t version_bytes_mf0ulx1[] = {0x00, 0x04, 0x03, 0x00, 0x01, 0x00, 0x00, 0x03}; -static const uint8_t version_bytes_ntag21x[] = {0x00, 0x04, 0x04, 0x02, 0x01, 0x00, 0x00, 0x03}; -static const uint8_t version_bytes_ntag_i2c[] = {0x00, 0x04, 0x04, 0x05, 0x02, 0x00, 0x00, 0x03}; -static const uint8_t default_data_ntag203[] = - {0xE1, 0x10, 0x12, 0x00, 0x01, 0x03, 0xA0, 0x10, 0x44, 0x03, 0x00, 0xFE}; -static const uint8_t default_data_ntag213[] = {0x01, 0x03, 0xA0, 0x0C, 0x34, 0x03, 0x00, 0xFE}; -static const uint8_t default_data_ntag215_216[] = {0x03, 0x00, 0xFE}; -static const uint8_t default_data_ntag_i2c[] = {0xE1, 0x10, 0x00, 0x00, 0x03, 0x00, 0xFE}; -static const uint8_t default_config_ntag_i2c[] = {0x01, 0x00, 0xF8, 0x48, 0x08, 0x01, 0x00, 0x00}; - -static void nfc_generate_common_start(NfcDevData* data) { - memset(data, 0, sizeof(NfcDevData)); -} - -static void nfc_generate_mf_ul_uid(uint8_t* uid) { - uid[0] = NXP_MANUFACTURER_ID; - furi_hal_random_fill_buf(&uid[1], 6); - // I'm not sure how this is generated, but the upper nybble always seems to be 8 - uid[6] &= 0x0F; - uid[6] |= 0x80; -} - -static void nfc_generate_mf_ul_common(NfcDevData* data) { - MfUltralightData* mfu_data = &data->mf_ul_data; - mfu_data->nfca_data.uid_len = 7; - nfc_generate_mf_ul_uid(mfu_data->nfca_data.uid); - mfu_data->nfca_data.atqa[0] = 0x44; - mfu_data->nfca_data.atqa[1] = 0x00; - mfu_data->nfca_data.sak = 0x00; - data->protocol = NfcDevProtocolMfUltralight; -} - -static void nfc_generate_calc_bcc(uint8_t* uid, uint8_t* bcc0, uint8_t* bcc1) { - *bcc0 = 0x88 ^ uid[0] ^ uid[1] ^ uid[2]; - *bcc1 = uid[3] ^ uid[4] ^ uid[5] ^ uid[6]; -} - -static void nfc_generate_mf_ul_copy_uid_with_bcc(NfcDevData* data) { - MfUltralightData* mfu_data = &data->mf_ul_data; - memcpy(mfu_data->page[0].data, mfu_data->nfca_data.uid, 3); - memcpy(mfu_data->page[1].data, &mfu_data->nfca_data.uid[3], 4); - - nfc_generate_calc_bcc( - mfu_data->nfca_data.uid, &mfu_data->page[0].data[3], &mfu_data->page[2].data[0]); -} - -static void nfc_generate_mf_ul_orig(NfcDevData* data) { - nfc_generate_common_start(data); - nfc_generate_mf_ul_common(data); - - MfUltralightData* mfu_data = &data->mf_ul_data; - mfu_data->type = MfUltralightTypeUnknown; - mfu_data->pages_total = 16; - mfu_data->pages_read = 16; - nfc_generate_mf_ul_copy_uid_with_bcc(data); - // TODO: what's internal byte on page 2? - memset(&mfu_data->page[4], 0xff, sizeof(MfUltralightPage)); -} - -static void nfc_generate_mf_ul_with_config_common(NfcDevData* data, uint8_t num_pages) { - nfc_generate_common_start(data); - nfc_generate_mf_ul_common(data); - - MfUltralightData* mfu_data = &data->mf_ul_data; - mfu_data->pages_total = num_pages; - mfu_data->pages_read = num_pages; - nfc_generate_mf_ul_copy_uid_with_bcc(data); - uint16_t config_index = (num_pages - 4); - mfu_data->page[config_index].data[0] = 0x04; // STRG_MOD_EN - mfu_data->page[config_index].data[3] = 0xff; // AUTH0 - mfu_data->page[config_index + 1].data[1] = 0x05; // VCTID - memset(&mfu_data->page[config_index + 2], 0xff, sizeof(MfUltralightPage)); // Default PWD - if(num_pages > 20) { - mfu_data->page[config_index - 1].data[3] = MF_ULTRALIGHT_TEARING_FLAG_DEFAULT; - } -} - -static void nfc_generate_mf_ul_ev1_common(NfcDevData* data, uint8_t num_pages) { - nfc_generate_mf_ul_with_config_common(data, num_pages); - MfUltralightData* mfu_data = &data->mf_ul_data; - memcpy(&mfu_data->version, version_bytes_mf0ulx1, sizeof(MfUltralightVersion)); - for(size_t i = 0; i < 3; ++i) { - mfu_data->tearing_flag[i].data[0] = MF_ULTRALIGHT_TEARING_FLAG_DEFAULT; - } - // TODO: what's internal byte on page 2? -} - -static void nfc_generate_mf_ul_11(NfcDevData* data) { - nfc_generate_mf_ul_ev1_common(data, 20); - MfUltralightData* mfu_data = &data->mf_ul_data; - mfu_data->type = MfUltralightTypeUL11; - mfu_data->version.prod_subtype = 0x01; - mfu_data->version.storage_size = 0x0B; - mfu_data->page[16].data[0] = 0x00; // Low capacitance version does not have STRG_MOD_EN -} - -static void nfc_generate_mf_ul_h11(NfcDevData* data) { - nfc_generate_mf_ul_ev1_common(data, 20); - MfUltralightData* mfu_data = &data->mf_ul_data; - mfu_data->type = MfUltralightTypeUL11; - mfu_data->version.prod_subtype = 0x02; - mfu_data->version.storage_size = 0x0B; -} - -static void nfc_generate_mf_ul_21(NfcDevData* data) { - nfc_generate_mf_ul_ev1_common(data, 41); - MfUltralightData* mfu_data = &data->mf_ul_data; - mfu_data->type = MfUltralightTypeUL21; - mfu_data->version.prod_subtype = 0x01; - mfu_data->version.storage_size = 0x0E; - mfu_data->page[37].data[0] = 0x00; // Low capacitance version does not have STRG_MOD_EN -} - -static void nfc_generate_mf_ul_h21(NfcDevData* data) { - nfc_generate_mf_ul_ev1_common(data, 41); - MfUltralightData* mfu_data = &data->mf_ul_data; - mfu_data->type = MfUltralightTypeUL21; - mfu_data->version.prod_subtype = 0x02; - mfu_data->version.storage_size = 0x0E; -} - -static void nfc_generate_ntag203(NfcDevData* data) { - nfc_generate_common_start(data); - nfc_generate_mf_ul_common(data); - - MfUltralightData* mfu_data = &data->mf_ul_data; - mfu_data->type = MfUltralightTypeNTAG203; - mfu_data->pages_total = 42; - mfu_data->pages_read = 42; - nfc_generate_mf_ul_copy_uid_with_bcc(data); - mfu_data->page[2].data[1] = 0x48; // Internal byte - memcpy(&mfu_data->page[3], default_data_ntag203, sizeof(MfUltralightPage)); -} - -static void nfc_generate_ntag21x_common(NfcDevData* data, uint8_t num_pages) { - nfc_generate_mf_ul_with_config_common(data, num_pages); - MfUltralightData* mfu_data = &data->mf_ul_data; - memcpy(&mfu_data->version, version_bytes_ntag21x, sizeof(MfUltralightVersion)); - mfu_data->page[2].data[1] = 0x48; // Internal byte - // Capability container - mfu_data->page[3].data[0] = 0xE1; - mfu_data->page[3].data[1] = 0x10; -} - -static void nfc_generate_ntag213(NfcDevData* data) { - nfc_generate_ntag21x_common(data, 45); - MfUltralightData* mfu_data = &data->mf_ul_data; - mfu_data->type = MfUltralightTypeNTAG213; - mfu_data->version.storage_size = 0x0F; - mfu_data->page[3].data[2] = 0x12; - // Default contents - memcpy(&mfu_data->page[4], default_data_ntag213, sizeof(default_data_ntag213)); -} - -static void nfc_generate_ntag215(NfcDevData* data) { - nfc_generate_ntag21x_common(data, 135); - MfUltralightData* mfu_data = &data->mf_ul_data; - mfu_data->type = MfUltralightTypeNTAG215; - mfu_data->version.storage_size = 0x11; - mfu_data->page[3].data[2] = 0x3E; - // Default contents - memcpy(&mfu_data->page[4], default_data_ntag215_216, sizeof(default_data_ntag215_216)); -} - -static void nfc_generate_ntag216(NfcDevData* data) { - nfc_generate_ntag21x_common(data, 231); - MfUltralightData* mfu_data = &data->mf_ul_data; - mfu_data->type = MfUltralightTypeNTAG216; - mfu_data->version.storage_size = 0x13; - mfu_data->page[3].data[2] = 0x6D; - // Default contents - memcpy(&mfu_data->page[4], default_data_ntag215_216, sizeof(default_data_ntag215_216)); -} - -static void - nfc_generate_ntag_i2c_common(NfcDevData* data, MfUltralightType type, uint16_t num_pages) { - nfc_generate_common_start(data); - nfc_generate_mf_ul_common(data); - - MfUltralightData* mfu_data = &data->mf_ul_data; - mfu_data->type = type; - memcpy(&mfu_data->version, version_bytes_ntag_i2c, sizeof(version_bytes_ntag_i2c)); - mfu_data->pages_total = num_pages; - mfu_data->pages_read = num_pages; - memcpy(mfu_data->page[0].data, mfu_data->nfca_data.uid, mfu_data->nfca_data.uid_len); - mfu_data->page[1].data[3] = mfu_data->nfca_data.sak; - mfu_data->page[2].data[0] = mfu_data->nfca_data.atqa[0]; - mfu_data->page[2].data[1] = mfu_data->nfca_data.atqa[1]; - - uint16_t config_register_page = 0; - uint16_t session_register_page = 0; - - // Sync with mifare_ultralight.c - switch(type) { - case MfUltralightTypeNTAGI2C1K: - config_register_page = 227; - session_register_page = 229; - break; - case MfUltralightTypeNTAGI2C2K: - config_register_page = 481; - session_register_page = 483; - break; - case MfUltralightTypeNTAGI2CPlus1K: - case MfUltralightTypeNTAGI2CPlus2K: - config_register_page = 232; - session_register_page = 234; - break; - default: - furi_crash("Unknown MFUL"); - break; - } - - memcpy( - &mfu_data->page[config_register_page], - default_config_ntag_i2c, - sizeof(default_config_ntag_i2c)); - memcpy( - &mfu_data->page[session_register_page], - default_config_ntag_i2c, - sizeof(default_config_ntag_i2c)); -} - -static void nfc_generate_ntag_i2c_1k(NfcDevData* data) { - nfc_generate_ntag_i2c_common(data, MfUltralightTypeNTAGI2C1K, 231); - MfUltralightData* mfu_data = &data->mf_ul_data; - mfu_data->version.prod_ver_minor = 0x01; - mfu_data->version.storage_size = 0x13; - - memcpy(&mfu_data->page[3], default_data_ntag_i2c, sizeof(default_data_ntag_i2c)); - mfu_data->page[3].data[2] = 0x6D; // Size of tag in CC -} - -static void nfc_generate_ntag_i2c_2k(NfcDevData* data) { - nfc_generate_ntag_i2c_common(data, MfUltralightTypeNTAGI2C2K, 485); - MfUltralightData* mfu_data = &data->mf_ul_data; - mfu_data->version.prod_ver_minor = 0x01; - mfu_data->version.storage_size = 0x15; - - memcpy(&mfu_data->page[3], default_data_ntag_i2c, sizeof(default_data_ntag_i2c)); - mfu_data->page[3].data[2] = 0xEA; // Size of tag in CC -} - -static void - nfc_generate_ntag_i2c_plus_common(NfcDevData* data, MfUltralightType type, uint16_t num_pages) { - nfc_generate_ntag_i2c_common(data, type, num_pages); - - MfUltralightData* mfu_data = &data->mf_ul_data; - uint16_t config_index = 227; - mfu_data->page[config_index].data[3] = 0xff; // AUTH0 - - memset(&mfu_data->page[config_index + 2], 0xFF, sizeof(MfUltralightPage)); // Default PWD -} - -static void nfc_generate_ntag_i2c_plus_1k(NfcDevData* data) { - nfc_generate_ntag_i2c_plus_common(data, MfUltralightTypeNTAGI2CPlus1K, 236); - MfUltralightData* mfu_data = &data->mf_ul_data; - mfu_data->version.prod_ver_minor = 0x02; - mfu_data->version.storage_size = 0x13; -} - -static void nfc_generate_ntag_i2c_plus_2k(NfcDevData* data) { - nfc_generate_ntag_i2c_plus_common(data, MfUltralightTypeNTAGI2CPlus2K, 492); - MfUltralightData* mfu_data = &data->mf_ul_data; - mfu_data->version.prod_ver_minor = 0x02; - mfu_data->version.storage_size = 0x15; -} - -static void nfc_generate_mf_classic_uid(uint8_t* uid, uint8_t length) { - uid[0] = NXP_MANUFACTURER_ID; - furi_hal_random_fill_buf(&uid[1], length - 1); -} - -static void - nfc_generate_mf_classic_common(MfClassicData* data, uint8_t uid_len, MfClassicType type) { - data->nfca_data.uid_len = uid_len; - data->nfca_data.atqa[0] = 0x44; - data->nfca_data.atqa[1] = 0x00; - data->nfca_data.sak = 0x08; - data->type = type; -} - -static void nfc_generate_mf_classic_sector_trailer(MfClassicData* data, uint8_t block) { - // All keys are set to FFFF FFFF FFFFh at chip delivery and the bytes 6, 7 and 8 are set to FF0780h. - MfClassicSectorTrailer* sec_tr = (MfClassicSectorTrailer*)data->block[block].data; - sec_tr->access_bits.data[0] = 0xFF; - sec_tr->access_bits.data[1] = 0x07; - sec_tr->access_bits.data[2] = 0x80; - sec_tr->access_bits.data[3] = 0x69; // Nice - - mf_classic_set_block_read(data, block, &data->block[block]); - mf_classic_set_key_found( - data, mf_classic_get_sector_by_block(block), MfClassicKeyTypeA, 0xFFFFFFFFFFFF); - mf_classic_set_key_found( - data, mf_classic_get_sector_by_block(block), MfClassicKeyTypeB, 0xFFFFFFFFFFFF); -} - -static void nfc_generate_mf_classic_block_0( - uint8_t* block, - uint8_t uid_len, - uint8_t sak, - uint8_t atqa0, - uint8_t atqa1) { - // Block length is always 16 bytes, and the UID can be either 4 or 7 bytes - furi_assert(uid_len == 4 || uid_len == 7); - furi_assert(block); - - if(uid_len == 4) { - // Calculate BCC - block[uid_len] = 0; - - for(int i = 0; i < uid_len; i++) { - block[uid_len] ^= block[i]; - } - } else { - uid_len -= 1; - } - - block[uid_len + 1] = sak; - block[uid_len + 2] = atqa0; - block[uid_len + 3] = atqa1; - - for(int i = uid_len + 4; i < 16; i++) { - block[i] = 0xFF; - } -} - -static void nfc_generate_mf_classic(NfcDevData* data, uint8_t uid_len, MfClassicType type) { - nfc_generate_common_start(data); - data->protocol = NfcDevProtocolMfClassic; - MfClassicData* mfc_data = &data->mf_classic_data; - nfc_generate_mf_classic_uid(mfc_data->block[0].data, uid_len); - nfc_generate_mf_classic_common(mfc_data, uid_len, type); - - // Set the UID - mfc_data->nfca_data.uid[0] = NXP_MANUFACTURER_ID; - for(int i = 1; i < uid_len; i++) { - mfc_data->nfca_data.uid[i] = mfc_data->block[0].data[i]; - } - - mf_classic_set_block_read(mfc_data, 0, &mfc_data->block[0]); - - uint16_t block_num = mf_classic_get_total_block_num(type); - if(type == MfClassicType4k) { - // Set every block to 0xFF - for(uint16_t i = 1; i < block_num; i += 1) { - if(mf_classic_is_sector_trailer(i)) { - nfc_generate_mf_classic_sector_trailer(mfc_data, i); - } else { - memset(&mfc_data->block[i].data, 0xFF, 16); - } - mf_classic_set_block_read(mfc_data, i, &mfc_data->block[i]); - } - // Set SAK to 18 - data->nfca_data.sak = 0x18; - } else if(type == MfClassicType1k) { - // Set every block to 0xFF - for(uint16_t i = 1; i < block_num; i += 1) { - if(mf_classic_is_sector_trailer(i)) { - nfc_generate_mf_classic_sector_trailer(mfc_data, i); - } else { - memset(&mfc_data->block[i].data, 0xFF, 16); - } - mf_classic_set_block_read(mfc_data, i, &mfc_data->block[i]); - } - // Set SAK to 08 - data->nfca_data.sak = 0x08; - } else if(type == MfClassicTypeMini) { - // Set every block to 0xFF - for(uint16_t i = 1; i < block_num; i += 1) { - if(mf_classic_is_sector_trailer(i)) { - nfc_generate_mf_classic_sector_trailer(mfc_data, i); - } else { - memset(&mfc_data->block[i].data, 0xFF, 16); - } - mf_classic_set_block_read(mfc_data, i, &mfc_data->block[i]); - } - // Set SAK to 09 - data->nfca_data.sak = 0x09; - } - - nfc_generate_mf_classic_block_0( - data->mf_classic_data.block[0].data, - uid_len, - data->nfca_data.sak, - data->nfca_data.atqa[0], - data->nfca_data.atqa[1]); - - mfc_data->type = type; -} - -static void nfc_generate_mf_classic_mini(NfcDevData* data) { - nfc_generate_mf_classic(data, 4, MfClassicTypeMini); -} - -static void nfc_generate_mf_classic_1k_4b_uid(NfcDevData* data) { - nfc_generate_mf_classic(data, 4, MfClassicType1k); -} - -static void nfc_generate_mf_classic_1k_7b_uid(NfcDevData* data) { - nfc_generate_mf_classic(data, 7, MfClassicType1k); -} - -static void nfc_generate_mf_classic_4k_4b_uid(NfcDevData* data) { - nfc_generate_mf_classic(data, 4, MfClassicType4k); -} - -static void nfc_generate_mf_classic_4k_7b_uid(NfcDevData* data) { - nfc_generate_mf_classic(data, 7, MfClassicType4k); +// static const uint8_t version_bytes_mf0ulx1[] = {0x00, 0x04, 0x03, 0x00, 0x01, 0x00, 0x00, 0x03}; +// static const uint8_t version_bytes_ntag21x[] = {0x00, 0x04, 0x04, 0x02, 0x01, 0x00, 0x00, 0x03}; +// static const uint8_t version_bytes_ntag_i2c[] = {0x00, 0x04, 0x04, 0x05, 0x02, 0x00, 0x00, 0x03}; +// static const uint8_t default_data_ntag203[] = +// {0xE1, 0x10, 0x12, 0x00, 0x01, 0x03, 0xA0, 0x10, 0x44, 0x03, 0x00, 0xFE}; +// static const uint8_t default_data_ntag213[] = {0x01, 0x03, 0xA0, 0x0C, 0x34, 0x03, 0x00, 0xFE}; +// static const uint8_t default_data_ntag215_216[] = {0x03, 0x00, 0xFE}; +// static const uint8_t default_data_ntag_i2c[] = {0xE1, 0x10, 0x00, 0x00, 0x03, 0x00, 0xFE}; +// static const uint8_t default_config_ntag_i2c[] = {0x01, 0x00, 0xF8, 0x48, 0x08, 0x01, 0x00, 0x00}; +// +// static void nfc_generate_common_start(NfcProtocolData* data) { +// memset(data, 0, sizeof(NfcProtocolData)); +// } + +// static void nfc_generate_mf_ul_uid(uint8_t* uid) { +// uid[0] = NXP_MANUFACTURER_ID; +// furi_hal_random_fill_buf(&uid[1], 6); +// // I'm not sure how this is generated, but the upper nybble always seems to be 8 +// uid[6] &= 0x0F; +// uid[6] |= 0x80; +// } + +// static void nfc_generate_mf_ul_common(NfcProtocolData* data) { +// MfUltralightData* mfu_data = data->mf_ul_data; +// mfu_data->nfca_data->uid_len = 7; +// nfc_generate_mf_ul_uid(mfu_data->nfca_data->uid); +// mfu_data->nfca_data->atqa[0] = 0x44; +// mfu_data->nfca_data->atqa[1] = 0x00; +// mfu_data->nfca_data->sak = 0x00; +// data->protocol = NfcDevProtocolMfUltralight; +// } + +// static void nfc_generate_calc_bcc(uint8_t* uid, uint8_t* bcc0, uint8_t* bcc1) { +// *bcc0 = 0x88 ^ uid[0] ^ uid[1] ^ uid[2]; +// *bcc1 = uid[3] ^ uid[4] ^ uid[5] ^ uid[6]; +// } + +// static void nfc_generate_mf_ul_copy_uid_with_bcc(NfcProtocolData* data) { +// MfUltralightData* mfu_data = data->mf_ul_data; +// memcpy(mfu_data->page[0].data, mfu_data->nfca_data->uid, 3); +// memcpy(mfu_data->page[1].data, &mfu_data->nfca_data->uid[3], 4); +// +// nfc_generate_calc_bcc( +// mfu_data->nfca_data->uid, &mfu_data->page[0].data[3], &mfu_data->page[2].data[0]); +// } + +static void nfc_generate_mf_ul_orig(NfcProtocolData* data) { + UNUSED(data); + // nfc_generate_common_start(data); + // nfc_generate_mf_ul_common(data); + + // MfUltralightData* mfu_data = data->mf_ul_data; + // mfu_data->type = MfUltralightTypeUnknown; + // mfu_data->pages_total = 16; + // mfu_data->pages_read = 16; + // nfc_generate_mf_ul_copy_uid_with_bcc(data); + // // TODO: what's internal byte on page 2? + // memset(&mfu_data->page[4], 0xff, sizeof(MfUltralightPage)); +} + +// static void nfc_generate_mf_ul_with_config_common(NfcProtocolData* data, uint8_t num_pages) { +// nfc_generate_common_start(data); +// nfc_generate_mf_ul_common(data); + +// MfUltralightData* mfu_data = data->mf_ul_data; +// mfu_data->pages_total = num_pages; +// mfu_data->pages_read = num_pages; +// nfc_generate_mf_ul_copy_uid_with_bcc(data); +// uint16_t config_index = (num_pages - 4); +// mfu_data->page[config_index].data[0] = 0x04; // STRG_MOD_EN +// mfu_data->page[config_index].data[3] = 0xff; // AUTH0 +// mfu_data->page[config_index + 1].data[1] = 0x05; // VCTID +// memset(&mfu_data->page[config_index + 2], 0xff, sizeof(MfUltralightPage)); // Default PWD +// if(num_pages > 20) { +// mfu_data->page[config_index - 1].data[3] = MF_ULTRALIGHT_TEARING_FLAG_DEFAULT; +// } +// } + +// static void nfc_generate_mf_ul_ev1_common(NfcProtocolData* data, uint8_t num_pages) { +// nfc_generate_mf_ul_with_config_common(data, num_pages); +// MfUltralightData* mfu_data = data->mf_ul_data; +// memcpy(&mfu_data->version, version_bytes_mf0ulx1, sizeof(MfUltralightVersion)); +// for(size_t i = 0; i < 3; ++i) { +// mfu_data->tearing_flag[i].data[0] = MF_ULTRALIGHT_TEARING_FLAG_DEFAULT; +// } +// TODO: what's internal byte on page 2? +// } + +static void nfc_generate_mf_ul_11(NfcProtocolData* data) { + UNUSED(data); + // nfc_generate_mf_ul_ev1_common(data, 20); + // MfUltralightData* mfu_data = data->mf_ul_data; + // mfu_data->type = MfUltralightTypeUL11; + // mfu_data->version.prod_subtype = 0x01; + // mfu_data->version.storage_size = 0x0B; + // mfu_data->page[16].data[0] = 0x00; // Low capacitance version does not have STRG_MOD_EN +} + +static void nfc_generate_mf_ul_h11(NfcProtocolData* data) { + UNUSED(data); + // nfc_generate_mf_ul_ev1_common(data, 20); + // MfUltralightData* mfu_data = data->mf_ul_data; + // mfu_data->type = MfUltralightTypeUL11; + // mfu_data->version.prod_subtype = 0x02; + // mfu_data->version.storage_size = 0x0B; +} + +static void nfc_generate_mf_ul_21(NfcProtocolData* data) { + UNUSED(data); + // nfc_generate_mf_ul_ev1_common(data, 41); + // MfUltralightData* mfu_data = data->mf_ul_data; + // mfu_data->type = MfUltralightTypeUL21; + // mfu_data->version.prod_subtype = 0x01; + // mfu_data->version.storage_size = 0x0E; + // mfu_data->page[37].data[0] = 0x00; // Low capacitance version does not have STRG_MOD_EN +} + +static void nfc_generate_mf_ul_h21(NfcProtocolData* data) { + UNUSED(data); + // nfc_generate_mf_ul_ev1_common(data, 41); + // MfUltralightData* mfu_data = data->mf_ul_data; + // mfu_data->type = MfUltralightTypeUL21; + // mfu_data->version.prod_subtype = 0x02; + // mfu_data->version.storage_size = 0x0E; +} + +static void nfc_generate_ntag203(NfcProtocolData* data) { + UNUSED(data); + // nfc_generate_common_start(data); + // nfc_generate_mf_ul_common(data); + + // MfUltralightData* mfu_data = data->mf_ul_data; + // mfu_data->type = MfUltralightTypeNTAG203; + // mfu_data->pages_total = 42; + // mfu_data->pages_read = 42; + // nfc_generate_mf_ul_copy_uid_with_bcc(data); + // mfu_data->page[2].data[1] = 0x48; // Internal byte + // memcpy(&mfu_data->page[3], default_data_ntag203, sizeof(MfUltralightPage)); +} + +// static void nfc_generate_ntag21x_common(NfcProtocolData* data, uint8_t num_pages) { +// nfc_generate_mf_ul_with_config_common(data, num_pages); +// MfUltralightData* mfu_data = data->mf_ul_data; +// memcpy(&mfu_data->version, version_bytes_ntag21x, sizeof(MfUltralightVersion)); +// mfu_data->page[2].data[1] = 0x48; // Internal byte +// // Capability container +// mfu_data->page[3].data[0] = 0xE1; +// mfu_data->page[3].data[1] = 0x10; +// } + +static void nfc_generate_ntag213(NfcProtocolData* data) { + UNUSED(data); + // nfc_generate_ntag21x_common(data, 45); + // MfUltralightData* mfu_data = data->mf_ul_data; + // mfu_data->type = MfUltralightTypeNTAG213; + // mfu_data->version.storage_size = 0x0F; + // mfu_data->page[3].data[2] = 0x12; + // // Default contents + // memcpy(&mfu_data->page[4], default_data_ntag213, sizeof(default_data_ntag213)); +} + +static void nfc_generate_ntag215(NfcProtocolData* data) { + UNUSED(data); + // nfc_generate_ntag21x_common(data, 135); + // MfUltralightData* mfu_data = data->mf_ul_data; + // mfu_data->type = MfUltralightTypeNTAG215; + // mfu_data->version.storage_size = 0x11; + // mfu_data->page[3].data[2] = 0x3E; + // // Default contents + // memcpy(&mfu_data->page[4], default_data_ntag215_216, sizeof(default_data_ntag215_216)); +} + +static void nfc_generate_ntag216(NfcProtocolData* data) { + UNUSED(data); + // nfc_generate_ntag21x_common(data, 231); + // MfUltralightData* mfu_data = data->mf_ul_data; + // mfu_data->type = MfUltralightTypeNTAG216; + // mfu_data->version.storage_size = 0x13; + // mfu_data->page[3].data[2] = 0x6D; + // // Default contents + // memcpy(&mfu_data->page[4], default_data_ntag215_216, sizeof(default_data_ntag215_216)); +} + +// static void +// nfc_generate_ntag_i2c_common(NfcProtocolData* data, MfUltralightType type, uint16_t num_pages) { +// nfc_generate_common_start(data); +// nfc_generate_mf_ul_common(data); + +// MfUltralightData* mfu_data = data->mf_ul_data; +// mfu_data->type = type; +// memcpy(&mfu_data->version, version_bytes_ntag_i2c, sizeof(version_bytes_ntag_i2c)); +// mfu_data->pages_total = num_pages; +// mfu_data->pages_read = num_pages; +// memcpy(mfu_data->page[0].data, mfu_data->nfca_data->uid, mfu_data->nfca_data->uid_len); +// mfu_data->page[1].data[3] = mfu_data->nfca_data->sak; +// mfu_data->page[2].data[0] = mfu_data->nfca_data->atqa[0]; +// mfu_data->page[2].data[1] = mfu_data->nfca_data->atqa[1]; + +// uint16_t config_register_page = 0; +// uint16_t session_register_page = 0; +// +// // Sync with mifare_ultralight.c +// switch(type) { +// case MfUltralightTypeNTAGI2C1K: +// config_register_page = 227; +// session_register_page = 229; +// break; +// case MfUltralightTypeNTAGI2C2K: +// config_register_page = 481; +// session_register_page = 483; +// break; +// case MfUltralightTypeNTAGI2CPlus1K: +// case MfUltralightTypeNTAGI2CPlus2K: +// config_register_page = 232; +// session_register_page = 234; +// break; +// default: +// furi_crash("Unknown MFUL"); +// break; +// } +// +// memcpy( +// &mfu_data->page[config_register_page], +// default_config_ntag_i2c, +// sizeof(default_config_ntag_i2c)); +// memcpy( +// &mfu_data->page[session_register_page], +// default_config_ntag_i2c, +// sizeof(default_config_ntag_i2c)); +// } + +static void nfc_generate_ntag_i2c_1k(NfcProtocolData* data) { + UNUSED(data); + // nfc_generate_ntag_i2c_common(data, MfUltralightTypeNTAGI2C1K, 231); + // MfUltralightData* mfu_data = data->mf_ul_data; + // mfu_data->version.prod_ver_minor = 0x01; + // mfu_data->version.storage_size = 0x13; + // + // memcpy(&mfu_data->page[3], default_data_ntag_i2c, sizeof(default_data_ntag_i2c)); + // mfu_data->page[3].data[2] = 0x6D; // Size of tag in CC +} + +static void nfc_generate_ntag_i2c_2k(NfcProtocolData* data) { + UNUSED(data); + // nfc_generate_ntag_i2c_common(data, MfUltralightTypeNTAGI2C2K, 485); + // MfUltralightData* mfu_data = data->mf_ul_data; + // mfu_data->version.prod_ver_minor = 0x01; + // mfu_data->version.storage_size = 0x15; + // + // memcpy(&mfu_data->page[3], default_data_ntag_i2c, sizeof(default_data_ntag_i2c)); + // mfu_data->page[3].data[2] = 0xEA; // Size of tag in CC +} + +// static void +// nfc_generate_ntag_i2c_plus_common(NfcProtocolData* data, MfUltralightType type, uint16_t num_pages) { +// nfc_generate_ntag_i2c_common(data, type, num_pages); +// +// MfUltralightData* mfu_data = data->mf_ul_data; +// uint16_t config_index = 227; +// mfu_data->page[config_index].data[3] = 0xff; // AUTH0 +// +// memset(&mfu_data->page[config_index + 2], 0xFF, sizeof(MfUltralightPage)); // Default PWD +// } + +static void nfc_generate_ntag_i2c_plus_1k(NfcProtocolData* data) { + UNUSED(data); + // nfc_generate_ntag_i2c_plus_common(data, MfUltralightTypeNTAGI2CPlus1K, 236); + // MfUltralightData* mfu_data = data->mf_ul_data; + // mfu_data->version.prod_ver_minor = 0x02; + // mfu_data->version.storage_size = 0x13; +} + +static void nfc_generate_ntag_i2c_plus_2k(NfcProtocolData* data) { + UNUSED(data); + // nfc_generate_ntag_i2c_plus_common(data, MfUltralightTypeNTAGI2CPlus2K, 492); + // MfUltralightData* mfu_data = data->mf_ul_data; + // mfu_data->version.prod_ver_minor = 0x02; + // mfu_data->version.storage_size = 0x15; +} + +// static void nfc_generate_mf_classic_uid(uint8_t* uid, uint8_t length) { +// uid[0] = NXP_MANUFACTURER_ID; +// furi_hal_random_fill_buf(&uid[1], length - 1); +// } + +// static void +// nfc_generate_mf_classic_common(MfClassicData* data, uint8_t uid_len, MfClassicType type) { +// data->nfca_data->uid_len = uid_len; +// data->nfca_data->atqa[0] = 0x44; +// data->nfca_data->atqa[1] = 0x00; +// data->nfca_data->sak = 0x08; +// data->type = type; +// } + +// static void nfc_generate_mf_classic_sector_trailer(MfClassicData* data, uint8_t block) { +// All keys are set to FFFF FFFF FFFFh at chip delivery and the bytes 6, 7 and 8 are set to FF0780h. +// MfClassicSectorTrailer* sec_tr = (MfClassicSectorTrailer*)data->block[block].data; +// sec_tr->access_bits.data[0] = 0xFF; +// sec_tr->access_bits.data[1] = 0x07; +// sec_tr->access_bits.data[2] = 0x80; +// sec_tr->access_bits.data[3] = 0x69; // Nice +// +// mf_classic_set_block_read(data, block, &data->block[block]); +// mf_classic_set_key_found( +// data, mf_classic_get_sector_by_block(block), MfClassicKeyTypeA, 0xFFFFFFFFFFFF); +// mf_classic_set_key_found( +// data, mf_classic_get_sector_by_block(block), MfClassicKeyTypeB, 0xFFFFFFFFFFFF); +// } + +// static void nfc_generate_mf_classic_block_0( +// uint8_t* block, +// uint8_t uid_len, +// uint8_t sak, +// uint8_t atqa0, +// uint8_t atqa1) { +// // Block length is always 16 bytes, and the UID can be either 4 or 7 bytes +// furi_assert(uid_len == 4 || uid_len == 7); +// furi_assert(block); +// +// if(uid_len == 4) { +// // Calculate BCC +// block[uid_len] = 0; +// +// for(int i = 0; i < uid_len; i++) { +// block[uid_len] ^= block[i]; +// } +// } else { +// uid_len -= 1; +// } +// +// block[uid_len + 1] = sak; +// block[uid_len + 2] = atqa0; +// block[uid_len + 3] = atqa1; +// +// for(int i = uid_len + 4; i < 16; i++) { +// block[i] = 0xFF; +// } +// } + +// static void nfc_generate_mf_classic(NfcProtocolData* data, uint8_t uid_len, MfClassicType type) { +// nfc_generate_common_start(data); +// data->protocol = NfcDevProtocolMfClassic; +// MfClassicData* mfc_data = data->mf_classic_data; +// nfc_generate_mf_classic_uid(mfc_data->block[0].data, uid_len); +// nfc_generate_mf_classic_common(mfc_data, uid_len, type); +// +// // Set the UID +// mfc_data->nfca_data->uid[0] = NXP_MANUFACTURER_ID; +// for(int i = 1; i < uid_len; i++) { +// mfc_data->nfca_data->uid[i] = mfc_data->block[0].data[i]; +// } +// +// mf_classic_set_block_read(mfc_data, 0, &mfc_data->block[0]); +// +// uint16_t block_num = mf_classic_get_total_block_num(type); +// if(type == MfClassicType4k) { +// // Set every block to 0xFF +// for(uint16_t i = 1; i < block_num; i += 1) { +// if(mf_classic_is_sector_trailer(i)) { +// nfc_generate_mf_classic_sector_trailer(mfc_data, i); +// } else { +// memset(&mfc_data->block[i].data, 0xFF, 16); +// } +// mf_classic_set_block_read(mfc_data, i, &mfc_data->block[i]); +// } +// // Set SAK to 18 +// data->nfca_data->sak = 0x18; +// } else if(type == MfClassicType1k) { +// // Set every block to 0xFF +// for(uint16_t i = 1; i < block_num; i += 1) { +// if(mf_classic_is_sector_trailer(i)) { +// nfc_generate_mf_classic_sector_trailer(mfc_data, i); +// } else { +// memset(&mfc_data->block[i].data, 0xFF, 16); +// } +// mf_classic_set_block_read(mfc_data, i, &mfc_data->block[i]); +// } +// // Set SAK to 08 +// data->nfca_data->sak = 0x08; +// } else if(type == MfClassicTypeMini) { +// // Set every block to 0xFF +// for(uint16_t i = 1; i < block_num; i += 1) { +// if(mf_classic_is_sector_trailer(i)) { +// nfc_generate_mf_classic_sector_trailer(mfc_data, i); +// } else { +// memset(&mfc_data->block[i].data, 0xFF, 16); +// } +// mf_classic_set_block_read(mfc_data, i, &mfc_data->block[i]); +// } +// // Set SAK to 09 +// data->nfca_data->sak = 0x09; +// } +// +// nfc_generate_mf_classic_block_0( +// data->mf_classic_data->block[0].data, +// uid_len, +// data->nfca_data->sak, +// data->nfca_data->atqa[0], +// data->nfca_data->atqa[1]); +// +// mfc_data->type = type; +// } + +static void nfc_generate_mf_classic_mini(NfcProtocolData* data) { + UNUSED(data); + // nfc_generate_mf_classic(data, 4, MfClassicTypeMini); +} + +static void nfc_generate_mf_classic_1k_4b_uid(NfcProtocolData* data) { + UNUSED(data); + // nfc_generate_mf_classic(data, 4, MfClassicType1k); +} + +static void nfc_generate_mf_classic_1k_7b_uid(NfcProtocolData* data) { + UNUSED(data); + // nfc_generate_mf_classic(data, 7, MfClassicType1k); +} + +static void nfc_generate_mf_classic_4k_4b_uid(NfcProtocolData* data) { + UNUSED(data); + // nfc_generate_mf_classic(data, 4, MfClassicType4k); +} + +static void nfc_generate_mf_classic_4k_7b_uid(NfcProtocolData* data) { + UNUSED(data); + // nfc_generate_mf_classic(data, 7, MfClassicType4k); } static const NfcDataGenerator nfc_data_generator[NfcDataGeneratorTypeNum] = { @@ -519,6 +540,6 @@ const char* nfc_data_generator_get_name(NfcDataGeneratorType type) { return nfc_data_generator[type].name; } -void nfc_data_generator_fill_data(NfcDataGeneratorType type, NfcDevData* data) { +void nfc_data_generator_fill_data(NfcDataGeneratorType type, NfcProtocolData* data) { nfc_data_generator[type].handler(data); } diff --git a/lib/nfc/helpers/nfc_data_generator.h b/lib/nfc/helpers/nfc_data_generator.h index 81e179b7cfba..fc114322dc43 100644 --- a/lib/nfc/helpers/nfc_data_generator.h +++ b/lib/nfc/helpers/nfc_data_generator.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #ifdef __cplusplus extern "C" { @@ -33,7 +33,7 @@ typedef enum { const char* nfc_data_generator_get_name(NfcDataGeneratorType type); -void nfc_data_generator_fill_data(NfcDataGeneratorType type, NfcDevData* data); +void nfc_data_generator_fill_data(NfcDataGeneratorType type, NfcProtocolData* data); #ifdef __cplusplus } diff --git a/lib/nfc/nfc_common.h b/lib/nfc/nfc_common.h new file mode 100644 index 000000000000..dbc1f42b7486 --- /dev/null +++ b/lib/nfc/nfc_common.h @@ -0,0 +1,12 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#define NFC_CURRENT_FORMAT_VERSION (3) +#define NFC_LSB_ATQA_FORMAT_VERSION (2) + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/nfc_dev.c b/lib/nfc/nfc_dev.c index bed58250201e..131e57541c9c 100644 --- a/lib/nfc/nfc_dev.c +++ b/lib/nfc/nfc_dev.c @@ -1,604 +1,111 @@ #include "nfc_dev.h" +#include #include #include -#include "protocols/nfc_util.h" -#include - -static const char* nfc_file_header = "Flipper NFC device"; -static const uint32_t nfc_file_version = 3; -static const uint32_t nfc_file_version_with_lsb_atqa = 2; - -// static const char* nfc_keys_file_header = "Flipper NFC keys"; -// static const uint32_t nfc_keys_file_version = 1; - -// Protocols format versions -static const uint32_t nfc_mifare_classic_data_format_version = 2; -static const uint32_t nfc_mifare_ultralight_data_format_version = 1; +#define NFC_FILE_HEADER "Flipper NFC device" +#define NFC_DEV_TYPE_ERROR "Protocol type mismatch" struct NfcDev { - bool shadow_file_exist; + NfcProtocolType protocol_type; + NfcProtocolData* protocol_data; NfcLoadingCallback loading_callback; void* loading_callback_context; }; -typedef bool (*NfcDevVerifyProtocol)(FuriString* device_type, NfcDevData* data); -typedef bool (*NfcDevDataHandler)(FlipperFormat* file, uint32_t version, NfcDevData* data); - -typedef struct { - NfcDevVerifyProtocol verify_handler; - NfcDevDataHandler load_handler; - NfcDevDataHandler save_handler; -} NfcDevDataParser; - -static bool nfc_dev_nfca_load_data(FlipperFormat* file, uint32_t version, NfcaData* data) { - furi_assert(file); - furi_assert(data); - - uint32_t data_cnt = 0; - bool parsed = false; - - do { - if(!flipper_format_get_value_count(file, "UID", &data_cnt)) break; - if(!(data_cnt == 4 || data_cnt == 7)) break; - data->uid_len = data_cnt; - if(!flipper_format_read_hex(file, "UID", data->uid, data->uid_len)) break; - if(version == nfc_file_version_with_lsb_atqa) { - if(!flipper_format_read_hex(file, "ATQA", data->atqa, 2)) break; - } else { - uint8_t atqa[2] = {}; - if(!flipper_format_read_hex(file, "ATQA", atqa, 2)) break; - data->atqa[0] = atqa[1]; - data->atqa[1] = atqa[0]; - } - if(!flipper_format_read_hex(file, "SAK", &data->sak, 1)) break; - - parsed = true; - } while(false); +NfcDev* nfc_dev_alloc() { + NfcDev* instance = malloc(sizeof(NfcDev)); - return parsed; + return instance; } -static bool nfc_dev_nfca_save_data(FlipperFormat* file, NfcaData* data) { - furi_assert(file); - furi_assert(data); - - bool saved = false; - do { - // Write UID, ATQA, SAK - if(!flipper_format_write_comment_cstr(file, "UID, ATQA and SAK are common for all formats")) - break; - if(!flipper_format_write_hex(file, "UID", data->uid, data->uid_len)) break; - // Save ATQA in MSB order for correct companion apps display - uint8_t atqa[2] = {data->atqa[1], data->atqa[0]}; - if(!flipper_format_write_hex(file, "ATQA", atqa, 2)) break; - if(!flipper_format_write_hex(file, "SAK", &data->sak, 1)) break; - saved = true; - } while(false); +void nfc_dev_free(NfcDev* instance) { + furi_assert(instance); - return saved; + nfc_dev_clear(instance); + free(instance); } -static bool nfc_dev_nfca_verify_handler(FuriString* device_type, NfcDevData* data) { - furi_assert(device_type); - furi_assert(data); +void nfc_dev_clear(NfcDev* instance) { + furi_assert(instance); + furi_assert(instance->protocol_type < NfcProtocolTypeMax); - bool verified = (furi_string_cmp_str(device_type, "UID") == 0); - if(verified) { - data->protocol = NfcDevProtocolNfca; + if(instance->protocol_data) { + nfc_protocols[instance->protocol_type]->free(instance->protocol_data); + instance->protocol_data = NULL; } - - return verified; -} - -static bool nfc_dev_nfca_save_handler(FlipperFormat* file, uint32_t version, NfcDevData* data) { - furi_assert(file); - furi_assert(data); - UNUSED(version); - - bool saved = false; - do { - if(!flipper_format_write_string_cstr(file, "Device type", "UID")) break; - if(!nfc_dev_nfca_save_data(file, &data->nfca_data)) break; - saved = true; - } while(false); - - return saved; } -static bool nfc_dev_nfca_load_handler(FlipperFormat* file, uint32_t version, NfcDevData* data) { - furi_assert(file); - furi_assert(data); - UNUSED(version); - - return nfc_dev_nfca_load_data(file, version, &data->nfca_data); -} +void nfc_dev_reset(NfcDev* instance) { + furi_assert(instance); + furi_assert(instance->protocol_type < NfcProtocolTypeMax); -static bool nfc_dev_mf_ultralight_verify_handler(FuriString* device_type, NfcDevData* data) { - furi_assert(device_type); - furi_assert(data); - - bool verified = false; - for(size_t i = 0; i < MfUltralightTypeNum; i++) { - const char* name = mf_ultralight_get_name(i, true); - verified = furi_string_equal_str(device_type, name); - if(verified) { - data->protocol = NfcDevProtocolMfUltralight; - data->mf_ul_data.type = i; - break; - } + if(instance->protocol_data) { + nfc_protocols[instance->protocol_type]->reset(instance->protocol_data); } - - return verified; -} - -static bool - nfc_dev_mf_ultralight_save_handler(FlipperFormat* file, uint32_t version, NfcDevData* data) { - furi_assert(file); - furi_assert(data); - UNUSED(version); - - FuriString* temp_str = furi_string_alloc(); - MfUltralightData* mfu_data = &data->mf_ul_data; - bool saved = false; - do { - const char* device_type_name = mf_ultralight_get_name(mfu_data->type, true); - if(!flipper_format_write_string_cstr(file, "Device type", device_type_name)) break; - if(!nfc_dev_nfca_save_data(file, &data->nfca_data)) break; - if(!flipper_format_write_comment_cstr(file, "Mifare Ultralight specific data")) break; - if(!flipper_format_write_uint32( - file, "Data format version", &nfc_mifare_ultralight_data_format_version, 1)) - break; - if(!flipper_format_write_hex( - file, "Signature", mfu_data->signature.data, sizeof(MfUltralightSignature))) - break; - if(!flipper_format_write_hex( - file, "Mifare version", (uint8_t*)&mfu_data->version, sizeof(MfUltralightVersion))) - break; - - // Write conters and tearing flags data - bool counters_saved = true; - for(size_t i = 0; i < 3; i++) { - furi_string_printf(temp_str, "Counter %d", i); - if(!flipper_format_write_uint32( - file, furi_string_get_cstr(temp_str), &mfu_data->counter[i].counter, 1)) { - counters_saved = false; - break; - } - furi_string_printf(temp_str, "Tearing %d", i); - if(!flipper_format_write_hex( - file, furi_string_get_cstr(temp_str), mfu_data->tearing_flag->data, 1)) { - counters_saved = false; - break; - } - } - if(!counters_saved) break; - - // Write pages data - uint32_t pages_total = mfu_data->pages_total; - uint32_t pages_read = mfu_data->pages_read; - if(!flipper_format_write_uint32(file, "Pages total", &pages_total, 1)) break; - if(!flipper_format_write_uint32(file, "Pages read", &pages_read, 1)) break; - bool pages_saved = true; - for(size_t i = 0; i < mfu_data->pages_total; i++) { - furi_string_printf(temp_str, "Page %d", i); - if(!flipper_format_write_hex( - file, - furi_string_get_cstr(temp_str), - mfu_data->page[i].data, - sizeof(MfUltralightPage))) { - pages_saved = false; - break; - } - } - if(!pages_saved) break; - - // Write authentication counter - if(!flipper_format_write_uint32( - file, "Failed authentication attempts", &mfu_data->auth_attempts, 1)) - break; - - saved = true; - } while(false); - - furi_string_free(temp_str); - - return saved; } -static bool - nfc_dev_mf_ultralight_load_handler(FlipperFormat* file, uint32_t version, NfcDevData* data) { - furi_assert(file); - furi_assert(data); - - FuriString* temp_str = furi_string_alloc(); - bool parsed = false; - do { - // Read NFCA data - if(!nfc_dev_nfca_load_data(file, version, &data->mf_ul_data.nfca_data)) break; - - // Read Ultralight specific data - // Read Mifare Ultralight format version - uint32_t data_format_version = 0; - if(!flipper_format_read_uint32(file, "Data format version", &data_format_version, 1)) { - if(!flipper_format_rewind(file)) break; - } - - // Read signature - MfUltralightData* mfu_data = &data->mf_ul_data; - if(!flipper_format_read_hex( - file, "Signature", mfu_data->signature.data, sizeof(MfUltralightSignature))) - break; - // Read Mifare version - if(!flipper_format_read_hex( - file, "Mifare version", (uint8_t*)&mfu_data->version, sizeof(MfUltralightVersion))) - break; - // Read counters and tearing flags - bool counters_parsed = true; - for(size_t i = 0; i < 3; i++) { - furi_string_printf(temp_str, "Counter %d", i); - if(!flipper_format_read_uint32( - file, furi_string_get_cstr(temp_str), &mfu_data->counter[i].counter, 1)) { - counters_parsed = false; - break; - } - furi_string_printf(temp_str, "Tearing %d", i); - if(!flipper_format_read_hex( - file, furi_string_get_cstr(temp_str), mfu_data->tearing_flag[i].data, 1)) { - counters_parsed = false; - break; - } - } - if(!counters_parsed) break; - // Read pages - uint32_t pages_total = 0; - if(!flipper_format_read_uint32(file, "Pages total", &pages_total, 1)) break; - uint32_t pages_read = 0; - if(data_format_version < nfc_mifare_ultralight_data_format_version) { - pages_read = pages_total; - } else { - if(!flipper_format_read_uint32(file, "Pages read", &pages_read, 1)) break; - } - mfu_data->pages_total = pages_total; - mfu_data->pages_read = pages_read; - - if((pages_read > MF_ULTRALIGHT_MAX_PAGE_NUM) || (pages_total > MF_ULTRALIGHT_MAX_PAGE_NUM)) - break; - - bool pages_parsed = true; - for(size_t i = 0; i < pages_total; i++) { - furi_string_printf(temp_str, "Page %d", i); - if(!flipper_format_read_hex( - file, - furi_string_get_cstr(temp_str), - mfu_data->page[i].data, - sizeof(MfUltralightPage))) { - pages_parsed = false; - break; - } - } - if(!pages_parsed) break; - - // Read authentication counter - if(!flipper_format_read_uint32( - file, "Failed authentication attempts", &mfu_data->auth_attempts, 1)) { - mfu_data->auth_attempts = 0; - } - - parsed = true; - } while(false); - - furi_string_free(temp_str); - - return parsed; +NfcProtocolType nfc_dev_get_protocol_type(const NfcDev* instance) { + furi_assert(instance); + return instance->protocol_type; } -static bool nfc_dev_mf_classic_verify_handler(FuriString* device_type, NfcDevData* data) { - furi_assert(device_type); - furi_assert(data); +const NfcProtocolData* + nfc_dev_get_protocol_data(const NfcDev* instance, NfcProtocolType protocol_type) { + furi_assert(instance); + furi_assert(protocol_type < NfcProtocolTypeMax); - bool verified = furi_string_equal_str(device_type, "Mifare Classic"); - if(verified) { - data->protocol = NfcDevProtocolMfClassic; + if(instance->protocol_type != protocol_type) { + furi_crash(NFC_DEV_TYPE_ERROR); } - return verified; -} - -static void nfc_dev_set_mf_classic_block_str( - FuriString* block_str, - MfClassicData* data, - uint8_t block_num) { - furi_string_reset(block_str); - bool is_sec_trailer = mf_classic_is_sector_trailer(block_num); - if(is_sec_trailer) { - uint8_t sector_num = mf_classic_get_sector_by_block(block_num); - MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(data, sector_num); - // Write key A - for(size_t i = 0; i < sizeof(sec_tr->key_a); i++) { - if(mf_classic_is_key_found(data, sector_num, MfClassicKeyTypeA)) { - furi_string_cat_printf(block_str, "%02X ", sec_tr->key_a.data[i]); - } else { - furi_string_cat_printf(block_str, "?? "); - } - } - // Write Access bytes - for(size_t i = 0; i < MF_CLASSIC_ACCESS_BYTES_SIZE; i++) { - if(mf_classic_is_block_read(data, block_num)) { - furi_string_cat_printf(block_str, "%02X ", sec_tr->access_bits.data[i]); - } else { - furi_string_cat_printf(block_str, "?? "); - } - } - // Write key B - for(size_t i = 0; i < sizeof(sec_tr->key_b); i++) { - if(mf_classic_is_key_found(data, sector_num, MfClassicKeyTypeB)) { - furi_string_cat_printf(block_str, "%02X ", sec_tr->key_b.data[i]); - } else { - furi_string_cat_printf(block_str, "?? "); - } - } - } else { - // Write data block - for(size_t i = 0; i < MF_CLASSIC_BLOCK_SIZE; i++) { - if(mf_classic_is_block_read(data, block_num)) { - furi_string_cat_printf(block_str, "%02X ", data->block[block_num].data[i]); - } else { - furi_string_cat_printf(block_str, "?? "); - } - } - } - furi_string_trim(block_str); + return instance->protocol_data; } -static bool - nfc_dev_mf_classic_save_handler(FlipperFormat* file, uint32_t version, NfcDevData* data) { - furi_assert(file); - furi_assert(data); - UNUSED(version); - - FuriString* temp_str = furi_string_alloc(); - MfClassicData* mfc_data = &data->mf_classic_data; - bool saved = false; - - do { - if(!flipper_format_write_string_cstr(file, "Device type", "Mifare Classic")) break; - if(!nfc_dev_nfca_save_data(file, &data->nfca_data)) break; - if(!flipper_format_write_string_cstr(file, "Device type", "")) break; - if(!flipper_format_write_comment_cstr(file, "Mifare Classic specific data")) break; - const char* type_name = mf_classic_get_name(mfc_data->type, false); - if(!flipper_format_write_string_cstr(file, "Mifare Classic type", type_name)) break; - if(!flipper_format_write_uint32( - file, "Data format version", &nfc_mifare_classic_data_format_version, 1)) - break; - if(!flipper_format_write_comment_cstr( - file, "Mifare Classic blocks, \'??\' means unknown data")) - break; - - uint16_t blocks_total = mf_classic_get_total_block_num(mfc_data->type); - FuriString* block_str = furi_string_alloc(); - bool block_saved = true; - for(size_t i = 0; i < blocks_total; i++) { - furi_string_printf(temp_str, "Block %d", i); - nfc_dev_set_mf_classic_block_str(block_str, mfc_data, i); - if(!flipper_format_write_string(file, furi_string_get_cstr(temp_str), block_str)) { - block_saved = false; - break; - } - } - furi_string_free(block_str); - if(!block_saved) break; - - saved = true; - } while(false); - - furi_string_free(temp_str); +const char* nfc_dev_get_protocol_name(const NfcDev* instance, NfcProtocolNameType name_type) { + furi_assert(instance); + furi_assert(instance->protocol_type < NfcProtocolTypeMax); - return saved; + return nfc_protocols[instance->protocol_type]->get_name(instance->protocol_data, name_type); } -static void nfc_device_parse_mifare_classic_block( - FuriString* block_str, - MfClassicData* data, - uint8_t block_num) { - furi_string_trim(block_str); - MfClassicBlock block_tmp = {}; - bool is_sector_trailer = mf_classic_is_sector_trailer(block_num); - uint8_t sector_num = mf_classic_get_sector_by_block(block_num); - uint16_t block_unknown_bytes_mask = 0; - - furi_string_trim(block_str); - for(size_t i = 0; i < MF_CLASSIC_BLOCK_SIZE; i++) { - char hi = furi_string_get_char(block_str, 3 * i); - char low = furi_string_get_char(block_str, 3 * i + 1); - uint8_t byte = 0; - if(hex_char_to_uint8(hi, low, &byte)) { - block_tmp.data[i] = byte; - } else { - FURI_BIT_SET(block_unknown_bytes_mask, i); - } - } +const uint8_t* nfc_dev_get_uid(const NfcDev* instance, size_t* uid_len) { + furi_assert(instance); + furi_assert(instance->protocol_type < NfcProtocolTypeMax); - if(block_unknown_bytes_mask != 0xffff) { - if(is_sector_trailer) { - MfClassicSectorTrailer* sec_tr_tmp = (MfClassicSectorTrailer*)&block_tmp; - // Load Key A - // Key A mask 0b0000000000111111 = 0x003f - if((block_unknown_bytes_mask & 0x003f) == 0) { - uint64_t key = nfc_util_bytes2num(sec_tr_tmp->key_a.data, sizeof(MfClassicKey)); - mf_classic_set_key_found(data, sector_num, MfClassicKeyTypeA, key); - } - // Load Access Bits - // Access bits mask 0b0000001111000000 = 0x03c0 - if((block_unknown_bytes_mask & 0x03c0) == 0) { - mf_classic_set_block_read(data, block_num, &block_tmp); - } - // Load Key B - // Key B mask 0b1111110000000000 = 0xfc00 - if((block_unknown_bytes_mask & 0xfc00) == 0) { - uint64_t key = nfc_util_bytes2num(sec_tr_tmp->key_b.data, sizeof(MfClassicKey)); - mf_classic_set_key_found(data, sector_num, MfClassicKeyTypeB, key); - } - } else { - if(block_unknown_bytes_mask == 0) { - mf_classic_set_block_read(data, block_num, &block_tmp); - } - } - } + return nfc_protocols[instance->protocol_type]->get_uid(instance->protocol_data, uid_len); } -static bool - nfc_dev_mf_classic_load_handler(FlipperFormat* file, uint32_t version, NfcDevData* data) { - furi_assert(file); - furi_assert(data); - - MfClassicData* mfc_data = &data->mf_classic_data; - FuriString* temp_str = furi_string_alloc(); - bool parsed = false; - - do { - // Read NFCA data - if(!nfc_dev_nfca_load_data(file, version, &data->mf_ul_data.nfca_data)) break; - - // Read Mifare Classic type - if(!flipper_format_read_string(file, "Mifare Classic type", temp_str)) break; - bool type_parsed = false; - for(size_t i = 0; i < MfClassicTypeNum; i++) { - const char* type_name = mf_classic_get_name(i, false); - if(furi_string_equal_str(temp_str, type_name)) { - mfc_data->type = i; - type_parsed = true; - } - } - if(!type_parsed) break; - - // Read format version - uint32_t data_format_version = 0; - bool old_format = false; - // Read Mifare Classic format version - if(!flipper_format_read_uint32(file, "Data format version", &data_format_version, 1)) { - // Load unread sectors with zero keys access for backward compatibility - if(!flipper_format_rewind(file)) break; - old_format = true; - } else { - if(data_format_version < nfc_mifare_classic_data_format_version) { - old_format = true; - } - } - - // Read Mifare Classic blocks - bool block_read = true; - FuriString* block_str = furi_string_alloc(); - uint16_t blocks_total = mf_classic_get_total_block_num(mfc_data->type); - for(size_t i = 0; i < blocks_total; i++) { - furi_string_printf(temp_str, "Block %d", i); - if(!flipper_format_read_string(file, furi_string_get_cstr(temp_str), block_str)) { - block_read = false; - break; - } - nfc_device_parse_mifare_classic_block(block_str, mfc_data, i); - } - furi_string_free(block_str); - if(!block_read) break; - - // Set keys and blocks as unknown for backward compatibility - if(old_format) { - mfc_data->key_a_mask = 0ULL; - mfc_data->key_b_mask = 0ULL; - memset(mfc_data->block_read_mask, 0, sizeof(mfc_data->block_read_mask)); - } +void nfc_dev_set_protocol_data( + NfcDev* instance, + NfcProtocolType protocol_type, + const NfcProtocolData* protocol_data) { + furi_assert(instance); + furi_assert(protocol_type < NfcProtocolTypeMax); - parsed = true; - } while(false); + nfc_dev_clear(instance); - furi_string_free(temp_str); + instance->protocol_type = protocol_type; + instance->protocol_data = nfc_protocols[protocol_type]->alloc(); - return parsed; + nfc_protocols[protocol_type]->copy(instance->protocol_data, protocol_data); } -static bool nfc_dev_mf_desfire_verify_handler(FuriString* device_type, NfcDevData* data) { - furi_assert(device_type); - furi_assert(data); +void nfc_dev_copy_protocol_data( + const NfcDev* instance, + NfcProtocolType protocol_type, + NfcProtocolData* protocol_data) { + furi_assert(instance); + furi_assert(protocol_type < NfcProtocolTypeMax); + furi_assert(protocol_data); - bool verified = furi_string_equal_str(device_type, "Mifare Desfire"); - if(verified) { - data->protocol = NfcDevProtocolMfDesfire; + if(instance->protocol_type != protocol_type) { + furi_crash(NFC_DEV_TYPE_ERROR); } - return verified; -} - -static bool - nfc_dev_mf_desfire_save_handler(FlipperFormat* file, uint32_t version, NfcDevData* data) { - furi_assert(file); - furi_assert(data); - UNUSED(version); - - bool saved = false; - - do { - if(!nfc_dev_nfca_save_data(file, &data->nfca_data)) break; - saved = true; - } while(false); - - return saved; -} - -static bool - nfc_dev_mf_desfire_load_handler(FlipperFormat* file, uint32_t version, NfcDevData* data) { - furi_assert(file); - furi_assert(data); - - bool parsed = false; - do { - // Read NFCA data - if(!nfc_dev_nfca_load_data(file, version, &data->mf_ul_data.nfca_data)) break; - - parsed = true; - } while(false); - - return parsed; -} - -static const NfcDevDataParser nfc_dev_data_parser[NfcDevProtocolNum] = { - [NfcDevProtocolNfca] = - { - .verify_handler = nfc_dev_nfca_verify_handler, - .save_handler = nfc_dev_nfca_save_handler, - .load_handler = nfc_dev_nfca_load_handler, - }, - [NfcDevProtocolMfUltralight] = - { - .verify_handler = nfc_dev_mf_ultralight_verify_handler, - .save_handler = nfc_dev_mf_ultralight_save_handler, - .load_handler = nfc_dev_mf_ultralight_load_handler, - }, - [NfcDevProtocolMfClassic] = - { - .verify_handler = nfc_dev_mf_classic_verify_handler, - .save_handler = nfc_dev_mf_classic_save_handler, - .load_handler = nfc_dev_mf_classic_load_handler, - }, - [NfcDevProtocolMfDesfire] = - { - .verify_handler = nfc_dev_mf_desfire_verify_handler, - .save_handler = nfc_dev_mf_desfire_save_handler, - .load_handler = nfc_dev_mf_desfire_load_handler, - }, - -}; - -NfcDev* nfc_dev_alloc() { - NfcDev* instance = malloc(sizeof(NfcDev)); - - return instance; -} - -void nfc_dev_free(NfcDev* instance) { - furi_assert(instance); - free(instance); + nfc_protocols[protocol_type]->copy(protocol_data, instance->protocol_data); } void nfc_dev_set_loading_callback(NfcDev* instance, NfcLoadingCallback callback, void* context) { @@ -609,9 +116,9 @@ void nfc_dev_set_loading_callback(NfcDev* instance, NfcLoadingCallback callback, instance->loading_callback_context = context; } -bool nfc_dev_save(NfcDev* instance, NfcDevData* data, const char* path) { +bool nfc_dev_save(NfcDev* instance, const char* path) { furi_assert(instance); - furi_assert(data); + furi_assert(instance->protocol_type < NfcProtocolTypeMax); furi_assert(path); bool saved = false; @@ -630,19 +137,17 @@ bool nfc_dev_save(NfcDev* instance, NfcDevData* data, const char* path) { if(!flipper_format_file_open_always(file, path)) break; // Write header - if(!flipper_format_write_header_cstr(file, nfc_file_header, nfc_file_version)) break; + if(!flipper_format_write_header_cstr(file, NFC_FILE_HEADER, NFC_CURRENT_FORMAT_VERSION)) + break; // Write nfc device type if(!flipper_format_write_comment_cstr( file, "Nfc device type can be UID, Mifare Ultralight, Mifare Classic")) break; - for(size_t i = 0; i < COUNT_OF(nfc_dev_data_parser); i++) { - if(data->protocol == i) { - saved = nfc_dev_data_parser[i].save_handler(file, nfc_file_version, data); - } - if(saved) break; - } + saved = nfc_protocols[instance->protocol_type]->save( + instance->protocol_data, file, NFC_CURRENT_FORMAT_VERSION); + } while(false); if(instance->loading_callback) { @@ -656,9 +161,8 @@ bool nfc_dev_save(NfcDev* instance, NfcDevData* data, const char* path) { return saved; } -bool nfc_dev_load(NfcDev* instance, NfcDevData* data, const char* path) { +bool nfc_dev_load(NfcDev* instance, const char* path) { furi_assert(instance); - furi_assert(data); furi_assert(path); bool loaded = false; @@ -678,17 +182,28 @@ bool nfc_dev_load(NfcDev* instance, NfcDevData* data, const char* path) { // Read and verify file header uint32_t version = 0; if(!flipper_format_read_header(file, temp_str, &version)) break; - if(furi_string_cmp_str(temp_str, nfc_file_header)) break; - if(version < nfc_file_version_with_lsb_atqa) break; + if(furi_string_cmp_str(temp_str, NFC_FILE_HEADER)) break; + if(version < NFC_LSB_ATQA_FORMAT_VERSION) break; // Read Nfc device type if(!flipper_format_read_string(file, "Device type", temp_str)) break; - for(size_t i = 0; i < COUNT_OF(nfc_dev_data_parser); i++) { - if(nfc_dev_data_parser[i].verify_handler(temp_str, data)) { - loaded = nfc_dev_data_parser[i].load_handler(file, version, data); + nfc_dev_clear(instance); + + for(NfcProtocolType i = 0; i < NfcProtocolTypeMax; i++) { + instance->protocol_type = i; + instance->protocol_data = nfc_protocols[i]->alloc(); + + if(nfc_protocols[i]->verify(instance->protocol_data, temp_str)) { + loaded = nfc_protocols[i]->load(instance->protocol_data, file, version); + } + + if(loaded) { + break; + } else { + nfc_protocols[i]->free(instance->protocol_data); + instance->protocol_data = NULL; } - if(loaded) break; } } while(false); diff --git a/lib/nfc/nfc_dev.h b/lib/nfc/nfc_dev.h index c8f45e176f03..425abb890e54 100644 --- a/lib/nfc/nfc_dev.h +++ b/lib/nfc/nfc_dev.h @@ -1,6 +1,8 @@ #pragma once -#include "nfc_device_data.h" +#include + +#include "protocols/nfc_protocol_defs.h" #ifdef __cplusplus extern "C" { @@ -14,11 +16,34 @@ NfcDev* nfc_dev_alloc(); void nfc_dev_free(NfcDev* instance); +void nfc_dev_clear(NfcDev* instance); + +void nfc_dev_reset(NfcDev* instance); + +NfcProtocolType nfc_dev_get_protocol_type(const NfcDev* instance); + +const NfcProtocolData* + nfc_dev_get_protocol_data(const NfcDev* instance, NfcProtocolType protocol_type); + +const char* nfc_dev_get_protocol_name(const NfcDev* instance, NfcProtocolNameType name_type); + +const uint8_t* nfc_dev_get_uid(const NfcDev* instance, size_t* uid_len); + +void nfc_dev_set_protocol_data( + NfcDev* instance, + NfcProtocolType protocol_type, + const NfcProtocolData* protocol_data); + +void nfc_dev_copy_protocol_data( + const NfcDev* instance, + NfcProtocolType protocol_type, + NfcProtocolData* protocol_data); + void nfc_dev_set_loading_callback(NfcDev* instance, NfcLoadingCallback callback, void* context); -bool nfc_dev_save(NfcDev* instance, NfcDevData* data, const char* path); +bool nfc_dev_save(NfcDev* instance, const char* path); -bool nfc_dev_load(NfcDev* instance, NfcDevData* data, const char* path); +bool nfc_dev_load(NfcDev* instance, const char* path); #ifdef __cplusplus } diff --git a/lib/nfc/nfc_device_data.h b/lib/nfc/nfc_device_data.h deleted file mode 100644 index 8c6e7af2995e..000000000000 --- a/lib/nfc/nfc_device_data.h +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum { - NfcDevProtocolNfca, - // NfcDevProtocolNfcb, - // NfcDevProtocolNfcf, - // NfcDevProtocolNfcv, - NfcDevProtocolMfUltralight, - NfcDevProtocolMfClassic, - NfcDevProtocolMfDesfire, - - NfcDevProtocolNum, -} NfcDevProtocol; - -// TODO rename to NfcData? -typedef struct { - NfcDevProtocol protocol; - union { - NfcaData nfca_data; - MfUltralightData mf_ul_data; - MfClassicData mf_classic_data; - MfDesfireData mf_desfire_data; - }; -} NfcDevData; - -#ifdef __cplusplus -} -#endif diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a.c b/lib/nfc/protocols/iso14443_4a/iso14443_4a.c index 41b69df11566..834f6a0a7909 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a.c +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a.c @@ -1 +1,85 @@ #include "iso14443_4a.h" + +#include + +#define ISO14443_4A_PROTOCOL_NAME "Unknown ISO14443-4A Tag" + +const NfcProtocolBase nfc_protocol_iso14443_4a = { + .alloc = (NfcProtocolAlloc)iso14443_4a_alloc, + .free = (NfcProtocolFree)iso14443_4a_free, + .reset = (NfcProtocolReset)iso14443_4a_reset, + .copy = (NfcProtocolCopy)iso14443_4a_copy, + .verify = (NfcProtocolVerify)iso14443_4a_verify, + .load = (NfcProtocolLoad)iso14443_4a_load, + .save = (NfcProtocolSave)iso14443_4a_save, + .is_equal = (NfcProtocolEqual)iso14443_4a_is_equal, + .get_name = (NfcProtocolGetName)iso14443_4a_get_name, + .get_uid = (NfcProtocolGetUid)iso14443_4a_get_uid, +}; + +Iso14443_4aData* iso14443_4a_alloc() { + Iso14443_4aData* data = malloc(sizeof(Iso14443_4aData)); + data->iso14443_3a_data = nfca_alloc(); + + return data; +} + +void iso14443_4a_free(Iso14443_4aData* data) { + furi_assert(data); + + nfca_free(data->iso14443_3a_data); + free(data); +} + +void iso14443_4a_reset(Iso14443_4aData* data) { + furi_assert(data); + + nfca_reset(data->iso14443_3a_data); +} + +void iso14443_4a_copy(Iso14443_4aData* data, const Iso14443_4aData* other) { + furi_assert(data); + furi_assert(other); + + nfca_copy(data->iso14443_3a_data, other->iso14443_3a_data); +} + +bool iso14443_4a_verify(Iso14443_4aData* data, const FuriString* device_type) { + UNUSED(data); + UNUSED(device_type); + + // TODO: implementation + return false; +} + +bool iso14443_4a_load(Iso14443_4aData* data, FlipperFormat* ff, uint32_t version) { + UNUSED(data); + UNUSED(ff); + UNUSED(version); + + // TODO: implementation + return false; +} + +bool iso14443_4a_save(const Iso14443_4aData* data, FlipperFormat* ff, uint32_t version) { + UNUSED(data); + UNUSED(ff); + UNUSED(version); + + // TODO: implementation + return false; +} + +bool iso14443_4a_is_equal(const Iso14443_4aData* data, const Iso14443_4aData* other) { + return nfca_is_equal(data->iso14443_3a_data, other->iso14443_3a_data); +} + +const char* iso14443_4a_get_name(const Iso14443_4aData* data, NfcProtocolNameType name_type) { + UNUSED(data); + UNUSED(name_type); + return ISO14443_4A_PROTOCOL_NAME; +} + +const uint8_t* iso14443_4a_get_uid(const Iso14443_4aData* data, size_t* uid_len) { + return nfca_get_uid(data->iso14443_3a_data, uid_len); +} diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a.h b/lib/nfc/protocols/iso14443_4a/iso14443_4a.h index 11c97807495b..e7c05d946bfe 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a.h +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #ifdef __cplusplus extern "C" { @@ -28,9 +28,31 @@ typedef struct { } Iso14443_4aAtsResponse; typedef struct { - NfcaData iso14443_3a_data; + NfcaData* iso14443_3a_data; } Iso14443_4aData; +extern const NfcProtocolBase nfc_protocol_iso14443_4a; + +Iso14443_4aData* iso14443_4a_alloc(); + +void iso14443_4a_free(Iso14443_4aData* data); + +void iso14443_4a_reset(Iso14443_4aData* data); + +void iso14443_4a_copy(Iso14443_4aData* data, const Iso14443_4aData* other); + +bool iso14443_4a_verify(Iso14443_4aData* data, const FuriString* device_type); + +bool iso14443_4a_load(Iso14443_4aData* data, FlipperFormat* ff, uint32_t version); + +bool iso14443_4a_save(const Iso14443_4aData* data, FlipperFormat* ff, uint32_t version); + +bool iso14443_4a_is_equal(const Iso14443_4aData* data, const Iso14443_4aData* other); + +const char* iso14443_4a_get_name(const Iso14443_4aData* data, NfcProtocolNameType name_type); + +const uint8_t* iso14443_4a_get_uid(const Iso14443_4aData* data, size_t* uid_len); + #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.c b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.c index c15ab93bf504..b73d25c418e5 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.c +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.c @@ -29,13 +29,23 @@ Iso14443_4aPoller* iso14443_4a_poller_alloc(NfcaPoller* iso14443_3a_poller) { void iso14443_4a_poller_free(Iso14443_4aPoller* instance) { furi_assert(instance); + furi_assert(instance->state == Iso14443_4aPollerStateIdle); + free(instance); } +const Iso14443_4aData* iso14443_4a_poller_get_data(Iso14443_4aPoller* instance) { + furi_assert(instance); + + return instance->data; +} + Iso14443_4aPollerCommand iso14443_4a_poller_handler_idle(Iso14443_4aPoller* instance) { bit_buffer_reset(instance->tx_buffer); bit_buffer_reset(instance->rx_buffer); - nfca_poller_get_data(instance->iso14443_3a_poller, &instance->data->iso14443_3a_data); + nfca_copy( + instance->data->iso14443_3a_data, nfca_poller_get_data(instance->iso14443_3a_poller)); + instance->state = Iso14443_4aPollerStateReadAts; return Iso14443_4aPollerCommandContinue; } @@ -118,7 +128,7 @@ Iso14443_4aError iso14443_4a_poller_start( furi_assert(callback); furi_assert(context); - instance->data = malloc(sizeof(Iso14443_4aData)); + instance->data = iso14443_4a_alloc(); instance->tx_buffer = bit_buffer_alloc(ISO14443_4A_BUF_SIZE_MAX); instance->rx_buffer = bit_buffer_alloc(ISO14443_4A_BUF_SIZE_MAX); @@ -166,17 +176,7 @@ Iso14443_4aError iso14443_4a_poller_stop(Iso14443_4aPoller* instance) { instance->session_state = Iso14443_4aPollerSessionStateStopRequest; nfca_poller_stop(instance->iso14443_3a_poller); instance->session_state = Iso14443_4aPollerSessionStateIdle; - free(instance->data); + iso14443_4a_free(instance->data); return iso14443_4a_poller_reset(instance); } - -Iso14443_4aError iso14443_4a_poller_get_data(Iso14443_4aPoller* instance, Iso14443_4aData* data) { - furi_assert(instance); - furi_assert(instance->data); - furi_assert(data); - - *data = *instance->data; - - return Iso14443_4aErrorNone; -} diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.h b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.h index ee77477ee58c..77bac4c7dd27 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.h +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.h @@ -37,6 +37,8 @@ Iso14443_4aPoller* iso14443_4a_poller_alloc(NfcaPoller* iso14443_3a_poller); void iso14443_4a_poller_free(Iso14443_4aPoller* instance); +const Iso14443_4aData* iso14443_4a_poller_get_data(Iso14443_4aPoller* instance); + Iso14443_4aError iso14443_4a_poller_start( Iso14443_4aPoller* instance, NfcaPollerEventCallback callback, @@ -49,8 +51,6 @@ Iso14443_4aError iso14443_4a_poller_read( Iso14443_4aError iso14443_4a_poller_stop(Iso14443_4aPoller* instance); -Iso14443_4aError iso14443_4a_poller_get_data(Iso14443_4aPoller* instance, Iso14443_4aData* data); - #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c index bb9bbb6c6a01..50d24551441a 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c @@ -28,7 +28,6 @@ Iso14443_4aError iso14443_4a_poller_process_error(NfcaError error) { Iso14443_4aError iso14443_4a_poller_halt(Iso14443_4aPoller* instance) { furi_assert(instance); - furi_assert(instance->iso14443_3a_poller); nfca_poller_halt(instance->iso14443_3a_poller); instance->state = Iso14443_4aPollerStateIdle; @@ -38,13 +37,13 @@ Iso14443_4aError iso14443_4a_poller_halt(Iso14443_4aPoller* instance) { Iso14443_4aError iso14443_4a_poller_async_read_ats(Iso14443_4aPoller* instance) { furi_assert(instance); - furi_assert(instance->iso14443_3a_poller); Iso14443_4aError ret = Iso14443_4aErrorProtocol; do { // Check whether ATS is available - if(!(instance->data->iso14443_3a_data.sak & ISO14443_4A_ATS_BIT)) { + NfcaData* iso14443_3a_data = instance->data->iso14443_3a_data; + if(!(iso14443_3a_data->sak & ISO14443_4A_ATS_BIT)) { FURI_LOG_E(TAG, "Ats not supported: not an ISO14443-4 card"); break; } @@ -85,7 +84,6 @@ Iso14443_4aError iso14443_4a_poller_send_block( BitBuffer* rx_buffer, uint32_t fwt) { furi_assert(instance); - furi_assert(instance->iso14443_3a_poller); furi_assert(tx_buffer); furi_assert(rx_buffer); diff --git a/lib/nfc/protocols/mf_classic/mf_classic.c b/lib/nfc/protocols/mf_classic/mf_classic.c index b8f07b6f84b9..b90cc9bbf1cd 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic.c +++ b/lib/nfc/protocols/mf_classic/mf_classic.c @@ -1,7 +1,9 @@ #include "mf_classic.h" #include -#include +#include + +#include typedef struct { uint8_t sectors_total; @@ -10,7 +12,9 @@ typedef struct { const char* type_name; } MfClassicFeatures; -MfClassicFeatures mf_classic_features[MfClassicTypeNum] = { +static const uint32_t mf_classic_data_format_version = 2; + +static const MfClassicFeatures mf_classic_features[MfClassicTypeNum] = { [MfClassicTypeMini] = { .sectors_total = 5, @@ -34,24 +38,284 @@ MfClassicFeatures mf_classic_features[MfClassicTypeNum] = { }, }; -uint8_t mf_classic_get_total_sectors_num(MfClassicType type) { - return mf_classic_features[type].sectors_total; +const NfcProtocolBase nfc_protocol_mf_classic = { + .alloc = (NfcProtocolAlloc)mf_classic_alloc, + .free = (NfcProtocolFree)mf_classic_free, + .reset = (NfcProtocolReset)mf_classic_reset, + .copy = (NfcProtocolCopy)mf_classic_copy, + .verify = (NfcProtocolVerify)mf_classic_verify, + .load = (NfcProtocolLoad)mf_classic_load, + .save = (NfcProtocolSave)mf_classic_save, + .is_equal = (NfcProtocolEqual)mf_classic_is_equal, + .get_name = (NfcProtocolGetName)mf_classic_get_name, + .get_uid = (NfcProtocolGetUid)mf_classic_get_uid, +}; + +MfClassicData* mf_classic_alloc() { + MfClassicData* data = malloc(sizeof(MfClassicData)); + data->nfca_data = nfca_alloc(); + return data; } -uint16_t mf_classic_get_total_block_num(MfClassicType type) { - return mf_classic_features[type].blocks_total; +void mf_classic_free(MfClassicData* data) { + furi_assert(data); + + nfca_free(data->nfca_data); + free(data); +} + +void mf_classic_reset(MfClassicData* data) { + furi_assert(data); + + nfca_reset(data->nfca_data); +} + +void mf_classic_copy(MfClassicData* data, const MfClassicData* other) { + furi_assert(data); + furi_assert(other); + + nfca_copy(data->nfca_data, other->nfca_data); + memcpy(data->block, other->block, MF_CLASSIC_TOTAL_BLOCKS_MAX); + memcpy(data->block_read_mask, other->block_read_mask, MF_CLASSIC_READ_MASK_SIZE); + + data->type = other->type; + data->key_a_mask = other->key_a_mask; + data->key_b_mask = other->key_b_mask; +} + +bool mf_classic_verify(MfClassicData* data, const FuriString* device_type) { + UNUSED(data); + return furi_string_equal_str(device_type, "Mifare Classic"); +} + +static void mf_classic_parse_block(FuriString* block_str, MfClassicData* data, uint8_t block_num) { + furi_string_trim(block_str); + MfClassicBlock block_tmp = {}; + bool is_sector_trailer = mf_classic_is_sector_trailer(block_num); + uint8_t sector_num = mf_classic_get_sector_by_block(block_num); + uint16_t block_unknown_bytes_mask = 0; + + furi_string_trim(block_str); + for(size_t i = 0; i < MF_CLASSIC_BLOCK_SIZE; i++) { + char hi = furi_string_get_char(block_str, 3 * i); + char low = furi_string_get_char(block_str, 3 * i + 1); + uint8_t byte = 0; + if(hex_char_to_uint8(hi, low, &byte)) { + block_tmp.data[i] = byte; + } else { + FURI_BIT_SET(block_unknown_bytes_mask, i); + } + } + + if(block_unknown_bytes_mask != 0xffff) { + if(is_sector_trailer) { + MfClassicSectorTrailer* sec_tr_tmp = (MfClassicSectorTrailer*)&block_tmp; + // Load Key A + // Key A mask 0b0000000000111111 = 0x003f + if((block_unknown_bytes_mask & 0x003f) == 0) { + uint64_t key = nfc_util_bytes2num(sec_tr_tmp->key_a.data, sizeof(MfClassicKey)); + mf_classic_set_key_found(data, sector_num, MfClassicKeyTypeA, key); + } + // Load Access Bits + // Access bits mask 0b0000001111000000 = 0x03c0 + if((block_unknown_bytes_mask & 0x03c0) == 0) { + mf_classic_set_block_read(data, block_num, &block_tmp); + } + // Load Key B + // Key B mask 0b1111110000000000 = 0xfc00 + if((block_unknown_bytes_mask & 0xfc00) == 0) { + uint64_t key = nfc_util_bytes2num(sec_tr_tmp->key_b.data, sizeof(MfClassicKey)); + mf_classic_set_key_found(data, sector_num, MfClassicKeyTypeB, key); + } + } else { + if(block_unknown_bytes_mask == 0) { + mf_classic_set_block_read(data, block_num, &block_tmp); + } + } + } } -const char* mf_classic_get_name(MfClassicType type, bool full_name) { - const char* ret = NULL; +bool mf_classic_load(MfClassicData* data, FlipperFormat* ff, uint32_t version) { + furi_assert(data); + + FuriString* temp_str = furi_string_alloc(); + bool parsed = false; + + do { + // Read NFCA data + if(!nfca_load_data(data->nfca_data, ff, version)) break; + + // Read Mifare Classic type + if(!flipper_format_read_string(ff, "Mifare Classic type", temp_str)) break; + bool type_parsed = false; + for(size_t i = 0; i < MfClassicTypeNum; i++) { + if(furi_string_equal_str(temp_str, mf_classic_features[i].type_name)) { + data->type = i; + type_parsed = true; + } + } + if(!type_parsed) break; + + // Read format version + uint32_t data_format_version = 0; + bool old_format = false; + // Read Mifare Classic format version + if(!flipper_format_read_uint32(ff, "Data format version", &data_format_version, 1)) { + // Load unread sectors with zero keys access for backward compatibility + if(!flipper_format_rewind(ff)) break; + old_format = true; + } else { + if(data_format_version < mf_classic_data_format_version) { + old_format = true; + } + } + + // Read Mifare Classic blocks + bool block_read = true; + FuriString* block_str = furi_string_alloc(); + uint16_t blocks_total = mf_classic_get_total_block_num(data->type); + for(size_t i = 0; i < blocks_total; i++) { + furi_string_printf(temp_str, "Block %d", i); + if(!flipper_format_read_string(ff, furi_string_get_cstr(temp_str), block_str)) { + block_read = false; + break; + } + mf_classic_parse_block(block_str, data, i); + } + furi_string_free(block_str); + if(!block_read) break; + + // Set keys and blocks as unknown for backward compatibility + if(old_format) { + data->key_a_mask = 0ULL; + data->key_b_mask = 0ULL; + memset(data->block_read_mask, 0, sizeof(data->block_read_mask)); + } + + parsed = true; + } while(false); - if(full_name) { - ret = mf_classic_features[type].full_name; + furi_string_free(temp_str); + + return parsed; +} + +static void + mf_classic_set_block_str(FuriString* block_str, const MfClassicData* data, uint8_t block_num) { + furi_string_reset(block_str); + bool is_sec_trailer = mf_classic_is_sector_trailer(block_num); + if(is_sec_trailer) { + uint8_t sector_num = mf_classic_get_sector_by_block(block_num); + MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(data, sector_num); + // Write key A + for(size_t i = 0; i < sizeof(sec_tr->key_a); i++) { + if(mf_classic_is_key_found(data, sector_num, MfClassicKeyTypeA)) { + furi_string_cat_printf(block_str, "%02X ", sec_tr->key_a.data[i]); + } else { + furi_string_cat_printf(block_str, "?? "); + } + } + // Write Access bytes + for(size_t i = 0; i < MF_CLASSIC_ACCESS_BYTES_SIZE; i++) { + if(mf_classic_is_block_read(data, block_num)) { + furi_string_cat_printf(block_str, "%02X ", sec_tr->access_bits.data[i]); + } else { + furi_string_cat_printf(block_str, "?? "); + } + } + // Write key B + for(size_t i = 0; i < sizeof(sec_tr->key_b); i++) { + if(mf_classic_is_key_found(data, sector_num, MfClassicKeyTypeB)) { + furi_string_cat_printf(block_str, "%02X ", sec_tr->key_b.data[i]); + } else { + furi_string_cat_printf(block_str, "?? "); + } + } } else { - ret = mf_classic_features[type].type_name; + // Write data block + for(size_t i = 0; i < MF_CLASSIC_BLOCK_SIZE; i++) { + if(mf_classic_is_block_read(data, block_num)) { + furi_string_cat_printf(block_str, "%02X ", data->block[block_num].data[i]); + } else { + furi_string_cat_printf(block_str, "?? "); + } + } } + furi_string_trim(block_str); +} - return ret; +bool mf_classic_save(const MfClassicData* data, FlipperFormat* ff, uint32_t version) { + furi_assert(data); + UNUSED(version); + + FuriString* temp_str = furi_string_alloc(); + bool saved = false; + + do { + if(!flipper_format_write_string_cstr(ff, "Device type", "Mifare Classic")) break; + if(!nfca_save_data(data->nfca_data, ff, version)) break; + if(!flipper_format_write_string_cstr(ff, "Device type", "")) break; + if(!flipper_format_write_comment_cstr(ff, "Mifare Classic specific data")) break; + if(!flipper_format_write_string_cstr( + ff, "Mifare Classic type", mf_classic_features[data->type].type_name)) + break; + if(!flipper_format_write_uint32( + ff, "Data format version", &mf_classic_data_format_version, 1)) + break; + if(!flipper_format_write_comment_cstr( + ff, "Mifare Classic blocks, \'??\' means unknown data")) + break; + + uint16_t blocks_total = mf_classic_get_total_block_num(data->type); + FuriString* block_str = furi_string_alloc(); + bool block_saved = true; + for(size_t i = 0; i < blocks_total; i++) { + furi_string_printf(temp_str, "Block %d", i); + mf_classic_set_block_str(block_str, data, i); + if(!flipper_format_write_string(ff, furi_string_get_cstr(temp_str), block_str)) { + block_saved = false; + break; + } + } + furi_string_free(block_str); + if(!block_saved) break; + + saved = true; + } while(false); + + furi_string_free(temp_str); + + return saved; +} + +bool mf_classic_is_equal(const MfClassicData* data, const MfClassicData* other) { + // TODO: Complete equality method + return nfca_is_equal(data->nfca_data, other->nfca_data); +} + +const char* mf_classic_get_name(const MfClassicData* data, NfcProtocolNameType name_type) { + furi_assert(data); + furi_assert(data->type < MfClassicTypeNum); + + if(name_type == NfcProtocolNameTypeFull) { + return mf_classic_features[data->type].full_name; + } else { + return mf_classic_features[data->type].type_name; + } +} + +const uint8_t* mf_classic_get_uid(const MfClassicData* data, size_t* uid_len) { + furi_assert(data); + + return nfca_get_uid(data->nfca_data, uid_len); +} + +uint8_t mf_classic_get_total_sectors_num(MfClassicType type) { + return mf_classic_features[type].sectors_total; +} + +uint16_t mf_classic_get_total_block_num(MfClassicType type) { + return mf_classic_features[type].blocks_total; } bool mf_classic_detect_protocol(NfcaData* data, MfClassicType* type) { @@ -117,7 +381,7 @@ uint8_t mf_classic_get_sector_trailer_num_by_block(uint8_t block) { } MfClassicSectorTrailer* - mf_classic_get_sector_trailer_by_sector(MfClassicData* data, uint8_t sector_num) { + mf_classic_get_sector_trailer_by_sector(const MfClassicData* data, uint8_t sector_num) { furi_assert(data); uint8_t sec_tr_block = mf_classic_get_sector_trailer_num_by_sector(sector_num); @@ -142,7 +406,10 @@ uint8_t mf_classic_get_sector_by_block(uint8_t block) { return sector; } -bool mf_classic_is_key_found(MfClassicData* data, uint8_t sector_num, MfClassicKeyType key_type) { +bool mf_classic_is_key_found( + const MfClassicData* data, + uint8_t sector_num, + MfClassicKeyType key_type) { furi_assert(data); bool key_found = false; @@ -188,7 +455,7 @@ void mf_classic_set_key_not_found( } } -bool mf_classic_is_block_read(MfClassicData* data, uint8_t block_num) { +bool mf_classic_is_block_read(const MfClassicData* data, uint8_t block_num) { furi_assert(data); return (FURI_BIT(data->block_read_mask[block_num / 32], block_num % 32) == 1); @@ -224,7 +491,7 @@ uint8_t mf_classic_get_blocks_num_in_sector(uint8_t sector) { } void mf_classic_get_read_sectors_and_keys( - MfClassicData* data, + const MfClassicData* data, uint8_t* sectors_read, uint8_t* keys_found) { furi_assert(data); @@ -254,7 +521,7 @@ void mf_classic_get_read_sectors_and_keys( } } -bool mf_classic_is_card_read(MfClassicData* data) { +bool mf_classic_is_card_read(const MfClassicData* data) { furi_assert(data); uint8_t sectors_total = mf_classic_get_total_sectors_num(data->type); @@ -266,7 +533,7 @@ bool mf_classic_is_card_read(MfClassicData* data) { return card_read; } -bool mf_classic_is_sector_read(MfClassicData* data, uint8_t sector_num) { +bool mf_classic_is_sector_read(const MfClassicData* data, uint8_t sector_num) { furi_assert(data); bool sector_read = false; diff --git a/lib/nfc/protocols/mf_classic/mf_classic.h b/lib/nfc/protocols/mf_classic/mf_classic.h index 5e27d22f523d..050bdb26dad7 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic.h +++ b/lib/nfc/protocols/mf_classic/mf_classic.h @@ -14,6 +14,7 @@ extern "C" { #define MF_CLASSIC_TOTAL_SECTORS_MAX (40) #define MF_CLASSIC_TOTAL_BLOCKS_MAX (256) +#define MF_CLASSIC_READ_MASK_SIZE (MF_CLASSIC_TOTAL_BLOCKS_MAX / 32) #define MF_CLASSIC_BLOCK_SIZE (16) #define MF_CLASSIC_KEY_SIZE (6) #define MF_CLASSIC_ACCESS_BYTES_SIZE (4) @@ -110,14 +111,36 @@ typedef struct { } MfClassicDeviceKeys; typedef struct { - NfcaData nfca_data; + NfcaData* nfca_data; MfClassicType type; - uint32_t block_read_mask[MF_CLASSIC_TOTAL_BLOCKS_MAX / 32]; + uint32_t block_read_mask[MF_CLASSIC_READ_MASK_SIZE]; uint64_t key_a_mask; uint64_t key_b_mask; MfClassicBlock block[MF_CLASSIC_TOTAL_BLOCKS_MAX]; } MfClassicData; +extern const NfcProtocolBase nfc_protocol_mf_classic; + +MfClassicData* mf_classic_alloc(); + +void mf_classic_free(MfClassicData* data); + +void mf_classic_reset(MfClassicData* data); + +void mf_classic_copy(MfClassicData* data, const MfClassicData* other); + +bool mf_classic_verify(MfClassicData* data, const FuriString* device_type); + +bool mf_classic_load(MfClassicData* data, FlipperFormat* ff, uint32_t version); + +bool mf_classic_save(const MfClassicData* data, FlipperFormat* ff, uint32_t version); + +bool mf_classic_is_equal(const MfClassicData* data, const MfClassicData* other); + +const char* mf_classic_get_name(const MfClassicData* data, NfcProtocolNameType name_type); + +const uint8_t* mf_classic_get_uid(const MfClassicData* data, size_t* uid_len); + bool mf_classic_detect_protocol(NfcaData* data, MfClassicType* type); uint8_t mf_classic_get_total_sectors_num(MfClassicType type); @@ -128,20 +151,21 @@ uint8_t mf_classic_get_first_block_num_of_sector(uint8_t sector); uint8_t mf_classic_get_blocks_num_in_sector(uint8_t sector); -const char* mf_classic_get_name(MfClassicType type, bool full_name); - uint8_t mf_classic_get_sector_trailer_num_by_sector(uint8_t sector); uint8_t mf_classic_get_sector_trailer_num_by_block(uint8_t block); MfClassicSectorTrailer* - mf_classic_get_sector_trailer_by_sector(MfClassicData* data, uint8_t sector_num); + mf_classic_get_sector_trailer_by_sector(const MfClassicData* data, uint8_t sector_num); bool mf_classic_is_sector_trailer(uint8_t block); uint8_t mf_classic_get_sector_by_block(uint8_t block); -bool mf_classic_is_key_found(MfClassicData* data, uint8_t sector_num, MfClassicKeyType key_type); +bool mf_classic_is_key_found( + const MfClassicData* data, + uint8_t sector_num, + MfClassicKeyType key_type); void mf_classic_set_key_found( MfClassicData* data, @@ -154,18 +178,18 @@ void mf_classic_set_key_not_found( uint8_t sector_num, MfClassicKeyType key_type); -bool mf_classic_is_block_read(MfClassicData* data, uint8_t block_num); +bool mf_classic_is_block_read(const MfClassicData* data, uint8_t block_num); void mf_classic_set_block_read(MfClassicData* data, uint8_t block_num, MfClassicBlock* block_data); -bool mf_classic_is_sector_read(MfClassicData* data, uint8_t sector_num); +bool mf_classic_is_sector_read(const MfClassicData* data, uint8_t sector_num); void mf_classic_get_read_sectors_and_keys( - MfClassicData* data, + const MfClassicData* data, uint8_t* sectors_read, uint8_t* keys_found); -bool mf_classic_is_card_read(MfClassicData* data); +bool mf_classic_is_card_read(const MfClassicData* data); #ifdef __cplusplus } diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller.c b/lib/nfc/protocols/mf_classic/mf_classic_poller.c index 921b2b1dd891..d9803e7d30e9 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller.c @@ -41,6 +41,12 @@ void mf_classic_poller_free(MfClassicPoller* instance) { free(instance); } +const MfClassicData* mf_classic_poller_get_data(MfClassicPoller* instance) { + furi_assert(instance); + + return instance->data; +} + MfClassicError mf_classic_poller_start( MfClassicPoller* instance, NfcaPollerEventCallback callback, @@ -50,7 +56,7 @@ MfClassicError mf_classic_poller_start( furi_assert(instance->nfca_poller); furi_assert(instance->session_state == MfClassicPollerSessionStateIdle); - instance->data = malloc(sizeof(MfClassicData)); + instance->data = mf_classic_alloc(); instance->crypto = crypto1_alloc(); instance->plain_buff = nfc_poller_buffer_alloc(MF_CLASSIC_MAX_BUFF_SIZE, MF_CLASSIC_MAX_BUFF_SIZE); @@ -64,11 +70,11 @@ MfClassicError mf_classic_poller_start( } MfClassicPollerCommand mf_classic_poller_handler_idle(MfClassicPoller* instance) { - nfca_poller_get_data(instance->nfca_poller, &instance->data->nfca_data); + nfca_copy(instance->data->nfca_data, nfca_poller_get_data(instance->nfca_poller)); MfClassicPollerCommand command = MfClassicPollerCommandContinue; MfClassicPollerEvent event = {}; - if(mf_classic_detect_protocol(&instance->data->nfca_data, &instance->data->type)) { + if(mf_classic_detect_protocol(instance->data->nfca_data, &instance->data->type)) { if(instance->card_state == MfClassicCardStateNotDetected) { instance->card_state = MfClassicCardStateDetected; event.type = MfClassicPollerEventTypeCardDetected; @@ -347,16 +353,6 @@ MfClassicError mf_classic_poller_dict_attack( return mf_classic_poller_start(instance, mf_classic_dict_attack_callback, instance); } -MfClassicError mf_classic_poller_get_data(MfClassicPoller* instance, MfClassicData* data) { - furi_assert(instance); - furi_assert(instance->data); - furi_assert(data); - - *data = *instance->data; - - return MfClassicErrorNone; -} - MfClassicError mf_classic_poller_reset(MfClassicPoller* instance) { furi_assert(instance); furi_assert(instance->data); @@ -381,7 +377,7 @@ MfClassicError mf_classic_poller_stop(MfClassicPoller* instance) { instance->session_state = MfClassicPollerSessionStateStopRequest; nfca_poller_stop(instance->nfca_poller); instance->session_state = MfClassicPollerSessionStateIdle; - free(instance->data); + mf_classic_free(instance->data); return mf_classic_poller_reset(instance); } diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller.h b/lib/nfc/protocols/mf_classic/mf_classic_poller.h index 3bf55d1e0b84..fc22f65f50b4 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller.h +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller.h @@ -63,6 +63,8 @@ MfClassicPoller* mf_classic_poller_alloc(NfcaPoller* nfca_poller); void mf_classic_poller_free(MfClassicPoller* instance); +const MfClassicData* mf_classic_poller_get_data(MfClassicPoller* instance); + MfClassicError mf_classic_poller_start( MfClassicPoller* instance, NfcaPollerEventCallback callback, @@ -73,8 +75,6 @@ MfClassicError mf_classic_poller_dict_attack( MfClassicPollerCallback callback, void* context); -MfClassicError mf_classic_poller_get_data(MfClassicPoller* instance, MfClassicData* data); - MfClassicError mf_classic_poller_reset(MfClassicPoller* instance); MfClassicError mf_classic_poller_stop(MfClassicPoller* instance); diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c index 607b97bdf796..7e90587ed082 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c @@ -45,7 +45,7 @@ MfClassicError mf_classic_async_auth( NfcaError error = NfcaErrorNone; do { - nfca_poller_get_data(instance->nfca_poller, &instance->data->nfca_data); + nfca_copy(instance->data->nfca_data, nfca_poller_get_data(instance->nfca_poller)); uint8_t auth_cmd = (key_type == MfClassicKeyTypeB) ? MF_CLASSIC_AUTH_KEY_B_CMD : MF_CLASSIC_AUTH_KEY_A_CMD; buff->tx_data[0] = auth_cmd; @@ -72,9 +72,9 @@ MfClassicError mf_classic_async_auth( memcpy(data->nt.data, buff->rx_data, sizeof(MfClassicNt)); } - uint8_t* cuid_start = instance->data->nfca_data.uid; - if(instance->data->nfca_data.uid_len == 7) { - cuid_start = &instance->data->nfca_data.uid[3]; + uint8_t* cuid_start = instance->data->nfca_data->uid; + if(instance->data->nfca_data->uid_len == 7) { + cuid_start = &instance->data->nfca_data->uid[3]; } uint32_t cuid = (cuid_start[0] << 24) | (cuid_start[1] << 16) | (cuid_start[2] << 8) | (cuid_start[3]); diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire.c b/lib/nfc/protocols/mf_desfire/mf_desfire.c index 78ff2dacf323..6affb4e0af96 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire.c +++ b/lib/nfc/protocols/mf_desfire/mf_desfire.c @@ -2,6 +2,225 @@ #include +#define MF_DESFIRE_PROTOCOL_NAME "Mifare DESfire" + +const NfcProtocolBase nfc_protocol_mf_desfire = { + .alloc = (NfcProtocolAlloc)mf_desfire_alloc, + .free = (NfcProtocolFree)mf_desfire_free, + .reset = (NfcProtocolReset)mf_desfire_reset, + .copy = (NfcProtocolCopy)mf_desfire_copy, + .verify = (NfcProtocolVerify)mf_desfire_verify, + .load = (NfcProtocolLoad)mf_desfire_load, + .save = (NfcProtocolSave)mf_desfire_save, + .is_equal = (NfcProtocolEqual)mf_desfire_is_equal, + .get_name = (NfcProtocolGetName)mf_desfire_get_name, + .get_uid = (NfcProtocolGetUid)mf_desfire_get_uid, +}; + +MfDesfireData* mf_desfire_alloc() { + MfDesfireData* data = malloc(sizeof(MfDesfireData)); + data->iso14443_4a_data = iso14443_4a_alloc(); + return data; +} + +void mf_desfire_free(MfDesfireData* data) { + furi_assert(data); + mf_desfire_reset(data); + iso14443_4a_free(data->iso14443_4a_data); + free(data); +} + +static inline void mf_desfire_reset_key_config(MfDesfireKeyConfiguration* config) { + if(config->key_versions) { + free(config->key_versions); + } + memset(config, 0, sizeof(MfDesfireKeyConfiguration)); +} + +static inline void mf_desfire_reset_file(MfDesfireFile* file) { + if(file->contents) { + free(file->contents); + } + memset(file, 0, sizeof(MfDesfireFile)); +} + +static inline void mf_desfire_reset_files(MfDesfireFiles* files) { + if(files->data) { + for(size_t i = 0; i < files->count; ++i) { + mf_desfire_reset_file(&files->data[i]); + } + free(files->data); + } + memset(files, 0, sizeof(MfDesfireFiles)); +} + +static inline void mf_desfire_reset_application(MfDesfireApplication* app) { + memset(app->id, 0, sizeof(app->id)); + mf_desfire_reset_key_config(&app->key_config); + mf_desfire_reset_files(&app->files); +} + +static inline void mf_desfire_reset_applications(MfDesfireApplications* apps) { + if(apps->data) { + for(size_t i = 0; i < apps->count; ++i) { + mf_desfire_reset_application(&apps->data[i]); + } + free(apps->data); + } + memset(apps, 0, sizeof(MfDesfireApplications)); +} + +void mf_desfire_reset(MfDesfireData* data) { + furi_assert(data); + + iso14443_4a_reset(data->iso14443_4a_data); + + memset(&data->version, 0, sizeof(MfDesfireVersion)); + memset(&data->free_memory, 0, sizeof(MfDesfireFreeMemory)); + + mf_desfire_reset_key_config(&data->master_key); + mf_desfire_reset_applications(&data->applications); +} + +static inline void mf_desfire_copy_key_config( + MfDesfireKeyConfiguration* config, + const MfDesfireKeyConfiguration* other) { + furi_assert(config->key_versions == NULL); + + config->key_settings = other->key_settings; + if(other->key_settings.max_keys == 0) { + return; + } + + const size_t key_versions_size = other->key_settings.max_keys * sizeof(MfDesfireKeyVersion); + config->key_versions = malloc(key_versions_size); + memcpy(config->key_versions, other->key_versions, key_versions_size); +} + +static inline void mf_desfire_copy_file(MfDesfireFile* file, const MfDesfireFile* other) { + furi_assert(file->contents == NULL); + + file->id = other->id; + file->type = other->type; + file->comm = other->comm; + file->access_rights = other->access_rights; + + if(other->type == MfDesfireFileTypeStandard || other->type == MfDesfireFileTypeBackup) { + file->data = other->data; + if(other->data.size == 0) { + return; + } + + file->contents = malloc(other->data.size); + memcpy(file->contents, other->contents, other->data.size); + + } else if(other->type == MfDesfireFileTypeValue) { + file->value = other->value; + } else if( + other->type == MfDesfireFileTypeLinearRecord || + other->type == MfDesfireFileTypeCyclicRecord) { + file->record = other->record; + } else { + furi_crash("Invalid file type"); + } +} + +static inline void mf_desfire_copy_files(MfDesfireFiles* files, const MfDesfireFiles* other) { + furi_assert(files->data == NULL); + + files->count = other->count; + if(other->count == 0) { + return; + } + + files->data = malloc(other->count * sizeof(MfDesfireFile)); + + for(size_t i = 0; i < other->count; ++i) { + mf_desfire_copy_file(&files->data[i], &other->data[i]); + } +} + +static inline void + mf_desfire_copy_application(MfDesfireApplication* app, const MfDesfireApplication* other) { + memcpy(app->id, other->id, sizeof(other->id)); + mf_desfire_copy_key_config(&app->key_config, &other->key_config); + mf_desfire_copy_files(&app->files, &other->files); +} + +static inline void + mf_desfire_copy_applications(MfDesfireApplications* apps, const MfDesfireApplications* other) { + furi_assert(apps->data == NULL); + + apps->count = other->count; + if(other->count == 0) { + return; + } + + apps->data = malloc(other->count * sizeof(MfDesfireApplication)); + + for(size_t i = 0; i < other->count; ++i) { + mf_desfire_copy_application(&apps->data[i], &other->data[i]); + } +} + +void mf_desfire_copy(MfDesfireData* data, const MfDesfireData* other) { + furi_assert(data); + furi_assert(other); + + mf_desfire_reset(data); + + iso14443_4a_copy(data->iso14443_4a_data, other->iso14443_4a_data); + + data->version = other->version; + data->free_memory = other->free_memory; + + mf_desfire_copy_key_config(&data->master_key, &other->master_key); + mf_desfire_copy_applications(&data->applications, &other->applications); +} + +bool mf_desfire_verify(MfDesfireData* data, const FuriString* device_type) { + UNUSED(data); + return furi_string_equal_str(device_type, "Mifare Desfire"); +} + +bool mf_desfire_load(MfDesfireData* data, FlipperFormat* ff, uint32_t version) { + UNUSED(data); + UNUSED(ff); + UNUSED(version); + + // TODO: Implementation + return false; +} + +bool mf_desfire_save(const MfDesfireData* data, FlipperFormat* ff, uint32_t version) { + UNUSED(data); + UNUSED(ff); + UNUSED(version); + + // TODO: Implementation + return false; +} + +bool mf_desfire_is_equal(const MfDesfireData* data, const MfDesfireData* other) { + furi_assert(data); + furi_assert(other); + + // TODO: Complete equality method + return iso14443_4a_is_equal(data->iso14443_4a_data, other->iso14443_4a_data); +} + +const char* mf_desfire_get_name(const MfDesfireData* data, NfcProtocolNameType name_type) { + UNUSED(data); + UNUSED(name_type); + return MF_DESFIRE_PROTOCOL_NAME; +} + +const uint8_t* mf_desfire_get_uid(const MfDesfireData* data, size_t* uid_len) { + furi_assert(data); + + return iso14443_4a_get_uid(data->iso14443_4a_data, uid_len); +} + bool mf_desfire_detect_protocol(NfcaData* nfca_data) { furi_assert(nfca_data); diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire.h b/lib/nfc/protocols/mf_desfire/mf_desfire.h index d8dac7d3f302..72d230e43a3b 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire.h +++ b/lib/nfc/protocols/mf_desfire/mf_desfire.h @@ -131,13 +131,35 @@ typedef enum { } MfDesfireError; typedef struct { - Iso14443_4aData iso14443_4a_data; + Iso14443_4aData* iso14443_4a_data; MfDesfireVersion version; MfDesfireFreeMemory free_memory; MfDesfireKeyConfiguration master_key; MfDesfireApplications applications; } MfDesfireData; +extern const NfcProtocolBase nfc_protocol_mf_desfire; + +MfDesfireData* mf_desfire_alloc(); + +void mf_desfire_free(MfDesfireData* data); + +void mf_desfire_reset(MfDesfireData* data); + +void mf_desfire_copy(MfDesfireData* data, const MfDesfireData* other); + +bool mf_desfire_verify(MfDesfireData* data, const FuriString* device_type); + +bool mf_desfire_load(MfDesfireData* data, FlipperFormat* ff, uint32_t version); + +bool mf_desfire_save(const MfDesfireData* data, FlipperFormat* ff, uint32_t version); + +bool mf_desfire_is_equal(const MfDesfireData* data, const MfDesfireData* other); + +const char* mf_desfire_get_name(const MfDesfireData* data, NfcProtocolNameType name_type); + +const uint8_t* mf_desfire_get_uid(const MfDesfireData* data, size_t* uid_len); + bool mf_desfire_detect_protocol(NfcaData* nfca_data); #ifdef __cplusplus diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c b/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c index c1cf5f7f5159..45062163ad95 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c @@ -36,12 +36,21 @@ void mf_desfire_poller_free(MfDesfirePoller* instance) { free(instance); } +const MfDesfireData* mf_desfire_poller_get_data(MfDesfirePoller* instance) { + furi_assert(instance); + + return instance->data; +} + static MfDesfirePollerCommand mf_desfire_poller_handler_idle(MfDesfirePoller* instance) { bit_buffer_reset(instance->input_buffer); bit_buffer_reset(instance->result_buffer); bit_buffer_reset(instance->tx_buffer); bit_buffer_reset(instance->rx_buffer); - iso14443_4a_poller_get_data(instance->iso14443_4a_poller, &instance->data->iso14443_4a_data); + + iso14443_4a_copy( + instance->data->iso14443_4a_data, + iso14443_4a_poller_get_data(instance->iso14443_4a_poller)); instance->state = MfDesfirePollerStateReadVersion; return MfDesfirePollerCommandContinue; @@ -156,7 +165,7 @@ MfDesfireError mf_desfire_poller_start( furi_assert(callback); furi_assert(instance->session_state == MfDesfirePollerSessionStateIdle); - instance->data = malloc(sizeof(MfDesfireData)); + instance->data = mf_desfire_alloc(); instance->input_buffer = bit_buffer_alloc(MF_DESFIRE_BUF_SIZE_MAX); instance->result_buffer = bit_buffer_alloc(MF_DESFIRE_BUF_SIZE_MAX); instance->tx_buffer = bit_buffer_alloc(MF_DESFIRE_BUF_SIZE_MAX); @@ -183,16 +192,6 @@ MfDesfireError mf_desfire_poller_read( return mf_desfire_poller_start(instance, mf_desfire_poller_read_callback, instance); } -MfDesfireError mf_desfire_poller_get_data(MfDesfirePoller* instance, MfDesfireData* data) { - furi_assert(instance); - furi_assert(instance->data); - furi_assert(data); - - *data = *instance->data; - - return MfDesfireErrorNone; -} - MfDesfireError mf_desfire_poller_reset(MfDesfirePoller* instance) { furi_assert(instance); furi_assert(instance->data); @@ -221,7 +220,7 @@ MfDesfireError mf_desfire_poller_stop(MfDesfirePoller* instance) { instance->session_state = MfDesfirePollerSessionStateStopRequest; iso14443_4a_poller_stop(instance->iso14443_4a_poller); instance->session_state = MfDesfirePollerSessionStateIdle; - free(instance->data); + mf_desfire_free(instance->data); return mf_desfire_poller_reset(instance); } diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_poller.h b/lib/nfc/protocols/mf_desfire/mf_desfire_poller.h index 00689e4152c1..d2ade664f276 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_poller.h +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_poller.h @@ -39,6 +39,8 @@ MfDesfirePoller* mf_desfire_poller_alloc(Iso14443_4aPoller* iso14443_4a_poller); void mf_desfire_poller_free(MfDesfirePoller* instance); +const MfDesfireData* mf_desfire_poller_get_data(MfDesfirePoller* instance); + MfDesfireError mf_desfire_poller_start( MfDesfirePoller* instance, Iso14443_4aPollerCallback callback, @@ -49,8 +51,6 @@ MfDesfireError mf_desfire_poller_read( MfDesfirePollerCallback callback, void* context); -MfDesfireError mf_desfire_poller_get_data(MfDesfirePoller* instance, MfDesfireData* data); - MfDesfireError mf_desfire_poller_stop(MfDesfirePoller* instance); #ifdef __cplusplus diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight.c index 2037ee7710bc..eb9978510cb6 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight.c @@ -8,6 +8,8 @@ typedef struct { uint32_t feature_set; } MfUltralightFeatures; +static const uint32_t mf_ultralight_data_format_version = 1; + static const MfUltralightFeatures mf_ultralight_features[MfUltralightTypeNum] = { [MfUltralightTypeUnknown] = { @@ -113,6 +115,276 @@ static const MfUltralightFeatures mf_ultralight_features[MfUltralightTypeNum] = }, }; +const NfcProtocolBase nfc_protocol_mf_ultralight = { + .alloc = (NfcProtocolAlloc)mf_ultralight_alloc, + .free = (NfcProtocolFree)mf_ultralight_free, + .reset = (NfcProtocolReset)mf_ultralight_reset, + .copy = (NfcProtocolCopy)mf_ultralight_copy, + .verify = (NfcProtocolVerify)mf_ultralight_verify, + .load = (NfcProtocolLoad)mf_ultralight_load, + .save = (NfcProtocolSave)mf_ultralight_save, + .is_equal = (NfcProtocolEqual)mf_ultralight_is_equal, + .get_name = (NfcProtocolGetName)mf_ultralight_get_name, + .get_uid = (NfcProtocolGetUid)mf_ultralight_get_uid, +}; + +MfUltralightData* mf_ultralight_alloc() { + MfUltralightData* data = malloc(sizeof(MfUltralightData)); + data->nfca_data = nfca_alloc(); + return data; +} + +void mf_ultralight_free(MfUltralightData* data) { + furi_assert(data); + + nfca_free(data->nfca_data); + free(data); +} + +void mf_ultralight_reset(MfUltralightData* data) { + furi_assert(data); + + nfca_reset(data->nfca_data); +} + +void mf_ultralight_copy(MfUltralightData* data, const MfUltralightData* other) { + furi_assert(data); + furi_assert(other); + + nfca_copy(data->nfca_data, other->nfca_data); + memcpy(data->counter, other->counter, MF_ULTRALIGHT_COUNTER_NUM); + memcpy(data->tearing_flag, other->tearing_flag, MF_ULTRALIGHT_TEARING_FLAG_NUM); + memcpy(data->page, other->page, MF_ULTRALIGHT_MAX_PAGE_NUM); + + data->type = other->type; + data->version = other->version; + data->signature = other->signature; + + data->pages_read = other->pages_read; + data->pages_total = other->pages_total; + data->auth_attempts = other->auth_attempts; +} + +// TODO: Improve this function +static const char* mf_ultralight_get_name_by_type(MfUltralightType type, bool full_name) { + // FIXME: Use a LUT instead of if/switch + if(type == MfUltralightTypeNTAG213) { + return "NTAG213"; + } else if(type == MfUltralightTypeNTAG215) { + return "NTAG215"; + } else if(type == MfUltralightTypeNTAG216) { + return "NTAG216"; + } else if(type == MfUltralightTypeNTAGI2C1K) { + return "NTAG I2C 1K"; + } else if(type == MfUltralightTypeNTAGI2C2K) { + return "NTAG I2C 2K"; + } else if(type == MfUltralightTypeNTAGI2CPlus1K) { + return "NTAG I2C Plus 1K"; + } else if(type == MfUltralightTypeNTAGI2CPlus2K) { + return "NTAG I2C Plus 2K"; + } else if(type == MfUltralightTypeNTAG203) { + return "NTAG203"; + } else if(type == MfUltralightTypeUL11 && full_name) { + return "Mifare Ultralight 11"; + } else if(type == MfUltralightTypeUL21 && full_name) { + return "Mifare Ultralight 21"; + } else { + return "Mifare Ultralight"; + } +} + +bool mf_ultralight_verify(MfUltralightData* data, const FuriString* device_type) { + furi_assert(data); + + bool verified = false; + + for(MfUltralightType i = 0; i < MfUltralightTypeNum; i++) { + const char* name = mf_ultralight_get_name_by_type(i, true); + verified = furi_string_equal_str(device_type, name); + if(verified) { + data->type = i; + break; + } + } + + return verified; +} + +bool mf_ultralight_load(MfUltralightData* data, FlipperFormat* ff, uint32_t version) { + furi_assert(data); + + FuriString* temp_str = furi_string_alloc(); + bool parsed = false; + + do { + // Read NFCA data + if(!nfca_load_data(data->nfca_data, ff, version)) break; + + // Read Ultralight specific data + // Read Mifare Ultralight format version + uint32_t data_format_version = 0; + if(!flipper_format_read_uint32(ff, "Data format version", &data_format_version, 1)) { + if(!flipper_format_rewind(ff)) break; + } + + // Read signature + if(!flipper_format_read_hex( + ff, "Signature", data->signature.data, sizeof(MfUltralightSignature))) + break; + // Read Mifare version + if(!flipper_format_read_hex( + ff, "Mifare version", (uint8_t*)&data->version, sizeof(MfUltralightVersion))) + break; + // Read counters and tearing flags + bool counters_parsed = true; + for(size_t i = 0; i < 3; i++) { + furi_string_printf(temp_str, "Counter %d", i); + if(!flipper_format_read_uint32( + ff, furi_string_get_cstr(temp_str), &data->counter[i].counter, 1)) { + counters_parsed = false; + break; + } + furi_string_printf(temp_str, "Tearing %d", i); + if(!flipper_format_read_hex( + ff, furi_string_get_cstr(temp_str), data->tearing_flag[i].data, 1)) { + counters_parsed = false; + break; + } + } + if(!counters_parsed) break; + // Read pages + uint32_t pages_total = 0; + if(!flipper_format_read_uint32(ff, "Pages total", &pages_total, 1)) break; + uint32_t pages_read = 0; + if(data_format_version < mf_ultralight_data_format_version) { + pages_read = pages_total; + } else { + if(!flipper_format_read_uint32(ff, "Pages read", &pages_read, 1)) break; + } + data->pages_total = pages_total; + data->pages_read = pages_read; + + if((pages_read > MF_ULTRALIGHT_MAX_PAGE_NUM) || (pages_total > MF_ULTRALIGHT_MAX_PAGE_NUM)) + break; + + bool pages_parsed = true; + for(size_t i = 0; i < pages_total; i++) { + furi_string_printf(temp_str, "Page %d", i); + if(!flipper_format_read_hex( + ff, + furi_string_get_cstr(temp_str), + data->page[i].data, + sizeof(MfUltralightPage))) { + pages_parsed = false; + break; + } + } + if(!pages_parsed) break; + + // Read authentication counter + if(!flipper_format_read_uint32( + ff, "Failed authentication attempts", &data->auth_attempts, 1)) { + data->auth_attempts = 0; + } + + parsed = true; + } while(false); + + furi_string_free(temp_str); + + return parsed; +} + +bool mf_ultralight_save(const MfUltralightData* data, FlipperFormat* ff, uint32_t version) { + furi_assert(data); + + FuriString* temp_str = furi_string_alloc(); + bool saved = false; + + do { + const char* device_type_name = mf_ultralight_get_name_by_type(data->type, true); + if(!flipper_format_write_string_cstr(ff, "Device type", device_type_name)) break; + if(!nfca_save_data(data->nfca_data, ff, version)) break; + if(!flipper_format_write_comment_cstr(ff, "Mifare Ultralight specific data")) break; + if(!flipper_format_write_uint32( + ff, "Data format version", &mf_ultralight_data_format_version, 1)) + break; + if(!flipper_format_write_hex( + ff, "Signature", data->signature.data, sizeof(MfUltralightSignature))) + break; + if(!flipper_format_write_hex( + ff, "Mifare version", (uint8_t*)&data->version, sizeof(MfUltralightVersion))) + break; + + // Write conters and tearing flags data + bool counters_saved = true; + for(size_t i = 0; i < 3; i++) { + furi_string_printf(temp_str, "Counter %d", i); + if(!flipper_format_write_uint32( + ff, furi_string_get_cstr(temp_str), &data->counter[i].counter, 1)) { + counters_saved = false; + break; + } + furi_string_printf(temp_str, "Tearing %d", i); + if(!flipper_format_write_hex( + ff, furi_string_get_cstr(temp_str), data->tearing_flag->data, 1)) { + counters_saved = false; + break; + } + } + if(!counters_saved) break; + + // Write pages data + uint32_t pages_total = data->pages_total; + uint32_t pages_read = data->pages_read; + if(!flipper_format_write_uint32(ff, "Pages total", &pages_total, 1)) break; + if(!flipper_format_write_uint32(ff, "Pages read", &pages_read, 1)) break; + bool pages_saved = true; + for(size_t i = 0; i < data->pages_total; i++) { + furi_string_printf(temp_str, "Page %d", i); + if(!flipper_format_write_hex( + ff, + furi_string_get_cstr(temp_str), + data->page[i].data, + sizeof(MfUltralightPage))) { + pages_saved = false; + break; + } + } + if(!pages_saved) break; + + // Write authentication counter + if(!flipper_format_write_uint32( + ff, "Failed authentication attempts", &data->auth_attempts, 1)) + break; + + saved = true; + } while(false); + + furi_string_free(temp_str); + + return saved; +} + +bool mf_ultralight_is_equal(const MfUltralightData* data, const MfUltralightData* other) { + // TODO: Complete equality method + return nfca_is_equal(data->nfca_data, other->nfca_data); +} + +// TODO: Improve this function +const char* mf_ultralight_get_name(const MfUltralightData* data, NfcProtocolNameType name_type) { + furi_assert(data); + furi_assert(data->type < MfUltralightTypeNum); + + return mf_ultralight_get_name_by_type(data->type, name_type == NfcProtocolNameTypeFull); +} + +const uint8_t* mf_ultralight_get_uid(const MfUltralightData* data, size_t* uid_len) { + furi_assert(data); + + return nfca_get_uid(data->nfca_data, uid_len); +} + MfUltralightType mf_ultralight_get_type_by_version(MfUltralightVersion* version) { furi_assert(version); @@ -155,33 +427,7 @@ uint32_t mf_ultralight_get_feature_support_set(MfUltralightType type) { return mf_ultralight_features[type].feature_set; } -const char* mf_ultralight_get_name(MfUltralightType type, bool full_name) { - if(type == MfUltralightTypeNTAG213) { - return "NTAG213"; - } else if(type == MfUltralightTypeNTAG215) { - return "NTAG215"; - } else if(type == MfUltralightTypeNTAG216) { - return "NTAG216"; - } else if(type == MfUltralightTypeNTAGI2C1K) { - return "NTAG I2C 1K"; - } else if(type == MfUltralightTypeNTAGI2C2K) { - return "NTAG I2C 2K"; - } else if(type == MfUltralightTypeNTAGI2CPlus1K) { - return "NTAG I2C Plus 1K"; - } else if(type == MfUltralightTypeNTAGI2CPlus2K) { - return "NTAG I2C Plus 2K"; - } else if(type == MfUltralightTypeNTAG203) { - return "NTAG203"; - } else if(type == MfUltralightTypeUL11 && full_name) { - return "Mifare Ultralight 11"; - } else if(type == MfUltralightTypeUL21 && full_name) { - return "Mifare Ultralight 21"; - } else { - return "Mifare Ultralight"; - } -} - -bool mf_ultralight_detect_protocol(NfcaData* nfca_data) { +bool mf_ultralight_detect_protocol(const NfcaData* nfca_data) { furi_assert(nfca_data); bool mfu_detected = (nfca_data->atqa[0] == 0x44) && (nfca_data->atqa[1] == 0x00) && @@ -194,7 +440,7 @@ uint16_t mf_ultralight_get_config_page_num(MfUltralightType type) { return mf_ultralight_features[type].config_page; } -bool mf_ultralight_get_config_page(MfUltralightData* data, MfUltralightConfigPages** config) { +bool mf_ultralight_get_config_page(const MfUltralightData* data, MfUltralightConfigPages** config) { furi_assert(data); furi_assert(config); @@ -209,7 +455,7 @@ bool mf_ultralight_get_config_page(MfUltralightData* data, MfUltralightConfigPag return config_pages_found; } -bool mf_ultralight_is_all_data_read(MfUltralightData* data) { +bool mf_ultralight_is_all_data_read(const MfUltralightData* data) { furi_assert(data); bool all_read = false; @@ -231,7 +477,7 @@ bool mf_ultralight_is_all_data_read(MfUltralightData* data) { return all_read; } -bool mf_ultralight_is_counter_configured(MfUltralightData* data) { +bool mf_ultralight_is_counter_configured(const MfUltralightData* data) { furi_assert(data); MfUltralightConfigPages* config = NULL; diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h index 1bb52847c54d..7a875eb3c4d7 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h @@ -153,7 +153,7 @@ typedef struct __attribute__((packed)) { } MfUltralightConfigPages; typedef struct { - NfcaData nfca_data; + NfcaData* nfca_data; MfUltralightType type; MfUltralightVersion version; MfUltralightSignature signature; @@ -165,23 +165,43 @@ typedef struct { uint32_t auth_attempts; } MfUltralightData; +extern const NfcProtocolBase nfc_protocol_mf_ultralight; + +MfUltralightData* mf_ultralight_alloc(); + +void mf_ultralight_free(MfUltralightData* data); + +void mf_ultralight_reset(MfUltralightData* data); + +void mf_ultralight_copy(MfUltralightData* data, const MfUltralightData* other); + +bool mf_ultralight_verify(MfUltralightData* data, const FuriString* device_type); + +bool mf_ultralight_load(MfUltralightData* data, FlipperFormat* ff, uint32_t version); + +bool mf_ultralight_save(const MfUltralightData* data, FlipperFormat* ff, uint32_t version); + +bool mf_ultralight_is_equal(const MfUltralightData* data, const MfUltralightData* other); + +const char* mf_ultralight_get_name(const MfUltralightData* data, NfcProtocolNameType name_type); + +const uint8_t* mf_ultralight_get_uid(const MfUltralightData* data, size_t* uid_len); + MfUltralightType mf_ultralight_get_type_by_version(MfUltralightVersion* version); uint16_t mf_ultralight_get_pages_total(MfUltralightType type); uint32_t mf_ultralight_get_feature_support_set(MfUltralightType type); -const char* mf_ultralight_get_name(MfUltralightType type, bool full_name); - uint16_t mf_ultralight_get_config_page_num(MfUltralightType type); -bool mf_ultralight_get_config_page(MfUltralightData* data, MfUltralightConfigPages** config); +bool mf_ultralight_get_config_page(const MfUltralightData* data, MfUltralightConfigPages** config); -bool mf_ultralight_is_all_data_read(MfUltralightData* data); +bool mf_ultralight_is_all_data_read(const MfUltralightData* data); -bool mf_ultralight_detect_protocol(NfcaData* nfca_data); +bool mf_ultralight_detect_protocol(const NfcaData* nfca_data); -bool mf_ultralight_is_counter_configured(MfUltralightData* data); +bool mf_ultralight_is_counter_configured(const MfUltralightData* data); #ifdef __cplusplus } diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c index 16d8611aa39b..c5d7af93b1b7 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c @@ -390,14 +390,14 @@ MfUltralightListener* mf_ultralight_listener_alloc(NfcaListener* nfca_listener) MfUltralightError mf_ultralight_listener_start( MfUltralightListener* instance, - MfUltralightData* data, + const MfUltralightData* data, MfUltralightListenerEventCallback callback, void* context) { furi_assert(instance); furi_assert(data); - instance->data = malloc(sizeof(MfUltralightData)); - *instance->data = *data; + instance->data = mf_ultralight_alloc(); + mf_ultralight_copy(instance->data, data); mf_ultralight_listener_prepare_emulation(instance); instance->callback = callback; @@ -405,7 +405,7 @@ MfUltralightError mf_ultralight_listener_start( NfcaError error = nfca_listener_start( instance->nfca_listener, - &instance->data->nfca_data, + instance->data->nfca_data, mf_ultralight_listener_event_handler, instance); @@ -424,7 +424,7 @@ MfUltralightError furi_assert(instance->data); furi_assert(data); - *data = *instance->data; + mf_ultralight_copy(data, instance->data); return MfUltralightErrorNone; } @@ -435,7 +435,7 @@ MfUltralightError mf_ultralight_listener_stop(MfUltralightListener* instance) { NfcaError error = nfca_listener_stop(instance->nfca_listener); instance->state = MfUltraligthListenerStateIdle; - free(instance->data); + mf_ultralight_free(instance->data); return mf_ultralight_process_error(error); } diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.h index 6858b4657db0..95ee14dbcfad 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.h @@ -38,7 +38,7 @@ void mf_ultralight_listener_free(MfUltralightListener* instance); MfUltralightError mf_ultralight_listener_start( MfUltralightListener* instance, - MfUltralightData* data, + const MfUltralightData* data, MfUltralightListenerEventCallback callback, void* context); diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c index df5fb693a8ec..a9632f210be8 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c @@ -38,9 +38,15 @@ void mf_ultralight_poller_free(MfUltralightPoller* instance) { free(instance); } +const MfUltralightData* mf_ultralight_poller_get_data(MfUltralightPoller* instance) { + furi_assert(instance); + + return instance->data; +} + static MfUltralightPollerCommand mf_ultralight_poller_handler_idle(MfUltralightPoller* instance) { nfc_poller_buffer_reset(instance->buffer); - nfca_poller_get_data(instance->nfca_poller, &instance->data->nfca_data); + nfca_copy(instance->data->nfca_data, nfca_poller_get_data(instance->nfca_poller)); instance->counters_read = 0; instance->counters_total = 3; instance->tearing_flag_read = 0; @@ -94,7 +100,7 @@ static MfUltralightPollerCommand FURI_LOG_D( TAG, "%s detected. Total pages: %d", - mf_ultralight_get_name(instance->data->type, true), + mf_ultralight_get_name(instance->data, NfcProtocolNameTypeFull), instance->pages_total); instance->state = MfUltralightPollerStateReadSignature; @@ -366,7 +372,7 @@ MfUltralightError mf_ultralight_poller_start( furi_assert(callback); furi_assert(instance->session_state == MfUltralightPollerSessionStateIdle); - instance->data = malloc(sizeof(MfUltralightData)); + instance->data = mf_ultralight_alloc(); instance->buffer = nfc_poller_buffer_alloc(MF_ULTRALIGHT_MAX_BUFF_SIZE, MF_ULTRALIGHT_MAX_BUFF_SIZE); @@ -391,17 +397,6 @@ MfUltralightError mf_ultralight_poller_read( return mf_ultralight_poller_start(instance, mf_ultralight_poller_read_callback, instance); } -MfUltralightError - mf_ultralight_poller_get_data(MfUltralightPoller* instance, MfUltralightData* data) { - furi_assert(instance); - furi_assert(instance->data); - furi_assert(data); - - *data = *instance->data; - - return MfUltralightErrorNone; -} - MfUltralightError mf_ultralight_poller_reset(MfUltralightPoller* instance) { furi_assert(instance); furi_assert(instance->data); @@ -423,7 +418,7 @@ MfUltralightError mf_ultralight_poller_stop(MfUltralightPoller* instance) { instance->session_state = MfUltralightPollerSessionStateStopRequest; nfca_poller_stop(instance->nfca_poller); instance->session_state = MfUltralightPollerSessionStateIdle; - free(instance->data); + mf_ultralight_free(instance->data); return mf_ultralight_poller_reset(instance); } diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h index cf059b2a0ea9..4b7c7a9f2d15 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h @@ -49,6 +49,8 @@ MfUltralightPoller* mf_ultralight_poller_alloc(NfcaPoller* nfca_poller); void mf_ultralight_poller_free(MfUltralightPoller* instance); +const MfUltralightData* mf_ultralight_poller_get_data(MfUltralightPoller* instance); + MfUltralightError mf_ultralight_poller_start( MfUltralightPoller* instance, NfcaPollerEventCallback callback, @@ -59,9 +61,6 @@ MfUltralightError mf_ultralight_poller_read( MfUltralightPollerCallback callback, void* context); -MfUltralightError - mf_ultralight_poller_get_data(MfUltralightPoller* instance, MfUltralightData* data); - MfUltralightError mf_ultralight_poller_reset(MfUltralightPoller* instance); MfUltralightError mf_ultralight_poller_stop(MfUltralightPoller* instance); diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c index 7074d96c649e..86bdd27aaf17 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c @@ -253,7 +253,8 @@ static MfUltralightPollerCommand MfUltralightPollerCommand command = MfUltralightPollerCommandContinue; if(event.type == MfUltralightPollerEventTypeReadSuccess) { - mf_ultralight_poller_get_data(poller_context->instance, &poller_context->data.data); + mf_ultralight_copy( + &poller_context->data.data, mf_ultralight_poller_get_data(poller_context->instance)); poller_context->error = MfUltralightErrorNone; command = MfUltralightPollerCommandStop; } else if(event.type == MfUltralightPollerEventTypeReadFailed) { @@ -283,7 +284,7 @@ MfUltralightError furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); if(poller_context.error == MfUltralightErrorNone) { - *data = poller_context.data.data; + mf_ultralight_copy(data, &poller_context.data.data); } mf_ultralight_poller_stop(instance); diff --git a/lib/nfc/protocols/nfc_protocol_base.h b/lib/nfc/protocols/nfc_protocol_base.h new file mode 100644 index 000000000000..d2bded0c7e84 --- /dev/null +++ b/lib/nfc/protocols/nfc_protocol_base.h @@ -0,0 +1,43 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + NfcProtocolNameTypeFull, + NfcProtocolNameTypeShort, +} NfcProtocolNameType; + +typedef void NfcProtocolData; + +typedef NfcProtocolData* (*NfcProtocolAlloc)(); +typedef void (*NfcProtocolFree)(NfcProtocolData* data); +typedef void (*NfcProtocolReset)(NfcProtocolData* data); +typedef void (*NfcProtocolCopy)(NfcProtocolData* data, const NfcProtocolData* other); +typedef bool (*NfcProtocolVerify)(NfcProtocolData* data, const FuriString* device_type); +typedef bool (*NfcProtocolLoad)(NfcProtocolData* data, FlipperFormat* ff, uint32_t version); +typedef bool (*NfcProtocolSave)(const NfcProtocolData* data, FlipperFormat* ff, uint32_t version); +typedef bool (*NfcProtocolEqual)(const NfcProtocolData* data, const NfcProtocolData* other); +typedef const char* ( + *NfcProtocolGetName)(const NfcProtocolData* data, NfcProtocolNameType name_type); +typedef const uint8_t* (*NfcProtocolGetUid)(const NfcProtocolData* data, size_t* uid_len); + +typedef struct { + NfcProtocolAlloc alloc; + NfcProtocolFree free; + NfcProtocolReset reset; + NfcProtocolCopy copy; + NfcProtocolVerify verify; + NfcProtocolLoad load; + NfcProtocolSave save; + NfcProtocolEqual is_equal; + NfcProtocolGetName get_name; + NfcProtocolGetUid get_uid; +} NfcProtocolBase; + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/nfc_protocol_defs.c b/lib/nfc/protocols/nfc_protocol_defs.c new file mode 100644 index 000000000000..cb3bae78eb77 --- /dev/null +++ b/lib/nfc/protocols/nfc_protocol_defs.c @@ -0,0 +1,16 @@ +#include "nfc_protocol_defs.h" + +#include +#include +#include +#include +#include + +const NfcProtocolBase* nfc_protocols[NfcProtocolTypeMax] = { + [NfcProtocolTypeIso14443_3a] = &nfc_protocol_iso14443_3a, + [NfcProtocolTypeIso14443_4a] = &nfc_protocol_iso14443_4a, + [NfcProtocolTypeMfUltralight] = &nfc_protocol_mf_ultralight, + [NfcProtocolTypeMfClassic] = &nfc_protocol_mf_classic, + [NfcProtocolTypeMfDesfire] = &nfc_protocol_mf_desfire, + /* Add new protocols here */ +}; diff --git a/lib/nfc/protocols/nfc_protocol_defs.h b/lib/nfc/protocols/nfc_protocol_defs.h new file mode 100644 index 000000000000..fd3c6dda2eb3 --- /dev/null +++ b/lib/nfc/protocols/nfc_protocol_defs.h @@ -0,0 +1,24 @@ +#pragma once + +#include "nfc_protocol_base.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + NfcProtocolTypeIso14443_3a, + NfcProtocolTypeIso14443_4a, + NfcProtocolTypeMfUltralight, + NfcProtocolTypeMfClassic, + NfcProtocolTypeMfDesfire, + /* Add new protocols here */ + + NfcProtocolTypeMax, +} NfcProtocolType; + +extern const NfcProtocolBase* nfc_protocols[]; + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/nfca/nfca.c b/lib/nfc/protocols/nfca/nfca.c index 9e1e5513e6f0..f075573f2edb 100644 --- a/lib/nfc/protocols/nfca/nfca.c +++ b/lib/nfc/protocols/nfca/nfca.c @@ -1,8 +1,91 @@ #include "nfca.h" #include +#include #define NFCA_CRC_INIT (0x6363) +#define NFCA_PROTOCOL_NAME "Unknown ISO14443-3A Tag" + +const NfcProtocolBase nfc_protocol_iso14443_3a = { + .alloc = (NfcProtocolAlloc)nfca_alloc, + .free = (NfcProtocolFree)nfca_free, + .reset = (NfcProtocolReset)nfca_reset, + .copy = (NfcProtocolCopy)nfca_copy, + .verify = (NfcProtocolVerify)nfca_verify, + .load = (NfcProtocolLoad)nfca_load, + .save = (NfcProtocolSave)nfca_save, + .is_equal = (NfcProtocolEqual)nfca_is_equal, + .get_name = (NfcProtocolGetName)nfca_get_name, + .get_uid = (NfcProtocolGetUid)nfca_get_uid, +}; + +NfcaData* nfca_alloc() { + NfcaData* data = malloc(sizeof(NfcaData)); + return data; +} + +void nfca_free(NfcaData* data) { + furi_assert(data); + + free(data); +} + +void nfca_reset(NfcaData* data) { + furi_assert(data); + + UNUSED(data); +} + +void nfca_copy(NfcaData* data, const NfcaData* other) { + furi_assert(data); + furi_assert(other); + + *data = *other; +} + +bool nfca_verify(NfcaData* data, const FuriString* device_type) { + UNUSED(data); + return furi_string_equal(device_type, "UID"); +} + +bool nfca_load(NfcaData* data, FlipperFormat* ff, uint32_t version) { + return nfca_load_data(data, ff, version); + return true; +} + +bool nfca_save(const NfcaData* data, FlipperFormat* ff, uint32_t version) { + bool saved = false; + do { + if(!flipper_format_write_string_cstr(ff, "Device type", "UID")) break; + if(!nfca_save_data(data, ff, version)) break; + saved = true; + } while(false); + + return saved; +} + +bool nfca_is_equal(const NfcaData* data, const NfcaData* other) { + furi_assert(data); + furi_assert(other); + + return memcmp(data, other, sizeof(NfcaData)) == 0; +} + +const char* nfca_get_name(const NfcaData* data, NfcProtocolNameType name_type) { + UNUSED(data); + UNUSED(name_type); + return NFCA_PROTOCOL_NAME; +} + +const uint8_t* nfca_get_uid(const NfcaData* data, size_t* uid_len) { + furi_assert(data); + + if(uid_len) { + *uid_len = data->uid_len; + } + + return data->uid; +} uint16_t nfca_get_crc(uint8_t* buff, uint16_t len) { furi_assert(buff); @@ -40,3 +123,51 @@ bool nfca_check_crc(uint8_t* buff, uint16_t len) { return crc_ok; } + +bool nfca_load_data(NfcaData* data, FlipperFormat* ff, uint32_t version) { + furi_assert(data); + + uint32_t data_cnt = 0; + bool parsed = false; + + do { + if(!flipper_format_get_value_count(ff, "UID", &data_cnt)) break; + if(!(data_cnt == 4 || data_cnt == 7)) break; + data->uid_len = data_cnt; + if(!flipper_format_read_hex(ff, "UID", data->uid, data->uid_len)) break; + if(version == NFC_LSB_ATQA_FORMAT_VERSION) { + if(!flipper_format_read_hex(ff, "ATQA", data->atqa, 2)) break; + } else { + uint8_t atqa[2] = {}; + if(!flipper_format_read_hex(ff, "ATQA", atqa, 2)) break; + data->atqa[0] = atqa[1]; + data->atqa[1] = atqa[0]; + } + if(!flipper_format_read_hex(ff, "SAK", &data->sak, 1)) break; + + parsed = true; + } while(false); + + return parsed; +} + +bool nfca_save_data(const NfcaData* data, FlipperFormat* ff, uint32_t version) { + furi_assert(data); + + UNUSED(version); + + bool saved = false; + do { + // Write UID, ATQA, SAK + if(!flipper_format_write_comment_cstr(ff, "UID, ATQA and SAK are common for all formats")) + break; + if(!flipper_format_write_hex(ff, "UID", data->uid, data->uid_len)) break; + // Save ATQA in MSB order for correct companion apps display + uint8_t atqa[2] = {data->atqa[1], data->atqa[0]}; + if(!flipper_format_write_hex(ff, "ATQA", atqa, 2)) break; + if(!flipper_format_write_hex(ff, "SAK", &data->sak, 1)) break; + saved = true; + } while(false); + + return saved; +} diff --git a/lib/nfc/protocols/nfca/nfca.h b/lib/nfc/protocols/nfca/nfca.h index 219b8eb0fcfa..51b456e51e0f 100644 --- a/lib/nfc/protocols/nfca/nfca.h +++ b/lib/nfc/protocols/nfca/nfca.h @@ -2,7 +2,8 @@ #include #include -#include + +#include #ifdef __cplusplus extern "C" { @@ -65,12 +66,39 @@ typedef struct { NfcaRats rats; } NfcaData; +extern const NfcProtocolBase nfc_protocol_iso14443_3a; + +NfcaData* nfca_alloc(); + +void nfca_free(NfcaData* data); + +void nfca_reset(NfcaData* data); + +void nfca_copy(NfcaData* data, const NfcaData* other); + +bool nfca_verify(NfcaData* data, const FuriString* device_type); + +bool nfca_load(NfcaData* data, FlipperFormat* ff, uint32_t version); + +bool nfca_save(const NfcaData* data, FlipperFormat* ff, uint32_t version); + +bool nfca_is_equal(const NfcaData* data, const NfcaData* other); + +const char* nfca_get_name(const NfcaData* data, NfcProtocolNameType name_type); + +const uint8_t* nfca_get_uid(const NfcaData* data, size_t* uid_len); + uint16_t nfca_get_crc(uint8_t* buff, uint16_t len); void nfca_append_crc(uint8_t* buff, uint16_t len); bool nfca_check_crc(uint8_t* buff, uint16_t len); +// TODO: Decide where should these methods go (*_i file?) +bool nfca_load_data(NfcaData* data, FlipperFormat* ff, uint32_t version); + +bool nfca_save_data(const NfcaData* data, FlipperFormat* ff, uint32_t version); + #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/nfca/nfca_listener.c b/lib/nfc/protocols/nfca/nfca_listener.c index 4f59d3e2a511..be77b10f8956 100644 --- a/lib/nfc/protocols/nfca/nfca_listener.c +++ b/lib/nfc/protocols/nfca/nfca_listener.c @@ -140,7 +140,7 @@ void nfca_listener_free(NfcaListener* instance) { NfcaError nfca_listener_start( NfcaListener* instance, - NfcaData* data, + const NfcaData* data, NfcaListenerEventCallback callback, void* context) { furi_assert(instance); @@ -148,8 +148,8 @@ NfcaError nfca_listener_start( instance->callback = callback; instance->context = context; - instance->data = malloc(sizeof(NfcaData)); - *instance->data = *data; + instance->data = nfca_alloc(); + nfca_copy(instance->data, data); nfc_start_listener(instance->nfc, nfca_listener_event_handler, instance); @@ -158,11 +158,9 @@ NfcaError nfca_listener_start( NfcaError nfca_listener_stop(NfcaListener* instance) { furi_assert(instance); - furi_assert(instance->nfc); - furi_assert(instance->data); nfc_listener_abort(instance->nfc); - free(instance->data); + nfca_free(instance->data); instance->callback = NULL; instance->context = NULL; @@ -173,10 +171,8 @@ NfcaError nfca_listener_stop(NfcaListener* instance) { NfcaError nfca_listener_get_data(NfcaListener* instance, NfcaData* data) { furi_assert(instance); - furi_assert(data); - furi_assert(instance->data); - *data = *instance->data; + nfca_copy(data, instance->data); return NfcaErrorNone; } diff --git a/lib/nfc/protocols/nfca/nfca_listener.h b/lib/nfc/protocols/nfca/nfca_listener.h index ddd0dfe63d1f..754be1eccb34 100644 --- a/lib/nfc/protocols/nfca/nfca_listener.h +++ b/lib/nfc/protocols/nfca/nfca_listener.h @@ -43,7 +43,7 @@ void nfca_listener_free(NfcaListener* instance); NfcaError nfca_listener_start( NfcaListener* instance, - NfcaData* data, + const NfcaData* data, NfcaListenerEventCallback callback, void* context); diff --git a/lib/nfc/protocols/nfca/nfca_poller.c b/lib/nfc/protocols/nfca/nfca_poller.c index ed7f9833d5f9..46ce19e3a7a1 100644 --- a/lib/nfc/protocols/nfca/nfca_poller.c +++ b/lib/nfc/protocols/nfca/nfca_poller.c @@ -28,6 +28,12 @@ void nfca_poller_free(NfcaPoller* instance) { free(instance); } +const NfcaData* nfca_poller_get_data(NfcaPoller* instance) { + furi_assert(instance); + + return instance->data; +} + static NfcCommand nfca_poller_process_command(NfcaPollerCommand command) { NfcCommand ret = NfcCommandContinue; @@ -92,13 +98,12 @@ NfcaError nfca_poller_start(NfcaPoller* instance, NfcaPollerEventCallback callback, void* context) { furi_assert(instance); furi_assert(callback); - furi_assert(instance->nfc); furi_assert(instance->session_state == NfcaPollerSessionStateIdle); instance->callback = callback; instance->context = context; - instance->data = malloc(sizeof(NfcaData)); + instance->data = nfca_alloc(); instance->session_state = NfcaPollerSessionStateActive; nfc_start_poller(instance->nfc, nfca_poller_event_callback, instance); @@ -106,16 +111,6 @@ NfcaError return NfcaErrorNone; } -NfcaError nfca_poller_get_data(NfcaPoller* instance, NfcaData* data) { - furi_assert(instance); - furi_assert(instance->data); - furi_assert(data); - - *data = *instance->data; - - return NfcaErrorNone; -} - NfcaError nfca_poller_stop(NfcaPoller* instance) { furi_assert(instance); furi_assert(instance->data); @@ -133,7 +128,7 @@ NfcaError nfca_poller_stop(NfcaPoller* instance) { // Check that data is freed furi_assert(instance->buff == NULL); - free(instance->data); + nfca_free(instance->data); return error; } @@ -156,7 +151,7 @@ NfcaError nfca_poller_read(NfcaPoller* instance, NfcaData* nfca_data) { furi_thread_flags_wait(NFCA_POLLER_FLAG_COMMAND_COMPLETE, FuriFlagWaitAny, FuriWaitForever); furi_thread_flags_clear(NFCA_POLLER_FLAG_COMMAND_COMPLETE); if(context.error == NfcaErrorNone) { - *nfca_data = *instance->data; + nfca_copy(nfca_data, instance->data); } nfc_stop(instance->nfc); diff --git a/lib/nfc/protocols/nfca/nfca_poller.h b/lib/nfc/protocols/nfca/nfca_poller.h index 25931fac9c44..c1ce931f5663 100644 --- a/lib/nfc/protocols/nfca/nfca_poller.h +++ b/lib/nfc/protocols/nfca/nfca_poller.h @@ -35,12 +35,12 @@ NfcaPoller* nfca_poller_alloc(Nfc* nfc); void nfca_poller_free(NfcaPoller* instance); +const NfcaData* nfca_poller_get_data(NfcaPoller* instance); + NfcaError nfca_poller_start(NfcaPoller* instance, NfcaPollerEventCallback callback, void* context); NfcaError nfca_poller_stop(NfcaPoller* instance); -NfcaError nfca_poller_get_data(NfcaPoller* instance, NfcaData* data); - // Sync call NfcaError nfca_poller_read(NfcaPoller* instance, NfcaData* nfca_data); From e40cecdb9b7bcd6a5d542311516adb16b368ad8c Mon Sep 17 00:00:00 2001 From: gornekich Date: Mon, 12 Jun 2023 12:57:49 +0400 Subject: [PATCH 102/149] Gornek/rework with bit buffer (#2763) * nfc: rework with bitbuffer * nfc: rework with bit buffer compiles * nfc: rework with bit buffer complete * nfc: clean up code * bit buffer: reuse BITS_IN_BYTE --- .../main/nfc/scenes/nfc_scene_nfca_emulate.c | 5 +- .../main/nfc_rpc/nfc_rpc_mf_ultralight.c | 6 - firmware/targets/f7/api_symbols.csv | 59 +++- firmware/targets/f7/furi_hal/f_hal_nfc.c | 8 +- firmware/targets/f7/furi_hal/f_hal_nfca.c | 5 +- firmware/targets/furi_hal_include/f_hal_nfc.h | 14 +- lib/drivers/st25r3916.c | 14 +- lib/drivers/st25r3916.h | 6 +- lib/drivers/st25r3916_reg.c | 22 +- lib/drivers/st25r3916_reg.h | 14 +- lib/nfc/helpers/bit_buffer.c | 116 ++++++- lib/nfc/helpers/bit_buffer.h | 75 ++++- lib/nfc/nfc.c | 105 +++--- lib/nfc/nfc.h | 34 +- .../iso14443_4a/iso14443_4a_poller_i.c | 34 +- lib/nfc/protocols/mf_classic/crypto1.c | 109 ++++--- lib/nfc/protocols/mf_classic/crypto1.h | 25 +- .../protocols/mf_classic/mf_classic_poller.c | 21 +- .../mf_classic/mf_classic_poller_i.c | 142 +++------ .../mf_classic/mf_classic_poller_i.h | 7 +- .../mf_ultralight/mf_ultralight_listener.c | 143 ++++----- .../mf_ultralight/mf_ultralight_poller.c | 16 +- .../mf_ultralight/mf_ultralight_poller_i.c | 168 ++++------ .../mf_ultralight/mf_ultralight_poller_i.h | 4 +- lib/nfc/protocols/nfca/nfca.c | 107 ++++--- lib/nfc/protocols/nfca/nfca.h | 12 +- lib/nfc/protocols/nfca/nfca_listener.c | 58 ++-- lib/nfc/protocols/nfca/nfca_listener.h | 8 +- lib/nfc/protocols/nfca/nfca_poller.c | 3 +- lib/nfc/protocols/nfca/nfca_poller_i.c | 299 +++++------------- lib/nfc/protocols/nfca/nfca_poller_i.h | 27 +- lib/nfc/protocols/nfcb/nfcb_poller.c | 6 - 32 files changed, 822 insertions(+), 850 deletions(-) diff --git a/applications/main/nfc/scenes/nfc_scene_nfca_emulate.c b/applications/main/nfc/scenes/nfc_scene_nfca_emulate.c index a8c827aecd31..adaa27857cea 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfca_emulate.c +++ b/applications/main/nfc/scenes/nfc_scene_nfca_emulate.c @@ -14,8 +14,9 @@ NfcaListenerCommand NfcApp* nfc = context; if(event.type == NfcaListenerEventTypeReceivedStandartFrame) { furi_string_cat_printf(nfc->text_box_store, "R:"); - for(size_t i = 0; i < event.data.rx_bits / 8; i++) { - furi_string_cat_printf(nfc->text_box_store, " %02X", event.data.rx_data[i]); + for(size_t i = 0; i < bit_buffer_get_size_bytes(event.data.buffer); i++) { + furi_string_cat_printf( + nfc->text_box_store, " %02X", bit_buffer_get_byte(event.data.buffer, i)); } furi_string_cat_printf(nfc->text_box_store, "\n"); view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerUpdate); diff --git a/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c b/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c index 04de863ed05b..ca753ba405bc 100644 --- a/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c +++ b/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c @@ -72,8 +72,6 @@ static void nfc_rpc_mf_ultralight_write_page(Nfc_Main* cmd, void* context) { cmd->command_status = Nfc_CommandStatus_OK; pb_mf_ul_write_page_resp.error = nfc_rpc_mf_ultralight_process_error(error); cmd->content.mf_ultralight_write_page_resp = pb_mf_ul_write_page_resp; - - mf_ultralight_poller_reset(instance->mf_ul_poller); } static void nfc_rpc_mf_ultralight_read_version(Nfc_Main* cmd, void* context) { @@ -146,8 +144,6 @@ static void nfc_rpc_mf_ultralight_read_counter(Nfc_Main* cmd, void* context) { pb_mf_ul_read_counter_resp.data.size = sizeof(MfUltralightCounter); } cmd->content.mf_ultralight_read_counter_resp = pb_mf_ul_read_counter_resp; - - mf_ultralight_poller_reset(instance->mf_ul_poller); } static void nfc_rpc_mf_ultralight_read_tearing_flag(Nfc_Main* cmd, void* context) { @@ -177,8 +173,6 @@ static void nfc_rpc_mf_ultralight_read_tearing_flag(Nfc_Main* cmd, void* context cmd->content.mf_ultralight_read_tearing_flag_resp = pb_mf_ul_read_tearing_flag_resp; FURI_LOG_D( TAG, "Tearing flag %ld: %02X", pb_mf_ul_read_tearing_flag_resp.flag_num, data.data[0]); - - mf_ultralight_poller_reset(instance->mf_ul_poller); } // TODO DELETE! diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 1d08c6def619..2965d34feea5 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -547,6 +547,31 @@ Function,-,atoll,long long,const char* Function,-,basename,char*,const char* Function,-,bcmp,int,"const void*, const void*, size_t" Function,-,bcopy,void,"const void*, void*, size_t" +Function,-,bit_buffer_alloc,BitBuffer*,size_t +Function,-,bit_buffer_append,void,"BitBuffer*, const BitBuffer*" +Function,-,bit_buffer_append_bytes,void,"BitBuffer*, const uint8_t*, size_t" +Function,-,bit_buffer_append_right,void,"BitBuffer*, const BitBuffer*, size_t" +Function,-,bit_buffer_copy,void,"BitBuffer*, const BitBuffer*" +Function,-,bit_buffer_copy_bits,void,"BitBuffer*, const uint8_t*, size_t" +Function,-,bit_buffer_copy_bytes,void,"BitBuffer*, const uint8_t*, size_t" +Function,-,bit_buffer_copy_bytes_with_parity,void,"BitBuffer*, const uint8_t*, size_t" +Function,-,bit_buffer_copy_left,void,"BitBuffer*, const BitBuffer*, size_t" +Function,-,bit_buffer_copy_right,void,"BitBuffer*, const BitBuffer*, size_t" +Function,-,bit_buffer_free,void,BitBuffer* +Function,-,bit_buffer_get_byte,uint8_t,"const BitBuffer*, size_t" +Function,-,bit_buffer_get_capacity_bytes,size_t,const BitBuffer* +Function,-,bit_buffer_get_data,const uint8_t*,const BitBuffer* +Function,-,bit_buffer_get_size,size_t,const BitBuffer* +Function,-,bit_buffer_get_size_bytes,size_t,const BitBuffer* +Function,-,bit_buffer_has_partial_byte,_Bool,const BitBuffer* +Function,-,bit_buffer_reset,void,BitBuffer* +Function,-,bit_buffer_set_byte,void,"BitBuffer*, size_t, uint8_t" +Function,-,bit_buffer_set_byte_with_parity,void,"BitBuffer*, size_t, uint8_t, _Bool" +Function,-,bit_buffer_set_size,void,"BitBuffer*, size_t" +Function,-,bit_buffer_set_size_bytes,void,"BitBuffer*, size_t" +Function,-,bit_buffer_starts_with_byte,_Bool,"const BitBuffer*, uint8_t" +Function,-,bit_buffer_write_bytes,void,"const BitBuffer*, void*, size_t" +Function,-,bit_buffer_write_bytes_with_parity,void,"const BitBuffer*, void*, size_t, size_t*" Function,+,bit_lib_add_parity,size_t,"const uint8_t*, size_t, uint8_t*, size_t, uint8_t, uint8_t, BitLibParity" Function,+,bit_lib_copy_bits,void,"uint8_t*, size_t, size_t, const uint8_t*, size_t" Function,+,bit_lib_crc16,uint16_t,"const uint8_t*, size_t, uint16_t, uint16_t, _Bool, _Bool, uint16_t" @@ -829,13 +854,13 @@ Function,-,f_hal_nfc_is_hal_ready,FHalNfcError, Function,-,f_hal_nfc_listen_start,FHalNfcError, Function,-,f_hal_nfc_listener_disable_auto_col_res,FHalNfcError, Function,-,f_hal_nfc_listener_sleep,FHalNfcError, -Function,-,f_hal_nfc_listener_tx,FHalNfcError,"uint8_t*, uint16_t" +Function,-,f_hal_nfc_listener_tx,FHalNfcError,"const uint8_t*, size_t" Function,-,f_hal_nfc_low_power_mode_start,FHalNfcError, Function,-,f_hal_nfc_low_power_mode_stop,FHalNfcError, Function,-,f_hal_nfc_poller_field_on,FHalNfcError, -Function,-,f_hal_nfc_poller_rx,FHalNfcError,"uint8_t*, uint16_t, uint16_t*" -Function,-,f_hal_nfc_poller_tx,FHalNfcError,"uint8_t*, uint16_t" -Function,-,f_hal_nfc_poller_tx_custom_parity,FHalNfcError,"uint8_t*, uint16_t" +Function,-,f_hal_nfc_poller_rx,FHalNfcError,"uint8_t*, size_t, size_t*" +Function,-,f_hal_nfc_poller_tx,FHalNfcError,"const uint8_t*, size_t" +Function,-,f_hal_nfc_poller_tx_custom_parity,FHalNfcError,"const uint8_t*, size_t" Function,-,f_hal_nfc_release,FHalNfcError, Function,-,f_hal_nfc_reset_mode,FHalNfcError, Function,-,f_hal_nfc_set_mask_receive_timer,void,uint32_t @@ -848,8 +873,8 @@ Function,-,f_hal_nfc_timer_fwt_start,void,uint32_t Function,-,f_hal_nfc_timer_fwt_stop,void, Function,-,f_hal_nfc_trx_reset,FHalNfcError, Function,-,f_hal_nfc_wait_event,FHalNfcEvent,uint32_t -Function,-,f_hal_nfca_receive_sdd_frame,FHalNfcError,"uint8_t*, uint16_t, uint16_t*" -Function,-,f_hal_nfca_send_sdd_frame,FHalNfcError,"uint8_t*, uint16_t" +Function,-,f_hal_nfca_receive_sdd_frame,FHalNfcError,"uint8_t*, size_t, size_t*" +Function,-,f_hal_nfca_send_sdd_frame,FHalNfcError,"const uint8_t*, size_t" Function,-,f_hal_nfca_send_short_frame,FHalNfcError,FHalNfcaShortFrame Function,-,fabs,double,double Function,-,fabsf,float,float @@ -2012,12 +2037,12 @@ Function,-,nexttowardl,long double,"long double, long double" Function,-,nfc_alloc,Nfc*, Function,-,nfc_config,void,"Nfc*, NfcMode" Function,-,nfc_free,void,Nfc* -Function,-,nfc_iso13444a_sdd_frame,NfcError,"Nfc*, uint8_t*, uint16_t, uint8_t*, uint16_t, uint16_t*, uint32_t" -Function,-,nfc_iso13444a_short_frame,NfcError,"Nfc*, NfcIso14443aShortFrame, uint8_t*, uint16_t, uint16_t*, uint32_t" +Function,-,nfc_iso13444a_sdd_frame,NfcError,"Nfc*, const BitBuffer*, BitBuffer*, uint32_t" +Function,-,nfc_iso13444a_short_frame,NfcError,"Nfc*, NfcIso14443aShortFrame, BitBuffer*, uint32_t" Function,-,nfc_listener_abort,void,Nfc* Function,-,nfc_listener_set_col_res_data,NfcError,"Nfc*, uint8_t*, uint8_t, uint8_t*, uint8_t" Function,-,nfc_listener_sleep,NfcError,Nfc* -Function,-,nfc_listener_tx,NfcError,"Nfc*, uint8_t*, uint16_t" +Function,-,nfc_listener_tx,NfcError,"Nfc*, const BitBuffer*" Function,-,nfc_set_fdt_listen_fc,void,"Nfc*, uint32_t" Function,-,nfc_set_fdt_poll_fc,void,"Nfc*, uint32_t" Function,-,nfc_set_fdt_poll_poll_us,void,"Nfc*, uint32_t" @@ -2026,17 +2051,18 @@ Function,-,nfc_set_mask_receive_time_fc,void,"Nfc*, uint32_t" Function,-,nfc_start_listener,void,"Nfc*, NfcEventCallback, void*" Function,-,nfc_start_poller,void,"Nfc*, NfcEventCallback, void*" Function,-,nfc_stop,void,Nfc* -Function,-,nfc_trx,NfcError,"Nfc*, uint8_t*, uint16_t, uint8_t*, uint16_t, uint16_t*, uint32_t" -Function,-,nfc_trx_custom_parity,NfcError,"Nfc*, uint8_t*, uint16_t, uint8_t*, uint16_t, uint16_t*, uint32_t" -Function,+,nfca_alloc,NfcaData*, -Function,-,nfca_append_crc,void,"uint8_t*, uint16_t" +Function,-,nfc_trx,NfcError,"Nfc*, const BitBuffer*, BitBuffer*, uint32_t" +Function,-,nfc_trx_custom_parity,NfcError,"Nfc*, const BitBuffer*, BitBuffer*, uint32_t" +Function,-,nfca_append_crc,void,BitBuffer* Function,-,nfca_append_crc16,void,"uint8_t*, uint16_t" -Function,-,nfca_check_crc,_Bool,"uint8_t*, uint16_t" -Function,+,nfca_copy,void,"NfcaData*, const NfcaData*" +Function,-,nfca_check_crc,_Bool,const BitBuffer* Function,-,nfca_emulation_handler,_Bool,"uint8_t*, uint16_t, uint8_t*, uint16_t*" +Function,-,nfca_get_crc16,uint16_t,"uint8_t*, uint16_t" +Function,-,nfca_get_cuid,uint32_t,NfcaData* +Function,+,nfca_alloc,NfcaData*, +Function,+,nfca_copy,void,"NfcaData*, const NfcaData*" Function,+,nfca_free,void,NfcaData* Function,-,nfca_get_crc,uint16_t,"uint8_t*, uint16_t" -Function,-,nfca_get_crc16,uint16_t,"uint8_t*, uint16_t" Function,+,nfca_get_name,const char*,"const NfcaData*, NfcProtocolNameType" Function,+,nfca_get_uid,const uint8_t*,"const NfcaData*, size_t*" Function,+,nfca_is_equal,_Bool,"const NfcaData*, const NfcaData*" @@ -2054,6 +2080,7 @@ Function,+,nfca_save_data,_Bool,"const NfcaData*, FlipperFormat*, uint32_t" Function,-,nfca_signal_alloc,NfcaSignal*, Function,-,nfca_signal_encode,void,"NfcaSignal*, uint8_t*, uint16_t, uint8_t*" Function,-,nfca_signal_free,void,NfcaSignal* +Function,-,nfca_trim_crc,void,BitBuffer* Function,+,nfca_verify,_Bool,"NfcaData*, const FuriString*" Function,+,notification_internal_message,void,"NotificationApp*, const NotificationSequence*" Function,+,notification_internal_message_block,void,"NotificationApp*, const NotificationSequence*" diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc.c b/firmware/targets/f7/furi_hal/f_hal_nfc.c index e2a79e92f3c1..c74ab4474b75 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfc.c +++ b/firmware/targets/f7/furi_hal/f_hal_nfc.c @@ -404,7 +404,7 @@ FHalNfcError f_hal_nfc_poller_field_on() { return error; } -FHalNfcError f_hal_nfc_poller_tx_custom_parity(uint8_t* tx_data, uint16_t tx_bits) { +FHalNfcError f_hal_nfc_poller_tx_custom_parity(const uint8_t* tx_data, size_t tx_bits) { furi_assert(tx_data); // TODO common code for f_hal_nfc_poller_tx @@ -437,7 +437,7 @@ FHalNfcError f_hal_nfc_poller_tx_custom_parity(uint8_t* tx_data, uint16_t tx_bit return err; } -FHalNfcError f_hal_nfc_poller_tx(uint8_t* tx_data, uint16_t tx_bits) { +FHalNfcError f_hal_nfc_poller_tx(const uint8_t* tx_data, size_t tx_bits) { furi_assert(tx_data); FHalNfcError err = FHalNfcErrorNone; @@ -468,7 +468,7 @@ FHalNfcError f_hal_nfc_poller_tx(uint8_t* tx_data, uint16_t tx_bits) { return err; } -FHalNfcError f_hal_nfc_listener_tx(uint8_t* tx_data, uint16_t tx_bits) { +FHalNfcError f_hal_nfc_listener_tx(const uint8_t* tx_data, size_t tx_bits) { furi_assert(tx_data); FHalNfcError err = FHalNfcErrorNone; @@ -483,7 +483,7 @@ FHalNfcError f_hal_nfc_listener_tx(uint8_t* tx_data, uint16_t tx_bits) { return err; } -FHalNfcError f_hal_nfc_poller_rx(uint8_t* rx_data, uint16_t rx_data_size, uint16_t* rx_bits) { +FHalNfcError f_hal_nfc_poller_rx(uint8_t* rx_data, size_t rx_data_size, size_t* rx_bits) { furi_assert(rx_data); furi_assert(rx_bits); diff --git a/firmware/targets/f7/furi_hal/f_hal_nfca.c b/firmware/targets/f7/furi_hal/f_hal_nfca.c index fcd514ef0540..d39fd246400c 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfca.c +++ b/firmware/targets/f7/furi_hal/f_hal_nfca.c @@ -40,7 +40,7 @@ FHalNfcError f_hal_nfca_send_short_frame(FHalNfcaShortFrame frame) { return error; } -FHalNfcError f_hal_nfca_send_sdd_frame(uint8_t* tx_data, uint16_t tx_bits) { +FHalNfcError f_hal_nfca_send_sdd_frame(const uint8_t* tx_data, size_t tx_bits) { FHalNfcError error = FHalNfcErrorNone; // TODO Set anticollision parameters error = f_hal_nfc_poller_tx(tx_data, tx_bits); @@ -48,8 +48,7 @@ FHalNfcError f_hal_nfca_send_sdd_frame(uint8_t* tx_data, uint16_t tx_bits) { return error; } -FHalNfcError - f_hal_nfca_receive_sdd_frame(uint8_t* rx_data, uint16_t rx_data_size, uint16_t* rx_bits) { +FHalNfcError f_hal_nfca_receive_sdd_frame(uint8_t* rx_data, size_t rx_data_size, size_t* rx_bits) { FHalNfcError error = FHalNfcErrorNone; UNUSED(rx_data); UNUSED(rx_bits); diff --git a/firmware/targets/furi_hal_include/f_hal_nfc.h b/firmware/targets/furi_hal_include/f_hal_nfc.h index 4fa83dcfe52a..e4c2b5a7500c 100644 --- a/firmware/targets/furi_hal_include/f_hal_nfc.h +++ b/firmware/targets/furi_hal_include/f_hal_nfc.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #ifdef __cplusplus @@ -110,13 +111,13 @@ FHalNfcError f_hal_nfc_release(); FHalNfcError f_hal_nfc_event_start(); -FHalNfcError f_hal_nfc_poller_tx(uint8_t* tx_data, uint16_t tx_bits); +FHalNfcError f_hal_nfc_poller_tx(const uint8_t* tx_data, size_t tx_bits); -FHalNfcError f_hal_nfc_poller_tx_custom_parity(uint8_t* tx_data, uint16_t tx_bits); +FHalNfcError f_hal_nfc_poller_tx_custom_parity(const uint8_t* tx_data, size_t tx_bits); -FHalNfcError f_hal_nfc_poller_rx(uint8_t* rx_data, uint16_t rx_data_size, uint16_t* rx_bits); +FHalNfcError f_hal_nfc_poller_rx(uint8_t* rx_data, size_t rx_data_size, size_t* rx_bits); -FHalNfcError f_hal_nfc_listener_tx(uint8_t* tx_data, uint16_t tx_bits); +FHalNfcError f_hal_nfc_listener_tx(const uint8_t* tx_data, size_t tx_bits); FHalNfcError f_hal_nfc_trx_reset(); @@ -148,10 +149,9 @@ void f_hal_nfc_set_mask_receive_timer(uint32_t time_fc); FHalNfcError f_hal_nfca_send_short_frame(FHalNfcaShortFrame frame); -FHalNfcError f_hal_nfca_send_sdd_frame(uint8_t* tx_data, uint16_t tx_bits); +FHalNfcError f_hal_nfca_send_sdd_frame(const uint8_t* tx_data, size_t tx_bits); -FHalNfcError - f_hal_nfca_receive_sdd_frame(uint8_t* rx_data, uint16_t rx_data_size, uint16_t* rx_bits); +FHalNfcError f_hal_nfca_receive_sdd_frame(uint8_t* rx_data, size_t rx_data_size, size_t* rx_bits); FHalNfcError furi_hal_nfca_set_col_res_data(uint8_t* uid, uint8_t uid_len, uint8_t* atqa, uint8_t sak); diff --git a/lib/drivers/st25r3916.c b/lib/drivers/st25r3916.c index 4d3e39f4e060..de27204ec44f 100644 --- a/lib/drivers/st25r3916.c +++ b/lib/drivers/st25r3916.c @@ -36,11 +36,11 @@ uint32_t st25r3916_get_irq(FuriHalSpiBusHandle* handle) { return irq; } -void st25r3916_write_fifo(FuriHalSpiBusHandle* handle, uint8_t* buff, uint16_t bits) { +void st25r3916_write_fifo(FuriHalSpiBusHandle* handle, const uint8_t* buff, size_t bits) { furi_assert(handle); furi_assert(buff); - uint16_t bytes = (bits + 7) / 8; + size_t bytes = (bits + 7) / 8; st25r3916_write_reg(handle, ST25R3916_REG_NUM_TX_BYTES2, (uint8_t)(bits & 0xFFU)); st25r3916_write_reg(handle, ST25R3916_REG_NUM_TX_BYTES1, (uint8_t)((bits >> 8) & 0xFFU)); @@ -51,8 +51,8 @@ void st25r3916_write_fifo(FuriHalSpiBusHandle* handle, uint8_t* buff, uint16_t b bool st25r3916_read_fifo( FuriHalSpiBusHandle* handle, uint8_t* buff, - uint16_t buff_size, - uint16_t* buff_bits) { + size_t buff_size, + size_t* buff_bits) { furi_assert(handle); furi_assert(buff); @@ -60,9 +60,9 @@ bool st25r3916_read_fifo( uint8_t fifo_status[2] = {}; st25r3916_read_burst_regs(handle, ST25R3916_REG_FIFO_STATUS1, fifo_status, 2); - uint16_t bytes = ((fifo_status[1] & ST25R3916_REG_FIFO_STATUS2_fifo_b_mask) >> - ST25R3916_REG_FIFO_STATUS2_fifo_b_shift) | - fifo_status[0]; + size_t bytes = ((fifo_status[1] & ST25R3916_REG_FIFO_STATUS2_fifo_b_mask) >> + ST25R3916_REG_FIFO_STATUS2_fifo_b_shift) | + fifo_status[0]; uint8_t bits = ((fifo_status[1] & ST25R3916_REG_FIFO_STATUS2_fifo_lb_mask) >> ST25R3916_REG_FIFO_STATUS2_fifo_lb_shift); diff --git a/lib/drivers/st25r3916.h b/lib/drivers/st25r3916.h index cbb964b73eab..213e52813f45 100644 --- a/lib/drivers/st25r3916.h +++ b/lib/drivers/st25r3916.h @@ -89,13 +89,13 @@ void st25r3916_mask_irq(FuriHalSpiBusHandle* handle, uint32_t mask); uint32_t st25r3916_get_irq(FuriHalSpiBusHandle* handle); -void st25r3916_write_fifo(FuriHalSpiBusHandle* handle, uint8_t* buff, uint16_t bits); +void st25r3916_write_fifo(FuriHalSpiBusHandle* handle, const uint8_t* buff, size_t bits); bool st25r3916_read_fifo( FuriHalSpiBusHandle* handle, uint8_t* buff, - uint16_t buff_size, - uint16_t* buff_bits); + size_t buff_size, + size_t* buff_bits); #ifdef __cplusplus } diff --git a/lib/drivers/st25r3916_reg.c b/lib/drivers/st25r3916_reg.c index b3ddee849b09..c03937176994 100644 --- a/lib/drivers/st25r3916_reg.c +++ b/lib/drivers/st25r3916_reg.c @@ -68,7 +68,7 @@ void st25r3916_write_reg(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t val) void st25r3916_write_burst_regs( FuriHalSpiBusHandle* handle, uint8_t reg_start, - uint8_t* values, + const uint8_t* values, uint8_t length) { furi_assert(handle); furi_assert(values); @@ -86,7 +86,7 @@ void st25r3916_write_burst_regs( furi_hal_gpio_write(handle->cs, true); } -void st25r3916_reg_write_fifo(FuriHalSpiBusHandle* handle, uint8_t* buff, uint16_t length) { +void st25r3916_reg_write_fifo(FuriHalSpiBusHandle* handle, const uint8_t* buff, size_t length) { furi_assert(handle); furi_assert(buff); furi_assert(length); @@ -98,7 +98,7 @@ void st25r3916_reg_write_fifo(FuriHalSpiBusHandle* handle, uint8_t* buff, uint16 furi_hal_gpio_write(handle->cs, true); } -void st25r3916_reg_read_fifo(FuriHalSpiBusHandle* handle, uint8_t* buff, uint16_t length) { +void st25r3916_reg_read_fifo(FuriHalSpiBusHandle* handle, uint8_t* buff, size_t length) { furi_assert(handle); furi_assert(buff); furi_assert(length); @@ -110,19 +110,19 @@ void st25r3916_reg_read_fifo(FuriHalSpiBusHandle* handle, uint8_t* buff, uint16_ furi_hal_gpio_write(handle->cs, true); } -void st25r3916_write_pta_mem(FuriHalSpiBusHandle* handle, uint8_t* buff, uint16_t length) { +void st25r3916_write_pta_mem(FuriHalSpiBusHandle* handle, const uint8_t* values, size_t length) { furi_assert(handle); - furi_assert(buff); + furi_assert(values); furi_assert(length); furi_assert(length <= ST25R3916_PTM_LEN); furi_hal_gpio_write(handle->cs, false); st25r3916_reg_tx_byte(handle, ST25R3916_PT_A_CONFIG_LOAD); - furi_hal_spi_bus_tx(handle, buff, length, 200); + furi_hal_spi_bus_tx(handle, values, length, 200); furi_hal_gpio_write(handle->cs, true); } -void st25r3916_read_pta_mem(FuriHalSpiBusHandle* handle, uint8_t* buff, uint16_t length) { +void st25r3916_read_pta_mem(FuriHalSpiBusHandle* handle, uint8_t* buff, size_t length) { furi_assert(handle); furi_assert(buff); furi_assert(length); @@ -137,17 +137,17 @@ void st25r3916_read_pta_mem(FuriHalSpiBusHandle* handle, uint8_t* buff, uint16_t memcpy(buff, tmp_buff + 1, length); } -void st25r3916_write_ptf_mem(FuriHalSpiBusHandle* handle, uint8_t* buff, uint16_t length) { +void st25r3916_write_ptf_mem(FuriHalSpiBusHandle* handle, const uint8_t* values, size_t length) { furi_assert(handle); - furi_assert(buff); + furi_assert(values); furi_hal_gpio_write(handle->cs, false); st25r3916_reg_tx_byte(handle, ST25R3916_PT_F_CONFIG_LOAD); - furi_hal_spi_bus_tx(handle, buff, length, 200); + furi_hal_spi_bus_tx(handle, values, length, 200); furi_hal_gpio_write(handle->cs, true); } -void st25r3916_write_pttsn_mem(FuriHalSpiBusHandle* handle, uint8_t* buff, uint16_t length) { +void st25r3916_write_pttsn_mem(FuriHalSpiBusHandle* handle, uint8_t* buff, size_t length) { furi_assert(handle); furi_assert(buff); diff --git a/lib/drivers/st25r3916_reg.h b/lib/drivers/st25r3916_reg.h index a9b2a532838f..29397ebdd924 100644 --- a/lib/drivers/st25r3916_reg.h +++ b/lib/drivers/st25r3916_reg.h @@ -1037,20 +1037,20 @@ void st25r3916_write_reg(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t val); void st25r3916_write_burst_regs( FuriHalSpiBusHandle* handle, uint8_t reg_start, - uint8_t* values, + const uint8_t* values, uint8_t length); -void st25r3916_reg_write_fifo(FuriHalSpiBusHandle* handle, uint8_t* buff, uint16_t length); +void st25r3916_reg_write_fifo(FuriHalSpiBusHandle* handle, const uint8_t* buff, size_t length); -void st25r3916_reg_read_fifo(FuriHalSpiBusHandle* handle, uint8_t* buff, uint16_t length); +void st25r3916_reg_read_fifo(FuriHalSpiBusHandle* handle, uint8_t* buff, size_t length); -void st25r3916_write_pta_mem(FuriHalSpiBusHandle* handle, uint8_t* values, uint16_t length); +void st25r3916_write_pta_mem(FuriHalSpiBusHandle* handle, const uint8_t* values, size_t length); -void st25r3916_read_pta_mem(FuriHalSpiBusHandle* handle, uint8_t* values, uint16_t length); +void st25r3916_read_pta_mem(FuriHalSpiBusHandle* handle, uint8_t* values, size_t length); -void st25r3916_write_ptf_mem(FuriHalSpiBusHandle* handle, uint8_t* values, uint16_t length); +void st25r3916_write_ptf_mem(FuriHalSpiBusHandle* handle, const uint8_t* values, size_t length); -void st25r3916_write_pttsn_mem(FuriHalSpiBusHandle* handle, uint8_t* values, uint16_t length); +void st25r3916_write_pttsn_mem(FuriHalSpiBusHandle* handle, uint8_t* values, size_t length); void st25r3916_direct_cmd(FuriHalSpiBusHandle* handle, uint8_t cmd); diff --git a/lib/nfc/helpers/bit_buffer.c b/lib/nfc/helpers/bit_buffer.c index 86b8ffb9164b..9f7974d8642f 100644 --- a/lib/nfc/helpers/bit_buffer.c +++ b/lib/nfc/helpers/bit_buffer.c @@ -6,7 +6,7 @@ struct BitBuffer { uint8_t* data; - uint8_t* parity; + bool* parity; size_t capacity_bytes; size_t size_bits; }; @@ -23,7 +23,7 @@ BitBuffer* bit_buffer_alloc(size_t capacity_bytes) { BitBuffer* buf = malloc(sizeof(BitBuffer)); buf->data = malloc(capacity_bytes); - buf->parity = malloc((capacity_bytes + BITS_IN_BYTE - 1) / BITS_IN_BYTE); + buf->parity = malloc(capacity_bytes); buf->capacity_bytes = capacity_bytes; buf->size_bits = 0; @@ -63,20 +63,118 @@ void bit_buffer_copy_right(BitBuffer* buf, const BitBuffer* other, size_t start_ buf->size_bits = other->size_bits - start_index * BITS_IN_BYTE; } +void bit_buffer_copy_left(BitBuffer* buf, const BitBuffer* other, size_t end_index) { + furi_assert(buf); + furi_assert(other); + furi_assert(bit_buffer_get_capacity_bytes(buf) >= end_index); + furi_assert(bit_buffer_get_size_bytes(other) >= end_index); + + memcpy(buf->data, other->data, end_index); + buf->size_bits = end_index * BITS_IN_BYTE; +} + void bit_buffer_copy_bytes(BitBuffer* buf, const uint8_t* data, size_t size_bytes) { furi_assert(buf); + furi_assert(data); furi_assert(buf->capacity_bytes >= size_bytes); memcpy(buf->data, data, size_bytes); buf->size_bits = size_bytes * BITS_IN_BYTE; } +void bit_buffer_copy_bits(BitBuffer* buf, const uint8_t* data, size_t size_bits) { + furi_assert(buf); + furi_assert(data); + furi_assert(buf->capacity_bytes * BITS_IN_BYTE >= size_bits); + + size_t size_bytes = (size_bits + BITS_IN_BYTE - 1) / BITS_IN_BYTE; + memcpy(buf->data, data, size_bytes); + buf->size_bits = size_bits; +} + +void bit_buffer_copy_bytes_with_parity(BitBuffer* buf, const uint8_t* data, size_t size_bits) { + furi_assert(buf); + furi_assert(data); + + size_t bit_processed = 0; + size_t curr_byte = 0; + + if(size_bits < BITS_IN_BYTE + 1) { + buf->size_bits = size_bits; + buf->data[0] = data[0]; + } else { + furi_assert(size_bits % (BITS_IN_BYTE + 1) == 0); + buf->size_bits = size_bits / (BITS_IN_BYTE + 1) * BITS_IN_BYTE; + while(bit_processed < size_bits) { + buf->data[curr_byte] = data[bit_processed / BITS_IN_BYTE] >> + (bit_processed % BITS_IN_BYTE); + buf->data[curr_byte] |= data[bit_processed / BITS_IN_BYTE + 1] + << (BITS_IN_BYTE - bit_processed % BITS_IN_BYTE); + buf->parity[curr_byte] = + FURI_BIT(data[bit_processed / BITS_IN_BYTE + 1], bit_processed % BITS_IN_BYTE); + bit_processed += BITS_IN_BYTE + 1; + curr_byte++; + } + buf->size_bits = curr_byte * BITS_IN_BYTE; + } +} + +void bit_buffer_append_bytes(BitBuffer* buf, const uint8_t* data, size_t size_bytes) { + furi_assert(buf); + furi_assert(data); + + size_t buf_size_bytes = bit_buffer_get_size_bytes(buf); + furi_assert(buf->capacity_bytes >= buf_size_bytes + size_bytes); + + memcpy(&buf->data[buf_size_bytes], data, size_bytes); + buf->size_bits += size_bytes * BITS_IN_BYTE; +} + void bit_buffer_write_bytes(const BitBuffer* buf, void* dest, size_t size_bytes) { furi_assert(buf); furi_assert(dest); - furi_assert(bit_buffer_get_size_bytes(buf) >= size_bytes); + furi_assert(bit_buffer_get_size_bytes(buf) <= size_bytes); + + memcpy(dest, buf->data, bit_buffer_get_size_bytes(buf)); +} - memcpy(dest, buf->data, size_bytes); +void bit_buffer_write_bytes_with_parity( + const BitBuffer* buf, + void* dest, + size_t size_bytes, + size_t* bits_written) { + furi_assert(buf); + furi_assert(dest); + furi_assert(bits_written); + + size_t buf_size_bytes = bit_buffer_get_size_bytes(buf); + size_t buf_size_with_parity_bytes = + (buf_size_bytes * (BITS_IN_BYTE + 1) + BITS_IN_BYTE) / BITS_IN_BYTE; + furi_assert(buf_size_with_parity_bytes <= size_bytes); + + uint8_t next_par_bit = 0; + uint16_t curr_bit_pos = 0; + uint8_t* bitstream = dest; + + for(size_t i = 0; i < buf_size_bytes; i++) { + next_par_bit = buf->parity[i]; + if(curr_bit_pos % BITS_IN_BYTE == 0) { + bitstream[curr_bit_pos / BITS_IN_BYTE] = buf->data[i]; + curr_bit_pos += BITS_IN_BYTE; + bitstream[curr_bit_pos / BITS_IN_BYTE] = next_par_bit; + curr_bit_pos++; + } else { + bitstream[curr_bit_pos / BITS_IN_BYTE] |= buf->data[i] + << (curr_bit_pos % BITS_IN_BYTE); + bitstream[curr_bit_pos / BITS_IN_BYTE + 1] = + buf->data[i] >> (BITS_IN_BYTE - curr_bit_pos % BITS_IN_BYTE); + bitstream[curr_bit_pos / BITS_IN_BYTE + 1] |= next_par_bit + << (curr_bit_pos % BITS_IN_BYTE); + curr_bit_pos += BITS_IN_BYTE + 1; + } + } + + *bits_written = curr_bit_pos; } bool bit_buffer_has_partial_byte(const BitBuffer* buf) { @@ -116,7 +214,7 @@ uint8_t bit_buffer_get_byte(const BitBuffer* buf, size_t index) { return buf->data[index]; } -uint8_t* bit_buffer_get_data(const BitBuffer* buf) { +const uint8_t* bit_buffer_get_data(const BitBuffer* buf) { furi_assert(buf); return buf->data; @@ -129,6 +227,14 @@ void bit_buffer_set_byte(BitBuffer* buf, size_t index, uint8_t byte) { buf->data[index] = byte; } +void bit_buffer_set_byte_with_parity(BitBuffer* buff, size_t index, uint8_t byte, bool parity) { + furi_assert(buff); + furi_assert(buff->size_bits / BITS_IN_BYTE > index); + + buff->data[index] = byte; + buff->parity[index] = parity; +} + void bit_buffer_append(BitBuffer* buf, const BitBuffer* other) { bit_buffer_append_right(buf, other, 0); } diff --git a/lib/nfc/helpers/bit_buffer.h b/lib/nfc/helpers/bit_buffer.h index 086df727ecc7..6bd1bd1fe290 100644 --- a/lib/nfc/helpers/bit_buffer.h +++ b/lib/nfc/helpers/bit_buffer.h @@ -59,6 +59,18 @@ void bit_buffer_copy(BitBuffer* buf, const BitBuffer* other); */ void bit_buffer_copy_right(BitBuffer* buf, const BitBuffer* other, size_t start_index); +/** + * Copy all BitBuffer instance's contents to this one, ending with end_index, + * replacing all of the original data. + * The destination capacity must be no less than the source data size + * counting to end_index. + * + * @param [in,out] buf pointer to a BitBuffer instance to copy into + * @param [in] other pointer to a BitBuffer instance to copy from + * @param [in] start_index index to begin copying source data from + */ +void bit_buffer_copy_left(BitBuffer* buf, const BitBuffer* other, size_t end_index); + /** * Copy a byte array to a BitBuffer instance, replacing all of the original data. * The destination capacity must be no less than the source data size. @@ -69,6 +81,36 @@ void bit_buffer_copy_right(BitBuffer* buf, const BitBuffer* other, size_t start_ */ void bit_buffer_copy_bytes(BitBuffer* buf, const uint8_t* data, size_t size_bytes); +/** + * Copy a byte array to a BitBuffer instance, replacing all of the original data. + * The destination capacity must be no less than the source data size. + * + * @param [in,out] buf pointer to a BitBuffer instance to copy into + * @param [in] data pointer to the byte array to be copied + * @param [in] size_bits size of the data to be copied, in bits + */ +void bit_buffer_copy_bits(BitBuffer* buf, const uint8_t* data, size_t size_bits); + +/** + * Copy a byte with parity array to a BitBuffer instance, replacing all of the original data. + * The destination capacity must be no less than the source data size. + * + * @param [in,out] buf pointer to a BitBuffer instance to copy into + * @param [in] data pointer to the byte array to be copied + * @param [in] size_bitss size of the data to be copied, in bits + */ +void bit_buffer_copy_bytes_with_parity(BitBuffer* buf, const uint8_t* data, size_t size_bits); + +/** + * Append a byte array to a BitBuffer instance, replacing all of the original data. + * The destination capacity must be no less its original data size plus source data size. + * + * @param [in,out] buf pointer to a BitBuffer instance to copy into + * @param [in] data pointer to the byte array to be copied + * @param [in] size_bytes size of the data to be copied, in bytes + */ +void bit_buffer_append_bytes(BitBuffer* buf, const uint8_t* data, size_t size_bytes); + /** * Write a BitBuffer instance's contents to an arbitrary memory location. * The destination memory must be allocated. Additionally, the instance @@ -76,10 +118,26 @@ void bit_buffer_copy_bytes(BitBuffer* buf, const uint8_t* data, size_t size_byte * * @param [in] buf pointer to a BitBuffer instance to write from * @param [out] dest pointer to the destination memory location - * @param [in] size_bytes size of the data to be written, in bytes + * @param [in] size_bytes maximum destination data size, in bytes */ void bit_buffer_write_bytes(const BitBuffer* buf, void* dest, size_t size_bytes); +/** + * Write a BitBuffer instance's contents to an arbitrary memory location. + * The destination memory must be allocated. Additionally, the instance + * must contain at least the requested amount of data (for easier underflow detection). + * + * @param [in] buf pointer to a BitBuffer instance to write from + * @param [out] dest pointer to the destination memory location + * @param [in] size_bytes maximum destination data size, in bytes + * @param [out] bits_written actual number of bits writen, in bits + */ +void bit_buffer_write_bytes_with_parity( + const BitBuffer* buf, + void* dest, + size_t size_bytes, + size_t* bits_written); + // Checks /** @@ -139,13 +197,11 @@ uint8_t bit_buffer_get_byte(const BitBuffer* buf, size_t index); /** * Get the pointer to a BitBuffer instance's underlying data. - * TODO: Make it return const uint8_t* after all compatibility problems - * will have been resolved. * * @param [in] buf pointer to a BitBuffer instance to be queried * @return pointer to the underlying data */ -uint8_t* bit_buffer_get_data(const BitBuffer* buf); +const uint8_t* bit_buffer_get_data(const BitBuffer* buf); // Setters @@ -159,6 +215,17 @@ uint8_t* bit_buffer_get_data(const BitBuffer* buf); */ void bit_buffer_set_byte(BitBuffer* buf, size_t index, uint8_t byte); +/** + * Set byte and parity bit value at a specified index in a BitBuffer instance. + * The index must be valid (i.e. less than the instance's data size in bytes). + * + * @param [in,out] buf pointer to a BitBuffer instance to be modified + * @param [in] index index of the byte in question + * @param [in] byte byte value to be set at index + * @param [in] parity parity bit value to be set at index + */ +void bit_buffer_set_byte_with_parity(BitBuffer* buff, size_t index, uint8_t byte, bool parity); + /** * Resize a BitBuffer instance to a new size, in bits. * @warning May cause bugs. Use only if absolutely necessary. diff --git a/lib/nfc/nfc.c b/lib/nfc/nfc.c index 65e0b5f8ac48..bac2dd50eb47 100644 --- a/lib/nfc/nfc.c +++ b/lib/nfc/nfc.c @@ -42,6 +42,11 @@ struct Nfc { NfcEventCallback callback; void* context; + uint8_t tx_buffer[NFC_MAX_BUFFER_SIZE]; + size_t tx_bits; + uint8_t rx_buffer[NFC_MAX_BUFFER_SIZE]; + size_t rx_bits; + FuriThread* worker_thread; }; @@ -63,9 +68,6 @@ static int32_t nfc_worker_listener(void* context) { Nfc* instance = context; furi_assert(instance->callback); - uint8_t* rx_data = malloc(NFC_MAX_BUFFER_SIZE); - uint16_t rx_bits = 0; - f_hal_nfc_low_power_mode_stop(); NfcEvent nfc_event = {.type = NfcEventTypeConfigureRequest}; @@ -76,6 +78,9 @@ static int32_t nfc_worker_listener(void* context) { f_hal_nfc_event_start(); + NfcEventData event_data = {}; + event_data.buffer = bit_buffer_alloc(NFC_MAX_BUFFER_SIZE); + while(true) { FHalNfcEvent event = f_hal_nfc_wait_event(F_HAL_NFC_EVENT_WAIT_FOREVER); if(event & FHalNfcEventAbortRequest) { @@ -101,10 +106,9 @@ static int32_t nfc_worker_listener(void* context) { } if(event & FHalNfcEventRxEnd) { nfc_event.type = NfcEventTypeRxEnd; - f_hal_nfc_poller_rx(rx_data, sizeof(rx_data), &rx_bits); - nfc_event.data.rx_data = rx_data; - nfc_event.data.rx_bits = rx_bits; - // TODO start block TX timer + f_hal_nfc_poller_rx( + instance->rx_buffer, sizeof(instance->rx_buffer), &instance->rx_bits); + bit_buffer_copy_bits(event_data.buffer, instance->rx_buffer, instance->rx_bits); instance->callback(nfc_event, instance->context); } } @@ -112,8 +116,8 @@ static int32_t nfc_worker_listener(void* context) { nfc_event.type = NfcEventTypeReset; instance->callback(nfc_event, instance->context); nfc_config(instance, NfcModeIdle); + bit_buffer_free(event_data.buffer); f_hal_nfc_low_power_mode_start(); - free(rx_data); return 0; } @@ -312,12 +316,13 @@ NfcError nfc_listener_sleep(Nfc* instance) { return NfcErrorNone; } -NfcError nfc_listener_tx(Nfc* instance, uint8_t* tx_data, uint16_t tx_bits) { +NfcError nfc_listener_tx(Nfc* instance, const BitBuffer* tx_buffer) { furi_assert(instance); - furi_assert(tx_data); + furi_assert(tx_buffer); NfcError ret = NfcErrorNone; - FHalNfcError error = f_hal_nfc_listener_tx(tx_data, tx_bits); + FHalNfcError error = + f_hal_nfc_listener_tx(bit_buffer_get_data(tx_buffer), bit_buffer_get_size(tx_buffer)); if(error != FHalNfcErrorNone) { FURI_LOG_E(TAG, "Failed in listener TX"); ret = nfc_process_hal_error(error); @@ -414,16 +419,12 @@ static NfcError nfc_poller_prepare_trx(Nfc* instance) { NfcError nfc_trx_custom_parity( Nfc* instance, - uint8_t* tx_data, - uint16_t tx_bits, - uint8_t* rx_data, - uint16_t rx_data_size, - uint16_t* rx_bits, + const BitBuffer* tx_buffer, + BitBuffer* rx_buffer, uint32_t fwt) { furi_assert(instance); - furi_assert(tx_data); - furi_assert(rx_data); - furi_assert(rx_bits); + furi_assert(tx_buffer); + furi_assert(rx_buffer); furi_assert(instance->state == NfcStatePollerReady); @@ -435,7 +436,10 @@ NfcError nfc_trx_custom_parity( FURI_LOG_E(TAG, "Failed in prepare tx rx"); break; } - error = f_hal_nfc_poller_tx_custom_parity(tx_data, tx_bits); + + bit_buffer_write_bytes_with_parity( + tx_buffer, instance->tx_buffer, sizeof(instance->tx_buffer), &instance->tx_bits); + error = f_hal_nfc_poller_tx_custom_parity(instance->tx_buffer, instance->tx_bits); if(error != FHalNfcErrorNone) { FURI_LOG_E(TAG, "Failed in poller TX"); ret = nfc_process_hal_error(error); @@ -447,29 +451,25 @@ NfcError nfc_trx_custom_parity( FURI_LOG_E(TAG, "Failed TRX state machine"); break; } - error = f_hal_nfc_poller_rx(rx_data, rx_data_size, rx_bits); + + error = f_hal_nfc_poller_rx( + instance->rx_buffer, sizeof(instance->rx_buffer), &instance->rx_bits); if(error != FHalNfcErrorNone) { FURI_LOG_E(TAG, "Failed in poller RX"); ret = nfc_process_hal_error(error); break; } + + bit_buffer_copy_bytes_with_parity(rx_buffer, instance->rx_buffer, instance->rx_bits); } while(false); return ret; } -NfcError nfc_trx( - Nfc* instance, - uint8_t* tx_data, - uint16_t tx_bits, - uint8_t* rx_data, - uint16_t rx_data_size, - uint16_t* rx_bits, - uint32_t fwt) { +NfcError nfc_trx(Nfc* instance, const BitBuffer* tx_buffer, BitBuffer* rx_buffer, uint32_t fwt) { furi_assert(instance); - furi_assert(tx_data); - furi_assert(rx_data); - furi_assert(rx_bits); + furi_assert(tx_buffer); + furi_assert(rx_buffer); furi_assert(instance->state == NfcStatePollerReady); @@ -481,7 +481,8 @@ NfcError nfc_trx( FURI_LOG_E(TAG, "Failed in prepare tx rx"); break; } - error = f_hal_nfc_poller_tx(tx_data, tx_bits); + error = + f_hal_nfc_poller_tx(bit_buffer_get_data(tx_buffer), bit_buffer_get_size(tx_buffer)); if(error != FHalNfcErrorNone) { FURI_LOG_E(TAG, "Failed in poller TX"); ret = nfc_process_hal_error(error); @@ -493,12 +494,16 @@ NfcError nfc_trx( FURI_LOG_E(TAG, "Failed TRX state machine"); break; } - error = f_hal_nfc_poller_rx(rx_data, rx_data_size, rx_bits); + + error = f_hal_nfc_poller_rx( + instance->rx_buffer, sizeof(instance->rx_buffer), &instance->rx_bits); if(error != FHalNfcErrorNone) { FURI_LOG_E(TAG, "Failed in poller RX"); ret = nfc_process_hal_error(error); break; } + + bit_buffer_copy_bits(rx_buffer, instance->rx_buffer, instance->rx_bits); } while(false); return ret; @@ -507,13 +512,10 @@ NfcError nfc_trx( NfcError nfc_iso13444a_short_frame( Nfc* instance, NfcIso14443aShortFrame frame, - uint8_t* rx_data, - uint16_t rx_data_size, - uint16_t* rx_bits, + BitBuffer* rx_buffer, uint32_t fwt) { furi_assert(instance); - furi_assert(rx_data); - furi_assert(rx_bits); + furi_assert(rx_buffer); FHalNfcaShortFrame short_frame = (frame == NfcIso14443aShortFrameAllReqa) ? FHalNfcaShortFrameAllReq : @@ -541,12 +543,16 @@ NfcError nfc_iso13444a_short_frame( FURI_LOG_E(TAG, "Failed TRX state machine"); break; } - error = f_hal_nfc_poller_rx(rx_data, rx_data_size, rx_bits); + + error = f_hal_nfc_poller_rx( + instance->rx_buffer, sizeof(instance->rx_buffer), &instance->rx_bits); if(error != FHalNfcErrorNone) { FURI_LOG_E(TAG, "Failed in poller RX"); ret = nfc_process_hal_error(error); break; } + + bit_buffer_copy_bits(rx_buffer, instance->rx_buffer, instance->rx_bits); } while(false); return ret; @@ -554,13 +560,13 @@ NfcError nfc_iso13444a_short_frame( NfcError nfc_iso13444a_sdd_frame( Nfc* instance, - uint8_t* tx_data, - uint16_t tx_bits, - uint8_t* rx_data, - uint16_t rx_data_size, - uint16_t* rx_bits, + const BitBuffer* tx_buffer, + BitBuffer* rx_buffer, uint32_t fwt) { furi_assert(instance); + furi_assert(tx_buffer); + furi_assert(rx_buffer); + furi_assert(instance->state == NfcStatePollerReady); NfcError ret = NfcErrorNone; @@ -571,7 +577,8 @@ NfcError nfc_iso13444a_sdd_frame( FURI_LOG_E(TAG, "Failed in prepare tx rx"); break; } - error = f_hal_nfca_send_sdd_frame(tx_data, tx_bits); + error = f_hal_nfca_send_sdd_frame( + bit_buffer_get_data(tx_buffer), bit_buffer_get_size(tx_buffer)); if(error != FHalNfcErrorNone) { FURI_LOG_E(TAG, "Failed in poller TX"); ret = nfc_process_hal_error(error); @@ -583,12 +590,16 @@ NfcError nfc_iso13444a_sdd_frame( FURI_LOG_E(TAG, "Failed TRX state machine"); break; } - error = f_hal_nfca_receive_sdd_frame(rx_data, rx_data_size, rx_bits); + + error = f_hal_nfc_poller_rx( + instance->rx_buffer, sizeof(instance->rx_buffer), &instance->rx_bits); if(error != FHalNfcErrorNone) { FURI_LOG_E(TAG, "Failed in poller RX"); ret = nfc_process_hal_error(error); break; } + + bit_buffer_copy_bits(rx_buffer, instance->rx_buffer, instance->rx_bits); } while(false); return ret; diff --git a/lib/nfc/nfc.h b/lib/nfc/nfc.h index 69b144e16f53..4e7083ea980d 100644 --- a/lib/nfc/nfc.h +++ b/lib/nfc/nfc.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #ifdef __cplusplus extern "C" { @@ -25,8 +25,7 @@ typedef enum { } NfcEventType; typedef struct { - uint8_t* rx_data; - uint16_t rx_bits; + BitBuffer* buffer; } NfcEventData; typedef struct { @@ -104,43 +103,28 @@ void nfc_stop(Nfc* instance); // Called from worker thread -NfcError nfc_listener_tx(Nfc* instance, uint8_t* tx_data, uint16_t tx_bits); +NfcError nfc_listener_tx(Nfc* instance, const BitBuffer* tx_buffer); NfcError nfc_trx_custom_parity( Nfc* instance, - uint8_t* tx_data, - uint16_t tx_bits, - uint8_t* rx_data, - uint16_t rx_data_size, - uint16_t* rx_bits, + const BitBuffer* tx_buffer, + BitBuffer* rx_buffer, uint32_t fwt); -NfcError nfc_trx( - Nfc* instance, - uint8_t* tx_data, - uint16_t tx_bits, - uint8_t* rx_data, - uint16_t rx_data_size, - uint16_t* rx_bits, - uint32_t fwt); +NfcError nfc_trx(Nfc* instance, const BitBuffer* tx_buffer, BitBuffer* rx_buffer, uint32_t fwt); // Technology specific API NfcError nfc_iso13444a_short_frame( Nfc* instance, NfcIso14443aShortFrame frame, - uint8_t* rx_data, - uint16_t rx_data_size, - uint16_t* rx_bits, + BitBuffer* rx_buffer, uint32_t fwt); NfcError nfc_iso13444a_sdd_frame( Nfc* instance, - uint8_t* tx_data, - uint16_t tx_bits, - uint8_t* rx_data, - uint16_t rx_data_size, - uint16_t* rx_bits, + const BitBuffer* tx_buffer, + BitBuffer* rx_buffer, uint32_t fwt); #ifdef __cplusplus diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c index 50d24551441a..5c69d46eebd8 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c @@ -52,23 +52,24 @@ Iso14443_4aError iso14443_4a_poller_async_read_ats(Iso14443_4aPoller* instance) instance->protocol_data.ats_request.cmd = 0xe0; instance->protocol_data.ats_request.param = 0x80; - uint16_t rx_bits; + bit_buffer_copy_bytes( + instance->tx_buffer, + (uint8_t*)&instance->protocol_data.ats_request, + sizeof(instance->protocol_data.ats_request)); - // TODO: Adapt lower methods to use BitBuffers NfcaError error = nfca_poller_send_standart_frame( instance->iso14443_3a_poller, - (uint8_t*)&instance->protocol_data.ats_request, - BITS_IN_BYTE * sizeof(instance->protocol_data.ats_request), - (uint8_t*)&instance->protocol_data.ats_response, - BITS_IN_BYTE * sizeof(instance->protocol_data.ats_response), - &rx_bits, + instance->tx_buffer, + instance->rx_buffer, NFCA_FDT_LISTEN_FC); - if(error != NfcaErrorNone) { FURI_LOG_E(TAG, "Ats request failed: %d", error); break; - } else if(rx_bits != BITS_IN_BYTE * sizeof(instance->protocol_data.ats_response)) { - FURI_LOG_E(TAG, "Ats response wrong length: %d bits", rx_bits); + } + if(bit_buffer_get_size_bytes(instance->rx_buffer) != + sizeof(instance->protocol_data.ats_response)) { + FURI_LOG_E(TAG, "Ats response wrong length"); + ret = Iso14443_4aErrorProtocol; break; } @@ -96,16 +97,8 @@ Iso14443_4aError iso14443_4a_poller_send_block( Iso14443_4aError ret = Iso14443_4aErrorNone; do { - // TODO: Adapt lower methods to use BitBuffers - uint16_t rx_size_bits; NfcaError error = nfca_poller_send_standart_frame( - instance->iso14443_3a_poller, - bit_buffer_get_data(instance->tx_buffer), - bit_buffer_get_size(instance->tx_buffer), - bit_buffer_get_data(instance->rx_buffer), - bit_buffer_get_capacity_bytes(instance->rx_buffer), - &rx_size_bits, - fwt); + instance->iso14443_3a_poller, instance->tx_buffer, instance->rx_buffer, fwt); if(error != NfcaErrorNone) { FURI_LOG_E(TAG, "Iso14443-3 error: %d", error); @@ -113,9 +106,6 @@ Iso14443_4aError iso14443_4a_poller_send_block( break; } - // TODO: Do not set the size directly - bit_buffer_set_size(instance->rx_buffer, rx_size_bits); - if(!bit_buffer_starts_with_byte(instance->rx_buffer, pcb)) { ret = Iso14443_4aErrorProtocol; break; diff --git a/lib/nfc/protocols/mf_classic/crypto1.c b/lib/nfc/protocols/mf_classic/crypto1.c index 77034c314467..b973228e6e0b 100644 --- a/lib/nfc/protocols/mf_classic/crypto1.c +++ b/lib/nfc/protocols/mf_classic/crypto1.c @@ -40,7 +40,7 @@ void crypto1_init(Crypto1* crypto1, uint64_t key) { } } -uint32_t crypto1_filter(uint32_t in) { +static uint32_t crypto1_filter(uint32_t in) { uint32_t out = 0; out = 0xf22c0 >> (in & 0xf) & 16; out |= 0x6c9c0 >> (in >> 4 & 0xf) & 8; @@ -81,61 +81,92 @@ uint32_t crypto1_word(Crypto1* crypto1, uint32_t in, int is_encrypted) { return out; } -uint32_t prng_successor(uint32_t x, uint32_t n) { +static uint32_t prng_successor(uint32_t x, uint32_t n) { SWAPENDIAN(x); while(n--) x = x >> 1 | (x >> 16 ^ x >> 18 ^ x >> 19 ^ x >> 21) << 31; return SWAPENDIAN(x); } -void crypto1_decrypt( - Crypto1* crypto, - uint8_t* encrypted_data, - uint16_t encrypted_data_bits, - uint8_t* decrypted_data) { +void crypto1_decrypt(Crypto1* crypto, const BitBuffer* buff, BitBuffer* out) { furi_assert(crypto); - furi_assert(encrypted_data); - furi_assert(decrypted_data); + furi_assert(buff); + furi_assert(out); - if(encrypted_data_bits < 8) { + size_t bits = bit_buffer_get_size(buff); + bit_buffer_set_size(out, bits); + const uint8_t* encrypted_data = bit_buffer_get_data(buff); + if(bits < 8) { uint8_t decrypted_byte = 0; - decrypted_byte |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(encrypted_data[0], 0)) << 0; - decrypted_byte |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(encrypted_data[0], 1)) << 1; - decrypted_byte |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(encrypted_data[0], 2)) << 2; - decrypted_byte |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(encrypted_data[0], 3)) << 3; - decrypted_data[0] = decrypted_byte; + uint8_t encrypted_byte = encrypted_data[0]; + decrypted_byte |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(encrypted_byte, 0)) << 0; + decrypted_byte |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(encrypted_byte, 1)) << 1; + decrypted_byte |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(encrypted_byte, 2)) << 2; + decrypted_byte |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(encrypted_byte, 3)) << 3; + bit_buffer_set_byte(out, 0, decrypted_byte); } else { - for(size_t i = 0; i < encrypted_data_bits / 8; i++) { - decrypted_data[i] = crypto1_byte(crypto, 0, 0) ^ encrypted_data[i]; + for(size_t i = 0; i < bits / 8; i++) { + uint8_t decrypted_byte = crypto1_byte(crypto, 0, 0) ^ encrypted_data[i]; + bit_buffer_set_byte(out, i, decrypted_byte); } } } -void crypto1_encrypt( - Crypto1* crypto, - uint8_t* keystream, - uint8_t* plain_data, - uint16_t plain_data_bits, - uint8_t* encrypted_data, - uint8_t* encrypted_parity) { +void crypto1_encrypt(Crypto1* crypto, uint8_t* keystream, const BitBuffer* buff, BitBuffer* out) { furi_assert(crypto); - furi_assert(plain_data); - furi_assert(encrypted_data); - furi_assert(encrypted_parity); - - if(plain_data_bits < 8) { - encrypted_data[0] = 0; - for(size_t i = 0; i < plain_data_bits; i++) { - encrypted_data[0] |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(plain_data[0], i)) << i; + furi_assert(buff); + furi_assert(out); + + size_t bits = bit_buffer_get_size(buff); + bit_buffer_set_size(out, bits); + const uint8_t* plain_data = bit_buffer_get_data(buff); + if(bits < 8) { + uint8_t encrypted_byte = 0; + for(size_t i = 0; i < bits; i++) { + encrypted_byte |= (crypto1_bit(crypto, 0, 0) ^ FURI_BIT(plain_data[0], i)) << i; } + bit_buffer_set_byte(out, 0, encrypted_byte); } else { - memset(encrypted_parity, 0, plain_data_bits / 8 + 1); - for(uint8_t i = 0; i < plain_data_bits / 8; i++) { - encrypted_data[i] = crypto1_byte(crypto, keystream ? keystream[i] : 0, 0) ^ - plain_data[i]; - encrypted_parity[i / 8] |= - (((crypto1_filter(crypto->odd) ^ nfc_util_odd_parity8(plain_data[i])) & 0x01) - << (7 - (i & 0x0007))); + for(uint8_t i = 0; i < bits / 8; i++) { + uint8_t encrypted_byte = crypto1_byte(crypto, keystream ? keystream[i] : 0, 0) ^ + plain_data[i]; + bool parity_bit = + ((crypto1_filter(crypto->odd) ^ nfc_util_odd_parity8(plain_data[i])) & 0x01); + bit_buffer_set_byte_with_parity(out, i, encrypted_byte, parity_bit); } } } + +void crypto1_encrypt_reader_nonce( + Crypto1* crypto, + uint64_t key, + uint32_t cuid, + uint8_t* nt, + uint8_t* nr, + BitBuffer* out) { + furi_assert(crypto); + furi_assert(nt); + furi_assert(nr); + furi_assert(out); + + bit_buffer_set_size_bytes(out, 8); + uint32_t nt_num = nfc_util_bytes2num(nt, sizeof(uint32_t)); + + crypto1_init(crypto, key); + crypto1_word(crypto, nt_num ^ cuid, 0); + + for(size_t i = 0; i < 4; i++) { + uint8_t byte = crypto1_byte(crypto, nr[i], 0) ^ nr[i]; + bool parity_bit = ((crypto1_filter(crypto->odd) ^ nfc_util_odd_parity8(nr[i])) & 0x01); + bit_buffer_set_byte_with_parity(out, i, byte, parity_bit); + nr[i] = byte; + } + + nt_num = prng_successor(nt_num, 32); + for(size_t i = 4; i < 8; i++) { + nt_num = prng_successor(nt_num, 8); + uint8_t byte = crypto1_byte(crypto, 0, 0) ^ (uint8_t)(nt_num); + bool parity_bit = ((crypto1_filter(crypto->odd) ^ nfc_util_odd_parity8(nt_num)) & 0x01); + bit_buffer_set_byte_with_parity(out, i, byte, parity_bit); + } +} diff --git a/lib/nfc/protocols/mf_classic/crypto1.h b/lib/nfc/protocols/mf_classic/crypto1.h index eaa636f0cfb7..0e251dae09dd 100644 --- a/lib/nfc/protocols/mf_classic/crypto1.h +++ b/lib/nfc/protocols/mf_classic/crypto1.h @@ -1,7 +1,6 @@ #pragma once -#include -#include +#include #ifdef __cplusplus extern "C" { @@ -26,23 +25,17 @@ uint8_t crypto1_byte(Crypto1* crypto1, uint8_t in, int is_encrypted); uint32_t crypto1_word(Crypto1* crypto1, uint32_t in, int is_encrypted); -uint32_t crypto1_filter(uint32_t in); +void crypto1_decrypt(Crypto1* crypto, const BitBuffer* buff, BitBuffer* out); -uint32_t prng_successor(uint32_t x, uint32_t n); +void crypto1_encrypt(Crypto1* crypto, uint8_t* keystream, const BitBuffer* buff, BitBuffer* out); -void crypto1_decrypt( +void crypto1_encrypt_reader_nonce( Crypto1* crypto, - uint8_t* encrypted_data, - uint16_t encrypted_data_bits, - uint8_t* decrypted_data); - -void crypto1_encrypt( - Crypto1* crypto, - uint8_t* keystream, - uint8_t* plain_data, - uint16_t plain_data_bits, - uint8_t* encrypted_data, - uint8_t* encrypted_parity); + uint64_t key, + uint32_t cuid, + uint8_t* nt, + uint8_t* nr, + BitBuffer* out); #ifdef __cplusplus } diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller.c b/lib/nfc/protocols/mf_classic/mf_classic_poller.c index d9803e7d30e9..8182afc6b085 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller.c @@ -58,10 +58,10 @@ MfClassicError mf_classic_poller_start( instance->data = mf_classic_alloc(); instance->crypto = crypto1_alloc(); - instance->plain_buff = - nfc_poller_buffer_alloc(MF_CLASSIC_MAX_BUFF_SIZE, MF_CLASSIC_MAX_BUFF_SIZE); - instance->encrypted_buff = - nfc_poller_buffer_alloc(MF_CLASSIC_MAX_BUFF_SIZE, MF_CLASSIC_MAX_BUFF_SIZE); + instance->tx_plain_buffer = bit_buffer_alloc(MF_CLASSIC_MAX_BUFF_SIZE); + instance->tx_encrypted_buffer = bit_buffer_alloc(MF_CLASSIC_MAX_BUFF_SIZE); + instance->rx_plain_buffer = bit_buffer_alloc(MF_CLASSIC_MAX_BUFF_SIZE); + instance->rx_encrypted_buffer = bit_buffer_alloc(MF_CLASSIC_MAX_BUFF_SIZE); instance->session_state = MfClassicPollerSessionStateActive; nfca_poller_start(instance->nfca_poller, callback, context); @@ -321,7 +321,6 @@ NfcaPollerCommand mf_classic_dict_attack_callback(NfcaPollerEvent event, void* c command = MfClassicPollerCommandStop; } else { if(event.type == NfcaPollerEventTypeReady) { - // furi_delay_ms(100); command = mf_classic_poller_dict_attack_handler[instance->state](instance); } else if(event.type == NfcaPollerEventTypeError) { if(event.data.error == NfcaErrorNotPresent) { @@ -356,14 +355,18 @@ MfClassicError mf_classic_poller_dict_attack( MfClassicError mf_classic_poller_reset(MfClassicPoller* instance) { furi_assert(instance); furi_assert(instance->data); - furi_assert(instance->plain_buff); - furi_assert(instance->encrypted_buff); furi_assert(instance->nfca_poller); + furi_assert(instance->tx_plain_buffer); + furi_assert(instance->rx_plain_buffer); + furi_assert(instance->tx_encrypted_buffer); + furi_assert(instance->rx_encrypted_buffer); instance->auth_state = MfClassicAuthStateIdle; crypto1_free(instance->crypto); - nfc_poller_buffer_free(instance->plain_buff); - nfc_poller_buffer_free(instance->encrypted_buff); + bit_buffer_free(instance->tx_plain_buffer); + bit_buffer_free(instance->rx_plain_buffer); + bit_buffer_free(instance->tx_encrypted_buffer); + bit_buffer_free(instance->rx_encrypted_buffer); instance->callback = NULL; instance->context = NULL; diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c index 7e90587ed082..bf9c94483c6d 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c @@ -39,87 +39,53 @@ MfClassicError mf_classic_async_auth( MfClassicKey* key, MfClassicKeyType key_type, MfClassicAuthContext* data) { - NfcPollerBuffer* buff = instance->plain_buff; - nfc_poller_buffer_reset(buff); MfClassicError ret = MfClassicErrorNone; NfcaError error = NfcaErrorNone; do { nfca_copy(instance->data->nfca_data, nfca_poller_get_data(instance->nfca_poller)); - uint8_t auth_cmd = (key_type == MfClassicKeyTypeB) ? MF_CLASSIC_AUTH_KEY_B_CMD : - MF_CLASSIC_AUTH_KEY_A_CMD; - buff->tx_data[0] = auth_cmd; - buff->tx_data[1] = block_num; - buff->tx_bits = 2 * 8; + uint8_t auth_type = (key_type == MfClassicKeyTypeB) ? MF_CLASSIC_AUTH_KEY_B_CMD : + MF_CLASSIC_AUTH_KEY_A_CMD; + uint8_t auth_cmd[2] = {auth_type, block_num}; + bit_buffer_copy_bytes(instance->tx_plain_buffer, auth_cmd, sizeof(auth_cmd)); error = nfca_poller_send_standart_frame( instance->nfca_poller, - buff->tx_data, - buff->tx_bits, - buff->rx_data, - buff->rx_data_size, - &buff->rx_bits, + instance->tx_plain_buffer, + instance->rx_plain_buffer, MF_CLASSIC_FWT_FC); if(error != NfcaErrorWrongCrc) { ret = mf_classic_process_error(error); break; } - if(buff->rx_bits != sizeof(MfClassicNt) * 8) { + if(bit_buffer_get_size_bytes(instance->rx_plain_buffer) != sizeof(MfClassicNt)) { ret = MfClassicErrorProtocol; break; } - if(data) { - memcpy(data->nt.data, buff->rx_data, sizeof(MfClassicNt)); - } - uint8_t* cuid_start = instance->data->nfca_data->uid; - if(instance->data->nfca_data->uid_len == 7) { - cuid_start = &instance->data->nfca_data->uid[3]; + MfClassicNt nt = {}; + bit_buffer_write_bytes(instance->rx_plain_buffer, nt.data, sizeof(nt.data)); + if(data) { + data->nt = nt; } - uint32_t cuid = (cuid_start[0] << 24) | (cuid_start[1] << 16) | (cuid_start[2] << 8) | - (cuid_start[3]); - - uint32_t nt = (uint32_t)nfc_util_bytes2num(buff->rx_data, sizeof(MfClassicNt)); + uint32_t cuid = nfca_get_cuid(instance->data->nfca_data); uint64_t key_num = nfc_util_bytes2num(key->data, sizeof(MfClassicKey)); - crypto1_init(instance->crypto, key_num); - crypto1_word(instance->crypto, nt ^ cuid, 0); - MfClassicNr nr = {}; furi_hal_random_fill_buf(nr.data, sizeof(MfClassicNr)); - // TODO rework! - for(size_t i = 0; i < sizeof(MfClassicNr); i++) { - buff->tx_data[i] = crypto1_byte(instance->crypto, nr.data[i], 0) ^ nr.data[i]; - buff->tx_parity[0] |= - (((crypto1_filter(instance->crypto->odd) ^ nfc_util_odd_parity8(nr.data[i])) & - 0x01) - << (7 - i)); - nr.data[i] = buff->tx_data[i]; - } - nt = prng_successor(nt, 32); - for(size_t i = 4; i < 8; i++) { - nt = prng_successor(nt, 8); - buff->tx_data[i] = crypto1_byte(instance->crypto, 0, 0) ^ (nt & 0xff); - buff->tx_parity[0] |= - (((crypto1_filter(instance->crypto->odd) ^ nfc_util_odd_parity8(nt & 0xff)) & 0x01) - << (7 - i)); - } - buff->tx_bits = 8 * 8; + crypto1_encrypt_reader_nonce( + instance->crypto, key_num, cuid, nt.data, nr.data, instance->tx_encrypted_buffer); error = nfca_poller_txrx_custom_parity( instance->nfca_poller, - buff->tx_data, - buff->tx_parity, - buff->tx_bits, - buff->rx_data, - buff->rx_parity, - buff->rx_data_size, - &buff->rx_bits, + instance->tx_encrypted_buffer, + instance->rx_encrypted_buffer, MF_CLASSIC_FWT_FC); + if(error != NfcaErrorNone) { ret = mf_classic_process_error(error); break; } - if(buff->rx_bits != 4 * 8) { + if(bit_buffer_get_size_bytes(instance->rx_encrypted_buffer) != 4) { ret = MfClassicErrorAuth; } @@ -128,8 +94,10 @@ MfClassicError mf_classic_async_auth( if(data) { data->nr = nr; - memcpy(data->ar.data, &buff->tx_data[4], sizeof(MfClassicAr)); - memcpy(data->at.data, buff->rx_data, sizeof(MfClassicAt)); + const uint8_t* nr_ar = bit_buffer_get_data(instance->tx_encrypted_buffer); + memcpy(data->ar.data, &nr_ar[4], sizeof(MfClassicAr)); + bit_buffer_write_bytes( + instance->rx_encrypted_buffer, data->at.data, sizeof(MfClassicAt)); } } while(false); @@ -141,35 +109,21 @@ MfClassicError mf_classic_async_auth( } MfClassicError mf_classic_aync_halt(MfClassicPoller* instance) { - NfcPollerBuffer* plain_buff = instance->plain_buff; - NfcPollerBuffer* encrypted_buff = instance->encrypted_buff; MfClassicError ret = MfClassicErrorNone; NfcaError error = NfcaErrorNone; do { - plain_buff->tx_data[0] = MF_CLASSIC_HALT_MSB_CMD; - plain_buff->tx_data[1] = MF_CLASSIC_HALT_LSB_CMD; - nfca_append_crc(plain_buff->tx_data, 2); - plain_buff->tx_bits = 4 * 8; + uint8_t halt_cmd[2] = {MF_CLASSIC_HALT_MSB_CMD, MF_CLASSIC_HALT_LSB_CMD}; + bit_buffer_copy_bytes(instance->tx_plain_buffer, halt_cmd, sizeof(halt_cmd)); + nfca_append_crc(instance->tx_plain_buffer); - encrypted_buff->tx_bits = plain_buff->tx_bits; crypto1_encrypt( - instance->crypto, - NULL, - plain_buff->tx_data, - plain_buff->tx_bits, - encrypted_buff->tx_data, - encrypted_buff->tx_parity); + instance->crypto, NULL, instance->tx_plain_buffer, instance->tx_encrypted_buffer); error = nfca_poller_txrx_custom_parity( instance->nfca_poller, - encrypted_buff->tx_data, - encrypted_buff->tx_parity, - encrypted_buff->tx_bits, - encrypted_buff->rx_data, - encrypted_buff->rx_parity, - encrypted_buff->rx_data_size, - &encrypted_buff->rx_bits, + instance->tx_encrypted_buffer, + instance->rx_encrypted_buffer, MF_CLASSIC_FWT_FC); if(error != NfcaErrorTimeout) { ret = mf_classic_process_error(error); @@ -186,57 +140,43 @@ MfClassicError mf_classic_async_read_block( MfClassicPoller* instance, uint8_t block_num, MfClassicBlock* data) { - NfcPollerBuffer* plain_buff = instance->plain_buff; - NfcPollerBuffer* encrypted_buff = instance->encrypted_buff; MfClassicError ret = MfClassicErrorNone; NfcaError error = NfcaErrorNone; do { - plain_buff->tx_data[0] = MF_CLASSIC_READ_BLOCK_CMD; - plain_buff->tx_data[1] = block_num; - nfca_append_crc(plain_buff->tx_data, 2); - plain_buff->tx_bits = 4 * 8; + uint8_t read_block_cmd[2] = {MF_CLASSIC_READ_BLOCK_CMD, block_num}; + bit_buffer_copy_bytes(instance->tx_plain_buffer, read_block_cmd, sizeof(read_block_cmd)); + nfca_append_crc(instance->tx_plain_buffer); - encrypted_buff->tx_bits = plain_buff->tx_bits; crypto1_encrypt( - instance->crypto, - NULL, - plain_buff->tx_data, - plain_buff->tx_bits, - encrypted_buff->tx_data, - encrypted_buff->tx_parity); + instance->crypto, NULL, instance->tx_plain_buffer, instance->tx_encrypted_buffer); error = nfca_poller_txrx_custom_parity( instance->nfca_poller, - encrypted_buff->tx_data, - encrypted_buff->tx_parity, - encrypted_buff->tx_bits, - encrypted_buff->rx_data, - encrypted_buff->rx_parity, - encrypted_buff->rx_data_size, - &encrypted_buff->rx_bits, + instance->tx_encrypted_buffer, + instance->rx_encrypted_buffer, MF_CLASSIC_FWT_FC); if(error != NfcaErrorNone) { ret = mf_classic_process_error(error); break; } - if(encrypted_buff->rx_bits != (sizeof(MfClassicBlock) + 2) * 8) { + if(bit_buffer_get_size_bytes(instance->rx_encrypted_buffer) != + (sizeof(MfClassicBlock) + 2)) { ret = MfClassicErrorProtocol; break; } crypto1_decrypt( - instance->crypto, - encrypted_buff->rx_data, - encrypted_buff->rx_bits, - plain_buff->rx_data); + instance->crypto, instance->rx_encrypted_buffer, instance->rx_plain_buffer); - if(!nfca_check_crc(plain_buff->rx_data, sizeof(MfClassicBlock) + 2)) { + if(!nfca_check_crc(instance->rx_plain_buffer)) { FURI_LOG_D(TAG, "CRC error"); ret = MfClassicErrorProtocol; break; } - memcpy(data->data, plain_buff->rx_data, sizeof(MfClassicBlock)); + + nfca_trim_crc(instance->rx_plain_buffer); + bit_buffer_write_bytes(instance->rx_plain_buffer, data->data, sizeof(MfClassicBlock)); } while(false); return ret; diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h index c369707151c5..3126e9a08dd2 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h @@ -2,7 +2,6 @@ #include "mf_classic_poller.h" #include -#include #include #include "crypto1.h" @@ -58,8 +57,10 @@ struct MfClassicPoller { uint8_t key_reuse_sector; uint8_t sectors_total; Crypto1* crypto; - NfcPollerBuffer* plain_buff; - NfcPollerBuffer* encrypted_buff; + BitBuffer* tx_plain_buffer; + BitBuffer* tx_encrypted_buffer; + BitBuffer* rx_plain_buffer; + BitBuffer* rx_encrypted_buffer; MfClassicData* data; MfClassicPollerCallback callback; void* context; diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c index c5d7af93b1b7..cfcd934208b9 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c @@ -25,8 +25,7 @@ struct MfUltralightListener { MfUltralightListenerAuthState auth_state; MfUltraligthListenerState state; MfUltralightData* data; - uint8_t tx_data[MF_ULTRALIGHT_LISTENER_MAX_TX_BUFF_SIZE]; - uint16_t tx_bits; + BitBuffer* tx_buffer; MfUltralightFeatureSupport features; MfUltralightConfigPages* config; @@ -34,14 +33,11 @@ struct MfUltralightListener { void* context; }; -typedef bool (*MfUltralightListenerCommandCallback)( - MfUltralightListener* instance, - uint8_t* rx_data, - uint16_t rx_bits); +typedef bool (*MfUltralightListenerCommandCallback)(MfUltralightListener* instance, BitBuffer* buf); typedef struct { uint8_t cmd; - uint16_t cmd_len_bits; + size_t cmd_len_bits; MfUltralightListenerCommandCallback callback; } MfUltralightListenerCmdHandler; @@ -103,16 +99,17 @@ static bool mf_ultralight_listener_check_access( } static void mf_ultralight_listener_send_short_resp(MfUltralightListener* instance, uint8_t data) { - nfca_listener_tx(instance->nfca_listener, &data, 4); + furi_assert(instance->tx_buffer); + + bit_buffer_set_size(instance->tx_buffer, 4); + bit_buffer_set_byte(instance->tx_buffer, 0, data); + nfca_listener_tx(instance->nfca_listener, instance->tx_buffer); }; -static bool mf_ultralight_listener_read_page_handler( - MfUltralightListener* instance, - uint8_t* rx_data, - uint16_t rx_bits) { - UNUSED(rx_bits); +static bool + mf_ultralight_listener_read_page_handler(MfUltralightListener* instance, BitBuffer* buffer) { bool command_processed = false; - uint8_t start_page = rx_data[1]; + uint8_t start_page = bit_buffer_get_byte(buffer, 1); uint16_t pages_total = instance->data->pages_total; MfUltralightPageReadCommandData read_cmd_data = {}; @@ -136,22 +133,21 @@ static bool mf_ultralight_listener_read_page_handler( read_cmd_data.page[i] = instance->data->page[(start_page + i) % pages_total]; } } - instance->tx_bits = sizeof(MfUltralightPageReadCommandData) * 8; - nfca_listener_send_standart_frame( - instance->nfca_listener, (uint8_t*)&read_cmd_data, instance->tx_bits); + bit_buffer_copy_bytes( + instance->tx_buffer, + (uint8_t*)&read_cmd_data, + sizeof(MfUltralightPageReadCommandData)); + nfca_listener_send_standart_frame(instance->nfca_listener, instance->tx_buffer); } command_processed = true; return command_processed; } -static bool mf_ultralight_listener_write_page_handler( - MfUltralightListener* instance, - uint8_t* rx_data, - uint16_t rx_bits) { - UNUSED(rx_bits); +static bool + mf_ultralight_listener_write_page_handler(MfUltralightListener* instance, BitBuffer* buffer) { bool command_processed = false; - uint8_t start_page = rx_data[1]; + uint8_t start_page = bit_buffer_get_byte(buffer, 1); uint16_t pages_total = instance->data->pages_total; if(pages_total < start_page) { @@ -164,6 +160,7 @@ static bool mf_ultralight_listener_write_page_handler( instance->state = MfUltraligthListenerStateIdle; instance->auth_state = MfUltralightListenerAuthStateIdle; } else { + const uint8_t* rx_data = bit_buffer_get_data(buffer); memcpy(instance->data->page[start_page].data, &rx_data[2], sizeof(MfUltralightPage)); mf_ultralight_listener_send_short_resp(instance, MF_ULTRALIGHT_CMD_ACK); } @@ -172,18 +169,16 @@ static bool mf_ultralight_listener_write_page_handler( return command_processed; } -static bool mf_ultralight_listener_read_version_handler( - MfUltralightListener* instance, - uint8_t* rx_data, - uint16_t rx_bits) { - UNUSED(rx_bits); - UNUSED(rx_data); +static bool + mf_ultralight_listener_read_version_handler(MfUltralightListener* instance, BitBuffer* buffer) { + UNUSED(buffer); + bool command_processed = false; + if((instance->features & MfUltralightFeatureSupportReadVersion)) { - memcpy(instance->tx_data, &instance->data->version, sizeof(instance->data->version)); - instance->tx_bits = sizeof(instance->data->version) * 8; - nfca_listener_send_standart_frame( - instance->nfca_listener, instance->tx_data, instance->tx_bits); + bit_buffer_copy_bytes( + instance->tx_buffer, (uint8_t*)&instance->data->version, sizeof(MfUltralightVersion)); + nfca_listener_send_standart_frame(instance->nfca_listener, instance->tx_buffer); } else { nfca_listener_sleep(instance->nfca_listener); instance->state = MfUltraligthListenerStateIdle; @@ -195,17 +190,15 @@ static bool mf_ultralight_listener_read_version_handler( static bool mf_ultralight_listener_read_signature_handler( MfUltralightListener* instance, - uint8_t* rx_data, - uint16_t rx_bits) { - UNUSED(rx_bits); - UNUSED(rx_data); + BitBuffer* buffer) { + UNUSED(buffer); bool command_processed = false; + if((instance->features & MfUltralightFeatureSupportReadSignature)) { - memcpy(instance->tx_data, &instance->data->signature, sizeof(instance->data->signature)); - instance->tx_bits = sizeof(instance->data->signature) * 8; - nfca_listener_send_standart_frame( - instance->nfca_listener, instance->tx_data, instance->tx_bits); + bit_buffer_copy_bytes( + instance->tx_buffer, instance->data->signature.data, sizeof(MfUltralightSignature)); + nfca_listener_send_standart_frame(instance->nfca_listener, instance->tx_buffer); } else { nfca_listener_sleep(instance->nfca_listener); instance->state = MfUltraligthListenerStateIdle; @@ -215,16 +208,12 @@ static bool mf_ultralight_listener_read_signature_handler( return command_processed; } -static bool mf_ultralight_listener_read_counter_handler( - MfUltralightListener* instance, - uint8_t* rx_data, - uint16_t rx_bits) { - UNUSED(rx_bits); - +static bool + mf_ultralight_listener_read_counter_handler(MfUltralightListener* instance, BitBuffer* buffer) { bool command_processed = false; do { - uint8_t counter_num = rx_data[1]; + uint8_t counter_num = bit_buffer_get_byte(buffer, 1); if((instance->features & MfUltralightFeatureSupportReadCounter) == 0) break; if(instance->features & MfUltralightFeatureSupportSingleCounter) { if(counter_num != 2) { @@ -242,12 +231,13 @@ static bool mf_ultralight_listener_read_counter_handler( } } if(counter_num > 2) break; - instance->tx_data[0] = (instance->data->counter[counter_num].counter >> 0) & 0xff; - instance->tx_data[1] = (instance->data->counter[counter_num].counter >> 8) & 0xff; - instance->tx_data[2] = (instance->data->counter[counter_num].counter >> 16) & 0xff; - instance->tx_bits = 3 * 8; - nfca_listener_send_standart_frame( - instance->nfca_listener, instance->tx_data, instance->tx_bits); + uint8_t cnt_value[3] = { + (instance->data->counter[counter_num].counter >> 0) & 0xff, + (instance->data->counter[counter_num].counter >> 8) & 0xff, + (instance->data->counter[counter_num].counter >> 16) & 0xff, + }; + bit_buffer_copy_bytes(instance->tx_buffer, cnt_value, sizeof(cnt_value)); + nfca_listener_send_standart_frame(instance->nfca_listener, instance->tx_buffer); command_processed = true; } while(false); @@ -256,36 +246,30 @@ static bool mf_ultralight_listener_read_counter_handler( static bool mf_ultralight_listener_check_tearing_handler( MfUltralightListener* instance, - uint8_t* rx_data, - uint16_t rx_bits) { - UNUSED(rx_bits); - + BitBuffer* buffer) { bool command_processed = false; do { - uint8_t tearing_flag_num = rx_data[1]; + uint8_t tearing_flag_num = bit_buffer_get_byte(buffer, 1); if((instance->features & MfUltralightFeatureSupportCheckTearingFlag) == 0) break; if(tearing_flag_num > 2) break; - instance->tx_data[0] = instance->data->tearing_flag->data[0]; - instance->tx_bits = 8; - nfca_listener_send_standart_frame( - instance->nfca_listener, instance->tx_data, instance->tx_bits); + bit_buffer_set_size_bytes(instance->tx_buffer, 1); + bit_buffer_set_byte(instance->tx_buffer, 0, instance->data->tearing_flag->data[0]); + nfca_listener_send_standart_frame(instance->nfca_listener, instance->tx_buffer); command_processed = true; } while(false); return command_processed; } -static bool mf_ultralight_listener_auth_handler( - MfUltralightListener* instance, - uint8_t* rx_data, - uint16_t rx_bits) { - UNUSED(rx_bits); - +static bool + mf_ultralight_listener_auth_handler(MfUltralightListener* instance, BitBuffer* buffer) { bool command_processed = false; do { if((instance->features & MfUltralightFeatureSupportAuthentication) == 0) break; + + const uint8_t* rx_data = bit_buffer_get_data(buffer); MfUltralightAuthPassword password = {}; memcpy(password.data, &rx_data[1], sizeof(MfUltralightAuthPassword)); if(instance->callback) { @@ -297,11 +281,11 @@ static bool mf_ultralight_listener_auth_handler( instance->callback(event, instance->context); } if(password.pass != instance->config->password.pass) break; - memcpy(instance->tx_data, instance->config->pack.data, sizeof(MfUltralightAuthPack)); - instance->tx_bits = sizeof(MfUltralightAuthPack) * 8; + + bit_buffer_copy_bytes( + instance->tx_buffer, instance->config->pack.data, sizeof(MfUltralightAuthPack)); instance->auth_state = MfUltralightListenerAuthStateSuccess; - nfca_listener_send_standart_frame( - instance->nfca_listener, instance->tx_data, instance->tx_bits); + nfca_listener_send_standart_frame(instance->nfca_listener, instance->tx_buffer); command_processed = true; } while(false); @@ -351,16 +335,15 @@ static NfcaListenerCommand furi_assert(context); MfUltralightListener* instance = context; - uint8_t* rx_data = event.data.rx_data; - uint16_t rx_bits = event.data.rx_bits; + BitBuffer* rx_buffer = event.data.buffer; NfcaListenerCommand command = NfcaListenerCommandContinue; if(event.type == NfcaListenerEventTypeReceivedStandartFrame) { bool cmd_processed = false; for(size_t i = 0; i < COUNT_OF(mf_ultralight_command); i++) { - if(rx_bits != mf_ultralight_command[i].cmd_len_bits) continue; - if(rx_data[0] != mf_ultralight_command[i].cmd) continue; - cmd_processed = mf_ultralight_command[i].callback(instance, rx_data, rx_bits); + if(bit_buffer_get_size(rx_buffer) != mf_ultralight_command[i].cmd_len_bits) continue; + if(bit_buffer_get_byte(rx_buffer, 0) != mf_ultralight_command[i].cmd) continue; + cmd_processed = mf_ultralight_command[i].callback(instance, rx_buffer); if(cmd_processed) break; } if(!cmd_processed) { @@ -398,6 +381,7 @@ MfUltralightError mf_ultralight_listener_start( instance->data = mf_ultralight_alloc(); mf_ultralight_copy(instance->data, data); + instance->tx_buffer = bit_buffer_alloc(MF_ULTRALIGHT_LISTENER_MAX_TX_BUFF_SIZE); mf_ultralight_listener_prepare_emulation(instance); instance->callback = callback; @@ -432,9 +416,12 @@ MfUltralightError MfUltralightError mf_ultralight_listener_stop(MfUltralightListener* instance) { furi_assert(instance); furi_assert(instance->data); + furi_assert(instance->tx_buffer); NfcaError error = nfca_listener_stop(instance->nfca_listener); instance->state = MfUltraligthListenerStateIdle; + + bit_buffer_free(instance->tx_buffer); mf_ultralight_free(instance->data); return mf_ultralight_process_error(error); diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c index a9632f210be8..47ffa0f62b45 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c @@ -45,7 +45,8 @@ const MfUltralightData* mf_ultralight_poller_get_data(MfUltralightPoller* instan } static MfUltralightPollerCommand mf_ultralight_poller_handler_idle(MfUltralightPoller* instance) { - nfc_poller_buffer_reset(instance->buffer); + bit_buffer_reset(instance->tx_buffer); + bit_buffer_reset(instance->rx_buffer); nfca_copy(instance->data->nfca_data, nfca_poller_get_data(instance->nfca_poller)); instance->counters_read = 0; instance->counters_total = 3; @@ -373,8 +374,8 @@ MfUltralightError mf_ultralight_poller_start( furi_assert(instance->session_state == MfUltralightPollerSessionStateIdle); instance->data = mf_ultralight_alloc(); - instance->buffer = - nfc_poller_buffer_alloc(MF_ULTRALIGHT_MAX_BUFF_SIZE, MF_ULTRALIGHT_MAX_BUFF_SIZE); + instance->tx_buffer = bit_buffer_alloc(MF_ULTRALIGHT_MAX_BUFF_SIZE); + instance->rx_buffer = bit_buffer_alloc(MF_ULTRALIGHT_MAX_BUFF_SIZE); instance->session_state = MfUltralightPollerSessionStateActive; nfca_poller_start(instance->nfca_poller, callback, context); @@ -400,10 +401,15 @@ MfUltralightError mf_ultralight_poller_read( MfUltralightError mf_ultralight_poller_reset(MfUltralightPoller* instance) { furi_assert(instance); furi_assert(instance->data); - furi_assert(instance->buffer); + furi_assert(instance->tx_buffer); + furi_assert(instance->rx_buffer); furi_assert(instance->nfca_poller); - nfc_poller_buffer_free(instance->buffer); + bit_buffer_free(instance->tx_buffer); + bit_buffer_free(instance->rx_buffer); + instance->tx_buffer = NULL; + instance->rx_buffer = NULL; + instance->callback = NULL; instance->context = NULL; instance->state = MfUltralightPollerStateIdle; diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c index 4f4fdd64c504..b66ebe42e4ed 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c @@ -191,33 +191,27 @@ bool mf_ultralight_poller_ntag_i2c_addr_lin_to_tag( MfUltralightError mf_ultralight_poller_async_auth( MfUltralightPoller* instance, MfUltralightPollerAuthContext* data) { - NfcPollerBuffer* buff = instance->buffer; - buff->tx_data[0] = MF_ULTRALIGHT_CMD_AUTH; - // fill password in lsb - nfc_util_num2bytes(data->password.pass, MF_ULTRALIGHT_AUTH_PASSWORD_SIZE, &buff->tx_data[1]); - buff->tx_bits = (MF_ULTRALIGHT_AUTH_PASSWORD_SIZE + 1) * 8; + uint8_t auth_cmd[5] = {MF_ULTRALIGHT_CMD_AUTH}; + nfc_util_num2bytes(data->password.pass, MF_ULTRALIGHT_AUTH_PASSWORD_SIZE, &auth_cmd[1]); + bit_buffer_copy_bytes(instance->tx_buffer, auth_cmd, sizeof(auth_cmd)); MfUltralightError ret = MfUltralightErrorNone; NfcaError error = NfcaErrorNone; do { error = nfca_poller_send_standart_frame( instance->nfca_poller, - buff->tx_data, - buff->tx_bits, - buff->rx_data, - buff->rx_data_size, - &buff->rx_bits, + instance->tx_buffer, + instance->rx_buffer, MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); if(error != NfcaErrorNone) { ret = mf_ultralight_process_error(error); break; } - if(buff->rx_bits != (MF_ULTRALIGHT_AUTH_PACK_SIZE * 8)) { + if(bit_buffer_get_size_bytes(instance->rx_buffer) != MF_ULTRALIGHT_AUTH_PACK_SIZE) { ret = MfUltralightErrorAuth; break; } - data->pack.data[0] = buff->rx_data[0]; - data->pack.data[1] = buff->rx_data[1]; + bit_buffer_write_bytes(instance->rx_buffer, data->pack.data, MF_ULTRALIGHT_AUTH_PACK_SIZE); } while(false); return ret; @@ -228,40 +222,29 @@ MfUltralightError mf_ultralight_poller_async_read_page_from_sector( uint8_t sector, uint8_t tag, MfUltralightPageReadCommandData* data) { - NfcPollerBuffer* buff = instance->buffer; MfUltralightError ret = MfUltralightErrorNone; NfcaError error = NfcaErrorNone; do { - buff->tx_data[0] = MF_ULTRALIGHT_CMD_SECTOR_SELECT; - buff->tx_data[1] = 0xff; - buff->tx_bits = 16; + const uint8_t select_sector_cmd[2] = {MF_ULTRALIGHT_CMD_SECTOR_SELECT, 0xff}; + bit_buffer_copy_bytes(instance->tx_buffer, select_sector_cmd, sizeof(select_sector_cmd)); error = nfca_poller_send_standart_frame( instance->nfca_poller, - buff->tx_data, - buff->tx_bits, - buff->rx_data, - buff->rx_data_size, - &buff->rx_bits, + instance->tx_buffer, + instance->rx_buffer, MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); - if(error != NfcaErrorNone) { + if(error != NfcaErrorWrongCrc) { FURI_LOG_D(TAG, "Failed to issue sector select command"); ret = mf_ultralight_process_error(error); break; } - buff->tx_data[0] = sector; - buff->tx_data[1] = 0x00; - buff->tx_data[2] = 0x00; - buff->tx_data[3] = 0x00; - buff->tx_bits = 32; + const uint8_t read_sector_cmd[4] = {sector, 0x00, 0x00, 0x00}; + bit_buffer_copy_bytes(instance->tx_buffer, read_sector_cmd, sizeof(read_sector_cmd)); error = nfca_poller_send_standart_frame( instance->nfca_poller, - buff->tx_data, - buff->tx_bits, - buff->rx_data, - buff->rx_data_size, - &buff->rx_bits, + instance->tx_buffer, + instance->rx_buffer, MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); if(error != NfcaErrorTimeout) { // This is NOT a typo! The tag ACKs by not sending a response within 1ms. @@ -280,31 +263,27 @@ MfUltralightError mf_ultralight_poller_async_read_page( MfUltralightPoller* instance, uint8_t start_page, MfUltralightPageReadCommandData* data) { - NfcPollerBuffer* buff = instance->buffer; - buff->tx_data[0] = MF_ULTRALIGHT_CMD_READ_PAGE; - buff->tx_data[1] = start_page; - buff->tx_bits = 16; - MfUltralightError ret = MfUltralightErrorNone; NfcaError error = NfcaErrorNone; + do { + uint8_t read_page_cmd[2] = {MF_ULTRALIGHT_CMD_READ_PAGE, start_page}; + bit_buffer_copy_bytes(instance->tx_buffer, read_page_cmd, sizeof(read_page_cmd)); error = nfca_poller_send_standart_frame( instance->nfca_poller, - buff->tx_data, - buff->tx_bits, - buff->rx_data, - buff->rx_data_size, - &buff->rx_bits, + instance->tx_buffer, + instance->rx_buffer, MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); if(error != NfcaErrorNone) { ret = mf_ultralight_process_error(error); break; } - if(buff->rx_bits != sizeof(MfUltralightPageReadCommandData) * 8) { + if(bit_buffer_get_size_bytes(instance->rx_buffer) != + sizeof(MfUltralightPageReadCommandData)) { ret = MfUltralightErrorProtocol; break; } - memcpy(data, buff->rx_data, sizeof(MfUltralightPageReadCommandData)); + bit_buffer_write_bytes(instance->rx_buffer, data, sizeof(MfUltralightPageReadCommandData)); } while(false); return ret; @@ -314,36 +293,30 @@ MfUltralightError mf_ultralight_poller_async_write_page( MfUltralightPoller* instance, uint8_t page, MfUltralightPage* data) { - NfcPollerBuffer* buff = instance->buffer; - buff->tx_data[0] = MF_ULTRALIGHT_CMD_WRITE_PAGE; - buff->tx_data[1] = page; - memcpy(&buff->tx_data[2], data, MF_ULTRALIGHT_PAGE_SIZE); - buff->tx_bits = (2 + MF_ULTRALIGHT_PAGE_SIZE) * 8; - MfUltralightError ret = MfUltralightErrorNone; NfcaError error = NfcaErrorNone; + do { + uint8_t write_page_cmd[MF_ULTRALIGHT_PAGE_SIZE + 2] = {MF_ULTRALIGHT_CMD_WRITE_PAGE, page}; + memcpy(&write_page_cmd[2], data->data, MF_ULTRALIGHT_PAGE_SIZE); + bit_buffer_copy_bytes(instance->tx_buffer, write_page_cmd, sizeof(write_page_cmd)); error = nfca_poller_send_standart_frame( instance->nfca_poller, - buff->tx_data, - buff->tx_bits, - buff->rx_data, - buff->rx_data_size, - &buff->rx_bits, + instance->tx_buffer, + instance->rx_buffer, MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); if(error != NfcaErrorWrongCrc) { ret = mf_ultralight_process_error(error); break; } - if(buff->rx_bits != 4) { + if(bit_buffer_get_size(instance->rx_buffer) != 4) { ret = MfUltralightErrorProtocol; break; } - if(buff->rx_data[0] != MF_ULTRALIGHT_CMD_ACK) { + if(!bit_buffer_starts_with_byte(instance->rx_buffer, MF_ULTRALIGHT_CMD_ACK)) { ret = MfUltralightErrorProtocol; break; } - memcpy(&instance->data->page[page], buff->rx_data, MF_ULTRALIGHT_PAGE_SIZE); } while(false); return ret; @@ -352,30 +325,28 @@ MfUltralightError mf_ultralight_poller_async_write_page( MfUltralightError mf_ultralight_poller_async_read_version( MfUltralightPoller* instance, MfUltralightVersion* data) { - NfcPollerBuffer* buff = instance->buffer; - buff->tx_data[0] = MF_ULTRALIGHT_CMD_GET_VERSION; - buff->tx_bits = 8; - MfUltralightError ret = MfUltralightErrorNone; NfcaError error = NfcaErrorNone; + do { + const uint8_t get_version_cmd = MF_ULTRALIGHT_CMD_GET_VERSION; + bit_buffer_copy_bytes(instance->tx_buffer, &get_version_cmd, sizeof(get_version_cmd)); error = nfca_poller_send_standart_frame( instance->nfca_poller, - buff->tx_data, - buff->tx_bits, - buff->rx_data, - buff->rx_data_size, - &buff->rx_bits, + instance->tx_buffer, + instance->rx_buffer, MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); if(error != NfcaErrorNone) { ret = mf_ultralight_process_error(error); break; } - if(buff->rx_bits != sizeof(MfUltralightVersion) * 8) { + if(bit_buffer_get_size_bytes(instance->rx_buffer) != sizeof(MfUltralightVersion)) { + FURI_LOG_I( + TAG, "Read Version failed: %d", bit_buffer_get_size_bytes(instance->rx_buffer)); ret = MfUltralightErrorProtocol; break; } - memcpy(data, buff->rx_data, sizeof(MfUltralightVersion)); + bit_buffer_write_bytes(instance->rx_buffer, data, sizeof(MfUltralightVersion)); } while(false); return ret; @@ -384,31 +355,26 @@ MfUltralightError mf_ultralight_poller_async_read_version( MfUltralightError mf_ultralight_poller_async_read_signature( MfUltralightPoller* instance, MfUltralightSignature* data) { - NfcPollerBuffer* buff = instance->buffer; - buff->tx_data[0] = MF_ULTRALIGTH_CMD_READ_SIG; - buff->rx_data[1] = 0x00; - buff->tx_bits = 16; - MfUltralightError ret = MfUltralightErrorNone; NfcaError error = NfcaErrorNone; + do { + const uint8_t read_signature_cmd[2] = {MF_ULTRALIGTH_CMD_READ_SIG, 0x00}; + bit_buffer_copy_bytes(instance->tx_buffer, read_signature_cmd, sizeof(read_signature_cmd)); error = nfca_poller_send_standart_frame( instance->nfca_poller, - buff->tx_data, - buff->tx_bits, - buff->rx_data, - buff->rx_data_size, - &buff->rx_bits, + instance->tx_buffer, + instance->rx_buffer, MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); if(error != NfcaErrorNone) { ret = mf_ultralight_process_error(error); break; } - if(buff->rx_bits != sizeof(MfUltralightSignature) * 8) { + if(bit_buffer_get_size_bytes(instance->rx_buffer) != sizeof(MfUltralightSignature)) { ret = MfUltralightErrorProtocol; break; } - memcpy(data, buff->rx_data, sizeof(MfUltralightSignature)); + bit_buffer_write_bytes(instance->rx_buffer, data, sizeof(MfUltralightSignature)); } while(false); return ret; @@ -418,31 +384,26 @@ MfUltralightError mf_ultralight_poller_async_read_counter( MfUltralightPoller* instance, uint8_t counter_num, MfUltralightCounter* data) { - NfcPollerBuffer* buff = instance->buffer; - buff->tx_data[0] = MF_ULTRALIGHT_CMD_READ_CNT; - buff->tx_data[1] = counter_num; - buff->tx_bits = 2 * 8; - MfUltralightError ret = MfUltralightErrorNone; NfcaError error = NfcaErrorNone; + do { + uint8_t read_counter_cmd[2] = {MF_ULTRALIGHT_CMD_READ_CNT, counter_num}; + bit_buffer_copy_bytes(instance->tx_buffer, read_counter_cmd, sizeof(read_counter_cmd)); error = nfca_poller_send_standart_frame( instance->nfca_poller, - buff->tx_data, - buff->tx_bits, - buff->rx_data, - buff->rx_data_size, - &buff->rx_bits, + instance->tx_buffer, + instance->rx_buffer, MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); if(error != NfcaErrorNone) { ret = mf_ultralight_process_error(error); break; } - if(buff->rx_bits != 3 * 8) { + if(bit_buffer_get_size_bytes(instance->rx_buffer) != MF_ULTRALIGHT_COUNTER_SIZE) { ret = MfUltralightErrorProtocol; break; } - memcpy(data, buff->rx_data, MF_ULTRALIGHT_COUNTER_SIZE); + bit_buffer_write_bytes(instance->rx_buffer, data->data, MF_ULTRALIGHT_COUNTER_SIZE); } while(false); return ret; @@ -452,31 +413,26 @@ MfUltralightError mf_ultralight_poller_async_read_tearing_flag( MfUltralightPoller* instance, uint8_t tearing_falg_num, MfUltralightTearingFlag* data) { - NfcPollerBuffer* buff = instance->buffer; - buff->tx_data[0] = MF_ULTRALIGHT_CMD_CHECK_TEARING; - buff->tx_data[1] = tearing_falg_num; - buff->tx_bits = 2 * 8; - MfUltralightError ret = MfUltralightErrorNone; NfcaError error = NfcaErrorNone; + do { + uint8_t check_tearing_cmd[2] = {MF_ULTRALIGHT_CMD_CHECK_TEARING, tearing_falg_num}; + bit_buffer_copy_bytes(instance->tx_buffer, check_tearing_cmd, sizeof(check_tearing_cmd)); error = nfca_poller_send_standart_frame( instance->nfca_poller, - buff->tx_data, - buff->tx_bits, - buff->rx_data, - buff->rx_data_size, - &buff->rx_bits, + instance->tx_buffer, + instance->rx_buffer, MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); if(error != NfcaErrorNone) { ret = mf_ultralight_process_error(error); break; } - if(buff->rx_bits != sizeof(MfUltralightTearingFlag) * 8) { + if(bit_buffer_get_size_bytes(instance->rx_buffer) != sizeof(MfUltralightTearingFlag)) { ret = MfUltralightErrorProtocol; break; } - memcpy(data, buff->rx_data, MF_ULTRALIGHT_TEARING_FLAG_SIZE); + bit_buffer_write_bytes(instance->rx_buffer, data, sizeof(MfUltralightTearingFlag)); } while(false); return ret; diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h index fe1606e8450e..2eb9bc5c2ece 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h @@ -2,7 +2,6 @@ #include "mf_ultralight_poller.h" #include -#include #include #define MF_ULTRALIGHT_POLLER_STANDART_FWT_FC (60000) @@ -68,7 +67,8 @@ struct MfUltralightPoller { NfcaPoller* nfca_poller; MfUltralightPollerSessionState session_state; MfUltralightPollerState state; - NfcPollerBuffer* buffer; + BitBuffer* tx_buffer; + BitBuffer* rx_buffer; MfUltralightData* data; MfUltralightPollerCallback callback; MfUltralightPollerAuthContext auth_context; diff --git a/lib/nfc/protocols/nfca/nfca.c b/lib/nfc/protocols/nfca/nfca.c index f075573f2edb..938c9153da45 100644 --- a/lib/nfc/protocols/nfca/nfca.c +++ b/lib/nfc/protocols/nfca/nfca.c @@ -87,43 +87,6 @@ const uint8_t* nfca_get_uid(const NfcaData* data, size_t* uid_len) { return data->uid; } -uint16_t nfca_get_crc(uint8_t* buff, uint16_t len) { - furi_assert(buff); - - uint16_t crc = NFCA_CRC_INIT; - uint8_t byte = 0; - - for(uint8_t i = 0; i < len; i++) { - byte = buff[i]; - byte ^= (uint8_t)(crc & 0xff); - byte ^= byte << 4; - crc = (crc >> 8) ^ (((uint16_t)byte) << 8) ^ (((uint16_t)byte) << 3) ^ - (((uint16_t)byte) >> 4); - } - - return crc; -} - -void nfca_append_crc(uint8_t* buff, uint16_t len) { - furi_assert(buff); - - uint16_t crc = nfca_get_crc(buff, len); - buff[len] = (uint8_t)crc; - buff[len + 1] = (uint8_t)(crc >> 8); -} - -bool nfca_check_crc(uint8_t* buff, uint16_t len) { - bool crc_ok = false; - - if(len > 2) { - uint16_t crc_calc = nfca_get_crc(buff, len - 2); - uint16_t crc_received = (buff[len - 1] << 8) | buff[len - 2]; - crc_ok = (crc_calc == crc_received); - } - - return crc_ok; -} - bool nfca_load_data(NfcaData* data, FlipperFormat* ff, uint32_t version) { furi_assert(data); @@ -171,3 +134,73 @@ bool nfca_save_data(const NfcaData* data, FlipperFormat* ff, uint32_t version) { return saved; } + +static uint16_t nfca_get_crc(const uint8_t* buff, uint16_t len) { + furi_assert(buff); + furi_assert(len); + + uint16_t crc = NFCA_CRC_INIT; + uint8_t byte = 0; + + for(uint8_t i = 0; i < len; i++) { + byte = buff[i]; + byte ^= (uint8_t)(crc & 0xff); + byte ^= byte << 4; + crc = (crc >> 8) ^ (((uint16_t)byte) << 8) ^ (((uint16_t)byte) << 3) ^ + (((uint16_t)byte) >> 4); + } + + return crc; +} + +uint32_t nfca_get_cuid(NfcaData* nfca_data) { + furi_assert(nfca_data); + + uint32_t cuid = 0; + uint8_t* cuid_start = nfca_data->uid; + if(nfca_data->uid_len == 7) { + cuid_start = &nfca_data->uid[3]; + } + cuid = (cuid_start[0] << 24) | (cuid_start[1] << 16) | (cuid_start[2] << 8) | (cuid_start[3]); + + return cuid; +} + +void nfca_append_crc(BitBuffer* buffer) { + furi_assert(buffer); + + const uint8_t* data = bit_buffer_get_data(buffer); + size_t bytes = bit_buffer_get_size_bytes(buffer); + + uint16_t crc = nfca_get_crc(data, bytes); + uint8_t crc_bytes[2] = {(uint8_t)crc, (uint8_t)(crc >> 8)}; + bit_buffer_append_bytes(buffer, crc_bytes, sizeof(crc_bytes)); +} + +bool nfca_check_crc(const BitBuffer* buf) { + furi_assert(buf); + + bool crc_ok = false; + do { + const uint8_t* data = bit_buffer_get_data(buf); + size_t bytes = bit_buffer_get_size_bytes(buf); + if(bytes < 3) break; + + uint16_t crc_calc = nfca_get_crc(data, bytes - 2); + uint8_t crc_start = bit_buffer_get_byte(buf, bytes - 2); + uint8_t crc_end = bit_buffer_get_byte(buf, bytes - 1); + uint16_t crc_received = (crc_end << 8) | crc_start; + crc_ok = (crc_calc == crc_received); + } while(false); + + return crc_ok; +} + +void nfca_trim_crc(BitBuffer* buf) { + furi_assert(buf); + + size_t bytes = bit_buffer_get_size_bytes(buf); + furi_assert(bytes > 2); + + bit_buffer_set_size_bytes(buf, bytes - 2); +} diff --git a/lib/nfc/protocols/nfca/nfca.h b/lib/nfc/protocols/nfca/nfca.h index 51b456e51e0f..ac17a4b67058 100644 --- a/lib/nfc/protocols/nfca/nfca.h +++ b/lib/nfc/protocols/nfca/nfca.h @@ -1,8 +1,6 @@ #pragma once -#include -#include - +#include #include #ifdef __cplusplus @@ -88,11 +86,13 @@ const char* nfca_get_name(const NfcaData* data, NfcProtocolNameType name_type); const uint8_t* nfca_get_uid(const NfcaData* data, size_t* uid_len); -uint16_t nfca_get_crc(uint8_t* buff, uint16_t len); +uint32_t nfca_get_cuid(NfcaData* nfca_data); + +void nfca_append_crc(BitBuffer* buffer); -void nfca_append_crc(uint8_t* buff, uint16_t len); +bool nfca_check_crc(const BitBuffer* buf); -bool nfca_check_crc(uint8_t* buff, uint16_t len); +void nfca_trim_crc(BitBuffer* buf); // TODO: Decide where should these methods go (*_i file?) bool nfca_load_data(NfcaData* data, FlipperFormat* ff, uint32_t version); diff --git a/lib/nfc/protocols/nfca/nfca_listener.c b/lib/nfc/protocols/nfca/nfca_listener.c index be77b10f8956..add21c293b9c 100644 --- a/lib/nfc/protocols/nfca/nfca_listener.c +++ b/lib/nfc/protocols/nfca/nfca_listener.c @@ -18,8 +18,7 @@ struct NfcaListener { NfcaListenerState state; NfcaListenerEventCallback callback; - uint8_t* tx_data; - uint16_t tx_bits; + BitBuffer* tx_buffer; void* context; }; @@ -40,8 +39,7 @@ static NfcaError nfca_listener_process_nfc_error(NfcError error) { static void nfca_listener_config(NfcaListener* instance) { furi_assert(instance); - instance->tx_data = malloc(NFCA_LISTENER_MAX_BUFFER_SIZE); - instance->tx_bits = 0; + instance->tx_buffer = bit_buffer_alloc(NFCA_LISTENER_MAX_BUFFER_SIZE); nfc_set_fdt_listen_fc(instance->nfc, NFCA_FDT_LISTEN_FC); nfc_config(instance->nfc, NfcModeNfcaListener); @@ -55,20 +53,20 @@ static void nfca_listener_config(NfcaListener* instance) { static void nfca_listener_reset(NfcaListener* instance) { furi_assert(instance); - furi_assert(instance->tx_data); + furi_assert(instance->tx_buffer); - free(instance->tx_data); - instance->tx_bits = 0; + bit_buffer_free(instance->tx_buffer); + instance->tx_buffer = NULL; } -static bool nfca_listener_halt_received(uint8_t* rx_data, uint16_t rx_bits) { +static bool nfca_listener_halt_received(BitBuffer* buf) { bool halt_cmd_received = false; do { - if(rx_bits != 4 * 8) break; - uint16_t rx_bytes = rx_bits / 8; - if(!nfca_check_crc(rx_data, rx_bytes)) break; - if(!((rx_data[0] == 0x50) && (rx_data[1] == 0x00))) break; + if(bit_buffer_get_size_bytes(buf) != 4) break; + if(!nfca_check_crc(buf)) break; + if(bit_buffer_get_byte(buf, 0) != 0x50) break; + if(bit_buffer_get_byte(buf, 1) != 0x00) break; halt_cmd_received = true; } while(false); @@ -92,7 +90,7 @@ static NfcCommand nfca_listener_event_handler(NfcEvent event, void* context) { } else if(event_type == NfcEventTypeListenerActivated) { instance->state = NfcaListenerStateActive; } else if((event_type == NfcEventTypeRxEnd) && (instance->state == NfcaListenerStateActive)) { - if(nfca_listener_halt_received(event.data.rx_data, event.data.rx_bits)) { + if(nfca_listener_halt_received(event.data.buffer)) { // TODO rework with commands nfca_listener_sleep(instance); instance->state = NfcaListenerStateIdle; @@ -101,14 +99,14 @@ static NfcCommand nfca_listener_event_handler(NfcEvent event, void* context) { instance->callback(nfca_listener_event, instance->context); } } else if(instance->callback) { - nfca_listener_event.data.rx_data = event.data.rx_data; - if(nfca_check_crc(event.data.rx_data, event.data.rx_bits / 8)) { + if(nfca_check_crc(event.data.buffer)) { nfca_listener_event.type = NfcaListenerEventTypeReceivedStandartFrame; - nfca_listener_event.data.rx_bits = event.data.rx_bits - 16; + size_t bytes = bit_buffer_get_size_bytes(event.data.buffer); + bit_buffer_set_size_bytes(event.data.buffer, bytes - 2); } else { nfca_listener_event.type = NfcaListenerEventTypeReceivedData; - nfca_listener_event.data.rx_bits = event.data.rx_bits; } + nfca_listener_event.data.buffer = event.data.buffer; if(instance->callback) { instance->callback(nfca_listener_event, instance->context); } @@ -186,37 +184,31 @@ NfcaError nfca_listener_sleep(NfcaListener* instance) { return nfca_listener_process_nfc_error(error); } -NfcaError nfca_listener_tx(NfcaListener* instance, uint8_t* tx_data, uint16_t tx_bits) { +NfcaError nfca_listener_tx(NfcaListener* instance, const BitBuffer* tx_buffer) { furi_assert(instance); - furi_assert(tx_data); + furi_assert(tx_buffer); NfcaError ret = NfcaErrorNone; - NfcError error = nfc_listener_tx(instance->nfc, tx_data, tx_bits); + NfcError error = nfc_listener_tx(instance->nfc, tx_buffer); if(error != NfcErrorNone) { FURI_LOG_W(TAG, "Tx error: %d", error); ret = nfca_listener_process_nfc_error(error); } + return ret; } -NfcaError - nfca_listener_send_standart_frame(NfcaListener* instance, uint8_t* tx_data, uint16_t tx_bits) { +NfcaError nfca_listener_send_standart_frame(NfcaListener* instance, const BitBuffer* tx_buffer) { furi_assert(instance); - furi_assert(tx_data); - furi_assert(instance->tx_data); + furi_assert(tx_buffer); + furi_assert(instance->tx_buffer); NfcaError ret = NfcaErrorNone; - uint16_t tx_bytes = tx_bits / 8; - do { - if(tx_bytes > NFCA_LISTENER_MAX_BUFFER_SIZE - 2) { - ret = NfcaErrorBufferOverflow; - break; - } - memcpy(instance->tx_data, tx_data, tx_bytes); - nfca_append_crc(instance->tx_data, tx_bytes); + bit_buffer_copy(instance->tx_buffer, tx_buffer); + nfca_append_crc(instance->tx_buffer); - NfcError error = nfc_listener_tx(instance->nfc, instance->tx_data, tx_bits + 16); + NfcError error = nfc_listener_tx(instance->nfc, instance->tx_buffer); if(error != NfcErrorNone) { FURI_LOG_W(TAG, "Tx error: %d", error); ret = nfca_listener_process_nfc_error(error); diff --git a/lib/nfc/protocols/nfca/nfca_listener.h b/lib/nfc/protocols/nfca/nfca_listener.h index 754be1eccb34..2579aa5b43a2 100644 --- a/lib/nfc/protocols/nfca/nfca_listener.h +++ b/lib/nfc/protocols/nfca/nfca_listener.h @@ -21,8 +21,7 @@ typedef enum { } NfcaListenerEventType; typedef struct { - uint8_t* rx_data; - uint16_t rx_bits; + BitBuffer* buffer; } NfcaListenerEventData; typedef struct { @@ -55,10 +54,9 @@ NfcaError nfca_listener_stop(NfcaListener* instance); NfcaError nfca_listener_sleep(NfcaListener* instance); -NfcaError nfca_listener_tx(NfcaListener* instance, uint8_t* tx_data, uint16_t tx_bits); +NfcaError nfca_listener_tx(NfcaListener* instance, const BitBuffer* tx_buffer); -NfcaError - nfca_listener_send_standart_frame(NfcaListener* instance, uint8_t* tx_data, uint16_t tx_bits); +NfcaError nfca_listener_send_standart_frame(NfcaListener* instance, const BitBuffer* tx_buffer); #ifdef __cplusplus } diff --git a/lib/nfc/protocols/nfca/nfca_poller.c b/lib/nfc/protocols/nfca/nfca_poller.c index 46ce19e3a7a1..070f845b6707 100644 --- a/lib/nfc/protocols/nfca/nfca_poller.c +++ b/lib/nfc/protocols/nfca/nfca_poller.c @@ -126,7 +126,8 @@ NfcaError nfca_poller_stop(NfcaPoller* instance) { } // Check that data is freed - furi_assert(instance->buff == NULL); + furi_assert(instance->tx_buffer == NULL); + furi_assert(instance->rx_buffer == NULL); nfca_free(instance->data); diff --git a/lib/nfc/protocols/nfca/nfca_poller_i.c b/lib/nfc/protocols/nfca/nfca_poller_i.c index 057a3eadab77..20753d16e474 100644 --- a/lib/nfc/protocols/nfca/nfca_poller_i.c +++ b/lib/nfc/protocols/nfca/nfca_poller_i.c @@ -28,68 +28,34 @@ static NfcaError nfca_poller_prepare_trx(NfcaPoller* instance) { static NfcaError nfca_poller_standart_frame_exchange( NfcaPoller* instance, - uint8_t* tx_data, - uint16_t tx_bits, - uint8_t* rx_data, - uint16_t rx_data_size, - uint16_t* rx_bits, + const BitBuffer* tx_buffer, + BitBuffer* rx_buffer, uint32_t fwt) { furi_assert(instance); - furi_assert(tx_data); - furi_assert(rx_data); - furi_assert(rx_bits); - furi_assert(tx_bits >= 8); - furi_assert(instance->buff); - - NfcPollerBuffer* buff = instance->buff; - uint16_t tx_bytes = tx_bits / 8; - furi_assert(tx_bytes <= buff->tx_data_size - 2); - - memcpy(buff->tx_data, tx_data, tx_bytes); - nfca_append_crc(buff->tx_data, tx_bytes); + furi_assert(tx_buffer); + furi_assert(rx_buffer); + + uint16_t tx_bytes = bit_buffer_get_size_bytes(tx_buffer); + furi_assert(tx_bytes <= bit_buffer_get_capacity_bytes(instance->tx_buffer) - 2); + + bit_buffer_copy(instance->tx_buffer, tx_buffer); + nfca_append_crc(instance->tx_buffer); NfcaError ret = NfcaErrorNone; do { - NfcError error = nfc_trx( - instance->nfc, - buff->tx_data, - tx_bits + 16, - buff->rx_data, - buff->rx_data_size, - &buff->rx_bits, - fwt); + NfcError error = nfc_trx(instance->nfc, instance->tx_buffer, instance->rx_buffer, fwt); if(error != NfcErrorNone) { ret = nfca_poller_process_error(error); break; } - if(buff->rx_bits < 8) { - rx_data[0] = buff->rx_data[0]; - *rx_bits = buff->rx_bits; - ret = NfcaErrorWrongCrc; - break; - } else if(buff->rx_bits < 3 * 8) { - uint16_t rx_bytes = buff->rx_bits / 8; - memcpy(rx_data, buff->rx_data, rx_bytes); - *rx_bits = buff->rx_bits; + + bit_buffer_copy(rx_buffer, instance->rx_buffer); + if(!nfca_check_crc(instance->rx_buffer)) { ret = NfcaErrorWrongCrc; break; - } else { - uint16_t rx_bytes = buff->rx_bits / 8; - if(rx_bytes - 2 > rx_data_size) { - ret = NfcaErrorBufferOverflow; - break; - } - - if(!nfca_check_crc(buff->rx_data, rx_bytes)) { - memcpy(rx_data, buff->rx_data, rx_bytes); - *rx_bits = rx_bytes * 8; - ret = NfcaErrorWrongCrc; - break; - } - - memcpy(rx_data, buff->rx_data, rx_bytes - 2); - *rx_bits = (rx_bytes - 2) * 8; } + + nfca_trim_crc(rx_buffer); } while(false); return ret; @@ -97,9 +63,11 @@ static NfcaError nfca_poller_standart_frame_exchange( NfcaError nfca_poller_config(NfcaPoller* instance) { furi_assert(instance); + furi_assert(instance->tx_buffer == NULL); + furi_assert(instance->rx_buffer == NULL); - instance->buff = - nfc_poller_buffer_alloc(NFCA_POLLER_MAX_BUFFER_SIZE, NFCA_POLLER_MAX_BUFFER_SIZE); + instance->tx_buffer = bit_buffer_alloc(NFCA_POLLER_MAX_BUFFER_SIZE); + instance->rx_buffer = bit_buffer_alloc(NFCA_POLLER_MAX_BUFFER_SIZE); nfc_config(instance->nfc, NfcModeNfcaPoller); nfc_set_guard_time_us(instance->nfc, NFCA_GUARD_TIME_US); @@ -112,14 +80,20 @@ NfcaError nfca_poller_config(NfcaPoller* instance) { NfcaError nfca_poller_reset(NfcaPoller* instance) { furi_assert(instance); + furi_assert(instance->tx_buffer); + furi_assert(instance->rx_buffer); instance->callback = NULL; instance->context = NULL; memset(&instance->col_res, 0, sizeof(NfcaPollerColRes)); - instance->state = NfcaPollerStateIdle; - nfc_poller_buffer_free(instance->buff); - instance->buff = NULL; + + bit_buffer_free(instance->tx_buffer); + instance->tx_buffer = NULL; + bit_buffer_free(instance->rx_buffer); + instance->rx_buffer = NULL; + instance->config_state = NfcaPollerConfigStateIdle; + instance->state = NfcaPollerStateIdle; return NfcaErrorNone; } @@ -128,22 +102,16 @@ NfcaError nfca_poller_check_presence(NfcaPoller* instance) { furi_assert(instance); furi_assert(instance->nfc); - uint16_t rx_bits = 0; NfcError error = NfcErrorNone; NfcaError ret = NfcaErrorNone; do { error = nfc_iso13444a_short_frame( - instance->nfc, - NfcIso14443aShortFrameSensReq, - (uint8_t*)&instance->col_res.sens_resp, - sizeof(instance->col_res.sens_resp), - &rx_bits, - NFCA_FDT_LISTEN_FC); + instance->nfc, NfcIso14443aShortFrameSensReq, instance->rx_buffer, NFCA_FDT_LISTEN_FC); if(error != NfcErrorNone) { ret = nfca_poller_process_error(error); break; } - if(rx_bits != 8 * sizeof(instance->col_res.sens_resp)) { + if(bit_buffer_get_size_bytes(instance->rx_buffer) != sizeof(instance->col_res.sens_resp)) { ret = NfcaErrorCommunication; break; } @@ -155,21 +123,14 @@ NfcaError nfca_poller_check_presence(NfcaPoller* instance) { NfcaError nfca_poller_halt(NfcaPoller* instance) { furi_assert(instance); furi_assert(instance->nfc); - furi_assert(instance->buff); + furi_assert(instance->tx_buffer); - NfcPollerBuffer* buff = instance->buff; - buff->tx_data[0] = 0x50; - buff->tx_data[1] = 0x00; - buff->tx_bits = 16; + uint8_t halt_cmd[2] = {0x50, 0x00}; + bit_buffer_copy_bytes(instance->tx_buffer, halt_cmd, sizeof(halt_cmd)); nfca_poller_standart_frame_exchange( - instance, - buff->tx_data, - buff->tx_bits, - buff->rx_data, - buff->rx_data_size, - &buff->rx_bits, - NFCA_FDT_LISTEN_FC); + instance, instance->tx_buffer, instance->rx_buffer, NFCA_FDT_LISTEN_FC); + instance->state = NfcaPollerStateIdle; return NfcaErrorNone; } @@ -177,10 +138,14 @@ NfcaError nfca_poller_halt(NfcaPoller* instance) { NfcaError nfca_poller_async_activate(NfcaPoller* instance, NfcaData* nfca_data) { furi_assert(instance); furi_assert(instance->nfc); + furi_assert(instance->tx_buffer); + furi_assert(instance->rx_buffer); // Reset Nfca poller state memset(&instance->col_res, 0, sizeof(instance->col_res)); memset(instance->data, 0, sizeof(NfcaData)); + bit_buffer_reset(instance->tx_buffer); + bit_buffer_reset(instance->rx_buffer); // Halt if necessary if(instance->state != NfcaPollerStateIdle) { @@ -190,27 +155,24 @@ NfcaError nfca_poller_async_activate(NfcaPoller* instance, NfcaData* nfca_data) NfcError error = NfcErrorNone; NfcaError ret = NfcaErrorNone; - uint16_t rx_bits = 0; - uint16_t tx_bits = 0; bool activated = false; do { error = nfc_iso13444a_short_frame( - instance->nfc, - NfcIso14443aShortFrameSensReq, - (uint8_t*)&instance->col_res.sens_resp, - sizeof(instance->col_res.sens_resp), - &rx_bits, - NFCA_FDT_LISTEN_FC); + instance->nfc, NfcIso14443aShortFrameSensReq, instance->rx_buffer, NFCA_FDT_LISTEN_FC); if(error != NfcErrorNone) { ret = NfcaErrorNotPresent; break; } - if(rx_bits != 8 * sizeof(instance->col_res.sens_resp)) { - FURI_LOG_W(TAG, "Wrong response: %d", rx_bits); + if(bit_buffer_get_size_bytes(instance->rx_buffer) != sizeof(instance->col_res.sens_resp)) { + FURI_LOG_W(TAG, "Wrong sens response size"); ret = NfcaErrorCommunication; break; } + bit_buffer_write_bytes( + instance->rx_buffer, + &instance->col_res.sens_resp, + sizeof(instance->col_res.sens_resp)); memcpy( instance->data->atqa, &instance->col_res.sens_resp, @@ -222,31 +184,27 @@ NfcaError nfca_poller_async_activate(NfcaPoller* instance, NfcaData* nfca_data) while(instance->state == NfcaPollerStateColResInProgress) { if(instance->col_res.state == NfcaPollerColResStateStateNewCascade) { - instance->col_res.sdd_req.sel_cmd = - NFCA_POLLER_SEL_CMD(instance->col_res.cascade_level); - instance->col_res.sdd_req.sel_par = NFCA_POLLER_SEL_PAR(2, 0); - tx_bits = 16; + bit_buffer_set_size_bytes(instance->tx_buffer, 2); + bit_buffer_set_byte( + instance->tx_buffer, 0, NFCA_POLLER_SEL_CMD(instance->col_res.cascade_level)); + bit_buffer_set_byte(instance->tx_buffer, 1, NFCA_POLLER_SEL_PAR(2, 0)); error = nfc_iso13444a_sdd_frame( - instance->nfc, - (uint8_t*)&instance->col_res.sdd_req, - tx_bits, - (uint8_t*)&instance->col_res.sdd_resp, - sizeof(instance->col_res.sdd_resp), - &rx_bits, - NFCA_FDT_LISTEN_FC); + instance->nfc, instance->tx_buffer, instance->rx_buffer, NFCA_FDT_LISTEN_FC); if(error != NfcErrorNone) { FURI_LOG_E(TAG, "Sdd request failed: %d", error); instance->state = NfcaPollerStateColResFailed; ret = NfcaErrorColResFailed; break; } - if(rx_bits != 5 * 8) { - FURI_LOG_E(TAG, "Sdd response wrong length: %d bits", rx_bits); + if(bit_buffer_get_size_bytes(instance->rx_buffer) != 5) { + FURI_LOG_E(TAG, "Sdd response wrong length"); instance->state = NfcaPollerStateColResFailed; ret = NfcaErrorColResFailed; break; } // TODO BCC check here + bit_buffer_write_bytes( + instance->rx_buffer, &instance->col_res.sdd_resp, sizeof(NfcaSddResp)); instance->col_res.state = NfcaPollerColResStateStateSelectCascade; } else if(instance->col_res.state == NfcaPollerColResStateStateSelectCascade) { instance->col_res.sel_req.sel_cmd = @@ -257,28 +215,29 @@ NfcaError nfca_poller_async_activate(NfcaPoller* instance, NfcaData* nfca_data) instance->col_res.sdd_resp.nfcid, sizeof(instance->col_res.sdd_resp.nfcid)); instance->col_res.sel_req.bcc = instance->col_res.sdd_resp.bss; - // Todo remove after Nfc handles timings - furi_delay_ms(10); - ret = nfca_poller_send_standart_frame( - instance, + bit_buffer_copy_bytes( + instance->tx_buffer, (uint8_t*)&instance->col_res.sel_req, - 8 * sizeof(instance->col_res.sel_req), - (uint8_t*)&instance->col_res.sel_resp, - sizeof(NfcaSelResp), - &rx_bits, - NFCA_FDT_LISTEN_FC); + sizeof(instance->col_res.sel_req)); + ret = nfca_poller_send_standart_frame( + instance, instance->tx_buffer, instance->rx_buffer, NFCA_FDT_LISTEN_FC); if(ret != NfcaErrorNone) { - FURI_LOG_E(TAG, "Sel request failed: %d", error); + FURI_LOG_E(TAG, "Sel request failed: %d", ret); instance->state = NfcaPollerStateColResFailed; ret = NfcaErrorColResFailed; break; } - if(rx_bits != 8 * sizeof(instance->col_res.sel_resp)) { - FURI_LOG_E(TAG, "Sel response wrong length: %d bits", rx_bits); + if(bit_buffer_get_size_bytes(instance->rx_buffer) != + sizeof(instance->col_res.sel_resp)) { + FURI_LOG_E(TAG, "Sel response wrong length"); instance->state = NfcaPollerStateColResFailed; ret = NfcaErrorColResFailed; break; } + bit_buffer_write_bytes( + instance->rx_buffer, + &instance->col_res.sel_resp, + sizeof(instance->col_res.sel_resp)); FURI_LOG_T(TAG, "Sel resp: %02X", instance->col_res.sel_resp.sak); if(instance->col_res.sel_req.nfcid[0] == NFCA_POLLER_SDD_CL) { // Copy part of UID @@ -313,107 +272,27 @@ NfcaError nfca_poller_async_activate(NfcaPoller* instance, NfcaData* nfca_data) return ret; } -static uint16_t - nfca_data_to_bitstream(uint8_t* data, uint8_t* parity, uint16_t bits, uint8_t* bitstream) { - furi_assert(data); - furi_assert(parity); - furi_assert(bitstream); - - uint8_t next_par_bit = 0; - uint16_t curr_bit_pos = 0; - uint16_t bytes = bits / 8; - - for(size_t i = 0; i < bytes; i++) { - next_par_bit = FURI_BIT(parity[i / 8], 7 - (i % 8)); - if(curr_bit_pos % 8 == 0) { - bitstream[curr_bit_pos / 8] = data[i]; - curr_bit_pos += 8; - bitstream[curr_bit_pos / 8] = next_par_bit; - curr_bit_pos++; - } else { - bitstream[curr_bit_pos / 8] |= data[i] << (curr_bit_pos % 8); - bitstream[curr_bit_pos / 8 + 1] = data[i] >> (8 - curr_bit_pos % 8); - bitstream[curr_bit_pos / 8 + 1] |= next_par_bit << (curr_bit_pos % 8); - curr_bit_pos += 9; - } - } - return curr_bit_pos; -} - -static uint16_t - nfca_bitstream_to_data(uint8_t* bitstream, uint16_t bits, uint8_t* data, uint8_t* parity) { - uint32_t data_bits = 0; - uint8_t curr_byte = 0; - uint16_t bit_processed = 0; - - if(bits < 8) { - data[0] = bitstream[0]; - data_bits = bits; - } else if(bits % 9 != 0) { - data_bits = 0; - } else { - memset(parity, 0, bits / 9); - while(bit_processed < bits) { - data[curr_byte] = bitstream[bit_processed / 8] >> (bit_processed % 8); - data[curr_byte] |= bitstream[bit_processed / 8 + 1] << (8 - bit_processed % 8); - parity[curr_byte / 8] |= FURI_BIT(bitstream[bit_processed / 8 + 1], bit_processed % 8) - << (7 - curr_byte % 8); - bit_processed += 9; - curr_byte++; - } - data_bits = curr_byte * 8; - } - - return data_bits; -} - NfcaError nfca_poller_txrx_custom_parity( NfcaPoller* instance, - uint8_t* tx_data, - uint8_t* tx_parity, - uint16_t tx_bits, - uint8_t* rx_data, - uint8_t* rx_parity, - uint16_t rx_buff_size, - uint16_t* rx_bits, + const BitBuffer* tx_buffer, + BitBuffer* rx_buffer, uint32_t fwt) { furi_assert(instance); - furi_assert(tx_data); - furi_assert(tx_parity); - furi_assert(rx_data); - furi_assert(rx_parity); - furi_assert(rx_bits); + furi_assert(tx_buffer); + furi_assert(rx_buffer); NfcaError ret = NfcaErrorNone; NfcError error = NfcErrorNone; - NfcPollerBuffer* buff = instance->buff; do { ret = nfca_poller_prepare_trx(instance); if(ret != NfcaErrorNone) break; - buff->tx_bits = nfca_data_to_bitstream(tx_data, tx_parity, tx_bits, buff->tx_data); - - error = nfc_trx_custom_parity( - instance->nfc, - buff->tx_data, - buff->tx_bits, - buff->rx_data, - buff->rx_data_size, - &buff->rx_bits, - fwt); + error = nfc_trx_custom_parity(instance->nfc, tx_buffer, rx_buffer, fwt); if(error != NfcErrorNone) { ret = nfca_poller_process_error(error); break; } - - uint16_t rx_bytes = buff->rx_bits / 9; - if(rx_buff_size < rx_bytes) { - ret = NfcaErrorBufferOverflow; - break; - } - - *rx_bits = nfca_bitstream_to_data(buff->rx_data, buff->rx_bits, rx_data, rx_parity); } while(false); return ret; @@ -421,16 +300,12 @@ NfcaError nfca_poller_txrx_custom_parity( NfcaError nfca_poller_txrx( NfcaPoller* instance, - uint8_t* tx_buff, - uint16_t tx_bits, - uint8_t* rx_buff, - uint16_t rx_buff_size, - uint16_t* rx_bits, + const BitBuffer* tx_buffer, + BitBuffer* rx_buffer, uint32_t fwt) { furi_assert(instance); - furi_assert(tx_buff); - furi_assert(rx_buff); - furi_assert(rx_bits); + furi_assert(tx_buffer); + furi_assert(rx_buffer); NfcaError ret = NfcaErrorNone; NfcError error = NfcErrorNone; @@ -439,7 +314,7 @@ NfcaError nfca_poller_txrx( ret = nfca_poller_prepare_trx(instance); if(ret != NfcaErrorNone) break; - error = nfc_trx(instance->nfc, tx_buff, tx_bits, rx_buff, rx_buff_size, rx_bits, fwt); + error = nfc_trx(instance->nfc, tx_buffer, rx_buffer, fwt); if(error != NfcErrorNone) { ret = nfca_poller_process_error(error); break; @@ -451,17 +326,12 @@ NfcaError nfca_poller_txrx( NfcaError nfca_poller_send_standart_frame( NfcaPoller* instance, - uint8_t* tx_data, - uint16_t tx_bits, - uint8_t* rx_data, - uint16_t rx_data_size, - uint16_t* rx_bits, + const BitBuffer* tx_buffer, + BitBuffer* rx_buffer, uint32_t fwt) { furi_assert(instance); - furi_assert(tx_data); - furi_assert(rx_data); - furi_assert(rx_bits); - furi_assert(tx_bits >= 8); + furi_assert(tx_buffer); + furi_assert(rx_buffer); NfcaError ret = NfcaErrorNone; @@ -469,8 +339,7 @@ NfcaError nfca_poller_send_standart_frame( ret = nfca_poller_prepare_trx(instance); if(ret != NfcaErrorNone) break; - ret = nfca_poller_standart_frame_exchange( - instance, tx_data, tx_bits, rx_data, rx_data_size, rx_bits, fwt); + ret = nfca_poller_standart_frame_exchange(instance, tx_buffer, rx_buffer, fwt); if(ret != NfcaErrorNone) break; } while(false); diff --git a/lib/nfc/protocols/nfca/nfca_poller_i.h b/lib/nfc/protocols/nfca/nfca_poller_i.h index 8d629f237b28..04c0612e3ef0 100644 --- a/lib/nfc/protocols/nfca/nfca_poller_i.h +++ b/lib/nfc/protocols/nfca/nfca_poller_i.h @@ -3,7 +3,6 @@ #include "nfca_poller.h" #include -#include #ifdef __cplusplus extern "C" { @@ -58,7 +57,8 @@ struct NfcaPoller { NfcaPollerConfigState config_state; NfcaPollerColRes col_res; NfcaData* data; - NfcPollerBuffer* buff; + BitBuffer* tx_buffer; + BitBuffer* rx_buffer; NfcaPollerEventCallback callback; void* context; }; @@ -75,31 +75,20 @@ NfcaError nfca_poller_halt(NfcaPoller* instance); NfcaError nfca_poller_txrx_custom_parity( NfcaPoller* instance, - uint8_t* tx_data, - uint8_t* tx_parity, - uint16_t tx_bits, - uint8_t* rx_data, - uint8_t* rx_parity, - uint16_t rx_buff_size, - uint16_t* rx_bits, + const BitBuffer* tx_buffer, + BitBuffer* rx_buffer, uint32_t fwt); NfcaError nfca_poller_txrx( NfcaPoller* instance, - uint8_t* tx_buff, - uint16_t tx_bits, - uint8_t* rx_buff, - uint16_t rx_buff_size, - uint16_t* rx_bits, + const BitBuffer* tx_buffer, + BitBuffer* rx_buffer, uint32_t fwt); NfcaError nfca_poller_send_standart_frame( NfcaPoller* instance, - uint8_t* tx_data, - uint16_t tx_bits, - uint8_t* rx_data, - uint16_t rx_data_size, - uint16_t* rx_bits, + const BitBuffer* tx_buffer, + BitBuffer* rx_buffer, uint32_t fwt); #ifdef __cplusplus diff --git a/lib/nfc/protocols/nfcb/nfcb_poller.c b/lib/nfc/protocols/nfcb/nfcb_poller.c index fb73c6b749f8..4dc2f72dd26c 100644 --- a/lib/nfc/protocols/nfcb/nfcb_poller.c +++ b/lib/nfc/protocols/nfcb/nfcb_poller.c @@ -1,5 +1,4 @@ #include "nfcb_poller.h" -#include #include @@ -16,7 +15,6 @@ struct NfcbPoller { Nfc* nfc; NfcbPollerState state; NfcbData* data; - NfcPollerBuffer* buff; NfcbPollerEventCallback callback; void* context; }; @@ -76,8 +74,6 @@ NfcbError nfcb_poller_reset(NfcbPoller* instance) { instance->context = NULL; free(instance->data); instance->data = NULL; - nfc_poller_buffer_free(instance->buff); - instance->buff = NULL; return NfcbErrorNone; } @@ -86,8 +82,6 @@ NfcbError nfcb_poller_config(NfcbPoller* instance) { furi_assert(instance); // instance->data = malloc(sizeof(NfcbData)); - // instance->buff = - // nfc_poller_buffer_alloc(NFCB_POLLER_BUFER_MAX_SIZE, NFCB_POLLER_BUFER_MAX_SIZE); nfc_config(instance->nfc, NfcModeNfcbPoller); nfc_set_guard_time_us(instance->nfc, NFCB_GUARD_TIME_US); From 31b818a819a64b26a0682bd9dca70401f697484b Mon Sep 17 00:00:00 2001 From: gornekich Date: Mon, 12 Jun 2023 17:05:19 +0400 Subject: [PATCH 103/149] nfc: move deprycated files to separate folder --- .../external/nfc_magic/lib/magic/magic.h | 2 +- .../external/picopass/views/dict_attack.h | 2 +- applications/main/nfc/application.fam | 16 ++++---- applications/main/nfc/helpers/mf_dict.c | 2 +- applications/main/nfc/nfc_cli.c | 4 +- applications/main/nfc_old/views/dict_attack.h | 2 +- firmware/targets/f7/furi_hal/furi_hal_nfc.h | 2 +- lib/nfc/SConscript | 2 +- .../helpers/mf_classic_dict.c | 0 .../helpers/mf_classic_dict.h | 0 lib/nfc/{ => deprycated}/helpers/mfkey32.c | 3 +- lib/nfc/{ => deprycated}/helpers/mfkey32.h | 2 +- .../{ => deprycated}/helpers/nfc_debug_log.c | 0 .../{ => deprycated}/helpers/nfc_debug_log.h | 0 .../{ => deprycated}/helpers/nfc_debug_pcap.c | 0 .../{ => deprycated}/helpers/nfc_debug_pcap.h | 0 .../{ => deprycated}/helpers/nfc_generators.c | 0 .../{ => deprycated}/helpers/nfc_generators.h | 0 .../helpers/reader_analyzer.c | 4 +- .../helpers/reader_analyzer.h | 2 +- lib/nfc/{ => deprycated}/nfc_device.c | 2 +- lib/nfc/{ => deprycated}/nfc_device.h | 10 ++--- lib/nfc/{ => deprycated}/nfc_types.c | 0 lib/nfc/{ => deprycated}/nfc_types.h | 0 lib/nfc/{ => deprycated}/nfc_worker.c | 0 lib/nfc/{ => deprycated}/nfc_worker.h | 0 lib/nfc/{ => deprycated}/nfc_worker_i.h | 13 +++--- lib/nfc/{ => deprycated}/parsers/all_in_one.c | 2 +- lib/nfc/{ => deprycated}/parsers/all_in_one.h | 0 .../parsers/nfc_supported_card.c | 0 .../parsers/nfc_supported_card.h | 0 .../parsers/plantain_4k_parser.c | 2 +- .../parsers/plantain_4k_parser.h | 0 .../parsers/plantain_parser.c | 2 +- .../parsers/plantain_parser.h | 0 .../parsers/troika_4k_parser.c | 2 +- .../parsers/troika_4k_parser.h | 0 .../{ => deprycated}/parsers/troika_parser.c | 2 +- .../{ => deprycated}/parsers/troika_parser.h | 0 lib/nfc/{ => deprycated}/parsers/two_cities.c | 2 +- lib/nfc/{ => deprycated}/parsers/two_cities.h | 0 lib/nfc/{ => deprycated}/protocols/crypto1.c | 2 +- lib/nfc/{ => deprycated}/protocols/crypto1.h | 0 lib/nfc/{ => deprycated}/protocols/emv.c | 0 lib/nfc/{ => deprycated}/protocols/emv.h | 0 .../protocols/mifare_classic.c | 4 +- .../protocols/mifare_classic.h | 0 .../protocols/mifare_common.c | 0 .../protocols/mifare_common.h | 0 .../protocols/mifare_desfire.c | 0 .../protocols/mifare_desfire.h | 0 .../protocols/mifare_ultralight.c | 2 +- .../protocols/mifare_ultralight.h | 0 .../{ => deprycated}/protocols/nfca_utils.c | 0 .../{ => deprycated}/protocols/nfca_utils.h | 0 lib/nfc/helpers/nfc_poller_buffer.c | 40 ------------------- lib/nfc/helpers/nfc_poller_buffer.h | 28 ------------- lib/nfc/{protocols => helpers}/nfc_util.c | 0 lib/nfc/{protocols => helpers}/nfc_util.h | 0 lib/nfc/protocols/mf_classic/crypto1.c | 2 +- lib/nfc/protocols/mf_classic/mf_classic.c | 2 +- .../mf_classic/mf_classic_poller_i.h | 2 +- .../mf_ultralight/mf_ultralight_poller_i.h | 2 +- 63 files changed, 47 insertions(+), 117 deletions(-) rename lib/nfc/{ => deprycated}/helpers/mf_classic_dict.c (100%) rename lib/nfc/{ => deprycated}/helpers/mf_classic_dict.h (100%) rename lib/nfc/{ => deprycated}/helpers/mfkey32.c (98%) rename lib/nfc/{ => deprycated}/helpers/mfkey32.h (90%) rename lib/nfc/{ => deprycated}/helpers/nfc_debug_log.c (100%) rename lib/nfc/{ => deprycated}/helpers/nfc_debug_log.h (100%) rename lib/nfc/{ => deprycated}/helpers/nfc_debug_pcap.c (100%) rename lib/nfc/{ => deprycated}/helpers/nfc_debug_pcap.h (100%) rename lib/nfc/{ => deprycated}/helpers/nfc_generators.c (100%) rename lib/nfc/{ => deprycated}/helpers/nfc_generators.h (100%) rename lib/nfc/{ => deprycated}/helpers/reader_analyzer.c (98%) rename lib/nfc/{ => deprycated}/helpers/reader_analyzer.h (96%) rename lib/nfc/{ => deprycated}/nfc_device.c (99%) rename lib/nfc/{ => deprycated}/nfc_device.h (90%) rename lib/nfc/{ => deprycated}/nfc_types.c (100%) rename lib/nfc/{ => deprycated}/nfc_types.h (100%) rename lib/nfc/{ => deprycated}/nfc_worker.c (100%) rename lib/nfc/{ => deprycated}/nfc_worker.h (100%) rename lib/nfc/{ => deprycated}/nfc_worker_i.h (77%) rename lib/nfc/{ => deprycated}/parsers/all_in_one.c (98%) rename lib/nfc/{ => deprycated}/parsers/all_in_one.h (100%) rename lib/nfc/{ => deprycated}/parsers/nfc_supported_card.c (100%) rename lib/nfc/{ => deprycated}/parsers/nfc_supported_card.h (100%) rename lib/nfc/{ => deprycated}/parsers/plantain_4k_parser.c (99%) rename lib/nfc/{ => deprycated}/parsers/plantain_4k_parser.h (100%) rename lib/nfc/{ => deprycated}/parsers/plantain_parser.c (98%) rename lib/nfc/{ => deprycated}/parsers/plantain_parser.h (100%) rename lib/nfc/{ => deprycated}/parsers/troika_4k_parser.c (99%) rename lib/nfc/{ => deprycated}/parsers/troika_4k_parser.h (100%) rename lib/nfc/{ => deprycated}/parsers/troika_parser.c (98%) rename lib/nfc/{ => deprycated}/parsers/troika_parser.h (100%) rename lib/nfc/{ => deprycated}/parsers/two_cities.c (99%) rename lib/nfc/{ => deprycated}/parsers/two_cities.h (100%) rename lib/nfc/{ => deprycated}/protocols/crypto1.c (99%) rename lib/nfc/{ => deprycated}/protocols/crypto1.h (100%) rename lib/nfc/{ => deprycated}/protocols/emv.c (100%) rename lib/nfc/{ => deprycated}/protocols/emv.h (100%) rename lib/nfc/{ => deprycated}/protocols/mifare_classic.c (99%) rename lib/nfc/{ => deprycated}/protocols/mifare_classic.h (100%) rename lib/nfc/{ => deprycated}/protocols/mifare_common.c (100%) rename lib/nfc/{ => deprycated}/protocols/mifare_common.h (100%) rename lib/nfc/{ => deprycated}/protocols/mifare_desfire.c (100%) rename lib/nfc/{ => deprycated}/protocols/mifare_desfire.h (100%) rename lib/nfc/{ => deprycated}/protocols/mifare_ultralight.c (99%) rename lib/nfc/{ => deprycated}/protocols/mifare_ultralight.h (100%) rename lib/nfc/{ => deprycated}/protocols/nfca_utils.c (100%) rename lib/nfc/{ => deprycated}/protocols/nfca_utils.h (100%) delete mode 100644 lib/nfc/helpers/nfc_poller_buffer.c delete mode 100644 lib/nfc/helpers/nfc_poller_buffer.h rename lib/nfc/{protocols => helpers}/nfc_util.c (100%) rename lib/nfc/{protocols => helpers}/nfc_util.h (100%) diff --git a/applications/external/nfc_magic/lib/magic/magic.h b/applications/external/nfc_magic/lib/magic/magic.h index 64c60a0a705a..9be1f7bf6616 100644 --- a/applications/external/nfc_magic/lib/magic/magic.h +++ b/applications/external/nfc_magic/lib/magic/magic.h @@ -1,6 +1,6 @@ #pragma once -#include +#include bool magic_wupa(); diff --git a/applications/external/picopass/views/dict_attack.h b/applications/external/picopass/views/dict_attack.h index bdfa3e952007..2474bf6e4335 100644 --- a/applications/external/picopass/views/dict_attack.h +++ b/applications/external/picopass/views/dict_attack.h @@ -3,7 +3,7 @@ #include #include -#include +#include typedef struct DictAttack DictAttack; diff --git a/applications/main/nfc/application.fam b/applications/main/nfc/application.fam index fdc1e81bf60a..ae8a981f5106 100644 --- a/applications/main/nfc/application.fam +++ b/applications/main/nfc/application.fam @@ -9,7 +9,7 @@ App( "gui", "dialogs", ], - provides=["nfc_start"], + # provides=["nfc_start"], icon="A_NFC_14", stack_size=5 * 1024, order=30, @@ -22,10 +22,10 @@ App( requires=["nfc"], ) -App( - appid="nfc_start", - apptype=FlipperAppType.STARTUP, - entry_point="nfc_on_system_start", - requires=["nfc"], - order=30, -) +# App( +# appid="nfc_start", +# apptype=FlipperAppType.STARTUP, +# entry_point="nfc_on_system_start", +# requires=["nfc"], +# order=30, +# ) diff --git a/applications/main/nfc/helpers/mf_dict.c b/applications/main/nfc/helpers/mf_dict.c index 9e66cca86e8c..71a4a23c61a3 100644 --- a/applications/main/nfc/helpers/mf_dict.c +++ b/applications/main/nfc/helpers/mf_dict.c @@ -3,7 +3,7 @@ #include #include -#include +#include #define MF_CLASSIC_DICT_FLIPPER_PATH EXT_PATH("nfc/assets/mf_classic_dict.nfc") #define MF_CLASSIC_DICT_USER_PATH EXT_PATH("nfc/assets/mf_dict_user.nfc") diff --git a/applications/main/nfc/nfc_cli.c b/applications/main/nfc/nfc_cli.c index b1f2a48490ad..c4ca6d6a6e87 100644 --- a/applications/main/nfc/nfc_cli.c +++ b/applications/main/nfc/nfc_cli.c @@ -4,8 +4,8 @@ #include #include -#include -#include +#include +#include static void nfc_cli_print_usage() { printf("Usage:\r\n"); diff --git a/applications/main/nfc_old/views/dict_attack.h b/applications/main/nfc_old/views/dict_attack.h index 73b98a1b827b..6a633f85c5c3 100644 --- a/applications/main/nfc_old/views/dict_attack.h +++ b/applications/main/nfc_old/views/dict_attack.h @@ -3,7 +3,7 @@ #include #include -#include +#include typedef struct DictAttack DictAttack; diff --git a/firmware/targets/f7/furi_hal/furi_hal_nfc.h b/firmware/targets/f7/furi_hal/furi_hal_nfc.h index 69f3c47b4e8c..0ead657cbae0 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_nfc.h +++ b/firmware/targets/f7/furi_hal/furi_hal_nfc.h @@ -13,7 +13,7 @@ extern "C" { #endif #include -#include +#include #define FURI_HAL_NFC_UID_MAX_LEN 10 #define FURI_HAL_NFC_DATA_BUFF_SIZE (512) diff --git a/lib/nfc/SConscript b/lib/nfc/SConscript index 7e2123b74614..779c8b390e94 100644 --- a/lib/nfc/SConscript +++ b/lib/nfc/SConscript @@ -13,7 +13,7 @@ env.Append( libenv = env.Clone(FW_LIB_NAME="nfc") libenv.ApplyLibFlags() -sources = libenv.GlobRecursive("*.c*") +sources = libenv.GlobRecursive("*.c*", exclude="deprycated/*c") lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) libenv.Install("${LIB_DIST_DIR}", lib) diff --git a/lib/nfc/helpers/mf_classic_dict.c b/lib/nfc/deprycated/helpers/mf_classic_dict.c similarity index 100% rename from lib/nfc/helpers/mf_classic_dict.c rename to lib/nfc/deprycated/helpers/mf_classic_dict.c diff --git a/lib/nfc/helpers/mf_classic_dict.h b/lib/nfc/deprycated/helpers/mf_classic_dict.h similarity index 100% rename from lib/nfc/helpers/mf_classic_dict.h rename to lib/nfc/deprycated/helpers/mf_classic_dict.h diff --git a/lib/nfc/helpers/mfkey32.c b/lib/nfc/deprycated/helpers/mfkey32.c similarity index 98% rename from lib/nfc/helpers/mfkey32.c rename to lib/nfc/deprycated/helpers/mfkey32.c index 81aa3c930711..e9701212ff3c 100644 --- a/lib/nfc/helpers/mfkey32.c +++ b/lib/nfc/deprycated/helpers/mfkey32.c @@ -6,8 +6,7 @@ #include #include -#include -#include +#include #define TAG "Mfkey32" diff --git a/lib/nfc/helpers/mfkey32.h b/lib/nfc/deprycated/helpers/mfkey32.h similarity index 90% rename from lib/nfc/helpers/mfkey32.h rename to lib/nfc/deprycated/helpers/mfkey32.h index e1f472e50c81..37d7761257d0 100644 --- a/lib/nfc/helpers/mfkey32.h +++ b/lib/nfc/deprycated/helpers/mfkey32.h @@ -1,6 +1,6 @@ #pragma once -#include +#include typedef struct Mfkey32 Mfkey32; diff --git a/lib/nfc/helpers/nfc_debug_log.c b/lib/nfc/deprycated/helpers/nfc_debug_log.c similarity index 100% rename from lib/nfc/helpers/nfc_debug_log.c rename to lib/nfc/deprycated/helpers/nfc_debug_log.c diff --git a/lib/nfc/helpers/nfc_debug_log.h b/lib/nfc/deprycated/helpers/nfc_debug_log.h similarity index 100% rename from lib/nfc/helpers/nfc_debug_log.h rename to lib/nfc/deprycated/helpers/nfc_debug_log.h diff --git a/lib/nfc/helpers/nfc_debug_pcap.c b/lib/nfc/deprycated/helpers/nfc_debug_pcap.c similarity index 100% rename from lib/nfc/helpers/nfc_debug_pcap.c rename to lib/nfc/deprycated/helpers/nfc_debug_pcap.c diff --git a/lib/nfc/helpers/nfc_debug_pcap.h b/lib/nfc/deprycated/helpers/nfc_debug_pcap.h similarity index 100% rename from lib/nfc/helpers/nfc_debug_pcap.h rename to lib/nfc/deprycated/helpers/nfc_debug_pcap.h diff --git a/lib/nfc/helpers/nfc_generators.c b/lib/nfc/deprycated/helpers/nfc_generators.c similarity index 100% rename from lib/nfc/helpers/nfc_generators.c rename to lib/nfc/deprycated/helpers/nfc_generators.c diff --git a/lib/nfc/helpers/nfc_generators.h b/lib/nfc/deprycated/helpers/nfc_generators.h similarity index 100% rename from lib/nfc/helpers/nfc_generators.h rename to lib/nfc/deprycated/helpers/nfc_generators.h diff --git a/lib/nfc/helpers/reader_analyzer.c b/lib/nfc/deprycated/helpers/reader_analyzer.c similarity index 98% rename from lib/nfc/helpers/reader_analyzer.c rename to lib/nfc/deprycated/helpers/reader_analyzer.c index 9bf37a60d296..bbdc2ad5b436 100644 --- a/lib/nfc/helpers/reader_analyzer.c +++ b/lib/nfc/deprycated/helpers/reader_analyzer.c @@ -1,6 +1,6 @@ #include "reader_analyzer.h" -#include -#include +#include +#include #include #include "mfkey32.h" diff --git a/lib/nfc/helpers/reader_analyzer.h b/lib/nfc/deprycated/helpers/reader_analyzer.h similarity index 96% rename from lib/nfc/helpers/reader_analyzer.h rename to lib/nfc/deprycated/helpers/reader_analyzer.h index 13bf4d77ccf9..12258e4c3fee 100644 --- a/lib/nfc/helpers/reader_analyzer.h +++ b/lib/nfc/deprycated/helpers/reader_analyzer.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include typedef enum { ReaderAnalyzerModeDebugLog = 0x01, diff --git a/lib/nfc/nfc_device.c b/lib/nfc/deprycated/nfc_device.c similarity index 99% rename from lib/nfc/nfc_device.c rename to lib/nfc/deprycated/nfc_device.c index 917f37861c0d..c9a3911b9fa5 100644 --- a/lib/nfc/nfc_device.c +++ b/lib/nfc/deprycated/nfc_device.c @@ -4,7 +4,7 @@ #include #include -#include +#include #include #define TAG "NfcDevice" diff --git a/lib/nfc/nfc_device.h b/lib/nfc/deprycated/nfc_device.h similarity index 90% rename from lib/nfc/nfc_device.h rename to lib/nfc/deprycated/nfc_device.h index df37ec3df53b..f264665aec37 100644 --- a/lib/nfc/nfc_device.h +++ b/lib/nfc/deprycated/nfc_device.h @@ -6,11 +6,11 @@ #include #include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #ifdef __cplusplus extern "C" { diff --git a/lib/nfc/nfc_types.c b/lib/nfc/deprycated/nfc_types.c similarity index 100% rename from lib/nfc/nfc_types.c rename to lib/nfc/deprycated/nfc_types.c diff --git a/lib/nfc/nfc_types.h b/lib/nfc/deprycated/nfc_types.h similarity index 100% rename from lib/nfc/nfc_types.h rename to lib/nfc/deprycated/nfc_types.h diff --git a/lib/nfc/nfc_worker.c b/lib/nfc/deprycated/nfc_worker.c similarity index 100% rename from lib/nfc/nfc_worker.c rename to lib/nfc/deprycated/nfc_worker.c diff --git a/lib/nfc/nfc_worker.h b/lib/nfc/deprycated/nfc_worker.h similarity index 100% rename from lib/nfc/nfc_worker.h rename to lib/nfc/deprycated/nfc_worker.h diff --git a/lib/nfc/nfc_worker_i.h b/lib/nfc/deprycated/nfc_worker_i.h similarity index 77% rename from lib/nfc/nfc_worker_i.h rename to lib/nfc/deprycated/nfc_worker_i.h index e36a12f27ccb..7129b4cf02fe 100644 --- a/lib/nfc/nfc_worker_i.h +++ b/lib/nfc/deprycated/nfc_worker_i.h @@ -5,13 +5,12 @@ #include #include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include struct NfcWorker { FuriThread* thread; diff --git a/lib/nfc/parsers/all_in_one.c b/lib/nfc/deprycated/parsers/all_in_one.c similarity index 98% rename from lib/nfc/parsers/all_in_one.c rename to lib/nfc/deprycated/parsers/all_in_one.c index edcc0d0c7caf..dfe21ce5e8a4 100644 --- a/lib/nfc/parsers/all_in_one.c +++ b/lib/nfc/deprycated/parsers/all_in_one.c @@ -2,7 +2,7 @@ #include "all_in_one.h" #include -#include +#include #include diff --git a/lib/nfc/parsers/all_in_one.h b/lib/nfc/deprycated/parsers/all_in_one.h similarity index 100% rename from lib/nfc/parsers/all_in_one.h rename to lib/nfc/deprycated/parsers/all_in_one.h diff --git a/lib/nfc/parsers/nfc_supported_card.c b/lib/nfc/deprycated/parsers/nfc_supported_card.c similarity index 100% rename from lib/nfc/parsers/nfc_supported_card.c rename to lib/nfc/deprycated/parsers/nfc_supported_card.c diff --git a/lib/nfc/parsers/nfc_supported_card.h b/lib/nfc/deprycated/parsers/nfc_supported_card.h similarity index 100% rename from lib/nfc/parsers/nfc_supported_card.h rename to lib/nfc/deprycated/parsers/nfc_supported_card.h diff --git a/lib/nfc/parsers/plantain_4k_parser.c b/lib/nfc/deprycated/parsers/plantain_4k_parser.c similarity index 99% rename from lib/nfc/parsers/plantain_4k_parser.c rename to lib/nfc/deprycated/parsers/plantain_4k_parser.c index 4063a7a868db..e41fafce34c5 100644 --- a/lib/nfc/parsers/plantain_4k_parser.c +++ b/lib/nfc/deprycated/parsers/plantain_4k_parser.c @@ -1,7 +1,7 @@ #include "nfc_supported_card.h" #include -#include +#include #include diff --git a/lib/nfc/parsers/plantain_4k_parser.h b/lib/nfc/deprycated/parsers/plantain_4k_parser.h similarity index 100% rename from lib/nfc/parsers/plantain_4k_parser.h rename to lib/nfc/deprycated/parsers/plantain_4k_parser.h diff --git a/lib/nfc/parsers/plantain_parser.c b/lib/nfc/deprycated/parsers/plantain_parser.c similarity index 98% rename from lib/nfc/parsers/plantain_parser.c rename to lib/nfc/deprycated/parsers/plantain_parser.c index 46ed5a86d419..1dd5dc49868b 100644 --- a/lib/nfc/parsers/plantain_parser.c +++ b/lib/nfc/deprycated/parsers/plantain_parser.c @@ -1,7 +1,7 @@ #include "nfc_supported_card.h" #include -#include +#include #include diff --git a/lib/nfc/parsers/plantain_parser.h b/lib/nfc/deprycated/parsers/plantain_parser.h similarity index 100% rename from lib/nfc/parsers/plantain_parser.h rename to lib/nfc/deprycated/parsers/plantain_parser.h diff --git a/lib/nfc/parsers/troika_4k_parser.c b/lib/nfc/deprycated/parsers/troika_4k_parser.c similarity index 99% rename from lib/nfc/parsers/troika_4k_parser.c rename to lib/nfc/deprycated/parsers/troika_4k_parser.c index eead3dec25d3..1a9108c74b93 100644 --- a/lib/nfc/parsers/troika_4k_parser.c +++ b/lib/nfc/deprycated/parsers/troika_4k_parser.c @@ -1,7 +1,7 @@ #include "nfc_supported_card.h" #include -#include +#include static const MfClassicAuthContext troika_4k_keys[] = { {.sector = 0, .key_a = 0xa0a1a2a3a4a5, .key_b = 0xfbf225dc5d58}, diff --git a/lib/nfc/parsers/troika_4k_parser.h b/lib/nfc/deprycated/parsers/troika_4k_parser.h similarity index 100% rename from lib/nfc/parsers/troika_4k_parser.h rename to lib/nfc/deprycated/parsers/troika_4k_parser.h diff --git a/lib/nfc/parsers/troika_parser.c b/lib/nfc/deprycated/parsers/troika_parser.c similarity index 98% rename from lib/nfc/parsers/troika_parser.c rename to lib/nfc/deprycated/parsers/troika_parser.c index 911bba18db98..d9e81bab617b 100644 --- a/lib/nfc/parsers/troika_parser.c +++ b/lib/nfc/deprycated/parsers/troika_parser.c @@ -1,7 +1,7 @@ #include "nfc_supported_card.h" #include -#include +#include static const MfClassicAuthContext troika_keys[] = { {.sector = 0, .key_a = 0xa0a1a2a3a4a5, .key_b = 0xfbf225dc5d58}, diff --git a/lib/nfc/parsers/troika_parser.h b/lib/nfc/deprycated/parsers/troika_parser.h similarity index 100% rename from lib/nfc/parsers/troika_parser.h rename to lib/nfc/deprycated/parsers/troika_parser.h diff --git a/lib/nfc/parsers/two_cities.c b/lib/nfc/deprycated/parsers/two_cities.c similarity index 99% rename from lib/nfc/parsers/two_cities.c rename to lib/nfc/deprycated/parsers/two_cities.c index 54107964f24e..9410f94f87e9 100644 --- a/lib/nfc/parsers/two_cities.c +++ b/lib/nfc/deprycated/parsers/two_cities.c @@ -2,7 +2,7 @@ #include "plantain_parser.h" // For plantain-specific stuff #include -#include +#include #include diff --git a/lib/nfc/parsers/two_cities.h b/lib/nfc/deprycated/parsers/two_cities.h similarity index 100% rename from lib/nfc/parsers/two_cities.h rename to lib/nfc/deprycated/parsers/two_cities.h diff --git a/lib/nfc/protocols/crypto1.c b/lib/nfc/deprycated/protocols/crypto1.c similarity index 99% rename from lib/nfc/protocols/crypto1.c rename to lib/nfc/deprycated/protocols/crypto1.c index 15c3724533c4..2df762df49da 100644 --- a/lib/nfc/protocols/crypto1.c +++ b/lib/nfc/deprycated/protocols/crypto1.c @@ -1,5 +1,5 @@ #include "crypto1.h" -#include "nfc_util.h" +#include #include // Algorithm from https://github.com/RfidResearchGroup/proxmark3.git diff --git a/lib/nfc/protocols/crypto1.h b/lib/nfc/deprycated/protocols/crypto1.h similarity index 100% rename from lib/nfc/protocols/crypto1.h rename to lib/nfc/deprycated/protocols/crypto1.h diff --git a/lib/nfc/protocols/emv.c b/lib/nfc/deprycated/protocols/emv.c similarity index 100% rename from lib/nfc/protocols/emv.c rename to lib/nfc/deprycated/protocols/emv.c diff --git a/lib/nfc/protocols/emv.h b/lib/nfc/deprycated/protocols/emv.h similarity index 100% rename from lib/nfc/protocols/emv.h rename to lib/nfc/deprycated/protocols/emv.h diff --git a/lib/nfc/protocols/mifare_classic.c b/lib/nfc/deprycated/protocols/mifare_classic.c similarity index 99% rename from lib/nfc/protocols/mifare_classic.c rename to lib/nfc/deprycated/protocols/mifare_classic.c index 56d685f7615d..cbab5928b0f0 100644 --- a/lib/nfc/protocols/mifare_classic.c +++ b/lib/nfc/deprycated/protocols/mifare_classic.c @@ -1,6 +1,6 @@ #include "mifare_classic.h" -#include "nfca_utils.h" -#include "nfc_util.h" +#include +#include #include // Algorithm from https://github.com/RfidResearchGroup/proxmark3.git diff --git a/lib/nfc/protocols/mifare_classic.h b/lib/nfc/deprycated/protocols/mifare_classic.h similarity index 100% rename from lib/nfc/protocols/mifare_classic.h rename to lib/nfc/deprycated/protocols/mifare_classic.h diff --git a/lib/nfc/protocols/mifare_common.c b/lib/nfc/deprycated/protocols/mifare_common.c similarity index 100% rename from lib/nfc/protocols/mifare_common.c rename to lib/nfc/deprycated/protocols/mifare_common.c diff --git a/lib/nfc/protocols/mifare_common.h b/lib/nfc/deprycated/protocols/mifare_common.h similarity index 100% rename from lib/nfc/protocols/mifare_common.h rename to lib/nfc/deprycated/protocols/mifare_common.h diff --git a/lib/nfc/protocols/mifare_desfire.c b/lib/nfc/deprycated/protocols/mifare_desfire.c similarity index 100% rename from lib/nfc/protocols/mifare_desfire.c rename to lib/nfc/deprycated/protocols/mifare_desfire.c diff --git a/lib/nfc/protocols/mifare_desfire.h b/lib/nfc/deprycated/protocols/mifare_desfire.h similarity index 100% rename from lib/nfc/protocols/mifare_desfire.h rename to lib/nfc/deprycated/protocols/mifare_desfire.h diff --git a/lib/nfc/protocols/mifare_ultralight.c b/lib/nfc/deprycated/protocols/mifare_ultralight.c similarity index 99% rename from lib/nfc/protocols/mifare_ultralight.c rename to lib/nfc/deprycated/protocols/mifare_ultralight.c index 0e28c0074f1d..ace08fb1db5f 100644 --- a/lib/nfc/protocols/mifare_ultralight.c +++ b/lib/nfc/deprycated/protocols/mifare_ultralight.c @@ -1,7 +1,7 @@ #include #include #include "mifare_ultralight.h" -#include "nfc_util.h" +#include #include #include diff --git a/lib/nfc/protocols/mifare_ultralight.h b/lib/nfc/deprycated/protocols/mifare_ultralight.h similarity index 100% rename from lib/nfc/protocols/mifare_ultralight.h rename to lib/nfc/deprycated/protocols/mifare_ultralight.h diff --git a/lib/nfc/protocols/nfca_utils.c b/lib/nfc/deprycated/protocols/nfca_utils.c similarity index 100% rename from lib/nfc/protocols/nfca_utils.c rename to lib/nfc/deprycated/protocols/nfca_utils.c diff --git a/lib/nfc/protocols/nfca_utils.h b/lib/nfc/deprycated/protocols/nfca_utils.h similarity index 100% rename from lib/nfc/protocols/nfca_utils.h rename to lib/nfc/deprycated/protocols/nfca_utils.h diff --git a/lib/nfc/helpers/nfc_poller_buffer.c b/lib/nfc/helpers/nfc_poller_buffer.c deleted file mode 100644 index 9d2a5d46d74f..000000000000 --- a/lib/nfc/helpers/nfc_poller_buffer.c +++ /dev/null @@ -1,40 +0,0 @@ -#include "nfc_poller_buffer.h" - -#include - -NfcPollerBuffer* nfc_poller_buffer_alloc(uint16_t tx_bytes_max, uint16_t rx_bytes_max) { - NfcPollerBuffer* instance = malloc(sizeof(NfcPollerBuffer)); - instance->tx_data = malloc(tx_bytes_max); - instance->tx_parity = malloc((tx_bytes_max + 7) / 8); - instance->tx_data_size = tx_bytes_max; - instance->rx_data = malloc(rx_bytes_max); - instance->rx_parity = malloc((rx_bytes_max + 7) / 8); - instance->rx_data_size = rx_bytes_max; - - return instance; -} - -void nfc_poller_buffer_free(NfcPollerBuffer* instance) { - furi_assert(instance); - furi_assert(instance->tx_data); - furi_assert(instance->rx_data); - - free(instance->tx_data); - free(instance->tx_parity); - free(instance->rx_data); - free(instance->rx_parity); - free(instance); -} - -void nfc_poller_buffer_reset(NfcPollerBuffer* instance) { - furi_assert(instance); - furi_assert(instance->tx_data); - furi_assert(instance->rx_data); - - memset(instance->tx_data, 0, instance->tx_data_size); - memset(instance->tx_parity, 0, (instance->tx_data_size + 7) / 8); - memset(instance->rx_data, 0, instance->rx_data_size); - memset(instance->rx_parity, 0, (instance->rx_data_size + 7) / 8); - instance->tx_bits = 0; - instance->rx_bits = 0; -} diff --git a/lib/nfc/helpers/nfc_poller_buffer.h b/lib/nfc/helpers/nfc_poller_buffer.h deleted file mode 100644 index 5d2423fea4c6..000000000000 --- a/lib/nfc/helpers/nfc_poller_buffer.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - uint8_t* tx_data; - uint8_t* tx_parity; - uint16_t tx_data_size; - uint16_t tx_bits; - uint8_t* rx_data; - uint8_t* rx_parity; - uint16_t rx_data_size; - uint16_t rx_bits; -} NfcPollerBuffer; - -NfcPollerBuffer* nfc_poller_buffer_alloc(uint16_t tx_bytes_max, uint16_t rx_bytes_max); - -void nfc_poller_buffer_free(NfcPollerBuffer* instance); - -void nfc_poller_buffer_reset(NfcPollerBuffer* instance); - -#ifdef __cplusplus -} -#endif diff --git a/lib/nfc/protocols/nfc_util.c b/lib/nfc/helpers/nfc_util.c similarity index 100% rename from lib/nfc/protocols/nfc_util.c rename to lib/nfc/helpers/nfc_util.c diff --git a/lib/nfc/protocols/nfc_util.h b/lib/nfc/helpers/nfc_util.h similarity index 100% rename from lib/nfc/protocols/nfc_util.h rename to lib/nfc/helpers/nfc_util.h diff --git a/lib/nfc/protocols/mf_classic/crypto1.c b/lib/nfc/protocols/mf_classic/crypto1.c index b973228e6e0b..1ca2966fea9a 100644 --- a/lib/nfc/protocols/mf_classic/crypto1.c +++ b/lib/nfc/protocols/mf_classic/crypto1.c @@ -1,6 +1,6 @@ #include "crypto1.h" -#include +#include #include // Algorithm from https://github.com/RfidResearchGroup/proxmark3.git diff --git a/lib/nfc/protocols/mf_classic/mf_classic.c b/lib/nfc/protocols/mf_classic/mf_classic.c index b90cc9bbf1cd..83c801d198bc 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic.c +++ b/lib/nfc/protocols/mf_classic/mf_classic.c @@ -3,7 +3,7 @@ #include #include -#include +#include typedef struct { uint8_t sectors_total; diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h index 3126e9a08dd2..6d412bf2760f 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h @@ -2,7 +2,7 @@ #include "mf_classic_poller.h" #include -#include +#include #include "crypto1.h" #ifdef __cplusplus diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h index 2eb9bc5c2ece..42300f84bf21 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h @@ -2,7 +2,7 @@ #include "mf_ultralight_poller.h" #include -#include +#include #define MF_ULTRALIGHT_POLLER_STANDART_FWT_FC (60000) From 4069d18cebd60b3b5f15b3693c958b0e1531954c Mon Sep 17 00:00:00 2001 From: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Date: Tue, 20 Jun 2023 15:12:09 +0300 Subject: [PATCH 104/149] Gsurkov/3324 mf desfire (#2788) * Add MfDesfire private API * Add SimpleArray type * Increase fwt for RATS command * Increase maximum fwt time * Implement GetApplicationIds * Implement SelectApplication * Implement MfDesfire reading up to GetFileIds * Implement MfDesfire reading up to GetFileSettings * Implement general Info scene * Complete Mf Desfire read procedure with GUI --- .../helpers/format/nfc_mf_desfire_format.c | 213 +++++++++++ .../helpers/format/nfc_mf_desfire_format.h | 27 ++ .../nfc/helpers/format/nfc_protocol_format.c | 130 +++++++ .../nfc/helpers/format/nfc_protocol_format.h | 12 + .../main/nfc/scenes/nfc_scene_config.h | 1 + applications/main/nfc/scenes/nfc_scene_info.c | 66 ++++ .../nfc/scenes/nfc_scene_mf_desfire_app.c | 104 ++++- .../nfc/scenes/nfc_scene_mf_desfire_data.c | 107 +++++- .../nfc/scenes/nfc_scene_mf_desfire_menu.c | 3 +- .../nfc_scene_mf_desfire_read_success.c | 5 +- firmware/targets/f7/api_symbols.csv | 11 +- .../targets/f7/furi_hal/f_hal_nfc_timer.c | 4 +- lib/nfc/helpers/bit_buffer.c | 64 ++-- lib/nfc/helpers/bit_buffer.h | 60 ++- lib/nfc/helpers/simple_array.c | 97 +++++ lib/nfc/helpers/simple_array.h | 35 ++ .../iso14443_4a/iso14443_4a_poller_i.c | 2 +- .../iso14443_4a/iso14443_4a_poller_i.h | 2 + lib/nfc/protocols/mf_desfire/mf_desfire.c | 142 +------ lib/nfc/protocols/mf_desfire/mf_desfire.h | 52 ++- lib/nfc/protocols/mf_desfire/mf_desfire_i.c | 132 +++++++ lib/nfc/protocols/mf_desfire/mf_desfire_i.h | 52 +++ .../protocols/mf_desfire/mf_desfire_poller.c | 64 +++- .../mf_desfire/mf_desfire_poller_i.c | 359 ++++++++++++++++-- .../mf_desfire/mf_desfire_poller_i.h | 65 +++- 25 files changed, 1550 insertions(+), 259 deletions(-) create mode 100644 applications/main/nfc/helpers/format/nfc_mf_desfire_format.c create mode 100644 applications/main/nfc/helpers/format/nfc_mf_desfire_format.h create mode 100644 applications/main/nfc/helpers/format/nfc_protocol_format.c create mode 100644 applications/main/nfc/helpers/format/nfc_protocol_format.h create mode 100644 applications/main/nfc/scenes/nfc_scene_info.c create mode 100644 lib/nfc/helpers/simple_array.c create mode 100644 lib/nfc/helpers/simple_array.h create mode 100644 lib/nfc/protocols/mf_desfire/mf_desfire_i.c create mode 100644 lib/nfc/protocols/mf_desfire/mf_desfire_i.h diff --git a/applications/main/nfc/helpers/format/nfc_mf_desfire_format.c b/applications/main/nfc/helpers/format/nfc_mf_desfire_format.c new file mode 100644 index 000000000000..9ecbeac85b60 --- /dev/null +++ b/applications/main/nfc/helpers/format/nfc_mf_desfire_format.c @@ -0,0 +1,213 @@ +#include "nfc_mf_desfire_format.h" + +void nfc_mf_desfire_format_data(const MfDesfireData* data, FuriString* str) { + nfc_mf_desfire_format_version(&data->version, str); + nfc_mf_desfire_format_free_memory(&data->free_memory, str); + nfc_mf_desfire_format_key_settings(&data->master_key_settings, str); + + for(uint32_t i = 0; i < simple_array_get_count(data->master_key_versions); ++i) { + nfc_mf_desfire_format_key_version(simple_array_cget(data->master_key_versions, i), i, str); + } +} + +void nfc_mf_desfire_format_version(const MfDesfireVersion* data, FuriString* str) { + furi_string_cat_printf( + str, + "%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", + data->uid[0], + data->uid[1], + data->uid[2], + data->uid[3], + data->uid[4], + data->uid[5], + data->uid[6]); + furi_string_cat_printf( + str, + "hw %02x type %02x sub %02x\n" + " maj %02x min %02x\n" + " size %02x proto %02x\n", + data->hw_vendor, + data->hw_type, + data->hw_subtype, + data->hw_major, + data->hw_minor, + data->hw_storage, + data->hw_proto); + furi_string_cat_printf( + str, + "sw %02x type %02x sub %02x\n" + " maj %02x min %02x\n" + " size %02x proto %02x\n", + data->sw_vendor, + data->sw_type, + data->sw_subtype, + data->sw_major, + data->sw_minor, + data->sw_storage, + data->sw_proto); + furi_string_cat_printf( + str, + "batch %02x:%02x:%02x:%02x:%02x\n" + "week %d year %d\n", + data->batch[0], + data->batch[1], + data->batch[2], + data->batch[3], + data->batch[4], + data->prod_week, + data->prod_year); +} + +void nfc_mf_desfire_format_free_memory(const MfDesfireFreeMemory* data, FuriString* str) { + if(data->is_present) { + furi_string_cat_printf(str, "freeMem %lu\n", data->bytes_free); + } +} + +void nfc_mf_desfire_format_key_settings(const MfDesfireKeySettings* data, FuriString* str) { + furi_string_cat_printf(str, "changeKeyID %d\n", data->change_key_id); + furi_string_cat_printf(str, "configChangeable %d\n", data->is_config_changeable); + furi_string_cat_printf(str, "freeCreateDelete %d\n", data->is_free_create_delete); + furi_string_cat_printf(str, "freeDirectoryList %d\n", data->is_free_directory_list); + furi_string_cat_printf(str, "masterChangeable %d\n", data->is_master_key_changeable); + + if(data->flags) { + furi_string_cat_printf(str, "flags %d\n", data->flags); + } + + furi_string_cat_printf(str, "maxKeys %d\n", data->max_keys); +} + +void nfc_mf_desfire_format_key_version( + const MfDesfireKeyVersion* data, + uint32_t index, + FuriString* str) { + furi_string_cat_printf(str, "key %lu version %u\n", index, *data); +} + +void nfc_mf_desfire_format_application_id(const MfDesfireApplicationId data, FuriString* str) { + furi_string_cat_printf(str, "Application %02x%02x%02x\n", data[0], data[1], data[2]); +} + +void nfc_mf_desfire_format_application(const MfDesfireApplication* data, FuriString* str) { + nfc_mf_desfire_format_key_settings(&data->key_settings, str); + + for(uint32_t i = 0; i < simple_array_get_count(data->key_versions); ++i) { + nfc_mf_desfire_format_key_version(simple_array_cget(data->key_versions, i), i, str); + } +} + +void nfc_mf_desfire_format_file_id(const MfDesfireFileId* data, FuriString* str) { + furi_string_cat_printf(str, "File %d\n", *data); +} + +void nfc_mf_desfire_format_file_settings_data( + const MfDesfireFileSettings* settings, + const MfDesfireFileData* data, + FuriString* str) { + const char* type; + switch(settings->type) { + case MfDesfireFileTypeStandard: + type = "standard"; + break; + case MfDesfireFileTypeBackup: + type = "backup"; + break; + case MfDesfireFileTypeValue: + type = "value"; + break; + case MfDesfireFileTypeLinearRecord: + type = "linear"; + break; + case MfDesfireFileTypeCyclicRecord: + type = "cyclic"; + break; + default: + type = "unknown"; + } + + const char* comm; + switch(settings->comm) { + case MfDesfireFileCommunicationSettingsPlaintext: + comm = "plain"; + break; + case MfDesfireFileCommunicationSettingsAuthenticated: + comm = "auth"; + break; + case MfDesfireFileCommunicationSettingsEnciphered: + comm = "enciphered"; + break; + default: + comm = "unknown"; + } + + furi_string_cat_printf(str, "%s %s\n", type, comm); + furi_string_cat_printf( + str, + "r %d w %d rw %d c %d\n", + settings->access_rights >> 12 & 0xF, + settings->access_rights >> 8 & 0xF, + settings->access_rights >> 4 & 0xF, + settings->access_rights & 0xF); + + uint32_t record_count = 1; + uint32_t record_size = 0; + + switch(settings->type) { + case MfDesfireFileTypeStandard: + case MfDesfireFileTypeBackup: + record_size = settings->data.size; + furi_string_cat_printf(str, "size %lu\n", record_size); + break; + case MfDesfireFileTypeValue: + furi_string_cat_printf( + str, "lo %lu hi %lu\n", settings->value.lo_limit, settings->value.hi_limit); + furi_string_cat_printf( + str, + "limit %lu enabled %d\n", + settings->value.limited_credit_value, + settings->value.limited_credit_enabled); + break; + case MfDesfireFileTypeLinearRecord: + case MfDesfireFileTypeCyclicRecord: + record_count = settings->record.cur; + record_size = settings->record.size; + furi_string_cat_printf(str, "size %lu\n", record_size); + furi_string_cat_printf(str, "num %lu max %lu\n", record_count, settings->record.max); + break; + } + + if(simple_array_get_count(data->data) == 0) { + return; + } + + // TODO: Replace with pretty_format + for(uint32_t rec = 0; rec < record_count; rec++) { + furi_string_cat_printf(str, "record %lu\n", rec); + for(uint32_t ch = 0; ch < record_size; ch += 4) { + furi_string_cat_printf(str, "%03lx|", ch); + for(uint32_t i = 0; i < 4; i++) { + if(ch + i < record_size) { + const uint32_t data_index = rec * record_size + ch + i; + const uint8_t data_byte = + *(const uint8_t*)simple_array_cget(data->data, data_index); + furi_string_cat_printf(str, "%02x ", data_byte); + } else { + furi_string_cat_printf(str, " "); + } + } + for(uint32_t i = 0; i < 4 && ch + i < record_size; i++) { + const uint32_t data_index = rec * record_size + ch + i; + const uint8_t data_byte = + *(const uint8_t*)simple_array_cget(data->data, data_index); + if(isprint(data_byte)) { + furi_string_cat_printf(str, "%c", data_byte); + } else { + furi_string_cat_printf(str, "."); + } + } + furi_string_push_back(str, '\n'); + } + furi_string_push_back(str, '\n'); + } +} diff --git a/applications/main/nfc/helpers/format/nfc_mf_desfire_format.h b/applications/main/nfc/helpers/format/nfc_mf_desfire_format.h new file mode 100644 index 000000000000..0ac98cdb6fa9 --- /dev/null +++ b/applications/main/nfc/helpers/format/nfc_mf_desfire_format.h @@ -0,0 +1,27 @@ +#pragma once + +#include + +void nfc_mf_desfire_format_data(const MfDesfireData* data, FuriString* str); + +void nfc_mf_desfire_format_version(const MfDesfireVersion* data, FuriString* str); + +void nfc_mf_desfire_format_free_memory(const MfDesfireFreeMemory* data, FuriString* str); + +void nfc_mf_desfire_format_key_settings(const MfDesfireKeySettings* data, FuriString* str); + +void nfc_mf_desfire_format_key_version( + const MfDesfireKeyVersion* data, + uint32_t index, + FuriString* str); + +void nfc_mf_desfire_format_application_id(const MfDesfireApplicationId data, FuriString* str); + +void nfc_mf_desfire_format_application(const MfDesfireApplication* data, FuriString* str); + +void nfc_mf_desfire_format_file_id(const MfDesfireFileId* data, FuriString* str); + +void nfc_mf_desfire_format_file_settings_data( + const MfDesfireFileSettings* settings, + const MfDesfireFileData* data, + FuriString* str); diff --git a/applications/main/nfc/helpers/format/nfc_protocol_format.c b/applications/main/nfc/helpers/format/nfc_protocol_format.c new file mode 100644 index 000000000000..8bdc530d75f2 --- /dev/null +++ b/applications/main/nfc/helpers/format/nfc_protocol_format.c @@ -0,0 +1,130 @@ +#include "nfc_protocol_format.h" + +#include +#include +#include +#include + +typedef void (*NfcProtocolFormatRenderInfo)(const NfcDev* device, FuriString* str); + +typedef struct { + NfcProtocolFormatRenderInfo render_info; + const NfcProtocolFormatFeature flags; +} NfcProtocolFormatBase; + +static void + nfc_protocol_format_common_iso14443_3a_render_info(const NfcaData* nfc_data, FuriString* str) { + const char iso_type = FURI_BIT(nfc_data->sak, 5) ? '4' : '3'; + + furi_string_cat_printf(str, "ISO 14443-%c (NFC-A)\n", iso_type); + furi_string_cat_printf(str, "UID:"); + + for(size_t i = 0; i < nfc_data->uid_len; i++) { + furi_string_cat_printf(str, " %02X", nfc_data->uid[i]); + } + + furi_string_cat_printf(str, "\nATQA: %02X %02X ", nfc_data->atqa[1], nfc_data->atqa[0]); + furi_string_cat_printf(str, " SAK: %02X", nfc_data->sak); +} + +static void nfc_protocol_format_iso14443_3a_render_info(const NfcDev* device, FuriString* str) { + furi_string_cat_printf( + str, "\e#%s\n", nfc_dev_get_protocol_name(device, NfcProtocolNameTypeFull)); + + const NfcaData* data = nfc_dev_get_protocol_data(device, NfcProtocolTypeIso14443_3a); + nfc_protocol_format_common_iso14443_3a_render_info(data, str); +} + +static void nfc_protocol_format_iso14443_4a_render_info(const NfcDev* device, FuriString* str) { + furi_string_cat_printf( + str, "\e#%s\n", nfc_dev_get_protocol_name(device, NfcProtocolNameTypeFull)); + + const Iso14443_4aData* data = nfc_dev_get_protocol_data(device, NfcProtocolTypeIso14443_4a); + nfc_protocol_format_common_iso14443_3a_render_info(data->iso14443_3a_data, str); +} + +static void nfc_protocol_format_mf_ultralight_render_info(const NfcDev* device, FuriString* str) { + furi_string_cat_printf( + str, "\e#%s\n", nfc_dev_get_protocol_name(device, NfcProtocolNameTypeFull)); + + const MfUltralightData* data = nfc_dev_get_protocol_data(device, NfcProtocolTypeMfUltralight); + nfc_protocol_format_common_iso14443_3a_render_info(data->nfca_data, str); +} + +static void nfc_protocol_format_mf_classic_render_info(const NfcDev* device, FuriString* str) { + furi_string_cat_printf( + str, "\e#%s\n", nfc_dev_get_protocol_name(device, NfcProtocolNameTypeFull)); + + const MfClassicData* data = nfc_dev_get_protocol_data(device, NfcProtocolTypeMfClassic); + nfc_protocol_format_common_iso14443_3a_render_info(data->nfca_data, str); +} + +// TODO: use proper type getters +static void nfc_protocol_format_mf_desfire_render_info(const NfcDev* device, FuriString* str) { + furi_string_cat_printf( + str, "\e#%s\n", nfc_dev_get_protocol_name(device, NfcProtocolNameTypeFull)); + + const MfDesfireData* data = nfc_dev_get_protocol_data(device, NfcProtocolTypeMfDesfire); + nfc_protocol_format_common_iso14443_3a_render_info( + data->iso14443_4a_data->iso14443_3a_data, str); + + const uint32_t bytes_total = 1UL << (data->version.sw_storage >> 1); + const uint32_t bytes_free = data->free_memory.is_present ? data->free_memory.bytes_free : 0; + + furi_string_cat_printf(str, "\n%lu", bytes_total); + + if(data->version.sw_storage & 1) { + furi_string_push_back(str, '+'); + } + + furi_string_cat_printf(str, " bytes, %lu bytes free\n", bytes_free); + + const uint32_t app_count = simple_array_get_count(data->applications); + uint32_t file_count = 0; + + for(uint32_t i = 0; i < app_count; ++i) { + const MfDesfireApplication* app = simple_array_cget(data->applications, i); + file_count += simple_array_get_count(app->file_ids); + } + + furi_string_cat_printf(str, "%lu Application%s", app_count, app_count != 1 ? "s" : ""); + furi_string_cat_printf(str, ", %lu File%s", file_count, file_count != 1 ? "s" : ""); +} + +static const NfcProtocolFormatBase nfc_protocol_format[NfcProtocolTypeMax] = { + [NfcProtocolTypeIso14443_3a] = + { + .flags = NfcProtocolFormatFeatureNone, + .render_info = nfc_protocol_format_iso14443_3a_render_info, + }, + [NfcProtocolTypeIso14443_4a] = + { + .flags = NfcProtocolFormatFeatureNone, + .render_info = nfc_protocol_format_iso14443_4a_render_info, + }, + [NfcProtocolTypeMfUltralight] = + { + .flags = NfcProtocolFormatFeatureMoreData, + .render_info = nfc_protocol_format_mf_ultralight_render_info, + }, + [NfcProtocolTypeMfClassic] = + { + .flags = NfcProtocolFormatFeatureMoreData, + .render_info = nfc_protocol_format_mf_classic_render_info, + }, + [NfcProtocolTypeMfDesfire] = + { + .flags = NfcProtocolFormatFeatureMoreData, + .render_info = nfc_protocol_format_mf_desfire_render_info, + }, +}; + +NfcProtocolFormatFeature nfc_protocol_format_get_features(const NfcDev* device) { + furi_assert(device); + return nfc_protocol_format[nfc_dev_get_protocol_type(device)].flags; +} + +void nfc_protocol_format_render_info(const NfcDev* device, FuriString* str) { + furi_assert(device); + nfc_protocol_format[nfc_dev_get_protocol_type(device)].render_info(device, str); +} diff --git a/applications/main/nfc/helpers/format/nfc_protocol_format.h b/applications/main/nfc/helpers/format/nfc_protocol_format.h new file mode 100644 index 000000000000..7c11bdab50bf --- /dev/null +++ b/applications/main/nfc/helpers/format/nfc_protocol_format.h @@ -0,0 +1,12 @@ +#pragma once + +#include + +typedef enum { + NfcProtocolFormatFeatureNone = 0, + NfcProtocolFormatFeatureMoreData = 1UL << 0, +} NfcProtocolFormatFeature; + +NfcProtocolFormatFeature nfc_protocol_format_get_features(const NfcDev* device); + +void nfc_protocol_format_render_info(const NfcDev* device, FuriString* str); diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index ad4960a9eec3..6fc1116267cf 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -7,6 +7,7 @@ ADD_SCENE(nfc, delete, Delete) ADD_SCENE(nfc, delete_success, DeleteSuccess) ADD_SCENE(nfc, read, Read) +ADD_SCENE(nfc, info, Info) ADD_SCENE(nfc, read_card_type, ReadCardType) ADD_SCENE(nfc, nfca_read, NfcaRead) ADD_SCENE(nfc, nfca_emulate, NfcaEmulate) diff --git a/applications/main/nfc/scenes/nfc_scene_info.c b/applications/main/nfc/scenes/nfc_scene_info.c new file mode 100644 index 000000000000..6ca3e9791755 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_info.c @@ -0,0 +1,66 @@ +#include "../nfc_app_i.h" + +#include "../helpers/format/nfc_protocol_format.h" + +static void + nfc_scene_nfc_info_widget_callback(GuiButtonType result, InputType type, void* context) { + NfcApp* nfc = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); + } +} + +void nfc_scene_info_on_enter(void* context) { + NfcApp* nfc = context; + Widget* widget = nfc->widget; + + uint8_t text_scroll_height = 0; + if(nfc_protocol_format_get_features(nfc->nfc_dev) & NfcProtocolFormatFeatureMoreData) { + widget_add_button_element( + widget, GuiButtonTypeRight, "More", nfc_scene_nfc_info_widget_callback, nfc); + text_scroll_height = 52; + } else { + text_scroll_height = 64; + } + + FuriString* temp_str; + temp_str = furi_string_alloc(); + + nfc_protocol_format_render_info(nfc->nfc_dev, temp_str); + + widget_add_text_scroll_element( + widget, 0, 0, 128, text_scroll_height, furi_string_get_cstr(temp_str)); + furi_string_free(temp_str); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); +} + +bool nfc_scene_info_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + NfcProtocolType protocol_type = nfc_dev_get_protocol_type(nfc->nfc_dev); + + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeRight) { + // TODO: Do not if the protocol type directly + if(protocol_type == NfcProtocolTypeMfDesfire) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireData); + consumed = true; + } else if(protocol_type == NfcProtocolTypeMfUltralight) { + // scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightData); + consumed = true; + } else if(protocol_type == NfcProtocolTypeMfClassic) { + // scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicData); + consumed = true; + } + } + } + + return consumed; +} + +void nfc_scene_info_on_exit(void* context) { + NfcApp* nfc = context; + widget_reset(nfc->widget); +} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_desfire_app.c b/applications/main/nfc/scenes/nfc_scene_mf_desfire_app.c index 6620576461e6..4f2a7649fc46 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_desfire_app.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_desfire_app.c @@ -1,15 +1,109 @@ #include "../nfc_app_i.h" +#include "../helpers/format/nfc_mf_desfire_format.h" + +enum SubmenuIndex { + SubmenuIndexAppInfo, + SubmenuIndexDynamic, // dynamic indexes start here +}; + +static void nfc_scene_mf_desfire_app_submenu_callback(void* context, uint32_t index) { + NfcApp* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, index); +} + void nfc_scene_mf_desfire_app_on_enter(void* context) { - UNUSED(context); + NfcApp* nfc = context; + + text_box_set_font(nfc->text_box, TextBoxFontHex); + submenu_add_item( + nfc->submenu, + "App info", + SubmenuIndexAppInfo, + nfc_scene_mf_desfire_app_submenu_callback, + nfc); + + const uint32_t app_idx = + scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireApp) >> 1; + + const MfDesfireData* data = nfc_dev_get_protocol_data(nfc->nfc_dev, NfcProtocolTypeMfDesfire); + const MfDesfireApplication* app = simple_array_cget(data->applications, app_idx); + + FuriString* label = furi_string_alloc(); + + for(uint32_t i = 0; i < simple_array_get_count(app->file_ids); ++i) { + const MfDesfireFileId file_id = + *(const MfDesfireFileId*)simple_array_cget(app->file_ids, i); + furi_string_printf(label, "File %d", file_id); + submenu_add_item( + nfc->submenu, + furi_string_get_cstr(label), + i + SubmenuIndexDynamic, + nfc_scene_mf_desfire_app_submenu_callback, + nfc); + } + + furi_string_free(label); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); } bool nfc_scene_mf_desfire_app_on_event(void* context, SceneManagerEvent event) { - UNUSED(context); - UNUSED(event); - return false; + NfcApp* nfc = context; + bool consumed = false; + + const uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireApp); + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventViewExit) { + consumed = scene_manager_previous_scene(nfc->scene_manager); + } else { + const MfDesfireData* data = + nfc_dev_get_protocol_data(nfc->nfc_dev, NfcProtocolTypeMfDesfire); + + const uint32_t app_index = + scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireApp) >> 1; + const MfDesfireApplication* app = simple_array_cget(data->applications, app_index); + + TextBox* text_box = nfc->text_box; + furi_string_reset(nfc->text_box_store); + if(event.event == SubmenuIndexAppInfo) { + const uint8_t* app_id = simple_array_cget(data->application_ids, app_index); + nfc_mf_desfire_format_application_id(app_id, nfc->text_box_store); + nfc_mf_desfire_format_application(app, nfc->text_box_store); + } else { + const uint32_t file_index = event.event - SubmenuIndexDynamic; + const MfDesfireFileId* file_id = simple_array_cget(app->file_ids, file_index); + const MfDesfireFileSettings* file_settings = + simple_array_cget(app->file_settings, file_index); + const MfDesfireFileData* file_data = simple_array_cget(app->file_data, file_index); + nfc_mf_desfire_format_file_id(file_id, nfc->text_box_store); + nfc_mf_desfire_format_file_settings_data( + file_settings, file_data, nfc->text_box_store); + } + text_box_set_text(text_box, furi_string_get_cstr(nfc->text_box_store)); + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfDesfireApp, state | 1); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); + 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, NfcSceneMfDesfireApp, state & ~1); + consumed = true; + } + } + + return consumed; } void nfc_scene_mf_desfire_app_on_exit(void* context) { - UNUSED(context); + NfcApp* nfc = context; + + // Clear views + text_box_reset(nfc->text_box); + furi_string_reset(nfc->text_box_store); + submenu_reset(nfc->submenu); } diff --git a/applications/main/nfc/scenes/nfc_scene_mf_desfire_data.c b/applications/main/nfc/scenes/nfc_scene_mf_desfire_data.c index b0cf44f6878c..ffd94736168b 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_desfire_data.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_desfire_data.c @@ -1,15 +1,112 @@ #include "../nfc_app_i.h" +#include "../helpers/format/nfc_mf_desfire_format.h" + +enum { + MifareDesfireDataStateMenu, + MifareDesfireDataStateItem, // MUST be last, states >= this correspond with submenu index +}; + +enum SubmenuIndex { + SubmenuIndexCardInfo, + SubmenuIndexDynamic, // dynamic indexes start here +}; + +static void nfc_scene_mf_desfire_data_submenu_callback(void* context, uint32_t index) { + NfcApp* nfc = (NfcApp*)context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, index); +} + void nfc_scene_mf_desfire_data_on_enter(void* context) { - UNUSED(context); + NfcApp* nfc = context; + Submenu* submenu = nfc->submenu; + + const uint32_t state = + scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireData); + const MfDesfireData* data = nfc_dev_get_protocol_data(nfc->nfc_dev, NfcProtocolTypeMfDesfire); + + text_box_set_font(nfc->text_box, TextBoxFontHex); + + submenu_add_item( + submenu, + "Card info", + SubmenuIndexCardInfo, + nfc_scene_mf_desfire_data_submenu_callback, + nfc); + + FuriString* label = furi_string_alloc(); + + for(uint32_t i = 0; i < simple_array_get_count(data->application_ids); ++i) { + // TODO: Make it more type safe + const uint8_t* app_id = simple_array_cget(data->application_ids, i); + furi_string_printf(label, "App %02x%02x%02x", app_id[0], app_id[1], app_id[2]); + submenu_add_item( + submenu, + furi_string_get_cstr(label), + i + SubmenuIndexDynamic, + nfc_scene_mf_desfire_data_submenu_callback, + nfc); + } + + furi_string_free(label); + + if(state >= MifareDesfireDataStateItem) { + submenu_set_selected_item( + nfc->submenu, state - MifareDesfireDataStateItem + SubmenuIndexDynamic); + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneMfDesfireData, MifareDesfireDataStateMenu); + } + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); } bool nfc_scene_mf_desfire_data_on_event(void* context, SceneManagerEvent event) { - UNUSED(context); - UNUSED(event); - return false; + NfcApp* nfc = context; + bool consumed = false; + + const uint32_t state = + scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireData); + const MfDesfireData* data = nfc_dev_get_protocol_data(nfc->nfc_dev, NfcProtocolTypeMfDesfire); + + if(event.type == SceneManagerEventTypeCustom) { + TextBox* text_box = nfc->text_box; + furi_string_reset(nfc->text_box_store); + + if(event.event == SubmenuIndexCardInfo) { + nfc_mf_desfire_format_data(data, nfc->text_box_store); + text_box_set_text(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, + NfcSceneMfDesfireData, + MifareDesfireDataStateItem + SubmenuIndexCardInfo); + consumed = true; + } else { + const uint32_t index = event.event - SubmenuIndexDynamic; + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneMfDesfireData, MifareDesfireDataStateItem + index); + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfDesfireApp, index << 1); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireApp); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeBack) { + if(state >= MifareDesfireDataStateItem) { + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneMfDesfireData, MifareDesfireDataStateMenu); + consumed = true; + } + } + + return consumed; } void nfc_scene_mf_desfire_data_on_exit(void* context) { - UNUSED(context); + NfcApp* nfc = context; + + // Clear views + text_box_reset(nfc->text_box); + furi_string_reset(nfc->text_box_store); + submenu_reset(nfc->submenu); } diff --git a/applications/main/nfc/scenes/nfc_scene_mf_desfire_menu.c b/applications/main/nfc/scenes/nfc_scene_mf_desfire_menu.c index 69697e073005..e116df649495 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_desfire_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_desfire_menu.c @@ -52,8 +52,7 @@ bool nfc_scene_mf_desfire_menu_on_event(void* context, SceneManagerEvent event) } consumed = true; } else if(event.event == SubmenuIndexInfo) { - // TODO: Implement info - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + scene_manager_next_scene(nfc->scene_manager, NfcSceneInfo); consumed = true; } } diff --git a/applications/main/nfc/scenes/nfc_scene_mf_desfire_read_success.c b/applications/main/nfc/scenes/nfc_scene_mf_desfire_read_success.c index 27d2611ee0ec..90f4a877dad1 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_desfire_read_success.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_desfire_read_success.c @@ -40,10 +40,11 @@ void nfc_scene_mf_desfire_read_success_on_enter(void* context) { furi_string_cat_printf(temp_str, " bytes, %lu bytes free\n", bytes_free); uint16_t n_files = 0; - uint16_t n_apps = data->applications.count; + uint16_t n_apps = simple_array_get_count(data->applications); for(size_t i = 0; i < n_apps; ++i) { - n_files += data->applications.data[i].files.count; + const MfDesfireApplication* app = simple_array_cget(data->applications, i); + n_files += simple_array_get_count(app->file_ids); } furi_string_cat_printf(temp_str, "%d Application", n_apps); if(n_apps != 1) { diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 2965d34feea5..6956aa6e7d9b 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,+,28.0,, +Version,+,28.2,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -549,6 +549,7 @@ Function,-,bcmp,int,"const void*, const void*, size_t" Function,-,bcopy,void,"const void*, void*, size_t" Function,-,bit_buffer_alloc,BitBuffer*,size_t Function,-,bit_buffer_append,void,"BitBuffer*, const BitBuffer*" +Function,+,bit_buffer_append_byte,void,"BitBuffer*, uint8_t" Function,-,bit_buffer_append_bytes,void,"BitBuffer*, const uint8_t*, size_t" Function,-,bit_buffer_append_right,void,"BitBuffer*, const BitBuffer*, size_t" Function,-,bit_buffer_copy,void,"BitBuffer*, const BitBuffer*" @@ -571,6 +572,7 @@ Function,-,bit_buffer_set_size,void,"BitBuffer*, size_t" Function,-,bit_buffer_set_size_bytes,void,"BitBuffer*, size_t" Function,-,bit_buffer_starts_with_byte,_Bool,"const BitBuffer*, uint8_t" Function,-,bit_buffer_write_bytes,void,"const BitBuffer*, void*, size_t" +Function,+,bit_buffer_write_bytes_mid,void,"const BitBuffer*, void*, size_t, size_t" Function,-,bit_buffer_write_bytes_with_parity,void,"const BitBuffer*, void*, size_t, size_t*" Function,+,bit_lib_add_parity,size_t,"const uint8_t*, size_t, uint8_t*, size_t, uint8_t, uint8_t, BitLibParity" Function,+,bit_lib_copy_bits,void,"uint8_t*, size_t, size_t, const uint8_t*, size_t" @@ -2053,16 +2055,15 @@ Function,-,nfc_start_poller,void,"Nfc*, NfcEventCallback, void*" Function,-,nfc_stop,void,Nfc* Function,-,nfc_trx,NfcError,"Nfc*, const BitBuffer*, BitBuffer*, uint32_t" Function,-,nfc_trx_custom_parity,NfcError,"Nfc*, const BitBuffer*, BitBuffer*, uint32_t" +Function,+,nfca_alloc,NfcaData*, Function,-,nfca_append_crc,void,BitBuffer* Function,-,nfca_append_crc16,void,"uint8_t*, uint16_t" Function,-,nfca_check_crc,_Bool,const BitBuffer* +Function,+,nfca_copy,void,"NfcaData*, const NfcaData*" Function,-,nfca_emulation_handler,_Bool,"uint8_t*, uint16_t, uint8_t*, uint16_t*" +Function,+,nfca_free,void,NfcaData* Function,-,nfca_get_crc16,uint16_t,"uint8_t*, uint16_t" Function,-,nfca_get_cuid,uint32_t,NfcaData* -Function,+,nfca_alloc,NfcaData*, -Function,+,nfca_copy,void,"NfcaData*, const NfcaData*" -Function,+,nfca_free,void,NfcaData* -Function,-,nfca_get_crc,uint16_t,"uint8_t*, uint16_t" Function,+,nfca_get_name,const char*,"const NfcaData*, NfcProtocolNameType" Function,+,nfca_get_uid,const uint8_t*,"const NfcaData*, size_t*" Function,+,nfca_is_equal,_Bool,"const NfcaData*, const NfcaData*" diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc_timer.c b/firmware/targets/f7/furi_hal/f_hal_nfc_timer.c index cd47642d6d61..be2a0ba78521 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfc_timer.c +++ b/firmware/targets/f7/furi_hal/f_hal_nfc_timer.c @@ -29,8 +29,8 @@ static FHalNfcTimerConfig f_hal_nfc_timers[FHalNfcTimerCount] = { { .pin = &gpio_ext_pa7, .timer = TIM1, - .prescaler = 7, - .freq_khz = 8000U, + .prescaler = 15, + .freq_khz = 4000U, .event = FHalNfcEventInternalTypeTimerFwtExpired, .irq_id = FuriHalInterruptIdTim1UpTim16, .irq_type = TIM1_UP_TIM16_IRQn, diff --git a/lib/nfc/helpers/bit_buffer.c b/lib/nfc/helpers/bit_buffer.c index 9f7974d8642f..9f62d09b0bcd 100644 --- a/lib/nfc/helpers/bit_buffer.c +++ b/lib/nfc/helpers/bit_buffer.c @@ -11,12 +11,6 @@ struct BitBuffer { size_t size_bits; }; -/* TODO: - * - Handle partial bytes - * - Calculate parity - * - Something else? - */ - BitBuffer* bit_buffer_alloc(size_t capacity_bytes) { furi_assert(capacity_bytes); @@ -119,17 +113,6 @@ void bit_buffer_copy_bytes_with_parity(BitBuffer* buf, const uint8_t* data, size } } -void bit_buffer_append_bytes(BitBuffer* buf, const uint8_t* data, size_t size_bytes) { - furi_assert(buf); - furi_assert(data); - - size_t buf_size_bytes = bit_buffer_get_size_bytes(buf); - furi_assert(buf->capacity_bytes >= buf_size_bytes + size_bytes); - - memcpy(&buf->data[buf_size_bytes], data, size_bytes); - buf->size_bits += size_bytes * BITS_IN_BYTE; -} - void bit_buffer_write_bytes(const BitBuffer* buf, void* dest, size_t size_bytes) { furi_assert(buf); furi_assert(dest); @@ -177,6 +160,18 @@ void bit_buffer_write_bytes_with_parity( *bits_written = curr_bit_pos; } +void bit_buffer_write_bytes_mid( + const BitBuffer* buf, + void* dest, + size_t start_index, + size_t size_bytes) { + furi_assert(buf); + furi_assert(dest); + furi_assert(start_index + size_bytes <= bit_buffer_get_size_bytes(buf)); + + memcpy(dest, buf->data + start_index, size_bytes); +} + bool bit_buffer_has_partial_byte(const BitBuffer* buf) { furi_assert(buf); @@ -235,6 +230,20 @@ void bit_buffer_set_byte_with_parity(BitBuffer* buff, size_t index, uint8_t byte buff->parity[index] = parity; } +void bit_buffer_set_size(BitBuffer* buf, size_t new_size) { + furi_assert(buf); + furi_assert(buf->capacity_bytes * BITS_IN_BYTE >= new_size); + + buf->size_bits = new_size; +} + +void bit_buffer_set_size_bytes(BitBuffer* buf, size_t new_size_bytes) { + furi_assert(buf); + furi_assert(buf->capacity_bytes >= new_size_bytes); + + buf->size_bits = new_size_bytes * BITS_IN_BYTE; +} + void bit_buffer_append(BitBuffer* buf, const BitBuffer* other) { bit_buffer_append_right(buf, other, 0); } @@ -252,16 +261,25 @@ void bit_buffer_append_right(BitBuffer* buf, const BitBuffer* other, size_t star buf->size_bits += other->size_bits - start_index * BITS_IN_BYTE; } -void bit_buffer_set_size(BitBuffer* buf, size_t new_size) { +void bit_buffer_append_byte(BitBuffer* buf, uint8_t byte) { furi_assert(buf); - furi_assert(buf->capacity_bytes * BITS_IN_BYTE >= new_size); - buf->size_bits = new_size; + const size_t data_size_bytes = bit_buffer_get_size_bytes(buf); + const size_t new_data_size_bytes = data_size_bytes + 1; + furi_assert(new_data_size_bytes <= buf->capacity_bytes); + + buf->data[data_size_bytes] = byte; + buf->size_bits = new_data_size_bytes * BITS_IN_BYTE; } -void bit_buffer_set_size_bytes(BitBuffer* buf, size_t new_size_bytes) { +void bit_buffer_append_bytes(BitBuffer* buf, const uint8_t* data, size_t size_bytes) { furi_assert(buf); - furi_assert(buf->capacity_bytes >= new_size_bytes); + furi_assert(data); - buf->size_bits = new_size_bytes * BITS_IN_BYTE; + size_t buf_size_bytes = bit_buffer_get_size_bytes(buf); + furi_assert(buf->capacity_bytes >= buf_size_bytes + size_bytes); + + // TODO: Correct size + memcpy(&buf->data[buf_size_bytes], data, size_bytes); + buf->size_bits += size_bytes * BITS_IN_BYTE; } diff --git a/lib/nfc/helpers/bit_buffer.h b/lib/nfc/helpers/bit_buffer.h index 6bd1bd1fe290..d3f621861a2d 100644 --- a/lib/nfc/helpers/bit_buffer.h +++ b/lib/nfc/helpers/bit_buffer.h @@ -67,7 +67,7 @@ void bit_buffer_copy_right(BitBuffer* buf, const BitBuffer* other, size_t start_ * * @param [in,out] buf pointer to a BitBuffer instance to copy into * @param [in] other pointer to a BitBuffer instance to copy from - * @param [in] start_index index to begin copying source data from + * @param [in] end_index index to end copying source data at */ void bit_buffer_copy_left(BitBuffer* buf, const BitBuffer* other, size_t end_index); @@ -102,19 +102,9 @@ void bit_buffer_copy_bits(BitBuffer* buf, const uint8_t* data, size_t size_bits) void bit_buffer_copy_bytes_with_parity(BitBuffer* buf, const uint8_t* data, size_t size_bits); /** - * Append a byte array to a BitBuffer instance, replacing all of the original data. - * The destination capacity must be no less its original data size plus source data size. - * - * @param [in,out] buf pointer to a BitBuffer instance to copy into - * @param [in] data pointer to the byte array to be copied - * @param [in] size_bytes size of the data to be copied, in bytes - */ -void bit_buffer_append_bytes(BitBuffer* buf, const uint8_t* data, size_t size_bytes); - -/** - * Write a BitBuffer instance's contents to an arbitrary memory location. - * The destination memory must be allocated. Additionally, the instance - * must contain at least the requested amount of data (for easier underflow detection). + * Write a BitBuffer instance's entire contents to an arbitrary memory location. + * The destination memory must be allocated. Additionally, the destination + * capacity must be no less than the source data size. * * @param [in] buf pointer to a BitBuffer instance to write from * @param [out] dest pointer to the destination memory location @@ -123,9 +113,10 @@ void bit_buffer_append_bytes(BitBuffer* buf, const uint8_t* data, size_t size_by void bit_buffer_write_bytes(const BitBuffer* buf, void* dest, size_t size_bytes); /** - * Write a BitBuffer instance's contents to an arbitrary memory location. - * The destination memory must be allocated. Additionally, the instance - * must contain at least the requested amount of data (for easier underflow detection). + * Write a BitBuffer instance's entire contents to an arbitrary memory location. + * Additionally, place a parity bit after each byte. + * The destination memory must be allocated. Additionally, the destination + * capacity must be no less than the source data size plus parity. * * @param [in] buf pointer to a BitBuffer instance to write from * @param [out] dest pointer to the destination memory location @@ -138,6 +129,22 @@ void bit_buffer_write_bytes_with_parity( size_t size_bytes, size_t* bits_written); +/** + * Write a slice of BitBuffer instance's contents to an arbitrary memory location. + * The destination memory must be allocated. Additionally, the destination + * capacity must be no less than the requested slice size. + * + * @param [in] buf pointer to a BitBuffer instance to write from + * @param [out] dest pointer to the destination memory location + * @param [in] start_index index to begin copying source data from + * @param [in] size_bytes data slice size, in bytes + */ +void bit_buffer_write_bytes_mid( + const BitBuffer* buf, + void* dest, + size_t start_index, + size_t size_bytes); + // Checks /** @@ -266,6 +273,25 @@ void bit_buffer_append(BitBuffer* buf, const BitBuffer* other); */ void bit_buffer_append_right(BitBuffer* buf, const BitBuffer* other, size_t start_index); +/** + * Append a byte to a BitBuffer instance. + * The destination capacity must be no less its original data size plus one. + * + * @param [in,out] buf pointer to a BitBuffer instance to be appended to + * @param [in] byte byte value to be appended + */ +void bit_buffer_append_byte(BitBuffer* buf, uint8_t byte); + +/** + * Append a byte array to a BitBuffer instance. + * The destination capacity must be no less its original data size plus source data size. + * + * @param [in,out] buf pointer to a BitBuffer instance to be appended to + * @param [in] data pointer to the byte array to be appended + * @param [in] size_bytes size of the data to be appended, in bytes + */ +void bit_buffer_append_bytes(BitBuffer* buf, const uint8_t* data, size_t size_bytes); + #ifdef __cplusplus } #endif diff --git a/lib/nfc/helpers/simple_array.c b/lib/nfc/helpers/simple_array.c new file mode 100644 index 000000000000..f93682ff1be6 --- /dev/null +++ b/lib/nfc/helpers/simple_array.c @@ -0,0 +1,97 @@ +#include "simple_array.h" + +#include + +struct SimpleArray { + const SimpleArrayConfig* config; + SimpleArrayElement* data; + uint32_t count; +}; + +SimpleArray* simple_array_alloc(const SimpleArrayConfig* config) { + SimpleArray* instance = malloc(sizeof(SimpleArray)); + instance->config = config; + return instance; +} + +void simple_array_free(SimpleArray* instance) { + furi_assert(instance); + + simple_array_reset(instance); + free(instance); +} + +void simple_array_init(SimpleArray* instance, uint32_t count) { + furi_assert(instance); + furi_assert(count > 0); + + simple_array_reset(instance); + + instance->data = malloc(count * instance->config->type_size); + instance->count = count; + + SimpleArrayInit init = instance->config->init; + if(init) { + for(uint32_t i = 0; i < instance->count; ++i) { + init(simple_array_get(instance, i)); + } + } +} + +void simple_array_reset(SimpleArray* instance) { + furi_assert(instance); + + if(instance->data) { + SimpleArrayReset reset = instance->config->reset; + + if(reset) { + for(uint32_t i = 0; i < instance->count; ++i) { + reset(simple_array_get(instance, i)); + } + } + + free(instance->data); + + instance->count = 0; + instance->data = NULL; + } +} + +void simple_array_copy(SimpleArray* instance, const SimpleArray* other) { + furi_assert(instance); + furi_assert(other); + furi_assert(instance->config == other->config); + + simple_array_reset(instance); + + if(other->count == 0) { + return; + } + + simple_array_init(instance, other->count); + + SimpleArrayCopy copy = instance->config->copy; + if(copy) { + for(uint32_t i = 0; i < other->count; ++i) { + copy(simple_array_get(instance, i), simple_array_cget(other, i)); + } + } else { + memcpy(instance->data, other->data, other->count * instance->config->type_size); + } +} + +uint32_t simple_array_get_count(const SimpleArray* instance) { + furi_assert(instance); + return instance->count; +} + +SimpleArrayElement* simple_array_get(SimpleArray* instance, uint32_t index) { + furi_assert(instance); + furi_assert(index < instance->count); + + return instance->data + index * instance->config->type_size; +} + +const SimpleArrayElement* simple_array_cget(const SimpleArray* instance, uint32_t index) { + return simple_array_get((SimpleArrayElement*)instance, index); +} diff --git a/lib/nfc/helpers/simple_array.h b/lib/nfc/helpers/simple_array.h new file mode 100644 index 000000000000..c97baca326a4 --- /dev/null +++ b/lib/nfc/helpers/simple_array.h @@ -0,0 +1,35 @@ +#pragma once + +#include +#include + +typedef struct SimpleArray SimpleArray; + +typedef void SimpleArrayElement; + +typedef void (*SimpleArrayInit)(SimpleArrayElement* elem); +typedef void (*SimpleArrayReset)(SimpleArrayElement* elem); +typedef void (*SimpleArrayCopy)(SimpleArrayElement* elem, const SimpleArrayElement* other); + +typedef struct { + SimpleArrayInit init; + SimpleArrayReset reset; + SimpleArrayCopy copy; + const size_t type_size; +} SimpleArrayConfig; + +SimpleArray* simple_array_alloc(const SimpleArrayConfig* config); + +void simple_array_free(SimpleArray* instance); + +void simple_array_init(SimpleArray* instance, uint32_t count); + +void simple_array_reset(SimpleArray* instance); + +void simple_array_copy(SimpleArray* instance, const SimpleArray* other); + +uint32_t simple_array_get_count(const SimpleArray* instance); + +SimpleArrayElement* simple_array_get(SimpleArray* instance, uint32_t index); + +const SimpleArrayElement* simple_array_cget(const SimpleArray* instance, uint32_t index); diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c index 5c69d46eebd8..a70369c93d10 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c @@ -61,7 +61,7 @@ Iso14443_4aError iso14443_4a_poller_async_read_ats(Iso14443_4aPoller* instance) instance->iso14443_3a_poller, instance->tx_buffer, instance->rx_buffer, - NFCA_FDT_LISTEN_FC); + ISO14443_4A_POLLER_ATS_FWT_FC); if(error != NfcaErrorNone) { FURI_LOG_E(TAG, "Ats request failed: %d", error); break; diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.h b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.h index 70879ff27d44..c152f4dc0ff8 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.h +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.h @@ -8,6 +8,8 @@ extern "C" { #endif +#define ISO14443_4A_POLLER_ATS_FWT_FC (12000) + typedef enum { Iso14443_4aPollerStateIdle, Iso14443_4aPollerStateReadAts, diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire.c b/lib/nfc/protocols/mf_desfire/mf_desfire.c index 6affb4e0af96..ced20a662916 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire.c +++ b/lib/nfc/protocols/mf_desfire/mf_desfire.c @@ -1,4 +1,4 @@ -#include "mf_desfire.h" +#include "mf_desfire_i.h" #include @@ -20,56 +20,24 @@ const NfcProtocolBase nfc_protocol_mf_desfire = { MfDesfireData* mf_desfire_alloc() { MfDesfireData* data = malloc(sizeof(MfDesfireData)); data->iso14443_4a_data = iso14443_4a_alloc(); + data->master_key_versions = simple_array_alloc(&mf_desfire_key_version_array_config); + data->application_ids = simple_array_alloc(&mf_desfire_app_id_array_config); + data->applications = simple_array_alloc(&mf_desfire_application_array_config); + return data; } void mf_desfire_free(MfDesfireData* data) { furi_assert(data); + mf_desfire_reset(data); + simple_array_free(data->applications); + simple_array_free(data->application_ids); + simple_array_free(data->master_key_versions); iso14443_4a_free(data->iso14443_4a_data); free(data); } -static inline void mf_desfire_reset_key_config(MfDesfireKeyConfiguration* config) { - if(config->key_versions) { - free(config->key_versions); - } - memset(config, 0, sizeof(MfDesfireKeyConfiguration)); -} - -static inline void mf_desfire_reset_file(MfDesfireFile* file) { - if(file->contents) { - free(file->contents); - } - memset(file, 0, sizeof(MfDesfireFile)); -} - -static inline void mf_desfire_reset_files(MfDesfireFiles* files) { - if(files->data) { - for(size_t i = 0; i < files->count; ++i) { - mf_desfire_reset_file(&files->data[i]); - } - free(files->data); - } - memset(files, 0, sizeof(MfDesfireFiles)); -} - -static inline void mf_desfire_reset_application(MfDesfireApplication* app) { - memset(app->id, 0, sizeof(app->id)); - mf_desfire_reset_key_config(&app->key_config); - mf_desfire_reset_files(&app->files); -} - -static inline void mf_desfire_reset_applications(MfDesfireApplications* apps) { - if(apps->data) { - for(size_t i = 0; i < apps->count; ++i) { - mf_desfire_reset_application(&apps->data[i]); - } - free(apps->data); - } - memset(apps, 0, sizeof(MfDesfireApplications)); -} - void mf_desfire_reset(MfDesfireData* data) { furi_assert(data); @@ -78,89 +46,9 @@ void mf_desfire_reset(MfDesfireData* data) { memset(&data->version, 0, sizeof(MfDesfireVersion)); memset(&data->free_memory, 0, sizeof(MfDesfireFreeMemory)); - mf_desfire_reset_key_config(&data->master_key); - mf_desfire_reset_applications(&data->applications); -} - -static inline void mf_desfire_copy_key_config( - MfDesfireKeyConfiguration* config, - const MfDesfireKeyConfiguration* other) { - furi_assert(config->key_versions == NULL); - - config->key_settings = other->key_settings; - if(other->key_settings.max_keys == 0) { - return; - } - - const size_t key_versions_size = other->key_settings.max_keys * sizeof(MfDesfireKeyVersion); - config->key_versions = malloc(key_versions_size); - memcpy(config->key_versions, other->key_versions, key_versions_size); -} - -static inline void mf_desfire_copy_file(MfDesfireFile* file, const MfDesfireFile* other) { - furi_assert(file->contents == NULL); - - file->id = other->id; - file->type = other->type; - file->comm = other->comm; - file->access_rights = other->access_rights; - - if(other->type == MfDesfireFileTypeStandard || other->type == MfDesfireFileTypeBackup) { - file->data = other->data; - if(other->data.size == 0) { - return; - } - - file->contents = malloc(other->data.size); - memcpy(file->contents, other->contents, other->data.size); - - } else if(other->type == MfDesfireFileTypeValue) { - file->value = other->value; - } else if( - other->type == MfDesfireFileTypeLinearRecord || - other->type == MfDesfireFileTypeCyclicRecord) { - file->record = other->record; - } else { - furi_crash("Invalid file type"); - } -} - -static inline void mf_desfire_copy_files(MfDesfireFiles* files, const MfDesfireFiles* other) { - furi_assert(files->data == NULL); - - files->count = other->count; - if(other->count == 0) { - return; - } - - files->data = malloc(other->count * sizeof(MfDesfireFile)); - - for(size_t i = 0; i < other->count; ++i) { - mf_desfire_copy_file(&files->data[i], &other->data[i]); - } -} - -static inline void - mf_desfire_copy_application(MfDesfireApplication* app, const MfDesfireApplication* other) { - memcpy(app->id, other->id, sizeof(other->id)); - mf_desfire_copy_key_config(&app->key_config, &other->key_config); - mf_desfire_copy_files(&app->files, &other->files); -} - -static inline void - mf_desfire_copy_applications(MfDesfireApplications* apps, const MfDesfireApplications* other) { - furi_assert(apps->data == NULL); - - apps->count = other->count; - if(other->count == 0) { - return; - } - - apps->data = malloc(other->count * sizeof(MfDesfireApplication)); - - for(size_t i = 0; i < other->count; ++i) { - mf_desfire_copy_application(&apps->data[i], &other->data[i]); - } + simple_array_reset(data->master_key_versions); + simple_array_reset(data->application_ids); + simple_array_reset(data->applications); } void mf_desfire_copy(MfDesfireData* data, const MfDesfireData* other) { @@ -173,9 +61,11 @@ void mf_desfire_copy(MfDesfireData* data, const MfDesfireData* other) { data->version = other->version; data->free_memory = other->free_memory; + data->master_key_settings = other->master_key_settings; - mf_desfire_copy_key_config(&data->master_key, &other->master_key); - mf_desfire_copy_applications(&data->applications, &other->applications); + simple_array_copy(data->master_key_versions, other->master_key_versions); + simple_array_copy(data->application_ids, other->application_ids); + simple_array_copy(data->applications, other->applications); } bool mf_desfire_verify(MfDesfireData* data, const FuriString* device_type) { diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire.h b/lib/nfc/protocols/mf_desfire/mf_desfire.h index 72d230e43a3b..ca357b883b6b 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire.h +++ b/lib/nfc/protocols/mf_desfire/mf_desfire.h @@ -2,6 +2,8 @@ #include +#include "helpers/simple_array.h" + #ifdef __cplusplus extern "C" { #endif @@ -24,6 +26,10 @@ extern "C" { #define MF_DESFIRE_MAX_KEYS (14) #define MF_DESFIRE_MAX_FILES (32) +#define MF_DESFIRE_UID_SIZE (7) +#define MF_DESFIRE_BATCH_SIZE (5) +#define MF_DESFIRE_APP_ID_SIZE (3) + typedef struct { uint8_t hw_vendor; uint8_t hw_type; @@ -41,8 +47,8 @@ typedef struct { uint8_t sw_storage; uint8_t sw_proto; - uint8_t uid[7]; - uint8_t batch[5]; + uint8_t uid[MF_DESFIRE_UID_SIZE]; + uint8_t batch[MF_DESFIRE_BATCH_SIZE]; uint8_t prod_week; uint8_t prod_year; } MfDesfireVersion; @@ -66,7 +72,7 @@ typedef uint8_t MfDesfireKeyVersion; typedef struct { MfDesfireKeySettings key_settings; - MfDesfireKeyVersion* key_versions; + SimpleArray* key_versions; } MfDesfireKeyConfiguration; typedef enum { @@ -83,11 +89,13 @@ typedef enum { MfDesfireFileCommunicationSettingsEnciphered = 3, } MfDesfireFileCommunicationSettings; -typedef struct MifareDesfireFile { - uint8_t id; +typedef uint8_t MfDesfireFileId; +typedef uint16_t MfDesfireFileAccessRights; + +typedef struct { MfDesfireFileType type; MfDesfireFileCommunicationSettings comm; - uint16_t access_rights; + MfDesfireFileAccessRights access_rights; union { struct { uint32_t size; @@ -104,25 +112,22 @@ typedef struct MifareDesfireFile { uint32_t cur; } record; }; - uint8_t* contents; -} MfDesfireFile; +} MfDesfireFileSettings; typedef struct { - MfDesfireFile* data; - uint8_t count; -} MfDesfireFiles; + SimpleArray* data; +} MfDesfireFileData; + +typedef uint8_t MfDesfireApplicationId[MF_DESFIRE_APP_ID_SIZE]; typedef struct MfDesfireApplication { - uint8_t id[3]; - MfDesfireKeyConfiguration key_config; - MfDesfireFiles files; + MfDesfireKeySettings key_settings; + SimpleArray* key_versions; + SimpleArray* file_ids; + SimpleArray* file_settings; + SimpleArray* file_data; } MfDesfireApplication; -typedef struct { - MfDesfireApplication* data; - uint8_t count; -} MfDesfireApplications; - typedef enum { MfDesfireErrorNone, MfDesfireErrorNotPresent, @@ -134,12 +139,16 @@ typedef struct { Iso14443_4aData* iso14443_4a_data; MfDesfireVersion version; MfDesfireFreeMemory free_memory; - MfDesfireKeyConfiguration master_key; - MfDesfireApplications applications; + MfDesfireKeySettings master_key_settings; + SimpleArray* master_key_versions; + SimpleArray* application_ids; + SimpleArray* applications; } MfDesfireData; extern const NfcProtocolBase nfc_protocol_mf_desfire; +// Virtual methods + MfDesfireData* mf_desfire_alloc(); void mf_desfire_free(MfDesfireData* data); @@ -160,6 +169,7 @@ const char* mf_desfire_get_name(const MfDesfireData* data, NfcProtocolNameType n const uint8_t* mf_desfire_get_uid(const MfDesfireData* data, size_t* uid_len); +// Deprecated ? bool mf_desfire_detect_protocol(NfcaData* nfca_data); #ifdef __cplusplus diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_i.c b/lib/nfc/protocols/mf_desfire/mf_desfire_i.c new file mode 100644 index 000000000000..e0d30c19f144 --- /dev/null +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_i.c @@ -0,0 +1,132 @@ +#include "mf_desfire_i.h" + +void mf_desfire_version_parse(MfDesfireVersion* data, const BitBuffer* buf) { + bit_buffer_write_bytes(buf, data, sizeof(MfDesfireVersion)); +} + +void mf_desfire_free_memory_parse(MfDesfireFreeMemory* data, const BitBuffer* buf) { + furi_assert(!data->is_present); + + bit_buffer_write_bytes(buf, &data->bytes_free, sizeof(data->bytes_free) - 1); + data->bytes_free &= 0x00ffffff; + data->is_present = true; +} + +void mf_desfire_key_settings_parse(MfDesfireKeySettings* data, const BitBuffer* buf) { + bit_buffer_write_bytes(buf, data, sizeof(MfDesfireKeySettings)); +} + +void mf_desfire_key_version_parse(MfDesfireKeyVersion* data, const BitBuffer* buf) { + bit_buffer_write_bytes(buf, data, sizeof(MfDesfireKeyVersion)); +} + +void mf_desfire_application_id_parse( + MfDesfireApplicationId data, + uint32_t index, + const BitBuffer* buf) { + bit_buffer_write_bytes_mid( + buf, data, index * sizeof(MfDesfireApplicationId), sizeof(MfDesfireApplicationId)); +} + +void mf_desfire_file_id_parse(MfDesfireFileId* data, uint32_t index, const BitBuffer* buf) { + bit_buffer_write_bytes_mid( + buf, data, index * sizeof(MfDesfireFileId), sizeof(MfDesfireFileId)); +} + +void mf_desfire_file_settings_parse(MfDesfireFileSettings* data, const BitBuffer* buf) { + bit_buffer_write_bytes(buf, data, sizeof(MfDesfireFileSettings)); +} + +void mf_desfire_file_data_parse(MfDesfireFileData* data, const BitBuffer* buf) { + const size_t data_size = bit_buffer_get_size_bytes(buf); + + if(data_size > 0) { + simple_array_init(data->data, data_size); + bit_buffer_write_bytes(buf, simple_array_get(data->data, 0), data_size); + } +} + +void mf_desfire_file_data_init(MfDesfireFileData* data) { + data->data = simple_array_alloc(&mf_desfire_file_data_element_array_config); +} + +void mf_desfire_application_init(MfDesfireApplication* data) { + data->key_versions = simple_array_alloc(&mf_desfire_key_version_array_config); + data->file_ids = simple_array_alloc(&mf_desfire_file_id_array_config); + data->file_settings = simple_array_alloc(&mf_desfire_file_settings_array_config); + data->file_data = simple_array_alloc(&mf_desfire_file_data_array_config); +} + +void mf_desfire_file_data_reset(MfDesfireFileData* data) { + simple_array_free(data->data); + memset(data, 0, sizeof(MfDesfireFileData)); +} + +void mf_desfire_application_reset(MfDesfireApplication* data) { + simple_array_free(data->key_versions); + simple_array_free(data->file_ids); + simple_array_free(data->file_settings); + simple_array_free(data->file_data); + memset(data, 0, sizeof(MfDesfireApplication)); +} + +void mf_desfire_file_data_copy(MfDesfireFileData* data, const MfDesfireFileData* other) { + simple_array_copy(data->data, other->data); +} + +void mf_desfire_application_copy(MfDesfireApplication* data, const MfDesfireApplication* other) { + data->key_settings = other->key_settings; + simple_array_copy(data->key_versions, other->key_versions); + simple_array_copy(data->file_ids, other->file_ids); + simple_array_copy(data->file_settings, other->file_settings); + simple_array_copy(data->file_data, other->file_data); +} + +const SimpleArrayConfig mf_desfire_key_version_array_config = { + .init = NULL, + .copy = NULL, + .reset = NULL, + .type_size = sizeof(MfDesfireKeyVersion), +}; + +const SimpleArrayConfig mf_desfire_app_id_array_config = { + .init = NULL, + .copy = NULL, + .reset = NULL, + .type_size = sizeof(MfDesfireApplicationId), +}; + +const SimpleArrayConfig mf_desfire_file_id_array_config = { + .init = NULL, + .copy = NULL, + .reset = NULL, + .type_size = sizeof(MfDesfireFileId), +}; + +const SimpleArrayConfig mf_desfire_file_settings_array_config = { + .init = NULL, + .copy = NULL, + .reset = NULL, + .type_size = sizeof(MfDesfireFileSettings), +}; + +const SimpleArrayConfig mf_desfire_file_data_array_config = { + .init = (SimpleArrayInit)mf_desfire_file_data_init, + .copy = (SimpleArrayCopy)mf_desfire_file_data_copy, + .reset = (SimpleArrayReset)mf_desfire_file_data_reset, + .type_size = sizeof(MfDesfireData), +}; + +const SimpleArrayConfig mf_desfire_file_data_element_array_config = { + .init = NULL, + .copy = NULL, + .reset = NULL, + .type_size = sizeof(uint8_t), +}; + +const SimpleArrayConfig mf_desfire_application_array_config = { + .init = (SimpleArrayInit)mf_desfire_application_init, + .copy = (SimpleArrayCopy)mf_desfire_application_copy, + .reset = (SimpleArrayReset)mf_desfire_application_reset, + .type_size = sizeof(MfDesfireApplication), +}; diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_i.h b/lib/nfc/protocols/mf_desfire/mf_desfire_i.h new file mode 100644 index 000000000000..a76cfa706b56 --- /dev/null +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_i.h @@ -0,0 +1,52 @@ +#pragma once + +#include "mf_desfire.h" + +// SimpleArray configurations + +extern const SimpleArrayConfig mf_desfire_key_version_array_config; +extern const SimpleArrayConfig mf_desfire_app_id_array_config; +extern const SimpleArrayConfig mf_desfire_file_id_array_config; +extern const SimpleArrayConfig mf_desfire_file_settings_array_config; +extern const SimpleArrayConfig mf_desfire_file_data_array_config; +extern const SimpleArrayConfig mf_desfire_file_data_element_array_config; +extern const SimpleArrayConfig mf_desfire_application_array_config; + +// Parse internal MfDesfire structures + +void mf_desfire_version_parse(MfDesfireVersion* data, const BitBuffer* buf); + +void mf_desfire_free_memory_parse(MfDesfireFreeMemory* data, const BitBuffer* buf); + +void mf_desfire_key_settings_parse(MfDesfireKeySettings* data, const BitBuffer* buf); + +void mf_desfire_key_version_parse(MfDesfireKeyVersion* data, const BitBuffer* buf); + +void mf_desfire_application_id_parse( + MfDesfireApplicationId data, + uint32_t index, + const BitBuffer* buf); + +void mf_desfire_file_id_parse(MfDesfireFileId* data, uint32_t index, const BitBuffer* buf); + +void mf_desfire_file_settings_parse(MfDesfireFileSettings* data, const BitBuffer* buf); + +void mf_desfire_file_data_parse(MfDesfireFileData* data, const BitBuffer* buf); + +// Init internal MfDesfire structures + +void mf_desfire_file_data_init(MfDesfireFileData* data); + +void mf_desfire_application_init(MfDesfireApplication* data); + +// Reset internal MfDesfire structures + +void mf_desfire_file_data_reset(MfDesfireFileData* data); + +void mf_desfire_application_reset(MfDesfireApplication* data); + +// Copy internal MfDesfire structures + +void mf_desfire_file_data_copy(MfDesfireFileData* data, const MfDesfireFileData* other); + +void mf_desfire_application_copy(MfDesfireApplication* data, const MfDesfireApplication* other); diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c b/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c index 45062163ad95..a901f4a736b9 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c @@ -76,7 +76,7 @@ static MfDesfirePollerCommand mf_desfire_poller_async_read_free_memory(instance, &instance->data->free_memory); if(instance->error == MfDesfireErrorNone) { FURI_LOG_D(TAG, "Read free memory success"); - instance->state = MfDesfirePollerStateReadMasterKey; + instance->state = MfDesfirePollerStateReadMasterKeySettings; } else { FURI_LOG_E(TAG, "Failed to read free memory"); iso14443_4a_poller_halt(instance->iso14443_4a_poller); @@ -87,14 +87,64 @@ static MfDesfirePollerCommand } static MfDesfirePollerCommand - mf_desfire_poller_handler_read_master_key(MfDesfirePoller* instance) { + mf_desfire_poller_handler_read_master_key_settings(MfDesfirePoller* instance) { instance->error = - mf_desfire_poller_async_read_key_configuration(instance, &instance->data->master_key); + mf_desfire_poller_async_read_key_settings(instance, &instance->data->master_key_settings); if(instance->error == MfDesfireErrorNone) { FURI_LOG_D(TAG, "Read master key settings success"); + instance->state = MfDesfirePollerStateReadMasterKeyVersion; + } else { + FURI_LOG_E(TAG, "Failed to read master key settings"); + iso14443_4a_poller_halt(instance->iso14443_4a_poller); + instance->state = MfDesfirePollerStateReadFailed; + } + + return MfDesfirePollerCommandContinue; +} + +static MfDesfirePollerCommand + mf_desfire_poller_handler_read_master_key_version(MfDesfirePoller* instance) { + instance->error = mf_desfire_poller_async_read_key_versions( + instance, + instance->data->master_key_versions, + instance->data->master_key_settings.max_keys); + if(instance->error == MfDesfireErrorNone) { + FURI_LOG_D(TAG, "Read master key version success"); + instance->state = MfDesfirePollerStateReadApplicationIds; + } else { + FURI_LOG_E(TAG, "Failed to read master key version"); + iso14443_4a_poller_halt(instance->iso14443_4a_poller); + instance->state = MfDesfirePollerStateReadFailed; + } + + return MfDesfirePollerCommandContinue; +} + +static MfDesfirePollerCommand + mf_desfire_poller_handler_read_application_ids(MfDesfirePoller* instance) { + instance->error = + mf_desfire_poller_async_read_application_ids(instance, instance->data->application_ids); + if(instance->error == MfDesfireErrorNone) { + FURI_LOG_D(TAG, "Read application ids success"); + instance->state = MfDesfirePollerStateReadApplications; + } else { + FURI_LOG_E(TAG, "Failed to read application ids"); + iso14443_4a_poller_halt(instance->iso14443_4a_poller); + instance->state = MfDesfirePollerStateReadFailed; + } + + return MfDesfirePollerCommandContinue; +} + +static MfDesfirePollerCommand + mf_desfire_poller_handler_read_applications(MfDesfirePoller* instance) { + instance->error = mf_desfire_poller_async_read_applications( + instance, instance->data->application_ids, instance->data->applications); + if(instance->error == MfDesfireErrorNone) { + FURI_LOG_D(TAG, "Read applications success"); instance->state = MfDesfirePollerStateReadSuccess; } else { - FURI_LOG_E(TAG, "Failed to read key settings"); + FURI_LOG_E(TAG, "Failed to read applications"); iso14443_4a_poller_halt(instance->iso14443_4a_poller); instance->state = MfDesfirePollerStateReadFailed; } @@ -124,7 +174,11 @@ static const MfDesfirePollerReadHandler mf_desfire_poller_read_handler[MfDesfire [MfDesfirePollerStateIdle] = mf_desfire_poller_handler_idle, [MfDesfirePollerStateReadVersion] = mf_desfire_poller_handler_read_version, [MfDesfirePollerStateReadFreeMemory] = mf_desfire_poller_handler_read_free_memory, - [MfDesfirePollerStateReadMasterKey] = mf_desfire_poller_handler_read_master_key, + [MfDesfirePollerStateReadMasterKeySettings] = + mf_desfire_poller_handler_read_master_key_settings, + [MfDesfirePollerStateReadMasterKeyVersion] = mf_desfire_poller_handler_read_master_key_version, + [MfDesfirePollerStateReadApplicationIds] = mf_desfire_poller_handler_read_application_ids, + [MfDesfirePollerStateReadApplications] = mf_desfire_poller_handler_read_applications, [MfDesfirePollerStateReadFailed] = mf_desfire_poller_handler_read_fail, [MfDesfirePollerStateReadSuccess] = mf_desfire_poller_handler_read_success, }; diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c b/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c index 5c8e8600d1d3..07886ad954d7 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c @@ -2,6 +2,8 @@ #include +#include "mf_desfire_i.h" + #define TAG "MfDesfirePoller" MfDesfireError mf_desfire_process_error(Iso14443_4aError error) { @@ -40,12 +42,16 @@ MfDesfireError mf_desfire_send_chunks( break; } - const uint8_t flag_has_next = MF_DESFIRE_FLAG_HAS_NEXT; + bit_buffer_reset(instance->tx_buffer); + bit_buffer_append_byte(instance->tx_buffer, MF_DESFIRE_FLAG_HAS_NEXT); - bit_buffer_copy_bytes(instance->tx_buffer, &flag_has_next, sizeof(flag_has_next)); - bit_buffer_copy_right(rx_buffer, instance->rx_buffer, sizeof(flag_has_next)); + if(bit_buffer_get_size_bytes(instance->rx_buffer) > sizeof(uint8_t)) { + bit_buffer_copy_right(rx_buffer, instance->rx_buffer, sizeof(uint8_t)); + } else { + bit_buffer_reset(rx_buffer); + } - while(bit_buffer_starts_with_byte(instance->rx_buffer, flag_has_next)) { + while(bit_buffer_starts_with_byte(instance->rx_buffer, MF_DESFIRE_FLAG_HAS_NEXT)) { Iso14443_4aError error = iso14443_4a_poller_send_block( instance->iso14443_4a_poller, instance->tx_buffer, instance->rx_buffer, fwt); @@ -54,7 +60,7 @@ MfDesfireError mf_desfire_send_chunks( break; } - bit_buffer_append_right(rx_buffer, instance->rx_buffer, sizeof(flag_has_next)); + bit_buffer_append_right(rx_buffer, instance->rx_buffer, sizeof(uint8_t)); } } while(false); @@ -65,8 +71,8 @@ MfDesfireError mf_desfire_poller_async_read_version(MfDesfirePoller* instance, MfDesfireVersion* data) { furi_assert(instance); - const uint8_t cmd = MF_DESFIRE_CMD_GET_VERSION; - bit_buffer_copy_bytes(instance->input_buffer, &cmd, sizeof(cmd)); + bit_buffer_reset(instance->input_buffer); + bit_buffer_append_byte(instance->input_buffer, MF_DESFIRE_CMD_GET_VERSION); MfDesfireError error = mf_desfire_send_chunks( instance, @@ -75,7 +81,7 @@ MfDesfireError MF_DESFIRE_POLLER_STANDARD_FWT_FC); if(error == MfDesfireErrorNone) { - bit_buffer_write_bytes(instance->result_buffer, data, sizeof(*data)); + mf_desfire_version_parse(data, instance->result_buffer); } return error; @@ -85,8 +91,8 @@ MfDesfireError mf_desfire_poller_async_read_free_memory(MfDesfirePoller* instance, MfDesfireFreeMemory* data) { furi_assert(instance); - const uint8_t cmd = MF_DESFIRE_CMD_GET_FREE_MEMORY; - bit_buffer_copy_bytes(instance->input_buffer, &cmd, sizeof(cmd)); + bit_buffer_reset(instance->input_buffer); + bit_buffer_append_byte(instance->input_buffer, MF_DESFIRE_CMD_GET_FREE_MEMORY); MfDesfireError error = mf_desfire_send_chunks( instance, @@ -95,12 +101,7 @@ MfDesfireError MF_DESFIRE_POLLER_STANDARD_FWT_FC); if(error == MfDesfireErrorNone) { - bit_buffer_write_bytes( - instance->result_buffer, &data->bytes_free, sizeof(data->bytes_free) - 1); - data->bytes_free &= 0x00ffffff; - data->is_present = true; - } else { - data->is_present = false; + mf_desfire_free_memory_parse(data, instance->result_buffer); } return error; @@ -110,10 +111,9 @@ MfDesfireError mf_desfire_poller_async_read_key_settings( MfDesfirePoller* instance, MfDesfireKeySettings* data) { furi_assert(instance); - furi_assert(data); - bit_buffer_set_size_bytes(instance->input_buffer, sizeof(uint8_t)); - bit_buffer_set_byte(instance->input_buffer, 0, MF_DESFIRE_CMD_GET_KEY_SETTINGS); + bit_buffer_reset(instance->input_buffer); + bit_buffer_append_byte(instance->input_buffer, MF_DESFIRE_CMD_GET_KEY_SETTINGS); MfDesfireError error = mf_desfire_send_chunks( instance, @@ -122,26 +122,28 @@ MfDesfireError mf_desfire_poller_async_read_key_settings( MF_DESFIRE_POLLER_STANDARD_FWT_FC); if(error == MfDesfireErrorNone) { - bit_buffer_write_bytes(instance->result_buffer, data, sizeof(*data)); + mf_desfire_key_settings_parse(data, instance->result_buffer); } return error; } -MfDesfireError mf_desfire_poller_async_read_key_version( +MfDesfireError mf_desfire_poller_async_read_key_versions( MfDesfirePoller* instance, - MfDesfireKeyVersion* data, - size_t key_count) { + SimpleArray* data, + uint32_t count) { furi_assert(instance); - furi_assert(data); + furi_assert(count > 0); - MfDesfireError error = MfDesfireErrorNone; + simple_array_init(data, count); bit_buffer_set_size_bytes(instance->input_buffer, sizeof(uint8_t) * 2); bit_buffer_set_byte(instance->input_buffer, 0, MF_DESFIRE_CMD_GET_KEY_VERSION); - for(size_t key_id = 0; key_id < key_count; ++key_id) { - bit_buffer_set_byte(instance->input_buffer, 1, key_id); + MfDesfireError error = MfDesfireErrorNone; + + for(uint32_t i = 0; i < count; ++i) { + bit_buffer_set_byte(instance->input_buffer, 1, i); error = mf_desfire_send_chunks( instance, @@ -149,34 +151,315 @@ MfDesfireError mf_desfire_poller_async_read_key_version( instance->result_buffer, MF_DESFIRE_POLLER_STANDARD_FWT_FC); - if(error == MfDesfireErrorNone) { - data[key_id] = bit_buffer_get_byte(instance->result_buffer, 0); - } else { - break; + if(error != MfDesfireErrorNone) break; + + mf_desfire_key_version_parse(simple_array_get(data, i), instance->result_buffer); + } + + return error; +} + +MfDesfireError + mf_desfire_poller_async_read_application_ids(MfDesfirePoller* instance, SimpleArray* data) { + furi_assert(instance); + + bit_buffer_reset(instance->input_buffer); + bit_buffer_append_byte(instance->input_buffer, MF_DESFIRE_CMD_GET_APPLICATION_IDS); + + MfDesfireError error; + + do { + error = mf_desfire_send_chunks( + instance, + instance->input_buffer, + instance->result_buffer, + MF_DESFIRE_POLLER_STANDARD_FWT_FC); + + if(error != MfDesfireErrorNone) break; + + const uint32_t app_id_count = + bit_buffer_get_size_bytes(instance->result_buffer) / sizeof(MfDesfireApplicationId); + if(app_id_count == 0) break; + + simple_array_init(data, app_id_count); + + for(uint32_t i = 0; i < app_id_count; ++i) { + mf_desfire_application_id_parse(simple_array_get(data, i), i, instance->result_buffer); } + } while(false); + + return error; +} + +MfDesfireError mf_desfire_poller_async_select_application( + MfDesfirePoller* instance, + const MfDesfireApplicationId id) { + furi_assert(instance); + + bit_buffer_reset(instance->input_buffer); + bit_buffer_append_byte(instance->input_buffer, MF_DESFIRE_CMD_SELECT_APPLICATION); + bit_buffer_append_bytes(instance->input_buffer, id, sizeof(MfDesfireApplicationId)); + + MfDesfireError error = mf_desfire_send_chunks( + instance, + instance->input_buffer, + instance->result_buffer, + MF_DESFIRE_POLLER_STANDARD_FWT_FC); + + return error; +} + +MfDesfireError + mf_desfire_poller_async_read_file_ids(MfDesfirePoller* instance, SimpleArray* data) { + furi_assert(instance); + + bit_buffer_reset(instance->input_buffer); + bit_buffer_append_byte(instance->input_buffer, MF_DESFIRE_CMD_GET_FILE_IDS); + + MfDesfireError error; + + do { + error = mf_desfire_send_chunks( + instance, + instance->input_buffer, + instance->result_buffer, + MF_DESFIRE_POLLER_STANDARD_FWT_FC); + + if(error != MfDesfireErrorNone) break; + + const uint32_t id_count = + bit_buffer_get_size_bytes(instance->result_buffer) / sizeof(MfDesfireFileId); + + if(id_count == 0) break; + simple_array_init(data, id_count); + + for(uint32_t i = 0; i < id_count; ++i) { + mf_desfire_file_id_parse(simple_array_get(data, i), i, instance->result_buffer); + } + } while(false); + + return error; +} + +MfDesfireError mf_desfire_poller_async_read_file_settings( + MfDesfirePoller* instance, + MfDesfireFileId id, + MfDesfireFileSettings* data) { + furi_assert(instance); + + bit_buffer_reset(instance->input_buffer); + bit_buffer_append_byte(instance->input_buffer, MF_DESFIRE_CMD_GET_FILE_SETTINGS); + bit_buffer_append_byte(instance->input_buffer, id); + + MfDesfireError error = mf_desfire_send_chunks( + instance, + instance->input_buffer, + instance->result_buffer, + MF_DESFIRE_POLLER_STANDARD_FWT_FC); + + if(error == MfDesfireErrorNone) { + mf_desfire_file_settings_parse(data, instance->result_buffer); } return error; } -MfDesfireError mf_desfire_poller_async_read_key_configuration( +MfDesfireError mf_desfire_poller_async_read_file_settings_multi( MfDesfirePoller* instance, - MfDesfireKeyConfiguration* data) { + const SimpleArray* file_ids, + SimpleArray* data) { furi_assert(instance); - furi_assert(data); - furi_assert(data->key_versions == NULL); MfDesfireError error = MfDesfireErrorNone; + const uint32_t file_id_count = simple_array_get_count(file_ids); + if(file_id_count > 0) { + simple_array_init(data, file_id_count); + } + + for(uint32_t i = 0; i < file_id_count; ++i) { + const MfDesfireFileId file_id = *(const MfDesfireFileId*)simple_array_cget(file_ids, i); + error = mf_desfire_poller_async_read_file_settings( + instance, file_id, simple_array_get(data, i)); + if(error != MfDesfireErrorNone) break; + } + + return error; +} + +MfDesfireError mf_desfire_poller_async_read_file_data( + MfDesfirePoller* instance, + MfDesfireFileId id, + uint32_t offset, + size_t size, + MfDesfireFileData* data) { + furi_assert(instance); + + bit_buffer_reset(instance->input_buffer); + bit_buffer_append_byte(instance->input_buffer, MF_DESFIRE_CMD_READ_DATA); + bit_buffer_append_byte(instance->input_buffer, id); + bit_buffer_append_bytes(instance->input_buffer, (const uint8_t*)&offset, 3); + bit_buffer_append_bytes(instance->input_buffer, (const uint8_t*)&size, 3); + + MfDesfireError error = mf_desfire_send_chunks( + instance, + instance->input_buffer, + instance->result_buffer, + MF_DESFIRE_POLLER_STANDARD_FWT_FC); + + if(error == MfDesfireErrorNone) { + mf_desfire_file_data_parse(data, instance->result_buffer); + } + + return error; +} + +MfDesfireError mf_desfire_poller_async_read_file_value( + MfDesfirePoller* instance, + MfDesfireFileId id, + MfDesfireFileData* data) { + furi_assert(instance); + + bit_buffer_reset(instance->input_buffer); + bit_buffer_append_byte(instance->input_buffer, MF_DESFIRE_CMD_GET_VALUE); + bit_buffer_append_byte(instance->input_buffer, id); + + MfDesfireError error = mf_desfire_send_chunks( + instance, + instance->input_buffer, + instance->result_buffer, + MF_DESFIRE_POLLER_STANDARD_FWT_FC); + + if(error == MfDesfireErrorNone) { + mf_desfire_file_data_parse(data, instance->result_buffer); + } + + return error; +} + +MfDesfireError mf_desfire_poller_async_read_file_records( + MfDesfirePoller* instance, + MfDesfireFileId id, + uint32_t offset, + size_t size, + MfDesfireFileData* data) { + furi_assert(instance); + + bit_buffer_reset(instance->input_buffer); + bit_buffer_append_byte(instance->input_buffer, MF_DESFIRE_CMD_READ_DATA); + bit_buffer_append_byte(instance->input_buffer, id); + bit_buffer_append_bytes(instance->input_buffer, (const uint8_t*)&offset, 3); + bit_buffer_append_bytes(instance->input_buffer, (const uint8_t*)&size, 3); + + MfDesfireError error = mf_desfire_send_chunks( + instance, + instance->input_buffer, + instance->result_buffer, + MF_DESFIRE_POLLER_STANDARD_FWT_FC); + + if(error == MfDesfireErrorNone) { + mf_desfire_file_data_parse(data, instance->result_buffer); + } + + return error; +} + +MfDesfireError mf_desfire_poller_async_read_file_data_multi( + MfDesfirePoller* instance, + const SimpleArray* file_ids, + const SimpleArray* file_settings, + SimpleArray* data) { + furi_assert(instance); + furi_assert(simple_array_get_count(file_ids) == simple_array_get_count(file_settings)); + + MfDesfireError error = MfDesfireErrorNone; + + const uint32_t file_id_count = simple_array_get_count(file_ids); + if(file_id_count > 0) { + simple_array_init(data, file_id_count); + } + + for(uint32_t i = 0; i < file_id_count; ++i) { + const MfDesfireFileId file_id = *(const MfDesfireFileId*)simple_array_cget(file_ids, i); + const MfDesfireFileSettings* file_settings_cur = simple_array_cget(file_settings, i); + const MfDesfireFileType file_type = file_settings_cur->type; + + MfDesfireFileData* file_data = simple_array_get(data, i); + + if(file_type == MfDesfireFileTypeStandard || file_type == MfDesfireFileTypeBackup) { + error = mf_desfire_poller_async_read_file_data( + instance, file_id, 0, file_settings_cur->data.size, file_data); + } else if(file_type == MfDesfireFileTypeValue) { + error = mf_desfire_poller_async_read_file_value(instance, file_id, file_data); + } else if( + file_type == MfDesfireFileTypeLinearRecord || + file_type == MfDesfireFileTypeCyclicRecord) { + error = mf_desfire_poller_async_read_file_records( + instance, file_id, 0, file_settings_cur->data.size, file_data); + } + + if(error != MfDesfireErrorNone) break; + } + + return error; +} + +MfDesfireError mf_desfire_poller_async_read_application( + MfDesfirePoller* instance, + MfDesfireApplication* data) { + furi_assert(instance); + furi_assert(data); + + MfDesfireError error; + do { error = mf_desfire_poller_async_read_key_settings(instance, &data->key_settings); if(error != MfDesfireErrorNone) break; - const uint8_t key_count = data->key_settings.max_keys; - data->key_versions = malloc(sizeof(MfDesfireKeyVersion) * key_count); + error = mf_desfire_poller_async_read_key_versions( + instance, data->key_versions, data->key_settings.max_keys); + if(error != MfDesfireErrorNone) break; + + error = mf_desfire_poller_async_read_file_ids(instance, data->file_ids); + if(error != MfDesfireErrorNone) break; + + error = mf_desfire_poller_async_read_file_settings_multi( + instance, data->file_ids, data->file_settings); + if(error != MfDesfireErrorNone) break; + + error = mf_desfire_poller_async_read_file_data_multi( + instance, data->file_ids, data->file_settings, data->file_data); + if(error != MfDesfireErrorNone) break; - error = mf_desfire_poller_async_read_key_version(instance, data->key_versions, key_count); } while(false); return error; } + +MfDesfireError mf_desfire_poller_async_read_applications( + MfDesfirePoller* instance, + const SimpleArray* app_ids, + SimpleArray* data) { + furi_assert(instance); + + MfDesfireError error = MfDesfireErrorNone; + + const uint32_t app_id_count = simple_array_get_count(app_ids); + if(app_id_count > 0) { + simple_array_init(data, app_id_count); + } + + for(uint32_t i = 0; i < app_id_count; ++i) { + do { + error = mf_desfire_poller_async_select_application( + instance, simple_array_cget(app_ids, i)); + if(error != MfDesfireErrorNone) break; + + MfDesfireApplication* current_app = simple_array_get(data, i); + error = mf_desfire_poller_async_read_application(instance, current_app); + + } while(false); + } + + return error; +} diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.h b/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.h index 80aae51883fe..96c456cc5954 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.h +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.h @@ -8,13 +8,16 @@ extern "C" { #endif -#define MF_DESFIRE_POLLER_STANDARD_FWT_FC (60000) +#define MF_DESFIRE_POLLER_STANDARD_FWT_FC (190000) typedef enum { MfDesfirePollerStateIdle, MfDesfirePollerStateReadVersion, MfDesfirePollerStateReadFreeMemory, - MfDesfirePollerStateReadMasterKey, + MfDesfirePollerStateReadMasterKeySettings, + MfDesfirePollerStateReadMasterKeyVersion, + MfDesfirePollerStateReadApplicationIds, + MfDesfirePollerStateReadApplications, MfDesfirePollerStateReadFailed, MfDesfirePollerStateReadSuccess, @@ -59,14 +62,62 @@ MfDesfireError mf_desfire_poller_async_read_key_settings( MfDesfirePoller* instance, MfDesfireKeySettings* data); -MfDesfireError mf_desfire_poller_async_read_key_version( +MfDesfireError mf_desfire_poller_async_read_key_versions( MfDesfirePoller* instance, - MfDesfireKeyVersion* data, - size_t key_count); + SimpleArray* data, + uint32_t count); -MfDesfireError mf_desfire_poller_async_read_key_configuration( +MfDesfireError + mf_desfire_poller_async_read_application_ids(MfDesfirePoller* instance, SimpleArray* data); + +MfDesfireError mf_desfire_poller_async_select_application( + MfDesfirePoller* instance, + const MfDesfireApplicationId id); + +MfDesfireError mf_desfire_poller_async_read_file_ids(MfDesfirePoller* instance, SimpleArray* data); + +MfDesfireError mf_desfire_poller_async_read_file_settings( + MfDesfirePoller* instance, + MfDesfireFileId id, + MfDesfireFileSettings* data); + +MfDesfireError mf_desfire_poller_async_read_file_settings_multi( + MfDesfirePoller* instance, + const SimpleArray* file_ids, + SimpleArray* data); + +MfDesfireError mf_desfire_poller_async_read_file_data( + MfDesfirePoller* instance, + MfDesfireFileId id, + uint32_t offset, + size_t size, + MfDesfireFileData* data); + +MfDesfireError mf_desfire_poller_async_read_file_value( + MfDesfirePoller* instance, + MfDesfireFileId id, + MfDesfireFileData* data); + +MfDesfireError mf_desfire_poller_async_read_file_records( + MfDesfirePoller* instance, + MfDesfireFileId id, + uint32_t offset, + size_t size, + MfDesfireFileData* data); + +MfDesfireError mf_desfire_poller_async_read_file_data_multi( + MfDesfirePoller* instance, + const SimpleArray* file_ids, + const SimpleArray* file_settings, + SimpleArray* data); + +MfDesfireError + mf_desfire_poller_async_read_application(MfDesfirePoller* instance, MfDesfireApplication* data); + +MfDesfireError mf_desfire_poller_async_read_applications( MfDesfirePoller* instance, - MfDesfireKeyConfiguration* data); + const SimpleArray* app_ids, + SimpleArray* data); #ifdef __cplusplus } From fe5b04326cd292839874d27c3ef0c180b668e9a0 Mon Sep 17 00:00:00 2001 From: gornekich Date: Tue, 20 Jun 2023 16:46:29 +0400 Subject: [PATCH 105/149] Gornek/generic poller v3 (#2780) * nfc: introduce poller manager * nfc: rework nfca poller with poller manager * nfc: working nfca read * nfc: rework mfu poller with poller manager * nfc: remove unused code * nfc: add detect poller api * nfc: implement detect in nfca poller * nfc: implement detect in mfu poller --- applications/main/nfc/nfc_app.c | 5 +- applications/main/nfc/nfc_app_i.h | 7 +- .../nfc/scenes/nfc_scene_mf_ultralight_read.c | 131 ++++-- .../main/nfc/scenes/nfc_scene_nfca_read.c | 62 ++- applications/main/nfc/scenes/nfc_scene_read.c | 20 +- firmware/targets/f7/api_symbols.csv | 7 + lib/nfc/nfc_poller.c | 96 ++--- lib/nfc/nfc_poller.h | 38 +- lib/nfc/nfc_poller_base.h | 41 ++ lib/nfc/nfc_poller_defs.c | 61 +++ lib/nfc/nfc_poller_defs.h | 22 + lib/nfc/nfc_poller_manager.c | 229 +++++++++++ lib/nfc/nfc_poller_manager.h | 27 ++ .../iso14443_4a/iso14443_4a_poller_i.c | 21 + .../iso14443_4a/iso14443_4a_poller_i.h | 2 + .../mf_ultralight/mf_ultralight_poller.c | 3 - .../mf_ultralight/mf_ultralight_poller.h | 5 + .../mf_ultralight/mf_ultralight_poller_i.c | 384 ++++++++++++++++++ .../mf_ultralight/mf_ultralight_poller_i.h | 16 +- .../mf_ultralight_poller_sync_api.c | 51 +++ lib/nfc/protocols/nfc_protocol_defs.h | 2 + lib/nfc/protocols/nfca/nfca_poller.c | 36 ++ lib/nfc/protocols/nfca/nfca_poller.h | 4 + lib/nfc/protocols/nfca/nfca_poller_i.c | 120 ++++++ lib/nfc/protocols/nfca/nfca_poller_i.h | 9 +- lib/nfc/protocols/nfcb/nfcb_poller_i .c | 6 + lib/nfc/protocols/nfcb/nfcb_poller_i.h | 14 + 27 files changed, 1274 insertions(+), 145 deletions(-) create mode 100644 lib/nfc/nfc_poller_base.h create mode 100644 lib/nfc/nfc_poller_defs.c create mode 100644 lib/nfc/nfc_poller_defs.h create mode 100644 lib/nfc/nfc_poller_manager.c create mode 100644 lib/nfc/nfc_poller_manager.h create mode 100644 lib/nfc/protocols/nfcb/nfcb_poller_i .c create mode 100644 lib/nfc/protocols/nfcb/nfcb_poller_i.h diff --git a/applications/main/nfc/nfc_app.c b/applications/main/nfc/nfc_app.c index 9c32dca5f63d..804fd35be1f1 100644 --- a/applications/main/nfc/nfc_app.c +++ b/applications/main/nfc/nfc_app.c @@ -57,13 +57,15 @@ NfcApp* nfc_app_alloc() { instance->parsed_data = furi_string_alloc(); - NfcPollerCollection collection = { + NfcPollerOldCollection collection = { .nfc = instance->nfc, .nfca_poller = instance->nfca_poller, .nfcb_poller = instance->nfcb_poller, }; instance->nfc_poller = nfc_poller_alloc(&collection); + instance->poller_manager = nfc_poller_manager_alloc(instance->nfc); + instance->mf_ul_auth = mf_ultralight_auth_alloc(); // Nfc device @@ -174,6 +176,7 @@ void nfc_app_free(NfcApp* instance) { nfcb_poller_free(instance->nfcb_poller); nfc_poller_free(instance->nfc_poller); nfc_free(instance->nfc); + nfc_poller_manager_free(instance->poller_manager); mf_ultralight_auth_free(instance->mf_ul_auth); diff --git a/applications/main/nfc/nfc_app_i.h b/applications/main/nfc/nfc_app_i.h index ea4893bc8876..81d5cf089190 100644 --- a/applications/main/nfc/nfc_app_i.h +++ b/applications/main/nfc/nfc_app_i.h @@ -48,6 +48,9 @@ #include #include +#include +#include + #include #include @@ -111,7 +114,9 @@ struct NfcApp { MfDesfirePoller* mf_desfire_poller; MfClassicPoller* mf_classic_poller; NfcbPoller* nfcb_poller; - NfcPoller* nfc_poller; + NfcPollerOld* nfc_poller; + + NfcPollerManager* poller_manager; MfUltralightAuth* mf_ul_auth; NfcMfClassicDictAttackContext mf_dict_context; diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read.c index e9664d9fbf7a..7457e4fd4047 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read.c @@ -5,72 +5,120 @@ enum { NfcWorkerEventMfUltralightReadSuccess, }; -MfUltralightPollerCommand - nfc_scene_mf_ultralight_read_worker_callback(MfUltralightPollerEvent event, void* context) { - NfcApp* nfc = context; +// MfUltralightPollerCommand +// nfc_scene_mf_ultralight_read_worker_callback(MfUltralightPollerEvent event, void* context) { +// NfcApp* nfc = context; - MfUltralightPollerCommand command = MfUltralightPollerCommandContinue; +// MfUltralightPollerCommand command = MfUltralightPollerCommandContinue; - if(event.type == MfUltralightPollerEventTypeReadSuccess) { +// if(event.type == MfUltralightPollerEventTypeReadSuccess) { +// view_dispatcher_send_custom_event( +// nfc->view_dispatcher, NfcWorkerEventMfUltralightReadSuccess); +// command = MfUltralightPollerCommandStop; +// } else if(event.type == MfUltralightPollerEventTypeAuthRequest) { +// nfc_dev_set_protocol_data( +// nfc->nfc_dev, +// NfcProtocolTypeMfUltralight, +// mf_ultralight_poller_get_data(nfc->mf_ul_poller)); +// const MfUltralightData* data = +// nfc_dev_get_protocol_data(nfc->nfc_dev, NfcProtocolTypeMfUltralight); +// if(nfc->mf_ul_auth->type == MfUltralightAuthTypeXiaomii) { +// if(mf_ultralight_generate_xiaomi_pass( +// nfc->mf_ul_auth, data->nfca_data->uid, data->nfca_data->uid_len)) { +// event.data->auth_context.skip_auth = false; +// } +// } else if(nfc->mf_ul_auth->type == MfUltralightAuthTypeAmiibo) { +// if(mf_ultralight_generate_amiibo_pass( +// nfc->mf_ul_auth, data->nfca_data->uid, data->nfca_data->uid_len)) { +// event.data->auth_context.skip_auth = false; +// } +// } else if(nfc->mf_ul_auth->type == MfUltralightAuthTypeManual) { +// event.data->auth_context.skip_auth = false; +// } else { +// event.data->auth_context.skip_auth = true; +// } +// if(!event.data->auth_context.skip_auth) { +// event.data->auth_context.password = nfc->mf_ul_auth->password; +// } +// } else if(event.type == MfUltralightPollerEventTypeAuthSuccess) { +// nfc->mf_ul_auth->pack = event.data->auth_context.pack; +// } + +// return command; +// } + +NfcCommand nfc_scene_mf_ultralight_read_worker_callback(NfcPollerEvent event, void* context) { + furi_assert(context); + furi_assert(event.poller); + furi_assert(event.data); + + NfcApp* instance = context; + const NfcPollerBase* poller_api = nfc_pollers_api[event.protocol_type]; + MfUltralightPollerEvent* mfu_event = event.data; + + NfcCommand command = NfcCommandContinue; + + if(mfu_event->type == MfUltralightPollerEventTypeReadSuccess) { + nfc_dev_set_protocol_data( + instance->nfc_dev, event.protocol_type, poller_api->get_data(event.poller)); view_dispatcher_send_custom_event( - nfc->view_dispatcher, NfcWorkerEventMfUltralightReadSuccess); - command = MfUltralightPollerCommandStop; - } else if(event.type == MfUltralightPollerEventTypeAuthRequest) { + instance->view_dispatcher, NfcWorkerEventMfUltralightReadSuccess); + command = NfcCommandStop; + } else if(mfu_event->type == MfUltralightPollerEventTypeAuthRequest) { nfc_dev_set_protocol_data( - nfc->nfc_dev, - NfcProtocolTypeMfUltralight, - mf_ultralight_poller_get_data(nfc->mf_ul_poller)); + instance->nfc_dev, event.protocol_type, poller_api->get_data(event.poller)); const MfUltralightData* data = - nfc_dev_get_protocol_data(nfc->nfc_dev, NfcProtocolTypeMfUltralight); - if(nfc->mf_ul_auth->type == MfUltralightAuthTypeXiaomii) { + nfc_dev_get_protocol_data(instance->nfc_dev, NfcProtocolTypeMfUltralight); + if(instance->mf_ul_auth->type == MfUltralightAuthTypeXiaomii) { if(mf_ultralight_generate_xiaomi_pass( - nfc->mf_ul_auth, data->nfca_data->uid, data->nfca_data->uid_len)) { - event.data->auth_context.skip_auth = false; + instance->mf_ul_auth, data->nfca_data->uid, data->nfca_data->uid_len)) { + mfu_event->data->auth_context.skip_auth = false; } - } else if(nfc->mf_ul_auth->type == MfUltralightAuthTypeAmiibo) { + } else if(instance->mf_ul_auth->type == MfUltralightAuthTypeAmiibo) { if(mf_ultralight_generate_amiibo_pass( - nfc->mf_ul_auth, data->nfca_data->uid, data->nfca_data->uid_len)) { - event.data->auth_context.skip_auth = false; + instance->mf_ul_auth, data->nfca_data->uid, data->nfca_data->uid_len)) { + mfu_event->data->auth_context.skip_auth = false; } - } else if(nfc->mf_ul_auth->type == MfUltralightAuthTypeManual) { - event.data->auth_context.skip_auth = false; + } else if(instance->mf_ul_auth->type == MfUltralightAuthTypeManual) { + mfu_event->data->auth_context.skip_auth = false; } else { - event.data->auth_context.skip_auth = true; + mfu_event->data->auth_context.skip_auth = true; } - if(!event.data->auth_context.skip_auth) { - event.data->auth_context.password = nfc->mf_ul_auth->password; + if(!mfu_event->data->auth_context.skip_auth) { + mfu_event->data->auth_context.password = instance->mf_ul_auth->password; } - } else if(event.type == MfUltralightPollerEventTypeAuthSuccess) { - nfc->mf_ul_auth->pack = event.data->auth_context.pack; + } else if(mfu_event->type == MfUltralightPollerEventTypeAuthSuccess) { + instance->mf_ul_auth->pack = mfu_event->data->auth_context.pack; } return command; } void nfc_scene_mf_ultralight_read_on_enter(void* context) { - NfcApp* nfc = context; + NfcApp* instance = context; // Setup view - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup); - mf_ultralight_poller_read( - nfc->mf_ul_poller, nfc_scene_mf_ultralight_read_worker_callback, nfc); + // mf_ultralight_poller_read( + // instance->mf_ul_poller, nfc_scene_mf_ultralight_read_worker_callback, instance); + nfc_poller_manager_start( + instance->poller_manager, + NfcProtocolTypeMfUltralight, + nfc_scene_mf_ultralight_read_worker_callback, + instance); - nfc_blink_read_start(nfc); + nfc_blink_read_start(instance); } bool nfc_scene_mf_ultralight_read_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + NfcApp* instance = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { if(event.event == NfcWorkerEventMfUltralightReadSuccess) { - notification_message(nfc->notifications, &sequence_success); - nfc_dev_set_protocol_data( - nfc->nfc_dev, - NfcProtocolTypeMfUltralight, - mf_ultralight_poller_get_data(nfc->mf_ul_poller)); - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadSuccess); + notification_message(instance->notifications, &sequence_success); + scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightReadSuccess); DOLPHIN_DEED(DolphinDeedNfcReadSuccess); consumed = true; } @@ -79,11 +127,12 @@ bool nfc_scene_mf_ultralight_read_on_event(void* context, SceneManagerEvent even } void nfc_scene_mf_ultralight_read_on_exit(void* context) { - NfcApp* nfc = context; + NfcApp* instance = context; - mf_ultralight_poller_stop(nfc->mf_ul_poller); + // mf_ultralight_poller_stop(nfc->mf_ul_poller); + nfc_poller_manager_stop(instance->poller_manager); // Clear view - popup_reset(nfc->popup); + popup_reset(instance->popup); - nfc_blink_stop(nfc); + nfc_blink_stop(instance); } diff --git a/applications/main/nfc/scenes/nfc_scene_nfca_read.c b/applications/main/nfc/scenes/nfc_scene_nfca_read.c index 156e2edeeba9..12ec0198b26a 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfca_read.c +++ b/applications/main/nfc/scenes/nfc_scene_nfca_read.c @@ -5,40 +5,65 @@ enum { NfcWorkerEventReadUidNfcA = 100, }; -NfcaPollerCommand nfc_scene_nfca_read_worker_callback(NfcaPollerEvent event, void* context) { - NfcApp* nfc = context; +// NfcaPollerCommand nfc_scene_nfca_read_worker_callback(NfcaPollerEvent event, void* context) { +// NfcApp* nfc = context; - NfcaPollerCommand command = NfcaPollerCommandContinue; +// NfcaPollerCommand command = NfcaPollerCommandContinue; - if(event.type == NfcaPollerEventTypeReady) { +// if(event.type == NfcaPollerEventTypeReady) { +// nfc_dev_set_protocol_data( +// nfc->nfc_dev, NfcProtocolTypeIso14443_3a, nfca_poller_get_data(nfc->nfca_poller)); +// view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcWorkerEventReadUidNfcA); +// command = NfcaPollerCommandStop; +// } + +// return command; +// } + +NfcCommand nfc_scene_nfca_read_worker_callback(NfcPollerEvent event, void* context) { + furi_assert(context); + furi_assert(event.data); + furi_assert(event.poller); + + NfcApp* instance = context; + NfcCommand command = NfcCommandContinue; + NfcaPollerEvent* nfca_event = event.data; + const NfcPollerBase* poller_api = nfc_pollers_api[event.protocol_type]; + + if(nfca_event->type == NfcaPollerEventTypeReady) { nfc_dev_set_protocol_data( - nfc->nfc_dev, NfcProtocolTypeIso14443_3a, nfca_poller_get_data(nfc->nfca_poller)); - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcWorkerEventReadUidNfcA); - command = NfcaPollerCommandStop; + instance->nfc_dev, event.protocol_type, poller_api->get_data(event.poller)); + view_dispatcher_send_custom_event(instance->view_dispatcher, NfcWorkerEventReadUidNfcA); + command = NfcCommandStop; } return command; } void nfc_scene_nfca_read_on_enter(void* context) { - NfcApp* nfc = context; + NfcApp* instance = context; // Setup view - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup); - nfca_poller_start(nfc->nfca_poller, nfc_scene_nfca_read_worker_callback, nfc); + // nfca_poller_start(nfc->nfca_poller, nfc_scene_nfca_read_worker_callback, nfc); + nfc_poller_manager_start( + instance->poller_manager, + NfcProtocolTypeIso14443_3a, + nfc_scene_nfca_read_worker_callback, + instance); - nfc_blink_read_start(nfc); + nfc_blink_read_start(instance); } bool nfc_scene_nfca_read_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + NfcApp* instance = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { if(event.event == NfcWorkerEventReadUidNfcA) { - notification_message(nfc->notifications, &sequence_success); - scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcaReadSuccess); + notification_message(instance->notifications, &sequence_success); + scene_manager_next_scene(instance->scene_manager, NfcSceneNfcaReadSuccess); DOLPHIN_DEED(DolphinDeedNfcReadSuccess); consumed = true; } @@ -47,11 +72,12 @@ bool nfc_scene_nfca_read_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_nfca_read_on_exit(void* context) { - NfcApp* nfc = context; + NfcApp* instance = context; - nfca_poller_stop(nfc->nfca_poller); + // nfca_poller_stop(nfc->nfca_poller); + nfc_poller_manager_stop(instance->poller_manager); // Clear view - popup_reset(nfc->popup); + popup_reset(instance->popup); - nfc_blink_stop(nfc); + nfc_blink_stop(instance); } diff --git a/applications/main/nfc/scenes/nfc_scene_read.c b/applications/main/nfc/scenes/nfc_scene_read.c index c18f36a89cc7..b431cf5c7285 100644 --- a/applications/main/nfc/scenes/nfc_scene_read.c +++ b/applications/main/nfc/scenes/nfc_scene_read.c @@ -8,25 +8,25 @@ enum { NfcSceneReadEventMfDesfireDetected, }; -NfcPollerCommand nfc_scene_read_worker_callback(NfcPollerEvent event, void* context) { +NfcPollerOldCommand nfc_scene_read_worker_callback(NfcPollerOldEvent event, void* context) { NfcApp* nfc = context; - NfcPollerCommand command = NfcPollerCommandContinue; + NfcPollerOldCommand command = NfcPollerOldCommandContinue; - if(event == NfcPollerEventNfcaDetected) { + if(event == NfcPollerOldEventNfcaDetected) { view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcSceneReadEventNfcaDetected); - command = NfcPollerCommandStop; - } else if(event == NfcPollerEventNfcbDetected) { + command = NfcPollerOldCommandStop; + } else if(event == NfcPollerOldEventNfcbDetected) { view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcSceneReadEventNfcbDetected); - command = NfcPollerCommandStop; - } else if(event == NfcPollerEventMfUltralightDetected) { + command = NfcPollerOldCommandStop; + } else if(event == NfcPollerOldEventMfUltralightDetected) { view_dispatcher_send_custom_event( nfc->view_dispatcher, NfcSceneReadEventMfUltralightDetected); - command = NfcPollerCommandStop; - } else if(event == NfcPollerEventMfDesfireDetected) { + command = NfcPollerOldCommandStop; + } else if(event == NfcPollerOldEventMfDesfireDetected) { view_dispatcher_send_custom_event( nfc->view_dispatcher, NfcSceneReadEventMfDesfireDetected); - command = NfcPollerCommandStop; + command = NfcPollerOldCommandStop; } return command; diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 6956aa6e7d9b..c6272f9694de 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -2045,6 +2045,11 @@ Function,-,nfc_listener_abort,void,Nfc* Function,-,nfc_listener_set_col_res_data,NfcError,"Nfc*, uint8_t*, uint8_t, uint8_t*, uint8_t" Function,-,nfc_listener_sleep,NfcError,Nfc* Function,-,nfc_listener_tx,NfcError,"Nfc*, const BitBuffer*" +Function,-,nfc_poller_manager_alloc,NfcPollerManager*,Nfc* +Function,-,nfc_poller_manager_free,void,NfcPollerManager* +Function,-,nfc_poller_manager_scan,void,"NfcPollerManager*, NfcPollerCallback, void*" +Function,-,nfc_poller_manager_start,void,"NfcPollerManager*, NfcProtocolType, NfcPollerCallback, void*" +Function,-,nfc_poller_manager_stop,void,NfcPollerManager* Function,-,nfc_set_fdt_listen_fc,void,"Nfc*, uint32_t" Function,-,nfc_set_fdt_poll_fc,void,"Nfc*, uint32_t" Function,-,nfc_set_fdt_poll_poll_us,void,"Nfc*, uint32_t" @@ -2073,6 +2078,7 @@ Function,-,nfca_poller_alloc,NfcaPoller*,Nfc* Function,-,nfca_poller_free,void,NfcaPoller* Function,+,nfca_poller_get_data,const NfcaData*,NfcaPoller* Function,-,nfca_poller_read,NfcaError,"NfcaPoller*, NfcaData*" +Function,-,nfca_poller_read_new,NfcaError,"NfcPollerManager*, NfcaData*" Function,-,nfca_poller_start,NfcaError,"NfcaPoller*, NfcaPollerEventCallback, void*" Function,-,nfca_poller_stop,NfcaError,NfcaPoller* Function,+,nfca_reset,void,NfcaData* @@ -3329,6 +3335,7 @@ Variable,+,message_vibro_off,const NotificationMessage, Variable,+,message_vibro_on,const NotificationMessage, Variable,+,nfc_protocol_iso14443_3a,const NfcProtocolBase, Variable,+,nfc_protocol_mf_classic,const NfcProtocolBase, +Variable,-,nfc_protocols,const NfcProtocolBase*[], Variable,+,sequence_audiovisual_alert,const NotificationSequence, Variable,+,sequence_blink_blue_10,const NotificationSequence, Variable,+,sequence_blink_blue_100,const NotificationSequence, diff --git a/lib/nfc/nfc_poller.c b/lib/nfc/nfc_poller.c index 850479f1d2c4..1503d4edaa2c 100644 --- a/lib/nfc/nfc_poller.c +++ b/lib/nfc/nfc_poller.c @@ -8,38 +8,38 @@ #include typedef enum { - NfcPollerStateIdle, - NfcPollerStateCheckPresenceNfca, - NfcPollerStateCheckPresenceNfcb, - NfcPollerStateCheckPresenceNfcf, - NfcPollerStateCheckPresenceNfcv, -} NfcPollerState; + NfcPollerOldStateIdle, + NfcPollerOldStateCheckPresenceNfca, + NfcPollerOldStateCheckPresenceNfcb, + NfcPollerOldStateCheckPresenceNfcf, + NfcPollerOldStateCheckPresenceNfcv, +} NfcPollerOldState; typedef enum { - NfcPollerSessionStateIdle, - NfcPollerSessionStateActive, - NfcPollerSessionStateStopRequest, -} NfcPollerSessionState; + NfcPollerOldSessionStateIdle, + NfcPollerOldSessionStateActive, + NfcPollerOldSessionStateStopRequest, +} NfcPollerOldSessionState; -struct NfcPoller { +struct NfcPollerOld { Nfc* nfc; - NfcPollerSessionState session_state; + NfcPollerOldSessionState session_state; NfcaPoller* nfca_poller; NfcaData nfca_data; NfcbPoller* nfcb_poller; NfcbData nfcb_data; - NfcPollerState state; - NfcPollerEventCallback callback; + NfcPollerOldState state; + NfcPollerOldEventCallback callback; void* context; }; -NfcPoller* nfc_poller_alloc(NfcPollerCollection* pollers) { +NfcPollerOld* nfc_poller_alloc(NfcPollerOldCollection* pollers) { furi_assert(pollers); furi_assert(pollers->nfc); furi_assert(pollers->nfca_poller); furi_assert(pollers->nfcb_poller); - NfcPoller* instance = malloc(sizeof(NfcPoller)); + NfcPollerOld* instance = malloc(sizeof(NfcPollerOld)); instance->nfc = pollers->nfc; instance->nfca_poller = pollers->nfca_poller; instance->nfcb_poller = pollers->nfcb_poller; @@ -47,18 +47,18 @@ NfcPoller* nfc_poller_alloc(NfcPollerCollection* pollers) { return instance; } -void nfc_poller_free(NfcPoller* instance) { +void nfc_poller_free(NfcPollerOld* instance) { furi_assert(instance); } -static NfcCommand nfc_poller_process_command(NfcPollerCommand command) { +static NfcCommand nfc_poller_process_command(NfcPollerOldCommand command) { NfcCommand ret = NfcCommandContinue; - if(command == NfcPollerCommandContinue) { + if(command == NfcPollerOldCommandContinue) { ret = NfcCommandContinue; - } else if(command == NfcPollerCommandReset) { + } else if(command == NfcPollerOldCommandReset) { ret = NfcCommandReset; - } else if(command == NfcPollerCommandStop) { + } else if(command == NfcPollerOldCommandStop) { ret = NfcCommandStop; } else { furi_crash("Unknown command"); @@ -70,59 +70,59 @@ static NfcCommand nfc_poller_process_command(NfcPollerCommand command) { static NfcCommand nfc_poller_event_callback(NfcEvent event, void* context) { furi_assert(context); - NfcPoller* instance = context; + NfcPollerOld* instance = context; furi_assert(instance->callback); - furi_assert(instance->session_state != NfcPollerSessionStateIdle); + furi_assert(instance->session_state != NfcPollerOldSessionStateIdle); - NfcPollerEvent poller_event; - NfcPollerCommand command = NfcPollerCommandContinue; + NfcPollerOldEvent poller_event; + NfcPollerOldCommand command = NfcPollerOldCommandContinue; - if(instance->session_state == NfcPollerSessionStateStopRequest) { - command = NfcPollerCommandStop; + if(instance->session_state == NfcPollerOldSessionStateStopRequest) { + command = NfcPollerOldCommandStop; } else { if(event.type == NfcEventTypeConfigureRequest) { - if(instance->state == NfcPollerStateCheckPresenceNfca) { + if(instance->state == NfcPollerOldStateCheckPresenceNfca) { nfca_poller_config(instance->nfca_poller); - } else if(instance->state == NfcPollerStateCheckPresenceNfcb) { + } else if(instance->state == NfcPollerOldStateCheckPresenceNfcb) { // nfcb_poller_config(instance->nfcb_poller); } } else if(event.type == NfcEventTypePollerReady) { - if(instance->state == NfcPollerStateCheckPresenceNfca) { + if(instance->state == NfcPollerOldStateCheckPresenceNfca) { NfcaError error = nfca_poller_async_activate(instance->nfca_poller, &instance->nfca_data); if(error == NfcaErrorNone) { if(mf_ultralight_detect_protocol(&instance->nfca_data)) { - poller_event = NfcPollerEventMfUltralightDetected; + poller_event = NfcPollerOldEventMfUltralightDetected; } else if(mf_desfire_detect_protocol(&instance->nfca_data)) { - poller_event = NfcPollerEventMfDesfireDetected; + poller_event = NfcPollerOldEventMfDesfireDetected; } else { - poller_event = NfcPollerEventNfcaDetected; + poller_event = NfcPollerOldEventNfcaDetected; } command = instance->callback(poller_event, instance->context); } else { // Nfca not present FURI_LOG_E("TAG", "NOT PRESENT"); furi_delay_ms(100); - instance->state = NfcPollerStateCheckPresenceNfcb; - command = NfcPollerCommandReset; + instance->state = NfcPollerOldStateCheckPresenceNfcb; + command = NfcPollerOldCommandReset; } - } else if(instance->state == NfcPollerStateCheckPresenceNfcb) { + } else if(instance->state == NfcPollerOldStateCheckPresenceNfcb) { // NfcbError error = // nfcb_poller_activate(instance->nfcb_poller, &instance->nfcb_data); // if(error == NfcbErrorNone) { - // poller_event = NfcPollerEventNfcbDetected; + // poller_event = NfcPollerOldEventNfcbDetected; // instance->callback(poller_event, instance->context); // } else { // // Nfcb not present // furi_delay_ms(100); - instance->state = NfcPollerStateCheckPresenceNfca; + instance->state = NfcPollerOldStateCheckPresenceNfca; // command = NfcCommandReset; // } } } else if(event.type == NfcEventTypeReset) { - if(instance->state == NfcPollerStateCheckPresenceNfca) { + if(instance->state == NfcPollerOldStateCheckPresenceNfca) { nfca_poller_reset(instance->nfca_poller); - } else if(instance->state == NfcPollerStateCheckPresenceNfcb) { + } else if(instance->state == NfcPollerOldStateCheckPresenceNfcb) { // nfcb_poller_reset(instance->nfcb_poller); } } @@ -131,32 +131,32 @@ static NfcCommand nfc_poller_event_callback(NfcEvent event, void* context) { return nfc_poller_process_command(command); } -void nfc_poller_start(NfcPoller* instance, NfcPollerEventCallback callback, void* context) { +void nfc_poller_start(NfcPollerOld* instance, NfcPollerOldEventCallback callback, void* context) { furi_assert(instance); furi_assert(callback); - furi_assert(instance->session_state == NfcPollerSessionStateIdle); + furi_assert(instance->session_state == NfcPollerOldSessionStateIdle); instance->callback = callback; instance->context = context; - instance->state = NfcPollerStateCheckPresenceNfca; - instance->session_state = NfcPollerSessionStateActive; + instance->state = NfcPollerOldStateCheckPresenceNfca; + instance->session_state = NfcPollerOldSessionStateActive; instance->nfca_poller->data = malloc(sizeof(NfcaData)); nfc_start_poller(instance->nfc, nfc_poller_event_callback, instance); } -void nfc_poller_stop(NfcPoller* instance) { +void nfc_poller_stop(NfcPollerOld* instance) { furi_assert(instance); furi_assert(instance->nfc); - instance->session_state = NfcPollerSessionStateStopRequest; + instance->session_state = NfcPollerOldSessionStateStopRequest; nfc_stop(instance->nfc); - instance->session_state = NfcPollerSessionStateIdle; + instance->session_state = NfcPollerOldSessionStateIdle; free(instance->nfca_poller->data); instance->callback = NULL; instance->context = NULL; - instance->state = NfcPollerStateIdle; + instance->state = NfcPollerOldStateIdle; } diff --git a/lib/nfc/nfc_poller.h b/lib/nfc/nfc_poller.h index c1553e5a9f14..9b2eac3abf82 100644 --- a/lib/nfc/nfc_poller.h +++ b/lib/nfc/nfc_poller.h @@ -10,7 +10,7 @@ extern "C" { #include #include -typedef struct NfcPoller NfcPoller; +typedef struct NfcPollerOld NfcPollerOld; typedef struct { Nfc* nfc; @@ -18,33 +18,33 @@ typedef struct { NfcbPoller* nfcb_poller; MfUltralightPoller* mfu_poller; MfClassicPoller* mfc_poller; -} NfcPollerCollection; +} NfcPollerOldCollection; typedef enum { - NfcPollerEventNfcaDetected, - NfcPollerEventNfcbDetected, - NfcPollerEventNfcfDetected, - NfcPollerEventNfcvDetected, - NfcPollerEventMfUltralightDetected, - NfcPollerEventMfClassicDetected, - NfcPollerEventMfDesfireDetected, -} NfcPollerEvent; + NfcPollerOldEventNfcaDetected, + NfcPollerOldEventNfcbDetected, + NfcPollerOldEventNfcfDetected, + NfcPollerOldEventNfcvDetected, + NfcPollerOldEventMfUltralightDetected, + NfcPollerOldEventMfClassicDetected, + NfcPollerOldEventMfDesfireDetected, +} NfcPollerOldEvent; typedef enum { - NfcPollerCommandContinue = NfcCommandContinue, - NfcPollerCommandReset = NfcCommandReset, - NfcPollerCommandStop = NfcCommandStop, -} NfcPollerCommand; + NfcPollerOldCommandContinue = NfcCommandContinue, + NfcPollerOldCommandReset = NfcCommandReset, + NfcPollerOldCommandStop = NfcCommandStop, +} NfcPollerOldCommand; -typedef NfcPollerCommand (*NfcPollerEventCallback)(NfcPollerEvent event, void* context); +typedef NfcPollerOldCommand (*NfcPollerOldEventCallback)(NfcPollerOldEvent event, void* context); -NfcPoller* nfc_poller_alloc(NfcPollerCollection* pollers); +NfcPollerOld* nfc_poller_alloc(NfcPollerOldCollection* pollers); -void nfc_poller_free(NfcPoller* instance); +void nfc_poller_free(NfcPollerOld* instance); -void nfc_poller_start(NfcPoller* instance, NfcPollerEventCallback callback, void* context); +void nfc_poller_start(NfcPollerOld* instance, NfcPollerOldEventCallback callback, void* context); -void nfc_poller_stop(NfcPoller* instance); +void nfc_poller_stop(NfcPollerOld* instance); #ifdef __cplusplus } diff --git a/lib/nfc/nfc_poller_base.h b/lib/nfc/nfc_poller_base.h new file mode 100644 index 000000000000..32d2424ab53b --- /dev/null +++ b/lib/nfc/nfc_poller_base.h @@ -0,0 +1,41 @@ +#pragma once + +#include "protocols/nfc_protocol_defs.h" +#include "nfc.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void NfcPoller; + +typedef void NfcPollerEventData; + +typedef struct { + NfcProtocolType protocol_type; + NfcPoller* poller; + NfcPollerEventData* data; +} NfcPollerEvent; + +typedef NfcCommand (*NfcPollerCallback)(NfcPollerEvent event, void* context); + +typedef NfcPoller* (*NfcPollerAlloc)(NfcPoller* base_poller); +typedef void (*NfcPollerFree)(NfcPoller* instance); + +typedef void (*NfcPollerSetCallback)(NfcPoller* poller, NfcPollerCallback callback, void* context); +typedef NfcCommand (*NfcPollerRun)(NfcPollerEvent event, void* context); +typedef bool (*NfcPollerDetect)(NfcPollerEvent event, void* context); +typedef const NfcProtocolData* (*NfcPollerGetData)(const NfcPoller* instance); + +typedef struct { + NfcPollerAlloc alloc; + NfcPollerFree free; + NfcPollerSetCallback set_callback; + NfcPollerRun run; + NfcPollerDetect detect; + NfcPollerGetData get_data; +} NfcPollerBase; + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/nfc_poller_defs.c b/lib/nfc/nfc_poller_defs.c new file mode 100644 index 000000000000..da7fa2d70796 --- /dev/null +++ b/lib/nfc/nfc_poller_defs.c @@ -0,0 +1,61 @@ +#include "nfc_poller_defs.h" + +#include +#include +#include + +#include + +const NfcPollerBase* nfc_pollers_api[NfcProtocolTypeMax] = { + [NfcProtocolTypeIso14443_3a] = &nfc_poller_iso14443_3a, + [NfcProtocolTypeIso14443_4a] = &nfc_poller_iso14443_4a, + [NfcProtocolTypeMfUltralight] = &mf_ultralight_poller, +}; + +// nfc-a nfc-b nfc-f nfc-v +// +// iso14443-4a mf ultraligh mf classic +// +// mf desfire bank card + +static const NfcProtocolType nfc_poller_iso14443_3a_children_protocol[] = { + NfcProtocolTypeIso14443_4a, + NfcProtocolTypeMfUltralight, +}; + +static const NfcProtocolType nfc_poller_iso14443_4a_children_protocol[] = { + NfcProtocolTypeMfDesfire, +}; + +const NfcPollerTreeNode nfc_poller_nodes[NfcProtocolTypeMax] = { + [NfcProtocolTypeIso14443_3a] = + { + .parent_protocol = NfcProtocolTypeInvalid, + .children_num = COUNT_OF(nfc_poller_iso14443_3a_children_protocol), + .children_protocol = nfc_poller_iso14443_3a_children_protocol, + }, + [NfcProtocolTypeIso14443_4a] = + { + .parent_protocol = NfcProtocolTypeIso14443_3a, + .children_num = COUNT_OF(nfc_poller_iso14443_4a_children_protocol), + .children_protocol = nfc_poller_iso14443_4a_children_protocol, + }, + [NfcProtocolTypeMfUltralight] = + { + .parent_protocol = NfcProtocolTypeIso14443_3a, + .children_num = 0, + .children_protocol = NULL, + }, + [NfcProtocolTypeMfClassic] = + { + .parent_protocol = NfcProtocolTypeIso14443_3a, + .children_num = 0, + .children_protocol = NULL, + }, + [NfcProtocolTypeMfDesfire] = + { + .parent_protocol = NfcProtocolTypeIso14443_4a, + .children_num = 0, + .children_protocol = NULL, + }, +}; diff --git a/lib/nfc/nfc_poller_defs.h b/lib/nfc/nfc_poller_defs.h new file mode 100644 index 000000000000..5e92ac71b7f3 --- /dev/null +++ b/lib/nfc/nfc_poller_defs.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include "nfc_poller_base.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + NfcProtocolType parent_protocol; + size_t children_num; + const NfcProtocolType* children_protocol; +} NfcPollerTreeNode; + +extern const NfcPollerBase* nfc_pollers_api[NfcProtocolTypeMax]; + +extern const NfcPollerTreeNode nfc_poller_nodes[NfcProtocolTypeMax]; + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/nfc_poller_manager.c b/lib/nfc/nfc_poller_manager.c new file mode 100644 index 000000000000..a6d3dd393dae --- /dev/null +++ b/lib/nfc/nfc_poller_manager.c @@ -0,0 +1,229 @@ +#include "nfc_poller_manager.h" + +#include "nfc_poller_defs.h" + +#include + +#include "nfc.h" + +typedef enum { + NfcPollerManagerStateIdle, + + NfcPollerManagerStateNum, +} NfcPollerManagerState; + +typedef enum { + NfcPollerManagerSessionStateIdle, + NfcPollerManagerSessionStateActive, + NfcPollerManagerSessionStateStopRequest, +} NfcPollerManagerSessionState; + +typedef struct NfcPollerListElement { + NfcProtocolType protocol; + NfcPoller* poller; + const NfcPollerBase* poller_api; + struct NfcPollerListElement* child; +} NfcPollerListElement; + +typedef struct { + NfcPollerListElement* head; +} NfcPollerList; + +struct NfcPollerManager { + Nfc* nfc; + NfcPollerManagerState state; + NfcPollerManagerSessionState session_state; + + size_t base_protocol_current; + size_t base_protocol_total; + NfcEvent* event; + + NfcPollerBase* current_poller_base; + NfcPoller* current_poller; + NfcPoller* base_poller; + + NfcPollerList* list; + NfcProtocolType protocol; + + NfcPollerCallback callback; + void* context; +}; + +NfcPollerManager* nfc_poller_manager_alloc(Nfc* nfc) { + NfcPollerManager* instance = malloc(sizeof(NfcPollerManager)); + instance->nfc = nfc; + instance->event = malloc(sizeof(NfcEvent)); + + return instance; +} + +void nfc_poller_manager_free(NfcPollerManager* instance) { + furi_assert(instance); + furi_assert(instance->event); + furi_assert(instance->nfc); + + free(instance->event); + free(instance); +} + +// typedef NfcCommand (*NfcPollerManagerHandler)(NfcPollerManager* instance); + +// NfcCommand nfc_poller_manager_handler_idle(NfcPollerManager* instance) { +// NfcCommand command = NfcCommandContinue; + +// instance->base_protocol_total = COUNT_OF(nfc_poller_base_type); +// instance->base_protocol_current = 0; + +// return command; +// } + +// static const NfcPollerManagerHandler nfc_poller_manager_handler[NfcPollerManagerStateNum] = { +// [NfcPollerManagerStateIdle] = nfc_poller_manager_handler_idle, +// }; + +// static NfcCommand nfc_poller_manager_scan_event_callback(NfcEvent event, void* context) { +// furi_assert(context); + +// NfcPollerManager* instance = context; +// furi_assert(instance->callback); + +// NfcPollerEvent poller_event; +// NfcPollerCommand command = NfcPollerCommandContinue; + +// if(instance->session_state == NfcPollerManagerSessionStateStopRequest) { +// command = NfcPollerCommandStop; +// } else { +// if(event.type == NfcEventTypeConfigureRequest) { +// instance->current_poller = instance->current_poller_base->alloc(instance->base_poller); +// } else if(event.type == NfcEventTypePollerReady) { +// command = instance->current_poller_base->run(instance->current_poller); +// } else if(event.type == NfcEventTypeReset) { +// instance->current_poller_base->free(instance->current_poller); +// } +// } + +// return nfc_poller_manager_process_command(command); +// } + +// void nfc_poller_manager_scan(NfcPollerManager* instance, NfcPollerCallback callback, void* context) { +// furi_assert(instance); +// furi_assert(callback); +// furi_assert(instance->session_state == NfcPollerManagerSessionStateIdle); + +// instance->callback = callback; +// instance->context = context; +// instance->session_state = NfcPollerManagerSessionStateActive; + +// nfc_start_poller(instance->nfc, nfc_poller_manager_scan_event_callback, instance); +// } + +static void nfc_poller_manager_poller_list_alloc(NfcPollerManager* instance) { + furi_assert(instance->list == NULL); + + instance->list = malloc(sizeof(NfcPollerList)); + + instance->list->head = malloc(sizeof(NfcPollerListElement)); + instance->list->head->protocol = instance->protocol; + instance->list->head->poller_api = nfc_pollers_api[instance->protocol]; + instance->list->head->child = NULL; + + do { + const NfcPollerTreeNode* node = &nfc_poller_nodes[instance->list->head->protocol]; + if(node->parent_protocol == NfcProtocolTypeInvalid) break; + + NfcPollerListElement* parent = malloc(sizeof(NfcPollerListElement)); + parent->protocol = node->parent_protocol; + parent->poller_api = nfc_pollers_api[node->parent_protocol]; + parent->child = instance->list->head; + instance->list->head = parent; + } while(true); + + NfcPollerListElement* iter = instance->list->head; + iter->poller = iter->poller_api->alloc(instance->nfc); + + do { + if(iter->child == NULL) break; + iter->child->poller = iter->child->poller_api->alloc(iter->poller); + iter->poller_api->set_callback( + iter->poller, iter->child->poller_api->run, iter->child->poller); + + iter = iter->child; + } while(true); + + iter->poller_api->set_callback(iter->poller, instance->callback, instance->context); +} + +static void nfc_poller_manager_poller_list_free(NfcPollerManager* instance) { + do { + NfcPollerListElement* child = instance->list->head->child; + if(child == NULL) break; + + instance->list->head->poller_api->free(instance->list->head->poller); + free(instance->list->head); + instance->list->head = child; + } while(true); + + free(instance->list->head); + free(instance->list); + instance->list = NULL; +} + +static NfcCommand nfc_poller_manager_start_event_callback(NfcEvent event, void* context) { + furi_assert(context); + + NfcPollerManager* instance = context; + furi_assert(instance->callback); + + NfcCommand command = NfcCommandContinue; + NfcPollerEvent poller_manager_event = { + .protocol_type = NfcProtocolTypeInvalid, + .poller = instance->nfc, + }; + + if(instance->session_state == NfcPollerManagerSessionStateStopRequest) { + command = NfcCommandStop; + } else { + if(event.type == NfcEventTypeConfigureRequest) { + nfc_poller_manager_poller_list_alloc(instance); + } else if(event.type == NfcEventTypePollerReady) { + *instance->event = event; + poller_manager_event.data = instance->event; + NfcPollerListElement* head = instance->list->head; + command = head->poller_api->run(poller_manager_event, head->poller); + } else if(event.type == NfcEventTypeReset) { + nfc_poller_manager_poller_list_free(instance); + } + } + + return command; +} + +void nfc_poller_manager_start( + NfcPollerManager* instance, + NfcProtocolType protocol, + NfcPollerCallback callback, + void* context) { + furi_assert(instance); + furi_assert(callback); + furi_assert(protocol < NfcProtocolTypeMax); + furi_assert(instance->session_state == NfcPollerManagerSessionStateIdle); + + instance->protocol = protocol; + instance->callback = callback; + instance->context = context; + instance->session_state = NfcPollerManagerSessionStateActive; + + nfc_start_poller(instance->nfc, nfc_poller_manager_start_event_callback, instance); +} + +void nfc_poller_manager_stop(NfcPollerManager* instance) { + furi_assert(instance); + furi_assert(instance->nfc); + + instance->session_state = NfcPollerManagerSessionStateStopRequest; + nfc_stop(instance->nfc); + instance->session_state = NfcPollerManagerSessionStateIdle; + + instance->callback = NULL; + instance->context = NULL; +} diff --git a/lib/nfc/nfc_poller_manager.h b/lib/nfc/nfc_poller_manager.h new file mode 100644 index 000000000000..94749f4281b4 --- /dev/null +++ b/lib/nfc/nfc_poller_manager.h @@ -0,0 +1,27 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "nfc_poller_base.h" + +typedef struct NfcPollerManager NfcPollerManager; + +NfcPollerManager* nfc_poller_manager_alloc(Nfc* nfc); + +void nfc_poller_manager_free(NfcPollerManager* instance); + +void nfc_poller_manager_scan(NfcPollerManager* instance, NfcPollerCallback callback, void* context); + +void nfc_poller_manager_start( + NfcPollerManager* instance, + NfcProtocolType protocol, + NfcPollerCallback callback, + void* context); + +void nfc_poller_manager_stop(NfcPollerManager* instance); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c index a70369c93d10..30e0b6ed6e46 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c @@ -117,3 +117,24 @@ Iso14443_4aError iso14443_4a_poller_send_block( return ret; } + +NfcPoller* iso14443_4a_poller_alloc_new(NfcPoller* iso14443_3a_poller) { + furi_assert(iso14443_3a_poller); + + Iso14443_4aPoller* instance = malloc(sizeof(Iso14443_4aPoller)); + instance->iso14443_3a_poller = iso14443_3a_poller; + + return instance; +} + +void iso14443_4a_poller_free_new(NfcPoller* iso14443_4a_poller) { + furi_assert(iso14443_4a_poller); + + Iso14443_4aPoller* instance = iso14443_4a_poller; + free(instance); +} + +const NfcPollerBase nfc_poller_iso14443_4a = { + .alloc = iso14443_4a_poller_alloc_new, + .free = iso14443_4a_poller_free_new, +}; diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.h b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.h index c152f4dc0ff8..811da4045f90 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.h +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.h @@ -56,6 +56,8 @@ Iso14443_4aError iso14443_4a_poller_send_block( BitBuffer* rx_buffer, uint32_t fwt); +extern const NfcPollerBase nfc_poller_iso14443_4a; + #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c index 47ffa0f62b45..c89ca0cb7778 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c @@ -4,9 +4,6 @@ #define TAG "MfUltralightPoller" -#define MF_ULTRALIGHT_MAX_BUFF_SIZE (64) -#define MF_ULTRALIGHT_DEFAULT_PASSWORD (0xffffffffUL) - typedef MfUltralightPollerCommand (*MfUltralightPollerReadHandler)(MfUltralightPoller* instance); static NfcaPollerCommand mf_ultralight_process_command(MfUltralightPollerCommand command) { diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h index 4b7c7a9f2d15..bc77a5ae0c3d 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h @@ -72,6 +72,11 @@ MfUltralightError mf_ultralight_poller_read_page( uint16_t page, MfUltralightPage* data); +MfUltralightError mf_ultralight_poller_read_page_new( + NfcPollerManager* poller_manager, + uint16_t page, + MfUltralightPage* data); + MfUltralightError mf_ultralight_poller_write_page( MfUltralightPoller* instance, uint16_t page, diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c index b66ebe42e4ed..a1c8ed9bf1a0 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c @@ -437,3 +437,387 @@ MfUltralightError mf_ultralight_poller_async_read_tearing_flag( return ret; } + +static NfcPoller* mf_ultralight_poller_alloc_new(NfcPoller* nfca_poller) { + furi_assert(nfca_poller); + + MfUltralightPoller* instance = malloc(sizeof(MfUltralightPoller)); + instance->nfca_poller = nfca_poller; + instance->tx_buffer = bit_buffer_alloc(MF_ULTRALIGHT_MAX_BUFF_SIZE); + instance->rx_buffer = bit_buffer_alloc(MF_ULTRALIGHT_MAX_BUFF_SIZE); + instance->event = malloc(sizeof(NfcPollerEvent)); + instance->mfu_event = malloc(sizeof(MfUltralightPollerEvent)); + instance->data = mf_ultralight_alloc(); + + return instance; +} + +static void mf_ultralight_poller_free_new(NfcPoller* mfu_poller) { + furi_assert(mfu_poller); + + MfUltralightPoller* instance = mfu_poller; + furi_assert(instance->data); + furi_assert(instance->tx_buffer); + furi_assert(instance->rx_buffer); + furi_assert(instance->mfu_event); + furi_assert(instance->event); + + bit_buffer_free(instance->tx_buffer); + bit_buffer_free(instance->rx_buffer); + mf_ultralight_free(instance->data); + free(instance->mfu_event); + free(instance->event); + free(instance); +} + +static void mf_ultralight_poller_set_callback( + NfcPoller* mfu_poller, + NfcPollerCallback callback, + void* context) { + furi_assert(mfu_poller); + furi_assert(callback); + + MfUltralightPoller* instance = mfu_poller; + instance->callback_new = callback; + instance->context_new = context; +} + +static const NfcProtocolData* mf_ultralight_poller_get_data_new(const NfcPoller* mfu_poller) { + furi_assert(mfu_poller); + + const MfUltralightPoller* instance = mfu_poller; + furi_assert(instance->data); + + return instance->data; +} + +typedef NfcCommand (*MfUltralightPollerReadHandler)(MfUltralightPoller* instance); + +static NfcCommand mf_ultralight_poller_handler_idle(MfUltralightPoller* instance) { + bit_buffer_reset(instance->tx_buffer); + bit_buffer_reset(instance->rx_buffer); + nfca_copy(instance->data->nfca_data, nfca_poller_get_data(instance->nfca_poller)); + instance->counters_read = 0; + instance->counters_total = 3; + instance->tearing_flag_read = 0; + instance->tearing_flag_total = 3; + instance->pages_read = 0; + instance->state = MfUltralightPollerStateReadVersion; + + return NfcCommandContinue; +} + +static NfcCommand mf_ultralight_poller_handler_read_version(MfUltralightPoller* instance) { + instance->error = mf_ultralight_poller_async_read_version(instance, &instance->data->version); + if(instance->error == MfUltralightErrorNone) { + FURI_LOG_D(TAG, "Read version success"); + instance->data->type = mf_ultralight_get_type_by_version(&instance->data->version); + instance->state = MfUltralightPollerStateGetFeatureSet; + } else { + FURI_LOG_D(TAG, "Didn't response. Check NTAG 203"); + nfca_poller_halt(instance->nfca_poller); + instance->state = MfUltralightPollerStateDetectNtag203; + } + + return NfcCommandContinue; +} + +static NfcCommand mf_ultralight_poller_handler_check_ntag_203(MfUltralightPoller* instance) { + MfUltralightPageReadCommandData data = {}; + instance->error = mf_ultralight_poller_async_read_page(instance, 41, &data); + if(instance->error == MfUltralightErrorNone) { + FURI_LOG_D(TAG, "NTAG203 detected"); + instance->data->type = MfUltralightTypeNTAG203; + } else { + FURI_LOG_D(TAG, "Original Ultralight detected"); + nfca_poller_halt(instance->nfca_poller); + instance->data->type = MfUltralightTypeUnknown; + } + instance->state = MfUltralightPollerStateGetFeatureSet; + + return NfcCommandContinue; +} + +static NfcCommand mf_ultralight_poller_handler_get_feature_set(MfUltralightPoller* instance) { + instance->feature_set = mf_ultralight_get_feature_support_set(instance->data->type); + instance->pages_total = mf_ultralight_get_pages_total(instance->data->type); + instance->data->pages_total = instance->pages_total; + FURI_LOG_D( + TAG, + "%s detected. Total pages: %d", + mf_ultralight_get_name(instance->data, NfcProtocolNameTypeFull), + instance->pages_total); + + instance->state = MfUltralightPollerStateReadSignature; + return NfcCommandContinue; +} + +static NfcCommand mf_ultralight_poller_handler_read_signature(MfUltralightPoller* instance) { + MfUltralightPollerState next_state = MfUltralightPollerStateAuth; + if(instance->feature_set & MfUltralightFeatureSupportReadSignature) { + FURI_LOG_D(TAG, "Reading signature"); + instance->error = + mf_ultralight_poller_async_read_signature(instance, &instance->data->signature); + if(instance->error != MfUltralightErrorNone) { + FURI_LOG_D(TAG, "Read signature failed"); + next_state = MfUltralightPollerStateReadFailed; + } + } else { + FURI_LOG_D(TAG, "Skip reading signature"); + } + instance->state = next_state; + + return NfcCommandContinue; +} + +static NfcCommand mf_ultralight_poller_handler_read_counters(MfUltralightPoller* instance) { + if(instance->feature_set & MfUltralightFeatureSupportReadCounter) { + if(mf_ultralight_is_counter_configured(instance->data)) { + if(instance->feature_set & MfUltralightFeatureSupportSingleCounter) { + instance->counters_read = 2; + } + if(instance->counters_read == instance->counters_total) { + instance->state = MfUltralightPollerStateReadTearingFlags; + } else { + FURI_LOG_D(TAG, "Reading counter %d", instance->counters_read); + instance->error = mf_ultralight_poller_async_read_counter( + instance, + instance->counters_read, + &instance->data->counter[instance->counters_read]); + if(instance->error != MfUltralightErrorNone) { + FURI_LOG_D(TAG, "Failed to read %d counter", instance->counters_read); + instance->state = MfUltralightPollerStateReadTearingFlags; + } else { + instance->counters_read++; + } + } + } else { + instance->state = MfUltralightPollerStateReadTearingFlags; + } + } else { + FURI_LOG_D(TAG, "Skip reading counters"); + instance->state = MfUltralightPollerStateReadTearingFlags; + } + + return NfcCommandContinue; +} + +static NfcCommand mf_ultralight_poller_handler_read_tearing_flags(MfUltralightPoller* instance) { + if(instance->feature_set & MfUltralightFeatureSupportCheckTearingFlag) { + if(instance->tearing_flag_read == instance->tearing_flag_total) { + instance->state = MfUltralightPollerStateTryDefaultPass; + } else { + FURI_LOG_D(TAG, "Reading tearing flag %d", instance->tearing_flag_read); + instance->error = mf_ultralight_poller_async_read_tearing_flag( + instance, + instance->tearing_flag_read, + &instance->data->tearing_flag[instance->tearing_flag_read]); + if(instance->error != MfUltralightErrorNone) { + FURI_LOG_D(TAG, "Reading tearing flag %d failed", instance->tearing_flag_read); + instance->state = MfUltralightPollerStateReadFailed; + } else { + instance->tearing_flag_read++; + } + } + } else { + FURI_LOG_D(TAG, "Skip reading tearing flags"); + instance->state = MfUltralightPollerStateTryDefaultPass; + } + + return NfcCommandContinue; +} + +static NfcCommand mf_ultralight_poller_handler_auth(MfUltralightPoller* instance) { + NfcCommand command = NfcCommandContinue; + if(instance->feature_set & MfUltralightFeatureSupportAuthentication) { + MfUltralightPollerEventData event_data = {}; + instance->mfu_event->type = MfUltralightPollerEventTypeAuthRequest; + instance->mfu_event->data = &event_data; + + command = instance->callback_new(*instance->event, instance->context_new); + if(!instance->mfu_event->data->auth_context.skip_auth) { + instance->auth_context.password = instance->mfu_event->data->auth_context.password; + FURI_LOG_D( + TAG, + "Trying to authenticate with password %08lX", + instance->auth_context.password.pass); + instance->error = mf_ultralight_poller_async_auth(instance, &instance->auth_context); + if(instance->error == MfUltralightErrorNone) { + FURI_LOG_D(TAG, "Auth success"); + instance->auth_context.auth_success = true; + instance->mfu_event->data->auth_context = instance->auth_context; + instance->mfu_event->type = MfUltralightPollerEventTypeAuthSuccess; + command = instance->callback_new(*instance->event, instance->context_new); + } else { + FURI_LOG_D(TAG, "Auth failed"); + instance->auth_context.auth_success = false; + instance->mfu_event->type = MfUltralightPollerEventTypeAuthFailed; + command = instance->callback_new(*instance->event, instance->context_new); + nfca_poller_halt(instance->nfca_poller); + } + } + } + instance->state = MfUltralightPollerStateReadPages; + + return command; +} + +static NfcCommand mf_ultralight_poller_handler_read_pages(MfUltralightPoller* instance) { + MfUltralightPageReadCommandData data = {}; + uint16_t start_page = instance->pages_read; + if(MF_ULTRALIGHT_IS_NTAG_I2C(instance->data->type)) { + uint8_t tag = 0; + uint8_t sector = 0; + uint8_t pages_left = 0; + if(mf_ultralight_poller_ntag_i2c_addr_lin_to_tag( + instance, start_page, §or, &tag, &pages_left)) { + instance->error = + mf_ultralight_poller_async_read_page_from_sector(instance, sector, tag, &data); + } else { + FURI_LOG_D(TAG, "Failed to calculate sector and tag from %d page", start_page); + instance->error = MfUltralightErrorProtocol; + } + } else { + instance->error = mf_ultralight_poller_async_read_page(instance, start_page, &data); + } + + if(instance->error == MfUltralightErrorNone) { + for(size_t i = 0; i < 4; i++) { + if(start_page + i < instance->pages_total) { + FURI_LOG_D(TAG, "Read page %d success", start_page + i); + instance->data->page[start_page + i] = data.page[i]; + instance->pages_read++; + instance->data->pages_read = instance->pages_read; + } + } + if(instance->pages_read == instance->pages_total) { + instance->state = MfUltralightPollerStateReadCounters; + } + } else { + FURI_LOG_D(TAG, "Read page %d failed", instance->pages_read); + if(instance->pages_read) { + instance->state = MfUltralightPollerStateReadCounters; + } else { + instance->state = MfUltralightPollerStateReadFailed; + } + } + + return NfcCommandContinue; +} + +static NfcCommand mf_ultralight_poller_handler_try_default_pass(MfUltralightPoller* instance) { + if(instance->feature_set & MfUltralightFeatureSupportAuthentication) { + MfUltralightConfigPages* config = NULL; + mf_ultralight_get_config_page(instance->data, &config); + if(instance->auth_context.auth_success) { + config->password = instance->auth_context.password; + config->pack = instance->auth_context.pack; + } else if(config->access.authlim == 0) { + FURI_LOG_D(TAG, "No limits in authentication. Trying default password"); + instance->auth_context.password.pass = MF_ULTRALIGHT_DEFAULT_PASSWORD; + instance->error = mf_ultralight_poller_async_auth(instance, &instance->auth_context); + if(instance->error == MfUltralightErrorNone) { + FURI_LOG_D(TAG, "Default password detected"); + config->password.pass = MF_ULTRALIGHT_DEFAULT_PASSWORD; + config->pack = instance->auth_context.pack; + } + } + + if(instance->pages_read != instance->pages_total) { + // Probably password protected, fix AUTH0 and PROT so before AUTH0 + // can be written and since AUTH0 won't be readable, like on the + // original card + config->auth0 = instance->pages_read; + config->access.prot = true; + } + } + + instance->state = MfUltralightPollerStateReadSuccess; + return NfcCommandContinue; +} + +static NfcCommand mf_ultralight_poller_handler_read_fail(MfUltralightPoller* instance) { + FURI_LOG_D(TAG, "Read Failed"); + nfca_poller_halt(instance->nfca_poller); + instance->mfu_event->data->error = instance->error; + NfcCommand command = instance->callback_new(*instance->event, instance->context_new); + instance->state = MfUltralightPollerStateIdle; + return command; +} + +static NfcCommand mf_ultralight_poller_handler_read_success(MfUltralightPoller* instance) { + FURI_LOG_D(TAG, "Read success."); + nfca_poller_halt(instance->nfca_poller); + instance->mfu_event->type = MfUltralightPollerEventTypeReadSuccess; + NfcCommand command = instance->callback_new(*instance->event, instance->context_new); + return command; +} + +static const MfUltralightPollerReadHandler + mf_ultralight_poller_read_handler[MfUltralightPollerStateNum] = { + [MfUltralightPollerStateIdle] = mf_ultralight_poller_handler_idle, + [MfUltralightPollerStateReadVersion] = mf_ultralight_poller_handler_read_version, + [MfUltralightPollerStateDetectNtag203] = mf_ultralight_poller_handler_check_ntag_203, + [MfUltralightPollerStateGetFeatureSet] = mf_ultralight_poller_handler_get_feature_set, + [MfUltralightPollerStateReadSignature] = mf_ultralight_poller_handler_read_signature, + [MfUltralightPollerStateReadCounters] = mf_ultralight_poller_handler_read_counters, + [MfUltralightPollerStateReadTearingFlags] = + mf_ultralight_poller_handler_read_tearing_flags, + [MfUltralightPollerStateAuth] = mf_ultralight_poller_handler_auth, + [MfUltralightPollerStateTryDefaultPass] = mf_ultralight_poller_handler_try_default_pass, + [MfUltralightPollerStateReadPages] = mf_ultralight_poller_handler_read_pages, + [MfUltralightPollerStateReadFailed] = mf_ultralight_poller_handler_read_fail, + [MfUltralightPollerStateReadSuccess] = mf_ultralight_poller_handler_read_success, + +}; + +static NfcCommand mf_ultralight_poller_run(NfcPollerEvent event, void* context) { + furi_assert(context); + furi_assert(event.data); + furi_assert(event.protocol_type == NfcProtocolTypeIso14443_3a); + + MfUltralightPoller* instance = context; + furi_assert(instance->callback_new); + NfcaPollerEvent* nfca_event = event.data; + + instance->event->protocol_type = NfcProtocolTypeMfUltralight; + instance->event->poller = instance; + instance->event->data = instance->mfu_event; + NfcCommand command = NfcCommandContinue; + + if(nfca_event->type == NfcaPollerEventTypeReady) { + command = mf_ultralight_poller_read_handler[instance->state](instance); + } else if(nfca_event->type == NfcaPollerEventTypeError) { + instance->mfu_event->type = MfUltralightPollerEventTypeReadFailed; + command = instance->callback_new(*instance->event, instance->context_new); + } + + return command; +} + +static bool mf_ultralight_poller_detect(NfcPollerEvent event, void* context) { + furi_assert(context); + furi_assert(event.data); + furi_assert(event.protocol_type == NfcProtocolTypeIso14443_3a); + + bool protocol_detected = false; + MfUltralightPoller* instance = context; + NfcaPollerEvent* nfca_event = event.data; + + if(nfca_event->type == NfcaPollerEventTypeReady) { + MfUltralightPage page = {}; + MfUltralightError error = mf_ultralight_poller_read_page(instance, 0, &page); + protocol_detected = (error == MfUltralightErrorNone); + } + + return protocol_detected; +} + +const NfcPollerBase mf_ultralight_poller = { + .alloc = mf_ultralight_poller_alloc_new, + .free = mf_ultralight_poller_free_new, + .set_callback = mf_ultralight_poller_set_callback, + .run = mf_ultralight_poller_run, + .detect = mf_ultralight_poller_detect, + .get_data = mf_ultralight_poller_get_data_new, +}; diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h index 42300f84bf21..e6c8f3ecb73b 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h @@ -4,7 +4,14 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + #define MF_ULTRALIGHT_POLLER_STANDART_FWT_FC (60000) +#define MF_ULTRALIGHT_MAX_BUFF_SIZE (64) + +#define MF_ULTRALIGHT_DEFAULT_PASSWORD (0xffffffffUL) #define MF_ULTRALIGHT_IS_NTAG_I2C(type) \ (((type) == MfUltralightTypeNTAGI2C1K) || ((type) == MfUltralightTypeNTAGI2C2K) || \ @@ -81,6 +88,11 @@ struct MfUltralightPoller { uint8_t tearing_flag_total; MfUltralightError error; void* context; + + NfcPollerEvent* event; + MfUltralightPollerEvent* mfu_event; + NfcPollerCallback callback_new; + void* context_new; }; MfUltralightError mf_ultralight_process_error(NfcaError error); @@ -130,9 +142,7 @@ MfUltralightError mf_ultralight_poller_async_read_tearing_flag( uint8_t tearing_falg_num, MfUltralightTearingFlag* data); -#ifdef __cplusplus -extern "C" { -#endif +extern const NfcPollerBase mf_ultralight_poller; #ifdef __cplusplus } diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c index 86bdd27aaf17..77dda81e1f13 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c @@ -52,6 +52,57 @@ MfUltralightError mf_ultralight_poller_read_page( return poller_context.error; } +NfcCommand mf_ultralight_poller_read_page_new_callback(NfcPollerEvent event, void* context) { + furi_assert(event.poller); + furi_assert(event.protocol_type == NfcProtocolTypeMfUltralight); + furi_assert(event.data); + furi_assert(context); + + MfUltralightPollerContext* poller_context = context; + NfcaPollerEvent* nfca_event = event.data; + MfUltralightPoller* mfu_poller = event.poller; + + if(nfca_event->type == NfcaPollerEventTypeReady) { + poller_context->error = mf_ultralight_poller_async_read_page( + mfu_poller, + poller_context->data.read_cmd.start_page, + &poller_context->data.read_cmd.data); + nfca_poller_halt(mfu_poller->nfca_poller); + } else if(nfca_event->type == NfcaPollerEventTypeError) { + poller_context->error = mf_ultralight_process_error(nfca_event->data.error); + } + furi_thread_flags_set(poller_context->thread_id, MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); + + return NfcCommandStop; +} + +MfUltralightError mf_ultralight_poller_read_page_new( + NfcPollerManager* poller_manager, + uint16_t page, + MfUltralightPage* data) { + furi_assert(poller_manager); + furi_assert(data); + + MfUltralightPollerContext poller_context = {}; + poller_context.data.read_cmd.start_page = page; + poller_context.thread_id = furi_thread_get_current_id(); + + nfc_poller_manager_start( + poller_manager, + NfcProtocolTypeMfUltralight, + mf_ultralight_poller_read_page_new_callback, + &poller_context); + furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); + + if(poller_context.error == MfUltralightErrorNone) { + *data = poller_context.data.read_cmd.data.page[0]; + } + + nfc_poller_manager_stop(poller_manager); + + return poller_context.error; +} + static NfcaPollerCommand mf_ultraight_write_page_callback(NfcaPollerEvent event, void* context) { furi_assert(context); diff --git a/lib/nfc/protocols/nfc_protocol_defs.h b/lib/nfc/protocols/nfc_protocol_defs.h index fd3c6dda2eb3..dee0b974a929 100644 --- a/lib/nfc/protocols/nfc_protocol_defs.h +++ b/lib/nfc/protocols/nfc_protocol_defs.h @@ -15,6 +15,8 @@ typedef enum { /* Add new protocols here */ NfcProtocolTypeMax, + + NfcProtocolTypeInvalid, } NfcProtocolType; extern const NfcProtocolBase* nfc_protocols[]; diff --git a/lib/nfc/protocols/nfca/nfca_poller.c b/lib/nfc/protocols/nfca/nfca_poller.c index 070f845b6707..bc09100fc751 100644 --- a/lib/nfc/protocols/nfca/nfca_poller.c +++ b/lib/nfc/protocols/nfca/nfca_poller.c @@ -10,6 +10,7 @@ typedef struct { NfcaPoller* instance; FuriThreadId thread_id; NfcaError error; + NfcaData data; } NfcaPollerContext; NfcaPoller* nfca_poller_alloc(Nfc* nfc) { @@ -158,3 +159,38 @@ NfcaError nfca_poller_read(NfcaPoller* instance, NfcaData* nfca_data) { return context.error; } + +NfcCommand nfca_poller_read_new_callback(NfcPollerEvent event, void* context) { + furi_assert(event.poller); + furi_assert(event.data); + furi_assert(context); + + NfcaPollerContext* nfca_poller_context = context; + NfcaPoller* nfca_poller = event.poller; + NfcEvent* nfc_event = event.data; + if(nfc_event->type == NfcEventTypePollerReady) { + nfca_poller_context->error = + nfca_poller_async_activate(nfca_poller, &nfca_poller_context->data); + } + furi_thread_flags_set(nfca_poller_context->thread_id, NFCA_POLLER_FLAG_COMMAND_COMPLETE); + + return NfcCommandStop; +} + +NfcaError nfca_poller_read_new(NfcPollerManager* poller_manager, NfcaData* nfca_data) { + furi_assert(poller_manager); + furi_assert(nfca_data); + + NfcaPollerContext context = {}; + context.thread_id = furi_thread_get_current_id(); + + nfc_poller_manager_start( + poller_manager, NfcProtocolTypeIso14443_3a, nfca_poller_read_new_callback, &context); + + furi_thread_flags_wait(NFCA_POLLER_FLAG_COMMAND_COMPLETE, FuriFlagWaitAny, FuriWaitForever); + furi_thread_flags_clear(NFCA_POLLER_FLAG_COMMAND_COMPLETE); + + nfc_poller_manager_stop(poller_manager); + + return context.error; +} \ No newline at end of file diff --git a/lib/nfc/protocols/nfca/nfca_poller.h b/lib/nfc/protocols/nfca/nfca_poller.h index c1ce931f5663..b411ed3b503b 100644 --- a/lib/nfc/protocols/nfca/nfca_poller.h +++ b/lib/nfc/protocols/nfca/nfca_poller.h @@ -3,6 +3,8 @@ #include "nfca.h" #include +#include + #ifdef __cplusplus extern "C" { #endif @@ -44,6 +46,8 @@ NfcaError nfca_poller_stop(NfcaPoller* instance); // Sync call NfcaError nfca_poller_read(NfcaPoller* instance, NfcaData* nfca_data); +NfcaError nfca_poller_read_new(NfcPollerManager* poller_manager, NfcaData* nfca_data); + #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/nfca/nfca_poller_i.c b/lib/nfc/protocols/nfca/nfca_poller_i.c index 20753d16e474..8e0caaa5ad6a 100644 --- a/lib/nfc/protocols/nfca/nfca_poller_i.c +++ b/lib/nfc/protocols/nfca/nfca_poller_i.c @@ -345,3 +345,123 @@ NfcaError nfca_poller_send_standart_frame( return ret; } + +static NfcPoller* nfca_poller_alloc_new(NfcPoller* nfc) { + furi_assert(nfc); + + NfcaPoller* instance = malloc(sizeof(NfcaPoller)); + instance->nfc = nfc; + instance->tx_buffer = bit_buffer_alloc(NFCA_POLLER_MAX_BUFFER_SIZE); + instance->rx_buffer = bit_buffer_alloc(NFCA_POLLER_MAX_BUFFER_SIZE); + + nfc_config(instance->nfc, NfcModeNfcaPoller); + nfc_set_guard_time_us(instance->nfc, NFCA_GUARD_TIME_US); + nfc_set_fdt_poll_fc(instance->nfc, NFCA_FDT_POLL_FC); + nfc_set_fdt_poll_poll_us(instance->nfc, NFCA_POLL_POLL_MIN_US); + instance->data = nfca_alloc(); + instance->event = malloc(sizeof(NfcaPollerEvent)); + + return instance; +} + +static void nfca_poller_free_new(NfcPoller* nfca_poller) { + furi_assert(nfca_poller); + + NfcaPoller* instance = nfca_poller; + furi_assert(instance->tx_buffer); + furi_assert(instance->rx_buffer); + furi_assert(instance->data); + furi_assert(instance->event); + + bit_buffer_free(instance->tx_buffer); + bit_buffer_free(instance->rx_buffer); + nfca_free(instance->data); + free(instance->event); + free(instance); +} + +static void + nfca_poller_set_callback(NfcPoller* poller, NfcPollerCallback callback, void* context) { + furi_assert(poller); + furi_assert(callback); + + NfcaPoller* instance = poller; + instance->callback_new = callback; + instance->context_new = context; +} + +static NfcCommand nfca_poller_run(NfcPollerEvent event, void* context) { + furi_assert(context); + + NfcaPoller* instance = context; + NfcEvent* nfc_event = event.data; + NfcCommand command = NfcCommandContinue; + NfcPollerEvent nfca_poller_event = { + .protocol_type = NfcProtocolTypeIso14443_3a, + .poller = instance, + }; + + if(nfc_event->type == NfcEventTypePollerReady) { + if(instance->state != NfcaPollerStateActivated) { + NfcaData data = {}; + NfcaError error = nfca_poller_async_activate(instance, &data); + if(error == NfcaErrorNone) { + instance->event->type = NfcaPollerEventTypeReady; + instance->event->data.error = error; + instance->state = NfcaPollerStateActivated; + nfca_poller_event.data = instance->event; + command = instance->callback_new(nfca_poller_event, instance->context_new); + } else { + instance->event->type = NfcaPollerEventTypeError; + instance->event->data.error = error; + nfca_poller_event.data = instance->event; + command = instance->callback_new(nfca_poller_event, instance->context_new); + // Add delay to switch context + furi_delay_ms(100); + } + } else { + instance->event->type = NfcaPollerEventTypeReady; + instance->event->data.error = NfcaErrorNone; + nfca_poller_event.data = instance->event; + command = instance->callback_new(nfca_poller_event, instance->context_new); + } + } + + return command; +} + +static bool nfca_poller_detect(NfcPollerEvent event, void* context) { + furi_assert(context); + furi_assert(event.data); + furi_assert(event.poller); + + bool protocol_detected = false; + NfcaPoller* instance = context; + NfcEvent* nfc_event = event.data; + furi_assert(instance->state == NfcaPollerStateIdle); + + if(nfc_event->type == NfcEventTypePollerReady) { + NfcaError error = nfca_poller_async_activate(instance, NULL); + protocol_detected = (error == NfcaErrorNone); + } + + return protocol_detected; +} + +static const NfcProtocolData* nfca_poller_get_data_new(const NfcPoller* nfca_poller) { + furi_assert(nfca_poller); + + const NfcaPoller* instance = nfca_poller; + furi_assert(instance->data); + + return instance->data; +} + +const NfcPollerBase nfc_poller_iso14443_3a = { + .alloc = nfca_poller_alloc_new, + .free = nfca_poller_free_new, + .set_callback = nfca_poller_set_callback, + .run = nfca_poller_run, + .detect = nfca_poller_detect, + .get_data = nfca_poller_get_data_new, +}; diff --git a/lib/nfc/protocols/nfca/nfca_poller_i.h b/lib/nfc/protocols/nfca/nfca_poller_i.h index 04c0612e3ef0..04e65b5c0b60 100644 --- a/lib/nfc/protocols/nfca/nfca_poller_i.h +++ b/lib/nfc/protocols/nfca/nfca_poller_i.h @@ -2,7 +2,8 @@ #include "nfca_poller.h" -#include +#include +#include #ifdef __cplusplus extern "C" { @@ -61,6 +62,10 @@ struct NfcaPoller { BitBuffer* rx_buffer; NfcaPollerEventCallback callback; void* context; + + NfcaPollerEvent* event; + NfcPollerCallback callback_new; + void* context_new; }; NfcaError nfca_poller_config(NfcaPoller* instance); @@ -91,6 +96,8 @@ NfcaError nfca_poller_send_standart_frame( BitBuffer* rx_buffer, uint32_t fwt); +extern const NfcPollerBase nfc_poller_iso14443_3a; + #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/nfcb/nfcb_poller_i .c b/lib/nfc/protocols/nfcb/nfcb_poller_i .c new file mode 100644 index 000000000000..9bd10a6ccddd --- /dev/null +++ b/lib/nfc/protocols/nfcb/nfcb_poller_i .c @@ -0,0 +1,6 @@ +#include "nfcb_poller_i.h" + +const NfcPollerBase nfcb_protocol_base = { + .alloc = NULL, + .free = NULL, +}; \ No newline at end of file diff --git a/lib/nfc/protocols/nfcb/nfcb_poller_i.h b/lib/nfc/protocols/nfcb/nfcb_poller_i.h new file mode 100644 index 000000000000..4eabadd0b0fe --- /dev/null +++ b/lib/nfc/protocols/nfcb/nfcb_poller_i.h @@ -0,0 +1,14 @@ +#pragma once + +#include "nfcb_poller.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern const NfcPollerBase nfcb_protocol_base; + +#ifdef __cplusplus +} +#endif From 6623c33482ec7c4ddf25f3933c26b422b96316a7 Mon Sep 17 00:00:00 2001 From: gornekich Date: Tue, 20 Jun 2023 16:53:45 +0400 Subject: [PATCH 106/149] nfc: fix typo --- applications/external/nfc_magic/lib/magic/magic.h | 2 +- applications/external/picopass/views/dict_attack.h | 2 +- applications/main/nfc/nfc_cli.c | 4 ++-- applications/main/nfc_old/views/dict_attack.h | 2 +- firmware/targets/f7/furi_hal/furi_hal_nfc.h | 2 +- lib/nfc/SConscript | 2 +- .../helpers/mf_classic_dict.c | 0 .../helpers/mf_classic_dict.h | 0 lib/nfc/{deprycated => deprecated}/helpers/mfkey32.c | 0 lib/nfc/{deprycated => deprecated}/helpers/mfkey32.h | 2 +- .../{deprycated => deprecated}/helpers/nfc_debug_log.c | 0 .../{deprycated => deprecated}/helpers/nfc_debug_log.h | 0 .../helpers/nfc_debug_pcap.c | 0 .../helpers/nfc_debug_pcap.h | 0 .../helpers/nfc_generators.c | 0 .../helpers/nfc_generators.h | 0 .../helpers/reader_analyzer.c | 2 +- .../helpers/reader_analyzer.h | 2 +- lib/nfc/{deprycated => deprecated}/nfc_device.c | 0 lib/nfc/{deprycated => deprecated}/nfc_device.h | 10 +++++----- lib/nfc/{deprycated => deprecated}/nfc_types.c | 0 lib/nfc/{deprycated => deprecated}/nfc_types.h | 0 lib/nfc/{deprycated => deprecated}/nfc_worker.c | 0 lib/nfc/{deprycated => deprecated}/nfc_worker.h | 0 lib/nfc/{deprycated => deprecated}/nfc_worker_i.h | 10 +++++----- .../{deprycated => deprecated}/parsers/all_in_one.c | 2 +- .../{deprycated => deprecated}/parsers/all_in_one.h | 0 .../parsers/nfc_supported_card.c | 0 .../parsers/nfc_supported_card.h | 0 .../parsers/plantain_4k_parser.c | 2 +- .../parsers/plantain_4k_parser.h | 0 .../parsers/plantain_parser.c | 2 +- .../parsers/plantain_parser.h | 0 .../parsers/troika_4k_parser.c | 2 +- .../parsers/troika_4k_parser.h | 0 .../{deprycated => deprecated}/parsers/troika_parser.c | 2 +- .../{deprycated => deprecated}/parsers/troika_parser.h | 0 .../{deprycated => deprecated}/parsers/two_cities.c | 2 +- .../{deprycated => deprecated}/parsers/two_cities.h | 0 lib/nfc/{deprycated => deprecated}/protocols/crypto1.c | 0 lib/nfc/{deprycated => deprecated}/protocols/crypto1.h | 0 lib/nfc/{deprycated => deprecated}/protocols/emv.c | 0 lib/nfc/{deprycated => deprecated}/protocols/emv.h | 0 .../protocols/mifare_classic.c | 2 +- .../protocols/mifare_classic.h | 0 .../protocols/mifare_common.c | 0 .../protocols/mifare_common.h | 0 .../protocols/mifare_desfire.c | 0 .../protocols/mifare_desfire.h | 0 .../protocols/mifare_ultralight.c | 0 .../protocols/mifare_ultralight.h | 0 .../{deprycated => deprecated}/protocols/nfca_utils.c | 0 .../{deprycated => deprecated}/protocols/nfca_utils.h | 0 53 files changed, 27 insertions(+), 27 deletions(-) rename lib/nfc/{deprycated => deprecated}/helpers/mf_classic_dict.c (100%) rename lib/nfc/{deprycated => deprecated}/helpers/mf_classic_dict.h (100%) rename lib/nfc/{deprycated => deprecated}/helpers/mfkey32.c (100%) rename lib/nfc/{deprycated => deprecated}/helpers/mfkey32.h (90%) rename lib/nfc/{deprycated => deprecated}/helpers/nfc_debug_log.c (100%) rename lib/nfc/{deprycated => deprecated}/helpers/nfc_debug_log.h (100%) rename lib/nfc/{deprycated => deprecated}/helpers/nfc_debug_pcap.c (100%) rename lib/nfc/{deprycated => deprecated}/helpers/nfc_debug_pcap.h (100%) rename lib/nfc/{deprycated => deprecated}/helpers/nfc_generators.c (100%) rename lib/nfc/{deprycated => deprecated}/helpers/nfc_generators.h (100%) rename lib/nfc/{deprycated => deprecated}/helpers/reader_analyzer.c (99%) rename lib/nfc/{deprycated => deprecated}/helpers/reader_analyzer.h (96%) rename lib/nfc/{deprycated => deprecated}/nfc_device.c (100%) rename lib/nfc/{deprycated => deprecated}/nfc_device.h (90%) rename lib/nfc/{deprycated => deprecated}/nfc_types.c (100%) rename lib/nfc/{deprycated => deprecated}/nfc_types.h (100%) rename lib/nfc/{deprycated => deprecated}/nfc_worker.c (100%) rename lib/nfc/{deprycated => deprecated}/nfc_worker.h (100%) rename lib/nfc/{deprycated => deprecated}/nfc_worker_i.h (80%) rename lib/nfc/{deprycated => deprecated}/parsers/all_in_one.c (98%) rename lib/nfc/{deprycated => deprecated}/parsers/all_in_one.h (100%) rename lib/nfc/{deprycated => deprecated}/parsers/nfc_supported_card.c (100%) rename lib/nfc/{deprycated => deprecated}/parsers/nfc_supported_card.h (100%) rename lib/nfc/{deprycated => deprecated}/parsers/plantain_4k_parser.c (99%) rename lib/nfc/{deprycated => deprecated}/parsers/plantain_4k_parser.h (100%) rename lib/nfc/{deprycated => deprecated}/parsers/plantain_parser.c (98%) rename lib/nfc/{deprycated => deprecated}/parsers/plantain_parser.h (100%) rename lib/nfc/{deprycated => deprecated}/parsers/troika_4k_parser.c (99%) rename lib/nfc/{deprycated => deprecated}/parsers/troika_4k_parser.h (100%) rename lib/nfc/{deprycated => deprecated}/parsers/troika_parser.c (98%) rename lib/nfc/{deprycated => deprecated}/parsers/troika_parser.h (100%) rename lib/nfc/{deprycated => deprecated}/parsers/two_cities.c (99%) rename lib/nfc/{deprycated => deprecated}/parsers/two_cities.h (100%) rename lib/nfc/{deprycated => deprecated}/protocols/crypto1.c (100%) rename lib/nfc/{deprycated => deprecated}/protocols/crypto1.h (100%) rename lib/nfc/{deprycated => deprecated}/protocols/emv.c (100%) rename lib/nfc/{deprycated => deprecated}/protocols/emv.h (100%) rename lib/nfc/{deprycated => deprecated}/protocols/mifare_classic.c (99%) rename lib/nfc/{deprycated => deprecated}/protocols/mifare_classic.h (100%) rename lib/nfc/{deprycated => deprecated}/protocols/mifare_common.c (100%) rename lib/nfc/{deprycated => deprecated}/protocols/mifare_common.h (100%) rename lib/nfc/{deprycated => deprecated}/protocols/mifare_desfire.c (100%) rename lib/nfc/{deprycated => deprecated}/protocols/mifare_desfire.h (100%) rename lib/nfc/{deprycated => deprecated}/protocols/mifare_ultralight.c (100%) rename lib/nfc/{deprycated => deprecated}/protocols/mifare_ultralight.h (100%) rename lib/nfc/{deprycated => deprecated}/protocols/nfca_utils.c (100%) rename lib/nfc/{deprycated => deprecated}/protocols/nfca_utils.h (100%) diff --git a/applications/external/nfc_magic/lib/magic/magic.h b/applications/external/nfc_magic/lib/magic/magic.h index 9be1f7bf6616..15e793d894cb 100644 --- a/applications/external/nfc_magic/lib/magic/magic.h +++ b/applications/external/nfc_magic/lib/magic/magic.h @@ -1,6 +1,6 @@ #pragma once -#include +#include bool magic_wupa(); diff --git a/applications/external/picopass/views/dict_attack.h b/applications/external/picopass/views/dict_attack.h index 2474bf6e4335..d675c1eb40c7 100644 --- a/applications/external/picopass/views/dict_attack.h +++ b/applications/external/picopass/views/dict_attack.h @@ -3,7 +3,7 @@ #include #include -#include +#include typedef struct DictAttack DictAttack; diff --git a/applications/main/nfc/nfc_cli.c b/applications/main/nfc/nfc_cli.c index c4ca6d6a6e87..3fbc7cd6848b 100644 --- a/applications/main/nfc/nfc_cli.c +++ b/applications/main/nfc/nfc_cli.c @@ -4,8 +4,8 @@ #include #include -#include -#include +#include +#include static void nfc_cli_print_usage() { printf("Usage:\r\n"); diff --git a/applications/main/nfc_old/views/dict_attack.h b/applications/main/nfc_old/views/dict_attack.h index 6a633f85c5c3..181cbbae5574 100644 --- a/applications/main/nfc_old/views/dict_attack.h +++ b/applications/main/nfc_old/views/dict_attack.h @@ -3,7 +3,7 @@ #include #include -#include +#include typedef struct DictAttack DictAttack; diff --git a/firmware/targets/f7/furi_hal/furi_hal_nfc.h b/firmware/targets/f7/furi_hal/furi_hal_nfc.h index 0ead657cbae0..81d2bae484f3 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_nfc.h +++ b/firmware/targets/f7/furi_hal/furi_hal_nfc.h @@ -13,7 +13,7 @@ extern "C" { #endif #include -#include +#include #define FURI_HAL_NFC_UID_MAX_LEN 10 #define FURI_HAL_NFC_DATA_BUFF_SIZE (512) diff --git a/lib/nfc/SConscript b/lib/nfc/SConscript index 779c8b390e94..e617537a4f35 100644 --- a/lib/nfc/SConscript +++ b/lib/nfc/SConscript @@ -13,7 +13,7 @@ env.Append( libenv = env.Clone(FW_LIB_NAME="nfc") libenv.ApplyLibFlags() -sources = libenv.GlobRecursive("*.c*", exclude="deprycated/*c") +sources = libenv.GlobRecursive("*.c*", exclude="deprecated/*c") lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) libenv.Install("${LIB_DIST_DIR}", lib) diff --git a/lib/nfc/deprycated/helpers/mf_classic_dict.c b/lib/nfc/deprecated/helpers/mf_classic_dict.c similarity index 100% rename from lib/nfc/deprycated/helpers/mf_classic_dict.c rename to lib/nfc/deprecated/helpers/mf_classic_dict.c diff --git a/lib/nfc/deprycated/helpers/mf_classic_dict.h b/lib/nfc/deprecated/helpers/mf_classic_dict.h similarity index 100% rename from lib/nfc/deprycated/helpers/mf_classic_dict.h rename to lib/nfc/deprecated/helpers/mf_classic_dict.h diff --git a/lib/nfc/deprycated/helpers/mfkey32.c b/lib/nfc/deprecated/helpers/mfkey32.c similarity index 100% rename from lib/nfc/deprycated/helpers/mfkey32.c rename to lib/nfc/deprecated/helpers/mfkey32.c diff --git a/lib/nfc/deprycated/helpers/mfkey32.h b/lib/nfc/deprecated/helpers/mfkey32.h similarity index 90% rename from lib/nfc/deprycated/helpers/mfkey32.h rename to lib/nfc/deprecated/helpers/mfkey32.h index 37d7761257d0..9648f3e7a8fd 100644 --- a/lib/nfc/deprycated/helpers/mfkey32.h +++ b/lib/nfc/deprecated/helpers/mfkey32.h @@ -1,6 +1,6 @@ #pragma once -#include +#include typedef struct Mfkey32 Mfkey32; diff --git a/lib/nfc/deprycated/helpers/nfc_debug_log.c b/lib/nfc/deprecated/helpers/nfc_debug_log.c similarity index 100% rename from lib/nfc/deprycated/helpers/nfc_debug_log.c rename to lib/nfc/deprecated/helpers/nfc_debug_log.c diff --git a/lib/nfc/deprycated/helpers/nfc_debug_log.h b/lib/nfc/deprecated/helpers/nfc_debug_log.h similarity index 100% rename from lib/nfc/deprycated/helpers/nfc_debug_log.h rename to lib/nfc/deprecated/helpers/nfc_debug_log.h diff --git a/lib/nfc/deprycated/helpers/nfc_debug_pcap.c b/lib/nfc/deprecated/helpers/nfc_debug_pcap.c similarity index 100% rename from lib/nfc/deprycated/helpers/nfc_debug_pcap.c rename to lib/nfc/deprecated/helpers/nfc_debug_pcap.c diff --git a/lib/nfc/deprycated/helpers/nfc_debug_pcap.h b/lib/nfc/deprecated/helpers/nfc_debug_pcap.h similarity index 100% rename from lib/nfc/deprycated/helpers/nfc_debug_pcap.h rename to lib/nfc/deprecated/helpers/nfc_debug_pcap.h diff --git a/lib/nfc/deprycated/helpers/nfc_generators.c b/lib/nfc/deprecated/helpers/nfc_generators.c similarity index 100% rename from lib/nfc/deprycated/helpers/nfc_generators.c rename to lib/nfc/deprecated/helpers/nfc_generators.c diff --git a/lib/nfc/deprycated/helpers/nfc_generators.h b/lib/nfc/deprecated/helpers/nfc_generators.h similarity index 100% rename from lib/nfc/deprycated/helpers/nfc_generators.h rename to lib/nfc/deprecated/helpers/nfc_generators.h diff --git a/lib/nfc/deprycated/helpers/reader_analyzer.c b/lib/nfc/deprecated/helpers/reader_analyzer.c similarity index 99% rename from lib/nfc/deprycated/helpers/reader_analyzer.c rename to lib/nfc/deprecated/helpers/reader_analyzer.c index bbdc2ad5b436..b76e560da4d6 100644 --- a/lib/nfc/deprycated/helpers/reader_analyzer.c +++ b/lib/nfc/deprecated/helpers/reader_analyzer.c @@ -1,6 +1,6 @@ #include "reader_analyzer.h" #include -#include +#include #include #include "mfkey32.h" diff --git a/lib/nfc/deprycated/helpers/reader_analyzer.h b/lib/nfc/deprecated/helpers/reader_analyzer.h similarity index 96% rename from lib/nfc/deprycated/helpers/reader_analyzer.h rename to lib/nfc/deprecated/helpers/reader_analyzer.h index 12258e4c3fee..41b274207d36 100644 --- a/lib/nfc/deprycated/helpers/reader_analyzer.h +++ b/lib/nfc/deprecated/helpers/reader_analyzer.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include typedef enum { ReaderAnalyzerModeDebugLog = 0x01, diff --git a/lib/nfc/deprycated/nfc_device.c b/lib/nfc/deprecated/nfc_device.c similarity index 100% rename from lib/nfc/deprycated/nfc_device.c rename to lib/nfc/deprecated/nfc_device.c diff --git a/lib/nfc/deprycated/nfc_device.h b/lib/nfc/deprecated/nfc_device.h similarity index 90% rename from lib/nfc/deprycated/nfc_device.h rename to lib/nfc/deprecated/nfc_device.h index f264665aec37..2a8fe3fcede2 100644 --- a/lib/nfc/deprycated/nfc_device.h +++ b/lib/nfc/deprecated/nfc_device.h @@ -6,11 +6,11 @@ #include #include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #ifdef __cplusplus extern "C" { diff --git a/lib/nfc/deprycated/nfc_types.c b/lib/nfc/deprecated/nfc_types.c similarity index 100% rename from lib/nfc/deprycated/nfc_types.c rename to lib/nfc/deprecated/nfc_types.c diff --git a/lib/nfc/deprycated/nfc_types.h b/lib/nfc/deprecated/nfc_types.h similarity index 100% rename from lib/nfc/deprycated/nfc_types.h rename to lib/nfc/deprecated/nfc_types.h diff --git a/lib/nfc/deprycated/nfc_worker.c b/lib/nfc/deprecated/nfc_worker.c similarity index 100% rename from lib/nfc/deprycated/nfc_worker.c rename to lib/nfc/deprecated/nfc_worker.c diff --git a/lib/nfc/deprycated/nfc_worker.h b/lib/nfc/deprecated/nfc_worker.h similarity index 100% rename from lib/nfc/deprycated/nfc_worker.h rename to lib/nfc/deprecated/nfc_worker.h diff --git a/lib/nfc/deprycated/nfc_worker_i.h b/lib/nfc/deprecated/nfc_worker_i.h similarity index 80% rename from lib/nfc/deprycated/nfc_worker_i.h rename to lib/nfc/deprecated/nfc_worker_i.h index 7129b4cf02fe..38afb67befe7 100644 --- a/lib/nfc/deprycated/nfc_worker_i.h +++ b/lib/nfc/deprecated/nfc_worker_i.h @@ -6,11 +6,11 @@ #include #include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include struct NfcWorker { FuriThread* thread; diff --git a/lib/nfc/deprycated/parsers/all_in_one.c b/lib/nfc/deprecated/parsers/all_in_one.c similarity index 98% rename from lib/nfc/deprycated/parsers/all_in_one.c rename to lib/nfc/deprecated/parsers/all_in_one.c index dfe21ce5e8a4..b309d240bbba 100644 --- a/lib/nfc/deprycated/parsers/all_in_one.c +++ b/lib/nfc/deprecated/parsers/all_in_one.c @@ -2,7 +2,7 @@ #include "all_in_one.h" #include -#include +#include #include diff --git a/lib/nfc/deprycated/parsers/all_in_one.h b/lib/nfc/deprecated/parsers/all_in_one.h similarity index 100% rename from lib/nfc/deprycated/parsers/all_in_one.h rename to lib/nfc/deprecated/parsers/all_in_one.h diff --git a/lib/nfc/deprycated/parsers/nfc_supported_card.c b/lib/nfc/deprecated/parsers/nfc_supported_card.c similarity index 100% rename from lib/nfc/deprycated/parsers/nfc_supported_card.c rename to lib/nfc/deprecated/parsers/nfc_supported_card.c diff --git a/lib/nfc/deprycated/parsers/nfc_supported_card.h b/lib/nfc/deprecated/parsers/nfc_supported_card.h similarity index 100% rename from lib/nfc/deprycated/parsers/nfc_supported_card.h rename to lib/nfc/deprecated/parsers/nfc_supported_card.h diff --git a/lib/nfc/deprycated/parsers/plantain_4k_parser.c b/lib/nfc/deprecated/parsers/plantain_4k_parser.c similarity index 99% rename from lib/nfc/deprycated/parsers/plantain_4k_parser.c rename to lib/nfc/deprecated/parsers/plantain_4k_parser.c index e41fafce34c5..092450e8515c 100644 --- a/lib/nfc/deprycated/parsers/plantain_4k_parser.c +++ b/lib/nfc/deprecated/parsers/plantain_4k_parser.c @@ -1,7 +1,7 @@ #include "nfc_supported_card.h" #include -#include +#include #include diff --git a/lib/nfc/deprycated/parsers/plantain_4k_parser.h b/lib/nfc/deprecated/parsers/plantain_4k_parser.h similarity index 100% rename from lib/nfc/deprycated/parsers/plantain_4k_parser.h rename to lib/nfc/deprecated/parsers/plantain_4k_parser.h diff --git a/lib/nfc/deprycated/parsers/plantain_parser.c b/lib/nfc/deprecated/parsers/plantain_parser.c similarity index 98% rename from lib/nfc/deprycated/parsers/plantain_parser.c rename to lib/nfc/deprecated/parsers/plantain_parser.c index 1dd5dc49868b..b29fadfdf6c4 100644 --- a/lib/nfc/deprycated/parsers/plantain_parser.c +++ b/lib/nfc/deprecated/parsers/plantain_parser.c @@ -1,7 +1,7 @@ #include "nfc_supported_card.h" #include -#include +#include #include diff --git a/lib/nfc/deprycated/parsers/plantain_parser.h b/lib/nfc/deprecated/parsers/plantain_parser.h similarity index 100% rename from lib/nfc/deprycated/parsers/plantain_parser.h rename to lib/nfc/deprecated/parsers/plantain_parser.h diff --git a/lib/nfc/deprycated/parsers/troika_4k_parser.c b/lib/nfc/deprecated/parsers/troika_4k_parser.c similarity index 99% rename from lib/nfc/deprycated/parsers/troika_4k_parser.c rename to lib/nfc/deprecated/parsers/troika_4k_parser.c index 1a9108c74b93..5f874a95fc91 100644 --- a/lib/nfc/deprycated/parsers/troika_4k_parser.c +++ b/lib/nfc/deprecated/parsers/troika_4k_parser.c @@ -1,7 +1,7 @@ #include "nfc_supported_card.h" #include -#include +#include static const MfClassicAuthContext troika_4k_keys[] = { {.sector = 0, .key_a = 0xa0a1a2a3a4a5, .key_b = 0xfbf225dc5d58}, diff --git a/lib/nfc/deprycated/parsers/troika_4k_parser.h b/lib/nfc/deprecated/parsers/troika_4k_parser.h similarity index 100% rename from lib/nfc/deprycated/parsers/troika_4k_parser.h rename to lib/nfc/deprecated/parsers/troika_4k_parser.h diff --git a/lib/nfc/deprycated/parsers/troika_parser.c b/lib/nfc/deprecated/parsers/troika_parser.c similarity index 98% rename from lib/nfc/deprycated/parsers/troika_parser.c rename to lib/nfc/deprecated/parsers/troika_parser.c index d9e81bab617b..fd1210ca9383 100644 --- a/lib/nfc/deprycated/parsers/troika_parser.c +++ b/lib/nfc/deprecated/parsers/troika_parser.c @@ -1,7 +1,7 @@ #include "nfc_supported_card.h" #include -#include +#include static const MfClassicAuthContext troika_keys[] = { {.sector = 0, .key_a = 0xa0a1a2a3a4a5, .key_b = 0xfbf225dc5d58}, diff --git a/lib/nfc/deprycated/parsers/troika_parser.h b/lib/nfc/deprecated/parsers/troika_parser.h similarity index 100% rename from lib/nfc/deprycated/parsers/troika_parser.h rename to lib/nfc/deprecated/parsers/troika_parser.h diff --git a/lib/nfc/deprycated/parsers/two_cities.c b/lib/nfc/deprecated/parsers/two_cities.c similarity index 99% rename from lib/nfc/deprycated/parsers/two_cities.c rename to lib/nfc/deprecated/parsers/two_cities.c index 9410f94f87e9..355995e4fb1c 100644 --- a/lib/nfc/deprycated/parsers/two_cities.c +++ b/lib/nfc/deprecated/parsers/two_cities.c @@ -2,7 +2,7 @@ #include "plantain_parser.h" // For plantain-specific stuff #include -#include +#include #include diff --git a/lib/nfc/deprycated/parsers/two_cities.h b/lib/nfc/deprecated/parsers/two_cities.h similarity index 100% rename from lib/nfc/deprycated/parsers/two_cities.h rename to lib/nfc/deprecated/parsers/two_cities.h diff --git a/lib/nfc/deprycated/protocols/crypto1.c b/lib/nfc/deprecated/protocols/crypto1.c similarity index 100% rename from lib/nfc/deprycated/protocols/crypto1.c rename to lib/nfc/deprecated/protocols/crypto1.c diff --git a/lib/nfc/deprycated/protocols/crypto1.h b/lib/nfc/deprecated/protocols/crypto1.h similarity index 100% rename from lib/nfc/deprycated/protocols/crypto1.h rename to lib/nfc/deprecated/protocols/crypto1.h diff --git a/lib/nfc/deprycated/protocols/emv.c b/lib/nfc/deprecated/protocols/emv.c similarity index 100% rename from lib/nfc/deprycated/protocols/emv.c rename to lib/nfc/deprecated/protocols/emv.c diff --git a/lib/nfc/deprycated/protocols/emv.h b/lib/nfc/deprecated/protocols/emv.h similarity index 100% rename from lib/nfc/deprycated/protocols/emv.h rename to lib/nfc/deprecated/protocols/emv.h diff --git a/lib/nfc/deprycated/protocols/mifare_classic.c b/lib/nfc/deprecated/protocols/mifare_classic.c similarity index 99% rename from lib/nfc/deprycated/protocols/mifare_classic.c rename to lib/nfc/deprecated/protocols/mifare_classic.c index cbab5928b0f0..d088be5b6126 100644 --- a/lib/nfc/deprycated/protocols/mifare_classic.c +++ b/lib/nfc/deprecated/protocols/mifare_classic.c @@ -1,5 +1,5 @@ #include "mifare_classic.h" -#include +#include #include #include diff --git a/lib/nfc/deprycated/protocols/mifare_classic.h b/lib/nfc/deprecated/protocols/mifare_classic.h similarity index 100% rename from lib/nfc/deprycated/protocols/mifare_classic.h rename to lib/nfc/deprecated/protocols/mifare_classic.h diff --git a/lib/nfc/deprycated/protocols/mifare_common.c b/lib/nfc/deprecated/protocols/mifare_common.c similarity index 100% rename from lib/nfc/deprycated/protocols/mifare_common.c rename to lib/nfc/deprecated/protocols/mifare_common.c diff --git a/lib/nfc/deprycated/protocols/mifare_common.h b/lib/nfc/deprecated/protocols/mifare_common.h similarity index 100% rename from lib/nfc/deprycated/protocols/mifare_common.h rename to lib/nfc/deprecated/protocols/mifare_common.h diff --git a/lib/nfc/deprycated/protocols/mifare_desfire.c b/lib/nfc/deprecated/protocols/mifare_desfire.c similarity index 100% rename from lib/nfc/deprycated/protocols/mifare_desfire.c rename to lib/nfc/deprecated/protocols/mifare_desfire.c diff --git a/lib/nfc/deprycated/protocols/mifare_desfire.h b/lib/nfc/deprecated/protocols/mifare_desfire.h similarity index 100% rename from lib/nfc/deprycated/protocols/mifare_desfire.h rename to lib/nfc/deprecated/protocols/mifare_desfire.h diff --git a/lib/nfc/deprycated/protocols/mifare_ultralight.c b/lib/nfc/deprecated/protocols/mifare_ultralight.c similarity index 100% rename from lib/nfc/deprycated/protocols/mifare_ultralight.c rename to lib/nfc/deprecated/protocols/mifare_ultralight.c diff --git a/lib/nfc/deprycated/protocols/mifare_ultralight.h b/lib/nfc/deprecated/protocols/mifare_ultralight.h similarity index 100% rename from lib/nfc/deprycated/protocols/mifare_ultralight.h rename to lib/nfc/deprecated/protocols/mifare_ultralight.h diff --git a/lib/nfc/deprycated/protocols/nfca_utils.c b/lib/nfc/deprecated/protocols/nfca_utils.c similarity index 100% rename from lib/nfc/deprycated/protocols/nfca_utils.c rename to lib/nfc/deprecated/protocols/nfca_utils.c diff --git a/lib/nfc/deprycated/protocols/nfca_utils.h b/lib/nfc/deprecated/protocols/nfca_utils.h similarity index 100% rename from lib/nfc/deprycated/protocols/nfca_utils.h rename to lib/nfc/deprecated/protocols/nfca_utils.h From 4b7e3d0f915030f917f53ddd940f66e4ec63add3 Mon Sep 17 00:00:00 2001 From: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Date: Wed, 21 Jun 2023 17:56:07 +0300 Subject: [PATCH 107/149] Gsurkov/mf desfire iter4 (#2791) * Remove unneeded functions * Port ISO14443-4A and Mifare DESfire to nfc_poller_manager * Refactor ISO14443-4A and MfDesfire code * Cleanup poller file structure * Implement detect method for ISO14443-4A * Implement detect method for Mifare DESfire --- applications/main/nfc/nfc_app.c | 4 - applications/main/nfc/nfc_app_i.h | 3 - .../nfc/scenes/nfc_scene_mf_desfire_read.c | 52 +++-- lib/nfc/nfc_poller.c | 2 - lib/nfc/nfc_poller_defs.c | 23 +- lib/nfc/nfc_poller_defs.h | 1 - lib/nfc/protocols/iso14443_4a/iso14443_4a.c | 9 +- lib/nfc/protocols/iso14443_4a/iso14443_4a.h | 16 +- lib/nfc/protocols/iso14443_4a/iso14443_4a_i.c | 9 + lib/nfc/protocols/iso14443_4a/iso14443_4a_i.h | 5 + .../iso14443_4a/iso14443_4a_poller.c | 206 +++++++---------- .../iso14443_4a/iso14443_4a_poller.h | 25 --- .../iso14443_4a/iso14443_4a_poller_defs.h | 5 + .../iso14443_4a/iso14443_4a_poller_i.c | 99 +++------ .../iso14443_4a/iso14443_4a_poller_i.h | 22 +- lib/nfc/protocols/mf_desfire/mf_desfire.c | 7 - lib/nfc/protocols/mf_desfire/mf_desfire.h | 3 - .../protocols/mf_desfire/mf_desfire_poller.c | 207 +++++++----------- .../protocols/mf_desfire/mf_desfire_poller.h | 25 --- .../mf_desfire/mf_desfire_poller_defs.h | 5 + .../mf_desfire/mf_desfire_poller_i.c | 18 +- .../mf_desfire/mf_desfire_poller_i.h | 11 +- .../mf_ultralight/mf_ultralight_poller_defs.h | 5 + .../mf_ultralight/mf_ultralight_poller_i.h | 2 - lib/nfc/protocols/nfca/nfca_poller_defs.h | 5 + lib/nfc/protocols/nfca/nfca_poller_i.h | 2 - 26 files changed, 325 insertions(+), 446 deletions(-) create mode 100644 lib/nfc/protocols/iso14443_4a/iso14443_4a_i.c create mode 100644 lib/nfc/protocols/iso14443_4a/iso14443_4a_i.h create mode 100644 lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_defs.h create mode 100644 lib/nfc/protocols/mf_desfire/mf_desfire_poller_defs.h create mode 100644 lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_defs.h create mode 100644 lib/nfc/protocols/nfca/nfca_poller_defs.h diff --git a/applications/main/nfc/nfc_app.c b/applications/main/nfc/nfc_app.c index 804fd35be1f1..9263a5e77441 100644 --- a/applications/main/nfc/nfc_app.c +++ b/applications/main/nfc/nfc_app.c @@ -47,9 +47,7 @@ NfcApp* nfc_app_alloc() { instance->nfc = nfc_alloc(); instance->nfca_poller = nfca_poller_alloc(instance->nfc); - instance->iso14443_4a_poller = iso14443_4a_poller_alloc(instance->nfca_poller); instance->mf_ul_poller = mf_ultralight_poller_alloc(instance->nfca_poller); - instance->mf_desfire_poller = mf_desfire_poller_alloc(instance->iso14443_4a_poller); instance->mf_classic_poller = mf_classic_poller_alloc(instance->nfca_poller); instance->nfca_listener = nfca_listener_alloc(instance->nfc); instance->mf_ul_listener = mf_ultralight_listener_alloc(instance->nfca_listener); @@ -166,11 +164,9 @@ void nfc_app_free(NfcApp* instance) { furi_string_free(instance->parsed_data); - mf_desfire_poller_free(instance->mf_desfire_poller); mf_classic_poller_free(instance->mf_classic_poller); mf_ultralight_listener_free(instance->mf_ul_listener); mf_ultralight_poller_free(instance->mf_ul_poller); - iso14443_4a_poller_free(instance->iso14443_4a_poller); nfca_listener_free(instance->nfca_listener); nfca_poller_free(instance->nfca_poller); nfcb_poller_free(instance->nfcb_poller); diff --git a/applications/main/nfc/nfc_app_i.h b/applications/main/nfc/nfc_app_i.h index 81d5cf089190..57f0b664da81 100644 --- a/applications/main/nfc/nfc_app_i.h +++ b/applications/main/nfc/nfc_app_i.h @@ -44,7 +44,6 @@ #include #include #include -#include #include #include @@ -108,10 +107,8 @@ struct NfcApp { Nfc* nfc; NfcaPoller* nfca_poller; NfcaListener* nfca_listener; - Iso14443_4aPoller* iso14443_4a_poller; MfUltralightPoller* mf_ul_poller; MfUltralightListener* mf_ul_listener; - MfDesfirePoller* mf_desfire_poller; MfClassicPoller* mf_classic_poller; NfcbPoller* nfcb_poller; NfcPollerOld* nfc_poller; diff --git a/applications/main/nfc/scenes/nfc_scene_mf_desfire_read.c b/applications/main/nfc/scenes/nfc_scene_mf_desfire_read.c index 133f8d0e1f0e..3b18c684e704 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_desfire_read.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_desfire_read.c @@ -5,44 +5,52 @@ enum { NfcWorkerEventMfDesfireReadSuccess, }; -MfDesfirePollerCommand - nfc_scene_mf_desfire_read_worker_callback(MfDesfirePollerEvent event, void* context) { - NfcApp* nfc = context; +static NfcCommand nfc_scene_mf_desfire_read_worker_callback(NfcPollerEvent event, void* context) { + furi_assert(event.protocol_type == NfcProtocolTypeMfDesfire); + furi_assert(context); - MfDesfirePollerCommand command = MfDesfirePollerCommandContinue; + NfcApp* instance = context; + MfDesfirePoller* mf_desfire_poller = event.poller; + const MfDesfirePollerEvent* mf_desfire_event = event.data; - if(event.type == MfDesfirePollerEventTypeReadSuccess) { + NfcCommand command = NfcCommandContinue; + + if(mf_desfire_event->type == MfDesfirePollerEventTypeReadSuccess) { + nfc_dev_set_protocol_data( + instance->nfc_dev, + NfcProtocolTypeMfDesfire, + mf_desfire_poller_get_data(mf_desfire_poller)); view_dispatcher_send_custom_event( - nfc->view_dispatcher, NfcWorkerEventMfDesfireReadSuccess); - command = MfDesfirePollerCommandStop; + instance->view_dispatcher, NfcWorkerEventMfDesfireReadSuccess); + command = NfcCommandStop; } return command; } void nfc_scene_mf_desfire_read_on_enter(void* context) { - NfcApp* nfc = context; + NfcApp* instance = context; // Setup view - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup); - mf_desfire_poller_read(nfc->mf_desfire_poller, nfc_scene_mf_desfire_read_worker_callback, nfc); + nfc_poller_manager_start( + instance->poller_manager, + NfcProtocolTypeMfDesfire, + nfc_scene_mf_desfire_read_worker_callback, + instance); - nfc_blink_read_start(nfc); + nfc_blink_read_start(instance); } bool nfc_scene_mf_desfire_read_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + NfcApp* instance = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { if(event.event == NfcWorkerEventMfDesfireReadSuccess) { - notification_message(nfc->notifications, &sequence_success); - nfc_dev_set_protocol_data( - nfc->nfc_dev, - NfcProtocolTypeMfDesfire, - mf_desfire_poller_get_data(nfc->mf_desfire_poller)); - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireReadSuccess); + notification_message(instance->notifications, &sequence_success); + scene_manager_next_scene(instance->scene_manager, NfcSceneMfDesfireReadSuccess); DOLPHIN_DEED(DolphinDeedNfcReadSuccess); consumed = true; } @@ -51,11 +59,11 @@ bool nfc_scene_mf_desfire_read_on_event(void* context, SceneManagerEvent event) } void nfc_scene_mf_desfire_read_on_exit(void* context) { - NfcApp* nfc = context; + NfcApp* instance = context; - mf_desfire_poller_stop(nfc->mf_desfire_poller); + nfc_poller_manager_stop(instance->poller_manager); // Clear view - popup_reset(nfc->popup); + popup_reset(instance->popup); - nfc_blink_stop(nfc); + nfc_blink_stop(instance); } diff --git a/lib/nfc/nfc_poller.c b/lib/nfc/nfc_poller.c index 1503d4edaa2c..c38b6591a6da 100644 --- a/lib/nfc/nfc_poller.c +++ b/lib/nfc/nfc_poller.c @@ -93,8 +93,6 @@ static NfcCommand nfc_poller_event_callback(NfcEvent event, void* context) { if(error == NfcaErrorNone) { if(mf_ultralight_detect_protocol(&instance->nfca_data)) { poller_event = NfcPollerOldEventMfUltralightDetected; - } else if(mf_desfire_detect_protocol(&instance->nfca_data)) { - poller_event = NfcPollerOldEventMfDesfireDetected; } else { poller_event = NfcPollerOldEventNfcaDetected; } diff --git a/lib/nfc/nfc_poller_defs.c b/lib/nfc/nfc_poller_defs.c index da7fa2d70796..bc530c1bd5ed 100644 --- a/lib/nfc/nfc_poller_defs.c +++ b/lib/nfc/nfc_poller_defs.c @@ -1,8 +1,9 @@ #include "nfc_poller_defs.h" -#include -#include -#include +#include +#include +#include +#include #include @@ -10,13 +11,19 @@ const NfcPollerBase* nfc_pollers_api[NfcProtocolTypeMax] = { [NfcProtocolTypeIso14443_3a] = &nfc_poller_iso14443_3a, [NfcProtocolTypeIso14443_4a] = &nfc_poller_iso14443_4a, [NfcProtocolTypeMfUltralight] = &mf_ultralight_poller, + [NfcProtocolTypeMfClassic] = NULL, + [NfcProtocolTypeMfDesfire] = &mf_desfire_poller, }; -// nfc-a nfc-b nfc-f nfc-v -// -// iso14443-4a mf ultraligh mf classic -// -// mf desfire bank card +/**************************** Poller tree structure **************************** + * _________ start ___________________________ + * / | | \ + * _________ iso14443-3a _______ nfc-b nfc-f nfc-v + * / | \ + * iso14443-4a mf ultralight mf classic + * / \ + * mf desfire bank card + */ static const NfcProtocolType nfc_poller_iso14443_3a_children_protocol[] = { NfcProtocolTypeIso14443_4a, diff --git a/lib/nfc/nfc_poller_defs.h b/lib/nfc/nfc_poller_defs.h index 5e92ac71b7f3..8eb550ebf277 100644 --- a/lib/nfc/nfc_poller_defs.h +++ b/lib/nfc/nfc_poller_defs.h @@ -1,6 +1,5 @@ #pragma once -#include #include "nfc_poller_base.h" #ifdef __cplusplus diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a.c b/lib/nfc/protocols/iso14443_4a/iso14443_4a.c index 834f6a0a7909..0776a5c8778c 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a.c +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a.c @@ -1,8 +1,9 @@ -#include "iso14443_4a.h" +#include "iso14443_4a_i.h" #include #define ISO14443_4A_PROTOCOL_NAME "Unknown ISO14443-4A Tag" +#define ISO14443_4A_ATS_BIT (1 << 5) const NfcProtocolBase nfc_protocol_iso14443_4a = { .alloc = (NfcProtocolAlloc)iso14443_4a_alloc, @@ -42,6 +43,7 @@ void iso14443_4a_copy(Iso14443_4aData* data, const Iso14443_4aData* other) { furi_assert(other); nfca_copy(data->iso14443_3a_data, other->iso14443_3a_data); + data->ats_data = other->ats_data; } bool iso14443_4a_verify(Iso14443_4aData* data, const FuriString* device_type) { @@ -83,3 +85,8 @@ const char* iso14443_4a_get_name(const Iso14443_4aData* data, NfcProtocolNameTyp const uint8_t* iso14443_4a_get_uid(const Iso14443_4aData* data, size_t* uid_len) { return nfca_get_uid(data->iso14443_3a_data, uid_len); } + +bool iso14443_4a_is_ats_supported(const Iso14443_4aData* data) { + const NfcaData* iso14443_3a_data = data->iso14443_3a_data; + return iso14443_3a_data->sak & ISO14443_4A_ATS_BIT; +} diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a.h b/lib/nfc/protocols/iso14443_4a/iso14443_4a.h index e7c05d946bfe..91ee64490438 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a.h +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a.h @@ -6,6 +6,8 @@ extern "C" { #endif +#define ISO14443_4A_CMD_READ_ATS (0xE0) + typedef enum { Iso14443_4aErrorNone, Iso14443_4aErrorNotPresent, @@ -13,11 +15,6 @@ typedef enum { Iso14443_4aErrorTimeout, } Iso14443_4aError; -typedef struct { - uint8_t cmd; - uint8_t param; -} Iso14443_4aAtsRequest; - typedef struct { uint8_t tl; uint8_t t0; @@ -25,14 +22,17 @@ typedef struct { uint8_t tb_1; uint8_t tc_1; uint8_t t1; -} Iso14443_4aAtsResponse; +} Iso14443_4aAtsData; typedef struct { NfcaData* iso14443_3a_data; + Iso14443_4aAtsData ats_data; } Iso14443_4aData; extern const NfcProtocolBase nfc_protocol_iso14443_4a; +// Virtual methods + Iso14443_4aData* iso14443_4a_alloc(); void iso14443_4a_free(Iso14443_4aData* data); @@ -53,6 +53,10 @@ const char* iso14443_4a_get_name(const Iso14443_4aData* data, NfcProtocolNameTyp const uint8_t* iso14443_4a_get_uid(const Iso14443_4aData* data, size_t* uid_len); +// Getters & Tests + +bool iso14443_4a_is_ats_supported(const Iso14443_4aData* data); + #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_i.c b/lib/nfc/protocols/iso14443_4a/iso14443_4a_i.c new file mode 100644 index 000000000000..cb434cf18f7b --- /dev/null +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_i.c @@ -0,0 +1,9 @@ +#include "iso14443_4a_i.h" + +bool iso14443_4a_ats_parse(Iso14443_4aAtsData* data, const BitBuffer* buf) { + const bool can_parse = bit_buffer_get_size_bytes(buf) >= sizeof(Iso14443_4aAtsData); + if(can_parse) { + bit_buffer_write_bytes(buf, data, sizeof(Iso14443_4aAtsData)); + } + return can_parse; +} diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_i.h b/lib/nfc/protocols/iso14443_4a/iso14443_4a_i.h new file mode 100644 index 000000000000..184b1bbb2809 --- /dev/null +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_i.h @@ -0,0 +1,5 @@ +#pragma once + +#include "iso14443_4a.h" + +bool iso14443_4a_ats_parse(Iso14443_4aAtsData* data, const BitBuffer* buf); diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.c b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.c index b73d25c418e5..65590b01cf39 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.c +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.c @@ -6,177 +6,141 @@ #define ISO14443_4A_BUF_SIZE_MAX (512U) -typedef Iso14443_4aPollerCommand (*Iso14443_4aPollerStateHandler)(Iso14443_4aPoller* instance); +typedef NfcCommand (*Iso14443_4aPollerStateHandler)(Iso14443_4aPoller* instance); -static Iso14443_4aPollerCommand iso14443_4a_poller_handler_idle(Iso14443_4aPoller* instance); -static Iso14443_4aPollerCommand iso14443_4a_poller_handler_read_ats(Iso14443_4aPoller* instance); -static Iso14443_4aPollerCommand iso14443_4a_poller_handler_error(Iso14443_4aPoller* instance); -static Iso14443_4aPollerCommand iso14443_4a_poller_handler_ready(Iso14443_4aPoller* instance); +const Iso14443_4aData* iso14443_4a_poller_get_data(Iso14443_4aPoller* instance) { + furi_assert(instance); -static const Iso14443_4aPollerStateHandler - iso14443_4a_poller_state_handler[Iso14443_4aPollerStateNum] = { - [Iso14443_4aPollerStateIdle] = iso14443_4a_poller_handler_idle, - [Iso14443_4aPollerStateReadAts] = iso14443_4a_poller_handler_read_ats, - [Iso14443_4aPollerStateError] = iso14443_4a_poller_handler_error, - [Iso14443_4aPollerStateReady] = iso14443_4a_poller_handler_ready, -}; + return instance->data; +} -Iso14443_4aPoller* iso14443_4a_poller_alloc(NfcaPoller* iso14443_3a_poller) { +static Iso14443_4aPoller* iso14443_4a_poller_alloc(NfcaPoller* iso14443_3a_poller) { Iso14443_4aPoller* instance = malloc(sizeof(Iso14443_4aPoller)); instance->iso14443_3a_poller = iso14443_3a_poller; - return instance; -} + instance->data = iso14443_4a_alloc(); + instance->tx_buffer = bit_buffer_alloc(ISO14443_4A_BUF_SIZE_MAX); + instance->rx_buffer = bit_buffer_alloc(ISO14443_4A_BUF_SIZE_MAX); -void iso14443_4a_poller_free(Iso14443_4aPoller* instance) { - furi_assert(instance); - furi_assert(instance->state == Iso14443_4aPollerStateIdle); + instance->iso14443_4a_event.data = &instance->iso14443_4a_event_data; - free(instance); + instance->general_event.protocol_type = NfcProtocolTypeIso14443_4a; + instance->general_event.data = &instance->iso14443_4a_event; + instance->general_event.poller = instance; + + return instance; } -const Iso14443_4aData* iso14443_4a_poller_get_data(Iso14443_4aPoller* instance) { +static void iso14443_4a_poller_free(Iso14443_4aPoller* instance) { furi_assert(instance); + furi_assert(instance->poller_state == Iso14443_4aPollerStateIdle); - return instance->data; + iso14443_4a_free(instance->data); + bit_buffer_free(instance->tx_buffer); + bit_buffer_free(instance->rx_buffer); + free(instance); } -Iso14443_4aPollerCommand iso14443_4a_poller_handler_idle(Iso14443_4aPoller* instance) { - bit_buffer_reset(instance->tx_buffer); - bit_buffer_reset(instance->rx_buffer); +static NfcCommand iso14443_4a_poller_handler_idle(Iso14443_4aPoller* instance) { nfca_copy( instance->data->iso14443_3a_data, nfca_poller_get_data(instance->iso14443_3a_poller)); - instance->state = Iso14443_4aPollerStateReadAts; - return Iso14443_4aPollerCommandContinue; + instance->poller_state = Iso14443_4aPollerStateReadAts; + instance->protocol_state.block_number = 0; + return NfcCommandContinue; } -Iso14443_4aPollerCommand iso14443_4a_poller_handler_read_ats(Iso14443_4aPoller* instance) { - Iso14443_4aError error = iso14443_4a_poller_async_read_ats(instance); +static NfcCommand iso14443_4a_poller_handler_read_ats(Iso14443_4aPoller* instance) { + Iso14443_4aError error = + iso14443_4a_poller_async_read_ats(instance, &instance->data->ats_data); if(error == Iso14443_4aErrorNone) { FURI_LOG_D(TAG, "Read ATS success"); - instance->state = Iso14443_4aPollerStateReady; + instance->poller_state = Iso14443_4aPollerStateReady; } else { FURI_LOG_D(TAG, "Failed to read ATS"); - instance->state = Iso14443_4aPollerStateError; + instance->poller_state = Iso14443_4aPollerStateError; } - return Iso14443_4aPollerCommandContinue; + return NfcCommandContinue; } -Iso14443_4aPollerCommand iso14443_4a_poller_handler_error(Iso14443_4aPoller* instance) { +static NfcCommand iso14443_4a_poller_handler_error(Iso14443_4aPoller* instance) { nfca_poller_halt(instance->iso14443_3a_poller); - Iso14443_4aPollerEventData event_data = {.error = instance->error}; - Iso14443_4aPollerEvent event = {.type = Iso14443_4aPollerEventTypeError, .data = &event_data}; - Iso14443_4aPollerCommand command = instance->callback(event, instance->context); - instance->state = Iso14443_4aPollerStateIdle; + instance->iso14443_4a_event_data.error = instance->error; + NfcCommand command = instance->callback(instance->general_event, instance->context); + instance->poller_state = Iso14443_4aPollerStateIdle; return command; } -Iso14443_4aPollerCommand iso14443_4a_poller_handler_ready(Iso14443_4aPoller* instance) { - Iso14443_4aPollerEvent event = {.type = Iso14443_4aPollerEventTypeReady}; - Iso14443_4aPollerCommand command = instance->callback(event, instance->context); +static NfcCommand iso14443_4a_poller_handler_ready(Iso14443_4aPoller* instance) { + instance->iso14443_4a_event.type = Iso14443_4aPollerEventTypeReady; + NfcCommand command = instance->callback(instance->general_event, instance->context); return command; } -static NfcaPollerCommand iso14443_4a_poller_process_command(Iso14443_4aPollerCommand command) { - NfcaPollerCommand ret = NfcaPollerCommandContinue; - - if(command == Iso14443_4aPollerCommandContinue) { - ret = NfcaPollerCommandContinue; - } else if(command == Iso14443_4aPollerCommandReset) { - ret = NfcaPollerCommandReset; - } else if(command == Iso14443_4aPollerCommandStop) { - ret = NfcaPollerCommandStop; - } else { - furi_crash("Unknown command"); - } - - return ret; -} - -static NfcaPollerCommand iso14443_4a_poller_callback(NfcaPollerEvent event, void* context) { - furi_assert(context); - - Iso14443_4aPoller* instance = context; - Iso14443_4aPollerEventData event_data = {}; - Iso14443_4aPollerEvent iso14443_4a_event = {.data = &event_data}; - Iso14443_4aPollerCommand command = Iso14443_4aPollerCommandContinue; - - furi_assert(instance->session_state != Iso14443_4aPollerSessionStateIdle); - if(instance->session_state == Iso14443_4aPollerSessionStateStopRequest) { - command = Iso14443_4aPollerCommandStop; - } else { - if(event.type == NfcaPollerEventTypeReady) { - command = iso14443_4a_poller_state_handler[instance->state](instance); - } else if(event.type == NfcaPollerEventTypeError) { - iso14443_4a_event.type = Iso14443_4aPollerEventTypeError; - command = instance->callback(iso14443_4a_event, instance->context); - } - } - - return iso14443_4a_poller_process_command(command); -} +static const Iso14443_4aPollerStateHandler + iso14443_4a_poller_state_handler[Iso14443_4aPollerStateNum] = { + [Iso14443_4aPollerStateIdle] = iso14443_4a_poller_handler_idle, + [Iso14443_4aPollerStateReadAts] = iso14443_4a_poller_handler_read_ats, + [Iso14443_4aPollerStateError] = iso14443_4a_poller_handler_error, + [Iso14443_4aPollerStateReady] = iso14443_4a_poller_handler_ready, +}; -Iso14443_4aError iso14443_4a_poller_start( +static void iso14443_4a_poller_set_callback( Iso14443_4aPoller* instance, - NfcaPollerEventCallback callback, + NfcPollerCallback callback, void* context) { furi_assert(instance); - furi_assert(instance->iso14443_3a_poller); - furi_assert(instance->state == Iso14443_4aPollerStateIdle); - furi_assert(instance->session_state == Iso14443_4aPollerSessionStateIdle); furi_assert(callback); - furi_assert(context); - instance->data = iso14443_4a_alloc(); - instance->tx_buffer = bit_buffer_alloc(ISO14443_4A_BUF_SIZE_MAX); - instance->rx_buffer = bit_buffer_alloc(ISO14443_4A_BUF_SIZE_MAX); + instance->callback = callback; + instance->context = context; +} - instance->session_state = Iso14443_4aPollerSessionStateActive; - instance->protocol_data.block_number = 0; +static NfcCommand iso14443_4a_poller_run(NfcPollerEvent event, void* context) { + furi_assert(event.protocol_type == NfcProtocolTypeIso14443_3a); - nfca_poller_start(instance->iso14443_3a_poller, callback, context); + Iso14443_4aPoller* instance = context; + furi_assert(instance); + furi_assert(instance->callback); - return Iso14443_4aErrorNone; -} + NfcaPollerEvent* iso14443_3a_event = event.data; + furi_assert(iso14443_3a_event); -Iso14443_4aError iso14443_4a_poller_read( - Iso14443_4aPoller* instance, - Iso14443_4aPollerCallback callback, - void* context) { - furi_assert(instance); - furi_assert(instance->iso14443_3a_poller); - furi_assert(instance->state == Iso14443_4aPollerStateIdle); - furi_assert(callback); + NfcCommand command = NfcCommandContinue; - instance->callback = callback; - instance->context = context; + if(iso14443_3a_event->type == NfcaPollerEventTypeReady) { + command = iso14443_4a_poller_state_handler[instance->poller_state](instance); + } else if(iso14443_3a_event->type == NfcaPollerEventTypeError) { + instance->iso14443_4a_event.type = Iso14443_4aPollerEventTypeError; + command = instance->callback(instance->general_event, instance->context); + } - return iso14443_4a_poller_start(instance, iso14443_4a_poller_callback, instance); + return command; } -Iso14443_4aError iso14443_4a_poller_reset(Iso14443_4aPoller* instance) { - furi_assert(instance); - furi_assert(instance->data); - furi_assert(instance->iso14443_3a_poller); +static bool iso14443_4a_poller_detect(NfcPollerEvent event, void* context) { + furi_assert(event.protocol_type == NfcProtocolTypeIso14443_3a); - bit_buffer_free(instance->tx_buffer); - bit_buffer_free(instance->rx_buffer); - instance->callback = NULL; - instance->context = NULL; - instance->state = Iso14443_4aPollerStateIdle; + const Iso14443_4aPoller* instance = context; + furi_assert(instance); - return Iso14443_4aErrorNone; -} + const NfcaPollerEvent* iso14443_3a_event = event.data; + furi_assert(iso14443_3a_event); -Iso14443_4aError iso14443_4a_poller_stop(Iso14443_4aPoller* instance) { - furi_assert(instance); - furi_assert(instance->iso14443_3a_poller); + bool protocol_detected = false; - instance->session_state = Iso14443_4aPollerSessionStateStopRequest; - nfca_poller_stop(instance->iso14443_3a_poller); - instance->session_state = Iso14443_4aPollerSessionStateIdle; - iso14443_4a_free(instance->data); + if(iso14443_3a_event->type == NfcaPollerEventTypeReady) { + protocol_detected = iso14443_4a_is_ats_supported(instance->data); + } - return iso14443_4a_poller_reset(instance); + return protocol_detected; } + +const NfcPollerBase nfc_poller_iso14443_4a = { + .alloc = (NfcPollerAlloc)iso14443_4a_poller_alloc, + .free = (NfcPollerFree)iso14443_4a_poller_free, + .set_callback = (NfcPollerSetCallback)iso14443_4a_poller_set_callback, + .run = (NfcPollerRun)iso14443_4a_poller_run, + .detect = (NfcPollerDetect)iso14443_4a_poller_detect, + .get_data = (NfcPollerGetData)iso14443_4a_poller_get_data, +}; diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.h b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.h index 77bac4c7dd27..8d9198a3a65d 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.h +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.h @@ -24,33 +24,8 @@ typedef struct { Iso14443_4aPollerEventData* data; } Iso14443_4aPollerEvent; -typedef enum { - Iso14443_4aPollerCommandContinue = NfcaPollerCommandContinue, - Iso14443_4aPollerCommandReset = NfcaPollerCommandReset, - Iso14443_4aPollerCommandStop = NfcaPollerCommandStop, -} Iso14443_4aPollerCommand; - -typedef Iso14443_4aPollerCommand ( - *Iso14443_4aPollerCallback)(Iso14443_4aPollerEvent event, void* context); - -Iso14443_4aPoller* iso14443_4a_poller_alloc(NfcaPoller* iso14443_3a_poller); - -void iso14443_4a_poller_free(Iso14443_4aPoller* instance); - const Iso14443_4aData* iso14443_4a_poller_get_data(Iso14443_4aPoller* instance); -Iso14443_4aError iso14443_4a_poller_start( - Iso14443_4aPoller* instance, - NfcaPollerEventCallback callback, - void* context); - -Iso14443_4aError iso14443_4a_poller_read( - Iso14443_4aPoller* instance, - Iso14443_4aPollerCallback callback, - void* context); - -Iso14443_4aError iso14443_4a_poller_stop(Iso14443_4aPoller* instance); - #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_defs.h b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_defs.h new file mode 100644 index 000000000000..645216a73f64 --- /dev/null +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_defs.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +extern const NfcPollerBase nfc_poller_iso14443_4a; diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c index 30e0b6ed6e46..f948c0ea639a 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c @@ -2,11 +2,10 @@ #include -#define TAG "Iso14443_4aPoller" +#include "iso14443_4a_i.h" -#define BITS_IN_BYTE (8) +#define TAG "Iso14443_4aPoller" -#define ISO14443_4A_ATS_BIT (1 << 5) #define ISO14443_4A_PCB_I (0x02) Iso14443_4aError iso14443_4a_poller_process_error(NfcaError error) { @@ -30,53 +29,42 @@ Iso14443_4aError iso14443_4a_poller_halt(Iso14443_4aPoller* instance) { furi_assert(instance); nfca_poller_halt(instance->iso14443_3a_poller); - instance->state = Iso14443_4aPollerStateIdle; + instance->poller_state = Iso14443_4aPollerStateIdle; return Iso14443_4aErrorNone; } -Iso14443_4aError iso14443_4a_poller_async_read_ats(Iso14443_4aPoller* instance) { +Iso14443_4aError + iso14443_4a_poller_async_read_ats(Iso14443_4aPoller* instance, Iso14443_4aAtsData* data) { furi_assert(instance); - Iso14443_4aError ret = Iso14443_4aErrorProtocol; - - do { - // Check whether ATS is available - NfcaData* iso14443_3a_data = instance->data->iso14443_3a_data; - if(!(iso14443_3a_data->sak & ISO14443_4A_ATS_BIT)) { - FURI_LOG_E(TAG, "Ats not supported: not an ISO14443-4 card"); - break; - } + bit_buffer_reset(instance->tx_buffer); + bit_buffer_append_byte(instance->tx_buffer, ISO14443_4A_CMD_READ_ATS); + bit_buffer_append_byte(instance->tx_buffer, 0x80); - // Send RATS & receive ATS - instance->protocol_data.ats_request.cmd = 0xe0; - instance->protocol_data.ats_request.param = 0x80; + Iso14443_4aError error = Iso14443_4aErrorNone; - bit_buffer_copy_bytes( - instance->tx_buffer, - (uint8_t*)&instance->protocol_data.ats_request, - sizeof(instance->protocol_data.ats_request)); - - NfcaError error = nfca_poller_send_standart_frame( + do { + const NfcaError iso14443_3a_error = nfca_poller_send_standart_frame( instance->iso14443_3a_poller, instance->tx_buffer, instance->rx_buffer, ISO14443_4A_POLLER_ATS_FWT_FC); - if(error != NfcaErrorNone) { - FURI_LOG_E(TAG, "Ats request failed: %d", error); + + if(iso14443_3a_error != NfcaErrorNone) { + FURI_LOG_E(TAG, "ATS request failed"); + error = iso14443_4a_poller_process_error(iso14443_3a_error); break; - } - if(bit_buffer_get_size_bytes(instance->rx_buffer) != - sizeof(instance->protocol_data.ats_response)) { - FURI_LOG_E(TAG, "Ats response wrong length"); - ret = Iso14443_4aErrorProtocol; + + } else if(!iso14443_4a_ats_parse(data, instance->rx_buffer)) { + FURI_LOG_E(TAG, "Failed to parse ATS response"); + error = Iso14443_4aErrorProtocol; break; } - ret = Iso14443_4aErrorNone; } while(false); - return ret; + return error; } Iso14443_4aError iso14443_4a_poller_send_block( @@ -85,56 +73,31 @@ Iso14443_4aError iso14443_4a_poller_send_block( BitBuffer* rx_buffer, uint32_t fwt) { furi_assert(instance); - furi_assert(tx_buffer); - furi_assert(rx_buffer); - const uint8_t pcb = ISO14443_4A_PCB_I | instance->protocol_data.block_number; - instance->protocol_data.block_number ^= 1; + const uint8_t pcb = ISO14443_4A_PCB_I | instance->protocol_state.block_number; + instance->protocol_state.block_number ^= 1; - bit_buffer_copy_bytes(instance->tx_buffer, &pcb, sizeof(pcb)); + bit_buffer_reset(instance->tx_buffer); + bit_buffer_append_byte(instance->tx_buffer, pcb); bit_buffer_append(instance->tx_buffer, tx_buffer); - Iso14443_4aError ret = Iso14443_4aErrorNone; + Iso14443_4aError error = Iso14443_4aErrorNone; do { - NfcaError error = nfca_poller_send_standart_frame( + NfcaError iso14443_3a_error = nfca_poller_send_standart_frame( instance->iso14443_3a_poller, instance->tx_buffer, instance->rx_buffer, fwt); - if(error != NfcaErrorNone) { - FURI_LOG_E(TAG, "Iso14443-3 error: %d", error); - ret = iso14443_4a_poller_process_error(error); + if(iso14443_3a_error != NfcaErrorNone) { + error = iso14443_4a_poller_process_error(iso14443_3a_error); break; - } - if(!bit_buffer_starts_with_byte(instance->rx_buffer, pcb)) { - ret = Iso14443_4aErrorProtocol; + } else if(!bit_buffer_starts_with_byte(instance->rx_buffer, pcb)) { + error = Iso14443_4aErrorProtocol; break; } bit_buffer_copy_right(rx_buffer, instance->rx_buffer, sizeof(pcb)); - ret = Iso14443_4aErrorNone; } while(false); - return ret; -} - -NfcPoller* iso14443_4a_poller_alloc_new(NfcPoller* iso14443_3a_poller) { - furi_assert(iso14443_3a_poller); - - Iso14443_4aPoller* instance = malloc(sizeof(Iso14443_4aPoller)); - instance->iso14443_3a_poller = iso14443_3a_poller; - - return instance; + return error; } - -void iso14443_4a_poller_free_new(NfcPoller* iso14443_4a_poller) { - furi_assert(iso14443_4a_poller); - - Iso14443_4aPoller* instance = iso14443_4a_poller; - free(instance); -} - -const NfcPollerBase nfc_poller_iso14443_4a = { - .alloc = iso14443_4a_poller_alloc_new, - .free = iso14443_4a_poller_free_new, -}; diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.h b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.h index 811da4045f90..d16e5cfde4df 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.h +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.h @@ -26,21 +26,22 @@ typedef enum { } Iso14443_4aPollerSessionState; typedef struct { - Iso14443_4aAtsRequest ats_request; - Iso14443_4aAtsResponse ats_response; uint32_t block_number; -} Iso14443_4aPollerProtocolData; +} Iso14443_4aPollerProtocolState; struct Iso14443_4aPoller { NfcaPoller* iso14443_3a_poller; - Iso14443_4aPollerState state; + Iso14443_4aPollerState poller_state; Iso14443_4aPollerSessionState session_state; + Iso14443_4aPollerProtocolState protocol_state; + Iso14443_4aError error; + Iso14443_4aData* data; BitBuffer* tx_buffer; BitBuffer* rx_buffer; - Iso14443_4aData* data; - Iso14443_4aPollerProtocolData protocol_data; - Iso14443_4aPollerCallback callback; - Iso14443_4aError error; + Iso14443_4aPollerEventData iso14443_4a_event_data; + Iso14443_4aPollerEvent iso14443_4a_event; + NfcPollerEvent general_event; + NfcPollerCallback callback; void* context; }; @@ -48,7 +49,8 @@ Iso14443_4aError iso14443_4a_poller_process_error(NfcaError error); Iso14443_4aError iso14443_4a_poller_halt(Iso14443_4aPoller* instance); -Iso14443_4aError iso14443_4a_poller_async_read_ats(Iso14443_4aPoller* instance); +Iso14443_4aError + iso14443_4a_poller_async_read_ats(Iso14443_4aPoller* instance, Iso14443_4aAtsData* data); Iso14443_4aError iso14443_4a_poller_send_block( Iso14443_4aPoller* instance, @@ -56,8 +58,6 @@ Iso14443_4aError iso14443_4a_poller_send_block( BitBuffer* rx_buffer, uint32_t fwt); -extern const NfcPollerBase nfc_poller_iso14443_4a; - #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire.c b/lib/nfc/protocols/mf_desfire/mf_desfire.c index ced20a662916..92cd638b3910 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire.c +++ b/lib/nfc/protocols/mf_desfire/mf_desfire.c @@ -110,10 +110,3 @@ const uint8_t* mf_desfire_get_uid(const MfDesfireData* data, size_t* uid_len) { return iso14443_4a_get_uid(data->iso14443_4a_data, uid_len); } - -bool mf_desfire_detect_protocol(NfcaData* nfca_data) { - furi_assert(nfca_data); - - bool mfu_detected = false; - return mfu_detected; -} diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire.h b/lib/nfc/protocols/mf_desfire/mf_desfire.h index ca357b883b6b..273b953b8e5a 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire.h +++ b/lib/nfc/protocols/mf_desfire/mf_desfire.h @@ -169,9 +169,6 @@ const char* mf_desfire_get_name(const MfDesfireData* data, NfcProtocolNameType n const uint8_t* mf_desfire_get_uid(const MfDesfireData* data, size_t* uid_len); -// Deprecated ? -bool mf_desfire_detect_protocol(NfcaData* nfca_data); - #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c b/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c index a901f4a736b9..e55394bb98ef 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c @@ -6,43 +6,44 @@ #define MF_DESFIRE_BUF_SIZE_MAX (64U) -typedef MfDesfirePollerCommand (*MfDesfirePollerReadHandler)(MfDesfirePoller* instance); +typedef NfcCommand (*MfDesfirePollerReadHandler)(MfDesfirePoller* instance); -static Iso14443_4aPollerCommand mf_desfire_process_command(MfDesfirePollerCommand command) { - Iso14443_4aPollerCommand ret = Iso14443_4aPollerCommandContinue; - - if(command == MfDesfirePollerCommandContinue) { - ret = Iso14443_4aPollerCommandContinue; - } else if(command == MfDesfirePollerCommandReset) { - ret = Iso14443_4aPollerCommandReset; - } else if(command == MfDesfirePollerCommandStop) { - ret = Iso14443_4aPollerCommandStop; - } else { - furi_crash("Unknown command"); - } +const MfDesfireData* mf_desfire_poller_get_data(MfDesfirePoller* instance) { + furi_assert(instance); - return ret; + return instance->data; } -MfDesfirePoller* mf_desfire_poller_alloc(Iso14443_4aPoller* iso14443_4a_poller) { +static MfDesfirePoller* mf_desfire_poller_alloc(Iso14443_4aPoller* iso14443_4a_poller) { MfDesfirePoller* instance = malloc(sizeof(MfDesfirePoller)); instance->iso14443_4a_poller = iso14443_4a_poller; + instance->data = mf_desfire_alloc(); + instance->tx_buffer = bit_buffer_alloc(MF_DESFIRE_BUF_SIZE_MAX); + instance->rx_buffer = bit_buffer_alloc(MF_DESFIRE_BUF_SIZE_MAX); + instance->input_buffer = bit_buffer_alloc(MF_DESFIRE_BUF_SIZE_MAX); + instance->result_buffer = bit_buffer_alloc(MF_DESFIRE_BUF_SIZE_MAX); + + instance->mf_desfire_event.data = &instance->mf_desfire_event_data; + + instance->general_event.protocol_type = NfcProtocolTypeMfDesfire; + instance->general_event.data = &instance->mf_desfire_event; + instance->general_event.poller = instance; return instance; } -void mf_desfire_poller_free(MfDesfirePoller* instance) { +static void mf_desfire_poller_free(MfDesfirePoller* instance) { furi_assert(instance); - free(instance); -} -const MfDesfireData* mf_desfire_poller_get_data(MfDesfirePoller* instance) { - furi_assert(instance); - - return instance->data; + mf_desfire_free(instance->data); + bit_buffer_free(instance->tx_buffer); + bit_buffer_free(instance->rx_buffer); + bit_buffer_free(instance->input_buffer); + bit_buffer_free(instance->result_buffer); + free(instance); } -static MfDesfirePollerCommand mf_desfire_poller_handler_idle(MfDesfirePoller* instance) { +static NfcCommand mf_desfire_poller_handler_idle(MfDesfirePoller* instance) { bit_buffer_reset(instance->input_buffer); bit_buffer_reset(instance->result_buffer); bit_buffer_reset(instance->tx_buffer); @@ -53,10 +54,10 @@ static MfDesfirePollerCommand mf_desfire_poller_handler_idle(MfDesfirePoller* in iso14443_4a_poller_get_data(instance->iso14443_4a_poller)); instance->state = MfDesfirePollerStateReadVersion; - return MfDesfirePollerCommandContinue; + return NfcCommandContinue; } -static MfDesfirePollerCommand mf_desfire_poller_handler_read_version(MfDesfirePoller* instance) { +static NfcCommand mf_desfire_poller_handler_read_version(MfDesfirePoller* instance) { instance->error = mf_desfire_poller_async_read_version(instance, &instance->data->version); if(instance->error == MfDesfireErrorNone) { FURI_LOG_D(TAG, "Read version success"); @@ -67,11 +68,10 @@ static MfDesfirePollerCommand mf_desfire_poller_handler_read_version(MfDesfirePo instance->state = MfDesfirePollerStateReadFailed; } - return MfDesfirePollerCommandContinue; + return NfcCommandContinue; } -static MfDesfirePollerCommand - mf_desfire_poller_handler_read_free_memory(MfDesfirePoller* instance) { +static NfcCommand mf_desfire_poller_handler_read_free_memory(MfDesfirePoller* instance) { instance->error = mf_desfire_poller_async_read_free_memory(instance, &instance->data->free_memory); if(instance->error == MfDesfireErrorNone) { @@ -83,11 +83,10 @@ static MfDesfirePollerCommand instance->state = MfDesfirePollerStateReadFailed; } - return MfDesfirePollerCommandContinue; + return NfcCommandContinue; } -static MfDesfirePollerCommand - mf_desfire_poller_handler_read_master_key_settings(MfDesfirePoller* instance) { +static NfcCommand mf_desfire_poller_handler_read_master_key_settings(MfDesfirePoller* instance) { instance->error = mf_desfire_poller_async_read_key_settings(instance, &instance->data->master_key_settings); if(instance->error == MfDesfireErrorNone) { @@ -99,11 +98,10 @@ static MfDesfirePollerCommand instance->state = MfDesfirePollerStateReadFailed; } - return MfDesfirePollerCommandContinue; + return NfcCommandContinue; } -static MfDesfirePollerCommand - mf_desfire_poller_handler_read_master_key_version(MfDesfirePoller* instance) { +static NfcCommand mf_desfire_poller_handler_read_master_key_version(MfDesfirePoller* instance) { instance->error = mf_desfire_poller_async_read_key_versions( instance, instance->data->master_key_versions, @@ -117,11 +115,10 @@ static MfDesfirePollerCommand instance->state = MfDesfirePollerStateReadFailed; } - return MfDesfirePollerCommandContinue; + return NfcCommandContinue; } -static MfDesfirePollerCommand - mf_desfire_poller_handler_read_application_ids(MfDesfirePoller* instance) { +static NfcCommand mf_desfire_poller_handler_read_application_ids(MfDesfirePoller* instance) { instance->error = mf_desfire_poller_async_read_application_ids(instance, instance->data->application_ids); if(instance->error == MfDesfireErrorNone) { @@ -133,11 +130,10 @@ static MfDesfirePollerCommand instance->state = MfDesfirePollerStateReadFailed; } - return MfDesfirePollerCommandContinue; + return NfcCommandContinue; } -static MfDesfirePollerCommand - mf_desfire_poller_handler_read_applications(MfDesfirePoller* instance) { +static NfcCommand mf_desfire_poller_handler_read_applications(MfDesfirePoller* instance) { instance->error = mf_desfire_poller_async_read_applications( instance, instance->data->application_ids, instance->data->applications); if(instance->error == MfDesfireErrorNone) { @@ -149,24 +145,23 @@ static MfDesfirePollerCommand instance->state = MfDesfirePollerStateReadFailed; } - return MfDesfirePollerCommandContinue; + return NfcCommandContinue; } -static MfDesfirePollerCommand mf_desfire_poller_handler_read_fail(MfDesfirePoller* instance) { +static NfcCommand mf_desfire_poller_handler_read_fail(MfDesfirePoller* instance) { FURI_LOG_D(TAG, "Read Failed"); iso14443_4a_poller_halt(instance->iso14443_4a_poller); - MfDesfirePollerEventData event_data = {.error = instance->error}; - MfDesfirePollerEvent event = {.type = MfDesfirePollerEventTypeReadFailed, .data = &event_data}; - MfDesfirePollerCommand command = instance->callback(event, instance->context); + instance->mf_desfire_event.data->error = instance->error; + NfcCommand command = instance->callback(instance->general_event, instance->context); instance->state = MfDesfirePollerStateIdle; return command; } -static MfDesfirePollerCommand mf_desfire_poller_handler_read_success(MfDesfirePoller* instance) { +static NfcCommand mf_desfire_poller_handler_read_success(MfDesfirePoller* instance) { FURI_LOG_D(TAG, "Read success."); iso14443_4a_poller_halt(instance->iso14443_4a_poller); - MfDesfirePollerEvent event = {.type = MfDesfirePollerEventTypeReadSuccess}; - MfDesfirePollerCommand command = instance->callback(event, instance->context); + instance->mf_desfire_event.type = MfDesfirePollerEventTypeReadSuccess; + NfcCommand command = instance->callback(instance->general_event, instance->context); return command; } @@ -183,98 +178,64 @@ static const MfDesfirePollerReadHandler mf_desfire_poller_read_handler[MfDesfire [MfDesfirePollerStateReadSuccess] = mf_desfire_poller_handler_read_success, }; -static Iso14443_4aPollerCommand - mf_desfire_poller_read_callback(Iso14443_4aPollerEvent event, void* context) { - furi_assert(context); - - MfDesfirePoller* instance = context; - MfDesfirePollerEventData event_data = {}; - MfDesfirePollerEvent poller_event = {.data = &event_data}; - MfDesfirePollerCommand command = MfDesfirePollerCommandContinue; - - furi_assert(instance->session_state != MfDesfirePollerSessionStateIdle); - if(instance->session_state == MfDesfirePollerSessionStateStopRequest) { - command = MfDesfirePollerCommandStop; - } else { - if(event.type == Iso14443_4aPollerEventTypeReady) { - command = mf_desfire_poller_read_handler[instance->state](instance); - } else if(event.type == Iso14443_4aPollerEventTypeError) { - if(instance->callback) { - poller_event.type = MfDesfirePollerEventTypeReadFailed; - command = instance->callback(poller_event, instance->context); - } - } - } - - return mf_desfire_process_command(command); -} - -MfDesfireError mf_desfire_poller_start( +static void mf_desfire_poller_set_callback( MfDesfirePoller* instance, - Iso14443_4aPollerCallback callback, + NfcPollerCallback callback, void* context) { furi_assert(instance); - furi_assert(instance->state == MfDesfirePollerStateIdle); - furi_assert(instance->iso14443_4a_poller); - furi_assert(callback); - furi_assert(instance->session_state == MfDesfirePollerSessionStateIdle); - - instance->data = mf_desfire_alloc(); - instance->input_buffer = bit_buffer_alloc(MF_DESFIRE_BUF_SIZE_MAX); - instance->result_buffer = bit_buffer_alloc(MF_DESFIRE_BUF_SIZE_MAX); - instance->tx_buffer = bit_buffer_alloc(MF_DESFIRE_BUF_SIZE_MAX); - instance->rx_buffer = bit_buffer_alloc(MF_DESFIRE_BUF_SIZE_MAX); - - instance->session_state = MfDesfirePollerSessionStateActive; - iso14443_4a_poller_read(instance->iso14443_4a_poller, callback, context); - - return MfDesfireErrorNone; -} - -MfDesfireError mf_desfire_poller_read( - MfDesfirePoller* instance, - MfDesfirePollerCallback callback, - void* context) { - furi_assert(instance); - furi_assert(instance->state == MfDesfirePollerStateIdle); - furi_assert(instance->iso14443_4a_poller); furi_assert(callback); instance->callback = callback; instance->context = context; - - return mf_desfire_poller_start(instance, mf_desfire_poller_read_callback, instance); } -MfDesfireError mf_desfire_poller_reset(MfDesfirePoller* instance) { +static NfcCommand mf_desfire_poller_run(NfcPollerEvent event, void* context) { + furi_assert(event.protocol_type == NfcProtocolTypeIso14443_4a); + + MfDesfirePoller* instance = context; furi_assert(instance); - furi_assert(instance->data); + furi_assert(instance->callback); - bit_buffer_free(instance->input_buffer); - bit_buffer_free(instance->result_buffer); - bit_buffer_free(instance->tx_buffer); - bit_buffer_free(instance->rx_buffer); + const Iso14443_4aPollerEvent* iso14443_4a_event = event.data; + furi_assert(iso14443_4a_event); - instance->input_buffer = NULL; - instance->result_buffer = NULL; - instance->tx_buffer = NULL; - instance->rx_buffer = NULL; + NfcCommand command = NfcCommandContinue; - instance->callback = NULL; - instance->context = NULL; - instance->state = MfDesfirePollerStateIdle; + if(iso14443_4a_event->type == Iso14443_4aPollerEventTypeReady) { + command = mf_desfire_poller_read_handler[instance->state](instance); + } else if(iso14443_4a_event->type == Iso14443_4aPollerEventTypeError) { + instance->mf_desfire_event.type = MfDesfirePollerEventTypeReadFailed; + command = instance->callback(instance->general_event, instance->context); + } - return MfDesfireErrorNone; + return command; } -MfDesfireError mf_desfire_poller_stop(MfDesfirePoller* instance) { +static bool mf_desfire_poller_detect(NfcPollerEvent event, void* context) { + furi_assert(event.protocol_type == NfcProtocolTypeIso14443_4a); + + MfDesfirePoller* instance = context; furi_assert(instance); - furi_assert(instance->iso14443_4a_poller); - instance->session_state = MfDesfirePollerSessionStateStopRequest; - iso14443_4a_poller_stop(instance->iso14443_4a_poller); - instance->session_state = MfDesfirePollerSessionStateIdle; - mf_desfire_free(instance->data); + const Iso14443_4aPollerEvent* iso14443_4a_event = event.data; + furi_assert(iso14443_4a_event); + + bool protocol_detected = false; - return mf_desfire_poller_reset(instance); + if(iso14443_4a_event->type == Iso14443_4aPollerEventTypeReady) { + MfDesfireVersion version = {}; + const MfDesfireError error = mf_desfire_poller_async_read_version(instance, &version); + protocol_detected = (error == MfDesfireErrorNone); + } + + return protocol_detected; } + +const NfcPollerBase mf_desfire_poller = { + .alloc = (NfcPollerAlloc)mf_desfire_poller_alloc, + .free = (NfcPollerFree)mf_desfire_poller_free, + .set_callback = (NfcPollerSetCallback)mf_desfire_poller_set_callback, + .run = (NfcPollerRun)mf_desfire_poller_run, + .detect = (NfcPollerDetect)mf_desfire_poller_detect, + .get_data = (NfcPollerGetData)mf_desfire_poller_get_data, +}; diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_poller.h b/lib/nfc/protocols/mf_desfire/mf_desfire_poller.h index d2ade664f276..fb2638df5293 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_poller.h +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_poller.h @@ -26,33 +26,8 @@ typedef struct { MfDesfirePollerEventData* data; } MfDesfirePollerEvent; -typedef enum { - MfDesfirePollerCommandContinue = NfcaPollerCommandContinue, - MfDesfirePollerCommandReset = NfcaPollerCommandReset, - MfDesfirePollerCommandStop = NfcaPollerCommandStop, -} MfDesfirePollerCommand; - -typedef MfDesfirePollerCommand ( - *MfDesfirePollerCallback)(MfDesfirePollerEvent event, void* context); - -MfDesfirePoller* mf_desfire_poller_alloc(Iso14443_4aPoller* iso14443_4a_poller); - -void mf_desfire_poller_free(MfDesfirePoller* instance); - const MfDesfireData* mf_desfire_poller_get_data(MfDesfirePoller* instance); -MfDesfireError mf_desfire_poller_start( - MfDesfirePoller* instance, - Iso14443_4aPollerCallback callback, - void* context); - -MfDesfireError mf_desfire_poller_read( - MfDesfirePoller* instance, - MfDesfirePollerCallback callback, - void* context); - -MfDesfireError mf_desfire_poller_stop(MfDesfirePoller* instance); - #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_poller_defs.h b/lib/nfc/protocols/mf_desfire/mf_desfire_poller_defs.h new file mode 100644 index 000000000000..07a8ca05768f --- /dev/null +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_poller_defs.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +extern const NfcPollerBase mf_desfire_poller; diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c b/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c index 07886ad954d7..45453b72c928 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c @@ -31,14 +31,14 @@ MfDesfireError mf_desfire_send_chunks( furi_assert(tx_buffer); furi_assert(rx_buffer); - MfDesfireError ret = MfDesfireErrorNone; + MfDesfireError error = MfDesfireErrorNone; do { - Iso14443_4aError error = iso14443_4a_poller_send_block( + Iso14443_4aError iso14443_4a_error = iso14443_4a_poller_send_block( instance->iso14443_4a_poller, tx_buffer, instance->rx_buffer, fwt); - if(error != Iso14443_4aErrorNone) { - ret = mf_desfire_process_error(error); + if(iso14443_4a_error != Iso14443_4aErrorNone) { + error = mf_desfire_process_error(iso14443_4a_error); break; } @@ -52,11 +52,11 @@ MfDesfireError mf_desfire_send_chunks( } while(bit_buffer_starts_with_byte(instance->rx_buffer, MF_DESFIRE_FLAG_HAS_NEXT)) { - Iso14443_4aError error = iso14443_4a_poller_send_block( + Iso14443_4aError iso14443_4a_error = iso14443_4a_poller_send_block( instance->iso14443_4a_poller, instance->tx_buffer, instance->rx_buffer, fwt); - if(error != Iso14443_4aErrorNone) { - ret = mf_desfire_process_error(error); + if(iso14443_4a_error != Iso14443_4aErrorNone) { + error = mf_desfire_process_error(iso14443_4a_error); break; } @@ -64,7 +64,7 @@ MfDesfireError mf_desfire_send_chunks( } } while(false); - return ret; + return error; } MfDesfireError @@ -82,6 +82,8 @@ MfDesfireError if(error == MfDesfireErrorNone) { mf_desfire_version_parse(data, instance->result_buffer); + } else { + FURI_LOG_D(TAG, "Read version error: %d", error); } return error; diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.h b/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.h index 96c456cc5954..52bcc91f12d7 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.h +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.h @@ -8,7 +8,7 @@ extern "C" { #endif -#define MF_DESFIRE_POLLER_STANDARD_FWT_FC (190000) +#define MF_DESFIRE_POLLER_STANDARD_FWT_FC (200000) typedef enum { MfDesfirePollerStateIdle, @@ -34,13 +34,16 @@ struct MfDesfirePoller { Iso14443_4aPoller* iso14443_4a_poller; MfDesfirePollerSessionState session_state; MfDesfirePollerState state; + MfDesfireError error; + MfDesfireData* data; BitBuffer* tx_buffer; BitBuffer* rx_buffer; BitBuffer* input_buffer; BitBuffer* result_buffer; - MfDesfireData* data; - MfDesfirePollerCallback callback; - MfDesfireError error; + MfDesfirePollerEventData mf_desfire_event_data; + MfDesfirePollerEvent mf_desfire_event; + NfcPollerEvent general_event; + NfcPollerCallback callback; void* context; }; diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_defs.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_defs.h new file mode 100644 index 000000000000..d4d7e719f967 --- /dev/null +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_defs.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +extern const NfcPollerBase mf_ultralight_poller; diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h index e6c8f3ecb73b..96e23d2f5cb3 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h @@ -142,8 +142,6 @@ MfUltralightError mf_ultralight_poller_async_read_tearing_flag( uint8_t tearing_falg_num, MfUltralightTearingFlag* data); -extern const NfcPollerBase mf_ultralight_poller; - #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/nfca/nfca_poller_defs.h b/lib/nfc/protocols/nfca/nfca_poller_defs.h new file mode 100644 index 000000000000..df45f713e04d --- /dev/null +++ b/lib/nfc/protocols/nfca/nfca_poller_defs.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +extern const NfcPollerBase nfc_poller_iso14443_3a; diff --git a/lib/nfc/protocols/nfca/nfca_poller_i.h b/lib/nfc/protocols/nfca/nfca_poller_i.h index 04e65b5c0b60..706461ae75ac 100644 --- a/lib/nfc/protocols/nfca/nfca_poller_i.h +++ b/lib/nfc/protocols/nfca/nfca_poller_i.h @@ -96,8 +96,6 @@ NfcaError nfca_poller_send_standart_frame( BitBuffer* rx_buffer, uint32_t fwt); -extern const NfcPollerBase nfc_poller_iso14443_3a; - #ifdef __cplusplus } #endif From 1ffc06d2eb329e1996211c114a561eb305868214 Mon Sep 17 00:00:00 2001 From: gornekich Date: Thu, 22 Jun 2023 18:24:10 +0400 Subject: [PATCH 108/149] Nfc Scanner (#2792) * nfc: introduce poller scanner * nfc app: add detect scene * nfc scanner: implement children detect * nfc: fix detect function * nfc scanner: add filter for detected protocols * nfc: complete detect scene * nfc: remove old nfc_poller * nfc: remove mfu poller * nfc: fix memory leak * nfc: remove unused code * nfc: remove extra logs * nfc iso14443-4: change check * nfc: move poller defenition files to protocols * nfc: separate device and protocol names * nfc: rework protocol select scene * nfc: simplify get protocol name * nfc app: fix exit confirm scene --- .../nfc/helpers/format/nfc_protocol_format.c | 10 +- applications/main/nfc/nfc_app.c | 14 +- applications/main/nfc/nfc_app_i.h | 13 +- .../main/nfc/scenes/nfc_scene_config.h | 4 +- .../main/nfc/scenes/nfc_scene_delete.c | 3 +- .../main/nfc/scenes/nfc_scene_detect.c | 67 ++++ .../main/nfc/scenes/nfc_scene_exit_confirm.c | 9 +- .../main/nfc/scenes/nfc_scene_extra_actions.c | 2 +- .../nfc_scene_mf_classic_read_success.c | 2 +- .../nfc_scene_mf_desfire_read_success.c | 2 +- .../nfc/scenes/nfc_scene_mf_ultralight_read.c | 51 +-- .../nfc_scene_mf_ultralight_read_success.c | 2 +- .../main/nfc/scenes/nfc_scene_nfca_read.c | 21 +- applications/main/nfc/scenes/nfc_scene_read.c | 80 ----- .../nfc/scenes/nfc_scene_read_card_type.c | 91 ----- .../main/nfc/scenes/nfc_scene_retry_confirm.c | 4 +- .../nfc/scenes/nfc_scene_select_protocol.c | 73 ++++ .../main/nfc/scenes/nfc_scene_start.c | 2 +- firmware/targets/f7/api_symbols.csv | 7 +- lib/nfc/nfc.c | 2 +- lib/nfc/nfc_dev.c | 11 +- lib/nfc/nfc_dev.h | 4 +- lib/nfc/nfc_poller.c | 160 --------- lib/nfc/nfc_poller.h | 51 --- lib/nfc/nfc_poller_manager.c | 90 +---- lib/nfc/nfc_poller_manager.h | 4 +- lib/nfc/nfc_scanner.c | 325 ++++++++++++++++++ lib/nfc/nfc_scanner.h | 38 ++ lib/nfc/protocols/iso14443_4a/iso14443_4a.c | 11 +- lib/nfc/protocols/iso14443_4a/iso14443_4a.h | 3 +- lib/nfc/protocols/iso14443_4a/iso14443_4a_i.c | 3 +- .../iso14443_4a/iso14443_4a_poller.c | 3 +- .../iso14443_4a/iso14443_4a_poller_defs.h | 2 +- lib/nfc/protocols/mf_classic/mf_classic.c | 7 +- lib/nfc/protocols/mf_classic/mf_classic.h | 2 +- lib/nfc/protocols/mf_desfire/mf_desfire.c | 8 +- lib/nfc/protocols/mf_desfire/mf_desfire.h | 2 +- .../mf_desfire/mf_desfire_poller_defs.h | 2 +- .../protocols/mf_ultralight/mf_ultralight.c | 16 +- .../protocols/mf_ultralight/mf_ultralight.h | 3 +- .../mf_ultralight/mf_ultralight_poller.c | 2 +- .../mf_ultralight/mf_ultralight_poller_defs.h | 2 +- .../mf_ultralight/mf_ultralight_poller_i.c | 8 +- lib/nfc/{ => protocols}/nfc_poller_base.h | 2 +- lib/nfc/{ => protocols}/nfc_poller_defs.c | 0 lib/nfc/{ => protocols}/nfc_poller_defs.h | 0 lib/nfc/protocols/nfc_protocol_base.h | 5 +- lib/nfc/protocols/nfca/nfca.c | 10 +- lib/nfc/protocols/nfca/nfca.h | 2 +- lib/nfc/protocols/nfca/nfca_poller_defs.h | 2 +- lib/nfc/protocols/nfca/nfca_poller_i.h | 2 +- lib/nfc/protocols/nfcb/nfcb_poller_i.h | 2 +- 52 files changed, 630 insertions(+), 611 deletions(-) create mode 100644 applications/main/nfc/scenes/nfc_scene_detect.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_read.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_read_card_type.c create mode 100644 applications/main/nfc/scenes/nfc_scene_select_protocol.c delete mode 100644 lib/nfc/nfc_poller.c delete mode 100644 lib/nfc/nfc_poller.h create mode 100644 lib/nfc/nfc_scanner.c create mode 100644 lib/nfc/nfc_scanner.h rename lib/nfc/{ => protocols}/nfc_poller_base.h (96%) rename lib/nfc/{ => protocols}/nfc_poller_defs.c (100%) rename lib/nfc/{ => protocols}/nfc_poller_defs.h (100%) diff --git a/applications/main/nfc/helpers/format/nfc_protocol_format.c b/applications/main/nfc/helpers/format/nfc_protocol_format.c index 8bdc530d75f2..403b081cc1cd 100644 --- a/applications/main/nfc/helpers/format/nfc_protocol_format.c +++ b/applications/main/nfc/helpers/format/nfc_protocol_format.c @@ -29,7 +29,7 @@ static void static void nfc_protocol_format_iso14443_3a_render_info(const NfcDev* device, FuriString* str) { furi_string_cat_printf( - str, "\e#%s\n", nfc_dev_get_protocol_name(device, NfcProtocolNameTypeFull)); + str, "\e#%s\n", nfc_dev_get_device_name(device, NfcProtocolNameTypeFull)); const NfcaData* data = nfc_dev_get_protocol_data(device, NfcProtocolTypeIso14443_3a); nfc_protocol_format_common_iso14443_3a_render_info(data, str); @@ -37,7 +37,7 @@ static void nfc_protocol_format_iso14443_3a_render_info(const NfcDev* device, Fu static void nfc_protocol_format_iso14443_4a_render_info(const NfcDev* device, FuriString* str) { furi_string_cat_printf( - str, "\e#%s\n", nfc_dev_get_protocol_name(device, NfcProtocolNameTypeFull)); + str, "\e#%s\n", nfc_dev_get_device_name(device, NfcProtocolNameTypeFull)); const Iso14443_4aData* data = nfc_dev_get_protocol_data(device, NfcProtocolTypeIso14443_4a); nfc_protocol_format_common_iso14443_3a_render_info(data->iso14443_3a_data, str); @@ -45,7 +45,7 @@ static void nfc_protocol_format_iso14443_4a_render_info(const NfcDev* device, Fu static void nfc_protocol_format_mf_ultralight_render_info(const NfcDev* device, FuriString* str) { furi_string_cat_printf( - str, "\e#%s\n", nfc_dev_get_protocol_name(device, NfcProtocolNameTypeFull)); + str, "\e#%s\n", nfc_dev_get_device_name(device, NfcProtocolNameTypeFull)); const MfUltralightData* data = nfc_dev_get_protocol_data(device, NfcProtocolTypeMfUltralight); nfc_protocol_format_common_iso14443_3a_render_info(data->nfca_data, str); @@ -53,7 +53,7 @@ static void nfc_protocol_format_mf_ultralight_render_info(const NfcDev* device, static void nfc_protocol_format_mf_classic_render_info(const NfcDev* device, FuriString* str) { furi_string_cat_printf( - str, "\e#%s\n", nfc_dev_get_protocol_name(device, NfcProtocolNameTypeFull)); + str, "\e#%s\n", nfc_dev_get_device_name(device, NfcProtocolNameTypeFull)); const MfClassicData* data = nfc_dev_get_protocol_data(device, NfcProtocolTypeMfClassic); nfc_protocol_format_common_iso14443_3a_render_info(data->nfca_data, str); @@ -62,7 +62,7 @@ static void nfc_protocol_format_mf_classic_render_info(const NfcDev* device, Fur // TODO: use proper type getters static void nfc_protocol_format_mf_desfire_render_info(const NfcDev* device, FuriString* str) { furi_string_cat_printf( - str, "\e#%s\n", nfc_dev_get_protocol_name(device, NfcProtocolNameTypeFull)); + str, "\e#%s\n", nfc_dev_get_device_name(device, NfcProtocolNameTypeFull)); const MfDesfireData* data = nfc_dev_get_protocol_data(device, NfcProtocolTypeMfDesfire); nfc_protocol_format_common_iso14443_3a_render_info( diff --git a/applications/main/nfc/nfc_app.c b/applications/main/nfc/nfc_app.c index 9263a5e77441..cbd2bddc4df7 100644 --- a/applications/main/nfc/nfc_app.c +++ b/applications/main/nfc/nfc_app.c @@ -47,22 +47,14 @@ NfcApp* nfc_app_alloc() { instance->nfc = nfc_alloc(); instance->nfca_poller = nfca_poller_alloc(instance->nfc); - instance->mf_ul_poller = mf_ultralight_poller_alloc(instance->nfca_poller); instance->mf_classic_poller = mf_classic_poller_alloc(instance->nfca_poller); instance->nfca_listener = nfca_listener_alloc(instance->nfc); instance->mf_ul_listener = mf_ultralight_listener_alloc(instance->nfca_listener); - instance->nfcb_poller = nfcb_poller_alloc(instance->nfc); instance->parsed_data = furi_string_alloc(); - NfcPollerOldCollection collection = { - .nfc = instance->nfc, - .nfca_poller = instance->nfca_poller, - .nfcb_poller = instance->nfcb_poller, - }; - instance->nfc_poller = nfc_poller_alloc(&collection); - instance->poller_manager = nfc_poller_manager_alloc(instance->nfc); + instance->scanner = nfc_scanner_alloc(instance->nfc); instance->mf_ul_auth = mf_ultralight_auth_alloc(); @@ -166,13 +158,11 @@ void nfc_app_free(NfcApp* instance) { mf_classic_poller_free(instance->mf_classic_poller); mf_ultralight_listener_free(instance->mf_ul_listener); - mf_ultralight_poller_free(instance->mf_ul_poller); nfca_listener_free(instance->nfca_listener); nfca_poller_free(instance->nfca_poller); - nfcb_poller_free(instance->nfcb_poller); - nfc_poller_free(instance->nfc_poller); nfc_free(instance->nfc); nfc_poller_manager_free(instance->poller_manager); + nfc_scanner_free(instance->scanner); mf_ultralight_auth_free(instance->mf_ul_auth); diff --git a/applications/main/nfc/nfc_app_i.h b/applications/main/nfc/nfc_app_i.h index 57f0b664da81..8dbdf886698c 100644 --- a/applications/main/nfc/nfc_app_i.h +++ b/applications/main/nfc/nfc_app_i.h @@ -39,16 +39,15 @@ #include #include -#include #include #include +#include #include #include #include -#include #include -#include +#include #include #include @@ -89,6 +88,10 @@ struct NfcApp { FuriString* text_box_store; uint8_t byte_input_store[6]; + size_t protocols_detected_num; + size_t protocols_detected_idx; + NfcProtocolType protocols_detected[NfcProtocolTypeMax]; + void* rpc_ctx; NfcRpcState rpc_state; @@ -107,13 +110,11 @@ struct NfcApp { Nfc* nfc; NfcaPoller* nfca_poller; NfcaListener* nfca_listener; - MfUltralightPoller* mf_ul_poller; MfUltralightListener* mf_ul_listener; MfClassicPoller* mf_classic_poller; - NfcbPoller* nfcb_poller; - NfcPollerOld* nfc_poller; NfcPollerManager* poller_manager; + NfcScanner* scanner; MfUltralightAuth* mf_ul_auth; NfcMfClassicDictAttackContext mf_dict_context; diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index 6fc1116267cf..e521056216b2 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -6,9 +6,9 @@ ADD_SCENE(nfc, save_success, SaveSuccess) ADD_SCENE(nfc, delete, Delete) ADD_SCENE(nfc, delete_success, DeleteSuccess) -ADD_SCENE(nfc, read, Read) +ADD_SCENE(nfc, detect, Detect) ADD_SCENE(nfc, info, Info) -ADD_SCENE(nfc, read_card_type, ReadCardType) +ADD_SCENE(nfc, select_protocol, SelectProtocol) ADD_SCENE(nfc, nfca_read, NfcaRead) ADD_SCENE(nfc, nfca_emulate, NfcaEmulate) ADD_SCENE(nfc, nfca_read_success, NfcaReadSuccess) diff --git a/applications/main/nfc/scenes/nfc_scene_delete.c b/applications/main/nfc/scenes/nfc_scene_delete.c index 88fb834da43b..518402c355d0 100644 --- a/applications/main/nfc/scenes/nfc_scene_delete.c +++ b/applications/main/nfc/scenes/nfc_scene_delete.c @@ -32,8 +32,7 @@ void nfc_scene_delete_on_enter(void* context) { widget_add_string_element( nfc->widget, 64, 24, AlignCenter, AlignTop, FontSecondary, furi_string_get_cstr(temp_str)); - furi_string_set_str( - temp_str, nfc_dev_get_protocol_name(nfc->nfc_dev, NfcProtocolNameTypeFull)); + furi_string_set_str(temp_str, nfc_dev_get_device_name(nfc->nfc_dev, NfcProtocolNameTypeFull)); widget_add_string_element( nfc->widget, 64, 34, AlignCenter, AlignTop, FontSecondary, furi_string_get_cstr(temp_str)); widget_add_string_element(nfc->widget, 64, 44, AlignCenter, AlignTop, FontSecondary, "NFC-A"); diff --git a/applications/main/nfc/scenes/nfc_scene_detect.c b/applications/main/nfc/scenes/nfc_scene_detect.c new file mode 100644 index 000000000000..9855f71ca55f --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_detect.c @@ -0,0 +1,67 @@ +#include "../nfc_app_i.h" +#include + +void nfc_scene_detect_scan_callback(NfcScannerEvent event, void* context) { + furi_assert(context); + + NfcApp* instance = context; + + if(event.type == NfcScannerEventTypeDetected) { + instance->protocols_detected_num = event.data.protocol_num; + memcpy(instance->protocols_detected, event.data.protocols, event.data.protocol_num); + view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventWorkerExit); + } +} + +void nfc_scene_detect_on_enter(void* context) { + NfcApp* instance = context; + + // Setup view + popup_reset(instance->popup); + popup_set_text( + instance->popup, "Apply card to\nFlipper's back", 97, 24, AlignCenter, AlignTop); + popup_set_icon(instance->popup, 0, 8, &I_NFC_manual_60x50); + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup); + + nfc_scanner_start(instance->scanner, nfc_scene_detect_scan_callback, instance); + + nfc_blink_detect_start(instance); +} + +bool nfc_scene_detect_on_event(void* context, SceneManagerEvent event) { + NfcApp* instance = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventWorkerExit) { + if(instance->protocols_detected_num > 1) { + scene_manager_next_scene(instance->scene_manager, NfcSceneSelectProtocol); + } else { + // TODO rework with generic read scene + const uint32_t nfc_read_scenes[NfcProtocolTypeMax] = { + NfcSceneNfcaRead, + NfcSceneNfcaRead, + NfcSceneMfUltralightRead, + NfcSceneMfClassicDictAttack, + NfcSceneMfDesfireRead, + }; + instance->protocols_detected_idx = 0; + scene_manager_next_scene( + instance->scene_manager, + nfc_read_scenes[instance->protocols_detected[instance->protocols_detected_idx]]); + } + consumed = true; + } + } + + return consumed; +} + +void nfc_scene_detect_on_exit(void* context) { + NfcApp* instance = context; + + nfc_scanner_stop(instance->scanner); + popup_reset(instance->popup); + + nfc_blink_stop(instance); +} diff --git a/applications/main/nfc/scenes/nfc_scene_exit_confirm.c b/applications/main/nfc/scenes/nfc_scene_exit_confirm.c index 3b2e73f97e70..c024d31295a2 100644 --- a/applications/main/nfc/scenes/nfc_scene_exit_confirm.c +++ b/applications/main/nfc/scenes/nfc_scene_exit_confirm.c @@ -29,8 +29,13 @@ bool nfc_scene_exit_confirm_on_event(void* context, SceneManagerEvent event) { if(event.event == DialogExResultRight) { consumed = scene_manager_previous_scene(nfc->scene_manager); } else if(event.event == DialogExResultLeft) { - consumed = scene_manager_search_and_switch_to_previous_scene( - nfc->scene_manager, NfcSceneStart); + if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSelectProtocol)) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneSelectProtocol); + } else { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneStart); + } } } else if(event.type == SceneManagerEventTypeBack) { consumed = true; diff --git a/applications/main/nfc/scenes/nfc_scene_extra_actions.c b/applications/main/nfc/scenes/nfc_scene_extra_actions.c index 35c8a9cea8c9..455afb06300a 100644 --- a/applications/main/nfc/scenes/nfc_scene_extra_actions.c +++ b/applications/main/nfc/scenes/nfc_scene_extra_actions.c @@ -52,7 +52,7 @@ bool nfc_scene_extra_actions_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockMenu); consumed = true; } else if(event.event == SubmenuIndexReadCardType) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardType); + scene_manager_next_scene(nfc->scene_manager, NfcSceneSelectProtocol); consumed = true; } scene_manager_set_scene_state(nfc->scene_manager, NfcSceneExtraActions, event.event); diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_read_success.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_read_success.c index 31310e08c58b..d9cdb6a93252 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_read_success.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_read_success.c @@ -29,7 +29,7 @@ void nfc_scene_mf_classic_read_success_on_enter(void* context) { temp_str = furi_string_alloc_set(nfc->parsed_data); } else { temp_str = furi_string_alloc_printf( - "\e#%s\n", nfc_dev_get_protocol_name(nfc->nfc_dev, NfcProtocolNameTypeFull)); + "\e#%s\n", nfc_dev_get_device_name(nfc->nfc_dev, NfcProtocolNameTypeFull)); furi_string_cat_printf(temp_str, "UID:"); for(size_t i = 0; i < mfc_data->nfca_data->uid_len; i++) { furi_string_cat_printf(temp_str, " %02X", mfc_data->nfca_data->uid[i]); diff --git a/applications/main/nfc/scenes/nfc_scene_mf_desfire_read_success.c b/applications/main/nfc/scenes/nfc_scene_mf_desfire_read_success.c index 90f4a877dad1..5d2bc55c3a55 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_desfire_read_success.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_desfire_read_success.c @@ -22,7 +22,7 @@ void nfc_scene_mf_desfire_read_success_on_enter(void* context) { FuriString* temp_str; temp_str = furi_string_alloc_printf( - "\e#%s\n", nfc_dev_get_protocol_name(nfc->nfc_dev, NfcProtocolNameTypeFull)); + "\e#%s\n", nfc_dev_get_device_name(nfc->nfc_dev, NfcProtocolNameTypeFull)); furi_string_cat_printf(temp_str, "UID:"); size_t uid_len; diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read.c index 7457e4fd4047..bc87d8b99e0e 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read.c @@ -5,68 +5,26 @@ enum { NfcWorkerEventMfUltralightReadSuccess, }; -// MfUltralightPollerCommand -// nfc_scene_mf_ultralight_read_worker_callback(MfUltralightPollerEvent event, void* context) { -// NfcApp* nfc = context; - -// MfUltralightPollerCommand command = MfUltralightPollerCommandContinue; - -// if(event.type == MfUltralightPollerEventTypeReadSuccess) { -// view_dispatcher_send_custom_event( -// nfc->view_dispatcher, NfcWorkerEventMfUltralightReadSuccess); -// command = MfUltralightPollerCommandStop; -// } else if(event.type == MfUltralightPollerEventTypeAuthRequest) { -// nfc_dev_set_protocol_data( -// nfc->nfc_dev, -// NfcProtocolTypeMfUltralight, -// mf_ultralight_poller_get_data(nfc->mf_ul_poller)); -// const MfUltralightData* data = -// nfc_dev_get_protocol_data(nfc->nfc_dev, NfcProtocolTypeMfUltralight); -// if(nfc->mf_ul_auth->type == MfUltralightAuthTypeXiaomii) { -// if(mf_ultralight_generate_xiaomi_pass( -// nfc->mf_ul_auth, data->nfca_data->uid, data->nfca_data->uid_len)) { -// event.data->auth_context.skip_auth = false; -// } -// } else if(nfc->mf_ul_auth->type == MfUltralightAuthTypeAmiibo) { -// if(mf_ultralight_generate_amiibo_pass( -// nfc->mf_ul_auth, data->nfca_data->uid, data->nfca_data->uid_len)) { -// event.data->auth_context.skip_auth = false; -// } -// } else if(nfc->mf_ul_auth->type == MfUltralightAuthTypeManual) { -// event.data->auth_context.skip_auth = false; -// } else { -// event.data->auth_context.skip_auth = true; -// } -// if(!event.data->auth_context.skip_auth) { -// event.data->auth_context.password = nfc->mf_ul_auth->password; -// } -// } else if(event.type == MfUltralightPollerEventTypeAuthSuccess) { -// nfc->mf_ul_auth->pack = event.data->auth_context.pack; -// } - -// return command; -// } - NfcCommand nfc_scene_mf_ultralight_read_worker_callback(NfcPollerEvent event, void* context) { furi_assert(context); furi_assert(event.poller); furi_assert(event.data); NfcApp* instance = context; - const NfcPollerBase* poller_api = nfc_pollers_api[event.protocol_type]; MfUltralightPollerEvent* mfu_event = event.data; + MfUltralightPoller* mfu_poller = event.poller; NfcCommand command = NfcCommandContinue; if(mfu_event->type == MfUltralightPollerEventTypeReadSuccess) { nfc_dev_set_protocol_data( - instance->nfc_dev, event.protocol_type, poller_api->get_data(event.poller)); + instance->nfc_dev, event.protocol_type, mf_ultralight_poller_get_data(mfu_poller)); view_dispatcher_send_custom_event( instance->view_dispatcher, NfcWorkerEventMfUltralightReadSuccess); command = NfcCommandStop; } else if(mfu_event->type == MfUltralightPollerEventTypeAuthRequest) { nfc_dev_set_protocol_data( - instance->nfc_dev, event.protocol_type, poller_api->get_data(event.poller)); + instance->nfc_dev, event.protocol_type, mf_ultralight_poller_get_data(mfu_poller)); const MfUltralightData* data = nfc_dev_get_protocol_data(instance->nfc_dev, NfcProtocolTypeMfUltralight); if(instance->mf_ul_auth->type == MfUltralightAuthTypeXiaomii) { @@ -100,8 +58,6 @@ void nfc_scene_mf_ultralight_read_on_enter(void* context) { // Setup view view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup); - // mf_ultralight_poller_read( - // instance->mf_ul_poller, nfc_scene_mf_ultralight_read_worker_callback, instance); nfc_poller_manager_start( instance->poller_manager, NfcProtocolTypeMfUltralight, @@ -129,7 +85,6 @@ bool nfc_scene_mf_ultralight_read_on_event(void* context, SceneManagerEvent even void nfc_scene_mf_ultralight_read_on_exit(void* context) { NfcApp* instance = context; - // mf_ultralight_poller_stop(nfc->mf_ul_poller); nfc_poller_manager_stop(instance->poller_manager); // Clear view popup_reset(instance->popup); diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_success.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_success.c index 3703bae9d659..cd4b9befad7a 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_success.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_success.c @@ -23,7 +23,7 @@ void nfc_scene_mf_ultralight_read_success_on_enter(void* context) { FuriString* temp_str; temp_str = furi_string_alloc_printf( - "\e#%s\n", nfc_dev_get_protocol_name(nfc->nfc_dev, NfcProtocolNameTypeFull)); + "\e#%s\n", nfc_dev_get_device_name(nfc->nfc_dev, NfcProtocolNameTypeFull)); furi_string_cat_printf(temp_str, "UID:"); for(size_t i = 0; i < data->nfca_data->uid_len; i++) { furi_string_cat_printf(temp_str, " %02X", data->nfca_data->uid[i]); diff --git a/applications/main/nfc/scenes/nfc_scene_nfca_read.c b/applications/main/nfc/scenes/nfc_scene_nfca_read.c index 12ec0198b26a..1401c7ade1d8 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfca_read.c +++ b/applications/main/nfc/scenes/nfc_scene_nfca_read.c @@ -5,21 +5,6 @@ enum { NfcWorkerEventReadUidNfcA = 100, }; -// NfcaPollerCommand nfc_scene_nfca_read_worker_callback(NfcaPollerEvent event, void* context) { -// NfcApp* nfc = context; - -// NfcaPollerCommand command = NfcaPollerCommandContinue; - -// if(event.type == NfcaPollerEventTypeReady) { -// nfc_dev_set_protocol_data( -// nfc->nfc_dev, NfcProtocolTypeIso14443_3a, nfca_poller_get_data(nfc->nfca_poller)); -// view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcWorkerEventReadUidNfcA); -// command = NfcaPollerCommandStop; -// } - -// return command; -// } - NfcCommand nfc_scene_nfca_read_worker_callback(NfcPollerEvent event, void* context) { furi_assert(context); furi_assert(event.data); @@ -28,11 +13,11 @@ NfcCommand nfc_scene_nfca_read_worker_callback(NfcPollerEvent event, void* conte NfcApp* instance = context; NfcCommand command = NfcCommandContinue; NfcaPollerEvent* nfca_event = event.data; - const NfcPollerBase* poller_api = nfc_pollers_api[event.protocol_type]; + NfcaPoller* nfca_poller = event.poller; if(nfca_event->type == NfcaPollerEventTypeReady) { nfc_dev_set_protocol_data( - instance->nfc_dev, event.protocol_type, poller_api->get_data(event.poller)); + instance->nfc_dev, event.protocol_type, nfca_poller_get_data(nfca_poller)); view_dispatcher_send_custom_event(instance->view_dispatcher, NfcWorkerEventReadUidNfcA); command = NfcCommandStop; } @@ -46,7 +31,6 @@ void nfc_scene_nfca_read_on_enter(void* context) { // Setup view view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup); - // nfca_poller_start(nfc->nfca_poller, nfc_scene_nfca_read_worker_callback, nfc); nfc_poller_manager_start( instance->poller_manager, NfcProtocolTypeIso14443_3a, @@ -74,7 +58,6 @@ bool nfc_scene_nfca_read_on_event(void* context, SceneManagerEvent event) { void nfc_scene_nfca_read_on_exit(void* context) { NfcApp* instance = context; - // nfca_poller_stop(nfc->nfca_poller); nfc_poller_manager_stop(instance->poller_manager); // Clear view popup_reset(instance->popup); diff --git a/applications/main/nfc/scenes/nfc_scene_read.c b/applications/main/nfc/scenes/nfc_scene_read.c deleted file mode 100644 index b431cf5c7285..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_read.c +++ /dev/null @@ -1,80 +0,0 @@ -#include "../nfc_app_i.h" -#include - -enum { - NfcSceneReadEventNfcaDetected = 100, - NfcSceneReadEventNfcbDetected, - NfcSceneReadEventMfUltralightDetected, - NfcSceneReadEventMfDesfireDetected, -}; - -NfcPollerOldCommand nfc_scene_read_worker_callback(NfcPollerOldEvent event, void* context) { - NfcApp* nfc = context; - - NfcPollerOldCommand command = NfcPollerOldCommandContinue; - - if(event == NfcPollerOldEventNfcaDetected) { - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcSceneReadEventNfcaDetected); - command = NfcPollerOldCommandStop; - } else if(event == NfcPollerOldEventNfcbDetected) { - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcSceneReadEventNfcbDetected); - command = NfcPollerOldCommandStop; - } else if(event == NfcPollerOldEventMfUltralightDetected) { - view_dispatcher_send_custom_event( - nfc->view_dispatcher, NfcSceneReadEventMfUltralightDetected); - command = NfcPollerOldCommandStop; - } else if(event == NfcPollerOldEventMfDesfireDetected) { - view_dispatcher_send_custom_event( - nfc->view_dispatcher, NfcSceneReadEventMfDesfireDetected); - command = NfcPollerOldCommandStop; - } - - return command; -} - -void nfc_scene_read_on_enter(void* context) { - NfcApp* nfc = context; - - // Setup view - popup_reset(nfc->popup); - popup_set_text(nfc->popup, "Apply card to\nFlipper's back", 97, 24, AlignCenter, AlignTop); - popup_set_icon(nfc->popup, 0, 8, &I_NFC_manual_60x50); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); - - nfc_poller_start(nfc->nfc_poller, nfc_scene_read_worker_callback, nfc); - - nfc_blink_read_start(nfc); -} - -bool nfc_scene_read_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == NfcSceneReadEventNfcaDetected) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcaRead); - consumed = true; - } else if(event.event == NfcSceneReadEventNfcbDetected) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); - consumed = true; - } else if(event.event == NfcSceneReadEventMfUltralightDetected) { - mf_ultralight_auth_reset(nfc->mf_ul_auth); - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightRead); - consumed = true; - } else if(event.event == NfcSceneReadEventMfDesfireDetected) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireRead); - consumed = true; - } - } - return consumed; -} - -void nfc_scene_read_on_exit(void* context) { - NfcApp* nfc = context; - - nfc_poller_stop(nfc->nfc_poller); - // Clear view - popup_reset(nfc->popup); - - nfc_blink_stop(nfc); -} diff --git a/applications/main/nfc/scenes/nfc_scene_read_card_type.c b/applications/main/nfc/scenes/nfc_scene_read_card_type.c deleted file mode 100644 index 9dffe8654fd8..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_read_card_type.c +++ /dev/null @@ -1,91 +0,0 @@ -#include "../nfc_app_i.h" - -enum SubmenuIndex { - SubmenuIndexReadNFCA, - SubmenuIndexReadMfUltralight, - SubmenuIndexReadMifareClassic, - SubmenuIndexReadMifareDesfire, - SubmenuIndexReadEMV, -}; - -void nfc_scene_read_card_type_submenu_callback(void* context, uint32_t index) { - NfcApp* nfc = context; - - view_dispatcher_send_custom_event(nfc->view_dispatcher, index); -} - -void nfc_scene_read_card_type_on_enter(void* context) { - NfcApp* nfc = context; - Submenu* submenu = nfc->submenu; - - submenu_add_item( - submenu, - "Read NFC-A data", - SubmenuIndexReadNFCA, - nfc_scene_read_card_type_submenu_callback, - nfc); - submenu_add_item( - submenu, - "Read NTAG/Ultralight", - SubmenuIndexReadMfUltralight, - nfc_scene_read_card_type_submenu_callback, - nfc); - submenu_add_item( - submenu, - "Read Mifare Classic", - SubmenuIndexReadMifareClassic, - nfc_scene_read_card_type_submenu_callback, - nfc); - submenu_add_item( - submenu, - "Read Mifare DESFire", - SubmenuIndexReadMifareDesfire, - nfc_scene_read_card_type_submenu_callback, - nfc); - submenu_add_item( - submenu, - "Read EMV card", - SubmenuIndexReadEMV, - nfc_scene_read_card_type_submenu_callback, - nfc); - uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadCardType); - submenu_set_selected_item(submenu, state); - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); -} - -bool nfc_scene_read_card_type_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == SubmenuIndexReadMifareDesfire) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireRead); - consumed = true; - } - if(event.event == SubmenuIndexReadMfUltralight) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightRead); - consumed = true; - } - if(event.event == SubmenuIndexReadMifareClassic) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSupportedCard); - consumed = true; - } - if(event.event == SubmenuIndexReadEMV) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); - consumed = true; - } - if(event.event == SubmenuIndexReadNFCA) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcaRead); - consumed = true; - } - scene_manager_set_scene_state(nfc->scene_manager, NfcSceneReadCardType, event.event); - } - return consumed; -} - -void nfc_scene_read_card_type_on_exit(void* context) { - NfcApp* nfc = context; - - submenu_reset(nfc->submenu); -} diff --git a/applications/main/nfc/scenes/nfc_scene_retry_confirm.c b/applications/main/nfc/scenes/nfc_scene_retry_confirm.c index 9ddd7c8aa3a2..4b4c305d18f2 100644 --- a/applications/main/nfc/scenes/nfc_scene_retry_confirm.c +++ b/applications/main/nfc/scenes/nfc_scene_retry_confirm.c @@ -29,9 +29,9 @@ bool nfc_scene_retry_confirm_on_event(void* context, SceneManagerEvent event) { if(event.event == DialogExResultRight) { consumed = scene_manager_previous_scene(nfc->scene_manager); } else if(event.event == DialogExResultLeft) { - if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneRead)) { + if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneDetect)) { consumed = scene_manager_search_and_switch_to_previous_scene( - nfc->scene_manager, NfcSceneRead); + nfc->scene_manager, NfcSceneDetect); } else if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneNfcaRead)) { consumed = scene_manager_search_and_switch_to_previous_scene( nfc->scene_manager, NfcSceneNfcaRead); diff --git a/applications/main/nfc/scenes/nfc_scene_select_protocol.c b/applications/main/nfc/scenes/nfc_scene_select_protocol.c new file mode 100644 index 000000000000..7c2c28f75244 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_select_protocol.c @@ -0,0 +1,73 @@ +#include "../nfc_app_i.h" + +void nfc_scene_select_protocol_submenu_callback(void* context, uint32_t index) { + NfcApp* instance = context; + + view_dispatcher_send_custom_event(instance->view_dispatcher, index); +} + +void nfc_scene_select_protocol_on_enter(void* context) { + NfcApp* instance = context; + Submenu* submenu = instance->submenu; + + FuriString* temp_str = furi_string_alloc(); + const char* prefix; + if(scene_manager_has_previous_scene(instance->scene_manager, NfcSceneExtraActions)) { + prefix = "Read"; + instance->protocols_detected_num = NfcProtocolTypeMax; + for(size_t i = 0; i < NfcProtocolTypeMax; i++) { + instance->protocols_detected[i] = i; + } + } else { + prefix = "Read as"; + submenu_set_header(submenu, "Multi-protocol card"); + } + + for(size_t i = 0; i < instance->protocols_detected_num; i++) { + furi_string_printf( + temp_str, "%s %s", prefix, nfc_dev_get_protocol_name(instance->protocols_detected[i])); + submenu_add_item( + submenu, + furi_string_get_cstr(temp_str), + i, + nfc_scene_select_protocol_submenu_callback, + instance); + } + furi_string_free(temp_str); + + uint32_t state = + scene_manager_get_scene_state(instance->scene_manager, NfcSceneSelectProtocol); + submenu_set_selected_item(submenu, state); + + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewMenu); +} + +bool nfc_scene_select_protocol_on_event(void* context, SceneManagerEvent event) { + NfcApp* instance = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + instance->protocols_detected_idx = event.event; + // TODO remove this and switch to generic read + const uint32_t nfc_read_scenes[NfcProtocolTypeMax] = { + NfcSceneNfcaRead, + NfcSceneNfcaRead, + NfcSceneMfUltralightRead, + NfcSceneMfClassicDictAttack, + NfcSceneMfDesfireRead, + }; + scene_manager_next_scene( + instance->scene_manager, + nfc_read_scenes[instance->protocols_detected[instance->protocols_detected_idx]]); + scene_manager_set_scene_state( + instance->scene_manager, NfcSceneSelectProtocol, event.event); + consumed = true; + } + return consumed; +} + +void nfc_scene_select_protocol_on_exit(void* context) { + NfcApp* nfc = context; + + submenu_reset(nfc->submenu); +} diff --git a/applications/main/nfc/scenes/nfc_scene_start.c b/applications/main/nfc/scenes/nfc_scene_start.c index 1315f1036866..fc21cfe79e68 100644 --- a/applications/main/nfc/scenes/nfc_scene_start.c +++ b/applications/main/nfc/scenes/nfc_scene_start.c @@ -47,7 +47,7 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubmenuIndexRead) { scene_manager_set_scene_state(nfc->scene_manager, NfcSceneStart, SubmenuIndexRead); - scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); + scene_manager_next_scene(nfc->scene_manager, NfcSceneDetect); DOLPHIN_DEED(DolphinDeedNfcRead); consumed = true; } else if(event.event == SubmenuIndexDetectReader) { diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index c6272f9694de..f5dee1bad387 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,+,28.2,, +Version,+,30.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -1980,8 +1980,8 @@ Function,+,mf_classic_copy,void,"MfClassicData*, const MfClassicData*" Function,-,mf_classic_detect_protocol,_Bool,"NfcaData*, MfClassicType*" Function,+,mf_classic_free,void,MfClassicData* Function,-,mf_classic_get_blocks_num_in_sector,uint8_t,uint8_t +Function,+,mf_classic_get_device_name,const char*,"const MfClassicData*, NfcProtocolNameType" Function,-,mf_classic_get_first_block_num_of_sector,uint8_t,uint8_t -Function,+,mf_classic_get_name,const char*,"const MfClassicData*, NfcProtocolNameType" Function,+,mf_classic_get_read_sectors_and_keys,void,"const MfClassicData*, uint8_t*, uint8_t*" Function,-,mf_classic_get_sector_by_block,uint8_t,uint8_t Function,+,mf_classic_get_sector_trailer_by_sector,MfClassicSectorTrailer*,"const MfClassicData*, uint8_t" @@ -2047,7 +2047,6 @@ Function,-,nfc_listener_sleep,NfcError,Nfc* Function,-,nfc_listener_tx,NfcError,"Nfc*, const BitBuffer*" Function,-,nfc_poller_manager_alloc,NfcPollerManager*,Nfc* Function,-,nfc_poller_manager_free,void,NfcPollerManager* -Function,-,nfc_poller_manager_scan,void,"NfcPollerManager*, NfcPollerCallback, void*" Function,-,nfc_poller_manager_start,void,"NfcPollerManager*, NfcProtocolType, NfcPollerCallback, void*" Function,-,nfc_poller_manager_stop,void,NfcPollerManager* Function,-,nfc_set_fdt_listen_fc,void,"Nfc*, uint32_t" @@ -2069,7 +2068,7 @@ Function,-,nfca_emulation_handler,_Bool,"uint8_t*, uint16_t, uint8_t*, uint16_t* Function,+,nfca_free,void,NfcaData* Function,-,nfca_get_crc16,uint16_t,"uint8_t*, uint16_t" Function,-,nfca_get_cuid,uint32_t,NfcaData* -Function,+,nfca_get_name,const char*,"const NfcaData*, NfcProtocolNameType" +Function,+,nfca_get_device_name,const char*,"const NfcaData*, NfcProtocolNameType" Function,+,nfca_get_uid,const uint8_t*,"const NfcaData*, size_t*" Function,+,nfca_is_equal,_Bool,"const NfcaData*, const NfcaData*" Function,+,nfca_load,_Bool,"NfcaData*, FlipperFormat*, uint32_t" diff --git a/lib/nfc/nfc.c b/lib/nfc/nfc.c index bac2dd50eb47..28731ea0c63b 100644 --- a/lib/nfc/nfc.c +++ b/lib/nfc/nfc.c @@ -345,7 +345,7 @@ static NfcError nfc_poller_trx_state_machine(Nfc* instance, uint32_t fwt_fc) { if(event & FHalNfcEventTxEnd) { if(instance->comm_state == NfcCommStateWaitTxEnd) { if(fwt_fc) { - f_hal_nfc_timer_fwt_start(fwt_fc); + f_hal_nfc_timer_fwt_start(fwt_fc + F_HAL_NFC_TIMER_OFFSET_FC); } f_hal_nfc_timer_block_tx_start_us(instance->fdt_poll_poll_us); instance->comm_state = NfcCommStateWaitRxStart; diff --git a/lib/nfc/nfc_dev.c b/lib/nfc/nfc_dev.c index 131e57541c9c..7b89c9bb57d2 100644 --- a/lib/nfc/nfc_dev.c +++ b/lib/nfc/nfc_dev.c @@ -64,11 +64,18 @@ const NfcProtocolData* return instance->protocol_data; } -const char* nfc_dev_get_protocol_name(const NfcDev* instance, NfcProtocolNameType name_type) { +const char* nfc_dev_get_protocol_name(NfcProtocolType protocol) { + furi_assert(protocol < NfcProtocolTypeMax); + + return nfc_protocols[protocol]->protocol_name; +} + +const char* nfc_dev_get_device_name(const NfcDev* instance, NfcProtocolNameType name_type) { furi_assert(instance); furi_assert(instance->protocol_type < NfcProtocolTypeMax); - return nfc_protocols[instance->protocol_type]->get_name(instance->protocol_data, name_type); + return nfc_protocols[instance->protocol_type]->get_device_name( + instance->protocol_data, name_type); } const uint8_t* nfc_dev_get_uid(const NfcDev* instance, size_t* uid_len) { diff --git a/lib/nfc/nfc_dev.h b/lib/nfc/nfc_dev.h index 425abb890e54..a7dba5ecf3c1 100644 --- a/lib/nfc/nfc_dev.h +++ b/lib/nfc/nfc_dev.h @@ -25,7 +25,9 @@ NfcProtocolType nfc_dev_get_protocol_type(const NfcDev* instance); const NfcProtocolData* nfc_dev_get_protocol_data(const NfcDev* instance, NfcProtocolType protocol_type); -const char* nfc_dev_get_protocol_name(const NfcDev* instance, NfcProtocolNameType name_type); +const char* nfc_dev_get_protocol_name(NfcProtocolType protocol); + +const char* nfc_dev_get_device_name(const NfcDev* instance, NfcProtocolNameType name_type); const uint8_t* nfc_dev_get_uid(const NfcDev* instance, size_t* uid_len); diff --git a/lib/nfc/nfc_poller.c b/lib/nfc/nfc_poller.c deleted file mode 100644 index c38b6591a6da..000000000000 --- a/lib/nfc/nfc_poller.c +++ /dev/null @@ -1,160 +0,0 @@ -#include "nfc_poller.h" - -#include - -#include "nfc.h" -#include -#include -#include - -typedef enum { - NfcPollerOldStateIdle, - NfcPollerOldStateCheckPresenceNfca, - NfcPollerOldStateCheckPresenceNfcb, - NfcPollerOldStateCheckPresenceNfcf, - NfcPollerOldStateCheckPresenceNfcv, -} NfcPollerOldState; - -typedef enum { - NfcPollerOldSessionStateIdle, - NfcPollerOldSessionStateActive, - NfcPollerOldSessionStateStopRequest, -} NfcPollerOldSessionState; - -struct NfcPollerOld { - Nfc* nfc; - NfcPollerOldSessionState session_state; - NfcaPoller* nfca_poller; - NfcaData nfca_data; - NfcbPoller* nfcb_poller; - NfcbData nfcb_data; - NfcPollerOldState state; - NfcPollerOldEventCallback callback; - void* context; -}; - -NfcPollerOld* nfc_poller_alloc(NfcPollerOldCollection* pollers) { - furi_assert(pollers); - furi_assert(pollers->nfc); - furi_assert(pollers->nfca_poller); - furi_assert(pollers->nfcb_poller); - - NfcPollerOld* instance = malloc(sizeof(NfcPollerOld)); - instance->nfc = pollers->nfc; - instance->nfca_poller = pollers->nfca_poller; - instance->nfcb_poller = pollers->nfcb_poller; - - return instance; -} - -void nfc_poller_free(NfcPollerOld* instance) { - furi_assert(instance); -} - -static NfcCommand nfc_poller_process_command(NfcPollerOldCommand command) { - NfcCommand ret = NfcCommandContinue; - - if(command == NfcPollerOldCommandContinue) { - ret = NfcCommandContinue; - } else if(command == NfcPollerOldCommandReset) { - ret = NfcCommandReset; - } else if(command == NfcPollerOldCommandStop) { - ret = NfcCommandStop; - } else { - furi_crash("Unknown command"); - } - - return ret; -} - -static NfcCommand nfc_poller_event_callback(NfcEvent event, void* context) { - furi_assert(context); - - NfcPollerOld* instance = context; - furi_assert(instance->callback); - furi_assert(instance->session_state != NfcPollerOldSessionStateIdle); - - NfcPollerOldEvent poller_event; - NfcPollerOldCommand command = NfcPollerOldCommandContinue; - - if(instance->session_state == NfcPollerOldSessionStateStopRequest) { - command = NfcPollerOldCommandStop; - } else { - if(event.type == NfcEventTypeConfigureRequest) { - if(instance->state == NfcPollerOldStateCheckPresenceNfca) { - nfca_poller_config(instance->nfca_poller); - } else if(instance->state == NfcPollerOldStateCheckPresenceNfcb) { - // nfcb_poller_config(instance->nfcb_poller); - } - } else if(event.type == NfcEventTypePollerReady) { - if(instance->state == NfcPollerOldStateCheckPresenceNfca) { - NfcaError error = - nfca_poller_async_activate(instance->nfca_poller, &instance->nfca_data); - if(error == NfcaErrorNone) { - if(mf_ultralight_detect_protocol(&instance->nfca_data)) { - poller_event = NfcPollerOldEventMfUltralightDetected; - } else { - poller_event = NfcPollerOldEventNfcaDetected; - } - command = instance->callback(poller_event, instance->context); - } else { - // Nfca not present - FURI_LOG_E("TAG", "NOT PRESENT"); - furi_delay_ms(100); - instance->state = NfcPollerOldStateCheckPresenceNfcb; - command = NfcPollerOldCommandReset; - } - } else if(instance->state == NfcPollerOldStateCheckPresenceNfcb) { - // NfcbError error = - // nfcb_poller_activate(instance->nfcb_poller, &instance->nfcb_data); - // if(error == NfcbErrorNone) { - // poller_event = NfcPollerOldEventNfcbDetected; - // instance->callback(poller_event, instance->context); - // } else { - // // Nfcb not present - // furi_delay_ms(100); - instance->state = NfcPollerOldStateCheckPresenceNfca; - // command = NfcCommandReset; - // } - } - } else if(event.type == NfcEventTypeReset) { - if(instance->state == NfcPollerOldStateCheckPresenceNfca) { - nfca_poller_reset(instance->nfca_poller); - } else if(instance->state == NfcPollerOldStateCheckPresenceNfcb) { - // nfcb_poller_reset(instance->nfcb_poller); - } - } - } - - return nfc_poller_process_command(command); -} - -void nfc_poller_start(NfcPollerOld* instance, NfcPollerOldEventCallback callback, void* context) { - furi_assert(instance); - furi_assert(callback); - furi_assert(instance->session_state == NfcPollerOldSessionStateIdle); - - instance->callback = callback; - instance->context = context; - instance->state = NfcPollerOldStateCheckPresenceNfca; - instance->session_state = NfcPollerOldSessionStateActive; - - instance->nfca_poller->data = malloc(sizeof(NfcaData)); - - nfc_start_poller(instance->nfc, nfc_poller_event_callback, instance); -} - -void nfc_poller_stop(NfcPollerOld* instance) { - furi_assert(instance); - furi_assert(instance->nfc); - - instance->session_state = NfcPollerOldSessionStateStopRequest; - nfc_stop(instance->nfc); - instance->session_state = NfcPollerOldSessionStateIdle; - - free(instance->nfca_poller->data); - - instance->callback = NULL; - instance->context = NULL; - instance->state = NfcPollerOldStateIdle; -} diff --git a/lib/nfc/nfc_poller.h b/lib/nfc/nfc_poller.h deleted file mode 100644 index 9b2eac3abf82..000000000000 --- a/lib/nfc/nfc_poller.h +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -#include -#include -#include - -typedef struct NfcPollerOld NfcPollerOld; - -typedef struct { - Nfc* nfc; - NfcaPoller* nfca_poller; - NfcbPoller* nfcb_poller; - MfUltralightPoller* mfu_poller; - MfClassicPoller* mfc_poller; -} NfcPollerOldCollection; - -typedef enum { - NfcPollerOldEventNfcaDetected, - NfcPollerOldEventNfcbDetected, - NfcPollerOldEventNfcfDetected, - NfcPollerOldEventNfcvDetected, - NfcPollerOldEventMfUltralightDetected, - NfcPollerOldEventMfClassicDetected, - NfcPollerOldEventMfDesfireDetected, -} NfcPollerOldEvent; - -typedef enum { - NfcPollerOldCommandContinue = NfcCommandContinue, - NfcPollerOldCommandReset = NfcCommandReset, - NfcPollerOldCommandStop = NfcCommandStop, -} NfcPollerOldCommand; - -typedef NfcPollerOldCommand (*NfcPollerOldEventCallback)(NfcPollerOldEvent event, void* context); - -NfcPollerOld* nfc_poller_alloc(NfcPollerOldCollection* pollers); - -void nfc_poller_free(NfcPollerOld* instance); - -void nfc_poller_start(NfcPollerOld* instance, NfcPollerOldEventCallback callback, void* context); - -void nfc_poller_stop(NfcPollerOld* instance); - -#ifdef __cplusplus -} -#endif diff --git a/lib/nfc/nfc_poller_manager.c b/lib/nfc/nfc_poller_manager.c index a6d3dd393dae..7ba01a362cff 100644 --- a/lib/nfc/nfc_poller_manager.c +++ b/lib/nfc/nfc_poller_manager.c @@ -1,11 +1,9 @@ #include "nfc_poller_manager.h" -#include "nfc_poller_defs.h" +#include #include -#include "nfc.h" - typedef enum { NfcPollerManagerStateIdle, @@ -34,14 +32,7 @@ struct NfcPollerManager { NfcPollerManagerState state; NfcPollerManagerSessionState session_state; - size_t base_protocol_current; - size_t base_protocol_total; NfcEvent* event; - - NfcPollerBase* current_poller_base; - NfcPoller* current_poller; - NfcPoller* base_poller; - NfcPollerList* list; NfcProtocolType protocol; @@ -66,57 +57,6 @@ void nfc_poller_manager_free(NfcPollerManager* instance) { free(instance); } -// typedef NfcCommand (*NfcPollerManagerHandler)(NfcPollerManager* instance); - -// NfcCommand nfc_poller_manager_handler_idle(NfcPollerManager* instance) { -// NfcCommand command = NfcCommandContinue; - -// instance->base_protocol_total = COUNT_OF(nfc_poller_base_type); -// instance->base_protocol_current = 0; - -// return command; -// } - -// static const NfcPollerManagerHandler nfc_poller_manager_handler[NfcPollerManagerStateNum] = { -// [NfcPollerManagerStateIdle] = nfc_poller_manager_handler_idle, -// }; - -// static NfcCommand nfc_poller_manager_scan_event_callback(NfcEvent event, void* context) { -// furi_assert(context); - -// NfcPollerManager* instance = context; -// furi_assert(instance->callback); - -// NfcPollerEvent poller_event; -// NfcPollerCommand command = NfcPollerCommandContinue; - -// if(instance->session_state == NfcPollerManagerSessionStateStopRequest) { -// command = NfcPollerCommandStop; -// } else { -// if(event.type == NfcEventTypeConfigureRequest) { -// instance->current_poller = instance->current_poller_base->alloc(instance->base_poller); -// } else if(event.type == NfcEventTypePollerReady) { -// command = instance->current_poller_base->run(instance->current_poller); -// } else if(event.type == NfcEventTypeReset) { -// instance->current_poller_base->free(instance->current_poller); -// } -// } - -// return nfc_poller_manager_process_command(command); -// } - -// void nfc_poller_manager_scan(NfcPollerManager* instance, NfcPollerCallback callback, void* context) { -// furi_assert(instance); -// furi_assert(callback); -// furi_assert(instance->session_state == NfcPollerManagerSessionStateIdle); - -// instance->callback = callback; -// instance->context = context; -// instance->session_state = NfcPollerManagerSessionStateActive; - -// nfc_start_poller(instance->nfc, nfc_poller_manager_scan_event_callback, instance); -// } - static void nfc_poller_manager_poller_list_alloc(NfcPollerManager* instance) { furi_assert(instance->list == NULL); @@ -155,15 +95,13 @@ static void nfc_poller_manager_poller_list_alloc(NfcPollerManager* instance) { static void nfc_poller_manager_poller_list_free(NfcPollerManager* instance) { do { - NfcPollerListElement* child = instance->list->head->child; - if(child == NULL) break; - instance->list->head->poller_api->free(instance->list->head->poller); + NfcPollerListElement* child = instance->list->head->child; free(instance->list->head); + if(child == NULL) break; instance->list->head = child; } while(true); - free(instance->list->head); free(instance->list); instance->list = NULL; } @@ -180,19 +118,19 @@ static NfcCommand nfc_poller_manager_start_event_callback(NfcEvent event, void* .poller = instance->nfc, }; + if(event.type == NfcEventTypeConfigureRequest) { + nfc_poller_manager_poller_list_alloc(instance); + } else if(event.type == NfcEventTypePollerReady) { + *instance->event = event; + poller_manager_event.data = instance->event; + NfcPollerListElement* head = instance->list->head; + command = head->poller_api->run(poller_manager_event, head->poller); + } else if(event.type == NfcEventTypeReset) { + nfc_poller_manager_poller_list_free(instance); + } + if(instance->session_state == NfcPollerManagerSessionStateStopRequest) { command = NfcCommandStop; - } else { - if(event.type == NfcEventTypeConfigureRequest) { - nfc_poller_manager_poller_list_alloc(instance); - } else if(event.type == NfcEventTypePollerReady) { - *instance->event = event; - poller_manager_event.data = instance->event; - NfcPollerListElement* head = instance->list->head; - command = head->poller_api->run(poller_manager_event, head->poller); - } else if(event.type == NfcEventTypeReset) { - nfc_poller_manager_poller_list_free(instance); - } } return command; diff --git a/lib/nfc/nfc_poller_manager.h b/lib/nfc/nfc_poller_manager.h index 94749f4281b4..66d54e940256 100644 --- a/lib/nfc/nfc_poller_manager.h +++ b/lib/nfc/nfc_poller_manager.h @@ -4,7 +4,7 @@ extern "C" { #endif -#include "nfc_poller_base.h" +#include typedef struct NfcPollerManager NfcPollerManager; @@ -12,8 +12,6 @@ NfcPollerManager* nfc_poller_manager_alloc(Nfc* nfc); void nfc_poller_manager_free(NfcPollerManager* instance); -void nfc_poller_manager_scan(NfcPollerManager* instance, NfcPollerCallback callback, void* context); - void nfc_poller_manager_start( NfcPollerManager* instance, NfcProtocolType protocol, diff --git a/lib/nfc/nfc_scanner.c b/lib/nfc/nfc_scanner.c new file mode 100644 index 000000000000..e955ca6b49b1 --- /dev/null +++ b/lib/nfc/nfc_scanner.c @@ -0,0 +1,325 @@ +#include "nfc_scanner.h" +#include "nfc_poller_manager.h" + +#include + +#include + +#define TAG "NfcScanner" + +#define NFC_SCANNER_POLLER_MANAGER_COMPLETE_EVENT (1UL << 0) + +typedef enum { + NfcScannerStateIdle, + NfcScannerStateTryBasePollers, + NfcScannerStateFindChildrenProtocols, + NfcScannerStateDetectChildrenProtocols, + // TODO add state to retry base pollers after children pollers detection + NfcScannerStateComplete, + + NfcScannerStateNum, +} NfcScannerState; + +typedef enum { + NfcScannerSessionStateIdle, + NfcScannerSessionStateActive, + NfcScannerSessionStateStopRequest, +} NfcScannerSessionState; + +struct NfcScanner { + Nfc* nfc; + NfcPollerManager* poller_manager; + NfcScannerState state; + NfcScannerSessionState session_state; + + NfcScannerCallback callback; + void* context; + + NfcEvent nfc_event; + + size_t base_protocols_num; + size_t base_protocols_idx; + NfcProtocolType base_protocols[NfcProtocolTypeMax]; + + size_t children_protocols_num; + size_t children_protocols_idx; + NfcProtocolType children_protocols[NfcProtocolTypeMax]; + + size_t detected_protocols_num; + NfcProtocolType detected_protocols[NfcProtocolTypeMax]; + + NfcProtocolType current_protocol; + NfcPoller* current_poller; + + FuriThread* scan_worker; +}; + +static void nfc_scanner_reset(NfcScanner* instance) { + instance->base_protocols_idx = 0; + instance->base_protocols_num = 0; + + instance->children_protocols_idx = 0; + instance->children_protocols_num = 0; + + instance->detected_protocols_num = 0; + + instance->current_protocol = 0; +} + +typedef void (*NfcScannerStateHandler)(NfcScanner* instance); + +void nfc_scanner_state_handler_idle(NfcScanner* instance) { + for(size_t i = 0; i < NfcProtocolTypeMax; i++) { + if(nfc_poller_nodes[i].parent_protocol == NfcProtocolTypeInvalid) { + instance->base_protocols[instance->base_protocols_num] = i; + instance->base_protocols_num++; + } + } + instance->base_protocols_idx = 0; + FURI_LOG_D(TAG, "Found %d base protocols", instance->base_protocols_num); + + instance->state = NfcScannerStateTryBasePollers; +} + +static NfcCommand nfc_scanner_base_poller_detect_callback(NfcEvent event, void* context) { + furi_assert(context); + + NfcScanner* instance = context; + + NfcCommand command = NfcCommandContinue; + instance->nfc_event = event; + NfcPollerEvent scanner_event = { + .protocol_type = NfcProtocolTypeInvalid, + .poller = instance->nfc, + .data = &instance->nfc_event, + }; + const NfcPollerBase* current_poller_api = nfc_pollers_api[instance->current_protocol]; + + if(event.type == NfcEventTypeConfigureRequest) { + instance->current_poller = current_poller_api->alloc(instance->nfc); + } else if(event.type == NfcEventTypePollerReady) { + bool protocol_detected = + current_poller_api->detect(scanner_event, instance->current_poller); + if(protocol_detected) { + instance->detected_protocols[instance->detected_protocols_num] = + instance->current_protocol; + instance->detected_protocols_num++; + } + command = NfcCommandStop; + } else if(event.type == NfcEventTypeReset) { + current_poller_api->free(instance->current_poller); + } + + return command; +} + +void nfc_scanner_state_handler_try_base_pollers(NfcScanner* instance) { + instance->current_protocol = instance->base_protocols[instance->base_protocols_idx]; + + nfc_start_poller(instance->nfc, nfc_scanner_base_poller_detect_callback, instance); + nfc_stop(instance->nfc); + + if(instance->detected_protocols_num > 0) { + instance->state = NfcScannerStateFindChildrenProtocols; + } else { + instance->base_protocols_idx = + (instance->base_protocols_idx + 1) % instance->base_protocols_num; + } +} + +static bool nfc_scanner_check_parent_protocol(NfcProtocolType child, NfcProtocolType parent) { + bool parent_found = false; + + const NfcPollerTreeNode* iter = &nfc_poller_nodes[child]; + while(iter->parent_protocol != NfcProtocolTypeInvalid) { + if(iter->parent_protocol == parent) { + parent_found = true; + break; + } + iter = &nfc_poller_nodes[iter->parent_protocol]; + } + + return parent_found; +} + +void nfc_scanner_state_handler_find_children_protocols(NfcScanner* instance) { + for(size_t i = 0; i < NfcProtocolTypeMax; i++) { + if(nfc_scanner_check_parent_protocol(i, instance->current_protocol)) { + instance->children_protocols[instance->children_protocols_num] = i; + instance->children_protocols_num++; + } + } + + if(instance->children_protocols_num > 0) { + instance->state = NfcScannerStateDetectChildrenProtocols; + } else { + instance->state = NfcScannerStateComplete; + } + FURI_LOG_D(TAG, "Found %d children", instance->children_protocols_num); +} + +static NfcCommand nfc_scanner_detect_child_protocol_callback(NfcPollerEvent event, void* context) { + furi_assert(context); + furi_assert(event.poller); + + bool protocol_detected = false; + NfcScanner* instance = context; + const NfcPollerBase* current_poller_api = nfc_pollers_api[instance->current_protocol]; + + if(current_poller_api) { + instance->current_poller = current_poller_api->alloc(event.poller); + protocol_detected = current_poller_api->detect(event, instance->current_poller); + current_poller_api->free(instance->current_poller); + } + + if(protocol_detected) { + instance->detected_protocols[instance->detected_protocols_num] = + instance->current_protocol; + instance->detected_protocols_num++; + } + + // Notify scan worker that detection is complete + FuriThreadId scan_worker_thread_id = furi_thread_get_id(instance->scan_worker); + furi_thread_flags_set(scan_worker_thread_id, NFC_SCANNER_POLLER_MANAGER_COMPLETE_EVENT); + + return NfcCommandStop; +} + +void nfc_scanner_state_handler_detect_children_protocols(NfcScanner* instance) { + furi_assert(instance->children_protocols_num); + + instance->current_protocol = instance->children_protocols[instance->children_protocols_idx]; + NfcProtocolType parent_protocol = nfc_poller_nodes[instance->current_protocol].parent_protocol; + + nfc_poller_manager_start( + instance->poller_manager, + parent_protocol, + nfc_scanner_detect_child_protocol_callback, + instance); + + // Wait until detection is complete + furi_thread_flags_wait( + NFC_SCANNER_POLLER_MANAGER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); + furi_thread_flags_clear(NFC_SCANNER_POLLER_MANAGER_COMPLETE_EVENT); + nfc_poller_manager_stop(instance->poller_manager); + + instance->children_protocols_idx++; + if(instance->children_protocols_idx == instance->children_protocols_num) { + instance->state = NfcScannerStateComplete; + } +} + +static void nfc_scanner_filter_detected_protocols(NfcScanner* instance) { + size_t filtered_protocols_num = 0; + NfcProtocolType filtered_protocols[NfcProtocolTypeMax] = {}; + + for(size_t i = 0; i < instance->detected_protocols_num; i++) { + bool is_parent = false; + for(size_t j = i; j < instance->detected_protocols_num; j++) { + is_parent = nfc_scanner_check_parent_protocol( + instance->detected_protocols[j], instance->detected_protocols[i]); + if(is_parent) break; + } + if(!is_parent) { + filtered_protocols[filtered_protocols_num] = instance->detected_protocols[i]; + filtered_protocols_num++; + } + } + + instance->detected_protocols_num = filtered_protocols_num; + memcpy(instance->detected_protocols, filtered_protocols, filtered_protocols_num); +} + +void nfc_scanner_state_handler_complete(NfcScanner* instance) { + if(instance->detected_protocols_num > 1) { + nfc_scanner_filter_detected_protocols(instance); + } + FURI_LOG_I(TAG, "Detected %d protocols", instance->detected_protocols_num); + + NfcScannerEvent event = { + .type = NfcScannerEventTypeDetected, + .data = + { + .protocol_num = instance->detected_protocols_num, + .protocols = instance->detected_protocols, + }, + }; + + instance->callback(event, instance->context); + furi_delay_ms(100); +} + +static NfcScannerStateHandler nfc_scanner_state_handlers[NfcScannerStateNum] = { + [NfcScannerStateIdle] = nfc_scanner_state_handler_idle, + [NfcScannerStateTryBasePollers] = nfc_scanner_state_handler_try_base_pollers, + [NfcScannerStateFindChildrenProtocols] = nfc_scanner_state_handler_find_children_protocols, + [NfcScannerStateDetectChildrenProtocols] = nfc_scanner_state_handler_detect_children_protocols, + [NfcScannerStateComplete] = nfc_scanner_state_handler_complete, +}; + +static int32_t nfc_scanner_worker(void* context) { + furi_assert(context); + + NfcScanner* instance = context; + furi_assert(instance->poller_manager); + + while(instance->session_state == NfcScannerSessionStateActive) { + nfc_scanner_state_handlers[instance->state](instance); + } + + nfc_scanner_reset(instance); + + return 0; +} + +NfcScanner* nfc_scanner_alloc(Nfc* nfc) { + furi_assert(nfc); + + NfcScanner* instance = malloc(sizeof(NfcScanner)); + instance->nfc = nfc; + instance->poller_manager = nfc_poller_manager_alloc(instance->nfc); + + return instance; +} + +void nfc_scanner_free(NfcScanner* instance) { + furi_assert(instance); + furi_assert(instance->poller_manager); + + nfc_poller_manager_free(instance->poller_manager); + free(instance); +} + +void nfc_scanner_start(NfcScanner* instance, NfcScannerCallback callback, void* context) { + furi_assert(instance); + furi_assert(callback); + furi_assert(instance->session_state == NfcScannerSessionStateIdle); + furi_assert(instance->scan_worker == NULL); + + instance->callback = callback; + instance->context = context; + instance->session_state = NfcScannerSessionStateActive; + + instance->scan_worker = furi_thread_alloc(); + furi_thread_set_name(instance->scan_worker, "NfcScanWorker"); + furi_thread_set_context(instance->scan_worker, instance); + furi_thread_set_stack_size(instance->scan_worker, 4 * 1024); + furi_thread_set_callback(instance->scan_worker, nfc_scanner_worker); + + furi_thread_start(instance->scan_worker); +} + +void nfc_scanner_stop(NfcScanner* instance) { + furi_assert(instance); + furi_assert(instance->scan_worker); + + instance->session_state = NfcScannerSessionStateStopRequest; + furi_thread_join(instance->scan_worker); + instance->session_state = NfcScannerSessionStateIdle; + + furi_thread_free(instance->scan_worker); + instance->scan_worker = NULL; + instance->callback = NULL; + instance->context = NULL; + instance->state = NfcScannerStateIdle; +} diff --git a/lib/nfc/nfc_scanner.h b/lib/nfc/nfc_scanner.h new file mode 100644 index 000000000000..9d01fe25c303 --- /dev/null +++ b/lib/nfc/nfc_scanner.h @@ -0,0 +1,38 @@ +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct NfcScanner NfcScanner; + +typedef enum { + NfcScannerEventTypeDetected, +} NfcScannerEventType; + +typedef struct { + size_t protocol_num; + NfcProtocolType* protocols; +} NfcScannerEventData; + +typedef struct { + NfcScannerEventType type; + NfcScannerEventData data; +} NfcScannerEvent; + +typedef void (*NfcScannerCallback)(NfcScannerEvent event, void* context); + +NfcScanner* nfc_scanner_alloc(Nfc* nfc); + +void nfc_scanner_free(NfcScanner* instance); + +void nfc_scanner_start(NfcScanner* instance, NfcScannerCallback callback, void* context); + +void nfc_scanner_stop(NfcScanner* instance); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a.c b/lib/nfc/protocols/iso14443_4a/iso14443_4a.c index 0776a5c8778c..472c5b5fd690 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a.c +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a.c @@ -2,10 +2,12 @@ #include -#define ISO14443_4A_PROTOCOL_NAME "Unknown ISO14443-4A Tag" +#define ISO14443_4A_PROTOCOL_NAME "ISO14443-4A" +#define ISO14443_4A_DEVICE_NAME "Unknown ISO14443-4A Tag" #define ISO14443_4A_ATS_BIT (1 << 5) const NfcProtocolBase nfc_protocol_iso14443_4a = { + .protocol_name = ISO14443_4A_PROTOCOL_NAME, .alloc = (NfcProtocolAlloc)iso14443_4a_alloc, .free = (NfcProtocolFree)iso14443_4a_free, .reset = (NfcProtocolReset)iso14443_4a_reset, @@ -14,7 +16,7 @@ const NfcProtocolBase nfc_protocol_iso14443_4a = { .load = (NfcProtocolLoad)iso14443_4a_load, .save = (NfcProtocolSave)iso14443_4a_save, .is_equal = (NfcProtocolEqual)iso14443_4a_is_equal, - .get_name = (NfcProtocolGetName)iso14443_4a_get_name, + .get_device_name = (NfcProtocolGetDeviceName)iso14443_4a_get_device_name, .get_uid = (NfcProtocolGetUid)iso14443_4a_get_uid, }; @@ -76,10 +78,11 @@ bool iso14443_4a_is_equal(const Iso14443_4aData* data, const Iso14443_4aData* ot return nfca_is_equal(data->iso14443_3a_data, other->iso14443_3a_data); } -const char* iso14443_4a_get_name(const Iso14443_4aData* data, NfcProtocolNameType name_type) { +const char* + iso14443_4a_get_device_name(const Iso14443_4aData* data, NfcProtocolNameType name_type) { UNUSED(data); UNUSED(name_type); - return ISO14443_4A_PROTOCOL_NAME; + return ISO14443_4A_DEVICE_NAME; } const uint8_t* iso14443_4a_get_uid(const Iso14443_4aData* data, size_t* uid_len) { diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a.h b/lib/nfc/protocols/iso14443_4a/iso14443_4a.h index 91ee64490438..51e8e8f54dd9 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a.h +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a.h @@ -49,7 +49,8 @@ bool iso14443_4a_save(const Iso14443_4aData* data, FlipperFormat* ff, uint32_t v bool iso14443_4a_is_equal(const Iso14443_4aData* data, const Iso14443_4aData* other); -const char* iso14443_4a_get_name(const Iso14443_4aData* data, NfcProtocolNameType name_type); +const char* + iso14443_4a_get_device_name(const Iso14443_4aData* data, NfcProtocolNameType name_type); const uint8_t* iso14443_4a_get_uid(const Iso14443_4aData* data, size_t* uid_len); diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_i.c b/lib/nfc/protocols/iso14443_4a/iso14443_4a_i.c index cb434cf18f7b..12222d40bbf2 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_i.c +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_i.c @@ -1,7 +1,8 @@ #include "iso14443_4a_i.h" bool iso14443_4a_ats_parse(Iso14443_4aAtsData* data, const BitBuffer* buf) { - const bool can_parse = bit_buffer_get_size_bytes(buf) >= sizeof(Iso14443_4aAtsData); + // TODO better check + const bool can_parse = bit_buffer_get_size_bytes(buf) == sizeof(Iso14443_4aAtsData); if(can_parse) { bit_buffer_write_bytes(buf, data, sizeof(Iso14443_4aAtsData)); } diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.c b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.c index 65590b01cf39..0c83100d3eef 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.c +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.c @@ -32,7 +32,6 @@ static Iso14443_4aPoller* iso14443_4a_poller_alloc(NfcaPoller* iso14443_3a_polle static void iso14443_4a_poller_free(Iso14443_4aPoller* instance) { furi_assert(instance); - furi_assert(instance->poller_state == Iso14443_4aPollerStateIdle); iso14443_4a_free(instance->data); bit_buffer_free(instance->tx_buffer); @@ -126,6 +125,8 @@ static bool iso14443_4a_poller_detect(NfcPollerEvent event, void* context) { const NfcaPollerEvent* iso14443_3a_event = event.data; furi_assert(iso14443_3a_event); + nfca_copy( + instance->data->iso14443_3a_data, nfca_poller_get_data(instance->iso14443_3a_poller)); bool protocol_detected = false; diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_defs.h b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_defs.h index 645216a73f64..aa62166742bf 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_defs.h +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_defs.h @@ -1,5 +1,5 @@ #pragma once -#include +#include extern const NfcPollerBase nfc_poller_iso14443_4a; diff --git a/lib/nfc/protocols/mf_classic/mf_classic.c b/lib/nfc/protocols/mf_classic/mf_classic.c index 83c801d198bc..fc2fa39a9cac 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic.c +++ b/lib/nfc/protocols/mf_classic/mf_classic.c @@ -5,6 +5,8 @@ #include +#define MF_CLASSIC_PROTOCOL_NAME "Mifare Classic" + typedef struct { uint8_t sectors_total; uint16_t blocks_total; @@ -39,6 +41,7 @@ static const MfClassicFeatures mf_classic_features[MfClassicTypeNum] = { }; const NfcProtocolBase nfc_protocol_mf_classic = { + .protocol_name = MF_CLASSIC_PROTOCOL_NAME, .alloc = (NfcProtocolAlloc)mf_classic_alloc, .free = (NfcProtocolFree)mf_classic_free, .reset = (NfcProtocolReset)mf_classic_reset, @@ -47,7 +50,7 @@ const NfcProtocolBase nfc_protocol_mf_classic = { .load = (NfcProtocolLoad)mf_classic_load, .save = (NfcProtocolSave)mf_classic_save, .is_equal = (NfcProtocolEqual)mf_classic_is_equal, - .get_name = (NfcProtocolGetName)mf_classic_get_name, + .get_device_name = (NfcProtocolGetDeviceName)mf_classic_get_device_name, .get_uid = (NfcProtocolGetUid)mf_classic_get_uid, }; @@ -293,7 +296,7 @@ bool mf_classic_is_equal(const MfClassicData* data, const MfClassicData* other) return nfca_is_equal(data->nfca_data, other->nfca_data); } -const char* mf_classic_get_name(const MfClassicData* data, NfcProtocolNameType name_type) { +const char* mf_classic_get_device_name(const MfClassicData* data, NfcProtocolNameType name_type) { furi_assert(data); furi_assert(data->type < MfClassicTypeNum); diff --git a/lib/nfc/protocols/mf_classic/mf_classic.h b/lib/nfc/protocols/mf_classic/mf_classic.h index 050bdb26dad7..01ae04f2b778 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic.h +++ b/lib/nfc/protocols/mf_classic/mf_classic.h @@ -137,7 +137,7 @@ bool mf_classic_save(const MfClassicData* data, FlipperFormat* ff, uint32_t vers bool mf_classic_is_equal(const MfClassicData* data, const MfClassicData* other); -const char* mf_classic_get_name(const MfClassicData* data, NfcProtocolNameType name_type); +const char* mf_classic_get_device_name(const MfClassicData* data, NfcProtocolNameType name_type); const uint8_t* mf_classic_get_uid(const MfClassicData* data, size_t* uid_len); diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire.c b/lib/nfc/protocols/mf_desfire/mf_desfire.c index 92cd638b3910..ede0f2e266dc 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire.c +++ b/lib/nfc/protocols/mf_desfire/mf_desfire.c @@ -3,8 +3,10 @@ #include #define MF_DESFIRE_PROTOCOL_NAME "Mifare DESfire" +#define MF_DESFIRE_DEVICE_NAME "Mifare DESfire" const NfcProtocolBase nfc_protocol_mf_desfire = { + .protocol_name = MF_DESFIRE_PROTOCOL_NAME, .alloc = (NfcProtocolAlloc)mf_desfire_alloc, .free = (NfcProtocolFree)mf_desfire_free, .reset = (NfcProtocolReset)mf_desfire_reset, @@ -13,7 +15,7 @@ const NfcProtocolBase nfc_protocol_mf_desfire = { .load = (NfcProtocolLoad)mf_desfire_load, .save = (NfcProtocolSave)mf_desfire_save, .is_equal = (NfcProtocolEqual)mf_desfire_is_equal, - .get_name = (NfcProtocolGetName)mf_desfire_get_name, + .get_device_name = (NfcProtocolGetDeviceName)mf_desfire_get_device_name, .get_uid = (NfcProtocolGetUid)mf_desfire_get_uid, }; @@ -99,10 +101,10 @@ bool mf_desfire_is_equal(const MfDesfireData* data, const MfDesfireData* other) return iso14443_4a_is_equal(data->iso14443_4a_data, other->iso14443_4a_data); } -const char* mf_desfire_get_name(const MfDesfireData* data, NfcProtocolNameType name_type) { +const char* mf_desfire_get_device_name(const MfDesfireData* data, NfcProtocolNameType name_type) { UNUSED(data); UNUSED(name_type); - return MF_DESFIRE_PROTOCOL_NAME; + return MF_DESFIRE_DEVICE_NAME; } const uint8_t* mf_desfire_get_uid(const MfDesfireData* data, size_t* uid_len) { diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire.h b/lib/nfc/protocols/mf_desfire/mf_desfire.h index 273b953b8e5a..902444d1fb15 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire.h +++ b/lib/nfc/protocols/mf_desfire/mf_desfire.h @@ -165,7 +165,7 @@ bool mf_desfire_save(const MfDesfireData* data, FlipperFormat* ff, uint32_t vers bool mf_desfire_is_equal(const MfDesfireData* data, const MfDesfireData* other); -const char* mf_desfire_get_name(const MfDesfireData* data, NfcProtocolNameType name_type); +const char* mf_desfire_get_device_name(const MfDesfireData* data, NfcProtocolNameType name_type); const uint8_t* mf_desfire_get_uid(const MfDesfireData* data, size_t* uid_len); diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_poller_defs.h b/lib/nfc/protocols/mf_desfire/mf_desfire_poller_defs.h index 07a8ca05768f..0c14ceee4d89 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_poller_defs.h +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_poller_defs.h @@ -1,5 +1,5 @@ #pragma once -#include +#include extern const NfcPollerBase mf_desfire_poller; diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight.c index eb9978510cb6..7c1fb2393d05 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight.c @@ -2,6 +2,8 @@ #include +#define MF_ULTRALIGHT_PROTOCOL_NAME "NTAG/Ultralight" + typedef struct { uint16_t total_pages; uint16_t config_page; @@ -116,6 +118,7 @@ static const MfUltralightFeatures mf_ultralight_features[MfUltralightTypeNum] = }; const NfcProtocolBase nfc_protocol_mf_ultralight = { + .protocol_name = MF_ULTRALIGHT_PROTOCOL_NAME, .alloc = (NfcProtocolAlloc)mf_ultralight_alloc, .free = (NfcProtocolFree)mf_ultralight_free, .reset = (NfcProtocolReset)mf_ultralight_reset, @@ -124,7 +127,7 @@ const NfcProtocolBase nfc_protocol_mf_ultralight = { .load = (NfcProtocolLoad)mf_ultralight_load, .save = (NfcProtocolSave)mf_ultralight_save, .is_equal = (NfcProtocolEqual)mf_ultralight_is_equal, - .get_name = (NfcProtocolGetName)mf_ultralight_get_name, + .get_device_name = (NfcProtocolGetDeviceName)mf_ultralight_get_device_name, .get_uid = (NfcProtocolGetUid)mf_ultralight_get_uid, }; @@ -166,7 +169,7 @@ void mf_ultralight_copy(MfUltralightData* data, const MfUltralightData* other) { } // TODO: Improve this function -static const char* mf_ultralight_get_name_by_type(MfUltralightType type, bool full_name) { +static const char* mf_ultralight_get_device_name_by_type(MfUltralightType type, bool full_name) { // FIXME: Use a LUT instead of if/switch if(type == MfUltralightTypeNTAG213) { return "NTAG213"; @@ -199,7 +202,7 @@ bool mf_ultralight_verify(MfUltralightData* data, const FuriString* device_type) bool verified = false; for(MfUltralightType i = 0; i < MfUltralightTypeNum; i++) { - const char* name = mf_ultralight_get_name_by_type(i, true); + const char* name = mf_ultralight_get_device_name_by_type(i, true); verified = furi_string_equal_str(device_type, name); if(verified) { data->type = i; @@ -302,7 +305,7 @@ bool mf_ultralight_save(const MfUltralightData* data, FlipperFormat* ff, uint32_ bool saved = false; do { - const char* device_type_name = mf_ultralight_get_name_by_type(data->type, true); + const char* device_type_name = mf_ultralight_get_device_name_by_type(data->type, true); if(!flipper_format_write_string_cstr(ff, "Device type", device_type_name)) break; if(!nfca_save_data(data->nfca_data, ff, version)) break; if(!flipper_format_write_comment_cstr(ff, "Mifare Ultralight specific data")) break; @@ -372,11 +375,12 @@ bool mf_ultralight_is_equal(const MfUltralightData* data, const MfUltralightData } // TODO: Improve this function -const char* mf_ultralight_get_name(const MfUltralightData* data, NfcProtocolNameType name_type) { +const char* + mf_ultralight_get_device_name(const MfUltralightData* data, NfcProtocolNameType name_type) { furi_assert(data); furi_assert(data->type < MfUltralightTypeNum); - return mf_ultralight_get_name_by_type(data->type, name_type == NfcProtocolNameTypeFull); + return mf_ultralight_get_device_name_by_type(data->type, name_type == NfcProtocolNameTypeFull); } const uint8_t* mf_ultralight_get_uid(const MfUltralightData* data, size_t* uid_len) { diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h index 7a875eb3c4d7..f7bbbf64ab08 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h @@ -183,7 +183,8 @@ bool mf_ultralight_save(const MfUltralightData* data, FlipperFormat* ff, uint32_ bool mf_ultralight_is_equal(const MfUltralightData* data, const MfUltralightData* other); -const char* mf_ultralight_get_name(const MfUltralightData* data, NfcProtocolNameType name_type); +const char* + mf_ultralight_get_device_name(const MfUltralightData* data, NfcProtocolNameType name_type); const uint8_t* mf_ultralight_get_uid(const MfUltralightData* data, size_t* uid_len); diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c index c89ca0cb7778..cb14acba8c04 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c @@ -98,7 +98,7 @@ static MfUltralightPollerCommand FURI_LOG_D( TAG, "%s detected. Total pages: %d", - mf_ultralight_get_name(instance->data, NfcProtocolNameTypeFull), + mf_ultralight_get_device_name(instance->data, NfcProtocolNameTypeFull), instance->pages_total); instance->state = MfUltralightPollerStateReadSignature; diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_defs.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_defs.h index d4d7e719f967..80b0d7b6eaa9 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_defs.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_defs.h @@ -1,5 +1,5 @@ #pragma once -#include +#include extern const NfcPollerBase mf_ultralight_poller; diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c index a1c8ed9bf1a0..1838a272b282 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c @@ -545,7 +545,7 @@ static NfcCommand mf_ultralight_poller_handler_get_feature_set(MfUltralightPolle FURI_LOG_D( TAG, "%s detected. Total pages: %d", - mf_ultralight_get_name(instance->data, NfcProtocolNameTypeFull), + mf_ultralight_get_device_name(instance->data, NfcProtocolNameTypeFull), instance->pages_total); instance->state = MfUltralightPollerStateReadSignature; @@ -805,9 +805,11 @@ static bool mf_ultralight_poller_detect(NfcPollerEvent event, void* context) { NfcaPollerEvent* nfca_event = event.data; if(nfca_event->type == NfcaPollerEventTypeReady) { - MfUltralightPage page = {}; - MfUltralightError error = mf_ultralight_poller_read_page(instance, 0, &page); + MfUltralightPageReadCommandData read_page_cmd_data = {}; + MfUltralightError error = + mf_ultralight_poller_async_read_page(instance, 0, &read_page_cmd_data); protocol_detected = (error == MfUltralightErrorNone); + nfca_poller_halt(instance->nfca_poller); } return protocol_detected; diff --git a/lib/nfc/nfc_poller_base.h b/lib/nfc/protocols/nfc_poller_base.h similarity index 96% rename from lib/nfc/nfc_poller_base.h rename to lib/nfc/protocols/nfc_poller_base.h index 32d2424ab53b..6cf5f127263b 100644 --- a/lib/nfc/nfc_poller_base.h +++ b/lib/nfc/protocols/nfc_poller_base.h @@ -1,6 +1,6 @@ #pragma once -#include "protocols/nfc_protocol_defs.h" +#include "nfc_protocol_defs.h" #include "nfc.h" #ifdef __cplusplus diff --git a/lib/nfc/nfc_poller_defs.c b/lib/nfc/protocols/nfc_poller_defs.c similarity index 100% rename from lib/nfc/nfc_poller_defs.c rename to lib/nfc/protocols/nfc_poller_defs.c diff --git a/lib/nfc/nfc_poller_defs.h b/lib/nfc/protocols/nfc_poller_defs.h similarity index 100% rename from lib/nfc/nfc_poller_defs.h rename to lib/nfc/protocols/nfc_poller_defs.h diff --git a/lib/nfc/protocols/nfc_protocol_base.h b/lib/nfc/protocols/nfc_protocol_base.h index d2bded0c7e84..575dbb4c4880 100644 --- a/lib/nfc/protocols/nfc_protocol_base.h +++ b/lib/nfc/protocols/nfc_protocol_base.h @@ -22,10 +22,11 @@ typedef bool (*NfcProtocolLoad)(NfcProtocolData* data, FlipperFormat* ff, uint32 typedef bool (*NfcProtocolSave)(const NfcProtocolData* data, FlipperFormat* ff, uint32_t version); typedef bool (*NfcProtocolEqual)(const NfcProtocolData* data, const NfcProtocolData* other); typedef const char* ( - *NfcProtocolGetName)(const NfcProtocolData* data, NfcProtocolNameType name_type); + *NfcProtocolGetDeviceName)(const NfcProtocolData* data, NfcProtocolNameType name_type); typedef const uint8_t* (*NfcProtocolGetUid)(const NfcProtocolData* data, size_t* uid_len); typedef struct { + const char* protocol_name; NfcProtocolAlloc alloc; NfcProtocolFree free; NfcProtocolReset reset; @@ -34,7 +35,7 @@ typedef struct { NfcProtocolLoad load; NfcProtocolSave save; NfcProtocolEqual is_equal; - NfcProtocolGetName get_name; + NfcProtocolGetDeviceName get_device_name; NfcProtocolGetUid get_uid; } NfcProtocolBase; diff --git a/lib/nfc/protocols/nfca/nfca.c b/lib/nfc/protocols/nfca/nfca.c index 938c9153da45..ad36700d59ac 100644 --- a/lib/nfc/protocols/nfca/nfca.c +++ b/lib/nfc/protocols/nfca/nfca.c @@ -4,9 +4,11 @@ #include #define NFCA_CRC_INIT (0x6363) -#define NFCA_PROTOCOL_NAME "Unknown ISO14443-3A Tag" +#define NFCA_PROTOCOL_NAME "ISO14443-3A" +#define NFCA_DEVICE_NAME "Unknown ISO14443-3A Tag" const NfcProtocolBase nfc_protocol_iso14443_3a = { + .protocol_name = NFCA_PROTOCOL_NAME, .alloc = (NfcProtocolAlloc)nfca_alloc, .free = (NfcProtocolFree)nfca_free, .reset = (NfcProtocolReset)nfca_reset, @@ -15,7 +17,7 @@ const NfcProtocolBase nfc_protocol_iso14443_3a = { .load = (NfcProtocolLoad)nfca_load, .save = (NfcProtocolSave)nfca_save, .is_equal = (NfcProtocolEqual)nfca_is_equal, - .get_name = (NfcProtocolGetName)nfca_get_name, + .get_device_name = (NfcProtocolGetDeviceName)nfca_get_device_name, .get_uid = (NfcProtocolGetUid)nfca_get_uid, }; @@ -71,10 +73,10 @@ bool nfca_is_equal(const NfcaData* data, const NfcaData* other) { return memcmp(data, other, sizeof(NfcaData)) == 0; } -const char* nfca_get_name(const NfcaData* data, NfcProtocolNameType name_type) { +const char* nfca_get_device_name(const NfcaData* data, NfcProtocolNameType name_type) { UNUSED(data); UNUSED(name_type); - return NFCA_PROTOCOL_NAME; + return NFCA_DEVICE_NAME; } const uint8_t* nfca_get_uid(const NfcaData* data, size_t* uid_len) { diff --git a/lib/nfc/protocols/nfca/nfca.h b/lib/nfc/protocols/nfca/nfca.h index ac17a4b67058..113754e1a6e7 100644 --- a/lib/nfc/protocols/nfca/nfca.h +++ b/lib/nfc/protocols/nfca/nfca.h @@ -82,7 +82,7 @@ bool nfca_save(const NfcaData* data, FlipperFormat* ff, uint32_t version); bool nfca_is_equal(const NfcaData* data, const NfcaData* other); -const char* nfca_get_name(const NfcaData* data, NfcProtocolNameType name_type); +const char* nfca_get_device_name(const NfcaData* data, NfcProtocolNameType name_type); const uint8_t* nfca_get_uid(const NfcaData* data, size_t* uid_len); diff --git a/lib/nfc/protocols/nfca/nfca_poller_defs.h b/lib/nfc/protocols/nfca/nfca_poller_defs.h index df45f713e04d..1bcc684b405e 100644 --- a/lib/nfc/protocols/nfca/nfca_poller_defs.h +++ b/lib/nfc/protocols/nfca/nfca_poller_defs.h @@ -1,5 +1,5 @@ #pragma once -#include +#include extern const NfcPollerBase nfc_poller_iso14443_3a; diff --git a/lib/nfc/protocols/nfca/nfca_poller_i.h b/lib/nfc/protocols/nfca/nfca_poller_i.h index 706461ae75ac..9e0d3748bde5 100644 --- a/lib/nfc/protocols/nfca/nfca_poller_i.h +++ b/lib/nfc/protocols/nfca/nfca_poller_i.h @@ -3,7 +3,7 @@ #include "nfca_poller.h" #include -#include +#include #ifdef __cplusplus extern "C" { diff --git a/lib/nfc/protocols/nfcb/nfcb_poller_i.h b/lib/nfc/protocols/nfcb/nfcb_poller_i.h index 4eabadd0b0fe..0a51fc556e24 100644 --- a/lib/nfc/protocols/nfcb/nfcb_poller_i.h +++ b/lib/nfc/protocols/nfcb/nfcb_poller_i.h @@ -1,7 +1,7 @@ #pragma once #include "nfcb_poller.h" -#include +#include #ifdef __cplusplus extern "C" { From 275872321446afbb64649e29526c1dc433b05be4 Mon Sep 17 00:00:00 2001 From: gornekich Date: Fri, 23 Jun 2023 14:24:18 +0400 Subject: [PATCH 109/149] Rework with furi hal bus, merge dev (#2798) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix typo in FuriHalDebuging.md (#2667) * [FL-3317] fbt: allow strings for fap_version field in app manifests (#2672) * [FL-3312] fix PIN retry count reset on reboot (#2671) * api: added lib/nfc/protocols/nfc_util.h (#2674) * Add new indexer (#2681) * fbt: Use union for old py (#2685) * fbt: Fix tar uid overflow when packaging (#2689) * fbt: Fix tar uid overflow when packaging * Fix trailing spaces * [FL-3328] Removed user-specific data from tar artifacts (#2691) * [FL-3327] Storage: common_rename is now POSIX compliant (#2693) * Storage: common_rename is now POSIX compliant * storage: check for success on storage_common_remove in file rename --------- Co-authored-by: hedger * Services: remove deallocator for persistent services (#2692) Co-authored-by: hedger * Storage, common_rename: check that old path is exists (#2698) * Storage, common_rename: check that old path is exists * Storage, common_rename: return correct status * [FL-3315] Desktop,Rpc: desktop status subscription (#2696) * Desktop,Rpc: desktop status subscription * Desktop,RPC: properly handle unsubscribe Co-authored-by: Sergey Gavrilov * :sparkles: Add fr-FR-mac key layout (#2666) Co-authored-by: あく * [FL-3322] Infrared: respect carrier frequency and duty cycle settings (#2677) * Make infrared_worker respect carrier frequency and duty cycle * Update comments Co-authored-by: あく * USB HID report timeout (#2682) Co-authored-by: あく * Add Airwell Prime DCI Series and match file style (#2686) Co-authored-by: あく * desktop: Refactor favorites settings and allow app browser in selection (#2687) * desktop: Refactor favorites settings and allow app browser in selection * desktop: Gate app browser entry add, just in case * Desktop: simplify favorite application selection * Desktop: refactor favorite application opening routine and cleanup code * Desktop: handle exit from external application selection Co-authored-by: hedger Co-authored-by: あく * NFC: Add support for Gen4 "ultimate card" in Magic app (#2238) * NFC: gen4 gtu detect in magic app * NFC: more support for GTU card * NFC: Fix Gen1 in Magic * Allow double UIDs for MFClassic on GTU cards * NFC: Small magic app tweaks * nfc magic: notify card event on wiping * nfc magic: fix power consumption * nfc magic: disable i2c writing and fix wipe loop * NfcMagic: correct formatting in printf * NfcMagic: correct formatting in printf, proper version * nfc_magic: rework card found notification and gen4 wiping Co-authored-by: あく * nfc: Fix MFUL tearing flags read (#2669) Co-authored-by: gornekich * api: added toolbox/api_lock.h (#2702) Co-authored-by: あく * Update ac.ir (#2701) Co-authored-by: あく * nfc: Mifare Ultralight C detection (#2668) * nfc: Add Mifare Ultralight C detection * nfc: Add display name for MFUL C and hide menu items MFUL C unlock and emulation currently not supported, so hide from menu if current card is MFUL C * nfc: Also check response when probing 3DES auth * nfc: Hide emulate option in saved menu for MFUL if not supported * nfc: Remove unlock options from saved menu if Ultralight C Co-authored-by: gornekich Co-authored-by: あく * [LRFID] Add support for Nexkey/Nexwatch (#2680) * [LRFID] Add support for Nexkey/Nexwatch * Update protocol_nexwatch.c: Remove unnecessary check Co-authored-by: SG Co-authored-by: あく * Add Carrier 42QHB12D8S (#2707) Co-authored-by: あく * BadUSB: script execution pause (#2700) Co-authored-by: あく * Implement support for reading Opal card (Sydney, Australia) (#2683) * Implement support for reading Opal card (Sydney, Australia) * stub_parser_verify_read: used UNUSED macro * furi_hal_rtc: expose calendaring as functions * opal: use bit-packed struct to parse, rather than manually shifting about * Update f18 api symbols Co-authored-by: あく * [FL-3295] FuriHal: add bus abstraction (#2614) * FuriHal: add bus abstraction and port some subsystem to it * Make PVS happy, cleanup code * Update API symbols for f18 * F18: backport bus changes from f7 * Revert to STOP2 sleep mode * Fix downgrading the firmware via updater * Port iButton TIM1 to furi_hal_bus * Port Infrared TIM1 and TIM2 to furi_hal_bus * Just enable the timer bus * Port furi_hal_pwm to bus API * Fix include statement * Port furi_hal_rfid to bus API * Port furi_hal_subghz and others to bus API * Remove unneeded include * Improve furi_hal_infrared defines * Reset LPTIM1 via furi_hal_bus API * Crash when trying to enable an already enabled peripheral * Better defines * Improved checks * Lots of macro wrappers * Copy spi changes for f18 * Fix crashes in LFRFID system * Fix crashes in NFC system * Improve comments * Create FuriHalBus.md * Update FuriHalBus.md * Fix crash when launching updater * Documentation: couple small fixes in FuriHalBus * FuriHal: fix copypaste in furi_hal_rfid_tim_reset * FuriHal: reset radio core related peripherals on restart * FuriHalBus: is enabled routine and bug fix for uart * RFID HAL: accomodate furi hal bus Co-authored-by: Georgii Surkov Co-authored-by: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Co-authored-by: SG * [FL-3330] fbt: added hooks for build & dist environments; added FW_ORIGIN_* macro for apps & SDK (#2705) * fbt: added hooks for build & dist environments * Moved env hooks to an optional file * Fixed var name * Added fw origin to device info * Bumped device info version * fbt: added FIRMWARE_ORIGIN option. Different implementation for FW_ORIGIN_* C macro. * api: bumped versions * fbt: added fbt_options_local.py * gitignore: cleanup Co-authored-by: あく * [FL-3335] Dolphin: new animation (#2713) * [FL-3340] SubGhz: fix flipper crashes after exiting broadcast blocking message and crash cli (#2714) * NFC: Fix gen1 writing with invalid BCC (lost fix from PR #2511) (#2710) Co-authored-by: あく * Update dolphin.py (#2717) Co-authored-by: あく * NFC: fix MFC timings (#2719) * digital signal: add optimization * nfc test: more restrict tests * digital signal: build as separate library * digital signal: remove unused flags, format sources * digital signal: fix cflag name * target: fix build for f18 target Co-authored-by: あく * FuriHal: disable bus re-initialization on early init and extra asserts for AHB1,AHB2,AHB3 which must be left intact on entering to FUS (#2725) * [DEVOPS-18]: Add map file parser, mariadb inserter (#2732) * [FL-3293] FuriHal: add system setting to device info, bump device info version (#2736) * [FL-3316] Settings: add contrast adjustment (#2737) Co-authored-by: hedger * [FL-3213] f7: add PB9 to debug pins (#2738) Co-authored-by: hedger * [FL-3352] Dolphin: new animation (#2735) Co-authored-by: hedger * [FL-2872] Remove unused resources (#2740) Co-authored-by: hedger * Serial_CLI: Fixing serial cli logger error so it sounds more concise (#2721) Co-authored-by: hedger * Furi: smaller critical enter and critical exit macro (#2716) * Furi: smaller critical enter and critical exit macro * api: bumped version --------- Co-authored-by: hedger Co-authored-by: hedger * [FL-3331] SubGhz: add subghz_protocol_registry external API (#2712) * [FL-3331] SubGhz: add subghz_protocol_registry external API * F18: fix API version --------- Co-authored-by: hedger * [FL-3045] Fix core2 permisions (#2742) * Fix core2 permisions * Fix Python code style * scripts: copro: changed int literals * scripts: copro: shorter string line in code --------- Co-authored-by: hedger Co-authored-by: hedger * [FL-3246] fbt, ufbt: added checks for appid in app manifests(#2720) Co-authored-by: あく * Map parser licence description (#2739) * Add map parser licence description * Add map parser copyright text & licence note --------- Co-authored-by: hedger * [FL-3346] fbt: added Flipper selection when multiple are connected over USB (#2723) * fbt: added Flipper selection when multiple are connected over USB * scripts: serial_cli: added --port (-p) option * added ISO15693 (NfcV) reading, saving, emulating and revealing from privacy mode (unlock) (#2316) * added support for ISO15693 (NfcV) emulation, added support for reading SLIX tags * SLIX: fixed crash situation when an invalid password was requested * ISO15693: show emulate menu when opening file * rename NfcV emulate scene to match other NfcV names * optimize allocation size for signals * ISO15693: further optimizations of allocation and free code * ISO15693: reduce latency on state machine reset * respond with block security status when option flag is set * increased maximum memory size to match standard added security status handling/load/save added SELECT/QUIET handling more fine grained allocation routines and checks fix memset sizes * added "Listen NfcV Reader" to sniff traffic from reader to card * added correct description to delete menu * also added DSFID/AFI handling and locking * increase sniff log size * scale NfcV frequency a bit, add echo mode, fix signal level at the end * use symbolic modulated/unmodulated GPIO levels * honor AFI field, decrease verbosity and removed debug code * refactor defines for less namespace pollution by using NFCV_ prefixes * correct an oversight that original cards return an generic error when addressing outside block range * use inverse modulation, increasing readable range significantly * rework and better document nfc chip initialization * nfcv code review fixes * Disable accidentally left on signal debug gpio output * Improve NFCV Read/Info GUIs. Authored by @xMasterX, committed by @nvx * Fix crash that occurs when you exit from NFCV emulation and start it again. Authored by @xMasterX, committed by @nvx * Remove delay from emulation loop. This improves compatibility when the reader is Android. * Lib: digital signal debug output pin info Co-authored-by: Tiernan Messmer Co-authored-by: MX <10697207+xMasterX@users.noreply.github.com> Co-authored-by: gornekich Co-authored-by: あく * [FL-3351] github: re-enabled f18 build (#2743) * github: re-enabled f18 build * scripts: storage: better transfer logging * Fix PVS warnings Co-authored-by: あく * Scripts: WiFi board updater (#2625) * Scripts: wifi updater * WiFi board updater: lint, process download error * WiFi board updater: auto cleanup temp dir * Scripts: fix server address * [FL-3267] ble: refactored bt gatt characteristics setup (#2587) * ble: refactored bt gatt characteristics setup * ble: naming fixes, small optimizations * ble: expanded bitfields; fixed pvs warnings * ble: fixed pvs warnings for real * ble: using FlipperGattCharacteristicDataPropsFixed for char[] props * ble: removed flipper_gatt_characteristic_props_const_char * ble: gatt: naming changes * ble: gatt: fixed device_info service constant attrs sizes * ble: gatt: copy descriptors to char instances; reworked hid chars to be callback-based; moved max size getter to callback with NULL data; added comments * ble: gatt: removed hid_svc_report_data_callback * ble: hid svc: better double loop idx naming * ble: hid svc: simplified hid_svc_update_info * ble: gatt: removed magic values; fixed type for HidSvcGattCharacteristicInfo * ble: gatt: moved long uuids to separate files Co-authored-by: gornekich Co-authored-by: あく * [FL-3359] github: added debugapps artifact; packaging resources per-target (#2750) * github: added debugapps artifact; packaging resources per-target * github: target name fixes * github: fixed path for debug apps * scripts: dist: removed lib stub artifact * scripts: fixed broken SDK * github: removed unused step * FuriHal: always clock SMPS from HSI (#2643) * FuriHal: always clock SMPS from HSI * FuriHal: add clock startup time check, ensure that we conform to core2 config value * FuriHal: set sleep mode to legacy if clock startup time is too high --------- Co-authored-by: hedger * Core2, SRAM2: provide safety gap (#2754) * Core2, SRAM2: use ob, provide safety gap * thread: comment about critical section and scheduler state * Services: simplify api (#2540) Co-authored-by: あく * weather_station: add oregon3 with THGR221 (#2748) Co-authored-by: hedger Co-authored-by: あく * [FL-3361] fbt: stable build dates (#2751) * scripts: using commit date for clean build timestamp; current day otherwise * scripts: version: Removing GIT_COMMIT_DATE from final data Co-authored-by: あく * [FL-3284] Fix reading Mifare Classic cards with unusual access conditions and fix emulation of unknown keys (#2620) * I was outplayed by the C programming language * Fix emulating empty keys as 0s * Add exceptions for Detect Reader * Sync api_symbols.csv for F18 * Outplayed by the C language [X2] Co-authored-by: Aleksandr Kutuzov * FuriHal: remove clock startup time tracking from clean builds (#2764) * furi_hal_nfc: fix rfalTransceiveBitsBlockingTx's 4th argument to bits count rather than bytes count (#2773) * [FL-3376] Fixed GATT attribute order (#2776) * hal: gatt: swapped rx/tx serial chars order * hal: gatt: reordered HID attrs to maintain previous order Co-authored-by: Aleksandr Kutuzov * Debug: sync apps on attach, makes it possible to debug already started app that has crashed (#2778) * hal nfc: add bus handling * nfc hal: fix timers work * nfc app: move old nfc suctom events --------- Co-authored-by: end-me-please <90796271+end-me-please@users.noreply.github.com> Co-authored-by: hedger Co-authored-by: あく Co-authored-by: Max Andreev Co-authored-by: MX <10697207+xMasterX@users.noreply.github.com> Co-authored-by: Yukai Li Co-authored-by: Sergey Gavrilov Co-authored-by: hedger Co-authored-by: Félix Legrelle Co-authored-by: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Co-authored-by: Nikolay Minaylov Co-authored-by: minchogaydarov <134236905+minchogaydarov@users.noreply.github.com> Co-authored-by: Avery <30564701+nullableVoidPtr@users.noreply.github.com> Co-authored-by: technobulb <84107091+technobulb@users.noreply.github.com> Co-authored-by: Sebastian Mauer Co-authored-by: micolous Co-authored-by: Georgii Surkov Co-authored-by: Skorpionm <85568270+Skorpionm@users.noreply.github.com> Co-authored-by: AloneLiberty <111039319+AloneLiberty@users.noreply.github.com> Co-authored-by: Zoë Prosvetova <109866245+ZoeMeetAgain@users.noreply.github.com> Co-authored-by: Astra <93453568+Astrrra@users.noreply.github.com> Co-authored-by: DEXV <89728480+DXVVAY@users.noreply.github.com> Co-authored-by: glebmashanov <65850300+glebmashanov@users.noreply.github.com> Co-authored-by: g3gg0.de Co-authored-by: Tiernan Messmer Co-authored-by: clashlab Co-authored-by: Leopold --- .github/workflows/build.yml | 94 +- .github/workflows/reindex.yml | 3 +- .gitignore | 22 +- SConstruct | 6 +- .../scenes/lfrfid_debug_app_scene_tune.c | 5 +- applications/external/hid_app/hid.c | 4 +- applications/external/mfkey32/mfkey32.c | 2 +- .../lib/magic/{magic.c => classic_gen1.c} | 78 +- .../nfc_magic/lib/magic/classic_gen1.h | 11 + .../external/nfc_magic/lib/magic/common.c | 33 + .../external/nfc_magic/lib/magic/common.h | 19 + .../external/nfc_magic/lib/magic/gen4.c | 199 +++ .../external/nfc_magic/lib/magic/gen4.h | 48 + .../external/nfc_magic/lib/magic/types.c | 23 + .../external/nfc_magic/lib/magic/types.h | 5 + applications/external/nfc_magic/nfc_magic.c | 22 +- applications/external/nfc_magic/nfc_magic.h | 2 + applications/external/nfc_magic/nfc_magic_i.h | 20 +- .../external/nfc_magic/nfc_magic_worker.c | 396 ++++- .../external/nfc_magic/nfc_magic_worker.h | 4 + .../external/nfc_magic/nfc_magic_worker_i.h | 5 + .../scenes/nfc_magic_scene_actions.c | 50 + .../nfc_magic/scenes/nfc_magic_scene_check.c | 4 +- .../nfc_magic/scenes/nfc_magic_scene_config.h | 6 + .../scenes/nfc_magic_scene_file_select.c | 60 +- .../scenes/nfc_magic_scene_gen4_actions.c | 70 + .../scenes/nfc_magic_scene_key_input.c | 45 + .../scenes/nfc_magic_scene_magic_info.c | 14 + .../scenes/nfc_magic_scene_new_key_input.c | 45 + .../nfc_magic/scenes/nfc_magic_scene_rekey.c | 95 ++ .../scenes/nfc_magic_scene_rekey_fail.c | 50 + .../nfc_magic/scenes/nfc_magic_scene_start.c | 25 +- .../nfc_magic/scenes/nfc_magic_scene_wipe.c | 11 +- .../nfc_magic/scenes/nfc_magic_scene_write.c | 11 +- .../scenes/nfc_magic_scene_wrong_card.c | 2 +- .../scenes/picopass_scene_device_info.c | 2 +- .../scenes/picopass_scene_read_card.c | 2 +- .../scenes/picopass_scene_read_card_success.c | 2 +- .../picopass_scene_read_factory_success.c | 2 +- .../scenes/picopass_scene_save_success.c | 2 +- .../scenes/picopass_scene_write_card.c | 2 +- .../picopass_scene_write_card_success.c | 2 +- .../scenes/picopass_scene_write_key.c | 2 +- applications/external/snake_game/snake_game.c | 2 +- .../weather_station/protocols/oregon3.c | 365 +++++ .../weather_station/protocols/oregon3.h | 6 + .../protocols/protocol_items.c | 3 +- .../protocols/protocol_items.h | 1 + .../main/bad_usb/helpers/ducky_script.c | 100 +- .../main/bad_usb/helpers/ducky_script.h | 5 +- .../main/bad_usb/scenes/bad_usb_scene_work.c | 5 +- .../main/bad_usb/views/bad_usb_view.c | 82 +- .../main/gpio/scenes/gpio_scene_start.c | 2 +- applications/main/ibutton/ibutton.c | 4 +- .../main/ibutton/scenes/ibutton_scene_read.c | 2 +- .../scenes/ibutton_scene_read_key_menu.c | 2 +- .../ibutton/scenes/ibutton_scene_save_name.c | 4 +- .../scenes/ibutton_scene_saved_key_menu.c | 2 +- .../main/ibutton/scenes/ibutton_scene_start.c | 2 +- applications/main/infrared/infrared.c | 5 +- .../common/infrared_scene_universal_common.c | 2 +- .../infrared/scenes/infrared_scene_learn.c | 2 +- .../scenes/infrared_scene_learn_enter_name.c | 2 +- applications/main/lfrfid/lfrfid.c | 4 +- .../scenes/lfrfid_scene_extra_actions.c | 4 +- .../main/lfrfid/scenes/lfrfid_scene_read.c | 2 +- .../scenes/lfrfid_scene_read_key_menu.c | 2 +- .../lfrfid/scenes/lfrfid_scene_save_name.c | 4 +- .../scenes/lfrfid_scene_saved_key_menu.c | 2 +- .../main/lfrfid/scenes/lfrfid_scene_start.c | 2 +- applications/main/nfc/nfc_app.c | 6 +- .../scenes/nfc_scene_mf_classic_dict_attack.c | 2 +- .../nfc/scenes/nfc_scene_mf_classic_menu.c | 6 +- .../nfc/scenes/nfc_scene_mf_desfire_menu.c | 4 +- .../nfc/scenes/nfc_scene_mf_desfire_read.c | 2 +- .../nfc/scenes/nfc_scene_mf_ultralight_menu.c | 4 +- .../nfc/scenes/nfc_scene_mf_ultralight_read.c | 2 +- .../nfc_scene_mf_ultralight_unlock_warn.c | 4 +- .../main/nfc/scenes/nfc_scene_nfca_menu.c | 4 +- .../main/nfc/scenes/nfc_scene_nfca_read.c | 2 +- .../main/nfc/scenes/nfc_scene_save_name.c | 4 +- .../main/nfc/scenes/nfc_scene_saved_menu.c | 4 +- .../main/nfc/scenes/nfc_scene_start.c | 2 +- .../main/nfc_old/helpers/nfc_custom_event.h | 2 + applications/main/nfc_old/nfc_app.c | 9 +- .../nfc_old/scenes/nfc_scene_device_info.c | 1 + .../scenes/nfc_scene_mf_classic_keys_add.c | 2 +- .../scenes/nfc_scene_mf_classic_update.c | 2 +- .../nfc_scene_mf_classic_update_success.c | 2 +- .../scenes/nfc_scene_mf_classic_write.c | 2 +- .../nfc_scene_mf_classic_write_success.c | 2 +- .../nfc_old/scenes/nfc_scene_nfc_data_info.c | 164 +- .../nfc_old/scenes/nfc_scene_nfcv_emulate.c | 169 ++ .../nfc_old/scenes/nfc_scene_nfcv_key_input.c | 48 + .../main/nfc_old/scenes/nfc_scene_nfcv_menu.c | 68 + .../scenes/nfc_scene_nfcv_read_success.c | 94 ++ .../nfc_old/scenes/nfc_scene_nfcv_sniff.c | 155 ++ .../nfc_old/scenes/nfc_scene_nfcv_unlock.c | 154 ++ .../scenes/nfc_scene_nfcv_unlock_menu.c | 60 + .../main/nfc_old/scenes/nfc_scene_read.c | 15 +- .../nfc_scene_restore_original_confirm.c | 2 +- .../main/nfc_old/scenes/nfc_scene_rpc.c | 7 + .../main/subghz/helpers/subghz_error_type.h | 1 + .../subghz/scenes/subghz_scene_read_raw.c | 4 +- .../subghz/scenes/subghz_scene_receiver.c | 2 +- .../main/subghz/scenes/subghz_scene_rpc.c | 33 +- .../subghz/scenes/subghz_scene_save_name.c | 4 +- .../main/subghz/scenes/subghz_scene_start.c | 2 +- .../subghz/scenes/subghz_scene_transmitter.c | 2 +- applications/main/subghz/subghz_cli.c | 17 +- applications/main/u2f/scenes/u2f_scene_main.c | 2 +- applications/services/bt/bt_service/bt.c | 2 +- applications/services/desktop/desktop.c | 70 +- applications/services/desktop/desktop.h | 8 + applications/services/desktop/desktop_i.h | 2 + .../services/desktop/desktop_settings.h | 2 - .../desktop/scenes/desktop_scene_debug.c | 4 +- .../desktop/scenes/desktop_scene_main.c | 49 +- .../desktop/scenes/desktop_scene_pin_input.c | 1 - applications/services/dolphin/dolphin.c | 16 +- applications/services/dolphin/dolphin.h | 9 +- applications/services/dolphin/dolphin_i.h | 2 - .../services/notification/notification.h | 2 + .../services/notification/notification_app.c | 55 +- .../services/notification/notification_app.h | 3 +- .../notification/notification_messages.c | 9 + .../notification/notification_messages.h | 6 + .../services/power/power_service/power.c | 26 +- applications/services/rpc/rpc_desktop.c | 64 + applications/services/storage/storage.h | 2 +- .../services/storage/storage_external_api.c | 21 +- .../scenes/desktop_settings_scene_favorite.c | 94 +- .../notification_settings_app.c | 44 + .../external/L1_Kaiju_128x64/frame_0.png | Bin 0 -> 1312 bytes .../external/L1_Kaiju_128x64/frame_1.png | Bin 0 -> 1302 bytes .../external/L1_Kaiju_128x64/frame_10.png | Bin 0 -> 1332 bytes .../external/L1_Kaiju_128x64/frame_11.png | Bin 0 -> 1228 bytes .../external/L1_Kaiju_128x64/frame_12.png | Bin 0 -> 1152 bytes .../external/L1_Kaiju_128x64/frame_13.png | Bin 0 -> 1152 bytes .../external/L1_Kaiju_128x64/frame_14.png | Bin 0 -> 1162 bytes .../external/L1_Kaiju_128x64/frame_15.png | Bin 0 -> 1209 bytes .../external/L1_Kaiju_128x64/frame_16.png | Bin 0 -> 1158 bytes .../external/L1_Kaiju_128x64/frame_17.png | Bin 0 -> 1161 bytes .../external/L1_Kaiju_128x64/frame_18.png | Bin 0 -> 828 bytes .../external/L1_Kaiju_128x64/frame_19.png | Bin 0 -> 817 bytes .../external/L1_Kaiju_128x64/frame_2.png | Bin 0 -> 1288 bytes .../external/L1_Kaiju_128x64/frame_20.png | Bin 0 -> 1222 bytes .../external/L1_Kaiju_128x64/frame_21.png | Bin 0 -> 1494 bytes .../external/L1_Kaiju_128x64/frame_22.png | Bin 0 -> 1685 bytes .../external/L1_Kaiju_128x64/frame_23.png | Bin 0 -> 1680 bytes .../external/L1_Kaiju_128x64/frame_24.png | Bin 0 -> 1690 bytes .../external/L1_Kaiju_128x64/frame_25.png | Bin 0 -> 1658 bytes .../external/L1_Kaiju_128x64/frame_26.png | Bin 0 -> 1716 bytes .../external/L1_Kaiju_128x64/frame_27.png | Bin 0 -> 1741 bytes .../external/L1_Kaiju_128x64/frame_28.png | Bin 0 -> 1686 bytes .../external/L1_Kaiju_128x64/frame_29.png | Bin 0 -> 1626 bytes .../external/L1_Kaiju_128x64/frame_3.png | Bin 0 -> 1305 bytes .../external/L1_Kaiju_128x64/frame_30.png | Bin 0 -> 1677 bytes .../external/L1_Kaiju_128x64/frame_31.png | Bin 0 -> 1639 bytes .../external/L1_Kaiju_128x64/frame_32.png | Bin 0 -> 1618 bytes .../external/L1_Kaiju_128x64/frame_33.png | Bin 0 -> 1595 bytes .../external/L1_Kaiju_128x64/frame_34.png | Bin 0 -> 1591 bytes .../external/L1_Kaiju_128x64/frame_35.png | Bin 0 -> 1560 bytes .../external/L1_Kaiju_128x64/frame_36.png | Bin 0 -> 1592 bytes .../external/L1_Kaiju_128x64/frame_37.png | Bin 0 -> 1494 bytes .../external/L1_Kaiju_128x64/frame_38.png | Bin 0 -> 1489 bytes .../external/L1_Kaiju_128x64/frame_39.png | Bin 0 -> 1438 bytes .../external/L1_Kaiju_128x64/frame_4.png | Bin 0 -> 1284 bytes .../external/L1_Kaiju_128x64/frame_40.png | Bin 0 -> 1438 bytes .../external/L1_Kaiju_128x64/frame_41.png | Bin 0 -> 1412 bytes .../external/L1_Kaiju_128x64/frame_42.png | Bin 0 -> 1425 bytes .../external/L1_Kaiju_128x64/frame_43.png | Bin 0 -> 1397 bytes .../external/L1_Kaiju_128x64/frame_44.png | Bin 0 -> 1217 bytes .../external/L1_Kaiju_128x64/frame_45.png | Bin 0 -> 1177 bytes .../external/L1_Kaiju_128x64/frame_46.png | Bin 0 -> 1300 bytes .../external/L1_Kaiju_128x64/frame_47.png | Bin 0 -> 1268 bytes .../external/L1_Kaiju_128x64/frame_5.png | Bin 0 -> 1318 bytes .../external/L1_Kaiju_128x64/frame_6.png | Bin 0 -> 1312 bytes .../external/L1_Kaiju_128x64/frame_7.png | Bin 0 -> 1301 bytes .../external/L1_Kaiju_128x64/frame_8.png | Bin 0 -> 1308 bytes .../external/L1_Kaiju_128x64/frame_9.png | Bin 0 -> 1336 bytes .../dolphin/external/L1_Kaiju_128x64/meta.txt | 50 + .../dolphin/external/L2_Dj_128x64/frame_0.png | Bin 0 -> 1640 bytes .../dolphin/external/L2_Dj_128x64/frame_1.png | Bin 0 -> 1687 bytes .../external/L2_Dj_128x64/frame_10.png | Bin 0 -> 1630 bytes .../external/L2_Dj_128x64/frame_11.png | Bin 0 -> 1660 bytes .../external/L2_Dj_128x64/frame_12.png | Bin 0 -> 1637 bytes .../external/L2_Dj_128x64/frame_13.png | Bin 0 -> 1654 bytes .../external/L2_Dj_128x64/frame_14.png | Bin 0 -> 1667 bytes .../external/L2_Dj_128x64/frame_15.png | Bin 0 -> 1344 bytes .../external/L2_Dj_128x64/frame_16.png | Bin 0 -> 1251 bytes .../external/L2_Dj_128x64/frame_17.png | Bin 0 -> 1292 bytes .../external/L2_Dj_128x64/frame_18.png | Bin 0 -> 1498 bytes .../external/L2_Dj_128x64/frame_19.png | Bin 0 -> 1530 bytes .../dolphin/external/L2_Dj_128x64/frame_2.png | Bin 0 -> 1726 bytes .../external/L2_Dj_128x64/frame_20.png | Bin 0 -> 1698 bytes .../external/L2_Dj_128x64/frame_21.png | Bin 0 -> 1665 bytes .../external/L2_Dj_128x64/frame_22.png | Bin 0 -> 1809 bytes .../external/L2_Dj_128x64/frame_23.png | Bin 0 -> 1775 bytes .../external/L2_Dj_128x64/frame_24.png | Bin 0 -> 1758 bytes .../external/L2_Dj_128x64/frame_25.png | Bin 0 -> 1725 bytes .../external/L2_Dj_128x64/frame_26.png | Bin 0 -> 1835 bytes .../external/L2_Dj_128x64/frame_27.png | Bin 0 -> 1759 bytes .../external/L2_Dj_128x64/frame_28.png | Bin 0 -> 1462 bytes .../external/L2_Dj_128x64/frame_29.png | Bin 0 -> 1407 bytes .../dolphin/external/L2_Dj_128x64/frame_3.png | Bin 0 -> 1777 bytes .../external/L2_Dj_128x64/frame_30.png | Bin 0 -> 1408 bytes .../external/L2_Dj_128x64/frame_31.png | Bin 0 -> 1404 bytes .../external/L2_Dj_128x64/frame_32.png | Bin 0 -> 1327 bytes .../external/L2_Dj_128x64/frame_33.png | Bin 0 -> 1306 bytes .../external/L2_Dj_128x64/frame_34.png | Bin 0 -> 1341 bytes .../external/L2_Dj_128x64/frame_35.png | Bin 0 -> 1255 bytes .../external/L2_Dj_128x64/frame_36.png | Bin 0 -> 1059 bytes .../dolphin/external/L2_Dj_128x64/frame_4.png | Bin 0 -> 1727 bytes .../dolphin/external/L2_Dj_128x64/frame_5.png | Bin 0 -> 1641 bytes .../dolphin/external/L2_Dj_128x64/frame_6.png | Bin 0 -> 1635 bytes .../dolphin/external/L2_Dj_128x64/frame_7.png | Bin 0 -> 1588 bytes .../dolphin/external/L2_Dj_128x64/frame_8.png | Bin 0 -> 1608 bytes .../dolphin/external/L2_Dj_128x64/frame_9.png | Bin 0 -> 1610 bytes assets/dolphin/external/L2_Dj_128x64/meta.txt | 14 + assets/dolphin/external/manifest.txt | 14 + assets/icons/NFC/Reader_detect_43x40.png | Bin 3799 -> 0 bytes assets/icons/NFC/Restoring_38x32.png | Bin 3794 -> 0 bytes assets/icons/NFC/Tap_reader_36x38.png | Bin 3748 -> 0 bytes assets/protobuf | 2 +- .../badusb/assets/layouts/fr-FR-mac.kl | Bin 0 -> 256 bytes assets/resources/infrared/assets/ac.ir | 103 +- documentation/AppManifests.md | 2 +- documentation/FuriHalBus.md | 113 ++ documentation/FuriHalDebuging.md | 4 +- documentation/fbt.md | 2 + fbt_options.py | 7 + firmware.scons | 11 + firmware/targets/f18/api_symbols.csv | 47 +- firmware/targets/f18/furi_hal/furi_hal.c | 5 + .../targets/f18/furi_hal/furi_hal_resources.c | 14 + .../f18/furi_hal/furi_hal_spi_config.c | 31 +- firmware/targets/f7/api_symbols.csv | 49 +- firmware/targets/f7/ble_glue/app_debug.c | 4 +- firmware/targets/f7/ble_glue/ble_app.c | 91 +- .../targets/f7/ble_glue/dev_info_service.c | 220 --- firmware/targets/f7/ble_glue/gap.c | 1 + firmware/targets/f7/ble_glue/hid_service.c | 332 ---- .../ble_glue/{ => services}/battery_service.c | 118 +- .../ble_glue/{ => services}/battery_service.h | 0 .../f7/ble_glue/services/dev_info_service.c | 176 +++ .../{ => services}/dev_info_service.h | 0 .../services/dev_info_service_uuid.inc | 3 + .../targets/f7/ble_glue/services/gatt_char.c | 123 ++ .../targets/f7/ble_glue/services/gatt_char.h | 96 ++ .../f7/ble_glue/services/hid_service.c | 302 ++++ .../f7/ble_glue/{ => services}/hid_service.h | 3 +- .../ble_glue/{ => services}/serial_service.c | 195 +-- .../ble_glue/{ => services}/serial_service.h | 0 .../ble_glue/services/serial_service_uuid.inc | 12 + .../targets/f7/furi_hal/f_hal_nfc_timer.c | 11 +- firmware/targets/f7/furi_hal/furi_hal.c | 5 + firmware/targets/f7/furi_hal/furi_hal_bt.c | 16 +- .../targets/f7/furi_hal/furi_hal_bt_hid.c | 10 +- .../targets/f7/furi_hal/furi_hal_bt_serial.c | 6 +- firmware/targets/f7/furi_hal/furi_hal_bus.c | 302 ++++ firmware/targets/f7/furi_hal/furi_hal_bus.h | 112 ++ firmware/targets/f7/furi_hal/furi_hal_clock.c | 104 +- .../targets/f7/furi_hal/furi_hal_crypto.c | 10 +- firmware/targets/f7/furi_hal/furi_hal_dma.c | 14 + firmware/targets/f7/furi_hal/furi_hal_dma.h | 15 + firmware/targets/f7/furi_hal/furi_hal_flash.c | 22 +- .../targets/f7/furi_hal/furi_hal_i2c_config.c | 32 +- .../targets/f7/furi_hal/furi_hal_ibutton.c | 12 +- .../targets/f7/furi_hal/furi_hal_idle_timer.h | 8 +- firmware/targets/f7/furi_hal/furi_hal_info.c | 35 +- .../targets/f7/furi_hal/furi_hal_infrared.c | 318 ++-- .../targets/f7/furi_hal/furi_hal_memory.c | 82 +- firmware/targets/f7/furi_hal/furi_hal_nfc.c | 4 +- firmware/targets/f7/furi_hal/furi_hal_pwm.c | 19 +- .../targets/f7/furi_hal/furi_hal_random.c | 9 +- .../targets/f7/furi_hal/furi_hal_resources.c | 15 + firmware/targets/f7/furi_hal/furi_hal_rfid.c | 107 +- firmware/targets/f7/furi_hal/furi_hal_rfid.h | 60 +- firmware/targets/f7/furi_hal/furi_hal_rtc.c | 26 +- .../targets/f7/furi_hal/furi_hal_speaker.c | 9 +- .../targets/f7/furi_hal/furi_hal_spi_config.c | 31 +- .../targets/f7/furi_hal/furi_hal_spi_types.h | 2 - .../targets/f7/furi_hal/furi_hal_subghz.c | 9 +- firmware/targets/f7/furi_hal/furi_hal_uart.c | 20 +- firmware/targets/f7/furi_hal/furi_hal_usb.c | 9 + .../targets/f7/furi_hal/furi_hal_usb_hid.c | 6 +- firmware/targets/f7/src/update.c | 6 + firmware/targets/f7/target.json | 1 + firmware/targets/furi_hal_include/furi_hal.h | 2 + .../targets/furi_hal_include/furi_hal_bt.h | 2 +- .../furi_hal_include/furi_hal_bt_serial.h | 2 +- .../furi_hal_include/furi_hal_random.h | 3 + .../targets/furi_hal_include/furi_hal_rtc.h | 24 + furi/core/common_defines.h | 31 +- furi/core/core_defines.h | 5 + furi/core/critical.c | 29 + furi/core/thread.c | 2 + lib/ReadMe.md | 1 + lib/SConscript | 2 +- lib/digital_signal/SConscript | 20 + lib/digital_signal/digital_signal.c | 20 +- lib/infrared/worker/infrared_worker.c | 32 +- lib/infrared/worker/infrared_worker.h | 10 +- lib/lfrfid/lfrfid_raw_worker.c | 4 +- lib/lfrfid/lfrfid_worker_modes.c | 9 +- lib/lfrfid/protocols/lfrfid_protocols.c | 4 +- lib/lfrfid/protocols/lfrfid_protocols.h | 3 +- lib/lfrfid/protocols/protocol_nexwatch.c | 323 ++++ lib/lfrfid/protocols/protocol_nexwatch.h | 4 + lib/lfrfid/tools/t5577.c | 9 +- lib/misc.scons | 2 - lib/nfc/deprecated/nfc_device.c | 376 ++++- lib/nfc/deprecated/nfc_device.h | 4 + lib/nfc/deprecated/nfc_types.c | 2 + lib/nfc/deprecated/nfc_worker.c | 284 +++- lib/nfc/deprecated/nfc_worker.h | 11 + lib/nfc/deprecated/nfc_worker_i.h | 3 + .../deprecated/parsers/nfc_supported_card.c | 15 + .../deprecated/parsers/nfc_supported_card.h | 6 + lib/nfc/deprecated/parsers/opal.c | 204 +++ lib/nfc/deprecated/parsers/opal.h | 5 + lib/nfc/deprecated/protocols/mifare_classic.c | 29 +- lib/nfc/deprecated/protocols/mifare_classic.h | 5 +- lib/nfc/deprecated/protocols/mifare_desfire.c | 24 + lib/nfc/deprecated/protocols/mifare_desfire.h | 3 + .../deprecated/protocols/mifare_ultralight.c | 42 +- .../deprecated/protocols/mifare_ultralight.h | 7 +- lib/nfc/deprecated/protocols/nfcv.c | 1395 +++++++++++++++++ lib/nfc/deprecated/protocols/nfcv.h | 290 ++++ lib/nfc/deprecated/protocols/slix.c | 409 +++++ lib/nfc/deprecated/protocols/slix.h | 45 + lib/nfc/helpers/nfc_util.h | 8 + lib/pulse_reader/pulse_reader.c | 3 + lib/subghz/SConscript | 1 + lib/subghz/environment.c | 7 +- lib/subghz/environment.h | 7 +- lib/subghz/protocols/protocol_items.h | 3 +- lib/subghz/registry.h | 1 + lib/subghz/subghz_protocol_registry.h | 13 + lib/subghz/types.h | 7 +- lib/toolbox/SConscript | 1 + lib/toolbox/value_index.c | 13 + lib/toolbox/value_index.h | 13 + lib/toolbox/version.c | 15 +- lib/toolbox/version.h | 11 + lib/u8g2/u8g2_glue.c | 20 +- lib/u8g2/u8g2_glue.h | 2 + scripts/debug/flipperapps.py | 6 +- scripts/debug/flipperversion.py | 16 +- scripts/fbt/appmanifest.py | 18 +- scripts/fbt_tools/fbt_dist.py | 2 +- scripts/fbt_tools/fbt_envhooks.py | 67 + scripts/fbt_tools/fbt_extapps.py | 3 +- scripts/fbt_tools/fbt_version.py | 4 +- scripts/flipper/assets/copro.py | 11 +- scripts/flipper/assets/coprobin.py | 5 +- scripts/flipper/assets/dolphin.py | 4 +- scripts/flipper/storage.py | 20 +- scripts/flipper/utils/cdc.py | 2 +- scripts/map_mariadb_insert.py | 139 ++ scripts/map_parser.py | 274 ++++ scripts/sconsdist.py | 21 +- scripts/serial_cli.py | 8 +- scripts/ufbt/SConstruct | 17 +- scripts/ufbt/commandline.scons | 5 + .../app_template/application.fam | 2 +- scripts/update.py | 3 + scripts/version.py | 45 +- scripts/wifi_board.py | 240 +++ site_scons/commandline.scons | 12 + 371 files changed, 9892 insertions(+), 2135 deletions(-) rename applications/external/nfc_magic/lib/magic/{magic.c => classic_gen1.c} (64%) create mode 100644 applications/external/nfc_magic/lib/magic/classic_gen1.h create mode 100644 applications/external/nfc_magic/lib/magic/common.c create mode 100644 applications/external/nfc_magic/lib/magic/common.h create mode 100644 applications/external/nfc_magic/lib/magic/gen4.c create mode 100644 applications/external/nfc_magic/lib/magic/gen4.h create mode 100644 applications/external/nfc_magic/lib/magic/types.c create mode 100644 applications/external/nfc_magic/lib/magic/types.h create mode 100644 applications/external/nfc_magic/scenes/nfc_magic_scene_actions.c create mode 100644 applications/external/nfc_magic/scenes/nfc_magic_scene_gen4_actions.c create mode 100644 applications/external/nfc_magic/scenes/nfc_magic_scene_key_input.c create mode 100644 applications/external/nfc_magic/scenes/nfc_magic_scene_new_key_input.c create mode 100644 applications/external/nfc_magic/scenes/nfc_magic_scene_rekey.c create mode 100644 applications/external/nfc_magic/scenes/nfc_magic_scene_rekey_fail.c create mode 100644 applications/external/weather_station/protocols/oregon3.c create mode 100644 applications/external/weather_station/protocols/oregon3.h create mode 100644 applications/main/nfc_old/scenes/nfc_scene_nfcv_emulate.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_nfcv_key_input.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_nfcv_menu.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_nfcv_read_success.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_nfcv_sniff.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_nfcv_unlock.c create mode 100644 applications/main/nfc_old/scenes/nfc_scene_nfcv_unlock_menu.c create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_0.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_1.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_10.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_11.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_12.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_13.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_14.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_15.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_16.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_17.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_18.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_19.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_2.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_20.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_21.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_22.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_23.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_24.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_25.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_26.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_27.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_28.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_29.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_3.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_30.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_31.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_32.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_33.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_34.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_35.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_36.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_37.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_38.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_39.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_4.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_40.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_41.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_42.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_43.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_44.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_45.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_46.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_47.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_5.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_6.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_7.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_8.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/frame_9.png create mode 100644 assets/dolphin/external/L1_Kaiju_128x64/meta.txt create mode 100644 assets/dolphin/external/L2_Dj_128x64/frame_0.png create mode 100644 assets/dolphin/external/L2_Dj_128x64/frame_1.png create mode 100644 assets/dolphin/external/L2_Dj_128x64/frame_10.png create mode 100644 assets/dolphin/external/L2_Dj_128x64/frame_11.png create mode 100644 assets/dolphin/external/L2_Dj_128x64/frame_12.png create mode 100644 assets/dolphin/external/L2_Dj_128x64/frame_13.png create mode 100644 assets/dolphin/external/L2_Dj_128x64/frame_14.png create mode 100644 assets/dolphin/external/L2_Dj_128x64/frame_15.png create mode 100644 assets/dolphin/external/L2_Dj_128x64/frame_16.png create mode 100644 assets/dolphin/external/L2_Dj_128x64/frame_17.png create mode 100644 assets/dolphin/external/L2_Dj_128x64/frame_18.png create mode 100644 assets/dolphin/external/L2_Dj_128x64/frame_19.png create mode 100644 assets/dolphin/external/L2_Dj_128x64/frame_2.png create mode 100644 assets/dolphin/external/L2_Dj_128x64/frame_20.png create mode 100644 assets/dolphin/external/L2_Dj_128x64/frame_21.png create mode 100644 assets/dolphin/external/L2_Dj_128x64/frame_22.png create mode 100644 assets/dolphin/external/L2_Dj_128x64/frame_23.png create mode 100644 assets/dolphin/external/L2_Dj_128x64/frame_24.png create mode 100644 assets/dolphin/external/L2_Dj_128x64/frame_25.png create mode 100644 assets/dolphin/external/L2_Dj_128x64/frame_26.png create mode 100644 assets/dolphin/external/L2_Dj_128x64/frame_27.png create mode 100644 assets/dolphin/external/L2_Dj_128x64/frame_28.png create mode 100644 assets/dolphin/external/L2_Dj_128x64/frame_29.png create mode 100644 assets/dolphin/external/L2_Dj_128x64/frame_3.png create mode 100644 assets/dolphin/external/L2_Dj_128x64/frame_30.png create mode 100644 assets/dolphin/external/L2_Dj_128x64/frame_31.png create mode 100644 assets/dolphin/external/L2_Dj_128x64/frame_32.png create mode 100644 assets/dolphin/external/L2_Dj_128x64/frame_33.png create mode 100644 assets/dolphin/external/L2_Dj_128x64/frame_34.png create mode 100644 assets/dolphin/external/L2_Dj_128x64/frame_35.png create mode 100644 assets/dolphin/external/L2_Dj_128x64/frame_36.png create mode 100644 assets/dolphin/external/L2_Dj_128x64/frame_4.png create mode 100644 assets/dolphin/external/L2_Dj_128x64/frame_5.png create mode 100644 assets/dolphin/external/L2_Dj_128x64/frame_6.png create mode 100644 assets/dolphin/external/L2_Dj_128x64/frame_7.png create mode 100644 assets/dolphin/external/L2_Dj_128x64/frame_8.png create mode 100644 assets/dolphin/external/L2_Dj_128x64/frame_9.png create mode 100644 assets/dolphin/external/L2_Dj_128x64/meta.txt delete mode 100644 assets/icons/NFC/Reader_detect_43x40.png delete mode 100644 assets/icons/NFC/Restoring_38x32.png delete mode 100644 assets/icons/NFC/Tap_reader_36x38.png create mode 100644 assets/resources/badusb/assets/layouts/fr-FR-mac.kl create mode 100644 documentation/FuriHalBus.md delete mode 100644 firmware/targets/f7/ble_glue/dev_info_service.c delete mode 100644 firmware/targets/f7/ble_glue/hid_service.c rename firmware/targets/f7/ble_glue/{ => services}/battery_service.c (53%) rename firmware/targets/f7/ble_glue/{ => services}/battery_service.h (100%) create mode 100644 firmware/targets/f7/ble_glue/services/dev_info_service.c rename firmware/targets/f7/ble_glue/{ => services}/dev_info_service.h (100%) create mode 100644 firmware/targets/f7/ble_glue/services/dev_info_service_uuid.inc create mode 100644 firmware/targets/f7/ble_glue/services/gatt_char.c create mode 100644 firmware/targets/f7/ble_glue/services/gatt_char.h create mode 100644 firmware/targets/f7/ble_glue/services/hid_service.c rename firmware/targets/f7/ble_glue/{ => services}/hid_service.h (87%) rename firmware/targets/f7/ble_glue/{ => services}/serial_service.c (57%) rename firmware/targets/f7/ble_glue/{ => services}/serial_service.h (100%) create mode 100644 firmware/targets/f7/ble_glue/services/serial_service_uuid.inc create mode 100644 firmware/targets/f7/furi_hal/furi_hal_bus.c create mode 100644 firmware/targets/f7/furi_hal/furi_hal_bus.h create mode 100644 firmware/targets/f7/furi_hal/furi_hal_dma.c create mode 100644 firmware/targets/f7/furi_hal/furi_hal_dma.h create mode 100644 furi/core/critical.c create mode 100644 lib/digital_signal/SConscript create mode 100644 lib/lfrfid/protocols/protocol_nexwatch.c create mode 100644 lib/lfrfid/protocols/protocol_nexwatch.h create mode 100644 lib/nfc/deprecated/parsers/opal.c create mode 100644 lib/nfc/deprecated/parsers/opal.h create mode 100644 lib/nfc/deprecated/protocols/nfcv.c create mode 100644 lib/nfc/deprecated/protocols/nfcv.h create mode 100644 lib/nfc/deprecated/protocols/slix.c create mode 100644 lib/nfc/deprecated/protocols/slix.h create mode 100644 lib/subghz/subghz_protocol_registry.h create mode 100644 scripts/fbt_tools/fbt_envhooks.py create mode 100755 scripts/map_mariadb_insert.py create mode 100755 scripts/map_parser.py create mode 100755 scripts/wifi_board.py diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8358d1706aa6..9fbcb16ebeb9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -9,7 +9,7 @@ on: pull_request: env: - TARGETS: f7 + TARGETS: f7 f18 DEFAULT_TARGET: f7 FBT_TOOLCHAIN_PATH: /runner/_work @@ -52,10 +52,8 @@ jobs: - name: 'Make artifacts directory' run: | - rm -rf artifacts - rm -rf map_analyser_files - mkdir artifacts - mkdir map_analyser_files + rm -rf artifacts map_analyser_files + mkdir artifacts map_analyser_files - name: 'Bundle scripts' if: ${{ !github.event.pull_request.head.repo.fork }} @@ -66,28 +64,21 @@ jobs: run: | set -e for TARGET in ${TARGETS}; do - TARGET="$(echo "${TARGET}" | sed 's/f//')"; \ - ./fbt TARGET_HW=$TARGET copro_dist updater_package \ - ${{ startsWith(github.ref, 'refs/tags') && 'DEBUG=0 COMPACT=1' || '' }} - done - - - name: 'Move upload files' - if: ${{ !github.event.pull_request.head.repo.fork }} - run: | - set -e - for TARGET in ${TARGETS}; do + TARGET_HW="$(echo "${TARGET}" | sed 's/f//')"; \ + ./fbt TARGET_HW=$TARGET_HW copro_dist updater_package \ + ${{ startsWith(github.ref, 'refs/tags') && 'DEBUG=0 COMPACT=1' || '' }} mv dist/${TARGET}-*/* artifacts/ + tar czpf "artifacts/flipper-z-${TARGET}-resources-${SUFFIX}.tgz" \ + -C assets resources + ./fbt TARGET_HW=$TARGET_HW fap_dist + tar czpf "artifacts/flipper-z-${TARGET}-debugapps-${SUFFIX}.tgz" \ + -C dist/${TARGET}-*/apps/Debug . done - name: "Check for uncommitted changes" run: | git diff --exit-code - - name: 'Bundle resources' - if: ${{ !github.event.pull_request.head.repo.fork }} - run: | - tar czpf "artifacts/flipper-z-any-resources-${SUFFIX}.tgz" -C assets resources - - name: 'Bundle core2 firmware' if: ${{ !github.event.pull_request.head.repo.fork }} run: | @@ -96,45 +87,44 @@ jobs: - name: 'Copy map analyser files' if: ${{ !github.event.pull_request.head.repo.fork }} run: | - cp build/f7-firmware-*/firmware.elf.map map_analyser_files/firmware.elf.map - cp build/f7-firmware-*/firmware.elf map_analyser_files/firmware.elf + cp build/${DEFAULT_TARGET}-firmware-*/firmware.elf.map map_analyser_files/firmware.elf.map + cp build/${DEFAULT_TARGET}-firmware-*/firmware.elf map_analyser_files/firmware.elf cp ${{ github.event_path }} map_analyser_files/event.json - - name: 'Upload map analyser files to storage' - if: ${{ !github.event.pull_request.head.repo.fork }} - uses: prewk/s3-cp-action@v2 - with: - aws_s3_endpoint: "${{ secrets.MAP_REPORT_AWS_ENDPOINT }}" - aws_access_key_id: "${{ secrets.MAP_REPORT_AWS_ACCESS_KEY }}" - aws_secret_access_key: "${{ secrets.MAP_REPORT_AWS_SECRET_KEY }}" - source: "./map_analyser_files/" - dest: "s3://${{ secrets.MAP_REPORT_AWS_BUCKET }}/${{steps.names.outputs.random_hash}}" - flags: "--recursive --acl public-read" - - - name: 'Trigger map file reporter' + - name: 'Analyse map file' if: ${{ !github.event.pull_request.head.repo.fork }} - uses: peter-evans/repository-dispatch@v2 - with: - repository: flipperdevices/flipper-map-reporter - token: ${{ secrets.REPOSITORY_DISPATCH_TOKEN }} - event-type: map-file-analyse - client-payload: '{"random_hash": "${{steps.names.outputs.random_hash}}", "event_type": "${{steps.names.outputs.event_type}}"}' + run: | + source scripts/toolchain/fbtenv.sh + get_size() + { + SECTION="$1"; + arm-none-eabi-size \ + -A map_analyser_files/firmware.elf \ + | grep "^$SECTION" | awk '{print $2}' + } + export BSS_SIZE="$(get_size ".bss")" + export TEXT_SIZE="$(get_size ".text")" + export RODATA_SIZE="$(get_size ".rodata")" + export DATA_SIZE="$(get_size ".data")" + export FREE_FLASH_SIZE="$(get_size ".free_flash")" + python3 -m pip install mariadb==1.1.6 cxxfilt==0.3.0 + python3 scripts/map_parser.py map_analyser_files/firmware.elf.map map_analyser_files/firmware.elf.map.all + python3 scripts/map_mariadb_insert.py \ + ${{ secrets.AMAP_MARIADB_USER }} \ + ${{ secrets.AMAP_MARIADB_PASSWORD }} \ + ${{ secrets.AMAP_MARIADB_HOST }} \ + ${{ secrets.AMAP_MARIADB_PORT }} \ + ${{ secrets.AMAP_MARIADB_DATABASE }} \ + map_analyser_files/firmware.elf.map.all - name: 'Upload artifacts to update server' if: ${{ !github.event.pull_request.head.repo.fork }} run: | - mkdir -p ~/.ssh - ssh-keyscan -p ${{ secrets.RSYNC_DEPLOY_PORT }} -H ${{ secrets.RSYNC_DEPLOY_HOST }} > ~/.ssh/known_hosts - echo "${{ secrets.RSYNC_DEPLOY_KEY }}" > deploy_key; - chmod 600 ./deploy_key; - rsync -avzP --delete --mkpath \ - -e 'ssh -p ${{ secrets.RSYNC_DEPLOY_PORT }} -i ./deploy_key' \ - artifacts/ ${{ secrets.RSYNC_DEPLOY_USER }}@${{ secrets.RSYNC_DEPLOY_HOST }}:"${{ secrets.RSYNC_DEPLOY_BASE_PATH }}${BRANCH_NAME}/"; - rm ./deploy_key; - - - name: 'Trigger update server reindex' - if: ${{ !github.event.pull_request.head.repo.fork }} - run: curl -X POST -F 'key=${{ secrets.REINDEX_KEY }}' ${{ secrets.REINDEX_URL }} + FILES=$(for CUR in $(ls artifacts/); do echo "-F files=@artifacts/$CUR"; done) + curl --fail -L -H "Token: ${{ secrets.INDEXER_TOKEN }}" \ + -F "branch=${BRANCH_NAME}" \ + ${FILES[@]} \ + "${{ secrets.INDEXER_URL }}"/firmware/uploadfiles - name: 'Find Previous Comment' if: ${{ !github.event.pull_request.head.repo.fork && github.event.pull_request }} diff --git a/.github/workflows/reindex.yml b/.github/workflows/reindex.yml index ea850e7051b7..5645f609badf 100644 --- a/.github/workflows/reindex.yml +++ b/.github/workflows/reindex.yml @@ -11,4 +11,5 @@ jobs: steps: - name: Trigger reindex run: | - curl -X POST -F 'key=${{ secrets.REINDEX_KEY }}' ${{ secrets.REINDEX_URL }} + curl --fail -L -H "Token: ${{ secrets.INDEXER_TOKEN }}" \ + "${{ secrets.INDEXER_URL }}"/firmware/reindex diff --git a/.gitignore b/.gitignore index bf17a94e28d0..d60dcec3f5db 100644 --- a/.gitignore +++ b/.gitignore @@ -30,27 +30,25 @@ bindings/ .mxproject Brewfile.lock.json -# Visual Studio Code -/.vscode/ - # Kate .kateproject .kateconfig -# legendary cmake's -build -CMakeLists.txt - -# bundle output -dist - # kde .directory # SCons .sconsign.dblite + + +# Visual Studio Code +/.vscode + +# bundle output +/dist + # SCons build dir -build/ +/build # Toolchain /toolchain @@ -64,3 +62,5 @@ PVS-Studio.log *.PVS-Studio.* .gdbinit + +/fbt_options_local.py \ No newline at end of file diff --git a/SConstruct b/SConstruct index e2568287dff4..b51154f70322 100644 --- a/SConstruct +++ b/SConstruct @@ -171,7 +171,7 @@ distenv.Depends(firmware_env["FW_RESOURCES"], external_apps_artifacts.resources_ fap_deploy = distenv.PhonyTarget( "fap_deploy", - "${PYTHON3} ${ROOT_DIR}/scripts/storage.py send ${SOURCE} /ext/apps", + "${PYTHON3} ${FBT_SCRIPT_DIR}/storage.py -p ${FLIP_PORT} send ${SOURCE} /ext/apps", source=Dir("#/assets/resources/apps"), ) @@ -323,7 +323,9 @@ distenv.PhonyTarget( ) # Start Flipper CLI via PySerial's miniterm -distenv.PhonyTarget("cli", "${PYTHON3} ${FBT_SCRIPT_DIR}/serial_cli.py") +distenv.PhonyTarget( + "cli", "${PYTHON3} ${FBT_SCRIPT_DIR}/serial_cli.py -p ${FLIP_PORT}" +) # Find blackmagic probe diff --git a/applications/debug/lfrfid_debug/scenes/lfrfid_debug_app_scene_tune.c b/applications/debug/lfrfid_debug/scenes/lfrfid_debug_app_scene_tune.c index c7f3bf24fdc7..74c53ae6d485 100644 --- a/applications/debug/lfrfid_debug/scenes/lfrfid_debug_app_scene_tune.c +++ b/applications/debug/lfrfid_debug/scenes/lfrfid_debug_app_scene_tune.c @@ -14,9 +14,7 @@ void lfrfid_debug_scene_tune_on_enter(void* context) { furi_hal_rfid_comp_set_callback(comparator_trigger_callback, app); furi_hal_rfid_comp_start(); - furi_hal_rfid_pins_read(); - furi_hal_rfid_tim_read(125000, 0.5); - furi_hal_rfid_tim_read_start(); + furi_hal_rfid_tim_read_start(125000, 0.5); view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidDebugViewTune); } @@ -43,6 +41,5 @@ void lfrfid_debug_scene_tune_on_exit(void* context) { furi_hal_gpio_init_simple(&gpio_ext_pa7, GpioModeAnalog); furi_hal_rfid_tim_read_stop(); - furi_hal_rfid_tim_reset(); furi_hal_rfid_pins_reset(); } diff --git a/applications/external/hid_app/hid.c b/applications/external/hid_app/hid.c index a4f64589d76b..ea408c392876 100644 --- a/applications/external/hid_app/hid.c +++ b/applications/external/hid_app/hid.c @@ -377,7 +377,7 @@ int32_t hid_usb_app(void* p) { bt_hid_connection_status_changed_callback(BtStatusConnected, app); - DOLPHIN_DEED(DolphinDeedPluginStart); + dolphin_deed(DolphinDeedPluginStart); view_dispatcher_run(app->view_dispatcher); @@ -417,7 +417,7 @@ int32_t hid_ble_app(void* p) { furi_hal_bt_start_advertising(); bt_set_status_changed_callback(app->bt, bt_hid_connection_status_changed_callback, app); - DOLPHIN_DEED(DolphinDeedPluginStart); + dolphin_deed(DolphinDeedPluginStart); view_dispatcher_run(app->view_dispatcher); diff --git a/applications/external/mfkey32/mfkey32.c b/applications/external/mfkey32/mfkey32.c index 24bd0ff86d7f..3f1142277419 100644 --- a/applications/external/mfkey32/mfkey32.c +++ b/applications/external/mfkey32/mfkey32.c @@ -1112,7 +1112,7 @@ void mfkey32(ProgramState* program_state) { } if(keyarray_size > 0) { // TODO: Should we use DolphinDeedNfcMfcAdd? - DOLPHIN_DEED(DolphinDeedNfcMfcAdd); + dolphin_deed(DolphinDeedNfcMfcAdd); } napi_mf_classic_nonce_array_free(nonce_arr); napi_mf_classic_dict_free(user_dict); diff --git a/applications/external/nfc_magic/lib/magic/magic.c b/applications/external/nfc_magic/lib/magic/classic_gen1.c similarity index 64% rename from applications/external/nfc_magic/lib/magic/magic.c rename to applications/external/nfc_magic/lib/magic/classic_gen1.c index 9a71daaa0ffa..8d87d63161d2 100644 --- a/applications/external/nfc_magic/lib/magic/magic.c +++ b/applications/external/nfc_magic/lib/magic/classic_gen1.c @@ -1,11 +1,10 @@ -#include "magic.h" +#include "classic_gen1.h" #include #define TAG "Magic" #define MAGIC_CMD_WUPA (0x40) -#define MAGIC_CMD_WIPE (0x41) #define MAGIC_CMD_ACCESS (0x43) #define MAGIC_MIFARE_READ_CMD (0x30) @@ -15,7 +14,7 @@ #define MAGIC_BUFFER_SIZE (32) -bool magic_wupa() { +bool magic_gen1_wupa() { bool magic_activated = false; uint8_t tx_data[MAGIC_BUFFER_SIZE] = {}; uint8_t rx_data[MAGIC_BUFFER_SIZE] = {}; @@ -23,19 +22,6 @@ bool magic_wupa() { FuriHalNfcReturn ret = 0; do { - // Setup nfc poller - furi_hal_nfc_exit_sleep(); - furi_hal_nfc_ll_txrx_on(); - furi_hal_nfc_ll_poll(); - ret = furi_hal_nfc_ll_set_mode( - FuriHalNfcModePollNfca, FuriHalNfcBitrate106, FuriHalNfcBitrate106); - if(ret != FuriHalNfcReturnOk) break; - - furi_hal_nfc_ll_set_fdt_listen(FURI_HAL_NFC_LL_FDT_LISTEN_NFCA_POLLER); - furi_hal_nfc_ll_set_fdt_poll(FURI_HAL_NFC_LL_FDT_POLL_NFCA_POLLER); - furi_hal_nfc_ll_set_error_handling(FuriHalNfcErrorHandlingNfc); - furi_hal_nfc_ll_set_guard_time(FURI_HAL_NFC_LL_GT_NFCA); - // Start communication tx_data[0] = MAGIC_CMD_WUPA; ret = furi_hal_nfc_ll_txrx_bits( @@ -53,15 +39,10 @@ bool magic_wupa() { magic_activated = true; } while(false); - if(!magic_activated) { - furi_hal_nfc_ll_txrx_off(); - furi_hal_nfc_start_sleep(); - } - return magic_activated; } -bool magic_data_access_cmd() { +bool magic_gen1_data_access_cmd() { bool write_cmd_success = false; uint8_t tx_data[MAGIC_BUFFER_SIZE] = {}; uint8_t rx_data[MAGIC_BUFFER_SIZE] = {}; @@ -86,15 +67,10 @@ bool magic_data_access_cmd() { write_cmd_success = true; } while(false); - if(!write_cmd_success) { - furi_hal_nfc_ll_txrx_off(); - furi_hal_nfc_start_sleep(); - } - return write_cmd_success; } -bool magic_read_block(uint8_t block_num, MfClassicBlock* data) { +bool magic_gen1_read_block(uint8_t block_num, MfClassicBlock* data) { furi_assert(data); bool read_success = false; @@ -122,15 +98,10 @@ bool magic_read_block(uint8_t block_num, MfClassicBlock* data) { read_success = true; } while(false); - if(!read_success) { - furi_hal_nfc_ll_txrx_off(); - furi_hal_nfc_start_sleep(); - } - return read_success; } -bool magic_write_blk(uint8_t block_num, MfClassicBlock* data) { +bool magic_gen1_write_blk(uint8_t block_num, MfClassicBlock* data) { furi_assert(data); bool write_success = false; @@ -170,44 +141,5 @@ bool magic_write_blk(uint8_t block_num, MfClassicBlock* data) { write_success = true; } while(false); - if(!write_success) { - furi_hal_nfc_ll_txrx_off(); - furi_hal_nfc_start_sleep(); - } - return write_success; } - -bool magic_wipe() { - bool wipe_success = false; - uint8_t tx_data[MAGIC_BUFFER_SIZE] = {}; - uint8_t rx_data[MAGIC_BUFFER_SIZE] = {}; - uint16_t rx_len = 0; - FuriHalNfcReturn ret = 0; - - do { - tx_data[0] = MAGIC_CMD_WIPE; - ret = furi_hal_nfc_ll_txrx_bits( - tx_data, - 8, - rx_data, - sizeof(rx_data), - &rx_len, - FURI_HAL_NFC_LL_TXRX_FLAGS_CRC_TX_MANUAL | FURI_HAL_NFC_LL_TXRX_FLAGS_AGC_ON | - FURI_HAL_NFC_LL_TXRX_FLAGS_CRC_RX_KEEP, - furi_hal_nfc_ll_ms2fc(2000)); - - if(ret != FuriHalNfcReturnIncompleteByte) break; - if(rx_len != 4) break; - if(rx_data[0] != MAGIC_ACK) break; - - wipe_success = true; - } while(false); - - return wipe_success; -} - -void magic_deactivate() { - furi_hal_nfc_ll_txrx_off(); - furi_hal_nfc_sleep(); -} diff --git a/applications/external/nfc_magic/lib/magic/classic_gen1.h b/applications/external/nfc_magic/lib/magic/classic_gen1.h new file mode 100644 index 000000000000..98de1230239b --- /dev/null +++ b/applications/external/nfc_magic/lib/magic/classic_gen1.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +bool magic_gen1_wupa(); + +bool magic_gen1_read_block(uint8_t block_num, MfClassicBlock* data); + +bool magic_gen1_data_access_cmd(); + +bool magic_gen1_write_blk(uint8_t block_num, MfClassicBlock* data); diff --git a/applications/external/nfc_magic/lib/magic/common.c b/applications/external/nfc_magic/lib/magic/common.c new file mode 100644 index 000000000000..0ea3cb218dd2 --- /dev/null +++ b/applications/external/nfc_magic/lib/magic/common.c @@ -0,0 +1,33 @@ +#include "common.h" + +#include + +#define REQA (0x26) +#define CL1_PREFIX (0x93) +#define SELECT (0x70) + +#define MAGIC_BUFFER_SIZE (32) + +bool magic_activate() { + FuriHalNfcReturn ret = 0; + + // Setup nfc poller + furi_hal_nfc_exit_sleep(); + furi_hal_nfc_ll_txrx_on(); + furi_hal_nfc_ll_poll(); + ret = furi_hal_nfc_ll_set_mode( + FuriHalNfcModePollNfca, FuriHalNfcBitrate106, FuriHalNfcBitrate106); + if(ret != FuriHalNfcReturnOk) return false; + + furi_hal_nfc_ll_set_fdt_listen(FURI_HAL_NFC_LL_FDT_LISTEN_NFCA_POLLER); + furi_hal_nfc_ll_set_fdt_poll(FURI_HAL_NFC_LL_FDT_POLL_NFCA_POLLER); + furi_hal_nfc_ll_set_error_handling(FuriHalNfcErrorHandlingNfc); + furi_hal_nfc_ll_set_guard_time(FURI_HAL_NFC_LL_GT_NFCA); + + return true; +} + +void magic_deactivate() { + furi_hal_nfc_ll_txrx_off(); + furi_hal_nfc_sleep(); +} \ No newline at end of file diff --git a/applications/external/nfc_magic/lib/magic/common.h b/applications/external/nfc_magic/lib/magic/common.h new file mode 100644 index 000000000000..bef166c8f220 --- /dev/null +++ b/applications/external/nfc_magic/lib/magic/common.h @@ -0,0 +1,19 @@ +#pragma once + +#include +#include + +typedef enum { + MagicTypeClassicGen1, + MagicTypeClassicDirectWrite, + MagicTypeClassicAPDU, + MagicTypeUltralightGen1, + MagicTypeUltralightDirectWrite, + MagicTypeUltralightC_Gen1, + MagicTypeUltralightC_DirectWrite, + MagicTypeGen4, +} MagicType; + +bool magic_activate(); + +void magic_deactivate(); \ No newline at end of file diff --git a/applications/external/nfc_magic/lib/magic/gen4.c b/applications/external/nfc_magic/lib/magic/gen4.c new file mode 100644 index 000000000000..31be649a04ec --- /dev/null +++ b/applications/external/nfc_magic/lib/magic/gen4.c @@ -0,0 +1,199 @@ +#include "gen4.h" + +#include +#include + +#define TAG "Magic" + +#define MAGIC_CMD_PREFIX (0xCF) + +#define MAGIC_CMD_GET_CFG (0xC6) +#define MAGIC_CMD_WRITE (0xCD) +#define MAGIC_CMD_READ (0xCE) +#define MAGIC_CMD_SET_CFG (0xF0) +#define MAGIC_CMD_FUSE_CFG (0xF1) +#define MAGIC_CMD_SET_PWD (0xFE) + +#define MAGIC_BUFFER_SIZE (40) + +const uint8_t MAGIC_DEFAULT_CONFIG[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x09, 0x78, 0x00, 0x91, 0x02, 0xDA, 0xBC, 0x19, 0x10, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x04, 0x00, 0x08, 0x00 +}; + +const uint8_t MAGIC_DEFAULT_BLOCK0[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x04, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +const uint8_t MAGIC_EMPTY_BLOCK[16] = { 0 }; + +const uint8_t MAGIC_DEFAULT_SECTOR_TRAILER[] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x80, 0x69, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + +static bool magic_gen4_is_block_num_trailer(uint8_t n) { + n++; + if (n < 32 * 4) { + return (n % 4 == 0); + } + + return (n % 16 == 0); +} + +bool magic_gen4_get_cfg(uint32_t pwd, uint8_t* config) { + bool is_valid_config_len = false; + uint8_t tx_data[MAGIC_BUFFER_SIZE] = {}; + uint8_t rx_data[MAGIC_BUFFER_SIZE] = {}; + uint16_t rx_len = 0; + FuriHalNfcReturn ret = 0; + + do { + // Start communication + tx_data[0] = MAGIC_CMD_PREFIX; + tx_data[1] = (uint8_t)(pwd >> 24); + tx_data[2] = (uint8_t)(pwd >> 16); + tx_data[3] = (uint8_t)(pwd >> 8); + tx_data[4] = (uint8_t)pwd; + tx_data[5] = MAGIC_CMD_GET_CFG; + ret = furi_hal_nfc_ll_txrx( + tx_data, + 6, + rx_data, + sizeof(rx_data), + &rx_len, + FURI_HAL_NFC_TXRX_DEFAULT, + furi_hal_nfc_ll_ms2fc(20)); + if(ret != FuriHalNfcReturnOk) break; + if(rx_len != 30 && rx_len != 32) break; + memcpy(config, rx_data, rx_len); + is_valid_config_len = true; + } while(false); + + return is_valid_config_len; +} + +bool magic_gen4_set_cfg(uint32_t pwd, const uint8_t* config, uint8_t config_length, bool fuse) { + bool write_success = false; + uint8_t tx_data[MAGIC_BUFFER_SIZE] = {}; + uint8_t rx_data[MAGIC_BUFFER_SIZE] = {}; + uint16_t rx_len = 0; + FuriHalNfcReturn ret = 0; + + do { + // Start communication + tx_data[0] = MAGIC_CMD_PREFIX; + tx_data[1] = (uint8_t)(pwd >> 24); + tx_data[2] = (uint8_t)(pwd >> 16); + tx_data[3] = (uint8_t)(pwd >> 8); + tx_data[4] = (uint8_t)pwd; + tx_data[5] = fuse ? MAGIC_CMD_FUSE_CFG : MAGIC_CMD_SET_CFG; + memcpy(tx_data + 6, config, config_length); + ret = furi_hal_nfc_ll_txrx( + tx_data, + 6 + config_length, + rx_data, + sizeof(rx_data), + &rx_len, + FURI_HAL_NFC_TXRX_DEFAULT, + furi_hal_nfc_ll_ms2fc(20)); + if(ret != FuriHalNfcReturnOk) break; + if(rx_len != 2) break; + write_success = true; + } while(false); + + return write_success; +} + +bool magic_gen4_set_pwd(uint32_t old_pwd, uint32_t new_pwd) { + bool change_success = false; + uint8_t tx_data[MAGIC_BUFFER_SIZE] = {}; + uint8_t rx_data[MAGIC_BUFFER_SIZE] = {}; + uint16_t rx_len = 0; + FuriHalNfcReturn ret = 0; + + do { + // Start communication + tx_data[0] = MAGIC_CMD_PREFIX; + tx_data[1] = (uint8_t)(old_pwd >> 24); + tx_data[2] = (uint8_t)(old_pwd >> 16); + tx_data[3] = (uint8_t)(old_pwd >> 8); + tx_data[4] = (uint8_t)old_pwd; + tx_data[5] = MAGIC_CMD_SET_PWD; + tx_data[6] = (uint8_t)(new_pwd >> 24); + tx_data[7] = (uint8_t)(new_pwd >> 16); + tx_data[8] = (uint8_t)(new_pwd >> 8); + tx_data[9] = (uint8_t)new_pwd; + ret = furi_hal_nfc_ll_txrx( + tx_data, + 10, + rx_data, + sizeof(rx_data), + &rx_len, + FURI_HAL_NFC_TXRX_DEFAULT, + furi_hal_nfc_ll_ms2fc(20)); + FURI_LOG_I(TAG, "ret %d, len %d", ret, rx_len); + if(ret != FuriHalNfcReturnOk) break; + if(rx_len != 2) break; + change_success = true; + } while(false); + + return change_success; +} + +bool magic_gen4_write_blk(uint32_t pwd, uint8_t block_num, const uint8_t* data) { + bool write_success = false; + uint8_t tx_data[MAGIC_BUFFER_SIZE] = {}; + uint8_t rx_data[MAGIC_BUFFER_SIZE] = {}; + uint16_t rx_len = 0; + FuriHalNfcReturn ret = 0; + + do { + // Start communication + tx_data[0] = MAGIC_CMD_PREFIX; + tx_data[1] = (uint8_t)(pwd >> 24); + tx_data[2] = (uint8_t)(pwd >> 16); + tx_data[3] = (uint8_t)(pwd >> 8); + tx_data[4] = (uint8_t)pwd; + tx_data[5] = MAGIC_CMD_WRITE; + tx_data[6] = block_num; + memcpy(tx_data + 7, data, 16); + ret = furi_hal_nfc_ll_txrx( + tx_data, + 23, + rx_data, + sizeof(rx_data), + &rx_len, + FURI_HAL_NFC_TXRX_DEFAULT, + furi_hal_nfc_ll_ms2fc(200)); + if(ret != FuriHalNfcReturnOk) break; + if(rx_len != 2) break; + write_success = true; + } while(false); + + return write_success; +} + +bool magic_gen4_wipe(uint32_t pwd) { + if(!magic_gen4_set_cfg(pwd, MAGIC_DEFAULT_CONFIG, sizeof(MAGIC_DEFAULT_CONFIG), false)) { + FURI_LOG_E(TAG, "Set config failed"); + return false; + } + if(!magic_gen4_write_blk(pwd, 0, MAGIC_DEFAULT_BLOCK0)) { + FURI_LOG_E(TAG, "Block 0 write failed"); + return false; + } + for(size_t i = 1; i < 64; i++) { + const uint8_t* block = magic_gen4_is_block_num_trailer(i) ? MAGIC_DEFAULT_SECTOR_TRAILER : MAGIC_EMPTY_BLOCK; + if(!magic_gen4_write_blk(pwd, i, block)) { + FURI_LOG_E(TAG, "Block %d write failed", i); + return false; + } + } + for(size_t i = 65; i < 256; i++) { + if(!magic_gen4_write_blk(pwd, i, MAGIC_EMPTY_BLOCK)) { + FURI_LOG_E(TAG, "Block %d write failed", i); + return false; + } + } + + return true; +} \ No newline at end of file diff --git a/applications/external/nfc_magic/lib/magic/gen4.h b/applications/external/nfc_magic/lib/magic/gen4.h new file mode 100644 index 000000000000..c515af820b00 --- /dev/null +++ b/applications/external/nfc_magic/lib/magic/gen4.h @@ -0,0 +1,48 @@ +#pragma once + +#include + +#define MAGIC_GEN4_DEFAULT_PWD 0x00000000 +#define MAGIC_GEN4_CONFIG_LEN 32 + +#define NFCID1_SINGLE_SIZE 4 +#define NFCID1_DOUBLE_SIZE 7 +#define NFCID1_TRIPLE_SIZE 10 + +typedef enum { + MagicGen4UIDLengthSingle = 0x00, + MagicGen4UIDLengthDouble = 0x01, + MagicGen4UIDLengthTriple = 0x02 +} MagicGen4UIDLength; + +typedef enum { + MagicGen4UltralightModeUL_EV1 = 0x00, + MagicGen4UltralightModeNTAG = 0x01, + MagicGen4UltralightModeUL_C = 0x02, + MagicGen4UltralightModeUL = 0x03 +} MagicGen4UltralightMode; + +typedef enum { + // for writing original (shadow) data + MagicGen4ShadowModePreWrite = 0x00, + // written data can be read once before restored to original + MagicGen4ShadowModeRestore = 0x01, + // written data is discarded + MagicGen4ShadowModeIgnore = 0x02, + // apparently for UL? + MagicGen4ShadowModeHighSpeedIgnore = 0x03 +} MagicGen4ShadowMode; + +bool magic_gen4_get_cfg(uint32_t pwd, uint8_t* config); + +bool magic_gen4_set_cfg(uint32_t pwd, const uint8_t* config, uint8_t config_length, bool fuse); + +bool magic_gen4_set_pwd(uint32_t old_pwd, uint32_t new_pwd); + +bool magic_gen4_read_blk(uint32_t pwd, uint8_t block_num, uint8_t* data); + +bool magic_gen4_write_blk(uint32_t pwd, uint8_t block_num, const uint8_t* data); + +bool magic_gen4_wipe(uint32_t pwd); + +void magic_gen4_deactivate(); diff --git a/applications/external/nfc_magic/lib/magic/types.c b/applications/external/nfc_magic/lib/magic/types.c new file mode 100644 index 000000000000..77c6c0a4eff1 --- /dev/null +++ b/applications/external/nfc_magic/lib/magic/types.c @@ -0,0 +1,23 @@ +#include "types.h" + +const char* nfc_magic_type(MagicType type) { + if(type == MagicTypeClassicGen1) { + return "Classic Gen 1A/B"; + } else if(type == MagicTypeClassicDirectWrite) { + return "Classic DirectWrite"; + } else if(type == MagicTypeClassicAPDU) { + return "Classic APDU"; + } else if(type == MagicTypeUltralightGen1) { + return "Ultralight Gen 1"; + } else if(type == MagicTypeUltralightDirectWrite) { + return "Ultralight DirectWrite"; + } else if(type == MagicTypeUltralightC_Gen1) { + return "Ultralight-C Gen 1"; + } else if(type == MagicTypeUltralightC_DirectWrite) { + return "Ultralight-C DirectWrite"; + } else if(type == MagicTypeGen4) { + return "Gen 4 GTU"; + } else { + return "Unknown"; + } +} diff --git a/applications/external/nfc_magic/lib/magic/types.h b/applications/external/nfc_magic/lib/magic/types.h new file mode 100644 index 000000000000..dbf5540637c2 --- /dev/null +++ b/applications/external/nfc_magic/lib/magic/types.h @@ -0,0 +1,5 @@ +#pragma once + +#include "common.h" + +const char* nfc_magic_type(MagicType type); \ No newline at end of file diff --git a/applications/external/nfc_magic/nfc_magic.c b/applications/external/nfc_magic/nfc_magic.c index 1805f35ed052..68c9a65b5fd5 100644 --- a/applications/external/nfc_magic/nfc_magic.c +++ b/applications/external/nfc_magic/nfc_magic.c @@ -48,8 +48,9 @@ NfcMagic* nfc_magic_alloc() { nfc_magic->view_dispatcher, nfc_magic_tick_event_callback, 100); // Nfc device - nfc_magic->nfc_dev = nfc_device_alloc(); - furi_string_set(nfc_magic->nfc_dev->folder, NFC_APP_FOLDER); + nfc_magic->dev = malloc(sizeof(NfcMagicDevice)); + nfc_magic->source_dev = nfc_device_alloc(); + furi_string_set(nfc_magic->source_dev->folder, NFC_APP_FOLDER); // Open GUI record nfc_magic->gui = furi_record_open(RECORD_GUI); @@ -81,6 +82,13 @@ NfcMagic* nfc_magic_alloc() { NfcMagicViewTextInput, text_input_get_view(nfc_magic->text_input)); + // Byte Input + nfc_magic->byte_input = byte_input_alloc(); + view_dispatcher_add_view( + nfc_magic->view_dispatcher, + NfcMagicViewByteInput, + byte_input_get_view(nfc_magic->byte_input)); + // Custom Widget nfc_magic->widget = widget_alloc(); view_dispatcher_add_view( @@ -93,7 +101,8 @@ void nfc_magic_free(NfcMagic* nfc_magic) { furi_assert(nfc_magic); // Nfc device - nfc_device_free(nfc_magic->nfc_dev); + free(nfc_magic->dev); + nfc_device_free(nfc_magic->source_dev); // Submenu view_dispatcher_remove_view(nfc_magic->view_dispatcher, NfcMagicViewMenu); @@ -107,10 +116,14 @@ void nfc_magic_free(NfcMagic* nfc_magic) { view_dispatcher_remove_view(nfc_magic->view_dispatcher, NfcMagicViewLoading); loading_free(nfc_magic->loading); - // TextInput + // Text Input view_dispatcher_remove_view(nfc_magic->view_dispatcher, NfcMagicViewTextInput); text_input_free(nfc_magic->text_input); + // Byte Input + view_dispatcher_remove_view(nfc_magic->view_dispatcher, NfcMagicViewByteInput); + byte_input_free(nfc_magic->byte_input); + // Custom Widget view_dispatcher_remove_view(nfc_magic->view_dispatcher, NfcMagicViewWidget); widget_free(nfc_magic->widget); @@ -164,6 +177,7 @@ int32_t nfc_magic_app(void* p) { view_dispatcher_run(nfc_magic->view_dispatcher); + magic_deactivate(); nfc_magic_free(nfc_magic); return 0; diff --git a/applications/external/nfc_magic/nfc_magic.h b/applications/external/nfc_magic/nfc_magic.h index 1abf1371ed07..f9cf395d8265 100644 --- a/applications/external/nfc_magic/nfc_magic.h +++ b/applications/external/nfc_magic/nfc_magic.h @@ -1,3 +1,5 @@ #pragma once +typedef struct NfcMagicDevice NfcMagicDevice; + typedef struct NfcMagic NfcMagic; diff --git a/applications/external/nfc_magic/nfc_magic_i.h b/applications/external/nfc_magic/nfc_magic_i.h index 378912e5b09f..4d6b89103d4e 100644 --- a/applications/external/nfc_magic/nfc_magic_i.h +++ b/applications/external/nfc_magic/nfc_magic_i.h @@ -3,7 +3,10 @@ #include "nfc_magic.h" #include "nfc_magic_worker.h" -#include "lib/magic/magic.h" +#include "lib/magic/common.h" +#include "lib/magic/types.h" +#include "lib/magic/classic_gen1.h" +#include "lib/magic/gen4.h" #include #include @@ -15,6 +18,7 @@ #include #include #include +#include #include #include @@ -39,14 +43,22 @@ enum NfcMagicCustomEvent { NfcMagicCustomEventTextInputDone, }; +struct NfcMagicDevice { + MagicType type; + uint32_t cuid; + uint32_t password; +}; + struct NfcMagic { NfcMagicWorker* worker; ViewDispatcher* view_dispatcher; Gui* gui; NotificationApp* notifications; SceneManager* scene_manager; - // NfcMagicDevice* dev; - NfcDevice* nfc_dev; + struct NfcMagicDevice* dev; + NfcDevice* source_dev; + + uint32_t new_password; FuriString* text_box_store; @@ -55,6 +67,7 @@ struct NfcMagic { Popup* popup; Loading* loading; TextInput* text_input; + ByteInput* byte_input; Widget* widget; }; @@ -63,6 +76,7 @@ typedef enum { NfcMagicViewPopup, NfcMagicViewLoading, NfcMagicViewTextInput, + NfcMagicViewByteInput, NfcMagicViewWidget, } NfcMagicView; diff --git a/applications/external/nfc_magic/nfc_magic_worker.c b/applications/external/nfc_magic/nfc_magic_worker.c index 92eb793a71d8..9ee7fd3eecdf 100644 --- a/applications/external/nfc_magic/nfc_magic_worker.c +++ b/applications/external/nfc_magic/nfc_magic_worker.c @@ -1,6 +1,9 @@ #include "nfc_magic_worker_i.h" -#include "lib/magic/magic.h" +#include "nfc_magic_i.h" +#include "lib/magic/common.h" +#include "lib/magic/classic_gen1.h" +#include "lib/magic/gen4.h" #define TAG "NfcMagicWorker" @@ -43,15 +46,20 @@ void nfc_magic_worker_stop(NfcMagicWorker* nfc_magic_worker) { void nfc_magic_worker_start( NfcMagicWorker* nfc_magic_worker, NfcMagicWorkerState state, + NfcMagicDevice* magic_dev, NfcDeviceData* dev_data, + uint32_t new_password, NfcMagicWorkerCallback callback, void* context) { furi_assert(nfc_magic_worker); + furi_assert(magic_dev); furi_assert(dev_data); nfc_magic_worker->callback = callback; nfc_magic_worker->context = context; + nfc_magic_worker->magic_dev = magic_dev; nfc_magic_worker->dev_data = dev_data; + nfc_magic_worker->new_password = new_password; nfc_magic_worker_change_state(nfc_magic_worker, state); furi_thread_start(nfc_magic_worker->thread); } @@ -63,6 +71,8 @@ int32_t nfc_magic_worker_task(void* context) { nfc_magic_worker_check(nfc_magic_worker); } else if(nfc_magic_worker->state == NfcMagicWorkerStateWrite) { nfc_magic_worker_write(nfc_magic_worker); + } else if(nfc_magic_worker->state == NfcMagicWorkerStateRekey) { + nfc_magic_worker_rekey(nfc_magic_worker); } else if(nfc_magic_worker->state == NfcMagicWorkerStateWipe) { nfc_magic_worker_wipe(nfc_magic_worker); } @@ -74,73 +84,302 @@ int32_t nfc_magic_worker_task(void* context) { void nfc_magic_worker_write(NfcMagicWorker* nfc_magic_worker) { bool card_found_notified = false; + bool done = false; FuriHalNfcDevData nfc_data = {}; - MfClassicData* src_data = &nfc_magic_worker->dev_data->mf_classic_data; + NfcMagicDevice* magic_dev = nfc_magic_worker->magic_dev; + NfcDeviceData* dev_data = nfc_magic_worker->dev_data; + NfcProtocol dev_protocol = dev_data->protocol; while(nfc_magic_worker->state == NfcMagicWorkerStateWrite) { - if(furi_hal_nfc_detect(&nfc_data, 200)) { - if(!card_found_notified) { - nfc_magic_worker->callback( - NfcMagicWorkerEventCardDetected, nfc_magic_worker->context); - card_found_notified = true; - } - furi_hal_nfc_sleep(); - if(!magic_wupa()) { - FURI_LOG_E(TAG, "No card response to WUPA (not a magic card)"); - nfc_magic_worker->callback( - NfcMagicWorkerEventWrongCard, nfc_magic_worker->context); - break; - } - furi_hal_nfc_sleep(); - } - if(magic_wupa()) { - if(!magic_data_access_cmd()) { - FURI_LOG_E(TAG, "No card response to data access command (not a magic card)"); - nfc_magic_worker->callback( - NfcMagicWorkerEventWrongCard, nfc_magic_worker->context); - break; - } - for(size_t i = 0; i < 64; i++) { - FURI_LOG_D(TAG, "Writing block %d", i); - if(!magic_write_blk(i, &src_data->block[i])) { - FURI_LOG_E(TAG, "Failed to write %d block", i); - nfc_magic_worker->callback(NfcMagicWorkerEventFail, nfc_magic_worker->context); + do { + if(magic_dev->type == MagicTypeClassicGen1) { + if(furi_hal_nfc_detect(&nfc_data, 200)) { + magic_deactivate(); + magic_activate(); + if(!magic_gen1_wupa()) { + FURI_LOG_E(TAG, "No card response to WUPA (not a magic card)"); + nfc_magic_worker->callback( + NfcMagicWorkerEventWrongCard, nfc_magic_worker->context); + done = true; + break; + } + magic_deactivate(); + } + magic_activate(); + if(magic_gen1_wupa()) { + if(!magic_gen1_data_access_cmd()) { + FURI_LOG_E( + TAG, "No card response to data access command (not a magic card)"); + nfc_magic_worker->callback( + NfcMagicWorkerEventWrongCard, nfc_magic_worker->context); + done = true; + break; + } + + MfClassicData* mfc_data = &dev_data->mf_classic_data; + for(size_t i = 0; i < 64; i++) { + FURI_LOG_D(TAG, "Writing block %d", i); + if(!magic_gen1_write_blk(i, &mfc_data->block[i])) { + FURI_LOG_E(TAG, "Failed to write %d block", i); + done = true; + nfc_magic_worker->callback( + NfcMagicWorkerEventFail, nfc_magic_worker->context); + break; + } + } + + done = true; + nfc_magic_worker->callback( + NfcMagicWorkerEventSuccess, nfc_magic_worker->context); + break; + } + } else if(magic_dev->type == MagicTypeGen4) { + if(furi_hal_nfc_detect(&nfc_data, 200)) { + uint8_t gen4_config[28]; + uint32_t password = magic_dev->password; + + uint32_t cuid; + if(dev_protocol == NfcDeviceProtocolMifareClassic) { + gen4_config[0] = 0x00; + gen4_config[27] = 0x00; + } else if(dev_protocol == NfcDeviceProtocolMifareUl) { + MfUltralightData* mf_ul_data = &dev_data->mf_ul_data; + gen4_config[0] = 0x01; + switch(mf_ul_data->type) { + case MfUltralightTypeUL11: + case MfUltralightTypeUL21: + // UL-C? + // UL? + default: + gen4_config[27] = MagicGen4UltralightModeUL_EV1; + break; + case MfUltralightTypeNTAG203: + case MfUltralightTypeNTAG213: + case MfUltralightTypeNTAG215: + case MfUltralightTypeNTAG216: + case MfUltralightTypeNTAGI2C1K: + case MfUltralightTypeNTAGI2C2K: + case MfUltralightTypeNTAGI2CPlus1K: + case MfUltralightTypeNTAGI2CPlus2K: + gen4_config[27] = MagicGen4UltralightModeNTAG; + break; + } + } + + if(dev_data->nfc_data.uid_len == 4) { + gen4_config[1] = MagicGen4UIDLengthSingle; + } else if(dev_data->nfc_data.uid_len == 7) { + gen4_config[1] = MagicGen4UIDLengthDouble; + } else { + FURI_LOG_E(TAG, "Unexpected UID length %d", dev_data->nfc_data.uid_len); + nfc_magic_worker->callback( + NfcMagicWorkerEventFail, nfc_magic_worker->context); + done = true; + break; + } + + gen4_config[2] = (uint8_t)(password >> 24); + gen4_config[3] = (uint8_t)(password >> 16); + gen4_config[4] = (uint8_t)(password >> 8); + gen4_config[5] = (uint8_t)password; + + if(dev_protocol == NfcDeviceProtocolMifareUl) { + gen4_config[6] = MagicGen4ShadowModeHighSpeedIgnore; + } else { + gen4_config[6] = MagicGen4ShadowModeIgnore; + } + gen4_config[7] = 0x00; + memset(gen4_config + 8, 0, 16); + gen4_config[24] = dev_data->nfc_data.atqa[0]; + gen4_config[25] = dev_data->nfc_data.atqa[1]; + gen4_config[26] = dev_data->nfc_data.sak; + + furi_hal_nfc_sleep(); + furi_hal_nfc_activate_nfca(200, &cuid); + if(!magic_gen4_set_cfg(password, gen4_config, sizeof(gen4_config), false)) { + nfc_magic_worker->callback( + NfcMagicWorkerEventFail, nfc_magic_worker->context); + done = true; + break; + } + if(dev_protocol == NfcDeviceProtocolMifareClassic) { + MfClassicData* mfc_data = &dev_data->mf_classic_data; + size_t block_count = 64; + if(mfc_data->type == MfClassicType4k) block_count = 256; + for(size_t i = 0; i < block_count; i++) { + FURI_LOG_D(TAG, "Writing block %d", i); + if(!magic_gen4_write_blk(password, i, mfc_data->block[i].value)) { + FURI_LOG_E(TAG, "Failed to write %d block", i); + nfc_magic_worker->callback( + NfcMagicWorkerEventFail, nfc_magic_worker->context); + done = true; + break; + } + } + } else if(dev_protocol == NfcDeviceProtocolMifareUl) { + MfUltralightData* mf_ul_data = &dev_data->mf_ul_data; + for(size_t i = 0; (i * 4) < mf_ul_data->data_read; i++) { + size_t data_offset = i * 4; + FURI_LOG_D( + TAG, + "Writing page %zu (%zu/%u)", + i, + data_offset, + mf_ul_data->data_read); + uint8_t* block = mf_ul_data->data + data_offset; + if(!magic_gen4_write_blk(password, i, block)) { + FURI_LOG_E(TAG, "Failed to write %zu page", i); + nfc_magic_worker->callback( + NfcMagicWorkerEventFail, nfc_magic_worker->context); + done = true; + break; + } + } + + uint8_t buffer[16] = {0}; + + for(size_t i = 0; i < 8; i++) { + memcpy(buffer, &mf_ul_data->signature[i * 4], 4); //-V1086 + if(!magic_gen4_write_blk(password, 0xF2 + i, buffer)) { + FURI_LOG_E(TAG, "Failed to write signature block %d", i); + nfc_magic_worker->callback( + NfcMagicWorkerEventFail, nfc_magic_worker->context); + done = true; + break; + } + } + + buffer[0] = mf_ul_data->version.header; + buffer[1] = mf_ul_data->version.vendor_id; + buffer[2] = mf_ul_data->version.prod_type; + buffer[3] = mf_ul_data->version.prod_subtype; + if(!magic_gen4_write_blk(password, 0xFA, buffer)) { + FURI_LOG_E(TAG, "Failed to write version block 0"); + nfc_magic_worker->callback( + NfcMagicWorkerEventFail, nfc_magic_worker->context); + done = true; + break; + } + + buffer[0] = mf_ul_data->version.prod_ver_major; + buffer[1] = mf_ul_data->version.prod_ver_minor; + buffer[2] = mf_ul_data->version.storage_size; + buffer[3] = mf_ul_data->version.protocol_type; + if(!magic_gen4_write_blk(password, 0xFB, buffer)) { + FURI_LOG_E(TAG, "Failed to write version block 1"); + nfc_magic_worker->callback( + NfcMagicWorkerEventFail, nfc_magic_worker->context); + done = true; + break; + } + } + + nfc_magic_worker->callback( + NfcMagicWorkerEventSuccess, nfc_magic_worker->context); + done = true; break; } } - nfc_magic_worker->callback(NfcMagicWorkerEventSuccess, nfc_magic_worker->context); - break; - } else { - if(card_found_notified) { - nfc_magic_worker->callback( - NfcMagicWorkerEventNoCardDetected, nfc_magic_worker->context); - card_found_notified = false; - } + } while(false); + + if(done) break; + + if(card_found_notified) { + nfc_magic_worker->callback( + NfcMagicWorkerEventNoCardDetected, nfc_magic_worker->context); + card_found_notified = false; } + furi_delay_ms(300); } magic_deactivate(); } void nfc_magic_worker_check(NfcMagicWorker* nfc_magic_worker) { + NfcMagicDevice* magic_dev = nfc_magic_worker->magic_dev; bool card_found_notified = false; + uint8_t gen4_config[MAGIC_GEN4_CONFIG_LEN]; while(nfc_magic_worker->state == NfcMagicWorkerStateCheck) { - if(magic_wupa()) { + magic_activate(); + if(magic_gen1_wupa()) { + magic_dev->type = MagicTypeClassicGen1; if(!card_found_notified) { nfc_magic_worker->callback( NfcMagicWorkerEventCardDetected, nfc_magic_worker->context); card_found_notified = true; } + furi_hal_nfc_activate_nfca(200, &magic_dev->cuid); nfc_magic_worker->callback(NfcMagicWorkerEventSuccess, nfc_magic_worker->context); break; - } else { + } + + magic_deactivate(); + furi_delay_ms(300); + magic_activate(); + + furi_hal_nfc_activate_nfca(200, &magic_dev->cuid); + if(magic_gen4_get_cfg(magic_dev->password, gen4_config)) { + magic_dev->type = MagicTypeGen4; + if(!card_found_notified) { + nfc_magic_worker->callback( + NfcMagicWorkerEventCardDetected, nfc_magic_worker->context); + card_found_notified = true; + } + + nfc_magic_worker->callback(NfcMagicWorkerEventSuccess, nfc_magic_worker->context); + break; + } + + if(card_found_notified) { + nfc_magic_worker->callback( + NfcMagicWorkerEventNoCardDetected, nfc_magic_worker->context); + card_found_notified = false; + } + + magic_deactivate(); + furi_delay_ms(300); + } + + magic_deactivate(); +} + +void nfc_magic_worker_rekey(NfcMagicWorker* nfc_magic_worker) { + NfcMagicDevice* magic_dev = nfc_magic_worker->magic_dev; + bool card_found_notified = false; + + if(magic_dev->type != MagicTypeGen4) { + nfc_magic_worker->callback(NfcMagicWorkerEventCardDetected, nfc_magic_worker->context); + return; + } + + while(nfc_magic_worker->state == NfcMagicWorkerStateRekey) { + magic_activate(); + uint32_t cuid; + furi_hal_nfc_activate_nfca(200, &cuid); + if(cuid != magic_dev->cuid) { if(card_found_notified) { nfc_magic_worker->callback( NfcMagicWorkerEventNoCardDetected, nfc_magic_worker->context); card_found_notified = false; } + continue; + } + + nfc_magic_worker->callback(NfcMagicWorkerEventCardDetected, nfc_magic_worker->context); + card_found_notified = true; + + if(magic_gen4_set_pwd(magic_dev->password, nfc_magic_worker->new_password)) { + magic_dev->password = nfc_magic_worker->new_password; + nfc_magic_worker->callback(NfcMagicWorkerEventSuccess, nfc_magic_worker->context); + break; + } + + if(card_found_notified) { //-V547 + nfc_magic_worker->callback( + NfcMagicWorkerEventNoCardDetected, nfc_magic_worker->context); + card_found_notified = false; } furi_delay_ms(300); } @@ -148,8 +387,17 @@ void nfc_magic_worker_check(NfcMagicWorker* nfc_magic_worker) { } void nfc_magic_worker_wipe(NfcMagicWorker* nfc_magic_worker) { + NfcMagicDevice* magic_dev = nfc_magic_worker->magic_dev; + bool card_found_notified = false; + bool card_wiped = false; + MfClassicBlock block; memset(&block, 0, sizeof(MfClassicBlock)); + MfClassicBlock empty_block; + memset(&empty_block, 0, sizeof(MfClassicBlock)); + MfClassicBlock trailer_block; + memset(&trailer_block, 0xff, sizeof(MfClassicBlock)); + block.value[0] = 0x01; block.value[1] = 0x02; block.value[2] = 0x03; @@ -158,15 +406,69 @@ void nfc_magic_worker_wipe(NfcMagicWorker* nfc_magic_worker) { block.value[5] = 0x08; block.value[6] = 0x04; + trailer_block.value[7] = 0x07; + trailer_block.value[8] = 0x80; + trailer_block.value[9] = 0x69; + while(nfc_magic_worker->state == NfcMagicWorkerStateWipe) { - magic_deactivate(); - furi_delay_ms(300); - if(!magic_wupa()) continue; - if(!magic_wipe()) continue; - if(!magic_data_access_cmd()) continue; - if(!magic_write_blk(0, &block)) continue; - nfc_magic_worker->callback(NfcMagicWorkerEventSuccess, nfc_magic_worker->context); - break; + do { + magic_deactivate(); + furi_delay_ms(300); + if(!magic_activate()) break; + if(magic_dev->type == MagicTypeClassicGen1) { + if(!magic_gen1_wupa()) break; + if(!card_found_notified) { + nfc_magic_worker->callback( + NfcMagicWorkerEventCardDetected, nfc_magic_worker->context); + card_found_notified = true; + } + + if(!magic_gen1_data_access_cmd()) break; + if(!magic_gen1_write_blk(0, &block)) break; + + for(size_t i = 1; i < 64; i++) { + FURI_LOG_D(TAG, "Wiping block %d", i); + bool success = false; + if((i | 0x03) == i) { + success = magic_gen1_write_blk(i, &trailer_block); + } else { + success = magic_gen1_write_blk(i, &empty_block); + } + + if(!success) { + FURI_LOG_E(TAG, "Failed to write %d block", i); + nfc_magic_worker->callback( + NfcMagicWorkerEventFail, nfc_magic_worker->context); + break; + } + } + + card_wiped = true; + nfc_magic_worker->callback(NfcMagicWorkerEventSuccess, nfc_magic_worker->context); + } else if(magic_dev->type == MagicTypeGen4) { + uint32_t cuid; + if(!furi_hal_nfc_activate_nfca(200, &cuid)) break; + if(cuid != magic_dev->cuid) break; + if(!card_found_notified) { + nfc_magic_worker->callback( + NfcMagicWorkerEventCardDetected, nfc_magic_worker->context); + card_found_notified = true; + } + + if(!magic_gen4_wipe(magic_dev->password)) break; + + card_wiped = true; + nfc_magic_worker->callback(NfcMagicWorkerEventSuccess, nfc_magic_worker->context); + } + } while(false); + + if(card_wiped) break; + + if(card_found_notified) { + nfc_magic_worker->callback( + NfcMagicWorkerEventNoCardDetected, nfc_magic_worker->context); + card_found_notified = false; + } } magic_deactivate(); } diff --git a/applications/external/nfc_magic/nfc_magic_worker.h b/applications/external/nfc_magic/nfc_magic_worker.h index 9d29bb3a8be9..51ff4ee438d4 100644 --- a/applications/external/nfc_magic/nfc_magic_worker.h +++ b/applications/external/nfc_magic/nfc_magic_worker.h @@ -1,6 +1,7 @@ #pragma once #include +#include "nfc_magic.h" typedef struct NfcMagicWorker NfcMagicWorker; @@ -9,6 +10,7 @@ typedef enum { NfcMagicWorkerStateCheck, NfcMagicWorkerStateWrite, + NfcMagicWorkerStateRekey, NfcMagicWorkerStateWipe, NfcMagicWorkerStateStop, @@ -33,6 +35,8 @@ void nfc_magic_worker_stop(NfcMagicWorker* nfc_magic_worker); void nfc_magic_worker_start( NfcMagicWorker* nfc_magic_worker, NfcMagicWorkerState state, + NfcMagicDevice* magic_dev, NfcDeviceData* dev_data, + uint32_t new_password, NfcMagicWorkerCallback callback, void* context); diff --git a/applications/external/nfc_magic/nfc_magic_worker_i.h b/applications/external/nfc_magic/nfc_magic_worker_i.h index 0cde2e7125bf..a354f8047634 100644 --- a/applications/external/nfc_magic/nfc_magic_worker_i.h +++ b/applications/external/nfc_magic/nfc_magic_worker_i.h @@ -3,11 +3,14 @@ #include #include "nfc_magic_worker.h" +#include "lib/magic/common.h" struct NfcMagicWorker { FuriThread* thread; + NfcMagicDevice* magic_dev; NfcDeviceData* dev_data; + uint32_t new_password; NfcMagicWorkerCallback callback; void* context; @@ -21,4 +24,6 @@ void nfc_magic_worker_check(NfcMagicWorker* nfc_magic_worker); void nfc_magic_worker_write(NfcMagicWorker* nfc_magic_worker); +void nfc_magic_worker_rekey(NfcMagicWorker* nfc_magic_worker); + void nfc_magic_worker_wipe(NfcMagicWorker* nfc_magic_worker); diff --git a/applications/external/nfc_magic/scenes/nfc_magic_scene_actions.c b/applications/external/nfc_magic/scenes/nfc_magic_scene_actions.c new file mode 100644 index 000000000000..675262a9b2ff --- /dev/null +++ b/applications/external/nfc_magic/scenes/nfc_magic_scene_actions.c @@ -0,0 +1,50 @@ +#include "../nfc_magic_i.h" +enum SubmenuIndex { + SubmenuIndexWrite, + SubmenuIndexWipe, +}; + +void nfc_magic_scene_actions_submenu_callback(void* context, uint32_t index) { + NfcMagic* nfc_magic = context; + view_dispatcher_send_custom_event(nfc_magic->view_dispatcher, index); +} + +void nfc_magic_scene_actions_on_enter(void* context) { + NfcMagic* nfc_magic = context; + + Submenu* submenu = nfc_magic->submenu; + submenu_add_item( + submenu, "Write", SubmenuIndexWrite, nfc_magic_scene_actions_submenu_callback, nfc_magic); + submenu_add_item( + submenu, "Wipe", SubmenuIndexWipe, nfc_magic_scene_actions_submenu_callback, nfc_magic); + + submenu_set_selected_item( + submenu, scene_manager_get_scene_state(nfc_magic->scene_manager, NfcMagicSceneActions)); + view_dispatcher_switch_to_view(nfc_magic->view_dispatcher, NfcMagicViewMenu); +} + +bool nfc_magic_scene_actions_on_event(void* context, SceneManagerEvent event) { + NfcMagic* nfc_magic = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexWrite) { + scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneFileSelect); + consumed = true; + } else if(event.event == SubmenuIndexWipe) { + scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneWipe); + consumed = true; + } + scene_manager_set_scene_state(nfc_magic->scene_manager, NfcMagicSceneActions, event.event); + } else if(event.type == SceneManagerEventTypeBack) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc_magic->scene_manager, NfcMagicSceneStart); + } + + return consumed; +} + +void nfc_magic_scene_actions_on_exit(void* context) { + NfcMagic* nfc_magic = context; + submenu_reset(nfc_magic->submenu); +} diff --git a/applications/external/nfc_magic/scenes/nfc_magic_scene_check.c b/applications/external/nfc_magic/scenes/nfc_magic_scene_check.c index d51797242832..90b43d7d3a2e 100644 --- a/applications/external/nfc_magic/scenes/nfc_magic_scene_check.c +++ b/applications/external/nfc_magic/scenes/nfc_magic_scene_check.c @@ -42,7 +42,9 @@ void nfc_magic_scene_check_on_enter(void* context) { nfc_magic_worker_start( nfc_magic->worker, NfcMagicWorkerStateCheck, - &nfc_magic->nfc_dev->dev_data, + nfc_magic->dev, + &nfc_magic->source_dev->dev_data, + nfc_magic->new_password, nfc_magic_check_worker_callback, nfc_magic); nfc_magic_blink_start(nfc_magic); diff --git a/applications/external/nfc_magic/scenes/nfc_magic_scene_config.h b/applications/external/nfc_magic/scenes/nfc_magic_scene_config.h index 557e26914e61..2f9860d96f2a 100644 --- a/applications/external/nfc_magic/scenes/nfc_magic_scene_config.h +++ b/applications/external/nfc_magic/scenes/nfc_magic_scene_config.h @@ -1,4 +1,8 @@ ADD_SCENE(nfc_magic, start, Start) +ADD_SCENE(nfc_magic, key_input, KeyInput) +ADD_SCENE(nfc_magic, actions, Actions) +ADD_SCENE(nfc_magic, gen4_actions, Gen4Actions) +ADD_SCENE(nfc_magic, new_key_input, NewKeyInput) ADD_SCENE(nfc_magic, file_select, FileSelect) ADD_SCENE(nfc_magic, write_confirm, WriteConfirm) ADD_SCENE(nfc_magic, wrong_card, WrongCard) @@ -8,5 +12,7 @@ ADD_SCENE(nfc_magic, success, Success) ADD_SCENE(nfc_magic, check, Check) ADD_SCENE(nfc_magic, not_magic, NotMagic) ADD_SCENE(nfc_magic, magic_info, MagicInfo) +ADD_SCENE(nfc_magic, rekey, Rekey) +ADD_SCENE(nfc_magic, rekey_fail, RekeyFail) ADD_SCENE(nfc_magic, wipe, Wipe) ADD_SCENE(nfc_magic, wipe_fail, WipeFail) diff --git a/applications/external/nfc_magic/scenes/nfc_magic_scene_file_select.c b/applications/external/nfc_magic/scenes/nfc_magic_scene_file_select.c index d78422eeb663..baa6bcccc2d2 100644 --- a/applications/external/nfc_magic/scenes/nfc_magic_scene_file_select.c +++ b/applications/external/nfc_magic/scenes/nfc_magic_scene_file_select.c @@ -1,22 +1,60 @@ #include "../nfc_magic_i.h" -static bool nfc_magic_scene_file_select_is_file_suitable(NfcDevice* nfc_dev) { - return (nfc_dev->format == NfcDeviceSaveFormatMifareClassic) && - (nfc_dev->dev_data.mf_classic_data.type == MfClassicType1k) && - (nfc_dev->dev_data.nfc_data.uid_len == 4); +static bool nfc_magic_scene_file_select_is_file_suitable(NfcMagic* nfc_magic) { + NfcDevice* nfc_dev = nfc_magic->source_dev; + if(nfc_dev->format == NfcDeviceSaveFormatMifareClassic) { + switch(nfc_magic->dev->type) { + case MagicTypeClassicGen1: + case MagicTypeClassicDirectWrite: + case MagicTypeClassicAPDU: + if((nfc_dev->dev_data.mf_classic_data.type != MfClassicType1k) || + (nfc_dev->dev_data.nfc_data.uid_len != 4)) { + return false; + } + return true; + + case MagicTypeGen4: + return true; + default: + return false; + } + } else if( + (nfc_dev->format == NfcDeviceSaveFormatMifareUl) && + (nfc_dev->dev_data.nfc_data.uid_len == 7)) { + switch(nfc_magic->dev->type) { + case MagicTypeUltralightGen1: + case MagicTypeUltralightDirectWrite: + case MagicTypeUltralightC_Gen1: + case MagicTypeUltralightC_DirectWrite: + case MagicTypeGen4: + switch(nfc_dev->dev_data.mf_ul_data.type) { + case MfUltralightTypeNTAGI2C1K: + case MfUltralightTypeNTAGI2C2K: + case MfUltralightTypeNTAGI2CPlus1K: + case MfUltralightTypeNTAGI2CPlus2K: + return false; + default: + return true; + } + default: + return false; + } + } + + return false; } void nfc_magic_scene_file_select_on_enter(void* context) { NfcMagic* nfc_magic = context; // Process file_select return - nfc_device_set_loading_callback(nfc_magic->nfc_dev, nfc_magic_show_loading_popup, nfc_magic); + nfc_device_set_loading_callback( + nfc_magic->source_dev, nfc_magic_show_loading_popup, nfc_magic); - if(!furi_string_size(nfc_magic->nfc_dev->load_path)) { - furi_string_set_str(nfc_magic->nfc_dev->load_path, NFC_APP_FOLDER); + if(!furi_string_size(nfc_magic->source_dev->load_path)) { + furi_string_set_str(nfc_magic->source_dev->load_path, NFC_APP_FOLDER); } - - if(nfc_file_select(nfc_magic->nfc_dev)) { - if(nfc_magic_scene_file_select_is_file_suitable(nfc_magic->nfc_dev)) { + if(nfc_file_select(nfc_magic->source_dev)) { + if(nfc_magic_scene_file_select_is_file_suitable(nfc_magic)) { scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneWriteConfirm); } else { scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneWrongCard); @@ -34,5 +72,5 @@ bool nfc_magic_scene_file_select_on_event(void* context, SceneManagerEvent event void nfc_magic_scene_file_select_on_exit(void* context) { NfcMagic* nfc_magic = context; - nfc_device_set_loading_callback(nfc_magic->nfc_dev, NULL, nfc_magic); + nfc_device_set_loading_callback(nfc_magic->source_dev, NULL, nfc_magic); } diff --git a/applications/external/nfc_magic/scenes/nfc_magic_scene_gen4_actions.c b/applications/external/nfc_magic/scenes/nfc_magic_scene_gen4_actions.c new file mode 100644 index 000000000000..ceaa33e29f00 --- /dev/null +++ b/applications/external/nfc_magic/scenes/nfc_magic_scene_gen4_actions.c @@ -0,0 +1,70 @@ +#include "../nfc_magic_i.h" +enum SubmenuIndex { + SubmenuIndexWrite, + SubmenuIndexChangePassword, + SubmenuIndexWipe, +}; + +void nfc_magic_scene_gen4_actions_submenu_callback(void* context, uint32_t index) { + NfcMagic* nfc_magic = context; + view_dispatcher_send_custom_event(nfc_magic->view_dispatcher, index); +} + +void nfc_magic_scene_gen4_actions_on_enter(void* context) { + NfcMagic* nfc_magic = context; + + Submenu* submenu = nfc_magic->submenu; + submenu_add_item( + submenu, + "Write", + SubmenuIndexWrite, + nfc_magic_scene_gen4_actions_submenu_callback, + nfc_magic); + submenu_add_item( + submenu, + "Change password", + SubmenuIndexChangePassword, + nfc_magic_scene_gen4_actions_submenu_callback, + nfc_magic); + submenu_add_item( + submenu, + "Wipe", + SubmenuIndexWipe, + nfc_magic_scene_gen4_actions_submenu_callback, + nfc_magic); + + submenu_set_selected_item( + submenu, + scene_manager_get_scene_state(nfc_magic->scene_manager, NfcMagicSceneGen4Actions)); + view_dispatcher_switch_to_view(nfc_magic->view_dispatcher, NfcMagicViewMenu); +} + +bool nfc_magic_scene_gen4_actions_on_event(void* context, SceneManagerEvent event) { + NfcMagic* nfc_magic = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexWrite) { + scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneFileSelect); + consumed = true; + } else if(event.event == SubmenuIndexChangePassword) { + scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneNewKeyInput); + consumed = true; + } else if(event.event == SubmenuIndexWipe) { + scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneWipe); + consumed = true; + } + scene_manager_set_scene_state( + nfc_magic->scene_manager, NfcMagicSceneGen4Actions, event.event); + } else if(event.type == SceneManagerEventTypeBack) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc_magic->scene_manager, NfcMagicSceneStart); + } + + return consumed; +} + +void nfc_magic_scene_gen4_actions_on_exit(void* context) { + NfcMagic* nfc_magic = context; + submenu_reset(nfc_magic->submenu); +} diff --git a/applications/external/nfc_magic/scenes/nfc_magic_scene_key_input.c b/applications/external/nfc_magic/scenes/nfc_magic_scene_key_input.c new file mode 100644 index 000000000000..58b487a09bbe --- /dev/null +++ b/applications/external/nfc_magic/scenes/nfc_magic_scene_key_input.c @@ -0,0 +1,45 @@ +#include "../nfc_magic_i.h" + +void nfc_magic_scene_key_input_byte_input_callback(void* context) { + NfcMagic* nfc_magic = context; + + view_dispatcher_send_custom_event( + nfc_magic->view_dispatcher, NfcMagicCustomEventByteInputDone); +} + +void nfc_magic_scene_key_input_on_enter(void* context) { + NfcMagic* nfc_magic = context; + + // Setup view + ByteInput* byte_input = nfc_magic->byte_input; + byte_input_set_header_text(byte_input, "Enter the password in hex"); + byte_input_set_result_callback( + byte_input, + nfc_magic_scene_key_input_byte_input_callback, + NULL, + nfc_magic, + (uint8_t*)&nfc_magic->dev->password, + 4); + view_dispatcher_switch_to_view(nfc_magic->view_dispatcher, NfcMagicViewByteInput); +} + +bool nfc_magic_scene_key_input_on_event(void* context, SceneManagerEvent event) { + NfcMagic* nfc_magic = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcMagicCustomEventByteInputDone) { + scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneCheck); + consumed = true; + } + } + return consumed; +} + +void nfc_magic_scene_key_input_on_exit(void* context) { + NfcMagic* nfc_magic = context; + + // Clear view + byte_input_set_result_callback(nfc_magic->byte_input, NULL, NULL, NULL, NULL, 0); + byte_input_set_header_text(nfc_magic->byte_input, ""); +} diff --git a/applications/external/nfc_magic/scenes/nfc_magic_scene_magic_info.c b/applications/external/nfc_magic/scenes/nfc_magic_scene_magic_info.c index e9b226b3abb3..c147ac4383f6 100644 --- a/applications/external/nfc_magic/scenes/nfc_magic_scene_magic_info.c +++ b/applications/external/nfc_magic/scenes/nfc_magic_scene_magic_info.c @@ -1,4 +1,5 @@ #include "../nfc_magic_i.h" +#include "../lib/magic/types.h" void nfc_magic_scene_magic_info_widget_callback( GuiButtonType result, @@ -13,14 +14,18 @@ void nfc_magic_scene_magic_info_widget_callback( void nfc_magic_scene_magic_info_on_enter(void* context) { NfcMagic* nfc_magic = context; Widget* widget = nfc_magic->widget; + const char* card_type = nfc_magic_type(nfc_magic->dev->type); notification_message(nfc_magic->notifications, &sequence_success); widget_add_icon_element(widget, 73, 17, &I_DolphinCommon_56x48); widget_add_string_element( widget, 3, 4, AlignLeft, AlignTop, FontPrimary, "Magic card detected"); + widget_add_string_element(widget, 3, 17, AlignLeft, AlignTop, FontSecondary, card_type); widget_add_button_element( widget, GuiButtonTypeLeft, "Retry", nfc_magic_scene_magic_info_widget_callback, nfc_magic); + widget_add_button_element( + widget, GuiButtonTypeRight, "More", nfc_magic_scene_magic_info_widget_callback, nfc_magic); // Setup and start worker view_dispatcher_switch_to_view(nfc_magic->view_dispatcher, NfcMagicViewWidget); @@ -33,6 +38,15 @@ bool nfc_magic_scene_magic_info_on_event(void* context, SceneManagerEvent event) if(event.type == SceneManagerEventTypeCustom) { if(event.event == GuiButtonTypeLeft) { consumed = scene_manager_previous_scene(nfc_magic->scene_manager); + } else if(event.event == GuiButtonTypeRight) { + MagicType type = nfc_magic->dev->type; + if(type == MagicTypeGen4) { + scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneGen4Actions); + consumed = true; + } else { + scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneActions); + consumed = true; + } } } return consumed; diff --git a/applications/external/nfc_magic/scenes/nfc_magic_scene_new_key_input.c b/applications/external/nfc_magic/scenes/nfc_magic_scene_new_key_input.c new file mode 100644 index 000000000000..b5247f6c555c --- /dev/null +++ b/applications/external/nfc_magic/scenes/nfc_magic_scene_new_key_input.c @@ -0,0 +1,45 @@ +#include "../nfc_magic_i.h" + +void nfc_magic_scene_new_key_input_byte_input_callback(void* context) { + NfcMagic* nfc_magic = context; + + view_dispatcher_send_custom_event( + nfc_magic->view_dispatcher, NfcMagicCustomEventByteInputDone); +} + +void nfc_magic_scene_new_key_input_on_enter(void* context) { + NfcMagic* nfc_magic = context; + + // Setup view + ByteInput* byte_input = nfc_magic->byte_input; + byte_input_set_header_text(byte_input, "Enter the password in hex"); + byte_input_set_result_callback( + byte_input, + nfc_magic_scene_new_key_input_byte_input_callback, + NULL, + nfc_magic, + (uint8_t*)&nfc_magic->new_password, + 4); + view_dispatcher_switch_to_view(nfc_magic->view_dispatcher, NfcMagicViewByteInput); +} + +bool nfc_magic_scene_new_key_input_on_event(void* context, SceneManagerEvent event) { + NfcMagic* nfc_magic = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcMagicCustomEventByteInputDone) { + scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneRekey); + consumed = true; + } + } + return consumed; +} + +void nfc_magic_scene_new_key_input_on_exit(void* context) { + NfcMagic* nfc_magic = context; + + // Clear view + byte_input_set_result_callback(nfc_magic->byte_input, NULL, NULL, NULL, NULL, 0); + byte_input_set_header_text(nfc_magic->byte_input, ""); +} diff --git a/applications/external/nfc_magic/scenes/nfc_magic_scene_rekey.c b/applications/external/nfc_magic/scenes/nfc_magic_scene_rekey.c new file mode 100644 index 000000000000..259dc78eaa54 --- /dev/null +++ b/applications/external/nfc_magic/scenes/nfc_magic_scene_rekey.c @@ -0,0 +1,95 @@ +#include "../nfc_magic_i.h" + +enum { + NfcMagicSceneRekeyStateCardSearch, + NfcMagicSceneRekeyStateCardFound, +}; + +bool nfc_magic_rekey_worker_callback(NfcMagicWorkerEvent event, void* context) { + furi_assert(context); + + NfcMagic* nfc_magic = context; + view_dispatcher_send_custom_event(nfc_magic->view_dispatcher, event); + + return true; +} + +static void nfc_magic_scene_rekey_setup_view(NfcMagic* nfc_magic) { + Popup* popup = nfc_magic->popup; + popup_reset(popup); + uint32_t state = scene_manager_get_scene_state(nfc_magic->scene_manager, NfcMagicSceneRekey); + + if(state == NfcMagicSceneRekeyStateCardSearch) { + popup_set_text( + nfc_magic->popup, + "Apply the\nsame card\nto the back", + 128, + 32, + AlignRight, + AlignCenter); + popup_set_icon(nfc_magic->popup, 0, 8, &I_NFC_manual_60x50); + } else { + popup_set_icon(popup, 12, 23, &I_Loading_24); + popup_set_header(popup, "Writing\nDon't move...", 52, 32, AlignLeft, AlignCenter); + } + + view_dispatcher_switch_to_view(nfc_magic->view_dispatcher, NfcMagicViewPopup); +} + +void nfc_magic_scene_rekey_on_enter(void* context) { + NfcMagic* nfc_magic = context; + + scene_manager_set_scene_state( + nfc_magic->scene_manager, NfcMagicSceneRekey, NfcMagicSceneRekeyStateCardSearch); + nfc_magic_scene_rekey_setup_view(nfc_magic); + + // Setup and start worker + nfc_magic_worker_start( + nfc_magic->worker, + NfcMagicWorkerStateRekey, + nfc_magic->dev, + &nfc_magic->source_dev->dev_data, + nfc_magic->new_password, + nfc_magic_rekey_worker_callback, + nfc_magic); + nfc_magic_blink_start(nfc_magic); +} + +bool nfc_magic_scene_rekey_on_event(void* context, SceneManagerEvent event) { + NfcMagic* nfc_magic = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcMagicWorkerEventSuccess) { + nfc_magic->dev->password = nfc_magic->new_password; + scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneSuccess); + consumed = true; + } else if(event.event == NfcMagicWorkerEventFail) { + scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneRekeyFail); + consumed = true; + } else if(event.event == NfcMagicWorkerEventCardDetected) { + scene_manager_set_scene_state( + nfc_magic->scene_manager, NfcMagicSceneRekey, NfcMagicSceneRekeyStateCardFound); + nfc_magic_scene_rekey_setup_view(nfc_magic); + consumed = true; + } else if(event.event == NfcMagicWorkerEventNoCardDetected) { + scene_manager_set_scene_state( + nfc_magic->scene_manager, NfcMagicSceneRekey, NfcMagicSceneRekeyStateCardSearch); + nfc_magic_scene_rekey_setup_view(nfc_magic); + consumed = true; + } + } + return consumed; +} + +void nfc_magic_scene_rekey_on_exit(void* context) { + NfcMagic* nfc_magic = context; + + nfc_magic_worker_stop(nfc_magic->worker); + scene_manager_set_scene_state( + nfc_magic->scene_manager, NfcMagicSceneRekey, NfcMagicSceneRekeyStateCardSearch); + // Clear view + popup_reset(nfc_magic->popup); + + nfc_magic_blink_stop(nfc_magic); +} diff --git a/applications/external/nfc_magic/scenes/nfc_magic_scene_rekey_fail.c b/applications/external/nfc_magic/scenes/nfc_magic_scene_rekey_fail.c new file mode 100644 index 000000000000..d30ee57bcfc9 --- /dev/null +++ b/applications/external/nfc_magic/scenes/nfc_magic_scene_rekey_fail.c @@ -0,0 +1,50 @@ +#include "../nfc_magic_i.h" + +void nfc_magic_scene_rekey_fail_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + NfcMagic* nfc_magic = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(nfc_magic->view_dispatcher, result); + } +} + +void nfc_magic_scene_rekey_fail_on_enter(void* context) { + NfcMagic* nfc_magic = context; + Widget* widget = nfc_magic->widget; + + notification_message(nfc_magic->notifications, &sequence_error); + + widget_add_icon_element(widget, 72, 17, &I_DolphinCommon_56x48); + widget_add_string_element( + widget, 7, 4, AlignLeft, AlignTop, FontPrimary, "Can't change password!"); + + widget_add_button_element( + widget, GuiButtonTypeLeft, "Finish", nfc_magic_scene_rekey_fail_widget_callback, nfc_magic); + + // Setup and start worker + view_dispatcher_switch_to_view(nfc_magic->view_dispatcher, NfcMagicViewWidget); +} + +bool nfc_magic_scene_rekey_fail_on_event(void* context, SceneManagerEvent event) { + NfcMagic* nfc_magic = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeLeft) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc_magic->scene_manager, NfcMagicSceneStart); + } + } else if(event.type == SceneManagerEventTypeBack) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc_magic->scene_manager, NfcMagicSceneStart); + } + return consumed; +} + +void nfc_magic_scene_rekey_fail_on_exit(void* context) { + NfcMagic* nfc_magic = context; + + widget_reset(nfc_magic->widget); +} diff --git a/applications/external/nfc_magic/scenes/nfc_magic_scene_start.c b/applications/external/nfc_magic/scenes/nfc_magic_scene_start.c index a70eb8accfe7..b5861629e432 100644 --- a/applications/external/nfc_magic/scenes/nfc_magic_scene_start.c +++ b/applications/external/nfc_magic/scenes/nfc_magic_scene_start.c @@ -1,8 +1,7 @@ #include "../nfc_magic_i.h" enum SubmenuIndex { SubmenuIndexCheck, - SubmenuIndexWriteGen1A, - SubmenuIndexWipe, + SubmenuIndexAuthenticateGen4, }; void nfc_magic_scene_start_submenu_callback(void* context, uint32_t index) { @@ -22,12 +21,10 @@ void nfc_magic_scene_start_on_enter(void* context) { nfc_magic); submenu_add_item( submenu, - "Write Gen1A", - SubmenuIndexWriteGen1A, + "Authenticate Gen4", + SubmenuIndexAuthenticateGen4, nfc_magic_scene_start_submenu_callback, nfc_magic); - submenu_add_item( - submenu, "Wipe", SubmenuIndexWipe, nfc_magic_scene_start_submenu_callback, nfc_magic); submenu_set_selected_item( submenu, scene_manager_get_scene_state(nfc_magic->scene_manager, NfcMagicSceneStart)); @@ -40,23 +37,13 @@ bool nfc_magic_scene_start_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubmenuIndexCheck) { + nfc_magic->dev->password = MAGIC_GEN4_DEFAULT_PWD; scene_manager_set_scene_state( nfc_magic->scene_manager, NfcMagicSceneStart, SubmenuIndexCheck); scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneCheck); consumed = true; - } else if(event.event == SubmenuIndexWriteGen1A) { - // Explicitly save state in each branch so that the - // correct option is reselected if the user cancels - // loading a file. - scene_manager_set_scene_state( - nfc_magic->scene_manager, NfcMagicSceneStart, SubmenuIndexWriteGen1A); - scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneFileSelect); - consumed = true; - } else if(event.event == SubmenuIndexWipe) { - scene_manager_set_scene_state( - nfc_magic->scene_manager, NfcMagicSceneStart, SubmenuIndexWipe); - scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneWipe); - consumed = true; + } else if(event.event == SubmenuIndexAuthenticateGen4) { + scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneKeyInput); } } diff --git a/applications/external/nfc_magic/scenes/nfc_magic_scene_wipe.c b/applications/external/nfc_magic/scenes/nfc_magic_scene_wipe.c index 1ca194286ad6..29640f89c6b5 100644 --- a/applications/external/nfc_magic/scenes/nfc_magic_scene_wipe.c +++ b/applications/external/nfc_magic/scenes/nfc_magic_scene_wipe.c @@ -22,7 +22,12 @@ static void nfc_magic_scene_wipe_setup_view(NfcMagic* nfc_magic) { if(state == NfcMagicSceneWipeStateCardSearch) { popup_set_icon(nfc_magic->popup, 0, 8, &I_NFC_manual_60x50); popup_set_text( - nfc_magic->popup, "Apply card to\nthe back", 128, 32, AlignRight, AlignCenter); + nfc_magic->popup, + "Apply the\nsame card\nto the back", + 128, + 32, + AlignRight, + AlignCenter); } else { popup_set_icon(popup, 12, 23, &I_Loading_24); popup_set_header(popup, "Wiping\nDon't move...", 52, 32, AlignLeft, AlignCenter); @@ -42,7 +47,9 @@ void nfc_magic_scene_wipe_on_enter(void* context) { nfc_magic_worker_start( nfc_magic->worker, NfcMagicWorkerStateWipe, - &nfc_magic->nfc_dev->dev_data, + nfc_magic->dev, + &nfc_magic->source_dev->dev_data, + nfc_magic->new_password, nfc_magic_wipe_worker_callback, nfc_magic); nfc_magic_blink_start(nfc_magic); diff --git a/applications/external/nfc_magic/scenes/nfc_magic_scene_write.c b/applications/external/nfc_magic/scenes/nfc_magic_scene_write.c index c3e6f962a344..45c54557f156 100644 --- a/applications/external/nfc_magic/scenes/nfc_magic_scene_write.c +++ b/applications/external/nfc_magic/scenes/nfc_magic_scene_write.c @@ -21,7 +21,12 @@ static void nfc_magic_scene_write_setup_view(NfcMagic* nfc_magic) { if(state == NfcMagicSceneWriteStateCardSearch) { popup_set_text( - nfc_magic->popup, "Apply card to\nthe back", 128, 32, AlignRight, AlignCenter); + nfc_magic->popup, + "Apply the\nsame card\nto the back", + 128, + 32, + AlignRight, + AlignCenter); popup_set_icon(nfc_magic->popup, 0, 8, &I_NFC_manual_60x50); } else { popup_set_icon(popup, 12, 23, &I_Loading_24); @@ -42,7 +47,9 @@ void nfc_magic_scene_write_on_enter(void* context) { nfc_magic_worker_start( nfc_magic->worker, NfcMagicWorkerStateWrite, - &nfc_magic->nfc_dev->dev_data, + nfc_magic->dev, + &nfc_magic->source_dev->dev_data, + nfc_magic->new_password, nfc_magic_write_worker_callback, nfc_magic); nfc_magic_blink_start(nfc_magic); diff --git a/applications/external/nfc_magic/scenes/nfc_magic_scene_wrong_card.c b/applications/external/nfc_magic/scenes/nfc_magic_scene_wrong_card.c index 4b80896932da..857d50c1f7d7 100644 --- a/applications/external/nfc_magic/scenes/nfc_magic_scene_wrong_card.c +++ b/applications/external/nfc_magic/scenes/nfc_magic_scene_wrong_card.c @@ -26,7 +26,7 @@ void nfc_magic_scene_wrong_card_on_enter(void* context) { AlignLeft, AlignTop, FontSecondary, - "Writing is supported\nonly for 4 bytes UID\nMifare Classic 1k"); + "Writing this file is\nnot supported for\nthis magic card."); widget_add_button_element( widget, GuiButtonTypeLeft, "Retry", nfc_magic_scene_wrong_card_widget_callback, nfc_magic); diff --git a/applications/external/picopass/scenes/picopass_scene_device_info.c b/applications/external/picopass/scenes/picopass_scene_device_info.c index 41caeabf5adc..bb149aa6b378 100644 --- a/applications/external/picopass/scenes/picopass_scene_device_info.c +++ b/applications/external/picopass/scenes/picopass_scene_device_info.c @@ -19,7 +19,7 @@ void picopass_scene_device_info_on_enter(void* context) { FuriString* wiegand_str = furi_string_alloc(); FuriString* sio_str = furi_string_alloc(); - DOLPHIN_DEED(DolphinDeedNfcReadSuccess); + dolphin_deed(DolphinDeedNfcReadSuccess); // Setup view PicopassBlock* AA1 = picopass->dev->dev_data.AA1; diff --git a/applications/external/picopass/scenes/picopass_scene_read_card.c b/applications/external/picopass/scenes/picopass_scene_read_card.c index 96ec7c668b96..c1cc7249c428 100644 --- a/applications/external/picopass/scenes/picopass_scene_read_card.c +++ b/applications/external/picopass/scenes/picopass_scene_read_card.c @@ -10,7 +10,7 @@ void picopass_read_card_worker_callback(PicopassWorkerEvent event, void* context void picopass_scene_read_card_on_enter(void* context) { Picopass* picopass = context; - DOLPHIN_DEED(DolphinDeedNfcRead); + dolphin_deed(DolphinDeedNfcRead); // Setup view Popup* popup = picopass->popup; diff --git a/applications/external/picopass/scenes/picopass_scene_read_card_success.c b/applications/external/picopass/scenes/picopass_scene_read_card_success.c index cc18ac066a0c..ffe7195b7928 100644 --- a/applications/external/picopass/scenes/picopass_scene_read_card_success.c +++ b/applications/external/picopass/scenes/picopass_scene_read_card_success.c @@ -21,7 +21,7 @@ void picopass_scene_read_card_success_on_enter(void* context) { FuriString* wiegand_str = furi_string_alloc(); FuriString* sio_str = furi_string_alloc(); - DOLPHIN_DEED(DolphinDeedNfcReadSuccess); + dolphin_deed(DolphinDeedNfcReadSuccess); // Send notification notification_message(picopass->notifications, &sequence_success); diff --git a/applications/external/picopass/scenes/picopass_scene_read_factory_success.c b/applications/external/picopass/scenes/picopass_scene_read_factory_success.c index bc07bb95302e..f5fcd10fda1f 100644 --- a/applications/external/picopass/scenes/picopass_scene_read_factory_success.c +++ b/applications/external/picopass/scenes/picopass_scene_read_factory_success.c @@ -19,7 +19,7 @@ void picopass_scene_read_factory_success_on_enter(void* context) { FuriString* title = furi_string_alloc_set("Factory Default"); FuriString* subtitle = furi_string_alloc_set(""); - DOLPHIN_DEED(DolphinDeedNfcReadSuccess); + dolphin_deed(DolphinDeedNfcReadSuccess); // Send notification notification_message(picopass->notifications, &sequence_success); diff --git a/applications/external/picopass/scenes/picopass_scene_save_success.c b/applications/external/picopass/scenes/picopass_scene_save_success.c index e92d91fb4400..3b0a1cadd257 100644 --- a/applications/external/picopass/scenes/picopass_scene_save_success.c +++ b/applications/external/picopass/scenes/picopass_scene_save_success.c @@ -8,7 +8,7 @@ void picopass_scene_save_success_popup_callback(void* context) { void picopass_scene_save_success_on_enter(void* context) { Picopass* picopass = context; - DOLPHIN_DEED(DolphinDeedNfcSave); + dolphin_deed(DolphinDeedNfcSave); // Setup view Popup* popup = picopass->popup; diff --git a/applications/external/picopass/scenes/picopass_scene_write_card.c b/applications/external/picopass/scenes/picopass_scene_write_card.c index a905dca95566..ce396fc10e12 100644 --- a/applications/external/picopass/scenes/picopass_scene_write_card.c +++ b/applications/external/picopass/scenes/picopass_scene_write_card.c @@ -9,7 +9,7 @@ void picopass_write_card_worker_callback(PicopassWorkerEvent event, void* contex void picopass_scene_write_card_on_enter(void* context) { Picopass* picopass = context; - DOLPHIN_DEED(DolphinDeedNfcSave); + dolphin_deed(DolphinDeedNfcSave); // Setup view Popup* popup = picopass->popup; diff --git a/applications/external/picopass/scenes/picopass_scene_write_card_success.c b/applications/external/picopass/scenes/picopass_scene_write_card_success.c index 4bbca816aa29..cd760272fe9a 100644 --- a/applications/external/picopass/scenes/picopass_scene_write_card_success.c +++ b/applications/external/picopass/scenes/picopass_scene_write_card_success.c @@ -18,7 +18,7 @@ void picopass_scene_write_card_success_on_enter(void* context) { Widget* widget = picopass->widget; FuriString* str = furi_string_alloc_set("Write Success!"); - DOLPHIN_DEED(DolphinDeedNfcReadSuccess); + dolphin_deed(DolphinDeedNfcReadSuccess); // Send notification notification_message(picopass->notifications, &sequence_success); diff --git a/applications/external/picopass/scenes/picopass_scene_write_key.c b/applications/external/picopass/scenes/picopass_scene_write_key.c index 0f417e1c3fe8..806a2b5a8561 100644 --- a/applications/external/picopass/scenes/picopass_scene_write_key.c +++ b/applications/external/picopass/scenes/picopass_scene_write_key.c @@ -9,7 +9,7 @@ void picopass_write_key_worker_callback(PicopassWorkerEvent event, void* context void picopass_scene_write_key_on_enter(void* context) { Picopass* picopass = context; - DOLPHIN_DEED(DolphinDeedNfcSave); + dolphin_deed(DolphinDeedNfcSave); // Setup view Popup* popup = picopass->popup; diff --git a/applications/external/snake_game/snake_game.c b/applications/external/snake_game/snake_game.c index 3cf9b6d53d02..6852cb215b28 100644 --- a/applications/external/snake_game/snake_game.c +++ b/applications/external/snake_game/snake_game.c @@ -346,7 +346,7 @@ int32_t snake_game_app(void* p) { notification_message_block(notification, &sequence_display_backlight_enforce_on); - DOLPHIN_DEED(DolphinDeedPluginGameStart); + dolphin_deed(DolphinDeedPluginGameStart); SnakeEvent event; for(bool processing = true; processing;) { diff --git a/applications/external/weather_station/protocols/oregon3.c b/applications/external/weather_station/protocols/oregon3.c new file mode 100644 index 000000000000..a211c5ad326f --- /dev/null +++ b/applications/external/weather_station/protocols/oregon3.c @@ -0,0 +1,365 @@ +#include "oregon3.h" + +#include +#include +#include +#include +#include "ws_generic.h" + +#include +#include + +#define TAG "WSProtocolOregon3" + +static const SubGhzBlockConst ws_oregon3_const = { + .te_long = 1100, + .te_short = 500, + .te_delta = 300, + .min_count_bit_for_found = 32, +}; + +#define OREGON3_PREAMBLE_BITS 28 +#define OREGON3_PREAMBLE_MASK 0b1111111111111111111111111111 +// 24 ones + 0101 (inverted A) +#define OREGON3_PREAMBLE 0b1111111111111111111111110101 + +// Fixed part contains: +// - Sensor type: 16 bits +// - Channel: 4 bits +// - ID (changes when batteries are changed): 8 bits +// - Battery status: 4 bits +#define OREGON3_FIXED_PART_BITS (16 + 4 + 8 + 4) +#define OREGON3_SENSOR_ID(d) (((d) >> 16) & 0xFFFF) +#define OREGON3_CHECKSUM_BITS 8 + +// bit indicating the low battery +#define OREGON3_FLAG_BAT_LOW 0x4 + +/// Documentation for Oregon Scientific protocols can be found here: +/// https://www.osengr.org/Articles/OS-RF-Protocols-IV.pdf +// Sensors ID +#define ID_THGR221 0xf824 + +struct WSProtocolDecoderOregon3 { + SubGhzProtocolDecoderBase base; + + SubGhzBlockDecoder decoder; + WSBlockGeneric generic; + ManchesterState manchester_state; + bool prev_bit; + + uint8_t var_bits; + uint64_t var_data; +}; + +typedef struct WSProtocolDecoderOregon3 WSProtocolDecoderOregon3; + +typedef enum { + Oregon3DecoderStepReset = 0, + Oregon3DecoderStepFoundPreamble, + Oregon3DecoderStepVarData, +} Oregon3DecoderStep; + +void* ws_protocol_decoder_oregon3_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + WSProtocolDecoderOregon3* instance = malloc(sizeof(WSProtocolDecoderOregon3)); + instance->base.protocol = &ws_protocol_oregon3; + instance->generic.protocol_name = instance->base.protocol->name; + instance->generic.humidity = WS_NO_HUMIDITY; + instance->generic.temp = WS_NO_TEMPERATURE; + instance->generic.btn = WS_NO_BTN; + instance->generic.channel = WS_NO_CHANNEL; + instance->generic.battery_low = WS_NO_BATT; + instance->generic.id = WS_NO_ID; + instance->prev_bit = false; + return instance; +} + +void ws_protocol_decoder_oregon3_free(void* context) { + furi_assert(context); + WSProtocolDecoderOregon3* instance = context; + free(instance); +} + +void ws_protocol_decoder_oregon3_reset(void* context) { + furi_assert(context); + WSProtocolDecoderOregon3* instance = context; + instance->decoder.parser_step = Oregon3DecoderStepReset; + instance->decoder.decode_data = 0UL; + instance->decoder.decode_count_bit = 0; + manchester_advance( + instance->manchester_state, ManchesterEventReset, &instance->manchester_state, NULL); + instance->prev_bit = false; + instance->var_data = 0; + instance->var_bits = 0; +} + +static ManchesterEvent level_and_duration_to_event(bool level, uint32_t duration) { + bool is_long = false; + + if(DURATION_DIFF(duration, ws_oregon3_const.te_long) < ws_oregon3_const.te_delta) { + is_long = true; + } else if(DURATION_DIFF(duration, ws_oregon3_const.te_short) < ws_oregon3_const.te_delta) { + is_long = false; + } else { + return ManchesterEventReset; + } + + if(level) + return is_long ? ManchesterEventLongHigh : ManchesterEventShortHigh; + else + return is_long ? ManchesterEventLongLow : ManchesterEventShortLow; +} + +// From sensor id code return amount of bits in variable section +// https://temofeev.ru/info/articles/o-dekodirovanii-protokola-pogodnykh-datchikov-oregon-scientific +static uint8_t oregon3_sensor_id_var_bits(uint16_t sensor_id) { + switch(sensor_id) { + case ID_THGR221: + default: + // nibbles: temp + hum + '0' + return (4 + 2 + 1) * 4; + } +} + +static void ws_oregon3_decode_const_data(WSBlockGeneric* ws_block) { + ws_block->id = OREGON3_SENSOR_ID(ws_block->data); + ws_block->channel = (ws_block->data >> 12) & 0xF; + ws_block->battery_low = (ws_block->data & OREGON3_FLAG_BAT_LOW) ? 1 : 0; +} + +static uint16_t ws_oregon3_bcd_decode_short(uint32_t data) { + return (data & 0xF) * 10 + ((data >> 4) & 0xF); +} + +static float ws_oregon3_decode_temp(uint32_t data) { + int32_t temp_val; + temp_val = ws_oregon3_bcd_decode_short(data >> 4); + temp_val *= 10; + temp_val += (data >> 12) & 0xF; + if(data & 0xF) temp_val = -temp_val; + return (float)temp_val / 10.0; +} + +static void ws_oregon3_decode_var_data(WSBlockGeneric* ws_b, uint16_t sensor_id, uint32_t data) { + switch(sensor_id) { + case ID_THGR221: + default: + ws_b->humidity = ws_oregon3_bcd_decode_short(data >> 4); + ws_b->temp = ws_oregon3_decode_temp(data >> 12); + break; + } +} + +void ws_protocol_decoder_oregon3_feed(void* context, bool level, uint32_t duration) { + furi_assert(context); + WSProtocolDecoderOregon3* instance = context; + // Oregon v3.0 protocol is inverted + ManchesterEvent event = level_and_duration_to_event(!level, duration); + + // low-level bit sequence decoding + if(event == ManchesterEventReset) { + instance->decoder.parser_step = Oregon3DecoderStepReset; + instance->prev_bit = false; + instance->decoder.decode_data = 0UL; + instance->decoder.decode_count_bit = 0; + } + if(manchester_advance( + instance->manchester_state, event, &instance->manchester_state, &instance->prev_bit)) { + subghz_protocol_blocks_add_bit(&instance->decoder, instance->prev_bit); + } + + switch(instance->decoder.parser_step) { + case Oregon3DecoderStepReset: + // waiting for fixed oregon3 preamble + if(instance->decoder.decode_count_bit >= OREGON3_PREAMBLE_BITS && + ((instance->decoder.decode_data & OREGON3_PREAMBLE_MASK) == OREGON3_PREAMBLE)) { + instance->decoder.parser_step = Oregon3DecoderStepFoundPreamble; + instance->decoder.decode_count_bit = 0; + instance->decoder.decode_data = 0UL; + } + break; + case Oregon3DecoderStepFoundPreamble: + // waiting for fixed oregon3 data + if(instance->decoder.decode_count_bit == OREGON3_FIXED_PART_BITS) { + instance->generic.data = instance->decoder.decode_data; + instance->generic.data_count_bit = instance->decoder.decode_count_bit; + instance->decoder.decode_data = 0UL; + instance->decoder.decode_count_bit = 0; + + // reverse nibbles in decoded data as oregon v3.0 is LSB first + instance->generic.data = (instance->generic.data & 0x55555555) << 1 | + (instance->generic.data & 0xAAAAAAAA) >> 1; + instance->generic.data = (instance->generic.data & 0x33333333) << 2 | + (instance->generic.data & 0xCCCCCCCC) >> 2; + + ws_oregon3_decode_const_data(&instance->generic); + instance->var_bits = + oregon3_sensor_id_var_bits(OREGON3_SENSOR_ID(instance->generic.data)); + + if(!instance->var_bits) { + // sensor is not supported, stop decoding, but showing the decoded fixed part + instance->decoder.parser_step = Oregon3DecoderStepReset; + if(instance->base.callback) + instance->base.callback(&instance->base, instance->base.context); + } else { + instance->decoder.parser_step = Oregon3DecoderStepVarData; + } + } + break; + case Oregon3DecoderStepVarData: + // waiting for variable (sensor-specific data) + if(instance->decoder.decode_count_bit == instance->var_bits + OREGON3_CHECKSUM_BITS) { + instance->var_data = instance->decoder.decode_data & 0xFFFFFFFFFFFFFFFF; + + // reverse nibbles in var data + instance->var_data = (instance->var_data & 0x5555555555555555) << 1 | + (instance->var_data & 0xAAAAAAAAAAAAAAAA) >> 1; + instance->var_data = (instance->var_data & 0x3333333333333333) << 2 | + (instance->var_data & 0xCCCCCCCCCCCCCCCC) >> 2; + + ws_oregon3_decode_var_data( + &instance->generic, + OREGON3_SENSOR_ID(instance->generic.data), + instance->var_data >> OREGON3_CHECKSUM_BITS); + + instance->decoder.parser_step = Oregon3DecoderStepReset; + if(instance->base.callback) + instance->base.callback(&instance->base, instance->base.context); + } + break; + } +} + +uint8_t ws_protocol_decoder_oregon3_get_hash_data(void* context) { + furi_assert(context); + WSProtocolDecoderOregon3* instance = context; + return subghz_protocol_blocks_get_hash_data( + &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); +} + +SubGhzProtocolStatus ws_protocol_decoder_oregon3_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzRadioPreset* preset) { + furi_assert(context); + WSProtocolDecoderOregon3* instance = context; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; + ret = ws_block_generic_serialize(&instance->generic, flipper_format, preset); + if(ret != SubGhzProtocolStatusOk) return ret; + uint32_t temp = instance->var_bits; + if(!flipper_format_write_uint32(flipper_format, "VarBits", &temp, 1)) { + FURI_LOG_E(TAG, "Error adding VarBits"); + return SubGhzProtocolStatusErrorParserOthers; + } + if(!flipper_format_write_hex( + flipper_format, + "VarData", + (const uint8_t*)&instance->var_data, + sizeof(instance->var_data))) { + FURI_LOG_E(TAG, "Error adding VarData"); + return SubGhzProtocolStatusErrorParserOthers; + } + return ret; +} + +SubGhzProtocolStatus + ws_protocol_decoder_oregon3_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + WSProtocolDecoderOregon3* instance = context; + uint32_t temp_data; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; + do { + ret = ws_block_generic_deserialize(&instance->generic, flipper_format); + if(ret != SubGhzProtocolStatusOk) { + break; + } + if(!flipper_format_read_uint32(flipper_format, "VarBits", &temp_data, 1)) { + FURI_LOG_E(TAG, "Missing VarLen"); + ret = SubGhzProtocolStatusErrorParserOthers; + break; + } + instance->var_bits = (uint8_t)temp_data; + if(!flipper_format_read_hex( + flipper_format, + "VarData", + (uint8_t*)&instance->var_data, + sizeof(instance->var_data))) { //-V1051 + FURI_LOG_E(TAG, "Missing VarData"); + ret = SubGhzProtocolStatusErrorParserOthers; + break; + } + if(instance->generic.data_count_bit != ws_oregon3_const.min_count_bit_for_found) { + FURI_LOG_E(TAG, "Wrong number of bits in key: %d", instance->generic.data_count_bit); + ret = SubGhzProtocolStatusErrorValueBitCount; + break; + } + } while(false); + return ret; +} + +static void oregon3_append_check_sum(uint32_t fix_data, uint64_t var_data, FuriString* output) { + uint8_t sum = fix_data & 0xF; + uint8_t ref_sum = var_data & 0xFF; + var_data >>= 4; + + for(uint8_t i = 1; i < 8; i++) { + fix_data >>= 4; + var_data >>= 4; + sum += (fix_data & 0xF) + (var_data & 0xF); + } + + // swap calculated sum nibbles + sum = (((sum >> 4) & 0xF) | (sum << 4)) & 0xFF; + if(sum == ref_sum) + furi_string_cat_printf(output, "Sum ok: 0x%hhX", ref_sum); + else + furi_string_cat_printf(output, "Sum err: 0x%hhX vs 0x%hhX", ref_sum, sum); +} + +void ws_protocol_decoder_oregon3_get_string(void* context, FuriString* output) { + furi_assert(context); + WSProtocolDecoderOregon3* instance = context; + furi_string_cat_printf( + output, + "%s\r\n" + "ID: 0x%04lX, ch: %d, bat: %d, rc: 0x%02lX\r\n", + instance->generic.protocol_name, + instance->generic.id, + instance->generic.channel, + instance->generic.battery_low, + (uint32_t)(instance->generic.data >> 4) & 0xFF); + + if(instance->var_bits > 0) { + furi_string_cat_printf( + output, + "Temp:%d.%d C Hum:%d%%", + (int16_t)instance->generic.temp, + abs( + ((int16_t)(instance->generic.temp * 10) - + (((int16_t)instance->generic.temp) * 10))), + instance->generic.humidity); + oregon3_append_check_sum((uint32_t)instance->generic.data, instance->var_data, output); + } +} + +const SubGhzProtocolDecoder ws_protocol_oregon3_decoder = { + .alloc = ws_protocol_decoder_oregon3_alloc, + .free = ws_protocol_decoder_oregon3_free, + + .feed = ws_protocol_decoder_oregon3_feed, + .reset = ws_protocol_decoder_oregon3_reset, + + .get_hash_data = ws_protocol_decoder_oregon3_get_hash_data, + .serialize = ws_protocol_decoder_oregon3_serialize, + .deserialize = ws_protocol_decoder_oregon3_deserialize, + .get_string = ws_protocol_decoder_oregon3_get_string, +}; + +const SubGhzProtocol ws_protocol_oregon3 = { + .name = WS_PROTOCOL_OREGON3_NAME, + .type = SubGhzProtocolWeatherStation, + .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable, + + .decoder = &ws_protocol_oregon3_decoder, +}; diff --git a/applications/external/weather_station/protocols/oregon3.h b/applications/external/weather_station/protocols/oregon3.h new file mode 100644 index 000000000000..ec51ddb00014 --- /dev/null +++ b/applications/external/weather_station/protocols/oregon3.h @@ -0,0 +1,6 @@ +#pragma once + +#include + +#define WS_PROTOCOL_OREGON3_NAME "Oregon3" +extern const SubGhzProtocol ws_protocol_oregon3; diff --git a/applications/external/weather_station/protocols/protocol_items.c b/applications/external/weather_station/protocols/protocol_items.c index cd4bae76dc28..93dc25488ddb 100644 --- a/applications/external/weather_station/protocols/protocol_items.c +++ b/applications/external/weather_station/protocols/protocol_items.c @@ -11,6 +11,7 @@ const SubGhzProtocol* weather_station_protocol_registry_items[] = { &ws_protocol_lacrosse_tx, &ws_protocol_lacrosse_tx141thbv2, &ws_protocol_oregon2, + &ws_protocol_oregon3, &ws_protocol_acurite_592txr, &ws_protocol_ambient_weather, &ws_protocol_auriol_th, @@ -21,4 +22,4 @@ const SubGhzProtocol* weather_station_protocol_registry_items[] = { const SubGhzProtocolRegistry weather_station_protocol_registry = { .items = weather_station_protocol_registry_items, - .size = COUNT_OF(weather_station_protocol_registry_items)}; \ No newline at end of file + .size = COUNT_OF(weather_station_protocol_registry_items)}; diff --git a/applications/external/weather_station/protocols/protocol_items.h b/applications/external/weather_station/protocols/protocol_items.h index 0398c11f256b..712eb07f2210 100644 --- a/applications/external/weather_station/protocols/protocol_items.h +++ b/applications/external/weather_station/protocols/protocol_items.h @@ -11,6 +11,7 @@ #include "lacrosse_tx.h" #include "lacrosse_tx141thbv2.h" #include "oregon2.h" +#include "oregon3.h" #include "acurite_592txr.h" #include "ambient_weather.h" #include "auriol_hg0601a.h" diff --git a/applications/main/bad_usb/helpers/ducky_script.c b/applications/main/bad_usb/helpers/ducky_script.c index 47d8a7e0517f..f194178a067e 100644 --- a/applications/main/bad_usb/helpers/ducky_script.c +++ b/applications/main/bad_usb/helpers/ducky_script.c @@ -16,10 +16,11 @@ (((uint8_t)x < 128) ? (script->layout[(uint8_t)x]) : HID_KEYBOARD_NONE) typedef enum { - WorkerEvtToggle = (1 << 0), - WorkerEvtEnd = (1 << 1), - WorkerEvtConnect = (1 << 2), - WorkerEvtDisconnect = (1 << 3), + WorkerEvtStartStop = (1 << 0), + WorkerEvtPauseResume = (1 << 1), + WorkerEvtEnd = (1 << 2), + WorkerEvtConnect = (1 << 3), + WorkerEvtDisconnect = (1 << 4), } WorkerEvtFlags; static const char ducky_cmd_id[] = {"ID"}; @@ -372,6 +373,7 @@ static int32_t bad_usb_worker(void* context) { BadUsbScript* bad_usb = context; BadUsbWorkerState worker_state = BadUsbStateInit; + BadUsbWorkerState pause_state = BadUsbStateRunning; int32_t delay_val = 0; FURI_LOG_I(WORKER_TAG, "Init"); @@ -406,25 +408,25 @@ static int32_t bad_usb_worker(void* context) { } else if(worker_state == BadUsbStateNotConnected) { // State: USB not connected uint32_t flags = bad_usb_flags_get( - WorkerEvtEnd | WorkerEvtConnect | WorkerEvtToggle, FuriWaitForever); + WorkerEvtEnd | WorkerEvtConnect | WorkerEvtStartStop, FuriWaitForever); if(flags & WorkerEvtEnd) { break; } else if(flags & WorkerEvtConnect) { worker_state = BadUsbStateIdle; // Ready to run - } else if(flags & WorkerEvtToggle) { + } else if(flags & WorkerEvtStartStop) { worker_state = BadUsbStateWillRun; // Will run when USB is connected } bad_usb->st.state = worker_state; } else if(worker_state == BadUsbStateIdle) { // State: ready to start uint32_t flags = bad_usb_flags_get( - WorkerEvtEnd | WorkerEvtToggle | WorkerEvtDisconnect, FuriWaitForever); + WorkerEvtEnd | WorkerEvtStartStop | WorkerEvtDisconnect, FuriWaitForever); if(flags & WorkerEvtEnd) { break; - } else if(flags & WorkerEvtToggle) { // Start executing script - DOLPHIN_DEED(DolphinDeedBadUsbPlayScript); + } else if(flags & WorkerEvtStartStop) { // Start executing script + dolphin_deed(DolphinDeedBadUsbPlayScript); delay_val = 0; bad_usb->buf_len = 0; bad_usb->st.line_cur = 0; @@ -442,12 +444,12 @@ static int32_t bad_usb_worker(void* context) { } else if(worker_state == BadUsbStateWillRun) { // State: start on connection uint32_t flags = bad_usb_flags_get( - WorkerEvtEnd | WorkerEvtConnect | WorkerEvtToggle, FuriWaitForever); + WorkerEvtEnd | WorkerEvtConnect | WorkerEvtStartStop, FuriWaitForever); if(flags & WorkerEvtEnd) { break; } else if(flags & WorkerEvtConnect) { // Start executing script - DOLPHIN_DEED(DolphinDeedBadUsbPlayScript); + dolphin_deed(DolphinDeedBadUsbPlayScript); delay_val = 0; bad_usb->buf_len = 0; bad_usb->st.line_cur = 0; @@ -458,17 +460,17 @@ static int32_t bad_usb_worker(void* context) { storage_file_seek(script_file, 0, true); // extra time for PC to recognize Flipper as keyboard flags = furi_thread_flags_wait( - WorkerEvtEnd | WorkerEvtDisconnect | WorkerEvtToggle, + WorkerEvtEnd | WorkerEvtDisconnect | WorkerEvtStartStop, FuriFlagWaitAny | FuriFlagNoClear, 1500); if(flags == (unsigned)FuriFlagErrorTimeout) { // If nothing happened - start script execution worker_state = BadUsbStateRunning; - } else if(flags & WorkerEvtToggle) { + } else if(flags & WorkerEvtStartStop) { worker_state = BadUsbStateIdle; - furi_thread_flags_clear(WorkerEvtToggle); + furi_thread_flags_clear(WorkerEvtStartStop); } - } else if(flags & WorkerEvtToggle) { // Cancel scheduled execution + } else if(flags & WorkerEvtStartStop) { // Cancel scheduled execution worker_state = BadUsbStateNotConnected; } bad_usb->st.state = worker_state; @@ -476,18 +478,23 @@ static int32_t bad_usb_worker(void* context) { } else if(worker_state == BadUsbStateRunning) { // State: running uint16_t delay_cur = (delay_val > 1000) ? (1000) : (delay_val); uint32_t flags = furi_thread_flags_wait( - WorkerEvtEnd | WorkerEvtToggle | WorkerEvtDisconnect, FuriFlagWaitAny, delay_cur); + WorkerEvtEnd | WorkerEvtStartStop | WorkerEvtPauseResume | WorkerEvtDisconnect, + FuriFlagWaitAny, + delay_cur); delay_val -= delay_cur; if(!(flags & FuriFlagError)) { if(flags & WorkerEvtEnd) { break; - } else if(flags & WorkerEvtToggle) { + } else if(flags & WorkerEvtStartStop) { worker_state = BadUsbStateIdle; // Stop executing script furi_hal_hid_kb_release_all(); } else if(flags & WorkerEvtDisconnect) { worker_state = BadUsbStateNotConnected; // USB disconnected furi_hal_hid_kb_release_all(); + } else if(flags & WorkerEvtPauseResume) { + pause_state = BadUsbStateRunning; + worker_state = BadUsbStatePaused; // Pause } bad_usb->st.state = worker_state; continue; @@ -526,13 +533,13 @@ static int32_t bad_usb_worker(void* context) { furi_check((flags & FuriFlagError) == 0); } } else if(worker_state == BadUsbStateWaitForBtn) { // State: Wait for button Press - uint16_t delay_cur = (delay_val > 1000) ? (1000) : (delay_val); - uint32_t flags = furi_thread_flags_wait( - WorkerEvtEnd | WorkerEvtToggle | WorkerEvtDisconnect, FuriFlagWaitAny, delay_cur); + uint32_t flags = bad_usb_flags_get( + WorkerEvtEnd | WorkerEvtStartStop | WorkerEvtPauseResume | WorkerEvtDisconnect, + FuriWaitForever); if(!(flags & FuriFlagError)) { if(flags & WorkerEvtEnd) { break; - } else if(flags & WorkerEvtToggle) { + } else if(flags & WorkerEvtStartStop) { delay_val = 0; worker_state = BadUsbStateRunning; } else if(flags & WorkerEvtDisconnect) { @@ -542,21 +549,55 @@ static int32_t bad_usb_worker(void* context) { bad_usb->st.state = worker_state; continue; } + } else if(worker_state == BadUsbStatePaused) { // State: Paused + uint32_t flags = bad_usb_flags_get( + WorkerEvtEnd | WorkerEvtStartStop | WorkerEvtPauseResume | WorkerEvtDisconnect, + FuriWaitForever); + if(!(flags & FuriFlagError)) { + if(flags & WorkerEvtEnd) { + break; + } else if(flags & WorkerEvtStartStop) { + worker_state = BadUsbStateIdle; // Stop executing script + bad_usb->st.state = worker_state; + furi_hal_hid_kb_release_all(); + } else if(flags & WorkerEvtDisconnect) { + worker_state = BadUsbStateNotConnected; // USB disconnected + bad_usb->st.state = worker_state; + furi_hal_hid_kb_release_all(); + } else if(flags & WorkerEvtPauseResume) { + if(pause_state == BadUsbStateRunning) { + if(delay_val > 0) { + bad_usb->st.state = BadUsbStateDelay; + bad_usb->st.delay_remain = delay_val / 1000; + } else { + bad_usb->st.state = BadUsbStateRunning; + delay_val = 0; + } + worker_state = BadUsbStateRunning; // Resume + } else if(pause_state == BadUsbStateStringDelay) { + bad_usb->st.state = BadUsbStateRunning; + worker_state = BadUsbStateStringDelay; // Resume + } + } + continue; + } } else if(worker_state == BadUsbStateStringDelay) { // State: print string with delays - uint32_t flags = furi_thread_flags_wait( - WorkerEvtEnd | WorkerEvtToggle | WorkerEvtDisconnect, - FuriFlagWaitAny, + uint32_t flags = bad_usb_flags_get( + WorkerEvtEnd | WorkerEvtStartStop | WorkerEvtPauseResume | WorkerEvtDisconnect, bad_usb->stringdelay); if(!(flags & FuriFlagError)) { if(flags & WorkerEvtEnd) { break; - } else if(flags & WorkerEvtToggle) { + } else if(flags & WorkerEvtStartStop) { worker_state = BadUsbStateIdle; // Stop executing script furi_hal_hid_kb_release_all(); } else if(flags & WorkerEvtDisconnect) { worker_state = BadUsbStateNotConnected; // USB disconnected furi_hal_hid_kb_release_all(); + } else if(flags & WorkerEvtPauseResume) { + pause_state = BadUsbStateStringDelay; + worker_state = BadUsbStatePaused; // Pause } bad_usb->st.state = worker_state; continue; @@ -651,9 +692,14 @@ void bad_usb_script_set_keyboard_layout(BadUsbScript* bad_usb, FuriString* layou storage_file_free(layout_file); } -void bad_usb_script_toggle(BadUsbScript* bad_usb) { +void bad_usb_script_start_stop(BadUsbScript* bad_usb) { + furi_assert(bad_usb); + furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtStartStop); +} + +void bad_usb_script_pause_resume(BadUsbScript* bad_usb) { furi_assert(bad_usb); - furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtToggle); + furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtPauseResume); } BadUsbState* bad_usb_script_get_state(BadUsbScript* bad_usb) { diff --git a/applications/main/bad_usb/helpers/ducky_script.h b/applications/main/bad_usb/helpers/ducky_script.h index cff7239420e5..c8705dbdd10d 100644 --- a/applications/main/bad_usb/helpers/ducky_script.h +++ b/applications/main/bad_usb/helpers/ducky_script.h @@ -16,6 +16,7 @@ typedef enum { BadUsbStateDelay, BadUsbStateStringDelay, BadUsbStateWaitForBtn, + BadUsbStatePaused, BadUsbStateDone, BadUsbStateScriptError, BadUsbStateFileError, @@ -42,7 +43,9 @@ void bad_usb_script_start(BadUsbScript* bad_usb); void bad_usb_script_stop(BadUsbScript* bad_usb); -void bad_usb_script_toggle(BadUsbScript* bad_usb); +void bad_usb_script_start_stop(BadUsbScript* bad_usb); + +void bad_usb_script_pause_resume(BadUsbScript* bad_usb); BadUsbState* bad_usb_script_get_state(BadUsbScript* bad_usb); diff --git a/applications/main/bad_usb/scenes/bad_usb_scene_work.c b/applications/main/bad_usb/scenes/bad_usb_scene_work.c index afc2e6f6f136..ad33a124d2a7 100644 --- a/applications/main/bad_usb/scenes/bad_usb_scene_work.c +++ b/applications/main/bad_usb/scenes/bad_usb_scene_work.c @@ -21,7 +21,10 @@ bool bad_usb_scene_work_on_event(void* context, SceneManagerEvent event) { } consumed = true; } else if(event.event == InputKeyOk) { - bad_usb_script_toggle(app->bad_usb_script); + bad_usb_script_start_stop(app->bad_usb_script); + consumed = true; + } else if(event.event == InputKeyRight) { + bad_usb_script_pause_resume(app->bad_usb_script); consumed = true; } } else if(event.type == SceneManagerEventTypeTick) { diff --git a/applications/main/bad_usb/views/bad_usb_view.c b/applications/main/bad_usb/views/bad_usb_view.c index 0ab4365b7b1f..fa75b50d038e 100644 --- a/applications/main/bad_usb/views/bad_usb_view.c +++ b/applications/main/bad_usb/views/bad_usb_view.c @@ -16,6 +16,7 @@ typedef struct { char file_name[MAX_NAME_LEN]; char layout[MAX_NAME_LEN]; BadUsbState state; + bool pause_wait; uint8_t anim_frame; } BadUsbModel; @@ -31,11 +32,7 @@ static void bad_usb_draw_callback(Canvas* canvas, void* _model) { if(strlen(model->layout) == 0) { furi_string_set(disp_str, "(default)"); } else { - furi_string_reset(disp_str); - furi_string_push_back(disp_str, '('); - for(size_t i = 0; i < strlen(model->layout); i++) - furi_string_push_back(disp_str, model->layout[i]); - furi_string_push_back(disp_str, ')'); + furi_string_printf(disp_str, "(%s)", model->layout); } elements_string_fit_width(canvas, disp_str, 128 - 2); canvas_draw_str( @@ -45,34 +42,42 @@ static void bad_usb_draw_callback(Canvas* canvas, void* _model) { canvas_draw_icon(canvas, 22, 24, &I_UsbTree_48x22); - if((model->state.state == BadUsbStateIdle) || (model->state.state == BadUsbStateDone) || - (model->state.state == BadUsbStateNotConnected)) { + BadUsbWorkerState state = model->state.state; + + if((state == BadUsbStateIdle) || (state == BadUsbStateDone) || + (state == BadUsbStateNotConnected)) { elements_button_center(canvas, "Run"); elements_button_left(canvas, "Config"); - } else if((model->state.state == BadUsbStateRunning) || (model->state.state == BadUsbStateDelay)) { + } else if((state == BadUsbStateRunning) || (state == BadUsbStateDelay)) { elements_button_center(canvas, "Stop"); - } else if(model->state.state == BadUsbStateWaitForBtn) { + if(!model->pause_wait) { + elements_button_right(canvas, "Pause"); + } + } else if(state == BadUsbStatePaused) { + elements_button_center(canvas, "End"); + elements_button_right(canvas, "Resume"); + } else if(state == BadUsbStateWaitForBtn) { elements_button_center(canvas, "Press to continue"); - } else if(model->state.state == BadUsbStateWillRun) { + } else if(state == BadUsbStateWillRun) { elements_button_center(canvas, "Cancel"); } - if(model->state.state == BadUsbStateNotConnected) { + if(state == BadUsbStateNotConnected) { canvas_draw_icon(canvas, 4, 26, &I_Clock_18x18); canvas_set_font(canvas, FontPrimary); canvas_draw_str_aligned(canvas, 127, 31, AlignRight, AlignBottom, "Connect"); canvas_draw_str_aligned(canvas, 127, 43, AlignRight, AlignBottom, "to USB"); - } else if(model->state.state == BadUsbStateWillRun) { + } else if(state == BadUsbStateWillRun) { canvas_draw_icon(canvas, 4, 26, &I_Clock_18x18); canvas_set_font(canvas, FontPrimary); canvas_draw_str_aligned(canvas, 127, 31, AlignRight, AlignBottom, "Will run"); canvas_draw_str_aligned(canvas, 127, 43, AlignRight, AlignBottom, "on connect"); - } else if(model->state.state == BadUsbStateFileError) { + } else if(state == BadUsbStateFileError) { canvas_draw_icon(canvas, 4, 26, &I_Error_18x18); canvas_set_font(canvas, FontPrimary); canvas_draw_str_aligned(canvas, 127, 31, AlignRight, AlignBottom, "File"); canvas_draw_str_aligned(canvas, 127, 43, AlignRight, AlignBottom, "ERROR"); - } else if(model->state.state == BadUsbStateScriptError) { + } else if(state == BadUsbStateScriptError) { canvas_draw_icon(canvas, 4, 26, &I_Error_18x18); canvas_set_font(canvas, FontPrimary); canvas_draw_str_aligned(canvas, 127, 33, AlignRight, AlignBottom, "ERROR:"); @@ -87,12 +92,12 @@ static void bad_usb_draw_callback(Canvas* canvas, void* _model) { canvas_draw_str_aligned( canvas, 127, 56, AlignRight, AlignBottom, furi_string_get_cstr(disp_str)); furi_string_reset(disp_str); - } else if(model->state.state == BadUsbStateIdle) { + } else if(state == BadUsbStateIdle) { canvas_draw_icon(canvas, 4, 26, &I_Smile_18x18); canvas_set_font(canvas, FontBigNumbers); canvas_draw_str_aligned(canvas, 114, 40, AlignRight, AlignBottom, "0"); canvas_draw_icon(canvas, 117, 26, &I_Percent_10x14); - } else if(model->state.state == BadUsbStateRunning) { + } else if(state == BadUsbStateRunning) { if(model->anim_frame == 0) { canvas_draw_icon(canvas, 4, 23, &I_EviSmile1_18x21); } else { @@ -105,13 +110,13 @@ static void bad_usb_draw_callback(Canvas* canvas, void* _model) { canvas, 114, 40, AlignRight, AlignBottom, furi_string_get_cstr(disp_str)); furi_string_reset(disp_str); canvas_draw_icon(canvas, 117, 26, &I_Percent_10x14); - } else if(model->state.state == BadUsbStateDone) { + } else if(state == BadUsbStateDone) { canvas_draw_icon(canvas, 4, 23, &I_EviSmile1_18x21); canvas_set_font(canvas, FontBigNumbers); canvas_draw_str_aligned(canvas, 114, 40, AlignRight, AlignBottom, "100"); furi_string_reset(disp_str); canvas_draw_icon(canvas, 117, 26, &I_Percent_10x14); - } else if(model->state.state == BadUsbStateDelay) { + } else if(state == BadUsbStateDelay) { if(model->anim_frame == 0) { canvas_draw_icon(canvas, 4, 23, &I_EviWaiting1_18x21); } else { @@ -129,6 +134,22 @@ static void bad_usb_draw_callback(Canvas* canvas, void* _model) { canvas_draw_str_aligned( canvas, 127, 50, AlignRight, AlignBottom, furi_string_get_cstr(disp_str)); furi_string_reset(disp_str); + } else if((state == BadUsbStatePaused) || (state == BadUsbStateWaitForBtn)) { + if(model->anim_frame == 0) { + canvas_draw_icon(canvas, 4, 23, &I_EviWaiting1_18x21); + } else { + canvas_draw_icon(canvas, 4, 23, &I_EviWaiting2_18x21); + } + canvas_set_font(canvas, FontBigNumbers); + furi_string_printf( + disp_str, "%u", ((model->state.line_cur - 1) * 100) / model->state.line_nb); + canvas_draw_str_aligned( + canvas, 114, 40, AlignRight, AlignBottom, furi_string_get_cstr(disp_str)); + furi_string_reset(disp_str); + canvas_draw_icon(canvas, 117, 26, &I_Percent_10x14); + canvas_set_font(canvas, FontSecondary); + canvas_draw_str_aligned(canvas, 127, 50, AlignRight, AlignBottom, "Paused"); + furi_string_reset(disp_str); } else { canvas_draw_icon(canvas, 4, 26, &I_Clock_18x18); } @@ -142,7 +163,27 @@ static bool bad_usb_input_callback(InputEvent* event, void* context) { bool consumed = false; if(event->type == InputTypeShort) { - if((event->key == InputKeyLeft) || (event->key == InputKeyOk)) { + if(event->key == InputKeyLeft) { + consumed = true; + furi_assert(bad_usb->callback); + bad_usb->callback(event->key, bad_usb->context); + } else if(event->key == InputKeyOk) { + with_view_model( + bad_usb->view, BadUsbModel * model, { model->pause_wait = false; }, true); + consumed = true; + furi_assert(bad_usb->callback); + bad_usb->callback(event->key, bad_usb->context); + } else if(event->key == InputKeyRight) { + with_view_model( + bad_usb->view, + BadUsbModel * model, + { + if((model->state.state == BadUsbStateRunning) || + (model->state.state == BadUsbStateDelay)) { + model->pause_wait = true; + } + }, + true); consumed = true; furi_assert(bad_usb->callback); bad_usb->callback(event->key, bad_usb->context); @@ -215,6 +256,9 @@ void bad_usb_set_state(BadUsb* bad_usb, BadUsbState* st) { { memcpy(&(model->state), st, sizeof(BadUsbState)); model->anim_frame ^= 1; + if(model->state.state == BadUsbStatePaused) { + model->pause_wait = false; + } }, true); } diff --git a/applications/main/gpio/scenes/gpio_scene_start.c b/applications/main/gpio/scenes/gpio_scene_start.c index 0272677934c5..421936488007 100644 --- a/applications/main/gpio/scenes/gpio_scene_start.c +++ b/applications/main/gpio/scenes/gpio_scene_start.c @@ -89,7 +89,7 @@ bool gpio_scene_start_on_event(void* context, SceneManagerEvent event) { } else if(event.event == GpioStartEventUsbUart) { scene_manager_set_scene_state(app->scene_manager, GpioSceneStart, GpioItemUsbUart); if(!furi_hal_usb_is_locked()) { - DOLPHIN_DEED(DolphinDeedGpioUartBridge); + dolphin_deed(DolphinDeedGpioUartBridge); scene_manager_next_scene(app->scene_manager, GpioSceneUsbUart); } else { scene_manager_next_scene(app->scene_manager, GpioSceneUsbUartCloseRpc); diff --git a/applications/main/ibutton/ibutton.c b/applications/main/ibutton/ibutton.c index 79999adb28cd..ad5b233b56e6 100644 --- a/applications/main/ibutton/ibutton.c +++ b/applications/main/ibutton/ibutton.c @@ -282,14 +282,14 @@ int32_t ibutton_app(void* arg) { view_dispatcher_attach_to_gui( ibutton->view_dispatcher, ibutton->gui, ViewDispatcherTypeDesktop); scene_manager_next_scene(ibutton->scene_manager, iButtonSceneRpc); - DOLPHIN_DEED(DolphinDeedIbuttonEmulate); + dolphin_deed(DolphinDeedIbuttonEmulate); } else { view_dispatcher_attach_to_gui( ibutton->view_dispatcher, ibutton->gui, ViewDispatcherTypeFullscreen); if(key_loaded) { //-V547 scene_manager_next_scene(ibutton->scene_manager, iButtonSceneEmulate); - DOLPHIN_DEED(DolphinDeedIbuttonEmulate); + dolphin_deed(DolphinDeedIbuttonEmulate); } else { scene_manager_next_scene(ibutton->scene_manager, iButtonSceneStart); } diff --git a/applications/main/ibutton/scenes/ibutton_scene_read.c b/applications/main/ibutton/scenes/ibutton_scene_read.c index a840fb7b7ec3..f360c3ac43af 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_read.c +++ b/applications/main/ibutton/scenes/ibutton_scene_read.c @@ -38,7 +38,7 @@ bool ibutton_scene_read_on_event(void* context, SceneManagerEvent event) { ibutton_notification_message(ibutton, iButtonNotificationMessageSuccess); scene_manager_next_scene(scene_manager, iButtonSceneReadSuccess); - DOLPHIN_DEED(DolphinDeedIbuttonReadSuccess); + dolphin_deed(DolphinDeedIbuttonReadSuccess); } else { scene_manager_next_scene(scene_manager, iButtonSceneReadError); diff --git a/applications/main/ibutton/scenes/ibutton_scene_read_key_menu.c b/applications/main/ibutton/scenes/ibutton_scene_read_key_menu.c index 716f72c7d3da..1555f2cc20c3 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_read_key_menu.c +++ b/applications/main/ibutton/scenes/ibutton_scene_read_key_menu.c @@ -75,7 +75,7 @@ bool ibutton_scene_read_key_menu_on_event(void* context, SceneManagerEvent event scene_manager_next_scene(scene_manager, iButtonSceneSaveName); } else if(event.event == SubmenuIndexEmulate) { scene_manager_next_scene(scene_manager, iButtonSceneEmulate); - DOLPHIN_DEED(DolphinDeedIbuttonEmulate); + dolphin_deed(DolphinDeedIbuttonEmulate); } else if(event.event == SubmenuIndexViewData) { scene_manager_next_scene(scene_manager, iButtonSceneViewData); } else if(event.event == SubmenuIndexWriteBlank) { diff --git a/applications/main/ibutton/scenes/ibutton_scene_save_name.c b/applications/main/ibutton/scenes/ibutton_scene_save_name.c index 4ad0315e54e5..7bd49df8337e 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_save_name.c +++ b/applications/main/ibutton/scenes/ibutton_scene_save_name.c @@ -58,9 +58,9 @@ bool ibutton_scene_save_name_on_event(void* context, SceneManagerEvent event) { // Nothing, do not count editing as saving } else if(scene_manager_has_previous_scene( ibutton->scene_manager, iButtonSceneAddType)) { - DOLPHIN_DEED(DolphinDeedIbuttonAdd); + dolphin_deed(DolphinDeedIbuttonAdd); } else { - DOLPHIN_DEED(DolphinDeedIbuttonSave); + dolphin_deed(DolphinDeedIbuttonSave); } } else { diff --git a/applications/main/ibutton/scenes/ibutton_scene_saved_key_menu.c b/applications/main/ibutton/scenes/ibutton_scene_saved_key_menu.c index 80fca28b5eea..fc0cf42e2ffe 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_saved_key_menu.c +++ b/applications/main/ibutton/scenes/ibutton_scene_saved_key_menu.c @@ -48,7 +48,7 @@ bool ibutton_scene_saved_key_menu_on_event(void* context, SceneManagerEvent even consumed = true; if(event.event == SubmenuIndexEmulate) { scene_manager_next_scene(scene_manager, iButtonSceneEmulate); - DOLPHIN_DEED(DolphinDeedIbuttonEmulate); + dolphin_deed(DolphinDeedIbuttonEmulate); } else if(event.event == SubmenuIndexWriteBlank) { ibutton->write_mode = iButtonWriteModeBlank; scene_manager_next_scene(scene_manager, iButtonSceneWrite); diff --git a/applications/main/ibutton/scenes/ibutton_scene_start.c b/applications/main/ibutton/scenes/ibutton_scene_start.c index 37bf96f39f00..63a4cf869d32 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_start.c +++ b/applications/main/ibutton/scenes/ibutton_scene_start.c @@ -33,7 +33,7 @@ bool ibutton_scene_start_on_event(void* context, SceneManagerEvent event) { consumed = true; if(event.event == SubmenuIndexRead) { scene_manager_next_scene(ibutton->scene_manager, iButtonSceneRead); - DOLPHIN_DEED(DolphinDeedIbuttonRead); + dolphin_deed(DolphinDeedIbuttonRead); } else if(event.event == SubmenuIndexSaved) { scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSelectKey); } else if(event.event == SubmenuIndexAdd) { diff --git a/applications/main/infrared/infrared.c b/applications/main/infrared/infrared.c index 4f450496d4c1..5957cdb13361 100644 --- a/applications/main/infrared/infrared.c +++ b/applications/main/infrared/infrared.c @@ -312,13 +312,14 @@ void infrared_tx_start_signal(Infrared* infrared, InfraredSignal* signal) { if(infrared_signal_is_raw(signal)) { InfraredRawSignal* raw = infrared_signal_get_raw_signal(signal); - infrared_worker_set_raw_signal(infrared->worker, raw->timings, raw->timings_size); + infrared_worker_set_raw_signal( + infrared->worker, raw->timings, raw->timings_size, raw->frequency, raw->duty_cycle); } else { InfraredMessage* message = infrared_signal_get_message(signal); infrared_worker_set_decoded_signal(infrared->worker, message); } - DOLPHIN_DEED(DolphinDeedIrSend); + dolphin_deed(DolphinDeedIrSend); infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStartSend); infrared_worker_tx_set_get_signal_callback( diff --git a/applications/main/infrared/scenes/common/infrared_scene_universal_common.c b/applications/main/infrared/scenes/common/infrared_scene_universal_common.c index d55d8d0a6dba..96f28cc48917 100644 --- a/applications/main/infrared/scenes/common/infrared_scene_universal_common.c +++ b/applications/main/infrared/scenes/common/infrared_scene_universal_common.c @@ -70,7 +70,7 @@ bool infrared_scene_universal_common_on_event(void* context, SceneManagerEvent e uint32_t record_count; if(infrared_brute_force_start( brute_force, infrared_custom_event_get_value(event.event), &record_count)) { - DOLPHIN_DEED(DolphinDeedIrSend); + dolphin_deed(DolphinDeedIrSend); infrared_scene_universal_common_show_popup(infrared, record_count); } else { scene_manager_next_scene(scene_manager, InfraredSceneErrorDatabases); diff --git a/applications/main/infrared/scenes/infrared_scene_learn.c b/applications/main/infrared/scenes/infrared_scene_learn.c index 48699a71fc99..46646c6d69a0 100644 --- a/applications/main/infrared/scenes/infrared_scene_learn.c +++ b/applications/main/infrared/scenes/infrared_scene_learn.c @@ -28,7 +28,7 @@ bool infrared_scene_learn_on_event(void* context, SceneManagerEvent event) { if(event.event == InfraredCustomEventTypeSignalReceived) { infrared_play_notification_message(infrared, InfraredNotificationMessageSuccess); scene_manager_next_scene(infrared->scene_manager, InfraredSceneLearnSuccess); - DOLPHIN_DEED(DolphinDeedIrLearnSuccess); + dolphin_deed(DolphinDeedIrLearnSuccess); consumed = true; } } diff --git a/applications/main/infrared/scenes/infrared_scene_learn_enter_name.c b/applications/main/infrared/scenes/infrared_scene_learn_enter_name.c index a8772a985cc3..104a4cb7b65f 100644 --- a/applications/main/infrared/scenes/infrared_scene_learn_enter_name.c +++ b/applications/main/infrared/scenes/infrared_scene_learn_enter_name.c @@ -50,7 +50,7 @@ bool infrared_scene_learn_enter_name_on_event(void* context, SceneManagerEvent e if(success) { scene_manager_next_scene(scene_manager, InfraredSceneLearnDone); - DOLPHIN_DEED(DolphinDeedIrSave); + dolphin_deed(DolphinDeedIrSave); } else { dialog_message_show_storage_error(infrared->dialogs, "Failed to save file"); const uint32_t possible_scenes[] = {InfraredSceneRemoteList, InfraredSceneStart}; diff --git a/applications/main/lfrfid/lfrfid.c b/applications/main/lfrfid/lfrfid.c index 85a00eea00d0..edde23804c27 100644 --- a/applications/main/lfrfid/lfrfid.c +++ b/applications/main/lfrfid/lfrfid.c @@ -183,14 +183,14 @@ int32_t lfrfid_app(void* p) { view_dispatcher_attach_to_gui( app->view_dispatcher, app->gui, ViewDispatcherTypeDesktop); scene_manager_next_scene(app->scene_manager, LfRfidSceneRpc); - DOLPHIN_DEED(DolphinDeedRfidEmulate); + dolphin_deed(DolphinDeedRfidEmulate); } else { furi_string_set(app->file_path, args); lfrfid_load_key_data(app, app->file_path, true); view_dispatcher_attach_to_gui( app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); scene_manager_next_scene(app->scene_manager, LfRfidSceneEmulate); - DOLPHIN_DEED(DolphinDeedRfidEmulate); + dolphin_deed(DolphinDeedRfidEmulate); } } else { diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_extra_actions.c b/applications/main/lfrfid/scenes/lfrfid_scene_extra_actions.c index fac2ebcec541..1aed9a03c379 100644 --- a/applications/main/lfrfid/scenes/lfrfid_scene_extra_actions.c +++ b/applications/main/lfrfid/scenes/lfrfid_scene_extra_actions.c @@ -58,12 +58,12 @@ bool lfrfid_scene_extra_actions_on_event(void* context, SceneManagerEvent event) if(event.event == SubmenuIndexASK) { app->read_type = LFRFIDWorkerReadTypeASKOnly; scene_manager_next_scene(app->scene_manager, LfRfidSceneRead); - DOLPHIN_DEED(DolphinDeedRfidRead); + dolphin_deed(DolphinDeedRfidRead); consumed = true; } else if(event.event == SubmenuIndexPSK) { app->read_type = LFRFIDWorkerReadTypePSKOnly; scene_manager_next_scene(app->scene_manager, LfRfidSceneRead); - DOLPHIN_DEED(DolphinDeedRfidRead); + dolphin_deed(DolphinDeedRfidRead); consumed = true; } else if(event.event == SubmenuIndexRAW) { scene_manager_next_scene(app->scene_manager, LfRfidSceneRawName); diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_read.c b/applications/main/lfrfid/scenes/lfrfid_scene_read.c index 5f19597282a7..d04ce41d4a6c 100644 --- a/applications/main/lfrfid/scenes/lfrfid_scene_read.c +++ b/applications/main/lfrfid/scenes/lfrfid_scene_read.c @@ -81,7 +81,7 @@ bool lfrfid_scene_read_on_event(void* context, SceneManagerEvent event) { notification_message(app->notifications, &sequence_success); furi_string_reset(app->file_name); scene_manager_next_scene(app->scene_manager, LfRfidSceneReadSuccess); - DOLPHIN_DEED(DolphinDeedRfidReadSuccess); + dolphin_deed(DolphinDeedRfidReadSuccess); consumed = true; } else if(event.event == LfRfidEventReadStartPSK) { if(app->read_type == LFRFIDWorkerReadTypeAuto) { diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_read_key_menu.c b/applications/main/lfrfid/scenes/lfrfid_scene_read_key_menu.c index 081c479123fb..36f0d6d93a32 100644 --- a/applications/main/lfrfid/scenes/lfrfid_scene_read_key_menu.c +++ b/applications/main/lfrfid/scenes/lfrfid_scene_read_key_menu.c @@ -44,7 +44,7 @@ bool lfrfid_scene_read_key_menu_on_event(void* context, SceneManagerEvent event) consumed = true; } else if(event.event == SubmenuIndexEmulate) { scene_manager_next_scene(app->scene_manager, LfRfidSceneEmulate); - DOLPHIN_DEED(DolphinDeedRfidEmulate); + dolphin_deed(DolphinDeedRfidEmulate); consumed = true; } scene_manager_set_scene_state(app->scene_manager, LfRfidSceneReadKeyMenu, event.event); diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_save_name.c b/applications/main/lfrfid/scenes/lfrfid_scene_save_name.c index 87e110f185bf..771f2f60387b 100644 --- a/applications/main/lfrfid/scenes/lfrfid_scene_save_name.c +++ b/applications/main/lfrfid/scenes/lfrfid_scene_save_name.c @@ -59,9 +59,9 @@ bool lfrfid_scene_save_name_on_event(void* context, SceneManagerEvent event) { if(scene_manager_has_previous_scene(scene_manager, LfRfidSceneSavedKeyMenu)) { // Nothing, do not count editing as saving } else if(scene_manager_has_previous_scene(scene_manager, LfRfidSceneSaveType)) { - DOLPHIN_DEED(DolphinDeedRfidAdd); + dolphin_deed(DolphinDeedRfidAdd); } else { - DOLPHIN_DEED(DolphinDeedRfidSave); + dolphin_deed(DolphinDeedRfidSave); } } else { scene_manager_search_and_switch_to_previous_scene( diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_saved_key_menu.c b/applications/main/lfrfid/scenes/lfrfid_scene_saved_key_menu.c index d3c3d389a8d6..206074e9b080 100644 --- a/applications/main/lfrfid/scenes/lfrfid_scene_saved_key_menu.c +++ b/applications/main/lfrfid/scenes/lfrfid_scene_saved_key_menu.c @@ -43,7 +43,7 @@ bool lfrfid_scene_saved_key_menu_on_event(void* context, SceneManagerEvent event if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubmenuIndexEmulate) { scene_manager_next_scene(app->scene_manager, LfRfidSceneEmulate); - DOLPHIN_DEED(DolphinDeedRfidEmulate); + dolphin_deed(DolphinDeedRfidEmulate); consumed = true; } else if(event.event == SubmenuIndexWrite) { scene_manager_next_scene(app->scene_manager, LfRfidSceneWrite); diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_start.c b/applications/main/lfrfid/scenes/lfrfid_scene_start.c index 2d83ba53b3b7..8a01fc707b1e 100644 --- a/applications/main/lfrfid/scenes/lfrfid_scene_start.c +++ b/applications/main/lfrfid/scenes/lfrfid_scene_start.c @@ -49,7 +49,7 @@ bool lfrfid_scene_start_on_event(void* context, SceneManagerEvent event) { if(event.event == SubmenuIndexRead) { scene_manager_set_scene_state(app->scene_manager, LfRfidSceneStart, SubmenuIndexRead); scene_manager_next_scene(app->scene_manager, LfRfidSceneRead); - DOLPHIN_DEED(DolphinDeedRfidRead); + dolphin_deed(DolphinDeedRfidRead); consumed = true; } else if(event.event == SubmenuIndexSaved) { // Like in the other apps, explicitly save the scene state diff --git a/applications/main/nfc/nfc_app.c b/applications/main/nfc/nfc_app.c index cbd2bddc4df7..88227dd936a9 100644 --- a/applications/main/nfc/nfc_app.c +++ b/applications/main/nfc/nfc_app.c @@ -476,15 +476,15 @@ int32_t nfc_app(void* p) { // if(nfc_device_load(nfc->dev, p, true)) { // if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { // scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate); - // DOLPHIN_DEED(DolphinDeedNfcEmulate); + // dolphin_deed(DolphinDeedNfcEmulate); // } else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) { // scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate); - // DOLPHIN_DEED(DolphinDeedNfcEmulate); + // dolphin_deed(DolphinDeedNfcEmulate); // } else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) { // scene_manager_next_scene(nfc->scene_manager, NfcSceneDeviceInfo); // } else { // scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); - // DOLPHIN_DEED(DolphinDeedNfcEmulate); + // dolphin_deed(DolphinDeedNfcEmulate); // } // } else { // // Exit app diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c index adf0fedabf60..e8ff22568c05 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c @@ -144,7 +144,7 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent } else { notification_message(nfc->notifications, &sequence_success); scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSuccess); - DOLPHIN_DEED(DolphinDeedNfcReadSuccess); + dolphin_deed(DolphinDeedNfcReadSuccess); consumed = true; } } else if(event.event == NfcCustomEventDictAttackCardDetected) { diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_menu.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_menu.c index 380d8e6e829b..99264824e914 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_menu.c @@ -53,15 +53,15 @@ bool nfc_scene_mf_classic_menu_on_event(void* context, SceneManagerEvent event) consumed = true; } else if(event.event == SubmenuIndexEmulate) { if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) { - DOLPHIN_DEED(DolphinDeedNfcAddEmulate); + dolphin_deed(DolphinDeedNfcAddEmulate); } else { - DOLPHIN_DEED(DolphinDeedNfcEmulate); + dolphin_deed(DolphinDeedNfcEmulate); } scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); consumed = true; } else if(event.event == SubmenuIndexDetectReader) { scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); - DOLPHIN_DEED(DolphinDeedNfcDetectReader); + dolphin_deed(DolphinDeedNfcDetectReader); consumed = true; } else if(event.event == SubmenuIndexInfo) { scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); diff --git a/applications/main/nfc/scenes/nfc_scene_mf_desfire_menu.c b/applications/main/nfc/scenes/nfc_scene_mf_desfire_menu.c index e116df649495..918a8020f61a 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_desfire_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_desfire_menu.c @@ -46,9 +46,9 @@ bool nfc_scene_mf_desfire_menu_on_event(void* context, SceneManagerEvent event) } else if(event.event == SubmenuIndexEmulateUid) { scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcaEmulate); if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneNotImplemented)) { - DOLPHIN_DEED(DolphinDeedNfcAddEmulate); + dolphin_deed(DolphinDeedNfcAddEmulate); } else { - DOLPHIN_DEED(DolphinDeedNfcEmulate); + dolphin_deed(DolphinDeedNfcEmulate); } consumed = true; } else if(event.event == SubmenuIndexInfo) { diff --git a/applications/main/nfc/scenes/nfc_scene_mf_desfire_read.c b/applications/main/nfc/scenes/nfc_scene_mf_desfire_read.c index 3b18c684e704..96122313fa01 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_desfire_read.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_desfire_read.c @@ -51,7 +51,7 @@ bool nfc_scene_mf_desfire_read_on_event(void* context, SceneManagerEvent event) if(event.event == NfcWorkerEventMfDesfireReadSuccess) { notification_message(instance->notifications, &sequence_success); scene_manager_next_scene(instance->scene_manager, NfcSceneMfDesfireReadSuccess); - DOLPHIN_DEED(DolphinDeedNfcReadSuccess); + dolphin_deed(DolphinDeedNfcReadSuccess); consumed = true; } } diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c index 74355e404c82..6a0b4f004e3c 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c @@ -57,9 +57,9 @@ bool nfc_scene_mf_ultralight_menu_on_event(void* context, SceneManagerEvent even } else if(event.event == SubmenuIndexEmulate) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate); // if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) { - // DOLPHIN_DEED(DolphinDeedNfcAddEmulate); + // dolphin_deed(DolphinDeedNfcAddEmulate); // } else { - // DOLPHIN_DEED(DolphinDeedNfcEmulate); + // dolphin_deed(DolphinDeedNfcEmulate); // } consumed = true; } else if(event.event == SubmenuIndexUnlock) { diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read.c index bc87d8b99e0e..4ad006d12751 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read.c @@ -75,7 +75,7 @@ bool nfc_scene_mf_ultralight_read_on_event(void* context, SceneManagerEvent even if(event.event == NfcWorkerEventMfUltralightReadSuccess) { notification_message(instance->notifications, &sequence_success); scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightReadSuccess); - DOLPHIN_DEED(DolphinDeedNfcReadSuccess); + dolphin_deed(DolphinDeedNfcReadSuccess); consumed = true; } } diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c index 659dcfb606fd..97da6d770661 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c @@ -57,7 +57,7 @@ bool nfc_scene_mf_ultralight_unlock_warn_on_event(void* context, SceneManagerEve if(event.type == SceneManagerEventTypeCustom) { if(event.event == DialogExResultRight) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightRead); - DOLPHIN_DEED(DolphinDeedNfcRead); + dolphin_deed(DolphinDeedNfcRead); consumed = true; } else if(event.event == DialogExResultLeft) { if(type == MfUltralightAuthTypeReader) { @@ -75,7 +75,7 @@ bool nfc_scene_mf_ultralight_unlock_warn_on_event(void* context, SceneManagerEve if(event.type == SceneManagerEventTypeCustom) { if(event.event == DialogExResultCenter) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightRead); - DOLPHIN_DEED(DolphinDeedNfcRead); + dolphin_deed(DolphinDeedNfcRead); consumed = true; } } diff --git a/applications/main/nfc/scenes/nfc_scene_nfca_menu.c b/applications/main/nfc/scenes/nfc_scene_nfca_menu.c index abe34caab2a4..7960b9210109 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfca_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_nfca_menu.c @@ -40,9 +40,9 @@ bool nfc_scene_nfca_menu_on_event(void* context, SceneManagerEvent event) { } else if(event.event == SubmenuIndexEmulateUid) { scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcaEmulate); if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneNotImplemented)) { - DOLPHIN_DEED(DolphinDeedNfcAddEmulate); + dolphin_deed(DolphinDeedNfcAddEmulate); } else { - DOLPHIN_DEED(DolphinDeedNfcEmulate); + dolphin_deed(DolphinDeedNfcEmulate); } consumed = true; } else if(event.event == SubmenuIndexInfo) { diff --git a/applications/main/nfc/scenes/nfc_scene_nfca_read.c b/applications/main/nfc/scenes/nfc_scene_nfca_read.c index 1401c7ade1d8..fe8de084c0d3 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfca_read.c +++ b/applications/main/nfc/scenes/nfc_scene_nfca_read.c @@ -48,7 +48,7 @@ bool nfc_scene_nfca_read_on_event(void* context, SceneManagerEvent event) { if(event.event == NfcWorkerEventReadUidNfcA) { notification_message(instance->notifications, &sequence_success); scene_manager_next_scene(instance->scene_manager, NfcSceneNfcaReadSuccess); - DOLPHIN_DEED(DolphinDeedNfcReadSuccess); + dolphin_deed(DolphinDeedNfcReadSuccess); consumed = true; } } diff --git a/applications/main/nfc/scenes/nfc_scene_save_name.c b/applications/main/nfc/scenes/nfc_scene_save_name.c index e1e90d260a61..1f7824fd7112 100644 --- a/applications/main/nfc/scenes/nfc_scene_save_name.c +++ b/applications/main/nfc/scenes/nfc_scene_save_name.c @@ -56,9 +56,9 @@ bool nfc_scene_save_name_on_event(void* context, SceneManagerEvent event) { if(nfc_save(nfc)) { scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess); if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) { - DOLPHIN_DEED(DolphinDeedNfcAddSave); + dolphin_deed(DolphinDeedNfcAddSave); } else { - DOLPHIN_DEED(DolphinDeedNfcSave); + dolphin_deed(DolphinDeedNfcSave); } consumed = true; } else { diff --git a/applications/main/nfc/scenes/nfc_scene_saved_menu.c b/applications/main/nfc/scenes/nfc_scene_saved_menu.c index 45a17f78f041..b1eb330972ba 100644 --- a/applications/main/nfc/scenes/nfc_scene_saved_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_saved_menu.c @@ -128,11 +128,11 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { } else { scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcaEmulate); } - DOLPHIN_DEED(DolphinDeedNfcEmulate); + dolphin_deed(DolphinDeedNfcEmulate); consumed = true; } else if(event.event == SubmenuIndexDetectReader) { scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); - DOLPHIN_DEED(DolphinDeedNfcDetectReader); + dolphin_deed(DolphinDeedNfcDetectReader); consumed = true; } else if(event.event == SubmenuIndexWrite) { scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); diff --git a/applications/main/nfc/scenes/nfc_scene_start.c b/applications/main/nfc/scenes/nfc_scene_start.c index fc21cfe79e68..dcfd34163903 100644 --- a/applications/main/nfc/scenes/nfc_scene_start.c +++ b/applications/main/nfc/scenes/nfc_scene_start.c @@ -48,7 +48,7 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) { if(event.event == SubmenuIndexRead) { scene_manager_set_scene_state(nfc->scene_manager, NfcSceneStart, SubmenuIndexRead); scene_manager_next_scene(nfc->scene_manager, NfcSceneDetect); - DOLPHIN_DEED(DolphinDeedNfcRead); + dolphin_deed(DolphinDeedNfcRead); consumed = true; } else if(event.event == SubmenuIndexDetectReader) { scene_manager_set_scene_state( diff --git a/applications/main/nfc_old/helpers/nfc_custom_event.h b/applications/main/nfc_old/helpers/nfc_custom_event.h index 4227a5b14e33..aa932a3d857d 100644 --- a/applications/main/nfc_old/helpers/nfc_custom_event.h +++ b/applications/main/nfc_old/helpers/nfc_custom_event.h @@ -12,4 +12,6 @@ enum NfcCustomEvent { NfcCustomEventDictAttackSkip, NfcCustomEventRpcLoad, NfcCustomEventRpcSessionClose, + NfcCustomEventUpdateLog, + NfcCustomEventSaveShadow, }; diff --git a/applications/main/nfc_old/nfc_app.c b/applications/main/nfc_old/nfc_app.c index 5884f8852d03..e9d070c98d21 100644 --- a/applications/main/nfc_old/nfc_app.c +++ b/applications/main/nfc_old/nfc_app.c @@ -286,15 +286,18 @@ int32_t nfc_app(void* p) { if(nfc_device_load(nfc->dev, p, true)) { if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate); - DOLPHIN_DEED(DolphinDeedNfcEmulate); + dolphin_deed(DolphinDeedNfcEmulate); } else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate); - DOLPHIN_DEED(DolphinDeedNfcEmulate); + dolphin_deed(DolphinDeedNfcEmulate); + } else if(nfc->dev->format == NfcDeviceSaveFormatNfcV) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVEmulate); + dolphin_deed(DolphinDeedNfcEmulate); } else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) { scene_manager_next_scene(nfc->scene_manager, NfcSceneDeviceInfo); } else { scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); - DOLPHIN_DEED(DolphinDeedNfcEmulate); + dolphin_deed(DolphinDeedNfcEmulate); } } else { // Exit app diff --git a/applications/main/nfc_old/scenes/nfc_scene_device_info.c b/applications/main/nfc_old/scenes/nfc_scene_device_info.c index 6d1bc8b42381..4ec17b1b0552 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_device_info.c +++ b/applications/main/nfc_old/scenes/nfc_scene_device_info.c @@ -52,6 +52,7 @@ void nfc_scene_device_info_on_enter(void* context) { } } else if( dev_data->protocol == NfcDeviceProtocolMifareClassic || + dev_data->protocol == NfcDeviceProtocolMifareDesfire || dev_data->protocol == NfcDeviceProtocolMifareUl) { furi_string_set(temp_str, nfc->dev->dev_data.parsed_data); } diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_add.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_add.c index d2b89829bf94..37b543b8d937 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_add.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_add.c @@ -37,7 +37,7 @@ bool nfc_scene_mf_classic_keys_add_on_event(void* context, SceneManagerEvent eve nfc->scene_manager, NfcSceneMfClassicKeysWarnDuplicate); } else if(mf_classic_dict_add_key(dict, nfc->byte_input_store)) { scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess); - DOLPHIN_DEED(DolphinDeedNfcMfcAdd); + dolphin_deed(DolphinDeedNfcMfcAdd); } else { scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound); } diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_update.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_update.c index 3819e799bb4c..731c1e2683d7 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_update.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_update.c @@ -34,7 +34,7 @@ static void nfc_scene_mf_classic_update_setup_view(NfcApp* nfc) { void nfc_scene_mf_classic_update_on_enter(void* context) { NfcApp* nfc = context; - DOLPHIN_DEED(DolphinDeedNfcEmulate); + dolphin_deed(DolphinDeedNfcEmulate); scene_manager_set_scene_state( nfc->scene_manager, NfcSceneMfClassicUpdate, NfcSceneMfClassicUpdateStateCardSearch); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_update_success.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_update_success.c index f52114b161d9..1f367caa0bb5 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_update_success.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_update_success.c @@ -8,7 +8,7 @@ void nfc_scene_mf_classic_update_success_popup_callback(void* context) { void nfc_scene_mf_classic_update_success_on_enter(void* context) { NfcApp* nfc = context; - DOLPHIN_DEED(DolphinDeedNfcSave); + dolphin_deed(DolphinDeedNfcSave); notification_message(nfc->notifications, &sequence_success); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_write.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_write.c index d33fbc4106a9..e074f8036c54 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_write.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_write.c @@ -34,7 +34,7 @@ static void nfc_scene_mf_classic_write_setup_view(NfcApp* nfc) { void nfc_scene_mf_classic_write_on_enter(void* context) { NfcApp* nfc = context; - DOLPHIN_DEED(DolphinDeedNfcEmulate); + dolphin_deed(DolphinDeedNfcEmulate); scene_manager_set_scene_state( nfc->scene_manager, NfcSceneMfClassicWrite, NfcSceneMfClassicWriteStateCardSearch); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_write_success.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_write_success.c index 272d607dfb35..9acc14b12ecb 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_write_success.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_write_success.c @@ -8,7 +8,7 @@ void nfc_scene_mf_classic_write_success_popup_callback(void* context) { void nfc_scene_mf_classic_write_success_on_enter(void* context) { NfcApp* nfc = context; - DOLPHIN_DEED(DolphinDeedNfcSave); + dolphin_deed(DolphinDeedNfcSave); notification_message(nfc->notifications, &sequence_success); diff --git a/applications/main/nfc_old/scenes/nfc_scene_nfc_data_info.c b/applications/main/nfc_old/scenes/nfc_scene_nfc_data_info.c index 8f66b85ce435..734a9a8ce92e 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_nfc_data_info.c +++ b/applications/main/nfc_old/scenes/nfc_scene_nfc_data_info.c @@ -40,20 +40,166 @@ void nfc_scene_nfc_data_info_on_enter(void* context) { furi_string_cat_printf( 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"); + furi_string_cat_printf(temp_str, "\e#MIFARE DESFire\n"); + } else if(protocol == NfcDeviceProtocolNfcV) { + switch(dev_data->nfcv_data.sub_type) { + case NfcVTypePlain: + furi_string_cat_printf(temp_str, "\e#ISO15693\n"); + break; + case NfcVTypeSlix: + furi_string_cat_printf(temp_str, "\e#ISO15693 SLIX\n"); + break; + case NfcVTypeSlixS: + furi_string_cat_printf(temp_str, "\e#ISO15693 SLIX-S\n"); + break; + case NfcVTypeSlixL: + furi_string_cat_printf(temp_str, "\e#ISO15693 SLIX-L\n"); + break; + case NfcVTypeSlix2: + furi_string_cat_printf(temp_str, "\e#ISO15693 SLIX2\n"); + break; + default: + furi_string_cat_printf(temp_str, "\e#ISO15693 (unknown)\n"); + break; + } } else { furi_string_cat_printf(temp_str, "\e#Unknown ISO tag\n"); } // Set tag iso data - char iso_type = FURI_BIT(nfc_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]); + if(protocol == NfcDeviceProtocolNfcV) { + NfcVData* nfcv_data = &nfc->dev->dev_data.nfcv_data; + + furi_string_cat_printf(temp_str, "UID:\n"); + 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, "\n"); + + furi_string_cat_printf( + temp_str, + "DSFID: %02X %s\n", + nfcv_data->dsfid, + (nfcv_data->security_status[0] & NfcVLockBitDsfid) ? "(locked)" : ""); + furi_string_cat_printf( + temp_str, + "AFI: %02X %s\n", + nfcv_data->afi, + (nfcv_data->security_status[0] & NfcVLockBitAfi) ? "(locked)" : ""); + furi_string_cat_printf(temp_str, "IC Ref: %02X\n", nfcv_data->ic_ref); + furi_string_cat_printf(temp_str, "Blocks: %02X\n", nfcv_data->block_num); + furi_string_cat_printf(temp_str, "Blocksize: %02X\n", nfcv_data->block_size); + + switch(dev_data->nfcv_data.sub_type) { + case NfcVTypePlain: + furi_string_cat_printf(temp_str, "Type: Plain\n"); + break; + case NfcVTypeSlix: + furi_string_cat_printf(temp_str, "Type: SLIX\n"); + furi_string_cat_printf(temp_str, "Keys:\n"); + furi_string_cat_printf( + temp_str, + " EAS %08llX\n", + nfc_util_bytes2num(nfcv_data->sub_data.slix.key_eas, 4)); + break; + case NfcVTypeSlixS: + furi_string_cat_printf(temp_str, "Type: SLIX-S\n"); + furi_string_cat_printf(temp_str, "Keys:\n"); + furi_string_cat_printf( + temp_str, + " Read %08llX\n", + nfc_util_bytes2num(nfcv_data->sub_data.slix.key_read, 4)); + furi_string_cat_printf( + temp_str, + " Write %08llX\n", + nfc_util_bytes2num(nfcv_data->sub_data.slix.key_write, 4)); + furi_string_cat_printf( + temp_str, + " Privacy %08llX\n", + nfc_util_bytes2num(nfcv_data->sub_data.slix.key_privacy, 4)); + furi_string_cat_printf( + temp_str, + " Destroy %08llX\n", + nfc_util_bytes2num(nfcv_data->sub_data.slix.key_destroy, 4)); + furi_string_cat_printf( + temp_str, + " EAS %08llX\n", + nfc_util_bytes2num(nfcv_data->sub_data.slix.key_eas, 4)); + break; + case NfcVTypeSlixL: + furi_string_cat_printf(temp_str, "Type: SLIX-L\n"); + furi_string_cat_printf(temp_str, "Keys:\n"); + furi_string_cat_printf( + temp_str, + " Privacy %08llX\n", + nfc_util_bytes2num(nfcv_data->sub_data.slix.key_privacy, 4)); + furi_string_cat_printf( + temp_str, + " Destroy %08llX\n", + nfc_util_bytes2num(nfcv_data->sub_data.slix.key_destroy, 4)); + furi_string_cat_printf( + temp_str, + " EAS %08llX\n", + nfc_util_bytes2num(nfcv_data->sub_data.slix.key_eas, 4)); + break; + case NfcVTypeSlix2: + furi_string_cat_printf(temp_str, "Type: SLIX2\n"); + furi_string_cat_printf(temp_str, "Keys:\n"); + furi_string_cat_printf( + temp_str, + " Read %08llX\n", + nfc_util_bytes2num(nfcv_data->sub_data.slix.key_read, 4)); + furi_string_cat_printf( + temp_str, + " Write %08llX\n", + nfc_util_bytes2num(nfcv_data->sub_data.slix.key_write, 4)); + furi_string_cat_printf( + temp_str, + " Privacy %08llX\n", + nfc_util_bytes2num(nfcv_data->sub_data.slix.key_privacy, 4)); + furi_string_cat_printf( + temp_str, + " Destroy %08llX\n", + nfc_util_bytes2num(nfcv_data->sub_data.slix.key_destroy, 4)); + furi_string_cat_printf( + temp_str, + " EAS %08llX\n", + nfc_util_bytes2num(nfcv_data->sub_data.slix.key_eas, 4)); + break; + default: + furi_string_cat_printf(temp_str, "\e#ISO15693 (unknown)\n"); + break; + } + + furi_string_cat_printf( + temp_str, "Data (%d byte)\n", nfcv_data->block_num * nfcv_data->block_size); + + int maxBlocks = nfcv_data->block_num; + if(maxBlocks > 32) { + maxBlocks = 32; + furi_string_cat_printf(temp_str, "(truncated to %d blocks)\n", maxBlocks); + } + + for(int block = 0; block < maxBlocks; block++) { + const char* status = (nfcv_data->security_status[block] & 0x01) ? "(lck)" : ""; + for(int pos = 0; pos < nfcv_data->block_size; pos++) { + furi_string_cat_printf( + temp_str, " %02X", nfcv_data->data[block * nfcv_data->block_size + pos]); + } + furi_string_cat_printf(temp_str, " %s\n", status); + } + + } else { + char iso_type = FURI_BIT(nfc_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->atqa[1], nfc_data->atqa[0]); + furi_string_cat_printf(temp_str, " SAK: %02X", nfc_data->sak); } - furi_string_cat_printf(temp_str, "\nATQA: %02X %02X ", nfc_data->atqa[1], nfc_data->atqa[0]); - furi_string_cat_printf(temp_str, " SAK: %02X", nfc_data->sak); // Set application specific data if(protocol == NfcDeviceProtocolMifareDesfire) { @@ -139,6 +285,8 @@ bool nfc_scene_nfc_data_info_on_event(void* context, SceneManagerEvent event) { consumed = true; } else if(protocol == NfcDeviceProtocolMifareClassic) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicData); + } else if(protocol == NfcDeviceProtocolNfcV) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVMenu); consumed = true; } } diff --git a/applications/main/nfc_old/scenes/nfc_scene_nfcv_emulate.c b/applications/main/nfc_old/scenes/nfc_scene_nfcv_emulate.c new file mode 100644 index 000000000000..d812988bdfd2 --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_nfcv_emulate.c @@ -0,0 +1,169 @@ +#include "../nfc_i.h" + +#define NFC_SCENE_EMULATE_NFCV_LOG_SIZE_MAX (200) + +enum { + NfcSceneNfcVEmulateStateWidget, + NfcSceneNfcVEmulateStateTextBox, +}; + +bool nfc_scene_nfcv_emulate_worker_callback(NfcWorkerEvent event, void* context) { + furi_assert(context); + Nfc* nfc = context; + + switch(event) { + case NfcWorkerEventNfcVCommandExecuted: + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventUpdateLog); + } + break; + case NfcWorkerEventNfcVContentChanged: + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventSaveShadow); + break; + default: + break; + } + return true; +} + +void nfc_scene_nfcv_emulate_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_nfcv_emulate_textbox_callback(void* context) { + furi_assert(context); + Nfc* nfc = context; + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); +} + +static void nfc_scene_nfcv_emulate_widget_config(Nfc* nfc, bool data_received) { + FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; + Widget* widget = nfc->widget; + widget_reset(widget); + FuriString* info_str; + info_str = furi_string_alloc(); + + widget_add_icon_element(widget, 0, 3, &I_NFC_dolphin_emulation_47x61); + widget_add_string_multiline_element( + widget, 87, 13, AlignCenter, AlignTop, FontPrimary, "Emulating\nNFC V"); + if(strcmp(nfc->dev->dev_name, "") != 0) { + furi_string_printf(info_str, "%s", nfc->dev->dev_name); + } else { + for(uint8_t i = 0; i < data->uid_len; i++) { + furi_string_cat_printf(info_str, "%02X ", data->uid[i]); + } + } + furi_string_trim(info_str); + widget_add_text_box_element( + widget, 52, 40, 70, 21, AlignCenter, AlignTop, furi_string_get_cstr(info_str), true); + furi_string_free(info_str); + if(data_received) { + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + widget_add_button_element( + widget, GuiButtonTypeCenter, "Log", nfc_scene_nfcv_emulate_widget_callback, nfc); + } + } +} + +void nfc_scene_nfcv_emulate_on_enter(void* context) { + Nfc* nfc = context; + + // Setup Widget + nfc_scene_nfcv_emulate_widget_config(nfc, false); + // Setup TextBox + TextBox* text_box = nfc->text_box; + text_box_set_font(text_box, TextBoxFontHex); + text_box_set_focus(text_box, TextBoxFocusEnd); + text_box_set_text(text_box, ""); + furi_string_reset(nfc->text_box_store); + + // Set Widget state and view + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneNfcVEmulate, NfcSceneNfcVEmulateStateWidget); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); + // Start worker + memset(&nfc->dev->dev_data.reader_data, 0, sizeof(NfcReaderRequestData)); + nfc_worker_start( + nfc->worker, + NfcWorkerStateNfcVEmulate, + &nfc->dev->dev_data, + nfc_scene_nfcv_emulate_worker_callback, + nfc); + + nfc_blink_emulate_start(nfc); +} + +bool nfc_scene_nfcv_emulate_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + NfcVData* nfcv_data = &nfc->dev->dev_data.nfcv_data; + uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneNfcVEmulate); + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventUpdateLog) { + // Add data button to widget if data is received for the first time + if(strlen(nfcv_data->last_command) > 0) { + if(!furi_string_size(nfc->text_box_store)) { + nfc_scene_nfcv_emulate_widget_config(nfc, true); + } + /* use the last n bytes from the log so there's enough space for the new log entry */ + size_t maxSize = + NFC_SCENE_EMULATE_NFCV_LOG_SIZE_MAX - (strlen(nfcv_data->last_command) + 1); + if(furi_string_size(nfc->text_box_store) >= maxSize) { + furi_string_right(nfc->text_box_store, (strlen(nfcv_data->last_command) + 1)); + } + furi_string_cat_printf(nfc->text_box_store, "%s", nfcv_data->last_command); + furi_string_push_back(nfc->text_box_store, '\n'); + text_box_set_text(nfc->text_box, furi_string_get_cstr(nfc->text_box_store)); + + /* clear previously logged command */ + strcpy(nfcv_data->last_command, ""); + } + consumed = true; + } else if(event.event == NfcCustomEventSaveShadow) { + if(furi_string_size(nfc->dev->load_path)) { + nfc_device_save_shadow(nfc->dev, furi_string_get_cstr(nfc->dev->load_path)); + } + consumed = true; + } else if(event.event == GuiButtonTypeCenter && state == NfcSceneNfcVEmulateStateWidget) { + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneNfcVEmulate, NfcSceneNfcVEmulateStateTextBox); + } + consumed = true; + } else if(event.event == NfcCustomEventViewExit && state == NfcSceneNfcVEmulateStateTextBox) { + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneNfcVEmulate, NfcSceneNfcVEmulateStateWidget); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeBack) { + if(state == NfcSceneNfcVEmulateStateTextBox) { + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneNfcVEmulate, NfcSceneNfcVEmulateStateWidget); + consumed = true; + } + } + + return consumed; +} + +void nfc_scene_nfcv_emulate_on_exit(void* context) { + Nfc* nfc = context; + + // Stop worker + nfc_worker_stop(nfc->worker); + + // Clear view + widget_reset(nfc->widget); + text_box_reset(nfc->text_box); + furi_string_reset(nfc->text_box_store); + + nfc_blink_stop(nfc); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_nfcv_key_input.c b/applications/main/nfc_old/scenes/nfc_scene_nfcv_key_input.c new file mode 100644 index 000000000000..13d903c4b777 --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_nfcv_key_input.c @@ -0,0 +1,48 @@ +#include "../nfc_i.h" +#include + +void nfc_scene_nfcv_key_input_byte_input_callback(void* context) { + Nfc* nfc = context; + NfcVSlixData* data = &nfc->dev->dev_data.nfcv_data.sub_data.slix; + + memcpy(data->key_privacy, nfc->byte_input_store, 4); + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); +} + +void nfc_scene_nfcv_key_input_on_enter(void* context) { + Nfc* nfc = context; + + // Setup view + ByteInput* byte_input = nfc->byte_input; + byte_input_set_header_text(byte_input, "Enter The Password In Hex"); + byte_input_set_result_callback( + byte_input, + nfc_scene_nfcv_key_input_byte_input_callback, + NULL, + nfc, + nfc->byte_input_store, + 4); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewByteInput); +} + +bool nfc_scene_nfcv_key_input_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventByteInputDone) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVUnlock); + dolphin_deed(DolphinDeedNfcRead); + consumed = true; + } + } + return consumed; +} + +void nfc_scene_nfcv_key_input_on_exit(void* context) { + Nfc* nfc = context; + + // Clear view + byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0); + byte_input_set_header_text(nfc->byte_input, ""); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_nfcv_menu.c b/applications/main/nfc_old/scenes/nfc_scene_nfcv_menu.c new file mode 100644 index 000000000000..60eb354e858d --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_nfcv_menu.c @@ -0,0 +1,68 @@ +#include "../nfc_i.h" +#include + +enum SubmenuIndex { + SubmenuIndexSave, + SubmenuIndexEmulate, + SubmenuIndexInfo, +}; + +void nfc_scene_nfcv_menu_submenu_callback(void* context, uint32_t index) { + Nfc* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, index); +} + +void nfc_scene_nfcv_menu_on_enter(void* context) { + Nfc* nfc = context; + Submenu* submenu = nfc->submenu; + + submenu_add_item( + submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_nfcv_menu_submenu_callback, nfc); + submenu_add_item(submenu, "Save", SubmenuIndexSave, nfc_scene_nfcv_menu_submenu_callback, nfc); + submenu_add_item(submenu, "Info", SubmenuIndexInfo, nfc_scene_nfcv_menu_submenu_callback, nfc); + + submenu_set_selected_item( + nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneNfcVMenu)); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); +} + +bool nfc_scene_nfcv_menu_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexSave) { + nfc->dev->format = NfcDeviceSaveFormatNfcV; + // 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, NfcSceneNfcVEmulate); + if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) { + dolphin_deed(DolphinDeedNfcAddEmulate); + } else { + dolphin_deed(DolphinDeedNfcEmulate); + } + 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, NfcSceneNfcVMenu, event.event); + + } else if(event.type == SceneManagerEventTypeBack) { + consumed = scene_manager_previous_scene(nfc->scene_manager); + } + + return consumed; +} + +void nfc_scene_nfcv_menu_on_exit(void* context) { + Nfc* nfc = context; + + // Clear view + submenu_reset(nfc->submenu); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_nfcv_read_success.c b/applications/main/nfc_old/scenes/nfc_scene_nfcv_read_success.c new file mode 100644 index 000000000000..bdf7692ccb22 --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_nfcv_read_success.c @@ -0,0 +1,94 @@ +#include "../nfc_i.h" + +void nfc_scene_nfcv_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_nfcv_read_success_on_enter(void* context) { + Nfc* nfc = context; + NfcDeviceData* dev_data = &nfc->dev->dev_data; + FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data; + NfcVData* nfcv_data = &nfc->dev->dev_data.nfcv_data; + // Setup view + Widget* widget = nfc->widget; + widget_add_button_element( + widget, GuiButtonTypeLeft, "Retry", nfc_scene_nfcv_read_success_widget_callback, nfc); + widget_add_button_element( + widget, GuiButtonTypeRight, "More", nfc_scene_nfcv_read_success_widget_callback, nfc); + + FuriString* temp_str = furi_string_alloc(); + + switch(dev_data->nfcv_data.sub_type) { + case NfcVTypePlain: + furi_string_cat_printf(temp_str, "\e#ISO15693\n"); + break; + case NfcVTypeSlix: + furi_string_cat_printf(temp_str, "\e#ISO15693 SLIX\n"); + break; + case NfcVTypeSlixS: + furi_string_cat_printf(temp_str, "\e#ISO15693 SLIX-S\n"); + break; + case NfcVTypeSlixL: + furi_string_cat_printf(temp_str, "\e#ISO15693 SLIX-L\n"); + break; + case NfcVTypeSlix2: + furi_string_cat_printf(temp_str, "\e#ISO15693 SLIX2\n"); + break; + default: + furi_string_cat_printf(temp_str, "\e#ISO15693 (unknown)\n"); + break; + } + 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, "\n"); + furi_string_cat_printf(temp_str, "Blocks: %02X\n", nfcv_data->block_num); + furi_string_cat_printf(temp_str, "Blocksize: %02X\n", nfcv_data->block_size); + + 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_nfcv_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) { + // Clear device name + nfc_device_set_name(nfc->dev, ""); + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVMenu); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeBack) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); + consumed = true; + } + + return consumed; +} + +void nfc_scene_nfcv_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_old/scenes/nfc_scene_nfcv_sniff.c b/applications/main/nfc_old/scenes/nfc_scene_nfcv_sniff.c new file mode 100644 index 000000000000..2c0f17981b46 --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_nfcv_sniff.c @@ -0,0 +1,155 @@ +#include "../nfc_i.h" + +#define NFC_SCENE_EMULATE_NFCV_LOG_SIZE_MAX (800) + +enum { + NfcSceneNfcVSniffStateWidget, + NfcSceneNfcVSniffStateTextBox, +}; + +bool nfc_scene_nfcv_sniff_worker_callback(NfcWorkerEvent event, void* context) { + UNUSED(event); + furi_assert(context); + Nfc* nfc = context; + + switch(event) { + case NfcWorkerEventNfcVCommandExecuted: + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventUpdateLog); + break; + case NfcWorkerEventNfcVContentChanged: + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventSaveShadow); + break; + default: + break; + } + return true; +} + +void nfc_scene_nfcv_sniff_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_nfcv_sniff_textbox_callback(void* context) { + furi_assert(context); + Nfc* nfc = context; + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); +} + +static void nfc_scene_nfcv_sniff_widget_config(Nfc* nfc, bool data_received) { + Widget* widget = nfc->widget; + widget_reset(widget); + FuriString* info_str; + info_str = furi_string_alloc(); + + widget_add_icon_element(widget, 0, 3, &I_RFIDDolphinSend_97x61); + widget_add_string_element(widget, 89, 32, AlignCenter, AlignTop, FontPrimary, "Listen NfcV"); + furi_string_trim(info_str); + widget_add_text_box_element( + widget, 56, 43, 70, 21, AlignCenter, AlignTop, furi_string_get_cstr(info_str), true); + furi_string_free(info_str); + if(data_received) { + widget_add_button_element( + widget, GuiButtonTypeCenter, "Log", nfc_scene_nfcv_sniff_widget_callback, nfc); + } +} + +void nfc_scene_nfcv_sniff_on_enter(void* context) { + Nfc* nfc = context; + + // Setup Widget + nfc_scene_nfcv_sniff_widget_config(nfc, false); + // Setup TextBox + TextBox* text_box = nfc->text_box; + text_box_set_font(text_box, TextBoxFontHex); + text_box_set_focus(text_box, TextBoxFocusEnd); + text_box_set_text(text_box, ""); + furi_string_reset(nfc->text_box_store); + + // Set Widget state and view + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneNfcVSniff, NfcSceneNfcVSniffStateWidget); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); + // Start worker + memset(&nfc->dev->dev_data.reader_data, 0, sizeof(NfcReaderRequestData)); + nfc_worker_start( + nfc->worker, + NfcWorkerStateNfcVSniff, + &nfc->dev->dev_data, + nfc_scene_nfcv_sniff_worker_callback, + nfc); + + nfc_blink_emulate_start(nfc); +} + +bool nfc_scene_nfcv_sniff_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + NfcVData* nfcv_data = &nfc->dev->dev_data.nfcv_data; + uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneNfcVSniff); + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventUpdateLog) { + // Add data button to widget if data is received for the first time + if(strlen(nfcv_data->last_command) > 0) { + if(!furi_string_size(nfc->text_box_store)) { + nfc_scene_nfcv_sniff_widget_config(nfc, true); + } + /* use the last n bytes from the log so there's enough space for the new log entry */ + size_t maxSize = + NFC_SCENE_EMULATE_NFCV_LOG_SIZE_MAX - (strlen(nfcv_data->last_command) + 1); + if(furi_string_size(nfc->text_box_store) >= maxSize) { + furi_string_right(nfc->text_box_store, (strlen(nfcv_data->last_command) + 1)); + } + furi_string_cat_printf(nfc->text_box_store, "%s", nfcv_data->last_command); + furi_string_push_back(nfc->text_box_store, '\n'); + text_box_set_text(nfc->text_box, furi_string_get_cstr(nfc->text_box_store)); + + /* clear previously logged command */ + strcpy(nfcv_data->last_command, ""); + } + consumed = true; + } else if(event.event == NfcCustomEventSaveShadow) { + if(furi_string_size(nfc->dev->load_path)) { + nfc_device_save_shadow(nfc->dev, furi_string_get_cstr(nfc->dev->load_path)); + } + consumed = true; + } else if(event.event == GuiButtonTypeCenter && state == NfcSceneNfcVSniffStateWidget) { + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneNfcVSniff, NfcSceneNfcVSniffStateTextBox); + consumed = true; + } else if(event.event == NfcCustomEventViewExit && state == NfcSceneNfcVSniffStateTextBox) { + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneNfcVSniff, NfcSceneNfcVSniffStateWidget); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeBack) { + if(state == NfcSceneNfcVSniffStateTextBox) { + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneNfcVSniff, NfcSceneNfcVSniffStateWidget); + consumed = true; + } + } + + return consumed; +} + +void nfc_scene_nfcv_sniff_on_exit(void* context) { + Nfc* nfc = context; + + // Stop worker + nfc_worker_stop(nfc->worker); + + // Clear view + widget_reset(nfc->widget); + text_box_reset(nfc->text_box); + furi_string_reset(nfc->text_box_store); + + nfc_blink_stop(nfc); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_nfcv_unlock.c b/applications/main/nfc_old/scenes/nfc_scene_nfcv_unlock.c new file mode 100644 index 000000000000..38d7ad563d8d --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_nfcv_unlock.c @@ -0,0 +1,154 @@ +#include "../nfc_i.h" +#include + +typedef enum { + NfcSceneNfcVUnlockStateIdle, + NfcSceneNfcVUnlockStateDetecting, + NfcSceneNfcVUnlockStateUnlocked, + NfcSceneNfcVUnlockStateAlreadyUnlocked, + NfcSceneNfcVUnlockStateNotSupportedCard, +} NfcSceneNfcVUnlockState; + +static bool nfc_scene_nfcv_unlock_worker_callback(NfcWorkerEvent event, void* context) { + Nfc* nfc = context; + NfcVSlixData* data = &nfc->dev->dev_data.nfcv_data.sub_data.slix; + + if(event == NfcWorkerEventNfcVPassKey) { + memcpy(data->key_privacy, nfc->byte_input_store, 4); + } else { + view_dispatcher_send_custom_event(nfc->view_dispatcher, event); + } + return true; +} + +void nfc_scene_nfcv_unlock_popup_callback(void* context) { + Nfc* nfc = context; + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); +} + +void nfc_scene_nfcv_unlock_set_state(Nfc* nfc, NfcSceneNfcVUnlockState state) { + FuriHalNfcDevData* nfc_data = &(nfc->dev->dev_data.nfc_data); + NfcVData* nfcv_data = &(nfc->dev->dev_data.nfcv_data); + + uint32_t curr_state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneNfcVUnlock); + if(curr_state != state) { + Popup* popup = nfc->popup; + if(state == NfcSceneNfcVUnlockStateDetecting) { + popup_reset(popup); + popup_set_text( + popup, "Put figurine on\nFlipper's back", 97, 24, AlignCenter, AlignTop); + popup_set_icon(popup, 0, 8, &I_NFC_manual_60x50); + } else if(state == NfcSceneNfcVUnlockStateUnlocked) { + popup_reset(popup); + + if(nfc_worker_get_state(nfc->worker) == NfcWorkerStateNfcVUnlockAndSave) { + snprintf( + nfc->dev->dev_name, + sizeof(nfc->dev->dev_name), + "SLIX_%02X%02X%02X%02X%02X%02X%02X%02X", + nfc_data->uid[0], + nfc_data->uid[1], + nfc_data->uid[2], + nfc_data->uid[3], + nfc_data->uid[4], + nfc_data->uid[5], + nfc_data->uid[6], + nfc_data->uid[7]); + + nfc->dev->format = NfcDeviceSaveFormatNfcV; + + if(nfc_save_file(nfc)) { + popup_set_header(popup, "Successfully\nsaved", 94, 3, AlignCenter, AlignTop); + } else { + popup_set_header( + popup, "Unlocked but\nsave failed!", 94, 3, AlignCenter, AlignTop); + } + } else { + popup_set_header(popup, "Successfully\nunlocked", 94, 3, AlignCenter, AlignTop); + } + + notification_message(nfc->notifications, &sequence_single_vibro); + //notification_message(nfc->notifications, &sequence_success); + + popup_set_icon(popup, 0, 6, &I_RFIDDolphinSuccess_108x57); + popup_set_context(popup, nfc); + popup_set_callback(popup, nfc_scene_nfcv_unlock_popup_callback); + popup_set_timeout(popup, 1500); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); + dolphin_deed(DolphinDeedNfcReadSuccess); + + } else if(state == NfcSceneNfcVUnlockStateAlreadyUnlocked) { + popup_reset(popup); + + popup_set_header(popup, "Already\nUnlocked!", 94, 3, AlignCenter, AlignTop); + popup_set_icon(popup, 0, 6, &I_RFIDDolphinSuccess_108x57); + popup_set_context(popup, nfc); + popup_set_callback(popup, nfc_scene_nfcv_unlock_popup_callback); + popup_set_timeout(popup, 1500); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); + } else if(state == NfcSceneNfcVUnlockStateNotSupportedCard) { + popup_reset(popup); + popup_set_header(popup, "Wrong Type Of Card!", 64, 3, AlignCenter, AlignTop); + popup_set_text(popup, nfcv_data->error, 4, 22, AlignLeft, AlignTop); + popup_set_icon(popup, 73, 20, &I_DolphinCommon_56x48); + } + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneNfcVUnlock, state); + } +} + +void nfc_scene_nfcv_unlock_on_enter(void* context) { + Nfc* nfc = context; + + nfc_device_clear(nfc->dev); + // Setup view + nfc_scene_nfcv_unlock_set_state(nfc, NfcSceneNfcVUnlockStateDetecting); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); + + // Start worker + nfc_worker_start( + nfc->worker, + NfcWorkerStateNfcVUnlockAndSave, + &nfc->dev->dev_data, + nfc_scene_nfcv_unlock_worker_callback, + nfc); + + nfc_blink_read_start(nfc); +} + +bool nfc_scene_nfcv_unlock_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcWorkerEventCardDetected) { + nfc_scene_nfcv_unlock_set_state(nfc, NfcSceneNfcVUnlockStateUnlocked); + consumed = true; + } else if(event.event == NfcWorkerEventAborted) { + nfc_scene_nfcv_unlock_set_state(nfc, NfcSceneNfcVUnlockStateAlreadyUnlocked); + consumed = true; + } else if(event.event == NfcWorkerEventNoCardDetected) { + nfc_scene_nfcv_unlock_set_state(nfc, NfcSceneNfcVUnlockStateDetecting); + consumed = true; + } else if(event.event == NfcWorkerEventWrongCardDetected) { + nfc_scene_nfcv_unlock_set_state(nfc, NfcSceneNfcVUnlockStateNotSupportedCard); + } + } else if(event.type == SceneManagerEventTypeBack) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneNfcVUnlockMenu); + } + return consumed; +} + +void nfc_scene_nfcv_unlock_on_exit(void* context) { + Nfc* nfc = context; + + // Stop worker + nfc_worker_stop(nfc->worker); + // Clear view + popup_reset(nfc->popup); + nfc_blink_stop(nfc); + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneNfcVUnlock, NfcSceneNfcVUnlockStateIdle); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_nfcv_unlock_menu.c b/applications/main/nfc_old/scenes/nfc_scene_nfcv_unlock_menu.c new file mode 100644 index 000000000000..2f7367256745 --- /dev/null +++ b/applications/main/nfc_old/scenes/nfc_scene_nfcv_unlock_menu.c @@ -0,0 +1,60 @@ +#include "../nfc_i.h" +#include + +enum SubmenuIndex { + SubmenuIndexNfcVUnlockMenuManual, + SubmenuIndexNfcVUnlockMenuTonieBox, +}; + +void nfc_scene_nfcv_unlock_menu_submenu_callback(void* context, uint32_t index) { + Nfc* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, index); +} + +void nfc_scene_nfcv_unlock_menu_on_enter(void* context) { + Nfc* nfc = context; + Submenu* submenu = nfc->submenu; + + uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneNfcVUnlockMenu); + submenu_add_item( + submenu, + "Enter PWD Manually", + SubmenuIndexNfcVUnlockMenuManual, + nfc_scene_nfcv_unlock_menu_submenu_callback, + nfc); + submenu_add_item( + submenu, + "Auth As TonieBox", + SubmenuIndexNfcVUnlockMenuTonieBox, + nfc_scene_nfcv_unlock_menu_submenu_callback, + nfc); + submenu_set_selected_item(submenu, state); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); +} + +bool nfc_scene_nfcv_unlock_menu_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexNfcVUnlockMenuManual) { + nfc->dev->dev_data.nfcv_data.auth_method = NfcVAuthMethodManual; + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVKeyInput); + consumed = true; + } else if(event.event == SubmenuIndexNfcVUnlockMenuTonieBox) { + nfc->dev->dev_data.nfcv_data.auth_method = NfcVAuthMethodTonieBox; + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVUnlock); + dolphin_deed(DolphinDeedNfcRead); + consumed = true; + } + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneNfcVUnlockMenu, event.event); + } + return consumed; +} + +void nfc_scene_nfcv_unlock_menu_on_exit(void* context) { + Nfc* nfc = context; + + submenu_reset(nfc->submenu); +} diff --git a/applications/main/nfc_old/scenes/nfc_scene_read.c b/applications/main/nfc_old/scenes/nfc_scene_read.c index ddb18706cbbc..57396a0e0848 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_read.c +++ b/applications/main/nfc_old/scenes/nfc_scene_read.c @@ -61,29 +61,34 @@ bool nfc_scene_read_on_event(void* context, SceneManagerEvent event) { (event.event == NfcWorkerEventReadUidNfcV)) { notification_message(nfc->notifications, &sequence_success); scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardSuccess); - DOLPHIN_DEED(DolphinDeedNfcReadSuccess); + dolphin_deed(DolphinDeedNfcReadSuccess); consumed = true; } else if(event.event == NfcWorkerEventReadUidNfcA) { notification_message(nfc->notifications, &sequence_success); scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcaReadSuccess); - DOLPHIN_DEED(DolphinDeedNfcReadSuccess); + dolphin_deed(DolphinDeedNfcReadSuccess); + consumed = true; + } else if(event.event == NfcWorkerEventReadNfcV) { + notification_message(nfc->notifications, &sequence_success); + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVReadSuccess); + dolphin_deed(DolphinDeedNfcReadSuccess); consumed = true; } else if(event.event == NfcWorkerEventReadMfUltralight) { notification_message(nfc->notifications, &sequence_success); // Set unlock password input to 0xFFFFFFFF only on fresh read memset(nfc->byte_input_store, 0xFF, sizeof(nfc->byte_input_store)); scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadSuccess); - DOLPHIN_DEED(DolphinDeedNfcReadSuccess); + dolphin_deed(DolphinDeedNfcReadSuccess); consumed = true; } else if(event.event == NfcWorkerEventReadMfClassicDone) { notification_message(nfc->notifications, &sequence_success); scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSuccess); - DOLPHIN_DEED(DolphinDeedNfcReadSuccess); + dolphin_deed(DolphinDeedNfcReadSuccess); consumed = true; } else if(event.event == NfcWorkerEventReadMfDesfire) { notification_message(nfc->notifications, &sequence_success); scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireReadSuccess); - DOLPHIN_DEED(DolphinDeedNfcReadSuccess); + dolphin_deed(DolphinDeedNfcReadSuccess); consumed = true; } else if(event.event == NfcWorkerEventReadBankCard) { notification_message(nfc->notifications, &sequence_success); diff --git a/applications/main/nfc_old/scenes/nfc_scene_restore_original_confirm.c b/applications/main/nfc_old/scenes/nfc_scene_restore_original_confirm.c index e396049aed90..e5570bd0df18 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_restore_original_confirm.c +++ b/applications/main/nfc_old/scenes/nfc_scene_restore_original_confirm.c @@ -11,7 +11,7 @@ void nfc_scene_restore_original_confirm_on_enter(void* context) { DialogEx* dialog_ex = nfc->dialog_ex; dialog_ex_set_header(dialog_ex, "Restore Card Data?", 64, 0, AlignCenter, AlignTop); - dialog_ex_set_icon(dialog_ex, 5, 15, &I_Restoring_38x32); + dialog_ex_set_icon(dialog_ex, 5, 11, &I_ArrowC_1_36x36); dialog_ex_set_text( dialog_ex, "It will be returned\nto its original state.", 47, 21, AlignLeft, AlignTop); dialog_ex_set_left_button_text(dialog_ex, "Cancel"); diff --git a/applications/main/nfc_old/scenes/nfc_scene_rpc.c b/applications/main/nfc_old/scenes/nfc_scene_rpc.c index ee6e8b990a9c..fa01cf41dbda 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_rpc.c +++ b/applications/main/nfc_old/scenes/nfc_scene_rpc.c @@ -55,6 +55,13 @@ bool nfc_scene_rpc_on_event(void* context, SceneManagerEvent event) { &nfc->dev->dev_data, nfc_scene_rpc_emulate_callback, nfc); + } else if(nfc->dev->format == NfcDeviceSaveFormatNfcV) { + nfc_worker_start( + nfc->worker, + NfcWorkerStateNfcVEmulate, + &nfc->dev->dev_data, + nfc_scene_rpc_emulate_callback, + nfc); } else { nfc_worker_start( nfc->worker, NfcWorkerStateUidEmulate, &nfc->dev->dev_data, NULL, nfc); diff --git a/applications/main/subghz/helpers/subghz_error_type.h b/applications/main/subghz/helpers/subghz_error_type.h index e481aa4be846..0f86d6ea7d16 100644 --- a/applications/main/subghz/helpers/subghz_error_type.h +++ b/applications/main/subghz/helpers/subghz_error_type.h @@ -10,4 +10,5 @@ typedef enum { 1, /** File parsing error, or wrong file structure, or missing required parameters. more accurate data can be obtained through the debug port */ SubGhzErrorTypeOnlyRX = 2, /** Transmission on this frequency is blocked by regional settings */ + SubGhzErrorTypeParserOthers = 3, /** Error in protocol parameters description */ } SubGhzErrorType; diff --git a/applications/main/subghz/scenes/subghz_scene_read_raw.c b/applications/main/subghz/scenes/subghz_scene_read_raw.c index 6e576a861838..a29f86a078cd 100644 --- a/applications/main/subghz/scenes/subghz_scene_read_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_read_raw.c @@ -204,7 +204,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { } else { if(scene_manager_has_previous_scene(subghz->scene_manager, SubGhzSceneSaved) || !scene_manager_has_previous_scene(subghz->scene_manager, SubGhzSceneStart)) { - DOLPHIN_DEED(DolphinDeedSubGhzSend); + dolphin_deed(DolphinDeedSubGhzSend); } // set callback end tx subghz_txrx_set_raw_file_encoder_worker_callback_end( @@ -259,7 +259,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { } else { SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx); if(subghz_protocol_raw_save_to_file_init(decoder_raw, RAW_FILE_NAME, &preset)) { - DOLPHIN_DEED(DolphinDeedSubGhzRawRec); + dolphin_deed(DolphinDeedSubGhzRawRec); subghz_txrx_rx_start(subghz->txrx); subghz->state_notifications = SubGhzNotificationStateRx; subghz_rx_key_state_set(subghz, SubGhzRxKeyStateAddKey); diff --git a/applications/main/subghz/scenes/subghz_scene_receiver.c b/applications/main/subghz/scenes/subghz_scene_receiver.c index dcc22b91cc79..6771f8213b55 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver.c @@ -163,7 +163,7 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { case SubGhzCustomEventViewReceiverOK: subghz->idx_menu_chosen = subghz_view_receiver_get_idx_menu(subghz->subghz_receiver); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverInfo); - DOLPHIN_DEED(DolphinDeedSubGhzReceiverInfo); + dolphin_deed(DolphinDeedSubGhzReceiverInfo); consumed = true; break; case SubGhzCustomEventViewReceiverConfig: diff --git a/applications/main/subghz/scenes/subghz_scene_rpc.c b/applications/main/subghz/scenes/subghz_scene_rpc.c index aa6f132d761d..d4bf3e808eb8 100644 --- a/applications/main/subghz/scenes/subghz_scene_rpc.c +++ b/applications/main/subghz/scenes/subghz_scene_rpc.c @@ -40,15 +40,26 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) { } else if(event.event == SubGhzCustomEventSceneRpcButtonPress) { bool result = false; if((state == SubGhzRpcStateLoaded)) { - result = subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx)); - state = SubGhzRpcStateTx; - if(result) subghz_blink_start(subghz); - } - if(!result) { - rpc_system_app_set_error_code(subghz->rpc_ctx, SubGhzErrorTypeOnlyRX); - rpc_system_app_set_error_text( - subghz->rpc_ctx, - "Transmission on this frequency is restricted in your region"); + switch( + subghz_txrx_tx_start(subghz->txrx, subghz_txrx_get_fff_data(subghz->txrx))) { + case SubGhzTxRxStartTxStateErrorOnlyRx: + rpc_system_app_set_error_code(subghz->rpc_ctx, SubGhzErrorTypeOnlyRX); + rpc_system_app_set_error_text( + subghz->rpc_ctx, + "Transmission on this frequency is restricted in your region"); + break; + case SubGhzTxRxStartTxStateErrorParserOthers: + rpc_system_app_set_error_code(subghz->rpc_ctx, SubGhzErrorTypeParserOthers); + rpc_system_app_set_error_text( + subghz->rpc_ctx, "Error in protocol parameters description"); + break; + + default: //if(SubGhzTxRxStartTxStateOk) + result = true; + subghz_blink_start(subghz); + state = SubGhzRpcStateTx; + break; + } } rpc_system_app_confirm(subghz->rpc_ctx, RpcAppEventButtonPress, result); } else if(event.event == SubGhzCustomEventSceneRpcButtonRelease) { @@ -56,9 +67,9 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) { if(state == SubGhzRpcStateTx) { subghz_txrx_stop(subghz->txrx); subghz_blink_stop(subghz); - state = SubGhzRpcStateIdle; result = true; } + state = SubGhzRpcStateIdle; rpc_system_app_confirm(subghz->rpc_ctx, RpcAppEventButtonRelease, result); } else if(event.event == SubGhzCustomEventSceneRpcLoad) { bool result = false; @@ -95,7 +106,7 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) { void subghz_scene_rpc_on_exit(void* context) { SubGhz* subghz = context; SubGhzRpcState state = scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneRpc); - if(state != SubGhzRpcStateIdle) { + if(state == SubGhzRpcStateTx) { subghz_txrx_stop(subghz->txrx); subghz_blink_stop(subghz); } diff --git a/applications/main/subghz/scenes/subghz_scene_save_name.c b/applications/main/subghz/scenes/subghz_scene_save_name.c index 2a292a1ef399..7d0a4f4f8b72 100644 --- a/applications/main/subghz/scenes/subghz_scene_save_name.c +++ b/applications/main/subghz/scenes/subghz_scene_save_name.c @@ -137,9 +137,9 @@ bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) { // Ditto, for RAW signals } else if(scene_manager_has_previous_scene( subghz->scene_manager, SubGhzSceneSetType)) { - DOLPHIN_DEED(DolphinDeedSubGhzAddManually); + dolphin_deed(DolphinDeedSubGhzAddManually); } else { - DOLPHIN_DEED(DolphinDeedSubGhzSave); + dolphin_deed(DolphinDeedSubGhzSave); } return true; } else { diff --git a/applications/main/subghz/scenes/subghz_scene_start.c b/applications/main/subghz/scenes/subghz_scene_start.c index a41e4b06f4ac..0ab5f123ed14 100644 --- a/applications/main/subghz/scenes/subghz_scene_start.c +++ b/applications/main/subghz/scenes/subghz_scene_start.c @@ -92,7 +92,7 @@ bool subghz_scene_start_on_event(void* context, SceneManagerEvent event) { scene_manager_set_scene_state( subghz->scene_manager, SubGhzSceneStart, SubmenuIndexFrequencyAnalyzer); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneFrequencyAnalyzer); - DOLPHIN_DEED(DolphinDeedSubGhzFrequencyAnalyzer); + dolphin_deed(DolphinDeedSubGhzFrequencyAnalyzer); return true; } else if(event.event == SubmenuIndexTest) { scene_manager_set_scene_state( diff --git a/applications/main/subghz/scenes/subghz_scene_transmitter.c b/applications/main/subghz/scenes/subghz_scene_transmitter.c index 1c193c1794d8..274dd61ad37e 100644 --- a/applications/main/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/main/subghz/scenes/subghz_scene_transmitter.c @@ -61,7 +61,7 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { if(subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx))) { subghz->state_notifications = SubGhzNotificationStateTx; subghz_scene_transmitter_update_data_show(subghz); - DOLPHIN_DEED(DolphinDeedSubGhzSend); + dolphin_deed(DolphinDeedSubGhzSend); } return true; } else if(event.event == SubGhzCustomEventViewTransmitterSendStop) { diff --git a/applications/main/subghz/subghz_cli.c b/applications/main/subghz/subghz_cli.c index ac19d65b4994..60845ac99861 100644 --- a/applications/main/subghz/subghz_cli.c +++ b/applications/main/subghz/subghz_cli.c @@ -176,16 +176,19 @@ void subghz_cli_command_tx(Cli* cli, FuriString* args, void* context) { furi_hal_power_suppress_charge_enter(); - furi_hal_subghz_start_async_tx(subghz_transmitter_yield, transmitter); + if(furi_hal_subghz_start_async_tx(subghz_transmitter_yield, transmitter)) { + while(!(furi_hal_subghz_is_async_tx_complete() || cli_cmd_interrupt_received(cli))) { + printf("."); + fflush(stdout); + furi_delay_ms(333); + } + furi_hal_subghz_stop_async_tx(); - while(!(furi_hal_subghz_is_async_tx_complete() || cli_cmd_interrupt_received(cli))) { - printf("."); - fflush(stdout); - furi_delay_ms(333); + } else { + printf("Transmission on this frequency is restricted in your region\r\n"); } - furi_hal_subghz_stop_async_tx(); - furi_hal_subghz_sleep(); + furi_hal_subghz_sleep(); furi_hal_power_suppress_charge_exit(); flipper_format_free(flipper_format); diff --git a/applications/main/u2f/scenes/u2f_scene_main.c b/applications/main/u2f/scenes/u2f_scene_main.c index 251bc4d991ae..992236e7a8b9 100644 --- a/applications/main/u2f/scenes/u2f_scene_main.c +++ b/applications/main/u2f/scenes/u2f_scene_main.c @@ -68,7 +68,7 @@ bool u2f_scene_main_on_event(void* context, SceneManagerEvent event) { notification_message(app->notifications, &sequence_blink_magenta_10); } else if(event.event == U2fCustomEventAuthSuccess) { notification_message_block(app->notifications, &sequence_set_green_255); - DOLPHIN_DEED(DolphinDeedU2fAuthorized); + dolphin_deed(DolphinDeedU2fAuthorized); furi_timer_start(app->timer, U2F_SUCCESS_TIMEOUT); app->event_cur = U2fCustomEventNone; u2f_view_set_state(app->u2f_view, U2fMsgSuccess); diff --git a/applications/services/bt/bt_service/bt.c b/applications/services/bt/bt_service/bt.c index 2dcea34856cc..1b12ee303c6c 100644 --- a/applications/services/bt/bt_service/bt.c +++ b/applications/services/bt/bt_service/bt.c @@ -1,7 +1,7 @@ #include "bt_i.h" -#include "battery_service.h" #include "bt_keys_storage.h" +#include #include #include #include diff --git a/applications/services/desktop/desktop.c b/applications/services/desktop/desktop.c index 28d09cc0d9d1..e1da649408b8 100644 --- a/applications/services/desktop/desktop.c +++ b/applications/services/desktop/desktop.c @@ -135,7 +135,6 @@ static void desktop_auto_lock_inhibit(Desktop* desktop) { void desktop_lock(Desktop* desktop) { furi_hal_rtc_set_flag(FuriHalRtcFlagLock); - furi_hal_rtc_set_pin_fails(0); if(desktop->settings.pin_code.length) { Cli* cli = furi_record_open(RECORD_CLI); @@ -148,6 +147,9 @@ void desktop_lock(Desktop* desktop) { desktop->scene_manager, DesktopSceneLocked, SCENE_LOCKED_FIRST_ENTER); scene_manager_next_scene(desktop->scene_manager, DesktopSceneLocked); notification_message(desktop->notification, &sequence_display_backlight_off_delay_1000); + + DesktopStatus status = {.locked = true}; + furi_pubsub_publish(desktop->status_pubsub, &status); } void desktop_unlock(Desktop* desktop) { @@ -159,12 +161,16 @@ void desktop_unlock(Desktop* desktop) { scene_manager_search_and_switch_to_previous_scene(desktop->scene_manager, DesktopSceneMain); desktop_auto_lock_arm(desktop); furi_hal_rtc_reset_flag(FuriHalRtcFlagLock); + furi_hal_rtc_set_pin_fails(0); if(desktop->settings.pin_code.length) { Cli* cli = furi_record_open(RECORD_CLI); cli_session_open(cli, &cli_vcp); furi_record_close(RECORD_CLI); } + + DesktopStatus status = {.locked = false}; + furi_pubsub_publish(desktop->status_pubsub, &status); } void desktop_set_dummy_mode_state(Desktop* desktop, bool enabled) { @@ -308,63 +314,13 @@ Desktop* desktop_alloc() { desktop->auto_lock_timer = furi_timer_alloc(desktop_auto_lock_timer_callback, FuriTimerTypeOnce, desktop); + desktop->status_pubsub = furi_pubsub_alloc(); + furi_record_create(RECORD_DESKTOP, desktop); return desktop; } -void desktop_free(Desktop* desktop) { - furi_assert(desktop); - furi_check(furi_record_destroy(RECORD_DESKTOP)); - - furi_pubsub_unsubscribe( - loader_get_pubsub(desktop->loader), desktop->app_start_stop_subscription); - - if(desktop->input_events_subscription) { - furi_pubsub_unsubscribe(desktop->input_events_pubsub, desktop->input_events_subscription); - desktop->input_events_subscription = NULL; - } - - desktop->loader = NULL; - desktop->input_events_pubsub = NULL; - furi_record_close(RECORD_LOADER); - furi_record_close(RECORD_NOTIFICATION); - furi_record_close(RECORD_INPUT_EVENTS); - - view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdMain); - view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdLockMenu); - view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdLocked); - view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdDebug); - view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdHwMismatch); - view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdPinInput); - view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdPinTimeout); - - view_dispatcher_free(desktop->view_dispatcher); - scene_manager_free(desktop->scene_manager); - - animation_manager_free(desktop->animation_manager); - view_stack_free(desktop->main_view_stack); - desktop_main_free(desktop->main_view); - view_stack_free(desktop->locked_view_stack); - desktop_view_locked_free(desktop->locked_view); - desktop_lock_menu_free(desktop->lock_menu); - desktop_view_locked_free(desktop->locked_view); - desktop_debug_free(desktop->debug_view); - popup_free(desktop->hw_mismatch_popup); - desktop_view_pin_timeout_free(desktop->pin_timeout_view); - - furi_record_close(RECORD_GUI); - desktop->gui = NULL; - - furi_thread_free(desktop->scene_thread); - - furi_record_close("menu"); - - furi_timer_free(desktop->auto_lock_timer); - - free(desktop); -} - static bool desktop_check_file_flag(const char* flag_path) { Storage* storage = furi_record_open(RECORD_STORAGE); bool exists = storage_common_stat(storage, flag_path, NULL) == FSE_OK; @@ -383,6 +339,11 @@ void desktop_api_unlock(Desktop* instance) { view_dispatcher_send_custom_event(instance->view_dispatcher, DesktopLockedEventUnlocked); } +FuriPubSub* desktop_api_get_status_pubsub(Desktop* instance) { + furi_assert(instance); + return instance->status_pubsub; +} + int32_t desktop_srv(void* p) { UNUSED(p); @@ -427,7 +388,8 @@ int32_t desktop_srv(void* p) { } view_dispatcher_run(desktop->view_dispatcher); - desktop_free(desktop); + + furi_crash("That was unexpected"); return 0; } diff --git a/applications/services/desktop/desktop.h b/applications/services/desktop/desktop.h index 5b12647b8a5f..4eab24fcc50c 100644 --- a/applications/services/desktop/desktop.h +++ b/applications/services/desktop/desktop.h @@ -1,5 +1,7 @@ #pragma once +#include + typedef struct Desktop Desktop; #define RECORD_DESKTOP "desktop" @@ -7,3 +9,9 @@ typedef struct Desktop Desktop; bool desktop_api_is_locked(Desktop* instance); void desktop_api_unlock(Desktop* instance); + +typedef struct { + bool locked; +} DesktopStatus; + +FuriPubSub* desktop_api_get_status_pubsub(Desktop* instance); diff --git a/applications/services/desktop/desktop_i.h b/applications/services/desktop/desktop_i.h index ede6bbcc31c1..0b3d568016b9 100644 --- a/applications/services/desktop/desktop_i.h +++ b/applications/services/desktop/desktop_i.h @@ -71,6 +71,8 @@ struct Desktop { FuriPubSubSubscription* input_events_subscription; FuriTimer* auto_lock_timer; + FuriPubSub* status_pubsub; + bool in_transition; }; diff --git a/applications/services/desktop/desktop_settings.h b/applications/services/desktop/desktop_settings.h index 5d1b6126febe..7ab39094d161 100644 --- a/applications/services/desktop/desktop_settings.h +++ b/applications/services/desktop/desktop_settings.h @@ -36,8 +36,6 @@ #define MIN_PIN_SIZE 4 #define MAX_APP_LENGTH 128 -#define FAP_LOADER_APP_NAME "Applications" - typedef struct { InputKey data[MAX_PIN_SIZE]; uint8_t length; diff --git a/applications/services/desktop/scenes/desktop_scene_debug.c b/applications/services/desktop/scenes/desktop_scene_debug.c index e79c56e111a4..a5bd3a6b1e63 100644 --- a/applications/services/desktop/scenes/desktop_scene_debug.c +++ b/applications/services/desktop/scenes/desktop_scene_debug.c @@ -34,13 +34,13 @@ bool desktop_scene_debug_on_event(void* context, SceneManagerEvent event) { break; case DesktopDebugEventDeed: - dolphin_deed(dolphin, DolphinDeedTestRight); + dolphin_deed(DolphinDeedTestRight); desktop_debug_get_dolphin_data(desktop->debug_view); consumed = true; break; case DesktopDebugEventWrongDeed: - dolphin_deed(dolphin, DolphinDeedTestLeft); + dolphin_deed(DolphinDeedTestLeft); desktop_debug_get_dolphin_data(desktop->debug_view); consumed = true; break; diff --git a/applications/services/desktop/scenes/desktop_scene_main.c b/applications/services/desktop/scenes/desktop_scene_main.c index 053ac56f1e71..d19b5560f940 100644 --- a/applications/services/desktop/scenes/desktop_scene_main.c +++ b/applications/services/desktop/scenes/desktop_scene_main.c @@ -16,6 +16,8 @@ #define SNAKE_GAME_APP EXT_PATH("/apps/Games/snake_game.fap") #define CLOCK_APP EXT_PATH("/apps/Tools/clock.fap") +#define FAP_LOADER_APP_NAME "Applications" + static void desktop_scene_main_new_idle_animation_callback(void* context) { furi_assert(context); Desktop* desktop = context; @@ -77,6 +79,21 @@ static void desktop_scene_main_open_app_or_profile(Desktop* desktop, const char* } while(false); } +static void desktop_scene_main_start_favorite(Desktop* desktop, FavoriteApp* application) { + LoaderStatus status = LoaderStatusErrorInternal; + if(application->is_external) { + status = loader_start(desktop->loader, FAP_LOADER_APP_NAME, application->name_or_path); + } else if(strlen(application->name_or_path) > 0) { + status = loader_start(desktop->loader, application->name_or_path, NULL); + } else { + status = loader_start(desktop->loader, FAP_LOADER_APP_NAME, NULL); + } + + if(status != LoaderStatusOk) { + FURI_LOG_E(TAG, "loader_start failed: %d", status); + } +} + void desktop_scene_main_callback(DesktopEvent event, void* context) { Desktop* desktop = (Desktop*)context; if(desktop->in_transition) return; @@ -141,40 +158,12 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) { case DesktopMainEventOpenFavoritePrimary: DESKTOP_SETTINGS_LOAD(&desktop->settings); - if(desktop->settings.favorite_primary.is_external) { - LoaderStatus status = loader_start( - desktop->loader, - FAP_LOADER_APP_NAME, - desktop->settings.favorite_primary.name_or_path); - if(status != LoaderStatusOk) { - FURI_LOG_E(TAG, "loader_start failed: %d", status); - } - } else { - LoaderStatus status = loader_start( - desktop->loader, desktop->settings.favorite_primary.name_or_path, NULL); - if(status != LoaderStatusOk) { - FURI_LOG_E(TAG, "loader_start failed: %d", status); - } - } + desktop_scene_main_start_favorite(desktop, &desktop->settings.favorite_primary); consumed = true; break; case DesktopMainEventOpenFavoriteSecondary: DESKTOP_SETTINGS_LOAD(&desktop->settings); - if(desktop->settings.favorite_secondary.is_external) { - LoaderStatus status = loader_start( - desktop->loader, - FAP_LOADER_APP_NAME, - desktop->settings.favorite_secondary.name_or_path); - if(status != LoaderStatusOk) { - FURI_LOG_E(TAG, "loader_start failed: %d", status); - } - } else { - LoaderStatus status = loader_start( - desktop->loader, desktop->settings.favorite_secondary.name_or_path, NULL); - if(status != LoaderStatusOk) { - FURI_LOG_E(TAG, "loader_start failed: %d", status); - } - } + desktop_scene_main_start_favorite(desktop, &desktop->settings.favorite_secondary); consumed = true; break; case DesktopAnimationEventCheckAnimation: diff --git a/applications/services/desktop/scenes/desktop_scene_pin_input.c b/applications/services/desktop/scenes/desktop_scene_pin_input.c index 157acebf5401..e062c1b97d27 100644 --- a/applications/services/desktop/scenes/desktop_scene_pin_input.c +++ b/applications/services/desktop/scenes/desktop_scene_pin_input.c @@ -55,7 +55,6 @@ static void desktop_scene_pin_input_back_callback(void* context) { static void desktop_scene_pin_input_done_callback(const PinCode* pin_code, void* context) { Desktop* desktop = (Desktop*)context; if(desktop_pin_compare(&desktop->settings.pin_code, pin_code)) { - furi_hal_rtc_set_pin_fails(0); view_dispatcher_send_custom_event(desktop->view_dispatcher, DesktopPinInputEventUnlocked); } else { uint32_t pin_fails = furi_hal_rtc_get_pin_fails(); diff --git a/applications/services/dolphin/dolphin.c b/applications/services/dolphin/dolphin.c index dd8b7105f094..579b400ad013 100644 --- a/applications/services/dolphin/dolphin.c +++ b/applications/services/dolphin/dolphin.c @@ -13,12 +13,13 @@ static void dolphin_update_clear_limits_timer_period(Dolphin* dolphin); -void dolphin_deed(Dolphin* dolphin, DolphinDeed deed) { - furi_assert(dolphin); +void dolphin_deed(DolphinDeed deed) { + Dolphin* dolphin = (Dolphin*)furi_record_open(RECORD_DOLPHIN); DolphinEvent event; event.type = DolphinEventTypeDeed; event.deed = deed; dolphin_event_send_async(dolphin, &event); + furi_record_close(RECORD_DOLPHIN); } DolphinStats dolphin_stats(Dolphin* dolphin) { @@ -89,15 +90,6 @@ Dolphin* dolphin_alloc() { return dolphin; } -void dolphin_free(Dolphin* dolphin) { - furi_assert(dolphin); - - dolphin_state_free(dolphin->state); - furi_message_queue_free(dolphin->event_queue); - - free(dolphin); -} - void dolphin_event_send_async(Dolphin* dolphin, DolphinEvent* event) { furi_assert(dolphin); furi_assert(event); @@ -204,7 +196,7 @@ int32_t dolphin_srv(void* p) { } } - dolphin_free(dolphin); + furi_crash("That was unexpected"); return 0; } diff --git a/applications/services/dolphin/dolphin.h b/applications/services/dolphin/dolphin.h index 8757e2a37735..1035247e718d 100644 --- a/applications/services/dolphin/dolphin.h +++ b/applications/services/dolphin/dolphin.h @@ -26,18 +26,11 @@ typedef enum { DolphinPubsubEventUpdate, } DolphinPubsubEvent; -#define DOLPHIN_DEED(deed) \ - do { \ - Dolphin* dolphin = (Dolphin*)furi_record_open("dolphin"); \ - dolphin_deed(dolphin, deed); \ - furi_record_close("dolphin"); \ - } while(0) - /** Deed complete notification. Call it on deed completion. * See dolphin_deed.h for available deeds. In futures it will become part of assets. * Thread safe, async */ -void dolphin_deed(Dolphin* dolphin, DolphinDeed deed); +void dolphin_deed(DolphinDeed deed); /** Retrieve dolphin stats * Thread safe, blocking diff --git a/applications/services/dolphin/dolphin_i.h b/applications/services/dolphin/dolphin_i.h index 4bb0df08ee65..ceeff1e1a9a3 100644 --- a/applications/services/dolphin/dolphin_i.h +++ b/applications/services/dolphin/dolphin_i.h @@ -37,8 +37,6 @@ struct Dolphin { Dolphin* dolphin_alloc(); -void dolphin_free(Dolphin* dolphin); - void dolphin_event_send_async(Dolphin* dolphin, DolphinEvent* event); void dolphin_event_send_wait(Dolphin* dolphin, DolphinEvent* event); diff --git a/applications/services/notification/notification.h b/applications/services/notification/notification.h index b38620f0f5f8..0e1c07e5df67 100644 --- a/applications/services/notification/notification.h +++ b/applications/services/notification/notification.h @@ -75,6 +75,8 @@ typedef enum { NotificationMessageTypeForceDisplayBrightnessSetting, NotificationMessageTypeLedBrightnessSettingApply, + + NotificationMessageTypeLcdContrastUpdate, } NotificationMessageType; typedef struct { diff --git a/applications/services/notification/notification_app.c b/applications/services/notification/notification_app.c index f91a73f321de..2f947fe8a00d 100644 --- a/applications/services/notification/notification_app.c +++ b/applications/services/notification/notification_app.c @@ -3,6 +3,9 @@ #include #include #include +#include +#include + #include "notification.h" #include "notification_messages.h" #include "notification_app.h" @@ -20,14 +23,14 @@ static const uint8_t reset_sound_mask = 1 << 4; static const uint8_t reset_display_mask = 1 << 5; static const uint8_t reset_blink_mask = 1 << 6; -void notification_vibro_on(bool force); -void notification_vibro_off(); -void notification_sound_on(float freq, float volume, bool force); -void notification_sound_off(); +static void notification_vibro_on(bool force); +static void notification_vibro_off(); +static void notification_sound_on(float freq, float volume, bool force); +static void notification_sound_off(); -uint8_t notification_settings_get_display_brightness(NotificationApp* app, uint8_t value); -uint8_t notification_settings_get_rgb_led_brightness(NotificationApp* app, uint8_t value); -uint32_t notification_settings_display_off_delay_ticks(NotificationApp* app); +static uint8_t notification_settings_get_display_brightness(NotificationApp* app, uint8_t value); +static uint8_t notification_settings_get_rgb_led_brightness(NotificationApp* app, uint8_t value); +static uint32_t notification_settings_display_off_delay_ticks(NotificationApp* app); void notification_message_save_settings(NotificationApp* app) { NotificationAppMessage m = { @@ -39,7 +42,8 @@ void notification_message_save_settings(NotificationApp* app) { }; // internal layer -void notification_apply_internal_led_layer(NotificationLedLayer* layer, uint8_t layer_value) { +static void + notification_apply_internal_led_layer(NotificationLedLayer* layer, uint8_t layer_value) { furi_assert(layer); furi_assert(layer->index < LayerMAX); @@ -52,7 +56,13 @@ void notification_apply_internal_led_layer(NotificationLedLayer* layer, uint8_t } } -bool notification_is_any_led_layer_internal_and_not_empty(NotificationApp* app) { +static void notification_apply_lcd_contrast(NotificationApp* app) { + Gui* gui = furi_record_open(RECORD_GUI); + u8x8_d_st756x_set_contrast(&gui->canvas->fb.u8x8, app->settings.contrast); + furi_record_close(RECORD_GUI); +} + +static bool notification_is_any_led_layer_internal_and_not_empty(NotificationApp* app) { bool result = false; if((app->led[0].index == LayerInternal) || (app->led[1].index == LayerInternal) || (app->led[2].index == LayerInternal)) { @@ -67,7 +77,7 @@ bool notification_is_any_led_layer_internal_and_not_empty(NotificationApp* app) } // notification layer -void notification_apply_notification_led_layer( +static void notification_apply_notification_led_layer( NotificationLedLayer* layer, const uint8_t layer_value) { furi_assert(layer); @@ -81,7 +91,7 @@ void notification_apply_notification_led_layer( furi_hal_light_set(layer->light, layer->value[LayerNotification]); } -void notification_reset_notification_led_layer(NotificationLedLayer* layer) { +static void notification_reset_notification_led_layer(NotificationLedLayer* layer) { furi_assert(layer); furi_assert(layer->index < LayerMAX); @@ -94,7 +104,7 @@ void notification_reset_notification_led_layer(NotificationLedLayer* layer) { furi_hal_light_set(layer->light, layer->value[LayerInternal]); } -void notification_reset_notification_layer(NotificationApp* app, uint8_t reset_mask) { +static void notification_reset_notification_layer(NotificationApp* app, uint8_t reset_mask) { if(reset_mask & reset_blink_mask) { furi_hal_light_blink_stop(); } @@ -130,28 +140,28 @@ uint8_t notification_settings_get_display_brightness(NotificationApp* app, uint8 return (value * app->settings.display_brightness); } -uint8_t notification_settings_get_rgb_led_brightness(NotificationApp* app, uint8_t value) { +static uint8_t notification_settings_get_rgb_led_brightness(NotificationApp* app, uint8_t value) { return (value * app->settings.led_brightness); } -uint32_t notification_settings_display_off_delay_ticks(NotificationApp* app) { +static uint32_t notification_settings_display_off_delay_ticks(NotificationApp* app) { return ( (float)(app->settings.display_off_delay_ms) / (1000.0f / furi_kernel_get_tick_frequency())); } // generics -void notification_vibro_on(bool force) { +static void notification_vibro_on(bool force) { if(!furi_hal_rtc_is_flag_set(FuriHalRtcFlagStealthMode) || force) { furi_hal_vibro_on(true); } } -void notification_vibro_off() { +static void notification_vibro_off() { furi_hal_vibro_on(false); } -void notification_sound_on(float freq, float volume, bool force) { +static void notification_sound_on(float freq, float volume, bool force) { if(!furi_hal_rtc_is_flag_set(FuriHalRtcFlagStealthMode) || force) { if(furi_hal_speaker_is_mine() || furi_hal_speaker_acquire(30)) { furi_hal_speaker_start(freq, volume); @@ -159,7 +169,7 @@ void notification_sound_on(float freq, float volume, bool force) { } } -void notification_sound_off() { +static void notification_sound_off() { if(furi_hal_speaker_is_mine()) { furi_hal_speaker_stop(); furi_hal_speaker_release(); @@ -174,7 +184,7 @@ static void notification_display_timer(void* ctx) { } // message processing -void notification_process_notification_message( +static void notification_process_notification_message( NotificationApp* app, NotificationAppMessage* message) { uint32_t notification_message_index = 0; @@ -333,6 +343,9 @@ void notification_process_notification_message( reset_mask |= reset_green_mask; reset_mask |= reset_blue_mask; break; + case NotificationMessageTypeLcdContrastUpdate: + notification_apply_lcd_contrast(app); + break; } notification_message_index++; notification_message = (*message->sequence)[notification_message_index]; @@ -361,7 +374,8 @@ void notification_process_notification_message( } } -void notification_process_internal_message(NotificationApp* app, NotificationAppMessage* message) { +static void + notification_process_internal_message(NotificationApp* app, NotificationAppMessage* message) { uint32_t notification_message_index = 0; const NotificationMessage* notification_message; notification_message = (*message->sequence)[notification_message_index]; @@ -548,6 +562,7 @@ int32_t notification_srv(void* p) { notification_apply_internal_led_layer(&app->led[0], 0x00); notification_apply_internal_led_layer(&app->led[1], 0x00); notification_apply_internal_led_layer(&app->led[2], 0x00); + notification_apply_lcd_contrast(app); furi_record_create(RECORD_NOTIFICATION, app); diff --git a/applications/services/notification/notification_app.h b/applications/services/notification/notification_app.h index 88194bfbd535..cacc17ffb0cd 100644 --- a/applications/services/notification/notification_app.h +++ b/applications/services/notification/notification_app.h @@ -32,7 +32,7 @@ typedef struct { Light light; } NotificationLedLayer; -#define NOTIFICATION_SETTINGS_VERSION 0x01 +#define NOTIFICATION_SETTINGS_VERSION 0x02 #define NOTIFICATION_SETTINGS_PATH INT_PATH(NOTIFICATION_SETTINGS_FILE_NAME) typedef struct { @@ -41,6 +41,7 @@ typedef struct { float led_brightness; float speaker_volume; uint32_t display_off_delay_ms; + int8_t contrast; bool vibro_on; } NotificationSettings; diff --git a/applications/services/notification/notification_messages.c b/applications/services/notification/notification_messages.c index 51f3533c32d2..28ec327c6e67 100644 --- a/applications/services/notification/notification_messages.c +++ b/applications/services/notification/notification_messages.c @@ -197,6 +197,10 @@ const NotificationMessage message_force_display_brightness_setting_1f = { .data.forced_settings.display_brightness = 1.0f, }; +const NotificationMessage message_lcd_contrast_update = { + .type = NotificationMessageTypeLcdContrastUpdate, +}; + /****************************** Message sequences ******************************/ // Reset @@ -566,3 +570,8 @@ const NotificationSequence sequence_audiovisual_alert = { &message_vibro_off, NULL, }; + +const NotificationSequence sequence_lcd_contrast_update = { + &message_lcd_contrast_update, + NULL, +}; diff --git a/applications/services/notification/notification_messages.h b/applications/services/notification/notification_messages.h index 1007969176c0..d87cf74f4ee6 100644 --- a/applications/services/notification/notification_messages.h +++ b/applications/services/notification/notification_messages.h @@ -63,6 +63,9 @@ extern const NotificationMessage message_force_vibro_setting_on; extern const NotificationMessage message_force_vibro_setting_off; extern const NotificationMessage message_force_display_brightness_setting_1f; +// LCD Messages +extern const NotificationMessage message_lcd_contrast_update; + /****************************** Message sequences ******************************/ // Reset @@ -138,6 +141,9 @@ extern const NotificationSequence sequence_success; extern const NotificationSequence sequence_error; extern const NotificationSequence sequence_audiovisual_alert; +// LCD +extern const NotificationSequence sequence_lcd_contrast_update; + #ifdef __cplusplus } #endif diff --git a/applications/services/power/power_service/power.c b/applications/services/power/power_service/power.c index 56dbd0f87cf6..72dc8f3f1e75 100644 --- a/applications/services/power/power_service/power.c +++ b/applications/services/power/power_service/power.c @@ -85,30 +85,6 @@ Power* power_alloc() { return power; } -void power_free(Power* power) { - furi_assert(power); - - // Gui - view_dispatcher_remove_view(power->view_dispatcher, PowerViewOff); - power_off_free(power->power_off); - view_dispatcher_remove_view(power->view_dispatcher, PowerViewUnplugUsb); - power_unplug_usb_free(power->power_unplug_usb); - - view_port_free(power->battery_view_port); - - // State - furi_mutex_free(power->api_mtx); - - // FuriPubSub - furi_pubsub_free(power->event_pubsub); - - // Records - furi_record_close(RECORD_NOTIFICATION); - furi_record_close(RECORD_GUI); - - free(power); -} - static void power_check_charging_state(Power* power) { if(furi_hal_power_is_charging()) { if((power->info.charge == 100) || (furi_hal_power_is_charging_done())) { @@ -252,7 +228,7 @@ int32_t power_srv(void* p) { furi_delay_ms(1000); } - power_free(power); + furi_crash("That was unexpected"); return 0; } diff --git a/applications/services/rpc/rpc_desktop.c b/applications/services/rpc/rpc_desktop.c index dbf9796ec56b..0d72b43d5516 100644 --- a/applications/services/rpc/rpc_desktop.c +++ b/applications/services/rpc/rpc_desktop.c @@ -8,6 +8,8 @@ typedef struct { RpcSession* session; Desktop* desktop; + FuriPubSub* status_pubsub; + FuriPubSubSubscription* status_subscription; } RpcDesktop; static void rpc_desktop_on_is_locked_request(const PB_Main* request, void* context) { @@ -39,11 +41,63 @@ static void rpc_desktop_on_unlock_request(const PB_Main* request, void* context) rpc_send_and_release_empty(session, request->command_id, PB_CommandStatus_OK); } +static void rpc_desktop_on_desktop_pubsub(const void* message, void* context) { + RpcDesktop* rpc_desktop = context; + RpcSession* session = rpc_desktop->session; + const DesktopStatus* status = message; + + PB_Main rpc_message = { + .command_id = 0, + .command_status = PB_CommandStatus_OK, + .has_next = false, + .which_content = PB_Main_desktop_status_tag, + .content.desktop_status.locked = status->locked, + }; + rpc_send_and_release(session, &rpc_message); +} + +static void rpc_desktop_on_status_subscribe_request(const PB_Main* request, void* context) { + furi_assert(request); + furi_assert(context); + furi_assert(request->which_content == PB_Main_desktop_status_subscribe_request_tag); + + FURI_LOG_D(TAG, "StatusSubscribeRequest"); + RpcDesktop* rpc_desktop = context; + RpcSession* session = rpc_desktop->session; + + if(rpc_desktop->status_subscription) { + rpc_send_and_release_empty(session, request->command_id, PB_CommandStatus_ERROR); + } else { + rpc_desktop->status_subscription = furi_pubsub_subscribe( + rpc_desktop->status_pubsub, rpc_desktop_on_desktop_pubsub, rpc_desktop); + rpc_send_and_release_empty(session, request->command_id, PB_CommandStatus_OK); + } +} + +static void rpc_desktop_on_status_unsubscribe_request(const PB_Main* request, void* context) { + furi_assert(request); + furi_assert(context); + furi_assert(request->which_content == PB_Main_desktop_status_unsubscribe_request_tag); + + FURI_LOG_D(TAG, "StatusUnsubscribeRequest"); + RpcDesktop* rpc_desktop = context; + RpcSession* session = rpc_desktop->session; + + if(rpc_desktop->status_subscription) { + furi_pubsub_unsubscribe(rpc_desktop->status_pubsub, rpc_desktop->status_subscription); + rpc_desktop->status_subscription = NULL; + rpc_send_and_release_empty(session, request->command_id, PB_CommandStatus_OK); + } else { + rpc_send_and_release_empty(session, request->command_id, PB_CommandStatus_ERROR); + } +} + void* rpc_desktop_alloc(RpcSession* session) { furi_assert(session); RpcDesktop* rpc_desktop = malloc(sizeof(RpcDesktop)); rpc_desktop->desktop = furi_record_open(RECORD_DESKTOP); + rpc_desktop->status_pubsub = desktop_api_get_status_pubsub(rpc_desktop->desktop); rpc_desktop->session = session; RpcHandler rpc_handler = { @@ -58,6 +112,12 @@ void* rpc_desktop_alloc(RpcSession* session) { rpc_handler.message_handler = rpc_desktop_on_unlock_request; rpc_add_handler(session, PB_Main_desktop_unlock_request_tag, &rpc_handler); + rpc_handler.message_handler = rpc_desktop_on_status_subscribe_request; + rpc_add_handler(session, PB_Main_desktop_status_subscribe_request_tag, &rpc_handler); + + rpc_handler.message_handler = rpc_desktop_on_status_unsubscribe_request; + rpc_add_handler(session, PB_Main_desktop_status_unsubscribe_request_tag, &rpc_handler); + return rpc_desktop; } @@ -65,6 +125,10 @@ void rpc_desktop_free(void* context) { furi_assert(context); RpcDesktop* rpc_desktop = context; + if(rpc_desktop->status_subscription) { + furi_pubsub_unsubscribe(rpc_desktop->status_pubsub, rpc_desktop->status_subscription); + } + furi_assert(rpc_desktop->desktop); furi_record_close(RECORD_DESKTOP); diff --git a/applications/services/storage/storage.h b/applications/services/storage/storage.h index a1267575fb88..dccf29592c63 100644 --- a/applications/services/storage/storage.h +++ b/applications/services/storage/storage.h @@ -226,7 +226,7 @@ FS_Error storage_common_stat(Storage* storage, const char* path, FileInfo* filei */ FS_Error storage_common_remove(Storage* storage, const char* path); -/** Renames file/directory, file/directory must not be open +/** Renames file/directory, file/directory must not be open. Will overwrite existing file. * @param app pointer to the api * @param old_path old path * @param new_path new path diff --git a/applications/services/storage/storage_external_api.c b/applications/services/storage/storage_external_api.c index bf474bc9d0b7..5fcaa59216be 100644 --- a/applications/services/storage/storage_external_api.c +++ b/applications/services/storage/storage_external_api.c @@ -422,12 +422,27 @@ FS_Error storage_common_remove(Storage* storage, const char* path) { } FS_Error storage_common_rename(Storage* storage, const char* old_path, const char* new_path) { - FS_Error error = storage_common_copy(storage, old_path, new_path); - if(error == FSE_OK) { + FS_Error error; + + do { + if(!storage_common_exists(storage, old_path)) { + error = FSE_INVALID_NAME; + break; + } + + if(storage_file_exists(storage, new_path)) { + storage_common_remove(storage, new_path); + } + + error = storage_common_copy(storage, old_path, new_path); + if(error != FSE_OK) { + break; + } + if(!storage_simply_remove_recursive(storage, old_path)) { error = FSE_INTERNAL; } - } + } while(false); return error; } diff --git a/applications/settings/desktop_settings/scenes/desktop_settings_scene_favorite.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_favorite.c index 94c5ee9f0493..4b5c47921239 100644 --- a/applications/settings/desktop_settings/scenes/desktop_settings_scene_favorite.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_favorite.c @@ -5,6 +5,9 @@ #include #include +#define EXTERNAL_APPLICATION_NAME ("[External Application]") +#define EXTERNAL_APPLICATION_INDEX (FLIPPER_APPS_COUNT + 1) + static bool favorite_fap_selector_item_callback( FuriString* file_path, void* context, @@ -44,6 +47,8 @@ void desktop_settings_scene_favorite_on_enter(void* context) { uint32_t primary_favorite = scene_manager_get_scene_state(app->scene_manager, DesktopSettingsAppSceneFavorite); uint32_t pre_select_item = 0; + FavoriteApp* curr_favorite_app = primary_favorite ? &app->settings.favorite_primary : + &app->settings.favorite_secondary; for(size_t i = 0; i < FLIPPER_APPS_COUNT; i++) { submenu_add_item( @@ -53,21 +58,25 @@ void desktop_settings_scene_favorite_on_enter(void* context) { desktop_settings_scene_favorite_submenu_callback, app); - if(primary_favorite) { // Select favorite item in submenu - if((app->settings.favorite_primary.is_external && - !strcmp(FLIPPER_APPS[i].name, FAP_LOADER_APP_NAME)) || - (!strcmp(FLIPPER_APPS[i].name, app->settings.favorite_primary.name_or_path))) { - pre_select_item = i; - } - } else { - if((app->settings.favorite_secondary.is_external && - !strcmp(FLIPPER_APPS[i].name, FAP_LOADER_APP_NAME)) || - (!strcmp(FLIPPER_APPS[i].name, app->settings.favorite_secondary.name_or_path))) { - pre_select_item = i; - } + // Select favorite item in submenu + if(!curr_favorite_app->is_external && + !strcmp(FLIPPER_APPS[i].name, curr_favorite_app->name_or_path)) { + pre_select_item = i; } } +#ifdef APP_FAP_LOADER + submenu_add_item( + submenu, + EXTERNAL_APPLICATION_NAME, + EXTERNAL_APPLICATION_INDEX, + desktop_settings_scene_favorite_submenu_callback, + app); + if(curr_favorite_app->is_external) { + pre_select_item = EXTERNAL_APPLICATION_INDEX; + } +#endif + submenu_set_header( submenu, primary_favorite ? "Primary favorite app:" : "Secondary favorite app:"); submenu_set_selected_item(submenu, pre_select_item); // If set during loop, visual glitch. @@ -82,23 +91,11 @@ bool desktop_settings_scene_favorite_on_event(void* context, SceneManagerEvent e uint32_t primary_favorite = scene_manager_get_scene_state(app->scene_manager, DesktopSettingsAppSceneFavorite); + FavoriteApp* curr_favorite_app = primary_favorite ? &app->settings.favorite_primary : + &app->settings.favorite_secondary; if(event.type == SceneManagerEventTypeCustom) { - if(strcmp(FLIPPER_APPS[event.event].name, FAP_LOADER_APP_NAME) != 0) { - if(primary_favorite) { - app->settings.favorite_primary.is_external = false; - strncpy( - app->settings.favorite_primary.name_or_path, - FLIPPER_APPS[event.event].name, - MAX_APP_LENGTH); - } else { - app->settings.favorite_secondary.is_external = false; - strncpy( - app->settings.favorite_secondary.name_or_path, - FLIPPER_APPS[event.event].name, - MAX_APP_LENGTH); - } - } else { + if(event.event == EXTERNAL_APPLICATION_INDEX) { const DialogsFileBrowserOptions browser_options = { .extension = ".fap", .icon = &I_unknown_10px, @@ -109,36 +106,29 @@ bool desktop_settings_scene_favorite_on_event(void* context, SceneManagerEvent e .base_path = EXT_PATH("apps"), }; - if(primary_favorite) { // Select favorite fap in file browser - if(favorite_fap_selector_file_exists( - app->settings.favorite_primary.name_or_path)) { - furi_string_set_str(temp_path, app->settings.favorite_primary.name_or_path); - } - } else { - if(favorite_fap_selector_file_exists( - app->settings.favorite_secondary.name_or_path)) { - furi_string_set_str(temp_path, app->settings.favorite_secondary.name_or_path); - } + // Select favorite fap in file browser + if(favorite_fap_selector_file_exists(curr_favorite_app->name_or_path)) { + furi_string_set_str(temp_path, curr_favorite_app->name_or_path); } - submenu_reset(app->submenu); if(dialog_file_browser_show(app->dialogs, temp_path, temp_path, &browser_options)) { - if(primary_favorite) { - app->settings.favorite_primary.is_external = true; - strncpy( - app->settings.favorite_primary.name_or_path, - furi_string_get_cstr(temp_path), - MAX_APP_LENGTH); - } else { - app->settings.favorite_secondary.is_external = true; - strncpy( - app->settings.favorite_secondary.name_or_path, - furi_string_get_cstr(temp_path), - MAX_APP_LENGTH); - } + submenu_reset(app->submenu); // Prevent menu from being shown when we exiting scene + curr_favorite_app->is_external = true; + strncpy( + curr_favorite_app->name_or_path, + furi_string_get_cstr(temp_path), + MAX_APP_LENGTH); + consumed = true; } + } else { + curr_favorite_app->is_external = false; + strncpy( + curr_favorite_app->name_or_path, FLIPPER_APPS[event.event].name, MAX_APP_LENGTH); + consumed = true; } - scene_manager_previous_scene(app->scene_manager); + if(consumed) { + scene_manager_previous_scene(app->scene_manager); + }; consumed = true; } diff --git a/applications/settings/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c index 8efbc5e0844a..450aaee144f9 100644 --- a/applications/settings/notification_settings/notification_settings_app.c +++ b/applications/settings/notification_settings/notification_settings_app.c @@ -20,6 +20,34 @@ static const NotificationSequence sequence_note_c = { NULL, }; +#define CONTRAST_COUNT 11 +const char* const contrast_text[CONTRAST_COUNT] = { + "-5", + "-4", + "-3", + "-2", + "-1", + "0", + "+1", + "+2", + "+3", + "+4", + "+5", +}; +const int32_t contrast_value[CONTRAST_COUNT] = { + -5, + -4, + -3, + -2, + -1, + 0, + 1, + 2, + 3, + 4, + 5, +}; + #define BACKLIGHT_COUNT 5 const char* const backlight_text[BACKLIGHT_COUNT] = { "0%", @@ -64,6 +92,15 @@ const char* const vibro_text[VIBRO_COUNT] = { }; const bool vibro_value[VIBRO_COUNT] = {false, true}; +static void contrast_changed(VariableItem* item) { + NotificationAppSettings* app = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + + variable_item_set_current_value_text(item, contrast_text[index]); + app->notification->settings.contrast = contrast_value[index]; + notification_message(app->notification, &sequence_lcd_contrast_update); +} + static void backlight_changed(VariableItem* item) { NotificationAppSettings* app = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); @@ -136,6 +173,13 @@ static NotificationAppSettings* alloc_settings() { VariableItem* item; uint8_t value_index; + item = variable_item_list_add( + app->variable_item_list, "LCD Contrast", CONTRAST_COUNT, contrast_changed, app); + value_index = + value_index_int32(app->notification->settings.contrast, contrast_value, CONTRAST_COUNT); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, contrast_text[value_index]); + item = variable_item_list_add( app->variable_item_list, "LCD Backlight", BACKLIGHT_COUNT, backlight_changed, app); value_index = value_index_float( diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_0.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_0.png new file mode 100644 index 0000000000000000000000000000000000000000..8b8dc80bce09adfd26988d9021687d77b536961a GIT binary patch literal 1312 zcmV+*1>gFKP)!9vlzwsRa1aLAChG-i`h5a7r0cT|980rK&1wUXT*8Mph`eZ4FU5kOPybzQGec!l*&!|Zn*r2HqzmnMLv z{I|h6?0VfJbH>BT@zy!6B0(w#_=@roR0Xs4hbWglXAi?UfCV;-k;9l}HK;f6(B5DF zmV2w8v*z>=CcqQckIJ{ku?~=#&`LQ{*=_DIJBg;h5W)t7Tug#W_be6Wxoj`)SJ@UB zW*HeR1hkBufgZuUIeVT9wX$Btz;xL?60nVoMgT3IF=STs!j80@o{aWdtF+z$qe|A~ zWC@}XflUHx61cJwXb)Jst|6*C6imfvd4Rmm#I!14CD4P{EK`%^d4k9qBGzwtrgjb{ z*+NMmn(*uj%`IzRZs~=xjE6zaO0LJdXL$%f+NEAQ^T|3MS%+u&NO;J`epb$q0Ym_# zU7D34F}seB^!GJ|Tb`jE8<{729}Cw_n$1eYMv^K`-i$Hrc#YUv?w~0y(%a8^2qvg~ z0Bxb!g?lAs`x)zyQvr5hp<<*`Yx@9N>E?~k%ux!SM_A#bVkgV5cr5`+S(hz)&7*d#mkU^l zW;>ULXj1E8YXa=pY-;=SnaZN)1+x8uEa>k9GO(lKOBr8RHU!Kp5r+uC%=$IgCa?8c zwb6XQgSIausnhOn|84K_);+tDcr*k=mF8u`J0w*edhs9iFig)oOaR3CGA&-DsWMaH zy{?`d(`$ff*00I2u%c3+cmOX;9@&J}i?@2`vwP{5#r8s>=Bh`$SdUa0(4GY_!HVY$ zIX#!%qDKHk`BDZ_Au!0WT^Y!#0J8Dbk|o`}28LB4%I|ra47MTwY9&#ys+1lHECr#~ z@8v`Fb19EOx^2E4yi04;f_ygM)#O@t4^@88&0F)0U<(hhyYefLT)?Y%EJa#>x0dhC z6U7#N0IQ1FkrbW>K*mKnfbIVy&m|B%LV(%j+6rXrcr?f9mA1?rU?~B!@atYJ z63B5@pTO#S$g!g&n4SdI#7Qpr&B#3?N;&-d-#+SS2LdCy4Gh90J&GoE;jhM$9ZA zHNMpwko&g61Ug4H9Hc`4;?_JM%(mvu$YTPr%xH+vfbJ<94k(X<>q1fVssWF|8Ea;g zOHay2=g5$N`kO%r5SO1l$fqid739i{NA6wrEWqodw~#H+HeT)kWG`%DM4Ct_3EU9i z^|s|WZL{p=k2S|iav)i^Yy_1u{!&aPz9X&a^a~;F#Z6}w_!jpTNF*m&mU|AX4`VVx_e>rre@}rpD6nZ1hFNgj(w)*AJsP!NBKaPJI WRj7UFKPQ6#0000UP)R>S-1ZeG$;H`iWptVDSHv&q4)(#2Y1~>r@ z-i0XyI9}jAI3D2Rm_~r(1>S)_PYduSP(oK5U&y&iav(Z^<^n(3C9Ldgr!zS@z#v9L z+)m1G?GT`ZED3f~ertySWkgA^qw-q=B!SZA=|=kj?YQ}aq6g@Tr9b`pm*9DUoef~v z14x_tn&M}opCu<3nn*(gctZJ+`74LR=g)>NZG6`Hsp6&k`S(>!YXl+PUX)zgI7<%g zK)d`a-FIXyjToay6JWLVBj&bbjvRROu%%oeswB(OC0SAAgnEG4{r`w1Ti-{lN2_Y0 z_gKa;N`}5ZCjx>5FamI)5Xc;CRH2%sN$W%omlMldOPVi2PWn9^QzZe605oQ5sJxQrKs^qQoTW8}&y$raL;$N+?$^EYC)>!`4O6KmKE0`x|o~3*FgcUL@88d+WMv!K)qplL= z0cOl2%_UVqR?-NFx(+UsGNU`=z<4G9;JoDTL+*l}_L+e5wzCfRy+}NI?IkcvAVT9RdtNBY{SQ z9WB3O>lZ_I$|pE95=7yZi*y}p4sVQy5&>qhR;Pp5(1+8tK<@8 z0z}-eb|BgKrditR=7|PQ0;`UX#DD2?G(@W8lezgN})QA(Y2#}d(8vTe!yt% zFaz)qfKUYDKvpD$+@<%mETtk6M}Dp11-9!0>{|LsWuF9V4EF+&y=sc3O0Rg4t@;47 zT;dE;c_h#jm)W0|*m;(p+3z+4nAr(K&KtEnOGy=yOY76HlilkUA)s0Ytps)B{j-LO z=dpSPnRc^>>HkHHxwvqMC<3fb0zFh+HJ>BXGPdwY2za_)N5V?d_-89G@Ss&3k@+nw zCBQE!o?^6=2Dfe;gW_j~~W?4yyPl36}K%P*$QPM~58$BbyJn1Q>}&(*5W#kpw3!2&HP)JgVkN<6 ztPOuX9C5%i8%ZZ$_!mp7fP?+8)$8HMn%Cp}<yl_rMZH_r8gO0LXcB!;h(BF|@B4lo39jq<_wVd;Rmw`Oqss&Qo8V<6n3xLmK3nv@F0^@o zw__^ML+~Aq;lJ()W+-?otk1Wj^2b;}fP=lUgaBXn0=ruO7{>#A9?J;uRWGo!^^b9? zfNcTG#m=6=A;AB@)*ESLQC=Y1C%|i{?jwAj0NjSojkl0MvQUrpTIP!MA0(6#fQo@| zkvp}At(K&%8U7AGKV`iZIe2~4TC4W5i~!tXsugZYBr}%Ak$5F>@mzC$OoWPcl@MUn z=2)u;ZXC5?Qq1sxn6;qJLU^!kQmA8VQeBptMu80GX1+BKrwYO5t(dl@CKFEXv{G$X<&V)+1#payK44|stJ-9a1Xgg$m+~n}hBijS`D$1KR0(K- zr2N$tL+eYSUG3N%Fe?Bm5u~h`3X72tKvf9dW)Z|`1Sz0A85iC(Prx;kIPzExD3eS4 z9090Stn_&$ETtjkEjSCNK3hYC6+iRE5RYQ3ss|`fvTBKh@cJB2MIe zd?MMzF5QxhRV0r1T82DZ5&$PyT)f5Oxz81#%06!G+!$!>R>g5-f`rJBV4EDk>f&*$ zxvJM-fu-qVg-7{Z5=xQ4`}~i30Ls#}nm01XLsC=m1p&k5iWT3`V70FK>261uiP0-E<#-Noem64SE2nik| zfTZ|}2FH}AZDuztCxmm{gjMm}JRU41fRx!+$9^v3?wF%mu5{>Qna4ABStDo++rfq= zLz88Z_f|wgLHg_AmPKhYs4<>SnH3$@x*NPCNR@%y;f)pA;-a!wDA?+jE5byi+_dIX zB_V)Iw6x|(CZ0W6DOi+=d-;{!Oi#~1TSLo#7$GS*vKgKSj)ol1S|C=2la9GtzZe1$ zZS-_x*jab{6guYK{y6xc7b*cFO$m5!XOdVs*H@tuAd|?gQoa{oC!`Z0000mBy|ne^TZt@vmHRM!mvv0_!KB`m38>n@-Qqt49G3Z(7^k6{s(`g^M- zUk=+7V5i<3fX=_({7$uV)b;*3Za&&Q61F4&<@6cCkOoPilaxTs4z{Hgk=*A|B5Xr| z-F7+$NjdCgTu#E}x&mun=QI{-Tn$SJV0Aj~dE33z;#+J*U{y7>GlBLTWn)yCj1UQ6 zA_1gB5-Y4q+)7BrB6Sad{(XY}cWa8Upqv1sMT!f1fmu7R?}{q9K#TmE%$ z#%`_J@tLB{i1VrOBMRYm1lXb9*I*$5?(;pujs?AjFoNxLfRzQ22VT)9`aFQ#I`;OC z6M|N0;8~C&K>vR3pw$9g zF{g<-+?r8!MP%)!2|)no>}V@2s$WC9?#b1ZLn-ZJnG)z}V=n$6<#7v%@b8q}X@@}; zLBxYo!@mY9JZlF(lu9Tmo{1RCt{2UD1vtD+r}F_y2#{eX5P&0)l{ImnWG_x~EH}I3gUn zGEZx*ffLX3002P1P#25wU&J7<<1Z1;!=K2(T5Hf+`$vR}`UoY!i%WuYkU{`}OM+97 zMgV|If)kKRfQ$M_C%}yYwQ(cB#}T3fjPOQ*)AfNql6h^39Ls|x1o##7j`9$?(q>q8 z1pHbqFl$dG=L6gvzy&J_syQFv62J{D2`V}t;1b~TSW19j%L87F?5eu^0d55NJT3u( zz(s+|yC2{Z;PbdbP#~x%Pbl2N1lXm2OXG~zlofvaRyVbV{&=Vu ziKYlZ8IqxdS&}O$4>=u~&s$9A0Hbmz`^Mwsid)ADNW0(TJbZ0N6fqNkGYG$r9VBJT z6fA~T2(7QPv7Hf)@864tnE;$YlF_5r6sm=8O_b?L(7(2jfGQpPIisUMxDqHCZCU&Z z_G@9S=Oex{rH_Wq8dIT-OzmvyGf~dx65Hr|aUTsEpmzpN>U#Sm5lW+%>?#-2 z9}SBfs{)}Y5@?PDP1M+-72J041gzzq6g74WML*pR&Wsq|h{QSH(oT*@6ptZ**O}3~ zORHB?&+|eOCfVIahO|N1xFg z0a|Bza)~koIANzpLUaC8ueC>n7F!9Rb$TB%-_PP}GYK>!>1rUgkyl|E0V0&a(al;F zIU)#Qb-uLwJ!?rPfVWiXjl_noJSs*v+Uf|c^SSZ*xjZCDCqTq5>Bo}FABk+yVK(bn zz;gh|)r8m9GD#o?Cy3zR`0o@Vouu7)BZABllAC{)kR_$yh~1i%SmEZ5)F9&4rE!uZ z6h(F-pH{5qvPhxYak5OL)=C{qQYg1Ty0&Z*sD))0RRZM{Dk?}}+R{+M^YrhPOae!U zXlU$)B;a5TqX#}tI7mtEu|kl>@h6dDHreBxNuBqjBcOaQKyxmi7XB?_OvFx>6wnzg z6M_KF+R>R9HGVYpeN-vvB7jH9`VzRE%7t{UIYeF8k3T~K7Xd~Kwc@1kuZ8xQ(3FRx zd}&(_z!5>anCKEvYOzKlq8UTM+w`$~HsyZ?SMky$bnb8!|+UcF&I*uek_Za2?GYN@haopH5Bv`fkHBP{4VAR^I zBp9t>Is%N8JZeI#>?@5yVK(Ae5Y>dKGWT>9AgNjuq8z{pB&!^;Gsno7+nogV;=>Dk z{>(TiqqO=;HDE!Q6pYWNU+D6E0inGBT!PHPvioo8=R>#-;B`i(L+>&0fBXfU?PI4J SQ|eRz00001RCt{2U0H79Fbq|Sx&M{jFBJlZt4K;ztOpcLQd=7z_Za;= z&+{}VKA%r(t+jxmE*9fo#2{Vpmk8(KCvvdodD`psEKO%iR*a$!879AbY z?-n|z{WIE&-IHa>%mkn|VqvM~FscP^l9lPghFO7?oLJ^C&KYe5(qaIt^JiK73ifMZ z-3N4k+C5__Wwv$uL_8gg4jjzX+3_Oc1FDh3X)1QVL>jG@N1p9{G)zE0Z1~{o_*xQ( z^w6x=ZFrFWXjtS}6$s_YaIoul3ct1cm9QyTqx*`Q-*HqW(27ip;k8JV@GafMh(Pfe z0(gZPtzDeZ;C0yb(rauUY5ti#mM6doRX!@+qtZu-6db5;Cczqn79|NlrCmEPThFkh za+EchtshuOP=){}XnG_x{$Kij0ri;$TM3{QI@WlC_hu5vTG7*j>mshgG6Ha|QZ1yz zT4gyR2w@dIr~RI_q!YlKs*Ib28(rxtq=U8!LMwb~ym2lM3DOA=p(W#3T>7J_$44Q{ zExJ3Xag$tiWn?N8@|=np>Af zNL--^n`63L`V`B#ETvHGI9Xf7){40$&Xilg-CH&Y)MB>7wi}pGFss0sX=_6Xi*?Ed zff6Db8oR+2a9|B%1av19xFGk~LXbxACy`<{*rSAr`FqI)lb_ zytFL_popMdOmqs!wOAt&(Tu_1ZTeWQP5GZe7L2AV0#yIt4X{=vTTA?(K^jOb?K$%J z;~DP_FqfvYO2Hc8W~74Lm>EqW?LNKpTgTx_&?CecU?w23ERGs`h6Jm$Un2xq4UAfw zl?2inrY(R}$-^eJmVLP~Fw9yU3!<7ZRpy?~0=TLchA0701(H>Q*coGF%W$Kpc= z^glBK%1Eu=k_}i8Rtko`=^MIyZ$M}-0Hz?buxS5H{d@?o19*jzDbVW%{>Lu}Np_em SiDGyF0000JTLyc{VyfP^~=?5+=tkt}LU=2#IdA;7m_bX0`Uoi@X= zBjDR|0k1usoDXnvfDo)C=;nNYLx3=}BMghMFrG=iUQs34iP{~d;t32fDCZ5ZWqaS zhLQ*{8l9#7X~uct29KKnuMuyMj*&2(0OQVI>3r_GZa2LX%7mcR&aWQBJ4g5a$5!1y zZYN7Ox+?sRNiHXZbqxOi1q7%H{ZeuzC8Il|GNE=8;9eB9xRC@^ZD5>SQJ=2@xBDZ` z!{4olB4z^248osti_XsIJA~HT*|;jmaQygLHp~Q=8Due9b5pv7ZcUUKNihCyApuo7 zj&o*5fwCNcGTyTI73|l-YDdPSVylF-(pSUq;=RUnc$|#d+0->z&YvZ=+4thS8YWt(? zEeSw5{iy`dt7k~pXpR7_Gb6b~8v^XG(=(wt|D^{^W}jK`C;_xiry5WAyOjj;NV*zu zZRAy0MgXo?u7z~7Rz;2sLRg*8?f%GG$_WrHRYoJRp(~FH=|)=}p>_Ujym77w36?w- z?giy=uKeN1mK|oRjs-ji0AEc+ZEceTV$1{){5Sr03YkvQ?mUSgUP8|1_Y$(D6r8bJ zs}d{R+~FETvvp~l#0f>2oygR;gEL@}Lbc;mnMkdbI+nOlZUOh*wn?BCmR-~dlvAjv zz=df`LkZ6_e%3Mxl#tQTcp995gEfp1_&Aw?OLDgrf;5ibi4@*sZ{|$uyqAuE_Pqej zxx8EWw}>$rJDF2JJy<3L0qnJ-D}+&*U00a$arsnS(>hrf;G;qCMDNk}YI!wr1?cpOwwTD_$jupmte#%I$vbot(Z)LsBCLAhI!_| z5oF?&Hkw;=@+oU6HQ82(5RwH@`R^=Kv&zUTV{*zHnSc2A_%nx5hM*xLg|IYmML~6cnU!ZM3E21O1sGYxOW0^OjB{eSZ!ET zE&fm^AN~oiOK}Vaj%oTcn)xh9c`bYv-pY?46PKpp@6^3B-O*8BVMe|(K_Es%LC4$W zSWh4o&0E|7{Eo*g=>ld@)$DVawFFXkkU9vX;PP=Z)I2o;sU5ZODc}6__Ljv zf<~FRmhV~3wA2iwHH7?!5uAc&Hp3$Dtjn>i1tQa(M9du$1ah6SDCJw%R@uE|&RxD8 zd=Lwf05e4i_-tg5=sDL{ArfFEkjqlO6<00000NkvXXu0mjfW{@gA literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_16.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_16.png new file mode 100644 index 0000000000000000000000000000000000000000..fc7b76696c1140ed9f17af4fcccc840e8a07b32b GIT binary patch literal 1158 zcmV;11bO?3P)%JcTp? zv{oW`0;vKh&L>>}6$Q?wBEZL4B7lkl=TZ^i<17#h&}*D43Q5 ztaiR+Bf<%sjqyIQ2q4*b)e?|})&bP-S%W;Qqe4ch;l~r zASch7RY1pQh>!KmS2wa$jm*8CyVB4ljV zTCR;<3)+hu*ZR{iC1a9FJsa$RT05e!oa~=7bDXpYkby`2vk`!s{n-CK`vII?s~s!# zN|+J2rdy&M7ddwA3A|bWSxb;r1l;c)=SMEDk7)(ZK5+D`f==+f_po#3ca9f8L>8X` z*Z+sd!Q-*>DO=i?OuS=rqyR9dpIlLB*7otUlt^+msNcLoI7R@c&U9}>%X*Au3BZmW z_e3n?w^aaIr;lN@AB(NO8e1o#T}~`Ev}3SL0Nf^t7AgD9+T0D*ez=Wwf3ADtp(Qp z+QiNh_NnhiTiZH;vvurO;ns0&-QPcBc9(4i&2C^oo*Moou<%S}@*S*G$aOsX@m3Lp zz7$G5r1re1T|Mv4nCChpTpplt4CibJ)$XRE3q@!S;E4#)4wCi{qKULW8{WCnlp-Yw zv~GxSzhkz&_MU{d#vetXiaL=?z<-8~2@U+sixh^Vu!QxfjU#L0ND~Rf2w+)*v}i+_ zl~uD};{>i%JcCsP(ml8%fRt!p7qqs0IU5)&mIrU58$rgk-8lePl3-*cO3}8x*Iz}( zwWqg($7G`e*B_6AqMhnpR^Con6@Zl>{rlov!utRbjyH9(UR3(+ApDJ>S!b+h+7$oz Y1sh6G!Jt?Yg#Z8m07*qoM6N<$g7uaj0ssI2 literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_17.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_17.png new file mode 100644 index 0000000000000000000000000000000000000000..013e2008a2f51e46a24ea78341d0916c5c7483fb GIT binary patch literal 1161 zcmV;41a|w0P)3~9W2H_#2~le4-xjm4|1^Uy6C#DKO!8|2b2Ie4hi-_3IT`?33fpm z0f-I>c0eit4(cPF0LKc{#<2h|2c!-#!fge1uMf1AEV>uuSP?8Cz_*|kRD{r#lwp|* z__kPJc0ZMbPjq5{5WFO)CVZkpfH15is3?4*Lx9)ggJ=i;4c5^FK73V8h(g;}R5iDFi@o(rRI(>#7}kC4_@Oez;EwKYNVXIjXzI z^dJxkZJyCVXPMtN$khsA70o|U@fg4pTxnIf-I4jc#WVqU2C$mlQr+PREz`6=az6aC z8CJwi0IlRJy{~Dn1kXk*nATg^JS#v5zI_i3Hvyy#c{Xi1lxn8iVr5zqv_E@D&`TZL zInh=C9s}^8Xf_Y7R9g1#197X^D%YC&Xc#I*tZ+M7PqTa1poA|4w&=4skA@A<3WEoA zmM$oF3)&p~^$Mgv8ipLJ0-<^&u($+^)p(*-aBc~kfH%F8N2JgoWmlG1q=%9O z=n4I)0C2XRF}lX$0<6M}#1dr)u!E)}Ve$W?8%(74Jb07K3SZOy$Xe0~5KUFuP4bPdbQPn6_6ou(d}+LPt_TUz34qX& zb}TLZ(a452vsrF|&q1VT6Vbhv2?9B!f(ZZ4f8PUANLI}o5oDH-()_c8ELjRhXlqtr z#hW`?gGgGJMMzqq2-%5*J{^pJrxa=(Cu@tnwf5YSX39O#K3g^jw8EoBmCzGP&njqU z+S5?t^R(}k3<5_$G&G)uR>0vkj27ITNYH}ZZ3{sb!S6(h*0?J6O-jWS?04oJ^-}DV#zBd5c3*afpEIitOQok7Bb%3ZaG6j0v b!2kFKs(*8sivuK+00000NkvXXu0mjf#}Wg} literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_18.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_18.png new file mode 100644 index 0000000000000000000000000000000000000000..795120e772fed8932017fd12c20a30b2fc3ab5be GIT binary patch literal 828 zcmV-C1H=4@P)m_ptak6Zugwsr>A z03Kq^ZIuyzfiytx-Bp}2!Y^=LfVcRRF-99>sDsJffil3C;!{pG0gM5n#GjmM0vH1z zaH0ty3=kdtClhV}H1SW%0^tTg8UQW&Poy${fF%p`-qUA_u$jQ@(Vu<)CzSyn zu#5Pul>t<^GO&~Qtpyoiw;wSxl>u(BqjAdshf@YHvSakO7GQu~f5@y<1~4!?f$Wn$ z9Ay9_yIwt11~9O5$tnXJ&Zh>*Iskl|_K{B-L0%S)2EB~@j)B+9&JhEk3}E1H^h*CX zn1e_p6O;iAP{FSLOtK10&4VQTWq>~*tN5*z0aWg`eA&cr?V}Qq^~bTY)_;oDEm+p`rp5p-u#EEGEc=2g z0S};~e0r*Q?E)ku@gq8fGQdrySW@J#ts(bWX<38`sstF(W&ox7p8@v_u)_e5i+Z|z zKIgE^97YbGQb0@VoAbskso!Yu(#ISzcG6WpjacHn1DYlI&$5tLbcO)Rc{UmfQf=}%1LLA8MwSW~oR;s-Gx$^Z(IU~AN0 z)p+_jZdv4|V$}sGXo6Vo9l*WMjr=2VGXP?`dy9014|fI7m9QvR3qh0s?!eK^L({aD z{;k{Mwi`jX0i=V^m_fMNzWHboI>HRF_X$L(k8k15A4u!b_VCN&h8_e)Wq^q66J>%h z17u6_)-=wsjvubpTc3O4Vt{PoQlyhN^YQI*SxrE{)6)np=K`*ND0G8(?H^*d6W#?N z;x!tN7Mlb9CQ(tHzz$uA1?VoI@aNABphY-(?O!<|3;YKcOHj7tfv;Tv0000FYewfNbI zDWw#ETYlcI0C*P&z&Q|rb07fcKmg8x0GtB>I0pi74g}yF2*5cIfO8-K=Rg3?fdHHX z0XXOP?Fx7!#@Ky+_wft}U@>)va~+(^?-Bw8u!yG}nah{LSt$kxKpCwFF0Wtd3J`!I zF~%jGRJwxp{V@wrVpZptq?Fh}?n3qSw_DWz^BTZsM;AOMyXQ?HYN00h(`I3@Zu#0dd72LcdcH5EVr&Vc|1 zIn4!Toe2UEviqRMF0dUepd9s|<^Z$60S2+=0B!}4mwF`;UFO*n9bjf0;4%f&3ptYf zo*UWPbkMy6gut)+=kn!GE4XujUi6nyF1f}6ZXF;~N55p<-%=WIFMv$$)LZlX(>l9I z0n&!4k6-t8{j5v}O$(qkx^Ic0{uIuQ4)7GSDS(PzD#y3R0v?25Rsb1kC${o``Pixu z%nP73sB5_ZSN;Y!cv45R0^kO5Ww{z^^T(nam=!>Y#098p^6%w!R%QSpgb?$846&r@ zn%-ybCG&o%o1DOCKYmRE>rt>3sOcb=+spDdiD0CTUk=clFW>OSd$isUC3dQ#TPftk zb{VM`xe(N96zaLtY31{}^CdfhnHy#VQa%FU?4NRn)5Xv`&c%K62DL#%{q08njR8X7 z?SI$z*Jwfsp_lqB?*e9;DWJ}8T%&Mh-h$fH=`95H)&<_o`6FYpk-CaDgCr4h+5mF2 zvrZ9h3&|msrws1~mJv_ce{TTUdS08_y{N{UZNwd}z-?;HzV_61u+;u{3WDqW+gM$H zmGc0j_P=V1Nlo$UGNaMc+97P+b2l0;pnf3aNwjOtDtgy&=lq`B`(%faieveSpix0c vr=qj(J9^jXwlmOQYjA7-TT@P>=R##Ln0S>~Ba{48}A=q`7@^@B%6tCz) zdLD2uiq6Co0VKt~@0+f0Bq{nb!FC$RFab2>X9Ja~wL6^{yS?L34se?Ct7S+s`&ZQ% zt1z7dXvk)^CCgJl)?E5HR92TgGRAJ}f1UvX?67`oyw;k!iCOcK6wgtW>{f@iR1dJK z^2aSu`h5mG#q+ghlfaUNkP<-}0s2H%mw&5VsJ8hM;i^tOp2x{R8Ubi5{5rfa$DdKl zN4x-)#g)A}FGvjmKT-MFA%@E5KS#%)eMUn<*(o3kE3HBDV(9pY7toYX`=cHpi%1~? z@N@6ZBTR*5_V3l}vOFakLbT`6Py!J^Q@G@U_(XVH3+TpkSs6;pP&#@FkoJrAv*c(Y zO7ke*Tp$7I`Pe^(lm4`e-TVky>p6nsZCuomG`Eq;JOx0(hCY_FPhw zcY5&JNbS^cludwajFMmn0r+^5QZx%is*YOBr_VJKX#0449pDQs%PWGc!f54Bd*+1?578RT))0Wk zZeC-^sx?$1T8NSq7doQVl>FUyAjSzFhfe?jSw4+NO8_$D;_a zJ9dwPpYyfNM{^-d`4+UQqlIG%K~AtYi3$I zJxNr7BYk^+P3e(@@Q6CV0US&N8V)RsC|@E$Z);%-0npp5uY#7ZNBVi_ZM;jd<8lB? z@uSuvjWLoyRlthHo@2fg*d6Sw~C@i1m-=BQt$HxE=t#z>xZ!W|>v+ zO0Oq+sScL_(U?BF*hv2qHa4RC)$>KX#&8H|?fLa6q+SQlusqs#S8|CSdn-^ecFF$<+#Q!Iv2$$|V;}Lskt?kK yLdN#b4ZO4o3>$ zaHIeZL#?JNQUHg6mx(EW!;u0w94UYg1dsDAqyRn;mhIpaz>8p6xl!CHfEQur_i`F{ z3Sc2-u5d3>01FYd!Xt&00@x6dq2fD?=|GIEMD*~6_b>_iTnfMdZt&Iw_f9aOM)j_C zR9qVyAC zhWDKUco8&1TS`hUEX@Pd>lAan`y$OZNw?BH*rB zTDh(3-q_Ig2my?4$5Kc?{H$D~iJRu8rE3iq;~(PzqR{dXh;dq+t?XTDQNAAUaRPXH zOO^sj)U>w6sokF*p!|3HJjoj6^Nz_HyERxn$(90$T*Xla9Qnd1%J_9Gs3$39(=yOH z(JjHyGR{(BXtB@T!sV}eb>9eE8=i@_oK1KkVku9%l zJkmYf6L^hZxgv~T3g-4HwiZBda(KP&nNWl~0ujdd@NAg_R9Ge_+F;SpvUe{JDx$3g z-~~T0zf8-yJ9bTd)>TGbkDvg%qN7P8O=J57SFH%xNC2{9|0|%qpP}Q zd~ITBb+8I8qm6twz+Vpy0WA^C=%cskf%MyRu}^Fv_l$Va>_}-YTxd6&z-U*b9%Cl?KKpwQXJu7}RzD5Ey8k+DTJVPM>HE`slT4JM= zFIYKN0ySD|j27d&asaMCWFjqb3+*3?jap2Ph_4h;6#{CsR$mt54|xDd1oi*uxX=6b z#70e&Qtsl(vLimHls|br0Ke8+Qx3oI6s>S#{qe_BC`=5c9+xJ!h8qe@P0C#`&I?63duw?M)gn8WlOtd@!S_L3H zumHR+Ju(5LeOru=PMl?Bt-?qZ(0cy2y$M^Sp*{^GxdsY}pXOb?WVLH-q5YQxu2lCf zn3>D;K=UfZn^{G$<%yst@btn!JFbH(2{{JuM9!{J%3V5)=cDg&#s!i(H*x+G8 zy1nlEzMF&Vx>~1+*_Mv4>w>PA*UEFFcA<7=j*-y^YA1cxn!R2Y-l!ox%q|p-!viLx z&*<2v_vv9|EGPhGCxKkQ)A`bdpM=+L0|>jFPe9WZ($5ou31Wa1;LhK@c+v5#pxHeS z1V;pbbp8{-?ev_yiq%Fp&UO*_ROh4frFJKzHw{ZfpoMRDKF6tnuq_2dYXo%7YGjYe z1L1@qcZc72^Pb=;adO>hq*WOCtw_$b%SKJX;%uDB%RsyqW-Rm!F5mEM|b|(s4S%&6VUJBNt zyy7^Emc7N3?M~M%eC@X|z)EC4d_m~>w4IM&%j00#ws$;((b~h#XAdjCjQSA(+JzO7 zjZkXl_!$ekyKEc5)NNpO-J9Nf@RX~3?;U5)<4Hk)V3`JpIz*#xi_X2{iazhf@iEDvyvT#Eo=P??nTmLacb3XM|`Bd!5;A>>9T?A$TShT$2t6ksV zs48eFg9n3EK(qW5z6*$yXrmMr*`=c*@SB3m3I^?*HSeLj0FMP`Z)YNpU!`5zv9#xe zRN$4gN8ts7*9O)AoMt>0hzc}~o{-d{6*a6esQqsAHb+G;3_T3e;2Ad~+B7G6{m8NS z^&S)K-ucM-tO{1X7SR6&%AKz3g?fy4-S>Taw+^TS zJt3IQ4BDi<;~ouK$DZBD-OFqM^z4d4v*jf}@bZrL%CDC@KPv7JSa$>3aa06)DZmQ~ zRJ_eV&XJF8`NXs9BL!GFy{7|sTbT+fp($MX+S|>tFK-MjooMN$g8p061KqMyYcKKA zC`A)hNDx@a)&$m=){a0`z19Yu`z$?2VFfzP1Jyig3h;92%*3-(K`+u#$MerM#>fbQ z?7*;69-jl9_n@W#l0R%nK7EL`G(`kKW?Ph7WOsNRGlqUP6er4eH z#(Qy!*8ccF-fQL#r-`DwmSDY~Wq^@aiE2i$SgVKb)4-_Vvw?sbF2|G3i|%HN0Z!Ba z(&pC2E0IV2NL1AM7LD_B{1q8{Rs*2(tVCoD-^k8D5m{*Td;}Tn!)?iCfC`4t`izY6 z?k#%MU`r78#LTGkBl#`@k5VnCN7kysW{IU5Koew^3YAg2;+Dz72+Q@Hj#^3rLQpkE9HH&_(OXCqCk0Fvx+1Uw zTD8h+TV>%_fC4S0Nh!7#ifuj0000007*qoM6N<$g86IQM*si- literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_22.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_22.png new file mode 100644 index 0000000000000000000000000000000000000000..d23ee492b07b731fde5b3b7f4847ea499e4e23c1 GIT binary patch literal 1685 zcmV;G25R|&qnJ%ymHr^`B z9Ai8qf#>->ea@L#2E$GM7H{bpTGkzVf59mIV4P6?F8nuuCcd-s#~9Bdz_`9^fWlPbTZuX`k-CDV;gzpAY?A z^Z?wNwUIK6%twzBe+?+UoZkA`17Dk&>&ZjULXuOXDW22wJWu6NBq7k_7h!`+unZ%5 z$oxPlUF{sab(TC5{fzNja#;M|*&9gV9bQ%GmD@w-X=^06Y2A2@egu{wTYJ#LfyQ4` zJf&yhU2(&lfyF4RbW3^s8Re-RfcCp|$aGFbah6d;l~3XAQQ~bqkMM_i04fw0u%h(n z;YB@(BwyyhEo9wphMwomx_EVBG8KfnFZ%Hk7Je(K3tZ1E_h%U^A2s@#!Q22hN-8e} zKRf;`x|fy*Sj?oKC4r5VcM;$huZmU2UseH{KEMw5t zMfP$Mk#Ho<$%e6Z72pXt#@Bkixg?9_xkh0PE1{;Y&Av zjVKQwLAvGiJ1Pe^7Bmp_t*|R4vRQ1c0;ElJJV0inUd)%|+vOE99@I)qDKxK|1;hhL zo1j8c!A>Y&lE*q6Eqrv*HK@$`>KQ?D0LqxpoHuC-8vSV?|y_AHYhsxHs^Gr*63G0d5%1 z7`>!SN=PI7ubxx;&jfntB#<{f0F_}k_&&3H_Cl_O_ab1y6NECA=2i~!w(`4(%3i&> zsPlPegtVS%nSWJ4zPXd}SdwE0w6lqx8RBxhGHxacY7mI{jZ^@-*0-ST9VtVX)@u>5 z#xZ(Ljj9LWG9Yo<2&9S!i7MUqZswhAxa;1e7+LX1-7uh4MOKrnB44Qtqyknme=k3% zHgR_0c2bG(0#<`<8AD{B5D(xXd*J9!+Koy=Ym8~ha_9C--$l>xPZ`+hz)8$#BB%*- zLMfkCPTs0!G(bFn6#_cXJ!H$JlSZKNLzl}OSvrs$KoTOdp0|&+ma>&gM0s%+7`VCq?~|`o~Nwv@BqmH5Vwi*U2-j0wLzMyy?mnEREwZPJN)MXP*_UcQU08S zX84w&?lyvomxTOV!Sq%m6+!7C+oY15XahoAqU_qrS-j}Ns@tNsn!5Q8xTipd04ito zRz|84Y5X*_J%FU}j*G7*b%+~`pmDpgrJbMleY+2!HEuZb3Qko4Ram^OMo^XqQZ5eY z{}+%+in8=}RRL%qqe2I1@EUe{xOb;%;k9TZO`hA0 zpk3uz)e|6<&BM49*56$PR1>yrZsBF!{CBGi)7~G@gf?4MaDH9GMCCSKE@!?A@LIbI z89{g5xCl*&x7SavqOyLMtGA4x6#~Z4ZzsCW_6`Tdzk2h~)yS#JCL97Z@c5#A$LB|( z&5wi-I`Z$e`TV<6i7XEtoJxhyTCbua>!M-i03C4UN|wFzkWnGv z1m9|2RPh!(KbsF&3(~F5Djoe!;UrEPP6b>(SPoz*{zeja3y2qAJ9+UnZ3FNWf9p-% fcS9$RcX<5*G3~Up?wLwo00000NkvXXu0mjfNd6$@ literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_23.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_23.png new file mode 100644 index 0000000000000000000000000000000000000000..9d368900c94f1a6dd069d22c2a5f79cc5ce0d497 GIT binary patch literal 1680 zcmV;B251O}g^0MJHLB< z3T^4WCj4FWt?PVoT;n$fXw$y$dyC~q*A)f*J%``>(H`JQbouva{v!LPR(@UA$4m17 zuX!_am6*uP?_N*Rw}hZs*Gl@@eM#UN|6_c602C9ug>X{&qR3c!R{7~w61=6n6K}Ky zdiT*DpmV5ErIYAO{789#Hdfn5RtYul6A}IxV_f%r-<3n5ge5m5eeSqhzOHqs-o`WZ zC828P;LWr6@y2O;*XBeO0OkQWV{}sy3)40ewH}GKHrBE@iT?;660N8ZxMD?UMU}udAv*Q6eN?=+2uEZ}wLkeA)wX)k+WnBB|1lIlGlKIG{OzS8iFGqt=HKem8-v z2*a9N6>enz)v5sYGl3G(itwyzVJCKY9Ewh*(m9{^T);vmagms*RuNs{pDOnxFBnC1 zEXp|Ekp(J5v>H5$&LN_J^gdqrlkz4H2;N>9H=}_jd0J+l#cAPp(Mg&!@RDl}uepeI z9m9U$Gw*wOLIzI}{>oec8KSB@zE=~kZt_(8MnVfA-JDCKL)VR--6LCUhMw)3&?`pTo0lZ5|!V->*Q{cp-g&RmfHW zokS_SS9(5@!XiA3#h0g0$2x(P5)etZI=7P4cl5}b$3e%e(4cY_vq_8svOE2;nlyb40%do_<0BZ2e*GT@~U3SC~SRe;s# z>0(E}0@4S_)YO%A=X(j2O;_C|r)%w%^Zk^vkK;84=H~(E3!w1-ZU<~;w*G}u~^zxDD8UT_XsZqt(e`osW9A1ky(&Rba2tur- zb>p4@w-eYEKs8~DDi?ikJqzHUt=vJficE*nc06>mdn z-S_?VKZ8=#9Y|K475Y!>`%~;xoC^Nw1fmy~1b-rlJB6K(e-Y=}Rsc`%Pi>Ao4HaP` ayv-jxa^1*R%sztv00001vA}yFDaTPfG_w8 zsoK{V;~EKE*Vpvd>y=rS#^fXMdcD5!x904W?Ue2(`G07Xn(z!B!5Y7=>vlu^Cfw=( z+USwNuIu_SZW((1{Lc|EyyqsNPmS#QX&7mo`I0pCD}pso($wQ!ojbaBo*DkpOX4*S z_5j*I-dIFG;*ZepWCN@JIGJ4#p57kF3@Yaw$pBWwdt>ui;ja~z(8_o9?$X<_?|P5r z{>t~?^!Qr)|Ago%86xu|Zr6s{8i2!HRX)1#CLbykbF*3F`eKC}Hq zWcWG0a;#6s2%ho14Pm6gh(8ixk`9tqGw`yLH`j7151#H_&@zA)YPaz<|Be$#IT@Jr z!`j>AYh@r!AEEv3)+ogIQsBO`7e*9p4i<4z}NX8;K+%Dg#uX8?;<7uo2y z)}IEw2Us})GXqHe^652xQcjN+!x1Ww@?{*s(kJ7Hty2KPP_JcX052%JKoz=Fjqn#*zm79F%9 z&6YP0lpbK#Eh&($$$CDsfm>}*gsgL)MAVb4GA#R=>a^iTQzUivupfnEoSxuQ;tdZ$!KQ)1hP+v=E%8!N(MljYKP;Y zpxpyRV>;3!8nd7H?Z&UjY|YO&hTLn^sXkFU)=y8NYzaV=xWfrLWx!gC(9yc-hB;a% z=U3(atQcvbDyT*SyDmQsk#4Bo-CpB^Fj~z)OF#zN_^1PQo#wYXT{#1wi?aDLGv%|?MG~aV!^c;ipyKBx!6lO-#oHGew7p1GN5x#MBz#v zy#|#F$ucWYdVp2xL)KfVT5nLawhBvDFB4@^y#TZ1+LcKt_W%r7&6>;#NEz8B%WCsI zhnezwFOLo*6Qc4{dVnW>F#ZkDLOkV3YtWm7?>rPL0-nZ%qcC zY+3%49)JbSGkXd^qcnSLMXq+O9%jXV=l-Il@#xsc-IDO;hZD=KHGUdtAe#||91sPdU3Fy+T8U!g{nPBRoQV!p9Vf0)< zra_jXx|}de05fB)dLZwZwhNIHSYuo60e0NZtx&yoWypx$99DT{b<1Reb`KyMA^BM+ ztxEnoNfvJ1j?(??0J) zbd4x7SL=~J;p9aS3sy<2g4s~JH-TLP>}tNO+pVYs==WY`%AS`i`Z3b~DW?v5fJkub z3KYSvFF-Qo>I9yene;xjO28O?bXISs^m@r>B?pr~!gGbH6YO#v^Bw>#0TEG6-1UJbyC>a5Z4zE$ktwBuy4<=a3>*fRVbP262LdFRjA*R}(! k4F9CdkSF8hZK34#AGJsPjXYbvdH?_b07*qoM6N<$f=y#C>i_@% literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_25.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_25.png new file mode 100644 index 0000000000000000000000000000000000000000..b40333654f83c6ccda04cbb4020621e79e7dfbdb GIT binary patch literal 1658 zcmV-=28H>FP)+!UnaoYS@m7gp+d$;h0t>nNG@)Lx(?w`-+ z8$TXTavz={JsIN$pjqu*!qSw@4Z-78<8yfw%NU+$2-3)3>x<~!T2Q-7L1-tXLq9W@ zUzR|YGOe-J{^effe!Z)@_so9f^Tp$JU3Ae<4xlMNG7m*xj<@Dm>uKR>=gs8!4qx6J zZ@d?7r7nnw-s?g1t`U^uBm**e>f9srcYJVILW;sl2zTCNmwQ+|N?xP;wRn2}X61W| z*Vf3u;widT#*=EawD4)|*W;<>0e0h%%Foc>ZCb7&1s+A^;sN+)ITq;&Ec#0b)foH)RJ_3Q03Aba=Kw^p-Z*FWDIVZInjV12 zeo4abT!9lFKz=@npKgGy9H4>;5Ad6CdOvLsz>^Vv8hKpS#-lwz7Ed;u3~yfI9YHGx zSdhfD#85Ja@BrD(?)ZKZ_@^7+~Z~e@c_GLd{bx- zu<)BI0`5UAXbE>^|LwPdoB@kT>CUE%;3q>$%04o`j*LtQIfpzbCAU<|ls9JbK;)G#9a)2Eo znd*cQ+)*WD=|z;B*?U$;N2`Ec7+GVw#)k?W)6gm;qIyNc=S1hfJ$Eech$zNvJJUJ=(tzu&cijRX}#m;tdIuAy|Ue zzOPg-(Xnz~x(Y~*HZTzao}R%=c>H#Z!h_diS!MT5hHpN}xhy?G#W%~!yknP)UnBwbos+BwB0r3D{2#7xK z^a`@Dvhp3D8f_~E@6h!C7Qb5J?(qc40W>Be^JSApcE;p$OA#GjIWJbdo>BBu!dJKz zj3P!aw_H|qhaRfM-Lm*4InLvnyjwP3~hE}o!#q8c9+IiO@WS_N=u%9r13 zCtr@&XnR7}Txm7FMo`HCs+Ek_2RNDoOkpYnWWrPhk@?f|jqU;739OWWNV(JT5KdG9)#R&dz^IcSRkVdymjSJbV_`A7u85b|8Dl4V z&hT#0wSa1>MG!dz)|eO3*Mv;FBe4XI7RaeK@`5GMQ+*SQpX}Og4?sj;PBqeK_dh5I5qeL#@bkw}W9xJ^4f zkK?$G0Iut2`FWm^Z6EuQhL^6i?z%3QOcH-?9mm5X;}j4{}X|7zt#iqyF}1>KhN{S_*^82@b|3c z42PeivFVF`PO+X#dn0F>(7h%PmHj*hYXDr^aqFXDIZ|_2&$#pKtP?!6wexaz7>@vw z@ps$;R0Q4#ZrzfNOCJ({Oe07`dUc;$lYxFuasKT6zd(DZ46XI3c&cPCzY2d%9!`;- z9Ir(PgtwdF=u7l8y;{#D+V6}Jknj%UNBCoekrYGa#I;^<%C(G1`DzhMgB0OB@=?6A z%3locGQPy$b5kT55lAw5X?da&(v_ZRQOJ^|H3CTJFn%Tic?@BNehrzM&(X;2%k1Is z>bikcu=N=gbXNq(D5pb_T?X-Domom3UU^;-BUnthb(o7Q?-Kut@t=T9?XmV{_b!xc zfCViFqp%YZAcKnHkj}R`-9jk>ENGvjmrg|hOAZN7Fm{YC6LS4#w-2A4jk zUw1_Si?4=na2!iUs-Nt6N?kxiNKWXE2vEUOYX>ZBIbg)aXI_*hfmC2kNV=~Q0iJei zC-T3PI;C~^EUKe&4dB6!2=GJ)xdXRE08R0DOa4*>=!BFi*Vj{Mi2$n@!`J!@_hRnC zwOQkH9mh^g@tdqwM&dDfJuI=Ri4Njol{%QW@F2G{SRjV3}6+N=ypYEY8(!?!7 z=dALp%86;iL+h=DV|?%E0=$Rlbb_6T^2^pY^uka&QM@TJ2~{O#510-AU8!ptT7ev) zvG!*0_As>8M7jVkP#KxrN*!;?5$-UWL^Bluyqls!2`W^zFv=EkT2AbY5MElE;j{8o zi^mrgOnR4u&IlRZQ?24@QHC8ym2O6cE;&%A*)z8MZs0@;=+58WgB6r5QY3S0JEPH} z=b`zgo1}LyQ$!^NOy%rsXJXM?;N-S=bvipn8VlQhJJ^HW!y64=Su`VNoFdCFs_Wl2 zurh(;4nuqJ==@+3kwVaWbGwS&JJ1pVECqT#ugnUfh*a!eTG7^SD#~$_Nlm7f8h{hR zvmaYDsio0wSVvEdN&TbZ3yMRhB+c5`Uw6rx^4=%|TL3ALLO+OZY zuN*BkK=&|(n?rbSpatn{9REz)Sd9RZBTuD_)-E8LTeYe=lL8`2vYY_VB=zlFy6`|s zJJrjC4sKoKmKq?^El7F3ip*a|O9%rP7kH}MjWq9r~O@(|< z2PCa=|2#k!mT|gf2gkA3@RT>FA5T#^=>$>QBR>x?(b{P__pU-!yLsGYiq0ys@`O`B zbq+vpH4XC>V5E@RxjVa*ZCEj)WC3z&2YXIu$ zRH>a6d3O|$=wT?o>-Kg6&w<~+qjPi$YeefA@=Uc&(u9oT>7Ax|&{YIed8^RQq5fis zw+)NJqtwbY&l-hBCTE#Qz}>nic10g`4&be5Bf>^*R8(=C)8I48f2R}N4JitgQowQO zKNwNT-5v#6!=We42(l4!0-QYV6rd4B;@mS_9}zn8d_j|4s#zlRJ(z4^tF+htbP8BR zEL7XT>_MxF&qkkVzPL7Xp=jr}^$$m8(J`3m+#iXWcTP1mUcXLo9I-zeS7l7$ZObyA z-tlh{yAXAfu5@*tr~m&4$Phn{Pob;rkrz8dag}ejF3OCXKZadbvlX;f44+#x5O-Jg z9_)0S3_iMmZo*m*9>F&lo5RkTe}`Vn4qzGnNyCsQW9PJx^7;pT0Jg)RaSLGp0000< KMNUMnLSTZld>|zN literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_27.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_27.png new file mode 100644 index 0000000000000000000000000000000000000000..0291dfb5830a140e9604c82b66e0fead0a9d8577 GIT binary patch literal 1741 zcmV;;1~U1HP)$@V{Y{3g8ONZp?cAc^=h3_`0oJ ze!%-ZVw~TKw-`Xwl05_A9%?;H*GT-SvNc2ajd<-X!rt{;a=@6p$Wr2wut zjRt*QTC+b(a%sq(UH2WqpTDkks0QGNOKD~3W%z3b5S78I0lMj{g6`fo==viO!1FA6 zph*5w2$y(kQH0;8*w?LSf_%^Ho6Anmfz~_E^Q?Pch`dWec3~6A>V@c}k}Xlt*Sz-7m!}qXbI`O%SU1{kduc90=uq0xGo! z3a^d_Qbg0iR0OC1b?Dz{bQ|pmu$Da|kR1ik+&9IDja_^7`5KRG=cWxTA zpvfwqM}gB30l}|JBWoz_-vsV^(re$#2t^G6(FL528Wn!1u4k{yocU`nv|e3wHj_OJ zy7}oGDz&(i{3y6?sz!517JAQQx_~I8a9&w^x+u)@LwJ3K@5UWni0lHQ{Hh*>NF662 z$=414S^P@@*85t${Hpiqfg{L?fTa5q3xyKh&NNKoQ<+U@_oQf*;Z;#S%3vT7z)Atp z`;y|PLL@ctPKztil+ZQ646=p+sR1M*BI|j9Hm!Jxe|5yopF^~}NJOJJvQEbsZX?*P0`A}WW(N4xLQ zl#0Ks(^Q>6Tl`%1$^FM`aJMz0i7(Fs83)AsD4;$&wkM@bn|`$QE&0y3ypG?y9nTXmH<94 z=%Ea!Uj@3Zp{aWB+5E$hhytpIpBc1d=I&k{6E#+CsN_K!{8S9=RPA8S0iqRcMp$I8 zt;v(+Kb1Zvr+-;!#@tE)Yw6zE9jtJg-a$?ecCzRwe|lt05l#UXQBK?%tYj5pjW#V< zxj1sIIvnDdGQh5J@Ac&ru!(r+wt>}+b`L%qaZd5&&sH3YI>%f8$!~Z@&h4@pc|Fhb_kRsbad#kjbyn#o=l*D%G@J_l>jKb(t*=Hi_y%Q5I63o2oGaufVVp3% j_9=sqPshn=A?5W4au)}*O&X|=00000NkvXXu0mjf^msif literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_28.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_28.png new file mode 100644 index 0000000000000000000000000000000000000000..54a889d8151209f012e5b42e1da564793606c3a7 GIT binary patch literal 1686 zcmV;H25I?;P)wUdPS!FH+Q14MrQ7gCtMTXN!pCPM8V$s7-M{BD=lCN>$uj7JR8QwhAmKV@?)%GEc;faQT`gqR=-n+G+cDGI( z3M@-MGFM*6pX5y&y8@1t`@^-gE4%l|e&zGY-}g0|asVxUGEPMFbY)z#CUDFFc4IsF zT8-D%m9jtL0gzFRf$ZHwU*p3%mAFn6Rw&t>dM#|M#(VaS`<>6^&xnsaox8in1dc;N z$jy4`ROoAbNI|WH8G*)=RvoP9c|4<3qD4!SvzMn&MG3p{$W%r75&GWEugX3TBDAde zQ64SY_{_^wn+HI~*vjA0kDkT~GRpTt3mKBG9FyVc9Z`Zs#AC$_BkVW6fN&^d}j{e z!5xD3BD0rD1yt$-NT8dS%xFm(!voCqGI+ArKsk1z)Cru-V#beP!JBjKK&b*|rjOTrCpW^(0e%at{q1Bff6jV?auwjg zDGxAdVa{

Fc87HT~&L9^=BZz|H0U{wlGOFDf9!RT5 z*w8}TPei#2@L)ATJ*U>6q7e?k7mhn9~fz>#a&#d98XRRcLaJu1)!FU`GgeYW6;1W#GGUay*LB& z^R)(zTm#=*C$YlooNLwVnNDVfk0>l}eKZG%x>N+K<2TpZjj?#p#zd2pUQ_QZC%PN%VCWYIz2yFMic=t5Tr z$Y$HC-@Wg$^rP_V?%hGyqX;bf7>t?Dh?PE`St zmZz@Xbvw1OEM#PgD0={{iDO|hJTFi7yE8^cBM8^acqg1wZKg%&RzkJ=?*Uktf?^AX z!7C%@S(Ua?ULrKJ`)~PsfR56xI|MKjUaOhaiL57h&&jL1hq$~Lr51V$W(dIKuA|z~ z!a)>K8Cr*7bx6uNfTr+@i_f0usLPbb+Nq$^Wpq@2lpFw0K3-YiDYa-<)<1PRv&hhi z7&f&Jpq>1Rg6^mSBG{F%72{$gqaNca=K%7A;s+cjl@dKEcXv5Y0DCl=j6RV*I%3zN z^)z{&*a-5#%XbuP!`y{~uvsllWx}y!v^ANA?UX`vBez zMi}gJy?40tuJVzs@YR~75HQC2k0vVu!Zmk7@zQ6U{tk5KB(h4Ablf3ewXh^$J;U)4 z#v{)sR^=nJe#bpm6?wwoB#-G3Fc;dPS_WnXT0Kpfs-i+G>iRQs!4~y(U1z=-R7JKK zQb9JsW3<7&U>Lz`jM#r0SAiCft>>6zc7B?s;fXyA8D_NS8Jg~YA0SHrna0lyx^OxK zROn{&qG-!r&izgbFR~W2Qyo=$N8kSxP8v=I$R8~SSSkLFB0E2AXF2dZzlUGf<(c+lJ|)8<+oPWwOW8n;#pAN~o<)cLyG)V-&hhYb{9P8?X?WqF z)3N^Nd47!hKVxJASfZ;7*x68*C93h9Hvw;65B5EMwh-%;GeWykQAceEkA9EsT-0CJ z^~Dq%D^R+nm)E}Ny>I(HFKGX@8fyT``PR7=`tclTo|KCA2J+M>78|*s(rlDcs0DC- zI|E?nTjzB!5UvR*JMrfnxX7oXj2jQ_qUKR-g!OM|5zpCv??tg(DM8$LxTx4rtG&`e~()k|!n)9vEp4lLjy%u?ztr(i~p-gIQ zIRj{hPBDPCI3DL#)GXQglnoZ=V_A64$KwRf0Q@~w^ktoI(QkGB6g29713py|xWT=j zVgLv^8^CZP0t8Q>qjk!FB> z<#I1{{C?lX0F?d=s%2FoV;A&Cx(4u~lL6k2H`L@KOebnaC0jeV9SGYHN2rtkZi^G*==tL18AtK0V0bN&Es7~r6!YN&`zWoKr<3A zWHkd|bkqeEa=e>qs;()k0Vq)ODj8q`S)Cd7nz-lGDZq+J2H5(#C_IW?C+(Mq(K=DW z0G<>u%>da2%xwNn=BnD@B{hI21;FvtwZi#$ZUk_CB?Cem-+<9mfMpX^>OYwZs-j<# zQ*m#jrvS;=EdxeecJoy*K?Ih2<{UbWTcTrptvCf}z_eS*K+$>D%>y^FS09{9ecpxJ zqU1y&RTaHed0f-6*7rJTHd}0&V6NMuL>uEd1z3TdpK%_=DqcG{xqFOcW5qpi$ZnF` zOK%h^QvjZ;>5j|%$IN8CI;i^S!5r3_Ofk(g{q>{sXPsW%)kS zD~NzQW^(VXGAl6Iy)3B#FszG*3nnh|q^OPN+&!nl@saV?V_thBs6q&Cfkq3UY{zfQ z(#Bxj*7?(z*aRgt0C&#y09V2Ls@YOWyP0&-1&R3}Q%7s6Ps%#MC~1sV1i~BB($UGt ztzs<=?F^8u0lZafM+fZm(Qz78o1*m;0KuKDDJrAdtWpZ_Jg2BSg1(_sS%JTggW=-i z>nV6o0iBfE#a5@+xU>dX%N}7Bg(KG61?lvVk&%HE3?8IwfE{@_zjNcT!P>EH>J%X9 z&+5?bVfsN3M7jpZJoWN6imFn81zptK#Z=MzFX;n#AhARSZ*@Mk;VFha!2-|o)YJf7 z4|z_cfR4zwGF?=5h6P)G9-yK*Lp>L$N&#F^SM7X_S*0Ve2bsBP27pB%{4CQ}jj)Jk z4opL^DOKTo>BOJ~R)*4#)&Ou3saF(JDZp|X$;k9>&det8qO=b{MSeC7y!lxG2Tbko zb9n7w0w~{tbRPiT6pYx8O5b8fWS$oNo@XLl5O~)jx(U3j^WkXQBEV9dNpn48s#8E` z=a7Si(eU{0O(6ba2<};HW2~@570#j7jb^E1puCRrzJ@oYE3p$O85(V3bamLQ>B^(q zJHD&A)yY=3B;2#8SWY&=uuMz3@aXS|{;tg(0e(iq!JGmlMNlF486IziR4Gf~qQ|A-_=j(KsW`g<=Y?;WV>S-X!I-H`uo2i&}g8%>k07*qoM6N<$f>LG@zW@LL literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_3.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_3.png new file mode 100644 index 0000000000000000000000000000000000000000..bedf366c6ccf988ca20807c9062e7e7f7b70d9b9 GIT binary patch literal 1305 zcmV+!1?KvRP)td%uS!`N3?sl70Tq=Y_f8vQs0;XV zED)XBPReiX#sDdJNwAypTe}2E!%Bi3mEYPWz|Z5!90#}7NcLlqyRyF$(j0f5e<};0 zCiXnf))PJj@VgcxQ^qg>IOU%TJa%s#gKO{I4ERen`2OlI;e-hACFOGq+UGdanpyhd zh!MrGLQwU>SqPTdX_8FqT&Rq|IwonSQ)8_nr<(vPcE43V*Un>>xuDj1kF+*XGW7m2 z5h_SfY5_)6{wn0bMdEf^hqv5|WpkfN@}%+Map534OM)^2-~o+*G)b*bD!9^Q!o?jG z4_K5>jj4(RWdwjhQ>Dxf&9qw0b0&(G7Mh#)i249W;)uM`O5n^)per5j2#Xbv$inqQ znRfg+C)4VBBFd}C2tIKf?8()m@+)>*2NgG1+?y5~M8@T^0I-u&^ZqFCqGD1=*@Nci zB^QBX5NUkFVgRXF(ywdzZ*?BO0@&PBB;b@yt)UiANG?MfqX#AeSo~X5281<_UjaBa zOagcf=j&Rfk?Myl2ub%vQ4#}S3*gPAx%+kjr4+7MBl&4g9(6sFt$0xSXc&CO*Q4@w z0ab~M#6q585J#rU&2b+MQvj7gnRH8V2Gi7NC2$mmJQ}u(tPy0S0zV50;42>ED&@EK zLthE2CMHD!jtD#M{Ekl)f>wYdffZW12>X#_Xl*oXO@Q6w2`UA&KvMqfj3MO$Mk(lo zN+S;Jv|UVtw!h?qVOR2=~qUvR(D`zla#?~1=3FjjX;$@uZ{~Oa}A+I^}UTn`J627{ZTOhg(`EX z`O_@4V2@LRXV+`W*W8i?TM=NCPpmX@aM3L!kTQm<{-N9P&UKqo@TyX%7ciLX?>S_M zEY%7;j(!ogX#iY9~!cz8q4sMj3sPQ2dGy5OmJhgzk@Z?a zfZ6HVXhc&v>`pjHY3}kukOyB=JVewIaLT0oz2*WUWEf6>(@eStmeMb7-&$@bOJ^Vv z3?V>N=_^a3Goc;)Sn~U-R50{-xCZY|_g2R&@+=j*S&+^LIw<8@&rmWXa1)?=1ibFXJXvWloWgxRI<@+<&e+sR~C zVdb1g^j)3>RPD0r-G4!&{Fg&#D&LE$O5>Ms9}oX=Z1u~b-raxAe;)q;>SwfYfJwge P00000NkvXXu0mjfKQdP` literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_30.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_30.png new file mode 100644 index 0000000000000000000000000000000000000000..0731760dffbaa07d4e1f50c1fd65bd0eb1f6ef19 GIT binary patch literal 1677 zcmV;826Fj{P)Pk0p{ai`))_7(%Z%c13qA~ z?!K<;z5d{Rf4{x&Tl`!542k!Bulv6L%Aug2Yxj7;$MZEuWOG|s-&N3I`;Rtxx1%Lk z&hL^%|Guu=df)f`dfoT^Wyclk$>O;#+4(CS|F1!^rxjqc0O|C_N89<@m1A~)^m+nN z2Dcc2zJ^TcHO6Rj)9*9aM^c;`V7%9i!oROvPYVK+J|2d(Y7a|4UT@Ge>aqEUE5;T2 z9~oc(O}&&6Bo?s7NT1JY4Uf$~Qbo(7NUI67`?A+4R@5mSGEg-Z4JZj7n?JnrjyMVF z{M`&-9X)pz#Iw}PS%t!5^N%!fg#n@pR2ZNFZ_v#sx)V~KAK<&6zo++EHvdWi(H-j9 z!9RroqUdIZNPtQ~Ky`C5KxT(>=TW2Z0_7wI(CVHD=njnPjt+Rqemoe=8h{SS)Bx6^ zD2<^RATtKxd`Sns<7VDqyvj;F9{pHGAV zvhXrMrWhOJ#%n~lWB^pbH`C=5$7_HyKqLip1X(lz#|7? z7*Bm5t%2)mjX`52dyMsbs?PTy!T<g*NrmcQKtaJ zt{*Zad0rj8vbt-EEUZ%q{|>?c(vBKJrLpuoex*uBjLXx9lydf&f);WthOC<_u;w zwsd^>Ko31j0xZQURBo|H#9%XqLBYddU9vNHu4_(3JMx@F-&vaN*!dJc!ReZgkH;XM zDmpt>1H$=SzfLFcTpL+;CnHfv^}rKR(wbNsQz?)T&L8Ne{#}T!iKo`D-vwybF))iP z18^O7!K*{%7`p@StNb!3ijEY3+^s8j|4Lbi^!oMVQ0?lO&{8n76aEFN_5{POwDgq% zRtSrplV^>ii0o)VhLXwOBZ2Bdx@&-$GW<0JXy2cjAGyO2rw?tO6Knvf0jw0@{l3yG z=tf32t8;l$p$Mq~IK1a>$`CwF@MEB6EKAnzqu;E3UDXY-Hs~oJYjA|4I+{IQyAxGs zjJYanhSUJjB2Sw`l0VZ0y}P*_#JUjkSo2o`3VI6gwv}f^AT`>|fY#1Gt@C$c5PZf2 z)^&!+X<;}OT>v5H@}A$L^NsiPa}=`ngfM_-A<|PhdL8rdqtogXz;)?3vaZnC3rG#n zg=z{w$+u1zk-4(=jLM0~f_DPF5r`-pxm-GTCjV=Cqc_6JX9Y8q`v6*g)9%yG`Vu@H zIdm<-^{G71kkHMlQWuu~%~56msfnY3=T%Rms5=Ez9Fj=`QAFmKd@)N2%WD8DuU3%N z)iTa$$4CvH4W+HK<=+FKjJ6{MbR(j#=e|ggN@=*|-vb~jbE#ICJqxG=LbN`idhTF~ ztc|(8Wd@Lnz^db`6?|lT=P|Mq-Xf2KZzkxo09xQ7nkcIpL5PP?(RI%5_kQm^_wzbo zjDz+8q~fm120I!--IU(dw30R)b-X0ETmxwNc~?&C9y6OSTQ~7}yz=OLJT1)RT-To; zhGdi+f~?}qv&bEdAWnrDtSbB@r_#@@F?5`Ezxl%uj{~wh&l_Cyy>$wRfX|h2rdF(0 z0|U)UvtrRa1w^CFgRY&EnNu25rSV1Pwuv5187CM(s~0L zESuji*b7p0MxEZ-_wUBaz{!B?2de=r$L}cOcA?T)Tp=se2=ZX&_|uD^Q;=~cf^B{Q X1UzU}jMrLx00000NkvXXu0mjfn1~uQ literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_31.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_31.png new file mode 100644 index 0000000000000000000000000000000000000000..898efdc4b8fe693c99eb9613e82bb5762b1d1645 GIT binary patch literal 1639 zcmV-t2AKJYP)OFJ=4bXJY&xJ?|e>!-lyPvB>sHvdZy8o=pu-&y$T)tzh#s*&p5yYF#~-|i5fwP5th5uK;OYkVpP zYOG~w{+VFsE0k%WHMxQeU9e>V=H`=#DuT_pjmc_=bFwHwmnW+=3Q1Z}6s|PJl)NiH2l+em#-{@b4L9=pb`XIDy4uJGysIFFVH za0`g>rKCx72L3E62MS3(ME9Bu+RqZ*R0PnNMiFr+kMS+ul*Sv9SdZ>KM**e#$r^t# zmpDWVcj~?N4Q?*wC5k*!i{>?cIipmYhZP{K0R7H_U zc}V5!j9?WGCeesgFS{%MKE^mx1)w1pP4rNnRwjKLZ;-1b0xaY4&w6HoCOZ<{><;cs zqN<=df=70)bHoN;D{Syk?h&3FPfJLu>s*hF8G3Kn!C8FAz+Warp*fGFK(53fPi*b`BpGl~78!dq2=i|2qP#i5V}{oPY~2EocYCK+?i3IT6`1xanA&Z^_>V zRyTrBctbYoFtjS!RUvPS5TP6(I#FWGQBlHG;tgT_Hh+%K2_{mFzr(I6R3Qse_3+a5 zCm_@ZSOYR0K&`B@&flBoptZJ+Xz{k)KSogwusZ@W&pD6Eo#-*J#QTlLj2z{k=)@gp z3)k9ZQngVbM}@OgI^7!`W{jd7fcO5rXa23^3^i~?*Y5-(Ilw16k-}?mjRtq3s8e_p zZaG1fQ+6F;S(H`*Xj|FJ@~f0yrEp0ePY1Q4nTFt6AHY*BNIN}4vjT7E4@3~@T=HkF zRRCwq$94AKy}RvX+1Kf8-s7_*2k^qm89WMlRK;j`BLy_@PiyKJ{=`{*;o!`t` zx!s~HuYYSuj6izHC0)nxC59)G!tEc1AUmw9R*o(n>1A}~0vbIoi&QB{^Rsdy^S7Nq ztF^n}ae_{-z7b8L=R1E-fXs=&a)Q(mFou2%RC%ulXsE4_FAMsD2z_VJ0r&{ez!M$q z9v_b)`n~{7rZT0g*MYR-$%+P@y@Bu%fC`q`VVPZ;-PzG>9SP@BRiO0?s#?XGE|2}c zff=0Y;Gy%QQ4_5a=)KA#N^De(;rnmnvI0xSzDt63Cc%o_6Ip}=&-v`Jrp+8IB z-hm8l{%+$0U(Y3U{({Q;LY;FKIu5$6B^002ovPDHLkV1lXu4UYf- literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_32.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_32.png new file mode 100644 index 0000000000000000000000000000000000000000..39f5db8a0131b28046b4450ce84eda9d9f519ba9 GIT binary patch literal 1618 zcmV-Y2CeytP)d$G==M{J<5M|M zV+}*|tM~rxqHQ%gJMSy__qI3(&}N~8Sv&e(o7u=S6x0bg?-M}yQ&|x?mq&n|@I(QW zo<&oOB=j2XD((`0s~tl3O}%AymjsygLy?)Ot09daNi?;)N9PgU4I7&ckZ4H8=l3l+0RNmph7QtqhZD?rjQ1HQ(B4Z9u{;8B zhP;hOan<1bd+(yMs(?5c)hjn%CIZZ4S`q<45-mH zx*2|DIRF&~Wf*OP&H`&zc@-9k9@X&h=edoP>+rTEIe^z_)&R7yHp_%H{ua%dEL^Ug zkP^a540ETN%MB9897S*}YhI{<*cbXBU8mTr|-`dCoHF)3`ydk_a%2$FK2j2Ab?hbh9&f zWfD~d%@I7ZbDbkLc+bKH59J==x$(4wqh8dj2yEXhUAqvfTBn47u$?(%? zXtHoeogo_mRydER4lwXW1VQ%OXkSgyS;HgI$>QNP$Y{GG3am_G->C4jU4Yg{5`H|B z_WRzV&8%kNsVVSU!Ka0IB#Ec`=)M120%jdEUZ^<%7hW2W1;jwoz-MwIvSo16u{ht7 z-v*+}t%f&bqYguNCDtzFwg?f*0iqox#u~i4hgG;Cte@u3@mfio?&GD4<^g=&UzPMA zOPREF{RBkn0Iz6A&X^|`T5*ShI>PwA170Vn!fms^wW0_>4UHIH>OXUWRfQb1Eys<< zj4b7^Xvbfg2sBwW0{%IdtJ?1t)%ps+CklOFL6QWvD2oAvjhCh}O|7X=ZRkeISBJ<&wWEsRT-4 z{j@T@vu%YFX!KS(n^eZPkj?>UL5CK3w04rP+8_|zxUNdzI;vcrJV`i5ItTFV`>C^3 z%>u5>Y)(;S9DV}Fb#zOGu_OoZV8_yMdimi8NLF#HVj^VdEIAFV7*GYg>mlWzHO!|Z zm1T7R?T}|DZpa6s&Xz@#PC5sW4DLM(km#Y1q7U+Hg)H8_G#5JM1f_oupfUf1P-ww( zD$3V>bfm#RqNn& zfLrj&CV*O7bp5NsO-hw?=~+&zq5y&y&)|7A&vJ;U5s{gI(A5e+7NW(WNPBumlfB3U z)MP+tm~{Ya;8Oh`!KdtxJ>bT*qNyh_+@Y(tWjutr=Gob-HnR_x?v=7>(CBelq@9A) zzeV7*^RE% z{Il0_JZA zxyBgJaNv3VcE7G`JkRsfLR{DNtFQK)0yi&QpOTB4s{-8GU0AXHof%9W(irq%aD6#& z#>K6}Ddl+{))4!2!zv@7*4Jp?vTh3lWXD>JugVCl>%l}1 zek3DU#Q;!tuHD7}E4>pcey+7UBuLJ(iUH==a}B5yZQY}D0E^*K8<%L=vR-zt90kLF zuV4VnzFw09aP&s?(Y(NG3|Q%v;RViL!2lNdX1^^A5HTDsv7zSX8BDDX*FtFiT|*p9+&)i^ruIKvRyEKX8YFJ=Q~mQk>Psc4MXPt?Rbr z0F>}lc)(sC*(B`W#b91wMyk?16%Jub^<9<&a2w_XqUek|Ob@smz+zMydsSgq2%ht` zpwtH{9VdNN6mJ1{<-u!GimsOH)SQFD9q|$l5&Ft1 zi!(Ug&3$@qrJe0zyP#t7AW|6;OcebSgS)6;NN#^VIxqVAR92oA!*w zIl`N0+KNyP5FJP@j8T=`RN-3>K7&ukB3wae$3d(%$ejje3FR0+*T75#kgLQ|iANNb zhjtPxP3&T)k{m$G{-fWA{i+X5Q}}5HV!^f?0Km2cTZ)L^AYl zz~U8rNwq76XY~-t0nBv(2^C7CHlOuk>$!1{E|8_w=?Lz=Jdc zc<#>l-rW&zqbva1jx|@#BcVM9n8vc=@K4AGpmD#!2udq~-SK~}4M8a^szmQN%!Y3W zAD=O5ejWgRb{GQ2uF^8~EGx^(P?=@`>cBG;pP}9r^G0hNZ$at102~T-GC^f1SRu

A_%cY^nB~nLryOmg z7U49U=22AfNPGVgMYdEvpNqd3VkwD66E>@HMdrqGRj_~tkC#`hpViMCE4~fXHi0L# z3a~0XNUxTuz7?`aZ#gBItR?g;=G@#`sSq$HmNM?n>mcMM`hxI|h z90DXkpg`O+O%QE<>+=aIDWdv$=eL6Mba;5xM&MzVa0q}4W#-VvMm@KJ+O6N$JPosf z6gHwpK&@v%%ij&mVpRn%IzGdiTumSos#3}17`{Inmw}b4D(=oF*WW34*t9ZvH2?nq zUSJ_9%kRj3qlg+%Ch7I|tzgFMDLw@*;o$_3=D;|mx+tOBaJ<0smE{1^!S6`ob|ETv tSDy1v9l$*Uf_Ctym1|E$rmB}&>kp8-&f}bY-Pr&D002ovPDHLkV1goI?@a&z literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_34.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_34.png new file mode 100644 index 0000000000000000000000000000000000000000..969b91193d409a832d6d33a097670ca00399d371 GIT binary patch literal 1591 zcmV-72FUq|P)N{wWzs0r^zh-ZRrN*TD7s&hj5Nyx;{jwADBgsG+(0nsZ^C+HrpYADRK4=SlBA&5=9|AUP4f*WGgRceWk! z=kxi_vKwg(_Be<1yk{IK2go?7hh2U`4j|=n5IaV@{lGJl z{GF{;zDK{;*aT0^kBmKr|AevHNzii7(Vf=adgSBzt;RJufQM2}!W*8nXDCC^x$iW- zM?Rh3YTOUg$~NOh$C3<>@88A%5j~d-&_&y)zf+uaNRuPyo?V}MnnqD`8MaTa)XNCeWZ+{pkIz3_WZ zzjg@C&#+l*4j_4DCQ({V<^)#yNz{z5S2#b_No%=hO%7mD zLfiHDbyXI8E3_mGUyI}l9eSD>KvF_7JiSK8sW85U9cVo6awtzS2G4t(z%%A*9kH&d z5Wp=a-Sr^Is^m{%0Bv!t*v$ZRy!S7KMi$z#>#6dQtT=<+PUK+#cz$ONK=mt00xeWM zr(VqiI>gW4&H!V4*EPxjFqYI-=Kz40Wq~!}D=+0HsL7~~*If%IA;JLkS`?8m`mz|G z#&qr;H%=seRfYlX6w=KqnH*pYdx^IS?+_p*G!|;NX5$`Y4CT$pvxw;0p`#@Spb$fV zXF`?`;YD;o$5+F_B0cB`0Up_&@pl|CEn{Aj16UrkB!gPN z-AAz%x^=pl0VuZoMo=ZANY8r{#!e?V#Q>o?K(r$_84Mgsq=k-9cLrU>CO{+)_!SJW zDqdLbON*vCk#(VW*99!HuFe509W_`d$5rX@81z`Wau6!-gyE@d%X2@T0jQC@6XN=L z$KvSs#KKzj{#7|Z#U!|bMTH}E^s(Z$(+`KzQ-H_w$A}+0HSDPNRp>yAZB=r$mP1(% z;7P_{?9M{WX(s@jU;%6Se2fAHupWK5XQ-hn4R?Dk(B&B3@LiGvc+ipbtYn=qL{x@$ z(y{dQu5bF!!>Q1Y*p>yyPM~KeJ8%paX*-e10X)Ypj!|~TX)gR|y8RWTa)9Vr9lzg+ z6Nct;ByZb^_xA+uQUEG`r*@mQeB2@P#t=~Q6)_M`cgO#zF;6(btuW;PD^EOGgRd+< zcOnxCI+6a07?==^?b%9RcOS0bE>^fM1Xw(AmEmJYI296ZcY+&3kIDcMTBUtyl%5AU$shA>3<^T+O(&v|Hf>+}PbGfp7>I!=G??kzLpfEDl7k zS26+JOkIv}^#27|5#7NVMCmtk1kJ?tDCQVr+u>I_->#Ck$j-{{nB6r251Uqg*0TJH zm?$I)+vVk5^@T3Eo_?9I@NKg_#a7_FGjmSGI8j;j;`S;e)vqiE&DR5;S@p!S{sCONsyh002ovPDHLkV1kQQ?b84N literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_35.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_35.png new file mode 100644 index 0000000000000000000000000000000000000000..a72cf1823ee1ad46ad72a8b4e1e9156c0dedcc88 GIT binary patch literal 1560 zcmV+z2Iu*SP)#en?wbq{JX}$ONb>MlP_v`U|ytY95QH*}ta|<5%J8)9=F8MDyFcma}&_&l2lAsxy zPJ%m|hKRHL0mEy&;D$zxqk$V*dTu!v#iZ92oYWItz5@r)xSWQMF(6|6+c0*2@BNE@VhDlk+2Ex8^@#%y!baO6~Yg+kN%Or}LYQ3ps!%q@08|Jy~sdgy3_p zG`>eZpWkfU4`^jK<3`8Q3{Rim76Br9P9wmsuzgC7Bv*sw1h+*1>%KK^83&M{O{!A% zEDdN*a8m@}bE4PTxL2eAir%|8;cOYhuokQoP#pm*`Q!c2na}Nt2%t@b-;*YE5}q7< zIs#}&i2&KV67k^i+!Gb7MWfF>um~2vR!4yG8qxn)1eg&OYtmAVL*UsV5oo)zG6Eoa z(f5*m+Z`Zkd}I;mm;;ux_%*}$ zQiRm5ydM++BB50B%3V8v%eeuw+?+B0m1wq=1882kLX>8cIf0peT4<*CGn}96WL>4U zkOLq}Si7FS&SJs0!XjbxUW6;`&=ZaTni87f`8_^PhVhZ;!1M7ghw_lI(ca?(o-t?Z zNOfIG0n%dfT|We&N`9vZU@b0+>IlHcd;g=*$U-B#o+}?=#Ve?GB2NSu?JGF|*Dr+x zBB8o>yP7w`A#Hzq1ZeGlU850TjHO+(Il#aRSzt@}%uA&SS~9Zp^{$1}5QzZ%UKEiu z`a+D)bGr0Q8Yhy!GSh%`3fUc1RyaUwc!@U)?-ZaB8YHx%Y}|ttLwOnbDk8e>&=KJP z9BK;iObAI4UPKqPwfXV0;yCDOf0E;TNda0YnoY_ITTud|r5!&0Ob0&Z?gd}r0INVa z09~`*KR*kQiY3zGM)OeA36MUwoDiaC_UZ^=9s_BJ^x&kSybD-y#6-rth65lC5i)2& zbC6TJcjvjfHD9DW&H;7~jvj3&F{AfAa=e6brxTot0HHcSw4*f{baL7mU2B_BD4}w* z(?Em={D=tPsU2wjH7BqLD7w(qbpb@y)f@onm<{cmP8UjZg4Xm;CTW{W{Hh4xNg3$b z-5Z`Yr>TZ_9exA{h*S(`EMU2Q*4lhG^*sS)qf(aU$29SmFSY-E%50YXv6y>;}$Ijim@cLoEHf6{iba z{Id@9x)bl;30zTNqySpQyVViU^6?ItH>QAP4j>sEMG&09U`pw-hMPr5JZg^tQ8jWrDJ6d5{Be;^_X zuA~%FcbAA)5OtsxQs`})5gFhAZCn;4?_6Q26xF*jf@;U{g6o&Y0W8CxAaSP<)w_!4 z@IK29Ff;sZweMRIF=mF-gdHFw)c;`(8BXJN03_7^?fQGco#r3AcOtGYWHw&_0000< KMNUMnLSTX%)YRDk literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_36.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_36.png new file mode 100644 index 0000000000000000000000000000000000000000..9a13e7c67db281d96949e0be75aa7ee4197dfa96 GIT binary patch literal 1592 zcmV-82FLk{P)PbXFRCt{2UE6ZqAPmGE|Nk$$Po#>DgjN?WZn85O5*vg-Vp%v% zdOgqcv;nT`YQ2i~z4WtWM*?r7)#LT8dNZ)I?^*rdNT*hC5oqn{V4ml3B@s`+U-)4r zKx_Y!U_~z`ls_^*)2%`?%=8L8uO89;1H zljGedExV^MK*Z0o1mF&Ir&lC`h0!FTex1$$qvs_Ipsf_H%saG%klu~#&e~40wohV! z4!-CRyQxzE4}RZQC8y}S>$=22NyyOj3_BgG8DP|Z|GAHo#~{rBS|;*m2ut*K+-cr^ z<(3gij1w7PG`_F~KswRhOAH~EQew@(XwS5u1%a2VHGt-u=BJARX6(PC!L3~NS!fBd zk^vCEIIBVoAO&QUW!5`s#hns-50&zE98?FbNP^y{<`3fEhX|yV`p?z`QQ^Tw2zMS4 zIBy3X*Ql%rzO+cSlDGTD0NSdr2oN0vIykNU8({6t)fyn;-J zVgbunFPnLjz++P@C0}pa5HaKhdI~`7oCsvaTkTge0JnE%9T*87>D_2wLYDD0Hgo)umh2FL=@ z035fqGNLO-OM)GN&WwTDK>PAw*PL{GTm(^MokN4ZGdZfUlK~J7Koj)3uJ88%ykdoO z)b5Tz@9584f2DsP$3Usl45yGJIE4i=iTXMXz$?xOf~53U1bat9oz4IpW&bSP8VD*1 zwP$a^=^B7T)c}>?!lT1V0zOHeM93yh^f>q<89*Df=W>Hjbj8F}CAIes1i^6{pfVHD z!SNFZKX+@#7o`6RT@z{hBN>1qG9YQ9`?K8>z|4V=DhMaTR;p%;0dgnE`7r_Lej8r|Ob~ zp5-N*(u7-q_N;28jwTGN@TTKxM~VR`l_GwCw-b;-z1)x06LrFyruYDUIJ!U?(L(Hut+6>gsXQTvh@)x_LNhUDOVo4*)hA$o~o z4Lo`ah$?9`5j;s|F-AqwXTcZsa0@^$Ya++38Hgm6mI%>cNl9=*;3YiIgKq&EMj9X+ zY%jZTdh^~VP#YP)`Fxxfc#8BEARSvqM;UZ7tN5PEgg2+$wn3v{FPb{)C z>Gyr#?Js)oZS3~m8wKfnHg?MY#%I5D2tTLaAH!!)kZ^CJRS6`~@=5KKh` z?GJq5Z=Qh}@-6z2HGmgT0Z0P4uN{L7S7;2#^z1FA=c)27_6a2bR&Xc*_a#W}Cq8C1 zCLGI@D>stQBHwDCGy*^+pu*bgF(_hqoX?GA#fcHXqbExMt-~TQoBfm_R*br;+i4MC zcHA8Ssz@NEi4}&gIDLkbA^@}#-b&+sbO998GBK2yIfyd?B#y_35qei`XY#QvusxS+ zfGiSNW~P(^esT>U!CV92L9?U43Opo;r~%+Onp~Sz18}-=dQKw%9uymHri5g?tX$lh zo&=HL2vHdUGs4KeR+6cr5Y)_g>Hf+Ih{p?w0Jx6W ziCG$`lCOca7O=>k)c{z(kO*K!WfZ6`1icZUHQVm`r^eKb`(*5l0Gb*A`lNU8HjrB=kU$k&)R;d7r$>N~Hjul> z@*q_29Su+3&S+sZGBr4+2AB=@&7nFAr$+#c={JEE5@`EQ&jau396UI^2EY(M3iXhH zQjFT)mHRS@^wiYqm>`oaz@}u#p*yv4WKoqmN3@wP9i~T z^1souZZq-r7eZhGmL>eYKmUS-7pJ`>!UgOTQot+95%8x9E9(Rq#Cc-9^3esr-z~KO z#Og9K!${ zq)T?I2W3Hc<#FpFv+Ln`s&3Gvq)QT_0X2qXe2sF{djpLwxI3^cYH0}+0 zyI3~ErF8)3WDm3v#X9?`alIsv^7-zTFDk-`Uj=K*{1`zHZLNsq17DL_(yTMzJtPRU{3zTMJEJPFAvKYk(DCC8>pqsvg>d>X~f0&$?DIvpM-6N3MWkr`72v=2tCtrvM39zpxr$=J*{& w+%9TB?jEFXW0F?irG_|vx-T(jq07*qoM6N<$f*O#b7XSbN literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_38.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_38.png new file mode 100644 index 0000000000000000000000000000000000000000..93da7f4f94b06909289dcbdc89181a3c10a2f39d GIT binary patch literal 1489 zcmV;?1upuDP)1ZUZe~C;v8JmN$l)F2__2&N)} z^#yMgWdi9ag^HljB`=k;8D>#&ZpEYRhCqCyj zCY;NaD>stQBj0PEG6Fy)pu*Pi7!)xg&gbUx;=~9L(UT>B)nS>CRzGEk8KchXc3K3G z&W9twDiUaEVus-}PM2^}1b}wJM{VAZE`VZMC5AGRgE%8V;zW#?q4%nzBp=%X+jF`G zs3L)9WojwlH`f3f+%*86v^omRAVPwS8UW5?$+cBA0H+(Lrx*e7q}Xth5}NUR z5@doS#L5U@(F=a2^t<3d&iR}Hxv(rLP)!C-PPRNLFRvoOkjd#|(eDMnfbXpe;DV#~ z{^Mm;E(=iR3bJuJQ0W05Gn`M=Hrx?k*L!a-tMj#x!+pQX@RY$UMy%4Mwa>)>7lk(h zV9b#EM-5_j@Csmjs?UwKM{Cy;fJEE6KE?5VWj#?fR7q5YLwq0dO6$ z6H*#jCEo&XE#Q$Y)c{z(lnCI($|$h95R68E)_l(+WFaL2oK_z|z3&hK@VO|wtz>KM ze;YW%LT`1wnlN{W09qYY76CK?+2LnbSCP5Wta2n&?3Z}<0R}D$^SBl6$*&bZSOS&4 zEC%6F72S3h&KKoeYgMl~pPJJ$@13zT0$6GQ=#$>T-9T=mKm%29QFHzloE`x_+CXlQ z=Z8?ecQzt?8bF#Xi=CA5pPB|vj{q3rGl3owNP7objbJGtcXSRBoL&Q9 zs1JokNC1`5##_hEVpSV>+X#@Uh<6@|WV3ovb62*3kEsFh#1;e0tgO{rwpF-o1khk5 zfptU3JN7PkTn&&3?0jpTP>}|za5vKadn9ZetBgcd^48pcmkyvcUj)ehO=UGeCT6yl zXXUPl0w)mFbL&2x02#RrJ1To0;H0~O+3?(;Yfbn&fnH(bdJfdw*1L$A?P+wrRnIz5 z*L(fp!7D@IaU)2>aKLzR*T8XiYzwtq>^)ZEH3UTpu84v|mUOL^R5Le-DsV@#PW_p< z0l2C&jB7Py)S1;?1?;Laj+OX90GP|Yw}auUqQ#+b+D#%{3*90G%nG3#ZmkKV`K)8T z*F@xa=DZs|x&Zjza~H5R`N7g^L@Io|U7CeErGS#Z6zbXU=Md=tX4<@rf-`duWL0_- z|8=m(pjgqY)S^Wf?Yivo+FTIcI*K}0@IQB2%9Uw0swFj&&@QXU)U7JMipMS_zkt z?=3oEdGK>2HDg>F%PayY=VY%yF3m_fdG)~ck0fh%%a>(eQwq=&feLZw@OaC-+Wi6v z)QYhJ%RObI34^k^7vU7pnvWn6RJL^*tSKN{t`{(6MPx63AS8n5e*X-t^$$igT4cA) zR`k}|GRks!l{$|@u=|HihV9iW*%M8ru8Iq^2zI3aE3kfPHGt&!9Yx$O%-s7}Aq!tKO#sdDr?yb1A>zyo(u4_+ r5$eB~Lk4Nw1h9nq@2Wo+m^6O?V_bGuj^r&O00000NkvXXu0mjfe?7R4 literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_39.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_39.png new file mode 100644 index 0000000000000000000000000000000000000000..7510931b44bb100b314d9bc617843bd51a2cf164 GIT binary patch literal 1438 zcmV;P1!4M$P)$~B7-|wG(!YA*5C(dt?@6`<69HDoHRyL1<=sgX#!|F#% z?fe-fru-e}x9aC31oR!D7xe?e-#J7p0nR__L|VYLH(6#nfo6WnPE>hei-ksqb?`NA z46KaW30~tz#PA&%z#}K>0C0d(aHVlOic<1@->FK-VuDfUi*^FexnaGT0WeTT;M#MF z^fCgcge>}}*0&1-K;8D`FavlX?f$-vg%PmvRyo0L3;;J4)bTI_Xq5tmz=ZDGw7QuL zU|})}J2C);DGZre2=El}GlL0hx z^?zgXrQ`q}NK8QWp~`G0z{awMvr#8#b5inX{n|o7Zpb^iq;4bg;5%`FiA9|*c_b$c;x%a0ie*cSpg!#XsZ~Y&0Pw; zks=rXLSh}P?bU>W)P!}&bP9|bM~z1@K;}BQB&@IV!o$VbKupgDk6S(!?WG}`VA0PDQa<^Vk|j3zR%f@Mx%04a$~V*oh# zP9Y%jE+BHJaTsBMsJS)w01elUaX%VR*%`+`YrDSvO8s9?H~ws_WB^SL&^u_Y_46h$ z+Z#ROXJ)_|*qs5sj)9s^)S`au@r~nh0ICC)7@o8fS7CPsfMAorjQHfiNnv338~_5% z0kWPv!Esl4{>-O=n)b_20hrKHXYe+b=k+XP9s`ff0kAu14=k5T)~n|ea2x})Um}lz z-lHDZFCsL}$Rm!-0U9tSusFqtf_HryX~ikYYD4(j!X*Rl`rIK3mdz6FEFsSVMp=LZ zH2xEIJj4zRz{vn#yD&p!7zaCIj?Sa$3t!LJdE9&yvShGc>ysg%A0+Z_K$GZYv%*eK z12z3EPGw!&`(xsw44l2gdhB{bD8*uHnThuYMPkbA>o{SW(HmP}ZL#s6mIIu)mXA*g zm7D+r_Kq70ZLHp5MzJFcz^m`kG7~S&gwZ*G)?rQq_0FRsLO_GZ*!`|vu^V?`ffJpY zeLnzpG{k@%wXph3SWXbx&T?D`z@Xh#eO&MByvCogoBJ@N{n6mW5J0{kz%qGjt7V8R ztiD~`B@|h}eqVrfLD+7YZH(DQz*yp>5J2Vt4cc9W9Uq?p%n(+#lOEM#r8F1T2CL(2 zadBP-lR^rVf~3nMNjNVeLV>jVI74G?y>XoiuhzVT0{f34QfDtkX&Gh2fYfekWB2V~ zU0;v&k>-WK#@2+48DQTJz!?BrfCe*@Gz}BXII?oi)H@*Ov{_Jv01lMEGicZnzIM2) zfU>QYqm;oAPzs(WaJhqap^^hxlTuA0Wf?yTFa*s$#kfO2DK-c3V1z|R4d`W`kqfXk zu5_;wiETbAmV-wTqYj|We;~X@lR{P&YALp_jvawE4nqZa6f(MdX2)a;n_BV)Nq1?V z4*-S4jyN+jZ!1Q3a%Mkkh~RXNerwnWFz>V)eRX0sg4vE^1(YxJ3nNO2JK~&RYz$tx sXXQDt&#(hXhCl7;*eZB(oCv4+1L}9b5t%S*1^@s607*qoM6N<$f(+J@S^xk5 literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_4.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_4.png new file mode 100644 index 0000000000000000000000000000000000000000..f99454b164c598c8b5e6ae11d8d9864b7e3077a6 GIT binary patch literal 1284 zcmV+f1^fDmP)#PQ8w{{HVu407ihiAtVW;!`7}vtu(r>w;lzx{D>EzvbeHm z=LIkV&}3)^cp@f!-vX`xq--vq|D0We&S?z^&=9by974z37NtkLfTnypKk5NcL>g8F zoCaFc&nhP+L_>&nJsV0=jUakRCpSMNRLkvAel!GX$z>#u(n6G0k$4Ds0L`sPF^FzJ z8f#%>?41qEk}V}>EMH0>>F0nr47~bZOWs;6KU;!#5dh(uDk2%I zXH7fh1X=GTDNZW?r19Q9x;ufR(Ayx{N#PV)EuWdIbrY>MwCmQ`ZURKyZ%g~rYIRDD z4sFhCWV3W>ZbW(3xQthZcmSzv(XRKdf$li=!U}^K59cX=RE`4=0qA@HA!7wOq}H#O zGewk7KU>xx^#a?y8+c;r$LoCU9-^VpQoaQ`FIs+X)d!Gz+9mSh}WX z`P+8_NA(m+S<@HrJb{$MWG!D(I{h381zUuG8OhEpcs=_FJmpIkFXai5JuD?a??LT~ zmiS%gMJ=Dpr^KUs@USEV>`<@IfE9~9;%9sRk-mw9sRa0n;-kr|l?z0}0GE>up~DG~ zZHD|Byo_8UfplFfH6y(P4MPaf(&MjVQB9!MIE-9dyH3G-2pL&i=9E@&l literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_40.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_40.png new file mode 100644 index 0000000000000000000000000000000000000000..a17a14044a94054ff24eff8c1b51bac31c273251 GIT binary patch literal 1438 zcmV;P1!4M$P)kKQKvOJQ80A_|Ne}^p9Gsmcu&^)qeHk^&j-j0Un{- ztN*$#I*#MFweV$t57ZyB@A~`K6=~aR?eiJADE$>J*S)%}(*M)bh1E(P$omofqbRRj zq<*V)?+l^sfqX8n-5&kX`8lPB^)7;CM8#xe7NH-P#mdExY`&?c|?LK@#*S2{uUqHEZR0r;Hvt;qmfs07V1`aaTluP3fz z02Fp(0KVZ`A8VdY-dURDCRFMp?fTJVS;nklfRUXM?8pEks0<)^jx^Ys3~OxlBt)EG zh6zUcdAphcMz)RYd}9F5;v(sD2L?c3f^Z}8}S zZGt04qG<3=C$M5OItQ4s55fQ(T9}ZOSI6$V7@+AUdUw+P{VW4;Sga%Ug*t%ru>1j# zIe^C=Nsf0yXP_lv{d+UHLWP|W2k<0ovz}kU05dYJ1&AbLy=}^4 z>&LEif>{P2ir>Z}01p8~@Am^*Hp<6HPJpmyX9nQ!&0;2u!cPG_+m3oKIuVrYszfFS zAd26}X5n&xY$7r<7PV-780g=tLWTiQy0sjD10DiKED!~9$4cR4RtBnH-+xtjl2DQZ z^q6Ii-hrNkI~l-}1MvK;+yRK@o#1JUPqaS+gpYwU2CgW;?27+B2at?<;!d8$?hL@O zECfXGWQW;32jEa009l70^|=F;4)!q&u%Zf=-36I4@r*8{?2pa?ybmW;45j*k#v~OJ znZZXe0OA%d0>o*-;|MEqi;v0yRzk`dc+o-|w+nW%#e+8o$eiCjW2El}a6~SZ_`Ukw zh%f-!UT6+bQN-c$D(d}rV+T7l8~A4@|F9|{kz|jY3>g9>**o0^q7h~Amwz1UU7)Oi zO*V&ifq@JGJKY9)#z&kg`fTd&1kQX9pn8XCdUt^pi=%BNP9oWJ`u8j+@EmC*HnBYR zX{UglZ1Lih7KP}2F*OSIdMcMOQz(-3Yxdm%p2K9@O8ka^M%~wSl~PZWkJhon;`7b( z=nxPApZtoW-8Tf(;6xZbI>u!kp(+GaFVd4jz)6%l?)4Lopsq|6GNL02k9_WosJ0R> zAwZjWPq9U#=^1=OKs{dS0NG4mO7603V6h4++#vC!5b*MA;q7%h5%ebm3w{44XXT=J zD`=HAp-%x^uB18HFxH( zh0lT;DS3P4B(DeoNWGD9R_UEXoAcuWuY%;A(M3n!DXhe5$BBa52g?Dpg})<-y9h($07*qoM6N<$f~i@aj{pDw literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_41.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_41.png new file mode 100644 index 0000000000000000000000000000000000000000..f763540c917b48c20a54984132b516ab47935de5 GIT binary patch literal 1412 zcmV-~1$+95P)hLzz;{h#>kuQEvwZiy!V{y1I$Kh&bN6xMN7?W4b5{{c@8a0}g5 z{pWeYaU9>RhKB(@P`}H*^XsS6(~j@b{fOKu{T(gUy}Iqv|H5>kwOjD4%Nc(VOvd-gHAhx$N z2sl|o$EqM0I%oD+>@x*`Gzrqga>iFVf5@NN)y)7BxO9_E7m}WF-#U+O2EYc-u1gc_ zF|vvVuM7e$H&@pH5&KFQfI>^H090OC0BF@F?l)^IozJbX74R^?=)bZCp!S&qAQOS(AtV{YS-5}3d3fx~ zAc!&mfd4eM0_7)voizGYf(hfX!% zWV0{@K(-KxjIDASP6PN_7cvY`rCX{2D9Tg7j0L=?T(MkwiOQ(zhx@NePaIlm0E{Se z-~hT4u4Dj94M6L&_5c8g2f^K(53oN2xL*S!2CmqE*%g1j2H=bu4@+0aCkDpu3_#Hu z0M=Iae1UN$~54ZF?M(0Uc1UuPc!LI=5dVlBS&GdK< zmFT(p)$lMtwY{Y^K-VUYM12{ZJ2)R;4?83q=)E_+S#kOXkjrhADS+E!*y%K|8eRtf z?;nR+DVkF{`p>}0n#t}?0Xv-rTE=^V%KL2M-wCw*9sqaVKEseTJ{@lXJ3!0D-nJ8O z06uc?waNm^^H6tt3)smPD_$He&(gsRcvV+U0A?2NdBT;THB7ec#CHn7j*o2R;!k&> z#bJk)M}zU!DZmO$dliObc~1)H$GgI4?Nl!lTtjZ=meV(^~{$LXSNR+k$qXt@c7o&Ry z1G8PmF3@@;+e*(yuS zb+9OzRp?qxQH9wgSF=Zj{GF(Oz?=eR;I@mUEoAG&X#r$OAsKWyA({d@5l#UBz5t0J z!y;MciKc*^ict%;`K3?^k=2lOgth*mh|~sGrho&$_n$^(Fw3jlby{S0ZVYi)y^=j_ z>Us6m=1%=v!BJ2nx#;ek|`=|f$13@63_$6Fk5UBk>stGx zC~Lmx=#g)Y?v){o6v*fD>g|yqwa=3p_B_v!6D%bvj4|T`dfzNoIzO`bqIy0h!;Ba~ zo1ET9&m)b6bV3xf!B-vp+Hq~($8j7lj_)VwF^h)i=YAjkeb!k~8bmo=!%hr9?J*in z29Q>AKc*=`gHWj*Xl^k4fjLvX(LkBY2!Y(lde`8DIpJ z0jxw4Kx2W3 zG3Yr?zuA>5={g##gFu>#r_1Uf=rTw8c=U5KfTo0%0(canR<5Q`H3Mjn(#>qT(B$;< zUOTD`P=Sb&C>p#n2&~+Ut^qRoL2H0W3P3V|N3Sawpv!LUJxJ;CSq9*+SVy`R5&)4D zfUE&LdP(zm4Vr;ggwbP}TA@PE zcvif1|4Ihn^N9=)HB=-8WUAr}q!qRT5eDejudD&MeoIq;_8{F^^!gd+(R)`0L6!kp zvlmANUIHL%ByS4P=H@vR>9pM$fFH{ulSY^C0xX~l!LHx#3}6+JOBf&uuTe7;hH@HB z1N2xGW*7h^TdM&$mN$YTbE1qRrI+j+sO#wUtJ0H%-vG!cVy)7dEli)Ya+Z3R|Ql_d9)aHt&ikU83WPUXD zk8CepBOOy;26?GnTWzD_%+uuYH~^Jer0cc7)okNAhgiv@^on}tpr!yT3bPLu-C9~T z#tcR~7=CVs;dZ3{4mAZ>t=*1@!V%iOqPr(O7fO$vs{amG3eaE`Xfwu()*W2_EGn62 z7r0Zv2z1LO^#iih>FGacm~|SRAGIPsDh0F_3y=(ESY(y~vg~7}O^f;?Iv}w8yMi;w z7y{LXj-Jcx4tTM>vi3Pzi~YB8Gw{AM;6}(81(^a?Ai}26EwtJPsCrPYq!jIyMy^f) zXt|O5qQ$9Z^Wy}2L5j|()6wq~R$_JFM8Wlg)c~5~uPEZK0^-G2r7V8WbO2b6|KvS1 f5}6tY5j6h*`5Py|3n0fx00000NkvXXu0mjfU$&E9 literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_43.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_43.png new file mode 100644 index 0000000000000000000000000000000000000000..7eadf75185ece2ac3ebd0906c97d054942ac276d GIT binary patch literal 1397 zcmV-*1&aEKP)RCt{2UE6Z&APj_z|NobL9y**7Rp`bF7P77K z&+{y`*8io3hXFoNzDvLJ=iBKi+h?ghGA>GfMoDF_F0FL3a3@}0(1N6#Bf;A;pGeCq1BnCt|cf|Qex{dUNGk_O6FaQE0 zhgit~7QOoKoPH1n(CR4tMpy1=5%Yp44}cIB#H*Fbb=;Fa!^$Gi|Pku08a=&GJuAw7@)~6<*$?W&(Vud zV;!#Tl3hUG7nuWCCWISjhRrl^E0t>#$rUp6JiIX}g1+w#3=kPpd-u_b*K|Y9yC(-| zy54#hpkYN0U|I26|CJ0t$2(fZj1ry@AjK)9@wpYY0v-lv?N{aiRKK?*Fv|m5e=U!Y zoFOW6wG%`cpcH*^WZ<9=B2Hip0g?e|3`H7kcLt!(qKJgiqbZ?zB5D^9eTf;|fdRB6 zav1|~f_fT_Akr6Qv_1^<&$2MX04Ui~4nV;sft<1y`X1FqUJ|)tx$qJl1J$l?zbZU& z_`?7rtO@~i%*@rAfh!rnk^}VfS!;cF0Io426OH!0oAFE8p8@`C0}+E}gn+x^wmCpQ z2$win1XG|-vF?D~8Gr)902;h6cxQ*%JqMs*9l*N<(~gL}N66X8bg-{v0PXN1TCZW| zm^dN}Irg?WKtI^b9$pjN*N?U-)=lxe>2R*cd zxgI74h+YR%!L;4TxsV}%8+)hQKs3D9=t~ZQdPvESbb)~k0Xy9WTKapO%KL8SzY{3M zYpTQ*G`IuxHfXWfTV?{j4IF`^CC~2+?yw8kNf#@o9l%37bb=xWMVx$Y>?=WYnAtKD z%l}ktyJbYv+YZL3O!##npdn*x_k@5Pq+AA}jybbJK(>+Y6auCkfEortU0kwgJ!kO9 z@WL`acPD}=VCE){_T?NQY9y{7o!n9Gu`-F`aJvwI za02dmHb%L}N*y@)XzCw10@sFnCSC?ff@UVrddPz`lH?FxmeN+ARF7QAqwtElb2uzU ziq=d0v=>0;CT%?WOq0d+=jt@tIzIE zW>BkqtsOb@uw?%h8AvSuK}ZCVi9jZhp1R2HfbPUrhNoJJ@88DFzu+iX`qTMD<>k=g>ZopM=qY>6!Qg9g!Rd;WYmMkIM6+eyIw200000NkvXXu0mjf DE2n)B literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_44.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_44.png new file mode 100644 index 0000000000000000000000000000000000000000..5241195d32bc160a3f8f6e1f04eda860211538bd GIT binary patch literal 1217 zcmV;y1U~zTP)z1 zai;(_V&x3?A_cG!Q8PSJNGX5=5t%Cfg)zMlGcyrAyx~1eg1#>WU;qzzZ-7T9n9!hl zXFDpc6aWD9I2r{#UiMVfTC)Zip;_t7Ol)Tq??mncI1qW56A{5mk>oyr5i3sejzoaw z?HS~GfSWO!4lE+!SE>CJfP!5=m(axE6$y1N`uhkf23nw|02o$SKL-s6vP`syfv-OJ zk7Rh;DS!t-3$$fP$%UmkKzp15aN@eIUw<<^4N`qDdYwZHwsw7m0MI;Z-JYd?RuOP( zmS%46@u+X;^%Vk`-HxTuL^4y|k8E0cticle*Em2FMh@W-f%I!;BzP#_i1&2@h}dn5 z$o-{Yg_?HlaccLc1C+nE&x@=(V6|<;0Z`r}1rWJsepk>bqJm$FZ52?;q2~dtLF)}1 z6%(4{dt4qtMFpSs0p&ST01|owBt5S!tB@T!sV#5t>3e5`&-;h)e2f6JAX}c-c%*xH z8uA9eaYY2b6wLN1jurr7+5Fy_nW}L|AR_o4o+FFE2Fu_)q1fv|tKPjlsECdhfEN*K z_-IJgyO)RZjd+d}01sX-n9}xXt^fD$pCX2+6lE3Bku?DSU`QPx-NS1Hlye2FOT8$b zBORc@;sg!aR%&wv?hdA=c3!v?w-vwBBwhAC>R%wBk zxak_3-h0D;wbdLkj`}li!LHIO5tO|Z9n^pm|K`Mk9F3HlZeV~xG zcAp@KmBBA1NC3znaVz#>wAansMEC4R!n{KWTF|Wh=i zM;3szZAF*6IM?zXre(1B*(M00000NkvXXu0mjf=Jgy8 literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_45.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_45.png new file mode 100644 index 0000000000000000000000000000000000000000..2a3ea8e23af713aa1210d6e19693e576aea86d6e GIT binary patch literal 1177 zcmV;K1ZMk*P)Y8+afiT?l%M3TOcp1*+Q}B7m0ov{wHCARx)QRU}^y zDG{JI8m0bO#(Cla_nTl`xsni8G5oidK!B{!uO(MnGP*M|6Y6OK+>4?X*OP!E1R|julPl|e8IX2= z#ChYr8BxSd0M4NC_tK&*MtF8^h0uCCd#nl&j_-emhMNGKK^CJu4`hY$9$2DGPlEnu z4+*H!v7Zwi1=4Z=%J|uZKdmNu>v_bhVylF-)Q^T$2+b%^JDa)&<$Nx&MZa3N%}2wY zdZ(~=hLqe&B2-TvX^!#x6-fVR*xNvnz;Yy5qQ(uzJMTv*ZI=!kE|vAoj_#U7S&srf%c%ij<7o4(pZa-07?L@ z9EqOuqoGu%jGG@FW>@q(xWrD|`5s##1h6D4BP8Rb>&LI--=%vIu zb_C3jq2&7jJB5Fbpwk}%GnLbQU8MUrqErOf#qm*SjUP*Wk17Qp?FEc@S{Kg(XP2gu zYMRJ6{tOAi{~y2uZBcJ_zC}vDVRbw=j|U+Fc$vz9DxV^dTC7MQnlThOk;giZ=UPY- zc!!=D^q~s@s$ulT$U=eAA2dL70Pn7|$fn#JGvj>&+|qQG6l~SRxxdXq8Z)CQz{@~{ r<2}3olzuV5yMa+>WIFU51OMX}ZL*z$)XYxz00000NkvXXu0mjfwJRcX literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_46.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_46.png new file mode 100644 index 0000000000000000000000000000000000000000..f4b263b199c8402088ad99c4dc27ab3c38f0bf2e GIT binary patch literal 1300 zcmV+v1?&2WP)W2D-85p<^O-V?-LPnye~A&P*RkfIgD9c7`y0J zKF{+!ki_Tn0RVskQx}Wzr^3i^{3XJ9_^;B~^E~i8&tD>3?2l3c3|tbNgBAh+ToRmu zHUa=#5}bfm0$l8mb^_ceus3c5_;Hlz02)RVI9(r@BUyGXm9{ciLV$0|FFAK((;=kcky4*qM5*a_JDt~((MX(7Ka6%66%u8}l@6alov2Vl>~!z|;Tp^-p3qa)`x?rZcvuW3~z zXo&#xq^s0Fiyg~Ca665%VOiX{4Yoz~r6tN-oB8*1n{0$FCjghdR@jWTqZZc^q2|Ty zI?620r^Zx8f;J&&weu}D@ZxzFOd_@S^YOcg(`G_uqwP_*fzo1WlaJ;k)b8STpCp87 zM^A(dn9y4gpeyui$yFplvx3URtFD7B#FW}#JKk}H2{3nv2ZtA|;~JRTOChE9BU;dIhRXBHMj{N)ui+1(x9s{`bgUh@Nqy9olEMdb(5+Bs;za59=Hi$VW3sb zlF$(~GQi0eM|51Tdqo^g`mL@++HwFbd9v7(9qADQ3rV)UWcHc?>t$KzfA>_m)jyzVvXL5;c2(UuW?}j9T zQEdS92TJhI)+54-R|#Ns`W!w-Tk2xQVk-j4p;lc$x+{3Iyj?~BZc#k2*4wLqL;4tl zG|q~|5r3A60__CICUE$Yg-U)_z*6r6z&~xM`vUxLtzW4hJT@cHu&4^IV_R zVb($d@As&-ls#?dd*)jDZeS%UO23Zsk#YuytdlI|VpdJuQU|EmtzC)Ld>oCRJH{Y6 z-y=6`*e(Kiq)@A!t|@vPTyZQ(k!RZ^&jc!_#2`F8$R-)oEhC=qz$J4gu{|xeA4qX+HE?~YLk;|sG7eg%2SUPIt`A^2)FThKJ zHYwQR+>TPva(!9>Ygn#2CcJj6mqcm~5J^ZpgX3&RNU&=6TbzKU+p4j7NuZ4(904>X zkLu7X`${$_L?ey|RhKZk^c}7OBvp$-l><0|WR)Y{%rQFpPA7r0_%MLapNNAxN~>R~ z20SQ}g7Mk(4Yz#1fYQ4FT!KX5+5NZl%b{Ec$U39bq4ya07ykon_@I`j=(wH$0000< KMNUMnLSTZO1z`dJ literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_47.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_47.png new file mode 100644 index 0000000000000000000000000000000000000000..1563ff39b27a83826ad84e5eb30d17b8d216a971 GIT binary patch literal 1268 zcmV6ZXSuAvd3*nNy%ItPdd9U0;0d7i&NS!1k1c?I~Od5L9!C@=fQ z>HGTn9vNe|_qR4dfNaU_`=@=oQfdj?Hude28xpzn(sd-eLk1n|Vu zlSx459vx!({^{@DG5R*6Aps_UC5PO#hy`0oq&}nfj*qB-WcCvvA zgnmz-O*(Cz&=4YB_l6RP01~U{|5NGYn5kiB*oaaqWZ}8E0kouMv~ZINssP*; zjY4_`YIw<$tsG1W0i_Ax$!04Uo}xFtR!c$Uf94sb^_wCio3U>8hE$EoZ-B?25BDJ zz0(9hk}!?^5@wWTcTyNV1b$2iq(u}V`syb>Y zQwYlP{FRFG8Nj>u|6pbQ^xl3yla` zwF3#^?*{f0()t)Fmqu)@vf(8*O&UFY(LR@yf@k9^68lCCT?vR0`l8L(=KHK=^&E*t z=P>>E0X&n@uG2oa$?s0;ER2M;9&}B$wT&Wt$Z>FM`ol#@uvI*%0&Px6NSfI_coF(y z2n9W~KoR|rQCmz6i1&}?BQtF+mKpA0RwedaAfL2(SB!T}MxW$!rED_d@I2|W&; zVY#>MuH+Kk_GTbs?9fv1uG;%b?0mM2u}ge$1=;$EP)YOFbE}8|NocMCsz~!X0uIheWdDkG7eriteMd~ z@B6+`faiIjNYuqf{HhZ4zArq_Qzh~%sUJ1+ox}HHQ2jDjKJWu&%Emqd?aKC^s0VL&D!zxo6 zw}Tk7YNxC90|aw`ZpvRR;{=8$#s6Qimt|#OHS0B5vxBk5XgZ%~57Kz=IgE9Td+7c2 z{Vd!BIAQ(TeDC|JuGcz`q_~~#+cK9#j3`Pyz^?v3XA$)J3|33>kbv92bxoS3b8D?4 zXBh#;LUum{iX6Z!VdLho-ZS%7k@b!FDG@42P(}dkGCM=Ev;l9s7muN`xVboaR0cN& zzmLacNl@Ae{F3tVLE?WH)cvl?bv$vMBU@%|?OVZB2^jWJSn=MqNC)k`j@RVHSUW8Z zBP4JUfYzm7LqzeM(mCssWX{Stx;76gDgsjupp{DF`YikH(9Vs@=Q8oC$HA6rL>oip zc-LhjfQ8*r85k?QN|s!dFxf)v!ugU8)VP6Bnt5Jk219OqFMHKNLEF)Xl>dKTFPL;mF$zs>CM#C`Ys`J_!0yM=}g#fLt zUI8shlh$RGA<2`@v1Kb*v&L%oueD%TB3jDPa3VqL`L}BX0oYvdY~kLH;^|x>>Io!e za`Ao^0=7I0$keV_hSny{%q_`WK@LmnmyQR>Su!O=Hq5!JfKhTpG23WV_SY&2?EWne zo5po4WBkqJQQ;6EC0a9AXi=18QD15kV`$F@1~}zP`<40%k$ynQ<6rJSM9Qv!Hn zde#~|_jh;yC*UPPI0Vp47GIBIr9!L2fYtq1gb8mL@Kgp{lE9w^i!y2Jwu;yuGFjHp z=G(#Edru{ol@F~t%zeKd>_o?Qa|SJbIC6*eU+_5oyMb4kXYsk8jk|=Y#nO+2ab+UL cRpxp80Znqgg|Y|Bf&c&j07*qoM6N<$g7rsmoB#j- literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_6.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_6.png new file mode 100644 index 0000000000000000000000000000000000000000..3f84ad47e3ded623ecc0323b5d64af350fd1e61a GIT binary patch literal 1312 zcmV+*1>gFKP)%Q;16>(ix1Bf|z0Dlld?)z@nbsKnc*=A;H@KC&0nG zFogie3%m!%1N=Cq5#V@%ci?z{1inPb;jt5BMDJ zQUE;}>`FSPg?pkz0BK{d>w4veb0WWO{#m36pl$x!(C4hJWfl>r{3pqmBES=y?~$KT zoHnMvKJsRn5J#`qbh(NI z$Yqb>J{`-6Fp~r@0#J9h0^F5KuaCep@zGeTV(=!79%w|EK>}z9c&ZGHDur((C2z%o zyG$+CkH$)}_?*!s__E7ZrO;j(MC=-u1Dl+&n*&+yhOIK;~}TCjw)OP@N~MG(!^0f}^or zlAVeDsGK1KND|1c!m_lH96HVdf4`E&YjcrYuqSLp?vovd0`#k4^pU@wm4}4YFX-<} z#FEHOU*rGt`)K5pEM3yy%<5`NCvcbKFrzrCaLFUl#*CD-NptXS{u7w;)vy(^qMjx) zFD?0#Hr|@Y?wjA*#M8hPn58)0)znHcj|}T|@8-|+tgj}(Y)G4J#bk{%9XnZm$JPXR zstK-6lr-Z&Z(u{}whG@d{5F(Vz!t|ZC?@VMXT0SX->b>g(n z*%O_#D6IJJ^)Sm1gGLx7Nr=hvP9v)0Xx&eX(exVaI?eheIT}_}3h)qs&Ib@OP)gJ+ z*2;w>S6#_tEK+5#-3LN;Dg9dWe>~e0;yjzrWm**i>WpBkK0s7S5xLdz)ZI%!Sf!^t zv^-4)+Yn%8yhDX0iv-#R@mwG?N6GT7{3C)bLO`S}dJ0|Ho|?SUztGCh$Vp=aTl4{T z+Gq<}`9?9y2S!~^{#=Xss4)2m0p7Op6eADdxh~QHM&X+0)8uGp z5%hgJzCwa90V3|pD-RhGtTGG@uWXHsmM7r%kj5ZN!s||Irqa%&GNL_lZ@uh!y#h~5 z*7AfJ8MG48yY8@e$`XLyoT9S%n#>4BH986&rF%EVV@$J1P;LZu_Y=Wrg4vB)SzUPY zl}N^~{dtW+N*+Cce=)?usFNni;|kdksN}VJj|>Tx^#M>WcvXy#VD>piM1C|e91>vE z+VqY`hlwcA)qqFVQ)`HjU`T*b;-V!UU+VgCcoRVSSkXha-1D@ip;Z8nK^2*ZYNB$j zC4*um!6k28UQd+({{?|8KGS7;vhnnGEUf|#_QO`c9D1yIJ! WF~&y6@>K)?0000&-uL|>!o_*$B0#|vZP;8qkLkA=s$H*W}iFLX*Ifg?b$?O@I~F zAC-@^7VYrs_-~DEMbzUU0DmC_4FtKeGOXm5=-<1L1-#=K>3(uq{CmFktlR(=0?LL* zwtuZdi5z<5Q0sA$#rJ^AufNZ(A(1Y-M;HNkHjI>6V1*saVlw-Yo*{amJpOCBfTnyt zzlEqhM1m%PGb;hKm2#In+WlJR6iFnl&$D^SN3?>A)%7S2C8M=k;R>_lXdz0gNIawn zpd~IB{{x}K=sX^Fq%Ng}PzccCik11cl!~jnVhGeOJZjnAvs=oq*Ou1Q zI7WB9Mx!=}ED5-rXvI?#A)QRVpwrb7vDTz2lGvffAmC-<+UF7(yz0RlBaPGa0R7W2 zX=AO29&w4*&nv(!Pbw!RrSQ+|Bvfh=)${q9T9?uSv@7#5dfL>dnJt3;>_j)qamG1ln|Qoqq&3hd3Psp6tYV5;^}I|6X}PY z=>SHQXN}7kWj6sL*4NVFmF7gssoAi+V20qH@<(|%hzE!?BoMN-xahS>S3qj+cp)>Q zeEzd#{ZTKlWh2NU5xV7!06%cc)kiA2$q2nj5BnSVW&ujyI7 zO3HT!fB6^IrACXaUKy?HW)#>mx6Id+o=FI|c_nOAPhmE^o_z!@%9lJ|WDi>q;8T=e z&=SAPyvUp~M(TxR6X7lT09qAsIw`DJ?2$g(`}}8%d!h(pl8d^ylFovX*W=Tnkz|X~=c8&n?t@wiJ!>rfCA84;EblN*6}6 z%S>y%$bNdNhb)>yfJTI@%ga)PyWLzi0xO?s z#M%Wiz|IeW_m7fKw)A&ia|2g!_vDJSL&07C;|NZy_mhDl>rw^mi00000 LNkvXXu0mjfjhAve literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_Kaiju_128x64/frame_8.png b/assets/dolphin/external/L1_Kaiju_128x64/frame_8.png new file mode 100644 index 0000000000000000000000000000000000000000..2c8cf3f5d7c34f1eedec4def10bb28095f2e1c4a GIT binary patch literal 1308 zcmV+%1>^dOP)2$7fJ|lyuf>K zJiw2mi~z?AyaUGr{5VPp@KrDHr9B-FkieISeF%`mS4eOO@Z-2gFM~KM=tX|{qUh~= z`#Un2+x&gs@I&#q+BYjG%2vq(` z@(qOm4d^i7QDSB-*6*!-GzCWXN}rdEX%-2>1XyAH+I-LRh=+w(7qw7?Qas8<|G z0cO?4^iVXSpywO4%zk`(&Fuj-rv>O+!syRgXdYn3yhwsm#nSb+Dym{m4lobEvH6RT z_Gr0mEAG>=lmv|&Rh|GE0^X+lJ`=YNSgRP2E?Xi(1qsTk02C@%-z$=OuMrDwGNo8= zjpbzZYethGlmpO3thV;HhUhxl0ZJ}7yD#KwHuoUYF4-%;&`2{zw66Jk>tTL_kYjh5-w6f;sNaP6{ksHzMI24B85AdHr;08uy zNs5ZhDRmjSSlwPnLV!0vs3Zlv3`8yzRr^N9Q!AI0-ky<&KryQPYHZ&JSOKl7vF;u` z`OhxOzpj@MKqg+#%W71zP;~ zdYI{#K@p(yfmP7Ddh{9TIm!AtITB`63fp})a0lf};4HT98E|8IS3OeBdSpbf6#>vC z&M2(9zQL2@L=|UM2q+S4(+H}ve1zO~@SY~n2ys2-p_UY8umu6oZjA!vNh}gb3hHx# z%sM&C*Yb}DmWF^xGi5cTjwFSo=!o*A^3&=rW&wXcfNN4Fu0~s;9{HnkJn|)IB#EH9 z#GV=gG{vJrfL3QCV0i$~bCC{U|NqFnga_pW(5w;d{JxA+J2~r;qx8QANaN{)j8JCCl0vUNyFTpwo$=&ya z8QEjF3TP8%VJ$Q(dqpJ?ap$y(;HnAjf=KeHoVSPq{#U{*ml#QaBK`B(;lXOmv}dIC zN#`b&kly`8_X@cVZWBvDDM0Fgt?VOM3X&AlTfaqaYmRI z5!^rTy0hWH^Z;7#+ZywR4j%%QwpV`vi zXEEa-QShvFRVa&ugW((?8mqnlPu5KvL8C;-#&>F*(irGv(8xwJ&6O3&rMK*@K(ssR zLCN0<+#xPkVRgxg#ui^3Im7x7cr5?kz@yByc-_~=9l~HSPbXFRCt{2UD=M?Fbt%N{r_KfU#hJj@E9Jlr9=Z1-6S?8i^D_X z9M^r{H#u=#7ZDK!PCZx*KarD~;|~$`$Dho}_kGiS-@imS*bgZJG#nD_ixL759TMz{ zG6E1C66}al0uUV%?1pjz9PEWD1UOk>AB1#(Z$(e)toBi9D>aXZ5(pc=u8$RoGS{}! zx||*$h-jHx$@xT+3GnH?fcN@Vb3W0@0BN8kSkd`JhX7xXLx2KUSzy)ZCwhPYpWX+| z!gXE0>(>6Bv5rRv_=jtU6S=sfx{GmW8J2e9^|Pwn}e)BA`(vVcYwX&f%KkFQHM z(b5xfUd4_8&HyXl^ziJ}qxLJJt%2(skn(2r29bHe1n{K2$V67hmJX?QuU{@*UIt=-{zAvm)K z!`QyFx1e?AGr%cv$j*bagNi{CnJTY!`X_@jo%agpox!Da%OT@76?OhonDWV>RWKtf zaE%{Ag8u(;j&C`iXz_OhX^Y|QF)9~UB7wIIzU_RXP3{Itcr)8bBtT(p7yEHE8`d!v zwkE*a7#)a~9L@Pp?--UY0V@kjV`FDUF(=hVN&vS*h^l}@$qX>7Zb@~tK@(is<0^3J zU6OOHOwd1%lmPTPGQC9lJA$gBbc`rOP~l!*p)b(Zh07LF1aptk5`p5?9>B|XPJMd< zT9b$B0=*s(?Hy(yO#meQYSAD;l9#pS=PCJgoZ~pQl>yrE(Z+FnE|UeyKOQczKWZm4 zz3RR|OV>TDuD%_EIA5|QJ@%5JyaZG&bhVA@G;1|`(mHse-g3TGmJlqb1I&_dtI#hx zLIQ2aP&IyEcD&cRln(Hg9O^;e%(cf7GGx}Y0*~BmVd_`Jc#z!-bM~?}JY!hMrs~m# zM>5v1LI-O@(CRyPj5dx3ZUR(BmNjATeTAnT zU2!vpL-wYR=h*c314IM~tuL_3K!kX2XMv{>DFtaMxDAG)pP*(lI+t%pA3#V?Rr;Gj z8k*pNI;rn+`+utdP0JN!V(cT(pT&1;%5cFB7JiT*piD$1&(|A0sN4@W-f ud@rh$#!tfe;m9w?Qa>E&jsBDV^Y{yo;l5Q`AXJb50000VNeuA$d_XjMR_@J904APtJopZ9>n2_@i7=U z7bDo5qK$XJUPju&uN5^?pmsbByVGQPN$hY<6bqD1?xCG>Ooqzsc5iND-YzkV`(MUu zy+r^u)WlR3N~EUfj2LD#=ya%2uU9Bh zW1=F3L=`@4y2B;X4uf5Kfw#kBWmel>Bf*-eP~sNUg5V^jLI@Q}A{L4z5lWGWsgxvv zlZ;h5foESS-*~G63rNH1Q==wv5?9fj0#Tuu0wI+Ij*tw6A_QqAX(dfqX^TQC2NLDp z&UvMid?wJI-tEiT03R=>i*taH62R;jKKImvxto-^G}{Q)(b3Vbd+KgLkUuD{F5A;P zl-J?7g@(qAj(+>#&CXml|0Zr_S82ZHZeDvy*Ju;jJ-hsezA0>E#l3uYha5U^Z>Hrj;ykkbVy( zL46TIbF*1n{J{pT?v6xo9<)U43Tx~)`z5sFVb6jaPj47mAKvhutpZ*b7P-a!N8;9@ z3ro9Gg5bIvmscG*Qq}j>>KVNk`=Zg*T_+_c-ONz+{$JhD?ojH!F6!FjbH_(KGvo4T zNzE+3jDH7L?fGc0wxi?flfyyRHyoX}sd35a<>mwOs(`D<6810nBs+(le86u<`ih#^ zy}u>s^$RmR4?>Tb!eblzdgovIYz}*P@xhY*>qgA)p<$=CdWoYxzNapsLOtW%ntDsQ z4(XcR_@lDhoOz~JcYDjDsQpb_D|=EW^|a>Zb?vTdi!SxwV{T1quXIbck(b-2s<>lA z=A4kxkjeloaz{{gXXn+Y0edb!OMh$%zf~Jw|8dQ2`@z*mMF^XA;pRVs=Vx#4^z56% zZH|gqDAqKcY&;qg@kMJ$LtJNE;i=`Vk5=CdHl3_0S3S)2d> literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_1.png b/assets/dolphin/external/L2_Dj_128x64/frame_1.png new file mode 100644 index 0000000000000000000000000000000000000000..32e13541d83eb0571414851957a4b8a5647a8c03 GIT binary patch literal 1687 zcmaJ?eNfY87!Qc9!no6Y$hV8dsi0}oG;PyJg_f4lL4hGUL{ZWtg^F!z8l>Pk8QumQ zDw}d_FsYn4r!YOyF~#A;={((380Z-294I1wu@8l*oUoJ+=O3QAB=7q^d4A9Hd%iA3 z332aud-{6<0N|~U)+X|69{)rLCh_l^f)WG2_;I>qZZTuxvI&+3)D&Z+LA`}YrxR&{ z%2|7k4g-Km1?Hq=F4+)^lZ-_~xO7Agi;YJEKv=lLMv$2_2O8;gvsESh^Scv5&`ha> z@5>CZ!4^qpn4@!9dU0-C5}BJxDk)+3A~4K>^9C$5M}Q8?8mk?5sDz_-aenU-i-q8* z3YV!8j*&_>B!H0&OM^-g43RJ_0ToIS2_rCSL@3&{07PI!DuxmMh9n3sL2(2H$1fr8 zk)=#{qBd&WAAeE_GdRwMi^bX5*`jQzh+)&k5~Whib)@T_r%R*Z@y;ddUzlbO^g_Ck6 zW<)UsM36=$gi0k!h>$2Th$c}4mB@{93Z^FPya=z;M9HEQFczgz>m(ALR;`A0k&#k4 ztdmJK7%ZK@>aBK;u#)tIZ!_+Cq;kXv8zBT!Dj-yWVUSTtVUSWPlPKgE zieRKkIF6^DOW#2CXA31sEII2g<_tf z*ws1Db<%{0Z%^0u*=+EKXVXPn`H^Dz+38uZNyN|Hl!VwM9lwr@jC|R#^LGGnFV$<+ zNsi8Y%iOG|VZq^%k=yzsbMj{0e!KlHy009qUmOq!PrVPuRn2SJJo3xW@|-fY$MKoHa(U7ZrpGOSUF)6a6GC_XmA9eF*S(8Q*&k59{m5Ho zCI?X;y>Mp3EnVMIps;RlOskLE!7rHMqds|+fo0m$OMo-w`po-JxooZ@YQqXzd!q%0? znvZAV>mM~<#zP@n$kOXix>JFOdgq6cin{|*g6-FWR<>VdPwhV58U#SrJKtzNhSx=K zYws@qbWTiFU&fY6POl|bYv<42mAj}e{*6~k2algC*?2=T1V4-$xJjrhB#YJ{;~i zc&F1hu6drO=Dm}1hf6ElZPegbA)ayjQnrN7S{M3>Q}deJ=3SM?e)`&0x#!wY>YF`p zxjj*z-{4!_)7V_N`UCJ#ha*uP&|K6Pky~<0Jvn+ws0jz^JvtT!rPeq#G3ITb-xO5W zpL<<%u{X6=9a@_|yQa1C=TKB-80w0=uZh`xFP@&N4%}4meM}Q)7=K%Y@gbv1L?vjBQzuNXySn^yxkc1Db;?AiCQf5mHeq8!Ge0IEMhTM`WmlliKa7{Vd*AoD=lMOq z=j-aSm!wCA$A$v{A~Q3LIpXRSA6;mW_`Vmq!z?b-1yjC|%h`kqnrDID%2`+_(?J)p zIV^3hTz`#C0w8FMJuhF#H)l}{=aAEW9l6Kh60HG9O7Xa8ri2wB3tMD&Cc^_~FTjx9 znhdX0n^CjNz!uvxs(3cHYDpebRl<-~IAtM}OQ6i&7{mDk|g^Dmlj&DU>8h`Y|vJ5j7BZrBk3ih|@hQfM8_Z z3~zS{cFqa;5orroCM3fm+p#blF0=VHu+u%BEHP~g5A9MY<*35p@W(c)?G|#_|7pBc z+nrbGVih^8n=9iPu_m@z0b?TqX@TSOIIc9%3E9P*z`2V#7lh$* z97-_LjNR#%B>Jl~7POJ&?d7aBjprQDXqqYeTPWDnDh*~qEeJ-CS_Ib;1Y#kr1VXCR zO09;#F@mwdPX9T*BWk<%2sl67)RO?D&nD@=^9(EaRhu@>2+8P=klx!>`T5|Hwa+h|e<1xm zv3Omx)O);r=lwJ3L$?yGS0t9m>(yrt*X-ZudD0u3AnnNyrNHI#uYwCZ8*65KTzDY_ zZ%e2|0wXzQyaiUiUR&l7j#mw zvg!ftrL3Troh?(PVbF2O>ZAox3nazUVnCIzF=!|z@-*16BddPefzHDciOxD_Bn7=V zEZe*F%CCRVB;qg13iCFvISD~+KJ_WZw)Kg=L(33QQg$eMXLH|;Pgc#l8G_B5(kO|0 zZ#J;V?hf1f!Y41qQ+uVgvEFV$cS$G7ht<(X*Mi-v=XXDe-}233+v0^??WLggblo0b zXxrou;vea9Uo1+`S+OjoN4>Y6<(E=iRk6M_>K`gq7b<0R=(M z#mF?oOC)*Ut8K^Jlkv*%wXV@%!mhaxbTrugy?{r+CkRq4h+= z%Dd5#uBp@h+ScZ~_UsW1mP@WaUw1!l-2g!Ho!cO*zbM%_$U7#Khw0tcr3MW F(|@~CN2UM( literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_11.png b/assets/dolphin/external/L2_Dj_128x64/frame_11.png new file mode 100644 index 0000000000000000000000000000000000000000..eca4a1296ee3dedf9ebd3b010c7be8763eaaa44d GIT binary patch literal 1660 zcmaJ?eM}Q)7{5{wsDfm1laGv?g=~Cy?e%)Jca>^OTLfY&D~+Nvlk448D)z3l2egQz z&P`+lb&HF*5tVG6ZU%;lafqm>bCdXm&S7L5V{Aj6_<=^iIbm0z&OeNoyL;dFx##yh zzvnAgn{QeiC5jgT01%a%qc`)bkAE}~LjL_%#5NS?f3o1<(va*E4De$9i*@h7#onB$x(skEY^LQ)}@u&y;y8II!t8wdjN8j#z|aD)e9+(|(T zdfH98>`uZsFu3yd|`-ndX_A6&C63R}g zNCl2rQA`ODq!ouyxeSL08ID0Ti6W>>VO3Bt6}0mryh4W~a-|N<&eCSfWCp!f3mbGg zxdJw1$g?n59>nG{ZjN9`I_TTZ`<}+iUy4=fTr|P4E(^=93wA<&G0U;;V%7;Fs00O5 zj09ZYE@pshv5veQDF#%C<$5)DPfr$!W1Y1VI&SiC}zV51%cWKt6VJQ zDM|yK^IRtdMSOb(w$EmRKRlZ*n&C&v#m`RjuGTz$?q=jKu^9MuVq(I7eb27|5aP|% zYb~DMKO62ao8Vc74Sf^-H=EP3ttUd7empeZ(3|R&+hf0Q;(q`5)48`byTd&P(!KSar-7QgDb=rJ z&T`&d`M9wt0jL?BCvFSNU#0tZ>{H)9Anj>VXyYf=wq5Vog}8LpwTUB};}U-})+H7T zyCc2c9;bG~psDNE`jSGAgkRkqo!QyGaG<8BCY%ur<(!Py7+XdCH-GNfn*7VCuWO4S zW?$NYWptGfwe?u|!gQD4GPjN0FE>PQ@LxoifZAKo*1Jp5wymV%+~(7C3= zug)%Nm)_oJr5ZLj?B5mH6a|b_e7;%|e<5CDB7|^Q^al=e`ddFmJQ3vi1m(_9>yz(d z_m21ku{QINt;uwuD_q^`&-l;zS;6s_ZjuPu#^3Jhie;4 zyLPa-gK5c88&ma)<23R0+<~1tYBdc)&5FT<^wL4?>*-}9<3k^IS%z2iSJmAJsg5Z) z=-GC=_CRD(3>tlY{eqT(^ME0G`&$14Z_}mH{MDggW7cQ?+;Du^+dJH8x4jJ)Ua2{> z>~g(N{eyW!S9Mu|rl%ztC@&cbi+K=%9jh01KLkF$DySH{zaTx*GV;{|W z(mqGi4mm_>8_+bWlaD8 literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_12.png b/assets/dolphin/external/L2_Dj_128x64/frame_12.png new file mode 100644 index 0000000000000000000000000000000000000000..5f92e47fdd7cdffb93e2cb52b64dd87858071c6b GIT binary patch literal 1637 zcmaJ>dr;GM98U}4iz153Ly=JC&`Fv!P1~fSyxO9@S=M1UVS3s$Noj#LAq}>8J|gGy zrW?~u-E?z$zHcWJ(Xs6We9hwyH@Tfo*ii8?<=n3w_Ddp2oF7Az&gJk~7)NuB}nY1YMnRv%f$ z6f-1UQ`N>~13=U|ucJgLvCTD5tWQOTbyOiAC!ql#J2%9UR0Sh|E~d=uH!AzSX;Fe+ z+NhkbwIMdn#CW`Omh#NJr9}>EX$3{l%G?|D~;}^&f<3u(8^i0oS1JryX=bTvALAFSW}{O2qN2UDfzlDU z3&ZsgNx29J)2IoER1-MFP#B7-buJx^&=EV&!|O~0s?nS9!h-xlwc29N&qpjKlSYSF zw3-4O(L}ITe?TDp6ch37m3$9l^)JL4OguvhEbn01%19^JJ*>b6JS+#Im)P=Yp6esi$rpIx}MbJ1zXtZj*4#!ZO zaw~`N^fT!jYE?-hg~3JG7;qFv^(3Q#^oUvm;W`Y3aEd@640q$Cj>O!gOQVD(ig37d zp6R5BNNUgU_UUX$ho{rU_@$BJrP)#7ubq|VF2+9BVUgB>fq{LUySf2D?y{Qm9igsY zx3_IRgN!ow4h-}jIOpQsRJJK?UC=?6Mvx9J;F@;a+2+2oO1 zzFu|8wr5WPm{rl>cBR_o?VslQ;wJ2+GX8Bz5(}ap-f{vhE4e9VYWf%j&fiQpdyJY` zOU$$%*xg^6bf)SndlFoK{Crc!jXgK~$GZ9)*^TqA3itBjoK&zWy7utr?zXq&2mdHJ zxxBe<)8);DE#u-x^glR%B{nZXFAt4KzbMW(T^ftZpO_NMM+YaZPEL9#-!QKd(N3|?l$+N920Vr zFP%*C{FK(bA_hDPFNyz4eOL>;GC6hA)+a3)7y5K@qDQ2c_;&$X6VUwqHlTK-%;Ou| zfQ)WaC?*2STDRRjQ@UF=ry+4_IhW8oL3Dfqsm|GNR+p#JT(`^_Q)>Mgd}BGEQg`r! zhDCXn)?hKFtqTFdw>`ZNj>NZL+dsWDkQU`!d}o1jBL$*qqDNK!5nhZ?zPej}$m- F{{s^?M>YTe literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_13.png b/assets/dolphin/external/L2_Dj_128x64/frame_13.png new file mode 100644 index 0000000000000000000000000000000000000000..1b1017ce259d7b511bfb2d6c565cbe8350ca929f GIT binary patch literal 1654 zcmaJ?dr;GM98X(TD+i*^sccSTIXtJPP1CeZdK6j-NN*H-(8=R)Gfh$`&?cmT7Iu#6 zx%0&-6BVc898TSx;Hg99oDZhsd~ABCi0_-5!tmxD+t_?;Se62H{^6NR^85Y1`F_6N z&-Zm%ZO>W|8~t`P006Pp3?f@xgW_XW$i#P#V!cgV;)S$4A%}Gdev)SZ3(Yzi(CQ(J zm~4imtIE$aNdO>Q>2~A^dA3X=#d=g^SVtA`a3UH2l2QU3NtH4J=wyoAUX!x_+fz!= zO`DXtIvZ@`Qki0RMm5jmRA)J;>QV})l_|+!Qotx0@Gt@i20Ue6pD|!k4%;<~`>CoRG!Tarm{Q(;wl)TU|0hha1{k3FzQ5T#x)N_U_`5i5%GpJh*5(Y5fmJ~ zl%hwTb{VsY^ihA}$)qe61kR{d`~7~EU#nvIBDDs`@vsd9fkX|+SLGGR0Oa*0L@W@D zkK)~&;AXvG*dpmmSS)Z_YN}Qb zr|GowF<2YHTD?Aj^ioX3w_Ef*iq*dsYfR-CQeb%p%a%nt!CuS?tgo2mKm=8x;A|U7 zxxHb@d*LdL1Who!yON>PdDa6Cr`hO!1qGK*t4Ex$6GAZD0HFp9gPb^xLAX|@G3YTA z!6=t<6i>gDzL8cHC1My{gpCnHFvLJITF3xvv=F985eTDj7(y`@M(Rn_MLM-gwMbDN z?wpr8DIyZvGrWB<8{*-`bTM9Wq ztw&pOz2Czz1pefd5QH{lj9a@_|D7_VI224w&N(ydvp>vR>5|1K zPA)D6LQyN|o{oI!{$+p9>*{yNexKO+bO$#6cz(h~cv^Ew5882L_OS=V(n-Lf-uP9a zRbc!50(0nn-M!Ymi<&N-Q0&rVOg;Hi_d%D=UK^8d?5nsUZV&00oqu@dl6=44_kExD zKJR_sOUjLz^FGOa40A zApvPyvSe9;0XDePCc(98qBlk|m?0vJ6Hrjqy+*E`=d049h_kF15l4j9L&IWuFToFrtvb2zNtrL@h_v z2nvo}63(N?W>=et^f7i0Y}cQ9lj!B~r&l#A69$r5fy zYNKsxs}jd7D5io)s|ANpg&c=SIgUY;6-7|F(xSA%wy>QS;W4=i!L>wcda5>EF4qxS zEv!pRQz&6wf+7`z6=AI2)#^x1Qws?O#M!Xq?%Z%IiyVW>>^H#9CtWE2;BZHH%gY{ax9> zC)HKLoj@ynAyGVdW}pYi-+d>lv*q>s_e8*!d-?!-{^s#Mkx@3S4ghlgou8e}8w!e( zo|e7I+wsUVyr^6^#C3}9o~_>}zP;?9_57YcelI$Alo{-4NMmufIf zueUd?-I3BUNI+E6Kz>!b)aW;L$IX)5-hF!t0+qd*p?LS1!jfsT z?gkSAZId@$l73gx`nIv0f9xsCyL*^Th_Kfh9_(zX<2iyA9m3NwRBY6_*jWKz*%zXtfZu9Xi~;@8j}*ap0E4 r14aC?w7aOMg&+C!?=^uYKr=29SRN~Sr=Tku5B(POx=f-uHE-R2HCSU* literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_15.png b/assets/dolphin/external/L2_Dj_128x64/frame_15.png new file mode 100644 index 0000000000000000000000000000000000000000..9b796498c0c48c2c9125e98dbfea9c0c812345ef GIT binary patch literal 1344 zcmaJ>YfKzf6rKgPB1nVPmPk@M9co&mv-4zjX2KR0cA?vJaiwdam25kYyD))yI5V&d z{%}KUjP(aL#-t@ptfo~HZSg^DLSwYs z@0s(R^PO|gnb#6+trca}We9>)#P&qmq0GUjv9uVz7fMIsP(0yAJKgf-Jl&v>fno4Ks|yKzp5oW-Ol(vQ8D#^M^_8p1m2;$+-v20hxIAsg%;YD+3Zy^5e>4ZG3$tOyDo8(r(j?6gBn@wzqD6`oX%=0* zFc{HR(_(w1Wi=k$g|HsiwM2r*WHNya6EN*=f)WJ5^Fh-%w7{J~!@?YQmWe;VsrJIO%{ z5beM*`)viDNxHTGhV^@JAkPr85udd+cra35#8moqV7ReJ2!me&s-}txC-5@M2XRS} z1)OCl0hcI&$AQAqEXB#3N~#4v>*0ASNDJXeOG{I@g`%R7aF~oXH!~a=tz(*ak||(g zhT}?x0t&G;7<&~PeIQnBwt?iDcG5Ka3Z0PXFntSWt`@PAkGGP9+w4`#|5U23UWM4^GX_9#jE#~Z>3eC z2Bu*Z*oZvM(?JO^c#xzRoaa~?=M{m(Sw786oW!OjnZXE1k?=a_zD_ErV0(JYwb_81 zwdn!|94Q;l&SPbN`~>H2Lt9@`cUJ=oZ-7!G~sv4Z*RGdpLt(;QFk`(M1HN3K3S3x z?h*foSF4IX?k2lNh@xByx$Xb`^^t|eft<`8dnruc+pu@~*vV4j;ATZxtVWa@+h?~b zAKm-(&eCFaY&_K3@Yn9CrTJH8o$=WevIB~D-@hQ>q4&yD>PQtJ6~on$xmA#|9Td*{sg zzVn@P&v~ypxqrvDC$|9rc9cu`8d*E!$qXjQ``X|_g)C1*g{kO(XGJX(V30LE9aCio zHE<0hbMEK`JO)7Gq+OqirYaMf;W;ddeb~0+6Epy0>9&uIX&g~HZrE;${`1RoG-aD9 z`nAytU-5IeX_w{$d|-aEZp=>`(4^C^P-AV45I8tORNI+xL#>^n*LXFukIfuSt+_>$k#Zo)oQUViS>d8CqM{e4pC%?2NTY@5o$ATIMQRt9rDs^R}-Z0a4>=X}i7aOlkj200UJ zqz5MTdvKuGk*LvL4Qz5SXeRF&vkrEnay~_qKdfn+nxQ~dm(?VL3>`AEBtQlUP-U2{M}m zxqGNOQ7@2nb#?X3Pam(4-PLkFTW|mT$CYn}&QseH)w`?5=P&=b=aZ!$sL6>UOx}E? ze`{Z3VDQ4?q0HHi+qZJ!SMYAf&9*X!GiMjm)XTRaej`)8)PMSg+Ye_-nOl!u1k1Ru zZ-4*Z>EFQa{^vT4Q^$6_4{FQC<*#3o|8x3-qRjV+yf zhlH=c+dVen?|J(B1@P>hcfzX&hlV?U{WG}u`Ri{dmbV-{HVi&{Jo7>NE_-Fyjpr|2 zTL4D}sArCE_upE&xcB$dO&9!q{oi4KUt%P4Zs1<$BuIdp=XWj~{U~dZTtT@onO_<| Ga^gRXW|=zx literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_17.png b/assets/dolphin/external/L2_Dj_128x64/frame_17.png new file mode 100644 index 0000000000000000000000000000000000000000..80863f0b6935ebcdc353deb69a6b5cf4d0c4d4ad GIT binary patch literal 1292 zcmaJ>Z)n_P7|*p`cWu3O-I%%|8ZwZ%HJ9W~E|~=*oE27&jfM8X;EgN@(wi zDFRHO&Nw4+p4zXX5s%dHq>@&r(Imqp;?XFbh{af*PK4M&fo7Z7lEZ|nc-Xltt%@l=YD+WXAJXoq~g(Bb#dwD4_l7W{^N3W<Y-MP88j#+;%e)*wV`r+Q!^6&d*!PZ}nesb;Ey{|`4O@H^E zwHM}3|8eWz{nxu@dbl(Br3>c^cWWQC9SPidt0z+1Om{ACD`0t~x literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_18.png b/assets/dolphin/external/L2_Dj_128x64/frame_18.png new file mode 100644 index 0000000000000000000000000000000000000000..b4527bc83306f43a5ee138258cee037f073fc276 GIT binary patch literal 1498 zcmaJ>eM}Q)7(YLT(BKS}%sFwKrxQi5z1|(yyK05P6{u2HDwz#iNUwKqrGxfrd(wiN zAY_|n6Py#qaEfMbnr%AgK25WY$!21Mf-VjlpaCyX1T^fe@dXWGBQ|2!0QYgR z7DGo=lxib3O3Goip#^dPpqz%lMS{?wdQKw}Btg4K3Ah)cBtcSIf`m7&BMmy*K+@>g zg+Y%2$!)Ong=7BU$%s`cir=8shC(4th|4_zi1?nWDpsS zbzthUYjF! zJ!ooAEOw&kjOXCQo_C2$%VzKGJoEUBtn&x9RIa)DMYM7aUUU0Y^QGvtTSLg&vU6!^ z{++SANb5iY&t7?~x%I><=e0@da~Vs({*6dauBCBc>iCE~{bWPu9_G)#w$8D3u?^8} z5;gEaws7OvD_c{X!M4jcGEf61uzU4P(c1+xUtGHxu`v_`q=u$!{_=IJkz2(knwig z6h78eu)lN_-H>XH|;_$zl))tN7eM7a0-Bp>eLkt1+uU36$^2gP&KbYYU7z=K$u}3bzxu<>2}iPRUG>i&yV>qE zty5pWx9h`c7rKWdEek&_t9zks#p`A7AoiIr+mkox+tV*auj!lLyw|$CV#l<9qT?d! zEw!PeeV>Jn4}NTQmMOOJ!?m_4hiYfFWZsFC_Wz3{Qw_yId-t_X`N+V~)hUtwjl+jh fpD?dzxRuq7Ftbvw?pm70#Q(Myb1AeM}Q)7{6L71%}|q+!x!9b1`bX-Y4zdg~Cc(5JREXIvaJ9>)ll@&|Ym%sYDTR z@e>ExG@5M$wq;_(sTs`g1q{okZlXA|S>iI6snacf42>93ySG4{e;6-!_rC9Q&+mDD z&)02qmKLR_zM2X_PtFEp#R8s~ev;-qqmW|sWNfcOAW5wPLPLNX`}Uu9E-Wqv837Te4S_+k)ckrRw8!3%OAE}0&$ z(n!!YDI_nK#KMr`hlkV5$<7x$th!m>XH5Q9~8EyFuf;5B0Hj6vb|I?1+6MA61 zEgFkm@9msAZ&7B|`F?9gv)Yn2-uc$I@UHDui`z6?AJ^8$wB7QfF6hD!*1O6{H1mz_ zar)iA&;Dx5*korxTFMKn)P;-f`=d(e z#O`;Rq}G9!B>tPc1<=Rq|9M!HetWZSP4WfU)mt~VydGBFcP3sNbC#HulzYyuJ}>OK*P?A$+w^zl{m##_S|{h8YpGlGerECpU9LWQ z^F-Ex8OaSVXQrJyoqg#j_IjPQuHC=!;Pu`;QMPsFwSlH1f2@V9gF`OSb1A3cs%QFp zLzUdw+Qq9s+PCt+vG20(k15%DweRM;$&-%T9%NiOtX-#@v-JF})G_VLyF1}%W7ChN zyZ2PC(KOvC>KBkh(;!#2(z|Kbj2+r7y1q^M*=2wA8SnM&>^XKZz2^4m`Tu^}IPL~D z)Ux@=oNagd$yF(O#?Jd_L_66A z(``)H1i8)W?o`l$;`xCff*{+e%*{XvL3(r&00N`GxS7$Prs$>aC8+e3Mhi5aGSTq1cudta2GM{2V4V9xe#&CyP+qs}# z8^g_rQo$-y0+p*zDmGJVi&NBOaXyJ_xhrD9Xq$vJV4xTRv>6JF7Ktr}J7rhG?ww*j z7o1XI@?*Huq%u{hU;=HXK%56dBn%5cG0r1l1Qu!#Ev1VD5g0-FFv8xD0FelU5=02j zTwK|(FM7{Z2sQt$f?M(k*qfB*}@P7GMX$hP)0^6i{Y|gcv`(y zLW*!qBgDiIL27VFhzf9s5a1X@kwQc$5NSkOSnIO$I=mttjfzvq6^i&cxj-P7#l^w$ zgalLs%cIbE3`Sj8rP0C=Mv`***0a86u<|!zB?)GVU}&?NrVCu1keW*~v?Z4|fryYN z1jAJXsW&<$%biu44q8T;^&2Uz!b}^$sWeOUuc4reLPdxM)<6h`iy@&H!ypZ=#ULDw z5{N~Z5Wz?tcLuM0C4JMa%1YQUOfEJO48agFL7|Ws7N8I&5+V>r;xHt{bQmEbggQcl za``MpzO!>)=_HqkZBOU+&8o@<*e9XkU%I80_j%HZ(V(#$pfqDB-95I6!p}Zx`|V-di>IA`JoQ?{ z?-X~gauf~6MrQY?^^|%y+wUA+=%Bl+X4SOKsrI?FY+U77eL84-cy&egngcaFAb_*v z^35%~fx6-Rz>&nlLoE?NvLkW5N7cz}u1E7T^TT%n!W_r%yWhGr(s8CwD(zLb6*b(F^Xy8Fzc>7>?8EUV^Ur3lQjDJTa7_F~PX>HB5Jd_csxO4F`nCSq4sd;QtidVYgB&M?yl+XQ0}gj{;)o!eY0)2>0t7WuzyV1 zPi)V5RXxGIR^Nf%^ky_H8n46P=>8VeV zmhElv2o{Xy9o>-GceGmFAD&!3R_dz_4?BON;A&l$-!Ai$?GerP`|XLBt@S2pgX~mc zmd~MxqGK&7zs}l<4sQDD&&KY3DPnZl`To|fU%nnFKK65H+`8bJBb?i3t{gASE7`I2 ztxCn?qx)m$ds%hH_wwF_db+m(mF^k-)zA4HPhjOE@7@FZJLWt8C`x&XtT8@&>wjET BgtY(w literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_20.png b/assets/dolphin/external/L2_Dj_128x64/frame_20.png new file mode 100644 index 0000000000000000000000000000000000000000..f63904f29b2f44112bcec74fe738a623b2d9f1c8 GIT binary patch literal 1698 zcmaJ?dr;GM91joWAtK1;K-?K3r>LY&)6k}cN=r+z&LYE3!P|s1O&^0cr46(KL#|9- zn};{2r`s5cn~F}y&BIgY1|lfp&f()w<_XGl^9eqVbHYiN0(Ji3Etll?`+f8Me7~RX z>r#`Eo;EXhZZH4P$O!qoHCl07u%@S#pxQdIFA(RpyXv>l2gnYFjEWxI?eeOyVxm#ChUsYy+_Q2 zzzG#5PXbMn%2H>5a@t0LA`SwR2*Lw}A`Xe52&P4Kls+Cr5tPqGQ1*s-sF;U|Q4E~A zAl9Qzrx#}`lvDoLlLRs{j8)9#Ivfs;gU_LD1};w|5_xQ(D9mcW_6-(>aKaY*0|#Jld{u=Hj=H0et{Rv=I{RiTNol=L6e1M%EG7=5{Ui6(V28& zQXs;$7%qefQY(TnK2HP_JP{64B!*%o<-AG$O6ysoE zoSGm_7LR1Hr%IDSD=3?(h|(!-v>BX8v)J?o3i<@T0M#N|7{x_G7!%?+tQF~SSj11@ z2?aQY;-ns$!s}j3-(;(@5;hF0myH-laa2f9d{~I^_%JTOP#7mg2#n!+oDdM0p3w3k zE=!T?>73U($tz;p)3bdw8|>lLbWs*|q-^Z$Sax10Vdrjo#!5{pySm-(@B12V0Dy0U zN+HuY|LDjLvUDJU^W5&shfb(Mc97N&&EKt1yG}dtkoa=q$2;L=4PA!F!QPzKvZ8Hc zrBR_SpW&_dKk+HQveD;pf6U9hM8~c31N5$es%9uKE;mrxxX~JhxoUm-$0K8BC?WaH z)pfaJbr(-ss~u~ul_U3BOmT+&y~w&!V_^I6`_WRVaZ{jlJg8}-czauB{Gzz#x^P27 z-8va<4hU=7bTs*MS{WV`8VVDQp}l98`YS@nfG-OL&Byx+D}LQPXWHXE@ag7Rzl&am zjXvFe?^MsK`m>8Gm9x_;G*tV-871A4S+Z}}3dkFW3huX8G+p?L7tyOpdlXa~o}Z}s z=9&A#7fU{#QPocYj=_0PvxevOJdGbZV%_&}=gI3ML62R&)y0{;Ys@30f9EwGuwS}+ zMRos@uG*sU)`~L>qQuXs9DPxGg_4ZT_jGno4_4gL?1T*uNv>&o=k{Rr+GRuF`2GEoX$eX;jmbqa)9i>YV9q z(A{mL>RW$~Uca<&%sUtm1R#hl@4Frf3s6%T<53TGiW?9wj})A>}Aon4&N`}L>w58Jsjn05N)j;9{8cm aKN6?|A`4=UbUyd|HB_nTio+?nu73e(FMSmN literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_21.png b/assets/dolphin/external/L2_Dj_128x64/frame_21.png new file mode 100644 index 0000000000000000000000000000000000000000..076448fa940b42f0740c62feeb1943e00616371f GIT binary patch literal 1665 zcmaJ?c~BE)6kotbz=O_+tyqsGqP55-dnMVd1PBBKAs8W5v>j!$*+2-%#?4{^s6(mX zF)gOmv6Sji4=T0}W(4VBhoYk3RmXx>@MzFt$I&S`)3H>ebOXfthtr+i{l4$*`@Q#j z*X%Z3_L3>#Gs6J@n39pM$r08H;YkV&5#9r#JG8saj+#EE!4y`F8~(u_y3OkiUJ#Q8D|y>LltXSy2Q%Z_zaCoEPRm|%|?=z zD+vQmC?JY9C?Om}ln{j|35cO_6i4I+xe+!7?7RxE(WD>*f@so`)oBQls!^-q)RYuV z4yVenWCF$l*bJM4r))G6@NE`+k7HB*7fYsa48^mYo@I*zouDgZdDc};o2?Golrq|4H$3hT(oNJDS^EdU7Kl%Y}U zU40#^dbtj8a`W?%LyH%`6}ly&*VFx1gE{omDr;oyu{FcK{O{^Fb-JF$&zg8K7dr4+ z?~w=CS(C?*)wptKuE=0Xn&zI_b}E1Bg&0r5*LNmPmX~}PUNL1y=Sb7>y<1o8Y4jdw zZwI{t+h-?EjY?Yk!SuPF)76JR{zTM0i402I&`O?c{Az0W(ETd!jF?BcS1P;S-@NUT zw|O-ud+50|P~8crXXo}~y|vc>Ji+6%sFxQQYDJe*KRO238~!=9sJwO0a&JHNr24_H zf9hdKeX(DBrn+rw{q7)DO`oOcc{H+PZDZq=?CH@WXlH---V0|tkIZM~(+^a(INuw( zT4OqFQk|cX*MerlNwcD^H)tO04-2liX_40fK_NG-Md{Os%+j6hzpSY8w60E!o94c) zQ;GI%=^Nl6$i7s(j zdVXBY@C|y|hNy>;k>!u(HFk)Epp~_O|TUWV$e-xag2+53mE$H?f-@US&5NnTHw%hKG{ubHTrC$+!GWa?jx>IuR=61uGuuCUn-P(;VNI@mp(>qsi0_UI(@nS&LHE==?~46>Y3P-=bBIav+ZV(4UU$iMgUUA8-f& literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_22.png b/assets/dolphin/external/L2_Dj_128x64/frame_22.png new file mode 100644 index 0000000000000000000000000000000000000000..8651f12f8bd91d684d5943af135697e9e7d700d0 GIT binary patch literal 1809 zcmaJ?dr;GM9FMfpg1~U&alT`4t}1DhG_+|2ZJ`AVR-x9T&KGH#N)OxAHcDYbD|!NR zDpSun>vN~>oKBs}eBcH?PQ|I9PCZbZcy@=6gQ@rcL6#~w|M1Ku`Tc(1d_Ujs=li;p zWll;94;>f^06@5Ig2uqDUhYu|dEDDCT&3rh0j$=Jr~4z zbXlxQgC@1dA9qTEa#_}?lt}XP^Tqj6G2@yeK@|!`zy^lFoCfSJaImBYcDUnuEof*r z<+3?h8{+^27D+QRpG|@|wr|6*JN5c^h8^ynWN~Secu1!N6(bV6JrLU)Z8vM6|EKXm zZMU(&NlOg0o0;#TxSCkwdcj=&KJF->$gxpQcG-5HL;Q7>>%!G7DnqweumoMw5aPD2Apct5Z=_t5K^FZAyw% zhG-L{$pj+p#p)bxmUK{buWuXYy9bMW6st^e(Im^bj0`ikw-YjR8J2P9GENY~#W*O^ zla$R7kc21&&+GSfnTT)$&9ek5!rR@V0tO-&XW=6~~MkwSkE++`stgsNULYjce zWdx29lojg1Ti#3G+g9ZyTo}$?HcA2`FgZy}VL5_IVM2yuFhMC07$>X*DI;+!X_i6~ zj-n*cIq!8+uZU~U!1mp2aEEu(MLW2Wa&fcMYI2R_<}NsMqEXAO-QC?g>bEp+YX!u9OJ&N0#opWU_y|KR&zITY9Ip_V0eMJ9@lr5#9y+=*fn)byNzk7lC0BorAn|VQRv$u&DmcOnOTTQ7J>G zhekI#=Dnzt+{!u@RNbtPSw2{-EV#in0n@Srpi{@2x@pMC8^Ydx{vsjItU&pdSwt-PK6 zS#91uzkh93W838TKX{SGFAjy2XD+JPiNxPi?ZGqDUD3RhoxbRnlB(asvjpeDc{lUj zv5%xHy?x|)qk^-W_*<2p^{;2$-gaQ!6ID$GPfH)q{0bT(hl$$bfOqq}+0Tj_59@Bl zjU9S4v>`9m{LA*Tk~ZfPzb;+?y6=^15A7P(rRI$glsD#HWVeqmsb4sALi%jlynp4V za<~K7N`<9QE9(ZzJC96RKl(Ud6*}uwwpg@c)ssK#D^c&&(jToVK{cst%vzNZeD3QV zg(0gJjm|w`l%o{tsyvoy!0K literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_23.png b/assets/dolphin/external/L2_Dj_128x64/frame_23.png new file mode 100644 index 0000000000000000000000000000000000000000..d2d8e7e5144697f5932a8e920d673c29de730372 GIT binary patch literal 1775 zcmaJ?dsNeA6pz&j7MvoYMe!I5Dr}}r(om8}kw>Xisk~nfkECfT9ki)!kb=j7xD8aC z98sLQDNNBRzEBxc(BeT*!8zt@o6Z9WPKIoXZWA|;E=6$u;V~!4_kB0_ckl1MPS!>* znm<-JMF;@ESapOlmS6MvC)jx;|Gw+IQNu5uTzE1U$LhIk%EAC4I#$boY9qCbiDf8V z&hm>)AOMUkG{h%!$(l%#W{nccp(C*w%{&?a0_WMx6rI6vpq5!?Fe$_j>g;0Bpi_vG z{57z~9LA&@B62NET<)THIyZwRbmDnIV4#iU4Hy}Y0&T`jla;h7#DjK8e(w-V#o(X{ zm!S~9B$cd*2E$kj0}>J#qG1>T0|*HXqcEmLb&P%vh{C8$3ZwiDAt;GpB#MDUmzeix z(do%prE16@e^Q9kInGQ&$8HUlU(Y!KjvJNGSPn*<6nWcyXmKu$Y*ao$&TrBfHjW=pr z<8#c6G?uZlSr(eFiQan{%;)dzjvR_S8#2mb;0r@#Dp@+q$e1{_QX%HQNOT4rNy`ab zi{SwfMQaHNlOY5|Ap{OFG=^e`Tr1bXx?wwS!Yh?w2#%oss?ZP>f`ltWLg4VQFqs?< z_m_p@uxuEsHd#5!L^H#_4ZQCmEcR9`8D?Q9jr>kvr}V;Y2@c_baZ5VIKRGl@uKqQUAF;1(5F_0 z#M^Gxr>r+M!p_~#U+mk*WMy_Ve7>g&Giat+e_b9p2MucYtMLBx#}m6+AJq1@rWQOk zugaFBJfAwZcgvHgAIC+vA|ujMa-*JYTzZ~ZAIla6Kb=!QvD>uk;^awgBGI=y zi^lj=8;;$-=i)WWUN&X2M|EQLqWZ_joT1en=hE)~5*ZkBo-1j({CDYEdl+4qme*0T z#3$z7=DSgu3gp`8Sg%>v(!JWN?;SN-7d8Rg6VTcHZhldb_N0wBT*J!CPMmYn`%E0A zDxN9Ln6_)vchjA^Dy|7dWmZ9AZovpb+VsiAmFI&V4qR4~Qjbdd`_qMmU;CUYT~oE- z>B9lfTTQnHeiH52ay@u={o(O(Er*(wY8)yRt9<*uX`UeL$$58i?=f<8acYVxe~;>< zJLUQDRy*fXywp3dc%1+PQrWW}8RGC`*ApTRJH5Abstihw*}dKhtfTvd3=4=pY)nc0 zbH5oF?_1e56}W<}My>>Rl(vtAPqoz5_4$>TUea%~f5rqBc;%1T+1Q)rm7<^DRTs3U zB~Fkq-s8Bi8FM*UFI=ctIgpU_t}q?kR5Xz4CslQ!?&)|jU% z7oG+hl01P~J?Gr>>s=eT6-OT}c{aTYsF?rH{_2>(t?frwGc#{Y+t1aO^vnPT?r>V!jYxL0%?X@U^8Rn^mmX{4IxE}-zSoP& zy}Kp@Uo@%H%Upq-8oX9dT`bygb?JOJKhUeMBIE~~d+^P13EKtNfNrPXHwb!#`Q294 zX3{>PyiHJ78{^yDwk5C46+CILikyN1&rT&4v^vWVK*8kk;KaohZSQtPjOaX6a75s9 yvUy!}=USJNI%3t#4?5Nq2z<^=`zm1bJb^14=IVc=Yf@ysZb_a9ICv+}Yjl``*6ad%t(hu85DD z=IcGmo5$n%YGPG7Zq4N$1%D9t{*%8}%Pj${I)R-+g-D@v6k*I< z)JTQ%c!P?~`UEyXJ6%T776IYX5jZV24$b3*M>=f;nMSdIfl4u3lrIAu27#RVCJ7t^!3&j$E(~@qr%baqs*RG7)yTn2e=v86U z1*F#~F(Oj7_9MnysxI^*@bwYTNah zHcF_Y?6iX+xtf@Q2f$qZ-tWkz$gz>lV9Z=$h;$WAIxLix)u`kk_eEed8)c+eiW@Lo z0uiJ^3SlBd3K57DhbR(5F+^+-8)4&sop<5YF>shTDjJT7QpO;NTBTIN>gZ^Z7*>ag zqHtI=fYn&-EMX<70pDiMcONz?=Dk>1G(!?j!Fnh1W8~-1mR)~g>X^|Ll|zt2{D102!jX|aukKG z&Uveo21HzYy0&j-gFC#LF3QS{6vNF<2YSrO&7EibbiJBedwP0yUMy?p@!T(IR7$huUd5+gHGv&pc0Q~_ z;GiGxlt0|!@dZD>E{Li)c5jK!DxMTJ6S4V?_s~sv>9OJ{e>Ac&8C0xX>%R>C+S_yX z;a{`o#BWINf-hhWpC?Tlx2Fpt|0vd-xF4MuTiC2w*?c4CK$OkmxowLcx8G{s z;t_gSH@xA8RCvJ&~N&egMHju_DHv%X1{FDt3L!3`k~ZW^vJt^ZURI^F$C%=JVnrF6O6CW8lkV#RB7FVlJo~DCSj3Lp8D2hT#;niWp0_Yqz*n6dKDZ<) zY_kt~Rxy9a;=9MMOC}^g_7vrA_eyO*-0u4}PILtA4qvDqJgVcHyzTb9=y86ED)r~5 zM+~0Y)eU>ZW^XC_DJ-#dX3>PbUf(*9qLO{GrMuQAZK`YixTPuW$dG`%xw>>O{pj*Q z^CHiXxgPp!MUBHwU5OaAbL5aStBNm;E%@s|#(vD}@UG((a^<8rV(TF06p+O4DXc50 zuR_;OezvZ@w9XmG3n;$Y_Ce{Bk(t4d97{I0hh!hz?|(tko<4Q{kkp2~f%kWZOc~6p ziBWhQ8#-rb?1S64_~1-M)mYyf>)cj@S-{;uyFNc?GvzcO2XDW zzBPT3J+~>t{g>8?Imv{g^hB{k+2#{6-InQ@wblKGoF`agjBHf)fPRuSuZFr^EGztX z)_K1m6gQuZux0pM@l(8*IIUV(5_D|Gxbn+mtNAUv?=*RSXa8t{6T2J#q;(e%U(3{Y m9xdPYnpbYGA+s`o6VAJ76ODEz(@cAr<7@t&1M4ul8wm%fm%$l z9j#N_3|3pmTD-8eQ#%wD9kBw%dbKi&P8E@3)QY0@Xi>o{-Edg{aNOD5@B7}q-+RAz z&3>AlnHmxl83X_bNl#Pf@T-%5k^_AB_g?{D==fzer^)AXStD0P*%+WSuzChcH&ew- z4nrBLmz`h|0PtC5%FE~Sbr~ehnuU}{N9ZtHc{BhCNe(MTmoXfqXNpZ01$?Kq4Tekx z1^iB&4%JyzOo=J2#>V8#`vgYhxg}5JhMd6+<$)kVY{S*JB387z<%2CJ~_+e5o4t;1Z6rk|I%6Rh6(xB4lmFBC%X9_t?NNgx5gq)fSF&AQt<)DGO@G zPTNdY&cs?Ek3~w)R&WZKXFCyw*{ah$H*B#_CW}v-$U#{}Vj(Irn?13OYumXT=6@P5 z)wbtVTNzOfV`nRDG+z_ryeTlBzgIi*DDrH`ESrfh3{|dX=?XJr;nLL#nExU)m<%K> zl@ofLkRcSUmm|1DEJrA@oIn^F$8fP!FEyZsDLXI2YqV&bG)0ALQQYz)P*wmg_u^|bJz+@C7L1d^{f)G+1LkL=qA~<0rC@F;-DZK<1 z@f1a#&UvAerbK*udbZDJgFif`MLAU&dAg7tK02v>}lu&!24jj zTAAm#cxYpmZ6IERD|Hr$-+O z!L^tzpAQJ~bKAoMlS$Afu(kT(mydzaxQ<}Z0|I2A;9dw=9MaSoc4tY^YwfwA1_jd^#YL4}boG-Z53Ewv z6?KwVTKCmA;Fa_0f7Vm_d&@wU1Q;cKW4=XX2z9l4oyoWqVKk4^nKIy@g{Tg z(~~>>&irtaiTJIw?TqWjKXV6b%7u50+tGntEvI?`+R$2;8kTu!Z0m_?I9k~l3-5Sq p$L=z@*M-{Ao%15wAD*1Od@Y7yv0!TN{e&hCES_xAnX`@L&+UgogD zox^&B0RTE@4AErsE5|=6p+WrnL1>AdU!qy9ksZNUSug3LL8^r@(@=(;oIq#Oq$PjS zNjedLpgA^!ku~av5)@;XkO3Wu&+g>W03;^+oFtV?vyhpdU~?pipYJ~;hHRE3@#q9S zqIagz6Kz8ZT=a;7VFs!omr_~8$%CLoAHf^2(<}-3?0F71;Y$*~w@dK*fLJPq-m9>= zN#YNrjQUI{jd9VCN`k-?g2*7HNT<$vuQWuaZ!9ttg-E2K7U_!6j0>Z5W`(IzA$8-hM_!m+QDXMlEnNMiN$6iD1{0) zW4IC~DYFX3 zQZ`3G5+A72hoCjI%Ql&|q`Me9^ghjm?K2dt333H$M$9mZtCTRN#BtcHvf!{vo*+{y za16yMtGEqs`6PWGT9udZVL02_5IBmXN|KhtN<=1yaRr9LIHf{h47cK>g2b$(SuU3H z6s3XA`J|KDMSOb(wjXDMKYW}n+QE;Mi=UnGT^(io+=XNgHE8*@wY9bCTE$I%NaHdz zsRm!e&J`DyJwigY*IHZayv3Il{%M&{Uulm&m^l`@pYr?aDTkY;Ha~jqY3Wn=Ze6pb zk-p!-xje0<#nyCsP6TMU|8kJ?@#?e5x5icYe&T9d$iIdLKRL9QdsBKY*K@dh(YdJJ zhoXR_E@DFRz^1|7-WbW9lRO)VD!bkaW};NkyzobD{6~nuA=6(n+3^DG=yDRtxO7ug*Rn5A+zUe!9 zWGCM90-U0_7Hj}8->z(q_h((2C2v}66dH86pn84SK|&r}-%tkhQRjsV#F+w9g8$Ln zVauo90TEo0Kpm4L;?4+&vHjJN0!8=+a7Faz!dFE6cffvY|LwYw<3;ijT(4;>f+{;6 zsO~=58O!1O7J>YQveFvpv@>Q}T=d4!t&=zFk7)N_0#!jmZunXK&Ek#$j90)@9xOcZSN}Sdc#9?%Z_mYI*m$+hWi3Swj_(Vk^b8($WtJZwBL^+h;%w`UZ*w4iU5 yGFN08BYf;tn8$_B*jzjYJUzoFv|1P3+QkHP*F=sS+q}rY?<+$)OtV#On*JZ+TCjKk literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_27.png b/assets/dolphin/external/L2_Dj_128x64/frame_27.png new file mode 100644 index 0000000000000000000000000000000000000000..39ddf46ab3bd195b3e75567a3f91021720c9e1c8 GIT binary patch literal 1759 zcmaJ?Yfuwc6ut?F6yJ_u#Ti)_P*gVAM@Tl&Ktd8El^|j&R7KfrHY7^2Fz> zAERxp7ObESZGB4_6_i?VtbzkoYIQ`bwQ3cgsN;yWDs+Qj{o%N?yZ7F+=R4;+ui4_X z)X4)v!b1Q61N6z-bbj^mk19BTf8PvVXW*9+oGz1_&RRGRMsYbcQl7 zTyTn+1VF$Fn=zBiG^8kK)-Iy_IwG&#$)f?7l;Cwz^n8YcOiYf=p@bjS*1?d?tb{Y- z45-1WVXU^~0v9vAAk|10%%|mMI3XUIVcP3)zdVoZdJ?RI}`-P&$0o%x@}JGI@$ zg-%AC&bZk;7tPni64?vp^Y?y7enp;*Vyer=7lz8!vUHxEad3LA66U{%%r>)vmdZ(! zgp?r^ZIUAr0+S;YCMOYwmf#XhYLc2!bFZCu;ggaQF||%jBqgeoFifXat5KasLr76w z9Fa((L@!qFaC4M{W_o?wc;7u({JmI(#>G$^>oT%zZf_@~Sy_&CTUjTBOGFYV#z4_F zhhH+zU!~VUYZ;diCt*D{4EarWMB?Pd|_X z(!kwm2liYT0v~BwvQ`t(mU2dLdw02U^|SUFq6%q5!o3^feTzR8Zhd$(y1lLi6K}B= z=D(EwF!$o3zN+w!E!%ep+M@-x@zzN4`dTxHJNEqWk-OW7$;P0Sv_^L4W0Jc{QPVBsFpFVzBq>H-D=J4n9;Jnl0}% z1NV!Q+g56vM$O{kF9Uq{hs67C6vnG|bQXZ!{rscSDsu8qQ?FWxczOczZUGoKjse-7sMnTQ0(YR0*4wk;U(q~Fg&DqM*;>`mg;ouFG z-oeo2*|{Kp9rZ%6aI8bCI?=JFI=XS@cG<5{;KzVr^=02?#f3i@ZEelKP+Rhi{zb<@ z`||NZ)%k>s5==OFO(GpqUk84PuU~X)VCAOcu6R`ivF=32g{l>w5Jm20rLW#_3;J?R z@|^Dn2`Yq8SVL#|y^pNzAT*%)j-JjAo0j#W2+XUyH*_L+YOMOKO9-m;!)r_TG{A7* zm_kGNa`lwuG3iel1M7F1moTxj!Y*x&R*?~Dd7HDPzjr)dy>oWMsf>oaTH@w~J-Ke5 zDSpSu&I~;@qkLxIFl^eM}o=7(WVhfH1qs)S1oQZV~t4wRhK}y*sGwL0eYk7f-q=zR5L@a+T0)#p!o_h07zoQc568m|kr)$qATxFuuuqCD z2t1>r*E^6|QdL|fT&ij^Oq(%O#4sGT(`FGPFj62SIrs!jV1(6z5#UB~g273KAmOA>3;ct8uMz$ z0?kp`;+JD;qb7oy1XrcNAb5;Xq2?#G|J;Ng~}pHkho2-Ntl$fGaugTEx}n2YxkD0UL5zhSr+q@mRfC?r_fqL zVb&DZ7m4Y7M3hs$72tagYr7|wDb-|NSG9nuHl#YCGNkHiETl$Zf;5xxYK|9`NK&#U zS*6*a-Lj@^l_jsHhT)ksGs-*^f`wKaAz%VZP_!K-?G%Lyv_zq_wGg-4D3YMWATo!S z?n>Wms{#oKBbs8vPy|KTdD)8EG2Dt$Hj+Rok;YJx3R1j{Cxg6TMJ#}#CD}Q5by7+M z+B3PmGaKM=XS(DF7%2_R&aayucYwJwR+a}mV4a?x?z`B18G_P|`rK?FKJw?AR|kgR zEU)vI=|1(NE$?}b-CA<_jbqMF3hK4JM_kK)8+z!`_OdIB;u&r0q4OVCyV$Y(E2j@; zO>Vos=EN>%r}LS#fwG=~!-F1Z`BY!DwZSwv(QJe#6l2ZA3&x%apYh5>=gFtq*R{QJ z(th9Ou>)z(_MI|Z|KjJI#0UPJx9iu`og;3HU7cL^K-U=ee%FHWe>d(u@p^Snq51o> z{foQWh_y#23MI%4)!Du^tlZv}(8q-wcdlu~aClr;Qd4Tmzi@wUhQZi-BE(ABxt9jt z^^Kliy?tlmZ2E!l=>ALtH}a{M>o=J8z`MPN7P958Gv^jE@Y5Lud)m8Jx^j-^I?5on zz2NV~8;pZzMsH;H8`uu$xyi4KuC-je+Li&|;@E>3a9}Mo-2GGCmYx-v`)aqc{U46s z-VF_}`2AX_pd(>2y?T+!%W|0>e7Lv&o9tz+t@Uqn)kiM;VE!!ERXz3Nru_$&P8v+{ zplijYkp-W3Bwlmor`^mhFUp(x=U8Ifq8IWi#v+u^#^ nn=?Fl^SeV|8BXJuyPeN5bB81L~h5FJCem|@tcg&F+lUB9?%E63=4vCBBTurrX&W%Szjpu)AcUV-Cd zcw=#lkid*v!c@jIalvdcx`o6z=SDPP)2PwR#kruExUh(hjWH8h1m6P=_Xpavec$)# z^ZcIQ^VJ@IW%=5yC$bO(S?k^As)B1AK4qDy@O>k*-v^gm!(C(S&_YIwr~^chwID#f zVX+QW0a0$?yC&~qq7P_%`h;Ej_MPcl5kpvxBq zJ?e6ZuX1^o{lSwRt2c}YZ?Uwrw3u6Hv!>TsNRHzY7!-v=4LsVa8e$ArqXkI>7l=x_ z5-}7_MH7f(P-`;m7-YK?MmXa0tpKahfq!YNsvQlq zMu4RXM71Vef;9;hB#mMI{@+nT5whW5&=pu1vC*YTO<|xKUY8w%U(B*1^OBWggA8lK zMJdSP3{7&lNOCL=B!*&0YtSkaauR1Xdy*yuht^4XnH`?8k3#iuh$GMTCYV=iZL^2kx!Hq zH6eLAQKhAzT|ifwf$Y(>FuIs#URi}gsF=1=K_ZA#EN8BA{^_LDD#DWhk7LI09$b5Gz_mCL{)F%mOJ|5}orv zCnZI&JrmoN*?@jSoDILzvsaM8iICpFO6#+L~7Zw)Yy*4zCAf^tlO9;e%{QcN? z_Gf73tLvs0zT0lymEOB^!zTlU+dq!&EghYa_Df@Zo1SlOyi|03bL-b3%;F`FqxhB75eX$TK?`u%+XpYvmPM`+G{c$OUKK=yUq zOFz-~>Cp*wE@OS kWlgiQ#)aE=FPFznh;lgdO7=+pfy6J->#lUY@2Kti2RHiax&QzG literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_3.png b/assets/dolphin/external/L2_Dj_128x64/frame_3.png new file mode 100644 index 0000000000000000000000000000000000000000..40d1314c95fb07190f995925e69f77df558f8cbf GIT binary patch literal 1777 zcmaJ?dsNeA6ptX!!4ySyz*i{vnx;+D7Scc`l(rV7h)@;h)TU`F9ki)QfP#v}Q*{jR zdFIq1zQHL+Jvtd4buwS`wZTzgQykzFA7ew9=wLFtRH*Y0k2y)c@4LCbdw=(JQk0TB zEzm#A9{_;BM71K7TkYHv=j+M6+kDq)xFwWTrn703k6 zxlG0afae;MHl0n^Bw++)=Ho6MzRhgq&;SrS)n>(sOp*ol z%6R>x(lsey0!5Rcln+A$3=6?%DW8B5Sgc13q;U#}z=%iyBis!M5lkq?5HUD#@i>pP z!HA_QR0ICFlZ=V0wEt3n9Z)(UTHIID)~Q+w`w!m zJS!{%gg+iqwJ|0#kB#5G5 zr9>o0VUZh~Xkl2~LXd9XCeHT&7I`NYOQ1=drD!chWw|>cC4*uqCWEqqh?p-1Cu(rQ zWN}F*xvJD3w1T8fIix{FQ)cj0nlaN`C>SN8C`1qIAq161L*i%@h4fMb3Q0v0VRRHK zMo_}Y8^9ahNMC=eauO~KtD6mmA}A7#lOiY@7K$J=N{m1#A%!6^YDDoUTx`VkBA$Sw zC~$So8=d49aqa2azMc*4@OrvP3pY|UH#>C0@?dW6yi=02N^W&Jo%?R>_!R&=IuaG} zTHEbE<_%hVAND=xbap>JwCSSv#`WJY*yHNSr8x~ruy?@aZU4qjty|%2&41}Ps)ZTS z&~SME%!2JJ+GanU&~aKNubvfj*2q3x(4}Lv!`8HnpS+}FOw~qo3sp?4yxSN6+UJI6 z72g=TXIoO>V`^=^v)M|&)ZeWeyY$Ph_Jp9F+a8cbS9pEB^t2=Ifm>A4AL0V{EP1mIw>30iOq)uLK>okRiy>lBR_MbYy7I(x7p2uiCOf!87(} zk5z|#q>DSg_b(_iyk=9Yj@Nvp&^OL;0t-6rr`t2MQ@y$I`QhH~oe^hz07hD{rf}=> z9+CXV+XsOP-|`fDw)Y&gb_S5;p(o|;L)Y>I~$)hhJ)JV4SL__$2QpOs=CTkLiU2}Zy^Ck6b=tZFpw6s>+jai0+s<# z^N0?}R1^f9de$R(`qlBW62E&tLqLxVj2K8B>;-$hl`ZNR@@)IWI8|WPqcW(p?quk`u<+*0)$>P* ziZ*rVhj^E4+BFC zJF#+Jeazt5`P9_F!lmPGhd8q@gs07T@cjKlF_)j!%eOkN?RIpXE*gHe_u|cez*Vto z|AtCQL*c}l9bcn2gFoJKY{Vd6AO4iJeTzH-fQAKrUcxWfcGpiRQJJhbB-gF{58GOv ANdN!< literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_30.png b/assets/dolphin/external/L2_Dj_128x64/frame_30.png new file mode 100644 index 0000000000000000000000000000000000000000..27c297e8d59c983d0a06ce9afafdc39064216039 GIT binary patch literal 1408 zcmaJ>YfKzf6rP0z)~)4H)TFJ3af+4#v-4zkX37ft;Mp#$+cgr4hIuVaV0YHpp}TC` zWUFb~{;1#&joKz9n$}lR5lz%I^00|sYcrp@Gh{}AEc8zbMHO( zeCK@U+;irLx1naed6OA}p!IdNZXcKv;H@;JgYPeQznpE;XP>c}<2Kk}Ak> zU65~;eKId~z4(n>4ngUM6n~T6*iKh9X;17Tj_~ z)ReHUs3ACMkr&iX-HrgZ%V7k=9?z=bP-G=pAZ=KT4`YM{$AZCRY)je^-6#J~V@>Ud zzbhd3k*Wl5o2sjkHZ=^Bw1tL?JiMrcl9Fx7 zTUrjI}Ii=#9XV0bG}2Y7)(FhCJYR?a<@loEmR zOfFY@18i2iOAdjS(m?M#)c2JN`YzME(_aPV#l^*wmrq=QAjAGTx5FR%@%PJrWWS7? zGR7|49sFy*wFU^`;UMVO|*cWakyoStc6*)cm!&`@H_nlwp zF*0}a)EyHKOdH1AzQu0*-9MH0ld-SA$%!u=fd-^IjZyKO4L24ZYPkN0@rcQlQp|;`e;wT z!GC)6s?uWge(8EM@qK>%lf7TuY&N5b(0pO#_Qxp0+f&D1r{rP@#gJW*+n|L}axNu4OzVvwe9JU;vjA4Jq zh#}s1JneAzVjwa1dMUhMYAG5>&wUl@9Nq!_S~Bo(?&b%_kdQPJ~{u%69q#* e7k@BOlQ2NG;zy>fj4vzsPpqqIaG!Rzy!0Pj5bA>f literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_31.png b/assets/dolphin/external/L2_Dj_128x64/frame_31.png new file mode 100644 index 0000000000000000000000000000000000000000..f2aefbfae2f1ed51e8e87c69f47d42b6d57b6a7b GIT binary patch literal 1404 zcmaJ>eM}o=7{6M;GCr)tk>FrEZ)%2ey-(V^la79mnw2$e<2ubUu6I|c&|bM7&=SIj zL#O|^X_h!PGEJrujL}Y)Y#B>{X)yYSiwSYr2a#kk47WJ8pu|O}Z-L_eAiLb%`@YXT zzvuZqU-zE3aZkyXXSYBQRN`)M_`uo^9*a&3-oNXPdcablI)kcT4y#?fB0*MB4oR>( z$~Q|si5FAtKT35Fq&*S|1l6EtFDJ-R1E19~B%^VFhM>CoWSkdTB^3@y&5@WHxi>bB zz!A}m?639Up156Vi8OR8lE1q#Aau71tccX_hU=0XFc6hg9!^HvVhJv3Mpo@|V4oFZ z2)wGIwwjSOQbCUww#$kHvj!X$aGZcmtU-x(r>EK~|bEf@RsP4U$BG2AW94R6dEu5<7Di98yA1 zB5^e$$Kb3*J|uUjW(2TZ3nLo$cs2~j66?tVX~U9y93u=k7L8_OTh&geKIwlNn`$Ql zsknssq=ej|2%sk6ojEYb-{T!+6#*M=pArFu;oBUt&=Hkls@q{kz!!rU5jnxgG9j8V zp}Y`cQJNxHlqXmQl?0lk31i48;$qIuW_W_atu~_xciC(>K{y>&EAF)0DI@NzrECmN z<*@EpLgizEl=B?{zSpou*JH7qU6FWIRsyozmg@v>i>%6t7C8=+w1I|qd3Yfb%Sx)V zRay($At{kgNpvZ46kbg;7ukeDxRx@KAv}bV3~NGZ6T_e(R%B3?swGTDh9(&yjI86u zN7A>}sz3t5i09aF49SotUZPMFPEaUgq)C(!SRAF9FvA;pI?RVC1OpVYZ09`ENjVW{ z&+K+%Ho#$Hx}+EwDFw{VKWD!m1anv5-5YR%HIvDFcJ1RC2-2k74r?HJ{qBhyrHAoi z`>jl7-u*^(q34H|)-!I$^|v3)QdmjBwr^+j^g&ABKi*!wKzz^OtruSZ zMSGy;>f%J|#ZQ+kC#Sv}(ZTm^d9x#M&o1&^=vdToe(FhP^oGWA(SHTH=>K3~VN5$b zxAj6^db_66(^vb1;gxhbZ|Rvoe1>0k`gvDh{^amV-Q<@mHItWCDmBH2{P3xXx$S*B zK1UWRKJmb|etJNs`{v&xi}N?DuT@&=lZ%Blf8Wth%$J_SI=_xL>EW5@ZP2ziFMkAS Zp_wY(uU8Hp3}*j_ZfB$8D_hfB{{f#7Z%Eu`7|(gm9z~0zAGWny36bgw=6~)kNj>$vJM~!4o#%}@7}WfEPlG18Cb4&l ztk+vFMKch&LrUSf)nd@y3CA|lPrLQRZ|9N zT$g%53P|eE(VL(FLAhcjPe zsHTRn!~O)7$VNb));?^3uHlZfGTg5SD%RA9HsnQUKnIS5=Jf%?7V{x&-L44tu9(Eo zbrq*Sgl&-OP9)KYX#rFqC|sc^8Vw4BLNOF4Gb+f`qYTBcB*nlRrx}svM215*FARFL z)Qp&lwr=`^rx4cXI9ZV-bGaOmV+qshC22trTpJ97Lk-*>G8`$78+J{}LKN7FrDYw> zG*H)~B%6ay2!m`l!qBsc#Fk;h-b@xu8=04~Bu!AHuDh|VYuio={7++BZ96@b1!M}? z=Afm(nq+E9V3@zBJ8~5v8}U_3gN2a>qNXya1H*|&Lm2!*sG2G&0fCn}K8Q<-EZ`hV z3%EoJJPs6&;pl)IP${)!XFEK@Mi@%)v#l*H6ivsX;V>18MA!fo^Rq2H#g?#f!*(P? z0VUrW^u38?o{AMC7LXj%N}J|DsS}cYreoTDW)@{Qf9G~H(fW&1anZ-y*k#sxfiB2ksV0*gTt=WKwt?2>= z94QOVPVM9HIXHI}$wTQFT-VmtF5VgY4M9Bh@n|@mzx&|Vxn19)zKVshe~vGK$I;6l z6vvl}+SLc+k4Eb%#Cr?K4*rH`SGM4NaiK8ze%C>7&(S(xm-*%o``E%?g=+Cuak}Qy z(JRmObdG$naIw%ja(Q745x*&GZruH4*^km2^>b`>>yhh!dzN=kTs!^lN+sIZd13mc z?~vc0y;OJQTWB0r7(Sb%F$s;dr8G7o9VeBhC3Bz5&Wzb6drellF>DqMBDQlmn+(a$OlBtT zCPcEtn&Lw!MG8f*^`TKKR;&-fQrpA}f)v3JDaKxmSV5s6_+U$*SF%trYpeqR)F-=QX|xv6(@|52-hb4bOrd437w_|Wt*n<<90cOIx12KuD35}*1EGUs0&CM+}au{6t3G>dM6VP%GwSsvTCaOBa^ zvvN9?*zku=A$-8|Y?-3+`8=8DNXzM`7)g?R8!Ss84ZWq;#p3{vWCi?&@*6pmOEhC7|WA9)|^r_!}KKw{VJ^o9fOYXI@A-6 zmBZH3EE`);$hL9^$6rxD^o%2X1l|`sM{q5##pu^^LK@*LX zgJx&^Yt=(@SKV_Y6Gv;QRGL{jcN>5}Loyc56n?pP=4Rcu*!I|gQfcwZPah92C5~nz z&-RY(taFF>?Q5*h~!hU|RSUbC_ zPgYKlVPXDM`#adv%Rip${A~B{rRfV`G5;+Rh=C39Wy>%%7E_R$fJ+XcMCjQio`US1}{KL=LZ+3!*AKu=BU2GXYFyC1WfNOfy UNHl%vIsb2!jCaRAjU1c&4=x3@iU0rr literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_34.png b/assets/dolphin/external/L2_Dj_128x64/frame_34.png new file mode 100644 index 0000000000000000000000000000000000000000..81f133ac5592569c6963b813e7eee54087a5195b GIT binary patch literal 1341 zcmaJ>YfKzf6dr^uO>wc>#DuoN>0qKnXXm-QGZVJmC+%vNlI_M4k(7DdWk;AtX9jn` zqy_t<`k(ow@g( zd%knNbM85FsIg(2ckPC?2!eQ%+v90C_rN#2rWAfJujxy{sme(-IlGLklNT+3L=-~; zXi^i~KpKcj*WPbI9fFh|R5MLZQ)-7G8=6ln==faCglGh*+v=L4+zuR60&S`u!e+<5 zz))2QVY~e)GG)d_+=< zkCu`Z(((Fbe{dJVa*ksP1d-3@eR;-bSZxHw^L)VuP2*4lx4U#lbaCCTDO!jFTeeiw zQ4Jj}SQI6r(+Oda?NS(;nM$n~*6rnF!L$*sXcCld| zWhfpODW1cD%+f3skOB&+6z!~rrM|($R-x}@Y~+DhA!Y&5F|3SXbQCM0F=sf2oij|7W_>LBbV`&}y&$PA+|p9eabT&h z0HxkCG;}e|g1QQYte*+c5-H&{#|LpX$Z@#DD;&-)_nFO2{78XwZa_kaP&;`s z^86 zSUq@pTkhoJga3XP9cY=_GmpMM7uzXC{=`}2Ir8(V-PEWZzWVV$rB99_?|#t3jSb&D zG1W6sO5ahlsJpK9YyZ!`hdtM;-btp$kBDg4~+HYXme{t=gri$nls2pT3LVj*o_N?A6hce5Fd%Q GzV;v5Zqt+i literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_35.png b/assets/dolphin/external/L2_Dj_128x64/frame_35.png new file mode 100644 index 0000000000000000000000000000000000000000..c828207d33ed6ec94a71c904597dd24b4805b3b3 GIT binary patch literal 1255 zcmaJ=U1%It6dt>whW_M5Y@;ZQ(+X8PGk1P=cV?2!-_E94%%;m`!T1t-XXftiG?|~y zOuCblYMP4L2dhGbRV)#;STGjEKd=xj6j5KaNeZtO$oFf;eg zne%<;JLjHrB0scm`<92d5CpM3JD?WuI*p&6));Tnc@?~m%q&H& zx&&h>YE9HgE>ET%50NqhXdM8KOv;Q7cpz%Lfl7Nx9`FJSczn|wuW+Kmi)7=Xa7522 zDFwB^5f6W*s7esH3d>fjRi-L1j#p+mS(YOXo~N+~?N8bP3~Afn)nrhSuY0B&n2t?G zj8JnXf)s_-uBBnQx!gLj?Kg^r%f^P#WjO}0mKEi;>g@*w^uLS^z5U{(i`WA4oe59J zXHweL1mpVMJ5c0^)hPQt6CVs5R~>!ALUxc?JlW9@lWEyg^ zL?d0~MJ}Nw3}7^QHo^-6P(`37`uq9-$7R&sUXV$rg#^gNg+2)gO>EZo18D208Qa9M z8`$_gu}a!QFmSx07njEsKIvB=dj zE9M3gN^v2t}wNUBbI7S+%zqE-u$Dv>gZA(l_taKlmb6d2eFRBM&489_+hz z;oRS%y1e+=hxU!5->~+!w`-g+9qTS^J^3%!Rd4_0{H@X1+h;c|-u(Kt>8>Yhm#FZN zPIPSkw4VL>^Sw*Z`U@RseQS$A5P8p$J+jU16A`K z2Y(-ZyuRG}QEjL#{A=d>(F2!fj?A69zV+hL^Eb*X?~Zl9v-{2p^RoC@aI~eJIOg8x U{4;a%BF>k{W`@*reFtX#193vGHUIzs literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_36.png b/assets/dolphin/external/L2_Dj_128x64/frame_36.png new file mode 100644 index 0000000000000000000000000000000000000000..fc923b40236dee851d9c3b1f60a64d0050b67350 GIT binary patch literal 1059 zcmaJ=&2G~`5O!4wRh2k$fYZvA_>ow9y>^nd)zBt!N+Z=JN+S_*Vr{P*)A|Q{OWdAN zC4@Nf25{mE55NI9@&pJZj@*#?2w|PXrH863+dDI!Z~o^^fA`__)my8QBwg=q+XHdG z6z}HBviSa4dFzPlChv~;UJ~#L&6w2k6PJNrMEBW%QUCb)ceXA`%df-Xh>x5d%S$4K zmO4rir2;KU>l;N%y#vO9%l5;#DW84*B7@Lx%8zRfa?%bPhubF^+dJ7EdM5{->B}1r zzng(Hff}|n!@>qw99ekG{Jv{)cg?c0N2#nL1#3a+G^0qFPSQg-NPJVmwRod^ZGh zzFjO9E0u}ed3UFHBKGcDe`nYg_jEe_@bmp|L4ls#8Wz9)ep^}++$orTinljQvOH(E Yze-?JTKaM0*{hQ8b$9KL?Wd>z0Hr%cDgXcg literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_4.png b/assets/dolphin/external/L2_Dj_128x64/frame_4.png new file mode 100644 index 0000000000000000000000000000000000000000..d372ff643b40c4cf27bc810fb25a3ed239535b5d GIT binary patch literal 1727 zcmaJ?c~BE)6kiBRhRdT$MX|0y8B{jeY(lcTLx4aMi4uws6;RO4W&<_xrxL@AuyCU9;nM`l^5xU6V3nUzLjT25#P7;MKG0|tsFK)WH`XvOUk&Y)eK**nBM4mhYn zr%548t5Y5Cmd0AZwNjFRMp;RV z-c0LFM$loA(3mo435Q`j6o$d9QoS*3v<@eWNgK~jn0b6I%rh7qu?=cl=~(K28t>G$ zsx!?LFP5^JGAtxh6P@1(n91M!9XS*kHu%RDJyRGWU1lOP43v>p$|M}-3s3WwtkP(u2_s33_|`MNhq0pfV(|zIMbIXT+GI)}>4cb66K%4ln#>>~m4iCG2GgPtCJ5q- zMW_%#NgZbxuYD_hL#@h4m@v#EY;Y7o5ivmtATi7rK&VKFKq!g9kPy|OgoqI82#tWl zV<_?*o%2>Fjfj}`bZpYwXXb8nOq5#AtOElB`~N6w0|4h! zN|{t`Z#k9V9^C+Y6g^v|cS*1A&?cSPF?M`c%kkols=C1J<@3kDFJ4_`ClV*XJO8+! zox!f^_vyi+_Sly-^|^R=-`s(FaNBrO*MH{L9GK+s-Q$JN>Smw6rTXpA*nNQ;8eA2X z9w*z$n~!S!{wE~ffz64j7pBc;6$59x;t87FbTPD|9L4h&xE59jLtLzJo4L-T0dTU< z-<`VZ2eW{r2_bi@XY}TG^pqRQI@~Ebj>uyfq2m5tBmo(HY z__3&Mpdz+)c+p zEi2yNr+jBFH==i9Nqyr1<@Ur!KF8FpE8{#%XU_1cJ&<0os!v`}=~>dus{scZn=&U{ z-G6S>QO@NJe`?}a#Y#JW)$b02JK8(8*vgiEOAD?=`ezsHE4nxPNQ}QUVaB8l;+-=KlMOI!zDSddDuouQvmIZjsBsC!Fjr4Os1%)+;r1jmjZSE;h9VFzIpQee$VfD z-sjnnVVoB_ar#6607CWY+AMjkke}q>0Qub?ywxBt(ULA#$`&nB3G3tmjafADpx(yj z^I1G=E-gCCCjmgfIw2=l$~7!tIMJqHy*>)J%^{-!AZf1K!E(!a2{iHff?W;WKY9WJ z1+yAjlxRQ@s5xSGJs^&CuLAV3M1W32eN?f^J)(-Nm@o&l8F$N_Vi~z?j zNRH?<)3RUk^6&70eZw@b?6|CjMn zZ&yyKgI8wpF0t6j$!B7T@qy*~y*iNBQC7pe?-b;NVGFe)S8U_$l3uHZf~8TbmoX+p|2A%tfC~ktfB+N2n7MYV_-SK z?zO~uPiZu1E$mEO*I zp_6UZqZfQKqt4>>;xjM z^8PHOwjt_zU~pS+L{S8m^zfUe#+G2q@4#fs@xV*_1Uz{|?YxsM->)fCLNVHs=M&a@PPedfEmY;l0M93#=g}bGU*!Tk%Yz zPkH-Z==ck+4_@og4?2$*o4Xe&4sOhnxVNG!>Tb1EDx=nS3GrlSf`5CEc~4!{hr^kX zU^x9pdxWr&udCkP&l&a|>i7FAB~toiO5v_W?wT5O>-PFzvFL)vnEJACzn->bHMzSj zJMlhE*tOFsD_d=Rxv8Y=*ur$n-U-=@&)0Jgn;G`AM@#g1GnzEFTS_m*9y{e9IDJQE z@wu*B$H>_quhq7MZB4Rd85gd9FC=i+uDUq#>mTz&_I2%Eqe?%tEpE!Y2T!&>uoI&hrEhO+t@MJ8-10H(1?aH75N0`nbEpTRxhfH&ZWW7d2gq>8$F!Z2WfVx#EJR z1=R<-kakt;o3lyd{!Kf|Gp6pn_T}wl=5XSpye9pUwJh&n9kBgWwI{X%Xd4dJ?Hpg* QB=;Vm*BQ0VDS4~^1HhwTkpKVy literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_6.png b/assets/dolphin/external/L2_Dj_128x64/frame_6.png new file mode 100644 index 0000000000000000000000000000000000000000..8a1e84a11eeb499fcd47e7709e166c714229afe5 GIT binary patch literal 1635 zcmaJ=e^AqQ6c4S8ilV>}0ri#@&MA;KNkf}t6#3DDJuP6V%0M^LB!voXY8s&Y5bIO~ zr^DOk+|=n#W&S+J)I%rR;ile(`iGv1%Fsid6P+R|sB>&A1?v36GneH1&CC0I-sipV zd-d6w89{+jfdBvm8D{EC;_4BfWSLZa-;y;L#U)bE=L$KTRVb%;7D!<@3kw?TR3U3( zDW+m^8=D9K(p5Hdu8?b-P12lQL3w=?Zo5-N13=;ox09laSpl@Lg*Jy){-C8*4%!&4 ze13uvHagSTBHPSLp3SMuG}D#EG{MMcB!P);QY5gm0tLG5B@P$q*2;%?NpbHrE9Kyj zi%_hU4~xn*W`k)Q&w_*khG-Z@Kn(+N*EPy2ti2%BT)<-x#VI* zp0Sc9UHV8o@k=W&5(FoyRF;>QE6P<0jxSUq1VMN?P!tk9AXkM$pxltd742itu`Zgo zIRzW%0KJTqg)0@ba#8JY8g{4A_=4Es8Yz}oHl>?#DiH;&wA;P84SBl+6Z^l6S9-h5 z6;4)ZVqIJ*Pm5<_jrM`X`n^7o*HKhMX7M)hV5kxuN0-`JhhWfY<>DU&V`E5KP2d&` z*FY3)As|eJ5DS~&#UloiUx!A7@nS*l8zvHT}le9PfJs&VSR!s z6^B(mtij)s{kM=Fz8au?v8u8 zqgP9ju?PPhytC3i&an6oM_|iWsnoQ!Ved8H)RiRFwLTtb{IOd9xANWRN1q%&P$O+p z&Z$ZYjjh#Y_&osYvfPn(PNUW4NuN#JCmd5=8#B<~pSWD==RuB^7>}U0? ze-^pyc0|_^;ND3#DokRMeAjew?(Zh)(cq6_lK)aH+|`tu0d$PnUUThoVe``JfMvL$ zYhysKS$6jQOR;AcLfHYFX#G zg7S{rX!iUdQl&Rvh$@wwlo$x$`!Ar(w#>fz^Ce%rgb znIC7HL?#z>wsa~c^jF`Cnb%%h8~a6wXM4laF(1SyZ>z(X5zAM2zV)j+)xE@=?x>f< z#4aPGC+F8U&S@)nns?!@=_ye4cFvOOkdpTFp1zJPe-;D~kKz{Xir!g$0fA3{D#O|j z3{*b6k$d%<$9vnTg0jjV=GCEwzP0*%GU~y;(C{sW^PiB0C-1C>vg-Y1*t5yg9J?!< z^IHz3|JoDsCA)5sB&zm#$htFUS`1N{d8$2gnQMKLw(tY86Y(9_4|mfmi`8s@{@kW2 zcWcA8s@+ub{WXt%o)W#U=fdT?NooG0;vA)$Z|wi6adv|&BQU?}^3nARcB*%@b;YA= zo=#P-xWBfs9}G&G8G6xftNEqHj!bpzIMwQCo!T;5rw?0osj9y-(uBHu~lm64G`-O$DQ51ch8>h zJKs6?oRx(I`6=2oEdU_JIn7=K*9d$p8Z~@h)vR*CWt8G5QD#X#rH+#YVD(BK0de}d zN})*Ly!AClged^1SBUNsrNlLz7YeNZ3Cw5MsmGXdf>N_ffL} zMfzNn>TI-MREet)u}QLkFnS#0ahyQRjGo6yobr%f!8aKpanfkONqA!f$r2PxQpmuC z!icih#}?W12I9f5Y_v*If~>(%S68R6GwLO|(m*f_6XhUD40>Rp`hdcPu|Oz2#$Xph zyetM4Q3@bYM$RMED%mJh+n;Y`YfQh(BRK^Er=-aJ|IBYkCN#b-$HWf@JR2lrqk&6qLDOw*W$@zNM$%p%Mtnj&f5 zhYsMqPnEB~RiOo@5sax}X_6+*oM6PvIAO$S6GdV)&)^tE`)JO@Q9jONL=8})A=)`l zbyCa(+cUa-G8^#Y$#e+;I8rj4owBwIHE`|{3a7graP95w-Fjx@c>v-Fr`_rfpY2+A zTRwnjmNR#IPi+wSH7(mR&fTPP>W=@B6t=9rvDk7XarE8E|NfrSdQsily-*9(?R&wY zLyMYZ@XN3=)!(}oFNpN0PO7ObBNA7F# zc($cRYq3`TwPtWA^D@SZ}{Hp*p*JkxmF!nbC{UZg!Sy#At#p1bdyYTeB{M_ zzm3`1b+1+)rXaEfYLr`J&~GMrT{YdbJLW{A=d?ovIu8t6L7&W6i`yK>f6B_2t$h#edSlFNk^|O*)s;gmhPFT ziQL<_>pgX;CjVQ`xzW(Bdl~=CYM+=sHZHgTztG%n&m7hfcYXM_Qc`zm)9}uVCrS%_ zHJ?msvu7$LIjWr%eNfY87=K%!D`HPPR0itI%H%{yo1~#lDxC#Vq|*XIopsy^X_A&4w25u71*g|? zI=0=ZL#H?9=EQBDI>$adZyw$uIQQY^>E^sCPTX{Q>U1jeYl<67fja;2%q4l>_sR2n zp5OD8*DA{9XvSoY0RU+1rBtQ7M&!q;PLSUh)N38`k|Eh#QkCG5LUe!wg{%Q4T)2tFMh)6s=}qKpQhV0KufnR-rw+?<#9TeR2r?bkv) zYtb&ucOVY2n5*MUn*&@`bD5KAu4hPAJNtR4AZ(Tm_&AA%!oCK7&>XgChwYl>eN3#^ zLc=Ojy+u1h%H^nliiH3Nkvars5Cnxxq>e!_1b1UB=gEUG1T*LnOuk_hGo!c}!=cej zD|-yE9&;sCGU`u0S+sSMB%1a5P$;Ae8FWIxt4B$ajM>02Sk{1pO@4_E!~S4a+ycb~ znE)?Jyx@mo7HPN8C|R^J+mSGQqQmjfus=AOEIDoZFfHm)9isR7VzCWt2c=5xe;SX~ z4mz7ePG89dg~k9Q*Tj<*2g~_;vZI)y%*I?E;N`;54V1t%`Z&L2rz~3ei;m@4Gh-wP zH%^#fnsJjbZa_(xMo9wZ7#zbs1qb1SSN@OhU;)>hJ$8! ze@v1StI|l&6c^x^a%@RJ@Ik|AHuI06;K?@_F*o9dF@iL~xQQTOH^~w(X~;)SMgqqO z#-km@vyY^2q*Y~!9EKQYVHGtry@HX*11CX6@+6AX#KIN>2^BaM4#w?V6yDe7aL z^GGMfMRI$_whw1RK0KT*&M%KtK%Skf(9TkM?o<`?oHltK8XEer@4bEilr}q6=nS8_ z+HT+YC8DNw4Ayl0I=2AIj;=a3dD(_lzU~euwCYlq^-#*V%{kq7lfsJo3UTpJLeDvs zdJ{PA-KYKsEIu-j7BSpOcT>G9BISGME`6cp~85hw;ZFDdHDY|JsOAvv=Ze^y-e(x|vb`=b;}4 zgYZQv7aV<%vF`noHy5?4Rwk=eB^B2jCTd>Yb2n#TOSJFX?w6Fw&}pk_%|W*MuV~i! z3>Vmb7(I*Mv#OEK@!Qm?na$CstZe&`qU2I;Z(CJD&#v_Jq-LPrrY?@`n=BnpNK=X* zYp!Td>o$0bx{vK0OkSw!O9?K|o?>D*P83wBlRJJCt}Q4$@OGD{sKp{#k6RUax0Ex4 z&pe+jS#LNqr~W2TCAI!O?U&ALinlZ!d0VfR=Vl_=ZHX;c7L3C|-dEp9GpLe?swZ a;?v;Bx|Au6L*e|`zuj&tqdJRfTmA#Jq%n&C literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Dj_128x64/frame_9.png b/assets/dolphin/external/L2_Dj_128x64/frame_9.png new file mode 100644 index 0000000000000000000000000000000000000000..05de5d5c698a86baccd74cfe33d1109ee566f793 GIT binary patch literal 1610 zcmaJ?eNfY87*FY-RYd$4;Mce;$Tm0ACTVDsj7keF*o^{*I5_7`lQe}4+JrQW!qls% zb4>51c<1~=xedSADd@J-`89URhTeJNoJ=VSH#ZzR*%XIt?mU(Pb^hU*OY*+&ljrw5 zzvt^xo0pRnGjY~L003ef3vKzz8c-gKR;|2$)qd<$mYK4>NM0nk9l8c<#6f1aibVx_%_lOD_08-QZBF&a^GRSbnyw?oD#SE^5Usx@1i>h-9*y>W2bU|qgz*Ik_81Qg14f;K0ULWN*L!)*nWgimj zA#hYhE;U1Aq>7w*V1^)ZAgM!O7C}(ZMCw=sLvRLjaqjsbhF}Igf+;tQVibx~7!HnK zkm6Btxv6|x=D0uQWQIy)S)}y(%F0Szr9mf1#d?$^$&d{UgB1q%nM#HWRYfs3fT-PY{$azh)(BY!(QKbvXr#x{j{h@b%@^M3B@+5?UVDl|7ko` z+gDH}a{7GECsatRQWJMl7_8*)*^WYr3L7d{;+4YCWj2AW@Niz)VKYO@7oCfDQLK?9 z7@RP{G|P}MZa_(xMo9wZSRBJqBV%+SuCSe_;W3k)w51!xRbht|!tr)~bp`2}2CCp$Lq?Of+YJO$cg$2_ufd1WO_?PPhr$NaJprF+h5SqCV6) zPjpgPq_k&f`*=2#!{h1Vyvj&P%ItLP`YBGCyQsYE0=u$~jEwBPzUKx2L}WQ^)&hUm zo$YT+XA!Oa>wkOX;<~QBn7V_(e%mts)!T`xh`H12)j!U;=6Bz#Oan$@fu38(fL6=y zNHIRq(5=b)VDjF(NkH}=L-&SmJLV1qs({niGM?YH=EceC#=$8`Q-hj7{gn3o&jo?E z(zd2eh*B{t|4ynq`_6-?nxLh{r!^MdY zC$;gLk^YF851H$lZ!L#-^{JECRQ0OaSb|!JnRBA?=;}?wvpR!l3lKP7f3iO!5`2)@ z_=UCtys5c+DeGLeba8gAs{MdZb@N$M@Qcm}vksJ!osZl6;O; zqZVUKS5pJ1I`6?&2&DzA+N}en>UA zv$^-BzOD#!)VsT4T$(-3&eWm3`4IgLP`WPP> zk|eSvDV1!!MnZT+BYvZ|_x=9<`1XCS=RD`!=lXm;_kGTNpX)kL0>;*SFTXTD004U} zEleHQy#~9fa&xi2>3_<*u{&-e$_51hwO7Mg_GxSzgtKt40f0Cm07zuFA8gY3qW};Q z0szb_0DznU0I6O&GByYR_@N{d6O5&a2?#@@c#-@F0ASITn-PS?z7~(`Zw(49c%jYd zaOp$yLtrQ@%^mHLC3RMnOAxMGt60b>f;PPYw!l1z9>gd)nbr#L!`ARB?N-&1L}N86 zW+PXsDq6lRFSDj9C|~YVvspZkraEzJP^$xe>PeT zuy!(QI#Uz2Te!RDMQolTjq?mQ$5NM|&$Tm&n$E_>yZUxBmpmKr*^E<@Q7ZdIz_E-tm-|YIt z|A2%M>;np`}va z?jaaBiS2Hd>&+_)4O_ukD^lL@Rd5bnIdKJ8$yw1eLRer!Q9Eqa0QF9iR|< z_~Xjbp>;hZ|B;wKg`72SjGM8RAXC zZs*Cz?iWD|DMbeds&ypy>@7;FeH`ow*0Id0&l2r5wwC!M>m>}on%&`9yX+iMAvdDX z^Mt=9c2s@de%@tXIFOUYWB%ms$6o5f165g}%xmQj0gP9RvVMdbs};x*zF zeW`feEL?vJ5y{zpG+D)4Y<{=mMWx3o$CL}wsVPg*OQ{x0Wg?Xc=S?B!4%DUwCkAI5 zn1x%VDl$`CEe4eoNxV#9rYsY}RL-^@0Uu5+dd9gdNP};1Zis9oaibqwJhr-^Rf{S# zD>U)6m~2#XcW@lCq}AiA@Uhc;-Jet84#8?#Y7%O9hC}a4-%WEk;6NYRM{*=ZF|kZh z=7FJ;w@dIfuv0KH%rBcWI|e3!f2y_{ojZBV!(Pu(noShL?m2OD4sBB??$}-=h#?XP z_{{E0-CjK-&+;z(8I)$1F|ItWwvFK^zEvVznp|9SW}@(Mufv?fSaC%$+Ugp#wPd%(oEnc> z)d^(jXthDf?TYDw>s8od28v{seP_Nj=eBEAxLL@l*h0_h$0yWI8kR3#hgby_mJDbx zTUT99pikJHDDY{Wi=Ml1qv2HPskT!$-v_FJM0eF6``l{RNT`F zvP&CJ-m{~-Tb=vmD?m+|FHVAloD z31aQ5!mi1f;&kQlx>vNf$2-(V%0_%Hq6pmD$0ai>2S@rwWGd`j+Uslo5E+%dzwu&Z zK<~|3{FhXJ{0=wBu3Y5zIdGU+qr7QzzTyPbu7QBgTBcbYZWUjFF!F2h-8(EzFYew9UHBlQ%o` zgCtb<`)Nv!Pu3O}V+xbc7}UKA^nI^4thdl`{>!Ja@`fl)PYE|IJ+&&;$TN@C8^0$p z_0z}0--@*3ZVlHlwrzWDKlDww2{sF6T4v5&}c5xEemvNt+uUbbDMH~=~V9A+!`3E5H>y#+4Z9`;CMi1z@i{k=-u6KrHkGJ zKBWfnhFKv?mN;kJ`29r6&71pfT)t^6J1Hk^B+Gbk|4murM*L*TkoW`iC@ezv`)typ zYx`%PLw=Q%qWb*`TwNEt@*)*jKbFqrPZ=GQJa{TkX^H4q)R zH*eMW%}f8W_gh7S*WzsN=9L+0g*C12nXrD8ZAYZ{_vKn0(We_vYzEs|_x}(Oks$xY zvnJ@e+8Df%$|@F!u#F%>$J~qqIzK({E>A4aeXUs?uzGs+{x<%rBP)95Xjee_XE*%{ z3PT8@fP_zLGq&!0eqnXLh3wYcI=S|dI=hscGMh4Zc>b_skmEwzgUk@h#MV>ZSzfeI zvAh$~A$)l0-a@~BQASZomuuH|1>PfVNBX3r)~udF7Z391CFf(U%dGY6vTbs21m?GW zWz4)xATs;Kz4)Wjx9Zm#`&JYp>6?{NdY*xkyS6(^#;x3+w5)>!oR z_BMNX;_=H!cE?AxaG?W$V8>45=%SS30f5Vdgmq>(+gKxT6n}^Zp5jS>1p8CjX!cF? zNHEm{=SyIKJPAY+*$BMY+ztkj@J8U1hitTMs3rt&l0_(u;23I)#fAFf4DsM2#(VjZ z!3eg3KY`%^3ikIS(-FZ&;Ge<>_IPI+3I_dzFno=`s2z_WXB!O2ghC^L^dUN0IBjih zkiH>=fcJoT!o56jnjn}qOb4pNe)Y9<^bs&PLdOvF>jASpfWJ2WVsSzoGvA|Dx#(2f}}X z{;$GxYzUPAbs*3w0W=(e4L`8sii$9y5j+?a8kR!w`)5Nj-V_Ff?oFYBU~q^INY%yz zMV@1puS%dRT6g@pcF)jQU|Cxbv{9|sz{?)~R9 zcmDorElp8agP!y>4$%(KZtg|}+3jsVlrDd|^=E6*_Ye8v!E-SVJUpn*Jsm!_EfZzO zCIsBotr9tdFVb6E_T;DJ8_0Ki%D|_TFH|mb8Dozt9hNJNxPI-t&)K)Va{}4JMn+cK zgqIUuQ2n5jSKew}(g!EBD!0|h8i@1t%cVUNdsdfs+W1o_Pkic(b)5adjA@p`*ZffZ y2ZlZ2%iq>4UpQ&knTIwm}#zFvM8!Y2lZ^{#9N|mO{bMR_dbE$YUqoR+cft54KK*>TSh_gWV?1@hyZ7r=c^I+{@c1a4r%UasV0jBL_zrTg0u83=4T@*N4|%@mre0KSXo39)@{kJQAa&*-(!rB+ zYfP?JIkIl-M7xypXukromd9*1DM!7*WZ$nI9bK58A2Djtwa0hb+&&;SU2Cw}_xLkV zHxq(CH*=hMbM$KszpzOLPLqNPj{uL+2Z^qKRI9kK(4ghS_kQ+b9 zurda@hRpQ&9Ik8a>t~$my{9YL(xl6)%kCU>hUy?&d{`!VPY+e$9=f@O;O! zW;V*y2D35gw6mVVi;YDvI7ZxZDEyf%6rrI$urrp57CV_s%qETAV;u`g`h2VPuSI z_R{+zSDvvrO;np=!{^g1N-Z9W;MQi{7Z>E&5}dkTh!=AfwF;MADrT&S+;-}F;lp$? z7}LO}%H*R9!k^VKz?tC8Mhx;nXC#$RjIpV)G2XLik`_ZryXI?aGZg> z#K)6yry#rm5vUe5$&-;Nm~{31V}>uDVFykQ=nZ&UN-WD4q$?W;OC)rRIlGs$z#qzk z&bNooXUsRxE6t0{i*4AmXEyF#=&$KruCKJz^CBL^B=vvnQocx(_ z%ZHOIj6b9;f+!=DewyVpQOM`?^AwX@p}}aOHmsr=bR}gel_!;KjgzaCyTu>h$)0GG zD3vH82f-E;<`zyBa#(L#cVXiSu3FtL)w5Qznk!)YkW^${m~nB%O2mp-pq?LINX#c= zwVnmq?ng4)Hk&k?qn=r0y|^}4+X~`v5~}c(7jx$-3cC@k(jxVuXY|%hxtf%H(VA#v zVL>(=rDUXJQ(?LJ&_#=7F2!s25zUNkNhU9OGcan3Z(Vj)RwP&1q#8=N>|U6ZoP;Yf zD6%NhU#U|qUCqnLt;5vV?gew}v>8cXmewc6^&ZbyvKqCT%wx|JFhwG^OTmTiIU?CL zXrFq|ytS0fw^xHQO~`puesxRV&)kOWWA{nl^S1Rlam*E*lFZ|ry{9$asd$k!L?LbC zUoB8qnzd0m_(Xj2%)R*PevPL?dcW)O#JIIyo|Bv-wUSz&N-;}`Ng11dFRn~fj+QDse zaMpHLD)dS+O3r<(DXGajkymY&U{;j*k=R`JwX&nKph~E0VT5_Sw31YL8&7l;Bv!pE zZC*>LOSt{!_V4>h7OwD7?jlh;(LnE)R6fKd#8g`EqcyGD@3xYbAw*msZ{LX0T;-`Q z*%r49tMoyAq9C!_J7hB=I@0)V7dTlHoG#Kj*W;*r^P&G?Kadx6j)BM+8LSg* ze{65p|CU&NtQKON@U47wRVOB^T8CdJ?rzE5g~k#w*Y-c|mx%2wrS!)4x^ahI4E+4@ zJqvyjAKe_tDIFRfY7?dvONqb<_d}CaeEKI)-qYys=p^)1IuU9Pf39GpBBxmhzOFH* z_D1=QRx8-WwtEPdfiv_lJ_85Km8yDryq*5Bx*0y3G0QO*AeaJaze4fL?rqu%%@Zg9 zpOi-=X`4itU3mB}9bUP7ftYg}r+m)EvimiOHW9@k{i^*DBdE)AXU#SY23(dGrxY^nxswW$7n8X?xkkrca!p@)xw`!gGY(1akr}TE zsYF#jt=D*6OUUc!?NQglKErNdzhhO`1}0zOhj%^u*F*wpzbXGQG;UwJv#;6lcHEl5 z+H}Zeh_Gk4SFxj28d4qcpfQh*!mf5VmsW%mhTQG5I6c_G7>Xx2ZH~ca2S758L;Hk zJAIvpy#9ulHZy=Zj9yZ&RqwsL@tU?#KE80u=Cw`QbHp{$7upw%gM>lzwwgyZX{FVd z-K*F9>s|%8>@169s`XB8)%krDIQ%%22}e%WZTgdU-tBBp3rq%5rT2TgYDRse*Gg*5 zYp-o-uj-7VCc}rc><=bJ)+g>Pfe9_P;c&2t6NfZE8LH zw!>EmdUfm4-fE-IgpcU@(`g>_`CFhnGKa2zzSy>UpSPDFl#p=9#F(=AV_oIpUHX5e z5DkN)S&?06K6okt&~YX^5hIR6HcY-^M zYiWWsd=Yd45`l&X`I0<5y%D}h@xOQxbos~(5eNO{LUTuo|0gM&=|vEVOeKKSz)%Gz zMMXuB8XQb;#={(yT<}ivAebTy3W3sZH3g^|0;Yt3!a;vu;`D%2XBUJeTJP_0bPXx) zN~2K_5QvYD57RJWT1XFV#J1p2FLgxfE3!RY;x z?{BR0uX9oSB^E+Y268mp|1;~KCi(&$iT^AwUHNDI37+(wr_z`Ew~Fsd^bdpWq6rpr zcz8$`>1W`2oH<=$q*Tsm~M%Mh)D^&N|OXu-`S#)@)Vzw_Dlc%^zw!%*SOjtlidA)h$OF~0J*4}Z>>Ab%`&ii|=>v_K0=e|GpXZc>&bJ@YpN>oHa1ONb0Ym5b! zH}2uR>L3B$H$%257XU=iBsAK=8jS|i=u|I~KM??ed$SyaaEVK@#)C^laToKR*@vnA z5dcJ$18S6T%agbc;4ex@n$}0fh`310?8wA8*Inom!DPjZ3<-iI#+zSy z3)KU_tN<%GjQPN1jqg4c;0I`3+Iu7$hJQs?IH=B)@>_+V@3TWADkCrbADZLk_DXmOk3uq2GgPH869P7E+W|mf zx#Pu#feCwJd~|r+Yr>!VqdsrLZo`=sVr>qMn28jZkOZK&PPq#j4_OA{5#>XEkhU*LjOvC22t}1Lx z03^Ki;H)J8NUT|oH{H(%w5Aq(27t;hJ5St6lCyaY0sxDgh*;J1Z{<3z{{8r0^=pm>nK*J&-n#Tw0tU1dq|X9$o;RjFCPHsc)ng@E4i;Cb(l% zziZK@4X>RrU19e%g5g)zu2fp-Bt<+rD)62^!1UQ2WrZuRa~K^=J#qK&lsvx(?6^^{9^YRZ!;vM@^wGheWx?m6FLpJUZ zNBx`1Zk24clYfXwol3;)5o@|WYA2$i#)eyOv-ZREVYCVy3yeD@NSQY3Q*3h6r%}+O za1J;%p^Pogw!gmG^lG$B8d)DRVk4Zl2V0ONc^E-7856v96Kcb3UR(`;@Fy-Q7Nbb@_=E2eqh5Whin#_e0&7b=tRMlu7KLry^}8IZXa@f?C`lr_`U4Ct|BGp=SBJ@ZP*}eyhHoZ zQ~A}W)-S9OL?2y>I+Sw>lkY?*do6!WMfNqEIEORurn?ACY5Lu;^*H`$dDwwFItZ*7JC(k6(8sg>8Zf=M20hk_0pDpjNV?dZ~VH3Xi-5`~B%w8P6v!mIkBB9PFzr#BJk8<^I(cYgC z!E(l49O^C)j@~C?zn>A_g9Ps@s4J)+t=`+31Dc4hiy zhe@wjrfACA3*6#WrP$bHl~hh2^r~@_}RBePT*;irnq$@1W?K zu{{Hs(fssIaYk`nUKc-7s=vU)}Mcs^+t&k;W+EO53D>@oQuLn;|!&t8Z6B22s_jVclVA zVO!U-R}Zcy%spMbJpn&7Ri2%&32&$mFg8_Sq) z7Z!C>rYBNs<-RK}6LkB%HPbs}-hi@Xjw!CdTGVZJckhV1)D9Yy2&3L!wwY{s3W^!B z@{cK3CdsGCEuWL#yAOU>`|HtCN9Gykl4dt&)NR$fDsC>m=<2hBeZEiWf!-Wnf2==Y zI-@+i{BC(faP&{hxl~D})E?oP%cFHYb*Rgq8T=Fe>AIPt=}sw3LdjTv-ZQ!J$+qU~ zAR{+~8#~k>>V{mX#kix;~!elDudz zaPS;@#pja!p@7%A!uHtxtOWV%&s67aT`amkaoRtg`KV=>l$n&7j};}QlnInbt>ccZ@C+u+cAjhYX?~Ql?l6MG zI)C?N^?#4UMt0u1h2DR`RWG?Hsi~P#^5fVuf($;{)0yj=+I8IJ{64wlQyd!SPRY*) zhswuCTdTy)-LYtT=aVOz{-?@F!+& zi0?vNYiaA7RsjSaF>}1-DW~syu73VvNY;7xW|#Hidu7!h)qA^Z27=Dci$yBQ9Q?#h zny!4ZKiJi;%JSR-rSsc`fp`TE#fqBouz_-`Ap834__MdpZe6tGPWdva{{8oBY90xb zvHI6`W0175jBsji#!Pz96WXzTVlU0cUi>k5JM`>lhcCHpulirL4yK(iTL4XASo=GX zH31y0d~yydw~G7aYJQf|NhPc5vR`3bozH}T21LATc21TCYHoS-LgME_&%*31I}_CV zw0_o-&03nD`%(8QZ*+UMi5&BrP1&iXruk13@$R#gv>%Wqk3O}sBgLo^lvNmQeHe59 zICYA+)I8&ARKomWJ9V&w`|kXTZ*3Rj!_N=e?l)Og+}G2JWfb*+UFB*O3qJ!FXXJuJ zzS;DV7Yf4x}^K|aL zqWj1O)duCtHWq5`_F8dU-#KnMw_>oNN;yqq&2+ZQ25q<$#^1kV-31=aeg)2 zP;CeAuTq|AiDNoay_i9GIuS7Qq*ZEv(RF&C`^2?7KNeuo56y}AkaxP zCW%S`Z!+RNr~ynAgeUf|D9E&bXeo@pGsVjpG#F2V>S)6@qxx-VYy1D3lF9#AGniQ7 zfA#(=F~f;PBSNu61~q_A;MLAcb<-6MiKY|rOe)=pO7;JpNCzJ(lgjX+(!g+CZ9TAt zEuKK4Z0_v+6Jl$Nw5BkacnX1NZGnRDNVG{LPb30upl4>TudicaV4$O8X<=ZYXLbl} zZeU=JKp2>tng7OGPzeEKB8B-I>-k^of&Yo!YzQ)q=h=ctCj}Bc57DV)@Sjm5N&lh+ zjW$FaK%)^lW(K|06u~42E=w@yIPpyA%@fv7z`cL!n7XP$Ak;3bF zI$6uszdEQ)Th3%5mF(328`*Mtu%O9B!Cv-m>L=%77YdAR_JMPkjgA zz}wl1=ueR}4Sp#5-UwSXO`koXAV3i=dM6b+c4NP+OloOuBmr3`wpx*a_q#Z zGgmHLIyaAHEaHW;H-;qCX%J` +#include #include #include @@ -118,6 +119,13 @@ static void furi_hal_resources_init_input_pins(GpioMode mode) { } void furi_hal_resources_init_early() { + furi_hal_bus_enable(FuriHalBusGPIOA); + furi_hal_bus_enable(FuriHalBusGPIOB); + furi_hal_bus_enable(FuriHalBusGPIOC); + furi_hal_bus_enable(FuriHalBusGPIOD); + furi_hal_bus_enable(FuriHalBusGPIOE); + furi_hal_bus_enable(FuriHalBusGPIOH); + furi_hal_resources_init_input_pins(GpioModeInput); // SD Card stepdown control @@ -162,6 +170,12 @@ void furi_hal_resources_init_early() { void furi_hal_resources_deinit_early() { furi_hal_resources_init_input_pins(GpioModeAnalog); + furi_hal_bus_disable(FuriHalBusGPIOA); + furi_hal_bus_disable(FuriHalBusGPIOB); + furi_hal_bus_disable(FuriHalBusGPIOC); + furi_hal_bus_disable(FuriHalBusGPIOD); + furi_hal_bus_disable(FuriHalBusGPIOE); + furi_hal_bus_disable(FuriHalBusGPIOH); } void furi_hal_resources_init() { diff --git a/firmware/targets/f18/furi_hal/furi_hal_spi_config.c b/firmware/targets/f18/furi_hal/furi_hal_spi_config.c index 0fbe55e2ac96..5ac84906f82c 100644 --- a/firmware/targets/f18/furi_hal/furi_hal_spi_config.c +++ b/firmware/targets/f18/furi_hal/furi_hal_spi_config.c @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -96,28 +97,17 @@ void furi_hal_spi_config_init() { static void furi_hal_spi_bus_r_event_callback(FuriHalSpiBus* bus, FuriHalSpiBusEvent event) { if(event == FuriHalSpiBusEventInit) { furi_hal_spi_bus_r_mutex = furi_mutex_alloc(FuriMutexTypeNormal); - FURI_CRITICAL_ENTER(); - LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_SPI1); - FURI_CRITICAL_EXIT(); bus->current_handle = NULL; } else if(event == FuriHalSpiBusEventDeinit) { furi_mutex_free(furi_hal_spi_bus_r_mutex); - FURI_CRITICAL_ENTER(); - LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_SPI1); - LL_APB2_GRP1_ReleaseReset(LL_APB2_GRP1_PERIPH_SPI1); - FURI_CRITICAL_EXIT(); } else if(event == FuriHalSpiBusEventLock) { furi_check(furi_mutex_acquire(furi_hal_spi_bus_r_mutex, FuriWaitForever) == FuriStatusOk); } else if(event == FuriHalSpiBusEventUnlock) { furi_check(furi_mutex_release(furi_hal_spi_bus_r_mutex) == FuriStatusOk); } else if(event == FuriHalSpiBusEventActivate) { - FURI_CRITICAL_ENTER(); - LL_APB2_GRP1_ReleaseReset(LL_APB2_GRP1_PERIPH_SPI1); - FURI_CRITICAL_EXIT(); + furi_hal_bus_enable(FuriHalBusSPI1); } else if(event == FuriHalSpiBusEventDeactivate) { - FURI_CRITICAL_ENTER(); - LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_SPI1); - FURI_CRITICAL_EXIT(); + furi_hal_bus_disable(FuriHalBusSPI1); } } @@ -131,28 +121,17 @@ FuriMutex* furi_hal_spi_bus_d_mutex = NULL; static void furi_hal_spi_bus_d_event_callback(FuriHalSpiBus* bus, FuriHalSpiBusEvent event) { if(event == FuriHalSpiBusEventInit) { furi_hal_spi_bus_d_mutex = furi_mutex_alloc(FuriMutexTypeNormal); - FURI_CRITICAL_ENTER(); - LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_SPI2); - FURI_CRITICAL_EXIT(); bus->current_handle = NULL; } else if(event == FuriHalSpiBusEventDeinit) { furi_mutex_free(furi_hal_spi_bus_d_mutex); - FURI_CRITICAL_ENTER(); - LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_SPI2); - LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_SPI2); - FURI_CRITICAL_EXIT(); } else if(event == FuriHalSpiBusEventLock) { furi_check(furi_mutex_acquire(furi_hal_spi_bus_d_mutex, FuriWaitForever) == FuriStatusOk); } else if(event == FuriHalSpiBusEventUnlock) { furi_check(furi_mutex_release(furi_hal_spi_bus_d_mutex) == FuriStatusOk); } else if(event == FuriHalSpiBusEventActivate) { - FURI_CRITICAL_ENTER(); - LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_SPI2); - FURI_CRITICAL_EXIT(); + furi_hal_bus_enable(FuriHalBusSPI2); } else if(event == FuriHalSpiBusEventDeactivate) { - FURI_CRITICAL_ENTER(); - LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_SPI2); - FURI_CRITICAL_EXIT(); + furi_hal_bus_disable(FuriHalBusSPI2); } } diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index f5dee1bad387..a4038a07eb43 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,+,30.0,, +Version,+,30.1,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -36,8 +36,10 @@ Header,+,applications/services/notification/notification_messages.h,, Header,+,applications/services/power/power_service/power.h,, Header,+,applications/services/rpc/rpc_app.h,, Header,+,applications/services/storage/storage.h,, +Header,+,firmware/targets/f7/furi_hal/furi_hal_bus.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_clock.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_console.h,, +Header,+,firmware/targets/f7/furi_hal/furi_hal_dma.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_flash.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_gpio.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_i2c_config.h,, @@ -85,6 +87,7 @@ Header,+,firmware/targets/furi_hal_include/furi_hal_usb_hid.h,, Header,+,firmware/targets/furi_hal_include/furi_hal_usb_hid_u2f.h,, Header,+,firmware/targets/furi_hal_include/furi_hal_version.h,, Header,+,firmware/targets/furi_hal_include/furi_hal_vibro.h,, +Header,+,lib/digital_signal/digital_signal.h,, Header,+,lib/flipper_application/api_hashtable/api_hashtable.h,, Header,+,lib/flipper_application/api_hashtable/compilesort.hpp,, Header,+,lib/flipper_application/flipper_application.h,, @@ -190,10 +193,12 @@ Header,+,lib/subghz/environment.h,, Header,+,lib/subghz/protocols/raw.h,, Header,+,lib/subghz/receiver.h,, Header,+,lib/subghz/registry.h,, +Header,+,lib/subghz/subghz_protocol_registry.h,, Header,+,lib/subghz/subghz_setting.h,, Header,+,lib/subghz/subghz_tx_rx_worker.h,, Header,+,lib/subghz/subghz_worker.h,, Header,+,lib/subghz/transmitter.h,, +Header,+,lib/toolbox/api_lock.h,, Header,+,lib/toolbox/args.h,, Header,+,lib/toolbox/crc32_calc.h,, Header,+,lib/toolbox/dir_walk.h,, @@ -323,6 +328,8 @@ Function,+,__errno,int*, Function,-,__fpclassifyd,int,double Function,-,__fpclassifyf,int,float Function,+,__furi_crash,void, +Function,+,__furi_critical_enter,__FuriCriticalInfo, +Function,+,__furi_critical_exit,void,__FuriCriticalInfo Function,+,__furi_halt,void, Function,-,__getdelim,ssize_t,"char**, size_t*, int, FILE*" Function,-,__getline,ssize_t,"char**, size_t*, FILE*" @@ -791,7 +798,7 @@ Function,+,dir_walk_read,DirWalkResult,"DirWalk*, FuriString*, FileInfo*" Function,+,dir_walk_set_filter_cb,void,"DirWalk*, DirWalkFilterCb, void*" Function,+,dir_walk_set_recursive,void,"DirWalk*, _Bool" Function,-,div,div_t,"int, int" -Function,+,dolphin_deed,void,"Dolphin*, DolphinDeed" +Function,+,dolphin_deed,void,DolphinDeed Function,+,dolphin_deed_get_app,DolphinApp,DolphinDeed Function,+,dolphin_deed_get_app_limit,uint8_t,DolphinApp Function,+,dolphin_deed_get_weight,uint8_t,DolphinDeed @@ -1115,6 +1122,12 @@ Function,+,furi_hal_bt_stop_tone_tx,void, Function,+,furi_hal_bt_unlock_core2,void, Function,+,furi_hal_bt_update_battery_level,void,uint8_t Function,+,furi_hal_bt_update_power_state,void, +Function,+,furi_hal_bus_deinit_early,void, +Function,+,furi_hal_bus_disable,void,FuriHalBus +Function,+,furi_hal_bus_enable,void,FuriHalBus +Function,+,furi_hal_bus_init_early,void, +Function,+,furi_hal_bus_is_enabled,_Bool,FuriHalBus +Function,+,furi_hal_bus_reset,void,FuriHalBus Function,+,furi_hal_cdc_get_ctrl_line_state,uint8_t,uint8_t Function,+,furi_hal_cdc_get_port_settings,usb_cdc_line_coding*,uint8_t Function,+,furi_hal_cdc_receive,int32_t,"uint8_t, uint8_t*, uint16_t" @@ -1157,6 +1170,8 @@ Function,+,furi_hal_debug_disable,void, Function,+,furi_hal_debug_enable,void, Function,+,furi_hal_debug_is_gdb_session_active,_Bool, Function,-,furi_hal_deinit_early,void, +Function,+,furi_hal_dma_deinit_early,void, +Function,+,furi_hal_dma_init_early,void, Function,-,furi_hal_flash_erase,void,uint8_t Function,-,furi_hal_flash_get_base,size_t, Function,-,furi_hal_flash_get_cycles_count,size_t, @@ -1324,6 +1339,7 @@ Function,+,furi_hal_pwm_start,void,"FuriHalPwmOutputId, uint32_t, uint8_t" Function,+,furi_hal_pwm_stop,void,FuriHalPwmOutputId Function,+,furi_hal_random_fill_buf,void,"uint8_t*, uint32_t" Function,+,furi_hal_random_get,uint32_t, +Function,+,furi_hal_random_init,void, Function,+,furi_hal_region_get,const FuriHalRegion*, Function,+,furi_hal_region_get_band,const FuriHalRegionBand*,uint32_t Function,+,furi_hal_region_get_name,const char*, @@ -1335,35 +1351,29 @@ Function,-,furi_hal_resources_deinit_early,void, Function,+,furi_hal_resources_get_ext_pin_number,int32_t,const GpioPin* Function,-,furi_hal_resources_init,void, Function,-,furi_hal_resources_init_early,void, -Function,+,furi_hal_rfid_change_read_config,void,"float, float" Function,+,furi_hal_rfid_comp_set_callback,void,"FuriHalRfidCompCallback, void*" Function,+,furi_hal_rfid_comp_start,void, Function,+,furi_hal_rfid_comp_stop,void, Function,-,furi_hal_rfid_init,void, Function,+,furi_hal_rfid_pin_pull_pulldown,void, Function,+,furi_hal_rfid_pin_pull_release,void, -Function,+,furi_hal_rfid_pins_emulate,void, -Function,+,furi_hal_rfid_pins_read,void, Function,+,furi_hal_rfid_pins_reset,void, -Function,+,furi_hal_rfid_set_emulate_period,void,uint32_t -Function,+,furi_hal_rfid_set_emulate_pulse,void,uint32_t Function,+,furi_hal_rfid_set_read_period,void,uint32_t Function,+,furi_hal_rfid_set_read_pulse,void,uint32_t -Function,+,furi_hal_rfid_tim_emulate,void,float Function,+,furi_hal_rfid_tim_emulate_dma_start,void,"uint32_t*, uint32_t*, size_t, FuriHalRfidDMACallback, void*" Function,+,furi_hal_rfid_tim_emulate_dma_stop,void, -Function,+,furi_hal_rfid_tim_emulate_start,void,"FuriHalRfidEmulateCallback, void*" -Function,+,furi_hal_rfid_tim_emulate_stop,void, -Function,+,furi_hal_rfid_tim_read,void,"float, float" Function,+,furi_hal_rfid_tim_read_capture_start,void,"FuriHalRfidReadCaptureCallback, void*" Function,+,furi_hal_rfid_tim_read_capture_stop,void, -Function,+,furi_hal_rfid_tim_read_start,void, +Function,+,furi_hal_rfid_tim_read_continue,void, +Function,+,furi_hal_rfid_tim_read_pause,void, +Function,+,furi_hal_rfid_tim_read_start,void,"float, float" Function,+,furi_hal_rfid_tim_read_stop,void, -Function,+,furi_hal_rfid_tim_reset,void, Function,+,furi_hal_rtc_datetime_to_timestamp,uint32_t,FuriHalRtcDateTime* Function,-,furi_hal_rtc_deinit_early,void, Function,+,furi_hal_rtc_get_boot_mode,FuriHalRtcBootMode, Function,+,furi_hal_rtc_get_datetime,void,FuriHalRtcDateTime* +Function,+,furi_hal_rtc_get_days_per_month,uint8_t,"_Bool, uint8_t" +Function,+,furi_hal_rtc_get_days_per_year,uint16_t,uint16_t Function,+,furi_hal_rtc_get_fault_data,uint32_t, Function,+,furi_hal_rtc_get_heap_track_mode,FuriHalRtcHeapTrackMode, Function,+,furi_hal_rtc_get_locale_dateformat,FuriHalRtcLocaleDateFormat, @@ -1376,6 +1386,7 @@ Function,+,furi_hal_rtc_get_timestamp,uint32_t, Function,-,furi_hal_rtc_init,void, Function,-,furi_hal_rtc_init_early,void, Function,+,furi_hal_rtc_is_flag_set,_Bool,FuriHalRtcFlag +Function,+,furi_hal_rtc_is_leap_year,_Bool,uint16_t Function,+,furi_hal_rtc_reset_flag,void,FuriHalRtcFlag Function,+,furi_hal_rtc_set_boot_mode,void,FuriHalRtcBootMode Function,+,furi_hal_rtc_set_datetime,void,FuriHalRtcDateTime* @@ -1767,7 +1778,7 @@ Function,+,infrared_worker_rx_set_received_signal_callback,void,"InfraredWorker* Function,+,infrared_worker_rx_start,void,InfraredWorker* Function,+,infrared_worker_rx_stop,void,InfraredWorker* Function,+,infrared_worker_set_decoded_signal,void,"InfraredWorker*, const InfraredMessage*" -Function,+,infrared_worker_set_raw_signal,void,"InfraredWorker*, const uint32_t*, size_t" +Function,+,infrared_worker_set_raw_signal,void,"InfraredWorker*, const uint32_t*, size_t, uint32_t, float" Function,+,infrared_worker_signal_is_decoded,_Bool,const InfraredWorkerSignal* Function,+,infrared_worker_tx_get_signal_steady_callback,InfraredWorkerGetSignalResponse,"void*, InfraredWorker*" Function,+,infrared_worker_tx_set_get_signal_callback,void,"InfraredWorker*, InfraredWorkerGetSignalCallback, void*" @@ -2689,12 +2700,12 @@ Function,+,subghz_environment_get_came_atomo_rainbow_table_file_name,const char* Function,+,subghz_environment_get_keystore,SubGhzKeystore*,SubGhzEnvironment* Function,+,subghz_environment_get_nice_flor_s_rainbow_table_file_name,const char*,SubGhzEnvironment* Function,+,subghz_environment_get_protocol_name_registry,const char*,"SubGhzEnvironment*, size_t" -Function,+,subghz_environment_get_protocol_registry,void*,SubGhzEnvironment* +Function,+,subghz_environment_get_protocol_registry,const SubGhzProtocolRegistry*,SubGhzEnvironment* Function,+,subghz_environment_load_keystore,_Bool,"SubGhzEnvironment*, const char*" Function,+,subghz_environment_set_alutech_at_4n_rainbow_table_file_name,void,"SubGhzEnvironment*, const char*" Function,+,subghz_environment_set_came_atomo_rainbow_table_file_name,void,"SubGhzEnvironment*, const char*" Function,+,subghz_environment_set_nice_flor_s_rainbow_table_file_name,void,"SubGhzEnvironment*, const char*" -Function,+,subghz_environment_set_protocol_registry,void,"SubGhzEnvironment*, void*" +Function,+,subghz_environment_set_protocol_registry,void,"SubGhzEnvironment*, const SubGhzProtocolRegistry*" Function,-,subghz_keystore_alloc,SubGhzKeystore*, Function,-,subghz_keystore_free,void,SubGhzKeystore* Function,-,subghz_keystore_get_data,SubGhzKeyArray_t*,SubGhzKeystore* @@ -2952,6 +2963,7 @@ Function,+,validator_is_file_callback,_Bool,"const char*, FuriString*, void*" Function,+,validator_is_file_free,void,ValidatorIsFile* Function,+,value_index_bool,uint8_t,"const _Bool, const _Bool[], uint8_t" Function,+,value_index_float,uint8_t,"const float, const float[], uint8_t" +Function,+,value_index_int32,uint8_t,"const int32_t, const int32_t[], uint8_t" Function,+,value_index_uint32,uint8_t,"const uint32_t, const uint32_t[], uint8_t" Function,+,variable_item_get_context,void*,VariableItem* Function,+,variable_item_get_current_value_index,uint8_t,VariableItem* @@ -2975,6 +2987,8 @@ Function,-,vdprintf,int,"int, const char*, __gnuc_va_list" Function,+,version_get,const Version*, Function,+,version_get_builddate,const char*,const Version* Function,+,version_get_dirty_flag,_Bool,const Version* +Function,+,version_get_firmware_origin,const char*,const Version* +Function,+,version_get_git_origin,const char*,const Version* Function,+,version_get_gitbranch,const char*,const Version* Function,+,version_get_gitbranchnum,const char*,const Version* Function,+,version_get_githash,const char*,const Version* @@ -3219,6 +3233,7 @@ Variable,+,message_force_vibro_setting_off,const NotificationMessage, Variable,+,message_force_vibro_setting_on,const NotificationMessage, Variable,+,message_green_0,const NotificationMessage, Variable,+,message_green_255,const NotificationMessage, +Variable,+,message_lcd_contrast_update,const NotificationMessage, Variable,+,message_note_a0,const NotificationMessage, Variable,+,message_note_a1,const NotificationMessage, Variable,+,message_note_a2,const NotificationMessage, @@ -3365,6 +3380,7 @@ Variable,+,sequence_display_backlight_off_delay_1000,const NotificationSequence, Variable,+,sequence_display_backlight_on,const NotificationSequence, Variable,+,sequence_double_vibro,const NotificationSequence, Variable,+,sequence_error,const NotificationSequence, +Variable,+,sequence_lcd_contrast_update,const NotificationSequence, Variable,+,sequence_not_charging,const NotificationSequence, Variable,+,sequence_reset_blue,const NotificationSequence, Variable,+,sequence_reset_display,const NotificationSequence, @@ -3386,6 +3402,7 @@ Variable,+,sequence_success,const NotificationSequence, Variable,+,subghz_protocol_raw,const SubGhzProtocol, Variable,+,subghz_protocol_raw_decoder,const SubGhzProtocolDecoder, Variable,+,subghz_protocol_raw_encoder,const SubGhzProtocolEncoder, +Variable,+,subghz_protocol_registry,const SubGhzProtocolRegistry, Variable,-,suboptarg,char*, Variable,+,usb_cdc_dual,FuriHalUsbInterface, Variable,+,usb_cdc_single,FuriHalUsbInterface, diff --git a/firmware/targets/f7/ble_glue/app_debug.c b/firmware/targets/f7/ble_glue/app_debug.c index b443bee21f02..d28852822308 100644 --- a/firmware/targets/f7/ble_glue/app_debug.c +++ b/firmware/targets/f7/ble_glue/app_debug.c @@ -196,14 +196,14 @@ static void APPD_SetCPU2GpioConfig(void) { gpio_config.Pin = gpiob_pin_list; LL_C2_AHB2_GRP1_EnableClock(LL_C2_AHB2_GRP1_PERIPH_GPIOB); LL_GPIO_Init(GPIOB, &gpio_config); - LL_GPIO_ResetOutputPin(GPIOB, gpioa_pin_list); + LL_GPIO_ResetOutputPin(GPIOB, gpiob_pin_list); } if(gpioc_pin_list != 0) { gpio_config.Pin = gpioc_pin_list; LL_C2_AHB2_GRP1_EnableClock(LL_C2_AHB2_GRP1_PERIPH_GPIOC); LL_GPIO_Init(GPIOC, &gpio_config); - LL_GPIO_ResetOutputPin(GPIOC, gpioa_pin_list); + LL_GPIO_ResetOutputPin(GPIOC, gpioc_pin_list); } } diff --git a/firmware/targets/f7/ble_glue/ble_app.c b/firmware/targets/f7/ble_glue/ble_app.c index 37d8f7cd04bd..c0418d9fe807 100644 --- a/firmware/targets/f7/ble_glue/ble_app.c +++ b/firmware/targets/f7/ble_glue/ble_app.c @@ -33,6 +33,51 @@ static int32_t ble_app_hci_thread(void* context); static void ble_app_hci_event_handler(void* pPayload); static void ble_app_hci_status_not_handler(HCI_TL_CmdStatus_t status); +static const HCI_TL_HciInitConf_t hci_tl_config = { + .p_cmdbuffer = (uint8_t*)&ble_app_cmd_buffer, + .StatusNotCallBack = ble_app_hci_status_not_handler, +}; + +static const SHCI_C2_CONFIG_Cmd_Param_t config_param = { + .PayloadCmdSize = SHCI_C2_CONFIG_PAYLOAD_CMD_SIZE, + .Config1 = SHCI_C2_CONFIG_CONFIG1_BIT0_BLE_NVM_DATA_TO_SRAM, + .BleNvmRamAddress = (uint32_t)ble_app_nvm, + .EvtMask1 = SHCI_C2_CONFIG_EVTMASK1_BIT1_BLE_NVM_RAM_UPDATE_ENABLE, +}; + +static const SHCI_C2_Ble_Init_Cmd_Packet_t ble_init_cmd_packet = { + .Header = {{0, 0, 0}}, // Header unused + .Param = { + .pBleBufferAddress = 0, // pBleBufferAddress not used + .BleBufferSize = 0, // BleBufferSize not used + .NumAttrRecord = CFG_BLE_NUM_GATT_ATTRIBUTES, + .NumAttrServ = CFG_BLE_NUM_GATT_SERVICES, + .AttrValueArrSize = CFG_BLE_ATT_VALUE_ARRAY_SIZE, + .NumOfLinks = CFG_BLE_NUM_LINK, + .ExtendedPacketLengthEnable = CFG_BLE_DATA_LENGTH_EXTENSION, + .PrWriteListSize = CFG_BLE_PREPARE_WRITE_LIST_SIZE, + .MblockCount = CFG_BLE_MBLOCK_COUNT, + .AttMtu = CFG_BLE_MAX_ATT_MTU, + .SlaveSca = CFG_BLE_SLAVE_SCA, + .MasterSca = CFG_BLE_MASTER_SCA, + .LsSource = CFG_BLE_LSE_SOURCE, + .MaxConnEventLength = CFG_BLE_MAX_CONN_EVENT_LENGTH, + .HsStartupTime = CFG_BLE_HSE_STARTUP_TIME, + .ViterbiEnable = CFG_BLE_VITERBI_MODE, + .Options = CFG_BLE_OPTIONS, + .HwVersion = 0, + .max_coc_initiator_nbr = 32, + .min_tx_power = 0, + .max_tx_power = 0, + .rx_model_config = 1, + /* New stack (13.3->15.0) */ + .max_adv_set_nbr = 1, // Only used if SHCI_C2_BLE_INIT_OPTIONS_EXT_ADV is set + .max_adv_data_len = 31, // Only used if SHCI_C2_BLE_INIT_OPTIONS_EXT_ADV is set + .tx_path_compens = 0, // RF TX Path Compensation, * 0.1 dB + .rx_path_compens = 0, // RF RX Path Compensation, * 0.1 dB + .ble_core_version = 11, // BLE Core Version: 11(5.2), 12(5.3) + }}; + bool ble_app_init() { SHCI_CmdStatus_t status; ble_app = malloc(sizeof(BleApp)); @@ -44,58 +89,16 @@ bool ble_app_init() { furi_thread_start(ble_app->thread); // Initialize Ble Transport Layer - HCI_TL_HciInitConf_t hci_tl_config = { - .p_cmdbuffer = (uint8_t*)&ble_app_cmd_buffer, - .StatusNotCallBack = ble_app_hci_status_not_handler, - }; hci_init(ble_app_hci_event_handler, (void*)&hci_tl_config); // Configure NVM store for pairing data - SHCI_C2_CONFIG_Cmd_Param_t config_param = { - .PayloadCmdSize = SHCI_C2_CONFIG_PAYLOAD_CMD_SIZE, - .Config1 = SHCI_C2_CONFIG_CONFIG1_BIT0_BLE_NVM_DATA_TO_SRAM, - .BleNvmRamAddress = (uint32_t)ble_app_nvm, - .EvtMask1 = SHCI_C2_CONFIG_EVTMASK1_BIT1_BLE_NVM_RAM_UPDATE_ENABLE, - }; - status = SHCI_C2_Config(&config_param); + status = SHCI_C2_Config((SHCI_C2_CONFIG_Cmd_Param_t*)&config_param); if(status) { FURI_LOG_E(TAG, "Failed to configure 2nd core: %d", status); } // Start ble stack on 2nd core - SHCI_C2_Ble_Init_Cmd_Packet_t ble_init_cmd_packet = { - .Header = {{0, 0, 0}}, // Header unused - .Param = { - .pBleBufferAddress = 0, // pBleBufferAddress not used - .BleBufferSize = 0, // BleBufferSize not used - .NumAttrRecord = CFG_BLE_NUM_GATT_ATTRIBUTES, - .NumAttrServ = CFG_BLE_NUM_GATT_SERVICES, - .AttrValueArrSize = CFG_BLE_ATT_VALUE_ARRAY_SIZE, - .NumOfLinks = CFG_BLE_NUM_LINK, - .ExtendedPacketLengthEnable = CFG_BLE_DATA_LENGTH_EXTENSION, - .PrWriteListSize = CFG_BLE_PREPARE_WRITE_LIST_SIZE, - .MblockCount = CFG_BLE_MBLOCK_COUNT, - .AttMtu = CFG_BLE_MAX_ATT_MTU, - .SlaveSca = CFG_BLE_SLAVE_SCA, - .MasterSca = CFG_BLE_MASTER_SCA, - .LsSource = CFG_BLE_LSE_SOURCE, - .MaxConnEventLength = CFG_BLE_MAX_CONN_EVENT_LENGTH, - .HsStartupTime = CFG_BLE_HSE_STARTUP_TIME, - .ViterbiEnable = CFG_BLE_VITERBI_MODE, - .Options = CFG_BLE_OPTIONS, - .HwVersion = 0, - .max_coc_initiator_nbr = 32, - .min_tx_power = 0, - .max_tx_power = 0, - .rx_model_config = 1, - /* New stack (13.3->15.0) */ - .max_adv_set_nbr = 1, // Only used if SHCI_C2_BLE_INIT_OPTIONS_EXT_ADV is set - .max_adv_data_len = 31, // Only used if SHCI_C2_BLE_INIT_OPTIONS_EXT_ADV is set - .tx_path_compens = 0, // RF TX Path Compensation, * 0.1 dB - .rx_path_compens = 0, // RF RX Path Compensation, * 0.1 dB - .ble_core_version = 11, // BLE Core Version: 11(5.2), 12(5.3) - }}; - status = SHCI_C2_BLE_Init(&ble_init_cmd_packet); + status = SHCI_C2_BLE_Init((SHCI_C2_Ble_Init_Cmd_Packet_t*)&ble_init_cmd_packet); if(status) { FURI_LOG_E(TAG, "Failed to start ble stack: %d", status); } diff --git a/firmware/targets/f7/ble_glue/dev_info_service.c b/firmware/targets/f7/ble_glue/dev_info_service.c deleted file mode 100644 index 8bdb2eea84c7..000000000000 --- a/firmware/targets/f7/ble_glue/dev_info_service.c +++ /dev/null @@ -1,220 +0,0 @@ -#include "dev_info_service.h" -#include "app_common.h" -#include - -#include -#include -#include - -#define TAG "BtDevInfoSvc" - -typedef struct { - uint16_t service_handle; - uint16_t man_name_char_handle; - uint16_t serial_num_char_handle; - uint16_t firmware_rev_char_handle; - uint16_t software_rev_char_handle; - uint16_t rpc_version_char_handle; - FuriString* version_string; - char hardware_revision[4]; -} DevInfoSvc; - -static DevInfoSvc* dev_info_svc = NULL; - -static const char dev_info_man_name[] = "Flipper Devices Inc."; -static const char dev_info_serial_num[] = "1.0"; -static const char dev_info_rpc_version[] = TOSTRING(PROTOBUF_MAJOR_VERSION.PROTOBUF_MINOR_VERSION); - -static const uint8_t dev_info_rpc_version_uuid[] = - {0x33, 0xa9, 0xb5, 0x3e, 0x87, 0x5d, 0x1a, 0x8e, 0xc8, 0x47, 0x5e, 0xae, 0x6d, 0x66, 0xf6, 0x03}; - -void dev_info_svc_start() { - dev_info_svc = malloc(sizeof(DevInfoSvc)); - dev_info_svc->version_string = furi_string_alloc_printf( - "%s %s %s %s", - version_get_githash(NULL), - version_get_gitbranch(NULL), - version_get_gitbranchnum(NULL), - version_get_builddate(NULL)); - snprintf( - dev_info_svc->hardware_revision, - sizeof(dev_info_svc->hardware_revision), - "%d", - version_get_target(NULL)); - tBleStatus status; - - // Add Device Information Service - uint16_t uuid = DEVICE_INFORMATION_SERVICE_UUID; - status = aci_gatt_add_service( - UUID_TYPE_16, (Service_UUID_t*)&uuid, PRIMARY_SERVICE, 11, &dev_info_svc->service_handle); - if(status) { - FURI_LOG_E(TAG, "Failed to add Device Information Service: %d", status); - } - - // Add characteristics - uuid = MANUFACTURER_NAME_UUID; - status = aci_gatt_add_char( - dev_info_svc->service_handle, - UUID_TYPE_16, - (Char_UUID_t*)&uuid, - strlen(dev_info_man_name), - CHAR_PROP_READ, - ATTR_PERMISSION_AUTHEN_READ, - GATT_DONT_NOTIFY_EVENTS, - 10, - CHAR_VALUE_LEN_CONSTANT, - &dev_info_svc->man_name_char_handle); - if(status) { - FURI_LOG_E(TAG, "Failed to add manufacturer name char: %d", status); - } - uuid = SERIAL_NUMBER_UUID; - status = aci_gatt_add_char( - dev_info_svc->service_handle, - UUID_TYPE_16, - (Char_UUID_t*)&uuid, - strlen(dev_info_serial_num), - CHAR_PROP_READ, - ATTR_PERMISSION_AUTHEN_READ, - GATT_DONT_NOTIFY_EVENTS, - 10, - CHAR_VALUE_LEN_CONSTANT, - &dev_info_svc->serial_num_char_handle); - if(status) { - FURI_LOG_E(TAG, "Failed to add serial number char: %d", status); - } - uuid = FIRMWARE_REVISION_UUID; - status = aci_gatt_add_char( - dev_info_svc->service_handle, - UUID_TYPE_16, - (Char_UUID_t*)&uuid, - strlen(dev_info_svc->hardware_revision), - CHAR_PROP_READ, - ATTR_PERMISSION_AUTHEN_READ, - GATT_DONT_NOTIFY_EVENTS, - 10, - CHAR_VALUE_LEN_CONSTANT, - &dev_info_svc->firmware_rev_char_handle); - if(status) { - FURI_LOG_E(TAG, "Failed to add firmware revision char: %d", status); - } - uuid = SOFTWARE_REVISION_UUID; - status = aci_gatt_add_char( - dev_info_svc->service_handle, - UUID_TYPE_16, - (Char_UUID_t*)&uuid, - furi_string_size(dev_info_svc->version_string), - CHAR_PROP_READ, - ATTR_PERMISSION_AUTHEN_READ, - GATT_DONT_NOTIFY_EVENTS, - 10, - CHAR_VALUE_LEN_CONSTANT, - &dev_info_svc->software_rev_char_handle); - if(status) { - FURI_LOG_E(TAG, "Failed to add software revision char: %d", status); - } - status = aci_gatt_add_char( - dev_info_svc->service_handle, - UUID_TYPE_128, - (const Char_UUID_t*)dev_info_rpc_version_uuid, - strlen(dev_info_rpc_version), - CHAR_PROP_READ, - ATTR_PERMISSION_AUTHEN_READ, - GATT_DONT_NOTIFY_EVENTS, - 10, - CHAR_VALUE_LEN_CONSTANT, - &dev_info_svc->rpc_version_char_handle); - if(status) { - FURI_LOG_E(TAG, "Failed to add rpc version characteristic: %d", status); - } - - // Update characteristics - status = aci_gatt_update_char_value( - dev_info_svc->service_handle, - dev_info_svc->man_name_char_handle, - 0, - strlen(dev_info_man_name), - (uint8_t*)dev_info_man_name); - if(status) { - FURI_LOG_E(TAG, "Failed to update manufacturer name char: %d", status); - } - status = aci_gatt_update_char_value( - dev_info_svc->service_handle, - dev_info_svc->serial_num_char_handle, - 0, - strlen(dev_info_serial_num), - (uint8_t*)dev_info_serial_num); - if(status) { - FURI_LOG_E(TAG, "Failed to update serial number char: %d", status); - } - status = aci_gatt_update_char_value( - dev_info_svc->service_handle, - dev_info_svc->firmware_rev_char_handle, - 0, - strlen(dev_info_svc->hardware_revision), - (uint8_t*)dev_info_svc->hardware_revision); - if(status) { - FURI_LOG_E(TAG, "Failed to update firmware revision char: %d", status); - } - status = aci_gatt_update_char_value( - dev_info_svc->service_handle, - dev_info_svc->software_rev_char_handle, - 0, - furi_string_size(dev_info_svc->version_string), - (uint8_t*)furi_string_get_cstr(dev_info_svc->version_string)); - if(status) { - FURI_LOG_E(TAG, "Failed to update software revision char: %d", status); - } - status = aci_gatt_update_char_value( - dev_info_svc->service_handle, - dev_info_svc->rpc_version_char_handle, - 0, - strlen(dev_info_rpc_version), - (uint8_t*)dev_info_rpc_version); - if(status) { - FURI_LOG_E(TAG, "Failed to update rpc version char: %d", status); - } -} - -void dev_info_svc_stop() { - tBleStatus status; - if(dev_info_svc) { - furi_string_free(dev_info_svc->version_string); - // Delete service characteristics - status = - aci_gatt_del_char(dev_info_svc->service_handle, dev_info_svc->man_name_char_handle); - if(status) { - FURI_LOG_E(TAG, "Failed to delete manufacturer name char: %d", status); - } - status = - aci_gatt_del_char(dev_info_svc->service_handle, dev_info_svc->serial_num_char_handle); - if(status) { - FURI_LOG_E(TAG, "Failed to delete serial number char: %d", status); - } - status = aci_gatt_del_char( - dev_info_svc->service_handle, dev_info_svc->firmware_rev_char_handle); - if(status) { - FURI_LOG_E(TAG, "Failed to delete firmware revision char: %d", status); - } - status = aci_gatt_del_char( - dev_info_svc->service_handle, dev_info_svc->software_rev_char_handle); - if(status) { - FURI_LOG_E(TAG, "Failed to delete software revision char: %d", status); - } - status = - aci_gatt_del_char(dev_info_svc->service_handle, dev_info_svc->rpc_version_char_handle); - if(status) { - FURI_LOG_E(TAG, "Failed to delete rpc version char: %d", status); - } - // Delete service - status = aci_gatt_del_service(dev_info_svc->service_handle); - if(status) { - FURI_LOG_E(TAG, "Failed to delete device info service: %d", status); - } - free(dev_info_svc); - dev_info_svc = NULL; - } -} - -bool dev_info_svc_is_started() { - return dev_info_svc != NULL; -} diff --git a/firmware/targets/f7/ble_glue/gap.c b/firmware/targets/f7/ble_glue/gap.c index f0a9ced3cb72..360c1f6b6844 100644 --- a/firmware/targets/f7/ble_glue/gap.c +++ b/firmware/targets/f7/ble_glue/gap.c @@ -330,6 +330,7 @@ static void gap_init_svc(Gap* gap) { if(status) { FURI_LOG_E(TAG, "Failed updating name characteristic: %d", status); } + uint8_t gap_appearence_char_uuid[2] = { gap->config->appearance_char & 0xff, gap->config->appearance_char >> 8}; status = aci_gatt_update_char_value( diff --git a/firmware/targets/f7/ble_glue/hid_service.c b/firmware/targets/f7/ble_glue/hid_service.c deleted file mode 100644 index 47d242d4dff8..000000000000 --- a/firmware/targets/f7/ble_glue/hid_service.c +++ /dev/null @@ -1,332 +0,0 @@ -#include "hid_service.h" -#include "app_common.h" -#include - -#include - -#define TAG "BtHid" - -typedef struct { - uint16_t svc_handle; - uint16_t protocol_mode_char_handle; - uint16_t report_char_handle[HID_SVC_REPORT_COUNT]; - uint16_t report_ref_desc_handle[HID_SVC_REPORT_COUNT]; - uint16_t report_map_char_handle; - uint16_t info_char_handle; - uint16_t ctrl_point_char_handle; -} HIDSvc; - -static HIDSvc* hid_svc = NULL; - -static SVCCTL_EvtAckStatus_t hid_svc_event_handler(void* event) { - SVCCTL_EvtAckStatus_t ret = SVCCTL_EvtNotAck; - hci_event_pckt* event_pckt = (hci_event_pckt*)(((hci_uart_pckt*)event)->data); - evt_blecore_aci* blecore_evt = (evt_blecore_aci*)event_pckt->data; - // aci_gatt_attribute_modified_event_rp0* attribute_modified; - if(event_pckt->evt == HCI_VENDOR_SPECIFIC_DEBUG_EVT_CODE) { - if(blecore_evt->ecode == ACI_GATT_ATTRIBUTE_MODIFIED_VSEVT_CODE) { - // Process modification events - ret = SVCCTL_EvtAckFlowEnable; - } else if(blecore_evt->ecode == ACI_GATT_SERVER_CONFIRMATION_VSEVT_CODE) { - // Process notification confirmation - ret = SVCCTL_EvtAckFlowEnable; - } - } - return ret; -} - -void hid_svc_start() { - tBleStatus status; - hid_svc = malloc(sizeof(HIDSvc)); - Service_UUID_t svc_uuid = {}; - Char_Desc_Uuid_t desc_uuid = {}; - Char_UUID_t char_uuid = {}; - - // Register event handler - SVCCTL_RegisterSvcHandler(hid_svc_event_handler); - // Add service - svc_uuid.Service_UUID_16 = HUMAN_INTERFACE_DEVICE_SERVICE_UUID; - /** - * Add Human Interface Device Service - */ - status = aci_gatt_add_service( - UUID_TYPE_16, - &svc_uuid, - PRIMARY_SERVICE, - 2 + /* protocol mode */ - (4 * HID_SVC_INPUT_REPORT_COUNT) + (3 * HID_SVC_OUTPUT_REPORT_COUNT) + - (3 * HID_SVC_FEATURE_REPORT_COUNT) + 1 + 2 + 2 + - 2, /* Service + Report Map + HID Information + HID Control Point */ - &hid_svc->svc_handle); - if(status) { - FURI_LOG_E(TAG, "Failed to add HID service: %d", status); - } - // Add Protocol mode characteristics - char_uuid.Char_UUID_16 = PROTOCOL_MODE_CHAR_UUID; - status = aci_gatt_add_char( - hid_svc->svc_handle, - UUID_TYPE_16, - &char_uuid, - 1, - CHAR_PROP_READ | CHAR_PROP_WRITE_WITHOUT_RESP, - ATTR_PERMISSION_NONE, - GATT_NOTIFY_ATTRIBUTE_WRITE, - 10, - CHAR_VALUE_LEN_CONSTANT, - &hid_svc->protocol_mode_char_handle); - if(status) { - FURI_LOG_E(TAG, "Failed to add protocol mode characteristic: %d", status); - } - // Update Protocol mode characteristic - uint8_t protocol_mode = 1; - status = aci_gatt_update_char_value( - hid_svc->svc_handle, hid_svc->protocol_mode_char_handle, 0, 1, &protocol_mode); - if(status) { - FURI_LOG_E(TAG, "Failed to update protocol mode characteristic: %d", status); - } - -#if(HID_SVC_REPORT_COUNT != 0) - for(uint8_t i = 0; i < HID_SVC_REPORT_COUNT; i++) { - if(i < HID_SVC_INPUT_REPORT_COUNT) { //-V547 - uint8_t buf[2] = {i + 1, 1}; // 1 input - char_uuid.Char_UUID_16 = REPORT_CHAR_UUID; - status = aci_gatt_add_char( - hid_svc->svc_handle, - UUID_TYPE_16, - &char_uuid, - HID_SVC_REPORT_MAX_LEN, - CHAR_PROP_READ | CHAR_PROP_NOTIFY, - ATTR_PERMISSION_NONE, - GATT_DONT_NOTIFY_EVENTS, - 10, - CHAR_VALUE_LEN_VARIABLE, - &(hid_svc->report_char_handle[i])); - if(status) { - FURI_LOG_E(TAG, "Failed to add report characteristic: %d", status); - } - - desc_uuid.Char_UUID_16 = REPORT_REFERENCE_DESCRIPTOR_UUID; - status = aci_gatt_add_char_desc( - hid_svc->svc_handle, - hid_svc->report_char_handle[i], - UUID_TYPE_16, - &desc_uuid, - HID_SVC_REPORT_REF_LEN, - HID_SVC_REPORT_REF_LEN, - buf, - ATTR_PERMISSION_NONE, - ATTR_ACCESS_READ_WRITE, - GATT_DONT_NOTIFY_EVENTS, - MIN_ENCRY_KEY_SIZE, - CHAR_VALUE_LEN_CONSTANT, - &(hid_svc->report_ref_desc_handle[i])); - if(status) { - FURI_LOG_E(TAG, "Failed to add report reference descriptor: %d", status); - } - } else if((i - HID_SVC_INPUT_REPORT_COUNT) < HID_SVC_OUTPUT_REPORT_COUNT) { - uint8_t buf[2] = {i + 1, 2}; // 2 output - char_uuid.Char_UUID_16 = REPORT_CHAR_UUID; - status = aci_gatt_add_char( - hid_svc->svc_handle, - UUID_TYPE_16, - &char_uuid, - HID_SVC_REPORT_MAX_LEN, - CHAR_PROP_READ | CHAR_PROP_NOTIFY, - ATTR_PERMISSION_NONE, - GATT_DONT_NOTIFY_EVENTS, - 10, - CHAR_VALUE_LEN_VARIABLE, - &(hid_svc->report_char_handle[i])); - if(status) { - FURI_LOG_E(TAG, "Failed to add report characteristic: %d", status); - } - - desc_uuid.Char_UUID_16 = REPORT_REFERENCE_DESCRIPTOR_UUID; - status = aci_gatt_add_char_desc( - hid_svc->svc_handle, - hid_svc->report_char_handle[i], - UUID_TYPE_16, - &desc_uuid, - HID_SVC_REPORT_REF_LEN, - HID_SVC_REPORT_REF_LEN, - buf, - ATTR_PERMISSION_NONE, - ATTR_ACCESS_READ_WRITE, - GATT_DONT_NOTIFY_EVENTS, - MIN_ENCRY_KEY_SIZE, - CHAR_VALUE_LEN_CONSTANT, - &(hid_svc->report_ref_desc_handle[i])); - if(status) { - FURI_LOG_E(TAG, "Failed to add report reference descriptor: %d", status); - } - } else { - uint8_t buf[2] = {i + 1, 3}; // 3 feature - char_uuid.Char_UUID_16 = REPORT_CHAR_UUID; - status = aci_gatt_add_char( - hid_svc->svc_handle, - UUID_TYPE_16, - &char_uuid, - HID_SVC_REPORT_MAX_LEN, - CHAR_PROP_READ | CHAR_PROP_NOTIFY, - ATTR_PERMISSION_NONE, - GATT_DONT_NOTIFY_EVENTS, - 10, - CHAR_VALUE_LEN_VARIABLE, - &(hid_svc->report_char_handle[i])); - if(status) { - FURI_LOG_E(TAG, "Failed to add report characteristic: %d", status); - } - - desc_uuid.Char_UUID_16 = REPORT_REFERENCE_DESCRIPTOR_UUID; - status = aci_gatt_add_char_desc( - hid_svc->svc_handle, - hid_svc->report_char_handle[i], - UUID_TYPE_16, - &desc_uuid, - HID_SVC_REPORT_REF_LEN, - HID_SVC_REPORT_REF_LEN, - buf, - ATTR_PERMISSION_NONE, - ATTR_ACCESS_READ_WRITE, - GATT_DONT_NOTIFY_EVENTS, - MIN_ENCRY_KEY_SIZE, - CHAR_VALUE_LEN_CONSTANT, - &(hid_svc->report_ref_desc_handle[i])); - if(status) { - FURI_LOG_E(TAG, "Failed to add report reference descriptor: %d", status); - } - } - } -#endif - // Add Report Map characteristic - char_uuid.Char_UUID_16 = REPORT_MAP_CHAR_UUID; - status = aci_gatt_add_char( - hid_svc->svc_handle, - UUID_TYPE_16, - &char_uuid, - HID_SVC_REPORT_MAP_MAX_LEN, - CHAR_PROP_READ, - ATTR_PERMISSION_NONE, - GATT_DONT_NOTIFY_EVENTS, - 10, - CHAR_VALUE_LEN_VARIABLE, - &hid_svc->report_map_char_handle); - if(status) { - FURI_LOG_E(TAG, "Failed to add report map characteristic: %d", status); - } - - // Add Information characteristic - char_uuid.Char_UUID_16 = HID_INFORMATION_CHAR_UUID; - status = aci_gatt_add_char( - hid_svc->svc_handle, - UUID_TYPE_16, - &char_uuid, - HID_SVC_INFO_LEN, - CHAR_PROP_READ, - ATTR_PERMISSION_NONE, - GATT_DONT_NOTIFY_EVENTS, - 10, - CHAR_VALUE_LEN_CONSTANT, - &hid_svc->info_char_handle); - if(status) { - FURI_LOG_E(TAG, "Failed to add information characteristic: %d", status); - } - // Add Control Point characteristic - char_uuid.Char_UUID_16 = HID_CONTROL_POINT_CHAR_UUID; - status = aci_gatt_add_char( - hid_svc->svc_handle, - UUID_TYPE_16, - &char_uuid, - HID_SVC_CONTROL_POINT_LEN, - CHAR_PROP_WRITE_WITHOUT_RESP, - ATTR_PERMISSION_NONE, - GATT_NOTIFY_ATTRIBUTE_WRITE, - 10, - CHAR_VALUE_LEN_CONSTANT, - &hid_svc->ctrl_point_char_handle); - if(status) { - FURI_LOG_E(TAG, "Failed to add control point characteristic: %d", status); - } -} - -bool hid_svc_update_report_map(const uint8_t* data, uint16_t len) { - furi_assert(data); - furi_assert(hid_svc); - - tBleStatus status = aci_gatt_update_char_value( - hid_svc->svc_handle, hid_svc->report_map_char_handle, 0, len, data); - if(status) { - FURI_LOG_E(TAG, "Failed updating report map characteristic: %d", status); - return false; - } - return true; -} - -bool hid_svc_update_input_report(uint8_t input_report_num, uint8_t* data, uint16_t len) { - furi_assert(data); - furi_assert(hid_svc); - - tBleStatus status = aci_gatt_update_char_value( - hid_svc->svc_handle, hid_svc->report_char_handle[input_report_num], 0, len, data); - if(status) { - FURI_LOG_E(TAG, "Failed updating report characteristic: %d", status); - return false; - } - return true; -} - -bool hid_svc_update_info(uint8_t* data, uint16_t len) { - furi_assert(data); - furi_assert(hid_svc); - - tBleStatus status = - aci_gatt_update_char_value(hid_svc->svc_handle, hid_svc->info_char_handle, 0, len, data); - if(status) { - FURI_LOG_E(TAG, "Failed updating info characteristic: %d", status); - return false; - } - return true; -} - -bool hid_svc_is_started() { - return hid_svc != NULL; -} - -void hid_svc_stop() { - tBleStatus status; - if(hid_svc) { - // Delete characteristics - status = aci_gatt_del_char(hid_svc->svc_handle, hid_svc->report_map_char_handle); - if(status) { - FURI_LOG_E(TAG, "Failed to delete Report Map characteristic: %d", status); - } -#if(HID_SVC_INPUT_REPORT_COUNT != 0) - for(uint8_t i = 0; i < HID_SVC_REPORT_COUNT; i++) { - status = aci_gatt_del_char(hid_svc->svc_handle, hid_svc->report_char_handle[i]); - if(status) { - FURI_LOG_E(TAG, "Failed to delete Report characteristic: %d", status); - } - } -#endif - status = aci_gatt_del_char(hid_svc->svc_handle, hid_svc->protocol_mode_char_handle); - if(status) { - FURI_LOG_E(TAG, "Failed to delete Protocol Mode characteristic: %d", status); - } - status = aci_gatt_del_char(hid_svc->svc_handle, hid_svc->info_char_handle); - if(status) { - FURI_LOG_E(TAG, "Failed to delete Information characteristic: %d", status); - } - status = aci_gatt_del_char(hid_svc->svc_handle, hid_svc->ctrl_point_char_handle); - if(status) { - FURI_LOG_E(TAG, "Failed to delete Control Point characteristic: %d", status); - } - // Delete service - status = aci_gatt_del_service(hid_svc->svc_handle); - if(status) { - FURI_LOG_E(TAG, "Failed to delete HID service: %d", status); - } - // Delete buffer size mutex - free(hid_svc); - hid_svc = NULL; - } -} diff --git a/firmware/targets/f7/ble_glue/battery_service.c b/firmware/targets/f7/ble_glue/services/battery_service.c similarity index 53% rename from firmware/targets/f7/ble_glue/battery_service.c rename to firmware/targets/f7/ble_glue/services/battery_service.c index 8c371efadba0..63f736b3b7ab 100644 --- a/firmware/targets/f7/ble_glue/battery_service.c +++ b/firmware/targets/f7/ble_glue/services/battery_service.c @@ -1,5 +1,7 @@ #include "battery_service.h" #include "app_common.h" +#include "gatt_char.h" + #include #include @@ -7,12 +9,6 @@ #define TAG "BtBatterySvc" -typedef struct { - uint16_t svc_handle; - uint16_t battery_level_char_handle; - uint16_t power_state_char_handle; -} BatterySvc; - enum { // Common states BatterySvcPowerStateUnknown = 0b00, @@ -40,13 +36,44 @@ typedef struct { _Static_assert(sizeof(BattrySvcPowerState) == 1, "Incorrect structure size"); -static BatterySvc* battery_svc = NULL; - #define BATTERY_POWER_STATE (0x2A1A) static const uint16_t service_uuid = BATTERY_SERVICE_UUID; -static const uint16_t battery_level_char_uuid = BATTERY_LEVEL_CHAR_UUID; -static const uint16_t power_state_char_uuid = BATTERY_POWER_STATE; + +typedef enum { + BatterySvcGattCharacteristicBatteryLevel = 0, + BatterySvcGattCharacteristicPowerState, + BatterySvcGattCharacteristicCount, +} BatterySvcGattCharacteristicId; + +static const FlipperGattCharacteristicParams battery_svc_chars[BatterySvcGattCharacteristicCount] = + {[BatterySvcGattCharacteristicBatteryLevel] = + {.name = "Battery Level", + .data_prop_type = FlipperGattCharacteristicDataFixed, + .data.fixed.length = 1, + .uuid.Char_UUID_16 = BATTERY_LEVEL_CHAR_UUID, + .uuid_type = UUID_TYPE_16, + .char_properties = CHAR_PROP_READ | CHAR_PROP_NOTIFY, + .security_permissions = ATTR_PERMISSION_AUTHEN_READ, + .gatt_evt_mask = GATT_DONT_NOTIFY_EVENTS, + .is_variable = CHAR_VALUE_LEN_CONSTANT}, + [BatterySvcGattCharacteristicPowerState] = { + .name = "Power State", + .data_prop_type = FlipperGattCharacteristicDataFixed, + .data.fixed.length = 1, + .uuid.Char_UUID_16 = BATTERY_POWER_STATE, + .uuid_type = UUID_TYPE_16, + .char_properties = CHAR_PROP_READ | CHAR_PROP_NOTIFY, + .security_permissions = ATTR_PERMISSION_AUTHEN_READ, + .gatt_evt_mask = GATT_DONT_NOTIFY_EVENTS, + .is_variable = CHAR_VALUE_LEN_CONSTANT}}; + +typedef struct { + uint16_t svc_handle; + FlipperGattCharacteristicInstance chars[BatterySvcGattCharacteristicCount]; +} BatterySvc; + +static BatterySvc* battery_svc = NULL; void battery_svc_start() { battery_svc = malloc(sizeof(BatterySvc)); @@ -58,53 +85,19 @@ void battery_svc_start() { if(status) { FURI_LOG_E(TAG, "Failed to add Battery service: %d", status); } - // Add Battery level characteristic - status = aci_gatt_add_char( - battery_svc->svc_handle, - UUID_TYPE_16, - (Char_UUID_t*)&battery_level_char_uuid, - 1, - CHAR_PROP_READ | CHAR_PROP_NOTIFY, - ATTR_PERMISSION_AUTHEN_READ, - GATT_DONT_NOTIFY_EVENTS, - 10, - CHAR_VALUE_LEN_CONSTANT, - &battery_svc->battery_level_char_handle); - if(status) { - FURI_LOG_E(TAG, "Failed to add Battery level characteristic: %d", status); + for(size_t i = 0; i < BatterySvcGattCharacteristicCount; i++) { + flipper_gatt_characteristic_init( + battery_svc->svc_handle, &battery_svc_chars[i], &battery_svc->chars[i]); } - // Add Power state characteristic - status = aci_gatt_add_char( - battery_svc->svc_handle, - UUID_TYPE_16, - (Char_UUID_t*)&power_state_char_uuid, - 1, - CHAR_PROP_READ | CHAR_PROP_NOTIFY, - ATTR_PERMISSION_AUTHEN_READ, - GATT_DONT_NOTIFY_EVENTS, - 10, - CHAR_VALUE_LEN_CONSTANT, - &battery_svc->power_state_char_handle); - if(status) { - FURI_LOG_E(TAG, "Failed to add Battery level characteristic: %d", status); - } - // Update power state charachteristic + battery_svc_update_power_state(); } void battery_svc_stop() { tBleStatus status; if(battery_svc) { - // Delete Battery level characteristic - status = - aci_gatt_del_char(battery_svc->svc_handle, battery_svc->battery_level_char_handle); - if(status) { - FURI_LOG_E(TAG, "Failed to delete Battery level characteristic: %d", status); - } - // Delete Power state characteristic - status = aci_gatt_del_char(battery_svc->svc_handle, battery_svc->power_state_char_handle); - if(status) { - FURI_LOG_E(TAG, "Failed to delete Battery level characteristic: %d", status); + for(size_t i = 0; i < BatterySvcGattCharacteristicCount; i++) { + flipper_gatt_characteristic_delete(battery_svc->svc_handle, &battery_svc->chars[i]); } // Delete Battery service status = aci_gatt_del_service(battery_svc->svc_handle); @@ -126,13 +119,10 @@ bool battery_svc_update_level(uint8_t battery_charge) { return false; } // Update battery level characteristic - FURI_LOG_D(TAG, "Updating battery level characteristic"); - tBleStatus result = aci_gatt_update_char_value( - battery_svc->svc_handle, battery_svc->battery_level_char_handle, 0, 1, &battery_charge); - if(result) { - FURI_LOG_E(TAG, "Failed updating RX characteristic: %d", result); - } - return result != BLE_STATUS_SUCCESS; + return flipper_gatt_characteristic_update( + battery_svc->svc_handle, + &battery_svc->chars[BatterySvcGattCharacteristicBatteryLevel], + &battery_charge); } bool battery_svc_update_power_state() { @@ -152,15 +142,9 @@ bool battery_svc_update_power_state() { power_state.charging = BatterySvcPowerStateNotCharging; power_state.discharging = BatterySvcPowerStateDischarging; } - FURI_LOG_D(TAG, "Updating power state characteristic"); - tBleStatus result = aci_gatt_update_char_value( + + return flipper_gatt_characteristic_update( battery_svc->svc_handle, - battery_svc->power_state_char_handle, - 0, - 1, - (uint8_t*)&power_state); - if(result) { - FURI_LOG_E(TAG, "Failed updating Power state characteristic: %d", result); - } - return result != BLE_STATUS_SUCCESS; + &battery_svc->chars[BatterySvcGattCharacteristicPowerState], + &power_state); } diff --git a/firmware/targets/f7/ble_glue/battery_service.h b/firmware/targets/f7/ble_glue/services/battery_service.h similarity index 100% rename from firmware/targets/f7/ble_glue/battery_service.h rename to firmware/targets/f7/ble_glue/services/battery_service.h diff --git a/firmware/targets/f7/ble_glue/services/dev_info_service.c b/firmware/targets/f7/ble_glue/services/dev_info_service.c new file mode 100644 index 000000000000..cc95bb2fc1c8 --- /dev/null +++ b/firmware/targets/f7/ble_glue/services/dev_info_service.c @@ -0,0 +1,176 @@ +#include "dev_info_service.h" +#include "app_common.h" +#include "gatt_char.h" +#include + +#include +#include +#include + +#include "dev_info_service_uuid.inc" + +#define TAG "BtDevInfoSvc" + +typedef enum { + DevInfoSvcGattCharacteristicMfgName = 0, + DevInfoSvcGattCharacteristicSerial, + DevInfoSvcGattCharacteristicFirmwareRev, + DevInfoSvcGattCharacteristicSoftwareRev, + DevInfoSvcGattCharacteristicRpcVersion, + DevInfoSvcGattCharacteristicCount, +} DevInfoSvcGattCharacteristicId; + +#define DEVICE_INFO_HARDWARE_REV_SIZE 4 +typedef struct { + uint16_t service_handle; + FlipperGattCharacteristicInstance characteristics[DevInfoSvcGattCharacteristicCount]; + FuriString* version_string; + char hardware_revision[DEVICE_INFO_HARDWARE_REV_SIZE]; +} DevInfoSvc; + +static DevInfoSvc* dev_info_svc = NULL; + +static const char dev_info_man_name[] = "Flipper Devices Inc."; +static const char dev_info_serial_num[] = "1.0"; +static const char dev_info_rpc_version[] = TOSTRING(PROTOBUF_MAJOR_VERSION.PROTOBUF_MINOR_VERSION); + +static bool dev_info_char_firmware_rev_callback( + const void* context, + const uint8_t** data, + uint16_t* data_len) { + const DevInfoSvc* dev_info_svc = *(DevInfoSvc**)context; + *data_len = sizeof(dev_info_svc->hardware_revision); + if(data) { + *data = (const uint8_t*)&dev_info_svc->hardware_revision; + } + return false; +} + +static bool dev_info_char_software_rev_callback( + const void* context, + const uint8_t** data, + uint16_t* data_len) { + const DevInfoSvc* dev_info_svc = *(DevInfoSvc**)context; + *data_len = furi_string_size(dev_info_svc->version_string); + if(data) { + *data = (const uint8_t*)furi_string_get_cstr(dev_info_svc->version_string); + } + return false; +} + +static const FlipperGattCharacteristicParams dev_info_svc_chars[DevInfoSvcGattCharacteristicCount] = + {[DevInfoSvcGattCharacteristicMfgName] = + {.name = "Manufacturer Name", + .data_prop_type = FlipperGattCharacteristicDataFixed, + .data.fixed.length = sizeof(dev_info_man_name) - 1, + .data.fixed.ptr = (const uint8_t*)&dev_info_man_name, + .uuid.Char_UUID_16 = MANUFACTURER_NAME_UUID, + .uuid_type = UUID_TYPE_16, + .char_properties = CHAR_PROP_READ, + .security_permissions = ATTR_PERMISSION_AUTHEN_READ, + .gatt_evt_mask = GATT_DONT_NOTIFY_EVENTS, + .is_variable = CHAR_VALUE_LEN_CONSTANT}, + [DevInfoSvcGattCharacteristicSerial] = + {.name = "Serial Number", + .data_prop_type = FlipperGattCharacteristicDataFixed, + .data.fixed.length = sizeof(dev_info_serial_num) - 1, + .data.fixed.ptr = (const uint8_t*)&dev_info_serial_num, + .uuid.Char_UUID_16 = SERIAL_NUMBER_UUID, + .uuid_type = UUID_TYPE_16, + .char_properties = CHAR_PROP_READ, + .security_permissions = ATTR_PERMISSION_AUTHEN_READ, + .gatt_evt_mask = GATT_DONT_NOTIFY_EVENTS, + .is_variable = CHAR_VALUE_LEN_CONSTANT}, + [DevInfoSvcGattCharacteristicFirmwareRev] = + {.name = "Firmware Revision", + .data_prop_type = FlipperGattCharacteristicDataCallback, + .data.callback.context = &dev_info_svc, + .data.callback.fn = dev_info_char_firmware_rev_callback, + .uuid.Char_UUID_16 = FIRMWARE_REVISION_UUID, + .uuid_type = UUID_TYPE_16, + .char_properties = CHAR_PROP_READ, + .security_permissions = ATTR_PERMISSION_AUTHEN_READ, + .gatt_evt_mask = GATT_DONT_NOTIFY_EVENTS, + .is_variable = CHAR_VALUE_LEN_CONSTANT}, + [DevInfoSvcGattCharacteristicSoftwareRev] = + {.name = "Software Revision", + .data_prop_type = FlipperGattCharacteristicDataCallback, + .data.callback.context = &dev_info_svc, + .data.callback.fn = dev_info_char_software_rev_callback, + .uuid.Char_UUID_16 = SOFTWARE_REVISION_UUID, + .uuid_type = UUID_TYPE_16, + .char_properties = CHAR_PROP_READ, + .security_permissions = ATTR_PERMISSION_AUTHEN_READ, + .gatt_evt_mask = GATT_DONT_NOTIFY_EVENTS, + .is_variable = CHAR_VALUE_LEN_CONSTANT}, + [DevInfoSvcGattCharacteristicRpcVersion] = { + .name = "RPC Version", + .data_prop_type = FlipperGattCharacteristicDataFixed, + .data.fixed.length = sizeof(dev_info_rpc_version) - 1, + .data.fixed.ptr = (const uint8_t*)&dev_info_rpc_version, + .uuid.Char_UUID_128 = DEV_INVO_RPC_VERSION_UID, + .uuid_type = UUID_TYPE_128, + .char_properties = CHAR_PROP_READ, + .security_permissions = ATTR_PERMISSION_AUTHEN_READ, + .gatt_evt_mask = GATT_DONT_NOTIFY_EVENTS, + .is_variable = CHAR_VALUE_LEN_CONSTANT}}; + +void dev_info_svc_start() { + dev_info_svc = malloc(sizeof(DevInfoSvc)); + dev_info_svc->version_string = furi_string_alloc_printf( + "%s %s %s %s", + version_get_githash(NULL), + version_get_gitbranch(NULL), + version_get_gitbranchnum(NULL), + version_get_builddate(NULL)); + snprintf( + dev_info_svc->hardware_revision, + sizeof(dev_info_svc->hardware_revision), + "%d", + version_get_target(NULL)); + tBleStatus status; + + // Add Device Information Service + uint16_t uuid = DEVICE_INFORMATION_SERVICE_UUID; + status = aci_gatt_add_service( + UUID_TYPE_16, + (Service_UUID_t*)&uuid, + PRIMARY_SERVICE, + 1 + 2 * DevInfoSvcGattCharacteristicCount, + &dev_info_svc->service_handle); + if(status) { + FURI_LOG_E(TAG, "Failed to add Device Information Service: %d", status); + } + + for(size_t i = 0; i < DevInfoSvcGattCharacteristicCount; i++) { + flipper_gatt_characteristic_init( + dev_info_svc->service_handle, + &dev_info_svc_chars[i], + &dev_info_svc->characteristics[i]); + flipper_gatt_characteristic_update( + dev_info_svc->service_handle, &dev_info_svc->characteristics[i], NULL); + } +} + +void dev_info_svc_stop() { + tBleStatus status; + if(dev_info_svc) { + furi_string_free(dev_info_svc->version_string); + // Delete service characteristics + for(size_t i = 0; i < DevInfoSvcGattCharacteristicCount; i++) { + flipper_gatt_characteristic_delete( + dev_info_svc->service_handle, &dev_info_svc->characteristics[i]); + } + // Delete service + status = aci_gatt_del_service(dev_info_svc->service_handle); + if(status) { + FURI_LOG_E(TAG, "Failed to delete device info service: %d", status); + } + free(dev_info_svc); + dev_info_svc = NULL; + } +} + +bool dev_info_svc_is_started() { + return dev_info_svc != NULL; +} diff --git a/firmware/targets/f7/ble_glue/dev_info_service.h b/firmware/targets/f7/ble_glue/services/dev_info_service.h similarity index 100% rename from firmware/targets/f7/ble_glue/dev_info_service.h rename to firmware/targets/f7/ble_glue/services/dev_info_service.h diff --git a/firmware/targets/f7/ble_glue/services/dev_info_service_uuid.inc b/firmware/targets/f7/ble_glue/services/dev_info_service_uuid.inc new file mode 100644 index 000000000000..ad520f62e5e0 --- /dev/null +++ b/firmware/targets/f7/ble_glue/services/dev_info_service_uuid.inc @@ -0,0 +1,3 @@ +#define DEV_INVO_RPC_VERSION_UID \ + { 0x33, 0xa9, 0xb5, 0x3e, 0x87, 0x5d, 0x1a, 0x8e, 0xc8, 0x47, 0x5e, 0xae, 0x6d, 0x66, 0xf6, 0x03 } + diff --git a/firmware/targets/f7/ble_glue/services/gatt_char.c b/firmware/targets/f7/ble_glue/services/gatt_char.c new file mode 100644 index 000000000000..9b6a44f61b43 --- /dev/null +++ b/firmware/targets/f7/ble_glue/services/gatt_char.c @@ -0,0 +1,123 @@ +#include "gatt_char.h" + +#include + +#define TAG "GattChar" + +#define GATT_MIN_READ_KEY_SIZE (10) + +void flipper_gatt_characteristic_init( + uint16_t svc_handle, + const FlipperGattCharacteristicParams* char_descriptor, + FlipperGattCharacteristicInstance* char_instance) { + furi_assert(char_descriptor); + furi_assert(char_instance); + + // Copy the descriptor to the instance, since it may point to stack memory + // TODO: only copy if really comes from stack + char_instance->characteristic = malloc(sizeof(FlipperGattCharacteristicParams)); + memcpy( + (void*)char_instance->characteristic, + char_descriptor, + sizeof(FlipperGattCharacteristicParams)); + + uint16_t char_data_size = 0; + if(char_descriptor->data_prop_type == FlipperGattCharacteristicDataFixed) { + char_data_size = char_descriptor->data.fixed.length; + } else if(char_descriptor->data_prop_type == FlipperGattCharacteristicDataCallback) { + char_descriptor->data.callback.fn( + char_descriptor->data.callback.context, NULL, &char_data_size); + } + + tBleStatus status = aci_gatt_add_char( + svc_handle, + char_descriptor->uuid_type, + &char_descriptor->uuid, + char_data_size, + char_descriptor->char_properties, + char_descriptor->security_permissions, + char_descriptor->gatt_evt_mask, + GATT_MIN_READ_KEY_SIZE, + char_descriptor->is_variable, + &char_instance->handle); + if(status) { + FURI_LOG_E(TAG, "Failed to add %s char: %d", char_descriptor->name, status); + } + + char_instance->descriptor_handle = 0; + if((status == 0) && char_descriptor->descriptor_params) { + uint8_t const* char_data = NULL; + const FlipperGattCharacteristicDescriptorParams* char_data_descriptor = + char_descriptor->descriptor_params; + bool release_data = char_data_descriptor->data_callback.fn( + char_data_descriptor->data_callback.context, &char_data, &char_data_size); + + status = aci_gatt_add_char_desc( + svc_handle, + char_instance->handle, + char_data_descriptor->uuid_type, + &char_data_descriptor->uuid, + char_data_descriptor->max_length, + char_data_size, + char_data, + char_data_descriptor->security_permissions, + char_data_descriptor->access_permissions, + char_data_descriptor->gatt_evt_mask, + GATT_MIN_READ_KEY_SIZE, + char_data_descriptor->is_variable, + &char_instance->descriptor_handle); + if(status) { + FURI_LOG_E(TAG, "Failed to add %s char descriptor: %d", char_descriptor->name, status); + } + if(release_data) { + free((void*)char_data); + } + } +} + +void flipper_gatt_characteristic_delete( + uint16_t svc_handle, + FlipperGattCharacteristicInstance* char_instance) { + tBleStatus status = aci_gatt_del_char(svc_handle, char_instance->handle); + if(status) { + FURI_LOG_E( + TAG, "Failed to delete %s char: %d", char_instance->characteristic->name, status); + } + free((void*)char_instance->characteristic); +} + +bool flipper_gatt_characteristic_update( + uint16_t svc_handle, + FlipperGattCharacteristicInstance* char_instance, + const void* source) { + furi_assert(char_instance); + const FlipperGattCharacteristicParams* char_descriptor = char_instance->characteristic; + FURI_LOG_D(TAG, "Updating %s char", char_descriptor->name); + + const uint8_t* char_data = NULL; + uint16_t char_data_size = 0; + bool release_data = false; + if(char_descriptor->data_prop_type == FlipperGattCharacteristicDataFixed) { + char_data = char_descriptor->data.fixed.ptr; + if(source) { + char_data = (uint8_t*)source; + } + char_data_size = char_descriptor->data.fixed.length; + } else if(char_descriptor->data_prop_type == FlipperGattCharacteristicDataCallback) { + const void* context = char_descriptor->data.callback.context; + if(source) { + context = source; + } + release_data = char_descriptor->data.callback.fn(context, &char_data, &char_data_size); + } + + tBleStatus result = aci_gatt_update_char_value( + svc_handle, char_instance->handle, 0, char_data_size, char_data); + if(result) { + FURI_LOG_E(TAG, "Failed updating %s characteristic: %d", char_descriptor->name, result); + } + if(release_data) { + free((void*)char_data); + } + return result != BLE_STATUS_SUCCESS; +} \ No newline at end of file diff --git a/firmware/targets/f7/ble_glue/services/gatt_char.h b/firmware/targets/f7/ble_glue/services/gatt_char.h new file mode 100644 index 000000000000..959ab67a49f7 --- /dev/null +++ b/firmware/targets/f7/ble_glue/services/gatt_char.h @@ -0,0 +1,96 @@ +#pragma once + +#include +#include +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// Callback signature for getting characteristic data +// Is called when characteristic is created to get max data length. Data ptr is NULL in this case +// The result is passed to aci_gatt_add_char as "Char_Value_Length" +// For updates, called with a context - see flipper_gatt_characteristic_update +// Returns true if *data ownership is transferred to the caller and will be freed +typedef bool (*cbFlipperGattCharacteristicData)( + const void* context, + const uint8_t** data, + uint16_t* data_len); + +typedef enum { + FlipperGattCharacteristicDataFixed, + FlipperGattCharacteristicDataCallback, +} FlipperGattCharacteristicDataType; + +typedef struct { + Char_Desc_Uuid_t uuid; + struct { + cbFlipperGattCharacteristicData fn; + const void* context; + } data_callback; + uint8_t uuid_type; + uint8_t max_length; + uint8_t security_permissions; + uint8_t access_permissions; + uint8_t gatt_evt_mask; + uint8_t is_variable; +} FlipperGattCharacteristicDescriptorParams; + +typedef struct { + const char* name; + FlipperGattCharacteristicDescriptorParams* descriptor_params; + union { + struct { + const uint8_t* ptr; + uint16_t length; + } fixed; + struct { + cbFlipperGattCharacteristicData fn; + const void* context; + } callback; + } data; + Char_UUID_t uuid; + // Some packed bitfields to save space + FlipperGattCharacteristicDataType data_prop_type : 2; + uint8_t is_variable : 2; + uint8_t uuid_type : 2; + uint8_t char_properties; + uint8_t security_permissions; + uint8_t gatt_evt_mask; +} FlipperGattCharacteristicParams; + +_Static_assert( + sizeof(FlipperGattCharacteristicParams) == 36, + "FlipperGattCharacteristicParams size must be 36 bytes"); + +typedef struct { + const FlipperGattCharacteristicParams* characteristic; + uint16_t handle; + uint16_t descriptor_handle; +} FlipperGattCharacteristicInstance; + +// Initialize a characteristic instance; copies the characteristic descriptor into the instance +void flipper_gatt_characteristic_init( + uint16_t svc_handle, + const FlipperGattCharacteristicParams* char_descriptor, + FlipperGattCharacteristicInstance* char_instance); + +// Delete a characteristic instance; frees the copied characteristic descriptor from the instance +void flipper_gatt_characteristic_delete( + uint16_t svc_handle, + FlipperGattCharacteristicInstance* char_instance); + +// Update a characteristic instance; if source==NULL, uses the data from the characteristic +// - For fixed data, fixed.ptr is used as the source if source==NULL +// - For callback-based data, collback.context is passed as the context if source==NULL +bool flipper_gatt_characteristic_update( + uint16_t svc_handle, + FlipperGattCharacteristicInstance* char_instance, + const void* source); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/firmware/targets/f7/ble_glue/services/hid_service.c b/firmware/targets/f7/ble_glue/services/hid_service.c new file mode 100644 index 000000000000..cf2aca24e3f4 --- /dev/null +++ b/firmware/targets/f7/ble_glue/services/hid_service.c @@ -0,0 +1,302 @@ +#include "hid_service.h" +#include "app_common.h" +#include +#include "gatt_char.h" + +#include + +#define TAG "BtHid" + +typedef enum { + HidSvcGattCharacteristicProtocolMode = 0, + HidSvcGattCharacteristicReportMap, + HidSvcGattCharacteristicInfo, + HidSvcGattCharacteristicCtrlPoint, + HidSvcGattCharacteristicCount, +} HidSvcGattCharacteristicId; + +typedef struct { + uint8_t report_idx; + uint8_t report_type; +} HidSvcReportId; + +static_assert(sizeof(HidSvcReportId) == sizeof(uint16_t), "HidSvcReportId must be 2 bytes"); + +static const Service_UUID_t hid_svc_uuid = { + .Service_UUID_16 = HUMAN_INTERFACE_DEVICE_SERVICE_UUID, +}; + +static bool + hid_svc_char_desc_data_callback(const void* context, const uint8_t** data, uint16_t* data_len) { + const HidSvcReportId* report_id = context; + *data_len = sizeof(HidSvcReportId); + if(data) { + *data = (const uint8_t*)report_id; + } + return false; +} + +typedef struct { + const void* data_ptr; + uint16_t data_len; +} HidSvcDataWrapper; + +static bool + hid_svc_report_data_callback(const void* context, const uint8_t** data, uint16_t* data_len) { + const HidSvcDataWrapper* report_data = context; + if(data) { + *data = report_data->data_ptr; + *data_len = report_data->data_len; + } else { + *data_len = HID_SVC_REPORT_MAP_MAX_LEN; + } + return false; +} + +static const FlipperGattCharacteristicParams hid_svc_chars[HidSvcGattCharacteristicCount] = { + [HidSvcGattCharacteristicProtocolMode] = + {.name = "Protocol Mode", + .data_prop_type = FlipperGattCharacteristicDataFixed, + .data.fixed.length = 1, + .uuid.Char_UUID_16 = PROTOCOL_MODE_CHAR_UUID, + .uuid_type = UUID_TYPE_16, + .char_properties = CHAR_PROP_READ | CHAR_PROP_WRITE_WITHOUT_RESP, + .security_permissions = ATTR_PERMISSION_NONE, + .gatt_evt_mask = GATT_NOTIFY_ATTRIBUTE_WRITE, + .is_variable = CHAR_VALUE_LEN_CONSTANT}, + [HidSvcGattCharacteristicReportMap] = + {.name = "Report Map", + .data_prop_type = FlipperGattCharacteristicDataCallback, + .data.callback.fn = hid_svc_report_data_callback, + .data.callback.context = NULL, + .uuid.Char_UUID_16 = REPORT_MAP_CHAR_UUID, + .uuid_type = UUID_TYPE_16, + .char_properties = CHAR_PROP_READ, + .security_permissions = ATTR_PERMISSION_NONE, + .gatt_evt_mask = GATT_DONT_NOTIFY_EVENTS, + .is_variable = CHAR_VALUE_LEN_VARIABLE}, + [HidSvcGattCharacteristicInfo] = + {.name = "HID Information", + .data_prop_type = FlipperGattCharacteristicDataFixed, + .data.fixed.length = HID_SVC_INFO_LEN, + .data.fixed.ptr = NULL, + .uuid.Char_UUID_16 = HID_INFORMATION_CHAR_UUID, + .uuid_type = UUID_TYPE_16, + .char_properties = CHAR_PROP_READ, + .security_permissions = ATTR_PERMISSION_NONE, + .gatt_evt_mask = GATT_DONT_NOTIFY_EVENTS, + .is_variable = CHAR_VALUE_LEN_CONSTANT}, + [HidSvcGattCharacteristicCtrlPoint] = + {.name = "HID Control Point", + .data_prop_type = FlipperGattCharacteristicDataFixed, + .data.fixed.length = HID_SVC_CONTROL_POINT_LEN, + .uuid.Char_UUID_16 = HID_CONTROL_POINT_CHAR_UUID, + .uuid_type = UUID_TYPE_16, + .char_properties = CHAR_PROP_WRITE_WITHOUT_RESP, + .security_permissions = ATTR_PERMISSION_NONE, + .gatt_evt_mask = GATT_NOTIFY_ATTRIBUTE_WRITE, + .is_variable = CHAR_VALUE_LEN_CONSTANT}, +}; + +static const FlipperGattCharacteristicDescriptorParams hid_svc_char_descr_template = { + .uuid_type = UUID_TYPE_16, + .uuid.Char_UUID_16 = REPORT_REFERENCE_DESCRIPTOR_UUID, + .max_length = HID_SVC_REPORT_REF_LEN, + .data_callback.fn = hid_svc_char_desc_data_callback, + .security_permissions = ATTR_PERMISSION_NONE, + .access_permissions = ATTR_ACCESS_READ_WRITE, + .gatt_evt_mask = GATT_DONT_NOTIFY_EVENTS, + .is_variable = CHAR_VALUE_LEN_CONSTANT, +}; + +static const FlipperGattCharacteristicParams hid_svc_report_template = { + .name = "Report", + .data_prop_type = FlipperGattCharacteristicDataCallback, + .data.callback.fn = hid_svc_report_data_callback, + .data.callback.context = NULL, + .uuid.Char_UUID_16 = REPORT_CHAR_UUID, + .uuid_type = UUID_TYPE_16, + .char_properties = CHAR_PROP_READ | CHAR_PROP_NOTIFY, + .security_permissions = ATTR_PERMISSION_NONE, + .gatt_evt_mask = GATT_DONT_NOTIFY_EVENTS, + .is_variable = CHAR_VALUE_LEN_VARIABLE, +}; + +typedef struct { + uint16_t svc_handle; + FlipperGattCharacteristicInstance chars[HidSvcGattCharacteristicCount]; + FlipperGattCharacteristicInstance input_report_chars[HID_SVC_INPUT_REPORT_COUNT]; + FlipperGattCharacteristicInstance output_report_chars[HID_SVC_OUTPUT_REPORT_COUNT]; + FlipperGattCharacteristicInstance feature_report_chars[HID_SVC_FEATURE_REPORT_COUNT]; +} HIDSvc; + +static HIDSvc* hid_svc = NULL; + +static SVCCTL_EvtAckStatus_t hid_svc_event_handler(void* event) { + SVCCTL_EvtAckStatus_t ret = SVCCTL_EvtNotAck; + hci_event_pckt* event_pckt = (hci_event_pckt*)(((hci_uart_pckt*)event)->data); + evt_blecore_aci* blecore_evt = (evt_blecore_aci*)event_pckt->data; + // aci_gatt_attribute_modified_event_rp0* attribute_modified; + if(event_pckt->evt == HCI_VENDOR_SPECIFIC_DEBUG_EVT_CODE) { + if(blecore_evt->ecode == ACI_GATT_ATTRIBUTE_MODIFIED_VSEVT_CODE) { + // Process modification events + ret = SVCCTL_EvtAckFlowEnable; + } else if(blecore_evt->ecode == ACI_GATT_SERVER_CONFIRMATION_VSEVT_CODE) { + // Process notification confirmation + ret = SVCCTL_EvtAckFlowEnable; + } + } + return ret; +} + +void hid_svc_start() { + tBleStatus status; + hid_svc = malloc(sizeof(HIDSvc)); + + // Register event handler + SVCCTL_RegisterSvcHandler(hid_svc_event_handler); + /** + * Add Human Interface Device Service + */ + status = aci_gatt_add_service( + UUID_TYPE_16, + &hid_svc_uuid, + PRIMARY_SERVICE, + 2 + /* protocol mode */ + (4 * HID_SVC_INPUT_REPORT_COUNT) + (3 * HID_SVC_OUTPUT_REPORT_COUNT) + + (3 * HID_SVC_FEATURE_REPORT_COUNT) + 1 + 2 + 2 + + 2, /* Service + Report Map + HID Information + HID Control Point */ + &hid_svc->svc_handle); + if(status) { + FURI_LOG_E(TAG, "Failed to add HID service: %d", status); + } + + // Maintain previously defined characteristic order + flipper_gatt_characteristic_init( + hid_svc->svc_handle, + &hid_svc_chars[HidSvcGattCharacteristicProtocolMode], + &hid_svc->chars[HidSvcGattCharacteristicProtocolMode]); + + uint8_t protocol_mode = 1; + flipper_gatt_characteristic_update( + hid_svc->svc_handle, + &hid_svc->chars[HidSvcGattCharacteristicProtocolMode], + &protocol_mode); + + // reports + FlipperGattCharacteristicDescriptorParams hid_svc_char_descr; + FlipperGattCharacteristicParams report_char; + HidSvcReportId report_id; + + memcpy(&hid_svc_char_descr, &hid_svc_char_descr_template, sizeof(hid_svc_char_descr)); + memcpy(&report_char, &hid_svc_report_template, sizeof(report_char)); + + hid_svc_char_descr.data_callback.context = &report_id; + report_char.descriptor_params = &hid_svc_char_descr; + + typedef struct { + uint8_t report_type; + uint8_t report_count; + FlipperGattCharacteristicInstance* chars; + } HidSvcReportCharProps; + + HidSvcReportCharProps hid_report_chars[] = { + {0x01, HID_SVC_INPUT_REPORT_COUNT, hid_svc->input_report_chars}, + {0x02, HID_SVC_OUTPUT_REPORT_COUNT, hid_svc->output_report_chars}, + {0x03, HID_SVC_FEATURE_REPORT_COUNT, hid_svc->feature_report_chars}, + }; + + for(size_t report_type_idx = 0; report_type_idx < COUNT_OF(hid_report_chars); + report_type_idx++) { + report_id.report_type = hid_report_chars[report_type_idx].report_type; + for(size_t report_idx = 0; report_idx < hid_report_chars[report_type_idx].report_count; + report_idx++) { + report_id.report_idx = report_idx + 1; + flipper_gatt_characteristic_init( + hid_svc->svc_handle, + &report_char, + &hid_report_chars[report_type_idx].chars[report_idx]); + } + } + + // Setup remaining characteristics + for(size_t i = HidSvcGattCharacteristicReportMap; i < HidSvcGattCharacteristicCount; i++) { + flipper_gatt_characteristic_init( + hid_svc->svc_handle, &hid_svc_chars[i], &hid_svc->chars[i]); + } +} + +bool hid_svc_update_report_map(const uint8_t* data, uint16_t len) { + furi_assert(data); + furi_assert(hid_svc); + + HidSvcDataWrapper report_data = { + .data_ptr = data, + .data_len = len, + }; + return flipper_gatt_characteristic_update( + hid_svc->svc_handle, &hid_svc->chars[HidSvcGattCharacteristicReportMap], &report_data); +} + +bool hid_svc_update_input_report(uint8_t input_report_num, uint8_t* data, uint16_t len) { + furi_assert(data); + furi_assert(hid_svc); + furi_assert(input_report_num < HID_SVC_INPUT_REPORT_COUNT); + + HidSvcDataWrapper report_data = { + .data_ptr = data, + .data_len = len, + }; + return flipper_gatt_characteristic_update( + hid_svc->svc_handle, &hid_svc->input_report_chars[input_report_num], &report_data); +} + +bool hid_svc_update_info(uint8_t* data) { + furi_assert(data); + furi_assert(hid_svc); + + return flipper_gatt_characteristic_update( + hid_svc->svc_handle, &hid_svc->chars[HidSvcGattCharacteristicInfo], &data); +} + +bool hid_svc_is_started() { + return hid_svc != NULL; +} + +void hid_svc_stop() { + tBleStatus status; + if(hid_svc) { + // Delete characteristics + for(size_t i = 0; i < HidSvcGattCharacteristicCount; i++) { + flipper_gatt_characteristic_delete(hid_svc->svc_handle, &hid_svc->chars[i]); + } + + typedef struct { + uint8_t report_count; + FlipperGattCharacteristicInstance* chars; + } HidSvcReportCharProps; + + HidSvcReportCharProps hid_report_chars[] = { + {HID_SVC_INPUT_REPORT_COUNT, hid_svc->input_report_chars}, + {HID_SVC_OUTPUT_REPORT_COUNT, hid_svc->output_report_chars}, + {HID_SVC_FEATURE_REPORT_COUNT, hid_svc->feature_report_chars}, + }; + + for(size_t report_type_idx = 0; report_type_idx < COUNT_OF(hid_report_chars); + report_type_idx++) { + for(size_t report_idx = 0; report_idx < hid_report_chars[report_type_idx].report_count; + report_idx++) { + flipper_gatt_characteristic_delete( + hid_svc->svc_handle, &hid_report_chars[report_type_idx].chars[report_idx]); + } + } + + // Delete service + status = aci_gatt_del_service(hid_svc->svc_handle); + if(status) { + FURI_LOG_E(TAG, "Failed to delete HID service: %d", status); + } + free(hid_svc); + hid_svc = NULL; + } +} diff --git a/firmware/targets/f7/ble_glue/hid_service.h b/firmware/targets/f7/ble_glue/services/hid_service.h similarity index 87% rename from firmware/targets/f7/ble_glue/hid_service.h rename to firmware/targets/f7/ble_glue/services/hid_service.h index 723460d496ac..211adcd6c440 100644 --- a/firmware/targets/f7/ble_glue/hid_service.h +++ b/firmware/targets/f7/ble_glue/services/hid_service.h @@ -25,4 +25,5 @@ bool hid_svc_update_report_map(const uint8_t* data, uint16_t len); bool hid_svc_update_input_report(uint8_t input_report_num, uint8_t* data, uint16_t len); -bool hid_svc_update_info(uint8_t* data, uint16_t len); +// Expects data to be of length HID_SVC_INFO_LEN (4 bytes) +bool hid_svc_update_info(uint8_t* data); diff --git a/firmware/targets/f7/ble_glue/serial_service.c b/firmware/targets/f7/ble_glue/services/serial_service.c similarity index 57% rename from firmware/targets/f7/ble_glue/serial_service.c rename to firmware/targets/f7/ble_glue/services/serial_service.c index c6421dc28fee..0db25b3d3af5 100644 --- a/firmware/targets/f7/ble_glue/serial_service.c +++ b/firmware/targets/f7/ble_glue/services/serial_service.c @@ -1,17 +1,67 @@ #include "serial_service.h" #include "app_common.h" #include +#include "gatt_char.h" #include +#include "serial_service_uuid.inc" + #define TAG "BtSerialSvc" +typedef enum { + SerialSvcGattCharacteristicRx = 0, + SerialSvcGattCharacteristicTx, + SerialSvcGattCharacteristicFlowCtrl, + SerialSvcGattCharacteristicStatus, + SerialSvcGattCharacteristicCount, +} SerialSvcGattCharacteristicId; + +static const FlipperGattCharacteristicParams serial_svc_chars[SerialSvcGattCharacteristicCount] = { + [SerialSvcGattCharacteristicRx] = + {.name = "RX", + .data_prop_type = FlipperGattCharacteristicDataFixed, + .data.fixed.length = SERIAL_SVC_DATA_LEN_MAX, + .uuid.Char_UUID_128 = SERIAL_SVC_RX_CHAR_UUID, + .uuid_type = UUID_TYPE_128, + .char_properties = CHAR_PROP_WRITE_WITHOUT_RESP | CHAR_PROP_WRITE | CHAR_PROP_READ, + .security_permissions = ATTR_PERMISSION_AUTHEN_READ | ATTR_PERMISSION_AUTHEN_WRITE, + .gatt_evt_mask = GATT_NOTIFY_ATTRIBUTE_WRITE, + .is_variable = CHAR_VALUE_LEN_VARIABLE}, + [SerialSvcGattCharacteristicTx] = + {.name = "TX", + .data_prop_type = FlipperGattCharacteristicDataFixed, + .data.fixed.length = SERIAL_SVC_DATA_LEN_MAX, + .uuid.Char_UUID_128 = SERIAL_SVC_TX_CHAR_UUID, + .uuid_type = UUID_TYPE_128, + .char_properties = CHAR_PROP_READ | CHAR_PROP_INDICATE, + .security_permissions = ATTR_PERMISSION_AUTHEN_READ, + .gatt_evt_mask = GATT_DONT_NOTIFY_EVENTS, + .is_variable = CHAR_VALUE_LEN_VARIABLE}, + [SerialSvcGattCharacteristicFlowCtrl] = + {.name = "Flow control", + .data_prop_type = FlipperGattCharacteristicDataFixed, + .data.fixed.length = sizeof(uint32_t), + .uuid.Char_UUID_128 = SERIAL_SVC_FLOW_CONTROL_UUID, + .uuid_type = UUID_TYPE_128, + .char_properties = CHAR_PROP_READ | CHAR_PROP_NOTIFY, + .security_permissions = ATTR_PERMISSION_AUTHEN_READ, + .gatt_evt_mask = GATT_DONT_NOTIFY_EVENTS, + .is_variable = CHAR_VALUE_LEN_CONSTANT}, + [SerialSvcGattCharacteristicStatus] = { + .name = "RPC status", + .data_prop_type = FlipperGattCharacteristicDataFixed, + .data.fixed.length = sizeof(SerialServiceRpcStatus), + .uuid.Char_UUID_128 = SERIAL_SVC_RPC_STATUS_UUID, + .uuid_type = UUID_TYPE_128, + .char_properties = CHAR_PROP_READ | CHAR_PROP_WRITE | CHAR_PROP_NOTIFY, + .security_permissions = ATTR_PERMISSION_AUTHEN_READ | ATTR_PERMISSION_AUTHEN_WRITE, + .gatt_evt_mask = GATT_NOTIFY_ATTRIBUTE_WRITE, + .is_variable = CHAR_VALUE_LEN_CONSTANT}}; + typedef struct { uint16_t svc_handle; - uint16_t rx_char_handle; - uint16_t tx_char_handle; - uint16_t flow_ctrl_char_handle; - uint16_t rpc_status_char_handle; + FlipperGattCharacteristicInstance chars[SerialSvcGattCharacteristicCount]; FuriMutex* buff_size_mtx; uint32_t buff_size; uint16_t bytes_ready_to_receive; @@ -21,17 +71,6 @@ typedef struct { static SerialSvc* serial_svc = NULL; -static const uint8_t service_uuid[] = - {0x00, 0x00, 0xfe, 0x60, 0xcc, 0x7a, 0x48, 0x2a, 0x98, 0x4a, 0x7f, 0x2e, 0xd5, 0xb3, 0xe5, 0x8f}; -static const uint8_t char_tx_uuid[] = - {0x00, 0x00, 0xfe, 0x61, 0x8e, 0x22, 0x45, 0x41, 0x9d, 0x4c, 0x21, 0xed, 0xae, 0x82, 0xed, 0x19}; -static const uint8_t char_rx_uuid[] = - {0x00, 0x00, 0xfe, 0x62, 0x8e, 0x22, 0x45, 0x41, 0x9d, 0x4c, 0x21, 0xed, 0xae, 0x82, 0xed, 0x19}; -static const uint8_t flow_ctrl_uuid[] = - {0x00, 0x00, 0xfe, 0x63, 0x8e, 0x22, 0x45, 0x41, 0x9d, 0x4c, 0x21, 0xed, 0xae, 0x82, 0xed, 0x19}; -static const uint8_t rpc_status_uuid[] = - {0x00, 0x00, 0xfe, 0x64, 0x8e, 0x22, 0x45, 0x41, 0x9d, 0x4c, 0x21, 0xed, 0xae, 0x82, 0xed, 0x19}; - static SVCCTL_EvtAckStatus_t serial_svc_event_handler(void* event) { SVCCTL_EvtAckStatus_t ret = SVCCTL_EvtNotAck; hci_event_pckt* event_pckt = (hci_event_pckt*)(((hci_uart_pckt*)event)->data); @@ -40,11 +79,14 @@ static SVCCTL_EvtAckStatus_t serial_svc_event_handler(void* event) { if(event_pckt->evt == HCI_VENDOR_SPECIFIC_DEBUG_EVT_CODE) { if(blecore_evt->ecode == ACI_GATT_ATTRIBUTE_MODIFIED_VSEVT_CODE) { attribute_modified = (aci_gatt_attribute_modified_event_rp0*)blecore_evt->data; - if(attribute_modified->Attr_Handle == serial_svc->rx_char_handle + 2) { + if(attribute_modified->Attr_Handle == + serial_svc->chars[SerialSvcGattCharacteristicRx].handle + 2) { // Descriptor handle ret = SVCCTL_EvtAckFlowEnable; FURI_LOG_D(TAG, "RX descriptor event"); - } else if(attribute_modified->Attr_Handle == serial_svc->rx_char_handle + 1) { + } else if( + attribute_modified->Attr_Handle == + serial_svc->chars[SerialSvcGattCharacteristicRx].handle + 1) { FURI_LOG_D(TAG, "Received %d bytes", attribute_modified->Attr_Data_Length); if(serial_svc->callback) { furi_check( @@ -70,7 +112,9 @@ static SVCCTL_EvtAckStatus_t serial_svc_event_handler(void* event) { furi_check(furi_mutex_release(serial_svc->buff_size_mtx) == FuriStatusOk); } ret = SVCCTL_EvtAckFlowEnable; - } else if(attribute_modified->Attr_Handle == serial_svc->rpc_status_char_handle + 1) { + } else if( + attribute_modified->Attr_Handle == + serial_svc->chars[SerialSvcGattCharacteristicStatus].handle + 1) { SerialServiceRpcStatus* rpc_status = (SerialServiceRpcStatus*)attribute_modified->Attr_Data; if(*rpc_status == SerialServiceRpcStatusNotActive) { @@ -97,18 +141,12 @@ static SVCCTL_EvtAckStatus_t serial_svc_event_handler(void* event) { } static void serial_svc_update_rpc_char(SerialServiceRpcStatus status) { - tBleStatus ble_status = aci_gatt_update_char_value( - serial_svc->svc_handle, - serial_svc->rpc_status_char_handle, - 0, - sizeof(SerialServiceRpcStatus), - (uint8_t*)&status); - if(ble_status) { - FURI_LOG_E(TAG, "Failed to update RPC status char: %d", ble_status); - } + flipper_gatt_characteristic_update( + serial_svc->svc_handle, &serial_svc->chars[SerialSvcGattCharacteristicStatus], &status); } void serial_svc_start() { + UNUSED(serial_svc_chars); tBleStatus status; serial_svc = malloc(sizeof(SerialSvc)); // Register event handler @@ -116,72 +154,17 @@ void serial_svc_start() { // Add service status = aci_gatt_add_service( - UUID_TYPE_128, (Service_UUID_t*)service_uuid, PRIMARY_SERVICE, 12, &serial_svc->svc_handle); + UUID_TYPE_128, &service_uuid, PRIMARY_SERVICE, 12, &serial_svc->svc_handle); if(status) { FURI_LOG_E(TAG, "Failed to add Serial service: %d", status); } - // Add RX characteristics - status = aci_gatt_add_char( - serial_svc->svc_handle, - UUID_TYPE_128, - (const Char_UUID_t*)char_rx_uuid, - SERIAL_SVC_DATA_LEN_MAX, - CHAR_PROP_WRITE_WITHOUT_RESP | CHAR_PROP_WRITE | CHAR_PROP_READ, - ATTR_PERMISSION_AUTHEN_READ | ATTR_PERMISSION_AUTHEN_WRITE, - GATT_NOTIFY_ATTRIBUTE_WRITE, - 10, - CHAR_VALUE_LEN_VARIABLE, - &serial_svc->rx_char_handle); - if(status) { - FURI_LOG_E(TAG, "Failed to add RX characteristic: %d", status); + // Add characteristics + for(uint8_t i = 0; i < SerialSvcGattCharacteristicCount; i++) { + flipper_gatt_characteristic_init( + serial_svc->svc_handle, &serial_svc_chars[i], &serial_svc->chars[i]); } - // Add TX characteristic - status = aci_gatt_add_char( - serial_svc->svc_handle, - UUID_TYPE_128, - (const Char_UUID_t*)char_tx_uuid, - SERIAL_SVC_DATA_LEN_MAX, - CHAR_PROP_READ | CHAR_PROP_INDICATE, - ATTR_PERMISSION_AUTHEN_READ, - GATT_DONT_NOTIFY_EVENTS, - 10, - CHAR_VALUE_LEN_VARIABLE, - &serial_svc->tx_char_handle); - if(status) { - FURI_LOG_E(TAG, "Failed to add TX characteristic: %d", status); - } - // Add Flow Control characteristic - status = aci_gatt_add_char( - serial_svc->svc_handle, - UUID_TYPE_128, - (const Char_UUID_t*)flow_ctrl_uuid, - sizeof(uint32_t), - CHAR_PROP_READ | CHAR_PROP_NOTIFY, - ATTR_PERMISSION_AUTHEN_READ, - GATT_DONT_NOTIFY_EVENTS, - 10, - CHAR_VALUE_LEN_CONSTANT, - &serial_svc->flow_ctrl_char_handle); - if(status) { - FURI_LOG_E(TAG, "Failed to add Flow Control characteristic: %d", status); - } - // Add RPC status characteristic - status = aci_gatt_add_char( - serial_svc->svc_handle, - UUID_TYPE_128, - (const Char_UUID_t*)rpc_status_uuid, - sizeof(SerialServiceRpcStatus), - CHAR_PROP_READ | CHAR_PROP_WRITE | CHAR_PROP_NOTIFY, - ATTR_PERMISSION_AUTHEN_READ | ATTR_PERMISSION_AUTHEN_WRITE, - GATT_NOTIFY_ATTRIBUTE_WRITE, - 10, - CHAR_VALUE_LEN_CONSTANT, - &serial_svc->rpc_status_char_handle); - if(status) { - FURI_LOG_E(TAG, "Failed to add RPC status characteristic: %d", status); - } serial_svc_update_rpc_char(SerialServiceRpcStatusNotActive); // Allocate buffer size mutex serial_svc->buff_size_mtx = furi_mutex_alloc(FuriMutexTypeNormal); @@ -196,13 +179,12 @@ void serial_svc_set_callbacks( serial_svc->context = context; serial_svc->buff_size = buff_size; serial_svc->bytes_ready_to_receive = buff_size; + uint32_t buff_size_reversed = REVERSE_BYTES_U32(serial_svc->buff_size); - aci_gatt_update_char_value( + flipper_gatt_characteristic_update( serial_svc->svc_handle, - serial_svc->flow_ctrl_char_handle, - 0, - sizeof(uint32_t), - (uint8_t*)&buff_size_reversed); + &serial_svc->chars[SerialSvcGattCharacteristicFlowCtrl], + &buff_size_reversed); } void serial_svc_notify_buffer_is_empty() { @@ -213,13 +195,12 @@ void serial_svc_notify_buffer_is_empty() { if(serial_svc->bytes_ready_to_receive == 0) { FURI_LOG_D(TAG, "Buffer is empty. Notifying client"); serial_svc->bytes_ready_to_receive = serial_svc->buff_size; + uint32_t buff_size_reversed = REVERSE_BYTES_U32(serial_svc->buff_size); - aci_gatt_update_char_value( + flipper_gatt_characteristic_update( serial_svc->svc_handle, - serial_svc->flow_ctrl_char_handle, - 0, - sizeof(uint32_t), - (uint8_t*)&buff_size_reversed); + &serial_svc->chars[SerialSvcGattCharacteristicFlowCtrl], + &buff_size_reversed); } furi_check(furi_mutex_release(serial_svc->buff_size_mtx) == FuriStatusOk); } @@ -227,22 +208,8 @@ void serial_svc_notify_buffer_is_empty() { void serial_svc_stop() { tBleStatus status; if(serial_svc) { - // Delete characteristics - status = aci_gatt_del_char(serial_svc->svc_handle, serial_svc->tx_char_handle); - if(status) { - FURI_LOG_E(TAG, "Failed to delete TX characteristic: %d", status); - } - status = aci_gatt_del_char(serial_svc->svc_handle, serial_svc->rx_char_handle); - if(status) { - FURI_LOG_E(TAG, "Failed to delete RX characteristic: %d", status); - } - status = aci_gatt_del_char(serial_svc->svc_handle, serial_svc->flow_ctrl_char_handle); - if(status) { - FURI_LOG_E(TAG, "Failed to delete Flow Control characteristic: %d", status); - } - status = aci_gatt_del_char(serial_svc->svc_handle, serial_svc->rpc_status_char_handle); - if(status) { - FURI_LOG_E(TAG, "Failed to delete RPC Status characteristic: %d", status); + for(uint8_t i = 0; i < SerialSvcGattCharacteristicCount; i++) { + flipper_gatt_characteristic_delete(serial_svc->svc_handle, &serial_svc->chars[i]); } // Delete service status = aci_gatt_del_service(serial_svc->svc_handle); @@ -273,7 +240,7 @@ bool serial_svc_update_tx(uint8_t* data, uint16_t data_len) { tBleStatus result = aci_gatt_update_char_value_ext( 0, serial_svc->svc_handle, - serial_svc->tx_char_handle, + serial_svc->chars[SerialSvcGattCharacteristicTx].handle, remained ? 0x00 : 0x02, data_len, value_offset, diff --git a/firmware/targets/f7/ble_glue/serial_service.h b/firmware/targets/f7/ble_glue/services/serial_service.h similarity index 100% rename from firmware/targets/f7/ble_glue/serial_service.h rename to firmware/targets/f7/ble_glue/services/serial_service.h diff --git a/firmware/targets/f7/ble_glue/services/serial_service_uuid.inc b/firmware/targets/f7/ble_glue/services/serial_service_uuid.inc new file mode 100644 index 000000000000..a297d9ad604a --- /dev/null +++ b/firmware/targets/f7/ble_glue/services/serial_service_uuid.inc @@ -0,0 +1,12 @@ + +static const Service_UUID_t service_uuid = { .Service_UUID_128 = \ + { 0x00, 0x00, 0xfe, 0x60, 0xcc, 0x7a, 0x48, 0x2a, 0x98, 0x4a, 0x7f, 0x2e, 0xd5, 0xb3, 0xe5, 0x8f }}; + +#define SERIAL_SVC_TX_CHAR_UUID \ + { 0x00, 0x00, 0xfe, 0x61, 0x8e, 0x22, 0x45, 0x41, 0x9d, 0x4c, 0x21, 0xed, 0xae, 0x82, 0xed, 0x19 } +#define SERIAL_SVC_RX_CHAR_UUID \ + { 0x00, 0x00, 0xfe, 0x62, 0x8e, 0x22, 0x45, 0x41, 0x9d, 0x4c, 0x21, 0xed, 0xae, 0x82, 0xed, 0x19 } +#define SERIAL_SVC_FLOW_CONTROL_UUID \ + { 0x00, 0x00, 0xfe, 0x63, 0x8e, 0x22, 0x45, 0x41, 0x9d, 0x4c, 0x21, 0xed, 0xae, 0x82, 0xed, 0x19 } +#define SERIAL_SVC_RPC_STATUS_UUID \ + { 0x00, 0x00, 0xfe, 0x64, 0x8e, 0x22, 0x45, 0x41, 0x9d, 0x4c, 0x21, 0xed, 0xae, 0x82, 0xed, 0x19 } diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc_timer.c b/firmware/targets/f7/furi_hal/f_hal_nfc_timer.c index be2a0ba78521..83c08bcb3bbe 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfc_timer.c +++ b/firmware/targets/f7/furi_hal/f_hal_nfc_timer.c @@ -4,6 +4,7 @@ #include #include #include +#include #define F_HAL_NFC_FREQ_KHZ (13560U) @@ -15,6 +16,7 @@ typedef enum { typedef struct { TIM_TypeDef* timer; + FuriHalBus bus; uint32_t prescaler; uint32_t freq_khz; FHalNfcEventInternalType event; @@ -29,6 +31,7 @@ static FHalNfcTimerConfig f_hal_nfc_timers[FHalNfcTimerCount] = { { .pin = &gpio_ext_pa7, .timer = TIM1, + .bus = FuriHalBusTIM1, .prescaler = 15, .freq_khz = 4000U, .event = FHalNfcEventInternalTypeTimerFwtExpired, @@ -40,6 +43,7 @@ static FHalNfcTimerConfig f_hal_nfc_timers[FHalNfcTimerCount] = { { .pin = &gpio_ext_pa6, .timer = TIM2, + .bus = FuriHalBusTIM2, .prescaler = 0, .freq_khz = 64000U, .event = FHalNfcEventInternalTypeTimerBlockTxExpired, @@ -59,7 +63,7 @@ static void f_hal_nfc_timer_irq_callback(void* context) { } static void f_hal_nfc_timer_init(FHalNfcTimer timer) { - LL_TIM_DeInit(f_hal_nfc_timers[timer].timer); + furi_hal_bus_enable(f_hal_nfc_timers[timer].bus); LL_TIM_EnableUpdateEvent(f_hal_nfc_timers[timer].timer); LL_TIM_SetOnePulseMode(f_hal_nfc_timers[timer].timer, LL_TIM_ONEPULSEMODE_SINGLE); LL_TIM_SetCounterMode(f_hal_nfc_timers[timer].timer, LL_TIM_COUNTERMODE_UP); @@ -79,10 +83,13 @@ static void f_hal_nfc_timer_init(FHalNfcTimer timer) { } static void f_hal_nfc_timer_deinit(FHalNfcTimer timer) { - LL_TIM_DeInit(f_hal_nfc_timers[timer].timer); furi_hal_interrupt_set_isr(f_hal_nfc_timers[timer].irq_id, NULL, NULL); NVIC_DisableIRQ(f_hal_nfc_timers[timer].irq_type); f_hal_nfc_timers[timer].is_configured = false; + + if(furi_hal_bus_is_enabled(f_hal_nfc_timers[timer].bus)) { + furi_hal_bus_disable(f_hal_nfc_timers[timer].bus); + } } static void f_hal_nfc_timer_start(FHalNfcTimer timer, uint32_t time_fc) { diff --git a/firmware/targets/f7/furi_hal/furi_hal.c b/firmware/targets/f7/furi_hal/furi_hal.c index b2a940e9edd1..6bfc40ef7b53 100644 --- a/firmware/targets/f7/furi_hal/furi_hal.c +++ b/firmware/targets/f7/furi_hal/furi_hal.c @@ -9,6 +9,8 @@ void furi_hal_init_early() { furi_hal_cortex_init_early(); furi_hal_clock_init_early(); + furi_hal_bus_init_early(); + furi_hal_dma_init_early(); furi_hal_resources_init_early(); furi_hal_os_init(); furi_hal_spi_config_init_early(); @@ -22,12 +24,15 @@ void furi_hal_deinit_early() { furi_hal_i2c_deinit_early(); furi_hal_spi_config_deinit_early(); furi_hal_resources_deinit_early(); + furi_hal_dma_deinit_early(); + furi_hal_bus_deinit_early(); furi_hal_clock_deinit_early(); } void furi_hal_init() { furi_hal_mpu_init(); furi_hal_clock_init(); + furi_hal_random_init(); furi_hal_console_init(); furi_hal_rtc_init(); furi_hal_interrupt_init(); diff --git a/firmware/targets/f7/furi_hal/furi_hal_bt.c b/firmware/targets/f7/furi_hal/furi_hal_bt.c index 048a8b3090b5..6ff9f0e3b1fd 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_bt.c +++ b/firmware/targets/f7/furi_hal/furi_hal_bt.c @@ -7,8 +7,8 @@ #include #include #include -#include "battery_service.h" - +#include +#include #include #define TAG "FuriHalBt" @@ -80,6 +80,12 @@ FuriHalBtProfileConfig profile_config[FuriHalBtProfileNumber] = { FuriHalBtProfileConfig* current_profile = NULL; void furi_hal_bt_init() { + furi_hal_bus_enable(FuriHalBusHSEM); + furi_hal_bus_enable(FuriHalBusIPCC); + furi_hal_bus_enable(FuriHalBusAES2); + furi_hal_bus_enable(FuriHalBusPKA); + furi_hal_bus_enable(FuriHalBusCRC); + if(!furi_hal_bt_core2_mtx) { furi_hal_bt_core2_mtx = furi_mutex_alloc(FuriMutexTypeNormal); furi_assert(furi_hal_bt_core2_mtx); @@ -256,6 +262,12 @@ void furi_hal_bt_reinit() { furi_delay_ms(100); ble_glue_thread_stop(); + furi_hal_bus_disable(FuriHalBusHSEM); + furi_hal_bus_disable(FuriHalBusIPCC); + furi_hal_bus_disable(FuriHalBusAES2); + furi_hal_bus_disable(FuriHalBusPKA); + furi_hal_bus_disable(FuriHalBusCRC); + FURI_LOG_I(TAG, "Start BT initialization"); furi_hal_bt_init(); diff --git a/firmware/targets/f7/furi_hal/furi_hal_bt_hid.c b/firmware/targets/f7/furi_hal/furi_hal_bt_hid.c index 8259be2f6cd1..7ec712af4dbb 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_bt_hid.c +++ b/firmware/targets/f7/furi_hal/furi_hal_bt_hid.c @@ -1,11 +1,11 @@ #include #include -#include "usb_hid.h" -#include "dev_info_service.h" -#include "battery_service.h" -#include "hid_service.h" +#include +#include +#include #include +#include #define FURI_HAL_BT_INFO_BASE_USB_SPECIFICATION (0x0101) #define FURI_HAL_BT_INFO_COUNTRY_CODE (0x00) @@ -153,7 +153,7 @@ void furi_hal_bt_hid_start() { FURI_HAL_BT_HID_INFO_FLAG_REMOTE_WAKE_MSK | FURI_HAL_BT_HID_INFO_FLAG_NORMALLY_CONNECTABLE_MSK, }; - hid_svc_update_info(hid_info_val, sizeof(hid_info_val)); + hid_svc_update_info(hid_info_val); } void furi_hal_bt_hid_stop() { diff --git a/firmware/targets/f7/furi_hal/furi_hal_bt_serial.c b/firmware/targets/f7/furi_hal/furi_hal_bt_serial.c index 2539e6bd0e90..2927d946f980 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_bt_serial.c +++ b/firmware/targets/f7/furi_hal/furi_hal_bt_serial.c @@ -1,7 +1,7 @@ #include -#include "dev_info_service.h" -#include "battery_service.h" -#include "serial_service.h" +#include +#include +#include #include diff --git a/firmware/targets/f7/furi_hal/furi_hal_bus.c b/firmware/targets/f7/furi_hal/furi_hal_bus.c new file mode 100644 index 000000000000..2c6f1f1ebc92 --- /dev/null +++ b/firmware/targets/f7/furi_hal/furi_hal_bus.c @@ -0,0 +1,302 @@ +#include +#include + +#include + +/* Bus bitmask definitions */ +#define FURI_HAL_BUS_IGNORE (0x0U) + +#define FURI_HAL_BUS_AHB1_GRP1 \ + (LL_AHB1_GRP1_PERIPH_DMA1 | LL_AHB1_GRP1_PERIPH_DMA2 | LL_AHB1_GRP1_PERIPH_DMAMUX1 | \ + LL_AHB1_GRP1_PERIPH_CRC | LL_AHB1_GRP1_PERIPH_TSC) + +#if defined(ADC_SUPPORT_5_MSPS) +#define FURI_HAL_BUS_AHB2_GRP1 \ + (LL_AHB2_GRP1_PERIPH_GPIOA | LL_AHB2_GRP1_PERIPH_GPIOB | LL_AHB2_GRP1_PERIPH_GPIOC | \ + LL_AHB2_GRP1_PERIPH_GPIOD | LL_AHB2_GRP1_PERIPH_GPIOE | LL_AHB2_GRP1_PERIPH_GPIOH | \ + LL_AHB2_GRP1_PERIPH_ADC | LL_AHB2_GRP1_PERIPH_AES1) + +#define FURI_HAL_BUS_APB2_GRP1 \ + (LL_APB2_GRP1_PERIPH_TIM1 | LL_APB2_GRP1_PERIPH_SPI1 | LL_APB2_GRP1_PERIPH_USART1 | \ + LL_APB2_GRP1_PERIPH_TIM16 | LL_APB2_GRP1_PERIPH_TIM17 | LL_APB2_GRP1_PERIPH_SAI1) +#else +#define FURI_HAL_BUS_AHB2_GRP1 \ + (LL_AHB2_GRP1_PERIPH_GPIOA | LL_AHB2_GRP1_PERIPH_GPIOB | LL_AHB2_GRP1_PERIPH_GPIOC | \ + LL_AHB2_GRP1_PERIPH_GPIOD | LL_AHB2_GRP1_PERIPH_GPIOE | LL_AHB2_GRP1_PERIPH_GPIOH | \ + LL_AHB2_GRP1_PERIPH_AES1) + +#define FURI_HAL_BUS_APB2_GRP1 \ + (LL_APB2_GRP1_PERIPH_ADC | LL_APB2_GRP1_PERIPH_TIM1 | LL_APB2_GRP1_PERIPH_SPI1 | \ + LL_APB2_GRP1_PERIPH_USART1 | LL_APB2_GRP1_PERIPH_TIM16 | LL_APB2_GRP1_PERIPH_TIM17 | \ + LL_APB2_GRP1_PERIPH_SAI1) +#endif + +#define FURI_HAL_BUS_AHB3_GRP1 \ + (LL_AHB3_GRP1_PERIPH_QUADSPI | LL_AHB3_GRP1_PERIPH_PKA | LL_AHB3_GRP1_PERIPH_AES2 | \ + LL_AHB3_GRP1_PERIPH_RNG | LL_AHB3_GRP1_PERIPH_HSEM | LL_AHB3_GRP1_PERIPH_IPCC) +// LL_AHB3_GRP1_PERIPH_FLASH enabled by default + +#define FURI_HAL_BUS_APB1_GRP1 \ + (LL_APB1_GRP1_PERIPH_TIM2 | LL_APB1_GRP1_PERIPH_LCD | LL_APB1_GRP1_PERIPH_SPI2 | \ + LL_APB1_GRP1_PERIPH_I2C1 | LL_APB1_GRP1_PERIPH_I2C3 | LL_APB1_GRP1_PERIPH_CRS | \ + LL_APB1_GRP1_PERIPH_USB | LL_APB1_GRP1_PERIPH_LPTIM1) + +#define FURI_HAL_BUS_APB1_GRP2 (LL_APB1_GRP2_PERIPH_LPUART1 | LL_APB1_GRP2_PERIPH_LPTIM2) +#define FURI_HAL_BUS_APB3_GRP1 (LL_APB3_GRP1_PERIPH_RF) + +/* Test macro definitions */ +#define FURI_HAL_BUS_IS_ALL_CLEAR(reg, value) (READ_BIT((reg), (value)) == 0UL) +#define FURI_HAL_BUS_IS_ALL_SET(reg, value) (READ_BIT((reg), (value)) == (value)) + +#define FURI_HAL_BUS_IS_CLOCK_ENABLED(bus, value, ...) \ + (FURI_HAL_BUS_IS_ALL_SET(RCC->bus##ENR##__VA_ARGS__, (value))) +#define FURI_HAL_BUS_IS_CLOCK_DISABLED(bus, value, ...) \ + (FURI_HAL_BUS_IS_ALL_CLEAR(RCC->bus##ENR##__VA_ARGS__, (value))) + +#define FURI_HAL_BUS_IS_RESET_ASSERTED(bus, value, ...) \ + (FURI_HAL_BUS_IS_ALL_SET(RCC->bus##RSTR##__VA_ARGS__, (value))) +#define FURI_HAL_BUS_IS_RESET_DEASSERTED(bus, value, ...) \ + (FURI_HAL_BUS_IS_ALL_CLEAR(RCC->bus##RSTR##__VA_ARGS__, (value))) + +#define FURI_HAL_BUS_IS_PERIPH_ENABLED(bus, value, ...) \ + (FURI_HAL_BUS_IS_RESET_DEASSERTED(bus, (value), __VA_ARGS__) && \ + FURI_HAL_BUS_IS_CLOCK_ENABLED(bus, (value), __VA_ARGS__)) + +#define FURI_HAL_BUS_IS_PERIPH_DISABLED(bus, value, ...) \ + (FURI_HAL_BUS_IS_CLOCK_DISABLED(bus, (value), __VA_ARGS__) && \ + FURI_HAL_BUS_IS_RESET_ASSERTED(bus, (value), __VA_ARGS__)) + +/* Control macro definitions */ +#define FURI_HAL_BUS_RESET_ASSERT(bus, value, grp) LL_##bus##_GRP##grp##_ForceReset(value) +#define FURI_HAL_BUS_RESET_DEASSERT(bus, value, grp) LL_##bus##_GRP##grp##_ReleaseReset(value) + +#define FURI_HAL_BUS_CLOCK_ENABLE(bus, value, grp) LL_##bus##_GRP##grp##_EnableClock(value) +#define FURI_HAL_BUS_CLOCK_DISABLE(bus, value, grp) LL_##bus##_GRP##grp##_DisableClock(value) + +#define FURI_HAL_BUS_PERIPH_ENABLE(bus, value, grp) \ + FURI_HAL_BUS_CLOCK_ENABLE(bus, value, grp); \ + FURI_HAL_BUS_RESET_DEASSERT(bus, value, grp) + +#define FURI_HAL_BUS_PERIPH_DISABLE(bus, value, grp) \ + FURI_HAL_BUS_RESET_ASSERT(bus, value, grp); \ + FURI_HAL_BUS_CLOCK_DISABLE(bus, value, grp) + +#define FURI_HAL_BUS_PERIPH_RESET(bus, value, grp) \ + FURI_HAL_BUS_RESET_ASSERT(bus, value, grp); \ + FURI_HAL_BUS_RESET_DEASSERT(bus, value, grp) + +static const uint32_t furi_hal_bus[] = { + [FuriHalBusAHB1_GRP1] = FURI_HAL_BUS_IGNORE, + [FuriHalBusDMA1] = LL_AHB1_GRP1_PERIPH_DMA1, + [FuriHalBusDMA2] = LL_AHB1_GRP1_PERIPH_DMA2, + [FuriHalBusDMAMUX1] = LL_AHB1_GRP1_PERIPH_DMAMUX1, + [FuriHalBusCRC] = LL_AHB1_GRP1_PERIPH_CRC, + [FuriHalBusTSC] = LL_AHB1_GRP1_PERIPH_TSC, + + [FuriHalBusAHB2_GRP1] = FURI_HAL_BUS_IGNORE, + [FuriHalBusGPIOA] = LL_AHB2_GRP1_PERIPH_GPIOA, + [FuriHalBusGPIOB] = LL_AHB2_GRP1_PERIPH_GPIOB, + [FuriHalBusGPIOC] = LL_AHB2_GRP1_PERIPH_GPIOC, + [FuriHalBusGPIOD] = LL_AHB2_GRP1_PERIPH_GPIOD, + [FuriHalBusGPIOE] = LL_AHB2_GRP1_PERIPH_GPIOE, + [FuriHalBusGPIOH] = LL_AHB2_GRP1_PERIPH_GPIOH, +#if defined(ADC_SUPPORT_5_MSPS) + [FuriHalBusADC] = LL_AHB2_GRP1_PERIPH_ADC, +#endif + [FuriHalBusAES1] = LL_AHB2_GRP1_PERIPH_AES1, + + [FuriHalBusAHB3_GRP1] = FURI_HAL_BUS_IGNORE, + [FuriHalBusQUADSPI] = LL_AHB3_GRP1_PERIPH_QUADSPI, + [FuriHalBusPKA] = LL_AHB3_GRP1_PERIPH_PKA, + [FuriHalBusAES2] = LL_AHB3_GRP1_PERIPH_AES2, + [FuriHalBusRNG] = LL_AHB3_GRP1_PERIPH_RNG, + [FuriHalBusHSEM] = LL_AHB3_GRP1_PERIPH_HSEM, + [FuriHalBusIPCC] = LL_AHB3_GRP1_PERIPH_IPCC, + [FuriHalBusFLASH] = LL_AHB3_GRP1_PERIPH_FLASH, + + [FuriHalBusAPB1_GRP1] = FURI_HAL_BUS_APB1_GRP1, + [FuriHalBusTIM2] = LL_APB1_GRP1_PERIPH_TIM2, + [FuriHalBusLCD] = LL_APB1_GRP1_PERIPH_LCD, + [FuriHalBusSPI2] = LL_APB1_GRP1_PERIPH_SPI2, + [FuriHalBusI2C1] = LL_APB1_GRP1_PERIPH_I2C1, + [FuriHalBusI2C3] = LL_APB1_GRP1_PERIPH_I2C3, + [FuriHalBusCRS] = LL_APB1_GRP1_PERIPH_CRS, + [FuriHalBusUSB] = LL_APB1_GRP1_PERIPH_USB, + [FuriHalBusLPTIM1] = LL_APB1_GRP1_PERIPH_LPTIM1, + + [FuriHalBusAPB1_GRP2] = FURI_HAL_BUS_APB1_GRP2, + [FuriHalBusLPUART1] = LL_APB1_GRP2_PERIPH_LPUART1, + [FuriHalBusLPTIM2] = LL_APB1_GRP2_PERIPH_LPTIM2, + + [FuriHalBusAPB2_GRP1] = FURI_HAL_BUS_APB2_GRP1, +#if defined(ADC_SUPPORT_2_5_MSPS) + [FuriHalBusADC] = LL_APB2_GRP1_PERIPH_ADC, +#endif + [FuriHalBusTIM1] = LL_APB2_GRP1_PERIPH_TIM1, + [FuriHalBusSPI1] = LL_APB2_GRP1_PERIPH_SPI1, + [FuriHalBusUSART1] = LL_APB2_GRP1_PERIPH_USART1, + [FuriHalBusTIM16] = LL_APB2_GRP1_PERIPH_TIM16, + [FuriHalBusTIM17] = LL_APB2_GRP1_PERIPH_TIM17, + [FuriHalBusSAI1] = LL_APB2_GRP1_PERIPH_SAI1, + + [FuriHalBusAPB3_GRP1] = FURI_HAL_BUS_IGNORE, // APB3_GRP1 clocking cannot be changed + [FuriHalBusRF] = LL_APB3_GRP1_PERIPH_RF, +}; + +void furi_hal_bus_init_early() { + FURI_CRITICAL_ENTER(); + + // FURI_HAL_BUS_PERIPH_DISABLE(AHB1, FURI_HAL_BUS_AHB1_GRP1, 1); + // FURI_HAL_BUS_PERIPH_DISABLE(AHB2, FURI_HAL_BUS_AHB2_GRP1, 1); + // FURI_HAL_BUS_PERIPH_DISABLE(AHB3, FURI_HAL_BUS_AHB3_GRP1, 1); + FURI_HAL_BUS_PERIPH_DISABLE(APB1, FURI_HAL_BUS_APB1_GRP1, 1); + FURI_HAL_BUS_PERIPH_DISABLE(APB1, FURI_HAL_BUS_APB1_GRP2, 2); + FURI_HAL_BUS_PERIPH_DISABLE(APB2, FURI_HAL_BUS_APB2_GRP1, 1); + + FURI_HAL_BUS_RESET_ASSERT(APB3, FURI_HAL_BUS_APB3_GRP1, 1); + + FURI_CRITICAL_EXIT(); +} + +void furi_hal_bus_deinit_early() { + FURI_CRITICAL_ENTER(); + + // FURI_HAL_BUS_PERIPH_ENABLE(AHB1, FURI_HAL_BUS_AHB1_GRP1, 1); + // FURI_HAL_BUS_PERIPH_ENABLE(AHB2, FURI_HAL_BUS_AHB2_GRP1, 1); + // FURI_HAL_BUS_PERIPH_ENABLE(AHB3, FURI_HAL_BUS_AHB3_GRP1, 1); + FURI_HAL_BUS_PERIPH_ENABLE(APB1, FURI_HAL_BUS_APB1_GRP1, 1); + FURI_HAL_BUS_PERIPH_ENABLE(APB1, FURI_HAL_BUS_APB1_GRP2, 2); + FURI_HAL_BUS_PERIPH_ENABLE(APB2, FURI_HAL_BUS_APB2_GRP1, 1); + + FURI_HAL_BUS_RESET_DEASSERT(APB3, FURI_HAL_BUS_APB3_GRP1, 1); + + FURI_CRITICAL_EXIT(); +} + +void furi_hal_bus_enable(FuriHalBus bus) { + furi_check(bus < FuriHalBusMAX); + const uint32_t value = furi_hal_bus[bus]; + if(!value) { + return; + } + + FURI_CRITICAL_ENTER(); + if(bus < FuriHalBusAHB2_GRP1) { + // furi_check(FURI_HAL_BUS_IS_PERIPH_DISABLED(AHB1, value)); + FURI_HAL_BUS_PERIPH_ENABLE(AHB1, value, 1); + } else if(bus < FuriHalBusAHB3_GRP1) { + // furi_check(FURI_HAL_BUS_IS_PERIPH_DISABLED(AHB2, value)); + FURI_HAL_BUS_PERIPH_ENABLE(AHB2, value, 1); + } else if(bus < FuriHalBusAPB1_GRP1) { + // furi_check(FURI_HAL_BUS_IS_PERIPH_DISABLED(AHB3, value)); + FURI_HAL_BUS_PERIPH_ENABLE(AHB3, value, 1); + } else if(bus < FuriHalBusAPB1_GRP2) { + furi_check(FURI_HAL_BUS_IS_PERIPH_DISABLED(APB1, value, 1)); + FURI_HAL_BUS_PERIPH_ENABLE(APB1, value, 1); + } else if(bus < FuriHalBusAPB2_GRP1) { + furi_check(FURI_HAL_BUS_IS_PERIPH_DISABLED(APB1, value, 2)); + FURI_HAL_BUS_PERIPH_ENABLE(APB1, value, 2); + } else if(bus < FuriHalBusAPB3_GRP1) { + furi_check(FURI_HAL_BUS_IS_PERIPH_DISABLED(APB2, value)); + FURI_HAL_BUS_PERIPH_ENABLE(APB2, value, 1); + } else { + furi_check(FURI_HAL_BUS_IS_RESET_ASSERTED(APB3, value)); + FURI_HAL_BUS_RESET_DEASSERT(APB3, FURI_HAL_BUS_APB3_GRP1, 1); + } + FURI_CRITICAL_EXIT(); +} + +void furi_hal_bus_reset(FuriHalBus bus) { + furi_check(bus < FuriHalBusMAX); + const uint32_t value = furi_hal_bus[bus]; + if(!value) { + return; + } + + FURI_CRITICAL_ENTER(); + if(bus < FuriHalBusAHB2_GRP1) { + // furi_check(FURI_HAL_BUS_IS_PERIPH_ENABLED(AHB1, value)); + FURI_HAL_BUS_PERIPH_RESET(AHB1, value, 1); + } else if(bus < FuriHalBusAHB3_GRP1) { + // furi_check(FURI_HAL_BUS_IS_PERIPH_ENABLED(AHB2, value)); + FURI_HAL_BUS_PERIPH_RESET(AHB2, value, 1); + } else if(bus < FuriHalBusAPB1_GRP1) { + // furi_check(FURI_HAL_BUS_IS_PERIPH_ENABLED(AHB3, value)); + FURI_HAL_BUS_PERIPH_RESET(AHB3, value, 1); + } else if(bus < FuriHalBusAPB1_GRP2) { + furi_check(FURI_HAL_BUS_IS_PERIPH_ENABLED(APB1, value, 1)); + FURI_HAL_BUS_PERIPH_RESET(APB1, value, 1); + } else if(bus < FuriHalBusAPB2_GRP1) { + furi_check(FURI_HAL_BUS_IS_PERIPH_ENABLED(APB1, value, 2)); + FURI_HAL_BUS_PERIPH_RESET(APB1, value, 2); + } else if(bus < FuriHalBusAPB3_GRP1) { + furi_check(FURI_HAL_BUS_IS_PERIPH_ENABLED(APB2, value)); + FURI_HAL_BUS_PERIPH_RESET(APB2, value, 1); + } else { + furi_check(FURI_HAL_BUS_IS_RESET_DEASSERTED(APB3, value)); + FURI_HAL_BUS_PERIPH_RESET(APB3, value, 1); + } + FURI_CRITICAL_EXIT(); +} + +void furi_hal_bus_disable(FuriHalBus bus) { + furi_check(bus < FuriHalBusMAX); + const uint32_t value = furi_hal_bus[bus]; + if(!value) { + return; + } + + FURI_CRITICAL_ENTER(); + if(bus < FuriHalBusAHB2_GRP1) { + // furi_check(FURI_HAL_BUS_IS_PERIPH_ENABLED(AHB1, value)); + FURI_HAL_BUS_PERIPH_DISABLE(AHB1, value, 1); + } else if(bus < FuriHalBusAHB3_GRP1) { + // furi_check(FURI_HAL_BUS_IS_PERIPH_ENABLED(AHB2, value)); + FURI_HAL_BUS_PERIPH_DISABLE(AHB2, value, 1); + } else if(bus < FuriHalBusAPB1_GRP1) { + // furi_check(FURI_HAL_BUS_IS_PERIPH_ENABLED(AHB3, value)); + FURI_HAL_BUS_PERIPH_DISABLE(AHB3, value, 1); + } else if(bus < FuriHalBusAPB1_GRP2) { + furi_check(FURI_HAL_BUS_IS_PERIPH_ENABLED(APB1, value, 1)); + FURI_HAL_BUS_PERIPH_DISABLE(APB1, value, 1); + } else if(bus < FuriHalBusAPB2_GRP1) { + furi_check(FURI_HAL_BUS_IS_PERIPH_ENABLED(APB1, value, 2)); + FURI_HAL_BUS_PERIPH_DISABLE(APB1, value, 2); + } else if(bus < FuriHalBusAPB3_GRP1) { + furi_check(FURI_HAL_BUS_IS_PERIPH_ENABLED(APB2, value)); + FURI_HAL_BUS_PERIPH_DISABLE(APB2, value, 1); + } else { + furi_check(FURI_HAL_BUS_IS_RESET_DEASSERTED(APB3, value)); + FURI_HAL_BUS_RESET_ASSERT(APB3, FURI_HAL_BUS_APB3_GRP1, 1); + } + FURI_CRITICAL_EXIT(); +} + +bool furi_hal_bus_is_enabled(FuriHalBus bus) { + furi_check(bus < FuriHalBusMAX); + const uint32_t value = furi_hal_bus[bus]; + if(value == FURI_HAL_BUS_IGNORE) { + return true; + } + + bool ret = false; + FURI_CRITICAL_ENTER(); + if(bus < FuriHalBusAHB2_GRP1) { + ret = FURI_HAL_BUS_IS_PERIPH_ENABLED(AHB1, value); + } else if(bus < FuriHalBusAHB3_GRP1) { + ret = FURI_HAL_BUS_IS_PERIPH_ENABLED(AHB2, value); + } else if(bus < FuriHalBusAPB1_GRP1) { + ret = FURI_HAL_BUS_IS_PERIPH_ENABLED(AHB3, value); + } else if(bus < FuriHalBusAPB1_GRP2) { + ret = FURI_HAL_BUS_IS_PERIPH_ENABLED(APB1, value, 1); + } else if(bus < FuriHalBusAPB2_GRP1) { + ret = FURI_HAL_BUS_IS_PERIPH_ENABLED(APB1, value, 2); + } else if(bus < FuriHalBusAPB3_GRP1) { + ret = FURI_HAL_BUS_IS_PERIPH_ENABLED(APB2, value); + } else { + ret = FURI_HAL_BUS_IS_RESET_DEASSERTED(APB3, value); + } + FURI_CRITICAL_EXIT(); + + return ret; +} diff --git a/firmware/targets/f7/furi_hal/furi_hal_bus.h b/firmware/targets/f7/furi_hal/furi_hal_bus.h new file mode 100644 index 000000000000..ad4bbec32496 --- /dev/null +++ b/firmware/targets/f7/furi_hal/furi_hal_bus.h @@ -0,0 +1,112 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stm32wbxx.h" +#include "stdbool.h" + +typedef enum { + FuriHalBusAHB1_GRP1, + FuriHalBusDMA1, + FuriHalBusDMA2, + FuriHalBusDMAMUX1, + FuriHalBusCRC, + FuriHalBusTSC, + + FuriHalBusAHB2_GRP1, + FuriHalBusGPIOA, + FuriHalBusGPIOB, + FuriHalBusGPIOC, + FuriHalBusGPIOD, + FuriHalBusGPIOE, + FuriHalBusGPIOH, +#if defined(ADC_SUPPORT_5_MSPS) + FuriHalBusADC, +#endif + FuriHalBusAES1, + + FuriHalBusAHB3_GRP1, + FuriHalBusQUADSPI, + FuriHalBusPKA, + FuriHalBusAES2, + FuriHalBusRNG, + FuriHalBusHSEM, + FuriHalBusIPCC, + FuriHalBusFLASH, + + FuriHalBusAPB1_GRP1, + FuriHalBusTIM2, + FuriHalBusLCD, + FuriHalBusSPI2, + FuriHalBusI2C1, + FuriHalBusI2C3, + FuriHalBusCRS, + FuriHalBusUSB, + FuriHalBusLPTIM1, + + FuriHalBusAPB1_GRP2, + FuriHalBusLPUART1, + FuriHalBusLPTIM2, + + FuriHalBusAPB2_GRP1, +#if defined(ADC_SUPPORT_2_5_MSPS) + FuriHalBusADC, +#endif + FuriHalBusTIM1, + FuriHalBusSPI1, + FuriHalBusUSART1, + FuriHalBusTIM16, + FuriHalBusTIM17, + FuriHalBusSAI1, + + FuriHalBusAPB3_GRP1, + FuriHalBusRF, + + FuriHalBusMAX, +} FuriHalBus; + +/** Early initialization */ +void furi_hal_bus_init_early(); + +/** Early de-initialization */ +void furi_hal_bus_deinit_early(); + +/** + * Enable a peripheral by turning the clocking on and deasserting the reset. + * @param [in] bus Peripheral to be enabled. + * @warning Peripheral must be in disabled state in order to be enabled. + */ +void furi_hal_bus_enable(FuriHalBus bus); + +/** + * Reset a peripheral by sequentially asserting and deasserting the reset. + * @param [in] bus Peripheral to be reset. + * @warning Peripheral must be in enabled state in order to be reset. + */ +void furi_hal_bus_reset(FuriHalBus bus); + +/** + * Disable a peripheral by turning the clocking off and asserting the reset. + * @param [in] bus Peripheral to be disabled. + * @warning Peripheral must be in enabled state in order to be disabled. + */ +void furi_hal_bus_disable(FuriHalBus bus); + +/** Check if peripheral is enabled + * + * @warning FuriHalBusAPB3_GRP1 is a special group of shared peripherals, for + * core1 its clock is always on and the only status we can report is + * peripheral reset status. Check code and Reference Manual for + * details. + * + * @param[in] bus The peripheral to check + * + * @return true if enabled or always enabled, false otherwise + */ +bool furi_hal_bus_is_enabled(FuriHalBus bus); + +#ifdef __cplusplus +} +#endif diff --git a/firmware/targets/f7/furi_hal/furi_hal_clock.c b/firmware/targets/f7/furi_hal/furi_hal_clock.c index a76fbfbca767..736ad9f7c054 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_clock.c +++ b/firmware/targets/f7/furi_hal/furi_hal_clock.c @@ -6,7 +6,6 @@ #include #include #include -#include #define TAG "FuriHalClock" @@ -19,36 +18,9 @@ void furi_hal_clock_init_early() { LL_SetSystemCoreClock(CPU_CLOCK_HZ_EARLY); LL_Init1msTick(SystemCoreClock); - - LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA); - LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB); - LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOC); - LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOD); - LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOE); - LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOH); - - LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI1); - LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_SPI2); - - LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_LPTIM2); - - LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1); - LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C3); } void furi_hal_clock_deinit_early() { - LL_APB1_GRP1_DisableClock(LL_APB1_GRP1_PERIPH_I2C1); - LL_APB1_GRP1_DisableClock(LL_APB1_GRP1_PERIPH_I2C3); - - LL_APB2_GRP1_DisableClock(LL_APB2_GRP1_PERIPH_SPI1); - LL_APB1_GRP1_DisableClock(LL_APB1_GRP1_PERIPH_SPI2); - - LL_AHB2_GRP1_DisableClock(LL_AHB2_GRP1_PERIPH_GPIOA); - LL_AHB2_GRP1_DisableClock(LL_AHB2_GRP1_PERIPH_GPIOB); - LL_AHB2_GRP1_DisableClock(LL_AHB2_GRP1_PERIPH_GPIOC); - LL_AHB2_GRP1_DisableClock(LL_AHB2_GRP1_PERIPH_GPIOD); - LL_AHB2_GRP1_DisableClock(LL_AHB2_GRP1_PERIPH_GPIOE); - LL_AHB2_GRP1_DisableClock(LL_AHB2_GRP1_PERIPH_GPIOH); } void furi_hal_clock_init() { @@ -76,6 +48,10 @@ void furi_hal_clock_init() { LL_RCC_LSI1_Enable(); while(!LS_CLOCK_IS_READY()) ; + + /* RF wakeup */ + LL_RCC_SetRFWKPClockSource(LL_RCC_RFWKP_CLKSOURCE_LSE); + LL_EXTI_EnableIT_0_31( LL_EXTI_LINE_18); /* Why? Because that's why. See RM0434, Table 61. CPU1 vector table. */ LL_EXTI_EnableRisingTrig_0_31(LL_EXTI_LINE_18); @@ -137,68 +113,12 @@ void furi_hal_clock_init() { SysTick_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), TICK_INT_PRIORITY, 0)); NVIC_EnableIRQ(SysTick_IRQn); - LL_RCC_SetUSARTClockSource(LL_RCC_USART1_CLKSOURCE_PCLK2); - LL_RCC_SetLPUARTClockSource(LL_RCC_LPUART1_CLKSOURCE_PCLK1); - LL_RCC_SetADCClockSource(LL_RCC_ADC_CLKSOURCE_PLLSAI1); - LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_PCLK1); - LL_RCC_SetRNGClockSource(LL_RCC_RNG_CLKSOURCE_CLK48); - LL_RCC_SetUSBClockSource(LL_RCC_USB_CLKSOURCE_PLLSAI1); LL_RCC_SetCLK48ClockSource(LL_RCC_CLK48_CLKSOURCE_PLLSAI1); LL_RCC_HSI_EnableInStopMode(); // Ensure that MR is capable of work in STOP0 - LL_RCC_SetSMPSClockSource(LL_RCC_SMPS_CLKSOURCE_HSE); + LL_RCC_SetSMPSClockSource(LL_RCC_SMPS_CLKSOURCE_HSI); LL_RCC_SetSMPSPrescaler(LL_RCC_SMPS_DIV_1); LL_RCC_SetRFWKPClockSource(LL_RCC_RFWKP_CLKSOURCE_LSE); - // AHB1 GRP1 - LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1); - LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA2); - LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMAMUX1); - LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_CRC); - // LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_TSC); - - // AHB2 GRP1 - LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA); - LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB); - LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOC); - LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOD); - LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOE); - LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOH); - LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_ADC); - LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_AES1); - - // AHB3 GRP1 - // LL_AHB3_GRP1_EnableClock(LL_AHB3_GRP1_PERIPH_QUADSPI); - LL_AHB3_GRP1_EnableClock(LL_AHB3_GRP1_PERIPH_PKA); - LL_AHB3_GRP1_EnableClock(LL_AHB3_GRP1_PERIPH_AES2); - LL_AHB3_GRP1_EnableClock(LL_AHB3_GRP1_PERIPH_RNG); - LL_AHB3_GRP1_EnableClock(LL_AHB3_GRP1_PERIPH_HSEM); - LL_AHB3_GRP1_EnableClock(LL_AHB3_GRP1_PERIPH_IPCC); - LL_AHB3_GRP1_EnableClock(LL_AHB3_GRP1_PERIPH_FLASH); - - // APB1 GRP1 - LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM2); - // LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_LCD); - LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_RTCAPB); - // LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_WWDG); - LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_SPI2); - LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1); - LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C3); - LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_CRS); - LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_USB); - LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_LPTIM1); - - // APB1 GRP2 - LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_LPUART1); - - // APB2 - // LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_ADC); - LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_TIM1); - LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI1); - LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_USART1); - LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_TIM16); - LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_TIM17); - // LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SAI1); - FURI_LOG_I(TAG, "Init OK"); } @@ -208,8 +128,8 @@ void furi_hal_clock_switch_to_hsi() { while(!LL_RCC_HSI_IsReady()) ; - LL_RCC_SetSMPSClockSource(LL_RCC_SMPS_CLKSOURCE_HSI); LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_HSI); + furi_assert(LL_RCC_GetSMPSClockSource() == LL_RCC_SMPS_CLKSOURCE_HSI); while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSI) ; @@ -222,6 +142,10 @@ void furi_hal_clock_switch_to_hsi() { } void furi_hal_clock_switch_to_pll() { +#ifdef FURI_HAL_CLOCK_TRACK_STARTUP + uint32_t clock_start_time = DWT->CYCCNT; +#endif + LL_RCC_HSE_Enable(); LL_RCC_PLL_Enable(); LL_RCC_PLLSAI1_Enable(); @@ -240,10 +164,16 @@ void furi_hal_clock_switch_to_pll() { ; LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL); - LL_RCC_SetSMPSClockSource(LL_RCC_SMPS_CLKSOURCE_HSE); while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL) ; + +#ifdef FURI_HAL_CLOCK_TRACK_STARTUP + uint32_t total = DWT->CYCCNT - clock_start_time; + if(total > (20 * 0x148)) { + furi_crash("Slow HSE/PLL startup"); + } +#endif } void furi_hal_clock_suspend_tick() { diff --git a/firmware/targets/f7/furi_hal/furi_hal_crypto.c b/firmware/targets/f7/furi_hal/furi_hal_crypto.c index e0ed3ab9be26..eb5c3b782c86 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_crypto.c +++ b/firmware/targets/f7/furi_hal/furi_hal_crypto.c @@ -1,8 +1,9 @@ #include #include #include +#include + #include -#include #include #include @@ -241,6 +242,8 @@ bool furi_hal_crypto_store_load_key(uint8_t slot, const uint8_t* iv) { furi_assert(furi_hal_crypto_mutex); furi_check(furi_mutex_acquire(furi_hal_crypto_mutex, FuriWaitForever) == FuriStatusOk); + furi_hal_bus_enable(FuriHalBusAES1); + if(!furi_hal_bt_is_alive()) { return false; } @@ -267,10 +270,7 @@ bool furi_hal_crypto_store_unload_key(uint8_t slot) { SHCI_CmdStatus_t shci_state = SHCI_C2_FUS_UnloadUsrKey(slot); furi_assert(shci_state == SHCI_Success); - FURI_CRITICAL_ENTER(); - LL_AHB2_GRP1_ForceReset(LL_AHB2_GRP1_PERIPH_AES1); - LL_AHB2_GRP1_ReleaseReset(LL_AHB2_GRP1_PERIPH_AES1); - FURI_CRITICAL_EXIT(); + furi_hal_bus_disable(FuriHalBusAES1); furi_check(furi_mutex_release(furi_hal_crypto_mutex) == FuriStatusOk); return (shci_state == SHCI_Success); diff --git a/firmware/targets/f7/furi_hal/furi_hal_dma.c b/firmware/targets/f7/furi_hal/furi_hal_dma.c new file mode 100644 index 000000000000..a6a30d906dae --- /dev/null +++ b/firmware/targets/f7/furi_hal/furi_hal_dma.c @@ -0,0 +1,14 @@ +#include +#include + +void furi_hal_dma_init_early() { + furi_hal_bus_enable(FuriHalBusDMA1); + furi_hal_bus_enable(FuriHalBusDMA2); + furi_hal_bus_enable(FuriHalBusDMAMUX1); +} + +void furi_hal_dma_deinit_early() { + furi_hal_bus_disable(FuriHalBusDMA1); + furi_hal_bus_disable(FuriHalBusDMA2); + furi_hal_bus_disable(FuriHalBusDMAMUX1); +} diff --git a/firmware/targets/f7/furi_hal/furi_hal_dma.h b/firmware/targets/f7/furi_hal/furi_hal_dma.h new file mode 100644 index 000000000000..cadcc7733e07 --- /dev/null +++ b/firmware/targets/f7/furi_hal/furi_hal_dma.h @@ -0,0 +1,15 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +/** Early initialization */ +void furi_hal_dma_init_early(); + +/** Early de-initialization */ +void furi_hal_dma_deinit_early(); + +#ifdef __cplusplus +} +#endif diff --git a/firmware/targets/f7/furi_hal/furi_hal_flash.c b/firmware/targets/f7/furi_hal/furi_hal_flash.c index 94d269345ba7..796d20b19fa8 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_flash.c +++ b/firmware/targets/f7/furi_hal/furi_hal_flash.c @@ -11,20 +11,20 @@ #define TAG "FuriHalFlash" #define FURI_HAL_CRITICAL_MSG "Critical flash operation fail" -#define FURI_HAL_FLASH_READ_BLOCK 8 -#define FURI_HAL_FLASH_WRITE_BLOCK 8 -#define FURI_HAL_FLASH_PAGE_SIZE 4096 -#define FURI_HAL_FLASH_CYCLES_COUNT 10000 -#define FURI_HAL_FLASH_TIMEOUT 1000 -#define FURI_HAL_FLASH_KEY1 0x45670123U -#define FURI_HAL_FLASH_KEY2 0xCDEF89ABU -#define FURI_HAL_FLASH_TOTAL_PAGES 256 +#define FURI_HAL_FLASH_READ_BLOCK (8U) +#define FURI_HAL_FLASH_WRITE_BLOCK (8U) +#define FURI_HAL_FLASH_PAGE_SIZE (4096U) +#define FURI_HAL_FLASH_CYCLES_COUNT (10000U) +#define FURI_HAL_FLASH_TIMEOUT (1000U) +#define FURI_HAL_FLASH_KEY1 (0x45670123U) +#define FURI_HAL_FLASH_KEY2 (0xCDEF89ABU) +#define FURI_HAL_FLASH_TOTAL_PAGES (256U) #define FURI_HAL_FLASH_SR_ERRORS \ (FLASH_SR_OPERR | FLASH_SR_PROGERR | FLASH_SR_WRPERR | FLASH_SR_PGAERR | FLASH_SR_SIZERR | \ FLASH_SR_PGSERR | FLASH_SR_MISERR | FLASH_SR_FASTERR | FLASH_SR_RDERR | FLASH_SR_OPTVERR) -#define FURI_HAL_FLASH_OPT_KEY1 0x08192A3B -#define FURI_HAL_FLASH_OPT_KEY2 0x4C5D6E7F +#define FURI_HAL_FLASH_OPT_KEY1 (0x08192A3BU) +#define FURI_HAL_FLASH_OPT_KEY2 (0x4C5D6E7FU) #define FURI_HAL_FLASH_OB_TOTAL_WORDS (0x80 / (sizeof(uint32_t) * 2)) /* STM32CubeWB/Projects/P-NUCLEO-WB55.Nucleo/Applications/BLE/BLE_RfWithFlash/Core/Src/flash_driver.c @@ -35,7 +35,7 @@ > If for any reason this test is never passed, this means there is a failure in the system and there is no other > way to recover than applying a device reset. */ -#define FURI_HAL_FLASH_C2_LOCK_TIMEOUT_MS 3000u /* 3 seconds */ +#define FURI_HAL_FLASH_C2_LOCK_TIMEOUT_MS (3000U) /* 3 seconds */ #define IS_ADDR_ALIGNED_64BITS(__VALUE__) (((__VALUE__)&0x7U) == (0x00UL)) #define IS_FLASH_PROGRAM_ADDRESS(__VALUE__) \ diff --git a/firmware/targets/f7/furi_hal/furi_hal_i2c_config.c b/firmware/targets/f7/furi_hal/furi_hal_i2c_config.c index afc4fdf5247c..f9d88abb3763 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_i2c_config.c +++ b/firmware/targets/f7/furi_hal/furi_hal_i2c_config.c @@ -1,7 +1,8 @@ #include #include #include -#include +#include + #include /** Timing register value is computed with the STM32CubeMX Tool, @@ -21,17 +22,9 @@ FuriMutex* furi_hal_i2c_bus_power_mutex = NULL; static void furi_hal_i2c_bus_power_event(FuriHalI2cBus* bus, FuriHalI2cBusEvent event) { if(event == FuriHalI2cBusEventInit) { furi_hal_i2c_bus_power_mutex = furi_mutex_alloc(FuriMutexTypeNormal); - FURI_CRITICAL_ENTER(); - LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_PCLK1); - LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C1); - FURI_CRITICAL_EXIT(); bus->current_handle = NULL; } else if(event == FuriHalI2cBusEventDeinit) { furi_mutex_free(furi_hal_i2c_bus_power_mutex); - FURI_CRITICAL_ENTER(); - LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C1); - LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_I2C1); - FURI_CRITICAL_EXIT(); } else if(event == FuriHalI2cBusEventLock) { furi_check( furi_mutex_acquire(furi_hal_i2c_bus_power_mutex, FuriWaitForever) == FuriStatusOk); @@ -39,12 +32,11 @@ static void furi_hal_i2c_bus_power_event(FuriHalI2cBus* bus, FuriHalI2cBusEvent furi_check(furi_mutex_release(furi_hal_i2c_bus_power_mutex) == FuriStatusOk); } else if(event == FuriHalI2cBusEventActivate) { FURI_CRITICAL_ENTER(); - LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_I2C1); + furi_hal_bus_enable(FuriHalBusI2C1); + LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_PCLK1); FURI_CRITICAL_EXIT(); } else if(event == FuriHalI2cBusEventDeactivate) { - FURI_CRITICAL_ENTER(); - LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C1); - FURI_CRITICAL_EXIT(); + furi_hal_bus_disable(FuriHalBusI2C1); } } @@ -58,17 +50,9 @@ FuriMutex* furi_hal_i2c_bus_external_mutex = NULL; static void furi_hal_i2c_bus_external_event(FuriHalI2cBus* bus, FuriHalI2cBusEvent event) { if(event == FuriHalI2cBusEventInit) { furi_hal_i2c_bus_external_mutex = furi_mutex_alloc(FuriMutexTypeNormal); - FURI_CRITICAL_ENTER(); - LL_RCC_SetI2CClockSource(LL_RCC_I2C3_CLKSOURCE_PCLK1); - LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C3); - FURI_CRITICAL_EXIT(); bus->current_handle = NULL; } else if(event == FuriHalI2cBusEventDeinit) { furi_mutex_free(furi_hal_i2c_bus_external_mutex); - FURI_CRITICAL_ENTER(); - LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C3); - LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_I2C3); - FURI_CRITICAL_EXIT(); } else if(event == FuriHalI2cBusEventLock) { furi_check( furi_mutex_acquire(furi_hal_i2c_bus_external_mutex, FuriWaitForever) == FuriStatusOk); @@ -76,13 +60,11 @@ static void furi_hal_i2c_bus_external_event(FuriHalI2cBus* bus, FuriHalI2cBusEve furi_check(furi_mutex_release(furi_hal_i2c_bus_external_mutex) == FuriStatusOk); } else if(event == FuriHalI2cBusEventActivate) { FURI_CRITICAL_ENTER(); + furi_hal_bus_enable(FuriHalBusI2C3); LL_RCC_SetI2CClockSource(LL_RCC_I2C3_CLKSOURCE_PCLK1); - LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_I2C3); FURI_CRITICAL_EXIT(); } else if(event == FuriHalI2cBusEventDeactivate) { - FURI_CRITICAL_ENTER(); - LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C3); - FURI_CRITICAL_EXIT(); + furi_hal_bus_disable(FuriHalBusI2C3); } } diff --git a/firmware/targets/f7/furi_hal/furi_hal_ibutton.c b/firmware/targets/f7/furi_hal/furi_hal_ibutton.c index c8041c9f2cd1..f8f7e4966dc9 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_ibutton.c +++ b/firmware/targets/f7/furi_hal/furi_hal_ibutton.c @@ -1,14 +1,15 @@ #include #include #include +#include #include -#include #include #define TAG "FuriHalIbutton" #define FURI_HAL_IBUTTON_TIMER TIM1 +#define FURI_HAL_IBUTTON_TIMER_BUS FuriHalBusTIM1 #define FURI_HAL_IBUTTON_TIMER_IRQ FuriHalInterruptIdTim1UpTim16 typedef enum { @@ -49,9 +50,7 @@ void furi_hal_ibutton_emulate_start( furi_hal_ibutton->callback = callback; furi_hal_ibutton->context = context; - FURI_CRITICAL_ENTER(); - LL_TIM_DeInit(FURI_HAL_IBUTTON_TIMER); - FURI_CRITICAL_EXIT(); + furi_hal_bus_enable(FURI_HAL_IBUTTON_TIMER_BUS); furi_hal_interrupt_set_isr(FURI_HAL_IBUTTON_TIMER_IRQ, furi_hal_ibutton_emulate_isr, NULL); @@ -81,10 +80,7 @@ void furi_hal_ibutton_emulate_stop() { furi_hal_ibutton->state = FuriHalIbuttonStateIdle; LL_TIM_DisableCounter(FURI_HAL_IBUTTON_TIMER); - FURI_CRITICAL_ENTER(); - LL_TIM_DeInit(FURI_HAL_IBUTTON_TIMER); - FURI_CRITICAL_EXIT(); - + furi_hal_bus_disable(FURI_HAL_IBUTTON_TIMER_BUS); furi_hal_interrupt_set_isr(FURI_HAL_IBUTTON_TIMER_IRQ, NULL, NULL); furi_hal_ibutton->callback = NULL; diff --git a/firmware/targets/f7/furi_hal/furi_hal_idle_timer.h b/firmware/targets/f7/furi_hal/furi_hal_idle_timer.h index 36b45755a924..e1ffb1b25f41 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_idle_timer.h +++ b/firmware/targets/f7/furi_hal/furi_hal_idle_timer.h @@ -1,9 +1,10 @@ #pragma once #include -#include #include -#include +#include + +#include // Timer used for tickless idle #define FURI_HAL_IDLE_TIMER_MAX 0xFFFF @@ -11,6 +12,7 @@ #define FURI_HAL_IDLE_TIMER_IRQ LPTIM1_IRQn static inline void furi_hal_idle_timer_init() { + furi_hal_bus_enable(FuriHalBusLPTIM1); // Configure clock source LL_RCC_SetLPTIMClockSource(LL_RCC_LPTIM1_CLKSOURCE_LSE); // There is a theoretical possibility that we need it @@ -41,7 +43,7 @@ static inline void furi_hal_idle_timer_start(uint32_t count) { static inline void furi_hal_idle_timer_reset() { // Hard reset timer // THE ONLY RELIABLE WAY to stop it according to errata - LL_LPTIM_DeInit(FURI_HAL_IDLE_TIMER); + furi_hal_bus_reset(FuriHalBusLPTIM1); // Prevent IRQ handler call NVIC_ClearPendingIRQ(FURI_HAL_IDLE_TIMER_IRQ); } diff --git a/firmware/targets/f7/furi_hal/furi_hal_info.c b/firmware/targets/f7/furi_hal/furi_hal_info.c index 4c034ff35217..a2c9232c0580 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_info.c +++ b/firmware/targets/f7/furi_hal/furi_hal_info.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -23,10 +24,10 @@ void furi_hal_info_get(PropertyValueCallback out, char sep, void* context) { // Device Info version if(sep == '.') { property_value_out(&property_context, NULL, 2, "format", "major", "3"); - property_value_out(&property_context, NULL, 2, "format", "minor", "1"); + property_value_out(&property_context, NULL, 2, "format", "minor", "2"); } else { property_value_out(&property_context, NULL, 3, "device", "info", "major", "2"); - property_value_out(&property_context, NULL, 3, "device", "info", "minor", "1"); + property_value_out(&property_context, NULL, 3, "device", "info", "minor", "3"); } // Model name @@ -173,6 +174,24 @@ void furi_hal_info_get(PropertyValueCallback out, char sep, void* context) { &property_context, "%d", 3, "firmware", "api", "major", api_version_major); property_value_out( &property_context, "%d", 3, "firmware", "api", "minor", api_version_minor); + + property_value_out( + &property_context, + NULL, + 3, + "firmware", + "origin", + "fork", + version_get_firmware_origin(firmware_version)); + + property_value_out( + &property_context, + NULL, + 3, + "firmware", + "origin", + "git", + version_get_git_origin(firmware_version)); } if(furi_hal_bt_is_alive()) { @@ -279,6 +298,18 @@ void furi_hal_info_get(PropertyValueCallback out, char sep, void* context) { property_value_out(&property_context, NULL, 2, "radio", "alive", "false"); } + property_value_out( + &property_context, + "%u", + 2, + "system", + "debug", + furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)); + property_value_out( + &property_context, "%u", 3, "system", "heap", "track", furi_hal_rtc_get_heap_track_mode()); + property_value_out( + &property_context, "%u", 3, "system", "log", "level", furi_hal_rtc_get_log_level()); + property_value_out( &property_context, "%u", 3, "protobuf", "version", "major", PROTOBUF_MAJOR_VERSION); property_context.last = true; diff --git a/firmware/targets/f7/furi_hal/furi_hal_infrared.c b/firmware/targets/f7/furi_hal/furi_hal_infrared.c index 2598e5fa314a..c60db5f20ef2 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_infrared.c +++ b/firmware/targets/f7/furi_hal/furi_hal_infrared.c @@ -1,23 +1,18 @@ #include -#include -#include "stm32wbxx_ll_dma.h" -#include "sys/_stdint.h" #include #include +#include -#include #include -#include +#include -#include #include #include -#define INFRARED_TX_DEBUG 0 +// #define INFRARED_TX_DEBUG -#if INFRARED_TX_DEBUG == 1 -#define gpio_infrared_tx gpio_infrared_tx_debug -const GpioPin gpio_infrared_tx_debug = {.port = GPIOA, .pin = GpioModeAnalog}; +#if defined INFRARED_TX_DEBUG +#define gpio_infrared_tx gpio_ext_pa7 #endif #define INFRARED_TIM_TX_DMA_BUFFER_SIZE 200 @@ -29,13 +24,23 @@ const GpioPin gpio_infrared_tx_debug = {.port = GPIOA, .pin = GpioModeAnalog}; (TIM_CCMR2_OC3PE | LL_TIM_OCMODE_FORCED_INACTIVE) /* Space time - force low */ /* DMA Channels definition */ -#define IR_DMA DMA2 -#define IR_DMA_CH1_CHANNEL LL_DMA_CHANNEL_1 -#define IR_DMA_CH2_CHANNEL LL_DMA_CHANNEL_2 -#define IR_DMA_CH1_IRQ FuriHalInterruptIdDma2Ch1 -#define IR_DMA_CH2_IRQ FuriHalInterruptIdDma2Ch2 -#define IR_DMA_CH1_DEF IR_DMA, IR_DMA_CH1_CHANNEL -#define IR_DMA_CH2_DEF IR_DMA, IR_DMA_CH2_CHANNEL +#define INFRARED_DMA DMA2 +#define INFRARED_DMA_CH1_CHANNEL LL_DMA_CHANNEL_1 +#define INFRARED_DMA_CH2_CHANNEL LL_DMA_CHANNEL_2 +#define INFRARED_DMA_CH1_IRQ FuriHalInterruptIdDma2Ch1 +#define INFRARED_DMA_CH2_IRQ FuriHalInterruptIdDma2Ch2 +#define INFRARED_DMA_CH1_DEF INFRARED_DMA, INFRARED_DMA_CH1_CHANNEL +#define INFRARED_DMA_CH2_DEF INFRARED_DMA, INFRARED_DMA_CH2_CHANNEL + +/* Timers definition */ +#define INFRARED_RX_TIMER TIM2 +#define INFRARED_DMA_TIMER TIM1 +#define INFRARED_RX_TIMER_BUS FuriHalBusTIM2 +#define INFRARED_DMA_TIMER_BUS FuriHalBusTIM1 + +/* Misc */ +#define INFRARED_RX_GPIO_ALT GpioAltFn1TIM2 +#define INFRARED_RX_IRQ FuriHalInterruptIdTIM2 typedef struct { FuriHalInfraredRxCaptureCallback capture_callback; @@ -93,8 +98,8 @@ static void furi_hal_infrared_tim_rx_isr() { static uint32_t previous_captured_ch2 = 0; /* Timeout */ - if(LL_TIM_IsActiveFlag_CC3(TIM2)) { - LL_TIM_ClearFlag_CC3(TIM2); + if(LL_TIM_IsActiveFlag_CC3(INFRARED_RX_TIMER)) { + LL_TIM_ClearFlag_CC3(INFRARED_RX_TIMER); furi_assert(furi_hal_infrared_state == InfraredStateAsyncRx); /* Timers CNT register starts to counting from 0 to ARR, but it is @@ -110,13 +115,13 @@ static void furi_hal_infrared_tim_rx_isr() { } /* Rising Edge */ - if(LL_TIM_IsActiveFlag_CC1(TIM2)) { - LL_TIM_ClearFlag_CC1(TIM2); + if(LL_TIM_IsActiveFlag_CC1(INFRARED_RX_TIMER)) { + LL_TIM_ClearFlag_CC1(INFRARED_RX_TIMER); furi_assert(furi_hal_infrared_state == InfraredStateAsyncRx); - if(READ_BIT(TIM2->CCMR1, TIM_CCMR1_CC1S)) { + if(READ_BIT(INFRARED_RX_TIMER->CCMR1, TIM_CCMR1_CC1S)) { /* Low pin level is a Mark state of INFRARED signal. Invert level for further processing. */ - uint32_t duration = LL_TIM_IC_GetCaptureCH1(TIM2) - previous_captured_ch2; + uint32_t duration = LL_TIM_IC_GetCaptureCH1(INFRARED_RX_TIMER) - previous_captured_ch2; if(infrared_tim_rx.capture_callback) infrared_tim_rx.capture_callback(infrared_tim_rx.capture_context, 1, duration); } else { @@ -125,13 +130,13 @@ static void furi_hal_infrared_tim_rx_isr() { } /* Falling Edge */ - if(LL_TIM_IsActiveFlag_CC2(TIM2)) { - LL_TIM_ClearFlag_CC2(TIM2); + if(LL_TIM_IsActiveFlag_CC2(INFRARED_RX_TIMER)) { + LL_TIM_ClearFlag_CC2(INFRARED_RX_TIMER); furi_assert(furi_hal_infrared_state == InfraredStateAsyncRx); - if(READ_BIT(TIM2->CCMR1, TIM_CCMR1_CC2S)) { + if(READ_BIT(INFRARED_RX_TIMER->CCMR1, TIM_CCMR1_CC2S)) { /* High pin level is a Space state of INFRARED signal. Invert level for further processing. */ - uint32_t duration = LL_TIM_IC_GetCaptureCH2(TIM2); + uint32_t duration = LL_TIM_IC_GetCaptureCH2(INFRARED_RX_TIMER); previous_captured_ch2 = duration; if(infrared_tim_rx.capture_callback) infrared_tim_rx.capture_callback(infrared_tim_rx.capture_context, 0, duration); @@ -145,62 +150,66 @@ void furi_hal_infrared_async_rx_start(void) { furi_assert(furi_hal_infrared_state == InfraredStateIdle); furi_hal_gpio_init_ex( - &gpio_infrared_rx, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedLow, GpioAltFn1TIM2); + &gpio_infrared_rx, + GpioModeAltFunctionPushPull, + GpioPullNo, + GpioSpeedLow, + INFRARED_RX_GPIO_ALT); + + furi_hal_bus_enable(INFRARED_RX_TIMER_BUS); LL_TIM_InitTypeDef TIM_InitStruct = {0}; TIM_InitStruct.Prescaler = 64 - 1; TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP; TIM_InitStruct.Autoreload = 0x7FFFFFFE; TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1; - LL_TIM_Init(TIM2, &TIM_InitStruct); - - LL_TIM_SetClockSource(TIM2, LL_TIM_CLOCKSOURCE_INTERNAL); - LL_TIM_DisableARRPreload(TIM2); - LL_TIM_SetTriggerInput(TIM2, LL_TIM_TS_TI1FP1); - LL_TIM_SetSlaveMode(TIM2, LL_TIM_SLAVEMODE_RESET); - LL_TIM_CC_DisableChannel(TIM2, LL_TIM_CHANNEL_CH2); - LL_TIM_IC_SetFilter(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_IC_FILTER_FDIV1); - LL_TIM_IC_SetPolarity(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_IC_POLARITY_FALLING); - LL_TIM_DisableIT_TRIG(TIM2); - LL_TIM_DisableDMAReq_TRIG(TIM2); - LL_TIM_SetTriggerOutput(TIM2, LL_TIM_TRGO_RESET); - LL_TIM_EnableMasterSlaveMode(TIM2); - LL_TIM_IC_SetActiveInput(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_ACTIVEINPUT_DIRECTTI); - LL_TIM_IC_SetPrescaler(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_ICPSC_DIV1); - LL_TIM_IC_SetFilter(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_IC_FILTER_FDIV1); - LL_TIM_IC_SetPolarity(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_IC_POLARITY_RISING); - LL_TIM_IC_SetActiveInput(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_ACTIVEINPUT_INDIRECTTI); - LL_TIM_IC_SetPrescaler(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_ICPSC_DIV1); - - furi_hal_interrupt_set_isr(FuriHalInterruptIdTIM2, furi_hal_infrared_tim_rx_isr, NULL); + LL_TIM_Init(INFRARED_RX_TIMER, &TIM_InitStruct); + + LL_TIM_SetClockSource(INFRARED_RX_TIMER, LL_TIM_CLOCKSOURCE_INTERNAL); + LL_TIM_DisableARRPreload(INFRARED_RX_TIMER); + LL_TIM_SetTriggerInput(INFRARED_RX_TIMER, LL_TIM_TS_TI1FP1); + LL_TIM_SetSlaveMode(INFRARED_RX_TIMER, LL_TIM_SLAVEMODE_RESET); + LL_TIM_CC_DisableChannel(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH2); + LL_TIM_IC_SetFilter(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH2, LL_TIM_IC_FILTER_FDIV1); + LL_TIM_IC_SetPolarity(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH2, LL_TIM_IC_POLARITY_FALLING); + LL_TIM_DisableIT_TRIG(INFRARED_RX_TIMER); + LL_TIM_DisableDMAReq_TRIG(INFRARED_RX_TIMER); + LL_TIM_SetTriggerOutput(INFRARED_RX_TIMER, LL_TIM_TRGO_RESET); + LL_TIM_EnableMasterSlaveMode(INFRARED_RX_TIMER); + LL_TIM_IC_SetActiveInput(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH1, LL_TIM_ACTIVEINPUT_DIRECTTI); + LL_TIM_IC_SetPrescaler(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH1, LL_TIM_ICPSC_DIV1); + LL_TIM_IC_SetFilter(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH1, LL_TIM_IC_FILTER_FDIV1); + LL_TIM_IC_SetPolarity(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH1, LL_TIM_IC_POLARITY_RISING); + LL_TIM_IC_SetActiveInput(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH2, LL_TIM_ACTIVEINPUT_INDIRECTTI); + LL_TIM_IC_SetPrescaler(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH2, LL_TIM_ICPSC_DIV1); + + furi_hal_interrupt_set_isr(INFRARED_RX_IRQ, furi_hal_infrared_tim_rx_isr, NULL); furi_hal_infrared_state = InfraredStateAsyncRx; - LL_TIM_EnableIT_CC1(TIM2); - LL_TIM_EnableIT_CC2(TIM2); - LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH1); - LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH2); + LL_TIM_EnableIT_CC1(INFRARED_RX_TIMER); + LL_TIM_EnableIT_CC2(INFRARED_RX_TIMER); + LL_TIM_CC_EnableChannel(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH1); + LL_TIM_CC_EnableChannel(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH2); - LL_TIM_SetCounter(TIM2, 0); - LL_TIM_EnableCounter(TIM2); + LL_TIM_SetCounter(INFRARED_RX_TIMER, 0); + LL_TIM_EnableCounter(INFRARED_RX_TIMER); } void furi_hal_infrared_async_rx_stop(void) { furi_assert(furi_hal_infrared_state == InfraredStateAsyncRx); FURI_CRITICAL_ENTER(); - - LL_TIM_DeInit(TIM2); - furi_hal_interrupt_set_isr(FuriHalInterruptIdTIM2, NULL, NULL); + furi_hal_bus_disable(INFRARED_RX_TIMER_BUS); + furi_hal_interrupt_set_isr(INFRARED_RX_IRQ, NULL, NULL); furi_hal_infrared_state = InfraredStateIdle; - FURI_CRITICAL_EXIT(); } void furi_hal_infrared_async_rx_set_timeout(uint32_t timeout_us) { - LL_TIM_OC_SetCompareCH3(TIM2, timeout_us); - LL_TIM_OC_SetMode(TIM2, LL_TIM_CHANNEL_CH3, LL_TIM_OCMODE_ACTIVE); - LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH3); - LL_TIM_EnableIT_CC3(TIM2); + LL_TIM_OC_SetCompareCH3(INFRARED_RX_TIMER, timeout_us); + LL_TIM_OC_SetMode(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH3, LL_TIM_OCMODE_ACTIVE); + LL_TIM_CC_EnableChannel(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH3); + LL_TIM_EnableIT_CC3(INFRARED_RX_TIMER); } bool furi_hal_infrared_is_busy(void) { @@ -222,16 +231,16 @@ void furi_hal_infrared_async_rx_set_timeout_isr_callback( } static void furi_hal_infrared_tx_dma_terminate(void) { - LL_DMA_DisableIT_TC(IR_DMA_CH1_DEF); - LL_DMA_DisableIT_HT(IR_DMA_CH2_DEF); - LL_DMA_DisableIT_TC(IR_DMA_CH2_DEF); + LL_DMA_DisableIT_TC(INFRARED_DMA_CH1_DEF); + LL_DMA_DisableIT_HT(INFRARED_DMA_CH2_DEF); + LL_DMA_DisableIT_TC(INFRARED_DMA_CH2_DEF); furi_assert(furi_hal_infrared_state == InfraredStateAsyncTxStopInProgress); - LL_DMA_DisableIT_TC(IR_DMA_CH1_DEF); - LL_DMA_DisableChannel(IR_DMA_CH2_DEF); - LL_DMA_DisableChannel(IR_DMA_CH1_DEF); - LL_TIM_DisableCounter(TIM1); + LL_DMA_DisableIT_TC(INFRARED_DMA_CH1_DEF); + LL_DMA_DisableChannel(INFRARED_DMA_CH2_DEF); + LL_DMA_DisableChannel(INFRARED_DMA_CH1_DEF); + LL_TIM_DisableCounter(INFRARED_DMA_TIMER); FuriStatus status = furi_semaphore_release(infrared_tim_tx.stop_semaphore); furi_check(status == FuriStatusOk); furi_hal_infrared_state = InfraredStateAsyncTxStopped; @@ -239,7 +248,7 @@ static void furi_hal_infrared_tx_dma_terminate(void) { static uint8_t furi_hal_infrared_get_current_dma_tx_buffer(void) { uint8_t buf_num = 0; - uint32_t buffer_adr = LL_DMA_GetMemoryAddress(IR_DMA_CH2_DEF); + uint32_t buffer_adr = LL_DMA_GetMemoryAddress(INFRARED_DMA_CH2_DEF); if(buffer_adr == (uint32_t)infrared_tim_tx.buffer[0].data) { buf_num = 0; } else if(buffer_adr == (uint32_t)infrared_tim_tx.buffer[1].data) { @@ -251,13 +260,13 @@ static uint8_t furi_hal_infrared_get_current_dma_tx_buffer(void) { } static void furi_hal_infrared_tx_dma_polarity_isr() { -#if IR_DMA_CH1_CHANNEL == LL_DMA_CHANNEL_1 - if(LL_DMA_IsActiveFlag_TE1(IR_DMA)) { - LL_DMA_ClearFlag_TE1(IR_DMA); +#if INFRARED_DMA_CH1_CHANNEL == LL_DMA_CHANNEL_1 + if(LL_DMA_IsActiveFlag_TE1(INFRARED_DMA)) { + LL_DMA_ClearFlag_TE1(INFRARED_DMA); furi_crash(NULL); } - if(LL_DMA_IsActiveFlag_TC1(IR_DMA) && LL_DMA_IsEnabledIT_TC(IR_DMA_CH1_DEF)) { - LL_DMA_ClearFlag_TC1(IR_DMA); + if(LL_DMA_IsActiveFlag_TC1(INFRARED_DMA) && LL_DMA_IsEnabledIT_TC(INFRARED_DMA_CH1_DEF)) { + LL_DMA_ClearFlag_TC1(INFRARED_DMA); furi_check( (furi_hal_infrared_state == InfraredStateAsyncTx) || @@ -273,23 +282,23 @@ static void furi_hal_infrared_tx_dma_polarity_isr() { } static void furi_hal_infrared_tx_dma_isr() { -#if IR_DMA_CH2_CHANNEL == LL_DMA_CHANNEL_2 - if(LL_DMA_IsActiveFlag_TE2(IR_DMA)) { - LL_DMA_ClearFlag_TE2(IR_DMA); +#if INFRARED_DMA_CH2_CHANNEL == LL_DMA_CHANNEL_2 + if(LL_DMA_IsActiveFlag_TE2(INFRARED_DMA)) { + LL_DMA_ClearFlag_TE2(INFRARED_DMA); furi_crash(NULL); } - if(LL_DMA_IsActiveFlag_HT2(IR_DMA) && LL_DMA_IsEnabledIT_HT(IR_DMA_CH2_DEF)) { - LL_DMA_ClearFlag_HT2(IR_DMA); + if(LL_DMA_IsActiveFlag_HT2(INFRARED_DMA) && LL_DMA_IsEnabledIT_HT(INFRARED_DMA_CH2_DEF)) { + LL_DMA_ClearFlag_HT2(INFRARED_DMA); uint8_t buf_num = furi_hal_infrared_get_current_dma_tx_buffer(); uint8_t next_buf_num = !buf_num; if(infrared_tim_tx.buffer[buf_num].last_packet_end) { - LL_DMA_DisableIT_HT(IR_DMA_CH2_DEF); + LL_DMA_DisableIT_HT(INFRARED_DMA_CH2_DEF); } else if( !infrared_tim_tx.buffer[buf_num].packet_end || (furi_hal_infrared_state == InfraredStateAsyncTx)) { furi_hal_infrared_tx_fill_buffer(next_buf_num, 0); if(infrared_tim_tx.buffer[next_buf_num].last_packet_end) { - LL_DMA_DisableIT_HT(IR_DMA_CH2_DEF); + LL_DMA_DisableIT_HT(INFRARED_DMA_CH2_DEF); } } else if(furi_hal_infrared_state == InfraredStateAsyncTxStopReq) { /* fallthrough */ @@ -297,8 +306,8 @@ static void furi_hal_infrared_tx_dma_isr() { furi_crash(NULL); } } - if(LL_DMA_IsActiveFlag_TC2(IR_DMA) && LL_DMA_IsEnabledIT_TC(IR_DMA_CH2_DEF)) { - LL_DMA_ClearFlag_TC2(IR_DMA); + if(LL_DMA_IsActiveFlag_TC2(INFRARED_DMA) && LL_DMA_IsEnabledIT_TC(INFRARED_DMA_CH2_DEF)) { + LL_DMA_ClearFlag_TC2(INFRARED_DMA); furi_check( (furi_hal_infrared_state == InfraredStateAsyncTxStopInProgress) || (furi_hal_infrared_state == InfraredStateAsyncTxStopReq) || @@ -330,39 +339,40 @@ static void furi_hal_infrared_tx_dma_isr() { } static void furi_hal_infrared_configure_tim_pwm_tx(uint32_t freq, float duty_cycle) { - /* LL_DBGMCU_APB2_GRP1_FreezePeriph(LL_DBGMCU_APB2_GRP1_TIM1_STOP); */ - - LL_TIM_DisableCounter(TIM1); - LL_TIM_SetRepetitionCounter(TIM1, 0); - LL_TIM_SetCounter(TIM1, 0); - LL_TIM_SetPrescaler(TIM1, 0); - LL_TIM_SetCounterMode(TIM1, LL_TIM_COUNTERMODE_UP); - LL_TIM_EnableARRPreload(TIM1); + LL_TIM_DisableCounter(INFRARED_DMA_TIMER); + LL_TIM_SetRepetitionCounter(INFRARED_DMA_TIMER, 0); + LL_TIM_SetCounter(INFRARED_DMA_TIMER, 0); + LL_TIM_SetPrescaler(INFRARED_DMA_TIMER, 0); + LL_TIM_SetCounterMode(INFRARED_DMA_TIMER, LL_TIM_COUNTERMODE_UP); + LL_TIM_EnableARRPreload(INFRARED_DMA_TIMER); LL_TIM_SetAutoReload( - TIM1, __LL_TIM_CALC_ARR(SystemCoreClock, LL_TIM_GetPrescaler(TIM1), freq)); -#if INFRARED_TX_DEBUG == 1 - LL_TIM_OC_SetCompareCH1(TIM1, ((LL_TIM_GetAutoReload(TIM1) + 1) * (1 - duty_cycle))); - LL_TIM_OC_EnablePreload(TIM1, LL_TIM_CHANNEL_CH1); + INFRARED_DMA_TIMER, + __LL_TIM_CALC_ARR(SystemCoreClock, LL_TIM_GetPrescaler(INFRARED_DMA_TIMER), freq)); +#if defined INFRARED_TX_DEBUG + LL_TIM_OC_SetCompareCH1( + INFRARED_DMA_TIMER, ((LL_TIM_GetAutoReload(INFRARED_DMA_TIMER) + 1) * (1 - duty_cycle))); + LL_TIM_OC_EnablePreload(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH1); /* LL_TIM_OCMODE_PWM2 set by DMA */ - LL_TIM_OC_SetMode(TIM1, LL_TIM_CHANNEL_CH1, LL_TIM_OCMODE_FORCED_INACTIVE); - LL_TIM_OC_SetPolarity(TIM1, LL_TIM_CHANNEL_CH1N, LL_TIM_OCPOLARITY_HIGH); - LL_TIM_OC_DisableFast(TIM1, LL_TIM_CHANNEL_CH1); - LL_TIM_CC_EnableChannel(TIM1, LL_TIM_CHANNEL_CH1N); - LL_TIM_DisableIT_CC1(TIM1); + LL_TIM_OC_SetMode(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH1, LL_TIM_OCMODE_FORCED_INACTIVE); + LL_TIM_OC_SetPolarity(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH1N, LL_TIM_OCPOLARITY_HIGH); + LL_TIM_OC_DisableFast(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH1); + LL_TIM_CC_EnableChannel(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH1N); + LL_TIM_DisableIT_CC1(INFRARED_DMA_TIMER); #else - LL_TIM_OC_SetCompareCH3(TIM1, ((LL_TIM_GetAutoReload(TIM1) + 1) * (1 - duty_cycle))); - LL_TIM_OC_EnablePreload(TIM1, LL_TIM_CHANNEL_CH3); + LL_TIM_OC_SetCompareCH3( + INFRARED_DMA_TIMER, ((LL_TIM_GetAutoReload(INFRARED_DMA_TIMER) + 1) * (1 - duty_cycle))); + LL_TIM_OC_EnablePreload(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH3); /* LL_TIM_OCMODE_PWM2 set by DMA */ - LL_TIM_OC_SetMode(TIM1, LL_TIM_CHANNEL_CH3, LL_TIM_OCMODE_FORCED_INACTIVE); - LL_TIM_OC_SetPolarity(TIM1, LL_TIM_CHANNEL_CH3N, LL_TIM_OCPOLARITY_HIGH); - LL_TIM_OC_DisableFast(TIM1, LL_TIM_CHANNEL_CH3); - LL_TIM_CC_EnableChannel(TIM1, LL_TIM_CHANNEL_CH3N); - LL_TIM_DisableIT_CC3(TIM1); + LL_TIM_OC_SetMode(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH3, LL_TIM_OCMODE_FORCED_INACTIVE); + LL_TIM_OC_SetPolarity(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH3N, LL_TIM_OCPOLARITY_HIGH); + LL_TIM_OC_DisableFast(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH3); + LL_TIM_CC_EnableChannel(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH3N); + LL_TIM_DisableIT_CC3(INFRARED_DMA_TIMER); #endif - LL_TIM_DisableMasterSlaveMode(TIM1); - LL_TIM_EnableAllOutputs(TIM1); - LL_TIM_DisableIT_UPDATE(TIM1); - LL_TIM_EnableDMAReq_UPDATE(TIM1); + LL_TIM_DisableMasterSlaveMode(INFRARED_DMA_TIMER); + LL_TIM_EnableAllOutputs(INFRARED_DMA_TIMER); + LL_TIM_DisableIT_UPDATE(INFRARED_DMA_TIMER); + LL_TIM_EnableDMAReq_UPDATE(INFRARED_DMA_TIMER); NVIC_SetPriority(TIM1_UP_TIM16_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0)); NVIC_EnableIRQ(TIM1_UP_TIM16_IRQn); @@ -370,10 +380,10 @@ static void furi_hal_infrared_configure_tim_pwm_tx(uint32_t freq, float duty_cyc static void furi_hal_infrared_configure_tim_cmgr2_dma_tx(void) { LL_DMA_InitTypeDef dma_config = {0}; -#if INFRARED_TX_DEBUG == 1 - dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (TIM1->CCMR1); +#if defined INFRARED_TX_DEBUG + dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (INFRARED_DMA_TIMER->CCMR1); #else - dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (TIM1->CCMR2); + dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (INFRARED_DMA_TIMER->CCMR2); #endif dma_config.MemoryOrM2MDstAddress = (uint32_t)NULL; dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; @@ -386,24 +396,25 @@ static void furi_hal_infrared_configure_tim_cmgr2_dma_tx(void) { dma_config.NbData = 0; dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM1_UP; dma_config.Priority = LL_DMA_PRIORITY_VERYHIGH; - LL_DMA_Init(IR_DMA_CH1_DEF, &dma_config); + LL_DMA_Init(INFRARED_DMA_CH1_DEF, &dma_config); -#if IR_DMA_CH1_CHANNEL == LL_DMA_CHANNEL_1 - LL_DMA_ClearFlag_TE1(IR_DMA); - LL_DMA_ClearFlag_TC1(IR_DMA); +#if INFRARED_DMA_CH1_CHANNEL == LL_DMA_CHANNEL_1 + LL_DMA_ClearFlag_TE1(INFRARED_DMA); + LL_DMA_ClearFlag_TC1(INFRARED_DMA); #else #error Update this code. Would you kindly? #endif - LL_DMA_EnableIT_TE(IR_DMA_CH1_DEF); - LL_DMA_EnableIT_TC(IR_DMA_CH1_DEF); + LL_DMA_EnableIT_TE(INFRARED_DMA_CH1_DEF); + LL_DMA_EnableIT_TC(INFRARED_DMA_CH1_DEF); - furi_hal_interrupt_set_isr_ex(IR_DMA_CH1_IRQ, 4, furi_hal_infrared_tx_dma_polarity_isr, NULL); + furi_hal_interrupt_set_isr_ex( + INFRARED_DMA_CH1_IRQ, 4, furi_hal_infrared_tx_dma_polarity_isr, NULL); } static void furi_hal_infrared_configure_tim_rcr_dma_tx(void) { LL_DMA_InitTypeDef dma_config = {0}; - dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (TIM1->RCR); + dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (INFRARED_DMA_TIMER->RCR); dma_config.MemoryOrM2MDstAddress = (uint32_t)NULL; dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; dma_config.Mode = LL_DMA_MODE_NORMAL; @@ -414,21 +425,21 @@ static void furi_hal_infrared_configure_tim_rcr_dma_tx(void) { dma_config.NbData = 0; dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM1_UP; dma_config.Priority = LL_DMA_PRIORITY_MEDIUM; - LL_DMA_Init(IR_DMA_CH2_DEF, &dma_config); + LL_DMA_Init(INFRARED_DMA_CH2_DEF, &dma_config); -#if IR_DMA_CH2_CHANNEL == LL_DMA_CHANNEL_2 - LL_DMA_ClearFlag_TC2(IR_DMA); - LL_DMA_ClearFlag_HT2(IR_DMA); - LL_DMA_ClearFlag_TE2(IR_DMA); +#if INFRARED_DMA_CH2_CHANNEL == LL_DMA_CHANNEL_2 + LL_DMA_ClearFlag_TC2(INFRARED_DMA); + LL_DMA_ClearFlag_HT2(INFRARED_DMA); + LL_DMA_ClearFlag_TE2(INFRARED_DMA); #else #error Update this code. Would you kindly? #endif - LL_DMA_EnableIT_TC(IR_DMA_CH2_DEF); - LL_DMA_EnableIT_HT(IR_DMA_CH2_DEF); - LL_DMA_EnableIT_TE(IR_DMA_CH2_DEF); + LL_DMA_EnableIT_TC(INFRARED_DMA_CH2_DEF); + LL_DMA_EnableIT_HT(INFRARED_DMA_CH2_DEF); + LL_DMA_EnableIT_TE(INFRARED_DMA_CH2_DEF); - furi_hal_interrupt_set_isr_ex(IR_DMA_CH2_IRQ, 5, furi_hal_infrared_tx_dma_isr, NULL); + furi_hal_interrupt_set_isr_ex(INFRARED_DMA_CH2_IRQ, 5, furi_hal_infrared_tx_dma_isr, NULL); } static void furi_hal_infrared_tx_fill_buffer_last(uint8_t buf_num) { @@ -530,14 +541,14 @@ static void furi_hal_infrared_tx_dma_set_polarity(uint8_t buf_num, uint8_t polar furi_assert(buffer->polarity != NULL); FURI_CRITICAL_ENTER(); - bool channel_enabled = LL_DMA_IsEnabledChannel(IR_DMA_CH1_DEF); + bool channel_enabled = LL_DMA_IsEnabledChannel(INFRARED_DMA_CH1_DEF); if(channel_enabled) { - LL_DMA_DisableChannel(IR_DMA_CH1_DEF); + LL_DMA_DisableChannel(INFRARED_DMA_CH1_DEF); } - LL_DMA_SetMemoryAddress(IR_DMA_CH1_DEF, (uint32_t)buffer->polarity); - LL_DMA_SetDataLength(IR_DMA_CH1_DEF, buffer->size + polarity_shift); + LL_DMA_SetMemoryAddress(INFRARED_DMA_CH1_DEF, (uint32_t)buffer->polarity); + LL_DMA_SetDataLength(INFRARED_DMA_CH1_DEF, buffer->size + polarity_shift); if(channel_enabled) { - LL_DMA_EnableChannel(IR_DMA_CH1_DEF); + LL_DMA_EnableChannel(INFRARED_DMA_CH1_DEF); } FURI_CRITICAL_EXIT(); } @@ -550,14 +561,14 @@ static void furi_hal_infrared_tx_dma_set_buffer(uint8_t buf_num) { /* non-circular mode requires disabled channel before setup */ FURI_CRITICAL_ENTER(); - bool channel_enabled = LL_DMA_IsEnabledChannel(IR_DMA_CH2_DEF); + bool channel_enabled = LL_DMA_IsEnabledChannel(INFRARED_DMA_CH2_DEF); if(channel_enabled) { - LL_DMA_DisableChannel(IR_DMA_CH2_DEF); + LL_DMA_DisableChannel(INFRARED_DMA_CH2_DEF); } - LL_DMA_SetMemoryAddress(IR_DMA_CH2_DEF, (uint32_t)buffer->data); - LL_DMA_SetDataLength(IR_DMA_CH2_DEF, buffer->size); + LL_DMA_SetMemoryAddress(INFRARED_DMA_CH2_DEF, (uint32_t)buffer->data); + LL_DMA_SetDataLength(INFRARED_DMA_CH2_DEF, buffer->size); if(channel_enabled) { - LL_DMA_EnableChannel(IR_DMA_CH2_DEF); + LL_DMA_EnableChannel(INFRARED_DMA_CH2_DEF); } FURI_CRITICAL_EXIT(); } @@ -568,9 +579,10 @@ static void furi_hal_infrared_async_tx_free_resources(void) { (furi_hal_infrared_state == InfraredStateAsyncTxStopped)); furi_hal_gpio_init(&gpio_infrared_tx, GpioModeAnalog, GpioPullDown, GpioSpeedLow); - furi_hal_interrupt_set_isr(IR_DMA_CH1_IRQ, NULL, NULL); - furi_hal_interrupt_set_isr(IR_DMA_CH2_IRQ, NULL, NULL); - LL_TIM_DeInit(TIM1); + furi_hal_interrupt_set_isr(INFRARED_DMA_CH1_IRQ, NULL, NULL); + furi_hal_interrupt_set_isr(INFRARED_DMA_CH2_IRQ, NULL, NULL); + + furi_hal_bus_disable(INFRARED_DMA_TIMER_BUS); furi_semaphore_free(infrared_tim_tx.stop_semaphore); free(infrared_tim_tx.buffer[0].data); @@ -611,6 +623,8 @@ void furi_hal_infrared_async_tx_start(uint32_t freq, float duty_cycle) { furi_hal_infrared_tx_fill_buffer(0, INFRARED_POLARITY_SHIFT); + furi_hal_bus_enable(INFRARED_DMA_TIMER_BUS); + furi_hal_infrared_configure_tim_pwm_tx(freq, duty_cycle); furi_hal_infrared_configure_tim_cmgr2_dma_tx(); furi_hal_infrared_configure_tim_rcr_dma_tx(); @@ -619,11 +633,11 @@ void furi_hal_infrared_async_tx_start(uint32_t freq, float duty_cycle) { furi_hal_infrared_state = InfraredStateAsyncTx; - LL_TIM_ClearFlag_UPDATE(TIM1); - LL_DMA_EnableChannel(IR_DMA_CH1_DEF); - LL_DMA_EnableChannel(IR_DMA_CH2_DEF); + LL_TIM_ClearFlag_UPDATE(INFRARED_DMA_TIMER); + LL_DMA_EnableChannel(INFRARED_DMA_CH1_DEF); + LL_DMA_EnableChannel(INFRARED_DMA_CH2_DEF); furi_delay_us(5); - LL_TIM_GenerateEvent_UPDATE(TIM1); /* DMA -> TIMx_RCR */ + LL_TIM_GenerateEvent_UPDATE(INFRARED_DMA_TIMER); /* DMA -> TIMx_RCR */ furi_delay_us(5); LL_GPIO_ResetOutputPin( gpio_infrared_tx.port, gpio_infrared_tx.pin); /* when disable it prevents false pulse */ @@ -631,8 +645,8 @@ void furi_hal_infrared_async_tx_start(uint32_t freq, float duty_cycle) { &gpio_infrared_tx, GpioModeAltFunctionPushPull, GpioPullUp, GpioSpeedHigh, GpioAltFn1TIM1); FURI_CRITICAL_ENTER(); - LL_TIM_GenerateEvent_UPDATE(TIM1); /* TIMx_RCR -> Repetition counter */ - LL_TIM_EnableCounter(TIM1); + LL_TIM_GenerateEvent_UPDATE(INFRARED_DMA_TIMER); /* TIMx_RCR -> Repetition counter */ + LL_TIM_EnableCounter(INFRARED_DMA_TIMER); FURI_CRITICAL_EXIT(); } diff --git a/firmware/targets/f7/furi_hal/furi_hal_memory.c b/firmware/targets/f7/furi_hal/furi_hal_memory.c index 9716f1e5292e..7f69b90ca2bb 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_memory.c +++ b/firmware/targets/f7/furi_hal/furi_hal_memory.c @@ -4,6 +4,9 @@ #define TAG "FuriHalMemory" +// STM(TM) Copro(TM) bug(TM) workaround size +#define RAM2B_COPRO_GAP_SIZE_KB 2 + typedef enum { SRAM_A, SRAM_B, @@ -30,53 +33,47 @@ void furi_hal_memory_init() { return; } - if(!ble_glue_wait_for_c2_start(FURI_HAL_BT_C2_START_TIMEOUT)) { - FURI_LOG_E(TAG, "C2 start timeout"); - return; - } - FuriHalMemory* memory = malloc(sizeof(FuriHalMemory)); - const BleGlueC2Info* c2_ver = ble_glue_get_c2_info(); + uint32_t sbrsa = (FLASH->SRRVR & FLASH_SRRVR_SBRSA_Msk) >> FLASH_SRRVR_SBRSA_Pos; + uint32_t snbrsa = (FLASH->SRRVR & FLASH_SRRVR_SNBRSA_Msk) >> FLASH_SRRVR_SNBRSA_Pos; + + uint32_t sram2a_busy_size = (uint32_t)&__sram2a_free__ - (uint32_t)&__sram2a_start__; + uint32_t sram2a_unprotected_size = (sbrsa)*1024; + uint32_t sram2b_unprotected_size = (snbrsa)*1024; - if(c2_ver->mode == BleGlueC2ModeStack) { - uint32_t sram2a_busy_size = (uint32_t)&__sram2a_free__ - (uint32_t)&__sram2a_start__; - uint32_t sram2a_unprotected_size = (32 - c2_ver->MemorySizeSram2A) * 1024; - uint32_t sram2b_unprotected_size = (32 - c2_ver->MemorySizeSram2B) * 1024; + // STM(TM) Copro(TM) bug(TM) workaround + sram2b_unprotected_size -= 1024 * RAM2B_COPRO_GAP_SIZE_KB; - memory->region[SRAM_A].start = (uint8_t*)&__sram2a_free__; - memory->region[SRAM_B].start = (uint8_t*)&__sram2b_start__; + memory->region[SRAM_A].start = (uint8_t*)&__sram2a_free__; + memory->region[SRAM_B].start = (uint8_t*)&__sram2b_start__; - if(sram2a_unprotected_size > sram2a_busy_size) { - memory->region[SRAM_A].size = sram2a_unprotected_size - sram2a_busy_size; - } else { - memory->region[SRAM_A].size = 0; + if(sram2a_unprotected_size > sram2a_busy_size) { + memory->region[SRAM_A].size = sram2a_unprotected_size - sram2a_busy_size; + } else { + memory->region[SRAM_A].size = 0; + } + memory->region[SRAM_B].size = sram2b_unprotected_size; + + FURI_LOG_I( + TAG, "SRAM2A: 0x%p, %lu", memory->region[SRAM_A].start, memory->region[SRAM_A].size); + FURI_LOG_I( + TAG, "SRAM2B: 0x%p, %lu", memory->region[SRAM_B].start, memory->region[SRAM_B].size); + + if((memory->region[SRAM_A].size > 0) || (memory->region[SRAM_B].size > 0)) { + if((memory->region[SRAM_A].size > 0)) { + FURI_LOG_I(TAG, "SRAM2A clear"); + memset(memory->region[SRAM_A].start, 0, memory->region[SRAM_A].size); } - memory->region[SRAM_B].size = sram2b_unprotected_size; - - FURI_LOG_I( - TAG, "SRAM2A: 0x%p, %lu", memory->region[SRAM_A].start, memory->region[SRAM_A].size); - FURI_LOG_I( - TAG, "SRAM2B: 0x%p, %lu", memory->region[SRAM_B].start, memory->region[SRAM_B].size); - - if((memory->region[SRAM_A].size > 0) || (memory->region[SRAM_B].size > 0)) { - if((memory->region[SRAM_A].size > 0)) { - FURI_LOG_I(TAG, "SRAM2A clear"); - memset(memory->region[SRAM_A].start, 0, memory->region[SRAM_A].size); - } - if((memory->region[SRAM_B].size > 0)) { - FURI_LOG_I(TAG, "SRAM2B clear"); - memset(memory->region[SRAM_B].start, 0, memory->region[SRAM_B].size); - } - furi_hal_memory = memory; - FURI_LOG_I(TAG, "Enabled"); - } else { - free(memory); - FURI_LOG_E(TAG, "No SRAM2 available"); + if((memory->region[SRAM_B].size > 0)) { + FURI_LOG_I(TAG, "SRAM2B clear"); + memset(memory->region[SRAM_B].start, 0, memory->region[SRAM_B].size); } + furi_hal_memory = memory; + FURI_LOG_I(TAG, "Enabled"); } else { free(memory); - FURI_LOG_E(TAG, "No Core2 available"); + FURI_LOG_E(TAG, "No SRAM2 available"); } } @@ -89,15 +86,20 @@ void* furi_hal_memory_alloc(size_t size) { return NULL; } + void* allocated_memory = NULL; + FURI_CRITICAL_ENTER(); for(int i = 0; i < SRAM_MAX; i++) { if(furi_hal_memory->region[i].size >= size) { void* ptr = furi_hal_memory->region[i].start; furi_hal_memory->region[i].start += size; furi_hal_memory->region[i].size -= size; - return ptr; + allocated_memory = ptr; + break; } } - return NULL; + FURI_CRITICAL_EXIT(); + + return allocated_memory; } size_t furi_hal_memory_get_free() { diff --git a/firmware/targets/f7/furi_hal/furi_hal_nfc.c b/firmware/targets/f7/furi_hal/furi_hal_nfc.c index c5605c48708b..bd621c2db7d7 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_nfc.c +++ b/firmware/targets/f7/furi_hal/furi_hal_nfc.c @@ -467,7 +467,7 @@ bool furi_hal_nfc_emulate_nfca( buff_tx, buff_tx_len, buff_rx, - sizeof(buff_rx), + rfalConvBytesToBits(buff_rx_size), &buff_rx_len, data_type, RFAL_FWT_NONE); @@ -491,7 +491,7 @@ bool furi_hal_nfc_emulate_nfca( buff_tx, buff_tx_len, buff_rx, - sizeof(buff_rx), + rfalConvBytesToBits(buff_rx_size), &buff_rx_len, data_type, RFAL_FWT_NONE); diff --git a/firmware/targets/f7/furi_hal/furi_hal_pwm.c b/firmware/targets/f7/furi_hal/furi_hal_pwm.c index 8f84b5fd8d59..7e985cbb11b6 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_pwm.c +++ b/firmware/targets/f7/furi_hal/furi_hal_pwm.c @@ -1,8 +1,7 @@ #include -#include #include +#include -#include #include #include #include @@ -29,9 +28,7 @@ void furi_hal_pwm_start(FuriHalPwmOutputId channel, uint32_t freq, uint8_t duty) GpioSpeedVeryHigh, GpioAltFn1TIM1); - FURI_CRITICAL_ENTER(); - LL_TIM_DeInit(TIM1); - FURI_CRITICAL_EXIT(); + furi_hal_bus_enable(FuriHalBusTIM1); LL_TIM_SetCounterMode(TIM1, LL_TIM_COUNTERMODE_UP); LL_TIM_SetRepetitionCounter(TIM1, 0); @@ -58,9 +55,7 @@ void furi_hal_pwm_start(FuriHalPwmOutputId channel, uint32_t freq, uint8_t duty) GpioSpeedVeryHigh, GpioAltFn14LPTIM2); - FURI_CRITICAL_ENTER(); - LL_LPTIM_DeInit(LPTIM2); - FURI_CRITICAL_EXIT(); + furi_hal_bus_enable(FuriHalBusLPTIM2); LL_LPTIM_SetUpdateMode(LPTIM2, LL_LPTIM_UPDATE_MODE_ENDOFPERIOD); LL_RCC_SetLPTIMClockSource(LL_RCC_LPTIM2_CLKSOURCE_PCLK1); @@ -80,14 +75,10 @@ void furi_hal_pwm_start(FuriHalPwmOutputId channel, uint32_t freq, uint8_t duty) void furi_hal_pwm_stop(FuriHalPwmOutputId channel) { if(channel == FuriHalPwmOutputIdTim1PA7) { furi_hal_gpio_init_simple(&gpio_ext_pa7, GpioModeAnalog); - FURI_CRITICAL_ENTER(); - LL_TIM_DeInit(TIM1); - FURI_CRITICAL_EXIT(); + furi_hal_bus_disable(FuriHalBusTIM1); } else if(channel == FuriHalPwmOutputIdLptim2PA4) { furi_hal_gpio_init_simple(&gpio_ext_pa4, GpioModeAnalog); - FURI_CRITICAL_ENTER(); - LL_LPTIM_DeInit(LPTIM2); - FURI_CRITICAL_EXIT(); + furi_hal_bus_disable(FuriHalBusLPTIM2); } } diff --git a/firmware/targets/f7/furi_hal/furi_hal_random.c b/firmware/targets/f7/furi_hal/furi_hal_random.c index d3461c4d12e0..cf4b552f6d8a 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_random.c +++ b/firmware/targets/f7/furi_hal/furi_hal_random.c @@ -1,8 +1,9 @@ #include +#include #include -#include #include +#include #include #include @@ -32,6 +33,11 @@ static uint32_t furi_hal_random_read_rng() { return LL_RNG_ReadRandData32(RNG); } +void furi_hal_random_init() { + furi_hal_bus_enable(FuriHalBusRNG); + LL_RCC_SetRNGClockSource(LL_RCC_RNG_CLKSOURCE_CLK48); +} + uint32_t furi_hal_random_get() { while(LL_HSEM_1StepLock(HSEM, CFG_HW_RNG_SEMID)) ; @@ -40,6 +46,7 @@ uint32_t furi_hal_random_get() { const uint32_t random_val = furi_hal_random_read_rng(); LL_RNG_Disable(RNG); + ; LL_HSEM_ReleaseLock(HSEM, CFG_HW_RNG_SEMID, 0); return random_val; diff --git a/firmware/targets/f7/furi_hal/furi_hal_resources.c b/firmware/targets/f7/furi_hal/furi_hal_resources.c index abfd977e52cc..34b26b831cfa 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_resources.c +++ b/firmware/targets/f7/furi_hal/furi_hal_resources.c @@ -1,4 +1,5 @@ #include +#include #include #include @@ -80,6 +81,7 @@ const GpioPinRecord gpio_pins[] = { /* Dangerous pins, may damage hardware */ {.pin = &gpio_usart_rx, .name = "PB7", .debug = true}, {.pin = &gpio_speaker, .name = "PB8", .debug = true}, + {.pin = &gpio_infrared_tx, .name = "PB9", .debug = true}, }; const size_t gpio_pins_count = sizeof(gpio_pins) / sizeof(GpioPinRecord); @@ -106,6 +108,13 @@ static void furi_hal_resources_init_input_pins(GpioMode mode) { } void furi_hal_resources_init_early() { + furi_hal_bus_enable(FuriHalBusGPIOA); + furi_hal_bus_enable(FuriHalBusGPIOB); + furi_hal_bus_enable(FuriHalBusGPIOC); + furi_hal_bus_enable(FuriHalBusGPIOD); + furi_hal_bus_enable(FuriHalBusGPIOE); + furi_hal_bus_enable(FuriHalBusGPIOH); + furi_hal_resources_init_input_pins(GpioModeInput); // SD Card stepdown control @@ -150,6 +159,12 @@ void furi_hal_resources_init_early() { void furi_hal_resources_deinit_early() { furi_hal_resources_init_input_pins(GpioModeAnalog); + furi_hal_bus_disable(FuriHalBusGPIOA); + furi_hal_bus_disable(FuriHalBusGPIOB); + furi_hal_bus_disable(FuriHalBusGPIOC); + furi_hal_bus_disable(FuriHalBusGPIOD); + furi_hal_bus_disable(FuriHalBusGPIOE); + furi_hal_bus_disable(FuriHalBusGPIOH); } void furi_hal_resources_init() { diff --git a/firmware/targets/f7/furi_hal/furi_hal_rfid.c b/firmware/targets/f7/furi_hal/furi_hal_rfid.c index 145e49df2c14..fa0c19b098b8 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_rfid.c +++ b/firmware/targets/f7/furi_hal/furi_hal_rfid.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -9,15 +10,18 @@ #include #define FURI_HAL_RFID_READ_TIMER TIM1 +#define FURI_HAL_RFID_READ_TIMER_BUS FuriHalBusTIM1 #define FURI_HAL_RFID_READ_TIMER_CHANNEL LL_TIM_CHANNEL_CH1N // We can't use N channel for LL_TIM_OC_Init, so... #define FURI_HAL_RFID_READ_TIMER_CHANNEL_CONFIG LL_TIM_CHANNEL_CH1 #define FURI_HAL_RFID_EMULATE_TIMER TIM2 +#define FURI_HAL_RFID_EMULATE_TIMER_BUS FuriHalBusTIM2 #define FURI_HAL_RFID_EMULATE_TIMER_IRQ FuriHalInterruptIdTIM2 #define FURI_HAL_RFID_EMULATE_TIMER_CHANNEL LL_TIM_CHANNEL_CH3 #define RFID_CAPTURE_TIM TIM2 +#define RFID_CAPTURE_TIM_BUS FuriHalBusTIM2 #define RFID_CAPTURE_IND_CH LL_TIM_CHANNEL_CH3 #define RFID_CAPTURE_DIR_CH LL_TIM_CHANNEL_CH4 @@ -30,7 +34,6 @@ #define RFID_DMA_CH2_DEF RFID_DMA, RFID_DMA_CH2_CHANNEL typedef struct { - FuriHalRfidEmulateCallback callback; FuriHalRfidDMACallback dma_callback; FuriHalRfidReadCaptureCallback read_capture_callback; void* context; @@ -56,11 +59,7 @@ void furi_hal_rfid_init() { COMP_InitStruct.InputPlus = LL_COMP_INPUT_PLUS_IO1; COMP_InitStruct.InputMinus = LL_COMP_INPUT_MINUS_1_2VREFINT; COMP_InitStruct.InputHysteresis = LL_COMP_HYSTERESIS_HIGH; -#ifdef INVERT_RFID_IN - COMP_InitStruct.OutputPolarity = LL_COMP_OUTPUTPOL_INVERTED; -#else COMP_InitStruct.OutputPolarity = LL_COMP_OUTPUTPOL_NONINVERTED; -#endif COMP_InitStruct.OutputBlankingSource = LL_COMP_BLANKINGSRC_NONE; LL_COMP_Init(COMP1, &COMP_InitStruct); LL_COMP_SetCommonWindowMode(__LL_COMP_COMMON_INSTANCE(COMP1), LL_COMP_WINDOWMODE_DISABLE); @@ -92,7 +91,7 @@ void furi_hal_rfid_pins_reset() { furi_hal_gpio_init(&gpio_rfid_data_in, GpioModeAnalog, GpioPullNo, GpioSpeedLow); } -void furi_hal_rfid_pins_emulate() { +static void furi_hal_rfid_pins_emulate() { // ibutton low furi_hal_ibutton_pin_configure(); furi_hal_ibutton_pin_write(false); @@ -113,7 +112,7 @@ void furi_hal_rfid_pins_emulate() { &gpio_rfid_carrier, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedLow, GpioAltFn2TIM2); } -void furi_hal_rfid_pins_read() { +static void furi_hal_rfid_pins_read() { // ibutton low furi_hal_ibutton_pin_configure(); furi_hal_ibutton_pin_write(false); @@ -142,10 +141,10 @@ void furi_hal_rfid_pin_pull_pulldown() { furi_hal_gpio_write(&gpio_nfc_irq_rfid_pull, false); } -void furi_hal_rfid_tim_read(float freq, float duty_cycle) { - FURI_CRITICAL_ENTER(); - LL_TIM_DeInit(FURI_HAL_RFID_READ_TIMER); - FURI_CRITICAL_EXIT(); +void furi_hal_rfid_tim_read_start(float freq, float duty_cycle) { + furi_hal_bus_enable(FURI_HAL_RFID_READ_TIMER_BUS); + + furi_hal_rfid_pins_read(); LL_TIM_InitTypeDef TIM_InitStruct = {0}; TIM_InitStruct.Autoreload = (SystemCoreClock / freq) - 1; @@ -160,23 +159,23 @@ void furi_hal_rfid_tim_read(float freq, float duty_cycle) { FURI_HAL_RFID_READ_TIMER, FURI_HAL_RFID_READ_TIMER_CHANNEL_CONFIG, &TIM_OC_InitStruct); LL_TIM_EnableCounter(FURI_HAL_RFID_READ_TIMER); + + furi_hal_rfid_tim_read_continue(); } -void furi_hal_rfid_tim_read_start() { +void furi_hal_rfid_tim_read_continue() { LL_TIM_EnableAllOutputs(FURI_HAL_RFID_READ_TIMER); } -void furi_hal_rfid_tim_read_stop() { +void furi_hal_rfid_tim_read_pause() { LL_TIM_DisableAllOutputs(FURI_HAL_RFID_READ_TIMER); } -void furi_hal_rfid_tim_emulate(float freq) { - UNUSED(freq); // FIXME - // basic PWM setup with needed freq and internal clock - FURI_CRITICAL_ENTER(); - LL_TIM_DeInit(FURI_HAL_RFID_EMULATE_TIMER); - FURI_CRITICAL_EXIT(); +void furi_hal_rfid_tim_read_stop() { + furi_hal_bus_disable(FURI_HAL_RFID_READ_TIMER_BUS); +} +static void furi_hal_rfid_tim_emulate() { LL_TIM_SetPrescaler(FURI_HAL_RFID_EMULATE_TIMER, 0); LL_TIM_SetCounterMode(FURI_HAL_RFID_EMULATE_TIMER, LL_TIM_COUNTERMODE_UP); LL_TIM_SetAutoReload(FURI_HAL_RFID_EMULATE_TIMER, 1); @@ -201,32 +200,6 @@ void furi_hal_rfid_tim_emulate(float freq) { LL_TIM_GenerateEvent_UPDATE(FURI_HAL_RFID_EMULATE_TIMER); } -static void furi_hal_rfid_emulate_isr() { - if(LL_TIM_IsActiveFlag_UPDATE(FURI_HAL_RFID_EMULATE_TIMER)) { - LL_TIM_ClearFlag_UPDATE(FURI_HAL_RFID_EMULATE_TIMER); - furi_hal_rfid->callback(furi_hal_rfid->context); - } -} - -void furi_hal_rfid_tim_emulate_start(FuriHalRfidEmulateCallback callback, void* context) { - furi_assert(furi_hal_rfid); - - furi_hal_rfid->callback = callback; - furi_hal_rfid->context = context; - - furi_hal_interrupt_set_isr(FURI_HAL_RFID_EMULATE_TIMER_IRQ, furi_hal_rfid_emulate_isr, NULL); - - LL_TIM_EnableIT_UPDATE(FURI_HAL_RFID_EMULATE_TIMER); - LL_TIM_EnableAllOutputs(FURI_HAL_RFID_EMULATE_TIMER); - LL_TIM_EnableCounter(FURI_HAL_RFID_EMULATE_TIMER); -} - -void furi_hal_rfid_tim_emulate_stop() { - LL_TIM_DisableCounter(FURI_HAL_RFID_EMULATE_TIMER); - LL_TIM_DisableAllOutputs(FURI_HAL_RFID_EMULATE_TIMER); - furi_hal_interrupt_set_isr(FURI_HAL_RFID_EMULATE_TIMER_IRQ, NULL, NULL); -} - static void furi_hal_capture_dma_isr(void* context) { UNUSED(context); @@ -247,15 +220,13 @@ static void furi_hal_capture_dma_isr(void* context) { } void furi_hal_rfid_tim_read_capture_start(FuriHalRfidReadCaptureCallback callback, void* context) { - FURI_CRITICAL_ENTER(); - LL_TIM_DeInit(RFID_CAPTURE_TIM); - FURI_CRITICAL_EXIT(); - furi_assert(furi_hal_rfid); furi_hal_rfid->read_capture_callback = callback; furi_hal_rfid->context = context; + furi_hal_bus_enable(RFID_CAPTURE_TIM_BUS); + // Timer: base LL_TIM_InitTypeDef TIM_InitStruct = {0}; TIM_InitStruct.Prescaler = 64 - 1; @@ -303,10 +274,7 @@ void furi_hal_rfid_tim_read_capture_stop() { furi_hal_rfid_comp_stop(); furi_hal_interrupt_set_isr(FURI_HAL_RFID_EMULATE_TIMER_IRQ, NULL, NULL); - - FURI_CRITICAL_ENTER(); - LL_TIM_DeInit(RFID_CAPTURE_TIM); - FURI_CRITICAL_EXIT(); + furi_hal_bus_disable(RFID_CAPTURE_TIM_BUS); } static void furi_hal_rfid_dma_isr() { @@ -341,7 +309,8 @@ void furi_hal_rfid_tim_emulate_dma_start( furi_hal_rfid_pins_emulate(); // configure timer - furi_hal_rfid_tim_emulate(125000); + furi_hal_bus_enable(FURI_HAL_RFID_EMULATE_TIMER_BUS); + furi_hal_rfid_tim_emulate(); LL_TIM_OC_SetPolarity( FURI_HAL_RFID_EMULATE_TIMER, FURI_HAL_RFID_EMULATE_TIMER_CHANNEL, LL_TIM_OCPOLARITY_HIGH); LL_TIM_EnableDMAReq_UPDATE(FURI_HAL_RFID_EMULATE_TIMER); @@ -405,32 +374,12 @@ void furi_hal_rfid_tim_emulate_dma_stop() { LL_DMA_DeInit(RFID_DMA_CH1_DEF); LL_DMA_DeInit(RFID_DMA_CH2_DEF); - LL_TIM_DeInit(FURI_HAL_RFID_EMULATE_TIMER); - - FURI_CRITICAL_EXIT(); -} -void furi_hal_rfid_tim_reset() { - FURI_CRITICAL_ENTER(); - - LL_TIM_DeInit(FURI_HAL_RFID_READ_TIMER); - LL_TIM_DeInit(FURI_HAL_RFID_EMULATE_TIMER); + furi_hal_bus_disable(FURI_HAL_RFID_EMULATE_TIMER_BUS); FURI_CRITICAL_EXIT(); } -void furi_hal_rfid_set_emulate_period(uint32_t period) { - LL_TIM_SetAutoReload(FURI_HAL_RFID_EMULATE_TIMER, period); -} - -void furi_hal_rfid_set_emulate_pulse(uint32_t pulse) { -#if FURI_HAL_RFID_EMULATE_TIMER_CHANNEL == LL_TIM_CHANNEL_CH3 - LL_TIM_OC_SetCompareCH3(FURI_HAL_RFID_EMULATE_TIMER, pulse); -#else -#error Update this code. Would you kindly? -#endif -} - void furi_hal_rfid_set_read_period(uint32_t period) { LL_TIM_SetAutoReload(FURI_HAL_RFID_READ_TIMER, period); } @@ -443,12 +392,6 @@ void furi_hal_rfid_set_read_pulse(uint32_t pulse) { #endif } -void furi_hal_rfid_change_read_config(float freq, float duty_cycle) { - uint32_t period = (uint32_t)((SystemCoreClock) / freq) - 1; - furi_hal_rfid_set_read_period(period); - furi_hal_rfid_set_read_pulse(period * duty_cycle); -} - void furi_hal_rfid_comp_start() { LL_COMP_Enable(COMP1); // Magic @@ -483,4 +426,4 @@ void COMP_IRQHandler() { (LL_COMP_ReadOutputLevel(COMP1) == LL_COMP_OUTPUT_LEVEL_LOW), furi_hal_rfid_comp_callback_context); } -} \ No newline at end of file +} diff --git a/firmware/targets/f7/furi_hal/furi_hal_rfid.h b/firmware/targets/f7/furi_hal/furi_hal_rfid.h index 36563c1d16ac..78d9b6658709 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_rfid.h +++ b/firmware/targets/f7/furi_hal/furi_hal_rfid.h @@ -21,14 +21,6 @@ void furi_hal_rfid_init(); */ void furi_hal_rfid_pins_reset(); -/** Config rfid pins to emulate state - */ -void furi_hal_rfid_pins_emulate(); - -/** Config rfid pins to read state - */ -void furi_hal_rfid_pins_read(); - /** Release rfid pull pin */ void furi_hal_rfid_pin_pull_release(); @@ -37,32 +29,23 @@ void furi_hal_rfid_pin_pull_release(); */ void furi_hal_rfid_pin_pull_pulldown(); -/** Config rfid timer to read state - * +/** Start read timer * @param freq timer frequency * @param duty_cycle timer duty cycle, 0.0-1.0 */ -void furi_hal_rfid_tim_read(float freq, float duty_cycle); +void furi_hal_rfid_tim_read_start(float freq, float duty_cycle); -/** Start read timer +/** Pause read timer, to be able to continue later */ -void furi_hal_rfid_tim_read_start(); +void furi_hal_rfid_tim_read_pause(); -/** Stop read timer +/** Continue read timer */ -void furi_hal_rfid_tim_read_stop(); - -/** Config rfid timer to emulate state - * - * @param freq timer frequency - */ -void furi_hal_rfid_tim_emulate(float freq); +void furi_hal_rfid_tim_read_continue(); -typedef void (*FuriHalRfidEmulateCallback)(void* context); - -/** Start emulation timer +/** Stop read timer */ -void furi_hal_rfid_tim_emulate_start(FuriHalRfidEmulateCallback callback, void* context); +void furi_hal_rfid_tim_read_stop(); typedef void (*FuriHalRfidReadCaptureCallback)(bool level, uint32_t duration, void* context); @@ -81,26 +64,6 @@ void furi_hal_rfid_tim_emulate_dma_start( void furi_hal_rfid_tim_emulate_dma_stop(); -/** Stop emulation timer - */ -void furi_hal_rfid_tim_emulate_stop(); - -/** Config rfid timers to reset state - */ -void furi_hal_rfid_tim_reset(); - -/** Set emulation timer period - * - * @param period overall duration - */ -void furi_hal_rfid_set_emulate_period(uint32_t period); - -/** Set emulation timer pulse - * - * @param pulse duration of high level - */ -void furi_hal_rfid_set_emulate_pulse(uint32_t pulse); - /** Set read timer period * * @param period overall duration @@ -113,13 +76,6 @@ void furi_hal_rfid_set_read_period(uint32_t period); */ void furi_hal_rfid_set_read_pulse(uint32_t pulse); -/** Сhanges the configuration of the RFID timer "on a fly" - * - * @param freq new frequency - * @param duty_cycle new duty cycle - */ -void furi_hal_rfid_change_read_config(float freq, float duty_cycle); - /** Start/Enable comparator */ void furi_hal_rfid_comp_start(); diff --git a/firmware/targets/f7/furi_hal/furi_hal_rtc.c b/firmware/targets/f7/furi_hal/furi_hal_rtc.c index 7bd45c35d71d..a8e25faad66c 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_rtc.c +++ b/firmware/targets/f7/furi_hal/furi_hal_rtc.c @@ -2,8 +2,8 @@ #include #include -#include #include +#include #include #include #include @@ -44,10 +44,8 @@ _Static_assert(sizeof(SystemReg) == 4, "SystemReg size mismatch"); #define FURI_HAL_RTC_SECONDS_PER_DAY (FURI_HAL_RTC_SECONDS_PER_HOUR * 24) #define FURI_HAL_RTC_MONTHS_COUNT 12 #define FURI_HAL_RTC_EPOCH_START_YEAR 1970 -#define FURI_HAL_RTC_IS_LEAP_YEAR(year) \ - ((((year) % 4 == 0) && ((year) % 100 != 0)) || ((year) % 400 == 0)) -static const uint8_t furi_hal_rtc_days_per_month[][FURI_HAL_RTC_MONTHS_COUNT] = { +static const uint8_t furi_hal_rtc_days_per_month[2][FURI_HAL_RTC_MONTHS_COUNT] = { {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}}; @@ -395,7 +393,7 @@ uint32_t furi_hal_rtc_datetime_to_timestamp(FuriHalRtcDateTime* datetime) { uint8_t leap_years = 0; for(uint16_t y = FURI_HAL_RTC_EPOCH_START_YEAR; y < datetime->year; y++) { - if(FURI_HAL_RTC_IS_LEAP_YEAR(y)) { + if(furi_hal_rtc_is_leap_year(y)) { leap_years++; } else { years++; @@ -406,10 +404,10 @@ uint32_t furi_hal_rtc_datetime_to_timestamp(FuriHalRtcDateTime* datetime) { ((years * furi_hal_rtc_days_per_year[0]) + (leap_years * furi_hal_rtc_days_per_year[1])) * FURI_HAL_RTC_SECONDS_PER_DAY; - uint8_t year_index = (FURI_HAL_RTC_IS_LEAP_YEAR(datetime->year)) ? 1 : 0; + bool leap_year = furi_hal_rtc_is_leap_year(datetime->year); - for(uint8_t m = 0; m < (datetime->month - 1); m++) { - timestamp += furi_hal_rtc_days_per_month[year_index][m] * FURI_HAL_RTC_SECONDS_PER_DAY; + for(uint8_t m = 1; m < datetime->month; m++) { + timestamp += furi_hal_rtc_get_days_per_month(leap_year, m) * FURI_HAL_RTC_SECONDS_PER_DAY; } timestamp += (datetime->day - 1) * FURI_HAL_RTC_SECONDS_PER_DAY; @@ -419,3 +417,15 @@ uint32_t furi_hal_rtc_datetime_to_timestamp(FuriHalRtcDateTime* datetime) { return timestamp; } + +uint16_t furi_hal_rtc_get_days_per_year(uint16_t year) { + return furi_hal_rtc_days_per_year[furi_hal_rtc_is_leap_year(year) ? 1 : 0]; +} + +bool furi_hal_rtc_is_leap_year(uint16_t year) { + return (((year) % 4 == 0) && ((year) % 100 != 0)) || ((year) % 400 == 0); +} + +uint8_t furi_hal_rtc_get_days_per_month(bool leap_year, uint8_t month) { + return furi_hal_rtc_days_per_month[leap_year ? 1 : 0][month - 1]; +} diff --git a/firmware/targets/f7/furi_hal/furi_hal_speaker.c b/firmware/targets/f7/furi_hal/furi_hal_speaker.c index 5421509cca51..ad7ed994af28 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_speaker.c +++ b/firmware/targets/f7/furi_hal/furi_hal_speaker.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -20,16 +21,11 @@ static FuriMutex* furi_hal_speaker_mutex = NULL; void furi_hal_speaker_init() { furi_assert(furi_hal_speaker_mutex == NULL); furi_hal_speaker_mutex = furi_mutex_alloc(FuriMutexTypeNormal); - FURI_CRITICAL_ENTER(); - LL_TIM_DeInit(FURI_HAL_SPEAKER_TIMER); - FURI_CRITICAL_EXIT(); FURI_LOG_I(TAG, "Init OK"); } void furi_hal_speaker_deinit() { furi_check(furi_hal_speaker_mutex != NULL); - LL_TIM_DeInit(FURI_HAL_SPEAKER_TIMER); - furi_hal_gpio_init(&gpio_speaker, GpioModeAnalog, GpioPullNo, GpioSpeedLow); furi_mutex_free(furi_hal_speaker_mutex); furi_hal_speaker_mutex = NULL; } @@ -39,6 +35,7 @@ bool furi_hal_speaker_acquire(uint32_t timeout) { if(furi_mutex_acquire(furi_hal_speaker_mutex, timeout) == FuriStatusOk) { furi_hal_power_insomnia_enter(); + furi_hal_bus_enable(FuriHalBusTIM16); furi_hal_gpio_init_ex( &gpio_speaker, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedLow, GpioAltFn14TIM16); return true; @@ -53,6 +50,8 @@ void furi_hal_speaker_release() { furi_hal_speaker_stop(); furi_hal_gpio_init(&gpio_speaker, GpioModeAnalog, GpioPullDown, GpioSpeedLow); + + furi_hal_bus_disable(FuriHalBusTIM16); furi_hal_power_insomnia_exit(); furi_check(furi_mutex_release(furi_hal_speaker_mutex) == FuriStatusOk); diff --git a/firmware/targets/f7/furi_hal/furi_hal_spi_config.c b/firmware/targets/f7/furi_hal/furi_hal_spi_config.c index 9cf332dacd6c..09ac79d2a3c0 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_spi_config.c +++ b/firmware/targets/f7/furi_hal/furi_hal_spi_config.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #define TAG "FuriHalSpiConfig" @@ -100,28 +101,17 @@ void furi_hal_spi_config_init() { static void furi_hal_spi_bus_r_event_callback(FuriHalSpiBus* bus, FuriHalSpiBusEvent event) { if(event == FuriHalSpiBusEventInit) { furi_hal_spi_bus_r_mutex = furi_mutex_alloc(FuriMutexTypeNormal); - FURI_CRITICAL_ENTER(); - LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_SPI1); - FURI_CRITICAL_EXIT(); bus->current_handle = NULL; } else if(event == FuriHalSpiBusEventDeinit) { furi_mutex_free(furi_hal_spi_bus_r_mutex); - FURI_CRITICAL_ENTER(); - LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_SPI1); - LL_APB2_GRP1_ReleaseReset(LL_APB2_GRP1_PERIPH_SPI1); - FURI_CRITICAL_EXIT(); } else if(event == FuriHalSpiBusEventLock) { furi_check(furi_mutex_acquire(furi_hal_spi_bus_r_mutex, FuriWaitForever) == FuriStatusOk); } else if(event == FuriHalSpiBusEventUnlock) { furi_check(furi_mutex_release(furi_hal_spi_bus_r_mutex) == FuriStatusOk); } else if(event == FuriHalSpiBusEventActivate) { - FURI_CRITICAL_ENTER(); - LL_APB2_GRP1_ReleaseReset(LL_APB2_GRP1_PERIPH_SPI1); - FURI_CRITICAL_EXIT(); + furi_hal_bus_enable(FuriHalBusSPI1); } else if(event == FuriHalSpiBusEventDeactivate) { - FURI_CRITICAL_ENTER(); - LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_SPI1); - FURI_CRITICAL_EXIT(); + furi_hal_bus_disable(FuriHalBusSPI1); } } @@ -135,28 +125,17 @@ FuriMutex* furi_hal_spi_bus_d_mutex = NULL; static void furi_hal_spi_bus_d_event_callback(FuriHalSpiBus* bus, FuriHalSpiBusEvent event) { if(event == FuriHalSpiBusEventInit) { furi_hal_spi_bus_d_mutex = furi_mutex_alloc(FuriMutexTypeNormal); - FURI_CRITICAL_ENTER(); - LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_SPI2); - FURI_CRITICAL_EXIT(); bus->current_handle = NULL; } else if(event == FuriHalSpiBusEventDeinit) { furi_mutex_free(furi_hal_spi_bus_d_mutex); - FURI_CRITICAL_ENTER(); - LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_SPI2); - LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_SPI2); - FURI_CRITICAL_EXIT(); } else if(event == FuriHalSpiBusEventLock) { furi_check(furi_mutex_acquire(furi_hal_spi_bus_d_mutex, FuriWaitForever) == FuriStatusOk); } else if(event == FuriHalSpiBusEventUnlock) { furi_check(furi_mutex_release(furi_hal_spi_bus_d_mutex) == FuriStatusOk); } else if(event == FuriHalSpiBusEventActivate) { - FURI_CRITICAL_ENTER(); - LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_SPI2); - FURI_CRITICAL_EXIT(); + furi_hal_bus_enable(FuriHalBusSPI2); } else if(event == FuriHalSpiBusEventDeactivate) { - FURI_CRITICAL_ENTER(); - LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_SPI2); - FURI_CRITICAL_EXIT(); + furi_hal_bus_disable(FuriHalBusSPI2); } } diff --git a/firmware/targets/f7/furi_hal/furi_hal_spi_types.h b/firmware/targets/f7/furi_hal/furi_hal_spi_types.h index d2273f38ba5e..ecc18d50db25 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_spi_types.h +++ b/firmware/targets/f7/furi_hal/furi_hal_spi_types.h @@ -6,8 +6,6 @@ #include #include -#include -#include #ifdef __cplusplus extern "C" { diff --git a/firmware/targets/f7/furi_hal/furi_hal_subghz.c b/firmware/targets/f7/furi_hal/furi_hal_subghz.c index 59646461352a..6d671a9e15b1 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_subghz.c +++ b/firmware/targets/f7/furi_hal/furi_hal_subghz.c @@ -7,6 +7,7 @@ #include #include #include +#include #include @@ -433,6 +434,8 @@ void furi_hal_subghz_start_async_rx(FuriHalSubGhzCaptureCallback callback, void* furi_hal_gpio_init_ex( &gpio_cc1101_g0, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedLow, GpioAltFn1TIM2); + furi_hal_bus_enable(FuriHalBusTIM2); + // Timer: base LL_TIM_InitTypeDef TIM_InitStruct = {0}; TIM_InitStruct.Prescaler = 64 - 1; @@ -496,7 +499,7 @@ void furi_hal_subghz_stop_async_rx() { furi_hal_subghz_idle(); FURI_CRITICAL_ENTER(); - LL_TIM_DeInit(TIM2); + furi_hal_bus_disable(FuriHalBusTIM2); // Stop debug furi_hal_subghz_stop_debug(); @@ -658,6 +661,8 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void* LL_DMA_EnableIT_HT(SUBGHZ_DMA_CH1_DEF); LL_DMA_EnableChannel(SUBGHZ_DMA_CH1_DEF); + furi_hal_bus_enable(FuriHalBusTIM2); + // Configure TIM2 LL_TIM_InitTypeDef TIM_InitStruct = {0}; TIM_InitStruct.Prescaler = 64 - 1; @@ -740,7 +745,7 @@ void furi_hal_subghz_stop_async_tx() { // Deinitialize Timer FURI_CRITICAL_ENTER(); - LL_TIM_DeInit(TIM2); + furi_hal_bus_disable(FuriHalBusTIM2); furi_hal_interrupt_set_isr(FuriHalInterruptIdTIM2, NULL, NULL); // Deinitialize DMA diff --git a/firmware/targets/f7/furi_hal/furi_hal_uart.c b/firmware/targets/f7/furi_hal/furi_hal_uart.c index 71b5c7ba0444..209c6be6a2ed 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_uart.c +++ b/firmware/targets/f7/furi_hal/furi_hal_uart.c @@ -4,6 +4,7 @@ #include #include #include +#include #include @@ -13,6 +14,9 @@ static void (*irq_cb[2])(uint8_t ev, uint8_t data, void* context); static void* irq_ctx[2]; static void furi_hal_usart_init(uint32_t baud) { + furi_hal_bus_enable(FuriHalBusUSART1); + LL_RCC_SetUSARTClockSource(LL_RCC_USART1_CLKSOURCE_PCLK2); + furi_hal_gpio_init_ex( &gpio_usart_tx, GpioModeAltFunctionPushPull, @@ -50,6 +54,9 @@ static void furi_hal_usart_init(uint32_t baud) { } static void furi_hal_lpuart_init(uint32_t baud) { + furi_hal_bus_enable(FuriHalBusLPUART1); + LL_RCC_SetLPUARTClockSource(LL_RCC_LPUART1_CLKSOURCE_PCLK1); + furi_hal_gpio_init_ex( &gpio_ext_pc0, GpioModeAltFunctionPushPull, @@ -86,10 +93,11 @@ static void furi_hal_lpuart_init(uint32_t baud) { } void furi_hal_uart_init(FuriHalUartId ch, uint32_t baud) { - if(ch == FuriHalUartIdLPUART1) + if(ch == FuriHalUartIdLPUART1) { furi_hal_lpuart_init(baud); - else if(ch == FuriHalUartIdUSART1) + } else if(ch == FuriHalUartIdUSART1) { furi_hal_usart_init(baud); + } } void furi_hal_uart_set_br(FuriHalUartId ch, uint32_t baud) { @@ -126,11 +134,15 @@ void furi_hal_uart_set_br(FuriHalUartId ch, uint32_t baud) { void furi_hal_uart_deinit(FuriHalUartId ch) { furi_hal_uart_set_irq_cb(ch, NULL, NULL); if(ch == FuriHalUartIdUSART1) { - LL_USART_Disable(USART1); + if(furi_hal_bus_is_enabled(FuriHalBusUSART1)) { + furi_hal_bus_disable(FuriHalBusUSART1); + } furi_hal_gpio_init(&gpio_usart_tx, GpioModeAnalog, GpioPullNo, GpioSpeedLow); furi_hal_gpio_init(&gpio_usart_rx, GpioModeAnalog, GpioPullNo, GpioSpeedLow); } else if(ch == FuriHalUartIdLPUART1) { - LL_LPUART_Disable(LPUART1); + if(furi_hal_bus_is_enabled(FuriHalBusLPUART1)) { + furi_hal_bus_disable(FuriHalBusLPUART1); + } furi_hal_gpio_init(&gpio_ext_pc0, GpioModeAnalog, GpioPullNo, GpioSpeedLow); furi_hal_gpio_init(&gpio_ext_pc1, GpioModeAnalog, GpioPullNo, GpioSpeedLow); } diff --git a/firmware/targets/f7/furi_hal/furi_hal_usb.c b/firmware/targets/f7/furi_hal/furi_hal_usb.c index 011add953238..b88168d5d0ca 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_usb.c +++ b/firmware/targets/f7/furi_hal/furi_hal_usb.c @@ -2,7 +2,9 @@ #include #include #include + #include +#include #include #include @@ -86,6 +88,8 @@ static void wkup_evt(usbd_device* dev, uint8_t event, uint8_t ep); /* Low-level init */ void furi_hal_usb_init(void) { + LL_RCC_SetUSBClockSource(LL_RCC_USB_CLKSOURCE_PLLSAI1); + LL_GPIO_InitTypeDef GPIO_InitStruct = {0}; LL_PWR_EnableVddUSB(); @@ -98,7 +102,10 @@ void furi_hal_usb_init(void) { LL_GPIO_Init(GPIOA, &GPIO_InitStruct); usbd_init(&udev, &usbd_hw, USB_EP0_SIZE, ubuf, sizeof(ubuf)); + + FURI_CRITICAL_ENTER(); usbd_enable(&udev, true); + FURI_CRITICAL_EXIT(); usbd_reg_descr(&udev, usb_descriptor_get); usbd_reg_event(&udev, usbd_evt_susp, susp_evt); @@ -359,8 +366,10 @@ static void usb_process_mode_reinit() { usbd_connect(&udev, false); usb.enabled = false; + FURI_CRITICAL_ENTER(); usbd_enable(&udev, false); usbd_enable(&udev, true); + FURI_CRITICAL_EXIT(); furi_delay_ms(USB_RECONNECT_DELAY); usb_process_mode_start(usb.interface, usb.interface_context); diff --git a/firmware/targets/f7/furi_hal/furi_hal_usb_hid.c b/firmware/targets/f7/furi_hal/furi_hal_usb_hid.c index d27613410bdc..334aa010264b 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_usb_hid.c +++ b/firmware/targets/f7/furi_hal/furi_hal_usb_hid.c @@ -436,7 +436,11 @@ static bool hid_send_report(uint8_t report_id) { if((hid_semaphore == NULL) || (hid_connected == false)) return false; if((boot_protocol == true) && (report_id != ReportIdKeyboard)) return false; - furi_check(furi_semaphore_acquire(hid_semaphore, FuriWaitForever) == FuriStatusOk); + FuriStatus status = furi_semaphore_acquire(hid_semaphore, HID_INTERVAL * 2); + if(status == FuriStatusErrorTimeout) { + return false; + } + furi_check(status == FuriStatusOk); if(hid_connected == false) { return false; } diff --git a/firmware/targets/f7/src/update.c b/firmware/targets/f7/src/update.c index c1e1084c218a..c6235a150f6d 100644 --- a/firmware/targets/f7/src/update.c +++ b/firmware/targets/f7/src/update.c @@ -38,6 +38,12 @@ static bool flipper_update_mount_sd() { } static bool flipper_update_init() { + // TODO: Configure missing peripherals properly + furi_hal_bus_enable(FuriHalBusHSEM); + furi_hal_bus_enable(FuriHalBusIPCC); + furi_hal_bus_enable(FuriHalBusRNG); + furi_hal_bus_enable(FuriHalBusUSART1); + furi_hal_clock_init(); furi_hal_rtc_init(); furi_hal_interrupt_init(); diff --git a/firmware/targets/f7/target.json b/firmware/targets/f7/target.json index eb306848f19d..5d8231b20ab9 100644 --- a/firmware/targets/f7/target.json +++ b/firmware/targets/f7/target.json @@ -28,6 +28,7 @@ "flipperformat", "toolbox", "nfc", + "digital_signal", "pulse_reader", "microtar", "usb_stm32", diff --git a/firmware/targets/furi_hal_include/furi_hal.h b/firmware/targets/furi_hal_include/furi_hal.h index 2eb4688d4288..9341dccecbe7 100644 --- a/firmware/targets/furi_hal_include/furi_hal.h +++ b/firmware/targets/furi_hal_include/furi_hal.h @@ -12,9 +12,11 @@ struct STOP_EXTERNING_ME {}; #include #include +#include #include #include #include +#include #include #include #include diff --git a/firmware/targets/furi_hal_include/furi_hal_bt.h b/firmware/targets/furi_hal_include/furi_hal_bt.h index 6ba38cb5e630..4d538265dbb2 100644 --- a/firmware/targets/furi_hal_include/furi_hal_bt.h +++ b/firmware/targets/furi_hal_include/furi_hal_bt.h @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include diff --git a/firmware/targets/furi_hal_include/furi_hal_bt_serial.h b/firmware/targets/furi_hal_include/furi_hal_bt_serial.h index 1b6e79ab0785..0472d31d1815 100644 --- a/firmware/targets/furi_hal_include/furi_hal_bt_serial.h +++ b/firmware/targets/furi_hal_include/furi_hal_bt_serial.h @@ -1,6 +1,6 @@ #pragma once -#include "serial_service.h" +#include #ifdef __cplusplus extern "C" { diff --git a/firmware/targets/furi_hal_include/furi_hal_random.h b/firmware/targets/furi_hal_include/furi_hal_random.h index ee69326f416c..5ca9cb723c3d 100644 --- a/firmware/targets/furi_hal_include/furi_hal_random.h +++ b/firmware/targets/furi_hal_include/furi_hal_random.h @@ -6,6 +6,9 @@ extern "C" { #endif +/** Initialize random subsystem */ +void furi_hal_random_init(); + /** Get random value * * @return random value diff --git a/firmware/targets/furi_hal_include/furi_hal_rtc.h b/firmware/targets/furi_hal_include/furi_hal_rtc.h index e706c5c76a02..186d22f07980 100644 --- a/firmware/targets/furi_hal_include/furi_hal_rtc.h +++ b/firmware/targets/furi_hal_include/furi_hal_rtc.h @@ -255,6 +255,30 @@ uint32_t furi_hal_rtc_get_timestamp(); */ uint32_t furi_hal_rtc_datetime_to_timestamp(FuriHalRtcDateTime* datetime); +/** Gets the number of days in the year according to the Gregorian calendar. + * + * @param year Input year. + * + * @return number of days in `year`. + */ +uint16_t furi_hal_rtc_get_days_per_year(uint16_t year); + +/** Check if a year a leap year in the Gregorian calendar. + * + * @param year Input year. + * + * @return true if `year` is a leap year. + */ +bool furi_hal_rtc_is_leap_year(uint16_t year); + +/** Get the number of days in the month. + * + * @param leap_year true to calculate based on leap years + * @param month month to check, where 1 = January + * @return the number of days in the month + */ +uint8_t furi_hal_rtc_get_days_per_month(bool leap_year, uint8_t month); + #ifdef __cplusplus } #endif diff --git a/furi/core/common_defines.h b/furi/core/common_defines.h index d7bfaf2076d0..5bd218d35762 100644 --- a/furi/core/common_defines.h +++ b/furi/core/common_defines.h @@ -31,29 +31,22 @@ extern "C" { #define FURI_IS_ISR() (FURI_IS_IRQ_MODE() || FURI_IS_IRQ_MASKED()) #endif +typedef struct { + uint32_t isrm; + bool from_isr; + bool kernel_running; +} __FuriCriticalInfo; + +__FuriCriticalInfo __furi_critical_enter(void); + +void __furi_critical_exit(__FuriCriticalInfo info); + #ifndef FURI_CRITICAL_ENTER -#define FURI_CRITICAL_ENTER() \ - uint32_t __isrm = 0; \ - bool __from_isr = FURI_IS_ISR(); \ - bool __kernel_running = (xTaskGetSchedulerState() == taskSCHEDULER_RUNNING); \ - if(__from_isr) { \ - __isrm = taskENTER_CRITICAL_FROM_ISR(); \ - } else if(__kernel_running) { \ - taskENTER_CRITICAL(); \ - } else { \ - __disable_irq(); \ - } +#define FURI_CRITICAL_ENTER() __FuriCriticalInfo __furi_critical_info = __furi_critical_enter(); #endif #ifndef FURI_CRITICAL_EXIT -#define FURI_CRITICAL_EXIT() \ - if(__from_isr) { \ - taskEXIT_CRITICAL_FROM_ISR(__isrm); \ - } else if(__kernel_running) { \ - taskEXIT_CRITICAL(); \ - } else { \ - __enable_irq(); \ - } +#define FURI_CRITICAL_EXIT() __furi_critical_exit(__furi_critical_info); #endif #ifdef __cplusplus diff --git a/furi/core/core_defines.h b/furi/core/core_defines.h index 830bb191c2ed..4309c20c5895 100644 --- a/furi/core/core_defines.h +++ b/furi/core/core_defines.h @@ -78,6 +78,11 @@ extern "C" { #define TOSTRING(x) STRINGIFY(x) #endif +#ifndef CONCATENATE +#define CONCATENATE(a, b) CONCATENATE_(a, b) +#define CONCATENATE_(a, b) a##b +#endif + #ifndef REVERSE_BYTES_U32 #define REVERSE_BYTES_U32(x) \ ((((x)&0x000000FF) << 24) | (((x)&0x0000FF00) << 8) | (((x)&0x00FF0000) >> 8) | \ diff --git a/furi/core/critical.c b/furi/core/critical.c new file mode 100644 index 000000000000..57fe2403be71 --- /dev/null +++ b/furi/core/critical.c @@ -0,0 +1,29 @@ +#include "common_defines.h" + +__FuriCriticalInfo __furi_critical_enter(void) { + __FuriCriticalInfo info; + + info.isrm = 0; + info.from_isr = FURI_IS_ISR(); + info.kernel_running = (xTaskGetSchedulerState() == taskSCHEDULER_RUNNING); + + if(info.from_isr) { + info.isrm = taskENTER_CRITICAL_FROM_ISR(); + } else if(info.kernel_running) { + taskENTER_CRITICAL(); + } else { + __disable_irq(); + } + + return info; +} + +void __furi_critical_exit(__FuriCriticalInfo info) { + if(info.from_isr) { + taskEXIT_CRITICAL_FROM_ISR(info.isrm); + } else if(info.kernel_running) { + taskEXIT_CRITICAL(); + } else { + __enable_irq(); + } +} \ No newline at end of file diff --git a/furi/core/thread.c b/furi/core/thread.c index facbcb411796..657b867d1e71 100644 --- a/furi/core/thread.c +++ b/furi/core/thread.c @@ -56,6 +56,8 @@ static int32_t __furi_thread_stdout_flush(FuriThread* thread); /** Catch threads that are trying to exit wrong way */ __attribute__((__noreturn__)) void furi_thread_catch() { //-V1082 + // If you're here it means you're probably doing something wrong + // with critical sections or with scheduler state asm volatile("nop"); // extra magic furi_crash("You are doing it wrong"); //-V779 __builtin_unreachable(); diff --git a/lib/ReadMe.md b/lib/ReadMe.md index 93236b2677fb..138bef2b343b 100644 --- a/lib/ReadMe.md +++ b/lib/ReadMe.md @@ -27,6 +27,7 @@ - `nfc` - NFC library, used by NFC application - `one_wire` - OneWire library, used by iButton application - `print` - Tiny printf implementation +- `digital_signal` - Digital Signal library used by NFC for software implemented protocols - `pulse_reader` - Pulse Reader library used by NFC for software implemented protocols - `qrcode` - QR-Code library - `stm32wb_cmsis` - STM32WB series CMSIS headers, extends CMSIS Core diff --git a/lib/SConscript b/lib/SConscript index 8727746d8181..495ba4bfe24b 100644 --- a/lib/SConscript +++ b/lib/SConscript @@ -15,7 +15,6 @@ env.Append( Dir("u8g2"), Dir("update_util"), Dir("print"), - Dir("pulse_reader"), ], ) @@ -95,6 +94,7 @@ libs = env.BuildModules( "mbedtls", "subghz", "nfc", + "digital_signal", "pulse_reader", "appframe", "misc", diff --git a/lib/digital_signal/SConscript b/lib/digital_signal/SConscript new file mode 100644 index 000000000000..2ddf7a58b098 --- /dev/null +++ b/lib/digital_signal/SConscript @@ -0,0 +1,20 @@ +Import("env") + +env.Append( + CPPPATH=[ + "#/lib/digital_signal", + ], + SDK_HEADERS=[ + File("digital_signal.h"), + ], +) + +libenv = env.Clone(FW_LIB_NAME="digital_signal") +libenv.ApplyLibFlags() +libenv.Append(CCFLAGS=["-O3", "-funroll-loops", "-Ofast"]) + +sources = libenv.GlobRecursive("*.c*") + +lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) +libenv.Install("${LIB_DIST_DIR}", lib) +Return("lib") diff --git a/lib/digital_signal/digital_signal.c b/lib/digital_signal/digital_signal.c index 51a87d22a5b3..39aa9cbc6e14 100644 --- a/lib/digital_signal/digital_signal.c +++ b/lib/digital_signal/digital_signal.c @@ -9,7 +9,7 @@ #include /* must be on bank B */ -#define DEBUG_OUTPUT gpio_ext_pb3 +// For debugging purposes use `--extra-define=DIGITAL_SIGNAL_DEBUG_OUTPUT_PIN=gpio_ext_pb3` fbt option struct ReloadBuffer { uint32_t* buffer; /* DMA ringbuffer */ @@ -194,9 +194,9 @@ void digital_signal_prepare_arr(DigitalSignal* signal) { uint32_t bit_set = internals->gpio->pin; uint32_t bit_reset = internals->gpio->pin << 16; -#ifdef DEBUG_OUTPUT - bit_set |= DEBUG_OUTPUT.pin; - bit_reset |= DEBUG_OUTPUT.pin << 16; +#ifdef DIGITAL_SIGNAL_DEBUG_OUTPUT_PIN + bit_set |= DIGITAL_SIGNAL_DEBUG_OUTPUT_PIN.pin; + bit_reset |= DIGITAL_SIGNAL_DEBUG_OUTPUT_PIN.pin << 16; #endif if(signal->start_level) { @@ -212,8 +212,7 @@ void digital_signal_prepare_arr(DigitalSignal* signal) { internals->reload_reg_entries = 0; for(size_t pos = 0; pos < signal->edge_cnt; pos++) { - uint32_t edge_scaled = (internals->factor * signal->edge_timings[pos]) / (1024 * 1024); - uint32_t pulse_duration = edge_scaled + internals->reload_reg_remainder; + uint32_t pulse_duration = signal->edge_timings[pos] + internals->reload_reg_remainder; if(pulse_duration < 10 || pulse_duration > 10000000) { FURI_LOG_D( TAG, @@ -243,10 +242,12 @@ static void digital_signal_stop_timer() { LL_TIM_DisableCounter(TIM2); LL_TIM_DisableUpdateEvent(TIM2); LL_TIM_DisableDMAReq_UPDATE(TIM2); + + furi_hal_bus_disable(FuriHalBusTIM2); } static void digital_signal_setup_timer() { - digital_signal_stop_timer(); + furi_hal_bus_enable(FuriHalBusTIM2); LL_TIM_SetCounterMode(TIM2, LL_TIM_COUNTERMODE_UP); LL_TIM_SetClockDivision(TIM2, LL_TIM_CLOCKDIVISION_DIV1); @@ -539,8 +540,9 @@ bool digital_sequence_send(DigitalSequence* sequence) { struct ReloadBuffer* dma_buffer = sequence->dma_buffer; furi_hal_gpio_init(sequence->gpio, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); -#ifdef DEBUG_OUTPUT - furi_hal_gpio_init(&DEBUG_OUTPUT, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); +#ifdef DIGITAL_SIGNAL_DEBUG_OUTPUT_PIN + furi_hal_gpio_init( + &DIGITAL_SIGNAL_DEBUG_OUTPUT_PIN, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); #endif if(sequence->bake) { diff --git a/lib/infrared/worker/infrared_worker.c b/lib/infrared/worker/infrared_worker.c index 5add1413e908..46effd420dc3 100644 --- a/lib/infrared/worker/infrared_worker.c +++ b/lib/infrared/worker/infrared_worker.c @@ -40,8 +40,12 @@ struct InfraredWorkerSignal { size_t timings_cnt; union { InfraredMessage message; - /* +1 is for pause we add at the beginning */ - uint32_t timings[MAX_TIMINGS_AMOUNT + 1]; + struct { + /* +1 is for pause we add at the beginning */ + uint32_t timings[MAX_TIMINGS_AMOUNT + 1]; + uint32_t frequency; + float duty_cycle; + } raw; }; }; @@ -146,7 +150,7 @@ static void } if(instance->signal.timings_cnt < MAX_TIMINGS_AMOUNT) { - instance->signal.timings[instance->signal.timings_cnt] = duration; + instance->signal.raw.timings[instance->signal.timings_cnt] = duration; ++instance->signal.timings_cnt; } else { uint32_t flags_set = furi_thread_flags_set( @@ -300,7 +304,7 @@ void infrared_worker_get_raw_signal( furi_assert(timings); furi_assert(timings_cnt); - *timings = signal->timings; + *timings = signal->raw.timings; *timings_cnt = signal->timings_cnt; } @@ -390,8 +394,8 @@ static bool infrared_get_new_signal(InfraredWorker* instance) { infrared_get_protocol_duty_cycle(instance->signal.message.protocol); } else { furi_assert(instance->signal.timings_cnt > 1); - new_tx_frequency = INFRARED_COMMON_CARRIER_FREQUENCY; - new_tx_duty_cycle = INFRARED_COMMON_DUTY_CYCLE; + new_tx_frequency = instance->signal.raw.frequency; + new_tx_duty_cycle = instance->signal.raw.duty_cycle; } instance->tx.tx_raw_cnt = 0; @@ -426,7 +430,7 @@ static bool infrared_worker_tx_fill_buffer(InfraredWorker* instance) { if(instance->signal.decoded) { status = infrared_encode(instance->infrared_encoder, &timing.duration, &timing.level); } else { - timing.duration = instance->signal.timings[instance->tx.tx_raw_cnt]; + timing.duration = instance->signal.raw.timings[instance->tx.tx_raw_cnt]; /* raw always starts from Mark, but we fill it with space delay at start */ timing.level = (instance->tx.tx_raw_cnt % 2); ++instance->tx.tx_raw_cnt; @@ -597,15 +601,21 @@ void infrared_worker_set_decoded_signal(InfraredWorker* instance, const Infrared void infrared_worker_set_raw_signal( InfraredWorker* instance, const uint32_t* timings, - size_t timings_cnt) { + size_t timings_cnt, + uint32_t frequency, + float duty_cycle) { furi_assert(instance); furi_assert(timings); furi_assert(timings_cnt > 0); - size_t max_copy_num = COUNT_OF(instance->signal.timings) - 1; + furi_assert((frequency <= INFRARED_MAX_FREQUENCY) && (frequency >= INFRARED_MIN_FREQUENCY)); + furi_assert((duty_cycle < 1.0f) && (duty_cycle > 0.0f)); + size_t max_copy_num = COUNT_OF(instance->signal.raw.timings) - 1; furi_check(timings_cnt <= max_copy_num); - instance->signal.timings[0] = INFRARED_RAW_TX_TIMING_DELAY_US; - memcpy(&instance->signal.timings[1], timings, timings_cnt * sizeof(uint32_t)); + instance->signal.raw.frequency = frequency; + instance->signal.raw.duty_cycle = duty_cycle; + instance->signal.raw.timings[0] = INFRARED_RAW_TX_TIMING_DELAY_US; + memcpy(&instance->signal.raw.timings[1], timings, timings_cnt * sizeof(uint32_t)); instance->signal.decoded = false; instance->signal.timings_cnt = timings_cnt + 1; } diff --git a/lib/infrared/worker/infrared_worker.h b/lib/infrared/worker/infrared_worker.h index 1a8cd9a76c4c..e0e86198309e 100644 --- a/lib/infrared/worker/infrared_worker.h +++ b/lib/infrared/worker/infrared_worker.h @@ -130,9 +130,9 @@ void infrared_worker_tx_set_signal_sent_callback( /** Callback to pass to infrared_worker_tx_set_get_signal_callback() if signal * is steady and will not be changed between infrared_worker start and stop. * Before starting transmission, desired steady signal must be set with - * infrared_worker_make_decoded_signal() or infrared_worker_make_raw_signal(). + * infrared_worker_set_decoded_signal() or infrared_worker_set_raw_signal(). * - * This function should not be implicitly called. + * This function should not be called directly. * * @param[in] context - context * @param[out] instance - InfraredWorker instance @@ -172,11 +172,15 @@ void infrared_worker_set_decoded_signal(InfraredWorker* instance, const Infrared * @param[out] instance - InfraredWorker instance * @param[in] timings - array of raw timings * @param[in] timings_cnt - size of array of raw timings + * @param[in] frequency - carrier frequency in Hertz + * @param[in] duty_cycle - carrier duty cycle (0.0 - 1.0) */ void infrared_worker_set_raw_signal( InfraredWorker* instance, const uint32_t* timings, - size_t timings_cnt); + size_t timings_cnt, + uint32_t frequency, + float duty_cycle); #ifdef __cplusplus } diff --git a/lib/lfrfid/lfrfid_raw_worker.c b/lib/lfrfid/lfrfid_raw_worker.c index 22c0bbd02c1f..aa962a47d690 100644 --- a/lib/lfrfid/lfrfid_raw_worker.c +++ b/lib/lfrfid/lfrfid_raw_worker.c @@ -151,9 +151,7 @@ static int32_t lfrfid_raw_read_worker_thread(void* thread_context) { if(file_valid) { // setup carrier - furi_hal_rfid_pins_read(); - furi_hal_rfid_tim_read(worker->frequency, worker->duty_cycle); - furi_hal_rfid_tim_read_start(); + furi_hal_rfid_tim_read_start(worker->frequency, worker->duty_cycle); // stabilize detector furi_delay_ms(1500); diff --git a/lib/lfrfid/lfrfid_worker_modes.c b/lib/lfrfid/lfrfid_worker_modes.c index 9b6f16eb14c9..8a26677746d1 100644 --- a/lib/lfrfid/lfrfid_worker_modes.c +++ b/lib/lfrfid/lfrfid_worker_modes.c @@ -100,24 +100,21 @@ static LFRFIDWorkerReadState lfrfid_worker_read_internal( uint32_t timeout, ProtocolId* result_protocol) { LFRFIDWorkerReadState state = LFRFIDWorkerReadTimeout; - furi_hal_rfid_pins_read(); if(feature & LFRFIDFeatureASK) { - furi_hal_rfid_tim_read(125000, 0.5); + furi_hal_rfid_tim_read_start(125000, 0.5); FURI_LOG_D(TAG, "Start ASK"); if(worker->read_cb) { worker->read_cb(LFRFIDWorkerReadStartASK, PROTOCOL_NO, worker->cb_ctx); } } else { - furi_hal_rfid_tim_read(62500, 0.25); + furi_hal_rfid_tim_read_start(62500, 0.25); FURI_LOG_D(TAG, "Start PSK"); if(worker->read_cb) { worker->read_cb(LFRFIDWorkerReadStartPSK, PROTOCOL_NO, worker->cb_ctx); } } - furi_hal_rfid_tim_read_start(); - // stabilize detector lfrfid_worker_delay(worker, LFRFID_WORKER_READ_STABILIZE_TIME_MS); @@ -205,7 +202,7 @@ static LFRFIDWorkerReadState lfrfid_worker_read_internal( average_index = 0; if(worker->read_cb) { - if(average > 0.2 && average < 0.8) { + if(average > 0.2f && average < 0.8f) { if(!card_detected) { card_detected = true; worker->read_cb( diff --git a/lib/lfrfid/protocols/lfrfid_protocols.c b/lib/lfrfid/protocols/lfrfid_protocols.c index 2c1f0ad97cd2..f07218d7f302 100644 --- a/lib/lfrfid/protocols/lfrfid_protocols.c +++ b/lib/lfrfid/protocols/lfrfid_protocols.c @@ -16,6 +16,7 @@ #include "protocol_pac_stanley.h" #include "protocol_keri.h" #include "protocol_gallagher.h" +#include "protocol_nexwatch.h" const ProtocolBase* lfrfid_protocols[] = { [LFRFIDProtocolEM4100] = &protocol_em4100, @@ -35,4 +36,5 @@ const ProtocolBase* lfrfid_protocols[] = { [LFRFIDProtocolPACStanley] = &protocol_pac_stanley, [LFRFIDProtocolKeri] = &protocol_keri, [LFRFIDProtocolGallagher] = &protocol_gallagher, -}; \ No newline at end of file + [LFRFIDProtocolNexwatch] = &protocol_nexwatch, +}; diff --git a/lib/lfrfid/protocols/lfrfid_protocols.h b/lib/lfrfid/protocols/lfrfid_protocols.h index 848f003a31e7..0cb7cbc84405 100644 --- a/lib/lfrfid/protocols/lfrfid_protocols.h +++ b/lib/lfrfid/protocols/lfrfid_protocols.h @@ -25,6 +25,7 @@ typedef enum { LFRFIDProtocolPACStanley, LFRFIDProtocolKeri, LFRFIDProtocolGallagher, + LFRFIDProtocolNexwatch, LFRFIDProtocolMax, } LFRFIDProtocol; @@ -39,4 +40,4 @@ typedef struct { union { LFRFIDT5577 t5577; }; -} LFRFIDWriteRequest; \ No newline at end of file +} LFRFIDWriteRequest; diff --git a/lib/lfrfid/protocols/protocol_nexwatch.c b/lib/lfrfid/protocols/protocol_nexwatch.c new file mode 100644 index 000000000000..3bbbb42f503c --- /dev/null +++ b/lib/lfrfid/protocols/protocol_nexwatch.c @@ -0,0 +1,323 @@ +#include +#include +#include +#include "lfrfid_protocols.h" + +#define NEXWATCH_PREAMBLE_BIT_SIZE (8) +#define NEXWATCH_PREAMBLE_DATA_SIZE (1) + +#define NEXWATCH_ENCODED_BIT_SIZE (96) +#define NEXWATCH_ENCODED_DATA_SIZE ((NEXWATCH_ENCODED_BIT_SIZE) / 8) + +#define NEXWATCH_DECODED_BIT_SIZE (NEXWATCH_DECODED_DATA_SIZE * 8) +#define NEXWATCH_DECODED_DATA_SIZE (8) + +#define NEXWATCH_US_PER_BIT (255) +#define NEXWATCH_ENCODER_PULSES_PER_BIT (16) + +typedef struct { + uint8_t magic; + char desc[13]; + uint8_t chk; +} ProtocolNexwatchMagic; + +ProtocolNexwatchMagic magic_items[] = { + {0xBE, "Quadrakey", 0}, + {0x88, "Nexkey", 0}, + {0x86, "Honeywell", 0}}; + +typedef struct { + uint8_t data_index; + uint8_t bit_clock_index; + bool last_bit; + bool current_polarity; + bool pulse_phase; +} ProtocolNexwatchEncoder; + +typedef struct { + uint8_t encoded_data[NEXWATCH_ENCODED_DATA_SIZE]; + uint8_t negative_encoded_data[NEXWATCH_ENCODED_DATA_SIZE]; + uint8_t corrupted_encoded_data[NEXWATCH_ENCODED_DATA_SIZE]; + uint8_t corrupted_negative_encoded_data[NEXWATCH_ENCODED_DATA_SIZE]; + + uint8_t data[NEXWATCH_DECODED_DATA_SIZE]; + ProtocolNexwatchEncoder encoder; +} ProtocolNexwatch; + +ProtocolNexwatch* protocol_nexwatch_alloc(void) { + ProtocolNexwatch* protocol = malloc(sizeof(ProtocolNexwatch)); + return protocol; +}; + +void protocol_nexwatch_free(ProtocolNexwatch* protocol) { + free(protocol); +}; + +uint8_t* protocol_nexwatch_get_data(ProtocolNexwatch* protocol) { + return protocol->data; +}; + +void protocol_nexwatch_decoder_start(ProtocolNexwatch* protocol) { + memset(protocol->encoded_data, 0, NEXWATCH_ENCODED_DATA_SIZE); + memset(protocol->negative_encoded_data, 0, NEXWATCH_ENCODED_DATA_SIZE); + memset(protocol->corrupted_encoded_data, 0, NEXWATCH_ENCODED_DATA_SIZE); + memset(protocol->corrupted_negative_encoded_data, 0, NEXWATCH_ENCODED_DATA_SIZE); +}; + +static bool protocol_nexwatch_check_preamble(uint8_t* data, size_t bit_index) { + // 01010110 + if(bit_lib_get_bits(data, bit_index, 8) != 0b01010110) return false; + return true; +} + +static uint8_t protocol_nexwatch_parity_swap(uint8_t parity) { + uint8_t a = (((parity >> 3) & 1)); + a |= (((parity >> 1) & 1) << 1); + a |= (((parity >> 2) & 1) << 2); + a |= ((parity & 1) << 3); + return a; +} + +static uint8_t protocol_nexwatch_parity(const uint8_t hexid[5]) { + uint8_t p = 0; + for(uint8_t i = 0; i < 5; i++) { + p ^= ((hexid[i]) & 0xF0) >> 4; + p ^= ((hexid[i]) & 0x0F); + } + return protocol_nexwatch_parity_swap(p); +} + +static uint8_t protocol_nexwatch_checksum(uint8_t magic, uint32_t id, uint8_t parity) { + uint8_t a = ((id >> 24) & 0xFF); + a -= ((id >> 16) & 0xFF); + a -= ((id >> 8) & 0xFF); + a -= (id & 0xFF); + a -= magic; + a -= (bit_lib_reverse_8_fast(parity) >> 4); + return bit_lib_reverse_8_fast(a); +} + +static bool protocol_nexwatch_can_be_decoded(uint8_t* data) { + if(!protocol_nexwatch_check_preamble(data, 0)) return false; + + // Check for reserved word (32-bit) + if(bit_lib_get_bits_32(data, 8, 32) != 0) { + return false; + } + + uint8_t parity = bit_lib_get_bits(data, 76, 4); + + // parity check + // from 32b hex id, 4b mode + uint8_t hex[5] = {0}; + for(uint8_t i = 0; i < 5; i++) { + hex[i] = bit_lib_get_bits(data, 40 + (i * 8), 8); + } + //mode is only 4 bits. + hex[4] &= 0xf0; + uint8_t calc_parity = protocol_nexwatch_parity(hex); + + if(calc_parity != parity) { + return false; + } + + return true; +} + +static bool protocol_nexwatch_decoder_feed_internal(bool polarity, uint32_t time, uint8_t* data) { + time += (NEXWATCH_US_PER_BIT / 2); + + size_t bit_count = (time / NEXWATCH_US_PER_BIT); + bool result = false; + + if(bit_count < NEXWATCH_ENCODED_BIT_SIZE) { + for(size_t i = 0; i < bit_count; i++) { + bit_lib_push_bit(data, NEXWATCH_ENCODED_DATA_SIZE, polarity); + if(protocol_nexwatch_can_be_decoded(data)) { + result = true; + break; + } + } + } + + return result; +} + +static void protocol_nexwatch_descramble(uint32_t* id, uint32_t* scrambled) { + // 255 = Not used/Unknown other values are the bit offset in the ID/FC values + const uint8_t hex_2_id[] = {31, 27, 23, 19, 15, 11, 7, 3, 30, 26, 22, 18, 14, 10, 6, 2, + 29, 25, 21, 17, 13, 9, 5, 1, 28, 24, 20, 16, 12, 8, 4, 0}; + + *id = 0; + for(uint8_t idx = 0; idx < 32; idx++) { + bool bit_state = (*scrambled >> hex_2_id[idx]) & 1; + *id |= (bit_state << (31 - idx)); + } +} + +static void protocol_nexwatch_decoder_save(uint8_t* data_to, const uint8_t* data_from) { + uint32_t id = bit_lib_get_bits_32(data_from, 40, 32); + data_to[4] = (uint8_t)id; + data_to[3] = (uint8_t)(id >>= 8); + data_to[2] = (uint8_t)(id >>= 8); + data_to[1] = (uint8_t)(id >>= 8); + data_to[0] = (uint8_t)(id >>= 8); + uint32_t check = bit_lib_get_bits_32(data_from, 72, 24); + data_to[7] = (uint8_t)check; + data_to[6] = (uint8_t)(check >>= 8); + data_to[5] = (uint8_t)(check >>= 8); +} + +bool protocol_nexwatch_decoder_feed(ProtocolNexwatch* protocol, bool level, uint32_t duration) { + bool result = false; + + if(duration > (NEXWATCH_US_PER_BIT / 2)) { + if(protocol_nexwatch_decoder_feed_internal(level, duration, protocol->encoded_data)) { + protocol_nexwatch_decoder_save(protocol->data, protocol->encoded_data); + result = true; + return result; + } + + if(protocol_nexwatch_decoder_feed_internal( + !level, duration, protocol->negative_encoded_data)) { + protocol_nexwatch_decoder_save(protocol->data, protocol->negative_encoded_data); + result = true; + return result; + } + } + + if(duration > (NEXWATCH_US_PER_BIT / 4)) { + // Try to decode wrong phase synced data + if(level) { + duration += 120; + } else { + if(duration > 120) { + duration -= 120; + } + } + + if(protocol_nexwatch_decoder_feed_internal( + level, duration, protocol->corrupted_encoded_data)) { + protocol_nexwatch_decoder_save(protocol->data, protocol->corrupted_encoded_data); + + result = true; + return result; + } + + if(protocol_nexwatch_decoder_feed_internal( + !level, duration, protocol->corrupted_negative_encoded_data)) { + protocol_nexwatch_decoder_save( + protocol->data, protocol->corrupted_negative_encoded_data); + + result = true; + return result; + } + } + + return result; +}; + +bool protocol_nexwatch_encoder_start(ProtocolNexwatch* protocol) { + memset(protocol->encoded_data, 0, NEXWATCH_ENCODED_DATA_SIZE); + *(uint32_t*)&protocol->encoded_data[0] = 0b00000000000000000000000001010110; + bit_lib_copy_bits(protocol->encoded_data, 32, 32, protocol->data, 0); + bit_lib_copy_bits(protocol->encoded_data, 64, 32, protocol->data, 32); + + protocol->encoder.last_bit = + bit_lib_get_bit(protocol->encoded_data, NEXWATCH_ENCODED_BIT_SIZE - 1); + protocol->encoder.data_index = 0; + protocol->encoder.current_polarity = true; + protocol->encoder.pulse_phase = true; + protocol->encoder.bit_clock_index = 0; + + return true; +}; + +LevelDuration protocol_nexwatch_encoder_yield(ProtocolNexwatch* protocol) { + LevelDuration level_duration; + ProtocolNexwatchEncoder* encoder = &protocol->encoder; + + if(encoder->pulse_phase) { + level_duration = level_duration_make(encoder->current_polarity, 1); + encoder->pulse_phase = false; + } else { + level_duration = level_duration_make(!encoder->current_polarity, 1); + encoder->pulse_phase = true; + + encoder->bit_clock_index++; + if(encoder->bit_clock_index >= NEXWATCH_ENCODER_PULSES_PER_BIT) { + encoder->bit_clock_index = 0; + + bool current_bit = bit_lib_get_bit(protocol->encoded_data, encoder->data_index); + + if(current_bit != encoder->last_bit) { + encoder->current_polarity = !encoder->current_polarity; + } + + encoder->last_bit = current_bit; + + bit_lib_increment_index(encoder->data_index, NEXWATCH_ENCODED_BIT_SIZE); + } + } + + return level_duration; +}; + +void protocol_nexwatch_render_data(ProtocolNexwatch* protocol, FuriString* result) { + uint32_t id = 0; + uint32_t scrambled = bit_lib_get_bits_32(protocol->data, 8, 32); + protocol_nexwatch_descramble(&id, &scrambled); + + uint8_t m_idx; + uint8_t mode = bit_lib_get_bits(protocol->data, 40, 4); + uint8_t parity = bit_lib_get_bits(protocol->data, 44, 4); + uint8_t chk = bit_lib_get_bits(protocol->data, 48, 8); + for(m_idx = 0; m_idx < 3; m_idx++) { + magic_items[m_idx].chk = protocol_nexwatch_checksum(magic_items[m_idx].magic, id, parity); + if(magic_items[m_idx].chk == chk) { + break; + } + } + furi_string_printf(result, "ID: %lu, M:%u\r\nType: %s\r\n", id, mode, magic_items[m_idx].desc); +} + +bool protocol_nexwatch_write_data(ProtocolNexwatch* protocol, void* data) { + LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data; + bool result = false; + + protocol_nexwatch_encoder_start(protocol); + if(request->write_type == LFRFIDWriteTypeT5577) { + request->t5577.block[0] = LFRFID_T5577_MODULATION_PSK1 | LFRFID_T5577_BITRATE_RF_32 | + (3 << LFRFID_T5577_MAXBLOCK_SHIFT); + request->t5577.block[1] = bit_lib_get_bits_32(protocol->encoded_data, 0, 32); + request->t5577.block[2] = bit_lib_get_bits_32(protocol->encoded_data, 32, 32); + request->t5577.block[3] = bit_lib_get_bits_32(protocol->encoded_data, 64, 32); + request->t5577.blocks_to_write = 4; + result = true; + } + return result; +}; + +const ProtocolBase protocol_nexwatch = { + .name = "Nexwatch", + .manufacturer = "Honeywell", + .data_size = NEXWATCH_DECODED_DATA_SIZE, + .features = LFRFIDFeaturePSK, + .validate_count = 6, + .alloc = (ProtocolAlloc)protocol_nexwatch_alloc, + .free = (ProtocolFree)protocol_nexwatch_free, + .get_data = (ProtocolGetData)protocol_nexwatch_get_data, + .decoder = + { + .start = (ProtocolDecoderStart)protocol_nexwatch_decoder_start, + .feed = (ProtocolDecoderFeed)protocol_nexwatch_decoder_feed, + }, + .encoder = + { + .start = (ProtocolEncoderStart)protocol_nexwatch_encoder_start, + .yield = (ProtocolEncoderYield)protocol_nexwatch_encoder_yield, + }, + .render_data = (ProtocolRenderData)protocol_nexwatch_render_data, + .render_brief_data = (ProtocolRenderData)protocol_nexwatch_render_data, + .write_data = (ProtocolWriteData)protocol_nexwatch_write_data, +}; diff --git a/lib/lfrfid/protocols/protocol_nexwatch.h b/lib/lfrfid/protocols/protocol_nexwatch.h new file mode 100644 index 000000000000..0872ca7dcdde --- /dev/null +++ b/lib/lfrfid/protocols/protocol_nexwatch.h @@ -0,0 +1,4 @@ +#pragma once +#include + +extern const ProtocolBase protocol_nexwatch; diff --git a/lib/lfrfid/tools/t5577.c b/lib/lfrfid/tools/t5577.c index 3444afea3e41..00c9ddfb6272 100644 --- a/lib/lfrfid/tools/t5577.c +++ b/lib/lfrfid/tools/t5577.c @@ -14,9 +14,7 @@ #define T5577_OPCODE_RESET 0b00 static void t5577_start() { - furi_hal_rfid_tim_read(125000, 0.5); - furi_hal_rfid_pins_read(); - furi_hal_rfid_tim_read_start(); + furi_hal_rfid_tim_read_start(125000, 0.5); // do not ground the antenna furi_hal_rfid_pin_pull_release(); @@ -24,14 +22,13 @@ static void t5577_start() { static void t5577_stop() { furi_hal_rfid_tim_read_stop(); - furi_hal_rfid_tim_reset(); furi_hal_rfid_pins_reset(); } static void t5577_write_gap(uint32_t gap_time) { - furi_hal_rfid_tim_read_stop(); + furi_hal_rfid_tim_read_pause(); furi_delay_us(gap_time * 8); - furi_hal_rfid_tim_read_start(); + furi_hal_rfid_tim_read_continue(); } static void t5577_write_bit(bool value) { diff --git a/lib/misc.scons b/lib/misc.scons index 6905b5035a10..92fa5a106ff1 100644 --- a/lib/misc.scons +++ b/lib/misc.scons @@ -4,7 +4,6 @@ Import("env") env.Append( CPPPATH=[ - "#/lib/digital_signal", "#/lib/fnv1a_hash", "#/lib/heatshrink", "#/lib/micro-ecc", @@ -29,7 +28,6 @@ libenv.ApplyLibFlags() sources = [] libs_recurse = [ - "digital_signal", "micro-ecc", "u8g2", "update_util", diff --git a/lib/nfc/deprecated/nfc_device.c b/lib/nfc/deprecated/nfc_device.c index c9a3911b9fa5..581eb6e97b99 100644 --- a/lib/nfc/deprecated/nfc_device.c +++ b/lib/nfc/deprecated/nfc_device.c @@ -58,6 +58,8 @@ static void nfc_device_prepare_format_string(NfcDevice* dev, FuriString* format_ furi_string_set(format_string, "Mifare Classic"); } else if(dev->format == NfcDeviceSaveFormatMifareDesfire) { furi_string_set(format_string, "Mifare DESFire"); + } else if(dev->format == NfcDeviceSaveFormatNfcV) { + furi_string_set(format_string, "ISO15693"); } else { furi_string_set(format_string, "Unknown"); } @@ -93,6 +95,11 @@ static bool nfc_device_parse_format_string(NfcDevice* dev, FuriString* format_st dev->dev_data.protocol = NfcDeviceProtocolMifareDesfire; return true; } + if(furi_string_start_with_str(format_string, "ISO15693")) { + dev->format = NfcDeviceSaveFormatNfcV; + dev->dev_data.protocol = NfcDeviceProtocolNfcV; + return true; + } return false; } @@ -650,7 +657,327 @@ bool nfc_device_load_mifare_df_data(FlipperFormat* file, NfcDevice* dev) { return parsed; } -// Leave for backward compatibility +static bool nfc_device_save_slix_data(FlipperFormat* file, NfcDevice* dev) { + bool saved = false; + NfcVSlixData* data = &dev->dev_data.nfcv_data.sub_data.slix; + + do { + if(!flipper_format_write_comment_cstr(file, "SLIX specific data")) break; + if(!flipper_format_write_hex(file, "Password EAS", data->key_eas, sizeof(data->key_eas))) + break; + saved = true; + } while(false); + + return saved; +} + +bool nfc_device_load_slix_data(FlipperFormat* file, NfcDevice* dev) { + bool parsed = false; + NfcVSlixData* data = &dev->dev_data.nfcv_data.sub_data.slix; + memset(data, 0, sizeof(NfcVSlixData)); + + do { + if(!flipper_format_read_hex(file, "Password EAS", data->key_eas, sizeof(data->key_eas))) + break; + + parsed = true; + } while(false); + + return parsed; +} + +static bool nfc_device_save_slix_s_data(FlipperFormat* file, NfcDevice* dev) { + bool saved = false; + NfcVSlixData* data = &dev->dev_data.nfcv_data.sub_data.slix; + + do { + if(!flipper_format_write_comment_cstr(file, "SLIX-S specific data")) break; + if(!flipper_format_write_hex(file, "Password Read", data->key_read, sizeof(data->key_read))) + break; + if(!flipper_format_write_hex( + file, "Password Write", data->key_write, sizeof(data->key_write))) + break; + if(!flipper_format_write_hex( + file, "Password Privacy", data->key_privacy, sizeof(data->key_privacy))) + break; + if(!flipper_format_write_hex( + file, "Password Destroy", data->key_destroy, sizeof(data->key_destroy))) + break; + if(!flipper_format_write_hex(file, "Password EAS", data->key_eas, sizeof(data->key_eas))) + break; + if(!flipper_format_write_bool(file, "Privacy Mode", &data->privacy, 1)) break; + saved = true; + } while(false); + + return saved; +} + +bool nfc_device_load_slix_s_data(FlipperFormat* file, NfcDevice* dev) { + bool parsed = false; + NfcVSlixData* data = &dev->dev_data.nfcv_data.sub_data.slix; + memset(data, 0, sizeof(NfcVSlixData)); + + do { + if(!flipper_format_read_hex(file, "Password Read", data->key_read, sizeof(data->key_read))) + break; + if(!flipper_format_read_hex( + file, "Password Write", data->key_write, sizeof(data->key_write))) + break; + if(!flipper_format_read_hex( + file, "Password Privacy", data->key_privacy, sizeof(data->key_privacy))) + break; + if(!flipper_format_read_hex( + file, "Password Destroy", data->key_destroy, sizeof(data->key_destroy))) + break; + if(!flipper_format_read_hex(file, "Password EAS", data->key_eas, sizeof(data->key_eas))) + break; + if(!flipper_format_read_bool(file, "Privacy Mode", &data->privacy, 1)) break; + + parsed = true; + } while(false); + + return parsed; +} + +static bool nfc_device_save_slix_l_data(FlipperFormat* file, NfcDevice* dev) { + bool saved = false; + NfcVSlixData* data = &dev->dev_data.nfcv_data.sub_data.slix; + + do { + if(!flipper_format_write_comment_cstr(file, "SLIX-L specific data")) break; + if(!flipper_format_write_hex( + file, "Password Privacy", data->key_privacy, sizeof(data->key_privacy))) + break; + if(!flipper_format_write_hex( + file, "Password Destroy", data->key_destroy, sizeof(data->key_destroy))) + break; + if(!flipper_format_write_hex(file, "Password EAS", data->key_eas, sizeof(data->key_eas))) + break; + if(!flipper_format_write_bool(file, "Privacy Mode", &data->privacy, 1)) break; + saved = true; + } while(false); + + return saved; +} + +bool nfc_device_load_slix_l_data(FlipperFormat* file, NfcDevice* dev) { + bool parsed = false; + NfcVSlixData* data = &dev->dev_data.nfcv_data.sub_data.slix; + memset(data, 0, sizeof(NfcVSlixData)); + + do { + if(!flipper_format_read_hex( + file, "Password Privacy", data->key_privacy, sizeof(data->key_privacy))) + break; + if(!flipper_format_read_hex( + file, "Password Destroy", data->key_destroy, sizeof(data->key_destroy))) + break; + if(!flipper_format_read_hex(file, "Password EAS", data->key_eas, sizeof(data->key_eas))) + break; + if(!flipper_format_read_bool(file, "Privacy Mode", &data->privacy, 1)) break; + + parsed = true; + } while(false); + + return parsed; +} + +static bool nfc_device_save_slix2_data(FlipperFormat* file, NfcDevice* dev) { + bool saved = false; + NfcVSlixData* data = &dev->dev_data.nfcv_data.sub_data.slix; + + do { + if(!flipper_format_write_comment_cstr(file, "SLIX2 specific data")) break; + if(!flipper_format_write_hex(file, "Password Read", data->key_read, sizeof(data->key_read))) + break; + if(!flipper_format_write_hex( + file, "Password Write", data->key_write, sizeof(data->key_write))) + break; + if(!flipper_format_write_hex( + file, "Password Privacy", data->key_privacy, sizeof(data->key_privacy))) + break; + if(!flipper_format_write_hex( + file, "Password Destroy", data->key_destroy, sizeof(data->key_destroy))) + break; + if(!flipper_format_write_hex(file, "Password EAS", data->key_eas, sizeof(data->key_eas))) + break; + if(!flipper_format_write_bool(file, "Privacy Mode", &data->privacy, 1)) break; + saved = true; + } while(false); + + return saved; +} + +bool nfc_device_load_slix2_data(FlipperFormat* file, NfcDevice* dev) { // -V524 + bool parsed = false; + NfcVSlixData* data = &dev->dev_data.nfcv_data.sub_data.slix; + memset(data, 0, sizeof(NfcVSlixData)); + + do { + if(!flipper_format_read_hex(file, "Password Read", data->key_read, sizeof(data->key_read))) + break; + if(!flipper_format_read_hex( + file, "Password Write", data->key_write, sizeof(data->key_write))) + break; + if(!flipper_format_read_hex( + file, "Password Privacy", data->key_privacy, sizeof(data->key_privacy))) + break; + if(!flipper_format_read_hex( + file, "Password Destroy", data->key_destroy, sizeof(data->key_destroy))) + break; + if(!flipper_format_read_hex(file, "Password EAS", data->key_eas, sizeof(data->key_eas))) + break; + if(!flipper_format_read_bool(file, "Privacy Mode", &data->privacy, 1)) break; + + parsed = true; + } while(false); + + return parsed; +} + +static bool nfc_device_save_nfcv_data(FlipperFormat* file, NfcDevice* dev) { + bool saved = false; + NfcVData* data = &dev->dev_data.nfcv_data; + + do { + uint32_t temp_uint32 = 0; + uint8_t temp_uint8 = 0; + + if(!flipper_format_write_comment_cstr(file, "Data Storage Format Identifier")) break; + if(!flipper_format_write_hex(file, "DSFID", &(data->dsfid), 1)) break; + if(!flipper_format_write_comment_cstr(file, "Application Family Identifier")) break; + if(!flipper_format_write_hex(file, "AFI", &(data->afi), 1)) break; + if(!flipper_format_write_hex(file, "IC Reference", &(data->ic_ref), 1)) break; + temp_uint32 = data->block_num; + if(!flipper_format_write_comment_cstr(file, "Number of memory blocks, usually 0 to 256")) + break; + if(!flipper_format_write_uint32(file, "Block Count", &temp_uint32, 1)) break; + if(!flipper_format_write_comment_cstr(file, "Size of a single memory block, usually 4")) + break; + if(!flipper_format_write_hex(file, "Block Size", &(data->block_size), 1)) break; + if(!flipper_format_write_hex( + file, "Data Content", data->data, data->block_num * data->block_size)) + break; + if(!flipper_format_write_comment_cstr( + file, "First byte: DSFID (0x01) / AFI (0x02) lock info, others: block lock info")) + break; + if(!flipper_format_write_hex( + file, "Security Status", data->security_status, 1 + data->block_num)) + break; + if(!flipper_format_write_comment_cstr( + file, + "Subtype of this card (0 = ISO15693, 1 = SLIX, 2 = SLIX-S, 3 = SLIX-L, 4 = SLIX2)")) + break; + temp_uint8 = (uint8_t)data->sub_type; + if(!flipper_format_write_hex(file, "Subtype", &temp_uint8, 1)) break; + + switch(data->sub_type) { + case NfcVTypePlain: + if(!flipper_format_write_comment_cstr(file, "End of ISO15693 parameters")) break; + saved = true; + break; + case NfcVTypeSlix: + saved = nfc_device_save_slix_data(file, dev); + break; + case NfcVTypeSlixS: + saved = nfc_device_save_slix_s_data(file, dev); + break; + case NfcVTypeSlixL: + saved = nfc_device_save_slix_l_data(file, dev); + break; + case NfcVTypeSlix2: + saved = nfc_device_save_slix2_data(file, dev); + break; + default: + break; + } + } while(false); + + return saved; +} + +bool nfc_device_load_nfcv_data(FlipperFormat* file, NfcDevice* dev) { + bool parsed = false; + NfcVData* data = &dev->dev_data.nfcv_data; + + memset(data, 0x00, sizeof(NfcVData)); + + do { + uint32_t temp_uint32 = 0; + uint8_t temp_value = 0; + + if(!flipper_format_read_hex(file, "DSFID", &(data->dsfid), 1)) break; + if(!flipper_format_read_hex(file, "AFI", &(data->afi), 1)) break; + if(!flipper_format_read_hex(file, "IC Reference", &(data->ic_ref), 1)) break; + if(!flipper_format_read_uint32(file, "Block Count", &temp_uint32, 1)) break; + data->block_num = temp_uint32; + if(!flipper_format_read_hex(file, "Block Size", &(data->block_size), 1)) break; + if(!flipper_format_read_hex( + file, "Data Content", data->data, data->block_num * data->block_size)) + break; + + /* optional, as added later */ + if(flipper_format_key_exist(file, "Security Status")) { + if(!flipper_format_read_hex( + file, "Security Status", data->security_status, 1 + data->block_num)) + break; + } + if(!flipper_format_read_hex(file, "Subtype", &temp_value, 1)) break; + data->sub_type = temp_value; + + switch(data->sub_type) { + case NfcVTypePlain: + parsed = true; + break; + case NfcVTypeSlix: + parsed = nfc_device_load_slix_data(file, dev); + break; + case NfcVTypeSlixS: + parsed = nfc_device_load_slix_s_data(file, dev); + break; + case NfcVTypeSlixL: + parsed = nfc_device_load_slix_l_data(file, dev); + break; + case NfcVTypeSlix2: + parsed = nfc_device_load_slix2_data(file, dev); + break; + default: + break; + } + } while(false); + + return parsed; +} + +static bool nfc_device_save_bank_card_data(FlipperFormat* file, NfcDevice* dev) { + bool saved = false; + EmvData* data = &dev->dev_data.emv_data; + uint32_t data_temp = 0; + + do { + // Write Bank card specific data + if(!flipper_format_write_comment_cstr(file, "Bank card specific data")) break; + if(!flipper_format_write_hex(file, "AID", data->aid, data->aid_len)) break; + if(!flipper_format_write_string_cstr(file, "Name", data->name)) break; + if(!flipper_format_write_hex(file, "Number", data->number, data->number_len)) break; + if(data->exp_mon) { + uint8_t exp_data[2] = {data->exp_mon, data->exp_year}; + if(!flipper_format_write_hex(file, "Exp data", exp_data, sizeof(exp_data))) break; + } + if(data->country_code) { + data_temp = data->country_code; + if(!flipper_format_write_uint32(file, "Country code", &data_temp, 1)) break; + } + if(data->currency_code) { + data_temp = data->currency_code; + if(!flipper_format_write_uint32(file, "Currency code", &data_temp, 1)) break; + } + saved = true; + } while(false); + + return saved; +} + bool nfc_device_load_bank_card_data(FlipperFormat* file, NfcDevice* dev) { bool parsed = false; EmvData* data = &dev->dev_data.emv_data; @@ -1070,23 +1397,32 @@ bool nfc_device_save(NfcDevice* dev, const char* dev_name) { if(!flipper_format_write_header_cstr(file, nfc_file_header, nfc_file_version)) break; // Write nfc device type if(!flipper_format_write_comment_cstr( - file, "Nfc device type can be UID, Mifare Ultralight, Mifare Classic")) + file, "Nfc device type can be UID, Mifare Ultralight, Mifare Classic or ISO15693")) break; nfc_device_prepare_format_string(dev, temp_str); if(!flipper_format_write_string(file, "Device type", temp_str)) break; - // Write UID, ATQA, SAK - if(!flipper_format_write_comment_cstr(file, "UID, ATQA and SAK are common for all formats")) - break; + // Write UID + if(!flipper_format_write_comment_cstr(file, "UID is common for all formats")) break; if(!flipper_format_write_hex(file, "UID", data->uid, data->uid_len)) break; - // Save ATQA in MSB order for correct companion apps display - uint8_t atqa[2] = {data->atqa[1], data->atqa[0]}; - if(!flipper_format_write_hex(file, "ATQA", atqa, 2)) break; - if(!flipper_format_write_hex(file, "SAK", &data->sak, 1)) break; + + if(dev->format != NfcDeviceSaveFormatNfcV) { + // Write ATQA, SAK + if(!flipper_format_write_comment_cstr(file, "ISO14443 specific fields")) break; + // Save ATQA in MSB order for correct companion apps display + uint8_t atqa[2] = {data->atqa[1], data->atqa[0]}; + if(!flipper_format_write_hex(file, "ATQA", atqa, 2)) break; + if(!flipper_format_write_hex(file, "SAK", &data->sak, 1)) break; + } + // Save more data if necessary if(dev->format == NfcDeviceSaveFormatMifareUl) { if(!nfc_device_save_mifare_ul_data(file, dev)) break; } else if(dev->format == NfcDeviceSaveFormatMifareDesfire) { if(!nfc_device_save_mifare_df_data(file, dev)) break; + } else if(dev->format == NfcDeviceSaveFormatNfcV) { + if(!nfc_device_save_nfcv_data(file, dev)) break; + } else if(dev->format == NfcDeviceSaveFormatBankCard) { + if(!nfc_device_save_bank_card_data(file, dev)) break; } else if(dev->format == NfcDeviceSaveFormatMifareClassic) { // Save data if(!nfc_device_save_mifare_classic_data(file, dev)) break; @@ -1161,18 +1497,20 @@ static bool nfc_device_load_data(NfcDevice* dev, FuriString* path, bool show_dia if(!nfc_device_parse_format_string(dev, temp_str)) break; // Read and parse UID, ATQA and SAK if(!flipper_format_get_value_count(file, "UID", &data_cnt)) break; - if(!(data_cnt == 4 || data_cnt == 7)) break; + if(!(data_cnt == 4 || data_cnt == 7 || data_cnt == 8)) break; data->uid_len = data_cnt; if(!flipper_format_read_hex(file, "UID", data->uid, data->uid_len)) break; - if(version == version_with_lsb_atqa) { - if(!flipper_format_read_hex(file, "ATQA", data->atqa, 2)) break; - } else { - uint8_t atqa[2] = {}; - if(!flipper_format_read_hex(file, "ATQA", atqa, 2)) break; - data->atqa[0] = atqa[1]; - data->atqa[1] = atqa[0]; + if(dev->format != NfcDeviceSaveFormatNfcV) { + if(version == version_with_lsb_atqa) { + if(!flipper_format_read_hex(file, "ATQA", data->atqa, 2)) break; + } else { + uint8_t atqa[2] = {}; + if(!flipper_format_read_hex(file, "ATQA", atqa, 2)) break; + data->atqa[0] = atqa[1]; + data->atqa[1] = atqa[0]; + } + if(!flipper_format_read_hex(file, "SAK", &data->sak, 1)) break; } - if(!flipper_format_read_hex(file, "SAK", &data->sak, 1)) break; // Load CUID uint8_t* cuid_start = data->uid; if(data->uid_len == 7) { @@ -1187,6 +1525,8 @@ static bool nfc_device_load_data(NfcDevice* dev, FuriString* path, bool show_dia if(!nfc_device_load_mifare_classic_data(file, dev)) break; } else if(dev->format == NfcDeviceSaveFormatMifareDesfire) { if(!nfc_device_load_mifare_df_data(file, dev)) break; + } else if(dev->format == NfcDeviceSaveFormatNfcV) { + if(!nfc_device_load_nfcv_data(file, dev)) break; } else if(dev->format == NfcDeviceSaveFormatBankCard) { if(!nfc_device_load_bank_card_data(file, dev)) break; } diff --git a/lib/nfc/deprecated/nfc_device.h b/lib/nfc/deprecated/nfc_device.h index 2a8fe3fcede2..8c447213b69b 100644 --- a/lib/nfc/deprecated/nfc_device.h +++ b/lib/nfc/deprecated/nfc_device.h @@ -11,6 +11,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -31,6 +32,7 @@ typedef enum { NfcDeviceProtocolMifareUl, NfcDeviceProtocolMifareClassic, NfcDeviceProtocolMifareDesfire, + NfcDeviceProtocolNfcV } NfcProtocol; typedef enum { @@ -39,6 +41,7 @@ typedef enum { NfcDeviceSaveFormatMifareUl, NfcDeviceSaveFormatMifareClassic, NfcDeviceSaveFormatMifareDesfire, + NfcDeviceSaveFormatNfcV, } NfcDeviceSaveFormat; typedef struct { @@ -73,6 +76,7 @@ typedef struct { MfUltralightData mf_ul_data; MfClassicData mf_classic_data; MifareDesfireData mf_df_data; + NfcVData nfcv_data; }; FuriString* parsed_data; } NfcDeviceData; diff --git a/lib/nfc/deprecated/nfc_types.c b/lib/nfc/deprecated/nfc_types.c index 02ca85580dbc..96b92640f0ec 100644 --- a/lib/nfc/deprecated/nfc_types.c +++ b/lib/nfc/deprecated/nfc_types.c @@ -45,6 +45,8 @@ const char* nfc_mf_ul_type(MfUltralightType type, bool full_name) { return "NTAG I2C Plus 2K"; } else if(type == MfUltralightTypeNTAG203) { return "NTAG203"; + } else if(type == MfUltralightTypeULC) { + return "Mifare Ultralight C"; } else if(type == MfUltralightTypeUL11 && full_name) { return "Mifare Ultralight 11"; } else if(type == MfUltralightTypeUL21 && full_name) { diff --git a/lib/nfc/deprecated/nfc_worker.c b/lib/nfc/deprecated/nfc_worker.c index 0d625142883d..2b230decaccb 100644 --- a/lib/nfc/deprecated/nfc_worker.c +++ b/lib/nfc/deprecated/nfc_worker.c @@ -111,6 +111,14 @@ int32_t nfc_worker_task(void* context) { nfc_worker_mf_classic_dict_attack(nfc_worker); } else if(nfc_worker->state == NfcWorkerStateAnalyzeReader) { nfc_worker_analyze_reader(nfc_worker); + } else if(nfc_worker->state == NfcWorkerStateNfcVEmulate) { + nfc_worker_nfcv_emulate(nfc_worker); + } else if(nfc_worker->state == NfcWorkerStateNfcVSniff) { + nfc_worker_nfcv_sniff(nfc_worker); + } else if(nfc_worker->state == NfcWorkerStateNfcVUnlock) { + nfc_worker_nfcv_unlock(nfc_worker); + } else if(nfc_worker->state == NfcWorkerStateNfcVUnlockAndSave) { + nfc_worker_nfcv_unlock(nfc_worker); } furi_hal_nfc_sleep(); nfc_worker_change_state(nfc_worker, NfcWorkerStateReady); @@ -118,6 +126,236 @@ int32_t nfc_worker_task(void* context) { return 0; } +static bool nfc_worker_read_nfcv(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) { + bool read_success = false; + NfcVReader reader = {}; + + FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; + NfcVData* nfcv_data = &nfc_worker->dev_data->nfcv_data; + + furi_hal_nfc_sleep(); + + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + reader_analyzer_prepare_tx_rx(nfc_worker->reader_analyzer, tx_rx, false); + reader_analyzer_start(nfc_worker->reader_analyzer, ReaderAnalyzerModeDebugLog); + } + + do { + if(!furi_hal_nfc_detect(&nfc_worker->dev_data->nfc_data, 200)) break; + if(!nfcv_read_card(&reader, nfc_data, nfcv_data)) break; + + read_success = true; + } while(false); + + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + reader_analyzer_stop(nfc_worker->reader_analyzer); + } + + return read_success; +} + +void nfc_worker_nfcv_emulate(NfcWorker* nfc_worker) { + FuriHalNfcTxRxContext tx_rx = {}; + FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; + NfcVData* nfcv_data = &nfc_worker->dev_data->nfcv_data; + + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + reader_analyzer_prepare_tx_rx(nfc_worker->reader_analyzer, &tx_rx, true); + reader_analyzer_start(nfc_worker->reader_analyzer, ReaderAnalyzerModeDebugLog); + } + + nfcv_emu_init(nfc_data, nfcv_data); + while(nfc_worker->state == NfcWorkerStateNfcVEmulate) { + if(nfcv_emu_loop(&tx_rx, nfc_data, nfcv_data, 100)) { + if(nfc_worker->callback) { + nfc_worker->callback(NfcWorkerEventNfcVCommandExecuted, nfc_worker->context); + if(nfcv_data->modified) { + nfc_worker->callback(NfcWorkerEventNfcVContentChanged, nfc_worker->context); + nfcv_data->modified = false; + } + } + } + } + nfcv_emu_deinit(nfcv_data); + + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + reader_analyzer_stop(nfc_worker->reader_analyzer); + } +} + +void nfc_worker_nfcv_sniff(NfcWorker* nfc_worker) { + FuriHalNfcTxRxContext tx_rx = {}; + FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; + NfcVData* nfcv_data = &nfc_worker->dev_data->nfcv_data; + + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + reader_analyzer_prepare_tx_rx(nfc_worker->reader_analyzer, &tx_rx, true); + reader_analyzer_start(nfc_worker->reader_analyzer, ReaderAnalyzerModeDebugLog); + } + + nfcv_data->sub_type = NfcVTypeSniff; + nfcv_emu_init(nfc_data, nfcv_data); + + while(nfc_worker->state == NfcWorkerStateNfcVSniff) { + if(nfcv_emu_loop(&tx_rx, nfc_data, nfcv_data, 100)) { + if(nfc_worker->callback) { + nfc_worker->callback(NfcWorkerEventNfcVCommandExecuted, nfc_worker->context); + } + } + } + nfcv_emu_deinit(nfcv_data); + + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + reader_analyzer_stop(nfc_worker->reader_analyzer); + } +} + +void nfc_worker_nfcv_unlock(NfcWorker* nfc_worker) { + furi_assert(nfc_worker); + furi_assert(nfc_worker->callback); + + NfcVData* nfcv_data = &nfc_worker->dev_data->nfcv_data; + FuriHalNfcTxRxContext tx_rx = {}; + uint8_t* key_data = nfcv_data->sub_data.slix.key_privacy; + uint32_t key = 0; + + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + reader_analyzer_prepare_tx_rx(nfc_worker->reader_analyzer, &tx_rx, true); + reader_analyzer_start(nfc_worker->reader_analyzer, ReaderAnalyzerModeDebugLog); + } + + furi_hal_nfc_sleep(); + + while((nfc_worker->state == NfcWorkerStateNfcVUnlock) || + (nfc_worker->state == NfcWorkerStateNfcVUnlockAndSave)) { + furi_hal_nfc_exit_sleep(); + furi_hal_nfc_ll_txrx_on(); + furi_hal_nfc_ll_poll(); + if(furi_hal_nfc_ll_set_mode( + FuriHalNfcModePollNfcv, FuriHalNfcBitrate26p48, FuriHalNfcBitrate26p48) != + FuriHalNfcReturnOk) { + break; + } + + furi_hal_nfc_ll_set_fdt_listen(FURI_HAL_NFC_LL_FDT_LISTEN_NFCV_POLLER); + furi_hal_nfc_ll_set_fdt_poll(FURI_HAL_NFC_LL_FDT_POLL_NFCV_POLLER); + furi_hal_nfc_ll_set_error_handling(FuriHalNfcErrorHandlingNfc); + furi_hal_nfc_ll_set_guard_time(FURI_HAL_NFC_LL_GT_NFCV); + + FURI_LOG_D(TAG, "Detect presence"); + ReturnCode ret = slix_get_random(nfcv_data); + + if(ret == ERR_NONE) { + /* there is some chip, responding with a RAND */ + nfc_worker->dev_data->protocol = NfcDeviceProtocolNfcV; + FURI_LOG_D(TAG, " Chip detected. In privacy?"); + ret = nfcv_inventory(NULL); + + if(ret == ERR_NONE) { + /* chip is also visible, so no action required, just save */ + if(nfc_worker->state == NfcWorkerStateNfcVUnlockAndSave) { + NfcVReader reader = {}; + + if(!nfcv_read_card(&reader, &nfc_worker->dev_data->nfc_data, nfcv_data)) { + FURI_LOG_D(TAG, " => failed, wait for chip to disappear."); + snprintf(nfcv_data->error, sizeof(nfcv_data->error), "Read card\nfailed"); + nfc_worker->callback(NfcWorkerEventWrongCardDetected, nfc_worker->context); + } else { + FURI_LOG_D(TAG, " => success, wait for chip to disappear."); + nfc_worker->callback(NfcWorkerEventCardDetected, nfc_worker->context); + } + } else { + FURI_LOG_D(TAG, " => success, wait for chip to disappear."); + nfc_worker->callback(NfcWorkerEventCardDetected, nfc_worker->context); + } + + while(slix_get_random(NULL) == ERR_NONE) { + furi_delay_ms(100); + } + + FURI_LOG_D(TAG, " => chip is already visible, wait for chip to disappear.\r\n"); + nfc_worker->callback(NfcWorkerEventAborted, nfc_worker->context); + while(slix_get_random(NULL) == ERR_NONE) { + furi_delay_ms(100); + } + + key_data[0] = 0; + key_data[1] = 0; + key_data[2] = 0; + key_data[3] = 0; + + } else { + /* chip is invisible, try to unlock */ + FURI_LOG_D(TAG, " chip is invisible, unlocking"); + + if(nfcv_data->auth_method == NfcVAuthMethodManual) { + key |= key_data[0] << 24; + key |= key_data[1] << 16; + key |= key_data[2] << 8; + key |= key_data[3] << 0; + + ret = slix_unlock(nfcv_data, 4); + } else { + key = 0x7FFD6E5B; + key_data[0] = (key >> 24) & 0xFF; + key_data[1] = (key >> 16) & 0xFF; + key_data[2] = (key >> 8) & 0xFF; + key_data[3] = (key >> 0) & 0xFF; + ret = slix_unlock(nfcv_data, 4); + + if(ret != ERR_NONE) { + /* main key failed, trying second one */ + FURI_LOG_D(TAG, " trying second key after resetting"); + + /* reset chip */ + furi_hal_nfc_ll_txrx_off(); + furi_delay_ms(20); + furi_hal_nfc_ll_txrx_on(); + + if(slix_get_random(nfcv_data) != ERR_NONE) { + FURI_LOG_D(TAG, " reset failed"); + } + + key = 0x0F0F0F0F; + key_data[0] = (key >> 24) & 0xFF; + key_data[1] = (key >> 16) & 0xFF; + key_data[2] = (key >> 8) & 0xFF; + key_data[3] = (key >> 0) & 0xFF; + ret = slix_unlock(nfcv_data, 4); + } + } + if(ret != ERR_NONE) { + /* unlock failed */ + FURI_LOG_D(TAG, " => failed, wait for chip to disappear."); + snprintf( + nfcv_data->error, sizeof(nfcv_data->error), "Passwords not\naccepted"); + nfc_worker->callback(NfcWorkerEventWrongCardDetected, nfc_worker->context); + + /* reset chip */ + furi_hal_nfc_ll_txrx_off(); + furi_delay_ms(20); + furi_hal_nfc_ll_txrx_on(); + + /* wait for disappearing */ + while(slix_get_random(NULL) == ERR_NONE) { + furi_delay_ms(100); + } + } + } + } else { + nfc_worker->callback(NfcWorkerEventNoCardDetected, nfc_worker->context); + } + + furi_hal_nfc_ll_txrx_off(); + furi_hal_nfc_sleep(); + furi_delay_ms(100); + } + + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + reader_analyzer_stop(nfc_worker->reader_analyzer); + } +} + static bool nfc_worker_read_mf_ultralight(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) { bool read_success = false; MfUltralightReader reader = {}; @@ -219,6 +457,19 @@ static bool nfc_worker_read_mf_desfire(NfcWorker* nfc_worker, FuriHalNfcTxRxCont do { if(!furi_hal_nfc_detect(&nfc_worker->dev_data->nfc_data, 300)) break; if(!mf_df_read_card(tx_rx, data)) break; + FURI_LOG_I(TAG, "Trying to parse a supported card ..."); + + // The model for parsing DESFire is a little different to other cards; + // we don't have parsers to provide encryption keys, so we can read the + // data normally, and then pass the read data to a parser. + // + // There are fully-protected DESFire cards, but providing keys for them + // is difficult (and unnessesary for many transit cards). + for(size_t i = 0; i < NfcSupportedCardTypeEnd; i++) { + if(nfc_supported_card[i].protocol == NfcDeviceProtocolMifareDesfire) { + if(nfc_supported_card[i].parse(nfc_worker->dev_data)) break; + } + } read_success = true; } while(false); @@ -304,7 +555,12 @@ void nfc_worker_read(NfcWorker* nfc_worker) { event = NfcWorkerEventReadUidNfcF; break; } else if(nfc_data->type == FuriHalNfcTypeV) { - event = NfcWorkerEventReadUidNfcV; + FURI_LOG_I(TAG, "NfcV detected"); + nfc_worker->dev_data->protocol = NfcDeviceProtocolNfcV; + if(nfc_worker_read_nfcv(nfc_worker, &tx_rx)) { + FURI_LOG_I(TAG, "nfc_worker_read_nfcv success"); + } + event = NfcWorkerEventReadNfcV; break; } } else { @@ -661,7 +917,8 @@ void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker) { if(mifare_classic_authenticate_skip_activate( &tx_rx, block_num, key, MfClassicKeyA, !deactivated, cuid)) { mifare_classic_set_key_found(data, i, MfClassicKeyA, key); - FURI_LOG_D(TAG, "Key A found"); + FURI_LOG_D( + TAG, "Key A found: %04lx%08lx", (uint32_t)(key >> 32), (uint32_t)key); nfc_worker->callback(NfcWorkerEventFoundKeyA, nfc_worker->context); uint64_t found_key; @@ -683,8 +940,14 @@ void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker) { deactivated = true; } else { // If the key A is marked as found and matches the searching key, invalidate it + uint8_t found_key[6]; + memcpy(found_key, data->block[i].value, 6); + + uint8_t current_key[6]; + memcpy(current_key, &key, 6); + if(mifare_classic_is_key_found(data, i, MfClassicKeyA) && - data->block[i].value[0] == key) { + memcmp(found_key, current_key, 6) == 0) { mifare_classic_set_key_not_found(data, i, MfClassicKeyA); is_key_a_found = false; FURI_LOG_D(TAG, "Key %dA not found in attack", i); @@ -694,7 +957,8 @@ void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker) { is_key_b_found = mifare_classic_is_key_found(data, i, MfClassicKeyB); if(mifare_classic_authenticate_skip_activate( &tx_rx, block_num, key, MfClassicKeyB, !deactivated, cuid)) { - FURI_LOG_D(TAG, "Key B found"); + FURI_LOG_D( + TAG, "Key B found: %04lx%08lx", (uint32_t)(key >> 32), (uint32_t)key); mifare_classic_set_key_found(data, i, MfClassicKeyB, key); nfc_worker->callback(NfcWorkerEventFoundKeyB, nfc_worker->context); nfc_worker_mf_classic_key_attack(nfc_worker, key, &tx_rx, i + 1); @@ -702,8 +966,14 @@ void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker) { deactivated = true; } else { // If the key B is marked as found and matches the searching key, invalidate it + uint8_t found_key[6]; + memcpy(found_key, data->block[i].value + 10, 6); + + uint8_t current_key[6]; + memcpy(current_key, &key, 6); + if(mifare_classic_is_key_found(data, i, MfClassicKeyB) && - data->block[i].value[10] == key) { + memcmp(found_key, current_key, 6) == 0) { mifare_classic_set_key_not_found(data, i, MfClassicKeyB); is_key_b_found = false; FURI_LOG_D(TAG, "Key %dB not found in attack", i); @@ -748,7 +1018,7 @@ void nfc_worker_emulate_mf_classic(NfcWorker* nfc_worker) { furi_hal_nfc_listen_start(nfc_data); while(nfc_worker->state == NfcWorkerStateMfClassicEmulate) { //-V1044 if(furi_hal_nfc_listen_rx(&tx_rx, 300)) { - mifare_classic_emulator(&emulator, &tx_rx); + mifare_classic_emulator(&emulator, &tx_rx, false); } } if(emulator.data_changed) { @@ -1035,7 +1305,7 @@ void nfc_worker_analyze_reader(NfcWorker* nfc_worker) { NfcProtocol protocol = reader_analyzer_guess_protocol(reader_analyzer, tx_rx.rx_data, tx_rx.rx_bits / 8); if(protocol == NfcDeviceProtocolMifareClassic) { - mifare_classic_emulator(&emulator, &tx_rx); + mifare_classic_emulator(&emulator, &tx_rx, true); } } else { reader_no_data_received_cnt++; diff --git a/lib/nfc/deprecated/nfc_worker.h b/lib/nfc/deprecated/nfc_worker.h index 8e993fc6aa3c..722f148574f2 100644 --- a/lib/nfc/deprecated/nfc_worker.h +++ b/lib/nfc/deprecated/nfc_worker.h @@ -18,6 +18,10 @@ typedef enum { NfcWorkerStateReadMfUltralightReadAuth, NfcWorkerStateMfClassicDictAttack, NfcWorkerStateAnalyzeReader, + NfcWorkerStateNfcVEmulate, + NfcWorkerStateNfcVUnlock, + NfcWorkerStateNfcVUnlockAndSave, + NfcWorkerStateNfcVSniff, // Debug NfcWorkerStateEmulateApdu, NfcWorkerStateField, @@ -39,6 +43,7 @@ typedef enum { NfcWorkerEventReadMfClassicDone, NfcWorkerEventReadMfClassicLoadKeyCache, NfcWorkerEventReadMfClassicDictAttackRequired, + NfcWorkerEventReadNfcV, // Nfc worker common events NfcWorkerEventSuccess, @@ -69,6 +74,9 @@ typedef enum { // Mifare Ultralight events NfcWorkerEventMfUltralightPassKey, // NFC worker requesting manual key NfcWorkerEventMfUltralightPwdAuth, // Reader sent auth command + NfcWorkerEventNfcVPassKey, // NFC worker requesting manual key + NfcWorkerEventNfcVCommandExecuted, + NfcWorkerEventNfcVContentChanged, } NfcWorkerEvent; typedef bool (*NfcWorkerCallback)(NfcWorkerEvent event, void* context); @@ -87,3 +95,6 @@ void nfc_worker_start( void* context); void nfc_worker_stop(NfcWorker* nfc_worker); +void nfc_worker_nfcv_unlock(NfcWorker* nfc_worker); +void nfc_worker_nfcv_emulate(NfcWorker* nfc_worker); +void nfc_worker_nfcv_sniff(NfcWorker* nfc_worker); \ No newline at end of file diff --git a/lib/nfc/deprecated/nfc_worker_i.h b/lib/nfc/deprecated/nfc_worker_i.h index 38afb67befe7..57cf9a51e7ab 100644 --- a/lib/nfc/deprecated/nfc_worker_i.h +++ b/lib/nfc/deprecated/nfc_worker_i.h @@ -11,6 +11,9 @@ #include #include #include +#include +#include + struct NfcWorker { FuriThread* thread; diff --git a/lib/nfc/deprecated/parsers/nfc_supported_card.c b/lib/nfc/deprecated/parsers/nfc_supported_card.c index fc2dc34e0ee1..153d4d3c511a 100644 --- a/lib/nfc/deprecated/parsers/nfc_supported_card.c +++ b/lib/nfc/deprecated/parsers/nfc_supported_card.c @@ -6,6 +6,7 @@ #include "troika_4k_parser.h" #include "two_cities.h" #include "all_in_one.h" +#include "opal.h" NfcSupportedCard nfc_supported_card[NfcSupportedCardTypeEnd] = { [NfcSupportedCardTypePlantain] = @@ -50,6 +51,14 @@ NfcSupportedCard nfc_supported_card[NfcSupportedCardTypeEnd] = { .read = all_in_one_parser_read, .parse = all_in_one_parser_parse, }, + [NfcSupportedCardTypeOpal] = + { + .protocol = NfcDeviceProtocolMifareDesfire, + .verify = stub_parser_verify_read, + .read = stub_parser_verify_read, + .parse = opal_parser_parse, + }, + }; bool nfc_supported_card_verify_and_parse(NfcDeviceData* dev_data) { @@ -65,3 +74,9 @@ bool nfc_supported_card_verify_and_parse(NfcDeviceData* dev_data) { return card_parsed; } + +bool stub_parser_verify_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) { + UNUSED(nfc_worker); + UNUSED(tx_rx); + return false; +} diff --git a/lib/nfc/deprecated/parsers/nfc_supported_card.h b/lib/nfc/deprecated/parsers/nfc_supported_card.h index 4af59aded635..877bda737452 100644 --- a/lib/nfc/deprecated/parsers/nfc_supported_card.h +++ b/lib/nfc/deprecated/parsers/nfc_supported_card.h @@ -11,6 +11,7 @@ typedef enum { NfcSupportedCardTypeTroika4K, NfcSupportedCardTypeTwoCities, NfcSupportedCardTypeAllInOne, + NfcSupportedCardTypeOpal, NfcSupportedCardTypeEnd, } NfcSupportedCardType; @@ -31,3 +32,8 @@ typedef struct { extern NfcSupportedCard nfc_supported_card[NfcSupportedCardTypeEnd]; bool nfc_supported_card_verify_and_parse(NfcDeviceData* dev_data); + +// stub_parser_verify_read does nothing, and always reports that it does not +// support the card. This is needed for DESFire card parsers which can't +// provide keys, and only use NfcSupportedCard->parse. +bool stub_parser_verify_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx); diff --git a/lib/nfc/deprecated/parsers/opal.c b/lib/nfc/deprecated/parsers/opal.c new file mode 100644 index 000000000000..9cd18c63e5a5 --- /dev/null +++ b/lib/nfc/deprecated/parsers/opal.c @@ -0,0 +1,204 @@ +/* + * opal.c - Parser for Opal card (Sydney, Australia). + * + * Copyright 2023 Michael Farrell + * + * This will only read "standard" MIFARE DESFire-based Opal cards. Free travel + * cards (including School Opal cards, veteran, vision-impaired persons and + * TfNSW employees' cards) and single-trip tickets are MIFARE Ultralight C + * cards and not supported. + * + * Reference: https://github.com/metrodroid/metrodroid/wiki/Opal + * + * Note: The card values are all little-endian (like Flipper), but the above + * reference was originally written based on Java APIs, which are big-endian. + * This implementation presumes a little-endian system. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "nfc_supported_card.h" +#include "opal.h" + +#include +#include +#include + +#include + +static const uint8_t opal_aid[3] = {0x31, 0x45, 0x53}; +static const char* opal_modes[5] = + {"Rail / Metro", "Ferry / Light Rail", "Bus", "Unknown mode", "Manly Ferry"}; +static const char* opal_usages[14] = { + "New / Unused", + "Tap on: new journey", + "Tap on: transfer from same mode", + "Tap on: transfer from other mode", + "", // Manly Ferry: new journey + "", // Manly Ferry: transfer from ferry + "", // Manly Ferry: transfer from other + "Tap off: distance fare", + "Tap off: flat fare", + "Automated tap off: failed to tap off", + "Tap off: end of trip without start", + "Tap off: reversal", + "Tap on: rejected", + "Unknown usage", +}; + +// Opal file 0x7 structure. Assumes a little-endian CPU. +typedef struct __attribute__((__packed__)) { + uint32_t serial : 32; + uint8_t check_digit : 4; + bool blocked : 1; + uint16_t txn_number : 16; + int32_t balance : 21; + uint16_t days : 15; + uint16_t minutes : 11; + uint8_t mode : 3; + uint16_t usage : 4; + bool auto_topup : 1; + uint8_t weekly_journeys : 4; + uint16_t checksum : 16; +} OpalFile; + +static_assert(sizeof(OpalFile) == 16); + +// Converts an Opal timestamp to FuriHalRtcDateTime. +// +// Opal measures days since 1980-01-01 and minutes since midnight, and presumes +// all days are 1440 minutes. +void opal_date_time_to_furi(uint16_t days, uint16_t minutes, FuriHalRtcDateTime* out) { + if(!out) return; + uint16_t diy; + out->year = 1980; + out->month = 1; + // 1980-01-01 is a Tuesday + out->weekday = ((days + 1) % 7) + 1; + out->hour = minutes / 60; + out->minute = minutes % 60; + out->second = 0; + + // What year is it? + for(;;) { + diy = furi_hal_rtc_get_days_per_year(out->year); + if(days < diy) break; + days -= diy; + out->year++; + } + + // 1-index the day of the year + days++; + // What month is it? + bool is_leap = furi_hal_rtc_is_leap_year(out->year); + + for(;;) { + uint8_t dim = furi_hal_rtc_get_days_per_month(is_leap, out->month); + if(days <= dim) break; + days -= dim; + out->month++; + } + + out->day = days; +} + +bool opal_parser_parse(NfcDeviceData* dev_data) { + if(dev_data->protocol != NfcDeviceProtocolMifareDesfire) { + return false; + } + + MifareDesfireApplication* app = mf_df_get_application(&dev_data->mf_df_data, &opal_aid); + if(app == NULL) { + return false; + } + MifareDesfireFile* f = mf_df_get_file(app, 0x07); + if(f == NULL || f->type != MifareDesfireFileTypeStandard || f->settings.data.size != 16 || + !f->contents) { + return false; + } + + OpalFile* o = (OpalFile*)f->contents; + + uint8_t serial2 = o->serial / 10000000; + uint16_t serial3 = (o->serial / 1000) % 10000; + uint16_t serial4 = (o->serial % 1000); + + if(o->check_digit > 9) { + return false; + } + + char* sign = ""; + if(o->balance < 0) { + // Negative balance. Make this a positive value again and record the + // sign separately, because then we can handle balances of -99..-1 + // cents, as the "dollars" division below would result in a positive + // zero value. + o->balance = abs(o->balance); //-V1081 + sign = "-"; + } + uint8_t cents = o->balance % 100; + int32_t dollars = o->balance / 100; + + FuriHalRtcDateTime timestamp; + opal_date_time_to_furi(o->days, o->minutes, ×tamp); + + if(o->mode >= 3) { + // 3..7 are "reserved", but we use 4 to indicate the Manly Ferry. + o->mode = 3; + } + + if(o->usage >= 4 && o->usage <= 6) { + // Usages 4..6 associated with the Manly Ferry, which correspond to + // usages 1..3 for other modes. + o->usage -= 3; + o->mode = 4; + } + + const char* mode_str = (o->mode <= 4 ? opal_modes[o->mode] : opal_modes[3]); //-V547 + const char* usage_str = (o->usage <= 12 ? opal_usages[o->usage] : opal_usages[13]); + + furi_string_printf( + dev_data->parsed_data, + "\e#Opal: $%s%ld.%02hu\n3085 22%02hhu %04hu %03hu%01hhu\n%s, %s\n", + sign, + dollars, + cents, + serial2, + serial3, + serial4, + o->check_digit, + mode_str, + usage_str); + FuriString* timestamp_str = furi_string_alloc(); + locale_format_date(timestamp_str, ×tamp, locale_get_date_format(), "-"); + furi_string_cat(dev_data->parsed_data, timestamp_str); + furi_string_cat_str(dev_data->parsed_data, " at "); + + locale_format_time(timestamp_str, ×tamp, locale_get_time_format(), false); + furi_string_cat(dev_data->parsed_data, timestamp_str); + + furi_string_free(timestamp_str); + furi_string_cat_printf( + dev_data->parsed_data, + "\nWeekly journeys: %hhu, Txn #%hu\n", + o->weekly_journeys, + o->txn_number); + + if(o->auto_topup) { + furi_string_cat_str(dev_data->parsed_data, "Auto-topup enabled\n"); + } + if(o->blocked) { + furi_string_cat_str(dev_data->parsed_data, "Card blocked\n"); + } + return true; +} diff --git a/lib/nfc/deprecated/parsers/opal.h b/lib/nfc/deprecated/parsers/opal.h new file mode 100644 index 000000000000..42caf9a1790a --- /dev/null +++ b/lib/nfc/deprecated/parsers/opal.h @@ -0,0 +1,5 @@ +#pragma once + +#include "nfc_supported_card.h" + +bool opal_parser_parse(NfcDeviceData* dev_data); diff --git a/lib/nfc/deprecated/protocols/mifare_classic.c b/lib/nfc/deprecated/protocols/mifare_classic.c index d088be5b6126..b728f2c4f550 100644 --- a/lib/nfc/deprecated/protocols/mifare_classic.c +++ b/lib/nfc/deprecated/protocols/mifare_classic.c @@ -854,7 +854,10 @@ uint8_t mifare_classic_update_card(FuriHalNfcTxRxContext* tx_rx, MfClassicData* return sectors_read; } -bool mifare_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_rx) { +bool mifare_classic_emulator( + MfClassicEmulator* emulator, + FuriHalNfcTxRxContext* tx_rx, + bool is_reader_analyzer) { furi_assert(emulator); furi_assert(tx_rx); bool command_processed = false; @@ -901,11 +904,27 @@ bool mifare_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* MfClassicSectorTrailer* sector_trailer = (MfClassicSectorTrailer*)emulator->data.block[sector_trailer_block].value; if(cmd == MF_CLASSIC_AUTH_KEY_A_CMD) { - key = nfc_util_bytes2num(sector_trailer->key_a, 6); - access_key = MfClassicKeyA; + if(mifare_classic_is_key_found( + &emulator->data, mifare_classic_get_sector_by_block(block), MfClassicKeyA) || + is_reader_analyzer) { + key = nfc_util_bytes2num(sector_trailer->key_a, 6); + access_key = MfClassicKeyA; + } else { + FURI_LOG_D(TAG, "Key not known"); + command_processed = true; + break; + } } else { - key = nfc_util_bytes2num(sector_trailer->key_b, 6); - access_key = MfClassicKeyB; + if(mifare_classic_is_key_found( + &emulator->data, mifare_classic_get_sector_by_block(block), MfClassicKeyB) || + is_reader_analyzer) { + key = nfc_util_bytes2num(sector_trailer->key_b, 6); + access_key = MfClassicKeyB; + } else { + FURI_LOG_D(TAG, "Key not known"); + command_processed = true; + break; + } } uint32_t nonce = old_prng_successor(DWT->CYCCNT, 32) ^ 0xAA; diff --git a/lib/nfc/deprecated/protocols/mifare_classic.h b/lib/nfc/deprecated/protocols/mifare_classic.h index e6530e2dc849..c02dc1c05603 100644 --- a/lib/nfc/deprecated/protocols/mifare_classic.h +++ b/lib/nfc/deprecated/protocols/mifare_classic.h @@ -205,7 +205,10 @@ uint8_t mifare_classic_read_card( uint8_t mifare_classic_update_card(FuriHalNfcTxRxContext* tx_rx, MfClassicData* data); -bool mifare_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_rx); +bool mifare_classic_emulator( + MfClassicEmulator* emulator, + FuriHalNfcTxRxContext* tx_rx, + bool is_reader_analyzer); void mifare_classic_halt(FuriHalNfcTxRxContext* tx_rx, Crypto1* crypto); diff --git a/lib/nfc/deprecated/protocols/mifare_desfire.c b/lib/nfc/deprecated/protocols/mifare_desfire.c index 23308ae95e34..e0ead737f87d 100644 --- a/lib/nfc/deprecated/protocols/mifare_desfire.c +++ b/lib/nfc/deprecated/protocols/mifare_desfire.c @@ -42,6 +42,30 @@ void mf_df_clear(MifareDesfireData* data) { data->app_head = NULL; } +MifareDesfireApplication* mf_df_get_application(MifareDesfireData* data, const uint8_t (*aid)[3]) { + if(!data) { + return NULL; + } + for(MifareDesfireApplication* app = data->app_head; app; app = app->next) { + if(memcmp(aid, app->id, 3) == 0) { + return app; + } + } + return NULL; +} + +MifareDesfireFile* mf_df_get_file(MifareDesfireApplication* app, uint8_t id) { + if(!app) { + return NULL; + } + for(MifareDesfireFile* file = app->file_head; file; file = file->next) { + if(file->id == id) { + return file; + } + } + return NULL; +} + void mf_df_cat_data(MifareDesfireData* data, FuriString* out) { mf_df_cat_card_info(data, out); for(MifareDesfireApplication* app = data->app_head; app; app = app->next) { diff --git a/lib/nfc/deprecated/protocols/mifare_desfire.h b/lib/nfc/deprecated/protocols/mifare_desfire.h index 963a18f585b8..3dc7c4c2a7c4 100644 --- a/lib/nfc/deprecated/protocols/mifare_desfire.h +++ b/lib/nfc/deprecated/protocols/mifare_desfire.h @@ -130,6 +130,9 @@ void mf_df_cat_file(MifareDesfireFile* file, FuriString* out); bool mf_df_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK); +MifareDesfireApplication* mf_df_get_application(MifareDesfireData* data, const uint8_t (*aid)[3]); +MifareDesfireFile* mf_df_get_file(MifareDesfireApplication* app, uint8_t id); + uint16_t mf_df_prepare_get_version(uint8_t* dest); bool mf_df_parse_get_version_response(uint8_t* buf, uint16_t len, MifareDesfireVersion* out); diff --git a/lib/nfc/deprecated/protocols/mifare_ultralight.c b/lib/nfc/deprecated/protocols/mifare_ultralight.c index ace08fb1db5f..56fbeee4991c 100644 --- a/lib/nfc/deprecated/protocols/mifare_ultralight.c +++ b/lib/nfc/deprecated/protocols/mifare_ultralight.c @@ -79,6 +79,8 @@ static MfUltralightFeatures mf_ul_get_features(MfUltralightType type) { MfUltralightSupportSectorSelect; case MfUltralightTypeNTAG203: return MfUltralightSupportCompatWrite | MfUltralightSupportCounterInMemory; + case MfUltralightTypeULC: + return MfUltralightSupportCompatWrite | MfUltralightSupport3DesAuth; default: // Assumed original MFUL 512-bit return MfUltralightSupportCompatWrite; @@ -95,6 +97,11 @@ static void mf_ul_set_version_ntag203(MfUltralightReader* reader, MfUltralightDa reader->pages_to_read = 42; } +static void mf_ul_set_version_ulc(MfUltralightReader* reader, MfUltralightData* data) { + data->type = MfUltralightTypeULC; + reader->pages_to_read = 48; +} + bool mf_ultralight_read_version( FuriHalNfcTxRxContext* tx_rx, MfUltralightReader* reader, @@ -175,7 +182,7 @@ bool mf_ultralight_authenticate(FuriHalNfcTxRxContext* tx_rx, uint32_t key, uint do { FURI_LOG_D(TAG, "Authenticating"); - tx_rx->tx_data[0] = MF_UL_AUTH; + tx_rx->tx_data[0] = MF_UL_PWD_AUTH; nfc_util_num2bytes(key, 4, &tx_rx->tx_data[1]); tx_rx->tx_bits = 40; tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault; @@ -702,7 +709,7 @@ bool mf_ultralight_read_tearing_flags(FuriHalNfcTxRxContext* tx_rx, MfUltralight FURI_LOG_D(TAG, "Reading tearing flags"); for(size_t i = 0; i < 3; i++) { tx_rx->tx_data[0] = MF_UL_CHECK_TEARING; - tx_rx->rx_data[1] = i; + tx_rx->tx_data[1] = i; tx_rx->tx_bits = 16; tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault; if(!furi_hal_nfc_tx_rx(tx_rx, 50)) { @@ -716,6 +723,21 @@ bool mf_ultralight_read_tearing_flags(FuriHalNfcTxRxContext* tx_rx, MfUltralight return flag_read == 2; } +static bool mf_ul_probe_3des_auth(FuriHalNfcTxRxContext* tx_rx) { + tx_rx->tx_data[0] = MF_UL_AUTHENTICATE_1; + tx_rx->tx_data[1] = 0; + tx_rx->tx_bits = 16; + tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault; + bool rc = furi_hal_nfc_tx_rx(tx_rx, 50) && tx_rx->rx_bits == 9 * 8 && + tx_rx->rx_data[0] == 0xAF; + + // Reset just in case, we're not going to finish authenticating and need to if tag doesn't support auth + furi_hal_nfc_sleep(); + furi_hal_nfc_activate_nfca(300, NULL); + + return rc; +} + bool mf_ul_read_card( FuriHalNfcTxRxContext* tx_rx, MfUltralightReader* reader, @@ -733,16 +755,20 @@ bool mf_ul_read_card( mf_ultralight_read_signature(tx_rx, data); } } else { - // No GET_VERSION command, check for NTAG203 by reading last page (41) uint8_t dummy[16]; - if(mf_ultralight_read_pages_direct(tx_rx, 41, dummy)) { + // No GET_VERSION command, check if AUTHENTICATE command available (detect UL C). + if(mf_ul_probe_3des_auth(tx_rx)) { + mf_ul_set_version_ulc(reader, data); + } else if(mf_ultralight_read_pages_direct(tx_rx, 41, dummy)) { + // No AUTHENTICATE, check for NTAG203 by reading last page (41) mf_ul_set_version_ntag203(reader, data); - reader->supported_features = mf_ul_get_features(data->type); } else { // We're really an original Mifare Ultralight, reset tag for safety furi_hal_nfc_sleep(); furi_hal_nfc_activate_nfca(300, NULL); } + + reader->supported_features = mf_ul_get_features(data->type); } card_read = mf_ultralight_read_pages(tx_rx, reader, data); @@ -1228,6 +1254,10 @@ static void mf_ul_emulate_write( emulator->data_changed = true; } +bool mf_ul_emulation_supported(MfUltralightData* data) { + return data->type != MfUltralightTypeULC; +} + void mf_ul_reset_emulation(MfUltralightEmulator* emulator, bool is_power_cycle) { emulator->comp_write_cmd_started = false; emulator->sector_select_cmd_started = false; @@ -1732,7 +1762,7 @@ bool mf_ul_prepare_emulation_response( } } } - } else if(cmd == MF_UL_AUTH) { + } else if(cmd == MF_UL_PWD_AUTH) { if(emulator->supported_features & MfUltralightSupportAuth) { if(buff_rx_len == (1 + 4) * 8) { // Record password sent by PCD diff --git a/lib/nfc/deprecated/protocols/mifare_ultralight.h b/lib/nfc/deprecated/protocols/mifare_ultralight.h index 4ab22e89cb8e..d444fa7983e6 100644 --- a/lib/nfc/deprecated/protocols/mifare_ultralight.h +++ b/lib/nfc/deprecated/protocols/mifare_ultralight.h @@ -16,7 +16,8 @@ #define MF_UL_COMP_WRITE (0xA0) #define MF_UL_READ_CNT (0x39) #define MF_UL_INC_CNT (0xA5) -#define MF_UL_AUTH (0x1B) +#define MF_UL_AUTHENTICATE_1 (0x1A) +#define MF_UL_PWD_AUTH (0x1B) #define MF_UL_READ_SIG (0x3C) #define MF_UL_CHECK_TEARING (0x3E) #define MF_UL_READ_VCSL (0x4B) @@ -41,6 +42,7 @@ typedef enum { typedef enum { MfUltralightTypeUnknown, MfUltralightTypeNTAG203, + MfUltralightTypeULC, // Below have config pages and GET_VERSION support MfUltralightTypeUL11, MfUltralightTypeUL21, @@ -77,6 +79,7 @@ typedef enum { MfUltralightSupportAsciiMirror = 1 << 11, // NTAG203 counter that's in memory rather than through a command MfUltralightSupportCounterInMemory = 1 << 12, + MfUltralightSupport3DesAuth = 1 << 13, } MfUltralightFeatures; typedef enum { @@ -237,6 +240,8 @@ bool mf_ul_read_card( MfUltralightReader* reader, MfUltralightData* data); +bool mf_ul_emulation_supported(MfUltralightData* data); + void mf_ul_reset_emulation(MfUltralightEmulator* emulator, bool is_power_cycle); void mf_ul_prepare_emulation(MfUltralightEmulator* emulator, MfUltralightData* data); diff --git a/lib/nfc/deprecated/protocols/nfcv.c b/lib/nfc/deprecated/protocols/nfcv.c new file mode 100644 index 000000000000..1ec82afd59fe --- /dev/null +++ b/lib/nfc/deprecated/protocols/nfcv.c @@ -0,0 +1,1395 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "nfcv.h" +#include "slix.h" + +#define TAG "NfcV" + +/* macros to map "modulate field" flag to GPIO level */ +#define GPIO_LEVEL_MODULATED NFCV_LOAD_MODULATION_POLARITY +#define GPIO_LEVEL_UNMODULATED (!GPIO_LEVEL_MODULATED) + +/* timing macros */ +#define DIGITAL_SIGNAL_UNIT_S (100000000000.0f) +#define DIGITAL_SIGNAL_UNIT_US (100000.0f) + +ReturnCode nfcv_inventory(uint8_t* uid) { + uint16_t received = 0; + rfalNfcvInventoryRes res; + ReturnCode ret = ERR_NONE; + + for(int tries = 0; tries < NFCV_COMMAND_RETRIES; tries++) { + /* TODO: needs proper abstraction via fury_hal(_ll)_* */ + ret = rfalNfcvPollerInventory(RFAL_NFCV_NUM_SLOTS_1, 0, NULL, &res, &received); + + if(ret == ERR_NONE) { + break; + } + } + + if(ret == ERR_NONE) { + if(uid != NULL) { + memcpy(uid, res.UID, NFCV_UID_LENGTH); + } + } + + return ret; +} + +ReturnCode nfcv_read_blocks(NfcVReader* reader, NfcVData* nfcv_data) { + UNUSED(reader); + + uint16_t received = 0; + for(size_t block = 0; block < nfcv_data->block_num; block++) { + uint8_t rxBuf[32]; + FURI_LOG_D(TAG, "Reading block %d/%d", block, (nfcv_data->block_num - 1)); + + ReturnCode ret = ERR_NONE; + for(int tries = 0; tries < NFCV_COMMAND_RETRIES; tries++) { + ret = rfalNfcvPollerReadSingleBlock( + RFAL_NFCV_REQ_FLAG_DEFAULT, NULL, block, rxBuf, sizeof(rxBuf), &received); + + if(ret == ERR_NONE) { + break; + } + } + if(ret != ERR_NONE) { + FURI_LOG_D(TAG, "failed to read: %d", ret); + return ret; + } + memcpy( + &(nfcv_data->data[block * nfcv_data->block_size]), &rxBuf[1], nfcv_data->block_size); + FURI_LOG_D( + TAG, + " %02X %02X %02X %02X", + nfcv_data->data[block * nfcv_data->block_size + 0], + nfcv_data->data[block * nfcv_data->block_size + 1], + nfcv_data->data[block * nfcv_data->block_size + 2], + nfcv_data->data[block * nfcv_data->block_size + 3]); + } + + return ERR_NONE; +} + +ReturnCode nfcv_read_sysinfo(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data) { + uint8_t rxBuf[32]; + uint16_t received = 0; + ReturnCode ret = ERR_NONE; + + FURI_LOG_D(TAG, "Read SYSTEM INFORMATION..."); + + for(int tries = 0; tries < NFCV_COMMAND_RETRIES; tries++) { + /* TODO: needs proper abstraction via fury_hal(_ll)_* */ + ret = rfalNfcvPollerGetSystemInformation( + RFAL_NFCV_REQ_FLAG_DEFAULT, NULL, rxBuf, sizeof(rxBuf), &received); + + if(ret == ERR_NONE) { + break; + } + } + + if(ret == ERR_NONE) { + nfc_data->type = FuriHalNfcTypeV; + nfc_data->uid_len = NFCV_UID_LENGTH; + /* UID is stored reversed in this response */ + for(int pos = 0; pos < nfc_data->uid_len; pos++) { + nfc_data->uid[pos] = rxBuf[2 + (NFCV_UID_LENGTH - 1 - pos)]; + } + nfcv_data->dsfid = rxBuf[NFCV_UID_LENGTH + 2]; + nfcv_data->afi = rxBuf[NFCV_UID_LENGTH + 3]; + nfcv_data->block_num = rxBuf[NFCV_UID_LENGTH + 4] + 1; + nfcv_data->block_size = rxBuf[NFCV_UID_LENGTH + 5] + 1; + nfcv_data->ic_ref = rxBuf[NFCV_UID_LENGTH + 6]; + FURI_LOG_D( + TAG, + " UID: %02X %02X %02X %02X %02X %02X %02X %02X", + nfc_data->uid[0], + nfc_data->uid[1], + nfc_data->uid[2], + nfc_data->uid[3], + nfc_data->uid[4], + nfc_data->uid[5], + nfc_data->uid[6], + nfc_data->uid[7]); + FURI_LOG_D( + TAG, + " DSFID %d, AFI %d, Blocks %d, Size %d, IC Ref %d", + nfcv_data->dsfid, + nfcv_data->afi, + nfcv_data->block_num, + nfcv_data->block_size, + nfcv_data->ic_ref); + return ret; + } + FURI_LOG_D(TAG, "Failed: %d", ret); + + return ret; +} + +bool nfcv_read_card(NfcVReader* reader, FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data) { + furi_assert(reader); + furi_assert(nfc_data); + furi_assert(nfcv_data); + + if(nfcv_read_sysinfo(nfc_data, nfcv_data) != ERR_NONE) { + return false; + } + + if(nfcv_read_blocks(reader, nfcv_data) != ERR_NONE) { + return false; + } + + if(slix_check_card_type(nfc_data)) { + FURI_LOG_I(TAG, "NXP SLIX detected"); + nfcv_data->sub_type = NfcVTypeSlix; + } else if(slix2_check_card_type(nfc_data)) { + FURI_LOG_I(TAG, "NXP SLIX2 detected"); + nfcv_data->sub_type = NfcVTypeSlix2; + } else if(slix_s_check_card_type(nfc_data)) { + FURI_LOG_I(TAG, "NXP SLIX-S detected"); + nfcv_data->sub_type = NfcVTypeSlixS; + } else if(slix_l_check_card_type(nfc_data)) { + FURI_LOG_I(TAG, "NXP SLIX-L detected"); + nfcv_data->sub_type = NfcVTypeSlixL; + } else { + nfcv_data->sub_type = NfcVTypePlain; + } + + return true; +} + +void nfcv_crc(uint8_t* data, uint32_t length) { + uint32_t reg = 0xFFFF; + + for(size_t i = 0; i < length; i++) { + reg = reg ^ ((uint32_t)data[i]); + for(size_t j = 0; j < 8; j++) { + if(reg & 0x0001) { + reg = (reg >> 1) ^ 0x8408; + } else { + reg = (reg >> 1); + } + } + } + + uint16_t crc = ~(uint16_t)(reg & 0xffff); + + data[length + 0] = crc & 0xFF; + data[length + 1] = crc >> 8; +} + +void nfcv_emu_free_signals(NfcVEmuAirSignals* signals) { + furi_assert(signals); + + if(signals->nfcv_resp_one) { + digital_signal_free(signals->nfcv_resp_one); + } + if(signals->nfcv_resp_zero) { + digital_signal_free(signals->nfcv_resp_zero); + } + if(signals->nfcv_resp_sof) { + digital_signal_free(signals->nfcv_resp_sof); + } + if(signals->nfcv_resp_eof) { + digital_signal_free(signals->nfcv_resp_eof); + } + signals->nfcv_resp_one = NULL; + signals->nfcv_resp_zero = NULL; + signals->nfcv_resp_sof = NULL; + signals->nfcv_resp_eof = NULL; +} + +bool nfcv_emu_alloc_signals(NfcVEmuAir* air, NfcVEmuAirSignals* signals, uint32_t slowdown) { + furi_assert(air); + furi_assert(signals); + + bool success = true; + + if(!signals->nfcv_resp_one) { + /* logical one: unmodulated then 8 pulses */ + signals->nfcv_resp_one = digital_signal_alloc( + slowdown * (air->nfcv_resp_unmod->edge_cnt + 8 * air->nfcv_resp_pulse->edge_cnt)); + if(!signals->nfcv_resp_one) { + return false; + } + for(size_t i = 0; i < slowdown; i++) { + success &= digital_signal_append(signals->nfcv_resp_one, air->nfcv_resp_unmod); + } + for(size_t i = 0; i < slowdown * 8; i++) { + success &= digital_signal_append(signals->nfcv_resp_one, air->nfcv_resp_pulse); + } + if(!success) { + return false; + } + } + if(!signals->nfcv_resp_zero) { + /* logical zero: 8 pulses then unmodulated */ + signals->nfcv_resp_zero = digital_signal_alloc( + slowdown * (8 * air->nfcv_resp_pulse->edge_cnt + air->nfcv_resp_unmod->edge_cnt)); + if(!signals->nfcv_resp_zero) { + return false; + } + for(size_t i = 0; i < slowdown * 8; i++) { + success &= digital_signal_append(signals->nfcv_resp_zero, air->nfcv_resp_pulse); + } + for(size_t i = 0; i < slowdown; i++) { + success &= digital_signal_append(signals->nfcv_resp_zero, air->nfcv_resp_unmod); + } + if(!success) { + return false; + } + } + if(!signals->nfcv_resp_sof) { + /* SOF: unmodulated, 24 pulses, logic 1 */ + signals->nfcv_resp_sof = digital_signal_alloc( + slowdown * (3 * air->nfcv_resp_unmod->edge_cnt + 24 * air->nfcv_resp_pulse->edge_cnt) + + signals->nfcv_resp_one->edge_cnt); + if(!signals->nfcv_resp_sof) { + return false; + } + for(size_t i = 0; i < slowdown * 3; i++) { + success &= digital_signal_append(signals->nfcv_resp_sof, air->nfcv_resp_unmod); + } + for(size_t i = 0; i < slowdown * 24; i++) { + success &= digital_signal_append(signals->nfcv_resp_sof, air->nfcv_resp_pulse); + } + success &= digital_signal_append(signals->nfcv_resp_sof, signals->nfcv_resp_one); + if(!success) { + return false; + } + } + if(!signals->nfcv_resp_eof) { + /* EOF: logic 0, 24 pulses, unmodulated */ + signals->nfcv_resp_eof = digital_signal_alloc( + signals->nfcv_resp_zero->edge_cnt + + slowdown * (24 * air->nfcv_resp_pulse->edge_cnt + 3 * air->nfcv_resp_unmod->edge_cnt) + + air->nfcv_resp_unmod->edge_cnt); + if(!signals->nfcv_resp_eof) { + return false; + } + success &= digital_signal_append(signals->nfcv_resp_eof, signals->nfcv_resp_zero); + for(size_t i = 0; i < slowdown * 23; i++) { + success &= digital_signal_append(signals->nfcv_resp_eof, air->nfcv_resp_pulse); + } + /* we don't want to add the last level as we just want a transition to "unmodulated" again */ + for(size_t i = 0; i < slowdown; i++) { + success &= digital_signal_append(signals->nfcv_resp_eof, air->nfcv_resp_half_pulse); + } + } + return success; +} + +bool nfcv_emu_alloc(NfcVData* nfcv_data) { + furi_assert(nfcv_data); + + if(!nfcv_data->frame) { + nfcv_data->frame = malloc(NFCV_FRAMESIZE_MAX); + if(!nfcv_data->frame) { + return false; + } + } + + if(!nfcv_data->emu_air.nfcv_signal) { + /* assuming max frame length is 255 bytes */ + nfcv_data->emu_air.nfcv_signal = digital_sequence_alloc(8 * 255 + 2, &gpio_spi_r_mosi); + if(!nfcv_data->emu_air.nfcv_signal) { + return false; + } + } + if(!nfcv_data->emu_air.nfcv_resp_unmod) { + /* unmodulated 256/fc or 1024/fc signal as building block */ + nfcv_data->emu_air.nfcv_resp_unmod = digital_signal_alloc(4); + if(!nfcv_data->emu_air.nfcv_resp_unmod) { + return false; + } + nfcv_data->emu_air.nfcv_resp_unmod->start_level = GPIO_LEVEL_UNMODULATED; + nfcv_data->emu_air.nfcv_resp_unmod->edge_timings[0] = + (uint32_t)(NFCV_RESP_SUBC1_UNMOD_256 * DIGITAL_SIGNAL_UNIT_S); + nfcv_data->emu_air.nfcv_resp_unmod->edge_cnt = 1; + } + if(!nfcv_data->emu_air.nfcv_resp_pulse) { + /* modulated fc/32 or fc/8 pulse as building block */ + nfcv_data->emu_air.nfcv_resp_pulse = digital_signal_alloc(4); + if(!nfcv_data->emu_air.nfcv_resp_pulse) { + return false; + } + nfcv_data->emu_air.nfcv_resp_pulse->start_level = GPIO_LEVEL_MODULATED; + nfcv_data->emu_air.nfcv_resp_pulse->edge_timings[0] = + (uint32_t)(NFCV_RESP_SUBC1_PULSE_32 * DIGITAL_SIGNAL_UNIT_S); + nfcv_data->emu_air.nfcv_resp_pulse->edge_timings[1] = + (uint32_t)(NFCV_RESP_SUBC1_PULSE_32 * DIGITAL_SIGNAL_UNIT_S); + nfcv_data->emu_air.nfcv_resp_pulse->edge_cnt = 2; + } + + if(!nfcv_data->emu_air.nfcv_resp_half_pulse) { + /* modulated fc/32 or fc/8 pulse as building block */ + nfcv_data->emu_air.nfcv_resp_half_pulse = digital_signal_alloc(4); + if(!nfcv_data->emu_air.nfcv_resp_half_pulse) { + return false; + } + nfcv_data->emu_air.nfcv_resp_half_pulse->start_level = GPIO_LEVEL_MODULATED; + nfcv_data->emu_air.nfcv_resp_half_pulse->edge_timings[0] = + (uint32_t)(NFCV_RESP_SUBC1_PULSE_32 * DIGITAL_SIGNAL_UNIT_S); + nfcv_data->emu_air.nfcv_resp_half_pulse->edge_cnt = 1; + } + + bool success = true; + success &= nfcv_emu_alloc_signals(&nfcv_data->emu_air, &nfcv_data->emu_air.signals_high, 1); + success &= nfcv_emu_alloc_signals(&nfcv_data->emu_air, &nfcv_data->emu_air.signals_low, 4); + + if(!success) { + FURI_LOG_E(TAG, "Failed to allocate signals"); + return false; + } + + digital_sequence_set_signal( + nfcv_data->emu_air.nfcv_signal, + NFCV_SIG_SOF, + nfcv_data->emu_air.signals_high.nfcv_resp_sof); + digital_sequence_set_signal( + nfcv_data->emu_air.nfcv_signal, + NFCV_SIG_BIT0, + nfcv_data->emu_air.signals_high.nfcv_resp_zero); + digital_sequence_set_signal( + nfcv_data->emu_air.nfcv_signal, + NFCV_SIG_BIT1, + nfcv_data->emu_air.signals_high.nfcv_resp_one); + digital_sequence_set_signal( + nfcv_data->emu_air.nfcv_signal, + NFCV_SIG_EOF, + nfcv_data->emu_air.signals_high.nfcv_resp_eof); + digital_sequence_set_signal( + nfcv_data->emu_air.nfcv_signal, + NFCV_SIG_LOW_SOF, + nfcv_data->emu_air.signals_low.nfcv_resp_sof); + digital_sequence_set_signal( + nfcv_data->emu_air.nfcv_signal, + NFCV_SIG_LOW_BIT0, + nfcv_data->emu_air.signals_low.nfcv_resp_zero); + digital_sequence_set_signal( + nfcv_data->emu_air.nfcv_signal, + NFCV_SIG_LOW_BIT1, + nfcv_data->emu_air.signals_low.nfcv_resp_one); + digital_sequence_set_signal( + nfcv_data->emu_air.nfcv_signal, + NFCV_SIG_LOW_EOF, + nfcv_data->emu_air.signals_low.nfcv_resp_eof); + + return true; +} + +void nfcv_emu_free(NfcVData* nfcv_data) { + furi_assert(nfcv_data); + + if(nfcv_data->frame) { + free(nfcv_data->frame); + } + if(nfcv_data->emu_protocol_ctx) { + free(nfcv_data->emu_protocol_ctx); + } + if(nfcv_data->emu_air.nfcv_resp_unmod) { + digital_signal_free(nfcv_data->emu_air.nfcv_resp_unmod); + } + if(nfcv_data->emu_air.nfcv_resp_pulse) { + digital_signal_free(nfcv_data->emu_air.nfcv_resp_pulse); + } + if(nfcv_data->emu_air.nfcv_resp_half_pulse) { + digital_signal_free(nfcv_data->emu_air.nfcv_resp_half_pulse); + } + if(nfcv_data->emu_air.nfcv_signal) { + digital_sequence_free(nfcv_data->emu_air.nfcv_signal); + } + if(nfcv_data->emu_air.reader_signal) { + // Stop pulse reader and disable bus before free + pulse_reader_stop(nfcv_data->emu_air.reader_signal); + // Free pulse reader + pulse_reader_free(nfcv_data->emu_air.reader_signal); + } + + nfcv_data->frame = NULL; + nfcv_data->emu_air.nfcv_resp_unmod = NULL; + nfcv_data->emu_air.nfcv_resp_pulse = NULL; + nfcv_data->emu_air.nfcv_resp_half_pulse = NULL; + nfcv_data->emu_air.nfcv_signal = NULL; + nfcv_data->emu_air.reader_signal = NULL; + + nfcv_emu_free_signals(&nfcv_data->emu_air.signals_high); + nfcv_emu_free_signals(&nfcv_data->emu_air.signals_low); +} + +void nfcv_emu_send( + FuriHalNfcTxRxContext* tx_rx, + NfcVData* nfcv, + uint8_t* data, + uint8_t length, + NfcVSendFlags flags, + uint32_t send_time) { + furi_assert(tx_rx); + furi_assert(nfcv); + + /* picked default value (0) to match the most common format */ + if(flags == NfcVSendFlagsNormal) { + flags = NfcVSendFlagsSof | NfcVSendFlagsCrc | NfcVSendFlagsEof | + NfcVSendFlagsOneSubcarrier | NfcVSendFlagsHighRate; + } + + if(flags & NfcVSendFlagsCrc) { + nfcv_crc(data, length); + length += 2; + } + + /* depending on the request flags, send with high or low rate */ + uint32_t bit0 = (flags & NfcVSendFlagsHighRate) ? NFCV_SIG_BIT0 : NFCV_SIG_LOW_BIT0; + uint32_t bit1 = (flags & NfcVSendFlagsHighRate) ? NFCV_SIG_BIT1 : NFCV_SIG_LOW_BIT1; + uint32_t sof = (flags & NfcVSendFlagsHighRate) ? NFCV_SIG_SOF : NFCV_SIG_LOW_SOF; + uint32_t eof = (flags & NfcVSendFlagsHighRate) ? NFCV_SIG_EOF : NFCV_SIG_LOW_EOF; + + digital_sequence_clear(nfcv->emu_air.nfcv_signal); + + if(flags & NfcVSendFlagsSof) { + digital_sequence_add(nfcv->emu_air.nfcv_signal, sof); + } + + for(int bit_total = 0; bit_total < length * 8; bit_total++) { + uint32_t byte_pos = bit_total / 8; + uint32_t bit_pos = bit_total % 8; + uint8_t bit_val = 0x01 << bit_pos; + + digital_sequence_add(nfcv->emu_air.nfcv_signal, (data[byte_pos] & bit_val) ? bit1 : bit0); + } + + if(flags & NfcVSendFlagsEof) { + digital_sequence_add(nfcv->emu_air.nfcv_signal, eof); + } + + furi_hal_gpio_write(&gpio_spi_r_mosi, GPIO_LEVEL_UNMODULATED); + digital_sequence_set_sendtime(nfcv->emu_air.nfcv_signal, send_time); + digital_sequence_send(nfcv->emu_air.nfcv_signal); + furi_hal_gpio_write(&gpio_spi_r_mosi, GPIO_LEVEL_UNMODULATED); + + if(tx_rx->sniff_tx) { + tx_rx->sniff_tx(data, length * 8, false, tx_rx->sniff_context); + } +} + +static void nfcv_revuidcpy(uint8_t* dst, uint8_t* src) { + for(int pos = 0; pos < NFCV_UID_LENGTH; pos++) { + dst[pos] = src[NFCV_UID_LENGTH - 1 - pos]; + } +} + +static int nfcv_revuidcmp(uint8_t* dst, uint8_t* src) { + for(int pos = 0; pos < NFCV_UID_LENGTH; pos++) { + if(dst[pos] != src[NFCV_UID_LENGTH - 1 - pos]) { + return 1; + } + } + return 0; +} + +void nfcv_emu_handle_packet( + FuriHalNfcTxRxContext* tx_rx, + FuriHalNfcDevData* nfc_data, + void* nfcv_data_in) { + furi_assert(tx_rx); + furi_assert(nfc_data); + furi_assert(nfcv_data_in); + + NfcVData* nfcv_data = (NfcVData*)nfcv_data_in; + NfcVEmuProtocolCtx* ctx = nfcv_data->emu_protocol_ctx; + + if(nfcv_data->frame_length < 2) { + return; + } + + if(nfcv_data->echo_mode) { + nfcv_emu_send( + tx_rx, + nfcv_data, + nfcv_data->frame, + nfcv_data->frame_length, + NfcVSendFlagsSof | NfcVSendFlagsHighRate | NfcVSendFlagsEof, + ctx->send_time); + snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "ECHO data"); + return; + } + + /* parse the frame data for the upcoming part 3 handling */ + ctx->flags = nfcv_data->frame[0]; + ctx->command = nfcv_data->frame[1]; + ctx->selected = !(ctx->flags & NFCV_REQ_FLAG_INVENTORY) && (ctx->flags & NFCV_REQ_FLAG_SELECT); + ctx->addressed = !(ctx->flags & NFCV_REQ_FLAG_INVENTORY) && + (ctx->flags & NFCV_REQ_FLAG_ADDRESS); + ctx->advanced = (ctx->command >= NFCV_CMD_ADVANCED); + ctx->address_offset = 2 + (ctx->advanced ? 1 : 0); + ctx->payload_offset = ctx->address_offset + (ctx->addressed ? NFCV_UID_LENGTH : 0); + ctx->response_flags = NfcVSendFlagsSof | NfcVSendFlagsCrc | NfcVSendFlagsEof; + ctx->send_time = nfcv_data->eof_timestamp + NFCV_FDT_FC(4380); + + if(ctx->flags & NFCV_REQ_FLAG_DATA_RATE) { + ctx->response_flags |= NfcVSendFlagsHighRate; + } + if(ctx->flags & NFCV_REQ_FLAG_SUB_CARRIER) { + ctx->response_flags |= NfcVSendFlagsTwoSubcarrier; + } + + if(ctx->payload_offset + 2 > nfcv_data->frame_length) { +#ifdef NFCV_VERBOSE + FURI_LOG_D(TAG, "command 0x%02X, but packet is too short", ctx->command); +#endif + return; + } + + /* standard behavior is implemented */ + if(ctx->addressed) { + uint8_t* address = &nfcv_data->frame[ctx->address_offset]; + if(nfcv_revuidcmp(address, nfc_data->uid)) { +#ifdef NFCV_VERBOSE + FURI_LOG_D(TAG, "addressed command 0x%02X, but not for us:", ctx->command); + FURI_LOG_D( + TAG, + " dest: %02X%02X%02X%02X%02X%02X%02X%02X", + address[7], + address[6], + address[5], + address[4], + address[3], + address[2], + address[1], + address[0]); + FURI_LOG_D( + TAG, + " our UID: %02X%02X%02X%02X%02X%02X%02X%02X", + nfc_data->uid[0], + nfc_data->uid[1], + nfc_data->uid[2], + nfc_data->uid[3], + nfc_data->uid[4], + nfc_data->uid[5], + nfc_data->uid[6], + nfc_data->uid[7]); +#endif + return; + } + } + + if(ctx->selected && !nfcv_data->selected) { +#ifdef NFCV_VERBOSE + FURI_LOG_D( + TAG, + "selected card shall execute command 0x%02X, but we were not selected", + ctx->command); +#endif + return; + } + + /* then give control to the card subtype specific protocol filter */ + if(ctx->emu_protocol_filter != NULL) { + if(ctx->emu_protocol_filter(tx_rx, nfc_data, nfcv_data)) { + if(strlen(nfcv_data->last_command) > 0) { +#ifdef NFCV_VERBOSE + FURI_LOG_D( + TAG, "Received command %s (handled by filter)", nfcv_data->last_command); +#endif + } + return; + } + } + + switch(ctx->command) { + case NFCV_CMD_INVENTORY: { + bool respond = false; + + if(ctx->flags & NFCV_REQ_FLAG_AFI) { + uint8_t afi = nfcv_data->frame[ctx->payload_offset]; + if(afi == nfcv_data->afi) { + respond = true; + } + } else { + respond = true; + } + + if(!nfcv_data->quiet && respond) { + int buffer_pos = 0; + ctx->response_buffer[buffer_pos++] = NFCV_NOERROR; + ctx->response_buffer[buffer_pos++] = nfcv_data->dsfid; + nfcv_revuidcpy(&ctx->response_buffer[buffer_pos], nfc_data->uid); + buffer_pos += NFCV_UID_LENGTH; + + nfcv_emu_send( + tx_rx, + nfcv_data, + ctx->response_buffer, + buffer_pos, + ctx->response_flags, + ctx->send_time); + snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "INVENTORY"); + } else { + snprintf( + nfcv_data->last_command, sizeof(nfcv_data->last_command), "INVENTORY (quiet)"); + } + break; + } + + case NFCV_CMD_STAY_QUIET: { + snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "STAYQUIET"); + nfcv_data->quiet = true; + break; + } + + case NFCV_CMD_LOCK_BLOCK: { + uint8_t block = nfcv_data->frame[ctx->payload_offset]; + nfcv_data->security_status[block] |= 0x01; + nfcv_data->modified = true; + + ctx->response_buffer[0] = NFCV_NOERROR; + nfcv_emu_send( + tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags, ctx->send_time); + + snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "LOCK BLOCK %d", block); + break; + } + + case NFCV_CMD_WRITE_DSFID: { + uint8_t id = nfcv_data->frame[ctx->payload_offset]; + + if(!(nfcv_data->security_status[0] & NfcVLockBitDsfid)) { + nfcv_data->dsfid = id; + nfcv_data->modified = true; + ctx->response_buffer[0] = NFCV_NOERROR; + nfcv_emu_send( + tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags, ctx->send_time); + } + + snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "WRITE DSFID %02X", id); + break; + } + + case NFCV_CMD_WRITE_AFI: { + uint8_t id = nfcv_data->frame[ctx->payload_offset]; + + if(!(nfcv_data->security_status[0] & NfcVLockBitAfi)) { + nfcv_data->afi = id; + nfcv_data->modified = true; + ctx->response_buffer[0] = NFCV_NOERROR; + nfcv_emu_send( + tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags, ctx->send_time); + } + + snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "WRITE AFI %02X", id); + break; + } + + case NFCV_CMD_LOCK_DSFID: { + if(!(nfcv_data->security_status[0] & NfcVLockBitDsfid)) { + nfcv_data->security_status[0] |= NfcVLockBitDsfid; + nfcv_data->modified = true; + + ctx->response_buffer[0] = NFCV_NOERROR; + nfcv_emu_send( + tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags, ctx->send_time); + } + + snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "LOCK DSFID"); + break; + } + + case NFCV_CMD_LOCK_AFI: { + if(!(nfcv_data->security_status[0] & NfcVLockBitAfi)) { + nfcv_data->security_status[0] |= NfcVLockBitAfi; + nfcv_data->modified = true; + + ctx->response_buffer[0] = NFCV_NOERROR; + nfcv_emu_send( + tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags, ctx->send_time); + } + + snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "LOCK AFI"); + break; + } + + case NFCV_CMD_SELECT: { + ctx->response_buffer[0] = NFCV_NOERROR; + nfcv_data->selected = true; + nfcv_data->quiet = false; + nfcv_emu_send( + tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags, ctx->send_time); + snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "SELECT"); + break; + } + + case NFCV_CMD_RESET_TO_READY: { + ctx->response_buffer[0] = NFCV_NOERROR; + nfcv_data->quiet = false; + nfcv_emu_send( + tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags, ctx->send_time); + snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "RESET_TO_READY"); + break; + } + + case NFCV_CMD_READ_MULTI_BLOCK: + case NFCV_CMD_READ_BLOCK: { + uint8_t block = nfcv_data->frame[ctx->payload_offset]; + uint8_t blocks = 1; + + if(ctx->command == NFCV_CMD_READ_MULTI_BLOCK) { + blocks = nfcv_data->frame[ctx->payload_offset + 1] + 1; + } + + if(block + blocks <= nfcv_data->block_num) { + uint8_t buffer_pos = 0; + + ctx->response_buffer[buffer_pos++] = NFCV_NOERROR; + + for(int block_index = 0; block_index < blocks; block_index++) { + int block_current = block + block_index; + /* prepend security status */ + if(ctx->flags & NFCV_REQ_FLAG_OPTION) { + ctx->response_buffer[buffer_pos++] = + nfcv_data->security_status[1 + block_current]; + } + /* then the data block */ + memcpy( + &ctx->response_buffer[buffer_pos], + &nfcv_data->data[nfcv_data->block_size * block_current], + nfcv_data->block_size); + buffer_pos += nfcv_data->block_size; + } + nfcv_emu_send( + tx_rx, + nfcv_data, + ctx->response_buffer, + buffer_pos, + ctx->response_flags, + ctx->send_time); + } else { + ctx->response_buffer[0] = NFCV_RES_FLAG_ERROR; + ctx->response_buffer[1] = NFCV_ERROR_GENERIC; + nfcv_emu_send( + tx_rx, nfcv_data, ctx->response_buffer, 2, ctx->response_flags, ctx->send_time); + } + snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "READ BLOCK %d", block); + + break; + } + + case NFCV_CMD_WRITE_MULTI_BLOCK: + case NFCV_CMD_WRITE_BLOCK: { + uint8_t blocks = 1; + uint8_t block = nfcv_data->frame[ctx->payload_offset]; + uint8_t data_pos = ctx->payload_offset + 1; + + if(ctx->command == NFCV_CMD_WRITE_MULTI_BLOCK) { + blocks = nfcv_data->frame[data_pos] + 1; + data_pos++; + } + + uint8_t* data = &nfcv_data->frame[data_pos]; + uint32_t data_len = nfcv_data->block_size * blocks; + + if((block + blocks) <= nfcv_data->block_num && + (data_pos + data_len + 2) == nfcv_data->frame_length) { + ctx->response_buffer[0] = NFCV_NOERROR; + memcpy( + &nfcv_data->data[nfcv_data->block_size * block], + &nfcv_data->frame[data_pos], + data_len); + nfcv_data->modified = true; + + nfcv_emu_send( + tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags, ctx->send_time); + } else { + ctx->response_buffer[0] = NFCV_RES_FLAG_ERROR; + ctx->response_buffer[1] = NFCV_ERROR_GENERIC; + nfcv_emu_send( + tx_rx, nfcv_data, ctx->response_buffer, 2, ctx->response_flags, ctx->send_time); + } + + if(ctx->command == NFCV_CMD_WRITE_MULTI_BLOCK) { + snprintf( + nfcv_data->last_command, + sizeof(nfcv_data->last_command), + "WRITE MULTI BLOCK %d, %d blocks", + block, + blocks); + } else { + snprintf( + nfcv_data->last_command, + sizeof(nfcv_data->last_command), + "WRITE BLOCK %d <- %02X %02X %02X %02X", + block, + data[0], + data[1], + data[2], + data[3]); + } + break; + } + + case NFCV_CMD_GET_SYSTEM_INFO: { + int buffer_pos = 0; + ctx->response_buffer[buffer_pos++] = NFCV_NOERROR; + ctx->response_buffer[buffer_pos++] = NFCV_SYSINFO_FLAG_DSFID | NFCV_SYSINFO_FLAG_AFI | + NFCV_SYSINFO_FLAG_MEMSIZE | NFCV_SYSINFO_FLAG_ICREF; + nfcv_revuidcpy(&ctx->response_buffer[buffer_pos], nfc_data->uid); + buffer_pos += NFCV_UID_LENGTH; + ctx->response_buffer[buffer_pos++] = nfcv_data->dsfid; /* DSFID */ + ctx->response_buffer[buffer_pos++] = nfcv_data->afi; /* AFI */ + ctx->response_buffer[buffer_pos++] = nfcv_data->block_num - 1; /* number of blocks */ + ctx->response_buffer[buffer_pos++] = nfcv_data->block_size - 1; /* block size */ + ctx->response_buffer[buffer_pos++] = nfcv_data->ic_ref; /* IC reference */ + + nfcv_emu_send( + tx_rx, + nfcv_data, + ctx->response_buffer, + buffer_pos, + ctx->response_flags, + ctx->send_time); + snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "SYSTEMINFO"); + break; + } + + case NFCV_CMD_CUST_ECHO_MODE: { + ctx->response_buffer[0] = NFCV_NOERROR; + nfcv_data->echo_mode = true; + nfcv_emu_send( + tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags, ctx->send_time); + snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "ECHO mode"); + break; + } + + case NFCV_CMD_CUST_ECHO_DATA: { + nfcv_emu_send( + tx_rx, + nfcv_data, + &nfcv_data->frame[ctx->payload_offset], + nfcv_data->frame_length - ctx->payload_offset - 2, + NfcVSendFlagsSof | NfcVSendFlagsHighRate | NfcVSendFlagsEof, + ctx->send_time); + snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "ECHO data"); + break; + } + + default: + snprintf( + nfcv_data->last_command, + sizeof(nfcv_data->last_command), + "unsupported: %02X", + ctx->command); + break; + } + + if(strlen(nfcv_data->last_command) > 0) { +#ifdef NFCV_VERBOSE + FURI_LOG_D(TAG, "Received command %s", nfcv_data->last_command); +#endif + } +} + +void nfcv_emu_sniff_packet( + FuriHalNfcTxRxContext* tx_rx, + FuriHalNfcDevData* nfc_data, + void* nfcv_data_in) { + furi_assert(tx_rx); + furi_assert(nfc_data); + furi_assert(nfcv_data_in); + + NfcVData* nfcv_data = (NfcVData*)nfcv_data_in; + NfcVEmuProtocolCtx* ctx = nfcv_data->emu_protocol_ctx; + + if(nfcv_data->frame_length < 2) { + return; + } + + /* parse the frame data for the upcoming part 3 handling */ + ctx->flags = nfcv_data->frame[0]; + ctx->command = nfcv_data->frame[1]; + ctx->selected = (ctx->flags & NFCV_REQ_FLAG_SELECT); + ctx->addressed = !(ctx->flags & NFCV_REQ_FLAG_INVENTORY) && + (ctx->flags & NFCV_REQ_FLAG_ADDRESS); + ctx->advanced = (ctx->command >= NFCV_CMD_ADVANCED); + ctx->address_offset = 2 + (ctx->advanced ? 1 : 0); + ctx->payload_offset = ctx->address_offset + (ctx->addressed ? NFCV_UID_LENGTH : 0); + + char flags_string[5]; + + snprintf( + flags_string, + 5, + "%c%c%c%d", + (ctx->flags & NFCV_REQ_FLAG_INVENTORY) ? + 'I' : + (ctx->addressed ? 'A' : (ctx->selected ? 'S' : '*')), + ctx->advanced ? 'X' : ' ', + (ctx->flags & NFCV_REQ_FLAG_DATA_RATE) ? 'h' : 'l', + (ctx->flags & NFCV_REQ_FLAG_SUB_CARRIER) ? 2 : 1); + + switch(ctx->command) { + case NFCV_CMD_INVENTORY: { + snprintf( + nfcv_data->last_command, sizeof(nfcv_data->last_command), "%s INVENTORY", flags_string); + break; + } + + case NFCV_CMD_STAY_QUIET: { + snprintf( + nfcv_data->last_command, sizeof(nfcv_data->last_command), "%s STAYQUIET", flags_string); + nfcv_data->quiet = true; + break; + } + + case NFCV_CMD_LOCK_BLOCK: { + uint8_t block = nfcv_data->frame[ctx->payload_offset]; + snprintf( + nfcv_data->last_command, + sizeof(nfcv_data->last_command), + "%s LOCK %d", + flags_string, + block); + break; + } + + case NFCV_CMD_WRITE_DSFID: { + uint8_t id = nfcv_data->frame[ctx->payload_offset]; + snprintf( + nfcv_data->last_command, + sizeof(nfcv_data->last_command), + "%s WR DSFID %d", + flags_string, + id); + break; + } + + case NFCV_CMD_WRITE_AFI: { + uint8_t id = nfcv_data->frame[ctx->payload_offset]; + snprintf( + nfcv_data->last_command, + sizeof(nfcv_data->last_command), + "%s WR AFI %d", + flags_string, + id); + break; + } + + case NFCV_CMD_LOCK_DSFID: { + snprintf( + nfcv_data->last_command, + sizeof(nfcv_data->last_command), + "%s LOCK DSFID", + flags_string); + break; + } + + case NFCV_CMD_LOCK_AFI: { + snprintf( + nfcv_data->last_command, sizeof(nfcv_data->last_command), "%s LOCK AFI", flags_string); + break; + } + + case NFCV_CMD_SELECT: { + snprintf( + nfcv_data->last_command, sizeof(nfcv_data->last_command), "%s SELECT", flags_string); + break; + } + + case NFCV_CMD_RESET_TO_READY: { + snprintf( + nfcv_data->last_command, sizeof(nfcv_data->last_command), "%s RESET", flags_string); + break; + } + + case NFCV_CMD_READ_MULTI_BLOCK: + case NFCV_CMD_READ_BLOCK: { + uint8_t block = nfcv_data->frame[ctx->payload_offset]; + uint8_t blocks = 1; + + if(ctx->command == NFCV_CMD_READ_MULTI_BLOCK) { + blocks = nfcv_data->frame[ctx->payload_offset + 1] + 1; + } + + snprintf( + nfcv_data->last_command, + sizeof(nfcv_data->last_command), + "%s READ %d cnt: %d", + flags_string, + block, + blocks); + + break; + } + + case NFCV_CMD_WRITE_MULTI_BLOCK: + case NFCV_CMD_WRITE_BLOCK: { + uint8_t block = nfcv_data->frame[ctx->payload_offset]; + uint8_t blocks = 1; + uint8_t data_pos = 1; + + if(ctx->command == NFCV_CMD_WRITE_MULTI_BLOCK) { + blocks = nfcv_data->frame[ctx->payload_offset + 1] + 1; + data_pos++; + } + + uint8_t* data = &nfcv_data->frame[ctx->payload_offset + data_pos]; + + if(ctx->command == NFCV_CMD_WRITE_MULTI_BLOCK) { + snprintf( + nfcv_data->last_command, + sizeof(nfcv_data->last_command), + "%s WRITE %d, cnd %d", + flags_string, + block, + blocks); + } else { + snprintf( + nfcv_data->last_command, + sizeof(nfcv_data->last_command), + "%s WRITE %d %02X %02X %02X %02X", + flags_string, + block, + data[0], + data[1], + data[2], + data[3]); + } + break; + } + + case NFCV_CMD_GET_SYSTEM_INFO: { + snprintf( + nfcv_data->last_command, + sizeof(nfcv_data->last_command), + "%s SYSTEMINFO", + flags_string); + break; + } + + default: + snprintf( + nfcv_data->last_command, + sizeof(nfcv_data->last_command), + "%s unsupported: %02X", + flags_string, + ctx->command); + break; + } + + if(strlen(nfcv_data->last_command) > 0) { + FURI_LOG_D(TAG, "Received command %s", nfcv_data->last_command); + } +} + +void nfcv_emu_init(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data) { + furi_assert(nfc_data); + furi_assert(nfcv_data); + + if(!nfcv_emu_alloc(nfcv_data)) { + FURI_LOG_E(TAG, "Failed to allocate structures"); + nfcv_data->ready = false; + return; + } + + strcpy(nfcv_data->last_command, ""); + nfcv_data->quiet = false; + nfcv_data->selected = false; + nfcv_data->modified = false; + + /* everything is initialized */ + nfcv_data->ready = true; + + /* ensure the GPIO is already in unmodulated state */ + furi_hal_gpio_init(&gpio_spi_r_mosi, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); + furi_hal_gpio_write(&gpio_spi_r_mosi, GPIO_LEVEL_UNMODULATED); + + rfal_platform_spi_acquire(); + /* stop operation to configure for transparent and passive mode */ + st25r3916ExecuteCommand(ST25R3916_CMD_STOP); + /* set enable, rx_enable and field detector enable */ + st25r3916WriteRegister( + ST25R3916_REG_OP_CONTROL, + ST25R3916_REG_OP_CONTROL_en | ST25R3916_REG_OP_CONTROL_rx_en | + ST25R3916_REG_OP_CONTROL_en_fd_auto_efd); + /* explicitely set the modulation resistor in case system config changes for some reason */ + st25r3916WriteRegister( + ST25R3916_REG_PT_MOD, + (0 << ST25R3916_REG_PT_MOD_ptm_res_shift) | (15 << ST25R3916_REG_PT_MOD_pt_res_shift)); + /* target mode: target, other fields do not have any effect as we use transparent mode */ + st25r3916WriteRegister(ST25R3916_REG_MODE, ST25R3916_REG_MODE_targ); + /* let us modulate the field using MOSI, read ASK modulation using IRQ */ + st25r3916ExecuteCommand(ST25R3916_CMD_TRANSPARENT_MODE); + + furi_hal_spi_bus_handle_deinit(&furi_hal_spi_bus_handle_nfc); + + /* if not set already, initialize the default protocol handler */ + if(!nfcv_data->emu_protocol_ctx) { + nfcv_data->emu_protocol_ctx = malloc(sizeof(NfcVEmuProtocolCtx)); + if(nfcv_data->sub_type == NfcVTypeSniff) { + nfcv_data->emu_protocol_handler = &nfcv_emu_sniff_packet; + } else { + nfcv_data->emu_protocol_handler = &nfcv_emu_handle_packet; + } + } + + FURI_LOG_D(TAG, "Starting NfcV emulation"); + FURI_LOG_D( + TAG, + " UID: %02X %02X %02X %02X %02X %02X %02X %02X", + nfc_data->uid[0], + nfc_data->uid[1], + nfc_data->uid[2], + nfc_data->uid[3], + nfc_data->uid[4], + nfc_data->uid[5], + nfc_data->uid[6], + nfc_data->uid[7]); + + switch(nfcv_data->sub_type) { + case NfcVTypeSlixL: + FURI_LOG_D(TAG, " Card type: SLIX-L"); + slix_l_prepare(nfcv_data); + break; + case NfcVTypeSlixS: + FURI_LOG_D(TAG, " Card type: SLIX-S"); + slix_s_prepare(nfcv_data); + break; + case NfcVTypeSlix2: + FURI_LOG_D(TAG, " Card type: SLIX2"); + slix2_prepare(nfcv_data); + break; + case NfcVTypeSlix: + FURI_LOG_D(TAG, " Card type: SLIX"); + slix_prepare(nfcv_data); + break; + case NfcVTypePlain: + FURI_LOG_D(TAG, " Card type: Plain"); + break; + case NfcVTypeSniff: + FURI_LOG_D(TAG, " Card type: Sniffing"); + break; + } + + /* allocate a 512 edge buffer, more than enough */ + nfcv_data->emu_air.reader_signal = + pulse_reader_alloc(&gpio_nfc_irq_rfid_pull, NFCV_PULSE_BUFFER); + /* timebase shall be 1 ns */ + pulse_reader_set_timebase(nfcv_data->emu_air.reader_signal, PulseReaderUnitNanosecond); + /* and configure to already calculate the number of bits */ + pulse_reader_set_bittime(nfcv_data->emu_air.reader_signal, NFCV_PULSE_DURATION_NS); + /* this IO is fed into the µC via a diode, so we need a pulldown */ + pulse_reader_set_pull(nfcv_data->emu_air.reader_signal, GpioPullDown); + + /* start sampling */ + pulse_reader_start(nfcv_data->emu_air.reader_signal); +} + +void nfcv_emu_deinit(NfcVData* nfcv_data) { + furi_assert(nfcv_data); + + furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_nfc); + nfcv_emu_free(nfcv_data); + + if(nfcv_data->emu_protocol_ctx) { + free(nfcv_data->emu_protocol_ctx); + nfcv_data->emu_protocol_ctx = NULL; + } + + /* set registers back to how we found them */ + st25r3916WriteRegister(ST25R3916_REG_OP_CONTROL, 0x00); + st25r3916WriteRegister(ST25R3916_REG_MODE, 0x08); + rfal_platform_spi_release(); +} + +bool nfcv_emu_loop( + FuriHalNfcTxRxContext* tx_rx, + FuriHalNfcDevData* nfc_data, + NfcVData* nfcv_data, + uint32_t timeout_ms) { + furi_assert(tx_rx); + furi_assert(nfc_data); + furi_assert(nfcv_data); + + bool ret = false; + uint32_t frame_state = NFCV_FRAME_STATE_SOF1; + uint32_t periods_previous = 0; + uint32_t frame_pos = 0; + uint32_t byte_value = 0; + uint32_t bits_received = 0; + uint32_t timeout = timeout_ms * 1000; + bool wait_for_pulse = false; + + if(!nfcv_data->ready) { + return false; + } + +#ifdef NFCV_DIAGNOSTIC_DUMPS + uint8_t period_buffer[NFCV_DIAGNOSTIC_DUMP_SIZE]; + uint32_t period_buffer_pos = 0; +#endif + + while(true) { + uint32_t periods = pulse_reader_receive(nfcv_data->emu_air.reader_signal, timeout); + uint32_t timestamp = DWT->CYCCNT; + + /* when timed out, reset to SOF state */ + if(periods == PULSE_READER_NO_EDGE || periods == PULSE_READER_LOST_EDGE) { + break; + } + +#ifdef NFCV_DIAGNOSTIC_DUMPS + if(period_buffer_pos < sizeof(period_buffer)) { + period_buffer[period_buffer_pos++] = periods; + } +#endif + + /* short helper for detecting a pulse position */ + if(wait_for_pulse) { + wait_for_pulse = false; + if(periods != 1) { + frame_state = NFCV_FRAME_STATE_RESET; + } + continue; + } + + switch(frame_state) { + case NFCV_FRAME_STATE_SOF1: + if(periods == 1) { + frame_state = NFCV_FRAME_STATE_SOF2; + } else { + frame_state = NFCV_FRAME_STATE_SOF1; + break; + } + break; + + case NFCV_FRAME_STATE_SOF2: + /* waiting for the second low period, telling us about coding */ + if(periods == 6) { + frame_state = NFCV_FRAME_STATE_CODING_256; + periods_previous = 0; + wait_for_pulse = true; + } else if(periods == 4) { + frame_state = NFCV_FRAME_STATE_CODING_4; + periods_previous = 2; + wait_for_pulse = true; + } else { + frame_state = NFCV_FRAME_STATE_RESET; + } + break; + + case NFCV_FRAME_STATE_CODING_256: + if(periods_previous > periods) { + frame_state = NFCV_FRAME_STATE_RESET; + break; + } + + /* previous symbol left us with some pulse periods */ + periods -= periods_previous; + + if(periods > 512) { + frame_state = NFCV_FRAME_STATE_RESET; + break; + } else if(periods == 2) { + frame_state = NFCV_FRAME_STATE_EOF; + break; + } + + periods_previous = 512 - (periods + 1); + byte_value = (periods - 1) / 2; + if(frame_pos < NFCV_FRAMESIZE_MAX) { + nfcv_data->frame[frame_pos++] = (uint8_t)byte_value; + } + + wait_for_pulse = true; + + break; + + case NFCV_FRAME_STATE_CODING_4: + if(periods_previous > periods) { + frame_state = NFCV_FRAME_STATE_RESET; + break; + } + + /* previous symbol left us with some pulse periods */ + periods -= periods_previous; + periods_previous = 0; + + byte_value >>= 2; + bits_received += 2; + + if(periods == 1) { + byte_value |= 0x00 << 6; // -V684 + periods_previous = 6; + } else if(periods == 3) { + byte_value |= 0x01 << 6; + periods_previous = 4; + } else if(periods == 5) { + byte_value |= 0x02 << 6; + periods_previous = 2; + } else if(periods == 7) { + byte_value |= 0x03 << 6; + periods_previous = 0; + } else if(periods == 2) { + frame_state = NFCV_FRAME_STATE_EOF; + break; + } else { + frame_state = NFCV_FRAME_STATE_RESET; + break; + } + + if(bits_received >= 8) { + if(frame_pos < NFCV_FRAMESIZE_MAX) { + nfcv_data->frame[frame_pos++] = (uint8_t)byte_value; + } + bits_received = 0; + } + wait_for_pulse = true; + break; + } + + /* post-state-machine cleanup and reset */ + if(frame_state == NFCV_FRAME_STATE_RESET) { + frame_state = NFCV_FRAME_STATE_SOF1; + } else if(frame_state == NFCV_FRAME_STATE_EOF) { + nfcv_data->frame_length = frame_pos; + nfcv_data->eof_timestamp = timestamp; + break; + } + } + + if(frame_state == NFCV_FRAME_STATE_EOF) { + /* we know that this code uses TIM2, so stop pulse reader */ + pulse_reader_stop(nfcv_data->emu_air.reader_signal); + if(tx_rx->sniff_rx) { + tx_rx->sniff_rx(nfcv_data->frame, frame_pos * 8, false, tx_rx->sniff_context); + } + nfcv_data->emu_protocol_handler(tx_rx, nfc_data, nfcv_data); + + pulse_reader_start(nfcv_data->emu_air.reader_signal); + ret = true; + + } +#ifdef NFCV_VERBOSE + else { + if(frame_state != NFCV_FRAME_STATE_SOF1) { + FURI_LOG_T(TAG, "leaving while in state: %lu", frame_state); + } + } +#endif + +#ifdef NFCV_DIAGNOSTIC_DUMPS + if(period_buffer_pos) { + FURI_LOG_T(TAG, "pulses:"); + for(uint32_t pos = 0; pos < period_buffer_pos; pos++) { + FURI_LOG_T(TAG, " #%lu: %u", pos, period_buffer[pos]); + } + } +#endif + + return ret; +} diff --git a/lib/nfc/deprecated/protocols/nfcv.h b/lib/nfc/deprecated/protocols/nfcv.h new file mode 100644 index 000000000000..dff92324ac1d --- /dev/null +++ b/lib/nfc/deprecated/protocols/nfcv.h @@ -0,0 +1,290 @@ +#pragma once + +#include +#include + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* true: modulating releases load, false: modulating adds load resistor to field coil */ +#define NFCV_LOAD_MODULATION_POLARITY (false) + +#define NFCV_FC (13560000.0f) /* MHz */ +#define NFCV_RESP_SUBC1_PULSE_32 (1.0f / (NFCV_FC / 32) / 2.0f) /* 1.1799 µs */ +#define NFCV_RESP_SUBC1_UNMOD_256 (256.0f / NFCV_FC) /* 18.8791 µs */ +#define NFCV_PULSE_DURATION_NS (128.0f * 1000000000.0f / NFCV_FC) + +/* ISO/IEC 15693-3:2019(E) 10.4.12: maximum number of blocks is defined as 256 */ +#define NFCV_BLOCKS_MAX 256 +/* ISO/IEC 15693-3:2019(E) 10.4.12: maximum size of blocks is defined as 32 */ +#define NFCV_BLOCKSIZE_MAX 32 +/* the resulting memory size a card can have */ +#define NFCV_MEMSIZE_MAX (NFCV_BLOCKS_MAX * NFCV_BLOCKSIZE_MAX) +/* ISO/IEC 15693-3:2019(E) 7.1b: standard allows up to 8192, the maxium frame length that we are expected to receive/send is less */ +#define NFCV_FRAMESIZE_MAX (1 + NFCV_MEMSIZE_MAX + NFCV_BLOCKS_MAX) + +/* maximum string length for log messages */ +#define NFCV_LOG_STR_LEN 128 +/* maximum of pulses to be buffered by pulse reader */ +#define NFCV_PULSE_BUFFER 512 + +//#define NFCV_DIAGNOSTIC_DUMPS +//#define NFCV_DIAGNOSTIC_DUMP_SIZE 256 +//#define NFCV_VERBOSE + +/* helpers to calculate the send time based on DWT->CYCCNT */ +#define NFCV_FDT_USEC(usec) ((usec)*64) +#define NFCV_FDT_FC(ticks) ((ticks)*6400 / 1356) + +/* state machine when receiving frame bits */ +#define NFCV_FRAME_STATE_SOF1 0 +#define NFCV_FRAME_STATE_SOF2 1 +#define NFCV_FRAME_STATE_CODING_4 2 +#define NFCV_FRAME_STATE_CODING_256 3 +#define NFCV_FRAME_STATE_EOF 4 +#define NFCV_FRAME_STATE_RESET 5 + +/* sequences for every section of a frame */ +#define NFCV_SIG_SOF 0 +#define NFCV_SIG_BIT0 1 +#define NFCV_SIG_BIT1 2 +#define NFCV_SIG_EOF 3 +#define NFCV_SIG_LOW_SOF 4 +#define NFCV_SIG_LOW_BIT0 5 +#define NFCV_SIG_LOW_BIT1 6 +#define NFCV_SIG_LOW_EOF 7 + +/* various constants */ +#define NFCV_COMMAND_RETRIES 5 +#define NFCV_UID_LENGTH 8 + +/* ISO15693 protocol flags */ +typedef enum { + /* ISO15693 protocol flags when INVENTORY is NOT set */ + NFCV_REQ_FLAG_SUB_CARRIER = (1 << 0), + NFCV_REQ_FLAG_DATA_RATE = (1 << 1), + NFCV_REQ_FLAG_INVENTORY = (1 << 2), + NFCV_REQ_FLAG_PROTOCOL_EXT = (1 << 3), + NFCV_REQ_FLAG_SELECT = (1 << 4), + NFCV_REQ_FLAG_ADDRESS = (1 << 5), + NFCV_REQ_FLAG_OPTION = (1 << 6), + /* ISO15693 protocol flags when INVENTORY flag is set */ + NFCV_REQ_FLAG_AFI = (1 << 4), + NFCV_REQ_FLAG_NB_SLOTS = (1 << 5) +} NfcVRequestFlags; + +/* ISO15693 protocol flags */ +typedef enum { + NFCV_RES_FLAG_ERROR = (1 << 0), + NFCV_RES_FLAG_VALIDITY = (1 << 1), + NFCV_RES_FLAG_FINAL = (1 << 2), + NFCV_RES_FLAG_PROTOCOL_EXT = (1 << 3), + NFCV_RES_FLAG_SEC_LEN1 = (1 << 4), + NFCV_RES_FLAG_SEC_LEN2 = (1 << 5), + NFCV_RES_FLAG_WAIT_EXT = (1 << 6), +} NfcVRsponseFlags; + +/* flags for SYSINFO response */ +typedef enum { + NFCV_SYSINFO_FLAG_DSFID = (1 << 0), + NFCV_SYSINFO_FLAG_AFI = (1 << 1), + NFCV_SYSINFO_FLAG_MEMSIZE = (1 << 2), + NFCV_SYSINFO_FLAG_ICREF = (1 << 3) +} NfcVSysinfoFlags; + +/* ISO15693 command codes */ +typedef enum { + /* mandatory command codes */ + NFCV_CMD_INVENTORY = 0x01, + NFCV_CMD_STAY_QUIET = 0x02, + /* optional command codes */ + NFCV_CMD_READ_BLOCK = 0x20, + NFCV_CMD_WRITE_BLOCK = 0x21, + NFCV_CMD_LOCK_BLOCK = 0x22, + NFCV_CMD_READ_MULTI_BLOCK = 0x23, + NFCV_CMD_WRITE_MULTI_BLOCK = 0x24, + NFCV_CMD_SELECT = 0x25, + NFCV_CMD_RESET_TO_READY = 0x26, + NFCV_CMD_WRITE_AFI = 0x27, + NFCV_CMD_LOCK_AFI = 0x28, + NFCV_CMD_WRITE_DSFID = 0x29, + NFCV_CMD_LOCK_DSFID = 0x2A, + NFCV_CMD_GET_SYSTEM_INFO = 0x2B, + NFCV_CMD_READ_MULTI_SECSTATUS = 0x2C, + /* advanced command codes */ + NFCV_CMD_ADVANCED = 0xA0, + /* flipper zero custom command codes */ + NFCV_CMD_CUST_ECHO_MODE = 0xDE, + NFCV_CMD_CUST_ECHO_DATA = 0xDF +} NfcVCommands; + +/* ISO15693 Response error codes */ +typedef enum { + NFCV_NOERROR = 0x00, + NFCV_ERROR_CMD_NOT_SUP = 0x01, // Command not supported + NFCV_ERROR_CMD_NOT_REC = 0x02, // Command not recognized (eg. parameter error) + NFCV_ERROR_CMD_OPTION = 0x03, // Command option not supported + NFCV_ERROR_GENERIC = 0x0F, // No additional Info about this error + NFCV_ERROR_BLOCK_UNAVAILABLE = 0x10, + NFCV_ERROR_BLOCK_LOCKED_ALREADY = 0x11, // cannot lock again + NFCV_ERROR_BLOCK_LOCKED = 0x12, // cannot be changed + NFCV_ERROR_BLOCK_WRITE = 0x13, // Writing was unsuccessful + NFCV_ERROR_BLOCL_WRITELOCK = 0x14 // Locking was unsuccessful +} NfcVErrorcodes; + +typedef enum { + NfcVLockBitDsfid = 1, + NfcVLockBitAfi = 2, +} NfcVLockBits; + +typedef enum { + NfcVAuthMethodManual, + NfcVAuthMethodTonieBox, +} NfcVAuthMethod; + +typedef enum { + NfcVTypePlain = 0, + NfcVTypeSlix = 1, + NfcVTypeSlixS = 2, + NfcVTypeSlixL = 3, + NfcVTypeSlix2 = 4, + NfcVTypeSniff = 255, +} NfcVSubtype; + +typedef enum { + NfcVSendFlagsNormal = 0, + NfcVSendFlagsSof = 1 << 0, + NfcVSendFlagsCrc = 1 << 1, + NfcVSendFlagsEof = 1 << 2, + NfcVSendFlagsOneSubcarrier = 0, + NfcVSendFlagsTwoSubcarrier = 1 << 3, + NfcVSendFlagsLowRate = 0, + NfcVSendFlagsHighRate = 1 << 4 +} NfcVSendFlags; + +typedef struct { + uint8_t key_read[4]; + uint8_t key_write[4]; + uint8_t key_privacy[4]; + uint8_t key_destroy[4]; + uint8_t key_eas[4]; + uint8_t rand[2]; + bool privacy; +} NfcVSlixData; + +typedef union { + NfcVSlixData slix; +} NfcVSubtypeData; + +typedef struct { + DigitalSignal* nfcv_resp_sof; + DigitalSignal* nfcv_resp_one; + DigitalSignal* nfcv_resp_zero; + DigitalSignal* nfcv_resp_eof; +} NfcVEmuAirSignals; + +typedef struct { + PulseReader* reader_signal; + DigitalSignal* nfcv_resp_pulse; /* pulse length, fc/32 */ + DigitalSignal* nfcv_resp_half_pulse; /* half pulse length, fc/32 */ + DigitalSignal* nfcv_resp_unmod; /* unmodulated length 256/fc */ + NfcVEmuAirSignals signals_high; + NfcVEmuAirSignals signals_low; + DigitalSequence* nfcv_signal; +} NfcVEmuAir; + +typedef void (*NfcVEmuProtocolHandler)( + FuriHalNfcTxRxContext* tx_rx, + FuriHalNfcDevData* nfc_data, + void* nfcv_data); +typedef bool (*NfcVEmuProtocolFilter)( + FuriHalNfcTxRxContext* tx_rx, + FuriHalNfcDevData* nfc_data, + void* nfcv_data); + +/* the default ISO15693 handler context */ +typedef struct { + uint8_t flags; /* ISO15693-3 flags of the header as specified */ + uint8_t command; /* ISO15693-3 command at offset 1 as specified */ + bool selected; /* ISO15693-3 flags: selected frame */ + bool addressed; /* ISO15693-3 flags: addressed frame */ + bool advanced; /* ISO15693-3 command: advanced command */ + uint8_t address_offset; /* ISO15693-3 offset of the address in frame, if addressed is set */ + uint8_t payload_offset; /* ISO15693-3 offset of the payload in frame */ + + uint8_t response_buffer[NFCV_FRAMESIZE_MAX]; /* pre-allocated response buffer */ + NfcVSendFlags response_flags; /* flags to use when sending response */ + uint32_t send_time; /* timestamp when to send the response */ + + NfcVEmuProtocolFilter emu_protocol_filter; +} NfcVEmuProtocolCtx; + +typedef struct { + /* common ISO15693 fields, being specified in ISO15693-3 */ + uint8_t dsfid; + uint8_t afi; + uint8_t ic_ref; + uint16_t block_num; + uint8_t block_size; + uint8_t data[NFCV_MEMSIZE_MAX]; + uint8_t security_status[1 + NFCV_BLOCKS_MAX]; + bool selected; + bool quiet; + + bool modified; + bool ready; + bool echo_mode; + + /* specfic variant infos */ + NfcVSubtype sub_type; + NfcVSubtypeData sub_data; + NfcVAuthMethod auth_method; + + /* precalced air level data */ + NfcVEmuAir emu_air; + + uint8_t* frame; /* [NFCV_FRAMESIZE_MAX] ISO15693-2 incoming raw data from air layer */ + uint8_t frame_length; /* ISO15693-2 length of incoming data */ + uint32_t eof_timestamp; /* ISO15693-2 EOF timestamp, read from DWT->CYCCNT */ + + /* handler for the protocol layer as specified in ISO15693-3 */ + NfcVEmuProtocolHandler emu_protocol_handler; + void* emu_protocol_ctx; + /* runtime data */ + char last_command[NFCV_LOG_STR_LEN]; + char error[NFCV_LOG_STR_LEN]; +} NfcVData; + +typedef struct { + uint16_t blocks_to_read; + int16_t blocks_read; +} NfcVReader; + +ReturnCode nfcv_read_blocks(NfcVReader* reader, NfcVData* data); +ReturnCode nfcv_read_sysinfo(FuriHalNfcDevData* nfc_data, NfcVData* data); +ReturnCode nfcv_inventory(uint8_t* uid); +bool nfcv_read_card(NfcVReader* reader, FuriHalNfcDevData* nfc_data, NfcVData* data); + +void nfcv_emu_init(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data); +void nfcv_emu_deinit(NfcVData* nfcv_data); +bool nfcv_emu_loop( + FuriHalNfcTxRxContext* tx_rx, + FuriHalNfcDevData* nfc_data, + NfcVData* nfcv_data, + uint32_t timeout_ms); +void nfcv_emu_send( + FuriHalNfcTxRxContext* tx_rx, + NfcVData* nfcv, + uint8_t* data, + uint8_t length, + NfcVSendFlags flags, + uint32_t send_time); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/deprecated/protocols/slix.c b/lib/nfc/deprecated/protocols/slix.c new file mode 100644 index 000000000000..7a30cf4fd274 --- /dev/null +++ b/lib/nfc/deprecated/protocols/slix.c @@ -0,0 +1,409 @@ + +#include +#include "nfcv.h" +#include "slix.h" +#include +#include "furi_hal_nfc.h" +#include + +#define TAG "SLIX" + +static uint32_t slix_read_be(uint8_t* data, uint32_t length) { + uint32_t value = 0; + + for(uint32_t pos = 0; pos < length; pos++) { + value <<= 8; + value |= data[pos]; + } + + return value; +} + +uint8_t slix_get_ti(FuriHalNfcDevData* nfc_data) { + return (nfc_data->uid[3] >> 3) & 3; +} + +bool slix_check_card_type(FuriHalNfcDevData* nfc_data) { + if((nfc_data->uid[0] == 0xE0) && (nfc_data->uid[1] == 0x04) && (nfc_data->uid[2] == 0x01) && + slix_get_ti(nfc_data) == 2) { + return true; + } + return false; +} + +bool slix2_check_card_type(FuriHalNfcDevData* nfc_data) { + if((nfc_data->uid[0] == 0xE0) && (nfc_data->uid[1] == 0x04) && (nfc_data->uid[2] == 0x01) && + slix_get_ti(nfc_data) == 1) { + return true; + } + return false; +} + +bool slix_s_check_card_type(FuriHalNfcDevData* nfc_data) { + if((nfc_data->uid[0] == 0xE0) && (nfc_data->uid[1] == 0x04) && (nfc_data->uid[2] == 0x02)) { + return true; + } + return false; +} + +bool slix_l_check_card_type(FuriHalNfcDevData* nfc_data) { + if((nfc_data->uid[0] == 0xE0) && (nfc_data->uid[1] == 0x04) && (nfc_data->uid[2] == 0x03)) { + return true; + } + return false; +} + +ReturnCode slix_get_random(NfcVData* data) { + uint16_t received = 0; + uint8_t rxBuf[32]; + + ReturnCode ret = rfalNfcvPollerTransceiveReq( + NFCV_CMD_NXP_GET_RANDOM_NUMBER, + RFAL_NFCV_REQ_FLAG_DEFAULT, + NFCV_MANUFACTURER_NXP, + NULL, + NULL, + 0, + rxBuf, + sizeof(rxBuf), + &received); + + if(ret == ERR_NONE) { + if(received != 3) { + return ERR_PROTO; + } + if(data != NULL) { + data->sub_data.slix.rand[0] = rxBuf[2]; + data->sub_data.slix.rand[1] = rxBuf[1]; + } + } + + return ret; +} + +ReturnCode slix_unlock(NfcVData* data, uint32_t password_id) { + uint16_t received = 0; + uint8_t rxBuf[32]; + uint8_t cmd_set_pass[] = { + password_id, + data->sub_data.slix.rand[1], + data->sub_data.slix.rand[0], + data->sub_data.slix.rand[1], + data->sub_data.slix.rand[0]}; + uint8_t* password = NULL; + + switch(password_id) { + case SLIX_PASS_READ: + password = data->sub_data.slix.key_read; + break; + case SLIX_PASS_WRITE: + password = data->sub_data.slix.key_write; + break; + case SLIX_PASS_PRIVACY: + password = data->sub_data.slix.key_privacy; + break; + case SLIX_PASS_DESTROY: + password = data->sub_data.slix.key_destroy; + break; + case SLIX_PASS_EASAFI: + password = data->sub_data.slix.key_eas; + break; + default: + break; + } + + if(!password) { + return ERR_NOTSUPP; + } + + for(int pos = 0; pos < 4; pos++) { + cmd_set_pass[1 + pos] ^= password[3 - pos]; + } + + ReturnCode ret = rfalNfcvPollerTransceiveReq( + NFCV_CMD_NXP_SET_PASSWORD, + RFAL_NFCV_REQ_FLAG_DATA_RATE, + NFCV_MANUFACTURER_NXP, + NULL, + cmd_set_pass, + sizeof(cmd_set_pass), + rxBuf, + sizeof(rxBuf), + &received); + + return ret; +} + +bool slix_generic_protocol_filter( + FuriHalNfcTxRxContext* tx_rx, + FuriHalNfcDevData* nfc_data, + void* nfcv_data_in, + uint32_t password_supported) { + furi_assert(tx_rx); + furi_assert(nfc_data); + furi_assert(nfcv_data_in); + + NfcVData* nfcv_data = (NfcVData*)nfcv_data_in; + NfcVEmuProtocolCtx* ctx = nfcv_data->emu_protocol_ctx; + NfcVSlixData* slix = &nfcv_data->sub_data.slix; + + if(slix->privacy && ctx->command != NFCV_CMD_NXP_GET_RANDOM_NUMBER && + ctx->command != NFCV_CMD_NXP_SET_PASSWORD) { + snprintf( + nfcv_data->last_command, + sizeof(nfcv_data->last_command), + "command 0x%02X ignored, privacy mode", + ctx->command); + FURI_LOG_D(TAG, "%s", nfcv_data->last_command); + return true; + } + + bool handled = false; + + switch(ctx->command) { + case NFCV_CMD_NXP_GET_RANDOM_NUMBER: { + slix->rand[0] = furi_hal_random_get(); + slix->rand[1] = furi_hal_random_get(); + + ctx->response_buffer[0] = NFCV_NOERROR; + ctx->response_buffer[1] = slix->rand[1]; + ctx->response_buffer[2] = slix->rand[0]; + + nfcv_emu_send( + tx_rx, nfcv_data, ctx->response_buffer, 3, ctx->response_flags, ctx->send_time); + snprintf( + nfcv_data->last_command, + sizeof(nfcv_data->last_command), + "GET_RANDOM_NUMBER -> 0x%02X%02X", + slix->rand[0], + slix->rand[1]); + + handled = true; + break; + } + + case NFCV_CMD_NXP_SET_PASSWORD: { + uint8_t password_id = nfcv_data->frame[ctx->payload_offset]; + + if(!(password_id & password_supported)) { + break; + } + + uint8_t* password_xored = &nfcv_data->frame[ctx->payload_offset + 1]; + uint8_t* rand = slix->rand; + uint8_t* password = NULL; + uint8_t password_rcv[4]; + + switch(password_id) { + case SLIX_PASS_READ: + password = slix->key_read; + break; + case SLIX_PASS_WRITE: + password = slix->key_write; + break; + case SLIX_PASS_PRIVACY: + password = slix->key_privacy; + break; + case SLIX_PASS_DESTROY: + password = slix->key_destroy; + break; + case SLIX_PASS_EASAFI: + password = slix->key_eas; + break; + default: + break; + } + + if(!password) { + break; + } + + for(int pos = 0; pos < 4; pos++) { + password_rcv[pos] = password_xored[3 - pos] ^ rand[pos % 2]; + } + uint32_t pass_expect = slix_read_be(password, 4); + uint32_t pass_received = slix_read_be(password_rcv, 4); + + /* if the password is all-zeroes, just accept any password*/ + if(!pass_expect || pass_expect == pass_received) { + switch(password_id) { + case SLIX_PASS_READ: + break; + case SLIX_PASS_WRITE: + break; + case SLIX_PASS_PRIVACY: + slix->privacy = false; + nfcv_data->modified = true; + break; + case SLIX_PASS_DESTROY: + FURI_LOG_D(TAG, "Pooof! Got destroyed"); + break; + case SLIX_PASS_EASAFI: + break; + default: + break; + } + ctx->response_buffer[0] = NFCV_NOERROR; + nfcv_emu_send( + tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags, ctx->send_time); + snprintf( + nfcv_data->last_command, + sizeof(nfcv_data->last_command), + "SET_PASSWORD #%02X 0x%08lX OK", + password_id, + pass_received); + } else { + snprintf( + nfcv_data->last_command, + sizeof(nfcv_data->last_command), + "SET_PASSWORD #%02X 0x%08lX/%08lX FAIL", + password_id, + pass_received, + pass_expect); + } + handled = true; + break; + } + + case NFCV_CMD_NXP_ENABLE_PRIVACY: { + ctx->response_buffer[0] = NFCV_NOERROR; + + nfcv_emu_send( + tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags, ctx->send_time); + snprintf( + nfcv_data->last_command, + sizeof(nfcv_data->last_command), + "NFCV_CMD_NXP_ENABLE_PRIVACY"); + + slix->privacy = true; + handled = true; + break; + } + } + + return handled; +} + +bool slix_l_protocol_filter( + FuriHalNfcTxRxContext* tx_rx, + FuriHalNfcDevData* nfc_data, + void* nfcv_data_in) { + furi_assert(tx_rx); + furi_assert(nfc_data); + furi_assert(nfcv_data_in); + + bool handled = false; + + /* many SLIX share some of the functions, place that in a generic handler */ + if(slix_generic_protocol_filter( + tx_rx, + nfc_data, + nfcv_data_in, + SLIX_PASS_PRIVACY | SLIX_PASS_DESTROY | SLIX_PASS_EASAFI)) { + return true; + } + + return handled; +} + +void slix_l_prepare(NfcVData* nfcv_data) { + FURI_LOG_D( + TAG, " Privacy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_privacy, 4)); + FURI_LOG_D( + TAG, " Destroy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_destroy, 4)); + FURI_LOG_D(TAG, " EAS pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_eas, 4)); + FURI_LOG_D(TAG, " Privacy mode: %s", nfcv_data->sub_data.slix.privacy ? "ON" : "OFF"); + + NfcVEmuProtocolCtx* ctx = nfcv_data->emu_protocol_ctx; + ctx->emu_protocol_filter = &slix_l_protocol_filter; +} + +bool slix_s_protocol_filter( + FuriHalNfcTxRxContext* tx_rx, + FuriHalNfcDevData* nfc_data, + void* nfcv_data_in) { + furi_assert(tx_rx); + furi_assert(nfc_data); + furi_assert(nfcv_data_in); + + bool handled = false; + + /* many SLIX share some of the functions, place that in a generic handler */ + if(slix_generic_protocol_filter(tx_rx, nfc_data, nfcv_data_in, SLIX_PASS_ALL)) { + return true; + } + + return handled; +} + +void slix_s_prepare(NfcVData* nfcv_data) { + FURI_LOG_D( + TAG, " Privacy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_privacy, 4)); + FURI_LOG_D( + TAG, " Destroy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_destroy, 4)); + FURI_LOG_D(TAG, " EAS pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_eas, 4)); + FURI_LOG_D(TAG, " Privacy mode: %s", nfcv_data->sub_data.slix.privacy ? "ON" : "OFF"); + + NfcVEmuProtocolCtx* ctx = nfcv_data->emu_protocol_ctx; + ctx->emu_protocol_filter = &slix_s_protocol_filter; +} + +bool slix_protocol_filter( + FuriHalNfcTxRxContext* tx_rx, + FuriHalNfcDevData* nfc_data, + void* nfcv_data_in) { + furi_assert(tx_rx); + furi_assert(nfc_data); + furi_assert(nfcv_data_in); + + bool handled = false; + + /* many SLIX share some of the functions, place that in a generic handler */ + if(slix_generic_protocol_filter(tx_rx, nfc_data, nfcv_data_in, SLIX_PASS_EASAFI)) { + return true; + } + + return handled; +} + +void slix_prepare(NfcVData* nfcv_data) { + FURI_LOG_D( + TAG, " Privacy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_privacy, 4)); + FURI_LOG_D( + TAG, " Destroy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_destroy, 4)); + FURI_LOG_D(TAG, " EAS pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_eas, 4)); + FURI_LOG_D(TAG, " Privacy mode: %s", nfcv_data->sub_data.slix.privacy ? "ON" : "OFF"); + + NfcVEmuProtocolCtx* ctx = nfcv_data->emu_protocol_ctx; + ctx->emu_protocol_filter = &slix_protocol_filter; +} + +bool slix2_protocol_filter( // -V524 + FuriHalNfcTxRxContext* tx_rx, + FuriHalNfcDevData* nfc_data, + void* nfcv_data_in) { + furi_assert(tx_rx); + furi_assert(nfc_data); + furi_assert(nfcv_data_in); + + bool handled = false; + + /* many SLIX share some of the functions, place that in a generic handler */ + if(slix_generic_protocol_filter(tx_rx, nfc_data, nfcv_data_in, SLIX_PASS_ALL)) { + return true; + } + + return handled; +} + +void slix2_prepare(NfcVData* nfcv_data) { + FURI_LOG_D( + TAG, " Privacy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_privacy, 4)); + FURI_LOG_D( + TAG, " Destroy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_destroy, 4)); + FURI_LOG_D(TAG, " EAS pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_eas, 4)); + FURI_LOG_D(TAG, " Privacy mode: %s", nfcv_data->sub_data.slix.privacy ? "ON" : "OFF"); + + NfcVEmuProtocolCtx* ctx = nfcv_data->emu_protocol_ctx; + ctx->emu_protocol_filter = &slix2_protocol_filter; +} diff --git a/lib/nfc/deprecated/protocols/slix.h b/lib/nfc/deprecated/protocols/slix.h new file mode 100644 index 000000000000..3ed7d43d70e4 --- /dev/null +++ b/lib/nfc/deprecated/protocols/slix.h @@ -0,0 +1,45 @@ +#pragma once + +#include +#include +#include + +#define NFCV_MANUFACTURER_NXP 0x04 + +/* ISO15693-3 CUSTOM NXP COMMANDS */ +#define NFCV_CMD_NXP_SET_EAS 0xA2 +#define NFCV_CMD_NXP_RESET_EAS 0xA3 +#define NFCV_CMD_NXP_LOCK_EAS 0xA4 +#define NFCV_CMD_NXP_EAS_ALARM 0xA5 +#define NFCV_CMD_NXP_PASSWORD_PROTECT_EAS_AFI 0xA6 +#define NFCV_CMD_NXP_WRITE_EAS_ID 0xA7 +#define NFCV_CMD_NXP_INVENTORY_PAGE_READ 0xB0 +#define NFCV_CMD_NXP_INVENTORY_PAGE_READ_FAST 0xB1 +#define NFCV_CMD_NXP_GET_RANDOM_NUMBER 0xB2 +#define NFCV_CMD_NXP_SET_PASSWORD 0xB3 +#define NFCV_CMD_NXP_WRITE_PASSWORD 0xB4 +#define NFCV_CMD_NXP_DESTROY 0xB9 +#define NFCV_CMD_NXP_ENABLE_PRIVACY 0xBA + +/* available passwords */ +#define SLIX_PASS_READ 0x01 +#define SLIX_PASS_WRITE 0x02 +#define SLIX_PASS_PRIVACY 0x04 +#define SLIX_PASS_DESTROY 0x08 +#define SLIX_PASS_EASAFI 0x10 + +#define SLIX_PASS_ALL \ + (SLIX_PASS_READ | SLIX_PASS_WRITE | SLIX_PASS_PRIVACY | SLIX_PASS_DESTROY | SLIX_PASS_EASAFI) + +bool slix_check_card_type(FuriHalNfcDevData* nfc_data); +bool slix2_check_card_type(FuriHalNfcDevData* nfc_data); +bool slix_s_check_card_type(FuriHalNfcDevData* nfc_data); +bool slix_l_check_card_type(FuriHalNfcDevData* nfc_data); + +ReturnCode slix_get_random(NfcVData* data); +ReturnCode slix_unlock(NfcVData* data, uint32_t password_id); + +void slix_prepare(NfcVData* nfcv_data); +void slix_s_prepare(NfcVData* nfcv_data); +void slix_l_prepare(NfcVData* nfcv_data); +void slix2_prepare(NfcVData* nfcv_data); diff --git a/lib/nfc/helpers/nfc_util.h b/lib/nfc/helpers/nfc_util.h index 04fa7622b931..a9d5a3f8ab0c 100644 --- a/lib/nfc/helpers/nfc_util.h +++ b/lib/nfc/helpers/nfc_util.h @@ -2,6 +2,10 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + void nfc_util_num2bytes(uint64_t src, uint8_t len, uint8_t* dest); uint64_t nfc_util_bytes2num(const uint8_t* src, uint8_t len); @@ -11,3 +15,7 @@ uint8_t nfc_util_even_parity32(uint32_t data); uint8_t nfc_util_odd_parity8(uint8_t data); void nfc_util_odd_parity(const uint8_t* src, uint8_t* dst, uint8_t len); + +#ifdef __cplusplus +} +#endif diff --git a/lib/pulse_reader/pulse_reader.c b/lib/pulse_reader/pulse_reader.c index 74d99fe801c2..1c3cb4a586f8 100644 --- a/lib/pulse_reader/pulse_reader.c +++ b/lib/pulse_reader/pulse_reader.c @@ -135,6 +135,7 @@ void pulse_reader_stop(PulseReader* signal) { LL_DMA_DisableChannel(DMA1, signal->dma_channel + 1); LL_DMAMUX_DisableRequestGen(NULL, LL_DMAMUX_REQ_GEN_0); LL_TIM_DisableCounter(TIM2); + furi_hal_bus_disable(FuriHalBusTIM2); furi_hal_gpio_init_simple(signal->gpio, GpioModeAnalog); } @@ -146,6 +147,8 @@ void pulse_reader_start(PulseReader* signal) { signal->dma_config_gpio.MemoryOrM2MDstAddress = (uint32_t)signal->gpio_buffer; signal->dma_config_gpio.NbData = signal->size; + furi_hal_bus_enable(FuriHalBusTIM2); + /* start counter */ LL_TIM_SetCounterMode(TIM2, LL_TIM_COUNTERMODE_UP); LL_TIM_SetClockDivision(TIM2, LL_TIM_CLOCKDIVISION_DIV1); diff --git a/lib/subghz/SConscript b/lib/subghz/SConscript index 6d9c0cd06385..3a0325b71db7 100644 --- a/lib/subghz/SConscript +++ b/lib/subghz/SConscript @@ -18,6 +18,7 @@ env.Append( File("blocks/generic.h"), File("blocks/math.h"), File("subghz_setting.h"), + File("subghz_protocol_registry.h"), ], ) diff --git a/lib/subghz/environment.c b/lib/subghz/environment.c index 5ded243c4168..3794dbad841c 100644 --- a/lib/subghz/environment.c +++ b/lib/subghz/environment.c @@ -92,16 +92,17 @@ const char* void subghz_environment_set_protocol_registry( SubGhzEnvironment* instance, - void* protocol_registry_items) { + const SubGhzProtocolRegistry* protocol_registry_items) { furi_assert(instance); const SubGhzProtocolRegistry* protocol_registry = protocol_registry_items; instance->protocol_registry = protocol_registry; } -void* subghz_environment_get_protocol_registry(SubGhzEnvironment* instance) { +const SubGhzProtocolRegistry* + subghz_environment_get_protocol_registry(SubGhzEnvironment* instance) { furi_assert(instance); furi_assert(instance->protocol_registry); - return (void*)instance->protocol_registry; + return instance->protocol_registry; } const char* diff --git a/lib/subghz/environment.h b/lib/subghz/environment.h index 7bd38ba2fe57..c15b8b211b00 100644 --- a/lib/subghz/environment.h +++ b/lib/subghz/environment.h @@ -1,6 +1,7 @@ #pragma once #include +#include "registry.h" #include "subghz_keystore.h" @@ -9,6 +10,7 @@ extern "C" { #endif typedef struct SubGhzEnvironment SubGhzEnvironment; +typedef struct SubGhzProtocolRegistry SubGhzProtocolRegistry; /** * Allocate SubGhzEnvironment. @@ -93,14 +95,15 @@ const char* */ void subghz_environment_set_protocol_registry( SubGhzEnvironment* instance, - void* protocol_registry_items); + const SubGhzProtocolRegistry* protocol_registry_items); /** * Get list of protocols to work. * @param instance Pointer to a SubGhzEnvironment instance * @return Pointer to a SubGhzProtocolRegistry */ -void* subghz_environment_get_protocol_registry(SubGhzEnvironment* instance); +const SubGhzProtocolRegistry* + subghz_environment_get_protocol_registry(SubGhzEnvironment* instance); /** * Get list of protocols names. diff --git a/lib/subghz/protocols/protocol_items.h b/lib/subghz/protocols/protocol_items.h index 4ca1c4679d15..f1a28ac9b514 100644 --- a/lib/subghz/protocols/protocol_items.h +++ b/lib/subghz/protocols/protocol_items.h @@ -1,5 +1,6 @@ #pragma once #include "../registry.h" +#include "../subghz_protocol_registry.h" #include "princeton.h" #include "keeloq.h" @@ -43,5 +44,3 @@ #include "alutech_at_4n.h" #include "kinggates_stylo_4k.h" #include "bin_raw.h" - -extern const SubGhzProtocolRegistry subghz_protocol_registry; diff --git a/lib/subghz/registry.h b/lib/subghz/registry.h index 91027807e898..8529c1097051 100644 --- a/lib/subghz/registry.h +++ b/lib/subghz/registry.h @@ -9,6 +9,7 @@ extern "C" { typedef struct SubGhzEnvironment SubGhzEnvironment; typedef struct SubGhzProtocolRegistry SubGhzProtocolRegistry; +typedef struct SubGhzProtocol SubGhzProtocol; struct SubGhzProtocolRegistry { const SubGhzProtocol** items; diff --git a/lib/subghz/subghz_protocol_registry.h b/lib/subghz/subghz_protocol_registry.h new file mode 100644 index 000000000000..6a27da992597 --- /dev/null +++ b/lib/subghz/subghz_protocol_registry.h @@ -0,0 +1,13 @@ +#pragma once + +#include "registry.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern const SubGhzProtocolRegistry subghz_protocol_registry; + +#ifdef __cplusplus +} +#endif diff --git a/lib/subghz/types.h b/lib/subghz/types.h index 09eb07eeaada..719beff45f8e 100644 --- a/lib/subghz/types.h +++ b/lib/subghz/types.h @@ -21,6 +21,9 @@ #define SUBGHZ_RAW_FILE_VERSION 1 #define SUBGHZ_RAW_FILE_TYPE "Flipper SubGhz RAW File" +typedef struct SubGhzProtocolRegistry SubGhzProtocolRegistry; +typedef struct SubGhzEnvironment SubGhzEnvironment; + // Radio Preset typedef struct { FuriString* name; @@ -115,11 +118,11 @@ typedef enum { SubGhzProtocolFlag_BinRAW = (1 << 10), } SubGhzProtocolFlag; -typedef struct { +struct SubGhzProtocol { const char* name; SubGhzProtocolType type; SubGhzProtocolFlag flag; const SubGhzProtocolEncoder* encoder; const SubGhzProtocolDecoder* decoder; -} SubGhzProtocol; +}; diff --git a/lib/toolbox/SConscript b/lib/toolbox/SConscript index 4e158e30ea79..6084969c4c5b 100644 --- a/lib/toolbox/SConscript +++ b/lib/toolbox/SConscript @@ -8,6 +8,7 @@ env.Append( "#/lib/toolbox", ], SDK_HEADERS=[ + File("api_lock.h"), File("manchester_decoder.h"), File("manchester_encoder.h"), File("path.h"), diff --git a/lib/toolbox/value_index.c b/lib/toolbox/value_index.c index e0745e434107..5ec0fb96287a 100644 --- a/lib/toolbox/value_index.c +++ b/lib/toolbox/value_index.c @@ -1,5 +1,18 @@ #include "value_index.h" +uint8_t value_index_int32(const int32_t value, const int32_t values[], uint8_t values_count) { + int64_t last_value = INT64_MIN; + uint8_t index = 0; + for(uint8_t i = 0; i < values_count; i++) { + if((value >= last_value) && (value <= values[i])) { + index = i; + break; + } + last_value = values[i]; + } + return index; +} + uint8_t value_index_uint32(const uint32_t value, const uint32_t values[], uint8_t values_count) { int64_t last_value = INT64_MIN; uint8_t index = 0; diff --git a/lib/toolbox/value_index.h b/lib/toolbox/value_index.h index 9459292a75b7..5aa768e3d1d9 100644 --- a/lib/toolbox/value_index.h +++ b/lib/toolbox/value_index.h @@ -7,6 +7,19 @@ extern "C" { #endif +/** Get the index of a int32_t array element which is closest to the given value. + * + * Returned index corresponds to the first element found. + * If no suitable elements were found, the function returns 0. + * + * @param value value to be searched. + * @param values pointer to the array to perform the search in. + * @param values_count array size. + * + * @return value's index. + */ +uint8_t value_index_int32(const int32_t value, const int32_t values[], uint8_t values_count); + /** Get the index of a uint32_t array element which is closest to the given value. * * Returned index corresponds to the first element found. diff --git a/lib/toolbox/version.c b/lib/toolbox/version.c index 6ba68e364d93..876695f07852 100644 --- a/lib/toolbox/version.c +++ b/lib/toolbox/version.c @@ -5,7 +5,7 @@ #define VERSION_MAGIC (0xBE40u) #define VERSION_MAJOR (0x1u) -#define VERSION_MINOR (0x0u) +#define VERSION_MINOR (0x1u) struct Version { // Header @@ -20,6 +20,9 @@ struct Version { // Payload bits and pieces const uint8_t target; const bool build_is_dirty; + // v 1.1 + const char* firmware_origin; + const char* git_origin; }; /* version of current running firmware (bootloader/flipper) */ @@ -37,6 +40,8 @@ static const Version version = { , .target = TARGET, .build_is_dirty = BUILD_DIRTY, + .firmware_origin = FIRMWARE_ORIGIN, + .git_origin = GIT_ORIGIN, }; const Version* version_get(void) { @@ -71,3 +76,11 @@ uint8_t version_get_target(const Version* v) { bool version_get_dirty_flag(const Version* v) { return v ? v->build_is_dirty : version.build_is_dirty; } + +const char* version_get_firmware_origin(const Version* v) { + return v ? v->firmware_origin : version.firmware_origin; +} + +const char* version_get_git_origin(const Version* v) { + return v ? v->git_origin : version.git_origin; +} diff --git a/lib/toolbox/version.h b/lib/toolbox/version.h index 652ff3feace8..0c04e5c75964 100644 --- a/lib/toolbox/version.h +++ b/lib/toolbox/version.h @@ -82,6 +82,17 @@ uint8_t version_get_target(const Version* v); */ bool version_get_dirty_flag(const Version* v); +/** + * Get firmware origin. "Official" for mainline firmware, fork name for forks. + * Set by FIRMWARE_ORIGIN fbt argument. +*/ +const char* version_get_firmware_origin(const Version* v); + +/** + * Get git repo origin +*/ +const char* version_get_git_origin(const Version* v); + #ifdef __cplusplus } #endif diff --git a/lib/u8g2/u8g2_glue.c b/lib/u8g2/u8g2_glue.c index 17a702b50fc2..0d4879bce5dc 100644 --- a/lib/u8g2/u8g2_glue.c +++ b/lib/u8g2/u8g2_glue.c @@ -2,6 +2,9 @@ #include +#define CONTRAST_ERC 32 +#define CONTRAST_MGG 31 + uint8_t u8g2_gpio_and_delay_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_ptr) { UNUSED(u8x8); UNUSED(arg_ptr); @@ -207,6 +210,19 @@ void u8x8_d_st756x_init(u8x8_t* u8x8, uint8_t contrast, uint8_t regulation_ratio u8x8_cad_EndTransfer(u8x8); } +void u8x8_d_st756x_set_contrast(u8x8_t* u8x8, int8_t contrast_offset) { + uint8_t contrast = (furi_hal_version_get_hw_display() == FuriHalVersionDisplayMgg) ? + CONTRAST_MGG : + CONTRAST_ERC; + contrast += contrast_offset; + contrast = contrast & 0b00111111; + + u8x8_cad_StartTransfer(u8x8); + u8x8_cad_SendCmd(u8x8, ST756X_CMD_SET_EV); + u8x8_cad_SendArg(u8x8, contrast); + u8x8_cad_EndTransfer(u8x8); +} + uint8_t u8x8_d_st756x_flipper(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_ptr) { /* call common procedure first and handle messages there */ if(u8x8_d_st756x_common(u8x8, msg, arg_int, arg_ptr) == 0) { @@ -225,7 +241,7 @@ uint8_t u8x8_d_st756x_flipper(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* * RR = 10 / ((1 - (63 - 32) / 162) * 2.1) ~= 5.88 is 6 (0b110) * Bias = 1/9 (false) */ - u8x8_d_st756x_init(u8x8, 31, 0b110, false); + u8x8_d_st756x_init(u8x8, CONTRAST_MGG, 0b110, false); } else { /* ERC v1(ST7565) and v2(ST7567) * EV = 33 @@ -233,7 +249,7 @@ uint8_t u8x8_d_st756x_flipper(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* * RR = 9.3 / ((1 - (63 - 32) / 162) * 2.1) ~= 5.47 is 5.5 (0b101) * Bias = 1/9 (false) */ - u8x8_d_st756x_init(u8x8, 32, 0b101, false); + u8x8_d_st756x_init(u8x8, CONTRAST_ERC, 0b101, false); } break; case U8X8_MSG_DISPLAY_SET_FLIP_MODE: diff --git a/lib/u8g2/u8g2_glue.h b/lib/u8g2/u8g2_glue.h index 91ba2980a5c5..af236279ecec 100644 --- a/lib/u8g2/u8g2_glue.h +++ b/lib/u8g2/u8g2_glue.h @@ -14,3 +14,5 @@ void u8g2_Setup_st756x_flipper( u8x8_msg_cb gpio_and_delay_cb); void u8x8_d_st756x_init(u8x8_t* u8x8, uint8_t contrast, uint8_t regulation_ratio, bool bias); + +void u8x8_d_st756x_set_contrast(u8x8_t* u8x8, int8_t contrast_offset); diff --git a/scripts/debug/flipperapps.py b/scripts/debug/flipperapps.py index 90582c1e44ad..6dba89a5640e 100644 --- a/scripts/debug/flipperapps.py +++ b/scripts/debug/flipperapps.py @@ -188,6 +188,7 @@ def attach_to_fw(self) -> None: ) self.app_type_ptr = gdb.lookup_type("FlipperApplication").pointer() self.app_list_entry_type = gdb.lookup_type("struct FlipperApplicationList_s") + self._sync_apps() def handle_stop(self, event) -> None: self._sync_apps() @@ -196,7 +197,10 @@ def handle_exit(self, event) -> None: self.set_debug_mode(False) def set_debug_mode(self, mode: bool) -> None: - gdb.execute(f"set variable furi_hal_debug_gdb_session_active = {int(mode)}") + try: + gdb.execute(f"set variable furi_hal_debug_gdb_session_active = {int(mode)}") + except gdb.error as e: + print(f"Failed to set debug mode: {e}") # Init additional 'fap-set-debug-elf-root' command and set up hooks diff --git a/scripts/debug/flipperversion.py b/scripts/debug/flipperversion.py index 4ac3bd200d1e..56915c0f28e1 100644 --- a/scripts/debug/flipperversion.py +++ b/scripts/debug/flipperversion.py @@ -23,6 +23,10 @@ class VersionData: version: str target: int build_is_dirty: bool + # Since version 1.1 + firmware_origin: str = "" + git_origin: str = "" + # More fields may be added in the future extra: Optional[Dict[str, str]] = field(default_factory=dict) @@ -52,7 +56,7 @@ def load_versioned(self, major, minor): # Struct version 1.0 extra_data = int(self.version_ptr[5].cast(self._uint_type)) - return VersionData( + version_data = VersionData( git_hash=self.version_ptr[1].cast(self._cstr_type).string(), git_branch=self.version_ptr[2].cast(self._cstr_type).string(), build_date=self.version_ptr[3].cast(self._cstr_type).string(), @@ -60,6 +64,12 @@ def load_versioned(self, major, minor): target=extra_data & 0xF, build_is_dirty=bool((extra_data >> 8) & 0xF), ) + if minor >= 1: + version_data.firmware_origin = ( + self.version_ptr[6].cast(self._cstr_type).string() + ) + version_data.git_origin = self.version_ptr[7].cast(self._cstr_type).string() + return version_data def load_unversioned(self): """Parse an early version of the version struct.""" @@ -104,6 +114,10 @@ def invoke(self, arg, from_tty): print(f"\tGit commit: {v.version.git_hash}") print(f"\tDirty: {v.version.build_is_dirty}") print(f"\tHW Target: {v.version.target}") + if v.version.firmware_origin: + print(f"\tOrigin: {v.version.firmware_origin}") + if v.version.git_origin: + print(f"\tGit origin: {v.version.git_origin}") FlipperFwVersion() diff --git a/scripts/fbt/appmanifest.py b/scripts/fbt/appmanifest.py index 5e41f4c0e305..820f5a8c55f0 100644 --- a/scripts/fbt/appmanifest.py +++ b/scripts/fbt/appmanifest.py @@ -1,7 +1,8 @@ import os +import re from dataclasses import dataclass, field from enum import Enum -from typing import Callable, List, Optional, Tuple +from typing import Callable, ClassVar, List, Optional, Tuple, Union class FlipperManifestException(Exception): @@ -23,6 +24,8 @@ class FlipperAppType(Enum): @dataclass class FlipperApplication: + APP_ID_REGEX: ClassVar[re.Pattern] = re.compile(r"^[a-z0-9_]+$") + @dataclass class ExternallyBuiltFile: path: str @@ -56,7 +59,7 @@ class Library: # .fap-specific sources: List[str] = field(default_factory=lambda: ["*.c*"]) - fap_version: Tuple[int] = field(default_factory=lambda: (0, 1)) + fap_version: Union[str, Tuple[int]] = "0.1" fap_icon: Optional[str] = None fap_libs: List[str] = field(default_factory=list) fap_category: str = "" @@ -84,6 +87,17 @@ def is_default_deployable(self): def __post_init__(self): if self.apptype == FlipperAppType.PLUGIN: self.stack_size = 0 + if not self.APP_ID_REGEX.match(self.appid): + raise FlipperManifestException( + f"Invalid appid '{self.appid}'. Must match regex '{self.APP_ID_REGEX}'" + ) + if isinstance(self.fap_version, str): + try: + self.fap_version = tuple(int(v) for v in self.fap_version.split(".")) + except ValueError: + raise FlipperManifestException( + f"Invalid version string '{self.fap_version}'. Must be in the form 'major.minor'" + ) class AppManager: diff --git a/scripts/fbt_tools/fbt_dist.py b/scripts/fbt_tools/fbt_dist.py index a43d62e9dc94..e47898bd9ed0 100644 --- a/scripts/fbt_tools/fbt_dist.py +++ b/scripts/fbt_tools/fbt_dist.py @@ -132,7 +132,7 @@ def generate(env): "UsbInstall": Builder( action=[ Action( - '${PYTHON3} "${SELFUPDATE_SCRIPT}" ${UPDATE_BUNDLE_DIR}/update.fuf' + '${PYTHON3} "${SELFUPDATE_SCRIPT}" -p ${FLIP_PORT} ${UPDATE_BUNDLE_DIR}/update.fuf' ), Touch("${TARGET}"), ] diff --git a/scripts/fbt_tools/fbt_envhooks.py b/scripts/fbt_tools/fbt_envhooks.py new file mode 100644 index 000000000000..0538e173c655 --- /dev/null +++ b/scripts/fbt_tools/fbt_envhooks.py @@ -0,0 +1,67 @@ +""" + +To introduce changes to firmware build environment that are specific to your fork: + + create a file "scripts/fbt/fbt_hooks.py" + +With it, you can define functions that will be called at specific points of +firmware build configuration, with environment as an argument. + +For example, you can define a function `PreConfigureFwEnvionment(env)` that +defines that will be a part of SDK build, so applications can +use them for conditional compilation. + +Here is a list of all available hooks: + + PreConfigureFwEnvionment(env): + This function is called on firmware environment (incl. updater) + before any major configuration is done. + + PostConfigureFwEnvionment(env): + This function is called on firmware environment (incl. updater) + after all configuration is done. + + PreConfigureUfbtEnvionment(env): + This function is called on ufbt environment at the beginning of + its configuration, before dist environment is created. + + PostConfigureUfbtEnvionment(env): + This function is called on ufbt dist_env environment after all + configuration and target creation is done. +""" + + +class DefaultFbtHooks: + pass + + +try: + from fbt import fbt_hooks +except ImportError: + fbt_hooks = DefaultFbtHooks() + + +def generate(env): + stub_hook = lambda env: None + control_hooks = [ + "PreConfigureFwEnvionment", + "PostConfigureFwEnvionment", + "PreConfigureUfbtEnvionment", + "PostConfigureUfbtEnvionment", + ] + + if ( + isinstance(fbt_hooks, DefaultFbtHooks) + and env.subst("${FIRMWARE_ORIGIN}") != "Official" + ): + # If fbt_hooks.py is not present, but we are not building official firmware, + # create "scripts/fbt/fbt_hooks.py" to implement changes to firmware build environment. + pass + + for hook_name in control_hooks: + hook_fn = getattr(fbt_hooks, hook_name, stub_hook) + env.AddMethod(hook_fn, hook_name) + + +def exists(): + return True diff --git a/scripts/fbt_tools/fbt_extapps.py b/scripts/fbt_tools/fbt_extapps.py index 1a1bad29e718..16d5dcbabd34 100644 --- a/scripts/fbt_tools/fbt_extapps.py +++ b/scripts/fbt_tools/fbt_extapps.py @@ -431,7 +431,7 @@ def _add_host_app_to_targets(host_app): # print(deploy_sources, flipp_dist_paths) env.PhonyTarget( launch_target_name, - '${PYTHON3} "${APP_RUN_SCRIPT}" ${EXTRA_ARGS} -s ${SOURCES} -t ${FLIPPER_FILE_TARGETS}', + '${PYTHON3} "${APP_RUN_SCRIPT}" -p ${FLIP_PORT} ${EXTRA_ARGS} -s ${SOURCES} -t ${FLIPPER_FILE_TARGETS}', source=deploy_sources, FLIPPER_FILE_TARGETS=flipp_dist_paths, EXTRA_ARGS=run_script_extra_ars, @@ -443,7 +443,6 @@ def generate(env, **kw): env.SetDefault( EXT_APPS_WORK_DIR="${FBT_FAP_DEBUG_ELF_ROOT}", APP_RUN_SCRIPT="${FBT_SCRIPT_DIR}/runfap.py", - STORAGE_SCRIPT="${FBT_SCRIPT_DIR}/storage.py", ) if not env["VERBOSE"]: env.SetDefault( diff --git a/scripts/fbt_tools/fbt_version.py b/scripts/fbt_tools/fbt_version.py index 8469e181a32a..aead13b29fa5 100644 --- a/scripts/fbt_tools/fbt_version.py +++ b/scripts/fbt_tools/fbt_version.py @@ -19,7 +19,9 @@ def generate(env): BUILDERS={ "VersionBuilder": Builder( action=Action( - '${PYTHON3} "${VERSION_SCRIPT}" generate -t ${TARGET_HW} -o ${TARGET.dir.posix} --dir "${ROOT_DIR}"', + '${PYTHON3} "${VERSION_SCRIPT}" generate ' + "-t ${TARGET_HW} -fw-origin ${FIRMWARE_ORIGIN} " + '-o ${TARGET.dir.posix} --dir "${ROOT_DIR}"', "${VERSIONCOMSTR}", ), emitter=version_emitter, diff --git a/scripts/flipper/assets/copro.py b/scripts/flipper/assets/copro.py index f176e3b2e82c..25c072899ea8 100644 --- a/scripts/flipper/assets/copro.py +++ b/scripts/flipper/assets/copro.py @@ -58,14 +58,23 @@ def loadCubeInfo(self, cube_dir, reference_cube_version): def _getFileName(self, name): return posixpath.join(self.COPRO_TAR_DIR, name) + def _addFileReadPermission(self, tarinfo): + tarinfo.mode = 0o644 + return tarinfo + def addFile(self, array, filename, **kwargs): source_file = os.path.join(self.mcu_copro, filename) - self.output_tar.add(source_file, arcname=self._getFileName(filename)) + self.output_tar.add( + source_file, + arcname=self._getFileName(filename), + filter=self._addFileReadPermission, + ) array.append({"name": filename, "sha256": file_sha256(source_file), **kwargs}) def bundle(self, output_file, stack_file_name, stack_type, stack_addr=None): self.output_tar = tarfile.open(output_file, "w:gz", format=tarfile.USTAR_FORMAT) fw_directory = tarfile.TarInfo(self.COPRO_TAR_DIR) + fw_directory.mode = 0o755 fw_directory.type = tarfile.DIRTYPE self.output_tar.addfile(fw_directory) diff --git a/scripts/flipper/assets/coprobin.py b/scripts/flipper/assets/coprobin.py index 75bf76d766dd..84f52fbb3eb5 100644 --- a/scripts/flipper/assets/coprobin.py +++ b/scripts/flipper/assets/coprobin.py @@ -46,7 +46,10 @@ class CoproFooterBase: _SIG_BIN_COMMON_SIZE = 2 * 4 def get_version(self): - return f"Version {self.version_major}.{self.version_minor}.{self.version_sub}, branch {self.version_branch}, build {self.version_build} (magic {self.magic:X})" + return ( + f"Version {self.version_major}.{self.version_minor}.{self.version_sub}, " + f"branch {self.version_branch}, build {self.version_build} (magic {self.magic:X})" + ) def get_details(self): raise CoproException("Not implemented") diff --git a/scripts/flipper/assets/dolphin.py b/scripts/flipper/assets/dolphin.py index ebe9fd889866..b4a53a62df5f 100644 --- a/scripts/flipper/assets/dolphin.py +++ b/scripts/flipper/assets/dolphin.py @@ -49,11 +49,11 @@ def __init__( def load(self, animation_directory: str): if not os.path.isdir(animation_directory): - raise Exception(f"Animation folder doesn't exists: { animation_directory }") + raise Exception(f"Animation folder doesn't exist: { animation_directory }") meta_filename = os.path.join(animation_directory, "meta.txt") if not os.path.isfile(meta_filename): - raise Exception(f"Animation meta file doesn't exists: { meta_filename }") + raise Exception(f"Animation meta file doesn't exist: { meta_filename }") self.logger.info(f"Loading meta from {meta_filename}") file = FlipperFormatFile() diff --git a/scripts/flipper/storage.py b/scripts/flipper/storage.py index f4d622bfe427..2c9c043d5a85 100644 --- a/scripts/flipper/storage.py +++ b/scripts/flipper/storage.py @@ -257,12 +257,12 @@ def send_file(self, filename_from: str, filename_to: str): self.read.until(self.CLI_PROMPT) ftell = file.tell() - percent = str(math.ceil(ftell / filesize * 100)) - total_chunks = str(math.ceil(filesize / buffer_size)) - current_chunk = str(math.ceil(ftell / buffer_size)) + percent = math.ceil(ftell / filesize * 100) + total_chunks = math.ceil(filesize / buffer_size) + current_chunk = math.ceil(ftell / buffer_size) approx_speed = ftell / (time.time() - start_time + 0.0001) sys.stdout.write( - f"\r{percent}%, chunk {current_chunk} of {total_chunks} @ {approx_speed/1024:.2f} kb/s" + f"\r<{percent:3d}%, chunk {current_chunk:2d} of {total_chunks:2d} @ {approx_speed/1024:.2f} kb/s" ) sys.stdout.flush() print() @@ -270,6 +270,7 @@ def send_file(self, filename_from: str, filename_to: str): def read_file(self, filename: str): """Receive file from Flipper, and get filedata (bytes)""" buffer_size = self.chunk_size + start_time = time.time() self.send_and_wait_eol( 'storage read_chunks "' + filename + '" ' + str(buffer_size) + "\r" ) @@ -290,10 +291,13 @@ def read_file(self, filename: str): filedata.extend(self.port.read(chunk_size)) read_size = read_size + chunk_size - percent = str(math.ceil(read_size / size * 100)) - total_chunks = str(math.ceil(size / buffer_size)) - current_chunk = str(math.ceil(read_size / buffer_size)) - sys.stdout.write(f"\r{percent}%, chunk {current_chunk} of {total_chunks}") + percent = math.ceil(read_size / size * 100) + total_chunks = math.ceil(size / buffer_size) + current_chunk = math.ceil(read_size / buffer_size) + approx_speed = read_size / (time.time() - start_time + 0.0001) + sys.stdout.write( + f"\r>{percent:3d}%, chunk {current_chunk:2d} of {total_chunks:2d} @ {approx_speed/1024:.2f} kb/s" + ) sys.stdout.flush() print() self.read.until(self.CLI_PROMPT) diff --git a/scripts/flipper/utils/cdc.py b/scripts/flipper/utils/cdc.py index 7c7351670291..9564088598e0 100644 --- a/scripts/flipper/utils/cdc.py +++ b/scripts/flipper/utils/cdc.py @@ -6,7 +6,7 @@ def resolve_port(logger, portname: str = "auto"): if portname != "auto": return portname # Try guessing - flippers = list(list_ports.grep("flip")) + flippers = list(list_ports.grep("flip_")) if len(flippers) == 1: flipper = flippers[0] logger.info(f"Using {flipper.serial_number} on {flipper.device}") diff --git a/scripts/map_mariadb_insert.py b/scripts/map_mariadb_insert.py new file mode 100755 index 000000000000..a4c9ed5c788d --- /dev/null +++ b/scripts/map_mariadb_insert.py @@ -0,0 +1,139 @@ +#!/usr/bin/env python3 + +# Requiremets: +# mariadb==1.1.6 + +from datetime import datetime +import argparse +import mariadb +import sys +import os + + +def parseArgs(): + parser = argparse.ArgumentParser() + parser.add_argument("db_user", help="MariaDB user") + parser.add_argument("db_pass", help="MariaDB password") + parser.add_argument("db_host", help="MariaDB hostname") + parser.add_argument("db_port", type=int, help="MariaDB port") + parser.add_argument("db_name", help="MariaDB database") + parser.add_argument("report_file", help="Report file(.map.all)") + args = parser.parse_args() + return args + + +def mariadbConnect(args): + try: + conn = mariadb.connect( + user=args.db_user, + password=args.db_pass, + host=args.db_host, + port=args.db_port, + database=args.db_name, + ) + except mariadb.Error as e: + print(f"Error connecting to MariaDB: {e}") + sys.exit(1) + return conn + + +def parseEnv(): + outArr = [] + outArr.append(datetime.now().strftime("%Y-%m-%d %H:%M:%S")) + outArr.append(os.getenv("COMMIT_HASH", default=None)) + outArr.append(os.getenv("COMMIT_MSG", default=None)) + outArr.append(os.getenv("BRANCH_NAME", default=None)) + outArr.append(os.getenv("BSS_SIZE", default=None)) + outArr.append(os.getenv("TEXT_SIZE", default=None)) + outArr.append(os.getenv("RODATA_SIZE", default=None)) + outArr.append(os.getenv("DATA_SIZE", default=None)) + outArr.append(os.getenv("FREE_FLASH_SIZE", default=None)) + outArr.append(os.getenv("PULL_ID", default=None)) + outArr.append(os.getenv("PULL_NAME", default=None)) + return outArr + + +def createTables(cur, conn): + headerTable = "CREATE TABLE IF NOT EXISTS `header` ( \ + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, \ + `datetime` datetime NOT NULL, \ + `commit` varchar(40) NOT NULL, \ + `commit_msg` text NOT NULL, \ + `branch_name` text NOT NULL, \ + `bss_size` int(10) unsigned NOT NULL, \ + `text_size` int(10) unsigned NOT NULL, \ + `rodata_size` int(10) unsigned NOT NULL, \ + `data_size` int(10) unsigned NOT NULL, \ + `free_flash_size` int(10) unsigned NOT NULL, \ + `pullrequest_id` int(10) unsigned DEFAULT NULL, \ + `pullrequest_name` text DEFAULT NULL, \ + PRIMARY KEY (`id`), \ + KEY `header_id_index` (`id`) )" + dataTable = "CREATE TABLE IF NOT EXISTS `data` ( \ + `header_id` int(10) unsigned NOT NULL, \ + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, \ + `section` text NOT NULL, \ + `address` text NOT NULL, \ + `size` int(10) unsigned NOT NULL, \ + `name` text NOT NULL, \ + `lib` text NOT NULL, \ + `obj_name` text NOT NULL, \ + PRIMARY KEY (`id`), \ + KEY `data_id_index` (`id`), \ + KEY `data_header_id_index` (`header_id`), \ + CONSTRAINT `data_header_id_foreign` FOREIGN KEY (`header_id`) REFERENCES `header` (`id`) )" + cur.execute(headerTable) + cur.execute(dataTable) + conn.commit() + + +def insertHeader(data, cur, conn): + query = "INSERT INTO `header` ( \ + datetime, commit, commit_msg, branch_name, bss_size, text_size, \ + rodata_size, data_size, free_flash_size, pullrequest_id, pullrequest_name) \ + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" + cur.execute(query, data) + conn.commit() + return cur.lastrowid + + +def parseFile(fileObj, headerID): + arr = [] + fileLines = fileObj.readlines() + for line in fileLines: + lineArr = [] + tempLineArr = line.split("\t") + lineArr.append(headerID) + lineArr.append(tempLineArr[0]) # section + lineArr.append(int(tempLineArr[2], 16)) # address hex + lineArr.append(int(tempLineArr[3])) # size + lineArr.append(tempLineArr[4]) # name + lineArr.append(tempLineArr[5]) # lib + lineArr.append(tempLineArr[6]) # obj_name + arr.append(tuple(lineArr)) + return arr + + +def insertData(data, cur, conn): + query = "INSERT INTO `data` ( \ + header_id, section, address, size, \ + name, lib, obj_name) \ + VALUES (?, ?, ?, ?, ? ,?, ?)" + cur.executemany(query, data) + conn.commit() + + +def main(): + args = parseArgs() + dbConn = mariadbConnect(args) + reportFile = open(args.report_file) + dbCurs = dbConn.cursor() + createTables(dbCurs, dbConn) + headerID = insertHeader(parseEnv(), dbCurs, dbConn) + insertData(parseFile(reportFile, headerID), dbCurs, dbConn) + reportFile.close() + dbCurs.close() + + +if __name__ == "__main__": + main() diff --git a/scripts/map_parser.py b/scripts/map_parser.py new file mode 100755 index 000000000000..1efc4fe82f3c --- /dev/null +++ b/scripts/map_parser.py @@ -0,0 +1,274 @@ +#!/usr/bin/env python3 + +# Requiremets: +# cxxfilt==0.3.0 + +# Most part of this code written by Lars-Dominik Braun https://github.com/PromyLOPh/linkermapviz +# and distributes under MIT licence + +# Copyright (c) 2017 Lars-Dominik Braun +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +import sys +import re +import os +from typing import TextIO +from cxxfilt import demangle + + +class Objectfile: + def __init__(self, section: str, offset: int, size: int, comment: str): + self.section = section.strip() + self.offset = offset + self.size = size + self.path = (None, None) + self.basepath = None + + if comment: + self.path = re.match(r"^(.+?)(?:\(([^\)]+)\))?$", comment).groups() + self.basepath = os.path.basename(self.path[0]) + + self.children = [] + + def __repr__(self) -> str: + return f"" + + +def update_children_size(children: list[list], subsection_size: int) -> list: + # set subsection size to an only child + if len(children) == 1: + children[0][1] = subsection_size + return children + + rest_size = subsection_size + + for index in range(1, len(children)): + if rest_size > 0: + # current size = current address - previous child address + child_size = children[index][0] - children[index - 1][0] + rest_size -= child_size + children[index - 1][1] = child_size + + # if there is rest size, set it to the last child element + if rest_size > 0: + children[-1][1] = rest_size + + return children + + +def parse_sections(file_name: str) -> list: + """ + Quick&Dirty parsing for GNU ld’s linker map output, needs LANG=C, because + some messages are localized. + """ + + sections = [] + with open(file_name, "r") as file: + # skip until memory map is found + found = False + + while True: + line = file.readline() + if not line: + break + if line.strip() == "Memory Configuration": + found = True + break + + if not found: + raise Exception(f"Memory configuration is not found in the{input_file}") + + # long section names result in a linebreak afterwards + sectionre = re.compile( + "(?P

.+?|.{14,}\n)[ ]+0x(?P[0-9a-f]+)[ ]+0x(?P[0-9a-f]+)(?:[ ]+(?P.+))?\n+", + re.I, + ) + subsectionre = re.compile( + "[ ]{16}0x(?P[0-9a-f]+)[ ]+(?P.+)\n+", re.I + ) + s = file.read() + pos = 0 + + while True: + m = sectionre.match(s, pos) + if not m: + # skip that line + try: + nextpos = s.index("\n", pos) + 1 + pos = nextpos + continue + except ValueError: + break + + pos = m.end() + section = m.group("section") + v = m.group("offset") + offset = int(v, 16) if v is not None else None + v = m.group("size") + size = int(v, 16) if v is not None else None + comment = m.group("comment") + + if section != "*default*" and size > 0: + of = Objectfile(section, offset, size, comment) + + if section.startswith(" "): + children = [] + sections[-1].children.append(of) + + while True: + m = subsectionre.match(s, pos) + if not m: + break + pos = m.end() + offset, function = m.groups() + offset = int(offset, 16) + if sections and sections[-1].children: + children.append([offset, 0, function]) + + if children: + children = update_children_size( + children=children, subsection_size=of.size + ) + + sections[-1].children[-1].children.extend(children) + + else: + sections.append(of) + + return sections + + +def get_subsection_name(section_name: str, subsection: Objectfile) -> str: + subsection_split_names = subsection.section.split(".") + if subsection.section.startswith("."): + subsection_split_names = subsection_split_names[1:] + + return ( + f".{subsection_split_names[1]}" + if len(subsection_split_names) > 2 + else section_name + ) + + +def write_subsection( + section_name: str, + subsection_name: str, + address: str, + size: int, + demangled_name: str, + module_name: str, + file_name: str, + mangled_name: str, + write_file_object: TextIO, +) -> None: + write_file_object.write( + f"{section_name}\t" + f"{subsection_name}\t" + f"{address}\t" + f"{size}\t" + f"{demangled_name}\t" + f"{module_name}\t" + f"{file_name}\t" + f"{mangled_name}\n" + ) + + +def save_subsection( + section_name: str, subsection: Objectfile, write_file_object: TextIO +) -> None: + subsection_name = get_subsection_name(section_name, subsection) + module_name = subsection.path[0] + file_name = subsection.path[1] + + if not file_name: + file_name, module_name = module_name, "" + + if not subsection.children: + address = f"{subsection.offset:x}" + size = subsection.size + mangled_name = ( + "" + if subsection.section == section_name + else subsection.section.split(".")[-1] + ) + demangled_name = demangle(mangled_name) if mangled_name else mangled_name + + write_subsection( + section_name=section_name, + subsection_name=subsection_name, + address=address, + size=size, + demangled_name=demangled_name, + module_name=module_name, + file_name=file_name, + mangled_name=mangled_name, + write_file_object=write_file_object, + ) + return + + for subsection_child in subsection.children: + address = f"{subsection_child[0]:x}" + size = subsection_child[1] + mangled_name = subsection_child[2] + demangled_name = demangle(mangled_name) + + write_subsection( + section_name=section_name, + subsection_name=subsection_name, + address=address, + size=size, + demangled_name=demangled_name, + module_name=module_name, + file_name=file_name, + mangled_name=mangled_name, + write_file_object=write_file_object, + ) + + +def save_section(section: Objectfile, write_file_object: TextIO) -> None: + section_name = section.section + for subsection in section.children: + save_subsection( + section_name=section_name, + subsection=subsection, + write_file_object=write_file_object, + ) + + +def save_parsed_data(parsed_data: list[Objectfile], output_file_name: str) -> None: + with open(output_file_name, "w") as write_file_object: + for section in parsed_data: + if section.children: + save_section(section=section, write_file_object=write_file_object) + + +if __name__ == "__main__": + if len(sys.argv) < 3: + raise Exception(f"Usage: {sys.argv[0]} ") + + input_file = sys.argv[1] + output_file = sys.argv[2] + + parsed_sections = parse_sections(input_file) + + if parsed_sections is None: + raise Exception(f"Memory configuration is not {input_file}") + + save_parsed_data(parsed_sections, output_file) diff --git a/scripts/sconsdist.py b/scripts/sconsdist.py index d2d1d2f49c95..2cf43dce02a4 100644 --- a/scripts/sconsdist.py +++ b/scripts/sconsdist.py @@ -84,17 +84,6 @@ def copy_single_project(self, project: ProjectDir) -> None: if exists(sdk_folder := join(obj_directory, foldertype)): self.note_dist_component(foldertype, "dir", sdk_folder) - # TODO: remove this after everyone migrates to new uFBT - self.create_zip_stub("lib") - - def create_zip_stub(self, foldertype): - with zipfile.ZipFile( - self.get_dist_path(self.get_dist_file_name(foldertype, "zip")), - "w", - zipfile.ZIP_DEFLATED, - ) as _: - pass - def copy(self) -> int: self._dist_components: dict[str, str] = dict() self.projects: dict[str, ProjectDir] = dict( @@ -271,7 +260,15 @@ def bundle_update_package(self): self.note_dist_component( "update", "tgz", self.get_dist_path(bundle_tgz) ) - tar.add(bundle_dir, arcname=bundle_dir_name) + + # Strip uid and gid in case of overflow + def tar_filter(tarinfo): + tarinfo.uid = tarinfo.gid = 0 + tarinfo.mtime = 0 + tarinfo.uname = tarinfo.gname = "furippa" + return tarinfo + + tar.add(bundle_dir, arcname=bundle_dir_name, filter=tar_filter) return bundle_result diff --git a/scripts/serial_cli.py b/scripts/serial_cli.py index 2fa37d7512a6..8e35d57facdd 100644 --- a/scripts/serial_cli.py +++ b/scripts/serial_cli.py @@ -1,3 +1,4 @@ +import argparse import logging import os import subprocess @@ -8,8 +9,11 @@ def main(): logger = logging.getLogger() - if not (port := resolve_port(logger, "auto")): - logger.error("Is Flipper connected over USB and is it not in DFU mode?") + parser = argparse.ArgumentParser() + parser.add_argument("-p", "--port", help="CDC Port", default="auto") + args = parser.parse_args() + if not (port := resolve_port(logger, args.port)): + logger.error("Is Flipper connected via USB and not in DFU mode?") return 1 subprocess.call( [ diff --git a/scripts/ufbt/SConstruct b/scripts/ufbt/SConstruct index 4dd1fb5b9044..8812a4e55928 100644 --- a/scripts/ufbt/SConstruct +++ b/scripts/ufbt/SConstruct @@ -75,7 +75,7 @@ from fbt.util import ( wrap_tempfile, path_as_posix, ) -from fbt.appmanifest import FlipperAppType +from fbt.appmanifest import FlipperAppType, FlipperApplication from fbt.sdk.cache import SdkCache # Base environment with all tools loaded from SDK @@ -98,6 +98,7 @@ env = core_env.Clone( "fbt_apps", "fbt_extapps", "fbt_assets", + "fbt_envhooks", ("compilation_db", {"COMPILATIONDB_COMSTR": "\tCDB\t${TARGET}"}), ], FBT_FAP_DEBUG_ELF_ROOT=ufbt_build_dir, @@ -117,6 +118,8 @@ env = core_env.Clone( wrap_tempfile(env, "LINKCOM") wrap_tempfile(env, "ARCOM") +env.PreConfigureUfbtEnvionment() + # print(env.Dump()) # Dist env @@ -339,7 +342,7 @@ else: appenv.PhonyTarget( "cli", - '${PYTHON3} "${FBT_SCRIPT_DIR}/serial_cli.py"', + '${PYTHON3} "${FBT_SCRIPT_DIR}/serial_cli.py" -p ${FLIP_PORT}', ) # Linter @@ -407,6 +410,12 @@ dist_env.Alias("vscode_dist", vscode_dist) # Creating app from base template dist_env.SetDefault(FBT_APPID=appenv.subst("$APPID") or "template") +if fbt_appid := dist_env.subst("$FBT_APPID"): + if not FlipperApplication.APP_ID_REGEX.match(fbt_appid): + raise UserError( + f"Invalid app id '{fbt_appid}'. App id must match {FlipperApplication.APP_ID_REGEX.pattern}" + ) + app_template_dir = project_template_dir.Dir("app_template") app_template_dist = [] for template_file in app_template_dir.glob("*"): @@ -460,7 +469,7 @@ if dolphin_src_dir.exists(): ) dist_env.PhonyTarget( "dolphin_ext", - '${PYTHON3} ${FBT_SCRIPT_DIR}/storage.py send "${SOURCE}" /ext/dolphin', + '${PYTHON3} ${FBT_SCRIPT_DIR}/storage.py -p ${FLIP_PORT} send "${SOURCE}" /ext/dolphin', source=ufbt_build_dir.Dir("dolphin"), ) else: @@ -474,3 +483,5 @@ dist_env.PhonyTarget( "env", "@echo $( ${FBT_SCRIPT_DIR}/toolchain/fbtenv.sh $)", ) + +dist_env.PostConfigureUfbtEnvionment() diff --git a/scripts/ufbt/commandline.scons b/scripts/ufbt/commandline.scons index a9b91bbca970..349b4ef2524b 100644 --- a/scripts/ufbt/commandline.scons +++ b/scripts/ufbt/commandline.scons @@ -71,6 +71,11 @@ vars.AddVariables( validator=PathVariable.PathIsDir, default="", ), + ( + "FLIP_PORT", + "CDC Port of Flipper to use, if multiple are connected", + "auto", + ), ) Return("vars") diff --git a/scripts/ufbt/project_template/app_template/application.fam b/scripts/ufbt/project_template/app_template/application.fam index 37a4ce665522..a2d23ef46605 100644 --- a/scripts/ufbt/project_template/app_template/application.fam +++ b/scripts/ufbt/project_template/app_template/application.fam @@ -8,7 +8,7 @@ App( stack_size=2 * 1024, fap_category="Examples", # Optional values - # fap_version=(0, 1), # (major, minor) + # fap_version="0.1", fap_icon="@FBT_APPID@.png", # 10x10 1-bit PNG # fap_description="A simple app", # fap_author="J. Doe", diff --git a/scripts/update.py b/scripts/update.py index 0f3ee6ea8b9d..9f0d95d94eea 100755 --- a/scripts/update.py +++ b/scripts/update.py @@ -211,6 +211,9 @@ def _tar_filter(self, tarinfo: tarfile.TarInfo): f"Cannot package resource: name '{tarinfo.name}' too long" ) raise ValueError("Resource name too long") + tarinfo.gid = tarinfo.uid = 0 + tarinfo.mtime = 0 + tarinfo.uname = tarinfo.gname = "furippa" return tarinfo def package_resources(self, srcdir: str, dst_name: str): diff --git a/scripts/version.py b/scripts/version.py index 3d68b2e98d41..e68f7b41d7c6 100644 --- a/scripts/version.py +++ b/scripts/version.py @@ -40,13 +40,39 @@ def get_version_info(self): except subprocess.CalledProcessError: version = "unknown" + if "SOURCE_DATE_EPOCH" in os.environ: + commit_date = datetime.utcfromtimestamp( + int(os.environ["SOURCE_DATE_EPOCH"]) + ) + else: + commit_date = datetime.strptime( + self._exec_git("log -1 --format=%cd").strip(), + "%a %b %d %H:%M:%S %Y %z", + ) + return { "GIT_COMMIT": commit, "GIT_BRANCH": branch, "VERSION": version, "BUILD_DIRTY": dirty and 1 or 0, + "GIT_ORIGIN": ",".join(self._get_git_origins()), + "GIT_COMMIT_DATE": commit_date, } + def _get_git_origins(self): + try: + remotes = self._exec_git("remote -v") + except subprocess.CalledProcessError: + return set() + origins = set() + for line in remotes.split("\n"): + if not line: + continue + _, destination = line.split("\t") + url, _ = destination.split(" ") + origins.add(url) + return origins + def _exec_git(self, args): cmd = ["git"] cmd.extend(args.split(" ")) @@ -74,24 +100,35 @@ def init(self): help="hardware target", required=True, ) + self.parser_generate.add_argument( + "-fw-origin", + dest="firmware_origin", + type=str, + help="firmware origin", + required=True, + ) self.parser_generate.add_argument("--dir", dest="sourcedir", required=True) self.parser_generate.set_defaults(func=self.generate) def generate(self): current_info = GitVersion(self.args.sourcedir).get_version_info() - if "SOURCE_DATE_EPOCH" in os.environ: - build_date = datetime.utcfromtimestamp(int(os.environ["SOURCE_DATE_EPOCH"])) - else: - build_date = date.today() + build_date = ( + date.today() + if current_info["BUILD_DIRTY"] + else current_info["GIT_COMMIT_DATE"] + ) current_info.update( { "BUILD_DATE": build_date.strftime("%d-%m-%Y"), "TARGET": self.args.target, + "FIRMWARE_ORIGIN": self.args.firmware_origin, } ) + del current_info["GIT_COMMIT_DATE"] + version_values = [] for key in current_info: val = current_info[key] diff --git a/scripts/wifi_board.py b/scripts/wifi_board.py new file mode 100755 index 000000000000..3f89ebdc6565 --- /dev/null +++ b/scripts/wifi_board.py @@ -0,0 +1,240 @@ +#!/usr/bin/env python3 + +from flipper.app import App +from serial.tools.list_ports_common import ListPortInfo + +import logging +import os +import tempfile +import subprocess +import serial.tools.list_ports as list_ports +import json +import requests +import tarfile + + +class UpdateDownloader: + UPDATE_SERVER = "https://update.flipperzero.one" + UPDATE_PROJECT = "/blackmagic-firmware" + UPDATE_INDEX = UPDATE_SERVER + UPDATE_PROJECT + "/directory.json" + UPDATE_TYPE = "full_tgz" + + CHANNEL_ID_ALIAS = { + "dev": "development", + "rc": "release-candidate", + "r": "release", + "rel": "release", + } + + def __init__(self): + self.logger = logging.getLogger() + + def download(self, channel_id: str, dir: str) -> bool: + # Aliases + if channel_id in self.CHANNEL_ID_ALIAS: + channel_id = self.CHANNEL_ID_ALIAS[channel_id] + + # Make directory + if not os.path.exists(dir): + self.logger.info(f"Creating directory {dir}") + os.makedirs(dir) + + # Download json index + self.logger.info(f"Downloading {self.UPDATE_INDEX}") + response = requests.get(self.UPDATE_INDEX) + if response.status_code != 200: + self.logger.error(f"Failed to download {self.UPDATE_INDEX}") + return False + + # Parse json index + try: + index = json.loads(response.content) + except Exception as e: + self.logger.error(f"Failed to parse json index: {e}") + return False + + # Find channel + channel = None + for channel_candidate in index["channels"]: + if channel_candidate["id"] == channel_id: + channel = channel_candidate + break + + # Check if channel found + if channel is None: + self.logger.error( + f"Channel '{channel_id}' not found. Valid channels: {', '.join([c['id'] for c in index['channels']])}" + ) + return False + + self.logger.info(f"Using channel '{channel_id}'") + + # Get latest version + try: + version = channel["versions"][0] + except Exception as e: + self.logger.error(f"Failed to get version: {e}") + return False + + self.logger.info(f"Using version '{version['version']}'") + + # Get changelog + changelog = None + try: + changelog = version["changelog"] + except Exception as e: + self.logger.error(f"Failed to get changelog: {e}") + + # print changelog + if changelog is not None: + self.logger.info(f"Changelog:") + for line in changelog.split("\n"): + if line.strip() == "": + continue + self.logger.info(f" {line}") + + # Find file + file_url = None + for file_candidate in version["files"]: + if file_candidate["type"] == self.UPDATE_TYPE: + file_url = file_candidate["url"] + break + + if file_url is None: + self.logger.error(f"File not found") + return False + + # Make file path + file_name = file_url.split("/")[-1] + file_path = os.path.join(dir, file_name) + + # Download file + self.logger.info(f"Downloading {file_url} to {file_path}") + with open(file_path, "wb") as f: + response = requests.get(file_url) + f.write(response.content) + + # Unzip tgz + self.logger.info(f"Unzipping {file_path}") + with tarfile.open(file_path, "r") as tar: + tar.extractall(dir) + + return True + + +class Main(App): + def init(self): + self.parser.add_argument("-p", "--port", help="CDC Port", default="auto") + self.parser.add_argument( + "-c", "--channel", help="Channel name", default="release" + ) + self.parser.set_defaults(func=self.update) + + # logging + self.logger = logging.getLogger() + + def find_wifi_board(self) -> bool: + # idk why, but python thinks that list_ports.grep returns tuple[str, str, str] + blackmagics: list[ListPortInfo] = list(list_ports.grep("blackmagic")) # type: ignore + daps: list[ListPortInfo] = list(list_ports.grep("CMSIS-DAP")) # type: ignore + + return len(blackmagics) > 0 or len(daps) > 0 + + def find_wifi_board_bootloader(self): + # idk why, but python thinks that list_ports.grep returns tuple[str, str, str] + ports: list[ListPortInfo] = list(list_ports.grep("ESP32-S2")) # type: ignore + + if len(ports) == 0: + # Blackmagic probe serial port not found, will be handled later + pass + elif len(ports) > 1: + raise Exception("More than one WiFi board found") + else: + port = ports[0] + if os.name == "nt": + port.device = f"\\\\.\\{port.device}" + return port.device + + def update(self): + try: + port = self.find_wifi_board_bootloader() + except Exception as e: + self.logger.error(f"{e}") + return 1 + + if self.args.port != "auto": + port = self.args.port + + available_ports = [p[0] for p in list(list_ports.comports())] + if port not in available_ports: + self.logger.error(f"Port {port} not found") + return 1 + + if port is None: + if self.find_wifi_board(): + self.logger.error("WiFi board found, but not in bootloader mode.") + self.logger.info("Please hold down BOOT button and press RESET button") + else: + self.logger.error("WiFi board not found") + self.logger.info( + "Please connect WiFi board to your computer, hold down BOOT button and press RESET button" + ) + return 1 + + # get temporary dir + with tempfile.TemporaryDirectory() as temp_dir: + downloader = UpdateDownloader() + + # download latest channel update + try: + if not downloader.download(self.args.channel, temp_dir): + self.logger.error(f"Cannot download update") + return 1 + except Exception as e: + self.logger.error(f"Cannot download update: {e}") + return 1 + + with open(os.path.join(temp_dir, "flash.command"), "r") as f: + flash_command = f.read() + + flash_command = flash_command.replace("\n", "").replace("\r", "") + flash_command = flash_command.replace("(PORT)", port) + + # We can't reset the board after flashing via usb + flash_command = flash_command.replace( + "--after hard_reset", "--after no_reset_stub" + ) + + args = flash_command.split(" ")[0:] + args = list(filter(None, args)) + + esptool_params = [] + esptool_params.extend(args) + + self.logger.info(f'Running command: "{" ".join(args)}" in "{temp_dir}"') + + process = subprocess.Popen( + esptool_params, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + cwd=temp_dir, + bufsize=1, + universal_newlines=True, + ) + + while process.poll() is None: + if process.stdout is not None: + for line in process.stdout: + self.logger.debug(f"{line.strip()}") + + if process.returncode != 0: + self.logger.error(f"Failed to flash WiFi board") + else: + self.logger.info("WiFi board flashed successfully") + self.logger.info("Press RESET button on WiFi board to start it") + + return process.returncode + + +if __name__ == "__main__": + Main()() diff --git a/site_scons/commandline.scons b/site_scons/commandline.scons index 2e9486627388..b70b5cff56f1 100644 --- a/site_scons/commandline.scons +++ b/site_scons/commandline.scons @@ -236,6 +236,18 @@ vars.AddVariables( help="Don't open browser after generating error repots", default=False, ), + ( + "FIRMWARE_ORIGIN", + "Firmware origin. 'Official' if follows upstream's API structure, otherwise fork name. " + " This will also create a C define FW_ORIGIN_ so that " + " app can check what version it is being built for.", + "Official", + ), + ( + "FLIP_PORT", + "Full port name of Flipper to use, if multiple Flippers are connected", + "auto", + ), ) Return("vars") From fc46026e5931f5669b959895232e7b50e8684612 Mon Sep 17 00:00:00 2001 From: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Date: Mon, 26 Jun 2023 12:30:30 +0300 Subject: [PATCH 110/149] Gsurkov/mf desfire iter5 (#2802) * Improve types * Add common read_success scene * Remove mf_desfire_read_success scene * common info scene * Use common read success scene for MfUltralight * Use common read success scene for MfClassic * Remove unneeded scenes * Use common read success scene for ISO14443-3A (NFCA) * Fix compilation issues caused by merge * Use common Info scene * Improve common read scene * Sync submodules * Cleanup dead-end code * Implement common read scene * Remove unneeded scenes * nfc app: reset detected protocols on detect scene start --------- Co-authored-by: gornekich --- .../helpers/format/nfc_mf_desfire_format.c | 5 +- .../helpers/format/nfc_mf_desfire_format.h | 2 +- .../nfc/helpers/format/nfc_protocol_format.c | 110 +++++++++------- .../nfc/helpers/format/nfc_protocol_format.h | 7 +- .../nfc/helpers/handlers/nfc_poller_handler.c | 118 ++++++++++++++++++ .../nfc/helpers/handlers/nfc_poller_handler.h | 7 ++ .../main/nfc/helpers/nfc_custom_event.h | 9 +- .../main/nfc/scenes/nfc_scene_config.h | 15 +-- .../main/nfc/scenes/nfc_scene_detect.c | 16 +-- applications/main/nfc/scenes/nfc_scene_info.c | 27 ++-- .../scenes/nfc_scene_mf_classic_dict_attack.c | 2 +- .../nfc/scenes/nfc_scene_mf_classic_menu.c | 2 +- .../nfc_scene_mf_classic_read_success.c | 81 ------------ ...nfc_scene_mf_classic_read_supported_card.c | 2 +- .../nfc/scenes/nfc_scene_mf_desfire_app.c | 3 +- .../nfc/scenes/nfc_scene_mf_desfire_data.c | 6 +- .../nfc/scenes/nfc_scene_mf_desfire_read.c | 69 ---------- .../nfc_scene_mf_desfire_read_success.c | 97 -------------- .../nfc/scenes/nfc_scene_mf_ultralight_menu.c | 2 +- .../nfc/scenes/nfc_scene_mf_ultralight_read.c | 93 -------------- .../nfc_scene_mf_ultralight_read_success.c | 83 ------------ .../nfc_scene_mf_ultralight_unlock_warn.c | 5 +- .../main/nfc/scenes/nfc_scene_nfca_menu.c | 2 +- .../main/nfc/scenes/nfc_scene_nfca_read.c | 66 ---------- .../nfc/scenes/nfc_scene_nfca_read_success.c | 73 ----------- applications/main/nfc/scenes/nfc_scene_read.c | 68 ++++++++++ .../main/nfc/scenes/nfc_scene_read_success.c | 70 +++++++++++ .../main/nfc/scenes/nfc_scene_retry_confirm.c | 11 +- .../nfc/scenes/nfc_scene_select_protocol.c | 12 +- lib/nfc/deprecated/nfc_worker_i.h | 1 - lib/nfc/protocols/mf_desfire/mf_desfire.h | 4 +- lib/nfc/protocols/mf_desfire/mf_desfire_i.c | 2 +- lib/nfc/protocols/mf_desfire/mf_desfire_i.h | 2 +- .../mf_desfire/mf_desfire_poller_i.c | 5 +- .../mf_desfire/mf_desfire_poller_i.h | 2 +- 35 files changed, 397 insertions(+), 682 deletions(-) create mode 100644 applications/main/nfc/helpers/handlers/nfc_poller_handler.c create mode 100644 applications/main/nfc/helpers/handlers/nfc_poller_handler.h delete mode 100644 applications/main/nfc/scenes/nfc_scene_mf_classic_read_success.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_mf_desfire_read.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_mf_desfire_read_success.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_mf_ultralight_read.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_success.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_nfca_read.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_nfca_read_success.c create mode 100644 applications/main/nfc/scenes/nfc_scene_read.c create mode 100644 applications/main/nfc/scenes/nfc_scene_read_success.c diff --git a/applications/main/nfc/helpers/format/nfc_mf_desfire_format.c b/applications/main/nfc/helpers/format/nfc_mf_desfire_format.c index 9ecbeac85b60..da1c0607c2ed 100644 --- a/applications/main/nfc/helpers/format/nfc_mf_desfire_format.c +++ b/applications/main/nfc/helpers/format/nfc_mf_desfire_format.c @@ -85,8 +85,9 @@ void nfc_mf_desfire_format_key_version( furi_string_cat_printf(str, "key %lu version %u\n", index, *data); } -void nfc_mf_desfire_format_application_id(const MfDesfireApplicationId data, FuriString* str) { - furi_string_cat_printf(str, "Application %02x%02x%02x\n", data[0], data[1], data[2]); +void nfc_mf_desfire_format_application_id(const MfDesfireApplicationId* data, FuriString* str) { + const uint8_t* app_id = data->data; + furi_string_cat_printf(str, "Application %02x%02x%02x\n", app_id[0], app_id[1], app_id[2]); } void nfc_mf_desfire_format_application(const MfDesfireApplication* data, FuriString* str) { diff --git a/applications/main/nfc/helpers/format/nfc_mf_desfire_format.h b/applications/main/nfc/helpers/format/nfc_mf_desfire_format.h index 0ac98cdb6fa9..85f137fb6b68 100644 --- a/applications/main/nfc/helpers/format/nfc_mf_desfire_format.h +++ b/applications/main/nfc/helpers/format/nfc_mf_desfire_format.h @@ -15,7 +15,7 @@ void nfc_mf_desfire_format_key_version( uint32_t index, FuriString* str); -void nfc_mf_desfire_format_application_id(const MfDesfireApplicationId data, FuriString* str); +void nfc_mf_desfire_format_application_id(const MfDesfireApplicationId* data, FuriString* str); void nfc_mf_desfire_format_application(const MfDesfireApplication* data, FuriString* str); diff --git a/applications/main/nfc/helpers/format/nfc_protocol_format.c b/applications/main/nfc/helpers/format/nfc_protocol_format.c index 403b081cc1cd..bf5e16ad0768 100644 --- a/applications/main/nfc/helpers/format/nfc_protocol_format.c +++ b/applications/main/nfc/helpers/format/nfc_protocol_format.c @@ -5,68 +5,94 @@ #include #include -typedef void (*NfcProtocolFormatRenderInfo)(const NfcDev* device, FuriString* str); +typedef void (*NfcProtocolFormatRenderInfo)( + const NfcDev* device, + NfcProtocolFormatType type, + FuriString* str); typedef struct { NfcProtocolFormatRenderInfo render_info; const NfcProtocolFormatFeature flags; } NfcProtocolFormatBase; -static void - nfc_protocol_format_common_iso14443_3a_render_info(const NfcaData* nfc_data, FuriString* str) { - const char iso_type = FURI_BIT(nfc_data->sak, 5) ? '4' : '3'; +static void nfc_protocol_format_info_iso14443_3a_common( + const NfcaData* nfc_data, + NfcProtocolFormatType type, + FuriString* str) { + if(type == NfcProtocolFormatTypeFull) { + const char iso_type = FURI_BIT(nfc_data->sak, 5) ? '4' : '3'; + furi_string_cat_printf(str, "ISO 14443-%c (NFC-A)\n", iso_type); + } - furi_string_cat_printf(str, "ISO 14443-%c (NFC-A)\n", iso_type); furi_string_cat_printf(str, "UID:"); for(size_t i = 0; i < nfc_data->uid_len; i++) { furi_string_cat_printf(str, " %02X", nfc_data->uid[i]); } - furi_string_cat_printf(str, "\nATQA: %02X %02X ", nfc_data->atqa[1], nfc_data->atqa[0]); - furi_string_cat_printf(str, " SAK: %02X", nfc_data->sak); + if(type == NfcProtocolFormatTypeFull) { + furi_string_cat_printf(str, "\nATQA: %02X %02X ", nfc_data->atqa[1], nfc_data->atqa[0]); + furi_string_cat_printf(str, " SAK: %02X", nfc_data->sak); + } } -static void nfc_protocol_format_iso14443_3a_render_info(const NfcDev* device, FuriString* str) { - furi_string_cat_printf( - str, "\e#%s\n", nfc_dev_get_device_name(device, NfcProtocolNameTypeFull)); - +static void nfc_protocol_format_info_iso14443_3a( + const NfcDev* device, + NfcProtocolFormatType type, + FuriString* str) { + UNUSED(type); const NfcaData* data = nfc_dev_get_protocol_data(device, NfcProtocolTypeIso14443_3a); - nfc_protocol_format_common_iso14443_3a_render_info(data, str); + nfc_protocol_format_info_iso14443_3a_common(data, NfcProtocolFormatTypeFull, str); } -static void nfc_protocol_format_iso14443_4a_render_info(const NfcDev* device, FuriString* str) { - furi_string_cat_printf( - str, "\e#%s\n", nfc_dev_get_device_name(device, NfcProtocolNameTypeFull)); - +static void nfc_protocol_format_info_iso14443_4a( + const NfcDev* device, + NfcProtocolFormatType type, + FuriString* str) { + UNUSED(type); const Iso14443_4aData* data = nfc_dev_get_protocol_data(device, NfcProtocolTypeIso14443_4a); - nfc_protocol_format_common_iso14443_3a_render_info(data->iso14443_3a_data, str); + nfc_protocol_format_info_iso14443_3a_common( + data->iso14443_3a_data, NfcProtocolFormatTypeFull, str); } -static void nfc_protocol_format_mf_ultralight_render_info(const NfcDev* device, FuriString* str) { - furi_string_cat_printf( - str, "\e#%s\n", nfc_dev_get_device_name(device, NfcProtocolNameTypeFull)); - +static void nfc_protocol_format_info_mf_ultralight( + const NfcDev* device, + NfcProtocolFormatType type, + FuriString* str) { const MfUltralightData* data = nfc_dev_get_protocol_data(device, NfcProtocolTypeMfUltralight); - nfc_protocol_format_common_iso14443_3a_render_info(data->nfca_data, str); -} + nfc_protocol_format_info_iso14443_3a_common(data->nfca_data, type, str); -static void nfc_protocol_format_mf_classic_render_info(const NfcDev* device, FuriString* str) { - furi_string_cat_printf( - str, "\e#%s\n", nfc_dev_get_device_name(device, NfcProtocolNameTypeFull)); + furi_string_cat_printf(str, "\nPages Read: %u/%u", data->pages_read, data->pages_total); + if(data->pages_read != data->pages_total) { + furi_string_cat_printf(str, "\nPassword-protected pages!"); + } +} +static void nfc_protocol_format_info_mf_classic( + const NfcDev* device, + NfcProtocolFormatType type, + FuriString* str) { const MfClassicData* data = nfc_dev_get_protocol_data(device, NfcProtocolTypeMfClassic); - nfc_protocol_format_common_iso14443_3a_render_info(data->nfca_data, str); + nfc_protocol_format_info_iso14443_3a_common(data->nfca_data, type, str); + + uint8_t sectors_total = mf_classic_get_total_sectors_num(data->type); + uint8_t keys_total = sectors_total * 2; + uint8_t keys_found = 0; + uint8_t sectors_read = 0; + mf_classic_get_read_sectors_and_keys(data, §ors_read, &keys_found); + + furi_string_cat_printf(str, "\nKeys Found: %u/%u", keys_found, keys_total); + furi_string_cat_printf(str, "\nSectors Read: %u/%u", sectors_read, sectors_total); } // TODO: use proper type getters -static void nfc_protocol_format_mf_desfire_render_info(const NfcDev* device, FuriString* str) { - furi_string_cat_printf( - str, "\e#%s\n", nfc_dev_get_device_name(device, NfcProtocolNameTypeFull)); - +static void nfc_protocol_format_info_mf_desfire( + const NfcDev* device, + NfcProtocolFormatType type, + FuriString* str) { const MfDesfireData* data = nfc_dev_get_protocol_data(device, NfcProtocolTypeMfDesfire); - nfc_protocol_format_common_iso14443_3a_render_info( - data->iso14443_4a_data->iso14443_3a_data, str); + nfc_protocol_format_info_iso14443_3a_common( + data->iso14443_4a_data->iso14443_3a_data, type, str); const uint32_t bytes_total = 1UL << (data->version.sw_storage >> 1); const uint32_t bytes_free = data->free_memory.is_present ? data->free_memory.bytes_free : 0; @@ -95,36 +121,36 @@ static const NfcProtocolFormatBase nfc_protocol_format[NfcProtocolTypeMax] = { [NfcProtocolTypeIso14443_3a] = { .flags = NfcProtocolFormatFeatureNone, - .render_info = nfc_protocol_format_iso14443_3a_render_info, + .render_info = nfc_protocol_format_info_iso14443_3a, }, [NfcProtocolTypeIso14443_4a] = { .flags = NfcProtocolFormatFeatureNone, - .render_info = nfc_protocol_format_iso14443_4a_render_info, + .render_info = nfc_protocol_format_info_iso14443_4a, }, [NfcProtocolTypeMfUltralight] = { .flags = NfcProtocolFormatFeatureMoreData, - .render_info = nfc_protocol_format_mf_ultralight_render_info, + .render_info = nfc_protocol_format_info_mf_ultralight, }, [NfcProtocolTypeMfClassic] = { .flags = NfcProtocolFormatFeatureMoreData, - .render_info = nfc_protocol_format_mf_classic_render_info, + .render_info = nfc_protocol_format_info_mf_classic, }, [NfcProtocolTypeMfDesfire] = { .flags = NfcProtocolFormatFeatureMoreData, - .render_info = nfc_protocol_format_mf_desfire_render_info, + .render_info = nfc_protocol_format_info_mf_desfire, }, }; NfcProtocolFormatFeature nfc_protocol_format_get_features(const NfcDev* device) { - furi_assert(device); return nfc_protocol_format[nfc_dev_get_protocol_type(device)].flags; } -void nfc_protocol_format_render_info(const NfcDev* device, FuriString* str) { - furi_assert(device); - nfc_protocol_format[nfc_dev_get_protocol_type(device)].render_info(device, str); +void nfc_protocol_format_info(const NfcDev* device, NfcProtocolFormatType type, FuriString* str) { + furi_string_cat_printf( + str, "\e#%s\n", nfc_dev_get_device_name(device, NfcProtocolNameTypeFull)); + nfc_protocol_format[nfc_dev_get_protocol_type(device)].render_info(device, type, str); } diff --git a/applications/main/nfc/helpers/format/nfc_protocol_format.h b/applications/main/nfc/helpers/format/nfc_protocol_format.h index 7c11bdab50bf..284e18e98c2f 100644 --- a/applications/main/nfc/helpers/format/nfc_protocol_format.h +++ b/applications/main/nfc/helpers/format/nfc_protocol_format.h @@ -7,6 +7,11 @@ typedef enum { NfcProtocolFormatFeatureMoreData = 1UL << 0, } NfcProtocolFormatFeature; +typedef enum { + NfcProtocolFormatTypeShort, + NfcProtocolFormatTypeFull, +} NfcProtocolFormatType; + NfcProtocolFormatFeature nfc_protocol_format_get_features(const NfcDev* device); -void nfc_protocol_format_render_info(const NfcDev* device, FuriString* str); +void nfc_protocol_format_info(const NfcDev* device, NfcProtocolFormatType type, FuriString* str); diff --git a/applications/main/nfc/helpers/handlers/nfc_poller_handler.c b/applications/main/nfc/helpers/handlers/nfc_poller_handler.c new file mode 100644 index 000000000000..54d4e61a3321 --- /dev/null +++ b/applications/main/nfc/helpers/handlers/nfc_poller_handler.c @@ -0,0 +1,118 @@ +#include "nfc_poller_handler.h" + +#include "../../nfc_app_i.h" + +typedef NfcCustomEvent ( + *NfcPollerReadHandler)(NfcaPoller* poller, NfcaPollerEvent* event, NfcApp* nfc_app); + +static NfcCustomEvent nfc_poller_handler_read_iso14443_3a( + NfcaPoller* poller, + NfcaPollerEvent* event, + NfcApp* nfc_app) { + NfcCustomEvent custom_event = NfcCustomEventReadHandlerIgnore; + + if(event->type == NfcaPollerEventTypeReady) { + nfc_dev_set_protocol_data( + nfc_app->nfc_dev, NfcProtocolTypeIso14443_3a, nfca_poller_get_data(poller)); + custom_event = NfcCustomEventReadHandlerSuccess; + } + + return custom_event; +} + +static NfcCustomEvent nfc_poller_handler_read_iso14443_4a( + Iso14443_4aPoller* poller, + Iso14443_4aPollerEvent* event, + NfcApp* nfc_app) { + NfcCustomEvent custom_event = NfcCustomEventReadHandlerIgnore; + + if(event->type == Iso14443_4aPollerEventTypeReady) { + nfc_dev_set_protocol_data( + nfc_app->nfc_dev, NfcProtocolTypeIso14443_4a, iso14443_4a_poller_get_data(poller)); + custom_event = NfcCustomEventReadHandlerSuccess; + } + + return custom_event; +} + +static NfcCustomEvent nfc_poller_handler_read_mf_ultralight( + MfUltralightPoller* poller, + MfUltralightPollerEvent* event, + NfcApp* nfc_app) { + NfcCustomEvent custom_event = NfcCustomEventReadHandlerIgnore; + + if(event->type == MfUltralightPollerEventTypeReadSuccess) { + nfc_dev_set_protocol_data( + nfc_app->nfc_dev, NfcProtocolTypeMfUltralight, mf_ultralight_poller_get_data(poller)); + custom_event = NfcCustomEventReadHandlerSuccess; + } else if(event->type == MfUltralightPollerEventTypeAuthRequest) { + nfc_dev_set_protocol_data( + nfc_app->nfc_dev, NfcProtocolTypeMfUltralight, mf_ultralight_poller_get_data(poller)); + const MfUltralightData* data = + nfc_dev_get_protocol_data(nfc_app->nfc_dev, NfcProtocolTypeMfUltralight); + if(nfc_app->mf_ul_auth->type == MfUltralightAuthTypeXiaomii) { + if(mf_ultralight_generate_xiaomi_pass( + nfc_app->mf_ul_auth, data->nfca_data->uid, data->nfca_data->uid_len)) { + event->data->auth_context.skip_auth = false; + } + } else if(nfc_app->mf_ul_auth->type == MfUltralightAuthTypeAmiibo) { + if(mf_ultralight_generate_amiibo_pass( + nfc_app->mf_ul_auth, data->nfca_data->uid, data->nfca_data->uid_len)) { + event->data->auth_context.skip_auth = false; + } + } else if(nfc_app->mf_ul_auth->type == MfUltralightAuthTypeManual) { + event->data->auth_context.skip_auth = false; + } else { + event->data->auth_context.skip_auth = true; + } + if(!event->data->auth_context.skip_auth) { + event->data->auth_context.password = nfc_app->mf_ul_auth->password; + } + } else if(event->type == MfUltralightPollerEventTypeAuthSuccess) { + nfc_app->mf_ul_auth->pack = event->data->auth_context.pack; + } + + return custom_event; +} + +static NfcCustomEvent nfc_poller_handler_read_mf_classic( + MfClassicPoller* poller, + MfClassicPollerEvent* event, + NfcApp* nfc_app) { + UNUSED(poller); + UNUSED(event); + UNUSED(nfc_app); + + NfcCustomEvent custom_event = NfcCustomEventReadHandlerIgnore; + // TODO: Implement read mf_classic using key cache + return custom_event; +} + +static NfcCustomEvent nfc_poller_handler_read_mf_desfire( + MfDesfirePoller* poller, + MfDesfirePollerEvent* event, + NfcApp* nfc_app) { + NfcCustomEvent custom_event = NfcCustomEventReadHandlerIgnore; + + if(event->type == MfDesfirePollerEventTypeReadSuccess) { + nfc_dev_set_protocol_data( + nfc_app->nfc_dev, NfcProtocolTypeMfDesfire, mf_desfire_poller_get_data(poller)); + custom_event = NfcCustomEventReadHandlerSuccess; + } + + return custom_event; +} + +static const NfcPollerReadHandler nfc_poller_handlers_read[] = { + [NfcProtocolTypeIso14443_3a] = (NfcPollerReadHandler)nfc_poller_handler_read_iso14443_3a, + [NfcProtocolTypeIso14443_4a] = (NfcPollerReadHandler)nfc_poller_handler_read_iso14443_4a, + [NfcProtocolTypeMfUltralight] = (NfcPollerReadHandler)nfc_poller_handler_read_mf_ultralight, + [NfcProtocolTypeMfClassic] = (NfcPollerReadHandler)nfc_poller_handler_read_mf_classic, + [NfcProtocolTypeMfDesfire] = (NfcPollerReadHandler)nfc_poller_handler_read_mf_desfire, +}; + +NfcCustomEvent nfc_poller_handler_read(NfcPollerEvent event, void* context) { + furi_assert(event.protocol_type < COUNT_OF(nfc_poller_handlers_read)); + + return nfc_poller_handlers_read[event.protocol_type](event.poller, event.data, context); +} diff --git a/applications/main/nfc/helpers/handlers/nfc_poller_handler.h b/applications/main/nfc/helpers/handlers/nfc_poller_handler.h new file mode 100644 index 000000000000..14fdaeb436a9 --- /dev/null +++ b/applications/main/nfc/helpers/handlers/nfc_poller_handler.h @@ -0,0 +1,7 @@ +#pragma once + +#include + +#include "../nfc_custom_event.h" + +NfcCustomEvent nfc_poller_handler_read(NfcPollerEvent event, void* context); diff --git a/applications/main/nfc/helpers/nfc_custom_event.h b/applications/main/nfc/helpers/nfc_custom_event.h index 78b204222a44..520679effd65 100644 --- a/applications/main/nfc/helpers/nfc_custom_event.h +++ b/applications/main/nfc/helpers/nfc_custom_event.h @@ -1,6 +1,6 @@ #pragma once -enum NfcCustomEvent { +typedef enum { // Reserve first 100 events for button types and indexes, starting from 0 NfcCustomEventReserved = 100, @@ -25,4 +25,9 @@ enum NfcCustomEvent { NfcCustomEventDictAttackDone, NfcCustomEventRpcLoad, NfcCustomEventRpcSessionClose, -}; + + NfcCustomEventReadHandlerIgnore, + NfcCustomEventReadHandlerSuccess, + NfcCustomEventReadHandlerFailure, + NfcCustomEventReadHandlerAltRead, +} NfcCustomEvent; diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index e521056216b2..3fc95f962c6b 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -7,34 +7,31 @@ ADD_SCENE(nfc, delete, Delete) ADD_SCENE(nfc, delete_success, DeleteSuccess) ADD_SCENE(nfc, detect, Detect) +ADD_SCENE(nfc, read, Read) ADD_SCENE(nfc, info, Info) ADD_SCENE(nfc, select_protocol, SelectProtocol) -ADD_SCENE(nfc, nfca_read, NfcaRead) -ADD_SCENE(nfc, nfca_emulate, NfcaEmulate) -ADD_SCENE(nfc, nfca_read_success, NfcaReadSuccess) -ADD_SCENE(nfc, nfca_menu, NfcaMenu) ADD_SCENE(nfc, extra_actions, ExtraActions) +ADD_SCENE(nfc, read_success, ReadSuccess) ADD_SCENE(nfc, debug, Debug) ADD_SCENE(nfc, retry_confirm, RetryConfirm) ADD_SCENE(nfc, exit_confirm, ExitConfirm) -ADD_SCENE(nfc, mf_ultralight_read, MfUltralightRead) -ADD_SCENE(nfc, mf_ultralight_read_success, MfUltralightReadSuccess) +ADD_SCENE(nfc, nfca_emulate, NfcaEmulate) +ADD_SCENE(nfc, nfca_menu, NfcaMenu) + ADD_SCENE(nfc, mf_ultralight_emulate, MfUltralightEmulate) ADD_SCENE(nfc, mf_ultralight_menu, MfUltralightMenu) ADD_SCENE(nfc, mf_ultralight_unlock_menu, MfUltralightUnlockMenu) ADD_SCENE(nfc, mf_ultralight_unlock_warn, MfUltralightUnlockWarn) ADD_SCENE(nfc, mf_ultralight_key_input, MfUltralightKeyInput) ADD_SCENE(nfc, mf_ultralight_capture_pass, MfUltralightCapturePass) -ADD_SCENE(nfc, mf_desfire_read, MfDesfireRead) -ADD_SCENE(nfc, mf_desfire_read_success, MfDesfireReadSuccess) + ADD_SCENE(nfc, mf_desfire_menu, MfDesfireMenu) ADD_SCENE(nfc, mf_desfire_data, MfDesfireData) ADD_SCENE(nfc, mf_desfire_app, MfDesfireApp) ADD_SCENE(nfc, mf_classic_read_supported_card, MfClassicReadSupportedCard) ADD_SCENE(nfc, mf_classic_dict_attack, MfClassicDictAttack) -ADD_SCENE(nfc, mf_classic_read_success, MfClassicReadSuccess) ADD_SCENE(nfc, mf_classic_menu, MfClassicMenu) ADD_SCENE(nfc, set_type, SetType) diff --git a/applications/main/nfc/scenes/nfc_scene_detect.c b/applications/main/nfc/scenes/nfc_scene_detect.c index 9855f71ca55f..db6d47b347b5 100644 --- a/applications/main/nfc/scenes/nfc_scene_detect.c +++ b/applications/main/nfc/scenes/nfc_scene_detect.c @@ -23,6 +23,10 @@ void nfc_scene_detect_on_enter(void* context) { popup_set_icon(instance->popup, 0, 8, &I_NFC_manual_60x50); view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup); + // Clear detected protocols + instance->protocols_detected_num = 0; + instance->protocols_detected_idx = 0; + nfc_scanner_start(instance->scanner, nfc_scene_detect_scan_callback, instance); nfc_blink_detect_start(instance); @@ -37,18 +41,8 @@ bool nfc_scene_detect_on_event(void* context, SceneManagerEvent event) { if(instance->protocols_detected_num > 1) { scene_manager_next_scene(instance->scene_manager, NfcSceneSelectProtocol); } else { - // TODO rework with generic read scene - const uint32_t nfc_read_scenes[NfcProtocolTypeMax] = { - NfcSceneNfcaRead, - NfcSceneNfcaRead, - NfcSceneMfUltralightRead, - NfcSceneMfClassicDictAttack, - NfcSceneMfDesfireRead, - }; instance->protocols_detected_idx = 0; - scene_manager_next_scene( - instance->scene_manager, - nfc_read_scenes[instance->protocols_detected[instance->protocols_detected_idx]]); + scene_manager_next_scene(instance->scene_manager, NfcSceneRead); } consumed = true; } diff --git a/applications/main/nfc/scenes/nfc_scene_info.c b/applications/main/nfc/scenes/nfc_scene_info.c index 6ca3e9791755..d460093e907f 100644 --- a/applications/main/nfc/scenes/nfc_scene_info.c +++ b/applications/main/nfc/scenes/nfc_scene_info.c @@ -26,7 +26,7 @@ void nfc_scene_info_on_enter(void* context) { FuriString* temp_str; temp_str = furi_string_alloc(); - nfc_protocol_format_render_info(nfc->nfc_dev, temp_str); + nfc_protocol_format_info(nfc->nfc_dev, NfcProtocolFormatTypeFull, temp_str); widget_add_text_scroll_element( widget, 0, 0, 128, text_scroll_height, furi_string_get_cstr(temp_str)); @@ -35,25 +35,24 @@ void nfc_scene_info_on_enter(void* context) { view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); } +static const NfcScene nfc_scene_info_data_scenes[NfcProtocolTypeMax] = { + [NfcProtocolTypeIso14443_3a] = NfcSceneNotImplemented, + [NfcProtocolTypeIso14443_4a] = NfcSceneNotImplemented, + [NfcProtocolTypeMfUltralight] = NfcSceneNotImplemented, + [NfcProtocolTypeMfClassic] = NfcSceneNotImplemented, + [NfcProtocolTypeMfDesfire] = NfcSceneMfDesfireData, +}; + bool nfc_scene_info_on_event(void* context, SceneManagerEvent event) { NfcApp* nfc = context; - NfcProtocolType protocol_type = nfc_dev_get_protocol_type(nfc->nfc_dev); - bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { if(event.event == GuiButtonTypeRight) { - // TODO: Do not if the protocol type directly - if(protocol_type == NfcProtocolTypeMfDesfire) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireData); - consumed = true; - } else if(protocol_type == NfcProtocolTypeMfUltralight) { - // scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightData); - consumed = true; - } else if(protocol_type == NfcProtocolTypeMfClassic) { - // scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicData); - consumed = true; - } + const NfcProtocolType protocol_type = nfc_dev_get_protocol_type(nfc->nfc_dev); + const NfcScene menu_scene = nfc_scene_info_data_scenes[protocol_type]; + scene_manager_next_scene(nfc->scene_manager, menu_scene); + consumed = true; } } diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c index e8ff22568c05..00276f2af559 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c @@ -143,7 +143,7 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent consumed = true; } else { notification_message(nfc->notifications, &sequence_success); - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSuccess); + scene_manager_next_scene(nfc->scene_manager, NfcSceneReadSuccess); dolphin_deed(DolphinDeedNfcReadSuccess); consumed = true; } diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_menu.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_menu.c index 99264824e914..5254ace99f4e 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_menu.c @@ -64,7 +64,7 @@ bool nfc_scene_mf_classic_menu_on_event(void* context, SceneManagerEvent event) dolphin_deed(DolphinDeedNfcDetectReader); consumed = true; } else if(event.event == SubmenuIndexInfo) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + scene_manager_next_scene(nfc->scene_manager, NfcSceneInfo); consumed = true; } } else if(event.type == SceneManagerEventTypeBack) { diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_read_success.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_read_success.c deleted file mode 100644 index d9cdb6a93252..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_read_success.c +++ /dev/null @@ -1,81 +0,0 @@ -#include "../nfc_app_i.h" - -void nfc_scene_mf_classic_read_success_widget_callback( - GuiButtonType result, - InputType type, - void* context) { - furi_assert(context); - NfcApp* nfc = context; - - if(type == InputTypeShort) { - view_dispatcher_send_custom_event(nfc->view_dispatcher, result); - } -} - -void nfc_scene_mf_classic_read_success_on_enter(void* context) { - NfcApp* nfc = context; - const MfClassicData* mfc_data = - nfc_dev_get_protocol_data(nfc->nfc_dev, NfcProtocolTypeMfClassic); - - // Setup view - Widget* widget = nfc->widget; - widget_add_button_element( - widget, GuiButtonTypeLeft, "Retry", nfc_scene_mf_classic_read_success_widget_callback, nfc); - widget_add_button_element( - widget, GuiButtonTypeRight, "More", nfc_scene_mf_classic_read_success_widget_callback, nfc); - - FuriString* temp_str = NULL; - if(furi_string_size(nfc->parsed_data)) { - temp_str = furi_string_alloc_set(nfc->parsed_data); - } else { - temp_str = furi_string_alloc_printf( - "\e#%s\n", nfc_dev_get_device_name(nfc->nfc_dev, NfcProtocolNameTypeFull)); - furi_string_cat_printf(temp_str, "UID:"); - for(size_t i = 0; i < mfc_data->nfca_data->uid_len; i++) { - furi_string_cat_printf(temp_str, " %02X", mfc_data->nfca_data->uid[i]); - } - uint8_t sectors_total = mf_classic_get_total_sectors_num(mfc_data->type); - uint8_t keys_total = sectors_total * 2; - uint8_t keys_found = 0; - uint8_t sectors_read = 0; - mf_classic_get_read_sectors_and_keys(mfc_data, §ors_read, &keys_found); - furi_string_cat_printf(temp_str, "\nKeys Found: %d/%d", keys_found, keys_total); - furi_string_cat_printf(temp_str, "\nSectors Read: %d/%d", sectors_read, sectors_total); - } - - 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_mf_classic_read_success_on_event(void* context, SceneManagerEvent event) { - NfcApp* 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, NfcSceneMfClassicMenu); - consumed = true; - } - } else if(event.type == SceneManagerEventTypeBack) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); - consumed = true; - } - - return consumed; -} - -void nfc_scene_mf_classic_read_success_on_exit(void* context) { - NfcApp* 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_mf_classic_read_supported_card.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_read_supported_card.c index 9b6b430d4231..f69a9d200072 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_read_supported_card.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_read_supported_card.c @@ -28,7 +28,7 @@ void nfc_scene_mf_classic_read_supported_card_on_enter(void* context) { // } if(supported) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSuccess); + scene_manager_next_scene(nfc->scene_manager, NfcSceneReadSuccess); } else { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicDictAttack); } diff --git a/applications/main/nfc/scenes/nfc_scene_mf_desfire_app.c b/applications/main/nfc/scenes/nfc_scene_mf_desfire_app.c index 4f2a7649fc46..83088840868e 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_desfire_app.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_desfire_app.c @@ -69,7 +69,8 @@ bool nfc_scene_mf_desfire_app_on_event(void* context, SceneManagerEvent event) { TextBox* text_box = nfc->text_box; furi_string_reset(nfc->text_box_store); if(event.event == SubmenuIndexAppInfo) { - const uint8_t* app_id = simple_array_cget(data->application_ids, app_index); + const MfDesfireApplicationId* app_id = + simple_array_cget(data->application_ids, app_index); nfc_mf_desfire_format_application_id(app_id, nfc->text_box_store); nfc_mf_desfire_format_application(app, nfc->text_box_store); } else { diff --git a/applications/main/nfc/scenes/nfc_scene_mf_desfire_data.c b/applications/main/nfc/scenes/nfc_scene_mf_desfire_data.c index ffd94736168b..568e5cc5c1e1 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_desfire_data.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_desfire_data.c @@ -38,9 +38,9 @@ void nfc_scene_mf_desfire_data_on_enter(void* context) { FuriString* label = furi_string_alloc(); for(uint32_t i = 0; i < simple_array_get_count(data->application_ids); ++i) { - // TODO: Make it more type safe - const uint8_t* app_id = simple_array_cget(data->application_ids, i); - furi_string_printf(label, "App %02x%02x%02x", app_id[0], app_id[1], app_id[2]); + const MfDesfireApplicationId* app_id = simple_array_cget(data->application_ids, i); + furi_string_printf( + label, "App %02x%02x%02x", app_id->data[0], app_id->data[1], app_id->data[2]); submenu_add_item( submenu, furi_string_get_cstr(label), diff --git a/applications/main/nfc/scenes/nfc_scene_mf_desfire_read.c b/applications/main/nfc/scenes/nfc_scene_mf_desfire_read.c deleted file mode 100644 index 96122313fa01..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_mf_desfire_read.c +++ /dev/null @@ -1,69 +0,0 @@ -#include "../nfc_app_i.h" -#include - -enum { - NfcWorkerEventMfDesfireReadSuccess, -}; - -static NfcCommand nfc_scene_mf_desfire_read_worker_callback(NfcPollerEvent event, void* context) { - furi_assert(event.protocol_type == NfcProtocolTypeMfDesfire); - furi_assert(context); - - NfcApp* instance = context; - MfDesfirePoller* mf_desfire_poller = event.poller; - const MfDesfirePollerEvent* mf_desfire_event = event.data; - - NfcCommand command = NfcCommandContinue; - - if(mf_desfire_event->type == MfDesfirePollerEventTypeReadSuccess) { - nfc_dev_set_protocol_data( - instance->nfc_dev, - NfcProtocolTypeMfDesfire, - mf_desfire_poller_get_data(mf_desfire_poller)); - view_dispatcher_send_custom_event( - instance->view_dispatcher, NfcWorkerEventMfDesfireReadSuccess); - command = NfcCommandStop; - } - - return command; -} - -void nfc_scene_mf_desfire_read_on_enter(void* context) { - NfcApp* instance = context; - - // Setup view - view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup); - - nfc_poller_manager_start( - instance->poller_manager, - NfcProtocolTypeMfDesfire, - nfc_scene_mf_desfire_read_worker_callback, - instance); - - nfc_blink_read_start(instance); -} - -bool nfc_scene_mf_desfire_read_on_event(void* context, SceneManagerEvent event) { - NfcApp* instance = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == NfcWorkerEventMfDesfireReadSuccess) { - notification_message(instance->notifications, &sequence_success); - scene_manager_next_scene(instance->scene_manager, NfcSceneMfDesfireReadSuccess); - dolphin_deed(DolphinDeedNfcReadSuccess); - consumed = true; - } - } - return consumed; -} - -void nfc_scene_mf_desfire_read_on_exit(void* context) { - NfcApp* instance = context; - - nfc_poller_manager_stop(instance->poller_manager); - // Clear view - popup_reset(instance->popup); - - nfc_blink_stop(instance); -} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_desfire_read_success.c b/applications/main/nfc/scenes/nfc_scene_mf_desfire_read_success.c deleted file mode 100644 index 5d2bc55c3a55..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_mf_desfire_read_success.c +++ /dev/null @@ -1,97 +0,0 @@ -#include "../nfc_app_i.h" - -void nfc_scene_mf_desfire_read_success_widget_callback( - GuiButtonType result, - InputType type, - void* context) { - furi_assert(context); - NfcApp* nfc = context; - - if(type == InputTypeShort) { - view_dispatcher_send_custom_event(nfc->view_dispatcher, result); - } -} - -void nfc_scene_mf_desfire_read_success_on_enter(void* context) { - NfcApp* nfc = context; - - // Setup view - const MfDesfireData* data = nfc_dev_get_protocol_data(nfc->nfc_dev, NfcProtocolTypeMfDesfire); - - Widget* widget = nfc->widget; - FuriString* temp_str; - - temp_str = furi_string_alloc_printf( - "\e#%s\n", nfc_dev_get_device_name(nfc->nfc_dev, NfcProtocolNameTypeFull)); - furi_string_cat_printf(temp_str, "UID:"); - - size_t uid_len; - const uint8_t* uid = nfc_dev_get_uid(nfc->nfc_dev, &uid_len); - for(size_t i = 0; i < uid_len; i++) { - furi_string_cat_printf(temp_str, " %02X", uid[i]); - } - - uint32_t bytes_total = 1UL << (data->version.sw_storage >> 1); - uint32_t bytes_free = data->free_memory.bytes_free; - furi_string_cat_printf(temp_str, "\n%lu", bytes_total); - if(data->version.sw_storage & 1) { - furi_string_push_back(temp_str, '+'); - } - furi_string_cat_printf(temp_str, " bytes, %lu bytes free\n", bytes_free); - - uint16_t n_files = 0; - uint16_t n_apps = simple_array_get_count(data->applications); - - for(size_t i = 0; i < n_apps; ++i) { - const MfDesfireApplication* app = simple_array_cget(data->applications, i); - n_files += simple_array_get_count(app->file_ids); - } - furi_string_cat_printf(temp_str, "%d Application", n_apps); - if(n_apps != 1) { - furi_string_push_back(temp_str, 's'); - } - furi_string_cat_printf(temp_str, ", %d file", n_files); - if(n_files != 1) { - furi_string_push_back(temp_str, 's'); - } - - widget_add_text_scroll_element(widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); - furi_string_free(temp_str); - - widget_add_button_element( - widget, GuiButtonTypeLeft, "Retry", nfc_scene_mf_desfire_read_success_widget_callback, nfc); - widget_add_button_element( - widget, GuiButtonTypeRight, "More", nfc_scene_mf_desfire_read_success_widget_callback, nfc); - - notification_message_block(nfc->notifications, &sequence_set_green_255); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); -} - -bool nfc_scene_mf_desfire_read_success_on_event(void* context, SceneManagerEvent event) { - NfcApp* 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, NfcSceneMfDesfireMenu); - consumed = true; - } - } else if(event.type == SceneManagerEventTypeBack) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); - consumed = true; - } - - return consumed; -} - -void nfc_scene_mf_desfire_read_success_on_exit(void* context) { - NfcApp* 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_mf_ultralight_menu.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c index 6a0b4f004e3c..3a5a2d129d73 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c @@ -66,7 +66,7 @@ bool nfc_scene_mf_ultralight_menu_on_event(void* context, SceneManagerEvent even scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockMenu); consumed = true; } else if(event.event == SubmenuIndexInfo) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + scene_manager_next_scene(nfc->scene_manager, NfcSceneInfo); consumed = true; } scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfUltralightMenu, event.event); diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read.c deleted file mode 100644 index 4ad006d12751..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read.c +++ /dev/null @@ -1,93 +0,0 @@ -#include "../nfc_app_i.h" -#include - -enum { - NfcWorkerEventMfUltralightReadSuccess, -}; - -NfcCommand nfc_scene_mf_ultralight_read_worker_callback(NfcPollerEvent event, void* context) { - furi_assert(context); - furi_assert(event.poller); - furi_assert(event.data); - - NfcApp* instance = context; - MfUltralightPollerEvent* mfu_event = event.data; - MfUltralightPoller* mfu_poller = event.poller; - - NfcCommand command = NfcCommandContinue; - - if(mfu_event->type == MfUltralightPollerEventTypeReadSuccess) { - nfc_dev_set_protocol_data( - instance->nfc_dev, event.protocol_type, mf_ultralight_poller_get_data(mfu_poller)); - view_dispatcher_send_custom_event( - instance->view_dispatcher, NfcWorkerEventMfUltralightReadSuccess); - command = NfcCommandStop; - } else if(mfu_event->type == MfUltralightPollerEventTypeAuthRequest) { - nfc_dev_set_protocol_data( - instance->nfc_dev, event.protocol_type, mf_ultralight_poller_get_data(mfu_poller)); - const MfUltralightData* data = - nfc_dev_get_protocol_data(instance->nfc_dev, NfcProtocolTypeMfUltralight); - if(instance->mf_ul_auth->type == MfUltralightAuthTypeXiaomii) { - if(mf_ultralight_generate_xiaomi_pass( - instance->mf_ul_auth, data->nfca_data->uid, data->nfca_data->uid_len)) { - mfu_event->data->auth_context.skip_auth = false; - } - } else if(instance->mf_ul_auth->type == MfUltralightAuthTypeAmiibo) { - if(mf_ultralight_generate_amiibo_pass( - instance->mf_ul_auth, data->nfca_data->uid, data->nfca_data->uid_len)) { - mfu_event->data->auth_context.skip_auth = false; - } - } else if(instance->mf_ul_auth->type == MfUltralightAuthTypeManual) { - mfu_event->data->auth_context.skip_auth = false; - } else { - mfu_event->data->auth_context.skip_auth = true; - } - if(!mfu_event->data->auth_context.skip_auth) { - mfu_event->data->auth_context.password = instance->mf_ul_auth->password; - } - } else if(mfu_event->type == MfUltralightPollerEventTypeAuthSuccess) { - instance->mf_ul_auth->pack = mfu_event->data->auth_context.pack; - } - - return command; -} - -void nfc_scene_mf_ultralight_read_on_enter(void* context) { - NfcApp* instance = context; - - // Setup view - view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup); - - nfc_poller_manager_start( - instance->poller_manager, - NfcProtocolTypeMfUltralight, - nfc_scene_mf_ultralight_read_worker_callback, - instance); - - nfc_blink_read_start(instance); -} - -bool nfc_scene_mf_ultralight_read_on_event(void* context, SceneManagerEvent event) { - NfcApp* instance = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == NfcWorkerEventMfUltralightReadSuccess) { - notification_message(instance->notifications, &sequence_success); - scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightReadSuccess); - dolphin_deed(DolphinDeedNfcReadSuccess); - consumed = true; - } - } - return consumed; -} - -void nfc_scene_mf_ultralight_read_on_exit(void* context) { - NfcApp* instance = context; - - nfc_poller_manager_stop(instance->poller_manager); - // Clear view - popup_reset(instance->popup); - - nfc_blink_stop(instance); -} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_success.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_success.c deleted file mode 100644 index cd4b9befad7a..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_read_success.c +++ /dev/null @@ -1,83 +0,0 @@ -#include "../nfc_app_i.h" - -void nfc_scene_mf_ultralight_read_success_widget_callback( - GuiButtonType result, - InputType type, - void* context) { - furi_assert(context); - NfcApp* nfc = context; - - if(type == InputTypeShort) { - view_dispatcher_send_custom_event(nfc->view_dispatcher, result); - } -} - -void nfc_scene_mf_ultralight_read_success_on_enter(void* context) { - NfcApp* nfc = context; - - // Setup view - const MfUltralightData* data = - nfc_dev_get_protocol_data(nfc->nfc_dev, NfcProtocolTypeMfUltralight); - Widget* widget = nfc->widget; - - FuriString* temp_str; - - temp_str = furi_string_alloc_printf( - "\e#%s\n", nfc_dev_get_device_name(nfc->nfc_dev, NfcProtocolNameTypeFull)); - furi_string_cat_printf(temp_str, "UID:"); - for(size_t i = 0; i < data->nfca_data->uid_len; i++) { - furi_string_cat_printf(temp_str, " %02X", data->nfca_data->uid[i]); - } - furi_string_cat_printf(temp_str, "\nPages Read: %d/%d", data->pages_read, data->pages_total); - if(data->pages_read != data->pages_total) { - furi_string_cat_printf(temp_str, "\nPassword-protected pages!"); - } - - widget_add_text_scroll_element(widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); - furi_string_free(temp_str); - - widget_add_button_element( - widget, - GuiButtonTypeLeft, - "Retry", - nfc_scene_mf_ultralight_read_success_widget_callback, - nfc); - widget_add_button_element( - widget, - GuiButtonTypeRight, - "More", - nfc_scene_mf_ultralight_read_success_widget_callback, - nfc); - - notification_message_block(nfc->notifications, &sequence_set_green_255); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); -} - -bool nfc_scene_mf_ultralight_read_success_on_event(void* context, SceneManagerEvent event) { - NfcApp* 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, NfcSceneMfUltralightMenu); - consumed = true; - } - } else if(event.type == SceneManagerEventTypeBack) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); - consumed = true; - } - - return consumed; -} - -void nfc_scene_mf_ultralight_read_success_on_exit(void* context) { - NfcApp* 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_mf_ultralight_unlock_warn.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c index 97da6d770661..7c6e9a32bb48 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c @@ -52,11 +52,12 @@ bool nfc_scene_mf_ultralight_unlock_warn_on_event(void* context, SceneManagerEve bool consumed = false; + // TODO: Set detected protocol accordingly MfUltralightAuthType type = nfc->mf_ul_auth->type; if((type == MfUltralightAuthTypeReader) || (type == MfUltralightAuthTypeManual)) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == DialogExResultRight) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightRead); + scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); dolphin_deed(DolphinDeedNfcRead); consumed = true; } else if(event.event == DialogExResultLeft) { @@ -74,7 +75,7 @@ bool nfc_scene_mf_ultralight_unlock_warn_on_event(void* context, SceneManagerEve } else { if(event.type == SceneManagerEventTypeCustom) { if(event.event == DialogExResultCenter) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightRead); + scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); dolphin_deed(DolphinDeedNfcRead); consumed = true; } diff --git a/applications/main/nfc/scenes/nfc_scene_nfca_menu.c b/applications/main/nfc/scenes/nfc_scene_nfca_menu.c index 7960b9210109..5fcb655c6a63 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfca_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_nfca_menu.c @@ -46,7 +46,7 @@ bool nfc_scene_nfca_menu_on_event(void* context, SceneManagerEvent event) { } consumed = true; } else if(event.event == SubmenuIndexInfo) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + scene_manager_next_scene(nfc->scene_manager, NfcSceneInfo); consumed = true; } scene_manager_set_scene_state(nfc->scene_manager, NfcSceneNfcaMenu, event.event); diff --git a/applications/main/nfc/scenes/nfc_scene_nfca_read.c b/applications/main/nfc/scenes/nfc_scene_nfca_read.c deleted file mode 100644 index fe8de084c0d3..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_nfca_read.c +++ /dev/null @@ -1,66 +0,0 @@ -#include "../nfc_app_i.h" -#include - -enum { - NfcWorkerEventReadUidNfcA = 100, -}; - -NfcCommand nfc_scene_nfca_read_worker_callback(NfcPollerEvent event, void* context) { - furi_assert(context); - furi_assert(event.data); - furi_assert(event.poller); - - NfcApp* instance = context; - NfcCommand command = NfcCommandContinue; - NfcaPollerEvent* nfca_event = event.data; - NfcaPoller* nfca_poller = event.poller; - - if(nfca_event->type == NfcaPollerEventTypeReady) { - nfc_dev_set_protocol_data( - instance->nfc_dev, event.protocol_type, nfca_poller_get_data(nfca_poller)); - view_dispatcher_send_custom_event(instance->view_dispatcher, NfcWorkerEventReadUidNfcA); - command = NfcCommandStop; - } - - return command; -} - -void nfc_scene_nfca_read_on_enter(void* context) { - NfcApp* instance = context; - - // Setup view - view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup); - - nfc_poller_manager_start( - instance->poller_manager, - NfcProtocolTypeIso14443_3a, - nfc_scene_nfca_read_worker_callback, - instance); - - nfc_blink_read_start(instance); -} - -bool nfc_scene_nfca_read_on_event(void* context, SceneManagerEvent event) { - NfcApp* instance = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == NfcWorkerEventReadUidNfcA) { - notification_message(instance->notifications, &sequence_success); - scene_manager_next_scene(instance->scene_manager, NfcSceneNfcaReadSuccess); - dolphin_deed(DolphinDeedNfcReadSuccess); - consumed = true; - } - } - return consumed; -} - -void nfc_scene_nfca_read_on_exit(void* context) { - NfcApp* instance = context; - - nfc_poller_manager_stop(instance->poller_manager); - // Clear view - popup_reset(instance->popup); - - nfc_blink_stop(instance); -} diff --git a/applications/main/nfc/scenes/nfc_scene_nfca_read_success.c b/applications/main/nfc/scenes/nfc_scene_nfca_read_success.c deleted file mode 100644 index 488632088bd0..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_nfca_read_success.c +++ /dev/null @@ -1,73 +0,0 @@ -#include "../nfc_app_i.h" - -void nfc_scene_nfca_read_success_widget_callback( - GuiButtonType result, - InputType type, - void* context) { - furi_assert(context); - NfcApp* nfc = context; - - if(type == InputTypeShort) { - view_dispatcher_send_custom_event(nfc->view_dispatcher, result); - } -} - -void nfc_scene_nfca_read_success_on_enter(void* context) { - NfcApp* nfc = context; - - // Setup view - const NfcaData* data = nfc_dev_get_protocol_data(nfc->nfc_dev, NfcProtocolTypeIso14443_3a); - Widget* widget = nfc->widget; - - FuriString* temp_str; - temp_str = furi_string_alloc_set("\e#Unknown ISO tag\n"); - - notification_message_block(nfc->notifications, &sequence_set_green_255); - - char iso_type = FURI_BIT(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 < data->uid_len; i++) { - furi_string_cat_printf(temp_str, " %02X", data->uid[i]); - } - furi_string_cat_printf(temp_str, "\nATQA: %02X %02X ", data->atqa[1], data->atqa[0]); - furi_string_cat_printf(temp_str, " SAK: %02X", data->sak); - - widget_add_text_scroll_element(widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); - furi_string_free(temp_str); - - widget_add_button_element( - widget, GuiButtonTypeLeft, "Retry", nfc_scene_nfca_read_success_widget_callback, nfc); - widget_add_button_element( - widget, GuiButtonTypeRight, "More", nfc_scene_nfca_read_success_widget_callback, nfc); - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); -} - -bool nfc_scene_nfca_read_success_on_event(void* context, SceneManagerEvent event) { - NfcApp* 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, NfcSceneNfcaMenu); - consumed = true; - } - } else if(event.type == SceneManagerEventTypeBack) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); - consumed = true; - } - return consumed; -} - -void nfc_scene_nfca_read_success_on_exit(void* context) { - NfcApp* 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 new file mode 100644 index 000000000000..dc7f81e2ba6d --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_read.c @@ -0,0 +1,68 @@ +#include "../nfc_app_i.h" + +#include "../helpers/handlers/nfc_poller_handler.h" + +static NfcCommand nfc_scene_read_poller_callback(NfcPollerEvent event, void* context) { + NfcApp* instance = context; + + const NfcCustomEvent custom_event = nfc_poller_handler_read(event, context); + view_dispatcher_send_custom_event(instance->view_dispatcher, custom_event); + return custom_event != NfcCustomEventReadHandlerIgnore ? NfcCommandStop : NfcCommandContinue; +} + +void nfc_scene_read_on_enter(void* context) { + NfcApp* instance = context; + + popup_set_header( + instance->popup, "Reading card\nDon't move...", 85, 24, AlignCenter, AlignTop); + popup_set_icon(instance->popup, 12, 23, &A_Loading_24); + + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup); + + const NfcProtocolType protocol_type = + instance->protocols_detected[instance->protocols_detected_idx]; + nfc_poller_manager_start( + instance->poller_manager, protocol_type, nfc_scene_read_poller_callback, instance); + + nfc_blink_detect_start(instance); +} + +bool nfc_scene_read_on_event(void* context, SceneManagerEvent event) { + NfcApp* instance = context; + + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventReadHandlerSuccess) { + notification_message(instance->notifications, &sequence_success); + scene_manager_next_scene(instance->scene_manager, NfcSceneReadSuccess); + dolphin_deed(DolphinDeedNfcReadSuccess); + consumed = true; + } else if(event.event == NfcCustomEventReadHandlerAltRead) { + // TODO: Go to alternative read scene + consumed = true; + } else if(event.event == NfcCustomEventReadHandlerFailure) { + if(scene_manager_has_previous_scene(instance->scene_manager, NfcSceneDetect)) { + scene_manager_search_and_switch_to_previous_scene( + instance->scene_manager, NfcSceneDetect); + } + consumed = true; + } + } else if(event.type == SceneManagerEventTypeBack) { + static const uint32_t possible_scenes[] = {NfcSceneSelectProtocol, NfcSceneStart}; + scene_manager_search_and_switch_to_previous_scene_one_of( + instance->scene_manager, possible_scenes, COUNT_OF(possible_scenes)); + consumed = true; + } + + return consumed; +} + +void nfc_scene_read_on_exit(void* context) { + NfcApp* instance = context; + + nfc_poller_manager_stop(instance->poller_manager); + popup_reset(instance->popup); + + nfc_blink_stop(instance); +} diff --git a/applications/main/nfc/scenes/nfc_scene_read_success.c b/applications/main/nfc/scenes/nfc_scene_read_success.c new file mode 100644 index 000000000000..9db40e569be9 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_read_success.c @@ -0,0 +1,70 @@ +#include "../nfc_app_i.h" + +#include "../helpers/format/nfc_protocol_format.h" + +static void + nfc_scene_read_success_widget_callback(GuiButtonType result, InputType type, void* context) { + furi_assert(context); + NfcApp* nfc = context; + + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); + } +} + +void nfc_scene_read_success_on_enter(void* context) { + NfcApp* nfc = context; + Widget* widget = nfc->widget; + + FuriString* temp_str = furi_string_alloc(); + nfc_protocol_format_info(nfc->nfc_dev, NfcProtocolFormatTypeShort, temp_str); + + widget_add_text_scroll_element(widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); + furi_string_free(temp_str); + + widget_add_button_element( + widget, GuiButtonTypeLeft, "Retry", nfc_scene_read_success_widget_callback, nfc); + widget_add_button_element( + widget, GuiButtonTypeRight, "More", nfc_scene_read_success_widget_callback, nfc); + + notification_message_block(nfc->notifications, &sequence_set_green_255); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); +} + +static const NfcScene nfc_scene_read_success_menu_scenes[NfcProtocolTypeMax] = { + [NfcProtocolTypeIso14443_3a] = NfcSceneNfcaMenu, + [NfcProtocolTypeIso14443_4a] = NfcSceneNotImplemented, //TODO: ISO14443-4A menu + [NfcProtocolTypeMfUltralight] = NfcSceneMfUltralightMenu, + [NfcProtocolTypeMfClassic] = NfcSceneMfUltralightMenu, + [NfcProtocolTypeMfDesfire] = NfcSceneMfDesfireMenu, +}; + +bool nfc_scene_read_success_on_event(void* context, SceneManagerEvent event) { + NfcApp* 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) { + const NfcProtocolType protocol_type = nfc_dev_get_protocol_type(nfc->nfc_dev); + const NfcScene menu_scene = nfc_scene_read_success_menu_scenes[protocol_type]; + scene_manager_next_scene(nfc->scene_manager, menu_scene); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeBack) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); + consumed = true; + } + + return consumed; +} + +void nfc_scene_read_success_on_exit(void* context) { + NfcApp* nfc = context; + + notification_message_block(nfc->notifications, &sequence_reset_green); + widget_reset(nfc->widget); +} diff --git a/applications/main/nfc/scenes/nfc_scene_retry_confirm.c b/applications/main/nfc/scenes/nfc_scene_retry_confirm.c index 4b4c305d18f2..b80f1bdcc143 100644 --- a/applications/main/nfc/scenes/nfc_scene_retry_confirm.c +++ b/applications/main/nfc/scenes/nfc_scene_retry_confirm.c @@ -32,16 +32,9 @@ bool nfc_scene_retry_confirm_on_event(void* context, SceneManagerEvent event) { if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneDetect)) { consumed = scene_manager_search_and_switch_to_previous_scene( nfc->scene_manager, NfcSceneDetect); - } else if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneNfcaRead)) { + } else if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneRead)) { consumed = scene_manager_search_and_switch_to_previous_scene( - nfc->scene_manager, NfcSceneNfcaRead); - } else if(scene_manager_has_previous_scene( - nfc->scene_manager, NfcSceneMfUltralightRead)) { - consumed = scene_manager_search_and_switch_to_previous_scene( - nfc->scene_manager, NfcSceneMfUltralightRead); - } else if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneMfDesfireRead)) { - consumed = scene_manager_search_and_switch_to_previous_scene( - nfc->scene_manager, NfcSceneMfDesfireRead); + nfc->scene_manager, NfcSceneRead); } } } else if(event.type == SceneManagerEventTypeBack) { diff --git a/applications/main/nfc/scenes/nfc_scene_select_protocol.c b/applications/main/nfc/scenes/nfc_scene_select_protocol.c index 7c2c28f75244..f1b31d490cd7 100644 --- a/applications/main/nfc/scenes/nfc_scene_select_protocol.c +++ b/applications/main/nfc/scenes/nfc_scene_select_protocol.c @@ -48,17 +48,7 @@ bool nfc_scene_select_protocol_on_event(void* context, SceneManagerEvent event) if(event.type == SceneManagerEventTypeCustom) { instance->protocols_detected_idx = event.event; - // TODO remove this and switch to generic read - const uint32_t nfc_read_scenes[NfcProtocolTypeMax] = { - NfcSceneNfcaRead, - NfcSceneNfcaRead, - NfcSceneMfUltralightRead, - NfcSceneMfClassicDictAttack, - NfcSceneMfDesfireRead, - }; - scene_manager_next_scene( - instance->scene_manager, - nfc_read_scenes[instance->protocols_detected[instance->protocols_detected_idx]]); + scene_manager_next_scene(instance->scene_manager, NfcSceneRead); scene_manager_set_scene_state( instance->scene_manager, NfcSceneSelectProtocol, event.event); consumed = true; diff --git a/lib/nfc/deprecated/nfc_worker_i.h b/lib/nfc/deprecated/nfc_worker_i.h index 57cf9a51e7ab..9e5fe5e3178b 100644 --- a/lib/nfc/deprecated/nfc_worker_i.h +++ b/lib/nfc/deprecated/nfc_worker_i.h @@ -14,7 +14,6 @@ #include #include - struct NfcWorker { FuriThread* thread; Storage* storage; diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire.h b/lib/nfc/protocols/mf_desfire/mf_desfire.h index 902444d1fb15..02de5987b76d 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire.h +++ b/lib/nfc/protocols/mf_desfire/mf_desfire.h @@ -118,7 +118,9 @@ typedef struct { SimpleArray* data; } MfDesfireFileData; -typedef uint8_t MfDesfireApplicationId[MF_DESFIRE_APP_ID_SIZE]; +typedef struct { + uint8_t data[MF_DESFIRE_APP_ID_SIZE]; +} MfDesfireApplicationId; typedef struct MfDesfireApplication { MfDesfireKeySettings key_settings; diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_i.c b/lib/nfc/protocols/mf_desfire/mf_desfire_i.c index e0d30c19f144..7fc6f13489db 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_i.c +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_i.c @@ -21,7 +21,7 @@ void mf_desfire_key_version_parse(MfDesfireKeyVersion* data, const BitBuffer* bu } void mf_desfire_application_id_parse( - MfDesfireApplicationId data, + MfDesfireApplicationId* data, uint32_t index, const BitBuffer* buf) { bit_buffer_write_bytes_mid( diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_i.h b/lib/nfc/protocols/mf_desfire/mf_desfire_i.h index a76cfa706b56..885b45d73254 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_i.h +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_i.h @@ -23,7 +23,7 @@ void mf_desfire_key_settings_parse(MfDesfireKeySettings* data, const BitBuffer* void mf_desfire_key_version_parse(MfDesfireKeyVersion* data, const BitBuffer* buf); void mf_desfire_application_id_parse( - MfDesfireApplicationId data, + MfDesfireApplicationId* data, uint32_t index, const BitBuffer* buf); diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c b/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c index 45453b72c928..404fedeb63b7 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c @@ -195,12 +195,13 @@ MfDesfireError MfDesfireError mf_desfire_poller_async_select_application( MfDesfirePoller* instance, - const MfDesfireApplicationId id) { + const MfDesfireApplicationId* id) { furi_assert(instance); bit_buffer_reset(instance->input_buffer); bit_buffer_append_byte(instance->input_buffer, MF_DESFIRE_CMD_SELECT_APPLICATION); - bit_buffer_append_bytes(instance->input_buffer, id, sizeof(MfDesfireApplicationId)); + bit_buffer_append_bytes( + instance->input_buffer, (const uint8_t*)id, sizeof(MfDesfireApplicationId)); MfDesfireError error = mf_desfire_send_chunks( instance, diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.h b/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.h index 52bcc91f12d7..c886046e0c73 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.h +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.h @@ -75,7 +75,7 @@ MfDesfireError MfDesfireError mf_desfire_poller_async_select_application( MfDesfirePoller* instance, - const MfDesfireApplicationId id); + const MfDesfireApplicationId* id); MfDesfireError mf_desfire_poller_async_read_file_ids(MfDesfirePoller* instance, SimpleArray* data); From bbe4170d06aba3da40c6896adf94c5643b039417 Mon Sep 17 00:00:00 2001 From: gornekich Date: Mon, 26 Jun 2023 14:10:57 +0400 Subject: [PATCH 111/149] MFU poller cleanup (#2803) * nfc: rework mfu poller * nfc: rework mfu sync api * mf ultralight: rework events * nfc mfu: fix alloc and free signatures * nfc app: fix mfu unlock * nfc app: add set and reset detected protocols --- applications/main/nfc/nfc_app.c | 17 + applications/main/nfc/nfc_app_i.h | 4 + .../main/nfc/scenes/nfc_scene_detect.c | 4 +- .../nfc_scene_mf_ultralight_unlock_warn.c | 2 + applications/main/nfc_rpc/nfc_rpc.c | 2 - applications/main/nfc_rpc/nfc_rpc_i.h | 2 - .../main/nfc_rpc/nfc_rpc_mf_ultralight.c | 13 +- .../mf_ultralight/mf_ultralight_poller.c | 396 ++++++++----- .../mf_ultralight/mf_ultralight_poller.h | 63 -- .../mf_ultralight/mf_ultralight_poller_i.c | 544 ------------------ .../mf_ultralight/mf_ultralight_poller_i.h | 22 +- .../mf_ultralight_poller_sync_api.c | 387 ++++++------- .../mf_ultralight_poller_sync_api.h | 30 + 13 files changed, 490 insertions(+), 996 deletions(-) create mode 100644 lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.h diff --git a/applications/main/nfc/nfc_app.c b/applications/main/nfc/nfc_app.c index 88227dd936a9..be7db554459e 100644 --- a/applications/main/nfc/nfc_app.c +++ b/applications/main/nfc/nfc_app.c @@ -432,6 +432,23 @@ void nfc_show_loading_popup(void* context, bool show) { } } +void nfc_app_set_detected_protocols(NfcApp* instance, const NfcProtocolType* types, uint32_t count) { + furi_assert(instance); + furi_assert(types); + furi_assert(count < NfcProtocolTypeMax); + + memcpy(instance->protocols_detected, types, count); + instance->protocols_detected_num = count; + instance->protocols_detected_idx = 0; +} + +void nfc_app_reset_detected_protocols(NfcApp* instance) { + furi_assert(instance); + + instance->protocols_detected_idx = 0; + instance->protocols_detected_num = 0; +} + static bool nfc_is_hal_ready() { if(f_hal_nfc_is_hal_ready() != FHalNfcErrorNone) { // No connection to the chip, show an error screen diff --git a/applications/main/nfc/nfc_app_i.h b/applications/main/nfc/nfc_app_i.h index 8dbdf886698c..9f9a2e32807d 100644 --- a/applications/main/nfc/nfc_app_i.h +++ b/applications/main/nfc/nfc_app_i.h @@ -171,3 +171,7 @@ bool nfc_load_file(NfcApp* instance, FuriString* path, bool show_dialog); bool nfc_save_file(NfcApp* instance, FuriString* path); void nfc_make_app_folder(NfcApp* instance); + +void nfc_app_set_detected_protocols(NfcApp* instance, const NfcProtocolType* types, uint32_t count); + +void nfc_app_reset_detected_protocols(NfcApp* instance); diff --git a/applications/main/nfc/scenes/nfc_scene_detect.c b/applications/main/nfc/scenes/nfc_scene_detect.c index db6d47b347b5..1ff5acb3ddf1 100644 --- a/applications/main/nfc/scenes/nfc_scene_detect.c +++ b/applications/main/nfc/scenes/nfc_scene_detect.c @@ -23,9 +23,7 @@ void nfc_scene_detect_on_enter(void* context) { popup_set_icon(instance->popup, 0, 8, &I_NFC_manual_60x50); view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup); - // Clear detected protocols - instance->protocols_detected_num = 0; - instance->protocols_detected_idx = 0; + nfc_app_reset_detected_protocols(instance); nfc_scanner_start(instance->scanner, nfc_scene_detect_scan_callback, instance); diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c index 7c6e9a32bb48..197c9bd83579 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c @@ -75,6 +75,8 @@ bool nfc_scene_mf_ultralight_unlock_warn_on_event(void* context, SceneManagerEve } else { if(event.type == SceneManagerEventTypeCustom) { if(event.event == DialogExResultCenter) { + const NfcProtocolType mfu_protocol[] = {NfcProtocolTypeMfUltralight}; + nfc_app_set_detected_protocols(nfc, mfu_protocol, COUNT_OF(mfu_protocol)); scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); dolphin_deed(DolphinDeedNfcRead); consumed = true; diff --git a/applications/main/nfc_rpc/nfc_rpc.c b/applications/main/nfc_rpc/nfc_rpc.c index 0c455aaf1266..7a6a60a7fe64 100644 --- a/applications/main/nfc_rpc/nfc_rpc.c +++ b/applications/main/nfc_rpc/nfc_rpc.c @@ -136,7 +136,6 @@ static NfcRpc* nfc_rpc_app_alloc() { instance->nfc = nfc_alloc(); instance->nfca_poller = nfca_poller_alloc(instance->nfc); - instance->mf_ul_poller = mf_ultralight_poller_alloc(instance->nfca_poller); instance->nfca_listener = nfca_listener_alloc(instance->nfc); instance->mf_ul_listener = mf_ultralight_listener_alloc(instance->nfca_listener); instance->mf_classic_poller = mf_classic_poller_alloc(instance->nfca_poller); @@ -176,7 +175,6 @@ void nfc_rpc_app_free(NfcRpc* instance) { mf_classic_poller_free(instance->mf_classic_poller); mf_ultralight_listener_free(instance->mf_ul_listener); - mf_ultralight_poller_free(instance->mf_ul_poller); nfca_listener_free(instance->nfca_listener); nfca_poller_free(instance->nfca_poller); nfc_free(instance->nfc); diff --git a/applications/main/nfc_rpc/nfc_rpc_i.h b/applications/main/nfc_rpc/nfc_rpc_i.h index a39b19a5383d..c8a60c007601 100644 --- a/applications/main/nfc_rpc/nfc_rpc_i.h +++ b/applications/main/nfc_rpc/nfc_rpc_i.h @@ -18,7 +18,6 @@ #include #include #include -#include #include #include @@ -58,7 +57,6 @@ struct NfcRpc { Nfc* nfc; NfcaPoller* nfca_poller; NfcaListener* nfca_listener; - MfUltralightPoller* mf_ul_poller; MfUltralightListener* mf_ul_listener; MfClassicPoller* mf_classic_poller; }; diff --git a/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c b/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c index ca753ba405bc..6250fdf53751 100644 --- a/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c +++ b/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c @@ -1,6 +1,7 @@ #include "nfc_rpc_i.h" #include "assets/compiled/mf_ultralight.pb.h" +#include #define TAG "NfcRpcMfUltralight" @@ -42,7 +43,7 @@ static void nfc_rpc_mf_ultralight_read_page(Nfc_Main* cmd, void* context) { MfUltralightPage page = {}; MfUltralightError error = mf_ultralight_poller_read_page( - instance->mf_ul_poller, cmd->content.mf_ultralight_read_page_req.page, &page); + instance->nfc, cmd->content.mf_ultralight_read_page_req.page, &page); cmd->command_status = Nfc_CommandStatus_OK; cmd->which_content = Nfc_Main_mf_ultralight_read_page_resp_tag; @@ -66,7 +67,7 @@ static void nfc_rpc_mf_ultralight_write_page(Nfc_Main* cmd, void* context) { MfUltralightPage data = {}; memcpy(&data, cmd->content.mf_ultralight_write_page_req.data.bytes, sizeof(MfUltralightPage)); uint16_t page = cmd->content.mf_ultralight_write_page_req.page; - MfUltralightError error = mf_ultralight_poller_write_page(instance->mf_ul_poller, page, &data); + MfUltralightError error = mf_ultralight_poller_write_page(instance->nfc, page, &data); cmd->which_content = Nfc_Main_mf_ultralight_write_page_resp_tag; cmd->command_status = Nfc_CommandStatus_OK; @@ -83,7 +84,7 @@ static void nfc_rpc_mf_ultralight_read_version(Nfc_Main* cmd, void* context) { PB_MfUltralight_ReadVersionResponse_init_default; MfUltralightVersion data = {}; - MfUltralightError error = mf_ultralight_poller_read_version(instance->mf_ul_poller, &data); + MfUltralightError error = mf_ultralight_poller_read_version(instance->nfc, &data); cmd->command_status = Nfc_CommandStatus_OK; cmd->which_content = Nfc_Main_mf_ultralight_read_version_resp_tag; @@ -110,7 +111,7 @@ static void nfc_rpc_mf_ultralight_read_signature(Nfc_Main* cmd, void* context) { PB_MfUltralight_ReadSignatureResponse_init_default; MfUltralightSignature data = {}; - MfUltralightError error = mf_ultralight_poller_read_signature(instance->mf_ul_poller, &data); + MfUltralightError error = mf_ultralight_poller_read_signature(instance->nfc, &data); cmd->command_status = Nfc_CommandStatus_OK; cmd->which_content = Nfc_Main_mf_ultralight_read_signature_resp_tag; @@ -132,7 +133,7 @@ static void nfc_rpc_mf_ultralight_read_counter(Nfc_Main* cmd, void* context) { MfUltralightCounter data = {}; MfUltralightError error = mf_ultralight_poller_read_counter( - instance->mf_ul_poller, cmd->content.mf_ultralight_read_counter_req.counter_num, &data); + instance->nfc, cmd->content.mf_ultralight_read_counter_req.counter_num, &data); cmd->command_status = Nfc_CommandStatus_OK; cmd->which_content = Nfc_Main_mf_ultralight_read_counter_resp_tag; @@ -156,7 +157,7 @@ static void nfc_rpc_mf_ultralight_read_tearing_flag(Nfc_Main* cmd, void* context MfUltralightTearingFlag data = {}; MfUltralightError error = mf_ultralight_poller_read_tearing_flag( - instance->mf_ul_poller, cmd->content.mf_ultralight_read_tearing_flag_req.flag_num, &data); + instance->nfc, cmd->content.mf_ultralight_read_tearing_flag_req.flag_num, &data); cmd->command_status = Nfc_CommandStatus_OK; cmd->which_content = Nfc_Main_mf_ultralight_read_tearing_flag_resp_tag; diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c index cb14acba8c04..424f3b8ff719 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c @@ -4,44 +4,214 @@ #define TAG "MfUltralightPoller" -typedef MfUltralightPollerCommand (*MfUltralightPollerReadHandler)(MfUltralightPoller* instance); +typedef NfcCommand (*MfUltralightPollerReadHandler)(MfUltralightPoller* instance); + +static bool mf_ultralight_poller_ntag_i2c_addr_lin_to_tag_ntag_i2c_1k( + uint16_t lin_addr, + uint8_t* sector, + uint8_t* tag, + uint8_t* pages_left) { + bool tag_calculated = false; + // 0 - 226: sector 0 + // 227 - 228: config registers + // 229 - 230: session registers + + if(lin_addr > 230) { + *pages_left = 0; + } else if(lin_addr >= 229) { + *sector = 3; + *pages_left = 2 - (lin_addr - 229); + *tag = lin_addr - 229 + 248; + tag_calculated = true; + } else if(lin_addr >= 227) { + *sector = 0; + *pages_left = 2 - (lin_addr - 227); + *tag = lin_addr - 227 + 232; + tag_calculated = true; + } else { + *sector = 0; + *pages_left = 227 - lin_addr; + *tag = lin_addr; + tag_calculated = true; + } + + return tag_calculated; +} + +static bool mf_ultralight_poller_ntag_i2c_addr_lin_to_tag_ntag_i2c_2k( + uint16_t lin_addr, + uint8_t* sector, + uint8_t* tag, + uint8_t* pages_left) { + bool tag_calculated = false; + // 0 - 255: sector 0 + // 256 - 480: sector 1 + // 481 - 482: config registers + // 483 - 484: session registers + + if(lin_addr > 484) { + *pages_left = 0; + } else if(lin_addr >= 483) { + *sector = 3; + *pages_left = 2 - (lin_addr - 483); + *tag = lin_addr - 483 + 248; + tag_calculated = true; + } else if(lin_addr >= 481) { + *sector = 1; + *pages_left = 2 - (lin_addr - 481); + *tag = lin_addr - 481 + 232; + tag_calculated = true; + } else if(lin_addr >= 256) { + *sector = 1; + *pages_left = 225 - (lin_addr - 256); + *tag = lin_addr - 256; + tag_calculated = true; + } else { + *sector = 0; + *pages_left = 256 - lin_addr; + *tag = lin_addr; + tag_calculated = true; + } + + return tag_calculated; +} + +static bool mf_ultralight_poller_ntag_i2c_addr_lin_to_tag_ntag_i2c_plus_1k( + uint16_t lin_addr, + uint8_t* sector, + uint8_t* tag, + uint8_t* pages_left) { + bool tag_calculated = false; + // 0 - 233: sector 0 + registers + // 234 - 235: session registers + + if(lin_addr > 235) { + *pages_left = 0; + } else if(lin_addr >= 234) { + *sector = 0; + *pages_left = 2 - (lin_addr - 234); + *tag = lin_addr - 234 + 236; + tag_calculated = true; + } else { + *sector = 0; + *pages_left = 234 - lin_addr; + *tag = lin_addr; + tag_calculated = true; + } -static NfcaPollerCommand mf_ultralight_process_command(MfUltralightPollerCommand command) { - NfcaPollerCommand ret = NfcaPollerCommandContinue; + return tag_calculated; +} - if(command == MfUltralightPollerCommandContinue) { - ret = NfcaPollerCommandContinue; - } else if(command == MfUltralightPollerCommandReset) { - ret = NfcaPollerCommandReset; - } else if(command == MfUltralightPollerCommandStop) { - ret = NfcaPollerCommandStop; +static bool mf_ultralight_poller_ntag_i2c_addr_lin_to_tag_ntag_i2c_plus_2k( + uint16_t lin_addr, + uint8_t* sector, + uint8_t* tag, + uint8_t* pages_left) { + bool tag_calculated = false; + // 0 - 233: sector 0 + registers + // 234 - 235: session registers + // 236 - 491: sector 1 + + if(lin_addr > 491) { + *pages_left = 0; + } else if(lin_addr >= 236) { + *sector = 1; + *pages_left = 256 - (lin_addr - 236); + *tag = lin_addr - 236; + tag_calculated = true; + } else if(lin_addr >= 234) { + *sector = 0; + *pages_left = 2 - (lin_addr - 234); + *tag = lin_addr - 234 + 236; + tag_calculated = true; } else { - furi_crash("Unknown command"); + *sector = 0; + *pages_left = 234 - lin_addr; + *tag = lin_addr; + tag_calculated = true; } - return ret; + return tag_calculated; +} + +bool mf_ultralight_poller_ntag_i2c_addr_lin_to_tag( + MfUltralightPoller* instance, + uint16_t lin_addr, + uint8_t* sector, + uint8_t* tag, + uint8_t* pages_left) { + furi_assert(instance); + furi_assert(sector); + furi_assert(tag); + furi_assert(pages_left); + + bool tag_calculated = false; + + if(instance->data->type == MfUltralightTypeNTAGI2C1K) { + tag_calculated = mf_ultralight_poller_ntag_i2c_addr_lin_to_tag_ntag_i2c_1k( + lin_addr, sector, tag, pages_left); + } else if(instance->data->type == MfUltralightTypeNTAGI2C2K) { + tag_calculated = mf_ultralight_poller_ntag_i2c_addr_lin_to_tag_ntag_i2c_2k( + lin_addr, sector, tag, pages_left); + } else if(instance->data->type == MfUltralightTypeNTAGI2CPlus1K) { + tag_calculated = mf_ultralight_poller_ntag_i2c_addr_lin_to_tag_ntag_i2c_plus_1k( + lin_addr, sector, tag, pages_left); + } else if(instance->data->type == MfUltralightTypeNTAGI2CPlus2K) { + tag_calculated = mf_ultralight_poller_ntag_i2c_addr_lin_to_tag_ntag_i2c_plus_2k( + lin_addr, sector, tag, pages_left); + } + + return tag_calculated; } MfUltralightPoller* mf_ultralight_poller_alloc(NfcaPoller* nfca_poller) { + furi_assert(nfca_poller); + MfUltralightPoller* instance = malloc(sizeof(MfUltralightPoller)); instance->nfca_poller = nfca_poller; + instance->tx_buffer = bit_buffer_alloc(MF_ULTRALIGHT_MAX_BUFF_SIZE); + instance->rx_buffer = bit_buffer_alloc(MF_ULTRALIGHT_MAX_BUFF_SIZE); + instance->data = mf_ultralight_alloc(); + + instance->mfu_event.data = &instance->mfu_event_data; + + instance->general_event.protocol_type = NfcProtocolTypeMfUltralight; + instance->general_event.data = &instance->mfu_event; + instance->general_event.poller = instance; return instance; } void mf_ultralight_poller_free(MfUltralightPoller* instance) { furi_assert(instance); + furi_assert(instance->data); + furi_assert(instance->tx_buffer); + furi_assert(instance->rx_buffer); + bit_buffer_free(instance->tx_buffer); + bit_buffer_free(instance->rx_buffer); + mf_ultralight_free(instance->data); free(instance); } +static void mf_ultralight_poller_set_callback( + MfUltralightPoller* instance, + NfcPollerCallback callback, + void* context) { + furi_assert(instance); + furi_assert(callback); + + instance->callback = callback; + instance->context = context; +} + const MfUltralightData* mf_ultralight_poller_get_data(MfUltralightPoller* instance) { furi_assert(instance); return instance->data; } -static MfUltralightPollerCommand mf_ultralight_poller_handler_idle(MfUltralightPoller* instance) { +static NfcCommand mf_ultralight_poller_handler_idle(MfUltralightPoller* instance) { bit_buffer_reset(instance->tx_buffer); bit_buffer_reset(instance->rx_buffer); nfca_copy(instance->data->nfca_data, nfca_poller_get_data(instance->nfca_poller)); @@ -52,11 +222,10 @@ static MfUltralightPollerCommand mf_ultralight_poller_handler_idle(MfUltralightP instance->pages_read = 0; instance->state = MfUltralightPollerStateReadVersion; - return MfUltralightPollerCommandContinue; + return NfcCommandContinue; } -static MfUltralightPollerCommand - mf_ultralight_poller_handler_read_version(MfUltralightPoller* instance) { +static NfcCommand mf_ultralight_poller_handler_read_version(MfUltralightPoller* instance) { instance->error = mf_ultralight_poller_async_read_version(instance, &instance->data->version); if(instance->error == MfUltralightErrorNone) { FURI_LOG_D(TAG, "Read version success"); @@ -68,11 +237,10 @@ static MfUltralightPollerCommand instance->state = MfUltralightPollerStateDetectNtag203; } - return MfUltralightPollerCommandContinue; + return NfcCommandContinue; } -static MfUltralightPollerCommand - mf_ultralight_poller_handler_check_ntag_203(MfUltralightPoller* instance) { +static NfcCommand mf_ultralight_poller_handler_check_ntag_203(MfUltralightPoller* instance) { MfUltralightPageReadCommandData data = {}; instance->error = mf_ultralight_poller_async_read_page(instance, 41, &data); if(instance->error == MfUltralightErrorNone) { @@ -85,13 +253,10 @@ static MfUltralightPollerCommand } instance->state = MfUltralightPollerStateGetFeatureSet; - return MfUltralightPollerCommandContinue; + return NfcCommandContinue; } -static MfUltralightPollerCommand - mf_ultralight_poller_handler_get_feature_set(MfUltralightPoller* instance) { - MfUltralightPollerCommand command = MfUltralightPollerCommandContinue; - +static NfcCommand mf_ultralight_poller_handler_get_feature_set(MfUltralightPoller* instance) { instance->feature_set = mf_ultralight_get_feature_support_set(instance->data->type); instance->pages_total = mf_ultralight_get_pages_total(instance->data->type); instance->data->pages_total = instance->pages_total; @@ -102,11 +267,10 @@ static MfUltralightPollerCommand instance->pages_total); instance->state = MfUltralightPollerStateReadSignature; - return command; + return NfcCommandContinue; } -static MfUltralightPollerCommand - mf_ultralight_poller_handler_read_signature(MfUltralightPoller* instance) { +static NfcCommand mf_ultralight_poller_handler_read_signature(MfUltralightPoller* instance) { MfUltralightPollerState next_state = MfUltralightPollerStateAuth; if(instance->feature_set & MfUltralightFeatureSupportReadSignature) { FURI_LOG_D(TAG, "Reading signature"); @@ -121,11 +285,10 @@ static MfUltralightPollerCommand } instance->state = next_state; - return MfUltralightPollerCommandContinue; + return NfcCommandContinue; } -static MfUltralightPollerCommand - mf_ultralight_poller_handler_read_counters(MfUltralightPoller* instance) { +static NfcCommand mf_ultralight_poller_handler_read_counters(MfUltralightPoller* instance) { if(instance->feature_set & MfUltralightFeatureSupportReadCounter) { if(mf_ultralight_is_counter_configured(instance->data)) { if(instance->feature_set & MfUltralightFeatureSupportSingleCounter) { @@ -154,11 +317,10 @@ static MfUltralightPollerCommand instance->state = MfUltralightPollerStateReadTearingFlags; } - return MfUltralightPollerCommandContinue; + return NfcCommandContinue; } -static MfUltralightPollerCommand - mf_ultralight_poller_handler_read_tearing_flags(MfUltralightPoller* instance) { +static NfcCommand mf_ultralight_poller_handler_read_tearing_flags(MfUltralightPoller* instance) { if(instance->feature_set & MfUltralightFeatureSupportCheckTearingFlag) { if(instance->tearing_flag_read == instance->tearing_flag_total) { instance->state = MfUltralightPollerStateTryDefaultPass; @@ -180,21 +342,17 @@ static MfUltralightPollerCommand instance->state = MfUltralightPollerStateTryDefaultPass; } - return MfUltralightPollerCommandContinue; + return NfcCommandContinue; } -static MfUltralightPollerCommand mf_ultralight_poller_handler_auth(MfUltralightPoller* instance) { - MfUltralightPollerCommand command = MfUltralightPollerCommandContinue; +static NfcCommand mf_ultralight_poller_handler_auth(MfUltralightPoller* instance) { + NfcCommand command = NfcCommandContinue; if(instance->feature_set & MfUltralightFeatureSupportAuthentication) { - MfUltralightPollerEventData event_data = {}; - MfUltralightPollerEvent event = { - .type = MfUltralightPollerEventTypeAuthRequest, - .data = &event_data, - }; - - command = instance->callback(event, instance->context); - if(!event.data->auth_context.skip_auth) { - instance->auth_context.password = event.data->auth_context.password; + instance->mfu_event.type = MfUltralightPollerEventTypeAuthRequest; + + command = instance->callback(instance->general_event, instance->context); + if(!instance->mfu_event.data->auth_context.skip_auth) { + instance->auth_context.password = instance->mfu_event.data->auth_context.password; FURI_LOG_D( TAG, "Trying to authenticate with password %08lX", @@ -203,14 +361,14 @@ static MfUltralightPollerCommand mf_ultralight_poller_handler_auth(MfUltralightP if(instance->error == MfUltralightErrorNone) { FURI_LOG_D(TAG, "Auth success"); instance->auth_context.auth_success = true; - event.data->auth_context = instance->auth_context; - event.type = MfUltralightPollerEventTypeAuthSuccess; - command = instance->callback(event, instance->context); + instance->mfu_event.data->auth_context = instance->auth_context; + instance->mfu_event.type = MfUltralightPollerEventTypeAuthSuccess; + command = instance->callback(instance->general_event, instance->context); } else { FURI_LOG_D(TAG, "Auth failed"); instance->auth_context.auth_success = false; - MfUltralightPollerEvent event = {.type = MfUltralightPollerEventTypeAuthFailed}; - command = instance->callback(event, instance->context); + instance->mfu_event.type = MfUltralightPollerEventTypeAuthFailed; + command = instance->callback(instance->general_event, instance->context); nfca_poller_halt(instance->nfca_poller); } } @@ -220,8 +378,7 @@ static MfUltralightPollerCommand mf_ultralight_poller_handler_auth(MfUltralightP return command; } -static MfUltralightPollerCommand - mf_ultralight_poller_handler_read_pages(MfUltralightPoller* instance) { +static NfcCommand mf_ultralight_poller_handler_read_pages(MfUltralightPoller* instance) { MfUltralightPageReadCommandData data = {}; uint16_t start_page = instance->pages_read; if(MF_ULTRALIGHT_IS_NTAG_I2C(instance->data->type)) { @@ -261,11 +418,10 @@ static MfUltralightPollerCommand } } - return MfUltralightPollerCommandContinue; + return NfcCommandContinue; } -static MfUltralightPollerCommand - mf_ultralight_poller_handler_try_default_pass(MfUltralightPoller* instance) { +static NfcCommand mf_ultralight_poller_handler_try_default_pass(MfUltralightPoller* instance) { if(instance->feature_set & MfUltralightFeatureSupportAuthentication) { MfUltralightConfigPages* config = NULL; mf_ultralight_get_config_page(instance->data, &config); @@ -293,27 +449,23 @@ static MfUltralightPollerCommand } instance->state = MfUltralightPollerStateReadSuccess; - return MfUltralightPollerCommandContinue; + return NfcCommandContinue; } -static MfUltralightPollerCommand - mf_ultralight_poller_handler_read_fail(MfUltralightPoller* instance) { +static NfcCommand mf_ultralight_poller_handler_read_fail(MfUltralightPoller* instance) { FURI_LOG_D(TAG, "Read Failed"); nfca_poller_halt(instance->nfca_poller); - MfUltralightPollerEventData event_data = {.error = instance->error}; - MfUltralightPollerEvent event = { - .type = MfUltralightPollerEventTypeReadFailed, .data = &event_data}; - MfUltralightPollerCommand command = instance->callback(event, instance->context); + instance->mfu_event.data->error = instance->error; + NfcCommand command = instance->callback(instance->general_event, instance->context); instance->state = MfUltralightPollerStateIdle; return command; } -static MfUltralightPollerCommand - mf_ultralight_poller_handler_read_success(MfUltralightPoller* instance) { - FURI_LOG_D(TAG, "Read success."); +static NfcCommand mf_ultralight_poller_handler_read_success(MfUltralightPoller* instance) { + FURI_LOG_D(TAG, "Read success"); nfca_poller_halt(instance->nfca_poller); - MfUltralightPollerEvent event = {.type = MfUltralightPollerEventTypeReadSuccess}; - MfUltralightPollerCommand command = instance->callback(event, instance->context); + instance->mfu_event.type = MfUltralightPollerEventTypeReadSuccess; + NfcCommand command = instance->callback(instance->general_event, instance->context); return command; } @@ -335,93 +487,53 @@ static const MfUltralightPollerReadHandler }; -static NfcaPollerCommand mf_ultralight_poller_read_callback(NfcaPollerEvent event, void* context) { +static NfcCommand mf_ultralight_poller_run(NfcPollerEvent event, void* context) { furi_assert(context); + furi_assert(event.data); + furi_assert(event.protocol_type == NfcProtocolTypeIso14443_3a); MfUltralightPoller* instance = context; - MfUltralightPollerEventData event_data = {}; - MfUltralightPollerEvent mf_ul_poller_event = {.data = &event_data}; - MfUltralightPollerCommand command = MfUltralightPollerCommandContinue; + furi_assert(instance->callback); - furi_assert(instance->session_state != MfUltralightPollerSessionStateIdle); - if(instance->session_state == MfUltralightPollerSessionStateStopRequest) { - command = MfUltralightPollerCommandStop; - } else { - if(event.type == NfcaPollerEventTypeReady) { - command = mf_ultralight_poller_read_handler[instance->state](instance); - } else if(event.type == NfcaPollerEventTypeError) { - if(instance->callback) { - mf_ul_poller_event.type = MfUltralightPollerEventTypeReadFailed; - command = instance->callback(mf_ul_poller_event, instance->context); - } - } - } - - return mf_ultralight_process_command(command); -} - -MfUltralightError mf_ultralight_poller_start( - MfUltralightPoller* instance, - NfcaPollerEventCallback callback, - void* context) { - furi_assert(instance); - furi_assert(instance->state == MfUltralightPollerStateIdle); - furi_assert(instance->nfca_poller); - furi_assert(callback); - furi_assert(instance->session_state == MfUltralightPollerSessionStateIdle); + const NfcaPollerEvent* nfca_event = event.data; - instance->data = mf_ultralight_alloc(); - instance->tx_buffer = bit_buffer_alloc(MF_ULTRALIGHT_MAX_BUFF_SIZE); - instance->rx_buffer = bit_buffer_alloc(MF_ULTRALIGHT_MAX_BUFF_SIZE); - - instance->session_state = MfUltralightPollerSessionStateActive; - nfca_poller_start(instance->nfca_poller, callback, context); - - return MfUltralightErrorNone; -} - -MfUltralightError mf_ultralight_poller_read( - MfUltralightPoller* instance, - MfUltralightPollerCallback callback, - void* context) { - furi_assert(instance); - furi_assert(instance->state == MfUltralightPollerStateIdle); - furi_assert(instance->nfca_poller); - furi_assert(callback); + NfcCommand command = NfcCommandContinue; - instance->callback = callback; - instance->context = context; + if(nfca_event->type == NfcaPollerEventTypeReady) { + command = mf_ultralight_poller_read_handler[instance->state](instance); + } else if(nfca_event->type == NfcaPollerEventTypeError) { + instance->mfu_event.type = MfUltralightPollerEventTypeReadFailed; + command = instance->callback(instance->general_event, instance->context); + } - return mf_ultralight_poller_start(instance, mf_ultralight_poller_read_callback, instance); + return command; } -MfUltralightError mf_ultralight_poller_reset(MfUltralightPoller* instance) { - furi_assert(instance); - furi_assert(instance->data); - furi_assert(instance->tx_buffer); - furi_assert(instance->rx_buffer); - furi_assert(instance->nfca_poller); +static bool mf_ultralight_poller_detect(NfcPollerEvent event, void* context) { + furi_assert(context); + furi_assert(event.data); + furi_assert(event.protocol_type == NfcProtocolTypeIso14443_3a); - bit_buffer_free(instance->tx_buffer); - bit_buffer_free(instance->rx_buffer); - instance->tx_buffer = NULL; - instance->rx_buffer = NULL; + bool protocol_detected = false; + MfUltralightPoller* instance = context; + const NfcaPollerEvent* nfca_event = event.data; - instance->callback = NULL; - instance->context = NULL; - instance->state = MfUltralightPollerStateIdle; + if(nfca_event->type == NfcaPollerEventTypeReady) { + MfUltralightPageReadCommandData read_page_cmd_data = {}; + MfUltralightError error = + mf_ultralight_poller_async_read_page(instance, 0, &read_page_cmd_data); + protocol_detected = (error == MfUltralightErrorNone); + nfca_poller_halt(instance->nfca_poller); + } - return MfUltralightErrorNone; + return protocol_detected; } -MfUltralightError mf_ultralight_poller_stop(MfUltralightPoller* instance) { - furi_assert(instance); - furi_assert(instance->nfca_poller); - - instance->session_state = MfUltralightPollerSessionStateStopRequest; - nfca_poller_stop(instance->nfca_poller); - instance->session_state = MfUltralightPollerSessionStateIdle; - mf_ultralight_free(instance->data); - - return mf_ultralight_poller_reset(instance); -} +const NfcPollerBase mf_ultralight_poller = { + .alloc = (NfcPollerAlloc)mf_ultralight_poller_alloc, + .free = (NfcPollerFree)mf_ultralight_poller_free, + .set_callback = (NfcPollerSetCallback)mf_ultralight_poller_set_callback, + .run = (NfcPollerRun)mf_ultralight_poller_run, + .detect = (NfcPollerDetect)mf_ultralight_poller_detect, + .get_data = (NfcPollerGetData)mf_ultralight_poller_get_data, +}; diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h index bc77a5ae0c3d..d4d25d4d04a0 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h @@ -36,71 +36,8 @@ typedef struct { MfUltralightPollerEventData* data; } MfUltralightPollerEvent; -typedef enum { - MfUltralightPollerCommandContinue = NfcaPollerCommandContinue, - MfUltralightPollerCommandReset = NfcaPollerCommandReset, - MfUltralightPollerCommandStop = NfcaPollerCommandStop, -} MfUltralightPollerCommand; - -typedef MfUltralightPollerCommand ( - *MfUltralightPollerCallback)(MfUltralightPollerEvent event, void* context); - -MfUltralightPoller* mf_ultralight_poller_alloc(NfcaPoller* nfca_poller); - -void mf_ultralight_poller_free(MfUltralightPoller* instance); - const MfUltralightData* mf_ultralight_poller_get_data(MfUltralightPoller* instance); -MfUltralightError mf_ultralight_poller_start( - MfUltralightPoller* instance, - NfcaPollerEventCallback callback, - void* context); - -MfUltralightError mf_ultralight_poller_read( - MfUltralightPoller* instance, - MfUltralightPollerCallback callback, - void* context); - -MfUltralightError mf_ultralight_poller_reset(MfUltralightPoller* instance); - -MfUltralightError mf_ultralight_poller_stop(MfUltralightPoller* instance); - -// Sync API - -MfUltralightError mf_ultralight_poller_read_page( - MfUltralightPoller* instance, - uint16_t page, - MfUltralightPage* data); - -MfUltralightError mf_ultralight_poller_read_page_new( - NfcPollerManager* poller_manager, - uint16_t page, - MfUltralightPage* data); - -MfUltralightError mf_ultralight_poller_write_page( - MfUltralightPoller* instance, - uint16_t page, - MfUltralightPage* data); - -MfUltralightError - mf_ultralight_poller_read_version(MfUltralightPoller* instance, MfUltralightVersion* data); - -MfUltralightError - mf_ultralight_poller_read_signature(MfUltralightPoller* instance, MfUltralightSignature* data); - -MfUltralightError mf_ultralight_poller_read_counter( - MfUltralightPoller* instance, - uint8_t counter_num, - MfUltralightCounter* data); - -MfUltralightError mf_ultralight_poller_read_tearing_flag( - MfUltralightPoller* instance, - uint8_t flag_num, - MfUltralightTearingFlag* data); - -MfUltralightError - mf_ultralight_poller_read_card(MfUltralightPoller* instance, MfUltralightData* data); - #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c index 1838a272b282..b1aeebc843cf 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c @@ -30,164 +30,6 @@ MfUltralightError mf_ultralight_process_error(NfcaError error) { return ret; } -static bool mf_ultralight_poller_ntag_i2c_addr_lin_to_tag_ntag_i2c_1k( - uint16_t lin_addr, - uint8_t* sector, - uint8_t* tag, - uint8_t* pages_left) { - bool tag_calculated = false; - // 0 - 226: sector 0 - // 227 - 228: config registers - // 229 - 230: session registers - - if(lin_addr > 230) { - *pages_left = 0; - } else if(lin_addr >= 229) { - *sector = 3; - *pages_left = 2 - (lin_addr - 229); - *tag = lin_addr - 229 + 248; - tag_calculated = true; - } else if(lin_addr >= 227) { - *sector = 0; - *pages_left = 2 - (lin_addr - 227); - *tag = lin_addr - 227 + 232; - tag_calculated = true; - } else { - *sector = 0; - *pages_left = 227 - lin_addr; - *tag = lin_addr; - tag_calculated = true; - } - - return tag_calculated; -} - -static bool mf_ultralight_poller_ntag_i2c_addr_lin_to_tag_ntag_i2c_2k( - uint16_t lin_addr, - uint8_t* sector, - uint8_t* tag, - uint8_t* pages_left) { - bool tag_calculated = false; - // 0 - 255: sector 0 - // 256 - 480: sector 1 - // 481 - 482: config registers - // 483 - 484: session registers - - if(lin_addr > 484) { - *pages_left = 0; - } else if(lin_addr >= 483) { - *sector = 3; - *pages_left = 2 - (lin_addr - 483); - *tag = lin_addr - 483 + 248; - tag_calculated = true; - } else if(lin_addr >= 481) { - *sector = 1; - *pages_left = 2 - (lin_addr - 481); - *tag = lin_addr - 481 + 232; - tag_calculated = true; - } else if(lin_addr >= 256) { - *sector = 1; - *pages_left = 225 - (lin_addr - 256); - *tag = lin_addr - 256; - tag_calculated = true; - } else { - *sector = 0; - *pages_left = 256 - lin_addr; - *tag = lin_addr; - tag_calculated = true; - } - - return tag_calculated; -} - -static bool mf_ultralight_poller_ntag_i2c_addr_lin_to_tag_ntag_i2c_plus_1k( - uint16_t lin_addr, - uint8_t* sector, - uint8_t* tag, - uint8_t* pages_left) { - bool tag_calculated = false; - // 0 - 233: sector 0 + registers - // 234 - 235: session registers - - if(lin_addr > 235) { - *pages_left = 0; - } else if(lin_addr >= 234) { - *sector = 0; - *pages_left = 2 - (lin_addr - 234); - *tag = lin_addr - 234 + 236; - tag_calculated = true; - } else { - *sector = 0; - *pages_left = 234 - lin_addr; - *tag = lin_addr; - tag_calculated = true; - } - - return tag_calculated; -} - -static bool mf_ultralight_poller_ntag_i2c_addr_lin_to_tag_ntag_i2c_plus_2k( - uint16_t lin_addr, - uint8_t* sector, - uint8_t* tag, - uint8_t* pages_left) { - bool tag_calculated = false; - // 0 - 233: sector 0 + registers - // 234 - 235: session registers - // 236 - 491: sector 1 - - if(lin_addr > 491) { - *pages_left = 0; - } else if(lin_addr >= 236) { - *sector = 1; - *pages_left = 256 - (lin_addr - 236); - *tag = lin_addr - 236; - tag_calculated = true; - } else if(lin_addr >= 234) { - *sector = 0; - *pages_left = 2 - (lin_addr - 234); - *tag = lin_addr - 234 + 236; - tag_calculated = true; - } else { - *sector = 0; - *pages_left = 234 - lin_addr; - *tag = lin_addr; - tag_calculated = true; - } - - return tag_calculated; -} - -bool mf_ultralight_poller_ntag_i2c_addr_lin_to_tag( - MfUltralightPoller* instance, - uint16_t lin_addr, - uint8_t* sector, - uint8_t* tag, - uint8_t* pages_left) { - furi_assert(instance); - furi_assert(sector); - furi_assert(tag); - furi_assert(pages_left); - - bool tag_calculated = false; - - if(instance->data->type == MfUltralightTypeNTAGI2C1K) { - tag_calculated = mf_ultralight_poller_ntag_i2c_addr_lin_to_tag_ntag_i2c_1k( - lin_addr, sector, tag, pages_left); - } else if(instance->data->type == MfUltralightTypeNTAGI2C2K) { - tag_calculated = mf_ultralight_poller_ntag_i2c_addr_lin_to_tag_ntag_i2c_2k( - lin_addr, sector, tag, pages_left); - } else if(instance->data->type == MfUltralightTypeNTAGI2CPlus1K) { - tag_calculated = mf_ultralight_poller_ntag_i2c_addr_lin_to_tag_ntag_i2c_plus_1k( - lin_addr, sector, tag, pages_left); - } else if(instance->data->type == MfUltralightTypeNTAGI2CPlus2K) { - tag_calculated = mf_ultralight_poller_ntag_i2c_addr_lin_to_tag_ntag_i2c_plus_2k( - lin_addr, sector, tag, pages_left); - } - - return tag_calculated; -} - MfUltralightError mf_ultralight_poller_async_auth( MfUltralightPoller* instance, MfUltralightPollerAuthContext* data) { @@ -437,389 +279,3 @@ MfUltralightError mf_ultralight_poller_async_read_tearing_flag( return ret; } - -static NfcPoller* mf_ultralight_poller_alloc_new(NfcPoller* nfca_poller) { - furi_assert(nfca_poller); - - MfUltralightPoller* instance = malloc(sizeof(MfUltralightPoller)); - instance->nfca_poller = nfca_poller; - instance->tx_buffer = bit_buffer_alloc(MF_ULTRALIGHT_MAX_BUFF_SIZE); - instance->rx_buffer = bit_buffer_alloc(MF_ULTRALIGHT_MAX_BUFF_SIZE); - instance->event = malloc(sizeof(NfcPollerEvent)); - instance->mfu_event = malloc(sizeof(MfUltralightPollerEvent)); - instance->data = mf_ultralight_alloc(); - - return instance; -} - -static void mf_ultralight_poller_free_new(NfcPoller* mfu_poller) { - furi_assert(mfu_poller); - - MfUltralightPoller* instance = mfu_poller; - furi_assert(instance->data); - furi_assert(instance->tx_buffer); - furi_assert(instance->rx_buffer); - furi_assert(instance->mfu_event); - furi_assert(instance->event); - - bit_buffer_free(instance->tx_buffer); - bit_buffer_free(instance->rx_buffer); - mf_ultralight_free(instance->data); - free(instance->mfu_event); - free(instance->event); - free(instance); -} - -static void mf_ultralight_poller_set_callback( - NfcPoller* mfu_poller, - NfcPollerCallback callback, - void* context) { - furi_assert(mfu_poller); - furi_assert(callback); - - MfUltralightPoller* instance = mfu_poller; - instance->callback_new = callback; - instance->context_new = context; -} - -static const NfcProtocolData* mf_ultralight_poller_get_data_new(const NfcPoller* mfu_poller) { - furi_assert(mfu_poller); - - const MfUltralightPoller* instance = mfu_poller; - furi_assert(instance->data); - - return instance->data; -} - -typedef NfcCommand (*MfUltralightPollerReadHandler)(MfUltralightPoller* instance); - -static NfcCommand mf_ultralight_poller_handler_idle(MfUltralightPoller* instance) { - bit_buffer_reset(instance->tx_buffer); - bit_buffer_reset(instance->rx_buffer); - nfca_copy(instance->data->nfca_data, nfca_poller_get_data(instance->nfca_poller)); - instance->counters_read = 0; - instance->counters_total = 3; - instance->tearing_flag_read = 0; - instance->tearing_flag_total = 3; - instance->pages_read = 0; - instance->state = MfUltralightPollerStateReadVersion; - - return NfcCommandContinue; -} - -static NfcCommand mf_ultralight_poller_handler_read_version(MfUltralightPoller* instance) { - instance->error = mf_ultralight_poller_async_read_version(instance, &instance->data->version); - if(instance->error == MfUltralightErrorNone) { - FURI_LOG_D(TAG, "Read version success"); - instance->data->type = mf_ultralight_get_type_by_version(&instance->data->version); - instance->state = MfUltralightPollerStateGetFeatureSet; - } else { - FURI_LOG_D(TAG, "Didn't response. Check NTAG 203"); - nfca_poller_halt(instance->nfca_poller); - instance->state = MfUltralightPollerStateDetectNtag203; - } - - return NfcCommandContinue; -} - -static NfcCommand mf_ultralight_poller_handler_check_ntag_203(MfUltralightPoller* instance) { - MfUltralightPageReadCommandData data = {}; - instance->error = mf_ultralight_poller_async_read_page(instance, 41, &data); - if(instance->error == MfUltralightErrorNone) { - FURI_LOG_D(TAG, "NTAG203 detected"); - instance->data->type = MfUltralightTypeNTAG203; - } else { - FURI_LOG_D(TAG, "Original Ultralight detected"); - nfca_poller_halt(instance->nfca_poller); - instance->data->type = MfUltralightTypeUnknown; - } - instance->state = MfUltralightPollerStateGetFeatureSet; - - return NfcCommandContinue; -} - -static NfcCommand mf_ultralight_poller_handler_get_feature_set(MfUltralightPoller* instance) { - instance->feature_set = mf_ultralight_get_feature_support_set(instance->data->type); - instance->pages_total = mf_ultralight_get_pages_total(instance->data->type); - instance->data->pages_total = instance->pages_total; - FURI_LOG_D( - TAG, - "%s detected. Total pages: %d", - mf_ultralight_get_device_name(instance->data, NfcProtocolNameTypeFull), - instance->pages_total); - - instance->state = MfUltralightPollerStateReadSignature; - return NfcCommandContinue; -} - -static NfcCommand mf_ultralight_poller_handler_read_signature(MfUltralightPoller* instance) { - MfUltralightPollerState next_state = MfUltralightPollerStateAuth; - if(instance->feature_set & MfUltralightFeatureSupportReadSignature) { - FURI_LOG_D(TAG, "Reading signature"); - instance->error = - mf_ultralight_poller_async_read_signature(instance, &instance->data->signature); - if(instance->error != MfUltralightErrorNone) { - FURI_LOG_D(TAG, "Read signature failed"); - next_state = MfUltralightPollerStateReadFailed; - } - } else { - FURI_LOG_D(TAG, "Skip reading signature"); - } - instance->state = next_state; - - return NfcCommandContinue; -} - -static NfcCommand mf_ultralight_poller_handler_read_counters(MfUltralightPoller* instance) { - if(instance->feature_set & MfUltralightFeatureSupportReadCounter) { - if(mf_ultralight_is_counter_configured(instance->data)) { - if(instance->feature_set & MfUltralightFeatureSupportSingleCounter) { - instance->counters_read = 2; - } - if(instance->counters_read == instance->counters_total) { - instance->state = MfUltralightPollerStateReadTearingFlags; - } else { - FURI_LOG_D(TAG, "Reading counter %d", instance->counters_read); - instance->error = mf_ultralight_poller_async_read_counter( - instance, - instance->counters_read, - &instance->data->counter[instance->counters_read]); - if(instance->error != MfUltralightErrorNone) { - FURI_LOG_D(TAG, "Failed to read %d counter", instance->counters_read); - instance->state = MfUltralightPollerStateReadTearingFlags; - } else { - instance->counters_read++; - } - } - } else { - instance->state = MfUltralightPollerStateReadTearingFlags; - } - } else { - FURI_LOG_D(TAG, "Skip reading counters"); - instance->state = MfUltralightPollerStateReadTearingFlags; - } - - return NfcCommandContinue; -} - -static NfcCommand mf_ultralight_poller_handler_read_tearing_flags(MfUltralightPoller* instance) { - if(instance->feature_set & MfUltralightFeatureSupportCheckTearingFlag) { - if(instance->tearing_flag_read == instance->tearing_flag_total) { - instance->state = MfUltralightPollerStateTryDefaultPass; - } else { - FURI_LOG_D(TAG, "Reading tearing flag %d", instance->tearing_flag_read); - instance->error = mf_ultralight_poller_async_read_tearing_flag( - instance, - instance->tearing_flag_read, - &instance->data->tearing_flag[instance->tearing_flag_read]); - if(instance->error != MfUltralightErrorNone) { - FURI_LOG_D(TAG, "Reading tearing flag %d failed", instance->tearing_flag_read); - instance->state = MfUltralightPollerStateReadFailed; - } else { - instance->tearing_flag_read++; - } - } - } else { - FURI_LOG_D(TAG, "Skip reading tearing flags"); - instance->state = MfUltralightPollerStateTryDefaultPass; - } - - return NfcCommandContinue; -} - -static NfcCommand mf_ultralight_poller_handler_auth(MfUltralightPoller* instance) { - NfcCommand command = NfcCommandContinue; - if(instance->feature_set & MfUltralightFeatureSupportAuthentication) { - MfUltralightPollerEventData event_data = {}; - instance->mfu_event->type = MfUltralightPollerEventTypeAuthRequest; - instance->mfu_event->data = &event_data; - - command = instance->callback_new(*instance->event, instance->context_new); - if(!instance->mfu_event->data->auth_context.skip_auth) { - instance->auth_context.password = instance->mfu_event->data->auth_context.password; - FURI_LOG_D( - TAG, - "Trying to authenticate with password %08lX", - instance->auth_context.password.pass); - instance->error = mf_ultralight_poller_async_auth(instance, &instance->auth_context); - if(instance->error == MfUltralightErrorNone) { - FURI_LOG_D(TAG, "Auth success"); - instance->auth_context.auth_success = true; - instance->mfu_event->data->auth_context = instance->auth_context; - instance->mfu_event->type = MfUltralightPollerEventTypeAuthSuccess; - command = instance->callback_new(*instance->event, instance->context_new); - } else { - FURI_LOG_D(TAG, "Auth failed"); - instance->auth_context.auth_success = false; - instance->mfu_event->type = MfUltralightPollerEventTypeAuthFailed; - command = instance->callback_new(*instance->event, instance->context_new); - nfca_poller_halt(instance->nfca_poller); - } - } - } - instance->state = MfUltralightPollerStateReadPages; - - return command; -} - -static NfcCommand mf_ultralight_poller_handler_read_pages(MfUltralightPoller* instance) { - MfUltralightPageReadCommandData data = {}; - uint16_t start_page = instance->pages_read; - if(MF_ULTRALIGHT_IS_NTAG_I2C(instance->data->type)) { - uint8_t tag = 0; - uint8_t sector = 0; - uint8_t pages_left = 0; - if(mf_ultralight_poller_ntag_i2c_addr_lin_to_tag( - instance, start_page, §or, &tag, &pages_left)) { - instance->error = - mf_ultralight_poller_async_read_page_from_sector(instance, sector, tag, &data); - } else { - FURI_LOG_D(TAG, "Failed to calculate sector and tag from %d page", start_page); - instance->error = MfUltralightErrorProtocol; - } - } else { - instance->error = mf_ultralight_poller_async_read_page(instance, start_page, &data); - } - - if(instance->error == MfUltralightErrorNone) { - for(size_t i = 0; i < 4; i++) { - if(start_page + i < instance->pages_total) { - FURI_LOG_D(TAG, "Read page %d success", start_page + i); - instance->data->page[start_page + i] = data.page[i]; - instance->pages_read++; - instance->data->pages_read = instance->pages_read; - } - } - if(instance->pages_read == instance->pages_total) { - instance->state = MfUltralightPollerStateReadCounters; - } - } else { - FURI_LOG_D(TAG, "Read page %d failed", instance->pages_read); - if(instance->pages_read) { - instance->state = MfUltralightPollerStateReadCounters; - } else { - instance->state = MfUltralightPollerStateReadFailed; - } - } - - return NfcCommandContinue; -} - -static NfcCommand mf_ultralight_poller_handler_try_default_pass(MfUltralightPoller* instance) { - if(instance->feature_set & MfUltralightFeatureSupportAuthentication) { - MfUltralightConfigPages* config = NULL; - mf_ultralight_get_config_page(instance->data, &config); - if(instance->auth_context.auth_success) { - config->password = instance->auth_context.password; - config->pack = instance->auth_context.pack; - } else if(config->access.authlim == 0) { - FURI_LOG_D(TAG, "No limits in authentication. Trying default password"); - instance->auth_context.password.pass = MF_ULTRALIGHT_DEFAULT_PASSWORD; - instance->error = mf_ultralight_poller_async_auth(instance, &instance->auth_context); - if(instance->error == MfUltralightErrorNone) { - FURI_LOG_D(TAG, "Default password detected"); - config->password.pass = MF_ULTRALIGHT_DEFAULT_PASSWORD; - config->pack = instance->auth_context.pack; - } - } - - if(instance->pages_read != instance->pages_total) { - // Probably password protected, fix AUTH0 and PROT so before AUTH0 - // can be written and since AUTH0 won't be readable, like on the - // original card - config->auth0 = instance->pages_read; - config->access.prot = true; - } - } - - instance->state = MfUltralightPollerStateReadSuccess; - return NfcCommandContinue; -} - -static NfcCommand mf_ultralight_poller_handler_read_fail(MfUltralightPoller* instance) { - FURI_LOG_D(TAG, "Read Failed"); - nfca_poller_halt(instance->nfca_poller); - instance->mfu_event->data->error = instance->error; - NfcCommand command = instance->callback_new(*instance->event, instance->context_new); - instance->state = MfUltralightPollerStateIdle; - return command; -} - -static NfcCommand mf_ultralight_poller_handler_read_success(MfUltralightPoller* instance) { - FURI_LOG_D(TAG, "Read success."); - nfca_poller_halt(instance->nfca_poller); - instance->mfu_event->type = MfUltralightPollerEventTypeReadSuccess; - NfcCommand command = instance->callback_new(*instance->event, instance->context_new); - return command; -} - -static const MfUltralightPollerReadHandler - mf_ultralight_poller_read_handler[MfUltralightPollerStateNum] = { - [MfUltralightPollerStateIdle] = mf_ultralight_poller_handler_idle, - [MfUltralightPollerStateReadVersion] = mf_ultralight_poller_handler_read_version, - [MfUltralightPollerStateDetectNtag203] = mf_ultralight_poller_handler_check_ntag_203, - [MfUltralightPollerStateGetFeatureSet] = mf_ultralight_poller_handler_get_feature_set, - [MfUltralightPollerStateReadSignature] = mf_ultralight_poller_handler_read_signature, - [MfUltralightPollerStateReadCounters] = mf_ultralight_poller_handler_read_counters, - [MfUltralightPollerStateReadTearingFlags] = - mf_ultralight_poller_handler_read_tearing_flags, - [MfUltralightPollerStateAuth] = mf_ultralight_poller_handler_auth, - [MfUltralightPollerStateTryDefaultPass] = mf_ultralight_poller_handler_try_default_pass, - [MfUltralightPollerStateReadPages] = mf_ultralight_poller_handler_read_pages, - [MfUltralightPollerStateReadFailed] = mf_ultralight_poller_handler_read_fail, - [MfUltralightPollerStateReadSuccess] = mf_ultralight_poller_handler_read_success, - -}; - -static NfcCommand mf_ultralight_poller_run(NfcPollerEvent event, void* context) { - furi_assert(context); - furi_assert(event.data); - furi_assert(event.protocol_type == NfcProtocolTypeIso14443_3a); - - MfUltralightPoller* instance = context; - furi_assert(instance->callback_new); - NfcaPollerEvent* nfca_event = event.data; - - instance->event->protocol_type = NfcProtocolTypeMfUltralight; - instance->event->poller = instance; - instance->event->data = instance->mfu_event; - NfcCommand command = NfcCommandContinue; - - if(nfca_event->type == NfcaPollerEventTypeReady) { - command = mf_ultralight_poller_read_handler[instance->state](instance); - } else if(nfca_event->type == NfcaPollerEventTypeError) { - instance->mfu_event->type = MfUltralightPollerEventTypeReadFailed; - command = instance->callback_new(*instance->event, instance->context_new); - } - - return command; -} - -static bool mf_ultralight_poller_detect(NfcPollerEvent event, void* context) { - furi_assert(context); - furi_assert(event.data); - furi_assert(event.protocol_type == NfcProtocolTypeIso14443_3a); - - bool protocol_detected = false; - MfUltralightPoller* instance = context; - NfcaPollerEvent* nfca_event = event.data; - - if(nfca_event->type == NfcaPollerEventTypeReady) { - MfUltralightPageReadCommandData read_page_cmd_data = {}; - MfUltralightError error = - mf_ultralight_poller_async_read_page(instance, 0, &read_page_cmd_data); - protocol_detected = (error == MfUltralightErrorNone); - nfca_poller_halt(instance->nfca_poller); - } - - return protocol_detected; -} - -const NfcPollerBase mf_ultralight_poller = { - .alloc = mf_ultralight_poller_alloc_new, - .free = mf_ultralight_poller_free_new, - .set_callback = mf_ultralight_poller_set_callback, - .run = mf_ultralight_poller_run, - .detect = mf_ultralight_poller_detect, - .get_data = mf_ultralight_poller_get_data_new, -}; diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h index 96e23d2f5cb3..4786f3c7951b 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h @@ -64,20 +64,12 @@ typedef enum { MfUltralightPollerStateNum, } MfUltralightPollerState; -typedef enum { - MfUltralightPollerSessionStateIdle, - MfUltralightPollerSessionStateActive, - MfUltralightPollerSessionStateStopRequest, -} MfUltralightPollerSessionState; - struct MfUltralightPoller { NfcaPoller* nfca_poller; - MfUltralightPollerSessionState session_state; MfUltralightPollerState state; BitBuffer* tx_buffer; BitBuffer* rx_buffer; MfUltralightData* data; - MfUltralightPollerCallback callback; MfUltralightPollerAuthContext auth_context; uint32_t feature_set; uint16_t pages_read; @@ -87,16 +79,20 @@ struct MfUltralightPoller { uint8_t tearing_flag_read; uint8_t tearing_flag_total; MfUltralightError error; - void* context; - NfcPollerEvent* event; - MfUltralightPollerEvent* mfu_event; - NfcPollerCallback callback_new; - void* context_new; + NfcPollerEvent general_event; + MfUltralightPollerEvent mfu_event; + MfUltralightPollerEventData mfu_event_data; + NfcPollerCallback callback; + void* context; }; MfUltralightError mf_ultralight_process_error(NfcaError error); +MfUltralightPoller* mf_ultralight_poller_alloc(NfcaPoller* nfca_poller); + +void mf_ultralight_poller_free(MfUltralightPoller* instance); + bool mf_ultralight_poller_ntag_i2c_addr_lin_to_tag( MfUltralightPoller* instance, uint16_t lin_addr, diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c index 77dda81e1f13..3f956302e90f 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c @@ -1,343 +1,288 @@ #include "mf_ultralight_poller_i.h" +#include + #include #define MF_ULTRALIGHT_POLLER_COMPLETE_EVENT (1UL << 0) +typedef enum { + MfUltralightPollerCmdTypeReadPage, + MfUltralightPollerCmdTypeWritePage, + MfUltralightPollerCmdTypeReadVersion, + MfUltralightPollerCmdTypeReadSignature, + MfUltralightPollerCmdTypeReadCounter, + MfUltralightPollerCmdTypeReadTearingFlag, + + MfUltralightPollerCmdTypeNum, +} MfUltralightPollerCmdType; + typedef struct { - MfUltralightPoller* instance; + MfUltralightPollerCmdType cmd_type; FuriThreadId thread_id; MfUltralightError error; MfUltralightPollerContextData data; } MfUltralightPollerContext; -static NfcaPollerCommand mf_ultraight_read_page_callback(NfcaPollerEvent event, void* context) { - furi_assert(context); - - MfUltralightPollerContext* poller_context = context; - if(event.type == NfcaPollerEventTypeReady) { - poller_context->error = mf_ultralight_poller_async_read_page( - poller_context->instance, - poller_context->data.read_cmd.start_page, - &poller_context->data.read_cmd.data); - nfca_poller_halt(poller_context->instance->nfca_poller); - } else if(event.type == NfcaPollerEventTypeError) { - poller_context->error = mf_ultralight_process_error(event.data.error); - } - furi_thread_flags_set(poller_context->thread_id, MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); +typedef MfUltralightError (*MfUltralightPollerCmdHandler)( + MfUltralightPoller* poller, + MfUltralightPollerContextData* data); - return NfcaPollerCommandStop; +MfUltralightError mf_ultralight_poller_read_page_handler( + MfUltralightPoller* poller, + MfUltralightPollerContextData* data) { + return mf_ultralight_poller_async_read_page( + poller, data->read_cmd.start_page, &data->read_cmd.data); } -MfUltralightError mf_ultralight_poller_read_page( - MfUltralightPoller* instance, - uint16_t page, - MfUltralightPage* data) { - furi_assert(instance); - furi_assert(data); +MfUltralightError mf_ultralight_poller_write_page_handler( + MfUltralightPoller* poller, + MfUltralightPollerContextData* data) { + return mf_ultralight_poller_async_write_page( + poller, data->write_cmd.page_to_write, &data->write_cmd.page); +} - MfUltralightPollerContext poller_context = {}; - poller_context.data.read_cmd.start_page = page; - poller_context.instance = instance; - poller_context.thread_id = furi_thread_get_current_id(); +MfUltralightError mf_ultralight_poller_read_version_handler( + MfUltralightPoller* poller, + MfUltralightPollerContextData* data) { + return mf_ultralight_poller_async_read_version(poller, &data->version); +} - mf_ultralight_poller_start(instance, mf_ultraight_read_page_callback, &poller_context); - furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); +MfUltralightError mf_ultralight_poller_read_signature_handler( + MfUltralightPoller* poller, + MfUltralightPollerContextData* data) { + return mf_ultralight_poller_async_read_signature(poller, &data->signature); +} - if(poller_context.error == MfUltralightErrorNone) { - *data = poller_context.data.read_cmd.data.page[0]; - } - mf_ultralight_poller_stop(instance); +MfUltralightError mf_ultralight_poller_read_counter_handler( + MfUltralightPoller* poller, + MfUltralightPollerContextData* data) { + return mf_ultralight_poller_async_read_counter( + poller, data->counter_cmd.counter_num, &data->counter_cmd.data); +} - return poller_context.error; +MfUltralightError mf_ultralight_poller_read_tearing_flag_handler( + MfUltralightPoller* poller, + MfUltralightPollerContextData* data) { + return mf_ultralight_poller_async_read_tearing_flag( + poller, data->tearing_flag_cmd.tearing_flag_num, &data->tearing_flag_cmd.data); } -NfcCommand mf_ultralight_poller_read_page_new_callback(NfcPollerEvent event, void* context) { +static const MfUltralightPollerCmdHandler + mf_ultralight_poller_cmd_handlers[MfUltralightPollerCmdTypeNum] = { + [MfUltralightPollerCmdTypeReadPage] = mf_ultralight_poller_read_page_handler, + [MfUltralightPollerCmdTypeWritePage] = mf_ultralight_poller_write_page_handler, + [MfUltralightPollerCmdTypeReadVersion] = mf_ultralight_poller_read_version_handler, + [MfUltralightPollerCmdTypeReadSignature] = mf_ultralight_poller_read_signature_handler, + [MfUltralightPollerCmdTypeReadCounter] = mf_ultralight_poller_read_counter_handler, + [MfUltralightPollerCmdTypeReadTearingFlag] = + mf_ultralight_poller_read_tearing_flag_handler, +}; + +static NfcCommand mf_ultralgiht_poller_cmd_callback(NfcPollerEvent event, void* context) { furi_assert(event.poller); - furi_assert(event.protocol_type == NfcProtocolTypeMfUltralight); + furi_assert(event.protocol_type == NfcProtocolTypeIso14443_3a); furi_assert(event.data); furi_assert(context); MfUltralightPollerContext* poller_context = context; NfcaPollerEvent* nfca_event = event.data; - MfUltralightPoller* mfu_poller = event.poller; + NfcaPoller* nfca_poller = event.poller; + MfUltralightPoller* mfu_poller = mf_ultralight_poller_alloc(nfca_poller); if(nfca_event->type == NfcaPollerEventTypeReady) { - poller_context->error = mf_ultralight_poller_async_read_page( - mfu_poller, - poller_context->data.read_cmd.start_page, - &poller_context->data.read_cmd.data); - nfca_poller_halt(mfu_poller->nfca_poller); + poller_context->error = mf_ultralight_poller_cmd_handlers[poller_context->cmd_type]( + mfu_poller, &poller_context->data); } else if(nfca_event->type == NfcaPollerEventTypeError) { poller_context->error = mf_ultralight_process_error(nfca_event->data.error); } + furi_thread_flags_set(poller_context->thread_id, MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); + mf_ultralight_poller_free(mfu_poller); + return NfcCommandStop; } -MfUltralightError mf_ultralight_poller_read_page_new( - NfcPollerManager* poller_manager, - uint16_t page, - MfUltralightPage* data) { - furi_assert(poller_manager); - furi_assert(data); +static MfUltralightError + mf_ultralight_poller_cmd_execute(Nfc* nfc, MfUltralightPollerContext* poller_ctx) { + furi_assert(poller_ctx->cmd_type < MfUltralightPollerCmdTypeNum); - MfUltralightPollerContext poller_context = {}; - poller_context.data.read_cmd.start_page = page; - poller_context.thread_id = furi_thread_get_current_id(); + poller_ctx->thread_id = furi_thread_get_current_id(); + NfcPollerManager* poller_manager = nfc_poller_manager_alloc(nfc); nfc_poller_manager_start( - poller_manager, - NfcProtocolTypeMfUltralight, - mf_ultralight_poller_read_page_new_callback, - &poller_context); + poller_manager, NfcProtocolTypeIso14443_3a, mf_ultralgiht_poller_cmd_callback, poller_ctx); furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); - - if(poller_context.error == MfUltralightErrorNone) { - *data = poller_context.data.read_cmd.data.page[0]; - } - + furi_thread_flags_clear(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); nfc_poller_manager_stop(poller_manager); - return poller_context.error; -} - -static NfcaPollerCommand mf_ultraight_write_page_callback(NfcaPollerEvent event, void* context) { - furi_assert(context); - - MfUltralightPollerContext* poller_context = context; - if(event.type == NfcaPollerEventTypeReady) { - poller_context->error = mf_ultralight_poller_async_write_page( - poller_context->instance, - poller_context->data.write_cmd.page_to_write, - &poller_context->data.write_cmd.page); - nfca_poller_halt(poller_context->instance->nfca_poller); - } else if(event.type == NfcaPollerEventTypeError) { - poller_context->error = mf_ultralight_process_error(event.data.error); - } - furi_thread_flags_set(poller_context->thread_id, MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); + nfc_poller_manager_free(poller_manager); - return NfcaPollerCommandStop; + return poller_ctx->error; } -MfUltralightError mf_ultralight_poller_write_page( - MfUltralightPoller* instance, - uint16_t page, - MfUltralightPage* data) { - furi_assert(instance); +MfUltralightError mf_ultralight_poller_read_page(Nfc* nfc, uint16_t page, MfUltralightPage* data) { + furi_assert(nfc); furi_assert(data); - MfUltralightPollerContext poller_context = {}; - poller_context.data.write_cmd.page_to_write = page; - poller_context.data.write_cmd.page = *data; - poller_context.instance = instance; - poller_context.thread_id = furi_thread_get_current_id(); - - mf_ultralight_poller_start(instance, mf_ultraight_write_page_callback, &poller_context); - furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); - mf_ultralight_poller_stop(instance); - - return poller_context.error; -} + MfUltralightPollerContext poller_context = { + .cmd_type = MfUltralightPollerCmdTypeReadPage, + .data.read_cmd.start_page = page, + }; -static NfcaPollerCommand mf_ultraight_read_version_callback(NfcaPollerEvent event, void* context) { - furi_assert(context); + MfUltralightError error = mf_ultralight_poller_cmd_execute(nfc, &poller_context); - MfUltralightPollerContext* poller_context = context; - if(event.type == NfcaPollerEventTypeReady) { - poller_context->error = mf_ultralight_poller_async_read_version( - poller_context->instance, &poller_context->data.version); - nfca_poller_halt(poller_context->instance->nfca_poller); - } else if(event.type == NfcaPollerEventTypeError) { - poller_context->error = mf_ultralight_process_error(event.data.error); + if(error == MfUltralightErrorNone) { + *data = poller_context.data.read_cmd.data.page[0]; } - furi_thread_flags_set(poller_context->thread_id, MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); - return NfcaPollerCommandStop; + return error; } MfUltralightError - mf_ultralight_poller_read_version(MfUltralightPoller* instance, MfUltralightVersion* data) { - furi_assert(instance); + mf_ultralight_poller_write_page(Nfc* nfc, uint16_t page, MfUltralightPage* data) { + furi_assert(nfc); furi_assert(data); - MfUltralightPollerContext poller_context = {}; - poller_context.instance = instance; - poller_context.thread_id = furi_thread_get_current_id(); - mf_ultralight_poller_start(instance, mf_ultraight_read_version_callback, &poller_context); - furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); + MfUltralightPollerContext poller_context = { + .cmd_type = MfUltralightPollerCmdTypeWritePage, + .data.write_cmd = + { + .page_to_write = page, + .page = *data, + }, + }; - if(poller_context.error == MfUltralightErrorNone) { - *data = poller_context.data.version; - } - mf_ultralight_poller_stop(instance); + MfUltralightError error = mf_ultralight_poller_cmd_execute(nfc, &poller_context); - return poller_context.error; + return error; } -static NfcaPollerCommand - mf_ultraight_read_signature_callback(NfcaPollerEvent event, void* context) { - furi_assert(context); +MfUltralightError mf_ultralight_poller_read_version(Nfc* nfc, MfUltralightVersion* data) { + furi_assert(nfc); + furi_assert(data); - MfUltralightPollerContext* poller_context = context; - if(event.type == NfcaPollerEventTypeReady) { - poller_context->error = mf_ultralight_poller_async_read_signature( - poller_context->instance, &poller_context->data.signature); - nfca_poller_halt(poller_context->instance->nfca_poller); - } else if(event.type == NfcaPollerEventTypeError) { - poller_context->error = mf_ultralight_process_error(event.data.error); + MfUltralightPollerContext poller_context = { + .cmd_type = MfUltralightPollerCmdTypeReadVersion, + }; + + MfUltralightError error = mf_ultralight_poller_cmd_execute(nfc, &poller_context); + + if(error == MfUltralightErrorNone) { + *data = poller_context.data.version; } - furi_thread_flags_set(poller_context->thread_id, MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); - return NfcaPollerCommandStop; + return error; } -MfUltralightError - mf_ultralight_poller_read_signature(MfUltralightPoller* instance, MfUltralightSignature* data) { - furi_assert(instance); +MfUltralightError mf_ultralight_poller_read_signature(Nfc* nfc, MfUltralightSignature* data) { + furi_assert(nfc); furi_assert(data); - MfUltralightPollerContext poller_context = {}; - poller_context.instance = instance; - poller_context.thread_id = furi_thread_get_current_id(); + MfUltralightPollerContext poller_context = { + .cmd_type = MfUltralightPollerCmdTypeReadSignature, + }; - mf_ultralight_poller_start(instance, mf_ultraight_read_signature_callback, &poller_context); - furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); + MfUltralightError error = mf_ultralight_poller_cmd_execute(nfc, &poller_context); - if(poller_context.error == MfUltralightErrorNone) { + if(error == MfUltralightErrorNone) { *data = poller_context.data.signature; } - mf_ultralight_poller_stop(instance); - - return poller_context.error; -} - -static NfcaPollerCommand mf_ultraight_read_counter_callback(NfcaPollerEvent event, void* context) { - furi_assert(context); - - MfUltralightPollerContext* poller_context = context; - if(event.type == NfcaPollerEventTypeReady) { - poller_context->error = mf_ultralight_poller_async_read_counter( - poller_context->instance, - poller_context->data.counter_cmd.counter_num, - &poller_context->data.counter_cmd.data); - nfca_poller_halt(poller_context->instance->nfca_poller); - } else if(event.type == NfcaPollerEventTypeError) { - poller_context->error = mf_ultralight_process_error(event.data.error); - } - furi_thread_flags_set(poller_context->thread_id, MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); - return NfcaPollerCommandStop; + return error; } -MfUltralightError mf_ultralight_poller_read_counter( - MfUltralightPoller* instance, - uint8_t counter_num, - MfUltralightCounter* data) { - furi_assert(instance); +MfUltralightError + mf_ultralight_poller_read_counter(Nfc* nfc, uint8_t counter_num, MfUltralightCounter* data) { + furi_assert(nfc); furi_assert(data); - MfUltralightPollerContext poller_context = {}; - poller_context.data.counter_cmd.counter_num = counter_num; - poller_context.instance = instance; - poller_context.thread_id = furi_thread_get_current_id(); + MfUltralightPollerContext poller_context = { + .cmd_type = MfUltralightPollerCmdTypeReadCounter, + .data.counter_cmd.counter_num = counter_num, + }; - mf_ultralight_poller_start(instance, mf_ultraight_read_counter_callback, &poller_context); - furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); + MfUltralightError error = mf_ultralight_poller_cmd_execute(nfc, &poller_context); - if(poller_context.error == MfUltralightErrorNone) { + if(error == MfUltralightErrorNone) { *data = poller_context.data.counter_cmd.data; } - mf_ultralight_poller_stop(instance); - - return poller_context.error; -} - -static NfcaPollerCommand - mf_ultraight_read_tering_flag_callback(NfcaPollerEvent event, void* context) { - furi_assert(context); - - MfUltralightPollerContext* poller_context = context; - if(event.type == NfcaPollerEventTypeReady) { - poller_context->error = mf_ultralight_poller_async_read_tearing_flag( - poller_context->instance, - poller_context->data.tearing_flag_cmd.tearing_flag_num, - &poller_context->data.tearing_flag_cmd.data); - nfca_poller_halt(poller_context->instance->nfca_poller); - } else if(event.type == NfcaPollerEventTypeError) { - poller_context->error = mf_ultralight_process_error(event.data.error); - } - furi_thread_flags_set(poller_context->thread_id, MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); - return NfcaPollerCommandStop; + return error; } MfUltralightError mf_ultralight_poller_read_tearing_flag( - MfUltralightPoller* instance, + Nfc* nfc, uint8_t flag_num, MfUltralightTearingFlag* data) { - furi_assert(instance); + furi_assert(nfc); furi_assert(data); - MfUltralightPollerContext poller_context = {}; - poller_context.data.tearing_flag_cmd.tearing_flag_num = flag_num; - poller_context.instance = instance; - poller_context.thread_id = furi_thread_get_current_id(); + MfUltralightPollerContext poller_context = { + .cmd_type = MfUltralightPollerCmdTypeReadTearingFlag, + .data.tearing_flag_cmd.tearing_flag_num = flag_num, + }; - mf_ultralight_poller_start(instance, mf_ultraight_read_tering_flag_callback, &poller_context); - furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); + MfUltralightError error = mf_ultralight_poller_cmd_execute(nfc, &poller_context); - if(poller_context.error == MfUltralightErrorNone) { + if(error == MfUltralightErrorNone) { *data = poller_context.data.tearing_flag_cmd.data; } - mf_ultralight_poller_stop(instance); - return poller_context.error; + return error; } -static MfUltralightPollerCommand - mf_ultralight_poller_read_callback(MfUltralightPollerEvent event, void* context) { +static NfcCommand mf_ultralight_poller_read_callback(NfcPollerEvent event, void* context) { furi_assert(context); + furi_assert(event.poller); + furi_assert(event.data); + furi_assert(event.protocol_type == NfcProtocolTypeMfUltralight); + NfcCommand command = NfcCommandContinue; MfUltralightPollerContext* poller_context = context; - MfUltralightPollerCommand command = MfUltralightPollerCommandContinue; + MfUltralightPoller* mfu_poller = event.poller; + MfUltralightPollerEvent* mfu_event = event.data; - if(event.type == MfUltralightPollerEventTypeReadSuccess) { - mf_ultralight_copy( - &poller_context->data.data, mf_ultralight_poller_get_data(poller_context->instance)); + if(mfu_event->type == MfUltralightPollerEventTypeReadSuccess) { + mf_ultralight_copy(&poller_context->data.data, mf_ultralight_poller_get_data(mfu_poller)); poller_context->error = MfUltralightErrorNone; - command = MfUltralightPollerCommandStop; - } else if(event.type == MfUltralightPollerEventTypeReadFailed) { - poller_context->error = event.data->error; - command = MfUltralightPollerCommandStop; - } else if(event.type == MfUltralightPollerEventTypeAuthRequest) { - event.data->auth_context.skip_auth = true; + command = NfcCommandStop; + } else if(mfu_event->type == MfUltralightPollerEventTypeReadFailed) { + poller_context->error = mfu_event->data->error; + command = NfcCommandStop; + } else if(mfu_event->type == MfUltralightPollerEventTypeAuthRequest) { + mfu_event->data->auth_context.skip_auth = true; } - if(command == MfUltralightPollerCommandStop) { + if(command == NfcCommandStop) { furi_thread_flags_set(poller_context->thread_id, MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); } return command; } -MfUltralightError - mf_ultralight_poller_read_card(MfUltralightPoller* instance, MfUltralightData* data) { - furi_assert(instance); +MfUltralightError mf_ultralight_poller_read_card(Nfc* nfc, MfUltralightData* data) { + furi_assert(nfc); furi_assert(data); MfUltralightPollerContext poller_context = {}; - poller_context.instance = instance; poller_context.thread_id = furi_thread_get_current_id(); + NfcPollerManager* poller_manager = nfc_poller_manager_alloc(nfc); - mf_ultralight_poller_read(instance, mf_ultralight_poller_read_callback, &poller_context); + nfc_poller_manager_start( + poller_manager, + NfcProtocolTypeMfUltralight, + mf_ultralight_poller_read_callback, + &poller_context); furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); + furi_thread_flags_clear(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); + nfc_poller_manager_stop(poller_manager); + nfc_poller_manager_free(poller_manager); if(poller_context.error == MfUltralightErrorNone) { mf_ultralight_copy(data, &poller_context.data.data); } - mf_ultralight_poller_stop(instance); return poller_context.error; } diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.h new file mode 100644 index 000000000000..a0124ae09218 --- /dev/null +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.h @@ -0,0 +1,30 @@ +#pragma once + +#include "mf_ultralight.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +MfUltralightError mf_ultralight_poller_read_page(Nfc* nfc, uint16_t page, MfUltralightPage* data); + +MfUltralightError mf_ultralight_poller_write_page(Nfc* nfc, uint16_t page, MfUltralightPage* data); + +MfUltralightError mf_ultralight_poller_read_version(Nfc* nfc, MfUltralightVersion* data); + +MfUltralightError mf_ultralight_poller_read_signature(Nfc* nfc, MfUltralightSignature* data); + +MfUltralightError + mf_ultralight_poller_read_counter(Nfc* nfc, uint8_t counter_num, MfUltralightCounter* data); + +MfUltralightError mf_ultralight_poller_read_tearing_flag( + Nfc* nfc, + uint8_t flag_num, + MfUltralightTearingFlag* data); + +MfUltralightError mf_ultralight_poller_read_card(Nfc* nfc, MfUltralightData* data); + +#ifdef __cplusplus +} +#endif From 01865f100582e5285f418d0eecea4b5da84544f9 Mon Sep 17 00:00:00 2001 From: gornekich Date: Tue, 27 Jun 2023 18:22:23 +0400 Subject: [PATCH 112/149] Nfc poller (#2804) * nfc: separate nfc poller base and common * nfc: rework nfc poller state machine * nfc: rework poller manager to nfc_poller * nfca: rework sync api * mfc: move sync api to separate header * nfc mfc: rework mfc poller * nfc nfca: rework poller * nfc app: get poller data in one place * nfc poller: make get_data private function * nfc rpc: remove unused code --- .../nfc/helpers/handlers/nfc_poller_handler.c | 61 ++-- .../nfc/helpers/handlers/nfc_poller_handler.h | 4 +- applications/main/nfc/nfc_app.c | 6 - applications/main/nfc/nfc_app_i.h | 6 +- applications/main/nfc/plugins/troika.c | 25 +- .../scenes/nfc_scene_mf_classic_dict_attack.c | 63 ++-- applications/main/nfc/scenes/nfc_scene_read.c | 7 +- applications/main/nfc_rpc/nfc_rpc.c | 4 - applications/main/nfc_rpc/nfc_rpc_i.h | 3 - .../main/nfc_rpc/nfc_rpc_mf_classic.c | 9 +- applications/main/nfc_rpc/nfc_rpc_nfca.c | 6 +- firmware/targets/f7/api_symbols.csv | 29 +- lib/nfc/nfc.c | 219 ++++++-------- lib/nfc/nfc.h | 3 +- lib/nfc/nfc_poller.c | 209 +++++++++++++ lib/nfc/nfc_poller.h | 25 ++ lib/nfc/nfc_poller_manager.c | 167 ----------- lib/nfc/nfc_poller_manager.h | 25 -- lib/nfc/nfc_scanner.c | 95 +----- .../iso14443_4a/iso14443_4a_poller.c | 2 + .../iso14443_4a/iso14443_4a_poller.h | 2 - .../iso14443_4a/iso14443_4a_poller_i.h | 2 + .../protocols/mf_classic/mf_classic_poller.c | 277 +++++++----------- .../protocols/mf_classic/mf_classic_poller.h | 51 ---- .../mf_classic/mf_classic_poller_defs.h | 5 + .../mf_classic/mf_classic_poller_i.h | 20 +- .../mf_classic/mf_classic_poller_sync_api.c | 179 ++++++----- .../mf_classic/mf_classic_poller_sync_api.h | 26 ++ .../protocols/mf_desfire/mf_desfire_poller.c | 2 + .../protocols/mf_desfire/mf_desfire_poller.h | 2 - .../mf_desfire/mf_desfire_poller_i.h | 2 + .../mf_ultralight/mf_ultralight_poller.c | 2 + .../mf_ultralight/mf_ultralight_poller.h | 2 - .../mf_ultralight/mf_ultralight_poller_i.h | 2 + .../mf_ultralight_poller_sync_api.c | 26 +- lib/nfc/protocols/nfc_poller_base.h | 24 +- lib/nfc/protocols/nfc_poller_common.h | 24 ++ lib/nfc/protocols/nfc_poller_defs.c | 3 +- lib/nfc/protocols/nfca/nfca_poller.c | 234 +++++---------- lib/nfc/protocols/nfca/nfca_poller.h | 27 +- lib/nfc/protocols/nfca/nfca_poller_i.c | 120 -------- lib/nfc/protocols/nfca/nfca_poller_i.h | 20 +- lib/nfc/protocols/nfca/nfca_poller_sync_api.c | 57 ++++ lib/nfc/protocols/nfca/nfca_poller_sync_api.h | 14 + 44 files changed, 917 insertions(+), 1174 deletions(-) create mode 100644 lib/nfc/nfc_poller.c create mode 100644 lib/nfc/nfc_poller.h delete mode 100644 lib/nfc/nfc_poller_manager.c delete mode 100644 lib/nfc/nfc_poller_manager.h create mode 100644 lib/nfc/protocols/mf_classic/mf_classic_poller_defs.h create mode 100644 lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.h create mode 100644 lib/nfc/protocols/nfc_poller_common.h create mode 100644 lib/nfc/protocols/nfca/nfca_poller_sync_api.c create mode 100644 lib/nfc/protocols/nfca/nfca_poller_sync_api.h diff --git a/applications/main/nfc/helpers/handlers/nfc_poller_handler.c b/applications/main/nfc/helpers/handlers/nfc_poller_handler.c index 54d4e61a3321..e6ecddb0774d 100644 --- a/applications/main/nfc/helpers/handlers/nfc_poller_handler.c +++ b/applications/main/nfc/helpers/handlers/nfc_poller_handler.c @@ -2,52 +2,41 @@ #include "../../nfc_app_i.h" -typedef NfcCustomEvent ( - *NfcPollerReadHandler)(NfcaPoller* poller, NfcaPollerEvent* event, NfcApp* nfc_app); +typedef NfcCustomEvent (*NfcPollerReadHandler)(NfcaPollerEvent* event, NfcApp* nfc_app); -static NfcCustomEvent nfc_poller_handler_read_iso14443_3a( - NfcaPoller* poller, - NfcaPollerEvent* event, - NfcApp* nfc_app) { +static NfcCustomEvent + nfc_poller_handler_read_iso14443_3a(NfcaPollerEvent* event, NfcApp* nfc_app) { + UNUSED(nfc_app); NfcCustomEvent custom_event = NfcCustomEventReadHandlerIgnore; if(event->type == NfcaPollerEventTypeReady) { - nfc_dev_set_protocol_data( - nfc_app->nfc_dev, NfcProtocolTypeIso14443_3a, nfca_poller_get_data(poller)); custom_event = NfcCustomEventReadHandlerSuccess; } return custom_event; } -static NfcCustomEvent nfc_poller_handler_read_iso14443_4a( - Iso14443_4aPoller* poller, - Iso14443_4aPollerEvent* event, - NfcApp* nfc_app) { +static NfcCustomEvent + nfc_poller_handler_read_iso14443_4a(Iso14443_4aPollerEvent* event, NfcApp* nfc_app) { + UNUSED(nfc_app); NfcCustomEvent custom_event = NfcCustomEventReadHandlerIgnore; if(event->type == Iso14443_4aPollerEventTypeReady) { - nfc_dev_set_protocol_data( - nfc_app->nfc_dev, NfcProtocolTypeIso14443_4a, iso14443_4a_poller_get_data(poller)); custom_event = NfcCustomEventReadHandlerSuccess; } return custom_event; } -static NfcCustomEvent nfc_poller_handler_read_mf_ultralight( - MfUltralightPoller* poller, - MfUltralightPollerEvent* event, - NfcApp* nfc_app) { +static NfcCustomEvent + nfc_poller_handler_read_mf_ultralight(MfUltralightPollerEvent* event, NfcApp* nfc_app) { NfcCustomEvent custom_event = NfcCustomEventReadHandlerIgnore; if(event->type == MfUltralightPollerEventTypeReadSuccess) { - nfc_dev_set_protocol_data( - nfc_app->nfc_dev, NfcProtocolTypeMfUltralight, mf_ultralight_poller_get_data(poller)); custom_event = NfcCustomEventReadHandlerSuccess; } else if(event->type == MfUltralightPollerEventTypeAuthRequest) { nfc_dev_set_protocol_data( - nfc_app->nfc_dev, NfcProtocolTypeMfUltralight, mf_ultralight_poller_get_data(poller)); + nfc_app->nfc_dev, NfcProtocolTypeMfUltralight, nfc_poller_get_data(nfc_app->poller)); const MfUltralightData* data = nfc_dev_get_protocol_data(nfc_app->nfc_dev, NfcProtocolTypeMfUltralight); if(nfc_app->mf_ul_auth->type == MfUltralightAuthTypeXiaomii) { @@ -75,11 +64,8 @@ static NfcCustomEvent nfc_poller_handler_read_mf_ultralight( return custom_event; } -static NfcCustomEvent nfc_poller_handler_read_mf_classic( - MfClassicPoller* poller, - MfClassicPollerEvent* event, - NfcApp* nfc_app) { - UNUSED(poller); +static NfcCustomEvent + nfc_poller_handler_read_mf_classic(MfClassicPollerEvent* event, NfcApp* nfc_app) { UNUSED(event); UNUSED(nfc_app); @@ -88,15 +74,12 @@ static NfcCustomEvent nfc_poller_handler_read_mf_classic( return custom_event; } -static NfcCustomEvent nfc_poller_handler_read_mf_desfire( - MfDesfirePoller* poller, - MfDesfirePollerEvent* event, - NfcApp* nfc_app) { +static NfcCustomEvent + nfc_poller_handler_read_mf_desfire(MfDesfirePollerEvent* event, NfcApp* nfc_app) { + UNUSED(nfc_app); NfcCustomEvent custom_event = NfcCustomEventReadHandlerIgnore; if(event->type == MfDesfirePollerEventTypeReadSuccess) { - nfc_dev_set_protocol_data( - nfc_app->nfc_dev, NfcProtocolTypeMfDesfire, mf_desfire_poller_get_data(poller)); custom_event = NfcCustomEventReadHandlerSuccess; } @@ -112,7 +95,19 @@ static const NfcPollerReadHandler nfc_poller_handlers_read[] = { }; NfcCustomEvent nfc_poller_handler_read(NfcPollerEvent event, void* context) { + furi_assert(context); + furi_assert(event.poller); + furi_assert(event.data); furi_assert(event.protocol_type < COUNT_OF(nfc_poller_handlers_read)); - return nfc_poller_handlers_read[event.protocol_type](event.poller, event.data, context); + NfcApp* nfc_app = context; + + NfcCustomEvent custom_event = + nfc_poller_handlers_read[event.protocol_type](event.data, context); + if(custom_event == NfcCustomEventReadHandlerSuccess) { + nfc_dev_set_protocol_data( + nfc_app->nfc_dev, event.protocol_type, nfc_poller_get_data(nfc_app->poller)); + } + + return custom_event; } diff --git a/applications/main/nfc/helpers/handlers/nfc_poller_handler.h b/applications/main/nfc/helpers/handlers/nfc_poller_handler.h index 14fdaeb436a9..10eee0dd9467 100644 --- a/applications/main/nfc/helpers/handlers/nfc_poller_handler.h +++ b/applications/main/nfc/helpers/handlers/nfc_poller_handler.h @@ -1,7 +1,7 @@ #pragma once -#include - #include "../nfc_custom_event.h" +#include + NfcCustomEvent nfc_poller_handler_read(NfcPollerEvent event, void* context); diff --git a/applications/main/nfc/nfc_app.c b/applications/main/nfc/nfc_app.c index be7db554459e..791ab71d5674 100644 --- a/applications/main/nfc/nfc_app.c +++ b/applications/main/nfc/nfc_app.c @@ -46,14 +46,11 @@ NfcApp* nfc_app_alloc() { instance->view_dispatcher, nfc_back_event_callback); instance->nfc = nfc_alloc(); - instance->nfca_poller = nfca_poller_alloc(instance->nfc); - instance->mf_classic_poller = mf_classic_poller_alloc(instance->nfca_poller); instance->nfca_listener = nfca_listener_alloc(instance->nfc); instance->mf_ul_listener = mf_ultralight_listener_alloc(instance->nfca_listener); instance->parsed_data = furi_string_alloc(); - instance->poller_manager = nfc_poller_manager_alloc(instance->nfc); instance->scanner = nfc_scanner_alloc(instance->nfc); instance->mf_ul_auth = mf_ultralight_auth_alloc(); @@ -156,12 +153,9 @@ void nfc_app_free(NfcApp* instance) { furi_string_free(instance->parsed_data); - mf_classic_poller_free(instance->mf_classic_poller); mf_ultralight_listener_free(instance->mf_ul_listener); nfca_listener_free(instance->nfca_listener); - nfca_poller_free(instance->nfca_poller); nfc_free(instance->nfc); - nfc_poller_manager_free(instance->poller_manager); nfc_scanner_free(instance->scanner); mf_ultralight_auth_free(instance->mf_ul_auth); diff --git a/applications/main/nfc/nfc_app_i.h b/applications/main/nfc/nfc_app_i.h index 9f9a2e32807d..0ebb90aa0e66 100644 --- a/applications/main/nfc/nfc_app_i.h +++ b/applications/main/nfc/nfc_app_i.h @@ -46,7 +46,7 @@ #include #include -#include +#include #include #include @@ -108,12 +108,10 @@ struct NfcApp { DetectReader* detect_reader; Nfc* nfc; - NfcaPoller* nfca_poller; NfcaListener* nfca_listener; MfUltralightListener* mf_ul_listener; - MfClassicPoller* mf_classic_poller; - NfcPollerManager* poller_manager; + NfcPoller* poller; NfcScanner* scanner; MfUltralightAuth* mf_ul_auth; diff --git a/applications/main/nfc/plugins/troika.c b/applications/main/nfc/plugins/troika.c index 0b4abdaf5506..dd9174cde62a 100644 --- a/applications/main/nfc/plugins/troika.c +++ b/applications/main/nfc/plugins/troika.c @@ -4,6 +4,7 @@ #include #include +#include #define TAG "Troika" @@ -30,18 +31,18 @@ bool troika_verify(void* poller) { furi_assert(poller); bool verified = false; - MfClassicPoller* mfc_poller = poller; - uint8_t sector = 11; - uint8_t block = mf_classic_get_sector_trailer_num_by_sector(sector); - MfClassicKey key = {.data = {0x08, 0xb3, 0x86, 0x46, 0x32, 0x29}}; - MfClassicAuthContext auth_context = {}; - - FURI_LOG_D("Troika", "Verifying sector %d", sector); - if(mf_classic_poller_auth(mfc_poller, block, &key, MfClassicKeyTypeA, &auth_context) == - MfClassicErrorNone) { - FURI_LOG_D(TAG, "Sector %d verified", sector); - verified = true; - } + // MfClassicPoller* mfc_poller = poller; + // uint8_t sector = 11; + // uint8_t block = mf_classic_get_sector_trailer_num_by_sector(sector); + // MfClassicKey key = {.data = {0x08, 0xb3, 0x86, 0x46, 0x32, 0x29}}; + // MfClassicAuthContext auth_context = {}; + + // FURI_LOG_D("Troika", "Verifying sector %d", sector); + // if(mf_classic_poller_auth(mfc_poller, block, &key, MfClassicKeyTypeA, &auth_context) == + // MfClassicErrorNone) { + // FURI_LOG_D(TAG, "Sector %d verified", sector); + // verified = true; + // } return verified; } diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c index 00276f2af559..06f423402a8d 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c @@ -9,62 +9,66 @@ typedef enum { DictAttackStateFlipperDictInProgress, } DictAttackState; -MfClassicPollerCommand nfc_dict_attack_worker_callback(MfClassicPollerEvent event, void* context) { +NfcCommand nfc_dict_attack_worker_callback(NfcPollerEvent event, void* context) { furi_assert(context); + furi_assert(event.data); + furi_assert(event.poller); + furi_assert(event.protocol_type == NfcProtocolTypeMfClassic); - MfClassicPollerCommand command = MfClassicPollerCommandContinue; + NfcCommand command = NfcCommandContinue; + MfClassicPollerEvent* mfc_event = event.data; NfcApp* nfc_app = context; - if(event.type == MfClassicPollerEventTypeStart) { - nfc_app->mf_dict_context.type = event.data->start_data.type; + if(mfc_event->type == MfClassicPollerEventTypeStart) { + nfc_app->mf_dict_context.type = mfc_event->data->start_data.type; view_dispatcher_send_custom_event( nfc_app->view_dispatcher, NfcCustomEventDictAttackCardDetected); - } else if(event.type == MfClassicPollerEventTypeCardDetected) { + } else if(mfc_event->type == MfClassicPollerEventTypeCardDetected) { view_dispatcher_send_custom_event( nfc_app->view_dispatcher, NfcCustomEventDictAttackCardDetected); - } else if(event.type == MfClassicPollerEventTypeCardNotDetected) { + } else if(mfc_event->type == MfClassicPollerEventTypeCardNotDetected) { view_dispatcher_send_custom_event( nfc_app->view_dispatcher, NfcCustomEventDictAttackCardNotDetected); - } else if(event.type == MfClassicPollerEventTypeRequestKey) { + } else if(mfc_event->type == MfClassicPollerEventTypeRequestKey) { MfClassicKey key = {}; if(mf_dict_get_next_key(nfc_app->mf_dict_context.dict, &key)) { - event.data->key_request_data.key = key; - event.data->key_request_data.key_provided = true; + mfc_event->data->key_request_data.key = key; + mfc_event->data->key_request_data.key_provided = true; nfc_app->mf_dict_context.current_key++; if(nfc_app->mf_dict_context.current_key % 10 == 0) { view_dispatcher_send_custom_event( nfc_app->view_dispatcher, NfcCustomEventDictAttackNewKeyBatch); } } else { - event.data->key_request_data.key_provided = false; + mfc_event->data->key_request_data.key_provided = false; } - } else if(event.type == MfClassicPollerEventTypeNewSector) { + } else if(mfc_event->type == MfClassicPollerEventTypeNewSector) { view_dispatcher_send_custom_event( nfc_app->view_dispatcher, NfcCustomEventDictAttackNewSector); mf_dict_rewind(nfc_app->mf_dict_context.dict); nfc_app->mf_dict_context.current_key = 0; - } else if(event.type == MfClassicPollerEventTypeFoundKeyA) { + } else if(mfc_event->type == MfClassicPollerEventTypeFoundKeyA) { view_dispatcher_send_custom_event( nfc_app->view_dispatcher, NfcCustomEventDictAttackFoundKeyA); - } else if(event.type == MfClassicPollerEventTypeFoundKeyB) { + } else if(mfc_event->type == MfClassicPollerEventTypeFoundKeyB) { view_dispatcher_send_custom_event( nfc_app->view_dispatcher, NfcCustomEventDictAttackFoundKeyB); - } else if(event.type == MfClassicPollerEventTypeKeyAttackStart) { - nfc_app->mf_dict_context.current_sector = event.data->key_attack_data.start_sector; + } else if(mfc_event->type == MfClassicPollerEventTypeKeyAttackStart) { + nfc_app->mf_dict_context.current_sector = mfc_event->data->key_attack_data.start_sector; view_dispatcher_send_custom_event( nfc_app->view_dispatcher, NfcCustomEventDictAttackKeyAttackStart); - } else if(event.type == MfClassicPollerEventTypeKeyAttackStop) { + } else if(mfc_event->type == MfClassicPollerEventTypeKeyAttackStop) { mf_dict_rewind(nfc_app->mf_dict_context.dict); nfc_app->mf_dict_context.current_key = 0; view_dispatcher_send_custom_event( nfc_app->view_dispatcher, NfcCustomEventDictAttackKeyAttackStop); - } else if(event.type == MfClassicPollerEventTypeKeyAttackNextSector) { + } else if(mfc_event->type == MfClassicPollerEventTypeKeyAttackNextSector) { view_dispatcher_send_custom_event( nfc_app->view_dispatcher, NfcCustomEventDictAttackKeyAttackNextSector); - } else if(event.type == MfClassicPollerEventTypeReadComplete) { + } else if(mfc_event->type == MfClassicPollerEventTypeReadComplete) { view_dispatcher_send_custom_event( nfc_app->view_dispatcher, NfcCustomEventDictAttackComplete); - command = MfClassicPollerCommandStop; + command = NfcCommandStop; } return command; @@ -127,7 +131,9 @@ void nfc_scene_mf_classic_dict_attack_on_enter(void* context) { view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDictAttack); nfc_blink_read_start(nfc); notification_message(nfc->notifications, &sequence_display_backlight_enforce_on); - mf_classic_poller_dict_attack(nfc->mf_classic_poller, nfc_dict_attack_worker_callback, nfc); + + nfc->poller = nfc_poller_alloc(nfc->nfc, NfcProtocolTypeMfClassic); + nfc_poller_start(nfc->poller, nfc_dict_attack_worker_callback, nfc); } bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent event) { @@ -161,26 +167,22 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent consumed = true; } else if(event.event == NfcCustomEventDictAttackNewSector) { nfc_dev_set_protocol_data( - nfc->nfc_dev, - NfcProtocolTypeMfClassic, - mf_classic_poller_get_data(nfc->mf_classic_poller)); + nfc->nfc_dev, NfcProtocolTypeMfClassic, nfc_poller_get_data(nfc->poller)); nfc_scene_mf_classic_dict_attack_update_view(nfc); dict_attack_inc_current_sector(nfc->dict_attack); consumed = true; } else if(event.event == NfcCustomEventDictAttackNewKeyBatch) { nfc_dev_set_protocol_data( - nfc->nfc_dev, - NfcProtocolTypeMfClassic, - mf_classic_poller_get_data(nfc->mf_classic_poller)); + nfc->nfc_dev, NfcProtocolTypeMfClassic, nfc_poller_get_data(nfc->poller)); nfc_scene_mf_classic_dict_attack_update_view(nfc); dict_attack_inc_current_dict_key(nfc->dict_attack, 10); consumed = true; } else if(event.event == NfcCustomEventDictAttackSkip) { if(state == DictAttackStateUserDictInProgress) { - mf_classic_poller_stop(nfc->mf_classic_poller); + nfc_poller_stop(nfc->poller); consumed = true; } else if(state == DictAttackStateFlipperDictInProgress) { - mf_classic_poller_stop(nfc->mf_classic_poller); + nfc_poller_stop(nfc->poller); consumed = true; } } else if(event.event == NfcCustomEventDictAttackKeyAttackStart) { @@ -200,7 +202,10 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent void nfc_scene_mf_classic_dict_attack_on_exit(void* context) { NfcApp* nfc = context; - mf_classic_poller_stop(nfc->mf_classic_poller); + + nfc_poller_stop(nfc->poller); + nfc_poller_free(nfc->poller); + nfc_blink_stop(nfc); notification_message(nfc->notifications, &sequence_display_backlight_enforce_auto); } diff --git a/applications/main/nfc/scenes/nfc_scene_read.c b/applications/main/nfc/scenes/nfc_scene_read.c index dc7f81e2ba6d..0234f3893ca8 100644 --- a/applications/main/nfc/scenes/nfc_scene_read.c +++ b/applications/main/nfc/scenes/nfc_scene_read.c @@ -21,8 +21,8 @@ void nfc_scene_read_on_enter(void* context) { const NfcProtocolType protocol_type = instance->protocols_detected[instance->protocols_detected_idx]; - nfc_poller_manager_start( - instance->poller_manager, protocol_type, nfc_scene_read_poller_callback, instance); + instance->poller = nfc_poller_alloc(instance->nfc, protocol_type); + nfc_poller_start(instance->poller, nfc_scene_read_poller_callback, instance); nfc_blink_detect_start(instance); } @@ -61,7 +61,8 @@ bool nfc_scene_read_on_event(void* context, SceneManagerEvent event) { void nfc_scene_read_on_exit(void* context) { NfcApp* instance = context; - nfc_poller_manager_stop(instance->poller_manager); + nfc_poller_stop(instance->poller); + nfc_poller_free(instance->poller); popup_reset(instance->popup); nfc_blink_stop(instance); diff --git a/applications/main/nfc_rpc/nfc_rpc.c b/applications/main/nfc_rpc/nfc_rpc.c index 7a6a60a7fe64..3d14dc9b9f87 100644 --- a/applications/main/nfc_rpc/nfc_rpc.c +++ b/applications/main/nfc_rpc/nfc_rpc.c @@ -135,10 +135,8 @@ static NfcRpc* nfc_rpc_app_alloc() { NfcRpc* instance = malloc(sizeof(NfcRpc)); instance->nfc = nfc_alloc(); - instance->nfca_poller = nfca_poller_alloc(instance->nfc); instance->nfca_listener = nfca_listener_alloc(instance->nfc); instance->mf_ul_listener = mf_ultralight_listener_alloc(instance->nfca_listener); - instance->mf_classic_poller = mf_classic_poller_alloc(instance->nfca_poller); NfcRpcHandlerDict_init(instance->handlers); for(size_t i = 0; i < COUNT_OF(nfc_rpc_callbacks); i++) { @@ -173,10 +171,8 @@ static NfcRpc* nfc_rpc_app_alloc() { void nfc_rpc_app_free(NfcRpc* instance) { furi_assert(instance); - mf_classic_poller_free(instance->mf_classic_poller); mf_ultralight_listener_free(instance->mf_ul_listener); nfca_listener_free(instance->nfca_listener); - nfca_poller_free(instance->nfca_poller); nfc_free(instance->nfc); for(size_t i = 0; i < COUNT_OF(nfc_rpc_callbacks); i++) { diff --git a/applications/main/nfc_rpc/nfc_rpc_i.h b/applications/main/nfc_rpc/nfc_rpc_i.h index c8a60c007601..19a78ed80d86 100644 --- a/applications/main/nfc_rpc/nfc_rpc_i.h +++ b/applications/main/nfc_rpc/nfc_rpc_i.h @@ -19,7 +19,6 @@ #include #include #include -#include typedef void (*NfcRpcHandler)(Nfc_Main* cmd, void* context); @@ -55,10 +54,8 @@ struct NfcRpc { NfcRpcHandlerDict_t handlers; Nfc* nfc; - NfcaPoller* nfca_poller; NfcaListener* nfca_listener; MfUltralightListener* mf_ul_listener; - MfClassicPoller* mf_classic_poller; }; typedef struct { diff --git a/applications/main/nfc_rpc/nfc_rpc_mf_classic.c b/applications/main/nfc_rpc/nfc_rpc_mf_classic.c index 88bc0785f7d0..5e0799c0e200 100644 --- a/applications/main/nfc_rpc/nfc_rpc_mf_classic.c +++ b/applications/main/nfc_rpc/nfc_rpc_mf_classic.c @@ -1,6 +1,7 @@ #include "nfc_rpc_i.h" #include "assets/compiled/mf_classic.pb.h" +#include #define TAG "NfcRpcMfClassic" @@ -45,8 +46,8 @@ static void nfc_rpc_mf_classic_auth(Nfc_Main* cmd, void* context) { memcpy(key.data, req->key.bytes, sizeof(MfClassicKey)); MfClassicKeyType key_type = (req->key_type == PB_MfClassic_KeyType_KeyTypeB) ? MfClassicKeyTypeB : MfClassicKeyTypeA; - MfClassicError error = mf_classic_poller_auth( - instance->mf_classic_poller, req->block, &key, key_type, &auth_context); + MfClassicError error = + mf_classic_poller_auth(instance->nfc, req->block, &key, key_type, &auth_context); cmd->command_status = Nfc_CommandStatus_OK; cmd->which_content = Nfc_Main_mf_classic_auth_resp_tag; @@ -85,8 +86,8 @@ static void nfc_rpc_mf_classic_read_block(Nfc_Main* cmd, void* context) { MfClassicKeyType key_type = (req->key_type == PB_MfClassic_KeyType_KeyTypeB) ? MfClassicKeyTypeB : MfClassicKeyTypeA; MfClassicBlock block = {}; - MfClassicError error = mf_classic_poller_read_block( - instance->mf_classic_poller, req->block, &key, key_type, &block); + MfClassicError error = + mf_classic_poller_read_block(instance->nfc, req->block, &key, key_type, &block); cmd->command_status = Nfc_CommandStatus_OK; cmd->which_content = Nfc_Main_mf_classic_read_block_resp_tag; diff --git a/applications/main/nfc_rpc/nfc_rpc_nfca.c b/applications/main/nfc_rpc/nfc_rpc_nfca.c index d7454b9c5d55..b15332f1fed8 100644 --- a/applications/main/nfc_rpc/nfc_rpc_nfca.c +++ b/applications/main/nfc_rpc/nfc_rpc_nfca.c @@ -1,7 +1,7 @@ #include "nfc_rpc_i.h" #include "assets/compiled/nfca.pb.h" -#include +#include #define TAG "NfcRpcNfca" @@ -49,7 +49,7 @@ static void nfc_rpc_nfca_read(Nfc_Main* cmd, void* context) { PB_Nfca_ReadResponse pb_nfca_read_resp = PB_Nfca_ReadResponse_init_default; NfcaData nfca_data = {}; - NfcaError error = nfca_poller_read(instance->nfca_poller, &nfca_data); + NfcaError error = nfca_poller_read(instance->nfc, &nfca_data); cmd->command_status = Nfc_CommandStatus_OK; cmd->which_content = Nfc_Main_nfca_read_resp_tag; @@ -64,8 +64,6 @@ static void nfc_rpc_nfca_read(Nfc_Main* cmd, void* context) { pb_nfca_read_resp.atqa.size = sizeof(nfca_data.atqa); } cmd->content.nfca_read_resp = pb_nfca_read_resp; - - nfca_poller_stop(instance->nfca_poller); } static void nfc_rpc_nfca_emulate_start(Nfc_Main* cmd, void* context) { diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index a4038a07eb43..c757219d9e74 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,+,30.1,, +Version,+,33.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -2008,16 +2008,6 @@ Function,+,mf_classic_is_key_found,_Bool,"const MfClassicData*, uint8_t, MfClass Function,+,mf_classic_is_sector_read,_Bool,"const MfClassicData*, uint8_t" Function,-,mf_classic_is_sector_trailer,_Bool,uint8_t Function,+,mf_classic_load,_Bool,"MfClassicData*, FlipperFormat*, uint32_t" -Function,-,mf_classic_poller_alloc,MfClassicPoller*,NfcaPoller* -Function,+,mf_classic_poller_auth,MfClassicError,"MfClassicPoller*, uint8_t, MfClassicKey*, MfClassicKeyType, MfClassicAuthContext*" -Function,-,mf_classic_poller_dict_attack,MfClassicError,"MfClassicPoller*, MfClassicPollerCallback, void*" -Function,-,mf_classic_poller_free,void,MfClassicPoller* -Function,+,mf_classic_poller_get_data,const MfClassicData*,MfClassicPoller* -Function,-,mf_classic_poller_read,MfClassicError,"MfClassicPoller*, MfClassicDeviceKeys*, MfClassicData*" -Function,-,mf_classic_poller_read_block,MfClassicError,"MfClassicPoller*, uint8_t, MfClassicKey*, MfClassicKeyType, MfClassicBlock*" -Function,-,mf_classic_poller_reset,MfClassicError,MfClassicPoller* -Function,-,mf_classic_poller_start,MfClassicError,"MfClassicPoller*, NfcaPollerEventCallback, void*" -Function,-,mf_classic_poller_stop,MfClassicError,MfClassicPoller* Function,+,mf_classic_reset,void,MfClassicData* Function,+,mf_classic_save,_Bool,"const MfClassicData*, FlipperFormat*, uint32_t" Function,-,mf_classic_set_block_read,void,"MfClassicData*, uint8_t, MfClassicBlock*" @@ -2056,10 +2046,12 @@ Function,-,nfc_listener_abort,void,Nfc* Function,-,nfc_listener_set_col_res_data,NfcError,"Nfc*, uint8_t*, uint8_t, uint8_t*, uint8_t" Function,-,nfc_listener_sleep,NfcError,Nfc* Function,-,nfc_listener_tx,NfcError,"Nfc*, const BitBuffer*" -Function,-,nfc_poller_manager_alloc,NfcPollerManager*,Nfc* -Function,-,nfc_poller_manager_free,void,NfcPollerManager* -Function,-,nfc_poller_manager_start,void,"NfcPollerManager*, NfcProtocolType, NfcPollerCallback, void*" -Function,-,nfc_poller_manager_stop,void,NfcPollerManager* +Function,-,nfc_poller_alloc,NfcPoller*,"Nfc*, NfcProtocolType" +Function,-,nfc_poller_detect,_Bool,NfcPoller* +Function,-,nfc_poller_free,void,NfcPoller* +Function,-,nfc_poller_get_data,const NfcProtocolData*,NfcPoller* +Function,-,nfc_poller_start,void,"NfcPoller*, NfcPollerCallback, void*" +Function,-,nfc_poller_stop,void,NfcPoller* Function,-,nfc_set_fdt_listen_fc,void,"Nfc*, uint32_t" Function,-,nfc_set_fdt_poll_fc,void,"Nfc*, uint32_t" Function,-,nfc_set_fdt_poll_poll_us,void,"Nfc*, uint32_t" @@ -2084,13 +2076,6 @@ Function,+,nfca_get_uid,const uint8_t*,"const NfcaData*, size_t*" Function,+,nfca_is_equal,_Bool,"const NfcaData*, const NfcaData*" Function,+,nfca_load,_Bool,"NfcaData*, FlipperFormat*, uint32_t" Function,+,nfca_load_data,_Bool,"NfcaData*, FlipperFormat*, uint32_t" -Function,-,nfca_poller_alloc,NfcaPoller*,Nfc* -Function,-,nfca_poller_free,void,NfcaPoller* -Function,+,nfca_poller_get_data,const NfcaData*,NfcaPoller* -Function,-,nfca_poller_read,NfcaError,"NfcaPoller*, NfcaData*" -Function,-,nfca_poller_read_new,NfcaError,"NfcPollerManager*, NfcaData*" -Function,-,nfca_poller_start,NfcaError,"NfcaPoller*, NfcaPollerEventCallback, void*" -Function,-,nfca_poller_stop,NfcaError,NfcaPoller* Function,+,nfca_reset,void,NfcaData* Function,+,nfca_save,_Bool,"const NfcaData*, FlipperFormat*, uint32_t" Function,+,nfca_save_data,_Bool,"const NfcaData*, FlipperFormat*, uint32_t" diff --git a/lib/nfc/nfc.c b/lib/nfc/nfc.c index 28731ea0c63b..5b591dbc2e40 100644 --- a/lib/nfc/nfc.c +++ b/lib/nfc/nfc.c @@ -11,16 +11,22 @@ typedef enum { NfcStateIdle, - NfcStateChipSleep, - NfcStateChipActive, - NfcStateConfigured, NfcStateFieldOn, - NfcStateFieldOff, NfcStateListenStarted, NfcStatePollerReady, NfcStatePollerReset, } NfcState; +typedef enum { + NfcPollerStateIdle, + NfcPollerStateStart, + NfcPollerStateReady, + NfcPollerStateReset, + NfcPollerStateStop, + + NfcPollerStateNum, +} NfcPollerState; + typedef enum { NfcCommStateIdle, NfcCommStateWaitBlockTxTimer, @@ -31,9 +37,16 @@ typedef enum { NfcCommStateFailed, } NfcCommState; +typedef enum { + NfcConfigurationStateIdle, + NfcConfigurationStateDone, +} NfcConfigurationState; + struct Nfc { NfcState state; + NfcPollerState poller_state; NfcCommState comm_state; + NfcConfigurationState config_state; uint32_t fdt_listen_fc; uint32_t mask_rx_time_fc; uint32_t fdt_poll_fc; @@ -122,74 +135,78 @@ static int32_t nfc_worker_listener(void* context) { return 0; } +typedef bool (*NfcWorkerPollerStateHandler)(Nfc* instance); + +bool nfc_worker_poller_idle_handler(Nfc* instance) { + f_hal_nfc_low_power_mode_stop(); + instance->poller_state = NfcPollerStateStart; + + return false; +} + +bool nfc_worker_poller_start_handler(Nfc* instance) { + f_hal_nfc_poller_field_on(); + if(instance->guard_time_us) { + f_hal_nfc_timer_block_tx_start_us(instance->guard_time_us); + FHalNfcEvent event = f_hal_nfc_wait_event(F_HAL_NFC_EVENT_WAIT_FOREVER); + furi_assert(event & FHalNfcEventTimerBlockTxExpired); + } + instance->poller_state = NfcPollerStateReady; + + return false; +} + +bool nfc_worker_poller_ready_handler(Nfc* instance) { + NfcCommand command = NfcCommandContinue; + + NfcEvent event = {.type = NfcEventTypePollerReady}; + command = instance->callback(event, instance->context); + if(command == NfcCommandReset) { + instance->poller_state = NfcPollerStateReset; + } else if(command == NfcCommandStop) { + instance->poller_state = NfcPollerStateStop; + } + + return false; +} + +bool nfc_worker_poller_reset_handler(Nfc* instance) { + f_hal_nfc_low_power_mode_start(); + furi_delay_ms(100); + instance->poller_state = NfcPollerStateIdle; + + return false; +} + +bool nfc_worker_poller_stop_handler(Nfc* instance) { + nfc_config(instance, NfcModeIdle); + f_hal_nfc_low_power_mode_start(); + instance->poller_state = NfcPollerStateIdle; + + return true; +} + +static const NfcWorkerPollerStateHandler nfc_worker_poller_state_handlers[NfcPollerStateNum] = { + [NfcPollerStateIdle] = nfc_worker_poller_idle_handler, + [NfcPollerStateStart] = nfc_worker_poller_start_handler, + [NfcPollerStateReady] = nfc_worker_poller_ready_handler, + [NfcPollerStateReset] = nfc_worker_poller_reset_handler, + [NfcPollerStateStop] = nfc_worker_poller_stop_handler, +}; + static int32_t nfc_worker_poller(void* context) { furi_assert(context); Nfc* instance = context; furi_assert(instance->callback); - instance->state = NfcStateIdle; - - NfcEvent nfc_event = {}; - NfcCommand cmd = NfcCommandContinue; + instance->poller_state = NfcPollerStateIdle; f_hal_nfc_event_start(); - while(true) { - if(instance->state == NfcStateIdle) { - f_hal_nfc_low_power_mode_stop(); - instance->state = NfcStateChipActive; - } else if(instance->state == NfcStateChipSleep) { - f_hal_nfc_low_power_mode_stop(); - instance->state = NfcStateChipActive; - } else if(instance->state == NfcStateChipActive) { - nfc_event.type = NfcEventTypeConfigureRequest; - cmd = instance->callback(nfc_event, instance->context); - if(cmd == NfcCommandReset) { - instance->state = NfcStatePollerReset; - } else if(cmd == NfcCommandStop) { - nfc_config(instance, NfcModeIdle); - nfc_event.type = NfcEventTypeReset; - instance->callback(nfc_event, instance->context); - f_hal_nfc_low_power_mode_start(); - break; - } else { - instance->state = NfcStateConfigured; - } - } else if(instance->state == NfcStateConfigured) { - f_hal_nfc_poller_field_on(); - instance->state = NfcStateFieldOn; - if(instance->guard_time_us) { - f_hal_nfc_timer_block_tx_start_us(instance->guard_time_us); - FHalNfcEvent event = f_hal_nfc_wait_event(F_HAL_NFC_EVENT_WAIT_FOREVER); - furi_assert(event & FHalNfcEventTimerBlockTxExpired); - } - instance->state = NfcStatePollerReady; - } else if(instance->state == NfcStatePollerReady) { - nfc_event.type = NfcEventTypePollerReady; - cmd = instance->callback(nfc_event, instance->context); - if(cmd == NfcCommandReset) { - instance->state = NfcStatePollerReset; - } else if(cmd == NfcCommandStop) { - nfc_config(instance, NfcModeIdle); - nfc_event.type = NfcEventTypeReset; - instance->callback(nfc_event, instance->context); - f_hal_nfc_low_power_mode_start(); - break; - } - } else if(instance->state == NfcStatePollerReset) { - nfc_config(instance, NfcModeIdle); - nfc_event.type = NfcEventTypeReset; - cmd = instance->callback(nfc_event, instance->context); - f_hal_nfc_low_power_mode_start(); - if(cmd == NfcCommandStop) { - break; - } - // Delay to power off target nfc device - furi_delay_ms(100); - instance->state = NfcStateChipSleep; - } + bool exit = false; + while(!exit) { + exit = nfc_worker_poller_state_handlers[instance->poller_state](instance); } - instance->state = NfcStateChipSleep; return 0; } @@ -199,6 +216,9 @@ Nfc* nfc_alloc() { Nfc* instance = malloc(sizeof(Nfc)); instance->state = NfcStateIdle; + instance->comm_state = NfcCommStateIdle; + instance->config_state = NfcConfigurationStateIdle; + instance->poller_state = NfcPollerStateIdle; instance->worker_thread = furi_thread_alloc(); furi_thread_set_name(instance->worker_thread, "NfcWorker"); @@ -227,10 +247,13 @@ void nfc_config(Nfc* instance, NfcMode mode) { furi_assert(instance); if(mode == NfcModeIdle) { f_hal_nfc_reset_mode(); + instance->config_state = NfcConfigurationStateIdle; } else if(mode == NfcModeNfcaPoller) { f_hal_nfc_set_mode(FHalNfcModeNfcaPoller, FHalNfcBitrate106); + instance->config_state = NfcConfigurationStateDone; } else if(mode == NfcModeNfcaListener) { f_hal_nfc_set_mode(FHalNfcModeNfcaListener, FHalNfcBitrate106); + instance->config_state = NfcConfigurationStateDone; } } @@ -276,6 +299,7 @@ void nfc_start_poller(Nfc* instance, NfcEventCallback callback, void* context) { furi_assert(instance); furi_assert(instance->worker_thread); furi_assert(callback); + furi_assert(instance->config_state == NfcConfigurationStateDone); instance->callback = callback; instance->context = context; @@ -381,42 +405,6 @@ static NfcError nfc_poller_trx_state_machine(Nfc* instance, uint32_t fwt_fc) { return error; } -static NfcError nfc_poller_prepare_trx(Nfc* instance) { - furi_assert(instance); - - FHalNfcError error = FHalNfcErrorNone; - NfcError ret = NfcErrorNone; - FHalNfcEvent event = 0; - do { - if(instance->state == NfcStateConfigured) { - error = f_hal_nfc_low_power_mode_stop(); - if(error != FHalNfcErrorNone) break; - instance->state = NfcStateChipActive; - } - if(instance->state == NfcStateChipActive) { - error = f_hal_nfc_poller_field_on(); - if(error != FHalNfcErrorNone) break; - instance->state = NfcStateFieldOn; - if(instance->guard_time_us) { - f_hal_nfc_timer_block_tx_start_us(instance->guard_time_us); - instance->comm_state = NfcCommStateWaitBlockTxTimer; - event = f_hal_nfc_wait_event(F_HAL_NFC_EVENT_WAIT_FOREVER); - if(event & FHalNfcEventTimerBlockTxExpired) { - f_hal_nfc_set_mask_receive_timer(instance->mask_rx_time_fc); - instance->comm_state = NfcCommStateReadyTx; - } else { - FURI_LOG_D(TAG, "Unexpected event in tx rx prepare %d", event); - instance->comm_state = NfcCommStateFailed; - } - } - } - } while(false); - ret = nfc_process_hal_error(error); - // Reset FIFO, prepare TX, setup Mask rx timer - f_hal_nfc_trx_reset(); - return ret; -} - NfcError nfc_trx_custom_parity( Nfc* instance, const BitBuffer* tx_buffer, @@ -426,17 +414,12 @@ NfcError nfc_trx_custom_parity( furi_assert(tx_buffer); furi_assert(rx_buffer); - furi_assert(instance->state == NfcStatePollerReady); + furi_assert(instance->poller_state == NfcPollerStateReady); NfcError ret = NfcErrorNone; FHalNfcError error = FHalNfcErrorNone; do { - ret = nfc_poller_prepare_trx(instance); - if(ret != NfcErrorNone) { - FURI_LOG_E(TAG, "Failed in prepare tx rx"); - break; - } - + f_hal_nfc_trx_reset(); bit_buffer_write_bytes_with_parity( tx_buffer, instance->tx_buffer, sizeof(instance->tx_buffer), &instance->tx_bits); error = f_hal_nfc_poller_tx_custom_parity(instance->tx_buffer, instance->tx_bits); @@ -471,16 +454,12 @@ NfcError nfc_trx(Nfc* instance, const BitBuffer* tx_buffer, BitBuffer* rx_buffer furi_assert(tx_buffer); furi_assert(rx_buffer); - furi_assert(instance->state == NfcStatePollerReady); + furi_assert(instance->poller_state == NfcPollerStateReady); NfcError ret = NfcErrorNone; FHalNfcError error = FHalNfcErrorNone; do { - ret = nfc_poller_prepare_trx(instance); - if(ret != NfcErrorNone) { - FURI_LOG_E(TAG, "Failed in prepare tx rx"); - break; - } + f_hal_nfc_trx_reset(); error = f_hal_nfc_poller_tx(bit_buffer_get_data(tx_buffer), bit_buffer_get_size(tx_buffer)); if(error != FHalNfcErrorNone) { @@ -521,16 +500,12 @@ NfcError nfc_iso13444a_short_frame( FHalNfcaShortFrameAllReq : FHalNfcaShortFrameSensReq; - furi_assert(instance->state == NfcStatePollerReady); + furi_assert(instance->poller_state == NfcPollerStateReady); NfcError ret = NfcErrorNone; FHalNfcError error = FHalNfcErrorNone; do { - ret = nfc_poller_prepare_trx(instance); - if(ret != NfcErrorNone) { - FURI_LOG_E(TAG, "Failed in prepare tx rx"); - break; - } + f_hal_nfc_trx_reset(); error = f_hal_nfca_send_short_frame(short_frame); if(error != FHalNfcErrorNone) { FURI_LOG_E(TAG, "Failed in poller TX"); @@ -567,16 +542,12 @@ NfcError nfc_iso13444a_sdd_frame( furi_assert(tx_buffer); furi_assert(rx_buffer); - furi_assert(instance->state == NfcStatePollerReady); + furi_assert(instance->poller_state == NfcPollerStateReady); NfcError ret = NfcErrorNone; FHalNfcError error = FHalNfcErrorNone; do { - ret = nfc_poller_prepare_trx(instance); - if(ret != NfcErrorNone) { - FURI_LOG_E(TAG, "Failed in prepare tx rx"); - break; - } + f_hal_nfc_trx_reset(); error = f_hal_nfca_send_sdd_frame( bit_buffer_get_data(tx_buffer), bit_buffer_get_size(tx_buffer)); if(error != FHalNfcErrorNone) { diff --git a/lib/nfc/nfc.h b/lib/nfc/nfc.h index 4e7083ea980d..0d9d443fa3fc 100644 --- a/lib/nfc/nfc.h +++ b/lib/nfc/nfc.h @@ -17,11 +17,12 @@ typedef enum { NfcEventTypeRxStart, NfcEventTypeRxEnd, + // TODO delete NfcEventTypeConfigureRequest, + NfcEventTypeReset, NfcEventTypeListenerActivated, NfcEventTypePollerReady, - NfcEventTypeReset, } NfcEventType; typedef struct { diff --git a/lib/nfc/nfc_poller.c b/lib/nfc/nfc_poller.c new file mode 100644 index 000000000000..06768ed0d75b --- /dev/null +++ b/lib/nfc/nfc_poller.c @@ -0,0 +1,209 @@ +#include "nfc_poller.h" + +#include + +#include + +typedef enum { + NfcPollerSessionStateIdle, + NfcPollerSessionStateActive, + NfcPollerSessionStateStopRequest, +} NfcPollerSessionState; + +typedef struct NfcPollerListElement { + NfcProtocolType protocol; + NfcPollerInstance* poller; + const NfcPollerBase* poller_api; + struct NfcPollerListElement* child; +} NfcPollerListElement; + +typedef struct { + NfcPollerListElement* head; + NfcPollerListElement* tail; +} NfcPollerList; + +struct NfcPoller { + NfcProtocolType protocol; + Nfc* nfc; + NfcPollerList list; + NfcPollerSessionState session_state; + bool protocol_detected; +}; + +static void nfc_poller_list_alloc(NfcPoller* instance) { + instance->list.head = malloc(sizeof(NfcPollerListElement)); + instance->list.head->protocol = instance->protocol; + instance->list.head->poller_api = nfc_pollers_api[instance->protocol]; + instance->list.head->child = NULL; + instance->list.tail = instance->list.head; + + do { + const NfcPollerTreeNode* node = &nfc_poller_nodes[instance->list.head->protocol]; + if(node->parent_protocol == NfcProtocolTypeInvalid) break; + + NfcPollerListElement* parent = malloc(sizeof(NfcPollerListElement)); + parent->protocol = node->parent_protocol; + parent->poller_api = nfc_pollers_api[node->parent_protocol]; + parent->child = instance->list.head; + instance->list.head = parent; + } while(true); + + NfcPollerListElement* iter = instance->list.head; + iter->poller = iter->poller_api->alloc(instance->nfc); + + do { + if(iter->child == NULL) break; + iter->child->poller = iter->child->poller_api->alloc(iter->poller); + iter->poller_api->set_callback( + iter->poller, iter->child->poller_api->run, iter->child->poller); + + iter = iter->child; + } while(true); +} + +static void nfc_poller_list_free(NfcPoller* instance) { + do { + instance->list.head->poller_api->free(instance->list.head->poller); + NfcPollerListElement* child = instance->list.head->child; + free(instance->list.head); + if(child == NULL) break; + instance->list.head = child; + } while(true); +} + +NfcPoller* nfc_poller_alloc(Nfc* nfc, NfcProtocolType protocol) { + furi_assert(nfc); + furi_assert(protocol < NfcProtocolTypeMax); + + NfcPoller* instance = malloc(sizeof(NfcPoller)); + instance->session_state = NfcPollerSessionStateIdle; + instance->nfc = nfc; + instance->protocol = protocol; + nfc_poller_list_alloc(instance); + + return instance; +} + +void nfc_poller_free(NfcPoller* instance) { + furi_assert(instance); + + nfc_poller_list_free(instance); + free(instance); +} + +static NfcCommand nfc_poller_start_callback(NfcEvent event, void* context) { + furi_assert(context); + + NfcPoller* instance = context; + + NfcCommand command = NfcCommandContinue; + NfcPollerEvent poller_event = { + .protocol_type = NfcProtocolTypeInvalid, + .poller = instance->nfc, + .data = &event, + }; + + if(event.type == NfcEventTypePollerReady) { + NfcPollerListElement* head_poller = instance->list.head; + command = head_poller->poller_api->run(poller_event, head_poller->poller); + } + + if(instance->session_state == NfcPollerSessionStateStopRequest) { + command = NfcCommandStop; + } + + return command; +} + +void nfc_poller_start(NfcPoller* instance, NfcPollerCallback callback, void* context) { + furi_assert(instance); + furi_assert(callback); + furi_assert(instance->session_state == NfcPollerSessionStateIdle); + + NfcPollerListElement* tail_poller = instance->list.tail; + tail_poller->poller_api->set_callback(tail_poller->poller, callback, context); + + instance->session_state = NfcPollerSessionStateActive; + nfc_start_poller(instance->nfc, nfc_poller_start_callback, instance); +} + +void nfc_poller_stop(NfcPoller* instance) { + furi_assert(instance); + furi_assert(instance->nfc); + + instance->session_state = NfcPollerSessionStateStopRequest; + nfc_stop(instance->nfc); + instance->session_state = NfcPollerSessionStateIdle; +} + +// TODO change name +static NfcCommand nfc_poller_detect_tail_callback(NfcPollerEvent event, void* context) { + furi_assert(context); + + NfcPoller* instance = context; + NfcPollerListElement* tail_poller = instance->list.tail; + instance->protocol_detected = tail_poller->poller_api->detect(event, tail_poller->poller); + + return NfcCommandStop; +} + +static NfcCommand nfc_poller_detect_callback(NfcEvent event, void* context) { + furi_assert(context); + + NfcPoller* instance = context; + NfcPollerListElement* tail_poller = instance->list.tail; + NfcPollerListElement* head_poller = instance->list.head; + + NfcCommand command = NfcCommandContinue; + NfcPollerEvent poller_event = { + .protocol_type = NfcProtocolTypeInvalid, + .poller = instance->nfc, + .data = &event, + }; + + // TODO hard to understand + if(event.type == NfcEventTypePollerReady) { + if(tail_poller == head_poller) { + instance->protocol_detected = + tail_poller->poller_api->detect(poller_event, tail_poller->poller); + command = NfcCommandStop; + } else { + command = head_poller->poller_api->run(poller_event, head_poller->poller); + } + } + + return command; +} + +bool nfc_poller_detect(NfcPoller* instance) { + furi_assert(instance); + furi_assert(instance->session_state == NfcPollerSessionStateIdle); + + instance->session_state = NfcPollerSessionStateActive; + NfcPollerListElement* tail_poller = instance->list.tail; + NfcPollerListElement* iter = instance->list.head; + + // TODO hard to understand + if(tail_poller != instance->list.head) { + while(iter->child != tail_poller) iter = iter->child; + iter->poller_api->set_callback(iter->poller, nfc_poller_detect_tail_callback, instance); + } + + nfc_start_poller(instance->nfc, nfc_poller_detect_callback, instance); + nfc_stop(instance->nfc); + + // TODO hard to understand + if(tail_poller != instance->list.head) { + iter->poller_api->set_callback( + iter->poller, tail_poller->poller_api->run, tail_poller->poller); + } + + return instance->protocol_detected; +} + +const NfcProtocolData* nfc_poller_get_data(NfcPoller* instance) { + furi_assert(instance); + + NfcPollerListElement* tail_poller = instance->list.tail; + return tail_poller->poller_api->get_data(tail_poller->poller); +} diff --git a/lib/nfc/nfc_poller.h b/lib/nfc/nfc_poller.h new file mode 100644 index 000000000000..b17e96d01f22 --- /dev/null +++ b/lib/nfc/nfc_poller.h @@ -0,0 +1,25 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +typedef struct NfcPoller NfcPoller; + +NfcPoller* nfc_poller_alloc(Nfc* nfc, NfcProtocolType protocol); + +void nfc_poller_free(NfcPoller* instance); + +void nfc_poller_start(NfcPoller* instance, NfcPollerCallback callback, void* context); + +void nfc_poller_stop(NfcPoller* instance); + +bool nfc_poller_detect(NfcPoller* instance); + +const NfcProtocolData* nfc_poller_get_data(NfcPoller* instance); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/nfc_poller_manager.c b/lib/nfc/nfc_poller_manager.c deleted file mode 100644 index 7ba01a362cff..000000000000 --- a/lib/nfc/nfc_poller_manager.c +++ /dev/null @@ -1,167 +0,0 @@ -#include "nfc_poller_manager.h" - -#include - -#include - -typedef enum { - NfcPollerManagerStateIdle, - - NfcPollerManagerStateNum, -} NfcPollerManagerState; - -typedef enum { - NfcPollerManagerSessionStateIdle, - NfcPollerManagerSessionStateActive, - NfcPollerManagerSessionStateStopRequest, -} NfcPollerManagerSessionState; - -typedef struct NfcPollerListElement { - NfcProtocolType protocol; - NfcPoller* poller; - const NfcPollerBase* poller_api; - struct NfcPollerListElement* child; -} NfcPollerListElement; - -typedef struct { - NfcPollerListElement* head; -} NfcPollerList; - -struct NfcPollerManager { - Nfc* nfc; - NfcPollerManagerState state; - NfcPollerManagerSessionState session_state; - - NfcEvent* event; - NfcPollerList* list; - NfcProtocolType protocol; - - NfcPollerCallback callback; - void* context; -}; - -NfcPollerManager* nfc_poller_manager_alloc(Nfc* nfc) { - NfcPollerManager* instance = malloc(sizeof(NfcPollerManager)); - instance->nfc = nfc; - instance->event = malloc(sizeof(NfcEvent)); - - return instance; -} - -void nfc_poller_manager_free(NfcPollerManager* instance) { - furi_assert(instance); - furi_assert(instance->event); - furi_assert(instance->nfc); - - free(instance->event); - free(instance); -} - -static void nfc_poller_manager_poller_list_alloc(NfcPollerManager* instance) { - furi_assert(instance->list == NULL); - - instance->list = malloc(sizeof(NfcPollerList)); - - instance->list->head = malloc(sizeof(NfcPollerListElement)); - instance->list->head->protocol = instance->protocol; - instance->list->head->poller_api = nfc_pollers_api[instance->protocol]; - instance->list->head->child = NULL; - - do { - const NfcPollerTreeNode* node = &nfc_poller_nodes[instance->list->head->protocol]; - if(node->parent_protocol == NfcProtocolTypeInvalid) break; - - NfcPollerListElement* parent = malloc(sizeof(NfcPollerListElement)); - parent->protocol = node->parent_protocol; - parent->poller_api = nfc_pollers_api[node->parent_protocol]; - parent->child = instance->list->head; - instance->list->head = parent; - } while(true); - - NfcPollerListElement* iter = instance->list->head; - iter->poller = iter->poller_api->alloc(instance->nfc); - - do { - if(iter->child == NULL) break; - iter->child->poller = iter->child->poller_api->alloc(iter->poller); - iter->poller_api->set_callback( - iter->poller, iter->child->poller_api->run, iter->child->poller); - - iter = iter->child; - } while(true); - - iter->poller_api->set_callback(iter->poller, instance->callback, instance->context); -} - -static void nfc_poller_manager_poller_list_free(NfcPollerManager* instance) { - do { - instance->list->head->poller_api->free(instance->list->head->poller); - NfcPollerListElement* child = instance->list->head->child; - free(instance->list->head); - if(child == NULL) break; - instance->list->head = child; - } while(true); - - free(instance->list); - instance->list = NULL; -} - -static NfcCommand nfc_poller_manager_start_event_callback(NfcEvent event, void* context) { - furi_assert(context); - - NfcPollerManager* instance = context; - furi_assert(instance->callback); - - NfcCommand command = NfcCommandContinue; - NfcPollerEvent poller_manager_event = { - .protocol_type = NfcProtocolTypeInvalid, - .poller = instance->nfc, - }; - - if(event.type == NfcEventTypeConfigureRequest) { - nfc_poller_manager_poller_list_alloc(instance); - } else if(event.type == NfcEventTypePollerReady) { - *instance->event = event; - poller_manager_event.data = instance->event; - NfcPollerListElement* head = instance->list->head; - command = head->poller_api->run(poller_manager_event, head->poller); - } else if(event.type == NfcEventTypeReset) { - nfc_poller_manager_poller_list_free(instance); - } - - if(instance->session_state == NfcPollerManagerSessionStateStopRequest) { - command = NfcCommandStop; - } - - return command; -} - -void nfc_poller_manager_start( - NfcPollerManager* instance, - NfcProtocolType protocol, - NfcPollerCallback callback, - void* context) { - furi_assert(instance); - furi_assert(callback); - furi_assert(protocol < NfcProtocolTypeMax); - furi_assert(instance->session_state == NfcPollerManagerSessionStateIdle); - - instance->protocol = protocol; - instance->callback = callback; - instance->context = context; - instance->session_state = NfcPollerManagerSessionStateActive; - - nfc_start_poller(instance->nfc, nfc_poller_manager_start_event_callback, instance); -} - -void nfc_poller_manager_stop(NfcPollerManager* instance) { - furi_assert(instance); - furi_assert(instance->nfc); - - instance->session_state = NfcPollerManagerSessionStateStopRequest; - nfc_stop(instance->nfc); - instance->session_state = NfcPollerManagerSessionStateIdle; - - instance->callback = NULL; - instance->context = NULL; -} diff --git a/lib/nfc/nfc_poller_manager.h b/lib/nfc/nfc_poller_manager.h deleted file mode 100644 index 66d54e940256..000000000000 --- a/lib/nfc/nfc_poller_manager.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -typedef struct NfcPollerManager NfcPollerManager; - -NfcPollerManager* nfc_poller_manager_alloc(Nfc* nfc); - -void nfc_poller_manager_free(NfcPollerManager* instance); - -void nfc_poller_manager_start( - NfcPollerManager* instance, - NfcProtocolType protocol, - NfcPollerCallback callback, - void* context); - -void nfc_poller_manager_stop(NfcPollerManager* instance); - -#ifdef __cplusplus -} -#endif diff --git a/lib/nfc/nfc_scanner.c b/lib/nfc/nfc_scanner.c index e955ca6b49b1..1e0f9102a83a 100644 --- a/lib/nfc/nfc_scanner.c +++ b/lib/nfc/nfc_scanner.c @@ -1,5 +1,5 @@ #include "nfc_scanner.h" -#include "nfc_poller_manager.h" +#include "nfc_poller.h" #include @@ -7,8 +7,6 @@ #define TAG "NfcScanner" -#define NFC_SCANNER_POLLER_MANAGER_COMPLETE_EVENT (1UL << 0) - typedef enum { NfcScannerStateIdle, NfcScannerStateTryBasePollers, @@ -28,7 +26,6 @@ typedef enum { struct NfcScanner { Nfc* nfc; - NfcPollerManager* poller_manager; NfcScannerState state; NfcScannerSessionState session_state; @@ -49,7 +46,6 @@ struct NfcScanner { NfcProtocolType detected_protocols[NfcProtocolTypeMax]; NfcProtocolType current_protocol; - NfcPoller* current_poller; FuriThread* scan_worker; }; @@ -81,43 +77,18 @@ void nfc_scanner_state_handler_idle(NfcScanner* instance) { instance->state = NfcScannerStateTryBasePollers; } -static NfcCommand nfc_scanner_base_poller_detect_callback(NfcEvent event, void* context) { - furi_assert(context); - - NfcScanner* instance = context; - - NfcCommand command = NfcCommandContinue; - instance->nfc_event = event; - NfcPollerEvent scanner_event = { - .protocol_type = NfcProtocolTypeInvalid, - .poller = instance->nfc, - .data = &instance->nfc_event, - }; - const NfcPollerBase* current_poller_api = nfc_pollers_api[instance->current_protocol]; - - if(event.type == NfcEventTypeConfigureRequest) { - instance->current_poller = current_poller_api->alloc(instance->nfc); - } else if(event.type == NfcEventTypePollerReady) { - bool protocol_detected = - current_poller_api->detect(scanner_event, instance->current_poller); - if(protocol_detected) { - instance->detected_protocols[instance->detected_protocols_num] = - instance->current_protocol; - instance->detected_protocols_num++; - } - command = NfcCommandStop; - } else if(event.type == NfcEventTypeReset) { - current_poller_api->free(instance->current_poller); - } - - return command; -} - void nfc_scanner_state_handler_try_base_pollers(NfcScanner* instance) { instance->current_protocol = instance->base_protocols[instance->base_protocols_idx]; - nfc_start_poller(instance->nfc, nfc_scanner_base_poller_detect_callback, instance); - nfc_stop(instance->nfc); + NfcPoller* poller = nfc_poller_alloc(instance->nfc, instance->current_protocol); + bool protocol_detected = nfc_poller_detect(poller); + nfc_poller_free(poller); + + if(protocol_detected) { + instance->detected_protocols[instance->detected_protocols_num] = + instance->current_protocol; + instance->detected_protocols_num++; + } if(instance->detected_protocols_num > 0) { instance->state = NfcScannerStateFindChildrenProtocols; @@ -158,19 +129,14 @@ void nfc_scanner_state_handler_find_children_protocols(NfcScanner* instance) { FURI_LOG_D(TAG, "Found %d children", instance->children_protocols_num); } -static NfcCommand nfc_scanner_detect_child_protocol_callback(NfcPollerEvent event, void* context) { - furi_assert(context); - furi_assert(event.poller); +void nfc_scanner_state_handler_detect_children_protocols(NfcScanner* instance) { + furi_assert(instance->children_protocols_num); - bool protocol_detected = false; - NfcScanner* instance = context; - const NfcPollerBase* current_poller_api = nfc_pollers_api[instance->current_protocol]; + instance->current_protocol = instance->children_protocols[instance->children_protocols_idx]; - if(current_poller_api) { - instance->current_poller = current_poller_api->alloc(event.poller); - protocol_detected = current_poller_api->detect(event, instance->current_poller); - current_poller_api->free(instance->current_poller); - } + NfcPoller* poller = nfc_poller_alloc(instance->nfc, instance->current_protocol); + bool protocol_detected = nfc_poller_detect(poller); + nfc_poller_free(poller); if(protocol_detected) { instance->detected_protocols[instance->detected_protocols_num] = @@ -178,31 +144,6 @@ static NfcCommand nfc_scanner_detect_child_protocol_callback(NfcPollerEvent even instance->detected_protocols_num++; } - // Notify scan worker that detection is complete - FuriThreadId scan_worker_thread_id = furi_thread_get_id(instance->scan_worker); - furi_thread_flags_set(scan_worker_thread_id, NFC_SCANNER_POLLER_MANAGER_COMPLETE_EVENT); - - return NfcCommandStop; -} - -void nfc_scanner_state_handler_detect_children_protocols(NfcScanner* instance) { - furi_assert(instance->children_protocols_num); - - instance->current_protocol = instance->children_protocols[instance->children_protocols_idx]; - NfcProtocolType parent_protocol = nfc_poller_nodes[instance->current_protocol].parent_protocol; - - nfc_poller_manager_start( - instance->poller_manager, - parent_protocol, - nfc_scanner_detect_child_protocol_callback, - instance); - - // Wait until detection is complete - furi_thread_flags_wait( - NFC_SCANNER_POLLER_MANAGER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); - furi_thread_flags_clear(NFC_SCANNER_POLLER_MANAGER_COMPLETE_EVENT); - nfc_poller_manager_stop(instance->poller_manager); - instance->children_protocols_idx++; if(instance->children_protocols_idx == instance->children_protocols_num) { instance->state = NfcScannerStateComplete; @@ -261,7 +202,6 @@ static int32_t nfc_scanner_worker(void* context) { furi_assert(context); NfcScanner* instance = context; - furi_assert(instance->poller_manager); while(instance->session_state == NfcScannerSessionStateActive) { nfc_scanner_state_handlers[instance->state](instance); @@ -277,16 +217,13 @@ NfcScanner* nfc_scanner_alloc(Nfc* nfc) { NfcScanner* instance = malloc(sizeof(NfcScanner)); instance->nfc = nfc; - instance->poller_manager = nfc_poller_manager_alloc(instance->nfc); return instance; } void nfc_scanner_free(NfcScanner* instance) { furi_assert(instance); - furi_assert(instance->poller_manager); - nfc_poller_manager_free(instance->poller_manager); free(instance); } diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.c b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.c index 0c83100d3eef..fae3638362ba 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.c +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.c @@ -1,5 +1,7 @@ #include "iso14443_4a_poller_i.h" +#include + #include #define TAG "Iso14443_4aPoller" diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.h b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.h index 8d9198a3a65d..224e1469aac8 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.h +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.h @@ -24,8 +24,6 @@ typedef struct { Iso14443_4aPollerEventData* data; } Iso14443_4aPollerEvent; -const Iso14443_4aData* iso14443_4a_poller_get_data(Iso14443_4aPoller* instance); - #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.h b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.h index d16e5cfde4df..d25e7efac3d2 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.h +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.h @@ -47,6 +47,8 @@ struct Iso14443_4aPoller { Iso14443_4aError iso14443_4a_poller_process_error(NfcaError error); +const Iso14443_4aData* iso14443_4a_poller_get_data(Iso14443_4aPoller* instance); + Iso14443_4aError iso14443_4a_poller_halt(Iso14443_4aPoller* instance); Iso14443_4aError diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller.c b/lib/nfc/protocols/mf_classic/mf_classic_poller.c index 8182afc6b085..b2a2f8aa7bbf 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller.c @@ -1,61 +1,20 @@ #include "mf_classic_poller_i.h" +#include + #include #define TAG "MfClassicPoller" #define MF_CLASSIC_MAX_BUFF_SIZE (64) -typedef MfClassicPollerCommand (*MfClassicPollerReadHandler)(MfClassicPoller* instance); - -static NfcaPollerCommand mf_classic_process_command(MfClassicPollerCommand command) { - NfcaPollerCommand ret = NfcaPollerCommandContinue; - - if(command == MfClassicPollerCommandContinue) { - ret = NfcaPollerCommandContinue; - } else if(command == MfClassicPollerCommandContinue) { - ret = NfcaPollerCommandContinue; - } else if(command == MfClassicPollerCommandReset) { - ret = NfcaPollerCommandReset; - } else if(command == MfClassicPollerCommandStop) { - ret = NfcaPollerCommandStop; - } else { - furi_crash("Unknown command"); - } - - return ret; -} +typedef NfcCommand (*MfClassicPollerReadHandler)(MfClassicPoller* instance); MfClassicPoller* mf_classic_poller_alloc(NfcaPoller* nfca_poller) { furi_assert(nfca_poller); MfClassicPoller* instance = malloc(sizeof(MfClassicPoller)); instance->nfca_poller = nfca_poller; - - return instance; -} - -void mf_classic_poller_free(MfClassicPoller* instance) { - furi_assert(instance); - - free(instance); -} - -const MfClassicData* mf_classic_poller_get_data(MfClassicPoller* instance) { - furi_assert(instance); - - return instance->data; -} - -MfClassicError mf_classic_poller_start( - MfClassicPoller* instance, - NfcaPollerEventCallback callback, - void* context) { - furi_assert(instance); - furi_assert(callback); - furi_assert(instance->nfca_poller); - furi_assert(instance->session_state == MfClassicPollerSessionStateIdle); - instance->data = mf_classic_alloc(); instance->crypto = crypto1_alloc(); instance->tx_plain_buffer = bit_buffer_alloc(MF_CLASSIC_MAX_BUFF_SIZE); @@ -63,22 +22,43 @@ MfClassicError mf_classic_poller_start( instance->rx_plain_buffer = bit_buffer_alloc(MF_CLASSIC_MAX_BUFF_SIZE); instance->rx_encrypted_buffer = bit_buffer_alloc(MF_CLASSIC_MAX_BUFF_SIZE); - instance->session_state = MfClassicPollerSessionStateActive; - nfca_poller_start(instance->nfca_poller, callback, context); + instance->mfc_event.data = &instance->mfc_event_data; + + instance->general_event.protocol_type = NfcProtocolTypeMfClassic; + instance->general_event.data = &instance->mfc_event; + instance->general_event.poller = instance; + + return instance; +} + +void mf_classic_poller_free(MfClassicPoller* instance) { + furi_assert(instance); + furi_assert(instance->data); + furi_assert(instance->crypto); + furi_assert(instance->tx_plain_buffer); + furi_assert(instance->rx_plain_buffer); + furi_assert(instance->tx_encrypted_buffer); + furi_assert(instance->rx_encrypted_buffer); + + mf_classic_free(instance->data); + crypto1_free(instance->crypto); + bit_buffer_free(instance->tx_plain_buffer); + bit_buffer_free(instance->rx_plain_buffer); + bit_buffer_free(instance->tx_encrypted_buffer); + bit_buffer_free(instance->rx_encrypted_buffer); - return MfClassicErrorNone; + free(instance); } -MfClassicPollerCommand mf_classic_poller_handler_idle(MfClassicPoller* instance) { +NfcCommand mf_classic_poller_handler_idle(MfClassicPoller* instance) { nfca_copy(instance->data->nfca_data, nfca_poller_get_data(instance->nfca_poller)); - MfClassicPollerCommand command = MfClassicPollerCommandContinue; - MfClassicPollerEvent event = {}; + NfcCommand command = NfcCommandContinue; if(mf_classic_detect_protocol(instance->data->nfca_data, &instance->data->type)) { if(instance->card_state == MfClassicCardStateNotDetected) { instance->card_state = MfClassicCardStateDetected; - event.type = MfClassicPollerEventTypeCardDetected; - command = instance->callback(event, instance->context); + instance->mfc_event.type = MfClassicPollerEventTypeCardDetected; + command = instance->callback(instance->general_event, instance->context); } instance->state = instance->prev_state; } @@ -86,48 +66,45 @@ MfClassicPollerCommand mf_classic_poller_handler_idle(MfClassicPoller* instance) return command; } -MfClassicPollerCommand mf_classic_poller_handler_start(MfClassicPoller* instance) { - MfClassicPollerCommand command = MfClassicPollerCommandContinue; +NfcCommand mf_classic_poller_handler_start(MfClassicPoller* instance) { + NfcCommand command = NfcCommandContinue; instance->sectors_read = 0; instance->sectors_total = mf_classic_get_total_sectors_num(instance->data->type); - instance->event_data.start_data.type = instance->data->type; - MfClassicPollerEvent event = { - .type = MfClassicPollerEventTypeStart, - .data = &instance->event_data, - }; - command = instance->callback(event, instance->context); + + instance->mfc_event_data.start_data.type = instance->data->type; + command = instance->callback(instance->general_event, instance->context); + instance->prev_state = MfClassicPollerStateStart; instance->state = MfClassicPollerStateNewSector; return command; } -MfClassicPollerCommand mf_classic_poller_handler_new_sector(MfClassicPoller* instance) { - MfClassicPollerCommand command = MfClassicPollerCommandContinue; - MfClassicPollerEvent event = {}; +NfcCommand mf_classic_poller_handler_new_sector(MfClassicPoller* instance) { + NfcCommand command = NfcCommandContinue; if(instance->read_mode == MfClassicReadModeKeyReuse) { instance->key_reuse_sector++; if(instance->key_reuse_sector == instance->sectors_total) { instance->read_mode = MfClassicReadModeDictAttack; - event.type = MfClassicPollerEventTypeKeyAttackStop; - command = instance->callback(event, instance->context); + instance->mfc_event.type = MfClassicPollerEventTypeKeyAttackStop; + command = instance->callback(instance->general_event, instance->context); } else if(mf_classic_is_sector_read(instance->data, instance->sectors_read)) { - event.type = MfClassicPollerEventTypeKeyAttackNextSector; - command = instance->callback(event, instance->context); + instance->mfc_event.type = MfClassicPollerEventTypeKeyAttackNextSector; + command = instance->callback(instance->general_event, instance->context); } else { instance->state = MfClassicPollerStateAuthKeyA; - event.type = MfClassicPollerEventTypeKeyAttackNextSector; - command = instance->callback(event, instance->context); + instance->mfc_event.type = MfClassicPollerEventTypeKeyAttackNextSector; + command = instance->callback(instance->general_event, instance->context); } } else { if(instance->sectors_read == instance->sectors_total) { instance->state = MfClassicPollerStateReadComplete; } else if(mf_classic_is_sector_read(instance->data, instance->sectors_read)) { instance->sectors_read++; - event.type = MfClassicPollerEventTypeNewSector; - command = instance->callback(event, instance->context); + instance->mfc_event.type = MfClassicPollerEventTypeNewSector; + command = instance->callback(instance->general_event, instance->context); } else { instance->state = MfClassicPollerStateRequestKey; } @@ -137,17 +114,13 @@ MfClassicPollerCommand mf_classic_poller_handler_new_sector(MfClassicPoller* ins return command; } -MfClassicPollerCommand mf_classic_poller_handler_request_key(MfClassicPoller* instance) { - MfClassicPollerCommand command = MfClassicPollerCommandContinue; - - instance->event_data.key_request_data.sector_num = instance->sectors_read; - MfClassicPollerEvent event = { - .type = MfClassicPollerEventTypeRequestKey, - .data = &instance->event_data, - }; - command = instance->callback(event, instance->context); - if(instance->event_data.key_request_data.key_provided) { - instance->current_key = instance->event_data.key_request_data.key; +NfcCommand mf_classic_poller_handler_request_key(MfClassicPoller* instance) { + NfcCommand command = NfcCommandContinue; + + instance->mfc_event_data.key_request_data.sector_num = instance->sectors_read; + command = instance->callback(instance->general_event, instance->context); + if(instance->mfc_event_data.key_request_data.key_provided) { + instance->current_key = instance->mfc_event_data.key_request_data.key; instance->state = MfClassicPollerStateAuthKeyA; } else { instance->state = MfClassicPollerStateNewSector; @@ -156,9 +129,8 @@ MfClassicPollerCommand mf_classic_poller_handler_request_key(MfClassicPoller* in return command; } -MfClassicPollerCommand mf_classic_poller_handler_auth_a(MfClassicPoller* instance) { - MfClassicPollerCommand command = MfClassicPollerCommandContinue; - MfClassicPollerEvent event = {}; +NfcCommand mf_classic_poller_handler_auth_a(MfClassicPoller* instance) { + NfcCommand command = NfcCommandContinue; uint8_t sector = 0; if(instance->read_mode == MfClassicReadModeKeyReuse) { @@ -184,14 +156,14 @@ MfClassicPollerCommand mf_classic_poller_handler_auth_a(MfClassicPoller* instanc if(sector < instance->sectors_total - 1) { instance->read_mode = MfClassicReadModeKeyReuse; instance->key_reuse_sector = sector; - event.type = MfClassicPollerEventTypeKeyAttackStart; - instance->event_data.key_attack_data.start_sector = instance->key_reuse_sector; - event.data = &instance->event_data; - command = instance->callback(event, instance->context); + instance->mfc_event.type = MfClassicPollerEventTypeKeyAttackStart; + instance->mfc_event_data.key_attack_data.start_sector = + instance->key_reuse_sector; + command = instance->callback(instance->general_event, instance->context); } } - event.type = MfClassicPollerEventTypeFoundKeyA; - command = instance->callback(event, instance->context); + instance->mfc_event.type = MfClassicPollerEventTypeFoundKeyA; + command = instance->callback(instance->general_event, instance->context); instance->prev_state = instance->state; instance->state = MfClassicPollerStateReadSector; } else { @@ -206,9 +178,8 @@ MfClassicPollerCommand mf_classic_poller_handler_auth_a(MfClassicPoller* instanc return command; } -MfClassicPollerCommand mf_classic_poller_handler_auth_b(MfClassicPoller* instance) { - MfClassicPollerCommand command = MfClassicPollerCommandContinue; - MfClassicPollerEvent event = {}; +NfcCommand mf_classic_poller_handler_auth_b(MfClassicPoller* instance) { + NfcCommand command = NfcCommandContinue; uint8_t sector = 0; if(instance->read_mode == MfClassicReadModeKeyReuse) { @@ -228,20 +199,20 @@ MfClassicPollerCommand mf_classic_poller_handler_auth_b(MfClassicPoller* instanc instance, block, &instance->current_key, MfClassicKeyTypeB, NULL); if(error == MfClassicErrorNone) { FURI_LOG_D(TAG, "Key B found"); - event.type = MfClassicPollerEventTypeFoundKeyB; + instance->mfc_event.type = MfClassicPollerEventTypeFoundKeyB; mf_classic_set_key_found(instance->data, sector, MfClassicKeyTypeB, key); if(instance->read_mode != MfClassicReadModeKeyReuse) { if(sector < instance->sectors_total - 1) { instance->read_mode = MfClassicReadModeKeyReuse; instance->key_reuse_sector = sector; - event.type = MfClassicPollerEventTypeKeyAttackStart; - instance->event_data.key_attack_data.start_sector = instance->key_reuse_sector; - event.data = &instance->event_data; - command = instance->callback(event, instance->context); + instance->mfc_event.type = MfClassicPollerEventTypeKeyAttackStart; + instance->mfc_event_data.key_attack_data.start_sector = + instance->key_reuse_sector; + command = instance->callback(instance->general_event, instance->context); } } - command = instance->callback(event, instance->context); + command = instance->callback(instance->general_event, instance->context); instance->state = MfClassicPollerStateReadSector; } else { if(instance->read_mode == MfClassicReadModeKeyReuse) { @@ -256,8 +227,8 @@ MfClassicPollerCommand mf_classic_poller_handler_auth_b(MfClassicPoller* instanc return command; } -MfClassicPollerCommand mf_classic_poller_handler_read_sector(MfClassicPoller* instance) { - MfClassicPollerCommand command = MfClassicPollerCommandContinue; +NfcCommand mf_classic_poller_handler_read_sector(MfClassicPoller* instance) { + NfcCommand command = NfcCommandContinue; uint8_t block_start = mf_classic_get_first_block_num_of_sector(instance->sectors_read); uint8_t total_blocks = mf_classic_get_blocks_num_in_sector(instance->sectors_read); @@ -285,13 +256,10 @@ MfClassicPollerCommand mf_classic_poller_handler_read_sector(MfClassicPoller* in return command; } -MfClassicPollerCommand mf_classic_poller_handler_read_complete(MfClassicPoller* instance) { - MfClassicPollerCommand command = MfClassicPollerCommandContinue; - MfClassicPollerEvent event = {.type = MfClassicPollerEventTypeReadComplete}; - command = instance->callback(event, instance->context); - if(command == MfClassicPollerCommandRestart) { - instance->state = MfClassicPollerStateStart; - } +NfcCommand mf_classic_poller_handler_read_complete(MfClassicPoller* instance) { + NfcCommand command = NfcCommandContinue; + instance->mfc_event.type = MfClassicPollerEventTypeReadComplete; + command = instance->callback(instance->general_event, instance->context); return command; } @@ -308,79 +276,62 @@ static const MfClassicPollerReadHandler [MfClassicPollerStateReadComplete] = mf_classic_poller_handler_read_complete, }; -NfcaPollerCommand mf_classic_dict_attack_callback(NfcaPollerEvent event, void* context) { +NfcCommand mf_classsic_poller_run(NfcPollerEvent event, void* context) { + furi_assert(event.data); + furi_assert(event.protocol_type == NfcProtocolTypeIso14443_3a); furi_assert(context); - MfClassicPoller* instance = context; - furi_assert(instance->callback); - MfClassicPollerCommand command = MfClassicPollerCommandContinue; - MfClassicPollerEvent mfc_event = {}; - - furi_assert(instance->session_state != MfClassicPollerSessionStateIdle); - if(instance->session_state == MfClassicPollerSessionStateStopRequest) { - command = MfClassicPollerCommandStop; - } else { - if(event.type == NfcaPollerEventTypeReady) { - command = mf_classic_poller_dict_attack_handler[instance->state](instance); - } else if(event.type == NfcaPollerEventTypeError) { - if(event.data.error == NfcaErrorNotPresent) { - if(instance->card_state == MfClassicCardStateDetected) { - instance->card_state = MfClassicCardStateNotDetected; - mfc_event.type = MfClassicPollerEventTypeCardNotDetected; - command = instance->callback(mfc_event, instance->context); - instance->state = MfClassicPollerStateIdle; - } + MfClassicPoller* instance = context; + NfcaPollerEvent* nfca_event = event.data; + NfcCommand command = NfcCommandContinue; + + if(nfca_event->type == NfcaPollerEventTypeReady) { + command = mf_classic_poller_dict_attack_handler[instance->state](instance); + } else if(nfca_event->type == NfcaPollerEventTypeError) { + if(nfca_event->data->error == NfcaErrorNotPresent) { + if(instance->card_state == MfClassicCardStateDetected) { + instance->card_state = MfClassicCardStateNotDetected; + instance->mfc_event.type = MfClassicPollerEventTypeCardNotDetected; + command = instance->callback(instance->general_event, instance->context); + instance->state = MfClassicPollerStateIdle; } } } - return mf_classic_process_command(command); + return command; +} + +bool mf_classsic_poller_detect(NfcPollerEvent event, void* context) { + furi_assert(event.data); + furi_assert(event.protocol_type == NfcProtocolTypeIso14443_3a); + furi_assert(context); + + return false; } -MfClassicError mf_classic_poller_dict_attack( +void mf_classic_poller_set_callback( MfClassicPoller* instance, - MfClassicPollerCallback callback, + NfcPollerCallback callback, void* context) { furi_assert(instance); furi_assert(callback); instance->callback = callback; instance->context = context; - instance->prev_state = MfClassicPollerStateStart; - instance->state = MfClassicPollerStateIdle; - - return mf_classic_poller_start(instance, mf_classic_dict_attack_callback, instance); } -MfClassicError mf_classic_poller_reset(MfClassicPoller* instance) { +const MfClassicData* mf_classic_poller_get_data(const MfClassicPoller* instance) { furi_assert(instance); furi_assert(instance->data); - furi_assert(instance->nfca_poller); - furi_assert(instance->tx_plain_buffer); - furi_assert(instance->rx_plain_buffer); - furi_assert(instance->tx_encrypted_buffer); - furi_assert(instance->rx_encrypted_buffer); - - instance->auth_state = MfClassicAuthStateIdle; - crypto1_free(instance->crypto); - bit_buffer_free(instance->tx_plain_buffer); - bit_buffer_free(instance->rx_plain_buffer); - bit_buffer_free(instance->tx_encrypted_buffer); - bit_buffer_free(instance->rx_encrypted_buffer); - instance->callback = NULL; - instance->context = NULL; - return MfClassicErrorNone; + return instance->data; } -MfClassicError mf_classic_poller_stop(MfClassicPoller* instance) { - furi_assert(instance); - furi_assert(instance->nfca_poller); - - instance->session_state = MfClassicPollerSessionStateStopRequest; - nfca_poller_stop(instance->nfca_poller); - instance->session_state = MfClassicPollerSessionStateIdle; - mf_classic_free(instance->data); - - return mf_classic_poller_reset(instance); -} +const NfcPollerBase mf_classic_poller = { + .alloc = (NfcPollerAlloc)mf_classic_poller_alloc, + .free = (NfcPollerFree)mf_classic_poller_free, + .set_callback = (NfcPollerSetCallback)mf_classic_poller_set_callback, + .run = (NfcPollerRun)mf_classsic_poller_run, + .detect = (NfcPollerDetect)mf_classsic_poller_detect, + .get_data = (NfcPollerGetData)mf_classic_poller_get_data, +}; diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller.h b/lib/nfc/protocols/mf_classic/mf_classic_poller.h index fc22f65f50b4..ced38777c26d 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller.h +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller.h @@ -49,57 +49,6 @@ typedef struct { MfClassicPollerEventData* data; } MfClassicPollerEvent; -typedef enum { - MfClassicPollerCommandContinue = NfcaPollerCommandContinue, - MfClassicPollerCommandReset = NfcaPollerCommandReset, - MfClassicPollerCommandStop = NfcaPollerCommandStop, - MfClassicPollerCommandRestart, -} MfClassicPollerCommand; - -typedef MfClassicPollerCommand ( - *MfClassicPollerCallback)(MfClassicPollerEvent event, void* context); - -MfClassicPoller* mf_classic_poller_alloc(NfcaPoller* nfca_poller); - -void mf_classic_poller_free(MfClassicPoller* instance); - -const MfClassicData* mf_classic_poller_get_data(MfClassicPoller* instance); - -MfClassicError mf_classic_poller_start( - MfClassicPoller* instance, - NfcaPollerEventCallback callback, - void* context); - -MfClassicError mf_classic_poller_dict_attack( - MfClassicPoller* instance, - MfClassicPollerCallback callback, - void* context); - -MfClassicError mf_classic_poller_reset(MfClassicPoller* instance); - -MfClassicError mf_classic_poller_stop(MfClassicPoller* instance); - -// Sync api - -MfClassicError mf_classic_poller_auth( - MfClassicPoller* instance, - uint8_t block_num, - MfClassicKey* key, - MfClassicKeyType key_type, - MfClassicAuthContext* data); - -MfClassicError mf_classic_poller_read_block( - MfClassicPoller* instance, - uint8_t block_num, - MfClassicKey* key, - MfClassicKeyType key_type, - MfClassicBlock* data); - -MfClassicError mf_classic_poller_read( - MfClassicPoller* instance, - MfClassicDeviceKeys* keys, - MfClassicData* data); - #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_defs.h b/lib/nfc/protocols/mf_classic/mf_classic_poller_defs.h new file mode 100644 index 000000000000..09b86c04c351 --- /dev/null +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_defs.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +extern const NfcPollerBase mf_classic_poller; diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h index 6d412bf2760f..ff68153d9a05 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h @@ -9,12 +9,6 @@ extern "C" { #endif -typedef enum { - MfClassicPollerSessionStateIdle, - MfClassicPollerSessionStateActive, - MfClassicPollerSessionStateStopRequest, -} MfClassicPollerSessionState; - typedef enum { MfClassicAuthStateIdle, MfClassicAuthStatePassed, @@ -45,14 +39,14 @@ typedef enum { struct MfClassicPoller { NfcaPoller* nfca_poller; + MfClassicPollerState state; MfClassicPollerState prev_state; - MfClassicPollerSessionState session_state; MfClassicAuthState auth_state; MfClassicCardState card_state; + MfClassicReadMode read_mode; MfClassicKey current_key; - MfClassicPollerEventData event_data; uint8_t sectors_read; uint8_t key_reuse_sector; uint8_t sectors_total; @@ -62,7 +56,11 @@ struct MfClassicPoller { BitBuffer* rx_plain_buffer; BitBuffer* rx_encrypted_buffer; MfClassicData* data; - MfClassicPollerCallback callback; + + NfcPollerEvent general_event; + MfClassicPollerEvent mfc_event; + MfClassicPollerEventData mfc_event_data; + NfcPollerCallback callback; void* context; }; @@ -80,6 +78,10 @@ typedef union { MfClassicError mf_classic_process_error(NfcaError error); +MfClassicPoller* mf_classic_poller_alloc(NfcaPoller* nfca_poller); + +void mf_classic_poller_free(MfClassicPoller* instance); + MfClassicError mf_classic_async_auth( MfClassicPoller* instance, uint8_t block_num, diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.c b/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.c index 76ed3baf0a8e..5276af17a1e4 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.c @@ -1,126 +1,151 @@ #include "mf_classic_poller_i.h" +#include + #include #define MF_CLASSIC_POLLER_COMPLETE_EVENT (1UL << 0) +typedef enum { + MfClassicPollerCmdTypeAuth, + MfClassicPollerCmdTypeReadBlock, + + MfClassicPollerCmdTypeNum, +} MfClassicPollerCmdType; + typedef struct { - MfClassicPoller* instance; + MfClassicPollerCmdType cmd_type; FuriThreadId thread_id; MfClassicError error; MfClassicPollerContextData data; } MfClassicPollerContext; -NfcaPollerCommand mf_classic_auth_callback(NfcaPollerEvent event, void* context) { +typedef MfClassicError ( + *MfClassicPollerCmdHandler)(MfClassicPoller* poller, MfClassicPollerContextData* data); + +static MfClassicError + mf_classic_poller_auth_handler(MfClassicPoller* poller, MfClassicPollerContextData* data) { + return mf_classic_async_auth( + poller, + data->auth_context.block_num, + &data->auth_context.key, + data->auth_context.key_type, + &data->auth_context); +} + +static MfClassicError mf_classic_poller_read_block_handler( + MfClassicPoller* poller, + MfClassicPollerContextData* data) { + MfClassicError error = MfClassicErrorNone; + + error = mf_classic_async_auth( + poller, + data->read_block_context.block_num, + &data->read_block_context.key, + data->read_block_context.key_type, + NULL); + if(error == MfClassicErrorNone) { + error = mf_classic_async_read_block( + poller, data->read_block_context.block_num, &data->read_block_context.block); + } + + return error; +} + +static const MfClassicPollerCmdHandler mf_classic_poller_cmd_handlers[MfClassicPollerCmdTypeNum] = { + [MfClassicPollerCmdTypeAuth] = mf_classic_poller_auth_handler, + [MfClassicPollerCmdTypeReadBlock] = mf_classic_poller_read_block_handler, +}; + +static NfcCommand mf_ultralgiht_poller_cmd_callback(NfcPollerEvent event, void* context) { + furi_assert(event.poller); + furi_assert(event.protocol_type == NfcProtocolTypeIso14443_3a); + furi_assert(event.data); furi_assert(context); MfClassicPollerContext* poller_context = context; - MfClassicAuthContext* auth_context = &poller_context->data.auth_context; - if(event.type == NfcaPollerEventTypeReady) { - poller_context->error = mf_classic_async_auth( - poller_context->instance, - auth_context->block_num, - &auth_context->key, - auth_context->key_type, - auth_context); - } else if(event.type == NfcaPollerEventTypeError) { - poller_context->error = mf_classic_process_error(event.data.error); + NfcaPollerEvent* nfca_event = event.data; + NfcaPoller* nfca_poller = event.poller; + MfClassicPoller* mfc_poller = mf_classic_poller_alloc(nfca_poller); + + if(nfca_event->type == NfcaPollerEventTypeReady) { + poller_context->error = mf_classic_poller_cmd_handlers[poller_context->cmd_type]( + mfc_poller, &poller_context->data); + } else if(nfca_event->type == NfcaPollerEventTypeError) { + poller_context->error = mf_classic_process_error(nfca_event->data->error); } + furi_thread_flags_set(poller_context->thread_id, MF_CLASSIC_POLLER_COMPLETE_EVENT); - return NfcaPollerCommandStop; + mf_classic_poller_free(mfc_poller); + + return NfcCommandStop; +} + +static MfClassicError mf_classic_poller_cmd_execute(Nfc* nfc, MfClassicPollerContext* poller_ctx) { + furi_assert(poller_ctx->cmd_type < MfClassicPollerCmdTypeNum); + + poller_ctx->thread_id = furi_thread_get_current_id(); + + NfcPoller* poller = nfc_poller_alloc(nfc, NfcProtocolTypeIso14443_3a); + nfc_poller_start(poller, mf_ultralgiht_poller_cmd_callback, poller_ctx); + furi_thread_flags_wait(MF_CLASSIC_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); + furi_thread_flags_clear(MF_CLASSIC_POLLER_COMPLETE_EVENT); + + nfc_poller_stop(poller); + nfc_poller_free(poller); + + return poller_ctx->error; } MfClassicError mf_classic_poller_auth( - MfClassicPoller* instance, + Nfc* nfc, uint8_t block_num, MfClassicKey* key, MfClassicKeyType key_type, MfClassicAuthContext* data) { - furi_assert(instance); + furi_assert(nfc); furi_assert(key); furi_assert(data); - MfClassicPollerContext poller_context = {}; - poller_context.data.auth_context.block_num = block_num; - poller_context.data.auth_context.key = *key; - poller_context.data.auth_context.key_type = key_type; - poller_context.instance = instance; - poller_context.thread_id = furi_thread_get_current_id(); + MfClassicPollerContext poller_context = { + .cmd_type = MfClassicPollerCmdTypeAuth, + .data.auth_context.block_num = block_num, + .data.auth_context.key = *key, + .data.auth_context.key_type = key_type, + }; - mf_classic_poller_start(instance, mf_classic_auth_callback, &poller_context); - furi_thread_flags_wait(MF_CLASSIC_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); - furi_thread_flags_clear(MF_CLASSIC_POLLER_COMPLETE_EVENT); + MfClassicError error = mf_classic_poller_cmd_execute(nfc, &poller_context); - if(poller_context.error == MfClassicErrorNone) { + if(error == MfClassicErrorNone) { *data = poller_context.data.auth_context; } - mf_classic_poller_stop(instance); - - return poller_context.error; -} - -NfcaPollerCommand mf_classic_read_block_callback(NfcaPollerEvent event, void* context) { - furi_assert(context); - - MfClassicPollerContext* poller_context = context; - MfClassicReadBlockContext* read_block_context = &poller_context->data.read_block_context; - NfcaPollerCommand command = NfcaPollerCommandContinue; - - if(event.type == NfcaPollerEventTypeReady) { - if(poller_context->instance->auth_state == MfClassicAuthStateIdle) { - poller_context->error = mf_classic_async_auth( - poller_context->instance, - read_block_context->block_num, - &read_block_context->key, - read_block_context->key_type, - NULL); - if(poller_context->error != MfClassicErrorNone) { - command = NfcaPollerCommandStop; - } - } else { - poller_context->error = mf_classic_async_read_block( - poller_context->instance, - read_block_context->block_num, - &read_block_context->block); - command = NfcaPollerCommandStop; - } - } else if(event.type == NfcaPollerEventTypeError) { - poller_context->error = mf_classic_process_error(event.data.error); - command = NfcaPollerCommandStop; - } - if(command == NfcaPollerCommandStop) { - furi_thread_flags_set(poller_context->thread_id, MF_CLASSIC_POLLER_COMPLETE_EVENT); - } - return command; + return error; } MfClassicError mf_classic_poller_read_block( - MfClassicPoller* instance, + Nfc* nfc, uint8_t block_num, MfClassicKey* key, MfClassicKeyType key_type, MfClassicBlock* data) { - furi_assert(instance); + furi_assert(nfc); furi_assert(key); furi_assert(data); - MfClassicPollerContext poller_context = {}; - poller_context.data.read_block_context.block_num = block_num; - poller_context.data.read_block_context.key = *key; - poller_context.data.read_block_context.key_type = key_type; - poller_context.instance = instance; - poller_context.thread_id = furi_thread_get_current_id(); + MfClassicPollerContext poller_context = { + .cmd_type = MfClassicPollerCmdTypeReadBlock, + .data.read_block_context.block_num = block_num, + .data.read_block_context.key = *key, + .data.read_block_context.key_type = key_type, + }; - mf_classic_poller_start(instance, mf_classic_read_block_callback, &poller_context); - furi_thread_flags_wait(MF_CLASSIC_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); - furi_thread_flags_clear(MF_CLASSIC_POLLER_COMPLETE_EVENT); + MfClassicError error = mf_classic_poller_cmd_execute(nfc, &poller_context); - if(poller_context.error == MfClassicErrorNone) { + if(error == MfClassicErrorNone) { *data = poller_context.data.read_block_context.block; } - mf_classic_poller_stop(instance); - return poller_context.error; + return error; } diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.h b/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.h new file mode 100644 index 000000000000..278a7e86584f --- /dev/null +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.h @@ -0,0 +1,26 @@ +#pragma once + +#include "mf_classic.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +MfClassicError mf_classic_poller_auth( + Nfc* nfc, + uint8_t block_num, + MfClassicKey* key, + MfClassicKeyType key_type, + MfClassicAuthContext* data); + +MfClassicError mf_classic_poller_read_block( + Nfc* nfc, + uint8_t block_num, + MfClassicKey* key, + MfClassicKeyType key_type, + MfClassicBlock* data); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c b/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c index e55394bb98ef..997f0f330f24 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c @@ -1,5 +1,7 @@ #include "mf_desfire_poller_i.h" +#include + #include #define TAG "MfDesfirePoller" diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_poller.h b/lib/nfc/protocols/mf_desfire/mf_desfire_poller.h index fb2638df5293..360b0508ff00 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_poller.h +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_poller.h @@ -26,8 +26,6 @@ typedef struct { MfDesfirePollerEventData* data; } MfDesfirePollerEvent; -const MfDesfireData* mf_desfire_poller_get_data(MfDesfirePoller* instance); - #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.h b/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.h index c886046e0c73..9a5e7096a0ff 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.h +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.h @@ -49,6 +49,8 @@ struct MfDesfirePoller { MfDesfireError mf_desfire_process_error(Iso14443_4aError error); +const MfDesfireData* mf_desfire_poller_get_data(MfDesfirePoller* instance); + MfDesfireError mf_desfire_send_chunks( MfDesfirePoller* instance, const BitBuffer* tx_buffer, diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c index 424f3b8ff719..f01fd936b865 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c @@ -1,5 +1,7 @@ #include "mf_ultralight_poller_i.h" +#include + #include #define TAG "MfUltralightPoller" diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h index d4d25d4d04a0..d350ee177f87 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h @@ -36,8 +36,6 @@ typedef struct { MfUltralightPollerEventData* data; } MfUltralightPollerEvent; -const MfUltralightData* mf_ultralight_poller_get_data(MfUltralightPoller* instance); - #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h index 4786f3c7951b..9128292a105a 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h @@ -93,6 +93,8 @@ MfUltralightPoller* mf_ultralight_poller_alloc(NfcaPoller* nfca_poller); void mf_ultralight_poller_free(MfUltralightPoller* instance); +const MfUltralightData* mf_ultralight_poller_get_data(MfUltralightPoller* instance); + bool mf_ultralight_poller_ntag_i2c_addr_lin_to_tag( MfUltralightPoller* instance, uint16_t lin_addr, diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c index 3f956302e90f..cc5c0408ac75 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c @@ -1,6 +1,6 @@ #include "mf_ultralight_poller_i.h" -#include +#include #include @@ -94,7 +94,7 @@ static NfcCommand mf_ultralgiht_poller_cmd_callback(NfcPollerEvent event, void* poller_context->error = mf_ultralight_poller_cmd_handlers[poller_context->cmd_type]( mfu_poller, &poller_context->data); } else if(nfca_event->type == NfcaPollerEventTypeError) { - poller_context->error = mf_ultralight_process_error(nfca_event->data.error); + poller_context->error = mf_ultralight_process_error(nfca_event->data->error); } furi_thread_flags_set(poller_context->thread_id, MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); @@ -109,15 +109,14 @@ static MfUltralightError furi_assert(poller_ctx->cmd_type < MfUltralightPollerCmdTypeNum); poller_ctx->thread_id = furi_thread_get_current_id(); - NfcPollerManager* poller_manager = nfc_poller_manager_alloc(nfc); - nfc_poller_manager_start( - poller_manager, NfcProtocolTypeIso14443_3a, mf_ultralgiht_poller_cmd_callback, poller_ctx); + NfcPoller* poller = nfc_poller_alloc(nfc, NfcProtocolTypeIso14443_3a); + nfc_poller_start(poller, mf_ultralgiht_poller_cmd_callback, poller_ctx); furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); furi_thread_flags_clear(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); - nfc_poller_manager_stop(poller_manager); - nfc_poller_manager_free(poller_manager); + nfc_poller_stop(poller); + nfc_poller_free(poller); return poller_ctx->error; } @@ -268,18 +267,15 @@ MfUltralightError mf_ultralight_poller_read_card(Nfc* nfc, MfUltralightData* dat MfUltralightPollerContext poller_context = {}; poller_context.thread_id = furi_thread_get_current_id(); - NfcPollerManager* poller_manager = nfc_poller_manager_alloc(nfc); - nfc_poller_manager_start( - poller_manager, - NfcProtocolTypeMfUltralight, - mf_ultralight_poller_read_callback, - &poller_context); + NfcPoller* poller = nfc_poller_alloc(nfc, NfcProtocolTypeMfUltralight); + nfc_poller_start(poller, mf_ultralight_poller_read_callback, &poller_context); furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); furi_thread_flags_clear(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); - nfc_poller_manager_stop(poller_manager); - nfc_poller_manager_free(poller_manager); + nfc_poller_stop(poller); + nfc_poller_free(poller); + if(poller_context.error == MfUltralightErrorNone) { mf_ultralight_copy(data, &poller_context.data.data); } diff --git a/lib/nfc/protocols/nfc_poller_base.h b/lib/nfc/protocols/nfc_poller_base.h index 6cf5f127263b..351e17defd69 100644 --- a/lib/nfc/protocols/nfc_poller_base.h +++ b/lib/nfc/protocols/nfc_poller_base.h @@ -1,31 +1,19 @@ #pragma once -#include "nfc_protocol_defs.h" -#include "nfc.h" +#include "nfc_poller_common.h" #ifdef __cplusplus extern "C" { #endif -typedef void NfcPoller; +typedef NfcPollerInstance* (*NfcPollerAlloc)(NfcPollerInstance* base_poller); +typedef void (*NfcPollerFree)(NfcPollerInstance* instance); -typedef void NfcPollerEventData; - -typedef struct { - NfcProtocolType protocol_type; - NfcPoller* poller; - NfcPollerEventData* data; -} NfcPollerEvent; - -typedef NfcCommand (*NfcPollerCallback)(NfcPollerEvent event, void* context); - -typedef NfcPoller* (*NfcPollerAlloc)(NfcPoller* base_poller); -typedef void (*NfcPollerFree)(NfcPoller* instance); - -typedef void (*NfcPollerSetCallback)(NfcPoller* poller, NfcPollerCallback callback, void* context); +typedef void ( + *NfcPollerSetCallback)(NfcPollerInstance* poller, NfcPollerCallback callback, void* context); typedef NfcCommand (*NfcPollerRun)(NfcPollerEvent event, void* context); typedef bool (*NfcPollerDetect)(NfcPollerEvent event, void* context); -typedef const NfcProtocolData* (*NfcPollerGetData)(const NfcPoller* instance); +typedef const NfcProtocolData* (*NfcPollerGetData)(const NfcPollerInstance* instance); typedef struct { NfcPollerAlloc alloc; diff --git a/lib/nfc/protocols/nfc_poller_common.h b/lib/nfc/protocols/nfc_poller_common.h new file mode 100644 index 000000000000..67e7f9af19d5 --- /dev/null +++ b/lib/nfc/protocols/nfc_poller_common.h @@ -0,0 +1,24 @@ +#pragma once + +#include "nfc_protocol_defs.h" +#include "nfc.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void NfcPollerInstance; + +typedef void NfcPollerEventData; + +typedef struct { + NfcProtocolType protocol_type; + NfcPollerInstance* poller; + NfcPollerEventData* data; +} NfcPollerEvent; + +typedef NfcCommand (*NfcPollerCallback)(NfcPollerEvent event, void* context); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/nfc_poller_defs.c b/lib/nfc/protocols/nfc_poller_defs.c index bc530c1bd5ed..afcda822061b 100644 --- a/lib/nfc/protocols/nfc_poller_defs.c +++ b/lib/nfc/protocols/nfc_poller_defs.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -11,7 +12,7 @@ const NfcPollerBase* nfc_pollers_api[NfcProtocolTypeMax] = { [NfcProtocolTypeIso14443_3a] = &nfc_poller_iso14443_3a, [NfcProtocolTypeIso14443_4a] = &nfc_poller_iso14443_4a, [NfcProtocolTypeMfUltralight] = &mf_ultralight_poller, - [NfcProtocolTypeMfClassic] = NULL, + [NfcProtocolTypeMfClassic] = &mf_classic_poller, [NfcProtocolTypeMfDesfire] = &mf_desfire_poller, }; diff --git a/lib/nfc/protocols/nfca/nfca_poller.c b/lib/nfc/protocols/nfca/nfca_poller.c index bc09100fc751..619932dbc2c6 100644 --- a/lib/nfc/protocols/nfca/nfca_poller.c +++ b/lib/nfc/protocols/nfca/nfca_poller.c @@ -1,196 +1,122 @@ #include "nfca_poller_i.h" +#include + #include #define TAG "NFCA" -#define NFCA_POLLER_FLAG_COMMAND_COMPLETE (1UL << 0) +const NfcaData* nfca_poller_get_data(NfcaPoller* instance) { + furi_assert(instance); + furi_assert(instance->data); -typedef struct { - NfcaPoller* instance; - FuriThreadId thread_id; - NfcaError error; - NfcaData data; -} NfcaPollerContext; + return instance->data; +} -NfcaPoller* nfca_poller_alloc(Nfc* nfc) { +static NfcaPoller* nfca_poller_alloc(Nfc* nfc) { furi_assert(nfc); NfcaPoller* instance = malloc(sizeof(NfcaPoller)); instance->nfc = nfc; + instance->tx_buffer = bit_buffer_alloc(NFCA_POLLER_MAX_BUFFER_SIZE); + instance->rx_buffer = bit_buffer_alloc(NFCA_POLLER_MAX_BUFFER_SIZE); - return instance; -} - -void nfca_poller_free(NfcaPoller* instance) { - furi_assert(instance); - furi_assert(instance->nfc); - - free(instance); -} - -const NfcaData* nfca_poller_get_data(NfcaPoller* instance) { - furi_assert(instance); - - return instance->data; -} + nfc_config(instance->nfc, NfcModeNfcaPoller); + nfc_set_guard_time_us(instance->nfc, NFCA_GUARD_TIME_US); + nfc_set_fdt_poll_fc(instance->nfc, NFCA_FDT_POLL_FC); + nfc_set_fdt_poll_poll_us(instance->nfc, NFCA_POLL_POLL_MIN_US); + instance->data = nfca_alloc(); -static NfcCommand nfca_poller_process_command(NfcaPollerCommand command) { - NfcCommand ret = NfcCommandContinue; - - if(command == NfcaPollerCommandContinue) { - ret = NfcCommandContinue; - } else if(command == NfcaPollerCommandReset) { - ret = NfcCommandReset; - } else if(command == NfcaPollerCommandStop) { - ret = NfcCommandStop; - } else { - furi_crash("Unknown command"); - } + instance->nfca_event.data = &instance->nfca_event_data; + instance->general_event.protocol_type = NfcProtocolTypeIso14443_3a; + instance->general_event.data = &instance->nfca_event; + instance->general_event.poller = instance; - return ret; + return instance; } -static NfcCommand nfca_poller_event_callback(NfcEvent event, void* context) { - furi_assert(context); +static void nfca_poller_free_new(NfcaPoller* nfca_poller) { + furi_assert(nfca_poller); - NfcaPoller* instance = context; - furi_assert(instance->callback); - furi_assert(instance->session_state != NfcaPollerSessionStateIdle); - - NfcaPollerEvent nfca_poller_event = {}; - NfcaPollerCommand command = NfcaPollerCommandContinue; - - if(instance->session_state == NfcaPollerSessionStateStopRequest) { - command = NfcaPollerCommandStop; - } else { - if(event.type == NfcEventTypeConfigureRequest) { - nfca_poller_config(instance); - } else if(event.type == NfcEventTypePollerReady) { - if(instance->state != NfcaPollerStateActivated) { - NfcaData data = {}; - NfcaError error = nfca_poller_async_activate(instance, &data); - if(error == NfcaErrorNone) { - nfca_poller_event.type = NfcaPollerEventTypeReady; - instance->state = NfcaPollerStateActivated; - nfca_poller_event.data.error = error; - command = instance->callback(nfca_poller_event, instance->context); - } else { - nfca_poller_event.type = NfcaPollerEventTypeError; - nfca_poller_event.data.error = error; - command = instance->callback(nfca_poller_event, instance->context); - // Add delay to switch context - furi_delay_ms(100); - } - } else { - nfca_poller_event.type = NfcaPollerEventTypeReady; - nfca_poller_event.data.error = NfcaErrorNone; - command = instance->callback(nfca_poller_event, instance->context); - } - } else if(event.type == NfcEventTypeReset) { - nfca_poller_reset(instance); - } - } + NfcaPoller* instance = nfca_poller; + furi_assert(instance->tx_buffer); + furi_assert(instance->rx_buffer); + furi_assert(instance->data); - return nfca_poller_process_command(command); + bit_buffer_free(instance->tx_buffer); + bit_buffer_free(instance->rx_buffer); + nfca_free(instance->data); + free(instance); } -NfcaError - nfca_poller_start(NfcaPoller* instance, NfcaPollerEventCallback callback, void* context) { +static void + nfca_poller_set_callback(NfcaPoller* instance, NfcPollerCallback callback, void* context) { furi_assert(instance); furi_assert(callback); - furi_assert(instance->session_state == NfcaPollerSessionStateIdle); instance->callback = callback; instance->context = context; - - instance->data = nfca_alloc(); - - instance->session_state = NfcaPollerSessionStateActive; - nfc_start_poller(instance->nfc, nfca_poller_event_callback, instance); - - return NfcaErrorNone; } -NfcaError nfca_poller_stop(NfcaPoller* instance) { - furi_assert(instance); - furi_assert(instance->data); - - NfcaError error = NfcaErrorNone; - - instance->session_state = NfcaPollerSessionStateStopRequest; - nfc_stop(instance->nfc); - instance->session_state = NfcaPollerSessionStateIdle; - - if(instance->config_state == NfcaPollerConfigStateDone) { - error = nfca_poller_reset(instance); - } - - // Check that data is freed - furi_assert(instance->tx_buffer == NULL); - furi_assert(instance->rx_buffer == NULL); - - nfca_free(instance->data); - - return error; -} - -static NfcaPollerCommand nfca_poller_sync_callback(NfcaPollerEvent event, void* context) { - NfcaPollerContext* nfca_poller_context = context; - nfca_poller_context->error = event.data.error; - furi_thread_flags_set(nfca_poller_context->thread_id, NFCA_POLLER_FLAG_COMMAND_COMPLETE); - - return NfcaPollerCommandStop; -} +static NfcCommand nfca_poller_run(NfcPollerEvent event, void* context) { + furi_assert(context); + furi_assert(event.protocol_type == NfcProtocolTypeInvalid); + furi_assert(event.data); -NfcaError nfca_poller_read(NfcaPoller* instance, NfcaData* nfca_data) { - furi_assert(instance); + NfcaPoller* instance = context; + NfcEvent* nfc_event = event.data; + NfcCommand command = NfcCommandContinue; - NfcaPollerContext context = {}; - context.instance = instance; - context.thread_id = furi_thread_get_current_id(); - nfca_poller_start(instance, nfca_poller_sync_callback, &context); - furi_thread_flags_wait(NFCA_POLLER_FLAG_COMMAND_COMPLETE, FuriFlagWaitAny, FuriWaitForever); - furi_thread_flags_clear(NFCA_POLLER_FLAG_COMMAND_COMPLETE); - if(context.error == NfcaErrorNone) { - nfca_copy(nfca_data, instance->data); + if(nfc_event->type == NfcEventTypePollerReady) { + if(instance->state != NfcaPollerStateActivated) { + NfcaData data = {}; + NfcaError error = nfca_poller_async_activate(instance, &data); + if(error == NfcaErrorNone) { + instance->state = NfcaPollerStateActivated; + instance->nfca_event.type = NfcaPollerEventTypeReady; + instance->nfca_event_data.error = error; + command = instance->callback(instance->general_event, instance->context); + } else { + instance->nfca_event.type = NfcaPollerEventTypeError; + instance->nfca_event_data.error = error; + command = instance->callback(instance->general_event, instance->context); + // Add delay to switch context + furi_delay_ms(100); + } + } else { + instance->nfca_event.type = NfcaPollerEventTypeReady; + instance->nfca_event_data.error = NfcaErrorNone; + command = instance->callback(instance->general_event, instance->context); + } } - nfc_stop(instance->nfc); - return context.error; + return command; } -NfcCommand nfca_poller_read_new_callback(NfcPollerEvent event, void* context) { - furi_assert(event.poller); - furi_assert(event.data); +static bool nfca_poller_detect(NfcPollerEvent event, void* context) { furi_assert(context); + furi_assert(event.data); + furi_assert(event.poller); + furi_assert(event.protocol_type = NfcProtocolTypeInvalid); - NfcaPollerContext* nfca_poller_context = context; - NfcaPoller* nfca_poller = event.poller; + bool protocol_detected = false; + NfcaPoller* instance = context; NfcEvent* nfc_event = event.data; + furi_assert(instance->state == NfcaPollerStateIdle); + if(nfc_event->type == NfcEventTypePollerReady) { - nfca_poller_context->error = - nfca_poller_async_activate(nfca_poller, &nfca_poller_context->data); + NfcaError error = nfca_poller_async_activate(instance, NULL); + protocol_detected = (error == NfcaErrorNone); } - furi_thread_flags_set(nfca_poller_context->thread_id, NFCA_POLLER_FLAG_COMMAND_COMPLETE); - return NfcCommandStop; + return protocol_detected; } -NfcaError nfca_poller_read_new(NfcPollerManager* poller_manager, NfcaData* nfca_data) { - furi_assert(poller_manager); - furi_assert(nfca_data); - - NfcaPollerContext context = {}; - context.thread_id = furi_thread_get_current_id(); - - nfc_poller_manager_start( - poller_manager, NfcProtocolTypeIso14443_3a, nfca_poller_read_new_callback, &context); - - furi_thread_flags_wait(NFCA_POLLER_FLAG_COMMAND_COMPLETE, FuriFlagWaitAny, FuriWaitForever); - furi_thread_flags_clear(NFCA_POLLER_FLAG_COMMAND_COMPLETE); - - nfc_poller_manager_stop(poller_manager); - - return context.error; -} \ No newline at end of file +const NfcPollerBase nfc_poller_iso14443_3a = { + .alloc = (NfcPollerAlloc)nfca_poller_alloc, + .free = (NfcPollerFree)nfca_poller_free_new, + .set_callback = (NfcPollerSetCallback)nfca_poller_set_callback, + .run = (NfcPollerRun)nfca_poller_run, + .detect = (NfcPollerDetect)nfca_poller_detect, + .get_data = (NfcPollerGetData)nfca_poller_get_data, +}; diff --git a/lib/nfc/protocols/nfca/nfca_poller.h b/lib/nfc/protocols/nfca/nfca_poller.h index b411ed3b503b..7a8a4dd5ed98 100644 --- a/lib/nfc/protocols/nfca/nfca_poller.h +++ b/lib/nfc/protocols/nfca/nfca_poller.h @@ -3,7 +3,7 @@ #include "nfca.h" #include -#include +#include #ifdef __cplusplus extern "C" { @@ -22,32 +22,9 @@ typedef struct { typedef struct { NfcaPollerEventType type; - NfcaPollerEventData data; + NfcaPollerEventData* data; } NfcaPollerEvent; -typedef enum { - NfcaPollerCommandContinue = NfcCommandContinue, - NfcaPollerCommandReset = NfcCommandReset, - NfcaPollerCommandStop = NfcCommandStop, -} NfcaPollerCommand; - -typedef NfcaPollerCommand (*NfcaPollerEventCallback)(NfcaPollerEvent event, void* context); - -NfcaPoller* nfca_poller_alloc(Nfc* nfc); - -void nfca_poller_free(NfcaPoller* instance); - -const NfcaData* nfca_poller_get_data(NfcaPoller* instance); - -NfcaError nfca_poller_start(NfcaPoller* instance, NfcaPollerEventCallback callback, void* context); - -NfcaError nfca_poller_stop(NfcaPoller* instance); - -// Sync call -NfcaError nfca_poller_read(NfcaPoller* instance, NfcaData* nfca_data); - -NfcaError nfca_poller_read_new(NfcPollerManager* poller_manager, NfcaData* nfca_data); - #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/nfca/nfca_poller_i.c b/lib/nfc/protocols/nfca/nfca_poller_i.c index 8e0caaa5ad6a..20753d16e474 100644 --- a/lib/nfc/protocols/nfca/nfca_poller_i.c +++ b/lib/nfc/protocols/nfca/nfca_poller_i.c @@ -345,123 +345,3 @@ NfcaError nfca_poller_send_standart_frame( return ret; } - -static NfcPoller* nfca_poller_alloc_new(NfcPoller* nfc) { - furi_assert(nfc); - - NfcaPoller* instance = malloc(sizeof(NfcaPoller)); - instance->nfc = nfc; - instance->tx_buffer = bit_buffer_alloc(NFCA_POLLER_MAX_BUFFER_SIZE); - instance->rx_buffer = bit_buffer_alloc(NFCA_POLLER_MAX_BUFFER_SIZE); - - nfc_config(instance->nfc, NfcModeNfcaPoller); - nfc_set_guard_time_us(instance->nfc, NFCA_GUARD_TIME_US); - nfc_set_fdt_poll_fc(instance->nfc, NFCA_FDT_POLL_FC); - nfc_set_fdt_poll_poll_us(instance->nfc, NFCA_POLL_POLL_MIN_US); - instance->data = nfca_alloc(); - instance->event = malloc(sizeof(NfcaPollerEvent)); - - return instance; -} - -static void nfca_poller_free_new(NfcPoller* nfca_poller) { - furi_assert(nfca_poller); - - NfcaPoller* instance = nfca_poller; - furi_assert(instance->tx_buffer); - furi_assert(instance->rx_buffer); - furi_assert(instance->data); - furi_assert(instance->event); - - bit_buffer_free(instance->tx_buffer); - bit_buffer_free(instance->rx_buffer); - nfca_free(instance->data); - free(instance->event); - free(instance); -} - -static void - nfca_poller_set_callback(NfcPoller* poller, NfcPollerCallback callback, void* context) { - furi_assert(poller); - furi_assert(callback); - - NfcaPoller* instance = poller; - instance->callback_new = callback; - instance->context_new = context; -} - -static NfcCommand nfca_poller_run(NfcPollerEvent event, void* context) { - furi_assert(context); - - NfcaPoller* instance = context; - NfcEvent* nfc_event = event.data; - NfcCommand command = NfcCommandContinue; - NfcPollerEvent nfca_poller_event = { - .protocol_type = NfcProtocolTypeIso14443_3a, - .poller = instance, - }; - - if(nfc_event->type == NfcEventTypePollerReady) { - if(instance->state != NfcaPollerStateActivated) { - NfcaData data = {}; - NfcaError error = nfca_poller_async_activate(instance, &data); - if(error == NfcaErrorNone) { - instance->event->type = NfcaPollerEventTypeReady; - instance->event->data.error = error; - instance->state = NfcaPollerStateActivated; - nfca_poller_event.data = instance->event; - command = instance->callback_new(nfca_poller_event, instance->context_new); - } else { - instance->event->type = NfcaPollerEventTypeError; - instance->event->data.error = error; - nfca_poller_event.data = instance->event; - command = instance->callback_new(nfca_poller_event, instance->context_new); - // Add delay to switch context - furi_delay_ms(100); - } - } else { - instance->event->type = NfcaPollerEventTypeReady; - instance->event->data.error = NfcaErrorNone; - nfca_poller_event.data = instance->event; - command = instance->callback_new(nfca_poller_event, instance->context_new); - } - } - - return command; -} - -static bool nfca_poller_detect(NfcPollerEvent event, void* context) { - furi_assert(context); - furi_assert(event.data); - furi_assert(event.poller); - - bool protocol_detected = false; - NfcaPoller* instance = context; - NfcEvent* nfc_event = event.data; - furi_assert(instance->state == NfcaPollerStateIdle); - - if(nfc_event->type == NfcEventTypePollerReady) { - NfcaError error = nfca_poller_async_activate(instance, NULL); - protocol_detected = (error == NfcaErrorNone); - } - - return protocol_detected; -} - -static const NfcProtocolData* nfca_poller_get_data_new(const NfcPoller* nfca_poller) { - furi_assert(nfca_poller); - - const NfcaPoller* instance = nfca_poller; - furi_assert(instance->data); - - return instance->data; -} - -const NfcPollerBase nfc_poller_iso14443_3a = { - .alloc = nfca_poller_alloc_new, - .free = nfca_poller_free_new, - .set_callback = nfca_poller_set_callback, - .run = nfca_poller_run, - .detect = nfca_poller_detect, - .get_data = nfca_poller_get_data_new, -}; diff --git a/lib/nfc/protocols/nfca/nfca_poller_i.h b/lib/nfc/protocols/nfca/nfca_poller_i.h index 9e0d3748bde5..d777dd30f4e0 100644 --- a/lib/nfc/protocols/nfca/nfca_poller_i.h +++ b/lib/nfc/protocols/nfca/nfca_poller_i.h @@ -3,7 +3,6 @@ #include "nfca_poller.h" #include -#include #ifdef __cplusplus extern "C" { @@ -40,12 +39,6 @@ typedef enum { NfcaPollerStateActivated, } NfcaPollerState; -typedef enum { - NfcaPollerSessionStateIdle, - NfcaPollerSessionStateActive, - NfcaPollerSessionStateStopRequest, -} NfcaPollerSessionState; - typedef enum { NfcaPollerConfigStateIdle, NfcaPollerConfigStateDone, @@ -54,20 +47,21 @@ typedef enum { struct NfcaPoller { Nfc* nfc; NfcaPollerState state; - NfcaPollerSessionState session_state; NfcaPollerConfigState config_state; NfcaPollerColRes col_res; NfcaData* data; BitBuffer* tx_buffer; BitBuffer* rx_buffer; - NfcaPollerEventCallback callback; - void* context; - NfcaPollerEvent* event; - NfcPollerCallback callback_new; - void* context_new; + NfcPollerEvent general_event; + NfcaPollerEvent nfca_event; + NfcaPollerEventData nfca_event_data; + NfcPollerCallback callback; + void* context; }; +const NfcaData* nfca_poller_get_data(NfcaPoller* instance); + NfcaError nfca_poller_config(NfcaPoller* instance); NfcaError nfca_poller_reset(NfcaPoller* instance); diff --git a/lib/nfc/protocols/nfca/nfca_poller_sync_api.c b/lib/nfc/protocols/nfca/nfca_poller_sync_api.c new file mode 100644 index 000000000000..d77d621542fb --- /dev/null +++ b/lib/nfc/protocols/nfca/nfca_poller_sync_api.c @@ -0,0 +1,57 @@ +#include "nfca_poller_sync_api.h" + +#include "nfca_poller_i.h" +#include + +#include + +#define NFCA_POLLER_FLAG_COMMAND_COMPLETE (1UL << 0) + +typedef struct { + NfcaPoller* instance; + FuriThreadId thread_id; + NfcaError error; + NfcaData data; +} NfcaPollerContext; + +NfcCommand nfca_poller_read_callback(NfcPollerEvent event, void* context) { + furi_assert(context); + furi_assert(event.data); + furi_assert(event.poller); + furi_assert(event.protocol_type == NfcProtocolTypeIso14443_3a); + + NfcaPollerContext* poller_context = context; + NfcaPoller* nfca_poller = event.poller; + NfcaPollerEvent* nfca_event = event.data; + + if(nfca_event->type == NfcaPollerEventTypeReady) { + nfca_copy(&poller_context->data, nfca_poller->data); + } + poller_context->error = nfca_event->data->error; + + furi_thread_flags_set(poller_context->thread_id, NFCA_POLLER_FLAG_COMMAND_COMPLETE); + + return NfcCommandStop; +} + +NfcaError nfca_poller_read(Nfc* nfc, NfcaData* nfca_data) { + furi_assert(nfc); + furi_assert(nfca_data); + + NfcaPollerContext poller_context = {}; + poller_context.thread_id = furi_thread_get_current_id(); + + NfcPoller* poller = nfc_poller_alloc(nfc, NfcProtocolTypeIso14443_3a); + nfc_poller_start(poller, nfca_poller_read_callback, &poller_context); + furi_thread_flags_wait(NFCA_POLLER_FLAG_COMMAND_COMPLETE, FuriFlagWaitAny, FuriWaitForever); + furi_thread_flags_clear(NFCA_POLLER_FLAG_COMMAND_COMPLETE); + + nfc_poller_stop(poller); + nfc_poller_free(poller); + + if(poller_context.error == NfcaErrorNone) { + *nfca_data = poller_context.data; + } + + return poller_context.error; +} \ No newline at end of file diff --git a/lib/nfc/protocols/nfca/nfca_poller_sync_api.h b/lib/nfc/protocols/nfca/nfca_poller_sync_api.h new file mode 100644 index 000000000000..b187d4e498a8 --- /dev/null +++ b/lib/nfc/protocols/nfca/nfca_poller_sync_api.h @@ -0,0 +1,14 @@ +#pragma once + +#include "nfca.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +NfcaError nfca_poller_read(Nfc* nfc, NfcaData* nfca_data); + +#ifdef __cplusplus +} +#endif From f99273813e8b9fe41e8f571854c49b9b54d0be04 Mon Sep 17 00:00:00 2001 From: gornekich Date: Wed, 28 Jun 2023 15:25:31 +0400 Subject: [PATCH 113/149] Massive renaming (#2810) * nfc: rename nfca -> iso14443_3a * nfc: rename deprecated nfc_device * nfc: rename nfc_dev -> nfc_device * nfc: rename protocol_type -> protocol * nfc: rename nfc_protocol_defs -> nfc_device_defs * nfc: revert incorrect changes --- applications/debug/unit_tests/nfc/nfc_test.c | 59 ++-- .../scenes/nfc_magic_scene_file_select.c | 14 +- .../nfc/helpers/format/nfc_protocol_format.c | 53 ++-- .../nfc/helpers/format/nfc_protocol_format.h | 6 +- .../nfc/helpers/handlers/nfc_poller_handler.c | 40 +-- .../main/nfc/helpers/nfc_supported_cards.h | 6 +- applications/main/nfc/nfc_app.c | 24 +- applications/main/nfc/nfc_app_i.h | 16 +- applications/main/nfc/nfc_cli.c | 2 +- .../nfc/plugins/nfc_supported_card_plugin.h | 4 +- applications/main/nfc/plugins/troika.c | 2 +- .../main/nfc/scenes/nfc_scene_delete.c | 4 +- .../main/nfc/scenes/nfc_scene_generate_info.c | 14 +- applications/main/nfc/scenes/nfc_scene_info.c | 20 +- .../scenes/nfc_scene_mf_classic_dict_attack.c | 16 +- .../nfc/scenes/nfc_scene_mf_classic_menu.c | 3 +- .../nfc/scenes/nfc_scene_mf_desfire_app.c | 5 +- .../nfc/scenes/nfc_scene_mf_desfire_data.c | 4 +- .../scenes/nfc_scene_mf_ultralight_emulate.c | 3 +- .../nfc/scenes/nfc_scene_mf_ultralight_menu.c | 3 +- .../nfc_scene_mf_ultralight_unlock_menu.c | 2 +- .../nfc_scene_mf_ultralight_unlock_warn.c | 2 +- .../main/nfc/scenes/nfc_scene_nfca_emulate.c | 18 +- applications/main/nfc/scenes/nfc_scene_read.c | 5 +- .../main/nfc/scenes/nfc_scene_read_success.c | 18 +- .../main/nfc/scenes/nfc_scene_saved_menu.c | 20 +- .../nfc/scenes/nfc_scene_select_protocol.c | 9 +- .../main/nfc/scenes/nfc_scene_set_uid.c | 10 +- applications/main/nfc_rpc/nfc_rpc.c | 6 +- applications/main/nfc_rpc/nfc_rpc_i.h | 6 +- .../main/nfc_rpc/nfc_rpc_mf_ultralight.c | 10 +- applications/main/nfc_rpc/nfc_rpc_nfca.c | 65 +++-- firmware/targets/f7/api_symbols.csv | 48 ++-- firmware/targets/f7/furi_hal/f_hal_nfc.c | 4 +- firmware/targets/furi_hal_include/f_hal_nfc.h | 4 +- lib/nfc/deprecated/helpers/nfc_generators.c | 66 ++--- lib/nfc/deprecated/helpers/nfc_generators.h | 6 +- lib/nfc/deprecated/helpers/reader_analyzer.c | 6 +- lib/nfc/deprecated/helpers/reader_analyzer.h | 4 +- .../{nfc_device.c => nfc_device_old.c} | 264 +++++++++--------- .../{nfc_device.h => nfc_device_old.h} | 67 ++--- lib/nfc/deprecated/nfc_types.c | 10 +- lib/nfc/deprecated/nfc_types.h | 4 +- lib/nfc/deprecated/nfc_worker.c | 58 ++-- lib/nfc/deprecated/nfc_worker.h | 4 +- lib/nfc/deprecated/nfc_worker_i.h | 2 +- lib/nfc/deprecated/parsers/all_in_one.c | 4 +- lib/nfc/deprecated/parsers/all_in_one.h | 2 +- .../deprecated/parsers/nfc_supported_card.c | 16 +- .../deprecated/parsers/nfc_supported_card.h | 8 +- lib/nfc/deprecated/parsers/opal.c | 4 +- lib/nfc/deprecated/parsers/opal.h | 2 +- .../deprecated/parsers/plantain_4k_parser.c | 2 +- .../deprecated/parsers/plantain_4k_parser.h | 2 +- lib/nfc/deprecated/parsers/plantain_parser.c | 2 +- lib/nfc/deprecated/parsers/plantain_parser.h | 2 +- lib/nfc/deprecated/parsers/troika_4k_parser.c | 2 +- lib/nfc/deprecated/parsers/troika_4k_parser.h | 2 +- lib/nfc/deprecated/parsers/troika_parser.c | 2 +- lib/nfc/deprecated/parsers/troika_parser.h | 2 +- lib/nfc/deprecated/parsers/two_cities.c | 2 +- lib/nfc/deprecated/parsers/two_cities.h | 2 +- lib/nfc/helpers/nfc_data_generator.c | 60 ++-- lib/nfc/helpers/nfc_data_generator.h | 4 +- lib/nfc/nfc.c | 8 +- lib/nfc/nfc.h | 4 +- lib/nfc/nfc_dev.h | 52 ---- lib/nfc/{nfc_dev.c => nfc_device.c} | 117 ++++---- lib/nfc/nfc_device.h | 54 ++++ lib/nfc/nfc_poller.c | 16 +- lib/nfc/nfc_poller.h | 4 +- lib/nfc/nfc_scanner.c | 20 +- lib/nfc/nfc_scanner.h | 4 +- .../nfca.c => iso14443_3a/iso14443_3a.c} | 92 +++--- lib/nfc/protocols/iso14443_3a/iso14443_3a.h | 104 +++++++ .../iso14443_3a/iso14443_3a_listener.c | 226 +++++++++++++++ .../iso14443_3a/iso14443_3a_listener.h | 68 +++++ .../iso14443_3a/iso14443_3a_poller.c | 124 ++++++++ .../iso14443_3a/iso14443_3a_poller.h | 30 ++ .../iso14443_3a_poller_defs.h} | 0 .../iso14443_3a_poller_i.c} | 226 +++++++-------- .../iso14443_3a/iso14443_3a_poller_i.h | 93 ++++++ .../iso14443_3a/iso14443_3a_poller_sync_api.c | 58 ++++ .../iso14443_3a/iso14443_3a_poller_sync_api.h | 14 + lib/nfc/protocols/iso14443_4a/iso14443_4a.c | 39 ++- lib/nfc/protocols/iso14443_4a/iso14443_4a.h | 9 +- .../iso14443_4a/iso14443_4a_poller.c | 30 +- .../iso14443_4a/iso14443_4a_poller.h | 2 +- .../iso14443_4a/iso14443_4a_poller_i.c | 24 +- .../iso14443_4a/iso14443_4a_poller_i.h | 6 +- lib/nfc/protocols/mf_classic/mf_classic.c | 46 +-- lib/nfc/protocols/mf_classic/mf_classic.h | 10 +- .../protocols/mf_classic/mf_classic_poller.c | 26 +- .../protocols/mf_classic/mf_classic_poller.h | 2 +- .../mf_classic/mf_classic_poller_i.c | 62 ++-- .../mf_classic/mf_classic_poller_i.h | 8 +- .../mf_classic/mf_classic_poller_sync_api.c | 16 +- lib/nfc/protocols/mf_desfire/mf_desfire.c | 24 +- lib/nfc/protocols/mf_desfire/mf_desfire.h | 4 +- .../protocols/mf_desfire/mf_desfire_poller.c | 6 +- .../protocols/mf_ultralight/mf_ultralight.c | 52 ++-- .../protocols/mf_ultralight/mf_ultralight.h | 10 +- .../mf_ultralight/mf_ultralight_listener.c | 62 ++-- .../mf_ultralight/mf_ultralight_listener.h | 8 +- .../mf_ultralight/mf_ultralight_poller.c | 40 +-- .../mf_ultralight/mf_ultralight_poller.h | 2 +- .../mf_ultralight/mf_ultralight_poller_i.c | 84 +++--- .../mf_ultralight/mf_ultralight_poller_i.h | 8 +- .../mf_ultralight_poller_sync_api.c | 20 +- lib/nfc/protocols/nfc_device_base.h | 43 +++ lib/nfc/protocols/nfc_device_defs.c | 16 ++ lib/nfc/protocols/nfc_device_defs.h | 26 ++ lib/nfc/protocols/nfc_poller_base.h | 2 +- lib/nfc/protocols/nfc_poller_common.h | 4 +- lib/nfc/protocols/nfc_poller_defs.c | 46 +-- lib/nfc/protocols/nfc_poller_defs.h | 8 +- lib/nfc/protocols/nfc_protocol_base.h | 44 --- lib/nfc/protocols/nfc_protocol_defs.c | 16 -- lib/nfc/protocols/nfc_protocol_defs.h | 26 -- lib/nfc/protocols/nfca/nfca.h | 104 ------- lib/nfc/protocols/nfca/nfca_listener.c | 220 --------------- lib/nfc/protocols/nfca/nfca_listener.h | 63 ----- lib/nfc/protocols/nfca/nfca_poller.c | 122 -------- lib/nfc/protocols/nfca/nfca_poller.h | 30 -- lib/nfc/protocols/nfca/nfca_poller_i.h | 95 ------- lib/nfc/protocols/nfca/nfca_poller_sync_api.c | 57 ---- lib/nfc/protocols/nfca/nfca_poller_sync_api.h | 14 - lib/nfc/protocols/nfcb/nfcb.h | 2 +- 128 files changed, 2001 insertions(+), 1987 deletions(-) rename lib/nfc/deprecated/{nfc_device.c => nfc_device_old.c} (87%) rename lib/nfc/deprecated/{nfc_device.h => nfc_device_old.h} (56%) delete mode 100644 lib/nfc/nfc_dev.h rename lib/nfc/{nfc_dev.c => nfc_device.c} (52%) create mode 100644 lib/nfc/nfc_device.h rename lib/nfc/protocols/{nfca/nfca.c => iso14443_3a/iso14443_3a.c} (57%) create mode 100644 lib/nfc/protocols/iso14443_3a/iso14443_3a.h create mode 100644 lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c create mode 100644 lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.h create mode 100644 lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.c create mode 100644 lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.h rename lib/nfc/protocols/{nfca/nfca_poller_defs.h => iso14443_3a/iso14443_3a_poller_defs.h} (100%) rename lib/nfc/protocols/{nfca/nfca_poller_i.c => iso14443_3a/iso14443_3a_poller_i.c} (51%) create mode 100644 lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.h create mode 100644 lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_sync_api.c create mode 100644 lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_sync_api.h create mode 100644 lib/nfc/protocols/nfc_device_base.h create mode 100644 lib/nfc/protocols/nfc_device_defs.c create mode 100644 lib/nfc/protocols/nfc_device_defs.h delete mode 100644 lib/nfc/protocols/nfc_protocol_base.h delete mode 100644 lib/nfc/protocols/nfc_protocol_defs.c delete mode 100644 lib/nfc/protocols/nfc_protocol_defs.h delete mode 100644 lib/nfc/protocols/nfca/nfca.h delete mode 100644 lib/nfc/protocols/nfca/nfca_listener.c delete mode 100644 lib/nfc/protocols/nfca/nfca_listener.h delete mode 100644 lib/nfc/protocols/nfca/nfca_poller.c delete mode 100644 lib/nfc/protocols/nfca/nfca_poller.h delete mode 100644 lib/nfc/protocols/nfca/nfca_poller_i.h delete mode 100644 lib/nfc/protocols/nfca/nfca_poller_sync_api.c delete mode 100644 lib/nfc/protocols/nfca/nfca_poller_sync_api.h diff --git a/applications/debug/unit_tests/nfc/nfc_test.c b/applications/debug/unit_tests/nfc/nfc_test.c index 4cea6f6d841c..a027ea958f5d 100644 --- a/applications/debug/unit_tests/nfc/nfc_test.c +++ b/applications/debug/unit_tests/nfc/nfc_test.c @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include @@ -15,7 +15,7 @@ #define TAG "NfcTest" -#define NFC_TEST_NFC_DEV_PATH EXT_PATH("unit_tests/nfc/nfc_dev_test.nfc") +#define NFC_TEST_NFC_DEV_PATH EXT_PATH("unit_tests/nfc/nfc_device_test.nfc") typedef struct { Storage* storage; @@ -37,51 +37,52 @@ static void nfc_test_free() { } static void nfc_test_save_and_load(NfcDevData* data) { - NfcDev* nfc_dev = nfc_dev_alloc(); + NfcDevice* nfc_device = nfc_device_alloc(); - NfcDevData* nfc_dev_data_dut = malloc(sizeof(NfcDevData)); + NfcDevData* nfc_device_data_dut = malloc(sizeof(NfcDevData)); - mu_assert(nfc_dev_save(nfc_dev, data, NFC_TEST_NFC_DEV_PATH), "nfc_dev_save() failed\r\n"); + mu_assert( + nfc_device_save(nfc_device, data, NFC_TEST_NFC_DEV_PATH), "nfc_device_save() failed\r\n"); mu_assert( - nfc_dev_load(nfc_dev, nfc_dev_data_dut, NFC_TEST_NFC_DEV_PATH), - "nfc_dev_load() failed\r\n"); + nfc_device_load(nfc_device, nfc_device_data_dut, NFC_TEST_NFC_DEV_PATH), + "nfc_device_load() failed\r\n"); mu_assert( - memcmp(nfc_dev_data_dut, data, sizeof(NfcDevData)) == 0, - "nfc_dev_data_dut != nfc_dev_data_ref\r\n"); + memcmp(nfc_device_data_dut, data, sizeof(NfcDevData)) == 0, + "nfc_device_data_dut != nfc_device_data_ref\r\n"); mu_assert( storage_simply_remove(nfc_test->storage, NFC_TEST_NFC_DEV_PATH), "storage_simply_remove() failed\r\n"); - free(nfc_dev_data_dut); - nfc_dev_free(nfc_dev); + free(nfc_device_data_dut); + nfc_device_free(nfc_device); } static void nfca_file_test(uint8_t uid_len) { - NfcDevData* nfc_dev_data_ref = malloc(sizeof(NfcDevData)); - mu_assert(nfc_dev_data_ref != NULL, "malloc() failed\r\n"); + NfcDevData* nfc_device_data_ref = malloc(sizeof(NfcDevData)); + mu_assert(nfc_device_data_ref != NULL, "malloc() failed\r\n"); - NfcaData* data = &nfc_dev_data_ref->nfca_data; + NfcaData* data = &nfc_device_data_ref->nfca_data; data->uid_len = uid_len; furi_hal_random_fill_buf(data->uid, uid_len); furi_hal_random_fill_buf(data->atqa, 2); furi_hal_random_fill_buf(&data->sak, 1); - nfc_test_save_and_load(nfc_dev_data_ref); + nfc_test_save_and_load(nfc_device_data_ref); - free(nfc_dev_data_ref); + free(nfc_device_data_ref); } static void nfc_file_test_with_generator(NfcDataGeneratorType type) { - NfcDevData* nfc_dev_data_ref = malloc(sizeof(NfcDevData)); + NfcDevData* nfc_device_data_ref = malloc(sizeof(NfcDevData)); - nfc_data_generator_fill_data(type, nfc_dev_data_ref); - nfc_test_save_and_load(nfc_dev_data_ref); + nfc_data_generator_fill_data(type, nfc_device_data_ref); + nfc_test_save_and_load(nfc_device_data_ref); - free(nfc_dev_data_ref); + free(nfc_device_data_ref); } MU_TEST(nfca_4b_file_test) { @@ -203,7 +204,7 @@ MU_TEST(nfca_reader) { static void mf_ultralight_reader_test(const char* path) { FURI_LOG_I(TAG, "Testing file: %s", path); - NfcDev* nfc_dev = nfc_dev_alloc(); + NfcDevice* nfc_device = nfc_device_alloc(); Nfc* poller = nfc_alloc(); Nfc* listener = nfc_alloc(); @@ -216,7 +217,7 @@ static void mf_ultralight_reader_test(const char* path) { MfUltralightError error = MfUltralightErrorNone; NfcDevData* dev_data = malloc(sizeof(NfcDevData)); - mu_assert(nfc_dev_load(nfc_dev, dev_data, path), "nfc_dev_load() failed\r\n"); + mu_assert(nfc_device_load(nfc_device, dev_data, path), "nfc_device_load() failed\r\n"); error = mf_ultralight_listener_start(mfu_listener, &dev_data->mf_ul_data, NULL, NULL); mu_assert(error == MfUltralightErrorNone, "mf_ultralight_listener_start() failed"); @@ -240,7 +241,7 @@ static void mf_ultralight_reader_test(const char* path) { nfc_free(listener); nfca_poller_free(nfca_poller); nfc_free(poller); - nfc_dev_free(nfc_dev); + nfc_device_free(nfc_device); } MU_TEST(mf_ultralight_11_reader) { @@ -261,7 +262,7 @@ MU_TEST(ntag_216_reader) { MU_TEST(ntag_213_locked_reader) { FURI_LOG_I(TAG, "Testing Ntag215 locked file"); - NfcDev* nfc_dev = nfc_dev_alloc(); + NfcDevice* nfc_device = nfc_device_alloc(); Nfc* poller = nfc_alloc(); Nfc* listener = nfc_alloc(); @@ -275,8 +276,8 @@ MU_TEST(ntag_213_locked_reader) { NfcDevData* dev_data = malloc(sizeof(NfcDevData)); mu_assert( - nfc_dev_load(nfc_dev, dev_data, EXT_PATH("unit_tests/nfc/Ntag213_locked.nfc")), - "nfc_dev_load() failed\r\n"); + nfc_device_load(nfc_device, dev_data, EXT_PATH("unit_tests/nfc/Ntag213_locked.nfc")), + "nfc_device_load() failed\r\n"); error = mf_ultralight_listener_start(mfu_listener, &dev_data->mf_ul_data, NULL, NULL); mu_assert(error == MfUltralightErrorNone, "mf_ultralight_listener_start() failed"); @@ -304,11 +305,11 @@ MU_TEST(ntag_213_locked_reader) { nfc_free(listener); nfca_poller_free(nfca_poller); nfc_free(poller); - nfc_dev_free(nfc_dev); + nfc_device_free(nfc_device); } static void mf_ultralight_write() { - NfcDev* nfc_dev = nfc_dev_alloc(); + NfcDevice* nfc_device = nfc_device_alloc(); Nfc* poller = nfc_alloc(); Nfc* listener = nfc_alloc(); @@ -366,7 +367,7 @@ static void mf_ultralight_write() { nfc_free(listener); nfca_poller_free(nfca_poller); nfc_free(poller); - nfc_dev_free(nfc_dev); + nfc_device_free(nfc_device); } MU_TEST_SUITE(nfc) { diff --git a/applications/external/nfc_magic/scenes/nfc_magic_scene_file_select.c b/applications/external/nfc_magic/scenes/nfc_magic_scene_file_select.c index baa6bcccc2d2..a7d1703d1378 100644 --- a/applications/external/nfc_magic/scenes/nfc_magic_scene_file_select.c +++ b/applications/external/nfc_magic/scenes/nfc_magic_scene_file_select.c @@ -1,14 +1,14 @@ #include "../nfc_magic_i.h" static bool nfc_magic_scene_file_select_is_file_suitable(NfcMagic* nfc_magic) { - NfcDevice* nfc_dev = nfc_magic->source_dev; - if(nfc_dev->format == NfcDeviceSaveFormatMifareClassic) { + NfcDevice* nfc_device = nfc_magic->source_dev; + if(nfc_device->format == NfcDeviceSaveFormatMifareClassic) { switch(nfc_magic->dev->type) { case MagicTypeClassicGen1: case MagicTypeClassicDirectWrite: case MagicTypeClassicAPDU: - if((nfc_dev->dev_data.mf_classic_data.type != MfClassicType1k) || - (nfc_dev->dev_data.nfc_data.uid_len != 4)) { + if((nfc_device->dev_data.mf_classic_data.type != MfClassicType1k) || + (nfc_device->dev_data.nfc_data.uid_len != 4)) { return false; } return true; @@ -19,15 +19,15 @@ static bool nfc_magic_scene_file_select_is_file_suitable(NfcMagic* nfc_magic) { return false; } } else if( - (nfc_dev->format == NfcDeviceSaveFormatMifareUl) && - (nfc_dev->dev_data.nfc_data.uid_len == 7)) { + (nfc_device->format == NfcDeviceSaveFormatMifareUl) && + (nfc_device->dev_data.nfc_data.uid_len == 7)) { switch(nfc_magic->dev->type) { case MagicTypeUltralightGen1: case MagicTypeUltralightDirectWrite: case MagicTypeUltralightC_Gen1: case MagicTypeUltralightC_DirectWrite: case MagicTypeGen4: - switch(nfc_dev->dev_data.mf_ul_data.type) { + switch(nfc_device->dev_data.mf_ul_data.type) { case MfUltralightTypeNTAGI2C1K: case MfUltralightTypeNTAGI2C2K: case MfUltralightTypeNTAGI2CPlus1K: diff --git a/applications/main/nfc/helpers/format/nfc_protocol_format.c b/applications/main/nfc/helpers/format/nfc_protocol_format.c index bf5e16ad0768..95cb76131179 100644 --- a/applications/main/nfc/helpers/format/nfc_protocol_format.c +++ b/applications/main/nfc/helpers/format/nfc_protocol_format.c @@ -1,12 +1,12 @@ #include "nfc_protocol_format.h" -#include +#include #include #include #include typedef void (*NfcProtocolFormatRenderInfo)( - const NfcDev* device, + const NfcDevice* device, NfcProtocolFormatType type, FuriString* str); @@ -16,7 +16,7 @@ typedef struct { } NfcProtocolFormatBase; static void nfc_protocol_format_info_iso14443_3a_common( - const NfcaData* nfc_data, + const Iso14443_3aData* nfc_data, NfcProtocolFormatType type, FuriString* str) { if(type == NfcProtocolFormatTypeFull) { @@ -37,30 +37,30 @@ static void nfc_protocol_format_info_iso14443_3a_common( } static void nfc_protocol_format_info_iso14443_3a( - const NfcDev* device, + const NfcDevice* device, NfcProtocolFormatType type, FuriString* str) { UNUSED(type); - const NfcaData* data = nfc_dev_get_protocol_data(device, NfcProtocolTypeIso14443_3a); + const Iso14443_3aData* data = nfc_device_get_data(device, NfcProtocolIso14443_3a); nfc_protocol_format_info_iso14443_3a_common(data, NfcProtocolFormatTypeFull, str); } static void nfc_protocol_format_info_iso14443_4a( - const NfcDev* device, + const NfcDevice* device, NfcProtocolFormatType type, FuriString* str) { UNUSED(type); - const Iso14443_4aData* data = nfc_dev_get_protocol_data(device, NfcProtocolTypeIso14443_4a); + const Iso14443_4aData* data = nfc_device_get_data(device, NfcProtocolIso14443_4a); nfc_protocol_format_info_iso14443_3a_common( data->iso14443_3a_data, NfcProtocolFormatTypeFull, str); } static void nfc_protocol_format_info_mf_ultralight( - const NfcDev* device, + const NfcDevice* device, NfcProtocolFormatType type, FuriString* str) { - const MfUltralightData* data = nfc_dev_get_protocol_data(device, NfcProtocolTypeMfUltralight); - nfc_protocol_format_info_iso14443_3a_common(data->nfca_data, type, str); + const MfUltralightData* data = nfc_device_get_data(device, NfcProtocolMfUltralight); + nfc_protocol_format_info_iso14443_3a_common(data->iso14443_3a_data, type, str); furi_string_cat_printf(str, "\nPages Read: %u/%u", data->pages_read, data->pages_total); if(data->pages_read != data->pages_total) { @@ -69,11 +69,11 @@ static void nfc_protocol_format_info_mf_ultralight( } static void nfc_protocol_format_info_mf_classic( - const NfcDev* device, + const NfcDevice* device, NfcProtocolFormatType type, FuriString* str) { - const MfClassicData* data = nfc_dev_get_protocol_data(device, NfcProtocolTypeMfClassic); - nfc_protocol_format_info_iso14443_3a_common(data->nfca_data, type, str); + const MfClassicData* data = nfc_device_get_data(device, NfcProtocolMfClassic); + nfc_protocol_format_info_iso14443_3a_common(data->iso14443_3a_data, type, str); uint8_t sectors_total = mf_classic_get_total_sectors_num(data->type); uint8_t keys_total = sectors_total * 2; @@ -87,10 +87,10 @@ static void nfc_protocol_format_info_mf_classic( // TODO: use proper type getters static void nfc_protocol_format_info_mf_desfire( - const NfcDev* device, + const NfcDevice* device, NfcProtocolFormatType type, FuriString* str) { - const MfDesfireData* data = nfc_dev_get_protocol_data(device, NfcProtocolTypeMfDesfire); + const MfDesfireData* data = nfc_device_get_data(device, NfcProtocolMfDesfire); nfc_protocol_format_info_iso14443_3a_common( data->iso14443_4a_data->iso14443_3a_data, type, str); @@ -117,40 +117,39 @@ static void nfc_protocol_format_info_mf_desfire( furi_string_cat_printf(str, ", %lu File%s", file_count, file_count != 1 ? "s" : ""); } -static const NfcProtocolFormatBase nfc_protocol_format[NfcProtocolTypeMax] = { - [NfcProtocolTypeIso14443_3a] = +static const NfcProtocolFormatBase nfc_protocol_format[NfcProtocolNum] = { + [NfcProtocolIso14443_3a] = { .flags = NfcProtocolFormatFeatureNone, .render_info = nfc_protocol_format_info_iso14443_3a, }, - [NfcProtocolTypeIso14443_4a] = + [NfcProtocolIso14443_4a] = { .flags = NfcProtocolFormatFeatureNone, .render_info = nfc_protocol_format_info_iso14443_4a, }, - [NfcProtocolTypeMfUltralight] = + [NfcProtocolMfUltralight] = { .flags = NfcProtocolFormatFeatureMoreData, .render_info = nfc_protocol_format_info_mf_ultralight, }, - [NfcProtocolTypeMfClassic] = + [NfcProtocolMfClassic] = { .flags = NfcProtocolFormatFeatureMoreData, .render_info = nfc_protocol_format_info_mf_classic, }, - [NfcProtocolTypeMfDesfire] = + [NfcProtocolMfDesfire] = { .flags = NfcProtocolFormatFeatureMoreData, .render_info = nfc_protocol_format_info_mf_desfire, }, }; -NfcProtocolFormatFeature nfc_protocol_format_get_features(const NfcDev* device) { - return nfc_protocol_format[nfc_dev_get_protocol_type(device)].flags; +NfcProtocolFormatFeature nfc_protocol_format_get_features(const NfcDevice* device) { + return nfc_protocol_format[nfc_device_get_protocol(device)].flags; } -void nfc_protocol_format_info(const NfcDev* device, NfcProtocolFormatType type, FuriString* str) { - furi_string_cat_printf( - str, "\e#%s\n", nfc_dev_get_device_name(device, NfcProtocolNameTypeFull)); - nfc_protocol_format[nfc_dev_get_protocol_type(device)].render_info(device, type, str); +void nfc_protocol_format_info(const NfcDevice* device, NfcProtocolFormatType type, FuriString* str) { + furi_string_cat_printf(str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull)); + nfc_protocol_format[nfc_device_get_protocol(device)].render_info(device, type, str); } diff --git a/applications/main/nfc/helpers/format/nfc_protocol_format.h b/applications/main/nfc/helpers/format/nfc_protocol_format.h index 284e18e98c2f..f1c2bf3244a4 100644 --- a/applications/main/nfc/helpers/format/nfc_protocol_format.h +++ b/applications/main/nfc/helpers/format/nfc_protocol_format.h @@ -1,6 +1,6 @@ #pragma once -#include +#include typedef enum { NfcProtocolFormatFeatureNone = 0, @@ -12,6 +12,6 @@ typedef enum { NfcProtocolFormatTypeFull, } NfcProtocolFormatType; -NfcProtocolFormatFeature nfc_protocol_format_get_features(const NfcDev* device); +NfcProtocolFormatFeature nfc_protocol_format_get_features(const NfcDevice* device); -void nfc_protocol_format_info(const NfcDev* device, NfcProtocolFormatType type, FuriString* str); +void nfc_protocol_format_info(const NfcDevice* device, NfcProtocolFormatType type, FuriString* str); diff --git a/applications/main/nfc/helpers/handlers/nfc_poller_handler.c b/applications/main/nfc/helpers/handlers/nfc_poller_handler.c index e6ecddb0774d..a1d61c2f4a62 100644 --- a/applications/main/nfc/helpers/handlers/nfc_poller_handler.c +++ b/applications/main/nfc/helpers/handlers/nfc_poller_handler.c @@ -2,14 +2,14 @@ #include "../../nfc_app_i.h" -typedef NfcCustomEvent (*NfcPollerReadHandler)(NfcaPollerEvent* event, NfcApp* nfc_app); +typedef NfcCustomEvent (*NfcPollerReadHandler)(Iso14443_3aPollerEvent* event, NfcApp* nfc_app); static NfcCustomEvent - nfc_poller_handler_read_iso14443_3a(NfcaPollerEvent* event, NfcApp* nfc_app) { + nfc_poller_handler_read_iso14443_3a(Iso14443_3aPollerEvent* event, NfcApp* nfc_app) { UNUSED(nfc_app); NfcCustomEvent custom_event = NfcCustomEventReadHandlerIgnore; - if(event->type == NfcaPollerEventTypeReady) { + if(event->type == Iso14443_3aPollerEventTypeReady) { custom_event = NfcCustomEventReadHandlerSuccess; } @@ -35,18 +35,22 @@ static NfcCustomEvent if(event->type == MfUltralightPollerEventTypeReadSuccess) { custom_event = NfcCustomEventReadHandlerSuccess; } else if(event->type == MfUltralightPollerEventTypeAuthRequest) { - nfc_dev_set_protocol_data( - nfc_app->nfc_dev, NfcProtocolTypeMfUltralight, nfc_poller_get_data(nfc_app->poller)); + nfc_device_set_data( + nfc_app->nfc_device, NfcProtocolMfUltralight, nfc_poller_get_data(nfc_app->poller)); const MfUltralightData* data = - nfc_dev_get_protocol_data(nfc_app->nfc_dev, NfcProtocolTypeMfUltralight); + nfc_device_get_data(nfc_app->nfc_device, NfcProtocolMfUltralight); if(nfc_app->mf_ul_auth->type == MfUltralightAuthTypeXiaomii) { if(mf_ultralight_generate_xiaomi_pass( - nfc_app->mf_ul_auth, data->nfca_data->uid, data->nfca_data->uid_len)) { + nfc_app->mf_ul_auth, + data->iso14443_3a_data->uid, + data->iso14443_3a_data->uid_len)) { event->data->auth_context.skip_auth = false; } } else if(nfc_app->mf_ul_auth->type == MfUltralightAuthTypeAmiibo) { if(mf_ultralight_generate_amiibo_pass( - nfc_app->mf_ul_auth, data->nfca_data->uid, data->nfca_data->uid_len)) { + nfc_app->mf_ul_auth, + data->iso14443_3a_data->uid, + data->iso14443_3a_data->uid_len)) { event->data->auth_context.skip_auth = false; } } else if(nfc_app->mf_ul_auth->type == MfUltralightAuthTypeManual) { @@ -87,26 +91,24 @@ static NfcCustomEvent } static const NfcPollerReadHandler nfc_poller_handlers_read[] = { - [NfcProtocolTypeIso14443_3a] = (NfcPollerReadHandler)nfc_poller_handler_read_iso14443_3a, - [NfcProtocolTypeIso14443_4a] = (NfcPollerReadHandler)nfc_poller_handler_read_iso14443_4a, - [NfcProtocolTypeMfUltralight] = (NfcPollerReadHandler)nfc_poller_handler_read_mf_ultralight, - [NfcProtocolTypeMfClassic] = (NfcPollerReadHandler)nfc_poller_handler_read_mf_classic, - [NfcProtocolTypeMfDesfire] = (NfcPollerReadHandler)nfc_poller_handler_read_mf_desfire, + [NfcProtocolIso14443_3a] = (NfcPollerReadHandler)nfc_poller_handler_read_iso14443_3a, + [NfcProtocolIso14443_4a] = (NfcPollerReadHandler)nfc_poller_handler_read_iso14443_4a, + [NfcProtocolMfUltralight] = (NfcPollerReadHandler)nfc_poller_handler_read_mf_ultralight, + [NfcProtocolMfClassic] = (NfcPollerReadHandler)nfc_poller_handler_read_mf_classic, + [NfcProtocolMfDesfire] = (NfcPollerReadHandler)nfc_poller_handler_read_mf_desfire, }; - NfcCustomEvent nfc_poller_handler_read(NfcPollerEvent event, void* context) { furi_assert(context); furi_assert(event.poller); furi_assert(event.data); - furi_assert(event.protocol_type < COUNT_OF(nfc_poller_handlers_read)); + furi_assert(event.protocol < COUNT_OF(nfc_poller_handlers_read)); NfcApp* nfc_app = context; - NfcCustomEvent custom_event = - nfc_poller_handlers_read[event.protocol_type](event.data, context); + NfcCustomEvent custom_event = nfc_poller_handlers_read[event.protocol](event.data, context); if(custom_event == NfcCustomEventReadHandlerSuccess) { - nfc_dev_set_protocol_data( - nfc_app->nfc_dev, event.protocol_type, nfc_poller_get_data(nfc_app->poller)); + nfc_device_set_data( + nfc_app->nfc_device, event.protocol, nfc_poller_get_data(nfc_app->poller)); } return custom_event; diff --git a/applications/main/nfc/helpers/nfc_supported_cards.h b/applications/main/nfc/helpers/nfc_supported_cards.h index da2f79e93572..08721a2e7871 100644 --- a/applications/main/nfc/helpers/nfc_supported_cards.h +++ b/applications/main/nfc/helpers/nfc_supported_cards.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #ifdef __cplusplus extern "C" { @@ -16,13 +16,13 @@ void nfc_supported_cards_free(NfcSupportedCards* instance); //FIXME: Make it compile // bool nfc_supported_cards_read( // NfcSupportedCards* instance, -// NfcProtocolType protocol, +// NfcProtocol protocol, // void* poller, // void* data); // // bool nfc_supported_cards_parse( // NfcSupportedCards* instance, -// NfcProtocolType protocol, +// NfcProtocol protocol, // void* data, // FuriString* parsed_data); diff --git a/applications/main/nfc/nfc_app.c b/applications/main/nfc/nfc_app.c index 791ab71d5674..a0b22be1902b 100644 --- a/applications/main/nfc/nfc_app.c +++ b/applications/main/nfc/nfc_app.c @@ -46,8 +46,8 @@ NfcApp* nfc_app_alloc() { instance->view_dispatcher, nfc_back_event_callback); instance->nfc = nfc_alloc(); - instance->nfca_listener = nfca_listener_alloc(instance->nfc); - instance->mf_ul_listener = mf_ultralight_listener_alloc(instance->nfca_listener); + instance->iso14443_3a_listener = iso14443_3a_listener_alloc(instance->nfc); + instance->mf_ul_listener = mf_ultralight_listener_alloc(instance->iso14443_3a_listener); instance->parsed_data = furi_string_alloc(); @@ -56,8 +56,8 @@ NfcApp* nfc_app_alloc() { instance->mf_ul_auth = mf_ultralight_auth_alloc(); // Nfc device - instance->nfc_dev = nfc_dev_alloc(); - nfc_dev_set_loading_callback(instance->nfc_dev, nfc_show_loading_popup, instance); + instance->nfc_device = nfc_device_alloc(); + nfc_device_set_loading_callback(instance->nfc_device, nfc_show_loading_popup, instance); // Open GUI record instance->gui = furi_record_open(RECORD_GUI); @@ -124,7 +124,7 @@ NfcApp* nfc_app_alloc() { NfcViewDetectReader, detect_reader_get_view(instance->detect_reader)); - instance->nfca_edit_data = nfca_alloc(); + instance->iso14443_3a_edit_data = iso14443_3a_alloc(); instance->file_path = furi_string_alloc_set(NFC_APP_FOLDER); instance->file_name = furi_string_alloc(); @@ -154,14 +154,14 @@ void nfc_app_free(NfcApp* instance) { furi_string_free(instance->parsed_data); mf_ultralight_listener_free(instance->mf_ul_listener); - nfca_listener_free(instance->nfca_listener); + iso14443_3a_listener_free(instance->iso14443_3a_listener); nfc_free(instance->nfc); nfc_scanner_free(instance->scanner); mf_ultralight_auth_free(instance->mf_ul_auth); // Nfc device - nfc_dev_free(instance->nfc_dev); + nfc_device_free(instance->nfc_device); // Submenu view_dispatcher_remove_view(instance->view_dispatcher, NfcViewMenu); @@ -219,7 +219,7 @@ void nfc_app_free(NfcApp* instance) { instance->notifications = NULL; - nfca_free(instance->nfca_edit_data); + iso14443_3a_free(instance->iso14443_3a_edit_data); furi_string_free(instance->file_path); furi_string_free(instance->file_name); @@ -267,7 +267,7 @@ bool nfc_save_file(NfcApp* instance, FuriString* path) { furi_assert(instance); furi_assert(path); - bool result = nfc_dev_save(instance->nfc_dev, furi_string_get_cstr(instance->file_path)); + bool result = nfc_device_save(instance->nfc_device, furi_string_get_cstr(instance->file_path)); if(!result) { dialog_message_show_storage_error(instance->dialogs, "Cannot save\nkey file"); @@ -360,7 +360,7 @@ bool nfc_load_file(NfcApp* instance, FuriString* path, bool show_dialog) { furi_string_set(load_path, path); } - result = nfc_dev_load(instance->nfc_dev, furi_string_get_cstr(load_path)); + result = nfc_device_load(instance->nfc_device, furi_string_get_cstr(load_path)); if(result) { path_extract_filename(load_path, instance->file_name, true); @@ -426,10 +426,10 @@ void nfc_show_loading_popup(void* context, bool show) { } } -void nfc_app_set_detected_protocols(NfcApp* instance, const NfcProtocolType* types, uint32_t count) { +void nfc_app_set_detected_protocols(NfcApp* instance, const NfcProtocol* types, uint32_t count) { furi_assert(instance); furi_assert(types); - furi_assert(count < NfcProtocolTypeMax); + furi_assert(count < NfcProtocolNum); memcpy(instance->protocols_detected, types, count); instance->protocols_detected_num = count; diff --git a/applications/main/nfc/nfc_app_i.h b/applications/main/nfc/nfc_app_i.h index 0ebb90aa0e66..74dd980aa930 100644 --- a/applications/main/nfc/nfc_app_i.h +++ b/applications/main/nfc/nfc_app_i.h @@ -39,8 +39,8 @@ #include #include -#include -#include +#include +#include #include #include #include @@ -49,7 +49,7 @@ #include #include -#include +#include #include #include @@ -90,7 +90,7 @@ struct NfcApp { size_t protocols_detected_num; size_t protocols_detected_idx; - NfcProtocolType protocols_detected[NfcProtocolTypeMax]; + NfcProtocol protocols_detected[NfcProtocolNum]; void* rpc_ctx; NfcRpcState rpc_state; @@ -108,7 +108,7 @@ struct NfcApp { DetectReader* detect_reader; Nfc* nfc; - NfcaListener* nfca_listener; + Iso14443_3aListener* iso14443_3a_listener; MfUltralightListener* mf_ul_listener; NfcPoller* poller; @@ -119,8 +119,8 @@ struct NfcApp { FuriString* parsed_data; NfcSupportedCards* supported_cards; - NfcDev* nfc_dev; - NfcaData* nfca_edit_data; + NfcDevice* nfc_device; + Iso14443_3aData* iso14443_3a_edit_data; FuriString* file_path; FuriString* file_name; }; @@ -170,6 +170,6 @@ bool nfc_save_file(NfcApp* instance, FuriString* path); void nfc_make_app_folder(NfcApp* instance); -void nfc_app_set_detected_protocols(NfcApp* instance, const NfcProtocolType* types, uint32_t count); +void nfc_app_set_detected_protocols(NfcApp* instance, const NfcProtocol* types, uint32_t count); void nfc_app_reset_detected_protocols(NfcApp* instance); diff --git a/applications/main/nfc/nfc_cli.c b/applications/main/nfc/nfc_cli.c index 3fbc7cd6848b..7aa010ba662f 100644 --- a/applications/main/nfc/nfc_cli.c +++ b/applications/main/nfc/nfc_cli.c @@ -5,7 +5,7 @@ #include #include -#include +#include static void nfc_cli_print_usage() { printf("Usage:\r\n"); diff --git a/applications/main/nfc/plugins/nfc_supported_card_plugin.h b/applications/main/nfc/plugins/nfc_supported_card_plugin.h index ebd2cf77b110..1f84d5759a75 100644 --- a/applications/main/nfc/plugins/nfc_supported_card_plugin.h +++ b/applications/main/nfc/plugins/nfc_supported_card_plugin.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #define NFC_SUPPORTED_CARD_PLUGIN_APP_ID "NfcSupportedCardPlugin" #define NFC_SUPPORTED_CARD_PLUGIN_API_VERSION 1 @@ -13,7 +13,7 @@ typedef bool (*NfcSupportedCardPluginRead)(void* poller, void* data); typedef bool (*NfcSupportedCardPluginParse)(void* data, FuriString* parsed_data); typedef struct { - NfcProtocolType protocol; + NfcProtocol protocol; NfcSupportedCardPluginVerify verify; NfcSupportedCardPluginRead read; NfcSupportedCardPluginParse parse; diff --git a/applications/main/nfc/plugins/troika.c b/applications/main/nfc/plugins/troika.c index dd9174cde62a..88a8f60a45c6 100644 --- a/applications/main/nfc/plugins/troika.c +++ b/applications/main/nfc/plugins/troika.c @@ -64,7 +64,7 @@ bool troika_parse(void* data, FuriString* parsed_data) { /* Actual implementation of app<>plugin interface */ static const NfcSupportedCardsPlugin troika_plugin = { - .protocol = NfcProtocolTypeMfClassic, + .protocol = NfcProtocolMfClassic, .verify = troika_verify, .read = troika_read, .parse = troika_parse, diff --git a/applications/main/nfc/scenes/nfc_scene_delete.c b/applications/main/nfc/scenes/nfc_scene_delete.c index 518402c355d0..d36b5fb54bf2 100644 --- a/applications/main/nfc/scenes/nfc_scene_delete.c +++ b/applications/main/nfc/scenes/nfc_scene_delete.c @@ -23,7 +23,7 @@ void nfc_scene_delete_on_enter(void* context) { nfc->widget, GuiButtonTypeRight, "Delete", nfc_scene_delete_widget_callback, nfc); size_t uid_len; - const uint8_t* uid = nfc_dev_get_uid(nfc->nfc_dev, &uid_len); + const uint8_t* uid = nfc_device_get_uid(nfc->nfc_device, &uid_len); furi_string_set(temp_str, "UID:"); for(size_t i = 0; i < uid_len; i++) { @@ -32,7 +32,7 @@ void nfc_scene_delete_on_enter(void* context) { widget_add_string_element( nfc->widget, 64, 24, AlignCenter, AlignTop, FontSecondary, furi_string_get_cstr(temp_str)); - furi_string_set_str(temp_str, nfc_dev_get_device_name(nfc->nfc_dev, NfcProtocolNameTypeFull)); + furi_string_set_str(temp_str, nfc_device_get_name(nfc->nfc_device, NfcDeviceNameTypeFull)); widget_add_string_element( nfc->widget, 64, 34, AlignCenter, AlignTop, FontSecondary, furi_string_get_cstr(temp_str)); widget_add_string_element(nfc->widget, 64, 44, AlignCenter, AlignTop, FontSecondary, "NFC-A"); diff --git a/applications/main/nfc/scenes/nfc_scene_generate_info.c b/applications/main/nfc/scenes/nfc_scene_generate_info.c index 396abc4602d8..f8bb835a5b6d 100644 --- a/applications/main/nfc/scenes/nfc_scene_generate_info.c +++ b/applications/main/nfc/scenes/nfc_scene_generate_info.c @@ -13,11 +13,11 @@ void nfc_scene_generate_info_widget_callback(GuiButtonType result, InputType typ void nfc_scene_generate_info_on_enter(void* context) { NfcApp* nfc = context; - NfcaData* nfca_data = NULL; - if(nfc_dev_get_protocol_type(nfc->nfc_dev) == NfcProtocolTypeMfUltralight) { + Iso14443_3aData* iso14443_3a_data = NULL; + if(nfc_device_get_protocol(nfc->nfc_device) == NfcProtocolMfUltralight) { const MfUltralightData* mfu_data = - nfc_dev_get_protocol_data(nfc->nfc_dev, NfcProtocolTypeMfUltralight); - nfca_data = mfu_data->nfca_data; + nfc_device_get_data(nfc->nfc_device, NfcProtocolMfUltralight); + iso14443_3a_data = mfu_data->iso14443_3a_data; } else { // TODO add Mf Classic furi_crash("Not supported protocol"); @@ -37,8 +37,8 @@ void nfc_scene_generate_info_on_enter(void* context) { FuriString* temp_str = furi_string_alloc_printf("UID:"); // Append UID - for(int i = 0; i < nfca_data->uid_len; i++) { - furi_string_cat_printf(temp_str, " %02X", nfca_data->uid[i]); + for(int i = 0; i < iso14443_3a_data->uid_len; i++) { + furi_string_cat_printf(temp_str, " %02X", iso14443_3a_data->uid[i]); } widget_add_string_element( widget, 0, 25, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(temp_str)); @@ -54,7 +54,7 @@ bool nfc_scene_generate_info_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == GuiButtonTypeRight) { // Switch either to NfcSceneMfClassicMenu or NfcSceneMfUltralightMenu - if(nfc_dev_get_protocol_type(nfc->nfc_dev) == NfcProtocolTypeMfUltralight) { + if(nfc_device_get_protocol(nfc->nfc_device) == NfcProtocolMfUltralight) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightMenu); } else { // TODO add classic diff --git a/applications/main/nfc/scenes/nfc_scene_info.c b/applications/main/nfc/scenes/nfc_scene_info.c index d460093e907f..0f4a5482cd04 100644 --- a/applications/main/nfc/scenes/nfc_scene_info.c +++ b/applications/main/nfc/scenes/nfc_scene_info.c @@ -15,7 +15,7 @@ void nfc_scene_info_on_enter(void* context) { Widget* widget = nfc->widget; uint8_t text_scroll_height = 0; - if(nfc_protocol_format_get_features(nfc->nfc_dev) & NfcProtocolFormatFeatureMoreData) { + if(nfc_protocol_format_get_features(nfc->nfc_device) & NfcProtocolFormatFeatureMoreData) { widget_add_button_element( widget, GuiButtonTypeRight, "More", nfc_scene_nfc_info_widget_callback, nfc); text_scroll_height = 52; @@ -26,7 +26,7 @@ void nfc_scene_info_on_enter(void* context) { FuriString* temp_str; temp_str = furi_string_alloc(); - nfc_protocol_format_info(nfc->nfc_dev, NfcProtocolFormatTypeFull, temp_str); + nfc_protocol_format_info(nfc->nfc_device, NfcProtocolFormatTypeFull, temp_str); widget_add_text_scroll_element( widget, 0, 0, 128, text_scroll_height, furi_string_get_cstr(temp_str)); @@ -35,12 +35,12 @@ void nfc_scene_info_on_enter(void* context) { view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); } -static const NfcScene nfc_scene_info_data_scenes[NfcProtocolTypeMax] = { - [NfcProtocolTypeIso14443_3a] = NfcSceneNotImplemented, - [NfcProtocolTypeIso14443_4a] = NfcSceneNotImplemented, - [NfcProtocolTypeMfUltralight] = NfcSceneNotImplemented, - [NfcProtocolTypeMfClassic] = NfcSceneNotImplemented, - [NfcProtocolTypeMfDesfire] = NfcSceneMfDesfireData, +static const NfcScene nfc_scene_info_data_scenes[NfcProtocolNum] = { + [NfcProtocolIso14443_3a] = NfcSceneNotImplemented, + [NfcProtocolIso14443_4a] = NfcSceneNotImplemented, + [NfcProtocolMfUltralight] = NfcSceneNotImplemented, + [NfcProtocolMfClassic] = NfcSceneNotImplemented, + [NfcProtocolMfDesfire] = NfcSceneMfDesfireData, }; bool nfc_scene_info_on_event(void* context, SceneManagerEvent event) { @@ -49,8 +49,8 @@ bool nfc_scene_info_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == GuiButtonTypeRight) { - const NfcProtocolType protocol_type = nfc_dev_get_protocol_type(nfc->nfc_dev); - const NfcScene menu_scene = nfc_scene_info_data_scenes[protocol_type]; + const NfcProtocol protocol = nfc_device_get_protocol(nfc->nfc_device); + const NfcScene menu_scene = nfc_scene_info_data_scenes[protocol]; scene_manager_next_scene(nfc->scene_manager, menu_scene); consumed = true; } diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c index 06f423402a8d..8683ef340222 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c @@ -13,7 +13,7 @@ NfcCommand nfc_dict_attack_worker_callback(NfcPollerEvent event, void* context) furi_assert(context); furi_assert(event.data); furi_assert(event.poller); - furi_assert(event.protocol_type == NfcProtocolTypeMfClassic); + furi_assert(event.protocol == NfcProtocolMfClassic); NfcCommand command = NfcCommandContinue; MfClassicPollerEvent* mfc_event = event.data; @@ -81,7 +81,7 @@ void nfc_dict_attack_dict_attack_result_callback(void* context) { } static void nfc_scene_mf_classic_dict_attack_update_view(NfcApp* nfc) { - const MfClassicData* data = nfc_dev_get_protocol_data(nfc->nfc_dev, NfcProtocolTypeMfClassic); + const MfClassicData* data = nfc_device_get_data(nfc->nfc_device, NfcProtocolMfClassic); uint8_t sectors_read = 0; uint8_t keys_found = 0; @@ -92,7 +92,7 @@ static void nfc_scene_mf_classic_dict_attack_update_view(NfcApp* nfc) { } static void nfc_scene_mf_classic_dict_attack_prepare_view(NfcApp* nfc, DictAttackState state) { - const MfClassicData* data = nfc_dev_get_protocol_data(nfc->nfc_dev, NfcProtocolTypeMfClassic); + const MfClassicData* data = nfc_device_get_data(nfc->nfc_device, NfcProtocolMfClassic); // Identify scene state if(state == DictAttackStateIdle) { @@ -132,7 +132,7 @@ void nfc_scene_mf_classic_dict_attack_on_enter(void* context) { nfc_blink_read_start(nfc); notification_message(nfc->notifications, &sequence_display_backlight_enforce_on); - nfc->poller = nfc_poller_alloc(nfc->nfc, NfcProtocolTypeMfClassic); + nfc->poller = nfc_poller_alloc(nfc->nfc, NfcProtocolMfClassic); nfc_poller_start(nfc->poller, nfc_dict_attack_worker_callback, nfc); } @@ -166,14 +166,14 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent dict_attack_inc_keys_found(nfc->dict_attack); consumed = true; } else if(event.event == NfcCustomEventDictAttackNewSector) { - nfc_dev_set_protocol_data( - nfc->nfc_dev, NfcProtocolTypeMfClassic, nfc_poller_get_data(nfc->poller)); + nfc_device_set_data( + nfc->nfc_device, NfcProtocolMfClassic, nfc_poller_get_data(nfc->poller)); nfc_scene_mf_classic_dict_attack_update_view(nfc); dict_attack_inc_current_sector(nfc->dict_attack); consumed = true; } else if(event.event == NfcCustomEventDictAttackNewKeyBatch) { - nfc_dev_set_protocol_data( - nfc->nfc_dev, NfcProtocolTypeMfClassic, nfc_poller_get_data(nfc->poller)); + nfc_device_set_data( + nfc->nfc_device, NfcProtocolMfClassic, nfc_poller_get_data(nfc->poller)); nfc_scene_mf_classic_dict_attack_update_view(nfc); dict_attack_inc_current_dict_key(nfc->dict_attack, 10); consumed = true; diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_menu.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_menu.c index 5254ace99f4e..efc5cfeb2462 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_menu.c @@ -23,8 +23,7 @@ void nfc_scene_mf_classic_menu_on_enter(void* context) { submenu_add_item( submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_mf_classic_menu_submenu_callback, nfc); - const MfClassicData* mfc_data = - nfc_dev_get_protocol_data(nfc->nfc_dev, NfcProtocolTypeMfClassic); + const MfClassicData* mfc_data = nfc_device_get_data(nfc->nfc_device, NfcProtocolMfClassic); if(!mf_classic_is_card_read(mfc_data)) { submenu_add_item( submenu, diff --git a/applications/main/nfc/scenes/nfc_scene_mf_desfire_app.c b/applications/main/nfc/scenes/nfc_scene_mf_desfire_app.c index 83088840868e..79cc17db27c2 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_desfire_app.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_desfire_app.c @@ -27,7 +27,7 @@ void nfc_scene_mf_desfire_app_on_enter(void* context) { const uint32_t app_idx = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireApp) >> 1; - const MfDesfireData* data = nfc_dev_get_protocol_data(nfc->nfc_dev, NfcProtocolTypeMfDesfire); + const MfDesfireData* data = nfc_device_get_data(nfc->nfc_device, NfcProtocolMfDesfire); const MfDesfireApplication* app = simple_array_cget(data->applications, app_idx); FuriString* label = furi_string_alloc(); @@ -59,8 +59,7 @@ bool nfc_scene_mf_desfire_app_on_event(void* context, SceneManagerEvent event) { if(event.event == NfcCustomEventViewExit) { consumed = scene_manager_previous_scene(nfc->scene_manager); } else { - const MfDesfireData* data = - nfc_dev_get_protocol_data(nfc->nfc_dev, NfcProtocolTypeMfDesfire); + const MfDesfireData* data = nfc_device_get_data(nfc->nfc_device, NfcProtocolMfDesfire); const uint32_t app_index = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireApp) >> 1; diff --git a/applications/main/nfc/scenes/nfc_scene_mf_desfire_data.c b/applications/main/nfc/scenes/nfc_scene_mf_desfire_data.c index 568e5cc5c1e1..84d6489b5833 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_desfire_data.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_desfire_data.c @@ -24,7 +24,7 @@ void nfc_scene_mf_desfire_data_on_enter(void* context) { const uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireData); - const MfDesfireData* data = nfc_dev_get_protocol_data(nfc->nfc_dev, NfcProtocolTypeMfDesfire); + const MfDesfireData* data = nfc_device_get_data(nfc->nfc_device, NfcProtocolMfDesfire); text_box_set_font(nfc->text_box, TextBoxFontHex); @@ -67,7 +67,7 @@ bool nfc_scene_mf_desfire_data_on_event(void* context, SceneManagerEvent event) const uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireData); - const MfDesfireData* data = nfc_dev_get_protocol_data(nfc->nfc_dev, NfcProtocolTypeMfDesfire); + const MfDesfireData* data = nfc_device_get_data(nfc->nfc_device, NfcProtocolMfDesfire); if(event.type == SceneManagerEventTypeCustom) { TextBox* text_box = nfc->text_box; diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_emulate.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_emulate.c index bd5eb11165e6..6e6042d47d3d 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_emulate.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_emulate.c @@ -4,8 +4,7 @@ void nfc_scene_mf_ultralight_emulate_on_enter(void* context) { NfcApp* nfc = context; // Setup view - const MfUltralightData* data = - nfc_dev_get_protocol_data(nfc->nfc_dev, NfcProtocolTypeMfUltralight); + const MfUltralightData* data = nfc_device_get_data(nfc->nfc_device, NfcProtocolMfUltralight); const MfUltralightType type = data->type; bool is_ultralight = (type == MfUltralightTypeUL11) || (type == MfUltralightTypeUL21) || diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c index 3a5a2d129d73..ae7f1f781a05 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c @@ -18,8 +18,7 @@ void nfc_scene_mf_ultralight_menu_on_enter(void* context) { NfcApp* nfc = context; Submenu* submenu = nfc->submenu; - const MfUltralightData* data = - nfc_dev_get_protocol_data(nfc->nfc_dev, NfcProtocolTypeMfUltralight); + const MfUltralightData* data = nfc_device_get_data(nfc->nfc_device, NfcProtocolMfUltralight); if(!mf_ultralight_is_all_data_read(data)) { submenu_add_item( diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_menu.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_menu.c index 7304c72ead30..912150d619bc 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_menu.c @@ -19,7 +19,7 @@ void nfc_scene_mf_ultralight_unlock_menu_on_enter(void* context) { uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightUnlockMenu); - if(nfc_dev_get_protocol_type(nfc->nfc_dev) == NfcProtocolTypeMfUltralight) { + if(nfc_device_get_protocol(nfc->nfc_device) == NfcProtocolMfUltralight) { submenu_add_item( submenu, "Unlock With Reader", diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c index 197c9bd83579..57f9429e130a 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c @@ -75,7 +75,7 @@ bool nfc_scene_mf_ultralight_unlock_warn_on_event(void* context, SceneManagerEve } else { if(event.type == SceneManagerEventTypeCustom) { if(event.event == DialogExResultCenter) { - const NfcProtocolType mfu_protocol[] = {NfcProtocolTypeMfUltralight}; + const NfcProtocol mfu_protocol[] = {NfcProtocolMfUltralight}; nfc_app_set_detected_protocols(nfc, mfu_protocol, COUNT_OF(mfu_protocol)); scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); dolphin_deed(DolphinDeedNfcRead); diff --git a/applications/main/nfc/scenes/nfc_scene_nfca_emulate.c b/applications/main/nfc/scenes/nfc_scene_nfca_emulate.c index adaa27857cea..b035faf56535 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfca_emulate.c +++ b/applications/main/nfc/scenes/nfc_scene_nfca_emulate.c @@ -7,12 +7,12 @@ enum { NfcSceneNfcaEmulateStateTextBox, }; -NfcaListenerCommand - nfc_scene_nfca_emulate_worker_callback(NfcaListenerEvent event, void* context) { +Iso14443_3aListenerCommand + nfc_scene_nfca_emulate_worker_callback(Iso14443_3aListenerEvent event, void* context) { furi_assert(context); NfcApp* nfc = context; - if(event.type == NfcaListenerEventTypeReceivedStandartFrame) { + if(event.type == Iso14443_3aListenerEventTypeReceivedStandartFrame) { furi_string_cat_printf(nfc->text_box_store, "R:"); for(size_t i = 0; i < bit_buffer_get_size_bytes(event.data.buffer); i++) { furi_string_cat_printf( @@ -22,7 +22,7 @@ NfcaListenerCommand view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerUpdate); } - return NfcaListenerCommandContinue; + return Iso14443_3aListenerCommandContinue; } void nfc_scene_nfca_emulate_widget_callback(GuiButtonType result, InputType type, void* context) { @@ -41,7 +41,7 @@ void nfc_nfca_emulate_textbox_callback(void* context) { // Add widget with device name or inform that data received static void nfc_scene_nfca_emulate_widget_config(NfcApp* nfc, bool data_received) { - const NfcaData* data = nfc_dev_get_protocol_data(nfc->nfc_dev, NfcProtocolTypeIso14443_3a); + const Iso14443_3aData* data = nfc_device_get_data(nfc->nfc_device, NfcProtocolIso14443_3a); Widget* widget = nfc->widget; widget_reset(widget); FuriString* info_str; @@ -73,9 +73,9 @@ void nfc_scene_nfca_emulate_on_enter(void* context) { text_box_set_focus(text_box, TextBoxFocusEnd); furi_string_reset(nfc->text_box_store); - nfca_listener_start( - nfc->nfca_listener, - nfc_dev_get_protocol_data(nfc->nfc_dev, NfcProtocolTypeIso14443_3a), + iso14443_3a_listener_start( + nfc->iso14443_3a_listener, + nfc_device_get_data(nfc->nfc_device, NfcProtocolIso14443_3a), nfc_scene_nfca_emulate_worker_callback, nfc); @@ -127,7 +127,7 @@ bool nfc_scene_nfca_emulate_on_event(void* context, SceneManagerEvent event) { void nfc_scene_nfca_emulate_on_exit(void* context) { NfcApp* nfc = context; - nfca_listener_stop(nfc->nfca_listener); + iso14443_3a_listener_stop(nfc->iso14443_3a_listener); // 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 0234f3893ca8..e533a71c0f70 100644 --- a/applications/main/nfc/scenes/nfc_scene_read.c +++ b/applications/main/nfc/scenes/nfc_scene_read.c @@ -19,9 +19,8 @@ void nfc_scene_read_on_enter(void* context) { view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup); - const NfcProtocolType protocol_type = - instance->protocols_detected[instance->protocols_detected_idx]; - instance->poller = nfc_poller_alloc(instance->nfc, protocol_type); + const NfcProtocol protocol = instance->protocols_detected[instance->protocols_detected_idx]; + instance->poller = nfc_poller_alloc(instance->nfc, protocol); nfc_poller_start(instance->poller, nfc_scene_read_poller_callback, instance); nfc_blink_detect_start(instance); diff --git a/applications/main/nfc/scenes/nfc_scene_read_success.c b/applications/main/nfc/scenes/nfc_scene_read_success.c index 9db40e569be9..959a0edaec5f 100644 --- a/applications/main/nfc/scenes/nfc_scene_read_success.c +++ b/applications/main/nfc/scenes/nfc_scene_read_success.c @@ -17,7 +17,7 @@ void nfc_scene_read_success_on_enter(void* context) { Widget* widget = nfc->widget; FuriString* temp_str = furi_string_alloc(); - nfc_protocol_format_info(nfc->nfc_dev, NfcProtocolFormatTypeShort, temp_str); + nfc_protocol_format_info(nfc->nfc_device, NfcProtocolFormatTypeShort, temp_str); widget_add_text_scroll_element(widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); furi_string_free(temp_str); @@ -31,12 +31,12 @@ void nfc_scene_read_success_on_enter(void* context) { view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); } -static const NfcScene nfc_scene_read_success_menu_scenes[NfcProtocolTypeMax] = { - [NfcProtocolTypeIso14443_3a] = NfcSceneNfcaMenu, - [NfcProtocolTypeIso14443_4a] = NfcSceneNotImplemented, //TODO: ISO14443-4A menu - [NfcProtocolTypeMfUltralight] = NfcSceneMfUltralightMenu, - [NfcProtocolTypeMfClassic] = NfcSceneMfUltralightMenu, - [NfcProtocolTypeMfDesfire] = NfcSceneMfDesfireMenu, +static const NfcScene nfc_scene_read_success_menu_scenes[NfcProtocolNum] = { + [NfcProtocolIso14443_3a] = NfcSceneNfcaMenu, + [NfcProtocolIso14443_4a] = NfcSceneNotImplemented, //TODO: ISO14443-4A menu + [NfcProtocolMfUltralight] = NfcSceneMfUltralightMenu, + [NfcProtocolMfClassic] = NfcSceneMfUltralightMenu, + [NfcProtocolMfDesfire] = NfcSceneMfDesfireMenu, }; bool nfc_scene_read_success_on_event(void* context, SceneManagerEvent event) { @@ -49,8 +49,8 @@ bool nfc_scene_read_success_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(nfc->scene_manager, NfcSceneRetryConfirm); consumed = true; } else if(event.event == GuiButtonTypeRight) { - const NfcProtocolType protocol_type = nfc_dev_get_protocol_type(nfc->nfc_dev); - const NfcScene menu_scene = nfc_scene_read_success_menu_scenes[protocol_type]; + const NfcProtocol protocol = nfc_device_get_protocol(nfc->nfc_device); + const NfcScene menu_scene = nfc_scene_read_success_menu_scenes[protocol]; scene_manager_next_scene(nfc->scene_manager, menu_scene); consumed = true; } diff --git a/applications/main/nfc/scenes/nfc_scene_saved_menu.c b/applications/main/nfc/scenes/nfc_scene_saved_menu.c index b1eb330972ba..c4235471cc55 100644 --- a/applications/main/nfc/scenes/nfc_scene_saved_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_saved_menu.c @@ -25,9 +25,9 @@ void nfc_scene_saved_menu_on_enter(void* context) { NfcApp* nfc = context; Submenu* submenu = nfc->submenu; - const NfcProtocolType protocol = nfc_dev_get_protocol_type(nfc->nfc_dev); + const NfcProtocol protocol = nfc_device_get_protocol(nfc->nfc_device); - if(protocol == NfcProtocolTypeIso14443_3a) { + if(protocol == NfcProtocolIso14443_3a) { submenu_add_item( submenu, "Emulate UID", @@ -37,19 +37,19 @@ void nfc_scene_saved_menu_on_enter(void* context) { submenu_add_item( submenu, "Edit UID", SubmenuIndexEditUid, nfc_scene_saved_menu_submenu_callback, nfc); - } else if(protocol == NfcProtocolTypeMfDesfire) { + } else if(protocol == NfcProtocolMfDesfire) { submenu_add_item( submenu, "Emulate UID", SubmenuIndexEmulate, nfc_scene_saved_menu_submenu_callback, nfc); - } else if((protocol == NfcProtocolTypeMfUltralight) || (protocol == NfcProtocolTypeMfClassic)) { + } else if((protocol == NfcProtocolMfUltralight) || (protocol == NfcProtocolMfClassic)) { submenu_add_item( submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_saved_menu_submenu_callback, nfc); } - if(protocol == NfcProtocolTypeMfClassic) { + if(protocol == NfcProtocolMfClassic) { // TODO // if(!mifare_classic_is_card_read(&nfc->dev->dev_data.mf_classic_data)) submenu_add_item( @@ -75,9 +75,9 @@ void nfc_scene_saved_menu_on_enter(void* context) { submenu_add_item( submenu, "Info", SubmenuIndexInfo, nfc_scene_saved_menu_submenu_callback, nfc); - if(protocol == NfcProtocolTypeMfUltralight) { + if(protocol == NfcProtocolMfUltralight) { const MfUltralightData* mfu_data = - nfc_dev_get_protocol_data(nfc->nfc_dev, NfcProtocolTypeMfUltralight); + nfc_device_get_data(nfc->nfc_device, NfcProtocolMfUltralight); if(!mf_ultralight_is_all_data_read(mfu_data)) { submenu_add_item( submenu, @@ -115,15 +115,15 @@ void nfc_scene_saved_menu_on_enter(void* context) { bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { NfcApp* nfc = context; - const NfcProtocolType protocol = nfc_dev_get_protocol_type(nfc->nfc_dev); + const NfcProtocol protocol = nfc_device_get_protocol(nfc->nfc_device); bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { scene_manager_set_scene_state(nfc->scene_manager, NfcSceneSavedMenu, event.event); if(event.event == SubmenuIndexEmulate) { - if(protocol == NfcProtocolTypeMfUltralight) { + if(protocol == NfcProtocolMfUltralight) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate); - } else if(protocol == NfcProtocolTypeMfClassic) { + } else if(protocol == NfcProtocolMfClassic) { scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); } else { scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcaEmulate); diff --git a/applications/main/nfc/scenes/nfc_scene_select_protocol.c b/applications/main/nfc/scenes/nfc_scene_select_protocol.c index f1b31d490cd7..fff7ab979964 100644 --- a/applications/main/nfc/scenes/nfc_scene_select_protocol.c +++ b/applications/main/nfc/scenes/nfc_scene_select_protocol.c @@ -14,8 +14,8 @@ void nfc_scene_select_protocol_on_enter(void* context) { const char* prefix; if(scene_manager_has_previous_scene(instance->scene_manager, NfcSceneExtraActions)) { prefix = "Read"; - instance->protocols_detected_num = NfcProtocolTypeMax; - for(size_t i = 0; i < NfcProtocolTypeMax; i++) { + instance->protocols_detected_num = NfcProtocolNum; + for(size_t i = 0; i < NfcProtocolNum; i++) { instance->protocols_detected[i] = i; } } else { @@ -25,7 +25,10 @@ void nfc_scene_select_protocol_on_enter(void* context) { for(size_t i = 0; i < instance->protocols_detected_num; i++) { furi_string_printf( - temp_str, "%s %s", prefix, nfc_dev_get_protocol_name(instance->protocols_detected[i])); + temp_str, + "%s %s", + prefix, + nfc_device_get_protocol_name(instance->protocols_detected[i])); submenu_add_item( submenu, furi_string_get_cstr(temp_str), diff --git a/applications/main/nfc/scenes/nfc_scene_set_uid.c b/applications/main/nfc/scenes/nfc_scene_set_uid.c index cf50f0d1ec2e..4d45432d7901 100644 --- a/applications/main/nfc/scenes/nfc_scene_set_uid.c +++ b/applications/main/nfc/scenes/nfc_scene_set_uid.c @@ -12,14 +12,14 @@ void nfc_scene_set_uid_on_enter(void* context) { // Setup view ByteInput* byte_input = nfc->byte_input; byte_input_set_header_text(byte_input, "Enter UID in hex"); - nfc_dev_copy_protocol_data(nfc->nfc_dev, NfcProtocolTypeIso14443_3a, nfc->nfca_edit_data); + nfc_device_copy_data(nfc->nfc_device, NfcProtocolIso14443_3a, nfc->iso14443_3a_edit_data); byte_input_set_result_callback( byte_input, nfc_scene_set_uid_byte_input_callback, NULL, nfc, - nfc->nfca_edit_data->uid, - nfc->nfca_edit_data->uid_len); + nfc->iso14443_3a_edit_data->uid, + nfc->iso14443_3a_edit_data->uid_len); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewByteInput); } @@ -29,8 +29,8 @@ bool nfc_scene_set_uid_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == NfcCustomEventByteInputDone) { - nfc_dev_set_protocol_data( - nfc->nfc_dev, NfcProtocolTypeIso14443_3a, nfc->nfca_edit_data); + nfc_device_set_data( + nfc->nfc_device, NfcProtocolIso14443_3a, nfc->iso14443_3a_edit_data); if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSavedMenu)) { if(nfc_save(nfc)) { scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess); diff --git a/applications/main/nfc_rpc/nfc_rpc.c b/applications/main/nfc_rpc/nfc_rpc.c index 3d14dc9b9f87..9f03558e41b8 100644 --- a/applications/main/nfc_rpc/nfc_rpc.c +++ b/applications/main/nfc_rpc/nfc_rpc.c @@ -135,8 +135,8 @@ static NfcRpc* nfc_rpc_app_alloc() { NfcRpc* instance = malloc(sizeof(NfcRpc)); instance->nfc = nfc_alloc(); - instance->nfca_listener = nfca_listener_alloc(instance->nfc); - instance->mf_ul_listener = mf_ultralight_listener_alloc(instance->nfca_listener); + instance->iso14443_3a_listener = iso14443_3a_listener_alloc(instance->nfc); + instance->mf_ul_listener = mf_ultralight_listener_alloc(instance->iso14443_3a_listener); NfcRpcHandlerDict_init(instance->handlers); for(size_t i = 0; i < COUNT_OF(nfc_rpc_callbacks); i++) { @@ -172,7 +172,7 @@ void nfc_rpc_app_free(NfcRpc* instance) { furi_assert(instance); mf_ultralight_listener_free(instance->mf_ul_listener); - nfca_listener_free(instance->nfca_listener); + iso14443_3a_listener_free(instance->iso14443_3a_listener); nfc_free(instance->nfc); for(size_t i = 0; i < COUNT_OF(nfc_rpc_callbacks); i++) { diff --git a/applications/main/nfc_rpc/nfc_rpc_i.h b/applications/main/nfc_rpc/nfc_rpc_i.h index 19a78ed80d86..0e81346241f9 100644 --- a/applications/main/nfc_rpc/nfc_rpc_i.h +++ b/applications/main/nfc_rpc/nfc_rpc_i.h @@ -16,8 +16,8 @@ #include #include -#include -#include +#include +#include #include typedef void (*NfcRpcHandler)(Nfc_Main* cmd, void* context); @@ -54,7 +54,7 @@ struct NfcRpc { NfcRpcHandlerDict_t handlers; Nfc* nfc; - NfcaListener* nfca_listener; + Iso14443_3aListener* iso14443_3a_listener; MfUltralightListener* mf_ul_listener; }; diff --git a/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c b/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c index 6250fdf53751..dec5bc857451 100644 --- a/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c +++ b/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c @@ -178,13 +178,13 @@ static void nfc_rpc_mf_ultralight_read_tearing_flag(Nfc_Main* cmd, void* context // TODO DELETE! static void init_mf_ul_data(MfUltralightData* data) { - NfcaData* nfca_data = data->nfca_data; + Iso14443_3aData* iso14443_3a_data = data->iso14443_3a_data; uint8_t uid[7] = {0x44, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05}; uint8_t atqa[2] = {0x44, 0x00}; - nfca_data->uid_len = sizeof(uid); - memcpy(nfca_data->uid, uid, sizeof(uid)); - memcpy(nfca_data->atqa, atqa, sizeof(atqa)); - nfca_data->sak = 0x00; + iso14443_3a_data->uid_len = sizeof(uid); + memcpy(iso14443_3a_data->uid, uid, sizeof(uid)); + memcpy(iso14443_3a_data->atqa, atqa, sizeof(atqa)); + iso14443_3a_data->sak = 0x00; data->type = MfUltralightTypeUnknown; MfUltralightVersion version = { diff --git a/applications/main/nfc_rpc/nfc_rpc_nfca.c b/applications/main/nfc_rpc/nfc_rpc_nfca.c index b15332f1fed8..0d2661e2a50d 100644 --- a/applications/main/nfc_rpc/nfc_rpc_nfca.c +++ b/applications/main/nfc_rpc/nfc_rpc_nfca.c @@ -1,35 +1,35 @@ #include "nfc_rpc_i.h" #include "assets/compiled/nfca.pb.h" -#include +#include -#define TAG "NfcRpcNfca" +#define TAG "NfcRpcIso14443_3a" -static PB_Nfca_Error nfc_rpc_nfca_process_error(NfcaError error) { +static PB_Nfca_Error nfc_rpc_nfca_process_error(Iso14443_3aError error) { PB_Nfca_Error ret = PB_Nfca_Error_None; switch(error) { - case NfcaErrorNone: + case Iso14443_3aErrorNone: ret = PB_Nfca_Error_None; break; - case NfcaErrorNotPresent: + case Iso14443_3aErrorNotPresent: ret = PB_Nfca_Error_NotPresent; break; - case NfcaErrorColResFailed: + case Iso14443_3aErrorColResFailed: ret = PB_Nfca_Error_ColResFailed; break; - case NfcaErrorBufferOverflow: + case Iso14443_3aErrorBufferOverflow: ret = PB_Nfca_Error_BufferOverflow; break; - case NfcaErrorCommunication: + case Iso14443_3aErrorCommunication: ret = PB_Nfca_Error_Communication; break; - case NfcaErrorFieldOff: + case Iso14443_3aErrorFieldOff: ret = PB_Nfca_Error_FieldOff; break; - case NfcaErrorWrongCrc: + case Iso14443_3aErrorWrongCrc: ret = PB_Nfca_Error_WrongCrc; break; - case NfcaErrorTimeout: + case Iso14443_3aErrorTimeout: ret = PB_Nfca_Error_Timeout; break; @@ -48,20 +48,20 @@ static void nfc_rpc_nfca_read(Nfc_Main* cmd, void* context) { NfcRpc* instance = context; PB_Nfca_ReadResponse pb_nfca_read_resp = PB_Nfca_ReadResponse_init_default; - NfcaData nfca_data = {}; - NfcaError error = nfca_poller_read(instance->nfc, &nfca_data); + Iso14443_3aData iso14443_3a_data = {}; + Iso14443_3aError error = iso14443_3a_poller_read(instance->nfc, &iso14443_3a_data); cmd->command_status = Nfc_CommandStatus_OK; cmd->which_content = Nfc_Main_nfca_read_resp_tag; pb_nfca_read_resp.error = nfc_rpc_nfca_process_error(error); if(pb_nfca_read_resp.error == PB_Nfca_Error_None) { - pb_nfca_read_resp.uid_len = nfca_data.uid_len; - memcpy(pb_nfca_read_resp.uid.bytes, nfca_data.uid, nfca_data.uid_len); - pb_nfca_read_resp.uid.size = nfca_data.uid_len; - memcpy(pb_nfca_read_resp.sak.bytes, &nfca_data.sak, sizeof(nfca_data.sak)); - pb_nfca_read_resp.sak.size = sizeof(nfca_data.sak); - memcpy(pb_nfca_read_resp.atqa.bytes, nfca_data.atqa, sizeof(nfca_data.atqa)); - pb_nfca_read_resp.atqa.size = sizeof(nfca_data.atqa); + pb_nfca_read_resp.uid_len = iso14443_3a_data.uid_len; + memcpy(pb_nfca_read_resp.uid.bytes, iso14443_3a_data.uid, iso14443_3a_data.uid_len); + pb_nfca_read_resp.uid.size = iso14443_3a_data.uid_len; + memcpy(pb_nfca_read_resp.sak.bytes, &iso14443_3a_data.sak, sizeof(iso14443_3a_data.sak)); + pb_nfca_read_resp.sak.size = sizeof(iso14443_3a_data.sak); + memcpy(pb_nfca_read_resp.atqa.bytes, iso14443_3a_data.atqa, sizeof(iso14443_3a_data.atqa)); + pb_nfca_read_resp.atqa.size = sizeof(iso14443_3a_data.atqa); } cmd->content.nfca_read_resp = pb_nfca_read_resp; } @@ -75,14 +75,17 @@ static void nfc_rpc_nfca_emulate_start(Nfc_Main* cmd, void* context) { PB_Nfca_EmulateStartResponse_init_default; cmd->command_status = Nfc_CommandStatus_OK; cmd->which_content = Nfc_Main_nfca_emulate_start_resp_tag; - if(instance->nfca_listener == NULL) { - NfcaData nfca_data = {}; - nfca_data.uid_len = cmd->content.nfca_emulate_start_req.uid_len; - memcpy(nfca_data.uid, cmd->content.nfca_emulate_start_req.uid.bytes, nfca_data.uid_len); - memcpy(nfca_data.atqa, cmd->content.nfca_emulate_start_req.atqa.bytes, 2); - memcpy(&nfca_data.sak, cmd->content.nfca_emulate_start_req.sak.bytes, 1); - - nfca_listener_start(instance->nfca_listener, &nfca_data, NULL, NULL); + if(instance->iso14443_3a_listener == NULL) { + Iso14443_3aData iso14443_3a_data = {}; + iso14443_3a_data.uid_len = cmd->content.nfca_emulate_start_req.uid_len; + memcpy( + iso14443_3a_data.uid, + cmd->content.nfca_emulate_start_req.uid.bytes, + iso14443_3a_data.uid_len); + memcpy(iso14443_3a_data.atqa, cmd->content.nfca_emulate_start_req.atqa.bytes, 2); + memcpy(&iso14443_3a_data.sak, cmd->content.nfca_emulate_start_req.sak.bytes, 1); + + iso14443_3a_listener_start(instance->iso14443_3a_listener, &iso14443_3a_data, NULL, NULL); pb_nfca_emulate_start_resp.error = PB_Nfca_Error_None; } else { // TODO add Busy error @@ -100,9 +103,9 @@ static void nfc_rpc_nfca_emulate_stop(Nfc_Main* cmd, void* context) { PB_Nfca_EmulateStopResponse_init_default; cmd->command_status = Nfc_CommandStatus_OK; cmd->which_content = Nfc_Main_nfca_emulate_stop_resp_tag; - if(instance->nfca_listener) { - nfca_listener_stop(instance->nfca_listener); - instance->nfca_listener = NULL; + if(instance->iso14443_3a_listener) { + iso14443_3a_listener_stop(instance->iso14443_3a_listener); + instance->iso14443_3a_listener = NULL; pb_nfca_emulate_stop_resp.error = PB_Nfca_Error_None; } else { // TODO add Busy error diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index c757219d9e74..e7103c19fbe3 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,+,33.0,, +Version,+,36.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -1810,6 +1810,22 @@ Function,-,islower,int,int Function,-,islower_l,int,"int, locale_t" Function,-,isnan,int,double Function,-,isnanf,int,float +Function,-,iso14443_3a_alloc,Iso14443_3aData*, +Function,-,iso14443_3a_append_crc,void,BitBuffer* +Function,-,iso14443_3a_check_crc,_Bool,const BitBuffer* +Function,-,iso14443_3a_copy,void,"Iso14443_3aData*, const Iso14443_3aData*" +Function,-,iso14443_3a_free,void,Iso14443_3aData* +Function,-,iso14443_3a_get_cuid,uint32_t,Iso14443_3aData* +Function,-,iso14443_3a_get_device_name,const char*,"const Iso14443_3aData*, NfcDeviceNameType" +Function,-,iso14443_3a_get_uid,const uint8_t*,"const Iso14443_3aData*, size_t*" +Function,-,iso14443_3a_is_equal,_Bool,"const Iso14443_3aData*, const Iso14443_3aData*" +Function,-,iso14443_3a_load,_Bool,"Iso14443_3aData*, FlipperFormat*, uint32_t" +Function,-,iso14443_3a_load_data,_Bool,"Iso14443_3aData*, FlipperFormat*, uint32_t" +Function,-,iso14443_3a_reset,void,Iso14443_3aData* +Function,-,iso14443_3a_save,_Bool,"const Iso14443_3aData*, FlipperFormat*, uint32_t" +Function,-,iso14443_3a_save_data,_Bool,"const Iso14443_3aData*, FlipperFormat*, uint32_t" +Function,-,iso14443_3a_trim_crc,void,BitBuffer* +Function,-,iso14443_3a_verify,_Bool,"Iso14443_3aData*, const FuriString*" Function,-,isprint,int,int Function,-,isprint_l,int,"int, locale_t" Function,-,ispunct,int,int @@ -1988,10 +2004,10 @@ Function,+,menu_reset,void,Menu* Function,+,menu_set_selected_item,void,"Menu*, uint32_t" Function,+,mf_classic_alloc,MfClassicData*, Function,+,mf_classic_copy,void,"MfClassicData*, const MfClassicData*" -Function,-,mf_classic_detect_protocol,_Bool,"NfcaData*, MfClassicType*" +Function,-,mf_classic_detect_protocol,_Bool,"Iso14443_3aData*, MfClassicType*" Function,+,mf_classic_free,void,MfClassicData* Function,-,mf_classic_get_blocks_num_in_sector,uint8_t,uint8_t -Function,+,mf_classic_get_device_name,const char*,"const MfClassicData*, NfcProtocolNameType" +Function,-,mf_classic_get_device_name,const char*,"const MfClassicData*, NfcDeviceNameType" Function,-,mf_classic_get_first_block_num_of_sector,uint8_t,uint8_t Function,+,mf_classic_get_read_sectors_and_keys,void,"const MfClassicData*, uint8_t*, uint8_t*" Function,-,mf_classic_get_sector_by_block,uint8_t,uint8_t @@ -2046,10 +2062,10 @@ Function,-,nfc_listener_abort,void,Nfc* Function,-,nfc_listener_set_col_res_data,NfcError,"Nfc*, uint8_t*, uint8_t, uint8_t*, uint8_t" Function,-,nfc_listener_sleep,NfcError,Nfc* Function,-,nfc_listener_tx,NfcError,"Nfc*, const BitBuffer*" -Function,-,nfc_poller_alloc,NfcPoller*,"Nfc*, NfcProtocolType" +Function,-,nfc_poller_alloc,NfcPoller*,"Nfc*, NfcProtocol" Function,-,nfc_poller_detect,_Bool,NfcPoller* Function,-,nfc_poller_free,void,NfcPoller* -Function,-,nfc_poller_get_data,const NfcProtocolData*,NfcPoller* +Function,-,nfc_poller_get_data,const NfcDeviceData*,NfcPoller* Function,-,nfc_poller_start,void,"NfcPoller*, NfcPollerCallback, void*" Function,-,nfc_poller_stop,void,NfcPoller* Function,-,nfc_set_fdt_listen_fc,void,"Nfc*, uint32_t" @@ -2062,28 +2078,12 @@ Function,-,nfc_start_poller,void,"Nfc*, NfcEventCallback, void*" Function,-,nfc_stop,void,Nfc* Function,-,nfc_trx,NfcError,"Nfc*, const BitBuffer*, BitBuffer*, uint32_t" Function,-,nfc_trx_custom_parity,NfcError,"Nfc*, const BitBuffer*, BitBuffer*, uint32_t" -Function,+,nfca_alloc,NfcaData*, -Function,-,nfca_append_crc,void,BitBuffer* Function,-,nfca_append_crc16,void,"uint8_t*, uint16_t" -Function,-,nfca_check_crc,_Bool,const BitBuffer* -Function,+,nfca_copy,void,"NfcaData*, const NfcaData*" Function,-,nfca_emulation_handler,_Bool,"uint8_t*, uint16_t, uint8_t*, uint16_t*" -Function,+,nfca_free,void,NfcaData* Function,-,nfca_get_crc16,uint16_t,"uint8_t*, uint16_t" -Function,-,nfca_get_cuid,uint32_t,NfcaData* -Function,+,nfca_get_device_name,const char*,"const NfcaData*, NfcProtocolNameType" -Function,+,nfca_get_uid,const uint8_t*,"const NfcaData*, size_t*" -Function,+,nfca_is_equal,_Bool,"const NfcaData*, const NfcaData*" -Function,+,nfca_load,_Bool,"NfcaData*, FlipperFormat*, uint32_t" -Function,+,nfca_load_data,_Bool,"NfcaData*, FlipperFormat*, uint32_t" -Function,+,nfca_reset,void,NfcaData* -Function,+,nfca_save,_Bool,"const NfcaData*, FlipperFormat*, uint32_t" -Function,+,nfca_save_data,_Bool,"const NfcaData*, FlipperFormat*, uint32_t" Function,-,nfca_signal_alloc,NfcaSignal*, Function,-,nfca_signal_encode,void,"NfcaSignal*, uint8_t*, uint16_t, uint8_t*" Function,-,nfca_signal_free,void,NfcaSignal* -Function,-,nfca_trim_crc,void,BitBuffer* -Function,+,nfca_verify,_Bool,"NfcaData*, const FuriString*" Function,+,notification_internal_message,void,"NotificationApp*, const NotificationSequence*" Function,+,notification_internal_message_block,void,"NotificationApp*, const NotificationSequence*" Function,+,notification_message,void,"NotificationApp*, const NotificationSequence*" @@ -3332,9 +3332,9 @@ Variable,+,message_red_255,const NotificationMessage, Variable,+,message_sound_off,const NotificationMessage, Variable,+,message_vibro_off,const NotificationMessage, Variable,+,message_vibro_on,const NotificationMessage, -Variable,+,nfc_protocol_iso14443_3a,const NfcProtocolBase, -Variable,+,nfc_protocol_mf_classic,const NfcProtocolBase, -Variable,-,nfc_protocols,const NfcProtocolBase*[], +Variable,-,nfc_device_iso14443_3a,const NfcDeviceBase, +Variable,-,nfc_device_mf_classic,const NfcDeviceBase, +Variable,-,nfc_devices,const NfcDeviceBase*[], Variable,+,sequence_audiovisual_alert,const NotificationSequence, Variable,+,sequence_blink_blue_10,const NotificationSequence, Variable,+,sequence_blink_blue_100,const NotificationSequence, diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc.c b/firmware/targets/f7/furi_hal/f_hal_nfc.c index c74ab4474b75..a374b2ee0904 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfc.c +++ b/firmware/targets/f7/furi_hal/f_hal_nfc.c @@ -317,7 +317,7 @@ FHalNfcError f_hal_nfc_set_mode(FHalNfcMode mode, FHalNfcBitrate bitrate) { FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; furi_hal_spi_acquire(handle); - if(mode == FHalNfcModeNfcaPoller) { + if(mode == FHalNfcModeIso14443_3aPoller) { f_hal_nfc_configure_poller_common(handle); // Disable wake up st25r3916_clear_reg_bits(handle, ST25R3916_REG_OP_CONTROL, ST25R3916_REG_OP_CONTROL_wu); @@ -332,7 +332,7 @@ FHalNfcError f_hal_nfc_set_mode(FHalNfcMode mode, FHalNfcBitrate bitrate) { st25r3916_change_reg_bits(handle, ST25R3916_REG_OVERSHOOT_CONF2, 0xff, 0x03); st25r3916_change_reg_bits(handle, ST25R3916_REG_UNDERSHOOT_CONF1, 0xff, 0x40); st25r3916_change_reg_bits(handle, ST25R3916_REG_UNDERSHOOT_CONF2, 0xff, 0x03); - } else if(mode == FHalNfcModeNfcaListener) { + } else if(mode == FHalNfcModeIso14443_3aListener) { st25r3916_write_reg( handle, ST25R3916_REG_OP_CONTROL, diff --git a/firmware/targets/furi_hal_include/f_hal_nfc.h b/firmware/targets/furi_hal_include/f_hal_nfc.h index e4c2b5a7500c..2ae128bf01ea 100644 --- a/firmware/targets/furi_hal_include/f_hal_nfc.h +++ b/firmware/targets/furi_hal_include/f_hal_nfc.h @@ -41,8 +41,8 @@ typedef enum { } FHalNfcError; typedef enum { - FHalNfcModeNfcaPoller, - FHalNfcModeNfcaListener, + FHalNfcModeIso14443_3aPoller, + FHalNfcModeIso14443_3aListener, FHalNfcModeNfcbPoller, FHalNfcModeNfcbListener, diff --git a/lib/nfc/deprecated/helpers/nfc_generators.c b/lib/nfc/deprecated/helpers/nfc_generators.c index 06056a8e24f0..7321183c819a 100644 --- a/lib/nfc/deprecated/helpers/nfc_generators.c +++ b/lib/nfc/deprecated/helpers/nfc_generators.c @@ -13,8 +13,8 @@ static const uint8_t default_data_ntag215_216[] = {0x03, 0x00, 0xFE}; static const uint8_t default_data_ntag_i2c[] = {0xE1, 0x10, 0x00, 0x00, 0x03, 0x00, 0xFE}; static const uint8_t default_config_ntag_i2c[] = {0x01, 0x00, 0xF8, 0x48, 0x08, 0x01, 0x00, 0x00}; -static void nfc_generate_common_start(NfcDeviceData* data) { - nfc_device_data_clear(data); +static void nfc_generate_common_start(NfcDeviceOldDataOld* data) { + nfc_device_old_data_clear(data); } static void nfc_generate_mf_ul_uid(uint8_t* uid) { @@ -78,7 +78,7 @@ static void nfc_generate_mf_classic_sector_trailer(MfClassicData* data, uint8_t data, mifare_classic_get_sector_by_block(block), MfClassicKeyB, 0xFFFFFFFFFFFF); } -static void nfc_generate_mf_ul_common(NfcDeviceData* data) { +static void nfc_generate_mf_ul_common(NfcDeviceOldDataOld* data) { data->nfc_data.type = FuriHalNfcTypeA; data->nfc_data.interface = FuriHalNfcInterfaceRf; data->nfc_data.uid_len = 7; @@ -86,18 +86,18 @@ static void nfc_generate_mf_ul_common(NfcDeviceData* data) { data->nfc_data.atqa[0] = 0x44; data->nfc_data.atqa[1] = 0x00; data->nfc_data.sak = 0x00; - data->protocol = NfcDeviceProtocolMifareUl; + data->protocol = NfcDeviceOldProtocolMifareUl; } static void - nfc_generate_mf_classic_common(NfcDeviceData* data, uint8_t uid_len, MfClassicType type) { + nfc_generate_mf_classic_common(NfcDeviceOldDataOld* data, uint8_t uid_len, MfClassicType type) { data->nfc_data.type = FuriHalNfcTypeA; data->nfc_data.interface = FuriHalNfcInterfaceRf; data->nfc_data.uid_len = uid_len; data->nfc_data.atqa[0] = 0x44; data->nfc_data.atqa[1] = 0x00; data->nfc_data.sak = 0x08; - data->protocol = NfcDeviceProtocolMifareClassic; + data->protocol = NfcDeviceOldProtocolMifareClassic; data->mf_classic_data.type = type; } @@ -106,14 +106,14 @@ static void nfc_generate_calc_bcc(uint8_t* uid, uint8_t* bcc0, uint8_t* bcc1) { *bcc1 = uid[3] ^ uid[4] ^ uid[5] ^ uid[6]; } -static void nfc_generate_mf_ul_copy_uid_with_bcc(NfcDeviceData* data) { +static void nfc_generate_mf_ul_copy_uid_with_bcc(NfcDeviceOldDataOld* data) { MfUltralightData* mful = &data->mf_ul_data; memcpy(mful->data, data->nfc_data.uid, 3); memcpy(&mful->data[4], &data->nfc_data.uid[3], 4); nfc_generate_calc_bcc(data->nfc_data.uid, &mful->data[3], &mful->data[8]); } -static void nfc_generate_mf_ul_orig(NfcDeviceData* data) { +static void nfc_generate_mf_ul_orig(NfcDeviceOldDataOld* data) { nfc_generate_common_start(data); nfc_generate_mf_ul_common(data); @@ -126,7 +126,7 @@ static void nfc_generate_mf_ul_orig(NfcDeviceData* data) { memset(&mful->data[4 * 4], 0xFF, 4); } -static void nfc_generate_mf_ul_ntag203(NfcDeviceData* data) { +static void nfc_generate_mf_ul_ntag203(NfcDeviceOldDataOld* data) { nfc_generate_common_start(data); nfc_generate_mf_ul_common(data); @@ -139,7 +139,7 @@ static void nfc_generate_mf_ul_ntag203(NfcDeviceData* data) { memcpy(&mful->data[3 * 4], default_data_ntag203, sizeof(default_data_ntag203)); } -static void nfc_generate_mf_ul_with_config_common(NfcDeviceData* data, uint8_t num_pages) { +static void nfc_generate_mf_ul_with_config_common(NfcDeviceOldDataOld* data, uint8_t num_pages) { nfc_generate_common_start(data); nfc_generate_mf_ul_common(data); @@ -155,7 +155,7 @@ static void nfc_generate_mf_ul_with_config_common(NfcDeviceData* data, uint8_t n if(num_pages > 20) mful->data[config_index - 1] = MF_UL_TEARING_FLAG_DEFAULT; } -static void nfc_generate_mf_ul_ev1_common(NfcDeviceData* data, uint8_t num_pages) { +static void nfc_generate_mf_ul_ev1_common(NfcDeviceOldDataOld* data, uint8_t num_pages) { nfc_generate_mf_ul_with_config_common(data, num_pages); MfUltralightData* mful = &data->mf_ul_data; memcpy(&mful->version, version_bytes_mf0ulx1, sizeof(version_bytes_mf0ulx1)); @@ -165,7 +165,7 @@ static void nfc_generate_mf_ul_ev1_common(NfcDeviceData* data, uint8_t num_pages // TODO: what's internal byte on page 2? } -static void nfc_generate_mf_ul_11(NfcDeviceData* data) { +static void nfc_generate_mf_ul_11(NfcDeviceOldDataOld* data) { nfc_generate_mf_ul_ev1_common(data, 20); MfUltralightData* mful = &data->mf_ul_data; mful->type = MfUltralightTypeUL11; @@ -174,7 +174,7 @@ static void nfc_generate_mf_ul_11(NfcDeviceData* data) { mful->data[16 * 4] = 0x00; // Low capacitance version does not have STRG_MOD_EN } -static void nfc_generate_mf_ul_h11(NfcDeviceData* data) { +static void nfc_generate_mf_ul_h11(NfcDeviceOldDataOld* data) { nfc_generate_mf_ul_ev1_common(data, 20); MfUltralightData* mful = &data->mf_ul_data; mful->type = MfUltralightTypeUL11; @@ -182,7 +182,7 @@ static void nfc_generate_mf_ul_h11(NfcDeviceData* data) { mful->version.storage_size = 0x0B; } -static void nfc_generate_mf_ul_21(NfcDeviceData* data) { +static void nfc_generate_mf_ul_21(NfcDeviceOldDataOld* data) { nfc_generate_mf_ul_ev1_common(data, 41); MfUltralightData* mful = &data->mf_ul_data; mful->type = MfUltralightTypeUL21; @@ -191,7 +191,7 @@ static void nfc_generate_mf_ul_21(NfcDeviceData* data) { mful->data[37 * 4] = 0x00; // Low capacitance version does not have STRG_MOD_EN } -static void nfc_generate_mf_ul_h21(NfcDeviceData* data) { +static void nfc_generate_mf_ul_h21(NfcDeviceOldDataOld* data) { nfc_generate_mf_ul_ev1_common(data, 41); MfUltralightData* mful = &data->mf_ul_data; mful->type = MfUltralightTypeUL21; @@ -199,7 +199,7 @@ static void nfc_generate_mf_ul_h21(NfcDeviceData* data) { mful->version.storage_size = 0x0E; } -static void nfc_generate_ntag21x_common(NfcDeviceData* data, uint8_t num_pages) { +static void nfc_generate_ntag21x_common(NfcDeviceOldDataOld* data, uint8_t num_pages) { nfc_generate_mf_ul_with_config_common(data, num_pages); MfUltralightData* mful = &data->mf_ul_data; memcpy(&mful->version, version_bytes_ntag21x, sizeof(version_bytes_mf0ulx1)); @@ -209,7 +209,7 @@ static void nfc_generate_ntag21x_common(NfcDeviceData* data, uint8_t num_pages) mful->data[13] = 0x10; } -static void nfc_generate_ntag213(NfcDeviceData* data) { +static void nfc_generate_ntag213(NfcDeviceOldDataOld* data) { nfc_generate_ntag21x_common(data, 45); MfUltralightData* mful = &data->mf_ul_data; mful->type = MfUltralightTypeNTAG213; @@ -219,7 +219,7 @@ static void nfc_generate_ntag213(NfcDeviceData* data) { memcpy(&mful->data[16], default_data_ntag213, sizeof(default_data_ntag213)); } -static void nfc_generate_ntag215(NfcDeviceData* data) { +static void nfc_generate_ntag215(NfcDeviceOldDataOld* data) { nfc_generate_ntag21x_common(data, 135); MfUltralightData* mful = &data->mf_ul_data; mful->type = MfUltralightTypeNTAG215; @@ -229,7 +229,7 @@ static void nfc_generate_ntag215(NfcDeviceData* data) { memcpy(&mful->data[16], default_data_ntag215_216, sizeof(default_data_ntag215_216)); } -static void nfc_generate_ntag216(NfcDeviceData* data) { +static void nfc_generate_ntag216(NfcDeviceOldDataOld* data) { nfc_generate_ntag21x_common(data, 231); MfUltralightData* mful = &data->mf_ul_data; mful->type = MfUltralightTypeNTAG216; @@ -239,8 +239,10 @@ static void nfc_generate_ntag216(NfcDeviceData* data) { memcpy(&mful->data[16], default_data_ntag215_216, sizeof(default_data_ntag215_216)); } -static void - nfc_generate_ntag_i2c_common(NfcDeviceData* data, MfUltralightType type, uint16_t num_pages) { +static void nfc_generate_ntag_i2c_common( + NfcDeviceOldDataOld* data, + MfUltralightType type, + uint16_t num_pages) { nfc_generate_common_start(data); nfc_generate_mf_ul_common(data); @@ -287,7 +289,7 @@ static void sizeof(default_config_ntag_i2c)); } -static void nfc_generate_ntag_i2c_1k(NfcDeviceData* data) { +static void nfc_generate_ntag_i2c_1k(NfcDeviceOldDataOld* data) { nfc_generate_ntag_i2c_common(data, MfUltralightTypeNTAGI2C1K, 231); MfUltralightData* mful = &data->mf_ul_data; mful->version.prod_ver_minor = 0x01; @@ -297,7 +299,7 @@ static void nfc_generate_ntag_i2c_1k(NfcDeviceData* data) { mful->data[14] = 0x6D; // Size of tag in CC } -static void nfc_generate_ntag_i2c_2k(NfcDeviceData* data) { +static void nfc_generate_ntag_i2c_2k(NfcDeviceOldDataOld* data) { nfc_generate_ntag_i2c_common(data, MfUltralightTypeNTAGI2C2K, 485); MfUltralightData* mful = &data->mf_ul_data; mful->version.prod_ver_minor = 0x01; @@ -308,7 +310,7 @@ static void nfc_generate_ntag_i2c_2k(NfcDeviceData* data) { } static void nfc_generate_ntag_i2c_plus_common( - NfcDeviceData* data, + NfcDeviceOldDataOld* data, MfUltralightType type, uint16_t num_pages) { nfc_generate_ntag_i2c_common(data, type, num_pages); @@ -319,21 +321,21 @@ static void nfc_generate_ntag_i2c_plus_common( memset(&mful->data[config_index + 8], 0xFF, 4); // Default PWD } -static void nfc_generate_ntag_i2c_plus_1k(NfcDeviceData* data) { +static void nfc_generate_ntag_i2c_plus_1k(NfcDeviceOldDataOld* data) { nfc_generate_ntag_i2c_plus_common(data, MfUltralightTypeNTAGI2CPlus1K, 236); MfUltralightData* mful = &data->mf_ul_data; mful->version.prod_ver_minor = 0x02; mful->version.storage_size = 0x13; } -static void nfc_generate_ntag_i2c_plus_2k(NfcDeviceData* data) { +static void nfc_generate_ntag_i2c_plus_2k(NfcDeviceOldDataOld* data) { nfc_generate_ntag_i2c_plus_common(data, MfUltralightTypeNTAGI2CPlus2K, 492); MfUltralightData* mful = &data->mf_ul_data; mful->version.prod_ver_minor = 0x02; mful->version.storage_size = 0x15; } -void nfc_generate_mf_classic(NfcDeviceData* data, uint8_t uid_len, MfClassicType type) { +void nfc_generate_mf_classic(NfcDeviceOldDataOld* data, uint8_t uid_len, MfClassicType type) { nfc_generate_common_start(data); nfc_generate_mf_classic_uid(data->mf_classic_data.block[0].value, uid_len); nfc_generate_mf_classic_common(data, uid_len, type); @@ -395,23 +397,23 @@ void nfc_generate_mf_classic(NfcDeviceData* data, uint8_t uid_len, MfClassicType mfc->type = type; } -static void nfc_generate_mf_mini(NfcDeviceData* data) { +static void nfc_generate_mf_mini(NfcDeviceOldDataOld* data) { nfc_generate_mf_classic(data, 4, MfClassicTypeMini); } -static void nfc_generate_mf_classic_1k_4b_uid(NfcDeviceData* data) { +static void nfc_generate_mf_classic_1k_4b_uid(NfcDeviceOldDataOld* data) { nfc_generate_mf_classic(data, 4, MfClassicType1k); } -static void nfc_generate_mf_classic_1k_7b_uid(NfcDeviceData* data) { +static void nfc_generate_mf_classic_1k_7b_uid(NfcDeviceOldDataOld* data) { nfc_generate_mf_classic(data, 7, MfClassicType1k); } -static void nfc_generate_mf_classic_4k_4b_uid(NfcDeviceData* data) { +static void nfc_generate_mf_classic_4k_4b_uid(NfcDeviceOldDataOld* data) { nfc_generate_mf_classic(data, 4, MfClassicType4k); } -static void nfc_generate_mf_classic_4k_7b_uid(NfcDeviceData* data) { +static void nfc_generate_mf_classic_4k_7b_uid(NfcDeviceOldDataOld* data) { nfc_generate_mf_classic(data, 7, MfClassicType4k); } diff --git a/lib/nfc/deprecated/helpers/nfc_generators.h b/lib/nfc/deprecated/helpers/nfc_generators.h index 8cee67067cac..289f3f3e6479 100644 --- a/lib/nfc/deprecated/helpers/nfc_generators.h +++ b/lib/nfc/deprecated/helpers/nfc_generators.h @@ -1,8 +1,8 @@ #pragma once -#include "../nfc_device.h" +#include "../nfc_device_old.h" -typedef void (*NfcGeneratorFunc)(NfcDeviceData* data); +typedef void (*NfcGeneratorFunc)(NfcDeviceOldDataOld* data); typedef struct { const char* name; @@ -11,4 +11,4 @@ typedef struct { extern const NfcGenerator* const nfc_generators[]; -void nfc_generate_mf_classic(NfcDeviceData* data, uint8_t uid_len, MfClassicType type); +void nfc_generate_mf_classic(NfcDeviceOldDataOld* data, uint8_t uid_len, MfClassicType type); diff --git a/lib/nfc/deprecated/helpers/reader_analyzer.c b/lib/nfc/deprecated/helpers/reader_analyzer.c index b76e560da4d6..10c576ac8353 100644 --- a/lib/nfc/deprecated/helpers/reader_analyzer.c +++ b/lib/nfc/deprecated/helpers/reader_analyzer.c @@ -183,15 +183,15 @@ void reader_analyzer_set_callback( instance->context = context; } -NfcProtocol +NfcProtocolOld reader_analyzer_guess_protocol(ReaderAnalyzer* instance, uint8_t* buff_rx, uint16_t len) { furi_assert(instance); furi_assert(buff_rx); UNUSED(len); - NfcProtocol protocol = NfcDeviceProtocolUnknown; + NfcProtocolOld protocol = NfcDeviceOldProtocolUnknown; if((buff_rx[0] == 0x60) || (buff_rx[0] == 0x61)) { - protocol = NfcDeviceProtocolMifareClassic; + protocol = NfcDeviceOldProtocolMifareClassic; } return protocol; diff --git a/lib/nfc/deprecated/helpers/reader_analyzer.h b/lib/nfc/deprecated/helpers/reader_analyzer.h index 41b274207d36..5170714608ed 100644 --- a/lib/nfc/deprecated/helpers/reader_analyzer.h +++ b/lib/nfc/deprecated/helpers/reader_analyzer.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include typedef enum { ReaderAnalyzerModeDebugLog = 0x01, @@ -30,7 +30,7 @@ void reader_analyzer_start(ReaderAnalyzer* instance, ReaderAnalyzerMode mode); void reader_analyzer_stop(ReaderAnalyzer* instance); -NfcProtocol +NfcProtocolOld reader_analyzer_guess_protocol(ReaderAnalyzer* instance, uint8_t* buff_rx, uint16_t len); FuriHalNfcDevData* reader_analyzer_get_nfc_data(ReaderAnalyzer* instance); diff --git a/lib/nfc/deprecated/nfc_device.c b/lib/nfc/deprecated/nfc_device_old.c similarity index 87% rename from lib/nfc/deprecated/nfc_device.c rename to lib/nfc/deprecated/nfc_device_old.c index 581eb6e97b99..40b548dbd1a2 100644 --- a/lib/nfc/deprecated/nfc_device.c +++ b/lib/nfc/deprecated/nfc_device_old.c @@ -1,4 +1,4 @@ -#include "nfc_device.h" +#include "nfc_device_old.h" #include "assets_icons.h" #include "nfc_types.h" @@ -7,7 +7,7 @@ #include #include -#define TAG "NfcDevice" +#define TAG "NfcDeviceOld" #define NFC_DEVICE_KEYS_FOLDER EXT_PATH("nfc/.cache") #define NFC_DEVICE_KEYS_EXTENSION ".keys" @@ -21,8 +21,8 @@ static const uint32_t nfc_keys_file_version = 1; static const uint32_t nfc_mifare_classic_data_format_version = 2; static const uint32_t nfc_mifare_ultralight_data_format_version = 1; -NfcDevice* nfc_device_alloc() { - NfcDevice* nfc_dev = malloc(sizeof(NfcDevice)); +NfcDeviceOld* nfc_device_old_alloc() { + NfcDeviceOld* nfc_dev = malloc(sizeof(NfcDeviceOld)); nfc_dev->storage = furi_record_open(RECORD_STORAGE); nfc_dev->dialogs = furi_record_open(RECORD_DIALOGS); nfc_dev->load_path = furi_string_alloc(); @@ -36,9 +36,9 @@ NfcDevice* nfc_device_alloc() { return nfc_dev; } -void nfc_device_free(NfcDevice* nfc_dev) { +void nfc_device_old_free(NfcDeviceOld* nfc_dev) { furi_assert(nfc_dev); - nfc_device_clear(nfc_dev); + nfc_device_old_clear(nfc_dev); furi_record_close(RECORD_STORAGE); furi_record_close(RECORD_DIALOGS); furi_string_free(nfc_dev->load_path); @@ -47,63 +47,63 @@ void nfc_device_free(NfcDevice* nfc_dev) { free(nfc_dev); } -static void nfc_device_prepare_format_string(NfcDevice* dev, FuriString* format_string) { - if(dev->format == NfcDeviceSaveFormatUid) { +static void nfc_device_old_prepare_format_string(NfcDeviceOld* dev, FuriString* format_string) { + if(dev->format == NfcDeviceOldSaveFormatUid) { furi_string_set(format_string, "UID"); - } else if(dev->format == NfcDeviceSaveFormatBankCard) { + } else if(dev->format == NfcDeviceOldSaveFormatBankCard) { furi_string_set(format_string, "Bank card"); - } else if(dev->format == NfcDeviceSaveFormatMifareUl) { + } else if(dev->format == NfcDeviceOldSaveFormatMifareUl) { furi_string_set(format_string, nfc_mf_ul_type(dev->dev_data.mf_ul_data.type, true)); - } else if(dev->format == NfcDeviceSaveFormatMifareClassic) { + } else if(dev->format == NfcDeviceOldSaveFormatMifareClassic) { furi_string_set(format_string, "Mifare Classic"); - } else if(dev->format == NfcDeviceSaveFormatMifareDesfire) { + } else if(dev->format == NfcDeviceOldSaveFormatMifareDesfire) { furi_string_set(format_string, "Mifare DESFire"); - } else if(dev->format == NfcDeviceSaveFormatNfcV) { + } else if(dev->format == NfcDeviceOldSaveFormatNfcV) { furi_string_set(format_string, "ISO15693"); } else { furi_string_set(format_string, "Unknown"); } } -static bool nfc_device_parse_format_string(NfcDevice* dev, FuriString* format_string) { +static bool nfc_device_old_parse_format_string(NfcDeviceOld* dev, FuriString* format_string) { if(furi_string_start_with_str(format_string, "UID")) { - dev->format = NfcDeviceSaveFormatUid; - dev->dev_data.protocol = NfcDeviceProtocolUnknown; + dev->format = NfcDeviceOldSaveFormatUid; + dev->dev_data.protocol = NfcDeviceOldProtocolUnknown; return true; } if(furi_string_start_with_str(format_string, "Bank card")) { - dev->format = NfcDeviceSaveFormatBankCard; - dev->dev_data.protocol = NfcDeviceProtocolEMV; + dev->format = NfcDeviceOldSaveFormatBankCard; + dev->dev_data.protocol = NfcDeviceOldProtocolEMV; return true; } // Check Mifare Ultralight types for(MfUltralightType type = MfUltralightTypeUnknown; type < MfUltralightTypeNum; type++) { if(furi_string_equal(format_string, nfc_mf_ul_type(type, true))) { - dev->format = NfcDeviceSaveFormatMifareUl; - dev->dev_data.protocol = NfcDeviceProtocolMifareUl; + dev->format = NfcDeviceOldSaveFormatMifareUl; + dev->dev_data.protocol = NfcDeviceOldProtocolMifareUl; dev->dev_data.mf_ul_data.type = type; return true; } } if(furi_string_start_with_str(format_string, "Mifare Classic")) { - dev->format = NfcDeviceSaveFormatMifareClassic; - dev->dev_data.protocol = NfcDeviceProtocolMifareClassic; + dev->format = NfcDeviceOldSaveFormatMifareClassic; + dev->dev_data.protocol = NfcDeviceOldProtocolMifareClassic; return true; } if(furi_string_start_with_str(format_string, "Mifare DESFire")) { - dev->format = NfcDeviceSaveFormatMifareDesfire; - dev->dev_data.protocol = NfcDeviceProtocolMifareDesfire; + dev->format = NfcDeviceOldSaveFormatMifareDesfire; + dev->dev_data.protocol = NfcDeviceOldProtocolMifareDesfire; return true; } if(furi_string_start_with_str(format_string, "ISO15693")) { - dev->format = NfcDeviceSaveFormatNfcV; - dev->dev_data.protocol = NfcDeviceProtocolNfcV; + dev->format = NfcDeviceOldSaveFormatNfcV; + dev->dev_data.protocol = NfcDeviceOldProtocolNfcV; return true; } return false; } -static bool nfc_device_save_mifare_ul_data(FlipperFormat* file, NfcDevice* dev) { +static bool nfc_device_old_save_mifare_ul_data(FlipperFormat* file, NfcDeviceOld* dev) { bool saved = false; MfUltralightData* data = &dev->dev_data.mf_ul_data; FuriString* temp_str; @@ -164,7 +164,7 @@ static bool nfc_device_save_mifare_ul_data(FlipperFormat* file, NfcDevice* dev) return saved; } -bool nfc_device_load_mifare_ul_data(FlipperFormat* file, NfcDevice* dev) { +bool nfc_device_old_load_mifare_ul_data(FlipperFormat* file, NfcDeviceOld* dev) { bool parsed = false; MfUltralightData* data = &dev->dev_data.mf_ul_data; FuriString* temp_str; @@ -239,7 +239,7 @@ bool nfc_device_load_mifare_ul_data(FlipperFormat* file, NfcDevice* dev) { return parsed; } -static bool nfc_device_save_mifare_df_key_settings( +static bool nfc_device_old_save_mifare_df_key_settings( FlipperFormat* file, MifareDesfireKeySettings* ks, const char* prefix) { @@ -281,7 +281,7 @@ static bool nfc_device_save_mifare_df_key_settings( return saved; } -bool nfc_device_load_mifare_df_key_settings( +bool nfc_device_old_load_mifare_df_key_settings( FlipperFormat* file, MifareDesfireKeySettings* ks, const char* prefix) { @@ -333,7 +333,7 @@ bool nfc_device_load_mifare_df_key_settings( return parsed; } -static bool nfc_device_save_mifare_df_app(FlipperFormat* file, MifareDesfireApplication* app) { +static bool nfc_device_old_save_mifare_df_app(FlipperFormat* file, MifareDesfireApplication* app) { bool saved = false; FuriString *prefix, *key; prefix = @@ -343,7 +343,7 @@ static bool nfc_device_save_mifare_df_app(FlipperFormat* file, MifareDesfireAppl do { if(app->key_settings) { - if(!nfc_device_save_mifare_df_key_settings( + if(!nfc_device_old_save_mifare_df_key_settings( file, app->key_settings, furi_string_get_cstr(prefix))) break; } @@ -441,7 +441,7 @@ static bool nfc_device_save_mifare_df_app(FlipperFormat* file, MifareDesfireAppl return saved; } -bool nfc_device_load_mifare_df_app(FlipperFormat* file, MifareDesfireApplication* app) { +bool nfc_device_old_load_mifare_df_app(FlipperFormat* file, MifareDesfireApplication* app) { bool parsed = false; FuriString *prefix, *key; prefix = @@ -453,7 +453,7 @@ bool nfc_device_load_mifare_df_app(FlipperFormat* file, MifareDesfireApplication do { app->key_settings = malloc(sizeof(MifareDesfireKeySettings)); memset(app->key_settings, 0, sizeof(MifareDesfireKeySettings)); - if(!nfc_device_load_mifare_df_key_settings( + if(!nfc_device_old_load_mifare_df_key_settings( file, app->key_settings, furi_string_get_cstr(prefix))) { free(app->key_settings); app->key_settings = NULL; @@ -556,7 +556,7 @@ bool nfc_device_load_mifare_df_app(FlipperFormat* file, MifareDesfireApplication return parsed; } -static bool nfc_device_save_mifare_df_data(FlipperFormat* file, NfcDevice* dev) { +static bool nfc_device_old_save_mifare_df_data(FlipperFormat* file, NfcDeviceOld* dev) { bool saved = false; MifareDesfireData* data = &dev->dev_data.mf_df_data; uint8_t* tmp = NULL; @@ -571,7 +571,7 @@ static bool nfc_device_save_mifare_df_data(FlipperFormat* file, NfcDevice* dev) break; } if(data->master_key_settings) { - if(!nfc_device_save_mifare_df_key_settings(file, data->master_key_settings, "PICC")) + if(!nfc_device_old_save_mifare_df_key_settings(file, data->master_key_settings, "PICC")) break; } uint32_t n_apps = 0; @@ -588,7 +588,7 @@ static bool nfc_device_save_mifare_df_data(FlipperFormat* file, NfcDevice* dev) } if(!flipper_format_write_hex(file, "Application IDs", tmp, n_apps * 3)) break; for(MifareDesfireApplication* app = data->app_head; app; app = app->next) { - if(!nfc_device_save_mifare_df_app(file, app)) break; + if(!nfc_device_old_save_mifare_df_app(file, app)) break; } } saved = true; @@ -598,7 +598,7 @@ static bool nfc_device_save_mifare_df_data(FlipperFormat* file, NfcDevice* dev) return saved; } -bool nfc_device_load_mifare_df_data(FlipperFormat* file, NfcDevice* dev) { +bool nfc_device_old_load_mifare_df_data(FlipperFormat* file, NfcDeviceOld* dev) { bool parsed = false; MifareDesfireData* data = &dev->dev_data.mf_df_data; memset(data, 0, sizeof(MifareDesfireData)); @@ -620,7 +620,8 @@ bool nfc_device_load_mifare_df_data(FlipperFormat* file, NfcDevice* dev) { if(flipper_format_key_exist(file, "PICC Change Key ID")) { data->master_key_settings = malloc(sizeof(MifareDesfireKeySettings)); memset(data->master_key_settings, 0, sizeof(MifareDesfireKeySettings)); - if(!nfc_device_load_mifare_df_key_settings(file, data->master_key_settings, "PICC")) { + if(!nfc_device_old_load_mifare_df_key_settings( + file, data->master_key_settings, "PICC")) { free(data->master_key_settings); data->master_key_settings = NULL; break; @@ -637,7 +638,7 @@ bool nfc_device_load_mifare_df_data(FlipperFormat* file, NfcDevice* dev) { MifareDesfireApplication* app = malloc(sizeof(MifareDesfireApplication)); memset(app, 0, sizeof(MifareDesfireApplication)); memcpy(app->id, &tmp[i * 3], 3); - if(!nfc_device_load_mifare_df_app(file, app)) { + if(!nfc_device_old_load_mifare_df_app(file, app)) { free(app); parsed_apps = false; break; @@ -657,7 +658,7 @@ bool nfc_device_load_mifare_df_data(FlipperFormat* file, NfcDevice* dev) { return parsed; } -static bool nfc_device_save_slix_data(FlipperFormat* file, NfcDevice* dev) { +static bool nfc_device_old_save_slix_data(FlipperFormat* file, NfcDeviceOld* dev) { bool saved = false; NfcVSlixData* data = &dev->dev_data.nfcv_data.sub_data.slix; @@ -671,7 +672,7 @@ static bool nfc_device_save_slix_data(FlipperFormat* file, NfcDevice* dev) { return saved; } -bool nfc_device_load_slix_data(FlipperFormat* file, NfcDevice* dev) { +bool nfc_device_old_load_slix_data(FlipperFormat* file, NfcDeviceOld* dev) { bool parsed = false; NfcVSlixData* data = &dev->dev_data.nfcv_data.sub_data.slix; memset(data, 0, sizeof(NfcVSlixData)); @@ -686,7 +687,7 @@ bool nfc_device_load_slix_data(FlipperFormat* file, NfcDevice* dev) { return parsed; } -static bool nfc_device_save_slix_s_data(FlipperFormat* file, NfcDevice* dev) { +static bool nfc_device_old_save_slix_s_data(FlipperFormat* file, NfcDeviceOld* dev) { bool saved = false; NfcVSlixData* data = &dev->dev_data.nfcv_data.sub_data.slix; @@ -712,7 +713,7 @@ static bool nfc_device_save_slix_s_data(FlipperFormat* file, NfcDevice* dev) { return saved; } -bool nfc_device_load_slix_s_data(FlipperFormat* file, NfcDevice* dev) { +bool nfc_device_old_load_slix_s_data(FlipperFormat* file, NfcDeviceOld* dev) { bool parsed = false; NfcVSlixData* data = &dev->dev_data.nfcv_data.sub_data.slix; memset(data, 0, sizeof(NfcVSlixData)); @@ -739,7 +740,7 @@ bool nfc_device_load_slix_s_data(FlipperFormat* file, NfcDevice* dev) { return parsed; } -static bool nfc_device_save_slix_l_data(FlipperFormat* file, NfcDevice* dev) { +static bool nfc_device_old_save_slix_l_data(FlipperFormat* file, NfcDeviceOld* dev) { bool saved = false; NfcVSlixData* data = &dev->dev_data.nfcv_data.sub_data.slix; @@ -760,7 +761,7 @@ static bool nfc_device_save_slix_l_data(FlipperFormat* file, NfcDevice* dev) { return saved; } -bool nfc_device_load_slix_l_data(FlipperFormat* file, NfcDevice* dev) { +bool nfc_device_old_load_slix_l_data(FlipperFormat* file, NfcDeviceOld* dev) { bool parsed = false; NfcVSlixData* data = &dev->dev_data.nfcv_data.sub_data.slix; memset(data, 0, sizeof(NfcVSlixData)); @@ -782,7 +783,7 @@ bool nfc_device_load_slix_l_data(FlipperFormat* file, NfcDevice* dev) { return parsed; } -static bool nfc_device_save_slix2_data(FlipperFormat* file, NfcDevice* dev) { +static bool nfc_device_old_save_slix2_data(FlipperFormat* file, NfcDeviceOld* dev) { bool saved = false; NfcVSlixData* data = &dev->dev_data.nfcv_data.sub_data.slix; @@ -808,7 +809,7 @@ static bool nfc_device_save_slix2_data(FlipperFormat* file, NfcDevice* dev) { return saved; } -bool nfc_device_load_slix2_data(FlipperFormat* file, NfcDevice* dev) { // -V524 +bool nfc_device_old_load_slix2_data(FlipperFormat* file, NfcDeviceOld* dev) { // -V524 bool parsed = false; NfcVSlixData* data = &dev->dev_data.nfcv_data.sub_data.slix; memset(data, 0, sizeof(NfcVSlixData)); @@ -835,7 +836,7 @@ bool nfc_device_load_slix2_data(FlipperFormat* file, NfcDevice* dev) { // -V524 return parsed; } -static bool nfc_device_save_nfcv_data(FlipperFormat* file, NfcDevice* dev) { +static bool nfc_device_old_save_nfcv_data(FlipperFormat* file, NfcDeviceOld* dev) { bool saved = false; NfcVData* data = &dev->dev_data.nfcv_data; @@ -877,16 +878,16 @@ static bool nfc_device_save_nfcv_data(FlipperFormat* file, NfcDevice* dev) { saved = true; break; case NfcVTypeSlix: - saved = nfc_device_save_slix_data(file, dev); + saved = nfc_device_old_save_slix_data(file, dev); break; case NfcVTypeSlixS: - saved = nfc_device_save_slix_s_data(file, dev); + saved = nfc_device_old_save_slix_s_data(file, dev); break; case NfcVTypeSlixL: - saved = nfc_device_save_slix_l_data(file, dev); + saved = nfc_device_old_save_slix_l_data(file, dev); break; case NfcVTypeSlix2: - saved = nfc_device_save_slix2_data(file, dev); + saved = nfc_device_old_save_slix2_data(file, dev); break; default: break; @@ -896,7 +897,7 @@ static bool nfc_device_save_nfcv_data(FlipperFormat* file, NfcDevice* dev) { return saved; } -bool nfc_device_load_nfcv_data(FlipperFormat* file, NfcDevice* dev) { +bool nfc_device_old_load_nfcv_data(FlipperFormat* file, NfcDeviceOld* dev) { bool parsed = false; NfcVData* data = &dev->dev_data.nfcv_data; @@ -930,16 +931,16 @@ bool nfc_device_load_nfcv_data(FlipperFormat* file, NfcDevice* dev) { parsed = true; break; case NfcVTypeSlix: - parsed = nfc_device_load_slix_data(file, dev); + parsed = nfc_device_old_load_slix_data(file, dev); break; case NfcVTypeSlixS: - parsed = nfc_device_load_slix_s_data(file, dev); + parsed = nfc_device_old_load_slix_s_data(file, dev); break; case NfcVTypeSlixL: - parsed = nfc_device_load_slix_l_data(file, dev); + parsed = nfc_device_old_load_slix_l_data(file, dev); break; case NfcVTypeSlix2: - parsed = nfc_device_load_slix2_data(file, dev); + parsed = nfc_device_old_load_slix2_data(file, dev); break; default: break; @@ -949,7 +950,7 @@ bool nfc_device_load_nfcv_data(FlipperFormat* file, NfcDevice* dev) { return parsed; } -static bool nfc_device_save_bank_card_data(FlipperFormat* file, NfcDevice* dev) { +static bool nfc_device_old_save_bank_card_data(FlipperFormat* file, NfcDeviceOld* dev) { bool saved = false; EmvData* data = &dev->dev_data.emv_data; uint32_t data_temp = 0; @@ -978,7 +979,7 @@ static bool nfc_device_save_bank_card_data(FlipperFormat* file, NfcDevice* dev) return saved; } -bool nfc_device_load_bank_card_data(FlipperFormat* file, NfcDevice* dev) { +bool nfc_device_old_load_bank_card_data(FlipperFormat* file, NfcDeviceOld* dev) { bool parsed = false; EmvData* data = &dev->dev_data.emv_data; memset(data, 0, sizeof(EmvData)); @@ -1015,7 +1016,7 @@ bool nfc_device_load_bank_card_data(FlipperFormat* file, NfcDevice* dev) { return parsed; } -static void nfc_device_write_mifare_classic_block( +static void nfc_device_old_write_mifare_classic_block( FuriString* block_str, MfClassicData* data, uint8_t block_num) { @@ -1062,7 +1063,7 @@ static void nfc_device_write_mifare_classic_block( furi_string_trim(block_str); } -static bool nfc_device_save_mifare_classic_data(FlipperFormat* file, NfcDevice* dev) { +static bool nfc_device_old_save_mifare_classic_data(FlipperFormat* file, NfcDeviceOld* dev) { bool saved = false; MfClassicData* data = &dev->dev_data.mf_classic_data; FuriString* temp_str; @@ -1094,7 +1095,7 @@ static bool nfc_device_save_mifare_classic_data(FlipperFormat* file, NfcDevice* block_str = furi_string_alloc(); for(size_t i = 0; i < blocks; i++) { furi_string_printf(temp_str, "Block %d", i); - nfc_device_write_mifare_classic_block(block_str, data, i); + nfc_device_old_write_mifare_classic_block(block_str, data, i); if(!flipper_format_write_string(file, furi_string_get_cstr(temp_str), block_str)) { block_saved = false; break; @@ -1109,7 +1110,7 @@ static bool nfc_device_save_mifare_classic_data(FlipperFormat* file, NfcDevice* return saved; } -static void nfc_device_load_mifare_classic_block( +static void nfc_device_old_load_mifare_classic_block( FuriString* block_str, MfClassicData* data, uint8_t block_num) { @@ -1162,7 +1163,7 @@ static void nfc_device_load_mifare_classic_block( } } -static bool nfc_device_load_mifare_classic_data(FlipperFormat* file, NfcDevice* dev) { +static bool nfc_device_old_load_mifare_classic_data(FlipperFormat* file, NfcDeviceOld* dev) { bool parsed = false; MfClassicData* data = &dev->dev_data.mf_classic_data; FuriString* temp_str; @@ -1209,7 +1210,7 @@ static bool nfc_device_load_mifare_classic_data(FlipperFormat* file, NfcDevice* block_read = false; break; } - nfc_device_load_mifare_classic_block(block_str, data, i); + nfc_device_old_load_mifare_classic_block(block_str, data, i); } furi_string_free(block_str); if(!block_read) break; @@ -1228,7 +1229,7 @@ static bool nfc_device_load_mifare_classic_data(FlipperFormat* file, NfcDevice* return parsed; } -static void nfc_device_get_key_cache_file_path(NfcDevice* dev, FuriString* file_path) { +static void nfc_device_old_get_key_cache_file_path(NfcDeviceOld* dev, FuriString* file_path) { uint8_t* uid = dev->dev_data.nfc_data.uid; uint8_t uid_len = dev->dev_data.nfc_data.uid_len; furi_string_set(file_path, NFC_DEVICE_KEYS_FOLDER "/"); @@ -1238,13 +1239,13 @@ static void nfc_device_get_key_cache_file_path(NfcDevice* dev, FuriString* file_ furi_string_cat_printf(file_path, NFC_DEVICE_KEYS_EXTENSION); } -static bool nfc_device_save_mifare_classic_keys(NfcDevice* dev) { +static bool nfc_device_old_save_mifare_classic_keys(NfcDeviceOld* dev) { FlipperFormat* file = flipper_format_file_alloc(dev->storage); MfClassicData* data = &dev->dev_data.mf_classic_data; FuriString* temp_str; temp_str = furi_string_alloc(); - nfc_device_get_key_cache_file_path(dev, temp_str); + nfc_device_old_get_key_cache_file_path(dev, temp_str); bool save_success = false; do { if(!storage_simply_mkdir(dev->storage, NFC_DEVICE_KEYS_FOLDER)) break; @@ -1285,13 +1286,13 @@ static bool nfc_device_save_mifare_classic_keys(NfcDevice* dev) { return save_success; } -bool nfc_device_load_key_cache(NfcDevice* dev) { +bool nfc_device_old_load_key_cache(NfcDeviceOld* dev) { furi_assert(dev); FuriString* temp_str; temp_str = furi_string_alloc(); MfClassicData* data = &dev->dev_data.mf_classic_data; - nfc_device_get_key_cache_file_path(dev, temp_str); + nfc_device_old_get_key_cache_file_path(dev, temp_str); FlipperFormat* file = flipper_format_file_alloc(dev->storage); bool load_success = false; @@ -1340,25 +1341,25 @@ bool nfc_device_load_key_cache(NfcDevice* dev) { return load_success; } -void nfc_device_set_name(NfcDevice* dev, const char* name) { +void nfc_device_old_set_name(NfcDeviceOld* dev, const char* name) { furi_assert(dev); strlcpy(dev->dev_name, name, NFC_DEV_NAME_MAX_LEN); } -static void nfc_device_get_path_without_ext(FuriString* orig_path, FuriString* shadow_path) { +static void nfc_device_old_get_path_without_ext(FuriString* orig_path, FuriString* shadow_path) { // TODO: this won't work if there is ".nfc" anywhere in the path other than // at the end size_t ext_start = furi_string_search(orig_path, NFC_APP_EXTENSION); furi_string_set_n(shadow_path, orig_path, 0, ext_start); } -static void nfc_device_get_shadow_path(FuriString* orig_path, FuriString* shadow_path) { - nfc_device_get_path_without_ext(orig_path, shadow_path); +static void nfc_device_old_get_shadow_path(FuriString* orig_path, FuriString* shadow_path) { + nfc_device_old_get_path_without_ext(orig_path, shadow_path); furi_string_cat_printf(shadow_path, "%s", NFC_APP_SHADOW_EXTENSION); } -static void nfc_device_get_folder_from_path(FuriString* path, FuriString* folder) { +static void nfc_device_old_get_folder_from_path(FuriString* path, FuriString* folder) { size_t last_slash = furi_string_search_rchar(path, '/'); if(last_slash == FURI_STRING_FAILURE) { // No slashes in the path, treat the whole path as a folder @@ -1368,7 +1369,7 @@ static void nfc_device_get_folder_from_path(FuriString* path, FuriString* folder } } -bool nfc_device_save(NfcDevice* dev, const char* dev_name) { +bool nfc_device_old_save(NfcDeviceOld* dev, const char* dev_name) { furi_assert(dev); bool saved = false; @@ -1383,7 +1384,7 @@ bool nfc_device_save(NfcDevice* dev, const char* dev_name) { // Get folder from filename (filename is in the form of "folder/filename.nfc", so the folder is "folder/") furi_string_set(temp_str, dev_name); // Get folder from filename - nfc_device_get_folder_from_path(temp_str, folder); + nfc_device_old_get_folder_from_path(temp_str, folder); FURI_LOG_I("Nfc", "Saving to folder %s", furi_string_get_cstr(folder)); if(!storage_simply_mkdir(dev->storage, furi_string_get_cstr(folder))) { FURI_LOG_E("Nfc", "Failed to create folder %s", furi_string_get_cstr(folder)); @@ -1399,13 +1400,13 @@ bool nfc_device_save(NfcDevice* dev, const char* dev_name) { if(!flipper_format_write_comment_cstr( file, "Nfc device type can be UID, Mifare Ultralight, Mifare Classic or ISO15693")) break; - nfc_device_prepare_format_string(dev, temp_str); + nfc_device_old_prepare_format_string(dev, temp_str); if(!flipper_format_write_string(file, "Device type", temp_str)) break; // Write UID if(!flipper_format_write_comment_cstr(file, "UID is common for all formats")) break; if(!flipper_format_write_hex(file, "UID", data->uid, data->uid_len)) break; - if(dev->format != NfcDeviceSaveFormatNfcV) { + if(dev->format != NfcDeviceOldSaveFormatNfcV) { // Write ATQA, SAK if(!flipper_format_write_comment_cstr(file, "ISO14443 specific fields")) break; // Save ATQA in MSB order for correct companion apps display @@ -1415,19 +1416,19 @@ bool nfc_device_save(NfcDevice* dev, const char* dev_name) { } // Save more data if necessary - if(dev->format == NfcDeviceSaveFormatMifareUl) { - if(!nfc_device_save_mifare_ul_data(file, dev)) break; - } else if(dev->format == NfcDeviceSaveFormatMifareDesfire) { - if(!nfc_device_save_mifare_df_data(file, dev)) break; - } else if(dev->format == NfcDeviceSaveFormatNfcV) { - if(!nfc_device_save_nfcv_data(file, dev)) break; - } else if(dev->format == NfcDeviceSaveFormatBankCard) { - if(!nfc_device_save_bank_card_data(file, dev)) break; - } else if(dev->format == NfcDeviceSaveFormatMifareClassic) { + if(dev->format == NfcDeviceOldSaveFormatMifareUl) { + if(!nfc_device_old_save_mifare_ul_data(file, dev)) break; + } else if(dev->format == NfcDeviceOldSaveFormatMifareDesfire) { + if(!nfc_device_old_save_mifare_df_data(file, dev)) break; + } else if(dev->format == NfcDeviceOldSaveFormatNfcV) { + if(!nfc_device_old_save_nfcv_data(file, dev)) break; + } else if(dev->format == NfcDeviceOldSaveFormatBankCard) { + if(!nfc_device_old_save_bank_card_data(file, dev)) break; + } else if(dev->format == NfcDeviceOldSaveFormatMifareClassic) { // Save data - if(!nfc_device_save_mifare_classic_data(file, dev)) break; + if(!nfc_device_old_save_mifare_classic_data(file, dev)) break; // Save keys cache - if(!nfc_device_save_mifare_classic_keys(dev)) break; + if(!nfc_device_old_save_mifare_classic_keys(dev)) break; } saved = true; } while(0); @@ -1440,22 +1441,22 @@ bool nfc_device_save(NfcDevice* dev, const char* dev_name) { return saved; } -bool nfc_device_save_shadow(NfcDevice* dev, const char* path) { +bool nfc_device_old_save_shadow(NfcDeviceOld* dev, const char* path) { dev->shadow_file_exist = true; // Replace extension from .nfc to .shd if necessary FuriString* orig_path = furi_string_alloc(); furi_string_set_str(orig_path, path); FuriString* shadow_path = furi_string_alloc(); - nfc_device_get_shadow_path(orig_path, shadow_path); + nfc_device_old_get_shadow_path(orig_path, shadow_path); - bool file_saved = nfc_device_save(dev, furi_string_get_cstr(shadow_path)); + bool file_saved = nfc_device_old_save(dev, furi_string_get_cstr(shadow_path)); furi_string_free(orig_path); furi_string_free(shadow_path); return file_saved; } -static bool nfc_device_load_data(NfcDevice* dev, FuriString* path, bool show_dialog) { +static bool nfc_device_old_load_data(NfcDeviceOld* dev, FuriString* path, bool show_dialog) { bool parsed = false; FlipperFormat* file = flipper_format_file_alloc(dev->storage); FuriHalNfcDevData* data = &dev->dev_data.nfc_data; @@ -1473,7 +1474,7 @@ static bool nfc_device_load_data(NfcDevice* dev, FuriString* path, bool show_dia do { // Check existence of shadow file - nfc_device_get_shadow_path(path, temp_str); + nfc_device_old_get_shadow_path(path, temp_str); dev->shadow_file_exist = storage_common_stat(dev->storage, furi_string_get_cstr(temp_str), NULL) == FSE_OK; // Open shadow file if it exists. If not - open original @@ -1494,13 +1495,13 @@ static bool nfc_device_load_data(NfcDevice* dev, FuriString* path, bool show_dia } // Read Nfc device type if(!flipper_format_read_string(file, "Device type", temp_str)) break; - if(!nfc_device_parse_format_string(dev, temp_str)) break; + if(!nfc_device_old_parse_format_string(dev, temp_str)) break; // Read and parse UID, ATQA and SAK if(!flipper_format_get_value_count(file, "UID", &data_cnt)) break; if(!(data_cnt == 4 || data_cnt == 7 || data_cnt == 8)) break; data->uid_len = data_cnt; if(!flipper_format_read_hex(file, "UID", data->uid, data->uid_len)) break; - if(dev->format != NfcDeviceSaveFormatNfcV) { + if(dev->format != NfcDeviceOldSaveFormatNfcV) { if(version == version_with_lsb_atqa) { if(!flipper_format_read_hex(file, "ATQA", data->atqa, 2)) break; } else { @@ -1519,16 +1520,16 @@ static bool nfc_device_load_data(NfcDevice* dev, FuriString* path, bool show_dia data->cuid = (cuid_start[0] << 24) | (cuid_start[1] << 16) | (cuid_start[2] << 8) | (cuid_start[3]); // Parse other data - if(dev->format == NfcDeviceSaveFormatMifareUl) { - if(!nfc_device_load_mifare_ul_data(file, dev)) break; - } else if(dev->format == NfcDeviceSaveFormatMifareClassic) { - if(!nfc_device_load_mifare_classic_data(file, dev)) break; - } else if(dev->format == NfcDeviceSaveFormatMifareDesfire) { - if(!nfc_device_load_mifare_df_data(file, dev)) break; - } else if(dev->format == NfcDeviceSaveFormatNfcV) { - if(!nfc_device_load_nfcv_data(file, dev)) break; - } else if(dev->format == NfcDeviceSaveFormatBankCard) { - if(!nfc_device_load_bank_card_data(file, dev)) break; + if(dev->format == NfcDeviceOldSaveFormatMifareUl) { + if(!nfc_device_old_load_mifare_ul_data(file, dev)) break; + } else if(dev->format == NfcDeviceOldSaveFormatMifareClassic) { + if(!nfc_device_old_load_mifare_classic_data(file, dev)) break; + } else if(dev->format == NfcDeviceOldSaveFormatMifareDesfire) { + if(!nfc_device_old_load_mifare_df_data(file, dev)) break; + } else if(dev->format == NfcDeviceOldSaveFormatNfcV) { + if(!nfc_device_old_load_nfcv_data(file, dev)) break; + } else if(dev->format == NfcDeviceOldSaveFormatBankCard) { + if(!nfc_device_old_load_bank_card_data(file, dev)) break; } parsed = true; } while(false); @@ -1550,26 +1551,26 @@ static bool nfc_device_load_data(NfcDevice* dev, FuriString* path, bool show_dia return parsed; } -bool nfc_device_load(NfcDevice* dev, const char* file_path, bool show_dialog) { +bool nfc_device_old_load(NfcDeviceOld* dev, const char* file_path, bool show_dialog) { furi_assert(dev); furi_assert(file_path); // Load device data furi_string_set(dev->load_path, file_path); - bool dev_load = nfc_device_load_data(dev, dev->load_path, show_dialog); + bool dev_load = nfc_device_old_load_data(dev, dev->load_path, show_dialog); if(dev_load) { // Set device name FuriString* filename; filename = furi_string_alloc(); path_extract_filename_no_ext(file_path, filename); - nfc_device_set_name(dev, furi_string_get_cstr(filename)); + nfc_device_old_set_name(dev, furi_string_get_cstr(filename)); furi_string_free(filename); } return dev_load; } -bool nfc_file_select(NfcDevice* dev) { +bool nfc_file_select(NfcDeviceOld* dev) { furi_assert(dev); const char* folder = furi_string_get_cstr(dev->folder); @@ -1594,9 +1595,9 @@ bool nfc_file_select(NfcDevice* dev) { filename = furi_string_alloc(); path_extract_filename(dev->load_path, filename, true); strncpy(dev->dev_name, furi_string_get_cstr(filename), NFC_DEV_NAME_MAX_LEN); - res = nfc_device_load_data(dev, dev->load_path, true); + res = nfc_device_old_load_data(dev, dev->load_path, true); if(res) { - nfc_device_set_name(dev, dev->dev_name); + nfc_device_old_set_name(dev, dev->dev_name); } furi_string_free(filename); } @@ -1604,31 +1605,31 @@ bool nfc_file_select(NfcDevice* dev) { return res; } -void nfc_device_data_clear(NfcDeviceData* dev_data) { - if(dev_data->protocol == NfcDeviceProtocolMifareDesfire) { +void nfc_device_old_data_clear(NfcDeviceOldDataOld* dev_data) { + if(dev_data->protocol == NfcDeviceOldProtocolMifareDesfire) { mf_df_clear(&dev_data->mf_df_data); - } else if(dev_data->protocol == NfcDeviceProtocolMifareClassic) { + } else if(dev_data->protocol == NfcDeviceOldProtocolMifareClassic) { memset(&dev_data->mf_classic_data, 0, sizeof(MfClassicData)); - } else if(dev_data->protocol == NfcDeviceProtocolMifareUl) { + } else if(dev_data->protocol == NfcDeviceOldProtocolMifareUl) { mf_ul_reset(&dev_data->mf_ul_data); - } else if(dev_data->protocol == NfcDeviceProtocolEMV) { + } else if(dev_data->protocol == NfcDeviceOldProtocolEMV) { memset(&dev_data->emv_data, 0, sizeof(EmvData)); } memset(&dev_data->nfc_data, 0, sizeof(FuriHalNfcDevData)); - dev_data->protocol = NfcDeviceProtocolUnknown; + dev_data->protocol = NfcDeviceOldProtocolUnknown; furi_string_reset(dev_data->parsed_data); } -void nfc_device_clear(NfcDevice* dev) { +void nfc_device_old_clear(NfcDeviceOld* dev) { furi_assert(dev); - nfc_device_set_name(dev, ""); - nfc_device_data_clear(&dev->dev_data); - dev->format = NfcDeviceSaveFormatUid; + nfc_device_old_set_name(dev, ""); + nfc_device_old_data_clear(&dev->dev_data); + dev->format = NfcDeviceOldSaveFormatUid; furi_string_reset(dev->load_path); } -bool nfc_device_delete(NfcDevice* dev, bool use_load_path) { +bool nfc_device_old_delete(NfcDeviceOld* dev, bool use_load_path) { furi_assert(dev); bool deleted = false; @@ -1651,7 +1652,7 @@ bool nfc_device_delete(NfcDevice* dev, bool use_load_path) { // Delete shadow file if it exists if(dev->shadow_file_exist) { if(use_load_path && !furi_string_empty(dev->load_path)) { - nfc_device_get_shadow_path(dev->load_path, file_path); + nfc_device_old_get_shadow_path(dev->load_path, file_path); } else { furi_string_printf( file_path, @@ -1673,7 +1674,7 @@ bool nfc_device_delete(NfcDevice* dev, bool use_load_path) { return deleted; } -bool nfc_device_restore(NfcDevice* dev, bool use_load_path) { +bool nfc_device_old_restore(NfcDeviceOld* dev, bool use_load_path) { furi_assert(dev); furi_assert(dev->shadow_file_exist); @@ -1684,7 +1685,7 @@ bool nfc_device_restore(NfcDevice* dev, bool use_load_path) { do { if(use_load_path && !furi_string_empty(dev->load_path)) { - nfc_device_get_shadow_path(dev->load_path, path); + nfc_device_old_get_shadow_path(dev->load_path, path); } else { furi_string_printf( path, @@ -1705,7 +1706,7 @@ bool nfc_device_restore(NfcDevice* dev, bool use_load_path) { dev->dev_name, NFC_APP_EXTENSION); } - if(!nfc_device_load_data(dev, path, true)) break; + if(!nfc_device_old_load_data(dev, path, true)) break; restored = true; } while(0); @@ -1713,7 +1714,10 @@ bool nfc_device_restore(NfcDevice* dev, bool use_load_path) { return restored; } -void nfc_device_set_loading_callback(NfcDevice* dev, NfcLoadingCallback callback, void* context) { +void nfc_device_old_set_loading_callback( + NfcDeviceOld* dev, + NfcLoadingCallback callback, + void* context) { furi_assert(dev); dev->loading_cb = callback; diff --git a/lib/nfc/deprecated/nfc_device.h b/lib/nfc/deprecated/nfc_device_old.h similarity index 56% rename from lib/nfc/deprecated/nfc_device.h rename to lib/nfc/deprecated/nfc_device_old.h index 8c447213b69b..03424a60bf59 100644 --- a/lib/nfc/deprecated/nfc_device.h +++ b/lib/nfc/deprecated/nfc_device_old.h @@ -27,22 +27,22 @@ extern "C" { typedef void (*NfcLoadingCallback)(void* context, bool state); typedef enum { - NfcDeviceProtocolUnknown, - NfcDeviceProtocolEMV, - NfcDeviceProtocolMifareUl, - NfcDeviceProtocolMifareClassic, - NfcDeviceProtocolMifareDesfire, - NfcDeviceProtocolNfcV -} NfcProtocol; + NfcDeviceOldProtocolUnknown, + NfcDeviceOldProtocolEMV, + NfcDeviceOldProtocolMifareUl, + NfcDeviceOldProtocolMifareClassic, + NfcDeviceOldProtocolMifareDesfire, + NfcDeviceOldProtocolNfcV +} NfcProtocolOld; typedef enum { - NfcDeviceSaveFormatUid, - NfcDeviceSaveFormatBankCard, - NfcDeviceSaveFormatMifareUl, - NfcDeviceSaveFormatMifareClassic, - NfcDeviceSaveFormatMifareDesfire, - NfcDeviceSaveFormatNfcV, -} NfcDeviceSaveFormat; + NfcDeviceOldSaveFormatUid, + NfcDeviceOldSaveFormatBankCard, + NfcDeviceOldSaveFormatMifareUl, + NfcDeviceOldSaveFormatMifareClassic, + NfcDeviceOldSaveFormatMifareDesfire, + NfcDeviceOldSaveFormatNfcV, +} NfcDeviceOldSaveFormat; typedef struct { uint8_t data[NFC_READER_DATA_MAX_SIZE]; @@ -64,7 +64,7 @@ typedef enum { typedef struct { FuriHalNfcDevData nfc_data; - NfcProtocol protocol; + NfcProtocolOld protocol; NfcReadMode read_mode; union { NfcReaderRequestData reader_data; @@ -79,47 +79,50 @@ typedef struct { NfcVData nfcv_data; }; FuriString* parsed_data; -} NfcDeviceData; +} NfcDeviceOldDataOld; typedef struct { Storage* storage; DialogsApp* dialogs; - NfcDeviceData dev_data; + NfcDeviceOldDataOld dev_data; char dev_name[NFC_DEV_NAME_MAX_LEN + 1]; FuriString* load_path; FuriString* folder; - NfcDeviceSaveFormat format; + NfcDeviceOldSaveFormat format; bool shadow_file_exist; NfcLoadingCallback loading_cb; void* loading_cb_ctx; -} NfcDevice; +} NfcDeviceOld; -NfcDevice* nfc_device_alloc(); +NfcDeviceOld* nfc_device_old_alloc(); -void nfc_device_free(NfcDevice* nfc_dev); +void nfc_device_old_free(NfcDeviceOld* nfc_dev); -void nfc_device_set_name(NfcDevice* dev, const char* name); +void nfc_device_old_set_name(NfcDeviceOld* dev, const char* name); -bool nfc_device_save(NfcDevice* dev, const char* dev_name); +bool nfc_device_old_save(NfcDeviceOld* dev, const char* dev_name); -bool nfc_device_save_shadow(NfcDevice* dev, const char* dev_name); +bool nfc_device_old_save_shadow(NfcDeviceOld* dev, const char* dev_name); -bool nfc_device_load(NfcDevice* dev, const char* file_path, bool show_dialog); +bool nfc_device_old_load(NfcDeviceOld* dev, const char* file_path, bool show_dialog); -bool nfc_device_load_key_cache(NfcDevice* dev); +bool nfc_device_old_load_key_cache(NfcDeviceOld* dev); -bool nfc_file_select(NfcDevice* dev); +bool nfc_file_select(NfcDeviceOld* dev); -void nfc_device_data_clear(NfcDeviceData* dev); +void nfc_device_old_data_clear(NfcDeviceOldDataOld* dev); -void nfc_device_clear(NfcDevice* dev); +void nfc_device_old_clear(NfcDeviceOld* dev); -bool nfc_device_delete(NfcDevice* dev, bool use_load_path); +bool nfc_device_old_delete(NfcDeviceOld* dev, bool use_load_path); -bool nfc_device_restore(NfcDevice* dev, bool use_load_path); +bool nfc_device_old_restore(NfcDeviceOld* dev, bool use_load_path); -void nfc_device_set_loading_callback(NfcDevice* dev, NfcLoadingCallback callback, void* context); +void nfc_device_old_set_loading_callback( + NfcDeviceOld* dev, + NfcLoadingCallback callback, + void* context); #ifdef __cplusplus } diff --git a/lib/nfc/deprecated/nfc_types.c b/lib/nfc/deprecated/nfc_types.c index 96b92640f0ec..3a0de7273993 100644 --- a/lib/nfc/deprecated/nfc_types.c +++ b/lib/nfc/deprecated/nfc_types.c @@ -14,14 +14,14 @@ const char* nfc_get_dev_type(FuriHalNfcType type) { } } -const char* nfc_guess_protocol(NfcProtocol protocol) { - if(protocol == NfcDeviceProtocolEMV) { +const char* nfc_guess_protocol(NfcProtocolOld protocol) { + if(protocol == NfcDeviceOldProtocolEMV) { return "EMV bank card"; - } else if(protocol == NfcDeviceProtocolMifareUl) { + } else if(protocol == NfcDeviceOldProtocolMifareUl) { return "Mifare Ultral/NTAG"; - } else if(protocol == NfcDeviceProtocolMifareClassic) { + } else if(protocol == NfcDeviceOldProtocolMifareClassic) { return "Mifare Classic"; - } else if(protocol == NfcDeviceProtocolMifareDesfire) { + } else if(protocol == NfcDeviceOldProtocolMifareDesfire) { return "Mifare DESFire"; } else { return "Unrecognized"; diff --git a/lib/nfc/deprecated/nfc_types.h b/lib/nfc/deprecated/nfc_types.h index fb53ce7c25be..bfe7a4a4ffda 100644 --- a/lib/nfc/deprecated/nfc_types.h +++ b/lib/nfc/deprecated/nfc_types.h @@ -1,10 +1,10 @@ #pragma once -#include "nfc_device.h" +#include "nfc_device_old.h" const char* nfc_get_dev_type(FuriHalNfcType type); -const char* nfc_guess_protocol(NfcProtocol protocol); +const char* nfc_guess_protocol(NfcProtocolOld protocol); const char* nfc_mf_ul_type(MfUltralightType type, bool full_name); diff --git a/lib/nfc/deprecated/nfc_worker.c b/lib/nfc/deprecated/nfc_worker.c index 2b230decaccb..2923e9eac81d 100644 --- a/lib/nfc/deprecated/nfc_worker.c +++ b/lib/nfc/deprecated/nfc_worker.c @@ -48,7 +48,7 @@ NfcWorkerState nfc_worker_get_state(NfcWorker* nfc_worker) { void nfc_worker_start( NfcWorker* nfc_worker, NfcWorkerState state, - NfcDeviceData* dev_data, + NfcDeviceOldDataOld* dev_data, NfcWorkerCallback callback, void* context) { furi_assert(nfc_worker); @@ -247,7 +247,7 @@ void nfc_worker_nfcv_unlock(NfcWorker* nfc_worker) { if(ret == ERR_NONE) { /* there is some chip, responding with a RAND */ - nfc_worker->dev_data->protocol = NfcDeviceProtocolNfcV; + nfc_worker->dev_data->protocol = NfcDeviceOldProtocolNfcV; FURI_LOG_D(TAG, " Chip detected. In privacy?"); ret = nfcv_inventory(NULL); @@ -370,7 +370,7 @@ static bool nfc_worker_read_mf_ultralight(NfcWorker* nfc_worker, FuriHalNfcTxRxC // Try to read supported card FURI_LOG_I(TAG, "Trying to read a supported card ..."); for(size_t i = 0; i < NfcSupportedCardTypeEnd; i++) { - if(nfc_supported_card[i].protocol == NfcDeviceProtocolMifareUl) { + if(nfc_supported_card[i].protocol == NfcDeviceOldProtocolMifareUl) { if(nfc_supported_card[i].verify(nfc_worker, tx_rx)) { if(nfc_supported_card[i].read(nfc_worker, tx_rx)) { read_success = true; @@ -413,7 +413,7 @@ static bool nfc_worker_read_mf_classic(NfcWorker* nfc_worker, FuriHalNfcTxRxCont // Try to read supported card FURI_LOG_I(TAG, "Trying to read a supported card ..."); for(size_t i = 0; i < NfcSupportedCardTypeEnd; i++) { - if(nfc_supported_card[i].protocol == NfcDeviceProtocolMifareClassic) { + if(nfc_supported_card[i].protocol == NfcDeviceOldProtocolMifareClassic) { if(nfc_supported_card[i].verify(nfc_worker, tx_rx)) { if(nfc_supported_card[i].read(nfc_worker, tx_rx)) { read_success = true; @@ -466,7 +466,7 @@ static bool nfc_worker_read_mf_desfire(NfcWorker* nfc_worker, FuriHalNfcTxRxCont // There are fully-protected DESFire cards, but providing keys for them // is difficult (and unnessesary for many transit cards). for(size_t i = 0; i < NfcSupportedCardTypeEnd; i++) { - if(nfc_supported_card[i].protocol == NfcDeviceProtocolMifareDesfire) { + if(nfc_supported_card[i].protocol == NfcDeviceOldProtocolMifareDesfire) { if(nfc_supported_card[i].parse(nfc_worker->dev_data)) break; } } @@ -487,24 +487,24 @@ static bool nfc_worker_read_nfca(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* t furi_hal_nfc_sleep(); if(mf_ul_check_card_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) { FURI_LOG_I(TAG, "Mifare Ultralight / NTAG detected"); - nfc_worker->dev_data->protocol = NfcDeviceProtocolMifareUl; + nfc_worker->dev_data->protocol = NfcDeviceOldProtocolMifareUl; card_read = nfc_worker_read_mf_ultralight(nfc_worker, tx_rx); } else if(mifare_classic_check_card_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) { FURI_LOG_I(TAG, "Mifare Classic detected"); - nfc_worker->dev_data->protocol = NfcDeviceProtocolMifareClassic; + nfc_worker->dev_data->protocol = NfcDeviceOldProtocolMifareClassic; nfc_worker->dev_data->mf_classic_data.type = mifare_classic_get_classic_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak); card_read = nfc_worker_read_mf_classic(nfc_worker, tx_rx); } else if(mf_df_check_card_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) { FURI_LOG_I(TAG, "Mifare DESFire detected"); - nfc_worker->dev_data->protocol = NfcDeviceProtocolMifareDesfire; + nfc_worker->dev_data->protocol = NfcDeviceOldProtocolMifareDesfire; if(!nfc_worker_read_mf_desfire(nfc_worker, tx_rx)) { FURI_LOG_I(TAG, "Unknown card. Save UID"); - nfc_worker->dev_data->protocol = NfcDeviceProtocolUnknown; + nfc_worker->dev_data->protocol = NfcDeviceOldProtocolUnknown; } card_read = true; } else { - nfc_worker->dev_data->protocol = NfcDeviceProtocolUnknown; + nfc_worker->dev_data->protocol = NfcDeviceOldProtocolUnknown; card_read = true; } @@ -515,8 +515,8 @@ void nfc_worker_read(NfcWorker* nfc_worker) { furi_assert(nfc_worker); furi_assert(nfc_worker->callback); - nfc_device_data_clear(nfc_worker->dev_data); - NfcDeviceData* dev_data = nfc_worker->dev_data; + nfc_device_old_data_clear(nfc_worker->dev_data); + NfcDeviceOldDataOld* dev_data = nfc_worker->dev_data; FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; FuriHalNfcTxRxContext tx_rx = {}; NfcWorkerEvent event = 0; @@ -529,21 +529,21 @@ void nfc_worker_read(NfcWorker* nfc_worker) { card_not_detected_notified = false; if(nfc_data->type == FuriHalNfcTypeA) { if(nfc_worker_read_nfca(nfc_worker, &tx_rx)) { - if(dev_data->protocol == NfcDeviceProtocolMifareUl) { + if(dev_data->protocol == NfcDeviceOldProtocolMifareUl) { event = NfcWorkerEventReadMfUltralight; break; - } else if(dev_data->protocol == NfcDeviceProtocolMifareClassic) { + } else if(dev_data->protocol == NfcDeviceOldProtocolMifareClassic) { event = NfcWorkerEventReadMfClassicDone; break; - } else if(dev_data->protocol == NfcDeviceProtocolMifareDesfire) { + } else if(dev_data->protocol == NfcDeviceOldProtocolMifareDesfire) { event = NfcWorkerEventReadMfDesfire; break; - } else if(dev_data->protocol == NfcDeviceProtocolUnknown) { + } else if(dev_data->protocol == NfcDeviceOldProtocolUnknown) { event = NfcWorkerEventReadUidNfcA; break; } } else { - if(dev_data->protocol == NfcDeviceProtocolMifareClassic) { + if(dev_data->protocol == NfcDeviceOldProtocolMifareClassic) { event = NfcWorkerEventReadMfClassicDictAttackRequired; break; } @@ -556,7 +556,7 @@ void nfc_worker_read(NfcWorker* nfc_worker) { break; } else if(nfc_data->type == FuriHalNfcTypeV) { FURI_LOG_I(TAG, "NfcV detected"); - nfc_worker->dev_data->protocol = NfcDeviceProtocolNfcV; + nfc_worker->dev_data->protocol = NfcDeviceOldProtocolNfcV; if(nfc_worker_read_nfcv(nfc_worker, &tx_rx)) { FURI_LOG_I(TAG, "nfc_worker_read_nfcv success"); } @@ -583,8 +583,8 @@ void nfc_worker_read_type(NfcWorker* nfc_worker) { furi_assert(nfc_worker->callback); NfcReadMode read_mode = nfc_worker->dev_data->read_mode; - nfc_device_data_clear(nfc_worker->dev_data); - NfcDeviceData* dev_data = nfc_worker->dev_data; + nfc_device_old_data_clear(nfc_worker->dev_data); + NfcDeviceOldDataOld* dev_data = nfc_worker->dev_data; FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; FuriHalNfcTxRxContext tx_rx = {}; NfcWorkerEvent event = 0; @@ -599,35 +599,35 @@ void nfc_worker_read_type(NfcWorker* nfc_worker) { card_not_detected_notified = false; if(nfc_data->type == FuriHalNfcTypeA) { if(read_mode == NfcReadModeMfClassic) { - nfc_worker->dev_data->protocol = NfcDeviceProtocolMifareClassic; + nfc_worker->dev_data->protocol = NfcDeviceOldProtocolMifareClassic; nfc_worker->dev_data->mf_classic_data.type = mifare_classic_get_classic_type( nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak); if(nfc_worker_read_mf_classic(nfc_worker, &tx_rx)) { FURI_LOG_D(TAG, "Card read"); - dev_data->protocol = NfcDeviceProtocolMifareClassic; + dev_data->protocol = NfcDeviceOldProtocolMifareClassic; event = NfcWorkerEventReadMfClassicDone; break; } else { FURI_LOG_D(TAG, "Card read failed"); - dev_data->protocol = NfcDeviceProtocolMifareClassic; + dev_data->protocol = NfcDeviceOldProtocolMifareClassic; event = NfcWorkerEventReadMfClassicDictAttackRequired; break; } } else if(read_mode == NfcReadModeMfUltralight) { FURI_LOG_I(TAG, "Mifare Ultralight / NTAG"); - nfc_worker->dev_data->protocol = NfcDeviceProtocolMifareUl; + nfc_worker->dev_data->protocol = NfcDeviceOldProtocolMifareUl; if(nfc_worker_read_mf_ultralight(nfc_worker, &tx_rx)) { event = NfcWorkerEventReadMfUltralight; break; } } else if(read_mode == NfcReadModeMfDesfire) { - nfc_worker->dev_data->protocol = NfcDeviceProtocolMifareDesfire; + nfc_worker->dev_data->protocol = NfcDeviceOldProtocolMifareDesfire; if(nfc_worker_read_mf_desfire(nfc_worker, &tx_rx)) { event = NfcWorkerEventReadMfDesfire; break; } } else if(read_mode == NfcReadModeNFCA) { - nfc_worker->dev_data->protocol = NfcDeviceProtocolUnknown; + nfc_worker->dev_data->protocol = NfcDeviceOldProtocolUnknown; event = NfcWorkerEventReadUidNfcA; break; } @@ -1268,7 +1268,7 @@ void nfc_worker_analyze_reader(NfcWorker* nfc_worker) { ReaderAnalyzer* reader_analyzer = nfc_worker->reader_analyzer; FuriHalNfcDevData* nfc_data = NULL; - if(nfc_worker->dev_data->protocol == NfcDeviceProtocolMifareClassic) { + if(nfc_worker->dev_data->protocol == NfcDeviceOldProtocolMifareClassic) { nfc_data = &nfc_worker->dev_data->nfc_data; reader_analyzer_set_nfc_data(reader_analyzer, nfc_data); } else { @@ -1302,9 +1302,9 @@ void nfc_worker_analyze_reader(NfcWorker* nfc_worker) { } reader_no_data_received_cnt = 0; reader_no_data_notified = false; - NfcProtocol protocol = + NfcProtocolOld protocol = reader_analyzer_guess_protocol(reader_analyzer, tx_rx.rx_data, tx_rx.rx_bits / 8); - if(protocol == NfcDeviceProtocolMifareClassic) { + if(protocol == NfcDeviceOldProtocolMifareClassic) { mifare_classic_emulator(&emulator, &tx_rx, true); } } else { diff --git a/lib/nfc/deprecated/nfc_worker.h b/lib/nfc/deprecated/nfc_worker.h index 722f148574f2..5243c338b7a9 100644 --- a/lib/nfc/deprecated/nfc_worker.h +++ b/lib/nfc/deprecated/nfc_worker.h @@ -1,6 +1,6 @@ #pragma once -#include "nfc_device.h" +#include "nfc_device_old.h" typedef struct NfcWorker NfcWorker; @@ -90,7 +90,7 @@ void nfc_worker_free(NfcWorker* nfc_worker); void nfc_worker_start( NfcWorker* nfc_worker, NfcWorkerState state, - NfcDeviceData* dev_data, + NfcDeviceOldDataOld* dev_data, NfcWorkerCallback callback, void* context); diff --git a/lib/nfc/deprecated/nfc_worker_i.h b/lib/nfc/deprecated/nfc_worker_i.h index 9e5fe5e3178b..2b51f7af8f41 100644 --- a/lib/nfc/deprecated/nfc_worker_i.h +++ b/lib/nfc/deprecated/nfc_worker_i.h @@ -19,7 +19,7 @@ struct NfcWorker { Storage* storage; Stream* dict_stream; - NfcDeviceData* dev_data; + NfcDeviceOldDataOld* dev_data; NfcWorkerCallback callback; void* context; diff --git a/lib/nfc/deprecated/parsers/all_in_one.c b/lib/nfc/deprecated/parsers/all_in_one.c index b309d240bbba..17cf6fcf859b 100644 --- a/lib/nfc/deprecated/parsers/all_in_one.c +++ b/lib/nfc/deprecated/parsers/all_in_one.c @@ -14,7 +14,7 @@ #define ALL_IN_ONE_LAYOUT_E5 5 #define ALL_IN_ONE_LAYOUT_2 6 -uint8_t all_in_one_get_layout(NfcDeviceData* dev_data) { +uint8_t all_in_one_get_layout(NfcDeviceOldDataOld* dev_data) { // I absolutely hate what's about to happen here. // Switch on the second half of the third byte of page 5 @@ -67,7 +67,7 @@ bool all_in_one_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) } } -bool all_in_one_parser_parse(NfcDeviceData* dev_data) { +bool all_in_one_parser_parse(NfcDeviceOldDataOld* dev_data) { if(dev_data->mf_ul_data.data[4 * 4] != 0x45 || dev_data->mf_ul_data.data[4 * 4 + 1] != 0xD9) { FURI_LOG_I("all_in_one", "Pass not verified"); return false; diff --git a/lib/nfc/deprecated/parsers/all_in_one.h b/lib/nfc/deprecated/parsers/all_in_one.h index 9b646d4dc300..967ccc334044 100644 --- a/lib/nfc/deprecated/parsers/all_in_one.h +++ b/lib/nfc/deprecated/parsers/all_in_one.h @@ -6,4 +6,4 @@ bool all_in_one_parser_verify(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_r bool all_in_one_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx); -bool all_in_one_parser_parse(NfcDeviceData* dev_data); \ No newline at end of file +bool all_in_one_parser_parse(NfcDeviceOldDataOld* dev_data); \ No newline at end of file diff --git a/lib/nfc/deprecated/parsers/nfc_supported_card.c b/lib/nfc/deprecated/parsers/nfc_supported_card.c index 153d4d3c511a..e8be829bf511 100644 --- a/lib/nfc/deprecated/parsers/nfc_supported_card.c +++ b/lib/nfc/deprecated/parsers/nfc_supported_card.c @@ -11,49 +11,49 @@ NfcSupportedCard nfc_supported_card[NfcSupportedCardTypeEnd] = { [NfcSupportedCardTypePlantain] = { - .protocol = NfcDeviceProtocolMifareClassic, + .protocol = NfcDeviceOldProtocolMifareClassic, .verify = plantain_parser_verify, .read = plantain_parser_read, .parse = plantain_parser_parse, }, [NfcSupportedCardTypeTroika] = { - .protocol = NfcDeviceProtocolMifareClassic, + .protocol = NfcDeviceOldProtocolMifareClassic, .verify = troika_parser_verify, .read = troika_parser_read, .parse = troika_parser_parse, }, [NfcSupportedCardTypePlantain4K] = { - .protocol = NfcDeviceProtocolMifareClassic, + .protocol = NfcDeviceOldProtocolMifareClassic, .verify = plantain_4k_parser_verify, .read = plantain_4k_parser_read, .parse = plantain_4k_parser_parse, }, [NfcSupportedCardTypeTroika4K] = { - .protocol = NfcDeviceProtocolMifareClassic, + .protocol = NfcDeviceOldProtocolMifareClassic, .verify = troika_4k_parser_verify, .read = troika_4k_parser_read, .parse = troika_4k_parser_parse, }, [NfcSupportedCardTypeTwoCities] = { - .protocol = NfcDeviceProtocolMifareClassic, + .protocol = NfcDeviceOldProtocolMifareClassic, .verify = two_cities_parser_verify, .read = two_cities_parser_read, .parse = two_cities_parser_parse, }, [NfcSupportedCardTypeAllInOne] = { - .protocol = NfcDeviceProtocolMifareUl, + .protocol = NfcDeviceOldProtocolMifareUl, .verify = all_in_one_parser_verify, .read = all_in_one_parser_read, .parse = all_in_one_parser_parse, }, [NfcSupportedCardTypeOpal] = { - .protocol = NfcDeviceProtocolMifareDesfire, + .protocol = NfcDeviceOldProtocolMifareDesfire, .verify = stub_parser_verify_read, .read = stub_parser_verify_read, .parse = opal_parser_parse, @@ -61,7 +61,7 @@ NfcSupportedCard nfc_supported_card[NfcSupportedCardTypeEnd] = { }; -bool nfc_supported_card_verify_and_parse(NfcDeviceData* dev_data) { +bool nfc_supported_card_verify_and_parse(NfcDeviceOldDataOld* dev_data) { furi_assert(dev_data); bool card_parsed = false; diff --git a/lib/nfc/deprecated/parsers/nfc_supported_card.h b/lib/nfc/deprecated/parsers/nfc_supported_card.h index 877bda737452..6c739100d38d 100644 --- a/lib/nfc/deprecated/parsers/nfc_supported_card.h +++ b/lib/nfc/deprecated/parsers/nfc_supported_card.h @@ -2,7 +2,7 @@ #include #include "../nfc_worker.h" -#include "../nfc_device.h" +#include "../nfc_device_old.h" typedef enum { NfcSupportedCardTypePlantain, @@ -20,10 +20,10 @@ typedef bool (*NfcSupportedCardVerify)(NfcWorker* nfc_worker, FuriHalNfcTxRxCont typedef bool (*NfcSupportedCardRead)(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx); -typedef bool (*NfcSupportedCardParse)(NfcDeviceData* dev_data); +typedef bool (*NfcSupportedCardParse)(NfcDeviceOldDataOld* dev_data); typedef struct { - NfcProtocol protocol; + NfcProtocolOld protocol; NfcSupportedCardVerify verify; NfcSupportedCardRead read; NfcSupportedCardParse parse; @@ -31,7 +31,7 @@ typedef struct { extern NfcSupportedCard nfc_supported_card[NfcSupportedCardTypeEnd]; -bool nfc_supported_card_verify_and_parse(NfcDeviceData* dev_data); +bool nfc_supported_card_verify_and_parse(NfcDeviceOldDataOld* dev_data); // stub_parser_verify_read does nothing, and always reports that it does not // support the card. This is needed for DESFire card parsers which can't diff --git a/lib/nfc/deprecated/parsers/opal.c b/lib/nfc/deprecated/parsers/opal.c index 9cd18c63e5a5..ff1cd670c99c 100644 --- a/lib/nfc/deprecated/parsers/opal.c +++ b/lib/nfc/deprecated/parsers/opal.c @@ -112,8 +112,8 @@ void opal_date_time_to_furi(uint16_t days, uint16_t minutes, FuriHalRtcDateTime* out->day = days; } -bool opal_parser_parse(NfcDeviceData* dev_data) { - if(dev_data->protocol != NfcDeviceProtocolMifareDesfire) { +bool opal_parser_parse(NfcDeviceOldDataOld* dev_data) { + if(dev_data->protocol != NfcDeviceOldProtocolMifareDesfire) { return false; } diff --git a/lib/nfc/deprecated/parsers/opal.h b/lib/nfc/deprecated/parsers/opal.h index 42caf9a1790a..d48b37aa7647 100644 --- a/lib/nfc/deprecated/parsers/opal.h +++ b/lib/nfc/deprecated/parsers/opal.h @@ -2,4 +2,4 @@ #include "nfc_supported_card.h" -bool opal_parser_parse(NfcDeviceData* dev_data); +bool opal_parser_parse(NfcDeviceOldDataOld* dev_data); diff --git a/lib/nfc/deprecated/parsers/plantain_4k_parser.c b/lib/nfc/deprecated/parsers/plantain_4k_parser.c index 092450e8515c..252f2ef2a27c 100644 --- a/lib/nfc/deprecated/parsers/plantain_4k_parser.c +++ b/lib/nfc/deprecated/parsers/plantain_4k_parser.c @@ -90,7 +90,7 @@ bool plantain_4k_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx return false; } -bool plantain_4k_parser_parse(NfcDeviceData* dev_data) { +bool plantain_4k_parser_parse(NfcDeviceOldDataOld* dev_data) { MfClassicData* data = &dev_data->mf_classic_data; // Verify key diff --git a/lib/nfc/deprecated/parsers/plantain_4k_parser.h b/lib/nfc/deprecated/parsers/plantain_4k_parser.h index 29998af15ea3..ef1308d151d8 100644 --- a/lib/nfc/deprecated/parsers/plantain_4k_parser.h +++ b/lib/nfc/deprecated/parsers/plantain_4k_parser.h @@ -6,4 +6,4 @@ bool plantain_4k_parser_verify(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_ bool plantain_4k_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx); -bool plantain_4k_parser_parse(NfcDeviceData* dev_data); +bool plantain_4k_parser_parse(NfcDeviceOldDataOld* dev_data); diff --git a/lib/nfc/deprecated/parsers/plantain_parser.c b/lib/nfc/deprecated/parsers/plantain_parser.c index b29fadfdf6c4..d2e091dde8b3 100644 --- a/lib/nfc/deprecated/parsers/plantain_parser.c +++ b/lib/nfc/deprecated/parsers/plantain_parser.c @@ -62,7 +62,7 @@ uint8_t plantain_calculate_luhn(uint64_t number) { return 0; } -bool plantain_parser_parse(NfcDeviceData* dev_data) { +bool plantain_parser_parse(NfcDeviceOldDataOld* dev_data) { MfClassicData* data = &dev_data->mf_classic_data; // Verify key diff --git a/lib/nfc/deprecated/parsers/plantain_parser.h b/lib/nfc/deprecated/parsers/plantain_parser.h index 1af8c50657aa..a7347aa595c1 100644 --- a/lib/nfc/deprecated/parsers/plantain_parser.h +++ b/lib/nfc/deprecated/parsers/plantain_parser.h @@ -6,6 +6,6 @@ bool plantain_parser_verify(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) bool plantain_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx); -bool plantain_parser_parse(NfcDeviceData* dev_data); +bool plantain_parser_parse(NfcDeviceOldDataOld* dev_data); uint8_t plantain_calculate_luhn(uint64_t number); diff --git a/lib/nfc/deprecated/parsers/troika_4k_parser.c b/lib/nfc/deprecated/parsers/troika_4k_parser.c index 5f874a95fc91..00e69fcc3803 100644 --- a/lib/nfc/deprecated/parsers/troika_4k_parser.c +++ b/lib/nfc/deprecated/parsers/troika_4k_parser.c @@ -78,7 +78,7 @@ bool troika_4k_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) return mifare_classic_read_card(tx_rx, &reader, &nfc_worker->dev_data->mf_classic_data) == 40; } -bool troika_4k_parser_parse(NfcDeviceData* dev_data) { +bool troika_4k_parser_parse(NfcDeviceOldDataOld* dev_data) { MfClassicData* data = &dev_data->mf_classic_data; // Verify key diff --git a/lib/nfc/deprecated/parsers/troika_4k_parser.h b/lib/nfc/deprecated/parsers/troika_4k_parser.h index c1d6f01d3aa9..36e814a7ad88 100644 --- a/lib/nfc/deprecated/parsers/troika_4k_parser.h +++ b/lib/nfc/deprecated/parsers/troika_4k_parser.h @@ -6,4 +6,4 @@ bool troika_4k_parser_verify(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx bool troika_4k_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx); -bool troika_4k_parser_parse(NfcDeviceData* dev_data); +bool troika_4k_parser_parse(NfcDeviceOldDataOld* dev_data); diff --git a/lib/nfc/deprecated/parsers/troika_parser.c b/lib/nfc/deprecated/parsers/troika_parser.c index fd1210ca9383..96b83778d564 100644 --- a/lib/nfc/deprecated/parsers/troika_parser.c +++ b/lib/nfc/deprecated/parsers/troika_parser.c @@ -55,7 +55,7 @@ bool troika_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) { return mifare_classic_read_card(tx_rx, &reader, &nfc_worker->dev_data->mf_classic_data) == 16; } -bool troika_parser_parse(NfcDeviceData* dev_data) { +bool troika_parser_parse(NfcDeviceOldDataOld* dev_data) { MfClassicData* data = &dev_data->mf_classic_data; bool troika_parsed = false; diff --git a/lib/nfc/deprecated/parsers/troika_parser.h b/lib/nfc/deprecated/parsers/troika_parser.h index 2aae48d29a5a..f91e3b8f46d7 100644 --- a/lib/nfc/deprecated/parsers/troika_parser.h +++ b/lib/nfc/deprecated/parsers/troika_parser.h @@ -6,4 +6,4 @@ bool troika_parser_verify(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx); bool troika_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx); -bool troika_parser_parse(NfcDeviceData* dev_data); +bool troika_parser_parse(NfcDeviceOldDataOld* dev_data); diff --git a/lib/nfc/deprecated/parsers/two_cities.c b/lib/nfc/deprecated/parsers/two_cities.c index 355995e4fb1c..0491452f442c 100644 --- a/lib/nfc/deprecated/parsers/two_cities.c +++ b/lib/nfc/deprecated/parsers/two_cities.c @@ -86,7 +86,7 @@ bool two_cities_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) return mifare_classic_read_card(tx_rx, &reader, &nfc_worker->dev_data->mf_classic_data) == 40; } -bool two_cities_parser_parse(NfcDeviceData* dev_data) { +bool two_cities_parser_parse(NfcDeviceOldDataOld* dev_data) { MfClassicData* data = &dev_data->mf_classic_data; // Verify key diff --git a/lib/nfc/deprecated/parsers/two_cities.h b/lib/nfc/deprecated/parsers/two_cities.h index e735bea8e1a2..d7ea9cd249a8 100644 --- a/lib/nfc/deprecated/parsers/two_cities.h +++ b/lib/nfc/deprecated/parsers/two_cities.h @@ -6,4 +6,4 @@ bool two_cities_parser_verify(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_r bool two_cities_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx); -bool two_cities_parser_parse(NfcDeviceData* dev_data); +bool two_cities_parser_parse(NfcDeviceOldDataOld* dev_data); diff --git a/lib/nfc/helpers/nfc_data_generator.c b/lib/nfc/helpers/nfc_data_generator.c index 7474634fbabf..3f02784c73e4 100644 --- a/lib/nfc/helpers/nfc_data_generator.c +++ b/lib/nfc/helpers/nfc_data_generator.c @@ -8,7 +8,7 @@ #define NXP_MANUFACTURER_ID (0x04) -typedef void (*NfcDataGeneratorHandler)(NfcProtocolData* data); +typedef void (*NfcDataGeneratorHandler)(NfcDeviceData* data); typedef struct { const char* name; @@ -25,8 +25,8 @@ typedef struct { // static const uint8_t default_data_ntag_i2c[] = {0xE1, 0x10, 0x00, 0x00, 0x03, 0x00, 0xFE}; // static const uint8_t default_config_ntag_i2c[] = {0x01, 0x00, 0xF8, 0x48, 0x08, 0x01, 0x00, 0x00}; // -// static void nfc_generate_common_start(NfcProtocolData* data) { -// memset(data, 0, sizeof(NfcProtocolData)); +// static void nfc_generate_common_start(NfcDeviceData* data) { +// memset(data, 0, sizeof(NfcDeviceData)); // } // static void nfc_generate_mf_ul_uid(uint8_t* uid) { @@ -37,7 +37,7 @@ typedef struct { // uid[6] |= 0x80; // } -// static void nfc_generate_mf_ul_common(NfcProtocolData* data) { +// static void nfc_generate_mf_ul_common(NfcDeviceData* data) { // MfUltralightData* mfu_data = data->mf_ul_data; // mfu_data->nfca_data->uid_len = 7; // nfc_generate_mf_ul_uid(mfu_data->nfca_data->uid); @@ -52,7 +52,7 @@ typedef struct { // *bcc1 = uid[3] ^ uid[4] ^ uid[5] ^ uid[6]; // } -// static void nfc_generate_mf_ul_copy_uid_with_bcc(NfcProtocolData* data) { +// static void nfc_generate_mf_ul_copy_uid_with_bcc(NfcDeviceData* data) { // MfUltralightData* mfu_data = data->mf_ul_data; // memcpy(mfu_data->page[0].data, mfu_data->nfca_data->uid, 3); // memcpy(mfu_data->page[1].data, &mfu_data->nfca_data->uid[3], 4); @@ -61,7 +61,7 @@ typedef struct { // mfu_data->nfca_data->uid, &mfu_data->page[0].data[3], &mfu_data->page[2].data[0]); // } -static void nfc_generate_mf_ul_orig(NfcProtocolData* data) { +static void nfc_generate_mf_ul_orig(NfcDeviceData* data) { UNUSED(data); // nfc_generate_common_start(data); // nfc_generate_mf_ul_common(data); @@ -75,7 +75,7 @@ static void nfc_generate_mf_ul_orig(NfcProtocolData* data) { // memset(&mfu_data->page[4], 0xff, sizeof(MfUltralightPage)); } -// static void nfc_generate_mf_ul_with_config_common(NfcProtocolData* data, uint8_t num_pages) { +// static void nfc_generate_mf_ul_with_config_common(NfcDeviceData* data, uint8_t num_pages) { // nfc_generate_common_start(data); // nfc_generate_mf_ul_common(data); @@ -93,7 +93,7 @@ static void nfc_generate_mf_ul_orig(NfcProtocolData* data) { // } // } -// static void nfc_generate_mf_ul_ev1_common(NfcProtocolData* data, uint8_t num_pages) { +// static void nfc_generate_mf_ul_ev1_common(NfcDeviceData* data, uint8_t num_pages) { // nfc_generate_mf_ul_with_config_common(data, num_pages); // MfUltralightData* mfu_data = data->mf_ul_data; // memcpy(&mfu_data->version, version_bytes_mf0ulx1, sizeof(MfUltralightVersion)); @@ -103,7 +103,7 @@ static void nfc_generate_mf_ul_orig(NfcProtocolData* data) { // TODO: what's internal byte on page 2? // } -static void nfc_generate_mf_ul_11(NfcProtocolData* data) { +static void nfc_generate_mf_ul_11(NfcDeviceData* data) { UNUSED(data); // nfc_generate_mf_ul_ev1_common(data, 20); // MfUltralightData* mfu_data = data->mf_ul_data; @@ -113,7 +113,7 @@ static void nfc_generate_mf_ul_11(NfcProtocolData* data) { // mfu_data->page[16].data[0] = 0x00; // Low capacitance version does not have STRG_MOD_EN } -static void nfc_generate_mf_ul_h11(NfcProtocolData* data) { +static void nfc_generate_mf_ul_h11(NfcDeviceData* data) { UNUSED(data); // nfc_generate_mf_ul_ev1_common(data, 20); // MfUltralightData* mfu_data = data->mf_ul_data; @@ -122,7 +122,7 @@ static void nfc_generate_mf_ul_h11(NfcProtocolData* data) { // mfu_data->version.storage_size = 0x0B; } -static void nfc_generate_mf_ul_21(NfcProtocolData* data) { +static void nfc_generate_mf_ul_21(NfcDeviceData* data) { UNUSED(data); // nfc_generate_mf_ul_ev1_common(data, 41); // MfUltralightData* mfu_data = data->mf_ul_data; @@ -132,7 +132,7 @@ static void nfc_generate_mf_ul_21(NfcProtocolData* data) { // mfu_data->page[37].data[0] = 0x00; // Low capacitance version does not have STRG_MOD_EN } -static void nfc_generate_mf_ul_h21(NfcProtocolData* data) { +static void nfc_generate_mf_ul_h21(NfcDeviceData* data) { UNUSED(data); // nfc_generate_mf_ul_ev1_common(data, 41); // MfUltralightData* mfu_data = data->mf_ul_data; @@ -141,7 +141,7 @@ static void nfc_generate_mf_ul_h21(NfcProtocolData* data) { // mfu_data->version.storage_size = 0x0E; } -static void nfc_generate_ntag203(NfcProtocolData* data) { +static void nfc_generate_ntag203(NfcDeviceData* data) { UNUSED(data); // nfc_generate_common_start(data); // nfc_generate_mf_ul_common(data); @@ -155,7 +155,7 @@ static void nfc_generate_ntag203(NfcProtocolData* data) { // memcpy(&mfu_data->page[3], default_data_ntag203, sizeof(MfUltralightPage)); } -// static void nfc_generate_ntag21x_common(NfcProtocolData* data, uint8_t num_pages) { +// static void nfc_generate_ntag21x_common(NfcDeviceData* data, uint8_t num_pages) { // nfc_generate_mf_ul_with_config_common(data, num_pages); // MfUltralightData* mfu_data = data->mf_ul_data; // memcpy(&mfu_data->version, version_bytes_ntag21x, sizeof(MfUltralightVersion)); @@ -165,7 +165,7 @@ static void nfc_generate_ntag203(NfcProtocolData* data) { // mfu_data->page[3].data[1] = 0x10; // } -static void nfc_generate_ntag213(NfcProtocolData* data) { +static void nfc_generate_ntag213(NfcDeviceData* data) { UNUSED(data); // nfc_generate_ntag21x_common(data, 45); // MfUltralightData* mfu_data = data->mf_ul_data; @@ -176,7 +176,7 @@ static void nfc_generate_ntag213(NfcProtocolData* data) { // memcpy(&mfu_data->page[4], default_data_ntag213, sizeof(default_data_ntag213)); } -static void nfc_generate_ntag215(NfcProtocolData* data) { +static void nfc_generate_ntag215(NfcDeviceData* data) { UNUSED(data); // nfc_generate_ntag21x_common(data, 135); // MfUltralightData* mfu_data = data->mf_ul_data; @@ -187,7 +187,7 @@ static void nfc_generate_ntag215(NfcProtocolData* data) { // memcpy(&mfu_data->page[4], default_data_ntag215_216, sizeof(default_data_ntag215_216)); } -static void nfc_generate_ntag216(NfcProtocolData* data) { +static void nfc_generate_ntag216(NfcDeviceData* data) { UNUSED(data); // nfc_generate_ntag21x_common(data, 231); // MfUltralightData* mfu_data = data->mf_ul_data; @@ -199,7 +199,7 @@ static void nfc_generate_ntag216(NfcProtocolData* data) { } // static void -// nfc_generate_ntag_i2c_common(NfcProtocolData* data, MfUltralightType type, uint16_t num_pages) { +// nfc_generate_ntag_i2c_common(NfcDeviceData* data, MfUltralightType type, uint16_t num_pages) { // nfc_generate_common_start(data); // nfc_generate_mf_ul_common(data); @@ -246,7 +246,7 @@ static void nfc_generate_ntag216(NfcProtocolData* data) { // sizeof(default_config_ntag_i2c)); // } -static void nfc_generate_ntag_i2c_1k(NfcProtocolData* data) { +static void nfc_generate_ntag_i2c_1k(NfcDeviceData* data) { UNUSED(data); // nfc_generate_ntag_i2c_common(data, MfUltralightTypeNTAGI2C1K, 231); // MfUltralightData* mfu_data = data->mf_ul_data; @@ -257,7 +257,7 @@ static void nfc_generate_ntag_i2c_1k(NfcProtocolData* data) { // mfu_data->page[3].data[2] = 0x6D; // Size of tag in CC } -static void nfc_generate_ntag_i2c_2k(NfcProtocolData* data) { +static void nfc_generate_ntag_i2c_2k(NfcDeviceData* data) { UNUSED(data); // nfc_generate_ntag_i2c_common(data, MfUltralightTypeNTAGI2C2K, 485); // MfUltralightData* mfu_data = data->mf_ul_data; @@ -269,7 +269,7 @@ static void nfc_generate_ntag_i2c_2k(NfcProtocolData* data) { } // static void -// nfc_generate_ntag_i2c_plus_common(NfcProtocolData* data, MfUltralightType type, uint16_t num_pages) { +// nfc_generate_ntag_i2c_plus_common(NfcDeviceData* data, MfUltralightType type, uint16_t num_pages) { // nfc_generate_ntag_i2c_common(data, type, num_pages); // // MfUltralightData* mfu_data = data->mf_ul_data; @@ -279,7 +279,7 @@ static void nfc_generate_ntag_i2c_2k(NfcProtocolData* data) { // memset(&mfu_data->page[config_index + 2], 0xFF, sizeof(MfUltralightPage)); // Default PWD // } -static void nfc_generate_ntag_i2c_plus_1k(NfcProtocolData* data) { +static void nfc_generate_ntag_i2c_plus_1k(NfcDeviceData* data) { UNUSED(data); // nfc_generate_ntag_i2c_plus_common(data, MfUltralightTypeNTAGI2CPlus1K, 236); // MfUltralightData* mfu_data = data->mf_ul_data; @@ -287,7 +287,7 @@ static void nfc_generate_ntag_i2c_plus_1k(NfcProtocolData* data) { // mfu_data->version.storage_size = 0x13; } -static void nfc_generate_ntag_i2c_plus_2k(NfcProtocolData* data) { +static void nfc_generate_ntag_i2c_plus_2k(NfcDeviceData* data) { UNUSED(data); // nfc_generate_ntag_i2c_plus_common(data, MfUltralightTypeNTAGI2CPlus2K, 492); // MfUltralightData* mfu_data = data->mf_ul_data; @@ -354,7 +354,7 @@ static void nfc_generate_ntag_i2c_plus_2k(NfcProtocolData* data) { // } // } -// static void nfc_generate_mf_classic(NfcProtocolData* data, uint8_t uid_len, MfClassicType type) { +// static void nfc_generate_mf_classic(NfcDeviceData* data, uint8_t uid_len, MfClassicType type) { // nfc_generate_common_start(data); // data->protocol = NfcDevProtocolMfClassic; // MfClassicData* mfc_data = data->mf_classic_data; @@ -418,27 +418,27 @@ static void nfc_generate_ntag_i2c_plus_2k(NfcProtocolData* data) { // mfc_data->type = type; // } -static void nfc_generate_mf_classic_mini(NfcProtocolData* data) { +static void nfc_generate_mf_classic_mini(NfcDeviceData* data) { UNUSED(data); // nfc_generate_mf_classic(data, 4, MfClassicTypeMini); } -static void nfc_generate_mf_classic_1k_4b_uid(NfcProtocolData* data) { +static void nfc_generate_mf_classic_1k_4b_uid(NfcDeviceData* data) { UNUSED(data); // nfc_generate_mf_classic(data, 4, MfClassicType1k); } -static void nfc_generate_mf_classic_1k_7b_uid(NfcProtocolData* data) { +static void nfc_generate_mf_classic_1k_7b_uid(NfcDeviceData* data) { UNUSED(data); // nfc_generate_mf_classic(data, 7, MfClassicType1k); } -static void nfc_generate_mf_classic_4k_4b_uid(NfcProtocolData* data) { +static void nfc_generate_mf_classic_4k_4b_uid(NfcDeviceData* data) { UNUSED(data); // nfc_generate_mf_classic(data, 4, MfClassicType4k); } -static void nfc_generate_mf_classic_4k_7b_uid(NfcProtocolData* data) { +static void nfc_generate_mf_classic_4k_7b_uid(NfcDeviceData* data) { UNUSED(data); // nfc_generate_mf_classic(data, 7, MfClassicType4k); } @@ -540,6 +540,6 @@ const char* nfc_data_generator_get_name(NfcDataGeneratorType type) { return nfc_data_generator[type].name; } -void nfc_data_generator_fill_data(NfcDataGeneratorType type, NfcProtocolData* data) { +void nfc_data_generator_fill_data(NfcDataGeneratorType type, NfcDeviceData* data) { nfc_data_generator[type].handler(data); } diff --git a/lib/nfc/helpers/nfc_data_generator.h b/lib/nfc/helpers/nfc_data_generator.h index fc114322dc43..d1f24f30b04b 100644 --- a/lib/nfc/helpers/nfc_data_generator.h +++ b/lib/nfc/helpers/nfc_data_generator.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #ifdef __cplusplus extern "C" { @@ -33,7 +33,7 @@ typedef enum { const char* nfc_data_generator_get_name(NfcDataGeneratorType type); -void nfc_data_generator_fill_data(NfcDataGeneratorType type, NfcProtocolData* data); +void nfc_data_generator_fill_data(NfcDataGeneratorType type, NfcDeviceData* data); #ifdef __cplusplus } diff --git a/lib/nfc/nfc.c b/lib/nfc/nfc.c index 5b591dbc2e40..f8bf2dc79800 100644 --- a/lib/nfc/nfc.c +++ b/lib/nfc/nfc.c @@ -248,11 +248,11 @@ void nfc_config(Nfc* instance, NfcMode mode) { if(mode == NfcModeIdle) { f_hal_nfc_reset_mode(); instance->config_state = NfcConfigurationStateIdle; - } else if(mode == NfcModeNfcaPoller) { - f_hal_nfc_set_mode(FHalNfcModeNfcaPoller, FHalNfcBitrate106); + } else if(mode == NfcModeIso14443_3aPoller) { + f_hal_nfc_set_mode(FHalNfcModeIso14443_3aPoller, FHalNfcBitrate106); instance->config_state = NfcConfigurationStateDone; - } else if(mode == NfcModeNfcaListener) { - f_hal_nfc_set_mode(FHalNfcModeNfcaListener, FHalNfcBitrate106); + } else if(mode == NfcModeIso14443_3aListener) { + f_hal_nfc_set_mode(FHalNfcModeIso14443_3aListener, FHalNfcBitrate106); instance->config_state = NfcConfigurationStateDone; } } diff --git a/lib/nfc/nfc.h b/lib/nfc/nfc.h index 0d9d443fa3fc..0c26e3b6cd1d 100644 --- a/lib/nfc/nfc.h +++ b/lib/nfc/nfc.h @@ -44,8 +44,8 @@ typedef NfcCommand (*NfcEventCallback)(NfcEvent event, void* context); typedef enum { NfcModeIdle, - NfcModeNfcaPoller, - NfcModeNfcaListener, + NfcModeIso14443_3aPoller, + NfcModeIso14443_3aListener, NfcModeNfcbPoller, NfcModeNfcbListener, NfcModeNfcfPoller, diff --git a/lib/nfc/nfc_dev.h b/lib/nfc/nfc_dev.h deleted file mode 100644 index a7dba5ecf3c1..000000000000 --- a/lib/nfc/nfc_dev.h +++ /dev/null @@ -1,52 +0,0 @@ -#pragma once - -#include - -#include "protocols/nfc_protocol_defs.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct NfcDev NfcDev; - -typedef void (*NfcLoadingCallback)(void* context, bool state); - -NfcDev* nfc_dev_alloc(); - -void nfc_dev_free(NfcDev* instance); - -void nfc_dev_clear(NfcDev* instance); - -void nfc_dev_reset(NfcDev* instance); - -NfcProtocolType nfc_dev_get_protocol_type(const NfcDev* instance); - -const NfcProtocolData* - nfc_dev_get_protocol_data(const NfcDev* instance, NfcProtocolType protocol_type); - -const char* nfc_dev_get_protocol_name(NfcProtocolType protocol); - -const char* nfc_dev_get_device_name(const NfcDev* instance, NfcProtocolNameType name_type); - -const uint8_t* nfc_dev_get_uid(const NfcDev* instance, size_t* uid_len); - -void nfc_dev_set_protocol_data( - NfcDev* instance, - NfcProtocolType protocol_type, - const NfcProtocolData* protocol_data); - -void nfc_dev_copy_protocol_data( - const NfcDev* instance, - NfcProtocolType protocol_type, - NfcProtocolData* protocol_data); - -void nfc_dev_set_loading_callback(NfcDev* instance, NfcLoadingCallback callback, void* context); - -bool nfc_dev_save(NfcDev* instance, const char* path); - -bool nfc_dev_load(NfcDev* instance, const char* path); - -#ifdef __cplusplus -} -#endif diff --git a/lib/nfc/nfc_dev.c b/lib/nfc/nfc_device.c similarity index 52% rename from lib/nfc/nfc_dev.c rename to lib/nfc/nfc_device.c index 7b89c9bb57d2..95a1cb361170 100644 --- a/lib/nfc/nfc_dev.c +++ b/lib/nfc/nfc_device.c @@ -1,4 +1,4 @@ -#include "nfc_dev.h" +#include "nfc_device.h" #include #include @@ -7,115 +7,116 @@ #define NFC_FILE_HEADER "Flipper NFC device" #define NFC_DEV_TYPE_ERROR "Protocol type mismatch" -struct NfcDev { - NfcProtocolType protocol_type; - NfcProtocolData* protocol_data; +struct NfcDevice { + NfcProtocol protocol; + NfcDeviceData* protocol_data; NfcLoadingCallback loading_callback; void* loading_callback_context; }; -NfcDev* nfc_dev_alloc() { - NfcDev* instance = malloc(sizeof(NfcDev)); +NfcDevice* nfc_device_alloc() { + NfcDevice* instance = malloc(sizeof(NfcDevice)); return instance; } -void nfc_dev_free(NfcDev* instance) { +void nfc_device_free(NfcDevice* instance) { furi_assert(instance); - nfc_dev_clear(instance); + nfc_device_clear(instance); free(instance); } -void nfc_dev_clear(NfcDev* instance) { +void nfc_device_clear(NfcDevice* instance) { furi_assert(instance); - furi_assert(instance->protocol_type < NfcProtocolTypeMax); + furi_assert(instance->protocol < NfcProtocolNum); if(instance->protocol_data) { - nfc_protocols[instance->protocol_type]->free(instance->protocol_data); + nfc_devices[instance->protocol]->free(instance->protocol_data); instance->protocol_data = NULL; } } -void nfc_dev_reset(NfcDev* instance) { +void nfc_device_reset(NfcDevice* instance) { furi_assert(instance); - furi_assert(instance->protocol_type < NfcProtocolTypeMax); + furi_assert(instance->protocol < NfcProtocolNum); if(instance->protocol_data) { - nfc_protocols[instance->protocol_type]->reset(instance->protocol_data); + nfc_devices[instance->protocol]->reset(instance->protocol_data); } } -NfcProtocolType nfc_dev_get_protocol_type(const NfcDev* instance) { +NfcProtocol nfc_device_get_protocol(const NfcDevice* instance) { furi_assert(instance); - return instance->protocol_type; + return instance->protocol; } -const NfcProtocolData* - nfc_dev_get_protocol_data(const NfcDev* instance, NfcProtocolType protocol_type) { +const NfcDeviceData* nfc_device_get_data(const NfcDevice* instance, NfcProtocol protocol) { furi_assert(instance); - furi_assert(protocol_type < NfcProtocolTypeMax); + furi_assert(protocol < NfcProtocolNum); - if(instance->protocol_type != protocol_type) { + if(instance->protocol != protocol) { furi_crash(NFC_DEV_TYPE_ERROR); } return instance->protocol_data; } -const char* nfc_dev_get_protocol_name(NfcProtocolType protocol) { - furi_assert(protocol < NfcProtocolTypeMax); +const char* nfc_device_get_protocol_name(NfcProtocol protocol) { + furi_assert(protocol < NfcProtocolNum); - return nfc_protocols[protocol]->protocol_name; + return nfc_devices[protocol]->protocol_name; } -const char* nfc_dev_get_device_name(const NfcDev* instance, NfcProtocolNameType name_type) { +const char* nfc_device_get_name(const NfcDevice* instance, NfcDeviceNameType name_type) { furi_assert(instance); - furi_assert(instance->protocol_type < NfcProtocolTypeMax); + furi_assert(instance->protocol < NfcProtocolNum); - return nfc_protocols[instance->protocol_type]->get_device_name( - instance->protocol_data, name_type); + return nfc_devices[instance->protocol]->get_name(instance->protocol_data, name_type); } -const uint8_t* nfc_dev_get_uid(const NfcDev* instance, size_t* uid_len) { +const uint8_t* nfc_device_get_uid(const NfcDevice* instance, size_t* uid_len) { furi_assert(instance); - furi_assert(instance->protocol_type < NfcProtocolTypeMax); + furi_assert(instance->protocol < NfcProtocolNum); - return nfc_protocols[instance->protocol_type]->get_uid(instance->protocol_data, uid_len); + return nfc_devices[instance->protocol]->get_uid(instance->protocol_data, uid_len); } -void nfc_dev_set_protocol_data( - NfcDev* instance, - NfcProtocolType protocol_type, - const NfcProtocolData* protocol_data) { +void nfc_device_set_data( + NfcDevice* instance, + NfcProtocol protocol, + const NfcDeviceData* protocol_data) { furi_assert(instance); - furi_assert(protocol_type < NfcProtocolTypeMax); + furi_assert(protocol < NfcProtocolNum); - nfc_dev_clear(instance); + nfc_device_clear(instance); - instance->protocol_type = protocol_type; - instance->protocol_data = nfc_protocols[protocol_type]->alloc(); + instance->protocol = protocol; + instance->protocol_data = nfc_devices[protocol]->alloc(); - nfc_protocols[protocol_type]->copy(instance->protocol_data, protocol_data); + nfc_devices[protocol]->copy(instance->protocol_data, protocol_data); } -void nfc_dev_copy_protocol_data( - const NfcDev* instance, - NfcProtocolType protocol_type, - NfcProtocolData* protocol_data) { +void nfc_device_copy_data( + const NfcDevice* instance, + NfcProtocol protocol, + NfcDeviceData* protocol_data) { furi_assert(instance); - furi_assert(protocol_type < NfcProtocolTypeMax); + furi_assert(protocol < NfcProtocolNum); furi_assert(protocol_data); - if(instance->protocol_type != protocol_type) { + if(instance->protocol != protocol) { furi_crash(NFC_DEV_TYPE_ERROR); } - nfc_protocols[protocol_type]->copy(protocol_data, instance->protocol_data); + nfc_devices[protocol]->copy(protocol_data, instance->protocol_data); } -void nfc_dev_set_loading_callback(NfcDev* instance, NfcLoadingCallback callback, void* context) { +void nfc_device_set_loading_callback( + NfcDevice* instance, + NfcLoadingCallback callback, + void* context) { furi_assert(instance); furi_assert(callback); @@ -123,9 +124,9 @@ void nfc_dev_set_loading_callback(NfcDev* instance, NfcLoadingCallback callback, instance->loading_callback_context = context; } -bool nfc_dev_save(NfcDev* instance, const char* path) { +bool nfc_device_save(NfcDevice* instance, const char* path) { furi_assert(instance); - furi_assert(instance->protocol_type < NfcProtocolTypeMax); + furi_assert(instance->protocol < NfcProtocolNum); furi_assert(path); bool saved = false; @@ -152,7 +153,7 @@ bool nfc_dev_save(NfcDev* instance, const char* path) { file, "Nfc device type can be UID, Mifare Ultralight, Mifare Classic")) break; - saved = nfc_protocols[instance->protocol_type]->save( + saved = nfc_devices[instance->protocol]->save( instance->protocol_data, file, NFC_CURRENT_FORMAT_VERSION); } while(false); @@ -168,7 +169,7 @@ bool nfc_dev_save(NfcDev* instance, const char* path) { return saved; } -bool nfc_dev_load(NfcDev* instance, const char* path) { +bool nfc_device_load(NfcDevice* instance, const char* path) { furi_assert(instance); furi_assert(path); @@ -195,20 +196,20 @@ bool nfc_dev_load(NfcDev* instance, const char* path) { // Read Nfc device type if(!flipper_format_read_string(file, "Device type", temp_str)) break; - nfc_dev_clear(instance); + nfc_device_clear(instance); - for(NfcProtocolType i = 0; i < NfcProtocolTypeMax; i++) { - instance->protocol_type = i; - instance->protocol_data = nfc_protocols[i]->alloc(); + for(NfcProtocol i = 0; i < NfcProtocolNum; i++) { + instance->protocol = i; + instance->protocol_data = nfc_devices[i]->alloc(); - if(nfc_protocols[i]->verify(instance->protocol_data, temp_str)) { - loaded = nfc_protocols[i]->load(instance->protocol_data, file, version); + if(nfc_devices[i]->verify(instance->protocol_data, temp_str)) { + loaded = nfc_devices[i]->load(instance->protocol_data, file, version); } if(loaded) { break; } else { - nfc_protocols[i]->free(instance->protocol_data); + nfc_devices[i]->free(instance->protocol_data); instance->protocol_data = NULL; } } diff --git a/lib/nfc/nfc_device.h b/lib/nfc/nfc_device.h new file mode 100644 index 000000000000..6017734cc92d --- /dev/null +++ b/lib/nfc/nfc_device.h @@ -0,0 +1,54 @@ +#pragma once + +#include + +#include "protocols/nfc_device_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct NfcDevice NfcDevice; + +typedef void (*NfcLoadingCallback)(void* context, bool state); + +NfcDevice* nfc_device_alloc(); + +void nfc_device_free(NfcDevice* instance); + +void nfc_device_clear(NfcDevice* instance); + +void nfc_device_reset(NfcDevice* instance); + +NfcProtocol nfc_device_get_protocol(const NfcDevice* instance); + +const NfcDeviceData* nfc_device_get_data(const NfcDevice* instance, NfcProtocol protocol); + +const char* nfc_device_get_protocol_name(NfcProtocol protocol); + +const char* nfc_device_get_name(const NfcDevice* instance, NfcDeviceNameType name_type); + +const uint8_t* nfc_device_get_uid(const NfcDevice* instance, size_t* uid_len); + +void nfc_device_set_data( + NfcDevice* instance, + NfcProtocol protocol, + const NfcDeviceData* protocol_data); + +void nfc_device_copy_data( + const NfcDevice* instance, + NfcProtocol protocol, + NfcDeviceData* protocol_data); + +void nfc_device_set_loading_callback( + NfcDevice* instance, + NfcLoadingCallback callback, + void* context); + +bool nfc_device_save(NfcDevice* instance, const char* path); + +bool nfc_device_load(NfcDevice* instance, const char* path); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/nfc_poller.c b/lib/nfc/nfc_poller.c index 06768ed0d75b..974b2436e9fe 100644 --- a/lib/nfc/nfc_poller.c +++ b/lib/nfc/nfc_poller.c @@ -11,7 +11,7 @@ typedef enum { } NfcPollerSessionState; typedef struct NfcPollerListElement { - NfcProtocolType protocol; + NfcProtocol protocol; NfcPollerInstance* poller; const NfcPollerBase* poller_api; struct NfcPollerListElement* child; @@ -23,7 +23,7 @@ typedef struct { } NfcPollerList; struct NfcPoller { - NfcProtocolType protocol; + NfcProtocol protocol; Nfc* nfc; NfcPollerList list; NfcPollerSessionState session_state; @@ -39,7 +39,7 @@ static void nfc_poller_list_alloc(NfcPoller* instance) { do { const NfcPollerTreeNode* node = &nfc_poller_nodes[instance->list.head->protocol]; - if(node->parent_protocol == NfcProtocolTypeInvalid) break; + if(node->parent_protocol == NfcProtocolInvalid) break; NfcPollerListElement* parent = malloc(sizeof(NfcPollerListElement)); parent->protocol = node->parent_protocol; @@ -71,9 +71,9 @@ static void nfc_poller_list_free(NfcPoller* instance) { } while(true); } -NfcPoller* nfc_poller_alloc(Nfc* nfc, NfcProtocolType protocol) { +NfcPoller* nfc_poller_alloc(Nfc* nfc, NfcProtocol protocol) { furi_assert(nfc); - furi_assert(protocol < NfcProtocolTypeMax); + furi_assert(protocol < NfcProtocolNum); NfcPoller* instance = malloc(sizeof(NfcPoller)); instance->session_state = NfcPollerSessionStateIdle; @@ -98,7 +98,7 @@ static NfcCommand nfc_poller_start_callback(NfcEvent event, void* context) { NfcCommand command = NfcCommandContinue; NfcPollerEvent poller_event = { - .protocol_type = NfcProtocolTypeInvalid, + .protocol = NfcProtocolInvalid, .poller = instance->nfc, .data = &event, }; @@ -156,7 +156,7 @@ static NfcCommand nfc_poller_detect_callback(NfcEvent event, void* context) { NfcCommand command = NfcCommandContinue; NfcPollerEvent poller_event = { - .protocol_type = NfcProtocolTypeInvalid, + .protocol = NfcProtocolInvalid, .poller = instance->nfc, .data = &event, }; @@ -201,7 +201,7 @@ bool nfc_poller_detect(NfcPoller* instance) { return instance->protocol_detected; } -const NfcProtocolData* nfc_poller_get_data(NfcPoller* instance) { +const NfcDeviceData* nfc_poller_get_data(NfcPoller* instance) { furi_assert(instance); NfcPollerListElement* tail_poller = instance->list.tail; diff --git a/lib/nfc/nfc_poller.h b/lib/nfc/nfc_poller.h index b17e96d01f22..06bc0c3d76d1 100644 --- a/lib/nfc/nfc_poller.h +++ b/lib/nfc/nfc_poller.h @@ -8,7 +8,7 @@ extern "C" { typedef struct NfcPoller NfcPoller; -NfcPoller* nfc_poller_alloc(Nfc* nfc, NfcProtocolType protocol); +NfcPoller* nfc_poller_alloc(Nfc* nfc, NfcProtocol protocol); void nfc_poller_free(NfcPoller* instance); @@ -18,7 +18,7 @@ void nfc_poller_stop(NfcPoller* instance); bool nfc_poller_detect(NfcPoller* instance); -const NfcProtocolData* nfc_poller_get_data(NfcPoller* instance); +const NfcDeviceData* nfc_poller_get_data(NfcPoller* instance); #ifdef __cplusplus } diff --git a/lib/nfc/nfc_scanner.c b/lib/nfc/nfc_scanner.c index 1e0f9102a83a..0aa621dc25b3 100644 --- a/lib/nfc/nfc_scanner.c +++ b/lib/nfc/nfc_scanner.c @@ -36,16 +36,16 @@ struct NfcScanner { size_t base_protocols_num; size_t base_protocols_idx; - NfcProtocolType base_protocols[NfcProtocolTypeMax]; + NfcProtocol base_protocols[NfcProtocolNum]; size_t children_protocols_num; size_t children_protocols_idx; - NfcProtocolType children_protocols[NfcProtocolTypeMax]; + NfcProtocol children_protocols[NfcProtocolNum]; size_t detected_protocols_num; - NfcProtocolType detected_protocols[NfcProtocolTypeMax]; + NfcProtocol detected_protocols[NfcProtocolNum]; - NfcProtocolType current_protocol; + NfcProtocol current_protocol; FuriThread* scan_worker; }; @@ -65,8 +65,8 @@ static void nfc_scanner_reset(NfcScanner* instance) { typedef void (*NfcScannerStateHandler)(NfcScanner* instance); void nfc_scanner_state_handler_idle(NfcScanner* instance) { - for(size_t i = 0; i < NfcProtocolTypeMax; i++) { - if(nfc_poller_nodes[i].parent_protocol == NfcProtocolTypeInvalid) { + for(size_t i = 0; i < NfcProtocolNum; i++) { + if(nfc_poller_nodes[i].parent_protocol == NfcProtocolInvalid) { instance->base_protocols[instance->base_protocols_num] = i; instance->base_protocols_num++; } @@ -98,11 +98,11 @@ void nfc_scanner_state_handler_try_base_pollers(NfcScanner* instance) { } } -static bool nfc_scanner_check_parent_protocol(NfcProtocolType child, NfcProtocolType parent) { +static bool nfc_scanner_check_parent_protocol(NfcProtocol child, NfcProtocol parent) { bool parent_found = false; const NfcPollerTreeNode* iter = &nfc_poller_nodes[child]; - while(iter->parent_protocol != NfcProtocolTypeInvalid) { + while(iter->parent_protocol != NfcProtocolInvalid) { if(iter->parent_protocol == parent) { parent_found = true; break; @@ -114,7 +114,7 @@ static bool nfc_scanner_check_parent_protocol(NfcProtocolType child, NfcProtocol } void nfc_scanner_state_handler_find_children_protocols(NfcScanner* instance) { - for(size_t i = 0; i < NfcProtocolTypeMax; i++) { + for(size_t i = 0; i < NfcProtocolNum; i++) { if(nfc_scanner_check_parent_protocol(i, instance->current_protocol)) { instance->children_protocols[instance->children_protocols_num] = i; instance->children_protocols_num++; @@ -152,7 +152,7 @@ void nfc_scanner_state_handler_detect_children_protocols(NfcScanner* instance) { static void nfc_scanner_filter_detected_protocols(NfcScanner* instance) { size_t filtered_protocols_num = 0; - NfcProtocolType filtered_protocols[NfcProtocolTypeMax] = {}; + NfcProtocol filtered_protocols[NfcProtocolNum] = {}; for(size_t i = 0; i < instance->detected_protocols_num; i++) { bool is_parent = false; diff --git a/lib/nfc/nfc_scanner.h b/lib/nfc/nfc_scanner.h index 9d01fe25c303..63ed1fc02bd4 100644 --- a/lib/nfc/nfc_scanner.h +++ b/lib/nfc/nfc_scanner.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #ifdef __cplusplus extern "C" { @@ -15,7 +15,7 @@ typedef enum { typedef struct { size_t protocol_num; - NfcProtocolType* protocols; + NfcProtocol* protocols; } NfcScannerEventData; typedef struct { diff --git a/lib/nfc/protocols/nfca/nfca.c b/lib/nfc/protocols/iso14443_3a/iso14443_3a.c similarity index 57% rename from lib/nfc/protocols/nfca/nfca.c rename to lib/nfc/protocols/iso14443_3a/iso14443_3a.c index ad36700d59ac..e460218fc391 100644 --- a/lib/nfc/protocols/nfca/nfca.c +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a.c @@ -1,85 +1,85 @@ -#include "nfca.h" +#include "iso14443_3a.h" #include #include -#define NFCA_CRC_INIT (0x6363) -#define NFCA_PROTOCOL_NAME "ISO14443-3A" -#define NFCA_DEVICE_NAME "Unknown ISO14443-3A Tag" - -const NfcProtocolBase nfc_protocol_iso14443_3a = { - .protocol_name = NFCA_PROTOCOL_NAME, - .alloc = (NfcProtocolAlloc)nfca_alloc, - .free = (NfcProtocolFree)nfca_free, - .reset = (NfcProtocolReset)nfca_reset, - .copy = (NfcProtocolCopy)nfca_copy, - .verify = (NfcProtocolVerify)nfca_verify, - .load = (NfcProtocolLoad)nfca_load, - .save = (NfcProtocolSave)nfca_save, - .is_equal = (NfcProtocolEqual)nfca_is_equal, - .get_device_name = (NfcProtocolGetDeviceName)nfca_get_device_name, - .get_uid = (NfcProtocolGetUid)nfca_get_uid, +#define ISO14443_3A_CRC_INIT (0x6363) +#define ISO14443_3A_PROTOCOL_NAME "ISO14443-3A" +#define ISO14443_3A_DEVICE_NAME "Unknown ISO14443-3A Tag" + +const NfcDeviceBase nfc_device_iso14443_3a = { + .protocol_name = ISO14443_3A_PROTOCOL_NAME, + .alloc = (NfcDeviceAlloc)iso14443_3a_alloc, + .free = (NfcDeviceFree)iso14443_3a_free, + .reset = (NfcDeviceReset)iso14443_3a_reset, + .copy = (NfcDeviceCopy)iso14443_3a_copy, + .verify = (NfcDeviceVerify)iso14443_3a_verify, + .load = (NfcDeviceLoad)iso14443_3a_load, + .save = (NfcDeviceSave)iso14443_3a_save, + .is_equal = (NfcDeviceEqual)iso14443_3a_is_equal, + .get_name = (NfcDeviceGetName)iso14443_3a_get_device_name, + .get_uid = (NfcDeviceGetUid)iso14443_3a_get_uid, }; -NfcaData* nfca_alloc() { - NfcaData* data = malloc(sizeof(NfcaData)); +Iso14443_3aData* iso14443_3a_alloc() { + Iso14443_3aData* data = malloc(sizeof(Iso14443_3aData)); return data; } -void nfca_free(NfcaData* data) { +void iso14443_3a_free(Iso14443_3aData* data) { furi_assert(data); free(data); } -void nfca_reset(NfcaData* data) { +void iso14443_3a_reset(Iso14443_3aData* data) { furi_assert(data); UNUSED(data); } -void nfca_copy(NfcaData* data, const NfcaData* other) { +void iso14443_3a_copy(Iso14443_3aData* data, const Iso14443_3aData* other) { furi_assert(data); furi_assert(other); *data = *other; } -bool nfca_verify(NfcaData* data, const FuriString* device_type) { +bool iso14443_3a_verify(Iso14443_3aData* data, const FuriString* device_type) { UNUSED(data); return furi_string_equal(device_type, "UID"); } -bool nfca_load(NfcaData* data, FlipperFormat* ff, uint32_t version) { - return nfca_load_data(data, ff, version); +bool iso14443_3a_load(Iso14443_3aData* data, FlipperFormat* ff, uint32_t version) { + return iso14443_3a_load_data(data, ff, version); return true; } -bool nfca_save(const NfcaData* data, FlipperFormat* ff, uint32_t version) { +bool iso14443_3a_save(const Iso14443_3aData* data, FlipperFormat* ff, uint32_t version) { bool saved = false; do { if(!flipper_format_write_string_cstr(ff, "Device type", "UID")) break; - if(!nfca_save_data(data, ff, version)) break; + if(!iso14443_3a_save_data(data, ff, version)) break; saved = true; } while(false); return saved; } -bool nfca_is_equal(const NfcaData* data, const NfcaData* other) { +bool iso14443_3a_is_equal(const Iso14443_3aData* data, const Iso14443_3aData* other) { furi_assert(data); furi_assert(other); - return memcmp(data, other, sizeof(NfcaData)) == 0; + return memcmp(data, other, sizeof(Iso14443_3aData)) == 0; } -const char* nfca_get_device_name(const NfcaData* data, NfcProtocolNameType name_type) { +const char* iso14443_3a_get_device_name(const Iso14443_3aData* data, NfcDeviceNameType name_type) { UNUSED(data); UNUSED(name_type); - return NFCA_DEVICE_NAME; + return ISO14443_3A_DEVICE_NAME; } -const uint8_t* nfca_get_uid(const NfcaData* data, size_t* uid_len) { +const uint8_t* iso14443_3a_get_uid(const Iso14443_3aData* data, size_t* uid_len) { furi_assert(data); if(uid_len) { @@ -89,7 +89,7 @@ const uint8_t* nfca_get_uid(const NfcaData* data, size_t* uid_len) { return data->uid; } -bool nfca_load_data(NfcaData* data, FlipperFormat* ff, uint32_t version) { +bool iso14443_3a_load_data(Iso14443_3aData* data, FlipperFormat* ff, uint32_t version) { furi_assert(data); uint32_t data_cnt = 0; @@ -116,7 +116,7 @@ bool nfca_load_data(NfcaData* data, FlipperFormat* ff, uint32_t version) { return parsed; } -bool nfca_save_data(const NfcaData* data, FlipperFormat* ff, uint32_t version) { +bool iso14443_3a_save_data(const Iso14443_3aData* data, FlipperFormat* ff, uint32_t version) { furi_assert(data); UNUSED(version); @@ -137,11 +137,11 @@ bool nfca_save_data(const NfcaData* data, FlipperFormat* ff, uint32_t version) { return saved; } -static uint16_t nfca_get_crc(const uint8_t* buff, uint16_t len) { +static uint16_t iso14443_3a_get_crc(const uint8_t* buff, uint16_t len) { furi_assert(buff); furi_assert(len); - uint16_t crc = NFCA_CRC_INIT; + uint16_t crc = ISO14443_3A_CRC_INIT; uint8_t byte = 0; for(uint8_t i = 0; i < len; i++) { @@ -155,31 +155,31 @@ static uint16_t nfca_get_crc(const uint8_t* buff, uint16_t len) { return crc; } -uint32_t nfca_get_cuid(NfcaData* nfca_data) { - furi_assert(nfca_data); +uint32_t iso14443_3a_get_cuid(Iso14443_3aData* iso14443_3a_data) { + furi_assert(iso14443_3a_data); uint32_t cuid = 0; - uint8_t* cuid_start = nfca_data->uid; - if(nfca_data->uid_len == 7) { - cuid_start = &nfca_data->uid[3]; + uint8_t* cuid_start = iso14443_3a_data->uid; + if(iso14443_3a_data->uid_len == 7) { + cuid_start = &iso14443_3a_data->uid[3]; } cuid = (cuid_start[0] << 24) | (cuid_start[1] << 16) | (cuid_start[2] << 8) | (cuid_start[3]); return cuid; } -void nfca_append_crc(BitBuffer* buffer) { +void iso14443_3a_append_crc(BitBuffer* buffer) { furi_assert(buffer); const uint8_t* data = bit_buffer_get_data(buffer); size_t bytes = bit_buffer_get_size_bytes(buffer); - uint16_t crc = nfca_get_crc(data, bytes); + uint16_t crc = iso14443_3a_get_crc(data, bytes); uint8_t crc_bytes[2] = {(uint8_t)crc, (uint8_t)(crc >> 8)}; bit_buffer_append_bytes(buffer, crc_bytes, sizeof(crc_bytes)); } -bool nfca_check_crc(const BitBuffer* buf) { +bool iso14443_3a_check_crc(const BitBuffer* buf) { furi_assert(buf); bool crc_ok = false; @@ -188,7 +188,7 @@ bool nfca_check_crc(const BitBuffer* buf) { size_t bytes = bit_buffer_get_size_bytes(buf); if(bytes < 3) break; - uint16_t crc_calc = nfca_get_crc(data, bytes - 2); + uint16_t crc_calc = iso14443_3a_get_crc(data, bytes - 2); uint8_t crc_start = bit_buffer_get_byte(buf, bytes - 2); uint8_t crc_end = bit_buffer_get_byte(buf, bytes - 1); uint16_t crc_received = (crc_end << 8) | crc_start; @@ -198,7 +198,7 @@ bool nfca_check_crc(const BitBuffer* buf) { return crc_ok; } -void nfca_trim_crc(BitBuffer* buf) { +void iso14443_3a_trim_crc(BitBuffer* buf) { furi_assert(buf); size_t bytes = bit_buffer_get_size_bytes(buf); diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a.h b/lib/nfc/protocols/iso14443_3a/iso14443_3a.h new file mode 100644 index 000000000000..db2ae30e3a7d --- /dev/null +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a.h @@ -0,0 +1,104 @@ +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define ISO14443_3A_MAX_UID_SIZE (10U) + +#define ISO14443_3A_GUARD_TIME_US (5000) +#define ISO14443_3A_FDT_POLL_FC (1620) +#define ISO14443_3A_FDT_LISTEN_FC (1172) +#define ISO14443_3A_POLLER_MASK_RX_FS ((ISO14443_3A_FDT_LISTEN_FC) / 2) +#define ISO14443_3A_POLL_POLL_MIN_US (1100) + +typedef enum { + Iso14443_3aErrorNone, + Iso14443_3aErrorNotPresent, + Iso14443_3aErrorColResFailed, + Iso14443_3aErrorBufferOverflow, + Iso14443_3aErrorCommunication, + Iso14443_3aErrorFieldOff, + Iso14443_3aErrorWrongCrc, + Iso14443_3aErrorTimeout, +} Iso14443_3aError; + +typedef struct { + uint8_t sens_resp[2]; +} Iso14443_3aSensResp; + +typedef struct { + uint8_t sel_cmd; + uint8_t sel_par; + uint8_t data[4]; // max data bit is 32 +} Iso14443_3aSddReq; + +typedef struct { + uint8_t nfcid[4]; + uint8_t bss; +} Iso14443_3aSddResp; + +typedef struct { + uint8_t sel_cmd; + uint8_t sel_par; + uint8_t nfcid[4]; + uint8_t bcc; +} Iso14443_3aSelReq; + +typedef struct { + uint8_t sak; +} Iso14443_3aSelResp; + +typedef struct { + uint8_t sak; +} Iso14443_3aRats; + +typedef struct { + uint8_t uid[ISO14443_3A_MAX_UID_SIZE]; + uint8_t uid_len; + uint8_t atqa[2]; + uint8_t sak; + Iso14443_3aRats rats; +} Iso14443_3aData; + +extern const NfcDeviceBase nfc_device_iso14443_3a; + +Iso14443_3aData* iso14443_3a_alloc(); + +void iso14443_3a_free(Iso14443_3aData* data); + +void iso14443_3a_reset(Iso14443_3aData* data); + +void iso14443_3a_copy(Iso14443_3aData* data, const Iso14443_3aData* other); + +bool iso14443_3a_verify(Iso14443_3aData* data, const FuriString* device_type); + +bool iso14443_3a_load(Iso14443_3aData* data, FlipperFormat* ff, uint32_t version); + +bool iso14443_3a_save(const Iso14443_3aData* data, FlipperFormat* ff, uint32_t version); + +bool iso14443_3a_is_equal(const Iso14443_3aData* data, const Iso14443_3aData* other); + +const char* iso14443_3a_get_device_name(const Iso14443_3aData* data, NfcDeviceNameType name_type); + +const uint8_t* iso14443_3a_get_uid(const Iso14443_3aData* data, size_t* uid_len); + +uint32_t iso14443_3a_get_cuid(Iso14443_3aData* iso14443_3a_data); + +void iso14443_3a_append_crc(BitBuffer* buffer); + +bool iso14443_3a_check_crc(const BitBuffer* buf); + +void iso14443_3a_trim_crc(BitBuffer* buf); + +// TODO: Decide where should these methods go (*_i file?) +bool iso14443_3a_load_data(Iso14443_3aData* data, FlipperFormat* ff, uint32_t version); + +bool iso14443_3a_save_data(const Iso14443_3aData* data, FlipperFormat* ff, uint32_t version); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c b/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c new file mode 100644 index 000000000000..f32b10f0119c --- /dev/null +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c @@ -0,0 +1,226 @@ +#include "iso14443_3a_listener.h" + +#include +#include + +#define TAG "Iso14443_3aListener" + +#define ISO14443_3A_LISTENER_MAX_BUFFER_SIZE (256) + +typedef enum { + Iso14443_3aListenerStateIdle, + Iso14443_3aListenerStateActive, +} Iso14443_3aListenerState; + +struct Iso14443_3aListener { + Nfc* nfc; + Iso14443_3aData* data; + Iso14443_3aListenerState state; + Iso14443_3aListenerEventCallback callback; + + BitBuffer* tx_buffer; + void* context; +}; + +static Iso14443_3aError iso14443_3a_listener_process_nfc_error(NfcError error) { + Iso14443_3aError ret = Iso14443_3aErrorNone; + + if(error == NfcErrorNone) { + ret = Iso14443_3aErrorNone; + } else if(error == NfcErrorTimeout) { + ret = Iso14443_3aErrorTimeout; + } else { + ret = Iso14443_3aErrorFieldOff; + } + + return ret; +} + +static void iso14443_3a_listener_config(Iso14443_3aListener* instance) { + furi_assert(instance); + + instance->tx_buffer = bit_buffer_alloc(ISO14443_3A_LISTENER_MAX_BUFFER_SIZE); + + nfc_set_fdt_listen_fc(instance->nfc, ISO14443_3A_FDT_LISTEN_FC); + nfc_config(instance->nfc, NfcModeIso14443_3aListener); + nfc_listener_set_col_res_data( + instance->nfc, + instance->data->uid, + instance->data->uid_len, + instance->data->atqa, + instance->data->sak); +} + +static void iso14443_3a_listener_reset(Iso14443_3aListener* instance) { + furi_assert(instance); + furi_assert(instance->tx_buffer); + + bit_buffer_free(instance->tx_buffer); + instance->tx_buffer = NULL; +} + +static bool iso14443_3a_listener_halt_received(BitBuffer* buf) { + bool halt_cmd_received = false; + + do { + if(bit_buffer_get_size_bytes(buf) != 4) break; + if(!iso14443_3a_check_crc(buf)) break; + if(bit_buffer_get_byte(buf, 0) != 0x50) break; + if(bit_buffer_get_byte(buf, 1) != 0x00) break; + halt_cmd_received = true; + } while(false); + + return halt_cmd_received; +} + +static NfcCommand iso14443_3a_listener_event_handler(NfcEvent event, void* context) { + furi_assert(context); + + Iso14443_3aListener* instance = context; + NfcEventType event_type = event.type; + Iso14443_3aListenerEvent iso14443_3a_listener_event = {}; + NfcCommand command = NfcCommandContinue; + + if(event_type == NfcEventTypeConfigureRequest) { + iso14443_3a_listener_config(instance); + if(instance->callback) { + iso14443_3a_listener_event.type = Iso14443_3aListenerEventConfigRequest; + instance->callback(iso14443_3a_listener_event, instance->context); + } + } else if(event_type == NfcEventTypeListenerActivated) { + instance->state = Iso14443_3aListenerStateActive; + } else if( + (event_type == NfcEventTypeRxEnd) && (instance->state == Iso14443_3aListenerStateActive)) { + if(iso14443_3a_listener_halt_received(event.data.buffer)) { + // TODO rework with commands + iso14443_3a_listener_sleep(instance); + instance->state = Iso14443_3aListenerStateIdle; + if(instance->callback) { + iso14443_3a_listener_event.type = Iso14443_3aListenerEventTypeHalted; + instance->callback(iso14443_3a_listener_event, instance->context); + } + } else if(instance->callback) { + if(iso14443_3a_check_crc(event.data.buffer)) { + iso14443_3a_listener_event.type = + Iso14443_3aListenerEventTypeReceivedStandartFrame; + size_t bytes = bit_buffer_get_size_bytes(event.data.buffer); + bit_buffer_set_size_bytes(event.data.buffer, bytes - 2); + } else { + iso14443_3a_listener_event.type = Iso14443_3aListenerEventTypeReceivedData; + } + iso14443_3a_listener_event.data.buffer = event.data.buffer; + if(instance->callback) { + instance->callback(iso14443_3a_listener_event, instance->context); + } + } + } else if(event_type == NfcEventTypeReset) { + iso14443_3a_listener_reset(instance); + if(instance->callback) { + iso14443_3a_listener_event.type = Iso14443_3aListenerEventTypeReset; + instance->callback(iso14443_3a_listener_event, instance->context); + } + } + + return command; +} + +Iso14443_3aListener* iso14443_3a_listener_alloc(Nfc* nfc) { + furi_assert(nfc); + + Iso14443_3aListener* instance = malloc(sizeof(Iso14443_3aListener)); + instance->nfc = nfc; + + return instance; +} + +void iso14443_3a_listener_free(Iso14443_3aListener* instance) { + furi_assert(instance); + free(instance); +} + +Iso14443_3aError iso14443_3a_listener_start( + Iso14443_3aListener* instance, + const Iso14443_3aData* data, + Iso14443_3aListenerEventCallback callback, + void* context) { + furi_assert(instance); + + instance->callback = callback; + instance->context = context; + + instance->data = iso14443_3a_alloc(); + iso14443_3a_copy(instance->data, data); + + nfc_start_listener(instance->nfc, iso14443_3a_listener_event_handler, instance); + + return Iso14443_3aErrorNone; +} + +Iso14443_3aError iso14443_3a_listener_stop(Iso14443_3aListener* instance) { + furi_assert(instance); + + nfc_listener_abort(instance->nfc); + iso14443_3a_free(instance->data); + + instance->callback = NULL; + instance->context = NULL; + instance->state = Iso14443_3aListenerStateIdle; + + return Iso14443_3aErrorNone; +} + +Iso14443_3aError + iso14443_3a_listener_get_data(Iso14443_3aListener* instance, Iso14443_3aData* data) { + furi_assert(instance); + + iso14443_3a_copy(data, instance->data); + + return Iso14443_3aErrorNone; +} + +Iso14443_3aError iso14443_3a_listener_sleep(Iso14443_3aListener* instance) { + furi_assert(instance); + + NfcError error = nfc_listener_sleep(instance->nfc); + instance->state = Iso14443_3aListenerStateIdle; + + return iso14443_3a_listener_process_nfc_error(error); +} + +Iso14443_3aError + iso14443_3a_listener_tx(Iso14443_3aListener* instance, const BitBuffer* tx_buffer) { + furi_assert(instance); + furi_assert(tx_buffer); + + Iso14443_3aError ret = Iso14443_3aErrorNone; + NfcError error = nfc_listener_tx(instance->nfc, tx_buffer); + if(error != NfcErrorNone) { + FURI_LOG_W(TAG, "Tx error: %d", error); + ret = iso14443_3a_listener_process_nfc_error(error); + } + + return ret; +} + +Iso14443_3aError iso14443_3a_listener_send_standart_frame( + Iso14443_3aListener* instance, + const BitBuffer* tx_buffer) { + furi_assert(instance); + furi_assert(tx_buffer); + furi_assert(instance->tx_buffer); + + Iso14443_3aError ret = Iso14443_3aErrorNone; + do { + bit_buffer_copy(instance->tx_buffer, tx_buffer); + iso14443_3a_append_crc(instance->tx_buffer); + + NfcError error = nfc_listener_tx(instance->nfc, instance->tx_buffer); + if(error != NfcErrorNone) { + FURI_LOG_W(TAG, "Tx error: %d", error); + ret = iso14443_3a_listener_process_nfc_error(error); + break; + } + } while(false); + + return ret; +} diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.h b/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.h new file mode 100644 index 000000000000..5596731012b0 --- /dev/null +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.h @@ -0,0 +1,68 @@ +#pragma once + +#include "iso14443_3a.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct Iso14443_3aListener Iso14443_3aListener; + +typedef enum { + Iso14443_3aListenerEventConfigRequest, + Iso14443_3aListenerEventTypeAbort, + Iso14443_3aListenerEventTypeFieldOn, + Iso14443_3aListenerEventTypeFieldOff, + Iso14443_3aListenerEventTypeHalted, + Iso14443_3aListenerEventTypeReceivedStandartFrame, + Iso14443_3aListenerEventTypeReceivedData, + Iso14443_3aListenerEventTypeReset, +} Iso14443_3aListenerEventType; + +typedef struct { + BitBuffer* buffer; +} Iso14443_3aListenerEventData; + +typedef struct { + Iso14443_3aListenerEventType type; + Iso14443_3aListenerEventData data; +} Iso14443_3aListenerEvent; + +typedef enum { + Iso14443_3aListenerCommandContinue = NfcCommandContinue, + Iso14443_3aListenerCommandReset = NfcCommandReset, +} Iso14443_3aListenerCommand; + +typedef Iso14443_3aListenerCommand ( + *Iso14443_3aListenerEventCallback)(Iso14443_3aListenerEvent event, void* context); + +Iso14443_3aListener* iso14443_3a_listener_alloc(Nfc* nfc); + +void iso14443_3a_listener_free(Iso14443_3aListener* instance); + +Iso14443_3aError iso14443_3a_listener_start( + Iso14443_3aListener* instance, + const Iso14443_3aData* data, + Iso14443_3aListenerEventCallback callback, + void* context); + +Iso14443_3aError + iso14443_3a_listener_get_data(Iso14443_3aListener* instance, Iso14443_3aData* data); + +Iso14443_3aError iso14443_3a_listener_stop(Iso14443_3aListener* instance); + +// Called from NfcWorker thread + +Iso14443_3aError iso14443_3a_listener_sleep(Iso14443_3aListener* instance); + +Iso14443_3aError + iso14443_3a_listener_tx(Iso14443_3aListener* instance, const BitBuffer* tx_buffer); + +Iso14443_3aError iso14443_3a_listener_send_standart_frame( + Iso14443_3aListener* instance, + const BitBuffer* tx_buffer); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.c b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.c new file mode 100644 index 000000000000..a5d7d4676783 --- /dev/null +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.c @@ -0,0 +1,124 @@ +#include "iso14443_3a_poller_i.h" + +#include + +#include + +#define TAG "ISO14443_3A" + +const Iso14443_3aData* iso14443_3a_poller_get_data(Iso14443_3aPoller* instance) { + furi_assert(instance); + furi_assert(instance->data); + + return instance->data; +} + +static Iso14443_3aPoller* iso14443_3a_poller_alloc(Nfc* nfc) { + furi_assert(nfc); + + Iso14443_3aPoller* instance = malloc(sizeof(Iso14443_3aPoller)); + instance->nfc = nfc; + instance->tx_buffer = bit_buffer_alloc(ISO14443_3A_POLLER_MAX_BUFFER_SIZE); + instance->rx_buffer = bit_buffer_alloc(ISO14443_3A_POLLER_MAX_BUFFER_SIZE); + + nfc_config(instance->nfc, NfcModeIso14443_3aPoller); + nfc_set_guard_time_us(instance->nfc, ISO14443_3A_GUARD_TIME_US); + nfc_set_fdt_poll_fc(instance->nfc, ISO14443_3A_FDT_POLL_FC); + nfc_set_fdt_poll_poll_us(instance->nfc, ISO14443_3A_POLL_POLL_MIN_US); + instance->data = iso14443_3a_alloc(); + + instance->iso14443_3a_event.data = &instance->iso14443_3a_event_data; + instance->general_event.protocol = NfcProtocolIso14443_3a; + instance->general_event.data = &instance->iso14443_3a_event; + instance->general_event.poller = instance; + + return instance; +} + +static void iso14443_3a_poller_free_new(Iso14443_3aPoller* iso14443_3a_poller) { + furi_assert(iso14443_3a_poller); + + Iso14443_3aPoller* instance = iso14443_3a_poller; + furi_assert(instance->tx_buffer); + furi_assert(instance->rx_buffer); + furi_assert(instance->data); + + bit_buffer_free(instance->tx_buffer); + bit_buffer_free(instance->rx_buffer); + iso14443_3a_free(instance->data); + free(instance); +} + +static void iso14443_3a_poller_set_callback( + Iso14443_3aPoller* instance, + NfcPollerCallback callback, + void* context) { + furi_assert(instance); + furi_assert(callback); + + instance->callback = callback; + instance->context = context; +} + +static NfcCommand iso14443_3a_poller_run(NfcPollerEvent event, void* context) { + furi_assert(context); + furi_assert(event.protocol == NfcProtocolInvalid); + furi_assert(event.data); + + Iso14443_3aPoller* instance = context; + NfcEvent* nfc_event = event.data; + NfcCommand command = NfcCommandContinue; + + if(nfc_event->type == NfcEventTypePollerReady) { + if(instance->state != Iso14443_3aPollerStateActivated) { + Iso14443_3aData data = {}; + Iso14443_3aError error = iso14443_3a_poller_async_activate(instance, &data); + if(error == Iso14443_3aErrorNone) { + instance->state = Iso14443_3aPollerStateActivated; + instance->iso14443_3a_event.type = Iso14443_3aPollerEventTypeReady; + instance->iso14443_3a_event_data.error = error; + command = instance->callback(instance->general_event, instance->context); + } else { + instance->iso14443_3a_event.type = Iso14443_3aPollerEventTypeError; + instance->iso14443_3a_event_data.error = error; + command = instance->callback(instance->general_event, instance->context); + // Add delay to switch context + furi_delay_ms(100); + } + } else { + instance->iso14443_3a_event.type = Iso14443_3aPollerEventTypeReady; + instance->iso14443_3a_event_data.error = Iso14443_3aErrorNone; + command = instance->callback(instance->general_event, instance->context); + } + } + + return command; +} + +static bool iso14443_3a_poller_detect(NfcPollerEvent event, void* context) { + furi_assert(context); + furi_assert(event.data); + furi_assert(event.poller); + furi_assert(event.protocol = NfcProtocolInvalid); + + bool protocol_detected = false; + Iso14443_3aPoller* instance = context; + NfcEvent* nfc_event = event.data; + furi_assert(instance->state == Iso14443_3aPollerStateIdle); + + if(nfc_event->type == NfcEventTypePollerReady) { + Iso14443_3aError error = iso14443_3a_poller_async_activate(instance, NULL); + protocol_detected = (error == Iso14443_3aErrorNone); + } + + return protocol_detected; +} + +const NfcPollerBase nfc_poller_iso14443_3a = { + .alloc = (NfcPollerAlloc)iso14443_3a_poller_alloc, + .free = (NfcPollerFree)iso14443_3a_poller_free_new, + .set_callback = (NfcPollerSetCallback)iso14443_3a_poller_set_callback, + .run = (NfcPollerRun)iso14443_3a_poller_run, + .detect = (NfcPollerDetect)iso14443_3a_poller_detect, + .get_data = (NfcPollerGetData)iso14443_3a_poller_get_data, +}; diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.h b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.h new file mode 100644 index 000000000000..a9ffb220fd96 --- /dev/null +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.h @@ -0,0 +1,30 @@ +#pragma once + +#include "iso14443_3a.h" +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct Iso14443_3aPoller Iso14443_3aPoller; + +typedef enum { + Iso14443_3aPollerEventTypeError, + Iso14443_3aPollerEventTypeReady, +} Iso14443_3aPollerEventType; + +typedef struct { + Iso14443_3aError error; +} Iso14443_3aPollerEventData; + +typedef struct { + Iso14443_3aPollerEventType type; + Iso14443_3aPollerEventData* data; +} Iso14443_3aPollerEvent; + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/nfca/nfca_poller_defs.h b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_defs.h similarity index 100% rename from lib/nfc/protocols/nfca/nfca_poller_defs.h rename to lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_defs.h diff --git a/lib/nfc/protocols/nfca/nfca_poller_i.c b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.c similarity index 51% rename from lib/nfc/protocols/nfca/nfca_poller_i.c rename to lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.c index 20753d16e474..a5fa00535a9c 100644 --- a/lib/nfc/protocols/nfca/nfca_poller_i.c +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.c @@ -1,33 +1,33 @@ -#include "nfca_poller_i.h" +#include "iso14443_3a_poller_i.h" #include -#define TAG "NFCA" +#define TAG "ISO14443_3A" -static NfcaError nfca_poller_process_error(NfcError error) { - NfcaError ret = NfcaErrorNone; +static Iso14443_3aError iso14443_3a_poller_process_error(NfcError error) { + Iso14443_3aError ret = Iso14443_3aErrorNone; if(error == NfcErrorNone) { - ret = NfcaErrorNone; + ret = Iso14443_3aErrorNone; } else if(error == NfcErrorTimeout) { - ret = NfcaErrorTimeout; + ret = Iso14443_3aErrorTimeout; } else { - ret = NfcaErrorNotPresent; + ret = Iso14443_3aErrorNotPresent; } return ret; } -static NfcaError nfca_poller_prepare_trx(NfcaPoller* instance) { - NfcaError ret = NfcaErrorNone; +static Iso14443_3aError iso14443_3a_poller_prepare_trx(Iso14443_3aPoller* instance) { + Iso14443_3aError ret = Iso14443_3aErrorNone; - if(instance->state == NfcaPollerStateIdle) { - ret = nfca_poller_async_activate(instance, NULL); + if(instance->state == Iso14443_3aPollerStateIdle) { + ret = iso14443_3a_poller_async_activate(instance, NULL); } return ret; } -static NfcaError nfca_poller_standart_frame_exchange( - NfcaPoller* instance, +static Iso14443_3aError iso14443_3a_poller_standart_frame_exchange( + Iso14443_3aPoller* instance, const BitBuffer* tx_buffer, BitBuffer* rx_buffer, uint32_t fwt) { @@ -39,80 +39,46 @@ static NfcaError nfca_poller_standart_frame_exchange( furi_assert(tx_bytes <= bit_buffer_get_capacity_bytes(instance->tx_buffer) - 2); bit_buffer_copy(instance->tx_buffer, tx_buffer); - nfca_append_crc(instance->tx_buffer); - NfcaError ret = NfcaErrorNone; + iso14443_3a_append_crc(instance->tx_buffer); + Iso14443_3aError ret = Iso14443_3aErrorNone; do { NfcError error = nfc_trx(instance->nfc, instance->tx_buffer, instance->rx_buffer, fwt); if(error != NfcErrorNone) { - ret = nfca_poller_process_error(error); + ret = iso14443_3a_poller_process_error(error); break; } bit_buffer_copy(rx_buffer, instance->rx_buffer); - if(!nfca_check_crc(instance->rx_buffer)) { - ret = NfcaErrorWrongCrc; + if(!iso14443_3a_check_crc(instance->rx_buffer)) { + ret = Iso14443_3aErrorWrongCrc; break; } - nfca_trim_crc(rx_buffer); + iso14443_3a_trim_crc(rx_buffer); } while(false); return ret; } -NfcaError nfca_poller_config(NfcaPoller* instance) { - furi_assert(instance); - furi_assert(instance->tx_buffer == NULL); - furi_assert(instance->rx_buffer == NULL); - - instance->tx_buffer = bit_buffer_alloc(NFCA_POLLER_MAX_BUFFER_SIZE); - instance->rx_buffer = bit_buffer_alloc(NFCA_POLLER_MAX_BUFFER_SIZE); - - nfc_config(instance->nfc, NfcModeNfcaPoller); - nfc_set_guard_time_us(instance->nfc, NFCA_GUARD_TIME_US); - nfc_set_fdt_poll_fc(instance->nfc, NFCA_FDT_POLL_FC); - nfc_set_fdt_poll_poll_us(instance->nfc, NFCA_POLL_POLL_MIN_US); - instance->config_state = NfcaPollerConfigStateDone; - - return NfcaErrorNone; -} - -NfcaError nfca_poller_reset(NfcaPoller* instance) { - furi_assert(instance); - furi_assert(instance->tx_buffer); - furi_assert(instance->rx_buffer); - - instance->callback = NULL; - instance->context = NULL; - memset(&instance->col_res, 0, sizeof(NfcaPollerColRes)); - - bit_buffer_free(instance->tx_buffer); - instance->tx_buffer = NULL; - bit_buffer_free(instance->rx_buffer); - instance->rx_buffer = NULL; - - instance->config_state = NfcaPollerConfigStateIdle; - instance->state = NfcaPollerStateIdle; - - return NfcaErrorNone; -} - -NfcaError nfca_poller_check_presence(NfcaPoller* instance) { +Iso14443_3aError iso14443_3a_poller_check_presence(Iso14443_3aPoller* instance) { furi_assert(instance); furi_assert(instance->nfc); NfcError error = NfcErrorNone; - NfcaError ret = NfcaErrorNone; + Iso14443_3aError ret = Iso14443_3aErrorNone; do { error = nfc_iso13444a_short_frame( - instance->nfc, NfcIso14443aShortFrameSensReq, instance->rx_buffer, NFCA_FDT_LISTEN_FC); + instance->nfc, + NfcIso14443aShortFrameSensReq, + instance->rx_buffer, + ISO14443_3A_FDT_LISTEN_FC); if(error != NfcErrorNone) { - ret = nfca_poller_process_error(error); + ret = iso14443_3a_poller_process_error(error); break; } if(bit_buffer_get_size_bytes(instance->rx_buffer) != sizeof(instance->col_res.sens_resp)) { - ret = NfcaErrorCommunication; + ret = Iso14443_3aErrorCommunication; break; } } while(false); @@ -120,7 +86,7 @@ NfcaError nfca_poller_check_presence(NfcaPoller* instance) { return ret; } -NfcaError nfca_poller_halt(NfcaPoller* instance) { +Iso14443_3aError iso14443_3a_poller_halt(Iso14443_3aPoller* instance) { furi_assert(instance); furi_assert(instance->nfc); furi_assert(instance->tx_buffer); @@ -128,45 +94,50 @@ NfcaError nfca_poller_halt(NfcaPoller* instance) { uint8_t halt_cmd[2] = {0x50, 0x00}; bit_buffer_copy_bytes(instance->tx_buffer, halt_cmd, sizeof(halt_cmd)); - nfca_poller_standart_frame_exchange( - instance, instance->tx_buffer, instance->rx_buffer, NFCA_FDT_LISTEN_FC); + iso14443_3a_poller_standart_frame_exchange( + instance, instance->tx_buffer, instance->rx_buffer, ISO14443_3A_FDT_LISTEN_FC); - instance->state = NfcaPollerStateIdle; - return NfcaErrorNone; + instance->state = Iso14443_3aPollerStateIdle; + return Iso14443_3aErrorNone; } -NfcaError nfca_poller_async_activate(NfcaPoller* instance, NfcaData* nfca_data) { +Iso14443_3aError iso14443_3a_poller_async_activate( + Iso14443_3aPoller* instance, + Iso14443_3aData* iso14443_3a_data) { furi_assert(instance); furi_assert(instance->nfc); furi_assert(instance->tx_buffer); furi_assert(instance->rx_buffer); - // Reset Nfca poller state + // Reset Iso14443_3a poller state memset(&instance->col_res, 0, sizeof(instance->col_res)); - memset(instance->data, 0, sizeof(NfcaData)); + memset(instance->data, 0, sizeof(Iso14443_3aData)); bit_buffer_reset(instance->tx_buffer); bit_buffer_reset(instance->rx_buffer); // Halt if necessary - if(instance->state != NfcaPollerStateIdle) { - nfca_poller_halt(instance); - instance->state = NfcaPollerStateIdle; + if(instance->state != Iso14443_3aPollerStateIdle) { + iso14443_3a_poller_halt(instance); + instance->state = Iso14443_3aPollerStateIdle; } NfcError error = NfcErrorNone; - NfcaError ret = NfcaErrorNone; + Iso14443_3aError ret = Iso14443_3aErrorNone; bool activated = false; do { error = nfc_iso13444a_short_frame( - instance->nfc, NfcIso14443aShortFrameSensReq, instance->rx_buffer, NFCA_FDT_LISTEN_FC); + instance->nfc, + NfcIso14443aShortFrameSensReq, + instance->rx_buffer, + ISO14443_3A_FDT_LISTEN_FC); if(error != NfcErrorNone) { - ret = NfcaErrorNotPresent; + ret = Iso14443_3aErrorNotPresent; break; } if(bit_buffer_get_size_bytes(instance->rx_buffer) != sizeof(instance->col_res.sens_resp)) { FURI_LOG_W(TAG, "Wrong sens response size"); - ret = NfcaErrorCommunication; + ret = Iso14443_3aErrorCommunication; break; } bit_buffer_write_bytes( @@ -178,38 +149,43 @@ NfcaError nfca_poller_async_activate(NfcaPoller* instance, NfcaData* nfca_data) &instance->col_res.sens_resp, sizeof(instance->col_res.sel_resp)); - instance->state = NfcaPollerStateColResInProgress; + instance->state = Iso14443_3aPollerStateColResInProgress; instance->col_res.cascade_level = 0; - instance->col_res.state = NfcaPollerColResStateStateNewCascade; + instance->col_res.state = Iso14443_3aPollerColResStateStateNewCascade; - while(instance->state == NfcaPollerStateColResInProgress) { - if(instance->col_res.state == NfcaPollerColResStateStateNewCascade) { + while(instance->state == Iso14443_3aPollerStateColResInProgress) { + if(instance->col_res.state == Iso14443_3aPollerColResStateStateNewCascade) { bit_buffer_set_size_bytes(instance->tx_buffer, 2); bit_buffer_set_byte( - instance->tx_buffer, 0, NFCA_POLLER_SEL_CMD(instance->col_res.cascade_level)); - bit_buffer_set_byte(instance->tx_buffer, 1, NFCA_POLLER_SEL_PAR(2, 0)); + instance->tx_buffer, + 0, + ISO14443_3A_POLLER_SEL_CMD(instance->col_res.cascade_level)); + bit_buffer_set_byte(instance->tx_buffer, 1, ISO14443_3A_POLLER_SEL_PAR(2, 0)); error = nfc_iso13444a_sdd_frame( - instance->nfc, instance->tx_buffer, instance->rx_buffer, NFCA_FDT_LISTEN_FC); + instance->nfc, + instance->tx_buffer, + instance->rx_buffer, + ISO14443_3A_FDT_LISTEN_FC); if(error != NfcErrorNone) { FURI_LOG_E(TAG, "Sdd request failed: %d", error); - instance->state = NfcaPollerStateColResFailed; - ret = NfcaErrorColResFailed; + instance->state = Iso14443_3aPollerStateColResFailed; + ret = Iso14443_3aErrorColResFailed; break; } if(bit_buffer_get_size_bytes(instance->rx_buffer) != 5) { FURI_LOG_E(TAG, "Sdd response wrong length"); - instance->state = NfcaPollerStateColResFailed; - ret = NfcaErrorColResFailed; + instance->state = Iso14443_3aPollerStateColResFailed; + ret = Iso14443_3aErrorColResFailed; break; } // TODO BCC check here bit_buffer_write_bytes( - instance->rx_buffer, &instance->col_res.sdd_resp, sizeof(NfcaSddResp)); - instance->col_res.state = NfcaPollerColResStateStateSelectCascade; - } else if(instance->col_res.state == NfcaPollerColResStateStateSelectCascade) { + instance->rx_buffer, &instance->col_res.sdd_resp, sizeof(Iso14443_3aSddResp)); + instance->col_res.state = Iso14443_3aPollerColResStateStateSelectCascade; + } else if(instance->col_res.state == Iso14443_3aPollerColResStateStateSelectCascade) { instance->col_res.sel_req.sel_cmd = - NFCA_POLLER_SEL_CMD(instance->col_res.cascade_level); - instance->col_res.sel_req.sel_par = NFCA_POLLER_SEL_PAR(7, 0); + ISO14443_3A_POLLER_SEL_CMD(instance->col_res.cascade_level); + instance->col_res.sel_req.sel_par = ISO14443_3A_POLLER_SEL_PAR(7, 0); memcpy( instance->col_res.sel_req.nfcid, instance->col_res.sdd_resp.nfcid, @@ -219,19 +195,19 @@ NfcaError nfca_poller_async_activate(NfcaPoller* instance, NfcaData* nfca_data) instance->tx_buffer, (uint8_t*)&instance->col_res.sel_req, sizeof(instance->col_res.sel_req)); - ret = nfca_poller_send_standart_frame( - instance, instance->tx_buffer, instance->rx_buffer, NFCA_FDT_LISTEN_FC); - if(ret != NfcaErrorNone) { + ret = iso14443_3a_poller_send_standart_frame( + instance, instance->tx_buffer, instance->rx_buffer, ISO14443_3A_FDT_LISTEN_FC); + if(ret != Iso14443_3aErrorNone) { FURI_LOG_E(TAG, "Sel request failed: %d", ret); - instance->state = NfcaPollerStateColResFailed; - ret = NfcaErrorColResFailed; + instance->state = Iso14443_3aPollerStateColResFailed; + ret = Iso14443_3aErrorColResFailed; break; } if(bit_buffer_get_size_bytes(instance->rx_buffer) != sizeof(instance->col_res.sel_resp)) { FURI_LOG_E(TAG, "Sel response wrong length"); - instance->state = NfcaPollerStateColResFailed; - ret = NfcaErrorColResFailed; + instance->state = Iso14443_3aPollerStateColResFailed; + ret = Iso14443_3aErrorColResFailed; break; } bit_buffer_write_bytes( @@ -239,7 +215,7 @@ NfcaError nfca_poller_async_activate(NfcaPoller* instance, NfcaData* nfca_data) &instance->col_res.sel_resp, sizeof(instance->col_res.sel_resp)); FURI_LOG_T(TAG, "Sel resp: %02X", instance->col_res.sel_resp.sak); - if(instance->col_res.sel_req.nfcid[0] == NFCA_POLLER_SDD_CL) { + if(instance->col_res.sel_req.nfcid[0] == ISO14443_3A_POLLER_SDD_CL) { // Copy part of UID memcpy( &instance->data->uid[instance->data->uid_len], @@ -247,7 +223,7 @@ NfcaError nfca_poller_async_activate(NfcaPoller* instance, NfcaData* nfca_data) 3); instance->data->uid_len += 3; instance->col_res.cascade_level++; - instance->col_res.state = NfcaPollerColResStateStateNewCascade; + instance->col_res.state = Iso14443_3aPollerColResStateStateNewCascade; } else { FURI_LOG_T(TAG, "Col resolution complete"); instance->data->sak = instance->col_res.sel_resp.sak; @@ -256,24 +232,24 @@ NfcaError nfca_poller_async_activate(NfcaPoller* instance, NfcaData* nfca_data) &instance->col_res.sel_req.nfcid[0], 4); instance->data->uid_len += 4; - instance->col_res.state = NfcaPollerColResStateStateSuccess; - instance->state = NfcaPollerStateActivated; + instance->col_res.state = Iso14443_3aPollerColResStateStateSuccess; + instance->state = Iso14443_3aPollerStateActivated; } } } - activated = (instance->state == NfcaPollerStateActivated); + activated = (instance->state == Iso14443_3aPollerStateActivated); } while(false); - if(activated && nfca_data) { - *nfca_data = *instance->data; + if(activated && iso14443_3a_data) { + *iso14443_3a_data = *instance->data; } return ret; } -NfcaError nfca_poller_txrx_custom_parity( - NfcaPoller* instance, +Iso14443_3aError iso14443_3a_poller_txrx_custom_parity( + Iso14443_3aPoller* instance, const BitBuffer* tx_buffer, BitBuffer* rx_buffer, uint32_t fwt) { @@ -281,16 +257,16 @@ NfcaError nfca_poller_txrx_custom_parity( furi_assert(tx_buffer); furi_assert(rx_buffer); - NfcaError ret = NfcaErrorNone; + Iso14443_3aError ret = Iso14443_3aErrorNone; NfcError error = NfcErrorNone; do { - ret = nfca_poller_prepare_trx(instance); - if(ret != NfcaErrorNone) break; + ret = iso14443_3a_poller_prepare_trx(instance); + if(ret != Iso14443_3aErrorNone) break; error = nfc_trx_custom_parity(instance->nfc, tx_buffer, rx_buffer, fwt); if(error != NfcErrorNone) { - ret = nfca_poller_process_error(error); + ret = iso14443_3a_poller_process_error(error); break; } } while(false); @@ -298,8 +274,8 @@ NfcaError nfca_poller_txrx_custom_parity( return ret; } -NfcaError nfca_poller_txrx( - NfcaPoller* instance, +Iso14443_3aError iso14443_3a_poller_txrx( + Iso14443_3aPoller* instance, const BitBuffer* tx_buffer, BitBuffer* rx_buffer, uint32_t fwt) { @@ -307,16 +283,16 @@ NfcaError nfca_poller_txrx( furi_assert(tx_buffer); furi_assert(rx_buffer); - NfcaError ret = NfcaErrorNone; + Iso14443_3aError ret = Iso14443_3aErrorNone; NfcError error = NfcErrorNone; do { - ret = nfca_poller_prepare_trx(instance); - if(ret != NfcaErrorNone) break; + ret = iso14443_3a_poller_prepare_trx(instance); + if(ret != Iso14443_3aErrorNone) break; error = nfc_trx(instance->nfc, tx_buffer, rx_buffer, fwt); if(error != NfcErrorNone) { - ret = nfca_poller_process_error(error); + ret = iso14443_3a_poller_process_error(error); break; } } while(false); @@ -324,8 +300,8 @@ NfcaError nfca_poller_txrx( return ret; } -NfcaError nfca_poller_send_standart_frame( - NfcaPoller* instance, +Iso14443_3aError iso14443_3a_poller_send_standart_frame( + Iso14443_3aPoller* instance, const BitBuffer* tx_buffer, BitBuffer* rx_buffer, uint32_t fwt) { @@ -333,14 +309,14 @@ NfcaError nfca_poller_send_standart_frame( furi_assert(tx_buffer); furi_assert(rx_buffer); - NfcaError ret = NfcaErrorNone; + Iso14443_3aError ret = Iso14443_3aErrorNone; do { - ret = nfca_poller_prepare_trx(instance); - if(ret != NfcaErrorNone) break; + ret = iso14443_3a_poller_prepare_trx(instance); + if(ret != Iso14443_3aErrorNone) break; - ret = nfca_poller_standart_frame_exchange(instance, tx_buffer, rx_buffer, fwt); - if(ret != NfcaErrorNone) break; + ret = iso14443_3a_poller_standart_frame_exchange(instance, tx_buffer, rx_buffer, fwt); + if(ret != Iso14443_3aErrorNone) break; } while(false); return ret; diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.h b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.h new file mode 100644 index 000000000000..9ae3cfb332ad --- /dev/null +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.h @@ -0,0 +1,93 @@ +#pragma once + +#include "iso14443_3a_poller.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define ISO14443_3A_POLLER_MAX_BUFFER_SIZE (512U) + +#define ISO14443_3A_POLLER_SEL_CMD(cascade_lvl) (0x93 + 2 * (cascade_lvl)) +#define ISO14443_3A_POLLER_SEL_PAR(bytes, bits) (((bytes) << 4 & 0xf0U) | ((bits)&0x0fU)) +#define ISO14443_3A_POLLER_SDD_CL (0x88U) + +typedef enum { + Iso14443_3aPollerColResStateStateIdle, + Iso14443_3aPollerColResStateStateNewCascade, + Iso14443_3aPollerColResStateStateSelectCascade, + Iso14443_3aPollerColResStateStateSuccess, + Iso14443_3aPollerColResStateStateFail, +} Iso14443_3aPollerColResState; + +typedef struct { + Iso14443_3aPollerColResState state; + Iso14443_3aSensResp sens_resp; + Iso14443_3aSddReq sdd_req; + Iso14443_3aSddResp sdd_resp; + Iso14443_3aSelReq sel_req; + Iso14443_3aSelResp sel_resp; + uint8_t cascade_level; +} Iso14443_3aPollerColRes; + +typedef enum { + Iso14443_3aPollerStateIdle, + Iso14443_3aPollerStateColResInProgress, + Iso14443_3aPollerStateColResFailed, + Iso14443_3aPollerStateActivated, +} Iso14443_3aPollerState; + +typedef enum { + Iso14443_3aPollerConfigStateIdle, + Iso14443_3aPollerConfigStateDone, +} Iso14443_3aPollerConfigState; + +struct Iso14443_3aPoller { + Nfc* nfc; + Iso14443_3aPollerState state; + Iso14443_3aPollerConfigState config_state; + Iso14443_3aPollerColRes col_res; + Iso14443_3aData* data; + BitBuffer* tx_buffer; + BitBuffer* rx_buffer; + + NfcPollerEvent general_event; + Iso14443_3aPollerEvent iso14443_3a_event; + Iso14443_3aPollerEventData iso14443_3a_event_data; + NfcPollerCallback callback; + void* context; +}; + +const Iso14443_3aData* iso14443_3a_poller_get_data(Iso14443_3aPoller* instance); + +Iso14443_3aError iso14443_3a_poller_check_presence(Iso14443_3aPoller* instance); + +Iso14443_3aError iso14443_3a_poller_async_activate( + Iso14443_3aPoller* instance, + Iso14443_3aData* iso14443_3a_data); + +Iso14443_3aError iso14443_3a_poller_halt(Iso14443_3aPoller* instance); + +Iso14443_3aError iso14443_3a_poller_txrx_custom_parity( + Iso14443_3aPoller* instance, + const BitBuffer* tx_buffer, + BitBuffer* rx_buffer, + uint32_t fwt); + +Iso14443_3aError iso14443_3a_poller_txrx( + Iso14443_3aPoller* instance, + const BitBuffer* tx_buffer, + BitBuffer* rx_buffer, + uint32_t fwt); + +Iso14443_3aError iso14443_3a_poller_send_standart_frame( + Iso14443_3aPoller* instance, + const BitBuffer* tx_buffer, + BitBuffer* rx_buffer, + uint32_t fwt); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_sync_api.c b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_sync_api.c new file mode 100644 index 000000000000..1edb4454a9f0 --- /dev/null +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_sync_api.c @@ -0,0 +1,58 @@ +#include "iso14443_3a_poller_sync_api.h" + +#include "iso14443_3a_poller_i.h" +#include + +#include + +#define ISO14443_3A_POLLER_FLAG_COMMAND_COMPLETE (1UL << 0) + +typedef struct { + Iso14443_3aPoller* instance; + FuriThreadId thread_id; + Iso14443_3aError error; + Iso14443_3aData data; +} Iso14443_3aPollerContext; + +NfcCommand iso14443_3a_poller_read_callback(NfcPollerEvent event, void* context) { + furi_assert(context); + furi_assert(event.data); + furi_assert(event.poller); + furi_assert(event.protocol == NfcProtocolIso14443_3a); + + Iso14443_3aPollerContext* poller_context = context; + Iso14443_3aPoller* iso14443_3a_poller = event.poller; + Iso14443_3aPollerEvent* iso14443_3a_event = event.data; + + if(iso14443_3a_event->type == Iso14443_3aPollerEventTypeReady) { + iso14443_3a_copy(&poller_context->data, iso14443_3a_poller->data); + } + poller_context->error = iso14443_3a_event->data->error; + + furi_thread_flags_set(poller_context->thread_id, ISO14443_3A_POLLER_FLAG_COMMAND_COMPLETE); + + return NfcCommandStop; +} + +Iso14443_3aError iso14443_3a_poller_read(Nfc* nfc, Iso14443_3aData* iso14443_3a_data) { + furi_assert(nfc); + furi_assert(iso14443_3a_data); + + Iso14443_3aPollerContext poller_context = {}; + poller_context.thread_id = furi_thread_get_current_id(); + + NfcPoller* poller = nfc_poller_alloc(nfc, NfcProtocolIso14443_3a); + nfc_poller_start(poller, iso14443_3a_poller_read_callback, &poller_context); + furi_thread_flags_wait( + ISO14443_3A_POLLER_FLAG_COMMAND_COMPLETE, FuriFlagWaitAny, FuriWaitForever); + furi_thread_flags_clear(ISO14443_3A_POLLER_FLAG_COMMAND_COMPLETE); + + nfc_poller_stop(poller); + nfc_poller_free(poller); + + if(poller_context.error == Iso14443_3aErrorNone) { + *iso14443_3a_data = poller_context.data; + } + + return poller_context.error; +} \ No newline at end of file diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_sync_api.h b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_sync_api.h new file mode 100644 index 000000000000..ed17ff43244d --- /dev/null +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_sync_api.h @@ -0,0 +1,14 @@ +#pragma once + +#include "iso14443_3a.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +Iso14443_3aError iso14443_3a_poller_read(Nfc* nfc, Iso14443_3aData* iso14443_3a_data); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a.c b/lib/nfc/protocols/iso14443_4a/iso14443_4a.c index 472c5b5fd690..bce0e4e3f125 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a.c +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a.c @@ -6,23 +6,23 @@ #define ISO14443_4A_DEVICE_NAME "Unknown ISO14443-4A Tag" #define ISO14443_4A_ATS_BIT (1 << 5) -const NfcProtocolBase nfc_protocol_iso14443_4a = { +const NfcDeviceBase nfc_device_iso14443_4a = { .protocol_name = ISO14443_4A_PROTOCOL_NAME, - .alloc = (NfcProtocolAlloc)iso14443_4a_alloc, - .free = (NfcProtocolFree)iso14443_4a_free, - .reset = (NfcProtocolReset)iso14443_4a_reset, - .copy = (NfcProtocolCopy)iso14443_4a_copy, - .verify = (NfcProtocolVerify)iso14443_4a_verify, - .load = (NfcProtocolLoad)iso14443_4a_load, - .save = (NfcProtocolSave)iso14443_4a_save, - .is_equal = (NfcProtocolEqual)iso14443_4a_is_equal, - .get_device_name = (NfcProtocolGetDeviceName)iso14443_4a_get_device_name, - .get_uid = (NfcProtocolGetUid)iso14443_4a_get_uid, + .alloc = (NfcDeviceAlloc)iso14443_4a_alloc, + .free = (NfcDeviceFree)iso14443_4a_free, + .reset = (NfcDeviceReset)iso14443_4a_reset, + .copy = (NfcDeviceCopy)iso14443_4a_copy, + .verify = (NfcDeviceVerify)iso14443_4a_verify, + .load = (NfcDeviceLoad)iso14443_4a_load, + .save = (NfcDeviceSave)iso14443_4a_save, + .is_equal = (NfcDeviceEqual)iso14443_4a_is_equal, + .get_name = (NfcDeviceGetName)iso14443_4a_get_device_name, + .get_uid = (NfcDeviceGetUid)iso14443_4a_get_uid, }; Iso14443_4aData* iso14443_4a_alloc() { Iso14443_4aData* data = malloc(sizeof(Iso14443_4aData)); - data->iso14443_3a_data = nfca_alloc(); + data->iso14443_3a_data = iso14443_3a_alloc(); return data; } @@ -30,21 +30,21 @@ Iso14443_4aData* iso14443_4a_alloc() { void iso14443_4a_free(Iso14443_4aData* data) { furi_assert(data); - nfca_free(data->iso14443_3a_data); + iso14443_3a_free(data->iso14443_3a_data); free(data); } void iso14443_4a_reset(Iso14443_4aData* data) { furi_assert(data); - nfca_reset(data->iso14443_3a_data); + iso14443_3a_reset(data->iso14443_3a_data); } void iso14443_4a_copy(Iso14443_4aData* data, const Iso14443_4aData* other) { furi_assert(data); furi_assert(other); - nfca_copy(data->iso14443_3a_data, other->iso14443_3a_data); + iso14443_3a_copy(data->iso14443_3a_data, other->iso14443_3a_data); data->ats_data = other->ats_data; } @@ -75,21 +75,20 @@ bool iso14443_4a_save(const Iso14443_4aData* data, FlipperFormat* ff, uint32_t v } bool iso14443_4a_is_equal(const Iso14443_4aData* data, const Iso14443_4aData* other) { - return nfca_is_equal(data->iso14443_3a_data, other->iso14443_3a_data); + return iso14443_3a_is_equal(data->iso14443_3a_data, other->iso14443_3a_data); } -const char* - iso14443_4a_get_device_name(const Iso14443_4aData* data, NfcProtocolNameType name_type) { +const char* iso14443_4a_get_device_name(const Iso14443_4aData* data, NfcDeviceNameType name_type) { UNUSED(data); UNUSED(name_type); return ISO14443_4A_DEVICE_NAME; } const uint8_t* iso14443_4a_get_uid(const Iso14443_4aData* data, size_t* uid_len) { - return nfca_get_uid(data->iso14443_3a_data, uid_len); + return iso14443_3a_get_uid(data->iso14443_3a_data, uid_len); } bool iso14443_4a_is_ats_supported(const Iso14443_4aData* data) { - const NfcaData* iso14443_3a_data = data->iso14443_3a_data; + const Iso14443_3aData* iso14443_3a_data = data->iso14443_3a_data; return iso14443_3a_data->sak & ISO14443_4A_ATS_BIT; } diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a.h b/lib/nfc/protocols/iso14443_4a/iso14443_4a.h index 51e8e8f54dd9..5c7d8c7e0a85 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a.h +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #ifdef __cplusplus extern "C" { @@ -25,11 +25,11 @@ typedef struct { } Iso14443_4aAtsData; typedef struct { - NfcaData* iso14443_3a_data; + Iso14443_3aData* iso14443_3a_data; Iso14443_4aAtsData ats_data; } Iso14443_4aData; -extern const NfcProtocolBase nfc_protocol_iso14443_4a; +extern const NfcDeviceBase nfc_device_iso14443_4a; // Virtual methods @@ -49,8 +49,7 @@ bool iso14443_4a_save(const Iso14443_4aData* data, FlipperFormat* ff, uint32_t v bool iso14443_4a_is_equal(const Iso14443_4aData* data, const Iso14443_4aData* other); -const char* - iso14443_4a_get_device_name(const Iso14443_4aData* data, NfcProtocolNameType name_type); +const char* iso14443_4a_get_device_name(const Iso14443_4aData* data, NfcDeviceNameType name_type); const uint8_t* iso14443_4a_get_uid(const Iso14443_4aData* data, size_t* uid_len); diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.c b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.c index fae3638362ba..79305ee6005b 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.c +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.c @@ -16,7 +16,7 @@ const Iso14443_4aData* iso14443_4a_poller_get_data(Iso14443_4aPoller* instance) return instance->data; } -static Iso14443_4aPoller* iso14443_4a_poller_alloc(NfcaPoller* iso14443_3a_poller) { +static Iso14443_4aPoller* iso14443_4a_poller_alloc(Iso14443_3aPoller* iso14443_3a_poller) { Iso14443_4aPoller* instance = malloc(sizeof(Iso14443_4aPoller)); instance->iso14443_3a_poller = iso14443_3a_poller; instance->data = iso14443_4a_alloc(); @@ -25,7 +25,7 @@ static Iso14443_4aPoller* iso14443_4a_poller_alloc(NfcaPoller* iso14443_3a_polle instance->iso14443_4a_event.data = &instance->iso14443_4a_event_data; - instance->general_event.protocol_type = NfcProtocolTypeIso14443_4a; + instance->general_event.protocol = NfcProtocolIso14443_4a; instance->general_event.data = &instance->iso14443_4a_event; instance->general_event.poller = instance; @@ -42,8 +42,9 @@ static void iso14443_4a_poller_free(Iso14443_4aPoller* instance) { } static NfcCommand iso14443_4a_poller_handler_idle(Iso14443_4aPoller* instance) { - nfca_copy( - instance->data->iso14443_3a_data, nfca_poller_get_data(instance->iso14443_3a_poller)); + iso14443_3a_copy( + instance->data->iso14443_3a_data, + iso14443_3a_poller_get_data(instance->iso14443_3a_poller)); instance->poller_state = Iso14443_4aPollerStateReadAts; instance->protocol_state.block_number = 0; @@ -65,7 +66,7 @@ static NfcCommand iso14443_4a_poller_handler_read_ats(Iso14443_4aPoller* instanc } static NfcCommand iso14443_4a_poller_handler_error(Iso14443_4aPoller* instance) { - nfca_poller_halt(instance->iso14443_3a_poller); + iso14443_3a_poller_halt(instance->iso14443_3a_poller); instance->iso14443_4a_event_data.error = instance->error; NfcCommand command = instance->callback(instance->general_event, instance->context); instance->poller_state = Iso14443_4aPollerStateIdle; @@ -98,20 +99,20 @@ static void iso14443_4a_poller_set_callback( } static NfcCommand iso14443_4a_poller_run(NfcPollerEvent event, void* context) { - furi_assert(event.protocol_type == NfcProtocolTypeIso14443_3a); + furi_assert(event.protocol == NfcProtocolIso14443_3a); Iso14443_4aPoller* instance = context; furi_assert(instance); furi_assert(instance->callback); - NfcaPollerEvent* iso14443_3a_event = event.data; + Iso14443_3aPollerEvent* iso14443_3a_event = event.data; furi_assert(iso14443_3a_event); NfcCommand command = NfcCommandContinue; - if(iso14443_3a_event->type == NfcaPollerEventTypeReady) { + if(iso14443_3a_event->type == Iso14443_3aPollerEventTypeReady) { command = iso14443_4a_poller_state_handler[instance->poller_state](instance); - } else if(iso14443_3a_event->type == NfcaPollerEventTypeError) { + } else if(iso14443_3a_event->type == Iso14443_3aPollerEventTypeError) { instance->iso14443_4a_event.type = Iso14443_4aPollerEventTypeError; command = instance->callback(instance->general_event, instance->context); } @@ -120,19 +121,20 @@ static NfcCommand iso14443_4a_poller_run(NfcPollerEvent event, void* context) { } static bool iso14443_4a_poller_detect(NfcPollerEvent event, void* context) { - furi_assert(event.protocol_type == NfcProtocolTypeIso14443_3a); + furi_assert(event.protocol == NfcProtocolIso14443_3a); const Iso14443_4aPoller* instance = context; furi_assert(instance); - const NfcaPollerEvent* iso14443_3a_event = event.data; + const Iso14443_3aPollerEvent* iso14443_3a_event = event.data; furi_assert(iso14443_3a_event); - nfca_copy( - instance->data->iso14443_3a_data, nfca_poller_get_data(instance->iso14443_3a_poller)); + iso14443_3a_copy( + instance->data->iso14443_3a_data, + iso14443_3a_poller_get_data(instance->iso14443_3a_poller)); bool protocol_detected = false; - if(iso14443_3a_event->type == NfcaPollerEventTypeReady) { + if(iso14443_3a_event->type == Iso14443_3aPollerEventTypeReady) { protocol_detected = iso14443_4a_is_ats_supported(instance->data); } diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.h b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.h index 224e1469aac8..b224299e0a73 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.h +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include "iso14443_4a.h" diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c index f948c0ea639a..8f51d6a599e3 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c @@ -8,17 +8,17 @@ #define ISO14443_4A_PCB_I (0x02) -Iso14443_4aError iso14443_4a_poller_process_error(NfcaError error) { +Iso14443_4aError iso14443_4a_poller_process_error(Iso14443_3aError error) { switch(error) { - case NfcaErrorNone: + case Iso14443_3aErrorNone: return Iso14443_4aErrorNone; - case NfcaErrorNotPresent: + case Iso14443_3aErrorNotPresent: return Iso14443_4aErrorNotPresent; - case NfcaErrorColResFailed: - case NfcaErrorCommunication: - case NfcaErrorWrongCrc: + case Iso14443_3aErrorColResFailed: + case Iso14443_3aErrorCommunication: + case Iso14443_3aErrorWrongCrc: return Iso14443_4aErrorProtocol; - case NfcaErrorTimeout: + case Iso14443_3aErrorTimeout: return Iso14443_4aErrorTimeout; default: return Iso14443_4aErrorProtocol; @@ -28,7 +28,7 @@ Iso14443_4aError iso14443_4a_poller_process_error(NfcaError error) { Iso14443_4aError iso14443_4a_poller_halt(Iso14443_4aPoller* instance) { furi_assert(instance); - nfca_poller_halt(instance->iso14443_3a_poller); + iso14443_3a_poller_halt(instance->iso14443_3a_poller); instance->poller_state = Iso14443_4aPollerStateIdle; return Iso14443_4aErrorNone; @@ -45,13 +45,13 @@ Iso14443_4aError Iso14443_4aError error = Iso14443_4aErrorNone; do { - const NfcaError iso14443_3a_error = nfca_poller_send_standart_frame( + const Iso14443_3aError iso14443_3a_error = iso14443_3a_poller_send_standart_frame( instance->iso14443_3a_poller, instance->tx_buffer, instance->rx_buffer, ISO14443_4A_POLLER_ATS_FWT_FC); - if(iso14443_3a_error != NfcaErrorNone) { + if(iso14443_3a_error != Iso14443_3aErrorNone) { FURI_LOG_E(TAG, "ATS request failed"); error = iso14443_4a_poller_process_error(iso14443_3a_error); break; @@ -84,10 +84,10 @@ Iso14443_4aError iso14443_4a_poller_send_block( Iso14443_4aError error = Iso14443_4aErrorNone; do { - NfcaError iso14443_3a_error = nfca_poller_send_standart_frame( + Iso14443_3aError iso14443_3a_error = iso14443_3a_poller_send_standart_frame( instance->iso14443_3a_poller, instance->tx_buffer, instance->rx_buffer, fwt); - if(iso14443_3a_error != NfcaErrorNone) { + if(iso14443_3a_error != Iso14443_3aErrorNone) { error = iso14443_4a_poller_process_error(iso14443_3a_error); break; diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.h b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.h index d25e7efac3d2..47ba6a69dde7 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.h +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include "iso14443_4a_poller.h" @@ -30,7 +30,7 @@ typedef struct { } Iso14443_4aPollerProtocolState; struct Iso14443_4aPoller { - NfcaPoller* iso14443_3a_poller; + Iso14443_3aPoller* iso14443_3a_poller; Iso14443_4aPollerState poller_state; Iso14443_4aPollerSessionState session_state; Iso14443_4aPollerProtocolState protocol_state; @@ -45,7 +45,7 @@ struct Iso14443_4aPoller { void* context; }; -Iso14443_4aError iso14443_4a_poller_process_error(NfcaError error); +Iso14443_4aError iso14443_4a_poller_process_error(Iso14443_3aError error); const Iso14443_4aData* iso14443_4a_poller_get_data(Iso14443_4aPoller* instance); diff --git a/lib/nfc/protocols/mf_classic/mf_classic.c b/lib/nfc/protocols/mf_classic/mf_classic.c index fc2fa39a9cac..034d785a527e 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic.c +++ b/lib/nfc/protocols/mf_classic/mf_classic.c @@ -40,44 +40,44 @@ static const MfClassicFeatures mf_classic_features[MfClassicTypeNum] = { }, }; -const NfcProtocolBase nfc_protocol_mf_classic = { +const NfcDeviceBase nfc_device_mf_classic = { .protocol_name = MF_CLASSIC_PROTOCOL_NAME, - .alloc = (NfcProtocolAlloc)mf_classic_alloc, - .free = (NfcProtocolFree)mf_classic_free, - .reset = (NfcProtocolReset)mf_classic_reset, - .copy = (NfcProtocolCopy)mf_classic_copy, - .verify = (NfcProtocolVerify)mf_classic_verify, - .load = (NfcProtocolLoad)mf_classic_load, - .save = (NfcProtocolSave)mf_classic_save, - .is_equal = (NfcProtocolEqual)mf_classic_is_equal, - .get_device_name = (NfcProtocolGetDeviceName)mf_classic_get_device_name, - .get_uid = (NfcProtocolGetUid)mf_classic_get_uid, + .alloc = (NfcDeviceAlloc)mf_classic_alloc, + .free = (NfcDeviceFree)mf_classic_free, + .reset = (NfcDeviceReset)mf_classic_reset, + .copy = (NfcDeviceCopy)mf_classic_copy, + .verify = (NfcDeviceVerify)mf_classic_verify, + .load = (NfcDeviceLoad)mf_classic_load, + .save = (NfcDeviceSave)mf_classic_save, + .is_equal = (NfcDeviceEqual)mf_classic_is_equal, + .get_name = (NfcDeviceGetName)mf_classic_get_device_name, + .get_uid = (NfcDeviceGetUid)mf_classic_get_uid, }; MfClassicData* mf_classic_alloc() { MfClassicData* data = malloc(sizeof(MfClassicData)); - data->nfca_data = nfca_alloc(); + data->iso14443_3a_data = iso14443_3a_alloc(); return data; } void mf_classic_free(MfClassicData* data) { furi_assert(data); - nfca_free(data->nfca_data); + iso14443_3a_free(data->iso14443_3a_data); free(data); } void mf_classic_reset(MfClassicData* data) { furi_assert(data); - nfca_reset(data->nfca_data); + iso14443_3a_reset(data->iso14443_3a_data); } void mf_classic_copy(MfClassicData* data, const MfClassicData* other) { furi_assert(data); furi_assert(other); - nfca_copy(data->nfca_data, other->nfca_data); + iso14443_3a_copy(data->iso14443_3a_data, other->iso14443_3a_data); memcpy(data->block, other->block, MF_CLASSIC_TOTAL_BLOCKS_MAX); memcpy(data->block_read_mask, other->block_read_mask, MF_CLASSIC_READ_MASK_SIZE); @@ -145,8 +145,8 @@ bool mf_classic_load(MfClassicData* data, FlipperFormat* ff, uint32_t version) { bool parsed = false; do { - // Read NFCA data - if(!nfca_load_data(data->nfca_data, ff, version)) break; + // Read ISO14443_3A data + if(!iso14443_3a_load_data(data->iso14443_3a_data, ff, version)) break; // Read Mifare Classic type if(!flipper_format_read_string(ff, "Mifare Classic type", temp_str)) break; @@ -256,7 +256,7 @@ bool mf_classic_save(const MfClassicData* data, FlipperFormat* ff, uint32_t vers do { if(!flipper_format_write_string_cstr(ff, "Device type", "Mifare Classic")) break; - if(!nfca_save_data(data->nfca_data, ff, version)) break; + if(!iso14443_3a_save_data(data->iso14443_3a_data, ff, version)) break; if(!flipper_format_write_string_cstr(ff, "Device type", "")) break; if(!flipper_format_write_comment_cstr(ff, "Mifare Classic specific data")) break; if(!flipper_format_write_string_cstr( @@ -293,14 +293,14 @@ bool mf_classic_save(const MfClassicData* data, FlipperFormat* ff, uint32_t vers bool mf_classic_is_equal(const MfClassicData* data, const MfClassicData* other) { // TODO: Complete equality method - return nfca_is_equal(data->nfca_data, other->nfca_data); + return iso14443_3a_is_equal(data->iso14443_3a_data, other->iso14443_3a_data); } -const char* mf_classic_get_device_name(const MfClassicData* data, NfcProtocolNameType name_type) { +const char* mf_classic_get_device_name(const MfClassicData* data, NfcDeviceNameType name_type) { furi_assert(data); furi_assert(data->type < MfClassicTypeNum); - if(name_type == NfcProtocolNameTypeFull) { + if(name_type == NfcDeviceNameTypeFull) { return mf_classic_features[data->type].full_name; } else { return mf_classic_features[data->type].type_name; @@ -310,7 +310,7 @@ const char* mf_classic_get_device_name(const MfClassicData* data, NfcProtocolNam const uint8_t* mf_classic_get_uid(const MfClassicData* data, size_t* uid_len) { furi_assert(data); - return nfca_get_uid(data->nfca_data, uid_len); + return iso14443_3a_get_uid(data->iso14443_3a_data, uid_len); } uint8_t mf_classic_get_total_sectors_num(MfClassicType type) { @@ -321,7 +321,7 @@ uint16_t mf_classic_get_total_block_num(MfClassicType type) { return mf_classic_features[type].blocks_total; } -bool mf_classic_detect_protocol(NfcaData* data, MfClassicType* type) { +bool mf_classic_detect_protocol(Iso14443_3aData* data, MfClassicType* type) { furi_assert(data); uint8_t atqa0 = data->atqa[0]; diff --git a/lib/nfc/protocols/mf_classic/mf_classic.h b/lib/nfc/protocols/mf_classic/mf_classic.h index 01ae04f2b778..8ceba0fc6fc1 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic.h +++ b/lib/nfc/protocols/mf_classic/mf_classic.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #ifdef __cplusplus extern "C" { @@ -111,7 +111,7 @@ typedef struct { } MfClassicDeviceKeys; typedef struct { - NfcaData* nfca_data; + Iso14443_3aData* iso14443_3a_data; MfClassicType type; uint32_t block_read_mask[MF_CLASSIC_READ_MASK_SIZE]; uint64_t key_a_mask; @@ -119,7 +119,7 @@ typedef struct { MfClassicBlock block[MF_CLASSIC_TOTAL_BLOCKS_MAX]; } MfClassicData; -extern const NfcProtocolBase nfc_protocol_mf_classic; +extern const NfcDeviceBase nfc_device_mf_classic; MfClassicData* mf_classic_alloc(); @@ -137,11 +137,11 @@ bool mf_classic_save(const MfClassicData* data, FlipperFormat* ff, uint32_t vers bool mf_classic_is_equal(const MfClassicData* data, const MfClassicData* other); -const char* mf_classic_get_device_name(const MfClassicData* data, NfcProtocolNameType name_type); +const char* mf_classic_get_device_name(const MfClassicData* data, NfcDeviceNameType name_type); const uint8_t* mf_classic_get_uid(const MfClassicData* data, size_t* uid_len); -bool mf_classic_detect_protocol(NfcaData* data, MfClassicType* type); +bool mf_classic_detect_protocol(Iso14443_3aData* data, MfClassicType* type); uint8_t mf_classic_get_total_sectors_num(MfClassicType type); diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller.c b/lib/nfc/protocols/mf_classic/mf_classic_poller.c index b2a2f8aa7bbf..f44808ddc609 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller.c @@ -10,11 +10,11 @@ typedef NfcCommand (*MfClassicPollerReadHandler)(MfClassicPoller* instance); -MfClassicPoller* mf_classic_poller_alloc(NfcaPoller* nfca_poller) { - furi_assert(nfca_poller); +MfClassicPoller* mf_classic_poller_alloc(Iso14443_3aPoller* iso14443_3a_poller) { + furi_assert(iso14443_3a_poller); MfClassicPoller* instance = malloc(sizeof(MfClassicPoller)); - instance->nfca_poller = nfca_poller; + instance->iso14443_3a_poller = iso14443_3a_poller; instance->data = mf_classic_alloc(); instance->crypto = crypto1_alloc(); instance->tx_plain_buffer = bit_buffer_alloc(MF_CLASSIC_MAX_BUFF_SIZE); @@ -24,7 +24,7 @@ MfClassicPoller* mf_classic_poller_alloc(NfcaPoller* nfca_poller) { instance->mfc_event.data = &instance->mfc_event_data; - instance->general_event.protocol_type = NfcProtocolTypeMfClassic; + instance->general_event.protocol = NfcProtocolMfClassic; instance->general_event.data = &instance->mfc_event; instance->general_event.poller = instance; @@ -51,10 +51,12 @@ void mf_classic_poller_free(MfClassicPoller* instance) { } NfcCommand mf_classic_poller_handler_idle(MfClassicPoller* instance) { - nfca_copy(instance->data->nfca_data, nfca_poller_get_data(instance->nfca_poller)); + iso14443_3a_copy( + instance->data->iso14443_3a_data, + iso14443_3a_poller_get_data(instance->iso14443_3a_poller)); NfcCommand command = NfcCommandContinue; - if(mf_classic_detect_protocol(instance->data->nfca_data, &instance->data->type)) { + if(mf_classic_detect_protocol(instance->data->iso14443_3a_data, &instance->data->type)) { if(instance->card_state == MfClassicCardStateNotDetected) { instance->card_state = MfClassicCardStateDetected; instance->mfc_event.type = MfClassicPollerEventTypeCardDetected; @@ -278,17 +280,17 @@ static const MfClassicPollerReadHandler NfcCommand mf_classsic_poller_run(NfcPollerEvent event, void* context) { furi_assert(event.data); - furi_assert(event.protocol_type == NfcProtocolTypeIso14443_3a); + furi_assert(event.protocol == NfcProtocolIso14443_3a); furi_assert(context); MfClassicPoller* instance = context; - NfcaPollerEvent* nfca_event = event.data; + Iso14443_3aPollerEvent* iso14443_3a_event = event.data; NfcCommand command = NfcCommandContinue; - if(nfca_event->type == NfcaPollerEventTypeReady) { + if(iso14443_3a_event->type == Iso14443_3aPollerEventTypeReady) { command = mf_classic_poller_dict_attack_handler[instance->state](instance); - } else if(nfca_event->type == NfcaPollerEventTypeError) { - if(nfca_event->data->error == NfcaErrorNotPresent) { + } else if(iso14443_3a_event->type == Iso14443_3aPollerEventTypeError) { + if(iso14443_3a_event->data->error == Iso14443_3aErrorNotPresent) { if(instance->card_state == MfClassicCardStateDetected) { instance->card_state = MfClassicCardStateNotDetected; instance->mfc_event.type = MfClassicPollerEventTypeCardNotDetected; @@ -303,7 +305,7 @@ NfcCommand mf_classsic_poller_run(NfcPollerEvent event, void* context) { bool mf_classsic_poller_detect(NfcPollerEvent event, void* context) { furi_assert(event.data); - furi_assert(event.protocol_type == NfcProtocolTypeIso14443_3a); + furi_assert(event.protocol == NfcProtocolIso14443_3a); furi_assert(context); return false; diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller.h b/lib/nfc/protocols/mf_classic/mf_classic_poller.h index ced38777c26d..4e2ae68ed633 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller.h +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller.h @@ -1,7 +1,7 @@ #pragma once #include "mf_classic.h" -#include +#include #ifdef __cplusplus extern "C" { diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c index bf9c94483c6d..e486764778e0 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c @@ -7,22 +7,22 @@ #define MF_CLASSIC_FWT_FC (60000) -MfClassicError mf_classic_process_error(NfcaError error) { +MfClassicError mf_classic_process_error(Iso14443_3aError error) { MfClassicError ret = MfClassicErrorNone; switch(error) { - case NfcaErrorNone: + case Iso14443_3aErrorNone: ret = MfClassicErrorNone; break; - case NfcaErrorNotPresent: + case Iso14443_3aErrorNotPresent: ret = MfClassicErrorNotPresent; break; - case NfcaErrorColResFailed: - case NfcaErrorCommunication: - case NfcaErrorWrongCrc: + case Iso14443_3aErrorColResFailed: + case Iso14443_3aErrorCommunication: + case Iso14443_3aErrorWrongCrc: ret = MfClassicErrorProtocol; break; - case NfcaErrorTimeout: + case Iso14443_3aErrorTimeout: ret = MfClassicErrorTimeout; break; default: @@ -40,21 +40,23 @@ MfClassicError mf_classic_async_auth( MfClassicKeyType key_type, MfClassicAuthContext* data) { MfClassicError ret = MfClassicErrorNone; - NfcaError error = NfcaErrorNone; + Iso14443_3aError error = Iso14443_3aErrorNone; do { - nfca_copy(instance->data->nfca_data, nfca_poller_get_data(instance->nfca_poller)); + iso14443_3a_copy( + instance->data->iso14443_3a_data, + iso14443_3a_poller_get_data(instance->iso14443_3a_poller)); uint8_t auth_type = (key_type == MfClassicKeyTypeB) ? MF_CLASSIC_AUTH_KEY_B_CMD : MF_CLASSIC_AUTH_KEY_A_CMD; uint8_t auth_cmd[2] = {auth_type, block_num}; bit_buffer_copy_bytes(instance->tx_plain_buffer, auth_cmd, sizeof(auth_cmd)); - error = nfca_poller_send_standart_frame( - instance->nfca_poller, + error = iso14443_3a_poller_send_standart_frame( + instance->iso14443_3a_poller, instance->tx_plain_buffer, instance->rx_plain_buffer, MF_CLASSIC_FWT_FC); - if(error != NfcaErrorWrongCrc) { + if(error != Iso14443_3aErrorWrongCrc) { ret = mf_classic_process_error(error); break; } @@ -68,20 +70,20 @@ MfClassicError mf_classic_async_auth( if(data) { data->nt = nt; } - uint32_t cuid = nfca_get_cuid(instance->data->nfca_data); + uint32_t cuid = iso14443_3a_get_cuid(instance->data->iso14443_3a_data); uint64_t key_num = nfc_util_bytes2num(key->data, sizeof(MfClassicKey)); MfClassicNr nr = {}; furi_hal_random_fill_buf(nr.data, sizeof(MfClassicNr)); crypto1_encrypt_reader_nonce( instance->crypto, key_num, cuid, nt.data, nr.data, instance->tx_encrypted_buffer); - error = nfca_poller_txrx_custom_parity( - instance->nfca_poller, + error = iso14443_3a_poller_txrx_custom_parity( + instance->iso14443_3a_poller, instance->tx_encrypted_buffer, instance->rx_encrypted_buffer, MF_CLASSIC_FWT_FC); - if(error != NfcaErrorNone) { + if(error != Iso14443_3aErrorNone) { ret = mf_classic_process_error(error); break; } @@ -102,7 +104,7 @@ MfClassicError mf_classic_async_auth( } while(false); if(ret != MfClassicErrorNone) { - nfca_poller_halt(instance->nfca_poller); + iso14443_3a_poller_halt(instance->iso14443_3a_poller); } return ret; @@ -110,27 +112,27 @@ MfClassicError mf_classic_async_auth( MfClassicError mf_classic_aync_halt(MfClassicPoller* instance) { MfClassicError ret = MfClassicErrorNone; - NfcaError error = NfcaErrorNone; + Iso14443_3aError error = Iso14443_3aErrorNone; do { uint8_t halt_cmd[2] = {MF_CLASSIC_HALT_MSB_CMD, MF_CLASSIC_HALT_LSB_CMD}; bit_buffer_copy_bytes(instance->tx_plain_buffer, halt_cmd, sizeof(halt_cmd)); - nfca_append_crc(instance->tx_plain_buffer); + iso14443_3a_append_crc(instance->tx_plain_buffer); crypto1_encrypt( instance->crypto, NULL, instance->tx_plain_buffer, instance->tx_encrypted_buffer); - error = nfca_poller_txrx_custom_parity( - instance->nfca_poller, + error = iso14443_3a_poller_txrx_custom_parity( + instance->iso14443_3a_poller, instance->tx_encrypted_buffer, instance->rx_encrypted_buffer, MF_CLASSIC_FWT_FC); - if(error != NfcaErrorTimeout) { + if(error != Iso14443_3aErrorTimeout) { ret = mf_classic_process_error(error); break; } instance->auth_state = MfClassicAuthStateIdle; - instance->nfca_poller->state = NfcaPollerStateIdle; + instance->iso14443_3a_poller->state = Iso14443_3aPollerStateIdle; } while(false); return ret; @@ -141,22 +143,22 @@ MfClassicError mf_classic_async_read_block( uint8_t block_num, MfClassicBlock* data) { MfClassicError ret = MfClassicErrorNone; - NfcaError error = NfcaErrorNone; + Iso14443_3aError error = Iso14443_3aErrorNone; do { uint8_t read_block_cmd[2] = {MF_CLASSIC_READ_BLOCK_CMD, block_num}; bit_buffer_copy_bytes(instance->tx_plain_buffer, read_block_cmd, sizeof(read_block_cmd)); - nfca_append_crc(instance->tx_plain_buffer); + iso14443_3a_append_crc(instance->tx_plain_buffer); crypto1_encrypt( instance->crypto, NULL, instance->tx_plain_buffer, instance->tx_encrypted_buffer); - error = nfca_poller_txrx_custom_parity( - instance->nfca_poller, + error = iso14443_3a_poller_txrx_custom_parity( + instance->iso14443_3a_poller, instance->tx_encrypted_buffer, instance->rx_encrypted_buffer, MF_CLASSIC_FWT_FC); - if(error != NfcaErrorNone) { + if(error != Iso14443_3aErrorNone) { ret = mf_classic_process_error(error); break; } @@ -169,13 +171,13 @@ MfClassicError mf_classic_async_read_block( crypto1_decrypt( instance->crypto, instance->rx_encrypted_buffer, instance->rx_plain_buffer); - if(!nfca_check_crc(instance->rx_plain_buffer)) { + if(!iso14443_3a_check_crc(instance->rx_plain_buffer)) { FURI_LOG_D(TAG, "CRC error"); ret = MfClassicErrorProtocol; break; } - nfca_trim_crc(instance->rx_plain_buffer); + iso14443_3a_trim_crc(instance->rx_plain_buffer); bit_buffer_write_bytes(instance->rx_plain_buffer, data->data, sizeof(MfClassicBlock)); } while(false); diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h index ff68153d9a05..2a232b685818 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h @@ -1,7 +1,7 @@ #pragma once #include "mf_classic_poller.h" -#include +#include #include #include "crypto1.h" @@ -38,7 +38,7 @@ typedef enum { } MfClassicPollerState; struct MfClassicPoller { - NfcaPoller* nfca_poller; + Iso14443_3aPoller* iso14443_3a_poller; MfClassicPollerState state; MfClassicPollerState prev_state; @@ -76,9 +76,9 @@ typedef union { MfClassicReadBlockContext read_block_context; } MfClassicPollerContextData; -MfClassicError mf_classic_process_error(NfcaError error); +MfClassicError mf_classic_process_error(Iso14443_3aError error); -MfClassicPoller* mf_classic_poller_alloc(NfcaPoller* nfca_poller); +MfClassicPoller* mf_classic_poller_alloc(Iso14443_3aPoller* iso14443_3a_poller); void mf_classic_poller_free(MfClassicPoller* instance); diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.c b/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.c index 5276af17a1e4..c3cc4a75cd4f 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.c @@ -59,20 +59,20 @@ static const MfClassicPollerCmdHandler mf_classic_poller_cmd_handlers[MfClassicP static NfcCommand mf_ultralgiht_poller_cmd_callback(NfcPollerEvent event, void* context) { furi_assert(event.poller); - furi_assert(event.protocol_type == NfcProtocolTypeIso14443_3a); + furi_assert(event.protocol == NfcProtocolIso14443_3a); furi_assert(event.data); furi_assert(context); MfClassicPollerContext* poller_context = context; - NfcaPollerEvent* nfca_event = event.data; - NfcaPoller* nfca_poller = event.poller; - MfClassicPoller* mfc_poller = mf_classic_poller_alloc(nfca_poller); + Iso14443_3aPollerEvent* iso14443_3a_event = event.data; + Iso14443_3aPoller* iso14443_3a_poller = event.poller; + MfClassicPoller* mfc_poller = mf_classic_poller_alloc(iso14443_3a_poller); - if(nfca_event->type == NfcaPollerEventTypeReady) { + if(iso14443_3a_event->type == Iso14443_3aPollerEventTypeReady) { poller_context->error = mf_classic_poller_cmd_handlers[poller_context->cmd_type]( mfc_poller, &poller_context->data); - } else if(nfca_event->type == NfcaPollerEventTypeError) { - poller_context->error = mf_classic_process_error(nfca_event->data->error); + } else if(iso14443_3a_event->type == Iso14443_3aPollerEventTypeError) { + poller_context->error = mf_classic_process_error(iso14443_3a_event->data->error); } furi_thread_flags_set(poller_context->thread_id, MF_CLASSIC_POLLER_COMPLETE_EVENT); @@ -87,7 +87,7 @@ static MfClassicError mf_classic_poller_cmd_execute(Nfc* nfc, MfClassicPollerCon poller_ctx->thread_id = furi_thread_get_current_id(); - NfcPoller* poller = nfc_poller_alloc(nfc, NfcProtocolTypeIso14443_3a); + NfcPoller* poller = nfc_poller_alloc(nfc, NfcProtocolIso14443_3a); nfc_poller_start(poller, mf_ultralgiht_poller_cmd_callback, poller_ctx); furi_thread_flags_wait(MF_CLASSIC_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); furi_thread_flags_clear(MF_CLASSIC_POLLER_COMPLETE_EVENT); diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire.c b/lib/nfc/protocols/mf_desfire/mf_desfire.c index ede0f2e266dc..84fe22ffba0e 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire.c +++ b/lib/nfc/protocols/mf_desfire/mf_desfire.c @@ -5,18 +5,18 @@ #define MF_DESFIRE_PROTOCOL_NAME "Mifare DESfire" #define MF_DESFIRE_DEVICE_NAME "Mifare DESfire" -const NfcProtocolBase nfc_protocol_mf_desfire = { +const NfcDeviceBase nfc_device_mf_desfire = { .protocol_name = MF_DESFIRE_PROTOCOL_NAME, - .alloc = (NfcProtocolAlloc)mf_desfire_alloc, - .free = (NfcProtocolFree)mf_desfire_free, - .reset = (NfcProtocolReset)mf_desfire_reset, - .copy = (NfcProtocolCopy)mf_desfire_copy, - .verify = (NfcProtocolVerify)mf_desfire_verify, - .load = (NfcProtocolLoad)mf_desfire_load, - .save = (NfcProtocolSave)mf_desfire_save, - .is_equal = (NfcProtocolEqual)mf_desfire_is_equal, - .get_device_name = (NfcProtocolGetDeviceName)mf_desfire_get_device_name, - .get_uid = (NfcProtocolGetUid)mf_desfire_get_uid, + .alloc = (NfcDeviceAlloc)mf_desfire_alloc, + .free = (NfcDeviceFree)mf_desfire_free, + .reset = (NfcDeviceReset)mf_desfire_reset, + .copy = (NfcDeviceCopy)mf_desfire_copy, + .verify = (NfcDeviceVerify)mf_desfire_verify, + .load = (NfcDeviceLoad)mf_desfire_load, + .save = (NfcDeviceSave)mf_desfire_save, + .is_equal = (NfcDeviceEqual)mf_desfire_is_equal, + .get_name = (NfcDeviceGetName)mf_desfire_get_device_name, + .get_uid = (NfcDeviceGetUid)mf_desfire_get_uid, }; MfDesfireData* mf_desfire_alloc() { @@ -101,7 +101,7 @@ bool mf_desfire_is_equal(const MfDesfireData* data, const MfDesfireData* other) return iso14443_4a_is_equal(data->iso14443_4a_data, other->iso14443_4a_data); } -const char* mf_desfire_get_device_name(const MfDesfireData* data, NfcProtocolNameType name_type) { +const char* mf_desfire_get_device_name(const MfDesfireData* data, NfcDeviceNameType name_type) { UNUSED(data); UNUSED(name_type); return MF_DESFIRE_DEVICE_NAME; diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire.h b/lib/nfc/protocols/mf_desfire/mf_desfire.h index 02de5987b76d..5e1fca19150b 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire.h +++ b/lib/nfc/protocols/mf_desfire/mf_desfire.h @@ -147,7 +147,7 @@ typedef struct { SimpleArray* applications; } MfDesfireData; -extern const NfcProtocolBase nfc_protocol_mf_desfire; +extern const NfcDeviceBase nfc_device_mf_desfire; // Virtual methods @@ -167,7 +167,7 @@ bool mf_desfire_save(const MfDesfireData* data, FlipperFormat* ff, uint32_t vers bool mf_desfire_is_equal(const MfDesfireData* data, const MfDesfireData* other); -const char* mf_desfire_get_device_name(const MfDesfireData* data, NfcProtocolNameType name_type); +const char* mf_desfire_get_device_name(const MfDesfireData* data, NfcDeviceNameType name_type); const uint8_t* mf_desfire_get_uid(const MfDesfireData* data, size_t* uid_len); diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c b/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c index 997f0f330f24..3273785de262 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c @@ -27,7 +27,7 @@ static MfDesfirePoller* mf_desfire_poller_alloc(Iso14443_4aPoller* iso14443_4a_p instance->mf_desfire_event.data = &instance->mf_desfire_event_data; - instance->general_event.protocol_type = NfcProtocolTypeMfDesfire; + instance->general_event.protocol = NfcProtocolMfDesfire; instance->general_event.data = &instance->mf_desfire_event; instance->general_event.poller = instance; @@ -192,7 +192,7 @@ static void mf_desfire_poller_set_callback( } static NfcCommand mf_desfire_poller_run(NfcPollerEvent event, void* context) { - furi_assert(event.protocol_type == NfcProtocolTypeIso14443_4a); + furi_assert(event.protocol == NfcProtocolIso14443_4a); MfDesfirePoller* instance = context; furi_assert(instance); @@ -214,7 +214,7 @@ static NfcCommand mf_desfire_poller_run(NfcPollerEvent event, void* context) { } static bool mf_desfire_poller_detect(NfcPollerEvent event, void* context) { - furi_assert(event.protocol_type == NfcProtocolTypeIso14443_4a); + furi_assert(event.protocol == NfcProtocolIso14443_4a); MfDesfirePoller* instance = context; furi_assert(instance); diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight.c index 7c1fb2393d05..8df26889c95b 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight.c @@ -117,44 +117,44 @@ static const MfUltralightFeatures mf_ultralight_features[MfUltralightTypeNum] = }, }; -const NfcProtocolBase nfc_protocol_mf_ultralight = { +const NfcDeviceBase nfc_device_mf_ultralight = { .protocol_name = MF_ULTRALIGHT_PROTOCOL_NAME, - .alloc = (NfcProtocolAlloc)mf_ultralight_alloc, - .free = (NfcProtocolFree)mf_ultralight_free, - .reset = (NfcProtocolReset)mf_ultralight_reset, - .copy = (NfcProtocolCopy)mf_ultralight_copy, - .verify = (NfcProtocolVerify)mf_ultralight_verify, - .load = (NfcProtocolLoad)mf_ultralight_load, - .save = (NfcProtocolSave)mf_ultralight_save, - .is_equal = (NfcProtocolEqual)mf_ultralight_is_equal, - .get_device_name = (NfcProtocolGetDeviceName)mf_ultralight_get_device_name, - .get_uid = (NfcProtocolGetUid)mf_ultralight_get_uid, + .alloc = (NfcDeviceAlloc)mf_ultralight_alloc, + .free = (NfcDeviceFree)mf_ultralight_free, + .reset = (NfcDeviceReset)mf_ultralight_reset, + .copy = (NfcDeviceCopy)mf_ultralight_copy, + .verify = (NfcDeviceVerify)mf_ultralight_verify, + .load = (NfcDeviceLoad)mf_ultralight_load, + .save = (NfcDeviceSave)mf_ultralight_save, + .is_equal = (NfcDeviceEqual)mf_ultralight_is_equal, + .get_name = (NfcDeviceGetName)mf_ultralight_get_device_name, + .get_uid = (NfcDeviceGetUid)mf_ultralight_get_uid, }; MfUltralightData* mf_ultralight_alloc() { MfUltralightData* data = malloc(sizeof(MfUltralightData)); - data->nfca_data = nfca_alloc(); + data->iso14443_3a_data = iso14443_3a_alloc(); return data; } void mf_ultralight_free(MfUltralightData* data) { furi_assert(data); - nfca_free(data->nfca_data); + iso14443_3a_free(data->iso14443_3a_data); free(data); } void mf_ultralight_reset(MfUltralightData* data) { furi_assert(data); - nfca_reset(data->nfca_data); + iso14443_3a_reset(data->iso14443_3a_data); } void mf_ultralight_copy(MfUltralightData* data, const MfUltralightData* other) { furi_assert(data); furi_assert(other); - nfca_copy(data->nfca_data, other->nfca_data); + iso14443_3a_copy(data->iso14443_3a_data, other->iso14443_3a_data); memcpy(data->counter, other->counter, MF_ULTRALIGHT_COUNTER_NUM); memcpy(data->tearing_flag, other->tearing_flag, MF_ULTRALIGHT_TEARING_FLAG_NUM); memcpy(data->page, other->page, MF_ULTRALIGHT_MAX_PAGE_NUM); @@ -220,8 +220,8 @@ bool mf_ultralight_load(MfUltralightData* data, FlipperFormat* ff, uint32_t vers bool parsed = false; do { - // Read NFCA data - if(!nfca_load_data(data->nfca_data, ff, version)) break; + // Read ISO14443_3A data + if(!iso14443_3a_load_data(data->iso14443_3a_data, ff, version)) break; // Read Ultralight specific data // Read Mifare Ultralight format version @@ -307,7 +307,7 @@ bool mf_ultralight_save(const MfUltralightData* data, FlipperFormat* ff, uint32_ do { const char* device_type_name = mf_ultralight_get_device_name_by_type(data->type, true); if(!flipper_format_write_string_cstr(ff, "Device type", device_type_name)) break; - if(!nfca_save_data(data->nfca_data, ff, version)) break; + if(!iso14443_3a_save_data(data->iso14443_3a_data, ff, version)) break; if(!flipper_format_write_comment_cstr(ff, "Mifare Ultralight specific data")) break; if(!flipper_format_write_uint32( ff, "Data format version", &mf_ultralight_data_format_version, 1)) @@ -371,22 +371,22 @@ bool mf_ultralight_save(const MfUltralightData* data, FlipperFormat* ff, uint32_ bool mf_ultralight_is_equal(const MfUltralightData* data, const MfUltralightData* other) { // TODO: Complete equality method - return nfca_is_equal(data->nfca_data, other->nfca_data); + return iso14443_3a_is_equal(data->iso14443_3a_data, other->iso14443_3a_data); } // TODO: Improve this function const char* - mf_ultralight_get_device_name(const MfUltralightData* data, NfcProtocolNameType name_type) { + mf_ultralight_get_device_name(const MfUltralightData* data, NfcDeviceNameType name_type) { furi_assert(data); furi_assert(data->type < MfUltralightTypeNum); - return mf_ultralight_get_device_name_by_type(data->type, name_type == NfcProtocolNameTypeFull); + return mf_ultralight_get_device_name_by_type(data->type, name_type == NfcDeviceNameTypeFull); } const uint8_t* mf_ultralight_get_uid(const MfUltralightData* data, size_t* uid_len) { furi_assert(data); - return nfca_get_uid(data->nfca_data, uid_len); + return iso14443_3a_get_uid(data->iso14443_3a_data, uid_len); } MfUltralightType mf_ultralight_get_type_by_version(MfUltralightVersion* version) { @@ -431,11 +431,11 @@ uint32_t mf_ultralight_get_feature_support_set(MfUltralightType type) { return mf_ultralight_features[type].feature_set; } -bool mf_ultralight_detect_protocol(const NfcaData* nfca_data) { - furi_assert(nfca_data); +bool mf_ultralight_detect_protocol(const Iso14443_3aData* iso14443_3a_data) { + furi_assert(iso14443_3a_data); - bool mfu_detected = (nfca_data->atqa[0] == 0x44) && (nfca_data->atqa[1] == 0x00) && - (nfca_data->sak == 0x00); + bool mfu_detected = (iso14443_3a_data->atqa[0] == 0x44) && + (iso14443_3a_data->atqa[1] == 0x00) && (iso14443_3a_data->sak == 0x00); return mfu_detected; } diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h index f7bbbf64ab08..22d096d9b6db 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #ifdef __cplusplus extern "C" { @@ -153,7 +153,7 @@ typedef struct __attribute__((packed)) { } MfUltralightConfigPages; typedef struct { - NfcaData* nfca_data; + Iso14443_3aData* iso14443_3a_data; MfUltralightType type; MfUltralightVersion version; MfUltralightSignature signature; @@ -165,7 +165,7 @@ typedef struct { uint32_t auth_attempts; } MfUltralightData; -extern const NfcProtocolBase nfc_protocol_mf_ultralight; +extern const NfcDeviceBase nfc_device_mf_ultralight; MfUltralightData* mf_ultralight_alloc(); @@ -184,7 +184,7 @@ bool mf_ultralight_save(const MfUltralightData* data, FlipperFormat* ff, uint32_ bool mf_ultralight_is_equal(const MfUltralightData* data, const MfUltralightData* other); const char* - mf_ultralight_get_device_name(const MfUltralightData* data, NfcProtocolNameType name_type); + mf_ultralight_get_device_name(const MfUltralightData* data, NfcDeviceNameType name_type); const uint8_t* mf_ultralight_get_uid(const MfUltralightData* data, size_t* uid_len); @@ -200,7 +200,7 @@ bool mf_ultralight_get_config_page(const MfUltralightData* data, MfUltralightCon bool mf_ultralight_is_all_data_read(const MfUltralightData* data); -bool mf_ultralight_detect_protocol(const NfcaData* nfca_data); +bool mf_ultralight_detect_protocol(const Iso14443_3aData* iso14443_3a_data); bool mf_ultralight_is_counter_configured(const MfUltralightData* data); diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c index cfcd934208b9..39e0be1e0075 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c @@ -21,7 +21,7 @@ typedef enum { } MfUltraligthListenerState; struct MfUltralightListener { - NfcaListener* nfca_listener; + Iso14443_3aListener* iso14443_3a_listener; MfUltralightListenerAuthState auth_state; MfUltraligthListenerState state; MfUltralightData* data; @@ -41,22 +41,22 @@ typedef struct { MfUltralightListenerCommandCallback callback; } MfUltralightListenerCmdHandler; -static MfUltralightError mf_ultralight_process_error(NfcaError error) { +static MfUltralightError mf_ultralight_process_error(Iso14443_3aError error) { MfUltralightError ret = MfUltralightErrorNone; switch(error) { - case NfcaErrorNone: + case Iso14443_3aErrorNone: ret = MfUltralightErrorNone; break; - case NfcaErrorNotPresent: + case Iso14443_3aErrorNotPresent: ret = MfUltralightErrorNotPresent; break; - case NfcaErrorColResFailed: - case NfcaErrorCommunication: - case NfcaErrorWrongCrc: + case Iso14443_3aErrorColResFailed: + case Iso14443_3aErrorCommunication: + case Iso14443_3aErrorWrongCrc: ret = MfUltralightErrorProtocol; break; - case NfcaErrorTimeout: + case Iso14443_3aErrorTimeout: ret = MfUltralightErrorTimeout; break; default: @@ -103,7 +103,7 @@ static void mf_ultralight_listener_send_short_resp(MfUltralightListener* instanc bit_buffer_set_size(instance->tx_buffer, 4); bit_buffer_set_byte(instance->tx_buffer, 0, data); - nfca_listener_tx(instance->nfca_listener, instance->tx_buffer); + iso14443_3a_listener_tx(instance->iso14443_3a_listener, instance->tx_buffer); }; static bool @@ -137,7 +137,8 @@ static bool instance->tx_buffer, (uint8_t*)&read_cmd_data, sizeof(MfUltralightPageReadCommandData)); - nfca_listener_send_standart_frame(instance->nfca_listener, instance->tx_buffer); + iso14443_3a_listener_send_standart_frame( + instance->iso14443_3a_listener, instance->tx_buffer); } command_processed = true; @@ -178,9 +179,10 @@ static bool if((instance->features & MfUltralightFeatureSupportReadVersion)) { bit_buffer_copy_bytes( instance->tx_buffer, (uint8_t*)&instance->data->version, sizeof(MfUltralightVersion)); - nfca_listener_send_standart_frame(instance->nfca_listener, instance->tx_buffer); + iso14443_3a_listener_send_standart_frame( + instance->iso14443_3a_listener, instance->tx_buffer); } else { - nfca_listener_sleep(instance->nfca_listener); + iso14443_3a_listener_sleep(instance->iso14443_3a_listener); instance->state = MfUltraligthListenerStateIdle; } command_processed = true; @@ -198,9 +200,10 @@ static bool mf_ultralight_listener_read_signature_handler( if((instance->features & MfUltralightFeatureSupportReadSignature)) { bit_buffer_copy_bytes( instance->tx_buffer, instance->data->signature.data, sizeof(MfUltralightSignature)); - nfca_listener_send_standart_frame(instance->nfca_listener, instance->tx_buffer); + iso14443_3a_listener_send_standart_frame( + instance->iso14443_3a_listener, instance->tx_buffer); } else { - nfca_listener_sleep(instance->nfca_listener); + iso14443_3a_listener_sleep(instance->iso14443_3a_listener); instance->state = MfUltraligthListenerStateIdle; } command_processed = true; @@ -237,7 +240,8 @@ static bool (instance->data->counter[counter_num].counter >> 16) & 0xff, }; bit_buffer_copy_bytes(instance->tx_buffer, cnt_value, sizeof(cnt_value)); - nfca_listener_send_standart_frame(instance->nfca_listener, instance->tx_buffer); + iso14443_3a_listener_send_standart_frame( + instance->iso14443_3a_listener, instance->tx_buffer); command_processed = true; } while(false); @@ -255,7 +259,8 @@ static bool mf_ultralight_listener_check_tearing_handler( if(tearing_flag_num > 2) break; bit_buffer_set_size_bytes(instance->tx_buffer, 1); bit_buffer_set_byte(instance->tx_buffer, 0, instance->data->tearing_flag->data[0]); - nfca_listener_send_standart_frame(instance->nfca_listener, instance->tx_buffer); + iso14443_3a_listener_send_standart_frame( + instance->iso14443_3a_listener, instance->tx_buffer); command_processed = true; } while(false); @@ -285,7 +290,8 @@ static bool bit_buffer_copy_bytes( instance->tx_buffer, instance->config->pack.data, sizeof(MfUltralightAuthPack)); instance->auth_state = MfUltralightListenerAuthStateSuccess; - nfca_listener_send_standart_frame(instance->nfca_listener, instance->tx_buffer); + iso14443_3a_listener_send_standart_frame( + instance->iso14443_3a_listener, instance->tx_buffer); command_processed = true; } while(false); @@ -330,15 +336,15 @@ static const MfUltralightListenerCmdHandler mf_ultralight_command[] = { .callback = mf_ultralight_listener_auth_handler, }}; -static NfcaListenerCommand - mf_ultralight_listener_event_handler(NfcaListenerEvent event, void* context) { +static Iso14443_3aListenerCommand + mf_ultralight_listener_event_handler(Iso14443_3aListenerEvent event, void* context) { furi_assert(context); MfUltralightListener* instance = context; BitBuffer* rx_buffer = event.data.buffer; - NfcaListenerCommand command = NfcaListenerCommandContinue; - if(event.type == NfcaListenerEventTypeReceivedStandartFrame) { + Iso14443_3aListenerCommand command = Iso14443_3aListenerCommandContinue; + if(event.type == Iso14443_3aListenerEventTypeReceivedStandartFrame) { bool cmd_processed = false; for(size_t i = 0; i < COUNT_OF(mf_ultralight_command); i++) { if(bit_buffer_get_size(rx_buffer) != mf_ultralight_command[i].cmd_len_bits) continue; @@ -362,11 +368,11 @@ static void mf_ultralight_listener_prepare_emulation(MfUltralightListener* insta mf_ultralight_get_config_page(data, &instance->config); } -MfUltralightListener* mf_ultralight_listener_alloc(NfcaListener* nfca_listener) { - furi_assert(nfca_listener); +MfUltralightListener* mf_ultralight_listener_alloc(Iso14443_3aListener* iso14443_3a_listener) { + furi_assert(iso14443_3a_listener); MfUltralightListener* instance = malloc(sizeof(MfUltralightListener)); - instance->nfca_listener = nfca_listener; + instance->iso14443_3a_listener = iso14443_3a_listener; return instance; } @@ -387,9 +393,9 @@ MfUltralightError mf_ultralight_listener_start( instance->callback = callback; instance->context = context; - NfcaError error = nfca_listener_start( - instance->nfca_listener, - instance->data->nfca_data, + Iso14443_3aError error = iso14443_3a_listener_start( + instance->iso14443_3a_listener, + instance->data->iso14443_3a_data, mf_ultralight_listener_event_handler, instance); @@ -418,7 +424,7 @@ MfUltralightError mf_ultralight_listener_stop(MfUltralightListener* instance) { furi_assert(instance->data); furi_assert(instance->tx_buffer); - NfcaError error = nfca_listener_stop(instance->nfca_listener); + Iso14443_3aError error = iso14443_3a_listener_stop(instance->iso14443_3a_listener); instance->state = MfUltraligthListenerStateIdle; bit_buffer_free(instance->tx_buffer); diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.h index 95ee14dbcfad..a45d22b6643f 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.h @@ -1,7 +1,7 @@ #pragma once #include "mf_ultralight.h" -#include +#include #ifdef __cplusplus extern "C" { @@ -25,14 +25,14 @@ typedef struct { } MfUltralightListenerEvent; typedef enum { - MfUltralightListenerCommandContinue = NfcaListenerCommandContinue, - MfUltralightListenerCommandReset = NfcaListenerCommandReset, + MfUltralightListenerCommandContinue = Iso14443_3aListenerCommandContinue, + MfUltralightListenerCommandReset = Iso14443_3aListenerCommandReset, } MfUltralightListenerCommand; typedef MfUltralightListenerCommand ( *MfUltralightListenerEventCallback)(MfUltralightListenerEvent event, void* context); -MfUltralightListener* mf_ultralight_listener_alloc(NfcaListener* nfca_listener); +MfUltralightListener* mf_ultralight_listener_alloc(Iso14443_3aListener* iso14443_3a_listener); void mf_ultralight_listener_free(MfUltralightListener* instance); diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c index f01fd936b865..1cc7ee36ffc1 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c @@ -166,18 +166,18 @@ bool mf_ultralight_poller_ntag_i2c_addr_lin_to_tag( return tag_calculated; } -MfUltralightPoller* mf_ultralight_poller_alloc(NfcaPoller* nfca_poller) { - furi_assert(nfca_poller); +MfUltralightPoller* mf_ultralight_poller_alloc(Iso14443_3aPoller* iso14443_3a_poller) { + furi_assert(iso14443_3a_poller); MfUltralightPoller* instance = malloc(sizeof(MfUltralightPoller)); - instance->nfca_poller = nfca_poller; + instance->iso14443_3a_poller = iso14443_3a_poller; instance->tx_buffer = bit_buffer_alloc(MF_ULTRALIGHT_MAX_BUFF_SIZE); instance->rx_buffer = bit_buffer_alloc(MF_ULTRALIGHT_MAX_BUFF_SIZE); instance->data = mf_ultralight_alloc(); instance->mfu_event.data = &instance->mfu_event_data; - instance->general_event.protocol_type = NfcProtocolTypeMfUltralight; + instance->general_event.protocol = NfcProtocolMfUltralight; instance->general_event.data = &instance->mfu_event; instance->general_event.poller = instance; @@ -216,7 +216,9 @@ const MfUltralightData* mf_ultralight_poller_get_data(MfUltralightPoller* instan static NfcCommand mf_ultralight_poller_handler_idle(MfUltralightPoller* instance) { bit_buffer_reset(instance->tx_buffer); bit_buffer_reset(instance->rx_buffer); - nfca_copy(instance->data->nfca_data, nfca_poller_get_data(instance->nfca_poller)); + iso14443_3a_copy( + instance->data->iso14443_3a_data, + iso14443_3a_poller_get_data(instance->iso14443_3a_poller)); instance->counters_read = 0; instance->counters_total = 3; instance->tearing_flag_read = 0; @@ -235,7 +237,7 @@ static NfcCommand mf_ultralight_poller_handler_read_version(MfUltralightPoller* instance->state = MfUltralightPollerStateGetFeatureSet; } else { FURI_LOG_D(TAG, "Didn't response. Check NTAG 203"); - nfca_poller_halt(instance->nfca_poller); + iso14443_3a_poller_halt(instance->iso14443_3a_poller); instance->state = MfUltralightPollerStateDetectNtag203; } @@ -250,7 +252,7 @@ static NfcCommand mf_ultralight_poller_handler_check_ntag_203(MfUltralightPoller instance->data->type = MfUltralightTypeNTAG203; } else { FURI_LOG_D(TAG, "Original Ultralight detected"); - nfca_poller_halt(instance->nfca_poller); + iso14443_3a_poller_halt(instance->iso14443_3a_poller); instance->data->type = MfUltralightTypeUnknown; } instance->state = MfUltralightPollerStateGetFeatureSet; @@ -265,7 +267,7 @@ static NfcCommand mf_ultralight_poller_handler_get_feature_set(MfUltralightPolle FURI_LOG_D( TAG, "%s detected. Total pages: %d", - mf_ultralight_get_device_name(instance->data, NfcProtocolNameTypeFull), + mf_ultralight_get_device_name(instance->data, NfcDeviceNameTypeFull), instance->pages_total); instance->state = MfUltralightPollerStateReadSignature; @@ -371,7 +373,7 @@ static NfcCommand mf_ultralight_poller_handler_auth(MfUltralightPoller* instance instance->auth_context.auth_success = false; instance->mfu_event.type = MfUltralightPollerEventTypeAuthFailed; command = instance->callback(instance->general_event, instance->context); - nfca_poller_halt(instance->nfca_poller); + iso14443_3a_poller_halt(instance->iso14443_3a_poller); } } } @@ -456,7 +458,7 @@ static NfcCommand mf_ultralight_poller_handler_try_default_pass(MfUltralightPoll static NfcCommand mf_ultralight_poller_handler_read_fail(MfUltralightPoller* instance) { FURI_LOG_D(TAG, "Read Failed"); - nfca_poller_halt(instance->nfca_poller); + iso14443_3a_poller_halt(instance->iso14443_3a_poller); instance->mfu_event.data->error = instance->error; NfcCommand command = instance->callback(instance->general_event, instance->context); instance->state = MfUltralightPollerStateIdle; @@ -465,7 +467,7 @@ static NfcCommand mf_ultralight_poller_handler_read_fail(MfUltralightPoller* ins static NfcCommand mf_ultralight_poller_handler_read_success(MfUltralightPoller* instance) { FURI_LOG_D(TAG, "Read success"); - nfca_poller_halt(instance->nfca_poller); + iso14443_3a_poller_halt(instance->iso14443_3a_poller); instance->mfu_event.type = MfUltralightPollerEventTypeReadSuccess; NfcCommand command = instance->callback(instance->general_event, instance->context); return command; @@ -492,18 +494,18 @@ static const MfUltralightPollerReadHandler static NfcCommand mf_ultralight_poller_run(NfcPollerEvent event, void* context) { furi_assert(context); furi_assert(event.data); - furi_assert(event.protocol_type == NfcProtocolTypeIso14443_3a); + furi_assert(event.protocol == NfcProtocolIso14443_3a); MfUltralightPoller* instance = context; furi_assert(instance->callback); - const NfcaPollerEvent* nfca_event = event.data; + const Iso14443_3aPollerEvent* iso14443_3a_event = event.data; NfcCommand command = NfcCommandContinue; - if(nfca_event->type == NfcaPollerEventTypeReady) { + if(iso14443_3a_event->type == Iso14443_3aPollerEventTypeReady) { command = mf_ultralight_poller_read_handler[instance->state](instance); - } else if(nfca_event->type == NfcaPollerEventTypeError) { + } else if(iso14443_3a_event->type == Iso14443_3aPollerEventTypeError) { instance->mfu_event.type = MfUltralightPollerEventTypeReadFailed; command = instance->callback(instance->general_event, instance->context); } @@ -514,18 +516,18 @@ static NfcCommand mf_ultralight_poller_run(NfcPollerEvent event, void* context) static bool mf_ultralight_poller_detect(NfcPollerEvent event, void* context) { furi_assert(context); furi_assert(event.data); - furi_assert(event.protocol_type == NfcProtocolTypeIso14443_3a); + furi_assert(event.protocol == NfcProtocolIso14443_3a); bool protocol_detected = false; MfUltralightPoller* instance = context; - const NfcaPollerEvent* nfca_event = event.data; + const Iso14443_3aPollerEvent* iso14443_3a_event = event.data; - if(nfca_event->type == NfcaPollerEventTypeReady) { + if(iso14443_3a_event->type == Iso14443_3aPollerEventTypeReady) { MfUltralightPageReadCommandData read_page_cmd_data = {}; MfUltralightError error = mf_ultralight_poller_async_read_page(instance, 0, &read_page_cmd_data); protocol_detected = (error == MfUltralightErrorNone); - nfca_poller_halt(instance->nfca_poller); + iso14443_3a_poller_halt(instance->iso14443_3a_poller); } return protocol_detected; diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h index d350ee177f87..2d4ef33ea947 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h @@ -1,7 +1,7 @@ #pragma once #include "mf_ultralight.h" -#include +#include #ifdef __cplusplus extern "C" { diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c index b1aeebc843cf..cc9596be80bc 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c @@ -4,22 +4,22 @@ #define TAG "MfUltralightPoller" -MfUltralightError mf_ultralight_process_error(NfcaError error) { +MfUltralightError mf_ultralight_process_error(Iso14443_3aError error) { MfUltralightError ret = MfUltralightErrorNone; switch(error) { - case NfcaErrorNone: + case Iso14443_3aErrorNone: ret = MfUltralightErrorNone; break; - case NfcaErrorNotPresent: + case Iso14443_3aErrorNotPresent: ret = MfUltralightErrorNotPresent; break; - case NfcaErrorColResFailed: - case NfcaErrorCommunication: - case NfcaErrorWrongCrc: + case Iso14443_3aErrorColResFailed: + case Iso14443_3aErrorCommunication: + case Iso14443_3aErrorWrongCrc: ret = MfUltralightErrorProtocol; break; - case NfcaErrorTimeout: + case Iso14443_3aErrorTimeout: ret = MfUltralightErrorTimeout; break; default: @@ -38,14 +38,14 @@ MfUltralightError mf_ultralight_poller_async_auth( bit_buffer_copy_bytes(instance->tx_buffer, auth_cmd, sizeof(auth_cmd)); MfUltralightError ret = MfUltralightErrorNone; - NfcaError error = NfcaErrorNone; + Iso14443_3aError error = Iso14443_3aErrorNone; do { - error = nfca_poller_send_standart_frame( - instance->nfca_poller, + error = iso14443_3a_poller_send_standart_frame( + instance->iso14443_3a_poller, instance->tx_buffer, instance->rx_buffer, MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); - if(error != NfcaErrorNone) { + if(error != Iso14443_3aErrorNone) { ret = mf_ultralight_process_error(error); break; } @@ -65,17 +65,17 @@ MfUltralightError mf_ultralight_poller_async_read_page_from_sector( uint8_t tag, MfUltralightPageReadCommandData* data) { MfUltralightError ret = MfUltralightErrorNone; - NfcaError error = NfcaErrorNone; + Iso14443_3aError error = Iso14443_3aErrorNone; do { const uint8_t select_sector_cmd[2] = {MF_ULTRALIGHT_CMD_SECTOR_SELECT, 0xff}; bit_buffer_copy_bytes(instance->tx_buffer, select_sector_cmd, sizeof(select_sector_cmd)); - error = nfca_poller_send_standart_frame( - instance->nfca_poller, + error = iso14443_3a_poller_send_standart_frame( + instance->iso14443_3a_poller, instance->tx_buffer, instance->rx_buffer, MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); - if(error != NfcaErrorWrongCrc) { + if(error != Iso14443_3aErrorWrongCrc) { FURI_LOG_D(TAG, "Failed to issue sector select command"); ret = mf_ultralight_process_error(error); break; @@ -83,12 +83,12 @@ MfUltralightError mf_ultralight_poller_async_read_page_from_sector( const uint8_t read_sector_cmd[4] = {sector, 0x00, 0x00, 0x00}; bit_buffer_copy_bytes(instance->tx_buffer, read_sector_cmd, sizeof(read_sector_cmd)); - error = nfca_poller_send_standart_frame( - instance->nfca_poller, + error = iso14443_3a_poller_send_standart_frame( + instance->iso14443_3a_poller, instance->tx_buffer, instance->rx_buffer, MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); - if(error != NfcaErrorTimeout) { + if(error != Iso14443_3aErrorTimeout) { // This is NOT a typo! The tag ACKs by not sending a response within 1ms. FURI_LOG_D(TAG, "Sector %u select NAK'd", sector); ret = MfUltralightErrorProtocol; @@ -106,17 +106,17 @@ MfUltralightError mf_ultralight_poller_async_read_page( uint8_t start_page, MfUltralightPageReadCommandData* data) { MfUltralightError ret = MfUltralightErrorNone; - NfcaError error = NfcaErrorNone; + Iso14443_3aError error = Iso14443_3aErrorNone; do { uint8_t read_page_cmd[2] = {MF_ULTRALIGHT_CMD_READ_PAGE, start_page}; bit_buffer_copy_bytes(instance->tx_buffer, read_page_cmd, sizeof(read_page_cmd)); - error = nfca_poller_send_standart_frame( - instance->nfca_poller, + error = iso14443_3a_poller_send_standart_frame( + instance->iso14443_3a_poller, instance->tx_buffer, instance->rx_buffer, MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); - if(error != NfcaErrorNone) { + if(error != Iso14443_3aErrorNone) { ret = mf_ultralight_process_error(error); break; } @@ -136,18 +136,18 @@ MfUltralightError mf_ultralight_poller_async_write_page( uint8_t page, MfUltralightPage* data) { MfUltralightError ret = MfUltralightErrorNone; - NfcaError error = NfcaErrorNone; + Iso14443_3aError error = Iso14443_3aErrorNone; do { uint8_t write_page_cmd[MF_ULTRALIGHT_PAGE_SIZE + 2] = {MF_ULTRALIGHT_CMD_WRITE_PAGE, page}; memcpy(&write_page_cmd[2], data->data, MF_ULTRALIGHT_PAGE_SIZE); bit_buffer_copy_bytes(instance->tx_buffer, write_page_cmd, sizeof(write_page_cmd)); - error = nfca_poller_send_standart_frame( - instance->nfca_poller, + error = iso14443_3a_poller_send_standart_frame( + instance->iso14443_3a_poller, instance->tx_buffer, instance->rx_buffer, MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); - if(error != NfcaErrorWrongCrc) { + if(error != Iso14443_3aErrorWrongCrc) { ret = mf_ultralight_process_error(error); break; } @@ -168,17 +168,17 @@ MfUltralightError mf_ultralight_poller_async_read_version( MfUltralightPoller* instance, MfUltralightVersion* data) { MfUltralightError ret = MfUltralightErrorNone; - NfcaError error = NfcaErrorNone; + Iso14443_3aError error = Iso14443_3aErrorNone; do { const uint8_t get_version_cmd = MF_ULTRALIGHT_CMD_GET_VERSION; bit_buffer_copy_bytes(instance->tx_buffer, &get_version_cmd, sizeof(get_version_cmd)); - error = nfca_poller_send_standart_frame( - instance->nfca_poller, + error = iso14443_3a_poller_send_standart_frame( + instance->iso14443_3a_poller, instance->tx_buffer, instance->rx_buffer, MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); - if(error != NfcaErrorNone) { + if(error != Iso14443_3aErrorNone) { ret = mf_ultralight_process_error(error); break; } @@ -198,17 +198,17 @@ MfUltralightError mf_ultralight_poller_async_read_signature( MfUltralightPoller* instance, MfUltralightSignature* data) { MfUltralightError ret = MfUltralightErrorNone; - NfcaError error = NfcaErrorNone; + Iso14443_3aError error = Iso14443_3aErrorNone; do { const uint8_t read_signature_cmd[2] = {MF_ULTRALIGTH_CMD_READ_SIG, 0x00}; bit_buffer_copy_bytes(instance->tx_buffer, read_signature_cmd, sizeof(read_signature_cmd)); - error = nfca_poller_send_standart_frame( - instance->nfca_poller, + error = iso14443_3a_poller_send_standart_frame( + instance->iso14443_3a_poller, instance->tx_buffer, instance->rx_buffer, MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); - if(error != NfcaErrorNone) { + if(error != Iso14443_3aErrorNone) { ret = mf_ultralight_process_error(error); break; } @@ -227,17 +227,17 @@ MfUltralightError mf_ultralight_poller_async_read_counter( uint8_t counter_num, MfUltralightCounter* data) { MfUltralightError ret = MfUltralightErrorNone; - NfcaError error = NfcaErrorNone; + Iso14443_3aError error = Iso14443_3aErrorNone; do { uint8_t read_counter_cmd[2] = {MF_ULTRALIGHT_CMD_READ_CNT, counter_num}; bit_buffer_copy_bytes(instance->tx_buffer, read_counter_cmd, sizeof(read_counter_cmd)); - error = nfca_poller_send_standart_frame( - instance->nfca_poller, + error = iso14443_3a_poller_send_standart_frame( + instance->iso14443_3a_poller, instance->tx_buffer, instance->rx_buffer, MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); - if(error != NfcaErrorNone) { + if(error != Iso14443_3aErrorNone) { ret = mf_ultralight_process_error(error); break; } @@ -256,17 +256,17 @@ MfUltralightError mf_ultralight_poller_async_read_tearing_flag( uint8_t tearing_falg_num, MfUltralightTearingFlag* data) { MfUltralightError ret = MfUltralightErrorNone; - NfcaError error = NfcaErrorNone; + Iso14443_3aError error = Iso14443_3aErrorNone; do { uint8_t check_tearing_cmd[2] = {MF_ULTRALIGHT_CMD_CHECK_TEARING, tearing_falg_num}; bit_buffer_copy_bytes(instance->tx_buffer, check_tearing_cmd, sizeof(check_tearing_cmd)); - error = nfca_poller_send_standart_frame( - instance->nfca_poller, + error = iso14443_3a_poller_send_standart_frame( + instance->iso14443_3a_poller, instance->tx_buffer, instance->rx_buffer, MF_ULTRALIGHT_POLLER_STANDART_FWT_FC); - if(error != NfcaErrorNone) { + if(error != Iso14443_3aErrorNone) { ret = mf_ultralight_process_error(error); break; } diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h index 9128292a105a..5d89902262fe 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h @@ -1,7 +1,7 @@ #pragma once #include "mf_ultralight_poller.h" -#include +#include #include #ifdef __cplusplus @@ -65,7 +65,7 @@ typedef enum { } MfUltralightPollerState; struct MfUltralightPoller { - NfcaPoller* nfca_poller; + Iso14443_3aPoller* iso14443_3a_poller; MfUltralightPollerState state; BitBuffer* tx_buffer; BitBuffer* rx_buffer; @@ -87,9 +87,9 @@ struct MfUltralightPoller { void* context; }; -MfUltralightError mf_ultralight_process_error(NfcaError error); +MfUltralightError mf_ultralight_process_error(Iso14443_3aError error); -MfUltralightPoller* mf_ultralight_poller_alloc(NfcaPoller* nfca_poller); +MfUltralightPoller* mf_ultralight_poller_alloc(Iso14443_3aPoller* iso14443_3a_poller); void mf_ultralight_poller_free(MfUltralightPoller* instance); diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c index cc5c0408ac75..18df55ab171e 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c @@ -81,20 +81,20 @@ static const MfUltralightPollerCmdHandler static NfcCommand mf_ultralgiht_poller_cmd_callback(NfcPollerEvent event, void* context) { furi_assert(event.poller); - furi_assert(event.protocol_type == NfcProtocolTypeIso14443_3a); + furi_assert(event.protocol == NfcProtocolIso14443_3a); furi_assert(event.data); furi_assert(context); MfUltralightPollerContext* poller_context = context; - NfcaPollerEvent* nfca_event = event.data; - NfcaPoller* nfca_poller = event.poller; - MfUltralightPoller* mfu_poller = mf_ultralight_poller_alloc(nfca_poller); + Iso14443_3aPollerEvent* iso14443_3a_event = event.data; + Iso14443_3aPoller* iso14443_3a_poller = event.poller; + MfUltralightPoller* mfu_poller = mf_ultralight_poller_alloc(iso14443_3a_poller); - if(nfca_event->type == NfcaPollerEventTypeReady) { + if(iso14443_3a_event->type == Iso14443_3aPollerEventTypeReady) { poller_context->error = mf_ultralight_poller_cmd_handlers[poller_context->cmd_type]( mfu_poller, &poller_context->data); - } else if(nfca_event->type == NfcaPollerEventTypeError) { - poller_context->error = mf_ultralight_process_error(nfca_event->data->error); + } else if(iso14443_3a_event->type == Iso14443_3aPollerEventTypeError) { + poller_context->error = mf_ultralight_process_error(iso14443_3a_event->data->error); } furi_thread_flags_set(poller_context->thread_id, MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); @@ -110,7 +110,7 @@ static MfUltralightError poller_ctx->thread_id = furi_thread_get_current_id(); - NfcPoller* poller = nfc_poller_alloc(nfc, NfcProtocolTypeIso14443_3a); + NfcPoller* poller = nfc_poller_alloc(nfc, NfcProtocolIso14443_3a); nfc_poller_start(poller, mf_ultralgiht_poller_cmd_callback, poller_ctx); furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); furi_thread_flags_clear(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); @@ -236,7 +236,7 @@ static NfcCommand mf_ultralight_poller_read_callback(NfcPollerEvent event, void* furi_assert(context); furi_assert(event.poller); furi_assert(event.data); - furi_assert(event.protocol_type == NfcProtocolTypeMfUltralight); + furi_assert(event.protocol == NfcProtocolMfUltralight); NfcCommand command = NfcCommandContinue; MfUltralightPollerContext* poller_context = context; @@ -268,7 +268,7 @@ MfUltralightError mf_ultralight_poller_read_card(Nfc* nfc, MfUltralightData* dat MfUltralightPollerContext poller_context = {}; poller_context.thread_id = furi_thread_get_current_id(); - NfcPoller* poller = nfc_poller_alloc(nfc, NfcProtocolTypeMfUltralight); + NfcPoller* poller = nfc_poller_alloc(nfc, NfcProtocolMfUltralight); nfc_poller_start(poller, mf_ultralight_poller_read_callback, &poller_context); furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); furi_thread_flags_clear(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); diff --git a/lib/nfc/protocols/nfc_device_base.h b/lib/nfc/protocols/nfc_device_base.h new file mode 100644 index 000000000000..f727950cb311 --- /dev/null +++ b/lib/nfc/protocols/nfc_device_base.h @@ -0,0 +1,43 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + NfcDeviceNameTypeFull, + NfcDeviceNameTypeShort, +} NfcDeviceNameType; + +typedef void NfcDeviceData; + +typedef NfcDeviceData* (*NfcDeviceAlloc)(); +typedef void (*NfcDeviceFree)(NfcDeviceData* data); +typedef void (*NfcDeviceReset)(NfcDeviceData* data); +typedef void (*NfcDeviceCopy)(NfcDeviceData* data, const NfcDeviceData* other); +typedef bool (*NfcDeviceVerify)(NfcDeviceData* data, const FuriString* device_type); +typedef bool (*NfcDeviceLoad)(NfcDeviceData* data, FlipperFormat* ff, uint32_t version); +typedef bool (*NfcDeviceSave)(const NfcDeviceData* data, FlipperFormat* ff, uint32_t version); +typedef bool (*NfcDeviceEqual)(const NfcDeviceData* data, const NfcDeviceData* other); +typedef const char* (*NfcDeviceGetName)(const NfcDeviceData* data, NfcDeviceNameType name_type); +typedef const uint8_t* (*NfcDeviceGetUid)(const NfcDeviceData* data, size_t* uid_len); + +typedef struct { + const char* protocol_name; + NfcDeviceAlloc alloc; + NfcDeviceFree free; + NfcDeviceReset reset; + NfcDeviceCopy copy; + NfcDeviceVerify verify; + NfcDeviceLoad load; + NfcDeviceSave save; + NfcDeviceEqual is_equal; + NfcDeviceGetName get_name; + NfcDeviceGetUid get_uid; +} NfcDeviceBase; + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/nfc_device_defs.c b/lib/nfc/protocols/nfc_device_defs.c new file mode 100644 index 000000000000..1e27c83379a3 --- /dev/null +++ b/lib/nfc/protocols/nfc_device_defs.c @@ -0,0 +1,16 @@ +#include "nfc_device_defs.h" + +#include +#include +#include +#include +#include + +const NfcDeviceBase* nfc_devices[NfcProtocolNum] = { + [NfcProtocolIso14443_3a] = &nfc_device_iso14443_3a, + [NfcProtocolIso14443_4a] = &nfc_device_iso14443_4a, + [NfcProtocolMfUltralight] = &nfc_device_mf_ultralight, + [NfcProtocolMfClassic] = &nfc_device_mf_classic, + [NfcProtocolMfDesfire] = &nfc_device_mf_desfire, + /* Add new protocols here */ +}; diff --git a/lib/nfc/protocols/nfc_device_defs.h b/lib/nfc/protocols/nfc_device_defs.h new file mode 100644 index 000000000000..e84bf6a9e102 --- /dev/null +++ b/lib/nfc/protocols/nfc_device_defs.h @@ -0,0 +1,26 @@ +#pragma once + +#include "nfc_device_base.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + NfcProtocolIso14443_3a, + NfcProtocolIso14443_4a, + NfcProtocolMfUltralight, + NfcProtocolMfClassic, + NfcProtocolMfDesfire, + /* Add new protocols here */ + + NfcProtocolNum, + + NfcProtocolInvalid, +} NfcProtocol; + +extern const NfcDeviceBase* nfc_devices[]; + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/nfc_poller_base.h b/lib/nfc/protocols/nfc_poller_base.h index 351e17defd69..7c03e36ba321 100644 --- a/lib/nfc/protocols/nfc_poller_base.h +++ b/lib/nfc/protocols/nfc_poller_base.h @@ -13,7 +13,7 @@ typedef void ( *NfcPollerSetCallback)(NfcPollerInstance* poller, NfcPollerCallback callback, void* context); typedef NfcCommand (*NfcPollerRun)(NfcPollerEvent event, void* context); typedef bool (*NfcPollerDetect)(NfcPollerEvent event, void* context); -typedef const NfcProtocolData* (*NfcPollerGetData)(const NfcPollerInstance* instance); +typedef const NfcDeviceData* (*NfcPollerGetData)(const NfcPollerInstance* instance); typedef struct { NfcPollerAlloc alloc; diff --git a/lib/nfc/protocols/nfc_poller_common.h b/lib/nfc/protocols/nfc_poller_common.h index 67e7f9af19d5..76210d7a8633 100644 --- a/lib/nfc/protocols/nfc_poller_common.h +++ b/lib/nfc/protocols/nfc_poller_common.h @@ -1,6 +1,6 @@ #pragma once -#include "nfc_protocol_defs.h" +#include "nfc_device_defs.h" #include "nfc.h" #ifdef __cplusplus @@ -12,7 +12,7 @@ typedef void NfcPollerInstance; typedef void NfcPollerEventData; typedef struct { - NfcProtocolType protocol_type; + NfcProtocol protocol; NfcPollerInstance* poller; NfcPollerEventData* data; } NfcPollerEvent; diff --git a/lib/nfc/protocols/nfc_poller_defs.c b/lib/nfc/protocols/nfc_poller_defs.c index afcda822061b..84960652c13b 100644 --- a/lib/nfc/protocols/nfc_poller_defs.c +++ b/lib/nfc/protocols/nfc_poller_defs.c @@ -1,6 +1,6 @@ #include "nfc_poller_defs.h" -#include +#include #include #include #include @@ -8,12 +8,12 @@ #include -const NfcPollerBase* nfc_pollers_api[NfcProtocolTypeMax] = { - [NfcProtocolTypeIso14443_3a] = &nfc_poller_iso14443_3a, - [NfcProtocolTypeIso14443_4a] = &nfc_poller_iso14443_4a, - [NfcProtocolTypeMfUltralight] = &mf_ultralight_poller, - [NfcProtocolTypeMfClassic] = &mf_classic_poller, - [NfcProtocolTypeMfDesfire] = &mf_desfire_poller, +const NfcPollerBase* nfc_pollers_api[NfcProtocolNum] = { + [NfcProtocolIso14443_3a] = &nfc_poller_iso14443_3a, + [NfcProtocolIso14443_4a] = &nfc_poller_iso14443_4a, + [NfcProtocolMfUltralight] = &mf_ultralight_poller, + [NfcProtocolMfClassic] = &mf_classic_poller, + [NfcProtocolMfDesfire] = &mf_desfire_poller, }; /**************************** Poller tree structure **************************** @@ -26,43 +26,43 @@ const NfcPollerBase* nfc_pollers_api[NfcProtocolTypeMax] = { * mf desfire bank card */ -static const NfcProtocolType nfc_poller_iso14443_3a_children_protocol[] = { - NfcProtocolTypeIso14443_4a, - NfcProtocolTypeMfUltralight, +static const NfcProtocol nfc_poller_iso14443_3a_children_protocol[] = { + NfcProtocolIso14443_4a, + NfcProtocolMfUltralight, }; -static const NfcProtocolType nfc_poller_iso14443_4a_children_protocol[] = { - NfcProtocolTypeMfDesfire, +static const NfcProtocol nfc_poller_iso14443_4a_children_protocol[] = { + NfcProtocolMfDesfire, }; -const NfcPollerTreeNode nfc_poller_nodes[NfcProtocolTypeMax] = { - [NfcProtocolTypeIso14443_3a] = +const NfcPollerTreeNode nfc_poller_nodes[NfcProtocolNum] = { + [NfcProtocolIso14443_3a] = { - .parent_protocol = NfcProtocolTypeInvalid, + .parent_protocol = NfcProtocolInvalid, .children_num = COUNT_OF(nfc_poller_iso14443_3a_children_protocol), .children_protocol = nfc_poller_iso14443_3a_children_protocol, }, - [NfcProtocolTypeIso14443_4a] = + [NfcProtocolIso14443_4a] = { - .parent_protocol = NfcProtocolTypeIso14443_3a, + .parent_protocol = NfcProtocolIso14443_3a, .children_num = COUNT_OF(nfc_poller_iso14443_4a_children_protocol), .children_protocol = nfc_poller_iso14443_4a_children_protocol, }, - [NfcProtocolTypeMfUltralight] = + [NfcProtocolMfUltralight] = { - .parent_protocol = NfcProtocolTypeIso14443_3a, + .parent_protocol = NfcProtocolIso14443_3a, .children_num = 0, .children_protocol = NULL, }, - [NfcProtocolTypeMfClassic] = + [NfcProtocolMfClassic] = { - .parent_protocol = NfcProtocolTypeIso14443_3a, + .parent_protocol = NfcProtocolIso14443_3a, .children_num = 0, .children_protocol = NULL, }, - [NfcProtocolTypeMfDesfire] = + [NfcProtocolMfDesfire] = { - .parent_protocol = NfcProtocolTypeIso14443_4a, + .parent_protocol = NfcProtocolIso14443_4a, .children_num = 0, .children_protocol = NULL, }, diff --git a/lib/nfc/protocols/nfc_poller_defs.h b/lib/nfc/protocols/nfc_poller_defs.h index 8eb550ebf277..0b6c65e156e1 100644 --- a/lib/nfc/protocols/nfc_poller_defs.h +++ b/lib/nfc/protocols/nfc_poller_defs.h @@ -7,14 +7,14 @@ extern "C" { #endif typedef struct { - NfcProtocolType parent_protocol; + NfcProtocol parent_protocol; size_t children_num; - const NfcProtocolType* children_protocol; + const NfcProtocol* children_protocol; } NfcPollerTreeNode; -extern const NfcPollerBase* nfc_pollers_api[NfcProtocolTypeMax]; +extern const NfcPollerBase* nfc_pollers_api[NfcProtocolNum]; -extern const NfcPollerTreeNode nfc_poller_nodes[NfcProtocolTypeMax]; +extern const NfcPollerTreeNode nfc_poller_nodes[NfcProtocolNum]; #ifdef __cplusplus } diff --git a/lib/nfc/protocols/nfc_protocol_base.h b/lib/nfc/protocols/nfc_protocol_base.h deleted file mode 100644 index 575dbb4c4880..000000000000 --- a/lib/nfc/protocols/nfc_protocol_base.h +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum { - NfcProtocolNameTypeFull, - NfcProtocolNameTypeShort, -} NfcProtocolNameType; - -typedef void NfcProtocolData; - -typedef NfcProtocolData* (*NfcProtocolAlloc)(); -typedef void (*NfcProtocolFree)(NfcProtocolData* data); -typedef void (*NfcProtocolReset)(NfcProtocolData* data); -typedef void (*NfcProtocolCopy)(NfcProtocolData* data, const NfcProtocolData* other); -typedef bool (*NfcProtocolVerify)(NfcProtocolData* data, const FuriString* device_type); -typedef bool (*NfcProtocolLoad)(NfcProtocolData* data, FlipperFormat* ff, uint32_t version); -typedef bool (*NfcProtocolSave)(const NfcProtocolData* data, FlipperFormat* ff, uint32_t version); -typedef bool (*NfcProtocolEqual)(const NfcProtocolData* data, const NfcProtocolData* other); -typedef const char* ( - *NfcProtocolGetDeviceName)(const NfcProtocolData* data, NfcProtocolNameType name_type); -typedef const uint8_t* (*NfcProtocolGetUid)(const NfcProtocolData* data, size_t* uid_len); - -typedef struct { - const char* protocol_name; - NfcProtocolAlloc alloc; - NfcProtocolFree free; - NfcProtocolReset reset; - NfcProtocolCopy copy; - NfcProtocolVerify verify; - NfcProtocolLoad load; - NfcProtocolSave save; - NfcProtocolEqual is_equal; - NfcProtocolGetDeviceName get_device_name; - NfcProtocolGetUid get_uid; -} NfcProtocolBase; - -#ifdef __cplusplus -} -#endif diff --git a/lib/nfc/protocols/nfc_protocol_defs.c b/lib/nfc/protocols/nfc_protocol_defs.c deleted file mode 100644 index cb3bae78eb77..000000000000 --- a/lib/nfc/protocols/nfc_protocol_defs.c +++ /dev/null @@ -1,16 +0,0 @@ -#include "nfc_protocol_defs.h" - -#include -#include -#include -#include -#include - -const NfcProtocolBase* nfc_protocols[NfcProtocolTypeMax] = { - [NfcProtocolTypeIso14443_3a] = &nfc_protocol_iso14443_3a, - [NfcProtocolTypeIso14443_4a] = &nfc_protocol_iso14443_4a, - [NfcProtocolTypeMfUltralight] = &nfc_protocol_mf_ultralight, - [NfcProtocolTypeMfClassic] = &nfc_protocol_mf_classic, - [NfcProtocolTypeMfDesfire] = &nfc_protocol_mf_desfire, - /* Add new protocols here */ -}; diff --git a/lib/nfc/protocols/nfc_protocol_defs.h b/lib/nfc/protocols/nfc_protocol_defs.h deleted file mode 100644 index dee0b974a929..000000000000 --- a/lib/nfc/protocols/nfc_protocol_defs.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include "nfc_protocol_base.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum { - NfcProtocolTypeIso14443_3a, - NfcProtocolTypeIso14443_4a, - NfcProtocolTypeMfUltralight, - NfcProtocolTypeMfClassic, - NfcProtocolTypeMfDesfire, - /* Add new protocols here */ - - NfcProtocolTypeMax, - - NfcProtocolTypeInvalid, -} NfcProtocolType; - -extern const NfcProtocolBase* nfc_protocols[]; - -#ifdef __cplusplus -} -#endif diff --git a/lib/nfc/protocols/nfca/nfca.h b/lib/nfc/protocols/nfca/nfca.h deleted file mode 100644 index 113754e1a6e7..000000000000 --- a/lib/nfc/protocols/nfca/nfca.h +++ /dev/null @@ -1,104 +0,0 @@ -#pragma once - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define NFCA_MAX_UID_SIZE (10U) - -#define NFCA_GUARD_TIME_US (5000) -#define NFCA_FDT_POLL_FC (1620) -#define NFCA_FDT_LISTEN_FC (1172) -#define NFCA_POLLER_MASK_RX_FS ((NFCA_FDT_LISTEN_FC) / 2) -#define NFCA_POLL_POLL_MIN_US (1100) - -typedef enum { - NfcaErrorNone, - NfcaErrorNotPresent, - NfcaErrorColResFailed, - NfcaErrorBufferOverflow, - NfcaErrorCommunication, - NfcaErrorFieldOff, - NfcaErrorWrongCrc, - NfcaErrorTimeout, -} NfcaError; - -typedef struct { - uint8_t sens_resp[2]; -} NfcaSensResp; - -typedef struct { - uint8_t sel_cmd; - uint8_t sel_par; - uint8_t data[4]; // max data bit is 32 -} NfcaSddReq; - -typedef struct { - uint8_t nfcid[4]; - uint8_t bss; -} NfcaSddResp; - -typedef struct { - uint8_t sel_cmd; - uint8_t sel_par; - uint8_t nfcid[4]; - uint8_t bcc; -} NfcaSelReq; - -typedef struct { - uint8_t sak; -} NfcaSelResp; - -typedef struct { - uint8_t sak; -} NfcaRats; - -typedef struct { - uint8_t uid[NFCA_MAX_UID_SIZE]; - uint8_t uid_len; - uint8_t atqa[2]; - uint8_t sak; - NfcaRats rats; -} NfcaData; - -extern const NfcProtocolBase nfc_protocol_iso14443_3a; - -NfcaData* nfca_alloc(); - -void nfca_free(NfcaData* data); - -void nfca_reset(NfcaData* data); - -void nfca_copy(NfcaData* data, const NfcaData* other); - -bool nfca_verify(NfcaData* data, const FuriString* device_type); - -bool nfca_load(NfcaData* data, FlipperFormat* ff, uint32_t version); - -bool nfca_save(const NfcaData* data, FlipperFormat* ff, uint32_t version); - -bool nfca_is_equal(const NfcaData* data, const NfcaData* other); - -const char* nfca_get_device_name(const NfcaData* data, NfcProtocolNameType name_type); - -const uint8_t* nfca_get_uid(const NfcaData* data, size_t* uid_len); - -uint32_t nfca_get_cuid(NfcaData* nfca_data); - -void nfca_append_crc(BitBuffer* buffer); - -bool nfca_check_crc(const BitBuffer* buf); - -void nfca_trim_crc(BitBuffer* buf); - -// TODO: Decide where should these methods go (*_i file?) -bool nfca_load_data(NfcaData* data, FlipperFormat* ff, uint32_t version); - -bool nfca_save_data(const NfcaData* data, FlipperFormat* ff, uint32_t version); - -#ifdef __cplusplus -} -#endif diff --git a/lib/nfc/protocols/nfca/nfca_listener.c b/lib/nfc/protocols/nfca/nfca_listener.c deleted file mode 100644 index add21c293b9c..000000000000 --- a/lib/nfc/protocols/nfca/nfca_listener.c +++ /dev/null @@ -1,220 +0,0 @@ -#include "nfca_listener.h" - -#include -#include - -#define TAG "NfcaListener" - -#define NFCA_LISTENER_MAX_BUFFER_SIZE (256) - -typedef enum { - NfcaListenerStateIdle, - NfcaListenerStateActive, -} NfcaListenerState; - -struct NfcaListener { - Nfc* nfc; - NfcaData* data; - NfcaListenerState state; - NfcaListenerEventCallback callback; - - BitBuffer* tx_buffer; - void* context; -}; - -static NfcaError nfca_listener_process_nfc_error(NfcError error) { - NfcaError ret = NfcaErrorNone; - - if(error == NfcErrorNone) { - ret = NfcaErrorNone; - } else if(error == NfcErrorTimeout) { - ret = NfcaErrorTimeout; - } else { - ret = NfcaErrorFieldOff; - } - - return ret; -} - -static void nfca_listener_config(NfcaListener* instance) { - furi_assert(instance); - - instance->tx_buffer = bit_buffer_alloc(NFCA_LISTENER_MAX_BUFFER_SIZE); - - nfc_set_fdt_listen_fc(instance->nfc, NFCA_FDT_LISTEN_FC); - nfc_config(instance->nfc, NfcModeNfcaListener); - nfc_listener_set_col_res_data( - instance->nfc, - instance->data->uid, - instance->data->uid_len, - instance->data->atqa, - instance->data->sak); -} - -static void nfca_listener_reset(NfcaListener* instance) { - furi_assert(instance); - furi_assert(instance->tx_buffer); - - bit_buffer_free(instance->tx_buffer); - instance->tx_buffer = NULL; -} - -static bool nfca_listener_halt_received(BitBuffer* buf) { - bool halt_cmd_received = false; - - do { - if(bit_buffer_get_size_bytes(buf) != 4) break; - if(!nfca_check_crc(buf)) break; - if(bit_buffer_get_byte(buf, 0) != 0x50) break; - if(bit_buffer_get_byte(buf, 1) != 0x00) break; - halt_cmd_received = true; - } while(false); - - return halt_cmd_received; -} - -static NfcCommand nfca_listener_event_handler(NfcEvent event, void* context) { - furi_assert(context); - - NfcaListener* instance = context; - NfcEventType event_type = event.type; - NfcaListenerEvent nfca_listener_event = {}; - NfcCommand command = NfcCommandContinue; - - if(event_type == NfcEventTypeConfigureRequest) { - nfca_listener_config(instance); - if(instance->callback) { - nfca_listener_event.type = NfcaListenerEventConfigRequest; - instance->callback(nfca_listener_event, instance->context); - } - } else if(event_type == NfcEventTypeListenerActivated) { - instance->state = NfcaListenerStateActive; - } else if((event_type == NfcEventTypeRxEnd) && (instance->state == NfcaListenerStateActive)) { - if(nfca_listener_halt_received(event.data.buffer)) { - // TODO rework with commands - nfca_listener_sleep(instance); - instance->state = NfcaListenerStateIdle; - if(instance->callback) { - nfca_listener_event.type = NfcaListenerEventTypeHalted; - instance->callback(nfca_listener_event, instance->context); - } - } else if(instance->callback) { - if(nfca_check_crc(event.data.buffer)) { - nfca_listener_event.type = NfcaListenerEventTypeReceivedStandartFrame; - size_t bytes = bit_buffer_get_size_bytes(event.data.buffer); - bit_buffer_set_size_bytes(event.data.buffer, bytes - 2); - } else { - nfca_listener_event.type = NfcaListenerEventTypeReceivedData; - } - nfca_listener_event.data.buffer = event.data.buffer; - if(instance->callback) { - instance->callback(nfca_listener_event, instance->context); - } - } - } else if(event_type == NfcEventTypeReset) { - nfca_listener_reset(instance); - if(instance->callback) { - nfca_listener_event.type = NfcaListenerEventTypeReset; - instance->callback(nfca_listener_event, instance->context); - } - } - - return command; -} - -NfcaListener* nfca_listener_alloc(Nfc* nfc) { - furi_assert(nfc); - - NfcaListener* instance = malloc(sizeof(NfcaListener)); - instance->nfc = nfc; - - return instance; -} - -void nfca_listener_free(NfcaListener* instance) { - furi_assert(instance); - free(instance); -} - -NfcaError nfca_listener_start( - NfcaListener* instance, - const NfcaData* data, - NfcaListenerEventCallback callback, - void* context) { - furi_assert(instance); - - instance->callback = callback; - instance->context = context; - - instance->data = nfca_alloc(); - nfca_copy(instance->data, data); - - nfc_start_listener(instance->nfc, nfca_listener_event_handler, instance); - - return NfcaErrorNone; -} - -NfcaError nfca_listener_stop(NfcaListener* instance) { - furi_assert(instance); - - nfc_listener_abort(instance->nfc); - nfca_free(instance->data); - - instance->callback = NULL; - instance->context = NULL; - instance->state = NfcaListenerStateIdle; - - return NfcaErrorNone; -} - -NfcaError nfca_listener_get_data(NfcaListener* instance, NfcaData* data) { - furi_assert(instance); - - nfca_copy(data, instance->data); - - return NfcaErrorNone; -} - -NfcaError nfca_listener_sleep(NfcaListener* instance) { - furi_assert(instance); - - NfcError error = nfc_listener_sleep(instance->nfc); - instance->state = NfcaListenerStateIdle; - - return nfca_listener_process_nfc_error(error); -} - -NfcaError nfca_listener_tx(NfcaListener* instance, const BitBuffer* tx_buffer) { - furi_assert(instance); - furi_assert(tx_buffer); - - NfcaError ret = NfcaErrorNone; - NfcError error = nfc_listener_tx(instance->nfc, tx_buffer); - if(error != NfcErrorNone) { - FURI_LOG_W(TAG, "Tx error: %d", error); - ret = nfca_listener_process_nfc_error(error); - } - - return ret; -} - -NfcaError nfca_listener_send_standart_frame(NfcaListener* instance, const BitBuffer* tx_buffer) { - furi_assert(instance); - furi_assert(tx_buffer); - furi_assert(instance->tx_buffer); - - NfcaError ret = NfcaErrorNone; - do { - bit_buffer_copy(instance->tx_buffer, tx_buffer); - nfca_append_crc(instance->tx_buffer); - - NfcError error = nfc_listener_tx(instance->nfc, instance->tx_buffer); - if(error != NfcErrorNone) { - FURI_LOG_W(TAG, "Tx error: %d", error); - ret = nfca_listener_process_nfc_error(error); - break; - } - } while(false); - - return ret; -} diff --git a/lib/nfc/protocols/nfca/nfca_listener.h b/lib/nfc/protocols/nfca/nfca_listener.h deleted file mode 100644 index 2579aa5b43a2..000000000000 --- a/lib/nfc/protocols/nfca/nfca_listener.h +++ /dev/null @@ -1,63 +0,0 @@ -#pragma once - -#include "nfca.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct NfcaListener NfcaListener; - -typedef enum { - NfcaListenerEventConfigRequest, - NfcaListenerEventTypeAbort, - NfcaListenerEventTypeFieldOn, - NfcaListenerEventTypeFieldOff, - NfcaListenerEventTypeHalted, - NfcaListenerEventTypeReceivedStandartFrame, - NfcaListenerEventTypeReceivedData, - NfcaListenerEventTypeReset, -} NfcaListenerEventType; - -typedef struct { - BitBuffer* buffer; -} NfcaListenerEventData; - -typedef struct { - NfcaListenerEventType type; - NfcaListenerEventData data; -} NfcaListenerEvent; - -typedef enum { - NfcaListenerCommandContinue = NfcCommandContinue, - NfcaListenerCommandReset = NfcCommandReset, -} NfcaListenerCommand; - -typedef NfcaListenerCommand (*NfcaListenerEventCallback)(NfcaListenerEvent event, void* context); - -NfcaListener* nfca_listener_alloc(Nfc* nfc); - -void nfca_listener_free(NfcaListener* instance); - -NfcaError nfca_listener_start( - NfcaListener* instance, - const NfcaData* data, - NfcaListenerEventCallback callback, - void* context); - -NfcaError nfca_listener_get_data(NfcaListener* instance, NfcaData* data); - -NfcaError nfca_listener_stop(NfcaListener* instance); - -// Called from NfcWorker thread - -NfcaError nfca_listener_sleep(NfcaListener* instance); - -NfcaError nfca_listener_tx(NfcaListener* instance, const BitBuffer* tx_buffer); - -NfcaError nfca_listener_send_standart_frame(NfcaListener* instance, const BitBuffer* tx_buffer); - -#ifdef __cplusplus -} -#endif diff --git a/lib/nfc/protocols/nfca/nfca_poller.c b/lib/nfc/protocols/nfca/nfca_poller.c deleted file mode 100644 index 619932dbc2c6..000000000000 --- a/lib/nfc/protocols/nfca/nfca_poller.c +++ /dev/null @@ -1,122 +0,0 @@ -#include "nfca_poller_i.h" - -#include - -#include - -#define TAG "NFCA" - -const NfcaData* nfca_poller_get_data(NfcaPoller* instance) { - furi_assert(instance); - furi_assert(instance->data); - - return instance->data; -} - -static NfcaPoller* nfca_poller_alloc(Nfc* nfc) { - furi_assert(nfc); - - NfcaPoller* instance = malloc(sizeof(NfcaPoller)); - instance->nfc = nfc; - instance->tx_buffer = bit_buffer_alloc(NFCA_POLLER_MAX_BUFFER_SIZE); - instance->rx_buffer = bit_buffer_alloc(NFCA_POLLER_MAX_BUFFER_SIZE); - - nfc_config(instance->nfc, NfcModeNfcaPoller); - nfc_set_guard_time_us(instance->nfc, NFCA_GUARD_TIME_US); - nfc_set_fdt_poll_fc(instance->nfc, NFCA_FDT_POLL_FC); - nfc_set_fdt_poll_poll_us(instance->nfc, NFCA_POLL_POLL_MIN_US); - instance->data = nfca_alloc(); - - instance->nfca_event.data = &instance->nfca_event_data; - instance->general_event.protocol_type = NfcProtocolTypeIso14443_3a; - instance->general_event.data = &instance->nfca_event; - instance->general_event.poller = instance; - - return instance; -} - -static void nfca_poller_free_new(NfcaPoller* nfca_poller) { - furi_assert(nfca_poller); - - NfcaPoller* instance = nfca_poller; - furi_assert(instance->tx_buffer); - furi_assert(instance->rx_buffer); - furi_assert(instance->data); - - bit_buffer_free(instance->tx_buffer); - bit_buffer_free(instance->rx_buffer); - nfca_free(instance->data); - free(instance); -} - -static void - nfca_poller_set_callback(NfcaPoller* instance, NfcPollerCallback callback, void* context) { - furi_assert(instance); - furi_assert(callback); - - instance->callback = callback; - instance->context = context; -} - -static NfcCommand nfca_poller_run(NfcPollerEvent event, void* context) { - furi_assert(context); - furi_assert(event.protocol_type == NfcProtocolTypeInvalid); - furi_assert(event.data); - - NfcaPoller* instance = context; - NfcEvent* nfc_event = event.data; - NfcCommand command = NfcCommandContinue; - - if(nfc_event->type == NfcEventTypePollerReady) { - if(instance->state != NfcaPollerStateActivated) { - NfcaData data = {}; - NfcaError error = nfca_poller_async_activate(instance, &data); - if(error == NfcaErrorNone) { - instance->state = NfcaPollerStateActivated; - instance->nfca_event.type = NfcaPollerEventTypeReady; - instance->nfca_event_data.error = error; - command = instance->callback(instance->general_event, instance->context); - } else { - instance->nfca_event.type = NfcaPollerEventTypeError; - instance->nfca_event_data.error = error; - command = instance->callback(instance->general_event, instance->context); - // Add delay to switch context - furi_delay_ms(100); - } - } else { - instance->nfca_event.type = NfcaPollerEventTypeReady; - instance->nfca_event_data.error = NfcaErrorNone; - command = instance->callback(instance->general_event, instance->context); - } - } - - return command; -} - -static bool nfca_poller_detect(NfcPollerEvent event, void* context) { - furi_assert(context); - furi_assert(event.data); - furi_assert(event.poller); - furi_assert(event.protocol_type = NfcProtocolTypeInvalid); - - bool protocol_detected = false; - NfcaPoller* instance = context; - NfcEvent* nfc_event = event.data; - furi_assert(instance->state == NfcaPollerStateIdle); - - if(nfc_event->type == NfcEventTypePollerReady) { - NfcaError error = nfca_poller_async_activate(instance, NULL); - protocol_detected = (error == NfcaErrorNone); - } - - return protocol_detected; -} - -const NfcPollerBase nfc_poller_iso14443_3a = { - .alloc = (NfcPollerAlloc)nfca_poller_alloc, - .free = (NfcPollerFree)nfca_poller_free_new, - .set_callback = (NfcPollerSetCallback)nfca_poller_set_callback, - .run = (NfcPollerRun)nfca_poller_run, - .detect = (NfcPollerDetect)nfca_poller_detect, - .get_data = (NfcPollerGetData)nfca_poller_get_data, -}; diff --git a/lib/nfc/protocols/nfca/nfca_poller.h b/lib/nfc/protocols/nfca/nfca_poller.h deleted file mode 100644 index 7a8a4dd5ed98..000000000000 --- a/lib/nfc/protocols/nfca/nfca_poller.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include "nfca.h" -#include - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct NfcaPoller NfcaPoller; - -typedef enum { - NfcaPollerEventTypeError, - NfcaPollerEventTypeReady, -} NfcaPollerEventType; - -typedef struct { - NfcaError error; -} NfcaPollerEventData; - -typedef struct { - NfcaPollerEventType type; - NfcaPollerEventData* data; -} NfcaPollerEvent; - -#ifdef __cplusplus -} -#endif diff --git a/lib/nfc/protocols/nfca/nfca_poller_i.h b/lib/nfc/protocols/nfca/nfca_poller_i.h deleted file mode 100644 index d777dd30f4e0..000000000000 --- a/lib/nfc/protocols/nfca/nfca_poller_i.h +++ /dev/null @@ -1,95 +0,0 @@ -#pragma once - -#include "nfca_poller.h" - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define NFCA_POLLER_MAX_BUFFER_SIZE (512U) - -#define NFCA_POLLER_SEL_CMD(cascade_lvl) (0x93 + 2 * (cascade_lvl)) -#define NFCA_POLLER_SEL_PAR(bytes, bits) (((bytes) << 4 & 0xf0U) | ((bits)&0x0fU)) -#define NFCA_POLLER_SDD_CL (0x88U) - -typedef enum { - NfcaPollerColResStateStateIdle, - NfcaPollerColResStateStateNewCascade, - NfcaPollerColResStateStateSelectCascade, - NfcaPollerColResStateStateSuccess, - NfcaPollerColResStateStateFail, -} NfcaPollerColResState; - -typedef struct { - NfcaPollerColResState state; - NfcaSensResp sens_resp; - NfcaSddReq sdd_req; - NfcaSddResp sdd_resp; - NfcaSelReq sel_req; - NfcaSelResp sel_resp; - uint8_t cascade_level; -} NfcaPollerColRes; - -typedef enum { - NfcaPollerStateIdle, - NfcaPollerStateColResInProgress, - NfcaPollerStateColResFailed, - NfcaPollerStateActivated, -} NfcaPollerState; - -typedef enum { - NfcaPollerConfigStateIdle, - NfcaPollerConfigStateDone, -} NfcaPollerConfigState; - -struct NfcaPoller { - Nfc* nfc; - NfcaPollerState state; - NfcaPollerConfigState config_state; - NfcaPollerColRes col_res; - NfcaData* data; - BitBuffer* tx_buffer; - BitBuffer* rx_buffer; - - NfcPollerEvent general_event; - NfcaPollerEvent nfca_event; - NfcaPollerEventData nfca_event_data; - NfcPollerCallback callback; - void* context; -}; - -const NfcaData* nfca_poller_get_data(NfcaPoller* instance); - -NfcaError nfca_poller_config(NfcaPoller* instance); - -NfcaError nfca_poller_reset(NfcaPoller* instance); - -NfcaError nfca_poller_check_presence(NfcaPoller* instance); - -NfcaError nfca_poller_async_activate(NfcaPoller* instance, NfcaData* nfca_data); - -NfcaError nfca_poller_halt(NfcaPoller* instance); - -NfcaError nfca_poller_txrx_custom_parity( - NfcaPoller* instance, - const BitBuffer* tx_buffer, - BitBuffer* rx_buffer, - uint32_t fwt); - -NfcaError nfca_poller_txrx( - NfcaPoller* instance, - const BitBuffer* tx_buffer, - BitBuffer* rx_buffer, - uint32_t fwt); - -NfcaError nfca_poller_send_standart_frame( - NfcaPoller* instance, - const BitBuffer* tx_buffer, - BitBuffer* rx_buffer, - uint32_t fwt); - -#ifdef __cplusplus -} -#endif diff --git a/lib/nfc/protocols/nfca/nfca_poller_sync_api.c b/lib/nfc/protocols/nfca/nfca_poller_sync_api.c deleted file mode 100644 index d77d621542fb..000000000000 --- a/lib/nfc/protocols/nfca/nfca_poller_sync_api.c +++ /dev/null @@ -1,57 +0,0 @@ -#include "nfca_poller_sync_api.h" - -#include "nfca_poller_i.h" -#include - -#include - -#define NFCA_POLLER_FLAG_COMMAND_COMPLETE (1UL << 0) - -typedef struct { - NfcaPoller* instance; - FuriThreadId thread_id; - NfcaError error; - NfcaData data; -} NfcaPollerContext; - -NfcCommand nfca_poller_read_callback(NfcPollerEvent event, void* context) { - furi_assert(context); - furi_assert(event.data); - furi_assert(event.poller); - furi_assert(event.protocol_type == NfcProtocolTypeIso14443_3a); - - NfcaPollerContext* poller_context = context; - NfcaPoller* nfca_poller = event.poller; - NfcaPollerEvent* nfca_event = event.data; - - if(nfca_event->type == NfcaPollerEventTypeReady) { - nfca_copy(&poller_context->data, nfca_poller->data); - } - poller_context->error = nfca_event->data->error; - - furi_thread_flags_set(poller_context->thread_id, NFCA_POLLER_FLAG_COMMAND_COMPLETE); - - return NfcCommandStop; -} - -NfcaError nfca_poller_read(Nfc* nfc, NfcaData* nfca_data) { - furi_assert(nfc); - furi_assert(nfca_data); - - NfcaPollerContext poller_context = {}; - poller_context.thread_id = furi_thread_get_current_id(); - - NfcPoller* poller = nfc_poller_alloc(nfc, NfcProtocolTypeIso14443_3a); - nfc_poller_start(poller, nfca_poller_read_callback, &poller_context); - furi_thread_flags_wait(NFCA_POLLER_FLAG_COMMAND_COMPLETE, FuriFlagWaitAny, FuriWaitForever); - furi_thread_flags_clear(NFCA_POLLER_FLAG_COMMAND_COMPLETE); - - nfc_poller_stop(poller); - nfc_poller_free(poller); - - if(poller_context.error == NfcaErrorNone) { - *nfca_data = poller_context.data; - } - - return poller_context.error; -} \ No newline at end of file diff --git a/lib/nfc/protocols/nfca/nfca_poller_sync_api.h b/lib/nfc/protocols/nfca/nfca_poller_sync_api.h deleted file mode 100644 index b187d4e498a8..000000000000 --- a/lib/nfc/protocols/nfca/nfca_poller_sync_api.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include "nfca.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -NfcaError nfca_poller_read(Nfc* nfc, NfcaData* nfca_data); - -#ifdef __cplusplus -} -#endif diff --git a/lib/nfc/protocols/nfcb/nfcb.h b/lib/nfc/protocols/nfcb/nfcb.h index 5f10b1aac372..d23d1a6fdb76 100644 --- a/lib/nfc/protocols/nfcb/nfcb.h +++ b/lib/nfc/protocols/nfcb/nfcb.h @@ -10,7 +10,7 @@ extern "C" { #define NFCB_GUARD_TIME_US (5000) #define NFCB_FDT_POLL_FC (1620) #define NFCB_FDT_LISTEN_FC (1172) -#define NFCB_POLLER_MASK_RX_FS ((NFCA_FDT_LISTEN_FC) / 2) +#define NFCB_POLLER_MASK_RX_FS ((NFCB_FDT_LISTEN_FC) / 2) #define NFCB_POLL_POLL_MIN_US (1100) typedef enum { From 399c77bc3b66ffc116ad5a371285c545668eabcc Mon Sep 17 00:00:00 2001 From: gornekich Date: Thu, 29 Jun 2023 15:21:46 +0400 Subject: [PATCH 114/149] Generic listener part 0 (#2813) * nfc: rename poller_common -> generic_event * nfc: introduce nfc listener base * nfc: move nfc protocols to separate file * nfc: move protocol tree definition to protocols, add API * nfc: introduce nfc listener * nfc: implement generic listener --- .../nfc/helpers/handlers/nfc_poller_handler.c | 2 +- .../nfc/helpers/handlers/nfc_poller_handler.h | 4 +- .../nfc/plugins/nfc_supported_card_plugin.h | 2 +- .../scenes/nfc_scene_mf_classic_dict_attack.c | 2 +- applications/main/nfc/scenes/nfc_scene_read.c | 2 +- firmware/targets/f7/api_symbols.csv | 7 +- lib/nfc/nfc_device.h | 1 + lib/nfc/nfc_listener.c | 139 ++++++++++++++++++ lib/nfc/nfc_listener.h | 24 +++ lib/nfc/nfc_poller.c | 18 +-- lib/nfc/nfc_poller.h | 7 +- lib/nfc/nfc_scanner.c | 22 +-- lib/nfc/nfc_scanner.h | 2 +- .../iso14443_3a/iso14443_3a_poller.c | 6 +- .../iso14443_3a/iso14443_3a_poller_i.h | 4 +- .../iso14443_3a/iso14443_3a_poller_sync_api.c | 2 +- .../iso14443_4a/iso14443_4a_poller.c | 6 +- .../iso14443_4a/iso14443_4a_poller_i.h | 4 +- .../protocols/mf_classic/mf_classic_poller.c | 6 +- .../mf_classic/mf_classic_poller_i.h | 4 +- .../mf_classic/mf_classic_poller_sync_api.c | 2 +- .../protocols/mf_desfire/mf_desfire_poller.c | 6 +- .../mf_desfire/mf_desfire_poller_i.h | 4 +- .../mf_ultralight/mf_ultralight_poller.c | 6 +- .../mf_ultralight/mf_ultralight_poller_i.h | 4 +- .../mf_ultralight_poller_sync_api.c | 4 +- lib/nfc/protocols/nfc_device_defs.c | 2 + lib/nfc/protocols/nfc_device_defs.h | 13 -- lib/nfc/protocols/nfc_generic_event.h | 24 +++ lib/nfc/protocols/nfc_listener_base.h | 36 +++++ lib/nfc/protocols/nfc_listener_defs.c | 14 ++ lib/nfc/protocols/nfc_listener_defs.h | 14 ++ lib/nfc/protocols/nfc_poller_base.h | 15 +- lib/nfc/protocols/nfc_poller_common.h | 24 --- lib/nfc/protocols/nfc_poller_defs.c | 54 ------- lib/nfc/protocols/nfc_poller_defs.h | 9 +- lib/nfc/protocols/nfc_protocol.c | 85 +++++++++++ lib/nfc/protocols/nfc_protocol.h | 28 ++++ 38 files changed, 433 insertions(+), 175 deletions(-) create mode 100644 lib/nfc/nfc_listener.c create mode 100644 lib/nfc/nfc_listener.h create mode 100644 lib/nfc/protocols/nfc_generic_event.h create mode 100644 lib/nfc/protocols/nfc_listener_base.h create mode 100644 lib/nfc/protocols/nfc_listener_defs.c create mode 100644 lib/nfc/protocols/nfc_listener_defs.h delete mode 100644 lib/nfc/protocols/nfc_poller_common.h create mode 100644 lib/nfc/protocols/nfc_protocol.c create mode 100644 lib/nfc/protocols/nfc_protocol.h diff --git a/applications/main/nfc/helpers/handlers/nfc_poller_handler.c b/applications/main/nfc/helpers/handlers/nfc_poller_handler.c index a1d61c2f4a62..179e525ceb4c 100644 --- a/applications/main/nfc/helpers/handlers/nfc_poller_handler.c +++ b/applications/main/nfc/helpers/handlers/nfc_poller_handler.c @@ -97,7 +97,7 @@ static const NfcPollerReadHandler nfc_poller_handlers_read[] = { [NfcProtocolMfClassic] = (NfcPollerReadHandler)nfc_poller_handler_read_mf_classic, [NfcProtocolMfDesfire] = (NfcPollerReadHandler)nfc_poller_handler_read_mf_desfire, }; -NfcCustomEvent nfc_poller_handler_read(NfcPollerEvent event, void* context) { +NfcCustomEvent nfc_poller_handler_read(NfcGenericEvent event, void* context) { furi_assert(context); furi_assert(event.poller); furi_assert(event.data); diff --git a/applications/main/nfc/helpers/handlers/nfc_poller_handler.h b/applications/main/nfc/helpers/handlers/nfc_poller_handler.h index 10eee0dd9467..54eb809ada75 100644 --- a/applications/main/nfc/helpers/handlers/nfc_poller_handler.h +++ b/applications/main/nfc/helpers/handlers/nfc_poller_handler.h @@ -2,6 +2,6 @@ #include "../nfc_custom_event.h" -#include +#include -NfcCustomEvent nfc_poller_handler_read(NfcPollerEvent event, void* context); +NfcCustomEvent nfc_poller_handler_read(NfcGenericEvent event, void* context); diff --git a/applications/main/nfc/plugins/nfc_supported_card_plugin.h b/applications/main/nfc/plugins/nfc_supported_card_plugin.h index 1f84d5759a75..7cb21c98dcaa 100644 --- a/applications/main/nfc/plugins/nfc_supported_card_plugin.h +++ b/applications/main/nfc/plugins/nfc_supported_card_plugin.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #define NFC_SUPPORTED_CARD_PLUGIN_APP_ID "NfcSupportedCardPlugin" #define NFC_SUPPORTED_CARD_PLUGIN_API_VERSION 1 diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c index 8683ef340222..80edbd903c94 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c @@ -9,7 +9,7 @@ typedef enum { DictAttackStateFlipperDictInProgress, } DictAttackState; -NfcCommand nfc_dict_attack_worker_callback(NfcPollerEvent event, void* context) { +NfcCommand nfc_dict_attack_worker_callback(NfcGenericEvent event, void* context) { furi_assert(context); furi_assert(event.data); furi_assert(event.poller); diff --git a/applications/main/nfc/scenes/nfc_scene_read.c b/applications/main/nfc/scenes/nfc_scene_read.c index e533a71c0f70..3a2ac29525db 100644 --- a/applications/main/nfc/scenes/nfc_scene_read.c +++ b/applications/main/nfc/scenes/nfc_scene_read.c @@ -2,7 +2,7 @@ #include "../helpers/handlers/nfc_poller_handler.h" -static NfcCommand nfc_scene_read_poller_callback(NfcPollerEvent event, void* context) { +static NfcCommand nfc_scene_read_poller_callback(NfcGenericEvent event, void* context) { NfcApp* instance = context; const NfcCustomEvent custom_event = nfc_poller_handler_read(event, context); diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index e7103c19fbe3..d7524f858e51 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,+,36.0,, +Version,+,36.2,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -2066,8 +2066,10 @@ Function,-,nfc_poller_alloc,NfcPoller*,"Nfc*, NfcProtocol" Function,-,nfc_poller_detect,_Bool,NfcPoller* Function,-,nfc_poller_free,void,NfcPoller* Function,-,nfc_poller_get_data,const NfcDeviceData*,NfcPoller* -Function,-,nfc_poller_start,void,"NfcPoller*, NfcPollerCallback, void*" +Function,-,nfc_poller_start,void,"NfcPoller*, NfcGenericCallback, void*" Function,-,nfc_poller_stop,void,NfcPoller* +Function,-,nfc_protocol_get_parent,NfcProtocol,NfcProtocol +Function,-,nfc_protocol_has_parent,_Bool,"NfcProtocol, NfcProtocol" Function,-,nfc_set_fdt_listen_fc,void,"Nfc*, uint32_t" Function,-,nfc_set_fdt_poll_fc,void,"Nfc*, uint32_t" Function,-,nfc_set_fdt_poll_poll_us,void,"Nfc*, uint32_t" @@ -3334,7 +3336,6 @@ Variable,+,message_vibro_off,const NotificationMessage, Variable,+,message_vibro_on,const NotificationMessage, Variable,-,nfc_device_iso14443_3a,const NfcDeviceBase, Variable,-,nfc_device_mf_classic,const NfcDeviceBase, -Variable,-,nfc_devices,const NfcDeviceBase*[], Variable,+,sequence_audiovisual_alert,const NotificationSequence, Variable,+,sequence_blink_blue_10,const NotificationSequence, Variable,+,sequence_blink_blue_100,const NotificationSequence, diff --git a/lib/nfc/nfc_device.h b/lib/nfc/nfc_device.h index 6017734cc92d..b072a3adcfac 100644 --- a/lib/nfc/nfc_device.h +++ b/lib/nfc/nfc_device.h @@ -3,6 +3,7 @@ #include #include "protocols/nfc_device_defs.h" +#include "protocols/nfc_protocol.h" #ifdef __cplusplus extern "C" { diff --git a/lib/nfc/nfc_listener.c b/lib/nfc/nfc_listener.c new file mode 100644 index 000000000000..b270d0030e4e --- /dev/null +++ b/lib/nfc/nfc_listener.c @@ -0,0 +1,139 @@ +#include "nfc_listener.h" + +#include + +#include + +typedef struct NfcListenerListElement { + NfcProtocol protocol; + NfcGenericInstance* listener; + const NfcListenerBase* listener_api; + struct NfcListenerListElement* child; + struct NfcListenerListElement* parent; +} NfcListenerListElement; + +typedef struct { + NfcListenerListElement* head; + NfcListenerListElement* tail; +} NfcListenerList; + +struct NfcListener { + NfcProtocol protocol; + Nfc* nfc; + NfcListenerList list; +}; + +static void nfc_listener_list_alloc(NfcListener* instance, NfcDeviceData* data) { + instance->list.head = malloc(sizeof(NfcListenerListElement)); + instance->list.head->protocol = instance->protocol; + instance->list.head->listener_api = nfc_listeners_api[instance->protocol]; + instance->list.head->child = NULL; + instance->list.tail = instance->list.head; + + // Build linked list + do { + NfcProtocol parent_protocol = nfc_protocol_get_parent(instance->list.head->protocol); + if(parent_protocol == NfcProtocolInvalid) break; + + NfcListenerListElement* parent = malloc(sizeof(NfcListenerListElement)); + parent->protocol = parent_protocol; + parent->listener_api = nfc_listeners_api[parent_protocol]; + parent->child = instance->list.head; + instance->list.head->parent = parent; + + instance->list.head = parent; + } while(true); + + // Allocate listener instances + NfcListenerListElement* iter = instance->list.head; + iter->listener = iter->listener_api->alloc(instance->nfc); + + do { + if(iter->child == NULL) break; + iter->child->listener = iter->child->listener_api->alloc(iter->listener); + iter->listener_api->set_callback( + iter->listener, iter->child->listener_api->run, iter->child->listener); + + iter = iter->child; + } while(true); + + // Set data for each listener + iter = instance->list.tail; + iter->listener_api->set_data(iter->listener, data); + + do { + if(iter == instance->list.head) break; + + const NfcDeviceData* base_data = iter->listener_api->get_base_data(iter->listener); + iter->parent->listener_api->set_data(iter->parent->listener, base_data); + iter = iter->parent; + } while(false); +} + +static void nfc_listener_list_free(NfcListener* instance) { + do { + instance->list.head->listener_api->free(instance->list.head->listener); + NfcListenerListElement* child = instance->list.head->child; + free(instance->list.head); + if(child == NULL) break; + instance->list.head = child; + } while(true); +} + +NfcListener* nfc_listener_alloc(Nfc* nfc, NfcProtocol protocol, NfcDeviceData* data) { + furi_assert(nfc); + furi_assert(protocol < NfcProtocolNum); + furi_assert(data); + + NfcListener* instance = malloc(sizeof(NfcListener)); + instance->nfc = nfc; + instance->protocol = protocol; + nfc_listener_list_alloc(instance, data); + + return instance; +} + +void nfc_listener_free(NfcListener* instance) { + furi_assert(instance); + + nfc_listener_list_free(instance); + free(instance); +} + +NfcCommand nfc_listener_start_callback(NfcEvent event, void* context) { + furi_assert(context); + + NfcListener* instance = context; + furi_assert(instance->list.head); + + NfcCommand command = NfcCommandContinue; + NfcGenericEvent generic_event = { + .protocol = NfcProtocolInvalid, + .poller = instance->nfc, + .data = &event, + }; + + NfcListenerListElement* head_listener = instance->list.head; + command = head_listener->listener_api->run(generic_event, head_listener->listener); + + return command; +} + +void nfc_listener_start(NfcListener* instance) { + furi_assert(instance); + + nfc_start_listener(instance->nfc, nfc_listener_start_callback, instance); +} + +void nfc_listener_stop(NfcListener* instance) { + furi_assert(instance); + + nfc_listener_abort(instance->nfc); +} + +const NfcDeviceData* nfc_listener_get_data(NfcListener* instance) { + furi_assert(instance); + + NfcListenerListElement* tail_element = instance->list.tail; + return tail_element->listener_api->get_base_data(tail_element->listener); +} diff --git a/lib/nfc/nfc_listener.h b/lib/nfc/nfc_listener.h new file mode 100644 index 000000000000..0e84499e79f2 --- /dev/null +++ b/lib/nfc/nfc_listener.h @@ -0,0 +1,24 @@ +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct NfcListener NfcListener; + +NfcListener* nfc_listener_alloc(Nfc* nfc, NfcProtocol protocol, NfcDeviceData* data); + +void nfc_listener_free(NfcListener* instance); + +void nfc_listener_start(NfcListener* instance); + +void nfc_listener_stop(NfcListener* instance); + +const NfcDeviceData* nfc_listener_get_data(NfcListener* instnace); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/nfc_poller.c b/lib/nfc/nfc_poller.c index 974b2436e9fe..69d86376f3aa 100644 --- a/lib/nfc/nfc_poller.c +++ b/lib/nfc/nfc_poller.c @@ -12,7 +12,7 @@ typedef enum { typedef struct NfcPollerListElement { NfcProtocol protocol; - NfcPollerInstance* poller; + NfcGenericInstance* poller; const NfcPollerBase* poller_api; struct NfcPollerListElement* child; } NfcPollerListElement; @@ -38,12 +38,12 @@ static void nfc_poller_list_alloc(NfcPoller* instance) { instance->list.tail = instance->list.head; do { - const NfcPollerTreeNode* node = &nfc_poller_nodes[instance->list.head->protocol]; - if(node->parent_protocol == NfcProtocolInvalid) break; + NfcProtocol parent_protocol = nfc_protocol_get_parent(instance->list.head->protocol); + if(parent_protocol == NfcProtocolInvalid) break; NfcPollerListElement* parent = malloc(sizeof(NfcPollerListElement)); - parent->protocol = node->parent_protocol; - parent->poller_api = nfc_pollers_api[node->parent_protocol]; + parent->protocol = parent_protocol; + parent->poller_api = nfc_pollers_api[parent_protocol]; parent->child = instance->list.head; instance->list.head = parent; } while(true); @@ -97,7 +97,7 @@ static NfcCommand nfc_poller_start_callback(NfcEvent event, void* context) { NfcPoller* instance = context; NfcCommand command = NfcCommandContinue; - NfcPollerEvent poller_event = { + NfcGenericEvent poller_event = { .protocol = NfcProtocolInvalid, .poller = instance->nfc, .data = &event, @@ -115,7 +115,7 @@ static NfcCommand nfc_poller_start_callback(NfcEvent event, void* context) { return command; } -void nfc_poller_start(NfcPoller* instance, NfcPollerCallback callback, void* context) { +void nfc_poller_start(NfcPoller* instance, NfcGenericCallback callback, void* context) { furi_assert(instance); furi_assert(callback); furi_assert(instance->session_state == NfcPollerSessionStateIdle); @@ -137,7 +137,7 @@ void nfc_poller_stop(NfcPoller* instance) { } // TODO change name -static NfcCommand nfc_poller_detect_tail_callback(NfcPollerEvent event, void* context) { +static NfcCommand nfc_poller_detect_tail_callback(NfcGenericEvent event, void* context) { furi_assert(context); NfcPoller* instance = context; @@ -155,7 +155,7 @@ static NfcCommand nfc_poller_detect_callback(NfcEvent event, void* context) { NfcPollerListElement* head_poller = instance->list.head; NfcCommand command = NfcCommandContinue; - NfcPollerEvent poller_event = { + NfcGenericEvent poller_event = { .protocol = NfcProtocolInvalid, .poller = instance->nfc, .data = &event, diff --git a/lib/nfc/nfc_poller.h b/lib/nfc/nfc_poller.h index 06bc0c3d76d1..4c7603da7dae 100644 --- a/lib/nfc/nfc_poller.h +++ b/lib/nfc/nfc_poller.h @@ -1,18 +1,19 @@ #pragma once +#include +#include + #ifdef __cplusplus extern "C" { #endif -#include - typedef struct NfcPoller NfcPoller; NfcPoller* nfc_poller_alloc(Nfc* nfc, NfcProtocol protocol); void nfc_poller_free(NfcPoller* instance); -void nfc_poller_start(NfcPoller* instance, NfcPollerCallback callback, void* context); +void nfc_poller_start(NfcPoller* instance, NfcGenericCallback callback, void* context); void nfc_poller_stop(NfcPoller* instance); diff --git a/lib/nfc/nfc_scanner.c b/lib/nfc/nfc_scanner.c index 0aa621dc25b3..e4c10a919783 100644 --- a/lib/nfc/nfc_scanner.c +++ b/lib/nfc/nfc_scanner.c @@ -66,7 +66,8 @@ typedef void (*NfcScannerStateHandler)(NfcScanner* instance); void nfc_scanner_state_handler_idle(NfcScanner* instance) { for(size_t i = 0; i < NfcProtocolNum; i++) { - if(nfc_poller_nodes[i].parent_protocol == NfcProtocolInvalid) { + NfcProtocol parent_protocol = nfc_protocol_get_parent(i); + if(parent_protocol == NfcProtocolInvalid) { instance->base_protocols[instance->base_protocols_num] = i; instance->base_protocols_num++; } @@ -98,24 +99,9 @@ void nfc_scanner_state_handler_try_base_pollers(NfcScanner* instance) { } } -static bool nfc_scanner_check_parent_protocol(NfcProtocol child, NfcProtocol parent) { - bool parent_found = false; - - const NfcPollerTreeNode* iter = &nfc_poller_nodes[child]; - while(iter->parent_protocol != NfcProtocolInvalid) { - if(iter->parent_protocol == parent) { - parent_found = true; - break; - } - iter = &nfc_poller_nodes[iter->parent_protocol]; - } - - return parent_found; -} - void nfc_scanner_state_handler_find_children_protocols(NfcScanner* instance) { for(size_t i = 0; i < NfcProtocolNum; i++) { - if(nfc_scanner_check_parent_protocol(i, instance->current_protocol)) { + if(nfc_protocol_has_parent(i, instance->current_protocol)) { instance->children_protocols[instance->children_protocols_num] = i; instance->children_protocols_num++; } @@ -157,7 +143,7 @@ static void nfc_scanner_filter_detected_protocols(NfcScanner* instance) { for(size_t i = 0; i < instance->detected_protocols_num; i++) { bool is_parent = false; for(size_t j = i; j < instance->detected_protocols_num; j++) { - is_parent = nfc_scanner_check_parent_protocol( + is_parent = nfc_protocol_has_parent( instance->detected_protocols[j], instance->detected_protocols[i]); if(is_parent) break; } diff --git a/lib/nfc/nfc_scanner.h b/lib/nfc/nfc_scanner.h index 63ed1fc02bd4..bcf1ddd51e56 100644 --- a/lib/nfc/nfc_scanner.h +++ b/lib/nfc/nfc_scanner.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #ifdef __cplusplus extern "C" { diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.c b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.c index a5d7d4676783..554c9b1790b5 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.c +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.c @@ -51,7 +51,7 @@ static void iso14443_3a_poller_free_new(Iso14443_3aPoller* iso14443_3a_poller) { static void iso14443_3a_poller_set_callback( Iso14443_3aPoller* instance, - NfcPollerCallback callback, + NfcGenericCallback callback, void* context) { furi_assert(instance); furi_assert(callback); @@ -60,7 +60,7 @@ static void iso14443_3a_poller_set_callback( instance->context = context; } -static NfcCommand iso14443_3a_poller_run(NfcPollerEvent event, void* context) { +static NfcCommand iso14443_3a_poller_run(NfcGenericEvent event, void* context) { furi_assert(context); furi_assert(event.protocol == NfcProtocolInvalid); furi_assert(event.data); @@ -95,7 +95,7 @@ static NfcCommand iso14443_3a_poller_run(NfcPollerEvent event, void* context) { return command; } -static bool iso14443_3a_poller_detect(NfcPollerEvent event, void* context) { +static bool iso14443_3a_poller_detect(NfcGenericEvent event, void* context) { furi_assert(context); furi_assert(event.data); furi_assert(event.poller); diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.h b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.h index 9ae3cfb332ad..1ca452b23266 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.h +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.h @@ -53,10 +53,10 @@ struct Iso14443_3aPoller { BitBuffer* tx_buffer; BitBuffer* rx_buffer; - NfcPollerEvent general_event; + NfcGenericEvent general_event; Iso14443_3aPollerEvent iso14443_3a_event; Iso14443_3aPollerEventData iso14443_3a_event_data; - NfcPollerCallback callback; + NfcGenericCallback callback; void* context; }; diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_sync_api.c b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_sync_api.c index 1edb4454a9f0..590512c099a1 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_sync_api.c +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_sync_api.c @@ -14,7 +14,7 @@ typedef struct { Iso14443_3aData data; } Iso14443_3aPollerContext; -NfcCommand iso14443_3a_poller_read_callback(NfcPollerEvent event, void* context) { +NfcCommand iso14443_3a_poller_read_callback(NfcGenericEvent event, void* context) { furi_assert(context); furi_assert(event.data); furi_assert(event.poller); diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.c b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.c index 79305ee6005b..ab98f1ae5535 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.c +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.c @@ -89,7 +89,7 @@ static const Iso14443_4aPollerStateHandler static void iso14443_4a_poller_set_callback( Iso14443_4aPoller* instance, - NfcPollerCallback callback, + NfcGenericCallback callback, void* context) { furi_assert(instance); furi_assert(callback); @@ -98,7 +98,7 @@ static void iso14443_4a_poller_set_callback( instance->context = context; } -static NfcCommand iso14443_4a_poller_run(NfcPollerEvent event, void* context) { +static NfcCommand iso14443_4a_poller_run(NfcGenericEvent event, void* context) { furi_assert(event.protocol == NfcProtocolIso14443_3a); Iso14443_4aPoller* instance = context; @@ -120,7 +120,7 @@ static NfcCommand iso14443_4a_poller_run(NfcPollerEvent event, void* context) { return command; } -static bool iso14443_4a_poller_detect(NfcPollerEvent event, void* context) { +static bool iso14443_4a_poller_detect(NfcGenericEvent event, void* context) { furi_assert(event.protocol == NfcProtocolIso14443_3a); const Iso14443_4aPoller* instance = context; diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.h b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.h index 47ba6a69dde7..b90b7c2000fc 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.h +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.h @@ -40,8 +40,8 @@ struct Iso14443_4aPoller { BitBuffer* rx_buffer; Iso14443_4aPollerEventData iso14443_4a_event_data; Iso14443_4aPollerEvent iso14443_4a_event; - NfcPollerEvent general_event; - NfcPollerCallback callback; + NfcGenericEvent general_event; + NfcGenericCallback callback; void* context; }; diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller.c b/lib/nfc/protocols/mf_classic/mf_classic_poller.c index f44808ddc609..32ee2c926ddb 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller.c @@ -278,7 +278,7 @@ static const MfClassicPollerReadHandler [MfClassicPollerStateReadComplete] = mf_classic_poller_handler_read_complete, }; -NfcCommand mf_classsic_poller_run(NfcPollerEvent event, void* context) { +NfcCommand mf_classsic_poller_run(NfcGenericEvent event, void* context) { furi_assert(event.data); furi_assert(event.protocol == NfcProtocolIso14443_3a); furi_assert(context); @@ -303,7 +303,7 @@ NfcCommand mf_classsic_poller_run(NfcPollerEvent event, void* context) { return command; } -bool mf_classsic_poller_detect(NfcPollerEvent event, void* context) { +bool mf_classsic_poller_detect(NfcGenericEvent event, void* context) { furi_assert(event.data); furi_assert(event.protocol == NfcProtocolIso14443_3a); furi_assert(context); @@ -313,7 +313,7 @@ bool mf_classsic_poller_detect(NfcPollerEvent event, void* context) { void mf_classic_poller_set_callback( MfClassicPoller* instance, - NfcPollerCallback callback, + NfcGenericCallback callback, void* context) { furi_assert(instance); furi_assert(callback); diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h index 2a232b685818..6f4cf35649d8 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h @@ -57,10 +57,10 @@ struct MfClassicPoller { BitBuffer* rx_encrypted_buffer; MfClassicData* data; - NfcPollerEvent general_event; + NfcGenericEvent general_event; MfClassicPollerEvent mfc_event; MfClassicPollerEventData mfc_event_data; - NfcPollerCallback callback; + NfcGenericCallback callback; void* context; }; diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.c b/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.c index c3cc4a75cd4f..f7fe5ad35ade 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.c @@ -57,7 +57,7 @@ static const MfClassicPollerCmdHandler mf_classic_poller_cmd_handlers[MfClassicP [MfClassicPollerCmdTypeReadBlock] = mf_classic_poller_read_block_handler, }; -static NfcCommand mf_ultralgiht_poller_cmd_callback(NfcPollerEvent event, void* context) { +static NfcCommand mf_ultralgiht_poller_cmd_callback(NfcGenericEvent event, void* context) { furi_assert(event.poller); furi_assert(event.protocol == NfcProtocolIso14443_3a); furi_assert(event.data); diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c b/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c index 3273785de262..df8e045b11c8 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c @@ -182,7 +182,7 @@ static const MfDesfirePollerReadHandler mf_desfire_poller_read_handler[MfDesfire static void mf_desfire_poller_set_callback( MfDesfirePoller* instance, - NfcPollerCallback callback, + NfcGenericCallback callback, void* context) { furi_assert(instance); furi_assert(callback); @@ -191,7 +191,7 @@ static void mf_desfire_poller_set_callback( instance->context = context; } -static NfcCommand mf_desfire_poller_run(NfcPollerEvent event, void* context) { +static NfcCommand mf_desfire_poller_run(NfcGenericEvent event, void* context) { furi_assert(event.protocol == NfcProtocolIso14443_4a); MfDesfirePoller* instance = context; @@ -213,7 +213,7 @@ static NfcCommand mf_desfire_poller_run(NfcPollerEvent event, void* context) { return command; } -static bool mf_desfire_poller_detect(NfcPollerEvent event, void* context) { +static bool mf_desfire_poller_detect(NfcGenericEvent event, void* context) { furi_assert(event.protocol == NfcProtocolIso14443_4a); MfDesfirePoller* instance = context; diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.h b/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.h index 9a5e7096a0ff..1f01e65d2716 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.h +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.h @@ -42,8 +42,8 @@ struct MfDesfirePoller { BitBuffer* result_buffer; MfDesfirePollerEventData mf_desfire_event_data; MfDesfirePollerEvent mf_desfire_event; - NfcPollerEvent general_event; - NfcPollerCallback callback; + NfcGenericEvent general_event; + NfcGenericCallback callback; void* context; }; diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c index 1cc7ee36ffc1..d050fa8ed78d 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c @@ -198,7 +198,7 @@ void mf_ultralight_poller_free(MfUltralightPoller* instance) { static void mf_ultralight_poller_set_callback( MfUltralightPoller* instance, - NfcPollerCallback callback, + NfcGenericCallback callback, void* context) { furi_assert(instance); furi_assert(callback); @@ -491,7 +491,7 @@ static const MfUltralightPollerReadHandler }; -static NfcCommand mf_ultralight_poller_run(NfcPollerEvent event, void* context) { +static NfcCommand mf_ultralight_poller_run(NfcGenericEvent event, void* context) { furi_assert(context); furi_assert(event.data); furi_assert(event.protocol == NfcProtocolIso14443_3a); @@ -513,7 +513,7 @@ static NfcCommand mf_ultralight_poller_run(NfcPollerEvent event, void* context) return command; } -static bool mf_ultralight_poller_detect(NfcPollerEvent event, void* context) { +static bool mf_ultralight_poller_detect(NfcGenericEvent event, void* context) { furi_assert(context); furi_assert(event.data); furi_assert(event.protocol == NfcProtocolIso14443_3a); diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h index 5d89902262fe..420fb6a7eeff 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h @@ -80,10 +80,10 @@ struct MfUltralightPoller { uint8_t tearing_flag_total; MfUltralightError error; - NfcPollerEvent general_event; + NfcGenericEvent general_event; MfUltralightPollerEvent mfu_event; MfUltralightPollerEventData mfu_event_data; - NfcPollerCallback callback; + NfcGenericCallback callback; void* context; }; diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c index 18df55ab171e..3a263e9544c7 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c @@ -79,7 +79,7 @@ static const MfUltralightPollerCmdHandler mf_ultralight_poller_read_tearing_flag_handler, }; -static NfcCommand mf_ultralgiht_poller_cmd_callback(NfcPollerEvent event, void* context) { +static NfcCommand mf_ultralgiht_poller_cmd_callback(NfcGenericEvent event, void* context) { furi_assert(event.poller); furi_assert(event.protocol == NfcProtocolIso14443_3a); furi_assert(event.data); @@ -232,7 +232,7 @@ MfUltralightError mf_ultralight_poller_read_tearing_flag( return error; } -static NfcCommand mf_ultralight_poller_read_callback(NfcPollerEvent event, void* context) { +static NfcCommand mf_ultralight_poller_read_callback(NfcGenericEvent event, void* context) { furi_assert(context); furi_assert(event.poller); furi_assert(event.data); diff --git a/lib/nfc/protocols/nfc_device_defs.c b/lib/nfc/protocols/nfc_device_defs.c index 1e27c83379a3..6095206aaff3 100644 --- a/lib/nfc/protocols/nfc_device_defs.c +++ b/lib/nfc/protocols/nfc_device_defs.c @@ -1,5 +1,7 @@ #include "nfc_device_defs.h" +#include "nfc_protocol.h" + #include #include #include diff --git a/lib/nfc/protocols/nfc_device_defs.h b/lib/nfc/protocols/nfc_device_defs.h index e84bf6a9e102..42f8d206ad51 100644 --- a/lib/nfc/protocols/nfc_device_defs.h +++ b/lib/nfc/protocols/nfc_device_defs.h @@ -6,19 +6,6 @@ extern "C" { #endif -typedef enum { - NfcProtocolIso14443_3a, - NfcProtocolIso14443_4a, - NfcProtocolMfUltralight, - NfcProtocolMfClassic, - NfcProtocolMfDesfire, - /* Add new protocols here */ - - NfcProtocolNum, - - NfcProtocolInvalid, -} NfcProtocol; - extern const NfcDeviceBase* nfc_devices[]; #ifdef __cplusplus diff --git a/lib/nfc/protocols/nfc_generic_event.h b/lib/nfc/protocols/nfc_generic_event.h new file mode 100644 index 000000000000..dac6a69fed6b --- /dev/null +++ b/lib/nfc/protocols/nfc_generic_event.h @@ -0,0 +1,24 @@ +#pragma once + +#include "nfc_protocol.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void NfcGenericInstance; + +typedef void NfcGenericEventData; + +typedef struct { + NfcProtocol protocol; + NfcGenericInstance* poller; + NfcGenericEventData* data; +} NfcGenericEvent; + +typedef NfcCommand (*NfcGenericCallback)(NfcGenericEvent event, void* context); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/nfc_listener_base.h b/lib/nfc/protocols/nfc_listener_base.h new file mode 100644 index 000000000000..028622c6a7b4 --- /dev/null +++ b/lib/nfc/protocols/nfc_listener_base.h @@ -0,0 +1,36 @@ +#pragma once + +#include "nfc_generic_event.h" +#include "nfc_device_base.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef NfcGenericInstance* (*NfcListenerAlloc)(NfcGenericInstance* base_listener); +typedef void (*NfcListenerFree)(NfcGenericInstance* instance); + +typedef const NfcDeviceData* (*NfcListenerGetBaseData)(const NfcGenericInstance* instance); +typedef void (*NfcListenerSetData)(NfcGenericInstance* instance, const NfcDeviceData* data); + +typedef void (*NfcListenerSetCallback)( + NfcGenericInstance* listener, + NfcGenericCallback callback, + void* context); +typedef NfcCommand (*NfcListenerRun)(NfcGenericEvent event, void* context); + +typedef const NfcDeviceData* (*NfcListenerGetData)(const NfcGenericInstance* instance); + +typedef struct { + NfcListenerAlloc alloc; + NfcListenerFree free; + NfcListenerGetBaseData get_base_data; + NfcListenerSetData set_data; + NfcListenerSetCallback set_callback; + NfcListenerRun run; + NfcListenerGetData get_data; +} NfcListenerBase; + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/nfc_listener_defs.c b/lib/nfc/protocols/nfc_listener_defs.c new file mode 100644 index 000000000000..8e7cc377a5ec --- /dev/null +++ b/lib/nfc/protocols/nfc_listener_defs.c @@ -0,0 +1,14 @@ +#include "nfc_listener_defs.h" + +// #include +// #include +// #include +// #include + +const NfcListenerBase* nfc_listeners_api[NfcProtocolNum] = { + [NfcProtocolIso14443_3a] = NULL, //&nfc_listener_iso14443_3a, + [NfcProtocolIso14443_4a] = NULL, //&nfc_listener_iso14443_4a, + [NfcProtocolMfUltralight] = NULL, //&mf_ultralight_listener, + [NfcProtocolMfClassic] = NULL, //&mf_classic_listener, + [NfcProtocolMfDesfire] = NULL, +}; diff --git a/lib/nfc/protocols/nfc_listener_defs.h b/lib/nfc/protocols/nfc_listener_defs.h new file mode 100644 index 000000000000..4d88cc09830d --- /dev/null +++ b/lib/nfc/protocols/nfc_listener_defs.h @@ -0,0 +1,14 @@ +#pragma once + +#include "nfc_listener_base.h" +#include "nfc_protocol.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern const NfcListenerBase* nfc_listeners_api[NfcProtocolNum]; + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/nfc_poller_base.h b/lib/nfc/protocols/nfc_poller_base.h index 7c03e36ba321..7f05ea33f5b3 100644 --- a/lib/nfc/protocols/nfc_poller_base.h +++ b/lib/nfc/protocols/nfc_poller_base.h @@ -1,19 +1,20 @@ #pragma once -#include "nfc_poller_common.h" +#include "nfc_generic_event.h" +#include "nfc_device_base.h" #ifdef __cplusplus extern "C" { #endif -typedef NfcPollerInstance* (*NfcPollerAlloc)(NfcPollerInstance* base_poller); -typedef void (*NfcPollerFree)(NfcPollerInstance* instance); +typedef NfcGenericInstance* (*NfcPollerAlloc)(NfcGenericInstance* base_poller); +typedef void (*NfcPollerFree)(NfcGenericInstance* instance); typedef void ( - *NfcPollerSetCallback)(NfcPollerInstance* poller, NfcPollerCallback callback, void* context); -typedef NfcCommand (*NfcPollerRun)(NfcPollerEvent event, void* context); -typedef bool (*NfcPollerDetect)(NfcPollerEvent event, void* context); -typedef const NfcDeviceData* (*NfcPollerGetData)(const NfcPollerInstance* instance); + *NfcPollerSetCallback)(NfcGenericInstance* poller, NfcGenericCallback callback, void* context); +typedef NfcCommand (*NfcPollerRun)(NfcGenericEvent event, void* context); +typedef bool (*NfcPollerDetect)(NfcGenericEvent event, void* context); +typedef const NfcDeviceData* (*NfcPollerGetData)(const NfcGenericInstance* instance); typedef struct { NfcPollerAlloc alloc; diff --git a/lib/nfc/protocols/nfc_poller_common.h b/lib/nfc/protocols/nfc_poller_common.h deleted file mode 100644 index 76210d7a8633..000000000000 --- a/lib/nfc/protocols/nfc_poller_common.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include "nfc_device_defs.h" -#include "nfc.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef void NfcPollerInstance; - -typedef void NfcPollerEventData; - -typedef struct { - NfcProtocol protocol; - NfcPollerInstance* poller; - NfcPollerEventData* data; -} NfcPollerEvent; - -typedef NfcCommand (*NfcPollerCallback)(NfcPollerEvent event, void* context); - -#ifdef __cplusplus -} -#endif diff --git a/lib/nfc/protocols/nfc_poller_defs.c b/lib/nfc/protocols/nfc_poller_defs.c index 84960652c13b..e54320e2bb7b 100644 --- a/lib/nfc/protocols/nfc_poller_defs.c +++ b/lib/nfc/protocols/nfc_poller_defs.c @@ -6,8 +6,6 @@ #include #include -#include - const NfcPollerBase* nfc_pollers_api[NfcProtocolNum] = { [NfcProtocolIso14443_3a] = &nfc_poller_iso14443_3a, [NfcProtocolIso14443_4a] = &nfc_poller_iso14443_4a, @@ -15,55 +13,3 @@ const NfcPollerBase* nfc_pollers_api[NfcProtocolNum] = { [NfcProtocolMfClassic] = &mf_classic_poller, [NfcProtocolMfDesfire] = &mf_desfire_poller, }; - -/**************************** Poller tree structure **************************** - * _________ start ___________________________ - * / | | \ - * _________ iso14443-3a _______ nfc-b nfc-f nfc-v - * / | \ - * iso14443-4a mf ultralight mf classic - * / \ - * mf desfire bank card - */ - -static const NfcProtocol nfc_poller_iso14443_3a_children_protocol[] = { - NfcProtocolIso14443_4a, - NfcProtocolMfUltralight, -}; - -static const NfcProtocol nfc_poller_iso14443_4a_children_protocol[] = { - NfcProtocolMfDesfire, -}; - -const NfcPollerTreeNode nfc_poller_nodes[NfcProtocolNum] = { - [NfcProtocolIso14443_3a] = - { - .parent_protocol = NfcProtocolInvalid, - .children_num = COUNT_OF(nfc_poller_iso14443_3a_children_protocol), - .children_protocol = nfc_poller_iso14443_3a_children_protocol, - }, - [NfcProtocolIso14443_4a] = - { - .parent_protocol = NfcProtocolIso14443_3a, - .children_num = COUNT_OF(nfc_poller_iso14443_4a_children_protocol), - .children_protocol = nfc_poller_iso14443_4a_children_protocol, - }, - [NfcProtocolMfUltralight] = - { - .parent_protocol = NfcProtocolIso14443_3a, - .children_num = 0, - .children_protocol = NULL, - }, - [NfcProtocolMfClassic] = - { - .parent_protocol = NfcProtocolIso14443_3a, - .children_num = 0, - .children_protocol = NULL, - }, - [NfcProtocolMfDesfire] = - { - .parent_protocol = NfcProtocolIso14443_4a, - .children_num = 0, - .children_protocol = NULL, - }, -}; diff --git a/lib/nfc/protocols/nfc_poller_defs.h b/lib/nfc/protocols/nfc_poller_defs.h index 0b6c65e156e1..a406a5f08b42 100644 --- a/lib/nfc/protocols/nfc_poller_defs.h +++ b/lib/nfc/protocols/nfc_poller_defs.h @@ -1,21 +1,14 @@ #pragma once #include "nfc_poller_base.h" +#include "nfc_protocol.h" #ifdef __cplusplus extern "C" { #endif -typedef struct { - NfcProtocol parent_protocol; - size_t children_num; - const NfcProtocol* children_protocol; -} NfcPollerTreeNode; - extern const NfcPollerBase* nfc_pollers_api[NfcProtocolNum]; -extern const NfcPollerTreeNode nfc_poller_nodes[NfcProtocolNum]; - #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/nfc_protocol.c b/lib/nfc/protocols/nfc_protocol.c new file mode 100644 index 000000000000..8bb96483fab2 --- /dev/null +++ b/lib/nfc/protocols/nfc_protocol.c @@ -0,0 +1,85 @@ +#include "nfc_protocol.h" + +#include + +typedef struct { + NfcProtocol parent_protocol; + size_t children_num; + const NfcProtocol* children_protocol; +} NfcProtocolTreeNode; + +/**************************** Protocol tree structure **************************** + * _________ start ___________________________ + * / | | \ + * _________ iso14443-3a _______ nfc-b nfc-f nfc-v + * / | \ + * iso14443-4a mf ultralight mf classic + * / \ + * mf desfire bank card + */ + +static const NfcProtocol nfc_protocol_iso14443_3a_children_protocol[] = { + NfcProtocolIso14443_4a, + NfcProtocolMfUltralight, +}; + +static const NfcProtocol nfc_protocol_iso14443_4a_children_protocol[] = { + NfcProtocolMfDesfire, +}; + +static const NfcProtocolTreeNode nfc_protocol_nodes[NfcProtocolNum] = { + [NfcProtocolIso14443_3a] = + { + .parent_protocol = NfcProtocolInvalid, + .children_num = COUNT_OF(nfc_protocol_iso14443_3a_children_protocol), + .children_protocol = nfc_protocol_iso14443_3a_children_protocol, + }, + [NfcProtocolIso14443_4a] = + { + .parent_protocol = NfcProtocolIso14443_3a, + .children_num = COUNT_OF(nfc_protocol_iso14443_4a_children_protocol), + .children_protocol = nfc_protocol_iso14443_4a_children_protocol, + }, + [NfcProtocolMfUltralight] = + { + .parent_protocol = NfcProtocolIso14443_3a, + .children_num = 0, + .children_protocol = NULL, + }, + [NfcProtocolMfClassic] = + { + .parent_protocol = NfcProtocolIso14443_3a, + .children_num = 0, + .children_protocol = NULL, + }, + [NfcProtocolMfDesfire] = + { + .parent_protocol = NfcProtocolIso14443_4a, + .children_num = 0, + .children_protocol = NULL, + }, +}; + +NfcProtocol nfc_protocol_get_parent(NfcProtocol protocol) { + furi_assert(protocol < NfcProtocolNum); + + return nfc_protocol_nodes[protocol].parent_protocol; +} + +bool nfc_protocol_has_parent(NfcProtocol protocol, NfcProtocol parent_protocol) { + furi_assert(protocol < NfcProtocolNum); + furi_assert(parent_protocol < NfcProtocolNum); + + bool parent_found = false; + const NfcProtocolTreeNode* iter = &nfc_protocol_nodes[protocol]; + + while(iter->parent_protocol != NfcProtocolInvalid) { + if(iter->parent_protocol == parent_protocol) { + parent_found = true; + break; + } + iter = &nfc_protocol_nodes[iter->parent_protocol]; + } + + return parent_found; +} diff --git a/lib/nfc/protocols/nfc_protocol.h b/lib/nfc/protocols/nfc_protocol.h new file mode 100644 index 000000000000..32ab9dbb1ca4 --- /dev/null +++ b/lib/nfc/protocols/nfc_protocol.h @@ -0,0 +1,28 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + NfcProtocolIso14443_3a, + NfcProtocolIso14443_4a, + NfcProtocolMfUltralight, + NfcProtocolMfClassic, + NfcProtocolMfDesfire, + /* Add new protocols here */ + + NfcProtocolNum, + + NfcProtocolInvalid, +} NfcProtocol; + +NfcProtocol nfc_protocol_get_parent(NfcProtocol protocol); + +bool nfc_protocol_has_parent(NfcProtocol protocol, NfcProtocol parent_protocol); + +#ifdef __cplusplus +} +#endif From 673465c4d401fb12430c987c9839dc9a0c66f125 Mon Sep 17 00:00:00 2001 From: gornekich Date: Fri, 30 Jun 2023 18:41:42 +0400 Subject: [PATCH 115/149] Generic listener part 1 (#2820) * nfc device data: add get base data api * nfc listener: rework generic listener * nfc: rework iso14443_3a emulation * nfc: complete iso14443a emulation * nfc: rework mf ultralight emulation * nfc: clean up code * nfc: rename poller -> instance in generic event * nfc listener: add assert for supported protocols * nfc: fix typos, code clean up --- .../nfc/helpers/handlers/nfc_poller_handler.c | 2 +- applications/main/nfc/nfc_app.c | 7 +- applications/main/nfc/nfc_app_i.h | 5 +- .../scenes/nfc_scene_mf_classic_dict_attack.c | 2 +- .../nfc_scene_mf_ultralight_capture_pass.c | 28 +- .../scenes/nfc_scene_mf_ultralight_emulate.c | 13 +- .../main/nfc/scenes/nfc_scene_nfca_emulate.c | 28 +- applications/main/nfc_rpc/nfc_rpc.c | 4 - applications/main/nfc_rpc/nfc_rpc_i.h | 5 +- .../main/nfc_rpc/nfc_rpc_mf_ultralight.c | 18 +- applications/main/nfc_rpc/nfc_rpc_nfca.c | 13 +- firmware/targets/f7/api_symbols.csv | 4 +- lib/nfc/helpers/bit_buffer.c | 4 +- lib/nfc/nfc.c | 10 +- lib/nfc/nfc.h | 4 - lib/nfc/nfc_listener.c | 40 ++- lib/nfc/nfc_listener.h | 6 +- lib/nfc/nfc_poller.c | 4 +- lib/nfc/protocols/iso14443_3a/iso14443_3a.c | 6 + lib/nfc/protocols/iso14443_3a/iso14443_3a.h | 2 + .../iso14443_3a/iso14443_3a_listener.c | 243 +++++------------- .../iso14443_3a/iso14443_3a_listener.h | 44 +--- .../iso14443_3a/iso14443_3a_listener_defs.h | 13 + .../iso14443_3a/iso14443_3a_listener_i.c | 64 +++++ .../iso14443_3a/iso14443_3a_listener_i.h | 40 +++ .../iso14443_3a/iso14443_3a_poller.c | 4 +- .../iso14443_3a/iso14443_3a_poller_defs.h | 8 + .../iso14443_3a/iso14443_3a_poller_i.c | 10 +- .../iso14443_3a/iso14443_3a_poller_i.h | 2 +- .../iso14443_3a/iso14443_3a_poller_sync_api.c | 4 +- lib/nfc/protocols/iso14443_4a/iso14443_4a.c | 7 + lib/nfc/protocols/iso14443_4a/iso14443_4a.h | 2 + .../iso14443_4a/iso14443_4a_poller.c | 2 +- .../iso14443_4a/iso14443_4a_poller_i.c | 4 +- lib/nfc/protocols/mf_classic/mf_classic.c | 7 + lib/nfc/protocols/mf_classic/mf_classic.h | 2 + .../protocols/mf_classic/mf_classic_poller.c | 2 +- .../mf_classic/mf_classic_poller_i.c | 2 +- .../mf_classic/mf_classic_poller_sync_api.c | 4 +- lib/nfc/protocols/mf_desfire/mf_desfire.c | 7 + lib/nfc/protocols/mf_desfire/mf_desfire.h | 2 + .../protocols/mf_desfire/mf_desfire_poller.c | 2 +- .../protocols/mf_ultralight/mf_ultralight.c | 7 + .../protocols/mf_ultralight/mf_ultralight.h | 2 + .../mf_ultralight/mf_ultralight_listener.c | 195 +++++--------- .../mf_ultralight/mf_ultralight_listener.h | 23 -- .../mf_ultralight_listener_defs.h | 13 + .../mf_ultralight/mf_ultralight_listener_i.h | 38 +++ .../mf_ultralight/mf_ultralight_poller.c | 2 +- .../mf_ultralight/mf_ultralight_poller_i.c | 18 +- .../mf_ultralight_poller_sync_api.c | 8 +- lib/nfc/protocols/nfc_device_base.h | 2 + lib/nfc/protocols/nfc_generic_event.h | 2 +- lib/nfc/protocols/nfc_listener_base.h | 8 +- lib/nfc/protocols/nfc_listener_defs.c | 8 +- lib/nfc/protocols/nfcb/nfcb_poller.c | 4 +- 56 files changed, 498 insertions(+), 512 deletions(-) create mode 100644 lib/nfc/protocols/iso14443_3a/iso14443_3a_listener_defs.h create mode 100644 lib/nfc/protocols/iso14443_3a/iso14443_3a_listener_i.c create mode 100644 lib/nfc/protocols/iso14443_3a/iso14443_3a_listener_i.h create mode 100644 lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_defs.h create mode 100644 lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h diff --git a/applications/main/nfc/helpers/handlers/nfc_poller_handler.c b/applications/main/nfc/helpers/handlers/nfc_poller_handler.c index 179e525ceb4c..8b891d05057e 100644 --- a/applications/main/nfc/helpers/handlers/nfc_poller_handler.c +++ b/applications/main/nfc/helpers/handlers/nfc_poller_handler.c @@ -99,7 +99,7 @@ static const NfcPollerReadHandler nfc_poller_handlers_read[] = { }; NfcCustomEvent nfc_poller_handler_read(NfcGenericEvent event, void* context) { furi_assert(context); - furi_assert(event.poller); + furi_assert(event.instance); furi_assert(event.data); furi_assert(event.protocol < COUNT_OF(nfc_poller_handlers_read)); diff --git a/applications/main/nfc/nfc_app.c b/applications/main/nfc/nfc_app.c index a0b22be1902b..ad5e5f82390b 100644 --- a/applications/main/nfc/nfc_app.c +++ b/applications/main/nfc/nfc_app.c @@ -46,13 +46,10 @@ NfcApp* nfc_app_alloc() { instance->view_dispatcher, nfc_back_event_callback); instance->nfc = nfc_alloc(); - instance->iso14443_3a_listener = iso14443_3a_listener_alloc(instance->nfc); - instance->mf_ul_listener = mf_ultralight_listener_alloc(instance->iso14443_3a_listener); + instance->scanner = nfc_scanner_alloc(instance->nfc); instance->parsed_data = furi_string_alloc(); - instance->scanner = nfc_scanner_alloc(instance->nfc); - instance->mf_ul_auth = mf_ultralight_auth_alloc(); // Nfc device @@ -153,8 +150,6 @@ void nfc_app_free(NfcApp* instance) { furi_string_free(instance->parsed_data); - mf_ultralight_listener_free(instance->mf_ul_listener); - iso14443_3a_listener_free(instance->iso14443_3a_listener); nfc_free(instance->nfc); nfc_scanner_free(instance->scanner); diff --git a/applications/main/nfc/nfc_app_i.h b/applications/main/nfc/nfc_app_i.h index 74dd980aa930..beada3ff78b5 100644 --- a/applications/main/nfc/nfc_app_i.h +++ b/applications/main/nfc/nfc_app_i.h @@ -48,6 +48,7 @@ #include #include +#include #include #include @@ -108,11 +109,9 @@ struct NfcApp { DetectReader* detect_reader; Nfc* nfc; - Iso14443_3aListener* iso14443_3a_listener; - MfUltralightListener* mf_ul_listener; - NfcPoller* poller; NfcScanner* scanner; + NfcListener* listener; MfUltralightAuth* mf_ul_auth; NfcMfClassicDictAttackContext mf_dict_context; diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c index 80edbd903c94..86bafd70001a 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c @@ -12,7 +12,7 @@ typedef enum { NfcCommand nfc_dict_attack_worker_callback(NfcGenericEvent event, void* context) { furi_assert(context); furi_assert(event.data); - furi_assert(event.poller); + furi_assert(event.instance); furi_assert(event.protocol == NfcProtocolMfClassic); NfcCommand command = NfcCommandContinue; diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_capture_pass.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_capture_pass.c index 4ca3fd97051e..95d286689d1e 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_capture_pass.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_capture_pass.c @@ -1,17 +1,17 @@ #include "../nfc_app_i.h" -MfUltralightListenerCommand nfc_scene_mf_ultralight_capture_pass_worker_callback( - MfUltralightListenerEvent event, - void* context) { - NfcApp* nfc = context; +// MfUltralightListenerCommand nfc_scene_mf_ultralight_capture_pass_worker_callback( +// MfUltralightListenerEvent event, +// void* context) { +// NfcApp* nfc = context; - if(event.type == MfUltralightListenerEventTypeAuth) { - nfc->mf_ul_auth->password = event.data->password; - view_dispatcher_send_custom_event(nfc->view_dispatcher, MfUltralightListenerEventTypeAuth); - } +// if(event.type == MfUltralightListenerEventTypeAuth) { +// nfc->mf_ul_auth->password = event.data->password; +// view_dispatcher_send_custom_event(nfc->view_dispatcher, MfUltralightListenerEventTypeAuth); +// } - return MfUltralightListenerCommandContinue; -} +// return MfUltralightListenerCommandContinue; +// } void nfc_scene_mf_ultralight_capture_pass_on_enter(void* context) { NfcApp* nfc = context; @@ -30,12 +30,6 @@ void nfc_scene_mf_ultralight_capture_pass_on_enter(void* context) { view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); // Start worker - // FIXME: Make it compile - // mf_ultralight_listener_start( - // nfc->mf_ul_listener, - // nfc->nfc_dev_data.mf_ul_data, - // nfc_scene_mf_ultralight_capture_pass_worker_callback, - // nfc); nfc_blink_read_start(nfc); } @@ -57,8 +51,6 @@ bool nfc_scene_mf_ultralight_capture_pass_on_event(void* context, SceneManagerEv void nfc_scene_mf_ultralight_capture_pass_on_exit(void* context) { NfcApp* nfc = context; - // Stop worker - mf_ultralight_listener_stop(nfc->mf_ul_listener); // Clear view widget_reset(nfc->widget); diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_emulate.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_emulate.c index 6e6042d47d3d..4e8b3ac59448 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_emulate.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_emulate.c @@ -23,19 +23,19 @@ void nfc_scene_mf_ultralight_emulate_on_enter(void* context) { // Setup and start worker view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); - mf_ultralight_listener_start(nfc->mf_ul_listener, data, NULL, NULL); + nfc->listener = nfc_listener_alloc(nfc->nfc, NfcProtocolMfUltralight, data); + nfc_listener_start(nfc->listener, NULL, NULL); nfc_blink_emulate_start(nfc); } bool nfc_scene_mf_ultralight_emulate_on_event(void* context, SceneManagerEvent event) { NfcApp* nfc = context; + UNUSED(nfc); bool consumed = false; if(event.type == SceneManagerEventTypeBack) { - MfUltralightData* mfu_data_after_emulation = mf_ultralight_alloc(); - mf_ultralight_listener_get_data(nfc->mf_ul_listener, mfu_data_after_emulation); - mf_ultralight_listener_stop(nfc->mf_ul_listener); + // MfUltralightData* mfu_data_after_emulation = nfc_listener_get_data(nfc->listener, NfcProtocolMfUltralight); // Check if data changed and save in shadow file // FIXME: A comparison method? // if(memcmp( @@ -47,7 +47,7 @@ bool nfc_scene_mf_ultralight_emulate_on_event(void* context, SceneManagerEvent e // nfc_save_shadow_file(nfc); // } // } - mf_ultralight_free(mfu_data_after_emulation); + // mf_ultralight_free(mfu_data_after_emulation); consumed = false; } return consumed; @@ -56,6 +56,9 @@ bool nfc_scene_mf_ultralight_emulate_on_event(void* context, SceneManagerEvent e void nfc_scene_mf_ultralight_emulate_on_exit(void* context) { NfcApp* nfc = context; + nfc_listener_stop(nfc->listener); + nfc_listener_free(nfc->listener); + // Clear view popup_reset(nfc->popup); diff --git a/applications/main/nfc/scenes/nfc_scene_nfca_emulate.c b/applications/main/nfc/scenes/nfc_scene_nfca_emulate.c index b035faf56535..c9177730dcb1 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfca_emulate.c +++ b/applications/main/nfc/scenes/nfc_scene_nfca_emulate.c @@ -7,22 +7,27 @@ enum { NfcSceneNfcaEmulateStateTextBox, }; -Iso14443_3aListenerCommand - nfc_scene_nfca_emulate_worker_callback(Iso14443_3aListenerEvent event, void* context) { +NfcCommand nfc_scene_nfca_emulate_worker_callback(NfcGenericEvent event, void* context) { furi_assert(context); + furi_assert(event.protocol == NfcProtocolIso14443_3a); + furi_assert(event.data); NfcApp* nfc = context; - if(event.type == Iso14443_3aListenerEventTypeReceivedStandartFrame) { + Iso14443_3aListenerEvent* iso14443_3a_event = event.data; + + if(iso14443_3a_event->type == Iso14443_3aListenerEventTypeReceivedStandardFrame) { furi_string_cat_printf(nfc->text_box_store, "R:"); - for(size_t i = 0; i < bit_buffer_get_size_bytes(event.data.buffer); i++) { + for(size_t i = 0; i < bit_buffer_get_size_bytes(iso14443_3a_event->data->buffer); i++) { furi_string_cat_printf( - nfc->text_box_store, " %02X", bit_buffer_get_byte(event.data.buffer, i)); + nfc->text_box_store, + " %02X", + bit_buffer_get_byte(iso14443_3a_event->data->buffer, i)); } furi_string_cat_printf(nfc->text_box_store, "\n"); view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerUpdate); } - return Iso14443_3aListenerCommandContinue; + return NfcCommandContinue; } void nfc_scene_nfca_emulate_widget_callback(GuiButtonType result, InputType type, void* context) { @@ -73,11 +78,9 @@ void nfc_scene_nfca_emulate_on_enter(void* context) { text_box_set_focus(text_box, TextBoxFocusEnd); furi_string_reset(nfc->text_box_store); - iso14443_3a_listener_start( - nfc->iso14443_3a_listener, - nfc_device_get_data(nfc->nfc_device, NfcProtocolIso14443_3a), - nfc_scene_nfca_emulate_worker_callback, - nfc); + const NfcDeviceData* data = nfc_device_get_data(nfc->nfc_device, NfcProtocolIso14443_3a); + nfc->listener = nfc_listener_alloc(nfc->nfc, NfcProtocolIso14443_3a, data); + nfc_listener_start(nfc->listener, nfc_scene_nfca_emulate_worker_callback, nfc); // Set Widget state and view scene_manager_set_scene_state( @@ -127,7 +130,8 @@ bool nfc_scene_nfca_emulate_on_event(void* context, SceneManagerEvent event) { void nfc_scene_nfca_emulate_on_exit(void* context) { NfcApp* nfc = context; - iso14443_3a_listener_stop(nfc->iso14443_3a_listener); + nfc_listener_stop(nfc->listener); + nfc_listener_free(nfc->listener); // Clear view widget_reset(nfc->widget); diff --git a/applications/main/nfc_rpc/nfc_rpc.c b/applications/main/nfc_rpc/nfc_rpc.c index 9f03558e41b8..b4d9138b12eb 100644 --- a/applications/main/nfc_rpc/nfc_rpc.c +++ b/applications/main/nfc_rpc/nfc_rpc.c @@ -135,8 +135,6 @@ static NfcRpc* nfc_rpc_app_alloc() { NfcRpc* instance = malloc(sizeof(NfcRpc)); instance->nfc = nfc_alloc(); - instance->iso14443_3a_listener = iso14443_3a_listener_alloc(instance->nfc); - instance->mf_ul_listener = mf_ultralight_listener_alloc(instance->iso14443_3a_listener); NfcRpcHandlerDict_init(instance->handlers); for(size_t i = 0; i < COUNT_OF(nfc_rpc_callbacks); i++) { @@ -171,8 +169,6 @@ static NfcRpc* nfc_rpc_app_alloc() { void nfc_rpc_app_free(NfcRpc* instance) { furi_assert(instance); - mf_ultralight_listener_free(instance->mf_ul_listener); - iso14443_3a_listener_free(instance->iso14443_3a_listener); nfc_free(instance->nfc); for(size_t i = 0; i < COUNT_OF(nfc_rpc_callbacks); i++) { diff --git a/applications/main/nfc_rpc/nfc_rpc_i.h b/applications/main/nfc_rpc/nfc_rpc_i.h index 0e81346241f9..69750a2685e3 100644 --- a/applications/main/nfc_rpc/nfc_rpc_i.h +++ b/applications/main/nfc_rpc/nfc_rpc_i.h @@ -20,6 +20,8 @@ #include #include +#include + typedef void (*NfcRpcHandler)(Nfc_Main* cmd, void* context); DICT_DEF2(NfcRpcHandlerDict, pb_size_t, M_DEFAULT_OPLIST, NfcRpcHandler, M_POD_OPLIST) @@ -54,8 +56,7 @@ struct NfcRpc { NfcRpcHandlerDict_t handlers; Nfc* nfc; - Iso14443_3aListener* iso14443_3a_listener; - MfUltralightListener* mf_ul_listener; + NfcListener* listener; }; typedef struct { diff --git a/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c b/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c index dec5bc857451..ddab5b7fdec0 100644 --- a/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c +++ b/applications/main/nfc_rpc/nfc_rpc_mf_ultralight.c @@ -187,6 +187,7 @@ static void init_mf_ul_data(MfUltralightData* data) { iso14443_3a_data->sak = 0x00; data->type = MfUltralightTypeUnknown; + data->pages_total = 16; MfUltralightVersion version = { .header = 1, .protocol_type = 228, @@ -208,11 +209,13 @@ void nfc_rpc_mf_ultralight_emulate_start(Nfc_Main* cmd, void* context) { PB_MfUltralight_EmulateStartResponse_init_default; cmd->command_status = Nfc_CommandStatus_OK; cmd->which_content = Nfc_Main_mf_ultralight_emulate_start_resp_tag; - if(instance->mf_ul_listener == NULL) { - MfUltralightData mf_ul_data = {}; + if(instance->listener == NULL) { + MfUltralightData* mf_ul_data = mf_ultralight_alloc(); // TODO initialize data from rpc message - init_mf_ul_data(&mf_ul_data); - mf_ultralight_listener_start(instance->mf_ul_listener, &mf_ul_data, NULL, NULL); + init_mf_ul_data(mf_ul_data); + instance->listener = + nfc_listener_alloc(instance->nfc, NfcProtocolMfUltralight, mf_ul_data); + nfc_listener_start(instance->listener, NULL, NULL); pb_mf_ultralight_emulate_start_resp.error = PB_MfUltralight_Error_None; } else { // TODO add Busy error @@ -230,10 +233,11 @@ void nfc_rpc_mf_ultralight_emulate_stop(Nfc_Main* cmd, void* context) { PB_MfUltralight_EmulateStopResponse_init_default; cmd->command_status = Nfc_CommandStatus_OK; cmd->which_content = Nfc_Main_mf_ultralight_emulate_stop_resp_tag; - if(instance->mf_ul_listener) { + if(instance->listener) { // Stop before free - mf_ultralight_listener_stop(instance->mf_ul_listener); - instance->mf_ul_listener = NULL; + nfc_listener_stop(instance->listener); + nfc_listener_free(instance->listener); + instance->listener = NULL; pb_mf_ultralight_emulate_stop_resp.error = PB_MfUltralight_Error_None; } else { // TODO emulation not started error diff --git a/applications/main/nfc_rpc/nfc_rpc_nfca.c b/applications/main/nfc_rpc/nfc_rpc_nfca.c index 0d2661e2a50d..986e909d0bdf 100644 --- a/applications/main/nfc_rpc/nfc_rpc_nfca.c +++ b/applications/main/nfc_rpc/nfc_rpc_nfca.c @@ -75,7 +75,7 @@ static void nfc_rpc_nfca_emulate_start(Nfc_Main* cmd, void* context) { PB_Nfca_EmulateStartResponse_init_default; cmd->command_status = Nfc_CommandStatus_OK; cmd->which_content = Nfc_Main_nfca_emulate_start_resp_tag; - if(instance->iso14443_3a_listener == NULL) { + if(instance->listener == NULL) { Iso14443_3aData iso14443_3a_data = {}; iso14443_3a_data.uid_len = cmd->content.nfca_emulate_start_req.uid_len; memcpy( @@ -85,7 +85,9 @@ static void nfc_rpc_nfca_emulate_start(Nfc_Main* cmd, void* context) { memcpy(iso14443_3a_data.atqa, cmd->content.nfca_emulate_start_req.atqa.bytes, 2); memcpy(&iso14443_3a_data.sak, cmd->content.nfca_emulate_start_req.sak.bytes, 1); - iso14443_3a_listener_start(instance->iso14443_3a_listener, &iso14443_3a_data, NULL, NULL); + instance->listener = + nfc_listener_alloc(instance->nfc, NfcProtocolIso14443_3a, &iso14443_3a_data); + nfc_listener_start(instance->listener, NULL, NULL); pb_nfca_emulate_start_resp.error = PB_Nfca_Error_None; } else { // TODO add Busy error @@ -103,9 +105,10 @@ static void nfc_rpc_nfca_emulate_stop(Nfc_Main* cmd, void* context) { PB_Nfca_EmulateStopResponse_init_default; cmd->command_status = Nfc_CommandStatus_OK; cmd->which_content = Nfc_Main_nfca_emulate_stop_resp_tag; - if(instance->iso14443_3a_listener) { - iso14443_3a_listener_stop(instance->iso14443_3a_listener); - instance->iso14443_3a_listener = NULL; + if(instance->listener) { + nfc_listener_stop(instance->listener); + nfc_listener_free(instance->listener); + instance->listener = NULL; pb_nfca_emulate_stop_resp.error = PB_Nfca_Error_None; } else { // TODO add Busy error diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index d7524f858e51..eb5b96f7b7f3 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,+,36.2,, +Version,+,36.6,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -1815,6 +1815,7 @@ Function,-,iso14443_3a_append_crc,void,BitBuffer* Function,-,iso14443_3a_check_crc,_Bool,const BitBuffer* Function,-,iso14443_3a_copy,void,"Iso14443_3aData*, const Iso14443_3aData*" Function,-,iso14443_3a_free,void,Iso14443_3aData* +Function,-,iso14443_3a_get_base_data,const Iso14443_3aData*,const Iso14443_3aData* Function,-,iso14443_3a_get_cuid,uint32_t,Iso14443_3aData* Function,-,iso14443_3a_get_device_name,const char*,"const Iso14443_3aData*, NfcDeviceNameType" Function,-,iso14443_3a_get_uid,const uint8_t*,"const Iso14443_3aData*, size_t*" @@ -2006,6 +2007,7 @@ Function,+,mf_classic_alloc,MfClassicData*, Function,+,mf_classic_copy,void,"MfClassicData*, const MfClassicData*" Function,-,mf_classic_detect_protocol,_Bool,"Iso14443_3aData*, MfClassicType*" Function,+,mf_classic_free,void,MfClassicData* +Function,-,mf_classic_get_base_data,const Iso14443_3aData*,const MfClassicData* Function,-,mf_classic_get_blocks_num_in_sector,uint8_t,uint8_t Function,-,mf_classic_get_device_name,const char*,"const MfClassicData*, NfcDeviceNameType" Function,-,mf_classic_get_first_block_num_of_sector,uint8_t,uint8_t diff --git a/lib/nfc/helpers/bit_buffer.c b/lib/nfc/helpers/bit_buffer.c index 9f62d09b0bcd..cab991e37d89 100644 --- a/lib/nfc/helpers/bit_buffer.c +++ b/lib/nfc/helpers/bit_buffer.c @@ -217,7 +217,9 @@ const uint8_t* bit_buffer_get_data(const BitBuffer* buf) { void bit_buffer_set_byte(BitBuffer* buf, size_t index, uint8_t byte) { furi_assert(buf); - furi_assert(buf->size_bits / BITS_IN_BYTE > index); + + size_t size_byted = bit_buffer_get_size_bytes(buf); + furi_assert(size_byted > index); buf->data[index] = byte; } diff --git a/lib/nfc/nfc.c b/lib/nfc/nfc.c index f8bf2dc79800..371b0997b0d5 100644 --- a/lib/nfc/nfc.c +++ b/lib/nfc/nfc.c @@ -80,11 +80,7 @@ static int32_t nfc_worker_listener(void* context) { Nfc* instance = context; furi_assert(instance->callback); - - f_hal_nfc_low_power_mode_stop(); - - NfcEvent nfc_event = {.type = NfcEventTypeConfigureRequest}; - instance->callback(nfc_event, instance->context); + furi_assert(instance->config_state == NfcConfigurationStateDone); f_hal_nfc_listen_start(); instance->state = NfcStateListenStarted; @@ -93,6 +89,7 @@ static int32_t nfc_worker_listener(void* context) { NfcEventData event_data = {}; event_data.buffer = bit_buffer_alloc(NFC_MAX_BUFFER_SIZE); + NfcEvent nfc_event = {.data = event_data}; while(true) { FHalNfcEvent event = f_hal_nfc_wait_event(F_HAL_NFC_EVENT_WAIT_FOREVER); @@ -126,8 +123,6 @@ static int32_t nfc_worker_listener(void* context) { } } - nfc_event.type = NfcEventTypeReset; - instance->callback(nfc_event, instance->context); nfc_config(instance, NfcModeIdle); bit_buffer_free(event_data.buffer); f_hal_nfc_low_power_mode_start(); @@ -252,6 +247,7 @@ void nfc_config(Nfc* instance, NfcMode mode) { f_hal_nfc_set_mode(FHalNfcModeIso14443_3aPoller, FHalNfcBitrate106); instance->config_state = NfcConfigurationStateDone; } else if(mode == NfcModeIso14443_3aListener) { + f_hal_nfc_low_power_mode_stop(); f_hal_nfc_set_mode(FHalNfcModeIso14443_3aListener, FHalNfcBitrate106); instance->config_state = NfcConfigurationStateDone; } diff --git a/lib/nfc/nfc.h b/lib/nfc/nfc.h index 0c26e3b6cd1d..a35ae41a2fce 100644 --- a/lib/nfc/nfc.h +++ b/lib/nfc/nfc.h @@ -17,10 +17,6 @@ typedef enum { NfcEventTypeRxStart, NfcEventTypeRxEnd, - // TODO delete - NfcEventTypeConfigureRequest, - NfcEventTypeReset, - NfcEventTypeListenerActivated, NfcEventTypePollerReady, } NfcEventType; diff --git a/lib/nfc/nfc_listener.c b/lib/nfc/nfc_listener.c index b270d0030e4e..a5e5051e7b33 100644 --- a/lib/nfc/nfc_listener.c +++ b/lib/nfc/nfc_listener.c @@ -1,15 +1,16 @@ #include "nfc_listener.h" #include +#include #include typedef struct NfcListenerListElement { NfcProtocol protocol; + const NfcDeviceData* data; NfcGenericInstance* listener; const NfcListenerBase* listener_api; struct NfcListenerListElement* child; - struct NfcListenerListElement* parent; } NfcListenerListElement; typedef struct { @@ -23,9 +24,10 @@ struct NfcListener { NfcListenerList list; }; -static void nfc_listener_list_alloc(NfcListener* instance, NfcDeviceData* data) { +static void nfc_listener_list_alloc(NfcListener* instance, const NfcDeviceData* data) { instance->list.head = malloc(sizeof(NfcListenerListElement)); instance->list.head->protocol = instance->protocol; + instance->list.head->data = data; instance->list.head->listener_api = nfc_listeners_api[instance->protocol]; instance->list.head->child = NULL; instance->list.tail = instance->list.head; @@ -37,37 +39,27 @@ static void nfc_listener_list_alloc(NfcListener* instance, NfcDeviceData* data) NfcListenerListElement* parent = malloc(sizeof(NfcListenerListElement)); parent->protocol = parent_protocol; + parent->data = + nfc_devices[instance->list.head->protocol]->get_base_data(instance->list.head->data); parent->listener_api = nfc_listeners_api[parent_protocol]; parent->child = instance->list.head; - instance->list.head->parent = parent; instance->list.head = parent; } while(true); // Allocate listener instances NfcListenerListElement* iter = instance->list.head; - iter->listener = iter->listener_api->alloc(instance->nfc); + iter->listener = iter->listener_api->alloc(instance->nfc, iter->data); do { if(iter->child == NULL) break; - iter->child->listener = iter->child->listener_api->alloc(iter->listener); + iter->child->listener = + iter->child->listener_api->alloc(iter->listener, iter->child->data); iter->listener_api->set_callback( iter->listener, iter->child->listener_api->run, iter->child->listener); iter = iter->child; } while(true); - - // Set data for each listener - iter = instance->list.tail; - iter->listener_api->set_data(iter->listener, data); - - do { - if(iter == instance->list.head) break; - - const NfcDeviceData* base_data = iter->listener_api->get_base_data(iter->listener); - iter->parent->listener_api->set_data(iter->parent->listener, base_data); - iter = iter->parent; - } while(false); } static void nfc_listener_list_free(NfcListener* instance) { @@ -80,10 +72,11 @@ static void nfc_listener_list_free(NfcListener* instance) { } while(true); } -NfcListener* nfc_listener_alloc(Nfc* nfc, NfcProtocol protocol, NfcDeviceData* data) { +NfcListener* nfc_listener_alloc(Nfc* nfc, NfcProtocol protocol, const NfcDeviceData* data) { furi_assert(nfc); furi_assert(protocol < NfcProtocolNum); furi_assert(data); + furi_assert(nfc_listeners_api[protocol]); NfcListener* instance = malloc(sizeof(NfcListener)); instance->nfc = nfc; @@ -109,7 +102,7 @@ NfcCommand nfc_listener_start_callback(NfcEvent event, void* context) { NfcCommand command = NfcCommandContinue; NfcGenericEvent generic_event = { .protocol = NfcProtocolInvalid, - .poller = instance->nfc, + .instance = instance->nfc, .data = &event, }; @@ -119,9 +112,11 @@ NfcCommand nfc_listener_start_callback(NfcEvent event, void* context) { return command; } -void nfc_listener_start(NfcListener* instance) { +void nfc_listener_start(NfcListener* instance, NfcGenericCallback callback, void* context) { furi_assert(instance); + NfcListenerListElement* tail_element = instance->list.tail; + tail_element->listener_api->set_callback(tail_element->listener, callback, context); nfc_start_listener(instance->nfc, nfc_listener_start_callback, instance); } @@ -131,9 +126,10 @@ void nfc_listener_stop(NfcListener* instance) { nfc_listener_abort(instance->nfc); } -const NfcDeviceData* nfc_listener_get_data(NfcListener* instance) { +const NfcDeviceData* nfc_listener_get_data(NfcListener* instance, NfcProtocol protocol) { furi_assert(instance); + furi_assert(instance->protocol == protocol); NfcListenerListElement* tail_element = instance->list.tail; - return tail_element->listener_api->get_base_data(tail_element->listener); + return tail_element->listener_api->get_data(tail_element->listener); } diff --git a/lib/nfc/nfc_listener.h b/lib/nfc/nfc_listener.h index 0e84499e79f2..7addc82ec5a2 100644 --- a/lib/nfc/nfc_listener.h +++ b/lib/nfc/nfc_listener.h @@ -9,15 +9,15 @@ extern "C" { typedef struct NfcListener NfcListener; -NfcListener* nfc_listener_alloc(Nfc* nfc, NfcProtocol protocol, NfcDeviceData* data); +NfcListener* nfc_listener_alloc(Nfc* nfc, NfcProtocol protocol, const NfcDeviceData* data); void nfc_listener_free(NfcListener* instance); -void nfc_listener_start(NfcListener* instance); +void nfc_listener_start(NfcListener* instance, NfcGenericCallback callback, void* context); void nfc_listener_stop(NfcListener* instance); -const NfcDeviceData* nfc_listener_get_data(NfcListener* instnace); +const NfcDeviceData* nfc_listener_get_data(NfcListener* instance, NfcProtocol protocol); #ifdef __cplusplus } diff --git a/lib/nfc/nfc_poller.c b/lib/nfc/nfc_poller.c index 69d86376f3aa..f1963c0d22c6 100644 --- a/lib/nfc/nfc_poller.c +++ b/lib/nfc/nfc_poller.c @@ -99,7 +99,7 @@ static NfcCommand nfc_poller_start_callback(NfcEvent event, void* context) { NfcCommand command = NfcCommandContinue; NfcGenericEvent poller_event = { .protocol = NfcProtocolInvalid, - .poller = instance->nfc, + .instance = instance->nfc, .data = &event, }; @@ -157,7 +157,7 @@ static NfcCommand nfc_poller_detect_callback(NfcEvent event, void* context) { NfcCommand command = NfcCommandContinue; NfcGenericEvent poller_event = { .protocol = NfcProtocolInvalid, - .poller = instance->nfc, + .instance = instance->nfc, .data = &event, }; diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a.c b/lib/nfc/protocols/iso14443_3a/iso14443_3a.c index e460218fc391..6ec1ba63618d 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a.c +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a.c @@ -19,6 +19,7 @@ const NfcDeviceBase nfc_device_iso14443_3a = { .is_equal = (NfcDeviceEqual)iso14443_3a_is_equal, .get_name = (NfcDeviceGetName)iso14443_3a_get_device_name, .get_uid = (NfcDeviceGetUid)iso14443_3a_get_uid, + .get_base_data = (NfcDeviceGetBaseData)iso14443_3a_get_base_data, }; Iso14443_3aData* iso14443_3a_alloc() { @@ -89,6 +90,11 @@ const uint8_t* iso14443_3a_get_uid(const Iso14443_3aData* data, size_t* uid_len) return data->uid; } +const Iso14443_3aData* iso14443_3a_get_base_data(const Iso14443_3aData* data) { + UNUSED(data); + furi_crash("No base data"); +} + bool iso14443_3a_load_data(Iso14443_3aData* data, FlipperFormat* ff, uint32_t version) { furi_assert(data); diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a.h b/lib/nfc/protocols/iso14443_3a/iso14443_3a.h index db2ae30e3a7d..6a3ce3170e93 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a.h +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a.h @@ -86,6 +86,8 @@ const char* iso14443_3a_get_device_name(const Iso14443_3aData* data, NfcDeviceNa const uint8_t* iso14443_3a_get_uid(const Iso14443_3aData* data, size_t* uid_len); +const Iso14443_3aData* iso14443_3a_get_base_data(const Iso14443_3aData* data); + uint32_t iso14443_3a_get_cuid(Iso14443_3aData* iso14443_3a_data); void iso14443_3a_append_crc(BitBuffer* buffer); diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c b/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c index f32b10f0119c..04d3064604df 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c @@ -1,4 +1,5 @@ -#include "iso14443_3a_listener.h" +#include "iso14443_3a_listener_i.h" +#include "iso14443_3a_listener_defs.h" #include #include @@ -7,58 +8,6 @@ #define ISO14443_3A_LISTENER_MAX_BUFFER_SIZE (256) -typedef enum { - Iso14443_3aListenerStateIdle, - Iso14443_3aListenerStateActive, -} Iso14443_3aListenerState; - -struct Iso14443_3aListener { - Nfc* nfc; - Iso14443_3aData* data; - Iso14443_3aListenerState state; - Iso14443_3aListenerEventCallback callback; - - BitBuffer* tx_buffer; - void* context; -}; - -static Iso14443_3aError iso14443_3a_listener_process_nfc_error(NfcError error) { - Iso14443_3aError ret = Iso14443_3aErrorNone; - - if(error == NfcErrorNone) { - ret = Iso14443_3aErrorNone; - } else if(error == NfcErrorTimeout) { - ret = Iso14443_3aErrorTimeout; - } else { - ret = Iso14443_3aErrorFieldOff; - } - - return ret; -} - -static void iso14443_3a_listener_config(Iso14443_3aListener* instance) { - furi_assert(instance); - - instance->tx_buffer = bit_buffer_alloc(ISO14443_3A_LISTENER_MAX_BUFFER_SIZE); - - nfc_set_fdt_listen_fc(instance->nfc, ISO14443_3A_FDT_LISTEN_FC); - nfc_config(instance->nfc, NfcModeIso14443_3aListener); - nfc_listener_set_col_res_data( - instance->nfc, - instance->data->uid, - instance->data->uid_len, - instance->data->atqa, - instance->data->sak); -} - -static void iso14443_3a_listener_reset(Iso14443_3aListener* instance) { - furi_assert(instance); - furi_assert(instance->tx_buffer); - - bit_buffer_free(instance->tx_buffer); - instance->tx_buffer = NULL; -} - static bool iso14443_3a_listener_halt_received(BitBuffer* buf) { bool halt_cmd_received = false; @@ -73,154 +22,102 @@ static bool iso14443_3a_listener_halt_received(BitBuffer* buf) { return halt_cmd_received; } -static NfcCommand iso14443_3a_listener_event_handler(NfcEvent event, void* context) { - furi_assert(context); - - Iso14443_3aListener* instance = context; - NfcEventType event_type = event.type; - Iso14443_3aListenerEvent iso14443_3a_listener_event = {}; - NfcCommand command = NfcCommandContinue; - - if(event_type == NfcEventTypeConfigureRequest) { - iso14443_3a_listener_config(instance); - if(instance->callback) { - iso14443_3a_listener_event.type = Iso14443_3aListenerEventConfigRequest; - instance->callback(iso14443_3a_listener_event, instance->context); - } - } else if(event_type == NfcEventTypeListenerActivated) { - instance->state = Iso14443_3aListenerStateActive; - } else if( - (event_type == NfcEventTypeRxEnd) && (instance->state == Iso14443_3aListenerStateActive)) { - if(iso14443_3a_listener_halt_received(event.data.buffer)) { - // TODO rework with commands - iso14443_3a_listener_sleep(instance); - instance->state = Iso14443_3aListenerStateIdle; - if(instance->callback) { - iso14443_3a_listener_event.type = Iso14443_3aListenerEventTypeHalted; - instance->callback(iso14443_3a_listener_event, instance->context); - } - } else if(instance->callback) { - if(iso14443_3a_check_crc(event.data.buffer)) { - iso14443_3a_listener_event.type = - Iso14443_3aListenerEventTypeReceivedStandartFrame; - size_t bytes = bit_buffer_get_size_bytes(event.data.buffer); - bit_buffer_set_size_bytes(event.data.buffer, bytes - 2); - } else { - iso14443_3a_listener_event.type = Iso14443_3aListenerEventTypeReceivedData; - } - iso14443_3a_listener_event.data.buffer = event.data.buffer; - if(instance->callback) { - instance->callback(iso14443_3a_listener_event, instance->context); - } - } - } else if(event_type == NfcEventTypeReset) { - iso14443_3a_listener_reset(instance); - if(instance->callback) { - iso14443_3a_listener_event.type = Iso14443_3aListenerEventTypeReset; - instance->callback(iso14443_3a_listener_event, instance->context); - } - } - - return command; -} - -Iso14443_3aListener* iso14443_3a_listener_alloc(Nfc* nfc) { +Iso14443_3aListener* iso14443_3a_listener_alloc(Nfc* nfc, const Iso14443_3aData* data) { furi_assert(nfc); Iso14443_3aListener* instance = malloc(sizeof(Iso14443_3aListener)); instance->nfc = nfc; + instance->data = iso14443_3a_alloc(); + iso14443_3a_copy(instance->data, data); + instance->tx_buffer = bit_buffer_alloc(ISO14443_3A_LISTENER_MAX_BUFFER_SIZE); + + instance->iso14443_3a_event.data = &instance->iso14443_3a_event_data; + instance->generic_event.protocol = NfcProtocolIso14443_3a; + instance->generic_event.instance = instance; + instance->generic_event.data = &instance->iso14443_3a_event; + + nfc_set_fdt_listen_fc(instance->nfc, ISO14443_3A_FDT_LISTEN_FC); + nfc_config(instance->nfc, NfcModeIso14443_3aListener); + nfc_listener_set_col_res_data( + instance->nfc, + instance->data->uid, + instance->data->uid_len, + instance->data->atqa, + instance->data->sak); return instance; } void iso14443_3a_listener_free(Iso14443_3aListener* instance) { furi_assert(instance); + furi_assert(instance->data); + furi_assert(instance->tx_buffer); + + bit_buffer_free(instance->tx_buffer); + iso14443_3a_free(instance->data); free(instance); } -Iso14443_3aError iso14443_3a_listener_start( +void iso14443_3a_listener_set_callback( Iso14443_3aListener* instance, - const Iso14443_3aData* data, - Iso14443_3aListenerEventCallback callback, + NfcGenericCallback callback, void* context) { furi_assert(instance); instance->callback = callback; instance->context = context; - - instance->data = iso14443_3a_alloc(); - iso14443_3a_copy(instance->data, data); - - nfc_start_listener(instance->nfc, iso14443_3a_listener_event_handler, instance); - - return Iso14443_3aErrorNone; -} - -Iso14443_3aError iso14443_3a_listener_stop(Iso14443_3aListener* instance) { - furi_assert(instance); - - nfc_listener_abort(instance->nfc); - iso14443_3a_free(instance->data); - - instance->callback = NULL; - instance->context = NULL; - instance->state = Iso14443_3aListenerStateIdle; - - return Iso14443_3aErrorNone; } -Iso14443_3aError - iso14443_3a_listener_get_data(Iso14443_3aListener* instance, Iso14443_3aData* data) { +const Iso14443_3aData* iso14443_3a_listener_get_data(Iso14443_3aListener* instance) { furi_assert(instance); + furi_assert(instance->data); - iso14443_3a_copy(data, instance->data); - - return Iso14443_3aErrorNone; + return instance->data; } -Iso14443_3aError iso14443_3a_listener_sleep(Iso14443_3aListener* instance) { - furi_assert(instance); - - NfcError error = nfc_listener_sleep(instance->nfc); - instance->state = Iso14443_3aListenerStateIdle; - - return iso14443_3a_listener_process_nfc_error(error); -} +NfcCommand iso14443_3a_listener_run(NfcGenericEvent event, void* context) { + furi_assert(context); + furi_assert(event.protocol == NfcProtocolInvalid); + furi_assert(event.data); -Iso14443_3aError - iso14443_3a_listener_tx(Iso14443_3aListener* instance, const BitBuffer* tx_buffer) { - furi_assert(instance); - furi_assert(tx_buffer); + Iso14443_3aListener* instance = context; + NfcEvent* nfc_event = event.data; + NfcCommand command = NfcCommandContinue; - Iso14443_3aError ret = Iso14443_3aErrorNone; - NfcError error = nfc_listener_tx(instance->nfc, tx_buffer); - if(error != NfcErrorNone) { - FURI_LOG_W(TAG, "Tx error: %d", error); - ret = iso14443_3a_listener_process_nfc_error(error); + if(nfc_event->type == NfcEventTypeListenerActivated) { + instance->state = Iso14443_3aListenerStateActive; + } else if(nfc_event->type == NfcEventTypeRxEnd) { + if(instance->state == Iso14443_3aListenerStateActive) { + if(iso14443_3a_listener_halt_received(nfc_event->data.buffer)) { + iso14443_3a_listener_sleep(instance); + instance->state = Iso14443_3aListenerStateIdle; + if(instance->callback) { + instance->iso14443_3a_event.type = Iso14443_3aListenerEventTypeHalted; + command = instance->callback(instance->generic_event, instance->context); + } + } else { + if(iso14443_3a_check_crc(nfc_event->data.buffer)) { + instance->iso14443_3a_event.type = + Iso14443_3aListenerEventTypeReceivedStandardFrame; + iso14443_3a_trim_crc(nfc_event->data.buffer); + } else { + instance->iso14443_3a_event.type = Iso14443_3aListenerEventTypeReceivedData; + } + instance->iso14443_3a_event_data.buffer = nfc_event->data.buffer; + if(instance->callback) { + command = instance->callback(instance->generic_event, instance->context); + } + } + } } - return ret; + return command; } -Iso14443_3aError iso14443_3a_listener_send_standart_frame( - Iso14443_3aListener* instance, - const BitBuffer* tx_buffer) { - furi_assert(instance); - furi_assert(tx_buffer); - furi_assert(instance->tx_buffer); - - Iso14443_3aError ret = Iso14443_3aErrorNone; - do { - bit_buffer_copy(instance->tx_buffer, tx_buffer); - iso14443_3a_append_crc(instance->tx_buffer); - - NfcError error = nfc_listener_tx(instance->nfc, instance->tx_buffer); - if(error != NfcErrorNone) { - FURI_LOG_W(TAG, "Tx error: %d", error); - ret = iso14443_3a_listener_process_nfc_error(error); - break; - } - } while(false); - - return ret; -} +const NfcListenerBase nfc_listener_iso14443_3a = { + .alloc = (NfcListenerAlloc)iso14443_3a_listener_alloc, + .free = (NfcListenerFree)iso14443_3a_listener_free, + .set_callback = (NfcListenerSetCallback)iso14443_3a_listener_set_callback, + .get_data = (NfcListenerGetData)iso14443_3a_listener_get_data, + .run = (NfcListenerRun)iso14443_3a_listener_run, +}; diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.h b/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.h index 5596731012b0..44c479664195 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.h +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.h @@ -10,14 +10,10 @@ extern "C" { typedef struct Iso14443_3aListener Iso14443_3aListener; typedef enum { - Iso14443_3aListenerEventConfigRequest, - Iso14443_3aListenerEventTypeAbort, - Iso14443_3aListenerEventTypeFieldOn, - Iso14443_3aListenerEventTypeFieldOff, Iso14443_3aListenerEventTypeHalted, - Iso14443_3aListenerEventTypeReceivedStandartFrame, + + Iso14443_3aListenerEventTypeReceivedStandardFrame, Iso14443_3aListenerEventTypeReceivedData, - Iso14443_3aListenerEventTypeReset, } Iso14443_3aListenerEventType; typedef struct { @@ -26,43 +22,9 @@ typedef struct { typedef struct { Iso14443_3aListenerEventType type; - Iso14443_3aListenerEventData data; + Iso14443_3aListenerEventData* data; } Iso14443_3aListenerEvent; -typedef enum { - Iso14443_3aListenerCommandContinue = NfcCommandContinue, - Iso14443_3aListenerCommandReset = NfcCommandReset, -} Iso14443_3aListenerCommand; - -typedef Iso14443_3aListenerCommand ( - *Iso14443_3aListenerEventCallback)(Iso14443_3aListenerEvent event, void* context); - -Iso14443_3aListener* iso14443_3a_listener_alloc(Nfc* nfc); - -void iso14443_3a_listener_free(Iso14443_3aListener* instance); - -Iso14443_3aError iso14443_3a_listener_start( - Iso14443_3aListener* instance, - const Iso14443_3aData* data, - Iso14443_3aListenerEventCallback callback, - void* context); - -Iso14443_3aError - iso14443_3a_listener_get_data(Iso14443_3aListener* instance, Iso14443_3aData* data); - -Iso14443_3aError iso14443_3a_listener_stop(Iso14443_3aListener* instance); - -// Called from NfcWorker thread - -Iso14443_3aError iso14443_3a_listener_sleep(Iso14443_3aListener* instance); - -Iso14443_3aError - iso14443_3a_listener_tx(Iso14443_3aListener* instance, const BitBuffer* tx_buffer); - -Iso14443_3aError iso14443_3a_listener_send_standart_frame( - Iso14443_3aListener* instance, - const BitBuffer* tx_buffer); - #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener_defs.h b/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener_defs.h new file mode 100644 index 000000000000..b92bf8837a92 --- /dev/null +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener_defs.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern const NfcListenerBase nfc_listener_iso14443_3a; + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener_i.c b/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener_i.c new file mode 100644 index 000000000000..a8d8bed05016 --- /dev/null +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener_i.c @@ -0,0 +1,64 @@ +#include "iso14443_3a_listener_i.h" + +#define TAG "Iso14443_3aListener" + +static Iso14443_3aError iso14443_3a_listener_process_nfc_error(NfcError error) { + Iso14443_3aError ret = Iso14443_3aErrorNone; + + if(error == NfcErrorNone) { + ret = Iso14443_3aErrorNone; + } else if(error == NfcErrorTimeout) { + ret = Iso14443_3aErrorTimeout; + } else { + ret = Iso14443_3aErrorFieldOff; + } + + return ret; +} + +Iso14443_3aError iso14443_3a_listener_sleep(Iso14443_3aListener* instance) { + furi_assert(instance); + + NfcError error = nfc_listener_sleep(instance->nfc); + instance->state = Iso14443_3aListenerStateIdle; + + return iso14443_3a_listener_process_nfc_error(error); +} + +Iso14443_3aError + iso14443_3a_listener_tx(Iso14443_3aListener* instance, const BitBuffer* tx_buffer) { + furi_assert(instance); + furi_assert(tx_buffer); + + Iso14443_3aError ret = Iso14443_3aErrorNone; + NfcError error = nfc_listener_tx(instance->nfc, tx_buffer); + if(error != NfcErrorNone) { + FURI_LOG_W(TAG, "Tx error: %d", error); + ret = iso14443_3a_listener_process_nfc_error(error); + } + + return ret; +} + +Iso14443_3aError iso14443_3a_listener_send_standard_frame( + Iso14443_3aListener* instance, + const BitBuffer* tx_buffer) { + furi_assert(instance); + furi_assert(tx_buffer); + furi_assert(instance->tx_buffer); + + Iso14443_3aError ret = Iso14443_3aErrorNone; + do { + bit_buffer_copy(instance->tx_buffer, tx_buffer); + iso14443_3a_append_crc(instance->tx_buffer); + + NfcError error = nfc_listener_tx(instance->nfc, instance->tx_buffer); + if(error != NfcErrorNone) { + FURI_LOG_W(TAG, "Tx error: %d", error); + ret = iso14443_3a_listener_process_nfc_error(error); + break; + } + } while(false); + + return ret; +} \ No newline at end of file diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener_i.h b/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener_i.h new file mode 100644 index 000000000000..5b0a56b26e01 --- /dev/null +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener_i.h @@ -0,0 +1,40 @@ +#pragma once + +#include "iso14443_3a_listener.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + Iso14443_3aListenerStateIdle, + Iso14443_3aListenerStateActive, +} Iso14443_3aListenerState; + +struct Iso14443_3aListener { + Nfc* nfc; + Iso14443_3aData* data; + Iso14443_3aListenerState state; + + BitBuffer* tx_buffer; + + NfcGenericEvent generic_event; + Iso14443_3aListenerEvent iso14443_3a_event; + Iso14443_3aListenerEventData iso14443_3a_event_data; + NfcGenericCallback callback; + void* context; +}; + +Iso14443_3aError iso14443_3a_listener_sleep(Iso14443_3aListener* instance); + +Iso14443_3aError + iso14443_3a_listener_tx(Iso14443_3aListener* instance, const BitBuffer* tx_buffer); + +Iso14443_3aError iso14443_3a_listener_send_standard_frame( + Iso14443_3aListener* instance, + const BitBuffer* tx_buffer); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.c b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.c index 554c9b1790b5..29ec412d46b1 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.c +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.c @@ -30,7 +30,7 @@ static Iso14443_3aPoller* iso14443_3a_poller_alloc(Nfc* nfc) { instance->iso14443_3a_event.data = &instance->iso14443_3a_event_data; instance->general_event.protocol = NfcProtocolIso14443_3a; instance->general_event.data = &instance->iso14443_3a_event; - instance->general_event.poller = instance; + instance->general_event.instance = instance; return instance; } @@ -98,7 +98,7 @@ static NfcCommand iso14443_3a_poller_run(NfcGenericEvent event, void* context) { static bool iso14443_3a_poller_detect(NfcGenericEvent event, void* context) { furi_assert(context); furi_assert(event.data); - furi_assert(event.poller); + furi_assert(event.instance); furi_assert(event.protocol = NfcProtocolInvalid); bool protocol_detected = false; diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_defs.h b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_defs.h index 1bcc684b405e..5ca9f538727a 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_defs.h +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_defs.h @@ -2,4 +2,12 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + extern const NfcPollerBase nfc_poller_iso14443_3a; + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.c b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.c index a5fa00535a9c..545d4932d23a 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.c +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.c @@ -26,7 +26,7 @@ static Iso14443_3aError iso14443_3a_poller_prepare_trx(Iso14443_3aPoller* instan return ret; } -static Iso14443_3aError iso14443_3a_poller_standart_frame_exchange( +static Iso14443_3aError iso14443_3a_poller_standard_frame_exchange( Iso14443_3aPoller* instance, const BitBuffer* tx_buffer, BitBuffer* rx_buffer, @@ -94,7 +94,7 @@ Iso14443_3aError iso14443_3a_poller_halt(Iso14443_3aPoller* instance) { uint8_t halt_cmd[2] = {0x50, 0x00}; bit_buffer_copy_bytes(instance->tx_buffer, halt_cmd, sizeof(halt_cmd)); - iso14443_3a_poller_standart_frame_exchange( + iso14443_3a_poller_standard_frame_exchange( instance, instance->tx_buffer, instance->rx_buffer, ISO14443_3A_FDT_LISTEN_FC); instance->state = Iso14443_3aPollerStateIdle; @@ -195,7 +195,7 @@ Iso14443_3aError iso14443_3a_poller_async_activate( instance->tx_buffer, (uint8_t*)&instance->col_res.sel_req, sizeof(instance->col_res.sel_req)); - ret = iso14443_3a_poller_send_standart_frame( + ret = iso14443_3a_poller_send_standard_frame( instance, instance->tx_buffer, instance->rx_buffer, ISO14443_3A_FDT_LISTEN_FC); if(ret != Iso14443_3aErrorNone) { FURI_LOG_E(TAG, "Sel request failed: %d", ret); @@ -300,7 +300,7 @@ Iso14443_3aError iso14443_3a_poller_txrx( return ret; } -Iso14443_3aError iso14443_3a_poller_send_standart_frame( +Iso14443_3aError iso14443_3a_poller_send_standard_frame( Iso14443_3aPoller* instance, const BitBuffer* tx_buffer, BitBuffer* rx_buffer, @@ -315,7 +315,7 @@ Iso14443_3aError iso14443_3a_poller_send_standart_frame( ret = iso14443_3a_poller_prepare_trx(instance); if(ret != Iso14443_3aErrorNone) break; - ret = iso14443_3a_poller_standart_frame_exchange(instance, tx_buffer, rx_buffer, fwt); + ret = iso14443_3a_poller_standard_frame_exchange(instance, tx_buffer, rx_buffer, fwt); if(ret != Iso14443_3aErrorNone) break; } while(false); diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.h b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.h index 1ca452b23266..99a2372bc96e 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.h +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.h @@ -82,7 +82,7 @@ Iso14443_3aError iso14443_3a_poller_txrx( BitBuffer* rx_buffer, uint32_t fwt); -Iso14443_3aError iso14443_3a_poller_send_standart_frame( +Iso14443_3aError iso14443_3a_poller_send_standard_frame( Iso14443_3aPoller* instance, const BitBuffer* tx_buffer, BitBuffer* rx_buffer, diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_sync_api.c b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_sync_api.c index 590512c099a1..ed1e30dc2a7d 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_sync_api.c +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_sync_api.c @@ -17,11 +17,11 @@ typedef struct { NfcCommand iso14443_3a_poller_read_callback(NfcGenericEvent event, void* context) { furi_assert(context); furi_assert(event.data); - furi_assert(event.poller); + furi_assert(event.instance); furi_assert(event.protocol == NfcProtocolIso14443_3a); Iso14443_3aPollerContext* poller_context = context; - Iso14443_3aPoller* iso14443_3a_poller = event.poller; + Iso14443_3aPoller* iso14443_3a_poller = event.instance; Iso14443_3aPollerEvent* iso14443_3a_event = event.data; if(iso14443_3a_event->type == Iso14443_3aPollerEventTypeReady) { diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a.c b/lib/nfc/protocols/iso14443_4a/iso14443_4a.c index bce0e4e3f125..8bc9f060876f 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a.c +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a.c @@ -18,6 +18,7 @@ const NfcDeviceBase nfc_device_iso14443_4a = { .is_equal = (NfcDeviceEqual)iso14443_4a_is_equal, .get_name = (NfcDeviceGetName)iso14443_4a_get_device_name, .get_uid = (NfcDeviceGetUid)iso14443_4a_get_uid, + .get_base_data = (NfcDeviceGetBaseData)iso14443_4a_get_base_data, }; Iso14443_4aData* iso14443_4a_alloc() { @@ -88,6 +89,12 @@ const uint8_t* iso14443_4a_get_uid(const Iso14443_4aData* data, size_t* uid_len) return iso14443_3a_get_uid(data->iso14443_3a_data, uid_len); } +const Iso14443_3aData* iso14443_4a_get_base_data(const Iso14443_4aData* data) { + furi_assert(data); + + return data->iso14443_3a_data; +} + bool iso14443_4a_is_ats_supported(const Iso14443_4aData* data) { const Iso14443_3aData* iso14443_3a_data = data->iso14443_3a_data; return iso14443_3a_data->sak & ISO14443_4A_ATS_BIT; diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a.h b/lib/nfc/protocols/iso14443_4a/iso14443_4a.h index 5c7d8c7e0a85..3b6eee22a27f 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a.h +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a.h @@ -53,6 +53,8 @@ const char* iso14443_4a_get_device_name(const Iso14443_4aData* data, NfcDeviceNa const uint8_t* iso14443_4a_get_uid(const Iso14443_4aData* data, size_t* uid_len); +const Iso14443_3aData* iso14443_4a_get_base_data(const Iso14443_4aData* data); + // Getters & Tests bool iso14443_4a_is_ats_supported(const Iso14443_4aData* data); diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.c b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.c index ab98f1ae5535..a5c599ba0bc7 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.c +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.c @@ -27,7 +27,7 @@ static Iso14443_4aPoller* iso14443_4a_poller_alloc(Iso14443_3aPoller* iso14443_3 instance->general_event.protocol = NfcProtocolIso14443_4a; instance->general_event.data = &instance->iso14443_4a_event; - instance->general_event.poller = instance; + instance->general_event.instance = instance; return instance; } diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c index 8f51d6a599e3..a33dfd061d02 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c @@ -45,7 +45,7 @@ Iso14443_4aError Iso14443_4aError error = Iso14443_4aErrorNone; do { - const Iso14443_3aError iso14443_3a_error = iso14443_3a_poller_send_standart_frame( + const Iso14443_3aError iso14443_3a_error = iso14443_3a_poller_send_standard_frame( instance->iso14443_3a_poller, instance->tx_buffer, instance->rx_buffer, @@ -84,7 +84,7 @@ Iso14443_4aError iso14443_4a_poller_send_block( Iso14443_4aError error = Iso14443_4aErrorNone; do { - Iso14443_3aError iso14443_3a_error = iso14443_3a_poller_send_standart_frame( + Iso14443_3aError iso14443_3a_error = iso14443_3a_poller_send_standard_frame( instance->iso14443_3a_poller, instance->tx_buffer, instance->rx_buffer, fwt); if(iso14443_3a_error != Iso14443_3aErrorNone) { diff --git a/lib/nfc/protocols/mf_classic/mf_classic.c b/lib/nfc/protocols/mf_classic/mf_classic.c index 034d785a527e..f139f3eb167e 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic.c +++ b/lib/nfc/protocols/mf_classic/mf_classic.c @@ -52,6 +52,7 @@ const NfcDeviceBase nfc_device_mf_classic = { .is_equal = (NfcDeviceEqual)mf_classic_is_equal, .get_name = (NfcDeviceGetName)mf_classic_get_device_name, .get_uid = (NfcDeviceGetUid)mf_classic_get_uid, + .get_base_data = (NfcDeviceGetBaseData)mf_classic_get_base_data, }; MfClassicData* mf_classic_alloc() { @@ -313,6 +314,12 @@ const uint8_t* mf_classic_get_uid(const MfClassicData* data, size_t* uid_len) { return iso14443_3a_get_uid(data->iso14443_3a_data, uid_len); } +const Iso14443_3aData* mf_classic_get_base_data(const MfClassicData* data) { + furi_assert(data); + + return data->iso14443_3a_data; +} + uint8_t mf_classic_get_total_sectors_num(MfClassicType type) { return mf_classic_features[type].sectors_total; } diff --git a/lib/nfc/protocols/mf_classic/mf_classic.h b/lib/nfc/protocols/mf_classic/mf_classic.h index 8ceba0fc6fc1..68724459cda4 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic.h +++ b/lib/nfc/protocols/mf_classic/mf_classic.h @@ -141,6 +141,8 @@ const char* mf_classic_get_device_name(const MfClassicData* data, NfcDeviceNameT const uint8_t* mf_classic_get_uid(const MfClassicData* data, size_t* uid_len); +const Iso14443_3aData* mf_classic_get_base_data(const MfClassicData* data); + bool mf_classic_detect_protocol(Iso14443_3aData* data, MfClassicType* type); uint8_t mf_classic_get_total_sectors_num(MfClassicType type); diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller.c b/lib/nfc/protocols/mf_classic/mf_classic_poller.c index 32ee2c926ddb..c39de0083fde 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller.c @@ -26,7 +26,7 @@ MfClassicPoller* mf_classic_poller_alloc(Iso14443_3aPoller* iso14443_3a_poller) instance->general_event.protocol = NfcProtocolMfClassic; instance->general_event.data = &instance->mfc_event; - instance->general_event.poller = instance; + instance->general_event.instance = instance; return instance; } diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c index e486764778e0..4944d46352c8 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c @@ -51,7 +51,7 @@ MfClassicError mf_classic_async_auth( uint8_t auth_cmd[2] = {auth_type, block_num}; bit_buffer_copy_bytes(instance->tx_plain_buffer, auth_cmd, sizeof(auth_cmd)); - error = iso14443_3a_poller_send_standart_frame( + error = iso14443_3a_poller_send_standard_frame( instance->iso14443_3a_poller, instance->tx_plain_buffer, instance->rx_plain_buffer, diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.c b/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.c index f7fe5ad35ade..23e0d9cacadc 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.c @@ -58,14 +58,14 @@ static const MfClassicPollerCmdHandler mf_classic_poller_cmd_handlers[MfClassicP }; static NfcCommand mf_ultralgiht_poller_cmd_callback(NfcGenericEvent event, void* context) { - furi_assert(event.poller); + furi_assert(event.instance); furi_assert(event.protocol == NfcProtocolIso14443_3a); furi_assert(event.data); furi_assert(context); MfClassicPollerContext* poller_context = context; Iso14443_3aPollerEvent* iso14443_3a_event = event.data; - Iso14443_3aPoller* iso14443_3a_poller = event.poller; + Iso14443_3aPoller* iso14443_3a_poller = event.instance; MfClassicPoller* mfc_poller = mf_classic_poller_alloc(iso14443_3a_poller); if(iso14443_3a_event->type == Iso14443_3aPollerEventTypeReady) { diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire.c b/lib/nfc/protocols/mf_desfire/mf_desfire.c index 84fe22ffba0e..43f6d1d47bc3 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire.c +++ b/lib/nfc/protocols/mf_desfire/mf_desfire.c @@ -17,6 +17,7 @@ const NfcDeviceBase nfc_device_mf_desfire = { .is_equal = (NfcDeviceEqual)mf_desfire_is_equal, .get_name = (NfcDeviceGetName)mf_desfire_get_device_name, .get_uid = (NfcDeviceGetUid)mf_desfire_get_uid, + .get_base_data = (NfcDeviceGetBaseData)mf_desfire_get_base_data, }; MfDesfireData* mf_desfire_alloc() { @@ -112,3 +113,9 @@ const uint8_t* mf_desfire_get_uid(const MfDesfireData* data, size_t* uid_len) { return iso14443_4a_get_uid(data->iso14443_4a_data, uid_len); } + +const Iso14443_4aData* mf_desfire_get_base_data(const MfDesfireData* data) { + furi_assert(data); + + return data->iso14443_4a_data; +} diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire.h b/lib/nfc/protocols/mf_desfire/mf_desfire.h index 5e1fca19150b..85821f648f0d 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire.h +++ b/lib/nfc/protocols/mf_desfire/mf_desfire.h @@ -171,6 +171,8 @@ const char* mf_desfire_get_device_name(const MfDesfireData* data, NfcDeviceNameT const uint8_t* mf_desfire_get_uid(const MfDesfireData* data, size_t* uid_len); +const Iso14443_4aData* mf_desfire_get_base_data(const MfDesfireData* data); + #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c b/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c index df8e045b11c8..6fb07091c2ac 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c @@ -29,7 +29,7 @@ static MfDesfirePoller* mf_desfire_poller_alloc(Iso14443_4aPoller* iso14443_4a_p instance->general_event.protocol = NfcProtocolMfDesfire; instance->general_event.data = &instance->mf_desfire_event; - instance->general_event.poller = instance; + instance->general_event.instance = instance; return instance; } diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight.c index 8df26889c95b..067e46a06b74 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight.c @@ -129,6 +129,7 @@ const NfcDeviceBase nfc_device_mf_ultralight = { .is_equal = (NfcDeviceEqual)mf_ultralight_is_equal, .get_name = (NfcDeviceGetName)mf_ultralight_get_device_name, .get_uid = (NfcDeviceGetUid)mf_ultralight_get_uid, + .get_base_data = (NfcDeviceGetBaseData)mf_ultralight_get_base_data, }; MfUltralightData* mf_ultralight_alloc() { @@ -389,6 +390,12 @@ const uint8_t* mf_ultralight_get_uid(const MfUltralightData* data, size_t* uid_l return iso14443_3a_get_uid(data->iso14443_3a_data, uid_len); } +const Iso14443_3aData* mf_ultralight_get_base_data(const MfUltralightData* data) { + furi_assert(data); + + return data->iso14443_3a_data; +} + MfUltralightType mf_ultralight_get_type_by_version(MfUltralightVersion* version) { furi_assert(version); diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h index 22d096d9b6db..460b907a4553 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h @@ -188,6 +188,8 @@ const char* const uint8_t* mf_ultralight_get_uid(const MfUltralightData* data, size_t* uid_len); +const Iso14443_3aData* mf_ultralight_get_base_data(const MfUltralightData* data); + MfUltralightType mf_ultralight_get_type_by_version(MfUltralightVersion* version); uint16_t mf_ultralight_get_pages_total(MfUltralightType type); diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c index 39e0be1e0075..41e8b0fd14f9 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c @@ -1,4 +1,7 @@ -#include "mf_ultralight_listener.h" +#include "mf_ultralight_listener_i.h" +#include "mf_ultralight_listener_defs.h" + +#include #include @@ -11,28 +14,6 @@ typedef enum { MfUltralightListenerAccessTypeWrite, } MfUltralightListenerAccessType; -typedef enum { - MfUltralightListenerAuthStateIdle, - MfUltralightListenerAuthStateSuccess, -} MfUltralightListenerAuthState; - -typedef enum { - MfUltraligthListenerStateIdle, -} MfUltraligthListenerState; - -struct MfUltralightListener { - Iso14443_3aListener* iso14443_3a_listener; - MfUltralightListenerAuthState auth_state; - MfUltraligthListenerState state; - MfUltralightData* data; - BitBuffer* tx_buffer; - MfUltralightFeatureSupport features; - MfUltralightConfigPages* config; - - MfUltralightListenerEventCallback callback; - void* context; -}; - typedef bool (*MfUltralightListenerCommandCallback)(MfUltralightListener* instance, BitBuffer* buf); typedef struct { @@ -41,32 +22,6 @@ typedef struct { MfUltralightListenerCommandCallback callback; } MfUltralightListenerCmdHandler; -static MfUltralightError mf_ultralight_process_error(Iso14443_3aError error) { - MfUltralightError ret = MfUltralightErrorNone; - - switch(error) { - case Iso14443_3aErrorNone: - ret = MfUltralightErrorNone; - break; - case Iso14443_3aErrorNotPresent: - ret = MfUltralightErrorNotPresent; - break; - case Iso14443_3aErrorColResFailed: - case Iso14443_3aErrorCommunication: - case Iso14443_3aErrorWrongCrc: - ret = MfUltralightErrorProtocol; - break; - case Iso14443_3aErrorTimeout: - ret = MfUltralightErrorTimeout; - break; - default: - ret = MfUltralightErrorProtocol; - break; - } - - return ret; -} - static bool mf_ultralight_listener_check_access( MfUltralightListener* instance, uint8_t start_page, @@ -137,7 +92,7 @@ static bool instance->tx_buffer, (uint8_t*)&read_cmd_data, sizeof(MfUltralightPageReadCommandData)); - iso14443_3a_listener_send_standart_frame( + iso14443_3a_listener_send_standard_frame( instance->iso14443_3a_listener, instance->tx_buffer); } command_processed = true; @@ -179,7 +134,7 @@ static bool if((instance->features & MfUltralightFeatureSupportReadVersion)) { bit_buffer_copy_bytes( instance->tx_buffer, (uint8_t*)&instance->data->version, sizeof(MfUltralightVersion)); - iso14443_3a_listener_send_standart_frame( + iso14443_3a_listener_send_standard_frame( instance->iso14443_3a_listener, instance->tx_buffer); } else { iso14443_3a_listener_sleep(instance->iso14443_3a_listener); @@ -200,7 +155,7 @@ static bool mf_ultralight_listener_read_signature_handler( if((instance->features & MfUltralightFeatureSupportReadSignature)) { bit_buffer_copy_bytes( instance->tx_buffer, instance->data->signature.data, sizeof(MfUltralightSignature)); - iso14443_3a_listener_send_standart_frame( + iso14443_3a_listener_send_standard_frame( instance->iso14443_3a_listener, instance->tx_buffer); } else { iso14443_3a_listener_sleep(instance->iso14443_3a_listener); @@ -240,7 +195,7 @@ static bool (instance->data->counter[counter_num].counter >> 16) & 0xff, }; bit_buffer_copy_bytes(instance->tx_buffer, cnt_value, sizeof(cnt_value)); - iso14443_3a_listener_send_standart_frame( + iso14443_3a_listener_send_standard_frame( instance->iso14443_3a_listener, instance->tx_buffer); command_processed = true; } while(false); @@ -259,7 +214,7 @@ static bool mf_ultralight_listener_check_tearing_handler( if(tearing_flag_num > 2) break; bit_buffer_set_size_bytes(instance->tx_buffer, 1); bit_buffer_set_byte(instance->tx_buffer, 0, instance->data->tearing_flag->data[0]); - iso14443_3a_listener_send_standart_frame( + iso14443_3a_listener_send_standard_frame( instance->iso14443_3a_listener, instance->tx_buffer); command_processed = true; } while(false); @@ -278,19 +233,16 @@ static bool MfUltralightAuthPassword password = {}; memcpy(password.data, &rx_data[1], sizeof(MfUltralightAuthPassword)); if(instance->callback) { - MfUltralightListenerEventData data = {.password = password}; - MfUltralightListenerEvent event = { - .type = MfUltralightListenerEventTypeAuth, - .data = &data, - }; - instance->callback(event, instance->context); + instance->mfu_event_data.password = password; + instance->mfu_event.type = MfUltralightListenerEventTypeAuth; + instance->callback(instance->generic_event, instance->context); } if(password.pass != instance->config->password.pass) break; bit_buffer_copy_bytes( instance->tx_buffer, instance->config->pack.data, sizeof(MfUltralightAuthPack)); instance->auth_state = MfUltralightListenerAuthStateSuccess; - iso14443_3a_listener_send_standart_frame( + iso14443_3a_listener_send_standard_frame( instance->iso14443_3a_listener, instance->tx_buffer); command_processed = true; @@ -334,33 +286,8 @@ static const MfUltralightListenerCmdHandler mf_ultralight_command[] = { .cmd = MF_ULTRALIGHT_CMD_AUTH, .cmd_len_bits = 5 * 8, .callback = mf_ultralight_listener_auth_handler, - }}; - -static Iso14443_3aListenerCommand - mf_ultralight_listener_event_handler(Iso14443_3aListenerEvent event, void* context) { - furi_assert(context); - - MfUltralightListener* instance = context; - BitBuffer* rx_buffer = event.data.buffer; - - Iso14443_3aListenerCommand command = Iso14443_3aListenerCommandContinue; - if(event.type == Iso14443_3aListenerEventTypeReceivedStandartFrame) { - bool cmd_processed = false; - for(size_t i = 0; i < COUNT_OF(mf_ultralight_command); i++) { - if(bit_buffer_get_size(rx_buffer) != mf_ultralight_command[i].cmd_len_bits) continue; - if(bit_buffer_get_byte(rx_buffer, 0) != mf_ultralight_command[i].cmd) continue; - cmd_processed = mf_ultralight_command[i].callback(instance, rx_buffer); - if(cmd_processed) break; - } - if(!cmd_processed) { - mf_ultralight_listener_send_short_resp(instance, MF_ULTRALIGHT_CMD_NACK); - instance->state = MfUltraligthListenerStateIdle; - instance->auth_state = MfUltralightListenerAuthStateIdle; - } - } - - return command; -} + }, +}; static void mf_ultralight_listener_prepare_emulation(MfUltralightListener* instance) { MfUltralightData* data = instance->data; @@ -368,67 +295,85 @@ static void mf_ultralight_listener_prepare_emulation(MfUltralightListener* insta mf_ultralight_get_config_page(data, &instance->config); } -MfUltralightListener* mf_ultralight_listener_alloc(Iso14443_3aListener* iso14443_3a_listener) { +MfUltralightListener* mf_ultralight_listener_alloc( + Iso14443_3aListener* iso14443_3a_listener, + const MfUltralightData* data) { furi_assert(iso14443_3a_listener); MfUltralightListener* instance = malloc(sizeof(MfUltralightListener)); instance->iso14443_3a_listener = iso14443_3a_listener; - - return instance; -} - -MfUltralightError mf_ultralight_listener_start( - MfUltralightListener* instance, - const MfUltralightData* data, - MfUltralightListenerEventCallback callback, - void* context) { - furi_assert(instance); - furi_assert(data); - instance->data = mf_ultralight_alloc(); mf_ultralight_copy(instance->data, data); - instance->tx_buffer = bit_buffer_alloc(MF_ULTRALIGHT_LISTENER_MAX_TX_BUFF_SIZE); mf_ultralight_listener_prepare_emulation(instance); + instance->tx_buffer = bit_buffer_alloc(MF_ULTRALIGHT_LISTENER_MAX_TX_BUFF_SIZE); - instance->callback = callback; - instance->context = context; - - Iso14443_3aError error = iso14443_3a_listener_start( - instance->iso14443_3a_listener, - instance->data->iso14443_3a_data, - mf_ultralight_listener_event_handler, - instance); + instance->mfu_event.data = &instance->mfu_event_data; + instance->generic_event.protocol = NfcProtocolMfUltralight; + instance->generic_event.instance = instance; + instance->generic_event.data = &instance->mfu_event; - return mf_ultralight_process_error(error); + return instance; } void mf_ultralight_listener_free(MfUltralightListener* instance) { furi_assert(instance); + furi_assert(instance->data); + furi_assert(instance->tx_buffer); + bit_buffer_free(instance->tx_buffer); + mf_ultralight_free(instance->data); free(instance); } -MfUltralightError - mf_ultralight_listener_get_data(MfUltralightListener* instance, MfUltralightData* data) { +const MfUltralightData* mf_ultralight_listener_get_data(MfUltralightListener* instance) { furi_assert(instance); furi_assert(instance->data); - furi_assert(data); - mf_ultralight_copy(data, instance->data); - - return MfUltralightErrorNone; + return instance->data; } -MfUltralightError mf_ultralight_listener_stop(MfUltralightListener* instance) { +void mf_ultralight_listener_set_callback( + MfUltralightListener* instance, + NfcGenericCallback callback, + void* context) { furi_assert(instance); - furi_assert(instance->data); - furi_assert(instance->tx_buffer); - Iso14443_3aError error = iso14443_3a_listener_stop(instance->iso14443_3a_listener); - instance->state = MfUltraligthListenerStateIdle; + instance->callback = callback; + instance->context = context; +} - bit_buffer_free(instance->tx_buffer); - mf_ultralight_free(instance->data); +NfcCommand mf_ultralight_listener_run(NfcGenericEvent event, void* context) { + furi_assert(context); + furi_assert(event.protocol == NfcProtocolIso14443_3a); + furi_assert(event.data); + + MfUltralightListener* instance = context; + Iso14443_3aListenerEvent* iso14443_3a_event = event.data; + BitBuffer* rx_buffer = iso14443_3a_event->data->buffer; + NfcCommand command = NfcCommandContinue; + + if(iso14443_3a_event->type == Iso14443_3aListenerEventTypeReceivedStandardFrame) { + bool cmd_processed = false; + for(size_t i = 0; i < COUNT_OF(mf_ultralight_command); i++) { + if(bit_buffer_get_size(rx_buffer) != mf_ultralight_command[i].cmd_len_bits) continue; + if(bit_buffer_get_byte(rx_buffer, 0) != mf_ultralight_command[i].cmd) continue; + cmd_processed = mf_ultralight_command[i].callback(instance, rx_buffer); + if(cmd_processed) break; + } + if(!cmd_processed) { + mf_ultralight_listener_send_short_resp(instance, MF_ULTRALIGHT_CMD_NACK); + instance->state = MfUltraligthListenerStateIdle; + instance->auth_state = MfUltralightListenerAuthStateIdle; + } + } - return mf_ultralight_process_error(error); + return command; } + +const NfcListenerBase mf_ultralight_listener = { + .alloc = (NfcListenerAlloc)mf_ultralight_listener_alloc, + .free = (NfcListenerFree)mf_ultralight_listener_free, + .get_data = (NfcListenerGetData)mf_ultralight_listener_get_data, + .set_callback = (NfcListenerSetCallback)mf_ultralight_listener_set_callback, + .run = (NfcListenerRun)mf_ultralight_listener_run, +}; diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.h index a45d22b6643f..befbdc837385 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.h @@ -24,29 +24,6 @@ typedef struct { MfUltralightListenerEventData* data; } MfUltralightListenerEvent; -typedef enum { - MfUltralightListenerCommandContinue = Iso14443_3aListenerCommandContinue, - MfUltralightListenerCommandReset = Iso14443_3aListenerCommandReset, -} MfUltralightListenerCommand; - -typedef MfUltralightListenerCommand ( - *MfUltralightListenerEventCallback)(MfUltralightListenerEvent event, void* context); - -MfUltralightListener* mf_ultralight_listener_alloc(Iso14443_3aListener* iso14443_3a_listener); - -void mf_ultralight_listener_free(MfUltralightListener* instance); - -MfUltralightError mf_ultralight_listener_start( - MfUltralightListener* instance, - const MfUltralightData* data, - MfUltralightListenerEventCallback callback, - void* context); - -MfUltralightError - mf_ultralight_listener_get_data(MfUltralightListener* instance, MfUltralightData* data); - -MfUltralightError mf_ultralight_listener_stop(MfUltralightListener* instance); - #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_defs.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_defs.h new file mode 100644 index 000000000000..aa3e11b8c4df --- /dev/null +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_defs.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern const NfcListenerBase mf_ultralight_listener; + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h new file mode 100644 index 000000000000..52ea07486f64 --- /dev/null +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h @@ -0,0 +1,38 @@ +#pragma once + +#include "mf_ultralight_listener.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + MfUltralightListenerAuthStateIdle, + MfUltralightListenerAuthStateSuccess, +} MfUltralightListenerAuthState; + +typedef enum { + MfUltraligthListenerStateIdle, +} MfUltraligthListenerState; + +struct MfUltralightListener { + Iso14443_3aListener* iso14443_3a_listener; + MfUltralightListenerAuthState auth_state; + MfUltraligthListenerState state; + + MfUltralightData* data; + BitBuffer* tx_buffer; + MfUltralightFeatureSupport features; + MfUltralightConfigPages* config; + + NfcGenericEvent generic_event; + MfUltralightListenerEvent mfu_event; + MfUltralightListenerEventData mfu_event_data; + NfcGenericCallback callback; + void* context; +}; + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c index d050fa8ed78d..30b6b1e47b31 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c @@ -179,7 +179,7 @@ MfUltralightPoller* mf_ultralight_poller_alloc(Iso14443_3aPoller* iso14443_3a_po instance->general_event.protocol = NfcProtocolMfUltralight; instance->general_event.data = &instance->mfu_event; - instance->general_event.poller = instance; + instance->general_event.instance = instance; return instance; } diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c index cc9596be80bc..8e362cd66f24 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c @@ -40,7 +40,7 @@ MfUltralightError mf_ultralight_poller_async_auth( MfUltralightError ret = MfUltralightErrorNone; Iso14443_3aError error = Iso14443_3aErrorNone; do { - error = iso14443_3a_poller_send_standart_frame( + error = iso14443_3a_poller_send_standard_frame( instance->iso14443_3a_poller, instance->tx_buffer, instance->rx_buffer, @@ -70,7 +70,7 @@ MfUltralightError mf_ultralight_poller_async_read_page_from_sector( do { const uint8_t select_sector_cmd[2] = {MF_ULTRALIGHT_CMD_SECTOR_SELECT, 0xff}; bit_buffer_copy_bytes(instance->tx_buffer, select_sector_cmd, sizeof(select_sector_cmd)); - error = iso14443_3a_poller_send_standart_frame( + error = iso14443_3a_poller_send_standard_frame( instance->iso14443_3a_poller, instance->tx_buffer, instance->rx_buffer, @@ -83,7 +83,7 @@ MfUltralightError mf_ultralight_poller_async_read_page_from_sector( const uint8_t read_sector_cmd[4] = {sector, 0x00, 0x00, 0x00}; bit_buffer_copy_bytes(instance->tx_buffer, read_sector_cmd, sizeof(read_sector_cmd)); - error = iso14443_3a_poller_send_standart_frame( + error = iso14443_3a_poller_send_standard_frame( instance->iso14443_3a_poller, instance->tx_buffer, instance->rx_buffer, @@ -111,7 +111,7 @@ MfUltralightError mf_ultralight_poller_async_read_page( do { uint8_t read_page_cmd[2] = {MF_ULTRALIGHT_CMD_READ_PAGE, start_page}; bit_buffer_copy_bytes(instance->tx_buffer, read_page_cmd, sizeof(read_page_cmd)); - error = iso14443_3a_poller_send_standart_frame( + error = iso14443_3a_poller_send_standard_frame( instance->iso14443_3a_poller, instance->tx_buffer, instance->rx_buffer, @@ -142,7 +142,7 @@ MfUltralightError mf_ultralight_poller_async_write_page( uint8_t write_page_cmd[MF_ULTRALIGHT_PAGE_SIZE + 2] = {MF_ULTRALIGHT_CMD_WRITE_PAGE, page}; memcpy(&write_page_cmd[2], data->data, MF_ULTRALIGHT_PAGE_SIZE); bit_buffer_copy_bytes(instance->tx_buffer, write_page_cmd, sizeof(write_page_cmd)); - error = iso14443_3a_poller_send_standart_frame( + error = iso14443_3a_poller_send_standard_frame( instance->iso14443_3a_poller, instance->tx_buffer, instance->rx_buffer, @@ -173,7 +173,7 @@ MfUltralightError mf_ultralight_poller_async_read_version( do { const uint8_t get_version_cmd = MF_ULTRALIGHT_CMD_GET_VERSION; bit_buffer_copy_bytes(instance->tx_buffer, &get_version_cmd, sizeof(get_version_cmd)); - error = iso14443_3a_poller_send_standart_frame( + error = iso14443_3a_poller_send_standard_frame( instance->iso14443_3a_poller, instance->tx_buffer, instance->rx_buffer, @@ -203,7 +203,7 @@ MfUltralightError mf_ultralight_poller_async_read_signature( do { const uint8_t read_signature_cmd[2] = {MF_ULTRALIGTH_CMD_READ_SIG, 0x00}; bit_buffer_copy_bytes(instance->tx_buffer, read_signature_cmd, sizeof(read_signature_cmd)); - error = iso14443_3a_poller_send_standart_frame( + error = iso14443_3a_poller_send_standard_frame( instance->iso14443_3a_poller, instance->tx_buffer, instance->rx_buffer, @@ -232,7 +232,7 @@ MfUltralightError mf_ultralight_poller_async_read_counter( do { uint8_t read_counter_cmd[2] = {MF_ULTRALIGHT_CMD_READ_CNT, counter_num}; bit_buffer_copy_bytes(instance->tx_buffer, read_counter_cmd, sizeof(read_counter_cmd)); - error = iso14443_3a_poller_send_standart_frame( + error = iso14443_3a_poller_send_standard_frame( instance->iso14443_3a_poller, instance->tx_buffer, instance->rx_buffer, @@ -261,7 +261,7 @@ MfUltralightError mf_ultralight_poller_async_read_tearing_flag( do { uint8_t check_tearing_cmd[2] = {MF_ULTRALIGHT_CMD_CHECK_TEARING, tearing_falg_num}; bit_buffer_copy_bytes(instance->tx_buffer, check_tearing_cmd, sizeof(check_tearing_cmd)); - error = iso14443_3a_poller_send_standart_frame( + error = iso14443_3a_poller_send_standard_frame( instance->iso14443_3a_poller, instance->tx_buffer, instance->rx_buffer, diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c index 3a263e9544c7..a4316fbec0ae 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c @@ -80,14 +80,14 @@ static const MfUltralightPollerCmdHandler }; static NfcCommand mf_ultralgiht_poller_cmd_callback(NfcGenericEvent event, void* context) { - furi_assert(event.poller); + furi_assert(event.instance); furi_assert(event.protocol == NfcProtocolIso14443_3a); furi_assert(event.data); furi_assert(context); MfUltralightPollerContext* poller_context = context; Iso14443_3aPollerEvent* iso14443_3a_event = event.data; - Iso14443_3aPoller* iso14443_3a_poller = event.poller; + Iso14443_3aPoller* iso14443_3a_poller = event.instance; MfUltralightPoller* mfu_poller = mf_ultralight_poller_alloc(iso14443_3a_poller); if(iso14443_3a_event->type == Iso14443_3aPollerEventTypeReady) { @@ -234,13 +234,13 @@ MfUltralightError mf_ultralight_poller_read_tearing_flag( static NfcCommand mf_ultralight_poller_read_callback(NfcGenericEvent event, void* context) { furi_assert(context); - furi_assert(event.poller); + furi_assert(event.instance); furi_assert(event.data); furi_assert(event.protocol == NfcProtocolMfUltralight); NfcCommand command = NfcCommandContinue; MfUltralightPollerContext* poller_context = context; - MfUltralightPoller* mfu_poller = event.poller; + MfUltralightPoller* mfu_poller = event.instance; MfUltralightPollerEvent* mfu_event = event.data; if(mfu_event->type == MfUltralightPollerEventTypeReadSuccess) { diff --git a/lib/nfc/protocols/nfc_device_base.h b/lib/nfc/protocols/nfc_device_base.h index f727950cb311..e877e4422b8a 100644 --- a/lib/nfc/protocols/nfc_device_base.h +++ b/lib/nfc/protocols/nfc_device_base.h @@ -23,6 +23,7 @@ typedef bool (*NfcDeviceSave)(const NfcDeviceData* data, FlipperFormat* ff, uint typedef bool (*NfcDeviceEqual)(const NfcDeviceData* data, const NfcDeviceData* other); typedef const char* (*NfcDeviceGetName)(const NfcDeviceData* data, NfcDeviceNameType name_type); typedef const uint8_t* (*NfcDeviceGetUid)(const NfcDeviceData* data, size_t* uid_len); +typedef const NfcDeviceData* (*NfcDeviceGetBaseData)(const NfcDeviceData* data); typedef struct { const char* protocol_name; @@ -36,6 +37,7 @@ typedef struct { NfcDeviceEqual is_equal; NfcDeviceGetName get_name; NfcDeviceGetUid get_uid; + NfcDeviceGetBaseData get_base_data; } NfcDeviceBase; #ifdef __cplusplus diff --git a/lib/nfc/protocols/nfc_generic_event.h b/lib/nfc/protocols/nfc_generic_event.h index dac6a69fed6b..64c7939d00d1 100644 --- a/lib/nfc/protocols/nfc_generic_event.h +++ b/lib/nfc/protocols/nfc_generic_event.h @@ -13,7 +13,7 @@ typedef void NfcGenericEventData; typedef struct { NfcProtocol protocol; - NfcGenericInstance* poller; + NfcGenericInstance* instance; NfcGenericEventData* data; } NfcGenericEvent; diff --git a/lib/nfc/protocols/nfc_listener_base.h b/lib/nfc/protocols/nfc_listener_base.h index 028622c6a7b4..52eaea49505b 100644 --- a/lib/nfc/protocols/nfc_listener_base.h +++ b/lib/nfc/protocols/nfc_listener_base.h @@ -7,12 +7,10 @@ extern "C" { #endif -typedef NfcGenericInstance* (*NfcListenerAlloc)(NfcGenericInstance* base_listener); +typedef NfcGenericInstance* ( + *NfcListenerAlloc)(NfcGenericInstance* base_listener, const NfcDeviceData* data); typedef void (*NfcListenerFree)(NfcGenericInstance* instance); -typedef const NfcDeviceData* (*NfcListenerGetBaseData)(const NfcGenericInstance* instance); -typedef void (*NfcListenerSetData)(NfcGenericInstance* instance, const NfcDeviceData* data); - typedef void (*NfcListenerSetCallback)( NfcGenericInstance* listener, NfcGenericCallback callback, @@ -24,8 +22,6 @@ typedef const NfcDeviceData* (*NfcListenerGetData)(const NfcGenericInstance* ins typedef struct { NfcListenerAlloc alloc; NfcListenerFree free; - NfcListenerGetBaseData get_base_data; - NfcListenerSetData set_data; NfcListenerSetCallback set_callback; NfcListenerRun run; NfcListenerGetData get_data; diff --git a/lib/nfc/protocols/nfc_listener_defs.c b/lib/nfc/protocols/nfc_listener_defs.c index 8e7cc377a5ec..7c7e3d26030e 100644 --- a/lib/nfc/protocols/nfc_listener_defs.c +++ b/lib/nfc/protocols/nfc_listener_defs.c @@ -1,14 +1,14 @@ #include "nfc_listener_defs.h" -// #include +#include // #include -// #include +#include // #include const NfcListenerBase* nfc_listeners_api[NfcProtocolNum] = { - [NfcProtocolIso14443_3a] = NULL, //&nfc_listener_iso14443_3a, + [NfcProtocolIso14443_3a] = &nfc_listener_iso14443_3a, [NfcProtocolIso14443_4a] = NULL, //&nfc_listener_iso14443_4a, - [NfcProtocolMfUltralight] = NULL, //&mf_ultralight_listener, + [NfcProtocolMfUltralight] = &mf_ultralight_listener, [NfcProtocolMfClassic] = NULL, //&mf_classic_listener, [NfcProtocolMfDesfire] = NULL, }; diff --git a/lib/nfc/protocols/nfcb/nfcb_poller.c b/lib/nfc/protocols/nfcb/nfcb_poller.c index 4dc2f72dd26c..920dfc5abc5d 100644 --- a/lib/nfc/protocols/nfcb/nfcb_poller.c +++ b/lib/nfc/protocols/nfcb/nfcb_poller.c @@ -34,12 +34,10 @@ void nfcb_poller_free(NfcbPoller* instance) { static NfcCommand nfcb_poller_event_callback(NfcEvent event, void* context) { furi_assert(context); + UNUSED(event); NfcbPoller* instance = context; furi_assert(instance->callback); - if(event.type == NfcEventTypeConfigureRequest) { - nfcb_poller_config(instance); - } return NfcCommandContinue; } From 39b87f7488775b403fe9fefbda271031e4e0d83b Mon Sep 17 00:00:00 2001 From: gornekich Date: Sun, 2 Jul 2023 02:16:00 +0400 Subject: [PATCH 116/149] Merge dev (#2827) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix typo in FuriHalDebuging.md (#2667) * [FL-3317] fbt: allow strings for fap_version field in app manifests (#2672) * [FL-3312] fix PIN retry count reset on reboot (#2671) * api: added lib/nfc/protocols/nfc_util.h (#2674) * Add new indexer (#2681) * fbt: Use union for old py (#2685) * fbt: Fix tar uid overflow when packaging (#2689) * fbt: Fix tar uid overflow when packaging * Fix trailing spaces * [FL-3328] Removed user-specific data from tar artifacts (#2691) * [FL-3327] Storage: common_rename is now POSIX compliant (#2693) * Storage: common_rename is now POSIX compliant * storage: check for success on storage_common_remove in file rename --------- Co-authored-by: hedger * Services: remove deallocator for persistent services (#2692) Co-authored-by: hedger * Storage, common_rename: check that old path is exists (#2698) * Storage, common_rename: check that old path is exists * Storage, common_rename: return correct status * [FL-3315] Desktop,Rpc: desktop status subscription (#2696) * Desktop,Rpc: desktop status subscription * Desktop,RPC: properly handle unsubscribe Co-authored-by: Sergey Gavrilov * :sparkles: Add fr-FR-mac key layout (#2666) Co-authored-by: あく * [FL-3322] Infrared: respect carrier frequency and duty cycle settings (#2677) * Make infrared_worker respect carrier frequency and duty cycle * Update comments Co-authored-by: あく * USB HID report timeout (#2682) Co-authored-by: あく * Add Airwell Prime DCI Series and match file style (#2686) Co-authored-by: あく * desktop: Refactor favorites settings and allow app browser in selection (#2687) * desktop: Refactor favorites settings and allow app browser in selection * desktop: Gate app browser entry add, just in case * Desktop: simplify favorite application selection * Desktop: refactor favorite application opening routine and cleanup code * Desktop: handle exit from external application selection Co-authored-by: hedger Co-authored-by: あく * NFC: Add support for Gen4 "ultimate card" in Magic app (#2238) * NFC: gen4 gtu detect in magic app * NFC: more support for GTU card * NFC: Fix Gen1 in Magic * Allow double UIDs for MFClassic on GTU cards * NFC: Small magic app tweaks * nfc magic: notify card event on wiping * nfc magic: fix power consumption * nfc magic: disable i2c writing and fix wipe loop * NfcMagic: correct formatting in printf * NfcMagic: correct formatting in printf, proper version * nfc_magic: rework card found notification and gen4 wiping Co-authored-by: あく * nfc: Fix MFUL tearing flags read (#2669) Co-authored-by: gornekich * api: added toolbox/api_lock.h (#2702) Co-authored-by: あく * Update ac.ir (#2701) Co-authored-by: あく * nfc: Mifare Ultralight C detection (#2668) * nfc: Add Mifare Ultralight C detection * nfc: Add display name for MFUL C and hide menu items MFUL C unlock and emulation currently not supported, so hide from menu if current card is MFUL C * nfc: Also check response when probing 3DES auth * nfc: Hide emulate option in saved menu for MFUL if not supported * nfc: Remove unlock options from saved menu if Ultralight C Co-authored-by: gornekich Co-authored-by: あく * [LRFID] Add support for Nexkey/Nexwatch (#2680) * [LRFID] Add support for Nexkey/Nexwatch * Update protocol_nexwatch.c: Remove unnecessary check Co-authored-by: SG Co-authored-by: あく * Add Carrier 42QHB12D8S (#2707) Co-authored-by: あく * BadUSB: script execution pause (#2700) Co-authored-by: あく * Implement support for reading Opal card (Sydney, Australia) (#2683) * Implement support for reading Opal card (Sydney, Australia) * stub_parser_verify_read: used UNUSED macro * furi_hal_rtc: expose calendaring as functions * opal: use bit-packed struct to parse, rather than manually shifting about * Update f18 api symbols Co-authored-by: あく * [FL-3295] FuriHal: add bus abstraction (#2614) * FuriHal: add bus abstraction and port some subsystem to it * Make PVS happy, cleanup code * Update API symbols for f18 * F18: backport bus changes from f7 * Revert to STOP2 sleep mode * Fix downgrading the firmware via updater * Port iButton TIM1 to furi_hal_bus * Port Infrared TIM1 and TIM2 to furi_hal_bus * Just enable the timer bus * Port furi_hal_pwm to bus API * Fix include statement * Port furi_hal_rfid to bus API * Port furi_hal_subghz and others to bus API * Remove unneeded include * Improve furi_hal_infrared defines * Reset LPTIM1 via furi_hal_bus API * Crash when trying to enable an already enabled peripheral * Better defines * Improved checks * Lots of macro wrappers * Copy spi changes for f18 * Fix crashes in LFRFID system * Fix crashes in NFC system * Improve comments * Create FuriHalBus.md * Update FuriHalBus.md * Fix crash when launching updater * Documentation: couple small fixes in FuriHalBus * FuriHal: fix copypaste in furi_hal_rfid_tim_reset * FuriHal: reset radio core related peripherals on restart * FuriHalBus: is enabled routine and bug fix for uart * RFID HAL: accomodate furi hal bus Co-authored-by: Georgii Surkov Co-authored-by: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Co-authored-by: SG * [FL-3330] fbt: added hooks for build & dist environments; added FW_ORIGIN_* macro for apps & SDK (#2705) * fbt: added hooks for build & dist environments * Moved env hooks to an optional file * Fixed var name * Added fw origin to device info * Bumped device info version * fbt: added FIRMWARE_ORIGIN option. Different implementation for FW_ORIGIN_* C macro. * api: bumped versions * fbt: added fbt_options_local.py * gitignore: cleanup Co-authored-by: あく * [FL-3335] Dolphin: new animation (#2713) * [FL-3340] SubGhz: fix flipper crashes after exiting broadcast blocking message and crash cli (#2714) * NFC: Fix gen1 writing with invalid BCC (lost fix from PR #2511) (#2710) Co-authored-by: あく * Update dolphin.py (#2717) Co-authored-by: あく * NFC: fix MFC timings (#2719) * digital signal: add optimization * nfc test: more restrict tests * digital signal: build as separate library * digital signal: remove unused flags, format sources * digital signal: fix cflag name * target: fix build for f18 target Co-authored-by: あく * FuriHal: disable bus re-initialization on early init and extra asserts for AHB1,AHB2,AHB3 which must be left intact on entering to FUS (#2725) * [DEVOPS-18]: Add map file parser, mariadb inserter (#2732) * [FL-3293] FuriHal: add system setting to device info, bump device info version (#2736) * [FL-3316] Settings: add contrast adjustment (#2737) Co-authored-by: hedger * [FL-3213] f7: add PB9 to debug pins (#2738) Co-authored-by: hedger * [FL-3352] Dolphin: new animation (#2735) Co-authored-by: hedger * [FL-2872] Remove unused resources (#2740) Co-authored-by: hedger * Serial_CLI: Fixing serial cli logger error so it sounds more concise (#2721) Co-authored-by: hedger * Furi: smaller critical enter and critical exit macro (#2716) * Furi: smaller critical enter and critical exit macro * api: bumped version --------- Co-authored-by: hedger Co-authored-by: hedger * [FL-3331] SubGhz: add subghz_protocol_registry external API (#2712) * [FL-3331] SubGhz: add subghz_protocol_registry external API * F18: fix API version --------- Co-authored-by: hedger * [FL-3045] Fix core2 permisions (#2742) * Fix core2 permisions * Fix Python code style * scripts: copro: changed int literals * scripts: copro: shorter string line in code --------- Co-authored-by: hedger Co-authored-by: hedger * [FL-3246] fbt, ufbt: added checks for appid in app manifests(#2720) Co-authored-by: あく * Map parser licence description (#2739) * Add map parser licence description * Add map parser copyright text & licence note --------- Co-authored-by: hedger * [FL-3346] fbt: added Flipper selection when multiple are connected over USB (#2723) * fbt: added Flipper selection when multiple are connected over USB * scripts: serial_cli: added --port (-p) option * added ISO15693 (NfcV) reading, saving, emulating and revealing from privacy mode (unlock) (#2316) * added support for ISO15693 (NfcV) emulation, added support for reading SLIX tags * SLIX: fixed crash situation when an invalid password was requested * ISO15693: show emulate menu when opening file * rename NfcV emulate scene to match other NfcV names * optimize allocation size for signals * ISO15693: further optimizations of allocation and free code * ISO15693: reduce latency on state machine reset * respond with block security status when option flag is set * increased maximum memory size to match standard added security status handling/load/save added SELECT/QUIET handling more fine grained allocation routines and checks fix memset sizes * added "Listen NfcV Reader" to sniff traffic from reader to card * added correct description to delete menu * also added DSFID/AFI handling and locking * increase sniff log size * scale NfcV frequency a bit, add echo mode, fix signal level at the end * use symbolic modulated/unmodulated GPIO levels * honor AFI field, decrease verbosity and removed debug code * refactor defines for less namespace pollution by using NFCV_ prefixes * correct an oversight that original cards return an generic error when addressing outside block range * use inverse modulation, increasing readable range significantly * rework and better document nfc chip initialization * nfcv code review fixes * Disable accidentally left on signal debug gpio output * Improve NFCV Read/Info GUIs. Authored by @xMasterX, committed by @nvx * Fix crash that occurs when you exit from NFCV emulation and start it again. Authored by @xMasterX, committed by @nvx * Remove delay from emulation loop. This improves compatibility when the reader is Android. * Lib: digital signal debug output pin info Co-authored-by: Tiernan Messmer Co-authored-by: MX <10697207+xMasterX@users.noreply.github.com> Co-authored-by: gornekich Co-authored-by: あく * [FL-3351] github: re-enabled f18 build (#2743) * github: re-enabled f18 build * scripts: storage: better transfer logging * Fix PVS warnings Co-authored-by: あく * Scripts: WiFi board updater (#2625) * Scripts: wifi updater * WiFi board updater: lint, process download error * WiFi board updater: auto cleanup temp dir * Scripts: fix server address * [FL-3267] ble: refactored bt gatt characteristics setup (#2587) * ble: refactored bt gatt characteristics setup * ble: naming fixes, small optimizations * ble: expanded bitfields; fixed pvs warnings * ble: fixed pvs warnings for real * ble: using FlipperGattCharacteristicDataPropsFixed for char[] props * ble: removed flipper_gatt_characteristic_props_const_char * ble: gatt: naming changes * ble: gatt: fixed device_info service constant attrs sizes * ble: gatt: copy descriptors to char instances; reworked hid chars to be callback-based; moved max size getter to callback with NULL data; added comments * ble: gatt: removed hid_svc_report_data_callback * ble: hid svc: better double loop idx naming * ble: hid svc: simplified hid_svc_update_info * ble: gatt: removed magic values; fixed type for HidSvcGattCharacteristicInfo * ble: gatt: moved long uuids to separate files Co-authored-by: gornekich Co-authored-by: あく * [FL-3359] github: added debugapps artifact; packaging resources per-target (#2750) * github: added debugapps artifact; packaging resources per-target * github: target name fixes * github: fixed path for debug apps * scripts: dist: removed lib stub artifact * scripts: fixed broken SDK * github: removed unused step * FuriHal: always clock SMPS from HSI (#2643) * FuriHal: always clock SMPS from HSI * FuriHal: add clock startup time check, ensure that we conform to core2 config value * FuriHal: set sleep mode to legacy if clock startup time is too high --------- Co-authored-by: hedger * Core2, SRAM2: provide safety gap (#2754) * Core2, SRAM2: use ob, provide safety gap * thread: comment about critical section and scheduler state * Services: simplify api (#2540) Co-authored-by: あく * weather_station: add oregon3 with THGR221 (#2748) Co-authored-by: hedger Co-authored-by: あく * [FL-3361] fbt: stable build dates (#2751) * scripts: using commit date for clean build timestamp; current day otherwise * scripts: version: Removing GIT_COMMIT_DATE from final data Co-authored-by: あく * [FL-3284] Fix reading Mifare Classic cards with unusual access conditions and fix emulation of unknown keys (#2620) * I was outplayed by the C programming language * Fix emulating empty keys as 0s * Add exceptions for Detect Reader * Sync api_symbols.csv for F18 * Outplayed by the C language [X2] Co-authored-by: Aleksandr Kutuzov * FuriHal: remove clock startup time tracking from clean builds (#2764) * furi_hal_nfc: fix rfalTransceiveBitsBlockingTx's 4th argument to bits count rather than bytes count (#2773) * [FL-3376] Fixed GATT attribute order (#2776) * hal: gatt: swapped rx/tx serial chars order * hal: gatt: reordered HID attrs to maintain previous order Co-authored-by: Aleksandr Kutuzov * Debug: sync apps on attach, makes it possible to debug already started app that has crashed (#2778) * [FL-2837][FL-3270] Loader refaptoring: second encounter (#2779) * Core: rename internal FlipperApplication to FlipperInternalApplication * FAP Loader: move load_name_and_icon to flipper_application library * Loader menu: rework api * View holder: move to gui service * Loader: simple "loading" worker * Loader: applications dialog * Loader: fapping * Update f18 api * Apps: remove fap_loader * Libs, flipper application: store args, rename thread allocation * Loader: error handling * Apps: use loader error handling * Loader: documentation * FBT: accomodate loader * Loader: do not raise gui error if loader is locked * Archive: accomodate loader * Loader: fix loading message * Flipper: drop some old dolphin legacy * Loader: generalize error construction Co-authored-by: Aleksandr Kutuzov * [FL-3373] Scroll acceleration (#2784) * Support for scroll acceleration * Revert keyboard acceleration * Add scroll acceleration to the text box * Remove redundant code from the file manager input handler * Archive: slightly better scrolling * Gui,Archive: final version of accelerated scrolling Co-authored-by: あく * fix: make `dialog_file_browser_set_basic_options` initialize all fields (#2756) * fix: make `dialog_file_browser_set_basic_options` initialize all fields * fix(GH-2756): use alternative test for `test_dialog_file_browser_set_basic_options_should_init_all_fields` Co-authored-by: Aleksandr Kutuzov * Fix M*LIB usage (#2762) * Fix M*LIB usage * Fix oplist definition of SubGhzFrequencyAnalyzerLogItem * Fix oplist definition of M_CSTR_DUP_OPLIST * Remove dependency of furi_string_utf8_decode to the internal definition of string_unicode_t * Replace obsolete macro M_IF_DEFAULT1 to M_DEFAULT_ARGS Co-authored-by: hedger Co-authored-by: あく * Actions: unit_test and updater timeouts (#2807) * added some extra timeouts, fixed duration of units run command and minor logging changes. No list_ports yet needed * increased timeouts * make pvs happy --------- Co-authored-by: doomwastaken Co-authored-by: SG * LF-RFID debug: make it work (#2793) Co-authored-by: あく * [FL-3386] Fast FAP Loader (#2790) * FBT: build and add FastFAP(tm) sections * Elf file: fast loading fap files. Really fast, like x15 times faster. * fastfap.py: cleanup unused imports * Toolchain: 23 version * Elf File: remove log messages * Scripts: fix file permissions * FBT: explicit interpreter for fastfap invocation Co-authored-by: あく * [FL-3388] NFC/RFID detector (#2795) * Field_Validation: add driver fild_validation_rfid * Field_Validation: add fild_validation_nfc * Field_Presence: added field validation functions to furi_hal_nfc * Field_Presence: added field validation functions to furi_hal_rfid * Field_Presence: add "NFC/RFID detector" app * Field_Presence: fix GUI "NFC/RFID detector" * NFC/RFID detector: add auto turn on backlight when field is detected * NFC/RFID detector: fix syntax errors * ApiSymbols: fix incorrect name * FuriHal: filed detect naming * FieldDetector: fix grammar Co-authored-by: Aleksandr Kutuzov * Fix furi_hal_bus related crashes in plugins (#2799) * Fix furi_hal_bus issues in plugins * Rework pwm is running check * ApiSymbols: update and sync targets Co-authored-by: あく * Fix fr-FR-mac keylayout (#2809) Co-authored-by: あく * Fix roll-over in file browser and archive (#2811) * Add Mitsubishi MSZ-AP25VGK universal ac remote (#2800) Co-authored-by: あく * Added Power Button for an unknown Sharp Model (#2787) Tested by me, i just asked if I can get the remote. Tested with the universal remote before and thought you would like to add the button data Co-authored-by: あく * NFC: Improvements to NFC Magic app (#2760) Ability to write gen1b tags (ignore 0x43) Ability to write gen1 7 byte UID tags Fix detection of non magic cards Co-authored-by: あく * Keynote with vertical layout (#2794) cherry pick from: * https://github.com/DarkFlippers/unleashed-firmware/pull/428/files * https://github.com/DarkFlippers/unleashed-firmware/pull/524/files Co-authored-by: * MX <10697207+xMasterX@users.noreply.github.com> * gid9798 <30450294+gid9798@users.noreply.github.com> Co-authored-by: MX <10697207+xMasterX@users.noreply.github.com> Co-authored-by: あく * SLIX2 emulation support / practical use for Dymo printers (#2783) * improve digital_signal for longer packets, also clean up code * added SLIX2 specific features like signature and unknown keys (for issue #2781), added WRITE_PASSWORD handling * fix NfcV AFI selection * when NFCV_CMD_READ_MULTI_BLOCK reads beyond memory end, return the maximum possible block's content * added SLIX2 reading * fix NXP SYSTEMINFO response check size * capture the first received password if none was set before * clear stored data before reading SLIX details renamed slix2_dump functions to slix2_read * display card block size values as decimal Co-authored-by: あく * NFC: Fix key invalidation logic (#2782) * NFC: Fix key invalidation logic * NFC: Fix crash in CLI with empty response * Fix incorrect key conversions * Proper call to nfc_util Co-authored-by: あく Co-authored-by: Astra * [FL-3211][FL-3212] Debug apps: speaker, uart_echo with baudrate (#2812) * Music player: move music_worker to library * Music player: drop cli * Debug: speaker debug app * Debug: baudrate arg in uart_echo app * Libs: add music_worker to api * Libs: add music_worker to targets linker_dependencies Co-authored-by: あく * increased timeouts (#2816) Co-authored-by: doomwastaken * Furi,FuriHal: various improvements (#2819) * Lib: adjust default contrast for ERC displays * Furi: various improvements in check module * Format Sources * FurHal: ble early hardfault detection --------- Co-authored-by: hedger * [FL-3375] SubGhz: add CC1101 module external (#2747) * SubGhz: add CC1101 Ext driver * SubGhz: move TIM2 -> TIM17 use cc1101_ext * FuriHal: SPI move channel DMA 3,4 -> 6.7 * Documentation: fix font * SubGhz: add work with SubGhz devices by link to device * SubGhz: add support switching external/internal cc1101 "subghz chat" * SubGhz: add support switching external/internal cc1101 "subghz tx" and "subghz rx" * SubGhz: add "Radio Settings" scene * SubGhz: add icon * SubGhz: add supported CC1101 external module in SubGhz app * SubGhz: fix check frequency supported radio device * SubGhz: fix clang-formatted * Sughz: move dirver CC1101_Ext to lib , compile cmd ./fbt launch_app APPSRC=radio_device_cc1101_ext * SubGhz: fix CLI * SubGhz: fix PVS * SubGhz: delete comments * SubGhz: fix unit_test * Format sources * Update api symbols and drivers targets * Drivers: find proper place for target option * SubGhz: external device connected method naming * Format sources * SubGhz: fix module selection menu, when external is not connected * SubGhz: fix furi_assert(device); * SubGhz: fix split h and c * SubGhz: furi_hal_subghz remove preset load function by name * SubGhz: deleted comments * Format Sources * SubGhz: add some consts and fix unit tests * Sync API Symbols Co-authored-by: Aleksandr Kutuzov * fix width of submenu items on Vertical orientation (#2306) * fix width of submenu items on vertical view * Gui: slightly better canvas width handling in submenu * Gui: remove unused include Co-authored-by: あく * SubGHz: properly working with missing external driver (#2821) * all: revert incorrect changes * nfc app: apply correct changes * nfc: build fixes --------- Co-authored-by: end-me-please <90796271+end-me-please@users.noreply.github.com> Co-authored-by: hedger Co-authored-by: あく Co-authored-by: Max Andreev Co-authored-by: MX <10697207+xMasterX@users.noreply.github.com> Co-authored-by: Yukai Li Co-authored-by: Sergey Gavrilov Co-authored-by: hedger Co-authored-by: Félix Legrelle Co-authored-by: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Co-authored-by: Nikolay Minaylov Co-authored-by: minchogaydarov <134236905+minchogaydarov@users.noreply.github.com> Co-authored-by: Avery <30564701+nullableVoidPtr@users.noreply.github.com> Co-authored-by: technobulb <84107091+technobulb@users.noreply.github.com> Co-authored-by: Sebastian Mauer Co-authored-by: micolous Co-authored-by: Georgii Surkov Co-authored-by: Skorpionm <85568270+Skorpionm@users.noreply.github.com> Co-authored-by: AloneLiberty <111039319+AloneLiberty@users.noreply.github.com> Co-authored-by: Zoë Prosvetova <109866245+ZoeMeetAgain@users.noreply.github.com> Co-authored-by: Astra <93453568+Astrrra@users.noreply.github.com> Co-authored-by: DEXV <89728480+DXVVAY@users.noreply.github.com> Co-authored-by: glebmashanov <65850300+glebmashanov@users.noreply.github.com> Co-authored-by: g3gg0.de Co-authored-by: Tiernan Messmer Co-authored-by: clashlab Co-authored-by: Leopold Co-authored-by: Petr Portnov | PROgrm_JARvis Co-authored-by: PpHd Co-authored-by: Konstantin Volkov <72250702+doomwastaken@users.noreply.github.com> Co-authored-by: doomwastaken Co-authored-by: Patrick Kilter Co-authored-by: Dmitry Zinin Co-authored-by: Astra Co-authored-by: Slavik Nychkalo --- .github/workflows/unit_tests.yml | 5 +- .github/workflows/updater_test.yml | 2 + CODING_STYLE.md | 2 +- applications/ReadMe.md | 1 - applications/debug/application.fam | 1 + applications/debug/crash_test/application.fam | 10 + applications/debug/crash_test/crash_test.c | 128 +++ .../scenes/lfrfid_debug_app_scene_tune.c | 7 + .../views/lfrfid_debug_view_tune.c | 44 +- .../views/lfrfid_debug_view_tune.h | 5 + .../debug/speaker_debug/application.fam | 11 + .../debug/speaker_debug/speaker_debug.c | 120 +++ applications/debug/uart_echo/uart_echo.c | 20 +- .../dialogs/dialogs_file_browser_options.c | 32 + applications/debug/unit_tests/nfc/nfc_test.c | 6 + .../debug/unit_tests/subghz/subghz_test.c | 11 +- applications/debug/unit_tests/test_index.c | 3 + applications/drivers/application.fam | 6 + applications/drivers/subghz/application.fam | 8 + .../drivers/subghz/cc1101_ext/cc1101_ext.c | 765 ++++++++++++++++++ .../drivers/subghz/cc1101_ext/cc1101_ext.h | 206 +++++ .../cc1101_ext/cc1101_ext_interconnect.c | 110 +++ .../cc1101_ext/cc1101_ext_interconnect.h | 8 + .../helpers/avr_isp_worker_rw.c | 19 +- .../external/hid_app/assets/Space_60x18.png | Bin 0 -> 2871 bytes applications/external/hid_app/hid.c | 12 + .../external/hid_app/views/hid_keynote.c | 98 +++ .../external/hid_app/views/hid_keynote.h | 2 + applications/external/mfkey32/mfkey32.c | 8 +- .../external/music_player/application.fam | 10 +- .../external/music_player/music_player.c | 27 +- .../external/music_player/music_player_cli.c | 48 -- .../music_player/music_player_worker.h | 38 - .../external/nfc_magic/lib/magic/magic.h | 15 - applications/external/nfc_magic/nfc_magic_i.h | 1 + .../external/nfc_magic/nfc_magic_worker.c | 66 +- .../scenes/nfc_magic_scene_file_select.c | 14 +- .../scenes/nfc_magic_scene_not_magic.c | 3 +- .../nfc_rfid_detector/application.fam | 13 + .../helpers/nfc_rfid_detector_event.h | 7 + .../helpers/nfc_rfid_detector_types.h | 15 + .../images/Modern_reader_18x34.png | Bin 0 -> 3670 bytes .../images/Move_flipper_26x39.png | Bin 0 -> 3698 bytes .../images/NFC_detect_45x30.png | Bin 0 -> 168 bytes .../images/Rfid_detect_45x30.png | Bin 0 -> 158 bytes .../nfc_rfid_detector_10px.png | Bin 0 -> 124 bytes .../nfc_rfid_detector/nfc_rfid_detector_app.c | 108 +++ .../nfc_rfid_detector_app_i.c | 40 + .../nfc_rfid_detector_app_i.h | 30 + .../scenes/nfc_rfid_detector_scene.c | 31 + .../scenes/nfc_rfid_detector_scene.h | 29 + .../scenes/nfc_rfid_detector_scene_about.c | 69 ++ .../scenes/nfc_rfid_detector_scene_config.h | 3 + .../nfc_rfid_detector_scene_field_presence.c | 60 ++ .../scenes/nfc_rfid_detector_scene_start.c | 58 ++ .../nfc_rfid_detector_view_field_presence.c | 164 ++++ .../nfc_rfid_detector_view_field_presence.h | 19 + .../external/picopass/views/dict_attack.h | 2 +- .../scenes/signal_gen_scene_pwm.c | 27 +- applications/main/application.fam | 1 - .../main/archive/helpers/archive_browser.c | 4 +- .../archive/scenes/archive_scene_browser.c | 57 +- .../main/archive/views/archive_browser_view.c | 37 +- .../main/archive/views/archive_browser_view.h | 2 + applications/main/fap_loader/application.fam | 15 - applications/main/fap_loader/fap_loader_app.c | 216 ----- applications/main/fap_loader/fap_loader_app.h | 27 - applications/main/nfc/nfc_cli.c | 4 + applications/main/nfc_old/application.fam | 4 +- .../main/nfc_old/{nfc_app.c => nfc.c} | 34 +- applications/main/nfc_old/nfc.h | 3 + applications/main/nfc_old/nfc_app.h | 3 - applications/main/nfc_old/nfc_cli.c | 23 +- .../main/nfc_old/{nfc_app_i.h => nfc_i.h} | 20 +- .../main/nfc_old/scenes/nfc_scene_config.h | 7 + .../main/nfc_old/scenes/nfc_scene_debug.c | 10 +- .../main/nfc_old/scenes/nfc_scene_delete.c | 17 +- .../nfc_old/scenes/nfc_scene_delete_success.c | 10 +- .../nfc_old/scenes/nfc_scene_detect_reader.c | 12 +- .../nfc_old/scenes/nfc_scene_device_info.c | 10 +- .../nfc_old/scenes/nfc_scene_dict_not_found.c | 10 +- .../scenes/nfc_scene_emulate_apdu_sequence.c | 6 +- .../nfc_old/scenes/nfc_scene_emulate_uid.c | 16 +- .../main/nfc_old/scenes/nfc_scene_emv_menu.c | 10 +- .../scenes/nfc_scene_emv_read_success.c | 10 +- .../nfc_old/scenes/nfc_scene_exit_confirm.c | 10 +- .../nfc_old/scenes/nfc_scene_extra_actions.c | 30 +- .../main/nfc_old/scenes/nfc_scene_field.c | 6 +- .../nfc_old/scenes/nfc_scene_file_select.c | 4 +- .../nfc_old/scenes/nfc_scene_generate_info.c | 10 +- .../scenes/nfc_scene_mf_classic_data.c | 20 +- .../scenes/nfc_scene_mf_classic_dict_attack.c | 22 +- .../scenes/nfc_scene_mf_classic_emulate.c | 10 +- .../scenes/nfc_scene_mf_classic_keys.c | 10 +- .../scenes/nfc_scene_mf_classic_keys_add.c | 10 +- .../scenes/nfc_scene_mf_classic_keys_delete.c | 10 +- .../scenes/nfc_scene_mf_classic_keys_list.c | 14 +- ...nfc_scene_mf_classic_keys_warn_duplicate.c | 10 +- .../scenes/nfc_scene_mf_classic_menu.c | 18 +- .../nfc_scene_mf_classic_read_success.c | 14 +- .../scenes/nfc_scene_mf_classic_update.c | 12 +- .../nfc_scene_mf_classic_update_success.c | 10 +- .../scenes/nfc_scene_mf_classic_write.c | 12 +- .../scenes/nfc_scene_mf_classic_write_fail.c | 10 +- .../nfc_scene_mf_classic_write_success.c | 10 +- .../scenes/nfc_scene_mf_classic_wrong_card.c | 10 +- .../nfc_old/scenes/nfc_scene_mf_desfire_app.c | 14 +- .../scenes/nfc_scene_mf_desfire_data.c | 10 +- .../scenes/nfc_scene_mf_desfire_menu.c | 14 +- .../nfc_scene_mf_desfire_read_success.c | 69 +- .../scenes/nfc_scene_mf_ultralight_data.c | 6 +- .../scenes/nfc_scene_mf_ultralight_emulate.c | 10 +- .../nfc_scene_mf_ultralight_key_input.c | 10 +- .../scenes/nfc_scene_mf_ultralight_menu.c | 30 +- .../nfc_scene_mf_ultralight_read_auth.c | 12 +- ...nfc_scene_mf_ultralight_read_auth_result.c | 10 +- .../nfc_scene_mf_ultralight_read_success.c | 10 +- .../nfc_scene_mf_ultralight_unlock_auto.c | 10 +- .../nfc_scene_mf_ultralight_unlock_menu.c | 10 +- .../nfc_scene_mf_ultralight_unlock_warn.c | 14 +- .../nfc_old/scenes/nfc_scene_mfkey_complete.c | 10 +- .../scenes/nfc_scene_mfkey_nonces_info.c | 10 +- .../nfc_old/scenes/nfc_scene_nfc_data_info.c | 175 ++-- .../main/nfc_old/scenes/nfc_scene_nfca_menu.c | 14 +- .../scenes/nfc_scene_nfca_read_success.c | 10 +- .../scenes/nfc_scene_nfcv_read_success.c | 6 +- .../main/nfc_old/scenes/nfc_scene_read.c | 17 +- .../scenes/nfc_scene_read_card_success.c | 10 +- .../nfc_old/scenes/nfc_scene_read_card_type.c | 22 +- .../scenes/nfc_scene_restore_original.c | 10 +- .../nfc_scene_restore_original_confirm.c | 10 +- .../nfc_old/scenes/nfc_scene_retry_confirm.c | 10 +- .../main/nfc_old/scenes/nfc_scene_rpc.c | 10 +- .../main/nfc_old/scenes/nfc_scene_save_name.c | 14 +- .../nfc_old/scenes/nfc_scene_save_success.c | 10 +- .../nfc_old/scenes/nfc_scene_saved_menu.c | 24 +- .../main/nfc_old/scenes/nfc_scene_set_atqa.c | 10 +- .../main/nfc_old/scenes/nfc_scene_set_sak.c | 10 +- .../main/nfc_old/scenes/nfc_scene_set_type.c | 10 +- .../main/nfc_old/scenes/nfc_scene_set_uid.c | 10 +- .../main/nfc_old/scenes/nfc_scene_start.c | 14 +- applications/main/nfc_old/views/dict_attack.c | 2 +- applications/main/nfc_old/views/dict_attack.h | 2 +- .../main/subghz/helpers/subghz_chat.c | 7 +- .../main/subghz/helpers/subghz_chat.h | 6 +- ...subghz_frequency_analyzer_log_item_array.h | 9 +- .../subghz/helpers/subghz_threshold_rssi.c | 3 +- .../subghz/helpers/subghz_threshold_rssi.h | 3 +- .../main/subghz/helpers/subghz_txrx.c | 167 +++- .../main/subghz/helpers/subghz_txrx.h | 46 ++ .../main/subghz/helpers/subghz_txrx_i.h | 2 + .../main/subghz/helpers/subghz_types.h | 7 + .../main/subghz/scenes/subghz_scene_config.h | 1 + .../scenes/subghz_scene_radio_setting.c | 70 ++ .../subghz/scenes/subghz_scene_read_raw.c | 11 +- .../subghz/scenes/subghz_scene_receiver.c | 6 +- .../subghz/scenes/subghz_scene_save_name.c | 3 +- .../main/subghz/scenes/subghz_scene_start.c | 14 +- .../subghz/scenes/subghz_scene_transmitter.c | 2 + applications/main/subghz/subghz_cli.c | 215 +++-- applications/main/subghz/subghz_i.c | 5 +- applications/main/subghz/views/receiver.c | 44 +- applications/main/subghz/views/receiver.h | 4 + .../subghz/views/subghz_frequency_analyzer.c | 3 +- .../main/subghz/views/subghz_read_raw.c | 20 +- .../main/subghz/views/subghz_read_raw.h | 5 + .../main/subghz/views/subghz_test_carrier.c | 3 +- .../main/subghz/views/subghz_test_packet.c | 3 +- .../main/subghz/views/subghz_test_static.c | 3 +- applications/main/subghz/views/transmitter.c | 23 +- applications/main/subghz/views/transmitter.h | 5 + applications/services/applications.h | 31 +- applications/services/desktop/desktop.c | 1 + .../desktop/scenes/desktop_scene_main.c | 46 +- applications/services/dialogs/dialogs.c | 3 +- applications/services/dialogs/dialogs.h | 9 +- applications/services/dialogs/dialogs_i.h | 2 +- .../services/gui/modules/file_browser.c | 39 +- applications/services/gui/modules/submenu.c | 2 +- applications/services/gui/modules/text_box.c | 70 +- .../services/{dialogs => gui}/view_holder.c | 0 .../services/{dialogs => gui}/view_holder.h | 0 applications/services/loader/loader.c | 311 +++++-- applications/services/loader/loader.h | 52 +- .../services/loader/loader_applications.c | 146 ++++ .../services/loader/loader_applications.h | 16 + applications/services/loader/loader_cli.c | 18 +- applications/services/loader/loader_i.h | 7 +- applications/services/loader/loader_menu.c | 189 +++-- applications/services/loader/loader_menu.h | 16 +- applications/services/rpc/rpc_app.c | 2 +- .../scenes/desktop_settings_scene_favorite.c | 3 - .../storage_move_to_sd/storage_move_to_sd.c | 2 +- applications/system/updater/cli/updater_cli.c | 2 +- .../icons/SubGhz/External_antenna_20x12.png | Bin 0 -> 990 bytes .../icons/SubGhz/Internal_antenna_20x12.png | Bin 0 -> 994 bytes assets/icons/SubGhz/Scanning_123x52.png | Bin 1690 -> 0 bytes assets/icons/SubGhz/Scanning_short_96x52.png | Bin 0 -> 1388 bytes .../badusb/assets/layouts/fr-FR-mac.kl | Bin 256 -> 256 bytes assets/resources/infrared/assets/ac.ir | 37 + assets/resources/infrared/assets/tv.ir | 6 + documentation/FuriHalBus.md | 16 +- firmware/targets/f18/api_symbols.csv | 26 +- firmware/targets/f18/target.json | 1 + firmware/targets/f7/api_symbols.csv | 101 ++- firmware/targets/f7/furi_hal/furi_hal_bt.c | 58 +- firmware/targets/f7/furi_hal/furi_hal_nfc.c | 14 + firmware/targets/f7/furi_hal/furi_hal_nfc.h | 4 + firmware/targets/f7/furi_hal/furi_hal_pwm.c | 9 + firmware/targets/f7/furi_hal/furi_hal_pwm.h | 8 + firmware/targets/f7/furi_hal/furi_hal_rfid.c | 159 ++++ firmware/targets/f7/furi_hal/furi_hal_rfid.h | 14 + firmware/targets/f7/furi_hal/furi_hal_spi.c | 28 +- .../targets/f7/furi_hal/furi_hal_subghz.c | 65 +- .../targets/f7/furi_hal/furi_hal_subghz.h | 51 +- .../f7/furi_hal/furi_hal_subghz_configs.h | 314 ------- .../f7/platform_specific/intrinsic_export.h | 2 + firmware/targets/f7/target.json | 1 + furi/core/check.c | 6 +- furi/core/check.h | 47 +- furi/core/string.c | 4 +- furi/core/string.h | 44 +- lib/SConscript | 2 + lib/digital_signal/digital_signal.c | 181 +++-- .../api_hashtable/api_hashtable.cpp | 19 +- .../api_hashtable/api_hashtable.h | 12 +- .../elf/elf_api_interface.h | 2 +- lib/flipper_application/elf/elf_file.c | 126 ++- lib/flipper_application/elf/elf_file_i.h | 10 +- lib/flipper_application/flipper_application.c | 48 +- lib/flipper_application/flipper_application.h | 21 +- .../plugins/composite_resolver.c | 4 +- lib/music_worker/SConscript | 27 + .../music_worker/music_worker.c | 69 +- lib/music_worker/music_worker.h | 37 + lib/subghz/SConscript | 1 + lib/subghz/devices/cc1101_configs.c | 431 ++++++++++ lib/subghz/devices/cc1101_configs.h | 18 + .../cc1101_int/cc1101_int_interconnect.c | 96 +++ .../cc1101_int/cc1101_int_interconnect.h | 8 + lib/subghz/devices/device_registry.h | 13 + lib/subghz/devices/devices.c | 236 ++++++ lib/subghz/devices/devices.h | 52 ++ lib/subghz/devices/preset.h | 13 + lib/subghz/devices/registry.c | 76 ++ lib/subghz/devices/registry.h | 40 + lib/subghz/devices/types.h | 91 +++ lib/subghz/protocols/raw.c | 25 +- lib/subghz/protocols/raw.h | 6 +- lib/subghz/subghz_file_encoder_worker.c | 13 +- lib/subghz/subghz_file_encoder_worker.h | 7 +- lib/subghz/subghz_setting.c | 32 +- lib/subghz/subghz_tx_rx_worker.c | 65 +- lib/subghz/subghz_tx_rx_worker.h | 7 +- lib/subghz/types.h | 6 + lib/toolbox/m_cstr_dup.h | 19 +- lib/u8g2/u8g2_glue.c | 2 +- scripts/distfap.py | 4 +- scripts/fastfap.py | 169 ++++ scripts/fbt/appmanifest.py | 22 +- scripts/fbt/sdk/collector.py | 8 +- scripts/fbt/sdk/hashes.py | 5 + scripts/fbt_tools/fbt_extapps.py | 15 +- scripts/fwsize.py | 0 scripts/get_env.py | 0 scripts/runfap.py | 2 +- scripts/sconsdist.py | 0 scripts/selfupdate.py | 0 scripts/slideshow.py | 0 scripts/testing/await_flipper.py | 5 +- scripts/testing/units.py | 4 +- scripts/toolchain/fbtenv.cmd | 2 +- scripts/toolchain/fbtenv.sh | 2 +- scripts/version.py | 0 site_scons/commandline.scons | 1 + 275 files changed, 6524 insertions(+), 2228 deletions(-) create mode 100644 applications/debug/crash_test/application.fam create mode 100644 applications/debug/crash_test/crash_test.c create mode 100644 applications/debug/speaker_debug/application.fam create mode 100644 applications/debug/speaker_debug/speaker_debug.c create mode 100644 applications/debug/unit_tests/dialogs/dialogs_file_browser_options.c create mode 100644 applications/drivers/application.fam create mode 100644 applications/drivers/subghz/application.fam create mode 100644 applications/drivers/subghz/cc1101_ext/cc1101_ext.c create mode 100644 applications/drivers/subghz/cc1101_ext/cc1101_ext.h create mode 100644 applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.c create mode 100644 applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h create mode 100644 applications/external/hid_app/assets/Space_60x18.png delete mode 100644 applications/external/music_player/music_player_cli.c delete mode 100644 applications/external/music_player/music_player_worker.h delete mode 100644 applications/external/nfc_magic/lib/magic/magic.h create mode 100644 applications/external/nfc_rfid_detector/application.fam create mode 100644 applications/external/nfc_rfid_detector/helpers/nfc_rfid_detector_event.h create mode 100644 applications/external/nfc_rfid_detector/helpers/nfc_rfid_detector_types.h create mode 100644 applications/external/nfc_rfid_detector/images/Modern_reader_18x34.png create mode 100644 applications/external/nfc_rfid_detector/images/Move_flipper_26x39.png create mode 100644 applications/external/nfc_rfid_detector/images/NFC_detect_45x30.png create mode 100644 applications/external/nfc_rfid_detector/images/Rfid_detect_45x30.png create mode 100644 applications/external/nfc_rfid_detector/nfc_rfid_detector_10px.png create mode 100644 applications/external/nfc_rfid_detector/nfc_rfid_detector_app.c create mode 100644 applications/external/nfc_rfid_detector/nfc_rfid_detector_app_i.c create mode 100644 applications/external/nfc_rfid_detector/nfc_rfid_detector_app_i.h create mode 100644 applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene.c create mode 100644 applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene.h create mode 100644 applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene_about.c create mode 100644 applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene_config.h create mode 100644 applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene_field_presence.c create mode 100644 applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene_start.c create mode 100644 applications/external/nfc_rfid_detector/views/nfc_rfid_detector_view_field_presence.c create mode 100644 applications/external/nfc_rfid_detector/views/nfc_rfid_detector_view_field_presence.h delete mode 100644 applications/main/fap_loader/application.fam delete mode 100644 applications/main/fap_loader/fap_loader_app.c delete mode 100644 applications/main/fap_loader/fap_loader_app.h rename applications/main/nfc_old/{nfc_app.c => nfc.c} (94%) create mode 100644 applications/main/nfc_old/nfc.h delete mode 100644 applications/main/nfc_old/nfc_app.h rename applications/main/nfc_old/{nfc_app_i.h => nfc_i.h} (86%) create mode 100644 applications/main/subghz/scenes/subghz_scene_radio_setting.c rename applications/services/{dialogs => gui}/view_holder.c (100%) rename applications/services/{dialogs => gui}/view_holder.h (100%) create mode 100644 applications/services/loader/loader_applications.c create mode 100644 applications/services/loader/loader_applications.h create mode 100644 assets/icons/SubGhz/External_antenna_20x12.png create mode 100644 assets/icons/SubGhz/Internal_antenna_20x12.png delete mode 100644 assets/icons/SubGhz/Scanning_123x52.png create mode 100644 assets/icons/SubGhz/Scanning_short_96x52.png delete mode 100644 firmware/targets/f7/furi_hal/furi_hal_subghz_configs.h create mode 100644 lib/music_worker/SConscript rename applications/external/music_player/music_player_worker.c => lib/music_worker/music_worker.c (85%) create mode 100644 lib/music_worker/music_worker.h create mode 100644 lib/subghz/devices/cc1101_configs.c create mode 100644 lib/subghz/devices/cc1101_configs.h create mode 100644 lib/subghz/devices/cc1101_int/cc1101_int_interconnect.c create mode 100644 lib/subghz/devices/cc1101_int/cc1101_int_interconnect.h create mode 100644 lib/subghz/devices/device_registry.h create mode 100644 lib/subghz/devices/devices.c create mode 100644 lib/subghz/devices/devices.h create mode 100644 lib/subghz/devices/preset.h create mode 100644 lib/subghz/devices/registry.c create mode 100644 lib/subghz/devices/registry.h create mode 100644 lib/subghz/devices/types.h mode change 100644 => 100755 scripts/distfap.py create mode 100755 scripts/fastfap.py create mode 100644 scripts/fbt/sdk/hashes.py mode change 100644 => 100755 scripts/fwsize.py mode change 100644 => 100755 scripts/get_env.py mode change 100644 => 100755 scripts/runfap.py mode change 100644 => 100755 scripts/sconsdist.py mode change 100644 => 100755 scripts/selfupdate.py mode change 100644 => 100755 scripts/slideshow.py mode change 100644 => 100755 scripts/version.py diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index 81f0e0d050e7..9c6c6b2db6f0 100644 --- a/.github/workflows/unit_tests.yml +++ b/.github/workflows/unit_tests.yml @@ -29,12 +29,14 @@ jobs: - name: 'Flash unit tests firmware' id: flashing if: success() + timeout-minutes: 10 run: | ./fbt flash OPENOCD_ADAPTER_SERIAL=2A0906016415303030303032 FIRMWARE_APP_SET=unit_tests FORCE=1 - name: 'Wait for flipper and format ext' id: format_ext if: steps.flashing.outcome == 'success' + timeout-minutes: 5 run: | source scripts/toolchain/fbtenv.sh python3 scripts/testing/await_flipper.py ${{steps.device.outputs.flipper}} @@ -43,6 +45,7 @@ jobs: - name: 'Copy assets and unit data, reboot and wait for flipper' id: copy if: steps.format_ext.outcome == 'success' + timeout-minutes: 5 run: | source scripts/toolchain/fbtenv.sh python3 scripts/storage.py -p ${{steps.device.outputs.flipper}} -f send assets/resources /ext @@ -53,7 +56,7 @@ jobs: - name: 'Run units and validate results' id: run_units if: steps.copy.outcome == 'success' - timeout-minutes: 2.5 + timeout-minutes: 7 run: | source scripts/toolchain/fbtenv.sh python3 scripts/testing/units.py ${{steps.device.outputs.flipper}} diff --git a/.github/workflows/updater_test.yml b/.github/workflows/updater_test.yml index bd837297974c..27a181c46120 100644 --- a/.github/workflows/updater_test.yml +++ b/.github/workflows/updater_test.yml @@ -30,6 +30,7 @@ jobs: - name: 'Flashing target firmware' id: first_full_flash + timeout-minutes: 10 run: | source scripts/toolchain/fbtenv.sh ./fbt flash_usb_full PORT=${{steps.device.outputs.flipper}} FORCE=1 @@ -37,6 +38,7 @@ jobs: - name: 'Validating updater' id: second_full_flash + timeout-minutes: 10 if: success() run: | source scripts/toolchain/fbtenv.sh diff --git a/CODING_STYLE.md b/CODING_STYLE.md index c62009eff5fd..002c67f246ae 100644 --- a/CODING_STYLE.md +++ b/CODING_STYLE.md @@ -48,7 +48,7 @@ Almost everything in flipper firmware is built around this concept. # C coding style - Tab is 4 spaces -- Use `fbt format` to reformat source code and check style guide before commit +- Use `./fbt format` to reformat source code and check style guide before commit ## Naming diff --git a/applications/ReadMe.md b/applications/ReadMe.md index e50d8e46a5f7..10e54ce22573 100644 --- a/applications/ReadMe.md +++ b/applications/ReadMe.md @@ -26,7 +26,6 @@ Applications for main Flipper menu. - `archive` - Archive and file manager - `bad_usb` - Bad USB application -- `fap_loader` - External applications loader - `gpio` - GPIO application: includes USART bridge and GPIO control - `ibutton` - iButton application, onewire keys and more - `infrared` - Infrared application, controls your IR devices diff --git a/applications/debug/application.fam b/applications/debug/application.fam index a33b3693dfea..cdbf8fe18b6c 100644 --- a/applications/debug/application.fam +++ b/applications/debug/application.fam @@ -12,5 +12,6 @@ App( "display_test", "text_box_test", "file_browser_test", + "speaker_debug", ], ) diff --git a/applications/debug/crash_test/application.fam b/applications/debug/crash_test/application.fam new file mode 100644 index 000000000000..55f62f86d89f --- /dev/null +++ b/applications/debug/crash_test/application.fam @@ -0,0 +1,10 @@ +App( + appid="crash_test", + name="Crash Test", + apptype=FlipperAppType.DEBUG, + entry_point="crash_test_app", + cdefines=["APP_CRASH_TEST"], + requires=["gui"], + stack_size=1 * 1024, + fap_category="Debug", +) diff --git a/applications/debug/crash_test/crash_test.c b/applications/debug/crash_test/crash_test.c new file mode 100644 index 000000000000..92f1668be9ff --- /dev/null +++ b/applications/debug/crash_test/crash_test.c @@ -0,0 +1,128 @@ +#include +#include + +#include +#include +#include + +#define TAG "CrashTest" + +typedef struct { + Gui* gui; + ViewDispatcher* view_dispatcher; + Submenu* submenu; +} CrashTest; + +typedef enum { + CrashTestViewSubmenu, +} CrashTestView; + +typedef enum { + CrashTestSubmenuCheck, + CrashTestSubmenuCheckMessage, + CrashTestSubmenuAssert, + CrashTestSubmenuAssertMessage, + CrashTestSubmenuCrash, + CrashTestSubmenuHalt, +} CrashTestSubmenu; + +static void crash_test_submenu_callback(void* context, uint32_t index) { + CrashTest* instance = (CrashTest*)context; + UNUSED(instance); + + switch(index) { + case CrashTestSubmenuCheck: + furi_check(false); + break; + case CrashTestSubmenuCheckMessage: + furi_check(false, "Crash test: furi_check with message"); + break; + case CrashTestSubmenuAssert: + furi_assert(false); + break; + case CrashTestSubmenuAssertMessage: + furi_assert(false, "Crash test: furi_assert with message"); + break; + case CrashTestSubmenuCrash: + furi_crash("Crash test: furi_crash"); + break; + case CrashTestSubmenuHalt: + furi_halt("Crash test: furi_halt"); + break; + default: + furi_crash("Programming error"); + } +} + +static uint32_t crash_test_exit_callback(void* context) { + UNUSED(context); + return VIEW_NONE; +} + +CrashTest* crash_test_alloc() { + CrashTest* instance = malloc(sizeof(CrashTest)); + + View* view = NULL; + + instance->gui = furi_record_open(RECORD_GUI); + instance->view_dispatcher = view_dispatcher_alloc(); + view_dispatcher_enable_queue(instance->view_dispatcher); + view_dispatcher_attach_to_gui( + instance->view_dispatcher, instance->gui, ViewDispatcherTypeFullscreen); + + // Menu + instance->submenu = submenu_alloc(); + view = submenu_get_view(instance->submenu); + view_set_previous_callback(view, crash_test_exit_callback); + view_dispatcher_add_view(instance->view_dispatcher, CrashTestViewSubmenu, view); + submenu_add_item( + instance->submenu, "Check", CrashTestSubmenuCheck, crash_test_submenu_callback, instance); + submenu_add_item( + instance->submenu, + "Check with message", + CrashTestSubmenuCheckMessage, + crash_test_submenu_callback, + instance); + submenu_add_item( + instance->submenu, "Assert", CrashTestSubmenuAssert, crash_test_submenu_callback, instance); + submenu_add_item( + instance->submenu, + "Assert with message", + CrashTestSubmenuAssertMessage, + crash_test_submenu_callback, + instance); + submenu_add_item( + instance->submenu, "Crash", CrashTestSubmenuCrash, crash_test_submenu_callback, instance); + submenu_add_item( + instance->submenu, "Halt", CrashTestSubmenuHalt, crash_test_submenu_callback, instance); + + return instance; +} + +void crash_test_free(CrashTest* instance) { + view_dispatcher_remove_view(instance->view_dispatcher, CrashTestViewSubmenu); + submenu_free(instance->submenu); + + view_dispatcher_free(instance->view_dispatcher); + furi_record_close(RECORD_GUI); + + free(instance); +} + +int32_t crash_test_run(CrashTest* instance) { + view_dispatcher_switch_to_view(instance->view_dispatcher, CrashTestViewSubmenu); + view_dispatcher_run(instance->view_dispatcher); + return 0; +} + +int32_t crash_test_app(void* p) { + UNUSED(p); + + CrashTest* instance = crash_test_alloc(); + + int32_t ret = crash_test_run(instance); + + crash_test_free(instance); + + return ret; +} diff --git a/applications/debug/lfrfid_debug/scenes/lfrfid_debug_app_scene_tune.c b/applications/debug/lfrfid_debug/scenes/lfrfid_debug_app_scene_tune.c index 74c53ae6d485..ac2e2b806116 100644 --- a/applications/debug/lfrfid_debug/scenes/lfrfid_debug_app_scene_tune.c +++ b/applications/debug/lfrfid_debug/scenes/lfrfid_debug_app_scene_tune.c @@ -6,6 +6,11 @@ static void comparator_trigger_callback(bool level, void* comp_ctx) { furi_hal_gpio_write(&gpio_ext_pa7, !level); } +void lfrfid_debug_view_tune_callback(void* context) { + LfRfidDebug* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, 0xBA); +} + void lfrfid_debug_scene_tune_on_enter(void* context) { LfRfidDebug* app = context; @@ -16,6 +21,8 @@ void lfrfid_debug_scene_tune_on_enter(void* context) { furi_hal_rfid_tim_read_start(125000, 0.5); + lfrfid_debug_view_tune_set_callback(app->tune_view, lfrfid_debug_view_tune_callback, app); + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidDebugViewTune); } diff --git a/applications/debug/lfrfid_debug/views/lfrfid_debug_view_tune.c b/applications/debug/lfrfid_debug/views/lfrfid_debug_view_tune.c index fd221c4e9d36..9e48a7e27fec 100644 --- a/applications/debug/lfrfid_debug/views/lfrfid_debug_view_tune.c +++ b/applications/debug/lfrfid_debug/views/lfrfid_debug_view_tune.c @@ -13,6 +13,8 @@ typedef struct { uint32_t ARR; uint32_t CCR; int pos; + void (*update_callback)(void* context); + void* update_context; } LfRfidTuneViewModel; static void lfrfid_debug_view_tune_draw_callback(Canvas* canvas, void* _model) { @@ -151,6 +153,18 @@ static bool lfrfid_debug_view_tune_input_callback(InputEvent* event, void* conte consumed = false; break; } + + if(event->key == InputKeyLeft || event->key == InputKeyRight) { + with_view_model( + tune_view->view, + LfRfidTuneViewModel * model, + { + if(model->update_callback) { + model->update_callback(model->update_context); + } + }, + false); + } } return consumed; @@ -161,19 +175,7 @@ LfRfidTuneView* lfrfid_debug_view_tune_alloc() { tune_view->view = view_alloc(); view_set_context(tune_view->view, tune_view); view_allocate_model(tune_view->view, ViewModelTypeLocking, sizeof(LfRfidTuneViewModel)); - - with_view_model( - tune_view->view, - LfRfidTuneViewModel * model, - { - model->dirty = true; - model->fine = false; - model->ARR = 511; - model->CCR = 255; - model->pos = 0; - }, - true); - + lfrfid_debug_view_tune_clean(tune_view); view_set_draw_callback(tune_view->view, lfrfid_debug_view_tune_draw_callback); view_set_input_callback(tune_view->view, lfrfid_debug_view_tune_input_callback); @@ -199,6 +201,8 @@ void lfrfid_debug_view_tune_clean(LfRfidTuneView* tune_view) { model->ARR = 511; model->CCR = 255; model->pos = 0; + model->update_callback = NULL; + model->update_context = NULL; }, true); } @@ -232,3 +236,17 @@ uint32_t lfrfid_debug_view_tune_get_ccr(LfRfidTuneView* tune_view) { return result; } + +void lfrfid_debug_view_tune_set_callback( + LfRfidTuneView* tune_view, + void (*callback)(void* context), + void* context) { + with_view_model( + tune_view->view, + LfRfidTuneViewModel * model, + { + model->update_callback = callback; + model->update_context = context; + }, + false); +} diff --git a/applications/debug/lfrfid_debug/views/lfrfid_debug_view_tune.h b/applications/debug/lfrfid_debug/views/lfrfid_debug_view_tune.h index fd6d0b1fe9a5..be54b63f9a81 100644 --- a/applications/debug/lfrfid_debug/views/lfrfid_debug_view_tune.h +++ b/applications/debug/lfrfid_debug/views/lfrfid_debug_view_tune.h @@ -16,3 +16,8 @@ bool lfrfid_debug_view_tune_is_dirty(LfRfidTuneView* tune_view); uint32_t lfrfid_debug_view_tune_get_arr(LfRfidTuneView* tune_view); uint32_t lfrfid_debug_view_tune_get_ccr(LfRfidTuneView* tune_view); + +void lfrfid_debug_view_tune_set_callback( + LfRfidTuneView* tune_view, + void (*callback)(void* context), + void* context); diff --git a/applications/debug/speaker_debug/application.fam b/applications/debug/speaker_debug/application.fam new file mode 100644 index 000000000000..68d8b188bdd8 --- /dev/null +++ b/applications/debug/speaker_debug/application.fam @@ -0,0 +1,11 @@ +App( + appid="speaker_debug", + name="Speaker Debug", + apptype=FlipperAppType.DEBUG, + entry_point="speaker_debug_app", + requires=["gui", "notification"], + stack_size=2 * 1024, + order=10, + fap_category="Debug", + fap_libs=["music_worker"], +) diff --git a/applications/debug/speaker_debug/speaker_debug.c b/applications/debug/speaker_debug/speaker_debug.c new file mode 100644 index 000000000000..e01d5b8ec449 --- /dev/null +++ b/applications/debug/speaker_debug/speaker_debug.c @@ -0,0 +1,120 @@ +#include +#include +#include +#include +#include + +#define TAG "SpeakerDebug" +#define CLI_COMMAND "speaker_debug" + +typedef enum { + SpeakerDebugAppMessageTypeStop, +} SpeakerDebugAppMessageType; + +typedef struct { + SpeakerDebugAppMessageType type; +} SpeakerDebugAppMessage; + +typedef struct { + MusicWorker* music_worker; + FuriMessageQueue* message_queue; + Cli* cli; +} SpeakerDebugApp; + +static SpeakerDebugApp* speaker_app_alloc() { + SpeakerDebugApp* app = (SpeakerDebugApp*)malloc(sizeof(SpeakerDebugApp)); + app->music_worker = music_worker_alloc(); + app->message_queue = furi_message_queue_alloc(8, sizeof(SpeakerDebugAppMessage)); + app->cli = furi_record_open(RECORD_CLI); + return app; +} + +static void speaker_app_free(SpeakerDebugApp* app) { + music_worker_free(app->music_worker); + furi_message_queue_free(app->message_queue); + furi_record_close(RECORD_CLI); + free(app); +} + +static void speaker_app_cli(Cli* cli, FuriString* args, void* context) { + UNUSED(cli); + + SpeakerDebugApp* app = (SpeakerDebugApp*)context; + SpeakerDebugAppMessage message; + FuriString* cmd = furi_string_alloc(); + + if(!args_read_string_and_trim(args, cmd)) { + furi_string_free(cmd); + printf("Usage:\r\n"); + printf("\t" CLI_COMMAND " stop\r\n"); + return; + } + + if(furi_string_cmp(cmd, "stop") == 0) { + message.type = SpeakerDebugAppMessageTypeStop; + FuriStatus status = furi_message_queue_put(app->message_queue, &message, 100); + if(status != FuriStatusOk) { + printf("Failed to send message\r\n"); + } else { + printf("Stopping\r\n"); + } + } else { + printf("Usage:\r\n"); + printf("\t" CLI_COMMAND " stop\r\n"); + } + + furi_string_free(cmd); +} + +static bool speaker_app_music_play(SpeakerDebugApp* app, const char* rtttl) { + if(music_worker_is_playing(app->music_worker)) { + music_worker_stop(app->music_worker); + } + + if(!music_worker_load_rtttl_from_string(app->music_worker, rtttl)) { + FURI_LOG_E(TAG, "Failed to load RTTTL"); + return false; + } + + music_worker_set_volume(app->music_worker, 1.0f); + music_worker_start(app->music_worker); + + return true; +} + +static void speaker_app_music_stop(SpeakerDebugApp* app) { + if(music_worker_is_playing(app->music_worker)) { + music_worker_stop(app->music_worker); + } +} + +static void speaker_app_run(SpeakerDebugApp* app, const char* arg) { + if(!arg || !speaker_app_music_play(app, arg)) { + FURI_LOG_E(TAG, "Provided RTTTL is invalid"); + return; + } + + cli_add_command(app->cli, CLI_COMMAND, CliCommandFlagParallelSafe, speaker_app_cli, app); + + SpeakerDebugAppMessage message; + FuriStatus status; + while(true) { + status = furi_message_queue_get(app->message_queue, &message, FuriWaitForever); + + if(status == FuriStatusOk) { + if(message.type == SpeakerDebugAppMessageTypeStop) { + speaker_app_music_stop(app); + break; + } + } + } + + cli_delete_command(app->cli, CLI_COMMAND); +} + +int32_t speaker_debug_app(void* arg) { + SpeakerDebugApp* app = speaker_app_alloc(); + speaker_app_run(app, arg); + speaker_app_free(app); + return 0; +} diff --git a/applications/debug/uart_echo/uart_echo.c b/applications/debug/uart_echo/uart_echo.c index dc1327529214..4bede9ab45fd 100644 --- a/applications/debug/uart_echo/uart_echo.c +++ b/applications/debug/uart_echo/uart_echo.c @@ -10,6 +10,8 @@ #define LINES_ON_SCREEN 6 #define COLUMNS_ON_SCREEN 21 +#define TAG "UartEcho" +#define DEFAULT_BAUD_RATE 230400 typedef struct UartDumpModel UartDumpModel; @@ -179,7 +181,7 @@ static int32_t uart_echo_worker(void* context) { return 0; } -static UartEchoApp* uart_echo_app_alloc() { +static UartEchoApp* uart_echo_app_alloc(uint32_t baudrate) { UartEchoApp* app = malloc(sizeof(UartEchoApp)); app->rx_stream = furi_stream_buffer_alloc(2048, 1); @@ -220,7 +222,7 @@ static UartEchoApp* uart_echo_app_alloc() { // Enable uart listener furi_hal_console_disable(); - furi_hal_uart_set_br(FuriHalUartIdUSART1, 115200); + furi_hal_uart_set_br(FuriHalUartIdUSART1, baudrate); furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, uart_echo_on_irq_cb, app); return app; @@ -263,8 +265,18 @@ static void uart_echo_app_free(UartEchoApp* app) { } int32_t uart_echo_app(void* p) { - UNUSED(p); - UartEchoApp* app = uart_echo_app_alloc(); + uint32_t baudrate = DEFAULT_BAUD_RATE; + if(p) { + const char* baudrate_str = p; + if(sscanf(baudrate_str, "%lu", &baudrate) != 1) { + FURI_LOG_E(TAG, "Invalid baudrate: %s", baudrate_str); + baudrate = DEFAULT_BAUD_RATE; + } + } + + FURI_LOG_I(TAG, "Using baudrate: %lu", baudrate); + + UartEchoApp* app = uart_echo_app_alloc(baudrate); view_dispatcher_run(app->view_dispatcher); uart_echo_app_free(app); return 0; diff --git a/applications/debug/unit_tests/dialogs/dialogs_file_browser_options.c b/applications/debug/unit_tests/dialogs/dialogs_file_browser_options.c new file mode 100644 index 000000000000..2d5bad4c8a55 --- /dev/null +++ b/applications/debug/unit_tests/dialogs/dialogs_file_browser_options.c @@ -0,0 +1,32 @@ +#include + +#include "../minunit.h" + +MU_TEST(test_dialog_file_browser_set_basic_options_should_init_all_fields) { + mu_assert( + sizeof(DialogsFileBrowserOptions) == 28, + "Changes to `DialogsFileBrowserOptions` should also be reflected in `dialog_file_browser_set_basic_options`"); + + DialogsFileBrowserOptions options; + dialog_file_browser_set_basic_options(&options, ".fap", NULL); + // note: this assertions can safely be changed, their primary purpose is to remind the maintainer + // to update `dialog_file_browser_set_basic_options` by including all structure fields in it + mu_assert_string_eq(".fap", options.extension); + mu_assert_null(options.base_path); + mu_assert(options.skip_assets, "`skip_assets` should default to `true"); + mu_assert(options.hide_dot_files, "`hide_dot_files` should default to `true"); + mu_assert_null(options.icon); + mu_assert(options.hide_ext, "`hide_ext` should default to `true"); + mu_assert_null(options.item_loader_callback); + mu_assert_null(options.item_loader_context); +} + +MU_TEST_SUITE(dialogs_file_browser_options) { + MU_RUN_TEST(test_dialog_file_browser_set_basic_options_should_init_all_fields); +} + +int run_minunit_test_dialogs_file_browser_options() { + MU_RUN_SUITE(dialogs_file_browser_options); + + return MU_EXIT_CODE; +} diff --git a/applications/debug/unit_tests/nfc/nfc_test.c b/applications/debug/unit_tests/nfc/nfc_test.c index a027ea958f5d..0cb0898986bb 100644 --- a/applications/debug/unit_tests/nfc/nfc_test.c +++ b/applications/debug/unit_tests/nfc/nfc_test.c @@ -17,6 +17,12 @@ #define NFC_TEST_NFC_DEV_PATH EXT_PATH("unit_tests/nfc/nfc_device_test.nfc") +// Maximum allowed time for buffer preparation to fit 500us nt message timeout +#define NFC_TEST_4_BYTE_BUILD_BUFFER_TIM_MAX (150) +#define NFC_TEST_16_BYTE_BUILD_BUFFER_TIM_MAX (640) +#define NFC_TEST_4_BYTE_BUILD_SIGNAL_TIM_MAX (110) +#define NFC_TEST_16_BYTE_BUILD_SIGNAL_TIM_MAX (440) + typedef struct { Storage* storage; } NfcTest; diff --git a/applications/debug/unit_tests/subghz/subghz_test.c b/applications/debug/unit_tests/subghz/subghz_test.c index f1ab926538fa..6bdaa641e8d6 100644 --- a/applications/debug/unit_tests/subghz/subghz_test.c +++ b/applications/debug/unit_tests/subghz/subghz_test.c @@ -7,6 +7,8 @@ #include #include #include +#include +#include #define TAG "SubGhz TEST" #define KEYSTORE_DIR_NAME EXT_PATH("subghz/assets/keeloq_mfcodes") @@ -49,12 +51,15 @@ static void subghz_test_init(void) { subghz_environment_set_protocol_registry( environment_handler, (void*)&subghz_protocol_registry); + subghz_devices_init(); + receiver_handler = subghz_receiver_alloc_init(environment_handler); subghz_receiver_set_filter(receiver_handler, SubGhzProtocolFlag_Decodable); subghz_receiver_set_rx_callback(receiver_handler, subghz_test_rx_callback, NULL); } static void subghz_test_deinit(void) { + subghz_devices_deinit(); subghz_receiver_free(receiver_handler); subghz_environment_free(environment_handler); } @@ -68,7 +73,7 @@ static bool subghz_decoder_test(const char* path, const char* name_decoder) { if(decoder) { file_worker_encoder_handler = subghz_file_encoder_worker_alloc(); - if(subghz_file_encoder_worker_start(file_worker_encoder_handler, path)) { + if(subghz_file_encoder_worker_start(file_worker_encoder_handler, path, NULL)) { // the worker needs a file in order to open and read part of the file furi_delay_ms(100); @@ -108,7 +113,7 @@ static bool subghz_decode_random_test(const char* path) { uint32_t test_start = furi_get_tick(); file_worker_encoder_handler = subghz_file_encoder_worker_alloc(); - if(subghz_file_encoder_worker_start(file_worker_encoder_handler, path)) { + if(subghz_file_encoder_worker_start(file_worker_encoder_handler, path, NULL)) { // the worker needs a file in order to open and read part of the file furi_delay_ms(100); @@ -318,7 +323,7 @@ bool subghz_hal_async_tx_test_run(SubGhzHalAsyncTxTestType type) { SubGhzHalAsyncTxTest test = {0}; test.type = type; furi_hal_subghz_reset(); - furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async); + furi_hal_subghz_load_custom_preset(subghz_device_cc1101_preset_ook_650khz_async_regs); furi_hal_subghz_set_frequency_and_path(433920000); if(!furi_hal_subghz_start_async_tx(subghz_hal_async_tx_test_yield, &test)) { diff --git a/applications/debug/unit_tests/test_index.c b/applications/debug/unit_tests/test_index.c index ac71ca397ee9..9d7631bfee3b 100644 --- a/applications/debug/unit_tests/test_index.c +++ b/applications/debug/unit_tests/test_index.c @@ -27,6 +27,7 @@ int run_minunit_test_nfc(); int run_minunit_test_bit_lib(); int run_minunit_test_float_tools(); int run_minunit_test_bt(); +int run_minunit_test_dialogs_file_browser_options(); typedef int (*UnitTestEntry)(); @@ -55,6 +56,8 @@ const UnitTest unit_tests[] = { {.name = "bit_lib", .entry = run_minunit_test_bit_lib}, {.name = "float_tools", .entry = run_minunit_test_float_tools}, {.name = "bt", .entry = run_minunit_test_bt}, + {.name = "dialogs_file_browser_options", + .entry = run_minunit_test_dialogs_file_browser_options}, }; void minunit_print_progress() { diff --git a/applications/drivers/application.fam b/applications/drivers/application.fam new file mode 100644 index 000000000000..dc70e630c9f6 --- /dev/null +++ b/applications/drivers/application.fam @@ -0,0 +1,6 @@ +# Placeholder +App( + appid="drivers", + name="Drivers device", + apptype=FlipperAppType.METAPACKAGE, +) diff --git a/applications/drivers/subghz/application.fam b/applications/drivers/subghz/application.fam new file mode 100644 index 000000000000..aaf0e1bd94d5 --- /dev/null +++ b/applications/drivers/subghz/application.fam @@ -0,0 +1,8 @@ +App( + appid="radio_device_cc1101_ext", + apptype=FlipperAppType.PLUGIN, + targets=["f7"], + entry_point="subghz_device_cc1101_ext_ep", + requires=["subghz"], + fap_libs=["hwdrivers"], +) diff --git a/applications/drivers/subghz/cc1101_ext/cc1101_ext.c b/applications/drivers/subghz/cc1101_ext/cc1101_ext.c new file mode 100644 index 000000000000..896b9bd2f605 --- /dev/null +++ b/applications/drivers/subghz/cc1101_ext/cc1101_ext.c @@ -0,0 +1,765 @@ +#include "cc1101_ext.h" +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#define TAG "SubGhz_Device_CC1101_Ext" + +#define SUBGHZ_DEVICE_CC1101_EXT_TX_GPIO &gpio_ext_pb2 + +/* DMA Channels definition */ +#define SUBGHZ_DEVICE_CC1101_EXT_DMA DMA2 +#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_CHANNEL LL_DMA_CHANNEL_3 +#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_CHANNEL LL_DMA_CHANNEL_4 +#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_CHANNEL LL_DMA_CHANNEL_5 +#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_IRQ FuriHalInterruptIdDma2Ch3 +#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF \ + SUBGHZ_DEVICE_CC1101_EXT_DMA, SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_CHANNEL +#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF \ + SUBGHZ_DEVICE_CC1101_EXT_DMA, SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_CHANNEL +#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_DEF \ + SUBGHZ_DEVICE_CC1101_EXT_DMA, SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_CHANNEL + +/** Low level buffer dimensions and guard times */ +#define SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_FULL (256) +#define SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_HALF \ + (SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_FULL / 2) +#define SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_GUARD_TIME 999 + +/** SubGhz state */ +typedef enum { + SubGhzDeviceCC1101ExtStateInit, /**< Init pending */ + SubGhzDeviceCC1101ExtStateIdle, /**< Idle, energy save mode */ + SubGhzDeviceCC1101ExtStateAsyncRx, /**< Async RX started */ + SubGhzDeviceCC1101ExtStateAsyncTx, /**< Async TX started, DMA and timer is on */ + SubGhzDeviceCC1101ExtStateAsyncTxEnd, /**< Async TX complete, cleanup needed */ +} SubGhzDeviceCC1101ExtState; + +/** SubGhz regulation, receive transmission on the current frequency for the + * region */ +typedef enum { + SubGhzDeviceCC1101ExtRegulationOnlyRx, /**only Rx*/ + SubGhzDeviceCC1101ExtRegulationTxRx, /**TxRx*/ +} SubGhzDeviceCC1101ExtRegulation; + +typedef struct { + uint32_t* buffer; + LevelDuration carry_ld; + SubGhzDeviceCC1101ExtCallback callback; + void* callback_context; + uint32_t gpio_tx_buff[2]; + uint32_t debug_gpio_buff[2]; +} SubGhzDeviceCC1101ExtAsyncTx; + +typedef struct { + uint32_t capture_delta_duration; + SubGhzDeviceCC1101ExtCaptureCallback capture_callback; + void* capture_callback_context; +} SubGhzDeviceCC1101ExtAsyncRx; + +typedef struct { + volatile SubGhzDeviceCC1101ExtState state; + volatile SubGhzDeviceCC1101ExtRegulation regulation; + const GpioPin* async_mirror_pin; + FuriHalSpiBusHandle* spi_bus_handle; + const GpioPin* g0_pin; + SubGhzDeviceCC1101ExtAsyncTx async_tx; + SubGhzDeviceCC1101ExtAsyncRx async_rx; +} SubGhzDeviceCC1101Ext; + +static SubGhzDeviceCC1101Ext* subghz_device_cc1101_ext = NULL; + +static bool subghz_device_cc1101_ext_check_init() { + furi_assert(subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateInit); + subghz_device_cc1101_ext->state = SubGhzDeviceCC1101ExtStateIdle; + + bool ret = false; + + furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle); + FuriHalCortexTimer timer = furi_hal_cortex_timer_get(100 * 1000); + do { + // Reset + furi_hal_gpio_init( + subghz_device_cc1101_ext->g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + cc1101_reset(subghz_device_cc1101_ext->spi_bus_handle); + cc1101_write_reg( + subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG0, CC1101IocfgHighImpedance); + + // Prepare GD0 for power on self test + furi_hal_gpio_init( + subghz_device_cc1101_ext->g0_pin, GpioModeInput, GpioPullNo, GpioSpeedLow); + + // GD0 low + cc1101_write_reg(subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG0, CC1101IocfgHW); + while(furi_hal_gpio_read(subghz_device_cc1101_ext->g0_pin) != false) { + if(furi_hal_cortex_timer_is_expired(timer)) { + //timeout + break; + } + } + if(furi_hal_cortex_timer_is_expired(timer)) { + //timeout + break; + } + + // GD0 high + cc1101_write_reg( + subghz_device_cc1101_ext->spi_bus_handle, + CC1101_IOCFG0, + CC1101IocfgHW | CC1101_IOCFG_INV); + while(furi_hal_gpio_read(subghz_device_cc1101_ext->g0_pin) != true) { + if(furi_hal_cortex_timer_is_expired(timer)) { + //timeout + break; + } + } + if(furi_hal_cortex_timer_is_expired(timer)) { + //timeout + break; + } + + // Reset GD0 to floating state + cc1101_write_reg( + subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG0, CC1101IocfgHighImpedance); + furi_hal_gpio_init( + subghz_device_cc1101_ext->g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + + // RF switches + furi_hal_gpio_init(&gpio_rf_sw_0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); + cc1101_write_reg(subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG2, CC1101IocfgHW); + + // Go to sleep + cc1101_shutdown(subghz_device_cc1101_ext->spi_bus_handle); + ret = true; + } while(false); + + furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle); + + if(ret) { + FURI_LOG_I(TAG, "Init OK"); + } else { + FURI_LOG_E(TAG, "Init failed"); + } + return ret; +} + +bool subghz_device_cc1101_ext_alloc() { + furi_assert(subghz_device_cc1101_ext == NULL); + subghz_device_cc1101_ext = malloc(sizeof(SubGhzDeviceCC1101Ext)); + subghz_device_cc1101_ext->state = SubGhzDeviceCC1101ExtStateInit; + subghz_device_cc1101_ext->regulation = SubGhzDeviceCC1101ExtRegulationTxRx; + subghz_device_cc1101_ext->async_mirror_pin = NULL; + subghz_device_cc1101_ext->spi_bus_handle = &furi_hal_spi_bus_handle_external; + subghz_device_cc1101_ext->g0_pin = SUBGHZ_DEVICE_CC1101_EXT_TX_GPIO; + + subghz_device_cc1101_ext->async_rx.capture_delta_duration = 0; + + furi_hal_spi_bus_handle_init(subghz_device_cc1101_ext->spi_bus_handle); + return subghz_device_cc1101_ext_check_init(); +} + +void subghz_device_cc1101_ext_free() { + furi_assert(subghz_device_cc1101_ext != NULL); + furi_hal_spi_bus_handle_deinit(subghz_device_cc1101_ext->spi_bus_handle); + free(subghz_device_cc1101_ext); + subghz_device_cc1101_ext = NULL; +} + +void subghz_device_cc1101_ext_set_async_mirror_pin(const GpioPin* pin) { + subghz_device_cc1101_ext->async_mirror_pin = pin; +} + +const GpioPin* subghz_device_cc1101_ext_get_data_gpio() { + return subghz_device_cc1101_ext->g0_pin; +} + +bool subghz_device_cc1101_ext_is_connect() { + bool ret = false; + + if(subghz_device_cc1101_ext == NULL) { // not initialized + ret = subghz_device_cc1101_ext_alloc(); + subghz_device_cc1101_ext_free(); + } else { // initialized + furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle); + uint8_t partnumber = cc1101_get_partnumber(subghz_device_cc1101_ext->spi_bus_handle); + furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle); + ret = (partnumber != 0) && (partnumber != 0xFF); + } + + return ret; +} + +void subghz_device_cc1101_ext_sleep() { + furi_assert(subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateIdle); + furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle); + + cc1101_switch_to_idle(subghz_device_cc1101_ext->spi_bus_handle); + + cc1101_write_reg( + subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG0, CC1101IocfgHighImpedance); + furi_hal_gpio_init(subghz_device_cc1101_ext->g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + + cc1101_shutdown(subghz_device_cc1101_ext->spi_bus_handle); + + furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle); +} + +void subghz_device_cc1101_ext_dump_state() { + furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle); + printf( + "[subghz_device_cc1101_ext] cc1101 chip %d, version %d\r\n", + cc1101_get_partnumber(subghz_device_cc1101_ext->spi_bus_handle), + cc1101_get_version(subghz_device_cc1101_ext->spi_bus_handle)); + furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle); +} + +void subghz_device_cc1101_ext_load_custom_preset(const uint8_t* preset_data) { + //load config + furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle); + cc1101_reset(subghz_device_cc1101_ext->spi_bus_handle); + uint32_t i = 0; + uint8_t pa[8] = {0}; + while(preset_data[i]) { + cc1101_write_reg( + subghz_device_cc1101_ext->spi_bus_handle, preset_data[i], preset_data[i + 1]); + i += 2; + } + furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle); + + //load pa table + memcpy(&pa[0], &preset_data[i + 2], 8); + subghz_device_cc1101_ext_load_patable(pa); + + //show debug + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + i = 0; + FURI_LOG_D(TAG, "Loading custom preset"); + while(preset_data[i]) { + FURI_LOG_D(TAG, "Reg[%lu]: %02X=%02X", i, preset_data[i], preset_data[i + 1]); + i += 2; + } + for(uint8_t y = i; y < i + 10; y++) { + FURI_LOG_D(TAG, "PA[%u]: %02X", y, preset_data[y]); + } + } +} + +void subghz_device_cc1101_ext_load_registers(const uint8_t* data) { + furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle); + cc1101_reset(subghz_device_cc1101_ext->spi_bus_handle); + uint32_t i = 0; + while(data[i]) { + cc1101_write_reg(subghz_device_cc1101_ext->spi_bus_handle, data[i], data[i + 1]); + i += 2; + } + furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle); +} + +void subghz_device_cc1101_ext_load_patable(const uint8_t data[8]) { + furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle); + cc1101_set_pa_table(subghz_device_cc1101_ext->spi_bus_handle, data); + furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle); +} + +void subghz_device_cc1101_ext_write_packet(const uint8_t* data, uint8_t size) { + furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle); + cc1101_flush_tx(subghz_device_cc1101_ext->spi_bus_handle); + cc1101_write_reg(subghz_device_cc1101_ext->spi_bus_handle, CC1101_FIFO, size); + cc1101_write_fifo(subghz_device_cc1101_ext->spi_bus_handle, data, size); + furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle); +} + +void subghz_device_cc1101_ext_flush_rx() { + furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle); + cc1101_flush_rx(subghz_device_cc1101_ext->spi_bus_handle); + furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle); +} + +void subghz_device_cc1101_ext_flush_tx() { + furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle); + cc1101_flush_tx(subghz_device_cc1101_ext->spi_bus_handle); + furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle); +} + +bool subghz_device_cc1101_ext_rx_pipe_not_empty() { + CC1101RxBytes status[1]; + furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle); + cc1101_read_reg( + subghz_device_cc1101_ext->spi_bus_handle, + (CC1101_STATUS_RXBYTES) | CC1101_BURST, + (uint8_t*)status); + furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle); + // TODO: you can add a buffer overflow flag if needed + if(status->NUM_RXBYTES > 0) { + return true; + } else { + return false; + } +} + +bool subghz_device_cc1101_ext_is_rx_data_crc_valid() { + furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle); + uint8_t data[1]; + cc1101_read_reg( + subghz_device_cc1101_ext->spi_bus_handle, CC1101_STATUS_LQI | CC1101_BURST, data); + furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle); + if(((data[0] >> 7) & 0x01)) { + return true; + } else { + return false; + } +} + +void subghz_device_cc1101_ext_read_packet(uint8_t* data, uint8_t* size) { + furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle); + cc1101_read_fifo(subghz_device_cc1101_ext->spi_bus_handle, data, size); + furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle); +} + +void subghz_device_cc1101_ext_shutdown() { + furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle); + // Reset and shutdown + cc1101_shutdown(subghz_device_cc1101_ext->spi_bus_handle); + furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle); +} + +void subghz_device_cc1101_ext_reset() { + furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle); + furi_hal_gpio_init(subghz_device_cc1101_ext->g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + cc1101_switch_to_idle(subghz_device_cc1101_ext->spi_bus_handle); + cc1101_reset(subghz_device_cc1101_ext->spi_bus_handle); + cc1101_write_reg( + subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG0, CC1101IocfgHighImpedance); + furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle); +} + +void subghz_device_cc1101_ext_idle() { + furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle); + cc1101_switch_to_idle(subghz_device_cc1101_ext->spi_bus_handle); + furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle); +} + +void subghz_device_cc1101_ext_rx() { + furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle); + cc1101_switch_to_rx(subghz_device_cc1101_ext->spi_bus_handle); + furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle); +} + +bool subghz_device_cc1101_ext_tx() { + if(subghz_device_cc1101_ext->regulation != SubGhzDeviceCC1101ExtRegulationTxRx) return false; + furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle); + cc1101_switch_to_tx(subghz_device_cc1101_ext->spi_bus_handle); + furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle); + return true; +} + +float subghz_device_cc1101_ext_get_rssi() { + furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle); + int32_t rssi_dec = cc1101_get_rssi(subghz_device_cc1101_ext->spi_bus_handle); + furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle); + + float rssi = rssi_dec; + if(rssi_dec >= 128) { + rssi = ((rssi - 256.0f) / 2.0f) - 74.0f; + } else { + rssi = (rssi / 2.0f) - 74.0f; + } + + return rssi; +} + +uint8_t subghz_device_cc1101_ext_get_lqi() { + furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle); + uint8_t data[1]; + cc1101_read_reg( + subghz_device_cc1101_ext->spi_bus_handle, CC1101_STATUS_LQI | CC1101_BURST, data); + furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle); + return data[0] & 0x7F; +} + +bool subghz_device_cc1101_ext_is_frequency_valid(uint32_t value) { + if(!(value >= 299999755 && value <= 348000335) && + !(value >= 386999938 && value <= 464000000) && + !(value >= 778999847 && value <= 928000000)) { + return false; + } + + return true; +} + +uint32_t subghz_device_cc1101_ext_set_frequency(uint32_t value) { + if(furi_hal_region_is_frequency_allowed(value)) { + subghz_device_cc1101_ext->regulation = SubGhzDeviceCC1101ExtRegulationTxRx; + } else { + subghz_device_cc1101_ext->regulation = SubGhzDeviceCC1101ExtRegulationOnlyRx; + } + + furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle); + uint32_t real_frequency = + cc1101_set_frequency(subghz_device_cc1101_ext->spi_bus_handle, value); + cc1101_calibrate(subghz_device_cc1101_ext->spi_bus_handle); + + while(true) { + CC1101Status status = cc1101_get_status(subghz_device_cc1101_ext->spi_bus_handle); + if(status.STATE == CC1101StateIDLE) break; + } + + furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle); + return real_frequency; +} + +static bool subghz_device_cc1101_ext_start_debug() { + bool ret = false; + if(subghz_device_cc1101_ext->async_mirror_pin != NULL) { + furi_hal_gpio_init( + subghz_device_cc1101_ext->async_mirror_pin, + GpioModeOutputPushPull, + GpioPullNo, + GpioSpeedVeryHigh); + ret = true; + } + return ret; +} + +static bool subghz_device_cc1101_ext_stop_debug() { + bool ret = false; + if(subghz_device_cc1101_ext->async_mirror_pin != NULL) { + furi_hal_gpio_init( + subghz_device_cc1101_ext->async_mirror_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + ret = true; + } + return ret; +} + +static void subghz_device_cc1101_ext_capture_ISR() { + if(!furi_hal_gpio_read(subghz_device_cc1101_ext->g0_pin)) { + if(subghz_device_cc1101_ext->async_rx.capture_callback) { + if(subghz_device_cc1101_ext->async_mirror_pin != NULL) + furi_hal_gpio_write(subghz_device_cc1101_ext->async_mirror_pin, false); + + subghz_device_cc1101_ext->async_rx.capture_callback( + true, + LL_TIM_GetCounter(TIM17), + (void*)subghz_device_cc1101_ext->async_rx.capture_callback_context); + } + } else { + if(subghz_device_cc1101_ext->async_rx.capture_callback) { + if(subghz_device_cc1101_ext->async_mirror_pin != NULL) + furi_hal_gpio_write(subghz_device_cc1101_ext->async_mirror_pin, true); + + subghz_device_cc1101_ext->async_rx.capture_callback( + false, + LL_TIM_GetCounter(TIM17), + (void*)subghz_device_cc1101_ext->async_rx.capture_callback_context); + } + } + LL_TIM_SetCounter(TIM17, 6); +} + +void subghz_device_cc1101_ext_start_async_rx( + SubGhzDeviceCC1101ExtCaptureCallback callback, + void* context) { + furi_assert(subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateIdle); + subghz_device_cc1101_ext->state = SubGhzDeviceCC1101ExtStateAsyncRx; + + subghz_device_cc1101_ext->async_rx.capture_callback = callback; + subghz_device_cc1101_ext->async_rx.capture_callback_context = context; + + furi_hal_bus_enable(FuriHalBusTIM17); + + // Configure TIM + LL_TIM_SetPrescaler(TIM17, 64 - 1); + LL_TIM_SetCounterMode(TIM17, LL_TIM_COUNTERMODE_UP); + LL_TIM_SetAutoReload(TIM17, 0xFFFF); + LL_TIM_SetClockDivision(TIM17, LL_TIM_CLOCKDIVISION_DIV1); + + // Timer: advanced + LL_TIM_SetClockSource(TIM17, LL_TIM_CLOCKSOURCE_INTERNAL); + LL_TIM_DisableARRPreload(TIM17); + LL_TIM_DisableDMAReq_TRIG(TIM17); + LL_TIM_DisableIT_TRIG(TIM17); + + furi_hal_gpio_init( + subghz_device_cc1101_ext->g0_pin, GpioModeInterruptRiseFall, GpioPullUp, GpioSpeedVeryHigh); + furi_hal_gpio_remove_int_callback(subghz_device_cc1101_ext->g0_pin); + furi_hal_gpio_add_int_callback( + subghz_device_cc1101_ext->g0_pin, + subghz_device_cc1101_ext_capture_ISR, + subghz_device_cc1101_ext->async_rx.capture_callback); + + // Start timer + LL_TIM_SetCounter(TIM17, 0); + LL_TIM_EnableCounter(TIM17); + + // Start debug + subghz_device_cc1101_ext_start_debug(); + + // Switch to RX + subghz_device_cc1101_ext_rx(); + + //Clear the variable after the end of the session + subghz_device_cc1101_ext->async_rx.capture_delta_duration = 0; +} + +void subghz_device_cc1101_ext_stop_async_rx() { + furi_assert(subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncRx); + subghz_device_cc1101_ext->state = SubGhzDeviceCC1101ExtStateIdle; + + // Shutdown radio + subghz_device_cc1101_ext_idle(); + + FURI_CRITICAL_ENTER(); + furi_hal_bus_disable(FuriHalBusTIM17); + + // Stop debug + subghz_device_cc1101_ext_stop_debug(); + + FURI_CRITICAL_EXIT(); + furi_hal_gpio_remove_int_callback(subghz_device_cc1101_ext->g0_pin); + furi_hal_gpio_init(subghz_device_cc1101_ext->g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow); +} + +static void subghz_device_cc1101_ext_async_tx_refill(uint32_t* buffer, size_t samples) { + furi_assert(subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTx); + while(samples > 0) { + bool is_odd = samples % 2; + LevelDuration ld; + if(level_duration_is_reset(subghz_device_cc1101_ext->async_tx.carry_ld)) { + ld = subghz_device_cc1101_ext->async_tx.callback( + subghz_device_cc1101_ext->async_tx.callback_context); + } else { + ld = subghz_device_cc1101_ext->async_tx.carry_ld; + subghz_device_cc1101_ext->async_tx.carry_ld = level_duration_reset(); + } + + if(level_duration_is_wait(ld)) { + *buffer = SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_GUARD_TIME; + buffer++; + samples--; + } else if(level_duration_is_reset(ld)) { + *buffer = 0; + buffer++; + samples--; + LL_DMA_DisableIT_HT(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF); + LL_DMA_DisableIT_TC(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF); + LL_TIM_EnableIT_UPDATE(TIM17); + break; + } else { + bool level = level_duration_get_level(ld); + + // Inject guard time if level is incorrect + if(is_odd != level) { + *buffer = SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_GUARD_TIME; + buffer++; + samples--; + + // Special case: prevent buffer overflow if sample is last + if(samples == 0) { + subghz_device_cc1101_ext->async_tx.carry_ld = ld; + break; + } + } + + uint32_t duration = level_duration_get_duration(ld); + furi_assert(duration > 0); + *buffer = duration - 1; + buffer++; + samples--; + } + } +} + +static void subghz_device_cc1101_ext_async_tx_dma_isr() { + furi_assert(subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTx); + +#if SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_CHANNEL == LL_DMA_CHANNEL_3 + if(LL_DMA_IsActiveFlag_HT3(SUBGHZ_DEVICE_CC1101_EXT_DMA)) { + LL_DMA_ClearFlag_HT3(SUBGHZ_DEVICE_CC1101_EXT_DMA); + subghz_device_cc1101_ext_async_tx_refill( + subghz_device_cc1101_ext->async_tx.buffer, + SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_HALF); + } + if(LL_DMA_IsActiveFlag_TC3(SUBGHZ_DEVICE_CC1101_EXT_DMA)) { + LL_DMA_ClearFlag_TC3(SUBGHZ_DEVICE_CC1101_EXT_DMA); + subghz_device_cc1101_ext_async_tx_refill( + subghz_device_cc1101_ext->async_tx.buffer + + SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_HALF, + SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_HALF); + } +#else +#error Update this code. Would you kindly? +#endif +} + +static void subghz_device_cc1101_ext_async_tx_timer_isr() { + if(LL_TIM_IsActiveFlag_UPDATE(TIM17)) { + if(LL_TIM_GetAutoReload(TIM17) == 0) { + LL_DMA_DisableChannel(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF); + furi_hal_gpio_write(subghz_device_cc1101_ext->g0_pin, false); + if(subghz_device_cc1101_ext->async_mirror_pin != NULL) + furi_hal_gpio_write(subghz_device_cc1101_ext->async_mirror_pin, false); + LL_TIM_DisableCounter(TIM17); + subghz_device_cc1101_ext->state = SubGhzDeviceCC1101ExtStateAsyncTxEnd; + } + LL_TIM_ClearFlag_UPDATE(TIM17); + } +} + +bool subghz_device_cc1101_ext_start_async_tx(SubGhzDeviceCC1101ExtCallback callback, void* context) { + furi_assert(subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateIdle); + furi_assert(callback); + + //If transmission is prohibited by regional settings + if(subghz_device_cc1101_ext->regulation != SubGhzDeviceCC1101ExtRegulationTxRx) return false; + + subghz_device_cc1101_ext->async_tx.callback = callback; + subghz_device_cc1101_ext->async_tx.callback_context = context; + + subghz_device_cc1101_ext->state = SubGhzDeviceCC1101ExtStateAsyncTx; + + subghz_device_cc1101_ext->async_tx.buffer = + malloc(SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_FULL * sizeof(uint32_t)); + + //Signal generation with mem-to-mem DMA + furi_hal_gpio_write(subghz_device_cc1101_ext->g0_pin, false); + furi_hal_gpio_init( + subghz_device_cc1101_ext->g0_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); + + // Configure DMA update timer + LL_DMA_SetMemoryAddress( + SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF, (uint32_t)subghz_device_cc1101_ext->async_tx.buffer); + LL_DMA_SetPeriphAddress(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF, (uint32_t) & (TIM17->ARR)); + LL_DMA_ConfigTransfer( + SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF, + LL_DMA_DIRECTION_MEMORY_TO_PERIPH | LL_DMA_MODE_CIRCULAR | LL_DMA_PERIPH_NOINCREMENT | + LL_DMA_MEMORY_INCREMENT | LL_DMA_PDATAALIGN_WORD | LL_DMA_MDATAALIGN_WORD | + LL_DMA_MODE_NORMAL); + LL_DMA_SetDataLength( + SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF, SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_FULL); + LL_DMA_SetPeriphRequest(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF, LL_DMAMUX_REQ_TIM17_UP); + + LL_DMA_EnableIT_TC(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF); + LL_DMA_EnableIT_HT(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF); + LL_DMA_EnableChannel(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF); + + furi_hal_interrupt_set_isr( + SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_IRQ, subghz_device_cc1101_ext_async_tx_dma_isr, NULL); + + furi_hal_bus_enable(FuriHalBusTIM17); + + // Configure TIM + LL_TIM_SetPrescaler(TIM17, 64 - 1); + LL_TIM_SetCounterMode(TIM17, LL_TIM_COUNTERMODE_UP); + LL_TIM_SetAutoReload(TIM17, 0xFFFF); + LL_TIM_SetClockDivision(TIM17, LL_TIM_CLOCKDIVISION_DIV1); + LL_TIM_SetClockSource(TIM17, LL_TIM_CLOCKSOURCE_INTERNAL); + LL_TIM_DisableARRPreload(TIM17); + + furi_hal_interrupt_set_isr( + FuriHalInterruptIdTim1TrgComTim17, subghz_device_cc1101_ext_async_tx_timer_isr, NULL); + + subghz_device_cc1101_ext_async_tx_refill( + subghz_device_cc1101_ext->async_tx.buffer, SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_FULL); + + // Configure tx gpio dma + const GpioPin* gpio = subghz_device_cc1101_ext->g0_pin; + + subghz_device_cc1101_ext->async_tx.gpio_tx_buff[0] = (uint32_t)gpio->pin << GPIO_NUMBER; + subghz_device_cc1101_ext->async_tx.gpio_tx_buff[1] = gpio->pin; + + LL_DMA_SetMemoryAddress( + SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF, + (uint32_t)subghz_device_cc1101_ext->async_tx.gpio_tx_buff); + LL_DMA_SetPeriphAddress(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF, (uint32_t) & (gpio->port->BSRR)); + LL_DMA_ConfigTransfer( + SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF, + LL_DMA_DIRECTION_MEMORY_TO_PERIPH | LL_DMA_MODE_CIRCULAR | LL_DMA_PERIPH_NOINCREMENT | + LL_DMA_MEMORY_INCREMENT | LL_DMA_PDATAALIGN_WORD | LL_DMA_MDATAALIGN_WORD | + LL_DMA_PRIORITY_HIGH); + LL_DMA_SetDataLength(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF, 2); + LL_DMA_SetPeriphRequest(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF, LL_DMAMUX_REQ_TIM17_UP); + LL_DMA_EnableChannel(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF); + + // Start debug + if(subghz_device_cc1101_ext_start_debug()) { + gpio = subghz_device_cc1101_ext->async_mirror_pin; + subghz_device_cc1101_ext->async_tx.debug_gpio_buff[0] = (uint32_t)gpio->pin << GPIO_NUMBER; + subghz_device_cc1101_ext->async_tx.debug_gpio_buff[1] = gpio->pin; + + LL_DMA_SetMemoryAddress( + SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_DEF, + (uint32_t)subghz_device_cc1101_ext->async_tx.debug_gpio_buff); + LL_DMA_SetPeriphAddress( + SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_DEF, (uint32_t) & (gpio->port->BSRR)); + LL_DMA_ConfigTransfer( + SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_DEF, + LL_DMA_DIRECTION_MEMORY_TO_PERIPH | LL_DMA_MODE_CIRCULAR | LL_DMA_PERIPH_NOINCREMENT | + LL_DMA_MEMORY_INCREMENT | LL_DMA_PDATAALIGN_WORD | LL_DMA_MDATAALIGN_WORD | + LL_DMA_PRIORITY_LOW); + LL_DMA_SetDataLength(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_DEF, 2); + LL_DMA_SetPeriphRequest(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_DEF, LL_DMAMUX_REQ_TIM17_UP); + LL_DMA_EnableChannel(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_DEF); + } + + // Start counter + LL_TIM_EnableDMAReq_UPDATE(TIM17); + LL_TIM_GenerateEvent_UPDATE(TIM17); + + subghz_device_cc1101_ext_tx(); + + LL_TIM_SetCounter(TIM17, 0); + LL_TIM_EnableCounter(TIM17); + + return true; +} + +bool subghz_device_cc1101_ext_is_async_tx_complete() { + return subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTxEnd; +} + +void subghz_device_cc1101_ext_stop_async_tx() { + furi_assert( + subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTx || + subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTxEnd); + + // Shutdown radio + subghz_device_cc1101_ext_idle(); + + // Deinitialize Timer + FURI_CRITICAL_ENTER(); + furi_hal_bus_disable(FuriHalBusTIM17); + furi_hal_interrupt_set_isr(FuriHalInterruptIdTim1TrgComTim17, NULL, NULL); + + // Deinitialize DMA + LL_DMA_DeInit(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF); + LL_DMA_DisableChannel(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF); + furi_hal_interrupt_set_isr(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_IRQ, NULL, NULL); + + // Deinitialize GPIO + furi_hal_gpio_write(subghz_device_cc1101_ext->g0_pin, false); + furi_hal_gpio_init(subghz_device_cc1101_ext->g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + + // Stop debug + if(subghz_device_cc1101_ext_stop_debug()) { + LL_DMA_DisableChannel(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_DEF); + } + + FURI_CRITICAL_EXIT(); + + free(subghz_device_cc1101_ext->async_tx.buffer); + + subghz_device_cc1101_ext->state = SubGhzDeviceCC1101ExtStateIdle; +} diff --git a/applications/drivers/subghz/cc1101_ext/cc1101_ext.h b/applications/drivers/subghz/cc1101_ext/cc1101_ext.h new file mode 100644 index 000000000000..d972fcb66185 --- /dev/null +++ b/applications/drivers/subghz/cc1101_ext/cc1101_ext.h @@ -0,0 +1,206 @@ +/** + * @file furi_hal_subghz.h + * SubGhz HAL API + */ + +#pragma once +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Mirror RX/TX async modulation signal to specified pin + * + * @warning Configures pin to output mode. Make sure it is not connected + * directly to power or ground. + * + * @param[in] pin pointer to the gpio pin structure or NULL to disable + */ +void subghz_device_cc1101_ext_set_async_mirror_pin(const GpioPin* pin); + +/** Get data GPIO + * + * @return pointer to the gpio pin structure + */ +const GpioPin* subghz_device_cc1101_ext_get_data_gpio(); + +/** Initialize device + * + * @return true if success + */ +bool subghz_device_cc1101_ext_alloc(); + +/** Deinitialize device + */ +void subghz_device_cc1101_ext_free(); + +/** Check and switch to power save mode Used by internal API-HAL + * initialization routine Can be used to reinitialize device to safe state and + * send it to sleep + */ +bool subghz_device_cc1101_ext_is_connect(); + +/** Send device to sleep mode + */ +void subghz_device_cc1101_ext_sleep(); + +/** Dump info to stdout + */ +void subghz_device_cc1101_ext_dump_state(); + +/** Load custom registers from preset + * + * @param preset_data registers to load + */ +void subghz_device_cc1101_ext_load_custom_preset(const uint8_t* preset_data); + +/** Load registers + * + * @param data Registers data + */ +void subghz_device_cc1101_ext_load_registers(const uint8_t* data); + +/** Load PATABLE + * + * @param data 8 uint8_t values + */ +void subghz_device_cc1101_ext_load_patable(const uint8_t data[8]); + +/** Write packet to FIFO + * + * @param data bytes array + * @param size size + */ +void subghz_device_cc1101_ext_write_packet(const uint8_t* data, uint8_t size); + +/** Check if receive pipe is not empty + * + * @return true if not empty + */ +bool subghz_device_cc1101_ext_rx_pipe_not_empty(); + +/** Check if received data crc is valid + * + * @return true if valid + */ +bool subghz_device_cc1101_ext_is_rx_data_crc_valid(); + +/** Read packet from FIFO + * + * @param data pointer + * @param size size + */ +void subghz_device_cc1101_ext_read_packet(uint8_t* data, uint8_t* size); + +/** Flush rx FIFO buffer + */ +void subghz_device_cc1101_ext_flush_rx(); + +/** Flush tx FIFO buffer + */ +void subghz_device_cc1101_ext_flush_tx(); + +/** Shutdown Issue SPWD command + * @warning registers content will be lost + */ +void subghz_device_cc1101_ext_shutdown(); + +/** Reset Issue reset command + * @warning registers content will be lost + */ +void subghz_device_cc1101_ext_reset(); + +/** Switch to Idle + */ +void subghz_device_cc1101_ext_idle(); + +/** Switch to Receive + */ +void subghz_device_cc1101_ext_rx(); + +/** Switch to Transmit + * + * @return true if the transfer is allowed by belonging to the region + */ +bool subghz_device_cc1101_ext_tx(); + +/** Get RSSI value in dBm + * + * @return RSSI value + */ +float subghz_device_cc1101_ext_get_rssi(); + +/** Get LQI + * + * @return LQI value + */ +uint8_t subghz_device_cc1101_ext_get_lqi(); + +/** Check if frequency is in valid range + * + * @param value frequency in Hz + * + * @return true if frequency is valid, otherwise false + */ +bool subghz_device_cc1101_ext_is_frequency_valid(uint32_t value); + +/** Set frequency + * + * @param value frequency in Hz + * + * @return real frequency in Hz + */ +uint32_t subghz_device_cc1101_ext_set_frequency(uint32_t value); + +/* High Level API */ + +/** Signal Timings Capture callback */ +typedef void (*SubGhzDeviceCC1101ExtCaptureCallback)(bool level, uint32_t duration, void* context); + +/** Enable signal timings capture Initializes GPIO and TIM2 for timings capture + * + * @param callback SubGhzDeviceCC1101ExtCaptureCallback + * @param context callback context + */ +void subghz_device_cc1101_ext_start_async_rx( + SubGhzDeviceCC1101ExtCaptureCallback callback, + void* context); + +/** Disable signal timings capture Resets GPIO and TIM2 + */ +void subghz_device_cc1101_ext_stop_async_rx(); + +/** Async TX callback type + * @param context callback context + * @return LevelDuration + */ +typedef LevelDuration (*SubGhzDeviceCC1101ExtCallback)(void* context); + +/** Start async TX Initializes GPIO, TIM2 and DMA1 for signal output + * + * @param callback SubGhzDeviceCC1101ExtCallback + * @param context callback context + * + * @return true if the transfer is allowed by belonging to the region + */ +bool subghz_device_cc1101_ext_start_async_tx(SubGhzDeviceCC1101ExtCallback callback, void* context); + +/** Wait for async transmission to complete + * + * @return true if TX complete + */ +bool subghz_device_cc1101_ext_is_async_tx_complete(); + +/** Stop async transmission and cleanup resources Resets GPIO, TIM2, and DMA1 + */ +void subghz_device_cc1101_ext_stop_async_tx(); + +#ifdef __cplusplus +} +#endif diff --git a/applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.c b/applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.c new file mode 100644 index 000000000000..51f5a0d1ddbe --- /dev/null +++ b/applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.c @@ -0,0 +1,110 @@ +#include "cc1101_ext_interconnect.h" +#include "cc1101_ext.h" +#include + +#define TAG "SubGhzDeviceCC1101Ext" + +static bool subghz_device_cc1101_ext_interconnect_is_frequency_valid(uint32_t frequency) { + bool ret = subghz_device_cc1101_ext_is_frequency_valid(frequency); + if(!ret) { + furi_crash("SubGhz: Incorrect frequency."); + } + return ret; +} + +static uint32_t subghz_device_cc1101_ext_interconnect_set_frequency(uint32_t frequency) { + subghz_device_cc1101_ext_interconnect_is_frequency_valid(frequency); + return subghz_device_cc1101_ext_set_frequency(frequency); +} + +static bool subghz_device_cc1101_ext_interconnect_start_async_tx(void* callback, void* context) { + return subghz_device_cc1101_ext_start_async_tx( + (SubGhzDeviceCC1101ExtCallback)callback, context); +} + +static void subghz_device_cc1101_ext_interconnect_start_async_rx(void* callback, void* context) { + subghz_device_cc1101_ext_start_async_rx( + (SubGhzDeviceCC1101ExtCaptureCallback)callback, context); +} + +static void subghz_device_cc1101_ext_interconnect_load_preset( + FuriHalSubGhzPreset preset, + uint8_t* preset_data) { + switch(preset) { + case FuriHalSubGhzPresetOok650Async: + subghz_device_cc1101_ext_load_custom_preset( + subghz_device_cc1101_preset_ook_650khz_async_regs); + break; + case FuriHalSubGhzPresetOok270Async: + subghz_device_cc1101_ext_load_custom_preset( + subghz_device_cc1101_preset_ook_270khz_async_regs); + break; + case FuriHalSubGhzPreset2FSKDev238Async: + subghz_device_cc1101_ext_load_custom_preset( + subghz_device_cc1101_preset_2fsk_dev2_38khz_async_regs); + break; + case FuriHalSubGhzPreset2FSKDev476Async: + subghz_device_cc1101_ext_load_custom_preset( + subghz_device_cc1101_preset_2fsk_dev47_6khz_async_regs); + break; + case FuriHalSubGhzPresetMSK99_97KbAsync: + subghz_device_cc1101_ext_load_custom_preset( + subghz_device_cc1101_preset_msk_99_97kb_async_regs); + break; + case FuriHalSubGhzPresetGFSK9_99KbAsync: + subghz_device_cc1101_ext_load_custom_preset( + subghz_device_cc1101_preset_gfsk_9_99kb_async_regs); + break; + + default: + subghz_device_cc1101_ext_load_custom_preset(preset_data); + } +} + +const SubGhzDeviceInterconnect subghz_device_cc1101_ext_interconnect = { + .begin = subghz_device_cc1101_ext_alloc, + .end = subghz_device_cc1101_ext_free, + .is_connect = subghz_device_cc1101_ext_is_connect, + .reset = subghz_device_cc1101_ext_reset, + .sleep = subghz_device_cc1101_ext_sleep, + .idle = subghz_device_cc1101_ext_idle, + .load_preset = subghz_device_cc1101_ext_interconnect_load_preset, + .set_frequency = subghz_device_cc1101_ext_interconnect_set_frequency, + .is_frequency_valid = subghz_device_cc1101_ext_is_frequency_valid, + .set_async_mirror_pin = subghz_device_cc1101_ext_set_async_mirror_pin, + .get_data_gpio = subghz_device_cc1101_ext_get_data_gpio, + + .set_tx = subghz_device_cc1101_ext_tx, + .flush_tx = subghz_device_cc1101_ext_flush_tx, + .start_async_tx = subghz_device_cc1101_ext_interconnect_start_async_tx, + .is_async_complete_tx = subghz_device_cc1101_ext_is_async_tx_complete, + .stop_async_tx = subghz_device_cc1101_ext_stop_async_tx, + + .set_rx = subghz_device_cc1101_ext_rx, + .flush_rx = subghz_device_cc1101_ext_flush_rx, + .start_async_rx = subghz_device_cc1101_ext_interconnect_start_async_rx, + .stop_async_rx = subghz_device_cc1101_ext_stop_async_rx, + + .get_rssi = subghz_device_cc1101_ext_get_rssi, + .get_lqi = subghz_device_cc1101_ext_get_lqi, + + .rx_pipe_not_empty = subghz_device_cc1101_ext_rx_pipe_not_empty, + .is_rx_data_crc_valid = subghz_device_cc1101_ext_is_rx_data_crc_valid, + .read_packet = subghz_device_cc1101_ext_read_packet, + .write_packet = subghz_device_cc1101_ext_write_packet, +}; + +const SubGhzDevice subghz_device_cc1101_ext = { + .name = SUBGHZ_DEVICE_CC1101_EXT_NAME, + .interconnect = &subghz_device_cc1101_ext_interconnect, +}; + +static const FlipperAppPluginDescriptor subghz_device_cc1101_ext_descriptor = { + .appid = SUBGHZ_RADIO_DEVICE_PLUGIN_APP_ID, + .ep_api_version = SUBGHZ_RADIO_DEVICE_PLUGIN_API_VERSION, + .entry_point = &subghz_device_cc1101_ext, +}; + +const FlipperAppPluginDescriptor* subghz_device_cc1101_ext_ep() { + return &subghz_device_cc1101_ext_descriptor; +} \ No newline at end of file diff --git a/applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h b/applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h new file mode 100644 index 000000000000..cf1ff3ee07f2 --- /dev/null +++ b/applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h @@ -0,0 +1,8 @@ +#pragma once +#include + +#define SUBGHZ_DEVICE_CC1101_EXT_NAME "cc1101_ext" + +typedef struct SubGhzDeviceCC1101Ext SubGhzDeviceCC1101Ext; + +const FlipperAppPluginDescriptor* subghz_device_cc1101_ext_ep(); diff --git a/applications/external/avr_isp_programmer/helpers/avr_isp_worker_rw.c b/applications/external/avr_isp_programmer/helpers/avr_isp_worker_rw.c index 0ee5cefa1de0..b4c12cbc38a4 100644 --- a/applications/external/avr_isp_programmer/helpers/avr_isp_worker_rw.c +++ b/applications/external/avr_isp_programmer/helpers/avr_isp_worker_rw.c @@ -60,7 +60,9 @@ static int32_t avr_isp_worker_rw_thread(void* context) { AvrIspWorkerRW* instance = context; /* start PWM on &gpio_ext_pa4 */ - furi_hal_pwm_start(FuriHalPwmOutputIdLptim2PA4, 4000000, 50); + if(!furi_hal_pwm_is_running(FuriHalPwmOutputIdLptim2PA4)) { + furi_hal_pwm_start(FuriHalPwmOutputIdLptim2PA4, 4000000, 50); + } FURI_LOG_D(TAG, "Start"); @@ -122,7 +124,9 @@ static int32_t avr_isp_worker_rw_thread(void* context) { } FURI_LOG_D(TAG, "Stop"); - furi_hal_pwm_stop(FuriHalPwmOutputIdLptim2PA4); + if(furi_hal_pwm_is_running(FuriHalPwmOutputIdLptim2PA4)) { + furi_hal_pwm_stop(FuriHalPwmOutputIdLptim2PA4); + } return 0; } @@ -136,7 +140,12 @@ bool avr_isp_worker_rw_detect_chip(AvrIspWorkerRW* instance) { instance->chip_arr_ind = avr_isp_chip_arr_size + 1; /* start PWM on &gpio_ext_pa4 */ - furi_hal_pwm_start(FuriHalPwmOutputIdLptim2PA4, 4000000, 50); + bool was_pwm_enabled = false; + if(!furi_hal_pwm_is_running(FuriHalPwmOutputIdLptim2PA4)) { + furi_hal_pwm_start(FuriHalPwmOutputIdLptim2PA4, 4000000, 50); + } else { + was_pwm_enabled = true; + } do { if(!avr_isp_auto_set_spi_speed_start_pmode(instance->avr_isp)) { @@ -200,7 +209,9 @@ bool avr_isp_worker_rw_detect_chip(AvrIspWorkerRW* instance) { } while(0); - furi_hal_pwm_stop(FuriHalPwmOutputIdLptim2PA4); + if(furi_hal_pwm_is_running(FuriHalPwmOutputIdLptim2PA4) && !was_pwm_enabled) { + furi_hal_pwm_stop(FuriHalPwmOutputIdLptim2PA4); + } if(instance->callback) { if(instance->chip_arr_ind > avr_isp_chip_arr_size) { diff --git a/applications/external/hid_app/assets/Space_60x18.png b/applications/external/hid_app/assets/Space_60x18.png new file mode 100644 index 0000000000000000000000000000000000000000..e29f50ae9220d2f9a9753850dedcc6be0a211e76 GIT binary patch literal 2871 zcmV-73&`||P)004&%004{+008|`004nN004b?008NW002DY000@xb3BE2000Uv zX+uL$Nkc;*aB^>EX>4Tx07%E3mUmQC*A|D*y?1({%`nm#dXp|Nfb=dP9RyJrW(F9_ z0K*JTY>22pL=h1IMUbF?0i&TvtcYSED5zi$NDxqBFp8+CWJcCXe0h2A<>mLsz2Dkr z?{oLrd!Mx~03=TzE-wX^0w9?u;0Jm*(^rK@(6Rjh26%u0rT{Qm>8ZX!?!iDLFE@L0LWj&=4?(nOT_siPRbOditRHZrp6?S8Agej zFG^6va$=5K|`EW#NwP&*~x4%_lS6VhL9s-#7D#h8C*`Lh;NHnGf9}t z74chfY%+(L4giWIwhK6{coCb3n8XhbbP@4#0C1$ZFF5847I3lz;zPNlq-OKEaq$AW zE=!MYYHiJ+dvY?9I0Av8Ka-Wn(gPeepdb@piwLhwjRWWeSr7baCBSDM=|p zK0Q5^$>Pur|2)M1IPkCYSQ^NQ`z*p zYmq4Rp8z$=2uR(a0_5jDfT9oq5_wSE_22vEgAWDbn-``!u{igi1^xT3aEbVl&W-yV z=Mor9X9@Wki)-R*3DAH5Bmou30~MeFbb%o-16IHmI084Y0{DSo5DwM?7KjJQfDbZ3 zF4znTKoQsl_JT@K1L{E|XaOfc2RIEbfXm=IxC!on2Vew@gXdrdyaDqN1YsdEM1kZX zRY(gmfXpBUWDmJPK2RVO4n;$85DyYUxzHA<2r7jtp<1XB`W89`U4X7a1JFHa6qn9`(3jA6(BtSg7z~Dn z(ZN_@JTc*z1k5^2G3EfK6>}alfEmNgVzF3xtO3>z>xX4x1=s@Ye(W*qIqV>I9QzhW z#Hr%UaPGJW91oX=E5|kA&f*4f6S#T26kZE&gZIO;@!9wid_BGke*-^`pC?EYbO?5Y zU_t_6GogaeLbybDNO(mg64i;;!~i0fxQSRnJWjkq93{RZ$&mC(E~H43khGI@gmj*C zkMxR6CTo)&$q{4$c_+D%e3AT^{8oY@VI<)t!Is!4Q6EtGo7CCWGzL)D>rQ4^>|)NiQ$)EQYB*=4e!vRSfKvS(yRXb4T4 z=0!`QmC#PmhG_4XC@*nZ!dbFoNz0PKC3A9$a*lEwxk9;CxjS<2<>~Tn@`>`hkG4N#KjNU~z;vi{c;cwx$aZXSoN&@}N^m;n^upQ1neW`@Jm+HLvfkyqE8^^jVTFG14;RpP@{Py@g^4IZC^Zz~o6W||E74S6BG%z=? zH;57x71R{;CfGT+B=|vyZiq0XJ5(|>GPE&tF3dHoG;Cy*@v8N!u7@jxbHh6$uo0mV z4H2`e-B#~iJsxQhSr9q2MrTddnyYIS)+Vhz6D1kNj5-;Ojt+}%ivGa#W7aWeW4vOj zV`f+`tbMHKY)5t(dx~SnDdkMW+QpW}PR7~A?TMR;cZe^KpXR!7E4eQdJQHdX<`Vr9 zk0dT6g(bBnMJ7e%MIVY;#n-+v{i@=tg`KfG`%5fK4(`J2;_VvR?Xdf3 zsdQ;h>DV6MJ?&-mvcj_0d!zPVEnik%vyZS(xNoGwr=oMe=Kfv#KUBt7-l=k~YOPkP z-cdbwfPG-_pyR=o8s(azn)ipehwj#T)V9}Y*Oec}9L_lWv_7=H_iM)2jSUJ7MGYU1 z@Q#ce4LsV@Xw}%*q|{W>3^xm#r;bG)yZMdlH=QkpEw!z*)}rI!xbXP1Z==5*I^lhy z`y}IJ%XeDeRku;v3frOf?DmPgz@Xmo#D^7KH*><&kZ}k0<(`u)y&d8oAIZHU3 ze|F(q&bit1spqFJ#9bKcj_Q7Jan;4!Jpn!am%J}sx$J)VVy{#0xhr;8PG7aTdg>bE zTE}(E>+O9OeQiHj{Lt2K+24M{>PF{H>ziEz%LmR5It*U8<$CM#ZLizc@2tEtFcdO$ zcQ|r*xkvZnNio#z9&IX9*nWZ zp8u5o(}(f=r{t&Q6RH!9lV+2rr`)G*K3n~4{CVp0`RRh6rGKt|q5I;yUmSnwn^`q8 z{*wQ4;n(6<@~@7(UiP|s)_?Z#o8&k1bA@l^-yVI(c-Q+r?ES=i<_GMDijR69yFPh; zdbp6hu<#rAg!B8%JG^WF000SaNLh0L01m_e01m_fl`9S#0000PbVXQnQ*UN;cVTj6 z06}DLVr3vnZDD6+Qe|Oed2z{QJOBUyO-V#SR9Hvt&&vq_APfZ2?Z4?5q7fA<73t;DzTElPZdnb+W-vX2=^0GVV0s4AyTEkxc3v0wl(p9E_klFChyj!; VN_%sSbR7Ty002ovPDHLkV1hy!X)pi) literal 0 HcmV?d00001 diff --git a/applications/external/hid_app/hid.c b/applications/external/hid_app/hid.c index ea408c392876..a969a933a12e 100644 --- a/applications/external/hid_app/hid.c +++ b/applications/external/hid_app/hid.c @@ -7,6 +7,7 @@ enum HidDebugSubmenuIndex { HidSubmenuIndexKeynote, + HidSubmenuIndexKeynoteVertical, HidSubmenuIndexKeyboard, HidSubmenuIndexMedia, HidSubmenuIndexTikTok, @@ -20,6 +21,11 @@ static void hid_submenu_callback(void* context, uint32_t index) { Hid* app = context; if(index == HidSubmenuIndexKeynote) { app->view_id = HidViewKeynote; + hid_keynote_set_orientation(app->hid_keynote, false); + view_dispatcher_switch_to_view(app->view_dispatcher, HidViewKeynote); + } else if(index == HidSubmenuIndexKeynoteVertical) { + app->view_id = HidViewKeynote; + hid_keynote_set_orientation(app->hid_keynote, true); view_dispatcher_switch_to_view(app->view_dispatcher, HidViewKeynote); } else if(index == HidSubmenuIndexKeyboard) { app->view_id = HidViewKeyboard; @@ -105,6 +111,12 @@ Hid* hid_alloc(HidTransport transport) { app->device_type_submenu = submenu_alloc(); submenu_add_item( app->device_type_submenu, "Keynote", HidSubmenuIndexKeynote, hid_submenu_callback, app); + submenu_add_item( + app->device_type_submenu, + "Keynote Vertical", + HidSubmenuIndexKeynoteVertical, + hid_submenu_callback, + app); submenu_add_item( app->device_type_submenu, "Keyboard", HidSubmenuIndexKeyboard, hid_submenu_callback, app); submenu_add_item( diff --git a/applications/external/hid_app/views/hid_keynote.c b/applications/external/hid_app/views/hid_keynote.c index 5e5eeb790948..543363bf67b7 100644 --- a/applications/external/hid_app/views/hid_keynote.c +++ b/applications/external/hid_app/views/hid_keynote.c @@ -111,6 +111,91 @@ static void hid_keynote_draw_callback(Canvas* canvas, void* context) { elements_multiline_text_aligned(canvas, 91, 57, AlignLeft, AlignBottom, "Back"); } +static void hid_keynote_draw_vertical_callback(Canvas* canvas, void* context) { + furi_assert(context); + HidKeynoteModel* model = context; + + // Header + if(model->transport == HidTransportBle) { + if(model->connected) { + canvas_draw_icon(canvas, 0, 0, &I_Ble_connected_15x15); + } else { + canvas_draw_icon(canvas, 0, 0, &I_Ble_disconnected_15x15); + } + canvas_set_font(canvas, FontPrimary); + elements_multiline_text_aligned(canvas, 20, 3, AlignLeft, AlignTop, "Keynote"); + } else { + canvas_set_font(canvas, FontPrimary); + elements_multiline_text_aligned(canvas, 12, 3, AlignLeft, AlignTop, "Keynote"); + } + + canvas_draw_icon(canvas, 2, 18, &I_Pin_back_arrow_10x8); + canvas_set_font(canvas, FontSecondary); + elements_multiline_text_aligned(canvas, 15, 19, AlignLeft, AlignTop, "Hold to exit"); + + const uint8_t x_2 = 23; + const uint8_t x_1 = 2; + const uint8_t x_3 = 44; + + const uint8_t y_1 = 44; + const uint8_t y_2 = 65; + + // Up + canvas_draw_icon(canvas, x_2, y_1, &I_Button_18x18); + if(model->up_pressed) { + elements_slightly_rounded_box(canvas, x_2 + 3, y_1 + 2, 13, 13); + canvas_set_color(canvas, ColorWhite); + } + hid_keynote_draw_arrow(canvas, x_2 + 9, y_1 + 6, CanvasDirectionBottomToTop); + canvas_set_color(canvas, ColorBlack); + + // Down + canvas_draw_icon(canvas, x_2, y_2, &I_Button_18x18); + if(model->down_pressed) { + elements_slightly_rounded_box(canvas, x_2 + 3, y_2 + 2, 13, 13); + canvas_set_color(canvas, ColorWhite); + } + hid_keynote_draw_arrow(canvas, x_2 + 9, y_2 + 10, CanvasDirectionTopToBottom); + canvas_set_color(canvas, ColorBlack); + + // Left + canvas_draw_icon(canvas, x_1, y_2, &I_Button_18x18); + if(model->left_pressed) { + elements_slightly_rounded_box(canvas, x_1 + 3, y_2 + 2, 13, 13); + canvas_set_color(canvas, ColorWhite); + } + hid_keynote_draw_arrow(canvas, x_1 + 7, y_2 + 8, CanvasDirectionRightToLeft); + canvas_set_color(canvas, ColorBlack); + + // Right + canvas_draw_icon(canvas, x_3, y_2, &I_Button_18x18); + if(model->right_pressed) { + elements_slightly_rounded_box(canvas, x_3 + 3, y_2 + 2, 13, 13); + canvas_set_color(canvas, ColorWhite); + } + hid_keynote_draw_arrow(canvas, x_3 + 11, y_2 + 8, CanvasDirectionLeftToRight); + canvas_set_color(canvas, ColorBlack); + + // Ok + canvas_draw_icon(canvas, 2, 86, &I_Space_60x18); + if(model->ok_pressed) { + elements_slightly_rounded_box(canvas, 5, 88, 55, 13); + canvas_set_color(canvas, ColorWhite); + } + canvas_draw_icon(canvas, 11, 90, &I_Ok_btn_9x9); + elements_multiline_text_aligned(canvas, 26, 98, AlignLeft, AlignBottom, "Space"); + canvas_set_color(canvas, ColorBlack); + + // Back + canvas_draw_icon(canvas, 2, 107, &I_Space_60x18); + if(model->back_pressed) { + elements_slightly_rounded_box(canvas, 5, 109, 55, 13); + canvas_set_color(canvas, ColorWhite); + } + canvas_draw_icon(canvas, 11, 111, &I_Pin_back_arrow_10x8); + elements_multiline_text_aligned(canvas, 26, 119, AlignLeft, AlignBottom, "Back"); +} + static void hid_keynote_process(HidKeynote* hid_keynote, InputEvent* event) { with_view_model( hid_keynote->view, @@ -212,3 +297,16 @@ void hid_keynote_set_connected_status(HidKeynote* hid_keynote, bool connected) { with_view_model( hid_keynote->view, HidKeynoteModel * model, { model->connected = connected; }, true); } + +void hid_keynote_set_orientation(HidKeynote* hid_keynote, bool vertical) { + furi_assert(hid_keynote); + + if(vertical) { + view_set_draw_callback(hid_keynote->view, hid_keynote_draw_vertical_callback); + view_set_orientation(hid_keynote->view, ViewOrientationVerticalFlip); + + } else { + view_set_draw_callback(hid_keynote->view, hid_keynote_draw_callback); + view_set_orientation(hid_keynote->view, ViewOrientationHorizontal); + } +} diff --git a/applications/external/hid_app/views/hid_keynote.h b/applications/external/hid_app/views/hid_keynote.h index 4d4a0a9b1a05..84bfed4ce415 100644 --- a/applications/external/hid_app/views/hid_keynote.h +++ b/applications/external/hid_app/views/hid_keynote.h @@ -12,3 +12,5 @@ void hid_keynote_free(HidKeynote* hid_keynote); View* hid_keynote_get_view(HidKeynote* hid_keynote); void hid_keynote_set_connected_status(HidKeynote* hid_keynote, bool connected); + +void hid_keynote_set_orientation(HidKeynote* hid_keynote, bool vertical); diff --git a/applications/external/mfkey32/mfkey32.c b/applications/external/mfkey32/mfkey32.c index 3f1142277419..5e790b01f6e4 100644 --- a/applications/external/mfkey32/mfkey32.c +++ b/applications/external/mfkey32/mfkey32.c @@ -161,7 +161,7 @@ static const uint8_t lookup2[256] = { 2, 6, 6, 6, 6, 2, 2, 6, 6, 2, 6, 2, 2, 2, 6, 2, 2, 6, 6, 6, 6, 2, 2, 6, 6, 2, 6, 2, 2, 2, 6, 2, 2, 6, 6, 6, 6, 2, 2, 6, 6, 2, 6, 2, 2, 2, 6, 2, 2, 6, 6, 6, 6}; -uint32_t old_prng_successor(uint32_t x, uint32_t n) { +uint32_t prng_successor(uint32_t x, uint32_t n) { SWAPENDIAN(x); while(n--) x = x >> 1 | (x >> 16 ^ x >> 18 ^ x >> 19 ^ x >> 21) << 31; return SWAPENDIAN(x); @@ -945,7 +945,7 @@ MfClassicNonceArray* napi_mf_classic_nonce_array_alloc( next_line_cstr = endptr; } (program_state->total)++; - uint32_t p64b = old_prng_successor(res.nt1, 64); + uint32_t p64b = prng_successor(res.nt1, 64); if((system_dict_exists && napi_key_already_found_for_nonce( system_dict, res.uid ^ res.nt1, res.nr1_enc, p64b, res.ar1_enc)) || @@ -1051,8 +1051,8 @@ void mfkey32(ProgramState* program_state) { // TODO: Work backwards on this array and free memory for(i = 0; i < nonce_arr->total_nonces; i++) { MfClassicNonce next_nonce = nonce_arr->remaining_nonce_array[i]; - uint32_t p64 = old_prng_successor(next_nonce.nt0, 64); - uint32_t p64b = old_prng_successor(next_nonce.nt1, 64); + uint32_t p64 = prng_successor(next_nonce.nt0, 64); + uint32_t p64b = prng_successor(next_nonce.nt1, 64); if(key_already_found_for_nonce( keyarray, keyarray_size, diff --git a/applications/external/music_player/application.fam b/applications/external/music_player/application.fam index 3414c0a482d3..c9cd5e44de7e 100644 --- a/applications/external/music_player/application.fam +++ b/applications/external/music_player/application.fam @@ -7,18 +7,10 @@ App( "gui", "dialogs", ], - provides=["music_player_start"], stack_size=2 * 1024, order=20, fap_icon="icons/music_10px.png", fap_category="Media", fap_icon_assets="icons", -) - -App( - appid="music_player_start", - apptype=FlipperAppType.STARTUP, - entry_point="music_player_on_system_start", - requires=["music_player"], - order=30, + fap_libs=["music_worker"], ) diff --git a/applications/external/music_player/music_player.c b/applications/external/music_player/music_player.c index 2380d7d17beb..8b0b758c1c15 100644 --- a/applications/external/music_player/music_player.c +++ b/applications/external/music_player/music_player.c @@ -1,4 +1,4 @@ -#include "music_player_worker.h" +#include #include #include @@ -34,7 +34,7 @@ typedef struct { ViewPort* view_port; Gui* gui; - MusicPlayerWorker* worker; + MusicWorker* worker; } MusicPlayer; static const float MUSIC_PLAYER_VOLUMES[] = {0, .25, .5, .75, 1}; @@ -218,7 +218,7 @@ static void input_callback(InputEvent* input_event, void* ctx) { } } -static void music_player_worker_callback( +static void music_worker_callback( uint8_t semitone, uint8_t dots, uint8_t duration, @@ -250,7 +250,7 @@ static void music_player_worker_callback( void music_player_clear(MusicPlayer* instance) { memset(instance->model->duration_history, 0xff, MUSIC_PLAYER_SEMITONE_HISTORY_SIZE); memset(instance->model->semitone_history, 0xff, MUSIC_PLAYER_SEMITONE_HISTORY_SIZE); - music_player_worker_clear(instance->worker); + music_worker_clear(instance->worker); } MusicPlayer* music_player_alloc() { @@ -263,10 +263,9 @@ MusicPlayer* music_player_alloc() { instance->input_queue = furi_message_queue_alloc(8, sizeof(InputEvent)); - instance->worker = music_player_worker_alloc(); - music_player_worker_set_volume( - instance->worker, MUSIC_PLAYER_VOLUMES[instance->model->volume]); - music_player_worker_set_callback(instance->worker, music_player_worker_callback, instance); + instance->worker = music_worker_alloc(); + music_worker_set_volume(instance->worker, MUSIC_PLAYER_VOLUMES[instance->model->volume]); + music_worker_set_callback(instance->worker, music_worker_callback, instance); music_player_clear(instance); @@ -286,7 +285,7 @@ void music_player_free(MusicPlayer* instance) { furi_record_close(RECORD_GUI); view_port_free(instance->view_port); - music_player_worker_free(instance->worker); + music_worker_free(instance->worker); furi_message_queue_free(instance->input_queue); @@ -330,12 +329,12 @@ int32_t music_player_app(void* p) { } } - if(!music_player_worker_load(music_player->worker, furi_string_get_cstr(file_path))) { + if(!music_worker_load(music_player->worker, furi_string_get_cstr(file_path))) { FURI_LOG_E(TAG, "Unable to load file"); break; } - music_player_worker_start(music_player->worker); + music_worker_start(music_player->worker); InputEvent input; while(furi_message_queue_get(music_player->input_queue, &input, FuriWaitForever) == @@ -349,11 +348,11 @@ int32_t music_player_app(void* p) { } else if(input.key == InputKeyUp) { if(music_player->model->volume < COUNT_OF(MUSIC_PLAYER_VOLUMES) - 1) music_player->model->volume++; - music_player_worker_set_volume( + music_worker_set_volume( music_player->worker, MUSIC_PLAYER_VOLUMES[music_player->model->volume]); } else if(input.key == InputKeyDown) { if(music_player->model->volume > 0) music_player->model->volume--; - music_player_worker_set_volume( + music_worker_set_volume( music_player->worker, MUSIC_PLAYER_VOLUMES[music_player->model->volume]); } @@ -361,7 +360,7 @@ int32_t music_player_app(void* p) { view_port_update(music_player->view_port); } - music_player_worker_stop(music_player->worker); + music_worker_stop(music_player->worker); if(p && strlen(p)) break; // Exit instead of going to browser if launched with arg music_player_clear(music_player); } while(1); diff --git a/applications/external/music_player/music_player_cli.c b/applications/external/music_player/music_player_cli.c deleted file mode 100644 index 90060d7ee00b..000000000000 --- a/applications/external/music_player/music_player_cli.c +++ /dev/null @@ -1,48 +0,0 @@ -#include -#include -#include -#include "music_player_worker.h" - -static void music_player_cli(Cli* cli, FuriString* args, void* context) { - UNUSED(context); - MusicPlayerWorker* music_player_worker = music_player_worker_alloc(); - Storage* storage = furi_record_open(RECORD_STORAGE); - - do { - if(storage_common_stat(storage, furi_string_get_cstr(args), NULL) == FSE_OK) { - if(!music_player_worker_load(music_player_worker, furi_string_get_cstr(args))) { - printf("Failed to open file %s\r\n", furi_string_get_cstr(args)); - break; - } - } else { - if(!music_player_worker_load_rtttl_from_string( - music_player_worker, furi_string_get_cstr(args))) { - printf("Argument is not a file or RTTTL\r\n"); - break; - } - } - - printf("Press CTRL+C to stop\r\n"); - music_player_worker_set_volume(music_player_worker, 1.0f); - music_player_worker_start(music_player_worker); - while(!cli_cmd_interrupt_received(cli)) { - furi_delay_ms(50); - } - music_player_worker_stop(music_player_worker); - } while(0); - - furi_record_close(RECORD_STORAGE); - music_player_worker_free(music_player_worker); -} - -void music_player_on_system_start() { -#ifdef SRV_CLI - Cli* cli = furi_record_open(RECORD_CLI); - - cli_add_command(cli, "music_player", CliCommandFlagDefault, music_player_cli, NULL); - - furi_record_close(RECORD_CLI); -#else - UNUSED(music_player_cli); -#endif -} diff --git a/applications/external/music_player/music_player_worker.h b/applications/external/music_player/music_player_worker.h deleted file mode 100644 index 00320b11fe5d..000000000000 --- a/applications/external/music_player/music_player_worker.h +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once - -#include -#include - -typedef void (*MusicPlayerWorkerCallback)( - uint8_t semitone, - uint8_t dots, - uint8_t duration, - float position, - void* context); - -typedef struct MusicPlayerWorker MusicPlayerWorker; - -MusicPlayerWorker* music_player_worker_alloc(); - -void music_player_worker_clear(MusicPlayerWorker* instance); - -void music_player_worker_free(MusicPlayerWorker* instance); - -bool music_player_worker_load(MusicPlayerWorker* instance, const char* file_path); - -bool music_player_worker_load_fmf_from_file(MusicPlayerWorker* instance, const char* file_path); - -bool music_player_worker_load_rtttl_from_file(MusicPlayerWorker* instance, const char* file_path); - -bool music_player_worker_load_rtttl_from_string(MusicPlayerWorker* instance, const char* string); - -void music_player_worker_set_callback( - MusicPlayerWorker* instance, - MusicPlayerWorkerCallback callback, - void* context); - -void music_player_worker_set_volume(MusicPlayerWorker* instance, float volume); - -void music_player_worker_start(MusicPlayerWorker* instance); - -void music_player_worker_stop(MusicPlayerWorker* instance); diff --git a/applications/external/nfc_magic/lib/magic/magic.h b/applications/external/nfc_magic/lib/magic/magic.h deleted file mode 100644 index 15e793d894cb..000000000000 --- a/applications/external/nfc_magic/lib/magic/magic.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include - -bool magic_wupa(); - -bool magic_read_block(uint8_t block_num, MfClassicBlock* data); - -bool magic_data_access_cmd(); - -bool magic_write_blk(uint8_t block_num, MfClassicBlock* data); - -bool magic_wipe(); - -void magic_deactivate(); diff --git a/applications/external/nfc_magic/nfc_magic_i.h b/applications/external/nfc_magic/nfc_magic_i.h index 4d6b89103d4e..88bc5706fa86 100644 --- a/applications/external/nfc_magic/nfc_magic_i.h +++ b/applications/external/nfc_magic/nfc_magic_i.h @@ -46,6 +46,7 @@ enum NfcMagicCustomEvent { struct NfcMagicDevice { MagicType type; uint32_t cuid; + uint8_t uid_len; uint32_t password; }; diff --git a/applications/external/nfc_magic/nfc_magic_worker.c b/applications/external/nfc_magic/nfc_magic_worker.c index 9ee7fd3eecdf..eb715fe0ddaa 100644 --- a/applications/external/nfc_magic/nfc_magic_worker.c +++ b/applications/external/nfc_magic/nfc_magic_worker.c @@ -107,14 +107,7 @@ void nfc_magic_worker_write(NfcMagicWorker* nfc_magic_worker) { } magic_activate(); if(magic_gen1_wupa()) { - if(!magic_gen1_data_access_cmd()) { - FURI_LOG_E( - TAG, "No card response to data access command (not a magic card)"); - nfc_magic_worker->callback( - NfcMagicWorkerEventWrongCard, nfc_magic_worker->context); - done = true; - break; - } + magic_gen1_data_access_cmd(); MfClassicData* mfc_data = &dev_data->mf_classic_data; for(size_t i = 0; i < 64; i++) { @@ -296,6 +289,7 @@ void nfc_magic_worker_write(NfcMagicWorker* nfc_magic_worker) { } void nfc_magic_worker_check(NfcMagicWorker* nfc_magic_worker) { + FuriHalNfcDevData nfc_data = {}; NfcMagicDevice* magic_dev = nfc_magic_worker->magic_dev; bool card_found_notified = false; uint8_t gen4_config[MAGIC_GEN4_CONFIG_LEN]; @@ -310,32 +304,44 @@ void nfc_magic_worker_check(NfcMagicWorker* nfc_magic_worker) { card_found_notified = true; } - furi_hal_nfc_activate_nfca(200, &magic_dev->cuid); - nfc_magic_worker->callback(NfcMagicWorkerEventSuccess, nfc_magic_worker->context); - break; - } - - magic_deactivate(); - furi_delay_ms(300); - magic_activate(); - - furi_hal_nfc_activate_nfca(200, &magic_dev->cuid); - if(magic_gen4_get_cfg(magic_dev->password, gen4_config)) { - magic_dev->type = MagicTypeGen4; - if(!card_found_notified) { - nfc_magic_worker->callback( - NfcMagicWorkerEventCardDetected, nfc_magic_worker->context); - card_found_notified = true; + if(furi_hal_nfc_detect(&nfc_data, 200)) { + magic_dev->cuid = nfc_data.cuid; + magic_dev->uid_len = nfc_data.uid_len; + } else { + // wrong BCC + magic_dev->uid_len = 4; } - nfc_magic_worker->callback(NfcMagicWorkerEventSuccess, nfc_magic_worker->context); break; - } + } else { + magic_deactivate(); + magic_activate(); + if(furi_hal_nfc_detect(&nfc_data, 200)) { + magic_dev->cuid = nfc_data.cuid; + magic_dev->uid_len = nfc_data.uid_len; + if(magic_gen4_get_cfg(magic_dev->password, gen4_config)) { + magic_dev->type = MagicTypeGen4; + if(!card_found_notified) { + nfc_magic_worker->callback( + NfcMagicWorkerEventCardDetected, nfc_magic_worker->context); + card_found_notified = true; + } - if(card_found_notified) { - nfc_magic_worker->callback( - NfcMagicWorkerEventNoCardDetected, nfc_magic_worker->context); - card_found_notified = false; + nfc_magic_worker->callback( + NfcMagicWorkerEventSuccess, nfc_magic_worker->context); + } else { + nfc_magic_worker->callback( + NfcMagicWorkerEventWrongCard, nfc_magic_worker->context); + card_found_notified = true; + } + break; + } else { + if(card_found_notified) { + nfc_magic_worker->callback( + NfcMagicWorkerEventNoCardDetected, nfc_magic_worker->context); + card_found_notified = false; + } + } } magic_deactivate(); diff --git a/applications/external/nfc_magic/scenes/nfc_magic_scene_file_select.c b/applications/external/nfc_magic/scenes/nfc_magic_scene_file_select.c index a7d1703d1378..04b7024ffbd5 100644 --- a/applications/external/nfc_magic/scenes/nfc_magic_scene_file_select.c +++ b/applications/external/nfc_magic/scenes/nfc_magic_scene_file_select.c @@ -1,14 +1,14 @@ #include "../nfc_magic_i.h" static bool nfc_magic_scene_file_select_is_file_suitable(NfcMagic* nfc_magic) { - NfcDevice* nfc_device = nfc_magic->source_dev; - if(nfc_device->format == NfcDeviceSaveFormatMifareClassic) { + NfcDevice* nfc_dev = nfc_magic->source_dev; + if(nfc_dev->format == NfcDeviceSaveFormatMifareClassic) { switch(nfc_magic->dev->type) { case MagicTypeClassicGen1: case MagicTypeClassicDirectWrite: case MagicTypeClassicAPDU: - if((nfc_device->dev_data.mf_classic_data.type != MfClassicType1k) || - (nfc_device->dev_data.nfc_data.uid_len != 4)) { + if((nfc_dev->dev_data.mf_classic_data.type != MfClassicType1k) || + (nfc_dev->dev_data.nfc_data.uid_len != nfc_magic->dev->uid_len)) { return false; } return true; @@ -19,15 +19,15 @@ static bool nfc_magic_scene_file_select_is_file_suitable(NfcMagic* nfc_magic) { return false; } } else if( - (nfc_device->format == NfcDeviceSaveFormatMifareUl) && - (nfc_device->dev_data.nfc_data.uid_len == 7)) { + (nfc_dev->format == NfcDeviceSaveFormatMifareUl) && + (nfc_dev->dev_data.nfc_data.uid_len == 7)) { switch(nfc_magic->dev->type) { case MagicTypeUltralightGen1: case MagicTypeUltralightDirectWrite: case MagicTypeUltralightC_Gen1: case MagicTypeUltralightC_DirectWrite: case MagicTypeGen4: - switch(nfc_device->dev_data.mf_ul_data.type) { + switch(nfc_dev->dev_data.mf_ul_data.type) { case MfUltralightTypeNTAGI2C1K: case MfUltralightTypeNTAGI2C2K: case MfUltralightTypeNTAGI2CPlus1K: diff --git a/applications/external/nfc_magic/scenes/nfc_magic_scene_not_magic.c b/applications/external/nfc_magic/scenes/nfc_magic_scene_not_magic.c index b87f7f383e86..b4f579f444d5 100644 --- a/applications/external/nfc_magic/scenes/nfc_magic_scene_not_magic.c +++ b/applications/external/nfc_magic/scenes/nfc_magic_scene_not_magic.c @@ -13,11 +13,10 @@ void nfc_magic_scene_not_magic_on_enter(void* context) { notification_message(nfc_magic->notifications, &sequence_error); - // widget_add_icon_element(widget, 73, 17, &I_DolphinCommon_56x48); widget_add_string_element( widget, 3, 4, AlignLeft, AlignTop, FontPrimary, "This is wrong card"); widget_add_string_multiline_element( - widget, 4, 17, AlignLeft, AlignTop, FontSecondary, "Not a magic\ncard"); + widget, 4, 17, AlignLeft, AlignTop, FontSecondary, "Not magic or unsupported\ncard"); widget_add_button_element( widget, GuiButtonTypeLeft, "Retry", nfc_magic_scene_not_magic_widget_callback, nfc_magic); diff --git a/applications/external/nfc_rfid_detector/application.fam b/applications/external/nfc_rfid_detector/application.fam new file mode 100644 index 000000000000..70c91bc84372 --- /dev/null +++ b/applications/external/nfc_rfid_detector/application.fam @@ -0,0 +1,13 @@ +App( + appid="nfc_rfid_detector", + name="NFC/RFID detector", + apptype=FlipperAppType.EXTERNAL, + targets=["f7"], + entry_point="nfc_rfid_detector_app", + requires=["gui"], + stack_size=4 * 1024, + order=50, + fap_icon="nfc_rfid_detector_10px.png", + fap_category="Tools", + fap_icon_assets="images", +) diff --git a/applications/external/nfc_rfid_detector/helpers/nfc_rfid_detector_event.h b/applications/external/nfc_rfid_detector/helpers/nfc_rfid_detector_event.h new file mode 100644 index 000000000000..bbffe2938e44 --- /dev/null +++ b/applications/external/nfc_rfid_detector/helpers/nfc_rfid_detector_event.h @@ -0,0 +1,7 @@ +#pragma once + +typedef enum { + //NfcRfidDetectorCustomEvent + NfcRfidDetectorCustomEventStartId = 100, + +} NfcRfidDetectorCustomEvent; diff --git a/applications/external/nfc_rfid_detector/helpers/nfc_rfid_detector_types.h b/applications/external/nfc_rfid_detector/helpers/nfc_rfid_detector_types.h new file mode 100644 index 000000000000..5d44b09b7f28 --- /dev/null +++ b/applications/external/nfc_rfid_detector/helpers/nfc_rfid_detector_types.h @@ -0,0 +1,15 @@ +#pragma once + +#include +#include + +#define NFC_RFID_DETECTOR_VERSION_APP "0.1" +#define NFC_RFID_DETECTOR_DEVELOPED "SkorP" +#define NFC_RFID_DETECTOR_GITHUB "https://github.com/flipperdevices/flipperzero-firmware" + +typedef enum { + NfcRfidDetectorViewVariableItemList, + NfcRfidDetectorViewSubmenu, + NfcRfidDetectorViewFieldPresence, + NfcRfidDetectorViewWidget, +} NfcRfidDetectorView; diff --git a/applications/external/nfc_rfid_detector/images/Modern_reader_18x34.png b/applications/external/nfc_rfid_detector/images/Modern_reader_18x34.png new file mode 100644 index 0000000000000000000000000000000000000000..b19c0f30c9f3928d3129acc9da92d5a9e962d084 GIT binary patch literal 3670 zcmaJ@c{r478-GRiEm@Lu#t;&-TAE=jGh>S(jEuAxj4^2zV`?lVl&v}>Wo<-dUn)uo zWeX)lN%pcNI{1zyPGY`s&gp#LA79^lz3=-x&wbs$-~GFn_qyJMgHE9q!yUB8;Xo`l)1P*d0stWcJU1%QZCV+#GO~nqh>yJH zz;sm-2f1P|MJgt1>uE^HABfk;?N@SX*k)}lqSlrZFPxYdd0ELtU;3itd$9?PTZ!jy z$6tK8_A&f+;JezDPaPW%`^=|G7kQOkV)f$Esdh*gqe$r@?CxzJ&bKzVe4Kz-MoDV1 z0D19BKaJpZO(9@4!pv+RxL)ijAQbXON*t&sWYxoV#qs54uo*{$A}O1A7Dgbe50Ok@OvlkEv2fW)fHA8?4 z8GxeAf`{4f`^x2~^aPd4s4%P6LRm+7i5mood3Zo}>vr0!>{B!*Zy{$|LK;IeR1r~z zavv670YFZ&k|5i~^^i{4^3G1<#46e21~bn@`CuQP@r}u@5|$+ZeB?xQZ|FlScSf3u zM$$KK?U@q^I3|^IYUPrDg`DL>AZL2OW0AF48|&OF)&2dG6BF+bG-JKUFFnp~P#cfe zd#s=QBf{+a%JPS&V_H#&qfxdZs~;L)Eji}x>bfd%!Dr}GlI{0LQvC1gZ@|s=KGh^W z#c>yfphSG;@-q zi($!qBa3G@=+;I_h*-6WZzpRE#0&XcBxxp!t7OEiYBbo1C|uG4y@*$I0Xrlc*}+{e z5<%{E>I)e57F663nr15gw%-SrN|&_kymzQnxF%uQ zx9dJvL?Oz$Ucy*}iv^K)TiKBuNlx$W3PHQH47UwPm`Dg;aB0*5rxZFo(0;P*kLDdd z2zVUHPG9q#Leh4qe0V&r*+fer0f*43zOu#s{vBeELXS-k!&P%yzbMPlZl`9-ivhpD z3Nh3*ebBzPmlcJP#gq8d4OxNMU zT;evPq{G;<+$z_*E^&q14NqmFI?gNGJLHw!y8dQofJ(p$?e1sJlWoJ-cRQuM_ULJ! zw*8#;S$K&nEfcGBzBQhztD3b#YzI}9yW?)UW4`K}ORB9zmvhMMG|jQOWccj2fw(fxlxNu z3*(BZg-oKwoe0nM1X0f>$0ldo9haQ@$H!}1KvKS{l_B~Xfifkrr=pCSweNTIpE<2p zlfJHAa|u&il#9Y44-290%eK-a(MoA8(Lw3X9cIss zf|zFN(AL4*TbL7m};H&2IPF{Awe2nbvY-Tx*=(LT|aPEvl`d?Le3z z%w@U~s`K~en>w00wsySgxYhA4!zc>_??X&wO=b0EjXv@|9CBE{s<7%Y#lB+VaK7hU zRV^dtFv>HJQrA-;HY|p!zvYLWz1=UU|P9@pzs7?2NuX<5c^hovII|O` zW;Mlf{?(j)bKHE~%wz;H;(7d)N&Ta?NA1o{%D3JMF*rFDrSyLgmYQ7PfQuBua)hsy9->&~D@I`1iOYdb^z# z?DPm>SAR>cH44>wj?B}atiGUAbfwl&#&I|covoaC8bn86&~@L>rx?WL5MijC)tOOK$tuZz71th`dX)zd(-3Y-6#cv!bjPppDU@$i4vk?<0gT9Uo5 zWA;_$%fTxqH|B5hXB8S1K3=WLi*@iYP$zw=D?Nd#FbfJDlpI&ux-a&SXsOxbi&c8` zUgwfokF@fLI_)q*VAQdOm(dLmg#y1wxl2yQoc%J?H+$5X1oa$!Nd6YfQ!`gexLB?@ zsFJ31?!E3%$fQ~v^X0RQp=%F{N}8+vy8L_mr$3DtWP8b`7N>nmlV!;C4?K_=J@jC9 z`K$FHG_6B-u;zRfuKM;fv&XfRf)||~rWV9I#3kZ4qVZhM@I!LnDx-T&Exh)t;cvZz zUbQRh<}aQOx(m4zdi{GTYxZlED;DJm#nY>)YxJXKPV}JJR^cAubumrZs=n&Cz3M#} zqHEH-eP3*4TYq`F!JFqA$QaAG|9YckOp}EVotR#c7+u*dgC012IlT0v*qdKYt5emX zC$O0dnKoH&nQLA?UQe7~nRmaN843GtJNS#-4MQ`}&;yIa7qo%t=r<|Ug|5rI>%6lO zkUxgJ2X9q{Px*F^o{(eCKauBr?6Kxwnli05?L4yZn6pqZIJw>9u}9`z^l|zOXU1$J z<&AS|&5fGO^6Ddj)pKEW55xUerq!}dI)|6)LVs80zw6CLVTS7#!z(a2{al^7vRdcb<4cyaR{gl)xLymdjiLARL+4J^b8{BEhiq3wW6pPNBrhk);kG7a zB(=xN#D2-%Z;nEZS+LiqzZc-T{JONWRW@#Iw3n+WLnBsuzw~u>r+4S3Eu^J9qo2uJ zpQ-<%dUvp;v1Rwu7a>Uav86+6vklxKuKN7#Q90*{GoW+2{D431FT1@iSW8h&N#TnK zr!Rh=H@X%r_^(vuSd%zzOn(lS%%%WVeoP+<$evE7Qd}uyztEr;6f*!2)};|i91_71 z?aQP?$eTWp5IReM1^_dQ5Ej`tkir4^P^dHp20UN$3=E?AVZa_n1Q>yZqXf|G!q^nI zFejpKSfDS;4{Tu$G7CWq2_OC4Htbb@3!GBjuP%~%ok9RP~ zmGU3G|C2bF7|NnRT`9rLQ*2*B@BB44L$S~}HigV#vWZOQ$sdJ07{KH(g9Df>5CRE- zgLDaGUm9c6viDC2fq=GW1ars?Uy3~*0~U}#Xf!`G9uC9W*z89l_alwqaBKX2BnoZ? zvw|5T_oLv3CfFZXJk$3SoxWBq=v1@TiXR3HYr+1vl>^$(L^fHt@P46oqu&-haqf|+LvhFcAp;MtHb?>>aojMU&+$&Jw2#YyGzNAg?=0N~xO|1%9#hzl z?cEASvP%gSwpPE+s1{*#d-3TN&&Ml8>K`_AH+6iBd^^X2G{h(8k literal 0 HcmV?d00001 diff --git a/applications/external/nfc_rfid_detector/images/Move_flipper_26x39.png b/applications/external/nfc_rfid_detector/images/Move_flipper_26x39.png new file mode 100644 index 0000000000000000000000000000000000000000..ff4af9ff05989e5ff04d3888971b7f7801c59ed4 GIT binary patch literal 3698 zcmaJ@c{r478-E?LZ^;tU8AG<1)zVDHGBb8V7#V3BV~j~-#+b52_N6)`*&At*T}3IO zY*|ByvR6pz;L8#x;Tz|i&iDQC^}W~ozR&aA*Zuq5zk7MF>rFi5U?m}{Bnkk4gpD=c znYSwO9!+6>-dlrJm<#}-7IYl$kPQw8VzHUt^wU%T2pZ|Mg~ijYkxm8?;ziiKJKsjPHn+T+f|x~$s*VSD1Yq&{J@j`Bss@YQot4%i7t$O2{| zN!UApnI&HYH&ep}$P)lgc2YbifkS%0NzL;g`hf`UT2?3@;Bi$|jxR3-0PUhC-~pe5 zKxxn63l;zg2FQBbHKTwxdH~GE&D$Ed_Xw!(mKLi3gv9}vQ$nmZAP@?iY*SMU0%EcN zS<6K?<1hQmrDt?_mCC9xu2x4`M0yD8`3t$ZLH25O+bHapH6;H+&NhQI24^WEBK4)- zF1-MNyc9WJwo4m9-IC?q-G)h3k|*>&JrmpldwNc8PWP0s%mCmWC%ku47h0(laZoUV zv3YafynxSfvAi>@7riT_%pL-Hv%_vntnJ!Z+_+plG&DUm^~Sat>p|{t3)`eMo~U=* zIQ>Vs@%Po0w@=@zMzL zhS~5+OPD{xC;DAa;MRiahE?7^Ai~?`ia!7x$E!n#9hIi7!T^BJi`2PiuDsl^Ten_t zPs5JU2C?ra4P&tC&5c-Ttf*JS9`;G?(kQG}T-QAnos-a4W-9viPCjv|EJ;YC>tjg_ zOX?e0IJZHoHc~{uyiIr)S#>yp&+`IFElF4*D|St_!CFA(qB^KOLDmUumttTIcfLRb zxmv3%V%Wc+;*VNBNjcaCAfmp<)mp)?MpigsUWq@%RTmm5#aP}Hd+Ei2XD7?&<-BA+ zP{Ld?yfO2##7Am4*#y@LtN*xL2-$oZ25D)+-anu#l1k~k4=xoiX;Hd&xRk#pafQ-z zKTtp>(xP6(P#_QsBJVY~CfSo5-dGoc_NeRc92PMW;g4}@)C8v%+C9*Cvh$DT-JS?| zJjq&DZBQn87gRbl0oQD#E|Z8uXjWhT#peEPVxLT(WuKq3+N^F-j=r^$T59{Smv4m- z>Z&eie_QMncdBU$Ii)>%emu}t>U!wwEnapH4|a(dMn#`tndbL zr$O=&Y}t(}=ethvg}e06WTU#GCT?7yhkN`x7~KWENlNo6rzNjgFsd$jYL8BCi^Bw+-;}4`zI!ATR>tI#mXRERbPpcxHFLk%^LT+hR&VUsma_> zskw+LF1mrjA#IUvmCj37y-kHCGyT`DaU4WuvVhNU-MfvS8~8Jg zRiLdSUz~8qn#^$dmcLm_U81)fom8J>v@lw3X$WelYSvJ&nLMaIaX;|#x2`7SW{M0u(P1rA=RNIcaYX}?@LvCRna5Gd(&?ON6M=hRbgbB zrvmNK^YW(o)VkELCt<&BV1y*%ha^i>j;MqOJYdVB52MGkyRXfghCN?SpM}y$J<>gI zkdsxrI<=eWT$h}FE1CkWIv{!};bNj)R3{|E1d^lNGS*f%Wy@LdKlU!9Z-tvvnbSB| zIC6L1aGpLNKYIOz{&nqKcVxiJrZ(JLr|Di(vFm9t--*(2N1S6M?ct0Xlmbn0D|>zK zQGQ_YDtSS{49%He%Bwb)Gf$2xi<)jIQ}t>4{c@S=>P%*LN;h3H z_E7l8!Iwhh59EtY;o_RH@v&}krb(;>l2R``!yvGC6c;do|AtS;kLS?fj;OnOwgx&T z#gJ3R!$wc^pP05lyxm_6khmn9({_7M5S?;Eztc}AzRxYizvsRen+#RRgti@H1>fjy zT#hY}FM`PEqSMXn6C4g){g=74PNDpzeT%yS_a%u2H>xz!z|da9-h?-}qdI#X7Oiy% zAy8X%D)Rmq>RT%pRkBCmn?bsi8Sg_Ri@r5cK#(-nV zoLfeDc%4QF!8h`FLq}A@Lq6ZnVy>dov08Z@mO&+K@XHG1_yQAu;PSC4m}_w0vpy<88;^x}*U8IpbyL&FawCJsNCTls1+ z0?p{s8mWn{!d2gTX8gF8TF~CzbblK(<*I3UV)5)+`a0uSnFGUru9d%!e?v%3vg&p9s{xfh4AD7x zaQ|m3$<|+=ZgLj_^&|`>Tz|XP@?MRF51yJ`6`5GwD}f$9dnvT^olyU;XH{q_&{Np# z#cazQm+W;9Pmd>#FHCv|KaGccw;K6X>YBc>d$8>iv7J6V8`YmmTkN^SP2+}zL;e^& zIdZcqbcWJBaY~B0@I;#PuFqoY;>^L?gWX3LA9EHfMy7YUJ$B2!i$1~l#Q9{rncDBz zT63)?yS)0SZ}ogg-NR7t)mi0SqwcZgy5KMJTZ03+D9l*hQV4VP`RdAq{8%_!bECVn zW++f|zO2@<_QbN;ocR!LEPlY$V{`P)!sz)^^?`Xyy`xsEg0ay(n<*>FQn($-S;?Jo z5^DFJzhN;xeA*%H#^G}+7iX00P$A#(52_&- z286ur0|{cVcxV7HHVtBtDZW$=$dgK=`(eNfHP65xx)%oQWF zf{Y+=Jqip40~w(pR4+2Z6X{K+=z(`CL173e0-?wA&tJ+l*vS<{1tK%oF=p77W%uw0;49SBh6NXb_nNg+pN5S^aP%5dOa_gYl1d0LPj7 zAHDyRIDi<;qC%ai0n9UO3a@wGYTKb$XdIhL<}lerCiC=s z1Tuy0w{6k>6G9-MZTtc_WIqbk29E*rNFa2&7a9+TVJ$5W7$FZJ4d8GK`~f5iZVoet z86pp$;QB_`A6Pt-a)v?m&>7lDnimJQg+KMf>kx^NwAax?J03VOnh9H^F_DX?m;7uKb-foq?HQV>E-q&-2^V QfL1Vgy85}Sb4q9e0PSTwjsO4v literal 0 HcmV?d00001 diff --git a/applications/external/nfc_rfid_detector/images/Rfid_detect_45x30.png b/applications/external/nfc_rfid_detector/images/Rfid_detect_45x30.png new file mode 100644 index 0000000000000000000000000000000000000000..35c205049bc5a6c7f0bb13a0cb3057963a023c6e GIT binary patch literal 158 zcmeAS@N?(olHy`uVBq!ia0vp^xG+l41V{G`^6RB9^&ce?Q{EhH1o(i zcG0sF=jLrIU`gfJ9e<(w?c#$+`{GybuV0XK^{NaL55t;h1_!r?84rQRGkCiCxvXf4IeWS|hDc0ZJK-P~g93;1_80%_ zf0mxq_>?eVL9oQDG>54hmUMGg2<9ZE<@p-^(r|y*a$w%vQ*}A2s_`AWqh21A3+I&= XdhU3CV!O&Kpm7YIu6{1-oD!M<1Jf%z literal 0 HcmV?d00001 diff --git a/applications/external/nfc_rfid_detector/nfc_rfid_detector_app.c b/applications/external/nfc_rfid_detector/nfc_rfid_detector_app.c new file mode 100644 index 000000000000..cba8b60856a3 --- /dev/null +++ b/applications/external/nfc_rfid_detector/nfc_rfid_detector_app.c @@ -0,0 +1,108 @@ +#include "nfc_rfid_detector_app_i.h" + +#include +#include + +static bool nfc_rfid_detector_app_custom_event_callback(void* context, uint32_t event) { + furi_assert(context); + NfcRfidDetectorApp* app = context; + return scene_manager_handle_custom_event(app->scene_manager, event); +} + +static bool nfc_rfid_detector_app_back_event_callback(void* context) { + furi_assert(context); + NfcRfidDetectorApp* app = context; + return scene_manager_handle_back_event(app->scene_manager); +} + +static void nfc_rfid_detector_app_tick_event_callback(void* context) { + furi_assert(context); + NfcRfidDetectorApp* app = context; + scene_manager_handle_tick_event(app->scene_manager); +} + +NfcRfidDetectorApp* nfc_rfid_detector_app_alloc() { + NfcRfidDetectorApp* app = malloc(sizeof(NfcRfidDetectorApp)); + + // GUI + app->gui = furi_record_open(RECORD_GUI); + + // View Dispatcher + app->view_dispatcher = view_dispatcher_alloc(); + app->scene_manager = scene_manager_alloc(&nfc_rfid_detector_scene_handlers, app); + view_dispatcher_enable_queue(app->view_dispatcher); + + view_dispatcher_set_event_callback_context(app->view_dispatcher, app); + view_dispatcher_set_custom_event_callback( + app->view_dispatcher, nfc_rfid_detector_app_custom_event_callback); + view_dispatcher_set_navigation_event_callback( + app->view_dispatcher, nfc_rfid_detector_app_back_event_callback); + view_dispatcher_set_tick_event_callback( + app->view_dispatcher, nfc_rfid_detector_app_tick_event_callback, 100); + + view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); + + // Open Notification record + app->notifications = furi_record_open(RECORD_NOTIFICATION); + + // SubMenu + app->submenu = submenu_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, NfcRfidDetectorViewSubmenu, submenu_get_view(app->submenu)); + + // Widget + app->widget = widget_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, NfcRfidDetectorViewWidget, widget_get_view(app->widget)); + + // Field Presence + app->nfc_rfid_detector_field_presence = nfc_rfid_detector_view_field_presence_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, + NfcRfidDetectorViewFieldPresence, + nfc_rfid_detector_view_field_presence_get_view(app->nfc_rfid_detector_field_presence)); + + scene_manager_next_scene(app->scene_manager, NfcRfidDetectorSceneStart); + + return app; +} + +void nfc_rfid_detector_app_free(NfcRfidDetectorApp* app) { + furi_assert(app); + + // Submenu + view_dispatcher_remove_view(app->view_dispatcher, NfcRfidDetectorViewSubmenu); + submenu_free(app->submenu); + + // Widget + view_dispatcher_remove_view(app->view_dispatcher, NfcRfidDetectorViewWidget); + widget_free(app->widget); + + // Field Presence + view_dispatcher_remove_view(app->view_dispatcher, NfcRfidDetectorViewFieldPresence); + nfc_rfid_detector_view_field_presence_free(app->nfc_rfid_detector_field_presence); + + // View dispatcher + view_dispatcher_free(app->view_dispatcher); + scene_manager_free(app->scene_manager); + + // Notifications + furi_record_close(RECORD_NOTIFICATION); + app->notifications = NULL; + + // Close records + furi_record_close(RECORD_GUI); + + free(app); +} + +int32_t nfc_rfid_detector_app(void* p) { + UNUSED(p); + NfcRfidDetectorApp* nfc_rfid_detector_app = nfc_rfid_detector_app_alloc(); + + view_dispatcher_run(nfc_rfid_detector_app->view_dispatcher); + + nfc_rfid_detector_app_free(nfc_rfid_detector_app); + + return 0; +} diff --git a/applications/external/nfc_rfid_detector/nfc_rfid_detector_app_i.c b/applications/external/nfc_rfid_detector/nfc_rfid_detector_app_i.c new file mode 100644 index 000000000000..c59d40d50c52 --- /dev/null +++ b/applications/external/nfc_rfid_detector/nfc_rfid_detector_app_i.c @@ -0,0 +1,40 @@ +#include "nfc_rfid_detector_app_i.h" + +#include + +#define TAG "NfcRfidDetector" + +void nfc_rfid_detector_app_field_presence_start(NfcRfidDetectorApp* app) { + furi_assert(app); + + // start the field presence rfid detection + furi_hal_rfid_field_detect_start(); + + // start the field presence nfc detection + furi_hal_nfc_exit_sleep(); + furi_hal_nfc_field_detect_start(); +} + +void nfc_rfid_detector_app_field_presence_stop(NfcRfidDetectorApp* app) { + furi_assert(app); + + // stop the field presence rfid detection + furi_hal_rfid_field_detect_stop(); + + // stop the field presence nfc detection + furi_hal_nfc_start_sleep(); +} + +bool nfc_rfid_detector_app_field_presence_is_nfc(NfcRfidDetectorApp* app) { + furi_assert(app); + + // check if the field presence is nfc + return furi_hal_nfc_field_is_present(); +} + +bool nfc_rfid_detector_app_field_presence_is_rfid(NfcRfidDetectorApp* app, uint32_t* frequency) { + furi_assert(app); + + // check if the field presence is rfid + return furi_hal_rfid_field_is_present(frequency); +} \ No newline at end of file diff --git a/applications/external/nfc_rfid_detector/nfc_rfid_detector_app_i.h b/applications/external/nfc_rfid_detector/nfc_rfid_detector_app_i.h new file mode 100644 index 000000000000..72cb126d4a3d --- /dev/null +++ b/applications/external/nfc_rfid_detector/nfc_rfid_detector_app_i.h @@ -0,0 +1,30 @@ +#pragma once + +#include "helpers/nfc_rfid_detector_types.h" +#include "helpers/nfc_rfid_detector_event.h" + +#include "scenes/nfc_rfid_detector_scene.h" +#include +#include +#include +#include +#include +#include +#include "views/nfc_rfid_detector_view_field_presence.h" + +typedef struct NfcRfidDetectorApp NfcRfidDetectorApp; + +struct NfcRfidDetectorApp { + Gui* gui; + ViewDispatcher* view_dispatcher; + SceneManager* scene_manager; + NotificationApp* notifications; + Submenu* submenu; + Widget* widget; + NfcRfidDetectorFieldPresence* nfc_rfid_detector_field_presence; +}; + +void nfc_rfid_detector_app_field_presence_start(NfcRfidDetectorApp* app); +void nfc_rfid_detector_app_field_presence_stop(NfcRfidDetectorApp* app); +bool nfc_rfid_detector_app_field_presence_is_nfc(NfcRfidDetectorApp* app); +bool nfc_rfid_detector_app_field_presence_is_rfid(NfcRfidDetectorApp* app, uint32_t* frequency); \ No newline at end of file diff --git a/applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene.c b/applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene.c new file mode 100644 index 000000000000..d75eb2884fe3 --- /dev/null +++ b/applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene.c @@ -0,0 +1,31 @@ +#include "../nfc_rfid_detector_app_i.h" + +// Generate scene on_enter handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter, +void (*const nfc_rfid_detector_scene_on_enter_handlers[])(void*) = { +#include "nfc_rfid_detector_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_event handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event, +bool (*const nfc_rfid_detector_scene_on_event_handlers[])(void* context, SceneManagerEvent event) = + { +#include "nfc_rfid_detector_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_exit handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit, +void (*const nfc_rfid_detector_scene_on_exit_handlers[])(void* context) = { +#include "nfc_rfid_detector_scene_config.h" +}; +#undef ADD_SCENE + +// Initialize scene handlers configuration structure +const SceneManagerHandlers nfc_rfid_detector_scene_handlers = { + .on_enter_handlers = nfc_rfid_detector_scene_on_enter_handlers, + .on_event_handlers = nfc_rfid_detector_scene_on_event_handlers, + .on_exit_handlers = nfc_rfid_detector_scene_on_exit_handlers, + .scene_num = NfcRfidDetectorSceneNum, +}; diff --git a/applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene.h b/applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene.h new file mode 100644 index 000000000000..74d324b4d3b7 --- /dev/null +++ b/applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +// Generate scene id and total number +#define ADD_SCENE(prefix, name, id) NfcRfidDetectorScene##id, +typedef enum { +#include "nfc_rfid_detector_scene_config.h" + NfcRfidDetectorSceneNum, +} NfcRfidDetectorScene; +#undef ADD_SCENE + +extern const SceneManagerHandlers nfc_rfid_detector_scene_handlers; + +// Generate scene on_enter handlers declaration +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*); +#include "nfc_rfid_detector_scene_config.h" +#undef ADD_SCENE + +// Generate scene on_event handlers declaration +#define ADD_SCENE(prefix, name, id) \ + bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event); +#include "nfc_rfid_detector_scene_config.h" +#undef ADD_SCENE + +// Generate scene on_exit handlers declaration +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context); +#include "nfc_rfid_detector_scene_config.h" +#undef ADD_SCENE diff --git a/applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene_about.c b/applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene_about.c new file mode 100644 index 000000000000..ddcb8aac0fe7 --- /dev/null +++ b/applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene_about.c @@ -0,0 +1,69 @@ +#include "../nfc_rfid_detector_app_i.h" + +void nfc_rfid_detector_scene_about_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + NfcRfidDetectorApp* app = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(app->view_dispatcher, result); + } +} + +void nfc_rfid_detector_scene_about_on_enter(void* context) { + NfcRfidDetectorApp* app = context; + + FuriString* temp_str; + temp_str = furi_string_alloc(); + furi_string_printf(temp_str, "\e#%s\n", "Information"); + + furi_string_cat_printf(temp_str, "Version: %s\n", NFC_RFID_DETECTOR_VERSION_APP); + furi_string_cat_printf(temp_str, "Developed by: %s\n", NFC_RFID_DETECTOR_DEVELOPED); + furi_string_cat_printf(temp_str, "Github: %s\n\n", NFC_RFID_DETECTOR_GITHUB); + + furi_string_cat_printf(temp_str, "\e#%s\n", "Description"); + furi_string_cat_printf( + temp_str, + "This application allows\nyou to determine what\ntype of electromagnetic\nfield the reader is using.\nFor LF RFID you can also\nsee the carrier frequency\n\n"); + + widget_add_text_box_element( + app->widget, + 0, + 0, + 128, + 14, + AlignCenter, + AlignBottom, + "\e#\e! \e!\n", + false); + widget_add_text_box_element( + app->widget, + 0, + 2, + 128, + 14, + AlignCenter, + AlignBottom, + "\e#\e! NFC/RFID detector \e!\n", + false); + widget_add_text_scroll_element(app->widget, 0, 16, 128, 50, furi_string_get_cstr(temp_str)); + furi_string_free(temp_str); + + view_dispatcher_switch_to_view(app->view_dispatcher, NfcRfidDetectorViewWidget); +} + +bool nfc_rfid_detector_scene_about_on_event(void* context, SceneManagerEvent event) { + NfcRfidDetectorApp* app = context; + bool consumed = false; + UNUSED(app); + UNUSED(event); + + return consumed; +} + +void nfc_rfid_detector_scene_about_on_exit(void* context) { + NfcRfidDetectorApp* app = context; + + // Clear views + widget_reset(app->widget); +} diff --git a/applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene_config.h b/applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene_config.h new file mode 100644 index 000000000000..ab49ad5c2cfb --- /dev/null +++ b/applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene_config.h @@ -0,0 +1,3 @@ +ADD_SCENE(nfc_rfid_detector, start, Start) +ADD_SCENE(nfc_rfid_detector, about, About) +ADD_SCENE(nfc_rfid_detector, field_presence, FieldPresence) diff --git a/applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene_field_presence.c b/applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene_field_presence.c new file mode 100644 index 000000000000..ec53b5a0a60f --- /dev/null +++ b/applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene_field_presence.c @@ -0,0 +1,60 @@ +#include "../nfc_rfid_detector_app_i.h" +#include "../views/nfc_rfid_detector_view_field_presence.h" + +void nfc_rfid_detector_scene_field_presence_callback( + NfcRfidDetectorCustomEvent event, + void* context) { + furi_assert(context); + NfcRfidDetectorApp* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, event); +} + +static const NotificationSequence notification_app_display_on = { + + &message_display_backlight_on, + NULL, +}; + +static void nfc_rfid_detector_scene_field_presence_update(void* context) { + furi_assert(context); + NfcRfidDetectorApp* app = context; + + uint32_t frequency = 0; + bool nfc_field = nfc_rfid_detector_app_field_presence_is_nfc(app); + bool rfid_field = nfc_rfid_detector_app_field_presence_is_rfid(app, &frequency); + + if(nfc_field || rfid_field) + notification_message(app->notifications, ¬ification_app_display_on); + + nfc_rfid_detector_view_field_presence_update( + app->nfc_rfid_detector_field_presence, nfc_field, rfid_field, frequency); +} + +void nfc_rfid_detector_scene_field_presence_on_enter(void* context) { + furi_assert(context); + NfcRfidDetectorApp* app = context; + + // Start detection of field presence + nfc_rfid_detector_app_field_presence_start(app); + + view_dispatcher_switch_to_view(app->view_dispatcher, NfcRfidDetectorViewFieldPresence); +} + +bool nfc_rfid_detector_scene_field_presence_on_event(void* context, SceneManagerEvent event) { + furi_assert(context); + NfcRfidDetectorApp* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeTick) { + nfc_rfid_detector_scene_field_presence_update(app); + } + + return consumed; +} + +void nfc_rfid_detector_scene_field_presence_on_exit(void* context) { + furi_assert(context); + NfcRfidDetectorApp* app = context; + // Stop detection of field presence + nfc_rfid_detector_app_field_presence_stop(app); +} diff --git a/applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene_start.c b/applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene_start.c new file mode 100644 index 000000000000..7b71bd973513 --- /dev/null +++ b/applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene_start.c @@ -0,0 +1,58 @@ +#include "../nfc_rfid_detector_app_i.h" + +typedef enum { + SubmenuIndexNfcRfidDetectorFieldPresence, + SubmenuIndexNfcRfidDetectorAbout, +} SubmenuIndex; + +void nfc_rfid_detector_scene_start_submenu_callback(void* context, uint32_t index) { + NfcRfidDetectorApp* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, index); +} + +void nfc_rfid_detector_scene_start_on_enter(void* context) { + UNUSED(context); + NfcRfidDetectorApp* app = context; + Submenu* submenu = app->submenu; + + submenu_add_item( + submenu, + "Detect field type", + SubmenuIndexNfcRfidDetectorFieldPresence, + nfc_rfid_detector_scene_start_submenu_callback, + app); + submenu_add_item( + submenu, + "About", + SubmenuIndexNfcRfidDetectorAbout, + nfc_rfid_detector_scene_start_submenu_callback, + app); + + submenu_set_selected_item( + submenu, scene_manager_get_scene_state(app->scene_manager, NfcRfidDetectorSceneStart)); + + view_dispatcher_switch_to_view(app->view_dispatcher, NfcRfidDetectorViewSubmenu); +} + +bool nfc_rfid_detector_scene_start_on_event(void* context, SceneManagerEvent event) { + NfcRfidDetectorApp* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexNfcRfidDetectorAbout) { + scene_manager_next_scene(app->scene_manager, NfcRfidDetectorSceneAbout); + consumed = true; + } else if(event.event == SubmenuIndexNfcRfidDetectorFieldPresence) { + scene_manager_next_scene(app->scene_manager, NfcRfidDetectorSceneFieldPresence); + consumed = true; + } + scene_manager_set_scene_state(app->scene_manager, NfcRfidDetectorSceneStart, event.event); + } + + return consumed; +} + +void nfc_rfid_detector_scene_start_on_exit(void* context) { + NfcRfidDetectorApp* app = context; + submenu_reset(app->submenu); +} diff --git a/applications/external/nfc_rfid_detector/views/nfc_rfid_detector_view_field_presence.c b/applications/external/nfc_rfid_detector/views/nfc_rfid_detector_view_field_presence.c new file mode 100644 index 000000000000..e65eb8362b48 --- /dev/null +++ b/applications/external/nfc_rfid_detector/views/nfc_rfid_detector_view_field_presence.c @@ -0,0 +1,164 @@ +#include "nfc_rfid_detector_view_field_presence.h" +#include "../nfc_rfid_detector_app_i.h" +#include + +#include +#include + +#define FIELD_FOUND_WEIGHT 5 + +typedef enum { + NfcRfidDetectorTypeFieldPresenceNfc, + NfcRfidDetectorTypeFieldPresenceRfid, +} NfcRfidDetectorTypeFieldPresence; + +static const Icon* NfcRfidDetectorFieldPresenceIcons[] = { + [NfcRfidDetectorTypeFieldPresenceNfc] = &I_NFC_detect_45x30, + [NfcRfidDetectorTypeFieldPresenceRfid] = &I_Rfid_detect_45x30, +}; + +struct NfcRfidDetectorFieldPresence { + View* view; +}; + +typedef struct { + uint8_t nfc_field; + uint8_t rfid_field; + uint32_t rfid_frequency; +} NfcRfidDetectorFieldPresenceModel; + +void nfc_rfid_detector_view_field_presence_update( + NfcRfidDetectorFieldPresence* instance, + bool nfc_field, + bool rfid_field, + uint32_t rfid_frequency) { + furi_assert(instance); + with_view_model( + instance->view, + NfcRfidDetectorFieldPresenceModel * model, + { + if(nfc_field) { + model->nfc_field = FIELD_FOUND_WEIGHT; + } else if(model->nfc_field) { + model->nfc_field--; + } + if(rfid_field) { + model->rfid_field = FIELD_FOUND_WEIGHT; + model->rfid_frequency = rfid_frequency; + } else if(model->rfid_field) { + model->rfid_field--; + } + }, + true); +} + +void nfc_rfid_detector_view_field_presence_draw( + Canvas* canvas, + NfcRfidDetectorFieldPresenceModel* model) { + canvas_clear(canvas); + canvas_set_color(canvas, ColorBlack); + + if(!model->nfc_field && !model->rfid_field) { + canvas_draw_icon(canvas, 0, 16, &I_Modern_reader_18x34); + canvas_draw_icon(canvas, 22, 12, &I_Move_flipper_26x39); + canvas_set_font(canvas, FontSecondary); + canvas_draw_str(canvas, 56, 36, "Touch the reader"); + } else { + if(model->nfc_field) { + canvas_set_font(canvas, FontPrimary); + canvas_draw_str(canvas, 21, 10, "NFC"); + canvas_draw_icon( + canvas, + 9, + 17, + NfcRfidDetectorFieldPresenceIcons[NfcRfidDetectorTypeFieldPresenceNfc]); + canvas_set_font(canvas, FontSecondary); + canvas_draw_str(canvas, 9, 62, "13,56 MHz"); + } + + if(model->rfid_field) { + char str[16]; + snprintf(str, sizeof(str), "%.02f KHz", (double)model->rfid_frequency / 1000); + canvas_set_font(canvas, FontPrimary); + canvas_draw_str(canvas, 76, 10, "LF RFID"); + canvas_draw_icon( + canvas, + 71, + 17, + NfcRfidDetectorFieldPresenceIcons[NfcRfidDetectorTypeFieldPresenceRfid]); + canvas_set_font(canvas, FontSecondary); + canvas_draw_str(canvas, 69, 62, str); + } + } +} + +bool nfc_rfid_detector_view_field_presence_input(InputEvent* event, void* context) { + furi_assert(context); + NfcRfidDetectorFieldPresence* instance = context; + UNUSED(instance); + + if(event->key == InputKeyBack) { + return false; + } + + return true; +} + +void nfc_rfid_detector_view_field_presence_enter(void* context) { + furi_assert(context); + NfcRfidDetectorFieldPresence* instance = context; + with_view_model( + instance->view, + NfcRfidDetectorFieldPresenceModel * model, + { + model->nfc_field = 0; + model->rfid_field = 0; + model->rfid_frequency = 0; + }, + true); +} + +void nfc_rfid_detector_view_field_presence_exit(void* context) { + furi_assert(context); + NfcRfidDetectorFieldPresence* instance = context; + UNUSED(instance); +} + +NfcRfidDetectorFieldPresence* nfc_rfid_detector_view_field_presence_alloc() { + NfcRfidDetectorFieldPresence* instance = malloc(sizeof(NfcRfidDetectorFieldPresence)); + + // View allocation and configuration + instance->view = view_alloc(); + + view_allocate_model( + instance->view, ViewModelTypeLocking, sizeof(NfcRfidDetectorFieldPresenceModel)); + view_set_context(instance->view, instance); + view_set_draw_callback( + instance->view, (ViewDrawCallback)nfc_rfid_detector_view_field_presence_draw); + view_set_input_callback(instance->view, nfc_rfid_detector_view_field_presence_input); + view_set_enter_callback(instance->view, nfc_rfid_detector_view_field_presence_enter); + view_set_exit_callback(instance->view, nfc_rfid_detector_view_field_presence_exit); + + with_view_model( + instance->view, + NfcRfidDetectorFieldPresenceModel * model, + { + model->nfc_field = 0; + model->rfid_field = 0; + model->rfid_frequency = 0; + }, + true); + return instance; +} + +void nfc_rfid_detector_view_field_presence_free(NfcRfidDetectorFieldPresence* instance) { + furi_assert(instance); + + view_free(instance->view); + free(instance); +} + +View* nfc_rfid_detector_view_field_presence_get_view(NfcRfidDetectorFieldPresence* instance) { + furi_assert(instance); + return instance->view; +} diff --git a/applications/external/nfc_rfid_detector/views/nfc_rfid_detector_view_field_presence.h b/applications/external/nfc_rfid_detector/views/nfc_rfid_detector_view_field_presence.h new file mode 100644 index 000000000000..0ddb4e2cd589 --- /dev/null +++ b/applications/external/nfc_rfid_detector/views/nfc_rfid_detector_view_field_presence.h @@ -0,0 +1,19 @@ +#pragma once + +#include +#include "../helpers/nfc_rfid_detector_types.h" +#include "../helpers/nfc_rfid_detector_event.h" + +typedef struct NfcRfidDetectorFieldPresence NfcRfidDetectorFieldPresence; + +void nfc_rfid_detector_view_field_presence_update( + NfcRfidDetectorFieldPresence* instance, + bool nfc_field, + bool rfid_field, + uint32_t rfid_frequency); + +NfcRfidDetectorFieldPresence* nfc_rfid_detector_view_field_presence_alloc(); + +void nfc_rfid_detector_view_field_presence_free(NfcRfidDetectorFieldPresence* instance); + +View* nfc_rfid_detector_view_field_presence_get_view(NfcRfidDetectorFieldPresence* instance); diff --git a/applications/external/picopass/views/dict_attack.h b/applications/external/picopass/views/dict_attack.h index d675c1eb40c7..bdfa3e952007 100644 --- a/applications/external/picopass/views/dict_attack.h +++ b/applications/external/picopass/views/dict_attack.h @@ -3,7 +3,7 @@ #include #include -#include +#include typedef struct DictAttack DictAttack; diff --git a/applications/external/signal_generator/scenes/signal_gen_scene_pwm.c b/applications/external/signal_generator/scenes/signal_gen_scene_pwm.c index 7ac3fadda4c1..1cadb3a1a47f 100644 --- a/applications/external/signal_generator/scenes/signal_gen_scene_pwm.c +++ b/applications/external/signal_generator/scenes/signal_gen_scene_pwm.c @@ -33,7 +33,13 @@ void signal_gen_scene_pwm_on_enter(void* context) { signal_gen_pwm_set_callback(app->pwm_view, signal_gen_pwm_callback, app); signal_gen_pwm_set_params(app->pwm_view, 0, DEFAULT_FREQ, DEFAULT_DUTY); - furi_hal_pwm_start(pwm_ch_id[0], DEFAULT_FREQ, DEFAULT_DUTY); + + if(!furi_hal_pwm_is_running(pwm_ch_id[0])) { + furi_hal_pwm_start(pwm_ch_id[0], DEFAULT_FREQ, DEFAULT_DUTY); + } else { + furi_hal_pwm_stop(pwm_ch_id[0]); + furi_hal_pwm_start(pwm_ch_id[0], DEFAULT_FREQ, DEFAULT_DUTY); + } } bool signal_gen_scene_pwm_on_event(void* context, SceneManagerEvent event) { @@ -46,8 +52,18 @@ bool signal_gen_scene_pwm_on_event(void* context, SceneManagerEvent event) { furi_hal_pwm_set_params(app->pwm_ch, app->pwm_freq, app->pwm_duty); } else if(event.event == SignalGenPwmEventChannelChange) { consumed = true; - furi_hal_pwm_stop(app->pwm_ch_prev); - furi_hal_pwm_start(app->pwm_ch, app->pwm_freq, app->pwm_duty); + // Stop previous channel PWM + if(furi_hal_pwm_is_running(app->pwm_ch_prev)) { + furi_hal_pwm_stop(app->pwm_ch_prev); + } + + // Start PWM and restart if it was starter already + if(furi_hal_pwm_is_running(app->pwm_ch)) { + furi_hal_pwm_stop(app->pwm_ch); + furi_hal_pwm_start(app->pwm_ch, app->pwm_freq, app->pwm_duty); + } else { + furi_hal_pwm_start(app->pwm_ch, app->pwm_freq, app->pwm_duty); + } } } return consumed; @@ -56,5 +72,8 @@ bool signal_gen_scene_pwm_on_event(void* context, SceneManagerEvent event) { void signal_gen_scene_pwm_on_exit(void* context) { SignalGenApp* app = context; variable_item_list_reset(app->var_item_list); - furi_hal_pwm_stop(app->pwm_ch); + + if(furi_hal_pwm_is_running(app->pwm_ch)) { + furi_hal_pwm_stop(app->pwm_ch); + } } diff --git a/applications/main/application.fam b/applications/main/application.fam index d74c004aaa33..e2b3dd437765 100644 --- a/applications/main/application.fam +++ b/applications/main/application.fam @@ -12,7 +12,6 @@ App( # "subghz", # "bad_usb", # "u2f", - # "fap_loader", # "archive", ], ) diff --git a/applications/main/archive/helpers/archive_browser.c b/applications/main/archive/helpers/archive_browser.c index 9a7973cb3884..70137d6944d5 100644 --- a/applications/main/archive/helpers/archive_browser.c +++ b/applications/main/archive/helpers/archive_browser.c @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include static void @@ -367,7 +367,7 @@ void archive_add_app_item(ArchiveBrowserView* browser, const char* name) { static bool archive_get_fap_meta(FuriString* file_path, FuriString* fap_name, uint8_t** icon_ptr) { Storage* storage = furi_record_open(RECORD_STORAGE); bool success = false; - if(fap_loader_load_name_and_icon(file_path, storage, icon_ptr, fap_name)) { + if(flipper_application_load_name_and_icon(file_path, storage, icon_ptr, fap_name)) { success = true; } furi_record_close(RECORD_STORAGE); diff --git a/applications/main/archive/scenes/archive_scene_browser.c b/applications/main/archive/scenes/archive_scene_browser.c index c28f91f52448..e02f7622a6da 100644 --- a/applications/main/archive/scenes/archive_scene_browser.c +++ b/applications/main/archive/scenes/archive_scene_browser.c @@ -11,17 +11,28 @@ #define SCENE_STATE_DEFAULT (0) #define SCENE_STATE_NEED_REFRESH (1) -static const char* flipper_app_name[] = { - [ArchiveFileTypeIButton] = "iButton", - [ArchiveFileTypeNFC] = "NFC", - [ArchiveFileTypeSubGhz] = "Sub-GHz", - [ArchiveFileTypeLFRFID] = "125 kHz RFID", - [ArchiveFileTypeInfrared] = "Infrared", - [ArchiveFileTypeBadUsb] = "Bad USB", - [ArchiveFileTypeU2f] = "U2F", - [ArchiveFileTypeUpdateManifest] = "UpdaterApp", - [ArchiveFileTypeApplication] = "Applications", -}; +const char* archive_get_flipper_app_name(ArchiveFileTypeEnum file_type) { + switch(file_type) { + case ArchiveFileTypeIButton: + return "iButton"; + case ArchiveFileTypeNFC: + return "NFC"; + case ArchiveFileTypeSubGhz: + return "Sub-GHz"; + case ArchiveFileTypeLFRFID: + return "125 kHz RFID"; + case ArchiveFileTypeInfrared: + return "Infrared"; + case ArchiveFileTypeBadUsb: + return "Bad USB"; + case ArchiveFileTypeU2f: + return "U2F"; + case ArchiveFileTypeUpdateManifest: + return "UpdaterApp"; + default: + return NULL; + } +} static void archive_loader_callback(const void* message, void* context) { furi_assert(message); @@ -39,20 +50,20 @@ static void archive_run_in_app(ArchiveBrowserView* browser, ArchiveFile_t* selec UNUSED(browser); Loader* loader = furi_record_open(RECORD_LOADER); - LoaderStatus status; - if(selected->is_app) { - char* param = strrchr(furi_string_get_cstr(selected->path), '/'); - if(param != NULL) { - param++; + const char* app_name = archive_get_flipper_app_name(selected->type); + + if(app_name) { + if(selected->is_app) { + char* param = strrchr(furi_string_get_cstr(selected->path), '/'); + if(param != NULL) { + param++; + } + loader_start_with_gui_error(loader, app_name, param); + } else { + loader_start_with_gui_error(loader, app_name, furi_string_get_cstr(selected->path)); } - status = loader_start(loader, flipper_app_name[selected->type], param); } else { - status = loader_start( - loader, flipper_app_name[selected->type], furi_string_get_cstr(selected->path)); - } - - if(status != LoaderStatusOk) { - FURI_LOG_E(TAG, "loader_start failed: %d", status); + loader_start_with_gui_error(loader, furi_string_get_cstr(selected->path), NULL); } furi_record_close(RECORD_LOADER); diff --git a/applications/main/archive/views/archive_browser_view.c b/applications/main/archive/views/archive_browser_view.c index 2aca3c02ba45..3c2f13215403 100644 --- a/applications/main/archive/views/archive_browser_view.c +++ b/applications/main/archive/views/archive_browser_view.c @@ -334,9 +334,24 @@ static bool archive_view_input(InputEvent* event, void* context) { browser->view, ArchiveBrowserViewModel * model, { + int32_t scroll_speed = 1; + if(model->button_held_for_ticks > 5) { + if(model->button_held_for_ticks % 2) { + scroll_speed = 0; + } else { + scroll_speed = model->button_held_for_ticks > 9 ? 4 : 2; + } + } + if(event->key == InputKeyUp) { - model->item_idx = - ((model->item_idx - 1) + model->item_cnt) % model->item_cnt; + if(model->item_idx < scroll_speed) { + model->button_held_for_ticks = 0; + model->item_idx = model->item_cnt - 1; + } else { + model->item_idx = + ((model->item_idx - scroll_speed) + model->item_cnt) % + model->item_cnt; + } if(is_file_list_load_required(model)) { model->list_loading = true; browser->callback(ArchiveBrowserEventLoadPrevItems, browser->context); @@ -345,8 +360,15 @@ static bool archive_view_input(InputEvent* event, void* context) { browser->callback(ArchiveBrowserEventFavMoveUp, browser->context); } model->scroll_counter = 0; + model->button_held_for_ticks += 1; } else if(event->key == InputKeyDown) { - model->item_idx = (model->item_idx + 1) % model->item_cnt; + int32_t count = model->item_cnt; + if(model->item_idx + scroll_speed >= count) { + model->button_held_for_ticks = 0; + model->item_idx = 0; + } else { + model->item_idx = (model->item_idx + scroll_speed) % model->item_cnt; + } if(is_file_list_load_required(model)) { model->list_loading = true; browser->callback(ArchiveBrowserEventLoadNextItems, browser->context); @@ -355,6 +377,7 @@ static bool archive_view_input(InputEvent* event, void* context) { browser->callback(ArchiveBrowserEventFavMoveDown, browser->context); } model->scroll_counter = 0; + model->button_held_for_ticks += 1; } }, true); @@ -391,6 +414,14 @@ static bool archive_view_input(InputEvent* event, void* context) { } } + if(event->type == InputTypeRelease) { + with_view_model( + browser->view, + ArchiveBrowserViewModel * model, + { model->button_held_for_ticks = 0; }, + true); + } + return true; } diff --git a/applications/main/archive/views/archive_browser_view.h b/applications/main/archive/views/archive_browser_view.h index 0a000e5ac348..25490aedd3e4 100644 --- a/applications/main/archive/views/archive_browser_view.h +++ b/applications/main/archive/views/archive_browser_view.h @@ -100,6 +100,8 @@ typedef struct { int32_t array_offset; int32_t list_offset; size_t scroll_counter; + + uint32_t button_held_for_ticks; } ArchiveBrowserViewModel; void archive_browser_set_callback( diff --git a/applications/main/fap_loader/application.fam b/applications/main/fap_loader/application.fam deleted file mode 100644 index b0e67cd42e3b..000000000000 --- a/applications/main/fap_loader/application.fam +++ /dev/null @@ -1,15 +0,0 @@ -App( - appid="fap_loader", - name="Applications", - apptype=FlipperAppType.APP, - entry_point="fap_loader_app", - cdefines=["APP_FAP_LOADER"], - requires=[ - "gui", - "storage", - "loader", - ], - stack_size=int(1.5 * 1024), - icon="A_Plugins_14", - order=90, -) diff --git a/applications/main/fap_loader/fap_loader_app.c b/applications/main/fap_loader/fap_loader_app.c deleted file mode 100644 index 7af5244ae493..000000000000 --- a/applications/main/fap_loader/fap_loader_app.c +++ /dev/null @@ -1,216 +0,0 @@ -#include "fap_loader_app.h" - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#define TAG "FapLoader" - -struct FapLoader { - FlipperApplication* app; - Storage* storage; - DialogsApp* dialogs; - Gui* gui; - FuriString* fap_path; - ViewDispatcher* view_dispatcher; - Loading* loading; -}; - -bool fap_loader_load_name_and_icon( - FuriString* path, - Storage* storage, - uint8_t** icon_ptr, - FuriString* item_name) { - FlipperApplication* app = flipper_application_alloc(storage, firmware_api_interface); - - FlipperApplicationPreloadStatus preload_res = - flipper_application_preload_manifest(app, furi_string_get_cstr(path)); - - bool load_success = false; - - if(preload_res == FlipperApplicationPreloadStatusSuccess) { - const FlipperApplicationManifest* manifest = flipper_application_get_manifest(app); - if(manifest->has_icon) { - memcpy(*icon_ptr, manifest->icon, FAP_MANIFEST_MAX_ICON_SIZE); - } - furi_string_set(item_name, manifest->name); - load_success = true; - } else { - FURI_LOG_E(TAG, "FAP Loader failed to preload %s", furi_string_get_cstr(path)); - load_success = false; - } - - flipper_application_free(app); - return load_success; -} - -static bool fap_loader_item_callback( - FuriString* path, - void* context, - uint8_t** icon_ptr, - FuriString* item_name) { - FapLoader* fap_loader = context; - furi_assert(fap_loader); - return fap_loader_load_name_and_icon(path, fap_loader->storage, icon_ptr, item_name); -} - -static bool fap_loader_run_selected_app(FapLoader* loader) { - furi_assert(loader); - - FuriString* error_message; - - error_message = furi_string_alloc_set("unknown error"); - - bool file_selected = false; - bool show_error = true; - do { - file_selected = true; - loader->app = flipper_application_alloc(loader->storage, firmware_api_interface); - size_t start = furi_get_tick(); - - FURI_LOG_I(TAG, "FAP Loader is loading %s", furi_string_get_cstr(loader->fap_path)); - - FlipperApplicationPreloadStatus preload_res = - flipper_application_preload(loader->app, furi_string_get_cstr(loader->fap_path)); - if(preload_res != FlipperApplicationPreloadStatusSuccess) { - const char* err_msg = flipper_application_preload_status_to_string(preload_res); - furi_string_printf(error_message, "Preload failed: %s", err_msg); - FURI_LOG_E( - TAG, - "FAP Loader failed to preload %s: %s", - furi_string_get_cstr(loader->fap_path), - err_msg); - break; - } - - FURI_LOG_I(TAG, "FAP Loader is mapping"); - FlipperApplicationLoadStatus load_status = flipper_application_map_to_memory(loader->app); - if(load_status != FlipperApplicationLoadStatusSuccess) { - const char* err_msg = flipper_application_load_status_to_string(load_status); - furi_string_printf(error_message, "Load failed: %s", err_msg); - FURI_LOG_E( - TAG, - "FAP Loader failed to map to memory %s: %s", - furi_string_get_cstr(loader->fap_path), - err_msg); - break; - } - - FURI_LOG_I(TAG, "Loaded in %ums", (size_t)(furi_get_tick() - start)); - FURI_LOG_I(TAG, "FAP Loader is starting app"); - - FuriThread* thread = flipper_application_spawn(loader->app, NULL); - - /* This flag is set by the debugger - to break on app start */ - if(furi_hal_debug_is_gdb_session_active()) { - FURI_LOG_W(TAG, "Triggering BP for debugger"); - /* After hitting this, you can set breakpoints in your .fap's code - * Note that you have to toggle breakpoints that were set before */ - __asm volatile("bkpt 0"); - } - - FuriString* app_name = furi_string_alloc(); - path_extract_filename_no_ext(furi_string_get_cstr(loader->fap_path), app_name); - furi_thread_set_appid(thread, furi_string_get_cstr(app_name)); - furi_string_free(app_name); - - furi_thread_start(thread); - furi_thread_join(thread); - - show_error = false; - int ret = furi_thread_get_return_code(thread); - - FURI_LOG_I(TAG, "FAP app returned: %i", ret); - } while(0); - - if(show_error) { - DialogMessage* message = dialog_message_alloc(); - dialog_message_set_header(message, "Error", 64, 0, AlignCenter, AlignTop); - dialog_message_set_buttons(message, NULL, NULL, NULL); - - FuriString* buffer; - buffer = furi_string_alloc(); - furi_string_printf(buffer, "%s", furi_string_get_cstr(error_message)); - furi_string_replace(buffer, ":", "\n"); - dialog_message_set_text( - message, furi_string_get_cstr(buffer), 64, 32, AlignCenter, AlignCenter); - - dialog_message_show(loader->dialogs, message); - dialog_message_free(message); - furi_string_free(buffer); - } - - furi_string_free(error_message); - - if(file_selected) { - flipper_application_free(loader->app); - } - - return file_selected; -} - -static bool fap_loader_select_app(FapLoader* loader) { - const DialogsFileBrowserOptions browser_options = { - .extension = ".fap", - .skip_assets = true, - .icon = &I_unknown_10px, - .hide_ext = true, - .item_loader_callback = fap_loader_item_callback, - .item_loader_context = loader, - .base_path = EXT_PATH("apps"), - }; - - return dialog_file_browser_show( - loader->dialogs, loader->fap_path, loader->fap_path, &browser_options); -} - -static FapLoader* fap_loader_alloc(const char* path) { - FapLoader* loader = malloc(sizeof(FapLoader)); //-V799 - loader->fap_path = furi_string_alloc_set(path); - loader->storage = furi_record_open(RECORD_STORAGE); - loader->dialogs = furi_record_open(RECORD_DIALOGS); - loader->gui = furi_record_open(RECORD_GUI); - loader->view_dispatcher = view_dispatcher_alloc(); - loader->loading = loading_alloc(); - view_dispatcher_attach_to_gui( - loader->view_dispatcher, loader->gui, ViewDispatcherTypeFullscreen); - view_dispatcher_add_view(loader->view_dispatcher, 0, loading_get_view(loader->loading)); - return loader; -} //-V773 - -static void fap_loader_free(FapLoader* loader) { - view_dispatcher_remove_view(loader->view_dispatcher, 0); - loading_free(loader->loading); - view_dispatcher_free(loader->view_dispatcher); - furi_string_free(loader->fap_path); - furi_record_close(RECORD_GUI); - furi_record_close(RECORD_DIALOGS); - furi_record_close(RECORD_STORAGE); - free(loader); -} - -int32_t fap_loader_app(void* p) { - FapLoader* loader; - if(p) { - loader = fap_loader_alloc((const char*)p); - view_dispatcher_switch_to_view(loader->view_dispatcher, 0); - fap_loader_run_selected_app(loader); - } else { - loader = fap_loader_alloc(EXT_PATH("apps")); - while(fap_loader_select_app(loader)) { - view_dispatcher_switch_to_view(loader->view_dispatcher, 0); - fap_loader_run_selected_app(loader); - }; - } - - fap_loader_free(loader); - return 0; -} diff --git a/applications/main/fap_loader/fap_loader_app.h b/applications/main/fap_loader/fap_loader_app.h deleted file mode 100644 index 9ed725efe528..000000000000 --- a/applications/main/fap_loader/fap_loader_app.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct FapLoader FapLoader; - -/** - * @brief Load name and icon from FAP file. - * - * @param path Path to FAP file. - * @param storage Storage instance. - * @param icon_ptr Icon pointer. - * @param item_name Application name. - * @return true if icon and name were loaded successfully. - */ -bool fap_loader_load_name_and_icon( - FuriString* path, - Storage* storage, - uint8_t** icon_ptr, - FuriString* item_name); - -#ifdef __cplusplus -} -#endif \ No newline at end of file diff --git a/applications/main/nfc/nfc_cli.c b/applications/main/nfc/nfc_cli.c index 7aa010ba662f..320cd94bf7dd 100644 --- a/applications/main/nfc/nfc_cli.c +++ b/applications/main/nfc/nfc_cli.c @@ -149,6 +149,10 @@ static void nfc_cli_apdu(Cli* cli, FuriString* args) { break; } resp_size = (tx_rx.rx_bits / 8) * 2; + if(!resp_size) { + printf("No response\r\n"); + break; + } resp_buffer = malloc(resp_size); uint8_to_hex_chars(tx_rx.rx_data, resp_buffer, resp_size); resp_buffer[resp_size] = 0; diff --git a/applications/main/nfc_old/application.fam b/applications/main/nfc_old/application.fam index b67b8e6b2d1f..364a800e89b4 100644 --- a/applications/main/nfc_old/application.fam +++ b/applications/main/nfc_old/application.fam @@ -1,5 +1,5 @@ App( - appid="nfc_old", + appid="nfc_app", name="NFC", apptype=FlipperAppType.APP, targets=["f7"], @@ -16,7 +16,7 @@ App( ) App( - appid="nfc_old_start", + appid="nfc_start", apptype=FlipperAppType.STARTUP, entry_point="nfc_on_system_start", requires=["nfc"], diff --git a/applications/main/nfc_old/nfc_app.c b/applications/main/nfc_old/nfc.c similarity index 94% rename from applications/main/nfc_old/nfc_app.c rename to applications/main/nfc_old/nfc.c index e9d070c98d21..56d98a8c61aa 100644 --- a/applications/main/nfc_old/nfc_app.c +++ b/applications/main/nfc_old/nfc.c @@ -1,22 +1,22 @@ -#include "nfc_app_i.h" +#include "nfc_i.h" #include #include bool nfc_custom_event_callback(void* context, uint32_t event) { furi_assert(context); - NfcApp* nfc = context; + Nfc* nfc = context; return scene_manager_handle_custom_event(nfc->scene_manager, event); } bool nfc_back_event_callback(void* context) { furi_assert(context); - NfcApp* nfc = context; + Nfc* nfc = context; return scene_manager_handle_back_event(nfc->scene_manager); } static void nfc_rpc_command_callback(RpcAppSystemEvent event, void* context) { furi_assert(context); - NfcApp* nfc = context; + Nfc* nfc = context; furi_assert(nfc->rpc_ctx); @@ -33,8 +33,8 @@ static void nfc_rpc_command_callback(RpcAppSystemEvent event, void* context) { } } -NfcApp* nfc_app_alloc() { - NfcApp* nfc = malloc(sizeof(NfcApp)); +Nfc* nfc_alloc() { + Nfc* nfc = malloc(sizeof(Nfc)); nfc->worker = nfc_worker_alloc(); nfc->view_dispatcher = view_dispatcher_alloc(); @@ -107,7 +107,7 @@ NfcApp* nfc_app_alloc() { return nfc; } -void nfc_app_free(NfcApp* nfc) { +void nfc_free(Nfc* nfc) { furi_assert(nfc); if(nfc->rpc_state == NfcRpcStateEmulating) { @@ -192,7 +192,7 @@ void nfc_app_free(NfcApp* nfc) { free(nfc); } -void nfc_text_store_set(NfcApp* nfc, const char* text, ...) { +void nfc_text_store_set(Nfc* nfc, const char* text, ...) { va_list args; va_start(args, text); @@ -201,27 +201,27 @@ void nfc_text_store_set(NfcApp* nfc, const char* text, ...) { va_end(args); } -void nfc_text_store_clear(NfcApp* nfc) { +void nfc_text_store_clear(Nfc* nfc) { memset(nfc->text_store, 0, sizeof(nfc->text_store)); } -void nfc_blink_read_start(NfcApp* nfc) { +void nfc_blink_read_start(Nfc* nfc) { notification_message(nfc->notifications, &sequence_blink_start_cyan); } -void nfc_blink_emulate_start(NfcApp* nfc) { +void nfc_blink_emulate_start(Nfc* nfc) { notification_message(nfc->notifications, &sequence_blink_start_magenta); } -void nfc_blink_detect_start(NfcApp* nfc) { +void nfc_blink_detect_start(Nfc* nfc) { notification_message(nfc->notifications, &sequence_blink_start_yellow); } -void nfc_blink_stop(NfcApp* nfc) { +void nfc_blink_stop(Nfc* nfc) { notification_message(nfc->notifications, &sequence_blink_stop); } -bool nfc_save_file(NfcApp* nfc) { +bool nfc_save_file(Nfc* nfc) { furi_string_printf( nfc->dev->load_path, "%s/%s%s", NFC_APP_FOLDER, nfc->dev->dev_name, NFC_APP_EXTENSION); bool file_saved = nfc_device_save(nfc->dev, furi_string_get_cstr(nfc->dev->load_path)); @@ -229,7 +229,7 @@ bool nfc_save_file(NfcApp* nfc) { } void nfc_show_loading_popup(void* context, bool show) { - NfcApp* nfc = context; + Nfc* nfc = context; TaskHandle_t timer_task = xTaskGetHandle(configTIMER_SERVICE_TASK_NAME); if(show) { @@ -266,7 +266,7 @@ static bool nfc_is_hal_ready() { int32_t nfc_app(void* p) { if(!nfc_is_hal_ready()) return 0; - NfcApp* nfc = nfc_app_alloc(); + Nfc* nfc = nfc_alloc(); char* args = p; // Check argument and run corresponding scene @@ -313,7 +313,7 @@ int32_t nfc_app(void* p) { view_dispatcher_run(nfc->view_dispatcher); - nfc_app_free(nfc); + nfc_free(nfc); return 0; } diff --git a/applications/main/nfc_old/nfc.h b/applications/main/nfc_old/nfc.h new file mode 100644 index 000000000000..e08be6a3aa9d --- /dev/null +++ b/applications/main/nfc_old/nfc.h @@ -0,0 +1,3 @@ +#pragma once + +typedef struct Nfc Nfc; diff --git a/applications/main/nfc_old/nfc_app.h b/applications/main/nfc_old/nfc_app.h deleted file mode 100644 index 0e456fd48b27..000000000000 --- a/applications/main/nfc_old/nfc_app.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -typedef struct NfcApp NfcApp; diff --git a/applications/main/nfc_old/nfc_cli.c b/applications/main/nfc_old/nfc_cli.c index da9e24cb9a74..0b7e75475483 100644 --- a/applications/main/nfc_old/nfc_cli.c +++ b/applications/main/nfc_old/nfc_cli.c @@ -7,16 +7,6 @@ #include #include -#include -#include - -#include - -#include -#include -#include -#include - static void nfc_cli_print_usage() { printf("Usage:\r\n"); printf("nfc \r\n"); @@ -29,11 +19,6 @@ static void nfc_cli_print_usage() { } } -static void nfc_cli_check(Cli* cli, FuriString* args) { - UNUSED(args); - UNUSED(cli); -} - static void nfc_cli_detect(Cli* cli, FuriString* args) { UNUSED(args); // Check if nfc worker is not busy @@ -159,6 +144,10 @@ static void nfc_cli_apdu(Cli* cli, FuriString* args) { break; } resp_size = (tx_rx.rx_bits / 8) * 2; + if(!resp_size) { + printf("No response\r\n"); + break; + } resp_buffer = malloc(resp_size); uint8_to_hex_chars(tx_rx.rx_data, resp_buffer, resp_size); resp_buffer[resp_size] = 0; @@ -186,10 +175,6 @@ static void nfc_cli(Cli* cli, FuriString* args, void* context) { nfc_cli_print_usage(); break; } - if(furi_string_cmp_str(cmd, "c") == 0) { - nfc_cli_check(cli, args); - break; - } if(furi_string_cmp_str(cmd, "detect") == 0) { nfc_cli_detect(cli, args); break; diff --git a/applications/main/nfc_old/nfc_app_i.h b/applications/main/nfc_old/nfc_i.h similarity index 86% rename from applications/main/nfc_old/nfc_app_i.h rename to applications/main/nfc_old/nfc_i.h index c361a5fc81f1..f7e489902921 100644 --- a/applications/main/nfc_old/nfc_app_i.h +++ b/applications/main/nfc_old/nfc_i.h @@ -1,6 +1,6 @@ #pragma once -#include "nfc_app.h" +#include "nfc.h" #include #include @@ -52,7 +52,7 @@ typedef enum { NfcRpcStateEmulated, } NfcRpcState; -struct NfcApp { +struct Nfc { NfcWorker* worker; ViewDispatcher* view_dispatcher; Gui* gui; @@ -97,22 +97,22 @@ typedef enum { NfcViewDetectReader, } NfcView; -NfcApp* nfc_alloc(); +Nfc* nfc_alloc(); int32_t nfc_task(void* p); -void nfc_text_store_set(NfcApp* nfc, const char* text, ...); +void nfc_text_store_set(Nfc* nfc, const char* text, ...); -void nfc_text_store_clear(NfcApp* nfc); +void nfc_text_store_clear(Nfc* nfc); -void nfc_blink_read_start(NfcApp* nfc); +void nfc_blink_read_start(Nfc* nfc); -void nfc_blink_emulate_start(NfcApp* nfc); +void nfc_blink_emulate_start(Nfc* nfc); -void nfc_blink_detect_start(NfcApp* nfc); +void nfc_blink_detect_start(Nfc* nfc); -void nfc_blink_stop(NfcApp* nfc); +void nfc_blink_stop(Nfc* nfc); -bool nfc_save_file(NfcApp* nfc); +bool nfc_save_file(Nfc* nfc); void nfc_show_loading_popup(void* context, bool show); diff --git a/applications/main/nfc_old/scenes/nfc_scene_config.h b/applications/main/nfc_old/scenes/nfc_scene_config.h index a9da07dfda00..f11d1479838e 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_config.h +++ b/applications/main/nfc_old/scenes/nfc_scene_config.h @@ -14,6 +14,13 @@ 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, nfcv_menu, NfcVMenu) +ADD_SCENE(nfc, nfcv_unlock_menu, NfcVUnlockMenu) +ADD_SCENE(nfc, nfcv_key_input, NfcVKeyInput) +ADD_SCENE(nfc, nfcv_unlock, NfcVUnlock) +ADD_SCENE(nfc, nfcv_emulate, NfcVEmulate) +ADD_SCENE(nfc, nfcv_sniff, NfcVSniff) +ADD_SCENE(nfc, nfcv_read_success, NfcVReadSuccess) 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_old/scenes/nfc_scene_debug.c b/applications/main/nfc_old/scenes/nfc_scene_debug.c index f6705c880f39..ed079c2ed9aa 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_debug.c +++ b/applications/main/nfc_old/scenes/nfc_scene_debug.c @@ -1,4 +1,4 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" enum SubmenuDebugIndex { SubmenuDebugIndexField, @@ -6,13 +6,13 @@ enum SubmenuDebugIndex { }; void nfc_scene_debug_submenu_callback(void* context, uint32_t index) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_debug_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; Submenu* submenu = nfc->submenu; submenu_add_item( @@ -28,7 +28,7 @@ void nfc_scene_debug_on_enter(void* context) { } bool nfc_scene_debug_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -48,7 +48,7 @@ bool nfc_scene_debug_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_debug_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; submenu_reset(nfc->submenu); } diff --git a/applications/main/nfc_old/scenes/nfc_scene_delete.c b/applications/main/nfc_old/scenes/nfc_scene_delete.c index a5debe5e1b47..0808db45a321 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_delete.c +++ b/applications/main/nfc_old/scenes/nfc_scene_delete.c @@ -1,14 +1,14 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_delete_widget_callback(GuiButtonType result, InputType type, void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } } void nfc_scene_delete_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data; // Setup Custom Widget view @@ -31,6 +31,8 @@ void nfc_scene_delete_on_enter(void* context) { nfc->widget, 64, 24, AlignCenter, AlignTop, FontSecondary, furi_string_get_cstr(temp_str)); NfcProtocol protocol = nfc->dev->dev_data.protocol; + const char* nfc_type = "NFC-A"; + if(protocol == NfcDeviceProtocolEMV) { furi_string_set(temp_str, "EMV bank card"); } else if(protocol == NfcDeviceProtocolMifareUl) { @@ -39,19 +41,22 @@ void nfc_scene_delete_on_enter(void* context) { furi_string_set(temp_str, nfc_mf_classic_type(nfc->dev->dev_data.mf_classic_data.type)); } else if(protocol == NfcDeviceProtocolMifareDesfire) { furi_string_set(temp_str, "MIFARE DESFire"); + } else if(protocol == NfcDeviceProtocolNfcV) { + furi_string_set(temp_str, "ISO15693 tag"); + nfc_type = "NFC-V"; } else { furi_string_set(temp_str, "Unknown ISO tag"); } widget_add_string_element( nfc->widget, 64, 34, AlignCenter, AlignTop, FontSecondary, furi_string_get_cstr(temp_str)); - widget_add_string_element(nfc->widget, 64, 44, AlignCenter, AlignTop, FontSecondary, "NFC-A"); + widget_add_string_element(nfc->widget, 64, 44, AlignCenter, AlignTop, FontSecondary, nfc_type); furi_string_free(temp_str); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); } bool nfc_scene_delete_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -71,7 +76,7 @@ bool nfc_scene_delete_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_delete_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; widget_reset(nfc->widget); } diff --git a/applications/main/nfc_old/scenes/nfc_scene_delete_success.c b/applications/main/nfc_old/scenes/nfc_scene_delete_success.c index f0c22eec4d58..795363527fcf 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_delete_success.c +++ b/applications/main/nfc_old/scenes/nfc_scene_delete_success.c @@ -1,12 +1,12 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_delete_success_popup_callback(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); } void nfc_scene_delete_success_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Setup view Popup* popup = nfc->popup; @@ -20,7 +20,7 @@ void nfc_scene_delete_success_on_enter(void* context) { } bool nfc_scene_delete_success_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -38,7 +38,7 @@ bool nfc_scene_delete_success_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_delete_success_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clear view popup_reset(nfc->popup); diff --git a/applications/main/nfc_old/scenes/nfc_scene_detect_reader.c b/applications/main/nfc_old/scenes/nfc_scene_detect_reader.c index 85c698d05350..745946157b0d 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_detect_reader.c +++ b/applications/main/nfc_old/scenes/nfc_scene_detect_reader.c @@ -1,4 +1,4 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #define NFC_SCENE_DETECT_READER_PAIR_NONCES_MAX (10U) @@ -12,19 +12,19 @@ static const NotificationSequence sequence_detect_reader = { bool nfc_detect_reader_worker_callback(NfcWorkerEvent event, void* context) { UNUSED(event); furi_assert(context); - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, event); return true; } void nfc_scene_detect_reader_callback(void* context) { furi_assert(context); - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); } void nfc_scene_detect_reader_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; detect_reader_set_callback(nfc->detect_reader, nfc_scene_detect_reader_callback, nfc); detect_reader_set_nonces_max(nfc->detect_reader, NFC_SCENE_DETECT_READER_PAIR_NONCES_MAX); @@ -48,7 +48,7 @@ void nfc_scene_detect_reader_on_enter(void* context) { } bool nfc_scene_detect_reader_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; uint32_t nonces_collected = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneDetectReader); @@ -89,7 +89,7 @@ bool nfc_scene_detect_reader_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_detect_reader_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Stop worker nfc_worker_stop(nfc->worker); diff --git a/applications/main/nfc_old/scenes/nfc_scene_device_info.c b/applications/main/nfc_old/scenes/nfc_scene_device_info.c index 4ec17b1b0552..5d51c0816c88 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_device_info.c +++ b/applications/main/nfc_old/scenes/nfc_scene_device_info.c @@ -1,15 +1,15 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #include "../helpers/nfc_emv_parser.h" void nfc_scene_device_info_widget_callback(GuiButtonType result, InputType type, void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } } void nfc_scene_device_info_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; NfcDeviceData* dev_data = &nfc->dev->dev_data; FuriString* temp_str; @@ -67,7 +67,7 @@ void nfc_scene_device_info_on_enter(void* context) { } bool nfc_scene_device_info_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -80,7 +80,7 @@ bool nfc_scene_device_info_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_device_info_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clear views widget_reset(nfc->widget); diff --git a/applications/main/nfc_old/scenes/nfc_scene_dict_not_found.c b/applications/main/nfc_old/scenes/nfc_scene_dict_not_found.c index 3b525c17e84f..781c5a932544 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_dict_not_found.c +++ b/applications/main/nfc_old/scenes/nfc_scene_dict_not_found.c @@ -1,12 +1,12 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_dict_not_found_popup_callback(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); } void nfc_scene_dict_not_found_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Setup view Popup* popup = nfc->popup; @@ -26,7 +26,7 @@ void nfc_scene_dict_not_found_on_enter(void* context) { } bool nfc_scene_dict_not_found_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -47,6 +47,6 @@ bool nfc_scene_dict_not_found_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_dict_not_found_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; popup_reset(nfc->popup); } diff --git a/applications/main/nfc_old/scenes/nfc_scene_emulate_apdu_sequence.c b/applications/main/nfc_old/scenes/nfc_scene_emulate_apdu_sequence.c index 81d00aeffc2c..358ad2ab6f57 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_emulate_apdu_sequence.c +++ b/applications/main/nfc_old/scenes/nfc_scene_emulate_apdu_sequence.c @@ -1,8 +1,8 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #include void nfc_scene_emulate_apdu_sequence_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Setup view Popup* popup = nfc->popup; @@ -23,7 +23,7 @@ bool nfc_scene_emulate_apdu_sequence_on_event(void* context, SceneManagerEvent e } void nfc_scene_emulate_apdu_sequence_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Stop worker nfc_worker_stop(nfc->worker); diff --git a/applications/main/nfc_old/scenes/nfc_scene_emulate_uid.c b/applications/main/nfc_old/scenes/nfc_scene_emulate_uid.c index 10435d2c7550..7316eebe0150 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_emulate_uid.c +++ b/applications/main/nfc_old/scenes/nfc_scene_emulate_uid.c @@ -1,4 +1,4 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #define NFC_SCENE_EMULATE_UID_LOG_SIZE_MAX (200) @@ -10,14 +10,14 @@ enum { bool nfc_emulate_uid_worker_callback(NfcWorkerEvent event, void* context) { UNUSED(event); furi_assert(context); - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit); return true; } void nfc_scene_emulate_uid_widget_callback(GuiButtonType result, InputType type, void* context) { furi_assert(context); - NfcApp* nfc = context; + Nfc* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } @@ -25,12 +25,12 @@ void nfc_scene_emulate_uid_widget_callback(GuiButtonType result, InputType type, void nfc_emulate_uid_textbox_callback(void* context) { furi_assert(context); - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); } // Add widget with device name or inform that data received -static void nfc_scene_emulate_uid_widget_config(NfcApp* nfc, bool data_received) { +static void nfc_scene_emulate_uid_widget_config(Nfc* nfc, bool data_received) { FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; Widget* widget = nfc->widget; widget_reset(widget); @@ -57,7 +57,7 @@ static void nfc_scene_emulate_uid_widget_config(NfcApp* nfc, bool data_received) } void nfc_scene_emulate_uid_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Setup Widget nfc_scene_emulate_uid_widget_config(nfc, false); @@ -84,7 +84,7 @@ void nfc_scene_emulate_uid_on_enter(void* context) { } bool nfc_scene_emulate_uid_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; NfcReaderRequestData* reader_data = &nfc->dev->dev_data.reader_data; uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneEmulateUid); bool consumed = false; @@ -130,7 +130,7 @@ bool nfc_scene_emulate_uid_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_emulate_uid_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Stop worker nfc_worker_stop(nfc->worker); diff --git a/applications/main/nfc_old/scenes/nfc_scene_emv_menu.c b/applications/main/nfc_old/scenes/nfc_scene_emv_menu.c index 88d3355a0b75..eb1e10043bd9 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_emv_menu.c +++ b/applications/main/nfc_old/scenes/nfc_scene_emv_menu.c @@ -1,17 +1,17 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" enum SubmenuIndex { SubmenuIndexInfo, }; void nfc_scene_emv_menu_submenu_callback(void* context, uint32_t index) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_emv_menu_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; Submenu* submenu = nfc->submenu; submenu_add_item(submenu, "Info", SubmenuIndexInfo, nfc_scene_emv_menu_submenu_callback, nfc); @@ -22,7 +22,7 @@ void nfc_scene_emv_menu_on_enter(void* context) { } bool nfc_scene_emv_menu_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -39,7 +39,7 @@ bool nfc_scene_emv_menu_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_emv_menu_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clear view submenu_reset(nfc->submenu); diff --git a/applications/main/nfc_old/scenes/nfc_scene_emv_read_success.c b/applications/main/nfc_old/scenes/nfc_scene_emv_read_success.c index 00057a2ee4ab..005b76cb2112 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_emv_read_success.c +++ b/applications/main/nfc_old/scenes/nfc_scene_emv_read_success.c @@ -1,18 +1,18 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #include "../helpers/nfc_emv_parser.h" void nfc_scene_emv_read_success_widget_callback( GuiButtonType result, InputType type, void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } } void nfc_scene_emv_read_success_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; EmvData* emv_data = &nfc->dev->dev_data.emv_data; // Setup Custom Widget view @@ -85,7 +85,7 @@ void nfc_scene_emv_read_success_on_enter(void* context) { } bool nfc_scene_emv_read_success_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -104,7 +104,7 @@ bool nfc_scene_emv_read_success_on_event(void* context, SceneManagerEvent event) } void nfc_scene_emv_read_success_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; notification_message_block(nfc->notifications, &sequence_reset_green); diff --git a/applications/main/nfc_old/scenes/nfc_scene_exit_confirm.c b/applications/main/nfc_old/scenes/nfc_scene_exit_confirm.c index 92933556d2ad..3ce4f6de839b 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_exit_confirm.c +++ b/applications/main/nfc_old/scenes/nfc_scene_exit_confirm.c @@ -1,13 +1,13 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_exit_confirm_dialog_callback(DialogExResult result, void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } void nfc_scene_exit_confirm_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; DialogEx* dialog_ex = nfc->dialog_ex; dialog_ex_set_left_button_text(dialog_ex, "Exit"); @@ -22,7 +22,7 @@ void nfc_scene_exit_confirm_on_enter(void* context) { } bool nfc_scene_exit_confirm_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -45,7 +45,7 @@ bool nfc_scene_exit_confirm_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_exit_confirm_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clean view dialog_ex_reset(nfc->dialog_ex); diff --git a/applications/main/nfc_old/scenes/nfc_scene_extra_actions.c b/applications/main/nfc_old/scenes/nfc_scene_extra_actions.c index 31106c76a4f3..7f5bc7e75857 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_extra_actions.c +++ b/applications/main/nfc_old/scenes/nfc_scene_extra_actions.c @@ -1,19 +1,21 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" enum SubmenuIndex { SubmenuIndexReadCardType, SubmenuIndexMfClassicKeys, SubmenuIndexMfUltralightUnlock, + SubmenuIndexNfcVUnlock, + SubmenuIndexNfcVSniff, }; void nfc_scene_extra_actions_submenu_callback(void* context, uint32_t index) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_extra_actions_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; Submenu* submenu = nfc->submenu; submenu_add_item( @@ -34,13 +36,25 @@ void nfc_scene_extra_actions_on_enter(void* context) { SubmenuIndexMfUltralightUnlock, nfc_scene_extra_actions_submenu_callback, nfc); + submenu_add_item( + submenu, + "Unlock SLIX-L", + SubmenuIndexNfcVUnlock, + nfc_scene_extra_actions_submenu_callback, + nfc); + submenu_add_item( + submenu, + "Listen NfcV Reader", + SubmenuIndexNfcVSniff, + nfc_scene_extra_actions_submenu_callback, + nfc); submenu_set_selected_item( submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneExtraActions)); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); } bool nfc_scene_extra_actions_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -58,6 +72,12 @@ bool nfc_scene_extra_actions_on_event(void* context, SceneManagerEvent event) { scene_manager_set_scene_state(nfc->scene_manager, NfcSceneReadCardType, 0); scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardType); consumed = true; + } else if(event.event == SubmenuIndexNfcVUnlock) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVUnlockMenu); + consumed = true; + } else if(event.event == SubmenuIndexNfcVSniff) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVSniff); + consumed = true; } scene_manager_set_scene_state(nfc->scene_manager, NfcSceneExtraActions, event.event); } @@ -66,7 +86,7 @@ bool nfc_scene_extra_actions_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_extra_actions_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; submenu_reset(nfc->submenu); } diff --git a/applications/main/nfc_old/scenes/nfc_scene_field.c b/applications/main/nfc_old/scenes/nfc_scene_field.c index 893f4d03ff91..e3eb6a7088b8 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_field.c +++ b/applications/main/nfc_old/scenes/nfc_scene_field.c @@ -1,7 +1,7 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_field_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; furi_hal_nfc_field_on(); @@ -25,7 +25,7 @@ bool nfc_scene_field_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_field_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; furi_hal_nfc_field_off(); notification_internal_message(nfc->notifications, &sequence_reset_blue); diff --git a/applications/main/nfc_old/scenes/nfc_scene_file_select.c b/applications/main/nfc_old/scenes/nfc_scene_file_select.c index 61ac593e0c4e..374a933d1c70 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_file_select.c +++ b/applications/main/nfc_old/scenes/nfc_scene_file_select.c @@ -1,8 +1,8 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #include "nfc/nfc_device.h" void nfc_scene_file_select_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Process file_select return nfc_device_set_loading_callback(nfc->dev, nfc_show_loading_popup, nfc); if(!furi_string_size(nfc->dev->load_path)) { diff --git a/applications/main/nfc_old/scenes/nfc_scene_generate_info.c b/applications/main/nfc_old/scenes/nfc_scene_generate_info.c index e877d771a6f0..7b84ae43b11f 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_generate_info.c +++ b/applications/main/nfc_old/scenes/nfc_scene_generate_info.c @@ -1,14 +1,14 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #include "lib/nfc/helpers/nfc_generators.h" void nfc_scene_generate_info_dialog_callback(DialogExResult result, void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } void nfc_scene_generate_info_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Setup dialog view FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; @@ -34,7 +34,7 @@ void nfc_scene_generate_info_on_enter(void* context) { } bool nfc_scene_generate_info_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -53,7 +53,7 @@ bool nfc_scene_generate_info_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_generate_info_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clean views dialog_ex_reset(nfc->dialog_ex); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_data.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_data.c index b2be2f53a66e..dcb02d3645a5 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_data.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_data.c @@ -1,7 +1,7 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_mf_classic_data_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; MfClassicType type = nfc->dev->dev_data.mf_classic_data.type; MfClassicData* data = &nfc->dev->dev_data.mf_classic_data; TextBox* text_box = nfc->text_box; @@ -20,17 +20,17 @@ void nfc_scene_mf_classic_data_on_enter(void* context) { int bytes_written = 0; for(int block_num = 0; block_num < card_blocks; block_num++) { - bool is_sec_trailer = mifare_classic_is_sector_trailer(block_num); + bool is_sec_trailer = mf_classic_is_sector_trailer(block_num); if(is_sec_trailer) { - uint8_t sector_num = mifare_classic_get_sector_by_block(block_num); + uint8_t sector_num = mf_classic_get_sector_by_block(block_num); MfClassicSectorTrailer* sec_tr = - mifare_classic_get_sector_trailer_by_sector(data, sector_num); + mf_classic_get_sector_trailer_by_sector(data, sector_num); // Key A for(size_t i = 0; i < sizeof(sec_tr->key_a); i += 2) { if((bytes_written % 8 == 0) && (bytes_written != 0)) { furi_string_push_back(nfc->text_box_store, '\n'); } - if(mifare_classic_is_key_found(data, sector_num, MfClassicKeyA)) { + if(mf_classic_is_key_found(data, sector_num, MfClassicKeyA)) { furi_string_cat_printf( nfc->text_box_store, "%02X%02X ", sec_tr->key_a[i], sec_tr->key_a[i + 1]); } else { @@ -43,7 +43,7 @@ void nfc_scene_mf_classic_data_on_enter(void* context) { if((bytes_written % 8 == 0) && (bytes_written != 0)) { furi_string_push_back(nfc->text_box_store, '\n'); } - if(mifare_classic_is_block_read(data, block_num)) { + if(mf_classic_is_block_read(data, block_num)) { furi_string_cat_printf( nfc->text_box_store, "%02X%02X ", @@ -59,7 +59,7 @@ void nfc_scene_mf_classic_data_on_enter(void* context) { if((bytes_written % 8 == 0) && (bytes_written != 0)) { furi_string_push_back(nfc->text_box_store, '\n'); } - if(mifare_classic_is_key_found(data, sector_num, MfClassicKeyB)) { + if(mf_classic_is_key_found(data, sector_num, MfClassicKeyB)) { furi_string_cat_printf( nfc->text_box_store, "%02X%02X ", sec_tr->key_b[i], sec_tr->key_b[i + 1]); } else { @@ -73,7 +73,7 @@ void nfc_scene_mf_classic_data_on_enter(void* context) { if((bytes_written % 8 == 0) && (bytes_written != 0)) { furi_string_push_back(nfc->text_box_store, '\n'); } - if(mifare_classic_is_block_read(data, block_num)) { + if(mf_classic_is_block_read(data, block_num)) { furi_string_cat_printf( nfc->text_box_store, "%02X%02X ", @@ -98,7 +98,7 @@ bool nfc_scene_mf_classic_data_on_event(void* context, SceneManagerEvent event) } void nfc_scene_mf_classic_data_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clean view text_box_reset(nfc->text_box); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_dict_attack.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_dict_attack.c index dd27b6c1b322..5bd24d7eac17 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_dict_attack.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_dict_attack.c @@ -1,4 +1,4 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #include #define TAG "NfcMfClassicDictAttack" @@ -11,29 +11,29 @@ typedef enum { bool nfc_dict_attack_worker_callback(NfcWorkerEvent event, void* context) { furi_assert(context); - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, event); return true; } void nfc_dict_attack_dict_attack_result_callback(void* context) { furi_assert(context); - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventDictAttackSkip); } -static void nfc_scene_mf_classic_dict_attack_update_view(NfcApp* nfc) { +static void nfc_scene_mf_classic_dict_attack_update_view(Nfc* nfc) { MfClassicData* data = &nfc->dev->dev_data.mf_classic_data; uint8_t sectors_read = 0; uint8_t keys_found = 0; // Calculate found keys and read sectors - mifare_classic_get_read_sectors_and_keys(data, §ors_read, &keys_found); + mf_classic_get_read_sectors_and_keys(data, §ors_read, &keys_found); dict_attack_set_keys_found(nfc->dict_attack, keys_found); dict_attack_set_sector_read(nfc->dict_attack, sectors_read); } -static void nfc_scene_mf_classic_dict_attack_prepare_view(NfcApp* nfc, DictAttackState state) { +static void nfc_scene_mf_classic_dict_attack_prepare_view(Nfc* nfc, DictAttackState state) { MfClassicData* data = &nfc->dev->dev_data.mf_classic_data; NfcMfClassicDictAttackData* dict_attack_data = &nfc->dev->dev_data.mf_classic_dict_attack_data; NfcWorkerState worker_state = NfcWorkerStateReady; @@ -88,7 +88,7 @@ static void nfc_scene_mf_classic_dict_attack_prepare_view(NfcApp* nfc, DictAttac } void nfc_scene_mf_classic_dict_attack_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; nfc_scene_mf_classic_dict_attack_prepare_view(nfc, DictAttackStateIdle); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDictAttack); nfc_blink_read_start(nfc); @@ -96,7 +96,7 @@ void nfc_scene_mf_classic_dict_attack_on_enter(void* context) { } bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; MfClassicData* data = &nfc->dev->dev_data.mf_classic_data; bool consumed = false; @@ -111,7 +111,7 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent } else { notification_message(nfc->notifications, &sequence_success); scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSuccess); - DOLPHIN_DEED(DolphinDeedNfcReadSuccess); + dolphin_deed(DolphinDeedNfcReadSuccess); consumed = true; } } else if(event.event == NfcWorkerEventAborted) { @@ -123,7 +123,7 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent notification_message(nfc->notifications, &sequence_success); scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSuccess); // Counting failed attempts too - DOLPHIN_DEED(DolphinDeedNfcReadSuccess); + dolphin_deed(DolphinDeedNfcReadSuccess); consumed = true; } } else if(event.event == NfcWorkerEventCardDetected) { @@ -172,7 +172,7 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent } void nfc_scene_mf_classic_dict_attack_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; NfcMfClassicDictAttackData* dict_attack_data = &nfc->dev->dev_data.mf_classic_dict_attack_data; // Stop worker nfc_worker_stop(nfc->worker); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_emulate.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_emulate.c index 6cf7689052c5..8c0f493e12b4 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_emulate.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_emulate.c @@ -1,11 +1,11 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #define NFC_MF_CLASSIC_DATA_NOT_CHANGED (0UL) #define NFC_MF_CLASSIC_DATA_CHANGED (1UL) bool nfc_mf_classic_emulate_worker_callback(NfcWorkerEvent event, void* context) { UNUSED(event); - NfcApp* nfc = context; + Nfc* nfc = context; scene_manager_set_scene_state( nfc->scene_manager, NfcSceneMfClassicEmulate, NFC_MF_CLASSIC_DATA_CHANGED); @@ -13,7 +13,7 @@ bool nfc_mf_classic_emulate_worker_callback(NfcWorkerEvent event, void* context) } void nfc_scene_mf_classic_emulate_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Setup view Popup* popup = nfc->popup; @@ -38,7 +38,7 @@ void nfc_scene_mf_classic_emulate_on_enter(void* context) { } bool nfc_scene_mf_classic_emulate_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeBack) { @@ -60,7 +60,7 @@ bool nfc_scene_mf_classic_emulate_on_event(void* context, SceneManagerEvent even } void nfc_scene_mf_classic_emulate_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clear view popup_reset(nfc->popup); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys.c index b7cc2f283450..8a7dc2c1839e 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys.c @@ -1,14 +1,14 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_mf_classic_keys_widget_callback(GuiButtonType result, InputType type, void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } } void nfc_scene_mf_classic_keys_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Load flipper dict keys total uint32_t flipper_dict_keys_total = 0; @@ -48,7 +48,7 @@ void nfc_scene_mf_classic_keys_on_enter(void* context) { } bool nfc_scene_mf_classic_keys_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -65,7 +65,7 @@ bool nfc_scene_mf_classic_keys_on_event(void* context, SceneManagerEvent event) } void nfc_scene_mf_classic_keys_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; widget_reset(nfc->widget); } diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_add.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_add.c index 37b543b8d937..3a999f031144 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_add.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_add.c @@ -1,14 +1,14 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #include void nfc_scene_mf_classic_keys_add_byte_input_callback(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); } void nfc_scene_mf_classic_keys_add_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Setup view ByteInput* byte_input = nfc->byte_input; @@ -24,7 +24,7 @@ void nfc_scene_mf_classic_keys_add_on_enter(void* context) { } bool nfc_scene_mf_classic_keys_add_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -52,7 +52,7 @@ bool nfc_scene_mf_classic_keys_add_on_event(void* context, SceneManagerEvent eve } void nfc_scene_mf_classic_keys_add_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clear view byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_delete.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_delete.c index 9f34c8eee0de..0ea3f59a45ef 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_delete.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_delete.c @@ -1,17 +1,17 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_mf_classic_keys_delete_widget_callback( GuiButtonType result, InputType type, void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } } void nfc_scene_mf_classic_keys_delete_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; MfClassicDict* dict = mf_classic_dict_alloc(MfClassicDictTypeUser); uint32_t key_index = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicKeysDelete); @@ -51,7 +51,7 @@ void nfc_scene_mf_classic_keys_delete_on_enter(void* context) { } bool nfc_scene_mf_classic_keys_delete_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; uint32_t key_index = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicKeysDelete); @@ -77,7 +77,7 @@ bool nfc_scene_mf_classic_keys_delete_on_event(void* context, SceneManagerEvent } void nfc_scene_mf_classic_keys_delete_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; widget_reset(nfc->widget); } diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_list.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_list.c index 6a7be48a0bb3..57f9fe656247 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_list.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_list.c @@ -1,22 +1,22 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #define NFC_SCENE_MF_CLASSIC_KEYS_LIST_MAX (100) void nfc_scene_mf_classic_keys_list_submenu_callback(void* context, uint32_t index) { furi_assert(context); - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_mf_classic_keys_list_popup_callback(void* context) { furi_assert(context); - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); } -void nfc_scene_mf_classic_keys_list_prepare(NfcApp* nfc, MfClassicDict* dict) { +void nfc_scene_mf_classic_keys_list_prepare(Nfc* nfc, MfClassicDict* dict) { Submenu* submenu = nfc->submenu; uint32_t index = 0; FuriString* temp_key; @@ -35,7 +35,7 @@ void nfc_scene_mf_classic_keys_list_prepare(NfcApp* nfc, MfClassicDict* dict) { } void nfc_scene_mf_classic_keys_list_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; MfClassicDict* dict = mf_classic_dict_alloc(MfClassicDictTypeUser); MfClassicUserKeys_init(nfc->mfc_key_strs); if(dict) { @@ -71,7 +71,7 @@ void nfc_scene_mf_classic_keys_list_on_enter(void* context) { } bool nfc_scene_mf_classic_keys_list_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { if(event.event == NfcCustomEventViewExit) { @@ -87,7 +87,7 @@ bool nfc_scene_mf_classic_keys_list_on_event(void* context, SceneManagerEvent ev } void nfc_scene_mf_classic_keys_list_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; MfClassicUserKeys_it_t it; for(MfClassicUserKeys_it(it, nfc->mfc_key_strs); !MfClassicUserKeys_end_p(it); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_warn_duplicate.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_warn_duplicate.c index 5cc1ba635399..ab41989b2c73 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_warn_duplicate.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_warn_duplicate.c @@ -1,12 +1,12 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_mf_classic_keys_warn_duplicate_popup_callback(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); } void nfc_scene_mf_classic_keys_warn_duplicate_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Setup view Popup* popup = nfc->popup; @@ -28,7 +28,7 @@ void nfc_scene_mf_classic_keys_warn_duplicate_on_enter(void* context) { } bool nfc_scene_mf_classic_keys_warn_duplicate_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -41,7 +41,7 @@ bool nfc_scene_mf_classic_keys_warn_duplicate_on_event(void* context, SceneManag } void nfc_scene_mf_classic_keys_warn_duplicate_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; popup_reset(nfc->popup); } diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_menu.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_menu.c index 18e1a78aa80b..9c4163676462 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_menu.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_menu.c @@ -1,4 +1,4 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #include enum SubmenuIndex { @@ -9,20 +9,20 @@ enum SubmenuIndex { }; void nfc_scene_mf_classic_menu_submenu_callback(void* context, uint32_t index) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_mf_classic_menu_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; Submenu* submenu = nfc->submenu; submenu_add_item( submenu, "Save", SubmenuIndexSave, nfc_scene_mf_classic_menu_submenu_callback, nfc); submenu_add_item( submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_mf_classic_menu_submenu_callback, nfc); - if(!mifare_classic_is_card_read(&nfc->dev->dev_data.mf_classic_data)) { + if(!mf_classic_is_card_read(&nfc->dev->dev_data.mf_classic_data)) { submenu_add_item( submenu, "Detect Reader", @@ -40,7 +40,7 @@ void nfc_scene_mf_classic_menu_on_enter(void* context) { } bool nfc_scene_mf_classic_menu_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -54,14 +54,14 @@ bool nfc_scene_mf_classic_menu_on_event(void* context, SceneManagerEvent event) } else if(event.event == SubmenuIndexEmulate) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate); if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) { - DOLPHIN_DEED(DolphinDeedNfcAddEmulate); + dolphin_deed(DolphinDeedNfcAddEmulate); } else { - DOLPHIN_DEED(DolphinDeedNfcEmulate); + dolphin_deed(DolphinDeedNfcEmulate); } consumed = true; } else if(event.event == SubmenuIndexDetectReader) { scene_manager_next_scene(nfc->scene_manager, NfcSceneDetectReader); - DOLPHIN_DEED(DolphinDeedNfcDetectReader); + dolphin_deed(DolphinDeedNfcDetectReader); consumed = true; } else if(event.event == SubmenuIndexInfo) { scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); @@ -75,7 +75,7 @@ bool nfc_scene_mf_classic_menu_on_event(void* context, SceneManagerEvent event) } void nfc_scene_mf_classic_menu_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clear view submenu_reset(nfc->submenu); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_read_success.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_read_success.c index bdc3b137eb23..444c9a540e7d 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_read_success.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_read_success.c @@ -1,11 +1,11 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_mf_classic_read_success_widget_callback( GuiButtonType result, InputType type, void* context) { furi_assert(context); - NfcApp* nfc = context; + Nfc* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); @@ -13,7 +13,7 @@ void nfc_scene_mf_classic_read_success_widget_callback( } void nfc_scene_mf_classic_read_success_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; NfcDeviceData* dev_data = &nfc->dev->dev_data; MfClassicData* mf_data = &dev_data->mf_classic_data; @@ -33,11 +33,11 @@ void nfc_scene_mf_classic_read_success_on_enter(void* context) { for(size_t i = 0; i < dev_data->nfc_data.uid_len; i++) { furi_string_cat_printf(temp_str, " %02X", dev_data->nfc_data.uid[i]); } - uint8_t sectors_total = mifare_classic_get_total_sectors_num(mf_data->type); + uint8_t sectors_total = mf_classic_get_total_sectors_num(mf_data->type); uint8_t keys_total = sectors_total * 2; uint8_t keys_found = 0; uint8_t sectors_read = 0; - mifare_classic_get_read_sectors_and_keys(mf_data, §ors_read, &keys_found); + mf_classic_get_read_sectors_and_keys(mf_data, §ors_read, &keys_found); furi_string_cat_printf(temp_str, "\nKeys Found: %d/%d", keys_found, keys_total); furi_string_cat_printf(temp_str, "\nSectors Read: %d/%d", sectors_read, sectors_total); } @@ -51,7 +51,7 @@ void nfc_scene_mf_classic_read_success_on_enter(void* context) { } bool nfc_scene_mf_classic_read_success_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -73,7 +73,7 @@ bool nfc_scene_mf_classic_read_success_on_event(void* context, SceneManagerEvent } void nfc_scene_mf_classic_read_success_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; notification_message_block(nfc->notifications, &sequence_reset_green); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_update.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_update.c index 731c1e2683d7..ffef1b7b9f06 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_update.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_update.c @@ -1,4 +1,4 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #include enum { @@ -9,13 +9,13 @@ enum { bool nfc_mf_classic_update_worker_callback(NfcWorkerEvent event, void* context) { furi_assert(context); - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, event); return true; } -static void nfc_scene_mf_classic_update_setup_view(NfcApp* nfc) { +static void nfc_scene_mf_classic_update_setup_view(Nfc* nfc) { Popup* popup = nfc->popup; popup_reset(popup); uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicUpdate); @@ -33,7 +33,7 @@ static void nfc_scene_mf_classic_update_setup_view(NfcApp* nfc) { } void nfc_scene_mf_classic_update_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; dolphin_deed(DolphinDeedNfcEmulate); scene_manager_set_scene_state( @@ -51,7 +51,7 @@ void nfc_scene_mf_classic_update_on_enter(void* context) { } bool nfc_scene_mf_classic_update_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -87,7 +87,7 @@ bool nfc_scene_mf_classic_update_on_event(void* context, SceneManagerEvent event } void nfc_scene_mf_classic_update_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; nfc_worker_stop(nfc->worker); scene_manager_set_scene_state( nfc->scene_manager, NfcSceneMfClassicUpdate, NfcSceneMfClassicUpdateStateCardSearch); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_update_success.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_update_success.c index 1f367caa0bb5..fb1868459d4a 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_update_success.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_update_success.c @@ -1,13 +1,13 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #include void nfc_scene_mf_classic_update_success_popup_callback(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); } void nfc_scene_mf_classic_update_success_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; dolphin_deed(DolphinDeedNfcSave); notification_message(nfc->notifications, &sequence_success); @@ -24,7 +24,7 @@ void nfc_scene_mf_classic_update_success_on_enter(void* context) { } bool nfc_scene_mf_classic_update_success_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -37,7 +37,7 @@ bool nfc_scene_mf_classic_update_success_on_event(void* context, SceneManagerEve } void nfc_scene_mf_classic_update_success_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clear view popup_reset(nfc->popup); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_write.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_write.c index e074f8036c54..20ebfcc70a2c 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_write.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_write.c @@ -1,4 +1,4 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #include enum { @@ -9,13 +9,13 @@ enum { bool nfc_mf_classic_write_worker_callback(NfcWorkerEvent event, void* context) { furi_assert(context); - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, event); return true; } -static void nfc_scene_mf_classic_write_setup_view(NfcApp* nfc) { +static void nfc_scene_mf_classic_write_setup_view(Nfc* nfc) { Popup* popup = nfc->popup; popup_reset(popup); uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicWrite); @@ -33,7 +33,7 @@ static void nfc_scene_mf_classic_write_setup_view(NfcApp* nfc) { } void nfc_scene_mf_classic_write_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; dolphin_deed(DolphinDeedNfcEmulate); scene_manager_set_scene_state( @@ -51,7 +51,7 @@ void nfc_scene_mf_classic_write_on_enter(void* context) { } bool nfc_scene_mf_classic_write_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -80,7 +80,7 @@ bool nfc_scene_mf_classic_write_on_event(void* context, SceneManagerEvent event) } void nfc_scene_mf_classic_write_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; nfc_worker_stop(nfc->worker); scene_manager_set_scene_state( diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_write_fail.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_write_fail.c index 695a3c4a7402..aeea6eef0692 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_write_fail.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_write_fail.c @@ -1,17 +1,17 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_mf_classic_write_fail_widget_callback( GuiButtonType result, InputType type, void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } } void nfc_scene_mf_classic_write_fail_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; Widget* widget = nfc->widget; notification_message(nfc->notifications, &sequence_error); @@ -36,7 +36,7 @@ void nfc_scene_mf_classic_write_fail_on_enter(void* context) { } bool nfc_scene_mf_classic_write_fail_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -52,7 +52,7 @@ bool nfc_scene_mf_classic_write_fail_on_event(void* context, SceneManagerEvent e } void nfc_scene_mf_classic_write_fail_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; widget_reset(nfc->widget); } diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_write_success.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_write_success.c index 9acc14b12ecb..00030d4fe8ca 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_write_success.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_write_success.c @@ -1,13 +1,13 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #include void nfc_scene_mf_classic_write_success_popup_callback(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); } void nfc_scene_mf_classic_write_success_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; dolphin_deed(DolphinDeedNfcSave); notification_message(nfc->notifications, &sequence_success); @@ -24,7 +24,7 @@ void nfc_scene_mf_classic_write_success_on_enter(void* context) { } bool nfc_scene_mf_classic_write_success_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -37,7 +37,7 @@ bool nfc_scene_mf_classic_write_success_on_event(void* context, SceneManagerEven } void nfc_scene_mf_classic_write_success_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clear view popup_reset(nfc->popup); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_wrong_card.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_wrong_card.c index ac7d6593470d..2c56270e36d2 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_wrong_card.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_wrong_card.c @@ -1,17 +1,17 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_mf_classic_wrong_card_widget_callback( GuiButtonType result, InputType type, void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } } void nfc_scene_mf_classic_wrong_card_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; Widget* widget = nfc->widget; notification_message(nfc->notifications, &sequence_error); @@ -35,7 +35,7 @@ void nfc_scene_mf_classic_wrong_card_on_enter(void* context) { } bool nfc_scene_mf_classic_wrong_card_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -47,7 +47,7 @@ bool nfc_scene_mf_classic_wrong_card_on_event(void* context, SceneManagerEvent e } void nfc_scene_mf_classic_wrong_card_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; widget_reset(nfc->widget); } \ No newline at end of file diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_desfire_app.c b/applications/main/nfc_old/scenes/nfc_scene_mf_desfire_app.c index 2c856157270d..882dc5fea8f2 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_desfire_app.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_desfire_app.c @@ -1,4 +1,4 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #define TAG "NfcSceneMfDesfireApp" @@ -10,11 +10,11 @@ enum SubmenuIndex { void nfc_scene_mf_desfire_popup_callback(void* context) { furi_assert(context); - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); } -MifareDesfireApplication* nfc_scene_mf_desfire_app_get_app(NfcApp* nfc) { +MifareDesfireApplication* nfc_scene_mf_desfire_app_get_app(Nfc* nfc) { uint32_t app_idx = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireApp) >> 1; MifareDesfireApplication* app = nfc->dev->dev_data.mf_df_data.app_head; @@ -25,13 +25,13 @@ MifareDesfireApplication* nfc_scene_mf_desfire_app_get_app(NfcApp* nfc) { } void nfc_scene_mf_desfire_app_submenu_callback(void* context, uint32_t index) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_mf_desfire_app_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; MifareDesfireApplication* app = nfc_scene_mf_desfire_app_get_app(nfc); if(!app) { popup_set_icon(nfc->popup, 5, 5, &I_WarningDolphin_45x42); @@ -69,7 +69,7 @@ void nfc_scene_mf_desfire_app_on_enter(void* context) { } bool nfc_scene_mf_desfire_app_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireApp); @@ -110,7 +110,7 @@ bool nfc_scene_mf_desfire_app_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_mf_desfire_app_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clear views popup_reset(nfc->popup); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_desfire_data.c b/applications/main/nfc_old/scenes/nfc_scene_mf_desfire_data.c index e9e529909dc5..c7caee8dc6d3 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_desfire_data.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_desfire_data.c @@ -1,4 +1,4 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #define TAG "NfcSceneMfDesfireData" @@ -13,13 +13,13 @@ enum SubmenuIndex { }; void nfc_scene_mf_desfire_data_submenu_callback(void* context, uint32_t index) { - NfcApp* nfc = (NfcApp*)context; + Nfc* nfc = (Nfc*)context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_mf_desfire_data_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; Submenu* submenu = nfc->submenu; uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireData); MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data; @@ -57,7 +57,7 @@ void nfc_scene_mf_desfire_data_on_enter(void* context) { } bool nfc_scene_mf_desfire_data_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireData); MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data; @@ -95,7 +95,7 @@ bool nfc_scene_mf_desfire_data_on_event(void* context, SceneManagerEvent event) } void nfc_scene_mf_desfire_data_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clear views text_box_reset(nfc->text_box); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_desfire_menu.c b/applications/main/nfc_old/scenes/nfc_scene_mf_desfire_menu.c index b3ebe9a469a9..9cebefedfa1b 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_desfire_menu.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_desfire_menu.c @@ -1,4 +1,4 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #include enum SubmenuIndex { @@ -8,13 +8,13 @@ enum SubmenuIndex { }; void nfc_scene_mf_desfire_menu_submenu_callback(void* context, uint32_t index) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_mf_desfire_menu_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; Submenu* submenu = nfc->submenu; submenu_add_item( @@ -35,7 +35,7 @@ void nfc_scene_mf_desfire_menu_on_enter(void* context) { } bool nfc_scene_mf_desfire_menu_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -50,9 +50,9 @@ bool nfc_scene_mf_desfire_menu_on_event(void* context, SceneManagerEvent event) } else if(event.event == SubmenuIndexEmulateUid) { scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) { - DOLPHIN_DEED(DolphinDeedNfcAddEmulate); + dolphin_deed(DolphinDeedNfcAddEmulate); } else { - DOLPHIN_DEED(DolphinDeedNfcEmulate); + dolphin_deed(DolphinDeedNfcEmulate); } consumed = true; } else if(event.event == SubmenuIndexInfo) { @@ -65,7 +65,7 @@ bool nfc_scene_mf_desfire_menu_on_event(void* context, SceneManagerEvent event) } void nfc_scene_mf_desfire_menu_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clear view submenu_reset(nfc->submenu); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_desfire_read_success.c b/applications/main/nfc_old/scenes/nfc_scene_mf_desfire_read_success.c index 919070595dbe..633549eb5d8f 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_desfire_read_success.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_desfire_read_success.c @@ -1,11 +1,11 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #include void nfc_scene_mf_desfire_read_success_widget_callback( GuiButtonType result, InputType type, void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); @@ -13,42 +13,47 @@ void nfc_scene_mf_desfire_read_success_widget_callback( } void nfc_scene_mf_desfire_read_success_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data; MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data; Widget* widget = nfc->widget; // Prepare string for data display - FuriString* temp_str = furi_string_alloc_printf("\e#MIFARE DESfire\n"); - 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]); - } + FuriString* temp_str = NULL; + if(furi_string_size(nfc->dev->dev_data.parsed_data)) { + temp_str = furi_string_alloc_set(nfc->dev->dev_data.parsed_data); + } else { + temp_str = furi_string_alloc_printf("\e#MIFARE DESFire\n"); + 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]); + } - uint32_t bytes_total = 1UL << (data->version.sw_storage >> 1); - uint32_t bytes_free = data->free_memory ? data->free_memory->bytes : 0; - furi_string_cat_printf(temp_str, "\n%lu", bytes_total); - if(data->version.sw_storage & 1) { - furi_string_push_back(temp_str, '+'); - } - furi_string_cat_printf(temp_str, " bytes, %lu bytes free\n", bytes_free); - - uint16_t n_apps = 0; - uint16_t n_files = 0; - for(MifareDesfireApplication* app = data->app_head; app; app = app->next) { - n_apps++; - for(MifareDesfireFile* file = app->file_head; file; file = file->next) { - n_files++; + uint32_t bytes_total = 1UL << (data->version.sw_storage >> 1); + uint32_t bytes_free = data->free_memory ? data->free_memory->bytes : 0; + furi_string_cat_printf(temp_str, "\n%lu", bytes_total); + if(data->version.sw_storage & 1) { + furi_string_push_back(temp_str, '+'); + } + furi_string_cat_printf(temp_str, " bytes, %lu bytes free\n", bytes_free); + + uint16_t n_apps = 0; + uint16_t n_files = 0; + for(MifareDesfireApplication* app = data->app_head; app; app = app->next) { + n_apps++; + for(MifareDesfireFile* file = app->file_head; file; file = file->next) { + n_files++; + } + } + furi_string_cat_printf(temp_str, "%d Application", n_apps); + if(n_apps != 1) { + furi_string_push_back(temp_str, 's'); + } + furi_string_cat_printf(temp_str, ", %d file", n_files); + if(n_files != 1) { + furi_string_push_back(temp_str, 's'); } - } - furi_string_cat_printf(temp_str, "%d Application", n_apps); - if(n_apps != 1) { - furi_string_push_back(temp_str, 's'); - } - furi_string_cat_printf(temp_str, ", %d file", n_files); - if(n_files != 1) { - furi_string_push_back(temp_str, 's'); } notification_message_block(nfc->notifications, &sequence_set_green_255); @@ -67,7 +72,7 @@ void nfc_scene_mf_desfire_read_success_on_enter(void* context) { } bool nfc_scene_mf_desfire_read_success_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -87,7 +92,7 @@ bool nfc_scene_mf_desfire_read_success_on_event(void* context, SceneManagerEvent } void nfc_scene_mf_desfire_read_success_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; notification_message_block(nfc->notifications, &sequence_reset_green); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_data.c b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_data.c index 7d56cb1483eb..8cd223ee64dd 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_data.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_data.c @@ -1,7 +1,7 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_mf_ultralight_data_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; MfUltralightData* data = &nfc->dev->dev_data.mf_ul_data; TextBox* text_box = nfc->text_box; @@ -24,7 +24,7 @@ bool nfc_scene_mf_ultralight_data_on_event(void* context, SceneManagerEvent even } void nfc_scene_mf_ultralight_data_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clean view text_box_reset(nfc->text_box); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_emulate.c b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_emulate.c index 192d67bef73e..9d8f17f9a2c0 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_emulate.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_emulate.c @@ -1,11 +1,11 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #define NFC_MF_UL_DATA_NOT_CHANGED (0UL) #define NFC_MF_UL_DATA_CHANGED (1UL) bool nfc_mf_ultralight_emulate_worker_callback(NfcWorkerEvent event, void* context) { UNUSED(event); - NfcApp* nfc = context; + Nfc* nfc = context; scene_manager_set_scene_state( nfc->scene_manager, NfcSceneMfUltralightEmulate, NFC_MF_UL_DATA_CHANGED); @@ -13,7 +13,7 @@ bool nfc_mf_ultralight_emulate_worker_callback(NfcWorkerEvent event, void* conte } void nfc_scene_mf_ultralight_emulate_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Setup view MfUltralightType type = nfc->dev->dev_data.mf_ul_data.type; @@ -43,7 +43,7 @@ void nfc_scene_mf_ultralight_emulate_on_enter(void* context) { } bool nfc_scene_mf_ultralight_emulate_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeBack) { @@ -65,7 +65,7 @@ bool nfc_scene_mf_ultralight_emulate_on_event(void* context, SceneManagerEvent e } void nfc_scene_mf_ultralight_emulate_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clear view popup_reset(nfc->popup); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_key_input.c b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_key_input.c index e8c87693d462..089187d5bc3a 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_key_input.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_key_input.c @@ -1,13 +1,13 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_mf_ultralight_key_input_byte_input_callback(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); } void nfc_scene_mf_ultralight_key_input_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Setup view ByteInput* byte_input = nfc->byte_input; @@ -23,7 +23,7 @@ void nfc_scene_mf_ultralight_key_input_on_enter(void* context) { } bool nfc_scene_mf_ultralight_key_input_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -36,7 +36,7 @@ bool nfc_scene_mf_ultralight_key_input_on_event(void* context, SceneManagerEvent } void nfc_scene_mf_ultralight_key_input_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clear view byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_menu.c b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_menu.c index 6069ed356c8f..b3bd780f4b4b 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_menu.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_menu.c @@ -1,4 +1,4 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #include enum SubmenuIndex { @@ -9,17 +9,17 @@ enum SubmenuIndex { }; void nfc_scene_mf_ultralight_menu_submenu_callback(void* context, uint32_t index) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_mf_ultralight_menu_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; Submenu* submenu = nfc->submenu; MfUltralightData* data = &nfc->dev->dev_data.mf_ul_data; - if(!mf_ul_is_full_capture(data)) { + if(!mf_ul_is_full_capture(data) && data->type != MfUltralightTypeULC) { submenu_add_item( submenu, "Unlock", @@ -29,12 +29,14 @@ void nfc_scene_mf_ultralight_menu_on_enter(void* context) { } submenu_add_item( submenu, "Save", SubmenuIndexSave, nfc_scene_mf_ultralight_menu_submenu_callback, nfc); - submenu_add_item( - submenu, - "Emulate", - SubmenuIndexEmulate, - nfc_scene_mf_ultralight_menu_submenu_callback, - nfc); + if(mf_ul_emulation_supported(data)) { + submenu_add_item( + submenu, + "Emulate", + SubmenuIndexEmulate, + nfc_scene_mf_ultralight_menu_submenu_callback, + nfc); + } submenu_add_item( submenu, "Info", SubmenuIndexInfo, nfc_scene_mf_ultralight_menu_submenu_callback, nfc); @@ -45,7 +47,7 @@ void nfc_scene_mf_ultralight_menu_on_enter(void* context) { } bool nfc_scene_mf_ultralight_menu_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -58,9 +60,9 @@ bool nfc_scene_mf_ultralight_menu_on_event(void* context, SceneManagerEvent even } else if(event.event == SubmenuIndexEmulate) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate); if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) { - DOLPHIN_DEED(DolphinDeedNfcAddEmulate); + dolphin_deed(DolphinDeedNfcAddEmulate); } else { - DOLPHIN_DEED(DolphinDeedNfcEmulate); + dolphin_deed(DolphinDeedNfcEmulate); } consumed = true; } else if(event.event == SubmenuIndexUnlock) { @@ -80,7 +82,7 @@ bool nfc_scene_mf_ultralight_menu_on_event(void* context, SceneManagerEvent even } void nfc_scene_mf_ultralight_menu_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clear view submenu_reset(nfc->submenu); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_read_auth.c b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_read_auth.c index 4d549989ab4a..2ab5e3f3f441 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_read_auth.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_read_auth.c @@ -1,4 +1,4 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" typedef enum { NfcSceneMfUlReadStateIdle, @@ -8,7 +8,7 @@ typedef enum { } NfcSceneMfUlReadState; bool nfc_scene_mf_ultralight_read_auth_worker_callback(NfcWorkerEvent event, void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; if(event == NfcWorkerEventMfUltralightPassKey) { memcpy(nfc->dev->dev_data.mf_ul_data.auth_key, nfc->byte_input_store, 4); @@ -18,7 +18,7 @@ bool nfc_scene_mf_ultralight_read_auth_worker_callback(NfcWorkerEvent event, voi return true; } -void nfc_scene_mf_ultralight_read_auth_set_state(NfcApp* nfc, NfcSceneMfUlReadState state) { +void nfc_scene_mf_ultralight_read_auth_set_state(Nfc* nfc, NfcSceneMfUlReadState state) { uint32_t curr_state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightReadAuth); if(curr_state != state) { @@ -53,7 +53,7 @@ void nfc_scene_mf_ultralight_read_auth_set_state(NfcApp* nfc, NfcSceneMfUlReadSt } void nfc_scene_mf_ultralight_read_auth_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; nfc_device_clear(nfc->dev); // Setup view @@ -69,7 +69,7 @@ void nfc_scene_mf_ultralight_read_auth_on_enter(void* context) { } bool nfc_scene_mf_ultralight_read_auth_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -104,7 +104,7 @@ bool nfc_scene_mf_ultralight_read_auth_on_event(void* context, SceneManagerEvent } void nfc_scene_mf_ultralight_read_auth_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Stop worker nfc_worker_stop(nfc->worker); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_read_auth_result.c b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_read_auth_result.c index c3ea1522fac3..b125e999127e 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_read_auth_result.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_read_auth_result.c @@ -1,10 +1,10 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_mf_ultralight_read_auth_result_widget_callback( GuiButtonType result, InputType type, void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); @@ -12,7 +12,7 @@ void nfc_scene_mf_ultralight_read_auth_result_widget_callback( } void nfc_scene_mf_ultralight_read_auth_result_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Setup dialog view FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data; @@ -74,7 +74,7 @@ void nfc_scene_mf_ultralight_read_auth_result_on_enter(void* context) { } bool nfc_scene_mf_ultralight_read_auth_result_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -107,7 +107,7 @@ bool nfc_scene_mf_ultralight_read_auth_result_on_event(void* context, SceneManag } void nfc_scene_mf_ultralight_read_auth_result_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clean views widget_reset(nfc->widget); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_read_success.c b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_read_success.c index 60c8191e5a10..cb5ccd6e8268 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_read_success.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_read_success.c @@ -1,10 +1,10 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_mf_ultralight_read_success_widget_callback( GuiButtonType result, InputType type, void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); @@ -12,7 +12,7 @@ void nfc_scene_mf_ultralight_read_success_widget_callback( } void nfc_scene_mf_ultralight_read_success_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Setup widget view FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; @@ -55,7 +55,7 @@ void nfc_scene_mf_ultralight_read_success_on_enter(void* context) { } bool nfc_scene_mf_ultralight_read_success_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -75,7 +75,7 @@ bool nfc_scene_mf_ultralight_read_success_on_event(void* context, SceneManagerEv } void nfc_scene_mf_ultralight_read_success_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; notification_message_block(nfc->notifications, &sequence_reset_green); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_unlock_auto.c b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_unlock_auto.c index 24f1703a28f5..c59fe3a7d090 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_unlock_auto.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_unlock_auto.c @@ -1,14 +1,14 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" bool nfc_scene_mf_ultralight_unlock_auto_worker_callback(NfcWorkerEvent event, void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, event); return true; } void nfc_scene_mf_ultralight_unlock_auto_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Setup view widget_add_string_multiline_element( @@ -35,7 +35,7 @@ void nfc_scene_mf_ultralight_unlock_auto_on_enter(void* context) { } bool nfc_scene_mf_ultralight_unlock_auto_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -53,7 +53,7 @@ bool nfc_scene_mf_ultralight_unlock_auto_on_event(void* context, SceneManagerEve } void nfc_scene_mf_ultralight_unlock_auto_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Stop worker nfc_worker_stop(nfc->worker); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_unlock_menu.c b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_unlock_menu.c index 5c0604d383c4..484629b0bbe1 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_unlock_menu.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_unlock_menu.c @@ -1,4 +1,4 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" enum SubmenuIndex { SubmenuIndexMfUlUnlockMenuAuto, @@ -8,13 +8,13 @@ enum SubmenuIndex { }; void nfc_scene_mf_ultralight_unlock_menu_submenu_callback(void* context, uint32_t index) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_mf_ultralight_unlock_menu_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; Submenu* submenu = nfc->submenu; uint32_t state = @@ -50,7 +50,7 @@ void nfc_scene_mf_ultralight_unlock_menu_on_enter(void* context) { } bool nfc_scene_mf_ultralight_unlock_menu_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -77,7 +77,7 @@ bool nfc_scene_mf_ultralight_unlock_menu_on_event(void* context, SceneManagerEve } void nfc_scene_mf_ultralight_unlock_menu_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; submenu_reset(nfc->submenu); } diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_unlock_warn.c b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_unlock_warn.c index 4c8a1c90ff93..af2eca0ce5d2 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_unlock_warn.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_unlock_warn.c @@ -1,14 +1,14 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #include void nfc_scene_mf_ultralight_unlock_warn_dialog_callback(DialogExResult result, void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } void nfc_scene_mf_ultralight_unlock_warn_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; DialogEx* dialog_ex = nfc->dialog_ex; MfUltralightAuthMethod auth_method = nfc->dev->dev_data.mf_ul_data.auth_method; @@ -52,7 +52,7 @@ void nfc_scene_mf_ultralight_unlock_warn_on_enter(void* context) { } bool nfc_scene_mf_ultralight_unlock_warn_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; @@ -61,7 +61,7 @@ bool nfc_scene_mf_ultralight_unlock_warn_on_event(void* context, SceneManagerEve if(event.type == SceneManagerEventTypeCustom) { if(event.event == DialogExResultRight) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadAuth); - DOLPHIN_DEED(DolphinDeedNfcRead); + dolphin_deed(DolphinDeedNfcRead); consumed = true; } else if(event.event == DialogExResultLeft) { if(auth_method == MfUltralightAuthMethodAuto) { @@ -79,7 +79,7 @@ bool nfc_scene_mf_ultralight_unlock_warn_on_event(void* context, SceneManagerEve if(event.type == SceneManagerEventTypeCustom) { if(event.event == DialogExResultCenter) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadAuth); - DOLPHIN_DEED(DolphinDeedNfcRead); + dolphin_deed(DolphinDeedNfcRead); consumed = true; } } @@ -89,7 +89,7 @@ bool nfc_scene_mf_ultralight_unlock_warn_on_event(void* context, SceneManagerEve } void nfc_scene_mf_ultralight_unlock_warn_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; dialog_ex_reset(nfc->dialog_ex); nfc_text_store_clear(nfc); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mfkey_complete.c b/applications/main/nfc_old/scenes/nfc_scene_mfkey_complete.c index b6ca75ee933a..04515f24ff64 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mfkey_complete.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mfkey_complete.c @@ -1,14 +1,14 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_mfkey_complete_callback(GuiButtonType result, InputType type, void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } } void nfc_scene_mfkey_complete_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; widget_add_string_element(nfc->widget, 64, 0, AlignCenter, AlignTop, FontPrimary, "Complete!"); widget_add_string_multiline_element( @@ -26,7 +26,7 @@ void nfc_scene_mfkey_complete_on_enter(void* context) { } bool nfc_scene_mfkey_complete_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -43,7 +43,7 @@ bool nfc_scene_mfkey_complete_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_mfkey_complete_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; widget_reset(nfc->widget); } diff --git a/applications/main/nfc_old/scenes/nfc_scene_mfkey_nonces_info.c b/applications/main/nfc_old/scenes/nfc_scene_mfkey_nonces_info.c index 5e86f2376fdb..6d9852f3e666 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mfkey_nonces_info.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mfkey_nonces_info.c @@ -1,15 +1,15 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #include void nfc_scene_mfkey_nonces_info_callback(GuiButtonType result, InputType type, void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } } void nfc_scene_mfkey_nonces_info_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; FuriString* temp_str; temp_str = furi_string_alloc(); @@ -31,7 +31,7 @@ void nfc_scene_mfkey_nonces_info_on_enter(void* context) { } bool nfc_scene_mfkey_nonces_info_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -48,7 +48,7 @@ bool nfc_scene_mfkey_nonces_info_on_event(void* context, SceneManagerEvent event } void nfc_scene_mfkey_nonces_info_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clear view widget_reset(nfc->widget); diff --git a/applications/main/nfc_old/scenes/nfc_scene_nfc_data_info.c b/applications/main/nfc_old/scenes/nfc_scene_nfc_data_info.c index 734a9a8ce92e..66a9174df476 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_nfc_data_info.c +++ b/applications/main/nfc_old/scenes/nfc_scene_nfc_data_info.c @@ -1,14 +1,91 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_nfc_data_info_widget_callback(GuiButtonType result, InputType type, void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } } +void nfc_scene_slix_build_string( + FuriString* temp_str, + NfcVData* nfcv_data, + SlixTypeFeatures features, + const char* type) { + furi_string_cat_printf(temp_str, "Type: %s\n", type); + furi_string_cat_printf(temp_str, "Keys:\n"); + if(features & SlixFeatureRead) { + furi_string_cat_printf( + temp_str, + " Read %08llX%s\n", + nfc_util_bytes2num(nfcv_data->sub_data.slix.key_read, 4), + (nfcv_data->sub_data.slix.flags & NfcVSlixDataFlagsHasKeyRead) ? "" : " (unset)"); + } + if(features & SlixFeatureWrite) { + furi_string_cat_printf( + temp_str, + " Write %08llX%s\n", + nfc_util_bytes2num(nfcv_data->sub_data.slix.key_write, 4), + (nfcv_data->sub_data.slix.flags & NfcVSlixDataFlagsHasKeyWrite) ? "" : " (unset)"); + } + if(features & SlixFeaturePrivacy) { + furi_string_cat_printf( + temp_str, + " Privacy %08llX%s\n", + nfc_util_bytes2num(nfcv_data->sub_data.slix.key_privacy, 4), + (nfcv_data->sub_data.slix.flags & NfcVSlixDataFlagsHasKeyPrivacy) ? "" : " (unset)"); + furi_string_cat_printf( + temp_str, + " Privacy mode %s\n", + (nfcv_data->sub_data.slix.flags & NfcVSlixDataFlagsPrivacy) ? "ENABLED" : "DISABLED"); + } + if(features & SlixFeatureDestroy) { + furi_string_cat_printf( + temp_str, + " Destroy %08llX%s\n", + nfc_util_bytes2num(nfcv_data->sub_data.slix.key_destroy, 4), + (nfcv_data->sub_data.slix.flags & NfcVSlixDataFlagsHasKeyDestroy) ? "" : " (unset)"); + } + if(features & SlixFeatureEas) { + furi_string_cat_printf( + temp_str, + " EAS %08llX%s\n", + nfc_util_bytes2num(nfcv_data->sub_data.slix.key_eas, 4), + (nfcv_data->sub_data.slix.flags & NfcVSlixDataFlagsHasKeyEas) ? "" : " (unset)"); + } + if(features & SlixFeatureSignature) { + furi_string_cat_printf( + temp_str, + "Signature %08llX...\n", + nfc_util_bytes2num(nfcv_data->sub_data.slix.signature, 4)); + } + furi_string_cat_printf( + temp_str, + "DSFID: %02X %s\n", + nfcv_data->dsfid, + (nfcv_data->security_status[0] & NfcVLockBitDsfid) ? "(locked)" : ""); + furi_string_cat_printf( + temp_str, + "AFI: %02X %s\n", + nfcv_data->afi, + (nfcv_data->security_status[0] & NfcVLockBitAfi) ? "(locked)" : ""); + furi_string_cat_printf( + temp_str, + "EAS: %s\n", + (nfcv_data->security_status[0] & NfcVLockBitEas) ? "locked" : "not locked"); + + if(features & SlixFeatureProtection) { + furi_string_cat_printf( + temp_str, + "PPL: %s\n", + (nfcv_data->security_status[0] & NfcVLockBitPpl) ? "locked" : "not locked"); + furi_string_cat_printf(temp_str, "Prot.ptr %02X\n", nfcv_data->sub_data.slix.pp_pointer); + furi_string_cat_printf(temp_str, "Prot.con %02X\n", nfcv_data->sub_data.slix.pp_condition); + } +} + void nfc_scene_nfc_data_info_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; Widget* widget = nfc->widget; FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data; NfcDeviceData* dev_data = &nfc->dev->dev_data; @@ -76,95 +153,25 @@ void nfc_scene_nfc_data_info_on_enter(void* context) { } furi_string_cat_printf(temp_str, "\n"); - furi_string_cat_printf( - temp_str, - "DSFID: %02X %s\n", - nfcv_data->dsfid, - (nfcv_data->security_status[0] & NfcVLockBitDsfid) ? "(locked)" : ""); - furi_string_cat_printf( - temp_str, - "AFI: %02X %s\n", - nfcv_data->afi, - (nfcv_data->security_status[0] & NfcVLockBitAfi) ? "(locked)" : ""); - furi_string_cat_printf(temp_str, "IC Ref: %02X\n", nfcv_data->ic_ref); - furi_string_cat_printf(temp_str, "Blocks: %02X\n", nfcv_data->block_num); - furi_string_cat_printf(temp_str, "Blocksize: %02X\n", nfcv_data->block_size); + furi_string_cat_printf(temp_str, "IC Ref: %d\n", nfcv_data->ic_ref); + furi_string_cat_printf(temp_str, "Blocks: %d\n", nfcv_data->block_num); + furi_string_cat_printf(temp_str, "Blocksize: %d\n", nfcv_data->block_size); switch(dev_data->nfcv_data.sub_type) { case NfcVTypePlain: furi_string_cat_printf(temp_str, "Type: Plain\n"); break; case NfcVTypeSlix: - furi_string_cat_printf(temp_str, "Type: SLIX\n"); - furi_string_cat_printf(temp_str, "Keys:\n"); - furi_string_cat_printf( - temp_str, - " EAS %08llX\n", - nfc_util_bytes2num(nfcv_data->sub_data.slix.key_eas, 4)); + nfc_scene_slix_build_string(temp_str, nfcv_data, SlixFeatureSlix, "SLIX"); break; case NfcVTypeSlixS: - furi_string_cat_printf(temp_str, "Type: SLIX-S\n"); - furi_string_cat_printf(temp_str, "Keys:\n"); - furi_string_cat_printf( - temp_str, - " Read %08llX\n", - nfc_util_bytes2num(nfcv_data->sub_data.slix.key_read, 4)); - furi_string_cat_printf( - temp_str, - " Write %08llX\n", - nfc_util_bytes2num(nfcv_data->sub_data.slix.key_write, 4)); - furi_string_cat_printf( - temp_str, - " Privacy %08llX\n", - nfc_util_bytes2num(nfcv_data->sub_data.slix.key_privacy, 4)); - furi_string_cat_printf( - temp_str, - " Destroy %08llX\n", - nfc_util_bytes2num(nfcv_data->sub_data.slix.key_destroy, 4)); - furi_string_cat_printf( - temp_str, - " EAS %08llX\n", - nfc_util_bytes2num(nfcv_data->sub_data.slix.key_eas, 4)); + nfc_scene_slix_build_string(temp_str, nfcv_data, SlixFeatureSlixS, "SLIX-S"); break; case NfcVTypeSlixL: - furi_string_cat_printf(temp_str, "Type: SLIX-L\n"); - furi_string_cat_printf(temp_str, "Keys:\n"); - furi_string_cat_printf( - temp_str, - " Privacy %08llX\n", - nfc_util_bytes2num(nfcv_data->sub_data.slix.key_privacy, 4)); - furi_string_cat_printf( - temp_str, - " Destroy %08llX\n", - nfc_util_bytes2num(nfcv_data->sub_data.slix.key_destroy, 4)); - furi_string_cat_printf( - temp_str, - " EAS %08llX\n", - nfc_util_bytes2num(nfcv_data->sub_data.slix.key_eas, 4)); + nfc_scene_slix_build_string(temp_str, nfcv_data, SlixFeatureSlixL, "SLIX-L"); break; case NfcVTypeSlix2: - furi_string_cat_printf(temp_str, "Type: SLIX2\n"); - furi_string_cat_printf(temp_str, "Keys:\n"); - furi_string_cat_printf( - temp_str, - " Read %08llX\n", - nfc_util_bytes2num(nfcv_data->sub_data.slix.key_read, 4)); - furi_string_cat_printf( - temp_str, - " Write %08llX\n", - nfc_util_bytes2num(nfcv_data->sub_data.slix.key_write, 4)); - furi_string_cat_printf( - temp_str, - " Privacy %08llX\n", - nfc_util_bytes2num(nfcv_data->sub_data.slix.key_privacy, 4)); - furi_string_cat_printf( - temp_str, - " Destroy %08llX\n", - nfc_util_bytes2num(nfcv_data->sub_data.slix.key_destroy, 4)); - furi_string_cat_printf( - temp_str, - " EAS %08llX\n", - nfc_util_bytes2num(nfcv_data->sub_data.slix.key_eas, 4)); + nfc_scene_slix_build_string(temp_str, nfcv_data, SlixFeatureSlix2, "SLIX2"); break; default: furi_string_cat_printf(temp_str, "\e#ISO15693 (unknown)\n"); @@ -253,11 +260,11 @@ void nfc_scene_nfc_data_info_on_enter(void* context) { } } else if(protocol == NfcDeviceProtocolMifareClassic) { MfClassicData* data = &dev_data->mf_classic_data; - uint8_t sectors_total = mifare_classic_get_total_sectors_num(data->type); + uint8_t sectors_total = mf_classic_get_total_sectors_num(data->type); uint8_t keys_total = sectors_total * 2; uint8_t keys_found = 0; uint8_t sectors_read = 0; - mifare_classic_get_read_sectors_and_keys(data, §ors_read, &keys_found); + mf_classic_get_read_sectors_and_keys(data, §ors_read, &keys_found); furi_string_cat_printf(temp_str, "\nKeys Found %d/%d", keys_found, keys_total); furi_string_cat_printf(temp_str, "\nSectors Read %d/%d", sectors_read, sectors_total); } @@ -271,7 +278,7 @@ void nfc_scene_nfc_data_info_on_enter(void* context) { } bool nfc_scene_nfc_data_info_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; NfcProtocol protocol = nfc->dev->dev_data.protocol; bool consumed = false; @@ -296,7 +303,7 @@ bool nfc_scene_nfc_data_info_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_nfc_data_info_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; widget_reset(nfc->widget); } diff --git a/applications/main/nfc_old/scenes/nfc_scene_nfca_menu.c b/applications/main/nfc_old/scenes/nfc_scene_nfca_menu.c index 702325a782bb..9779470a387b 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_nfca_menu.c +++ b/applications/main/nfc_old/scenes/nfc_scene_nfca_menu.c @@ -1,4 +1,4 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #include enum SubmenuIndex { @@ -8,13 +8,13 @@ enum SubmenuIndex { }; void nfc_scene_nfca_menu_submenu_callback(void* context, uint32_t index) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_nfca_menu_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; Submenu* submenu = nfc->submenu; submenu_add_item( @@ -30,7 +30,7 @@ void nfc_scene_nfca_menu_on_enter(void* context) { } bool nfc_scene_nfca_menu_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -43,9 +43,9 @@ bool nfc_scene_nfca_menu_on_event(void* context, SceneManagerEvent event) { } else if(event.event == SubmenuIndexEmulateUid) { scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) { - DOLPHIN_DEED(DolphinDeedNfcAddEmulate); + dolphin_deed(DolphinDeedNfcAddEmulate); } else { - DOLPHIN_DEED(DolphinDeedNfcEmulate); + dolphin_deed(DolphinDeedNfcEmulate); } consumed = true; } else if(event.event == SubmenuIndexInfo) { @@ -61,7 +61,7 @@ bool nfc_scene_nfca_menu_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_nfca_menu_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clear view submenu_reset(nfc->submenu); diff --git a/applications/main/nfc_old/scenes/nfc_scene_nfca_read_success.c b/applications/main/nfc_old/scenes/nfc_scene_nfca_read_success.c index 089ee067c11f..a38f31a9813c 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_nfca_read_success.c +++ b/applications/main/nfc_old/scenes/nfc_scene_nfca_read_success.c @@ -1,11 +1,11 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_nfca_read_success_widget_callback( GuiButtonType result, InputType type, void* context) { furi_assert(context); - NfcApp* nfc = context; + Nfc* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); @@ -13,7 +13,7 @@ void nfc_scene_nfca_read_success_widget_callback( } void nfc_scene_nfca_read_success_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Setup view FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; @@ -45,7 +45,7 @@ void nfc_scene_nfca_read_success_on_enter(void* context) { } bool nfc_scene_nfca_read_success_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -64,7 +64,7 @@ bool nfc_scene_nfca_read_success_on_event(void* context, SceneManagerEvent event } void nfc_scene_nfca_read_success_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; notification_message_block(nfc->notifications, &sequence_reset_green); diff --git a/applications/main/nfc_old/scenes/nfc_scene_nfcv_read_success.c b/applications/main/nfc_old/scenes/nfc_scene_nfcv_read_success.c index bdf7692ccb22..04e60611d00f 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_nfcv_read_success.c +++ b/applications/main/nfc_old/scenes/nfc_scene_nfcv_read_success.c @@ -16,7 +16,6 @@ void nfc_scene_nfcv_read_success_on_enter(void* context) { Nfc* nfc = context; NfcDeviceData* dev_data = &nfc->dev->dev_data; FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data; - NfcVData* nfcv_data = &nfc->dev->dev_data.nfcv_data; // Setup view Widget* widget = nfc->widget; widget_add_button_element( @@ -46,13 +45,12 @@ void nfc_scene_nfcv_read_success_on_enter(void* context) { furi_string_cat_printf(temp_str, "\e#ISO15693 (unknown)\n"); break; } - furi_string_cat_printf(temp_str, "UID:"); + furi_string_cat_printf(temp_str, "UID:\n"); 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, "\n"); - furi_string_cat_printf(temp_str, "Blocks: %02X\n", nfcv_data->block_num); - furi_string_cat_printf(temp_str, "Blocksize: %02X\n", nfcv_data->block_size); + furi_string_cat_printf(temp_str, "(see More->Info for details)\n"); widget_add_text_scroll_element(widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); furi_string_free(temp_str); diff --git a/applications/main/nfc_old/scenes/nfc_scene_read.c b/applications/main/nfc_old/scenes/nfc_scene_read.c index 57396a0e0848..1690a9557572 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_read.c +++ b/applications/main/nfc_old/scenes/nfc_scene_read.c @@ -1,4 +1,4 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #include typedef enum { @@ -8,7 +8,7 @@ typedef enum { } NfcSceneReadState; bool nfc_scene_read_worker_callback(NfcWorkerEvent event, void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event == NfcWorkerEventReadMfClassicLoadKeyCache) { consumed = nfc_device_load_key_cache(nfc->dev); @@ -19,7 +19,7 @@ bool nfc_scene_read_worker_callback(NfcWorkerEvent event, void* context) { return consumed; } -void nfc_scene_read_set_state(NfcApp* nfc, NfcSceneReadState state) { +void nfc_scene_read_set_state(Nfc* nfc, NfcSceneReadState state) { uint32_t curr_state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneRead); if(curr_state != state) { if(state == NfcSceneReadStateDetecting) { @@ -38,7 +38,7 @@ void nfc_scene_read_set_state(NfcApp* nfc, NfcSceneReadState state) { } void nfc_scene_read_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; nfc_device_clear(nfc->dev); // Setup view @@ -52,7 +52,7 @@ void nfc_scene_read_on_enter(void* context) { } bool nfc_scene_read_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -90,11 +90,6 @@ bool nfc_scene_read_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireReadSuccess); dolphin_deed(DolphinDeedNfcReadSuccess); consumed = true; - } else if(event.event == NfcWorkerEventReadBankCard) { - notification_message(nfc->notifications, &sequence_success); - scene_manager_next_scene(nfc->scene_manager, NfcSceneEmvReadSuccess); - DOLPHIN_DEED(DolphinDeedNfcReadSuccess); - consumed = true; } else if(event.event == NfcWorkerEventReadMfClassicDictAttackRequired) { if(mf_classic_dict_check_presence(MfClassicDictTypeSystem)) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicDictAttack); @@ -116,7 +111,7 @@ bool nfc_scene_read_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_read_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Stop worker nfc_worker_stop(nfc->worker); diff --git a/applications/main/nfc_old/scenes/nfc_scene_read_card_success.c b/applications/main/nfc_old/scenes/nfc_scene_read_card_success.c index 009de9c966fd..ee80ee768837 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_read_card_success.c +++ b/applications/main/nfc_old/scenes/nfc_scene_read_card_success.c @@ -1,11 +1,11 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_read_card_success_widget_callback( GuiButtonType result, InputType type, void* context) { furi_assert(context); - NfcApp* nfc = context; + Nfc* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); @@ -13,7 +13,7 @@ void nfc_scene_read_card_success_widget_callback( } void nfc_scene_read_card_success_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; FuriString* temp_str; temp_str = furi_string_alloc(); @@ -39,7 +39,7 @@ void nfc_scene_read_card_success_on_enter(void* context) { } bool nfc_scene_read_card_success_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -54,7 +54,7 @@ bool nfc_scene_read_card_success_on_event(void* context, SceneManagerEvent event } void nfc_scene_read_card_success_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clear view widget_reset(nfc->widget); diff --git a/applications/main/nfc_old/scenes/nfc_scene_read_card_type.c b/applications/main/nfc_old/scenes/nfc_scene_read_card_type.c index d763f2f723df..8023026c3da8 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_read_card_type.c +++ b/applications/main/nfc_old/scenes/nfc_scene_read_card_type.c @@ -1,22 +1,21 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #include "nfc_worker_i.h" enum SubmenuIndex { SubmenuIndexReadMifareClassic, SubmenuIndexReadMifareDesfire, SubmenuIndexReadMfUltralight, - SubmenuIndexReadEMV, SubmenuIndexReadNFCA, }; void nfc_scene_read_card_type_submenu_callback(void* context, uint32_t index) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_read_card_type_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; Submenu* submenu = nfc->submenu; submenu_add_item( @@ -37,12 +36,6 @@ void nfc_scene_read_card_type_on_enter(void* context) { SubmenuIndexReadMfUltralight, nfc_scene_read_card_type_submenu_callback, nfc); - submenu_add_item( - submenu, - "Read EMV card", - SubmenuIndexReadEMV, - nfc_scene_read_card_type_submenu_callback, - nfc); submenu_add_item( submenu, "Read NFC-A data", @@ -56,7 +49,7 @@ void nfc_scene_read_card_type_on_enter(void* context) { } bool nfc_scene_read_card_type_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -75,11 +68,6 @@ bool nfc_scene_read_card_type_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); consumed = true; } - if(event.event == SubmenuIndexReadEMV) { - nfc->dev->dev_data.read_mode = NfcReadModeEMV; - scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); - consumed = true; - } if(event.event == SubmenuIndexReadNFCA) { nfc->dev->dev_data.read_mode = NfcReadModeNFCA; scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); @@ -91,7 +79,7 @@ bool nfc_scene_read_card_type_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_read_card_type_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; submenu_reset(nfc->submenu); } diff --git a/applications/main/nfc_old/scenes/nfc_scene_restore_original.c b/applications/main/nfc_old/scenes/nfc_scene_restore_original.c index f059eeac497b..3ecf5c048e41 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_restore_original.c +++ b/applications/main/nfc_old/scenes/nfc_scene_restore_original.c @@ -1,12 +1,12 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_restore_original_popup_callback(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); } void nfc_scene_restore_original_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Setup view Popup* popup = nfc->popup; @@ -20,7 +20,7 @@ void nfc_scene_restore_original_on_enter(void* context) { } bool nfc_scene_restore_original_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -38,7 +38,7 @@ bool nfc_scene_restore_original_on_event(void* context, SceneManagerEvent event) } void nfc_scene_restore_original_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clear view popup_reset(nfc->popup); diff --git a/applications/main/nfc_old/scenes/nfc_scene_restore_original_confirm.c b/applications/main/nfc_old/scenes/nfc_scene_restore_original_confirm.c index e5570bd0df18..16b0953f8096 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_restore_original_confirm.c +++ b/applications/main/nfc_old/scenes/nfc_scene_restore_original_confirm.c @@ -1,13 +1,13 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_restore_original_confirm_dialog_callback(DialogExResult result, void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } void nfc_scene_restore_original_confirm_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; DialogEx* dialog_ex = nfc->dialog_ex; dialog_ex_set_header(dialog_ex, "Restore Card Data?", 64, 0, AlignCenter, AlignTop); @@ -23,7 +23,7 @@ void nfc_scene_restore_original_confirm_on_enter(void* context) { } bool nfc_scene_restore_original_confirm_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -46,7 +46,7 @@ bool nfc_scene_restore_original_confirm_on_event(void* context, SceneManagerEven } void nfc_scene_restore_original_confirm_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clean view dialog_ex_reset(nfc->dialog_ex); diff --git a/applications/main/nfc_old/scenes/nfc_scene_retry_confirm.c b/applications/main/nfc_old/scenes/nfc_scene_retry_confirm.c index 9f37c41588b5..5f4f7985e777 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_retry_confirm.c +++ b/applications/main/nfc_old/scenes/nfc_scene_retry_confirm.c @@ -1,13 +1,13 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_retry_confirm_dialog_callback(DialogExResult result, void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } void nfc_scene_retry_confirm_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; DialogEx* dialog_ex = nfc->dialog_ex; dialog_ex_set_left_button_text(dialog_ex, "Retry"); @@ -22,7 +22,7 @@ void nfc_scene_retry_confirm_on_enter(void* context) { } bool nfc_scene_retry_confirm_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -40,7 +40,7 @@ bool nfc_scene_retry_confirm_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_retry_confirm_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clean view dialog_ex_reset(nfc->dialog_ex); diff --git a/applications/main/nfc_old/scenes/nfc_scene_rpc.c b/applications/main/nfc_old/scenes/nfc_scene_rpc.c index fa01cf41dbda..d06ee7564658 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_rpc.c +++ b/applications/main/nfc_old/scenes/nfc_scene_rpc.c @@ -1,7 +1,7 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_rpc_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; Popup* popup = nfc->popup; popup_set_header(popup, "NFC", 89, 42, AlignCenter, AlignBottom); @@ -16,14 +16,14 @@ void nfc_scene_rpc_on_enter(void* context) { static bool nfc_scene_rpc_emulate_callback(NfcWorkerEvent event, void* context) { UNUSED(event); - NfcApp* nfc = context; + Nfc* nfc = context; nfc->rpc_state = NfcRpcStateEmulated; return true; } bool nfc_scene_rpc_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; Popup* popup = nfc->popup; bool consumed = false; @@ -82,7 +82,7 @@ bool nfc_scene_rpc_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_rpc_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; Popup* popup = nfc->popup; nfc_blink_stop(nfc); diff --git a/applications/main/nfc_old/scenes/nfc_scene_save_name.c b/applications/main/nfc_old/scenes/nfc_scene_save_name.c index 41fbb8833de3..a7b97aac06b3 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_save_name.c +++ b/applications/main/nfc_old/scenes/nfc_scene_save_name.c @@ -1,17 +1,17 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #include #include #include #include void nfc_scene_save_name_text_input_callback(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventTextInputDone); } void nfc_scene_save_name_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Setup view TextInput* text_input = nfc->text_input; @@ -50,7 +50,7 @@ void nfc_scene_save_name_on_enter(void* context) { } bool nfc_scene_save_name_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -67,9 +67,9 @@ bool nfc_scene_save_name_on_event(void* context, SceneManagerEvent event) { if(!scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSavedMenu)) { // Nothing, do not count editing as saving } else if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) { - DOLPHIN_DEED(DolphinDeedNfcAddSave); + dolphin_deed(DolphinDeedNfcAddSave); } else { - DOLPHIN_DEED(DolphinDeedNfcSave); + dolphin_deed(DolphinDeedNfcSave); } consumed = true; } else { @@ -82,7 +82,7 @@ bool nfc_scene_save_name_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_save_name_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clear view void* validator_context = text_input_get_validator_callback_context(nfc->text_input); diff --git a/applications/main/nfc_old/scenes/nfc_scene_save_success.c b/applications/main/nfc_old/scenes/nfc_scene_save_success.c index 4c19f2f42e0f..34919cbd863a 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_save_success.c +++ b/applications/main/nfc_old/scenes/nfc_scene_save_success.c @@ -1,12 +1,12 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_save_success_popup_callback(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); } void nfc_scene_save_success_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Setup view Popup* popup = nfc->popup; @@ -20,7 +20,7 @@ void nfc_scene_save_success_on_enter(void* context) { } bool nfc_scene_save_success_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -41,7 +41,7 @@ bool nfc_scene_save_success_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_save_success_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clear view popup_reset(nfc->popup); diff --git a/applications/main/nfc_old/scenes/nfc_scene_saved_menu.c b/applications/main/nfc_old/scenes/nfc_scene_saved_menu.c index 045760338581..b3205554a431 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_saved_menu.c +++ b/applications/main/nfc_old/scenes/nfc_scene_saved_menu.c @@ -1,4 +1,4 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #include enum SubmenuIndex { @@ -16,13 +16,13 @@ enum SubmenuIndex { }; void nfc_scene_saved_menu_submenu_callback(void* context, uint32_t index) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_saved_menu_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; Submenu* submenu = nfc->submenu; if(nfc->dev->format == NfcDeviceSaveFormatUid || @@ -42,13 +42,15 @@ void nfc_scene_saved_menu_on_enter(void* context) { nfc); } } else if( - nfc->dev->format == NfcDeviceSaveFormatMifareUl || + (nfc->dev->format == NfcDeviceSaveFormatMifareUl && + mf_ul_emulation_supported(&nfc->dev->dev_data.mf_ul_data)) || + nfc->dev->format == NfcDeviceSaveFormatNfcV || nfc->dev->format == NfcDeviceSaveFormatMifareClassic) { submenu_add_item( submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_saved_menu_submenu_callback, nfc); } if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) { - if(!mifare_classic_is_card_read(&nfc->dev->dev_data.mf_classic_data)) { + if(!mf_classic_is_card_read(&nfc->dev->dev_data.mf_classic_data)) { submenu_add_item( submenu, "Detect Reader", @@ -72,6 +74,7 @@ void nfc_scene_saved_menu_on_enter(void* context) { submenu_add_item( submenu, "Info", SubmenuIndexInfo, nfc_scene_saved_menu_submenu_callback, nfc); if(nfc->dev->format == NfcDeviceSaveFormatMifareUl && + nfc->dev->dev_data.mf_ul_data.type != MfUltralightTypeULC && !mf_ul_is_full_capture(&nfc->dev->dev_data.mf_ul_data)) { submenu_add_item( submenu, @@ -105,7 +108,7 @@ void nfc_scene_saved_menu_on_enter(void* context) { } bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; NfcDeviceData* dev_data = &nfc->dev->dev_data; bool consumed = false; @@ -116,14 +119,16 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate); } else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate); + } else if(nfc->dev->format == NfcDeviceSaveFormatNfcV) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVEmulate); } else { scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); } - DOLPHIN_DEED(DolphinDeedNfcEmulate); + dolphin_deed(DolphinDeedNfcEmulate); consumed = true; } else if(event.event == SubmenuIndexDetectReader) { scene_manager_next_scene(nfc->scene_manager, NfcSceneDetectReader); - DOLPHIN_DEED(DolphinDeedNfcDetectReader); + dolphin_deed(DolphinDeedNfcDetectReader); consumed = true; } else if(event.event == SubmenuIndexWrite) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicWrite); @@ -146,6 +151,7 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { application_info_present = true; } else if( dev_data->protocol == NfcDeviceProtocolMifareClassic || + dev_data->protocol == NfcDeviceProtocolMifareDesfire || dev_data->protocol == NfcDeviceProtocolMifareUl) { application_info_present = nfc_supported_card_verify_and_parse(dev_data); } @@ -174,7 +180,7 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_saved_menu_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; submenu_reset(nfc->submenu); } diff --git a/applications/main/nfc_old/scenes/nfc_scene_set_atqa.c b/applications/main/nfc_old/scenes/nfc_scene_set_atqa.c index 4e0e11e7877c..d079b3804754 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_set_atqa.c +++ b/applications/main/nfc_old/scenes/nfc_scene_set_atqa.c @@ -1,13 +1,13 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_set_atqa_byte_input_callback(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); } void nfc_scene_set_atqa_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Setup view ByteInput* byte_input = nfc->byte_input; @@ -23,7 +23,7 @@ void nfc_scene_set_atqa_on_enter(void* context) { } bool nfc_scene_set_atqa_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -36,7 +36,7 @@ bool nfc_scene_set_atqa_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_set_atqa_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clear view byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0); diff --git a/applications/main/nfc_old/scenes/nfc_scene_set_sak.c b/applications/main/nfc_old/scenes/nfc_scene_set_sak.c index 2c4a230cc4f5..60a1e1494b84 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_set_sak.c +++ b/applications/main/nfc_old/scenes/nfc_scene_set_sak.c @@ -1,13 +1,13 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_set_sak_byte_input_callback(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); } void nfc_scene_set_sak_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Setup view ByteInput* byte_input = nfc->byte_input; @@ -23,7 +23,7 @@ void nfc_scene_set_sak_on_enter(void* context) { } bool nfc_scene_set_sak_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -36,7 +36,7 @@ bool nfc_scene_set_sak_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_set_sak_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clear view byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0); diff --git a/applications/main/nfc_old/scenes/nfc_scene_set_type.c b/applications/main/nfc_old/scenes/nfc_scene_set_type.c index 9e417939d62f..cadf2eb69ef3 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_set_type.c +++ b/applications/main/nfc_old/scenes/nfc_scene_set_type.c @@ -1,4 +1,4 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #include "lib/nfc/helpers/nfc_generators.h" enum SubmenuIndex { @@ -8,13 +8,13 @@ enum SubmenuIndex { }; void nfc_scene_set_type_submenu_callback(void* context, uint32_t index) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_set_type_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; Submenu* submenu = nfc->submenu; // Clear device name nfc_device_set_name(nfc->dev, ""); @@ -35,7 +35,7 @@ void nfc_scene_set_type_on_enter(void* context) { } bool nfc_scene_set_type_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -62,7 +62,7 @@ bool nfc_scene_set_type_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_set_type_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; submenu_reset(nfc->submenu); } diff --git a/applications/main/nfc_old/scenes/nfc_scene_set_uid.c b/applications/main/nfc_old/scenes/nfc_scene_set_uid.c index 4c2dc7d04931..54606b68eec7 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_set_uid.c +++ b/applications/main/nfc_old/scenes/nfc_scene_set_uid.c @@ -1,13 +1,13 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_set_uid_byte_input_callback(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); } void nfc_scene_set_uid_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Setup view ByteInput* byte_input = nfc->byte_input; @@ -24,7 +24,7 @@ void nfc_scene_set_uid_on_enter(void* context) { } bool nfc_scene_set_uid_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = (NfcApp*)context; + Nfc* nfc = (Nfc*)context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -46,7 +46,7 @@ bool nfc_scene_set_uid_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_set_uid_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clear view byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0); diff --git a/applications/main/nfc_old/scenes/nfc_scene_start.c b/applications/main/nfc_old/scenes/nfc_scene_start.c index d528e2bb6801..c9e8bf78cf59 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_start.c +++ b/applications/main/nfc_old/scenes/nfc_scene_start.c @@ -1,4 +1,4 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #include "nfc_worker_i.h" #include @@ -12,13 +12,13 @@ enum SubmenuIndex { }; void nfc_scene_start_submenu_callback(void* context, uint32_t index) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_start_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; Submenu* submenu = nfc->submenu; submenu_add_item(submenu, "Read", SubmenuIndexRead, nfc_scene_start_submenu_callback, nfc); @@ -43,7 +43,7 @@ void nfc_scene_start_on_enter(void* context) { } bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -51,7 +51,7 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) { scene_manager_set_scene_state(nfc->scene_manager, NfcSceneStart, SubmenuIndexRead); nfc->dev->dev_data.read_mode = NfcReadModeAuto; scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); - DOLPHIN_DEED(DolphinDeedNfcRead); + dolphin_deed(DolphinDeedNfcRead); consumed = true; } else if(event.event == SubmenuIndexDetectReader) { scene_manager_set_scene_state( @@ -60,7 +60,7 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) { if(sd_exist) { nfc_device_data_clear(&nfc->dev->dev_data); scene_manager_next_scene(nfc->scene_manager, NfcSceneDetectReader); - DOLPHIN_DEED(DolphinDeedNfcDetectReader); + dolphin_deed(DolphinDeedNfcDetectReader); } else { scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound); } @@ -92,7 +92,7 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_start_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; submenu_reset(nfc->submenu); } diff --git a/applications/main/nfc_old/views/dict_attack.c b/applications/main/nfc_old/views/dict_attack.c index dd6b919f0899..8f4bd063e8b8 100644 --- a/applications/main/nfc_old/views/dict_attack.c +++ b/applications/main/nfc_old/views/dict_attack.c @@ -169,7 +169,7 @@ void dict_attack_set_card_detected(DictAttack* dict_attack, MfClassicType type) DictAttackViewModel * model, { model->state = DictAttackStateRead; - model->sectors_total = mifare_classic_get_total_sectors_num(type); + model->sectors_total = mf_classic_get_total_sectors_num(type); model->keys_total = model->sectors_total * 2; }, true); diff --git a/applications/main/nfc_old/views/dict_attack.h b/applications/main/nfc_old/views/dict_attack.h index 181cbbae5574..73b98a1b827b 100644 --- a/applications/main/nfc_old/views/dict_attack.h +++ b/applications/main/nfc_old/views/dict_attack.h @@ -3,7 +3,7 @@ #include #include -#include +#include typedef struct DictAttack DictAttack; diff --git a/applications/main/subghz/helpers/subghz_chat.c b/applications/main/subghz/helpers/subghz_chat.c index dbf34c97051a..bbe219fd2f74 100644 --- a/applications/main/subghz/helpers/subghz_chat.c +++ b/applications/main/subghz/helpers/subghz_chat.c @@ -76,12 +76,15 @@ void subghz_chat_worker_free(SubGhzChatWorker* instance) { free(instance); } -bool subghz_chat_worker_start(SubGhzChatWorker* instance, uint32_t frequency) { +bool subghz_chat_worker_start( + SubGhzChatWorker* instance, + const SubGhzDevice* device, + uint32_t frequency) { furi_assert(instance); furi_assert(!instance->worker_running); bool res = false; - if(subghz_tx_rx_worker_start(instance->subghz_txrx, frequency)) { + if(subghz_tx_rx_worker_start(instance->subghz_txrx, device, frequency)) { furi_message_queue_reset(instance->event_queue); subghz_tx_rx_worker_set_callback_have_read( instance->subghz_txrx, subghz_chat_worker_update_rx_event_chat, instance); diff --git a/applications/main/subghz/helpers/subghz_chat.h b/applications/main/subghz/helpers/subghz_chat.h index b418bbdbffce..2c454b75d981 100644 --- a/applications/main/subghz/helpers/subghz_chat.h +++ b/applications/main/subghz/helpers/subghz_chat.h @@ -1,5 +1,6 @@ #pragma once #include "../subghz_i.h" +#include #include typedef struct SubGhzChatWorker SubGhzChatWorker; @@ -20,7 +21,10 @@ typedef struct { SubGhzChatWorker* subghz_chat_worker_alloc(Cli* cli); void subghz_chat_worker_free(SubGhzChatWorker* instance); -bool subghz_chat_worker_start(SubGhzChatWorker* instance, uint32_t frequency); +bool subghz_chat_worker_start( + SubGhzChatWorker* instance, + const SubGhzDevice* device, + uint32_t frequency); void subghz_chat_worker_stop(SubGhzChatWorker* instance); bool subghz_chat_worker_is_running(SubGhzChatWorker* instance); SubGhzChatEvent subghz_chat_worker_get_event_chat(SubGhzChatWorker* instance); diff --git a/applications/main/subghz/helpers/subghz_frequency_analyzer_log_item_array.h b/applications/main/subghz/helpers/subghz_frequency_analyzer_log_item_array.h index b94ebe3809df..df53143d23f4 100644 --- a/applications/main/subghz/helpers/subghz_frequency_analyzer_log_item_array.h +++ b/applications/main/subghz/helpers/subghz_frequency_analyzer_log_item_array.h @@ -27,10 +27,15 @@ TUPLE_DEF2( (rssi_max, uint8_t)) /* Register globally the oplist */ #define M_OPL_SubGhzFrequencyAnalyzerLogItem_t() \ - TUPLE_OPLIST(SubGhzFrequencyAnalyzerLogItem, M_POD_OPLIST, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST) + TUPLE_OPLIST( \ + SubGhzFrequencyAnalyzerLogItem, \ + M_DEFAULT_OPLIST, \ + M_DEFAULT_OPLIST, \ + M_DEFAULT_OPLIST, \ + M_DEFAULT_OPLIST) /* Define the array, register the oplist and define further algorithms on it */ -ARRAY_DEF(SubGhzFrequencyAnalyzerLogItemArray, SubGhzFrequencyAnalyzerLogItem_t) +ARRAY_DEF(SubGhzFrequencyAnalyzerLogItemArray, SubGhzFrequencyAnalyzerLogItem_t) //-V779 #define M_OPL_SubGhzFrequencyAnalyzerLogItemArray_t() \ ARRAY_OPLIST(SubGhzFrequencyAnalyzerLogItemArray, M_OPL_SubGhzFrequencyAnalyzerLogItem_t()) ALGO_DEF(SubGhzFrequencyAnalyzerLogItemArray, SubGhzFrequencyAnalyzerLogItemArray_t) diff --git a/applications/main/subghz/helpers/subghz_threshold_rssi.c b/applications/main/subghz/helpers/subghz_threshold_rssi.c index 04a06bc1736c..07d7bccf93df 100644 --- a/applications/main/subghz/helpers/subghz_threshold_rssi.c +++ b/applications/main/subghz/helpers/subghz_threshold_rssi.c @@ -32,9 +32,8 @@ float subghz_threshold_rssi_get(SubGhzThresholdRssi* instance) { return instance->threshold_rssi; } -SubGhzThresholdRssiData subghz_threshold_get_rssi_data(SubGhzThresholdRssi* instance) { +SubGhzThresholdRssiData subghz_threshold_get_rssi_data(SubGhzThresholdRssi* instance, float rssi) { furi_assert(instance); - float rssi = furi_hal_subghz_get_rssi(); SubGhzThresholdRssiData ret = {.rssi = rssi, .is_above = false}; if(float_is_equal(instance->threshold_rssi, SUBGHZ_RAW_THRESHOLD_MIN)) { diff --git a/applications/main/subghz/helpers/subghz_threshold_rssi.h b/applications/main/subghz/helpers/subghz_threshold_rssi.h index e28092acbc00..1d588e271b3a 100644 --- a/applications/main/subghz/helpers/subghz_threshold_rssi.h +++ b/applications/main/subghz/helpers/subghz_threshold_rssi.h @@ -38,6 +38,7 @@ float subghz_threshold_rssi_get(SubGhzThresholdRssi* instance); /** Check threshold * * @param instance Pointer to a SubGhzThresholdRssi + * @param rssi Current RSSI * @return SubGhzThresholdRssiData */ -SubGhzThresholdRssiData subghz_threshold_get_rssi_data(SubGhzThresholdRssi* instance); +SubGhzThresholdRssiData subghz_threshold_get_rssi_data(SubGhzThresholdRssi* instance, float rssi); diff --git a/applications/main/subghz/helpers/subghz_txrx.c b/applications/main/subghz/helpers/subghz_txrx.c index 1517cb99892c..b911f443459a 100644 --- a/applications/main/subghz/helpers/subghz_txrx.c +++ b/applications/main/subghz/helpers/subghz_txrx.c @@ -1,9 +1,26 @@ #include "subghz_txrx_i.h" #include +#include +#include #define TAG "SubGhz" +static void subghz_txrx_radio_device_power_on(SubGhzTxRx* instance) { + UNUSED(instance); + uint8_t attempts = 0; + while(!furi_hal_power_is_otg_enabled() && attempts++ < 5) { + furi_hal_power_enable_otg(); + //CC1101 power-up time + furi_delay_ms(10); + } +} + +static void subghz_txrx_radio_device_power_off(SubGhzTxRx* instance) { + UNUSED(instance); + if(furi_hal_power_is_otg_enabled()) furi_hal_power_disable_otg(); +} + SubGhzTxRx* subghz_txrx_alloc() { SubGhzTxRx* instance = malloc(sizeof(SubGhzTxRx)); instance->setting = subghz_setting_alloc(); @@ -23,16 +40,15 @@ SubGhzTxRx* subghz_txrx_alloc() { instance->fff_data = flipper_format_string_alloc(); instance->environment = subghz_environment_alloc(); - instance->is_database_loaded = subghz_environment_load_keystore( - instance->environment, EXT_PATH("subghz/assets/keeloq_mfcodes")); - subghz_environment_load_keystore( - instance->environment, EXT_PATH("subghz/assets/keeloq_mfcodes_user")); + instance->is_database_loaded = + subghz_environment_load_keystore(instance->environment, SUBGHZ_KEYSTORE_DIR_NAME); + subghz_environment_load_keystore(instance->environment, SUBGHZ_KEYSTORE_DIR_USER_NAME); subghz_environment_set_came_atomo_rainbow_table_file_name( - instance->environment, EXT_PATH("subghz/assets/came_atomo")); + instance->environment, SUBGHZ_CAME_ATOMO_DIR_NAME); subghz_environment_set_alutech_at_4n_rainbow_table_file_name( - instance->environment, EXT_PATH("subghz/assets/alutech_at_4n")); + instance->environment, SUBGHZ_ALUTECH_AT_4N_DIR_NAME); subghz_environment_set_nice_flor_s_rainbow_table_file_name( - instance->environment, EXT_PATH("subghz/assets/nice_flor_s")); + instance->environment, SUBGHZ_NICE_FLOR_S_DIR_NAME); subghz_environment_set_protocol_registry( instance->environment, (void*)&subghz_protocol_registry); instance->receiver = subghz_receiver_alloc_init(instance->environment); @@ -43,18 +59,32 @@ SubGhzTxRx* subghz_txrx_alloc() { instance->worker, (SubGhzWorkerPairCallback)subghz_receiver_decode); subghz_worker_set_context(instance->worker, instance->receiver); + //set default device External + subghz_devices_init(); + instance->radio_device_type = SubGhzRadioDeviceTypeInternal; + instance->radio_device_type = + subghz_txrx_radio_device_set(instance, SubGhzRadioDeviceTypeExternalCC1101); + return instance; } void subghz_txrx_free(SubGhzTxRx* instance) { furi_assert(instance); + if(instance->radio_device_type != SubGhzRadioDeviceTypeInternal) { + subghz_txrx_radio_device_power_off(instance); + subghz_devices_end(instance->radio_device); + } + + subghz_devices_deinit(); + subghz_worker_free(instance->worker); subghz_receiver_free(instance->receiver); subghz_environment_free(instance->environment); flipper_format_free(instance->fff_data); furi_string_free(instance->preset->name); subghz_setting_free(instance->setting); + free(instance->preset); free(instance); } @@ -122,29 +152,26 @@ void subghz_txrx_get_frequency_and_modulation( static void subghz_txrx_begin(SubGhzTxRx* instance, uint8_t* preset_data) { furi_assert(instance); - furi_hal_subghz_reset(); - furi_hal_subghz_idle(); - furi_hal_subghz_load_custom_preset(preset_data); - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); + subghz_devices_reset(instance->radio_device); + subghz_devices_idle(instance->radio_device); + subghz_devices_load_preset(instance->radio_device, FuriHalSubGhzPresetCustom, preset_data); instance->txrx_state = SubGhzTxRxStateIDLE; } static uint32_t subghz_txrx_rx(SubGhzTxRx* instance, uint32_t frequency) { furi_assert(instance); - if(!furi_hal_subghz_is_frequency_valid(frequency)) { - furi_crash("SubGhz: Incorrect RX frequency."); - } + furi_assert( instance->txrx_state != SubGhzTxRxStateRx && instance->txrx_state != SubGhzTxRxStateSleep); - furi_hal_subghz_idle(); - uint32_t value = furi_hal_subghz_set_frequency_and_path(frequency); - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); - furi_hal_subghz_flush_rx(); + subghz_devices_idle(instance->radio_device); + + uint32_t value = subghz_devices_set_frequency(instance->radio_device, frequency); + subghz_devices_flush_rx(instance->radio_device); subghz_txrx_speaker_on(instance); - furi_hal_subghz_rx(); - furi_hal_subghz_start_async_rx(subghz_worker_rx_callback, instance->worker); + subghz_devices_start_async_rx( + instance->radio_device, subghz_worker_rx_callback, instance->worker); subghz_worker_start(instance->worker); instance->txrx_state = SubGhzTxRxStateRx; return value; @@ -153,7 +180,7 @@ static uint32_t subghz_txrx_rx(SubGhzTxRx* instance, uint32_t frequency) { static void subghz_txrx_idle(SubGhzTxRx* instance) { furi_assert(instance); furi_assert(instance->txrx_state != SubGhzTxRxStateSleep); - furi_hal_subghz_idle(); + subghz_devices_idle(instance->radio_device); subghz_txrx_speaker_off(instance); instance->txrx_state = SubGhzTxRxStateIDLE; } @@ -164,30 +191,26 @@ static void subghz_txrx_rx_end(SubGhzTxRx* instance) { if(subghz_worker_is_running(instance->worker)) { subghz_worker_stop(instance->worker); - furi_hal_subghz_stop_async_rx(); + subghz_devices_stop_async_rx(instance->radio_device); } - furi_hal_subghz_idle(); + subghz_devices_idle(instance->radio_device); subghz_txrx_speaker_off(instance); instance->txrx_state = SubGhzTxRxStateIDLE; } void subghz_txrx_sleep(SubGhzTxRx* instance) { furi_assert(instance); - furi_hal_subghz_sleep(); + subghz_devices_sleep(instance->radio_device); instance->txrx_state = SubGhzTxRxStateSleep; } static bool subghz_txrx_tx(SubGhzTxRx* instance, uint32_t frequency) { furi_assert(instance); - if(!furi_hal_subghz_is_frequency_valid(frequency)) { - furi_crash("SubGhz: Incorrect TX frequency."); - } furi_assert(instance->txrx_state != SubGhzTxRxStateSleep); - furi_hal_subghz_idle(); - furi_hal_subghz_set_frequency_and_path(frequency); - furi_hal_gpio_write(&gpio_cc1101_g0, false); - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); - bool ret = furi_hal_subghz_tx(); + subghz_devices_idle(instance->radio_device); + subghz_devices_set_frequency(instance->radio_device, frequency); + + bool ret = subghz_devices_set_tx(instance->radio_device); if(ret) { subghz_txrx_speaker_on(instance); instance->txrx_state = SubGhzTxRxStateTx; @@ -249,8 +272,8 @@ SubGhzTxRxStartTxState subghz_txrx_tx_start(SubGhzTxRx* instance, FlipperFormat* if(ret == SubGhzTxRxStartTxStateOk) { //Start TX - furi_hal_subghz_start_async_tx( - subghz_transmitter_yield, instance->transmitter); + subghz_devices_start_async_tx( + instance->radio_device, subghz_transmitter_yield, instance->transmitter); } } else { ret = SubGhzTxRxStartTxStateErrorParserOthers; @@ -293,7 +316,7 @@ static void subghz_txrx_tx_stop(SubGhzTxRx* instance) { furi_assert(instance); furi_assert(instance->txrx_state == SubGhzTxRxStateTx); //Stop TX - furi_hal_subghz_stop_async_tx(); + subghz_devices_stop_async_tx(instance->radio_device); subghz_transmitter_stop(instance->transmitter); subghz_transmitter_free(instance->transmitter); @@ -306,7 +329,6 @@ static void subghz_txrx_tx_stop(SubGhzTxRx* instance) { subghz_txrx_idle(instance); subghz_txrx_speaker_off(instance); //Todo: Show message - // notification_message(notifications, &sequence_reset_red); } FlipperFormat* subghz_txrx_get_fff_data(SubGhzTxRx* instance) { @@ -356,7 +378,7 @@ void subghz_txrx_hopper_update(SubGhzTxRx* instance) { float rssi = -127.0f; if(instance->hopper_state != SubGhzHopperStateRSSITimeOut) { // See RSSI Calculation timings in CC1101 17.3 RSSI - rssi = furi_hal_subghz_get_rssi(); + rssi = subghz_devices_get_rssi(instance->radio_device); // Stay if RSSI is high enough if(rssi > -90.0f) { @@ -414,7 +436,7 @@ void subghz_txrx_speaker_on(SubGhzTxRx* instance) { furi_assert(instance); if(instance->speaker_state == SubGhzSpeakerStateEnable) { if(furi_hal_speaker_acquire(30)) { - furi_hal_subghz_set_async_mirror_pin(&gpio_speaker); + subghz_devices_set_async_mirror_pin(instance->radio_device, &gpio_speaker); } else { instance->speaker_state = SubGhzSpeakerStateDisable; } @@ -425,7 +447,7 @@ void subghz_txrx_speaker_off(SubGhzTxRx* instance) { furi_assert(instance); if(instance->speaker_state != SubGhzSpeakerStateDisable) { if(furi_hal_speaker_is_mine()) { - furi_hal_subghz_set_async_mirror_pin(NULL); + subghz_devices_set_async_mirror_pin(instance->radio_device, NULL); furi_hal_speaker_release(); if(instance->speaker_state == SubGhzSpeakerStateShutdown) instance->speaker_state = SubGhzSpeakerStateDisable; @@ -437,7 +459,7 @@ void subghz_txrx_speaker_mute(SubGhzTxRx* instance) { furi_assert(instance); if(instance->speaker_state == SubGhzSpeakerStateEnable) { if(furi_hal_speaker_is_mine()) { - furi_hal_subghz_set_async_mirror_pin(NULL); + subghz_devices_set_async_mirror_pin(instance->radio_device, NULL); } } } @@ -446,7 +468,7 @@ void subghz_txrx_speaker_unmute(SubGhzTxRx* instance) { furi_assert(instance); if(instance->speaker_state == SubGhzSpeakerStateEnable) { if(furi_hal_speaker_is_mine()) { - furi_hal_subghz_set_async_mirror_pin(&gpio_speaker); + subghz_devices_set_async_mirror_pin(instance->radio_device, &gpio_speaker); } } } @@ -519,3 +541,66 @@ void subghz_txrx_set_raw_file_encoder_worker_callback_end( callback, context); } + +bool subghz_txrx_radio_device_is_external_connected(SubGhzTxRx* instance, const char* name) { + furi_assert(instance); + + bool is_connect = false; + bool is_otg_enabled = furi_hal_power_is_otg_enabled(); + + if(!is_otg_enabled) { + subghz_txrx_radio_device_power_on(instance); + } + + const SubGhzDevice* device = subghz_devices_get_by_name(name); + if(device) { + is_connect = subghz_devices_is_connect(device); + } + + if(!is_otg_enabled) { + subghz_txrx_radio_device_power_off(instance); + } + return is_connect; +} + +SubGhzRadioDeviceType + subghz_txrx_radio_device_set(SubGhzTxRx* instance, SubGhzRadioDeviceType radio_device_type) { + furi_assert(instance); + + if(radio_device_type == SubGhzRadioDeviceTypeExternalCC1101 && + subghz_txrx_radio_device_is_external_connected(instance, SUBGHZ_DEVICE_CC1101_EXT_NAME)) { + subghz_txrx_radio_device_power_on(instance); + instance->radio_device = subghz_devices_get_by_name(SUBGHZ_DEVICE_CC1101_EXT_NAME); + subghz_devices_begin(instance->radio_device); + instance->radio_device_type = SubGhzRadioDeviceTypeExternalCC1101; + } else { + subghz_txrx_radio_device_power_off(instance); + if(instance->radio_device_type != SubGhzRadioDeviceTypeInternal) { + subghz_devices_end(instance->radio_device); + } + instance->radio_device = subghz_devices_get_by_name(SUBGHZ_DEVICE_CC1101_INT_NAME); + instance->radio_device_type = SubGhzRadioDeviceTypeInternal; + } + + return instance->radio_device_type; +} + +SubGhzRadioDeviceType subghz_txrx_radio_device_get(SubGhzTxRx* instance) { + furi_assert(instance); + return instance->radio_device_type; +} + +float subghz_txrx_radio_device_get_rssi(SubGhzTxRx* instance) { + furi_assert(instance); + return subghz_devices_get_rssi(instance->radio_device); +} + +const char* subghz_txrx_radio_device_get_name(SubGhzTxRx* instance) { + furi_assert(instance); + return subghz_devices_get_name(instance->radio_device); +} + +bool subghz_txrx_radio_device_is_frequecy_valid(SubGhzTxRx* instance, uint32_t frequency) { + furi_assert(instance); + return subghz_devices_is_frequency_valid(instance->radio_device, frequency); +} \ No newline at end of file diff --git a/applications/main/subghz/helpers/subghz_txrx.h b/applications/main/subghz/helpers/subghz_txrx.h index 0f2daf05d49f..e49789206f0f 100644 --- a/applications/main/subghz/helpers/subghz_txrx.h +++ b/applications/main/subghz/helpers/subghz_txrx.h @@ -7,6 +7,7 @@ #include #include #include +#include typedef struct SubGhzTxRx SubGhzTxRx; @@ -288,3 +289,48 @@ void subghz_txrx_set_raw_file_encoder_worker_callback_end( SubGhzTxRx* instance, SubGhzProtocolEncoderRAWCallbackEnd callback, void* context); + +/* Checking if an external radio device is connected +* +* @param instance Pointer to a SubGhzTxRx +* @param name Name of external radio device +* @return bool True if is connected to the external radio device +*/ +bool subghz_txrx_radio_device_is_external_connected(SubGhzTxRx* instance, const char* name); + +/* Set the selected radio device to use +* +* @param instance Pointer to a SubGhzTxRx +* @param radio_device_type Radio device type +* @return SubGhzRadioDeviceType Type of installed radio device +*/ +SubGhzRadioDeviceType + subghz_txrx_radio_device_set(SubGhzTxRx* instance, SubGhzRadioDeviceType radio_device_type); + +/* Get the selected radio device to use +* +* @param instance Pointer to a SubGhzTxRx +* @return SubGhzRadioDeviceType Type of installed radio device +*/ +SubGhzRadioDeviceType subghz_txrx_radio_device_get(SubGhzTxRx* instance); + +/* Get RSSI the selected radio device to use +* +* @param instance Pointer to a SubGhzTxRx +* @return float RSSI +*/ +float subghz_txrx_radio_device_get_rssi(SubGhzTxRx* instance); + +/* Get name the selected radio device to use +* +* @param instance Pointer to a SubGhzTxRx +* @return const char* Name of installed radio device +*/ +const char* subghz_txrx_radio_device_get_name(SubGhzTxRx* instance); + +/* Get get intelligence whether frequency the selected radio device to use +* +* @param instance Pointer to a SubGhzTxRx +* @return bool True if the frequency is valid +*/ +bool subghz_txrx_radio_device_is_frequecy_valid(SubGhzTxRx* instance, uint32_t frequency); \ No newline at end of file diff --git a/applications/main/subghz/helpers/subghz_txrx_i.h b/applications/main/subghz/helpers/subghz_txrx_i.h index bd0ad8b7be34..b7d74fd492f5 100644 --- a/applications/main/subghz/helpers/subghz_txrx_i.h +++ b/applications/main/subghz/helpers/subghz_txrx_i.h @@ -21,6 +21,8 @@ struct SubGhzTxRx { SubGhzTxRxState txrx_state; SubGhzSpeakerState speaker_state; + const SubGhzDevice* radio_device; + SubGhzRadioDeviceType radio_device_type; SubGhzTxRxNeedSaveCallback need_save_callback; void* need_save_context; diff --git a/applications/main/subghz/helpers/subghz_types.h b/applications/main/subghz/helpers/subghz_types.h index 46bf940f4690..8beb7b9ed097 100644 --- a/applications/main/subghz/helpers/subghz_types.h +++ b/applications/main/subghz/helpers/subghz_types.h @@ -35,6 +35,13 @@ typedef enum { SubGhzSpeakerStateEnable, } SubGhzSpeakerState; +/** SubGhzRadioDeviceType */ +typedef enum { + SubGhzRadioDeviceTypeAuto, + SubGhzRadioDeviceTypeInternal, + SubGhzRadioDeviceTypeExternalCC1101, +} SubGhzRadioDeviceType; + /** SubGhzRxKeyState state */ typedef enum { SubGhzRxKeyStateIDLE, diff --git a/applications/main/subghz/scenes/subghz_scene_config.h b/applications/main/subghz/scenes/subghz_scene_config.h index 86a307317923..97aa946e8adb 100644 --- a/applications/main/subghz/scenes/subghz_scene_config.h +++ b/applications/main/subghz/scenes/subghz_scene_config.h @@ -24,3 +24,4 @@ ADD_SCENE(subghz, delete_raw, DeleteRAW) ADD_SCENE(subghz, need_saving, NeedSaving) ADD_SCENE(subghz, rpc, Rpc) ADD_SCENE(subghz, region_info, RegionInfo) +ADD_SCENE(subghz, radio_settings, RadioSettings) diff --git a/applications/main/subghz/scenes/subghz_scene_radio_setting.c b/applications/main/subghz/scenes/subghz_scene_radio_setting.c new file mode 100644 index 000000000000..0a47d5bfdbd4 --- /dev/null +++ b/applications/main/subghz/scenes/subghz_scene_radio_setting.c @@ -0,0 +1,70 @@ +#include "../subghz_i.h" +#include +#include + +enum SubGhzRadioSettingIndex { + SubGhzRadioSettingIndexDevice, +}; + +#define RADIO_DEVICE_COUNT 2 +const char* const radio_device_text[RADIO_DEVICE_COUNT] = { + "Internal", + "External", +}; + +const uint32_t radio_device_value[RADIO_DEVICE_COUNT] = { + SubGhzRadioDeviceTypeInternal, + SubGhzRadioDeviceTypeExternalCC1101, +}; + +static void subghz_scene_radio_settings_set_device(VariableItem* item) { + SubGhz* subghz = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + + if(!subghz_txrx_radio_device_is_external_connected( + subghz->txrx, SUBGHZ_DEVICE_CC1101_EXT_NAME) && + radio_device_value[index] == SubGhzRadioDeviceTypeExternalCC1101) { + //ToDo correct if there is more than 1 module + index = 0; + } + variable_item_set_current_value_text(item, radio_device_text[index]); + subghz_txrx_radio_device_set(subghz->txrx, radio_device_value[index]); +} + +void subghz_scene_radio_settings_on_enter(void* context) { + SubGhz* subghz = context; + VariableItem* item; + uint8_t value_index; + + uint8_t value_count_device = RADIO_DEVICE_COUNT; + if(subghz_txrx_radio_device_get(subghz->txrx) == SubGhzRadioDeviceTypeInternal && + !subghz_txrx_radio_device_is_external_connected(subghz->txrx, SUBGHZ_DEVICE_CC1101_EXT_NAME)) + value_count_device = 1; + item = variable_item_list_add( + subghz->variable_item_list, + "Module", + value_count_device, + subghz_scene_radio_settings_set_device, + subghz); + value_index = value_index_uint32( + subghz_txrx_radio_device_get(subghz->txrx), radio_device_value, value_count_device); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, radio_device_text[value_index]); + + view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdVariableItemList); +} + +bool subghz_scene_radio_settings_on_event(void* context, SceneManagerEvent event) { + SubGhz* subghz = context; + bool consumed = false; + UNUSED(subghz); + UNUSED(event); + + return consumed; +} + +void subghz_scene_radio_settings_on_exit(void* context) { + SubGhz* subghz = context; + variable_item_list_set_selected_item(subghz->variable_item_list, 0); + variable_item_list_reset(subghz->variable_item_list); +} diff --git a/applications/main/subghz/scenes/subghz_scene_read_raw.c b/applications/main/subghz/scenes/subghz_scene_read_raw.c index a29f86a078cd..58e4b042954c 100644 --- a/applications/main/subghz/scenes/subghz_scene_read_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_read_raw.c @@ -48,6 +48,9 @@ static void subghz_scene_read_raw_update_statusbar(void* context) { furi_string_free(frequency_str); furi_string_free(modulation_str); + + subghz_read_raw_set_radio_device_type( + subghz->subghz_read_raw, subghz_txrx_radio_device_get(subghz->txrx)); } void subghz_scene_read_raw_callback(SubGhzCustomEvent event, void* context) { @@ -238,7 +241,9 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { furi_string_printf( temp_str, "%s/%s%s", SUBGHZ_RAW_FOLDER, RAW_FILE_NAME, SUBGHZ_APP_EXTENSION); subghz_protocol_raw_gen_fff_data( - subghz_txrx_get_fff_data(subghz->txrx), furi_string_get_cstr(temp_str)); + subghz_txrx_get_fff_data(subghz->txrx), + furi_string_get_cstr(temp_str), + subghz_txrx_radio_device_get_name(subghz->txrx)); furi_string_free(temp_str); if(spl_count > 0) { @@ -298,8 +303,8 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { subghz_read_raw_update_sample_write( subghz->subghz_read_raw, subghz_protocol_raw_get_sample_write(decoder_raw)); - SubGhzThresholdRssiData ret_rssi = - subghz_threshold_get_rssi_data(subghz->threshold_rssi); + SubGhzThresholdRssiData ret_rssi = subghz_threshold_get_rssi_data( + subghz->threshold_rssi, subghz_txrx_radio_device_get_rssi(subghz->txrx)); subghz_read_raw_add_data_rssi( subghz->subghz_read_raw, ret_rssi.rssi, ret_rssi.is_above); subghz_protocol_raw_save_to_file_pause(decoder_raw, !ret_rssi.is_above); diff --git a/applications/main/subghz/scenes/subghz_scene_receiver.c b/applications/main/subghz/scenes/subghz_scene_receiver.c index 6771f8213b55..6ab443579bbb 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver.c @@ -56,6 +56,9 @@ static void subghz_scene_receiver_update_statusbar(void* context) { subghz->state_notifications = SubGhzNotificationStateIDLE; } furi_string_free(history_stat_str); + + subghz_view_receiver_set_radio_device_type( + subghz->subghz_receiver, subghz_txrx_radio_device_get(subghz->txrx)); } void subghz_scene_receiver_callback(SubGhzCustomEvent event, void* context) { @@ -189,7 +192,8 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { subghz_scene_receiver_update_statusbar(subghz); } - SubGhzThresholdRssiData ret_rssi = subghz_threshold_get_rssi_data(subghz->threshold_rssi); + SubGhzThresholdRssiData ret_rssi = subghz_threshold_get_rssi_data( + subghz->threshold_rssi, subghz_txrx_radio_device_get_rssi(subghz->txrx)); subghz_receiver_rssi(subghz->subghz_receiver, ret_rssi.rssi); subghz_protocol_decoder_bin_raw_data_input_rssi( diff --git a/applications/main/subghz/scenes/subghz_scene_save_name.c b/applications/main/subghz/scenes/subghz_scene_save_name.c index 7d0a4f4f8b72..86eddfe8e97f 100644 --- a/applications/main/subghz/scenes/subghz_scene_save_name.c +++ b/applications/main/subghz/scenes/subghz_scene_save_name.c @@ -122,7 +122,8 @@ bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) { SubGhzCustomEventManagerNoSet) { subghz_protocol_raw_gen_fff_data( subghz_txrx_get_fff_data(subghz->txrx), - furi_string_get_cstr(subghz->file_path)); + furi_string_get_cstr(subghz->file_path), + subghz_txrx_radio_device_get_name(subghz->txrx)); scene_manager_set_scene_state( subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerNoSet); } else { diff --git a/applications/main/subghz/scenes/subghz_scene_start.c b/applications/main/subghz/scenes/subghz_scene_start.c index 0ab5f123ed14..ce631b398124 100644 --- a/applications/main/subghz/scenes/subghz_scene_start.c +++ b/applications/main/subghz/scenes/subghz_scene_start.c @@ -8,7 +8,8 @@ enum SubmenuIndex { SubmenuIndexAddManually, SubmenuIndexFrequencyAnalyzer, SubmenuIndexReadRAW, - SubmenuIndexShowRegionInfo + SubmenuIndexShowRegionInfo, + SubmenuIndexRadioSetting, }; void subghz_scene_start_submenu_callback(void* context, uint32_t index) { @@ -49,6 +50,12 @@ void subghz_scene_start_on_enter(void* context) { SubmenuIndexShowRegionInfo, subghz_scene_start_submenu_callback, subghz); + submenu_add_item( + subghz->submenu, + "Radio Settings", + SubmenuIndexRadioSetting, + subghz_scene_start_submenu_callback, + subghz); if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { submenu_add_item( subghz->submenu, "Test", SubmenuIndexTest, subghz_scene_start_submenu_callback, subghz); @@ -104,6 +111,11 @@ bool subghz_scene_start_on_event(void* context, SceneManagerEvent event) { subghz->scene_manager, SubGhzSceneStart, SubmenuIndexShowRegionInfo); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneRegionInfo); return true; + } else if(event.event == SubmenuIndexRadioSetting) { + scene_manager_set_scene_state( + subghz->scene_manager, SubGhzSceneStart, SubmenuIndexRadioSetting); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneRadioSettings); + return true; } } return false; diff --git a/applications/main/subghz/scenes/subghz_scene_transmitter.c b/applications/main/subghz/scenes/subghz_scene_transmitter.c index 274dd61ad37e..f83e44a0a1d5 100644 --- a/applications/main/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/main/subghz/scenes/subghz_scene_transmitter.c @@ -35,6 +35,8 @@ bool subghz_scene_transmitter_update_data_show(void* context) { furi_string_free(modulation_str); furi_string_free(key_str); } + subghz_view_transmitter_set_radio_device_type( + subghz->subghz_transmitter, subghz_txrx_radio_device_get(subghz->txrx)); return ret; } diff --git a/applications/main/subghz/subghz_cli.c b/applications/main/subghz/subghz_cli.c index 60845ac99861..bc7be507e73f 100644 --- a/applications/main/subghz/subghz_cli.c +++ b/applications/main/subghz/subghz_cli.c @@ -10,6 +10,10 @@ #include #include #include +#include +#include +#include +#include #include "helpers/subghz_chat.h" @@ -24,6 +28,19 @@ #define SUBGHZ_REGION_FILENAME "/int/.region_data" +static void subghz_cli_radio_device_power_on() { + uint8_t attempts = 0; + while(!furi_hal_power_is_otg_enabled() && attempts++ < 5) { + furi_hal_power_enable_otg(); + //CC1101 power-up time + furi_delay_ms(10); + } +} + +static void subghz_cli_radio_device_power_off() { + if(furi_hal_power_is_otg_enabled()) furi_hal_power_disable_otg(); +} + void subghz_cli_command_tx_carrier(Cli* cli, FuriString* args, void* context) { UNUSED(context); uint32_t frequency = 433920000; @@ -44,7 +61,7 @@ void subghz_cli_command_tx_carrier(Cli* cli, FuriString* args, void* context) { } furi_hal_subghz_reset(); - furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async); + furi_hal_subghz_load_custom_preset(subghz_device_cc1101_preset_ook_650khz_async_regs); frequency = furi_hal_subghz_set_frequency_and_path(frequency); furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); @@ -88,7 +105,7 @@ void subghz_cli_command_rx_carrier(Cli* cli, FuriString* args, void* context) { } furi_hal_subghz_reset(); - furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async); + furi_hal_subghz_load_custom_preset(subghz_device_cc1101_preset_ook_650khz_async_regs); frequency = furi_hal_subghz_set_frequency_and_path(frequency); printf("Receiving at frequency %lu Hz\r\n", frequency); printf("Press CTRL+C to stop\r\n"); @@ -109,44 +126,70 @@ void subghz_cli_command_rx_carrier(Cli* cli, FuriString* args, void* context) { furi_hal_subghz_sleep(); } +static const SubGhzDevice* subghz_cli_command_get_device(uint32_t device_ind) { + const SubGhzDevice* device = NULL; + switch(device_ind) { + case 1: + subghz_cli_radio_device_power_on(); + device = subghz_devices_get_by_name(SUBGHZ_DEVICE_CC1101_EXT_NAME); + break; + + default: + device = subghz_devices_get_by_name(SUBGHZ_DEVICE_CC1101_INT_NAME); + break; + } + return device; +} + void subghz_cli_command_tx(Cli* cli, FuriString* args, void* context) { UNUSED(context); uint32_t frequency = 433920000; uint32_t key = 0x0074BADE; uint32_t repeat = 10; uint32_t te = 403; + uint32_t device_ind = 0; // 0 - CC1101_INT, 1 - CC1101_EXT if(furi_string_size(args)) { - int ret = - sscanf(furi_string_get_cstr(args), "%lx %lu %lu %lu", &key, &frequency, &te, &repeat); - if(ret != 4) { + int ret = sscanf( + furi_string_get_cstr(args), + "%lx %lu %lu %lu %lu", + &key, + &frequency, + &te, + &repeat, + &device_ind); + if(ret != 5) { printf( - "sscanf returned %d, key: %lx, frequency: %lu, te:%lu, repeat: %lu\r\n", + "sscanf returned %d, key: %lx, frequency: %lu, te: %lu, repeat: %lu, device: %lu\r\n ", ret, key, frequency, te, - repeat); + repeat, + device_ind); cli_print_usage( "subghz tx", - "<3 Byte Key: in hex> ", + "<3 Byte Key: in hex> ", furi_string_get_cstr(args)); return; } - if(!furi_hal_subghz_is_frequency_valid(frequency)) { - printf( - "Frequency must be in " SUBGHZ_FREQUENCY_RANGE_STR " range, not %lu\r\n", - frequency); - return; - } } - + subghz_devices_init(); + const SubGhzDevice* device = subghz_cli_command_get_device(device_ind); + if(!subghz_devices_is_frequency_valid(device, frequency)) { + printf( + "Frequency must be in " SUBGHZ_FREQUENCY_RANGE_STR " range, not %lu\r\n", frequency); + subghz_devices_deinit(); + subghz_cli_radio_device_power_off(); + return; + } printf( - "Transmitting at %lu, key %lx, te %lu, repeat %lu. Press CTRL+C to stop\r\n", + "Transmitting at %lu, key %lx, te %lu, repeat %lu device %lu. Press CTRL+C to stop\r\n", frequency, key, te, - repeat); + repeat, + device_ind); FuriString* flipper_format_string = furi_string_alloc_printf( "Protocol: Princeton\n" @@ -170,25 +213,29 @@ void subghz_cli_command_tx(Cli* cli, FuriString* args, void* context) { SubGhzTransmitter* transmitter = subghz_transmitter_alloc_init(environment, "Princeton"); subghz_transmitter_deserialize(transmitter, flipper_format); - furi_hal_subghz_reset(); - furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async); - frequency = furi_hal_subghz_set_frequency_and_path(frequency); + subghz_devices_begin(device); + subghz_devices_reset(device); + subghz_devices_load_preset(device, FuriHalSubGhzPresetOok650Async, NULL); + frequency = subghz_devices_set_frequency(device, frequency); furi_hal_power_suppress_charge_enter(); - - if(furi_hal_subghz_start_async_tx(subghz_transmitter_yield, transmitter)) { - while(!(furi_hal_subghz_is_async_tx_complete() || cli_cmd_interrupt_received(cli))) { + if(subghz_devices_start_async_tx(device, subghz_transmitter_yield, transmitter)) { + while(!(subghz_devices_is_async_complete_tx(device) || cli_cmd_interrupt_received(cli))) { printf("."); fflush(stdout); furi_delay_ms(333); } - furi_hal_subghz_stop_async_tx(); + subghz_devices_stop_async_tx(device); } else { printf("Transmission on this frequency is restricted in your region\r\n"); } - furi_hal_subghz_sleep(); + subghz_devices_sleep(device); + subghz_devices_end(device); + subghz_devices_deinit(); + subghz_cli_radio_device_power_off(); + furi_hal_power_suppress_charge_exit(); flipper_format_free(flipper_format); @@ -233,21 +280,29 @@ static void subghz_cli_command_rx_callback( void subghz_cli_command_rx(Cli* cli, FuriString* args, void* context) { UNUSED(context); uint32_t frequency = 433920000; + uint32_t device_ind = 0; // 0 - CC1101_INT, 1 - CC1101_EXT if(furi_string_size(args)) { - int ret = sscanf(furi_string_get_cstr(args), "%lu", &frequency); - if(ret != 1) { - printf("sscanf returned %d, frequency: %lu\r\n", ret, frequency); - cli_print_usage("subghz rx", "", furi_string_get_cstr(args)); - return; - } - if(!furi_hal_subghz_is_frequency_valid(frequency)) { + int ret = sscanf(furi_string_get_cstr(args), "%lu %lu", &frequency, &device_ind); + if(ret != 2) { printf( - "Frequency must be in " SUBGHZ_FREQUENCY_RANGE_STR " range, not %lu\r\n", - frequency); + "sscanf returned %d, frequency: %lu device: %lu\r\n", ret, frequency, device_ind); + cli_print_usage( + "subghz rx", + " ", + furi_string_get_cstr(args)); return; } } + subghz_devices_init(); + const SubGhzDevice* device = subghz_cli_command_get_device(device_ind); + if(!subghz_devices_is_frequency_valid(device, frequency)) { + printf( + "Frequency must be in " SUBGHZ_FREQUENCY_RANGE_STR " range, not %lu\r\n", frequency); + subghz_devices_deinit(); + subghz_cli_radio_device_power_off(); + return; + } // Allocate context and buffers SubGhzCliCommandRx* instance = malloc(sizeof(SubGhzCliCommandRx)); @@ -256,14 +311,14 @@ void subghz_cli_command_rx(Cli* cli, FuriString* args, void* context) { furi_check(instance->stream); SubGhzEnvironment* environment = subghz_environment_alloc(); - subghz_environment_load_keystore(environment, EXT_PATH("subghz/assets/keeloq_mfcodes")); - subghz_environment_load_keystore(environment, EXT_PATH("subghz/assets/keeloq_mfcodes_user")); + subghz_environment_load_keystore(environment, SUBGHZ_KEYSTORE_DIR_NAME); + subghz_environment_load_keystore(environment, SUBGHZ_KEYSTORE_DIR_USER_NAME); subghz_environment_set_came_atomo_rainbow_table_file_name( - environment, EXT_PATH("subghz/assets/came_atomo")); + environment, SUBGHZ_CAME_ATOMO_DIR_NAME); subghz_environment_set_alutech_at_4n_rainbow_table_file_name( - environment, EXT_PATH("subghz/assets/alutech_at_4n")); + environment, SUBGHZ_ALUTECH_AT_4N_DIR_NAME); subghz_environment_set_nice_flor_s_rainbow_table_file_name( - environment, EXT_PATH("subghz/assets/nice_flor_s")); + environment, SUBGHZ_NICE_FLOR_S_DIR_NAME); subghz_environment_set_protocol_registry(environment, (void*)&subghz_protocol_registry); SubGhzReceiver* receiver = subghz_receiver_alloc_init(environment); @@ -271,18 +326,21 @@ void subghz_cli_command_rx(Cli* cli, FuriString* args, void* context) { subghz_receiver_set_rx_callback(receiver, subghz_cli_command_rx_callback, instance); // Configure radio - furi_hal_subghz_reset(); - furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async); - frequency = furi_hal_subghz_set_frequency_and_path(frequency); - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); + subghz_devices_begin(device); + subghz_devices_reset(device); + subghz_devices_load_preset(device, FuriHalSubGhzPresetOok650Async, NULL); + frequency = subghz_devices_set_frequency(device, frequency); furi_hal_power_suppress_charge_enter(); // Prepare and start RX - furi_hal_subghz_start_async_rx(subghz_cli_command_rx_capture_callback, instance); + subghz_devices_start_async_rx(device, subghz_cli_command_rx_capture_callback, instance); // Wait for packets to arrive - printf("Listening at %lu. Press CTRL+C to stop\r\n", frequency); + printf( + "Listening at frequency: %lu device: %lu. Press CTRL+C to stop\r\n", + frequency, + device_ind); LevelDuration level_duration; while(!cli_cmd_interrupt_received(cli)) { int ret = furi_stream_buffer_receive( @@ -300,8 +358,11 @@ void subghz_cli_command_rx(Cli* cli, FuriString* args, void* context) { } // Shutdown radio - furi_hal_subghz_stop_async_rx(); - furi_hal_subghz_sleep(); + subghz_devices_stop_async_rx(device); + subghz_devices_sleep(device); + subghz_devices_end(device); + subghz_devices_deinit(); + subghz_cli_radio_device_power_off(); furi_hal_power_suppress_charge_exit(); @@ -341,7 +402,7 @@ void subghz_cli_command_rx_raw(Cli* cli, FuriString* args, void* context) { // Configure radio furi_hal_subghz_reset(); - furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok270Async); + furi_hal_subghz_load_custom_preset(subghz_device_cc1101_preset_ook_270khz_async_regs); frequency = furi_hal_subghz_set_frequency_and_path(frequency); furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); @@ -389,6 +450,7 @@ void subghz_cli_command_rx_raw(Cli* cli, FuriString* args, void* context) { furi_stream_buffer_free(instance->stream); free(instance); } + void subghz_cli_command_decode_raw(Cli* cli, FuriString* args, void* context) { UNUSED(context); FuriString* file_name; @@ -442,25 +504,23 @@ void subghz_cli_command_decode_raw(Cli* cli, FuriString* args, void* context) { SubGhzCliCommandRx* instance = malloc(sizeof(SubGhzCliCommandRx)); SubGhzEnvironment* environment = subghz_environment_alloc(); - if(subghz_environment_load_keystore( - environment, EXT_PATH("subghz/assets/keeloq_mfcodes"))) { + if(subghz_environment_load_keystore(environment, SUBGHZ_KEYSTORE_DIR_NAME)) { printf("SubGhz decode_raw: Load_keystore keeloq_mfcodes \033[0;32mOK\033[0m\r\n"); } else { printf("SubGhz decode_raw: Load_keystore keeloq_mfcodes \033[0;31mERROR\033[0m\r\n"); } - if(subghz_environment_load_keystore( - environment, EXT_PATH("subghz/assets/keeloq_mfcodes_user"))) { + if(subghz_environment_load_keystore(environment, SUBGHZ_KEYSTORE_DIR_USER_NAME)) { printf("SubGhz decode_raw: Load_keystore keeloq_mfcodes_user \033[0;32mOK\033[0m\r\n"); } else { printf( "SubGhz decode_raw: Load_keystore keeloq_mfcodes_user \033[0;31mERROR\033[0m\r\n"); } subghz_environment_set_came_atomo_rainbow_table_file_name( - environment, EXT_PATH("subghz/assets/came_atomo")); + environment, SUBGHZ_CAME_ATOMO_DIR_NAME); subghz_environment_set_alutech_at_4n_rainbow_table_file_name( - environment, EXT_PATH("subghz/assets/alutech_at_4n")); + environment, SUBGHZ_ALUTECH_AT_4N_DIR_NAME); subghz_environment_set_nice_flor_s_rainbow_table_file_name( - environment, EXT_PATH("subghz/assets/nice_flor_s")); + environment, SUBGHZ_NICE_FLOR_S_DIR_NAME); subghz_environment_set_protocol_registry(environment, (void*)&subghz_protocol_registry); SubGhzReceiver* receiver = subghz_receiver_alloc_init(environment); @@ -468,7 +528,8 @@ void subghz_cli_command_decode_raw(Cli* cli, FuriString* args, void* context) { subghz_receiver_set_rx_callback(receiver, subghz_cli_command_rx_callback, instance); SubGhzFileEncoderWorker* file_worker_encoder = subghz_file_encoder_worker_alloc(); - if(subghz_file_encoder_worker_start(file_worker_encoder, furi_string_get_cstr(file_name))) { + if(subghz_file_encoder_worker_start( + file_worker_encoder, furi_string_get_cstr(file_name), NULL)) { //the worker needs a file in order to open and read part of the file furi_delay_ms(100); } @@ -510,10 +571,11 @@ static void subghz_cli_command_print_usage() { printf("subghz \r\n"); printf("Cmd list:\r\n"); - printf("\tchat \t - Chat with other Flippers\r\n"); printf( - "\ttx <3 byte Key: in hex> \t - Transmitting key\r\n"); - printf("\trx \t - Receive\r\n"); + "\tchat \t - Chat with other Flippers\r\n"); + printf( + "\ttx <3 byte Key: in hex> \t - Transmitting key\r\n"); + printf("\trx \t - Receive\r\n"); printf("\trx_raw \t - Receive RAW\r\n"); printf("\tdecode_raw \t - Testing\r\n"); @@ -611,21 +673,29 @@ static void subghz_cli_command_encrypt_raw(Cli* cli, FuriString* args) { static void subghz_cli_command_chat(Cli* cli, FuriString* args) { uint32_t frequency = 433920000; + uint32_t device_ind = 0; // 0 - CC1101_INT, 1 - CC1101_EXT if(furi_string_size(args)) { - int ret = sscanf(furi_string_get_cstr(args), "%lu", &frequency); - if(ret != 1) { - printf("sscanf returned %d, frequency: %lu\r\n", ret, frequency); - cli_print_usage("subghz chat", "", furi_string_get_cstr(args)); - return; - } - if(!furi_hal_subghz_is_frequency_valid(frequency)) { - printf( - "Frequency must be in " SUBGHZ_FREQUENCY_RANGE_STR " range, not %lu\r\n", - frequency); + int ret = sscanf(furi_string_get_cstr(args), "%lu %lu", &frequency, &device_ind); + if(ret != 2) { + printf("sscanf returned %d, Frequency: %lu\r\n", ret, frequency); + printf("sscanf returned %d, Device: %lu\r\n", ret, device_ind); + cli_print_usage( + "subghz chat", + " ", + furi_string_get_cstr(args)); return; } } + subghz_devices_init(); + const SubGhzDevice* device = subghz_cli_command_get_device(device_ind); + if(!subghz_devices_is_frequency_valid(device, frequency)) { + printf( + "Frequency must be in " SUBGHZ_FREQUENCY_RANGE_STR " range, not %lu\r\n", frequency); + subghz_devices_deinit(); + subghz_cli_radio_device_power_off(); + return; + } if(!furi_hal_region_is_frequency_allowed(frequency)) { printf( "In your region, only reception on this frequency (%lu) is allowed,\r\n" @@ -635,7 +705,8 @@ static void subghz_cli_command_chat(Cli* cli, FuriString* args) { } SubGhzChatWorker* subghz_chat = subghz_chat_worker_alloc(cli); - if(!subghz_chat_worker_start(subghz_chat, frequency)) { + + if(!subghz_chat_worker_start(subghz_chat, device, frequency)) { printf("Startup error SubGhzChatWorker\r\n"); if(subghz_chat_worker_is_running(subghz_chat)) { @@ -781,6 +852,10 @@ static void subghz_cli_command_chat(Cli* cli, FuriString* args) { furi_string_free(name); furi_string_free(output); furi_string_free(sysmsg); + + subghz_devices_deinit(); + subghz_cli_radio_device_power_off(); + furi_hal_power_suppress_charge_exit(); furi_record_close(RECORD_NOTIFICATION); diff --git a/applications/main/subghz/subghz_i.c b/applications/main/subghz/subghz_i.c index 8036ed5f7ac4..55036846cae1 100644 --- a/applications/main/subghz/subghz_i.c +++ b/applications/main/subghz/subghz_i.c @@ -115,7 +115,7 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) { break; } - if(!furi_hal_subghz_is_frequency_valid(temp_data32)) { + if(!subghz_txrx_radio_device_is_frequecy_valid(subghz->txrx, temp_data32)) { FURI_LOG_E(TAG, "Frequency not supported"); break; } @@ -163,7 +163,8 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) { if(!strcmp(furi_string_get_cstr(temp_str), "RAW")) { //if RAW subghz->load_type_file = SubGhzLoadTypeFileRaw; - subghz_protocol_raw_gen_fff_data(fff_data, file_path); + subghz_protocol_raw_gen_fff_data( + fff_data, file_path, subghz_txrx_radio_device_get_name(subghz->txrx)); } else { subghz->load_type_file = SubGhzLoadTypeFileKey; stream_copy_full( diff --git a/applications/main/subghz/views/receiver.c b/applications/main/subghz/views/receiver.c index f84ddfed086f..e1014b811095 100644 --- a/applications/main/subghz/views/receiver.c +++ b/applications/main/subghz/views/receiver.c @@ -62,6 +62,7 @@ typedef struct { uint16_t history_item; SubGhzViewReceiverBarShow bar_show; uint8_t u_rssi; + SubGhzRadioDeviceType device_type; } SubGhzViewReceiverModel; void subghz_receiver_rssi(SubGhzViewReceiver* instance, float rssi) { @@ -173,6 +174,17 @@ void subghz_view_receiver_add_data_statusbar( true); } +void subghz_view_receiver_set_radio_device_type( + SubGhzViewReceiver* subghz_receiver, + SubGhzRadioDeviceType device_type) { + furi_assert(subghz_receiver); + with_view_model( + subghz_receiver->view, + SubGhzViewReceiverModel * model, + { model->device_type = device_type; }, + true); +} + static void subghz_view_receiver_draw_frame(Canvas* canvas, uint16_t idx, bool scrollbar) { canvas_set_color(canvas, ColorBlack); canvas_draw_box(canvas, 0, 0 + idx * FRAME_HEIGHT, scrollbar ? 122 : 127, FRAME_HEIGHT); @@ -190,9 +202,9 @@ static void subghz_view_receiver_draw_frame(Canvas* canvas, uint16_t idx, bool s static void subghz_view_rssi_draw(Canvas* canvas, SubGhzViewReceiverModel* model) { for(uint8_t i = 1; i < model->u_rssi; i++) { if(i % 5) { - canvas_draw_dot(canvas, 46 + i, 50); - canvas_draw_dot(canvas, 47 + i, 51); canvas_draw_dot(canvas, 46 + i, 52); + canvas_draw_dot(canvas, 47 + i, 53); + canvas_draw_dot(canvas, 46 + i, 54); } } } @@ -232,22 +244,28 @@ void subghz_view_receiver_draw(Canvas* canvas, SubGhzViewReceiverModel* model) { canvas_set_color(canvas, ColorBlack); if(model->history_item == 0) { - canvas_draw_icon(canvas, 0, 0, &I_Scanning_123x52); + canvas_draw_icon(canvas, 0, 0, &I_Scanning_short_96x52); canvas_set_font(canvas, FontPrimary); canvas_draw_str(canvas, 63, 44, "Scanning..."); canvas_set_font(canvas, FontSecondary); } + if(model->device_type == SubGhzRadioDeviceTypeInternal) { + canvas_draw_icon(canvas, 108, 0, &I_Internal_antenna_20x12); + } else { + canvas_draw_icon(canvas, 108, 0, &I_External_antenna_20x12); + } + subghz_view_rssi_draw(canvas, model); switch(model->bar_show) { case SubGhzViewReceiverBarShowLock: - canvas_draw_icon(canvas, 64, 55, &I_Lock_7x8); - canvas_draw_str(canvas, 74, 62, "Locked"); + canvas_draw_icon(canvas, 64, 56, &I_Lock_7x8); + canvas_draw_str(canvas, 74, 64, "Locked"); break; case SubGhzViewReceiverBarShowToUnlockPress: - canvas_draw_str(canvas, 44, 62, furi_string_get_cstr(model->frequency_str)); - canvas_draw_str(canvas, 79, 62, furi_string_get_cstr(model->preset_str)); - canvas_draw_str(canvas, 96, 62, furi_string_get_cstr(model->history_stat_str)); + canvas_draw_str(canvas, 44, 64, furi_string_get_cstr(model->frequency_str)); + canvas_draw_str(canvas, 79, 64, furi_string_get_cstr(model->preset_str)); + canvas_draw_str(canvas, 97, 64, furi_string_get_cstr(model->history_stat_str)); canvas_set_font(canvas, FontSecondary); elements_bold_rounded_frame(canvas, 14, 8, 99, 48); elements_multiline_text(canvas, 65, 26, "To unlock\npress:"); @@ -258,13 +276,13 @@ void subghz_view_receiver_draw(Canvas* canvas, SubGhzViewReceiverModel* model) { canvas_draw_dot(canvas, 17, 61); break; case SubGhzViewReceiverBarShowUnlock: - canvas_draw_icon(canvas, 64, 55, &I_Unlock_7x8); - canvas_draw_str(canvas, 74, 62, "Unlocked"); + canvas_draw_icon(canvas, 64, 56, &I_Unlock_7x8); + canvas_draw_str(canvas, 74, 64, "Unlocked"); break; default: - canvas_draw_str(canvas, 44, 62, furi_string_get_cstr(model->frequency_str)); - canvas_draw_str(canvas, 79, 62, furi_string_get_cstr(model->preset_str)); - canvas_draw_str(canvas, 96, 62, furi_string_get_cstr(model->history_stat_str)); + canvas_draw_str(canvas, 44, 64, furi_string_get_cstr(model->frequency_str)); + canvas_draw_str(canvas, 79, 64, furi_string_get_cstr(model->preset_str)); + canvas_draw_str(canvas, 97, 64, furi_string_get_cstr(model->history_stat_str)); break; } } diff --git a/applications/main/subghz/views/receiver.h b/applications/main/subghz/views/receiver.h index 5119105e93ba..c91c069386cb 100644 --- a/applications/main/subghz/views/receiver.h +++ b/applications/main/subghz/views/receiver.h @@ -29,6 +29,10 @@ void subghz_view_receiver_add_data_statusbar( const char* preset_str, const char* history_stat_str); +void subghz_view_receiver_set_radio_device_type( + SubGhzViewReceiver* subghz_receiver, + SubGhzRadioDeviceType device_type); + void subghz_view_receiver_add_item_to_menu( SubGhzViewReceiver* subghz_receiver, const char* name, diff --git a/applications/main/subghz/views/subghz_frequency_analyzer.c b/applications/main/subghz/views/subghz_frequency_analyzer.c index 325664f4a9c5..d90401678a85 100644 --- a/applications/main/subghz/views/subghz_frequency_analyzer.c +++ b/applications/main/subghz/views/subghz_frequency_analyzer.c @@ -177,7 +177,8 @@ void subghz_frequency_analyzer_draw(Canvas* canvas, SubGhzFrequencyAnalyzerModel } subghz_frequency_analyzer_log_frequency_draw(canvas, model); } else { - canvas_draw_str(canvas, 20, 8, "Frequency Analyzer"); + canvas_draw_str(canvas, 0, 8, "Frequency Analyzer"); + canvas_draw_icon(canvas, 108, 0, &I_Internal_antenna_20x12); canvas_draw_str(canvas, 0, 64, "RSSI"); subghz_frequency_analyzer_draw_rssi(canvas, model->rssi, 20, 64); diff --git a/applications/main/subghz/views/subghz_read_raw.c b/applications/main/subghz/views/subghz_read_raw.c index 2ff598b60584..88ac129ca9ec 100644 --- a/applications/main/subghz/views/subghz_read_raw.c +++ b/applications/main/subghz/views/subghz_read_raw.c @@ -29,6 +29,7 @@ typedef struct { uint8_t ind_sin; SubGhzReadRAWStatus status; float raw_threshold_rssi; + SubGhzRadioDeviceType device_type; } SubGhzReadRAWModel; void subghz_read_raw_set_callback( @@ -56,6 +57,14 @@ void subghz_read_raw_add_data_statusbar( true); } +void subghz_read_raw_set_radio_device_type( + SubGhzReadRAW* instance, + SubGhzRadioDeviceType device_type) { + furi_assert(instance); + with_view_model( + instance->view, SubGhzReadRAWModel * model, { model->device_type = device_type; }, true); +} + void subghz_read_raw_add_data_rssi(SubGhzReadRAW* instance, float rssi, bool trace) { furi_assert(instance); uint8_t u_rssi = 0; @@ -279,11 +288,16 @@ void subghz_read_raw_draw(Canvas* canvas, SubGhzReadRAWModel* model) { uint8_t graphics_mode = 1; canvas_set_color(canvas, ColorBlack); canvas_set_font(canvas, FontSecondary); - canvas_draw_str(canvas, 5, 7, furi_string_get_cstr(model->frequency_str)); - canvas_draw_str(canvas, 40, 7, furi_string_get_cstr(model->preset_str)); + canvas_draw_str(canvas, 0, 9, furi_string_get_cstr(model->frequency_str)); + canvas_draw_str(canvas, 35, 9, furi_string_get_cstr(model->preset_str)); canvas_draw_str_aligned( - canvas, 126, 0, AlignRight, AlignTop, furi_string_get_cstr(model->sample_write)); + canvas, 106, 2, AlignRight, AlignTop, furi_string_get_cstr(model->sample_write)); + if(model->device_type == SubGhzRadioDeviceTypeInternal) { + canvas_draw_icon(canvas, 108, 0, &I_Internal_antenna_20x12); + } else { + canvas_draw_icon(canvas, 108, 0, &I_External_antenna_20x12); + } canvas_draw_line(canvas, 0, 14, 115, 14); canvas_draw_line(canvas, 0, 48, 115, 48); canvas_draw_line(canvas, 115, 14, 115, 48); diff --git a/applications/main/subghz/views/subghz_read_raw.h b/applications/main/subghz/views/subghz_read_raw.h index 31aa9db6fdd1..83403e9750c9 100644 --- a/applications/main/subghz/views/subghz_read_raw.h +++ b/applications/main/subghz/views/subghz_read_raw.h @@ -1,6 +1,7 @@ #pragma once #include +#include "../helpers/subghz_types.h" #include "../helpers/subghz_custom_event.h" #define SUBGHZ_RAW_THRESHOLD_MIN -90.0f @@ -36,6 +37,10 @@ void subghz_read_raw_add_data_statusbar( const char* frequency_str, const char* preset_str); +void subghz_read_raw_set_radio_device_type( + SubGhzReadRAW* instance, + SubGhzRadioDeviceType device_type); + void subghz_read_raw_update_sample_write(SubGhzReadRAW* instance, size_t sample); void subghz_read_raw_stop_send(SubGhzReadRAW* instance); diff --git a/applications/main/subghz/views/subghz_test_carrier.c b/applications/main/subghz/views/subghz_test_carrier.c index e533a6aac4e9..254a4127bc4f 100644 --- a/applications/main/subghz/views/subghz_test_carrier.c +++ b/applications/main/subghz/views/subghz_test_carrier.c @@ -1,6 +1,7 @@ #include "subghz_test_carrier.h" #include "../subghz_i.h" #include "../helpers/subghz_testing.h" +#include #include #include @@ -138,7 +139,7 @@ void subghz_test_carrier_enter(void* context) { SubGhzTestCarrier* subghz_test_carrier = context; furi_hal_subghz_reset(); - furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async); + furi_hal_subghz_load_custom_preset(subghz_device_cc1101_preset_ook_650khz_async_regs); furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); diff --git a/applications/main/subghz/views/subghz_test_packet.c b/applications/main/subghz/views/subghz_test_packet.c index 43502180cea4..bc2c474b513f 100644 --- a/applications/main/subghz/views/subghz_test_packet.c +++ b/applications/main/subghz/views/subghz_test_packet.c @@ -1,6 +1,7 @@ #include "subghz_test_packet.h" #include "../subghz_i.h" #include "../helpers/subghz_testing.h" +#include #include #include @@ -194,7 +195,7 @@ void subghz_test_packet_enter(void* context) { SubGhzTestPacket* instance = context; furi_hal_subghz_reset(); - furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async); + furi_hal_subghz_load_custom_preset(subghz_device_cc1101_preset_ook_650khz_async_regs); with_view_model( instance->view, diff --git a/applications/main/subghz/views/subghz_test_static.c b/applications/main/subghz/views/subghz_test_static.c index 6abefda763e8..197af21fb5f7 100644 --- a/applications/main/subghz/views/subghz_test_static.c +++ b/applications/main/subghz/views/subghz_test_static.c @@ -1,6 +1,7 @@ #include "subghz_test_static.h" #include "../subghz_i.h" #include "../helpers/subghz_testing.h" +#include #include #include @@ -141,7 +142,7 @@ void subghz_test_static_enter(void* context) { SubGhzTestStatic* instance = context; furi_hal_subghz_reset(); - furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async); + furi_hal_subghz_load_custom_preset(subghz_device_cc1101_preset_ook_650khz_async_regs); furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); furi_hal_gpio_write(&gpio_cc1101_g0, false); diff --git a/applications/main/subghz/views/transmitter.c b/applications/main/subghz/views/transmitter.c index 86dc17a38f7f..2a876f8c268b 100644 --- a/applications/main/subghz/views/transmitter.c +++ b/applications/main/subghz/views/transmitter.c @@ -15,6 +15,7 @@ typedef struct { FuriString* preset_str; FuriString* key_str; bool show_button; + SubGhzRadioDeviceType device_type; } SubGhzViewTransmitterModel; void subghz_view_transmitter_set_callback( @@ -46,6 +47,17 @@ void subghz_view_transmitter_add_data_to_show( true); } +void subghz_view_transmitter_set_radio_device_type( + SubGhzViewTransmitter* subghz_transmitter, + SubGhzRadioDeviceType device_type) { + furi_assert(subghz_transmitter); + with_view_model( + subghz_transmitter->view, + SubGhzViewTransmitterModel * model, + { model->device_type = device_type; }, + true); +} + static void subghz_view_transmitter_button_right(Canvas* canvas, const char* str) { const uint8_t button_height = 12; const uint8_t vertical_offset = 3; @@ -56,7 +68,7 @@ static void subghz_view_transmitter_button_right(Canvas* canvas, const char* str const uint8_t icon_width_with_offset = icon_get_width(icon) + icon_offset; const uint8_t button_width = string_width + horizontal_offset * 2 + icon_width_with_offset; - const uint8_t x = (canvas_width(canvas) - button_width) / 2 + 40; + const uint8_t x = (canvas_width(canvas) - button_width) / 2 + 44; const uint8_t y = canvas_height(canvas); canvas_draw_box(canvas, x, y - button_height, button_width, button_height); @@ -88,7 +100,14 @@ void subghz_view_transmitter_draw(Canvas* canvas, SubGhzViewTransmitterModel* mo canvas, 0, 0, AlignLeft, AlignTop, furi_string_get_cstr(model->key_str)); canvas_draw_str(canvas, 78, 7, furi_string_get_cstr(model->frequency_str)); canvas_draw_str(canvas, 113, 7, furi_string_get_cstr(model->preset_str)); - if(model->show_button) subghz_view_transmitter_button_right(canvas, "Send"); + if(model->show_button) { + if(model->device_type == SubGhzRadioDeviceTypeInternal) { + canvas_draw_icon(canvas, 108, 39, &I_Internal_antenna_20x12); + } else { + canvas_draw_icon(canvas, 108, 39, &I_External_antenna_20x12); + } + subghz_view_transmitter_button_right(canvas, "Send"); + } } bool subghz_view_transmitter_input(InputEvent* event, void* context) { diff --git a/applications/main/subghz/views/transmitter.h b/applications/main/subghz/views/transmitter.h index 06aae7c6bf74..19da3145c95c 100644 --- a/applications/main/subghz/views/transmitter.h +++ b/applications/main/subghz/views/transmitter.h @@ -1,6 +1,7 @@ #pragma once #include +#include "../helpers/subghz_types.h" #include "../helpers/subghz_custom_event.h" typedef struct SubGhzViewTransmitter SubGhzViewTransmitter; @@ -12,6 +13,10 @@ void subghz_view_transmitter_set_callback( SubGhzViewTransmitterCallback callback, void* context); +void subghz_view_transmitter_set_radio_device_type( + SubGhzViewTransmitter* subghz_transmitter, + SubGhzRadioDeviceType device_type); + SubGhzViewTransmitter* subghz_view_transmitter_alloc(); void subghz_view_transmitter_free(SubGhzViewTransmitter* subghz_transmitter); diff --git a/applications/services/applications.h b/applications/services/applications.h index 85f736742326..45b050a06ecc 100644 --- a/applications/services/applications.h +++ b/applications/services/applications.h @@ -4,9 +4,9 @@ #include typedef enum { - FlipperApplicationFlagDefault = 0, - FlipperApplicationFlagInsomniaSafe = (1 << 0), -} FlipperApplicationFlag; + FlipperInternalApplicationFlagDefault = 0, + FlipperInternalApplicationFlagInsomniaSafe = (1 << 0), +} FlipperInternalApplicationFlag; typedef struct { const FuriThreadCallback app; @@ -14,48 +14,41 @@ typedef struct { const char* appid; const size_t stack_size; const Icon* icon; - const FlipperApplicationFlag flags; -} FlipperApplication; + const FlipperInternalApplicationFlag flags; +} FlipperInternalApplication; -typedef void (*FlipperOnStartHook)(void); +typedef void (*FlipperInternalOnStartHook)(void); extern const char* FLIPPER_AUTORUN_APP_NAME; /* Services list * Spawned on startup */ -extern const FlipperApplication FLIPPER_SERVICES[]; +extern const FlipperInternalApplication FLIPPER_SERVICES[]; extern const size_t FLIPPER_SERVICES_COUNT; /* Apps list * Spawned by loader */ -extern const FlipperApplication FLIPPER_APPS[]; +extern const FlipperInternalApplication FLIPPER_APPS[]; extern const size_t FLIPPER_APPS_COUNT; /* On system start hooks * Called by loader, after OS initialization complete */ -extern const FlipperOnStartHook FLIPPER_ON_SYSTEM_START[]; +extern const FlipperInternalOnStartHook FLIPPER_ON_SYSTEM_START[]; extern const size_t FLIPPER_ON_SYSTEM_START_COUNT; /* System apps * Can only be spawned by loader by name */ -extern const FlipperApplication FLIPPER_SYSTEM_APPS[]; +extern const FlipperInternalApplication FLIPPER_SYSTEM_APPS[]; extern const size_t FLIPPER_SYSTEM_APPS_COUNT; -/* Separate scene app holder - * Spawned by loader - */ -extern const FlipperApplication FLIPPER_SCENE; -extern const FlipperApplication FLIPPER_SCENE_APPS[]; -extern const size_t FLIPPER_SCENE_APPS_COUNT; - -extern const FlipperApplication FLIPPER_ARCHIVE; +extern const FlipperInternalApplication FLIPPER_ARCHIVE; /* Settings list * Spawned by loader */ -extern const FlipperApplication FLIPPER_SETTINGS_APPS[]; +extern const FlipperInternalApplication FLIPPER_SETTINGS_APPS[]; extern const size_t FLIPPER_SETTINGS_APPS_COUNT; diff --git a/applications/services/desktop/desktop.c b/applications/services/desktop/desktop.c index e1da649408b8..1233af8938fe 100644 --- a/applications/services/desktop/desktop.c +++ b/applications/services/desktop/desktop.c @@ -36,6 +36,7 @@ static void desktop_loader_callback(const void* message, void* context) { view_dispatcher_send_custom_event(desktop->view_dispatcher, DesktopGlobalAfterAppFinished); } } + static void desktop_lock_icon_draw_callback(Canvas* canvas, void* context) { UNUSED(context); furi_assert(canvas); diff --git a/applications/services/desktop/scenes/desktop_scene_main.c b/applications/services/desktop/scenes/desktop_scene_main.c index d19b5560f940..ae39ec223767 100644 --- a/applications/services/desktop/scenes/desktop_scene_main.c +++ b/applications/services/desktop/scenes/desktop_scene_main.c @@ -16,8 +16,6 @@ #define SNAKE_GAME_APP EXT_PATH("/apps/Games/snake_game.fap") #define CLOCK_APP EXT_PATH("/apps/Tools/clock.fap") -#define FAP_LOADER_APP_NAME "Applications" - static void desktop_scene_main_new_idle_animation_callback(void* context) { furi_assert(context); Desktop* desktop = context; @@ -40,7 +38,8 @@ static void desktop_scene_main_interact_animation_callback(void* context) { } #ifdef APP_ARCHIVE -static void desktop_switch_to_app(Desktop* desktop, const FlipperApplication* flipper_app) { +static void + desktop_switch_to_app(Desktop* desktop, const FlipperInternalApplication* flipper_app) { furi_assert(desktop); furi_assert(flipper_app); furi_assert(flipper_app->app); @@ -67,30 +66,16 @@ static void desktop_switch_to_app(Desktop* desktop, const FlipperApplication* fl #endif static void desktop_scene_main_open_app_or_profile(Desktop* desktop, const char* path) { - do { - LoaderStatus status = loader_start(desktop->loader, FAP_LOADER_APP_NAME, path); - if(status == LoaderStatusOk) break; - FURI_LOG_E(TAG, "loader_start failed: %d", status); - - status = loader_start(desktop->loader, "Passport", NULL); - if(status != LoaderStatusOk) { - FURI_LOG_E(TAG, "loader_start failed: %d", status); - } - } while(false); + if(loader_start_with_gui_error(desktop->loader, path, NULL) != LoaderStatusOk) { + loader_start(desktop->loader, "Passport", NULL, NULL); + } } static void desktop_scene_main_start_favorite(Desktop* desktop, FavoriteApp* application) { - LoaderStatus status = LoaderStatusErrorInternal; - if(application->is_external) { - status = loader_start(desktop->loader, FAP_LOADER_APP_NAME, application->name_or_path); - } else if(strlen(application->name_or_path) > 0) { - status = loader_start(desktop->loader, application->name_or_path, NULL); + if(strlen(application->name_or_path) > 0) { + loader_start_with_gui_error(desktop->loader, application->name_or_path, NULL); } else { - status = loader_start(desktop->loader, FAP_LOADER_APP_NAME, NULL); - } - - if(status != LoaderStatusOk) { - FURI_LOG_E(TAG, "loader_start failed: %d", status); + loader_start(desktop->loader, LOADER_APPLICATIONS_NAME, NULL, NULL); } } @@ -148,10 +133,7 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) { break; case DesktopMainEventOpenPowerOff: { - LoaderStatus status = loader_start(desktop->loader, "Power", "off"); - if(status != LoaderStatusOk) { - FURI_LOG_E(TAG, "loader_start failed: %d", status); - } + loader_start(desktop->loader, "Power", "off", NULL); consumed = true; break; } @@ -176,18 +158,12 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) { break; case DesktopAnimationEventInteractAnimation: if(!animation_manager_interact_process(desktop->animation_manager)) { - LoaderStatus status = loader_start(desktop->loader, "Passport", NULL); - if(status != LoaderStatusOk) { - FURI_LOG_E(TAG, "loader_start failed: %d", status); - } + loader_start(desktop->loader, "Passport", NULL, NULL); } consumed = true; break; case DesktopMainEventOpenPassport: { - LoaderStatus status = loader_start(desktop->loader, "Passport", NULL); - if(status != LoaderStatusOk) { - FURI_LOG_E(TAG, "loader_start failed: %d", status); - } + loader_start(desktop->loader, "Passport", NULL, NULL); break; } case DesktopMainEventOpenGame: { diff --git a/applications/services/dialogs/dialogs.c b/applications/services/dialogs/dialogs.c index 3908ca31b585..10c08a991b39 100644 --- a/applications/services/dialogs/dialogs.c +++ b/applications/services/dialogs/dialogs.c @@ -9,12 +9,13 @@ void dialog_file_browser_set_basic_options( const char* extension, const Icon* icon) { options->extension = extension; + options->base_path = NULL; options->skip_assets = true; + options->hide_dot_files = true; options->icon = icon; options->hide_ext = true; options->item_loader_callback = NULL; options->item_loader_context = NULL; - options->base_path = NULL; } static DialogsApp* dialogs_app_alloc() { diff --git a/applications/services/dialogs/dialogs.h b/applications/services/dialogs/dialogs.h index 4c1b675a6446..39b15c67c2ed 100644 --- a/applications/services/dialogs/dialogs.h +++ b/applications/services/dialogs/dialogs.h @@ -16,7 +16,8 @@ typedef struct DialogsApp DialogsApp; /****************** FILE BROWSER ******************/ /** - * File browser dialog extra options + * File browser dialog extra options. + * This can be default-initialized using {@link dialog_file_browser_set_basic_options}. * @param extension file extension to be offered for selection * @param base_path root folder path for navigation with back key * @param skip_assets true - do not show assets folders @@ -38,8 +39,10 @@ typedef struct { } DialogsFileBrowserOptions; /** - * Initialize file browser dialog options - * and set default values + * Initialize file browser dialog options and set default values. + * This is guaranteed to initialize all fields + * so it is safe to pass pointer to uninitialized {@code options} + * and assume that the data behind it becomes fully initialized after the call. * @param options pointer to options structure * @param extension file extension to filter * @param icon file icon pointer, NULL for default icon diff --git a/applications/services/dialogs/dialogs_i.h b/applications/services/dialogs/dialogs_i.h index 76495d31b0a3..29417b41b52f 100644 --- a/applications/services/dialogs/dialogs_i.h +++ b/applications/services/dialogs/dialogs_i.h @@ -1,7 +1,7 @@ #pragma once #include "dialogs.h" #include "dialogs_message.h" -#include "view_holder.h" +#include #include #ifdef __cplusplus diff --git a/applications/services/gui/modules/file_browser.c b/applications/services/gui/modules/file_browser.c index d12a00ba5984..c764a1cf7e35 100644 --- a/applications/services/gui/modules/file_browser.c +++ b/applications/services/gui/modules/file_browser.c @@ -118,6 +118,8 @@ typedef struct { const Icon* file_icon; bool hide_ext; size_t scroll_counter; + + uint32_t button_held_for_ticks; } FileBrowserModel; static const Icon* BrowserItemIcons[] = { @@ -589,9 +591,24 @@ static bool file_browser_view_input_callback(InputEvent* event, void* context) { browser->view, FileBrowserModel * model, { + int32_t scroll_speed = 1; + if(model->button_held_for_ticks > 5) { + if(model->button_held_for_ticks % 2) { + scroll_speed = 0; + } else { + scroll_speed = model->button_held_for_ticks > 9 ? 5 : 3; + } + } + if(event->key == InputKeyUp) { - model->item_idx = - ((model->item_idx - 1) + model->item_cnt) % model->item_cnt; + if(model->item_idx < scroll_speed) { + model->button_held_for_ticks = 0; + model->item_idx = model->item_cnt - 1; + } else { + model->item_idx = + ((model->item_idx - scroll_speed) + model->item_cnt) % + model->item_cnt; + } if(browser_is_list_load_required(model)) { model->list_loading = true; int32_t load_offset = CLAMP( @@ -602,8 +619,16 @@ static bool file_browser_view_input_callback(InputEvent* event, void* context) { browser->worker, load_offset, ITEM_LIST_LEN_MAX); } model->scroll_counter = 0; + + model->button_held_for_ticks += 1; } else if(event->key == InputKeyDown) { - model->item_idx = (model->item_idx + 1) % model->item_cnt; + int32_t count = model->item_cnt; + if(model->item_idx + scroll_speed >= count) { + model->button_held_for_ticks = 0; + model->item_idx = 0; + } else { + model->item_idx = (model->item_idx + scroll_speed) % model->item_cnt; + } if(browser_is_list_load_required(model)) { model->list_loading = true; int32_t load_offset = CLAMP( @@ -614,11 +639,19 @@ static bool file_browser_view_input_callback(InputEvent* event, void* context) { browser->worker, load_offset, ITEM_LIST_LEN_MAX); } model->scroll_counter = 0; + + model->button_held_for_ticks += 1; } }, true); browser_update_offset(browser); consumed = true; + } else if(event->type == InputTypeRelease) { + with_view_model( + browser->view, + FileBrowserModel * model, + { model->button_held_for_ticks = 0; }, + true); } } else if(event->key == InputKeyOk) { if(event->type == InputTypeShort) { diff --git a/applications/services/gui/modules/submenu.c b/applications/services/gui/modules/submenu.c index 9d81c30b688a..3ba35edde079 100644 --- a/applications/services/gui/modules/submenu.c +++ b/applications/services/gui/modules/submenu.c @@ -63,7 +63,7 @@ static void submenu_view_draw_callback(Canvas* canvas, void* _model) { SubmenuModel* model = _model; const uint8_t item_height = 16; - const uint8_t item_width = 123; + uint8_t item_width = canvas_width(canvas) - 5; canvas_clear(canvas); diff --git a/applications/services/gui/modules/text_box.c b/applications/services/gui/modules/text_box.c index 01ccdbf52b5e..0e4aae9446b5 100644 --- a/applications/services/gui/modules/text_box.c +++ b/applications/services/gui/modules/text_box.c @@ -6,6 +6,8 @@ struct TextBox { View* view; + + uint16_t button_held_for_ticks; }; typedef struct { @@ -19,36 +21,52 @@ typedef struct { bool formatted; } TextBoxModel; -static void text_box_process_down(TextBox* text_box) { +static void text_box_process_down(TextBox* text_box, uint8_t lines) { with_view_model( text_box->view, TextBoxModel * model, { - if(model->scroll_pos < model->scroll_num - 1) { - model->scroll_pos++; - // Search next line start - while(*model->text_pos++ != '\n') - ; + if(model->scroll_pos < model->scroll_num - lines) { + model->scroll_pos += lines; + for(uint8_t i = 0; i < lines; i++) { + // Search next line start + while(*model->text_pos++ != '\n') + ; + } + } else if(lines > 1) { + lines = model->scroll_num - model->scroll_pos - 1; + model->scroll_pos = model->scroll_num - 1; + for(uint8_t i = 0; i < lines; i++) { + // Search next line start + while(*model->text_pos++ != '\n') + ; + } } }, true); } -static void text_box_process_up(TextBox* text_box) { +static void text_box_process_up(TextBox* text_box, uint8_t lines) { with_view_model( text_box->view, TextBoxModel * model, { - if(model->scroll_pos > 0) { - model->scroll_pos--; - // Reach last symbol of previous line - model->text_pos--; - // Search previous line start - while((model->text_pos != model->text) && (*(--model->text_pos) != '\n')) - ; - if(*model->text_pos == '\n') { - model->text_pos++; + if(model->scroll_pos > lines - 1) { + model->scroll_pos -= lines; + for(uint8_t i = 0; i < lines; i++) { + // Reach last symbol of previous line + model->text_pos--; + // Search previous line start + while((model->text_pos != model->text) && (*(--model->text_pos) != '\n')) + ; + if(*model->text_pos == '\n') { + model->text_pos++; + } } + } else if(lines > 1) { + lines = model->scroll_pos; + model->scroll_pos = 0; + model->text_pos = (char*)model->text; } }, true); @@ -120,14 +138,28 @@ static bool text_box_view_input_callback(InputEvent* event, void* context) { TextBox* text_box = context; bool consumed = false; - if(event->type == InputTypeShort) { + if(event->type == InputTypeShort || event->type == InputTypeRepeat) { + int32_t scroll_speed = 1; + if(text_box->button_held_for_ticks > 5) { + if(text_box->button_held_for_ticks % 2) { + scroll_speed = 0; + } else { + scroll_speed = text_box->button_held_for_ticks > 9 ? 5 : 3; + } + } + if(event->key == InputKeyDown) { - text_box_process_down(text_box); + text_box_process_down(text_box, scroll_speed); consumed = true; } else if(event->key == InputKeyUp) { - text_box_process_up(text_box); + text_box_process_up(text_box, scroll_speed); consumed = true; } + + text_box->button_held_for_ticks++; + } else if(event->type == InputTypeRelease) { + text_box->button_held_for_ticks = 0; + consumed = true; } return consumed; } diff --git a/applications/services/dialogs/view_holder.c b/applications/services/gui/view_holder.c similarity index 100% rename from applications/services/dialogs/view_holder.c rename to applications/services/gui/view_holder.c diff --git a/applications/services/dialogs/view_holder.h b/applications/services/gui/view_holder.h similarity index 100% rename from applications/services/dialogs/view_holder.h rename to applications/services/gui/view_holder.h diff --git a/applications/services/loader/loader.c b/applications/services/loader/loader.c index f385efdf95ae..ab7876a03661 100644 --- a/applications/services/loader/loader.c +++ b/applications/services/loader/loader.c @@ -1,20 +1,27 @@ #include "loader.h" #include "loader_i.h" -#include "loader_menu.h" #include +#include #include +#include +#include +#include +#include + #define TAG "Loader" #define LOADER_MAGIC_THREAD_VALUE 0xDEADBEEF // api -LoaderStatus loader_start(Loader* loader, const char* name, const char* args) { +LoaderStatus + loader_start(Loader* loader, const char* name, const char* args, FuriString* error_message) { LoaderMessage message; LoaderMessageLoaderStatusResult result; message.type = LoaderMessageTypeStartByName; message.start.name = name; message.start.args = args; + message.start.error_message = error_message; message.api_lock = api_lock_alloc_locked(); message.status_value = &result; furi_message_queue_put(loader->queue, &message, FuriWaitForever); @@ -22,6 +29,31 @@ LoaderStatus loader_start(Loader* loader, const char* name, const char* args) { return result.value; } +LoaderStatus loader_start_with_gui_error(Loader* loader, const char* name, const char* args) { + FuriString* error_message = furi_string_alloc(); + LoaderStatus status = loader_start(loader, name, args, error_message); + + // TODO: we have many places where we can emit a double start, ex: desktop, menu + // so i prefer to not show LoaderStatusErrorAppStarted error message for now + if(status == LoaderStatusErrorUnknownApp || status == LoaderStatusErrorInternal) { + DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS); + DialogMessage* message = dialog_message_alloc(); + dialog_message_set_header(message, "Error", 64, 0, AlignCenter, AlignTop); + dialog_message_set_buttons(message, NULL, NULL, NULL); + + furi_string_replace(error_message, ":", "\n"); + dialog_message_set_text( + message, furi_string_get_cstr(error_message), 64, 32, AlignCenter, AlignCenter); + + dialog_message_show(dialogs, message); + dialog_message_free(message); + furi_record_close(RECORD_DIALOGS); + } + + furi_string_free(error_message); + return status; +} + bool loader_lock(Loader* loader) { LoaderMessage message; LoaderMessageBoolResult result; @@ -73,27 +105,26 @@ static void loader_menu_closed_callback(void* context) { furi_message_queue_put(loader->queue, &message, FuriWaitForever); } -static void loader_menu_click_callback(const char* name, void* context) { +static void loader_applications_closed_callback(void* context) { Loader* loader = context; - loader_start(loader, name, NULL); + LoaderMessage message; + message.type = LoaderMessageTypeApplicationsClosed; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); } static void loader_thread_state_callback(FuriThreadState thread_state, void* context) { furi_assert(context); Loader* loader = context; - LoaderEvent event; if(thread_state == FuriThreadStateRunning) { + LoaderEvent event; event.type = LoaderEventTypeApplicationStarted; furi_pubsub_publish(loader->pubsub, &event); } else if(thread_state == FuriThreadStateStopped) { LoaderMessage message; message.type = LoaderMessageTypeAppClosed; furi_message_queue_put(loader->queue, &message, FuriWaitForever); - - event.type = LoaderEventTypeApplicationStopped; - furi_pubsub_publish(loader->pubsub, &event); } } @@ -104,16 +135,17 @@ static Loader* loader_alloc() { loader->pubsub = furi_pubsub_alloc(); loader->queue = furi_message_queue_alloc(1, sizeof(LoaderMessage)); loader->loader_menu = NULL; + loader->loader_applications = NULL; loader->app.args = NULL; - loader->app.name = NULL; loader->app.thread = NULL; loader->app.insomniac = false; + loader->app.fap = NULL; return loader; } -static FlipperApplication const* loader_find_application_by_name_in_list( +static FlipperInternalApplication const* loader_find_application_by_name_in_list( const char* name, - const FlipperApplication* list, + const FlipperInternalApplication* list, const uint32_t n_apps) { for(size_t i = 0; i < n_apps; i++) { if(strcmp(name, list[i].name) == 0) { @@ -123,8 +155,8 @@ static FlipperApplication const* loader_find_application_by_name_in_list( return NULL; } -static const FlipperApplication* loader_find_application_by_name(const char* name) { - const FlipperApplication* application = NULL; +static const FlipperInternalApplication* loader_find_application_by_name(const char* name) { + const FlipperInternalApplication* application = NULL; application = loader_find_application_by_name_in_list(name, FLIPPER_APPS, FLIPPER_APPS_COUNT); if(!application) { application = loader_find_application_by_name_in_list( @@ -138,25 +170,7 @@ static const FlipperApplication* loader_find_application_by_name(const char* nam return application; } -static void - loader_start_internal_app(Loader* loader, const FlipperApplication* app, const char* args) { - FURI_LOG_I(TAG, "Starting %s", app->name); - - // store args - furi_assert(loader->app.args == NULL); - if(args && strlen(args) > 0) { - loader->app.args = strdup(args); - } - - // store name - furi_assert(loader->app.name == NULL); - loader->app.name = strdup(app->name); - - // setup app thread - loader->app.thread = - furi_thread_alloc_ex(app->name, app->stack_size, app->app, loader->app.args); - furi_thread_set_appid(loader->app.thread, app->appid); - +static void loader_start_app_thread(Loader* loader, FlipperInternalApplicationFlag flags) { // setup heap trace FuriHalRtcHeapTrackMode mode = furi_hal_rtc_get_heap_track_mode(); if(mode > FuriHalRtcHeapTrackModeNone) { @@ -166,14 +180,14 @@ static void } // setup insomnia - if(!(app->flags & FlipperApplicationFlagInsomniaSafe)) { + if(!(flags & FlipperInternalApplicationFlagInsomniaSafe)) { furi_hal_power_insomnia_enter(); loader->app.insomniac = true; } else { loader->app.insomniac = false; } - // setup app thread callbacks + // setup thread state callbacks furi_thread_set_state_context(loader->app.thread, loader); furi_thread_set_state_callback(loader->app.thread, loader_thread_state_callback); @@ -181,42 +195,206 @@ static void furi_thread_start(loader->app.thread); } +static void loader_start_internal_app( + Loader* loader, + const FlipperInternalApplication* app, + const char* args) { + FURI_LOG_I(TAG, "Starting %s", app->name); + + // store args + furi_assert(loader->app.args == NULL); + if(args && strlen(args) > 0) { + loader->app.args = strdup(args); + } + + loader->app.thread = + furi_thread_alloc_ex(app->name, app->stack_size, app->app, loader->app.args); + furi_thread_set_appid(loader->app.thread, app->appid); + + loader_start_app_thread(loader, app->flags); +} + +static void loader_log_status_error( + LoaderStatus status, + FuriString* error_message, + const char* format, + va_list args) { + if(error_message) { + furi_string_vprintf(error_message, format, args); + FURI_LOG_E(TAG, "Status [%d]: %s", status, furi_string_get_cstr(error_message)); + } else { + FuriString* tmp = furi_string_alloc(); + FURI_LOG_E(TAG, "Status [%d]: %s", status, furi_string_get_cstr(tmp)); + furi_string_free(tmp); + } +} + +static LoaderStatus loader_make_status_error( + LoaderStatus status, + FuriString* error_message, + const char* format, + ...) { + va_list args; + va_start(args, format); + loader_log_status_error(status, error_message, format, args); + va_end(args); + return status; +} + +static LoaderStatus loader_make_success_status(FuriString* error_message) { + if(error_message) { + furi_string_set(error_message, "App started"); + } + + return LoaderStatusOk; +} + +static LoaderStatus loader_start_external_app( + Loader* loader, + Storage* storage, + const char* path, + const char* args, + FuriString* error_message) { + LoaderStatus status = loader_make_success_status(error_message); + + do { + loader->app.fap = flipper_application_alloc(storage, firmware_api_interface); + size_t start = furi_get_tick(); + + FURI_LOG_I(TAG, "Loading %s", path); + + FlipperApplicationPreloadStatus preload_res = + flipper_application_preload(loader->app.fap, path); + if(preload_res != FlipperApplicationPreloadStatusSuccess) { + const char* err_msg = flipper_application_preload_status_to_string(preload_res); + status = loader_make_status_error( + LoaderStatusErrorInternal, error_message, "Preload failed %s: %s", path, err_msg); + break; + } + + FURI_LOG_I(TAG, "Mapping"); + FlipperApplicationLoadStatus load_status = + flipper_application_map_to_memory(loader->app.fap); + if(load_status != FlipperApplicationLoadStatusSuccess) { + const char* err_msg = flipper_application_load_status_to_string(load_status); + status = loader_make_status_error( + LoaderStatusErrorInternal, error_message, "Load failed %s: %s", path, err_msg); + break; + } + + FURI_LOG_I(TAG, "Loaded in %zums", (size_t)(furi_get_tick() - start)); + FURI_LOG_I(TAG, "Starting app"); + + loader->app.thread = flipper_application_alloc_thread(loader->app.fap, args); + FuriString* app_name = furi_string_alloc(); + path_extract_filename_no_ext(path, app_name); + furi_thread_set_appid(loader->app.thread, furi_string_get_cstr(app_name)); + furi_string_free(app_name); + + /* This flag is set by the debugger - to break on app start */ + if(furi_hal_debug_is_gdb_session_active()) { + FURI_LOG_W(TAG, "Triggering BP for debugger"); + /* After hitting this, you can set breakpoints in your .fap's code + * Note that you have to toggle breakpoints that were set before */ + __asm volatile("bkpt 0"); + } + + loader_start_app_thread(loader, FlipperInternalApplicationFlagDefault); + } while(0); + + if(status != LoaderStatusOk) { + flipper_application_free(loader->app.fap); + loader->app.fap = NULL; + } + + return status; +} + // process messages static void loader_do_menu_show(Loader* loader) { if(!loader->loader_menu) { - loader->loader_menu = loader_menu_alloc(); - loader_menu_set_closed_callback(loader->loader_menu, loader_menu_closed_callback, loader); - loader_menu_set_click_callback(loader->loader_menu, loader_menu_click_callback, loader); - loader_menu_start(loader->loader_menu); + loader->loader_menu = loader_menu_alloc(loader_menu_closed_callback, loader); } } static void loader_do_menu_closed(Loader* loader) { if(loader->loader_menu) { - loader_menu_stop(loader->loader_menu); loader_menu_free(loader->loader_menu); loader->loader_menu = NULL; } } +static void loader_do_applications_show(Loader* loader) { + if(!loader->loader_applications) { + loader->loader_applications = + loader_applications_alloc(loader_applications_closed_callback, loader); + } +} + +static void loader_do_applications_closed(Loader* loader) { + if(loader->loader_applications) { + loader_applications_free(loader->loader_applications); + loader->loader_applications = NULL; + } +} + static bool loader_do_is_locked(Loader* loader) { return loader->app.thread != NULL; } -static LoaderStatus loader_do_start_by_name(Loader* loader, const char* name, const char* args) { - if(loader_do_is_locked(loader)) { - return LoaderStatusErrorAppStarted; - } +static LoaderStatus loader_do_start_by_name( + Loader* loader, + const char* name, + const char* args, + FuriString* error_message) { + LoaderStatus status; + do { + // check lock + if(loader_do_is_locked(loader)) { + const char* current_thread_name = + furi_thread_get_name(furi_thread_get_id(loader->app.thread)); + status = loader_make_status_error( + LoaderStatusErrorAppStarted, + error_message, + "Loader is locked, please close the \"%s\" first", + current_thread_name); + break; + } + + // check internal apps + { + const FlipperInternalApplication* app = loader_find_application_by_name(name); + if(app) { + loader_start_internal_app(loader, app, args); + status = loader_make_success_status(error_message); + break; + } + } - const FlipperApplication* app = loader_find_application_by_name(name); + // check Applications + if(strcmp(name, LOADER_APPLICATIONS_NAME) == 0) { + loader_do_applications_show(loader); + status = loader_make_success_status(error_message); + break; + } - if(!app) { - return LoaderStatusErrorUnknownApp; - } + // check external apps + { + Storage* storage = furi_record_open(RECORD_STORAGE); + if(storage_file_exists(storage, name)) { + status = loader_start_external_app(loader, storage, name, args, error_message); + furi_record_close(RECORD_STORAGE); + break; + } + furi_record_close(RECORD_STORAGE); + } - loader_start_internal_app(loader, app, args); - return LoaderStatusOk; + status = loader_make_status_error( + LoaderStatusErrorUnknownApp, error_message, "Application \"%s\" not found", name); + } while(false); + + return status; } static bool loader_do_lock(Loader* loader) { @@ -229,13 +407,16 @@ static bool loader_do_lock(Loader* loader) { } static void loader_do_unlock(Loader* loader) { - furi_assert(loader->app.thread == (FuriThread*)LOADER_MAGIC_THREAD_VALUE); + furi_check(loader->app.thread == (FuriThread*)LOADER_MAGIC_THREAD_VALUE); loader->app.thread = NULL; } static void loader_do_app_closed(Loader* loader) { furi_assert(loader->app.thread); - FURI_LOG_I(TAG, "Application stopped. Free heap: %zu", memmgr_get_free_heap()); + + furi_thread_join(loader->app.thread); + FURI_LOG_I(TAG, "App returned: %li", furi_thread_get_return_code(loader->app.thread)); + if(loader->app.args) { free(loader->app.args); loader->app.args = NULL; @@ -245,12 +426,20 @@ static void loader_do_app_closed(Loader* loader) { furi_hal_power_insomnia_exit(); } - free(loader->app.name); - loader->app.name = NULL; + if(loader->app.fap) { + flipper_application_free(loader->app.fap); + loader->app.fap = NULL; + loader->app.thread = NULL; + } else { + furi_thread_free(loader->app.thread); + loader->app.thread = NULL; + } - furi_thread_join(loader->app.thread); - furi_thread_free(loader->app.thread); - loader->app.thread = NULL; + FURI_LOG_I(TAG, "Application stopped. Free heap: %zu", memmgr_get_free_heap()); + + LoaderEvent event; + event.type = LoaderEventTypeApplicationStopped; + furi_pubsub_publish(loader->pubsub, &event); } // app @@ -266,7 +455,7 @@ int32_t loader_srv(void* p) { } if(FLIPPER_AUTORUN_APP_NAME && strlen(FLIPPER_AUTORUN_APP_NAME)) { - loader_do_start_by_name(loader, FLIPPER_AUTORUN_APP_NAME, NULL); + loader_do_start_by_name(loader, FLIPPER_AUTORUN_APP_NAME, NULL, NULL); } LoaderMessage message; @@ -274,8 +463,8 @@ int32_t loader_srv(void* p) { if(furi_message_queue_get(loader->queue, &message, FuriWaitForever) == FuriStatusOk) { switch(message.type) { case LoaderMessageTypeStartByName: - message.status_value->value = - loader_do_start_by_name(loader, message.start.name, message.start.args); + message.status_value->value = loader_do_start_by_name( + loader, message.start.name, message.start.args, message.start.error_message); api_lock_unlock(message.api_lock); break; case LoaderMessageTypeShowMenu: @@ -297,6 +486,10 @@ int32_t loader_srv(void* p) { break; case LoaderMessageTypeUnlock: loader_do_unlock(loader); + break; + case LoaderMessageTypeApplicationsClosed: + loader_do_applications_closed(loader); + break; } } } diff --git a/applications/services/loader/loader.h b/applications/services/loader/loader.h index e3a691b768c5..9fc4059f2d9e 100644 --- a/applications/services/loader/loader.h +++ b/applications/services/loader/loader.h @@ -6,6 +6,7 @@ extern "C" { #endif #define RECORD_LOADER "loader" +#define LOADER_APPLICATIONS_NAME "Applications" typedef struct Loader Loader; @@ -25,28 +26,57 @@ typedef struct { LoaderEventType type; } LoaderEvent; -/** Start application - * @param name - application name - * @param args - application arguments - * @retval true on success +/** + * @brief Start application + * @param[in] instance loader instance + * @param[in] name application name + * @param[in] args application arguments + * @param[out] error_message detailed error message, can be NULL + * @return LoaderStatus */ -LoaderStatus loader_start(Loader* instance, const char* name, const char* args); +LoaderStatus + loader_start(Loader* instance, const char* name, const char* args, FuriString* error_message); -/** Lock application start - * @retval true on success +/** + * @brief Start application with GUI error message + * @param[in] instance loader instance + * @param[in] name application name + * @param[in] args application arguments + * @return LoaderStatus + */ +LoaderStatus loader_start_with_gui_error(Loader* loader, const char* name, const char* args); + +/** + * @brief Lock application start + * @param[in] instance loader instance + * @return true on success */ bool loader_lock(Loader* instance); -/** Unlock application start */ +/** + * @brief Unlock application start + * @param[in] instance loader instance + */ void loader_unlock(Loader* instance); -/** Get loader lock status */ +/** + * @brief Check if loader is locked + * @param[in] instance loader instance + * @return true if locked + */ bool loader_is_locked(Loader* instance); -/** Show primary loader */ +/** + * @brief Show loader menu + * @param[in] instance loader instance + */ void loader_show_menu(Loader* instance); -/** Show primary loader */ +/** + * @brief Get loader pubsub + * @param[in] instance loader instance + * @return FuriPubSub* + */ FuriPubSub* loader_get_pubsub(Loader* instance); #ifdef __cplusplus diff --git a/applications/services/loader/loader_applications.c b/applications/services/loader/loader_applications.c new file mode 100644 index 000000000000..1801edef9f95 --- /dev/null +++ b/applications/services/loader/loader_applications.c @@ -0,0 +1,146 @@ +#include "loader.h" +#include "loader_applications.h" +#include +#include +#include +#include +#include +#include + +#define TAG "LoaderApplications" + +struct LoaderApplications { + FuriThread* thread; + void (*closed_cb)(void*); + void* context; +}; + +static int32_t loader_applications_thread(void* p); + +LoaderApplications* loader_applications_alloc(void (*closed_cb)(void*), void* context) { + LoaderApplications* loader_applications = malloc(sizeof(LoaderApplications)); + loader_applications->thread = + furi_thread_alloc_ex(TAG, 512, loader_applications_thread, (void*)loader_applications); + loader_applications->closed_cb = closed_cb; + loader_applications->context = context; + furi_thread_start(loader_applications->thread); + return loader_applications; +} + +void loader_applications_free(LoaderApplications* loader_applications) { + furi_assert(loader_applications); + furi_thread_join(loader_applications->thread); + furi_thread_free(loader_applications->thread); + free(loader_applications); +} + +typedef struct { + FuriString* fap_path; + DialogsApp* dialogs; + Storage* storage; +} LoaderApplicationsApp; + +static LoaderApplicationsApp* loader_applications_app_alloc() { + LoaderApplicationsApp* app = malloc(sizeof(LoaderApplicationsApp)); //-V799 + app->fap_path = furi_string_alloc_set(EXT_PATH("apps")); + app->dialogs = furi_record_open(RECORD_DIALOGS); + app->storage = furi_record_open(RECORD_STORAGE); + return app; +} //-V773 + +static void loader_applications_app_free(LoaderApplicationsApp* loader_applications_app) { + furi_assert(loader_applications_app); + furi_record_close(RECORD_DIALOGS); + furi_record_close(RECORD_STORAGE); + furi_string_free(loader_applications_app->fap_path); + free(loader_applications_app); +} + +static bool loader_applications_item_callback( + FuriString* path, + void* context, + uint8_t** icon_ptr, + FuriString* item_name) { + LoaderApplicationsApp* loader_applications_app = context; + furi_assert(loader_applications_app); + return flipper_application_load_name_and_icon( + path, loader_applications_app->storage, icon_ptr, item_name); +} + +static bool loader_applications_select_app(LoaderApplicationsApp* loader_applications_app) { + const DialogsFileBrowserOptions browser_options = { + .extension = ".fap", + .skip_assets = true, + .icon = &I_unknown_10px, + .hide_ext = true, + .item_loader_callback = loader_applications_item_callback, + .item_loader_context = loader_applications_app, + .base_path = EXT_PATH("apps"), + }; + + return dialog_file_browser_show( + loader_applications_app->dialogs, + loader_applications_app->fap_path, + loader_applications_app->fap_path, + &browser_options); +} + +#define APPLICATION_STOP_EVENT 1 + +static void loader_pubsub_callback(const void* message, void* context) { + const LoaderEvent* event = message; + const FuriThreadId thread_id = (FuriThreadId)context; + + if(event->type == LoaderEventTypeApplicationStopped) { + furi_thread_flags_set(thread_id, APPLICATION_STOP_EVENT); + } +} + +static void loader_applications_start_app(const char* name) { + // start loading animation + Gui* gui = furi_record_open(RECORD_GUI); + ViewHolder* view_holder = view_holder_alloc(); + Loading* loading = loading_alloc(); + + view_holder_attach_to_gui(view_holder, gui); + view_holder_set_view(view_holder, loading_get_view(loading)); + view_holder_start(view_holder); + + // load app + FuriThreadId thread_id = furi_thread_get_current_id(); + Loader* loader = furi_record_open(RECORD_LOADER); + FuriPubSubSubscription* subscription = + furi_pubsub_subscribe(loader_get_pubsub(loader), loader_pubsub_callback, thread_id); + + LoaderStatus status = loader_start_with_gui_error(loader, name, NULL); + + if(status == LoaderStatusOk) { + furi_thread_flags_wait(APPLICATION_STOP_EVENT, FuriFlagWaitAny, FuriWaitForever); + } + + furi_pubsub_unsubscribe(loader_get_pubsub(loader), subscription); + furi_record_close(RECORD_LOADER); + + // stop loading animation + view_holder_stop(view_holder); + view_holder_free(view_holder); + loading_free(loading); + furi_record_close(RECORD_GUI); +} + +static int32_t loader_applications_thread(void* p) { + LoaderApplications* loader_applications = p; + LoaderApplicationsApp* loader_applications_app = loader_applications_app_alloc(); + + while(loader_applications_select_app(loader_applications_app)) { + loader_applications_start_app(furi_string_get_cstr(loader_applications_app->fap_path)); + } + + loader_applications_app_free(loader_applications_app); + + if(loader_applications->closed_cb) { + loader_applications->closed_cb(loader_applications->context); + } + + return 0; +} \ No newline at end of file diff --git a/applications/services/loader/loader_applications.h b/applications/services/loader/loader_applications.h new file mode 100644 index 000000000000..6b132af0559f --- /dev/null +++ b/applications/services/loader/loader_applications.h @@ -0,0 +1,16 @@ +#pragma once +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct LoaderApplications LoaderApplications; + +LoaderApplications* loader_applications_alloc(void (*closed_cb)(void*), void* context); + +void loader_applications_free(LoaderApplications* loader_applications); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/applications/services/loader/loader_cli.c b/applications/services/loader/loader_cli.c index 2d4602215784..af3ebf9e002d 100644 --- a/applications/services/loader/loader_cli.c +++ b/applications/services/loader/loader_cli.c @@ -50,21 +50,11 @@ static void loader_cli_open(FuriString* args, Loader* loader) { const char* app_name_str = furi_string_get_cstr(app_name); - LoaderStatus status = loader_start(loader, app_name_str, args_str); - - switch(status) { - case LoaderStatusOk: - break; - case LoaderStatusErrorAppStarted: - printf("Can't start, application is running"); - break; - case LoaderStatusErrorUnknownApp: - printf("%s doesn't exists\r\n", app_name_str); - break; - case LoaderStatusErrorInternal: - printf("Internal error\r\n"); - break; + FuriString* error_message = furi_string_alloc(); + if(loader_start(loader, app_name_str, args_str, error_message) != LoaderStatusOk) { + printf("%s\r\n", furi_string_get_cstr(error_message)); } + furi_string_free(error_message); } while(false); furi_string_free(app_name); diff --git a/applications/services/loader/loader_i.h b/applications/services/loader/loader_i.h index 2e3f10dad02a..688b8fb665c6 100644 --- a/applications/services/loader/loader_i.h +++ b/applications/services/loader/loader_i.h @@ -1,20 +1,23 @@ #pragma once #include #include +#include #include "loader.h" #include "loader_menu.h" +#include "loader_applications.h" typedef struct { char* args; - char* name; FuriThread* thread; bool insomniac; + FlipperApplication* fap; } LoaderAppData; struct Loader { FuriPubSub* pubsub; FuriMessageQueue* queue; LoaderMenu* loader_menu; + LoaderApplications* loader_applications; LoaderAppData app; }; @@ -23,6 +26,7 @@ typedef enum { LoaderMessageTypeAppClosed, LoaderMessageTypeShowMenu, LoaderMessageTypeMenuClosed, + LoaderMessageTypeApplicationsClosed, LoaderMessageTypeLock, LoaderMessageTypeUnlock, LoaderMessageTypeIsLocked, @@ -31,6 +35,7 @@ typedef enum { typedef struct { const char* name; const char* args; + FuriString* error_message; } LoaderMessageStartByName; typedef struct { diff --git a/applications/services/loader/loader_menu.c b/applications/services/loader/loader_menu.c index ec853661fbbf..28283f85cd20 100644 --- a/applications/services/loader/loader_menu.c +++ b/applications/services/loader/loader_menu.c @@ -5,106 +5,76 @@ #include #include +#include "loader.h" #include "loader_menu.h" #define TAG "LoaderMenu" struct LoaderMenu { - Gui* gui; - ViewDispatcher* view_dispatcher; - Menu* primary_menu; - Submenu* settings_menu; - - void (*closed_callback)(void*); - void* closed_callback_context; - - void (*click_callback)(const char*, void*); - void* click_callback_context; - FuriThread* thread; + void (*closed_cb)(void*); + void* context; }; -typedef enum { - LoaderMenuViewPrimary, - LoaderMenuViewSettings, -} LoaderMenuView; - static int32_t loader_menu_thread(void* p); -LoaderMenu* loader_menu_alloc() { +LoaderMenu* loader_menu_alloc(void (*closed_cb)(void*), void* context) { LoaderMenu* loader_menu = malloc(sizeof(LoaderMenu)); - loader_menu->gui = furi_record_open(RECORD_GUI); - loader_menu->view_dispatcher = view_dispatcher_alloc(); - loader_menu->primary_menu = menu_alloc(); - loader_menu->settings_menu = submenu_alloc(); - loader_menu->thread = NULL; - return loader_menu; -} - -void loader_menu_free(LoaderMenu* loader_menu) { - furi_assert(loader_menu); - // check if thread is running - furi_assert(!loader_menu->thread); - - submenu_free(loader_menu->settings_menu); - menu_free(loader_menu->primary_menu); - view_dispatcher_free(loader_menu->view_dispatcher); - furi_record_close(RECORD_GUI); - free(loader_menu); -} - -void loader_menu_start(LoaderMenu* loader_menu) { - furi_assert(loader_menu); - furi_assert(!loader_menu->thread); + loader_menu->closed_cb = closed_cb; + loader_menu->context = context; loader_menu->thread = furi_thread_alloc_ex(TAG, 1024, loader_menu_thread, loader_menu); furi_thread_start(loader_menu->thread); + return loader_menu; } -void loader_menu_stop(LoaderMenu* loader_menu) { +void loader_menu_free(LoaderMenu* loader_menu) { furi_assert(loader_menu); - furi_assert(loader_menu->thread); - view_dispatcher_stop(loader_menu->view_dispatcher); furi_thread_join(loader_menu->thread); furi_thread_free(loader_menu->thread); - loader_menu->thread = NULL; + free(loader_menu); } -void loader_menu_set_closed_callback( - LoaderMenu* loader_menu, - void (*callback)(void*), - void* context) { - loader_menu->closed_callback = callback; - loader_menu->closed_callback_context = context; -} +typedef enum { + LoaderMenuViewPrimary, + LoaderMenuViewSettings, +} LoaderMenuView; + +typedef struct { + Gui* gui; + ViewDispatcher* view_dispatcher; + Menu* primary_menu; + Submenu* settings_menu; +} LoaderMenuApp; -void loader_menu_set_click_callback( - LoaderMenu* loader_menu, - void (*callback)(const char*, void*), - void* context) { - loader_menu->click_callback = callback; - loader_menu->click_callback_context = context; +static void loader_menu_start(const char* name) { + Loader* loader = furi_record_open(RECORD_LOADER); + loader_start_with_gui_error(loader, name, NULL); + furi_record_close(RECORD_LOADER); } static void loader_menu_callback(void* context, uint32_t index) { - LoaderMenu* loader_menu = context; + UNUSED(context); const char* name = FLIPPER_APPS[index].name; - if(loader_menu->click_callback) { - loader_menu->click_callback(name, loader_menu->click_callback_context); - } + loader_menu_start(name); +} + +static void loader_menu_applications_callback(void* context, uint32_t index) { + UNUSED(index); + UNUSED(context); + const char* name = LOADER_APPLICATIONS_NAME; + loader_menu_start(name); } static void loader_menu_settings_menu_callback(void* context, uint32_t index) { - LoaderMenu* loader_menu = context; + UNUSED(context); const char* name = FLIPPER_SETTINGS_APPS[index].name; - if(loader_menu->click_callback) { - loader_menu->click_callback(name, loader_menu->click_callback_context); - } + loader_menu_start(name); } static void loader_menu_switch_to_settings(void* context, uint32_t index) { UNUSED(index); - LoaderMenu* loader_menu = context; - view_dispatcher_switch_to_view(loader_menu->view_dispatcher, LoaderMenuViewSettings); + LoaderMenuApp* app = context; + view_dispatcher_switch_to_view(app->view_dispatcher, LoaderMenuViewSettings); } static uint32_t loader_menu_switch_to_primary(void* context) { @@ -117,30 +87,32 @@ static uint32_t loader_menu_exit(void* context) { return VIEW_NONE; } -static void loader_menu_build_menu(LoaderMenu* loader_menu) { +static void loader_menu_build_menu(LoaderMenuApp* app, LoaderMenu* menu) { size_t i; for(i = 0; i < FLIPPER_APPS_COUNT; i++) { menu_add_item( - loader_menu->primary_menu, + app->primary_menu, FLIPPER_APPS[i].name, FLIPPER_APPS[i].icon, i, loader_menu_callback, - (void*)loader_menu); + (void*)menu); } menu_add_item( - loader_menu->primary_menu, - "Settings", - &A_Settings_14, + app->primary_menu, "Settings", &A_Settings_14, i++, loader_menu_switch_to_settings, app); + menu_add_item( + app->primary_menu, + LOADER_APPLICATIONS_NAME, + &A_Plugins_14, i++, - loader_menu_switch_to_settings, - loader_menu); + loader_menu_applications_callback, + (void*)menu); }; -static void loader_menu_build_submenu(LoaderMenu* loader_menu) { +static void loader_menu_build_submenu(LoaderMenuApp* app, LoaderMenu* loader_menu) { for(size_t i = 0; i < FLIPPER_SETTINGS_APPS_COUNT; i++) { submenu_add_item( - loader_menu->settings_menu, + app->settings_menu, FLIPPER_SETTINGS_APPS[i].name, i, loader_menu_settings_menu_callback, @@ -148,40 +120,59 @@ static void loader_menu_build_submenu(LoaderMenu* loader_menu) { } } -static int32_t loader_menu_thread(void* p) { - LoaderMenu* loader_menu = p; - furi_assert(loader_menu); - - loader_menu_build_menu(loader_menu); - loader_menu_build_submenu(loader_menu); +static LoaderMenuApp* loader_menu_app_alloc(LoaderMenu* loader_menu) { + LoaderMenuApp* app = malloc(sizeof(LoaderMenuApp)); + app->gui = furi_record_open(RECORD_GUI); + app->view_dispatcher = view_dispatcher_alloc(); + app->primary_menu = menu_alloc(); + app->settings_menu = submenu_alloc(); - view_dispatcher_attach_to_gui( - loader_menu->view_dispatcher, loader_menu->gui, ViewDispatcherTypeFullscreen); + loader_menu_build_menu(app, loader_menu); + loader_menu_build_submenu(app, loader_menu); // Primary menu - View* primary_view = menu_get_view(loader_menu->primary_menu); - view_set_context(primary_view, loader_menu->primary_menu); + View* primary_view = menu_get_view(app->primary_menu); + view_set_context(primary_view, app->primary_menu); view_set_previous_callback(primary_view, loader_menu_exit); - view_dispatcher_add_view(loader_menu->view_dispatcher, LoaderMenuViewPrimary, primary_view); + view_dispatcher_add_view(app->view_dispatcher, LoaderMenuViewPrimary, primary_view); // Settings menu - View* settings_view = submenu_get_view(loader_menu->settings_menu); - view_set_context(settings_view, loader_menu->settings_menu); + View* settings_view = submenu_get_view(app->settings_menu); + view_set_context(settings_view, app->settings_menu); view_set_previous_callback(settings_view, loader_menu_switch_to_primary); - view_dispatcher_add_view(loader_menu->view_dispatcher, LoaderMenuViewSettings, settings_view); + view_dispatcher_add_view(app->view_dispatcher, LoaderMenuViewSettings, settings_view); - view_dispatcher_enable_queue(loader_menu->view_dispatcher); - view_dispatcher_switch_to_view(loader_menu->view_dispatcher, LoaderMenuViewPrimary); + view_dispatcher_enable_queue(app->view_dispatcher); + view_dispatcher_switch_to_view(app->view_dispatcher, LoaderMenuViewPrimary); - // run view dispatcher - view_dispatcher_run(loader_menu->view_dispatcher); + return app; +} + +static void loader_menu_app_free(LoaderMenuApp* app) { + view_dispatcher_remove_view(app->view_dispatcher, LoaderMenuViewPrimary); + view_dispatcher_remove_view(app->view_dispatcher, LoaderMenuViewSettings); + view_dispatcher_free(app->view_dispatcher); - view_dispatcher_remove_view(loader_menu->view_dispatcher, LoaderMenuViewPrimary); - view_dispatcher_remove_view(loader_menu->view_dispatcher, LoaderMenuViewSettings); + menu_free(app->primary_menu); + submenu_free(app->settings_menu); + furi_record_close(RECORD_GUI); + free(app); +} - if(loader_menu->closed_callback) { - loader_menu->closed_callback(loader_menu->closed_callback_context); +static int32_t loader_menu_thread(void* p) { + LoaderMenu* loader_menu = p; + furi_assert(loader_menu); + + LoaderMenuApp* app = loader_menu_app_alloc(loader_menu); + + view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); + view_dispatcher_run(app->view_dispatcher); + + if(loader_menu->closed_cb) { + loader_menu->closed_cb(loader_menu->context); } + loader_menu_app_free(app); + return 0; } \ No newline at end of file diff --git a/applications/services/loader/loader_menu.h b/applications/services/loader/loader_menu.h index 7405b87be772..528fe7d291c2 100644 --- a/applications/services/loader/loader_menu.h +++ b/applications/services/loader/loader_menu.h @@ -7,24 +7,10 @@ extern "C" { typedef struct LoaderMenu LoaderMenu; -LoaderMenu* loader_menu_alloc(); +LoaderMenu* loader_menu_alloc(void (*closed_cb)(void*), void* context); void loader_menu_free(LoaderMenu* loader_menu); -void loader_menu_start(LoaderMenu* loader_menu); - -void loader_menu_stop(LoaderMenu* loader_menu); - -void loader_menu_set_closed_callback( - LoaderMenu* loader_menu, - void (*callback)(void*), - void* context); - -void loader_menu_set_click_callback( - LoaderMenu* loader_menu, - void (*callback)(const char*, void*), - void* context); - #ifdef __cplusplus } #endif \ No newline at end of file diff --git a/applications/services/rpc/rpc_app.c b/applications/services/rpc/rpc_app.c index cc18b6cec37f..bf44ed2deed0 100644 --- a/applications/services/rpc/rpc_app.c +++ b/applications/services/rpc/rpc_app.c @@ -52,7 +52,7 @@ static void rpc_system_app_start_process(const PB_Main* request, void* context) snprintf(args_temp, RPC_SYSTEM_APP_TEMP_ARGS_SIZE, "RPC %08lX", (uint32_t)rpc_app); app_args = args_temp; } - LoaderStatus status = loader_start(loader, app_name, app_args); + LoaderStatus status = loader_start(loader, app_name, app_args, NULL); if(status == LoaderStatusErrorAppStarted) { result = PB_CommandStatus_ERROR_APP_SYSTEM_LOCKED; } else if(status == LoaderStatusErrorInternal) { diff --git a/applications/settings/desktop_settings/scenes/desktop_settings_scene_favorite.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_favorite.c index 4b5c47921239..698cfae1b814 100644 --- a/applications/settings/desktop_settings/scenes/desktop_settings_scene_favorite.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_favorite.c @@ -3,7 +3,6 @@ #include "desktop_settings_scene.h" #include #include -#include #define EXTERNAL_APPLICATION_NAME ("[External Application]") #define EXTERNAL_APPLICATION_INDEX (FLIPPER_APPS_COUNT + 1) @@ -65,7 +64,6 @@ void desktop_settings_scene_favorite_on_enter(void* context) { } } -#ifdef APP_FAP_LOADER submenu_add_item( submenu, EXTERNAL_APPLICATION_NAME, @@ -75,7 +73,6 @@ void desktop_settings_scene_favorite_on_enter(void* context) { if(curr_favorite_app->is_external) { pre_select_item = EXTERNAL_APPLICATION_INDEX; } -#endif submenu_set_header( submenu, primary_favorite ? "Primary favorite app:" : "Secondary favorite app:"); diff --git a/applications/system/storage_move_to_sd/storage_move_to_sd.c b/applications/system/storage_move_to_sd/storage_move_to_sd.c index 9c91b9266809..25893f011061 100644 --- a/applications/system/storage_move_to_sd/storage_move_to_sd.c +++ b/applications/system/storage_move_to_sd/storage_move_to_sd.c @@ -172,7 +172,7 @@ static void storage_move_to_sd_mount_callback(const void* message, void* context if(storage_event->type == StorageEventTypeCardMount) { Loader* loader = furi_record_open(RECORD_LOADER); - loader_start(loader, "StorageMoveToSd", NULL); + loader_start(loader, "StorageMoveToSd", NULL, NULL); furi_record_close(RECORD_LOADER); } } diff --git a/applications/system/updater/cli/updater_cli.c b/applications/system/updater/cli/updater_cli.c index 659c431f7017..cebdc4d7cab6 100644 --- a/applications/system/updater/cli/updater_cli.c +++ b/applications/system/updater/cli/updater_cli.c @@ -99,7 +99,7 @@ static void updater_start_app(void* context, uint32_t arg) { * So, accessing its record would cause a deadlock */ Loader* loader = furi_record_open(RECORD_LOADER); - loader_start(loader, "UpdaterApp", NULL); + loader_start(loader, "UpdaterApp", NULL, NULL); furi_record_close(RECORD_LOADER); } diff --git a/assets/icons/SubGhz/External_antenna_20x12.png b/assets/icons/SubGhz/External_antenna_20x12.png new file mode 100644 index 0000000000000000000000000000000000000000..940087071a1c4225eb48383e3a93d5c841b638b2 GIT binary patch literal 990 zcmaJ=zi-n(6t>hBswf?bK&VV7S4dPe_W6LTf33i9am!vER3maae$(r__=1^b4 zsgIQSAx8^Bc`FIA(@%PtnBJf;Yd{MNa9h#))?T#XHFxqc8qrRiM;?^@z zPBc#76NW+J9|f_N=;D}H<9ceAMKE?@eOlf;6R|p#qpZB99ok9j$KdOycpAF7_A;HCY}E2GSre(Womcs;Z_O2<5m( zE*=I9C%GVApE6h^b|Noi9t}Xsh}-mp=_1eex(q*@(FXCPRlI3(fiaYAnAOQmzW*eS8^e&ubrRE)$l=55tf!$u&5Q_UG-^vCn{I?3^2ip6yqCn?iKq|8Rcqe-T+F$A6RbNw7i%t7=E=zEZ2y|| z)WjDkRcG7F53~Iz0blxvZ}*$#HV%6gRB|C29u*3tc$5LZVXRk4r*o6H_^HN`vYuq=9C{u`i9)p3m49;&em^ zfspzyAO@HKu~vL^r4xb$0YYMBKrk{Og>$~j5U^~&cTey4d%t)0?p}HA(oAAD!ExM7 zX~n28dy0M2Qt%PmE|Wp5!0>S)vTH2%kneIB@u#&2Xy$@B}T>8|VqXnkj`YVT~> zio-8m1i46M1Q<~ZM0nc^)kx!eyejkKu*id63fx1^uoCzgMmUjaDD0$55$aCowTUNGqwFTus@>p!ogOtO%o%_7iB?; z+ZraC=KoVM9%YBLf)4eLB@U|{ABhzdl2%}|!)wgNrF^vzAd8ZqO33zbC(BJjN!TPl zfN3EE&Y70&dU0gF2Qf{x!{g6=6pJ%>k=%aWVu+>mBp+A^G06Q z^$b+9L##pU7DgT&Vx2>5{-4-*BCyXY8z^vZB4;@u81%YU-7#A7c|9c+78S+^$7|_h zoiSPl*tn1JSdobl)>*yJ)S*p|h?~Q6$-f1d>2NNH}5%Lt|z{KrzQc(y-YyStJQ+g^C9Q zSWv-YttjHfh@wyt@GLFhMTjB}M;LSv6%;{^;@J%X_DAW??0&~Q&+|U-`@P@n?x@Hx zJ8Nfa0)b%14d?LjF%^HQmS*_Zy;Prz4^CJ}G`0p!z*2-Nm=GjEMKHicgo!X87D}`~ zG{XJ_!fZF0AR3G2MKHxELKK=XL=B?E*#v@rphhVa%V7)_o@3{?OoMWF~y##kV3^-~Ura#~iQo~#pIF_K28B$0`bDW@qQkN5vj1er#wF+Tj+ z?|%xb1zIIc;=^h*StZ6#E@7!Dl#l0+R;G}k zDeC1D1RjscRj4tcLJV^`ED)C<%48Czw=bJb<4}SjatMt~4q?;jbe~|z8=_EsXfzI; zGR5Vf;$#F?U{hSlXD)k2uBjOiB_5drt7MyCNvH}%fQg)$vYEXwX4ISHN@n&FG$WUU zn<1G__FpGGwS~8jX*%7w_+q;CVFljrD!j4V;}c)t_r;dW2@+`9`eU1O>Hy1H=Z_x? z#)vXQ4`HsunYK6jxY4-M*|zlR`rg;$+V*St8!R`}`J(H(M(Fn4S4n;$pnW-UN$QA` z?fY?KM*pGHedF?8-QC`CtG>sHp2-iZetB?^`cj>4f5g#9o;N06J$3^rWaoX6Zp!iN6AS8ml(v%micb;q2O2KuEfM&;;GfOLnbEbQ;Xh2MB~uUb$O z=Tf34Z;Mngv^s8}xvK?|Q)X5xaeMf&yLz=D);7(;s_;xKaAkeDy_0K?%Yn2|k9C6T z^kdg4x7}!2l%F~e-2N&yKK{I*<bm{PN1M%~EqIS+ z#{g%nih7mt;>v=&E{mA(e4W(c;<>|5`bM6gWBHY@vRSt9LE+^Uhns6zS!2UzZw(cU zoUfWE)n;PLGTwze=xNtR#E5s54 z?u4@P3{ljfm#4cr?==i}&Q~nx+6o_SALMl>7g+8+b*EGr+g0b>QusCdoqSG@XTkT} zJKW>*p7M7!ScsC+I$SWe`PeH**g7LKd+2^e4BT{9(i5Fx*_t#~^L&3q*^<`Bg8SLL zJr^&8Wvz+nlWyNPFyz7qEt>zJmbmY7f19~I|Kz}R|I(kU_SSdG*|X+`TiP_=YR)O9 z%>w2`t#*GaxqGd${KiVYrAK$bi$_|DyT^Fr>F$>+;8w9Tw&Z$d+!FWSfdT)vdK%bz zZxc14Zjp1X%kW^EaVRy?Y1r_3XHB46)J>z~?!08J+0&8}hNJx?^62efuWTu{t@zFL zVZ4jin2pbcGJ}2f!HjR`wC}%p=#A$7DVOR4RjdwPz~ZWrAMHE3V&KiltB9(rl{Yu) zpLzA}yq2xqYW6IxKLj-^F^5Q^3s;lX5 N!3~Mzlm%~0{|8*@s)qmo diff --git a/assets/icons/SubGhz/Scanning_short_96x52.png b/assets/icons/SubGhz/Scanning_short_96x52.png new file mode 100644 index 0000000000000000000000000000000000000000..718d0e695a2560bbb7ccd538c062375d2a318ffb GIT binary patch literal 1388 zcmeAS@N?(olHy`uVBq!ia0vp^2|#SZ!3-pwBG0}CQj#UE5hcO-X(i=}MX3yqDfvmM z3ZA)%>8U}fi7AzZCsS=07??FPLn2Bde0{8v^KOF1ees}+T7#dW-K+~^CEYLU9GXQxDrqI_HztY@Xxa#7Ppj3o=u^L<) zQdy9yACy|0Us{w5jJz~ukW~d%&PAz-CHX}m`T04pkPOJkFUc>?$S+VZGSM?t(C|%6 z&ddXeXo9u)`dWGB6_+IDC8v72*eU@H(aX$Cv2rvwbTM{yvotVrF*h`Hb+t5ib#ZZZ zGBYr7HZyQ^c7^G6$xklLP0cHT=}kfCb;PL`lp=BqfHu3N7G;*DrnnX5=PH1GZIy}J zE#^4QgX&Ge?G_81di8;h(FesXQe4A?fC&i1gr{C02cG^@^MHxI2$;HE)=X;#<_xv~ zpAgso|NjG-p@%NlF)%P5_jGX#skrrK#_ef`6*ydP{{Me@b6A>-Lx{=S+e`Fw7pH3% zdAs~uznOdQKDGRP;?HGHaQkgH+0OUlYP}u%=DQ!xddxlW<9jtjncLh35yqCy>x5P@ z99nmph1Eg!gFqI;m$L2IZAmtkId|qVUWuQv{-flTsXLiZSp3i5+YxWBeR>{4#?3=K zQI)4O879AZQ!=f=OphVwlFMhA6*GHUS2Jun{nDgi4&yF~hwUt~FTby;Ok>#fvsCFC zgLT90@}S8k5r-}+1~*7Jtl;ZBy)z@GLQshF(2R*k^si5`SIfI4o-plV-QgL*9Sk=a zbl8*MN4oOyJ#{*I*J09={JmL|?tkbM6X($R#JRC=Vu_J%Y75Vf{xaL$l#n(7>J9Z>Rsez4>?m+v^4&(=dnl-7VtQ3hUR|<$h?CUGgiufh#fR z%(}0KHCtpPcD3>gZd$&^{MVzu8kg;Bj?5L<)Uo%9dbPy-BY$?*-Bo?}_2;U(sTYb~ z&aKl-jNh-QDG;}};pXvkx4&CUAG$r=-JXeuLGKE4-|ks^mx9VaPgg&ebxsLQ09S_o Aa{vGU literal 0 HcmV?d00001 diff --git a/assets/resources/badusb/assets/layouts/fr-FR-mac.kl b/assets/resources/badusb/assets/layouts/fr-FR-mac.kl index 0906936547cd3c8accd9632bac82cb4193a24c25..2887aae0fda061fe85930922db12ab03126a5002 100644 GIT binary patch delta 43 ycmZo*YG9h+#+WkE-H_9i!Ggh*Nq{M3Vxt)=n>m{<+r&NAoGkoox-5b$3=9C%s0beb delta 43 ycmZo*YG9h+#%Max-HStackType == INFO_STACK_TYPE_BLE_LIGHT) { if(info->VersionMajor >= FURI_HAL_BT_STACK_VERSION_MAJOR && info->VersionMinor >= FURI_HAL_BT_STACK_VERSION_MINOR) { - furi_hal_bt_stack = FuriHalBtStackLight; + furi_hal_bt.stack = FuriHalBtStackLight; supported = true; } } else if(info->StackType == INFO_STACK_TYPE_BLE_FULL) { if(info->VersionMajor >= FURI_HAL_BT_STACK_VERSION_MAJOR && info->VersionMinor >= FURI_HAL_BT_STACK_VERSION_MINOR) { - furi_hal_bt_stack = FuriHalBtStackFull; + furi_hal_bt.stack = FuriHalBtStackFull; supported = true; } } else { - furi_hal_bt_stack = FuriHalBtStackUnknown; + furi_hal_bt.stack = FuriHalBtStackUnknown; } return supported; } bool furi_hal_bt_start_radio_stack() { bool res = false; - furi_assert(furi_hal_bt_core2_mtx); + furi_assert(furi_hal_bt.core2_mtx); - furi_mutex_acquire(furi_hal_bt_core2_mtx, FuriWaitForever); + furi_mutex_acquire(furi_hal_bt.core2_mtx, FuriWaitForever); // Explicitly tell that we are in charge of CLK48 domain furi_check(LL_HSEM_1StepLock(HSEM, CFG_HW_CLK48_CONFIG_SEMID) == 0); @@ -166,17 +188,17 @@ bool furi_hal_bt_start_radio_stack() { } res = true; } while(false); - furi_mutex_release(furi_hal_bt_core2_mtx); + furi_mutex_release(furi_hal_bt.core2_mtx); return res; } FuriHalBtStack furi_hal_bt_get_radio_stack() { - return furi_hal_bt_stack; + return furi_hal_bt.stack; } bool furi_hal_bt_is_ble_gatt_gap_supported() { - if(furi_hal_bt_stack == FuriHalBtStackLight || furi_hal_bt_stack == FuriHalBtStackFull) { + if(furi_hal_bt.stack == FuriHalBtStackLight || furi_hal_bt.stack == FuriHalBtStackFull) { return true; } else { return false; @@ -184,7 +206,7 @@ bool furi_hal_bt_is_ble_gatt_gap_supported() { } bool furi_hal_bt_is_testing_supported() { - if(furi_hal_bt_stack == FuriHalBtStackFull) { + if(furi_hal_bt.stack == FuriHalBtStackFull) { return true; } else { return false; diff --git a/firmware/targets/f7/furi_hal/furi_hal_nfc.c b/firmware/targets/f7/furi_hal/furi_hal_nfc.c index bd621c2db7d7..ffda124a4078 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_nfc.c +++ b/firmware/targets/f7/furi_hal/furi_hal_nfc.c @@ -819,3 +819,17 @@ FuriHalNfcReturn furi_hal_nfc_ll_txrx_bits( void furi_hal_nfc_ll_poll() { rfalWorker(); } + +void furi_hal_nfc_field_detect_start() { + st25r3916WriteRegister( + ST25R3916_REG_OP_CONTROL, + ST25R3916_REG_OP_CONTROL_en | ST25R3916_REG_OP_CONTROL_en_fd_mask); + st25r3916WriteRegister(ST25R3916_REG_MODE, ST25R3916_REG_MODE_targ | ST25R3916_REG_MODE_om0); +} + +bool furi_hal_nfc_field_is_present() { + return st25r3916CheckReg( + ST25R3916_REG_AUX_DISPLAY, + ST25R3916_REG_AUX_DISPLAY_efd_o, + ST25R3916_REG_AUX_DISPLAY_efd_o); +} \ No newline at end of file diff --git a/firmware/targets/f7/furi_hal/furi_hal_nfc.h b/firmware/targets/f7/furi_hal/furi_hal_nfc.h index 81d2bae484f3..c106f70a05c4 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_nfc.h +++ b/firmware/targets/f7/furi_hal/furi_hal_nfc.h @@ -423,6 +423,10 @@ FuriHalNfcReturn furi_hal_nfc_ll_txrx_bits( void furi_hal_nfc_ll_poll(); +void furi_hal_nfc_field_detect_start(); + +bool furi_hal_nfc_field_is_present(); + #ifdef __cplusplus } #endif diff --git a/firmware/targets/f7/furi_hal/furi_hal_pwm.c b/firmware/targets/f7/furi_hal/furi_hal_pwm.c index 7e985cbb11b6..879460e6bd54 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_pwm.c +++ b/firmware/targets/f7/furi_hal/furi_hal_pwm.c @@ -82,6 +82,15 @@ void furi_hal_pwm_stop(FuriHalPwmOutputId channel) { } } +bool furi_hal_pwm_is_running(FuriHalPwmOutputId channel) { + if(channel == FuriHalPwmOutputIdTim1PA7) { + return furi_hal_bus_is_enabled(FuriHalBusTIM1); + } else if(channel == FuriHalPwmOutputIdLptim2PA4) { + return furi_hal_bus_is_enabled(FuriHalBusLPTIM2); + } + return false; +} + void furi_hal_pwm_set_params(FuriHalPwmOutputId channel, uint32_t freq, uint8_t duty) { furi_assert(freq > 0); uint32_t freq_div = 64000000LU / freq; diff --git a/firmware/targets/f7/furi_hal/furi_hal_pwm.h b/firmware/targets/f7/furi_hal/furi_hal_pwm.h index a8682c5fbb16..16acca05efe5 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_pwm.h +++ b/firmware/targets/f7/furi_hal/furi_hal_pwm.h @@ -9,6 +9,7 @@ extern "C" { #endif #include +#include typedef enum { FuriHalPwmOutputIdTim1PA7, @@ -37,6 +38,13 @@ void furi_hal_pwm_stop(FuriHalPwmOutputId channel); */ void furi_hal_pwm_set_params(FuriHalPwmOutputId channel, uint32_t freq, uint8_t duty); +/** Is PWM channel running? + * + * @param[in] channel PWM channel (FuriHalPwmOutputId) + * @return bool - true if running +*/ +bool furi_hal_pwm_is_running(FuriHalPwmOutputId channel); + #ifdef __cplusplus } #endif diff --git a/firmware/targets/f7/furi_hal/furi_hal_rfid.c b/firmware/targets/f7/furi_hal/furi_hal_rfid.c index fa0c19b098b8..67f11d6ff7bc 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_rfid.c +++ b/firmware/targets/f7/furi_hal/furi_hal_rfid.c @@ -25,6 +25,19 @@ #define RFID_CAPTURE_IND_CH LL_TIM_CHANNEL_CH3 #define RFID_CAPTURE_DIR_CH LL_TIM_CHANNEL_CH4 +// Field presence detection +#define FURI_HAL_RFID_FIELD_FREQUENCY_MIN 80000 +#define FURI_HAL_RFID_FIELD_FREQUENCY_MAX 200000 + +#define FURI_HAL_RFID_FIELD_COUNTER_TIMER TIM2 +#define FURI_HAL_RFID_FIELD_COUNTER_TIMER_BUS FuriHalBusTIM2 +#define FURI_HAL_RFID_FIELD_COUNTER_TIMER_CHANNEL LL_TIM_CHANNEL_CH3 + +#define FURI_HAL_RFID_FIELD_TIMEOUT_TIMER TIM1 +#define FURI_HAL_RFID_FIELD_TIMEOUT_TIMER_BUS FuriHalBusTIM1 + +#define FURI_HAL_RFID_FIELD_DMAMUX_DMA LL_DMAMUX_REQ_TIM1_UP + /* DMA Channels definition */ #define RFID_DMA DMA2 #define RFID_DMA_CH1_CHANNEL LL_DMA_CHANNEL_1 @@ -33,10 +46,16 @@ #define RFID_DMA_CH1_DEF RFID_DMA, RFID_DMA_CH1_CHANNEL #define RFID_DMA_CH2_DEF RFID_DMA, RFID_DMA_CH2_CHANNEL +typedef struct { + uint32_t counter; + uint32_t set_tim_counter_cnt; +} FuriHalRfidField; + typedef struct { FuriHalRfidDMACallback dma_callback; FuriHalRfidReadCaptureCallback read_capture_callback; void* context; + FuriHalRfidField field; } FuriHalRfid; FuriHalRfid* furi_hal_rfid = NULL; @@ -51,6 +70,8 @@ FuriHalRfid* furi_hal_rfid = NULL; void furi_hal_rfid_init() { furi_assert(furi_hal_rfid == NULL); furi_hal_rfid = malloc(sizeof(FuriHalRfid)); + furi_hal_rfid->field.counter = 0; + furi_hal_rfid->field.set_tim_counter_cnt = 0; furi_hal_rfid_pins_reset(); @@ -133,6 +154,23 @@ static void furi_hal_rfid_pins_read() { furi_hal_gpio_init(&gpio_rfid_data_in, GpioModeAnalog, GpioPullNo, GpioSpeedLow); } +static void furi_hal_rfid_pins_field() { + // ibutton low + furi_hal_ibutton_pin_configure(); + furi_hal_ibutton_pin_write(false); + + // pull pin to timer out + furi_hal_gpio_init(&gpio_nfc_irq_rfid_pull, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_write(&gpio_nfc_irq_rfid_pull, false); + + // pull rfid antenna from carrier side + furi_hal_gpio_init(&gpio_rfid_carrier_out, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_write(&gpio_rfid_carrier_out, false); + + furi_hal_gpio_init_ex( + &gpio_rfid_carrier, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedLow, GpioAltFn2TIM2); +} + void furi_hal_rfid_pin_pull_release() { furi_hal_gpio_write(&gpio_nfc_irq_rfid_pull, true); } @@ -427,3 +465,124 @@ void COMP_IRQHandler() { furi_hal_rfid_comp_callback_context); } } + +static void furi_hal_rfid_field_tim_setup() { + // setup timer counter + furi_hal_bus_enable(FURI_HAL_RFID_FIELD_COUNTER_TIMER_BUS); + + LL_TIM_SetPrescaler(FURI_HAL_RFID_FIELD_COUNTER_TIMER, 0); + LL_TIM_SetCounterMode(FURI_HAL_RFID_FIELD_COUNTER_TIMER, LL_TIM_COUNTERMODE_UP); + LL_TIM_SetAutoReload(FURI_HAL_RFID_FIELD_COUNTER_TIMER, 0xFFFFFFFF); + LL_TIM_DisableARRPreload(FURI_HAL_RFID_FIELD_COUNTER_TIMER); + LL_TIM_SetRepetitionCounter(FURI_HAL_RFID_FIELD_COUNTER_TIMER, 0); + + LL_TIM_SetClockDivision(FURI_HAL_RFID_FIELD_COUNTER_TIMER, LL_TIM_CLOCKDIVISION_DIV1); + LL_TIM_SetClockSource(FURI_HAL_RFID_FIELD_COUNTER_TIMER, LL_TIM_CLOCKSOURCE_EXT_MODE2); + LL_TIM_ConfigETR( + FURI_HAL_RFID_FIELD_COUNTER_TIMER, + LL_TIM_ETR_POLARITY_INVERTED, + LL_TIM_ETR_PRESCALER_DIV1, + LL_TIM_ETR_FILTER_FDIV1); + + LL_TIM_OC_InitTypeDef TIM_OC_InitStruct = {0}; + TIM_OC_InitStruct.OCMode = LL_TIM_OCMODE_PWM1; + TIM_OC_InitStruct.OCState = LL_TIM_OCSTATE_ENABLE; + TIM_OC_InitStruct.CompareValue = 1; + LL_TIM_OC_Init( + FURI_HAL_RFID_FIELD_COUNTER_TIMER, + FURI_HAL_RFID_FIELD_COUNTER_TIMER_CHANNEL, + &TIM_OC_InitStruct); + + LL_TIM_GenerateEvent_UPDATE(FURI_HAL_RFID_FIELD_COUNTER_TIMER); + LL_TIM_OC_SetPolarity( + FURI_HAL_RFID_FIELD_COUNTER_TIMER, + FURI_HAL_RFID_FIELD_COUNTER_TIMER_CHANNEL, + LL_TIM_OCPOLARITY_HIGH); + LL_TIM_EnableDMAReq_UPDATE(FURI_HAL_RFID_FIELD_COUNTER_TIMER); + + // setup timer timeouts dma + furi_hal_bus_enable(FURI_HAL_RFID_FIELD_TIMEOUT_TIMER_BUS); + + LL_TIM_SetPrescaler(FURI_HAL_RFID_FIELD_TIMEOUT_TIMER, 64000 - 1); + LL_TIM_SetCounterMode(FURI_HAL_RFID_FIELD_TIMEOUT_TIMER, LL_TIM_COUNTERMODE_UP); + LL_TIM_SetAutoReload(FURI_HAL_RFID_FIELD_TIMEOUT_TIMER, 100 - 1); // 100 ms + LL_TIM_SetClockDivision(FURI_HAL_RFID_FIELD_TIMEOUT_TIMER, LL_TIM_CLOCKDIVISION_DIV1); + LL_TIM_SetClockSource(FURI_HAL_RFID_FIELD_TIMEOUT_TIMER, LL_TIM_CLOCKSOURCE_INTERNAL); + + LL_TIM_DisableARRPreload(FURI_HAL_RFID_FIELD_TIMEOUT_TIMER); + + LL_TIM_EnableDMAReq_UPDATE(FURI_HAL_RFID_FIELD_TIMEOUT_TIMER); + LL_TIM_GenerateEvent_UPDATE(FURI_HAL_RFID_FIELD_TIMEOUT_TIMER); +} + +void furi_hal_rfid_field_detect_start(void) { + // setup pins + furi_hal_rfid_pins_field(); + + // configure timer + furi_hal_rfid_field_tim_setup(); + + // configure DMA "TIM_COUNTER_CNT -> counter" + LL_DMA_SetMemoryAddress(RFID_DMA_CH1_DEF, (uint32_t) & (furi_hal_rfid->field.counter)); + LL_DMA_SetPeriphAddress( + RFID_DMA_CH1_DEF, (uint32_t) & (FURI_HAL_RFID_FIELD_COUNTER_TIMER->CNT)); + LL_DMA_ConfigTransfer( + RFID_DMA_CH1_DEF, + LL_DMA_DIRECTION_PERIPH_TO_MEMORY | LL_DMA_MODE_CIRCULAR | LL_DMA_PERIPH_NOINCREMENT | + LL_DMA_MEMORY_NOINCREMENT | LL_DMA_PDATAALIGN_WORD | LL_DMA_MDATAALIGN_WORD | + LL_DMA_PRIORITY_MEDIUM); + LL_DMA_SetDataLength(RFID_DMA_CH1_DEF, 1); + LL_DMA_SetPeriphRequest(RFID_DMA_CH1_DEF, FURI_HAL_RFID_FIELD_DMAMUX_DMA); + LL_DMA_EnableChannel(RFID_DMA_CH1_DEF); + + // configure DMA "mem -> TIM_COUNTER_CNT" + LL_DMA_SetMemoryAddress( + RFID_DMA_CH2_DEF, (uint32_t) & (furi_hal_rfid->field.set_tim_counter_cnt)); + LL_DMA_SetPeriphAddress( + RFID_DMA_CH2_DEF, (uint32_t) & (FURI_HAL_RFID_FIELD_COUNTER_TIMER->CNT)); + LL_DMA_ConfigTransfer( + RFID_DMA_CH2_DEF, + LL_DMA_DIRECTION_MEMORY_TO_PERIPH | LL_DMA_MODE_CIRCULAR | LL_DMA_PERIPH_NOINCREMENT | + LL_DMA_MEMORY_NOINCREMENT | LL_DMA_PDATAALIGN_WORD | LL_DMA_MDATAALIGN_WORD | + LL_DMA_PRIORITY_LOW); + LL_DMA_SetDataLength(RFID_DMA_CH2_DEF, 1); + LL_DMA_SetPeriphRequest(RFID_DMA_CH2_DEF, FURI_HAL_RFID_FIELD_DMAMUX_DMA); + LL_DMA_EnableChannel(RFID_DMA_CH2_DEF); + + // start tim counter + LL_TIM_EnableAllOutputs(FURI_HAL_RFID_FIELD_COUNTER_TIMER); + + LL_TIM_SetCounter(FURI_HAL_RFID_FIELD_COUNTER_TIMER, 0); + LL_TIM_EnableCounter(FURI_HAL_RFID_FIELD_COUNTER_TIMER); + + // start tim timeout + LL_TIM_SetCounter(FURI_HAL_RFID_FIELD_TIMEOUT_TIMER, 0); + LL_TIM_EnableCounter(FURI_HAL_RFID_FIELD_TIMEOUT_TIMER); + LL_TIM_EnableIT_UPDATE(FURI_HAL_RFID_FIELD_TIMEOUT_TIMER); +} + +void furi_hal_rfid_field_detect_stop(void) { + LL_TIM_DisableCounter(FURI_HAL_RFID_FIELD_COUNTER_TIMER); + LL_TIM_DisableAllOutputs(FURI_HAL_RFID_FIELD_COUNTER_TIMER); + + LL_TIM_DisableCounter(FURI_HAL_RFID_FIELD_TIMEOUT_TIMER); + + FURI_CRITICAL_ENTER(); + + LL_DMA_DeInit(RFID_DMA_CH1_DEF); + LL_DMA_DeInit(RFID_DMA_CH2_DEF); + + furi_hal_bus_disable(FURI_HAL_RFID_FIELD_COUNTER_TIMER_BUS); + furi_hal_bus_disable(FURI_HAL_RFID_FIELD_TIMEOUT_TIMER_BUS); + + furi_hal_rfid_pins_reset(); + + FURI_CRITICAL_EXIT(); +} + +bool furi_hal_rfid_field_is_present(uint32_t* frequency) { + *frequency = furi_hal_rfid->field.counter * 10; + return ( + (*frequency >= FURI_HAL_RFID_FIELD_FREQUENCY_MIN) && + (*frequency <= FURI_HAL_RFID_FIELD_FREQUENCY_MAX)); +} \ No newline at end of file diff --git a/firmware/targets/f7/furi_hal/furi_hal_rfid.h b/firmware/targets/f7/furi_hal/furi_hal_rfid.h index 78d9b6658709..7087ba991fac 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_rfid.h +++ b/firmware/targets/f7/furi_hal/furi_hal_rfid.h @@ -87,6 +87,20 @@ typedef void (*FuriHalRfidCompCallback)(bool level, void* context); /** Set comparator callback */ void furi_hal_rfid_comp_set_callback(FuriHalRfidCompCallback callback, void* context); +/** Start/Enable Field Presence detect */ +void furi_hal_rfid_field_detect_start(); + +/** Stop/Disable Field Presence detect */ +void furi_hal_rfid_field_detect_stop(); + +/** Check Field Presence + * + * @param[out] frequency pointer to frequency value to be set if filed detected + * + * @return true if field is present, false if not + */ +bool furi_hal_rfid_field_is_present(uint32_t* frequency); + #ifdef __cplusplus } #endif diff --git a/firmware/targets/f7/furi_hal/furi_hal_spi.c b/firmware/targets/f7/furi_hal/furi_hal_spi.c index 42b854799557..17769832b6ad 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_spi.c +++ b/firmware/targets/f7/furi_hal/furi_hal_spi.c @@ -12,10 +12,10 @@ #define TAG "FuriHalSpi" #define SPI_DMA DMA2 -#define SPI_DMA_RX_CHANNEL LL_DMA_CHANNEL_3 -#define SPI_DMA_TX_CHANNEL LL_DMA_CHANNEL_4 -#define SPI_DMA_RX_IRQ FuriHalInterruptIdDma2Ch3 -#define SPI_DMA_TX_IRQ FuriHalInterruptIdDma2Ch4 +#define SPI_DMA_RX_CHANNEL LL_DMA_CHANNEL_6 +#define SPI_DMA_TX_CHANNEL LL_DMA_CHANNEL_7 +#define SPI_DMA_RX_IRQ FuriHalInterruptIdDma2Ch6 +#define SPI_DMA_TX_IRQ FuriHalInterruptIdDma2Ch7 #define SPI_DMA_RX_DEF SPI_DMA, SPI_DMA_RX_CHANNEL #define SPI_DMA_TX_DEF SPI_DMA, SPI_DMA_TX_CHANNEL @@ -170,18 +170,18 @@ bool furi_hal_spi_bus_trx( } static void spi_dma_isr() { -#if SPI_DMA_RX_CHANNEL == LL_DMA_CHANNEL_3 - if(LL_DMA_IsActiveFlag_TC3(SPI_DMA) && LL_DMA_IsEnabledIT_TC(SPI_DMA_RX_DEF)) { - LL_DMA_ClearFlag_TC3(SPI_DMA); +#if SPI_DMA_RX_CHANNEL == LL_DMA_CHANNEL_6 + if(LL_DMA_IsActiveFlag_TC6(SPI_DMA) && LL_DMA_IsEnabledIT_TC(SPI_DMA_RX_DEF)) { + LL_DMA_ClearFlag_TC6(SPI_DMA); furi_check(furi_semaphore_release(spi_dma_completed) == FuriStatusOk); } #else #error Update this code. Would you kindly? #endif -#if SPI_DMA_TX_CHANNEL == LL_DMA_CHANNEL_4 - if(LL_DMA_IsActiveFlag_TC4(SPI_DMA) && LL_DMA_IsEnabledIT_TC(SPI_DMA_TX_DEF)) { - LL_DMA_ClearFlag_TC4(SPI_DMA); +#if SPI_DMA_TX_CHANNEL == LL_DMA_CHANNEL_7 + if(LL_DMA_IsActiveFlag_TC7(SPI_DMA) && LL_DMA_IsEnabledIT_TC(SPI_DMA_TX_DEF)) { + LL_DMA_ClearFlag_TC7(SPI_DMA); furi_check(furi_semaphore_release(spi_dma_completed) == FuriStatusOk); } #else @@ -241,8 +241,8 @@ bool furi_hal_spi_bus_trx_dma( dma_config.Priority = LL_DMA_PRIORITY_MEDIUM; LL_DMA_Init(SPI_DMA_TX_DEF, &dma_config); -#if SPI_DMA_TX_CHANNEL == LL_DMA_CHANNEL_4 - LL_DMA_ClearFlag_TC4(SPI_DMA); +#if SPI_DMA_TX_CHANNEL == LL_DMA_CHANNEL_7 + LL_DMA_ClearFlag_TC7(SPI_DMA); #else #error Update this code. Would you kindly? #endif @@ -315,8 +315,8 @@ bool furi_hal_spi_bus_trx_dma( dma_config.Priority = LL_DMA_PRIORITY_MEDIUM; LL_DMA_Init(SPI_DMA_RX_DEF, &dma_config); -#if SPI_DMA_RX_CHANNEL == LL_DMA_CHANNEL_3 - LL_DMA_ClearFlag_TC3(SPI_DMA); +#if SPI_DMA_RX_CHANNEL == LL_DMA_CHANNEL_6 + LL_DMA_ClearFlag_TC6(SPI_DMA); #else #error Update this code. Would you kindly? #endif diff --git a/firmware/targets/f7/furi_hal/furi_hal_subghz.c b/firmware/targets/f7/furi_hal/furi_hal_subghz.c index 6d671a9e15b1..ac5adefb8dfd 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_subghz.c +++ b/firmware/targets/f7/furi_hal/furi_hal_subghz.c @@ -1,6 +1,5 @@ #include -#include - +#include #include #include #include @@ -27,17 +26,36 @@ static uint32_t furi_hal_subghz_debug_gpio_buff[2]; #define SUBGHZ_DMA_CH1_DEF SUBGHZ_DMA, SUBGHZ_DMA_CH1_CHANNEL #define SUBGHZ_DMA_CH2_DEF SUBGHZ_DMA, SUBGHZ_DMA_CH2_CHANNEL +/** SubGhz state */ +typedef enum { + SubGhzStateInit, /**< Init pending */ + + SubGhzStateIdle, /**< Idle, energy save mode */ + + SubGhzStateAsyncRx, /**< Async RX started */ + + SubGhzStateAsyncTx, /**< Async TX started, DMA and timer is on */ + SubGhzStateAsyncTxLast, /**< Async TX continue, DMA completed and timer got last value to go */ + SubGhzStateAsyncTxEnd, /**< Async TX complete, cleanup needed */ + +} SubGhzState; + +/** SubGhz regulation, receive transmission on the current frequency for the + * region */ +typedef enum { + SubGhzRegulationOnlyRx, /**only Rx*/ + SubGhzRegulationTxRx, /**TxRx*/ +} SubGhzRegulation; + typedef struct { volatile SubGhzState state; volatile SubGhzRegulation regulation; - volatile FuriHalSubGhzPreset preset; const GpioPin* async_mirror_pin; } FuriHalSubGhz; volatile FuriHalSubGhz furi_hal_subghz = { .state = SubGhzStateInit, .regulation = SubGhzRegulationTxRx, - .preset = FuriHalSubGhzPresetIDLE, .async_mirror_pin = NULL, }; @@ -45,10 +63,13 @@ void furi_hal_subghz_set_async_mirror_pin(const GpioPin* pin) { furi_hal_subghz.async_mirror_pin = pin; } +const GpioPin* furi_hal_subghz_get_data_gpio() { + return &gpio_cc1101_g0; +} + void furi_hal_subghz_init() { furi_assert(furi_hal_subghz.state == SubGhzStateInit); furi_hal_subghz.state = SubGhzStateIdle; - furi_hal_subghz.preset = FuriHalSubGhzPresetIDLE; furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz); @@ -102,8 +123,6 @@ void furi_hal_subghz_sleep() { cc1101_shutdown(&furi_hal_spi_bus_handle_subghz); furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz); - - furi_hal_subghz.preset = FuriHalSubGhzPresetIDLE; } void furi_hal_subghz_dump_state() { @@ -115,34 +134,7 @@ void furi_hal_subghz_dump_state() { furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz); } -void furi_hal_subghz_load_preset(FuriHalSubGhzPreset preset) { - if(preset == FuriHalSubGhzPresetOok650Async) { - furi_hal_subghz_load_registers((uint8_t*)furi_hal_subghz_preset_ook_650khz_async_regs); - furi_hal_subghz_load_patable(furi_hal_subghz_preset_ook_async_patable); - } else if(preset == FuriHalSubGhzPresetOok270Async) { - furi_hal_subghz_load_registers((uint8_t*)furi_hal_subghz_preset_ook_270khz_async_regs); - furi_hal_subghz_load_patable(furi_hal_subghz_preset_ook_async_patable); - } else if(preset == FuriHalSubGhzPreset2FSKDev238Async) { - furi_hal_subghz_load_registers( - (uint8_t*)furi_hal_subghz_preset_2fsk_dev2_38khz_async_regs); - furi_hal_subghz_load_patable(furi_hal_subghz_preset_2fsk_async_patable); - } else if(preset == FuriHalSubGhzPreset2FSKDev476Async) { - furi_hal_subghz_load_registers( - (uint8_t*)furi_hal_subghz_preset_2fsk_dev47_6khz_async_regs); - furi_hal_subghz_load_patable(furi_hal_subghz_preset_2fsk_async_patable); - } else if(preset == FuriHalSubGhzPresetMSK99_97KbAsync) { - furi_hal_subghz_load_registers((uint8_t*)furi_hal_subghz_preset_msk_99_97kb_async_regs); - furi_hal_subghz_load_patable(furi_hal_subghz_preset_msk_async_patable); - } else if(preset == FuriHalSubGhzPresetGFSK9_99KbAsync) { - furi_hal_subghz_load_registers((uint8_t*)furi_hal_subghz_preset_gfsk_9_99kb_async_regs); - furi_hal_subghz_load_patable(furi_hal_subghz_preset_gfsk_async_patable); - } else { - furi_crash("SubGhz: Missing config."); - } - furi_hal_subghz.preset = preset; -} - -void furi_hal_subghz_load_custom_preset(uint8_t* preset_data) { +void furi_hal_subghz_load_custom_preset(const uint8_t* preset_data) { //load config furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz); cc1101_reset(&furi_hal_spi_bus_handle_subghz); @@ -157,7 +149,6 @@ void furi_hal_subghz_load_custom_preset(uint8_t* preset_data) { //load pa table memcpy(&pa[0], &preset_data[i + 2], 8); furi_hal_subghz_load_patable(pa); - furi_hal_subghz.preset = FuriHalSubGhzPresetCustom; //show debug if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { @@ -173,7 +164,7 @@ void furi_hal_subghz_load_custom_preset(uint8_t* preset_data) { } } -void furi_hal_subghz_load_registers(uint8_t* data) { +void furi_hal_subghz_load_registers(const uint8_t* data) { furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz); cc1101_reset(&furi_hal_spi_bus_handle_subghz); uint32_t i = 0; diff --git a/firmware/targets/f7/furi_hal/furi_hal_subghz.h b/firmware/targets/f7/furi_hal/furi_hal_subghz.h index 102981dbeb58..855ce31619ce 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_subghz.h +++ b/firmware/targets/f7/furi_hal/furi_hal_subghz.h @@ -5,6 +5,8 @@ #pragma once +#include + #include #include #include @@ -20,18 +22,6 @@ extern "C" { #define API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF (API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL / 2) #define API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME 999 -/** Radio Presets */ -typedef enum { - FuriHalSubGhzPresetIDLE, /**< default configuration */ - FuriHalSubGhzPresetOok270Async, /**< OOK, bandwidth 270kHz, asynchronous */ - FuriHalSubGhzPresetOok650Async, /**< OOK, bandwidth 650kHz, asynchronous */ - FuriHalSubGhzPreset2FSKDev238Async, /**< FM, deviation 2.380371 kHz, asynchronous */ - FuriHalSubGhzPreset2FSKDev476Async, /**< FM, deviation 47.60742 kHz, asynchronous */ - FuriHalSubGhzPresetMSK99_97KbAsync, /**< MSK, deviation 47.60742 kHz, 99.97Kb/s, asynchronous */ - FuriHalSubGhzPresetGFSK9_99KbAsync, /**< GFSK, deviation 19.042969 kHz, 9.996Kb/s, asynchronous */ - FuriHalSubGhzPresetCustom, /**Custom Preset*/ -} FuriHalSubGhzPreset; - /** Switchable Radio Paths */ typedef enum { FuriHalSubGhzPathIsolate, /**< Isolate Radio from antenna */ @@ -40,27 +30,6 @@ typedef enum { FuriHalSubGhzPath868, /**< Center Frequency: 868MHz. Path 3: SW1RF3-SW2RF3, LCLC */ } FuriHalSubGhzPath; -/** SubGhz state */ -typedef enum { - SubGhzStateInit, /**< Init pending */ - - SubGhzStateIdle, /**< Idle, energy save mode */ - - SubGhzStateAsyncRx, /**< Async RX started */ - - SubGhzStateAsyncTx, /**< Async TX started, DMA and timer is on */ - SubGhzStateAsyncTxLast, /**< Async TX continue, DMA completed and timer got last value to go */ - SubGhzStateAsyncTxEnd, /**< Async TX complete, cleanup needed */ - -} SubGhzState; - -/** SubGhz regulation, receive transmission on the current frequency for the - * region */ -typedef enum { - SubGhzRegulationOnlyRx, /**only Rx*/ - SubGhzRegulationTxRx, /**TxRx*/ -} SubGhzRegulation; - /* Mirror RX/TX async modulation signal to specified pin * * @warning Configures pin to output mode. Make sure it is not connected @@ -70,6 +39,12 @@ typedef enum { */ void furi_hal_subghz_set_async_mirror_pin(const GpioPin* pin); +/** Get data GPIO + * + * @return pointer to the gpio pin structure + */ +const GpioPin* furi_hal_subghz_get_data_gpio(); + /** Initialize and switch to power save mode Used by internal API-HAL * initialization routine Can be used to reinitialize device to safe state and * send it to sleep @@ -84,23 +59,17 @@ void furi_hal_subghz_sleep(); */ void furi_hal_subghz_dump_state(); -/** Load registers from preset by preset name - * - * @param preset to load - */ -void furi_hal_subghz_load_preset(FuriHalSubGhzPreset preset); - /** Load custom registers from preset * * @param preset_data registers to load */ -void furi_hal_subghz_load_custom_preset(uint8_t* preset_data); +void furi_hal_subghz_load_custom_preset(const uint8_t* preset_data); /** Load registers * * @param data Registers data */ -void furi_hal_subghz_load_registers(uint8_t* data); +void furi_hal_subghz_load_registers(const uint8_t* data); /** Load PATABLE * diff --git a/firmware/targets/f7/furi_hal/furi_hal_subghz_configs.h b/firmware/targets/f7/furi_hal/furi_hal_subghz_configs.h deleted file mode 100644 index 5ea17b6ddd0d..000000000000 --- a/firmware/targets/f7/furi_hal/furi_hal_subghz_configs.h +++ /dev/null @@ -1,314 +0,0 @@ -#pragma once - -#include - -static const uint8_t furi_hal_subghz_preset_ook_270khz_async_regs[][2] = { - // https://e2e.ti.com/support/wireless-connectivity/sub-1-ghz-group/sub-1-ghz/f/sub-1-ghz-forum/382066/cc1101---don-t-know-the-correct-registers-configuration - - /* GPIO GD0 */ - {CC1101_IOCFG0, 0x0D}, // GD0 as async serial data output/input - - /* FIFO and internals */ - {CC1101_FIFOTHR, 0x47}, // The only important bit is ADC_RETENTION, FIFO Tx=33 Rx=32 - - /* Packet engine */ - {CC1101_PKTCTRL0, 0x32}, // Async, continious, no whitening - - /* Frequency Synthesizer Control */ - {CC1101_FSCTRL1, 0x06}, // IF = (26*10^6) / (2^10) * 0x06 = 152343.75Hz - - // Modem Configuration - {CC1101_MDMCFG0, 0x00}, // Channel spacing is 25kHz - {CC1101_MDMCFG1, 0x00}, // Channel spacing is 25kHz - {CC1101_MDMCFG2, 0x30}, // Format ASK/OOK, No preamble/sync - {CC1101_MDMCFG3, 0x32}, // Data rate is 3.79372 kBaud - {CC1101_MDMCFG4, 0x67}, // Rx BW filter is 270.833333kHz - - /* Main Radio Control State Machine */ - {CC1101_MCSM0, 0x18}, // Autocalibrate on idle-to-rx/tx, PO_TIMEOUT is 64 cycles(149-155us) - - /* Frequency Offset Compensation Configuration */ - {CC1101_FOCCFG, - 0x18}, // no frequency offset compensation, POST_K same as PRE_K, PRE_K is 4K, GATE is off - - /* Automatic Gain Control */ - {CC1101_AGCCTRL0, - 0x40}, // 01 - Low hysteresis, small asymmetric dead zone, medium gain; 00 - 8 samples agc; 00 - Normal AGC, 00 - 4dB boundary - {CC1101_AGCCTRL1, - 0x00}, // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 0000 - RSSI to MAIN_TARGET - {CC1101_AGCCTRL2, 0x03}, // 00 - DVGA all; 000 - MAX LNA+LNA2; 011 - MAIN_TARGET 24 dB - - /* Wake on radio and timeouts control */ - {CC1101_WORCTRL, 0xFB}, // WOR_RES is 2^15 periods (0.91 - 0.94 s) 16.5 - 17.2 hours - - /* Frontend configuration */ - {CC1101_FREND0, 0x11}, // Adjusts current TX LO buffer + high is PATABLE[1] - {CC1101_FREND1, 0xB6}, // - - /* End */ - {0, 0}, -}; - -static const uint8_t furi_hal_subghz_preset_ook_650khz_async_regs[][2] = { - // https://e2e.ti.com/support/wireless-connectivity/sub-1-ghz-group/sub-1-ghz/f/sub-1-ghz-forum/382066/cc1101---don-t-know-the-correct-registers-configuration - - /* GPIO GD0 */ - {CC1101_IOCFG0, 0x0D}, // GD0 as async serial data output/input - - /* FIFO and internals */ - {CC1101_FIFOTHR, 0x07}, // The only important bit is ADC_RETENTION - - /* Packet engine */ - {CC1101_PKTCTRL0, 0x32}, // Async, continious, no whitening - - /* Frequency Synthesizer Control */ - {CC1101_FSCTRL1, 0x06}, // IF = (26*10^6) / (2^10) * 0x06 = 152343.75Hz - - // Modem Configuration - {CC1101_MDMCFG0, 0x00}, // Channel spacing is 25kHz - {CC1101_MDMCFG1, 0x00}, // Channel spacing is 25kHz - {CC1101_MDMCFG2, 0x30}, // Format ASK/OOK, No preamble/sync - {CC1101_MDMCFG3, 0x32}, // Data rate is 3.79372 kBaud - {CC1101_MDMCFG4, 0x17}, // Rx BW filter is 650.000kHz - - /* Main Radio Control State Machine */ - {CC1101_MCSM0, 0x18}, // Autocalibrate on idle-to-rx/tx, PO_TIMEOUT is 64 cycles(149-155us) - - /* Frequency Offset Compensation Configuration */ - {CC1101_FOCCFG, - 0x18}, // no frequency offset compensation, POST_K same as PRE_K, PRE_K is 4K, GATE is off - - /* Automatic Gain Control */ - // {CC1101_AGCTRL0,0x40}, // 01 - Low hysteresis, small asymmetric dead zone, medium gain; 00 - 8 samples agc; 00 - Normal AGC, 00 - 4dB boundary - // {CC1101_AGCTRL1,0x00}, // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 0000 - RSSI to MAIN_TARGET - // {CC1101_AGCCTRL2, 0x03}, // 00 - DVGA all; 000 - MAX LNA+LNA2; 011 - MAIN_TARGET 24 dB - //MAGN_TARGET for RX filter BW =< 100 kHz is 0x3. For higher RX filter BW's MAGN_TARGET is 0x7. - {CC1101_AGCCTRL0, - 0x91}, // 10 - Medium hysteresis, medium asymmetric dead zone, medium gain ; 01 - 16 samples agc; 00 - Normal AGC, 01 - 8dB boundary - {CC1101_AGCCTRL1, - 0x0}, // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 0000 - RSSI to MAIN_TARGET - {CC1101_AGCCTRL2, 0x07}, // 00 - DVGA all; 000 - MAX LNA+LNA2; 111 - MAIN_TARGET 42 dB - - /* Wake on radio and timeouts control */ - {CC1101_WORCTRL, 0xFB}, // WOR_RES is 2^15 periods (0.91 - 0.94 s) 16.5 - 17.2 hours - - /* Frontend configuration */ - {CC1101_FREND0, 0x11}, // Adjusts current TX LO buffer + high is PATABLE[1] - {CC1101_FREND1, 0xB6}, // - - /* End */ - {0, 0}, -}; - -static const uint8_t furi_hal_subghz_preset_2fsk_dev2_38khz_async_regs[][2] = { - - /* GPIO GD0 */ - {CC1101_IOCFG0, 0x0D}, // GD0 as async serial data output/input - - /* Frequency Synthesizer Control */ - {CC1101_FSCTRL1, 0x06}, // IF = (26*10^6) / (2^10) * 0x06 = 152343.75Hz - - /* Packet engine */ - {CC1101_PKTCTRL0, 0x32}, // Async, continious, no whitening - {CC1101_PKTCTRL1, 0x04}, - - // // Modem Configuration - {CC1101_MDMCFG0, 0x00}, - {CC1101_MDMCFG1, 0x02}, - {CC1101_MDMCFG2, 0x04}, // Format 2-FSK/FM, No preamble/sync, Disable (current optimized) - {CC1101_MDMCFG3, 0x83}, // Data rate is 4.79794 kBaud - {CC1101_MDMCFG4, 0x67}, //Rx BW filter is 270.833333 kHz - {CC1101_DEVIATN, 0x04}, //Deviation 2.380371 kHz - - /* Main Radio Control State Machine */ - {CC1101_MCSM0, 0x18}, // Autocalibrate on idle-to-rx/tx, PO_TIMEOUT is 64 cycles(149-155us) - - /* Frequency Offset Compensation Configuration */ - {CC1101_FOCCFG, - 0x16}, // no frequency offset compensation, POST_K same as PRE_K, PRE_K is 4K, GATE is off - - /* Automatic Gain Control */ - {CC1101_AGCCTRL0, - 0x91}, //10 - Medium hysteresis, medium asymmetric dead zone, medium gain ; 01 - 16 samples agc; 00 - Normal AGC, 01 - 8dB boundary - {CC1101_AGCCTRL1, - 0x00}, // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 0000 - RSSI to MAIN_TARGET - {CC1101_AGCCTRL2, 0x07}, // 00 - DVGA all; 000 - MAX LNA+LNA2; 111 - MAIN_TARGET 42 dB - - /* Wake on radio and timeouts control */ - {CC1101_WORCTRL, 0xFB}, // WOR_RES is 2^15 periods (0.91 - 0.94 s) 16.5 - 17.2 hours - - /* Frontend configuration */ - {CC1101_FREND0, 0x10}, // Adjusts current TX LO buffer - {CC1101_FREND1, 0x56}, - - /* End */ - {0, 0}, -}; - -static const uint8_t furi_hal_subghz_preset_2fsk_dev47_6khz_async_regs[][2] = { - - /* GPIO GD0 */ - {CC1101_IOCFG0, 0x0D}, // GD0 as async serial data output/input - - /* Frequency Synthesizer Control */ - {CC1101_FSCTRL1, 0x06}, // IF = (26*10^6) / (2^10) * 0x06 = 152343.75Hz - - /* Packet engine */ - {CC1101_PKTCTRL0, 0x32}, // Async, continious, no whitening - {CC1101_PKTCTRL1, 0x04}, - - // // Modem Configuration - {CC1101_MDMCFG0, 0x00}, - {CC1101_MDMCFG1, 0x02}, - {CC1101_MDMCFG2, 0x04}, // Format 2-FSK/FM, No preamble/sync, Disable (current optimized) - {CC1101_MDMCFG3, 0x83}, // Data rate is 4.79794 kBaud - {CC1101_MDMCFG4, 0x67}, //Rx BW filter is 270.833333 kHz - {CC1101_DEVIATN, 0x47}, //Deviation 47.60742 kHz - - /* Main Radio Control State Machine */ - {CC1101_MCSM0, 0x18}, // Autocalibrate on idle-to-rx/tx, PO_TIMEOUT is 64 cycles(149-155us) - - /* Frequency Offset Compensation Configuration */ - {CC1101_FOCCFG, - 0x16}, // no frequency offset compensation, POST_K same as PRE_K, PRE_K is 4K, GATE is off - - /* Automatic Gain Control */ - {CC1101_AGCCTRL0, - 0x91}, //10 - Medium hysteresis, medium asymmetric dead zone, medium gain ; 01 - 16 samples agc; 00 - Normal AGC, 01 - 8dB boundary - {CC1101_AGCCTRL1, - 0x00}, // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 0000 - RSSI to MAIN_TARGET - {CC1101_AGCCTRL2, 0x07}, // 00 - DVGA all; 000 - MAX LNA+LNA2; 111 - MAIN_TARGET 42 dB - - /* Wake on radio and timeouts control */ - {CC1101_WORCTRL, 0xFB}, // WOR_RES is 2^15 periods (0.91 - 0.94 s) 16.5 - 17.2 hours - - /* Frontend configuration */ - {CC1101_FREND0, 0x10}, // Adjusts current TX LO buffer - {CC1101_FREND1, 0x56}, - - /* End */ - {0, 0}, -}; - -static const uint8_t furi_hal_subghz_preset_msk_99_97kb_async_regs[][2] = { - /* GPIO GD0 */ - {CC1101_IOCFG0, 0x06}, - - {CC1101_FIFOTHR, 0x07}, // The only important bit is ADC_RETENTION - {CC1101_SYNC1, 0x46}, - {CC1101_SYNC0, 0x4C}, - {CC1101_ADDR, 0x00}, - {CC1101_PKTLEN, 0x00}, - {CC1101_CHANNR, 0x00}, - - {CC1101_PKTCTRL0, 0x05}, - - {CC1101_FSCTRL0, 0x23}, - {CC1101_FSCTRL1, 0x06}, - - {CC1101_MDMCFG0, 0xF8}, - {CC1101_MDMCFG1, 0x22}, - {CC1101_MDMCFG2, 0x72}, - {CC1101_MDMCFG3, 0xF8}, - {CC1101_MDMCFG4, 0x5B}, - {CC1101_DEVIATN, 0x47}, - - {CC1101_MCSM0, 0x18}, - {CC1101_FOCCFG, 0x16}, - - {CC1101_AGCCTRL0, 0xB2}, - {CC1101_AGCCTRL1, 0x00}, - {CC1101_AGCCTRL2, 0xC7}, - - {CC1101_FREND0, 0x10}, - {CC1101_FREND1, 0x56}, - - {CC1101_BSCFG, 0x1C}, - {CC1101_FSTEST, 0x59}, - - /* End */ - {0, 0}, -}; - -static const uint8_t furi_hal_subghz_preset_gfsk_9_99kb_async_regs[][2] = { - - {CC1101_IOCFG0, 0x06}, //GDO0 Output Pin Configuration - {CC1101_FIFOTHR, 0x47}, //RX FIFO and TX FIFO Thresholds - - //1 : CRC calculation in TX and CRC check in RX enabled, - //1 : Variable packet length mode. Packet length configured by the first byte after sync word - {CC1101_PKTCTRL0, 0x05}, - - {CC1101_FSCTRL1, 0x06}, //Frequency Synthesizer Control - - {CC1101_SYNC1, 0x46}, - {CC1101_SYNC0, 0x4C}, - {CC1101_ADDR, 0x00}, - {CC1101_PKTLEN, 0x00}, - - {CC1101_MDMCFG4, 0xC8}, //Modem Configuration 9.99 - {CC1101_MDMCFG3, 0x93}, //Modem Configuration - {CC1101_MDMCFG2, 0x12}, // 2: 16/16 sync word bits detected - - {CC1101_DEVIATN, 0x34}, //Deviation = 19.042969 - {CC1101_MCSM0, 0x18}, //Main Radio Control State Machine Configuration - {CC1101_FOCCFG, 0x16}, //Frequency Offset Compensation Configuration - - {CC1101_AGCCTRL2, 0x43}, //AGC Control - {CC1101_AGCCTRL1, 0x40}, - {CC1101_AGCCTRL0, 0x91}, - - {CC1101_WORCTRL, 0xFB}, //Wake On Radio Control - /* End */ - {0, 0}, -}; - -static const uint8_t furi_hal_subghz_preset_ook_async_patable[8] = { - 0x00, - 0xC0, // 12dBm 0xC0, 10dBm 0xC5, 7dBm 0xCD, 5dBm 0x86, 0dBm 0x50, -6dBm 0x37, -10dBm 0x26, -15dBm 0x1D, -20dBm 0x17, -30dBm 0x03 - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00}; - -static const uint8_t furi_hal_subghz_preset_ook_async_patable_au[8] = { - 0x00, - 0x37, // 12dBm 0xC0, 10dBm 0xC5, 7dBm 0xCD, 5dBm 0x86, 0dBm 0x50, -6dBm 0x37, -10dBm 0x26, -15dBm 0x1D, -20dBm 0x17, -30dBm 0x03 - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00}; - -static const uint8_t furi_hal_subghz_preset_2fsk_async_patable[8] = { - 0xC0, // 10dBm 0xC0, 7dBm 0xC8, 5dBm 0x84, 0dBm 0x60, -10dBm 0x34, -15dBm 0x1D, -20dBm 0x0E, -30dBm 0x12 - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00}; - -static const uint8_t furi_hal_subghz_preset_msk_async_patable[8] = { - 0xC0, // 10dBm 0xC0, 7dBm 0xC8, 5dBm 0x84, 0dBm 0x60, -10dBm 0x34, -15dBm 0x1D, -20dBm 0x0E, -30dBm 0x12 - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00}; - -static const uint8_t furi_hal_subghz_preset_gfsk_async_patable[8] = { - 0xC0, // 10dBm 0xC0, 7dBm 0xC8, 5dBm 0x84, 0dBm 0x60, -10dBm 0x34, -15dBm 0x1D, -20dBm 0x0E, -30dBm 0x12 - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00}; diff --git a/firmware/targets/f7/platform_specific/intrinsic_export.h b/firmware/targets/f7/platform_specific/intrinsic_export.h index 8dbc4bd03209..ca343a12862e 100644 --- a/firmware/targets/f7/platform_specific/intrinsic_export.h +++ b/firmware/targets/f7/platform_specific/intrinsic_export.h @@ -1,10 +1,12 @@ #include +#include #ifdef __cplusplus extern "C" { #endif void __clear_cache(void*, void*); +void* __aeabi_uldivmod(uint64_t, uint64_t); #ifdef __cplusplus } diff --git a/firmware/targets/f7/target.json b/firmware/targets/f7/target.json index 5d8231b20ab9..0c083b68ddba 100644 --- a/firmware/targets/f7/target.json +++ b/firmware/targets/f7/target.json @@ -38,6 +38,7 @@ "assets", "one_wire", "ibutton", + "music_worker", "misc", "mbedtls", "lfrfid", diff --git a/furi/core/check.c b/furi/core/check.c index 478f3aacccf1..c5c4ef1a4af3 100644 --- a/furi/core/check.c +++ b/furi/core/check.c @@ -166,7 +166,11 @@ FURI_NORETURN void __furi_crash() { RESTORE_REGISTERS_AND_HALT_MCU(true); #ifndef FURI_DEBUG } else { - furi_hal_rtc_set_fault_data((uint32_t)__furi_check_message); + uint32_t ptr = (uint32_t)__furi_check_message; + if(ptr < FLASH_BASE || ptr > (FLASH_BASE + FLASH_SIZE)) { + ptr = (uint32_t) "Check serial logs"; + } + furi_hal_rtc_set_fault_data(ptr); furi_hal_console_puts("\r\nRebooting system.\r\n"); furi_hal_console_puts("\033[0m\r\n"); furi_hal_power_reset(); diff --git a/furi/core/check.h b/furi/core/check.h index ea83f2219c2b..004422e807e5 100644 --- a/furi/core/check.h +++ b/furi/core/check.h @@ -13,6 +13,8 @@ */ #pragma once +#include + #ifdef __cplusplus extern "C" { #define FURI_NORETURN [[noreturn]] @@ -48,28 +50,47 @@ FURI_NORETURN void __furi_halt(); } while(0) /** Check condition and crash if check failed */ -#define furi_check(__e) \ - do { \ - if(!(__e)) { \ - furi_crash(__FURI_CHECK_MESSAGE_FLAG); \ - } \ +#define __furi_check(__e, __m) \ + do { \ + if(!(__e)) { \ + furi_crash(__m); \ + } \ } while(0) +/** Check condition and crash if failed + * + * @param condition to check + * @param optional message + */ +#define furi_check(...) \ + M_APPLY(__furi_check, M_DEFAULT_ARGS(2, (__FURI_CHECK_MESSAGE_FLAG), __VA_ARGS__)) + /** Only in debug build: Assert condition and crash if assert failed */ #ifdef FURI_DEBUG -#define furi_assert(__e) \ - do { \ - if(!(__e)) { \ - furi_crash(__FURI_ASSERT_MESSAGE_FLAG); \ - } \ +#define __furi_assert(__e, __m) \ + do { \ + if(!(__e)) { \ + furi_crash(__m); \ + } \ } while(0) #else -#define furi_assert(__e) \ - do { \ - ((void)(__e)); \ +#define __furi_assert(__e, __m) \ + do { \ + ((void)(__e)); \ + ((void)(__m)); \ } while(0) #endif +/** Assert condition and crash if failed + * + * @warning only will do check if firmware compiled in debug mode + * + * @param condition to check + * @param optional message + */ +#define furi_assert(...) \ + M_APPLY(__furi_assert, M_DEFAULT_ARGS(2, (__FURI_ASSERT_MESSAGE_FLAG), __VA_ARGS__)) + #ifdef __cplusplus } #endif diff --git a/furi/core/string.c b/furi/core/string.c index 4384fe06a224..682c8d409778 100644 --- a/furi/core/string.c +++ b/furi/core/string.c @@ -296,7 +296,9 @@ static FuriStringUTF8State state_to_furi_state(m_str1ng_utf8_state_e state) { } void furi_string_utf8_decode(char c, FuriStringUTF8State* state, FuriStringUnicodeValue* unicode) { + string_unicode_t m_u = *unicode; m_str1ng_utf8_state_e m_state = furi_state_to_state(*state); - m_str1ng_utf8_decode(c, &m_state, unicode); + m_str1ng_utf8_decode(c, &m_state, &m_u); *state = state_to_furi_state(m_state); + *unicode = m_u; } diff --git a/furi/core/string.h b/furi/core/string.h index 0523d3ba04ed..7529deacd7c1 100644 --- a/furi/core/string.h +++ b/furi/core/string.h @@ -633,20 +633,17 @@ void furi_string_utf8_decode(char c, FuriStringUTF8State* state, FuriStringUnico * @brief Search for a string (or C string) in a string * (string, [c]string[, start=0]) */ -#define furi_string_search(v, ...) \ - M_APPLY( \ - FURI_STRING_SELECT3, \ - furi_string_search, \ - furi_string_search_str, \ - v, \ - M_IF_DEFAULT1(0, __VA_ARGS__)) - +#define furi_string_search(...) \ + M_APPLY( \ + FURI_STRING_SELECT3, \ + furi_string_search, \ + furi_string_search_str, \ + M_DEFAULT_ARGS(3, (0), __VA_ARGS__)) /** * @brief Search for a C string in a string * (string, cstring[, start=0]) */ -#define furi_string_search_str(v, ...) \ - M_APPLY(furi_string_search_str, v, M_IF_DEFAULT1(0, __VA_ARGS__)) +#define furi_string_search_str(...) furi_string_search_str(M_DEFAULT_ARGS(3, (0), __VA_ARGS__)) /** * @brief Test if the string starts with the given string (or C string). @@ -672,41 +669,36 @@ void furi_string_utf8_decode(char c, FuriStringUTF8State* state, FuriStringUnico * @brief Trim a string from the given set of characters (default is " \n\r\t"). * (string[, set=" \n\r\t"]) */ -#define furi_string_trim(...) M_APPLY(furi_string_trim, M_IF_DEFAULT1(" \n\r\t", __VA_ARGS__)) +#define furi_string_trim(...) furi_string_trim(M_DEFAULT_ARGS(2, (" \n\r\t"), __VA_ARGS__)) /** * @brief Search for a character in a string. * (string, character[, start=0]) */ -#define furi_string_search_char(v, ...) \ - M_APPLY(furi_string_search_char, v, M_IF_DEFAULT1(0, __VA_ARGS__)) +#define furi_string_search_char(...) furi_string_search_char(M_DEFAULT_ARGS(3, (0), __VA_ARGS__)) /** * @brief Reverse Search for a character in a string. * (string, character[, start=0]) */ -#define furi_string_search_rchar(v, ...) \ - M_APPLY(furi_string_search_rchar, v, M_IF_DEFAULT1(0, __VA_ARGS__)) +#define furi_string_search_rchar(...) furi_string_search_rchar(M_DEFAULT_ARGS(3, (0), __VA_ARGS__)) /** * @brief Replace a string to another string (or C string to another C string) in a string. * (string, [c]string, [c]string[, start=0]) */ -#define furi_string_replace(a, b, ...) \ - M_APPLY( \ - FURI_STRING_SELECT4, \ - furi_string_replace, \ - furi_string_replace_str, \ - a, \ - b, \ - M_IF_DEFAULT1(0, __VA_ARGS__)) +#define furi_string_replace(...) \ + M_APPLY( \ + FURI_STRING_SELECT4, \ + furi_string_replace, \ + furi_string_replace_str, \ + M_DEFAULT_ARGS(4, (0), __VA_ARGS__)) /** * @brief Replace a C string to another C string in a string. * (string, cstring, cstring[, start=0]) */ -#define furi_string_replace_str(a, b, ...) \ - M_APPLY(furi_string_replace_str, a, b, M_IF_DEFAULT1(0, __VA_ARGS__)) +#define furi_string_replace_str(...) furi_string_replace_str(M_DEFAULT_ARGS(4, (0), __VA_ARGS__)) /** * @brief INIT OPLIST for FuriString. @@ -743,4 +735,4 @@ void furi_string_utf8_decode(char c, FuriStringUTF8State* state, FuriStringUnico #ifdef __cplusplus } -#endif \ No newline at end of file +#endif diff --git a/lib/SConscript b/lib/SConscript index 495ba4bfe24b..ab78c6ea4d44 100644 --- a/lib/SConscript +++ b/lib/SConscript @@ -15,6 +15,7 @@ env.Append( Dir("u8g2"), Dir("update_util"), Dir("print"), + Dir("music_worker"), ], ) @@ -100,6 +101,7 @@ libs = env.BuildModules( "misc", "lfrfid", "flipper_application", + "music_worker", ], ) diff --git a/lib/digital_signal/digital_signal.c b/lib/digital_signal/digital_signal.c index 39aa9cbc6e14..25adb878b78e 100644 --- a/lib/digital_signal/digital_signal.c +++ b/lib/digital_signal/digital_signal.c @@ -51,8 +51,16 @@ struct DigitalSignalInternals { #define T_TIM 1562 /* 15.625 ns *100 */ #define T_TIM_DIV2 781 /* 15.625 ns / 2 *100 */ +/* end marker in DMA ringbuffer, will get written into timer register at the end */ +#define SEQ_TIMER_MAX 0xFFFFFFFF + +/* time to wait in loops before returning */ +#define SEQ_LOCK_WAIT_MS 10UL +#define SEQ_LOCK_WAIT_TICKS (SEQ_LOCK_WAIT_MS * 1000 * 64) + /* maximum entry count of the sequence dma ring buffer */ -#define SEQUENCE_DMA_RINGBUFFER_SIZE 32 +#define RINGBUFFER_SIZE 128 + /* maximum number of DigitalSignals in a sequence */ #define SEQUENCE_SIGNALS_SIZE 32 /* @@ -252,7 +260,7 @@ static void digital_signal_setup_timer() { LL_TIM_SetCounterMode(TIM2, LL_TIM_COUNTERMODE_UP); LL_TIM_SetClockDivision(TIM2, LL_TIM_CLOCKDIVISION_DIV1); LL_TIM_SetPrescaler(TIM2, 0); - LL_TIM_SetAutoReload(TIM2, 0xFFFFFFFF); + LL_TIM_SetAutoReload(TIM2, SEQ_TIMER_MAX); LL_TIM_SetCounter(TIM2, 0); } @@ -335,7 +343,7 @@ DigitalSequence* digital_sequence_alloc(uint32_t size, const GpioPin* gpio) { sequence->bake = false; sequence->dma_buffer = malloc(sizeof(struct ReloadBuffer)); - sequence->dma_buffer->size = SEQUENCE_DMA_RINGBUFFER_SIZE; + sequence->dma_buffer->size = RINGBUFFER_SIZE; sequence->dma_buffer->buffer = malloc(sequence->dma_buffer->size * sizeof(uint32_t)); sequence->dma_config_gpio.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; @@ -454,39 +462,23 @@ static DigitalSignal* digital_sequence_bake(DigitalSequence* sequence) { return ret; } -static void digital_sequence_update_pos(DigitalSequence* sequence) { - struct ReloadBuffer* dma_buffer = sequence->dma_buffer; - - dma_buffer->read_pos = dma_buffer->size - LL_DMA_GetDataLength(DMA1, LL_DMA_CHANNEL_2); -} - -static const uint32_t wait_ms = 10; -static const uint32_t wait_ticks = wait_ms * 1000 * 64; - static void digital_sequence_finish(DigitalSequence* sequence) { struct ReloadBuffer* dma_buffer = sequence->dma_buffer; if(dma_buffer->dma_active) { uint32_t prev_timer = DWT->CYCCNT; - uint32_t end_pos = (dma_buffer->write_pos + 1) % dma_buffer->size; do { - uint32_t last_pos = dma_buffer->read_pos; - - digital_sequence_update_pos(sequence); - - /* we are finished, when the DMA transferred the 0xFFFFFFFF-timer which is the current write_pos */ - if(dma_buffer->read_pos == end_pos) { + /* we are finished, when the DMA transferred the SEQ_TIMER_MAX marker */ + if(TIM2->ARR == SEQ_TIMER_MAX) { break; } - - if(last_pos != dma_buffer->read_pos) { //-V547 - prev_timer = DWT->CYCCNT; - } - if(DWT->CYCCNT - prev_timer > wait_ticks) { + if(DWT->CYCCNT - prev_timer > SEQ_LOCK_WAIT_TICKS) { + dma_buffer->read_pos = + RINGBUFFER_SIZE - LL_DMA_GetDataLength(DMA1, LL_DMA_CHANNEL_2); FURI_LOG_D( TAG, "[SEQ] hung %lu ms in finish (ARR 0x%08lx, read %lu, write %lu)", - wait_ms, + SEQ_LOCK_WAIT_MS, TIM2->ARR, dma_buffer->read_pos, dma_buffer->write_pos); @@ -504,23 +496,30 @@ static void digital_sequence_queue_pulse(DigitalSequence* sequence, uint32_t len if(dma_buffer->dma_active) { uint32_t prev_timer = DWT->CYCCNT; - uint32_t end_pos = (dma_buffer->write_pos + 1) % dma_buffer->size; do { - uint32_t last_pos = dma_buffer->read_pos; - digital_sequence_update_pos(sequence); + dma_buffer->read_pos = RINGBUFFER_SIZE - LL_DMA_GetDataLength(DMA1, LL_DMA_CHANNEL_2); + + uint32_t free = + (RINGBUFFER_SIZE + dma_buffer->read_pos - dma_buffer->write_pos) % RINGBUFFER_SIZE; - if(dma_buffer->read_pos != end_pos) { + if(free > 2) { break; } - if(last_pos != dma_buffer->read_pos) { //-V547 - prev_timer = DWT->CYCCNT; - } - if(DWT->CYCCNT - prev_timer > wait_ticks) { + if(DWT->CYCCNT - prev_timer > SEQ_LOCK_WAIT_TICKS) { FURI_LOG_D( TAG, "[SEQ] hung %lu ms in queue (ARR 0x%08lx, read %lu, write %lu)", - wait_ms, + SEQ_LOCK_WAIT_MS, + TIM2->ARR, + dma_buffer->read_pos, + dma_buffer->write_pos); + break; + } + if(TIM2->ARR == SEQ_TIMER_MAX) { + FURI_LOG_D( + TAG, + "[SEQ] buffer underrun in queue (ARR 0x%08lx, read %lu, write %lu)", TIM2->ARR, dma_buffer->read_pos, dma_buffer->write_pos); @@ -530,8 +529,9 @@ static void digital_sequence_queue_pulse(DigitalSequence* sequence, uint32_t len } dma_buffer->buffer[dma_buffer->write_pos] = length; - dma_buffer->write_pos = (dma_buffer->write_pos + 1) % dma_buffer->size; - dma_buffer->buffer[dma_buffer->write_pos] = 0xFFFFFFFF; + dma_buffer->write_pos++; + dma_buffer->write_pos %= RINGBUFFER_SIZE; + dma_buffer->buffer[dma_buffer->write_pos] = SEQ_TIMER_MAX; } bool digital_sequence_send(DigitalSequence* sequence) { @@ -553,90 +553,97 @@ bool digital_sequence_send(DigitalSequence* sequence) { return true; } - int32_t remainder = 0; - bool traded_first = false; + if(!sequence->sequence_used) { + return false; + } - FURI_CRITICAL_ENTER(); + int32_t remainder = 0; + uint32_t trade_for_next = 0; + uint32_t seq_pos_next = 1; dma_buffer->dma_active = false; - dma_buffer->buffer[0] = 0xFFFFFFFF; + dma_buffer->buffer[0] = SEQ_TIMER_MAX; dma_buffer->read_pos = 0; dma_buffer->write_pos = 0; - for(uint32_t seq_pos = 0; seq_pos < sequence->sequence_used; seq_pos++) { - uint8_t signal_index = sequence->sequence[seq_pos]; - DigitalSignal* sig = sequence->signals[signal_index]; - bool last_signal = ((seq_pos + 1) == sequence->sequence_used); + /* already prepare the current signal pointer */ + DigitalSignal* sig = sequence->signals[sequence->sequence[0]]; + DigitalSignal* sig_next = NULL; + /* re-use the GPIO buffer from the first signal */ + sequence->gpio_buff = sig->internals->gpio_buff; + + FURI_CRITICAL_ENTER(); + + while(sig) { + bool last_signal = (seq_pos_next >= sequence->sequence_used); - /* all signals are prepared and we can re-use the GPIO buffer from the fist signal */ - if(seq_pos == 0) { - sequence->gpio_buff = sig->internals->gpio_buff; + if(!last_signal) { + sig_next = sequence->signals[sequence->sequence[seq_pos_next++]]; } for(uint32_t pulse_pos = 0; pulse_pos < sig->internals->reload_reg_entries; pulse_pos++) { - if(traded_first) { - traded_first = false; - continue; - } - uint32_t pulse_length = 0; - bool last_pulse = ((pulse_pos + 1) == sig->internals->reload_reg_entries); + bool last_pulse = ((pulse_pos + 1) >= sig->internals->reload_reg_entries); + uint32_t pulse_length = sig->reload_reg_buff[pulse_pos] + trade_for_next; - pulse_length = sig->reload_reg_buff[pulse_pos]; + trade_for_next = 0; /* when we are too late more than half a tick, make the first edge temporarily longer */ if(remainder >= T_TIM_DIV2) { remainder -= T_TIM; pulse_length += 1; } - remainder += sig->internals->reload_reg_remainder; - - /* last pulse in that signal and have a next signal? */ - if(last_pulse) { - if((seq_pos + 1) < sequence->sequence_used) { - DigitalSignal* sig_next = sequence->signals[sequence->sequence[seq_pos + 1]]; - /* when a signal ends with the same level as the next signal begins, let the fist signal generate the whole pulse */ - /* beware, we do not want the level after the last edge, but the last level before that edge */ - bool end_level = sig->start_level ^ ((sig->edge_cnt % 2) == 0); + /* last pulse in current signal and have a next signal? */ + if(last_pulse && sig_next) { + /* when a signal ends with the same level as the next signal begins, let the next signal generate the whole pulse. + beware, we do not want the level after the last edge, but the last level before that edge */ + bool end_level = sig->start_level ^ ((sig->edge_cnt % 2) == 0); - /* take from the next, add it to the current if they have the same level */ - if(end_level == sig_next->start_level) { - pulse_length += sig_next->reload_reg_buff[0]; - traded_first = true; - } + /* if they have the same level, pass the duration to the next pulse(s) */ + if(end_level == sig_next->start_level) { + trade_for_next = pulse_length; } } - digital_sequence_queue_pulse(sequence, pulse_length); + /* if it was decided, that the next signal's first pulse shall also handle our "length", then do not queue here */ + if(!trade_for_next) { + digital_sequence_queue_pulse(sequence, pulse_length); - /* start transmission when buffer was filled enough */ - bool start_send = sequence->dma_buffer->write_pos >= (sequence->dma_buffer->size - 4); - - /* or it was the last pulse */ - if(last_pulse && last_signal) { - start_send = true; - } + if(!dma_buffer->dma_active) { + /* start transmission when buffer was filled enough */ + bool start_send = sequence->dma_buffer->write_pos >= (RINGBUFFER_SIZE - 2); - /* start transmission */ - if(start_send && !dma_buffer->dma_active) { - digital_sequence_setup_dma(sequence); - digital_signal_setup_timer(); + /* or it was the last pulse */ + if(last_pulse && last_signal) { + start_send = true; + } - /* if the send time is specified, wait till the core timer passed beyond that time */ - if(sequence->send_time_active) { - sequence->send_time_active = false; - while(sequence->send_time - DWT->CYCCNT < 0x80000000) { + /* start transmission */ + if(start_send) { + digital_sequence_setup_dma(sequence); + digital_signal_setup_timer(); + + /* if the send time is specified, wait till the core timer passed beyond that time */ + if(sequence->send_time_active) { + sequence->send_time_active = false; + while(sequence->send_time - DWT->CYCCNT < 0x80000000) { + } + } + digital_signal_start_timer(); + dma_buffer->dma_active = true; } } - digital_signal_start_timer(); - dma_buffer->dma_active = true; } } + + remainder += sig->internals->reload_reg_remainder; + sig = sig_next; + sig_next = NULL; } /* wait until last dma transaction was finished */ - digital_sequence_finish(sequence); FURI_CRITICAL_EXIT(); + digital_sequence_finish(sequence); return true; } diff --git a/lib/flipper_application/api_hashtable/api_hashtable.cpp b/lib/flipper_application/api_hashtable/api_hashtable.cpp index 022792dce63b..6db5fb5fde64 100644 --- a/lib/flipper_application/api_hashtable/api_hashtable.cpp +++ b/lib/flipper_application/api_hashtable/api_hashtable.cpp @@ -7,27 +7,22 @@ bool elf_resolve_from_hashtable( const ElfApiInterface* interface, - const char* name, + uint32_t hash, Elf32_Addr* address) { + bool result = false; const HashtableApiInterface* hashtable_interface = static_cast(interface); - bool result = false; - uint32_t gnu_sym_hash = elf_gnu_hash(name); sym_entry key = { - .hash = gnu_sym_hash, + .hash = hash, .address = 0, }; auto find_res = std::lower_bound(hashtable_interface->table_cbegin, hashtable_interface->table_cend, key); - if((find_res == hashtable_interface->table_cend || (find_res->hash != gnu_sym_hash))) { + if((find_res == hashtable_interface->table_cend || (find_res->hash != hash))) { FURI_LOG_W( - TAG, - "Can't find symbol '%s' (hash %lx) @ %p!", - name, - gnu_sym_hash, - hashtable_interface->table_cbegin); + TAG, "Can't find symbol with hash %lx @ %p!", hash, hashtable_interface->table_cbegin); result = false; } else { result = true; @@ -36,3 +31,7 @@ bool elf_resolve_from_hashtable( return result; } + +uint32_t elf_symbolname_hash(const char* s) { + return elf_gnu_hash(s); +} \ No newline at end of file diff --git a/lib/flipper_application/api_hashtable/api_hashtable.h b/lib/flipper_application/api_hashtable/api_hashtable.h index 7e4b4aba1dd3..7ba6aab9727c 100644 --- a/lib/flipper_application/api_hashtable/api_hashtable.h +++ b/lib/flipper_application/api_hashtable/api_hashtable.h @@ -19,15 +19,17 @@ struct sym_entry { /** * @brief Resolver for API entries using a pre-sorted table with hashes * @param interface pointer to HashtableApiInterface - * @param name function name + * @param hash gnu hash of function name * @param address output for function address * @return true if the table contains a function */ bool elf_resolve_from_hashtable( const ElfApiInterface* interface, - const char* name, + uint32_t hash, Elf32_Addr* address); +uint32_t elf_symbolname_hash(const char* s); + #ifdef __cplusplus } @@ -48,8 +50,10 @@ struct HashtableApiInterface : public ElfApiInterface { .hash = elf_gnu_hash(#x), .address = (uint32_t)(static_cast(x)) \ } -#define API_VARIABLE(x, var_type) \ - sym_entry { .hash = elf_gnu_hash(#x), .address = (uint32_t)(&(x)), } +#define API_VARIABLE(x, var_type) \ + sym_entry { \ + .hash = elf_gnu_hash(#x), .address = (uint32_t)(&(x)), \ + } constexpr bool operator<(const sym_entry& k1, const sym_entry& k2) { return k1.hash < k2.hash; diff --git a/lib/flipper_application/elf/elf_api_interface.h b/lib/flipper_application/elf/elf_api_interface.h index f07df4edb763..facdc44473d6 100644 --- a/lib/flipper_application/elf/elf_api_interface.h +++ b/lib/flipper_application/elf/elf_api_interface.h @@ -11,6 +11,6 @@ typedef struct ElfApiInterface { uint16_t api_version_minor; bool (*resolver_callback)( const struct ElfApiInterface* interface, - const char* name, + uint32_t hash, Elf32_Addr* address); } ElfApiInterface; diff --git a/lib/flipper_application/elf/elf_file.c b/lib/flipper_application/elf/elf_file.c index 0338144a9a74..fc9dd06ba818 100644 --- a/lib/flipper_application/elf/elf_file.c +++ b/lib/flipper_application/elf/elf_file.c @@ -2,6 +2,7 @@ #include "elf_file.h" #include "elf_file_i.h" #include "elf_api_interface.h" +#include "../api_hashtable/api_hashtable.h" #define TAG "elf" @@ -9,6 +10,7 @@ #define SECTION_OFFSET(e, n) ((e)->section_table + (n) * sizeof(Elf32_Shdr)) #define IS_FLAGS_SET(v, m) (((v) & (m)) == (m)) #define RESOLVER_THREAD_YIELD_STEP 30 +#define FAST_RELOCATION_VERSION 1 // #define ELF_DEBUG_LOG 1 @@ -71,6 +73,7 @@ static ELFSection* elf_file_get_or_put_section(ELFFile* elf, const char* name) { .size = 0, .rel_count = 0, .rel_offset = 0, + .fast_rel = NULL, }); section_p = elf_file_get_section(elf, name); } @@ -168,7 +171,8 @@ static ELFSection* elf_section_of(ELFFile* elf, int index) { static Elf32_Addr elf_address_of(ELFFile* elf, Elf32_Sym* sym, const char* sName) { if(sym->st_shndx == SHN_UNDEF) { Elf32_Addr addr = 0; - if(elf->api_interface->resolver_callback(elf->api_interface, sName, &addr)) { + uint32_t hash = elf_symbolname_hash(sName); + if(elf->api_interface->resolver_callback(elf->api_interface, hash, &addr)) { return addr; } } else { @@ -424,6 +428,7 @@ typedef enum { SectionTypeSymTab = 1 << 3, SectionTypeStrTab = 1 << 4, SectionTypeDebugLink = 1 << 5, + SectionTypeFastRelData = 1 << 6, SectionTypeValid = SectionTypeSymTab | SectionTypeStrTab, } SectionType; @@ -505,7 +510,8 @@ static SectionType elf_preload_section( // TODO: how to do it not by name? // .ARM: type 0x70000001, flags SHF_ALLOC | SHF_LINK_ORDER // .rel.ARM: type 0x9, flags SHT_REL - if(str_prefix(name, ".ARM.") || str_prefix(name, ".rel.ARM.")) { + if(str_prefix(name, ".ARM.") || str_prefix(name, ".rel.ARM.") || + str_prefix(name, ".fast.rel.ARM.")) { FURI_LOG_D(TAG, "Ignoring ARM section"); return SectionTypeUnused; } @@ -536,11 +542,31 @@ static SectionType elf_preload_section( // Load link info section if(section_header->sh_flags & SHF_INFO_LINK) { - name = name + strlen(".rel"); + if(str_prefix(name, ".rel")) { + name = name + strlen(".rel"); + ELFSection* section_p = elf_file_get_or_put_section(elf, name); + section_p->rel_count = section_header->sh_size / sizeof(Elf32_Rel); + section_p->rel_offset = section_header->sh_offset; + return SectionTypeRelData; + } else { + FURI_LOG_E(TAG, "Unknown link info section '%s'", name); + return SectionTypeERROR; + } + } + + // Load fast rel section + if(str_prefix(name, ".fast.rel")) { + name = name + strlen(".fast.rel"); ELFSection* section_p = elf_file_get_or_put_section(elf, name); - section_p->rel_count = section_header->sh_size / sizeof(Elf32_Rel); - section_p->rel_offset = section_header->sh_offset; - return SectionTypeRelData; + section_p->fast_rel = malloc(sizeof(ELFSection)); + + if(!elf_load_section_data(elf, section_p->fast_rel, section_header)) { + FURI_LOG_E(TAG, "Error loading section '%s'", name); + return SectionTypeERROR; + } + + FURI_LOG_D(TAG, "Loaded fast rel section for '%s'", name); + return SectionTypeFastRelData; } // Load symbol table @@ -571,8 +597,90 @@ static SectionType elf_preload_section( return SectionTypeUnused; } +static Elf32_Addr elf_address_of_by_hash(ELFFile* elf, uint32_t hash) { + Elf32_Addr addr = 0; + if(elf->api_interface->resolver_callback(elf->api_interface, hash, &addr)) { + return addr; + } + return ELF_INVALID_ADDRESS; +} + +static bool elf_relocate_fast(ELFFile* elf, ELFSection* s) { + UNUSED(elf); + const uint8_t* start = s->fast_rel->data; + const uint8_t version = *start; + + if(version != FAST_RELOCATION_VERSION) { + FURI_LOG_E(TAG, "Unsupported fast relocation version %d", version); + return false; + } + start += 1; + + const uint32_t records_count = *((uint32_t*)start); + start += 4; + FURI_LOG_D(TAG, "Fast relocation records count: %ld", records_count); + + for(uint32_t i = 0; i < records_count; i++) { + bool is_section = (*start & (0x1 << 7)) ? true : false; + uint8_t type = *start & 0x7F; + start += 1; + uint32_t hash_or_section_index = *((uint32_t*)start); + start += 4; + + uint32_t section_value = ELF_INVALID_ADDRESS; + if(is_section) { + section_value = *((uint32_t*)start); + start += 4; + } + + const uint32_t offsets_count = *((uint32_t*)start); + start += 4; + + FURI_LOG_D( + TAG, + "Fast relocation record %ld: is_section=%d, type=%d, hash_or_section_index=%lX, offsets_count=%ld", + i, + is_section, + type, + hash_or_section_index, + offsets_count); + + Elf32_Addr address = 0; + if(is_section) { + ELFSection* symSec = elf_section_of(elf, hash_or_section_index); + if(symSec) { + address = ((Elf32_Addr)symSec->data) + section_value; + } + } else { + address = elf_address_of_by_hash(elf, hash_or_section_index); + } + + if(address == ELF_INVALID_ADDRESS) { + FURI_LOG_E(TAG, "Failed to resolve address for hash %lX", hash_or_section_index); + return false; + } + + for(uint32_t j = 0; j < offsets_count; j++) { + uint32_t offset = *((uint32_t*)start) & 0x00FFFFFF; + start += 3; + // FURI_LOG_I(TAG, " Fast relocation offset %ld: %ld", j, offset); + Elf32_Addr relAddr = ((Elf32_Addr)s->data) + offset; + elf_relocate_symbol(elf, relAddr, type, address); + } + } + + aligned_free(s->fast_rel->data); + free(s->fast_rel); + s->fast_rel = NULL; + + return true; +} + static bool elf_relocate_section(ELFFile* elf, ELFSection* section) { - if(section->rel_count) { + if(section->fast_rel) { + FURI_LOG_D(TAG, "Fast relocating section"); + return elf_relocate_fast(elf, section); + } else if(section->rel_count) { FURI_LOG_D(TAG, "Relocating section"); return elf_relocate(elf, section); } else { @@ -630,6 +738,10 @@ void elf_file_free(ELFFile* elf) { if(itref->value.data) { aligned_free(itref->value.data); } + if(itref->value.fast_rel) { + aligned_free(itref->value.fast_rel->data); + free(itref->value.fast_rel); + } free((void*)itref->key); } diff --git a/lib/flipper_application/elf/elf_file_i.h b/lib/flipper_application/elf/elf_file_i.h index af9a1d9b4fbc..39cadfdc6f6d 100644 --- a/lib/flipper_application/elf/elf_file_i.h +++ b/lib/flipper_application/elf/elf_file_i.h @@ -13,14 +13,18 @@ DICT_DEF2(AddressCache, int, M_DEFAULT_OPLIST, Elf32_Addr, M_DEFAULT_OPLIST) */ typedef int32_t(entry_t)(void*); -typedef struct { +typedef struct ELFSection ELFSection; + +struct ELFSection { void* data; - uint16_t sec_idx; Elf32_Word size; size_t rel_count; Elf32_Off rel_offset; -} ELFSection; + ELFSection* fast_rel; + + uint16_t sec_idx; +}; DICT_DEF2(ELFSectionDict, const char*, M_CSTR_OPLIST, ELFSection, M_POD_OPLIST) diff --git a/lib/flipper_application/flipper_application.c b/lib/flipper_application/flipper_application.c index 1b4f5681486c..fbcf2973dbed 100644 --- a/lib/flipper_application/flipper_application.c +++ b/lib/flipper_application/flipper_application.c @@ -2,6 +2,7 @@ #include "elf/elf_file.h" #include #include "application_assets.h" +#include #include @@ -81,6 +82,12 @@ void flipper_application_free(FlipperApplication* app) { } elf_file_free(app->elf); + + if(app->ep_thread_args) { + free(app->ep_thread_args); + app->ep_thread_args = NULL; + } + free(app); } @@ -224,10 +231,19 @@ static int32_t flipper_application_thread(void* context) { return ret_code; } -FuriThread* flipper_application_spawn(FlipperApplication* app, void* args) { +FuriThread* flipper_application_alloc_thread(FlipperApplication* app, const char* args) { furi_check(app->thread == NULL); furi_check(!flipper_application_is_plugin(app)); - app->ep_thread_args = args; + + if(app->ep_thread_args) { + free(app->ep_thread_args); + } + + if(args) { + app->ep_thread_args = strdup(args); + } else { + app->ep_thread_args = NULL; + } const FlipperApplicationManifest* manifest = flipper_application_get_manifest(app); app->thread = furi_thread_alloc_ex( @@ -289,4 +305,32 @@ const FlipperAppPluginDescriptor* lib_descriptor->ep_api_version); return lib_descriptor; +} + +bool flipper_application_load_name_and_icon( + FuriString* path, + Storage* storage, + uint8_t** icon_ptr, + FuriString* item_name) { + FlipperApplication* app = flipper_application_alloc(storage, firmware_api_interface); + + FlipperApplicationPreloadStatus preload_res = + flipper_application_preload_manifest(app, furi_string_get_cstr(path)); + + bool load_success = false; + + if(preload_res == FlipperApplicationPreloadStatusSuccess) { + const FlipperApplicationManifest* manifest = flipper_application_get_manifest(app); + if(manifest->has_icon) { + memcpy(*icon_ptr, manifest->icon, FAP_MANIFEST_MAX_ICON_SIZE); + } + furi_string_set(item_name, manifest->name); + load_success = true; + } else { + FURI_LOG_E(TAG, "Failed to preload %s", furi_string_get_cstr(path)); + load_success = false; + } + + flipper_application_free(app); + return load_success; } \ No newline at end of file diff --git a/lib/flipper_application/flipper_application.h b/lib/flipper_application/flipper_application.h index 519cc397108c..20baae8264f2 100644 --- a/lib/flipper_application/flipper_application.h +++ b/lib/flipper_application/flipper_application.h @@ -106,14 +106,14 @@ const FlipperApplicationManifest* flipper_application_get_manifest(FlipperApplic FlipperApplicationLoadStatus flipper_application_map_to_memory(FlipperApplication* app); /** - * @brief Create application thread at entry point address, using app name and + * @brief Allocate application thread at entry point address, using app name and * stack size from metadata. Returned thread isn't started yet. * Can be only called once for application instance. * @param app Applicaiton pointer - * @param args Object to pass to app's entry point + * @param args Args to pass to app's entry point * @return Created thread */ -FuriThread* flipper_application_spawn(FlipperApplication* app, void* args); +FuriThread* flipper_application_alloc_thread(FlipperApplication* app, const char* args); /** * @brief Check if application is a plugin (not a runnable standalone app) @@ -149,6 +149,21 @@ typedef const FlipperAppPluginDescriptor* (*FlipperApplicationPluginEntryPoint)( const FlipperAppPluginDescriptor* flipper_application_plugin_get_descriptor(FlipperApplication* app); +/** + * @brief Load name and icon from FAP file. + * + * @param path Path to FAP file. + * @param storage Storage instance. + * @param icon_ptr Icon pointer. + * @param item_name Application name. + * @return true if icon and name were loaded successfully. + */ +bool flipper_application_load_name_and_icon( + FuriString* path, + Storage* storage, + uint8_t** icon_ptr, + FuriString* item_name); + #ifdef __cplusplus } #endif diff --git a/lib/flipper_application/plugins/composite_resolver.c b/lib/flipper_application/plugins/composite_resolver.c index 1402c3ad08fa..7cc2b340a96d 100644 --- a/lib/flipper_application/plugins/composite_resolver.c +++ b/lib/flipper_application/plugins/composite_resolver.c @@ -13,12 +13,12 @@ struct CompositeApiResolver { static bool composite_api_resolver_callback( const ElfApiInterface* interface, - const char* name, + uint32_t hash, Elf32_Addr* address) { CompositeApiResolver* resolver = (CompositeApiResolver*)interface; for M_EACH(interface, resolver->interfaces, ElfApiInterfaceList_t) { - if((*interface)->resolver_callback(*interface, name, address)) { + if((*interface)->resolver_callback(*interface, hash, address)) { return true; } } diff --git a/lib/music_worker/SConscript b/lib/music_worker/SConscript new file mode 100644 index 000000000000..36d01d8596ab --- /dev/null +++ b/lib/music_worker/SConscript @@ -0,0 +1,27 @@ +Import("env") + +env.Append( + CPPPATH=[ + "#/lib/music_worker", + ], + SDK_HEADERS=[ + File("music_worker.h"), + ], +) + +libenv = env.Clone(FW_LIB_NAME="music_worker") +libenv.ApplyLibFlags() + +libenv.AppendUnique( + CCFLAGS=[ + # Required for lib to be linkable with .faps + "-mword-relocations", + "-mlong-calls", + ], +) + +sources = libenv.GlobRecursive("*.c*") + +lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) +libenv.Install("${LIB_DIST_DIR}", lib) +Return("lib") diff --git a/applications/external/music_player/music_player_worker.c b/lib/music_worker/music_worker.c similarity index 85% rename from applications/external/music_player/music_player_worker.c rename to lib/music_worker/music_worker.c index ee350ee80455..61fc838f2e36 100644 --- a/applications/external/music_player/music_player_worker.c +++ b/lib/music_worker/music_worker.c @@ -1,4 +1,4 @@ -#include "music_player_worker.h" +#include "music_worker.h" #include #include @@ -9,7 +9,7 @@ #include #include -#define TAG "MusicPlayerWorker" +#define TAG "MusicWorker" #define MUSIC_PLAYER_FILETYPE "Flipper Music Format" #define MUSIC_PLAYER_VERSION 0 @@ -28,11 +28,11 @@ typedef struct { ARRAY_DEF(NoteBlockArray, NoteBlock, M_POD_OPLIST); -struct MusicPlayerWorker { +struct MusicWorker { FuriThread* thread; bool should_work; - MusicPlayerWorkerCallback callback; + MusicWorkerCallback callback; void* callback_context; float volume; @@ -42,9 +42,9 @@ struct MusicPlayerWorker { NoteBlockArray_t notes; }; -static int32_t music_player_worker_thread_callback(void* context) { +static int32_t music_worker_thread_callback(void* context) { furi_assert(context); - MusicPlayerWorker* instance = context; + MusicWorker* instance = context; NoteBlockArray_it_t it; NoteBlockArray_it(it, instance->notes); @@ -97,24 +97,24 @@ static int32_t music_player_worker_thread_callback(void* context) { return 0; } -MusicPlayerWorker* music_player_worker_alloc() { - MusicPlayerWorker* instance = malloc(sizeof(MusicPlayerWorker)); +MusicWorker* music_worker_alloc() { + MusicWorker* instance = malloc(sizeof(MusicWorker)); NoteBlockArray_init(instance->notes); - instance->thread = furi_thread_alloc_ex( - "MusicPlayerWorker", 1024, music_player_worker_thread_callback, instance); + instance->thread = + furi_thread_alloc_ex("MusicWorker", 1024, music_worker_thread_callback, instance); instance->volume = 1.0f; return instance; } -void music_player_worker_clear(MusicPlayerWorker* instance) { +void music_worker_clear(MusicWorker* instance) { NoteBlockArray_reset(instance->notes); } -void music_player_worker_free(MusicPlayerWorker* instance) { +void music_worker_free(MusicWorker* instance) { furi_assert(instance); furi_thread_free(instance->thread); NoteBlockArray_clear(instance->notes); @@ -186,11 +186,8 @@ static size_t skip_till(const char* string, const char symbol) { return ret; } -static bool music_player_worker_add_note( - MusicPlayerWorker* instance, - uint8_t semitone, - uint8_t duration, - uint8_t dots) { +static bool + music_worker_add_note(MusicWorker* instance, uint8_t semitone, uint8_t duration, uint8_t dots) { NoteBlock note_block; note_block.semitone = semitone; @@ -228,7 +225,7 @@ static int8_t note_to_semitone(const char note) { } } -static bool music_player_worker_parse_notes(MusicPlayerWorker* instance, const char* string) { +static bool music_worker_parse_notes(MusicWorker* instance, const char* string) { const char* cursor = string; bool result = true; @@ -286,7 +283,7 @@ static bool music_player_worker_parse_notes(MusicPlayerWorker* instance, const c semitone += sharp_char == '#' ? 1 : 0; } - if(music_player_worker_add_note(instance, semitone, duration, dots)) { + if(music_worker_add_note(instance, semitone, duration, dots)) { FURI_LOG_D( TAG, "Added note: %c%c%lu.%lu = %u %lu", @@ -316,20 +313,20 @@ static bool music_player_worker_parse_notes(MusicPlayerWorker* instance, const c return result; } -bool music_player_worker_load(MusicPlayerWorker* instance, const char* file_path) { +bool music_worker_load(MusicWorker* instance, const char* file_path) { furi_assert(instance); furi_assert(file_path); bool ret = false; if(strcasestr(file_path, ".fmf")) { - ret = music_player_worker_load_fmf_from_file(instance, file_path); + ret = music_worker_load_fmf_from_file(instance, file_path); } else { - ret = music_player_worker_load_rtttl_from_file(instance, file_path); + ret = music_worker_load_rtttl_from_file(instance, file_path); } return ret; } -bool music_player_worker_load_fmf_from_file(MusicPlayerWorker* instance, const char* file_path) { +bool music_worker_load_fmf_from_file(MusicWorker* instance, const char* file_path) { furi_assert(instance); furi_assert(file_path); @@ -369,7 +366,7 @@ bool music_player_worker_load_fmf_from_file(MusicPlayerWorker* instance, const c break; } - if(!music_player_worker_parse_notes(instance, furi_string_get_cstr(temp_str))) { + if(!music_worker_parse_notes(instance, furi_string_get_cstr(temp_str))) { break; } @@ -383,7 +380,7 @@ bool music_player_worker_load_fmf_from_file(MusicPlayerWorker* instance, const c return result; } -bool music_player_worker_load_rtttl_from_file(MusicPlayerWorker* instance, const char* file_path) { +bool music_worker_load_rtttl_from_file(MusicWorker* instance, const char* file_path) { furi_assert(instance); furi_assert(file_path); @@ -414,7 +411,7 @@ bool music_player_worker_load_rtttl_from_file(MusicPlayerWorker* instance, const break; } - if(!music_player_worker_load_rtttl_from_string(instance, furi_string_get_cstr(content))) { + if(!music_worker_load_rtttl_from_string(instance, furi_string_get_cstr(content))) { FURI_LOG_E(TAG, "Invalid file content"); break; } @@ -429,7 +426,7 @@ bool music_player_worker_load_rtttl_from_file(MusicPlayerWorker* instance, const return result; } -bool music_player_worker_load_rtttl_from_string(MusicPlayerWorker* instance, const char* string) { +bool music_worker_load_rtttl_from_string(MusicWorker* instance, const char* string) { furi_assert(instance); const char* cursor = string; @@ -470,28 +467,25 @@ bool music_player_worker_load_rtttl_from_string(MusicPlayerWorker* instance, con return false; } cursor++; - if(!music_player_worker_parse_notes(instance, cursor)) { + if(!music_worker_parse_notes(instance, cursor)) { return false; } return true; } -void music_player_worker_set_callback( - MusicPlayerWorker* instance, - MusicPlayerWorkerCallback callback, - void* context) { +void music_worker_set_callback(MusicWorker* instance, MusicWorkerCallback callback, void* context) { furi_assert(instance); instance->callback = callback; instance->callback_context = context; } -void music_player_worker_set_volume(MusicPlayerWorker* instance, float volume) { +void music_worker_set_volume(MusicWorker* instance, float volume) { furi_assert(instance); instance->volume = volume; } -void music_player_worker_start(MusicPlayerWorker* instance) { +void music_worker_start(MusicWorker* instance) { furi_assert(instance); furi_assert(instance->should_work == false); @@ -499,10 +493,15 @@ void music_player_worker_start(MusicPlayerWorker* instance) { furi_thread_start(instance->thread); } -void music_player_worker_stop(MusicPlayerWorker* instance) { +void music_worker_stop(MusicWorker* instance) { furi_assert(instance); furi_assert(instance->should_work == true); instance->should_work = false; furi_thread_join(instance->thread); } + +bool music_worker_is_playing(MusicWorker* instance) { + furi_assert(instance); + return instance->should_work; +} diff --git a/lib/music_worker/music_worker.h b/lib/music_worker/music_worker.h new file mode 100644 index 000000000000..5a7cb4936a9f --- /dev/null +++ b/lib/music_worker/music_worker.h @@ -0,0 +1,37 @@ +#pragma once + +#include +#include + +typedef void (*MusicWorkerCallback)( + uint8_t semitone, + uint8_t dots, + uint8_t duration, + float position, + void* context); + +typedef struct MusicWorker MusicWorker; + +MusicWorker* music_worker_alloc(); + +void music_worker_clear(MusicWorker* instance); + +void music_worker_free(MusicWorker* instance); + +bool music_worker_load(MusicWorker* instance, const char* file_path); + +bool music_worker_load_fmf_from_file(MusicWorker* instance, const char* file_path); + +bool music_worker_load_rtttl_from_file(MusicWorker* instance, const char* file_path); + +bool music_worker_load_rtttl_from_string(MusicWorker* instance, const char* string); + +void music_worker_set_callback(MusicWorker* instance, MusicWorkerCallback callback, void* context); + +void music_worker_set_volume(MusicWorker* instance, float volume); + +void music_worker_start(MusicWorker* instance); + +void music_worker_stop(MusicWorker* instance); + +bool music_worker_is_playing(MusicWorker* instance); diff --git a/lib/subghz/SConscript b/lib/subghz/SConscript index 3a0325b71db7..2c42a5157f21 100644 --- a/lib/subghz/SConscript +++ b/lib/subghz/SConscript @@ -19,6 +19,7 @@ env.Append( File("blocks/math.h"), File("subghz_setting.h"), File("subghz_protocol_registry.h"), + File("devices/cc1101_configs.h"), ], ) diff --git a/lib/subghz/devices/cc1101_configs.c b/lib/subghz/devices/cc1101_configs.c new file mode 100644 index 000000000000..35ddccd54f6d --- /dev/null +++ b/lib/subghz/devices/cc1101_configs.c @@ -0,0 +1,431 @@ +#include "cc1101_configs.h" +#include + +const uint8_t subghz_device_cc1101_preset_ook_270khz_async_regs[] = { + // https://e2e.ti.com/support/wireless-connectivity/sub-1-ghz-group/sub-1-ghz/f/sub-1-ghz-forum/382066/cc1101---don-t-know-the-correct-registers-configuration + + /* GPIO GD0 */ + CC1101_IOCFG0, + 0x0D, // GD0 as async serial data output/input + + /* FIFO and internals */ + CC1101_FIFOTHR, + 0x47, // The only important bit is ADC_RETENTION, FIFO Tx=33 Rx=32 + + /* Packet engine */ + CC1101_PKTCTRL0, + 0x32, // Async, continious, no whitening + + /* Frequency Synthesizer Control */ + CC1101_FSCTRL1, + 0x06, // IF = (26*10^6) / (2^10) * 0x06 = 152343.75Hz + + // Modem Configuration + CC1101_MDMCFG0, + 0x00, // Channel spacing is 25kHz + CC1101_MDMCFG1, + 0x00, // Channel spacing is 25kHz + CC1101_MDMCFG2, + 0x30, // Format ASK/OOK, No preamble/sync + CC1101_MDMCFG3, + 0x32, // Data rate is 3.79372 kBaud + CC1101_MDMCFG4, + 0x67, // Rx BW filter is 270.833333kHz + + /* Main Radio Control State Machine */ + CC1101_MCSM0, + 0x18, // Autocalibrate on idle-to-rx/tx, PO_TIMEOUT is 64 cycles(149-155us) + + /* Frequency Offset Compensation Configuration */ + CC1101_FOCCFG, + 0x18, // no frequency offset compensation, POST_K same as PRE_K, PRE_K is 4K, GATE is off + + /* Automatic Gain Control */ + CC1101_AGCCTRL0, + 0x40, // 01 - Low hysteresis, small asymmetric dead zone, medium gain; 00 - 8 samples agc; 00 - Normal AGC, 00 - 4dB boundary + CC1101_AGCCTRL1, + 0x00, // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 0000 - RSSI to MAIN_TARGET + CC1101_AGCCTRL2, + 0x03, // 00 - DVGA all; 000 - MAX LNA+LNA2; 011 - MAIN_TARGET 24 dB + + /* Wake on radio and timeouts control */ + CC1101_WORCTRL, + 0xFB, // WOR_RES is 2^15 periods (0.91 - 0.94 s) 16.5 - 17.2 hours + + /* Frontend configuration */ + CC1101_FREND0, + 0x11, // Adjusts current TX LO buffer + high is PATABLE[1] + CC1101_FREND1, + 0xB6, // + + /* End load reg */ + 0, + 0, + + //ook_async_patable[8] + 0x00, + 0xC0, // 12dBm 0xC0, 10dBm 0xC5, 7dBm 0xCD, 5dBm 0x86, 0dBm 0x50, -6dBm 0x37, -10dBm 0x26, -15dBm 0x1D, -20dBm 0x17, -30dBm 0x03 + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, +}; + +const uint8_t subghz_device_cc1101_preset_ook_650khz_async_regs[] = { + // https://e2e.ti.com/support/wireless-connectivity/sub-1-ghz-group/sub-1-ghz/f/sub-1-ghz-forum/382066/cc1101---don-t-know-the-correct-registers-configuration + + /* GPIO GD0 */ + CC1101_IOCFG0, + 0x0D, // GD0 as async serial data output/input + + /* FIFO and internals */ + CC1101_FIFOTHR, + 0x07, // The only important bit is ADC_RETENTION + + /* Packet engine */ + CC1101_PKTCTRL0, + 0x32, // Async, continious, no whitening + + /* Frequency Synthesizer Control */ + CC1101_FSCTRL1, + 0x06, // IF = (26*10^6) / (2^10) * 0x06 = 152343.75Hz + + // Modem Configuration + CC1101_MDMCFG0, + 0x00, // Channel spacing is 25kHz + CC1101_MDMCFG1, + 0x00, // Channel spacing is 25kHz + CC1101_MDMCFG2, + 0x30, // Format ASK/OOK, No preamble/sync + CC1101_MDMCFG3, + 0x32, // Data rate is 3.79372 kBaud + CC1101_MDMCFG4, + 0x17, // Rx BW filter is 650.000kHz + + /* Main Radio Control State Machine */ + CC1101_MCSM0, + 0x18, // Autocalibrate on idle-to-rx/tx, PO_TIMEOUT is 64 cycles(149-155us) + + /* Frequency Offset Compensation Configuration */ + CC1101_FOCCFG, + 0x18, // no frequency offset compensation, POST_K same as PRE_K, PRE_K is 4K, GATE is off + + /* Automatic Gain Control */ + // CC1101_AGCTRL0,0x40, // 01 - Low hysteresis, small asymmetric dead zone, medium gain; 00 - 8 samples agc; 00 - Normal AGC, 00 - 4dB boundary + // CC1101_AGCTRL1,0x00, // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 0000 - RSSI to MAIN_TARGET + // CC1101_AGCCTRL2, 0x03, // 00 - DVGA all; 000 - MAX LNA+LNA2; 011 - MAIN_TARGET 24 dB + //MAGN_TARGET for RX filter BW =< 100 kHz is 0x3. For higher RX filter BW's MAGN_TARGET is 0x7. + CC1101_AGCCTRL0, + 0x91, // 10 - Medium hysteresis, medium asymmetric dead zone, medium gain ; 01 - 16 samples agc; 00 - Normal AGC, 01 - 8dB boundary + CC1101_AGCCTRL1, + 0x0, // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 0000 - RSSI to MAIN_TARGET + CC1101_AGCCTRL2, + 0x07, // 00 - DVGA all; 000 - MAX LNA+LNA2; 111 - MAIN_TARGET 42 dB + + /* Wake on radio and timeouts control */ + CC1101_WORCTRL, + 0xFB, // WOR_RES is 2^15 periods (0.91 - 0.94 s) 16.5 - 17.2 hours + + /* Frontend configuration */ + CC1101_FREND0, + 0x11, // Adjusts current TX LO buffer + high is PATABLE[1] + CC1101_FREND1, + 0xB6, // + + /* End load reg */ + 0, + 0, + + //ook_async_patable[8] + 0x00, + 0xC0, // 12dBm 0xC0, 10dBm 0xC5, 7dBm 0xCD, 5dBm 0x86, 0dBm 0x50, -6dBm 0x37, -10dBm 0x26, -15dBm 0x1D, -20dBm 0x17, -30dBm 0x03 + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, +}; + +const uint8_t subghz_device_cc1101_preset_2fsk_dev2_38khz_async_regs[] = { + + /* GPIO GD0 */ + CC1101_IOCFG0, + 0x0D, // GD0 as async serial data output/input + + /* Frequency Synthesizer Control */ + CC1101_FSCTRL1, + 0x06, // IF = (26*10^6) / (2^10) * 0x06 = 152343.75Hz + + /* Packet engine */ + CC1101_PKTCTRL0, + 0x32, // Async, continious, no whitening + CC1101_PKTCTRL1, + 0x04, + + // // Modem Configuration + CC1101_MDMCFG0, + 0x00, + CC1101_MDMCFG1, + 0x02, + CC1101_MDMCFG2, + 0x04, // Format 2-FSK/FM, No preamble/sync, Disable (current optimized) + CC1101_MDMCFG3, + 0x83, // Data rate is 4.79794 kBaud + CC1101_MDMCFG4, + 0x67, //Rx BW filter is 270.833333 kHz + CC1101_DEVIATN, + 0x04, //Deviation 2.380371 kHz + + /* Main Radio Control State Machine */ + CC1101_MCSM0, + 0x18, // Autocalibrate on idle-to-rx/tx, PO_TIMEOUT is 64 cycles(149-155us) + + /* Frequency Offset Compensation Configuration */ + CC1101_FOCCFG, + 0x16, // no frequency offset compensation, POST_K same as PRE_K, PRE_K is 4K, GATE is off + + /* Automatic Gain Control */ + CC1101_AGCCTRL0, + 0x91, //10 - Medium hysteresis, medium asymmetric dead zone, medium gain ; 01 - 16 samples agc; 00 - Normal AGC, 01 - 8dB boundary + CC1101_AGCCTRL1, + 0x00, // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 0000 - RSSI to MAIN_TARGET + CC1101_AGCCTRL2, + 0x07, // 00 - DVGA all; 000 - MAX LNA+LNA2; 111 - MAIN_TARGET 42 dB + + /* Wake on radio and timeouts control */ + CC1101_WORCTRL, + 0xFB, // WOR_RES is 2^15 periods (0.91 - 0.94 s) 16.5 - 17.2 hours + + /* Frontend configuration */ + CC1101_FREND0, + 0x10, // Adjusts current TX LO buffer + CC1101_FREND1, + 0x56, + + /* End load reg */ + 0, + 0, + + // 2fsk_async_patable[8] + 0xC0, // 10dBm 0xC0, 7dBm 0xC8, 5dBm 0x84, 0dBm 0x60, -10dBm 0x34, -15dBm 0x1D, -20dBm 0x0E, -30dBm 0x12 + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, +}; + +const uint8_t subghz_device_cc1101_preset_2fsk_dev47_6khz_async_regs[] = { + + /* GPIO GD0 */ + CC1101_IOCFG0, + 0x0D, // GD0 as async serial data output/input + + /* Frequency Synthesizer Control */ + CC1101_FSCTRL1, + 0x06, // IF = (26*10^6) / (2^10) * 0x06 = 152343.75Hz + + /* Packet engine */ + CC1101_PKTCTRL0, + 0x32, // Async, continious, no whitening + CC1101_PKTCTRL1, + 0x04, + + // // Modem Configuration + CC1101_MDMCFG0, + 0x00, + CC1101_MDMCFG1, + 0x02, + CC1101_MDMCFG2, + 0x04, // Format 2-FSK/FM, No preamble/sync, Disable (current optimized) + CC1101_MDMCFG3, + 0x83, // Data rate is 4.79794 kBaud + CC1101_MDMCFG4, + 0x67, //Rx BW filter is 270.833333 kHz + CC1101_DEVIATN, + 0x47, //Deviation 47.60742 kHz + + /* Main Radio Control State Machine */ + CC1101_MCSM0, + 0x18, // Autocalibrate on idle-to-rx/tx, PO_TIMEOUT is 64 cycles(149-155us) + + /* Frequency Offset Compensation Configuration */ + CC1101_FOCCFG, + 0x16, // no frequency offset compensation, POST_K same as PRE_K, PRE_K is 4K, GATE is off + + /* Automatic Gain Control */ + CC1101_AGCCTRL0, + 0x91, //10 - Medium hysteresis, medium asymmetric dead zone, medium gain ; 01 - 16 samples agc; 00 - Normal AGC, 01 - 8dB boundary + CC1101_AGCCTRL1, + 0x00, // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 0000 - RSSI to MAIN_TARGET + CC1101_AGCCTRL2, + 0x07, // 00 - DVGA all; 000 - MAX LNA+LNA2; 111 - MAIN_TARGET 42 dB + + /* Wake on radio and timeouts control */ + CC1101_WORCTRL, + 0xFB, // WOR_RES is 2^15 periods (0.91 - 0.94 s) 16.5 - 17.2 hours + + /* Frontend configuration */ + CC1101_FREND0, + 0x10, // Adjusts current TX LO buffer + CC1101_FREND1, + 0x56, + + /* End load reg */ + 0, + 0, + + // 2fsk_async_patable[8] + 0xC0, // 10dBm 0xC0, 7dBm 0xC8, 5dBm 0x84, 0dBm 0x60, -10dBm 0x34, -15dBm 0x1D, -20dBm 0x0E, -30dBm 0x12 + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, +}; + +const uint8_t subghz_device_cc1101_preset_msk_99_97kb_async_regs[] = { + /* GPIO GD0 */ + CC1101_IOCFG0, + 0x06, + + CC1101_FIFOTHR, + 0x07, // The only important bit is ADC_RETENTION + CC1101_SYNC1, + 0x46, + CC1101_SYNC0, + 0x4C, + CC1101_ADDR, + 0x00, + CC1101_PKTLEN, + 0x00, + CC1101_CHANNR, + 0x00, + + CC1101_PKTCTRL0, + 0x05, + + CC1101_FSCTRL0, + 0x23, + CC1101_FSCTRL1, + 0x06, + + CC1101_MDMCFG0, + 0xF8, + CC1101_MDMCFG1, + 0x22, + CC1101_MDMCFG2, + 0x72, + CC1101_MDMCFG3, + 0xF8, + CC1101_MDMCFG4, + 0x5B, + CC1101_DEVIATN, + 0x47, + + CC1101_MCSM0, + 0x18, + CC1101_FOCCFG, + 0x16, + + CC1101_AGCCTRL0, + 0xB2, + CC1101_AGCCTRL1, + 0x00, + CC1101_AGCCTRL2, + 0xC7, + + CC1101_FREND0, + 0x10, + CC1101_FREND1, + 0x56, + + CC1101_BSCFG, + 0x1C, + CC1101_FSTEST, + 0x59, + + /* End load reg */ + 0, + 0, + + // msk_async_patable[8] + 0xC0, // 10dBm 0xC0, 7dBm 0xC8, 5dBm 0x84, 0dBm 0x60, -10dBm 0x34, -15dBm 0x1D, -20dBm 0x0E, -30dBm 0x12 + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, +}; + +const uint8_t subghz_device_cc1101_preset_gfsk_9_99kb_async_regs[] = { + + CC1101_IOCFG0, + 0x06, //GDO0 Output Pin Configuration + CC1101_FIFOTHR, + 0x47, //RX FIFO and TX FIFO Thresholds + + //1 : CRC calculation in TX and CRC check in RX enabled, + //1 : Variable packet length mode. Packet length configured by the first byte after sync word + CC1101_PKTCTRL0, + 0x05, + + CC1101_FSCTRL1, + 0x06, //Frequency Synthesizer Control + + CC1101_SYNC1, + 0x46, + CC1101_SYNC0, + 0x4C, + CC1101_ADDR, + 0x00, + CC1101_PKTLEN, + 0x00, + + CC1101_MDMCFG4, + 0xC8, //Modem Configuration 9.99 + CC1101_MDMCFG3, + 0x93, //Modem Configuration + CC1101_MDMCFG2, + 0x12, // 2: 16/16 sync word bits detected + + CC1101_DEVIATN, + 0x34, //Deviation = 19.042969 + CC1101_MCSM0, + 0x18, //Main Radio Control State Machine Configuration + CC1101_FOCCFG, + 0x16, //Frequency Offset Compensation Configuration + + CC1101_AGCCTRL2, + 0x43, //AGC Control + CC1101_AGCCTRL1, + 0x40, + CC1101_AGCCTRL0, + 0x91, + + CC1101_WORCTRL, + 0xFB, //Wake On Radio Control + + /* End load reg */ + 0, + 0, + + // gfsk_async_patable[8] + 0xC0, // 10dBm 0xC0, 7dBm 0xC8, 5dBm 0x84, 0dBm 0x60, -10dBm 0x34, -15dBm 0x1D, -20dBm 0x0E, -30dBm 0x12 + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, +}; diff --git a/lib/subghz/devices/cc1101_configs.h b/lib/subghz/devices/cc1101_configs.h new file mode 100644 index 000000000000..eecab01d999e --- /dev/null +++ b/lib/subghz/devices/cc1101_configs.h @@ -0,0 +1,18 @@ +#pragma once +#pragma once +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern const uint8_t subghz_device_cc1101_preset_ook_270khz_async_regs[]; +extern const uint8_t subghz_device_cc1101_preset_ook_650khz_async_regs[]; +extern const uint8_t subghz_device_cc1101_preset_2fsk_dev2_38khz_async_regs[]; +extern const uint8_t subghz_device_cc1101_preset_2fsk_dev47_6khz_async_regs[]; +extern const uint8_t subghz_device_cc1101_preset_msk_99_97kb_async_regs[]; +extern const uint8_t subghz_device_cc1101_preset_gfsk_9_99kb_async_regs[]; + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/lib/subghz/devices/cc1101_int/cc1101_int_interconnect.c b/lib/subghz/devices/cc1101_int/cc1101_int_interconnect.c new file mode 100644 index 000000000000..41a0609df00c --- /dev/null +++ b/lib/subghz/devices/cc1101_int/cc1101_int_interconnect.c @@ -0,0 +1,96 @@ +#include "cc1101_int_interconnect.h" +#include +#include "../cc1101_configs.h" + +#define TAG "SubGhzDeviceCC1101Int" + +static bool subghz_device_cc1101_int_interconnect_is_frequency_valid(uint32_t frequency) { + bool ret = furi_hal_subghz_is_frequency_valid(frequency); + if(!ret) { + furi_crash("SubGhz: Incorrect frequency."); + } + return ret; +} + +static uint32_t subghz_device_cc1101_int_interconnect_set_frequency(uint32_t frequency) { + subghz_device_cc1101_int_interconnect_is_frequency_valid(frequency); + return furi_hal_subghz_set_frequency_and_path(frequency); +} + +static bool subghz_device_cc1101_int_interconnect_start_async_tx(void* callback, void* context) { + return furi_hal_subghz_start_async_tx((FuriHalSubGhzAsyncTxCallback)callback, context); +} + +static void subghz_device_cc1101_int_interconnect_start_async_rx(void* callback, void* context) { + furi_hal_subghz_start_async_rx((FuriHalSubGhzCaptureCallback)callback, context); +} + +static void subghz_device_cc1101_int_interconnect_load_preset( + FuriHalSubGhzPreset preset, + uint8_t* preset_data) { + switch(preset) { + case FuriHalSubGhzPresetOok650Async: + furi_hal_subghz_load_custom_preset(subghz_device_cc1101_preset_ook_650khz_async_regs); + break; + case FuriHalSubGhzPresetOok270Async: + furi_hal_subghz_load_custom_preset(subghz_device_cc1101_preset_ook_270khz_async_regs); + break; + case FuriHalSubGhzPreset2FSKDev238Async: + furi_hal_subghz_load_custom_preset(subghz_device_cc1101_preset_2fsk_dev2_38khz_async_regs); + break; + case FuriHalSubGhzPreset2FSKDev476Async: + furi_hal_subghz_load_custom_preset(subghz_device_cc1101_preset_2fsk_dev47_6khz_async_regs); + break; + case FuriHalSubGhzPresetMSK99_97KbAsync: + furi_hal_subghz_load_custom_preset(subghz_device_cc1101_preset_msk_99_97kb_async_regs); + break; + case FuriHalSubGhzPresetGFSK9_99KbAsync: + furi_hal_subghz_load_custom_preset(subghz_device_cc1101_preset_gfsk_9_99kb_async_regs); + break; + + default: + furi_hal_subghz_load_custom_preset(preset_data); + } +} + +static bool subghz_device_cc1101_int_interconnect_is_connect(void) { + return true; +} + +const SubGhzDeviceInterconnect subghz_device_cc1101_int_interconnect = { + .begin = NULL, + .end = furi_hal_subghz_shutdown, + .is_connect = subghz_device_cc1101_int_interconnect_is_connect, + .reset = furi_hal_subghz_reset, + .sleep = furi_hal_subghz_sleep, + .idle = furi_hal_subghz_idle, + .load_preset = subghz_device_cc1101_int_interconnect_load_preset, + .set_frequency = subghz_device_cc1101_int_interconnect_set_frequency, + .is_frequency_valid = furi_hal_subghz_is_frequency_valid, + .set_async_mirror_pin = furi_hal_subghz_set_async_mirror_pin, + .get_data_gpio = furi_hal_subghz_get_data_gpio, + + .set_tx = furi_hal_subghz_tx, + .flush_tx = furi_hal_subghz_flush_tx, + .start_async_tx = subghz_device_cc1101_int_interconnect_start_async_tx, + .is_async_complete_tx = furi_hal_subghz_is_async_tx_complete, + .stop_async_tx = furi_hal_subghz_stop_async_tx, + + .set_rx = furi_hal_subghz_rx, + .flush_rx = furi_hal_subghz_flush_rx, + .start_async_rx = subghz_device_cc1101_int_interconnect_start_async_rx, + .stop_async_rx = furi_hal_subghz_stop_async_rx, + + .get_rssi = furi_hal_subghz_get_rssi, + .get_lqi = furi_hal_subghz_get_lqi, + + .rx_pipe_not_empty = furi_hal_subghz_rx_pipe_not_empty, + .is_rx_data_crc_valid = furi_hal_subghz_is_rx_data_crc_valid, + .read_packet = furi_hal_subghz_read_packet, + .write_packet = furi_hal_subghz_write_packet, +}; + +const SubGhzDevice subghz_device_cc1101_int = { + .name = SUBGHZ_DEVICE_CC1101_INT_NAME, + .interconnect = &subghz_device_cc1101_int_interconnect, +}; diff --git a/lib/subghz/devices/cc1101_int/cc1101_int_interconnect.h b/lib/subghz/devices/cc1101_int/cc1101_int_interconnect.h new file mode 100644 index 000000000000..629d1264c093 --- /dev/null +++ b/lib/subghz/devices/cc1101_int/cc1101_int_interconnect.h @@ -0,0 +1,8 @@ +#pragma once +#include "../types.h" + +#define SUBGHZ_DEVICE_CC1101_INT_NAME "cc1101_int" + +typedef struct SubGhzDeviceCC1101Int SubGhzDeviceCC1101Int; + +extern const SubGhzDevice subghz_device_cc1101_int; diff --git a/lib/subghz/devices/device_registry.h b/lib/subghz/devices/device_registry.h new file mode 100644 index 000000000000..70a0db4b2656 --- /dev/null +++ b/lib/subghz/devices/device_registry.h @@ -0,0 +1,13 @@ +#pragma once + +#include "registry.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern const SubGhzDeviceRegistry subghz_device_registry; + +#ifdef __cplusplus +} +#endif diff --git a/lib/subghz/devices/devices.c b/lib/subghz/devices/devices.c new file mode 100644 index 000000000000..55db61e11880 --- /dev/null +++ b/lib/subghz/devices/devices.c @@ -0,0 +1,236 @@ +#include "devices.h" + +#include "registry.h" + +void subghz_devices_init() { + furi_check(!subghz_device_registry_is_valid()); + subghz_device_registry_init(); +} + +void subghz_devices_deinit(void) { + furi_check(subghz_device_registry_is_valid()); + subghz_device_registry_deinit(); +} + +const SubGhzDevice* subghz_devices_get_by_name(const char* device_name) { + furi_check(subghz_device_registry_is_valid()); + const SubGhzDevice* device = subghz_device_registry_get_by_name(device_name); + return device; +} + +const char* subghz_devices_get_name(const SubGhzDevice* device) { + const char* ret = NULL; + if(device) { + ret = device->name; + } + return ret; +} + +bool subghz_devices_begin(const SubGhzDevice* device) { + bool ret = false; + furi_assert(device); + if(device->interconnect->begin) { + ret = device->interconnect->begin(); + } + return ret; +} + +void subghz_devices_end(const SubGhzDevice* device) { + furi_assert(device); + if(device->interconnect->end) { + device->interconnect->end(); + } +} + +bool subghz_devices_is_connect(const SubGhzDevice* device) { + bool ret = false; + furi_assert(device); + if(device->interconnect->is_connect) { + ret = device->interconnect->is_connect(); + } + return ret; +} + +void subghz_devices_reset(const SubGhzDevice* device) { + furi_assert(device); + if(device->interconnect->reset) { + device->interconnect->reset(); + } +} + +void subghz_devices_sleep(const SubGhzDevice* device) { + furi_assert(device); + if(device->interconnect->sleep) { + device->interconnect->sleep(); + } +} + +void subghz_devices_idle(const SubGhzDevice* device) { + furi_assert(device); + if(device->interconnect->idle) { + device->interconnect->idle(); + } +} + +void subghz_devices_load_preset( + const SubGhzDevice* device, + FuriHalSubGhzPreset preset, + uint8_t* preset_data) { + furi_assert(device); + if(device->interconnect->load_preset) { + device->interconnect->load_preset(preset, preset_data); + } +} + +uint32_t subghz_devices_set_frequency(const SubGhzDevice* device, uint32_t frequency) { + uint32_t ret = 0; + furi_assert(device); + if(device->interconnect->set_frequency) { + ret = device->interconnect->set_frequency(frequency); + } + return ret; +} + +bool subghz_devices_is_frequency_valid(const SubGhzDevice* device, uint32_t frequency) { + bool ret = false; + furi_assert(device); + if(device->interconnect->is_frequency_valid) { + ret = device->interconnect->is_frequency_valid(frequency); + } + return ret; +} + +void subghz_devices_set_async_mirror_pin(const SubGhzDevice* device, const GpioPin* gpio) { + furi_assert(device); + if(device->interconnect->set_async_mirror_pin) { + device->interconnect->set_async_mirror_pin(gpio); + } +} + +const GpioPin* subghz_devices_get_data_gpio(const SubGhzDevice* device) { + const GpioPin* ret = NULL; + furi_assert(device); + if(device->interconnect->get_data_gpio) { + ret = device->interconnect->get_data_gpio(); + } + return ret; +} + +bool subghz_devices_set_tx(const SubGhzDevice* device) { + bool ret = 0; + furi_assert(device); + if(device->interconnect->set_tx) { + ret = device->interconnect->set_tx(); + } + return ret; +} + +void subghz_devices_flush_tx(const SubGhzDevice* device) { + furi_assert(device); + if(device->interconnect->flush_tx) { + device->interconnect->flush_tx(); + } +} + +bool subghz_devices_start_async_tx(const SubGhzDevice* device, void* callback, void* context) { + bool ret = false; + furi_assert(device); + if(device->interconnect->start_async_tx) { + ret = device->interconnect->start_async_tx(callback, context); + } + return ret; +} + +bool subghz_devices_is_async_complete_tx(const SubGhzDevice* device) { + bool ret = false; + furi_assert(device); + if(device->interconnect->is_async_complete_tx) { + ret = device->interconnect->is_async_complete_tx(); + } + return ret; +} + +void subghz_devices_stop_async_tx(const SubGhzDevice* device) { + furi_assert(device); + if(device->interconnect->stop_async_tx) { + device->interconnect->stop_async_tx(); + } +} + +void subghz_devices_set_rx(const SubGhzDevice* device) { + furi_assert(device); + if(device->interconnect->set_rx) { + device->interconnect->set_rx(); + } +} + +void subghz_devices_flush_rx(const SubGhzDevice* device) { + furi_assert(device); + if(device->interconnect->flush_rx) { + device->interconnect->flush_rx(); + } +} + +void subghz_devices_start_async_rx(const SubGhzDevice* device, void* callback, void* context) { + furi_assert(device); + if(device->interconnect->start_async_rx) { + device->interconnect->start_async_rx(callback, context); + } +} + +void subghz_devices_stop_async_rx(const SubGhzDevice* device) { + furi_assert(device); + if(device->interconnect->stop_async_rx) { + device->interconnect->stop_async_rx(); + } +} + +float subghz_devices_get_rssi(const SubGhzDevice* device) { + float ret = 0; + furi_assert(device); + if(device->interconnect->get_rssi) { + ret = device->interconnect->get_rssi(); + } + return ret; +} + +uint8_t subghz_devices_get_lqi(const SubGhzDevice* device) { + uint8_t ret = 0; + furi_assert(device); + if(device->interconnect->get_lqi) { + ret = device->interconnect->get_lqi(); + } + return ret; +} + +bool subghz_devices_rx_pipe_not_empty(const SubGhzDevice* device) { + bool ret = false; + furi_assert(device); + if(device->interconnect->rx_pipe_not_empty) { + ret = device->interconnect->rx_pipe_not_empty(); + } + return ret; +} + +bool subghz_devices_is_rx_data_crc_valid(const SubGhzDevice* device) { + bool ret = false; + furi_assert(device); + if(device->interconnect->is_rx_data_crc_valid) { + ret = device->interconnect->is_rx_data_crc_valid(); + } + return ret; +} + +void subghz_devices_read_packet(const SubGhzDevice* device, uint8_t* data, uint8_t* size) { + furi_assert(device); + if(device->interconnect->read_packet) { + device->interconnect->read_packet(data, size); + } +} + +void subghz_devices_write_packet(const SubGhzDevice* device, const uint8_t* data, uint8_t size) { + furi_assert(device); + if(device->interconnect->write_packet) { + device->interconnect->write_packet(data, size); + } +} diff --git a/lib/subghz/devices/devices.h b/lib/subghz/devices/devices.h new file mode 100644 index 000000000000..dad3c9aeb538 --- /dev/null +++ b/lib/subghz/devices/devices.h @@ -0,0 +1,52 @@ +#pragma once + +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct SubGhzDevice SubGhzDevice; + +void subghz_devices_init(); +void subghz_devices_deinit(void); + +const SubGhzDevice* subghz_devices_get_by_name(const char* device_name); +const char* subghz_devices_get_name(const SubGhzDevice* device); +bool subghz_devices_begin(const SubGhzDevice* device); +void subghz_devices_end(const SubGhzDevice* device); +bool subghz_devices_is_connect(const SubGhzDevice* device); +void subghz_devices_reset(const SubGhzDevice* device); +void subghz_devices_sleep(const SubGhzDevice* device); +void subghz_devices_idle(const SubGhzDevice* device); +void subghz_devices_load_preset( + const SubGhzDevice* device, + FuriHalSubGhzPreset preset, + uint8_t* preset_data); +uint32_t subghz_devices_set_frequency(const SubGhzDevice* device, uint32_t frequency); +bool subghz_devices_is_frequency_valid(const SubGhzDevice* device, uint32_t frequency); +void subghz_devices_set_async_mirror_pin(const SubGhzDevice* device, const GpioPin* gpio); +const GpioPin* subghz_devices_get_data_gpio(const SubGhzDevice* device); + +bool subghz_devices_set_tx(const SubGhzDevice* device); +void subghz_devices_flush_tx(const SubGhzDevice* device); +bool subghz_devices_start_async_tx(const SubGhzDevice* device, void* callback, void* context); +bool subghz_devices_is_async_complete_tx(const SubGhzDevice* device); +void subghz_devices_stop_async_tx(const SubGhzDevice* device); + +void subghz_devices_set_rx(const SubGhzDevice* device); +void subghz_devices_flush_rx(const SubGhzDevice* device); +void subghz_devices_start_async_rx(const SubGhzDevice* device, void* callback, void* context); +void subghz_devices_stop_async_rx(const SubGhzDevice* device); + +float subghz_devices_get_rssi(const SubGhzDevice* device); +uint8_t subghz_devices_get_lqi(const SubGhzDevice* device); + +bool subghz_devices_rx_pipe_not_empty(const SubGhzDevice* device); +bool subghz_devices_is_rx_data_crc_valid(const SubGhzDevice* device); +void subghz_devices_read_packet(const SubGhzDevice* device, uint8_t* data, uint8_t* size); +void subghz_devices_write_packet(const SubGhzDevice* device, const uint8_t* data, uint8_t size); + +#ifdef __cplusplus +} +#endif diff --git a/lib/subghz/devices/preset.h b/lib/subghz/devices/preset.h new file mode 100644 index 000000000000..8716f2e233c5 --- /dev/null +++ b/lib/subghz/devices/preset.h @@ -0,0 +1,13 @@ +#pragma once + +/** Radio Presets */ +typedef enum { + FuriHalSubGhzPresetIDLE, /**< default configuration */ + FuriHalSubGhzPresetOok270Async, /**< OOK, bandwidth 270kHz, asynchronous */ + FuriHalSubGhzPresetOok650Async, /**< OOK, bandwidth 650kHz, asynchronous */ + FuriHalSubGhzPreset2FSKDev238Async, /**< FM, deviation 2.380371 kHz, asynchronous */ + FuriHalSubGhzPreset2FSKDev476Async, /**< FM, deviation 47.60742 kHz, asynchronous */ + FuriHalSubGhzPresetMSK99_97KbAsync, /**< MSK, deviation 47.60742 kHz, 99.97Kb/s, asynchronous */ + FuriHalSubGhzPresetGFSK9_99KbAsync, /**< GFSK, deviation 19.042969 kHz, 9.996Kb/s, asynchronous */ + FuriHalSubGhzPresetCustom, /**Custom Preset*/ +} FuriHalSubGhzPreset; diff --git a/lib/subghz/devices/registry.c b/lib/subghz/devices/registry.c new file mode 100644 index 000000000000..c0d5bb292dce --- /dev/null +++ b/lib/subghz/devices/registry.c @@ -0,0 +1,76 @@ +#include "registry.h" + +#include "cc1101_int/cc1101_int_interconnect.h" +#include +#include + +#define TAG "SubGhzDeviceRegistry" + +struct SubGhzDeviceRegistry { + const SubGhzDevice** items; + size_t size; + PluginManager* manager; +}; + +static SubGhzDeviceRegistry* subghz_device_registry = NULL; + +void subghz_device_registry_init(void) { + SubGhzDeviceRegistry* subghz_device = + (SubGhzDeviceRegistry*)malloc(sizeof(SubGhzDeviceRegistry)); + subghz_device->manager = plugin_manager_alloc( + SUBGHZ_RADIO_DEVICE_PLUGIN_APP_ID, + SUBGHZ_RADIO_DEVICE_PLUGIN_API_VERSION, + firmware_api_interface); + + //ToDo: fix path to plugins + if(plugin_manager_load_all(subghz_device->manager, "/any/apps_data/subghz/plugins") != + //if(plugin_manager_load_all(subghz_device->manager, APP_DATA_PATH("plugins")) != + PluginManagerErrorNone) { + FURI_LOG_E(TAG, "Failed to load all libs"); + } + + subghz_device->size = plugin_manager_get_count(subghz_device->manager) + 1; + subghz_device->items = + (const SubGhzDevice**)malloc(sizeof(SubGhzDevice*) * subghz_device->size); + subghz_device->items[0] = &subghz_device_cc1101_int; + for(uint32_t i = 1; i < subghz_device->size; i++) { + const SubGhzDevice* plugin = plugin_manager_get_ep(subghz_device->manager, i - 1); + subghz_device->items[i] = plugin; + } + + FURI_LOG_I(TAG, "Loaded %zu radio device", subghz_device->size); + subghz_device_registry = subghz_device; +} + +void subghz_device_registry_deinit(void) { + plugin_manager_free(subghz_device_registry->manager); + free(subghz_device_registry->items); + free(subghz_device_registry); + subghz_device_registry = NULL; +} + +bool subghz_device_registry_is_valid(void) { + return subghz_device_registry != NULL; +} + +const SubGhzDevice* subghz_device_registry_get_by_name(const char* name) { + furi_assert(subghz_device_registry); + + if(name != NULL) { + for(size_t i = 0; i < subghz_device_registry->size; i++) { + if(strcmp(name, subghz_device_registry->items[i]->name) == 0) { + return subghz_device_registry->items[i]; + } + } + } + return NULL; +} + +const SubGhzDevice* subghz_device_registry_get_by_index(size_t index) { + furi_assert(subghz_device_registry); + if(index < subghz_device_registry->size) { + return subghz_device_registry->items[index]; + } else { + return NULL; + } +} diff --git a/lib/subghz/devices/registry.h b/lib/subghz/devices/registry.h new file mode 100644 index 000000000000..5200589205bd --- /dev/null +++ b/lib/subghz/devices/registry.h @@ -0,0 +1,40 @@ +#pragma once + +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct SubGhzDevice SubGhzDevice; + +void subghz_device_registry_init(void); + +void subghz_device_registry_deinit(void); + +bool subghz_device_registry_is_valid(void); + +/** + * Registration by name SubGhzDevice. + * @param name SubGhzDevice name + * @return SubGhzDevice* pointer to a SubGhzDevice instance + */ +const SubGhzDevice* subghz_device_registry_get_by_name(const char* name); + +/** + * Registration subghzdevice by index in array SubGhzDevice. + * @param index SubGhzDevice by index in array + * @return SubGhzDevice* pointer to a SubGhzDevice instance + */ +const SubGhzDevice* subghz_device_registry_get_by_index(size_t index); + +/** + * Getting the number of registered subghzdevices. + * @param subghz_device SubGhzDeviceRegistry + * @return Number of subghzdevices + */ +size_t subghz_device_registry_count(void); + +#ifdef __cplusplus +} +#endif diff --git a/lib/subghz/devices/types.h b/lib/subghz/devices/types.h new file mode 100644 index 000000000000..8a41984263fc --- /dev/null +++ b/lib/subghz/devices/types.h @@ -0,0 +1,91 @@ +#pragma once + +#include +#include +#include + +#include +#include + +#include "preset.h" + +#include + +#define SUBGHZ_RADIO_DEVICE_PLUGIN_APP_ID "subghz_radio_device" +#define SUBGHZ_RADIO_DEVICE_PLUGIN_API_VERSION 1 + +typedef struct SubGhzDeviceRegistry SubGhzDeviceRegistry; +typedef struct SubGhzDevice SubGhzDevice; + +typedef bool (*SubGhzBegin)(void); +typedef void (*SubGhzEnd)(void); +typedef bool (*SubGhzIsConnect)(void); +typedef void (*SubGhzReset)(void); +typedef void (*SubGhzSleep)(void); +typedef void (*SubGhzIdle)(void); +typedef void (*SubGhzLoadPreset)(FuriHalSubGhzPreset preset, uint8_t* preset_data); +typedef uint32_t (*SubGhzSetFrequency)(uint32_t frequency); +typedef bool (*SubGhzIsFrequencyValid)(uint32_t frequency); + +typedef void (*SubGhzSetAsyncMirrorPin)(const GpioPin* gpio); +typedef const GpioPin* (*SubGhzGetDataGpio)(void); + +typedef bool (*SubGhzSetTx)(void); +typedef void (*SubGhzFlushTx)(void); +typedef bool (*SubGhzStartAsyncTx)(void* callback, void* context); +typedef bool (*SubGhzIsAsyncCompleteTx)(void); +typedef void (*SubGhzStopAsyncTx)(void); + +typedef void (*SubGhzSetRx)(void); +typedef void (*SubGhzFlushRx)(void); +typedef void (*SubGhzStartAsyncRx)(void* callback, void* context); +typedef void (*SubGhzStopAsyncRx)(void); + +typedef float (*SubGhzGetRSSI)(void); +typedef uint8_t (*SubGhzGetLQI)(void); + +typedef bool (*SubGhzRxPipeNotEmpty)(void); +typedef bool (*SubGhzRxIsDataCrcValid)(void); +typedef void (*SubGhzReadPacket)(uint8_t* data, uint8_t* size); +typedef void (*SubGhzWritePacket)(const uint8_t* data, uint8_t size); + +typedef struct { + SubGhzBegin begin; + SubGhzEnd end; + + SubGhzIsConnect is_connect; + SubGhzReset reset; + SubGhzSleep sleep; + SubGhzIdle idle; + + SubGhzLoadPreset load_preset; + SubGhzSetFrequency set_frequency; + SubGhzIsFrequencyValid is_frequency_valid; + SubGhzSetAsyncMirrorPin set_async_mirror_pin; + SubGhzGetDataGpio get_data_gpio; + + SubGhzSetTx set_tx; + SubGhzFlushTx flush_tx; + SubGhzStartAsyncTx start_async_tx; + SubGhzIsAsyncCompleteTx is_async_complete_tx; + SubGhzStopAsyncTx stop_async_tx; + + SubGhzSetRx set_rx; + SubGhzFlushRx flush_rx; + SubGhzStartAsyncRx start_async_rx; + SubGhzStopAsyncRx stop_async_rx; + + SubGhzGetRSSI get_rssi; + SubGhzGetLQI get_lqi; + + SubGhzRxPipeNotEmpty rx_pipe_not_empty; + SubGhzRxIsDataCrcValid is_rx_data_crc_valid; + SubGhzReadPacket read_packet; + SubGhzWritePacket write_packet; + +} SubGhzDeviceInterconnect; + +struct SubGhzDevice { + const char* name; + const SubGhzDeviceInterconnect* interconnect; +}; diff --git a/lib/subghz/protocols/raw.c b/lib/subghz/protocols/raw.c index 66358698ac93..1288c957371f 100644 --- a/lib/subghz/protocols/raw.c +++ b/lib/subghz/protocols/raw.c @@ -40,6 +40,7 @@ struct SubGhzProtocolEncoderRAW { bool is_running; FuriString* file_name; + FuriString* radio_device_name; SubGhzFileEncoderWorker* file_worker_encoder; }; @@ -282,6 +283,7 @@ void* subghz_protocol_encoder_raw_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_raw; instance->file_name = furi_string_alloc(); + instance->radio_device_name = furi_string_alloc(); instance->is_running = false; return instance; } @@ -300,6 +302,7 @@ void subghz_protocol_encoder_raw_free(void* context) { SubGhzProtocolEncoderRAW* instance = context; subghz_protocol_encoder_raw_stop(instance); furi_string_free(instance->file_name); + furi_string_free(instance->radio_device_name); free(instance); } @@ -318,7 +321,9 @@ static bool subghz_protocol_encoder_raw_worker_init(SubGhzProtocolEncoderRAW* in instance->file_worker_encoder = subghz_file_encoder_worker_alloc(); if(subghz_file_encoder_worker_start( - instance->file_worker_encoder, furi_string_get_cstr(instance->file_name))) { + instance->file_worker_encoder, + furi_string_get_cstr(instance->file_name), + furi_string_get_cstr(instance->radio_device_name))) { //the worker needs a file in order to open and read part of the file furi_delay_ms(100); instance->is_running = true; @@ -328,7 +333,10 @@ static bool subghz_protocol_encoder_raw_worker_init(SubGhzProtocolEncoderRAW* in return instance->is_running; } -void subghz_protocol_raw_gen_fff_data(FlipperFormat* flipper_format, const char* file_path) { +void subghz_protocol_raw_gen_fff_data( + FlipperFormat* flipper_format, + const char* file_path, + const char* radio_device_name) { do { stream_clean(flipper_format_get_raw_stream(flipper_format)); if(!flipper_format_write_string_cstr(flipper_format, "Protocol", "RAW")) { @@ -340,6 +348,12 @@ void subghz_protocol_raw_gen_fff_data(FlipperFormat* flipper_format, const char* FURI_LOG_E(TAG, "Unable to add File_name"); break; } + + if(!flipper_format_write_string_cstr( + flipper_format, "Radio_device_name", radio_device_name)) { + FURI_LOG_E(TAG, "Unable to add Radio_device_name"); + break; + } } while(false); } @@ -364,6 +378,13 @@ SubGhzProtocolStatus } furi_string_set(instance->file_name, temp_str); + if(!flipper_format_read_string(flipper_format, "Radio_device_name", temp_str)) { + FURI_LOG_E(TAG, "Missing Radio_device_name"); + res = SubGhzProtocolStatusErrorParserOthers; + break; + } + furi_string_set(instance->radio_device_name, temp_str); + if(!subghz_protocol_encoder_raw_worker_init(instance)) { res = SubGhzProtocolStatusErrorEncoderGetUpload; break; diff --git a/lib/subghz/protocols/raw.h b/lib/subghz/protocols/raw.h index 4f67a4e2f24a..6d791bb3663e 100644 --- a/lib/subghz/protocols/raw.h +++ b/lib/subghz/protocols/raw.h @@ -126,8 +126,12 @@ void subghz_protocol_raw_file_encoder_worker_set_callback_end( * File generation for RAW work. * @param flipper_format Pointer to a FlipperFormat instance * @param file_path File path + * @param radio_dev_name Radio device name */ -void subghz_protocol_raw_gen_fff_data(FlipperFormat* flipper_format, const char* file_path); +void subghz_protocol_raw_gen_fff_data( + FlipperFormat* flipper_format, + const char* file_path, + const char* radio_dev_name); /** * Deserialize and generating an upload to send. diff --git a/lib/subghz/subghz_file_encoder_worker.c b/lib/subghz/subghz_file_encoder_worker.c index 5c4d36f78e88..519ff3fdcc35 100644 --- a/lib/subghz/subghz_file_encoder_worker.c +++ b/lib/subghz/subghz_file_encoder_worker.c @@ -3,6 +3,7 @@ #include #include #include +#include #define TAG "SubGhzFileEncoderWorker" @@ -21,6 +22,7 @@ struct SubGhzFileEncoderWorker { bool is_storage_slow; FuriString* str_data; FuriString* file_path; + const SubGhzDevice* device; SubGhzFileEncoderWorkerCallbackEnd callback_end; void* context_end; @@ -156,10 +158,13 @@ static int32_t subghz_file_encoder_worker_thread(void* context) { if(instance->is_storage_slow) { FURI_LOG_E(TAG, "Storage is slow"); } + FURI_LOG_I(TAG, "End read file"); - while(!furi_hal_subghz_is_async_tx_complete() && instance->worker_running) { + while(instance->device && !subghz_devices_is_async_complete_tx(instance->device) && + instance->worker_running) { furi_delay_ms(5); } + FURI_LOG_I(TAG, "End transmission"); while(instance->worker_running) { if(instance->worker_stoping) { @@ -206,12 +211,16 @@ void subghz_file_encoder_worker_free(SubGhzFileEncoderWorker* instance) { free(instance); } -bool subghz_file_encoder_worker_start(SubGhzFileEncoderWorker* instance, const char* file_path) { +bool subghz_file_encoder_worker_start( + SubGhzFileEncoderWorker* instance, + const char* file_path, + const char* radio_device_name) { furi_assert(instance); furi_assert(!instance->worker_running); furi_stream_buffer_reset(instance->stream); furi_string_set(instance->file_path, file_path); + instance->device = subghz_devices_get_by_name(radio_device_name); instance->worker_running = true; furi_thread_start(instance->thread); diff --git a/lib/subghz/subghz_file_encoder_worker.h b/lib/subghz/subghz_file_encoder_worker.h index a87be5cd6f3a..e66c66d76eab 100644 --- a/lib/subghz/subghz_file_encoder_worker.h +++ b/lib/subghz/subghz_file_encoder_worker.h @@ -38,9 +38,14 @@ LevelDuration subghz_file_encoder_worker_get_level_duration(void* context); /** * Start SubGhzFileEncoderWorker. * @param instance Pointer to a SubGhzFileEncoderWorker instance + * @param file_path File path + * @param radio_device_name Radio device name * @return bool - true if ok */ -bool subghz_file_encoder_worker_start(SubGhzFileEncoderWorker* instance, const char* file_path); +bool subghz_file_encoder_worker_start( + SubGhzFileEncoderWorker* instance, + const char* file_path, + const char* radio_device_name); /** * Stop SubGhzFileEncoderWorker diff --git a/lib/subghz/subghz_setting.c b/lib/subghz/subghz_setting.c index 656580043f05..9804f827733c 100644 --- a/lib/subghz/subghz_setting.c +++ b/lib/subghz/subghz_setting.c @@ -4,7 +4,7 @@ #include #include -#include +#include #define TAG "SubGhzSetting" @@ -218,8 +218,7 @@ void subghz_setting_free(SubGhzSetting* instance) { static void subghz_setting_load_default_preset( SubGhzSetting* instance, const char* preset_name, - const uint8_t* preset_data, - const uint8_t preset_pa_table[8]) { + const uint8_t* preset_data) { furi_assert(instance); furi_assert(preset_data); uint32_t preset_data_count = 0; @@ -235,10 +234,8 @@ static void subghz_setting_load_default_preset( preset_data_count += 2; item->custom_preset_data_size = sizeof(uint8_t) * preset_data_count + sizeof(uint8_t) * 8; item->custom_preset_data = malloc(item->custom_preset_data_size); - //load preset register - memcpy(&item->custom_preset_data[0], &preset_data[0], preset_data_count); - //load pa table - memcpy(&item->custom_preset_data[preset_data_count], &preset_pa_table[0], 8); + //load preset register + pa table + memcpy(&item->custom_preset_data[0], &preset_data[0], item->custom_preset_data_size); } static void subghz_setting_load_default_region( @@ -262,25 +259,13 @@ static void subghz_setting_load_default_region( } subghz_setting_load_default_preset( - instance, - "AM270", - (uint8_t*)furi_hal_subghz_preset_ook_270khz_async_regs, - furi_hal_subghz_preset_ook_async_patable); + instance, "AM270", subghz_device_cc1101_preset_ook_270khz_async_regs); subghz_setting_load_default_preset( - instance, - "AM650", - (uint8_t*)furi_hal_subghz_preset_ook_650khz_async_regs, - furi_hal_subghz_preset_ook_async_patable); + instance, "AM650", subghz_device_cc1101_preset_ook_650khz_async_regs); subghz_setting_load_default_preset( - instance, - "FM238", - (uint8_t*)furi_hal_subghz_preset_2fsk_dev2_38khz_async_regs, - furi_hal_subghz_preset_2fsk_async_patable); + instance, "FM238", subghz_device_cc1101_preset_2fsk_dev2_38khz_async_regs); subghz_setting_load_default_preset( - instance, - "FM476", - (uint8_t*)furi_hal_subghz_preset_2fsk_dev47_6khz_async_regs, - furi_hal_subghz_preset_2fsk_async_patable); + instance, "FM476", subghz_device_cc1101_preset_2fsk_dev47_6khz_async_regs); } void subghz_setting_load_default(SubGhzSetting* instance) { @@ -359,6 +344,7 @@ void subghz_setting_load(SubGhzSetting* instance, const char* file_path) { } while(flipper_format_read_uint32( fff_data_file, "Frequency", (uint32_t*)&temp_data32, 1)) { + //Todo: add a frequency support check depending on the selected radio device if(furi_hal_subghz_is_frequency_valid(temp_data32)) { FURI_LOG_I(TAG, "Frequency loaded %lu", temp_data32); FrequencyList_push_back(instance->frequencies, temp_data32); diff --git a/lib/subghz/subghz_tx_rx_worker.c b/lib/subghz/subghz_tx_rx_worker.c index 42124bebc1c8..250e6666f407 100644 --- a/lib/subghz/subghz_tx_rx_worker.c +++ b/lib/subghz/subghz_tx_rx_worker.c @@ -21,6 +21,8 @@ struct SubGhzTxRxWorker { SubGhzTxRxWorkerStatus status; uint32_t frequency; + const SubGhzDevice* device; + const GpioPin* device_data_gpio; SubGhzTxRxWorkerCallbackHaveRead callback_have_read; void* context_have_read; @@ -65,33 +67,33 @@ bool subghz_tx_rx_worker_rx(SubGhzTxRxWorker* instance, uint8_t* data, uint8_t* uint8_t timeout = 100; bool ret = false; if(instance->status != SubGhzTxRxWorkerStatusRx) { - furi_hal_subghz_rx(); + subghz_devices_set_rx(instance->device); instance->status = SubGhzTxRxWorkerStatusRx; furi_delay_tick(1); } //waiting for reception to complete - while(furi_hal_gpio_read(&gpio_cc1101_g0)) { + while(furi_hal_gpio_read(instance->device_data_gpio)) { furi_delay_tick(1); if(!--timeout) { FURI_LOG_W(TAG, "RX cc1101_g0 timeout"); - furi_hal_subghz_flush_rx(); - furi_hal_subghz_rx(); + subghz_devices_flush_rx(instance->device); + subghz_devices_set_rx(instance->device); break; } } - if(furi_hal_subghz_rx_pipe_not_empty()) { + if(subghz_devices_rx_pipe_not_empty(instance->device)) { FURI_LOG_I( TAG, "RSSI: %03.1fdbm LQI: %d", - (double)furi_hal_subghz_get_rssi(), - furi_hal_subghz_get_lqi()); - if(furi_hal_subghz_is_rx_data_crc_valid()) { - furi_hal_subghz_read_packet(data, size); + (double)subghz_devices_get_rssi(instance->device), + subghz_devices_get_lqi(instance->device)); + if(subghz_devices_is_rx_data_crc_valid(instance->device)) { + subghz_devices_read_packet(instance->device, data, size); ret = true; } - furi_hal_subghz_flush_rx(); - furi_hal_subghz_rx(); + subghz_devices_flush_rx(instance->device); + subghz_devices_set_rx(instance->device); } return ret; } @@ -99,26 +101,28 @@ bool subghz_tx_rx_worker_rx(SubGhzTxRxWorker* instance, uint8_t* data, uint8_t* void subghz_tx_rx_worker_tx(SubGhzTxRxWorker* instance, uint8_t* data, size_t size) { uint8_t timeout = 200; if(instance->status != SubGhzTxRxWorkerStatusIDLE) { - furi_hal_subghz_idle(); + subghz_devices_idle(instance->device); } - furi_hal_subghz_write_packet(data, size); - furi_hal_subghz_tx(); //start send + subghz_devices_write_packet(instance->device, data, size); + subghz_devices_set_tx(instance->device); //start send instance->status = SubGhzTxRxWorkerStatusTx; - while(!furi_hal_gpio_read(&gpio_cc1101_g0)) { // Wait for GDO0 to be set -> sync transmitted + while(!furi_hal_gpio_read( + instance->device_data_gpio)) { // Wait for GDO0 to be set -> sync transmitted furi_delay_tick(1); if(!--timeout) { FURI_LOG_W(TAG, "TX !cc1101_g0 timeout"); break; } } - while(furi_hal_gpio_read(&gpio_cc1101_g0)) { // Wait for GDO0 to be cleared -> end of packet + while(furi_hal_gpio_read( + instance->device_data_gpio)) { // Wait for GDO0 to be cleared -> end of packet furi_delay_tick(1); if(!--timeout) { FURI_LOG_W(TAG, "TX cc1101_g0 timeout"); break; } } - furi_hal_subghz_idle(); + subghz_devices_idle(instance->device); instance->status = SubGhzTxRxWorkerStatusIDLE; } /** Worker thread @@ -128,16 +132,19 @@ void subghz_tx_rx_worker_tx(SubGhzTxRxWorker* instance, uint8_t* data, size_t si */ static int32_t subghz_tx_rx_worker_thread(void* context) { SubGhzTxRxWorker* instance = context; + furi_assert(instance->device); FURI_LOG_I(TAG, "Worker start"); - furi_hal_subghz_reset(); - furi_hal_subghz_idle(); - furi_hal_subghz_load_preset(FuriHalSubGhzPresetGFSK9_99KbAsync); - //furi_hal_subghz_load_preset(FuriHalSubGhzPresetMSK99_97KbAsync); - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); + subghz_devices_begin(instance->device); + instance->device_data_gpio = subghz_devices_get_data_gpio(instance->device); + subghz_devices_reset(instance->device); + subghz_devices_idle(instance->device); + subghz_devices_load_preset(instance->device, FuriHalSubGhzPresetGFSK9_99KbAsync, NULL); - furi_hal_subghz_set_frequency_and_path(instance->frequency); - furi_hal_subghz_flush_rx(); + furi_hal_gpio_init(instance->device_data_gpio, GpioModeInput, GpioPullNo, GpioSpeedLow); + + subghz_devices_set_frequency(instance->device, instance->frequency); + subghz_devices_flush_rx(instance->device); uint8_t data[SUBGHZ_TXRX_WORKER_MAX_TXRX_SIZE + 1] = {0}; size_t size_tx = 0; @@ -191,8 +198,8 @@ static int32_t subghz_tx_rx_worker_thread(void* context) { furi_delay_tick(1); } - furi_hal_subghz_set_path(FuriHalSubGhzPathIsolate); - furi_hal_subghz_sleep(); + subghz_devices_sleep(instance->device); + subghz_devices_end(instance->device); FURI_LOG_I(TAG, "Worker stop"); return 0; @@ -224,7 +231,10 @@ void subghz_tx_rx_worker_free(SubGhzTxRxWorker* instance) { free(instance); } -bool subghz_tx_rx_worker_start(SubGhzTxRxWorker* instance, uint32_t frequency) { +bool subghz_tx_rx_worker_start( + SubGhzTxRxWorker* instance, + const SubGhzDevice* device, + uint32_t frequency) { furi_assert(instance); furi_assert(!instance->worker_running); bool res = false; @@ -235,6 +245,7 @@ bool subghz_tx_rx_worker_start(SubGhzTxRxWorker* instance, uint32_t frequency) { if(furi_hal_region_is_frequency_allowed(frequency)) { instance->frequency = frequency; + instance->device = device; res = true; } diff --git a/lib/subghz/subghz_tx_rx_worker.h b/lib/subghz/subghz_tx_rx_worker.h index ddc02e749d8f..56bdb0a1febd 100644 --- a/lib/subghz/subghz_tx_rx_worker.h +++ b/lib/subghz/subghz_tx_rx_worker.h @@ -1,6 +1,7 @@ #pragma once #include +#include #ifdef __cplusplus extern "C" { @@ -67,9 +68,13 @@ void subghz_tx_rx_worker_free(SubGhzTxRxWorker* instance); /** * Start SubGhzTxRxWorker * @param instance Pointer to a SubGhzTxRxWorker instance + * @param device Pointer to a SubGhzDevice instance * @return bool - true if ok */ -bool subghz_tx_rx_worker_start(SubGhzTxRxWorker* instance, uint32_t frequency); +bool subghz_tx_rx_worker_start( + SubGhzTxRxWorker* instance, + const SubGhzDevice* device, + uint32_t frequency); /** * Stop SubGhzTxRxWorker diff --git a/lib/subghz/types.h b/lib/subghz/types.h index 719beff45f8e..d87a0dc760c0 100644 --- a/lib/subghz/types.h +++ b/lib/subghz/types.h @@ -21,6 +21,12 @@ #define SUBGHZ_RAW_FILE_VERSION 1 #define SUBGHZ_RAW_FILE_TYPE "Flipper SubGhz RAW File" +#define SUBGHZ_KEYSTORE_DIR_NAME EXT_PATH("subghz/assets/keeloq_mfcodes") +#define SUBGHZ_KEYSTORE_DIR_USER_NAME EXT_PATH("subghz/assets/keeloq_mfcodes_user") +#define SUBGHZ_CAME_ATOMO_DIR_NAME EXT_PATH("subghz/assets/came_atomo") +#define SUBGHZ_NICE_FLOR_S_DIR_NAME EXT_PATH("subghz/assets/nice_flor_s") +#define SUBGHZ_ALUTECH_AT_4N_DIR_NAME EXT_PATH("subghz/assets/alutech_at_4n") + typedef struct SubGhzProtocolRegistry SubGhzProtocolRegistry; typedef struct SubGhzEnvironment SubGhzEnvironment; diff --git a/lib/toolbox/m_cstr_dup.h b/lib/toolbox/m_cstr_dup.h index 0555f72c651c..11b7fe35adac 100644 --- a/lib/toolbox/m_cstr_dup.h +++ b/lib/toolbox/m_cstr_dup.h @@ -2,15 +2,16 @@ #include #define M_INIT_DUP(a) ((a) = strdup("")) -#define M_SET_DUP(a, b) (M_CHECK_DEFAULT_TYPE(a), free((void*)a), (a) = strdup(b)) +#define M_INIT_SET_DUP(a, b) ((a) = strdup(b)) +#define M_SET_DUP(a, b) (free((void*)a), (a) = strdup(b)) #define M_CLEAR_DUP(a) (free((void*)a)) -#define M_CSTR_DUP_OPLIST \ - (INIT(M_INIT_DUP), \ - INIT_SET(M_SET_DUP), \ - SET(M_SET_DUP), \ - CLEAR(M_CLEAR_DUP), \ - HASH(m_core_cstr_hash), \ - EQUAL(M_CSTR_EQUAL), \ - CMP(strcmp), \ +#define M_CSTR_DUP_OPLIST \ + (INIT(M_INIT_DUP), \ + INIT_SET(M_INIT_SET_DUP), \ + SET(M_SET_DUP), \ + CLEAR(M_CLEAR_DUP), \ + HASH(m_core_cstr_hash), \ + EQUAL(M_CSTR_EQUAL), \ + CMP(strcmp), \ TYPE(const char*)) diff --git a/lib/u8g2/u8g2_glue.c b/lib/u8g2/u8g2_glue.c index 0d4879bce5dc..0142e3e2fdc7 100644 --- a/lib/u8g2/u8g2_glue.c +++ b/lib/u8g2/u8g2_glue.c @@ -2,7 +2,7 @@ #include -#define CONTRAST_ERC 32 +#define CONTRAST_ERC 31 #define CONTRAST_MGG 31 uint8_t u8g2_gpio_and_delay_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_ptr) { diff --git a/scripts/distfap.py b/scripts/distfap.py old mode 100644 new mode 100755 index d330988b51e7..b1c5587906b7 --- a/scripts/distfap.py +++ b/scripts/distfap.py @@ -52,9 +52,7 @@ def install(self): if not self.args.launch_app: return 0 - storage.send_and_wait_eol( - f'loader open "Applications" {fap_dst_path}\r' - ) + storage.send_and_wait_eol(f"loader open {fap_dst_path}\r") if len(result := storage.read.until(storage.CLI_EOL)): self.logger.error(f"Unexpected response: {result.decode('ascii')}") diff --git a/scripts/fastfap.py b/scripts/fastfap.py new file mode 100755 index 000000000000..95e32c37be99 --- /dev/null +++ b/scripts/fastfap.py @@ -0,0 +1,169 @@ +#!/usr/bin/env python3 +import hashlib +import os +import struct +import subprocess +import tempfile +from collections import defaultdict +from dataclasses import dataclass + +from elftools.elf.elffile import ELFFile +from elftools.elf.relocation import RelocationSection +from elftools.elf.sections import SymbolTableSection +from fbt.sdk.hashes import gnu_sym_hash +from flipper.app import App + +VERSION = 1 + + +@dataclass +class RelData: + section: int + section_value: int + type: int + offset: int + name: str + + +@dataclass(frozen=True) +class UniqueRelData: + section: int + section_value: int + type: int + name: str + + +@dataclass +class RelSection: + name: str + oringinal_name: str + data: dict[UniqueRelData, list[int]] + + +def serialize_relsection_data(data: dict[UniqueRelData, list[int]]) -> bytes: + result = struct.pack(" 0: + result += struct.pack("> 8) & 0xFF, (offset >> 16) & 0xFF + ) + + return result + + +class Main(App): + def init(self): + self.parser.add_argument("fap_src_path", help="App file to upload") + self.parser.add_argument("objcopy_path", help="Objcopy path") + self.parser.set_defaults(func=self.process) + + def process(self): + fap_path = self.args.fap_src_path + objcopy_path = self.args.objcopy_path + + sections: list[RelSection] = [] + + with open(fap_path, "rb") as f: + elf_file = ELFFile(f) + + relocation_sections: list[RelocationSection] = [] + symtab_section: SymbolTableSection | None = None + + for section in elf_file.iter_sections(): + if isinstance(section, RelocationSection): + relocation_sections.append(section) + + if isinstance(section, SymbolTableSection): + symtab_section = section + + if not symtab_section: + self.logger.error("No symbol table found") + return 1 + + if not relocation_sections: + self.logger.info("No relocation sections found") + return 0 + + for section in relocation_sections: + section_relocations: list[RelData] = [] + + for relocation in section.iter_relocations(): + symbol_id: int = relocation.entry["r_info_sym"] + offset: int = relocation.entry["r_offset"] + type: int = relocation.entry["r_info_type"] + symbol = symtab_section.get_symbol(symbol_id) + section_index: int = symbol["st_shndx"] + section_value: int = symbol["st_value"] + if section_index == "SHN_UNDEF": + section_index = 0 + + section_relocations.append( + RelData(section_index, section_value, type, offset, symbol.name) + ) + + unique_relocations: dict[UniqueRelData, list[int]] = defaultdict(list) + for relocation in section_relocations: + unique = UniqueRelData( + relocation.section, + relocation.section_value, + relocation.type, + relocation.name, + ) + + unique_relocations[unique].append(relocation.offset) + + section_name = section.name + if section_name.startswith(".rel"): + section_name = ".fast.rel" + section_name[4:] + else: + self.logger.error( + "Unknown relocation section name: %s", section_name + ) + return 1 + + sections.append( + RelSection(section_name, section.name, unique_relocations) + ) + + with tempfile.TemporaryDirectory() as temp_dir: + for section in sections: + data = serialize_relsection_data(section.data) + hash_name = hashlib.md5(section.name.encode()).hexdigest() + filename = f"{temp_dir}/{hash_name}.bin" + + if os.path.isfile(filename): + self.logger.error(f"File {filename} already exists") + return 1 + + with open(filename, "wb") as f: + f.write(data) + + exit_code = subprocess.run( + [ + objcopy_path, + "--add-section", + f"{section.name}={filename}", + fap_path, + ], + check=True, + ) + + if exit_code.returncode != 0: + self.logger.error("objcopy failed") + return 1 + + return 0 + + +if __name__ == "__main__": + Main()() diff --git a/scripts/fbt/appmanifest.py b/scripts/fbt/appmanifest.py index 820f5a8c55f0..73e5c777079b 100644 --- a/scripts/fbt/appmanifest.py +++ b/scripts/fbt/appmanifest.py @@ -353,12 +353,18 @@ def get_builtin_app_folders(self): class ApplicationsCGenerator: APP_TYPE_MAP = { - FlipperAppType.SERVICE: ("FlipperApplication", "FLIPPER_SERVICES"), - FlipperAppType.SYSTEM: ("FlipperApplication", "FLIPPER_SYSTEM_APPS"), - FlipperAppType.APP: ("FlipperApplication", "FLIPPER_APPS"), - FlipperAppType.DEBUG: ("FlipperApplication", "FLIPPER_DEBUG_APPS"), - FlipperAppType.SETTINGS: ("FlipperApplication", "FLIPPER_SETTINGS_APPS"), - FlipperAppType.STARTUP: ("FlipperOnStartHook", "FLIPPER_ON_SYSTEM_START"), + FlipperAppType.SERVICE: ("FlipperInternalApplication", "FLIPPER_SERVICES"), + FlipperAppType.SYSTEM: ("FlipperInternalApplication", "FLIPPER_SYSTEM_APPS"), + FlipperAppType.APP: ("FlipperInternalApplication", "FLIPPER_APPS"), + FlipperAppType.DEBUG: ("FlipperInternalApplication", "FLIPPER_DEBUG_APPS"), + FlipperAppType.SETTINGS: ( + "FlipperInternalApplication", + "FLIPPER_SETTINGS_APPS", + ), + FlipperAppType.STARTUP: ( + "FlipperInternalOnStartHook", + "FLIPPER_ON_SYSTEM_START", + ), } def __init__(self, buildset: AppBuildset, autorun_app: str = ""): @@ -379,7 +385,7 @@ def get_app_descr(self, app: FlipperApplication): .appid = "{app.appid}", .stack_size = {app.stack_size}, .icon = {f"&{app.icon}" if app.icon else "NULL"}, - .flags = {'|'.join(f"FlipperApplicationFlag{flag}" for flag in app.flags)} }}""" + .flags = {'|'.join(f"FlipperInternalApplicationFlag{flag}" for flag in app.flags)} }}""" def generate(self): contents = [ @@ -408,7 +414,7 @@ def generate(self): contents.extend( [ self.get_app_ep_forward(archive_app[0]), - f"const FlipperApplication FLIPPER_ARCHIVE = {self.get_app_descr(archive_app[0])};", + f"const FlipperInternalApplication FLIPPER_ARCHIVE = {self.get_app_descr(archive_app[0])};", ] ) diff --git a/scripts/fbt/sdk/collector.py b/scripts/fbt/sdk/collector.py index 578a8c7a62b9..1dd3bc4ebb99 100644 --- a/scripts/fbt/sdk/collector.py +++ b/scripts/fbt/sdk/collector.py @@ -1,4 +1,5 @@ from typing import List +from .hashes import gnu_sym_hash from cxxheaderparser.parser import CxxParser from . import ( @@ -72,13 +73,6 @@ def add_header(self, header: str): self.api.headers.add(ApiHeader(header)) -def gnu_sym_hash(name: str): - h = 0x1505 - for c in name: - h = (h << 5) + h + ord(c) - return str(hex(h))[-8:] - - class SdkCollector: def __init__(self): self.symbol_manager = SymbolManager() diff --git a/scripts/fbt/sdk/hashes.py b/scripts/fbt/sdk/hashes.py new file mode 100644 index 000000000000..fef88ddb5ee0 --- /dev/null +++ b/scripts/fbt/sdk/hashes.py @@ -0,0 +1,5 @@ +def gnu_sym_hash(name: str) -> int: + h = 0x1505 + for c in name: + h = ((h << 5) + h + ord(c)) & 0xFFFFFFFF + return h diff --git a/scripts/fbt_tools/fbt_extapps.py b/scripts/fbt_tools/fbt_extapps.py index 16d5dcbabd34..69d70021413d 100644 --- a/scripts/fbt_tools/fbt_extapps.py +++ b/scripts/fbt_tools/fbt_extapps.py @@ -384,10 +384,16 @@ def generate_embed_app_metadata_actions(source, target, env, for_signature): "${SOURCES} ${TARGET}" ) - actions.append( - Action( - objcopy_str, - "$APPMETAEMBED_COMSTR", + actions.extend( + ( + Action( + objcopy_str, + "$APPMETAEMBED_COMSTR", + ), + Action( + "${PYTHON3} ${FBT_SCRIPT_DIR}/fastfap.py ${TARGET} ${OBJCOPY}", + "$FASTFAP_COMSTR", + ), ) ) @@ -450,6 +456,7 @@ def generate(env, **kw): APPMETA_COMSTR="\tAPPMETA\t${TARGET}", APPFILE_COMSTR="\tAPPFILE\t${TARGET}", APPMETAEMBED_COMSTR="\tFAP\t${TARGET}", + FASTFAP_COMSTR="\tFASTFAP\t${TARGET}", APPCHECK_COMSTR="\tAPPCHK\t${SOURCE}", ) diff --git a/scripts/fwsize.py b/scripts/fwsize.py old mode 100644 new mode 100755 diff --git a/scripts/get_env.py b/scripts/get_env.py old mode 100644 new mode 100755 diff --git a/scripts/runfap.py b/scripts/runfap.py old mode 100644 new mode 100755 index a240acf1212f..42141acff656 --- a/scripts/runfap.py +++ b/scripts/runfap.py @@ -63,7 +63,7 @@ def install(self): storage_ops.recursive_send(fap_dst_path, fap_local_path, False) fap_host_app = self.args.targets[0] - startup_command = f'"Applications" {fap_host_app}' + startup_command = f"{fap_host_app}" if self.args.host_app: startup_command = self.args.host_app diff --git a/scripts/sconsdist.py b/scripts/sconsdist.py old mode 100644 new mode 100755 diff --git a/scripts/selfupdate.py b/scripts/selfupdate.py old mode 100644 new mode 100755 diff --git a/scripts/slideshow.py b/scripts/slideshow.py old mode 100644 new mode 100755 diff --git a/scripts/testing/await_flipper.py b/scripts/testing/await_flipper.py index 2b4c8b4c39bc..ea07d6be7ff3 100755 --- a/scripts/testing/await_flipper.py +++ b/scripts/testing/await_flipper.py @@ -8,6 +8,7 @@ def flp_serial_by_name(flp_name): if sys.platform == "darwin": # MacOS flp_serial = "/dev/cu.usbmodemflip_" + flp_name + "1" + logging.info(f"Darwin, looking for {flp_serial}") elif sys.platform == "linux": # Linux flp_serial = ( "/dev/serial/by-id/usb-Flipper_Devices_Inc._Flipper_" @@ -16,10 +17,12 @@ def flp_serial_by_name(flp_name): + flp_name + "-if00" ) + logging.info(f"linux, looking for {flp_serial}") if os.path.exists(flp_serial): return flp_serial else: + logging.info(f"Couldn't find {logging.info} on this attempt.") if os.path.exists(flp_name): return flp_name else: @@ -38,7 +41,7 @@ def main(): level=logging.INFO, datefmt="%Y-%m-%d %H:%M:%S", ) - logging.info("Waiting for Flipper to be ready...") + logging.info(f"Waiting for Flipper {flipper_name} to be ready...") while flipper == "" and elapsed < UPDATE_TIMEOUT: elapsed += 1 diff --git a/scripts/testing/units.py b/scripts/testing/units.py index 5083bcd4350b..fd8e29a73336 100755 --- a/scripts/testing/units.py +++ b/scripts/testing/units.py @@ -20,13 +20,13 @@ def main(): logging.error("Flipper not found!") sys.exit(1) - with serial.Serial(flp_serial, timeout=1) as flipper: + with serial.Serial(flp_serial, timeout=10) as flipper: logging.info(f"Found Flipper at {flp_serial}") flipper.baudrate = 230400 flipper.flushOutput() flipper.flushInput() - flipper.timeout = 180 + flipper.timeout = 300 flipper.read_until(b">: ").decode("utf-8") flipper.write(b"unit_tests\r") diff --git a/scripts/toolchain/fbtenv.cmd b/scripts/toolchain/fbtenv.cmd index 9d45b7e9d7ec..4ae04e2a2cbf 100644 --- a/scripts/toolchain/fbtenv.cmd +++ b/scripts/toolchain/fbtenv.cmd @@ -13,7 +13,7 @@ if not ["%FBT_NOENV%"] == [""] ( exit /b 0 ) -set "FLIPPER_TOOLCHAIN_VERSION=21" +set "FLIPPER_TOOLCHAIN_VERSION=22" if ["%FBT_TOOLCHAIN_PATH%"] == [""] ( set "FBT_TOOLCHAIN_PATH=%FBT_ROOT%" diff --git a/scripts/toolchain/fbtenv.sh b/scripts/toolchain/fbtenv.sh index 143dce74b914..e5548f488b1b 100755 --- a/scripts/toolchain/fbtenv.sh +++ b/scripts/toolchain/fbtenv.sh @@ -4,7 +4,7 @@ # public variables DEFAULT_SCRIPT_PATH="$(pwd -P)"; -FBT_TOOLCHAIN_VERSION="${FBT_TOOLCHAIN_VERSION:-"21"}"; +FBT_TOOLCHAIN_VERSION="${FBT_TOOLCHAIN_VERSION:-"22"}"; if [ -z ${FBT_TOOLCHAIN_PATH+x} ] ; then FBT_TOOLCHAIN_PATH_WAS_SET=0; diff --git a/scripts/version.py b/scripts/version.py old mode 100644 new mode 100755 diff --git a/site_scons/commandline.scons b/site_scons/commandline.scons index b70b5cff56f1..776977cda74b 100644 --- a/site_scons/commandline.scons +++ b/site_scons/commandline.scons @@ -228,6 +228,7 @@ vars.AddVariables( ("applications/debug", False), ("applications/external", False), ("applications/examples", False), + ("applications/drivers", False), ("applications_user", False), ], ), From 2a9ca19c395b260e14dc478eb84bdc3787e325cc Mon Sep 17 00:00:00 2001 From: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Date: Tue, 4 Jul 2023 15:38:31 +0300 Subject: [PATCH 117/149] Nfc gui rework (#2822) * Enable card info in saved menu * Initial (incomplete) implementation of DESfire file loading * Complete implementation of loading DESFire files * Improve prefix handling * Load file contents * Use buffered file stream for loading files * Implement DESFire saving * Move layout struct definition inside function * Use buffered file format for saving * Correctly copy ATQA upon activation * Initial protocol support framework implementation * Get rid of format helper folder * Remove unneeded includes * Implement protocol-dependent scene handling framework * Improve unified scenes via protocol_support * Improve GUI protocol support * Separate include files * Rename and separate some files * Add unified Read menu * Remove unneeded scenes * Code cleanup --- .../helpers/format/nfc_mf_desfire_format.h | 27 - .../nfc/helpers/format/nfc_protocol_format.c | 155 ----- .../nfc/helpers/format/nfc_protocol_format.h | 17 - .../nfc/helpers/handlers/nfc_poller_handler.c | 115 ---- .../nfc/helpers/handlers/nfc_poller_handler.h | 7 - .../iso14443_3a/iso14443_3a.c | 94 +++ .../iso14443_3a/iso14443_3a.h | 5 + .../iso14443_3a/iso14443_3a_i.h | 9 + .../iso14443_3a/iso14443_3a_render.c | 22 + .../iso14443_3a/iso14443_3a_render.h | 10 + .../iso14443_4a/iso14443_4a.c | 80 +++ .../iso14443_4a/iso14443_4a.h | 5 + .../iso14443_4a/iso14443_4a_render.c | 11 + .../iso14443_4a/iso14443_4a_render.h | 10 + .../protocol_support/mf_classic/mf_classic.c | 135 +++++ .../protocol_support/mf_classic/mf_classic.h | 5 + .../mf_classic/mf_classic_render.c | 21 + .../mf_classic/mf_classic_render.h | 10 + .../protocol_support/mf_desfire/mf_desfire.c | 84 +++ .../protocol_support/mf_desfire/mf_desfire.h | 5 + .../mf_desfire/mf_desfire_render.c} | 63 +- .../mf_desfire/mf_desfire_render.h | 34 ++ .../mf_ultralight/mf_ultralight.c | 161 ++++++ .../mf_ultralight/mf_ultralight.h | 5 + .../mf_ultralight/mf_ultralight_render.c | 17 + .../mf_ultralight/mf_ultralight_render.h | 10 + .../protocol_support/nfc_protocol_support.c | 241 ++++++++ .../protocol_support/nfc_protocol_support.h | 27 + .../nfc_protocol_support_base.h | 32 ++ .../nfc_protocol_support_common.h | 18 + .../nfc_protocol_support_defs.c | 16 + .../nfc_protocol_support_defs.h | 5 + .../nfc_protocol_support_gui_common.c | 20 + .../nfc_protocol_support_gui_common.h | 20 + .../nfc_protocol_support_render_common.h | 6 + applications/main/nfc/nfc_app.c | 4 +- applications/main/nfc/nfc_app_i.h | 5 +- .../main/nfc/scenes/nfc_scene_config.h | 5 +- .../main/nfc/scenes/nfc_scene_generate_info.c | 2 +- applications/main/nfc/scenes/nfc_scene_info.c | 45 +- .../scenes/nfc_scene_mf_classic_dict_attack.c | 2 + .../nfc/scenes/nfc_scene_mf_classic_menu.c | 81 --- .../nfc/scenes/nfc_scene_mf_desfire_app.c | 10 +- .../nfc/scenes/nfc_scene_mf_desfire_data.c | 4 +- .../nfc/scenes/nfc_scene_mf_desfire_menu.c | 68 --- .../nfc/scenes/nfc_scene_mf_ultralight_menu.c | 85 --- .../main/nfc/scenes/nfc_scene_nfca_menu.c | 65 --- applications/main/nfc/scenes/nfc_scene_read.c | 4 +- .../main/nfc/scenes/nfc_scene_read_menu.c | 33 ++ .../main/nfc/scenes/nfc_scene_read_success.c | 43 +- .../main/nfc/scenes/nfc_scene_saved_menu.c | 160 +----- lib/nfc/nfc_device.c | 8 +- lib/nfc/protocols/iso14443_3a/iso14443_3a.c | 6 +- .../iso14443_3a/iso14443_3a_poller_i.c | 2 +- lib/nfc/protocols/iso14443_4a/iso14443_4a.c | 18 +- lib/nfc/protocols/mf_desfire/mf_desfire.c | 136 ++++- lib/nfc/protocols/mf_desfire/mf_desfire.h | 14 +- lib/nfc/protocols/mf_desfire/mf_desfire_i.c | 544 +++++++++++++++++- lib/nfc/protocols/mf_desfire/mf_desfire_i.h | 89 +++ 59 files changed, 1997 insertions(+), 938 deletions(-) delete mode 100644 applications/main/nfc/helpers/format/nfc_mf_desfire_format.h delete mode 100644 applications/main/nfc/helpers/format/nfc_protocol_format.c delete mode 100644 applications/main/nfc/helpers/format/nfc_protocol_format.h delete mode 100644 applications/main/nfc/helpers/handlers/nfc_poller_handler.c delete mode 100644 applications/main/nfc/helpers/handlers/nfc_poller_handler.h create mode 100644 applications/main/nfc/helpers/protocol_support/iso14443_3a/iso14443_3a.c create mode 100644 applications/main/nfc/helpers/protocol_support/iso14443_3a/iso14443_3a.h create mode 100644 applications/main/nfc/helpers/protocol_support/iso14443_3a/iso14443_3a_i.h create mode 100644 applications/main/nfc/helpers/protocol_support/iso14443_3a/iso14443_3a_render.c create mode 100644 applications/main/nfc/helpers/protocol_support/iso14443_3a/iso14443_3a_render.h create mode 100644 applications/main/nfc/helpers/protocol_support/iso14443_4a/iso14443_4a.c create mode 100644 applications/main/nfc/helpers/protocol_support/iso14443_4a/iso14443_4a.h create mode 100644 applications/main/nfc/helpers/protocol_support/iso14443_4a/iso14443_4a_render.c create mode 100644 applications/main/nfc/helpers/protocol_support/iso14443_4a/iso14443_4a_render.h create mode 100644 applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c create mode 100644 applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.h create mode 100644 applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic_render.c create mode 100644 applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic_render.h create mode 100644 applications/main/nfc/helpers/protocol_support/mf_desfire/mf_desfire.c create mode 100644 applications/main/nfc/helpers/protocol_support/mf_desfire/mf_desfire.h rename applications/main/nfc/helpers/{format/nfc_mf_desfire_format.c => protocol_support/mf_desfire/mf_desfire_render.c} (75%) create mode 100644 applications/main/nfc/helpers/protocol_support/mf_desfire/mf_desfire_render.h create mode 100644 applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c create mode 100644 applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.h create mode 100644 applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight_render.c create mode 100644 applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight_render.h create mode 100644 applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c create mode 100644 applications/main/nfc/helpers/protocol_support/nfc_protocol_support.h create mode 100644 applications/main/nfc/helpers/protocol_support/nfc_protocol_support_base.h create mode 100644 applications/main/nfc/helpers/protocol_support/nfc_protocol_support_common.h create mode 100644 applications/main/nfc/helpers/protocol_support/nfc_protocol_support_defs.c create mode 100644 applications/main/nfc/helpers/protocol_support/nfc_protocol_support_defs.h create mode 100644 applications/main/nfc/helpers/protocol_support/nfc_protocol_support_gui_common.c create mode 100644 applications/main/nfc/helpers/protocol_support/nfc_protocol_support_gui_common.h create mode 100644 applications/main/nfc/helpers/protocol_support/nfc_protocol_support_render_common.h delete mode 100644 applications/main/nfc/scenes/nfc_scene_mf_classic_menu.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_mf_desfire_menu.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_nfca_menu.c create mode 100644 applications/main/nfc/scenes/nfc_scene_read_menu.c diff --git a/applications/main/nfc/helpers/format/nfc_mf_desfire_format.h b/applications/main/nfc/helpers/format/nfc_mf_desfire_format.h deleted file mode 100644 index 85f137fb6b68..000000000000 --- a/applications/main/nfc/helpers/format/nfc_mf_desfire_format.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -#include - -void nfc_mf_desfire_format_data(const MfDesfireData* data, FuriString* str); - -void nfc_mf_desfire_format_version(const MfDesfireVersion* data, FuriString* str); - -void nfc_mf_desfire_format_free_memory(const MfDesfireFreeMemory* data, FuriString* str); - -void nfc_mf_desfire_format_key_settings(const MfDesfireKeySettings* data, FuriString* str); - -void nfc_mf_desfire_format_key_version( - const MfDesfireKeyVersion* data, - uint32_t index, - FuriString* str); - -void nfc_mf_desfire_format_application_id(const MfDesfireApplicationId* data, FuriString* str); - -void nfc_mf_desfire_format_application(const MfDesfireApplication* data, FuriString* str); - -void nfc_mf_desfire_format_file_id(const MfDesfireFileId* data, FuriString* str); - -void nfc_mf_desfire_format_file_settings_data( - const MfDesfireFileSettings* settings, - const MfDesfireFileData* data, - FuriString* str); diff --git a/applications/main/nfc/helpers/format/nfc_protocol_format.c b/applications/main/nfc/helpers/format/nfc_protocol_format.c deleted file mode 100644 index 95cb76131179..000000000000 --- a/applications/main/nfc/helpers/format/nfc_protocol_format.c +++ /dev/null @@ -1,155 +0,0 @@ -#include "nfc_protocol_format.h" - -#include -#include -#include -#include - -typedef void (*NfcProtocolFormatRenderInfo)( - const NfcDevice* device, - NfcProtocolFormatType type, - FuriString* str); - -typedef struct { - NfcProtocolFormatRenderInfo render_info; - const NfcProtocolFormatFeature flags; -} NfcProtocolFormatBase; - -static void nfc_protocol_format_info_iso14443_3a_common( - const Iso14443_3aData* nfc_data, - NfcProtocolFormatType type, - FuriString* str) { - if(type == NfcProtocolFormatTypeFull) { - const char iso_type = FURI_BIT(nfc_data->sak, 5) ? '4' : '3'; - furi_string_cat_printf(str, "ISO 14443-%c (NFC-A)\n", iso_type); - } - - furi_string_cat_printf(str, "UID:"); - - for(size_t i = 0; i < nfc_data->uid_len; i++) { - furi_string_cat_printf(str, " %02X", nfc_data->uid[i]); - } - - if(type == NfcProtocolFormatTypeFull) { - furi_string_cat_printf(str, "\nATQA: %02X %02X ", nfc_data->atqa[1], nfc_data->atqa[0]); - furi_string_cat_printf(str, " SAK: %02X", nfc_data->sak); - } -} - -static void nfc_protocol_format_info_iso14443_3a( - const NfcDevice* device, - NfcProtocolFormatType type, - FuriString* str) { - UNUSED(type); - const Iso14443_3aData* data = nfc_device_get_data(device, NfcProtocolIso14443_3a); - nfc_protocol_format_info_iso14443_3a_common(data, NfcProtocolFormatTypeFull, str); -} - -static void nfc_protocol_format_info_iso14443_4a( - const NfcDevice* device, - NfcProtocolFormatType type, - FuriString* str) { - UNUSED(type); - const Iso14443_4aData* data = nfc_device_get_data(device, NfcProtocolIso14443_4a); - nfc_protocol_format_info_iso14443_3a_common( - data->iso14443_3a_data, NfcProtocolFormatTypeFull, str); -} - -static void nfc_protocol_format_info_mf_ultralight( - const NfcDevice* device, - NfcProtocolFormatType type, - FuriString* str) { - const MfUltralightData* data = nfc_device_get_data(device, NfcProtocolMfUltralight); - nfc_protocol_format_info_iso14443_3a_common(data->iso14443_3a_data, type, str); - - furi_string_cat_printf(str, "\nPages Read: %u/%u", data->pages_read, data->pages_total); - if(data->pages_read != data->pages_total) { - furi_string_cat_printf(str, "\nPassword-protected pages!"); - } -} - -static void nfc_protocol_format_info_mf_classic( - const NfcDevice* device, - NfcProtocolFormatType type, - FuriString* str) { - const MfClassicData* data = nfc_device_get_data(device, NfcProtocolMfClassic); - nfc_protocol_format_info_iso14443_3a_common(data->iso14443_3a_data, type, str); - - uint8_t sectors_total = mf_classic_get_total_sectors_num(data->type); - uint8_t keys_total = sectors_total * 2; - uint8_t keys_found = 0; - uint8_t sectors_read = 0; - mf_classic_get_read_sectors_and_keys(data, §ors_read, &keys_found); - - furi_string_cat_printf(str, "\nKeys Found: %u/%u", keys_found, keys_total); - furi_string_cat_printf(str, "\nSectors Read: %u/%u", sectors_read, sectors_total); -} - -// TODO: use proper type getters -static void nfc_protocol_format_info_mf_desfire( - const NfcDevice* device, - NfcProtocolFormatType type, - FuriString* str) { - const MfDesfireData* data = nfc_device_get_data(device, NfcProtocolMfDesfire); - nfc_protocol_format_info_iso14443_3a_common( - data->iso14443_4a_data->iso14443_3a_data, type, str); - - const uint32_t bytes_total = 1UL << (data->version.sw_storage >> 1); - const uint32_t bytes_free = data->free_memory.is_present ? data->free_memory.bytes_free : 0; - - furi_string_cat_printf(str, "\n%lu", bytes_total); - - if(data->version.sw_storage & 1) { - furi_string_push_back(str, '+'); - } - - furi_string_cat_printf(str, " bytes, %lu bytes free\n", bytes_free); - - const uint32_t app_count = simple_array_get_count(data->applications); - uint32_t file_count = 0; - - for(uint32_t i = 0; i < app_count; ++i) { - const MfDesfireApplication* app = simple_array_cget(data->applications, i); - file_count += simple_array_get_count(app->file_ids); - } - - furi_string_cat_printf(str, "%lu Application%s", app_count, app_count != 1 ? "s" : ""); - furi_string_cat_printf(str, ", %lu File%s", file_count, file_count != 1 ? "s" : ""); -} - -static const NfcProtocolFormatBase nfc_protocol_format[NfcProtocolNum] = { - [NfcProtocolIso14443_3a] = - { - .flags = NfcProtocolFormatFeatureNone, - .render_info = nfc_protocol_format_info_iso14443_3a, - }, - [NfcProtocolIso14443_4a] = - { - .flags = NfcProtocolFormatFeatureNone, - .render_info = nfc_protocol_format_info_iso14443_4a, - }, - [NfcProtocolMfUltralight] = - { - .flags = NfcProtocolFormatFeatureMoreData, - .render_info = nfc_protocol_format_info_mf_ultralight, - }, - [NfcProtocolMfClassic] = - { - .flags = NfcProtocolFormatFeatureMoreData, - .render_info = nfc_protocol_format_info_mf_classic, - }, - [NfcProtocolMfDesfire] = - { - .flags = NfcProtocolFormatFeatureMoreData, - .render_info = nfc_protocol_format_info_mf_desfire, - }, -}; - -NfcProtocolFormatFeature nfc_protocol_format_get_features(const NfcDevice* device) { - return nfc_protocol_format[nfc_device_get_protocol(device)].flags; -} - -void nfc_protocol_format_info(const NfcDevice* device, NfcProtocolFormatType type, FuriString* str) { - furi_string_cat_printf(str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull)); - nfc_protocol_format[nfc_device_get_protocol(device)].render_info(device, type, str); -} diff --git a/applications/main/nfc/helpers/format/nfc_protocol_format.h b/applications/main/nfc/helpers/format/nfc_protocol_format.h deleted file mode 100644 index f1c2bf3244a4..000000000000 --- a/applications/main/nfc/helpers/format/nfc_protocol_format.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include - -typedef enum { - NfcProtocolFormatFeatureNone = 0, - NfcProtocolFormatFeatureMoreData = 1UL << 0, -} NfcProtocolFormatFeature; - -typedef enum { - NfcProtocolFormatTypeShort, - NfcProtocolFormatTypeFull, -} NfcProtocolFormatType; - -NfcProtocolFormatFeature nfc_protocol_format_get_features(const NfcDevice* device); - -void nfc_protocol_format_info(const NfcDevice* device, NfcProtocolFormatType type, FuriString* str); diff --git a/applications/main/nfc/helpers/handlers/nfc_poller_handler.c b/applications/main/nfc/helpers/handlers/nfc_poller_handler.c deleted file mode 100644 index 8b891d05057e..000000000000 --- a/applications/main/nfc/helpers/handlers/nfc_poller_handler.c +++ /dev/null @@ -1,115 +0,0 @@ -#include "nfc_poller_handler.h" - -#include "../../nfc_app_i.h" - -typedef NfcCustomEvent (*NfcPollerReadHandler)(Iso14443_3aPollerEvent* event, NfcApp* nfc_app); - -static NfcCustomEvent - nfc_poller_handler_read_iso14443_3a(Iso14443_3aPollerEvent* event, NfcApp* nfc_app) { - UNUSED(nfc_app); - NfcCustomEvent custom_event = NfcCustomEventReadHandlerIgnore; - - if(event->type == Iso14443_3aPollerEventTypeReady) { - custom_event = NfcCustomEventReadHandlerSuccess; - } - - return custom_event; -} - -static NfcCustomEvent - nfc_poller_handler_read_iso14443_4a(Iso14443_4aPollerEvent* event, NfcApp* nfc_app) { - UNUSED(nfc_app); - NfcCustomEvent custom_event = NfcCustomEventReadHandlerIgnore; - - if(event->type == Iso14443_4aPollerEventTypeReady) { - custom_event = NfcCustomEventReadHandlerSuccess; - } - - return custom_event; -} - -static NfcCustomEvent - nfc_poller_handler_read_mf_ultralight(MfUltralightPollerEvent* event, NfcApp* nfc_app) { - NfcCustomEvent custom_event = NfcCustomEventReadHandlerIgnore; - - if(event->type == MfUltralightPollerEventTypeReadSuccess) { - custom_event = NfcCustomEventReadHandlerSuccess; - } else if(event->type == MfUltralightPollerEventTypeAuthRequest) { - nfc_device_set_data( - nfc_app->nfc_device, NfcProtocolMfUltralight, nfc_poller_get_data(nfc_app->poller)); - const MfUltralightData* data = - nfc_device_get_data(nfc_app->nfc_device, NfcProtocolMfUltralight); - if(nfc_app->mf_ul_auth->type == MfUltralightAuthTypeXiaomii) { - if(mf_ultralight_generate_xiaomi_pass( - nfc_app->mf_ul_auth, - data->iso14443_3a_data->uid, - data->iso14443_3a_data->uid_len)) { - event->data->auth_context.skip_auth = false; - } - } else if(nfc_app->mf_ul_auth->type == MfUltralightAuthTypeAmiibo) { - if(mf_ultralight_generate_amiibo_pass( - nfc_app->mf_ul_auth, - data->iso14443_3a_data->uid, - data->iso14443_3a_data->uid_len)) { - event->data->auth_context.skip_auth = false; - } - } else if(nfc_app->mf_ul_auth->type == MfUltralightAuthTypeManual) { - event->data->auth_context.skip_auth = false; - } else { - event->data->auth_context.skip_auth = true; - } - if(!event->data->auth_context.skip_auth) { - event->data->auth_context.password = nfc_app->mf_ul_auth->password; - } - } else if(event->type == MfUltralightPollerEventTypeAuthSuccess) { - nfc_app->mf_ul_auth->pack = event->data->auth_context.pack; - } - - return custom_event; -} - -static NfcCustomEvent - nfc_poller_handler_read_mf_classic(MfClassicPollerEvent* event, NfcApp* nfc_app) { - UNUSED(event); - UNUSED(nfc_app); - - NfcCustomEvent custom_event = NfcCustomEventReadHandlerIgnore; - // TODO: Implement read mf_classic using key cache - return custom_event; -} - -static NfcCustomEvent - nfc_poller_handler_read_mf_desfire(MfDesfirePollerEvent* event, NfcApp* nfc_app) { - UNUSED(nfc_app); - NfcCustomEvent custom_event = NfcCustomEventReadHandlerIgnore; - - if(event->type == MfDesfirePollerEventTypeReadSuccess) { - custom_event = NfcCustomEventReadHandlerSuccess; - } - - return custom_event; -} - -static const NfcPollerReadHandler nfc_poller_handlers_read[] = { - [NfcProtocolIso14443_3a] = (NfcPollerReadHandler)nfc_poller_handler_read_iso14443_3a, - [NfcProtocolIso14443_4a] = (NfcPollerReadHandler)nfc_poller_handler_read_iso14443_4a, - [NfcProtocolMfUltralight] = (NfcPollerReadHandler)nfc_poller_handler_read_mf_ultralight, - [NfcProtocolMfClassic] = (NfcPollerReadHandler)nfc_poller_handler_read_mf_classic, - [NfcProtocolMfDesfire] = (NfcPollerReadHandler)nfc_poller_handler_read_mf_desfire, -}; -NfcCustomEvent nfc_poller_handler_read(NfcGenericEvent event, void* context) { - furi_assert(context); - furi_assert(event.instance); - furi_assert(event.data); - furi_assert(event.protocol < COUNT_OF(nfc_poller_handlers_read)); - - NfcApp* nfc_app = context; - - NfcCustomEvent custom_event = nfc_poller_handlers_read[event.protocol](event.data, context); - if(custom_event == NfcCustomEventReadHandlerSuccess) { - nfc_device_set_data( - nfc_app->nfc_device, event.protocol, nfc_poller_get_data(nfc_app->poller)); - } - - return custom_event; -} diff --git a/applications/main/nfc/helpers/handlers/nfc_poller_handler.h b/applications/main/nfc/helpers/handlers/nfc_poller_handler.h deleted file mode 100644 index 54eb809ada75..000000000000 --- a/applications/main/nfc/helpers/handlers/nfc_poller_handler.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -#include "../nfc_custom_event.h" - -#include - -NfcCustomEvent nfc_poller_handler_read(NfcGenericEvent event, void* context); diff --git a/applications/main/nfc/helpers/protocol_support/iso14443_3a/iso14443_3a.c b/applications/main/nfc/helpers/protocol_support/iso14443_3a/iso14443_3a.c new file mode 100644 index 000000000000..6dd83ab16e13 --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/iso14443_3a/iso14443_3a.c @@ -0,0 +1,94 @@ +#include "iso14443_3a_i.h" +#include "iso14443_3a_render.h" + +#include + +#include "../nfc_protocol_support_gui_common.h" +#include "../../../nfc_app_i.h" + +static void nfc_protocol_support_render_info_iso14443_3a( + const Iso14443_3aData* data, + NfcProtocolFormatType format_type, + FuriString* str) { + nfc_render_iso14443_3a_info(data, format_type, str); +} + +static NfcCustomEvent + nfc_protocol_support_handle_poller_iso14443_3a(Iso14443_3aPollerEvent* event, void* context) { + UNUSED(context); + NfcCustomEvent custom_event = NfcCustomEventReadHandlerIgnore; + + if(event->type == Iso14443_3aPollerEventTypeReady) { + custom_event = NfcCustomEventReadHandlerSuccess; + } + + return custom_event; +} + +static void nfc_protocol_support_build_scene_read_menu_iso14443_3a(NfcApp* instance) { + UNUSED(instance); +} + +static void nfc_protocol_support_build_scene_saved_menu_iso14443_3a(NfcApp* instance) { + UNUSED(instance); +} + +static bool nfc_protocol_support_handle_scene_info_iso14443_3a(NfcApp* instance, uint32_t event) { + if(event == GuiButtonTypeRight) { + scene_manager_next_scene(instance->scene_manager, NfcSceneNotImplemented); + return true; + } + + return false; +} + +static bool + nfc_protocol_support_handle_scene_read_menu_iso14443_3a(NfcApp* instance, uint32_t event) { + if(event == SubmenuIndexCommonEmulate) { + scene_manager_next_scene(instance->scene_manager, NfcSceneNfcaEmulate); + return true; + } + + return false; +} + +bool nfc_protocol_support_handle_scene_saved_menu_iso14443_3a_common( + NfcApp* instance, + uint32_t event) { + switch(event) { + case SubmenuIndexCommonEmulate: + scene_manager_next_scene(instance->scene_manager, NfcSceneNfcaEmulate); + return true; + case SubmenuIndexCommonEdit: + scene_manager_next_scene(instance->scene_manager, NfcSceneSetUid); + return true; + default: + return false; + } +} + +static bool + nfc_protocol_support_handle_scene_saved_menu_iso14443_3a(NfcApp* instance, uint32_t event) { + return nfc_protocol_support_handle_scene_saved_menu_iso14443_3a_common(instance, event); +} + +const NfcProtocolSupportBase nfc_protocol_support_iso14443_3a = { + .features = NfcProtocolFeatureEmulateUid | NfcProtocolFeatureEditUid, + + .render_info = (NfcProtocolSupportRenderData)nfc_protocol_support_render_info_iso14443_3a, + + .handle_poller = + (NfcProtocolSupportPollerHandler)nfc_protocol_support_handle_poller_iso14443_3a, + + .build_scene_read_menu = + (NfcProtocolSupportSceneBuilder)nfc_protocol_support_build_scene_read_menu_iso14443_3a, + .build_scene_saved_menu = + (NfcProtocolSupportSceneBuilder)nfc_protocol_support_build_scene_saved_menu_iso14443_3a, + + .handle_scene_info = + (NfcProtocolSupportSceneHandler)nfc_protocol_support_handle_scene_info_iso14443_3a, + .handle_scene_read_menu = + (NfcProtocolSupportSceneHandler)nfc_protocol_support_handle_scene_read_menu_iso14443_3a, + .handle_scene_saved_menu = + (NfcProtocolSupportSceneHandler)nfc_protocol_support_handle_scene_saved_menu_iso14443_3a, +}; diff --git a/applications/main/nfc/helpers/protocol_support/iso14443_3a/iso14443_3a.h b/applications/main/nfc/helpers/protocol_support/iso14443_3a/iso14443_3a.h new file mode 100644 index 000000000000..d085f25c77ba --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/iso14443_3a/iso14443_3a.h @@ -0,0 +1,5 @@ +#pragma once + +#include "../nfc_protocol_support_base.h" + +extern const NfcProtocolSupportBase nfc_protocol_support_iso14443_3a; diff --git a/applications/main/nfc/helpers/protocol_support/iso14443_3a/iso14443_3a_i.h b/applications/main/nfc/helpers/protocol_support/iso14443_3a/iso14443_3a_i.h new file mode 100644 index 000000000000..2c41d475f0d1 --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/iso14443_3a/iso14443_3a_i.h @@ -0,0 +1,9 @@ +#pragma once + +#include + +#include "iso14443_3a.h" + +bool nfc_protocol_support_handle_scene_saved_menu_iso14443_3a_common( + NfcApp* instance, + uint32_t event); diff --git a/applications/main/nfc/helpers/protocol_support/iso14443_3a/iso14443_3a_render.c b/applications/main/nfc/helpers/protocol_support/iso14443_3a/iso14443_3a_render.c new file mode 100644 index 000000000000..805680856cf6 --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/iso14443_3a/iso14443_3a_render.c @@ -0,0 +1,22 @@ +#include "iso14443_3a_render.h" + +void nfc_render_iso14443_3a_info( + const Iso14443_3aData* data, + NfcProtocolFormatType format_type, + FuriString* str) { + if(format_type == NfcProtocolFormatTypeFull) { + const char iso_type = FURI_BIT(data->sak, 5) ? '4' : '3'; + furi_string_cat_printf(str, "ISO 14443-%c (NFC-A)\n", iso_type); + } + + furi_string_cat_printf(str, "UID:"); + + for(size_t i = 0; i < data->uid_len; i++) { + furi_string_cat_printf(str, " %02X", data->uid[i]); + } + + if(format_type == NfcProtocolFormatTypeFull) { + furi_string_cat_printf(str, "\nATQA: %02X %02X ", data->atqa[1], data->atqa[0]); + furi_string_cat_printf(str, " SAK: %02X", data->sak); + } +} diff --git a/applications/main/nfc/helpers/protocol_support/iso14443_3a/iso14443_3a_render.h b/applications/main/nfc/helpers/protocol_support/iso14443_3a/iso14443_3a_render.h new file mode 100644 index 000000000000..ed5e3677c9d6 --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/iso14443_3a/iso14443_3a_render.h @@ -0,0 +1,10 @@ +#pragma once + +#include + +#include "../nfc_protocol_support_render_common.h" + +void nfc_render_iso14443_3a_info( + const Iso14443_3aData* data, + NfcProtocolFormatType format_type, + FuriString* str); diff --git a/applications/main/nfc/helpers/protocol_support/iso14443_4a/iso14443_4a.c b/applications/main/nfc/helpers/protocol_support/iso14443_4a/iso14443_4a.c new file mode 100644 index 000000000000..854ed483e7ad --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/iso14443_4a/iso14443_4a.c @@ -0,0 +1,80 @@ +#include "iso14443_4a.h" +#include "iso14443_4a_render.h" + +#include + +#include "../nfc_protocol_support_gui_common.h" +#include "../iso14443_3a/iso14443_3a_i.h" +#include "../../../nfc_app_i.h" + +static void nfc_protocol_support_render_info_iso14443_4a( + const Iso14443_4aData* data, + NfcProtocolFormatType format_type, + FuriString* str) { + nfc_render_iso14443_4a_info(data, format_type, str); +} + +static NfcCustomEvent + nfc_protocol_support_handle_poller_iso14443_4a(Iso14443_4aPollerEvent* event, void* context) { + UNUSED(context); + NfcCustomEvent custom_event = NfcCustomEventReadHandlerIgnore; + + if(event->type == Iso14443_4aPollerEventTypeReady) { + custom_event = NfcCustomEventReadHandlerSuccess; + } + + return custom_event; +} + +static void nfc_protocol_support_build_scene_read_menu_iso14443_4a(NfcApp* instance) { + UNUSED(instance); +} + +static void nfc_protocol_support_build_scene_saved_menu_iso14443_4a(NfcApp* instance) { + UNUSED(instance); +} + +static bool nfc_protocol_support_handle_scene_info_iso14443_4a(NfcApp* instance, uint32_t event) { + if(event == GuiButtonTypeRight) { + scene_manager_next_scene(instance->scene_manager, NfcSceneNotImplemented); + return true; + } + + return false; +} + +static bool + nfc_protocol_support_handle_scene_read_menu_iso14443_4a(NfcApp* instance, uint32_t event) { + if(event == SubmenuIndexCommonEmulate) { + scene_manager_next_scene(instance->scene_manager, NfcSceneNfcaEmulate); + return true; + } + + return false; +} + +static bool + nfc_protocol_support_handle_scene_saved_menu_iso14443_4a(NfcApp* instance, uint32_t event) { + return nfc_protocol_support_handle_scene_saved_menu_iso14443_3a_common(instance, event); +} + +const NfcProtocolSupportBase nfc_protocol_support_iso14443_4a = { + .features = NfcProtocolFeatureEmulateUid | NfcProtocolFeatureEditUid, + + .render_info = (NfcProtocolSupportRenderData)nfc_protocol_support_render_info_iso14443_4a, + + .handle_poller = + (NfcProtocolSupportPollerHandler)nfc_protocol_support_handle_poller_iso14443_4a, + + .build_scene_read_menu = + (NfcProtocolSupportSceneBuilder)nfc_protocol_support_build_scene_read_menu_iso14443_4a, + .build_scene_saved_menu = + (NfcProtocolSupportSceneBuilder)nfc_protocol_support_build_scene_saved_menu_iso14443_4a, + + .handle_scene_info = + (NfcProtocolSupportSceneHandler)nfc_protocol_support_handle_scene_info_iso14443_4a, + .handle_scene_read_menu = + (NfcProtocolSupportSceneHandler)nfc_protocol_support_handle_scene_read_menu_iso14443_4a, + .handle_scene_saved_menu = + (NfcProtocolSupportSceneHandler)nfc_protocol_support_handle_scene_saved_menu_iso14443_4a, +}; diff --git a/applications/main/nfc/helpers/protocol_support/iso14443_4a/iso14443_4a.h b/applications/main/nfc/helpers/protocol_support/iso14443_4a/iso14443_4a.h new file mode 100644 index 000000000000..1b173d7b091c --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/iso14443_4a/iso14443_4a.h @@ -0,0 +1,5 @@ +#pragma once + +#include "../nfc_protocol_support_base.h" + +extern const NfcProtocolSupportBase nfc_protocol_support_iso14443_4a; diff --git a/applications/main/nfc/helpers/protocol_support/iso14443_4a/iso14443_4a_render.c b/applications/main/nfc/helpers/protocol_support/iso14443_4a/iso14443_4a_render.c new file mode 100644 index 000000000000..7d426c4b20b1 --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/iso14443_4a/iso14443_4a_render.c @@ -0,0 +1,11 @@ +#include "iso14443_4a_render.h" + +#include "../iso14443_3a/iso14443_3a_render.h" + +void nfc_render_iso14443_4a_info( + const Iso14443_4aData* data, + NfcProtocolFormatType format_type, + FuriString* str) { + nfc_render_iso14443_3a_info(data->iso14443_3a_data, format_type, str); + // TODO: Add RATS info? +} diff --git a/applications/main/nfc/helpers/protocol_support/iso14443_4a/iso14443_4a_render.h b/applications/main/nfc/helpers/protocol_support/iso14443_4a/iso14443_4a_render.h new file mode 100644 index 000000000000..c736707e00f5 --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/iso14443_4a/iso14443_4a_render.h @@ -0,0 +1,10 @@ +#pragma once + +#include + +#include "../nfc_protocol_support_render_common.h" + +void nfc_render_iso14443_4a_info( + const Iso14443_4aData* data, + NfcProtocolFormatType format_type, + FuriString* str); diff --git a/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c b/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c new file mode 100644 index 000000000000..316af9029283 --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c @@ -0,0 +1,135 @@ +#include "mf_classic.h" +#include "mf_classic_render.h" + +#include + +#include "../nfc_protocol_support_gui_common.h" +#include "../../../nfc_app_i.h" + +enum { + SubmenuIndexDetectReader = SubmenuIndexCommonMax, + SubmenuIndexWrite, + SubmenuIndexUpdate, +}; + +static void nfc_protocol_support_render_info_mf_classic( + const MfClassicData* data, + NfcProtocolFormatType type, + FuriString* str) { + nfc_render_mf_classic_info(data, type, str); +} + +static NfcCustomEvent + nfc_protocol_support_handle_poller_mf_classic(MfClassicPollerEvent* event, void* context) { + UNUSED(event); + UNUSED(context); + + NfcCustomEvent custom_event = NfcCustomEventReadHandlerIgnore; + // TODO: Implement read mf_classic using key cache + return custom_event; +} + +static void nfc_protocol_support_build_scene_read_menu_mf_classic(NfcApp* instance) { + Submenu* submenu = instance->submenu; + const MfClassicData* data = nfc_device_get_data(instance->nfc_device, NfcProtocolMfClassic); + + if(!mf_classic_is_card_read(data)) { + submenu_add_item( + submenu, + "Detect Reader", + SubmenuIndexDetectReader, + nfc_protocol_support_common_submenu_callback, + instance); + } +} + +static void nfc_protocol_support_build_scene_saved_menu_mf_classic(NfcApp* instance) { + Submenu* submenu = instance->submenu; + const MfClassicData* data = nfc_device_get_data(instance->nfc_device, NfcProtocolMfClassic); + + if(!mf_classic_is_card_read(data)) { + submenu_add_item( + submenu, + "Detect Reader", + SubmenuIndexDetectReader, + nfc_protocol_support_common_submenu_callback, + instance); + } + submenu_add_item( + submenu, + "Write to Initial Card", + SubmenuIndexWrite, + nfc_protocol_support_common_submenu_callback, + instance); + submenu_add_item( + submenu, + "Update from Initial Card", + SubmenuIndexUpdate, + nfc_protocol_support_common_submenu_callback, + instance); +} + +static bool nfc_protocol_support_handle_scene_info_mf_classic(NfcApp* instance, uint32_t event) { + if(event == GuiButtonTypeRight) { + scene_manager_next_scene(instance->scene_manager, NfcSceneNotImplemented); + return true; + } + + return false; +} + +static bool + nfc_protocol_support_handle_scene_read_menu_mf_classic(NfcApp* instance, uint32_t event) { + switch(event) { + case SubmenuIndexCommonEmulate: + scene_manager_next_scene(instance->scene_manager, NfcSceneNotImplemented); + return true; + case SubmenuIndexDetectReader: + scene_manager_next_scene(instance->scene_manager, NfcSceneNotImplemented); + dolphin_deed(DolphinDeedNfcDetectReader); + return true; + default: + return false; + } +} + +static bool + nfc_protocol_support_handle_scene_saved_menu_mf_classic(NfcApp* instance, uint32_t event) { + switch(event) { + case SubmenuIndexCommonEmulate: + scene_manager_next_scene(instance->scene_manager, NfcSceneNotImplemented); + return true; + case SubmenuIndexDetectReader: + scene_manager_next_scene(instance->scene_manager, NfcSceneNotImplemented); + return true; + case SubmenuIndexWrite: + scene_manager_next_scene(instance->scene_manager, NfcSceneNotImplemented); + return true; + case SubmenuIndexUpdate: + scene_manager_next_scene(instance->scene_manager, NfcSceneNotImplemented); + return true; + default: + return false; + } +} + +const NfcProtocolSupportBase nfc_protocol_support_mf_classic = { + .features = NfcProtocolFeatureMoreData | NfcProtocolFeatureEmulateFull, + + .render_info = (NfcProtocolSupportRenderData)nfc_protocol_support_render_info_mf_classic, + + .handle_poller = + (NfcProtocolSupportPollerHandler)nfc_protocol_support_handle_poller_mf_classic, + + .build_scene_read_menu = + (NfcProtocolSupportSceneBuilder)nfc_protocol_support_build_scene_read_menu_mf_classic, + .build_scene_saved_menu = + (NfcProtocolSupportSceneBuilder)nfc_protocol_support_build_scene_saved_menu_mf_classic, + + .handle_scene_info = + (NfcProtocolSupportSceneHandler)nfc_protocol_support_handle_scene_info_mf_classic, + .handle_scene_read_menu = + (NfcProtocolSupportSceneHandler)nfc_protocol_support_handle_scene_read_menu_mf_classic, + .handle_scene_saved_menu = + (NfcProtocolSupportSceneHandler)nfc_protocol_support_handle_scene_saved_menu_mf_classic, +}; diff --git a/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.h b/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.h new file mode 100644 index 000000000000..d0f09f5d78ea --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.h @@ -0,0 +1,5 @@ +#pragma once + +#include "../nfc_protocol_support_base.h" + +extern const NfcProtocolSupportBase nfc_protocol_support_mf_classic; diff --git a/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic_render.c b/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic_render.c new file mode 100644 index 000000000000..3559369373e2 --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic_render.c @@ -0,0 +1,21 @@ +#include "mf_classic_render.h" + +#include "../iso14443_3a/iso14443_3a_render.h" + +void nfc_render_mf_classic_info( + const MfClassicData* data, + NfcProtocolFormatType format_type, + FuriString* str) { + nfc_render_iso14443_3a_info(data->iso14443_3a_data, format_type, str); + + uint8_t sectors_total = mf_classic_get_total_sectors_num(data->type); + uint8_t keys_total = sectors_total * 2; + uint8_t keys_found = 0; + uint8_t sectors_read = 0; + mf_classic_get_read_sectors_and_keys(data, §ors_read, &keys_found); + + furi_string_cat_printf(str, "\nKeys Found: %u/%u", keys_found, keys_total); + furi_string_cat_printf(str, "\nSectors Read: %u/%u", sectors_read, sectors_total); + + // TODO: Something else? +} diff --git a/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic_render.h b/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic_render.h new file mode 100644 index 000000000000..07177bd59200 --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic_render.h @@ -0,0 +1,10 @@ +#pragma once + +#include + +#include "../nfc_protocol_support_render_common.h" + +void nfc_render_mf_classic_info( + const MfClassicData* data, + NfcProtocolFormatType format_type, + FuriString* str); diff --git a/applications/main/nfc/helpers/protocol_support/mf_desfire/mf_desfire.c b/applications/main/nfc/helpers/protocol_support/mf_desfire/mf_desfire.c new file mode 100644 index 000000000000..14de69e49208 --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/mf_desfire/mf_desfire.c @@ -0,0 +1,84 @@ +#include "mf_desfire.h" +#include "mf_desfire_render.h" + +#include + +#include "../nfc_protocol_support_gui_common.h" +#include "../../../nfc_app_i.h" + +static void nfc_protocol_support_render_info_mf_desfire( + const MfDesfireData* data, + NfcProtocolFormatType format_type, + FuriString* str) { + nfc_render_mf_desfire_info(data, format_type, str); +} + +static NfcCustomEvent + nfc_protocol_support_handle_poller_mf_desfire(MfDesfirePollerEvent* event, void* context) { + UNUSED(context); + NfcCustomEvent custom_event = NfcCustomEventReadHandlerIgnore; + + if(event->type == MfDesfirePollerEventTypeReadSuccess) { + custom_event = NfcCustomEventReadHandlerSuccess; + } + + return custom_event; +} + +static void nfc_protocol_support_build_scene_read_menu_mf_desfire(NfcApp* instance) { + UNUSED(instance); +} + +static void nfc_protocol_support_build_scene_saved_menu_mf_desfire(NfcApp* instance) { + UNUSED(instance); +} + +static bool nfc_protocol_support_handle_scene_info_mf_desfire(NfcApp* instance, uint32_t event) { + if(event == GuiButtonTypeRight) { + scene_manager_next_scene(instance->scene_manager, NfcSceneMfDesfireData); + return true; + } + + return false; +} + +static bool + nfc_protocol_support_handle_scene_read_menu_mf_desfire(NfcApp* instance, uint32_t event) { + if(event == SubmenuIndexCommonEmulate) { + scene_manager_next_scene(instance->scene_manager, NfcSceneNfcaEmulate); + return true; + } + + return false; +} + +static bool + nfc_protocol_support_handle_scene_saved_menu_mf_desfire(NfcApp* instance, uint32_t event) { + if(event == SubmenuIndexCommonEmulate) { + scene_manager_next_scene(instance->scene_manager, NfcSceneNfcaEmulate); + return true; + } + + return false; +} + +const NfcProtocolSupportBase nfc_protocol_support_mf_desfire = { + .features = NfcProtocolFeatureMoreData | NfcProtocolFeatureEmulateUid, + + .render_info = (NfcProtocolSupportRenderData)nfc_protocol_support_render_info_mf_desfire, + + .handle_poller = + (NfcProtocolSupportPollerHandler)nfc_protocol_support_handle_poller_mf_desfire, + + .build_scene_read_menu = + (NfcProtocolSupportSceneBuilder)nfc_protocol_support_build_scene_read_menu_mf_desfire, + .build_scene_saved_menu = + (NfcProtocolSupportSceneBuilder)nfc_protocol_support_build_scene_saved_menu_mf_desfire, + + .handle_scene_info = + (NfcProtocolSupportSceneHandler)nfc_protocol_support_handle_scene_info_mf_desfire, + .handle_scene_read_menu = + (NfcProtocolSupportSceneHandler)nfc_protocol_support_handle_scene_read_menu_mf_desfire, + .handle_scene_saved_menu = + (NfcProtocolSupportSceneHandler)nfc_protocol_support_handle_scene_saved_menu_mf_desfire, +}; diff --git a/applications/main/nfc/helpers/protocol_support/mf_desfire/mf_desfire.h b/applications/main/nfc/helpers/protocol_support/mf_desfire/mf_desfire.h new file mode 100644 index 000000000000..504860f16a45 --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/mf_desfire/mf_desfire.h @@ -0,0 +1,5 @@ +#pragma once + +#include "../nfc_protocol_support_base.h" + +extern const NfcProtocolSupportBase nfc_protocol_support_mf_desfire; diff --git a/applications/main/nfc/helpers/format/nfc_mf_desfire_format.c b/applications/main/nfc/helpers/protocol_support/mf_desfire/mf_desfire_render.c similarity index 75% rename from applications/main/nfc/helpers/format/nfc_mf_desfire_format.c rename to applications/main/nfc/helpers/protocol_support/mf_desfire/mf_desfire_render.c index da1c0607c2ed..1af01c56e920 100644 --- a/applications/main/nfc/helpers/format/nfc_mf_desfire_format.c +++ b/applications/main/nfc/helpers/protocol_support/mf_desfire/mf_desfire_render.c @@ -1,16 +1,47 @@ -#include "nfc_mf_desfire_format.h" +#include "mf_desfire_render.h" -void nfc_mf_desfire_format_data(const MfDesfireData* data, FuriString* str) { - nfc_mf_desfire_format_version(&data->version, str); - nfc_mf_desfire_format_free_memory(&data->free_memory, str); - nfc_mf_desfire_format_key_settings(&data->master_key_settings, str); +#include "../iso14443_3a/iso14443_3a_render.h" + +void nfc_render_mf_desfire_info( + const MfDesfireData* data, + NfcProtocolFormatType format_type, + FuriString* str) { + nfc_render_iso14443_3a_info(data->iso14443_4a_data->iso14443_3a_data, format_type, str); + + const uint32_t bytes_total = 1UL << (data->version.sw_storage >> 1); + const uint32_t bytes_free = data->free_memory.is_present ? data->free_memory.bytes_free : 0; + + furi_string_cat_printf(str, "\n%lu", bytes_total); + + if(data->version.sw_storage & 1) { + furi_string_push_back(str, '+'); + } + + furi_string_cat_printf(str, " bytes, %lu bytes free\n", bytes_free); + + const uint32_t app_count = simple_array_get_count(data->applications); + uint32_t file_count = 0; + + for(uint32_t i = 0; i < app_count; ++i) { + const MfDesfireApplication* app = simple_array_cget(data->applications, i); + file_count += simple_array_get_count(app->file_ids); + } + + furi_string_cat_printf(str, "%lu Application%s", app_count, app_count != 1 ? "s" : ""); + furi_string_cat_printf(str, ", %lu File%s", file_count, file_count != 1 ? "s" : ""); +} + +void nfc_render_mf_desfire_data(const MfDesfireData* data, FuriString* str) { + nfc_render_mf_desfire_version(&data->version, str); + nfc_render_mf_desfire_free_memory(&data->free_memory, str); + nfc_render_mf_desfire_key_settings(&data->master_key_settings, str); for(uint32_t i = 0; i < simple_array_get_count(data->master_key_versions); ++i) { - nfc_mf_desfire_format_key_version(simple_array_cget(data->master_key_versions, i), i, str); + nfc_render_mf_desfire_key_version(simple_array_cget(data->master_key_versions, i), i, str); } } -void nfc_mf_desfire_format_version(const MfDesfireVersion* data, FuriString* str) { +void nfc_render_mf_desfire_version(const MfDesfireVersion* data, FuriString* str) { furi_string_cat_printf( str, "%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", @@ -58,13 +89,13 @@ void nfc_mf_desfire_format_version(const MfDesfireVersion* data, FuriString* str data->prod_year); } -void nfc_mf_desfire_format_free_memory(const MfDesfireFreeMemory* data, FuriString* str) { +void nfc_render_mf_desfire_free_memory(const MfDesfireFreeMemory* data, FuriString* str) { if(data->is_present) { furi_string_cat_printf(str, "freeMem %lu\n", data->bytes_free); } } -void nfc_mf_desfire_format_key_settings(const MfDesfireKeySettings* data, FuriString* str) { +void nfc_render_mf_desfire_key_settings(const MfDesfireKeySettings* data, FuriString* str) { furi_string_cat_printf(str, "changeKeyID %d\n", data->change_key_id); furi_string_cat_printf(str, "configChangeable %d\n", data->is_config_changeable); furi_string_cat_printf(str, "freeCreateDelete %d\n", data->is_free_create_delete); @@ -78,31 +109,31 @@ void nfc_mf_desfire_format_key_settings(const MfDesfireKeySettings* data, FuriSt furi_string_cat_printf(str, "maxKeys %d\n", data->max_keys); } -void nfc_mf_desfire_format_key_version( +void nfc_render_mf_desfire_key_version( const MfDesfireKeyVersion* data, uint32_t index, FuriString* str) { furi_string_cat_printf(str, "key %lu version %u\n", index, *data); } -void nfc_mf_desfire_format_application_id(const MfDesfireApplicationId* data, FuriString* str) { +void nfc_render_mf_desfire_application_id(const MfDesfireApplicationId* data, FuriString* str) { const uint8_t* app_id = data->data; furi_string_cat_printf(str, "Application %02x%02x%02x\n", app_id[0], app_id[1], app_id[2]); } -void nfc_mf_desfire_format_application(const MfDesfireApplication* data, FuriString* str) { - nfc_mf_desfire_format_key_settings(&data->key_settings, str); +void nfc_render_mf_desfire_application(const MfDesfireApplication* data, FuriString* str) { + nfc_render_mf_desfire_key_settings(&data->key_settings, str); for(uint32_t i = 0; i < simple_array_get_count(data->key_versions); ++i) { - nfc_mf_desfire_format_key_version(simple_array_cget(data->key_versions, i), i, str); + nfc_render_mf_desfire_key_version(simple_array_cget(data->key_versions, i), i, str); } } -void nfc_mf_desfire_format_file_id(const MfDesfireFileId* data, FuriString* str) { +void nfc_render_mf_desfire_file_id(const MfDesfireFileId* data, FuriString* str) { furi_string_cat_printf(str, "File %d\n", *data); } -void nfc_mf_desfire_format_file_settings_data( +void nfc_render_mf_desfire_file_settings_data( const MfDesfireFileSettings* settings, const MfDesfireFileData* data, FuriString* str) { diff --git a/applications/main/nfc/helpers/protocol_support/mf_desfire/mf_desfire_render.h b/applications/main/nfc/helpers/protocol_support/mf_desfire/mf_desfire_render.h new file mode 100644 index 000000000000..ff5e815bff05 --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/mf_desfire/mf_desfire_render.h @@ -0,0 +1,34 @@ +#pragma once + +#include + +#include "../nfc_protocol_support_render_common.h" + +void nfc_render_mf_desfire_info( + const MfDesfireData* data, + NfcProtocolFormatType format_type, + FuriString* str); + +void nfc_render_mf_desfire_data(const MfDesfireData* data, FuriString* str); + +void nfc_render_mf_desfire_version(const MfDesfireVersion* data, FuriString* str); + +void nfc_render_mf_desfire_free_memory(const MfDesfireFreeMemory* data, FuriString* str); + +void nfc_render_mf_desfire_key_settings(const MfDesfireKeySettings* data, FuriString* str); + +void nfc_render_mf_desfire_key_version( + const MfDesfireKeyVersion* data, + uint32_t index, + FuriString* str); + +void nfc_render_mf_desfire_application_id(const MfDesfireApplicationId* data, FuriString* str); + +void nfc_render_mf_desfire_application(const MfDesfireApplication* data, FuriString* str); + +void nfc_render_mf_desfire_file_id(const MfDesfireFileId* data, FuriString* str); + +void nfc_render_mf_desfire_file_settings_data( + const MfDesfireFileSettings* settings, + const MfDesfireFileData* data, + FuriString* str); diff --git a/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c b/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c new file mode 100644 index 000000000000..44e53e4cd94d --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c @@ -0,0 +1,161 @@ +#include "mf_ultralight.h" +#include "mf_ultralight_render.h" + +#include + +#include "../nfc_protocol_support_gui_common.h" +#include "../../../nfc_app_i.h" + +enum { + SubmenuIndexUnlock = SubmenuIndexCommonMax, + SubmenuIndexUnlockByReader, + SubmenuIndexUnlockByPassword, +}; + +static void nfc_protocol_support_render_info_mf_ultralight( + const MfUltralightData* data, + NfcProtocolFormatType format_type, + FuriString* str) { + nfc_render_mf_ultralight_info(data, format_type, str); +} + +static NfcCustomEvent nfc_protocol_support_handle_poller_mf_ultralight( + MfUltralightPollerEvent* event, + NfcApp* nfc_app) { + NfcCustomEvent custom_event = NfcCustomEventReadHandlerIgnore; + + if(event->type == MfUltralightPollerEventTypeReadSuccess) { + custom_event = NfcCustomEventReadHandlerSuccess; + } else if(event->type == MfUltralightPollerEventTypeAuthRequest) { + nfc_device_set_data( + nfc_app->nfc_device, NfcProtocolMfUltralight, nfc_poller_get_data(nfc_app->poller)); + const MfUltralightData* data = + nfc_device_get_data(nfc_app->nfc_device, NfcProtocolMfUltralight); + if(nfc_app->mf_ul_auth->type == MfUltralightAuthTypeXiaomii) { + if(mf_ultralight_generate_xiaomi_pass( + nfc_app->mf_ul_auth, + data->iso14443_3a_data->uid, + data->iso14443_3a_data->uid_len)) { + event->data->auth_context.skip_auth = false; + } + } else if(nfc_app->mf_ul_auth->type == MfUltralightAuthTypeAmiibo) { + if(mf_ultralight_generate_amiibo_pass( + nfc_app->mf_ul_auth, + data->iso14443_3a_data->uid, + data->iso14443_3a_data->uid_len)) { + event->data->auth_context.skip_auth = false; + } + } else if(nfc_app->mf_ul_auth->type == MfUltralightAuthTypeManual) { + event->data->auth_context.skip_auth = false; + } else { + event->data->auth_context.skip_auth = true; + } + if(!event->data->auth_context.skip_auth) { + event->data->auth_context.password = nfc_app->mf_ul_auth->password; + } + } else if(event->type == MfUltralightPollerEventTypeAuthSuccess) { + nfc_app->mf_ul_auth->pack = event->data->auth_context.pack; + } + + return custom_event; +} + +static void nfc_protocol_support_build_scene_read_menu_mf_ultralight(NfcApp* instance) { + Submenu* submenu = instance->submenu; + + const MfUltralightData* data = + nfc_device_get_data(instance->nfc_device, NfcProtocolMfUltralight); + + if(!mf_ultralight_is_all_data_read(data)) { + submenu_add_item( + submenu, + "Unlock", + SubmenuIndexUnlock, + nfc_protocol_support_common_submenu_callback, + instance); + } +} + +static void nfc_protocol_support_build_scene_saved_menu_mf_ultralight(NfcApp* instance) { + Submenu* submenu = instance->submenu; + const MfUltralightData* data = + nfc_device_get_data(instance->nfc_device, NfcProtocolMfUltralight); + + if(!mf_ultralight_is_all_data_read(data)) { + submenu_add_item( + submenu, + "Unlock with Reader", + SubmenuIndexUnlockByReader, + nfc_protocol_support_common_submenu_callback, + instance); + + submenu_add_item( + submenu, + "Unlock with Password", + SubmenuIndexUnlockByPassword, + nfc_protocol_support_common_submenu_callback, + instance); + } +} + +static bool + nfc_protocol_support_handle_scene_info_mf_ultralight(NfcApp* instance, uint32_t event) { + if(event == GuiButtonTypeRight) { + scene_manager_next_scene(instance->scene_manager, NfcSceneNotImplemented); + return true; + } + + return false; +} + +static bool + nfc_protocol_support_handle_scene_read_menu_mf_ultralight(NfcApp* instance, uint32_t event) { + switch(event) { + case SubmenuIndexCommonEmulate: + scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightEmulate); + return true; + case SubmenuIndexUnlock: + scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightUnlockMenu); + return true; + default: + return false; + } +} + +static bool + nfc_protocol_support_handle_scene_saved_menu_mf_ultralight(NfcApp* instance, uint32_t event) { + switch(event) { + case SubmenuIndexCommonEmulate: + scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightEmulate); + return true; + case SubmenuIndexUnlockByReader: + scene_manager_next_scene(instance->scene_manager, NfcSceneNotImplemented); + return true; + case SubmenuIndexUnlockByPassword: + scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightUnlockMenu); + return true; + default: + return false; + } +} + +const NfcProtocolSupportBase nfc_protocol_support_mf_ultralight = { + .features = NfcProtocolFeatureMoreData | NfcProtocolFeatureEmulateFull, + + .render_info = (NfcProtocolSupportRenderData)nfc_protocol_support_render_info_mf_ultralight, + + .handle_poller = + (NfcProtocolSupportPollerHandler)nfc_protocol_support_handle_poller_mf_ultralight, + + .build_scene_read_menu = + (NfcProtocolSupportSceneBuilder)nfc_protocol_support_build_scene_read_menu_mf_ultralight, + .build_scene_saved_menu = + (NfcProtocolSupportSceneBuilder)nfc_protocol_support_build_scene_saved_menu_mf_ultralight, + + .handle_scene_info = + (NfcProtocolSupportSceneHandler)nfc_protocol_support_handle_scene_info_mf_ultralight, + .handle_scene_read_menu = + (NfcProtocolSupportSceneHandler)nfc_protocol_support_handle_scene_read_menu_mf_ultralight, + .handle_scene_saved_menu = + (NfcProtocolSupportSceneHandler)nfc_protocol_support_handle_scene_saved_menu_mf_ultralight, +}; diff --git a/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.h b/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.h new file mode 100644 index 000000000000..83e58732e41d --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.h @@ -0,0 +1,5 @@ +#pragma once + +#include "../nfc_protocol_support_base.h" + +extern const NfcProtocolSupportBase nfc_protocol_support_mf_ultralight; diff --git a/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight_render.c b/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight_render.c new file mode 100644 index 000000000000..d0f087fd23bf --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight_render.c @@ -0,0 +1,17 @@ +#include "mf_ultralight_render.h" + +#include "../iso14443_3a/iso14443_3a_render.h" + +void nfc_render_mf_ultralight_info( + const MfUltralightData* data, + NfcProtocolFormatType format_type, + FuriString* str) { + nfc_render_iso14443_3a_info(data->iso14443_3a_data, format_type, str); + + furi_string_cat_printf(str, "\nPages Read: %u/%u", data->pages_read, data->pages_total); + if(data->pages_read != data->pages_total) { + furi_string_cat_printf(str, "\nPassword-protected pages!"); + } + + //TODO: Something else? +} diff --git a/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight_render.h b/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight_render.h new file mode 100644 index 000000000000..e3c0a69d6fa5 --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight_render.h @@ -0,0 +1,10 @@ +#pragma once + +#include + +#include "../nfc_protocol_support_render_common.h" + +void nfc_render_mf_ultralight_info( + const MfUltralightData* data, + NfcProtocolFormatType format_type, + FuriString* str); diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c new file mode 100644 index 000000000000..2ee7993ffaa2 --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c @@ -0,0 +1,241 @@ +#include "nfc_protocol_support.h" + +#include "nfc_protocol_support_defs.h" +#include "nfc_protocol_support_gui_common.h" + +#include "../../nfc_app_i.h" + +static bool nfc_protocol_support_has_feature(NfcProtocol protocol, NfcProtocolFeature feature) { + return nfc_protocol_support[protocol]->features & feature; +} + +static void nfc_protocol_support_render_info( + const NfcDevice* device, + NfcProtocolFormatType format_type, + FuriString* str) { + const NfcProtocol protocol = nfc_device_get_protocol(device); + const NfcDeviceData* data = nfc_device_get_data(device, protocol); + furi_string_cat_printf(str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull)); + nfc_protocol_support[protocol]->render_info(data, format_type, str); +} + +NfcCustomEvent nfc_protocol_support_handle_poller(NfcGenericEvent event, void* context) { + furi_assert(context); + NfcApp* nfc_app = context; + + NfcCustomEvent custom_event = + nfc_protocol_support[event.protocol]->handle_poller(event.data, context); + if(custom_event == NfcCustomEventReadHandlerSuccess) { + nfc_device_set_data( + nfc_app->nfc_device, event.protocol, nfc_poller_get_data(nfc_app->poller)); + } + + return custom_event; +} + +// Scene builders + +void nfc_protocol_support_build_scene_info(NfcApp* instance) { + const NfcProtocol protocol = nfc_device_get_protocol(instance->nfc_device); + Widget* widget = instance->widget; + + FuriString* temp_str = furi_string_alloc(); + nfc_protocol_support_render_info(instance->nfc_device, NfcProtocolFormatTypeFull, temp_str); + + uint8_t text_scroll_height; + + if(nfc_protocol_support_has_feature(protocol, NfcProtocolFeatureMoreData)) { + widget_add_button_element( + widget, + GuiButtonTypeRight, + "More", + nfc_protocol_support_common_widget_callback, + instance); + text_scroll_height = 52; + } else { + text_scroll_height = 64; + } + + widget_add_text_scroll_element( + widget, 0, 0, 128, text_scroll_height, furi_string_get_cstr(temp_str)); + furi_string_free(temp_str); +} + +void nfc_protocol_support_build_scene_read_menu(NfcApp* instance) { + const NfcProtocol protocol = nfc_device_get_protocol(instance->nfc_device); + + Submenu* submenu = instance->submenu; + + submenu_add_item( + submenu, + "Save", + SubmenuIndexCommonSave, + nfc_protocol_support_common_submenu_callback, + instance); + + if(nfc_protocol_support_has_feature(protocol, NfcProtocolFeatureEmulateUid)) { + submenu_add_item( + submenu, + "Emulate UID", + SubmenuIndexCommonEmulate, + nfc_protocol_support_common_submenu_callback, + instance); + } + + if(nfc_protocol_support_has_feature(protocol, NfcProtocolFeatureEmulateFull)) { + submenu_add_item( + submenu, + "Emulate", + SubmenuIndexCommonEmulate, + nfc_protocol_support_common_submenu_callback, + instance); + } + + nfc_protocol_support[protocol]->build_scene_read_menu(instance); + + submenu_add_item( + submenu, + "Info", + SubmenuIndexCommonInfo, + nfc_protocol_support_common_submenu_callback, + instance); +} + +void nfc_protocol_support_build_scene_read_success(NfcApp* instance) { + Widget* widget = instance->widget; + + FuriString* temp_str = furi_string_alloc(); + nfc_protocol_support_render_info(instance->nfc_device, NfcProtocolFormatTypeShort, temp_str); + + widget_add_text_scroll_element(widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); + furi_string_free(temp_str); + + widget_add_button_element( + widget, GuiButtonTypeLeft, "Retry", nfc_protocol_support_common_widget_callback, instance); + widget_add_button_element( + widget, GuiButtonTypeRight, "More", nfc_protocol_support_common_widget_callback, instance); +} + +void nfc_protocol_support_build_scene_saved_menu(NfcApp* instance) { + const NfcProtocol protocol = nfc_device_get_protocol(instance->nfc_device); + + Submenu* submenu = instance->submenu; + + // Header submenu items + if(nfc_protocol_support_has_feature(protocol, NfcProtocolFeatureEmulateUid)) { + submenu_add_item( + submenu, + "Emulate UID", + SubmenuIndexCommonEmulate, + nfc_protocol_support_common_submenu_callback, + instance); + } + + if(nfc_protocol_support_has_feature(protocol, NfcProtocolFeatureEmulateFull)) { + submenu_add_item( + submenu, + "Emulate", + SubmenuIndexCommonEmulate, + nfc_protocol_support_common_submenu_callback, + instance); + } + + if(nfc_protocol_support_has_feature(protocol, NfcProtocolFeatureEditUid)) { + submenu_add_item( + submenu, + "Edit UID", + SubmenuIndexCommonEdit, + nfc_protocol_support_common_submenu_callback, + instance); + } + + // Protocol-dependent menu items + nfc_protocol_support[protocol]->build_scene_saved_menu(instance); + + // Trailer submenu items + submenu_add_item( + submenu, + "Info", + SubmenuIndexCommonInfo, + nfc_protocol_support_common_submenu_callback, + instance); + submenu_add_item( + submenu, + "Rename", + SubmenuIndexCommonRename, + nfc_protocol_support_common_submenu_callback, + instance); + submenu_add_item( + submenu, + "Delete", + SubmenuIndexCommonDelete, + nfc_protocol_support_common_submenu_callback, + instance); + + // TODO: Implement restore from shadow file +} + +// Scene handlers + +bool nfc_protocol_support_handle_scene_info(NfcApp* instance, uint32_t event) { + const NfcProtocol protocol = nfc_device_get_protocol(instance->nfc_device); + return nfc_protocol_support[protocol]->handle_scene_info(instance, event); +} + +bool nfc_protocol_support_handle_scene_read_menu(NfcApp* instance, uint32_t event) { + const NfcProtocol protocol = nfc_device_get_protocol(instance->nfc_device); + + switch(event) { + case SubmenuIndexCommonSave: + scene_manager_next_scene(instance->scene_manager, NfcSceneNotImplemented); + return true; + case SubmenuIndexCommonInfo: + scene_manager_next_scene(instance->scene_manager, NfcSceneInfo); + return true; + case SubmenuIndexCommonEmulate: + dolphin_deed(DolphinDeedNfcEmulate); + // FALLTHRU + default: + return nfc_protocol_support[protocol]->handle_scene_read_menu(instance, event); + } +} + +bool nfc_protocol_support_handle_scene_read_success(NfcApp* instance, uint32_t event) { + switch(event) { + case GuiButtonTypeLeft: + scene_manager_next_scene(instance->scene_manager, NfcSceneRetryConfirm); + return true; + case GuiButtonTypeRight: + scene_manager_next_scene(instance->scene_manager, NfcSceneReadMenu); + return true; + default: + return false; + } +} + +bool nfc_protocol_support_handle_scene_saved_menu(NfcApp* instance, uint32_t event) { + const NfcProtocol protocol = nfc_device_get_protocol(instance->nfc_device); + + // TODO: Implement restore from shadow file + + switch(event) { + case SubmenuIndexCommonInfo: + scene_manager_next_scene(instance->scene_manager, NfcSceneInfo); + return true; + case SubmenuIndexCommonRename: + scene_manager_next_scene(instance->scene_manager, NfcSceneSaveName); + return true; + case SubmenuIndexCommonDelete: + scene_manager_next_scene(instance->scene_manager, NfcSceneDelete); + return true; + case SubmenuIndexCommonEmulate: + if(scene_manager_has_previous_scene(instance->scene_manager, NfcSceneSetType)) { + dolphin_deed(DolphinDeedNfcAddEmulate); + } else { + dolphin_deed(DolphinDeedNfcEmulate); + } + // FALLTHRU + default: + return nfc_protocol_support[protocol]->handle_scene_saved_menu(instance, event); + } +} diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.h b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.h new file mode 100644 index 000000000000..75b379426564 --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.h @@ -0,0 +1,27 @@ +#pragma once + +#include "nfc_protocol_support_common.h" + +// Poller handler +NfcCustomEvent nfc_protocol_support_handle_poller(NfcGenericEvent event, void* context); + +// Listener handler +// TODO + +// Scene builders +void nfc_protocol_support_build_scene_info(NfcApp* instance); + +void nfc_protocol_support_build_scene_read_menu(NfcApp* instance); + +void nfc_protocol_support_build_scene_read_success(NfcApp* instance); + +void nfc_protocol_support_build_scene_saved_menu(NfcApp* instance); + +// Scene handlers +bool nfc_protocol_support_handle_scene_info(NfcApp* instance, uint32_t event); + +bool nfc_protocol_support_handle_scene_read_menu(NfcApp* instance, uint32_t event); + +bool nfc_protocol_support_handle_scene_read_success(NfcApp* instance, uint32_t event); + +bool nfc_protocol_support_handle_scene_saved_menu(NfcApp* instance, uint32_t event); diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_base.h b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_base.h new file mode 100644 index 000000000000..2123778cd652 --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_base.h @@ -0,0 +1,32 @@ +#pragma once + +#include + +#include "nfc_protocol_support_common.h" + +typedef void (*NfcProtocolSupportRenderData)( + const NfcDeviceData* data, + NfcProtocolFormatType format_type, + FuriString* str); + +typedef NfcCustomEvent ( + *NfcProtocolSupportPollerHandler)(NfcGenericEventData* event_data, void* context); + +typedef void (*NfcProtocolSupportSceneBuilder)(NfcApp* instance); + +typedef bool (*NfcProtocolSupportSceneHandler)(NfcApp* instance, uint32_t event); + +typedef struct { + const uint32_t features; + + NfcProtocolSupportRenderData render_info; + + NfcProtocolSupportPollerHandler handle_poller; + + NfcProtocolSupportSceneBuilder build_scene_read_menu; + NfcProtocolSupportSceneBuilder build_scene_saved_menu; + + NfcProtocolSupportSceneHandler handle_scene_info; + NfcProtocolSupportSceneHandler handle_scene_read_menu; + NfcProtocolSupportSceneHandler handle_scene_saved_menu; +} NfcProtocolSupportBase; diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_common.h b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_common.h new file mode 100644 index 000000000000..8b9c43abbdd3 --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_common.h @@ -0,0 +1,18 @@ +#pragma once + +#include +#include + +#include "nfc_protocol_support_render_common.h" + +#include "../nfc_custom_event.h" +#include "../../scenes/nfc_scene.h" +#include "../../nfc_app.h" + +typedef enum { + NfcProtocolFeatureNone = 0, + NfcProtocolFeatureMoreData = 1UL << 0, + NfcProtocolFeatureEmulateUid = 1UL << 1, + NfcProtocolFeatureEmulateFull = 1UL << 2, + NfcProtocolFeatureEditUid = 1UL << 3, +} NfcProtocolFeature; diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_defs.c b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_defs.c new file mode 100644 index 000000000000..92a4cd561f65 --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_defs.c @@ -0,0 +1,16 @@ +#include "nfc_protocol_support_defs.h" + +#include "iso14443_3a/iso14443_3a.h" +#include "iso14443_4a/iso14443_4a.h" +#include "mf_ultralight/mf_ultralight.h" +#include "mf_classic/mf_classic.h" +#include "mf_desfire/mf_desfire.h" + +const NfcProtocolSupportBase* nfc_protocol_support[NfcProtocolNum] = { + [NfcProtocolIso14443_3a] = &nfc_protocol_support_iso14443_3a, + [NfcProtocolIso14443_4a] = &nfc_protocol_support_iso14443_4a, + [NfcProtocolMfUltralight] = &nfc_protocol_support_mf_ultralight, + [NfcProtocolMfClassic] = &nfc_protocol_support_mf_classic, + [NfcProtocolMfDesfire] = &nfc_protocol_support_mf_desfire, + /* Add new protocols here */ +}; diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_defs.h b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_defs.h new file mode 100644 index 000000000000..8a15a56ec57a --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_defs.h @@ -0,0 +1,5 @@ +#pragma once + +#include "nfc_protocol_support_base.h" + +extern const NfcProtocolSupportBase* nfc_protocol_support[]; diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_gui_common.c b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_gui_common.c new file mode 100644 index 000000000000..22f8895e71d5 --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_gui_common.c @@ -0,0 +1,20 @@ +#include "nfc_protocol_support_gui_common.h" + +#include "../../nfc_app_i.h" + +void nfc_protocol_support_common_submenu_callback(void* context, uint32_t index) { + furi_assert(context); + NfcApp* nfc = context; + view_dispatcher_send_custom_event(nfc->view_dispatcher, index); +} + +void nfc_protocol_support_common_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + furi_assert(context); + NfcApp* nfc = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); + } +} diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_gui_common.h b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_gui_common.h new file mode 100644 index 000000000000..4f8e12ed79ef --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_gui_common.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +enum { + SubmenuIndexCommonEmulate, + SubmenuIndexCommonEdit, + SubmenuIndexCommonInfo, + SubmenuIndexCommonSave, + SubmenuIndexCommonRename, + SubmenuIndexCommonDelete, + SubmenuIndexCommonMax, +}; + +void nfc_protocol_support_common_submenu_callback(void* context, uint32_t index); + +void nfc_protocol_support_common_widget_callback( + GuiButtonType result, + InputType type, + void* context); diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_render_common.h b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_render_common.h new file mode 100644 index 000000000000..102934668191 --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_render_common.h @@ -0,0 +1,6 @@ +#pragma once + +typedef enum { + NfcProtocolFormatTypeShort, + NfcProtocolFormatTypeFull, +} NfcProtocolFormatType; diff --git a/applications/main/nfc/nfc_app.c b/applications/main/nfc/nfc_app.c index ad5e5f82390b..d911a98e0378 100644 --- a/applications/main/nfc/nfc_app.c +++ b/applications/main/nfc/nfc_app.c @@ -334,13 +334,13 @@ static bool nfc_save_internal(NfcApp* instance, const char* extension) { bool nfc_save_shadow_file(NfcApp* instance) { furi_assert(instance); - return nfc_save_internal(instance, NFC_APP_EXTENSION); + return nfc_save_internal(instance, NFC_APP_SHADOW_EXTENSION); } bool nfc_save(NfcApp* instance) { furi_assert(instance); - return nfc_save_internal(instance, NFC_APP_SHADOW_EXTENSION); + return nfc_save_internal(instance, NFC_APP_EXTENSION); } bool nfc_load_file(NfcApp* instance, FuriString* path, bool show_dialog) { diff --git a/applications/main/nfc/nfc_app_i.h b/applications/main/nfc/nfc_app_i.h index beada3ff78b5..8731edcdcc5e 100644 --- a/applications/main/nfc/nfc_app_i.h +++ b/applications/main/nfc/nfc_app_i.h @@ -39,12 +39,9 @@ #include #include -#include +#include #include -#include -#include #include -#include #include #include diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index 3fc95f962c6b..df83c43d75f0 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -12,27 +12,24 @@ ADD_SCENE(nfc, info, Info) ADD_SCENE(nfc, select_protocol, SelectProtocol) ADD_SCENE(nfc, extra_actions, ExtraActions) ADD_SCENE(nfc, read_success, ReadSuccess) +ADD_SCENE(nfc, read_menu, ReadMenu) ADD_SCENE(nfc, debug, Debug) ADD_SCENE(nfc, retry_confirm, RetryConfirm) ADD_SCENE(nfc, exit_confirm, ExitConfirm) ADD_SCENE(nfc, nfca_emulate, NfcaEmulate) -ADD_SCENE(nfc, nfca_menu, NfcaMenu) ADD_SCENE(nfc, mf_ultralight_emulate, MfUltralightEmulate) -ADD_SCENE(nfc, mf_ultralight_menu, MfUltralightMenu) ADD_SCENE(nfc, mf_ultralight_unlock_menu, MfUltralightUnlockMenu) ADD_SCENE(nfc, mf_ultralight_unlock_warn, MfUltralightUnlockWarn) ADD_SCENE(nfc, mf_ultralight_key_input, MfUltralightKeyInput) ADD_SCENE(nfc, mf_ultralight_capture_pass, MfUltralightCapturePass) -ADD_SCENE(nfc, mf_desfire_menu, MfDesfireMenu) ADD_SCENE(nfc, mf_desfire_data, MfDesfireData) ADD_SCENE(nfc, mf_desfire_app, MfDesfireApp) ADD_SCENE(nfc, mf_classic_read_supported_card, MfClassicReadSupportedCard) ADD_SCENE(nfc, mf_classic_dict_attack, MfClassicDictAttack) -ADD_SCENE(nfc, mf_classic_menu, MfClassicMenu) ADD_SCENE(nfc, set_type, SetType) ADD_SCENE(nfc, set_sak, SetSak) diff --git a/applications/main/nfc/scenes/nfc_scene_generate_info.c b/applications/main/nfc/scenes/nfc_scene_generate_info.c index f8bb835a5b6d..20cd9c4aac9a 100644 --- a/applications/main/nfc/scenes/nfc_scene_generate_info.c +++ b/applications/main/nfc/scenes/nfc_scene_generate_info.c @@ -55,7 +55,7 @@ bool nfc_scene_generate_info_on_event(void* context, SceneManagerEvent event) { if(event.event == GuiButtonTypeRight) { // Switch either to NfcSceneMfClassicMenu or NfcSceneMfUltralightMenu if(nfc_device_get_protocol(nfc->nfc_device) == NfcProtocolMfUltralight) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightMenu); + // scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightMenu); } else { // TODO add classic } diff --git a/applications/main/nfc/scenes/nfc_scene_info.c b/applications/main/nfc/scenes/nfc_scene_info.c index 0f4a5482cd04..74528833e3b3 100644 --- a/applications/main/nfc/scenes/nfc_scene_info.c +++ b/applications/main/nfc/scenes/nfc_scene_info.c @@ -1,59 +1,20 @@ #include "../nfc_app_i.h" -#include "../helpers/format/nfc_protocol_format.h" - -static void - nfc_scene_nfc_info_widget_callback(GuiButtonType result, InputType type, void* context) { - NfcApp* nfc = context; - if(type == InputTypeShort) { - view_dispatcher_send_custom_event(nfc->view_dispatcher, result); - } -} +#include "../helpers/protocol_support/nfc_protocol_support.h" void nfc_scene_info_on_enter(void* context) { NfcApp* nfc = context; - Widget* widget = nfc->widget; - - uint8_t text_scroll_height = 0; - if(nfc_protocol_format_get_features(nfc->nfc_device) & NfcProtocolFormatFeatureMoreData) { - widget_add_button_element( - widget, GuiButtonTypeRight, "More", nfc_scene_nfc_info_widget_callback, nfc); - text_scroll_height = 52; - } else { - text_scroll_height = 64; - } - - FuriString* temp_str; - temp_str = furi_string_alloc(); - - nfc_protocol_format_info(nfc->nfc_device, NfcProtocolFormatTypeFull, temp_str); - - widget_add_text_scroll_element( - widget, 0, 0, 128, text_scroll_height, furi_string_get_cstr(temp_str)); - furi_string_free(temp_str); + nfc_protocol_support_build_scene_info(nfc); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); } -static const NfcScene nfc_scene_info_data_scenes[NfcProtocolNum] = { - [NfcProtocolIso14443_3a] = NfcSceneNotImplemented, - [NfcProtocolIso14443_4a] = NfcSceneNotImplemented, - [NfcProtocolMfUltralight] = NfcSceneNotImplemented, - [NfcProtocolMfClassic] = NfcSceneNotImplemented, - [NfcProtocolMfDesfire] = NfcSceneMfDesfireData, -}; - bool nfc_scene_info_on_event(void* context, SceneManagerEvent event) { NfcApp* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { - if(event.event == GuiButtonTypeRight) { - const NfcProtocol protocol = nfc_device_get_protocol(nfc->nfc_device); - const NfcScene menu_scene = nfc_scene_info_data_scenes[protocol]; - scene_manager_next_scene(nfc->scene_manager, menu_scene); - consumed = true; - } + consumed = nfc_protocol_support_handle_scene_info(nfc, event.event); } return consumed; diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c index 86bafd70001a..24a29a95cd08 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c @@ -1,5 +1,7 @@ #include "../nfc_app_i.h" + #include +#include #define TAG "NfcMfClassicDictAttack" diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_menu.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_menu.c deleted file mode 100644 index efc5cfeb2462..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_menu.c +++ /dev/null @@ -1,81 +0,0 @@ -#include "../nfc_app_i.h" -#include - -enum SubmenuIndex { - SubmenuIndexSave, - SubmenuIndexEmulate, - SubmenuIndexDetectReader, - SubmenuIndexInfo, -}; - -void nfc_scene_mf_classic_menu_submenu_callback(void* context, uint32_t index) { - NfcApp* nfc = context; - - view_dispatcher_send_custom_event(nfc->view_dispatcher, index); -} - -void nfc_scene_mf_classic_menu_on_enter(void* context) { - NfcApp* nfc = context; - Submenu* submenu = nfc->submenu; - - submenu_add_item( - submenu, "Save", SubmenuIndexSave, nfc_scene_mf_classic_menu_submenu_callback, nfc); - submenu_add_item( - submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_mf_classic_menu_submenu_callback, nfc); - - const MfClassicData* mfc_data = nfc_device_get_data(nfc->nfc_device, NfcProtocolMfClassic); - if(!mf_classic_is_card_read(mfc_data)) { - submenu_add_item( - submenu, - "Detect Reader", - SubmenuIndexDetectReader, - nfc_scene_mf_classic_menu_submenu_callback, - nfc); - } - submenu_add_item( - submenu, "Info", SubmenuIndexInfo, nfc_scene_mf_classic_menu_submenu_callback, nfc); - - submenu_set_selected_item( - nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicMenu)); - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); -} - -bool nfc_scene_mf_classic_menu_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfClassicMenu, event.event); - if(event.event == SubmenuIndexSave) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); - consumed = true; - } else if(event.event == SubmenuIndexEmulate) { - if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) { - dolphin_deed(DolphinDeedNfcAddEmulate); - } else { - dolphin_deed(DolphinDeedNfcEmulate); - } - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); - consumed = true; - } else if(event.event == SubmenuIndexDetectReader) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); - dolphin_deed(DolphinDeedNfcDetectReader); - consumed = true; - } else if(event.event == SubmenuIndexInfo) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneInfo); - consumed = true; - } - } else if(event.type == SceneManagerEventTypeBack) { - consumed = scene_manager_previous_scene(nfc->scene_manager); - } - - return consumed; -} - -void nfc_scene_mf_classic_menu_on_exit(void* context) { - NfcApp* nfc = context; - - // Clear view - submenu_reset(nfc->submenu); -} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_desfire_app.c b/applications/main/nfc/scenes/nfc_scene_mf_desfire_app.c index 79cc17db27c2..8d6a92b6c7e6 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_desfire_app.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_desfire_app.c @@ -1,6 +1,6 @@ #include "../nfc_app_i.h" -#include "../helpers/format/nfc_mf_desfire_format.h" +#include "../helpers/protocol_support/mf_desfire/mf_desfire_render.h" enum SubmenuIndex { SubmenuIndexAppInfo, @@ -70,16 +70,16 @@ bool nfc_scene_mf_desfire_app_on_event(void* context, SceneManagerEvent event) { if(event.event == SubmenuIndexAppInfo) { const MfDesfireApplicationId* app_id = simple_array_cget(data->application_ids, app_index); - nfc_mf_desfire_format_application_id(app_id, nfc->text_box_store); - nfc_mf_desfire_format_application(app, nfc->text_box_store); + nfc_render_mf_desfire_application_id(app_id, nfc->text_box_store); + nfc_render_mf_desfire_application(app, nfc->text_box_store); } else { const uint32_t file_index = event.event - SubmenuIndexDynamic; const MfDesfireFileId* file_id = simple_array_cget(app->file_ids, file_index); const MfDesfireFileSettings* file_settings = simple_array_cget(app->file_settings, file_index); const MfDesfireFileData* file_data = simple_array_cget(app->file_data, file_index); - nfc_mf_desfire_format_file_id(file_id, nfc->text_box_store); - nfc_mf_desfire_format_file_settings_data( + nfc_render_mf_desfire_file_id(file_id, nfc->text_box_store); + nfc_render_mf_desfire_file_settings_data( file_settings, file_data, nfc->text_box_store); } text_box_set_text(text_box, furi_string_get_cstr(nfc->text_box_store)); diff --git a/applications/main/nfc/scenes/nfc_scene_mf_desfire_data.c b/applications/main/nfc/scenes/nfc_scene_mf_desfire_data.c index 84d6489b5833..f26aa06a1bcf 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_desfire_data.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_desfire_data.c @@ -1,6 +1,6 @@ #include "../nfc_app_i.h" -#include "../helpers/format/nfc_mf_desfire_format.h" +#include "../helpers/protocol_support/mf_desfire/mf_desfire_render.h" enum { MifareDesfireDataStateMenu, @@ -74,7 +74,7 @@ bool nfc_scene_mf_desfire_data_on_event(void* context, SceneManagerEvent event) furi_string_reset(nfc->text_box_store); if(event.event == SubmenuIndexCardInfo) { - nfc_mf_desfire_format_data(data, nfc->text_box_store); + nfc_render_mf_desfire_data(data, nfc->text_box_store); text_box_set_text(text_box, furi_string_get_cstr(nfc->text_box_store)); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); scene_manager_set_scene_state( diff --git a/applications/main/nfc/scenes/nfc_scene_mf_desfire_menu.c b/applications/main/nfc/scenes/nfc_scene_mf_desfire_menu.c deleted file mode 100644 index 918a8020f61a..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_mf_desfire_menu.c +++ /dev/null @@ -1,68 +0,0 @@ -#include "../nfc_app_i.h" -#include - -enum SubmenuIndex { - SubmenuIndexSave, - SubmenuIndexEmulateUid, - SubmenuIndexInfo, -}; - -void nfc_scene_mf_desfire_menu_submenu_callback(void* context, uint32_t index) { - NfcApp* nfc = context; - - view_dispatcher_send_custom_event(nfc->view_dispatcher, index); -} - -void nfc_scene_mf_desfire_menu_on_enter(void* context) { - NfcApp* nfc = context; - Submenu* submenu = nfc->submenu; - - submenu_add_item( - submenu, "Save", SubmenuIndexSave, nfc_scene_mf_desfire_menu_submenu_callback, nfc); - submenu_add_item( - submenu, - "Emulate UID", - SubmenuIndexEmulateUid, - nfc_scene_mf_desfire_menu_submenu_callback, - nfc); - submenu_add_item( - submenu, "Info", SubmenuIndexInfo, nfc_scene_mf_desfire_menu_submenu_callback, nfc); - - submenu_set_selected_item( - nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireMenu)); - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); -} - -bool nfc_scene_mf_desfire_menu_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == SubmenuIndexSave) { - // TODO: Implement saving - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); - consumed = true; - } else if(event.event == SubmenuIndexEmulateUid) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcaEmulate); - if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneNotImplemented)) { - dolphin_deed(DolphinDeedNfcAddEmulate); - } else { - dolphin_deed(DolphinDeedNfcEmulate); - } - consumed = true; - } else if(event.event == SubmenuIndexInfo) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneInfo); - consumed = true; - } - } - - return consumed; -} - -void nfc_scene_mf_desfire_menu_on_exit(void* context) { - NfcApp* nfc = context; - - // Clear view - submenu_reset(nfc->submenu); -} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c deleted file mode 100644 index ae7f1f781a05..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_menu.c +++ /dev/null @@ -1,85 +0,0 @@ -#include "../nfc_app_i.h" -#include - -enum SubmenuIndex { - SubmenuIndexUnlock, - SubmenuIndexSave, - SubmenuIndexEmulate, - SubmenuIndexInfo, -}; - -void nfc_scene_mf_ultralight_menu_submenu_callback(void* context, uint32_t index) { - NfcApp* nfc = context; - - view_dispatcher_send_custom_event(nfc->view_dispatcher, index); -} - -void nfc_scene_mf_ultralight_menu_on_enter(void* context) { - NfcApp* nfc = context; - Submenu* submenu = nfc->submenu; - - const MfUltralightData* data = nfc_device_get_data(nfc->nfc_device, NfcProtocolMfUltralight); - - if(!mf_ultralight_is_all_data_read(data)) { - submenu_add_item( - submenu, - "Unlock", - SubmenuIndexUnlock, - nfc_scene_mf_ultralight_menu_submenu_callback, - nfc); - } - submenu_add_item( - submenu, "Save", SubmenuIndexSave, nfc_scene_mf_ultralight_menu_submenu_callback, nfc); - submenu_add_item( - submenu, - "Emulate", - SubmenuIndexEmulate, - nfc_scene_mf_ultralight_menu_submenu_callback, - nfc); - submenu_add_item( - submenu, "Info", SubmenuIndexInfo, nfc_scene_mf_ultralight_menu_submenu_callback, nfc); - - submenu_set_selected_item( - nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightMenu)); - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); -} - -bool nfc_scene_mf_ultralight_menu_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == SubmenuIndexSave) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); - consumed = true; - } else if(event.event == SubmenuIndexEmulate) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate); - // 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, NfcSceneMfUltralightUnlockMenu); - consumed = true; - } else if(event.event == SubmenuIndexInfo) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneInfo); - consumed = true; - } - scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfUltralightMenu, event.event); - - } else if(event.type == SceneManagerEventTypeBack) { - consumed = scene_manager_previous_scene(nfc->scene_manager); - } - - return consumed; -} - -void nfc_scene_mf_ultralight_menu_on_exit(void* context) { - NfcApp* nfc = context; - - // Clear view - submenu_reset(nfc->submenu); -} diff --git a/applications/main/nfc/scenes/nfc_scene_nfca_menu.c b/applications/main/nfc/scenes/nfc_scene_nfca_menu.c deleted file mode 100644 index 5fcb655c6a63..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_nfca_menu.c +++ /dev/null @@ -1,65 +0,0 @@ -#include "../nfc_app_i.h" -#include - -enum SubmenuIndex { - SubmenuIndexSaveUid, - SubmenuIndexEmulateUid, - SubmenuIndexInfo, -}; - -void nfc_scene_nfca_menu_submenu_callback(void* context, uint32_t index) { - NfcApp* nfc = context; - - view_dispatcher_send_custom_event(nfc->view_dispatcher, index); -} - -void nfc_scene_nfca_menu_on_enter(void* context) { - NfcApp* nfc = context; - Submenu* submenu = nfc->submenu; - - submenu_add_item( - submenu, "Save UID", SubmenuIndexSaveUid, nfc_scene_nfca_menu_submenu_callback, nfc); - submenu_add_item( - submenu, "Emulate UID", SubmenuIndexEmulateUid, nfc_scene_nfca_menu_submenu_callback, nfc); - submenu_add_item(submenu, "Info", SubmenuIndexInfo, nfc_scene_nfca_menu_submenu_callback, nfc); - - submenu_set_selected_item( - nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneNfcaMenu)); - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); -} - -bool nfc_scene_nfca_menu_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == SubmenuIndexSaveUid) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); - consumed = true; - } else if(event.event == SubmenuIndexEmulateUid) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcaEmulate); - if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneNotImplemented)) { - dolphin_deed(DolphinDeedNfcAddEmulate); - } else { - dolphin_deed(DolphinDeedNfcEmulate); - } - consumed = true; - } else if(event.event == SubmenuIndexInfo) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneInfo); - consumed = true; - } - scene_manager_set_scene_state(nfc->scene_manager, NfcSceneNfcaMenu, event.event); - } else if(event.type == SceneManagerEventTypeBack) { - consumed = scene_manager_previous_scene(nfc->scene_manager); - } - - return consumed; -} - -void nfc_scene_nfca_menu_on_exit(void* context) { - NfcApp* nfc = context; - - // Clear view - submenu_reset(nfc->submenu); -} diff --git a/applications/main/nfc/scenes/nfc_scene_read.c b/applications/main/nfc/scenes/nfc_scene_read.c index 3a2ac29525db..31bb7dd8ef1e 100644 --- a/applications/main/nfc/scenes/nfc_scene_read.c +++ b/applications/main/nfc/scenes/nfc_scene_read.c @@ -1,11 +1,11 @@ #include "../nfc_app_i.h" -#include "../helpers/handlers/nfc_poller_handler.h" +#include "../helpers/protocol_support/nfc_protocol_support.h" static NfcCommand nfc_scene_read_poller_callback(NfcGenericEvent event, void* context) { NfcApp* instance = context; - const NfcCustomEvent custom_event = nfc_poller_handler_read(event, context); + const NfcCustomEvent custom_event = nfc_protocol_support_handle_poller(event, context); view_dispatcher_send_custom_event(instance->view_dispatcher, custom_event); return custom_event != NfcCustomEventReadHandlerIgnore ? NfcCommandStop : NfcCommandContinue; } diff --git a/applications/main/nfc/scenes/nfc_scene_read_menu.c b/applications/main/nfc/scenes/nfc_scene_read_menu.c new file mode 100644 index 000000000000..bd152e269c08 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_read_menu.c @@ -0,0 +1,33 @@ +#include "../nfc_app_i.h" + +#include "../helpers/protocol_support/nfc_protocol_support.h" + +void nfc_scene_read_menu_on_enter(void* context) { + NfcApp* nfc = context; + + nfc_protocol_support_build_scene_read_menu(nfc); + + submenu_set_selected_item( + nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadMenu)); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); +} + +bool nfc_scene_read_menu_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneReadMenu, event.event); + consumed = nfc_protocol_support_handle_scene_read_menu(nfc, event.event); + } + + return consumed; +} + +void nfc_scene_read_menu_on_exit(void* context) { + NfcApp* nfc = context; + + submenu_reset(nfc->submenu); +} diff --git a/applications/main/nfc/scenes/nfc_scene_read_success.c b/applications/main/nfc/scenes/nfc_scene_read_success.c index 959a0edaec5f..f6717c92bf68 100644 --- a/applications/main/nfc/scenes/nfc_scene_read_success.c +++ b/applications/main/nfc/scenes/nfc_scene_read_success.c @@ -1,59 +1,22 @@ #include "../nfc_app_i.h" -#include "../helpers/format/nfc_protocol_format.h" - -static void - nfc_scene_read_success_widget_callback(GuiButtonType result, InputType type, void* context) { - furi_assert(context); - NfcApp* nfc = context; - - if(type == InputTypeShort) { - view_dispatcher_send_custom_event(nfc->view_dispatcher, result); - } -} +#include "../helpers/protocol_support/nfc_protocol_support.h" void nfc_scene_read_success_on_enter(void* context) { NfcApp* nfc = context; - Widget* widget = nfc->widget; - - FuriString* temp_str = furi_string_alloc(); - nfc_protocol_format_info(nfc->nfc_device, NfcProtocolFormatTypeShort, temp_str); - - widget_add_text_scroll_element(widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); - furi_string_free(temp_str); - - widget_add_button_element( - widget, GuiButtonTypeLeft, "Retry", nfc_scene_read_success_widget_callback, nfc); - widget_add_button_element( - widget, GuiButtonTypeRight, "More", nfc_scene_read_success_widget_callback, nfc); + nfc_protocol_support_build_scene_read_success(nfc); notification_message_block(nfc->notifications, &sequence_set_green_255); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); } -static const NfcScene nfc_scene_read_success_menu_scenes[NfcProtocolNum] = { - [NfcProtocolIso14443_3a] = NfcSceneNfcaMenu, - [NfcProtocolIso14443_4a] = NfcSceneNotImplemented, //TODO: ISO14443-4A menu - [NfcProtocolMfUltralight] = NfcSceneMfUltralightMenu, - [NfcProtocolMfClassic] = NfcSceneMfUltralightMenu, - [NfcProtocolMfDesfire] = NfcSceneMfDesfireMenu, -}; - bool nfc_scene_read_success_on_event(void* context, SceneManagerEvent event) { NfcApp* 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) { - const NfcProtocol protocol = nfc_device_get_protocol(nfc->nfc_device); - const NfcScene menu_scene = nfc_scene_read_success_menu_scenes[protocol]; - scene_manager_next_scene(nfc->scene_manager, menu_scene); - consumed = true; - } + consumed = nfc_protocol_support_handle_scene_read_success(nfc, event.event); } else if(event.type == SceneManagerEventTypeBack) { scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); consumed = true; diff --git a/applications/main/nfc/scenes/nfc_scene_saved_menu.c b/applications/main/nfc/scenes/nfc_scene_saved_menu.c index c4235471cc55..d2ad71ca2155 100644 --- a/applications/main/nfc/scenes/nfc_scene_saved_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_saved_menu.c @@ -1,111 +1,12 @@ #include "../nfc_app_i.h" -#include -enum SubmenuIndex { - SubmenuIndexEmulate, - SubmenuIndexEditUid, - SubmenuIndexDetectReader, - SubmenuIndexWrite, - SubmenuIndexUpdate, - SubmenuIndexRename, - SubmenuIndexDelete, - SubmenuIndexInfo, - SubmenuIndexRestoreOriginal, - SubmenuIndexMfUlUnlockByReader, - SubmenuIndexMfUlUnlockByPassword, -}; - -void nfc_scene_saved_menu_submenu_callback(void* context, uint32_t index) { - NfcApp* nfc = context; - - view_dispatcher_send_custom_event(nfc->view_dispatcher, index); -} +#include "../helpers/protocol_support/nfc_protocol_support.h" void nfc_scene_saved_menu_on_enter(void* context) { NfcApp* nfc = context; - Submenu* submenu = nfc->submenu; - - const NfcProtocol protocol = nfc_device_get_protocol(nfc->nfc_device); - - if(protocol == NfcProtocolIso14443_3a) { - submenu_add_item( - submenu, - "Emulate UID", - SubmenuIndexEmulate, - nfc_scene_saved_menu_submenu_callback, - nfc); - submenu_add_item( - submenu, "Edit UID", SubmenuIndexEditUid, nfc_scene_saved_menu_submenu_callback, nfc); - - } else if(protocol == NfcProtocolMfDesfire) { - submenu_add_item( - submenu, - "Emulate UID", - SubmenuIndexEmulate, - nfc_scene_saved_menu_submenu_callback, - nfc); - } else if((protocol == NfcProtocolMfUltralight) || (protocol == NfcProtocolMfClassic)) { - submenu_add_item( - submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_saved_menu_submenu_callback, nfc); - } - - if(protocol == NfcProtocolMfClassic) { - // TODO - // if(!mifare_classic_is_card_read(&nfc->dev->dev_data.mf_classic_data)) - submenu_add_item( - submenu, - "Detect Reader", - SubmenuIndexDetectReader, - nfc_scene_saved_menu_submenu_callback, - nfc); - submenu_add_item( - submenu, - "Write to Initial Card", - SubmenuIndexWrite, - nfc_scene_saved_menu_submenu_callback, - nfc); - submenu_add_item( - submenu, - "Update from Initial Card", - SubmenuIndexUpdate, - nfc_scene_saved_menu_submenu_callback, - nfc); - } - submenu_add_item( - submenu, "Info", SubmenuIndexInfo, nfc_scene_saved_menu_submenu_callback, nfc); + nfc_protocol_support_build_scene_saved_menu(nfc); - if(protocol == NfcProtocolMfUltralight) { - const MfUltralightData* mfu_data = - nfc_device_get_data(nfc->nfc_device, NfcProtocolMfUltralight); - if(!mf_ultralight_is_all_data_read(mfu_data)) { - submenu_add_item( - submenu, - "Unlock with Reader", - SubmenuIndexMfUlUnlockByReader, - nfc_scene_saved_menu_submenu_callback, - nfc); - submenu_add_item( - submenu, - "Unlock with Password", - SubmenuIndexMfUlUnlockByPassword, - nfc_scene_saved_menu_submenu_callback, - nfc); - } - } - // TODO - // if(nfc_is_shadow_file_exist) - submenu_add_item( - submenu, - "Restore to original", - SubmenuIndexRestoreOriginal, - nfc_scene_saved_menu_submenu_callback, - nfc); - - submenu_add_item( - submenu, "Rename", SubmenuIndexRename, nfc_scene_saved_menu_submenu_callback, nfc); - submenu_add_item( - submenu, "Delete", SubmenuIndexDelete, nfc_scene_saved_menu_submenu_callback, nfc); submenu_set_selected_item( nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneSavedMenu)); @@ -115,66 +16,11 @@ void nfc_scene_saved_menu_on_enter(void* context) { bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { NfcApp* nfc = context; - const NfcProtocol protocol = nfc_device_get_protocol(nfc->nfc_device); bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { scene_manager_set_scene_state(nfc->scene_manager, NfcSceneSavedMenu, event.event); - if(event.event == SubmenuIndexEmulate) { - if(protocol == NfcProtocolMfUltralight) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate); - } else if(protocol == NfcProtocolMfClassic) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); - } else { - scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcaEmulate); - } - dolphin_deed(DolphinDeedNfcEmulate); - consumed = true; - } else if(event.event == SubmenuIndexDetectReader) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); - dolphin_deed(DolphinDeedNfcDetectReader); - consumed = true; - } else if(event.event == SubmenuIndexWrite) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); - consumed = true; - } else if(event.event == SubmenuIndexUpdate) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); - consumed = true; - } else if(event.event == SubmenuIndexRename) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); - consumed = true; - } else if(event.event == SubmenuIndexEditUid) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneSetUid); - consumed = true; - } else if(event.event == SubmenuIndexDelete) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneDelete); - consumed = true; - } else if(event.event == SubmenuIndexInfo) { - // bool application_info_present = false; - // if( - // dev_data->protocol == NfcDeviceProtocolMifareClassic || - // dev_data->protocol == NfcDeviceProtocolMifareUl) { - // application_info_present = nfc_supported_card_verify_and_parse(dev_data); - // } - - // FURI_LOG_I("nfc", "application_info_present: %d", application_info_present); - - // if(application_info_present) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); - // } else { - // scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); - // } - consumed = true; - } else if(event.event == SubmenuIndexRestoreOriginal) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); - consumed = true; - } else if(event.event == SubmenuIndexMfUlUnlockByReader) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); - consumed = true; - } else if(event.event == SubmenuIndexMfUlUnlockByPassword) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockMenu); - consumed = true; - } + consumed = nfc_protocol_support_handle_scene_saved_menu(nfc, event.event); } return consumed; diff --git a/lib/nfc/nfc_device.c b/lib/nfc/nfc_device.c index 95a1cb361170..cf9d4dfd8460 100644 --- a/lib/nfc/nfc_device.c +++ b/lib/nfc/nfc_device.c @@ -131,7 +131,7 @@ bool nfc_device_save(NfcDevice* instance, const char* path) { bool saved = false; Storage* storage = furi_record_open(RECORD_STORAGE); - FlipperFormat* file = flipper_format_file_alloc(storage); + FlipperFormat* file = flipper_format_buffered_file_alloc(storage); FuriString* temp_str; temp_str = furi_string_alloc(); @@ -142,7 +142,7 @@ bool nfc_device_save(NfcDevice* instance, const char* path) { do { // Open file - if(!flipper_format_file_open_always(file, path)) break; + if(!flipper_format_buffered_file_open_always(file, path)) break; // Write header if(!flipper_format_write_header_cstr(file, NFC_FILE_HEADER, NFC_CURRENT_FORMAT_VERSION)) @@ -175,7 +175,7 @@ bool nfc_device_load(NfcDevice* instance, const char* path) { bool loaded = false; Storage* storage = furi_record_open(RECORD_STORAGE); - FlipperFormat* file = flipper_format_file_alloc(storage); + FlipperFormat* file = flipper_format_buffered_file_alloc(storage); FuriString* temp_str; temp_str = furi_string_alloc(); @@ -185,7 +185,7 @@ bool nfc_device_load(NfcDevice* instance, const char* path) { } do { - if(!flipper_format_file_open_existing(file, path)) break; + if(!flipper_format_buffered_file_open_existing(file, path)) break; // Read and verify file header uint32_t version = 0; diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a.c b/lib/nfc/protocols/iso14443_3a/iso14443_3a.c index 6ec1ba63618d..5d4e07191410 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a.c +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a.c @@ -53,7 +53,6 @@ bool iso14443_3a_verify(Iso14443_3aData* data, const FuriString* device_type) { bool iso14443_3a_load(Iso14443_3aData* data, FlipperFormat* ff, uint32_t version) { return iso14443_3a_load_data(data, ff, version); - return true; } bool iso14443_3a_save(const Iso14443_3aData* data, FlipperFormat* ff, uint32_t version) { @@ -130,11 +129,12 @@ bool iso14443_3a_save_data(const Iso14443_3aData* data, FlipperFormat* ff, uint3 bool saved = false; do { // Write UID, ATQA, SAK - if(!flipper_format_write_comment_cstr(ff, "UID, ATQA and SAK are common for all formats")) - break; + if(!flipper_format_write_comment_cstr(ff, "UID is common for all formats")) break; if(!flipper_format_write_hex(ff, "UID", data->uid, data->uid_len)) break; // Save ATQA in MSB order for correct companion apps display uint8_t atqa[2] = {data->atqa[1], data->atqa[0]}; + if(!flipper_format_write_comment_cstr(ff, ISO14443_3A_PROTOCOL_NAME " specific fields")) + break; if(!flipper_format_write_hex(ff, "ATQA", atqa, 2)) break; if(!flipper_format_write_hex(ff, "SAK", &data->sak, 1)) break; saved = true; diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.c b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.c index 545d4932d23a..bd68fa905d11 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.c +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.c @@ -147,7 +147,7 @@ Iso14443_3aError iso14443_3a_poller_async_activate( memcpy( instance->data->atqa, &instance->col_res.sens_resp, - sizeof(instance->col_res.sel_resp)); + sizeof(instance->col_res.sens_resp)); instance->state = Iso14443_3aPollerStateColResInProgress; instance->col_res.cascade_level = 0; diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a.c b/lib/nfc/protocols/iso14443_4a/iso14443_4a.c index 8bc9f060876f..f1a2e506b4cf 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a.c +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a.c @@ -58,21 +58,15 @@ bool iso14443_4a_verify(Iso14443_4aData* data, const FuriString* device_type) { } bool iso14443_4a_load(Iso14443_4aData* data, FlipperFormat* ff, uint32_t version) { - UNUSED(data); - UNUSED(ff); - UNUSED(version); - - // TODO: implementation - return false; + furi_assert(data); + // TODO: handle additional fields + return iso14443_3a_load_data(data->iso14443_3a_data, ff, version); } bool iso14443_4a_save(const Iso14443_4aData* data, FlipperFormat* ff, uint32_t version) { - UNUSED(data); - UNUSED(ff); - UNUSED(version); - - // TODO: implementation - return false; + furi_assert(data); + // TODO: handle additional fields + return iso14443_3a_save_data(data->iso14443_3a_data, ff, version); } bool iso14443_4a_is_equal(const Iso14443_4aData* data, const Iso14443_4aData* other) { diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire.c b/lib/nfc/protocols/mf_desfire/mf_desfire.c index 43f6d1d47bc3..8a3d12f5d05a 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire.c +++ b/lib/nfc/protocols/mf_desfire/mf_desfire.c @@ -2,8 +2,7 @@ #include -#define MF_DESFIRE_PROTOCOL_NAME "Mifare DESfire" -#define MF_DESFIRE_DEVICE_NAME "Mifare DESfire" +#define MF_DESFIRE_PROTOCOL_NAME "Mifare DESFire" const NfcDeviceBase nfc_device_mf_desfire = { .protocol_name = MF_DESFIRE_PROTOCOL_NAME, @@ -73,25 +72,136 @@ void mf_desfire_copy(MfDesfireData* data, const MfDesfireData* other) { bool mf_desfire_verify(MfDesfireData* data, const FuriString* device_type) { UNUSED(data); - return furi_string_equal_str(device_type, "Mifare Desfire"); + return furi_string_equal_str(device_type, MF_DESFIRE_PROTOCOL_NAME); } bool mf_desfire_load(MfDesfireData* data, FlipperFormat* ff, uint32_t version) { - UNUSED(data); - UNUSED(ff); - UNUSED(version); + furi_assert(data); - // TODO: Implementation - return false; + FuriString* prefix = furi_string_alloc(); + + bool success = false; + + do { + if(!iso14443_4a_load(data->iso14443_4a_data, ff, version)) break; + + if(!mf_desfire_version_load(&data->version, ff)) break; + if(!mf_desfire_free_memory_load(&data->free_memory, ff)) break; + if(!mf_desfire_key_settings_load( + &data->master_key_settings, MF_DESFIRE_FFF_PICC_PREFIX, ff)) + break; + + const uint32_t master_key_version_count = data->master_key_settings.max_keys; + simple_array_init(data->master_key_versions, master_key_version_count); + + uint32_t i; + for(i = 0; i < master_key_version_count; ++i) { + if(!mf_desfire_key_version_load( + simple_array_get(data->master_key_versions, i), + MF_DESFIRE_FFF_PICC_PREFIX, + i, + ff)) + break; + } + + if(i != master_key_version_count) break; + + uint32_t application_count; + if(!mf_desfire_application_count_load(&application_count, ff)) break; + + simple_array_init(data->application_ids, application_count); + if(!mf_desfire_application_ids_load( + simple_array_get(data->application_ids, 0), application_count, ff)) + break; + + simple_array_init(data->applications, application_count); + for(i = 0; i < application_count; ++i) { + const MfDesfireApplicationId* app_id = simple_array_cget(data->application_ids, i); + furi_string_printf( + prefix, + "%s %02x%02x%02x", + MF_DESFIRE_FFF_APP_PREFIX, + app_id->data[0], + app_id->data[1], + app_id->data[2]); + + if(!mf_desfire_application_load( + simple_array_get(data->applications, i), furi_string_get_cstr(prefix), ff)) + break; + } + + if(i != application_count) break; + + success = true; + } while(false); + + furi_string_free(prefix); + return success; } bool mf_desfire_save(const MfDesfireData* data, FlipperFormat* ff, uint32_t version) { - UNUSED(data); - UNUSED(ff); + furi_assert(data); UNUSED(version); - // TODO: Implementation - return false; + FuriString* prefix = furi_string_alloc(); + + bool success = false; + + do { + if(!flipper_format_write_string_cstr(ff, "Device type", MF_DESFIRE_PROTOCOL_NAME)) break; + + if(!iso14443_4a_save(data->iso14443_4a_data, ff, version)) break; + + if(!flipper_format_write_comment_cstr(ff, MF_DESFIRE_PROTOCOL_NAME " specific data")) + break; + if(!mf_desfire_version_save(&data->version, ff)) break; + if(!mf_desfire_free_memory_save(&data->free_memory, ff)) break; + if(!mf_desfire_key_settings_save( + &data->master_key_settings, MF_DESFIRE_FFF_PICC_PREFIX, ff)) + break; + + const uint32_t master_key_version_count = + simple_array_get_count(data->master_key_versions); + + uint32_t i; + for(i = 0; i < master_key_version_count; ++i) { + if(!mf_desfire_key_version_save( + simple_array_cget(data->master_key_versions, i), + MF_DESFIRE_FFF_PICC_PREFIX, + i, + ff)) + break; + } + + if(i != master_key_version_count) break; + + const uint32_t application_count = simple_array_get_count(data->application_ids); + if(!mf_desfire_application_count_save(&application_count, ff)) break; + if(!mf_desfire_application_ids_save( + simple_array_cget(data->application_ids, 0), application_count, ff)) + break; + + for(i = 0; i < application_count; ++i) { + const MfDesfireApplicationId* app_id = simple_array_cget(data->application_ids, i); + furi_string_printf( + prefix, + "%s %02x%02x%02x", + MF_DESFIRE_FFF_APP_PREFIX, + app_id->data[0], + app_id->data[1], + app_id->data[2]); + + const MfDesfireApplication* app = simple_array_cget(data->applications, i); + if(!mf_desfire_application_save(app, furi_string_get_cstr(prefix), ff)) break; + } + + if(i != application_count) break; + + success = true; + } while(false); + + furi_string_free(prefix); + return success; } bool mf_desfire_is_equal(const MfDesfireData* data, const MfDesfireData* other) { @@ -105,7 +215,7 @@ bool mf_desfire_is_equal(const MfDesfireData* data, const MfDesfireData* other) const char* mf_desfire_get_device_name(const MfDesfireData* data, NfcDeviceNameType name_type) { UNUSED(data); UNUSED(name_type); - return MF_DESFIRE_DEVICE_NAME; + return MF_DESFIRE_PROTOCOL_NAME; } const uint8_t* mf_desfire_get_uid(const MfDesfireData* data, size_t* uid_len) { diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire.h b/lib/nfc/protocols/mf_desfire/mf_desfire.h index 85821f648f0d..a7569350e9e1 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire.h +++ b/lib/nfc/protocols/mf_desfire/mf_desfire.h @@ -59,13 +59,13 @@ typedef struct { } MfDesfireFreeMemory; // EV1+ only typedef struct { - bool is_master_key_changeable : 1; - bool is_free_directory_list : 1; - bool is_free_create_delete : 1; - bool is_config_changeable : 1; - uint8_t change_key_id : 4; - uint8_t max_keys : 4; - uint8_t flags : 4; + bool is_master_key_changeable; + bool is_free_directory_list; + bool is_free_create_delete; + bool is_config_changeable; + uint8_t change_key_id; + uint8_t max_keys; + uint8_t flags; } MfDesfireKeySettings; typedef uint8_t MfDesfireKeyVersion; diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_i.c b/lib/nfc/protocols/mf_desfire/mf_desfire_i.c index 7fc6f13489db..18dfaaca15c4 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_i.c +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_i.c @@ -1,19 +1,80 @@ #include "mf_desfire_i.h" +#define MF_DESFIRE_FFF_VERSION_KEY \ + MF_DESFIRE_FFF_PICC_PREFIX " " \ + "Version" +#define MF_DESFIRE_FFF_FREE_MEM_KEY \ + MF_DESFIRE_FFF_PICC_PREFIX " " \ + "Free Memory" + +#define MF_DESFIRE_FFF_CHANGE_KEY_ID_KEY "Change Key ID" +#define MF_DESFIRE_FFF_CONFIG_CHANGEABLE_KEY "Config Changeable" +#define MF_DESFIRE_FFF_FREE_CREATE_DELETE_KEY "Free Create Delete" +#define MF_DESFIRE_FFF_FREE_DIR_LIST_KEY "Free Directory List" +#define MF_DESFIRE_FFF_KEY_CHANGEABLE_KEY "Key Changeable" +#define MF_DESFIRE_FFF_FLAGS_KEY "Flags" +#define MF_DESFIRE_FFF_MAX_KEYS_KEY "Max Keys" + +#define MF_DESFIRE_FFF_KEY_SUB_PREFIX "Key" +#define MF_DESFIRE_FFF_KEY_VERSION_KEY "Version" + +#define MF_DESFIRE_FFF_APPLICATION_COUNT_KEY \ + MF_DESFIRE_FFF_APP_PREFIX " " \ + "Count" +#define MF_DESFIRE_FFF_APPLICATION_IDS_KEY \ + MF_DESFIRE_FFF_APP_PREFIX " " \ + "IDs" + +#define MF_DESFIRE_FFF_FILE_SUB_PREFIX "File" +#define MF_DESFIRE_FFF_FILE_IDS_KEY \ + MF_DESFIRE_FFF_FILE_SUB_PREFIX " " \ + "IDs" +#define MF_DESFIRE_FFF_FILE_TYPE_KEY "Type" +#define MF_DESFIRE_FFF_FILE_COMM_SETTINGS_KEY "Communication Settings" +#define MF_DESFIRE_FFF_FILE_ACCESS_RIGHTS_KEY "Access Rights" + +#define MF_DESFIRE_FFF_FILE_SIZE_KEY "Size" + +#define MF_DESFIRE_FFF_FILE_HI_LIMIT_KEY "Hi Limit" +#define MF_DESFIRE_FFF_FILE_LO_LIMIT_KEY "Lo Limit" +#define MF_DESFIRE_FFF_FILE_LIMIT_CREDIT_VALUE_KEY "Limited Credit Value" +#define MF_DESFIRE_FFF_FILE_LIMIT_CREDIT_ENABLED_KEY "Limited Credit Enabled" + +#define MF_DESFIRE_FFF_FILE_MAX_KEY "Max" +#define MF_DESFIRE_FFF_FILE_CUR_KEY "Cur" + void mf_desfire_version_parse(MfDesfireVersion* data, const BitBuffer* buf) { bit_buffer_write_bytes(buf, data, sizeof(MfDesfireVersion)); } void mf_desfire_free_memory_parse(MfDesfireFreeMemory* data, const BitBuffer* buf) { - furi_assert(!data->is_present); - bit_buffer_write_bytes(buf, &data->bytes_free, sizeof(data->bytes_free) - 1); data->bytes_free &= 0x00ffffff; data->is_present = true; } void mf_desfire_key_settings_parse(MfDesfireKeySettings* data, const BitBuffer* buf) { - bit_buffer_write_bytes(buf, data, sizeof(MfDesfireKeySettings)); + typedef struct { + bool is_master_key_changeable : 1; + bool is_free_directory_list : 1; + bool is_free_create_delete : 1; + bool is_config_changeable : 1; + uint8_t change_key_id : 4; + uint8_t max_keys : 4; + uint8_t flags : 4; + } MfDesfireKeySettingsLayout; + + MfDesfireKeySettingsLayout layout; + bit_buffer_write_bytes(buf, &layout, sizeof(MfDesfireKeySettingsLayout)); + + data->is_master_key_changeable = layout.is_master_key_changeable; + data->is_free_directory_list = layout.is_free_directory_list; + data->is_free_create_delete = layout.is_free_create_delete; + data->is_config_changeable = layout.is_config_changeable; + + data->change_key_id = layout.change_key_id; + data->max_keys = layout.max_keys; + data->flags = layout.flags; } void mf_desfire_key_version_parse(MfDesfireKeyVersion* data, const BitBuffer* buf) { @@ -82,6 +143,483 @@ void mf_desfire_application_copy(MfDesfireApplication* data, const MfDesfireAppl simple_array_copy(data->file_data, other->file_data); } +bool mf_desfire_version_load(MfDesfireVersion* data, FlipperFormat* ff) { + return flipper_format_read_hex( + ff, MF_DESFIRE_FFF_VERSION_KEY, (uint8_t*)data, sizeof(MfDesfireVersion)); +} + +bool mf_desfire_free_memory_load(MfDesfireFreeMemory* data, FlipperFormat* ff) { + data->is_present = flipper_format_key_exist(ff, MF_DESFIRE_FFF_FREE_MEM_KEY); + return data->is_present ? + flipper_format_read_uint32(ff, MF_DESFIRE_FFF_FREE_MEM_KEY, &data->bytes_free, 1) : + true; +} + +bool mf_desfire_key_settings_load( + MfDesfireKeySettings* data, + const char* prefix, + FlipperFormat* ff) { + bool success = false; + + FuriString* key = furi_string_alloc(); + + do { + furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_CHANGE_KEY_ID_KEY); + if(!flipper_format_read_hex(ff, furi_string_get_cstr(key), &data->change_key_id, 1)) break; + + furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_CONFIG_CHANGEABLE_KEY); + if(!flipper_format_read_bool(ff, furi_string_get_cstr(key), &data->is_config_changeable, 1)) + break; + + furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_FREE_CREATE_DELETE_KEY); + if(!flipper_format_read_bool( + ff, furi_string_get_cstr(key), &data->is_free_create_delete, 1)) + break; + + furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_FREE_DIR_LIST_KEY); + if(!flipper_format_read_bool( + ff, furi_string_get_cstr(key), &data->is_free_directory_list, 1)) + break; + + furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_KEY_CHANGEABLE_KEY); + if(!flipper_format_read_bool( + ff, furi_string_get_cstr(key), &data->is_master_key_changeable, 1)) + break; + + furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_FLAGS_KEY); + if(flipper_format_key_exist(ff, furi_string_get_cstr(key))) { + if(!flipper_format_read_hex(ff, furi_string_get_cstr(key), &data->flags, 1)) break; + } + + furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_MAX_KEYS_KEY); + if(!flipper_format_read_hex(ff, furi_string_get_cstr(key), &data->max_keys, 1)) break; + + // TODO: Whaaa + // ks->flags |= ks->max_keys >> 4; + // ks->max_keys &= 0xF; + + success = true; + } while(false); + + furi_string_free(key); + return success; +} + +bool mf_desfire_key_version_load( + MfDesfireKeyVersion* data, + const char* prefix, + uint32_t index, + FlipperFormat* ff) { + FuriString* key = furi_string_alloc_printf( + "%s %s %lu %s", + prefix, + MF_DESFIRE_FFF_KEY_SUB_PREFIX, + index, + MF_DESFIRE_FFF_KEY_VERSION_KEY); + const bool success = flipper_format_read_hex(ff, furi_string_get_cstr(key), data, 1); + furi_string_free(key); + return success; +} + +bool mf_desfire_file_count_load(uint32_t* data, const char* prefix, FlipperFormat* ff) { + FuriString* key = furi_string_alloc_printf("%s %s", prefix, MF_DESFIRE_FFF_FILE_IDS_KEY); + const bool success = flipper_format_get_value_count(ff, furi_string_get_cstr(key), data); + furi_string_free(key); + return success; +} + +bool mf_desfire_file_ids_load( + MfDesfireFileId* data, + uint32_t count, + const char* prefix, + FlipperFormat* ff) { + FuriString* key = furi_string_alloc_printf("%s %s", prefix, MF_DESFIRE_FFF_FILE_IDS_KEY); + const bool success = flipper_format_read_hex(ff, furi_string_get_cstr(key), data, count); + furi_string_free(key); + return success; +} + +bool mf_desfire_file_settings_load( + MfDesfireFileSettings* data, + const char* prefix, + FlipperFormat* ff) { + bool success = false; + + FuriString* key = furi_string_alloc(); + + do { + furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_FILE_TYPE_KEY); + if(!flipper_format_read_hex(ff, furi_string_get_cstr(key), (uint8_t*)&data->type, 1)) + break; + + furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_FILE_COMM_SETTINGS_KEY); + if(!flipper_format_read_hex(ff, furi_string_get_cstr(key), (uint8_t*)&data->comm, 1)) + break; + + furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_FILE_ACCESS_RIGHTS_KEY); + if(!flipper_format_read_hex( + ff, + furi_string_get_cstr(key), + (uint8_t*)&data->access_rights, + sizeof(MfDesfireFileAccessRights))) + break; + + if(data->type == MfDesfireFileTypeStandard || data->type == MfDesfireFileTypeBackup) { + furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_FILE_SIZE_KEY); + if(!flipper_format_read_uint32(ff, furi_string_get_cstr(key), &data->data.size, 1)) + break; + + } else if(data->type == MfDesfireFileTypeValue) { + furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_FILE_HI_LIMIT_KEY); + if(!flipper_format_read_uint32(ff, furi_string_get_cstr(key), &data->value.hi_limit, 1)) + break; + + furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_FILE_LO_LIMIT_KEY); + if(!flipper_format_read_uint32(ff, furi_string_get_cstr(key), &data->value.lo_limit, 1)) + break; + + furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_FILE_LIMIT_CREDIT_VALUE_KEY); + if(!flipper_format_read_uint32( + ff, furi_string_get_cstr(key), &data->value.limited_credit_value, 1)) + break; + + furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_FILE_LIMIT_CREDIT_ENABLED_KEY); + if(!flipper_format_read_bool( + ff, furi_string_get_cstr(key), &data->value.limited_credit_enabled, 1)) + break; + } else if( + data->type == MfDesfireFileTypeLinearRecord || + data->type == MfDesfireFileTypeCyclicRecord) { + furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_FILE_SIZE_KEY); + if(!flipper_format_read_uint32(ff, furi_string_get_cstr(key), &data->record.size, 1)) + break; + + furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_FILE_MAX_KEY); + if(!flipper_format_read_uint32(ff, furi_string_get_cstr(key), &data->record.max, 1)) + break; + + furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_FILE_CUR_KEY); + if(!flipper_format_read_uint32(ff, furi_string_get_cstr(key), &data->record.cur, 1)) + break; + } + + success = true; + } while(false); + + furi_string_free(key); + + return success; +} + +bool mf_desfire_file_data_load(MfDesfireFileData* data, const char* prefix, FlipperFormat* ff) { + bool success = false; + do { + if(!flipper_format_key_exist(ff, prefix)) { + success = true; + break; + } + + uint32_t data_size; + if(!flipper_format_get_value_count(ff, prefix, &data_size)) break; + + simple_array_init(data->data, data_size); + + if(!flipper_format_read_hex(ff, prefix, simple_array_get(data->data, 0), data_size)) break; + + success = true; + } while(false); + + return success; +} + +bool mf_desfire_application_count_load(uint32_t* data, FlipperFormat* ff) { + return flipper_format_read_uint32(ff, MF_DESFIRE_FFF_APPLICATION_COUNT_KEY, data, 1); +} + +bool mf_desfire_application_ids_load( + MfDesfireApplicationId* data, + uint32_t count, + FlipperFormat* ff) { + return flipper_format_read_hex( + ff, MF_DESFIRE_FFF_APPLICATION_IDS_KEY, data->data, count * sizeof(MfDesfireApplicationId)); +} + +bool mf_desfire_application_load(MfDesfireApplication* data, const char* prefix, FlipperFormat* ff) { + FuriString* sub_prefix = furi_string_alloc(); + bool success = false; + + do { + if(!mf_desfire_key_settings_load(&data->key_settings, prefix, ff)) break; + + const uint32_t key_version_count = data->key_settings.max_keys; + simple_array_init(data->key_versions, key_version_count); + + uint32_t i; + for(i = 0; i < key_version_count; ++i) { + if(!mf_desfire_key_version_load(simple_array_get(data->key_versions, i), prefix, i, ff)) + break; + } + + if(i != key_version_count) break; + + uint32_t file_count; + if(!mf_desfire_file_count_load(&file_count, prefix, ff)) break; + + simple_array_init(data->file_ids, file_count); + if(!mf_desfire_file_ids_load(simple_array_get(data->file_ids, 0), file_count, prefix, ff)) + break; + + simple_array_init(data->file_settings, file_count); + simple_array_init(data->file_data, file_count); + + for(i = 0; i < file_count; ++i) { + const MfDesfireFileId* file_id = simple_array_cget(data->file_ids, i); + furi_string_printf( + sub_prefix, "%s %s %u", prefix, MF_DESFIRE_FFF_FILE_SUB_PREFIX, *file_id); + + MfDesfireFileSettings* file_settings = simple_array_get(data->file_settings, i); + if(!mf_desfire_file_settings_load(file_settings, furi_string_get_cstr(sub_prefix), ff)) + break; + + MfDesfireFileData* file_data = simple_array_get(data->file_data, i); + if(!mf_desfire_file_data_load(file_data, furi_string_get_cstr(sub_prefix), ff)) break; + } + + if(i != file_count) break; + + success = true; + } while(false); + + furi_string_free(sub_prefix); + return success; +} + +bool mf_desfire_version_save(const MfDesfireVersion* data, FlipperFormat* ff) { + return flipper_format_write_hex( + ff, MF_DESFIRE_FFF_VERSION_KEY, (const uint8_t*)data, sizeof(MfDesfireVersion)); +} + +bool mf_desfire_free_memory_save(const MfDesfireFreeMemory* data, FlipperFormat* ff) { + return data->is_present ? + flipper_format_write_uint32(ff, MF_DESFIRE_FFF_FREE_MEM_KEY, &data->bytes_free, 1) : + true; +} + +bool mf_desfire_key_settings_save( + const MfDesfireKeySettings* data, + const char* prefix, + FlipperFormat* ff) { + bool success = false; + + FuriString* key = furi_string_alloc(); + + do { + furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_CHANGE_KEY_ID_KEY); + if(!flipper_format_write_hex(ff, furi_string_get_cstr(key), &data->change_key_id, 1)) + break; + + furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_CONFIG_CHANGEABLE_KEY); + if(!flipper_format_write_bool( + ff, furi_string_get_cstr(key), &data->is_config_changeable, 1)) + break; + + furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_FREE_CREATE_DELETE_KEY); + if(!flipper_format_write_bool( + ff, furi_string_get_cstr(key), &data->is_free_create_delete, 1)) + break; + + furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_FREE_DIR_LIST_KEY); + if(!flipper_format_write_bool( + ff, furi_string_get_cstr(key), &data->is_free_directory_list, 1)) + break; + + furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_KEY_CHANGEABLE_KEY); + if(!flipper_format_write_bool( + ff, furi_string_get_cstr(key), &data->is_master_key_changeable, 1)) + break; + + furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_FLAGS_KEY); + if(!flipper_format_write_hex(ff, furi_string_get_cstr(key), &data->flags, 1)) break; + + furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_MAX_KEYS_KEY); + if(!flipper_format_write_hex(ff, furi_string_get_cstr(key), &data->max_keys, 1)) break; + + success = true; + } while(false); + + furi_string_free(key); + return success; +} + +bool mf_desfire_key_version_save( + const MfDesfireKeyVersion* data, + const char* prefix, + uint32_t index, + FlipperFormat* ff) { + FuriString* key = furi_string_alloc_printf( + "%s %s %lu %s", + prefix, + MF_DESFIRE_FFF_KEY_SUB_PREFIX, + index, + MF_DESFIRE_FFF_KEY_VERSION_KEY); + const bool success = flipper_format_write_hex(ff, furi_string_get_cstr(key), data, 1); + furi_string_free(key); + return success; +} + +bool mf_desfire_file_ids_save( + const MfDesfireFileId* data, + uint32_t count, + const char* prefix, + FlipperFormat* ff) { + FuriString* key = furi_string_alloc_printf("%s %s", prefix, MF_DESFIRE_FFF_FILE_IDS_KEY); + const bool success = flipper_format_write_hex(ff, furi_string_get_cstr(key), data, count); + furi_string_free(key); + return success; +} + +bool mf_desfire_file_settings_save( + const MfDesfireFileSettings* data, + const char* prefix, + FlipperFormat* ff) { + bool success = false; + + FuriString* key = furi_string_alloc(); + + do { + furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_FILE_TYPE_KEY); + if(!flipper_format_write_hex(ff, furi_string_get_cstr(key), (const uint8_t*)&data->type, 1)) + break; + + furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_FILE_COMM_SETTINGS_KEY); + if(!flipper_format_write_hex(ff, furi_string_get_cstr(key), (const uint8_t*)&data->comm, 1)) + break; + + furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_FILE_ACCESS_RIGHTS_KEY); + if(!flipper_format_write_hex( + ff, + furi_string_get_cstr(key), + (const uint8_t*)&data->access_rights, + sizeof(MfDesfireFileAccessRights))) + break; + + if(data->type == MfDesfireFileTypeStandard || data->type == MfDesfireFileTypeBackup) { + furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_FILE_SIZE_KEY); + if(!flipper_format_write_uint32(ff, furi_string_get_cstr(key), &data->data.size, 1)) + break; + + } else if(data->type == MfDesfireFileTypeValue) { + furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_FILE_HI_LIMIT_KEY); + if(!flipper_format_write_uint32( + ff, furi_string_get_cstr(key), &data->value.hi_limit, 1)) + break; + + furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_FILE_LO_LIMIT_KEY); + if(!flipper_format_write_uint32( + ff, furi_string_get_cstr(key), &data->value.lo_limit, 1)) + break; + + furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_FILE_LIMIT_CREDIT_VALUE_KEY); + if(!flipper_format_write_uint32( + ff, furi_string_get_cstr(key), &data->value.limited_credit_value, 1)) + break; + + furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_FILE_LIMIT_CREDIT_ENABLED_KEY); + if(!flipper_format_write_bool( + ff, furi_string_get_cstr(key), &data->value.limited_credit_enabled, 1)) + break; + } else if( + data->type == MfDesfireFileTypeLinearRecord || + data->type == MfDesfireFileTypeCyclicRecord) { + furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_FILE_SIZE_KEY); + if(!flipper_format_write_uint32(ff, furi_string_get_cstr(key), &data->record.size, 1)) + break; + + furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_FILE_MAX_KEY); + if(!flipper_format_write_uint32(ff, furi_string_get_cstr(key), &data->record.max, 1)) + break; + + furi_string_printf(key, "%s %s", prefix, MF_DESFIRE_FFF_FILE_CUR_KEY); + if(!flipper_format_write_uint32(ff, furi_string_get_cstr(key), &data->record.cur, 1)) + break; + } + + success = true; + } while(false); + + furi_string_free(key); + return success; +} + +bool mf_desfire_file_data_save( + const MfDesfireFileData* data, + const char* prefix, + FlipperFormat* ff) { + const uint32_t data_size = simple_array_get_count(data->data); + return data_size > 0 ? + flipper_format_write_hex(ff, prefix, simple_array_cget(data->data, 0), data_size) : + true; +} + +bool mf_desfire_application_count_save(const uint32_t* data, FlipperFormat* ff) { + return flipper_format_write_uint32(ff, MF_DESFIRE_FFF_APPLICATION_COUNT_KEY, data, 1); +} + +bool mf_desfire_application_ids_save( + const MfDesfireApplicationId* data, + uint32_t count, + FlipperFormat* ff) { + return flipper_format_write_hex( + ff, MF_DESFIRE_FFF_APPLICATION_IDS_KEY, data->data, count * sizeof(MfDesfireApplicationId)); +} + +bool mf_desfire_application_save( + const MfDesfireApplication* data, + const char* prefix, + FlipperFormat* ff) { + FuriString* sub_prefix = furi_string_alloc(); + bool success = false; + + do { + if(!mf_desfire_key_settings_save(&data->key_settings, prefix, ff)) break; + + const uint32_t key_version_count = data->key_settings.max_keys; + + uint32_t i; + for(i = 0; i < key_version_count; ++i) { + if(!mf_desfire_key_version_save( + simple_array_cget(data->key_versions, i), prefix, i, ff)) + break; + } + + if(i != key_version_count) break; + + const uint32_t file_count = simple_array_get_count(data->file_ids); + if(!mf_desfire_file_ids_save(simple_array_get(data->file_ids, 0), file_count, prefix, ff)) + break; + + for(i = 0; i < file_count; ++i) { + const MfDesfireFileId* file_id = simple_array_cget(data->file_ids, i); + furi_string_printf( + sub_prefix, "%s %s %u", prefix, MF_DESFIRE_FFF_FILE_SUB_PREFIX, *file_id); + + const MfDesfireFileSettings* file_settings = simple_array_cget(data->file_settings, i); + if(!mf_desfire_file_settings_save(file_settings, furi_string_get_cstr(sub_prefix), ff)) + break; + + const MfDesfireFileData* file_data = simple_array_cget(data->file_data, i); + if(!mf_desfire_file_data_save(file_data, furi_string_get_cstr(sub_prefix), ff)) break; + } + + if(i != file_count) break; + + success = true; + } while(false); + + furi_string_free(sub_prefix); + return success; +} + const SimpleArrayConfig mf_desfire_key_version_array_config = { .init = NULL, .copy = NULL, diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_i.h b/lib/nfc/protocols/mf_desfire/mf_desfire_i.h index 885b45d73254..9825a2cbf3fe 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_i.h +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_i.h @@ -2,6 +2,9 @@ #include "mf_desfire.h" +#define MF_DESFIRE_FFF_PICC_PREFIX "PICC" +#define MF_DESFIRE_FFF_APP_PREFIX "Application" + // SimpleArray configurations extern const SimpleArrayConfig mf_desfire_key_version_array_config; @@ -50,3 +53,89 @@ void mf_desfire_application_reset(MfDesfireApplication* data); void mf_desfire_file_data_copy(MfDesfireFileData* data, const MfDesfireFileData* other); void mf_desfire_application_copy(MfDesfireApplication* data, const MfDesfireApplication* other); + +// Load internal MfDesfire structures + +bool mf_desfire_version_load(MfDesfireVersion* data, FlipperFormat* ff); + +bool mf_desfire_free_memory_load(MfDesfireFreeMemory* data, FlipperFormat* ff); + +bool mf_desfire_key_settings_load( + MfDesfireKeySettings* data, + const char* prefix, + FlipperFormat* ff); + +bool mf_desfire_key_version_load( + MfDesfireKeyVersion* data, + const char* prefix, + uint32_t index, + FlipperFormat* ff); + +bool mf_desfire_file_count_load(uint32_t* data, const char* prefix, FlipperFormat* ff); + +bool mf_desfire_file_ids_load( + MfDesfireFileId* data, + uint32_t count, + const char* prefix, + FlipperFormat* ff); + +bool mf_desfire_file_settings_load( + MfDesfireFileSettings* data, + const char* prefix, + FlipperFormat* ff); + +bool mf_desfire_file_data_load(MfDesfireFileData* data, const char* prefix, FlipperFormat* ff); + +bool mf_desfire_application_count_load(uint32_t* data, FlipperFormat* ff); + +bool mf_desfire_application_ids_load( + MfDesfireApplicationId* data, + uint32_t count, + FlipperFormat* ff); + +bool mf_desfire_application_load(MfDesfireApplication* data, const char* prefix, FlipperFormat* ff); + +// Save internal MFDesfire structures + +bool mf_desfire_version_save(const MfDesfireVersion* data, FlipperFormat* ff); + +bool mf_desfire_free_memory_save(const MfDesfireFreeMemory* data, FlipperFormat* ff); + +bool mf_desfire_key_settings_save( + const MfDesfireKeySettings* data, + const char* prefix, + FlipperFormat* ff); + +bool mf_desfire_key_version_save( + const MfDesfireKeyVersion* data, + const char* prefix, + uint32_t index, + FlipperFormat* ff); + +bool mf_desfire_file_ids_save( + const MfDesfireFileId* data, + uint32_t count, + const char* prefix, + FlipperFormat* ff); + +bool mf_desfire_file_settings_save( + const MfDesfireFileSettings* data, + const char* prefix, + FlipperFormat* ff); + +bool mf_desfire_file_data_save( + const MfDesfireFileData* data, + const char* prefix, + FlipperFormat* ff); + +bool mf_desfire_application_count_save(const uint32_t* data, FlipperFormat* ff); + +bool mf_desfire_application_ids_save( + const MfDesfireApplicationId* data, + uint32_t count, + FlipperFormat* ff); + +bool mf_desfire_application_save( + const MfDesfireApplication* data, + const char* prefix, + FlipperFormat* ff); From 2641a2c33b1958b9dca01188ff16288e67c35190 Mon Sep 17 00:00:00 2001 From: gornekich Date: Wed, 5 Jul 2023 17:28:09 +0400 Subject: [PATCH 118/149] Unit tests, add manually scenes fixes (#2844) * nfc device: add is equal function * nfc data generators: rework with nfc_device * nfc: fix unit tests * nfc: implement add manually scenes * nfc: fix mfu and mfc copy functions * nfc: implement mfu and mfc is_equal function * linter: exclude compiled directory * firmware: format python sources --- applications/debug/unit_tests/nfc/nfc_test.c | 228 ++--- .../debug/unit_tests/nfc/nfc_transport.c | 197 ++-- .../main/nfc/scenes/nfc_scene_generate_info.c | 41 +- .../main/nfc/scenes/nfc_scene_set_atqa.c | 41 +- .../main/nfc/scenes/nfc_scene_set_sak.c | 42 +- .../main/nfc/scenes/nfc_scene_set_type.c | 52 +- .../main/nfc/scenes/nfc_scene_set_uid.c | 40 +- firmware.scons | 2 +- lib/nfc/helpers/nfc_data_generator.c | 883 +++++++++--------- lib/nfc/helpers/nfc_data_generator.h | 4 +- lib/nfc/nfc_device.c | 24 + lib/nfc/nfc_device.h | 4 + lib/nfc/protocols/iso14443_3a/iso14443_3a.h | 5 - lib/nfc/protocols/mf_classic/mf_classic.c | 40 +- .../protocols/mf_ultralight/mf_ultralight.c | 58 +- .../mf_ultralight/mf_ultralight_poller_i.h | 2 +- .../mf_ultralight_poller_sync_api.c | 7 +- .../{nfcb_poller_i .c => nfcb_poller_i.c} | 0 scripts/lint.py | 3 + 19 files changed, 877 insertions(+), 796 deletions(-) rename lib/nfc/protocols/nfcb/{nfcb_poller_i .c => nfcb_poller_i.c} (100%) diff --git a/applications/debug/unit_tests/nfc/nfc_test.c b/applications/debug/unit_tests/nfc/nfc_test.c index 0cb0898986bb..e5db6ccce7f9 100644 --- a/applications/debug/unit_tests/nfc/nfc_test.c +++ b/applications/debug/unit_tests/nfc/nfc_test.c @@ -2,14 +2,16 @@ #include #include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include -#include -#include -#include -#include #include "../minunit.h" @@ -42,61 +44,57 @@ static void nfc_test_free() { nfc_test = NULL; } -static void nfc_test_save_and_load(NfcDevData* data) { - NfcDevice* nfc_device = nfc_device_alloc(); - - NfcDevData* nfc_device_data_dut = malloc(sizeof(NfcDevData)); +static void nfc_test_save_and_load(NfcDevice* nfc_device_ref) { + NfcDevice* nfc_device_dut = nfc_device_alloc(); mu_assert( - nfc_device_save(nfc_device, data, NFC_TEST_NFC_DEV_PATH), "nfc_device_save() failed\r\n"); + nfc_device_save(nfc_device_ref, NFC_TEST_NFC_DEV_PATH), "nfc_device_save() failed\r\n"); mu_assert( - nfc_device_load(nfc_device, nfc_device_data_dut, NFC_TEST_NFC_DEV_PATH), - "nfc_device_load() failed\r\n"); + nfc_device_load(nfc_device_dut, NFC_TEST_NFC_DEV_PATH), "nfc_device_load() failed\r\n"); mu_assert( - memcmp(nfc_device_data_dut, data, sizeof(NfcDevData)) == 0, + nfc_device_is_equal(nfc_device_ref, nfc_device_dut), "nfc_device_data_dut != nfc_device_data_ref\r\n"); mu_assert( storage_simply_remove(nfc_test->storage, NFC_TEST_NFC_DEV_PATH), "storage_simply_remove() failed\r\n"); - free(nfc_device_data_dut); - nfc_device_free(nfc_device); + nfc_device_free(nfc_device_dut); } -static void nfca_file_test(uint8_t uid_len) { - NfcDevData* nfc_device_data_ref = malloc(sizeof(NfcDevData)); - mu_assert(nfc_device_data_ref != NULL, "malloc() failed\r\n"); - - NfcaData* data = &nfc_device_data_ref->nfca_data; +static void iso14443_3a_file_test(uint8_t uid_len) { + NfcDevice* nfc_device = nfc_device_alloc(); + Iso14443_3aData* data = iso14443_3a_alloc(); data->uid_len = uid_len; furi_hal_random_fill_buf(data->uid, uid_len); furi_hal_random_fill_buf(data->atqa, 2); furi_hal_random_fill_buf(&data->sak, 1); - nfc_test_save_and_load(nfc_device_data_ref); + nfc_device_set_data(nfc_device, NfcProtocolIso14443_3a, data); + nfc_test_save_and_load(nfc_device); - free(nfc_device_data_ref); + iso14443_3a_free(data); + nfc_device_free(nfc_device); } static void nfc_file_test_with_generator(NfcDataGeneratorType type) { - NfcDevData* nfc_device_data_ref = malloc(sizeof(NfcDevData)); + NfcDevice* nfc_device_ref = nfc_device_alloc(); - nfc_data_generator_fill_data(type, nfc_device_data_ref); - nfc_test_save_and_load(nfc_device_data_ref); + nfc_data_generator_fill_data(type, nfc_device_ref); + nfc_test_save_and_load(nfc_device_ref); - free(nfc_device_data_ref); + nfc_device_free(nfc_device_ref); } -MU_TEST(nfca_4b_file_test) { - nfca_file_test(4); +MU_TEST(iso14443_3a_4b_file_test) { + iso14443_3a_file_test(4); } -MU_TEST(nfca_7b_file_test) { - nfca_file_test(7); +MU_TEST(iso14443_3a_7b_file_test) { + iso14443_3a_file_test(7); } MU_TEST(mf_ultralight_file_test) { @@ -171,83 +169,64 @@ MU_TEST(mf_classic_4k_7b_file_test) { nfc_file_test_with_generator(NfcDataGeneratorTypeMfClassic4k_7b); } -MU_TEST(nfca_reader) { +MU_TEST(iso14443_3a_reader) { Nfc* poller = nfc_alloc(); Nfc* listener = nfc_alloc(); - NfcaPoller* nfca_poller = nfca_poller_alloc(poller); - NfcaListener* nfca_listener = nfca_listener_alloc(listener); - - NfcaData nfca_listener_data = { + Iso14443_3aData iso14443_3a_listener_data = { .uid_len = 7, .uid = {0x04, 0x51, 0x5C, 0xFA, 0x6F, 0x73, 0x81}, .atqa = {0x44, 0x00}, .sak = 0x00, }; - // nfca_listener_data.uid_len = 7; - // furi_hal_random_fill_buf(nfca_listener_data.uid, 7); - // furi_hal_random_fill_buf(nfca_listener_data.atqa, 2); - // furi_hal_random_fill_buf(&nfca_listener_data.sak, 1); - NfcaData nfca_poller_data = {}; + NfcListener* iso3_listener = + nfc_listener_alloc(listener, NfcProtocolIso14443_3a, &iso14443_3a_listener_data); + nfc_listener_start(iso3_listener, NULL, NULL); + Iso14443_3aData iso14443_3a_poller_data = {}; mu_assert( - nfca_listener_start(nfca_listener, &nfca_listener_data, NULL, NULL) == NfcaErrorNone, - "nfca_listener_start() failed"); + iso14443_3a_poller_read(poller, &iso14443_3a_poller_data) == Iso14443_3aErrorNone, + "iso14443_3a_poller_read() failed"); + nfc_listener_stop(iso3_listener); mu_assert( - nfca_poller_read(nfca_poller, &nfca_poller_data) == NfcaErrorNone, - "nfca_poller_read() failed"); - mu_assert(nfca_listener_stop(nfca_listener) == NfcaErrorNone, "nfca_listener_stop() failed"); - - mu_assert( - memcmp(&nfca_poller_data, &nfca_listener_data, sizeof(NfcaData)) == 0, "Data not matches"); + iso14443_3a_is_equal(&iso14443_3a_poller_data, &iso14443_3a_listener_data), + "Data not matches"); - nfca_listener_free(nfca_listener); + nfc_listener_free(iso3_listener); nfc_free(listener); - nfca_poller_free(nfca_poller); nfc_free(poller); } static void mf_ultralight_reader_test(const char* path) { FURI_LOG_I(TAG, "Testing file: %s", path); - NfcDevice* nfc_device = nfc_device_alloc(); Nfc* poller = nfc_alloc(); Nfc* listener = nfc_alloc(); - NfcaPoller* nfca_poller = nfca_poller_alloc(poller); - NfcaListener* nfca_listener = nfca_listener_alloc(listener); - - MfUltralightPoller* mfu_poller = mf_ultralight_poller_alloc(nfca_poller); - MfUltralightListener* mfu_listener = mf_ultralight_listener_alloc(nfca_listener); - - MfUltralightError error = MfUltralightErrorNone; - NfcDevData* dev_data = malloc(sizeof(NfcDevData)); - - mu_assert(nfc_device_load(nfc_device, dev_data, path), "nfc_device_load() failed\r\n"); + NfcDevice* nfc_device = nfc_device_alloc(); + mu_assert(nfc_device_load(nfc_device, path), "nfc_device_load() failed\r\n"); - error = mf_ultralight_listener_start(mfu_listener, &dev_data->mf_ul_data, NULL, NULL); - mu_assert(error == MfUltralightErrorNone, "mf_ultralight_listener_start() failed"); + NfcListener* mfu_listener = nfc_listener_alloc( + listener, + NfcProtocolMfUltralight, + nfc_device_get_data(nfc_device, NfcProtocolMfUltralight)); + nfc_listener_start(mfu_listener, NULL, NULL); - MfUltralightData* mfu_data = malloc(sizeof(MfUltralightData)); - error = mf_ultralight_poller_read_card(mfu_poller, mfu_data); + MfUltralightData* mfu_data = mf_ultralight_alloc(); + MfUltralightError error = mf_ultralight_poller_read_card(poller, mfu_data); mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_read_card() failed"); - error = mf_ultralight_listener_stop(mfu_listener); - mu_assert(error == MfUltralightErrorNone, "mf_ultralight_listener_stop() failed"); + nfc_listener_stop(mfu_listener); + nfc_listener_free(mfu_listener); mu_assert( - memcmp(mfu_data, &dev_data->mf_ul_data, sizeof(MfUltralightData)) == 0, + mf_ultralight_is_equal(mfu_data, nfc_device_get_data(nfc_device, NfcProtocolMfUltralight)), "Data not matches"); - free(mfu_data); - free(dev_data); - mf_ultralight_listener_free(mfu_listener); - mf_ultralight_poller_free(mfu_poller); - nfca_listener_free(nfca_listener); + mf_ultralight_free(mfu_data); + nfc_device_free(nfc_device); nfc_free(listener); - nfca_poller_free(nfca_poller); nfc_free(poller); - nfc_device_free(nfc_device); } MU_TEST(mf_ultralight_11_reader) { @@ -268,78 +247,64 @@ MU_TEST(ntag_216_reader) { MU_TEST(ntag_213_locked_reader) { FURI_LOG_I(TAG, "Testing Ntag215 locked file"); - NfcDevice* nfc_device = nfc_device_alloc(); Nfc* poller = nfc_alloc(); Nfc* listener = nfc_alloc(); - NfcaPoller* nfca_poller = nfca_poller_alloc(poller); - NfcaListener* nfca_listener = nfca_listener_alloc(listener); - - MfUltralightPoller* mfu_poller = mf_ultralight_poller_alloc(nfca_poller); - MfUltralightListener* mfu_listener = mf_ultralight_listener_alloc(nfca_listener); - - MfUltralightError error = MfUltralightErrorNone; - NfcDevData* dev_data = malloc(sizeof(NfcDevData)); - + NfcDeviceData* nfc_device = nfc_device_alloc(); mu_assert( - nfc_device_load(nfc_device, dev_data, EXT_PATH("unit_tests/nfc/Ntag213_locked.nfc")), + nfc_device_load(nfc_device, EXT_PATH("unit_tests/nfc/Ntag213_locked.nfc")), "nfc_device_load() failed\r\n"); - error = mf_ultralight_listener_start(mfu_listener, &dev_data->mf_ul_data, NULL, NULL); - mu_assert(error == MfUltralightErrorNone, "mf_ultralight_listener_start() failed"); + NfcListener* mfu_listener = nfc_listener_alloc( + listener, + NfcProtocolMfUltralight, + nfc_device_get_data(nfc_device, NfcProtocolMfUltralight)); + nfc_listener_start(mfu_listener, NULL, NULL); - MfUltralightData* mfu_data = malloc(sizeof(MfUltralightData)); - error = mf_ultralight_poller_read_card(mfu_poller, mfu_data); + MfUltralightData* mfu_data = mf_ultralight_alloc(); + MfUltralightError error = mf_ultralight_poller_read_card(poller, mfu_data); mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_read_card() failed"); - error = mf_ultralight_listener_stop(mfu_listener); - mu_assert(error == MfUltralightErrorNone, "mf_ultralight_listener_stop() failed"); + nfc_listener_stop(mfu_listener); + nfc_listener_free(mfu_listener); MfUltralightConfigPages* config = NULL; + const MfUltralightData* mfu_ref_data = + nfc_device_get_data(nfc_device, NfcProtocolMfUltralight); mu_assert( - mf_ultralight_get_config_page(&dev_data->mf_ul_data, &config), + mf_ultralight_get_config_page(mfu_ref_data, &config), "mf_ultralight_get_config_page() failed"); uint16_t pages_locked = config->auth0; mu_assert(mfu_data->pages_read == pages_locked, "Unexpected pages read"); - free(mfu_data); - free(dev_data); - mf_ultralight_listener_free(mfu_listener); - mf_ultralight_poller_free(mfu_poller); - nfca_listener_free(nfca_listener); + mf_ultralight_free(mfu_data); + nfc_device_free(nfc_device); nfc_free(listener); - nfca_poller_free(nfca_poller); nfc_free(poller); - nfc_device_free(nfc_device); } static void mf_ultralight_write() { - NfcDevice* nfc_device = nfc_device_alloc(); Nfc* poller = nfc_alloc(); Nfc* listener = nfc_alloc(); - NfcaPoller* nfca_poller = nfca_poller_alloc(poller); - NfcaListener* nfca_listener = nfca_listener_alloc(listener); - - MfUltralightPoller* mfu_poller = mf_ultralight_poller_alloc(nfca_poller); - MfUltralightListener* mfu_listener = mf_ultralight_listener_alloc(nfca_listener); - - MfUltralightError error = MfUltralightErrorNone; - NfcDevData* dev_data = malloc(sizeof(NfcDevData)); - nfc_data_generator_fill_data(NfcDataGeneratorTypeMfUltralightEV1_21, dev_data); + NfcDevice* nfc_device = nfc_device_alloc(); + nfc_data_generator_fill_data(NfcDataGeneratorTypeMfUltralightEV1_21, nfc_device); - error = mf_ultralight_listener_start(mfu_listener, &dev_data->mf_ul_data, NULL, NULL); - mu_assert(error == MfUltralightErrorNone, "mf_ultralight_listener_start() failed"); + NfcListener* mfu_listener = nfc_listener_alloc( + listener, + NfcProtocolMfUltralight, + nfc_device_get_data(nfc_device, NfcProtocolMfUltralight)); + nfc_listener_start(mfu_listener, NULL, NULL); - MfUltralightData* mfu_data = malloc(sizeof(MfUltralightData)); + MfUltralightData* mfu_data = mf_ultralight_alloc(); // Initial read - error = mf_ultralight_poller_read_card(mfu_poller, mfu_data); + MfUltralightError error = mf_ultralight_poller_read_card(poller, mfu_data); mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_read_card() failed"); mu_assert( - memcmp(mfu_data, &dev_data->mf_ul_data, sizeof(MfUltralightData)) == 0, + mf_ultralight_is_equal(mfu_data, nfc_device_get_data(nfc_device, NfcProtocolMfUltralight)), "Data not matches"); // Write random data @@ -348,38 +313,31 @@ static void mf_ultralight_write() { FURI_LOG_D(TAG, "Writing page %d", i); furi_hal_random_fill_buf(page.data, sizeof(MfUltralightPage)); mfu_data->page[i] = page; - error = mf_ultralight_poller_write_page(mfu_poller, i, &page); + error = mf_ultralight_poller_write_page(poller, i, &page); mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_read_card() failed"); } // Verification read - error = mf_ultralight_poller_read_card(mfu_poller, mfu_data); + error = mf_ultralight_poller_read_card(poller, mfu_data); mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_read_card() failed"); - mf_ultralight_listener_get_data(mfu_listener, &dev_data->mf_ul_data); - error = mf_ultralight_listener_stop(mfu_listener); - - mu_assert(error == MfUltralightErrorNone, "mf_ultralight_listener_stop() failed"); + nfc_listener_stop(mfu_listener); + const MfUltralightData* mfu_listener_data = + nfc_listener_get_data(mfu_listener, NfcProtocolMfUltralight); - mu_assert( - memcmp(mfu_data, &dev_data->mf_ul_data, sizeof(MfUltralightData)) == 0, - "Data not matches"); + mu_assert(mf_ultralight_is_equal(mfu_data, mfu_listener_data), "Data not matches"); - free(mfu_data); - free(dev_data); - mf_ultralight_listener_free(mfu_listener); - mf_ultralight_poller_free(mfu_poller); - nfca_listener_free(nfca_listener); + nfc_listener_free(mfu_listener); + mf_ultralight_free(mfu_data); + nfc_device_free(nfc_device); nfc_free(listener); - nfca_poller_free(nfca_poller); nfc_free(poller); - nfc_device_free(nfc_device); } MU_TEST_SUITE(nfc) { nfc_test_alloc(); - MU_RUN_TEST(nfca_reader); + MU_RUN_TEST(iso14443_3a_reader); MU_RUN_TEST(mf_ultralight_11_reader); MU_RUN_TEST(mf_ultralight_21_reader); MU_RUN_TEST(ntag_215_reader); @@ -388,8 +346,8 @@ MU_TEST_SUITE(nfc) { MU_RUN_TEST(mf_ultralight_write); - MU_RUN_TEST(nfca_4b_file_test); - MU_RUN_TEST(nfca_7b_file_test); + MU_RUN_TEST(iso14443_3a_4b_file_test); + MU_RUN_TEST(iso14443_3a_7b_file_test); MU_RUN_TEST(mf_ultralight_file_test); MU_RUN_TEST(mf_ultralight_ev1_11_file_test); diff --git a/applications/debug/unit_tests/nfc/nfc_transport.c b/applications/debug/unit_tests/nfc/nfc_transport.c index ed582576b5f4..fe87dd204bd5 100644 --- a/applications/debug/unit_tests/nfc/nfc_transport.c +++ b/applications/debug/unit_tests/nfc/nfc_transport.c @@ -1,11 +1,11 @@ #ifdef APP_UNIT_TESTS #include -#include +#include #include -#define NFC_MAX_DATA_SIZE (128) +#define NFC_MAX_BUFFER_SIZE (256) typedef enum { NfcTransportLogLevelWarning, @@ -23,7 +23,7 @@ typedef enum { typedef struct { uint16_t data_bits; - uint8_t data[NFC_MAX_DATA_SIZE]; + uint8_t data[NFC_MAX_BUFFER_SIZE]; } NfcMessageData; typedef struct { @@ -33,28 +33,27 @@ typedef struct { typedef enum { NfcStateIdle, - NfcStateStarted, NfcStateReady, NfcStateReset, } NfcState; typedef enum { - NfcaColResStatusIdle, - NfcaColResStatusInProgress, - NfcaColResStatusDone, -} NfcaColResStatus; + Iso14443_3aColResStatusIdle, + Iso14443_3aColResStatusInProgress, + Iso14443_3aColResStatusDone, +} Iso14443_3aColResStatus; typedef struct { - NfcaSensResp sens_resp; - NfcaSddResp sdd_resp[2]; - NfcaSelResp sel_resp[2]; -} NfcaColResData; + Iso14443_3aSensResp sens_resp; + Iso14443_3aSddResp sdd_resp[2]; + Iso14443_3aSelResp sel_resp[2]; +} Iso14443_3aColResData; struct Nfc { NfcState state; - NfcaColResStatus col_res_status; - NfcaColResData col_res_data; + Iso14443_3aColResStatus col_res_status; + Iso14443_3aColResData col_res_data; NfcEventCallback callback; void* context; @@ -174,27 +173,15 @@ static int32_t nfc_worker_poller(void* context) { Nfc* instance = context; furi_assert(instance->callback); - instance->state = NfcStateStarted; + instance->state = NfcStateReady; NfcCommand command = NfcCommandContinue; NfcEvent event = {}; while(true) { - if(instance->state == NfcStateStarted) { - event.type = NfcEventTypeConfigureRequest; - instance->callback(event, instance->context); - instance->state = NfcStateReady; - } else if(instance->state == NfcStateReady) { - event.type = NfcEventTypePollerReady; - command = instance->callback(event, instance->context); - if(command == NfcCommandReset) { - event.type = NfcEventTypeReset; - instance->callback(event, instance->context); - instance->state = NfcStateStarted; - } else if(command == NfcCommandStop) { - event.type = NfcEventTypeReset; - instance->callback(event, instance->context); - break; - } + event.type = NfcEventTypePollerReady; + command = instance->callback(event, instance->context); + if(command == NfcCommandStop) { + break; } } @@ -226,36 +213,48 @@ void nfc_start_poller(Nfc* instance, NfcEventCallback callback, void* context) { } static void nfc_worker_listener_pass_col_res(Nfc* instance, uint8_t* rx_data, uint16_t rx_bits) { - furi_assert(instance->col_res_status != NfcaColResStatusDone); + furi_assert(instance->col_res_status != Iso14443_3aColResStatusDone); + BitBuffer* tx_buffer = bit_buffer_alloc(NFC_MAX_BUFFER_SIZE); bool processed = false; if((rx_bits == 7) && (rx_data[0] == 0x52)) { - instance->col_res_status = NfcaColResStatusInProgress; - nfc_listener_tx(instance, instance->col_res_data.sens_resp.sens_resp, 16); + instance->col_res_status = Iso14443_3aColResStatusInProgress; + bit_buffer_copy_bytes( + tx_buffer, + instance->col_res_data.sens_resp.sens_resp, + sizeof(instance->col_res_data.sens_resp.sens_resp)); + nfc_listener_tx(instance, tx_buffer); processed = true; } else if(rx_bits == 2 * 8) { if((rx_data[0] == 0x93) && (rx_data[1] == 0x20)) { - nfc_listener_tx( - instance, (uint8_t*)&instance->col_res_data.sdd_resp[0], sizeof(NfcaSddResp) * 8); + bit_buffer_copy_bytes( + tx_buffer, + (const uint8_t*)&instance->col_res_data.sdd_resp[0], + sizeof(Iso14443_3aSddResp)); + nfc_listener_tx(instance, tx_buffer); processed = true; } else if((rx_data[0] == 0x95) && (rx_data[1] == 0x20)) { - nfc_listener_tx( - instance, (uint8_t*)&instance->col_res_data.sdd_resp[1], sizeof(NfcaSddResp) * 8); + bit_buffer_copy_bytes( + tx_buffer, + (const uint8_t*)&instance->col_res_data.sdd_resp[1], + sizeof(Iso14443_3aSddResp)); + nfc_listener_tx(instance, tx_buffer); processed = true; } } else if(rx_bits == 9 * 8) { if((rx_data[0] == 0x93) && (rx_data[1] == 0x70)) { - uint8_t sak_with_crc[3] = {instance->col_res_data.sel_resp[0].sak}; - nfca_append_crc(sak_with_crc, 1); - nfc_listener_tx(instance, sak_with_crc, 3 * 8); + bit_buffer_set_size_bytes(tx_buffer, 1); + bit_buffer_set_byte(tx_buffer, 0, instance->col_res_data.sel_resp[0].sak); + iso14443_3a_append_crc(tx_buffer); + nfc_listener_tx(instance, tx_buffer); processed = true; } else if((rx_data[0] == 0x95) && (rx_data[1] == 0x70)) { - uint8_t sak_with_crc[3] = {instance->col_res_data.sel_resp[1].sak}; - nfca_append_crc(sak_with_crc, 1); - nfc_listener_tx(instance, sak_with_crc, 3 * 8); - - instance->col_res_status = NfcaColResStatusDone; + bit_buffer_set_size_bytes(tx_buffer, 1); + bit_buffer_set_byte(tx_buffer, 0, instance->col_res_data.sel_resp[1].sak); + iso14443_3a_append_crc(tx_buffer); + nfc_listener_tx(instance, tx_buffer); + instance->col_res_status = Iso14443_3aColResStatusDone; NfcEvent event = {.type = NfcEventTypeListenerActivated}; instance->callback(event, instance->context); @@ -267,52 +266,47 @@ static void nfc_worker_listener_pass_col_res(Nfc* instance, uint8_t* rx_data, ui NfcMessage message = {.type = NfcMessageTypeTimeout}; furi_message_queue_put(poller_queue, &message, FuriWaitForever); } + + bit_buffer_free(tx_buffer); } static int32_t nfc_worker_listener(void* context) { Nfc* instance = context; furi_assert(instance->callback); - instance->state = NfcStateStarted; - NfcEvent event = {}; NfcMessage message = {}; - uint8_t* rx_data = malloc(NFC_MAX_DATA_SIZE); - - event.type = NfcEventTypeConfigureRequest; - instance->callback(event, instance->context); + NfcEventData event_data = {}; + event_data.buffer = bit_buffer_alloc(NFC_MAX_BUFFER_SIZE); + NfcEvent nfc_event = {.data = event_data}; while(true) { furi_message_queue_get(listener_queue, &message, FuriWaitForever); + bit_buffer_copy_bits(event_data.buffer, message.data.data, message.data.data_bits); + if((message.data.data[0] == 0x52) && (message.data.data_bits == 7)) { + instance->col_res_status = Iso14443_3aColResStatusIdle; + } + if(message.type == NfcMessageTypeAbort) { - event.type = NfcEventTypeUserAbort; - instance->callback(event, instance->context); break; } else if(message.type == NfcMessageTypeTx) { nfc_test_print( NfcTransportLogLevelInfo, "RDR", message.data.data, message.data.data_bits); - if(instance->col_res_status != NfcaColResStatusDone) { + if(instance->col_res_status != Iso14443_3aColResStatusDone) { nfc_worker_listener_pass_col_res( instance, message.data.data, message.data.data_bits); } else { instance->state = NfcStateReady; - event.type = NfcEventTypeRxEnd; - memcpy(rx_data, message.data.data, (message.data.data_bits + 7) / 8); - event.data.rx_data = rx_data; - event.data.rx_bits = message.data.data_bits; - instance->callback(event, instance->context); + nfc_event.type = NfcEventTypeRxEnd; + instance->callback(nfc_event, instance->context); } } } - event.type = NfcEventTypeReset; - instance->callback(event, instance->context); - instance->state = NfcStateIdle; - instance->col_res_status = NfcaColResStatusIdle; + instance->col_res_status = Iso14443_3aColResStatusIdle; memset(&instance->col_res_data, 0, sizeof(instance->col_res_data)); - - free(rx_data); + bit_buffer_free(nfc_event.data.buffer); return 0; } @@ -343,7 +337,7 @@ NfcError nfc_listener_sleep(Nfc* instance) { furi_assert(instance); furi_assert(poller_queue); - instance->col_res_status = NfcaColResStatusIdle; + instance->col_res_status = Iso14443_3aColResStatusIdle; NfcMessage message = {.type = NfcMessageTypeTimeout}; furi_message_queue_put(poller_queue, &message, FuriWaitForever); @@ -380,56 +374,45 @@ void nfc_stop(Nfc* instance) { // Called from worker thread -NfcError nfc_listener_tx(Nfc* instance, uint8_t* tx_data, uint16_t tx_bits) { +NfcError nfc_listener_tx(Nfc* instance, const BitBuffer* tx_buffer) { furi_assert(instance); furi_assert(poller_queue); furi_assert(listener_queue); - furi_assert(tx_data); - furi_assert(tx_bits / 8 < NFC_MAX_DATA_SIZE); + furi_assert(tx_buffer); NfcMessage message = {}; message.type = NfcMessageTypeTx; - message.data.data_bits = tx_bits; - memcpy(message.data.data, tx_data, (tx_bits + 7) / 8); + message.data.data_bits = bit_buffer_get_size(tx_buffer); + bit_buffer_write_bytes(tx_buffer, message.data.data, bit_buffer_get_size_bytes(tx_buffer)); furi_message_queue_put(poller_queue, &message, FuriWaitForever); return NfcErrorNone; } -NfcError nfc_trx( - Nfc* instance, - uint8_t* tx_data, - uint16_t tx_bits, - uint8_t* rx_data, - uint16_t rx_data_size, - uint16_t* rx_bits, - uint32_t fwt) { +NfcError nfc_trx(Nfc* instance, const BitBuffer* tx_buffer, BitBuffer* rx_buffer, uint32_t fwt) { furi_assert(instance); - furi_assert(tx_data); - furi_assert(rx_data); - furi_assert(rx_bits); + furi_assert(tx_buffer); + furi_assert(rx_buffer); furi_assert(poller_queue); furi_assert(listener_queue); - furi_assert(tx_bits / 8 < NFC_MAX_DATA_SIZE); UNUSED(fwt); NfcError error = NfcErrorNone; NfcMessage message = {}; message.type = NfcMessageTypeTx; - message.data.data_bits = tx_bits; - memcpy(message.data.data, tx_data, (tx_bits + 7) / 8); + message.data.data_bits = bit_buffer_get_size(tx_buffer); + bit_buffer_write_bytes(tx_buffer, message.data.data, bit_buffer_get_size_bytes(tx_buffer)); // Tx furi_assert(furi_message_queue_put(listener_queue, &message, FuriWaitForever) == FuriStatusOk); // Rx furi_assert(furi_message_queue_get(poller_queue, &message, FuriWaitForever) == FuriStatusOk); if(message.type == NfcMessageTypeTx) { - furi_assert(message.data.data_bits / 8 <= rx_data_size); - *rx_bits = message.data.data_bits; - memcpy(rx_data, message.data.data, (message.data.data_bits + 7) / 8); - nfc_test_print(NfcTransportLogLevelWarning, "TAG", rx_data, *rx_bits); + bit_buffer_copy_bits(rx_buffer, message.data.data, message.data.data_bits); + nfc_test_print( + NfcTransportLogLevelWarning, "TAG", message.data.data, message.data.data_bits); } else if(message.type == NfcMessageTypeTimeout) { error = NfcErrorTimeout; } @@ -437,32 +420,40 @@ NfcError nfc_trx( return error; } +NfcError nfc_trx_custom_parity( + Nfc* instance, + const BitBuffer* tx_buffer, + BitBuffer* rx_buffer, + uint32_t fwt) { + return nfc_trx(instance, tx_buffer, rx_buffer, fwt); +} + // Technology specific API NfcError nfc_iso13444a_short_frame( Nfc* instance, NfcIso14443aShortFrame frame, - uint8_t* rx_data, - uint16_t rx_data_size, - uint16_t* rx_bits, + BitBuffer* rx_buffer, uint32_t fwt) { UNUSED(frame); - uint8_t tx_data[1] = {0x52}; - uint16_t tx_bits = 7; + BitBuffer* tx_buffer = bit_buffer_alloc(32); + bit_buffer_set_size(tx_buffer, 7); + bit_buffer_set_byte(tx_buffer, 0, 0x52); + + NfcError error = nfc_trx(instance, tx_buffer, rx_buffer, fwt); - return nfc_trx(instance, tx_data, tx_bits, rx_data, rx_data_size, rx_bits, fwt); + bit_buffer_free(tx_buffer); + + return error; } NfcError nfc_iso13444a_sdd_frame( Nfc* instance, - uint8_t* tx_data, - uint16_t tx_bits, - uint8_t* rx_data, - uint16_t rx_data_size, - uint16_t* rx_bits, + const BitBuffer* tx_buffer, + BitBuffer* rx_buffer, uint32_t fwt) { - return nfc_trx(instance, tx_data, tx_bits, rx_data, rx_data_size, rx_bits, fwt); + return nfc_trx(instance, tx_buffer, rx_buffer, fwt); } -#endif \ No newline at end of file +#endif diff --git a/applications/main/nfc/scenes/nfc_scene_generate_info.c b/applications/main/nfc/scenes/nfc_scene_generate_info.c index 20cd9c4aac9a..1e6db818fd94 100644 --- a/applications/main/nfc/scenes/nfc_scene_generate_info.c +++ b/applications/main/nfc/scenes/nfc_scene_generate_info.c @@ -1,36 +1,32 @@ #include "../nfc_app_i.h" void nfc_scene_generate_info_widget_callback(GuiButtonType result, InputType type, void* context) { - NfcApp* nfc = context; + NfcApp* instance = context; if(type == InputTypeShort) { if(result == GuiButtonTypeRight) { - view_dispatcher_send_custom_event(nfc->view_dispatcher, result); + view_dispatcher_send_custom_event(instance->view_dispatcher, result); } } } void nfc_scene_generate_info_on_enter(void* context) { - NfcApp* nfc = context; + NfcApp* instance = context; - Iso14443_3aData* iso14443_3a_data = NULL; - if(nfc_device_get_protocol(nfc->nfc_device) == NfcProtocolMfUltralight) { - const MfUltralightData* mfu_data = - nfc_device_get_data(nfc->nfc_device, NfcProtocolMfUltralight); - iso14443_3a_data = mfu_data->iso14443_3a_data; - } else { - // TODO add Mf Classic - furi_crash("Not supported protocol"); - } + NfcProtocol protocol = nfc_device_get_protocol(instance->nfc_device); + furi_assert((protocol == NfcProtocolMfUltralight) || (protocol == NfcProtocolMfClassic)); + + const Iso14443_3aData* iso14443_3a_data = + nfc_device_get_base_data(instance->nfc_device, protocol); // Setup dialog view - Widget* widget = nfc->widget; + Widget* widget = instance->widget; widget_add_button_element( - widget, GuiButtonTypeRight, "More", nfc_scene_generate_info_widget_callback, nfc); + widget, GuiButtonTypeRight, "More", nfc_scene_generate_info_widget_callback, instance); // Create info text NfcDataGeneratorType type = - scene_manager_get_scene_state(nfc->scene_manager, NfcSceneGenerateInfo); + scene_manager_get_scene_state(instance->scene_manager, NfcSceneGenerateInfo); const char* name = nfc_data_generator_get_name(type); widget_add_string_element(widget, 0, 0, AlignLeft, AlignTop, FontPrimary, name); widget_add_string_element(widget, 0, 13, AlignLeft, AlignTop, FontSecondary, "NFC-A"); @@ -44,21 +40,16 @@ void nfc_scene_generate_info_on_enter(void* context) { widget, 0, 25, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(temp_str)); furi_string_free(temp_str); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewWidget); } bool nfc_scene_generate_info_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + NfcApp* instance = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { if(event.event == GuiButtonTypeRight) { - // Switch either to NfcSceneMfClassicMenu or NfcSceneMfUltralightMenu - if(nfc_device_get_protocol(nfc->nfc_device) == NfcProtocolMfUltralight) { - // scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightMenu); - } else { - // TODO add classic - } + scene_manager_next_scene(instance->scene_manager, NfcSceneReadMenu); consumed = true; } } @@ -67,8 +58,8 @@ bool nfc_scene_generate_info_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_generate_info_on_exit(void* context) { - NfcApp* nfc = context; + NfcApp* instance = context; // Clean views - widget_reset(nfc->widget); + widget_reset(instance->widget); } diff --git a/applications/main/nfc/scenes/nfc_scene_set_atqa.c b/applications/main/nfc/scenes/nfc_scene_set_atqa.c index ffc0035b7822..f0b399b2c765 100644 --- a/applications/main/nfc/scenes/nfc_scene_set_atqa.c +++ b/applications/main/nfc/scenes/nfc_scene_set_atqa.c @@ -1,35 +1,34 @@ #include "../nfc_app_i.h" -// FIXME: Make it work -// void nfc_scene_set_atqa_byte_input_callback(void* context) { -// NfcApp* nfc = context; -// -// view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); -// } +void nfc_scene_set_atqa_byte_input_callback(void* context) { + NfcApp* instance = context; + + view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventByteInputDone); +} void nfc_scene_set_atqa_on_enter(void* context) { - NfcApp* nfc = context; + NfcApp* instance = context; // Setup view - ByteInput* byte_input = nfc->byte_input; + ByteInput* byte_input = instance->byte_input; byte_input_set_header_text(byte_input, "Enter ATQA in hex"); - // byte_input_set_result_callback( - // byte_input, - // nfc_scene_set_atqa_byte_input_callback, - // NULL, - // nfc, - // nfc->nfc_dev_data.nfca_data->atqa, - // 2); - // view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewByteInput); + byte_input_set_result_callback( + byte_input, + nfc_scene_set_atqa_byte_input_callback, + NULL, + instance, + instance->iso14443_3a_edit_data->atqa, + 2); + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewByteInput); } bool nfc_scene_set_atqa_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + NfcApp* instance = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { if(event.event == NfcCustomEventByteInputDone) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneSetUid); + scene_manager_next_scene(instance->scene_manager, NfcSceneSetUid); consumed = true; } } @@ -37,9 +36,9 @@ bool nfc_scene_set_atqa_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_set_atqa_on_exit(void* context) { - NfcApp* nfc = context; + NfcApp* instance = context; // Clear view - byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0); - byte_input_set_header_text(nfc->byte_input, ""); + byte_input_set_result_callback(instance->byte_input, NULL, NULL, NULL, NULL, 0); + byte_input_set_header_text(instance->byte_input, ""); } diff --git a/applications/main/nfc/scenes/nfc_scene_set_sak.c b/applications/main/nfc/scenes/nfc_scene_set_sak.c index cfeaa5167e26..9968e3b1c6a8 100644 --- a/applications/main/nfc/scenes/nfc_scene_set_sak.c +++ b/applications/main/nfc/scenes/nfc_scene_set_sak.c @@ -1,45 +1,45 @@ #include "../nfc_app_i.h" -// FIXME: Make this work -// void nfc_scene_set_sak_byte_input_callback(void* context) { -// NfcApp* nfc = context; -// -// view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); -// } +void nfc_scene_set_sak_byte_input_callback(void* context) { + NfcApp* instance = context; + + view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventByteInputDone); +} void nfc_scene_set_sak_on_enter(void* context) { - NfcApp* nfc = context; + NfcApp* instance = context; // Setup view - ByteInput* byte_input = nfc->byte_input; + ByteInput* byte_input = instance->byte_input; byte_input_set_header_text(byte_input, "Enter SAK in hex"); - // byte_input_set_result_callback( - // byte_input, - // nfc_scene_set_sak_byte_input_callback, - // NULL, - // nfc, - // &nfc->nfc_dev_data.nfca_data->sak, - // 1); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewByteInput); + byte_input_set_result_callback( + byte_input, + nfc_scene_set_sak_byte_input_callback, + NULL, + instance, + &instance->iso14443_3a_edit_data->sak, + 1); + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewByteInput); } bool nfc_scene_set_sak_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + NfcApp* instance = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { if(event.event == NfcCustomEventByteInputDone) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneSetAtqa); + scene_manager_next_scene(instance->scene_manager, NfcSceneSetAtqa); consumed = true; } } + return consumed; } void nfc_scene_set_sak_on_exit(void* context) { - NfcApp* nfc = context; + NfcApp* instance = context; // Clear view - byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0); - byte_input_set_header_text(nfc->byte_input, ""); + byte_input_set_result_callback(instance->byte_input, NULL, NULL, NULL, NULL, 0); + byte_input_set_header_text(instance->byte_input, ""); } diff --git a/applications/main/nfc/scenes/nfc_scene_set_type.c b/applications/main/nfc/scenes/nfc_scene_set_type.c index 3a9fd755fccc..f50299578568 100644 --- a/applications/main/nfc/scenes/nfc_scene_set_type.c +++ b/applications/main/nfc/scenes/nfc_scene_set_type.c @@ -7,57 +7,65 @@ enum SubmenuIndex { }; void nfc_scene_set_type_submenu_callback(void* context, uint32_t index) { - NfcApp* nfc = context; + NfcApp* instance = context; - view_dispatcher_send_custom_event(nfc->view_dispatcher, index); + view_dispatcher_send_custom_event(instance->view_dispatcher, index); } void nfc_scene_set_type_on_enter(void* context) { - NfcApp* nfc = context; - Submenu* submenu = nfc->submenu; + NfcApp* instance = context; + + Submenu* submenu = instance->submenu; // Clear device name - furi_string_reset(nfc->file_name); + furi_string_reset(instance->file_name); submenu_add_item( - submenu, "NFC-A 7-bytes UID", SubmenuIndexNFCA7, nfc_scene_set_type_submenu_callback, nfc); + submenu, + "NFC-A 7-bytes UID", + SubmenuIndexNFCA7, + nfc_scene_set_type_submenu_callback, + instance); submenu_add_item( - submenu, "NFC-A 4-bytes UID", SubmenuIndexNFCA4, nfc_scene_set_type_submenu_callback, nfc); + submenu, + "NFC-A 4-bytes UID", + SubmenuIndexNFCA4, + nfc_scene_set_type_submenu_callback, + instance); for(size_t i = 0; i < NfcDataGeneratorTypeNum; i++) { const char* name = nfc_data_generator_get_name(i); - submenu_add_item(submenu, name, i, nfc_scene_set_type_submenu_callback, nfc); + submenu_add_item(submenu, name, i, nfc_scene_set_type_submenu_callback, instance); } - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewMenu); } bool nfc_scene_set_type_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + NfcApp* instance = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubmenuIndexNFCA7) { - // FIXME: Make this work - // nfc->nfc_dev_data.protocol = NfcDevProtocolNfca; - // nfc->nfc_dev_data.nfca_data->uid_len = 7; - scene_manager_next_scene(nfc->scene_manager, NfcSceneSetSak); + instance->iso14443_3a_edit_data->uid_len = 7; + scene_manager_next_scene(instance->scene_manager, NfcSceneSetSak); consumed = true; } else if(event.event == SubmenuIndexNFCA4) { - // nfc->nfc_dev_data.protocol = NfcDevProtocolNfca; - // nfc->nfc_dev_data.nfca_data->uid_len = 4; - scene_manager_next_scene(nfc->scene_manager, NfcSceneSetSak); + instance->iso14443_3a_edit_data->uid_len = 4; + scene_manager_next_scene(instance->scene_manager, NfcSceneSetSak); consumed = true; } else { - // nfc_data_generator_fill_data(event.event, &nfc->nfc_dev_data); - scene_manager_set_scene_state(nfc->scene_manager, NfcSceneGenerateInfo, event.event); - scene_manager_next_scene(nfc->scene_manager, NfcSceneGenerateInfo); + nfc_data_generator_fill_data(event.event, instance->nfc_device); + scene_manager_set_scene_state( + instance->scene_manager, NfcSceneGenerateInfo, event.event); + scene_manager_next_scene(instance->scene_manager, NfcSceneGenerateInfo); consumed = true; } } + return consumed; } void nfc_scene_set_type_on_exit(void* context) { - NfcApp* nfc = context; + NfcApp* instance = context; - submenu_reset(nfc->submenu); + submenu_reset(instance->submenu); } diff --git a/applications/main/nfc/scenes/nfc_scene_set_uid.c b/applications/main/nfc/scenes/nfc_scene_set_uid.c index 4d45432d7901..ea10baf79a23 100644 --- a/applications/main/nfc/scenes/nfc_scene_set_uid.c +++ b/applications/main/nfc/scenes/nfc_scene_set_uid.c @@ -1,43 +1,47 @@ #include "../nfc_app_i.h" void nfc_scene_set_uid_byte_input_callback(void* context) { - NfcApp* nfc = context; + NfcApp* instance = context; - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); + view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventByteInputDone); } void nfc_scene_set_uid_on_enter(void* context) { - NfcApp* nfc = context; + NfcApp* instance = context; + + if(scene_manager_has_previous_scene(instance->scene_manager, NfcSceneSavedMenu)) { + nfc_device_copy_data( + instance->nfc_device, NfcProtocolIso14443_3a, instance->iso14443_3a_edit_data); + } // Setup view - ByteInput* byte_input = nfc->byte_input; + ByteInput* byte_input = instance->byte_input; byte_input_set_header_text(byte_input, "Enter UID in hex"); - nfc_device_copy_data(nfc->nfc_device, NfcProtocolIso14443_3a, nfc->iso14443_3a_edit_data); byte_input_set_result_callback( byte_input, nfc_scene_set_uid_byte_input_callback, NULL, - nfc, - nfc->iso14443_3a_edit_data->uid, - nfc->iso14443_3a_edit_data->uid_len); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewByteInput); + instance, + instance->iso14443_3a_edit_data->uid, + instance->iso14443_3a_edit_data->uid_len); + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewByteInput); } bool nfc_scene_set_uid_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + NfcApp* instance = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { if(event.event == NfcCustomEventByteInputDone) { nfc_device_set_data( - nfc->nfc_device, NfcProtocolIso14443_3a, nfc->iso14443_3a_edit_data); - if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSavedMenu)) { - if(nfc_save(nfc)) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess); + instance->nfc_device, NfcProtocolIso14443_3a, instance->iso14443_3a_edit_data); + if(scene_manager_has_previous_scene(instance->scene_manager, NfcSceneSavedMenu)) { + if(nfc_save(instance)) { + scene_manager_next_scene(instance->scene_manager, NfcSceneSaveSuccess); consumed = true; } } else { - scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); + scene_manager_next_scene(instance->scene_manager, NfcSceneSaveName); consumed = true; } } @@ -47,9 +51,9 @@ bool nfc_scene_set_uid_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_set_uid_on_exit(void* context) { - NfcApp* nfc = context; + NfcApp* instance = context; // Clear view - byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0); - byte_input_set_header_text(nfc->byte_input, ""); + byte_input_set_result_callback(instance->byte_input, NULL, NULL, NULL, NULL, 0); + byte_input_set_header_text(instance->byte_input, ""); } diff --git a/firmware.scons b/firmware.scons index f1ce26791283..5e4398427513 100644 --- a/firmware.scons +++ b/firmware.scons @@ -76,7 +76,7 @@ env = ENV.Clone( "NDEBUG", "FURI_DEBUG", ], - } + }, }, FW_API_TABLE=None, _APP_ICONS=None, diff --git a/lib/nfc/helpers/nfc_data_generator.c b/lib/nfc/helpers/nfc_data_generator.c index 3f02784c73e4..d717e402dd1f 100644 --- a/lib/nfc/helpers/nfc_data_generator.c +++ b/lib/nfc/helpers/nfc_data_generator.c @@ -2,445 +2,468 @@ #include #include - +#include #include #include #define NXP_MANUFACTURER_ID (0x04) -typedef void (*NfcDataGeneratorHandler)(NfcDeviceData* data); +typedef void (*NfcDataGeneratorHandler)(NfcDevice* nfc_device); typedef struct { const char* name; NfcDataGeneratorHandler handler; } NfcDataGenerator; -// static const uint8_t version_bytes_mf0ulx1[] = {0x00, 0x04, 0x03, 0x00, 0x01, 0x00, 0x00, 0x03}; -// static const uint8_t version_bytes_ntag21x[] = {0x00, 0x04, 0x04, 0x02, 0x01, 0x00, 0x00, 0x03}; -// static const uint8_t version_bytes_ntag_i2c[] = {0x00, 0x04, 0x04, 0x05, 0x02, 0x00, 0x00, 0x03}; -// static const uint8_t default_data_ntag203[] = -// {0xE1, 0x10, 0x12, 0x00, 0x01, 0x03, 0xA0, 0x10, 0x44, 0x03, 0x00, 0xFE}; -// static const uint8_t default_data_ntag213[] = {0x01, 0x03, 0xA0, 0x0C, 0x34, 0x03, 0x00, 0xFE}; -// static const uint8_t default_data_ntag215_216[] = {0x03, 0x00, 0xFE}; -// static const uint8_t default_data_ntag_i2c[] = {0xE1, 0x10, 0x00, 0x00, 0x03, 0x00, 0xFE}; -// static const uint8_t default_config_ntag_i2c[] = {0x01, 0x00, 0xF8, 0x48, 0x08, 0x01, 0x00, 0x00}; -// -// static void nfc_generate_common_start(NfcDeviceData* data) { -// memset(data, 0, sizeof(NfcDeviceData)); -// } - -// static void nfc_generate_mf_ul_uid(uint8_t* uid) { -// uid[0] = NXP_MANUFACTURER_ID; -// furi_hal_random_fill_buf(&uid[1], 6); -// // I'm not sure how this is generated, but the upper nybble always seems to be 8 -// uid[6] &= 0x0F; -// uid[6] |= 0x80; -// } - -// static void nfc_generate_mf_ul_common(NfcDeviceData* data) { -// MfUltralightData* mfu_data = data->mf_ul_data; -// mfu_data->nfca_data->uid_len = 7; -// nfc_generate_mf_ul_uid(mfu_data->nfca_data->uid); -// mfu_data->nfca_data->atqa[0] = 0x44; -// mfu_data->nfca_data->atqa[1] = 0x00; -// mfu_data->nfca_data->sak = 0x00; -// data->protocol = NfcDevProtocolMfUltralight; -// } - -// static void nfc_generate_calc_bcc(uint8_t* uid, uint8_t* bcc0, uint8_t* bcc1) { -// *bcc0 = 0x88 ^ uid[0] ^ uid[1] ^ uid[2]; -// *bcc1 = uid[3] ^ uid[4] ^ uid[5] ^ uid[6]; -// } - -// static void nfc_generate_mf_ul_copy_uid_with_bcc(NfcDeviceData* data) { -// MfUltralightData* mfu_data = data->mf_ul_data; -// memcpy(mfu_data->page[0].data, mfu_data->nfca_data->uid, 3); -// memcpy(mfu_data->page[1].data, &mfu_data->nfca_data->uid[3], 4); -// -// nfc_generate_calc_bcc( -// mfu_data->nfca_data->uid, &mfu_data->page[0].data[3], &mfu_data->page[2].data[0]); -// } - -static void nfc_generate_mf_ul_orig(NfcDeviceData* data) { - UNUSED(data); - // nfc_generate_common_start(data); - // nfc_generate_mf_ul_common(data); - - // MfUltralightData* mfu_data = data->mf_ul_data; - // mfu_data->type = MfUltralightTypeUnknown; - // mfu_data->pages_total = 16; - // mfu_data->pages_read = 16; - // nfc_generate_mf_ul_copy_uid_with_bcc(data); - // // TODO: what's internal byte on page 2? - // memset(&mfu_data->page[4], 0xff, sizeof(MfUltralightPage)); -} - -// static void nfc_generate_mf_ul_with_config_common(NfcDeviceData* data, uint8_t num_pages) { -// nfc_generate_common_start(data); -// nfc_generate_mf_ul_common(data); - -// MfUltralightData* mfu_data = data->mf_ul_data; -// mfu_data->pages_total = num_pages; -// mfu_data->pages_read = num_pages; -// nfc_generate_mf_ul_copy_uid_with_bcc(data); -// uint16_t config_index = (num_pages - 4); -// mfu_data->page[config_index].data[0] = 0x04; // STRG_MOD_EN -// mfu_data->page[config_index].data[3] = 0xff; // AUTH0 -// mfu_data->page[config_index + 1].data[1] = 0x05; // VCTID -// memset(&mfu_data->page[config_index + 2], 0xff, sizeof(MfUltralightPage)); // Default PWD -// if(num_pages > 20) { -// mfu_data->page[config_index - 1].data[3] = MF_ULTRALIGHT_TEARING_FLAG_DEFAULT; -// } -// } - -// static void nfc_generate_mf_ul_ev1_common(NfcDeviceData* data, uint8_t num_pages) { -// nfc_generate_mf_ul_with_config_common(data, num_pages); -// MfUltralightData* mfu_data = data->mf_ul_data; -// memcpy(&mfu_data->version, version_bytes_mf0ulx1, sizeof(MfUltralightVersion)); -// for(size_t i = 0; i < 3; ++i) { -// mfu_data->tearing_flag[i].data[0] = MF_ULTRALIGHT_TEARING_FLAG_DEFAULT; -// } -// TODO: what's internal byte on page 2? -// } - -static void nfc_generate_mf_ul_11(NfcDeviceData* data) { - UNUSED(data); - // nfc_generate_mf_ul_ev1_common(data, 20); - // MfUltralightData* mfu_data = data->mf_ul_data; - // mfu_data->type = MfUltralightTypeUL11; - // mfu_data->version.prod_subtype = 0x01; - // mfu_data->version.storage_size = 0x0B; - // mfu_data->page[16].data[0] = 0x00; // Low capacitance version does not have STRG_MOD_EN -} - -static void nfc_generate_mf_ul_h11(NfcDeviceData* data) { - UNUSED(data); - // nfc_generate_mf_ul_ev1_common(data, 20); - // MfUltralightData* mfu_data = data->mf_ul_data; - // mfu_data->type = MfUltralightTypeUL11; - // mfu_data->version.prod_subtype = 0x02; - // mfu_data->version.storage_size = 0x0B; -} - -static void nfc_generate_mf_ul_21(NfcDeviceData* data) { - UNUSED(data); - // nfc_generate_mf_ul_ev1_common(data, 41); - // MfUltralightData* mfu_data = data->mf_ul_data; - // mfu_data->type = MfUltralightTypeUL21; - // mfu_data->version.prod_subtype = 0x01; - // mfu_data->version.storage_size = 0x0E; - // mfu_data->page[37].data[0] = 0x00; // Low capacitance version does not have STRG_MOD_EN -} - -static void nfc_generate_mf_ul_h21(NfcDeviceData* data) { - UNUSED(data); - // nfc_generate_mf_ul_ev1_common(data, 41); - // MfUltralightData* mfu_data = data->mf_ul_data; - // mfu_data->type = MfUltralightTypeUL21; - // mfu_data->version.prod_subtype = 0x02; - // mfu_data->version.storage_size = 0x0E; -} - -static void nfc_generate_ntag203(NfcDeviceData* data) { - UNUSED(data); - // nfc_generate_common_start(data); - // nfc_generate_mf_ul_common(data); - - // MfUltralightData* mfu_data = data->mf_ul_data; - // mfu_data->type = MfUltralightTypeNTAG203; - // mfu_data->pages_total = 42; - // mfu_data->pages_read = 42; - // nfc_generate_mf_ul_copy_uid_with_bcc(data); - // mfu_data->page[2].data[1] = 0x48; // Internal byte - // memcpy(&mfu_data->page[3], default_data_ntag203, sizeof(MfUltralightPage)); -} - -// static void nfc_generate_ntag21x_common(NfcDeviceData* data, uint8_t num_pages) { -// nfc_generate_mf_ul_with_config_common(data, num_pages); -// MfUltralightData* mfu_data = data->mf_ul_data; -// memcpy(&mfu_data->version, version_bytes_ntag21x, sizeof(MfUltralightVersion)); -// mfu_data->page[2].data[1] = 0x48; // Internal byte -// // Capability container -// mfu_data->page[3].data[0] = 0xE1; -// mfu_data->page[3].data[1] = 0x10; -// } - -static void nfc_generate_ntag213(NfcDeviceData* data) { - UNUSED(data); - // nfc_generate_ntag21x_common(data, 45); - // MfUltralightData* mfu_data = data->mf_ul_data; - // mfu_data->type = MfUltralightTypeNTAG213; - // mfu_data->version.storage_size = 0x0F; - // mfu_data->page[3].data[2] = 0x12; - // // Default contents - // memcpy(&mfu_data->page[4], default_data_ntag213, sizeof(default_data_ntag213)); -} - -static void nfc_generate_ntag215(NfcDeviceData* data) { - UNUSED(data); - // nfc_generate_ntag21x_common(data, 135); - // MfUltralightData* mfu_data = data->mf_ul_data; - // mfu_data->type = MfUltralightTypeNTAG215; - // mfu_data->version.storage_size = 0x11; - // mfu_data->page[3].data[2] = 0x3E; - // // Default contents - // memcpy(&mfu_data->page[4], default_data_ntag215_216, sizeof(default_data_ntag215_216)); -} - -static void nfc_generate_ntag216(NfcDeviceData* data) { - UNUSED(data); - // nfc_generate_ntag21x_common(data, 231); - // MfUltralightData* mfu_data = data->mf_ul_data; - // mfu_data->type = MfUltralightTypeNTAG216; - // mfu_data->version.storage_size = 0x13; - // mfu_data->page[3].data[2] = 0x6D; - // // Default contents - // memcpy(&mfu_data->page[4], default_data_ntag215_216, sizeof(default_data_ntag215_216)); -} - -// static void -// nfc_generate_ntag_i2c_common(NfcDeviceData* data, MfUltralightType type, uint16_t num_pages) { -// nfc_generate_common_start(data); -// nfc_generate_mf_ul_common(data); - -// MfUltralightData* mfu_data = data->mf_ul_data; -// mfu_data->type = type; -// memcpy(&mfu_data->version, version_bytes_ntag_i2c, sizeof(version_bytes_ntag_i2c)); -// mfu_data->pages_total = num_pages; -// mfu_data->pages_read = num_pages; -// memcpy(mfu_data->page[0].data, mfu_data->nfca_data->uid, mfu_data->nfca_data->uid_len); -// mfu_data->page[1].data[3] = mfu_data->nfca_data->sak; -// mfu_data->page[2].data[0] = mfu_data->nfca_data->atqa[0]; -// mfu_data->page[2].data[1] = mfu_data->nfca_data->atqa[1]; - -// uint16_t config_register_page = 0; -// uint16_t session_register_page = 0; -// -// // Sync with mifare_ultralight.c -// switch(type) { -// case MfUltralightTypeNTAGI2C1K: -// config_register_page = 227; -// session_register_page = 229; -// break; -// case MfUltralightTypeNTAGI2C2K: -// config_register_page = 481; -// session_register_page = 483; -// break; -// case MfUltralightTypeNTAGI2CPlus1K: -// case MfUltralightTypeNTAGI2CPlus2K: -// config_register_page = 232; -// session_register_page = 234; -// break; -// default: -// furi_crash("Unknown MFUL"); -// break; -// } -// -// memcpy( -// &mfu_data->page[config_register_page], -// default_config_ntag_i2c, -// sizeof(default_config_ntag_i2c)); -// memcpy( -// &mfu_data->page[session_register_page], -// default_config_ntag_i2c, -// sizeof(default_config_ntag_i2c)); -// } - -static void nfc_generate_ntag_i2c_1k(NfcDeviceData* data) { - UNUSED(data); - // nfc_generate_ntag_i2c_common(data, MfUltralightTypeNTAGI2C1K, 231); - // MfUltralightData* mfu_data = data->mf_ul_data; - // mfu_data->version.prod_ver_minor = 0x01; - // mfu_data->version.storage_size = 0x13; - // - // memcpy(&mfu_data->page[3], default_data_ntag_i2c, sizeof(default_data_ntag_i2c)); - // mfu_data->page[3].data[2] = 0x6D; // Size of tag in CC -} - -static void nfc_generate_ntag_i2c_2k(NfcDeviceData* data) { - UNUSED(data); - // nfc_generate_ntag_i2c_common(data, MfUltralightTypeNTAGI2C2K, 485); - // MfUltralightData* mfu_data = data->mf_ul_data; - // mfu_data->version.prod_ver_minor = 0x01; - // mfu_data->version.storage_size = 0x15; - // - // memcpy(&mfu_data->page[3], default_data_ntag_i2c, sizeof(default_data_ntag_i2c)); - // mfu_data->page[3].data[2] = 0xEA; // Size of tag in CC -} - -// static void -// nfc_generate_ntag_i2c_plus_common(NfcDeviceData* data, MfUltralightType type, uint16_t num_pages) { -// nfc_generate_ntag_i2c_common(data, type, num_pages); -// -// MfUltralightData* mfu_data = data->mf_ul_data; -// uint16_t config_index = 227; -// mfu_data->page[config_index].data[3] = 0xff; // AUTH0 -// -// memset(&mfu_data->page[config_index + 2], 0xFF, sizeof(MfUltralightPage)); // Default PWD -// } - -static void nfc_generate_ntag_i2c_plus_1k(NfcDeviceData* data) { - UNUSED(data); - // nfc_generate_ntag_i2c_plus_common(data, MfUltralightTypeNTAGI2CPlus1K, 236); - // MfUltralightData* mfu_data = data->mf_ul_data; - // mfu_data->version.prod_ver_minor = 0x02; - // mfu_data->version.storage_size = 0x13; -} - -static void nfc_generate_ntag_i2c_plus_2k(NfcDeviceData* data) { - UNUSED(data); - // nfc_generate_ntag_i2c_plus_common(data, MfUltralightTypeNTAGI2CPlus2K, 492); - // MfUltralightData* mfu_data = data->mf_ul_data; - // mfu_data->version.prod_ver_minor = 0x02; - // mfu_data->version.storage_size = 0x15; -} - -// static void nfc_generate_mf_classic_uid(uint8_t* uid, uint8_t length) { -// uid[0] = NXP_MANUFACTURER_ID; -// furi_hal_random_fill_buf(&uid[1], length - 1); -// } - -// static void -// nfc_generate_mf_classic_common(MfClassicData* data, uint8_t uid_len, MfClassicType type) { -// data->nfca_data->uid_len = uid_len; -// data->nfca_data->atqa[0] = 0x44; -// data->nfca_data->atqa[1] = 0x00; -// data->nfca_data->sak = 0x08; -// data->type = type; -// } - -// static void nfc_generate_mf_classic_sector_trailer(MfClassicData* data, uint8_t block) { -// All keys are set to FFFF FFFF FFFFh at chip delivery and the bytes 6, 7 and 8 are set to FF0780h. -// MfClassicSectorTrailer* sec_tr = (MfClassicSectorTrailer*)data->block[block].data; -// sec_tr->access_bits.data[0] = 0xFF; -// sec_tr->access_bits.data[1] = 0x07; -// sec_tr->access_bits.data[2] = 0x80; -// sec_tr->access_bits.data[3] = 0x69; // Nice -// -// mf_classic_set_block_read(data, block, &data->block[block]); -// mf_classic_set_key_found( -// data, mf_classic_get_sector_by_block(block), MfClassicKeyTypeA, 0xFFFFFFFFFFFF); -// mf_classic_set_key_found( -// data, mf_classic_get_sector_by_block(block), MfClassicKeyTypeB, 0xFFFFFFFFFFFF); -// } - -// static void nfc_generate_mf_classic_block_0( -// uint8_t* block, -// uint8_t uid_len, -// uint8_t sak, -// uint8_t atqa0, -// uint8_t atqa1) { -// // Block length is always 16 bytes, and the UID can be either 4 or 7 bytes -// furi_assert(uid_len == 4 || uid_len == 7); -// furi_assert(block); -// -// if(uid_len == 4) { -// // Calculate BCC -// block[uid_len] = 0; -// -// for(int i = 0; i < uid_len; i++) { -// block[uid_len] ^= block[i]; -// } -// } else { -// uid_len -= 1; -// } -// -// block[uid_len + 1] = sak; -// block[uid_len + 2] = atqa0; -// block[uid_len + 3] = atqa1; -// -// for(int i = uid_len + 4; i < 16; i++) { -// block[i] = 0xFF; -// } -// } - -// static void nfc_generate_mf_classic(NfcDeviceData* data, uint8_t uid_len, MfClassicType type) { -// nfc_generate_common_start(data); -// data->protocol = NfcDevProtocolMfClassic; -// MfClassicData* mfc_data = data->mf_classic_data; -// nfc_generate_mf_classic_uid(mfc_data->block[0].data, uid_len); -// nfc_generate_mf_classic_common(mfc_data, uid_len, type); -// -// // Set the UID -// mfc_data->nfca_data->uid[0] = NXP_MANUFACTURER_ID; -// for(int i = 1; i < uid_len; i++) { -// mfc_data->nfca_data->uid[i] = mfc_data->block[0].data[i]; -// } -// -// mf_classic_set_block_read(mfc_data, 0, &mfc_data->block[0]); -// -// uint16_t block_num = mf_classic_get_total_block_num(type); -// if(type == MfClassicType4k) { -// // Set every block to 0xFF -// for(uint16_t i = 1; i < block_num; i += 1) { -// if(mf_classic_is_sector_trailer(i)) { -// nfc_generate_mf_classic_sector_trailer(mfc_data, i); -// } else { -// memset(&mfc_data->block[i].data, 0xFF, 16); -// } -// mf_classic_set_block_read(mfc_data, i, &mfc_data->block[i]); -// } -// // Set SAK to 18 -// data->nfca_data->sak = 0x18; -// } else if(type == MfClassicType1k) { -// // Set every block to 0xFF -// for(uint16_t i = 1; i < block_num; i += 1) { -// if(mf_classic_is_sector_trailer(i)) { -// nfc_generate_mf_classic_sector_trailer(mfc_data, i); -// } else { -// memset(&mfc_data->block[i].data, 0xFF, 16); -// } -// mf_classic_set_block_read(mfc_data, i, &mfc_data->block[i]); -// } -// // Set SAK to 08 -// data->nfca_data->sak = 0x08; -// } else if(type == MfClassicTypeMini) { -// // Set every block to 0xFF -// for(uint16_t i = 1; i < block_num; i += 1) { -// if(mf_classic_is_sector_trailer(i)) { -// nfc_generate_mf_classic_sector_trailer(mfc_data, i); -// } else { -// memset(&mfc_data->block[i].data, 0xFF, 16); -// } -// mf_classic_set_block_read(mfc_data, i, &mfc_data->block[i]); -// } -// // Set SAK to 09 -// data->nfca_data->sak = 0x09; -// } -// -// nfc_generate_mf_classic_block_0( -// data->mf_classic_data->block[0].data, -// uid_len, -// data->nfca_data->sak, -// data->nfca_data->atqa[0], -// data->nfca_data->atqa[1]); -// -// mfc_data->type = type; -// } - -static void nfc_generate_mf_classic_mini(NfcDeviceData* data) { - UNUSED(data); - // nfc_generate_mf_classic(data, 4, MfClassicTypeMini); -} - -static void nfc_generate_mf_classic_1k_4b_uid(NfcDeviceData* data) { - UNUSED(data); - // nfc_generate_mf_classic(data, 4, MfClassicType1k); -} - -static void nfc_generate_mf_classic_1k_7b_uid(NfcDeviceData* data) { - UNUSED(data); - // nfc_generate_mf_classic(data, 7, MfClassicType1k); -} - -static void nfc_generate_mf_classic_4k_4b_uid(NfcDeviceData* data) { - UNUSED(data); - // nfc_generate_mf_classic(data, 4, MfClassicType4k); -} - -static void nfc_generate_mf_classic_4k_7b_uid(NfcDeviceData* data) { - UNUSED(data); - // nfc_generate_mf_classic(data, 7, MfClassicType4k); +static const uint8_t version_bytes_mf0ulx1[] = {0x00, 0x04, 0x03, 0x00, 0x01, 0x00, 0x00, 0x03}; +static const uint8_t version_bytes_ntag21x[] = {0x00, 0x04, 0x04, 0x02, 0x01, 0x00, 0x00, 0x03}; +static const uint8_t version_bytes_ntag_i2c[] = {0x00, 0x04, 0x04, 0x05, 0x02, 0x00, 0x00, 0x03}; +static const uint8_t default_data_ntag203[] = + {0xE1, 0x10, 0x12, 0x00, 0x01, 0x03, 0xA0, 0x10, 0x44, 0x03, 0x00, 0xFE}; +static const uint8_t default_data_ntag213[] = {0x01, 0x03, 0xA0, 0x0C, 0x34, 0x03, 0x00, 0xFE}; +static const uint8_t default_data_ntag215_216[] = {0x03, 0x00, 0xFE}; +static const uint8_t default_data_ntag_i2c[] = {0xE1, 0x10, 0x00, 0x00, 0x03, 0x00, 0xFE}; +static const uint8_t default_config_ntag_i2c[] = {0x01, 0x00, 0xF8, 0x48, 0x08, 0x01, 0x00, 0x00}; + +static void nfc_generate_mf_ul_uid(uint8_t* uid) { + uid[0] = NXP_MANUFACTURER_ID; + furi_hal_random_fill_buf(&uid[1], 6); + // I'm not sure how this is generated, but the upper nybble always seems to be 8 + uid[6] &= 0x0F; + uid[6] |= 0x80; +} + +static void nfc_generate_mf_ul_common(MfUltralightData* mfu_data) { + mfu_data->iso14443_3a_data->uid_len = 7; + nfc_generate_mf_ul_uid(mfu_data->iso14443_3a_data->uid); + mfu_data->iso14443_3a_data->atqa[0] = 0x44; + mfu_data->iso14443_3a_data->atqa[1] = 0x00; + mfu_data->iso14443_3a_data->sak = 0x00; +} + +static void nfc_generate_calc_bcc(uint8_t* uid, uint8_t* bcc0, uint8_t* bcc1) { + *bcc0 = 0x88 ^ uid[0] ^ uid[1] ^ uid[2]; + *bcc1 = uid[3] ^ uid[4] ^ uid[5] ^ uid[6]; +} + +static void nfc_generate_mf_ul_copy_uid_with_bcc(MfUltralightData* mfu_data) { + memcpy(mfu_data->page[0].data, mfu_data->iso14443_3a_data->uid, 3); + memcpy(mfu_data->page[1].data, &mfu_data->iso14443_3a_data->uid[3], 4); + + nfc_generate_calc_bcc( + mfu_data->iso14443_3a_data->uid, &mfu_data->page[0].data[3], &mfu_data->page[2].data[0]); +} + +static void nfc_generate_mf_ul_orig(NfcDevice* nfc_device) { + MfUltralightData* mfu_data = mf_ultralight_alloc(); + nfc_generate_mf_ul_common(mfu_data); + + mfu_data->type = MfUltralightTypeUnknown; + mfu_data->pages_total = 16; + mfu_data->pages_read = 16; + nfc_generate_mf_ul_copy_uid_with_bcc(mfu_data); + // TODO: what's internal byte on page 2? + memset(&mfu_data->page[4], 0xff, sizeof(MfUltralightPage)); + + nfc_device_set_data(nfc_device, NfcProtocolMfUltralight, mfu_data); + mf_ultralight_free(mfu_data); +} + +static void nfc_generate_mf_ul_with_config_common(MfUltralightData* mfu_data, uint8_t num_pages) { + nfc_generate_mf_ul_common(mfu_data); + + mfu_data->pages_total = num_pages; + mfu_data->pages_read = num_pages; + nfc_generate_mf_ul_copy_uid_with_bcc(mfu_data); + uint16_t config_index = (num_pages - 4); + mfu_data->page[config_index].data[0] = 0x04; // STRG_MOD_EN + mfu_data->page[config_index].data[3] = 0xff; // AUTH0 + mfu_data->page[config_index + 1].data[1] = 0x05; // VCTID + memset(&mfu_data->page[config_index + 2], 0xff, sizeof(MfUltralightPage)); // Default PWD + if(num_pages > 20) { + mfu_data->page[config_index - 1].data[3] = MF_ULTRALIGHT_TEARING_FLAG_DEFAULT; + } +} + +static void nfc_generate_mf_ul_ev1_common(MfUltralightData* mfu_data, uint8_t num_pages) { + nfc_generate_mf_ul_with_config_common(mfu_data, num_pages); + memcpy(&mfu_data->version, version_bytes_mf0ulx1, sizeof(MfUltralightVersion)); + for(size_t i = 0; i < 3; ++i) { + mfu_data->tearing_flag[i].data[0] = MF_ULTRALIGHT_TEARING_FLAG_DEFAULT; + } + // TODO: what's internal byte on page 2? +} + +static void nfc_generate_mf_ul_11(NfcDevice* nfc_device) { + MfUltralightData* mfu_data = mf_ultralight_alloc(); + + nfc_generate_mf_ul_ev1_common(mfu_data, 20); + mfu_data->type = MfUltralightTypeUL11; + mfu_data->version.prod_subtype = 0x01; + mfu_data->version.storage_size = 0x0B; + mfu_data->page[16].data[0] = 0x00; // Low capacitance version does not have STRG_MOD_EN + + nfc_device_set_data(nfc_device, NfcProtocolMfUltralight, mfu_data); + mf_ultralight_free(mfu_data); +} + +static void nfc_generate_mf_ul_h11(NfcDevice* nfc_device) { + MfUltralightData* mfu_data = mf_ultralight_alloc(); + + nfc_generate_mf_ul_ev1_common(mfu_data, 20); + mfu_data->type = MfUltralightTypeUL11; + mfu_data->version.prod_subtype = 0x02; + mfu_data->version.storage_size = 0x0B; + + nfc_device_set_data(nfc_device, NfcProtocolMfUltralight, mfu_data); + mf_ultralight_free(mfu_data); +} + +static void nfc_generate_mf_ul_21(NfcDevice* nfc_device) { + MfUltralightData* mfu_data = mf_ultralight_alloc(); + + nfc_generate_mf_ul_ev1_common(mfu_data, 41); + mfu_data->type = MfUltralightTypeUL21; + mfu_data->version.prod_subtype = 0x01; + mfu_data->version.storage_size = 0x0E; + mfu_data->page[37].data[0] = 0x00; // Low capacitance version does not have STRG_MOD_EN + + nfc_device_set_data(nfc_device, NfcProtocolMfUltralight, mfu_data); + mf_ultralight_free(mfu_data); +} + +static void nfc_generate_mf_ul_h21(NfcDevice* nfc_device) { + MfUltralightData* mfu_data = mf_ultralight_alloc(); + + nfc_generate_mf_ul_ev1_common(mfu_data, 41); + mfu_data->type = MfUltralightTypeUL21; + mfu_data->version.prod_subtype = 0x02; + mfu_data->version.storage_size = 0x0E; + + nfc_device_set_data(nfc_device, NfcProtocolMfUltralight, mfu_data); + mf_ultralight_free(mfu_data); +} + +static void nfc_generate_ntag203(NfcDevice* nfc_device) { + MfUltralightData* mfu_data = mf_ultralight_alloc(); + + nfc_generate_mf_ul_common(mfu_data); + mfu_data->type = MfUltralightTypeNTAG203; + mfu_data->pages_total = 42; + mfu_data->pages_read = 42; + nfc_generate_mf_ul_copy_uid_with_bcc(mfu_data); + mfu_data->page[2].data[1] = 0x48; // Internal byte + memcpy(&mfu_data->page[3], default_data_ntag203, sizeof(MfUltralightPage)); + + nfc_device_set_data(nfc_device, NfcProtocolMfUltralight, mfu_data); + mf_ultralight_free(mfu_data); +} + +static void nfc_generate_ntag21x_common(MfUltralightData* mfu_data, uint8_t num_pages) { + nfc_generate_mf_ul_with_config_common(mfu_data, num_pages); + memcpy(&mfu_data->version, version_bytes_ntag21x, sizeof(MfUltralightVersion)); + mfu_data->page[2].data[1] = 0x48; // Internal byte + // Capability container + mfu_data->page[3].data[0] = 0xE1; + mfu_data->page[3].data[1] = 0x10; +} + +static void nfc_generate_ntag213(NfcDevice* nfc_device) { + MfUltralightData* mfu_data = mf_ultralight_alloc(); + + nfc_generate_ntag21x_common(mfu_data, 45); + mfu_data->type = MfUltralightTypeNTAG213; + mfu_data->version.storage_size = 0x0F; + mfu_data->page[3].data[2] = 0x12; + // Default contents + memcpy(&mfu_data->page[4], default_data_ntag213, sizeof(default_data_ntag213)); + + nfc_device_set_data(nfc_device, NfcProtocolMfUltralight, mfu_data); + mf_ultralight_free(mfu_data); +} + +static void nfc_generate_ntag215(NfcDevice* nfc_device) { + MfUltralightData* mfu_data = mf_ultralight_alloc(); + + nfc_generate_ntag21x_common(mfu_data, 135); + mfu_data->type = MfUltralightTypeNTAG215; + mfu_data->version.storage_size = 0x11; + mfu_data->page[3].data[2] = 0x3E; + // Default contents + memcpy(&mfu_data->page[4], default_data_ntag215_216, sizeof(default_data_ntag215_216)); + + nfc_device_set_data(nfc_device, NfcProtocolMfUltralight, mfu_data); + mf_ultralight_free(mfu_data); +} + +static void nfc_generate_ntag216(NfcDevice* nfc_device) { + MfUltralightData* mfu_data = mf_ultralight_alloc(); + + nfc_generate_ntag21x_common(mfu_data, 231); + mfu_data->type = MfUltralightTypeNTAG216; + mfu_data->version.storage_size = 0x13; + mfu_data->page[3].data[2] = 0x6D; + // Default contents + memcpy(&mfu_data->page[4], default_data_ntag215_216, sizeof(default_data_ntag215_216)); + + nfc_device_set_data(nfc_device, NfcProtocolMfUltralight, mfu_data); + mf_ultralight_free(mfu_data); +} + +static void nfc_generate_ntag_i2c_common( + MfUltralightData* mfu_data, + MfUltralightType type, + uint16_t num_pages) { + nfc_generate_mf_ul_common(mfu_data); + + mfu_data->type = type; + memcpy(&mfu_data->version, version_bytes_ntag_i2c, sizeof(version_bytes_ntag_i2c)); + mfu_data->pages_total = num_pages; + mfu_data->pages_read = num_pages; + memcpy( + mfu_data->page[0].data, + mfu_data->iso14443_3a_data->uid, + mfu_data->iso14443_3a_data->uid_len); + mfu_data->page[1].data[3] = mfu_data->iso14443_3a_data->sak; + mfu_data->page[2].data[0] = mfu_data->iso14443_3a_data->atqa[0]; + mfu_data->page[2].data[1] = mfu_data->iso14443_3a_data->atqa[1]; + + uint16_t config_register_page = 0; + uint16_t session_register_page = 0; + + // Sync with mifare_ultralight.c + switch(type) { + case MfUltralightTypeNTAGI2C1K: + config_register_page = 227; + session_register_page = 229; + break; + case MfUltralightTypeNTAGI2C2K: + config_register_page = 481; + session_register_page = 483; + break; + case MfUltralightTypeNTAGI2CPlus1K: + case MfUltralightTypeNTAGI2CPlus2K: + config_register_page = 232; + session_register_page = 234; + break; + default: + furi_crash("Unknown MFUL"); + break; + } + + memcpy( + &mfu_data->page[config_register_page], + default_config_ntag_i2c, + sizeof(default_config_ntag_i2c)); + memcpy( + &mfu_data->page[session_register_page], + default_config_ntag_i2c, + sizeof(default_config_ntag_i2c)); +} + +static void nfc_generate_ntag_i2c_1k(NfcDevice* nfc_device) { + MfUltralightData* mfu_data = mf_ultralight_alloc(); + + nfc_generate_ntag_i2c_common(mfu_data, MfUltralightTypeNTAGI2C1K, 231); + mfu_data->version.prod_ver_minor = 0x01; + mfu_data->version.storage_size = 0x13; + memcpy(&mfu_data->page[3], default_data_ntag_i2c, sizeof(default_data_ntag_i2c)); + mfu_data->page[3].data[2] = 0x6D; // Size of tag in CC + + nfc_device_set_data(nfc_device, NfcProtocolMfUltralight, mfu_data); + mf_ultralight_free(mfu_data); +} + +static void nfc_generate_ntag_i2c_2k(NfcDevice* nfc_device) { + MfUltralightData* mfu_data = mf_ultralight_alloc(); + + nfc_generate_ntag_i2c_common(mfu_data, MfUltralightTypeNTAGI2C2K, 485); + mfu_data->version.prod_ver_minor = 0x01; + mfu_data->version.storage_size = 0x15; + memcpy(&mfu_data->page[3], default_data_ntag_i2c, sizeof(default_data_ntag_i2c)); + mfu_data->page[3].data[2] = 0xEA; // Size of tag in CC + + nfc_device_set_data(nfc_device, NfcProtocolMfUltralight, mfu_data); + mf_ultralight_free(mfu_data); +} + +static void nfc_generate_ntag_i2c_plus_common( + MfUltralightData* mfu_data, + MfUltralightType type, + uint16_t num_pages) { + nfc_generate_ntag_i2c_common(mfu_data, type, num_pages); + + uint16_t config_index = 227; + mfu_data->page[config_index].data[3] = 0xff; // AUTH0 + + memset(&mfu_data->page[config_index + 2], 0xFF, sizeof(MfUltralightPage)); // Default PWD +} + +static void nfc_generate_ntag_i2c_plus_1k(NfcDevice* nfc_device) { + MfUltralightData* mfu_data = mf_ultralight_alloc(); + + nfc_generate_ntag_i2c_plus_common(mfu_data, MfUltralightTypeNTAGI2CPlus1K, 236); + mfu_data->version.prod_ver_minor = 0x02; + mfu_data->version.storage_size = 0x13; + + nfc_device_set_data(nfc_device, NfcProtocolMfUltralight, mfu_data); + mf_ultralight_free(mfu_data); +} + +static void nfc_generate_ntag_i2c_plus_2k(NfcDevice* nfc_device) { + MfUltralightData* mfu_data = mf_ultralight_alloc(); + + nfc_generate_ntag_i2c_plus_common(mfu_data, MfUltralightTypeNTAGI2CPlus2K, 492); + mfu_data->version.prod_ver_minor = 0x02; + mfu_data->version.storage_size = 0x15; + + nfc_device_set_data(nfc_device, NfcProtocolMfUltralight, mfu_data); + mf_ultralight_free(mfu_data); +} + +static void nfc_generate_mf_classic_uid(uint8_t* uid, uint8_t length) { + uid[0] = NXP_MANUFACTURER_ID; + furi_hal_random_fill_buf(&uid[1], length - 1); +} + +static void + nfc_generate_mf_classic_common(MfClassicData* data, uint8_t uid_len, MfClassicType type) { + data->iso14443_3a_data->uid_len = uid_len; + data->iso14443_3a_data->atqa[0] = 0x44; + data->iso14443_3a_data->atqa[1] = 0x00; + data->iso14443_3a_data->sak = 0x08; + data->type = type; +} + +static void nfc_generate_mf_classic_sector_trailer(MfClassicData* data, uint8_t block) { + // All keys are set to FFFF FFFF FFFFh at chip delivery and the bytes 6, 7 and 8 are set to FF0780h. + MfClassicSectorTrailer* sec_tr = (MfClassicSectorTrailer*)data->block[block].data; + sec_tr->access_bits.data[0] = 0xFF; + sec_tr->access_bits.data[1] = 0x07; + sec_tr->access_bits.data[2] = 0x80; + sec_tr->access_bits.data[3] = 0x69; // Nice + + mf_classic_set_block_read(data, block, &data->block[block]); + mf_classic_set_key_found( + data, mf_classic_get_sector_by_block(block), MfClassicKeyTypeA, 0xFFFFFFFFFFFF); + mf_classic_set_key_found( + data, mf_classic_get_sector_by_block(block), MfClassicKeyTypeB, 0xFFFFFFFFFFFF); +} + +static void nfc_generate_mf_classic_block_0( + uint8_t* block, + uint8_t uid_len, + uint8_t sak, + uint8_t atqa0, + uint8_t atqa1) { + // Block length is always 16 bytes, and the UID can be either 4 or 7 bytes + furi_assert(uid_len == 4 || uid_len == 7); + furi_assert(block); + + if(uid_len == 4) { + // Calculate BCC + block[uid_len] = 0; + + for(int i = 0; i < uid_len; i++) { + block[uid_len] ^= block[i]; + } + } else { + uid_len -= 1; + } + + block[uid_len + 1] = sak; + block[uid_len + 2] = atqa0; + block[uid_len + 3] = atqa1; + + for(int i = uid_len + 4; i < 16; i++) { + block[i] = 0xFF; + } +} + +static void nfc_generate_mf_classic(NfcDevice* nfc_device, uint8_t uid_len, MfClassicType type) { + MfClassicData* mfc_data = mf_classic_alloc(); + + nfc_generate_mf_classic_uid(mfc_data->block[0].data, uid_len); + nfc_generate_mf_classic_common(mfc_data, uid_len, type); + + // Set the UID + mfc_data->iso14443_3a_data->uid[0] = NXP_MANUFACTURER_ID; + for(int i = 1; i < uid_len; i++) { + mfc_data->iso14443_3a_data->uid[i] = mfc_data->block[0].data[i]; + } + + mf_classic_set_block_read(mfc_data, 0, &mfc_data->block[0]); + + uint16_t block_num = mf_classic_get_total_block_num(type); + if(type == MfClassicType4k) { + // Set every block to 0xFF + for(uint16_t i = 1; i < block_num; i++) { + if(mf_classic_is_sector_trailer(i)) { + nfc_generate_mf_classic_sector_trailer(mfc_data, i); + } else { + memset(&mfc_data->block[i].data, 0xFF, 16); + } + mf_classic_set_block_read(mfc_data, i, &mfc_data->block[i]); + } + // Set SAK to 18 + mfc_data->iso14443_3a_data->sak = 0x18; + } else if(type == MfClassicType1k) { + // Set every block to 0xFF + for(uint16_t i = 1; i < block_num; i++) { + if(mf_classic_is_sector_trailer(i)) { + nfc_generate_mf_classic_sector_trailer(mfc_data, i); + } else { + memset(&mfc_data->block[i].data, 0xFF, 16); + } + mf_classic_set_block_read(mfc_data, i, &mfc_data->block[i]); + } + // Set SAK to 08 + mfc_data->iso14443_3a_data->sak = 0x08; + } else if(type == MfClassicTypeMini) { + // Set every block to 0xFF + for(uint16_t i = 1; i < block_num; i++) { + if(mf_classic_is_sector_trailer(i)) { + nfc_generate_mf_classic_sector_trailer(mfc_data, i); + } else { + memset(&mfc_data->block[i].data, 0xFF, 16); + } + mf_classic_set_block_read(mfc_data, i, &mfc_data->block[i]); + } + // Set SAK to 09 + mfc_data->iso14443_3a_data->sak = 0x09; + } + + nfc_generate_mf_classic_block_0( + mfc_data->block[0].data, + uid_len, + mfc_data->iso14443_3a_data->sak, + mfc_data->iso14443_3a_data->atqa[0], + mfc_data->iso14443_3a_data->atqa[1]); + + mfc_data->type = type; + + nfc_device_set_data(nfc_device, NfcProtocolMfClassic, mfc_data); + mf_classic_free(mfc_data); +} + +static void nfc_generate_mf_classic_mini(NfcDevice* nfc_device) { + nfc_generate_mf_classic(nfc_device, 4, MfClassicTypeMini); +} + +static void nfc_generate_mf_classic_1k_4b_uid(NfcDevice* nfc_device) { + nfc_generate_mf_classic(nfc_device, 4, MfClassicType1k); +} + +static void nfc_generate_mf_classic_1k_7b_uid(NfcDevice* nfc_device) { + nfc_generate_mf_classic(nfc_device, 7, MfClassicType1k); +} + +static void nfc_generate_mf_classic_4k_4b_uid(NfcDevice* nfc_device) { + nfc_generate_mf_classic(nfc_device, 4, MfClassicType4k); +} + +static void nfc_generate_mf_classic_4k_7b_uid(NfcDevice* nfc_device) { + nfc_generate_mf_classic(nfc_device, 7, MfClassicType4k); } static const NfcDataGenerator nfc_data_generator[NfcDataGeneratorTypeNum] = { @@ -540,6 +563,6 @@ const char* nfc_data_generator_get_name(NfcDataGeneratorType type) { return nfc_data_generator[type].name; } -void nfc_data_generator_fill_data(NfcDataGeneratorType type, NfcDeviceData* data) { - nfc_data_generator[type].handler(data); +void nfc_data_generator_fill_data(NfcDataGeneratorType type, NfcDevice* nfc_device) { + nfc_data_generator[type].handler(nfc_device); } diff --git a/lib/nfc/helpers/nfc_data_generator.h b/lib/nfc/helpers/nfc_data_generator.h index d1f24f30b04b..01f5dac16e5d 100644 --- a/lib/nfc/helpers/nfc_data_generator.h +++ b/lib/nfc/helpers/nfc_data_generator.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #ifdef __cplusplus extern "C" { @@ -33,7 +33,7 @@ typedef enum { const char* nfc_data_generator_get_name(NfcDataGeneratorType type); -void nfc_data_generator_fill_data(NfcDataGeneratorType type, NfcDeviceData* data); +void nfc_data_generator_fill_data(NfcDataGeneratorType type, NfcDevice* nfc_device); #ifdef __cplusplus } diff --git a/lib/nfc/nfc_device.c b/lib/nfc/nfc_device.c index cf9d4dfd8460..53097a5fe77d 100644 --- a/lib/nfc/nfc_device.c +++ b/lib/nfc/nfc_device.c @@ -63,6 +63,17 @@ const NfcDeviceData* nfc_device_get_data(const NfcDevice* instance, NfcProtocol return instance->protocol_data; } +const NfcDeviceData* nfc_device_get_base_data(const NfcDevice* instance, NfcProtocol protocol) { + furi_assert(instance); + furi_assert(protocol < NfcProtocolNum); + + if(instance->protocol != protocol) { + furi_crash(NFC_DEV_TYPE_ERROR); + } + + return nfc_devices[protocol]->get_base_data(instance->protocol_data); +} + const char* nfc_device_get_protocol_name(NfcProtocol protocol) { furi_assert(protocol < NfcProtocolNum); @@ -113,6 +124,19 @@ void nfc_device_copy_data( nfc_devices[protocol]->copy(protocol_data, instance->protocol_data); } +bool nfc_device_is_equal(const NfcDevice* instance, const NfcDevice* other) { + furi_assert(instance); + furi_assert(other); + + bool is_equal = false; + if(instance->protocol == other->protocol) { + is_equal = nfc_devices[instance->protocol]->is_equal( + instance->protocol_data, other->protocol_data); + } + + return is_equal; +} + void nfc_device_set_loading_callback( NfcDevice* instance, NfcLoadingCallback callback, diff --git a/lib/nfc/nfc_device.h b/lib/nfc/nfc_device.h index b072a3adcfac..bc90f5a5c641 100644 --- a/lib/nfc/nfc_device.h +++ b/lib/nfc/nfc_device.h @@ -25,6 +25,8 @@ NfcProtocol nfc_device_get_protocol(const NfcDevice* instance); const NfcDeviceData* nfc_device_get_data(const NfcDevice* instance, NfcProtocol protocol); +const NfcDeviceData* nfc_device_get_base_data(const NfcDevice* instance, NfcProtocol protocol); + const char* nfc_device_get_protocol_name(NfcProtocol protocol); const char* nfc_device_get_name(const NfcDevice* instance, NfcDeviceNameType name_type); @@ -41,6 +43,8 @@ void nfc_device_copy_data( NfcProtocol protocol, NfcDeviceData* protocol_data); +bool nfc_device_is_equal(const NfcDevice* instance, const NfcDevice* other); + void nfc_device_set_loading_callback( NfcDevice* instance, NfcLoadingCallback callback, diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a.h b/lib/nfc/protocols/iso14443_3a/iso14443_3a.h index 6a3ce3170e93..2fa99f68f666 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a.h +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a.h @@ -52,16 +52,11 @@ typedef struct { uint8_t sak; } Iso14443_3aSelResp; -typedef struct { - uint8_t sak; -} Iso14443_3aRats; - typedef struct { uint8_t uid[ISO14443_3A_MAX_UID_SIZE]; uint8_t uid_len; uint8_t atqa[2]; uint8_t sak; - Iso14443_3aRats rats; } Iso14443_3aData; extern const NfcDeviceBase nfc_device_iso14443_3a; diff --git a/lib/nfc/protocols/mf_classic/mf_classic.c b/lib/nfc/protocols/mf_classic/mf_classic.c index f139f3eb167e..5bbc63b9519c 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic.c +++ b/lib/nfc/protocols/mf_classic/mf_classic.c @@ -79,9 +79,12 @@ void mf_classic_copy(MfClassicData* data, const MfClassicData* other) { furi_assert(other); iso14443_3a_copy(data->iso14443_3a_data, other->iso14443_3a_data); - memcpy(data->block, other->block, MF_CLASSIC_TOTAL_BLOCKS_MAX); - memcpy(data->block_read_mask, other->block_read_mask, MF_CLASSIC_READ_MASK_SIZE); - + for(size_t i = 0; i < COUNT_OF(data->block); i++) { + data->block[i] = other->block[i]; + } + for(size_t i = 0; i < COUNT_OF(data->block_read_mask); i++) { + data->block_read_mask[i] = other->block_read_mask[i]; + } data->type = other->type; data->key_a_mask = other->key_a_mask; data->key_b_mask = other->key_b_mask; @@ -293,8 +296,35 @@ bool mf_classic_save(const MfClassicData* data, FlipperFormat* ff, uint32_t vers } bool mf_classic_is_equal(const MfClassicData* data, const MfClassicData* other) { - // TODO: Complete equality method - return iso14443_3a_is_equal(data->iso14443_3a_data, other->iso14443_3a_data); + bool is_equal = false; + bool data_array_is_equal = true; + + do { + if(!iso14443_3a_is_equal(data->iso14443_3a_data, other->iso14443_3a_data)) break; + if(data->type != other->type) break; + if(data->key_a_mask != other->key_a_mask) break; + if(data->key_b_mask != other->key_b_mask) break; + + for(size_t i = 0; i < COUNT_OF(data->block_read_mask); i++) { + if(data->block_read_mask[i] != other->block_read_mask[i]) { + data_array_is_equal = false; + break; + } + } + if(!data_array_is_equal) break; + + for(size_t i = 0; i < COUNT_OF(data->block); i++) { + if(memcmp(&data->block[i], &other->block[i], sizeof(data->block[i]))) { + data_array_is_equal = false; + break; + } + } + if(!data_array_is_equal) break; + + is_equal = true; + } while(false); + + return is_equal; } const char* mf_classic_get_device_name(const MfClassicData* data, NfcDeviceNameType name_type) { diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight.c index 067e46a06b74..ebffe1a1bb9a 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight.c @@ -156,9 +156,15 @@ void mf_ultralight_copy(MfUltralightData* data, const MfUltralightData* other) { furi_assert(other); iso14443_3a_copy(data->iso14443_3a_data, other->iso14443_3a_data); - memcpy(data->counter, other->counter, MF_ULTRALIGHT_COUNTER_NUM); - memcpy(data->tearing_flag, other->tearing_flag, MF_ULTRALIGHT_TEARING_FLAG_NUM); - memcpy(data->page, other->page, MF_ULTRALIGHT_MAX_PAGE_NUM); + for(size_t i = 0; i < COUNT_OF(data->counter); i++) { + data->counter[i] = other->counter[i]; + } + for(size_t i = 0; i < COUNT_OF(data->tearing_flag); i++) { + data->tearing_flag[i] = other->tearing_flag[i]; + } + for(size_t i = 0; i < COUNT_OF(data->page); i++) { + data->page[i] = other->page[i]; + } data->type = other->type; data->version = other->version; @@ -371,8 +377,50 @@ bool mf_ultralight_save(const MfUltralightData* data, FlipperFormat* ff, uint32_ } bool mf_ultralight_is_equal(const MfUltralightData* data, const MfUltralightData* other) { - // TODO: Complete equality method - return iso14443_3a_is_equal(data->iso14443_3a_data, other->iso14443_3a_data); + bool is_equal = false; + bool data_array_is_equal = true; + + do { + if(!iso14443_3a_is_equal(data->iso14443_3a_data, other->iso14443_3a_data)) break; + if(data->type != other->type) break; + if(data->pages_read != other->pages_read) break; + if(data->pages_total != other->pages_total) break; + if(data->auth_attempts != other->auth_attempts) break; + + if(memcmp(&data->version, &other->version, sizeof(data->version))) break; + if(memcmp(&data->signature, &other->signature, sizeof(data->signature))) break; + + for(size_t i = 0; i < COUNT_OF(data->counter); i++) { + if(memcmp(&data->counter[i], &other->counter[i], sizeof(data->counter[i]))) { + data_array_is_equal = false; + break; + } + } + if(!data_array_is_equal) break; + + for(size_t i = 0; i < COUNT_OF(data->tearing_flag); i++) { + if(memcmp( + &data->tearing_flag[i], + &other->tearing_flag[i], + sizeof(data->tearing_flag[i]))) { + data_array_is_equal = false; + break; + } + } + if(!data_array_is_equal) break; + + for(size_t i = 0; i < COUNT_OF(data->page); i++) { + if(memcmp(&data->page[i], &other->page[i], sizeof(data->page[i]))) { + data_array_is_equal = false; + break; + } + } + if(!data_array_is_equal) break; + + is_equal = true; + } while(false); + + return is_equal; } // TODO: Improve this function diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h index 420fb6a7eeff..b6b540cbcb97 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h @@ -44,7 +44,7 @@ typedef union { MfUltralightSignature signature; MfUltralightPollerReadCounterCommand counter_cmd; MfUltralightPollerReadTearingFlagCommand tearing_flag_cmd; - MfUltralightData data; + MfUltralightData* data; } MfUltralightPollerContextData; typedef enum { diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c index a4316fbec0ae..72041c6c5408 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c @@ -244,7 +244,7 @@ static NfcCommand mf_ultralight_poller_read_callback(NfcGenericEvent event, void MfUltralightPollerEvent* mfu_event = event.data; if(mfu_event->type == MfUltralightPollerEventTypeReadSuccess) { - mf_ultralight_copy(&poller_context->data.data, mf_ultralight_poller_get_data(mfu_poller)); + mf_ultralight_copy(poller_context->data.data, mf_ultralight_poller_get_data(mfu_poller)); poller_context->error = MfUltralightErrorNone; command = NfcCommandStop; } else if(mfu_event->type == MfUltralightPollerEventTypeReadFailed) { @@ -267,6 +267,7 @@ MfUltralightError mf_ultralight_poller_read_card(Nfc* nfc, MfUltralightData* dat MfUltralightPollerContext poller_context = {}; poller_context.thread_id = furi_thread_get_current_id(); + poller_context.data.data = mf_ultralight_alloc(); NfcPoller* poller = nfc_poller_alloc(nfc, NfcProtocolMfUltralight); nfc_poller_start(poller, mf_ultralight_poller_read_callback, &poller_context); @@ -277,8 +278,10 @@ MfUltralightError mf_ultralight_poller_read_card(Nfc* nfc, MfUltralightData* dat nfc_poller_free(poller); if(poller_context.error == MfUltralightErrorNone) { - mf_ultralight_copy(data, &poller_context.data.data); + mf_ultralight_copy(data, poller_context.data.data); } + mf_ultralight_free(poller_context.data.data); + return poller_context.error; } diff --git a/lib/nfc/protocols/nfcb/nfcb_poller_i .c b/lib/nfc/protocols/nfcb/nfcb_poller_i.c similarity index 100% rename from lib/nfc/protocols/nfcb/nfcb_poller_i .c rename to lib/nfc/protocols/nfcb/nfcb_poller_i.c diff --git a/scripts/lint.py b/scripts/lint.py index 8530209bec08..1fc327e545ad 100755 --- a/scripts/lint.py +++ b/scripts/lint.py @@ -39,6 +39,9 @@ def _filter_lint_directories(dirnames: list[str]): # Skipping 3rd-party code - usually resides in subfolder "lib" if "lib" in dirnames: dirnames.remove("lib") + if "compiled" in dirnames: + dirnames.remove("compiled") + # Skipping hidden folders for dirname in dirnames.copy(): if dirname.startswith("."): From 7df53a2bf7991ff5481643205533b7739b5bed5b Mon Sep 17 00:00:00 2001 From: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Date: Thu, 6 Jul 2023 11:12:14 +0300 Subject: [PATCH 119/149] New NFC GUI (#2848) * Refactored scene-wise protocol support * Remove unneeded methods * Implement all protocols within new scene design * Refactor info and read_success scenes * Re-enable saving files * Fix submenu index weirdness * Fix f18 compilation and api --- .../iso14443_3a/iso14443_3a.c | 116 ++++-- .../iso14443_3a/iso14443_3a_i.h | 4 +- .../iso14443_4a/iso14443_4a.c | 112 ++++-- .../protocol_support/mf_classic/mf_classic.c | 121 ++++-- .../protocol_support/mf_desfire/mf_desfire.c | 120 ++++-- .../mf_ultralight/mf_ultralight.c | 154 +++++--- .../protocol_support/nfc_protocol_support.c | 359 ++++++++++++------ .../protocol_support/nfc_protocol_support.h | 27 +- .../nfc_protocol_support_base.h | 31 +- .../nfc_protocol_support_common.h | 17 +- .../nfc_protocol_support_gui_common.h | 2 +- applications/main/nfc/scenes/nfc_scene_info.c | 19 +- applications/main/nfc/scenes/nfc_scene_read.c | 61 +-- .../main/nfc/scenes/nfc_scene_read_menu.c | 26 +- .../main/nfc/scenes/nfc_scene_read_success.c | 26 +- .../main/nfc/scenes/nfc_scene_saved_menu.c | 26 +- firmware/targets/f18/api_symbols.csv | 66 +++- firmware/targets/f18/target.json | 8 +- 18 files changed, 794 insertions(+), 501 deletions(-) diff --git a/applications/main/nfc/helpers/protocol_support/iso14443_3a/iso14443_3a.c b/applications/main/nfc/helpers/protocol_support/iso14443_3a/iso14443_3a.c index 6dd83ab16e13..0cd53005f320 100644 --- a/applications/main/nfc/helpers/protocol_support/iso14443_3a/iso14443_3a.c +++ b/applications/main/nfc/helpers/protocol_support/iso14443_3a/iso14443_3a.c @@ -6,34 +6,67 @@ #include "../nfc_protocol_support_gui_common.h" #include "../../../nfc_app_i.h" -static void nfc_protocol_support_render_info_iso14443_3a( - const Iso14443_3aData* data, - NfcProtocolFormatType format_type, - FuriString* str) { - nfc_render_iso14443_3a_info(data, format_type, str); +static void nfc_scene_info_on_enter_iso14443_3a(NfcApp* instance) { + const NfcDevice* device = instance->nfc_device; + const Iso14443_3aData* data = nfc_device_get_data(device, NfcProtocolIso14443_3a); + + FuriString* temp_str = furi_string_alloc(); + furi_string_cat_printf( + temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull)); + nfc_render_iso14443_3a_info(data, NfcProtocolFormatTypeFull, temp_str); + + widget_add_text_scroll_element( + instance->widget, 0, 0, 128, 64, furi_string_get_cstr(temp_str)); + + furi_string_free(temp_str); } -static NfcCustomEvent - nfc_protocol_support_handle_poller_iso14443_3a(Iso14443_3aPollerEvent* event, void* context) { - UNUSED(context); - NfcCustomEvent custom_event = NfcCustomEventReadHandlerIgnore; +static NfcCommand + nfc_scene_read_poller_callback_iso14443_3a(NfcGenericEvent event, void* context) { + furi_assert(event.protocol == NfcProtocolIso14443_3a); + + NfcApp* instance = context; + const Iso14443_3aPollerEvent* iso14443_3a_event = event.data; - if(event->type == Iso14443_3aPollerEventTypeReady) { - custom_event = NfcCustomEventReadHandlerSuccess; + if(iso14443_3a_event->type == Iso14443_3aPollerEventTypeReady) { + nfc_device_set_data( + instance->nfc_device, NfcProtocolIso14443_3a, nfc_poller_get_data(instance->poller)); + view_dispatcher_send_custom_event( + instance->view_dispatcher, NfcCustomEventReadHandlerSuccess); + return NfcCommandStop; } - return custom_event; + return NfcCommandContinue; } -static void nfc_protocol_support_build_scene_read_menu_iso14443_3a(NfcApp* instance) { +static void nfc_scene_read_on_enter_iso14443_3a(NfcApp* instance) { + nfc_poller_start(instance->poller, nfc_scene_read_poller_callback_iso14443_3a, instance); +} + +static void nfc_scene_read_menu_on_enter_iso14443_3a(NfcApp* instance) { UNUSED(instance); } -static void nfc_protocol_support_build_scene_saved_menu_iso14443_3a(NfcApp* instance) { +static void nfc_scene_read_success_on_enter_iso14443_3a(NfcApp* instance) { + const NfcDevice* device = instance->nfc_device; + const Iso14443_3aData* data = nfc_device_get_data(device, NfcProtocolIso14443_3a); + + FuriString* temp_str = furi_string_alloc(); + furi_string_cat_printf( + temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull)); + nfc_render_iso14443_3a_info(data, NfcProtocolFormatTypeShort, temp_str); + + widget_add_text_scroll_element( + instance->widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); + + furi_string_free(temp_str); +} + +static void nfc_scene_saved_menu_on_enter_iso14443_3a(NfcApp* instance) { UNUSED(instance); } -static bool nfc_protocol_support_handle_scene_info_iso14443_3a(NfcApp* instance, uint32_t event) { +static bool nfc_scene_info_on_event_iso14443_3a(NfcApp* instance, uint32_t event) { if(event == GuiButtonTypeRight) { scene_manager_next_scene(instance->scene_manager, NfcSceneNotImplemented); return true; @@ -42,8 +75,7 @@ static bool nfc_protocol_support_handle_scene_info_iso14443_3a(NfcApp* instance, return false; } -static bool - nfc_protocol_support_handle_scene_read_menu_iso14443_3a(NfcApp* instance, uint32_t event) { +static bool nfc_scene_read_menu_on_event_iso14443_3a(NfcApp* instance, uint32_t event) { if(event == SubmenuIndexCommonEmulate) { scene_manager_next_scene(instance->scene_manager, NfcSceneNfcaEmulate); return true; @@ -52,9 +84,7 @@ static bool return false; } -bool nfc_protocol_support_handle_scene_saved_menu_iso14443_3a_common( - NfcApp* instance, - uint32_t event) { +bool nfc_scene_saved_menu_on_event_iso14443_3a_common(NfcApp* instance, uint32_t event) { switch(event) { case SubmenuIndexCommonEmulate: scene_manager_next_scene(instance->scene_manager, NfcSceneNfcaEmulate); @@ -67,28 +97,36 @@ bool nfc_protocol_support_handle_scene_saved_menu_iso14443_3a_common( } } -static bool - nfc_protocol_support_handle_scene_saved_menu_iso14443_3a(NfcApp* instance, uint32_t event) { - return nfc_protocol_support_handle_scene_saved_menu_iso14443_3a_common(instance, event); +static bool nfc_scene_saved_menu_on_event_iso14443_3a(NfcApp* instance, uint32_t event) { + return nfc_scene_saved_menu_on_event_iso14443_3a_common(instance, event); } const NfcProtocolSupportBase nfc_protocol_support_iso14443_3a = { .features = NfcProtocolFeatureEmulateUid | NfcProtocolFeatureEditUid, - .render_info = (NfcProtocolSupportRenderData)nfc_protocol_support_render_info_iso14443_3a, - - .handle_poller = - (NfcProtocolSupportPollerHandler)nfc_protocol_support_handle_poller_iso14443_3a, - - .build_scene_read_menu = - (NfcProtocolSupportSceneBuilder)nfc_protocol_support_build_scene_read_menu_iso14443_3a, - .build_scene_saved_menu = - (NfcProtocolSupportSceneBuilder)nfc_protocol_support_build_scene_saved_menu_iso14443_3a, - - .handle_scene_info = - (NfcProtocolSupportSceneHandler)nfc_protocol_support_handle_scene_info_iso14443_3a, - .handle_scene_read_menu = - (NfcProtocolSupportSceneHandler)nfc_protocol_support_handle_scene_read_menu_iso14443_3a, - .handle_scene_saved_menu = - (NfcProtocolSupportSceneHandler)nfc_protocol_support_handle_scene_saved_menu_iso14443_3a, + .scene_info = + { + .on_enter = nfc_scene_info_on_enter_iso14443_3a, + .on_event = nfc_scene_info_on_event_iso14443_3a, + }, + .scene_read = + { + .on_enter = nfc_scene_read_on_enter_iso14443_3a, + .on_event = NULL, + }, + .scene_read_menu = + { + .on_enter = nfc_scene_read_menu_on_enter_iso14443_3a, + .on_event = nfc_scene_read_menu_on_event_iso14443_3a, + }, + .scene_read_success = + { + .on_enter = nfc_scene_read_success_on_enter_iso14443_3a, + .on_event = NULL, + }, + .scene_saved_menu = + { + .on_enter = nfc_scene_saved_menu_on_enter_iso14443_3a, + .on_event = nfc_scene_saved_menu_on_event_iso14443_3a, + }, }; diff --git a/applications/main/nfc/helpers/protocol_support/iso14443_3a/iso14443_3a_i.h b/applications/main/nfc/helpers/protocol_support/iso14443_3a/iso14443_3a_i.h index 2c41d475f0d1..e087d71d997b 100644 --- a/applications/main/nfc/helpers/protocol_support/iso14443_3a/iso14443_3a_i.h +++ b/applications/main/nfc/helpers/protocol_support/iso14443_3a/iso14443_3a_i.h @@ -4,6 +4,4 @@ #include "iso14443_3a.h" -bool nfc_protocol_support_handle_scene_saved_menu_iso14443_3a_common( - NfcApp* instance, - uint32_t event); +bool nfc_scene_saved_menu_on_event_iso14443_3a_common(NfcApp* instance, uint32_t event); diff --git a/applications/main/nfc/helpers/protocol_support/iso14443_4a/iso14443_4a.c b/applications/main/nfc/helpers/protocol_support/iso14443_4a/iso14443_4a.c index 854ed483e7ad..e7a4012867e1 100644 --- a/applications/main/nfc/helpers/protocol_support/iso14443_4a/iso14443_4a.c +++ b/applications/main/nfc/helpers/protocol_support/iso14443_4a/iso14443_4a.c @@ -7,34 +7,67 @@ #include "../iso14443_3a/iso14443_3a_i.h" #include "../../../nfc_app_i.h" -static void nfc_protocol_support_render_info_iso14443_4a( - const Iso14443_4aData* data, - NfcProtocolFormatType format_type, - FuriString* str) { - nfc_render_iso14443_4a_info(data, format_type, str); +static void nfc_scene_info_on_enter_iso14443_4a(NfcApp* instance) { + const NfcDevice* device = instance->nfc_device; + const Iso14443_4aData* data = nfc_device_get_data(device, NfcProtocolIso14443_4a); + + FuriString* temp_str = furi_string_alloc(); + furi_string_cat_printf( + temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull)); + nfc_render_iso14443_4a_info(data, NfcProtocolFormatTypeFull, temp_str); + + widget_add_text_scroll_element( + instance->widget, 0, 0, 128, 64, furi_string_get_cstr(temp_str)); + + furi_string_free(temp_str); } -static NfcCustomEvent - nfc_protocol_support_handle_poller_iso14443_4a(Iso14443_4aPollerEvent* event, void* context) { - UNUSED(context); - NfcCustomEvent custom_event = NfcCustomEventReadHandlerIgnore; +static NfcCommand + nfc_scene_read_poller_callback_iso14443_4a(NfcGenericEvent event, void* context) { + furi_assert(event.protocol == NfcProtocolIso14443_4a); + + NfcApp* instance = context; + const Iso14443_4aPollerEvent* iso14443_4a_event = event.data; - if(event->type == Iso14443_4aPollerEventTypeReady) { - custom_event = NfcCustomEventReadHandlerSuccess; + if(iso14443_4a_event->type == Iso14443_4aPollerEventTypeReady) { + nfc_device_set_data( + instance->nfc_device, NfcProtocolIso14443_4a, nfc_poller_get_data(instance->poller)); + view_dispatcher_send_custom_event( + instance->view_dispatcher, NfcCustomEventReadHandlerSuccess); + return NfcCommandStop; } - return custom_event; + return NfcCommandContinue; } -static void nfc_protocol_support_build_scene_read_menu_iso14443_4a(NfcApp* instance) { +static void nfc_scene_read_on_enter_iso14443_4a(NfcApp* instance) { + nfc_poller_start(instance->poller, nfc_scene_read_poller_callback_iso14443_4a, instance); +} + +static void nfc_scene_read_menu_on_enter_iso14443_4a(NfcApp* instance) { UNUSED(instance); } -static void nfc_protocol_support_build_scene_saved_menu_iso14443_4a(NfcApp* instance) { +static void nfc_scene_read_success_on_enter_iso14443_4a(NfcApp* instance) { + const NfcDevice* device = instance->nfc_device; + const Iso14443_4aData* data = nfc_device_get_data(device, NfcProtocolIso14443_4a); + + FuriString* temp_str = furi_string_alloc(); + furi_string_cat_printf( + temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull)); + nfc_render_iso14443_4a_info(data, NfcProtocolFormatTypeShort, temp_str); + + widget_add_text_scroll_element( + instance->widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); + + furi_string_free(temp_str); +} + +static void nfc_scene_saved_menu_on_enter_iso14443_4a(NfcApp* instance) { UNUSED(instance); } -static bool nfc_protocol_support_handle_scene_info_iso14443_4a(NfcApp* instance, uint32_t event) { +static bool nfc_scene_info_on_event_iso14443_4a(NfcApp* instance, uint32_t event) { if(event == GuiButtonTypeRight) { scene_manager_next_scene(instance->scene_manager, NfcSceneNotImplemented); return true; @@ -43,8 +76,7 @@ static bool nfc_protocol_support_handle_scene_info_iso14443_4a(NfcApp* instance, return false; } -static bool - nfc_protocol_support_handle_scene_read_menu_iso14443_4a(NfcApp* instance, uint32_t event) { +static bool nfc_scene_read_menu_on_event_iso14443_4a(NfcApp* instance, uint32_t event) { if(event == SubmenuIndexCommonEmulate) { scene_manager_next_scene(instance->scene_manager, NfcSceneNfcaEmulate); return true; @@ -53,28 +85,36 @@ static bool return false; } -static bool - nfc_protocol_support_handle_scene_saved_menu_iso14443_4a(NfcApp* instance, uint32_t event) { - return nfc_protocol_support_handle_scene_saved_menu_iso14443_3a_common(instance, event); +static bool nfc_scene_saved_menu_on_event_iso14443_4a(NfcApp* instance, uint32_t event) { + return nfc_scene_saved_menu_on_event_iso14443_3a_common(instance, event); } const NfcProtocolSupportBase nfc_protocol_support_iso14443_4a = { .features = NfcProtocolFeatureEmulateUid | NfcProtocolFeatureEditUid, - .render_info = (NfcProtocolSupportRenderData)nfc_protocol_support_render_info_iso14443_4a, - - .handle_poller = - (NfcProtocolSupportPollerHandler)nfc_protocol_support_handle_poller_iso14443_4a, - - .build_scene_read_menu = - (NfcProtocolSupportSceneBuilder)nfc_protocol_support_build_scene_read_menu_iso14443_4a, - .build_scene_saved_menu = - (NfcProtocolSupportSceneBuilder)nfc_protocol_support_build_scene_saved_menu_iso14443_4a, - - .handle_scene_info = - (NfcProtocolSupportSceneHandler)nfc_protocol_support_handle_scene_info_iso14443_4a, - .handle_scene_read_menu = - (NfcProtocolSupportSceneHandler)nfc_protocol_support_handle_scene_read_menu_iso14443_4a, - .handle_scene_saved_menu = - (NfcProtocolSupportSceneHandler)nfc_protocol_support_handle_scene_saved_menu_iso14443_4a, + .scene_info = + { + .on_enter = nfc_scene_info_on_enter_iso14443_4a, + .on_event = nfc_scene_info_on_event_iso14443_4a, + }, + .scene_read = + { + .on_enter = nfc_scene_read_on_enter_iso14443_4a, + .on_event = NULL, + }, + .scene_read_menu = + { + .on_enter = nfc_scene_read_menu_on_enter_iso14443_4a, + .on_event = nfc_scene_read_menu_on_event_iso14443_4a, + }, + .scene_read_success = + { + .on_enter = nfc_scene_read_success_on_enter_iso14443_4a, + .on_event = NULL, + }, + .scene_saved_menu = + { + .on_enter = nfc_scene_saved_menu_on_enter_iso14443_4a, + .on_event = nfc_scene_saved_menu_on_event_iso14443_4a, + }, }; diff --git a/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c b/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c index 316af9029283..b548853b9353 100644 --- a/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c +++ b/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c @@ -12,24 +12,51 @@ enum { SubmenuIndexUpdate, }; -static void nfc_protocol_support_render_info_mf_classic( - const MfClassicData* data, - NfcProtocolFormatType type, - FuriString* str) { - nfc_render_mf_classic_info(data, type, str); +static void nfc_scene_info_on_enter_mf_classic(NfcApp* instance) { + const NfcDevice* device = instance->nfc_device; + const MfClassicData* data = nfc_device_get_data(device, NfcProtocolMfClassic); + + FuriString* temp_str = furi_string_alloc(); + furi_string_cat_printf( + temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull)); + nfc_render_mf_classic_info(data, NfcProtocolFormatTypeFull, temp_str); + + widget_add_text_scroll_element( + instance->widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); + + widget_add_button_element( + instance->widget, + GuiButtonTypeRight, + "More", + nfc_protocol_support_common_widget_callback, + instance); + + furi_string_free(temp_str); } -static NfcCustomEvent - nfc_protocol_support_handle_poller_mf_classic(MfClassicPollerEvent* event, void* context) { - UNUSED(event); - UNUSED(context); +static NfcCommand nfc_scene_read_poller_callback_mf_classic(NfcGenericEvent event, void* context) { + furi_assert(event.protocol == NfcProtocolMfClassic); + + NfcApp* instance = context; + const MfClassicPollerEvent* mf_classic_event = event.data; - NfcCustomEvent custom_event = NfcCustomEventReadHandlerIgnore; // TODO: Implement read mf_classic using key cache - return custom_event; + if(mf_classic_event->type == MfClassicPollerEventTypeReadComplete) { + nfc_device_set_data( + instance->nfc_device, NfcProtocolMfClassic, nfc_poller_get_data(instance->poller)); + view_dispatcher_send_custom_event( + instance->view_dispatcher, NfcCustomEventReadHandlerSuccess); + return NfcCommandStop; + } + + return NfcCommandContinue; +} + +static void nfc_scene_read_on_enter_mf_classic(NfcApp* instance) { + nfc_poller_start(instance->poller, nfc_scene_read_poller_callback_mf_classic, instance); } -static void nfc_protocol_support_build_scene_read_menu_mf_classic(NfcApp* instance) { +static void nfc_scene_read_menu_on_enter_mf_classic(NfcApp* instance) { Submenu* submenu = instance->submenu; const MfClassicData* data = nfc_device_get_data(instance->nfc_device, NfcProtocolMfClassic); @@ -43,7 +70,22 @@ static void nfc_protocol_support_build_scene_read_menu_mf_classic(NfcApp* instan } } -static void nfc_protocol_support_build_scene_saved_menu_mf_classic(NfcApp* instance) { +static void nfc_scene_read_success_on_enter_mf_classic(NfcApp* instance) { + const NfcDevice* device = instance->nfc_device; + const MfClassicData* data = nfc_device_get_data(device, NfcProtocolMfClassic); + + FuriString* temp_str = furi_string_alloc(); + furi_string_cat_printf( + temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull)); + nfc_render_mf_classic_info(data, NfcProtocolFormatTypeShort, temp_str); + + widget_add_text_scroll_element( + instance->widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); + + furi_string_free(temp_str); +} + +static void nfc_scene_saved_menu_on_enter_mf_classic(NfcApp* instance) { Submenu* submenu = instance->submenu; const MfClassicData* data = nfc_device_get_data(instance->nfc_device, NfcProtocolMfClassic); @@ -69,7 +111,7 @@ static void nfc_protocol_support_build_scene_saved_menu_mf_classic(NfcApp* insta instance); } -static bool nfc_protocol_support_handle_scene_info_mf_classic(NfcApp* instance, uint32_t event) { +static bool nfc_scene_info_on_event_mf_classic(NfcApp* instance, uint32_t event) { if(event == GuiButtonTypeRight) { scene_manager_next_scene(instance->scene_manager, NfcSceneNotImplemented); return true; @@ -78,8 +120,7 @@ static bool nfc_protocol_support_handle_scene_info_mf_classic(NfcApp* instance, return false; } -static bool - nfc_protocol_support_handle_scene_read_menu_mf_classic(NfcApp* instance, uint32_t event) { +static bool nfc_scene_read_menu_on_event_mf_classic(NfcApp* instance, uint32_t event) { switch(event) { case SubmenuIndexCommonEmulate: scene_manager_next_scene(instance->scene_manager, NfcSceneNotImplemented); @@ -93,8 +134,7 @@ static bool } } -static bool - nfc_protocol_support_handle_scene_saved_menu_mf_classic(NfcApp* instance, uint32_t event) { +static bool nfc_scene_saved_menu_on_event_mf_classic(NfcApp* instance, uint32_t event) { switch(event) { case SubmenuIndexCommonEmulate: scene_manager_next_scene(instance->scene_manager, NfcSceneNotImplemented); @@ -114,22 +154,31 @@ static bool } const NfcProtocolSupportBase nfc_protocol_support_mf_classic = { - .features = NfcProtocolFeatureMoreData | NfcProtocolFeatureEmulateFull, - - .render_info = (NfcProtocolSupportRenderData)nfc_protocol_support_render_info_mf_classic, - - .handle_poller = - (NfcProtocolSupportPollerHandler)nfc_protocol_support_handle_poller_mf_classic, - - .build_scene_read_menu = - (NfcProtocolSupportSceneBuilder)nfc_protocol_support_build_scene_read_menu_mf_classic, - .build_scene_saved_menu = - (NfcProtocolSupportSceneBuilder)nfc_protocol_support_build_scene_saved_menu_mf_classic, - - .handle_scene_info = - (NfcProtocolSupportSceneHandler)nfc_protocol_support_handle_scene_info_mf_classic, - .handle_scene_read_menu = - (NfcProtocolSupportSceneHandler)nfc_protocol_support_handle_scene_read_menu_mf_classic, - .handle_scene_saved_menu = - (NfcProtocolSupportSceneHandler)nfc_protocol_support_handle_scene_saved_menu_mf_classic, + .features = NfcProtocolFeatureEmulateFull, + + .scene_info = + { + .on_enter = nfc_scene_info_on_enter_mf_classic, + .on_event = nfc_scene_info_on_event_mf_classic, + }, + .scene_read = + { + .on_enter = nfc_scene_read_on_enter_mf_classic, + .on_event = NULL, + }, + .scene_read_menu = + { + .on_enter = nfc_scene_read_menu_on_enter_mf_classic, + .on_event = nfc_scene_read_menu_on_event_mf_classic, + }, + .scene_read_success = + { + .on_enter = nfc_scene_read_success_on_enter_mf_classic, + .on_event = NULL, + }, + .scene_saved_menu = + { + .on_enter = nfc_scene_saved_menu_on_enter_mf_classic, + .on_event = nfc_scene_saved_menu_on_event_mf_classic, + }, }; diff --git a/applications/main/nfc/helpers/protocol_support/mf_desfire/mf_desfire.c b/applications/main/nfc/helpers/protocol_support/mf_desfire/mf_desfire.c index 14de69e49208..fa5f87af4073 100644 --- a/applications/main/nfc/helpers/protocol_support/mf_desfire/mf_desfire.c +++ b/applications/main/nfc/helpers/protocol_support/mf_desfire/mf_desfire.c @@ -6,34 +6,73 @@ #include "../nfc_protocol_support_gui_common.h" #include "../../../nfc_app_i.h" -static void nfc_protocol_support_render_info_mf_desfire( - const MfDesfireData* data, - NfcProtocolFormatType format_type, - FuriString* str) { - nfc_render_mf_desfire_info(data, format_type, str); +static void nfc_scene_info_on_enter_mf_desfire(NfcApp* instance) { + const NfcDevice* device = instance->nfc_device; + const MfDesfireData* data = nfc_device_get_data(device, NfcProtocolMfDesfire); + + FuriString* temp_str = furi_string_alloc(); + furi_string_cat_printf( + temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull)); + nfc_render_mf_desfire_info(data, NfcProtocolFormatTypeFull, temp_str); + + widget_add_text_scroll_element( + instance->widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); + + widget_add_button_element( + instance->widget, + GuiButtonTypeRight, + "More", + nfc_protocol_support_common_widget_callback, + instance); + + furi_string_free(temp_str); } -static NfcCustomEvent - nfc_protocol_support_handle_poller_mf_desfire(MfDesfirePollerEvent* event, void* context) { - UNUSED(context); - NfcCustomEvent custom_event = NfcCustomEventReadHandlerIgnore; +static NfcCommand nfc_scene_read_poller_callback_mf_desfire(NfcGenericEvent event, void* context) { + furi_assert(event.protocol == NfcProtocolMfDesfire); - if(event->type == MfDesfirePollerEventTypeReadSuccess) { - custom_event = NfcCustomEventReadHandlerSuccess; + NfcApp* instance = context; + const MfDesfirePollerEvent* mf_desfire_event = event.data; + + if(mf_desfire_event->type == MfDesfirePollerEventTypeReadSuccess) { + nfc_device_set_data( + instance->nfc_device, NfcProtocolMfDesfire, nfc_poller_get_data(instance->poller)); + view_dispatcher_send_custom_event( + instance->view_dispatcher, NfcCustomEventReadHandlerSuccess); + return NfcCommandStop; } - return custom_event; + return NfcCommandContinue; +} + +static void nfc_scene_read_on_enter_mf_desfire(NfcApp* instance) { + nfc_poller_start(instance->poller, nfc_scene_read_poller_callback_mf_desfire, instance); } -static void nfc_protocol_support_build_scene_read_menu_mf_desfire(NfcApp* instance) { +static void nfc_scene_read_menu_on_enter_mf_desfire(NfcApp* instance) { UNUSED(instance); } -static void nfc_protocol_support_build_scene_saved_menu_mf_desfire(NfcApp* instance) { +static void nfc_scene_read_success_on_enter_mf_desfire(NfcApp* instance) { + const NfcDevice* device = instance->nfc_device; + const MfDesfireData* data = nfc_device_get_data(device, NfcProtocolMfDesfire); + + FuriString* temp_str = furi_string_alloc(); + furi_string_cat_printf( + temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull)); + nfc_render_mf_desfire_info(data, NfcProtocolFormatTypeShort, temp_str); + + widget_add_text_scroll_element( + instance->widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); + + furi_string_free(temp_str); +} + +static void nfc_scene_saved_menu_on_enter_mf_desfire(NfcApp* instance) { UNUSED(instance); } -static bool nfc_protocol_support_handle_scene_info_mf_desfire(NfcApp* instance, uint32_t event) { +static bool nfc_scene_info_on_event_mf_desfire(NfcApp* instance, uint32_t event) { if(event == GuiButtonTypeRight) { scene_manager_next_scene(instance->scene_manager, NfcSceneMfDesfireData); return true; @@ -42,8 +81,7 @@ static bool nfc_protocol_support_handle_scene_info_mf_desfire(NfcApp* instance, return false; } -static bool - nfc_protocol_support_handle_scene_read_menu_mf_desfire(NfcApp* instance, uint32_t event) { +static bool nfc_scene_read_menu_on_event_mf_desfire(NfcApp* instance, uint32_t event) { if(event == SubmenuIndexCommonEmulate) { scene_manager_next_scene(instance->scene_manager, NfcSceneNfcaEmulate); return true; @@ -52,8 +90,7 @@ static bool return false; } -static bool - nfc_protocol_support_handle_scene_saved_menu_mf_desfire(NfcApp* instance, uint32_t event) { +static bool nfc_scene_saved_menu_on_event_mf_desfire(NfcApp* instance, uint32_t event) { if(event == SubmenuIndexCommonEmulate) { scene_manager_next_scene(instance->scene_manager, NfcSceneNfcaEmulate); return true; @@ -63,22 +100,31 @@ static bool } const NfcProtocolSupportBase nfc_protocol_support_mf_desfire = { - .features = NfcProtocolFeatureMoreData | NfcProtocolFeatureEmulateUid, - - .render_info = (NfcProtocolSupportRenderData)nfc_protocol_support_render_info_mf_desfire, - - .handle_poller = - (NfcProtocolSupportPollerHandler)nfc_protocol_support_handle_poller_mf_desfire, - - .build_scene_read_menu = - (NfcProtocolSupportSceneBuilder)nfc_protocol_support_build_scene_read_menu_mf_desfire, - .build_scene_saved_menu = - (NfcProtocolSupportSceneBuilder)nfc_protocol_support_build_scene_saved_menu_mf_desfire, - - .handle_scene_info = - (NfcProtocolSupportSceneHandler)nfc_protocol_support_handle_scene_info_mf_desfire, - .handle_scene_read_menu = - (NfcProtocolSupportSceneHandler)nfc_protocol_support_handle_scene_read_menu_mf_desfire, - .handle_scene_saved_menu = - (NfcProtocolSupportSceneHandler)nfc_protocol_support_handle_scene_saved_menu_mf_desfire, + .features = NfcProtocolFeatureEmulateUid, + + .scene_info = + { + .on_enter = nfc_scene_info_on_enter_mf_desfire, + .on_event = nfc_scene_info_on_event_mf_desfire, + }, + .scene_read = + { + .on_enter = nfc_scene_read_on_enter_mf_desfire, + .on_event = NULL, + }, + .scene_read_menu = + { + .on_enter = nfc_scene_read_menu_on_enter_mf_desfire, + .on_event = nfc_scene_read_menu_on_event_mf_desfire, + }, + .scene_read_success = + { + .on_enter = nfc_scene_read_success_on_enter_mf_desfire, + .on_event = NULL, + }, + .scene_saved_menu = + { + .on_enter = nfc_scene_saved_menu_on_enter_mf_desfire, + .on_event = nfc_scene_saved_menu_on_event_mf_desfire, + }, }; diff --git a/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c b/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c index 44e53e4cd94d..15b56118d4d3 100644 --- a/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c +++ b/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c @@ -12,55 +12,80 @@ enum { SubmenuIndexUnlockByPassword, }; -static void nfc_protocol_support_render_info_mf_ultralight( - const MfUltralightData* data, - NfcProtocolFormatType format_type, - FuriString* str) { - nfc_render_mf_ultralight_info(data, format_type, str); +static void nfc_scene_info_on_enter_mf_ultralight(NfcApp* instance) { + const NfcDevice* device = instance->nfc_device; + const MfUltralightData* data = nfc_device_get_data(device, NfcProtocolMfUltralight); + + FuriString* temp_str = furi_string_alloc(); + furi_string_cat_printf( + temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull)); + nfc_render_mf_ultralight_info(data, NfcProtocolFormatTypeFull, temp_str); + + widget_add_text_scroll_element( + instance->widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); + + widget_add_button_element( + instance->widget, + GuiButtonTypeRight, + "More", + nfc_protocol_support_common_widget_callback, + instance); + + furi_string_free(temp_str); } -static NfcCustomEvent nfc_protocol_support_handle_poller_mf_ultralight( - MfUltralightPollerEvent* event, - NfcApp* nfc_app) { - NfcCustomEvent custom_event = NfcCustomEventReadHandlerIgnore; +static NfcCommand + nfc_scene_read_poller_callback_mf_ultralight(NfcGenericEvent event, void* context) { + furi_assert(event.protocol == NfcProtocolMfUltralight); - if(event->type == MfUltralightPollerEventTypeReadSuccess) { - custom_event = NfcCustomEventReadHandlerSuccess; - } else if(event->type == MfUltralightPollerEventTypeAuthRequest) { + NfcApp* instance = context; + const MfUltralightPollerEvent* mf_ultralight_event = event.data; + + if(mf_ultralight_event->type == MfUltralightPollerEventTypeReadSuccess) { + nfc_device_set_data( + instance->nfc_device, NfcProtocolMfUltralight, nfc_poller_get_data(instance->poller)); + view_dispatcher_send_custom_event( + instance->view_dispatcher, NfcCustomEventReadHandlerSuccess); + return NfcCommandStop; + } else if(mf_ultralight_event->type == MfUltralightPollerEventTypeAuthRequest) { nfc_device_set_data( - nfc_app->nfc_device, NfcProtocolMfUltralight, nfc_poller_get_data(nfc_app->poller)); + instance->nfc_device, NfcProtocolMfUltralight, nfc_poller_get_data(instance->poller)); const MfUltralightData* data = - nfc_device_get_data(nfc_app->nfc_device, NfcProtocolMfUltralight); - if(nfc_app->mf_ul_auth->type == MfUltralightAuthTypeXiaomii) { + nfc_device_get_data(instance->nfc_device, NfcProtocolMfUltralight); + if(instance->mf_ul_auth->type == MfUltralightAuthTypeXiaomii) { if(mf_ultralight_generate_xiaomi_pass( - nfc_app->mf_ul_auth, + instance->mf_ul_auth, data->iso14443_3a_data->uid, data->iso14443_3a_data->uid_len)) { - event->data->auth_context.skip_auth = false; + mf_ultralight_event->data->auth_context.skip_auth = false; } - } else if(nfc_app->mf_ul_auth->type == MfUltralightAuthTypeAmiibo) { + } else if(instance->mf_ul_auth->type == MfUltralightAuthTypeAmiibo) { if(mf_ultralight_generate_amiibo_pass( - nfc_app->mf_ul_auth, + instance->mf_ul_auth, data->iso14443_3a_data->uid, data->iso14443_3a_data->uid_len)) { - event->data->auth_context.skip_auth = false; + mf_ultralight_event->data->auth_context.skip_auth = false; } - } else if(nfc_app->mf_ul_auth->type == MfUltralightAuthTypeManual) { - event->data->auth_context.skip_auth = false; + } else if(instance->mf_ul_auth->type == MfUltralightAuthTypeManual) { + mf_ultralight_event->data->auth_context.skip_auth = false; } else { - event->data->auth_context.skip_auth = true; + mf_ultralight_event->data->auth_context.skip_auth = true; } - if(!event->data->auth_context.skip_auth) { - event->data->auth_context.password = nfc_app->mf_ul_auth->password; + if(!mf_ultralight_event->data->auth_context.skip_auth) { + mf_ultralight_event->data->auth_context.password = instance->mf_ul_auth->password; } - } else if(event->type == MfUltralightPollerEventTypeAuthSuccess) { - nfc_app->mf_ul_auth->pack = event->data->auth_context.pack; + } else if(mf_ultralight_event->type == MfUltralightPollerEventTypeAuthSuccess) { + instance->mf_ul_auth->pack = mf_ultralight_event->data->auth_context.pack; } - return custom_event; + return NfcCommandContinue; +} + +static void nfc_scene_read_on_enter_mf_ultralight(NfcApp* instance) { + nfc_poller_start(instance->poller, nfc_scene_read_poller_callback_mf_ultralight, instance); } -static void nfc_protocol_support_build_scene_read_menu_mf_ultralight(NfcApp* instance) { +static void nfc_scene_read_menu_on_enter_mf_ultralight(NfcApp* instance) { Submenu* submenu = instance->submenu; const MfUltralightData* data = @@ -76,7 +101,22 @@ static void nfc_protocol_support_build_scene_read_menu_mf_ultralight(NfcApp* ins } } -static void nfc_protocol_support_build_scene_saved_menu_mf_ultralight(NfcApp* instance) { +static void nfc_scene_read_success_on_enter_mf_ultralight(NfcApp* instance) { + const NfcDevice* device = instance->nfc_device; + const MfUltralightData* data = nfc_device_get_data(device, NfcProtocolMfUltralight); + + FuriString* temp_str = furi_string_alloc(); + furi_string_cat_printf( + temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull)); + nfc_render_mf_ultralight_info(data, NfcProtocolFormatTypeShort, temp_str); + + widget_add_text_scroll_element( + instance->widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); + + furi_string_free(temp_str); +} + +static void nfc_scene_saved_menu_on_enter_mf_ultralight(NfcApp* instance) { Submenu* submenu = instance->submenu; const MfUltralightData* data = nfc_device_get_data(instance->nfc_device, NfcProtocolMfUltralight); @@ -98,8 +138,7 @@ static void nfc_protocol_support_build_scene_saved_menu_mf_ultralight(NfcApp* in } } -static bool - nfc_protocol_support_handle_scene_info_mf_ultralight(NfcApp* instance, uint32_t event) { +static bool nfc_scene_info_on_event_mf_ultralight(NfcApp* instance, uint32_t event) { if(event == GuiButtonTypeRight) { scene_manager_next_scene(instance->scene_manager, NfcSceneNotImplemented); return true; @@ -108,8 +147,7 @@ static bool return false; } -static bool - nfc_protocol_support_handle_scene_read_menu_mf_ultralight(NfcApp* instance, uint32_t event) { +static bool nfc_scene_read_menu_on_event_mf_ultralight(NfcApp* instance, uint32_t event) { switch(event) { case SubmenuIndexCommonEmulate: scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightEmulate); @@ -122,8 +160,7 @@ static bool } } -static bool - nfc_protocol_support_handle_scene_saved_menu_mf_ultralight(NfcApp* instance, uint32_t event) { +static bool nfc_scene_saved_menu_on_event_mf_ultralight(NfcApp* instance, uint32_t event) { switch(event) { case SubmenuIndexCommonEmulate: scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightEmulate); @@ -140,22 +177,31 @@ static bool } const NfcProtocolSupportBase nfc_protocol_support_mf_ultralight = { - .features = NfcProtocolFeatureMoreData | NfcProtocolFeatureEmulateFull, - - .render_info = (NfcProtocolSupportRenderData)nfc_protocol_support_render_info_mf_ultralight, - - .handle_poller = - (NfcProtocolSupportPollerHandler)nfc_protocol_support_handle_poller_mf_ultralight, - - .build_scene_read_menu = - (NfcProtocolSupportSceneBuilder)nfc_protocol_support_build_scene_read_menu_mf_ultralight, - .build_scene_saved_menu = - (NfcProtocolSupportSceneBuilder)nfc_protocol_support_build_scene_saved_menu_mf_ultralight, - - .handle_scene_info = - (NfcProtocolSupportSceneHandler)nfc_protocol_support_handle_scene_info_mf_ultralight, - .handle_scene_read_menu = - (NfcProtocolSupportSceneHandler)nfc_protocol_support_handle_scene_read_menu_mf_ultralight, - .handle_scene_saved_menu = - (NfcProtocolSupportSceneHandler)nfc_protocol_support_handle_scene_saved_menu_mf_ultralight, + .features = NfcProtocolFeatureEmulateFull, + + .scene_info = + { + .on_enter = nfc_scene_info_on_enter_mf_ultralight, + .on_event = nfc_scene_info_on_event_mf_ultralight, + }, + .scene_read = + { + .on_enter = nfc_scene_read_on_enter_mf_ultralight, + .on_event = NULL, + }, + .scene_read_menu = + { + .on_enter = nfc_scene_read_menu_on_enter_mf_ultralight, + .on_event = nfc_scene_read_menu_on_event_mf_ultralight, + }, + .scene_read_success = + { + .on_enter = nfc_scene_read_success_on_enter_mf_ultralight, + .on_event = NULL, + }, + .scene_saved_menu = + { + .on_enter = nfc_scene_saved_menu_on_enter_mf_ultralight, + .on_event = nfc_scene_saved_menu_on_event_mf_ultralight, + }, }; diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c index 2ee7993ffaa2..db4591c905f2 100644 --- a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c @@ -5,63 +5,127 @@ #include "../../nfc_app_i.h" +typedef void (*NfcProtocolSupportCommonOnEnter)(NfcApp* instance); +typedef bool (*NfcProtocolSupportCommonOnEvent)(NfcApp* instance, SceneManagerEvent event); +typedef void (*NfcProtocolSupportCommonOnExit)(NfcApp* instance); + +typedef struct { + NfcProtocolSupportCommonOnEnter on_enter; + NfcProtocolSupportCommonOnEvent on_event; + NfcProtocolSupportCommonOnExit on_exit; +} NfcProtocolSupportCommonSceneBase; + +static const NfcProtocolSupportCommonSceneBase nfc_protocol_support_scenes[]; + +// Interface functions +void nfc_protocol_support_on_enter(NfcProtocolSupportScene scene, void* context) { + furi_assert(scene < NfcProtocolSupportSceneCount); + furi_assert(context); + + NfcApp* instance = context; + nfc_protocol_support_scenes[scene].on_enter(instance); +} + +bool nfc_protocol_support_on_event( + NfcProtocolSupportScene scene, + void* context, + SceneManagerEvent event) { + furi_assert(scene < NfcProtocolSupportSceneCount); + furi_assert(context); + + NfcApp* instance = context; + return nfc_protocol_support_scenes[scene].on_event(instance, event); +} + +void nfc_protocol_support_on_exit(NfcProtocolSupportScene scene, void* context) { + furi_assert(scene < NfcProtocolSupportSceneCount); + furi_assert(context); + + NfcApp* instance = context; + nfc_protocol_support_scenes[scene].on_exit(instance); +} + static bool nfc_protocol_support_has_feature(NfcProtocol protocol, NfcProtocolFeature feature) { return nfc_protocol_support[protocol]->features & feature; } -static void nfc_protocol_support_render_info( - const NfcDevice* device, - NfcProtocolFormatType format_type, - FuriString* str) { - const NfcProtocol protocol = nfc_device_get_protocol(device); - const NfcDeviceData* data = nfc_device_get_data(device, protocol); - furi_string_cat_printf(str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull)); - nfc_protocol_support[protocol]->render_info(data, format_type, str); +// Common scene handlers +// SceneInfo +static void nfc_protocol_support_scene_info_on_enter(NfcApp* instance) { + const NfcProtocol protocol = nfc_device_get_protocol(instance->nfc_device); + nfc_protocol_support[protocol]->scene_info.on_enter(instance); + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewWidget); } -NfcCustomEvent nfc_protocol_support_handle_poller(NfcGenericEvent event, void* context) { - furi_assert(context); - NfcApp* nfc_app = context; +static bool nfc_protocol_support_scene_info_on_event(NfcApp* instance, SceneManagerEvent event) { + bool consumed = false; + const NfcProtocol protocol = nfc_device_get_protocol(instance->nfc_device); - NfcCustomEvent custom_event = - nfc_protocol_support[event.protocol]->handle_poller(event.data, context); - if(custom_event == NfcCustomEventReadHandlerSuccess) { - nfc_device_set_data( - nfc_app->nfc_device, event.protocol, nfc_poller_get_data(nfc_app->poller)); + if(event.type == SceneManagerEventTypeCustom) { + consumed = nfc_protocol_support[protocol]->scene_info.on_event(instance, event.event); } - return custom_event; + return consumed; } -// Scene builders +static void nfc_protocol_support_scene_info_on_exit(NfcApp* instance) { + widget_reset(instance->widget); +} -void nfc_protocol_support_build_scene_info(NfcApp* instance) { - const NfcProtocol protocol = nfc_device_get_protocol(instance->nfc_device); - Widget* widget = instance->widget; +// SceneRead +static void nfc_protocol_support_scene_read_on_enter(NfcApp* instance) { + popup_set_header( + instance->popup, "Reading card\nDon't move...", 85, 24, AlignCenter, AlignTop); + popup_set_icon(instance->popup, 12, 23, &A_Loading_24); - FuriString* temp_str = furi_string_alloc(); - nfc_protocol_support_render_info(instance->nfc_device, NfcProtocolFormatTypeFull, temp_str); + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup); - uint8_t text_scroll_height; + const NfcProtocol protocol = instance->protocols_detected[instance->protocols_detected_idx]; + instance->poller = nfc_poller_alloc(instance->nfc, protocol); - if(nfc_protocol_support_has_feature(protocol, NfcProtocolFeatureMoreData)) { - widget_add_button_element( - widget, - GuiButtonTypeRight, - "More", - nfc_protocol_support_common_widget_callback, - instance); - text_scroll_height = 52; - } else { - text_scroll_height = 64; + // Start poller with the appropriate callback + nfc_protocol_support[protocol]->scene_read.on_enter(instance); + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup); + + nfc_blink_detect_start(instance); +} + +static bool nfc_protocol_support_scene_read_on_event(NfcApp* instance, SceneManagerEvent event) { + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventReadHandlerSuccess) { + notification_message(instance->notifications, &sequence_success); + scene_manager_next_scene(instance->scene_manager, NfcSceneReadSuccess); + dolphin_deed(DolphinDeedNfcReadSuccess); + consumed = true; + } else if(event.event == NfcCustomEventReadHandlerFailure) { + if(scene_manager_has_previous_scene(instance->scene_manager, NfcSceneDetect)) { + scene_manager_search_and_switch_to_previous_scene( + instance->scene_manager, NfcSceneDetect); + } + consumed = true; + } + } else if(event.type == SceneManagerEventTypeBack) { + static const uint32_t possible_scenes[] = {NfcSceneSelectProtocol, NfcSceneStart}; + scene_manager_search_and_switch_to_previous_scene_one_of( + instance->scene_manager, possible_scenes, COUNT_OF(possible_scenes)); + consumed = true; } - widget_add_text_scroll_element( - widget, 0, 0, 128, text_scroll_height, furi_string_get_cstr(temp_str)); - furi_string_free(temp_str); + return consumed; +} + +static void nfc_protocol_support_scene_read_on_exit(NfcApp* instance) { + nfc_poller_stop(instance->poller); + nfc_poller_free(instance->poller); + popup_reset(instance->popup); + + nfc_blink_stop(instance); } -void nfc_protocol_support_build_scene_read_menu(NfcApp* instance) { +// SceneReadMenu +static void nfc_protocol_support_scene_read_menu_on_enter(NfcApp* instance) { const NfcProtocol protocol = nfc_device_get_protocol(instance->nfc_device); Submenu* submenu = instance->submenu; @@ -80,9 +144,8 @@ void nfc_protocol_support_build_scene_read_menu(NfcApp* instance) { SubmenuIndexCommonEmulate, nfc_protocol_support_common_submenu_callback, instance); - } - if(nfc_protocol_support_has_feature(protocol, NfcProtocolFeatureEmulateFull)) { + } else if(nfc_protocol_support_has_feature(protocol, NfcProtocolFeatureEmulateFull)) { submenu_add_item( submenu, "Emulate", @@ -91,7 +154,7 @@ void nfc_protocol_support_build_scene_read_menu(NfcApp* instance) { instance); } - nfc_protocol_support[protocol]->build_scene_read_menu(instance); + nfc_protocol_support[protocol]->scene_read_menu.on_enter(instance); submenu_add_item( submenu, @@ -99,24 +162,90 @@ void nfc_protocol_support_build_scene_read_menu(NfcApp* instance) { SubmenuIndexCommonInfo, nfc_protocol_support_common_submenu_callback, instance); + + submenu_set_selected_item( + instance->submenu, + scene_manager_get_scene_state(instance->scene_manager, NfcSceneReadMenu)); + + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewMenu); } -void nfc_protocol_support_build_scene_read_success(NfcApp* instance) { - Widget* widget = instance->widget; +static bool + nfc_protocol_support_scene_read_menu_on_event(NfcApp* instance, SceneManagerEvent event) { + if(event.type == SceneManagerEventTypeCustom) { + scene_manager_set_scene_state(instance->scene_manager, NfcSceneReadMenu, event.event); + + const NfcProtocol protocol = nfc_device_get_protocol(instance->nfc_device); + + switch(event.event) { + case SubmenuIndexCommonSave: + scene_manager_next_scene(instance->scene_manager, NfcSceneSaveName); + return true; + case SubmenuIndexCommonInfo: + scene_manager_next_scene(instance->scene_manager, NfcSceneInfo); + return true; + case SubmenuIndexCommonEmulate: + dolphin_deed(DolphinDeedNfcEmulate); + // FALLTHRU + default: + return nfc_protocol_support[protocol]->scene_read_menu.on_event(instance, event.event); + } + + } else if(event.type == SceneManagerEventTypeBack) { + scene_manager_set_scene_state(instance->scene_manager, NfcSceneSavedMenu, 0); + } - FuriString* temp_str = furi_string_alloc(); - nfc_protocol_support_render_info(instance->nfc_device, NfcProtocolFormatTypeShort, temp_str); + return false; +} + +static void nfc_protocol_support_scene_read_menu_on_exit(NfcApp* instance) { + submenu_reset(instance->submenu); +} + +// SceneReadSuccess +static void nfc_protocol_support_scene_read_success_on_enter(NfcApp* instance) { + Widget* widget = instance->widget; - widget_add_text_scroll_element(widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); - furi_string_free(temp_str); + const NfcProtocol protocol = nfc_device_get_protocol(instance->nfc_device); + nfc_protocol_support[protocol]->scene_read_success.on_enter(instance); widget_add_button_element( widget, GuiButtonTypeLeft, "Retry", nfc_protocol_support_common_widget_callback, instance); widget_add_button_element( widget, GuiButtonTypeRight, "More", nfc_protocol_support_common_widget_callback, instance); + + notification_message_block(instance->notifications, &sequence_set_green_255); + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewWidget); } -void nfc_protocol_support_build_scene_saved_menu(NfcApp* instance) { +static bool + nfc_protocol_support_scene_read_success_on_event(NfcApp* instance, SceneManagerEvent event) { + if(event.type == SceneManagerEventTypeCustom) { + switch(event.event) { + case GuiButtonTypeLeft: + scene_manager_next_scene(instance->scene_manager, NfcSceneRetryConfirm); + return true; + case GuiButtonTypeRight: + scene_manager_next_scene(instance->scene_manager, NfcSceneReadMenu); + return true; + default: + return false; + } + } else if(event.type == SceneManagerEventTypeBack) { + scene_manager_next_scene(instance->scene_manager, NfcSceneExitConfirm); + return true; + } + + return false; +} + +static void nfc_protocol_support_scene_read_success_on_exit(NfcApp* instance) { + notification_message_block(instance->notifications, &sequence_reset_green); + widget_reset(instance->widget); +} + +// SceneSavedMenu +static void nfc_protocol_support_scene_saved_menu_on_enter(NfcApp* instance) { const NfcProtocol protocol = nfc_device_get_protocol(instance->nfc_device); Submenu* submenu = instance->submenu; @@ -129,9 +258,8 @@ void nfc_protocol_support_build_scene_saved_menu(NfcApp* instance) { SubmenuIndexCommonEmulate, nfc_protocol_support_common_submenu_callback, instance); - } - if(nfc_protocol_support_has_feature(protocol, NfcProtocolFeatureEmulateFull)) { + } else if(nfc_protocol_support_has_feature(protocol, NfcProtocolFeatureEmulateFull)) { submenu_add_item( submenu, "Emulate", @@ -150,7 +278,7 @@ void nfc_protocol_support_build_scene_saved_menu(NfcApp* instance) { } // Protocol-dependent menu items - nfc_protocol_support[protocol]->build_scene_saved_menu(instance); + nfc_protocol_support[protocol]->scene_saved_menu.on_enter(instance); // Trailer submenu items submenu_add_item( @@ -173,69 +301,86 @@ void nfc_protocol_support_build_scene_saved_menu(NfcApp* instance) { instance); // TODO: Implement restore from shadow file -} -// Scene handlers + submenu_set_selected_item( + instance->submenu, + scene_manager_get_scene_state(instance->scene_manager, NfcSceneSavedMenu)); -bool nfc_protocol_support_handle_scene_info(NfcApp* instance, uint32_t event) { - const NfcProtocol protocol = nfc_device_get_protocol(instance->nfc_device); - return nfc_protocol_support[protocol]->handle_scene_info(instance, event); + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewMenu); } -bool nfc_protocol_support_handle_scene_read_menu(NfcApp* instance, uint32_t event) { - const NfcProtocol protocol = nfc_device_get_protocol(instance->nfc_device); +static bool + nfc_protocol_support_scene_saved_menu_on_event(NfcApp* instance, SceneManagerEvent event) { + if(event.type == SceneManagerEventTypeCustom) { + scene_manager_set_scene_state(instance->scene_manager, NfcSceneSavedMenu, event.event); + + const NfcProtocol protocol = nfc_device_get_protocol(instance->nfc_device); + + // TODO: Implement restore from shadow file + + switch(event.event) { + case SubmenuIndexCommonInfo: + scene_manager_next_scene(instance->scene_manager, NfcSceneInfo); + return true; + case SubmenuIndexCommonRename: + scene_manager_next_scene(instance->scene_manager, NfcSceneSaveName); + return true; + case SubmenuIndexCommonDelete: + scene_manager_next_scene(instance->scene_manager, NfcSceneDelete); + return true; + case SubmenuIndexCommonEmulate: + if(scene_manager_has_previous_scene(instance->scene_manager, NfcSceneSetType)) { + dolphin_deed(DolphinDeedNfcAddEmulate); + } else { + dolphin_deed(DolphinDeedNfcEmulate); + } + // FALLTHRU + default: + return nfc_protocol_support[protocol]->scene_saved_menu.on_event( + instance, event.event); + } - switch(event) { - case SubmenuIndexCommonSave: - scene_manager_next_scene(instance->scene_manager, NfcSceneNotImplemented); - return true; - case SubmenuIndexCommonInfo: - scene_manager_next_scene(instance->scene_manager, NfcSceneInfo); - return true; - case SubmenuIndexCommonEmulate: - dolphin_deed(DolphinDeedNfcEmulate); - // FALLTHRU - default: - return nfc_protocol_support[protocol]->handle_scene_read_menu(instance, event); + } else if(event.type == SceneManagerEventTypeBack) { + scene_manager_set_scene_state(instance->scene_manager, NfcSceneSavedMenu, 0); } -} -bool nfc_protocol_support_handle_scene_read_success(NfcApp* instance, uint32_t event) { - switch(event) { - case GuiButtonTypeLeft: - scene_manager_next_scene(instance->scene_manager, NfcSceneRetryConfirm); - return true; - case GuiButtonTypeRight: - scene_manager_next_scene(instance->scene_manager, NfcSceneReadMenu); - return true; - default: - return false; - } + return false; } -bool nfc_protocol_support_handle_scene_saved_menu(NfcApp* instance, uint32_t event) { - const NfcProtocol protocol = nfc_device_get_protocol(instance->nfc_device); - - // TODO: Implement restore from shadow file - - switch(event) { - case SubmenuIndexCommonInfo: - scene_manager_next_scene(instance->scene_manager, NfcSceneInfo); - return true; - case SubmenuIndexCommonRename: - scene_manager_next_scene(instance->scene_manager, NfcSceneSaveName); - return true; - case SubmenuIndexCommonDelete: - scene_manager_next_scene(instance->scene_manager, NfcSceneDelete); - return true; - case SubmenuIndexCommonEmulate: - if(scene_manager_has_previous_scene(instance->scene_manager, NfcSceneSetType)) { - dolphin_deed(DolphinDeedNfcAddEmulate); - } else { - dolphin_deed(DolphinDeedNfcEmulate); - } - // FALLTHRU - default: - return nfc_protocol_support[protocol]->handle_scene_saved_menu(instance, event); - } +static void nfc_protocol_support_scene_saved_menu_on_exit(NfcApp* instance) { + submenu_reset(instance->submenu); } + +static const NfcProtocolSupportCommonSceneBase + nfc_protocol_support_scenes[NfcProtocolSupportSceneCount] = { + [NfcProtocolSupportSceneInfo] = + { + .on_enter = nfc_protocol_support_scene_info_on_enter, + .on_event = nfc_protocol_support_scene_info_on_event, + .on_exit = nfc_protocol_support_scene_info_on_exit, + }, + [NfcProtocolSupportSceneRead] = + { + .on_enter = nfc_protocol_support_scene_read_on_enter, + .on_event = nfc_protocol_support_scene_read_on_event, + .on_exit = nfc_protocol_support_scene_read_on_exit, + }, + [NfcProtocolSupportSceneReadMenu] = + { + .on_enter = nfc_protocol_support_scene_read_menu_on_enter, + .on_event = nfc_protocol_support_scene_read_menu_on_event, + .on_exit = nfc_protocol_support_scene_read_menu_on_exit, + }, + [NfcProtocolSupportSceneReadSuccess] = + { + .on_enter = nfc_protocol_support_scene_read_success_on_enter, + .on_event = nfc_protocol_support_scene_read_success_on_event, + .on_exit = nfc_protocol_support_scene_read_success_on_exit, + }, + [NfcProtocolSupportSceneSavedMenu] = + { + .on_enter = nfc_protocol_support_scene_saved_menu_on_enter, + .on_event = nfc_protocol_support_scene_saved_menu_on_event, + .on_exit = nfc_protocol_support_scene_saved_menu_on_exit, + }, +}; diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.h b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.h index 75b379426564..c5b295d5759e 100644 --- a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.h +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.h @@ -2,26 +2,11 @@ #include "nfc_protocol_support_common.h" -// Poller handler -NfcCustomEvent nfc_protocol_support_handle_poller(NfcGenericEvent event, void* context); +void nfc_protocol_support_on_enter(NfcProtocolSupportScene scene, void* context); -// Listener handler -// TODO +bool nfc_protocol_support_on_event( + NfcProtocolSupportScene scene, + void* context, + SceneManagerEvent event); -// Scene builders -void nfc_protocol_support_build_scene_info(NfcApp* instance); - -void nfc_protocol_support_build_scene_read_menu(NfcApp* instance); - -void nfc_protocol_support_build_scene_read_success(NfcApp* instance); - -void nfc_protocol_support_build_scene_saved_menu(NfcApp* instance); - -// Scene handlers -bool nfc_protocol_support_handle_scene_info(NfcApp* instance, uint32_t event); - -bool nfc_protocol_support_handle_scene_read_menu(NfcApp* instance, uint32_t event); - -bool nfc_protocol_support_handle_scene_read_success(NfcApp* instance, uint32_t event); - -bool nfc_protocol_support_handle_scene_saved_menu(NfcApp* instance, uint32_t event); +void nfc_protocol_support_on_exit(NfcProtocolSupportScene scene, void* context); diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_base.h b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_base.h index 2123778cd652..1b9c78a9d1d6 100644 --- a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_base.h +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_base.h @@ -4,29 +4,24 @@ #include "nfc_protocol_support_common.h" -typedef void (*NfcProtocolSupportRenderData)( - const NfcDeviceData* data, - NfcProtocolFormatType format_type, - FuriString* str); +typedef void (*NfcProtocolSupportOnEnter)(NfcApp* instance); -typedef NfcCustomEvent ( - *NfcProtocolSupportPollerHandler)(NfcGenericEventData* event_data, void* context); +typedef bool (*NfcProtocolSupportOnEvent)(NfcApp* instance, uint32_t event); -typedef void (*NfcProtocolSupportSceneBuilder)(NfcApp* instance); +typedef void (*NfcProtocolSupportOnExit)(NfcApp* instance); -typedef bool (*NfcProtocolSupportSceneHandler)(NfcApp* instance, uint32_t event); +typedef struct { + NfcProtocolSupportOnEnter on_enter; + NfcProtocolSupportOnEvent on_event; + /*NfcProtocolSupportOnExit on_exit; is not necessary */ +} NfcProtocolSupportSceneBase; typedef struct { const uint32_t features; - NfcProtocolSupportRenderData render_info; - - NfcProtocolSupportPollerHandler handle_poller; - - NfcProtocolSupportSceneBuilder build_scene_read_menu; - NfcProtocolSupportSceneBuilder build_scene_saved_menu; - - NfcProtocolSupportSceneHandler handle_scene_info; - NfcProtocolSupportSceneHandler handle_scene_read_menu; - NfcProtocolSupportSceneHandler handle_scene_saved_menu; + NfcProtocolSupportSceneBase scene_info; + NfcProtocolSupportSceneBase scene_read; + NfcProtocolSupportSceneBase scene_read_menu; + NfcProtocolSupportSceneBase scene_read_success; + NfcProtocolSupportSceneBase scene_saved_menu; } NfcProtocolSupportBase; diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_common.h b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_common.h index 8b9c43abbdd3..cdee870e9ab6 100644 --- a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_common.h +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_common.h @@ -11,8 +11,17 @@ typedef enum { NfcProtocolFeatureNone = 0, - NfcProtocolFeatureMoreData = 1UL << 0, - NfcProtocolFeatureEmulateUid = 1UL << 1, - NfcProtocolFeatureEmulateFull = 1UL << 2, - NfcProtocolFeatureEditUid = 1UL << 3, + NfcProtocolFeatureEmulateUid = 1UL << 0, + NfcProtocolFeatureEmulateFull = 1UL << 1, + NfcProtocolFeatureEditUid = 1UL << 2, } NfcProtocolFeature; + +typedef enum { + NfcProtocolSupportSceneInfo = 0, + NfcProtocolSupportSceneRead, + NfcProtocolSupportSceneReadMenu, + NfcProtocolSupportSceneReadSuccess, + NfcProtocolSupportSceneSavedMenu, + + NfcProtocolSupportSceneCount, +} NfcProtocolSupportScene; diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_gui_common.h b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_gui_common.h index 4f8e12ed79ef..80012ad4fd83 100644 --- a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_gui_common.h +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_gui_common.h @@ -3,10 +3,10 @@ #include enum { + SubmenuIndexCommonSave, SubmenuIndexCommonEmulate, SubmenuIndexCommonEdit, SubmenuIndexCommonInfo, - SubmenuIndexCommonSave, SubmenuIndexCommonRename, SubmenuIndexCommonDelete, SubmenuIndexCommonMax, diff --git a/applications/main/nfc/scenes/nfc_scene_info.c b/applications/main/nfc/scenes/nfc_scene_info.c index 74528833e3b3..6e9d504975f0 100644 --- a/applications/main/nfc/scenes/nfc_scene_info.c +++ b/applications/main/nfc/scenes/nfc_scene_info.c @@ -1,26 +1,13 @@ -#include "../nfc_app_i.h" - #include "../helpers/protocol_support/nfc_protocol_support.h" void nfc_scene_info_on_enter(void* context) { - NfcApp* nfc = context; - - nfc_protocol_support_build_scene_info(nfc); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); + nfc_protocol_support_on_enter(NfcProtocolSupportSceneInfo, context); } bool nfc_scene_info_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - consumed = nfc_protocol_support_handle_scene_info(nfc, event.event); - } - - return consumed; + return nfc_protocol_support_on_event(NfcProtocolSupportSceneInfo, context, event); } void nfc_scene_info_on_exit(void* context) { - NfcApp* nfc = context; - widget_reset(nfc->widget); + nfc_protocol_support_on_exit(NfcProtocolSupportSceneInfo, context); } diff --git a/applications/main/nfc/scenes/nfc_scene_read.c b/applications/main/nfc/scenes/nfc_scene_read.c index 31bb7dd8ef1e..e9603afd1ad5 100644 --- a/applications/main/nfc/scenes/nfc_scene_read.c +++ b/applications/main/nfc/scenes/nfc_scene_read.c @@ -1,68 +1,13 @@ -#include "../nfc_app_i.h" - #include "../helpers/protocol_support/nfc_protocol_support.h" -static NfcCommand nfc_scene_read_poller_callback(NfcGenericEvent event, void* context) { - NfcApp* instance = context; - - const NfcCustomEvent custom_event = nfc_protocol_support_handle_poller(event, context); - view_dispatcher_send_custom_event(instance->view_dispatcher, custom_event); - return custom_event != NfcCustomEventReadHandlerIgnore ? NfcCommandStop : NfcCommandContinue; -} - void nfc_scene_read_on_enter(void* context) { - NfcApp* instance = context; - - popup_set_header( - instance->popup, "Reading card\nDon't move...", 85, 24, AlignCenter, AlignTop); - popup_set_icon(instance->popup, 12, 23, &A_Loading_24); - - view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup); - - const NfcProtocol protocol = instance->protocols_detected[instance->protocols_detected_idx]; - instance->poller = nfc_poller_alloc(instance->nfc, protocol); - nfc_poller_start(instance->poller, nfc_scene_read_poller_callback, instance); - - nfc_blink_detect_start(instance); + nfc_protocol_support_on_enter(NfcProtocolSupportSceneRead, context); } bool nfc_scene_read_on_event(void* context, SceneManagerEvent event) { - NfcApp* instance = context; - - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == NfcCustomEventReadHandlerSuccess) { - notification_message(instance->notifications, &sequence_success); - scene_manager_next_scene(instance->scene_manager, NfcSceneReadSuccess); - dolphin_deed(DolphinDeedNfcReadSuccess); - consumed = true; - } else if(event.event == NfcCustomEventReadHandlerAltRead) { - // TODO: Go to alternative read scene - consumed = true; - } else if(event.event == NfcCustomEventReadHandlerFailure) { - if(scene_manager_has_previous_scene(instance->scene_manager, NfcSceneDetect)) { - scene_manager_search_and_switch_to_previous_scene( - instance->scene_manager, NfcSceneDetect); - } - consumed = true; - } - } else if(event.type == SceneManagerEventTypeBack) { - static const uint32_t possible_scenes[] = {NfcSceneSelectProtocol, NfcSceneStart}; - scene_manager_search_and_switch_to_previous_scene_one_of( - instance->scene_manager, possible_scenes, COUNT_OF(possible_scenes)); - consumed = true; - } - - return consumed; + return nfc_protocol_support_on_event(NfcProtocolSupportSceneRead, context, event); } void nfc_scene_read_on_exit(void* context) { - NfcApp* instance = context; - - nfc_poller_stop(instance->poller); - nfc_poller_free(instance->poller); - popup_reset(instance->popup); - - nfc_blink_stop(instance); + nfc_protocol_support_on_exit(NfcProtocolSupportSceneRead, context); } diff --git a/applications/main/nfc/scenes/nfc_scene_read_menu.c b/applications/main/nfc/scenes/nfc_scene_read_menu.c index bd152e269c08..cba07a485ae5 100644 --- a/applications/main/nfc/scenes/nfc_scene_read_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_read_menu.c @@ -1,33 +1,13 @@ -#include "../nfc_app_i.h" - #include "../helpers/protocol_support/nfc_protocol_support.h" void nfc_scene_read_menu_on_enter(void* context) { - NfcApp* nfc = context; - - nfc_protocol_support_build_scene_read_menu(nfc); - - submenu_set_selected_item( - nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadMenu)); - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); + nfc_protocol_support_on_enter(NfcProtocolSupportSceneReadMenu, context); } bool nfc_scene_read_menu_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - scene_manager_set_scene_state(nfc->scene_manager, NfcSceneReadMenu, event.event); - consumed = nfc_protocol_support_handle_scene_read_menu(nfc, event.event); - } - - return consumed; + return nfc_protocol_support_on_event(NfcProtocolSupportSceneReadMenu, context, event); } void nfc_scene_read_menu_on_exit(void* context) { - NfcApp* nfc = context; - - submenu_reset(nfc->submenu); + nfc_protocol_support_on_exit(NfcProtocolSupportSceneReadMenu, context); } diff --git a/applications/main/nfc/scenes/nfc_scene_read_success.c b/applications/main/nfc/scenes/nfc_scene_read_success.c index f6717c92bf68..5ceada48b5a9 100644 --- a/applications/main/nfc/scenes/nfc_scene_read_success.c +++ b/applications/main/nfc/scenes/nfc_scene_read_success.c @@ -1,33 +1,13 @@ -#include "../nfc_app_i.h" - #include "../helpers/protocol_support/nfc_protocol_support.h" void nfc_scene_read_success_on_enter(void* context) { - NfcApp* nfc = context; - nfc_protocol_support_build_scene_read_success(nfc); - - notification_message_block(nfc->notifications, &sequence_set_green_255); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); + nfc_protocol_support_on_enter(NfcProtocolSupportSceneReadSuccess, context); } bool nfc_scene_read_success_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - consumed = nfc_protocol_support_handle_scene_read_success(nfc, event.event); - } else if(event.type == SceneManagerEventTypeBack) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); - consumed = true; - } - - return consumed; + return nfc_protocol_support_on_event(NfcProtocolSupportSceneReadSuccess, context, event); } void nfc_scene_read_success_on_exit(void* context) { - NfcApp* nfc = context; - - notification_message_block(nfc->notifications, &sequence_reset_green); - widget_reset(nfc->widget); + nfc_protocol_support_on_exit(NfcProtocolSupportSceneReadSuccess, context); } diff --git a/applications/main/nfc/scenes/nfc_scene_saved_menu.c b/applications/main/nfc/scenes/nfc_scene_saved_menu.c index d2ad71ca2155..d367e8ab8610 100644 --- a/applications/main/nfc/scenes/nfc_scene_saved_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_saved_menu.c @@ -1,33 +1,13 @@ -#include "../nfc_app_i.h" - #include "../helpers/protocol_support/nfc_protocol_support.h" void nfc_scene_saved_menu_on_enter(void* context) { - NfcApp* nfc = context; - - nfc_protocol_support_build_scene_saved_menu(nfc); - - submenu_set_selected_item( - nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneSavedMenu)); - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); + nfc_protocol_support_on_enter(NfcProtocolSupportSceneSavedMenu, context); } bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - scene_manager_set_scene_state(nfc->scene_manager, NfcSceneSavedMenu, event.event); - consumed = nfc_protocol_support_handle_scene_saved_menu(nfc, event.event); - } - - return consumed; + return nfc_protocol_support_on_event(NfcProtocolSupportSceneSavedMenu, context, event); } void nfc_scene_saved_menu_on_exit(void* context) { - NfcApp* nfc = context; - - submenu_reset(nfc->submenu); + nfc_protocol_support_on_exit(NfcProtocolSupportSceneSavedMenu, context); } diff --git a/firmware/targets/f18/api_symbols.csv b/firmware/targets/f18/api_symbols.csv index 1884fe433737..3298509d0ad0 100644 --- a/firmware/targets/f18/api_symbols.csv +++ b/firmware/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,32.0,, +Version,+,33.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -56,6 +56,7 @@ Header,+,firmware/targets/f7/furi_hal/furi_hal_spi_types.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_uart.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_usb_cdc.h,, Header,+,firmware/targets/f7/platform_specific/intrinsic_export.h,, +Header,-,firmware/targets/furi_hal_include/f_hal_nfc.h,, Header,+,firmware/targets/furi_hal_include/furi_hal.h,, Header,+,firmware/targets/furi_hal_include/furi_hal_bt.h,, Header,+,firmware/targets/furi_hal_include/furi_hal_bt_hid.h,, @@ -129,6 +130,9 @@ Header,+,lib/mlib/m-rbtree.h,, Header,+,lib/mlib/m-tuple.h,, Header,+,lib/mlib/m-variant.h,, Header,+,lib/music_worker/music_worker.h,, +Header,+,lib/nanopb/pb.h,, +Header,+,lib/nanopb/pb_decode.h,, +Header,+,lib/nanopb/pb_encode.h,, Header,+,lib/one_wire/maxim_crc.h,, Header,+,lib/one_wire/one_wire_host.h,, Header,+,lib/one_wire/one_wire_slave.h,, @@ -689,6 +693,36 @@ Function,+,empty_screen_get_view,View*,EmptyScreen* Function,-,erand48,double,unsigned short[3] Function,-,exit,void,int Function,-,explicit_bzero,void,"void*, size_t" +Function,-,f_hal_nfc_abort,FHalNfcError, +Function,-,f_hal_nfc_acquire,FHalNfcError, +Function,-,f_hal_nfc_event_start,FHalNfcError, +Function,-,f_hal_nfc_init,FHalNfcError, +Function,-,f_hal_nfc_is_hal_ready,FHalNfcError, +Function,-,f_hal_nfc_listen_start,FHalNfcError, +Function,-,f_hal_nfc_listener_disable_auto_col_res,FHalNfcError, +Function,-,f_hal_nfc_listener_sleep,FHalNfcError, +Function,-,f_hal_nfc_listener_tx,FHalNfcError,"const uint8_t*, size_t" +Function,-,f_hal_nfc_low_power_mode_start,FHalNfcError, +Function,-,f_hal_nfc_low_power_mode_stop,FHalNfcError, +Function,-,f_hal_nfc_poller_field_on,FHalNfcError, +Function,-,f_hal_nfc_poller_rx,FHalNfcError,"uint8_t*, size_t, size_t*" +Function,-,f_hal_nfc_poller_tx,FHalNfcError,"const uint8_t*, size_t" +Function,-,f_hal_nfc_poller_tx_custom_parity,FHalNfcError,"const uint8_t*, size_t" +Function,-,f_hal_nfc_release,FHalNfcError, +Function,-,f_hal_nfc_reset_mode,FHalNfcError, +Function,-,f_hal_nfc_set_mask_receive_timer,void,uint32_t +Function,-,f_hal_nfc_set_mode,FHalNfcError,"FHalNfcMode, FHalNfcBitrate" +Function,-,f_hal_nfc_timer_block_tx_is_running,_Bool, +Function,-,f_hal_nfc_timer_block_tx_start,void,uint32_t +Function,-,f_hal_nfc_timer_block_tx_start_us,void,uint32_t +Function,-,f_hal_nfc_timer_block_tx_stop,void, +Function,-,f_hal_nfc_timer_fwt_start,void,uint32_t +Function,-,f_hal_nfc_timer_fwt_stop,void, +Function,-,f_hal_nfc_trx_reset,FHalNfcError, +Function,-,f_hal_nfc_wait_event,FHalNfcEvent,uint32_t +Function,-,f_hal_nfca_receive_sdd_frame,FHalNfcError,"uint8_t*, size_t, size_t*" +Function,-,f_hal_nfca_send_sdd_frame,FHalNfcError,"const uint8_t*, size_t" +Function,-,f_hal_nfca_send_short_frame,FHalNfcError,FHalNfcaShortFrame Function,-,fclose,int,FILE* Function,-,fcloseall,int, Function,-,fdopen,FILE*,"int, const char*" @@ -1028,6 +1062,7 @@ Function,-,furi_hal_mpu_init,void, Function,+,furi_hal_mpu_protect_disable,void,FuriHalMpuRegion Function,+,furi_hal_mpu_protect_no_access,void,"FuriHalMpuRegion, uint32_t, FuriHalMPURegionSize" Function,+,furi_hal_mpu_protect_read_only,void,"FuriHalMpuRegion, uint32_t, FuriHalMPURegionSize" +Function,-,furi_hal_nfca_set_col_res_data,FHalNfcError,"uint8_t*, uint8_t, uint8_t*, uint8_t" Function,-,furi_hal_os_init,void, Function,+,furi_hal_os_tick,void, Function,+,furi_hal_power_check_otg_status,void, @@ -1575,6 +1610,35 @@ Function,+,path_extract_dirname,void,"const char*, FuriString*" Function,+,path_extract_extension,void,"FuriString*, char*, size_t" Function,+,path_extract_filename,void,"FuriString*, FuriString*, _Bool" Function,+,path_extract_filename_no_ext,void,"const char*, FuriString*" +Function,+,pb_close_string_substream,_Bool,"pb_istream_t*, pb_istream_t*" +Function,+,pb_decode,_Bool,"pb_istream_t*, const pb_msgdesc_t*, void*" +Function,+,pb_decode_bool,_Bool,"pb_istream_t*, _Bool*" +Function,+,pb_decode_ex,_Bool,"pb_istream_t*, const pb_msgdesc_t*, void*, unsigned int" +Function,+,pb_decode_fixed32,_Bool,"pb_istream_t*, void*" +Function,+,pb_decode_fixed64,_Bool,"pb_istream_t*, void*" +Function,+,pb_decode_svarint,_Bool,"pb_istream_t*, int64_t*" +Function,+,pb_decode_tag,_Bool,"pb_istream_t*, pb_wire_type_t*, uint32_t*, _Bool*" +Function,+,pb_decode_varint,_Bool,"pb_istream_t*, uint64_t*" +Function,+,pb_decode_varint32,_Bool,"pb_istream_t*, uint32_t*" +Function,+,pb_default_field_callback,_Bool,"pb_istream_t*, pb_ostream_t*, const pb_field_t*" +Function,+,pb_encode,_Bool,"pb_ostream_t*, const pb_msgdesc_t*, const void*" +Function,+,pb_encode_ex,_Bool,"pb_ostream_t*, const pb_msgdesc_t*, const void*, unsigned int" +Function,+,pb_encode_fixed32,_Bool,"pb_ostream_t*, const void*" +Function,+,pb_encode_fixed64,_Bool,"pb_ostream_t*, const void*" +Function,+,pb_encode_string,_Bool,"pb_ostream_t*, const pb_byte_t*, size_t" +Function,+,pb_encode_submessage,_Bool,"pb_ostream_t*, const pb_msgdesc_t*, const void*" +Function,+,pb_encode_svarint,_Bool,"pb_ostream_t*, int64_t" +Function,+,pb_encode_tag,_Bool,"pb_ostream_t*, pb_wire_type_t, uint32_t" +Function,+,pb_encode_tag_for_field,_Bool,"pb_ostream_t*, const pb_field_iter_t*" +Function,+,pb_encode_varint,_Bool,"pb_ostream_t*, uint64_t" +Function,+,pb_get_encoded_size,_Bool,"size_t*, const pb_msgdesc_t*, const void*" +Function,+,pb_istream_from_buffer,pb_istream_t,"const pb_byte_t*, size_t" +Function,+,pb_make_string_substream,_Bool,"pb_istream_t*, pb_istream_t*" +Function,+,pb_ostream_from_buffer,pb_ostream_t,"pb_byte_t*, size_t" +Function,+,pb_read,_Bool,"pb_istream_t*, pb_byte_t*, size_t" +Function,+,pb_release,void,"const pb_msgdesc_t*, void*" +Function,+,pb_skip_field,_Bool,"pb_istream_t*, pb_wire_type_t" +Function,+,pb_write,_Bool,"pb_ostream_t*, const pb_byte_t*, size_t" Function,-,pcTaskGetName,char*,TaskHandle_t Function,-,pcTimerGetName,const char*,TimerHandle_t Function,-,pclose,int,FILE* diff --git a/firmware/targets/f18/target.json b/firmware/targets/f18/target.json index 2d14813f6da0..4b8fac047547 100644 --- a/firmware/targets/f18/target.json +++ b/firmware/targets/f18/target.json @@ -35,12 +35,18 @@ "excluded_sources": [ "furi_hal_infrared.c", "furi_hal_nfc.c", + "f_hal_nfc.c", + "f_hal_nfca.c", + "f_hal_nfc_event.c", + "f_hal_nfc_irq.c", + "f_hal_nfc_timer.c", "furi_hal_rfid.c", "furi_hal_subghz.c" ], "excluded_headers": [ "furi_hal_infrared.h", "furi_hal_nfc.h", + "f_hal_nfc.h", "furi_hal_rfid.h", "furi_hal_subghz.h", "furi_hal_ibutton.h", @@ -54,4 +60,4 @@ "infrared", "st25rfal002" ] -} \ No newline at end of file +} From 69ca0de2670d027f185d0e6027740f58ed17d9e5 Mon Sep 17 00:00:00 2001 From: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Date: Fri, 7 Jul 2023 17:35:41 +0300 Subject: [PATCH 120/149] [NFC] New file format (#2856) * Exclude version parameter for save() * Save nfc files in the new format * Load NFC files in new format (incl. migration), refactor Ultralight * Load and save ATS, fill default if absent * Fix crash when loading/saving Mifare DESfire files with 0 apps * Update NfcFileFormats.md * Rename Mifare Ultralight to NTAG/Ultralight * Fix loading of old Ultralight files --- documentation/file_formats/NfcFileFormats.md | 100 +++++++++--- firmware/targets/f7/api_symbols.csv | 7 +- lib/nfc/nfc_common.h | 4 +- lib/nfc/nfc_device.c | 151 +++++++++++++----- lib/nfc/protocols/iso14443_3a/iso14443_3a.c | 103 ++++++------ lib/nfc/protocols/iso14443_3a/iso14443_3a.h | 7 +- lib/nfc/protocols/iso14443_4a/iso14443_4a.c | 46 +++++- lib/nfc/protocols/iso14443_4a/iso14443_4a.h | 2 +- lib/nfc/protocols/iso14443_4a/iso14443_4a_i.c | 28 ++++ lib/nfc/protocols/iso14443_4a/iso14443_4a_i.h | 2 + lib/nfc/protocols/mf_classic/mf_classic.c | 10 +- lib/nfc/protocols/mf_classic/mf_classic.h | 2 +- lib/nfc/protocols/mf_desfire/mf_desfire.c | 86 +++++----- lib/nfc/protocols/mf_desfire/mf_desfire.h | 2 +- .../protocols/mf_ultralight/mf_ultralight.c | 135 ++++++++++------ .../protocols/mf_ultralight/mf_ultralight.h | 2 +- lib/nfc/protocols/nfc_device_base.h | 2 +- 17 files changed, 451 insertions(+), 238 deletions(-) diff --git a/documentation/file_formats/NfcFileFormats.md b/documentation/file_formats/NfcFileFormats.md index 78c6420ee037..ff3f215e267d 100644 --- a/documentation/file_formats/NfcFileFormats.md +++ b/documentation/file_formats/NfcFileFormats.md @@ -1,44 +1,89 @@ # NFC Flipper File Formats -## NFC-A (UID) + Header +## UID + Header (General format) ### Example Filetype: Flipper NFC device - Version: 3 - # Nfc device type can be UID, Mifare Ultralight, Mifare Classic, Bank card - Device type: UID - # UID, ATQA and SAK are common for all formats - UID: 04 85 92 8A A0 61 81 - ATQA: 00 44 - SAK: 00 + Version: 4 + # Device type can be ISO14443-3A, ISO14443-4A, NTAG/Ultralight, Mifare Classic, Mifare DESFire + Device type: ISO14443-4A + # UID is common for all formats + UID: 04 48 6A 32 33 58 80 + ------------------------- + (Device-specific data) ### Description -This file format is used to store the UID, SAK and ATQA of a NFC-A device. It does not store any internal data, so it can be used for multiple different card types. Also used as a header for other formats. +This file format is used to store the device type and the UID of an NFC device. It does not store any internal data, so it is only used as a header for other formats. Version differences: 1. Initial version, deprecated 2. LSB ATQA (e.g. 4400 instead of 0044) 3. MSB ATQA (current version) +4. Replace UID device type with ISO14443-3A + +## ISO14443-3A + + Filetype: Flipper NFC device + Version: 4 + # Device type can be ISO14443-3A, ISO14443-4A, NTAG/Ultralight, Mifare Classic, Mifare DESFire + Device type: ISO14443-3A + # UID is common for all formats + UID: 34 19 6D 41 14 56 E6 + # ISO14443-3A specific data + ATQA: 00 44 + SAK: 00 -UID can be either 4 or 7 bytes long. ATQA is 2 bytes long. SAK is 1 byte long. +### Description -## Mifare Ultralight/NTAG +This file format is used to store the UID, SAK and ATQA of a ISO14443-3A device. +UID must be either 4 or 7 bytes long. ATQA is 2 bytes long. SAK is 1 byte long. + +Version differences: +None, there are no versions yet. + +## ISO14443-4A ### Example Filetype: Flipper NFC device - Version: 3 - # Nfc device type can be UID, Mifare Ultralight, Mifare Classic - Device type: NTAG216 - # UID, ATQA and SAK are common for all formats + Version: 4 + # Device type can be ISO14443-3A, ISO14443-4A, NTAG/Ultralight, Mifare Classic, Mifare DESFire + Device type: ISO14443-4A + # UID is common for all formats + UID: 04 48 6A 32 33 58 80 + # ISO14443-3A specific data + ATQA: 03 44 + SAK: 20 + # ISO14443-4A specific data + ATS: 06 75 77 81 02 80 + +### Description + +This file format is used to store the UID, SAK and ATQA of a ISO14443-4A device. It also stores the Answer to Select (ATS) data of the card. +ATS must be 6 bytes long. + +Version differences: +None, there are no versions yet. + +## NTAG/Ultralight + +### Example + + Filetype: Flipper NFC device + Version: 4 + # Device type can be ISO14443-3A, ISO14443-4A, NTAG/Ultralight, Mifare Classic, Mifare DESFire + Device type: NTAG/Ultralight + # UID is common for all formats UID: 04 85 90 54 12 98 23 + # ISO14443-3A specific data ATQA: 00 44 SAK: 00 - # Mifare Ultralight specific data - Data format version: 1 + # NTAG/Ultralight specific data + Data format version: 2 + NTAG/Ultralight type: NTAG216 Signature: 1B 84 EB 70 BD 4C BD 1B 1D E4 98 0B 18 58 BD 7C 72 85 B4 E4 7B 38 8E 96 CF 88 6B EE A3 43 AD 90 Mifare version: 00 04 04 02 01 00 13 03 Counter 0: 0 @@ -66,6 +111,8 @@ UID can be either 4 or 7 bytes long. ATQA is 2 bytes long. SAK is 1 byte long. This file format is used to store the UID, SAK and ATQA of a Mifare Ultralight/NTAG device. It also stores the internal data of the card, the signature, the version, and the counters. The data is stored in pages, just like on the card itself. +The "NTAG/Ultralight type" field contains the concrete device type. It must be one of: Mifare Ultralight, Mifare Ultralight 11, Mifare Ultralight 21, NTAG203, NTAG213, NTAG215, NTAG216, NTAG I2C 1K, NTAG I2C 2K, NTAG I2C Plus 1K, NTAG I2C Plus 2K. + The "Signature" field contains the reply of the tag to the READ_SIG command. More on that can be found here: (page 31) The "Mifare version" field is not related to the file format version but to the Mifare Ultralight version. It contains the response of the tag to the GET_VERSION command. More on that can be found here: (page 21) @@ -74,18 +121,20 @@ Other fields are the direct representation of the card's internal state. Learn m Version differences: -1. Current version +1. Mifare Ultralight type is stored directly in Device type field +2. Current version, Mifare Ultralight type is stored in the same-named field ## Mifare Classic ### Example Filetype: Flipper NFC device - Version: 3 - # Nfc device type can be UID, Mifare Ultralight, Mifare Classic + Version: 4 + # Device type can be ISO14443-3A, ISO14443-4A, NTAG/Ultralight, Mifare Classic, Mifare DESFire Device type: Mifare Classic - # UID, ATQA and SAK are common for all formats + # UID is common for all formats UID: BA E2 7C 9D + # ISO14443-3A specific data ATQA: 00 02 SAK: 18 # Mifare Classic specific data @@ -145,13 +194,16 @@ Example: ### Example Filetype: Flipper NFC device - Version: 3 - # Nfc device type can be UID, Mifare Ultralight, Mifare Classic + Version: 4 + # Device type can be ISO14443-3A, ISO14443-4A, NTAG/Ultralight, Mifare Classic, Mifare DESFire Device type: Mifare DESFire - # UID, ATQA and SAK are common for all formats + # UID is common for all formats UID: 04 2F 19 0A CD 66 80 + # ISO14443-3A specific data ATQA: 03 44 SAK: 20 + # ISO14443-4A specific data + ATS: 06 75 77 81 02 80 # Mifare DESFire specific data PICC Version: 04 01 01 12 00 1A 05 04 01 01 02 01 1A 05 04 2F 19 0A CD 66 80 CE ED D4 51 80 31 19 PICC Free Memory: 7520 diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index b28602e2ba3f..6dfb92f63a5b 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,+,33.0,, +Version,+,34.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -1813,8 +1813,7 @@ Function,-,iso14443_3a_is_equal,_Bool,"const Iso14443_3aData*, const Iso14443_3a Function,-,iso14443_3a_load,_Bool,"Iso14443_3aData*, FlipperFormat*, uint32_t" Function,-,iso14443_3a_load_data,_Bool,"Iso14443_3aData*, FlipperFormat*, uint32_t" Function,-,iso14443_3a_reset,void,Iso14443_3aData* -Function,-,iso14443_3a_save,_Bool,"const Iso14443_3aData*, FlipperFormat*, uint32_t" -Function,-,iso14443_3a_save_data,_Bool,"const Iso14443_3aData*, FlipperFormat*, uint32_t" +Function,+,iso14443_3a_save,_Bool,"const Iso14443_3aData*, FlipperFormat*" Function,-,iso14443_3a_trim_crc,void,BitBuffer* Function,-,iso14443_3a_verify,_Bool,"Iso14443_3aData*, const FuriString*" Function,-,isprint,int,int @@ -2018,7 +2017,7 @@ Function,+,mf_classic_is_sector_read,_Bool,"const MfClassicData*, uint8_t" Function,-,mf_classic_is_sector_trailer,_Bool,uint8_t Function,+,mf_classic_load,_Bool,"MfClassicData*, FlipperFormat*, uint32_t" Function,+,mf_classic_reset,void,MfClassicData* -Function,+,mf_classic_save,_Bool,"const MfClassicData*, FlipperFormat*, uint32_t" +Function,+,mf_classic_save,_Bool,"const MfClassicData*, FlipperFormat*" Function,-,mf_classic_set_block_read,void,"MfClassicData*, uint8_t, MfClassicBlock*" Function,-,mf_classic_set_key_found,void,"MfClassicData*, uint8_t, MfClassicKeyType, uint64_t" Function,-,mf_classic_set_key_not_found,void,"MfClassicData*, uint8_t, MfClassicKeyType" diff --git a/lib/nfc/nfc_common.h b/lib/nfc/nfc_common.h index dbc1f42b7486..c6fe19c20340 100644 --- a/lib/nfc/nfc_common.h +++ b/lib/nfc/nfc_common.h @@ -4,8 +4,10 @@ extern "C" { #endif -#define NFC_CURRENT_FORMAT_VERSION (3) #define NFC_LSB_ATQA_FORMAT_VERSION (2) +#define NFC_MINIMUM_SUPPORTED_FORMAT_VERSION NFC_LSB_ATQA_FORMAT_VERSION +#define NFC_UNIFIED_FORMAT_VERSION (4) +#define NFC_CURRENT_FORMAT_VERSION NFC_UNIFIED_FORMAT_VERSION #ifdef __cplusplus } diff --git a/lib/nfc/nfc_device.c b/lib/nfc/nfc_device.c index 53097a5fe77d..98054cb63000 100644 --- a/lib/nfc/nfc_device.c +++ b/lib/nfc/nfc_device.c @@ -7,6 +7,9 @@ #define NFC_FILE_HEADER "Flipper NFC device" #define NFC_DEV_TYPE_ERROR "Protocol type mismatch" +#define NFC_DEVICE_UID_KEY "UID" +#define NFC_DEVICE_TYPE_KEY "Device type" + struct NfcDevice { NfcProtocol protocol; NfcDeviceData* protocol_data; @@ -155,10 +158,8 @@ bool nfc_device_save(NfcDevice* instance, const char* path) { bool saved = false; Storage* storage = furi_record_open(RECORD_STORAGE); - FlipperFormat* file = flipper_format_buffered_file_alloc(storage); - - FuriString* temp_str; - temp_str = furi_string_alloc(); + FlipperFormat* ff = flipper_format_buffered_file_alloc(storage); + FuriString* temp_str = furi_string_alloc(); if(instance->loading_callback) { instance->loading_callback(instance->loading_callback_context, true); @@ -166,20 +167,40 @@ bool nfc_device_save(NfcDevice* instance, const char* path) { do { // Open file - if(!flipper_format_buffered_file_open_always(file, path)) break; + if(!flipper_format_buffered_file_open_always(ff, path)) break; // Write header - if(!flipper_format_write_header_cstr(file, NFC_FILE_HEADER, NFC_CURRENT_FORMAT_VERSION)) + if(!flipper_format_write_header_cstr(ff, NFC_FILE_HEADER, NFC_CURRENT_FORMAT_VERSION)) break; - // Write nfc device type - if(!flipper_format_write_comment_cstr( - file, "Nfc device type can be UID, Mifare Ultralight, Mifare Classic")) + // Write allowed device types + furi_string_printf(temp_str, "%s can be ", NFC_DEVICE_TYPE_KEY); + for(NfcProtocol protocol = 0; protocol < NfcProtocolNum; ++protocol) { + furi_string_cat(temp_str, nfc_devices[protocol]->protocol_name); + if(protocol < NfcProtocolNum - 1) { + furi_string_cat(temp_str, ", "); + } + } + + if(!flipper_format_write_comment(ff, temp_str)) break; + + // Write device type + if(!flipper_format_write_string_cstr( + ff, NFC_DEVICE_TYPE_KEY, nfc_devices[instance->protocol]->protocol_name)) break; - saved = nfc_devices[instance->protocol]->save( - instance->protocol_data, file, NFC_CURRENT_FORMAT_VERSION); + // Write UID + furi_string_printf(temp_str, "%s is common for all formats", NFC_DEVICE_UID_KEY); + if(!flipper_format_write_comment(ff, temp_str)) break; + size_t uid_len; + const uint8_t* uid = nfc_device_get_uid(instance, &uid_len); + if(!flipper_format_write_hex(ff, NFC_DEVICE_UID_KEY, uid, uid_len)) break; + + // Write protocol-dependent data + if(!nfc_devices[instance->protocol]->save(instance->protocol_data, ff)) break; + + saved = true; } while(false); if(instance->loading_callback) { @@ -187,19 +208,91 @@ bool nfc_device_save(NfcDevice* instance, const char* path) { } furi_string_free(temp_str); - flipper_format_free(file); + flipper_format_free(ff); furi_record_close(RECORD_STORAGE); return saved; } +static bool nfc_device_load_unified(NfcDevice* instance, FlipperFormat* ff, uint32_t version) { + bool loaded = false; + + FuriString* temp_str = furi_string_alloc(); + + do { + // Read Nfc device type + if(!flipper_format_read_string(ff, NFC_DEVICE_TYPE_KEY, temp_str)) break; + + // Detect protocol + NfcProtocol protocol; + for(protocol = 0; protocol < NfcProtocolNum; ++protocol) { + if(furi_string_equal(temp_str, nfc_devices[protocol]->protocol_name)) { + break; + } + } + + if(protocol == NfcProtocolNum) break; + + nfc_device_clear(instance); + + instance->protocol = protocol; + instance->protocol_data = nfc_devices[protocol]->alloc(); + + // Load UID + // TODO: move the respective code from ISO14443-3A to here + + // Load data + if(!nfc_devices[protocol]->load(instance->protocol_data, ff, version)) { + nfc_device_clear(instance); + break; + } + + loaded = true; + } while(false); + + furi_string_free(temp_str); + return loaded; +} + +static bool nfc_device_load_legacy(NfcDevice* instance, FlipperFormat* ff, uint32_t version) { + bool loaded = false; + + FuriString* temp_str = furi_string_alloc(); + + do { + // Read Nfc device type + if(!flipper_format_read_string(ff, NFC_DEVICE_TYPE_KEY, temp_str)) break; + + nfc_device_clear(instance); + + // Detect protocol + for(NfcProtocol protocol = 0; protocol < NfcProtocolNum; protocol++) { + instance->protocol = protocol; + instance->protocol_data = nfc_devices[protocol]->alloc(); + + if(nfc_devices[protocol]->verify(instance->protocol_data, temp_str)) { + if(nfc_devices[protocol]->load(instance->protocol_data, ff, version)) { + loaded = true; + break; + } + } + + nfc_device_clear(instance); + } + + } while(false); + + furi_string_free(temp_str); + return loaded; +} + bool nfc_device_load(NfcDevice* instance, const char* path) { furi_assert(instance); furi_assert(path); bool loaded = false; Storage* storage = furi_record_open(RECORD_STORAGE); - FlipperFormat* file = flipper_format_buffered_file_alloc(storage); + FlipperFormat* ff = flipper_format_buffered_file_alloc(storage); FuriString* temp_str; temp_str = furi_string_alloc(); @@ -209,34 +302,20 @@ bool nfc_device_load(NfcDevice* instance, const char* path) { } do { - if(!flipper_format_buffered_file_open_existing(file, path)) break; + if(!flipper_format_buffered_file_open_existing(ff, path)) break; // Read and verify file header uint32_t version = 0; - if(!flipper_format_read_header(file, temp_str, &version)) break; - if(furi_string_cmp_str(temp_str, NFC_FILE_HEADER)) break; - if(version < NFC_LSB_ATQA_FORMAT_VERSION) break; - - // Read Nfc device type - if(!flipper_format_read_string(file, "Device type", temp_str)) break; + if(!flipper_format_read_header(ff, temp_str, &version)) break; - nfc_device_clear(instance); - - for(NfcProtocol i = 0; i < NfcProtocolNum; i++) { - instance->protocol = i; - instance->protocol_data = nfc_devices[i]->alloc(); + if(furi_string_cmp_str(temp_str, NFC_FILE_HEADER)) break; + if(version < NFC_MINIMUM_SUPPORTED_FORMAT_VERSION) break; - if(nfc_devices[i]->verify(instance->protocol_data, temp_str)) { - loaded = nfc_devices[i]->load(instance->protocol_data, file, version); - } + // Select loading method + loaded = (version < NFC_UNIFIED_FORMAT_VERSION) ? + nfc_device_load_legacy(instance, ff, version) : + nfc_device_load_unified(instance, ff, version); - if(loaded) { - break; - } else { - nfc_devices[i]->free(instance->protocol_data); - instance->protocol_data = NULL; - } - } } while(false); if(instance->loading_callback) { @@ -244,7 +323,7 @@ bool nfc_device_load(NfcDevice* instance, const char* path) { } furi_string_free(temp_str); - flipper_format_free(file); + flipper_format_free(ff); furi_record_close(RECORD_STORAGE); return loaded; diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a.c b/lib/nfc/protocols/iso14443_3a/iso14443_3a.c index 5d4e07191410..94739b5b70da 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a.c +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a.c @@ -4,9 +4,14 @@ #include #define ISO14443_3A_CRC_INIT (0x6363) +#define ISO14443_3A_PROTOCOL_NAME_LEGACY "UID" #define ISO14443_3A_PROTOCOL_NAME "ISO14443-3A" #define ISO14443_3A_DEVICE_NAME "Unknown ISO14443-3A Tag" +#define ISO14443_3A_UID_KEY "UID" +#define ISO14443_3A_ATQA_KEY "ATQA" +#define ISO14443_3A_SAK_KEY "SAK" + const NfcDeviceBase nfc_device_iso14443_3a = { .protocol_name = ISO14443_3A_PROTOCOL_NAME, .alloc = (NfcDeviceAlloc)iso14443_3a_alloc, @@ -48,18 +53,57 @@ void iso14443_3a_copy(Iso14443_3aData* data, const Iso14443_3aData* other) { bool iso14443_3a_verify(Iso14443_3aData* data, const FuriString* device_type) { UNUSED(data); - return furi_string_equal(device_type, "UID"); + return furi_string_equal(device_type, ISO14443_3A_PROTOCOL_NAME_LEGACY); } bool iso14443_3a_load(Iso14443_3aData* data, FlipperFormat* ff, uint32_t version) { - return iso14443_3a_load_data(data, ff, version); + furi_assert(data); + + bool parsed = false; + + do { + // TODO: Load UID in nfc_device.c + // if(version < NFC_UNIFIED_FORMAT_VERSION) { + uint32_t uid_len = 0; + if(!flipper_format_get_value_count(ff, ISO14443_3A_UID_KEY, &uid_len)) break; + if(!(uid_len == 4 || uid_len == 7)) break; + + data->uid_len = uid_len; + + if(!flipper_format_read_hex(ff, ISO14443_3A_UID_KEY, data->uid, data->uid_len)) break; + // } + + // Common to all format versions + if(!flipper_format_read_hex(ff, ISO14443_3A_ATQA_KEY, data->atqa, 2)) break; + if(!flipper_format_read_hex(ff, ISO14443_3A_SAK_KEY, &data->sak, 1)) break; + + if(version > NFC_LSB_ATQA_FORMAT_VERSION) { + // Swap ATQA bytes for newer versions + const uint8_t tmp = data->atqa[0]; + data->atqa[0] = data->atqa[1]; + data->atqa[1] = tmp; + } + + parsed = true; + } while(false); + + return parsed; } -bool iso14443_3a_save(const Iso14443_3aData* data, FlipperFormat* ff, uint32_t version) { +bool iso14443_3a_save(const Iso14443_3aData* data, FlipperFormat* ff) { + furi_assert(data); + bool saved = false; + do { - if(!flipper_format_write_string_cstr(ff, "Device type", "UID")) break; - if(!iso14443_3a_save_data(data, ff, version)) break; + // Save ATQA in MSB order for correct companion apps display + const uint8_t atqa[2] = {data->atqa[1], data->atqa[0]}; + if(!flipper_format_write_comment_cstr(ff, ISO14443_3A_PROTOCOL_NAME " specific data")) + break; + + // Write ATQA and SAK + if(!flipper_format_write_hex(ff, ISO14443_3A_ATQA_KEY, atqa, 2)) break; + if(!flipper_format_write_hex(ff, ISO14443_3A_SAK_KEY, &data->sak, 1)) break; saved = true; } while(false); @@ -94,55 +138,6 @@ const Iso14443_3aData* iso14443_3a_get_base_data(const Iso14443_3aData* data) { furi_crash("No base data"); } -bool iso14443_3a_load_data(Iso14443_3aData* data, FlipperFormat* ff, uint32_t version) { - furi_assert(data); - - uint32_t data_cnt = 0; - bool parsed = false; - - do { - if(!flipper_format_get_value_count(ff, "UID", &data_cnt)) break; - if(!(data_cnt == 4 || data_cnt == 7)) break; - data->uid_len = data_cnt; - if(!flipper_format_read_hex(ff, "UID", data->uid, data->uid_len)) break; - if(version == NFC_LSB_ATQA_FORMAT_VERSION) { - if(!flipper_format_read_hex(ff, "ATQA", data->atqa, 2)) break; - } else { - uint8_t atqa[2] = {}; - if(!flipper_format_read_hex(ff, "ATQA", atqa, 2)) break; - data->atqa[0] = atqa[1]; - data->atqa[1] = atqa[0]; - } - if(!flipper_format_read_hex(ff, "SAK", &data->sak, 1)) break; - - parsed = true; - } while(false); - - return parsed; -} - -bool iso14443_3a_save_data(const Iso14443_3aData* data, FlipperFormat* ff, uint32_t version) { - furi_assert(data); - - UNUSED(version); - - bool saved = false; - do { - // Write UID, ATQA, SAK - if(!flipper_format_write_comment_cstr(ff, "UID is common for all formats")) break; - if(!flipper_format_write_hex(ff, "UID", data->uid, data->uid_len)) break; - // Save ATQA in MSB order for correct companion apps display - uint8_t atqa[2] = {data->atqa[1], data->atqa[0]}; - if(!flipper_format_write_comment_cstr(ff, ISO14443_3A_PROTOCOL_NAME " specific fields")) - break; - if(!flipper_format_write_hex(ff, "ATQA", atqa, 2)) break; - if(!flipper_format_write_hex(ff, "SAK", &data->sak, 1)) break; - saved = true; - } while(false); - - return saved; -} - static uint16_t iso14443_3a_get_crc(const uint8_t* buff, uint16_t len) { furi_assert(buff); furi_assert(len); diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a.h b/lib/nfc/protocols/iso14443_3a/iso14443_3a.h index 2fa99f68f666..6873645ffc90 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a.h +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a.h @@ -73,7 +73,7 @@ bool iso14443_3a_verify(Iso14443_3aData* data, const FuriString* device_type); bool iso14443_3a_load(Iso14443_3aData* data, FlipperFormat* ff, uint32_t version); -bool iso14443_3a_save(const Iso14443_3aData* data, FlipperFormat* ff, uint32_t version); +bool iso14443_3a_save(const Iso14443_3aData* data, FlipperFormat* ff); bool iso14443_3a_is_equal(const Iso14443_3aData* data, const Iso14443_3aData* other); @@ -91,11 +91,6 @@ bool iso14443_3a_check_crc(const BitBuffer* buf); void iso14443_3a_trim_crc(BitBuffer* buf); -// TODO: Decide where should these methods go (*_i file?) -bool iso14443_3a_load_data(Iso14443_3aData* data, FlipperFormat* ff, uint32_t version); - -bool iso14443_3a_save_data(const Iso14443_3aData* data, FlipperFormat* ff, uint32_t version); - #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a.c b/lib/nfc/protocols/iso14443_4a/iso14443_4a.c index f1a2e506b4cf..96b8fa57b55c 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a.c +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a.c @@ -4,7 +4,9 @@ #define ISO14443_4A_PROTOCOL_NAME "ISO14443-4A" #define ISO14443_4A_DEVICE_NAME "Unknown ISO14443-4A Tag" -#define ISO14443_4A_ATS_BIT (1 << 5) +#define ISO14443_4A_ATS_BIT (1U << 5) + +#define ISO14443_4A_ATS_KEY "ATS" const NfcDeviceBase nfc_device_iso14443_4a = { .protocol_name = ISO14443_4A_PROTOCOL_NAME, @@ -39,6 +41,7 @@ void iso14443_4a_reset(Iso14443_4aData* data) { furi_assert(data); iso14443_3a_reset(data->iso14443_3a_data); + memset(&data->ats_data, 0, sizeof(Iso14443_4aAtsData)); } void iso14443_4a_copy(Iso14443_4aData* data, const Iso14443_4aData* other) { @@ -53,20 +56,49 @@ bool iso14443_4a_verify(Iso14443_4aData* data, const FuriString* device_type) { UNUSED(data); UNUSED(device_type); - // TODO: implementation + // Empty, unified file format only return false; } bool iso14443_4a_load(Iso14443_4aData* data, FlipperFormat* ff, uint32_t version) { furi_assert(data); - // TODO: handle additional fields - return iso14443_3a_load_data(data->iso14443_3a_data, ff, version); + + bool parsed = false; + + do { + if(!iso14443_3a_load(data->iso14443_3a_data, ff, version)) break; + if(flipper_format_key_exist(ff, ISO14443_4A_ATS_KEY)) { + if(!flipper_format_read_hex( + ff, ISO14443_4A_ATS_KEY, (uint8_t*)&data->ats_data, sizeof(Iso14443_4aAtsData))) + break; + } else { + iso14443_4a_ats_fill_default(&data->ats_data); + } + parsed = true; + } while(false); + + return parsed; } -bool iso14443_4a_save(const Iso14443_4aData* data, FlipperFormat* ff, uint32_t version) { +bool iso14443_4a_save(const Iso14443_4aData* data, FlipperFormat* ff) { furi_assert(data); - // TODO: handle additional fields - return iso14443_3a_save_data(data->iso14443_3a_data, ff, version); + + bool saved = false; + + do { + if(!iso14443_3a_save(data->iso14443_3a_data, ff)) break; + if(!flipper_format_write_comment_cstr(ff, ISO14443_4A_PROTOCOL_NAME " specific data")) + break; + if(!flipper_format_write_hex( + ff, + ISO14443_4A_ATS_KEY, + (const uint8_t*)&data->ats_data, + sizeof(Iso14443_4aAtsData))) + break; + saved = true; + } while(false); + + return saved; } bool iso14443_4a_is_equal(const Iso14443_4aData* data, const Iso14443_4aData* other) { diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a.h b/lib/nfc/protocols/iso14443_4a/iso14443_4a.h index 3b6eee22a27f..3b6bad6b6cef 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a.h +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a.h @@ -45,7 +45,7 @@ bool iso14443_4a_verify(Iso14443_4aData* data, const FuriString* device_type); bool iso14443_4a_load(Iso14443_4aData* data, FlipperFormat* ff, uint32_t version); -bool iso14443_4a_save(const Iso14443_4aData* data, FlipperFormat* ff, uint32_t version); +bool iso14443_4a_save(const Iso14443_4aData* data, FlipperFormat* ff); bool iso14443_4a_is_equal(const Iso14443_4aData* data, const Iso14443_4aData* other); diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_i.c b/lib/nfc/protocols/iso14443_4a/iso14443_4a_i.c index 12222d40bbf2..0878e823ec3d 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_i.c +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_i.c @@ -1,5 +1,23 @@ #include "iso14443_4a_i.h" +// T0 bits +#define ISO14443_4A_ATS_T0_TA1_FLAG (1U << 4) +#define ISO14443_4A_ATS_T0_TB1_FLAG (1U << 5) +#define ISO14443_4A_ATS_T0_TC1_FLAG (1U << 5) +#define ISO14443_4A_ATS_T0_FSCI_32 (2U << 0) +#define ISO14443_4A_ATS_T0_FSCI_64 (5U << 0) + +// TA_1 bits +#define ISO14443_4A_ATS_TA1_SAME_D (1U << 7) + +// TB_1 bits +#define ISO14443_4A_ATS_TB1_SFGI (0U << 0) +#define ISO14443_4A_ATS_TB1_FWI (14U << 4) + +// TC_1 bits +#define ISO14443_4A_ATS_TC1_NAD_FLAG (1U << 0) +#define ISO14443_4A_ATS_TC1_CID_FLAG (1U << 1) + bool iso14443_4a_ats_parse(Iso14443_4aAtsData* data, const BitBuffer* buf) { // TODO better check const bool can_parse = bit_buffer_get_size_bytes(buf) == sizeof(Iso14443_4aAtsData); @@ -8,3 +26,13 @@ bool iso14443_4a_ats_parse(Iso14443_4aAtsData* data, const BitBuffer* buf) { } return can_parse; } + +void iso14443_4a_ats_fill_default(Iso14443_4aAtsData* data) { + data->tl = sizeof(Iso14443_4aAtsData); + data->t0 = ISO14443_4A_ATS_T0_TA1_FLAG | ISO14443_4A_ATS_T0_TB1_FLAG | + ISO14443_4A_ATS_T0_TC1_FLAG | ISO14443_4A_ATS_T0_FSCI_64; + data->ta_1 = ISO14443_4A_ATS_TA1_SAME_D; + data->tb_1 = ISO14443_4A_ATS_TB1_FWI | ISO14443_4A_ATS_TB1_SFGI; + data->tc_1 = ISO14443_4A_ATS_TC1_CID_FLAG; + data->t1 = 0; +} diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_i.h b/lib/nfc/protocols/iso14443_4a/iso14443_4a_i.h index 184b1bbb2809..2bbab55ae8f7 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_i.h +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_i.h @@ -3,3 +3,5 @@ #include "iso14443_4a.h" bool iso14443_4a_ats_parse(Iso14443_4aAtsData* data, const BitBuffer* buf); + +void iso14443_4a_ats_fill_default(Iso14443_4aAtsData* data); diff --git a/lib/nfc/protocols/mf_classic/mf_classic.c b/lib/nfc/protocols/mf_classic/mf_classic.c index 5bbc63b9519c..0eba4722e089 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic.c +++ b/lib/nfc/protocols/mf_classic/mf_classic.c @@ -150,7 +150,7 @@ bool mf_classic_load(MfClassicData* data, FlipperFormat* ff, uint32_t version) { do { // Read ISO14443_3A data - if(!iso14443_3a_load_data(data->iso14443_3a_data, ff, version)) break; + if(!iso14443_3a_load(data->iso14443_3a_data, ff, version)) break; // Read Mifare Classic type if(!flipper_format_read_string(ff, "Mifare Classic type", temp_str)) break; @@ -251,17 +251,15 @@ static void furi_string_trim(block_str); } -bool mf_classic_save(const MfClassicData* data, FlipperFormat* ff, uint32_t version) { +bool mf_classic_save(const MfClassicData* data, FlipperFormat* ff) { furi_assert(data); - UNUSED(version); FuriString* temp_str = furi_string_alloc(); bool saved = false; do { - if(!flipper_format_write_string_cstr(ff, "Device type", "Mifare Classic")) break; - if(!iso14443_3a_save_data(data->iso14443_3a_data, ff, version)) break; - if(!flipper_format_write_string_cstr(ff, "Device type", "")) break; + if(!iso14443_3a_save(data->iso14443_3a_data, ff)) break; + if(!flipper_format_write_comment_cstr(ff, "Mifare Classic specific data")) break; if(!flipper_format_write_string_cstr( ff, "Mifare Classic type", mf_classic_features[data->type].type_name)) diff --git a/lib/nfc/protocols/mf_classic/mf_classic.h b/lib/nfc/protocols/mf_classic/mf_classic.h index 68724459cda4..056f9002bf37 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic.h +++ b/lib/nfc/protocols/mf_classic/mf_classic.h @@ -133,7 +133,7 @@ bool mf_classic_verify(MfClassicData* data, const FuriString* device_type); bool mf_classic_load(MfClassicData* data, FlipperFormat* ff, uint32_t version); -bool mf_classic_save(const MfClassicData* data, FlipperFormat* ff, uint32_t version); +bool mf_classic_save(const MfClassicData* data, FlipperFormat* ff); bool mf_classic_is_equal(const MfClassicData* data, const MfClassicData* other); diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire.c b/lib/nfc/protocols/mf_desfire/mf_desfire.c index 8a3d12f5d05a..64ee75ee274c 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire.c +++ b/lib/nfc/protocols/mf_desfire/mf_desfire.c @@ -109,28 +109,30 @@ bool mf_desfire_load(MfDesfireData* data, FlipperFormat* ff, uint32_t version) { uint32_t application_count; if(!mf_desfire_application_count_load(&application_count, ff)) break; - simple_array_init(data->application_ids, application_count); - if(!mf_desfire_application_ids_load( - simple_array_get(data->application_ids, 0), application_count, ff)) - break; - - simple_array_init(data->applications, application_count); - for(i = 0; i < application_count; ++i) { - const MfDesfireApplicationId* app_id = simple_array_cget(data->application_ids, i); - furi_string_printf( - prefix, - "%s %02x%02x%02x", - MF_DESFIRE_FFF_APP_PREFIX, - app_id->data[0], - app_id->data[1], - app_id->data[2]); - - if(!mf_desfire_application_load( - simple_array_get(data->applications, i), furi_string_get_cstr(prefix), ff)) + if(application_count > 0) { + simple_array_init(data->application_ids, application_count); + if(!mf_desfire_application_ids_load( + simple_array_get(data->application_ids, 0), application_count, ff)) break; - } - if(i != application_count) break; + simple_array_init(data->applications, application_count); + for(i = 0; i < application_count; ++i) { + const MfDesfireApplicationId* app_id = simple_array_cget(data->application_ids, i); + furi_string_printf( + prefix, + "%s %02x%02x%02x", + MF_DESFIRE_FFF_APP_PREFIX, + app_id->data[0], + app_id->data[1], + app_id->data[2]); + + if(!mf_desfire_application_load( + simple_array_get(data->applications, i), furi_string_get_cstr(prefix), ff)) + break; + } + + if(i != application_count) break; + } success = true; } while(false); @@ -139,18 +141,15 @@ bool mf_desfire_load(MfDesfireData* data, FlipperFormat* ff, uint32_t version) { return success; } -bool mf_desfire_save(const MfDesfireData* data, FlipperFormat* ff, uint32_t version) { +bool mf_desfire_save(const MfDesfireData* data, FlipperFormat* ff) { furi_assert(data); - UNUSED(version); FuriString* prefix = furi_string_alloc(); bool success = false; do { - if(!flipper_format_write_string_cstr(ff, "Device type", MF_DESFIRE_PROTOCOL_NAME)) break; - - if(!iso14443_4a_save(data->iso14443_4a_data, ff, version)) break; + if(!iso14443_4a_save(data->iso14443_4a_data, ff)) break; if(!flipper_format_write_comment_cstr(ff, MF_DESFIRE_PROTOCOL_NAME " specific data")) break; @@ -177,25 +176,28 @@ bool mf_desfire_save(const MfDesfireData* data, FlipperFormat* ff, uint32_t vers const uint32_t application_count = simple_array_get_count(data->application_ids); if(!mf_desfire_application_count_save(&application_count, ff)) break; - if(!mf_desfire_application_ids_save( - simple_array_cget(data->application_ids, 0), application_count, ff)) - break; - for(i = 0; i < application_count; ++i) { - const MfDesfireApplicationId* app_id = simple_array_cget(data->application_ids, i); - furi_string_printf( - prefix, - "%s %02x%02x%02x", - MF_DESFIRE_FFF_APP_PREFIX, - app_id->data[0], - app_id->data[1], - app_id->data[2]); - - const MfDesfireApplication* app = simple_array_cget(data->applications, i); - if(!mf_desfire_application_save(app, furi_string_get_cstr(prefix), ff)) break; - } + if(application_count > 0) { + if(!mf_desfire_application_ids_save( + simple_array_cget(data->application_ids, 0), application_count, ff)) + break; - if(i != application_count) break; + for(i = 0; i < application_count; ++i) { + const MfDesfireApplicationId* app_id = simple_array_cget(data->application_ids, i); + furi_string_printf( + prefix, + "%s %02x%02x%02x", + MF_DESFIRE_FFF_APP_PREFIX, + app_id->data[0], + app_id->data[1], + app_id->data[2]); + + const MfDesfireApplication* app = simple_array_cget(data->applications, i); + if(!mf_desfire_application_save(app, furi_string_get_cstr(prefix), ff)) break; + } + + if(i != application_count) break; + } success = true; } while(false); diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire.h b/lib/nfc/protocols/mf_desfire/mf_desfire.h index a7569350e9e1..1b8695b44d24 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire.h +++ b/lib/nfc/protocols/mf_desfire/mf_desfire.h @@ -163,7 +163,7 @@ bool mf_desfire_verify(MfDesfireData* data, const FuriString* device_type); bool mf_desfire_load(MfDesfireData* data, FlipperFormat* ff, uint32_t version); -bool mf_desfire_save(const MfDesfireData* data, FlipperFormat* ff, uint32_t version); +bool mf_desfire_save(const MfDesfireData* data, FlipperFormat* ff); bool mf_desfire_is_equal(const MfDesfireData* data, const MfDesfireData* other); diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight.c index ebffe1a1bb9a..9138cc8fae8b 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight.c @@ -4,23 +4,37 @@ #define MF_ULTRALIGHT_PROTOCOL_NAME "NTAG/Ultralight" +#define MF_ULTRALIGHT_FORMAT_VERSION_KEY "Data format version" +#define MF_ULTRALIGHT_TYPE_KEY MF_ULTRALIGHT_PROTOCOL_NAME " type" +#define MF_ULTRALIGHT_SIGNATURE_KEY "Signature" +#define MF_ULTRALIGHT_MIFARE_VERSION_KEY "Mifare version" +#define MF_ULTRALIGHT_COUNTER_KEY "Counter" +#define MF_ULTRALIGHT_TEARING_KEY "Tearing" +#define MF_ULTRALIGHT_PAGES_TOTAL_KEY "Pages total" +#define MF_ULTRALIGHT_PAGES_READ_KEY "Pages read" +#define MF_ULTRALIGHT_PAGE_KEY "Page" +#define MF_ULTRALIGHT_FAILED_ATTEMPTS_KEY "Failed authentication attempts" + typedef struct { + const char* device_name; uint16_t total_pages; uint16_t config_page; uint32_t feature_set; } MfUltralightFeatures; -static const uint32_t mf_ultralight_data_format_version = 1; +static const uint32_t mf_ultralight_data_format_version = 2; static const MfUltralightFeatures mf_ultralight_features[MfUltralightTypeNum] = { [MfUltralightTypeUnknown] = { + .device_name = "Mifare Ultralight", .total_pages = 16, .config_page = 0, .feature_set = MfUltralightFeatureSupportCompatibleWrite, }, [MfUltralightTypeNTAG203] = { + .device_name = "NTAG203", .total_pages = 42, .config_page = 0, .feature_set = MfUltralightFeatureSupportCompatibleWrite | @@ -28,6 +42,7 @@ static const MfUltralightFeatures mf_ultralight_features[MfUltralightTypeNum] = }, [MfUltralightTypeUL11] = { + .device_name = "Mifare Ultralight 11", .total_pages = 20, .config_page = 16, .feature_set = @@ -39,6 +54,7 @@ static const MfUltralightFeatures mf_ultralight_features[MfUltralightTypeNum] = }, [MfUltralightTypeUL21] = { + .device_name = "Mifare Ultralight 21", .total_pages = 41, .config_page = 37, .feature_set = @@ -50,6 +66,7 @@ static const MfUltralightFeatures mf_ultralight_features[MfUltralightTypeNum] = }, [MfUltralightTypeNTAG213] = { + .device_name = "NTAG213", .total_pages = 45, .config_page = 41, .feature_set = @@ -61,6 +78,7 @@ static const MfUltralightFeatures mf_ultralight_features[MfUltralightTypeNum] = }, [MfUltralightTypeNTAG215] = { + .device_name = "NTAG215", .total_pages = 135, .config_page = 131, .feature_set = @@ -72,6 +90,7 @@ static const MfUltralightFeatures mf_ultralight_features[MfUltralightTypeNum] = }, [MfUltralightTypeNTAG216] = { + .device_name = "NTAG216", .total_pages = 231, .config_page = 227, .feature_set = @@ -83,6 +102,7 @@ static const MfUltralightFeatures mf_ultralight_features[MfUltralightTypeNum] = }, [MfUltralightTypeNTAGI2C1K] = { + .device_name = "NTAG I2C 1K", .total_pages = 231, .config_page = 0, .feature_set = @@ -91,6 +111,7 @@ static const MfUltralightFeatures mf_ultralight_features[MfUltralightTypeNum] = }, [MfUltralightTypeNTAGI2C2K] = { + .device_name = "NTAG I2C 2K", .total_pages = 485, .config_page = 0, .feature_set = @@ -99,6 +120,7 @@ static const MfUltralightFeatures mf_ultralight_features[MfUltralightTypeNum] = }, [MfUltralightTypeNTAGI2CPlus1K] = { + .device_name = "NTAG I2C Plus 1K", .total_pages = 236, .config_page = 227, .feature_set = @@ -108,6 +130,7 @@ static const MfUltralightFeatures mf_ultralight_features[MfUltralightTypeNum] = }, [MfUltralightTypeNTAGI2CPlus2K] = { + .device_name = "NTAG I2C Plus 2K", .total_pages = 492, .config_page = 227, .feature_set = @@ -175,32 +198,14 @@ void mf_ultralight_copy(MfUltralightData* data, const MfUltralightData* other) { data->auth_attempts = other->auth_attempts; } -// TODO: Improve this function -static const char* mf_ultralight_get_device_name_by_type(MfUltralightType type, bool full_name) { - // FIXME: Use a LUT instead of if/switch - if(type == MfUltralightTypeNTAG213) { - return "NTAG213"; - } else if(type == MfUltralightTypeNTAG215) { - return "NTAG215"; - } else if(type == MfUltralightTypeNTAG216) { - return "NTAG216"; - } else if(type == MfUltralightTypeNTAGI2C1K) { - return "NTAG I2C 1K"; - } else if(type == MfUltralightTypeNTAGI2C2K) { - return "NTAG I2C 2K"; - } else if(type == MfUltralightTypeNTAGI2CPlus1K) { - return "NTAG I2C Plus 1K"; - } else if(type == MfUltralightTypeNTAGI2CPlus2K) { - return "NTAG I2C Plus 2K"; - } else if(type == MfUltralightTypeNTAG203) { - return "NTAG203"; - } else if(type == MfUltralightTypeUL11 && full_name) { - return "Mifare Ultralight 11"; - } else if(type == MfUltralightTypeUL21 && full_name) { - return "Mifare Ultralight 21"; - } else { - return "Mifare Ultralight"; +static const char* + mf_ultralight_get_device_name_by_type(MfUltralightType type, NfcDeviceNameType name_type) { + if(name_type == NfcDeviceNameTypeShort && + (type == MfUltralightTypeUL11 || type == MfUltralightTypeUL21)) { + type = MfUltralightTypeUnknown; } + + return mf_ultralight_features[type].device_name; } bool mf_ultralight_verify(MfUltralightData* data, const FuriString* device_type) { @@ -209,8 +214,8 @@ bool mf_ultralight_verify(MfUltralightData* data, const FuriString* device_type) bool verified = false; for(MfUltralightType i = 0; i < MfUltralightTypeNum; i++) { - const char* name = mf_ultralight_get_device_name_by_type(i, true); - verified = furi_string_equal_str(device_type, name); + const char* name = mf_ultralight_get_device_name_by_type(i, NfcDeviceNameTypeFull); + verified = furi_string_equal(device_type, name); if(verified) { data->type = i; break; @@ -228,33 +233,46 @@ bool mf_ultralight_load(MfUltralightData* data, FlipperFormat* ff, uint32_t vers do { // Read ISO14443_3A data - if(!iso14443_3a_load_data(data->iso14443_3a_data, ff, version)) break; + if(!iso14443_3a_load(data->iso14443_3a_data, ff, version)) break; // Read Ultralight specific data // Read Mifare Ultralight format version uint32_t data_format_version = 0; - if(!flipper_format_read_uint32(ff, "Data format version", &data_format_version, 1)) { + if(!flipper_format_read_uint32( + ff, MF_ULTRALIGHT_FORMAT_VERSION_KEY, &data_format_version, 1)) { if(!flipper_format_rewind(ff)) break; } + // Read Mifare Ultralight type + if(data_format_version > 1) { + if(!flipper_format_read_string(ff, MF_ULTRALIGHT_TYPE_KEY, temp_str)) break; + if(!mf_ultralight_verify(data, temp_str)) break; + } + // Read signature if(!flipper_format_read_hex( - ff, "Signature", data->signature.data, sizeof(MfUltralightSignature))) + ff, + MF_ULTRALIGHT_SIGNATURE_KEY, + data->signature.data, + sizeof(MfUltralightSignature))) break; // Read Mifare version if(!flipper_format_read_hex( - ff, "Mifare version", (uint8_t*)&data->version, sizeof(MfUltralightVersion))) + ff, + MF_ULTRALIGHT_MIFARE_VERSION_KEY, + (uint8_t*)&data->version, + sizeof(MfUltralightVersion))) break; // Read counters and tearing flags bool counters_parsed = true; for(size_t i = 0; i < 3; i++) { - furi_string_printf(temp_str, "Counter %d", i); + furi_string_printf(temp_str, "%s %d", MF_ULTRALIGHT_COUNTER_KEY, i); if(!flipper_format_read_uint32( ff, furi_string_get_cstr(temp_str), &data->counter[i].counter, 1)) { counters_parsed = false; break; } - furi_string_printf(temp_str, "Tearing %d", i); + furi_string_printf(temp_str, "%s %d", MF_ULTRALIGHT_TEARING_KEY, i); if(!flipper_format_read_hex( ff, furi_string_get_cstr(temp_str), data->tearing_flag[i].data, 1)) { counters_parsed = false; @@ -264,12 +282,13 @@ bool mf_ultralight_load(MfUltralightData* data, FlipperFormat* ff, uint32_t vers if(!counters_parsed) break; // Read pages uint32_t pages_total = 0; - if(!flipper_format_read_uint32(ff, "Pages total", &pages_total, 1)) break; + if(!flipper_format_read_uint32(ff, MF_ULTRALIGHT_PAGES_TOTAL_KEY, &pages_total, 1)) break; uint32_t pages_read = 0; if(data_format_version < mf_ultralight_data_format_version) { pages_read = pages_total; } else { - if(!flipper_format_read_uint32(ff, "Pages read", &pages_read, 1)) break; + if(!flipper_format_read_uint32(ff, MF_ULTRALIGHT_PAGES_READ_KEY, &pages_read, 1)) + break; } data->pages_total = pages_total; data->pages_read = pages_read; @@ -279,7 +298,7 @@ bool mf_ultralight_load(MfUltralightData* data, FlipperFormat* ff, uint32_t vers bool pages_parsed = true; for(size_t i = 0; i < pages_total; i++) { - furi_string_printf(temp_str, "Page %d", i); + furi_string_printf(temp_str, "%s %d", MF_ULTRALIGHT_PAGE_KEY, i); if(!flipper_format_read_hex( ff, furi_string_get_cstr(temp_str), @@ -293,7 +312,7 @@ bool mf_ultralight_load(MfUltralightData* data, FlipperFormat* ff, uint32_t vers // Read authentication counter if(!flipper_format_read_uint32( - ff, "Failed authentication attempts", &data->auth_attempts, 1)) { + ff, MF_ULTRALIGHT_FAILED_ATTEMPTS_KEY, &data->auth_attempts, 1)) { data->auth_attempts = 0; } @@ -305,37 +324,47 @@ bool mf_ultralight_load(MfUltralightData* data, FlipperFormat* ff, uint32_t vers return parsed; } -bool mf_ultralight_save(const MfUltralightData* data, FlipperFormat* ff, uint32_t version) { +bool mf_ultralight_save(const MfUltralightData* data, FlipperFormat* ff) { furi_assert(data); FuriString* temp_str = furi_string_alloc(); bool saved = false; do { - const char* device_type_name = mf_ultralight_get_device_name_by_type(data->type, true); - if(!flipper_format_write_string_cstr(ff, "Device type", device_type_name)) break; - if(!iso14443_3a_save_data(data->iso14443_3a_data, ff, version)) break; - if(!flipper_format_write_comment_cstr(ff, "Mifare Ultralight specific data")) break; + if(!iso14443_3a_save(data->iso14443_3a_data, ff)) break; + + if(!flipper_format_write_comment_cstr(ff, MF_ULTRALIGHT_PROTOCOL_NAME " specific data")) + break; if(!flipper_format_write_uint32( - ff, "Data format version", &mf_ultralight_data_format_version, 1)) + ff, MF_ULTRALIGHT_FORMAT_VERSION_KEY, &mf_ultralight_data_format_version, 1)) break; + + const char* device_type_name = + mf_ultralight_get_device_name_by_type(data->type, NfcDeviceNameTypeFull); + if(!flipper_format_write_string_cstr(ff, MF_ULTRALIGHT_TYPE_KEY, device_type_name)) break; if(!flipper_format_write_hex( - ff, "Signature", data->signature.data, sizeof(MfUltralightSignature))) + ff, + MF_ULTRALIGHT_SIGNATURE_KEY, + data->signature.data, + sizeof(MfUltralightSignature))) break; if(!flipper_format_write_hex( - ff, "Mifare version", (uint8_t*)&data->version, sizeof(MfUltralightVersion))) + ff, + MF_ULTRALIGHT_MIFARE_VERSION_KEY, + (uint8_t*)&data->version, + sizeof(MfUltralightVersion))) break; // Write conters and tearing flags data bool counters_saved = true; for(size_t i = 0; i < 3; i++) { - furi_string_printf(temp_str, "Counter %d", i); + furi_string_printf(temp_str, "%s %d", MF_ULTRALIGHT_COUNTER_KEY, i); if(!flipper_format_write_uint32( ff, furi_string_get_cstr(temp_str), &data->counter[i].counter, 1)) { counters_saved = false; break; } - furi_string_printf(temp_str, "Tearing %d", i); + furi_string_printf(temp_str, "%s %d", MF_ULTRALIGHT_TEARING_KEY, i); if(!flipper_format_write_hex( ff, furi_string_get_cstr(temp_str), data->tearing_flag->data, 1)) { counters_saved = false; @@ -347,11 +376,11 @@ bool mf_ultralight_save(const MfUltralightData* data, FlipperFormat* ff, uint32_ // Write pages data uint32_t pages_total = data->pages_total; uint32_t pages_read = data->pages_read; - if(!flipper_format_write_uint32(ff, "Pages total", &pages_total, 1)) break; - if(!flipper_format_write_uint32(ff, "Pages read", &pages_read, 1)) break; + if(!flipper_format_write_uint32(ff, MF_ULTRALIGHT_PAGES_TOTAL_KEY, &pages_total, 1)) break; + if(!flipper_format_write_uint32(ff, MF_ULTRALIGHT_PAGES_READ_KEY, &pages_read, 1)) break; bool pages_saved = true; for(size_t i = 0; i < data->pages_total; i++) { - furi_string_printf(temp_str, "Page %d", i); + furi_string_printf(temp_str, "%s %d", MF_ULTRALIGHT_PAGE_KEY, i); if(!flipper_format_write_hex( ff, furi_string_get_cstr(temp_str), @@ -365,7 +394,7 @@ bool mf_ultralight_save(const MfUltralightData* data, FlipperFormat* ff, uint32_ // Write authentication counter if(!flipper_format_write_uint32( - ff, "Failed authentication attempts", &data->auth_attempts, 1)) + ff, MF_ULTRALIGHT_FAILED_ATTEMPTS_KEY, &data->auth_attempts, 1)) break; saved = true; @@ -429,7 +458,7 @@ const char* furi_assert(data); furi_assert(data->type < MfUltralightTypeNum); - return mf_ultralight_get_device_name_by_type(data->type, name_type == NfcDeviceNameTypeFull); + return mf_ultralight_get_device_name_by_type(data->type, name_type); } const uint8_t* mf_ultralight_get_uid(const MfUltralightData* data, size_t* uid_len) { diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h index 460b907a4553..3df841043ed8 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h @@ -179,7 +179,7 @@ bool mf_ultralight_verify(MfUltralightData* data, const FuriString* device_type) bool mf_ultralight_load(MfUltralightData* data, FlipperFormat* ff, uint32_t version); -bool mf_ultralight_save(const MfUltralightData* data, FlipperFormat* ff, uint32_t version); +bool mf_ultralight_save(const MfUltralightData* data, FlipperFormat* ff); bool mf_ultralight_is_equal(const MfUltralightData* data, const MfUltralightData* other); diff --git a/lib/nfc/protocols/nfc_device_base.h b/lib/nfc/protocols/nfc_device_base.h index e877e4422b8a..acb69ad3bcba 100644 --- a/lib/nfc/protocols/nfc_device_base.h +++ b/lib/nfc/protocols/nfc_device_base.h @@ -19,7 +19,7 @@ typedef void (*NfcDeviceReset)(NfcDeviceData* data); typedef void (*NfcDeviceCopy)(NfcDeviceData* data, const NfcDeviceData* other); typedef bool (*NfcDeviceVerify)(NfcDeviceData* data, const FuriString* device_type); typedef bool (*NfcDeviceLoad)(NfcDeviceData* data, FlipperFormat* ff, uint32_t version); -typedef bool (*NfcDeviceSave)(const NfcDeviceData* data, FlipperFormat* ff, uint32_t version); +typedef bool (*NfcDeviceSave)(const NfcDeviceData* data, FlipperFormat* ff); typedef bool (*NfcDeviceEqual)(const NfcDeviceData* data, const NfcDeviceData* other); typedef const char* (*NfcDeviceGetName)(const NfcDeviceData* data, NfcDeviceNameType name_type); typedef const uint8_t* (*NfcDeviceGetUid)(const NfcDeviceData* data, size_t* uid_len); From f54f7fc8507fdf5db3663446bb57d3832abf7030 Mon Sep 17 00:00:00 2001 From: gornekich Date: Wed, 12 Jul 2023 15:08:29 +0400 Subject: [PATCH 121/149] MFC emulation part 0 (#2867) * nfc: introduce mifare classic listener * mf listener: continue implementation * nfc: add listener commands * nfc app: add mf classic emulate scene * mf classic: emulation fixes * mf classic: read block command emulation * nfc tests: add mfc poller listener test * nfc: introduce iso14443_3a signal for transparent mode * nfc: working transparent mode * nfc: not working change TIM2 -> TIM17 * furi hal nfca: single signal alloc * nfc hal: nfc acquires spi bus * nfc hal: fix incorrect prescaler setting --- applications/debug/unit_tests/nfc/nfc_test.c | 91 +++-- .../debug/unit_tests/nfc/nfc_transport.c | 8 +- .../protocol_support/mf_classic/mf_classic.c | 2 +- applications/main/nfc/nfc_app.c | 75 ++-- .../main/nfc/scenes/nfc_scene_config.h | 1 + .../nfc/scenes/nfc_scene_mf_classic_emulate.c | 46 +++ firmware/targets/f7/api_symbols.csv | 11 +- firmware/targets/f7/furi_hal/f_hal_nfc.c | 83 ++-- .../targets/f7/furi_hal/f_hal_nfc_event.c | 2 - .../targets/f7/furi_hal/f_hal_nfc_timer.c | 37 +- firmware/targets/f7/furi_hal/f_hal_nfca.c | 40 +- firmware/targets/f7/target.json | 3 +- firmware/targets/furi_hal_include/f_hal_nfc.h | 5 + lib/nfc/helpers/bit_buffer.c | 6 + lib/nfc/helpers/bit_buffer.h | 8 + lib/nfc/helpers/iso14443_3a_signal.c | 122 ++++++ lib/nfc/helpers/iso14443_3a_signal.h | 26 ++ lib/nfc/nfc.c | 21 +- lib/nfc/nfc.h | 6 +- .../iso14443_3a/iso14443_3a_listener.c | 44 ++- .../iso14443_3a/iso14443_3a_listener.h | 1 + .../iso14443_3a/iso14443_3a_listener_i.c | 16 + .../iso14443_3a/iso14443_3a_listener_i.h | 4 + .../iso14443_3a/iso14443_3a_poller_i.c | 6 +- lib/nfc/protocols/mf_classic/crypto1.c | 4 +- lib/nfc/protocols/mf_classic/crypto1.h | 2 + lib/nfc/protocols/mf_classic/mf_classic.c | 129 ++++++ lib/nfc/protocols/mf_classic/mf_classic.h | 18 +- .../mf_classic/mf_classic_listener.c | 373 ++++++++++++++++++ .../mf_classic/mf_classic_listener.h | 26 ++ .../mf_classic/mf_classic_listener_defs.h | 13 + .../mf_classic/mf_classic_listener_i.h | 76 ++++ .../mf_classic/mf_classic_poller_defs.h | 8 + .../mf_classic/mf_classic_poller_i.c | 8 +- .../mf_ultralight/mf_ultralight_listener.h | 1 - .../mf_ultralight/mf_ultralight_listener_i.h | 1 + lib/nfc/protocols/nfc_listener_defs.c | 4 +- 37 files changed, 1128 insertions(+), 199 deletions(-) create mode 100644 applications/main/nfc/scenes/nfc_scene_mf_classic_emulate.c create mode 100644 lib/nfc/helpers/iso14443_3a_signal.c create mode 100644 lib/nfc/helpers/iso14443_3a_signal.h create mode 100644 lib/nfc/protocols/mf_classic/mf_classic_listener.c create mode 100644 lib/nfc/protocols/mf_classic/mf_classic_listener.h create mode 100644 lib/nfc/protocols/mf_classic/mf_classic_listener_defs.h create mode 100644 lib/nfc/protocols/mf_classic/mf_classic_listener_i.h diff --git a/applications/debug/unit_tests/nfc/nfc_test.c b/applications/debug/unit_tests/nfc/nfc_test.c index e5db6ccce7f9..38ed49e470f7 100644 --- a/applications/debug/unit_tests/nfc/nfc_test.c +++ b/applications/debug/unit_tests/nfc/nfc_test.c @@ -10,6 +10,7 @@ #include #include #include +#include #include @@ -334,40 +335,68 @@ static void mf_ultralight_write() { nfc_free(poller); } +static void mf_classic_reader() { + Nfc* poller = nfc_alloc(); + Nfc* listener = nfc_alloc(); + + NfcDevice* nfc_device = nfc_device_alloc(); + nfc_data_generator_fill_data(NfcDataGeneratorTypeMfClassic4k_7b, nfc_device); + NfcListener* mfc_listener = nfc_listener_alloc( + listener, NfcProtocolMfClassic, nfc_device_get_data(nfc_device, NfcProtocolMfClassic)); + nfc_listener_start(mfc_listener, NULL, NULL); + + MfClassicBlock block = {}; + MfClassicKey key = {.data = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}; + + mf_classic_poller_read_block(poller, 0, &key, MfClassicKeyTypeA, &block); + + nfc_listener_stop(mfc_listener); + nfc_listener_free(mfc_listener); + + const MfClassicData* mfc_data = nfc_device_get_data(nfc_device, NfcProtocolMfClassic); + mu_assert(memcmp(&mfc_data->block[0], &block, sizeof(MfClassicBlock)) == 0, "Data mismatch"); + + nfc_device_free(nfc_device); + nfc_free(listener); + nfc_free(poller); +} + MU_TEST_SUITE(nfc) { nfc_test_alloc(); - MU_RUN_TEST(iso14443_3a_reader); - MU_RUN_TEST(mf_ultralight_11_reader); - MU_RUN_TEST(mf_ultralight_21_reader); - MU_RUN_TEST(ntag_215_reader); - MU_RUN_TEST(ntag_216_reader); - MU_RUN_TEST(ntag_213_locked_reader); - - MU_RUN_TEST(mf_ultralight_write); - - MU_RUN_TEST(iso14443_3a_4b_file_test); - MU_RUN_TEST(iso14443_3a_7b_file_test); - - MU_RUN_TEST(mf_ultralight_file_test); - MU_RUN_TEST(mf_ultralight_ev1_11_file_test); - MU_RUN_TEST(mf_ultralight_ev1_h11_file_test); - MU_RUN_TEST(mf_ultralight_ev1_21_file_test); - MU_RUN_TEST(mf_ultralight_ev1_h21_file_test); - MU_RUN_TEST(mf_ultralight_ntag_203_file_test); - MU_RUN_TEST(mf_ultralight_ntag_213_file_test); - MU_RUN_TEST(mf_ultralight_ntag_215_file_test); - MU_RUN_TEST(mf_ultralight_ntag_216_file_test); - MU_RUN_TEST(mf_ultralight_ntag_i2c_1k_file_test); - MU_RUN_TEST(mf_ultralight_ntag_i2c_2k_file_test); - MU_RUN_TEST(mf_ultralight_ntag_i2c_plus_1k_file_test); - MU_RUN_TEST(mf_ultralight_ntag_i2c_plus_2k_file_test); - - MU_RUN_TEST(mf_classic_mini_file_test); - MU_RUN_TEST(mf_classic_1k_4b_file_test); - MU_RUN_TEST(mf_classic_1k_7b_file_test); - MU_RUN_TEST(mf_classic_4k_4b_file_test); - MU_RUN_TEST(mf_classic_4k_7b_file_test); + MU_RUN_TEST(mf_classic_reader); + + UNUSED(iso14443_3a_reader); + UNUSED(mf_ultralight_11_reader); + UNUSED(mf_ultralight_21_reader); + UNUSED(ntag_215_reader); + UNUSED(ntag_216_reader); + UNUSED(ntag_213_locked_reader); + + UNUSED(mf_ultralight_write); + + UNUSED(iso14443_3a_4b_file_test); + UNUSED(iso14443_3a_7b_file_test); + + UNUSED(mf_ultralight_file_test); + UNUSED(mf_ultralight_ev1_11_file_test); + UNUSED(mf_ultralight_ev1_h11_file_test); + UNUSED(mf_ultralight_ev1_21_file_test); + UNUSED(mf_ultralight_ev1_h21_file_test); + UNUSED(mf_ultralight_ntag_203_file_test); + UNUSED(mf_ultralight_ntag_213_file_test); + UNUSED(mf_ultralight_ntag_215_file_test); + UNUSED(mf_ultralight_ntag_216_file_test); + UNUSED(mf_ultralight_ntag_i2c_1k_file_test); + UNUSED(mf_ultralight_ntag_i2c_2k_file_test); + UNUSED(mf_ultralight_ntag_i2c_plus_1k_file_test); + UNUSED(mf_ultralight_ntag_i2c_plus_2k_file_test); + + UNUSED(mf_classic_mini_file_test); + UNUSED(mf_classic_1k_4b_file_test); + UNUSED(mf_classic_1k_7b_file_test); + UNUSED(mf_classic_4k_4b_file_test); + UNUSED(mf_classic_4k_7b_file_test); nfc_test_free(); } diff --git a/applications/debug/unit_tests/nfc/nfc_transport.c b/applications/debug/unit_tests/nfc/nfc_transport.c index fe87dd204bd5..bf8dce4ece48 100644 --- a/applications/debug/unit_tests/nfc/nfc_transport.c +++ b/applications/debug/unit_tests/nfc/nfc_transport.c @@ -390,6 +390,10 @@ NfcError nfc_listener_tx(Nfc* instance, const BitBuffer* tx_buffer) { return NfcErrorNone; } +NfcError nfc_iso14443_3a_listener_tx_custom_parity(Nfc* instance, const BitBuffer* tx_buffer) { + return nfc_listener_tx(instance, tx_buffer); +} + NfcError nfc_trx(Nfc* instance, const BitBuffer* tx_buffer, BitBuffer* rx_buffer, uint32_t fwt) { furi_assert(instance); furi_assert(tx_buffer); @@ -430,7 +434,7 @@ NfcError nfc_trx_custom_parity( // Technology specific API -NfcError nfc_iso13444a_short_frame( +NfcError nfc_iso14443_3a_short_frame( Nfc* instance, NfcIso14443aShortFrame frame, BitBuffer* rx_buffer, @@ -448,7 +452,7 @@ NfcError nfc_iso13444a_short_frame( return error; } -NfcError nfc_iso13444a_sdd_frame( +NfcError nfc_iso14443_3a_sdd_frame( Nfc* instance, const BitBuffer* tx_buffer, BitBuffer* rx_buffer, diff --git a/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c b/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c index b548853b9353..eca8f63792a2 100644 --- a/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c +++ b/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c @@ -137,7 +137,7 @@ static bool nfc_scene_read_menu_on_event_mf_classic(NfcApp* instance, uint32_t e static bool nfc_scene_saved_menu_on_event_mf_classic(NfcApp* instance, uint32_t event) { switch(event) { case SubmenuIndexCommonEmulate: - scene_manager_next_scene(instance->scene_manager, NfcSceneNotImplemented); + scene_manager_next_scene(instance->scene_manager, NfcSceneMfClassicEmulate); return true; case SubmenuIndexDetectReader: scene_manager_next_scene(instance->scene_manager, NfcSceneNotImplemented); diff --git a/applications/main/nfc/nfc_app.c b/applications/main/nfc/nfc_app.c index d911a98e0378..2037fc6eac84 100644 --- a/applications/main/nfc/nfc_app.c +++ b/applications/main/nfc/nfc_app.c @@ -14,24 +14,24 @@ bool nfc_back_event_callback(void* context) { return scene_manager_handle_back_event(nfc->scene_manager); } -static void nfc_rpc_command_callback(RpcAppSystemEvent event, void* context) { - furi_assert(context); - NfcApp* nfc = context; - - furi_assert(nfc->rpc_ctx); - - if(event == RpcAppEventSessionClose) { - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventRpcSessionClose); - rpc_system_app_set_callback(nfc->rpc_ctx, NULL, NULL); - nfc->rpc_ctx = NULL; - } else if(event == RpcAppEventAppExit) { - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); - } else if(event == RpcAppEventLoadFile) { - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventRpcLoad); - } else { - rpc_system_app_confirm(nfc->rpc_ctx, event, false); - } -} +// static void nfc_rpc_command_callback(RpcAppSystemEvent event, void* context) { +// furi_assert(context); +// NfcApp* nfc = context; + +// furi_assert(nfc->rpc_ctx); + +// if(event == RpcAppEventSessionClose) { +// view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventRpcSessionClose); +// rpc_system_app_set_callback(nfc->rpc_ctx, NULL, NULL); +// nfc->rpc_ctx = NULL; +// } else if(event == RpcAppEventAppExit) { +// view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); +// } else if(event == RpcAppEventLoadFile) { +// view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventRpcLoad); +// } else { +// rpc_system_app_confirm(nfc->rpc_ctx, event, false); +// } +// } NfcApp* nfc_app_alloc() { NfcApp* instance = malloc(sizeof(NfcApp)); @@ -460,44 +460,25 @@ static bool nfc_is_hal_ready() { } int32_t nfc_app(void* p) { + UNUSED(p); if(!nfc_is_hal_ready()) return 0; NfcApp* nfc = nfc_app_alloc(); char* args = p; + // const char* args = "/ext/nfc/4.nfc"; // Check argument and run corresponding scene if(args && strlen(args)) { - // nfc_device_set_loading_callback(nfc->dev, nfc_show_loading_popup, nfc); - uint32_t rpc_ctx = 0; - if(sscanf(p, "RPC %lX", &rpc_ctx) == 1) { - nfc->rpc_ctx = (void*)rpc_ctx; - rpc_system_app_set_callback(nfc->rpc_ctx, nfc_rpc_command_callback, nfc); - rpc_system_app_send_started(nfc->rpc_ctx); - view_dispatcher_attach_to_gui( - nfc->view_dispatcher, nfc->gui, ViewDispatcherTypeDesktop); - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + nfc_device_set_loading_callback(nfc->nfc_device, nfc_show_loading_popup, nfc); + view_dispatcher_attach_to_gui( + nfc->view_dispatcher, nfc->gui, ViewDispatcherTypeFullscreen); + if(nfc_device_load(nfc->nfc_device, args)) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate); + } else { - view_dispatcher_attach_to_gui( - nfc->view_dispatcher, nfc->gui, ViewDispatcherTypeFullscreen); - // if(nfc_device_load(nfc->dev, p, true)) { - // if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { - // scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate); - // dolphin_deed(DolphinDeedNfcEmulate); - // } else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) { - // scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate); - // dolphin_deed(DolphinDeedNfcEmulate); - // } else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) { - // scene_manager_next_scene(nfc->scene_manager, NfcSceneDeviceInfo); - // } else { - // scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); - // dolphin_deed(DolphinDeedNfcEmulate); - // } - // } else { - // // Exit app - // view_dispatcher_stop(nfc->view_dispatcher); - // } + // Exit app + view_dispatcher_stop(nfc->view_dispatcher); } - // nfc_device_set_loading_callback(nfc->dev, NULL, nfc); } else { view_dispatcher_attach_to_gui( nfc->view_dispatcher, nfc->gui, ViewDispatcherTypeFullscreen); diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index df83c43d75f0..cb9d05f8f2ba 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -30,6 +30,7 @@ ADD_SCENE(nfc, mf_desfire_app, MfDesfireApp) ADD_SCENE(nfc, mf_classic_read_supported_card, MfClassicReadSupportedCard) ADD_SCENE(nfc, mf_classic_dict_attack, MfClassicDictAttack) +ADD_SCENE(nfc, mf_classic_emulate, MfClassicEmulate) ADD_SCENE(nfc, set_type, SetType) ADD_SCENE(nfc, set_sak, SetSak) diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_emulate.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_emulate.c new file mode 100644 index 000000000000..9aee0ee72b47 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_emulate.c @@ -0,0 +1,46 @@ +#include "../nfc_app_i.h" + +void nfc_scene_mf_classic_emulate_on_enter(void* context) { + NfcApp* nfc = context; + + // Setup view + const MfClassicData* data = nfc_device_get_data(nfc->nfc_device, NfcProtocolMfClassic); + + Popup* popup = nfc->popup; + popup_set_header(popup, "Emulating", 67, 13, AlignLeft, AlignTop); + if(!furi_string_empty(nfc->file_name)) { + nfc_text_store_set(nfc, "%s", furi_string_get_cstr(nfc->file_name)); + } else { + nfc_text_store_set(nfc, "Mf Classic"); + } + popup_set_icon(popup, 0, 3, &I_NFC_dolphin_emulation_47x61); + popup_set_text(popup, nfc->text_store, 90, 28, AlignCenter, AlignTop); + + // Setup and start worker + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); + nfc->listener = nfc_listener_alloc(nfc->nfc, NfcProtocolMfClassic, data); + nfc_listener_start(nfc->listener, NULL, NULL); + + nfc_blink_emulate_start(nfc); +} + +bool nfc_scene_mf_classic_emulate_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + UNUSED(nfc); + UNUSED(event); + bool consumed = false; + + return consumed; +} + +void nfc_scene_mf_classic_emulate_on_exit(void* context) { + NfcApp* nfc = context; + + nfc_listener_stop(nfc->listener); + nfc_listener_free(nfc->listener); + + // Clear view + popup_reset(nfc->popup); + + nfc_blink_stop(nfc); +} diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 6dfb92f63a5b..e3b1310ca470 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,+,34.0,, +Version,+,34.3,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -571,6 +571,7 @@ Function,-,bit_buffer_free,void,BitBuffer* Function,-,bit_buffer_get_byte,uint8_t,"const BitBuffer*, size_t" Function,-,bit_buffer_get_capacity_bytes,size_t,const BitBuffer* Function,-,bit_buffer_get_data,const uint8_t*,const BitBuffer* +Function,-,bit_buffer_get_parity,const _Bool*,const BitBuffer* Function,-,bit_buffer_get_size,size_t,const BitBuffer* Function,-,bit_buffer_get_size_bytes,size_t,const BitBuffer* Function,-,bit_buffer_has_partial_byte,_Bool,const BitBuffer* @@ -865,6 +866,7 @@ Function,-,f_hal_nfc_timer_fwt_start,void,uint32_t Function,-,f_hal_nfc_timer_fwt_stop,void, Function,-,f_hal_nfc_trx_reset,FHalNfcError, Function,-,f_hal_nfc_wait_event,FHalNfcEvent,uint32_t +Function,-,f_hal_nfca_listener_tx_custom_parity,FHalNfcError,"const uint8_t*, const _Bool*, size_t" Function,-,f_hal_nfca_receive_sdd_frame,FHalNfcError,"uint8_t*, size_t, size_t*" Function,-,f_hal_nfca_send_sdd_frame,FHalNfcError,"const uint8_t*, size_t" Function,-,f_hal_nfca_send_short_frame,FHalNfcError,FHalNfcaShortFrame @@ -1811,7 +1813,6 @@ Function,-,iso14443_3a_get_device_name,const char*,"const Iso14443_3aData*, NfcD Function,-,iso14443_3a_get_uid,const uint8_t*,"const Iso14443_3aData*, size_t*" Function,-,iso14443_3a_is_equal,_Bool,"const Iso14443_3aData*, const Iso14443_3aData*" Function,-,iso14443_3a_load,_Bool,"Iso14443_3aData*, FlipperFormat*, uint32_t" -Function,-,iso14443_3a_load_data,_Bool,"Iso14443_3aData*, FlipperFormat*, uint32_t" Function,-,iso14443_3a_reset,void,Iso14443_3aData* Function,+,iso14443_3a_save,_Bool,"const Iso14443_3aData*, FlipperFormat*" Function,-,iso14443_3a_trim_crc,void,BitBuffer* @@ -2009,6 +2010,7 @@ Function,+,mf_classic_get_sector_trailer_num_by_sector,uint8_t,uint8_t Function,-,mf_classic_get_total_block_num,uint16_t,MfClassicType Function,-,mf_classic_get_total_sectors_num,uint8_t,MfClassicType Function,+,mf_classic_get_uid,const uint8_t*,"const MfClassicData*, size_t*" +Function,-,mf_classic_is_allowed_access,_Bool,"MfClassicData*, uint8_t, MfClassicKeyType, MfClassicAction" Function,+,mf_classic_is_block_read,_Bool,"const MfClassicData*, uint8_t" Function,+,mf_classic_is_card_read,_Bool,const MfClassicData* Function,+,mf_classic_is_equal,_Bool,"const MfClassicData*, const MfClassicData*" @@ -2060,8 +2062,9 @@ Function,-,nexttowardl,long double,"long double, long double" Function,-,nfc_alloc,Nfc*, Function,-,nfc_config,void,"Nfc*, NfcMode" Function,-,nfc_free,void,Nfc* -Function,-,nfc_iso13444a_sdd_frame,NfcError,"Nfc*, const BitBuffer*, BitBuffer*, uint32_t" -Function,-,nfc_iso13444a_short_frame,NfcError,"Nfc*, NfcIso14443aShortFrame, BitBuffer*, uint32_t" +Function,-,nfc_iso14443_3a_listener_tx_custom_parity,NfcError,"Nfc*, const BitBuffer*" +Function,-,nfc_iso14443_3a_sdd_frame,NfcError,"Nfc*, const BitBuffer*, BitBuffer*, uint32_t" +Function,-,nfc_iso14443_3a_short_frame,NfcError,"Nfc*, NfcIso14443aShortFrame, BitBuffer*, uint32_t" Function,-,nfc_listener_abort,void,Nfc* Function,-,nfc_listener_set_col_res_data,NfcError,"Nfc*, uint8_t*, uint8_t, uint8_t*, uint8_t" Function,-,nfc_listener_sleep,NfcError,Nfc* diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc.c b/firmware/targets/f7/furi_hal/f_hal_nfc.c index a374b2ee0904..171ec4a85d06 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfc.c +++ b/firmware/targets/f7/furi_hal/f_hal_nfc.c @@ -38,32 +38,40 @@ static FHalNfcError f_hal_nfc_turn_on_osc(FuriHalSpiBusHandle* handle) { FHalNfcError f_hal_nfc_is_hal_ready() { FHalNfcError error = FHalNfcErrorNone; - FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; - furi_hal_spi_acquire(handle); - - uint8_t chip_id = 0; - st25r3916_read_reg(handle, ST25R3916_REG_IC_IDENTITY, &chip_id); - if((chip_id & ST25R3916_REG_IC_IDENTITY_ic_type_mask) != - ST25R3916_REG_IC_IDENTITY_ic_type_st25r3916) { - FURI_LOG_E(TAG, "Wrong chip id"); - error = FHalNfcErrorCommunication; - } - furi_hal_spi_release(handle); + + do { + error = f_hal_nfc_acquire(); + if(error != FHalNfcErrorNone) break; + + FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; + uint8_t chip_id = 0; + st25r3916_read_reg(handle, ST25R3916_REG_IC_IDENTITY, &chip_id); + if((chip_id & ST25R3916_REG_IC_IDENTITY_ic_type_mask) != + ST25R3916_REG_IC_IDENTITY_ic_type_st25r3916) { + FURI_LOG_E(TAG, "Wrong chip id"); + error = FHalNfcErrorCommunication; + } + + f_hal_nfc_release(); + } while(false); return error; } FHalNfcError f_hal_nfc_init() { furi_assert(f_hal_nfc_mutex == NULL); + f_hal_nfc_mutex = furi_mutex_alloc(FuriMutexTypeNormal); FHalNfcError error = FHalNfcErrorNone; + f_hal_nfc_event_init(); f_hal_nfc_event_start(); - FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; - furi_hal_spi_acquire(handle); - do { + error = f_hal_nfc_acquire(); + if(error != FHalNfcErrorNone) break; + + FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; // Set default state st25r3916_direct_cmd(handle, ST25R3916_CMD_SET_DEFAULT); // Increase IO driver strength of MISO and IRQ @@ -218,11 +226,10 @@ FHalNfcError f_hal_nfc_init() { furi_delay_ms(6); } - furi_hal_spi_release(&furi_hal_spi_bus_handle_nfc); + f_hal_nfc_low_power_mode_start(); + f_hal_nfc_release(); } while(false); - f_hal_nfc_low_power_mode_start(); - return error; } @@ -233,8 +240,11 @@ static bool f_hal_nfc_is_mine() { FHalNfcError f_hal_nfc_acquire() { furi_check(f_hal_nfc_mutex); + furi_hal_spi_acquire(&furi_hal_spi_bus_handle_nfc); + FHalNfcError error = FHalNfcErrorNone; if(furi_mutex_acquire(f_hal_nfc_mutex, 100) != FuriStatusOk) { + furi_hal_spi_release(&furi_hal_spi_bus_handle_nfc); error = FHalNfcErrorBusy; } @@ -246,13 +256,14 @@ FHalNfcError f_hal_nfc_release() { furi_check(f_hal_nfc_is_mine()); furi_check(furi_mutex_release(f_hal_nfc_mutex) == FuriStatusOk); + furi_hal_spi_release(&furi_hal_spi_bus_handle_nfc); + return FHalNfcErrorNone; } FHalNfcError f_hal_nfc_low_power_mode_start() { FHalNfcError error = FHalNfcErrorNone; FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; - furi_hal_spi_acquire(handle); st25r3916_direct_cmd(handle, ST25R3916_CMD_STOP); st25r3916_clear_reg_bits( @@ -264,15 +275,12 @@ FHalNfcError f_hal_nfc_low_power_mode_start() { f_hal_nfc_deinit_gpio_isr(); f_hal_nfc_timers_deinit(); - furi_hal_spi_release(handle); - return error; } FHalNfcError f_hal_nfc_low_power_mode_stop() { FHalNfcError error = FHalNfcErrorNone; FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; - furi_hal_spi_acquire(handle); do { f_hal_nfc_init_gpio_isr(); @@ -286,7 +294,6 @@ FHalNfcError f_hal_nfc_low_power_mode_stop() { ST25R3916_REG_OP_CONTROL_en_fd_auto_efd); } while(false); - furi_hal_spi_release(handle); return error; } @@ -315,7 +322,6 @@ static void f_hal_nfc_configure_poller_common(FuriHalSpiBusHandle* handle) { FHalNfcError f_hal_nfc_set_mode(FHalNfcMode mode, FHalNfcBitrate bitrate) { FHalNfcError error = FHalNfcErrorNone; FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; - furi_hal_spi_acquire(handle); if(mode == FHalNfcModeIso14443_3aPoller) { f_hal_nfc_configure_poller_common(handle); @@ -359,30 +365,24 @@ FHalNfcError f_hal_nfc_set_mode(FHalNfcMode mode, FHalNfcBitrate bitrate) { st25r3916_change_reg_bits(handle, ST25R3916_REG_CORR_CONF2, 0xff, 0x00); } - furi_hal_spi_release(handle); - return error; } FHalNfcError f_hal_nfc_reset_mode() { FHalNfcError error = FHalNfcErrorNone; FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; - furi_hal_spi_acquire(handle); st25r3916_direct_cmd(handle, ST25R3916_CMD_STOP); // Set default value in mode register st25r3916_write_reg(handle, ST25R3916_REG_MODE, ST25R3916_REG_MODE_om0); st25r3916_clear_reg_bits(handle, ST25R3916_REG_AUX, ST25R3916_REG_AUX_no_crc_rx); - furi_hal_spi_release(handle); - return error; } FHalNfcError f_hal_nfc_poller_field_on() { FHalNfcError error = FHalNfcErrorNone; FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; - furi_hal_spi_acquire(handle); if(!st25r3916_check_reg( handle, @@ -399,8 +399,6 @@ FHalNfcError f_hal_nfc_poller_field_on() { (ST25R3916_REG_OP_CONTROL_rx_en | ST25R3916_REG_OP_CONTROL_tx_en)); } - furi_hal_spi_release(handle); - return error; } @@ -411,7 +409,6 @@ FHalNfcError f_hal_nfc_poller_tx_custom_parity(const uint8_t* tx_data, size_t tx FHalNfcError err = FHalNfcErrorNone; FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; - furi_hal_spi_acquire(handle); // Prepare tx st25r3916_direct_cmd(handle, ST25R3916_CMD_CLEAR_FIFO); @@ -433,7 +430,6 @@ FHalNfcError f_hal_nfc_poller_tx_custom_parity(const uint8_t* tx_data, size_t tx st25r3916_write_fifo(handle, tx_data, tx_bits); st25r3916_direct_cmd(handle, ST25R3916_CMD_TRANSMIT_WITHOUT_CRC); - furi_hal_spi_release(handle); return err; } @@ -442,7 +438,6 @@ FHalNfcError f_hal_nfc_poller_tx(const uint8_t* tx_data, size_t tx_bits) { FHalNfcError err = FHalNfcErrorNone; FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; - furi_hal_spi_acquire(handle); // Prepare tx st25r3916_direct_cmd(handle, ST25R3916_CMD_CLEAR_FIFO); @@ -464,7 +459,7 @@ FHalNfcError f_hal_nfc_poller_tx(const uint8_t* tx_data, size_t tx_bits) { st25r3916_write_fifo(handle, tx_data, tx_bits); st25r3916_direct_cmd(handle, ST25R3916_CMD_TRANSMIT_WITHOUT_CRC); - furi_hal_spi_release(handle); + return err; } @@ -473,13 +468,12 @@ FHalNfcError f_hal_nfc_listener_tx(const uint8_t* tx_data, size_t tx_bits) { FHalNfcError err = FHalNfcErrorNone; FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; - furi_hal_spi_acquire(handle); st25r3916_direct_cmd(handle, ST25R3916_CMD_CLEAR_FIFO); st25r3916_write_fifo(handle, tx_data, tx_bits); st25r3916_direct_cmd(handle, ST25R3916_CMD_TRANSMIT_WITHOUT_CRC); - furi_hal_spi_release(handle); + return err; } @@ -488,32 +482,25 @@ FHalNfcError f_hal_nfc_poller_rx(uint8_t* rx_data, size_t rx_data_size, size_t* furi_assert(rx_bits); FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; - furi_hal_spi_acquire(handle); - FHalNfcError error = FHalNfcErrorNone; if(!st25r3916_read_fifo(handle, rx_data, rx_data_size, rx_bits)) { error = FHalNfcErrorBufferOverflow; } - furi_hal_spi_release(handle); - return error; } FHalNfcError f_hal_nfc_trx_reset() { FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; - furi_hal_spi_acquire(handle); st25r3916_direct_cmd(handle, ST25R3916_CMD_STOP); - furi_hal_spi_release(handle); return FHalNfcErrorNone; } FHalNfcError f_hal_nfc_listen_start() { FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; - furi_hal_spi_acquire(handle); st25r3916_direct_cmd(handle, ST25R3916_CMD_STOP); uint32_t interrupts = @@ -531,13 +518,11 @@ FHalNfcError f_hal_nfc_listen_start() { handle, ST25R3916_REG_PASSIVE_TARGET, ST25R3916_REG_PASSIVE_TARGET_d_106_ac_a); st25r3916_direct_cmd(handle, ST25R3916_CMD_GOTO_SENSE); - furi_hal_spi_release(handle); return FHalNfcErrorNone; } FHalNfcError f_hal_nfc_listener_sleep() { FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; - furi_hal_spi_acquire(handle); // Enable auto collision resolution st25r3916_clear_reg_bits( @@ -545,26 +530,20 @@ FHalNfcError f_hal_nfc_listener_sleep() { st25r3916_direct_cmd(handle, ST25R3916_CMD_STOP); st25r3916_direct_cmd(handle, ST25R3916_CMD_GOTO_SLEEP); - furi_hal_spi_release(handle); return FHalNfcErrorNone; } FHalNfcError f_hal_nfc_listener_disable_auto_col_res() { FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; - furi_hal_spi_acquire(handle); st25r3916_set_reg_bits( handle, ST25R3916_REG_PASSIVE_TARGET, ST25R3916_REG_PASSIVE_TARGET_d_106_ac_a); - furi_hal_spi_release(handle); return FHalNfcErrorNone; } void f_hal_nfc_set_mask_receive_timer(uint32_t time_fc) { FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; - furi_hal_spi_acquire(handle); st25r3916_write_reg(handle, ST25R3916_REG_MASK_RX_TIMER, time_fc); - - furi_hal_spi_release(handle); } diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc_event.c b/firmware/targets/f7/furi_hal/f_hal_nfc_event.c index 23e100371228..f28967ffb869 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfc_event.c +++ b/firmware/targets/f7/furi_hal/f_hal_nfc_event.c @@ -40,9 +40,7 @@ FHalNfcEvent f_hal_nfc_wait_event(uint32_t timeout_ms) { if(event_flag & FHalNfcEventInternalTypeIrq) { furi_thread_flags_clear(FHalNfcEventInternalTypeIrq); FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; - furi_hal_spi_acquire(handle); uint32_t irq = f_hal_nfc_get_irq(handle); - furi_hal_spi_release(handle); if(irq & ST25R3916_IRQ_MASK_OSC) { event |= FHalNfcEventOscOn; } diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc_timer.c b/firmware/targets/f7/furi_hal/f_hal_nfc_timer.c index 83c08bcb3bbe..f75c51828d05 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfc_timer.c +++ b/firmware/targets/f7/furi_hal/f_hal_nfc_timer.c @@ -42,13 +42,13 @@ static FHalNfcTimerConfig f_hal_nfc_timers[FHalNfcTimerCount] = { [FHalNfcTimerBlockTx] = { .pin = &gpio_ext_pa6, - .timer = TIM2, - .bus = FuriHalBusTIM2, - .prescaler = 0, - .freq_khz = 64000U, + .timer = TIM17, + .bus = FuriHalBusTIM17, + .prescaler = 15, + .freq_khz = 4000U, .event = FHalNfcEventInternalTypeTimerBlockTxExpired, - .irq_id = FuriHalInterruptIdTIM2, - .irq_type = TIM2_IRQn, + .irq_id = FuriHalInterruptIdTim1TrgComTim17, + .irq_type = TIM1_TRG_COM_TIM17_IRQn, .is_configured = false, }, }; @@ -64,11 +64,15 @@ static void f_hal_nfc_timer_irq_callback(void* context) { static void f_hal_nfc_timer_init(FHalNfcTimer timer) { furi_hal_bus_enable(f_hal_nfc_timers[timer].bus); - LL_TIM_EnableUpdateEvent(f_hal_nfc_timers[timer].timer); + + LL_TIM_SetPrescaler(f_hal_nfc_timers[timer].timer, f_hal_nfc_timers[timer].prescaler); LL_TIM_SetOnePulseMode(f_hal_nfc_timers[timer].timer, LL_TIM_ONEPULSEMODE_SINGLE); + LL_TIM_EnableUpdateEvent(f_hal_nfc_timers[timer].timer); LL_TIM_SetCounterMode(f_hal_nfc_timers[timer].timer, LL_TIM_COUNTERMODE_UP); - LL_TIM_SetPrescaler(f_hal_nfc_timers[timer].timer, f_hal_nfc_timers[timer].prescaler); LL_TIM_SetClockSource(f_hal_nfc_timers[timer].timer, LL_TIM_CLOCKSOURCE_INTERNAL); + + LL_TIM_GenerateEvent_UPDATE(f_hal_nfc_timers[timer].timer); + LL_TIM_EnableIT_UPDATE(f_hal_nfc_timers[timer].timer); furi_hal_interrupt_set_isr( @@ -94,6 +98,8 @@ static void f_hal_nfc_timer_deinit(FHalNfcTimer timer) { static void f_hal_nfc_timer_start(FHalNfcTimer timer, uint32_t time_fc) { uint32_t arr_reg = f_hal_nfc_timers[timer].freq_khz * time_fc / F_HAL_NFC_FREQ_KHZ; + furi_check(arr_reg < UINT16_MAX); + LL_TIM_SetAutoReload(f_hal_nfc_timers[timer].timer, arr_reg); LL_TIM_EnableCounter(f_hal_nfc_timers[timer].timer); furi_hal_gpio_write(f_hal_nfc_timers[timer].pin, true); @@ -122,31 +128,36 @@ void f_hal_nfc_timers_deinit() { } void f_hal_nfc_timer_fwt_start(uint32_t time_fc) { - furi_assert(f_hal_nfc_timers[FHalNfcTimerFwt].is_configured); + furi_check(f_hal_nfc_timers[FHalNfcTimerFwt].is_configured); f_hal_nfc_timer_start(FHalNfcTimerFwt, time_fc); } void f_hal_nfc_timer_fwt_stop() { - furi_assert(f_hal_nfc_timers[FHalNfcTimerFwt].is_configured); + furi_check(f_hal_nfc_timers[FHalNfcTimerFwt].is_configured); f_hal_nfc_timer_stop(FHalNfcTimerFwt); } void f_hal_nfc_timer_block_tx_start(uint32_t time_fc) { - furi_assert(f_hal_nfc_timers[FHalNfcTimerBlockTx].is_configured); + furi_check(f_hal_nfc_timers[FHalNfcTimerBlockTx].is_configured); + furi_check(!f_hal_nfc_timer_block_tx_is_running()); + f_hal_nfc_timer_start(FHalNfcTimerBlockTx, time_fc); } void f_hal_nfc_timer_block_tx_start_us(uint32_t time_us) { - furi_assert(f_hal_nfc_timers[FHalNfcTimerBlockTx].is_configured); + furi_check(f_hal_nfc_timers[FHalNfcTimerBlockTx].is_configured); + furi_check(!f_hal_nfc_timer_block_tx_is_running()); uint32_t arr_reg = f_hal_nfc_timers[FHalNfcTimerBlockTx].freq_khz / 1000 * time_us; + furi_check(arr_reg < UINT16_MAX); + LL_TIM_SetAutoReload(f_hal_nfc_timers[FHalNfcTimerBlockTx].timer, arr_reg); LL_TIM_EnableCounter(f_hal_nfc_timers[FHalNfcTimerBlockTx].timer); furi_hal_gpio_write(f_hal_nfc_timers[FHalNfcTimerBlockTx].pin, true); } void f_hal_nfc_timer_block_tx_stop() { - furi_assert(f_hal_nfc_timers[FHalNfcTimerBlockTx].is_configured); + furi_check(f_hal_nfc_timers[FHalNfcTimerBlockTx].is_configured); f_hal_nfc_timer_stop(FHalNfcTimerBlockTx); } diff --git a/firmware/targets/f7/furi_hal/f_hal_nfca.c b/firmware/targets/f7/furi_hal/f_hal_nfca.c index d39fd246400c..67e26b338438 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfca.c +++ b/firmware/targets/f7/furi_hal/f_hal_nfca.c @@ -3,14 +3,17 @@ #include #include #include +#include +#include #define TAG "FuriHalNfcA" +static Iso14443_3aSignal* iso14443_3a_signal = NULL; + FHalNfcError f_hal_nfca_send_short_frame(FHalNfcaShortFrame frame) { FHalNfcError error = FHalNfcErrorNone; FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; - furi_hal_spi_acquire(handle); // Disable crc check st25r3916_set_reg_bits(handle, ST25R3916_REG_AUX, ST25R3916_REG_AUX_no_crc_rx); @@ -35,8 +38,6 @@ FHalNfcError f_hal_nfca_send_short_frame(FHalNfcaShortFrame frame) { st25r3916_direct_cmd(handle, ST25R3916_CMD_TRANSMIT_WUPA); } - furi_hal_spi_release(handle); - return error; } @@ -69,7 +70,6 @@ FHalNfcError FHalNfcError error = FHalNfcErrorNone; FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; - furi_hal_spi_acquire(handle); // Set 4 or 7 bytes UID if(uid_len == 4) { @@ -99,7 +99,37 @@ FHalNfcError pt_memory[14] = sak & ~0x04; st25r3916_write_pta_mem(handle, pt_memory, sizeof(pt_memory)); - furi_hal_spi_release(handle); + + iso14443_3a_signal = iso14443_3a_signal_alloc(&gpio_spi_r_mosi); return error; } + +FHalNfcError f_hal_nfca_listener_tx_custom_parity( + const uint8_t* tx_data, + const bool* tx_parity, + size_t tx_bits) { + furi_assert(tx_data); + furi_assert(tx_parity); + + furi_assert(iso14443_3a_signal); + + FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; + + st25r3916_direct_cmd(handle, ST25R3916_CMD_TRANSPARENT_MODE); + // Reconfigure gpio for Transparent mode + furi_hal_spi_bus_handle_deinit(&furi_hal_spi_bus_handle_nfc); + + // Send signal + iso14443_3a_signal_tx(iso14443_3a_signal, tx_data, tx_parity, tx_bits); + + // Exit transparent mode + furi_hal_gpio_write(&gpio_spi_r_mosi, false); + + // Configure gpio back to SPI and exit transparent + furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_nfc); + st25r3916_direct_cmd(handle, ST25R3916_CMD_UNMASK_RECEIVE_DATA); + + // TODO handle field off + return FHalNfcErrorNone; +} diff --git a/firmware/targets/f7/target.json b/firmware/targets/f7/target.json index 0c083b68ddba..e5fd21c1058d 100644 --- a/firmware/targets/f7/target.json +++ b/firmware/targets/f7/target.json @@ -45,6 +45,7 @@ "flipper_application", "flipperformat", "toolbox", - "flipper7" + "flipper7", + "nfc" ] } \ No newline at end of file diff --git a/firmware/targets/furi_hal_include/f_hal_nfc.h b/firmware/targets/furi_hal_include/f_hal_nfc.h index 2ae128bf01ea..982b3b4083d0 100644 --- a/firmware/targets/furi_hal_include/f_hal_nfc.h +++ b/firmware/targets/furi_hal_include/f_hal_nfc.h @@ -156,6 +156,11 @@ FHalNfcError f_hal_nfca_receive_sdd_frame(uint8_t* rx_data, size_t rx_data_size, FHalNfcError furi_hal_nfca_set_col_res_data(uint8_t* uid, uint8_t uid_len, uint8_t* atqa, uint8_t sak); +FHalNfcError f_hal_nfca_listener_tx_custom_parity( + const uint8_t* tx_data, + const bool* tx_parity, + size_t tx_bits); + #ifdef __cplusplus } #endif diff --git a/lib/nfc/helpers/bit_buffer.c b/lib/nfc/helpers/bit_buffer.c index cab991e37d89..c9c6bd5c980a 100644 --- a/lib/nfc/helpers/bit_buffer.c +++ b/lib/nfc/helpers/bit_buffer.c @@ -215,6 +215,12 @@ const uint8_t* bit_buffer_get_data(const BitBuffer* buf) { return buf->data; } +const bool* bit_buffer_get_parity(const BitBuffer* buf) { + furi_assert(buf); + + return buf->parity; +} + void bit_buffer_set_byte(BitBuffer* buf, size_t index, uint8_t byte) { furi_assert(buf); diff --git a/lib/nfc/helpers/bit_buffer.h b/lib/nfc/helpers/bit_buffer.h index d3f621861a2d..bd5003b71fca 100644 --- a/lib/nfc/helpers/bit_buffer.h +++ b/lib/nfc/helpers/bit_buffer.h @@ -210,6 +210,14 @@ uint8_t bit_buffer_get_byte(const BitBuffer* buf, size_t index); */ const uint8_t* bit_buffer_get_data(const BitBuffer* buf); +/** + * Get the pointer to a BitBuffer instance's underlying data. + * + * @param [in] buf pointer to a BitBuffer instance to be queried + * @return pointer to the underlying data + */ +const bool* bit_buffer_get_parity(const BitBuffer* buf); + // Setters /** diff --git a/lib/nfc/helpers/iso14443_3a_signal.c b/lib/nfc/helpers/iso14443_3a_signal.c new file mode 100644 index 000000000000..a255b235356b --- /dev/null +++ b/lib/nfc/helpers/iso14443_3a_signal.c @@ -0,0 +1,122 @@ +#include "iso14443_3a_signal.h" + +#include + +#define ISO14443_3A_SIGNAL_BIT_MAX_EDGES (10) +#define ISO14443_3A_SIGNAL_MAX_EDGES (1350) + +#define ISO14443_3A_SIGNAL_F_SIG (13560000.0) +#define ISO14443_3A_SIGNAL_T_SIG 7374 //73.746ns*100 +#define ISO14443_3A_SIGNAL_T_SIG_X8 58992 //T_SIG*8 +#define ISO14443_3A_SIGNAL_T_SIG_X8_X8 471936 //T_SIG*8*8 +#define ISO14443_3A_SIGNAL_T_SIG_X8_X9 530928 //T_SIG*8*9 + +struct Iso14443_3aSignal { + const GpioPin* pin; + DigitalSignal* one; + DigitalSignal* zero; + DigitalSignal* tx_signal; +}; + +static void iso14443_3a_add_bit(DigitalSignal* signal, bool bit) { + if(bit) { + signal->start_level = true; + for(size_t i = 0; i < 7; i++) { + signal->edge_timings[i] = ISO14443_3A_SIGNAL_T_SIG_X8; + } + signal->edge_timings[7] = ISO14443_3A_SIGNAL_T_SIG_X8_X9; + signal->edge_cnt = 8; + } else { + signal->start_level = false; + signal->edge_timings[0] = ISO14443_3A_SIGNAL_T_SIG_X8_X8; + for(size_t i = 1; i < 9; i++) { + signal->edge_timings[i] = ISO14443_3A_SIGNAL_T_SIG_X8; + } + signal->edge_cnt = 9; + } +} + +static void iso14443_3a_add_byte(Iso14443_3aSignal* instance, uint8_t byte, bool parity) { + for(size_t i = 0; i < 8; i++) { + if(byte & (1 << i)) { + digital_signal_append(instance->tx_signal, instance->one); + } else { + digital_signal_append(instance->tx_signal, instance->zero); + } + } + if(parity) { + digital_signal_append(instance->tx_signal, instance->one); + } else { + digital_signal_append(instance->tx_signal, instance->zero); + } +} + +static void iso14443_3a_signal_encode( + Iso14443_3aSignal* instance, + const uint8_t* tx_data, + const bool* tx_parity, + size_t tx_bits) { + furi_assert(instance); + furi_assert(tx_data); + furi_assert(tx_parity); + + instance->tx_signal->edge_cnt = 0; + instance->tx_signal->start_level = true; + // Start of frame + digital_signal_append(instance->tx_signal, instance->one); + + if(tx_bits < 8) { + for(size_t i = 0; i < tx_bits; i++) { + if(FURI_BIT(tx_data[0], i)) { + digital_signal_append(instance->tx_signal, instance->one); + } else { + digital_signal_append(instance->tx_signal, instance->zero); + } + } + } else { + for(size_t i = 0; i < tx_bits / 8; i++) { + iso14443_3a_add_byte(instance, tx_data[i], tx_parity[i]); + } + } +} + +Iso14443_3aSignal* iso14443_3a_signal_alloc(const GpioPin* pin) { + furi_assert(pin); + + Iso14443_3aSignal* instance = malloc(sizeof(Iso14443_3aSignal)); + instance->pin = pin; + instance->one = digital_signal_alloc(ISO14443_3A_SIGNAL_BIT_MAX_EDGES); + instance->zero = digital_signal_alloc(ISO14443_3A_SIGNAL_BIT_MAX_EDGES); + iso14443_3a_add_bit(instance->one, true); + iso14443_3a_add_bit(instance->zero, false); + instance->tx_signal = digital_signal_alloc(ISO14443_3A_SIGNAL_MAX_EDGES); + + return instance; +} + +void iso14443_3a_signal_free(Iso14443_3aSignal* instance) { + furi_assert(instance); + furi_assert(instance->one); + furi_assert(instance->zero); + furi_assert(instance->tx_signal); + + digital_signal_free(instance->one); + digital_signal_free(instance->zero); + digital_signal_free(instance->tx_signal); + free(instance); +} + +void iso14443_3a_signal_tx( + Iso14443_3aSignal* instance, + const uint8_t* tx_data, + const bool* tx_parity, + size_t tx_bits) { + furi_assert(instance); + furi_assert(tx_data); + furi_assert(tx_parity); + + FURI_CRITICAL_ENTER(); + iso14443_3a_signal_encode(instance, tx_data, tx_parity, tx_bits); + digital_signal_send(instance->tx_signal, instance->pin); + FURI_CRITICAL_EXIT(); +} diff --git a/lib/nfc/helpers/iso14443_3a_signal.h b/lib/nfc/helpers/iso14443_3a_signal.h new file mode 100644 index 000000000000..7da00567f93c --- /dev/null +++ b/lib/nfc/helpers/iso14443_3a_signal.h @@ -0,0 +1,26 @@ +#pragma once + +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct Iso14443_3aSignal Iso14443_3aSignal; + +Iso14443_3aSignal* iso14443_3a_signal_alloc(const GpioPin* pin); + +void iso14443_3a_signal_free(Iso14443_3aSignal* instance); + +void iso14443_3a_signal_tx( + Iso14443_3aSignal* instance, + const uint8_t* tx_data, + const bool* tx_parity, + size_t tx_bits); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/nfc.c b/lib/nfc/nfc.c index 371b0997b0d5..60c65d681625 100644 --- a/lib/nfc/nfc.c +++ b/lib/nfc/nfc.c @@ -484,7 +484,7 @@ NfcError nfc_trx(Nfc* instance, const BitBuffer* tx_buffer, BitBuffer* rx_buffer return ret; } -NfcError nfc_iso13444a_short_frame( +NfcError nfc_iso14443_3a_short_frame( Nfc* instance, NfcIso14443aShortFrame frame, BitBuffer* rx_buffer, @@ -529,7 +529,7 @@ NfcError nfc_iso13444a_short_frame( return ret; } -NfcError nfc_iso13444a_sdd_frame( +NfcError nfc_iso14443_3a_sdd_frame( Nfc* instance, const BitBuffer* tx_buffer, BitBuffer* rx_buffer, @@ -572,4 +572,21 @@ NfcError nfc_iso13444a_sdd_frame( return ret; } +NfcError nfc_iso14443_3a_listener_tx_custom_parity(Nfc* instance, const BitBuffer* tx_buffer) { + furi_assert(instance); + furi_assert(tx_buffer); + + NfcError ret = NfcErrorNone; + FHalNfcError error = FHalNfcErrorNone; + + const uint8_t* tx_data = bit_buffer_get_data(tx_buffer); + const bool* tx_parity = bit_buffer_get_parity(tx_buffer); + size_t tx_bits = bit_buffer_get_size(tx_buffer); + + error = f_hal_nfca_listener_tx_custom_parity(tx_data, tx_parity, tx_bits); + ret = nfc_process_hal_error(error); + + return ret; +} + #endif // APP_UNIT_TESTS diff --git a/lib/nfc/nfc.h b/lib/nfc/nfc.h index a35ae41a2fce..797e512ae0d0 100644 --- a/lib/nfc/nfc.h +++ b/lib/nfc/nfc.h @@ -112,18 +112,20 @@ NfcError nfc_trx(Nfc* instance, const BitBuffer* tx_buffer, BitBuffer* rx_buffer // Technology specific API -NfcError nfc_iso13444a_short_frame( +NfcError nfc_iso14443_3a_short_frame( Nfc* instance, NfcIso14443aShortFrame frame, BitBuffer* rx_buffer, uint32_t fwt); -NfcError nfc_iso13444a_sdd_frame( +NfcError nfc_iso14443_3a_sdd_frame( Nfc* instance, const BitBuffer* tx_buffer, BitBuffer* rx_buffer, uint32_t fwt); +NfcError nfc_iso14443_3a_listener_tx_custom_parity(Nfc* instance, const BitBuffer* tx_buffer); + #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c b/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c index 04d3064604df..96da690cfde6 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c @@ -84,29 +84,33 @@ NfcCommand iso14443_3a_listener_run(NfcGenericEvent event, void* context) { NfcEvent* nfc_event = event.data; NfcCommand command = NfcCommandContinue; - if(nfc_event->type == NfcEventTypeListenerActivated) { + if(nfc_event->type == NfcEventTypeFieldOff) { + if(instance->callback) { + instance->iso14443_3a_event.type = Iso14443_3aListenerEventTypeFieldOff; + command = instance->callback(instance->generic_event, instance->context); + } + iso14443_3a_listener_sleep(instance); + } else if(nfc_event->type == NfcEventTypeListenerActivated) { instance->state = Iso14443_3aListenerStateActive; } else if(nfc_event->type == NfcEventTypeRxEnd) { - if(instance->state == Iso14443_3aListenerStateActive) { - if(iso14443_3a_listener_halt_received(nfc_event->data.buffer)) { - iso14443_3a_listener_sleep(instance); - instance->state = Iso14443_3aListenerStateIdle; - if(instance->callback) { - instance->iso14443_3a_event.type = Iso14443_3aListenerEventTypeHalted; - command = instance->callback(instance->generic_event, instance->context); - } + if(iso14443_3a_listener_halt_received(nfc_event->data.buffer)) { + iso14443_3a_listener_sleep(instance); + instance->state = Iso14443_3aListenerStateIdle; + if(instance->callback) { + instance->iso14443_3a_event.type = Iso14443_3aListenerEventTypeHalted; + command = instance->callback(instance->generic_event, instance->context); + } + } else { + if(iso14443_3a_check_crc(nfc_event->data.buffer)) { + instance->iso14443_3a_event.type = + Iso14443_3aListenerEventTypeReceivedStandardFrame; + iso14443_3a_trim_crc(nfc_event->data.buffer); } else { - if(iso14443_3a_check_crc(nfc_event->data.buffer)) { - instance->iso14443_3a_event.type = - Iso14443_3aListenerEventTypeReceivedStandardFrame; - iso14443_3a_trim_crc(nfc_event->data.buffer); - } else { - instance->iso14443_3a_event.type = Iso14443_3aListenerEventTypeReceivedData; - } - instance->iso14443_3a_event_data.buffer = nfc_event->data.buffer; - if(instance->callback) { - command = instance->callback(instance->generic_event, instance->context); - } + instance->iso14443_3a_event.type = Iso14443_3aListenerEventTypeReceivedData; + } + instance->iso14443_3a_event_data.buffer = nfc_event->data.buffer; + if(instance->callback) { + command = instance->callback(instance->generic_event, instance->context); } } } diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.h b/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.h index 44c479664195..8a550ca0a892 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.h +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.h @@ -10,6 +10,7 @@ extern "C" { typedef struct Iso14443_3aListener Iso14443_3aListener; typedef enum { + Iso14443_3aListenerEventTypeFieldOff, Iso14443_3aListenerEventTypeHalted, Iso14443_3aListenerEventTypeReceivedStandardFrame, diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener_i.c b/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener_i.c index a8d8bed05016..4f5f702b6d56 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener_i.c +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener_i.c @@ -40,6 +40,22 @@ Iso14443_3aError return ret; } +Iso14443_3aError iso14443_3a_listener_tx_with_custom_parity( + Iso14443_3aListener* instance, + const BitBuffer* tx_buffer) { + furi_assert(instance); + furi_assert(tx_buffer); + + Iso14443_3aError ret = Iso14443_3aErrorNone; + NfcError error = nfc_iso14443_3a_listener_tx_custom_parity(instance->nfc, tx_buffer); + if(error != NfcErrorNone) { + FURI_LOG_W(TAG, "Tx error: %d", error); + ret = iso14443_3a_listener_process_nfc_error(error); + } + + return ret; +}; + Iso14443_3aError iso14443_3a_listener_send_standard_frame( Iso14443_3aListener* instance, const BitBuffer* tx_buffer) { diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener_i.h b/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener_i.h index 5b0a56b26e01..56aee01104ab 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener_i.h +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener_i.h @@ -31,6 +31,10 @@ Iso14443_3aError iso14443_3a_listener_sleep(Iso14443_3aListener* instance); Iso14443_3aError iso14443_3a_listener_tx(Iso14443_3aListener* instance, const BitBuffer* tx_buffer); +Iso14443_3aError iso14443_3a_listener_tx_with_custom_parity( + Iso14443_3aListener* instance, + const BitBuffer* tx_buffer); + Iso14443_3aError iso14443_3a_listener_send_standard_frame( Iso14443_3aListener* instance, const BitBuffer* tx_buffer); diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.c b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.c index bd68fa905d11..90b9169a5866 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.c +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.c @@ -68,7 +68,7 @@ Iso14443_3aError iso14443_3a_poller_check_presence(Iso14443_3aPoller* instance) NfcError error = NfcErrorNone; Iso14443_3aError ret = Iso14443_3aErrorNone; do { - error = nfc_iso13444a_short_frame( + error = nfc_iso14443_3a_short_frame( instance->nfc, NfcIso14443aShortFrameSensReq, instance->rx_buffer, @@ -126,7 +126,7 @@ Iso14443_3aError iso14443_3a_poller_async_activate( bool activated = false; do { - error = nfc_iso13444a_short_frame( + error = nfc_iso14443_3a_short_frame( instance->nfc, NfcIso14443aShortFrameSensReq, instance->rx_buffer, @@ -161,7 +161,7 @@ Iso14443_3aError iso14443_3a_poller_async_activate( 0, ISO14443_3A_POLLER_SEL_CMD(instance->col_res.cascade_level)); bit_buffer_set_byte(instance->tx_buffer, 1, ISO14443_3A_POLLER_SEL_PAR(2, 0)); - error = nfc_iso13444a_sdd_frame( + error = nfc_iso14443_3a_sdd_frame( instance->nfc, instance->tx_buffer, instance->rx_buffer, diff --git a/lib/nfc/protocols/mf_classic/crypto1.c b/lib/nfc/protocols/mf_classic/crypto1.c index 1ca2966fea9a..70f897254489 100644 --- a/lib/nfc/protocols/mf_classic/crypto1.c +++ b/lib/nfc/protocols/mf_classic/crypto1.c @@ -81,7 +81,7 @@ uint32_t crypto1_word(Crypto1* crypto1, uint32_t in, int is_encrypted) { return out; } -static uint32_t prng_successor(uint32_t x, uint32_t n) { +uint32_t prng_successor(uint32_t x, uint32_t n) { SWAPENDIAN(x); while(n--) x = x >> 1 | (x >> 16 ^ x >> 18 ^ x >> 19 ^ x >> 21) << 31; @@ -127,7 +127,7 @@ void crypto1_encrypt(Crypto1* crypto, uint8_t* keystream, const BitBuffer* buff, } bit_buffer_set_byte(out, 0, encrypted_byte); } else { - for(uint8_t i = 0; i < bits / 8; i++) { + for(size_t i = 0; i < bits / 8; i++) { uint8_t encrypted_byte = crypto1_byte(crypto, keystream ? keystream[i] : 0, 0) ^ plain_data[i]; bool parity_bit = diff --git a/lib/nfc/protocols/mf_classic/crypto1.h b/lib/nfc/protocols/mf_classic/crypto1.h index 0e251dae09dd..4273ac82c5b5 100644 --- a/lib/nfc/protocols/mf_classic/crypto1.h +++ b/lib/nfc/protocols/mf_classic/crypto1.h @@ -37,6 +37,8 @@ void crypto1_encrypt_reader_nonce( uint8_t* nr, BitBuffer* out); +uint32_t prng_successor(uint32_t x, uint32_t n); + #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/mf_classic/mf_classic.c b/lib/nfc/protocols/mf_classic/mf_classic.c index 0eba4722e089..7f1026a8289d 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic.c +++ b/lib/nfc/protocols/mf_classic/mf_classic.c @@ -590,3 +590,132 @@ bool mf_classic_is_sector_read(const MfClassicData* data, uint8_t sector_num) { return sector_read; } + +static bool mf_classic_is_allowed_access_sector_trailer( + MfClassicData* data, + uint8_t block_num, + MfClassicKeyType key_type, + MfClassicAction action) { + uint8_t sector_num = mf_classic_get_sector_by_block(block_num); + MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(data, sector_num); + uint8_t* access_bits_arr = sec_tr->access_bits.data; + uint8_t AC = ((access_bits_arr[1] >> 5) & 0x04) | ((access_bits_arr[2] >> 2) & 0x02) | + ((access_bits_arr[2] >> 7) & 0x01); + + switch(action) { + case MfClassicActionKeyARead: { + return false; + } + case MfClassicActionKeyAWrite: + case MfClassicActionKeyBWrite: { + return ( + (key_type == MfClassicKeyTypeA && (AC == 0x00 || AC == 0x01)) || + (key_type == MfClassicKeyTypeB && (AC == 0x04 || AC == 0x03))); + } + case MfClassicActionKeyBRead: { + return (key_type == MfClassicKeyTypeA && (AC == 0x00 || AC == 0x02 || AC == 0x01)); + } + case MfClassicActionACRead: { + return ( + (key_type == MfClassicKeyTypeA) || + (key_type == MfClassicKeyTypeB && !(AC == 0x00 || AC == 0x02 || AC == 0x01))); + } + case MfClassicActionACWrite: { + return ( + (key_type == MfClassicKeyTypeA && (AC == 0x01)) || + (key_type == MfClassicKeyTypeB && (AC == 0x03 || AC == 0x05))); + } + default: + return false; + } + return true; +} + +static bool mifare_classic_is_allowed_access_data_block( + MfClassicData* data, + uint8_t block_num, + MfClassicKeyType key_type, + MfClassicAction action) { + uint8_t sector_num = mf_classic_get_sector_by_block(block_num); + MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(data, sector_num); + uint8_t* access_bits_arr = sec_tr->access_bits.data; + + if(block_num == 0 && action == MfClassicActionDataWrite) { + return false; + } + + uint8_t sector_block = 0; + if(block_num <= 128) { + sector_block = block_num & 0x03; + } else { + sector_block = (block_num & 0x0f) / 5; + } + + uint8_t AC; + switch(sector_block) { + case 0x00: { + AC = ((access_bits_arr[1] >> 2) & 0x04) | ((access_bits_arr[2] << 1) & 0x02) | + ((access_bits_arr[2] >> 4) & 0x01); + break; + } + case 0x01: { + AC = ((access_bits_arr[1] >> 3) & 0x04) | ((access_bits_arr[2] >> 0) & 0x02) | + ((access_bits_arr[2] >> 5) & 0x01); + break; + } + case 0x02: { + AC = ((access_bits_arr[1] >> 4) & 0x04) | ((access_bits_arr[2] >> 1) & 0x02) | + ((access_bits_arr[2] >> 6) & 0x01); + break; + } + default: + return false; + } + + switch(action) { + case MfClassicActionDataRead: { + return ( + (key_type == MfClassicKeyTypeA && !(AC == 0x03 || AC == 0x05 || AC == 0x07)) || + (key_type == MfClassicKeyTypeB && !(AC == 0x07))); + } + case MfClassicActionDataWrite: { + return ( + (key_type == MfClassicKeyTypeA && (AC == 0x00)) || + (key_type == MfClassicKeyTypeB && + (AC == 0x00 || AC == 0x04 || AC == 0x06 || AC == 0x03))); + } + case MfClassicActionDataInc: { + return ( + (key_type == MfClassicKeyTypeA && (AC == 0x00)) || + (key_type == MfClassicKeyTypeB && (AC == 0x00 || AC == 0x06))); + } + case MfClassicActionDataDec: { + return ( + (key_type == MfClassicKeyTypeA && (AC == 0x00 || AC == 0x06 || AC == 0x01)) || + (key_type == MfClassicKeyTypeB && (AC == 0x00 || AC == 0x06 || AC == 0x01))); + } + default: + return false; + } + + return false; +} + +bool mf_classic_is_allowed_access( + MfClassicData* data, + uint8_t block_num, + MfClassicKeyType key_type, + MfClassicAction action) { + furi_assert(data); + + bool access_allowed = false; + if(mf_classic_is_sector_trailer(block_num)) { + access_allowed = + mf_classic_is_allowed_access_sector_trailer(data, block_num, key_type, action); + } else { + access_allowed = + mifare_classic_is_allowed_access_data_block(data, block_num, key_type, action); + } + + return access_allowed; +} diff --git a/lib/nfc/protocols/mf_classic/mf_classic.h b/lib/nfc/protocols/mf_classic/mf_classic.h index 056f9002bf37..b0fa14b063aa 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic.h +++ b/lib/nfc/protocols/mf_classic/mf_classic.h @@ -6,11 +6,13 @@ extern "C" { #endif -#define MF_CLASSIC_AUTH_KEY_A_CMD (0x60U) -#define MF_CLASSIC_AUTH_KEY_B_CMD (0x61U) -#define MF_CLASSIC_READ_BLOCK_CMD (0x30U) -#define MF_CLASSIC_HALT_MSB_CMD (0x50) -#define MF_CLASSIC_HALT_LSB_CMD (0x00) +#define MF_CLASSIC_CMD_AUTH_KEY_A (0x60U) +#define MF_CLASSIC_CMD_AUTH_KEY_B (0x61U) +#define MF_CLASSIC_CMD_READ_BLOCK (0x30U) +#define MF_CLASSIC_CMD_HALT_MSB (0x50) +#define MF_CLASSIC_CMD_HALT_LSB (0x00) +#define MF_CLASSIC_CMD_ACK (0x0A) +#define MF_CLASSIC_CMD_NACK (0x00) #define MF_CLASSIC_TOTAL_SECTORS_MAX (40) #define MF_CLASSIC_TOTAL_BLOCKS_MAX (256) @@ -193,6 +195,12 @@ void mf_classic_get_read_sectors_and_keys( bool mf_classic_is_card_read(const MfClassicData* data); +bool mf_classic_is_allowed_access( + MfClassicData* data, + uint8_t block_num, + MfClassicKeyType key_type, + MfClassicAction action); + #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/mf_classic/mf_classic_listener.c b/lib/nfc/protocols/mf_classic/mf_classic_listener.c new file mode 100644 index 000000000000..ee9cd76133e4 --- /dev/null +++ b/lib/nfc/protocols/mf_classic/mf_classic_listener.c @@ -0,0 +1,373 @@ +#include "mf_classic_listener_i.h" +#include "mf_classic_listener_defs.h" +#include + +#include +#include + +#define TAG "MfClassicListener" + +#define MF_CLASSIC_MAX_BUFF_SIZE (64) + +typedef MfClassicListenerCommand ( + *MfClassicListenerCommandCallback)(MfClassicListener* instance, BitBuffer* buf); + +typedef struct { + uint8_t cmd; + size_t cmd_len_bits; + MfClassicListenerCommandCallback callback; +} MfClassicListenerCmdHandler; + +static void mf_classic_listener_prepare_emulation(MfClassicListener* instance) { + instance->total_block_num = mf_classic_get_total_block_num(instance->data->type); +} + +static void mf_classic_listener_reset_state(MfClassicListener* instance) { + crypto1_reset(instance->crypto); + memset(&instance->auth_context, 0, sizeof(MfClassicAuthContext)); + instance->comm_state = MfClassicListenerCommStatePlain; + instance->state = MfClassicListenerStateIdle; + instance->auth_state = MfClassicListenerAuthStateIdle; + instance->cmd_type = MfClassicListenerCommandTypeOnePart; +} + +static MfClassicListenerCommand + mf_classic_listener_halt_handler(MfClassicListener* instance, BitBuffer* buff) { + MfClassicListenerCommand command = MfClassicListenerCommandNack; + + if(bit_buffer_get_byte(buff, 1) == MF_CLASSIC_CMD_HALT_LSB) { + mf_classic_listener_reset_state(instance); + command = MfClassicListenerCommandSilent; + } + + return command; +} + +static MfClassicListenerCommand mf_classic_listnener_auth_first_part_handler( + MfClassicListener* instance, + MfClassicKeyType key_type, + uint8_t block_num) { + MfClassicListenerCommand command = MfClassicListenerCommandNack; + do { + if(block_num >= instance->total_block_num) { + mf_classic_listener_reset_state(instance); + break; + } + + uint8_t sector_num = mf_classic_get_sector_by_block(block_num); + if(!mf_classic_is_key_found(instance->data, sector_num, key_type)) { + command = MfClassicListenerCommandSilent; + break; + } + + MfClassicSectorTrailer* sec_tr = + mf_classic_get_sector_trailer_by_sector(instance->data, sector_num); + MfClassicKey* key = (key_type == MfClassicKeyTypeA) ? &sec_tr->key_a : &sec_tr->key_b; + uint64_t key_num = nfc_util_bytes2num(key->data, sizeof(MfClassicKey)); + uint32_t cuid = iso14443_3a_get_cuid(instance->data->iso14443_3a_data); + + instance->auth_context.key_type = key_type; + instance->auth_context.block_num = block_num; + + furi_hal_random_fill_buf(instance->auth_context.nt.data, sizeof(MfClassicNt)); + uint32_t nt_num = nfc_util_bytes2num(instance->auth_context.nt.data, sizeof(MfClassicNt)); + + crypto1_init(instance->crypto, key_num); + if(instance->comm_state == MfClassicListenerCommStatePlain) { + crypto1_word(instance->crypto, nt_num ^ cuid, 0); + bit_buffer_copy_bytes( + instance->tx_encrypted_buffer, + instance->auth_context.nt.data, + sizeof(MfClassicNt)); + iso14443_3a_listener_tx(instance->iso14443_3a_listener, instance->tx_encrypted_buffer); + command = MfClassicListenerCommandProcessed; + } else { + uint8_t key_stream[4] = {}; + nfc_util_num2bytes(nt_num ^ cuid, sizeof(uint32_t), key_stream); + bit_buffer_copy_bytes( + instance->tx_plain_buffer, instance->auth_context.nt.data, sizeof(MfClassicNt)); + crypto1_encrypt( + instance->crypto, + key_stream, + instance->tx_plain_buffer, + instance->tx_encrypted_buffer); + + iso14443_3a_listener_tx(instance->iso14443_3a_listener, instance->tx_encrypted_buffer); + + command = MfClassicListenerCommandProcessed; + } + + instance->auth_state = MfClassicListenerAuthStateStarted; + instance->cmd_type = MfClassicListenerCommandTypeTwoParts; + instance->second_part = MfClassicListenerCommandSecondPartAuth; + } while(false); + + return command; +} + +static MfClassicListenerCommand + mf_classic_listener_auth_key_a_handler(MfClassicListener* instance, BitBuffer* buff) { + MfClassicListenerCommand command = mf_classic_listnener_auth_first_part_handler( + instance, MfClassicKeyTypeA, bit_buffer_get_byte(buff, 1)); + + return command; +} + +static MfClassicListenerCommand + mf_classic_listener_auth_key_b_handler(MfClassicListener* instance, BitBuffer* buff) { + MfClassicListenerCommand command = mf_classic_listnener_auth_first_part_handler( + instance, MfClassicKeyTypeB, bit_buffer_get_byte(buff, 1)); + + return command; +} + +static MfClassicListenerCommand + mf_classic_listener_auth_second_part_handler(MfClassicListener* instance, BitBuffer* buff) { + MfClassicListenerCommand command = MfClassicListenerCommandSilent; + + do { + if(bit_buffer_get_size_bytes(buff) != (sizeof(MfClassicNr) + sizeof(MfClassicAr))) { + mf_classic_listener_reset_state(instance); + break; + } + bit_buffer_write_bytes_mid(buff, instance->auth_context.nr.data, 0, sizeof(MfClassicNr)); + bit_buffer_write_bytes_mid( + buff, instance->auth_context.ar.data, sizeof(MfClassicNr), sizeof(MfClassicAr)); + uint32_t nr_num = nfc_util_bytes2num(instance->auth_context.nr.data, sizeof(MfClassicNr)); + uint32_t ar_num = nfc_util_bytes2num(instance->auth_context.ar.data, sizeof(MfClassicAr)); + + crypto1_word(instance->crypto, nr_num, 1); + uint32_t nt_num = nfc_util_bytes2num(instance->auth_context.nt.data, sizeof(MfClassicNt)); + uint32_t secret_poller = ar_num ^ crypto1_word(instance->crypto, 0, 0); + if(secret_poller != prng_successor(nt_num, 64)) { + FURI_LOG_D( + TAG, "Wrong reader key: %08lX != %08lX", secret_poller, prng_successor(nt_num, 64)); + mf_classic_listener_reset_state(instance); + break; + } + + uint32_t at_num = prng_successor(nt_num, 96); + nfc_util_num2bytes(at_num, sizeof(uint32_t), instance->auth_context.at.data); + bit_buffer_copy_bytes( + instance->tx_plain_buffer, instance->auth_context.at.data, sizeof(MfClassicAr)); + crypto1_encrypt( + instance->crypto, NULL, instance->tx_plain_buffer, instance->tx_encrypted_buffer); + iso14443_3a_listener_tx_with_custom_parity( + instance->iso14443_3a_listener, instance->tx_encrypted_buffer); + + instance->auth_state = MfClassicListenerAuthStateIdle; + instance->state = MfClassicListenerStateAuthComplete; + instance->comm_state = MfClassicListenerCommStateEncrypted; + instance->cmd_type = MfClassicListenerCommandTypeOnePart; + + if(instance->callback) { + instance->mfc_event_data.auth_context = instance->auth_context; + instance->callback(instance->generic_event, instance->context); + } + } while(false); + + return command; +} + +static MfClassicListenerCommand + mf_classic_listener_read_block_handler(MfClassicListener* instance, BitBuffer* buff) { + MfClassicListenerCommand command = MfClassicListenerCommandNack; + MfClassicAuthContext* auth_ctx = &instance->auth_context; + + do { + uint8_t block_num = bit_buffer_get_byte(buff, 1); + uint8_t sector_num = mf_classic_get_sector_by_block(block_num); + uint8_t auth_sector_num = mf_classic_get_sector_by_block(auth_ctx->block_num); + if(sector_num != auth_sector_num) break; + + MfClassicBlock access_block = instance->data->block[block_num]; + + if(mf_classic_is_sector_trailer(block_num)) { + MfClassicSectorTrailer* access_sec_tr = (MfClassicSectorTrailer*)&access_block; + if(!mf_classic_is_allowed_access( + instance->data, block_num, auth_ctx->key_type, MfClassicActionKeyARead)) { + memset(access_sec_tr->key_a.data, 0, sizeof(MfClassicKey)); + } + if(!mf_classic_is_allowed_access( + instance->data, block_num, auth_ctx->key_type, MfClassicActionKeyBRead)) { + memset(access_sec_tr->key_b.data, 0, sizeof(MfClassicKey)); + } + if(!mf_classic_is_allowed_access( + instance->data, block_num, auth_ctx->key_type, MfClassicActionACRead)) { + memset(access_sec_tr->access_bits.data, 0, sizeof(MfClassicAccessBits)); + } + } else if(!mf_classic_is_allowed_access( + instance->data, block_num, auth_ctx->key_type, MfClassicActionDataRead)) { + break; + } + + bit_buffer_copy_bytes( + instance->tx_plain_buffer, access_block.data, sizeof(MfClassicBlock)); + iso14443_3a_append_crc(instance->tx_plain_buffer); + crypto1_encrypt( + instance->crypto, NULL, instance->tx_plain_buffer, instance->tx_encrypted_buffer); + iso14443_3a_listener_tx_with_custom_parity( + instance->iso14443_3a_listener, instance->tx_encrypted_buffer); + command = MfClassicListenerCommandProcessed; + } while(false); + + return command; +} + +static const MfClassicListenerCmdHandler mf_classic_cmd_first_part[] = { + { + .cmd = MF_CLASSIC_CMD_HALT_MSB, + .cmd_len_bits = 4 * 8, + .callback = mf_classic_listener_halt_handler, + }, + { + .cmd = MF_CLASSIC_CMD_AUTH_KEY_A, + .cmd_len_bits = 2 * 8, + .callback = mf_classic_listener_auth_key_a_handler, + }, + { + .cmd = MF_CLASSIC_CMD_AUTH_KEY_B, + .cmd_len_bits = 2 * 8, + .callback = mf_classic_listener_auth_key_b_handler, + }, + { + .cmd = MF_CLASSIC_CMD_READ_BLOCK, + .cmd_len_bits = 4 * 8, + .callback = mf_classic_listener_read_block_handler, + }, +}; + +static const MfClassicListenerCmdHandler + mf_classic_cmd_second_part[MfClassicListenerCommandSecondPartNum] = { + [MfClassicListenerCommandSecondPartAuth] = + { + .callback = mf_classic_listener_auth_second_part_handler, + }, +}; + +MfClassicListener* + mf_classic_listener_alloc(Iso14443_3aListener* iso14443_3a_listener, MfClassicData* data) { + MfClassicListener* instance = malloc(sizeof(MfClassicListener)); + instance->iso14443_3a_listener = iso14443_3a_listener; + instance->data = mf_classic_alloc(); + mf_classic_copy(instance->data, data); + mf_classic_listener_prepare_emulation(instance); + + instance->crypto = crypto1_alloc(); + instance->tx_plain_buffer = bit_buffer_alloc(MF_CLASSIC_MAX_BUFF_SIZE); + instance->tx_encrypted_buffer = bit_buffer_alloc(MF_CLASSIC_MAX_BUFF_SIZE); + instance->rx_plain_buffer = bit_buffer_alloc(MF_CLASSIC_MAX_BUFF_SIZE); + + instance->mfc_event.data = &instance->mfc_event_data; + instance->generic_event.protocol = NfcProtocolMfClassic; + instance->generic_event.data = &instance->mfc_event; + instance->generic_event.instance = instance; + + return instance; +} + +void mf_classic_listener_free(MfClassicListener* instance) { + furi_assert(instance); + furi_assert(instance->data); + furi_assert(instance->crypto); + furi_assert(instance->rx_plain_buffer); + furi_assert(instance->tx_encrypted_buffer); + furi_assert(instance->tx_plain_buffer); + + mf_classic_free(instance->data); + crypto1_free(instance->crypto); + bit_buffer_free(instance->rx_plain_buffer); + bit_buffer_free(instance->tx_encrypted_buffer); + bit_buffer_free(instance->tx_plain_buffer); + + free(instance); +} + +void mf_classic_listener_set_callback( + MfClassicListener* instance, + NfcGenericCallback callback, + void* context) { + furi_assert(instance); + + instance->callback = callback; + instance->context = context; +} + +const MfClassicData* mf_classic_listener_get_data(const MfClassicListener* instance) { + furi_assert(instance); + furi_assert(instance->data); + + return instance->data; +} + +static void mf_classic_listener_send_short_frame(MfClassicListener* instance, uint8_t data) { + BitBuffer* tx_buffer = instance->tx_plain_buffer; + + bit_buffer_set_size(instance->tx_plain_buffer, 4); + bit_buffer_set_byte(instance->tx_plain_buffer, 0, data); + if(instance->comm_state == MfClassicListenerCommStateEncrypted) { + crypto1_encrypt( + instance->crypto, NULL, instance->tx_plain_buffer, instance->tx_encrypted_buffer); + tx_buffer = instance->tx_encrypted_buffer; + } + + iso14443_3a_listener_tx(instance->iso14443_3a_listener, tx_buffer); +} + +NfcCommand mf_classic_listener_run(NfcGenericEvent event, void* context) { + furi_assert(context); + furi_assert(event.data); + furi_assert(event.protocol == NfcProtocolIso14443_3a); + + NfcCommand command = NfcCommandContinue; + MfClassicListener* instance = context; + Iso14443_3aListenerEvent* iso3_event = event.data; + BitBuffer* rx_buffer_plain; + + if(iso3_event->type == Iso14443_3aListenerEventTypeFieldOff) { + mf_classic_listener_reset_state(instance); + } else if( + (iso3_event->type == Iso14443_3aListenerEventTypeReceivedData) || + (iso3_event->type == Iso14443_3aListenerEventTypeReceivedStandardFrame)) { + if(instance->comm_state == MfClassicListenerCommStateEncrypted) { + crypto1_decrypt(instance->crypto, iso3_event->data->buffer, instance->rx_plain_buffer); + rx_buffer_plain = instance->rx_plain_buffer; + } else { + rx_buffer_plain = iso3_event->data->buffer; + } + + MfClassicListenerCommand mfc_command = MfClassicListenerCommandNack; + if(instance->cmd_type == MfClassicListenerCommandTypeOnePart) { + for(size_t i = 0; i < COUNT_OF(mf_classic_cmd_first_part); i++) { + if(bit_buffer_get_size(rx_buffer_plain) != + mf_classic_cmd_first_part[i].cmd_len_bits) + continue; + if(bit_buffer_get_byte(rx_buffer_plain, 0) != mf_classic_cmd_first_part[i].cmd) + continue; + mfc_command = mf_classic_cmd_first_part[i].callback(instance, rx_buffer_plain); + break; + } + } else { + mfc_command = mf_classic_cmd_second_part[instance->second_part].callback( + instance, rx_buffer_plain); + } + + if(mfc_command == MfClassicListenerCommandAck) { + mf_classic_listener_send_short_frame(instance, MF_CLASSIC_CMD_ACK); + } else if(mfc_command == MfClassicListenerCommandNack) { + mf_classic_listener_send_short_frame(instance, MF_CLASSIC_CMD_NACK); + } + } else if(iso3_event->type == Iso14443_3aListenerEventTypeHalted) { + mf_classic_listener_reset_state(instance); + } + + return command; +} + +const NfcListenerBase mf_classic_listener = { + .alloc = (NfcListenerAlloc)mf_classic_listener_alloc, + .free = (NfcListenerFree)mf_classic_listener_free, + .set_callback = (NfcListenerSetCallback)mf_classic_listener_set_callback, + .get_data = (NfcListenerGetData)mf_classic_listener_get_data, + .run = (NfcListenerRun)mf_classic_listener_run, +}; diff --git a/lib/nfc/protocols/mf_classic/mf_classic_listener.h b/lib/nfc/protocols/mf_classic/mf_classic_listener.h new file mode 100644 index 000000000000..676901510f3d --- /dev/null +++ b/lib/nfc/protocols/mf_classic/mf_classic_listener.h @@ -0,0 +1,26 @@ +#pragma once + +#include "mf_classic.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct MfClassicListener MfClassicListener; + +typedef enum { + MfClassicListenerEventTypeAuthContextGathered, +} MfClassicListenerEventType; + +typedef union { + MfClassicAuthContext auth_context; +} MfClassicListenerEventData; + +typedef struct { + MfClassicListenerEventType type; + MfClassicListenerEventData* data; +} MfClassicListenerEvent; + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/mf_classic/mf_classic_listener_defs.h b/lib/nfc/protocols/mf_classic/mf_classic_listener_defs.h new file mode 100644 index 000000000000..6c7a1dd6a74e --- /dev/null +++ b/lib/nfc/protocols/mf_classic/mf_classic_listener_defs.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern const NfcListenerBase mf_classic_listener; + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/mf_classic/mf_classic_listener_i.h b/lib/nfc/protocols/mf_classic/mf_classic_listener_i.h new file mode 100644 index 000000000000..5e617b5e92b7 --- /dev/null +++ b/lib/nfc/protocols/mf_classic/mf_classic_listener_i.h @@ -0,0 +1,76 @@ +#pragma once + +#include "mf_classic_listener.h" +#include +#include +#include "crypto1.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + MfClassicListenerCommandProcessed, + MfClassicListenerCommandAck, + MfClassicListenerCommandNack, + MfClassicListenerCommandSilent, +} MfClassicListenerCommand; + +typedef enum { + MfClassicListenerStateIdle, + MfClassicListenerStateAuthComplete, +} MfClassicListenerState; + +typedef enum { + MfClassicListenerAuthStateIdle, + MfClassicListenerAuthStateStarted, + MfClassicListenerAuthStatePollerSecretReceived, +} MfClassicListenerAuthState; + +typedef enum { + MfClassicListenerCommStatePlain, + MfClassicListenerCommStateEncrypted, +} MfClassicListenerCommState; + +typedef enum { + MfClassicListenerCommandTypeOnePart, + MfClassicListenerCommandTypeTwoParts, +} MfClassicListenerCommandType; + +typedef enum { + MfClassicListenerCommandSecondPartAuth, + MfClassicListenerCommandSecondPartWrite, + MfClassicListenerCommandSecondPartInc, + MfClassicListenerCommandSecondPartDec, + + MfClassicListenerCommandSecondPartNum, +} MfClassicListenerCommandSecondPart; + +struct MfClassicListener { + Iso14443_3aListener* iso14443_3a_listener; + MfClassicListenerState state; + MfClassicListenerAuthState auth_state; + MfClassicListenerCommState comm_state; + MfClassicListenerCommandType cmd_type; + MfClassicListenerCommandSecondPart second_part; + + MfClassicData* data; + BitBuffer* tx_plain_buffer; + BitBuffer* tx_encrypted_buffer; + BitBuffer* rx_plain_buffer; + + Crypto1* crypto; + MfClassicAuthContext auth_context; + + NfcGenericEvent generic_event; + MfClassicListenerEvent mfc_event; + MfClassicListenerEventData mfc_event_data; + NfcGenericCallback callback; + void* context; + + size_t total_block_num; +}; + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_defs.h b/lib/nfc/protocols/mf_classic/mf_classic_poller_defs.h index 09b86c04c351..d0c0b18fcfc2 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_defs.h +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_defs.h @@ -2,4 +2,12 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + extern const NfcPollerBase mf_classic_poller; + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c index 4944d46352c8..a1060fc1186f 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c @@ -46,8 +46,8 @@ MfClassicError mf_classic_async_auth( iso14443_3a_copy( instance->data->iso14443_3a_data, iso14443_3a_poller_get_data(instance->iso14443_3a_poller)); - uint8_t auth_type = (key_type == MfClassicKeyTypeB) ? MF_CLASSIC_AUTH_KEY_B_CMD : - MF_CLASSIC_AUTH_KEY_A_CMD; + uint8_t auth_type = (key_type == MfClassicKeyTypeB) ? MF_CLASSIC_CMD_AUTH_KEY_B : + MF_CLASSIC_CMD_AUTH_KEY_A; uint8_t auth_cmd[2] = {auth_type, block_num}; bit_buffer_copy_bytes(instance->tx_plain_buffer, auth_cmd, sizeof(auth_cmd)); @@ -115,7 +115,7 @@ MfClassicError mf_classic_aync_halt(MfClassicPoller* instance) { Iso14443_3aError error = Iso14443_3aErrorNone; do { - uint8_t halt_cmd[2] = {MF_CLASSIC_HALT_MSB_CMD, MF_CLASSIC_HALT_LSB_CMD}; + uint8_t halt_cmd[2] = {MF_CLASSIC_CMD_HALT_MSB, MF_CLASSIC_CMD_HALT_LSB}; bit_buffer_copy_bytes(instance->tx_plain_buffer, halt_cmd, sizeof(halt_cmd)); iso14443_3a_append_crc(instance->tx_plain_buffer); @@ -146,7 +146,7 @@ MfClassicError mf_classic_async_read_block( Iso14443_3aError error = Iso14443_3aErrorNone; do { - uint8_t read_block_cmd[2] = {MF_CLASSIC_READ_BLOCK_CMD, block_num}; + uint8_t read_block_cmd[2] = {MF_CLASSIC_CMD_READ_BLOCK, block_num}; bit_buffer_copy_bytes(instance->tx_plain_buffer, read_block_cmd, sizeof(read_block_cmd)); iso14443_3a_append_crc(instance->tx_plain_buffer); diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.h index befbdc837385..fa6a6bd7e70a 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.h @@ -1,7 +1,6 @@ #pragma once #include "mf_ultralight.h" -#include #ifdef __cplusplus extern "C" { diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h index 52ea07486f64..10aaec982833 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h @@ -1,6 +1,7 @@ #pragma once #include "mf_ultralight_listener.h" +#include #include #ifdef __cplusplus diff --git a/lib/nfc/protocols/nfc_listener_defs.c b/lib/nfc/protocols/nfc_listener_defs.c index 7c7e3d26030e..539cec4afa1a 100644 --- a/lib/nfc/protocols/nfc_listener_defs.c +++ b/lib/nfc/protocols/nfc_listener_defs.c @@ -3,12 +3,12 @@ #include // #include #include -// #include +#include const NfcListenerBase* nfc_listeners_api[NfcProtocolNum] = { [NfcProtocolIso14443_3a] = &nfc_listener_iso14443_3a, [NfcProtocolIso14443_4a] = NULL, //&nfc_listener_iso14443_4a, [NfcProtocolMfUltralight] = &mf_ultralight_listener, - [NfcProtocolMfClassic] = NULL, //&mf_classic_listener, + [NfcProtocolMfClassic] = &mf_classic_listener, [NfcProtocolMfDesfire] = NULL, }; From 2196a531c3c6ac2549ef95236dd36f5c488c4b18 Mon Sep 17 00:00:00 2001 From: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Date: Wed, 12 Jul 2023 18:07:23 +0300 Subject: [PATCH 122/149] [NFC] ISO14443-4A emulation, MF DESFire and GUI fixes (#2869) --- .../main/nfc/helpers/nfc_custom_event.h | 8 +- .../iso14443_3a/iso14443_3a.c | 64 ++++-- .../iso14443_4a/iso14443_4a.c | 52 ++++- .../iso14443_4a/iso14443_4a_i.h | 7 + .../protocol_support/mf_classic/mf_classic.c | 49 +++-- .../protocol_support/mf_desfire/mf_desfire.c | 52 ++--- .../mf_ultralight/mf_ultralight.c | 46 ++-- .../protocol_support/nfc_protocol_support.c | 205 ++++++++++++++---- .../nfc_protocol_support_base.h | 1 + .../nfc_protocol_support_common.h | 1 + .../nfc_protocol_support_gui_common.c | 20 +- .../nfc_protocol_support_gui_common.h | 6 + applications/main/nfc/nfc_app.c | 2 +- .../main/nfc/scenes/nfc_scene_config.h | 5 +- .../main/nfc/scenes/nfc_scene_emulate.c | 13 ++ .../nfc/scenes/nfc_scene_mf_classic_emulate.c | 46 ---- .../scenes/nfc_scene_mf_ultralight_emulate.c | 66 ------ .../main/nfc/scenes/nfc_scene_nfca_emulate.c | 142 ------------ .../main/nfc/scenes/nfc_scene_set_type.c | 2 - .../main/nfc/scenes/nfc_scene_start.c | 4 + documentation/file_formats/NfcFileFormats.md | 2 +- lib/nfc/helpers/simple_array.c | 7 + lib/nfc/helpers/simple_array.h | 2 + lib/nfc/protocols/iso14443_4a/iso14443_4a.c | 22 +- lib/nfc/protocols/iso14443_4a/iso14443_4a.h | 15 +- lib/nfc/protocols/iso14443_4a/iso14443_4a_i.c | 62 ++++-- lib/nfc/protocols/iso14443_4a/iso14443_4a_i.h | 42 +++- .../iso14443_4a/iso14443_4a_listener.c | 102 +++++++++ .../iso14443_4a/iso14443_4a_listener.h | 29 +++ .../iso14443_4a/iso14443_4a_listener_defs.h | 13 ++ .../iso14443_4a/iso14443_4a_listener_i.c | 13 ++ .../iso14443_4a/iso14443_4a_listener_i.h | 36 +++ .../iso14443_4a/iso14443_4a_poller.c | 9 +- .../iso14443_4a/iso14443_4a_poller_i.c | 30 +-- .../iso14443_4a/iso14443_4a_poller_i.h | 5 +- lib/nfc/protocols/mf_desfire/mf_desfire_i.c | 195 ++++++++++++++--- lib/nfc/protocols/mf_desfire/mf_desfire_i.h | 17 +- .../mf_desfire/mf_desfire_poller_i.c | 172 +++++++++------ lib/nfc/protocols/nfc_listener_defs.c | 4 +- 39 files changed, 972 insertions(+), 596 deletions(-) create mode 100644 applications/main/nfc/helpers/protocol_support/iso14443_4a/iso14443_4a_i.h create mode 100644 applications/main/nfc/scenes/nfc_scene_emulate.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_mf_classic_emulate.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_mf_ultralight_emulate.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_nfca_emulate.c create mode 100644 lib/nfc/protocols/iso14443_4a/iso14443_4a_listener.c create mode 100644 lib/nfc/protocols/iso14443_4a/iso14443_4a_listener.h create mode 100644 lib/nfc/protocols/iso14443_4a/iso14443_4a_listener_defs.h create mode 100644 lib/nfc/protocols/iso14443_4a/iso14443_4a_listener_i.c create mode 100644 lib/nfc/protocols/iso14443_4a/iso14443_4a_listener_i.h diff --git a/applications/main/nfc/helpers/nfc_custom_event.h b/applications/main/nfc/helpers/nfc_custom_event.h index 520679effd65..9d09caf90114 100644 --- a/applications/main/nfc/helpers/nfc_custom_event.h +++ b/applications/main/nfc/helpers/nfc_custom_event.h @@ -26,8 +26,8 @@ typedef enum { NfcCustomEventRpcLoad, NfcCustomEventRpcSessionClose, - NfcCustomEventReadHandlerIgnore, - NfcCustomEventReadHandlerSuccess, - NfcCustomEventReadHandlerFailure, - NfcCustomEventReadHandlerAltRead, + NfcCustomEventPollerSuccess, + NfcCustomEventPollerFailure, + + NfcCustomEventListenerUpdate, } NfcCustomEvent; diff --git a/applications/main/nfc/helpers/protocol_support/iso14443_3a/iso14443_3a.c b/applications/main/nfc/helpers/protocol_support/iso14443_3a/iso14443_3a.c index 0cd53005f320..1ac5870c7fd5 100644 --- a/applications/main/nfc/helpers/protocol_support/iso14443_3a/iso14443_3a.c +++ b/applications/main/nfc/helpers/protocol_support/iso14443_3a/iso14443_3a.c @@ -3,8 +3,9 @@ #include +#include "nfc/nfc_app_i.h" + #include "../nfc_protocol_support_gui_common.h" -#include "../../../nfc_app_i.h" static void nfc_scene_info_on_enter_iso14443_3a(NfcApp* instance) { const NfcDevice* device = instance->nfc_device; @@ -31,8 +32,7 @@ static NfcCommand if(iso14443_3a_event->type == Iso14443_3aPollerEventTypeReady) { nfc_device_set_data( instance->nfc_device, NfcProtocolIso14443_3a, nfc_poller_get_data(instance->poller)); - view_dispatcher_send_custom_event( - instance->view_dispatcher, NfcCustomEventReadHandlerSuccess); + view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventPollerSuccess); return NfcCommandStop; } @@ -43,10 +43,6 @@ static void nfc_scene_read_on_enter_iso14443_3a(NfcApp* instance) { nfc_poller_start(instance->poller, nfc_scene_read_poller_callback_iso14443_3a, instance); } -static void nfc_scene_read_menu_on_enter_iso14443_3a(NfcApp* instance) { - UNUSED(instance); -} - static void nfc_scene_read_success_on_enter_iso14443_3a(NfcApp* instance) { const NfcDevice* device = instance->nfc_device; const Iso14443_3aData* data = nfc_device_get_data(device, NfcProtocolIso14443_3a); @@ -62,8 +58,37 @@ static void nfc_scene_read_success_on_enter_iso14443_3a(NfcApp* instance) { furi_string_free(temp_str); } -static void nfc_scene_saved_menu_on_enter_iso14443_3a(NfcApp* instance) { - UNUSED(instance); +static NfcCommand + nfc_scene_emulate_listener_callback_iso14443_3a(NfcGenericEvent event, void* context) { + furi_assert(context); + furi_assert(event.protocol == NfcProtocolIso14443_3a); + furi_assert(event.data); + + NfcApp* nfc = context; + Iso14443_3aListenerEvent* iso14443_3a_event = event.data; + + if(iso14443_3a_event->type == Iso14443_3aListenerEventTypeReceivedStandardFrame) { + furi_string_cat_printf(nfc->text_box_store, "R:"); + for(size_t i = 0; i < bit_buffer_get_size_bytes(iso14443_3a_event->data->buffer); i++) { + furi_string_cat_printf( + nfc->text_box_store, + " %02X", + bit_buffer_get_byte(iso14443_3a_event->data->buffer, i)); + } + furi_string_push_back(nfc->text_box_store, '\n'); + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventListenerUpdate); + } + + return NfcCommandContinue; +} + +static void nfc_scene_emulate_on_enter_iso14443_3a(NfcApp* instance) { + const Iso14443_3aData* data = + nfc_device_get_data(instance->nfc_device, NfcProtocolIso14443_3a); + + instance->listener = nfc_listener_alloc(instance->nfc, NfcProtocolIso14443_3a, data); + nfc_listener_start( + instance->listener, nfc_scene_emulate_listener_callback_iso14443_3a, instance); } static bool nfc_scene_info_on_event_iso14443_3a(NfcApp* instance, uint32_t event) { @@ -77,7 +102,7 @@ static bool nfc_scene_info_on_event_iso14443_3a(NfcApp* instance, uint32_t event static bool nfc_scene_read_menu_on_event_iso14443_3a(NfcApp* instance, uint32_t event) { if(event == SubmenuIndexCommonEmulate) { - scene_manager_next_scene(instance->scene_manager, NfcSceneNfcaEmulate); + scene_manager_next_scene(instance->scene_manager, NfcSceneEmulate); return true; } @@ -85,16 +110,12 @@ static bool nfc_scene_read_menu_on_event_iso14443_3a(NfcApp* instance, uint32_t } bool nfc_scene_saved_menu_on_event_iso14443_3a_common(NfcApp* instance, uint32_t event) { - switch(event) { - case SubmenuIndexCommonEmulate: - scene_manager_next_scene(instance->scene_manager, NfcSceneNfcaEmulate); - return true; - case SubmenuIndexCommonEdit: + if(event == SubmenuIndexCommonEdit) { scene_manager_next_scene(instance->scene_manager, NfcSceneSetUid); return true; - default: - return false; } + + return false; } static bool nfc_scene_saved_menu_on_event_iso14443_3a(NfcApp* instance, uint32_t event) { @@ -116,7 +137,7 @@ const NfcProtocolSupportBase nfc_protocol_support_iso14443_3a = { }, .scene_read_menu = { - .on_enter = nfc_scene_read_menu_on_enter_iso14443_3a, + .on_enter = nfc_protocol_support_common_on_enter_empty, .on_event = nfc_scene_read_menu_on_event_iso14443_3a, }, .scene_read_success = @@ -126,7 +147,12 @@ const NfcProtocolSupportBase nfc_protocol_support_iso14443_3a = { }, .scene_saved_menu = { - .on_enter = nfc_scene_saved_menu_on_enter_iso14443_3a, + .on_enter = nfc_protocol_support_common_on_enter_empty, .on_event = nfc_scene_saved_menu_on_event_iso14443_3a, }, + .scene_emulate = + { + .on_enter = nfc_scene_emulate_on_enter_iso14443_3a, + .on_event = NULL, + }, }; diff --git a/applications/main/nfc/helpers/protocol_support/iso14443_4a/iso14443_4a.c b/applications/main/nfc/helpers/protocol_support/iso14443_4a/iso14443_4a.c index e7a4012867e1..8de3c8af83cd 100644 --- a/applications/main/nfc/helpers/protocol_support/iso14443_4a/iso14443_4a.c +++ b/applications/main/nfc/helpers/protocol_support/iso14443_4a/iso14443_4a.c @@ -2,10 +2,12 @@ #include "iso14443_4a_render.h" #include +#include + +#include "nfc/nfc_app_i.h" #include "../nfc_protocol_support_gui_common.h" #include "../iso14443_3a/iso14443_3a_i.h" -#include "../../../nfc_app_i.h" static void nfc_scene_info_on_enter_iso14443_4a(NfcApp* instance) { const NfcDevice* device = instance->nfc_device; @@ -32,8 +34,7 @@ static NfcCommand if(iso14443_4a_event->type == Iso14443_4aPollerEventTypeReady) { nfc_device_set_data( instance->nfc_device, NfcProtocolIso14443_4a, nfc_poller_get_data(instance->poller)); - view_dispatcher_send_custom_event( - instance->view_dispatcher, NfcCustomEventReadHandlerSuccess); + view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventPollerSuccess); return NfcCommandStop; } @@ -44,10 +45,6 @@ static void nfc_scene_read_on_enter_iso14443_4a(NfcApp* instance) { nfc_poller_start(instance->poller, nfc_scene_read_poller_callback_iso14443_4a, instance); } -static void nfc_scene_read_menu_on_enter_iso14443_4a(NfcApp* instance) { - UNUSED(instance); -} - static void nfc_scene_read_success_on_enter_iso14443_4a(NfcApp* instance) { const NfcDevice* device = instance->nfc_device; const Iso14443_4aData* data = nfc_device_get_data(device, NfcProtocolIso14443_4a); @@ -67,6 +64,38 @@ static void nfc_scene_saved_menu_on_enter_iso14443_4a(NfcApp* instance) { UNUSED(instance); } +NfcCommand nfc_scene_emulate_listener_callback_iso14443_4a(NfcGenericEvent event, void* context) { + furi_assert(context); + furi_assert(event.protocol == NfcProtocolIso14443_4a); + furi_assert(event.data); + + NfcApp* nfc = context; + Iso14443_4aListenerEvent* iso14443_4a_event = event.data; + + if(iso14443_4a_event->type == Iso14443_4aListenerEventTypeReceivedData) { + furi_string_cat_printf(nfc->text_box_store, "R:"); + for(size_t i = 0; i < bit_buffer_get_size_bytes(iso14443_4a_event->data->buffer); i++) { + furi_string_cat_printf( + nfc->text_box_store, + " %02X", + bit_buffer_get_byte(iso14443_4a_event->data->buffer, i)); + } + furi_string_push_back(nfc->text_box_store, '\n'); + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventListenerUpdate); + } + + return NfcCommandContinue; +} + +static void nfc_scene_emulate_on_enter_iso14443_4a(NfcApp* instance) { + const Iso14443_4aData* data = + nfc_device_get_data(instance->nfc_device, NfcProtocolIso14443_4a); + + instance->listener = nfc_listener_alloc(instance->nfc, NfcProtocolIso14443_4a, data); + nfc_listener_start( + instance->listener, nfc_scene_emulate_listener_callback_iso14443_4a, instance); +} + static bool nfc_scene_info_on_event_iso14443_4a(NfcApp* instance, uint32_t event) { if(event == GuiButtonTypeRight) { scene_manager_next_scene(instance->scene_manager, NfcSceneNotImplemented); @@ -78,7 +107,7 @@ static bool nfc_scene_info_on_event_iso14443_4a(NfcApp* instance, uint32_t event static bool nfc_scene_read_menu_on_event_iso14443_4a(NfcApp* instance, uint32_t event) { if(event == SubmenuIndexCommonEmulate) { - scene_manager_next_scene(instance->scene_manager, NfcSceneNfcaEmulate); + scene_manager_next_scene(instance->scene_manager, NfcSceneEmulate); return true; } @@ -104,7 +133,7 @@ const NfcProtocolSupportBase nfc_protocol_support_iso14443_4a = { }, .scene_read_menu = { - .on_enter = nfc_scene_read_menu_on_enter_iso14443_4a, + .on_enter = nfc_protocol_support_common_on_enter_empty, .on_event = nfc_scene_read_menu_on_event_iso14443_4a, }, .scene_read_success = @@ -117,4 +146,9 @@ const NfcProtocolSupportBase nfc_protocol_support_iso14443_4a = { .on_enter = nfc_scene_saved_menu_on_enter_iso14443_4a, .on_event = nfc_scene_saved_menu_on_event_iso14443_4a, }, + .scene_emulate = + { + .on_enter = nfc_scene_emulate_on_enter_iso14443_4a, + .on_event = NULL, + }, }; diff --git a/applications/main/nfc/helpers/protocol_support/iso14443_4a/iso14443_4a_i.h b/applications/main/nfc/helpers/protocol_support/iso14443_4a/iso14443_4a_i.h new file mode 100644 index 000000000000..7e13403da13a --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/iso14443_4a/iso14443_4a_i.h @@ -0,0 +1,7 @@ +#pragma once + +#include + +#include "iso14443_4a.h" + +NfcCommand nfc_scene_emulate_listener_callback_iso14443_4a(NfcGenericEvent event, void* context); diff --git a/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c b/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c index eca8f63792a2..b416e5a11093 100644 --- a/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c +++ b/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c @@ -3,8 +3,9 @@ #include +#include "nfc/nfc_app_i.h" + #include "../nfc_protocol_support_gui_common.h" -#include "../../../nfc_app_i.h" enum { SubmenuIndexDetectReader = SubmenuIndexCommonMax, @@ -44,8 +45,7 @@ static NfcCommand nfc_scene_read_poller_callback_mf_classic(NfcGenericEvent even if(mf_classic_event->type == MfClassicPollerEventTypeReadComplete) { nfc_device_set_data( instance->nfc_device, NfcProtocolMfClassic, nfc_poller_get_data(instance->poller)); - view_dispatcher_send_custom_event( - instance->view_dispatcher, NfcCustomEventReadHandlerSuccess); + view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventPollerSuccess); return NfcCommandStop; } @@ -111,6 +111,12 @@ static void nfc_scene_saved_menu_on_enter_mf_classic(NfcApp* instance) { instance); } +static void nfc_scene_emulate_on_enter_mf_classic(NfcApp* instance) { + const MfClassicData* data = nfc_device_get_data(instance->nfc_device, NfcProtocolMfClassic); + instance->listener = nfc_listener_alloc(instance->nfc, NfcProtocolMfClassic, data); + nfc_listener_start(instance->listener, NULL, NULL); +} + static bool nfc_scene_info_on_event_mf_classic(NfcApp* instance, uint32_t event) { if(event == GuiButtonTypeRight) { scene_manager_next_scene(instance->scene_manager, NfcSceneNotImplemented); @@ -121,36 +127,30 @@ static bool nfc_scene_info_on_event_mf_classic(NfcApp* instance, uint32_t event) } static bool nfc_scene_read_menu_on_event_mf_classic(NfcApp* instance, uint32_t event) { - switch(event) { - case SubmenuIndexCommonEmulate: - scene_manager_next_scene(instance->scene_manager, NfcSceneNotImplemented); - return true; - case SubmenuIndexDetectReader: + if(event == SubmenuIndexDetectReader) { scene_manager_next_scene(instance->scene_manager, NfcSceneNotImplemented); dolphin_deed(DolphinDeedNfcDetectReader); return true; - default: - return false; } + + return false; } static bool nfc_scene_saved_menu_on_event_mf_classic(NfcApp* instance, uint32_t event) { - switch(event) { - case SubmenuIndexCommonEmulate: - scene_manager_next_scene(instance->scene_manager, NfcSceneMfClassicEmulate); - return true; - case SubmenuIndexDetectReader: + bool consumed = false; + + if(event == SubmenuIndexDetectReader) { scene_manager_next_scene(instance->scene_manager, NfcSceneNotImplemented); - return true; - case SubmenuIndexWrite: + consumed = true; + } else if(event == SubmenuIndexWrite) { scene_manager_next_scene(instance->scene_manager, NfcSceneNotImplemented); - return true; - case SubmenuIndexUpdate: + consumed = true; + } else if(event == SubmenuIndexUpdate) { scene_manager_next_scene(instance->scene_manager, NfcSceneNotImplemented); - return true; - default: - return false; + consumed = true; } + + return consumed; } const NfcProtocolSupportBase nfc_protocol_support_mf_classic = { @@ -181,4 +181,7 @@ const NfcProtocolSupportBase nfc_protocol_support_mf_classic = { .on_enter = nfc_scene_saved_menu_on_enter_mf_classic, .on_event = nfc_scene_saved_menu_on_event_mf_classic, }, -}; + .scene_emulate = { + .on_enter = nfc_scene_emulate_on_enter_mf_classic, + .on_event = NULL, + }}; diff --git a/applications/main/nfc/helpers/protocol_support/mf_desfire/mf_desfire.c b/applications/main/nfc/helpers/protocol_support/mf_desfire/mf_desfire.c index fa5f87af4073..c96c40d6ac25 100644 --- a/applications/main/nfc/helpers/protocol_support/mf_desfire/mf_desfire.c +++ b/applications/main/nfc/helpers/protocol_support/mf_desfire/mf_desfire.c @@ -3,8 +3,10 @@ #include +#include "nfc/nfc_app_i.h" + #include "../nfc_protocol_support_gui_common.h" -#include "../../../nfc_app_i.h" +#include "../iso14443_4a/iso14443_4a_i.h" static void nfc_scene_info_on_enter_mf_desfire(NfcApp* instance) { const NfcDevice* device = instance->nfc_device; @@ -37,8 +39,7 @@ static NfcCommand nfc_scene_read_poller_callback_mf_desfire(NfcGenericEvent even if(mf_desfire_event->type == MfDesfirePollerEventTypeReadSuccess) { nfc_device_set_data( instance->nfc_device, NfcProtocolMfDesfire, nfc_poller_get_data(instance->poller)); - view_dispatcher_send_custom_event( - instance->view_dispatcher, NfcCustomEventReadHandlerSuccess); + view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventPollerSuccess); return NfcCommandStop; } @@ -49,10 +50,6 @@ static void nfc_scene_read_on_enter_mf_desfire(NfcApp* instance) { nfc_poller_start(instance->poller, nfc_scene_read_poller_callback_mf_desfire, instance); } -static void nfc_scene_read_menu_on_enter_mf_desfire(NfcApp* instance) { - UNUSED(instance); -} - static void nfc_scene_read_success_on_enter_mf_desfire(NfcApp* instance) { const NfcDevice* device = instance->nfc_device; const MfDesfireData* data = nfc_device_get_data(device, NfcProtocolMfDesfire); @@ -68,8 +65,14 @@ static void nfc_scene_read_success_on_enter_mf_desfire(NfcApp* instance) { furi_string_free(temp_str); } -static void nfc_scene_saved_menu_on_enter_mf_desfire(NfcApp* instance) { - UNUSED(instance); +static void nfc_scene_emulate_on_enter_mf_desfire(NfcApp* instance) { + const MfDesfireData* data = nfc_device_get_data(instance->nfc_device, NfcProtocolMfDesfire); + const Iso14443_4aData* iso14443_4a_data = data->iso14443_4a_data; + + instance->listener = + nfc_listener_alloc(instance->nfc, NfcProtocolIso14443_4a, iso14443_4a_data); + nfc_listener_start( + instance->listener, nfc_scene_emulate_listener_callback_iso14443_4a, instance); } static bool nfc_scene_info_on_event_mf_desfire(NfcApp* instance, uint32_t event) { @@ -81,24 +84,6 @@ static bool nfc_scene_info_on_event_mf_desfire(NfcApp* instance, uint32_t event) return false; } -static bool nfc_scene_read_menu_on_event_mf_desfire(NfcApp* instance, uint32_t event) { - if(event == SubmenuIndexCommonEmulate) { - scene_manager_next_scene(instance->scene_manager, NfcSceneNfcaEmulate); - return true; - } - - return false; -} - -static bool nfc_scene_saved_menu_on_event_mf_desfire(NfcApp* instance, uint32_t event) { - if(event == SubmenuIndexCommonEmulate) { - scene_manager_next_scene(instance->scene_manager, NfcSceneNfcaEmulate); - return true; - } - - return false; -} - const NfcProtocolSupportBase nfc_protocol_support_mf_desfire = { .features = NfcProtocolFeatureEmulateUid, @@ -114,8 +99,8 @@ const NfcProtocolSupportBase nfc_protocol_support_mf_desfire = { }, .scene_read_menu = { - .on_enter = nfc_scene_read_menu_on_enter_mf_desfire, - .on_event = nfc_scene_read_menu_on_event_mf_desfire, + .on_enter = nfc_protocol_support_common_on_enter_empty, + .on_event = nfc_protocol_support_common_on_event_empty, }, .scene_read_success = { @@ -124,7 +109,12 @@ const NfcProtocolSupportBase nfc_protocol_support_mf_desfire = { }, .scene_saved_menu = { - .on_enter = nfc_scene_saved_menu_on_enter_mf_desfire, - .on_event = nfc_scene_saved_menu_on_event_mf_desfire, + .on_enter = nfc_protocol_support_common_on_enter_empty, + .on_event = nfc_protocol_support_common_on_event_empty, + }, + .scene_emulate = + { + .on_enter = nfc_scene_emulate_on_enter_mf_desfire, + .on_event = NULL, }, }; diff --git a/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c b/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c index 15b56118d4d3..42058451cfc8 100644 --- a/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c +++ b/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c @@ -3,8 +3,9 @@ #include +#include "nfc/nfc_app_i.h" + #include "../nfc_protocol_support_gui_common.h" -#include "../../../nfc_app_i.h" enum { SubmenuIndexUnlock = SubmenuIndexCommonMax, @@ -44,8 +45,7 @@ static NfcCommand if(mf_ultralight_event->type == MfUltralightPollerEventTypeReadSuccess) { nfc_device_set_data( instance->nfc_device, NfcProtocolMfUltralight, nfc_poller_get_data(instance->poller)); - view_dispatcher_send_custom_event( - instance->view_dispatcher, NfcCustomEventReadHandlerSuccess); + view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventPollerSuccess); return NfcCommandStop; } else if(mf_ultralight_event->type == MfUltralightPollerEventTypeAuthRequest) { nfc_device_set_data( @@ -138,6 +138,13 @@ static void nfc_scene_saved_menu_on_enter_mf_ultralight(NfcApp* instance) { } } +static void nfc_scene_emulate_on_enter_mf_ultralight(NfcApp* instance) { + const MfUltralightData* data = + nfc_device_get_data(instance->nfc_device, NfcProtocolMfUltralight); + instance->listener = nfc_listener_alloc(instance->nfc, NfcProtocolMfUltralight, data); + nfc_listener_start(instance->listener, NULL, NULL); +} + static bool nfc_scene_info_on_event_mf_ultralight(NfcApp* instance, uint32_t event) { if(event == GuiButtonTypeRight) { scene_manager_next_scene(instance->scene_manager, NfcSceneNotImplemented); @@ -148,32 +155,26 @@ static bool nfc_scene_info_on_event_mf_ultralight(NfcApp* instance, uint32_t eve } static bool nfc_scene_read_menu_on_event_mf_ultralight(NfcApp* instance, uint32_t event) { - switch(event) { - case SubmenuIndexCommonEmulate: - scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightEmulate); - return true; - case SubmenuIndexUnlock: + if(event == SubmenuIndexUnlock) { scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightUnlockMenu); return true; - default: - return false; } + + return false; } static bool nfc_scene_saved_menu_on_event_mf_ultralight(NfcApp* instance, uint32_t event) { - switch(event) { - case SubmenuIndexCommonEmulate: - scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightEmulate); - return true; - case SubmenuIndexUnlockByReader: + bool consumed = false; + + if(event == SubmenuIndexUnlockByReader) { scene_manager_next_scene(instance->scene_manager, NfcSceneNotImplemented); - return true; - case SubmenuIndexUnlockByPassword: + consumed = true; + } else if(event == SubmenuIndexUnlockByPassword) { scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightUnlockMenu); - return true; - default: - return false; + consumed = true; } + + return consumed; } const NfcProtocolSupportBase nfc_protocol_support_mf_ultralight = { @@ -204,4 +205,9 @@ const NfcProtocolSupportBase nfc_protocol_support_mf_ultralight = { .on_enter = nfc_scene_saved_menu_on_enter_mf_ultralight, .on_event = nfc_scene_saved_menu_on_event_mf_ultralight, }, + .scene_emulate = + { + .on_enter = nfc_scene_emulate_on_enter_mf_ultralight, + .on_event = NULL, + }, }; diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c index db4591c905f2..6d272bfa4221 100644 --- a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c @@ -1,10 +1,10 @@ #include "nfc_protocol_support.h" +#include "nfc/nfc_app_i.h" + #include "nfc_protocol_support_defs.h" #include "nfc_protocol_support_gui_common.h" -#include "../../nfc_app_i.h" - typedef void (*NfcProtocolSupportCommonOnEnter)(NfcApp* instance); typedef bool (*NfcProtocolSupportCommonOnEvent)(NfcApp* instance, SceneManagerEvent event); typedef void (*NfcProtocolSupportCommonOnExit)(NfcApp* instance); @@ -59,9 +59,9 @@ static void nfc_protocol_support_scene_info_on_enter(NfcApp* instance) { static bool nfc_protocol_support_scene_info_on_event(NfcApp* instance, SceneManagerEvent event) { bool consumed = false; - const NfcProtocol protocol = nfc_device_get_protocol(instance->nfc_device); if(event.type == SceneManagerEventTypeCustom) { + const NfcProtocol protocol = nfc_device_get_protocol(instance->nfc_device); consumed = nfc_protocol_support[protocol]->scene_info.on_event(instance, event.event); } @@ -94,12 +94,12 @@ static bool nfc_protocol_support_scene_read_on_event(NfcApp* instance, SceneMana bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { - if(event.event == NfcCustomEventReadHandlerSuccess) { + if(event.event == NfcCustomEventPollerSuccess) { notification_message(instance->notifications, &sequence_success); scene_manager_next_scene(instance->scene_manager, NfcSceneReadSuccess); dolphin_deed(DolphinDeedNfcReadSuccess); consumed = true; - } else if(event.event == NfcCustomEventReadHandlerFailure) { + } else if(event.event == NfcCustomEventPollerFailure) { if(scene_manager_has_previous_scene(instance->scene_manager, NfcSceneDetect)) { scene_manager_search_and_switch_to_previous_scene( instance->scene_manager, NfcSceneDetect); @@ -172,30 +172,32 @@ static void nfc_protocol_support_scene_read_menu_on_enter(NfcApp* instance) { static bool nfc_protocol_support_scene_read_menu_on_event(NfcApp* instance, SceneManagerEvent event) { + bool consumed = false; + if(event.type == SceneManagerEventTypeCustom) { scene_manager_set_scene_state(instance->scene_manager, NfcSceneReadMenu, event.event); - const NfcProtocol protocol = nfc_device_get_protocol(instance->nfc_device); - - switch(event.event) { - case SubmenuIndexCommonSave: + if(event.event == SubmenuIndexCommonSave) { scene_manager_next_scene(instance->scene_manager, NfcSceneSaveName); - return true; - case SubmenuIndexCommonInfo: + consumed = true; + } else if(event.event == SubmenuIndexCommonInfo) { scene_manager_next_scene(instance->scene_manager, NfcSceneInfo); - return true; - case SubmenuIndexCommonEmulate: + consumed = true; + } else if(event.event == SubmenuIndexCommonEmulate) { dolphin_deed(DolphinDeedNfcEmulate); - // FALLTHRU - default: - return nfc_protocol_support[protocol]->scene_read_menu.on_event(instance, event.event); + scene_manager_next_scene(instance->scene_manager, NfcSceneEmulate); + consumed = true; + } else { + const NfcProtocol protocol = nfc_device_get_protocol(instance->nfc_device); + consumed = + nfc_protocol_support[protocol]->scene_read_menu.on_event(instance, event.event); } } else if(event.type == SceneManagerEventTypeBack) { scene_manager_set_scene_state(instance->scene_manager, NfcSceneSavedMenu, 0); } - return false; + return consumed; } static void nfc_protocol_support_scene_read_menu_on_exit(NfcApp* instance) { @@ -220,23 +222,24 @@ static void nfc_protocol_support_scene_read_success_on_enter(NfcApp* instance) { static bool nfc_protocol_support_scene_read_success_on_event(NfcApp* instance, SceneManagerEvent event) { + bool consumed = false; + if(event.type == SceneManagerEventTypeCustom) { - switch(event.event) { - case GuiButtonTypeLeft: + if(event.event == GuiButtonTypeLeft) { scene_manager_next_scene(instance->scene_manager, NfcSceneRetryConfirm); - return true; - case GuiButtonTypeRight: + consumed = true; + + } else if(event.event == GuiButtonTypeRight) { scene_manager_next_scene(instance->scene_manager, NfcSceneReadMenu); - return true; - default: - return false; + consumed = true; } + } else if(event.type == SceneManagerEventTypeBack) { scene_manager_next_scene(instance->scene_manager, NfcSceneExitConfirm); - return true; + consumed = true; } - return false; + return consumed; } static void nfc_protocol_support_scene_read_success_on_exit(NfcApp* instance) { @@ -311,46 +314,150 @@ static void nfc_protocol_support_scene_saved_menu_on_enter(NfcApp* instance) { static bool nfc_protocol_support_scene_saved_menu_on_event(NfcApp* instance, SceneManagerEvent event) { + bool consumed = false; + if(event.type == SceneManagerEventTypeCustom) { scene_manager_set_scene_state(instance->scene_manager, NfcSceneSavedMenu, event.event); - const NfcProtocol protocol = nfc_device_get_protocol(instance->nfc_device); - // TODO: Implement restore from shadow file - switch(event.event) { - case SubmenuIndexCommonInfo: + if(event.event == SubmenuIndexCommonInfo) { scene_manager_next_scene(instance->scene_manager, NfcSceneInfo); - return true; - case SubmenuIndexCommonRename: + consumed = true; + } else if(event.event == SubmenuIndexCommonRename) { scene_manager_next_scene(instance->scene_manager, NfcSceneSaveName); - return true; - case SubmenuIndexCommonDelete: + consumed = true; + } else if(event.event == SubmenuIndexCommonDelete) { scene_manager_next_scene(instance->scene_manager, NfcSceneDelete); - return true; - case SubmenuIndexCommonEmulate: - if(scene_manager_has_previous_scene(instance->scene_manager, NfcSceneSetType)) { - dolphin_deed(DolphinDeedNfcAddEmulate); - } else { - dolphin_deed(DolphinDeedNfcEmulate); - } - // FALLTHRU - default: - return nfc_protocol_support[protocol]->scene_saved_menu.on_event( - instance, event.event); + consumed = true; + } else if(event.event == SubmenuIndexCommonEmulate) { + const bool is_added = + scene_manager_has_previous_scene(instance->scene_manager, NfcSceneSetType); + dolphin_deed(is_added ? DolphinDeedNfcAddEmulate : DolphinDeedNfcEmulate); + scene_manager_next_scene(instance->scene_manager, NfcSceneEmulate); + consumed = true; + } else { + const NfcProtocol protocol = nfc_device_get_protocol(instance->nfc_device); + consumed = + nfc_protocol_support[protocol]->scene_saved_menu.on_event(instance, event.event); } } else if(event.type == SceneManagerEventTypeBack) { scene_manager_set_scene_state(instance->scene_manager, NfcSceneSavedMenu, 0); } - return false; + return consumed; } static void nfc_protocol_support_scene_saved_menu_on_exit(NfcApp* instance) { submenu_reset(instance->submenu); } +// SceneEmulate +enum { + NfcSceneEmulateStateWidget, + NfcSceneEmulateStateTextBox, +}; + +static void nfc_protocol_support_scene_emulate_on_enter(NfcApp* instance) { + Widget* widget = instance->widget; + TextBox* text_box = instance->text_box; + + FuriString* temp_str = furi_string_alloc(); + const NfcProtocol protocol = nfc_device_get_protocol(instance->nfc_device); + + widget_add_icon_element(widget, 0, 3, &I_NFC_dolphin_emulation_47x61); + + if(nfc_protocol_support_has_feature(protocol, NfcProtocolFeatureEmulateUid)) { + widget_add_string_element( + widget, 90, 13, AlignCenter, AlignTop, FontPrimary, "Emulating UID"); + + size_t uid_len; + const uint8_t* uid = nfc_device_get_uid(instance->nfc_device, &uid_len); + + for(size_t i = 0; i < uid_len; ++i) { + furi_string_cat_printf(temp_str, "%02X ", uid[i]); + } + + furi_string_trim(temp_str); + + } else { + widget_add_string_element(widget, 90, 13, AlignCenter, AlignTop, FontPrimary, "Emulating"); + furi_string_set( + temp_str, nfc_device_get_name(instance->nfc_device, NfcDeviceNameTypeFull)); + } + + widget_add_text_box_element( + widget, 56, 28, 68, 25, AlignCenter, AlignTop, furi_string_get_cstr(temp_str), false); + + furi_string_free(temp_str); + + text_box_set_font(text_box, TextBoxFontHex); + text_box_set_focus(text_box, TextBoxFocusEnd); + furi_string_reset(instance->text_box_store); + + // instance->listener is allocated in the respective on_enter() handler + nfc_protocol_support[protocol]->scene_emulate.on_enter(instance); + + scene_manager_set_scene_state( + instance->scene_manager, NfcSceneEmulate, NfcSceneEmulateStateWidget); + + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewWidget); + nfc_blink_emulate_start(instance); +} + +static bool + nfc_protocol_support_scene_emulate_on_event(NfcApp* instance, SceneManagerEvent event) { + bool consumed = false; + + const uint32_t state = scene_manager_get_scene_state(instance->scene_manager, NfcSceneEmulate); + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventListenerUpdate) { + // Add data button to widget if data is received for the first time + if(furi_string_size(instance->text_box_store)) { + widget_add_button_element( + instance->widget, + GuiButtonTypeCenter, + "Log", + nfc_protocol_support_common_widget_callback, + instance); + } + // Update TextBox data + text_box_set_text(instance->text_box, furi_string_get_cstr(instance->text_box_store)); + consumed = true; + } else if(event.event == GuiButtonTypeCenter) { + if(state == NfcSceneEmulateStateWidget) { + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewTextBox); + scene_manager_set_scene_state( + instance->scene_manager, NfcSceneEmulate, NfcSceneEmulateStateTextBox); + consumed = true; + } + } + } else if(event.type == SceneManagerEventTypeBack) { + if(state == NfcSceneEmulateStateTextBox) { + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewWidget); + scene_manager_set_scene_state( + instance->scene_manager, NfcSceneEmulate, NfcSceneEmulateStateWidget); + consumed = true; + } + } + + return consumed; +} + +static void nfc_protocol_support_scene_emulate_on_exit(NfcApp* instance) { + nfc_listener_stop(instance->listener); + nfc_listener_free(instance->listener); + + // Clear view + widget_reset(instance->widget); + text_box_reset(instance->text_box); + furi_string_reset(instance->text_box_store); + + nfc_blink_stop(instance); +} + static const NfcProtocolSupportCommonSceneBase nfc_protocol_support_scenes[NfcProtocolSupportSceneCount] = { [NfcProtocolSupportSceneInfo] = @@ -383,4 +490,10 @@ static const NfcProtocolSupportCommonSceneBase .on_event = nfc_protocol_support_scene_saved_menu_on_event, .on_exit = nfc_protocol_support_scene_saved_menu_on_exit, }, + [NfcProtocolSupportSceneEmulate] = + { + .on_enter = nfc_protocol_support_scene_emulate_on_enter, + .on_event = nfc_protocol_support_scene_emulate_on_event, + .on_exit = nfc_protocol_support_scene_emulate_on_exit, + }, }; diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_base.h b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_base.h index 1b9c78a9d1d6..37f56f799c4d 100644 --- a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_base.h +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_base.h @@ -24,4 +24,5 @@ typedef struct { NfcProtocolSupportSceneBase scene_read_menu; NfcProtocolSupportSceneBase scene_read_success; NfcProtocolSupportSceneBase scene_saved_menu; + NfcProtocolSupportSceneBase scene_emulate; } NfcProtocolSupportBase; diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_common.h b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_common.h index cdee870e9ab6..291e2b01fb6d 100644 --- a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_common.h +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_common.h @@ -22,6 +22,7 @@ typedef enum { NfcProtocolSupportSceneReadMenu, NfcProtocolSupportSceneReadSuccess, NfcProtocolSupportSceneSavedMenu, + NfcProtocolSupportSceneEmulate, NfcProtocolSupportSceneCount, } NfcProtocolSupportScene; diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_gui_common.c b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_gui_common.c index 22f8895e71d5..3330f48c52bc 100644 --- a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_gui_common.c +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_gui_common.c @@ -1,11 +1,11 @@ #include "nfc_protocol_support_gui_common.h" -#include "../../nfc_app_i.h" +#include "nfc/nfc_app_i.h" void nfc_protocol_support_common_submenu_callback(void* context, uint32_t index) { furi_assert(context); - NfcApp* nfc = context; - view_dispatcher_send_custom_event(nfc->view_dispatcher, index); + NfcApp* instance = context; + view_dispatcher_send_custom_event(instance->view_dispatcher, index); } void nfc_protocol_support_common_widget_callback( @@ -13,8 +13,18 @@ void nfc_protocol_support_common_widget_callback( InputType type, void* context) { furi_assert(context); - NfcApp* nfc = context; + NfcApp* instance = context; if(type == InputTypeShort) { - view_dispatcher_send_custom_event(nfc->view_dispatcher, result); + view_dispatcher_send_custom_event(instance->view_dispatcher, result); } } + +void nfc_protocol_support_common_on_enter_empty(NfcApp* instance) { + UNUSED(instance); +} + +bool nfc_protocol_support_common_on_event_empty(NfcApp* instance, uint32_t event) { + UNUSED(instance); + UNUSED(event); + return false; +} diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_gui_common.h b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_gui_common.h index 80012ad4fd83..0f1532bd30d5 100644 --- a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_gui_common.h +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_gui_common.h @@ -2,6 +2,8 @@ #include +#include "nfc/nfc_app.h" + enum { SubmenuIndexCommonSave, SubmenuIndexCommonEmulate, @@ -18,3 +20,7 @@ void nfc_protocol_support_common_widget_callback( GuiButtonType result, InputType type, void* context); + +void nfc_protocol_support_common_on_enter_empty(NfcApp* instance); + +bool nfc_protocol_support_common_on_event_empty(NfcApp* instance, uint32_t event); diff --git a/applications/main/nfc/nfc_app.c b/applications/main/nfc/nfc_app.c index 2037fc6eac84..04c7be9b6ecd 100644 --- a/applications/main/nfc/nfc_app.c +++ b/applications/main/nfc/nfc_app.c @@ -473,7 +473,7 @@ int32_t nfc_app(void* p) { view_dispatcher_attach_to_gui( nfc->view_dispatcher, nfc->gui, ViewDispatcherTypeFullscreen); if(nfc_device_load(nfc->nfc_device, args)) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate); + scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulate); } else { // Exit app diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index cb9d05f8f2ba..d6a6cbb827f0 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -13,13 +13,11 @@ ADD_SCENE(nfc, select_protocol, SelectProtocol) ADD_SCENE(nfc, extra_actions, ExtraActions) ADD_SCENE(nfc, read_success, ReadSuccess) ADD_SCENE(nfc, read_menu, ReadMenu) +ADD_SCENE(nfc, emulate, Emulate) ADD_SCENE(nfc, debug, Debug) ADD_SCENE(nfc, retry_confirm, RetryConfirm) ADD_SCENE(nfc, exit_confirm, ExitConfirm) -ADD_SCENE(nfc, nfca_emulate, NfcaEmulate) - -ADD_SCENE(nfc, mf_ultralight_emulate, MfUltralightEmulate) ADD_SCENE(nfc, mf_ultralight_unlock_menu, MfUltralightUnlockMenu) ADD_SCENE(nfc, mf_ultralight_unlock_warn, MfUltralightUnlockWarn) ADD_SCENE(nfc, mf_ultralight_key_input, MfUltralightKeyInput) @@ -30,7 +28,6 @@ ADD_SCENE(nfc, mf_desfire_app, MfDesfireApp) ADD_SCENE(nfc, mf_classic_read_supported_card, MfClassicReadSupportedCard) ADD_SCENE(nfc, mf_classic_dict_attack, MfClassicDictAttack) -ADD_SCENE(nfc, mf_classic_emulate, MfClassicEmulate) ADD_SCENE(nfc, set_type, SetType) ADD_SCENE(nfc, set_sak, SetSak) diff --git a/applications/main/nfc/scenes/nfc_scene_emulate.c b/applications/main/nfc/scenes/nfc_scene_emulate.c new file mode 100644 index 000000000000..6f217f315487 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_emulate.c @@ -0,0 +1,13 @@ +#include "../helpers/protocol_support/nfc_protocol_support.h" + +void nfc_scene_emulate_on_enter(void* context) { + nfc_protocol_support_on_enter(NfcProtocolSupportSceneEmulate, context); +} + +bool nfc_scene_emulate_on_event(void* context, SceneManagerEvent event) { + return nfc_protocol_support_on_event(NfcProtocolSupportSceneEmulate, context, event); +} + +void nfc_scene_emulate_on_exit(void* context) { + nfc_protocol_support_on_exit(NfcProtocolSupportSceneEmulate, context); +} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_emulate.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_emulate.c deleted file mode 100644 index 9aee0ee72b47..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_emulate.c +++ /dev/null @@ -1,46 +0,0 @@ -#include "../nfc_app_i.h" - -void nfc_scene_mf_classic_emulate_on_enter(void* context) { - NfcApp* nfc = context; - - // Setup view - const MfClassicData* data = nfc_device_get_data(nfc->nfc_device, NfcProtocolMfClassic); - - Popup* popup = nfc->popup; - popup_set_header(popup, "Emulating", 67, 13, AlignLeft, AlignTop); - if(!furi_string_empty(nfc->file_name)) { - nfc_text_store_set(nfc, "%s", furi_string_get_cstr(nfc->file_name)); - } else { - nfc_text_store_set(nfc, "Mf Classic"); - } - popup_set_icon(popup, 0, 3, &I_NFC_dolphin_emulation_47x61); - popup_set_text(popup, nfc->text_store, 90, 28, AlignCenter, AlignTop); - - // Setup and start worker - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); - nfc->listener = nfc_listener_alloc(nfc->nfc, NfcProtocolMfClassic, data); - nfc_listener_start(nfc->listener, NULL, NULL); - - nfc_blink_emulate_start(nfc); -} - -bool nfc_scene_mf_classic_emulate_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - UNUSED(nfc); - UNUSED(event); - bool consumed = false; - - return consumed; -} - -void nfc_scene_mf_classic_emulate_on_exit(void* context) { - NfcApp* nfc = context; - - nfc_listener_stop(nfc->listener); - nfc_listener_free(nfc->listener); - - // Clear view - popup_reset(nfc->popup); - - nfc_blink_stop(nfc); -} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_emulate.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_emulate.c deleted file mode 100644 index 4e8b3ac59448..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_emulate.c +++ /dev/null @@ -1,66 +0,0 @@ -#include "../nfc_app_i.h" - -void nfc_scene_mf_ultralight_emulate_on_enter(void* context) { - NfcApp* nfc = context; - - // Setup view - const MfUltralightData* data = nfc_device_get_data(nfc->nfc_device, NfcProtocolMfUltralight); - const MfUltralightType type = data->type; - - bool is_ultralight = (type == MfUltralightTypeUL11) || (type == MfUltralightTypeUL21) || - (type == MfUltralightTypeUnknown); - Popup* popup = nfc->popup; - popup_set_header(popup, "Emulating", 67, 13, AlignLeft, AlignTop); - if(!furi_string_empty(nfc->file_name)) { - nfc_text_store_set(nfc, "%s", furi_string_get_cstr(nfc->file_name)); - } else if(is_ultralight) { - nfc_text_store_set(nfc, "MIFARE\nUltralight"); - } else { - nfc_text_store_set(nfc, "MIFARE\nNTAG"); - } - popup_set_icon(popup, 0, 3, &I_NFC_dolphin_emulation_47x61); - popup_set_text(popup, nfc->text_store, 90, 28, AlignCenter, AlignTop); - - // Setup and start worker - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); - nfc->listener = nfc_listener_alloc(nfc->nfc, NfcProtocolMfUltralight, data); - nfc_listener_start(nfc->listener, NULL, NULL); - - nfc_blink_emulate_start(nfc); -} - -bool nfc_scene_mf_ultralight_emulate_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - UNUSED(nfc); - bool consumed = false; - - if(event.type == SceneManagerEventTypeBack) { - // MfUltralightData* mfu_data_after_emulation = nfc_listener_get_data(nfc->listener, NfcProtocolMfUltralight); - // Check if data changed and save in shadow file - // FIXME: A comparison method? - // if(memcmp( - // mfu_data_after_emulation, - // &nfc->nfc_dev_data.mf_ul_data, - // sizeof(MfUltralightData)) != 0) { - // // Save shadow file - // if(!furi_string_empty(nfc->file_name)) { - // nfc_save_shadow_file(nfc); - // } - // } - // mf_ultralight_free(mfu_data_after_emulation); - consumed = false; - } - return consumed; -} - -void nfc_scene_mf_ultralight_emulate_on_exit(void* context) { - NfcApp* nfc = context; - - nfc_listener_stop(nfc->listener); - nfc_listener_free(nfc->listener); - - // Clear view - popup_reset(nfc->popup); - - nfc_blink_stop(nfc); -} diff --git a/applications/main/nfc/scenes/nfc_scene_nfca_emulate.c b/applications/main/nfc/scenes/nfc_scene_nfca_emulate.c deleted file mode 100644 index c9177730dcb1..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_nfca_emulate.c +++ /dev/null @@ -1,142 +0,0 @@ -#include "../nfc_app_i.h" - -#define NFC_SCENE_NFCA_EMULATE_LOG_SIZE_MAX (200) - -enum { - NfcSceneNfcaEmulateStateWidget, - NfcSceneNfcaEmulateStateTextBox, -}; - -NfcCommand nfc_scene_nfca_emulate_worker_callback(NfcGenericEvent event, void* context) { - furi_assert(context); - furi_assert(event.protocol == NfcProtocolIso14443_3a); - furi_assert(event.data); - - NfcApp* nfc = context; - Iso14443_3aListenerEvent* iso14443_3a_event = event.data; - - if(iso14443_3a_event->type == Iso14443_3aListenerEventTypeReceivedStandardFrame) { - furi_string_cat_printf(nfc->text_box_store, "R:"); - for(size_t i = 0; i < bit_buffer_get_size_bytes(iso14443_3a_event->data->buffer); i++) { - furi_string_cat_printf( - nfc->text_box_store, - " %02X", - bit_buffer_get_byte(iso14443_3a_event->data->buffer, i)); - } - furi_string_cat_printf(nfc->text_box_store, "\n"); - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerUpdate); - } - - return NfcCommandContinue; -} - -void nfc_scene_nfca_emulate_widget_callback(GuiButtonType result, InputType type, void* context) { - furi_assert(context); - NfcApp* nfc = context; - if(type == InputTypeShort) { - view_dispatcher_send_custom_event(nfc->view_dispatcher, result); - } -} - -void nfc_nfca_emulate_textbox_callback(void* context) { - furi_assert(context); - NfcApp* nfc = context; - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); -} - -// Add widget with device name or inform that data received -static void nfc_scene_nfca_emulate_widget_config(NfcApp* nfc, bool data_received) { - const Iso14443_3aData* data = nfc_device_get_data(nfc->nfc_device, NfcProtocolIso14443_3a); - Widget* widget = nfc->widget; - widget_reset(widget); - FuriString* info_str; - info_str = furi_string_alloc(); - - widget_add_icon_element(widget, 0, 3, &I_NFC_dolphin_emulation_47x61); - widget_add_string_element(widget, 57, 13, AlignLeft, AlignTop, FontPrimary, "Emulating UID"); - for(uint8_t i = 0; i < data->uid_len; i++) { - furi_string_cat_printf(info_str, "%02X ", data->uid[i]); - } - furi_string_trim(info_str); - widget_add_text_box_element( - widget, 57, 28, 67, 25, AlignCenter, AlignTop, furi_string_get_cstr(info_str), true); - furi_string_free(info_str); - if(data_received) { - widget_add_button_element( - widget, GuiButtonTypeCenter, "Log", nfc_scene_nfca_emulate_widget_callback, nfc); - } -} - -void nfc_scene_nfca_emulate_on_enter(void* context) { - NfcApp* nfc = context; - - // Setup Widget - nfc_scene_nfca_emulate_widget_config(nfc, false); - // Setup TextBox - TextBox* text_box = nfc->text_box; - text_box_set_font(text_box, TextBoxFontHex); - text_box_set_focus(text_box, TextBoxFocusEnd); - furi_string_reset(nfc->text_box_store); - - const NfcDeviceData* data = nfc_device_get_data(nfc->nfc_device, NfcProtocolIso14443_3a); - nfc->listener = nfc_listener_alloc(nfc->nfc, NfcProtocolIso14443_3a, data); - nfc_listener_start(nfc->listener, nfc_scene_nfca_emulate_worker_callback, nfc); - - // Set Widget state and view - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneNfcaEmulate, NfcSceneNfcaEmulateStateWidget); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); - - nfc_blink_emulate_start(nfc); -} - -bool nfc_scene_nfca_emulate_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; - uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneNfcaEmulate); - bool consumed = false; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == NfcCustomEventWorkerUpdate) { - // Add data button to widget if data is received for the first time - if(furi_string_size(nfc->text_box_store)) { - nfc_scene_nfca_emulate_widget_config(nfc, true); - } - // Update TextBox data - text_box_set_text(nfc->text_box, furi_string_get_cstr(nfc->text_box_store)); - consumed = true; - } else if(event.event == GuiButtonTypeCenter && state == NfcSceneNfcaEmulateStateWidget) { - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneNfcaEmulate, NfcSceneNfcaEmulateStateTextBox); - consumed = true; - } else if(event.event == NfcCustomEventViewExit && state == NfcSceneNfcaEmulateStateTextBox) { - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneNfcaEmulate, NfcSceneNfcaEmulateStateWidget); - consumed = true; - } - } else if(event.type == SceneManagerEventTypeBack) { - if(state == NfcSceneNfcaEmulateStateTextBox) { - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneNfcaEmulate, NfcSceneNfcaEmulateStateWidget); - consumed = true; - } - } - - return consumed; -} - -void nfc_scene_nfca_emulate_on_exit(void* context) { - NfcApp* nfc = context; - - nfc_listener_stop(nfc->listener); - nfc_listener_free(nfc->listener); - - // Clear view - widget_reset(nfc->widget); - text_box_reset(nfc->text_box); - furi_string_reset(nfc->text_box_store); - - nfc_blink_stop(nfc); -} diff --git a/applications/main/nfc/scenes/nfc_scene_set_type.c b/applications/main/nfc/scenes/nfc_scene_set_type.c index f50299578568..6b8f2c3f92c5 100644 --- a/applications/main/nfc/scenes/nfc_scene_set_type.c +++ b/applications/main/nfc/scenes/nfc_scene_set_type.c @@ -16,8 +16,6 @@ void nfc_scene_set_type_on_enter(void* context) { NfcApp* instance = context; Submenu* submenu = instance->submenu; - // Clear device name - furi_string_reset(instance->file_name); submenu_add_item( submenu, "NFC-A 7-bytes UID", diff --git a/applications/main/nfc/scenes/nfc_scene_start.c b/applications/main/nfc/scenes/nfc_scene_start.c index dcfd34163903..1a487df630f0 100644 --- a/applications/main/nfc/scenes/nfc_scene_start.c +++ b/applications/main/nfc/scenes/nfc_scene_start.c @@ -20,6 +20,10 @@ void nfc_scene_start_on_enter(void* context) { NfcApp* nfc = context; Submenu* submenu = nfc->submenu; + // Clear file name and device contents + furi_string_reset(nfc->file_name); + nfc_device_clear(nfc->nfc_device); + submenu_add_item(submenu, "Read", SubmenuIndexRead, nfc_scene_start_submenu_callback, nfc); submenu_add_item( submenu, "Detect Reader", SubmenuIndexDetectReader, nfc_scene_start_submenu_callback, nfc); diff --git a/documentation/file_formats/NfcFileFormats.md b/documentation/file_formats/NfcFileFormats.md index ff3f215e267d..f3b77c55a99b 100644 --- a/documentation/file_formats/NfcFileFormats.md +++ b/documentation/file_formats/NfcFileFormats.md @@ -63,7 +63,7 @@ None, there are no versions yet. ### Description This file format is used to store the UID, SAK and ATQA of a ISO14443-4A device. It also stores the Answer to Select (ATS) data of the card. -ATS must be 6 bytes long. +ATS must be no less than 5 bytes long. Version differences: None, there are no versions yet. diff --git a/lib/nfc/helpers/simple_array.c b/lib/nfc/helpers/simple_array.c index f93682ff1be6..78f7bdf12d38 100644 --- a/lib/nfc/helpers/simple_array.c +++ b/lib/nfc/helpers/simple_array.c @@ -95,3 +95,10 @@ SimpleArrayElement* simple_array_get(SimpleArray* instance, uint32_t index) { const SimpleArrayElement* simple_array_cget(const SimpleArray* instance, uint32_t index) { return simple_array_get((SimpleArrayElement*)instance, index); } + +const SimpleArrayConfig simple_array_config_uint8_t = { + .init = NULL, + .copy = NULL, + .reset = NULL, + .type_size = sizeof(uint8_t), +}; diff --git a/lib/nfc/helpers/simple_array.h b/lib/nfc/helpers/simple_array.h index c97baca326a4..72de4b886a4a 100644 --- a/lib/nfc/helpers/simple_array.h +++ b/lib/nfc/helpers/simple_array.h @@ -33,3 +33,5 @@ uint32_t simple_array_get_count(const SimpleArray* instance); SimpleArrayElement* simple_array_get(SimpleArray* instance, uint32_t index); const SimpleArrayElement* simple_array_cget(const SimpleArray* instance, uint32_t index); + +extern const SimpleArrayConfig simple_array_config_uint8_t; diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a.c b/lib/nfc/protocols/iso14443_4a/iso14443_4a.c index 96b8fa57b55c..992682931daa 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a.c +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a.c @@ -25,7 +25,9 @@ const NfcDeviceBase nfc_device_iso14443_4a = { Iso14443_4aData* iso14443_4a_alloc() { Iso14443_4aData* data = malloc(sizeof(Iso14443_4aData)); + data->iso14443_3a_data = iso14443_3a_alloc(); + data->ats_data = simple_array_alloc(&simple_array_config_uint8_t); return data; } @@ -33,7 +35,9 @@ Iso14443_4aData* iso14443_4a_alloc() { void iso14443_4a_free(Iso14443_4aData* data) { furi_assert(data); + simple_array_free(data->ats_data); iso14443_3a_free(data->iso14443_3a_data); + free(data); } @@ -41,7 +45,7 @@ void iso14443_4a_reset(Iso14443_4aData* data) { furi_assert(data); iso14443_3a_reset(data->iso14443_3a_data); - memset(&data->ats_data, 0, sizeof(Iso14443_4aAtsData)); + simple_array_reset(data->ats_data); } void iso14443_4a_copy(Iso14443_4aData* data, const Iso14443_4aData* other) { @@ -49,7 +53,7 @@ void iso14443_4a_copy(Iso14443_4aData* data, const Iso14443_4aData* other) { furi_assert(other); iso14443_3a_copy(data->iso14443_3a_data, other->iso14443_3a_data); - data->ats_data = other->ats_data; + simple_array_copy(data->ats_data, other->ats_data); } bool iso14443_4a_verify(Iso14443_4aData* data, const FuriString* device_type) { @@ -68,11 +72,17 @@ bool iso14443_4a_load(Iso14443_4aData* data, FlipperFormat* ff, uint32_t version do { if(!iso14443_3a_load(data->iso14443_3a_data, ff, version)) break; if(flipper_format_key_exist(ff, ISO14443_4A_ATS_KEY)) { + uint32_t ats_size = 0; + if(!flipper_format_get_value_count(ff, ISO14443_4A_ATS_KEY, &ats_size)) break; + + if(ats_size < sizeof(Iso14443_4aAtsData)) break; + simple_array_init(data->ats_data, ats_size); + if(!flipper_format_read_hex( - ff, ISO14443_4A_ATS_KEY, (uint8_t*)&data->ats_data, sizeof(Iso14443_4aAtsData))) + ff, ISO14443_4A_ATS_KEY, simple_array_get(data->ats_data, 0), ats_size)) break; } else { - iso14443_4a_ats_fill_default(&data->ats_data); + iso14443_4a_ats_fill_default(data->ats_data); } parsed = true; } while(false); @@ -92,8 +102,8 @@ bool iso14443_4a_save(const Iso14443_4aData* data, FlipperFormat* ff) { if(!flipper_format_write_hex( ff, ISO14443_4A_ATS_KEY, - (const uint8_t*)&data->ats_data, - sizeof(Iso14443_4aAtsData))) + simple_array_cget(data->ats_data, 0), + simple_array_get_count(data->ats_data))) break; saved = true; } while(false); diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a.h b/lib/nfc/protocols/iso14443_4a/iso14443_4a.h index 3b6bad6b6cef..d5f982c8b977 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a.h +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a.h @@ -2,12 +2,12 @@ #include +#include "helpers/simple_array.h" + #ifdef __cplusplus extern "C" { #endif -#define ISO14443_4A_CMD_READ_ATS (0xE0) - typedef enum { Iso14443_4aErrorNone, Iso14443_4aErrorNotPresent, @@ -15,18 +15,9 @@ typedef enum { Iso14443_4aErrorTimeout, } Iso14443_4aError; -typedef struct { - uint8_t tl; - uint8_t t0; - uint8_t ta_1; - uint8_t tb_1; - uint8_t tc_1; - uint8_t t1; -} Iso14443_4aAtsData; - typedef struct { Iso14443_3aData* iso14443_3a_data; - Iso14443_4aAtsData ats_data; + SimpleArray* ats_data; } Iso14443_4aData; extern const NfcDeviceBase nfc_device_iso14443_4a; diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_i.c b/lib/nfc/protocols/iso14443_4a/iso14443_4a_i.c index 0878e823ec3d..cc0388b4e43b 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_i.c +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_i.c @@ -3,9 +3,7 @@ // T0 bits #define ISO14443_4A_ATS_T0_TA1_FLAG (1U << 4) #define ISO14443_4A_ATS_T0_TB1_FLAG (1U << 5) -#define ISO14443_4A_ATS_T0_TC1_FLAG (1U << 5) -#define ISO14443_4A_ATS_T0_FSCI_32 (2U << 0) -#define ISO14443_4A_ATS_T0_FSCI_64 (5U << 0) +#define ISO14443_4A_ATS_T0_TC1_FLAG (1U << 6) // TA_1 bits #define ISO14443_4A_ATS_TA1_SAME_D (1U << 7) @@ -18,21 +16,51 @@ #define ISO14443_4A_ATS_TC1_NAD_FLAG (1U << 0) #define ISO14443_4A_ATS_TC1_CID_FLAG (1U << 1) -bool iso14443_4a_ats_parse(Iso14443_4aAtsData* data, const BitBuffer* buf) { - // TODO better check - const bool can_parse = bit_buffer_get_size_bytes(buf) == sizeof(Iso14443_4aAtsData); - if(can_parse) { - bit_buffer_write_bytes(buf, data, sizeof(Iso14443_4aAtsData)); - } +bool iso14443_4a_ats_parse(SimpleArray* data, const BitBuffer* buf) { + bool can_parse = false; + + do { + const size_t buf_size = bit_buffer_get_size_bytes(buf); + if(buf_size < sizeof(Iso14443_4aAtsData)) break; + + const size_t ats_size = bit_buffer_get_byte(buf, 0); + if(ats_size != buf_size) break; + + simple_array_init(data, ats_size); + bit_buffer_write_bytes(buf, simple_array_get(data, 0), ats_size); + + can_parse = true; + } while(false); + return can_parse; } -void iso14443_4a_ats_fill_default(Iso14443_4aAtsData* data) { - data->tl = sizeof(Iso14443_4aAtsData); - data->t0 = ISO14443_4A_ATS_T0_TA1_FLAG | ISO14443_4A_ATS_T0_TB1_FLAG | - ISO14443_4A_ATS_T0_TC1_FLAG | ISO14443_4A_ATS_T0_FSCI_64; - data->ta_1 = ISO14443_4A_ATS_TA1_SAME_D; - data->tb_1 = ISO14443_4A_ATS_TB1_FWI | ISO14443_4A_ATS_TB1_SFGI; - data->tc_1 = ISO14443_4A_ATS_TC1_CID_FLAG; - data->t1 = 0; +void iso14443_4a_ats_fill_default(SimpleArray* data) { + simple_array_init(data, sizeof(Iso14443_4aAtsData)); + + Iso14443_4aAtsData* ats_data = simple_array_get(data, 0); + + ats_data->tl = sizeof(Iso14443_4aAtsData); + ats_data->t0 = ISO14443_4A_ATS_T0_TA1_FLAG | ISO14443_4A_ATS_T0_TB1_FLAG | + ISO14443_4A_ATS_T0_TC1_FLAG | ISO14443_4A_FSCI_256; + ats_data->ta_1 = ISO14443_4A_ATS_TA1_SAME_D; + ats_data->tb_1 = ISO14443_4A_ATS_TB1_FWI | ISO14443_4A_ATS_TB1_SFGI; + ats_data->tc_1 = ISO14443_4A_ATS_TC1_CID_FLAG; +} + +Iso14443_4aError iso14443_4a_process_error(Iso14443_3aError error) { + switch(error) { + case Iso14443_3aErrorNone: + return Iso14443_4aErrorNone; + case Iso14443_3aErrorNotPresent: + return Iso14443_4aErrorNotPresent; + case Iso14443_3aErrorColResFailed: + case Iso14443_3aErrorCommunication: + case Iso14443_3aErrorWrongCrc: + return Iso14443_4aErrorProtocol; + case Iso14443_3aErrorTimeout: + return Iso14443_4aErrorTimeout; + default: + return Iso14443_4aErrorProtocol; + } } diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_i.h b/lib/nfc/protocols/iso14443_4a/iso14443_4a_i.h index 2bbab55ae8f7..a1e95774d53a 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_i.h +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_i.h @@ -2,6 +2,44 @@ #include "iso14443_4a.h" -bool iso14443_4a_ats_parse(Iso14443_4aAtsData* data, const BitBuffer* buf); +#define ISO14443_4A_CMD_READ_ATS (0xE0) -void iso14443_4a_ats_fill_default(Iso14443_4aAtsData* data); +#define ISO14443_4A_FSDI_16 (0x00) +#define ISO14443_4A_FSDI_24 (0x01) +#define ISO14443_4A_FSDI_32 (0x02) +#define ISO14443_4A_FSDI_40 (0x03) +#define ISO14443_4A_FSDI_48 (0x04) +#define ISO14443_4A_FSDI_64 (0x05) +#define ISO14443_4A_FSDI_96 (0x06) +#define ISO14443_4A_FSDI_128 (0x07) +#define ISO14443_4A_FSDI_256 (0x08) + +#define ISO14443_4A_FSCI_16 ISO14443_4A_FSDI_16 +#define ISO14443_4A_FSCI_24 ISO14443_4A_FSDI_24 +#define ISO14443_4A_FSCI_32 ISO14443_4A_FSDI_32 +#define ISO14443_4A_FSCI_40 ISO14443_4A_FSDI_40 +#define ISO14443_4A_FSCI_48 ISO14443_4A_FSDI_48 +#define ISO14443_4A_FSCI_64 ISO14443_4A_FSDI_64 +#define ISO14443_4A_FSCI_96 ISO14443_4A_FSDI_96 +#define ISO14443_4A_FSCI_128 ISO14443_4A_FSDI_128 +#define ISO14443_4A_FSCI_256 ISO14443_4A_FSDI_256 + +#define ISO14443_4A_BLOCK_PCB (1U << 1) +#define ISO14443_4A_BLOCK_PCB_I (0U) +#define ISO14443_4A_BLOCK_PCB_R (5U << 5) +#define ISO14443_4A_BLOCK_PCB_S (3U << 6) + +typedef struct { + uint8_t tl; + uint8_t t0; + uint8_t ta_1; + uint8_t tb_1; + uint8_t tc_1; + uint8_t t1_tk[]; +} Iso14443_4aAtsData; + +bool iso14443_4a_ats_parse(SimpleArray* data, const BitBuffer* buf); + +void iso14443_4a_ats_fill_default(SimpleArray* data); + +Iso14443_4aError iso14443_4a_process_error(Iso14443_3aError error); diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_listener.c b/lib/nfc/protocols/iso14443_4a/iso14443_4a_listener.c new file mode 100644 index 000000000000..4bb413090ea4 --- /dev/null +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_listener.c @@ -0,0 +1,102 @@ +#include "iso14443_4a_listener_i.h" + +#include +#include + +#define TAG "Iso14443_4aListener" + +#define ISO14443_4A_LISTENER_BUF_SIZE (256U) + +static Iso14443_4aListener* iso14443_4a_listener_alloc( + Iso14443_3aListener* iso14443_3a_listener, + const Iso14443_4aData* data) { + furi_assert(iso14443_3a_listener); + + Iso14443_4aListener* instance = malloc(sizeof(Iso14443_4aListener)); + instance->iso14443_3a_listener = iso14443_3a_listener; + instance->data = iso14443_4a_alloc(); + iso14443_4a_copy(instance->data, data); + + instance->tx_buffer = bit_buffer_alloc(ISO14443_4A_LISTENER_BUF_SIZE); + + instance->iso14443_4a_event.data = &instance->iso14443_4a_event_data; + instance->generic_event.protocol = NfcProtocolIso14443_4a; + instance->generic_event.instance = instance; + instance->generic_event.data = &instance->iso14443_4a_event; + + return instance; +} + +static void iso14443_4a_listener_free(Iso14443_4aListener* instance) { + furi_assert(instance); + furi_assert(instance->data); + furi_assert(instance->tx_buffer); + + bit_buffer_free(instance->tx_buffer); + iso14443_4a_free(instance->data); + free(instance); +} + +static void iso14443_4a_listener_set_callback( + Iso14443_4aListener* instance, + NfcGenericCallback callback, + void* context) { + furi_assert(instance); + + instance->callback = callback; + instance->context = context; +} + +static const Iso14443_4aData* iso14443_4a_listener_get_data(Iso14443_4aListener* instance) { + furi_assert(instance); + furi_assert(instance->data); + + return instance->data; +} + +static NfcCommand iso14443_4a_listener_run(NfcGenericEvent event, void* context) { + furi_assert(context); + furi_assert(event.protocol == NfcProtocolIso14443_3a); + furi_assert(event.data); + + Iso14443_4aListener* instance = context; + Iso14443_3aListenerEvent* iso14443_3a_event = event.data; + BitBuffer* rx_buffer = iso14443_3a_event->data->buffer; + NfcCommand command = NfcCommandContinue; + + if(iso14443_3a_event->type == Iso14443_3aListenerEventTypeReceivedStandardFrame) { + if(instance->state == Iso14443_4aListenerStateIdle) { + if(bit_buffer_get_size_bytes(rx_buffer) == 2 && + bit_buffer_get_byte(rx_buffer, 0) == ISO14443_4A_CMD_READ_ATS) { + if(iso14443_4a_listener_send_ats(instance, instance->data->ats_data) != + Iso14443_4aErrorNone) { + command = NfcCommandStop; + } else { + instance->state = Iso14443_4aListenerStateActive; + } + } + } else { + instance->iso14443_4a_event.type = Iso14443_4aListenerEventTypeReceivedData; + instance->iso14443_4a_event.data->buffer = rx_buffer; + + if(instance->callback) { + command = instance->callback(instance->generic_event, instance->context); + } + } + } else if( + iso14443_3a_event->type == Iso14443_3aListenerEventTypeHalted || + iso14443_3a_event->type == Iso14443_3aListenerEventTypeFieldOff) { + instance->state = Iso14443_4aListenerStateIdle; + command = NfcCommandStop; + } + + return command; +} + +const NfcListenerBase nfc_listener_iso14443_4a = { + .alloc = (NfcListenerAlloc)iso14443_4a_listener_alloc, + .free = (NfcListenerFree)iso14443_4a_listener_free, + .set_callback = (NfcListenerSetCallback)iso14443_4a_listener_set_callback, + .get_data = (NfcListenerGetData)iso14443_4a_listener_get_data, + .run = (NfcListenerRun)iso14443_4a_listener_run, +}; diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_listener.h b/lib/nfc/protocols/iso14443_4a/iso14443_4a_listener.h new file mode 100644 index 000000000000..ba649847b274 --- /dev/null +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_listener.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +#include "iso14443_4a.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct Iso14443_4aListener Iso14443_4aListener; + +typedef enum { + Iso14443_4aListenerEventTypeHalted, + Iso14443_4aListenerEventTypeReceivedData, +} Iso14443_4aListenerEventType; + +typedef struct { + BitBuffer* buffer; +} Iso14443_4aListenerEventData; + +typedef struct { + Iso14443_4aListenerEventType type; + Iso14443_4aListenerEventData* data; +} Iso14443_4aListenerEvent; + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_listener_defs.h b/lib/nfc/protocols/iso14443_4a/iso14443_4a_listener_defs.h new file mode 100644 index 000000000000..06f20846a7d6 --- /dev/null +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_listener_defs.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern const NfcListenerBase nfc_listener_iso14443_4a; + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_listener_i.c b/lib/nfc/protocols/iso14443_4a/iso14443_4a_listener_i.c new file mode 100644 index 000000000000..ec604265fcb4 --- /dev/null +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_listener_i.c @@ -0,0 +1,13 @@ +#include "iso14443_4a_listener_i.h" + +#include + +Iso14443_4aError + iso14443_4a_listener_send_ats(Iso14443_4aListener* instance, const SimpleArray* data) { + bit_buffer_copy_bytes( + instance->tx_buffer, simple_array_cget(data, 0), simple_array_get_count(data)); + + const Iso14443_3aError error = iso14443_3a_listener_send_standard_frame( + instance->iso14443_3a_listener, instance->tx_buffer); + return iso14443_4a_process_error(error); +} diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_listener_i.h b/lib/nfc/protocols/iso14443_4a/iso14443_4a_listener_i.h new file mode 100644 index 000000000000..c98eecc5c0e5 --- /dev/null +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_listener_i.h @@ -0,0 +1,36 @@ +#pragma once + +#include + +#include "iso14443_4a_listener.h" +#include "iso14443_4a_i.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + Iso14443_4aListenerStateIdle, + Iso14443_4aListenerStateActive, +} Iso14443_4aListenerState; + +struct Iso14443_4aListener { + Iso14443_3aListener* iso14443_3a_listener; + Iso14443_4aData* data; + Iso14443_4aListenerState state; + + BitBuffer* tx_buffer; + + NfcGenericEvent generic_event; + Iso14443_4aListenerEvent iso14443_4a_event; + Iso14443_4aListenerEventData iso14443_4a_event_data; + NfcGenericCallback callback; + void* context; +}; + +Iso14443_4aError + iso14443_4a_listener_send_ats(Iso14443_4aListener* instance, const SimpleArray* data); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.c b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.c index a5c599ba0bc7..90e5c9cc0dc8 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.c +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.c @@ -6,7 +6,7 @@ #define TAG "Iso14443_4aPoller" -#define ISO14443_4A_BUF_SIZE_MAX (512U) +#define ISO14443_4A_POLLER_BUF_SIZE (256U) typedef NfcCommand (*Iso14443_4aPollerStateHandler)(Iso14443_4aPoller* instance); @@ -20,8 +20,8 @@ static Iso14443_4aPoller* iso14443_4a_poller_alloc(Iso14443_3aPoller* iso14443_3 Iso14443_4aPoller* instance = malloc(sizeof(Iso14443_4aPoller)); instance->iso14443_3a_poller = iso14443_3a_poller; instance->data = iso14443_4a_alloc(); - instance->tx_buffer = bit_buffer_alloc(ISO14443_4A_BUF_SIZE_MAX); - instance->rx_buffer = bit_buffer_alloc(ISO14443_4A_BUF_SIZE_MAX); + instance->tx_buffer = bit_buffer_alloc(ISO14443_4A_POLLER_BUF_SIZE); + instance->rx_buffer = bit_buffer_alloc(ISO14443_4A_POLLER_BUF_SIZE); instance->iso14443_4a_event.data = &instance->iso14443_4a_event_data; @@ -52,8 +52,7 @@ static NfcCommand iso14443_4a_poller_handler_idle(Iso14443_4aPoller* instance) { } static NfcCommand iso14443_4a_poller_handler_read_ats(Iso14443_4aPoller* instance) { - Iso14443_4aError error = - iso14443_4a_poller_async_read_ats(instance, &instance->data->ats_data); + Iso14443_4aError error = iso14443_4a_poller_async_read_ats(instance, instance->data->ats_data); if(error == Iso14443_4aErrorNone) { FURI_LOG_D(TAG, "Read ATS success"); instance->poller_state = Iso14443_4aPollerStateReady; diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c index a33dfd061d02..53d90e9684e0 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c @@ -6,25 +6,6 @@ #define TAG "Iso14443_4aPoller" -#define ISO14443_4A_PCB_I (0x02) - -Iso14443_4aError iso14443_4a_poller_process_error(Iso14443_3aError error) { - switch(error) { - case Iso14443_3aErrorNone: - return Iso14443_4aErrorNone; - case Iso14443_3aErrorNotPresent: - return Iso14443_4aErrorNotPresent; - case Iso14443_3aErrorColResFailed: - case Iso14443_3aErrorCommunication: - case Iso14443_3aErrorWrongCrc: - return Iso14443_4aErrorProtocol; - case Iso14443_3aErrorTimeout: - return Iso14443_4aErrorTimeout; - default: - return Iso14443_4aErrorProtocol; - } -} - Iso14443_4aError iso14443_4a_poller_halt(Iso14443_4aPoller* instance) { furi_assert(instance); @@ -35,12 +16,12 @@ Iso14443_4aError iso14443_4a_poller_halt(Iso14443_4aPoller* instance) { } Iso14443_4aError - iso14443_4a_poller_async_read_ats(Iso14443_4aPoller* instance, Iso14443_4aAtsData* data) { + iso14443_4a_poller_async_read_ats(Iso14443_4aPoller* instance, SimpleArray* data) { furi_assert(instance); bit_buffer_reset(instance->tx_buffer); bit_buffer_append_byte(instance->tx_buffer, ISO14443_4A_CMD_READ_ATS); - bit_buffer_append_byte(instance->tx_buffer, 0x80); + bit_buffer_append_byte(instance->tx_buffer, ISO14443_4A_FSDI_256 << 4); Iso14443_4aError error = Iso14443_4aErrorNone; @@ -53,7 +34,7 @@ Iso14443_4aError if(iso14443_3a_error != Iso14443_3aErrorNone) { FURI_LOG_E(TAG, "ATS request failed"); - error = iso14443_4a_poller_process_error(iso14443_3a_error); + error = iso14443_4a_process_error(iso14443_3a_error); break; } else if(!iso14443_4a_ats_parse(data, instance->rx_buffer)) { @@ -74,7 +55,8 @@ Iso14443_4aError iso14443_4a_poller_send_block( uint32_t fwt) { furi_assert(instance); - const uint8_t pcb = ISO14443_4A_PCB_I | instance->protocol_state.block_number; + const uint8_t pcb = ISO14443_4A_BLOCK_PCB_I | ISO14443_4A_BLOCK_PCB | + instance->protocol_state.block_number; instance->protocol_state.block_number ^= 1; bit_buffer_reset(instance->tx_buffer); @@ -88,7 +70,7 @@ Iso14443_4aError iso14443_4a_poller_send_block( instance->iso14443_3a_poller, instance->tx_buffer, instance->rx_buffer, fwt); if(iso14443_3a_error != Iso14443_3aErrorNone) { - error = iso14443_4a_poller_process_error(iso14443_3a_error); + error = iso14443_4a_process_error(iso14443_3a_error); break; } else if(!bit_buffer_starts_with_byte(instance->rx_buffer, pcb)) { diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.h b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.h index b90b7c2000fc..0673d74dcdf5 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.h +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.h @@ -45,14 +45,13 @@ struct Iso14443_4aPoller { void* context; }; -Iso14443_4aError iso14443_4a_poller_process_error(Iso14443_3aError error); +Iso14443_4aError iso14443_4a_process_error(Iso14443_3aError error); const Iso14443_4aData* iso14443_4a_poller_get_data(Iso14443_4aPoller* instance); Iso14443_4aError iso14443_4a_poller_halt(Iso14443_4aPoller* instance); -Iso14443_4aError - iso14443_4a_poller_async_read_ats(Iso14443_4aPoller* instance, Iso14443_4aAtsData* data); +Iso14443_4aError iso14443_4a_poller_async_read_ats(Iso14443_4aPoller* instance, SimpleArray* data); Iso14443_4aError iso14443_4a_poller_send_block( Iso14443_4aPoller* instance, diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_i.c b/lib/nfc/protocols/mf_desfire/mf_desfire_i.c index 18dfaaca15c4..e0ca0a30437c 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_i.c +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_i.c @@ -1,5 +1,7 @@ #include "mf_desfire_i.h" +#define BITS_IN_BYTE (8U) + #define MF_DESFIRE_FFF_VERSION_KEY \ MF_DESFIRE_FFF_PICC_PREFIX " " \ "Version" @@ -43,18 +45,36 @@ #define MF_DESFIRE_FFF_FILE_MAX_KEY "Max" #define MF_DESFIRE_FFF_FILE_CUR_KEY "Cur" -void mf_desfire_version_parse(MfDesfireVersion* data, const BitBuffer* buf) { - bit_buffer_write_bytes(buf, data, sizeof(MfDesfireVersion)); +bool mf_desfire_version_parse(MfDesfireVersion* data, const BitBuffer* buf) { + const bool can_parse = bit_buffer_get_size_bytes(buf) == sizeof(MfDesfireVersion); + + if(can_parse) { + bit_buffer_write_bytes(buf, data, sizeof(MfDesfireVersion)); + } + + return can_parse; } -void mf_desfire_free_memory_parse(MfDesfireFreeMemory* data, const BitBuffer* buf) { - bit_buffer_write_bytes(buf, &data->bytes_free, sizeof(data->bytes_free) - 1); - data->bytes_free &= 0x00ffffff; - data->is_present = true; +bool mf_desfire_free_memory_parse(MfDesfireFreeMemory* data, const BitBuffer* buf) { + typedef struct __attribute__((packed)) { + uint32_t bytes_free : 3 * BITS_IN_BYTE; + } MfDesfireFreeMemoryLayout; + + const bool can_parse = bit_buffer_get_size_bytes(buf) == sizeof(MfDesfireFreeMemoryLayout); + + if(can_parse) { + MfDesfireFreeMemoryLayout layout; + bit_buffer_write_bytes(buf, &layout, sizeof(MfDesfireFreeMemoryLayout)); + data->bytes_free = layout.bytes_free; + } + + data->is_present = can_parse; + + return can_parse; } -void mf_desfire_key_settings_parse(MfDesfireKeySettings* data, const BitBuffer* buf) { - typedef struct { +bool mf_desfire_key_settings_parse(MfDesfireKeySettings* data, const BitBuffer* buf) { + typedef struct __attribute__((packed)) { bool is_master_key_changeable : 1; bool is_free_directory_list : 1; bool is_free_create_delete : 1; @@ -64,51 +84,161 @@ void mf_desfire_key_settings_parse(MfDesfireKeySettings* data, const BitBuffer* uint8_t flags : 4; } MfDesfireKeySettingsLayout; - MfDesfireKeySettingsLayout layout; - bit_buffer_write_bytes(buf, &layout, sizeof(MfDesfireKeySettingsLayout)); + const bool can_parse = bit_buffer_get_size_bytes(buf) == sizeof(MfDesfireKeySettingsLayout); - data->is_master_key_changeable = layout.is_master_key_changeable; - data->is_free_directory_list = layout.is_free_directory_list; - data->is_free_create_delete = layout.is_free_create_delete; - data->is_config_changeable = layout.is_config_changeable; + if(can_parse) { + MfDesfireKeySettingsLayout layout; + bit_buffer_write_bytes(buf, &layout, sizeof(MfDesfireKeySettingsLayout)); - data->change_key_id = layout.change_key_id; - data->max_keys = layout.max_keys; - data->flags = layout.flags; + data->is_master_key_changeable = layout.is_master_key_changeable; + data->is_free_directory_list = layout.is_free_directory_list; + data->is_free_create_delete = layout.is_free_create_delete; + data->is_config_changeable = layout.is_config_changeable; + + data->change_key_id = layout.change_key_id; + data->max_keys = layout.max_keys; + data->flags = layout.flags; + } + + return can_parse; } -void mf_desfire_key_version_parse(MfDesfireKeyVersion* data, const BitBuffer* buf) { - bit_buffer_write_bytes(buf, data, sizeof(MfDesfireKeyVersion)); +bool mf_desfire_key_version_parse(MfDesfireKeyVersion* data, const BitBuffer* buf) { + const bool can_parse = bit_buffer_get_size_bytes(buf) == sizeof(MfDesfireKeyVersion); + + if(can_parse) { + bit_buffer_write_bytes(buf, data, sizeof(MfDesfireKeyVersion)); + } + + return can_parse; } -void mf_desfire_application_id_parse( +bool mf_desfire_application_id_parse( MfDesfireApplicationId* data, uint32_t index, const BitBuffer* buf) { - bit_buffer_write_bytes_mid( - buf, data, index * sizeof(MfDesfireApplicationId), sizeof(MfDesfireApplicationId)); + const bool can_parse = + bit_buffer_get_size_bytes(buf) >= + (index * sizeof(MfDesfireApplicationId) + sizeof(MfDesfireApplicationId)); + + if(can_parse) { + bit_buffer_write_bytes_mid( + buf, data, index * sizeof(MfDesfireApplicationId), sizeof(MfDesfireApplicationId)); + } + + return can_parse; } -void mf_desfire_file_id_parse(MfDesfireFileId* data, uint32_t index, const BitBuffer* buf) { - bit_buffer_write_bytes_mid( - buf, data, index * sizeof(MfDesfireFileId), sizeof(MfDesfireFileId)); +bool mf_desfire_file_id_parse(MfDesfireFileId* data, uint32_t index, const BitBuffer* buf) { + const bool can_parse = bit_buffer_get_size_bytes(buf) >= + (index * sizeof(MfDesfireFileId) + sizeof(MfDesfireFileId)); + if(can_parse) { + bit_buffer_write_bytes_mid( + buf, data, index * sizeof(MfDesfireFileId), sizeof(MfDesfireFileId)); + } + + return can_parse; } -void mf_desfire_file_settings_parse(MfDesfireFileSettings* data, const BitBuffer* buf) { - bit_buffer_write_bytes(buf, data, sizeof(MfDesfireFileSettings)); +bool mf_desfire_file_settings_parse(MfDesfireFileSettings* data, const BitBuffer* buf) { + bool parsed = false; + + typedef struct __attribute__((packed)) { + uint8_t type; + uint8_t comm; + uint16_t access_rights; + } MfDesfireFileSettingsHeader; + + typedef struct __attribute__((packed)) { + uint32_t size : 3 * BITS_IN_BYTE; + } MfDesfireFileSettingsData; + + typedef struct __attribute__((packed)) { + uint32_t lo_limit; + uint32_t hi_limit; + uint32_t limited_credit_value; + uint8_t limited_credit_enabled; + } MfDesfireFileSettingsValue; + + typedef struct __attribute__((packed)) { + uint32_t size : 3 * BITS_IN_BYTE; + uint32_t max : 3 * BITS_IN_BYTE; + uint32_t cur : 3 * BITS_IN_BYTE; + } MfDesfireFileSettingsRecord; + + typedef struct __attribute__((packed)) { + MfDesfireFileSettingsHeader header; + union { + MfDesfireFileSettingsData data; + MfDesfireFileSettingsValue value; + MfDesfireFileSettingsRecord record; + }; + } MfDesfireFileSettingsLayout; + + do { + const size_t data_size = bit_buffer_get_size_bytes(buf); + const size_t min_data_size = + sizeof(MfDesfireFileSettingsHeader) + sizeof(MfDesfireFileSettingsData); + + if(data_size < min_data_size) break; + + MfDesfireFileSettingsLayout layout; + bit_buffer_write_bytes(buf, &layout, sizeof(MfDesfireFileSettingsLayout)); + + data->type = layout.header.type; + data->comm = layout.header.comm; + data->access_rights = layout.header.access_rights; + + if(data->type == MfDesfireFileTypeStandard || data->type == MfDesfireFileTypeBackup) { + if(data_size != min_data_size) break; + + data->data.size = layout.data.size; + + } else if(data->type == MfDesfireFileTypeValue) { + if(data_size != + sizeof(MfDesfireFileSettingsHeader) + sizeof(MfDesfireFileSettingsValue)) + break; + + data->value.lo_limit = layout.value.lo_limit; + data->value.hi_limit = layout.value.hi_limit; + data->value.limited_credit_value = layout.value.hi_limit; + data->value.limited_credit_enabled = layout.value.limited_credit_enabled; + + } else if( + data->type == MfDesfireFileTypeLinearRecord || + data->type == MfDesfireFileTypeCyclicRecord) { + if(data_size != + sizeof(MfDesfireFileSettingsHeader) + sizeof(MfDesfireFileSettingsRecord)) + break; + + data->record.size = layout.record.size; + data->record.max = layout.record.max; + data->record.cur = layout.record.cur; + + } else { + break; + } + + parsed = true; + } while(false); + + return parsed; } -void mf_desfire_file_data_parse(MfDesfireFileData* data, const BitBuffer* buf) { +bool mf_desfire_file_data_parse(MfDesfireFileData* data, const BitBuffer* buf) { const size_t data_size = bit_buffer_get_size_bytes(buf); if(data_size > 0) { simple_array_init(data->data, data_size); bit_buffer_write_bytes(buf, simple_array_get(data->data, 0), data_size); } + + // Success no matter whether there is data or not + return true; } void mf_desfire_file_data_init(MfDesfireFileData* data) { - data->data = simple_array_alloc(&mf_desfire_file_data_element_array_config); + data->data = simple_array_alloc(&simple_array_config_uint8_t); } void mf_desfire_application_init(MfDesfireApplication* data) { @@ -655,13 +785,6 @@ const SimpleArrayConfig mf_desfire_file_data_array_config = { .type_size = sizeof(MfDesfireData), }; -const SimpleArrayConfig mf_desfire_file_data_element_array_config = { - .init = NULL, - .copy = NULL, - .reset = NULL, - .type_size = sizeof(uint8_t), -}; - const SimpleArrayConfig mf_desfire_application_array_config = { .init = (SimpleArrayInit)mf_desfire_application_init, .copy = (SimpleArrayCopy)mf_desfire_application_copy, diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_i.h b/lib/nfc/protocols/mf_desfire/mf_desfire_i.h index 9825a2cbf3fe..05381096d169 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_i.h +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_i.h @@ -12,29 +12,28 @@ extern const SimpleArrayConfig mf_desfire_app_id_array_config; extern const SimpleArrayConfig mf_desfire_file_id_array_config; extern const SimpleArrayConfig mf_desfire_file_settings_array_config; extern const SimpleArrayConfig mf_desfire_file_data_array_config; -extern const SimpleArrayConfig mf_desfire_file_data_element_array_config; extern const SimpleArrayConfig mf_desfire_application_array_config; // Parse internal MfDesfire structures -void mf_desfire_version_parse(MfDesfireVersion* data, const BitBuffer* buf); +bool mf_desfire_version_parse(MfDesfireVersion* data, const BitBuffer* buf); -void mf_desfire_free_memory_parse(MfDesfireFreeMemory* data, const BitBuffer* buf); +bool mf_desfire_free_memory_parse(MfDesfireFreeMemory* data, const BitBuffer* buf); -void mf_desfire_key_settings_parse(MfDesfireKeySettings* data, const BitBuffer* buf); +bool mf_desfire_key_settings_parse(MfDesfireKeySettings* data, const BitBuffer* buf); -void mf_desfire_key_version_parse(MfDesfireKeyVersion* data, const BitBuffer* buf); +bool mf_desfire_key_version_parse(MfDesfireKeyVersion* data, const BitBuffer* buf); -void mf_desfire_application_id_parse( +bool mf_desfire_application_id_parse( MfDesfireApplicationId* data, uint32_t index, const BitBuffer* buf); -void mf_desfire_file_id_parse(MfDesfireFileId* data, uint32_t index, const BitBuffer* buf); +bool mf_desfire_file_id_parse(MfDesfireFileId* data, uint32_t index, const BitBuffer* buf); -void mf_desfire_file_settings_parse(MfDesfireFileSettings* data, const BitBuffer* buf); +bool mf_desfire_file_settings_parse(MfDesfireFileSettings* data, const BitBuffer* buf); -void mf_desfire_file_data_parse(MfDesfireFileData* data, const BitBuffer* buf); +bool mf_desfire_file_data_parse(MfDesfireFileData* data, const BitBuffer* buf); // Init internal MfDesfire structures diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c b/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c index 404fedeb63b7..64868d07fc3c 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c @@ -74,17 +74,21 @@ MfDesfireError bit_buffer_reset(instance->input_buffer); bit_buffer_append_byte(instance->input_buffer, MF_DESFIRE_CMD_GET_VERSION); - MfDesfireError error = mf_desfire_send_chunks( - instance, - instance->input_buffer, - instance->result_buffer, - MF_DESFIRE_POLLER_STANDARD_FWT_FC); + MfDesfireError error; - if(error == MfDesfireErrorNone) { - mf_desfire_version_parse(data, instance->result_buffer); - } else { - FURI_LOG_D(TAG, "Read version error: %d", error); - } + do { + error = mf_desfire_send_chunks( + instance, + instance->input_buffer, + instance->result_buffer, + MF_DESFIRE_POLLER_STANDARD_FWT_FC); + + if(error != MfDesfireErrorNone) break; + + if(!mf_desfire_version_parse(data, instance->result_buffer)) { + error = MfDesfireErrorProtocol; + } + } while(false); return error; } @@ -96,15 +100,21 @@ MfDesfireError bit_buffer_reset(instance->input_buffer); bit_buffer_append_byte(instance->input_buffer, MF_DESFIRE_CMD_GET_FREE_MEMORY); - MfDesfireError error = mf_desfire_send_chunks( - instance, - instance->input_buffer, - instance->result_buffer, - MF_DESFIRE_POLLER_STANDARD_FWT_FC); + MfDesfireError error; - if(error == MfDesfireErrorNone) { - mf_desfire_free_memory_parse(data, instance->result_buffer); - } + do { + error = mf_desfire_send_chunks( + instance, + instance->input_buffer, + instance->result_buffer, + MF_DESFIRE_POLLER_STANDARD_FWT_FC); + + if(error != MfDesfireErrorNone) break; + + if(!mf_desfire_free_memory_parse(data, instance->result_buffer)) { + error = MfDesfireErrorProtocol; + } + } while(false); return error; } @@ -117,15 +127,21 @@ MfDesfireError mf_desfire_poller_async_read_key_settings( bit_buffer_reset(instance->input_buffer); bit_buffer_append_byte(instance->input_buffer, MF_DESFIRE_CMD_GET_KEY_SETTINGS); - MfDesfireError error = mf_desfire_send_chunks( - instance, - instance->input_buffer, - instance->result_buffer, - MF_DESFIRE_POLLER_STANDARD_FWT_FC); + MfDesfireError error; - if(error == MfDesfireErrorNone) { - mf_desfire_key_settings_parse(data, instance->result_buffer); - } + do { + error = mf_desfire_send_chunks( + instance, + instance->input_buffer, + instance->result_buffer, + MF_DESFIRE_POLLER_STANDARD_FWT_FC); + + if(error != MfDesfireErrorNone) break; + + if(!mf_desfire_key_settings_parse(data, instance->result_buffer)) { + error = MfDesfireErrorProtocol; + } + } while(false); return error; } @@ -155,7 +171,10 @@ MfDesfireError mf_desfire_poller_async_read_key_versions( if(error != MfDesfireErrorNone) break; - mf_desfire_key_version_parse(simple_array_get(data, i), instance->result_buffer); + if(!mf_desfire_key_version_parse(simple_array_get(data, i), instance->result_buffer)) { + error = MfDesfireErrorProtocol; + break; + } } return error; @@ -186,7 +205,11 @@ MfDesfireError simple_array_init(data, app_id_count); for(uint32_t i = 0; i < app_id_count; ++i) { - mf_desfire_application_id_parse(simple_array_get(data, i), i, instance->result_buffer); + if(!mf_desfire_application_id_parse( + simple_array_get(data, i), i, instance->result_buffer)) { + error = MfDesfireErrorProtocol; + break; + } } } while(false); @@ -237,7 +260,10 @@ MfDesfireError simple_array_init(data, id_count); for(uint32_t i = 0; i < id_count; ++i) { - mf_desfire_file_id_parse(simple_array_get(data, i), i, instance->result_buffer); + if(!mf_desfire_file_id_parse(simple_array_get(data, i), i, instance->result_buffer)) { + error = MfDesfireErrorProtocol; + break; + } } } while(false); @@ -254,15 +280,21 @@ MfDesfireError mf_desfire_poller_async_read_file_settings( bit_buffer_append_byte(instance->input_buffer, MF_DESFIRE_CMD_GET_FILE_SETTINGS); bit_buffer_append_byte(instance->input_buffer, id); - MfDesfireError error = mf_desfire_send_chunks( - instance, - instance->input_buffer, - instance->result_buffer, - MF_DESFIRE_POLLER_STANDARD_FWT_FC); + MfDesfireError error; - if(error == MfDesfireErrorNone) { - mf_desfire_file_settings_parse(data, instance->result_buffer); - } + do { + error = mf_desfire_send_chunks( + instance, + instance->input_buffer, + instance->result_buffer, + MF_DESFIRE_POLLER_STANDARD_FWT_FC); + + if(error != MfDesfireErrorNone) break; + + if(!mf_desfire_file_settings_parse(data, instance->result_buffer)) { + error = MfDesfireErrorProtocol; + } + } while(false); return error; } @@ -304,15 +336,21 @@ MfDesfireError mf_desfire_poller_async_read_file_data( bit_buffer_append_bytes(instance->input_buffer, (const uint8_t*)&offset, 3); bit_buffer_append_bytes(instance->input_buffer, (const uint8_t*)&size, 3); - MfDesfireError error = mf_desfire_send_chunks( - instance, - instance->input_buffer, - instance->result_buffer, - MF_DESFIRE_POLLER_STANDARD_FWT_FC); + MfDesfireError error; - if(error == MfDesfireErrorNone) { - mf_desfire_file_data_parse(data, instance->result_buffer); - } + do { + error = mf_desfire_send_chunks( + instance, + instance->input_buffer, + instance->result_buffer, + MF_DESFIRE_POLLER_STANDARD_FWT_FC); + + if(error != MfDesfireErrorNone) break; + + if(!mf_desfire_file_data_parse(data, instance->result_buffer)) { + error = MfDesfireErrorProtocol; + } + } while(false); return error; } @@ -327,15 +365,21 @@ MfDesfireError mf_desfire_poller_async_read_file_value( bit_buffer_append_byte(instance->input_buffer, MF_DESFIRE_CMD_GET_VALUE); bit_buffer_append_byte(instance->input_buffer, id); - MfDesfireError error = mf_desfire_send_chunks( - instance, - instance->input_buffer, - instance->result_buffer, - MF_DESFIRE_POLLER_STANDARD_FWT_FC); + MfDesfireError error; - if(error == MfDesfireErrorNone) { - mf_desfire_file_data_parse(data, instance->result_buffer); - } + do { + error = mf_desfire_send_chunks( + instance, + instance->input_buffer, + instance->result_buffer, + MF_DESFIRE_POLLER_STANDARD_FWT_FC); + + if(error != MfDesfireErrorNone) break; + + if(!mf_desfire_file_data_parse(data, instance->result_buffer)) { + error = MfDesfireErrorProtocol; + } + } while(false); return error; } @@ -354,15 +398,21 @@ MfDesfireError mf_desfire_poller_async_read_file_records( bit_buffer_append_bytes(instance->input_buffer, (const uint8_t*)&offset, 3); bit_buffer_append_bytes(instance->input_buffer, (const uint8_t*)&size, 3); - MfDesfireError error = mf_desfire_send_chunks( - instance, - instance->input_buffer, - instance->result_buffer, - MF_DESFIRE_POLLER_STANDARD_FWT_FC); + MfDesfireError error; - if(error == MfDesfireErrorNone) { - mf_desfire_file_data_parse(data, instance->result_buffer); - } + do { + error = mf_desfire_send_chunks( + instance, + instance->input_buffer, + instance->result_buffer, + MF_DESFIRE_POLLER_STANDARD_FWT_FC); + + if(error != MfDesfireErrorNone) break; + + if(!mf_desfire_file_data_parse(data, instance->result_buffer)) { + error = MfDesfireErrorProtocol; + } + } while(false); return error; } diff --git a/lib/nfc/protocols/nfc_listener_defs.c b/lib/nfc/protocols/nfc_listener_defs.c index 539cec4afa1a..0a44454f0934 100644 --- a/lib/nfc/protocols/nfc_listener_defs.c +++ b/lib/nfc/protocols/nfc_listener_defs.c @@ -1,13 +1,13 @@ #include "nfc_listener_defs.h" #include -// #include +#include #include #include const NfcListenerBase* nfc_listeners_api[NfcProtocolNum] = { [NfcProtocolIso14443_3a] = &nfc_listener_iso14443_3a, - [NfcProtocolIso14443_4a] = NULL, //&nfc_listener_iso14443_4a, + [NfcProtocolIso14443_4a] = &nfc_listener_iso14443_4a, [NfcProtocolMfUltralight] = &mf_ultralight_listener, [NfcProtocolMfClassic] = &mf_classic_listener, [NfcProtocolMfDesfire] = NULL, From 30d8fda9bbbde9d1e7d74d09f051dae21257965b Mon Sep 17 00:00:00 2001 From: gornekich Date: Mon, 17 Jul 2023 15:05:47 +0400 Subject: [PATCH 123/149] Full MFC emulation , Detect Reader (#2886) * nfc hal: add nfca hal init and deinit * lib: move iso14443_3a signal lo digital signal lib * mfc: rework emulation * nfc app: add detect reader scene * nfc: set NfcProtocolInvalid as default * nfc mf classic: add more events for mfc emulation * nfc app: introduce mfkey32 logger * nfc app: implement detect reader scenes * nfc rpc: add mf classic commands * nfc mf classic: implement write block command * nfc mf classi: add read value command * nfc mf classic: implement value commands * nfc mf classic: implement write listener and test * nfc mf classic: complete listener * nfc: add listener reset * nfc tests: fix unit tests * nfc: clean up code * nfc device: check Invalid protocol --- applications/debug/unit_tests/nfc/nfc_test.c | 129 +++-- .../debug/unit_tests/nfc/nfc_transport.c | 6 +- .../main/nfc/helpers/mfkey32_logger.c | 173 +++++++ .../main/nfc/helpers/mfkey32_logger.h | 25 + .../main/nfc/helpers/nfc_custom_event.h | 1 + applications/main/nfc/nfc_app_i.h | 6 + .../main/nfc/scenes/nfc_scene_config.h | 3 + .../nfc_scene_mf_classic_detect_reader.c | 139 ++++++ .../nfc_scene_mf_classic_mfkey_complete.c | 58 +++ .../nfc_scene_mf_classic_mfkey_nonces_info.c | 72 +++ .../main/nfc/scenes/nfc_scene_start.c | 2 +- applications/main/nfc/views/detect_reader.c | 5 +- .../main/nfc_rpc/assets/compiled/main.pb.c | 5 + .../main/nfc_rpc/assets/compiled/main.pb.h | 284 ++++------- .../nfc_rpc/assets/compiled/mf_classic.pb.c | 26 + .../nfc_rpc/assets/compiled/mf_classic.pb.h | 260 +++++++--- .../assets/compiled/mf_ultralight.pb.c | 19 + .../assets/compiled/mf_ultralight.pb.h | 264 ++++------- .../main/nfc_rpc/assets/compiled/nfca.pb.c | 9 + .../main/nfc_rpc/assets/compiled/nfca.pb.h | 131 ++--- .../main/nfc_rpc/assets/protobuf/main.proto | 7 + .../assets/protobuf/mf_classic.options | 12 +- .../nfc_rpc/assets/protobuf/mf_classic.proto | 34 ++ .../main/nfc_rpc/nfc_rpc_mf_classic.c | 86 ++++ firmware/targets/f7/api_symbols.csv | 10 +- firmware/targets/f7/furi_hal/f_hal_nfc.c | 10 + firmware/targets/f7/furi_hal/f_hal_nfca.c | 21 +- firmware/targets/f7/target.json | 3 +- firmware/targets/furi_hal_include/f_hal_nfc.h | 9 + .../presets/nfc}/iso14443_3a_signal.c | 0 .../presets/nfc}/iso14443_3a_signal.h | 0 lib/nfc/nfc.c | 8 +- lib/nfc/nfc_device.c | 13 +- lib/nfc/protocols/iso14443_3a/iso14443_3a.c | 4 +- lib/nfc/protocols/iso14443_3a/iso14443_3a.h | 2 +- lib/nfc/protocols/mf_classic/mf_classic.c | 51 +- lib/nfc/protocols/mf_classic/mf_classic.h | 20 + .../mf_classic/mf_classic_listener.c | 447 ++++++++++++++---- .../mf_classic/mf_classic_listener.h | 3 +- .../mf_classic/mf_classic_listener_i.h | 24 +- .../mf_classic/mf_classic_poller_i.c | 183 +++++++ .../mf_classic/mf_classic_poller_i.h | 39 ++ .../mf_classic/mf_classic_poller_sync_api.c | 217 ++++++++- .../mf_classic/mf_classic_poller_sync_api.h | 22 + 44 files changed, 2140 insertions(+), 702 deletions(-) create mode 100644 applications/main/nfc/helpers/mfkey32_logger.c create mode 100644 applications/main/nfc/helpers/mfkey32_logger.h create mode 100644 applications/main/nfc/scenes/nfc_scene_mf_classic_detect_reader.c create mode 100644 applications/main/nfc/scenes/nfc_scene_mf_classic_mfkey_complete.c create mode 100644 applications/main/nfc/scenes/nfc_scene_mf_classic_mfkey_nonces_info.c rename lib/{nfc/helpers => digital_signal/presets/nfc}/iso14443_3a_signal.c (100%) rename lib/{nfc/helpers => digital_signal/presets/nfc}/iso14443_3a_signal.h (100%) diff --git a/applications/debug/unit_tests/nfc/nfc_test.c b/applications/debug/unit_tests/nfc/nfc_test.c index 38ed49e470f7..8e557a1fad83 100644 --- a/applications/debug/unit_tests/nfc/nfc_test.c +++ b/applications/debug/unit_tests/nfc/nfc_test.c @@ -361,42 +361,109 @@ static void mf_classic_reader() { nfc_free(poller); } +static void mf_classic_write() { + Nfc* poller = nfc_alloc(); + Nfc* listener = nfc_alloc(); + + NfcDevice* nfc_device = nfc_device_alloc(); + nfc_data_generator_fill_data(NfcDataGeneratorTypeMfClassic4k_7b, nfc_device); + NfcListener* mfc_listener = nfc_listener_alloc( + listener, NfcProtocolMfClassic, nfc_device_get_data(nfc_device, NfcProtocolMfClassic)); + nfc_listener_start(mfc_listener, NULL, NULL); + + MfClassicBlock block_write = {}; + MfClassicBlock block_read = {}; + furi_hal_random_fill_buf(block_write.data, sizeof(MfClassicBlock)); + MfClassicKey key = {.data = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}; + + mf_classic_poller_write_block(poller, 1, &key, MfClassicKeyTypeA, &block_write); + mf_classic_poller_read_block(poller, 1, &key, MfClassicKeyTypeA, &block_read); + + nfc_listener_stop(mfc_listener); + nfc_listener_free(mfc_listener); + + mu_assert(memcmp(&block_read, &block_write, sizeof(MfClassicBlock)) == 0, "Data mismatch"); + + nfc_device_free(nfc_device); + nfc_free(listener); + nfc_free(poller); +} + +static void mf_classic_value_block() { + Nfc* poller = nfc_alloc(); + Nfc* listener = nfc_alloc(); + + NfcDevice* nfc_device = nfc_device_alloc(); + nfc_data_generator_fill_data(NfcDataGeneratorTypeMfClassic4k_7b, nfc_device); + NfcListener* mfc_listener = nfc_listener_alloc( + listener, NfcProtocolMfClassic, nfc_device_get_data(nfc_device, NfcProtocolMfClassic)); + nfc_listener_start(mfc_listener, NULL, NULL); + + MfClassicKey key = {.data = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}; + + int32_t value = 228; + MfClassicBlock block_write = {}; + mf_classic_value_to_block(value, 1, &block_write); + + MfClassicError error = MfClassicErrorNone; + error = mf_classic_poller_write_block(poller, 1, &key, MfClassicKeyTypeA, &block_write); + mu_assert(error == MfClassicErrorNone, "Write failed"); + + int32_t data = 200; + int32_t new_value = 0; + error = mf_classic_poller_change_value(poller, 1, &key, MfClassicKeyTypeA, data, &new_value); + mu_assert(error == MfClassicErrorNone, "Value increment failed"); + mu_assert(new_value == value + data, "Value not match"); + + error = mf_classic_poller_change_value(poller, 1, &key, MfClassicKeyTypeA, -data, &new_value); + mu_assert(error == MfClassicErrorNone, "Value decrement failed"); + mu_assert(new_value == value, "Value not match"); + + nfc_listener_stop(mfc_listener); + nfc_listener_free(mfc_listener); + nfc_device_free(nfc_device); + nfc_free(listener); + nfc_free(poller); +} + MU_TEST_SUITE(nfc) { nfc_test_alloc(); + MU_RUN_TEST(iso14443_3a_reader); + MU_RUN_TEST(mf_ultralight_11_reader); + MU_RUN_TEST(mf_ultralight_21_reader); + MU_RUN_TEST(ntag_215_reader); + MU_RUN_TEST(ntag_216_reader); + MU_RUN_TEST(ntag_213_locked_reader); + + MU_RUN_TEST(mf_ultralight_write); + + MU_RUN_TEST(iso14443_3a_4b_file_test); + MU_RUN_TEST(iso14443_3a_7b_file_test); + + MU_RUN_TEST(mf_ultralight_file_test); + MU_RUN_TEST(mf_ultralight_ev1_11_file_test); + MU_RUN_TEST(mf_ultralight_ev1_h11_file_test); + MU_RUN_TEST(mf_ultralight_ev1_21_file_test); + MU_RUN_TEST(mf_ultralight_ev1_h21_file_test); + MU_RUN_TEST(mf_ultralight_ntag_203_file_test); + MU_RUN_TEST(mf_ultralight_ntag_213_file_test); + MU_RUN_TEST(mf_ultralight_ntag_215_file_test); + MU_RUN_TEST(mf_ultralight_ntag_216_file_test); + MU_RUN_TEST(mf_ultralight_ntag_i2c_1k_file_test); + MU_RUN_TEST(mf_ultralight_ntag_i2c_2k_file_test); + MU_RUN_TEST(mf_ultralight_ntag_i2c_plus_1k_file_test); + MU_RUN_TEST(mf_ultralight_ntag_i2c_plus_2k_file_test); + + MU_RUN_TEST(mf_classic_mini_file_test); + MU_RUN_TEST(mf_classic_1k_4b_file_test); + MU_RUN_TEST(mf_classic_1k_7b_file_test); + MU_RUN_TEST(mf_classic_4k_4b_file_test); + MU_RUN_TEST(mf_classic_4k_7b_file_test); MU_RUN_TEST(mf_classic_reader); - UNUSED(iso14443_3a_reader); - UNUSED(mf_ultralight_11_reader); - UNUSED(mf_ultralight_21_reader); - UNUSED(ntag_215_reader); - UNUSED(ntag_216_reader); - UNUSED(ntag_213_locked_reader); - - UNUSED(mf_ultralight_write); - - UNUSED(iso14443_3a_4b_file_test); - UNUSED(iso14443_3a_7b_file_test); - - UNUSED(mf_ultralight_file_test); - UNUSED(mf_ultralight_ev1_11_file_test); - UNUSED(mf_ultralight_ev1_h11_file_test); - UNUSED(mf_ultralight_ev1_21_file_test); - UNUSED(mf_ultralight_ev1_h21_file_test); - UNUSED(mf_ultralight_ntag_203_file_test); - UNUSED(mf_ultralight_ntag_213_file_test); - UNUSED(mf_ultralight_ntag_215_file_test); - UNUSED(mf_ultralight_ntag_216_file_test); - UNUSED(mf_ultralight_ntag_i2c_1k_file_test); - UNUSED(mf_ultralight_ntag_i2c_2k_file_test); - UNUSED(mf_ultralight_ntag_i2c_plus_1k_file_test); - UNUSED(mf_ultralight_ntag_i2c_plus_2k_file_test); - - UNUSED(mf_classic_mini_file_test); - UNUSED(mf_classic_1k_4b_file_test); - UNUSED(mf_classic_1k_7b_file_test); - UNUSED(mf_classic_4k_4b_file_test); - UNUSED(mf_classic_4k_7b_file_test); + MU_RUN_TEST(mf_classic_write); + MU_RUN_TEST(mf_classic_value_block); nfc_test_free(); } diff --git a/applications/debug/unit_tests/nfc/nfc_transport.c b/applications/debug/unit_tests/nfc/nfc_transport.c index bf8dce4ece48..fab6693db873 100644 --- a/applications/debug/unit_tests/nfc/nfc_transport.c +++ b/applications/debug/unit_tests/nfc/nfc_transport.c @@ -411,9 +411,11 @@ NfcError nfc_trx(Nfc* instance, const BitBuffer* tx_buffer, BitBuffer* rx_buffer // Tx furi_assert(furi_message_queue_put(listener_queue, &message, FuriWaitForever) == FuriStatusOk); // Rx - furi_assert(furi_message_queue_get(poller_queue, &message, FuriWaitForever) == FuriStatusOk); + FuriStatus status = furi_message_queue_get(poller_queue, &message, 50); - if(message.type == NfcMessageTypeTx) { + if(status == FuriStatusErrorTimeout) { + error = NfcErrorTimeout; + } else if(message.type == NfcMessageTypeTx) { bit_buffer_copy_bits(rx_buffer, message.data.data, message.data.data_bits); nfc_test_print( NfcTransportLogLevelWarning, "TAG", message.data.data, message.data.data_bits); diff --git a/applications/main/nfc/helpers/mfkey32_logger.c b/applications/main/nfc/helpers/mfkey32_logger.c new file mode 100644 index 000000000000..8024179f809f --- /dev/null +++ b/applications/main/nfc/helpers/mfkey32_logger.c @@ -0,0 +1,173 @@ +#include "mfkey32_logger.h" + +#include + +#include +#include +#include + +#define MFKEY32_LOGGER_MAX_NONCES_SAVED (100) + +typedef struct { + bool is_filled; + uint32_t cuid; + uint8_t sector_num; + MfClassicKeyType key_type; + uint32_t nt0; + uint32_t nr0; + uint32_t ar0; + uint32_t nt1; + uint32_t nr1; + uint32_t ar1; +} Mfkey32LoggerParams; + +ARRAY_DEF(Mfkey32LoggerParams, Mfkey32LoggerParams, M_POD_OPLIST); + +struct Mfkey32Logger { + uint32_t cuid; + Mfkey32LoggerParams_t params_arr; + size_t nonces_saves; + size_t params_collected; +}; + +Mfkey32Logger* mfkey32_logger_alloc(uint32_t cuid) { + Mfkey32Logger* instance = malloc(sizeof(Mfkey32Logger)); + instance->cuid = cuid; + Mfkey32LoggerParams_init(instance->params_arr); + + return instance; +} + +void mfkey32_logger_free(Mfkey32Logger* instance) { + furi_assert(instance); + furi_assert(instance->params_arr); + + Mfkey32LoggerParams_clear(instance->params_arr); + free(instance); +} + +static bool mfkey32_logger_add_nonce_to_existing_params( + Mfkey32Logger* instance, + MfClassicAuthContext* auth_context) { + bool nonce_added = false; + do { + if(Mfkey32LoggerParams_size(instance->params_arr) == 0) break; + + Mfkey32LoggerParams_it_t it; + for(Mfkey32LoggerParams_it(it, instance->params_arr); !Mfkey32LoggerParams_end_p(it); + Mfkey32LoggerParams_next(it)) { + Mfkey32LoggerParams* params = Mfkey32LoggerParams_ref(it); + if(params->is_filled) continue; + + uint8_t sector_num = mf_classic_get_sector_by_block(auth_context->block_num); + if(params->sector_num != sector_num) continue; + if(params->key_type != auth_context->key_type) continue; + + params->nt1 = nfc_util_bytes2num(auth_context->nt.data, sizeof(MfClassicNt)); + params->nr1 = nfc_util_bytes2num(auth_context->nr.data, sizeof(MfClassicNr)); + params->ar1 = nfc_util_bytes2num(auth_context->ar.data, sizeof(MfClassicAr)); + params->is_filled = true; + + instance->params_collected++; + nonce_added = true; + break; + } + + } while(false); + + return nonce_added; +} + +void mfkey32_logger_add_nonce(Mfkey32Logger* instance, MfClassicAuthContext* auth_context) { + furi_assert(instance); + furi_assert(auth_context); + + bool nonce_added = mfkey32_logger_add_nonce_to_existing_params(instance, auth_context); + if(!nonce_added && (instance->nonces_saves < MFKEY32_LOGGER_MAX_NONCES_SAVED)) { + uint8_t sector_num = mf_classic_get_sector_by_block(auth_context->block_num); + Mfkey32LoggerParams params = { + .is_filled = false, + .cuid = instance->cuid, + .sector_num = sector_num, + .key_type = auth_context->key_type, + .nt0 = nfc_util_bytes2num(auth_context->nt.data, sizeof(MfClassicNt)), + .nr0 = nfc_util_bytes2num(auth_context->nr.data, sizeof(MfClassicNr)), + .ar0 = nfc_util_bytes2num(auth_context->ar.data, sizeof(MfClassicAr)), + }; + Mfkey32LoggerParams_push_back(instance->params_arr, params); + instance->nonces_saves++; + } +} + +size_t mfkey32_logger_get_params_num(Mfkey32Logger* instance) { + furi_assert(instance); + + return instance->params_collected; +} + +bool mfkey32_logger_save_params(Mfkey32Logger* instance, const char* path) { + furi_assert(instance); + furi_assert(path); + furi_assert(instance->params_collected > 0); + furi_assert(instance->params_arr); + + bool params_saved = false; + Storage* storage = furi_record_open(RECORD_STORAGE); + Stream* stream = buffered_file_stream_alloc(storage); + FuriString* temp_str = furi_string_alloc(); + + do { + if(!buffered_file_stream_open(stream, path, FSAM_WRITE, FSOM_OPEN_APPEND)) break; + + bool params_write_success = true; + Mfkey32LoggerParams_it_t it; + for(Mfkey32LoggerParams_it(it, instance->params_arr); !Mfkey32LoggerParams_end_p(it); + Mfkey32LoggerParams_next(it)) { + Mfkey32LoggerParams* params = Mfkey32LoggerParams_ref(it); + if(!params->is_filled) continue; + furi_string_printf( + temp_str, + "Sec %d key %c cuid %08lx nt0 %08lx nr0 %08lx ar0 %08lx nt1 %08lx nr1 %08lx ar1 %08lx\n", + params->sector_num, + params->key_type == MfClassicKeyTypeA ? 'A' : 'B', + params->cuid, + params->nt0, + params->nr0, + params->ar0, + params->nt1, + params->nr1, + params->ar1); + if(!stream_write_string(stream, temp_str)) { + params_write_success = false; + break; + } + } + if(!params_write_success) break; + + params_saved = true; + } while(false); + + furi_string_free(temp_str); + buffered_file_stream_close(stream); + stream_free(stream); + furi_record_close(RECORD_STORAGE); + + return params_saved; +} + +void mfkey32_logger_get_params_data(Mfkey32Logger* instance, FuriString* str) { + furi_assert(instance); + furi_assert(str); + furi_assert(instance->params_collected > 0); + + furi_string_reset(str); + Mfkey32LoggerParams_it_t it; + for(Mfkey32LoggerParams_it(it, instance->params_arr); !Mfkey32LoggerParams_end_p(it); + Mfkey32LoggerParams_next(it)) { + Mfkey32LoggerParams* params = Mfkey32LoggerParams_ref(it); + if(!params->is_filled) continue; + + char key_char = params->key_type == MfClassicKeyTypeA ? 'A' : 'B'; + furi_string_cat_printf(str, "Sector %d, key %c\n", params->sector_num, key_char); + } +} diff --git a/applications/main/nfc/helpers/mfkey32_logger.h b/applications/main/nfc/helpers/mfkey32_logger.h new file mode 100644 index 000000000000..12b42e1fb516 --- /dev/null +++ b/applications/main/nfc/helpers/mfkey32_logger.h @@ -0,0 +1,25 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct Mfkey32Logger Mfkey32Logger; + +Mfkey32Logger* mfkey32_logger_alloc(uint32_t cuid); + +void mfkey32_logger_free(Mfkey32Logger* instance); + +void mfkey32_logger_add_nonce(Mfkey32Logger* instance, MfClassicAuthContext* auth_context); + +size_t mfkey32_logger_get_params_num(Mfkey32Logger* instance); + +bool mfkey32_logger_save_params(Mfkey32Logger* instance, const char* path); + +void mfkey32_logger_get_params_data(Mfkey32Logger* instance, FuriString* str); + +#ifdef __cplusplus +} +#endif diff --git a/applications/main/nfc/helpers/nfc_custom_event.h b/applications/main/nfc/helpers/nfc_custom_event.h index 9d09caf90114..b2dea6642cea 100644 --- a/applications/main/nfc/helpers/nfc_custom_event.h +++ b/applications/main/nfc/helpers/nfc_custom_event.h @@ -20,6 +20,7 @@ typedef enum { NfcCustomEventViewExit, NfcCustomEventWorkerExit, NfcCustomEventWorkerUpdate, + NfcCustomEventTimerExpired, NfcCustomEventByteInputDone, NfcCustomEventTextInputDone, NfcCustomEventDictAttackDone, diff --git a/applications/main/nfc/nfc_app_i.h b/applications/main/nfc/nfc_app_i.h index 8731edcdcc5e..280d93b281a2 100644 --- a/applications/main/nfc/nfc_app_i.h +++ b/applications/main/nfc/nfc_app_i.h @@ -29,6 +29,7 @@ #include "helpers/mf_ultralight_auth.h" #include "helpers/mf_dict.h" #include "helpers/nfc_supported_cards.h" +#include "helpers/mfkey32_logger.h" #include #include @@ -60,6 +61,9 @@ #define NFC_APP_EXTENSION ".nfc" #define NFC_APP_SHADOW_EXTENSION ".shd" +#define NFC_APP_MFKEY32_LOGS_FILE_NAME ".mfkey32.log" +#define NFC_APP_MFKEY32_LOGS_FILE_PATH NFC_APP_FOLDER "/" NFC_APP_MFKEY32_LOGS_FILE_NAME + typedef enum { NfcRpcStateIdle, NfcRpcStateEmulating, @@ -114,11 +118,13 @@ struct NfcApp { NfcMfClassicDictAttackContext mf_dict_context; FuriString* parsed_data; NfcSupportedCards* supported_cards; + Mfkey32Logger* mfkey32_logger; NfcDevice* nfc_device; Iso14443_3aData* iso14443_3a_edit_data; FuriString* file_path; FuriString* file_name; + FuriTimer* timer; }; typedef enum { diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index d6a6cbb827f0..a9482a483877 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -28,6 +28,9 @@ ADD_SCENE(nfc, mf_desfire_app, MfDesfireApp) ADD_SCENE(nfc, mf_classic_read_supported_card, MfClassicReadSupportedCard) ADD_SCENE(nfc, mf_classic_dict_attack, MfClassicDictAttack) +ADD_SCENE(nfc, mf_classic_detect_reader, MfClassicDetectReader) +ADD_SCENE(nfc, mf_classic_mfkey_nonces_info, MfClassicMfkeyNoncesInfo) +ADD_SCENE(nfc, mf_classic_mfkey_complete, MfClassicMfkeyComplete) ADD_SCENE(nfc, set_type, SetType) ADD_SCENE(nfc, set_sak, SetSak) diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_detect_reader.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_detect_reader.c new file mode 100644 index 000000000000..756544faf2ff --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_detect_reader.c @@ -0,0 +1,139 @@ +#include "../nfc_app_i.h" + +#include + +#define NFC_SCENE_DETECT_READER_PAIR_NONCES_MAX (10U) +#define NFC_SCENE_DETECT_READER_WAIT_NONCES_TIMEOUT_MS (1000) + +static const NotificationSequence sequence_detect_reader = { + &message_green_255, + &message_blue_255, + &message_do_not_reset, + NULL, +}; + +void nfc_scene_mf_classic_detect_reader_view_callback(void* context) { + NfcApp* instance = context; + + view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventViewExit); +} + +NfcCommand nfc_scene_mf_classic_detect_listener_callback(NfcGenericEvent event, void* context) { + furi_assert(context); + furi_assert(event.data); + furi_assert(event.protocol == NfcProtocolMfClassic); + + NfcApp* instance = context; + MfClassicListenerEvent* mfc_event = event.data; + + if(mfc_event->type == MfClassicListenerEventTypeAuthContextPartCollected) { + MfClassicAuthContext* auth_ctx = &mfc_event->data->auth_context; + mfkey32_logger_add_nonce(instance->mfkey32_logger, auth_ctx); + view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventWorkerUpdate); + } + + return NfcCommandContinue; +} + +void nfc_scene_mf_classic_timer_callback(void* context) { + NfcApp* instance = context; + + view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventTimerExpired); +} + +void nfc_scene_mf_classic_detect_reader_on_enter(void* context) { + NfcApp* instance = context; + + if(nfc_device_get_protocol(instance->nfc_device) == NfcProtocolInvalid) { + const Iso14443_3aData iso3_data = { + .uid_len = 7, + .uid = {0x04, 0x77, 0x70, 0x2A, 0x23, 0x4F, 0x80}, + .atqa = {0x44, 0x00}, + .sak = 0x08, + }; + MfClassicData* mfc_data = mf_classic_alloc(); + + mfc_data->type = MfClassicType4k; + iso14443_3a_copy(mfc_data->iso14443_3a_data, &iso3_data); + nfc_device_set_data(instance->nfc_device, NfcProtocolMfClassic, mfc_data); + + mf_classic_free(mfc_data); + } + + const Iso14443_3aData* iso3_data = + nfc_device_get_base_data(instance->nfc_device, NfcProtocolMfClassic); + uint32_t cuid = iso14443_3a_get_cuid(iso3_data); + + instance->mfkey32_logger = mfkey32_logger_alloc(cuid); + instance->timer = + furi_timer_alloc(nfc_scene_mf_classic_timer_callback, FuriTimerTypeOnce, instance); + + detect_reader_set_nonces_max(instance->detect_reader, NFC_SCENE_DETECT_READER_PAIR_NONCES_MAX); + detect_reader_set_callback( + instance->detect_reader, nfc_scene_mf_classic_detect_reader_view_callback, instance); + + notification_message(instance->notifications, &sequence_detect_reader); + + instance->listener = nfc_listener_alloc( + instance->nfc, + NfcProtocolMfClassic, + nfc_device_get_data(instance->nfc_device, NfcProtocolMfClassic)); + nfc_listener_start( + instance->listener, nfc_scene_mf_classic_detect_listener_callback, instance); + + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewDetectReader); +} + +bool nfc_scene_mf_classic_detect_reader_on_event(void* context, SceneManagerEvent event) { + NfcApp* instance = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventWorkerUpdate) { + furi_timer_stop(instance->timer); + notification_message(instance->notifications, &sequence_blink_start_cyan); + + size_t nonces_pairs = 2 * mfkey32_logger_get_params_num(instance->mfkey32_logger); + detect_reader_set_state(instance->detect_reader, DetectReaderStateReaderDetected); + detect_reader_set_nonces_collected(instance->detect_reader, nonces_pairs); + if(nonces_pairs >= NFC_SCENE_DETECT_READER_PAIR_NONCES_MAX) { + nfc_listener_stop(instance->listener); + nfc_listener_free(instance->listener); + detect_reader_set_state(instance->detect_reader, DetectReaderStateDone); + nfc_blink_stop(instance); + notification_message(instance->notifications, &sequence_single_vibro); + notification_message(instance->notifications, &sequence_set_green_255); + } else { + furi_timer_start(instance->timer, NFC_SCENE_DETECT_READER_WAIT_NONCES_TIMEOUT_MS); + } + consumed = true; + } else if(event.event == NfcCustomEventTimerExpired) { + detect_reader_set_state(instance->detect_reader, DetectReaderStateReaderLost); + nfc_blink_stop(instance); + notification_message(instance->notifications, &sequence_detect_reader); + } else if(event.event == NfcCustomEventViewExit) { + scene_manager_next_scene(instance->scene_manager, NfcSceneMfClassicMfkeyNoncesInfo); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeBack) { + nfc_listener_stop(instance->listener); + nfc_listener_free(instance->listener); + mfkey32_logger_free(instance->mfkey32_logger); + } + + return consumed; +} + +void nfc_scene_mf_classic_detect_reader_on_exit(void* context) { + NfcApp* instance = context; + + // Clear view + detect_reader_reset(instance->detect_reader); + + furi_timer_stop(instance->timer); + furi_timer_free(instance->timer); + + // Stop notifications + nfc_blink_stop(instance); + notification_message(instance->notifications, &sequence_reset_green); +} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_mfkey_complete.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_mfkey_complete.c new file mode 100644 index 000000000000..26c7aa918f78 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_mfkey_complete.c @@ -0,0 +1,58 @@ +#include "../nfc_app_i.h" + +void nfc_scene_mf_classic_mfkey_complete_callback( + GuiButtonType result, + InputType type, + void* context) { + NfcApp* instance = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(instance->view_dispatcher, result); + } +} + +void nfc_scene_mf_classic_mfkey_complete_on_enter(void* context) { + NfcApp* instance = context; + + widget_add_string_element( + instance->widget, 64, 0, AlignCenter, AlignTop, FontPrimary, "Complete!"); + widget_add_string_multiline_element( + instance->widget, + 64, + 32, + AlignCenter, + AlignCenter, + FontSecondary, + "Now use Mfkey32\nto extract keys"); + widget_add_button_element( + instance->widget, + GuiButtonTypeCenter, + "OK", + nfc_scene_mf_classic_mfkey_complete_callback, + instance); + + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewWidget); +} + +bool nfc_scene_mf_classic_mfkey_complete_on_event(void* context, SceneManagerEvent event) { + NfcApp* instance = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeCenter) { + consumed = scene_manager_search_and_switch_to_previous_scene( + instance->scene_manager, NfcSceneStart); + } + } else if(event.event == SceneManagerEventTypeBack) { + const uint32_t prev_scenes[] = {NfcSceneSavedMenu, NfcSceneStart}; + consumed = scene_manager_search_and_switch_to_previous_scene_one_of( + instance->scene_manager, prev_scenes, COUNT_OF(prev_scenes)); + } + + return consumed; +} + +void nfc_scene_mf_classic_mfkey_complete_on_exit(void* context) { + NfcApp* instance = context; + + widget_reset(instance->widget); +} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_mfkey_nonces_info.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_mfkey_nonces_info.c new file mode 100644 index 000000000000..44f3500a7808 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_mfkey_nonces_info.c @@ -0,0 +1,72 @@ +#include "../nfc_app_i.h" + +void nfc_scene_mf_classic_mfkey_nonces_info_callback( + GuiButtonType result, + InputType type, + void* context) { + NfcApp* instance = context; + + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(instance->view_dispatcher, result); + } +} + +void nfc_scene_mf_classic_mfkey_nonces_info_on_enter(void* context) { + NfcApp* instance = context; + + FuriString* temp_str = furi_string_alloc(); + + size_t mfkey_params_saved = mfkey32_logger_get_params_num(instance->mfkey32_logger); + furi_string_printf(temp_str, "Nonce pairs saved: %d\n", mfkey_params_saved); + widget_add_string_element( + instance->widget, 0, 0, AlignLeft, AlignTop, FontPrimary, furi_string_get_cstr(temp_str)); + widget_add_string_element( + instance->widget, 0, 12, AlignLeft, AlignTop, FontSecondary, "Authenticated sectors:"); + + mfkey32_logger_get_params_data(instance->mfkey32_logger, temp_str); + widget_add_text_scroll_element( + instance->widget, 0, 22, 128, 42, furi_string_get_cstr(temp_str)); + widget_add_button_element( + instance->widget, + GuiButtonTypeCenter, + "OK", + nfc_scene_mf_classic_mfkey_nonces_info_callback, + instance); + + furi_string_free(temp_str); + + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewWidget); +} + +bool nfc_scene_mf_classic_mfkey_nonces_info_on_event(void* context, SceneManagerEvent event) { + NfcApp* instance = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeCenter) { + if(mfkey32_logger_save_params( + instance->mfkey32_logger, NFC_APP_MFKEY32_LOGS_FILE_PATH)) { + scene_manager_next_scene(instance->scene_manager, NfcSceneMfClassicMfkeyComplete); + } else { + scene_manager_search_and_switch_to_previous_scene( + instance->scene_manager, NfcSceneStart); + } + consumed = true; + } + } else if(event.type == SceneManagerEventTypeBack) { + const uint32_t prev_scenes[] = {NfcSceneSavedMenu, NfcSceneStart}; + consumed = scene_manager_search_and_switch_to_previous_scene_one_of( + instance->scene_manager, prev_scenes, COUNT_OF(prev_scenes)); + } + + return consumed; +} + +void nfc_scene_mf_classic_mfkey_nonces_info_on_exit(void* context) { + NfcApp* instance = context; + + mfkey32_logger_free(instance->mfkey32_logger); + + // Clear view + widget_reset(instance->widget); +} diff --git a/applications/main/nfc/scenes/nfc_scene_start.c b/applications/main/nfc/scenes/nfc_scene_start.c index 1a487df630f0..771e9682e084 100644 --- a/applications/main/nfc/scenes/nfc_scene_start.c +++ b/applications/main/nfc/scenes/nfc_scene_start.c @@ -57,7 +57,7 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) { } else if(event.event == SubmenuIndexDetectReader) { scene_manager_set_scene_state( nfc->scene_manager, NfcSceneStart, SubmenuIndexDetectReader); - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicDetectReader); consumed = true; } else if(event.event == SubmenuIndexSaved) { // Save the scene state explicitly in each branch, so that diff --git a/applications/main/nfc/views/detect_reader.c b/applications/main/nfc/views/detect_reader.c index e5951beb2674..ebcda7caf1b7 100644 --- a/applications/main/nfc/views/detect_reader.c +++ b/applications/main/nfc/views/detect_reader.c @@ -163,7 +163,10 @@ void detect_reader_set_nonces_collected(DetectReader* detect_reader, uint16_t no with_view_model( detect_reader->view, DetectReaderViewModel * model, - { model->nonces = nonces_collected; }, + { + model->nonces = nonces_collected; + model->state = DetectReaderStateReaderDetected; + }, false); } diff --git a/applications/main/nfc_rpc/assets/compiled/main.pb.c b/applications/main/nfc_rpc/assets/compiled/main.pb.c index a9c4d20613c5..9b574c9d6f71 100644 --- a/applications/main/nfc_rpc/assets/compiled/main.pb.c +++ b/applications/main/nfc_rpc/assets/compiled/main.pb.c @@ -8,4 +8,9 @@ PB_BIND(Nfc_Empty, Nfc_Empty, AUTO) + PB_BIND(Nfc_Main, Nfc_Main, 2) + + + + diff --git a/applications/main/nfc_rpc/assets/compiled/main.pb.h b/applications/main/nfc_rpc/assets/compiled/main.pb.h index 6c85b126d8cb..130e4ca6a30e 100644 --- a/applications/main/nfc_rpc/assets/compiled/main.pb.h +++ b/applications/main/nfc_rpc/assets/compiled/main.pb.h @@ -18,8 +18,7 @@ typedef enum _Nfc_CommandStatus { Nfc_CommandStatus_ERROR = 1, /* *< Unknown error */ Nfc_CommandStatus_ERROR_NOT_IMPLEMENTED = 3, /* *< Command succesfully decoded, but not implemented (deprecated or not yet implemented) */ - Nfc_CommandStatus_ERROR_BUSY = - 4 /* *< Somebody took global lock, so not all commands are available */ + Nfc_CommandStatus_ERROR_BUSY = 4 /* *< Somebody took global lock, so not all commands are available */ } Nfc_CommandStatus; /* Struct definitions */ @@ -59,9 +58,16 @@ typedef struct _Nfc_Main { PB_MfClassic_AuthResponse mf_classic_auth_resp; PB_MfClassic_ReadBlockRequest mf_classic_read_block_req; PB_MfClassic_ReadBlockResponse mf_classic_read_block_resp; + PB_MfClassic_WriteBlockRequest mf_classic_write_block_req; + PB_MfClassic_WriteBlockResponse mf_classic_write_block_resp; + PB_MfClassic_ReadValueRequest mf_classic_read_value_req; + PB_MfClassic_ReadValueResponse mf_classic_read_value_resp; + PB_MfClassic_ChangeValueRequest mf_classic_change_value_req; + PB_MfClassic_ChangeValueResponse mf_classic_change_value_resp; } content; } Nfc_Main; + #ifdef __cplusplus extern "C" { #endif @@ -69,37 +75,27 @@ extern "C" { /* Helper constants for enums */ #define _Nfc_CommandStatus_MIN Nfc_CommandStatus_OK #define _Nfc_CommandStatus_MAX Nfc_CommandStatus_ERROR_BUSY -#define _Nfc_CommandStatus_ARRAYSIZE ((Nfc_CommandStatus)(Nfc_CommandStatus_ERROR_BUSY + 1)) +#define _Nfc_CommandStatus_ARRAYSIZE ((Nfc_CommandStatus)(Nfc_CommandStatus_ERROR_BUSY+1)) + #define Nfc_Main_command_status_ENUMTYPE Nfc_CommandStatus + /* Initializer values for message structs */ -#define Nfc_Empty_init_default \ - { 0 } -#define Nfc_Main_init_default \ - { \ - _Nfc_CommandStatus_MIN, {{NULL}, NULL}, 0, { \ - Nfc_Empty_init_default \ - } \ - } -#define Nfc_Empty_init_zero \ - { 0 } -#define Nfc_Main_init_zero \ - { \ - _Nfc_CommandStatus_MIN, {{NULL}, NULL}, 0, { \ - Nfc_Empty_init_zero \ - } \ - } +#define Nfc_Empty_init_default {0} +#define Nfc_Main_init_default {_Nfc_CommandStatus_MIN, {{NULL}, NULL}, 0, {Nfc_Empty_init_default}} +#define Nfc_Empty_init_zero {0} +#define Nfc_Main_init_zero {_Nfc_CommandStatus_MIN, {{NULL}, NULL}, 0, {Nfc_Empty_init_zero}} /* Field tags (for use in manual encoding/decoding) */ -#define Nfc_Main_command_status_tag 1 -#define Nfc_Main_empty_tag 2 -#define Nfc_Main_nfca_read_req_tag 3 -#define Nfc_Main_nfca_read_resp_tag 4 -#define Nfc_Main_nfca_emulate_start_req_tag 5 -#define Nfc_Main_nfca_emulate_start_resp_tag 6 -#define Nfc_Main_nfca_emulate_stop_req_tag 7 -#define Nfc_Main_nfca_emulate_stop_resp_tag 8 +#define Nfc_Main_command_status_tag 1 +#define Nfc_Main_empty_tag 2 +#define Nfc_Main_nfca_read_req_tag 3 +#define Nfc_Main_nfca_read_resp_tag 4 +#define Nfc_Main_nfca_emulate_start_req_tag 5 +#define Nfc_Main_nfca_emulate_start_resp_tag 6 +#define Nfc_Main_nfca_emulate_stop_req_tag 7 +#define Nfc_Main_nfca_emulate_stop_resp_tag 8 #define Nfc_Main_mf_ultralight_read_page_req_tag 9 #define Nfc_Main_mf_ultralight_read_page_resp_tag 10 #define Nfc_Main_mf_ultralight_read_version_req_tag 11 @@ -116,163 +112,58 @@ extern "C" { #define Nfc_Main_mf_ultralight_emulate_start_resp_tag 22 #define Nfc_Main_mf_ultralight_emulate_stop_req_tag 23 #define Nfc_Main_mf_ultralight_emulate_stop_resp_tag 24 -#define Nfc_Main_mf_classic_auth_req_tag 25 -#define Nfc_Main_mf_classic_auth_resp_tag 26 -#define Nfc_Main_mf_classic_read_block_req_tag 27 -#define Nfc_Main_mf_classic_read_block_resp_tag 28 +#define Nfc_Main_mf_classic_auth_req_tag 25 +#define Nfc_Main_mf_classic_auth_resp_tag 26 +#define Nfc_Main_mf_classic_read_block_req_tag 27 +#define Nfc_Main_mf_classic_read_block_resp_tag 28 +#define Nfc_Main_mf_classic_write_block_req_tag 29 +#define Nfc_Main_mf_classic_write_block_resp_tag 30 +#define Nfc_Main_mf_classic_read_value_req_tag 31 +#define Nfc_Main_mf_classic_read_value_resp_tag 32 +#define Nfc_Main_mf_classic_change_value_req_tag 33 +#define Nfc_Main_mf_classic_change_value_resp_tag 34 /* Struct field encoding specification for nanopb */ -#define Nfc_Empty_FIELDLIST(X, a) +#define Nfc_Empty_FIELDLIST(X, a) \ #define Nfc_Empty_CALLBACK NULL #define Nfc_Empty_DEFAULT NULL -#define Nfc_Main_FIELDLIST(X, a) \ - X(a, STATIC, SINGULAR, UENUM, command_status, 1) \ - X(a, STATIC, ONEOF, MSG_W_CB, (content, empty, content.empty), 2) \ - X(a, STATIC, ONEOF, MSG_W_CB, (content, nfca_read_req, content.nfca_read_req), 3) \ - X(a, STATIC, ONEOF, MSG_W_CB, (content, nfca_read_resp, content.nfca_read_resp), 4) \ - X(a, \ - STATIC, \ - ONEOF, \ - MSG_W_CB, \ - (content, nfca_emulate_start_req, content.nfca_emulate_start_req), \ - 5) \ - X(a, \ - STATIC, \ - ONEOF, \ - MSG_W_CB, \ - (content, nfca_emulate_start_resp, content.nfca_emulate_start_resp), \ - 6) \ - X(a, \ - STATIC, \ - ONEOF, \ - MSG_W_CB, \ - (content, nfca_emulate_stop_req, content.nfca_emulate_stop_req), \ - 7) \ - X(a, \ - STATIC, \ - ONEOF, \ - MSG_W_CB, \ - (content, nfca_emulate_stop_resp, content.nfca_emulate_stop_resp), \ - 8) \ - X(a, \ - STATIC, \ - ONEOF, \ - MSG_W_CB, \ - (content, mf_ultralight_read_page_req, content.mf_ultralight_read_page_req), \ - 9) \ - X(a, \ - STATIC, \ - ONEOF, \ - MSG_W_CB, \ - (content, mf_ultralight_read_page_resp, content.mf_ultralight_read_page_resp), \ - 10) \ - X(a, \ - STATIC, \ - ONEOF, \ - MSG_W_CB, \ - (content, mf_ultralight_read_version_req, content.mf_ultralight_read_version_req), \ - 11) \ - X(a, \ - STATIC, \ - ONEOF, \ - MSG_W_CB, \ - (content, mf_ultralight_read_version_resp, content.mf_ultralight_read_version_resp), \ - 12) \ - X(a, \ - STATIC, \ - ONEOF, \ - MSG_W_CB, \ - (content, mf_ultralight_write_page_req, content.mf_ultralight_write_page_req), \ - 13) \ - X(a, \ - STATIC, \ - ONEOF, \ - MSG_W_CB, \ - (content, mf_ultralight_write_page_resp, content.mf_ultralight_write_page_resp), \ - 14) \ - X(a, \ - STATIC, \ - ONEOF, \ - MSG_W_CB, \ - (content, mf_ultralight_read_signature_req, content.mf_ultralight_read_signature_req), \ - 15) \ - X(a, \ - STATIC, \ - ONEOF, \ - MSG_W_CB, \ - (content, mf_ultralight_read_signature_resp, content.mf_ultralight_read_signature_resp), \ - 16) \ - X(a, \ - STATIC, \ - ONEOF, \ - MSG_W_CB, \ - (content, mf_ultralight_read_counter_req, content.mf_ultralight_read_counter_req), \ - 17) \ - X(a, \ - STATIC, \ - ONEOF, \ - MSG_W_CB, \ - (content, mf_ultralight_read_counter_resp, content.mf_ultralight_read_counter_resp), \ - 18) \ - X(a, \ - STATIC, \ - ONEOF, \ - MSG_W_CB, \ - (content, mf_ultralight_read_tearing_flag_req, content.mf_ultralight_read_tearing_flag_req), \ - 19) \ - X(a, \ - STATIC, \ - ONEOF, \ - MSG_W_CB, \ - (content, \ - mf_ultralight_read_tearing_flag_resp, \ - content.mf_ultralight_read_tearing_flag_resp), \ - 20) \ - X(a, \ - STATIC, \ - ONEOF, \ - MSG_W_CB, \ - (content, mf_ultralight_emulate_start_req, content.mf_ultralight_emulate_start_req), \ - 21) \ - X(a, \ - STATIC, \ - ONEOF, \ - MSG_W_CB, \ - (content, mf_ultralight_emulate_start_resp, content.mf_ultralight_emulate_start_resp), \ - 22) \ - X(a, \ - STATIC, \ - ONEOF, \ - MSG_W_CB, \ - (content, mf_ultralight_emulate_stop_req, content.mf_ultralight_emulate_stop_req), \ - 23) \ - X(a, \ - STATIC, \ - ONEOF, \ - MSG_W_CB, \ - (content, mf_ultralight_emulate_stop_resp, content.mf_ultralight_emulate_stop_resp), \ - 24) \ - X(a, STATIC, ONEOF, MSG_W_CB, (content, mf_classic_auth_req, content.mf_classic_auth_req), 25) \ - X(a, \ - STATIC, \ - ONEOF, \ - MSG_W_CB, \ - (content, mf_classic_auth_resp, content.mf_classic_auth_resp), \ - 26) \ - X(a, \ - STATIC, \ - ONEOF, \ - MSG_W_CB, \ - (content, mf_classic_read_block_req, content.mf_classic_read_block_req), \ - 27) \ - X(a, \ - STATIC, \ - ONEOF, \ - MSG_W_CB, \ - (content, mf_classic_read_block_resp, content.mf_classic_read_block_resp), \ - 28) +#define Nfc_Main_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UENUM, command_status, 1) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,empty,content.empty), 2) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,nfca_read_req,content.nfca_read_req), 3) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,nfca_read_resp,content.nfca_read_resp), 4) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,nfca_emulate_start_req,content.nfca_emulate_start_req), 5) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,nfca_emulate_start_resp,content.nfca_emulate_start_resp), 6) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,nfca_emulate_stop_req,content.nfca_emulate_stop_req), 7) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,nfca_emulate_stop_resp,content.nfca_emulate_stop_resp), 8) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_page_req,content.mf_ultralight_read_page_req), 9) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_page_resp,content.mf_ultralight_read_page_resp), 10) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_version_req,content.mf_ultralight_read_version_req), 11) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_version_resp,content.mf_ultralight_read_version_resp), 12) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_write_page_req,content.mf_ultralight_write_page_req), 13) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_write_page_resp,content.mf_ultralight_write_page_resp), 14) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_signature_req,content.mf_ultralight_read_signature_req), 15) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_signature_resp,content.mf_ultralight_read_signature_resp), 16) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_counter_req,content.mf_ultralight_read_counter_req), 17) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_counter_resp,content.mf_ultralight_read_counter_resp), 18) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_tearing_flag_req,content.mf_ultralight_read_tearing_flag_req), 19) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_read_tearing_flag_resp,content.mf_ultralight_read_tearing_flag_resp), 20) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_emulate_start_req,content.mf_ultralight_emulate_start_req), 21) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_emulate_start_resp,content.mf_ultralight_emulate_start_resp), 22) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_emulate_stop_req,content.mf_ultralight_emulate_stop_req), 23) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_ultralight_emulate_stop_resp,content.mf_ultralight_emulate_stop_resp), 24) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_classic_auth_req,content.mf_classic_auth_req), 25) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_classic_auth_resp,content.mf_classic_auth_resp), 26) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_classic_read_block_req,content.mf_classic_read_block_req), 27) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_classic_read_block_resp,content.mf_classic_read_block_resp), 28) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_classic_write_block_req,content.mf_classic_write_block_req), 29) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_classic_write_block_resp,content.mf_classic_write_block_resp), 30) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_classic_read_value_req,content.mf_classic_read_value_req), 31) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_classic_read_value_resp,content.mf_classic_read_value_resp), 32) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_classic_change_value_req,content.mf_classic_change_value_req), 33) \ +X(a, STATIC, ONEOF, MSG_W_CB, (content,mf_classic_change_value_resp,content.mf_classic_change_value_resp), 34) #define Nfc_Main_CALLBACK NULL #define Nfc_Main_DEFAULT NULL #define Nfc_Main_content_empty_MSGTYPE Nfc_Empty @@ -285,32 +176,29 @@ extern "C" { #define Nfc_Main_content_mf_ultralight_read_page_req_MSGTYPE PB_MfUltralight_ReadPageRequest #define Nfc_Main_content_mf_ultralight_read_page_resp_MSGTYPE PB_MfUltralight_ReadPageResponse #define Nfc_Main_content_mf_ultralight_read_version_req_MSGTYPE PB_MfUltralight_ReadVersionRequest -#define Nfc_Main_content_mf_ultralight_read_version_resp_MSGTYPE \ - PB_MfUltralight_ReadVersionResponse +#define Nfc_Main_content_mf_ultralight_read_version_resp_MSGTYPE PB_MfUltralight_ReadVersionResponse #define Nfc_Main_content_mf_ultralight_write_page_req_MSGTYPE PB_MfUltralight_WritePageRequest #define Nfc_Main_content_mf_ultralight_write_page_resp_MSGTYPE PB_MfUltralight_WritePageResponse -#define Nfc_Main_content_mf_ultralight_read_signature_req_MSGTYPE \ - PB_MfUltralight_ReadSignatureRequest -#define Nfc_Main_content_mf_ultralight_read_signature_resp_MSGTYPE \ - PB_MfUltralight_ReadSignatureResponse +#define Nfc_Main_content_mf_ultralight_read_signature_req_MSGTYPE PB_MfUltralight_ReadSignatureRequest +#define Nfc_Main_content_mf_ultralight_read_signature_resp_MSGTYPE PB_MfUltralight_ReadSignatureResponse #define Nfc_Main_content_mf_ultralight_read_counter_req_MSGTYPE PB_MfUltralight_ReadCounterRequest -#define Nfc_Main_content_mf_ultralight_read_counter_resp_MSGTYPE \ - PB_MfUltralight_ReadCounterResponse -#define Nfc_Main_content_mf_ultralight_read_tearing_flag_req_MSGTYPE \ - PB_MfUltralight_ReadTearingFlagRequest -#define Nfc_Main_content_mf_ultralight_read_tearing_flag_resp_MSGTYPE \ - PB_MfUltralight_ReadTearingFlagResponse -#define Nfc_Main_content_mf_ultralight_emulate_start_req_MSGTYPE \ - PB_MfUltralight_EmulateStartRequest -#define Nfc_Main_content_mf_ultralight_emulate_start_resp_MSGTYPE \ - PB_MfUltralight_EmulateStartResponse +#define Nfc_Main_content_mf_ultralight_read_counter_resp_MSGTYPE PB_MfUltralight_ReadCounterResponse +#define Nfc_Main_content_mf_ultralight_read_tearing_flag_req_MSGTYPE PB_MfUltralight_ReadTearingFlagRequest +#define Nfc_Main_content_mf_ultralight_read_tearing_flag_resp_MSGTYPE PB_MfUltralight_ReadTearingFlagResponse +#define Nfc_Main_content_mf_ultralight_emulate_start_req_MSGTYPE PB_MfUltralight_EmulateStartRequest +#define Nfc_Main_content_mf_ultralight_emulate_start_resp_MSGTYPE PB_MfUltralight_EmulateStartResponse #define Nfc_Main_content_mf_ultralight_emulate_stop_req_MSGTYPE PB_MfUltralight_EmulateStopRequest -#define Nfc_Main_content_mf_ultralight_emulate_stop_resp_MSGTYPE \ - PB_MfUltralight_EmulateStopResponse +#define Nfc_Main_content_mf_ultralight_emulate_stop_resp_MSGTYPE PB_MfUltralight_EmulateStopResponse #define Nfc_Main_content_mf_classic_auth_req_MSGTYPE PB_MfClassic_AuthRequest #define Nfc_Main_content_mf_classic_auth_resp_MSGTYPE PB_MfClassic_AuthResponse #define Nfc_Main_content_mf_classic_read_block_req_MSGTYPE PB_MfClassic_ReadBlockRequest #define Nfc_Main_content_mf_classic_read_block_resp_MSGTYPE PB_MfClassic_ReadBlockResponse +#define Nfc_Main_content_mf_classic_write_block_req_MSGTYPE PB_MfClassic_WriteBlockRequest +#define Nfc_Main_content_mf_classic_write_block_resp_MSGTYPE PB_MfClassic_WriteBlockResponse +#define Nfc_Main_content_mf_classic_read_value_req_MSGTYPE PB_MfClassic_ReadValueRequest +#define Nfc_Main_content_mf_classic_read_value_resp_MSGTYPE PB_MfClassic_ReadValueResponse +#define Nfc_Main_content_mf_classic_change_value_req_MSGTYPE PB_MfClassic_ChangeValueRequest +#define Nfc_Main_content_mf_classic_change_value_resp_MSGTYPE PB_MfClassic_ChangeValueResponse extern const pb_msgdesc_t Nfc_Empty_msg; extern const pb_msgdesc_t Nfc_Main_msg; @@ -320,8 +208,8 @@ extern const pb_msgdesc_t Nfc_Main_msg; #define Nfc_Main_fields &Nfc_Main_msg /* Maximum encoded size of messages (where known) */ -#define Nfc_Empty_size 0 -#define Nfc_Main_size 2057 +#define Nfc_Empty_size 0 +#define Nfc_Main_size 2057 #ifdef __cplusplus } /* extern "C" */ diff --git a/applications/main/nfc_rpc/assets/compiled/mf_classic.pb.c b/applications/main/nfc_rpc/assets/compiled/mf_classic.pb.c index eb96ffe1657e..b58f0167f7e9 100644 --- a/applications/main/nfc_rpc/assets/compiled/mf_classic.pb.c +++ b/applications/main/nfc_rpc/assets/compiled/mf_classic.pb.c @@ -8,8 +8,34 @@ PB_BIND(PB_MfClassic_AuthRequest, PB_MfClassic_AuthRequest, AUTO) + PB_BIND(PB_MfClassic_AuthResponse, PB_MfClassic_AuthResponse, AUTO) + PB_BIND(PB_MfClassic_ReadBlockRequest, PB_MfClassic_ReadBlockRequest, AUTO) + PB_BIND(PB_MfClassic_ReadBlockResponse, PB_MfClassic_ReadBlockResponse, AUTO) + + +PB_BIND(PB_MfClassic_WriteBlockRequest, PB_MfClassic_WriteBlockRequest, AUTO) + + +PB_BIND(PB_MfClassic_WriteBlockResponse, PB_MfClassic_WriteBlockResponse, AUTO) + + +PB_BIND(PB_MfClassic_ReadValueRequest, PB_MfClassic_ReadValueRequest, AUTO) + + +PB_BIND(PB_MfClassic_ReadValueResponse, PB_MfClassic_ReadValueResponse, AUTO) + + +PB_BIND(PB_MfClassic_ChangeValueRequest, PB_MfClassic_ChangeValueRequest, AUTO) + + +PB_BIND(PB_MfClassic_ChangeValueResponse, PB_MfClassic_ChangeValueResponse, AUTO) + + + + + diff --git a/applications/main/nfc_rpc/assets/compiled/mf_classic.pb.h b/applications/main/nfc_rpc/assets/compiled/mf_classic.pb.h index dbc649cb0aa7..19edf9893acf 100644 --- a/applications/main/nfc_rpc/assets/compiled/mf_classic.pb.h +++ b/applications/main/nfc_rpc/assets/compiled/mf_classic.pb.h @@ -60,6 +60,45 @@ typedef struct _PB_MfClassic_ReadBlockResponse { PB_MfClassic_ReadBlockResponse_data_t data; } PB_MfClassic_ReadBlockResponse; +typedef PB_BYTES_ARRAY_T(6) PB_MfClassic_WriteBlockRequest_key_t; +typedef PB_BYTES_ARRAY_T(16) PB_MfClassic_WriteBlockRequest_data_t; +typedef struct _PB_MfClassic_WriteBlockRequest { + uint8_t block; + PB_MfClassic_WriteBlockRequest_key_t key; + PB_MfClassic_KeyType key_type; + PB_MfClassic_WriteBlockRequest_data_t data; +} PB_MfClassic_WriteBlockRequest; + +typedef struct _PB_MfClassic_WriteBlockResponse { + PB_MfClassic_Error error; +} PB_MfClassic_WriteBlockResponse; + +typedef PB_BYTES_ARRAY_T(6) PB_MfClassic_ReadValueRequest_key_t; +typedef struct _PB_MfClassic_ReadValueRequest { + uint8_t block; + PB_MfClassic_ReadValueRequest_key_t key; + PB_MfClassic_KeyType key_type; +} PB_MfClassic_ReadValueRequest; + +typedef struct _PB_MfClassic_ReadValueResponse { + PB_MfClassic_Error error; + int32_t value; +} PB_MfClassic_ReadValueResponse; + +typedef PB_BYTES_ARRAY_T(6) PB_MfClassic_ChangeValueRequest_key_t; +typedef struct _PB_MfClassic_ChangeValueRequest { + uint8_t block; + PB_MfClassic_ChangeValueRequest_key_t key; + PB_MfClassic_KeyType key_type; + int32_t data; +} PB_MfClassic_ChangeValueRequest; + +typedef struct _PB_MfClassic_ChangeValueResponse { + PB_MfClassic_Error error; + int32_t value; +} PB_MfClassic_ChangeValueResponse; + + #ifdef __cplusplus extern "C" { #endif @@ -67,11 +106,11 @@ extern "C" { /* Helper constants for enums */ #define _PB_MfClassic_Error_MIN PB_MfClassic_Error_None #define _PB_MfClassic_Error_MAX PB_MfClassic_Error_Timeout -#define _PB_MfClassic_Error_ARRAYSIZE ((PB_MfClassic_Error)(PB_MfClassic_Error_Timeout + 1)) +#define _PB_MfClassic_Error_ARRAYSIZE ((PB_MfClassic_Error)(PB_MfClassic_Error_Timeout+1)) #define _PB_MfClassic_KeyType_MIN PB_MfClassic_KeyType_KeyTypeA #define _PB_MfClassic_KeyType_MAX PB_MfClassic_KeyType_KeyTypeB -#define _PB_MfClassic_KeyType_ARRAYSIZE ((PB_MfClassic_KeyType)(PB_MfClassic_KeyType_KeyTypeB + 1)) +#define _PB_MfClassic_KeyType_ARRAYSIZE ((PB_MfClassic_KeyType)(PB_MfClassic_KeyType_KeyTypeB+1)) #define PB_MfClassic_AuthRequest_key_type_ENUMTYPE PB_MfClassic_KeyType @@ -82,117 +121,182 @@ extern "C" { #define PB_MfClassic_ReadBlockResponse_error_ENUMTYPE PB_MfClassic_Error +#define PB_MfClassic_WriteBlockRequest_key_type_ENUMTYPE PB_MfClassic_KeyType + +#define PB_MfClassic_WriteBlockResponse_error_ENUMTYPE PB_MfClassic_Error + +#define PB_MfClassic_ReadValueRequest_key_type_ENUMTYPE PB_MfClassic_KeyType + +#define PB_MfClassic_ReadValueResponse_error_ENUMTYPE PB_MfClassic_Error + +#define PB_MfClassic_ChangeValueRequest_key_type_ENUMTYPE PB_MfClassic_KeyType + +#define PB_MfClassic_ChangeValueResponse_error_ENUMTYPE PB_MfClassic_Error + + /* Initializer values for message structs */ -#define PB_MfClassic_AuthRequest_init_default \ - { 0, {0, {0}}, _PB_MfClassic_KeyType_MIN } -#define PB_MfClassic_AuthResponse_init_default \ - { \ - _PB_MfClassic_Error_MIN, 0, {0, {0}}, _PB_MfClassic_KeyType_MIN, {0, {0}}, {0, {0}}, \ - {0, {0}}, { \ - 0, { \ - 0 \ - } \ - } \ - } -#define PB_MfClassic_ReadBlockRequest_init_default \ - { 0, {0, {0}}, _PB_MfClassic_KeyType_MIN } -#define PB_MfClassic_ReadBlockResponse_init_default \ - { \ - _PB_MfClassic_Error_MIN, { \ - 0, { \ - 0 \ - } \ - } \ - } -#define PB_MfClassic_AuthRequest_init_zero \ - { 0, {0, {0}}, _PB_MfClassic_KeyType_MIN } -#define PB_MfClassic_AuthResponse_init_zero \ - { \ - _PB_MfClassic_Error_MIN, 0, {0, {0}}, _PB_MfClassic_KeyType_MIN, {0, {0}}, {0, {0}}, \ - {0, {0}}, { \ - 0, { \ - 0 \ - } \ - } \ - } -#define PB_MfClassic_ReadBlockRequest_init_zero \ - { 0, {0, {0}}, _PB_MfClassic_KeyType_MIN } -#define PB_MfClassic_ReadBlockResponse_init_zero \ - { \ - _PB_MfClassic_Error_MIN, { \ - 0, { \ - 0 \ - } \ - } \ - } +#define PB_MfClassic_AuthRequest_init_default {0, {0, {0}}, _PB_MfClassic_KeyType_MIN} +#define PB_MfClassic_AuthResponse_init_default {_PB_MfClassic_Error_MIN, 0, {0, {0}}, _PB_MfClassic_KeyType_MIN, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}} +#define PB_MfClassic_ReadBlockRequest_init_default {0, {0, {0}}, _PB_MfClassic_KeyType_MIN} +#define PB_MfClassic_ReadBlockResponse_init_default {_PB_MfClassic_Error_MIN, {0, {0}}} +#define PB_MfClassic_WriteBlockRequest_init_default {0, {0, {0}}, _PB_MfClassic_KeyType_MIN, {0, {0}}} +#define PB_MfClassic_WriteBlockResponse_init_default {_PB_MfClassic_Error_MIN} +#define PB_MfClassic_ReadValueRequest_init_default {0, {0, {0}}, _PB_MfClassic_KeyType_MIN} +#define PB_MfClassic_ReadValueResponse_init_default {_PB_MfClassic_Error_MIN, 0} +#define PB_MfClassic_ChangeValueRequest_init_default {0, {0, {0}}, _PB_MfClassic_KeyType_MIN, 0} +#define PB_MfClassic_ChangeValueResponse_init_default {_PB_MfClassic_Error_MIN, 0} +#define PB_MfClassic_AuthRequest_init_zero {0, {0, {0}}, _PB_MfClassic_KeyType_MIN} +#define PB_MfClassic_AuthResponse_init_zero {_PB_MfClassic_Error_MIN, 0, {0, {0}}, _PB_MfClassic_KeyType_MIN, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}} +#define PB_MfClassic_ReadBlockRequest_init_zero {0, {0, {0}}, _PB_MfClassic_KeyType_MIN} +#define PB_MfClassic_ReadBlockResponse_init_zero {_PB_MfClassic_Error_MIN, {0, {0}}} +#define PB_MfClassic_WriteBlockRequest_init_zero {0, {0, {0}}, _PB_MfClassic_KeyType_MIN, {0, {0}}} +#define PB_MfClassic_WriteBlockResponse_init_zero {_PB_MfClassic_Error_MIN} +#define PB_MfClassic_ReadValueRequest_init_zero {0, {0, {0}}, _PB_MfClassic_KeyType_MIN} +#define PB_MfClassic_ReadValueResponse_init_zero {_PB_MfClassic_Error_MIN, 0} +#define PB_MfClassic_ChangeValueRequest_init_zero {0, {0, {0}}, _PB_MfClassic_KeyType_MIN, 0} +#define PB_MfClassic_ChangeValueResponse_init_zero {_PB_MfClassic_Error_MIN, 0} /* Field tags (for use in manual encoding/decoding) */ -#define PB_MfClassic_AuthRequest_block_tag 1 -#define PB_MfClassic_AuthRequest_key_tag 2 -#define PB_MfClassic_AuthRequest_key_type_tag 3 -#define PB_MfClassic_AuthResponse_error_tag 1 -#define PB_MfClassic_AuthResponse_block_tag 2 -#define PB_MfClassic_AuthResponse_key_tag 3 -#define PB_MfClassic_AuthResponse_key_type_tag 4 -#define PB_MfClassic_AuthResponse_nt_tag 5 -#define PB_MfClassic_AuthResponse_nr_tag 6 -#define PB_MfClassic_AuthResponse_ar_tag 7 -#define PB_MfClassic_AuthResponse_at_tag 8 -#define PB_MfClassic_ReadBlockRequest_block_tag 1 -#define PB_MfClassic_ReadBlockRequest_key_tag 2 +#define PB_MfClassic_AuthRequest_block_tag 1 +#define PB_MfClassic_AuthRequest_key_tag 2 +#define PB_MfClassic_AuthRequest_key_type_tag 3 +#define PB_MfClassic_AuthResponse_error_tag 1 +#define PB_MfClassic_AuthResponse_block_tag 2 +#define PB_MfClassic_AuthResponse_key_tag 3 +#define PB_MfClassic_AuthResponse_key_type_tag 4 +#define PB_MfClassic_AuthResponse_nt_tag 5 +#define PB_MfClassic_AuthResponse_nr_tag 6 +#define PB_MfClassic_AuthResponse_ar_tag 7 +#define PB_MfClassic_AuthResponse_at_tag 8 +#define PB_MfClassic_ReadBlockRequest_block_tag 1 +#define PB_MfClassic_ReadBlockRequest_key_tag 2 #define PB_MfClassic_ReadBlockRequest_key_type_tag 3 #define PB_MfClassic_ReadBlockResponse_error_tag 1 -#define PB_MfClassic_ReadBlockResponse_data_tag 2 +#define PB_MfClassic_ReadBlockResponse_data_tag 2 +#define PB_MfClassic_WriteBlockRequest_block_tag 1 +#define PB_MfClassic_WriteBlockRequest_key_tag 2 +#define PB_MfClassic_WriteBlockRequest_key_type_tag 3 +#define PB_MfClassic_WriteBlockRequest_data_tag 4 +#define PB_MfClassic_WriteBlockResponse_error_tag 1 +#define PB_MfClassic_ReadValueRequest_block_tag 1 +#define PB_MfClassic_ReadValueRequest_key_tag 2 +#define PB_MfClassic_ReadValueRequest_key_type_tag 3 +#define PB_MfClassic_ReadValueResponse_error_tag 1 +#define PB_MfClassic_ReadValueResponse_value_tag 2 +#define PB_MfClassic_ChangeValueRequest_block_tag 1 +#define PB_MfClassic_ChangeValueRequest_key_tag 2 +#define PB_MfClassic_ChangeValueRequest_key_type_tag 3 +#define PB_MfClassic_ChangeValueRequest_data_tag 4 +#define PB_MfClassic_ChangeValueResponse_error_tag 1 +#define PB_MfClassic_ChangeValueResponse_value_tag 2 /* Struct field encoding specification for nanopb */ #define PB_MfClassic_AuthRequest_FIELDLIST(X, a) \ - X(a, STATIC, SINGULAR, UINT32, block, 1) \ - X(a, STATIC, SINGULAR, BYTES, key, 2) \ - X(a, STATIC, SINGULAR, UENUM, key_type, 3) +X(a, STATIC, SINGULAR, UINT32, block, 1) \ +X(a, STATIC, SINGULAR, BYTES, key, 2) \ +X(a, STATIC, SINGULAR, UENUM, key_type, 3) #define PB_MfClassic_AuthRequest_CALLBACK NULL #define PB_MfClassic_AuthRequest_DEFAULT NULL #define PB_MfClassic_AuthResponse_FIELDLIST(X, a) \ - X(a, STATIC, SINGULAR, UENUM, error, 1) \ - X(a, STATIC, SINGULAR, UINT32, block, 2) \ - X(a, STATIC, SINGULAR, BYTES, key, 3) \ - X(a, STATIC, SINGULAR, UENUM, key_type, 4) \ - X(a, STATIC, SINGULAR, BYTES, nt, 5) \ - X(a, STATIC, SINGULAR, BYTES, nr, 6) \ - X(a, STATIC, SINGULAR, BYTES, ar, 7) \ - X(a, STATIC, SINGULAR, BYTES, at, 8) +X(a, STATIC, SINGULAR, UENUM, error, 1) \ +X(a, STATIC, SINGULAR, UINT32, block, 2) \ +X(a, STATIC, SINGULAR, BYTES, key, 3) \ +X(a, STATIC, SINGULAR, UENUM, key_type, 4) \ +X(a, STATIC, SINGULAR, BYTES, nt, 5) \ +X(a, STATIC, SINGULAR, BYTES, nr, 6) \ +X(a, STATIC, SINGULAR, BYTES, ar, 7) \ +X(a, STATIC, SINGULAR, BYTES, at, 8) #define PB_MfClassic_AuthResponse_CALLBACK NULL #define PB_MfClassic_AuthResponse_DEFAULT NULL #define PB_MfClassic_ReadBlockRequest_FIELDLIST(X, a) \ - X(a, STATIC, SINGULAR, UINT32, block, 1) \ - X(a, STATIC, SINGULAR, BYTES, key, 2) \ - X(a, STATIC, SINGULAR, UENUM, key_type, 3) +X(a, STATIC, SINGULAR, UINT32, block, 1) \ +X(a, STATIC, SINGULAR, BYTES, key, 2) \ +X(a, STATIC, SINGULAR, UENUM, key_type, 3) #define PB_MfClassic_ReadBlockRequest_CALLBACK NULL #define PB_MfClassic_ReadBlockRequest_DEFAULT NULL #define PB_MfClassic_ReadBlockResponse_FIELDLIST(X, a) \ - X(a, STATIC, SINGULAR, UENUM, error, 1) \ - X(a, STATIC, SINGULAR, BYTES, data, 2) +X(a, STATIC, SINGULAR, UENUM, error, 1) \ +X(a, STATIC, SINGULAR, BYTES, data, 2) #define PB_MfClassic_ReadBlockResponse_CALLBACK NULL #define PB_MfClassic_ReadBlockResponse_DEFAULT NULL +#define PB_MfClassic_WriteBlockRequest_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UINT32, block, 1) \ +X(a, STATIC, SINGULAR, BYTES, key, 2) \ +X(a, STATIC, SINGULAR, UENUM, key_type, 3) \ +X(a, STATIC, SINGULAR, BYTES, data, 4) +#define PB_MfClassic_WriteBlockRequest_CALLBACK NULL +#define PB_MfClassic_WriteBlockRequest_DEFAULT NULL + +#define PB_MfClassic_WriteBlockResponse_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UENUM, error, 1) +#define PB_MfClassic_WriteBlockResponse_CALLBACK NULL +#define PB_MfClassic_WriteBlockResponse_DEFAULT NULL + +#define PB_MfClassic_ReadValueRequest_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UINT32, block, 1) \ +X(a, STATIC, SINGULAR, BYTES, key, 2) \ +X(a, STATIC, SINGULAR, UENUM, key_type, 3) +#define PB_MfClassic_ReadValueRequest_CALLBACK NULL +#define PB_MfClassic_ReadValueRequest_DEFAULT NULL + +#define PB_MfClassic_ReadValueResponse_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UENUM, error, 1) \ +X(a, STATIC, SINGULAR, INT32, value, 2) +#define PB_MfClassic_ReadValueResponse_CALLBACK NULL +#define PB_MfClassic_ReadValueResponse_DEFAULT NULL + +#define PB_MfClassic_ChangeValueRequest_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UINT32, block, 1) \ +X(a, STATIC, SINGULAR, BYTES, key, 2) \ +X(a, STATIC, SINGULAR, UENUM, key_type, 3) \ +X(a, STATIC, SINGULAR, INT32, data, 4) +#define PB_MfClassic_ChangeValueRequest_CALLBACK NULL +#define PB_MfClassic_ChangeValueRequest_DEFAULT NULL + +#define PB_MfClassic_ChangeValueResponse_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UENUM, error, 1) \ +X(a, STATIC, SINGULAR, INT32, value, 2) +#define PB_MfClassic_ChangeValueResponse_CALLBACK NULL +#define PB_MfClassic_ChangeValueResponse_DEFAULT NULL + extern const pb_msgdesc_t PB_MfClassic_AuthRequest_msg; extern const pb_msgdesc_t PB_MfClassic_AuthResponse_msg; extern const pb_msgdesc_t PB_MfClassic_ReadBlockRequest_msg; extern const pb_msgdesc_t PB_MfClassic_ReadBlockResponse_msg; +extern const pb_msgdesc_t PB_MfClassic_WriteBlockRequest_msg; +extern const pb_msgdesc_t PB_MfClassic_WriteBlockResponse_msg; +extern const pb_msgdesc_t PB_MfClassic_ReadValueRequest_msg; +extern const pb_msgdesc_t PB_MfClassic_ReadValueResponse_msg; +extern const pb_msgdesc_t PB_MfClassic_ChangeValueRequest_msg; +extern const pb_msgdesc_t PB_MfClassic_ChangeValueResponse_msg; /* Defines for backwards compatibility with code written before nanopb-0.4.0 */ #define PB_MfClassic_AuthRequest_fields &PB_MfClassic_AuthRequest_msg #define PB_MfClassic_AuthResponse_fields &PB_MfClassic_AuthResponse_msg #define PB_MfClassic_ReadBlockRequest_fields &PB_MfClassic_ReadBlockRequest_msg #define PB_MfClassic_ReadBlockResponse_fields &PB_MfClassic_ReadBlockResponse_msg +#define PB_MfClassic_WriteBlockRequest_fields &PB_MfClassic_WriteBlockRequest_msg +#define PB_MfClassic_WriteBlockResponse_fields &PB_MfClassic_WriteBlockResponse_msg +#define PB_MfClassic_ReadValueRequest_fields &PB_MfClassic_ReadValueRequest_msg +#define PB_MfClassic_ReadValueResponse_fields &PB_MfClassic_ReadValueResponse_msg +#define PB_MfClassic_ChangeValueRequest_fields &PB_MfClassic_ChangeValueRequest_msg +#define PB_MfClassic_ChangeValueResponse_fields &PB_MfClassic_ChangeValueResponse_msg /* Maximum encoded size of messages (where known) */ -#define PB_MfClassic_AuthRequest_size 13 -#define PB_MfClassic_AuthResponse_size 39 -#define PB_MfClassic_ReadBlockRequest_size 13 -#define PB_MfClassic_ReadBlockResponse_size 20 +#define PB_MfClassic_AuthRequest_size 13 +#define PB_MfClassic_AuthResponse_size 39 +#define PB_MfClassic_ChangeValueRequest_size 24 +#define PB_MfClassic_ChangeValueResponse_size 13 +#define PB_MfClassic_ReadBlockRequest_size 13 +#define PB_MfClassic_ReadBlockResponse_size 20 +#define PB_MfClassic_ReadValueRequest_size 13 +#define PB_MfClassic_ReadValueResponse_size 13 +#define PB_MfClassic_WriteBlockRequest_size 31 +#define PB_MfClassic_WriteBlockResponse_size 2 #ifdef __cplusplus } /* extern "C" */ diff --git a/applications/main/nfc_rpc/assets/compiled/mf_ultralight.pb.c b/applications/main/nfc_rpc/assets/compiled/mf_ultralight.pb.c index d509af5ac47e..a16a9020aaf3 100644 --- a/applications/main/nfc_rpc/assets/compiled/mf_ultralight.pb.c +++ b/applications/main/nfc_rpc/assets/compiled/mf_ultralight.pb.c @@ -8,32 +8,51 @@ PB_BIND(PB_MfUltralight_ReadPageRequest, PB_MfUltralight_ReadPageRequest, AUTO) + PB_BIND(PB_MfUltralight_ReadPageResponse, PB_MfUltralight_ReadPageResponse, AUTO) + PB_BIND(PB_MfUltralight_ReadVersionRequest, PB_MfUltralight_ReadVersionRequest, AUTO) + PB_BIND(PB_MfUltralight_ReadVersionResponse, PB_MfUltralight_ReadVersionResponse, AUTO) + PB_BIND(PB_MfUltralight_WritePageRequest, PB_MfUltralight_WritePageRequest, AUTO) + PB_BIND(PB_MfUltralight_WritePageResponse, PB_MfUltralight_WritePageResponse, AUTO) + PB_BIND(PB_MfUltralight_ReadSignatureRequest, PB_MfUltralight_ReadSignatureRequest, AUTO) + PB_BIND(PB_MfUltralight_ReadSignatureResponse, PB_MfUltralight_ReadSignatureResponse, AUTO) + PB_BIND(PB_MfUltralight_ReadCounterRequest, PB_MfUltralight_ReadCounterRequest, AUTO) + PB_BIND(PB_MfUltralight_ReadCounterResponse, PB_MfUltralight_ReadCounterResponse, AUTO) + PB_BIND(PB_MfUltralight_ReadTearingFlagRequest, PB_MfUltralight_ReadTearingFlagRequest, AUTO) + PB_BIND(PB_MfUltralight_ReadTearingFlagResponse, PB_MfUltralight_ReadTearingFlagResponse, AUTO) + PB_BIND(PB_MfUltralight_EmulateStartRequest, PB_MfUltralight_EmulateStartRequest, 2) + PB_BIND(PB_MfUltralight_EmulateStartResponse, PB_MfUltralight_EmulateStartResponse, AUTO) + PB_BIND(PB_MfUltralight_EmulateStopRequest, PB_MfUltralight_EmulateStopRequest, AUTO) + PB_BIND(PB_MfUltralight_EmulateStopResponse, PB_MfUltralight_EmulateStopResponse, AUTO) + + + + diff --git a/applications/main/nfc_rpc/assets/compiled/mf_ultralight.pb.h b/applications/main/nfc_rpc/assets/compiled/mf_ultralight.pb.h index 0754b98a5aa9..087ff3819553 100644 --- a/applications/main/nfc_rpc/assets/compiled/mf_ultralight.pb.h +++ b/applications/main/nfc_rpc/assets/compiled/mf_ultralight.pb.h @@ -106,6 +106,7 @@ typedef struct _PB_MfUltralight_EmulateStopResponse { PB_MfUltralight_Error error; } PB_MfUltralight_EmulateStopResponse; + #ifdef __cplusplus extern "C" { #endif @@ -113,162 +114,66 @@ extern "C" { /* Helper constants for enums */ #define _PB_MfUltralight_Error_MIN PB_MfUltralight_Error_None #define _PB_MfUltralight_Error_MAX PB_MfUltralight_Error_Timeout -#define _PB_MfUltralight_Error_ARRAYSIZE \ - ((PB_MfUltralight_Error)(PB_MfUltralight_Error_Timeout + 1)) +#define _PB_MfUltralight_Error_ARRAYSIZE ((PB_MfUltralight_Error)(PB_MfUltralight_Error_Timeout+1)) + #define PB_MfUltralight_ReadPageResponse_error_ENUMTYPE PB_MfUltralight_Error + #define PB_MfUltralight_ReadVersionResponse_error_ENUMTYPE PB_MfUltralight_Error + #define PB_MfUltralight_WritePageResponse_error_ENUMTYPE PB_MfUltralight_Error + #define PB_MfUltralight_ReadSignatureResponse_error_ENUMTYPE PB_MfUltralight_Error + #define PB_MfUltralight_ReadCounterResponse_error_ENUMTYPE PB_MfUltralight_Error + #define PB_MfUltralight_ReadTearingFlagResponse_error_ENUMTYPE PB_MfUltralight_Error + #define PB_MfUltralight_EmulateStartResponse_error_ENUMTYPE PB_MfUltralight_Error + #define PB_MfUltralight_EmulateStopResponse_error_ENUMTYPE PB_MfUltralight_Error + /* Initializer values for message structs */ -#define PB_MfUltralight_ReadPageRequest_init_default \ - { 0 } -#define PB_MfUltralight_ReadPageResponse_init_default \ - { \ - _PB_MfUltralight_Error_MIN, 0, { \ - 0, { \ - 0 \ - } \ - } \ - } -#define PB_MfUltralight_ReadVersionRequest_init_default \ - { 0 } -#define PB_MfUltralight_ReadVersionResponse_init_default \ - { _PB_MfUltralight_Error_MIN, 0, 0, 0, 0, 0, 0, 0, 0 } -#define PB_MfUltralight_WritePageRequest_init_default \ - { \ - 0, { \ - 0, { \ - 0 \ - } \ - } \ - } -#define PB_MfUltralight_WritePageResponse_init_default \ - { _PB_MfUltralight_Error_MIN, 0 } -#define PB_MfUltralight_ReadSignatureRequest_init_default \ - { 0 } -#define PB_MfUltralight_ReadSignatureResponse_init_default \ - { \ - _PB_MfUltralight_Error_MIN, { \ - 0, { \ - 0 \ - } \ - } \ - } -#define PB_MfUltralight_ReadCounterRequest_init_default \ - { 0 } -#define PB_MfUltralight_ReadCounterResponse_init_default \ - { \ - _PB_MfUltralight_Error_MIN, 0, { \ - 0, { \ - 0 \ - } \ - } \ - } -#define PB_MfUltralight_ReadTearingFlagRequest_init_default \ - { 0 } -#define PB_MfUltralight_ReadTearingFlagResponse_init_default \ - { \ - _PB_MfUltralight_Error_MIN, 0, { \ - 0, { \ - 0 \ - } \ - } \ - } -#define PB_MfUltralight_EmulateStartRequest_init_default \ - { \ - { \ - 0, { \ - 0 \ - } \ - } \ - } -#define PB_MfUltralight_EmulateStartResponse_init_default \ - { _PB_MfUltralight_Error_MIN } -#define PB_MfUltralight_EmulateStopRequest_init_default \ - { 0 } -#define PB_MfUltralight_EmulateStopResponse_init_default \ - { _PB_MfUltralight_Error_MIN } -#define PB_MfUltralight_ReadPageRequest_init_zero \ - { 0 } -#define PB_MfUltralight_ReadPageResponse_init_zero \ - { \ - _PB_MfUltralight_Error_MIN, 0, { \ - 0, { \ - 0 \ - } \ - } \ - } -#define PB_MfUltralight_ReadVersionRequest_init_zero \ - { 0 } -#define PB_MfUltralight_ReadVersionResponse_init_zero \ - { _PB_MfUltralight_Error_MIN, 0, 0, 0, 0, 0, 0, 0, 0 } -#define PB_MfUltralight_WritePageRequest_init_zero \ - { \ - 0, { \ - 0, { \ - 0 \ - } \ - } \ - } -#define PB_MfUltralight_WritePageResponse_init_zero \ - { _PB_MfUltralight_Error_MIN, 0 } -#define PB_MfUltralight_ReadSignatureRequest_init_zero \ - { 0 } -#define PB_MfUltralight_ReadSignatureResponse_init_zero \ - { \ - _PB_MfUltralight_Error_MIN, { \ - 0, { \ - 0 \ - } \ - } \ - } -#define PB_MfUltralight_ReadCounterRequest_init_zero \ - { 0 } -#define PB_MfUltralight_ReadCounterResponse_init_zero \ - { \ - _PB_MfUltralight_Error_MIN, 0, { \ - 0, { \ - 0 \ - } \ - } \ - } -#define PB_MfUltralight_ReadTearingFlagRequest_init_zero \ - { 0 } -#define PB_MfUltralight_ReadTearingFlagResponse_init_zero \ - { \ - _PB_MfUltralight_Error_MIN, 0, { \ - 0, { \ - 0 \ - } \ - } \ - } -#define PB_MfUltralight_EmulateStartRequest_init_zero \ - { \ - { \ - 0, { \ - 0 \ - } \ - } \ - } -#define PB_MfUltralight_EmulateStartResponse_init_zero \ - { _PB_MfUltralight_Error_MIN } -#define PB_MfUltralight_EmulateStopRequest_init_zero \ - { 0 } -#define PB_MfUltralight_EmulateStopResponse_init_zero \ - { _PB_MfUltralight_Error_MIN } +#define PB_MfUltralight_ReadPageRequest_init_default {0} +#define PB_MfUltralight_ReadPageResponse_init_default {_PB_MfUltralight_Error_MIN, 0, {0, {0}}} +#define PB_MfUltralight_ReadVersionRequest_init_default {0} +#define PB_MfUltralight_ReadVersionResponse_init_default {_PB_MfUltralight_Error_MIN, 0, 0, 0, 0, 0, 0, 0, 0} +#define PB_MfUltralight_WritePageRequest_init_default {0, {0, {0}}} +#define PB_MfUltralight_WritePageResponse_init_default {_PB_MfUltralight_Error_MIN, 0} +#define PB_MfUltralight_ReadSignatureRequest_init_default {0} +#define PB_MfUltralight_ReadSignatureResponse_init_default {_PB_MfUltralight_Error_MIN, {0, {0}}} +#define PB_MfUltralight_ReadCounterRequest_init_default {0} +#define PB_MfUltralight_ReadCounterResponse_init_default {_PB_MfUltralight_Error_MIN, 0, {0, {0}}} +#define PB_MfUltralight_ReadTearingFlagRequest_init_default {0} +#define PB_MfUltralight_ReadTearingFlagResponse_init_default {_PB_MfUltralight_Error_MIN, 0, {0, {0}}} +#define PB_MfUltralight_EmulateStartRequest_init_default {{0, {0}}} +#define PB_MfUltralight_EmulateStartResponse_init_default {_PB_MfUltralight_Error_MIN} +#define PB_MfUltralight_EmulateStopRequest_init_default {0} +#define PB_MfUltralight_EmulateStopResponse_init_default {_PB_MfUltralight_Error_MIN} +#define PB_MfUltralight_ReadPageRequest_init_zero {0} +#define PB_MfUltralight_ReadPageResponse_init_zero {_PB_MfUltralight_Error_MIN, 0, {0, {0}}} +#define PB_MfUltralight_ReadVersionRequest_init_zero {0} +#define PB_MfUltralight_ReadVersionResponse_init_zero {_PB_MfUltralight_Error_MIN, 0, 0, 0, 0, 0, 0, 0, 0} +#define PB_MfUltralight_WritePageRequest_init_zero {0, {0, {0}}} +#define PB_MfUltralight_WritePageResponse_init_zero {_PB_MfUltralight_Error_MIN, 0} +#define PB_MfUltralight_ReadSignatureRequest_init_zero {0} +#define PB_MfUltralight_ReadSignatureResponse_init_zero {_PB_MfUltralight_Error_MIN, {0, {0}}} +#define PB_MfUltralight_ReadCounterRequest_init_zero {0} +#define PB_MfUltralight_ReadCounterResponse_init_zero {_PB_MfUltralight_Error_MIN, 0, {0, {0}}} +#define PB_MfUltralight_ReadTearingFlagRequest_init_zero {0} +#define PB_MfUltralight_ReadTearingFlagResponse_init_zero {_PB_MfUltralight_Error_MIN, 0, {0, {0}}} +#define PB_MfUltralight_EmulateStartRequest_init_zero {{0, {0}}} +#define PB_MfUltralight_EmulateStartResponse_init_zero {_PB_MfUltralight_Error_MIN} +#define PB_MfUltralight_EmulateStopRequest_init_zero {0} +#define PB_MfUltralight_EmulateStopResponse_init_zero {_PB_MfUltralight_Error_MIN} /* Field tags (for use in manual encoding/decoding) */ #define PB_MfUltralight_ReadPageRequest_page_tag 1 @@ -303,97 +208,100 @@ extern "C" { #define PB_MfUltralight_EmulateStopResponse_error_tag 1 /* Struct field encoding specification for nanopb */ -#define PB_MfUltralight_ReadPageRequest_FIELDLIST(X, a) X(a, STATIC, SINGULAR, UINT32, page, 1) +#define PB_MfUltralight_ReadPageRequest_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UINT32, page, 1) #define PB_MfUltralight_ReadPageRequest_CALLBACK NULL #define PB_MfUltralight_ReadPageRequest_DEFAULT NULL #define PB_MfUltralight_ReadPageResponse_FIELDLIST(X, a) \ - X(a, STATIC, SINGULAR, UENUM, error, 1) \ - X(a, STATIC, SINGULAR, UINT32, page, 2) \ - X(a, STATIC, SINGULAR, BYTES, data, 3) +X(a, STATIC, SINGULAR, UENUM, error, 1) \ +X(a, STATIC, SINGULAR, UINT32, page, 2) \ +X(a, STATIC, SINGULAR, BYTES, data, 3) #define PB_MfUltralight_ReadPageResponse_CALLBACK NULL #define PB_MfUltralight_ReadPageResponse_DEFAULT NULL -#define PB_MfUltralight_ReadVersionRequest_FIELDLIST(X, a) +#define PB_MfUltralight_ReadVersionRequest_FIELDLIST(X, a) \ #define PB_MfUltralight_ReadVersionRequest_CALLBACK NULL #define PB_MfUltralight_ReadVersionRequest_DEFAULT NULL #define PB_MfUltralight_ReadVersionResponse_FIELDLIST(X, a) \ - X(a, STATIC, SINGULAR, UENUM, error, 1) \ - X(a, STATIC, SINGULAR, UINT32, header, 2) \ - X(a, STATIC, SINGULAR, UINT32, vendor_id, 3) \ - X(a, STATIC, SINGULAR, UINT32, prod_type, 4) \ - X(a, STATIC, SINGULAR, UINT32, prod_subtype, 5) \ - X(a, STATIC, SINGULAR, UINT32, prod_ver_major, 6) \ - X(a, STATIC, SINGULAR, UINT32, prod_ver_minor, 7) \ - X(a, STATIC, SINGULAR, UINT32, storage_size, 8) \ - X(a, STATIC, SINGULAR, UINT32, protocol_type, 9) +X(a, STATIC, SINGULAR, UENUM, error, 1) \ +X(a, STATIC, SINGULAR, UINT32, header, 2) \ +X(a, STATIC, SINGULAR, UINT32, vendor_id, 3) \ +X(a, STATIC, SINGULAR, UINT32, prod_type, 4) \ +X(a, STATIC, SINGULAR, UINT32, prod_subtype, 5) \ +X(a, STATIC, SINGULAR, UINT32, prod_ver_major, 6) \ +X(a, STATIC, SINGULAR, UINT32, prod_ver_minor, 7) \ +X(a, STATIC, SINGULAR, UINT32, storage_size, 8) \ +X(a, STATIC, SINGULAR, UINT32, protocol_type, 9) #define PB_MfUltralight_ReadVersionResponse_CALLBACK NULL #define PB_MfUltralight_ReadVersionResponse_DEFAULT NULL #define PB_MfUltralight_WritePageRequest_FIELDLIST(X, a) \ - X(a, STATIC, SINGULAR, UINT32, page, 1) \ - X(a, STATIC, SINGULAR, BYTES, data, 2) +X(a, STATIC, SINGULAR, UINT32, page, 1) \ +X(a, STATIC, SINGULAR, BYTES, data, 2) #define PB_MfUltralight_WritePageRequest_CALLBACK NULL #define PB_MfUltralight_WritePageRequest_DEFAULT NULL #define PB_MfUltralight_WritePageResponse_FIELDLIST(X, a) \ - X(a, STATIC, SINGULAR, UENUM, error, 1) \ - X(a, STATIC, SINGULAR, BOOL, result, 2) +X(a, STATIC, SINGULAR, UENUM, error, 1) \ +X(a, STATIC, SINGULAR, BOOL, result, 2) #define PB_MfUltralight_WritePageResponse_CALLBACK NULL #define PB_MfUltralight_WritePageResponse_DEFAULT NULL -#define PB_MfUltralight_ReadSignatureRequest_FIELDLIST(X, a) +#define PB_MfUltralight_ReadSignatureRequest_FIELDLIST(X, a) \ #define PB_MfUltralight_ReadSignatureRequest_CALLBACK NULL #define PB_MfUltralight_ReadSignatureRequest_DEFAULT NULL #define PB_MfUltralight_ReadSignatureResponse_FIELDLIST(X, a) \ - X(a, STATIC, SINGULAR, UENUM, error, 1) \ - X(a, STATIC, SINGULAR, BYTES, data, 2) +X(a, STATIC, SINGULAR, UENUM, error, 1) \ +X(a, STATIC, SINGULAR, BYTES, data, 2) #define PB_MfUltralight_ReadSignatureResponse_CALLBACK NULL #define PB_MfUltralight_ReadSignatureResponse_DEFAULT NULL #define PB_MfUltralight_ReadCounterRequest_FIELDLIST(X, a) \ - X(a, STATIC, SINGULAR, UINT32, counter_num, 1) +X(a, STATIC, SINGULAR, UINT32, counter_num, 1) #define PB_MfUltralight_ReadCounterRequest_CALLBACK NULL #define PB_MfUltralight_ReadCounterRequest_DEFAULT NULL #define PB_MfUltralight_ReadCounterResponse_FIELDLIST(X, a) \ - X(a, STATIC, SINGULAR, UENUM, error, 1) \ - X(a, STATIC, SINGULAR, UINT32, counter_num, 2) \ - X(a, STATIC, SINGULAR, BYTES, data, 3) +X(a, STATIC, SINGULAR, UENUM, error, 1) \ +X(a, STATIC, SINGULAR, UINT32, counter_num, 2) \ +X(a, STATIC, SINGULAR, BYTES, data, 3) #define PB_MfUltralight_ReadCounterResponse_CALLBACK NULL #define PB_MfUltralight_ReadCounterResponse_DEFAULT NULL #define PB_MfUltralight_ReadTearingFlagRequest_FIELDLIST(X, a) \ - X(a, STATIC, SINGULAR, UINT32, flag_num, 1) +X(a, STATIC, SINGULAR, UINT32, flag_num, 1) #define PB_MfUltralight_ReadTearingFlagRequest_CALLBACK NULL #define PB_MfUltralight_ReadTearingFlagRequest_DEFAULT NULL #define PB_MfUltralight_ReadTearingFlagResponse_FIELDLIST(X, a) \ - X(a, STATIC, SINGULAR, UENUM, error, 1) \ - X(a, STATIC, SINGULAR, UINT32, flag_num, 2) \ - X(a, STATIC, SINGULAR, BYTES, data, 3) +X(a, STATIC, SINGULAR, UENUM, error, 1) \ +X(a, STATIC, SINGULAR, UINT32, flag_num, 2) \ +X(a, STATIC, SINGULAR, BYTES, data, 3) #define PB_MfUltralight_ReadTearingFlagResponse_CALLBACK NULL #define PB_MfUltralight_ReadTearingFlagResponse_DEFAULT NULL -#define PB_MfUltralight_EmulateStartRequest_FIELDLIST(X, a) X(a, STATIC, SINGULAR, BYTES, data, 1) +#define PB_MfUltralight_EmulateStartRequest_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, BYTES, data, 1) #define PB_MfUltralight_EmulateStartRequest_CALLBACK NULL #define PB_MfUltralight_EmulateStartRequest_DEFAULT NULL #define PB_MfUltralight_EmulateStartResponse_FIELDLIST(X, a) \ - X(a, STATIC, SINGULAR, UENUM, error, 1) +X(a, STATIC, SINGULAR, UENUM, error, 1) #define PB_MfUltralight_EmulateStartResponse_CALLBACK NULL #define PB_MfUltralight_EmulateStartResponse_DEFAULT NULL -#define PB_MfUltralight_EmulateStopRequest_FIELDLIST(X, a) +#define PB_MfUltralight_EmulateStopRequest_FIELDLIST(X, a) \ #define PB_MfUltralight_EmulateStopRequest_CALLBACK NULL #define PB_MfUltralight_EmulateStopRequest_DEFAULT NULL -#define PB_MfUltralight_EmulateStopResponse_FIELDLIST(X, a) X(a, STATIC, SINGULAR, UENUM, error, 1) +#define PB_MfUltralight_EmulateStopResponse_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UENUM, error, 1) #define PB_MfUltralight_EmulateStopResponse_CALLBACK NULL #define PB_MfUltralight_EmulateStopResponse_DEFAULT NULL @@ -435,20 +343,20 @@ extern const pb_msgdesc_t PB_MfUltralight_EmulateStopResponse_msg; /* Maximum encoded size of messages (where known) */ #define PB_MfUltralight_EmulateStartRequest_size 2051 #define PB_MfUltralight_EmulateStartResponse_size 2 -#define PB_MfUltralight_EmulateStopRequest_size 0 +#define PB_MfUltralight_EmulateStopRequest_size 0 #define PB_MfUltralight_EmulateStopResponse_size 2 -#define PB_MfUltralight_ReadCounterRequest_size 6 +#define PB_MfUltralight_ReadCounterRequest_size 6 #define PB_MfUltralight_ReadCounterResponse_size 13 -#define PB_MfUltralight_ReadPageRequest_size 4 -#define PB_MfUltralight_ReadPageResponse_size 12 +#define PB_MfUltralight_ReadPageRequest_size 4 +#define PB_MfUltralight_ReadPageResponse_size 12 #define PB_MfUltralight_ReadSignatureRequest_size 0 #define PB_MfUltralight_ReadSignatureResponse_size 36 #define PB_MfUltralight_ReadTearingFlagRequest_size 6 #define PB_MfUltralight_ReadTearingFlagResponse_size 11 -#define PB_MfUltralight_ReadVersionRequest_size 0 +#define PB_MfUltralight_ReadVersionRequest_size 0 #define PB_MfUltralight_ReadVersionResponse_size 50 -#define PB_MfUltralight_WritePageRequest_size 10 -#define PB_MfUltralight_WritePageResponse_size 4 +#define PB_MfUltralight_WritePageRequest_size 10 +#define PB_MfUltralight_WritePageResponse_size 4 #ifdef __cplusplus } /* extern "C" */ diff --git a/applications/main/nfc_rpc/assets/compiled/nfca.pb.c b/applications/main/nfc_rpc/assets/compiled/nfca.pb.c index e7b784a5c25a..44e2f02579da 100644 --- a/applications/main/nfc_rpc/assets/compiled/nfca.pb.c +++ b/applications/main/nfc_rpc/assets/compiled/nfca.pb.c @@ -8,12 +8,21 @@ PB_BIND(PB_Nfca_ReadRequest, PB_Nfca_ReadRequest, AUTO) + PB_BIND(PB_Nfca_ReadResponse, PB_Nfca_ReadResponse, AUTO) + PB_BIND(PB_Nfca_EmulateStartRequest, PB_Nfca_EmulateStartRequest, AUTO) + PB_BIND(PB_Nfca_EmulateStartResponse, PB_Nfca_EmulateStartResponse, AUTO) + PB_BIND(PB_Nfca_EmulateStopRequest, PB_Nfca_EmulateStopRequest, AUTO) + PB_BIND(PB_Nfca_EmulateStopResponse, PB_Nfca_EmulateStopResponse, AUTO) + + + + diff --git a/applications/main/nfc_rpc/assets/compiled/nfca.pb.h b/applications/main/nfc_rpc/assets/compiled/nfca.pb.h index 349dab811cbe..df751cbd0c92 100644 --- a/applications/main/nfc_rpc/assets/compiled/nfca.pb.h +++ b/applications/main/nfc_rpc/assets/compiled/nfca.pb.h @@ -59,6 +59,7 @@ typedef struct _PB_Nfca_EmulateStopResponse { PB_Nfca_Error error; } PB_Nfca_EmulateStopResponse; + #ifdef __cplusplus extern "C" { #endif @@ -66,110 +67,80 @@ extern "C" { /* Helper constants for enums */ #define _PB_Nfca_Error_MIN PB_Nfca_Error_None #define _PB_Nfca_Error_MAX PB_Nfca_Error_Timeout -#define _PB_Nfca_Error_ARRAYSIZE ((PB_Nfca_Error)(PB_Nfca_Error_Timeout + 1)) +#define _PB_Nfca_Error_ARRAYSIZE ((PB_Nfca_Error)(PB_Nfca_Error_Timeout+1)) + #define PB_Nfca_ReadResponse_error_ENUMTYPE PB_Nfca_Error + #define PB_Nfca_EmulateStartResponse_error_ENUMTYPE PB_Nfca_Error + #define PB_Nfca_EmulateStopResponse_error_ENUMTYPE PB_Nfca_Error + /* Initializer values for message structs */ -#define PB_Nfca_ReadRequest_init_default \ - { 0 } -#define PB_Nfca_ReadResponse_init_default \ - { \ - _PB_Nfca_Error_MIN, 0, {0, {0}}, {0, {0}}, { \ - 0, { \ - 0 \ - } \ - } \ - } -#define PB_Nfca_EmulateStartRequest_init_default \ - { \ - 0, {0, {0}}, {0, {0}}, { \ - 0, { \ - 0 \ - } \ - } \ - } -#define PB_Nfca_EmulateStartResponse_init_default \ - { _PB_Nfca_Error_MIN } -#define PB_Nfca_EmulateStopRequest_init_default \ - { 0 } -#define PB_Nfca_EmulateStopResponse_init_default \ - { _PB_Nfca_Error_MIN } -#define PB_Nfca_ReadRequest_init_zero \ - { 0 } -#define PB_Nfca_ReadResponse_init_zero \ - { \ - _PB_Nfca_Error_MIN, 0, {0, {0}}, {0, {0}}, { \ - 0, { \ - 0 \ - } \ - } \ - } -#define PB_Nfca_EmulateStartRequest_init_zero \ - { \ - 0, {0, {0}}, {0, {0}}, { \ - 0, { \ - 0 \ - } \ - } \ - } -#define PB_Nfca_EmulateStartResponse_init_zero \ - { _PB_Nfca_Error_MIN } -#define PB_Nfca_EmulateStopRequest_init_zero \ - { 0 } -#define PB_Nfca_EmulateStopResponse_init_zero \ - { _PB_Nfca_Error_MIN } +#define PB_Nfca_ReadRequest_init_default {0} +#define PB_Nfca_ReadResponse_init_default {_PB_Nfca_Error_MIN, 0, {0, {0}}, {0, {0}}, {0, {0}}} +#define PB_Nfca_EmulateStartRequest_init_default {0, {0, {0}}, {0, {0}}, {0, {0}}} +#define PB_Nfca_EmulateStartResponse_init_default {_PB_Nfca_Error_MIN} +#define PB_Nfca_EmulateStopRequest_init_default {0} +#define PB_Nfca_EmulateStopResponse_init_default {_PB_Nfca_Error_MIN} +#define PB_Nfca_ReadRequest_init_zero {0} +#define PB_Nfca_ReadResponse_init_zero {_PB_Nfca_Error_MIN, 0, {0, {0}}, {0, {0}}, {0, {0}}} +#define PB_Nfca_EmulateStartRequest_init_zero {0, {0, {0}}, {0, {0}}, {0, {0}}} +#define PB_Nfca_EmulateStartResponse_init_zero {_PB_Nfca_Error_MIN} +#define PB_Nfca_EmulateStopRequest_init_zero {0} +#define PB_Nfca_EmulateStopResponse_init_zero {_PB_Nfca_Error_MIN} /* Field tags (for use in manual encoding/decoding) */ -#define PB_Nfca_ReadResponse_error_tag 1 -#define PB_Nfca_ReadResponse_uid_len_tag 2 -#define PB_Nfca_ReadResponse_uid_tag 3 -#define PB_Nfca_ReadResponse_sak_tag 4 -#define PB_Nfca_ReadResponse_atqa_tag 5 -#define PB_Nfca_EmulateStartRequest_uid_len_tag 1 -#define PB_Nfca_EmulateStartRequest_uid_tag 2 -#define PB_Nfca_EmulateStartRequest_sak_tag 3 -#define PB_Nfca_EmulateStartRequest_atqa_tag 4 -#define PB_Nfca_EmulateStartResponse_error_tag 1 -#define PB_Nfca_EmulateStopResponse_error_tag 1 +#define PB_Nfca_ReadResponse_error_tag 1 +#define PB_Nfca_ReadResponse_uid_len_tag 2 +#define PB_Nfca_ReadResponse_uid_tag 3 +#define PB_Nfca_ReadResponse_sak_tag 4 +#define PB_Nfca_ReadResponse_atqa_tag 5 +#define PB_Nfca_EmulateStartRequest_uid_len_tag 1 +#define PB_Nfca_EmulateStartRequest_uid_tag 2 +#define PB_Nfca_EmulateStartRequest_sak_tag 3 +#define PB_Nfca_EmulateStartRequest_atqa_tag 4 +#define PB_Nfca_EmulateStartResponse_error_tag 1 +#define PB_Nfca_EmulateStopResponse_error_tag 1 /* Struct field encoding specification for nanopb */ -#define PB_Nfca_ReadRequest_FIELDLIST(X, a) +#define PB_Nfca_ReadRequest_FIELDLIST(X, a) \ #define PB_Nfca_ReadRequest_CALLBACK NULL #define PB_Nfca_ReadRequest_DEFAULT NULL -#define PB_Nfca_ReadResponse_FIELDLIST(X, a) \ - X(a, STATIC, SINGULAR, UENUM, error, 1) \ - X(a, STATIC, SINGULAR, UINT32, uid_len, 2) \ - X(a, STATIC, SINGULAR, BYTES, uid, 3) \ - X(a, STATIC, SINGULAR, BYTES, sak, 4) \ - X(a, STATIC, SINGULAR, BYTES, atqa, 5) +#define PB_Nfca_ReadResponse_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UENUM, error, 1) \ +X(a, STATIC, SINGULAR, UINT32, uid_len, 2) \ +X(a, STATIC, SINGULAR, BYTES, uid, 3) \ +X(a, STATIC, SINGULAR, BYTES, sak, 4) \ +X(a, STATIC, SINGULAR, BYTES, atqa, 5) #define PB_Nfca_ReadResponse_CALLBACK NULL #define PB_Nfca_ReadResponse_DEFAULT NULL #define PB_Nfca_EmulateStartRequest_FIELDLIST(X, a) \ - X(a, STATIC, SINGULAR, UINT32, uid_len, 1) \ - X(a, STATIC, SINGULAR, BYTES, uid, 2) \ - X(a, STATIC, SINGULAR, BYTES, sak, 3) \ - X(a, STATIC, SINGULAR, BYTES, atqa, 4) +X(a, STATIC, SINGULAR, UINT32, uid_len, 1) \ +X(a, STATIC, SINGULAR, BYTES, uid, 2) \ +X(a, STATIC, SINGULAR, BYTES, sak, 3) \ +X(a, STATIC, SINGULAR, BYTES, atqa, 4) #define PB_Nfca_EmulateStartRequest_CALLBACK NULL #define PB_Nfca_EmulateStartRequest_DEFAULT NULL -#define PB_Nfca_EmulateStartResponse_FIELDLIST(X, a) X(a, STATIC, SINGULAR, UENUM, error, 1) +#define PB_Nfca_EmulateStartResponse_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UENUM, error, 1) #define PB_Nfca_EmulateStartResponse_CALLBACK NULL #define PB_Nfca_EmulateStartResponse_DEFAULT NULL -#define PB_Nfca_EmulateStopRequest_FIELDLIST(X, a) +#define PB_Nfca_EmulateStopRequest_FIELDLIST(X, a) \ #define PB_Nfca_EmulateStopRequest_CALLBACK NULL #define PB_Nfca_EmulateStopRequest_DEFAULT NULL -#define PB_Nfca_EmulateStopResponse_FIELDLIST(X, a) X(a, STATIC, SINGULAR, UENUM, error, 1) +#define PB_Nfca_EmulateStopResponse_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UENUM, error, 1) #define PB_Nfca_EmulateStopResponse_CALLBACK NULL #define PB_Nfca_EmulateStopResponse_DEFAULT NULL @@ -189,12 +160,12 @@ extern const pb_msgdesc_t PB_Nfca_EmulateStopResponse_msg; #define PB_Nfca_EmulateStopResponse_fields &PB_Nfca_EmulateStopResponse_msg /* Maximum encoded size of messages (where known) */ -#define PB_Nfca_EmulateStartRequest_size 25 -#define PB_Nfca_EmulateStartResponse_size 2 -#define PB_Nfca_EmulateStopRequest_size 0 -#define PB_Nfca_EmulateStopResponse_size 2 -#define PB_Nfca_ReadRequest_size 0 -#define PB_Nfca_ReadResponse_size 27 +#define PB_Nfca_EmulateStartRequest_size 25 +#define PB_Nfca_EmulateStartResponse_size 2 +#define PB_Nfca_EmulateStopRequest_size 0 +#define PB_Nfca_EmulateStopResponse_size 2 +#define PB_Nfca_ReadRequest_size 0 +#define PB_Nfca_ReadResponse_size 27 #ifdef __cplusplus } /* extern "C" */ diff --git a/applications/main/nfc_rpc/assets/protobuf/main.proto b/applications/main/nfc_rpc/assets/protobuf/main.proto index 115b7f40a654..1c9c3c73e9b8 100644 --- a/applications/main/nfc_rpc/assets/protobuf/main.proto +++ b/applications/main/nfc_rpc/assets/protobuf/main.proto @@ -54,5 +54,12 @@ message Main { .PB_MfClassic.AuthResponse mf_classic_auth_resp = 26; .PB_MfClassic.ReadBlockRequest mf_classic_read_block_req = 27; .PB_MfClassic.ReadBlockResponse mf_classic_read_block_resp = 28; + .PB_MfClassic.WriteBlockRequest mf_classic_write_block_req = 29; + .PB_MfClassic.WriteBlockResponse mf_classic_write_block_resp = 30; + .PB_MfClassic.ReadValueRequest mf_classic_read_value_req = 31; + .PB_MfClassic.ReadValueResponse mf_classic_read_value_resp = 32; + .PB_MfClassic.ChangeValueRequest mf_classic_change_value_req = 33; + .PB_MfClassic.ChangeValueResponse mf_classic_change_value_resp = 34; + } } diff --git a/applications/main/nfc_rpc/assets/protobuf/mf_classic.options b/applications/main/nfc_rpc/assets/protobuf/mf_classic.options index d6cd11ef9438..dad52776630b 100644 --- a/applications/main/nfc_rpc/assets/protobuf/mf_classic.options +++ b/applications/main/nfc_rpc/assets/protobuf/mf_classic.options @@ -1,6 +1,6 @@ -PB_MfClassic.AuthRequest.block int_size:IS_8 +PB_MfClassic.AuthRequest.block int_size:IS_8 PB_MfClassic.AuthRequest.key max_size: 6 -PB_MfClassic.AuthResponse.block int_size:IS_8 +PB_MfClassic.AuthResponse.block int_size:IS_8 PB_MfClassic.AuthResponse.key max_size: 6 PB_MfClassic.AuthResponse.nt max_size: 4 PB_MfClassic.AuthResponse.nr max_size: 4 @@ -9,3 +9,11 @@ PB_MfClassic.AuthResponse.at max_size: 4 PB_MfClassic.ReadBlockRequest.block int_size:IS_8 PB_MfClassic.ReadBlockRequest.key max_size: 6 PB_MfClassic.ReadBlockResponse.data max_size: 16 +PB_MfClassic.WriteBlockRequest.block int_size:IS_8 +PB_MfClassic.WriteBlockRequest.key max_size: 6 +PB_MfClassic.WriteBlockRequest.data max_size: 16 +PB_MfClassic.ReadValueRequest.block int_size:IS_8 +PB_MfClassic.ReadValueRequest.key max_size: 6 +PB_MfClassic.ChangeValueRequest.block int_size:IS_8 +PB_MfClassic.ChangeValueRequest.key max_size: 6 + diff --git a/applications/main/nfc_rpc/assets/protobuf/mf_classic.proto b/applications/main/nfc_rpc/assets/protobuf/mf_classic.proto index cce98380cfbc..c9e75e8c9ec7 100644 --- a/applications/main/nfc_rpc/assets/protobuf/mf_classic.proto +++ b/applications/main/nfc_rpc/assets/protobuf/mf_classic.proto @@ -43,3 +43,37 @@ message ReadBlockResponse { Error error = 1; bytes data = 2; } + +message WriteBlockRequest { + uint32 block = 1; + bytes key = 2; + KeyType key_type = 3; + bytes data = 4; +} + +message WriteBlockResponse { + Error error = 1; +} + +message ReadValueRequest { + uint32 block = 1; + bytes key = 2; + KeyType key_type = 3; +} + +message ReadValueResponse { + Error error = 1; + int32 value = 2; +} + +message ChangeValueRequest { + uint32 block = 1; + bytes key = 2; + KeyType key_type = 3; + int32 data = 4; +} + +message ChangeValueResponse { + Error error = 1; + int32 value = 2; +} diff --git a/applications/main/nfc_rpc/nfc_rpc_mf_classic.c b/applications/main/nfc_rpc/nfc_rpc_mf_classic.c index 5e0799c0e200..86227b455b69 100644 --- a/applications/main/nfc_rpc/nfc_rpc_mf_classic.c +++ b/applications/main/nfc_rpc/nfc_rpc_mf_classic.c @@ -100,6 +100,86 @@ static void nfc_rpc_mf_classic_read_block(Nfc_Main* cmd, void* context) { cmd->content.mf_classic_read_block_resp = pb_mf_classic_read_block_resp; } +static void nfc_rpc_mf_classic_write_block(Nfc_Main* cmd, void* context) { + furi_assert(cmd); + furi_assert(context); + + NfcRpc* instance = context; + PB_MfClassic_WriteBlockResponse pb_mf_classic_write_block_resp = + PB_MfClassic_WriteBlockResponse_init_default; + + PB_MfClassic_WriteBlockRequest* req = &cmd->content.mf_classic_write_block_req; + MfClassicKey key = {}; + memcpy(key.data, req->key.bytes, sizeof(MfClassicKey)); + MfClassicKeyType key_type = + (req->key_type == PB_MfClassic_KeyType_KeyTypeB) ? MfClassicKeyTypeB : MfClassicKeyTypeA; + MfClassicBlock block = {}; + memcpy(block.data, req->data.bytes, sizeof(MfClassicBlock)); + MfClassicError error = + mf_classic_poller_write_block(instance->nfc, req->block, &key, key_type, &block); + + cmd->command_status = Nfc_CommandStatus_OK; + cmd->which_content = Nfc_Main_mf_classic_write_block_resp_tag; + + pb_mf_classic_write_block_resp.error = nfc_rpc_mf_classic_process_error(error); + cmd->content.mf_classic_write_block_resp = pb_mf_classic_write_block_resp; +} + +static void nfc_rpc_mf_classic_read_value(Nfc_Main* cmd, void* context) { + furi_assert(cmd); + furi_assert(context); + + NfcRpc* instance = context; + PB_MfClassic_ReadValueResponse pb_mf_classic_read_value_resp = + PB_MfClassic_ReadValueResponse_init_default; + + PB_MfClassic_ReadValueRequest* req = &cmd->content.mf_classic_read_value_req; + MfClassicKey key = {}; + memcpy(key.data, req->key.bytes, sizeof(MfClassicKey)); + MfClassicKeyType key_type = + (req->key_type == PB_MfClassic_KeyType_KeyTypeB) ? MfClassicKeyTypeB : MfClassicKeyTypeA; + int32_t value = 0; + MfClassicError error = + mf_classic_poller_read_value(instance->nfc, req->block, &key, key_type, &value); + + cmd->command_status = Nfc_CommandStatus_OK; + cmd->which_content = Nfc_Main_mf_classic_read_value_resp_tag; + + pb_mf_classic_read_value_resp.error = nfc_rpc_mf_classic_process_error(error); + if(pb_mf_classic_read_value_resp.error == PB_MfClassic_Error_None) { + pb_mf_classic_read_value_resp.value = value; + } + cmd->content.mf_classic_read_value_resp = pb_mf_classic_read_value_resp; +} + +static void nfc_rpc_mf_classic_change_value(Nfc_Main* cmd, void* context) { + furi_assert(cmd); + furi_assert(context); + + NfcRpc* instance = context; + PB_MfClassic_ChangeValueResponse pb_mf_classic_change_value_resp = + PB_MfClassic_ChangeValueResponse_init_default; + + PB_MfClassic_ChangeValueRequest* req = &cmd->content.mf_classic_change_value_req; + MfClassicKey key = {}; + memcpy(key.data, req->key.bytes, sizeof(MfClassicKey)); + MfClassicKeyType key_type = + (req->key_type == PB_MfClassic_KeyType_KeyTypeB) ? MfClassicKeyTypeB : MfClassicKeyTypeA; + int32_t data = req->data; + int32_t new_value = 0; + MfClassicError error = mf_classic_poller_change_value( + instance->nfc, req->block, &key, key_type, data, &new_value); + + cmd->command_status = Nfc_CommandStatus_OK; + cmd->which_content = Nfc_Main_mf_classic_change_value_resp_tag; + + pb_mf_classic_change_value_resp.error = nfc_rpc_mf_classic_process_error(error); + if(pb_mf_classic_change_value_resp.error == PB_MfClassic_Error_None) { + pb_mf_classic_change_value_resp.value = new_value; + } + cmd->content.mf_classic_change_value_resp = pb_mf_classic_change_value_resp; +} + void nfc_rpc_mf_classic_alloc(void* context) { furi_assert(context); @@ -107,4 +187,10 @@ void nfc_rpc_mf_classic_alloc(void* context) { nfc_rpc_add_handler(instance, Nfc_Main_mf_classic_auth_req_tag, nfc_rpc_mf_classic_auth); nfc_rpc_add_handler( instance, Nfc_Main_mf_classic_read_block_req_tag, nfc_rpc_mf_classic_read_block); + nfc_rpc_add_handler( + instance, Nfc_Main_mf_classic_write_block_req_tag, nfc_rpc_mf_classic_write_block); + nfc_rpc_add_handler( + instance, Nfc_Main_mf_classic_read_value_req_tag, nfc_rpc_mf_classic_read_value); + nfc_rpc_add_handler( + instance, Nfc_Main_mf_classic_change_value_req_tag, nfc_rpc_mf_classic_change_value); } diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index e3b1310ca470..1a7bf934e683 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,+,34.3,, +Version,+,35.1,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -844,6 +844,7 @@ Function,-,f_hal_nfc_acquire,FHalNfcError, Function,-,f_hal_nfc_event_start,FHalNfcError, Function,-,f_hal_nfc_init,FHalNfcError, Function,-,f_hal_nfc_is_hal_ready,FHalNfcError, +Function,-,f_hal_nfc_listen_reset,FHalNfcError, Function,-,f_hal_nfc_listen_start,FHalNfcError, Function,-,f_hal_nfc_listener_disable_auto_col_res,FHalNfcError, Function,-,f_hal_nfc_listener_sleep,FHalNfcError, @@ -866,6 +867,8 @@ Function,-,f_hal_nfc_timer_fwt_start,void,uint32_t Function,-,f_hal_nfc_timer_fwt_stop,void, Function,-,f_hal_nfc_trx_reset,FHalNfcError, Function,-,f_hal_nfc_wait_event,FHalNfcEvent,uint32_t +Function,-,f_hal_nfca_listener_deinit,FHalNfcError, +Function,-,f_hal_nfca_listener_init,FHalNfcError, Function,-,f_hal_nfca_listener_tx_custom_parity,FHalNfcError,"const uint8_t*, const _Bool*, size_t" Function,-,f_hal_nfca_receive_sdd_frame,FHalNfcError,"uint8_t*, size_t, size_t*" Function,-,f_hal_nfca_send_sdd_frame,FHalNfcError,"const uint8_t*, size_t" @@ -1808,7 +1811,7 @@ Function,-,iso14443_3a_check_crc,_Bool,const BitBuffer* Function,-,iso14443_3a_copy,void,"Iso14443_3aData*, const Iso14443_3aData*" Function,-,iso14443_3a_free,void,Iso14443_3aData* Function,-,iso14443_3a_get_base_data,const Iso14443_3aData*,const Iso14443_3aData* -Function,-,iso14443_3a_get_cuid,uint32_t,Iso14443_3aData* +Function,-,iso14443_3a_get_cuid,uint32_t,const Iso14443_3aData* Function,-,iso14443_3a_get_device_name,const char*,"const Iso14443_3aData*, NfcDeviceNameType" Function,-,iso14443_3a_get_uid,const uint8_t*,"const Iso14443_3aData*, size_t*" Function,-,iso14443_3a_is_equal,_Bool,"const Iso14443_3aData*, const Iso14443_3aData*" @@ -1995,6 +1998,7 @@ Function,+,menu_get_view,View*,Menu* Function,+,menu_reset,void,Menu* Function,+,menu_set_selected_item,void,"Menu*, uint32_t" Function,+,mf_classic_alloc,MfClassicData*, +Function,+,mf_classic_block_to_value,_Bool,"const MfClassicBlock*, int32_t*, uint8_t*" Function,+,mf_classic_copy,void,"MfClassicData*, const MfClassicData*" Function,-,mf_classic_detect_protocol,_Bool,"Iso14443_3aData*, MfClassicType*" Function,+,mf_classic_free,void,MfClassicData* @@ -2017,12 +2021,14 @@ Function,+,mf_classic_is_equal,_Bool,"const MfClassicData*, const MfClassicData* Function,+,mf_classic_is_key_found,_Bool,"const MfClassicData*, uint8_t, MfClassicKeyType" Function,+,mf_classic_is_sector_read,_Bool,"const MfClassicData*, uint8_t" Function,-,mf_classic_is_sector_trailer,_Bool,uint8_t +Function,+,mf_classic_is_value_block,_Bool,"MfClassicData*, uint8_t" Function,+,mf_classic_load,_Bool,"MfClassicData*, FlipperFormat*, uint32_t" Function,+,mf_classic_reset,void,MfClassicData* Function,+,mf_classic_save,_Bool,"const MfClassicData*, FlipperFormat*" Function,-,mf_classic_set_block_read,void,"MfClassicData*, uint8_t, MfClassicBlock*" Function,-,mf_classic_set_key_found,void,"MfClassicData*, uint8_t, MfClassicKeyType, uint64_t" Function,-,mf_classic_set_key_not_found,void,"MfClassicData*, uint8_t, MfClassicKeyType" +Function,+,mf_classic_value_to_block,void,"int32_t, uint8_t, MfClassicBlock*" Function,+,mf_classic_verify,_Bool,"MfClassicData*, const FuriString*" Function,-,mkdtemp,char*,char* Function,-,mkostemp,int,"char*, int" diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc.c b/firmware/targets/f7/furi_hal/f_hal_nfc.c index 171ec4a85d06..70e33bf83376 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfc.c +++ b/firmware/targets/f7/furi_hal/f_hal_nfc.c @@ -339,6 +339,7 @@ FHalNfcError f_hal_nfc_set_mode(FHalNfcMode mode, FHalNfcBitrate bitrate) { st25r3916_change_reg_bits(handle, ST25R3916_REG_UNDERSHOOT_CONF1, 0xff, 0x40); st25r3916_change_reg_bits(handle, ST25R3916_REG_UNDERSHOOT_CONF2, 0xff, 0x03); } else if(mode == FHalNfcModeIso14443_3aListener) { + f_hal_nfca_listener_init(); st25r3916_write_reg( handle, ST25R3916_REG_OP_CONTROL, @@ -376,6 +377,7 @@ FHalNfcError f_hal_nfc_reset_mode() { // Set default value in mode register st25r3916_write_reg(handle, ST25R3916_REG_MODE, ST25R3916_REG_MODE_om0); st25r3916_clear_reg_bits(handle, ST25R3916_REG_AUX, ST25R3916_REG_AUX_no_crc_rx); + f_hal_nfca_listener_deinit(); return error; } @@ -521,6 +523,14 @@ FHalNfcError f_hal_nfc_listen_start() { return FHalNfcErrorNone; } +FHalNfcError f_hal_nfc_listen_reset() { + FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; + + st25r3916_direct_cmd(handle, ST25R3916_CMD_UNMASK_RECEIVE_DATA); + + return FHalNfcErrorNone; +} + FHalNfcError f_hal_nfc_listener_sleep() { FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; diff --git a/firmware/targets/f7/furi_hal/f_hal_nfca.c b/firmware/targets/f7/furi_hal/f_hal_nfca.c index 67e26b338438..fbd705663a16 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfca.c +++ b/firmware/targets/f7/furi_hal/f_hal_nfca.c @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include #define TAG "FuriHalNfcA" @@ -100,9 +100,26 @@ FHalNfcError st25r3916_write_pta_mem(handle, pt_memory, sizeof(pt_memory)); + return error; +} + +// TODO change this + +FHalNfcError f_hal_nfca_listener_init() { + furi_check(iso14443_3a_signal == NULL); + iso14443_3a_signal = iso14443_3a_signal_alloc(&gpio_spi_r_mosi); - return error; + return FHalNfcErrorNone; +} + +FHalNfcError f_hal_nfca_listener_deinit() { + if(iso14443_3a_signal) { + iso14443_3a_signal_free(iso14443_3a_signal); + iso14443_3a_signal = NULL; + } + + return FHalNfcErrorNone; } FHalNfcError f_hal_nfca_listener_tx_custom_parity( diff --git a/firmware/targets/f7/target.json b/firmware/targets/f7/target.json index e5fd21c1058d..0c083b68ddba 100644 --- a/firmware/targets/f7/target.json +++ b/firmware/targets/f7/target.json @@ -45,7 +45,6 @@ "flipper_application", "flipperformat", "toolbox", - "flipper7", - "nfc" + "flipper7" ] } \ No newline at end of file diff --git a/firmware/targets/furi_hal_include/f_hal_nfc.h b/firmware/targets/furi_hal_include/f_hal_nfc.h index 982b3b4083d0..9dccf1365319 100644 --- a/firmware/targets/furi_hal_include/f_hal_nfc.h +++ b/firmware/targets/furi_hal_include/f_hal_nfc.h @@ -52,6 +52,8 @@ typedef enum { FHalNfcModeNfcvPoller, FHalNfcModeNfcvListener, + + FHalNfcModeNum, } FHalNfcMode; typedef enum { @@ -123,6 +125,8 @@ FHalNfcError f_hal_nfc_trx_reset(); FHalNfcError f_hal_nfc_listen_start(); +FHalNfcError f_hal_nfc_listen_reset(); + FHalNfcError f_hal_nfc_listener_sleep(); FHalNfcError f_hal_nfc_listener_disable_auto_col_res(); @@ -153,6 +157,11 @@ FHalNfcError f_hal_nfca_send_sdd_frame(const uint8_t* tx_data, size_t tx_bits); FHalNfcError f_hal_nfca_receive_sdd_frame(uint8_t* rx_data, size_t rx_data_size, size_t* rx_bits); +// TODO virtual methods? +FHalNfcError f_hal_nfca_listener_init(); + +FHalNfcError f_hal_nfca_listener_deinit(); + FHalNfcError furi_hal_nfca_set_col_res_data(uint8_t* uid, uint8_t uid_len, uint8_t* atqa, uint8_t sak); diff --git a/lib/nfc/helpers/iso14443_3a_signal.c b/lib/digital_signal/presets/nfc/iso14443_3a_signal.c similarity index 100% rename from lib/nfc/helpers/iso14443_3a_signal.c rename to lib/digital_signal/presets/nfc/iso14443_3a_signal.c diff --git a/lib/nfc/helpers/iso14443_3a_signal.h b/lib/digital_signal/presets/nfc/iso14443_3a_signal.h similarity index 100% rename from lib/nfc/helpers/iso14443_3a_signal.h rename to lib/digital_signal/presets/nfc/iso14443_3a_signal.h diff --git a/lib/nfc/nfc.c b/lib/nfc/nfc.c index 60c65d681625..1090b412083c 100644 --- a/lib/nfc/nfc.c +++ b/lib/nfc/nfc.c @@ -90,6 +90,7 @@ static int32_t nfc_worker_listener(void* context) { NfcEventData event_data = {}; event_data.buffer = bit_buffer_alloc(NFC_MAX_BUFFER_SIZE); NfcEvent nfc_event = {.data = event_data}; + NfcCommand command = NfcCommandContinue; while(true) { FHalNfcEvent event = f_hal_nfc_wait_event(F_HAL_NFC_EVENT_WAIT_FOREVER); @@ -119,7 +120,12 @@ static int32_t nfc_worker_listener(void* context) { f_hal_nfc_poller_rx( instance->rx_buffer, sizeof(instance->rx_buffer), &instance->rx_bits); bit_buffer_copy_bits(event_data.buffer, instance->rx_buffer, instance->rx_bits); - instance->callback(nfc_event, instance->context); + command = instance->callback(nfc_event, instance->context); + if(command == NfcCommandStop) { + break; + } else if(command == NfcCommandReset) { + f_hal_nfc_listen_reset(); + } } } diff --git a/lib/nfc/nfc_device.c b/lib/nfc/nfc_device.c index 98054cb63000..344b34c77805 100644 --- a/lib/nfc/nfc_device.c +++ b/lib/nfc/nfc_device.c @@ -20,6 +20,7 @@ struct NfcDevice { NfcDevice* nfc_device_alloc() { NfcDevice* instance = malloc(sizeof(NfcDevice)); + instance->protocol = NfcProtocolInvalid; return instance; } @@ -33,11 +34,15 @@ void nfc_device_free(NfcDevice* instance) { void nfc_device_clear(NfcDevice* instance) { furi_assert(instance); - furi_assert(instance->protocol < NfcProtocolNum); - if(instance->protocol_data) { - nfc_devices[instance->protocol]->free(instance->protocol_data); - instance->protocol_data = NULL; + if(instance->protocol == NfcProtocolInvalid) { + furi_assert(instance->protocol_data == NULL); + } else if(instance->protocol < NfcProtocolNum) { + if(instance->protocol_data) { + nfc_devices[instance->protocol]->free(instance->protocol_data); + instance->protocol_data = NULL; + } + instance->protocol = NfcProtocolInvalid; } } diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a.c b/lib/nfc/protocols/iso14443_3a/iso14443_3a.c index 94739b5b70da..6ecc0d350644 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a.c +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a.c @@ -156,11 +156,11 @@ static uint16_t iso14443_3a_get_crc(const uint8_t* buff, uint16_t len) { return crc; } -uint32_t iso14443_3a_get_cuid(Iso14443_3aData* iso14443_3a_data) { +uint32_t iso14443_3a_get_cuid(const Iso14443_3aData* iso14443_3a_data) { furi_assert(iso14443_3a_data); uint32_t cuid = 0; - uint8_t* cuid_start = iso14443_3a_data->uid; + const uint8_t* cuid_start = iso14443_3a_data->uid; if(iso14443_3a_data->uid_len == 7) { cuid_start = &iso14443_3a_data->uid[3]; } diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a.h b/lib/nfc/protocols/iso14443_3a/iso14443_3a.h index 6873645ffc90..a1e93d24e79a 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a.h +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a.h @@ -83,7 +83,7 @@ const uint8_t* iso14443_3a_get_uid(const Iso14443_3aData* data, size_t* uid_len) const Iso14443_3aData* iso14443_3a_get_base_data(const Iso14443_3aData* data); -uint32_t iso14443_3a_get_cuid(Iso14443_3aData* iso14443_3a_data); +uint32_t iso14443_3a_get_cuid(const Iso14443_3aData* iso14443_3a_data); void iso14443_3a_append_crc(BitBuffer* buffer); diff --git a/lib/nfc/protocols/mf_classic/mf_classic.c b/lib/nfc/protocols/mf_classic/mf_classic.c index 7f1026a8289d..1f5c6dc34929 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic.c +++ b/lib/nfc/protocols/mf_classic/mf_classic.c @@ -444,6 +444,41 @@ uint8_t mf_classic_get_sector_by_block(uint8_t block) { return sector; } +bool mf_classic_block_to_value(const MfClassicBlock* block, int32_t* value, uint8_t* addr) { + furi_assert(block); + furi_assert(value); + + uint32_t v = *(uint32_t*)&block->data[0]; + uint32_t v_inv = *(uint32_t*)&block->data[4]; + uint32_t v1 = *(uint32_t*)&block->data[8]; + + bool val_checks = + ((v == v1) && (v == ~v_inv) && (block->data[12] == (~block->data[13] & 0xFF)) && + (block->data[14] == (~block->data[15] & 0xFF)) && (block->data[12] == block->data[14])); + if(value) { + *value = (int32_t)v; + } + if(addr) { + *addr = block->data[12]; + } + return val_checks; +} + +void mf_classic_value_to_block(int32_t value, uint8_t addr, MfClassicBlock* block) { + furi_assert(block); + + uint32_t v_inv = ~((uint32_t)value); + + memcpy(&block->data[0], &value, 4); //-V1086 + memcpy(&block->data[4], &v_inv, 4); //-V1086 + memcpy(&block->data[8], &value, 4); //-V1086 + + block->data[12] = addr; + block->data[13] = ~addr & 0xFF; + block->data[14] = addr; + block->data[15] = ~addr & 0xFF; +} + bool mf_classic_is_key_found( const MfClassicData* data, uint8_t sector_num, @@ -631,7 +666,7 @@ static bool mf_classic_is_allowed_access_sector_trailer( return true; } -static bool mifare_classic_is_allowed_access_data_block( +static bool mf_classic_is_allowed_access_data_block( MfClassicData* data, uint8_t block_num, MfClassicKeyType key_type, @@ -714,8 +749,20 @@ bool mf_classic_is_allowed_access( mf_classic_is_allowed_access_sector_trailer(data, block_num, key_type, action); } else { access_allowed = - mifare_classic_is_allowed_access_data_block(data, block_num, key_type, action); + mf_classic_is_allowed_access_data_block(data, block_num, key_type, action); } return access_allowed; } + +bool mf_classic_is_value_block(MfClassicData* data, uint8_t block_num) { + furi_assert(data); + + // Check if key A can write, if it can, it's transport configuration, not data block + return !mf_classic_is_allowed_access_data_block( + data, block_num, MfClassicKeyTypeA, MfClassicActionDataWrite) && + (mf_classic_is_allowed_access_data_block( + data, block_num, MfClassicKeyTypeB, MfClassicActionDataInc) || + mf_classic_is_allowed_access_data_block( + data, block_num, MfClassicKeyTypeB, MfClassicActionDataDec)); +} diff --git a/lib/nfc/protocols/mf_classic/mf_classic.h b/lib/nfc/protocols/mf_classic/mf_classic.h index b0fa14b063aa..0601042dfe53 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic.h +++ b/lib/nfc/protocols/mf_classic/mf_classic.h @@ -9,6 +9,12 @@ extern "C" { #define MF_CLASSIC_CMD_AUTH_KEY_A (0x60U) #define MF_CLASSIC_CMD_AUTH_KEY_B (0x61U) #define MF_CLASSIC_CMD_READ_BLOCK (0x30U) +#define MF_CLASSIC_CMD_WRITE_BLOCK (0xA0U) +#define MF_CLASSIC_CMD_VALUE_DEC (0xC0U) +#define MF_CLASSIC_CMD_VALUE_INC (0xC1U) +#define MF_CLASSIC_CMD_VALUE_RESTORE (0xC2U) +#define MF_CLASSIC_CMD_VALUE_TRANSFER (0xB0U) + #define MF_CLASSIC_CMD_HALT_MSB (0x50) #define MF_CLASSIC_CMD_HALT_LSB (0x00) #define MF_CLASSIC_CMD_ACK (0x0A) @@ -56,6 +62,14 @@ typedef enum { MfClassicActionACWrite, } MfClassicAction; +typedef enum { + MfClassicValueCommandIncrement, + MfClassicValueCommandDecrement, + MfClassicValueCommandRestore, + + MfClassicValueCommandInvalid, +} MfClassicValueCommand; + typedef struct { uint8_t data[MF_CLASSIC_BLOCK_SIZE]; } MfClassicBlock; @@ -166,6 +180,12 @@ bool mf_classic_is_sector_trailer(uint8_t block); uint8_t mf_classic_get_sector_by_block(uint8_t block); +bool mf_classic_is_value_block(MfClassicData* data, uint8_t block_num); + +bool mf_classic_block_to_value(const MfClassicBlock* block, int32_t* value, uint8_t* addr); + +void mf_classic_value_to_block(int32_t value, uint8_t addr, MfClassicBlock* block); + bool mf_classic_is_key_found( const MfClassicData* data, uint8_t sector_num, diff --git a/lib/nfc/protocols/mf_classic/mf_classic_listener.c b/lib/nfc/protocols/mf_classic/mf_classic_listener.c index ee9cd76133e4..4ca586f56869 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_listener.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_listener.c @@ -10,13 +10,14 @@ #define MF_CLASSIC_MAX_BUFF_SIZE (64) typedef MfClassicListenerCommand ( - *MfClassicListenerCommandCallback)(MfClassicListener* instance, BitBuffer* buf); + *MfClassicListenerCommandHandler)(MfClassicListener* instance, BitBuffer* buf); typedef struct { - uint8_t cmd; + uint8_t cmd_start_byte; size_t cmd_len_bits; - MfClassicListenerCommandCallback callback; -} MfClassicListenerCmdHandler; + size_t command_num; + MfClassicListenerCommandHandler* handler; +} MfClassicListenerCmd; static void mf_classic_listener_prepare_emulation(MfClassicListener* instance) { instance->total_block_num = mf_classic_get_total_block_num(instance->data->type); @@ -28,7 +29,10 @@ static void mf_classic_listener_reset_state(MfClassicListener* instance) { instance->comm_state = MfClassicListenerCommStatePlain; instance->state = MfClassicListenerStateIdle; instance->auth_state = MfClassicListenerAuthStateIdle; - instance->cmd_type = MfClassicListenerCommandTypeOnePart; + instance->cmd_in_progress = false; + instance->current_cmd_handler_idx = 0; + instance->transfer_value = 0; + instance->value_cmd = MfClassicValueCommandInvalid; } static MfClassicListenerCommand @@ -55,10 +59,6 @@ static MfClassicListenerCommand mf_classic_listnener_auth_first_part_handler( } uint8_t sector_num = mf_classic_get_sector_by_block(block_num); - if(!mf_classic_is_key_found(instance->data, sector_num, key_type)) { - command = MfClassicListenerCommandSilent; - break; - } MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(instance->data, sector_num); @@ -97,9 +97,9 @@ static MfClassicListenerCommand mf_classic_listnener_auth_first_part_handler( command = MfClassicListenerCommandProcessed; } + instance->cmd_in_progress = true; + instance->current_cmd_handler_idx++; instance->auth_state = MfClassicListenerAuthStateStarted; - instance->cmd_type = MfClassicListenerCommandTypeTwoParts; - instance->second_part = MfClassicListenerCommandSecondPartAuth; } while(false); return command; @@ -126,6 +126,8 @@ static MfClassicListenerCommand MfClassicListenerCommand command = MfClassicListenerCommandSilent; do { + instance->cmd_in_progress = false; + if(bit_buffer_get_size_bytes(buff) != (sizeof(MfClassicNr) + sizeof(MfClassicAr))) { mf_classic_listener_reset_state(instance); break; @@ -133,6 +135,13 @@ static MfClassicListenerCommand bit_buffer_write_bytes_mid(buff, instance->auth_context.nr.data, 0, sizeof(MfClassicNr)); bit_buffer_write_bytes_mid( buff, instance->auth_context.ar.data, sizeof(MfClassicNr), sizeof(MfClassicAr)); + + if(instance->callback) { + instance->mfc_event.type = MfClassicListenerEventTypeAuthContextPartCollected, + instance->mfc_event_data.auth_context = instance->auth_context; + instance->callback(instance->generic_event, instance->context); + } + uint32_t nr_num = nfc_util_bytes2num(instance->auth_context.nr.data, sizeof(MfClassicNr)); uint32_t ar_num = nfc_util_bytes2num(instance->auth_context.ar.data, sizeof(MfClassicAr)); @@ -158,9 +167,9 @@ static MfClassicListenerCommand instance->auth_state = MfClassicListenerAuthStateIdle; instance->state = MfClassicListenerStateAuthComplete; instance->comm_state = MfClassicListenerCommStateEncrypted; - instance->cmd_type = MfClassicListenerCommandTypeOnePart; if(instance->callback) { + instance->mfc_event.type = MfClassicListenerEventTypeAuthContextFullCollected, instance->mfc_event_data.auth_context = instance->auth_context; instance->callback(instance->generic_event, instance->context); } @@ -175,6 +184,8 @@ static MfClassicListenerCommand MfClassicAuthContext* auth_ctx = &instance->auth_context; do { + if(instance->state != MfClassicListenerStateAuthComplete) break; + uint8_t block_num = bit_buffer_get_byte(buff, 1); uint8_t sector_num = mf_classic_get_sector_by_block(block_num); uint8_t auth_sector_num = mf_classic_get_sector_by_block(auth_ctx->block_num); @@ -214,92 +225,284 @@ static MfClassicListenerCommand return command; } -static const MfClassicListenerCmdHandler mf_classic_cmd_first_part[] = { - { - .cmd = MF_CLASSIC_CMD_HALT_MSB, - .cmd_len_bits = 4 * 8, - .callback = mf_classic_listener_halt_handler, - }, - { - .cmd = MF_CLASSIC_CMD_AUTH_KEY_A, - .cmd_len_bits = 2 * 8, - .callback = mf_classic_listener_auth_key_a_handler, - }, - { - .cmd = MF_CLASSIC_CMD_AUTH_KEY_B, - .cmd_len_bits = 2 * 8, - .callback = mf_classic_listener_auth_key_b_handler, - }, - { - .cmd = MF_CLASSIC_CMD_READ_BLOCK, - .cmd_len_bits = 4 * 8, - .callback = mf_classic_listener_read_block_handler, - }, -}; +static MfClassicListenerCommand mf_classic_listener_write_block_first_part_handler( + MfClassicListener* instance, + BitBuffer* buff) { + MfClassicListenerCommand command = MfClassicListenerCommandNack; + MfClassicAuthContext* auth_ctx = &instance->auth_context; -static const MfClassicListenerCmdHandler - mf_classic_cmd_second_part[MfClassicListenerCommandSecondPartNum] = { - [MfClassicListenerCommandSecondPartAuth] = - { - .callback = mf_classic_listener_auth_second_part_handler, - }, -}; + do { + if(instance->state != MfClassicListenerStateAuthComplete) break; -MfClassicListener* - mf_classic_listener_alloc(Iso14443_3aListener* iso14443_3a_listener, MfClassicData* data) { - MfClassicListener* instance = malloc(sizeof(MfClassicListener)); - instance->iso14443_3a_listener = iso14443_3a_listener; - instance->data = mf_classic_alloc(); - mf_classic_copy(instance->data, data); - mf_classic_listener_prepare_emulation(instance); + uint8_t block_num = bit_buffer_get_byte(buff, 1); + if(block_num >= instance->total_block_num) break; - instance->crypto = crypto1_alloc(); - instance->tx_plain_buffer = bit_buffer_alloc(MF_CLASSIC_MAX_BUFF_SIZE); - instance->tx_encrypted_buffer = bit_buffer_alloc(MF_CLASSIC_MAX_BUFF_SIZE); - instance->rx_plain_buffer = bit_buffer_alloc(MF_CLASSIC_MAX_BUFF_SIZE); + uint8_t sector_num = mf_classic_get_sector_by_block(block_num); + uint8_t auth_sector_num = mf_classic_get_sector_by_block(auth_ctx->block_num); + if(sector_num != auth_sector_num) break; - instance->mfc_event.data = &instance->mfc_event_data; - instance->generic_event.protocol = NfcProtocolMfClassic; - instance->generic_event.data = &instance->mfc_event; - instance->generic_event.instance = instance; + instance->cmd_in_progress = true; + instance->current_cmd_handler_idx++; + command = MfClassicListenerCommandAck; + } while(false); - return instance; + return command; } -void mf_classic_listener_free(MfClassicListener* instance) { - furi_assert(instance); - furi_assert(instance->data); - furi_assert(instance->crypto); - furi_assert(instance->rx_plain_buffer); - furi_assert(instance->tx_encrypted_buffer); - furi_assert(instance->tx_plain_buffer); +static MfClassicListenerCommand mf_classic_listener_write_block_second_part_handler( + MfClassicListener* instance, + BitBuffer* buff) { + MfClassicListenerCommand command = MfClassicListenerCommandNack; + MfClassicAuthContext* auth_ctx = &instance->auth_context; - mf_classic_free(instance->data); - crypto1_free(instance->crypto); - bit_buffer_free(instance->rx_plain_buffer); - bit_buffer_free(instance->tx_encrypted_buffer); - bit_buffer_free(instance->tx_plain_buffer); + do { + instance->cmd_in_progress = false; - free(instance); + size_t buff_size = bit_buffer_get_size_bytes(buff); + if(buff_size != sizeof(MfClassicBlock) + sizeof(uint16_t)) break; + + uint8_t block_num = auth_ctx->block_num; + MfClassicKeyType key_type = auth_ctx->key_type; + MfClassicBlock block = instance->data->block[block_num]; + + if(mf_classic_is_sector_trailer(block_num)) { + if(mf_classic_is_allowed_access( + instance->data, block_num, key_type, MfClassicActionKeyAWrite)) { + bit_buffer_write_bytes_mid(buff, block.data, 0, sizeof(MfClassicKey)); + } + if(mf_classic_is_allowed_access( + instance->data, block_num, key_type, MfClassicActionKeyBWrite)) { + bit_buffer_write_bytes_mid(buff, block.data, 10, sizeof(MfClassicKey)); + } + if(mf_classic_is_allowed_access( + instance->data, block_num, key_type, MfClassicActionACWrite)) { + bit_buffer_write_bytes_mid(buff, block.data, 6, sizeof(MfClassicAccessBits)); + } + } else { + if(mf_classic_is_allowed_access( + instance->data, block_num, key_type, MfClassicActionDataWrite)) { + bit_buffer_write_bytes_mid(buff, block.data, 0, sizeof(MfClassicBlock)); + } else { + break; + } + } + + instance->data->block[block_num] = block; + command = MfClassicListenerCommandAck; + } while(false); + + return command; } -void mf_classic_listener_set_callback( - MfClassicListener* instance, - NfcGenericCallback callback, - void* context) { - furi_assert(instance); +static MfClassicListenerCommand + mf_classic_listener_value_cmd_handler(MfClassicListener* instance, BitBuffer* buff) { + MfClassicListenerCommand command = MfClassicListenerCommandNack; + MfClassicAuthContext* auth_ctx = &instance->auth_context; - instance->callback = callback; - instance->context = context; + do { + if(instance->state != MfClassicListenerStateAuthComplete) break; + + uint8_t block_num = bit_buffer_get_byte(buff, 1); + if(block_num >= instance->total_block_num) break; + + uint8_t sector_num = mf_classic_get_sector_by_block(block_num); + uint8_t auth_sector_num = mf_classic_get_sector_by_block(auth_ctx->block_num); + if(sector_num != auth_sector_num) break; + + uint8_t cmd = bit_buffer_get_byte(buff, 0); + MfClassicAction action = MfClassicActionDataDec; + if(cmd == MF_CLASSIC_CMD_VALUE_DEC) { + instance->value_cmd = MfClassicValueCommandDecrement; + action = MfClassicActionDataDec; + } else if(cmd == MF_CLASSIC_CMD_VALUE_INC) { + instance->value_cmd = MfClassicValueCommandIncrement; + action = MfClassicActionDataInc; + } else if(cmd == MF_CLASSIC_CMD_VALUE_RESTORE) { + instance->value_cmd = MfClassicValueCommandRestore; + } else { + break; + } + + if(!mf_classic_is_allowed_access(instance->data, block_num, auth_ctx->key_type, action)) { + break; + } + + if(!mf_classic_block_to_value( + &instance->data->block[block_num], &instance->transfer_value, NULL)) { + break; + } + + instance->cmd_in_progress = true; + instance->current_cmd_handler_idx++; + command = MfClassicListenerCommandAck; + } while(false); + + return command; } -const MfClassicData* mf_classic_listener_get_data(const MfClassicListener* instance) { - furi_assert(instance); - furi_assert(instance->data); +static MfClassicListenerCommand + mf_classic_listener_value_dec_handler(MfClassicListener* instance, BitBuffer* buff) { + return mf_classic_listener_value_cmd_handler(instance, buff); +} - return instance->data; +static MfClassicListenerCommand + mf_classic_listener_value_inc_handler(MfClassicListener* instance, BitBuffer* buff) { + return mf_classic_listener_value_cmd_handler(instance, buff); } +static MfClassicListenerCommand + mf_classic_listener_value_restore_handler(MfClassicListener* instance, BitBuffer* buff) { + return mf_classic_listener_value_cmd_handler(instance, buff); +} + +static MfClassicListenerCommand + mf_classic_listener_value_data_receive_handler(MfClassicListener* instance, BitBuffer* buff) { + MfClassicListenerCommand command = MfClassicListenerCommandNack; + + do { + if(bit_buffer_get_size_bytes(buff) != 6) break; + uint8_t data_arr[4] = {}; + bit_buffer_write_bytes_mid(buff, data_arr, 0, sizeof(data_arr)); + int32_t data = *(int32_t*)data_arr; + if(data < 0) { + data = -data; + } + + if(instance->value_cmd == MfClassicValueCommandDecrement) { + data = -data; + } else if(instance->value_cmd == MfClassicValueCommandRestore) { + data = 0; + } + + instance->transfer_value += data; + + instance->cmd_in_progress = true; + instance->current_cmd_handler_idx++; + command = MfClassicListenerCommandSilent; + } while(false); + + return command; +} + +static MfClassicListenerCommand + mf_classic_listener_value_transfer_handler(MfClassicListener* instance, BitBuffer* buff) { + MfClassicListenerCommand command = MfClassicListenerCommandNack; + MfClassicAuthContext* auth_ctx = &instance->auth_context; + + do { + instance->cmd_in_progress = false; + + if(bit_buffer_get_size_bytes(buff) != 4) break; + if(bit_buffer_get_byte(buff, 0) != MF_CLASSIC_CMD_VALUE_TRANSFER) break; + + uint8_t block_num = bit_buffer_get_byte(buff, 1); + if(!mf_classic_is_allowed_access( + instance->data, block_num, auth_ctx->key_type, MfClassicActionDataDec)) { + break; + } + + mf_classic_value_to_block( + instance->transfer_value, block_num, &instance->data->block[block_num]); + instance->transfer_value = 0; + + command = MfClassicListenerCommandAck; + } while(false); + + return command; +} + +static MfClassicListenerCommandHandler mf_classic_listener_halt_handlers[] = { + mf_classic_listener_halt_handler, +}; + +static MfClassicListenerCommandHandler mf_classic_listener_auth_key_a_handlers[] = { + mf_classic_listener_auth_key_a_handler, + mf_classic_listener_auth_second_part_handler, +}; + +static MfClassicListenerCommandHandler mf_classic_listener_auth_key_b_handlers[] = { + mf_classic_listener_auth_key_b_handler, + mf_classic_listener_auth_second_part_handler, +}; + +static MfClassicListenerCommandHandler mf_classic_listener_read_block_handlers[] = { + mf_classic_listener_read_block_handler, +}; + +static MfClassicListenerCommandHandler mf_classic_listener_write_block_handlers[] = { + mf_classic_listener_write_block_first_part_handler, + mf_classic_listener_write_block_second_part_handler, +}; + +static MfClassicListenerCommandHandler mf_classic_listener_value_dec_handlers[] = { + mf_classic_listener_value_dec_handler, + mf_classic_listener_value_data_receive_handler, + mf_classic_listener_value_transfer_handler, +}; + +static MfClassicListenerCommandHandler mf_classic_listener_value_inc_handlers[] = { + mf_classic_listener_value_inc_handler, + mf_classic_listener_value_data_receive_handler, + mf_classic_listener_value_transfer_handler, +}; + +static MfClassicListenerCommandHandler mf_classic_listener_value_restore_handlers[] = { + mf_classic_listener_value_restore_handler, + mf_classic_listener_value_data_receive_handler, + mf_classic_listener_value_transfer_handler, +}; + +static const MfClassicListenerCmd mf_classic_listener_cmd_handlers[] = { + { + .cmd_start_byte = MF_CLASSIC_CMD_HALT_MSB, + .cmd_len_bits = 4 * 8, + .command_num = COUNT_OF(mf_classic_listener_halt_handlers), + .handler = mf_classic_listener_halt_handlers, + }, + { + .cmd_start_byte = MF_CLASSIC_CMD_AUTH_KEY_A, + .cmd_len_bits = 2 * 8, + .command_num = COUNT_OF(mf_classic_listener_auth_key_a_handlers), + .handler = mf_classic_listener_auth_key_a_handlers, + }, + { + .cmd_start_byte = MF_CLASSIC_CMD_AUTH_KEY_B, + .cmd_len_bits = 2 * 8, + .command_num = COUNT_OF(mf_classic_listener_auth_key_b_handlers), + .handler = mf_classic_listener_auth_key_b_handlers, + }, + { + .cmd_start_byte = MF_CLASSIC_CMD_READ_BLOCK, + .cmd_len_bits = 4 * 8, + .command_num = COUNT_OF(mf_classic_listener_read_block_handlers), + .handler = mf_classic_listener_read_block_handlers, + }, + { + .cmd_start_byte = MF_CLASSIC_CMD_WRITE_BLOCK, + .cmd_len_bits = 4 * 8, + .command_num = COUNT_OF(mf_classic_listener_write_block_handlers), + .handler = mf_classic_listener_write_block_handlers, + }, + { + .cmd_start_byte = MF_CLASSIC_CMD_VALUE_DEC, + .cmd_len_bits = 4 * 8, + .command_num = COUNT_OF(mf_classic_listener_value_dec_handlers), + .handler = mf_classic_listener_value_dec_handlers, + }, + { + .cmd_start_byte = MF_CLASSIC_CMD_VALUE_INC, + .cmd_len_bits = 4 * 8, + .command_num = COUNT_OF(mf_classic_listener_value_inc_handlers), + .handler = mf_classic_listener_value_inc_handlers, + }, + { + .cmd_start_byte = MF_CLASSIC_CMD_VALUE_RESTORE, + .cmd_len_bits = 4 * 8, + .command_num = COUNT_OF(mf_classic_listener_value_restore_handlers), + .handler = mf_classic_listener_value_restore_handlers, + }, +}; + static void mf_classic_listener_send_short_frame(MfClassicListener* instance, uint8_t data) { BitBuffer* tx_buffer = instance->tx_plain_buffer; @@ -311,7 +514,7 @@ static void mf_classic_listener_send_short_frame(MfClassicListener* instance, ui tx_buffer = instance->tx_encrypted_buffer; } - iso14443_3a_listener_tx(instance->iso14443_3a_listener, tx_buffer); + iso14443_3a_listener_tx_with_custom_parity(instance->iso14443_3a_listener, tx_buffer); } NfcCommand mf_classic_listener_run(NfcGenericEvent event, void* context) { @@ -337,25 +540,34 @@ NfcCommand mf_classic_listener_run(NfcGenericEvent event, void* context) { } MfClassicListenerCommand mfc_command = MfClassicListenerCommandNack; - if(instance->cmd_type == MfClassicListenerCommandTypeOnePart) { - for(size_t i = 0; i < COUNT_OF(mf_classic_cmd_first_part); i++) { + if(instance->cmd_in_progress) { + mfc_command = + mf_classic_listener_cmd_handlers[instance->current_cmd_idx] + .handler[instance->current_cmd_handler_idx](instance, rx_buffer_plain); + } else { + for(size_t i = 0; i < COUNT_OF(mf_classic_listener_cmd_handlers); i++) { if(bit_buffer_get_size(rx_buffer_plain) != - mf_classic_cmd_first_part[i].cmd_len_bits) + mf_classic_listener_cmd_handlers[i].cmd_len_bits) { continue; - if(bit_buffer_get_byte(rx_buffer_plain, 0) != mf_classic_cmd_first_part[i].cmd) + } + if(bit_buffer_get_byte(rx_buffer_plain, 0) != + mf_classic_listener_cmd_handlers[i].cmd_start_byte) { continue; - mfc_command = mf_classic_cmd_first_part[i].callback(instance, rx_buffer_plain); + } + instance->current_cmd_idx = i; + instance->current_cmd_handler_idx = 0; + mfc_command = + mf_classic_listener_cmd_handlers[i].handler[0](instance, rx_buffer_plain); break; } - } else { - mfc_command = mf_classic_cmd_second_part[instance->second_part].callback( - instance, rx_buffer_plain); } if(mfc_command == MfClassicListenerCommandAck) { mf_classic_listener_send_short_frame(instance, MF_CLASSIC_CMD_ACK); } else if(mfc_command == MfClassicListenerCommandNack) { mf_classic_listener_send_short_frame(instance, MF_CLASSIC_CMD_NACK); + } else if(mfc_command == MfClassicListenerCommandSilent) { + command = NfcCommandReset; } } else if(iso3_event->type == Iso14443_3aListenerEventTypeHalted) { mf_classic_listener_reset_state(instance); @@ -364,6 +576,61 @@ NfcCommand mf_classic_listener_run(NfcGenericEvent event, void* context) { return command; } +MfClassicListener* + mf_classic_listener_alloc(Iso14443_3aListener* iso14443_3a_listener, MfClassicData* data) { + MfClassicListener* instance = malloc(sizeof(MfClassicListener)); + instance->iso14443_3a_listener = iso14443_3a_listener; + instance->data = mf_classic_alloc(); + mf_classic_copy(instance->data, data); + mf_classic_listener_prepare_emulation(instance); + + instance->crypto = crypto1_alloc(); + instance->tx_plain_buffer = bit_buffer_alloc(MF_CLASSIC_MAX_BUFF_SIZE); + instance->tx_encrypted_buffer = bit_buffer_alloc(MF_CLASSIC_MAX_BUFF_SIZE); + instance->rx_plain_buffer = bit_buffer_alloc(MF_CLASSIC_MAX_BUFF_SIZE); + + instance->mfc_event.data = &instance->mfc_event_data; + instance->generic_event.protocol = NfcProtocolMfClassic; + instance->generic_event.data = &instance->mfc_event; + instance->generic_event.instance = instance; + + return instance; +} + +void mf_classic_listener_free(MfClassicListener* instance) { + furi_assert(instance); + furi_assert(instance->data); + furi_assert(instance->crypto); + furi_assert(instance->rx_plain_buffer); + furi_assert(instance->tx_encrypted_buffer); + furi_assert(instance->tx_plain_buffer); + + mf_classic_free(instance->data); + crypto1_free(instance->crypto); + bit_buffer_free(instance->rx_plain_buffer); + bit_buffer_free(instance->tx_encrypted_buffer); + bit_buffer_free(instance->tx_plain_buffer); + + free(instance); +} + +void mf_classic_listener_set_callback( + MfClassicListener* instance, + NfcGenericCallback callback, + void* context) { + furi_assert(instance); + + instance->callback = callback; + instance->context = context; +} + +const MfClassicData* mf_classic_listener_get_data(const MfClassicListener* instance) { + furi_assert(instance); + furi_assert(instance->data); + + return instance->data; +} + const NfcListenerBase mf_classic_listener = { .alloc = (NfcListenerAlloc)mf_classic_listener_alloc, .free = (NfcListenerFree)mf_classic_listener_free, diff --git a/lib/nfc/protocols/mf_classic/mf_classic_listener.h b/lib/nfc/protocols/mf_classic/mf_classic_listener.h index 676901510f3d..5169de62d81c 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_listener.h +++ b/lib/nfc/protocols/mf_classic/mf_classic_listener.h @@ -9,7 +9,8 @@ extern "C" { typedef struct MfClassicListener MfClassicListener; typedef enum { - MfClassicListenerEventTypeAuthContextGathered, + MfClassicListenerEventTypeAuthContextPartCollected, + MfClassicListenerEventTypeAuthContextFullCollected, } MfClassicListenerEventType; typedef union { diff --git a/lib/nfc/protocols/mf_classic/mf_classic_listener_i.h b/lib/nfc/protocols/mf_classic/mf_classic_listener_i.h index 5e617b5e92b7..4507ac8c0951 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_listener_i.h +++ b/lib/nfc/protocols/mf_classic/mf_classic_listener_i.h @@ -32,27 +32,11 @@ typedef enum { MfClassicListenerCommStateEncrypted, } MfClassicListenerCommState; -typedef enum { - MfClassicListenerCommandTypeOnePart, - MfClassicListenerCommandTypeTwoParts, -} MfClassicListenerCommandType; - -typedef enum { - MfClassicListenerCommandSecondPartAuth, - MfClassicListenerCommandSecondPartWrite, - MfClassicListenerCommandSecondPartInc, - MfClassicListenerCommandSecondPartDec, - - MfClassicListenerCommandSecondPartNum, -} MfClassicListenerCommandSecondPart; - struct MfClassicListener { Iso14443_3aListener* iso14443_3a_listener; MfClassicListenerState state; MfClassicListenerAuthState auth_state; MfClassicListenerCommState comm_state; - MfClassicListenerCommandType cmd_type; - MfClassicListenerCommandSecondPart second_part; MfClassicData* data; BitBuffer* tx_plain_buffer; @@ -62,12 +46,20 @@ struct MfClassicListener { Crypto1* crypto; MfClassicAuthContext auth_context; + // Value operation data + int32_t transfer_value; + MfClassicValueCommand value_cmd; + NfcGenericEvent generic_event; MfClassicListenerEvent mfc_event; MfClassicListenerEventData mfc_event_data; NfcGenericCallback callback; void* context; + bool cmd_in_progress; + size_t current_cmd_idx; + size_t current_cmd_handler_idx; + size_t total_block_num; }; diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c index a1060fc1186f..6bb6afd3648e 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c @@ -183,3 +183,186 @@ MfClassicError mf_classic_async_read_block( return ret; } + +MfClassicError mf_classic_async_write_block( + MfClassicPoller* instance, + uint8_t block_num, + MfClassicBlock* data) { + MfClassicError ret = MfClassicErrorNone; + Iso14443_3aError error = Iso14443_3aErrorNone; + + do { + uint8_t write_block_cmd[2] = {MF_CLASSIC_CMD_WRITE_BLOCK, block_num}; + bit_buffer_copy_bytes(instance->tx_plain_buffer, write_block_cmd, sizeof(write_block_cmd)); + iso14443_3a_append_crc(instance->tx_plain_buffer); + + crypto1_encrypt( + instance->crypto, NULL, instance->tx_plain_buffer, instance->tx_encrypted_buffer); + + error = iso14443_3a_poller_txrx_custom_parity( + instance->iso14443_3a_poller, + instance->tx_encrypted_buffer, + instance->rx_encrypted_buffer, + MF_CLASSIC_FWT_FC); + if(error != Iso14443_3aErrorNone) { + ret = mf_classic_process_error(error); + break; + } + if(bit_buffer_get_size(instance->rx_encrypted_buffer) != 4) { + ret = MfClassicErrorProtocol; + break; + } + + crypto1_decrypt( + instance->crypto, instance->rx_encrypted_buffer, instance->rx_plain_buffer); + + if(bit_buffer_get_byte(instance->rx_plain_buffer, 0) != MF_CLASSIC_CMD_ACK) { + FURI_LOG_D(TAG, "Not ACK received"); + ret = MfClassicErrorProtocol; + break; + } + + bit_buffer_copy_bytes(instance->tx_plain_buffer, data->data, sizeof(MfClassicBlock)); + iso14443_3a_append_crc(instance->tx_plain_buffer); + + crypto1_encrypt( + instance->crypto, NULL, instance->tx_plain_buffer, instance->tx_encrypted_buffer); + + error = iso14443_3a_poller_txrx_custom_parity( + instance->iso14443_3a_poller, + instance->tx_encrypted_buffer, + instance->rx_encrypted_buffer, + MF_CLASSIC_FWT_FC); + if(error != Iso14443_3aErrorNone) { + ret = mf_classic_process_error(error); + break; + } + if(bit_buffer_get_size(instance->rx_encrypted_buffer) != 4) { + ret = MfClassicErrorProtocol; + break; + } + + crypto1_decrypt( + instance->crypto, instance->rx_encrypted_buffer, instance->rx_plain_buffer); + + if(bit_buffer_get_byte(instance->rx_plain_buffer, 0) != MF_CLASSIC_CMD_ACK) { + FURI_LOG_D(TAG, "Not ACK received"); + ret = MfClassicErrorProtocol; + break; + } + } while(false); + + return ret; +} + +MfClassicError mf_classic_async_value_cmd( + MfClassicPoller* instance, + uint8_t block_num, + MfClassicValueCommand cmd, + int32_t data) { + MfClassicError ret = MfClassicErrorNone; + Iso14443_3aError error = Iso14443_3aErrorNone; + + do { + uint8_t cmd_value = 0; + if(cmd == MfClassicValueCommandDecrement) { + cmd_value = MF_CLASSIC_CMD_VALUE_DEC; + } else if(cmd == MfClassicValueCommandIncrement) { + cmd_value = MF_CLASSIC_CMD_VALUE_INC; + } else { + cmd_value = MF_CLASSIC_CMD_VALUE_RESTORE; + } + uint8_t value_cmd[2] = {cmd_value, block_num}; + bit_buffer_copy_bytes(instance->tx_plain_buffer, value_cmd, sizeof(value_cmd)); + iso14443_3a_append_crc(instance->tx_plain_buffer); + + crypto1_encrypt( + instance->crypto, NULL, instance->tx_plain_buffer, instance->tx_encrypted_buffer); + + error = iso14443_3a_poller_txrx_custom_parity( + instance->iso14443_3a_poller, + instance->tx_encrypted_buffer, + instance->rx_encrypted_buffer, + MF_CLASSIC_FWT_FC); + if(error != Iso14443_3aErrorNone) { + ret = mf_classic_process_error(error); + break; + } + if(bit_buffer_get_size(instance->rx_encrypted_buffer) != 4) { + ret = MfClassicErrorProtocol; + break; + } + + crypto1_decrypt( + instance->crypto, instance->rx_encrypted_buffer, instance->rx_plain_buffer); + + if(bit_buffer_get_byte(instance->rx_plain_buffer, 0) != MF_CLASSIC_CMD_ACK) { + FURI_LOG_D(TAG, "Not ACK received"); + ret = MfClassicErrorProtocol; + break; + } + + uint8_t data_arr[4] = {}; + memcpy(data_arr, &data, sizeof(int32_t)); + bit_buffer_copy_bytes(instance->tx_plain_buffer, data_arr, sizeof(data_arr)); + iso14443_3a_append_crc(instance->tx_plain_buffer); + + crypto1_encrypt( + instance->crypto, NULL, instance->tx_plain_buffer, instance->tx_encrypted_buffer); + + error = iso14443_3a_poller_txrx_custom_parity( + instance->iso14443_3a_poller, + instance->tx_encrypted_buffer, + instance->rx_encrypted_buffer, + MF_CLASSIC_FWT_FC); + + // Command processed if tag doesn't respond + if(error != Iso14443_3aErrorTimeout) { + ret = MfClassicErrorProtocol; + break; + } + ret = MfClassicErrorNone; + } while(false); + + return ret; +} + +MfClassicError mf_classic_async_value_transfer(MfClassicPoller* instance, uint8_t block_num) { + MfClassicError ret = MfClassicErrorNone; + Iso14443_3aError error = Iso14443_3aErrorNone; + + do { + uint8_t transfer_cmd[2] = {MF_CLASSIC_CMD_VALUE_TRANSFER, block_num}; + bit_buffer_copy_bytes(instance->tx_plain_buffer, transfer_cmd, sizeof(transfer_cmd)); + iso14443_3a_append_crc(instance->tx_plain_buffer); + + crypto1_encrypt( + instance->crypto, NULL, instance->tx_plain_buffer, instance->tx_encrypted_buffer); + + error = iso14443_3a_poller_txrx_custom_parity( + instance->iso14443_3a_poller, + instance->tx_encrypted_buffer, + instance->rx_encrypted_buffer, + MF_CLASSIC_FWT_FC); + if(error != Iso14443_3aErrorNone) { + ret = mf_classic_process_error(error); + break; + } + if(bit_buffer_get_size(instance->rx_encrypted_buffer) != 4) { + ret = MfClassicErrorProtocol; + break; + } + + crypto1_decrypt( + instance->crypto, instance->rx_encrypted_buffer, instance->rx_plain_buffer); + + if(bit_buffer_get_byte(instance->rx_plain_buffer, 0) != MF_CLASSIC_CMD_ACK) { + FURI_LOG_D(TAG, "Not ACK received"); + ret = MfClassicErrorProtocol; + break; + } + + } while(false); + + return ret; +} diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h index 6f4cf35649d8..812865675386 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h @@ -71,9 +71,35 @@ typedef struct { MfClassicBlock block; } MfClassicReadBlockContext; +typedef struct { + uint8_t block_num; + MfClassicKey key; + MfClassicKeyType key_type; + MfClassicBlock block; +} MfClassicWriteBlockContext; + +typedef struct { + uint8_t block_num; + MfClassicKey key; + MfClassicKeyType key_type; + int32_t value; +} MfClassicReadValueContext; + +typedef struct { + uint8_t block_num; + MfClassicKey key; + MfClassicKeyType key_type; + MfClassicValueCommand value_cmd; + int32_t data; + int32_t new_value; +} MfClassicChangeValueContext; + typedef union { MfClassicAuthContext auth_context; MfClassicReadBlockContext read_block_context; + MfClassicWriteBlockContext write_block_context; + MfClassicReadValueContext read_value_context; + MfClassicChangeValueContext change_value_context; } MfClassicPollerContextData; MfClassicError mf_classic_process_error(Iso14443_3aError error); @@ -94,6 +120,19 @@ MfClassicError mf_classic_aync_halt(MfClassicPoller* instance); MfClassicError mf_classic_async_read_block(MfClassicPoller* instance, uint8_t block_num, MfClassicBlock* data); +MfClassicError mf_classic_async_write_block( + MfClassicPoller* instance, + uint8_t block_num, + MfClassicBlock* data); + +MfClassicError mf_classic_async_value_cmd( + MfClassicPoller* instance, + uint8_t block_num, + MfClassicValueCommand cmd, + int32_t data); + +MfClassicError mf_classic_async_value_transfer(MfClassicPoller* instance, uint8_t block_num); + #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.c b/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.c index 23e0d9cacadc..a787a43258b7 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.c @@ -4,11 +4,16 @@ #include +#define TAG "MfClassicPoller" + #define MF_CLASSIC_POLLER_COMPLETE_EVENT (1UL << 0) typedef enum { MfClassicPollerCmdTypeAuth, MfClassicPollerCmdTypeReadBlock, + MfClassicPollerCmdTypeWriteBlock, + MfClassicPollerCmdTypeReadValue, + MfClassicPollerCmdTypeChangeValue, MfClassicPollerCmdTypeNum, } MfClassicPollerCmdType; @@ -38,16 +43,121 @@ static MfClassicError mf_classic_poller_read_block_handler( MfClassicPollerContextData* data) { MfClassicError error = MfClassicErrorNone; - error = mf_classic_async_auth( - poller, - data->read_block_context.block_num, - &data->read_block_context.key, - data->read_block_context.key_type, - NULL); - if(error == MfClassicErrorNone) { + do { + error = mf_classic_async_auth( + poller, + data->read_block_context.block_num, + &data->read_block_context.key, + data->read_block_context.key_type, + NULL); + if(error != MfClassicErrorNone) break; + error = mf_classic_async_read_block( poller, data->read_block_context.block_num, &data->read_block_context.block); - } + if(error != MfClassicErrorNone) break; + + error = mf_classic_aync_halt(poller); + if(error != MfClassicErrorNone) break; + + } while(false); + + return error; +} + +static MfClassicError mf_classic_poller_write_block_handler( + MfClassicPoller* poller, + MfClassicPollerContextData* data) { + MfClassicError error = MfClassicErrorNone; + + do { + error = mf_classic_async_auth( + poller, + data->read_block_context.block_num, + &data->read_block_context.key, + data->read_block_context.key_type, + NULL); + if(error != MfClassicErrorNone) break; + + error = mf_classic_async_write_block( + poller, data->write_block_context.block_num, &data->write_block_context.block); + if(error != MfClassicErrorNone) break; + + error = mf_classic_aync_halt(poller); + if(error != MfClassicErrorNone) break; + + } while(false); + + return error; +} + +static MfClassicError mf_classic_poller_read_value_handler( + MfClassicPoller* poller, + MfClassicPollerContextData* data) { + MfClassicError error = MfClassicErrorNone; + + do { + error = mf_classic_async_auth( + poller, + data->read_value_context.block_num, + &data->read_value_context.key, + data->read_value_context.key_type, + NULL); + if(error != MfClassicErrorNone) break; + + MfClassicBlock block = {}; + error = mf_classic_async_read_block(poller, data->read_value_context.block_num, &block); + if(error != MfClassicErrorNone) break; + + if(!mf_classic_block_to_value(&block, &data->read_value_context.value, NULL)) { + error = MfClassicErrorProtocol; + break; + } + + error = mf_classic_aync_halt(poller); + if(error != MfClassicErrorNone) break; + + } while(false); + + return error; +} + +static MfClassicError mf_classic_poller_change_value_handler( + MfClassicPoller* poller, + MfClassicPollerContextData* data) { + MfClassicError error = MfClassicErrorNone; + + do { + error = mf_classic_async_auth( + poller, + data->change_value_context.block_num, + &data->change_value_context.key, + data->change_value_context.key_type, + NULL); + if(error != MfClassicErrorNone) break; + + error = mf_classic_async_value_cmd( + poller, + data->change_value_context.block_num, + data->change_value_context.value_cmd, + data->change_value_context.data); + if(error != MfClassicErrorNone) break; + + error = mf_classic_async_value_transfer(poller, data->change_value_context.block_num); + if(error != MfClassicErrorNone) break; + + MfClassicBlock block = {}; + error = mf_classic_async_read_block(poller, data->change_value_context.block_num, &block); + if(error != MfClassicErrorNone) break; + + error = mf_classic_aync_halt(poller); + if(error != MfClassicErrorNone) break; + + if(!mf_classic_block_to_value(&block, &data->change_value_context.new_value, NULL)) { + error = MfClassicErrorProtocol; + break; + } + + } while(false); return error; } @@ -55,6 +165,9 @@ static MfClassicError mf_classic_poller_read_block_handler( static const MfClassicPollerCmdHandler mf_classic_poller_cmd_handlers[MfClassicPollerCmdTypeNum] = { [MfClassicPollerCmdTypeAuth] = mf_classic_poller_auth_handler, [MfClassicPollerCmdTypeReadBlock] = mf_classic_poller_read_block_handler, + [MfClassicPollerCmdTypeWriteBlock] = mf_classic_poller_write_block_handler, + [MfClassicPollerCmdTypeReadValue] = mf_classic_poller_read_value_handler, + [MfClassicPollerCmdTypeChangeValue] = mf_classic_poller_change_value_handler, }; static NfcCommand mf_ultralgiht_poller_cmd_callback(NfcGenericEvent event, void* context) { @@ -149,3 +262,91 @@ MfClassicError mf_classic_poller_read_block( return error; } + +MfClassicError mf_classic_poller_write_block( + Nfc* nfc, + uint8_t block_num, + MfClassicKey* key, + MfClassicKeyType key_type, + MfClassicBlock* data) { + furi_assert(nfc); + furi_assert(key); + furi_assert(data); + + MfClassicPollerContext poller_context = { + .cmd_type = MfClassicPollerCmdTypeWriteBlock, + .data.write_block_context.block_num = block_num, + .data.write_block_context.key = *key, + .data.write_block_context.key_type = key_type, + .data.write_block_context.block = *data, + }; + + MfClassicError error = mf_classic_poller_cmd_execute(nfc, &poller_context); + + return error; +} + +MfClassicError mf_classic_poller_read_value( + Nfc* nfc, + uint8_t block_num, + MfClassicKey* key, + MfClassicKeyType key_type, + int32_t* value) { + furi_assert(nfc); + furi_assert(key); + furi_assert(value); + + MfClassicPollerContext poller_context = { + .cmd_type = MfClassicPollerCmdTypeReadValue, + .data.write_block_context.block_num = block_num, + .data.write_block_context.key = *key, + .data.write_block_context.key_type = key_type, + }; + + MfClassicError error = mf_classic_poller_cmd_execute(nfc, &poller_context); + + if(error == MfClassicErrorNone) { + *value = poller_context.data.read_value_context.value; + } + + return error; +} + +MfClassicError mf_classic_poller_change_value( + Nfc* nfc, + uint8_t block_num, + MfClassicKey* key, + MfClassicKeyType key_type, + int32_t data, + int32_t* new_value) { + furi_assert(nfc); + furi_assert(key); + furi_assert(new_value); + + MfClassicValueCommand command = MfClassicValueCommandRestore; + int32_t command_data = 0; + if(data > 0) { + command = MfClassicValueCommandIncrement; + command_data = data; + } else if(data < 0) { + command = MfClassicValueCommandDecrement; + command_data = -data; + } + + MfClassicPollerContext poller_context = { + .cmd_type = MfClassicPollerCmdTypeChangeValue, + .data.change_value_context.block_num = block_num, + .data.change_value_context.key = *key, + .data.change_value_context.key_type = key_type, + .data.change_value_context.value_cmd = command, + .data.change_value_context.data = command_data, + }; + + MfClassicError error = mf_classic_poller_cmd_execute(nfc, &poller_context); + + if(error == MfClassicErrorNone) { + *new_value = poller_context.data.change_value_context.new_value; + } + + return error; +} diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.h b/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.h index 278a7e86584f..bf0ef05f7d2f 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.h +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.h @@ -21,6 +21,28 @@ MfClassicError mf_classic_poller_read_block( MfClassicKeyType key_type, MfClassicBlock* data); +MfClassicError mf_classic_poller_write_block( + Nfc* nfc, + uint8_t block_num, + MfClassicKey* key, + MfClassicKeyType key_type, + MfClassicBlock* data); + +MfClassicError mf_classic_poller_read_value( + Nfc* nfc, + uint8_t block_num, + MfClassicKey* key, + MfClassicKeyType key_type, + int32_t* value); + +MfClassicError mf_classic_poller_change_value( + Nfc* nfc, + uint8_t block_num, + MfClassicKey* key, + MfClassicKeyType key_type, + int32_t data, + int32_t* new_value); + #ifdef __cplusplus } #endif From ef3a322074536cbd49bf653725020e9a24b93111 Mon Sep 17 00:00:00 2001 From: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Date: Tue, 18 Jul 2023 14:30:22 +0300 Subject: [PATCH 124/149] [NFC] Supported card plugins (#2889) * Add Opal supported card parser * Some Opal parser improvements * Add All In One (Ediniy) parser * Slight Opal parser improvement * Do not return to SceneSupportedCard if the card could not be parsed * Add Troika 1K parser (parse only) * Enable basic reading of MfClassic cards * Implement read method for Troika parsers * Use parser on SceneReadSuccess * Improve Troika code a bit * Improve parsers API * Merge Troika 1K and 4K to single plugin * Improve Troika code * Slight file structure improvements * Use app data for nfc plugins * Load nfc plugins one by one --- applications/main/nfc/application.fam | 16 ++ .../main/nfc/helpers/nfc_custom_event.h | 1 + .../main/nfc/helpers/nfc_supported_cards.c | 212 +++++++++------- .../main/nfc/helpers/nfc_supported_cards.h | 25 +- .../protocol_support/mf_classic/mf_classic.c | 10 +- .../protocol_support/nfc_protocol_support.c | 29 ++- applications/main/nfc/nfc_app.c | 4 - applications/main/nfc/nfc_app_i.h | 3 - .../nfc/plugins/supported_cards/all_in_one.c | 107 ++++++++ .../nfc_supported_card_plugin.h | 10 +- .../main/nfc/plugins/supported_cards/opal.c | 233 ++++++++++++++++++ .../main/nfc/plugins/supported_cards/troika.c | 219 ++++++++++++++++ applications/main/nfc/plugins/troika.c | 83 ------- .../main/nfc/scenes/nfc_scene_config.h | 2 +- ...nfc_scene_mf_classic_read_supported_card.c | 53 ---- .../nfc/scenes/nfc_scene_supported_card.c | 50 ++++ firmware/targets/f7/api_symbols.csv | 152 ++++++++++-- lib/nfc/SConscript | 27 ++ lib/nfc/nfc_device.c | 4 +- lib/nfc/nfc_device.h | 4 +- lib/nfc/protocols/iso14443_3a/iso14443_3a.h | 2 +- lib/nfc/protocols/iso14443_4a/iso14443_4a.h | 2 +- .../protocols/mf_classic/mf_classic_poller.c | 57 +++-- lib/nfc/protocols/mf_desfire/mf_desfire.c | 42 ++++ lib/nfc/protocols/mf_desfire/mf_desfire.h | 13 +- lib/nfc/protocols/nfc_device_base.h | 29 --- lib/nfc/protocols/nfc_device_base_i.h | 40 +++ lib/nfc/protocols/nfc_device_defs.h | 2 +- lib/toolbox/SConscript | 1 + lib/{nfc/helpers => toolbox}/simple_array.c | 0 lib/{nfc/helpers => toolbox}/simple_array.h | 8 + 31 files changed, 1115 insertions(+), 325 deletions(-) create mode 100644 applications/main/nfc/plugins/supported_cards/all_in_one.c rename applications/main/nfc/plugins/{ => supported_cards}/nfc_supported_card_plugin.h (56%) create mode 100644 applications/main/nfc/plugins/supported_cards/opal.c create mode 100644 applications/main/nfc/plugins/supported_cards/troika.c delete mode 100644 applications/main/nfc/plugins/troika.c delete mode 100644 applications/main/nfc/scenes/nfc_scene_mf_classic_read_supported_card.c create mode 100644 applications/main/nfc/scenes/nfc_scene_supported_card.c create mode 100644 lib/nfc/protocols/nfc_device_base_i.h rename lib/{nfc/helpers => toolbox}/simple_array.c (100%) rename lib/{nfc/helpers => toolbox}/simple_array.h (94%) diff --git a/applications/main/nfc/application.fam b/applications/main/nfc/application.fam index ae8a981f5106..2d96f99c2799 100644 --- a/applications/main/nfc/application.fam +++ b/applications/main/nfc/application.fam @@ -15,6 +15,22 @@ App( order=30, ) +# Parser plugins + +App( + appid="all_in_one_parser", + apptype=FlipperAppType.PLUGIN, + entry_point="all_in_one_plugin_ep", + requires=["nfc"], +) + +App( + appid="opal_parser", + apptype=FlipperAppType.PLUGIN, + entry_point="opal_plugin_ep", + requires=["nfc"], +) + App( appid="troika_parser", apptype=FlipperAppType.PLUGIN, diff --git a/applications/main/nfc/helpers/nfc_custom_event.h b/applications/main/nfc/helpers/nfc_custom_event.h index b2dea6642cea..fb94cb334d69 100644 --- a/applications/main/nfc/helpers/nfc_custom_event.h +++ b/applications/main/nfc/helpers/nfc_custom_event.h @@ -28,6 +28,7 @@ typedef enum { NfcCustomEventRpcSessionClose, NfcCustomEventPollerSuccess, + NfcCustomEventPollerIncomplete, NfcCustomEventPollerFailure, NfcCustomEventListenerUpdate, diff --git a/applications/main/nfc/helpers/nfc_supported_cards.c b/applications/main/nfc/helpers/nfc_supported_cards.c index 51133b15f5c5..303334e6bd28 100644 --- a/applications/main/nfc/helpers/nfc_supported_cards.c +++ b/applications/main/nfc/helpers/nfc_supported_cards.c @@ -1,109 +1,147 @@ #include "nfc_supported_cards.h" -#include "../plugins/nfc_supported_card_plugin.h" +#include "../plugins/supported_cards/nfc_supported_card_plugin.h" #include #include #include #include +#include #define TAG "NfcSupportedCards" -#define NFC_SUPPORTED_CARDS_PLUGINS_PATH EXT_PATH("nfc/plugins") +#define NFC_SUPPORTED_CARDS_PLUGINS_PATH APP_DATA_PATH("plugins") +#define NFC_SUPPORTED_CARDS_PLUGIN_SUFFIX "_parser.fal" -typedef enum { - NfcSupportCardsStatusIdle, - NfcSupportCardsStatusLoadSuccess, - NfcSupportCardsStatusLoadFailed, -} NfcSupportCardsStatus; +typedef struct { + Storage* storage; + File* directory; + FuriString* file_path; + char file_name[256]; + FlipperApplication* app; +} NfcSupportedCards; -struct NfcSupportedCards { - PluginManager* manager; - uint32_t plugin_cnt; - NfcSupportCardsStatus status; -}; - -NfcSupportedCards* nfc_supported_cards_alloc() { +static NfcSupportedCards* nfc_supported_cards_alloc() { NfcSupportedCards* instance = malloc(sizeof(NfcSupportedCards)); - instance->manager = plugin_manager_alloc( - NFC_SUPPORTED_CARD_PLUGIN_APP_ID, - NFC_SUPPORTED_CARD_PLUGIN_API_VERSION, - firmware_api_interface); - if(plugin_manager_load_all(instance->manager, NFC_SUPPORTED_CARDS_PLUGINS_PATH) != - PluginManagerErrorNone) { - FURI_LOG_W(TAG, "Failed to load all libs"); - instance->status = NfcSupportCardsStatusLoadFailed; - } else { - instance->plugin_cnt = plugin_manager_get_count(instance->manager); - instance->status = NfcSupportCardsStatusLoadSuccess; - FURI_LOG_D(TAG, "Loaded %ld parsers", instance->plugin_cnt); + + instance->storage = furi_record_open(RECORD_STORAGE); + instance->directory = storage_file_alloc(instance->storage); + instance->file_path = furi_string_alloc(); + + if(!storage_dir_open(instance->directory, NFC_SUPPORTED_CARDS_PLUGINS_PATH)) { + FURI_LOG_D(TAG, "Failed to open directory: %s", NFC_SUPPORTED_CARDS_PLUGINS_PATH); } return instance; } -void nfc_supported_cards_free(NfcSupportedCards* instance) { - furi_assert(instance); +static void nfc_supported_cards_free(NfcSupportedCards* instance) { + if(instance->app) { + flipper_application_free(instance->app); + } + + furi_string_free(instance->file_path); - plugin_manager_free(instance->manager); + storage_dir_close(instance->directory); + storage_file_free(instance->directory); + + furi_record_close(RECORD_STORAGE); free(instance); } -//FIXME: Make it compile -// bool nfc_supported_cards_read( -// NfcSupportedCards* instance, -// NfcDevProtocol protocol, -// void* poller, -// void* data) { -// furi_assert(instance); -// furi_assert(poller); -// furi_assert(data); -// -// bool card_read = false; -// bool verified = false; -// -// do { -// if(instance->status != NfcSupportCardsStatusLoadSuccess) break; -// -// for(size_t i = 0; i < instance->plugin_cnt; i++) { -// const NfcSupportedCardsPlugin* plugin = plugin_manager_get_ep(instance->manager, i); -// if(plugin->protocol != protocol) continue; -// if(plugin->verify) { -// verified = plugin->verify(poller); -// } -// if(verified && (plugin->read)) { -// card_read = plugin->read(poller, data); -// } -// if(card_read) break; -// } -// } while(false); -// -// return card_read; -// } -// -// bool nfc_supported_cards_parse( -// NfcSupportedCards* instance, -// NfcDevProtocol protocol, -// void* data, -// FuriString* parsed_data) { -// furi_assert(instance); -// furi_assert(data); -// furi_assert(parsed_data); -// -// bool parsed = false; -// -// do { -// if(instance->status != NfcSupportCardsStatusLoadSuccess) break; -// -// for(size_t i = 0; i < instance->plugin_cnt; i++) { -// const NfcSupportedCardsPlugin* plugin = plugin_manager_get_ep(instance->manager, i); -// if(plugin->protocol != protocol) continue; -// if(plugin->parse) { -// parsed = plugin->parse(data, parsed_data); -// } -// if(parsed) break; -// } -// } while(false); -// -// return parsed; -// } +static const NfcSupportedCardsPlugin* + nfc_supported_cards_get_next_plugin(NfcSupportedCards* instance) { + const NfcSupportedCardsPlugin* plugin = NULL; + + do { + if(!storage_file_is_open(instance->directory)) break; + if(!storage_dir_read( + instance->directory, NULL, instance->file_name, sizeof(instance->file_name))) + break; + + furi_string_set(instance->file_path, instance->file_name); + if(!furi_string_end_with_str(instance->file_path, NFC_SUPPORTED_CARDS_PLUGIN_SUFFIX)) + continue; + + path_concat(NFC_SUPPORTED_CARDS_PLUGINS_PATH, instance->file_name, instance->file_path); + + if(instance->app) flipper_application_free(instance->app); + instance->app = flipper_application_alloc(instance->storage, firmware_api_interface); + + if(flipper_application_preload(instance->app, furi_string_get_cstr(instance->file_path)) != + FlipperApplicationPreloadStatusSuccess) + continue; + if(!flipper_application_is_plugin(instance->app)) continue; + + if(flipper_application_map_to_memory(instance->app) != FlipperApplicationLoadStatusSuccess) + continue; + + const FlipperAppPluginDescriptor* descriptor = + flipper_application_plugin_get_descriptor(instance->app); + + if(descriptor == NULL) continue; + + if(strcmp(descriptor->appid, NFC_SUPPORTED_CARD_PLUGIN_APP_ID) != 0) continue; + if(descriptor->ep_api_version != NFC_SUPPORTED_CARD_PLUGIN_API_VERSION) continue; + + plugin = descriptor->entry_point; + } while(plugin == NULL); + + return plugin; +} + +bool nfc_supported_cards_read(NfcDevice* device, Nfc* nfc) { + furi_assert(device); + furi_assert(nfc); + + bool card_read = false; + + NfcSupportedCards* supported_cards = nfc_supported_cards_alloc(); + + do { + const NfcSupportedCardsPlugin* plugin = + nfc_supported_cards_get_next_plugin(supported_cards); + if(plugin == NULL) break; + + const NfcProtocol protocol = nfc_device_get_protocol(device); + if(plugin->protocol != protocol) continue; + + if(plugin->verify) { + if(!plugin->verify(nfc)) continue; + } + + if(plugin->read) { + card_read = plugin->read(nfc, device); + } + + } while(!card_read); + + nfc_supported_cards_free(supported_cards); + return card_read; +} + +bool nfc_supported_cards_parse(const NfcDevice* device, FuriString* parsed_data) { + furi_assert(device); + furi_assert(parsed_data); + + bool parsed = false; + + NfcSupportedCards* supported_cards = nfc_supported_cards_alloc(); + + do { + const NfcSupportedCardsPlugin* plugin = + nfc_supported_cards_get_next_plugin(supported_cards); + if(plugin == NULL) break; + + const NfcProtocol protocol = nfc_device_get_protocol(device); + if(plugin->protocol != protocol) continue; + + if(plugin->parse) { + parsed = plugin->parse(device, parsed_data); + } + + } while(!parsed); + + nfc_supported_cards_free(supported_cards); + return parsed; +} diff --git a/applications/main/nfc/helpers/nfc_supported_cards.h b/applications/main/nfc/helpers/nfc_supported_cards.h index 08721a2e7871..2bf57211c780 100644 --- a/applications/main/nfc/helpers/nfc_supported_cards.h +++ b/applications/main/nfc/helpers/nfc_supported_cards.h @@ -1,30 +1,17 @@ #pragma once -#include -#include +#include + +#include +#include #ifdef __cplusplus extern "C" { #endif -typedef struct NfcSupportedCards NfcSupportedCards; - -NfcSupportedCards* nfc_supported_cards_alloc(); - -void nfc_supported_cards_free(NfcSupportedCards* instance); +bool nfc_supported_cards_read(NfcDevice* device, Nfc* nfc); -//FIXME: Make it compile -// bool nfc_supported_cards_read( -// NfcSupportedCards* instance, -// NfcProtocol protocol, -// void* poller, -// void* data); -// -// bool nfc_supported_cards_parse( -// NfcSupportedCards* instance, -// NfcProtocol protocol, -// void* data, -// FuriString* parsed_data); +bool nfc_supported_cards_parse(const NfcDevice* device, FuriString* parsed_data); #ifdef __cplusplus } diff --git a/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c b/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c index b416e5a11093..f25432f13fa1 100644 --- a/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c +++ b/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c @@ -43,9 +43,13 @@ static NfcCommand nfc_scene_read_poller_callback_mf_classic(NfcGenericEvent even // TODO: Implement read mf_classic using key cache if(mf_classic_event->type == MfClassicPollerEventTypeReadComplete) { - nfc_device_set_data( - instance->nfc_device, NfcProtocolMfClassic, nfc_poller_get_data(instance->poller)); - view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventPollerSuccess); + const MfClassicData* mf_classic_data = nfc_poller_get_data(instance->poller); + nfc_device_set_data(instance->nfc_device, NfcProtocolMfClassic, mf_classic_data); + + const NfcCustomEvent custom_event = mf_classic_is_card_read(mf_classic_data) ? + NfcCustomEventPollerSuccess : + NfcCustomEventPollerIncomplete; + view_dispatcher_send_custom_event(instance->view_dispatcher, custom_event); return NfcCommandStop; } diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c index 6d272bfa4221..cd1c49c611a8 100644 --- a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c @@ -1,6 +1,7 @@ #include "nfc_protocol_support.h" #include "nfc/nfc_app_i.h" +#include "nfc/helpers/nfc_supported_cards.h" #include "nfc_protocol_support_defs.h" #include "nfc_protocol_support_gui_common.h" @@ -63,6 +64,14 @@ static bool nfc_protocol_support_scene_info_on_event(NfcApp* instance, SceneMana if(event.type == SceneManagerEventTypeCustom) { const NfcProtocol protocol = nfc_device_get_protocol(instance->nfc_device); consumed = nfc_protocol_support[protocol]->scene_info.on_event(instance, event.event); + } else if(event.type == SceneManagerEventTypeBack) { + // If the card could not be parsed, return to the respective menu + if(!scene_manager_get_scene_state(instance->scene_manager, NfcSceneSupportedCard)) { + const uint32_t scenes[] = {NfcSceneSavedMenu, NfcSceneReadMenu}; + scene_manager_search_and_switch_to_previous_scene_one_of( + instance->scene_manager, scenes, COUNT_OF(scenes)); + consumed = true; + } } return consumed; @@ -99,6 +108,12 @@ static bool nfc_protocol_support_scene_read_on_event(NfcApp* instance, SceneMana scene_manager_next_scene(instance->scene_manager, NfcSceneReadSuccess); dolphin_deed(DolphinDeedNfcReadSuccess); consumed = true; + } else if(event.event == NfcCustomEventPollerIncomplete) { + nfc_supported_cards_read(instance->nfc_device, instance->nfc); + + view_dispatcher_send_custom_event( + instance->view_dispatcher, NfcCustomEventPollerSuccess); + consumed = true; } else if(event.event == NfcCustomEventPollerFailure) { if(scene_manager_has_previous_scene(instance->scene_manager, NfcSceneDetect)) { scene_manager_search_and_switch_to_previous_scene( @@ -208,8 +223,16 @@ static void nfc_protocol_support_scene_read_menu_on_exit(NfcApp* instance) { static void nfc_protocol_support_scene_read_success_on_enter(NfcApp* instance) { Widget* widget = instance->widget; - const NfcProtocol protocol = nfc_device_get_protocol(instance->nfc_device); - nfc_protocol_support[protocol]->scene_read_success.on_enter(instance); + FuriString* temp_str = furi_string_alloc(); + if(nfc_supported_cards_parse(instance->nfc_device, temp_str)) { + widget_add_text_scroll_element( + instance->widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); + } else { + const NfcProtocol protocol = nfc_device_get_protocol(instance->nfc_device); + nfc_protocol_support[protocol]->scene_read_success.on_enter(instance); + } + + furi_string_free(temp_str); widget_add_button_element( widget, GuiButtonTypeLeft, "Retry", nfc_protocol_support_common_widget_callback, instance); @@ -322,7 +345,7 @@ static bool // TODO: Implement restore from shadow file if(event.event == SubmenuIndexCommonInfo) { - scene_manager_next_scene(instance->scene_manager, NfcSceneInfo); + scene_manager_next_scene(instance->scene_manager, NfcSceneSupportedCard); consumed = true; } else if(event.event == SubmenuIndexCommonRename) { scene_manager_next_scene(instance->scene_manager, NfcSceneSaveName); diff --git a/applications/main/nfc/nfc_app.c b/applications/main/nfc/nfc_app.c index 04c7be9b6ecd..5fda1359cb6c 100644 --- a/applications/main/nfc/nfc_app.c +++ b/applications/main/nfc/nfc_app.c @@ -48,8 +48,6 @@ NfcApp* nfc_app_alloc() { instance->nfc = nfc_alloc(); instance->scanner = nfc_scanner_alloc(instance->nfc); - instance->parsed_data = furi_string_alloc(); - instance->mf_ul_auth = mf_ultralight_auth_alloc(); // Nfc device @@ -148,8 +146,6 @@ void nfc_app_free(NfcApp* instance) { instance->rpc_ctx = NULL; } - furi_string_free(instance->parsed_data); - nfc_free(instance->nfc); nfc_scanner_free(instance->scanner); diff --git a/applications/main/nfc/nfc_app_i.h b/applications/main/nfc/nfc_app_i.h index 280d93b281a2..0d1f31abef76 100644 --- a/applications/main/nfc/nfc_app_i.h +++ b/applications/main/nfc/nfc_app_i.h @@ -28,7 +28,6 @@ #include "helpers/nfc_custom_event.h" #include "helpers/mf_ultralight_auth.h" #include "helpers/mf_dict.h" -#include "helpers/nfc_supported_cards.h" #include "helpers/mfkey32_logger.h" #include @@ -116,8 +115,6 @@ struct NfcApp { MfUltralightAuth* mf_ul_auth; NfcMfClassicDictAttackContext mf_dict_context; - FuriString* parsed_data; - NfcSupportedCards* supported_cards; Mfkey32Logger* mfkey32_logger; NfcDevice* nfc_device; diff --git a/applications/main/nfc/plugins/supported_cards/all_in_one.c b/applications/main/nfc/plugins/supported_cards/all_in_one.c new file mode 100644 index 000000000000..1be23d1f3329 --- /dev/null +++ b/applications/main/nfc/plugins/supported_cards/all_in_one.c @@ -0,0 +1,107 @@ +#include "nfc_supported_card_plugin.h" + +#include +#include + +#define TAG "AllInOne" + +typedef enum { + AllInOneLayoutTypeA, + AllInOneLayoutTypeD, + AllInOneLayoutTypeE2, + AllInOneLayoutTypeE3, + AllInOneLayoutTypeE5, + AllInOneLayoutType2, + AllInOneLayoutTypeUnknown, +} AllInOneLayoutType; + +static AllInOneLayoutType all_in_one_get_layout(const MfUltralightData* data) { + // Switch on the second half of the third byte of page 5 + const uint8_t layout_byte = data->page[5].data[2]; + const uint8_t layout_half_byte = data->page[5].data[2] & 0x0F; + + FURI_LOG_I(TAG, "Layout byte: %02x", layout_byte); + FURI_LOG_I(TAG, "Layout half-byte: %02x", layout_half_byte); + + switch(layout_half_byte) { + // If it is A, the layout type is a type A layout + case 0x0A: + return AllInOneLayoutTypeA; + case 0x0D: + return AllInOneLayoutTypeD; + case 0x02: + return AllInOneLayoutType2; + default: + FURI_LOG_I(TAG, "Unknown layout type: %d", layout_half_byte); + return AllInOneLayoutTypeUnknown; + } +} + +static bool all_in_one_parse(const NfcDevice* device, FuriString* parsed_data) { + furi_assert(device); + furi_assert(parsed_data); + + const MfUltralightData* data = nfc_device_get_data(device, NfcProtocolMfUltralight); + + bool parsed = false; + + do { + if(data->page[4].data[0] != 0x45 || data->page[4].data[1] != 0xD9) { + FURI_LOG_I(TAG, "Pass not verified"); + break; + } + + uint8_t ride_count = 0; + uint32_t serial = 0; + + const AllInOneLayoutType layout_type = all_in_one_get_layout(data); + + if(layout_type == AllInOneLayoutTypeA) { + // If the layout is A then the ride count is stored in the first byte of page 8 + ride_count = data->page[8].data[0]; + } else if(layout_type == AllInOneLayoutTypeD) { + // If the layout is D, the ride count is stored in the second byte of page 9 + ride_count = data->page[9].data[1]; + } else { + FURI_LOG_I(TAG, "Unknown layout: %d", layout_type); + ride_count = 137; + } + + // // The number starts at the second half of the third byte on page 4, and is 32 bits long + // // So we get the second half of the third byte, then bytes 4-6, and then the first half of the 7th byte + // // B8 17 A2 A4 BD becomes 81 7A 2A 4B + const uint8_t* serial_data_lo = data->page[4].data; + const uint8_t* serial_data_hi = data->page[5].data; + + serial = (serial_data_lo[2] & 0x0F) << 28 | serial_data_lo[3] << 20 | + serial_data_hi[0] << 12 | serial_data_hi[1] << 4 | serial_data_hi[2] >> 4; + + // Format string for rides count + furi_string_printf( + parsed_data, "\e#All-In-One\nNumber: %lu\nRides left: %u", serial, ride_count); + + parsed = true; + } while(false); + + return parsed; +} + +/* Actual implementation of app<>plugin interface */ +static const NfcSupportedCardsPlugin all_in_one_plugin = { + .protocol = NfcProtocolMfUltralight, + .verify = NULL, + .read = NULL, + .parse = all_in_one_parse, +}; + +/* Plugin descriptor to comply with basic plugin specification */ +static const FlipperAppPluginDescriptor all_in_one_plugin_descriptor = { + .appid = NFC_SUPPORTED_CARD_PLUGIN_APP_ID, + .ep_api_version = NFC_SUPPORTED_CARD_PLUGIN_API_VERSION, + .entry_point = &all_in_one_plugin, +}; + +/* Plugin entry point - must return a pointer to const descriptor */ +const FlipperAppPluginDescriptor* all_in_one_plugin_ep() { + return &all_in_one_plugin_descriptor; +} diff --git a/applications/main/nfc/plugins/nfc_supported_card_plugin.h b/applications/main/nfc/plugins/supported_cards/nfc_supported_card_plugin.h similarity index 56% rename from applications/main/nfc/plugins/nfc_supported_card_plugin.h rename to applications/main/nfc/plugins/supported_cards/nfc_supported_card_plugin.h index 7cb21c98dcaa..f87e21083180 100644 --- a/applications/main/nfc/plugins/nfc_supported_card_plugin.h +++ b/applications/main/nfc/plugins/supported_cards/nfc_supported_card_plugin.h @@ -1,16 +1,18 @@ #pragma once #include -#include + +#include +#include #define NFC_SUPPORTED_CARD_PLUGIN_APP_ID "NfcSupportedCardPlugin" #define NFC_SUPPORTED_CARD_PLUGIN_API_VERSION 1 -typedef bool (*NfcSupportedCardPluginVerify)(void* poller); +typedef bool (*NfcSupportedCardPluginVerify)(Nfc* nfc); -typedef bool (*NfcSupportedCardPluginRead)(void* poller, void* data); +typedef bool (*NfcSupportedCardPluginRead)(Nfc* nfc, NfcDevice* device); -typedef bool (*NfcSupportedCardPluginParse)(void* data, FuriString* parsed_data); +typedef bool (*NfcSupportedCardPluginParse)(const NfcDevice* device, FuriString* parsed_data); typedef struct { NfcProtocol protocol; diff --git a/applications/main/nfc/plugins/supported_cards/opal.c b/applications/main/nfc/plugins/supported_cards/opal.c new file mode 100644 index 000000000000..824df5523c33 --- /dev/null +++ b/applications/main/nfc/plugins/supported_cards/opal.c @@ -0,0 +1,233 @@ +/* + * opal.c - Parser for Opal card (Sydney, Australia). + * + * Copyright 2023 Michael Farrell + * + * This will only read "standard" MIFARE DESFire-based Opal cards. Free travel + * cards (including School Opal cards, veteran, vision-impaired persons and + * TfNSW employees' cards) and single-trip tickets are MIFARE Ultralight C + * cards and not supported. + * + * Reference: https://github.com/metrodroid/metrodroid/wiki/Opal + * + * Note: The card values are all little-endian (like Flipper), but the above + * reference was originally written based on Java APIs, which are big-endian. + * This implementation presumes a little-endian system. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "nfc_supported_card_plugin.h" + +#include +#include +#include + +#include + +static const MfDesfireApplicationId opal_app_id = {.data = {0x31, 0x45, 0x53}}; + +static const MfDesfireFileId opal_file_id = 0x07; + +static const char* opal_modes[5] = + {"Rail / Metro", "Ferry / Light Rail", "Bus", "Unknown mode", "Manly Ferry"}; + +static const char* opal_usages[14] = { + "New / Unused", + "Tap on: new journey", + "Tap on: transfer from same mode", + "Tap on: transfer from other mode", + NULL, // Manly Ferry: new journey + NULL, // Manly Ferry: transfer from ferry + NULL, // Manly Ferry: transfer from other + "Tap off: distance fare", + "Tap off: flat fare", + "Automated tap off: failed to tap off", + "Tap off: end of trip without start", + "Tap off: reversal", + "Tap on: rejected", + "Unknown usage", +}; + +// Opal file 0x7 structure. Assumes a little-endian CPU. +typedef struct __attribute__((__packed__)) { + uint32_t serial : 32; + uint8_t check_digit : 4; + bool blocked : 1; + uint16_t txn_number : 16; + int32_t balance : 21; + uint16_t days : 15; + uint16_t minutes : 11; + uint8_t mode : 3; + uint16_t usage : 4; + bool auto_topup : 1; + uint8_t weekly_journeys : 4; + uint16_t checksum : 16; +} OpalFile; + +static_assert(sizeof(OpalFile) == 16, "OpalFile"); + +// Converts an Opal timestamp to FuriHalRtcDateTime. +// +// Opal measures days since 1980-01-01 and minutes since midnight, and presumes +// all days are 1440 minutes. +static void opal_date_time_to_furi(uint16_t days, uint16_t minutes, FuriHalRtcDateTime* out) { + out->year = 1980; + out->month = 1; + // 1980-01-01 is a Tuesday + out->weekday = ((days + 1) % 7) + 1; + out->hour = minutes / 60; + out->minute = minutes % 60; + out->second = 0; + + // What year is it? + for(;;) { + const uint16_t num_days_in_year = furi_hal_rtc_get_days_per_year(out->year); + if(days < num_days_in_year) break; + days -= num_days_in_year; + out->year++; + } + + // 1-index the day of the year + days++; + + for(;;) { + // What month is it? + const bool is_leap = furi_hal_rtc_is_leap_year(out->year); + const uint8_t num_days_in_month = furi_hal_rtc_get_days_per_month(is_leap, out->month); + if(days <= num_days_in_month) break; + days -= num_days_in_month; + out->month++; + } + + out->day = days; +} + +static bool opal_parse(const NfcDevice* device, FuriString* parsed_data) { + furi_assert(device); + furi_assert(parsed_data); + + const MfDesfireData* data = nfc_device_get_data(device, NfcProtocolMfDesfire); + + bool parsed = false; + + do { + const MfDesfireApplication* app = mf_desfire_get_application(data, &opal_app_id); + if(app == NULL) break; + + const MfDesfireFileSettings* file_settings = + mf_desfire_get_file_settings(app, &opal_file_id); + if(file_settings == NULL || file_settings->type != MfDesfireFileTypeStandard || + file_settings->data.size != sizeof(OpalFile)) + break; + + const MfDesfireFileData* file_data = mf_desfire_get_file_data(app, &opal_file_id); + if(file_data == NULL) break; + + const OpalFile* opal_file = simple_array_cget(file_data->data, 0); + + const uint8_t serial2 = opal_file->serial / 10000000; + const uint16_t serial3 = (opal_file->serial / 1000) % 10000; + const uint16_t serial4 = (opal_file->serial % 1000); + + if(opal_file->check_digit > 9) break; + + // Negative balance. Make this a positive value again and record the + // sign separately, because then we can handle balances of -99..-1 + // cents, as the "dollars" division below would result in a positive + // zero value. + const bool is_negative_balance = (opal_file->balance < 0); + const char* sign = is_negative_balance ? "-" : ""; + const int32_t balance = is_negative_balance ? labs(opal_file->balance) : + opal_file->balance; + const uint8_t balance_cents = balance % 100; + const int32_t balance_dollars = balance / 100; + + FuriHalRtcDateTime timestamp; + opal_date_time_to_furi(opal_file->days, opal_file->minutes, ×tamp); + + // Usages 4..6 associated with the Manly Ferry, which correspond to + // usages 1..3 for other modes. + const bool is_manly_ferry = (opal_file->usage >= 4) && (opal_file->usage <= 6); + + // 3..7 are "reserved", but we use 4 to indicate the Manly Ferry. + const uint8_t mode = is_manly_ferry ? 4 : (opal_file->mode > 3 ? 3 : opal_file->mode); + const uint8_t usage = is_manly_ferry ? opal_file->usage - 3 : opal_file->usage; + + const char* mode_str = opal_modes[mode > 4 ? 3 : mode]; + const char* usage_str = opal_usages[usage > 12 ? 13 : usage]; + + furi_string_printf( + parsed_data, + "\e#Opal: $%s%ld.%02hu\n3085 22%02hhu %04hu %03hu%01hhu\n%s, %s\n", + sign, + balance_dollars, + balance_cents, + serial2, + serial3, + serial4, + opal_file->check_digit, + mode_str, + usage_str); + + FuriString* timestamp_str = furi_string_alloc(); + + locale_format_date(timestamp_str, ×tamp, locale_get_date_format(), "-"); + furi_string_cat(parsed_data, timestamp_str); + furi_string_cat(parsed_data, " at "); + + locale_format_time(timestamp_str, ×tamp, locale_get_time_format(), false); + furi_string_cat(parsed_data, timestamp_str); + + furi_string_free(timestamp_str); + + furi_string_cat_printf( + parsed_data, + "\nWeekly journeys: %hhu, Txn #%hu\n", + opal_file->weekly_journeys, + opal_file->txn_number); + + if(opal_file->auto_topup) { + furi_string_cat_str(parsed_data, "Auto-topup enabled\n"); + } + + if(opal_file->blocked) { + furi_string_cat_str(parsed_data, "Card blocked\n"); + } + + parsed = true; + } while(false); + + return parsed; +} + +/* Actual implementation of app<>plugin interface */ +static const NfcSupportedCardsPlugin opal_plugin = { + .protocol = NfcProtocolMfDesfire, + .verify = NULL, + .read = NULL, + .parse = opal_parse, +}; + +/* Plugin descriptor to comply with basic plugin specification */ +static const FlipperAppPluginDescriptor opal_plugin_descriptor = { + .appid = NFC_SUPPORTED_CARD_PLUGIN_APP_ID, + .ep_api_version = NFC_SUPPORTED_CARD_PLUGIN_API_VERSION, + .entry_point = &opal_plugin, +}; + +/* Plugin entry point - must return a pointer to const descriptor */ +const FlipperAppPluginDescriptor* opal_plugin_ep() { + return &opal_plugin_descriptor; +} diff --git a/applications/main/nfc/plugins/supported_cards/troika.c b/applications/main/nfc/plugins/supported_cards/troika.c new file mode 100644 index 000000000000..3b7cd60b0f95 --- /dev/null +++ b/applications/main/nfc/plugins/supported_cards/troika.c @@ -0,0 +1,219 @@ +#include "nfc_supported_card_plugin.h" + +#include + +#include +#include +#include + +#define TAG "Troika" + +typedef struct { + uint64_t a; + uint64_t b; +} MfClassicKeyPair; + +typedef struct { + const MfClassicKeyPair* keys; + uint32_t data_sector; +} TroikaCardConfig; + +static const MfClassicKeyPair troika_1k_keys[] = { + {.a = 0xa0a1a2a3a4a5, .b = 0xfbf225dc5d58}, + {.a = 0xa82607b01c0d, .b = 0x2910989b6880}, + {.a = 0x2aa05ed1856f, .b = 0xeaac88e5dc99}, + {.a = 0x2aa05ed1856f, .b = 0xeaac88e5dc99}, + {.a = 0x73068f118c13, .b = 0x2b7f3253fac5}, + {.a = 0xfbc2793d540b, .b = 0xd3a297dc2698}, + {.a = 0x2aa05ed1856f, .b = 0xeaac88e5dc99}, + {.a = 0xae3d65a3dad4, .b = 0x0f1c63013dba}, + {.a = 0xa73f5dc1d333, .b = 0xe35173494a81}, + {.a = 0x69a32f1c2f19, .b = 0x6b8bd9860763}, + {.a = 0x9becdf3d9273, .b = 0xf8493407799d}, + {.a = 0x08b386463229, .b = 0x5efbaecef46b}, + {.a = 0xcd4c61c26e3d, .b = 0x31c7610de3b0}, + {.a = 0xa82607b01c0d, .b = 0x2910989b6880}, + {.a = 0x0e8f64340ba4, .b = 0x4acec1205d75}, + {.a = 0x2aa05ed1856f, .b = 0xeaac88e5dc99}, +}; + +static const MfClassicKeyPair troika_4k_keys[] = { + {.a = 0xa0a1a2a3a4a5, .b = 0xfbf225dc5d58}, {.a = 0xa82607b01c0d, .b = 0x2910989b6880}, + {.a = 0x2aa05ed1856f, .b = 0xeaac88e5dc99}, {.a = 0x2aa05ed1856f, .b = 0xeaac88e5dc99}, + {.a = 0x73068f118c13, .b = 0x2b7f3253fac5}, {.a = 0xfbc2793d540b, .b = 0xd3a297dc2698}, + {.a = 0x2aa05ed1856f, .b = 0xeaac88e5dc99}, {.a = 0xae3d65a3dad4, .b = 0x0f1c63013dbb}, + {.a = 0xa73f5dc1d333, .b = 0xe35173494a81}, {.a = 0x69a32f1c2f19, .b = 0x6b8bd9860763}, + {.a = 0x9becdf3d9273, .b = 0xf8493407799d}, {.a = 0x08b386463229, .b = 0x5efbaecef46b}, + {.a = 0xcd4c61c26e3d, .b = 0x31c7610de3b0}, {.a = 0xa82607b01c0d, .b = 0x2910989b6880}, + {.a = 0x0e8f64340ba4, .b = 0x4acec1205d75}, {.a = 0x2aa05ed1856f, .b = 0xeaac88e5dc99}, + {.a = 0x6b02733bb6ec, .b = 0x7038cd25c408}, {.a = 0x403d706ba880, .b = 0xb39d19a280df}, + {.a = 0xc11f4597efb5, .b = 0x70d901648cb9}, {.a = 0x0db520c78c1c, .b = 0x73e5b9d9d3a4}, + {.a = 0x3ebce0925b2f, .b = 0x372cc880f216}, {.a = 0x16a27af45407, .b = 0x9868925175ba}, + {.a = 0xaba208516740, .b = 0xce26ecb95252}, {.a = 0xcd64e567abcd, .b = 0x8f79c4fd8a01}, + {.a = 0x764cd061f1e6, .b = 0xa74332f74994}, {.a = 0x1cc219e9fec1, .b = 0xb90de525ceb6}, + {.a = 0x2fe3cb83ea43, .b = 0xfba88f109b32}, {.a = 0x07894ffec1d6, .b = 0xefcb0e689db3}, + {.a = 0x04c297b91308, .b = 0xc8454c154cb5}, {.a = 0x7a38e3511a38, .b = 0xab16584c972a}, + {.a = 0x7545df809202, .b = 0xecf751084a80}, {.a = 0x5125974cd391, .b = 0xd3eafb5df46d}, + {.a = 0x7a86aa203788, .b = 0xe41242278ca2}, {.a = 0xafcef64c9913, .b = 0x9db96dca4324}, + {.a = 0x04eaa462f70b, .b = 0xac17b93e2fae}, {.a = 0xe734c210f27e, .b = 0x29ba8c3e9fda}, + {.a = 0xd5524f591eed, .b = 0x5daf42861b4d}, {.a = 0xe4821a377b75, .b = 0xe8709e486465}, + {.a = 0x518dc6eea089, .b = 0x97c64ac98ca4}, {.a = 0xbb52f8cce07f, .b = 0x6b6119752c70}, +}; + +static bool troika_get_card_config(TroikaCardConfig* config, MfClassicType type) { + bool success = true; + + if(type == MfClassicType1k) { + config->data_sector = 8; + config->keys = troika_1k_keys; + } else if(type == MfClassicType4k) { + config->data_sector = 4; + config->keys = troika_4k_keys; + } else { + success = false; + } + + return success; +} + +static bool troika_verify_type(Nfc* nfc, MfClassicType type) { + bool verified = false; + + do { + TroikaCardConfig cfg; + if(!troika_get_card_config(&cfg, type)) break; + + const uint8_t block_num = mf_classic_get_first_block_num_of_sector(cfg.data_sector); + FURI_LOG_D(TAG, "Verifying sector %lu", cfg.data_sector); + + MfClassicKey key = {0}; + nfc_util_num2bytes(cfg.keys[cfg.data_sector].a, COUNT_OF(key.data), key.data); + + MfClassicAuthContext auth_context; + MfClassicError error = + mf_classic_poller_auth(nfc, block_num, &key, MfClassicKeyTypeA, &auth_context); + if(error != MfClassicErrorNone) { + FURI_LOG_D(TAG, "Failed to read block %u: %d", block_num, error); + break; + } + + verified = true; + } while(false); + + return verified; +} + +static bool troika_verify(Nfc* nfc) { + return troika_verify_type(nfc, MfClassicType1k) || troika_verify_type(nfc, MfClassicType4k); +} + +static bool troika_read(Nfc* nfc, NfcDevice* device) { + furi_assert(nfc); + furi_assert(device); + + bool is_read = false; + + MfClassicData* data = mf_classic_alloc(); + nfc_device_copy_data(device, NfcProtocolMfClassic, data); + + do { + if(!mf_classic_detect_protocol(data->iso14443_3a_data, &data->type)) break; + + TroikaCardConfig cfg; + if(!troika_get_card_config(&cfg, data->type)) break; + + MfClassicKey key = {0}; + nfc_util_num2bytes(cfg.keys[cfg.data_sector].a, COUNT_OF(key.data), key.data); + + const uint8_t block_num_start = mf_classic_get_first_block_num_of_sector(cfg.data_sector); + const uint8_t block_num_end = block_num_start + 2; + + uint8_t block_num; + for(block_num = block_num_start; block_num < block_num_end; ++block_num) { + MfClassicBlock block; + MfClassicError error; + + error = mf_classic_poller_read_block(nfc, block_num, &key, MfClassicKeyTypeA, &block); + + if(error != MfClassicErrorNone) { + FURI_LOG_D(TAG, "Failed to read block %u: %d", block_num, error); + break; + } + + mf_classic_set_block_read(data, block_num, &block); + } + + if(block_num != block_num_end) break; + + mf_classic_set_key_found( + data, cfg.data_sector, MfClassicKeyTypeA, cfg.keys[cfg.data_sector].a); + nfc_device_set_data(device, NfcProtocolMfClassic, data); + + is_read = true; + } while(false); + + mf_classic_free(data); + + return is_read; +} + +static bool troika_parse(const NfcDevice* device, FuriString* parsed_data) { + furi_assert(device); + + const MfClassicData* data = nfc_device_get_data(device, NfcProtocolMfClassic); + + bool parsed = false; + + do { + // Verify card type + TroikaCardConfig cfg; + if(!troika_get_card_config(&cfg, data->type)) break; + + // Verify key + const MfClassicSectorTrailer* sec_tr = + mf_classic_get_sector_trailer_by_sector(data, cfg.data_sector); + + const uint64_t key = nfc_util_bytes2num(sec_tr->key_a.data, COUNT_OF(sec_tr->key_a.data)); + if(key != cfg.keys[cfg.data_sector].a) break; + + // Parse data + const uint8_t start_block_num = mf_classic_get_first_block_num_of_sector(cfg.data_sector); + + const uint8_t* temp_ptr = &data->block[start_block_num + 1].data[5]; + uint16_t balance = ((temp_ptr[0] << 8) | temp_ptr[1]) / 25; + temp_ptr = &data->block[start_block_num].data[2]; + + uint32_t number = 0; + for(size_t i = 1; i < 5; i++) { + number <<= 8; + number |= temp_ptr[i]; + } + number >>= 4; + number |= (temp_ptr[0] & 0xf) << 28; + + furi_string_printf(parsed_data, "\e#Troika\nNum: %lu\nBalance: %u RUR", number, balance); + parsed = true; + } while(false); + + return parsed; +} + +/* Actual implementation of app<>plugin interface */ +static const NfcSupportedCardsPlugin troika_plugin = { + .protocol = NfcProtocolMfClassic, + .verify = troika_verify, + .read = troika_read, + .parse = troika_parse, +}; + +/* Plugin descriptor to comply with basic plugin specification */ +static const FlipperAppPluginDescriptor troika_plugin_descriptor = { + .appid = NFC_SUPPORTED_CARD_PLUGIN_APP_ID, + .ep_api_version = NFC_SUPPORTED_CARD_PLUGIN_API_VERSION, + .entry_point = &troika_plugin, +}; + +/* Plugin entry point - must return a pointer to const descriptor */ +const FlipperAppPluginDescriptor* troika_plugin_ep() { + return &troika_plugin_descriptor; +} diff --git a/applications/main/nfc/plugins/troika.c b/applications/main/nfc/plugins/troika.c deleted file mode 100644 index 88a8f60a45c6..000000000000 --- a/applications/main/nfc/plugins/troika.c +++ /dev/null @@ -1,83 +0,0 @@ -#include "nfc_supported_card_plugin.h" - -#include - -#include -#include -#include - -#define TAG "Troika" - -// static const MfClassicAuthContext troika_keys[] = { -// {.sector = 0, .key_a = 0xa0a1a2a3a4a5, .key_b = 0xfbf225dc5d58}, -// {.sector = 1, .key_a = 0xa82607b01c0d, .key_b = 0x2910989b6880}, -// {.sector = 2, .key_a = 0x2aa05ed1856f, .key_b = 0xeaac88e5dc99}, -// {.sector = 3, .key_a = 0x2aa05ed1856f, .key_b = 0xeaac88e5dc99}, -// {.sector = 4, .key_a = 0x73068f118c13, .key_b = 0x2b7f3253fac5}, -// {.sector = 5, .key_a = 0xfbc2793d540b, .key_b = 0xd3a297dc2698}, -// {.sector = 6, .key_a = 0x2aa05ed1856f, .key_b = 0xeaac88e5dc99}, -// {.sector = 7, .key_a = 0xae3d65a3dad4, .key_b = 0x0f1c63013dba}, -// {.sector = 8, .key_a = 0xa73f5dc1d333, .key_b = 0xe35173494a81}, -// {.sector = 9, .key_a = 0x69a32f1c2f19, .key_b = 0x6b8bd9860763}, -// {.sector = 10, .key_a = 0x9becdf3d9273, .key_b = 0xf8493407799d}, -// {.sector = 11, .key_a = 0x08b386463229, .key_b = 0x5efbaecef46b}, -// {.sector = 12, .key_a = 0xcd4c61c26e3d, .key_b = 0x31c7610de3b0}, -// {.sector = 13, .key_a = 0xa82607b01c0d, .key_b = 0x2910989b6880}, -// {.sector = 14, .key_a = 0x0e8f64340ba4, .key_b = 0x4acec1205d75}, -// {.sector = 15, .key_a = 0x2aa05ed1856f, .key_b = 0xeaac88e5dc99}, -// }; - -bool troika_verify(void* poller) { - furi_assert(poller); - - bool verified = false; - // MfClassicPoller* mfc_poller = poller; - // uint8_t sector = 11; - // uint8_t block = mf_classic_get_sector_trailer_num_by_sector(sector); - // MfClassicKey key = {.data = {0x08, 0xb3, 0x86, 0x46, 0x32, 0x29}}; - // MfClassicAuthContext auth_context = {}; - - // FURI_LOG_D("Troika", "Verifying sector %d", sector); - // if(mf_classic_poller_auth(mfc_poller, block, &key, MfClassicKeyTypeA, &auth_context) == - // MfClassicErrorNone) { - // FURI_LOG_D(TAG, "Sector %d verified", sector); - // verified = true; - // } - - return verified; -} - -bool troika_read(void* poller, void* data) { - furi_assert(poller); - furi_assert(data); - - return true; -} - -bool troika_parse(void* data, FuriString* parsed_data) { - furi_assert(data); - - furi_string_printf(parsed_data, "%s", "Hello Troika"); - - return true; -} - -/* Actual implementation of app<>plugin interface */ -static const NfcSupportedCardsPlugin troika_plugin = { - .protocol = NfcProtocolMfClassic, - .verify = troika_verify, - .read = troika_read, - .parse = troika_parse, -}; - -/* Plugin descriptor to comply with basic plugin specification */ -static const FlipperAppPluginDescriptor troika_plugin_descriptor = { - .appid = NFC_SUPPORTED_CARD_PLUGIN_APP_ID, - .ep_api_version = NFC_SUPPORTED_CARD_PLUGIN_API_VERSION, - .entry_point = &troika_plugin, -}; - -/* Plugin entry point - must return a pointer to const descriptor */ -const FlipperAppPluginDescriptor* troika_plugin_ep() { - return &troika_plugin_descriptor; -} diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index a9482a483877..c52a7c397aae 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -9,6 +9,7 @@ ADD_SCENE(nfc, delete_success, DeleteSuccess) ADD_SCENE(nfc, detect, Detect) ADD_SCENE(nfc, read, Read) ADD_SCENE(nfc, info, Info) +ADD_SCENE(nfc, supported_card, SupportedCard) ADD_SCENE(nfc, select_protocol, SelectProtocol) ADD_SCENE(nfc, extra_actions, ExtraActions) ADD_SCENE(nfc, read_success, ReadSuccess) @@ -26,7 +27,6 @@ ADD_SCENE(nfc, mf_ultralight_capture_pass, MfUltralightCapturePass) ADD_SCENE(nfc, mf_desfire_data, MfDesfireData) ADD_SCENE(nfc, mf_desfire_app, MfDesfireApp) -ADD_SCENE(nfc, mf_classic_read_supported_card, MfClassicReadSupportedCard) ADD_SCENE(nfc, mf_classic_dict_attack, MfClassicDictAttack) ADD_SCENE(nfc, mf_classic_detect_reader, MfClassicDetectReader) ADD_SCENE(nfc, mf_classic_mfkey_nonces_info, MfClassicMfkeyNoncesInfo) diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_read_supported_card.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_read_supported_card.c deleted file mode 100644 index f69a9d200072..000000000000 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_read_supported_card.c +++ /dev/null @@ -1,53 +0,0 @@ -#include "../nfc_app_i.h" -#include - -void nfc_scene_mf_classic_read_supported_card_on_enter(void* context) { - NfcApp* nfc = context; - - // Setup view - popup_reset(nfc->popup); - popup_set_text(nfc->popup, "Apply card to\nFlipper's back", 97, 24, AlignCenter, AlignTop); - popup_set_icon(nfc->popup, 0, 8, &I_NFC_manual_60x50); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); - - nfc_blink_read_start(nfc); - - bool supported = false; - nfc->supported_cards = nfc_supported_cards_alloc(); - // FIXME: Make it compile - // if(nfc_supported_cards_read( - // nfc->supported_cards, - // NfcDevProtocolMfClassic, - // nfc->mf_classic_poller, - // &nfc->nfc_dev_data.mf_classic_data)) { - // supported = nfc_supported_cards_parse( - // nfc->supported_cards, - // NfcDevProtocolMfClassic, - // &nfc->nfc_dev_data.mf_classic_data, - // nfc->parsed_data); - // } - - if(supported) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneReadSuccess); - } else { - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicDictAttack); - } - - nfc_supported_cards_free(nfc->supported_cards); -} - -bool nfc_scene_mf_classic_read_supported_card_on_event(void* context, SceneManagerEvent event) { - UNUSED(context); - UNUSED(event); - - return false; -} - -void nfc_scene_mf_classic_read_supported_card_on_exit(void* context) { - NfcApp* nfc = context; - - // Clear view - popup_reset(nfc->popup); - - nfc_blink_stop(nfc); -} diff --git a/applications/main/nfc/scenes/nfc_scene_supported_card.c b/applications/main/nfc/scenes/nfc_scene_supported_card.c new file mode 100644 index 000000000000..cea55b783bcb --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_supported_card.c @@ -0,0 +1,50 @@ +#include "nfc/nfc_app_i.h" + +#include "nfc/helpers/nfc_supported_cards.h" +#include "nfc/helpers/protocol_support/nfc_protocol_support_gui_common.h" + +void nfc_scene_supported_card_on_enter(void* context) { + NfcApp* instance = context; + + FuriString* temp_str = furi_string_alloc(); + + if(nfc_supported_cards_parse(instance->nfc_device, temp_str)) { + widget_add_text_scroll_element( + instance->widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); + widget_add_button_element( + instance->widget, + GuiButtonTypeRight, + "More", + nfc_protocol_support_common_widget_callback, + instance); + + scene_manager_set_scene_state(instance->scene_manager, NfcSceneSupportedCard, true); + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewWidget); + + } else { + scene_manager_set_scene_state(instance->scene_manager, NfcSceneSupportedCard, false); + scene_manager_next_scene(instance->scene_manager, NfcSceneInfo); + } + + furi_string_free(temp_str); +} + +bool nfc_scene_supported_card_on_event(void* context, SceneManagerEvent event) { + NfcApp* instance = context; + + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeRight) { + scene_manager_next_scene(instance->scene_manager, NfcSceneInfo); + consumed = true; + } + } + + return consumed; +} + +void nfc_scene_supported_card_on_exit(void* context) { + NfcApp* instance = context; + widget_reset(instance->widget); +} diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 1a7bf934e683..ad0f16aaac31 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,+,35.1,, +Version,+,35.2,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -150,8 +150,29 @@ Header,+,lib/music_worker/music_worker.h,, Header,+,lib/nanopb/pb.h,, Header,+,lib/nanopb/pb_decode.h,, Header,+,lib/nanopb/pb_encode.h,, +Header,+,lib/nfc/helpers/nfc_util.h,, +Header,+,lib/nfc/nfc.h,, +Header,+,lib/nfc/nfc_device.h,, +Header,+,lib/nfc/nfc_listener.h,, +Header,+,lib/nfc/nfc_poller.h,, +Header,+,lib/nfc/nfc_scanner.h,, +Header,+,lib/nfc/protocols/iso14443_3a/iso14443_3a.h,, +Header,+,lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.h,, +Header,+,lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.h,, +Header,+,lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_sync_api.h,, +Header,+,lib/nfc/protocols/iso14443_4a/iso14443_4a.h,, +Header,+,lib/nfc/protocols/iso14443_4a/iso14443_4a_listener.h,, +Header,+,lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.h,, Header,+,lib/nfc/protocols/mf_classic/mf_classic.h,, +Header,+,lib/nfc/protocols/mf_classic/mf_classic_listener.h,, Header,+,lib/nfc/protocols/mf_classic/mf_classic_poller.h,, +Header,+,lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.h,, +Header,+,lib/nfc/protocols/mf_desfire/mf_desfire.h,, +Header,+,lib/nfc/protocols/mf_desfire/mf_desfire_poller.h,, +Header,+,lib/nfc/protocols/mf_ultralight/mf_ultralight.h,, +Header,+,lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.h,, +Header,+,lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h,, +Header,+,lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.h,, Header,+,lib/one_wire/maxim_crc.h,, Header,+,lib/one_wire/one_wire_host.h,, Header,+,lib/one_wire/one_wire_slave.h,, @@ -214,6 +235,7 @@ Header,+,lib/toolbox/protocols/protocol_dict.h,, Header,+,lib/toolbox/random_name.h,, Header,+,lib/toolbox/saved_struct.h,, Header,+,lib/toolbox/sha256.h,, +Header,+,lib/toolbox/simple_array.h,, Header,+,lib/toolbox/stream/buffered_file_stream.h,, Header,+,lib/toolbox/stream/file_stream.h,, Header,+,lib/toolbox/stream/stream.h,, @@ -1816,10 +1838,23 @@ Function,-,iso14443_3a_get_device_name,const char*,"const Iso14443_3aData*, NfcD Function,-,iso14443_3a_get_uid,const uint8_t*,"const Iso14443_3aData*, size_t*" Function,-,iso14443_3a_is_equal,_Bool,"const Iso14443_3aData*, const Iso14443_3aData*" Function,-,iso14443_3a_load,_Bool,"Iso14443_3aData*, FlipperFormat*, uint32_t" +Function,+,iso14443_3a_poller_read,Iso14443_3aError,"Nfc*, Iso14443_3aData*" Function,-,iso14443_3a_reset,void,Iso14443_3aData* Function,+,iso14443_3a_save,_Bool,"const Iso14443_3aData*, FlipperFormat*" Function,-,iso14443_3a_trim_crc,void,BitBuffer* Function,-,iso14443_3a_verify,_Bool,"Iso14443_3aData*, const FuriString*" +Function,+,iso14443_4a_alloc,Iso14443_4aData*, +Function,+,iso14443_4a_copy,void,"Iso14443_4aData*, const Iso14443_4aData*" +Function,+,iso14443_4a_free,void,Iso14443_4aData* +Function,+,iso14443_4a_get_base_data,const Iso14443_3aData*,const Iso14443_4aData* +Function,+,iso14443_4a_get_device_name,const char*,"const Iso14443_4aData*, NfcDeviceNameType" +Function,+,iso14443_4a_get_uid,const uint8_t*,"const Iso14443_4aData*, size_t*" +Function,+,iso14443_4a_is_ats_supported,_Bool,const Iso14443_4aData* +Function,+,iso14443_4a_is_equal,_Bool,"const Iso14443_4aData*, const Iso14443_4aData*" +Function,+,iso14443_4a_load,_Bool,"Iso14443_4aData*, FlipperFormat*, uint32_t" +Function,+,iso14443_4a_reset,void,Iso14443_4aData* +Function,+,iso14443_4a_save,_Bool,"const Iso14443_4aData*, FlipperFormat*" +Function,+,iso14443_4a_verify,_Bool,"Iso14443_4aData*, const FuriString*" Function,-,isprint,int,int Function,-,isprint_l,int,"int, locale_t" Function,-,ispunct,int,int @@ -2000,36 +2035,81 @@ Function,+,menu_set_selected_item,void,"Menu*, uint32_t" Function,+,mf_classic_alloc,MfClassicData*, Function,+,mf_classic_block_to_value,_Bool,"const MfClassicBlock*, int32_t*, uint8_t*" Function,+,mf_classic_copy,void,"MfClassicData*, const MfClassicData*" -Function,-,mf_classic_detect_protocol,_Bool,"Iso14443_3aData*, MfClassicType*" +Function,+,mf_classic_detect_protocol,_Bool,"Iso14443_3aData*, MfClassicType*" Function,+,mf_classic_free,void,MfClassicData* -Function,-,mf_classic_get_base_data,const Iso14443_3aData*,const MfClassicData* -Function,-,mf_classic_get_blocks_num_in_sector,uint8_t,uint8_t -Function,-,mf_classic_get_device_name,const char*,"const MfClassicData*, NfcDeviceNameType" -Function,-,mf_classic_get_first_block_num_of_sector,uint8_t,uint8_t +Function,+,mf_classic_get_base_data,const Iso14443_3aData*,const MfClassicData* +Function,+,mf_classic_get_blocks_num_in_sector,uint8_t,uint8_t +Function,+,mf_classic_get_device_name,const char*,"const MfClassicData*, NfcDeviceNameType" +Function,+,mf_classic_get_first_block_num_of_sector,uint8_t,uint8_t Function,+,mf_classic_get_read_sectors_and_keys,void,"const MfClassicData*, uint8_t*, uint8_t*" -Function,-,mf_classic_get_sector_by_block,uint8_t,uint8_t +Function,+,mf_classic_get_sector_by_block,uint8_t,uint8_t Function,+,mf_classic_get_sector_trailer_by_sector,MfClassicSectorTrailer*,"const MfClassicData*, uint8_t" -Function,-,mf_classic_get_sector_trailer_num_by_block,uint8_t,uint8_t +Function,+,mf_classic_get_sector_trailer_num_by_block,uint8_t,uint8_t Function,+,mf_classic_get_sector_trailer_num_by_sector,uint8_t,uint8_t -Function,-,mf_classic_get_total_block_num,uint16_t,MfClassicType -Function,-,mf_classic_get_total_sectors_num,uint8_t,MfClassicType +Function,+,mf_classic_get_total_block_num,uint16_t,MfClassicType +Function,+,mf_classic_get_total_sectors_num,uint8_t,MfClassicType Function,+,mf_classic_get_uid,const uint8_t*,"const MfClassicData*, size_t*" -Function,-,mf_classic_is_allowed_access,_Bool,"MfClassicData*, uint8_t, MfClassicKeyType, MfClassicAction" +Function,+,mf_classic_is_allowed_access,_Bool,"MfClassicData*, uint8_t, MfClassicKeyType, MfClassicAction" Function,+,mf_classic_is_block_read,_Bool,"const MfClassicData*, uint8_t" Function,+,mf_classic_is_card_read,_Bool,const MfClassicData* Function,+,mf_classic_is_equal,_Bool,"const MfClassicData*, const MfClassicData*" Function,+,mf_classic_is_key_found,_Bool,"const MfClassicData*, uint8_t, MfClassicKeyType" Function,+,mf_classic_is_sector_read,_Bool,"const MfClassicData*, uint8_t" -Function,-,mf_classic_is_sector_trailer,_Bool,uint8_t +Function,+,mf_classic_is_sector_trailer,_Bool,uint8_t Function,+,mf_classic_is_value_block,_Bool,"MfClassicData*, uint8_t" Function,+,mf_classic_load,_Bool,"MfClassicData*, FlipperFormat*, uint32_t" +Function,+,mf_classic_poller_auth,MfClassicError,"Nfc*, uint8_t, MfClassicKey*, MfClassicKeyType, MfClassicAuthContext*" +Function,+,mf_classic_poller_change_value,MfClassicError,"Nfc*, uint8_t, MfClassicKey*, MfClassicKeyType, int32_t, int32_t*" +Function,+,mf_classic_poller_read_block,MfClassicError,"Nfc*, uint8_t, MfClassicKey*, MfClassicKeyType, MfClassicBlock*" +Function,+,mf_classic_poller_read_value,MfClassicError,"Nfc*, uint8_t, MfClassicKey*, MfClassicKeyType, int32_t*" +Function,+,mf_classic_poller_write_block,MfClassicError,"Nfc*, uint8_t, MfClassicKey*, MfClassicKeyType, MfClassicBlock*" Function,+,mf_classic_reset,void,MfClassicData* Function,+,mf_classic_save,_Bool,"const MfClassicData*, FlipperFormat*" -Function,-,mf_classic_set_block_read,void,"MfClassicData*, uint8_t, MfClassicBlock*" -Function,-,mf_classic_set_key_found,void,"MfClassicData*, uint8_t, MfClassicKeyType, uint64_t" -Function,-,mf_classic_set_key_not_found,void,"MfClassicData*, uint8_t, MfClassicKeyType" +Function,+,mf_classic_set_block_read,void,"MfClassicData*, uint8_t, MfClassicBlock*" +Function,+,mf_classic_set_key_found,void,"MfClassicData*, uint8_t, MfClassicKeyType, uint64_t" +Function,+,mf_classic_set_key_not_found,void,"MfClassicData*, uint8_t, MfClassicKeyType" Function,+,mf_classic_value_to_block,void,"int32_t, uint8_t, MfClassicBlock*" Function,+,mf_classic_verify,_Bool,"MfClassicData*, const FuriString*" +Function,+,mf_desfire_alloc,MfDesfireData*, +Function,+,mf_desfire_copy,void,"MfDesfireData*, const MfDesfireData*" +Function,+,mf_desfire_free,void,MfDesfireData* +Function,+,mf_desfire_get_application,const MfDesfireApplication*,"const MfDesfireData*, const MfDesfireApplicationId*" +Function,+,mf_desfire_get_base_data,const Iso14443_4aData*,const MfDesfireData* +Function,+,mf_desfire_get_device_name,const char*,"const MfDesfireData*, NfcDeviceNameType" +Function,+,mf_desfire_get_file_data,const MfDesfireFileData*,"const MfDesfireApplication*, const MfDesfireFileId*" +Function,+,mf_desfire_get_file_settings,const MfDesfireFileSettings*,"const MfDesfireApplication*, const MfDesfireFileId*" +Function,+,mf_desfire_get_uid,const uint8_t*,"const MfDesfireData*, size_t*" +Function,+,mf_desfire_is_equal,_Bool,"const MfDesfireData*, const MfDesfireData*" +Function,+,mf_desfire_load,_Bool,"MfDesfireData*, FlipperFormat*, uint32_t" +Function,+,mf_desfire_reset,void,MfDesfireData* +Function,+,mf_desfire_save,_Bool,"const MfDesfireData*, FlipperFormat*" +Function,+,mf_desfire_verify,_Bool,"MfDesfireData*, const FuriString*" +Function,+,mf_ultralight_alloc,MfUltralightData*, +Function,+,mf_ultralight_copy,void,"MfUltralightData*, const MfUltralightData*" +Function,+,mf_ultralight_detect_protocol,_Bool,const Iso14443_3aData* +Function,+,mf_ultralight_free,void,MfUltralightData* +Function,+,mf_ultralight_get_base_data,const Iso14443_3aData*,const MfUltralightData* +Function,+,mf_ultralight_get_config_page,_Bool,"const MfUltralightData*, MfUltralightConfigPages**" +Function,+,mf_ultralight_get_config_page_num,uint16_t,MfUltralightType +Function,+,mf_ultralight_get_device_name,const char*,"const MfUltralightData*, NfcDeviceNameType" +Function,+,mf_ultralight_get_feature_support_set,uint32_t,MfUltralightType +Function,+,mf_ultralight_get_pages_total,uint16_t,MfUltralightType +Function,+,mf_ultralight_get_type_by_version,MfUltralightType,MfUltralightVersion* +Function,+,mf_ultralight_get_uid,const uint8_t*,"const MfUltralightData*, size_t*" +Function,+,mf_ultralight_is_all_data_read,_Bool,const MfUltralightData* +Function,+,mf_ultralight_is_counter_configured,_Bool,const MfUltralightData* +Function,+,mf_ultralight_is_equal,_Bool,"const MfUltralightData*, const MfUltralightData*" +Function,+,mf_ultralight_load,_Bool,"MfUltralightData*, FlipperFormat*, uint32_t" +Function,+,mf_ultralight_poller_read_card,MfUltralightError,"Nfc*, MfUltralightData*" +Function,+,mf_ultralight_poller_read_counter,MfUltralightError,"Nfc*, uint8_t, MfUltralightCounter*" +Function,+,mf_ultralight_poller_read_page,MfUltralightError,"Nfc*, uint16_t, MfUltralightPage*" +Function,+,mf_ultralight_poller_read_signature,MfUltralightError,"Nfc*, MfUltralightSignature*" +Function,+,mf_ultralight_poller_read_tearing_flag,MfUltralightError,"Nfc*, uint8_t, MfUltralightTearingFlag*" +Function,+,mf_ultralight_poller_read_version,MfUltralightError,"Nfc*, MfUltralightVersion*" +Function,+,mf_ultralight_poller_write_page,MfUltralightError,"Nfc*, uint16_t, MfUltralightPage*" +Function,+,mf_ultralight_reset,void,MfUltralightData* +Function,+,mf_ultralight_save,_Bool,"const MfUltralightData*, FlipperFormat*" +Function,+,mf_ultralight_verify,_Bool,"MfUltralightData*, const FuriString*" Function,-,mkdtemp,char*,char* Function,-,mkostemp,int,"char*, int" Function,-,mkostemps,int,"char*, int, int" @@ -2067,13 +2147,34 @@ Function,-,nexttowardf,float,"float, long double" Function,-,nexttowardl,long double,"long double, long double" Function,-,nfc_alloc,Nfc*, Function,-,nfc_config,void,"Nfc*, NfcMode" +Function,+,nfc_device_alloc,NfcDevice*, +Function,+,nfc_device_clear,void,NfcDevice* +Function,+,nfc_device_copy_data,void,"const NfcDevice*, NfcProtocol, NfcDeviceData*" +Function,+,nfc_device_free,void,NfcDevice* +Function,+,nfc_device_get_base_data,const NfcDeviceData*,"const NfcDevice*, NfcProtocol" +Function,+,nfc_device_get_data,const NfcDeviceData*,"const NfcDevice*, NfcProtocol" +Function,+,nfc_device_get_name,const char*,"const NfcDevice*, NfcDeviceNameType" +Function,+,nfc_device_get_protocol,NfcProtocol,const NfcDevice* +Function,+,nfc_device_get_protocol_name,const char*,NfcProtocol +Function,+,nfc_device_get_uid,const uint8_t*,"const NfcDevice*, size_t*" +Function,+,nfc_device_is_equal,_Bool,"const NfcDevice*, const NfcDevice*" +Function,+,nfc_device_load,_Bool,"NfcDevice*, const char*" +Function,+,nfc_device_reset,void,NfcDevice* +Function,+,nfc_device_save,_Bool,"NfcDevice*, const char*" +Function,+,nfc_device_set_data,void,"NfcDevice*, NfcProtocol, const NfcDeviceData*" +Function,+,nfc_device_set_loading_callback,void,"NfcDevice*, NfcLoadingCallback, void*" Function,-,nfc_free,void,Nfc* Function,-,nfc_iso14443_3a_listener_tx_custom_parity,NfcError,"Nfc*, const BitBuffer*" Function,-,nfc_iso14443_3a_sdd_frame,NfcError,"Nfc*, const BitBuffer*, BitBuffer*, uint32_t" Function,-,nfc_iso14443_3a_short_frame,NfcError,"Nfc*, NfcIso14443aShortFrame, BitBuffer*, uint32_t" Function,-,nfc_listener_abort,void,Nfc* +Function,+,nfc_listener_alloc,NfcListener*,"Nfc*, NfcProtocol, const NfcDeviceData*" +Function,+,nfc_listener_free,void,NfcListener* +Function,+,nfc_listener_get_data,const NfcDeviceData*,"NfcListener*, NfcProtocol" Function,-,nfc_listener_set_col_res_data,NfcError,"Nfc*, uint8_t*, uint8_t, uint8_t*, uint8_t" Function,-,nfc_listener_sleep,NfcError,Nfc* +Function,+,nfc_listener_start,void,"NfcListener*, NfcGenericCallback, void*" +Function,+,nfc_listener_stop,void,NfcListener* Function,-,nfc_listener_tx,NfcError,"Nfc*, const BitBuffer*" Function,-,nfc_poller_alloc,NfcPoller*,"Nfc*, NfcProtocol" Function,-,nfc_poller_detect,_Bool,NfcPoller* @@ -2083,6 +2184,10 @@ Function,-,nfc_poller_start,void,"NfcPoller*, NfcGenericCallback, void*" Function,-,nfc_poller_stop,void,NfcPoller* Function,-,nfc_protocol_get_parent,NfcProtocol,NfcProtocol Function,-,nfc_protocol_has_parent,_Bool,"NfcProtocol, NfcProtocol" +Function,+,nfc_scanner_alloc,NfcScanner*,Nfc* +Function,+,nfc_scanner_free,void,NfcScanner* +Function,+,nfc_scanner_start,void,"NfcScanner*, NfcScannerCallback, void*" +Function,+,nfc_scanner_stop,void,NfcScanner* Function,-,nfc_set_fdt_listen_fc,void,"Nfc*, uint32_t" Function,-,nfc_set_fdt_poll_fc,void,"Nfc*, uint32_t" Function,-,nfc_set_fdt_poll_poll_us,void,"Nfc*, uint32_t" @@ -2093,6 +2198,11 @@ Function,-,nfc_start_poller,void,"Nfc*, NfcEventCallback, void*" Function,-,nfc_stop,void,Nfc* Function,-,nfc_trx,NfcError,"Nfc*, const BitBuffer*, BitBuffer*, uint32_t" Function,-,nfc_trx_custom_parity,NfcError,"Nfc*, const BitBuffer*, BitBuffer*, uint32_t" +Function,+,nfc_util_bytes2num,uint64_t,"const uint8_t*, uint8_t" +Function,+,nfc_util_even_parity32,uint8_t,uint32_t +Function,+,nfc_util_num2bytes,void,"uint64_t, uint8_t, uint8_t*" +Function,+,nfc_util_odd_parity,void,"const uint8_t*, uint8_t*, uint8_t" +Function,+,nfc_util_odd_parity8,uint8_t,uint8_t Function,-,nfca_append_crc16,void,"uint8_t*, uint16_t" Function,-,nfca_emulation_handler,_Bool,"uint8_t*, uint16_t, uint8_t*, uint16_t*" Function,-,nfca_get_crc16,uint16_t,"uint8_t*, uint16_t" @@ -2527,6 +2637,14 @@ Function,+,sha256_finish,void,"sha256_context*, unsigned char[32]" Function,+,sha256_process,void,sha256_context* Function,+,sha256_start,void,sha256_context* Function,+,sha256_update,void,"sha256_context*, const unsigned char*, unsigned int" +Function,+,simple_array_alloc,SimpleArray*,const SimpleArrayConfig* +Function,+,simple_array_cget,const SimpleArrayElement*,"const SimpleArray*, uint32_t" +Function,+,simple_array_copy,void,"SimpleArray*, const SimpleArray*" +Function,+,simple_array_free,void,SimpleArray* +Function,+,simple_array_get,SimpleArrayElement*,"SimpleArray*, uint32_t" +Function,+,simple_array_get_count,uint32_t,const SimpleArray* +Function,+,simple_array_init,void,"SimpleArray*, uint32_t" +Function,+,simple_array_reset,void,SimpleArray* Function,-,sin,double,double Function,-,sincos,void,"double, double*, double*" Function,-,sincosf,void,"float, float*, float*" @@ -3378,7 +3496,10 @@ Variable,+,message_sound_off,const NotificationMessage, Variable,+,message_vibro_off,const NotificationMessage, Variable,+,message_vibro_on,const NotificationMessage, Variable,-,nfc_device_iso14443_3a,const NfcDeviceBase, +Variable,+,nfc_device_iso14443_4a,const NfcDeviceBase, Variable,-,nfc_device_mf_classic,const NfcDeviceBase, +Variable,+,nfc_device_mf_desfire,const NfcDeviceBase, +Variable,+,nfc_device_mf_ultralight,const NfcDeviceBase, Variable,+,sequence_audiovisual_alert,const NotificationSequence, Variable,+,sequence_blink_blue_10,const NotificationSequence, Variable,+,sequence_blink_blue_100,const NotificationSequence, @@ -3428,6 +3549,7 @@ Variable,+,sequence_set_vibro_on,const NotificationSequence, Variable,+,sequence_single_vibro,const NotificationSequence, Variable,+,sequence_solid_yellow,const NotificationSequence, Variable,+,sequence_success,const NotificationSequence, +Variable,+,simple_array_config_uint8_t,const SimpleArrayConfig, Variable,+,subghz_device_cc1101_preset_2fsk_dev2_38khz_async_regs,const uint8_t[], Variable,+,subghz_device_cc1101_preset_2fsk_dev47_6khz_async_regs,const uint8_t[], Variable,+,subghz_device_cc1101_preset_gfsk_9_99kb_async_regs,const uint8_t[], diff --git a/lib/nfc/SConscript b/lib/nfc/SConscript index e617537a4f35..fb9d1d3cc5ff 100644 --- a/lib/nfc/SConscript +++ b/lib/nfc/SConscript @@ -5,8 +5,35 @@ env.Append( "#/lib/nfc", ], SDK_HEADERS=[ + # Main + File("nfc.h"), + File("nfc_device.h"), + File("nfc_listener.h"), + File("nfc_poller.h"), + File("nfc_scanner.h"), + # Protocols + File("protocols/iso14443_3a/iso14443_3a.h"), + File("protocols/iso14443_4a/iso14443_4a.h"), + File("protocols/mf_ultralight/mf_ultralight.h"), File("protocols/mf_classic/mf_classic.h"), + File("protocols/mf_desfire/mf_desfire.h"), + # Pollers + File("protocols/iso14443_3a/iso14443_3a_poller.h"), + File("protocols/iso14443_4a/iso14443_4a_poller.h"), + File("protocols/mf_ultralight/mf_ultralight_poller.h"), File("protocols/mf_classic/mf_classic_poller.h"), + File("protocols/mf_desfire/mf_desfire_poller.h"), + # Listeners + File("protocols/iso14443_3a/iso14443_3a_listener.h"), + File("protocols/iso14443_4a/iso14443_4a_listener.h"), + File("protocols/mf_ultralight/mf_ultralight_listener.h"), + File("protocols/mf_classic/mf_classic_listener.h"), + # Sync API + File("protocols/iso14443_3a/iso14443_3a_poller_sync_api.h"), + File("protocols/mf_ultralight/mf_ultralight_poller_sync_api.h"), + File("protocols/mf_classic/mf_classic_poller_sync_api.h"), + # Misc + File("helpers/nfc_util.h"), ], ) diff --git a/lib/nfc/nfc_device.c b/lib/nfc/nfc_device.c index 344b34c77805..c7fb3c94d197 100644 --- a/lib/nfc/nfc_device.c +++ b/lib/nfc/nfc_device.c @@ -1,9 +1,11 @@ #include "nfc_device.h" -#include #include #include +#include "nfc_common.h" +#include "protocols/nfc_device_defs.h" + #define NFC_FILE_HEADER "Flipper NFC device" #define NFC_DEV_TYPE_ERROR "Protocol type mismatch" diff --git a/lib/nfc/nfc_device.h b/lib/nfc/nfc_device.h index bc90f5a5c641..74ca73eaf6e4 100644 --- a/lib/nfc/nfc_device.h +++ b/lib/nfc/nfc_device.h @@ -1,8 +1,10 @@ #pragma once +#include +#include #include -#include "protocols/nfc_device_defs.h" +#include "protocols/nfc_device_base.h" #include "protocols/nfc_protocol.h" #ifdef __cplusplus diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a.h b/lib/nfc/protocols/iso14443_3a/iso14443_3a.h index a1e93d24e79a..46b443acafc7 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a.h +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #ifdef __cplusplus extern "C" { diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a.h b/lib/nfc/protocols/iso14443_4a/iso14443_4a.h index d5f982c8b977..9b6feb29cc19 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a.h +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a.h @@ -2,7 +2,7 @@ #include -#include "helpers/simple_array.h" +#include #ifdef __cplusplus extern "C" { diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller.c b/lib/nfc/protocols/mf_classic/mf_classic_poller.c index c39de0083fde..0d11dc2574a2 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller.c @@ -278,7 +278,7 @@ static const MfClassicPollerReadHandler [MfClassicPollerStateReadComplete] = mf_classic_poller_handler_read_complete, }; -NfcCommand mf_classsic_poller_run(NfcGenericEvent event, void* context) { +NfcCommand mf_classic_poller_run(NfcGenericEvent event, void* context) { furi_assert(event.data); furi_assert(event.protocol == NfcProtocolIso14443_3a); furi_assert(context); @@ -287,28 +287,55 @@ NfcCommand mf_classsic_poller_run(NfcGenericEvent event, void* context) { Iso14443_3aPollerEvent* iso14443_3a_event = event.data; NfcCommand command = NfcCommandContinue; + UNUSED(mf_classic_poller_dict_attack_handler); if(iso14443_3a_event->type == Iso14443_3aPollerEventTypeReady) { - command = mf_classic_poller_dict_attack_handler[instance->state](instance); - } else if(iso14443_3a_event->type == Iso14443_3aPollerEventTypeError) { - if(iso14443_3a_event->data->error == Iso14443_3aErrorNotPresent) { - if(instance->card_state == MfClassicCardStateDetected) { - instance->card_state = MfClassicCardStateNotDetected; - instance->mfc_event.type = MfClassicPollerEventTypeCardNotDetected; - command = instance->callback(instance->general_event, instance->context); - instance->state = MfClassicPollerStateIdle; - } - } + // TODO: Temporary measure + iso14443_3a_copy( + instance->data->iso14443_3a_data, + iso14443_3a_poller_get_data(instance->iso14443_3a_poller)); + instance->mfc_event.type = MfClassicPollerEventTypeReadComplete; + command = instance->callback(instance->general_event, instance->context); + + // command = mf_classic_poller_dict_attack_handler[instance->state](instance); + // } else if(iso14443_3a_event->type == Iso14443_3aPollerEventTypeError) { + // if(iso14443_3a_event->data->error == Iso14443_3aErrorNotPresent) { + // if(instance->card_state == MfClassicCardStateDetected) { + // instance->card_state = MfClassicCardStateNotDetected; + // instance->mfc_event.type = MfClassicPollerEventTypeCardNotDetected; + // command = instance->callback(instance->general_event, instance->context); + // instance->state = MfClassicPollerStateIdle; + // } + // } } return command; } -bool mf_classsic_poller_detect(NfcGenericEvent event, void* context) { +bool mf_classic_poller_detect(NfcGenericEvent event, void* context) { furi_assert(event.data); furi_assert(event.protocol == NfcProtocolIso14443_3a); furi_assert(context); - return false; + Iso14443_3aPoller* iso3_poller = event.instance; + Iso14443_3aPollerEvent* iso14443_3a_event = event.data; + bool detected = false; + + if(iso14443_3a_event->type == Iso14443_3aPollerEventTypeReady) { + const Iso14443_3aData* iso3_data = iso14443_3a_poller_get_data(iso3_poller); + uint8_t atqa0 = iso3_data->atqa[0]; + uint8_t atqa1 = iso3_data->atqa[1]; + uint8_t sak = iso3_data->sak; + if((atqa0 == 0x44 || atqa0 == 0x04) && (sak == 0x08 || sak == 0x88 || sak == 0x09)) { + detected = true; + } else if((atqa0 == 0x01) && (atqa1 == 0x0F) && (sak == 0x01)) { + //skylanders support + detected = true; + } else if((atqa0 == 0x42 || atqa0 == 0x02) && (sak == 0x18)) { + detected = true; + } + } + + return detected; } void mf_classic_poller_set_callback( @@ -333,7 +360,7 @@ const NfcPollerBase mf_classic_poller = { .alloc = (NfcPollerAlloc)mf_classic_poller_alloc, .free = (NfcPollerFree)mf_classic_poller_free, .set_callback = (NfcPollerSetCallback)mf_classic_poller_set_callback, - .run = (NfcPollerRun)mf_classsic_poller_run, - .detect = (NfcPollerDetect)mf_classsic_poller_detect, + .run = (NfcPollerRun)mf_classic_poller_run, + .detect = (NfcPollerDetect)mf_classic_poller_detect, .get_data = (NfcPollerGetData)mf_classic_poller_get_data, }; diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire.c b/lib/nfc/protocols/mf_desfire/mf_desfire.c index 64ee75ee274c..0c5709c5b645 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire.c +++ b/lib/nfc/protocols/mf_desfire/mf_desfire.c @@ -231,3 +231,45 @@ const Iso14443_4aData* mf_desfire_get_base_data(const MfDesfireData* data) { return data->iso14443_4a_data; } + +const MfDesfireApplication* + mf_desfire_get_application(const MfDesfireData* data, const MfDesfireApplicationId* app_id) { + MfDesfireApplication* app = NULL; + + for(uint32_t i = 0; i < simple_array_get_count(data->application_ids); ++i) { + const MfDesfireApplicationId* current_app_id = simple_array_cget(data->application_ids, i); + if(memcmp(app_id, current_app_id, sizeof(MfDesfireApplicationId)) == 0) { + app = simple_array_get(data->applications, i); + } + } + + return app; +} + +const MfDesfireFileSettings* + mf_desfire_get_file_settings(const MfDesfireApplication* data, const MfDesfireFileId* file_id) { + MfDesfireFileSettings* file_settings = NULL; + + for(uint32_t i = 0; i < simple_array_get_count(data->file_ids); ++i) { + const MfDesfireFileId* current_file_id = simple_array_cget(data->file_ids, i); + if(*file_id == *current_file_id) { + file_settings = simple_array_get(data->file_settings, i); + } + } + + return file_settings; +} + +const MfDesfireFileData* + mf_desfire_get_file_data(const MfDesfireApplication* data, const MfDesfireFileId* file_id) { + MfDesfireFileData* file_data = NULL; + + for(uint32_t i = 0; i < simple_array_get_count(data->file_ids); ++i) { + const MfDesfireFileId* current_file_id = simple_array_cget(data->file_ids, i); + if(*file_id == *current_file_id) { + file_data = simple_array_get(data->file_data, i); + } + } + + return file_data; +} diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire.h b/lib/nfc/protocols/mf_desfire/mf_desfire.h index 1b8695b44d24..977c05121458 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire.h +++ b/lib/nfc/protocols/mf_desfire/mf_desfire.h @@ -2,7 +2,7 @@ #include -#include "helpers/simple_array.h" +#include #ifdef __cplusplus extern "C" { @@ -173,6 +173,17 @@ const uint8_t* mf_desfire_get_uid(const MfDesfireData* data, size_t* uid_len); const Iso14443_4aData* mf_desfire_get_base_data(const MfDesfireData* data); +// Getters and tests + +const MfDesfireApplication* + mf_desfire_get_application(const MfDesfireData* data, const MfDesfireApplicationId* app_id); + +const MfDesfireFileSettings* + mf_desfire_get_file_settings(const MfDesfireApplication* data, const MfDesfireFileId* file_id); + +const MfDesfireFileData* + mf_desfire_get_file_data(const MfDesfireApplication* data, const MfDesfireFileId* file_id); + #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/nfc_device_base.h b/lib/nfc/protocols/nfc_device_base.h index acb69ad3bcba..11905e30b115 100644 --- a/lib/nfc/protocols/nfc_device_base.h +++ b/lib/nfc/protocols/nfc_device_base.h @@ -1,7 +1,5 @@ #pragma once -#include - #ifdef __cplusplus extern "C" { #endif @@ -13,33 +11,6 @@ typedef enum { typedef void NfcDeviceData; -typedef NfcDeviceData* (*NfcDeviceAlloc)(); -typedef void (*NfcDeviceFree)(NfcDeviceData* data); -typedef void (*NfcDeviceReset)(NfcDeviceData* data); -typedef void (*NfcDeviceCopy)(NfcDeviceData* data, const NfcDeviceData* other); -typedef bool (*NfcDeviceVerify)(NfcDeviceData* data, const FuriString* device_type); -typedef bool (*NfcDeviceLoad)(NfcDeviceData* data, FlipperFormat* ff, uint32_t version); -typedef bool (*NfcDeviceSave)(const NfcDeviceData* data, FlipperFormat* ff); -typedef bool (*NfcDeviceEqual)(const NfcDeviceData* data, const NfcDeviceData* other); -typedef const char* (*NfcDeviceGetName)(const NfcDeviceData* data, NfcDeviceNameType name_type); -typedef const uint8_t* (*NfcDeviceGetUid)(const NfcDeviceData* data, size_t* uid_len); -typedef const NfcDeviceData* (*NfcDeviceGetBaseData)(const NfcDeviceData* data); - -typedef struct { - const char* protocol_name; - NfcDeviceAlloc alloc; - NfcDeviceFree free; - NfcDeviceReset reset; - NfcDeviceCopy copy; - NfcDeviceVerify verify; - NfcDeviceLoad load; - NfcDeviceSave save; - NfcDeviceEqual is_equal; - NfcDeviceGetName get_name; - NfcDeviceGetUid get_uid; - NfcDeviceGetBaseData get_base_data; -} NfcDeviceBase; - #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/nfc_device_base_i.h b/lib/nfc/protocols/nfc_device_base_i.h new file mode 100644 index 000000000000..ee6569459bc5 --- /dev/null +++ b/lib/nfc/protocols/nfc_device_base_i.h @@ -0,0 +1,40 @@ +#pragma once + +#include "nfc_device_base.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef NfcDeviceData* (*NfcDeviceAlloc)(); +typedef void (*NfcDeviceFree)(NfcDeviceData* data); +typedef void (*NfcDeviceReset)(NfcDeviceData* data); +typedef void (*NfcDeviceCopy)(NfcDeviceData* data, const NfcDeviceData* other); +typedef bool (*NfcDeviceVerify)(NfcDeviceData* data, const FuriString* device_type); +typedef bool (*NfcDeviceLoad)(NfcDeviceData* data, FlipperFormat* ff, uint32_t version); +typedef bool (*NfcDeviceSave)(const NfcDeviceData* data, FlipperFormat* ff); +typedef bool (*NfcDeviceEqual)(const NfcDeviceData* data, const NfcDeviceData* other); +typedef const char* (*NfcDeviceGetName)(const NfcDeviceData* data, NfcDeviceNameType name_type); +typedef const uint8_t* (*NfcDeviceGetUid)(const NfcDeviceData* data, size_t* uid_len); +typedef const NfcDeviceData* (*NfcDeviceGetBaseData)(const NfcDeviceData* data); + +typedef struct { + const char* protocol_name; + NfcDeviceAlloc alloc; + NfcDeviceFree free; + NfcDeviceReset reset; + NfcDeviceCopy copy; + NfcDeviceVerify verify; + NfcDeviceLoad load; + NfcDeviceSave save; + NfcDeviceEqual is_equal; + NfcDeviceGetName get_name; + NfcDeviceGetUid get_uid; + NfcDeviceGetBaseData get_base_data; +} NfcDeviceBase; + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/nfc_device_defs.h b/lib/nfc/protocols/nfc_device_defs.h index 42f8d206ad51..f5ba2563f461 100644 --- a/lib/nfc/protocols/nfc_device_defs.h +++ b/lib/nfc/protocols/nfc_device_defs.h @@ -1,6 +1,6 @@ #pragma once -#include "nfc_device_base.h" +#include "nfc_device_base_i.h" #ifdef __cplusplus extern "C" { diff --git a/lib/toolbox/SConscript b/lib/toolbox/SConscript index 6084969c4c5b..3aaae2fd3416 100644 --- a/lib/toolbox/SConscript +++ b/lib/toolbox/SConscript @@ -30,6 +30,7 @@ env.Append( File("protocols/protocol_dict.h"), File("pretty_format.h"), File("hex.h"), + File("simple_array.h"), ], ) diff --git a/lib/nfc/helpers/simple_array.c b/lib/toolbox/simple_array.c similarity index 100% rename from lib/nfc/helpers/simple_array.c rename to lib/toolbox/simple_array.c diff --git a/lib/nfc/helpers/simple_array.h b/lib/toolbox/simple_array.h similarity index 94% rename from lib/nfc/helpers/simple_array.h rename to lib/toolbox/simple_array.h index 72de4b886a4a..1a3538712d9e 100644 --- a/lib/nfc/helpers/simple_array.h +++ b/lib/toolbox/simple_array.h @@ -3,6 +3,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + typedef struct SimpleArray SimpleArray; typedef void SimpleArrayElement; @@ -35,3 +39,7 @@ SimpleArrayElement* simple_array_get(SimpleArray* instance, uint32_t index); const SimpleArrayElement* simple_array_cget(const SimpleArray* instance, uint32_t index); extern const SimpleArrayConfig simple_array_config_uint8_t; + +#ifdef __cplusplus +} +#endif From 6d74e5130f4096929e495db5ad722ad46ade54ea Mon Sep 17 00:00:00 2001 From: gornekich Date: Tue, 18 Jul 2023 16:02:41 +0400 Subject: [PATCH 125/149] Merge remote-tracking branch 'origin/dev' into gornek/nfc_refactoring --- .vscode/example/tasks.json | 20 +- .../debug/subghz_test/application.fam | 14 + .../subghz_test/helpers/subghz_test_event.h | 7 + .../helpers/subghz_test_frequency.c} | 2 +- .../helpers/subghz_test_frequency.h} | 2 +- .../subghz_test/helpers/subghz_test_types.h | 18 ++ .../images/DolphinCommon_56x48.png | Bin 0 -> 1416 bytes .../debug/subghz_test/protocol/math.c | 244 ++++++++++++++++ .../debug/subghz_test/protocol/math.h | 222 +++++++++++++++ .../protocol}/princeton_for_testing.c | 2 +- .../protocol}/princeton_for_testing.h | 4 +- .../subghz_test/scenes/subghz_test_scene.c | 30 ++ .../subghz_test/scenes/subghz_test_scene.h | 29 ++ .../scenes/subghz_test_scene_about.c | 66 +++++ .../scenes/subghz_test_scene_carrier.c | 29 ++ .../scenes/subghz_test_scene_config.h | 6 + .../scenes/subghz_test_scene_packet.c | 29 ++ .../scenes/subghz_test_scene_show_only_rx.c | 49 ++++ .../scenes/subghz_test_scene_start.c | 77 ++++++ .../scenes/subghz_test_scene_static.c | 29 ++ .../debug/subghz_test/subghz_test_10px.png | Bin 0 -> 181 bytes .../debug/subghz_test/subghz_test_app.c | 139 ++++++++++ .../debug/subghz_test/subghz_test_app_i.c | 5 + .../debug/subghz_test/subghz_test_app_i.h | 32 +++ .../subghz_test}/views/subghz_test_carrier.c | 4 +- .../subghz_test}/views/subghz_test_carrier.h | 0 .../subghz_test}/views/subghz_test_packet.c | 6 +- .../subghz_test}/views/subghz_test_packet.h | 0 .../subghz_test}/views/subghz_test_static.c | 6 +- .../subghz_test}/views/subghz_test_static.h | 0 .../debug/unit_tests/infrared/infrared_test.c | 12 + applications/debug/unit_tests/nfc/nfc_test.c | 6 + .../debug/unit_tests/nfc/nfc_test_old.c | 73 ++++- applications/drivers/subghz/application.fam | 1 + .../drivers/subghz/cc1101_ext/cc1101_ext.c | 55 +++- .../examples/example_thermo/README.md | 2 +- .../external/picopass/picopass_device.c | 3 + .../external/picopass/picopass_device.h | 1 + .../external/picopass/picopass_worker.c | 3 +- .../picopass/scenes/picopass_scene_key_menu.c | 8 +- .../weather_station/protocols/oregon3.c | 8 +- applications/main/application.fam | 15 + .../main/archive/helpers/archive_browser.c | 34 ++- .../main/archive/helpers/archive_browser.h | 1 + .../archive/scenes/archive_scene_browser.c | 3 +- .../main/archive/views/archive_browser_view.c | 26 +- applications/main/bad_usb/application.fam | 9 +- applications/main/bad_usb/icon.png | Bin 0 -> 576 bytes applications/main/gpio/application.fam | 6 +- applications/main/gpio/icon.png | Bin 0 -> 1760 bytes applications/main/ibutton/application.fam | 12 +- applications/main/ibutton/icon.png | Bin 0 -> 304 bytes .../scenes/ibutton_scene_delete_confirm.c | 8 +- applications/main/infrared/application.fam | 12 +- applications/main/infrared/icon.png | Bin 0 -> 305 bytes applications/main/lfrfid/application.fam | 14 +- applications/main/lfrfid/icon.png | Bin 0 -> 308 bytes applications/main/nfc_old/application.fam | 17 +- applications/main/nfc_old/icon.png | Bin 0 -> 304 bytes applications/main/onewire/application.fam | 8 - applications/main/subghz/application.fam | 14 +- .../main/subghz/helpers/subghz_txrx.c | 16 +- .../main/subghz/helpers/subghz_types.h | 3 - applications/main/subghz/icon.png | Bin 0 -> 299 bytes .../main/subghz/scenes/subghz_scene_config.h | 4 - .../main/subghz/scenes/subghz_scene_start.c | 10 - .../main/subghz/scenes/subghz_scene_test.c | 61 ---- .../subghz/scenes/subghz_scene_test_carrier.c | 30 -- .../subghz/scenes/subghz_scene_test_packet.c | 30 -- .../subghz/scenes/subghz_scene_test_static.c | 30 -- applications/main/subghz/subghz.c | 33 --- applications/main/subghz/subghz_cli.c | 34 ++- applications/main/subghz/subghz_i.h | 7 - applications/main/u2f/application.fam | 9 +- applications/main/u2f/icon.png | Bin 0 -> 583 bytes applications/services/applications.h | 12 + applications/services/cli/cli_commands.c | 50 ++-- .../services/desktop/desktop_settings.h | 3 +- .../desktop/scenes/desktop_scene_debug.c | 23 +- .../desktop/views/desktop_view_debug.c | 213 +++++--------- .../desktop/views/desktop_view_debug.h | 19 +- .../services/gui/modules/file_browser.c | 39 ++- applications/services/loader/loader.c | 58 +++- .../services/loader/loader_applications.c | 69 +++-- applications/services/loader/loader_menu.c | 21 +- .../services/power/power_service/power.c | 3 +- .../services/power/power_service/power.h | 1 + .../services/storage/storage_external_api.c | 14 + applications/settings/about/about.c | 4 +- .../scenes/desktop_settings_scene_favorite.c | 75 +++-- .../power_settings_app/views/battery_info.c | 3 +- .../system/updater/util/update_task.c | 192 ++++++++++++- .../system/updater/util/update_task_i.h | 5 + .../updater/util/update_task_worker_backup.c | 5 - .../updater/util/update_task_worker_flasher.c | 26 +- .../system/updater/views/updater_main.c | 15 +- .../external/L1_My_dude_128x64/frame_0.png | Bin 0 -> 1615 bytes .../external/L1_My_dude_128x64/frame_1.png | Bin 0 -> 1637 bytes .../external/L1_My_dude_128x64/frame_10.png | Bin 0 -> 1044 bytes .../external/L1_My_dude_128x64/frame_11.png | Bin 0 -> 990 bytes .../external/L1_My_dude_128x64/frame_12.png | Bin 0 -> 1100 bytes .../external/L1_My_dude_128x64/frame_13.png | Bin 0 -> 1494 bytes .../external/L1_My_dude_128x64/frame_14.png | Bin 0 -> 1460 bytes .../external/L1_My_dude_128x64/frame_15.png | Bin 0 -> 1440 bytes .../external/L1_My_dude_128x64/frame_16.png | Bin 0 -> 1210 bytes .../external/L1_My_dude_128x64/frame_17.png | Bin 0 -> 1399 bytes .../external/L1_My_dude_128x64/frame_18.png | Bin 0 -> 1454 bytes .../external/L1_My_dude_128x64/frame_19.png | Bin 0 -> 1648 bytes .../external/L1_My_dude_128x64/frame_2.png | Bin 0 -> 1629 bytes .../external/L1_My_dude_128x64/frame_20.png | Bin 0 -> 1433 bytes .../external/L1_My_dude_128x64/frame_21.png | Bin 0 -> 1032 bytes .../external/L1_My_dude_128x64/frame_22.png | Bin 0 -> 1054 bytes .../external/L1_My_dude_128x64/frame_23.png | Bin 0 -> 1050 bytes .../external/L1_My_dude_128x64/frame_24.png | Bin 0 -> 939 bytes .../external/L1_My_dude_128x64/frame_25.png | Bin 0 -> 1447 bytes .../external/L1_My_dude_128x64/frame_26.png | Bin 0 -> 1509 bytes .../external/L1_My_dude_128x64/frame_27.png | Bin 0 -> 1504 bytes .../external/L1_My_dude_128x64/frame_28.png | Bin 0 -> 1529 bytes .../external/L1_My_dude_128x64/frame_29.png | Bin 0 -> 1625 bytes .../external/L1_My_dude_128x64/frame_3.png | Bin 0 -> 1599 bytes .../external/L1_My_dude_128x64/frame_30.png | Bin 0 -> 1575 bytes .../external/L1_My_dude_128x64/frame_31.png | Bin 0 -> 1609 bytes .../external/L1_My_dude_128x64/frame_32.png | Bin 0 -> 1635 bytes .../external/L1_My_dude_128x64/frame_33.png | Bin 0 -> 1668 bytes .../external/L1_My_dude_128x64/frame_34.png | Bin 0 -> 1588 bytes .../external/L1_My_dude_128x64/frame_35.png | Bin 0 -> 1551 bytes .../external/L1_My_dude_128x64/frame_36.png | Bin 0 -> 1656 bytes .../external/L1_My_dude_128x64/frame_37.png | Bin 0 -> 1545 bytes .../external/L1_My_dude_128x64/frame_38.png | Bin 0 -> 1650 bytes .../external/L1_My_dude_128x64/frame_39.png | Bin 0 -> 1028 bytes .../external/L1_My_dude_128x64/frame_4.png | Bin 0 -> 1623 bytes .../external/L1_My_dude_128x64/frame_40.png | Bin 0 -> 1225 bytes .../external/L1_My_dude_128x64/frame_41.png | Bin 0 -> 1256 bytes .../external/L1_My_dude_128x64/frame_42.png | Bin 0 -> 1055 bytes .../external/L1_My_dude_128x64/frame_43.png | Bin 0 -> 831 bytes .../external/L1_My_dude_128x64/frame_44.png | Bin 0 -> 623 bytes .../external/L1_My_dude_128x64/frame_45.png | Bin 0 -> 556 bytes .../external/L1_My_dude_128x64/frame_46.png | Bin 0 -> 928 bytes .../external/L1_My_dude_128x64/frame_47.png | Bin 0 -> 1206 bytes .../external/L1_My_dude_128x64/frame_48.png | Bin 0 -> 1019 bytes .../external/L1_My_dude_128x64/frame_5.png | Bin 0 -> 1648 bytes .../external/L1_My_dude_128x64/frame_6.png | Bin 0 -> 1570 bytes .../external/L1_My_dude_128x64/frame_7.png | Bin 0 -> 1063 bytes .../external/L1_My_dude_128x64/frame_8.png | Bin 0 -> 1024 bytes .../external/L1_My_dude_128x64/frame_9.png | Bin 0 -> 1078 bytes .../external/L1_My_dude_128x64/meta.txt | 32 +++ assets/dolphin/external/manifest.txt | 7 + assets/icons/About/Certification2_46x33.png | Bin 0 -> 229 bytes assets/icons/About/Certification2_98x33.png | Bin 2495 -> 0 bytes assets/protobuf | 2 +- .../picopass/assets/iclass_elite_dict.txt | 4 + .../badusb/Install_qFlipper_windows.txt | 42 +++ assets/resources/infrared/assets/ac.ir | 74 +++++ assets/resources/infrared/assets/tv.ir | 36 +++ assets/unit_tests/infrared/test_rca.irtest | 105 +++++++ documentation/AppsOnSDCard.md | 3 +- documentation/OTA.md | 7 +- .../file_formats/InfraredFileFormats.md | 17 ++ firmware/targets/f18/api_symbols.csv | 261 +++++++++++++++--- .../f18/furi_hal/furi_hal_power_calibration.h | 37 --- .../f18/furi_hal/furi_hal_power_config.c | 149 ++++++++++ .../f18/furi_hal/furi_hal_version_device.c | 12 +- firmware/targets/f7/api_symbols.csv | 138 ++++----- .../targets/f7/furi_hal/furi_hal_infrared.c | 3 - .../targets/f7/furi_hal/furi_hal_interrupt.c | 10 +- firmware/targets/f7/furi_hal/furi_hal_power.c | 60 +++- .../f7/furi_hal/furi_hal_power_calibration.h | 37 --- .../f7/furi_hal/furi_hal_power_config.c | 149 ++++++++++ .../targets/f7/furi_hal/furi_hal_spi_config.c | 49 +++- .../f7/furi_hal/furi_hal_version_device.c | 4 + .../f7/platform_specific/intrinsic_export.h | 1 + .../f7/platform_specific/math_wrapper.h | 2 + .../targets/furi_hal_include/furi_hal_power.h | 12 +- .../furi_hal_include/furi_hal_version.h | 6 + furi/core/check.c | 2 +- furi/core/log.c | 35 +++ furi/core/log.h | 18 ++ lib/drivers/SConscript | 3 + lib/drivers/bq25896.c | 26 +- lib/drivers/bq25896.h | 5 +- lib/drivers/bq25896_reg.h | 18 +- lib/drivers/bq27220.c | 248 ++++++++++++----- lib/drivers/bq27220.h | 60 +--- lib/drivers/bq27220_data_memory.h | 84 ++++++ lib/drivers/bq27220_reg.h | 25 -- lib/drivers/cc1101.c | 83 +++--- lib/drivers/cc1101.h | 28 +- lib/drivers/cc1101_regs.h | 2 +- lib/infrared/encoder_decoder/infrared.c | 15 + lib/infrared/encoder_decoder/infrared.h | 1 + .../rca/infrared_decoder_rca.c | 45 +++ .../rca/infrared_encoder_rca.c | 37 +++ .../rca/infrared_protocol_rca.c | 40 +++ .../rca/infrared_protocol_rca.h | 30 ++ .../rca/infrared_protocol_rca_i.h | 30 ++ lib/subghz/SConscript | 1 + lib/subghz/subghz_protocol_registry.h | 25 ++ lib/update_util/update_operation.c | 21 +- lib/update_util/update_operation.h | 3 +- scripts/fbt/appmanifest.py | 34 ++- scripts/fbt_tools/fbt_extapps.py | 60 ++-- scripts/fbt_tools/fbt_help.py | 5 +- scripts/toolchain/fbtenv.cmd | 2 +- scripts/toolchain/fbtenv.sh | 2 +- scripts/ufbt/SConstruct | 3 + site_scons/extapps.scons | 15 +- 206 files changed, 3675 insertions(+), 1129 deletions(-) create mode 100644 applications/debug/subghz_test/application.fam create mode 100644 applications/debug/subghz_test/helpers/subghz_test_event.h rename applications/{main/subghz/helpers/subghz_testing.c => debug/subghz_test/helpers/subghz_test_frequency.c} (95%) rename applications/{main/subghz/helpers/subghz_testing.h => debug/subghz_test/helpers/subghz_test_frequency.h} (84%) create mode 100644 applications/debug/subghz_test/helpers/subghz_test_types.h create mode 100644 applications/debug/subghz_test/images/DolphinCommon_56x48.png create mode 100644 applications/debug/subghz_test/protocol/math.c create mode 100644 applications/debug/subghz_test/protocol/math.h rename {lib/subghz/protocols => applications/debug/subghz_test/protocol}/princeton_for_testing.c (99%) rename {lib/subghz/protocols => applications/debug/subghz_test/protocol}/princeton_for_testing.h (97%) create mode 100644 applications/debug/subghz_test/scenes/subghz_test_scene.c create mode 100644 applications/debug/subghz_test/scenes/subghz_test_scene.h create mode 100644 applications/debug/subghz_test/scenes/subghz_test_scene_about.c create mode 100644 applications/debug/subghz_test/scenes/subghz_test_scene_carrier.c create mode 100644 applications/debug/subghz_test/scenes/subghz_test_scene_config.h create mode 100644 applications/debug/subghz_test/scenes/subghz_test_scene_packet.c create mode 100644 applications/debug/subghz_test/scenes/subghz_test_scene_show_only_rx.c create mode 100644 applications/debug/subghz_test/scenes/subghz_test_scene_start.c create mode 100644 applications/debug/subghz_test/scenes/subghz_test_scene_static.c create mode 100644 applications/debug/subghz_test/subghz_test_10px.png create mode 100644 applications/debug/subghz_test/subghz_test_app.c create mode 100644 applications/debug/subghz_test/subghz_test_app_i.c create mode 100644 applications/debug/subghz_test/subghz_test_app_i.h rename applications/{main/subghz => debug/subghz_test}/views/subghz_test_carrier.c (98%) rename applications/{main/subghz => debug/subghz_test}/views/subghz_test_carrier.h (100%) rename applications/{main/subghz => debug/subghz_test}/views/subghz_test_packet.c (98%) rename applications/{main/subghz => debug/subghz_test}/views/subghz_test_packet.h (100%) rename applications/{main/subghz => debug/subghz_test}/views/subghz_test_static.c (98%) rename applications/{main/subghz => debug/subghz_test}/views/subghz_test_static.h (100%) create mode 100644 applications/main/bad_usb/icon.png create mode 100644 applications/main/gpio/icon.png create mode 100644 applications/main/ibutton/icon.png create mode 100644 applications/main/infrared/icon.png create mode 100644 applications/main/lfrfid/icon.png create mode 100644 applications/main/nfc_old/icon.png create mode 100644 applications/main/subghz/icon.png delete mode 100644 applications/main/subghz/scenes/subghz_scene_test.c delete mode 100644 applications/main/subghz/scenes/subghz_scene_test_carrier.c delete mode 100644 applications/main/subghz/scenes/subghz_scene_test_packet.c delete mode 100644 applications/main/subghz/scenes/subghz_scene_test_static.c create mode 100644 applications/main/u2f/icon.png create mode 100644 assets/dolphin/external/L1_My_dude_128x64/frame_0.png create mode 100644 assets/dolphin/external/L1_My_dude_128x64/frame_1.png create mode 100644 assets/dolphin/external/L1_My_dude_128x64/frame_10.png create mode 100644 assets/dolphin/external/L1_My_dude_128x64/frame_11.png create mode 100644 assets/dolphin/external/L1_My_dude_128x64/frame_12.png create mode 100644 assets/dolphin/external/L1_My_dude_128x64/frame_13.png create mode 100644 assets/dolphin/external/L1_My_dude_128x64/frame_14.png create mode 100644 assets/dolphin/external/L1_My_dude_128x64/frame_15.png create mode 100644 assets/dolphin/external/L1_My_dude_128x64/frame_16.png create mode 100644 assets/dolphin/external/L1_My_dude_128x64/frame_17.png create mode 100644 assets/dolphin/external/L1_My_dude_128x64/frame_18.png create mode 100644 assets/dolphin/external/L1_My_dude_128x64/frame_19.png create mode 100644 assets/dolphin/external/L1_My_dude_128x64/frame_2.png create mode 100644 assets/dolphin/external/L1_My_dude_128x64/frame_20.png create mode 100644 assets/dolphin/external/L1_My_dude_128x64/frame_21.png create mode 100644 assets/dolphin/external/L1_My_dude_128x64/frame_22.png create mode 100644 assets/dolphin/external/L1_My_dude_128x64/frame_23.png create mode 100644 assets/dolphin/external/L1_My_dude_128x64/frame_24.png create mode 100644 assets/dolphin/external/L1_My_dude_128x64/frame_25.png create mode 100644 assets/dolphin/external/L1_My_dude_128x64/frame_26.png create mode 100644 assets/dolphin/external/L1_My_dude_128x64/frame_27.png create mode 100644 assets/dolphin/external/L1_My_dude_128x64/frame_28.png create mode 100644 assets/dolphin/external/L1_My_dude_128x64/frame_29.png create mode 100644 assets/dolphin/external/L1_My_dude_128x64/frame_3.png create mode 100644 assets/dolphin/external/L1_My_dude_128x64/frame_30.png create mode 100644 assets/dolphin/external/L1_My_dude_128x64/frame_31.png create mode 100644 assets/dolphin/external/L1_My_dude_128x64/frame_32.png create mode 100644 assets/dolphin/external/L1_My_dude_128x64/frame_33.png create mode 100644 assets/dolphin/external/L1_My_dude_128x64/frame_34.png create mode 100644 assets/dolphin/external/L1_My_dude_128x64/frame_35.png create mode 100644 assets/dolphin/external/L1_My_dude_128x64/frame_36.png create mode 100644 assets/dolphin/external/L1_My_dude_128x64/frame_37.png create mode 100644 assets/dolphin/external/L1_My_dude_128x64/frame_38.png create mode 100644 assets/dolphin/external/L1_My_dude_128x64/frame_39.png create mode 100644 assets/dolphin/external/L1_My_dude_128x64/frame_4.png create mode 100644 assets/dolphin/external/L1_My_dude_128x64/frame_40.png create mode 100644 assets/dolphin/external/L1_My_dude_128x64/frame_41.png create mode 100644 assets/dolphin/external/L1_My_dude_128x64/frame_42.png create mode 100644 assets/dolphin/external/L1_My_dude_128x64/frame_43.png create mode 100644 assets/dolphin/external/L1_My_dude_128x64/frame_44.png create mode 100644 assets/dolphin/external/L1_My_dude_128x64/frame_45.png create mode 100644 assets/dolphin/external/L1_My_dude_128x64/frame_46.png create mode 100644 assets/dolphin/external/L1_My_dude_128x64/frame_47.png create mode 100644 assets/dolphin/external/L1_My_dude_128x64/frame_48.png create mode 100644 assets/dolphin/external/L1_My_dude_128x64/frame_5.png create mode 100644 assets/dolphin/external/L1_My_dude_128x64/frame_6.png create mode 100644 assets/dolphin/external/L1_My_dude_128x64/frame_7.png create mode 100644 assets/dolphin/external/L1_My_dude_128x64/frame_8.png create mode 100644 assets/dolphin/external/L1_My_dude_128x64/frame_9.png create mode 100644 assets/dolphin/external/L1_My_dude_128x64/meta.txt create mode 100644 assets/icons/About/Certification2_46x33.png delete mode 100644 assets/icons/About/Certification2_98x33.png create mode 100644 assets/resources/badusb/Install_qFlipper_windows.txt create mode 100644 assets/unit_tests/infrared/test_rca.irtest delete mode 100644 firmware/targets/f18/furi_hal/furi_hal_power_calibration.h create mode 100644 firmware/targets/f18/furi_hal/furi_hal_power_config.c delete mode 100644 firmware/targets/f7/furi_hal/furi_hal_power_calibration.h create mode 100644 firmware/targets/f7/furi_hal/furi_hal_power_config.c create mode 100644 firmware/targets/f7/platform_specific/math_wrapper.h create mode 100644 lib/drivers/bq27220_data_memory.h create mode 100644 lib/infrared/encoder_decoder/rca/infrared_decoder_rca.c create mode 100644 lib/infrared/encoder_decoder/rca/infrared_encoder_rca.c create mode 100644 lib/infrared/encoder_decoder/rca/infrared_protocol_rca.c create mode 100644 lib/infrared/encoder_decoder/rca/infrared_protocol_rca.h create mode 100644 lib/infrared/encoder_decoder/rca/infrared_protocol_rca_i.h diff --git a/.vscode/example/tasks.json b/.vscode/example/tasks.json index 28e67d456dc8..3c01506a8c11 100644 --- a/.vscode/example/tasks.json +++ b/.vscode/example/tasks.json @@ -4,13 +4,13 @@ "version": "2.0.0", "tasks": [ { - "label": "[Release] Build", + "label": "[Release] Build Firmware", "group": "build", "type": "shell", "command": "./fbt COMPACT=1 DEBUG=0" }, { - "label": "[Debug] Build", + "label": "[Debug] Build Firmware", "group": "build", "type": "shell", "command": "./fbt" @@ -123,17 +123,29 @@ "type": "shell", "command": "./fbt COMPACT=1 DEBUG=0 fap_dist" }, + { + "label": "[Debug] Build App", + "group": "build", + "type": "shell", + "command": "./fbt build APPSRC=${relativeFileDirname}" + }, + { + "label": "[Release] Build App", + "group": "build", + "type": "shell", + "command": "./fbt COMPACT=1 DEBUG=0 build APPSRC=${relativeFileDirname}" + }, { "label": "[Debug] Launch App on Flipper", "group": "build", "type": "shell", - "command": "./fbt launch_app APPSRC=${relativeFileDirname}" + "command": "./fbt launch APPSRC=${relativeFileDirname}" }, { "label": "[Release] Launch App on Flipper", "group": "build", "type": "shell", - "command": "./fbt COMPACT=1 DEBUG=0 launch_app APPSRC=${relativeFileDirname}" + "command": "./fbt COMPACT=1 DEBUG=0 launch APPSRC=${relativeFileDirname}" }, { "label": "[Debug] Launch App on Flipper with Serial Console", diff --git a/applications/debug/subghz_test/application.fam b/applications/debug/subghz_test/application.fam new file mode 100644 index 000000000000..1b3e19d73f9c --- /dev/null +++ b/applications/debug/subghz_test/application.fam @@ -0,0 +1,14 @@ +App( + appid="subghz_test", + name="Sub-Ghz test", + apptype=FlipperAppType.DEBUG, + targets=["f7"], + entry_point="subghz_test_app", + requires=["gui"], + stack_size=4 * 1024, + order=50, + fap_icon="subghz_test_10px.png", + fap_category="Debug", + fap_icon_assets="images", + fap_version="0.1", +) diff --git a/applications/debug/subghz_test/helpers/subghz_test_event.h b/applications/debug/subghz_test/helpers/subghz_test_event.h new file mode 100644 index 000000000000..a0a851976ad8 --- /dev/null +++ b/applications/debug/subghz_test/helpers/subghz_test_event.h @@ -0,0 +1,7 @@ +#pragma once + +typedef enum { + //SubGhzTestCustomEvent + SubGhzTestCustomEventStartId = 100, + SubGhzTestCustomEventSceneShowOnlyRX, +} SubGhzTestCustomEvent; diff --git a/applications/main/subghz/helpers/subghz_testing.c b/applications/debug/subghz_test/helpers/subghz_test_frequency.c similarity index 95% rename from applications/main/subghz/helpers/subghz_testing.c rename to applications/debug/subghz_test/helpers/subghz_test_frequency.c index 8afa868e0126..ed1ba704e4de 100644 --- a/applications/main/subghz/helpers/subghz_testing.c +++ b/applications/debug/subghz_test/helpers/subghz_test_frequency.c @@ -1,4 +1,4 @@ -#include "subghz_testing.h" +#include "subghz_test_frequency.h" const uint32_t subghz_frequencies_testing[] = { /* 300 - 348 */ diff --git a/applications/main/subghz/helpers/subghz_testing.h b/applications/debug/subghz_test/helpers/subghz_test_frequency.h similarity index 84% rename from applications/main/subghz/helpers/subghz_testing.h rename to applications/debug/subghz_test/helpers/subghz_test_frequency.h index 29ce578a0106..7dd1423f968e 100644 --- a/applications/main/subghz/helpers/subghz_testing.h +++ b/applications/debug/subghz_test/helpers/subghz_test_frequency.h @@ -1,5 +1,5 @@ #pragma once -#include "../subghz_i.h" +#include "../subghz_test_app_i.h" extern const uint32_t subghz_frequencies_testing[]; extern const uint32_t subghz_frequencies_count_testing; diff --git a/applications/debug/subghz_test/helpers/subghz_test_types.h b/applications/debug/subghz_test/helpers/subghz_test_types.h new file mode 100644 index 000000000000..03be6459ec13 --- /dev/null +++ b/applications/debug/subghz_test/helpers/subghz_test_types.h @@ -0,0 +1,18 @@ +#pragma once + +#include +#include + +#define SUBGHZ_TEST_VERSION_APP "0.1" +#define SUBGHZ_TEST_DEVELOPED "SkorP" +#define SUBGHZ_TEST_GITHUB "https://github.com/flipperdevices/flipperzero-firmware" + +typedef enum { + SubGhzTestViewVariableItemList, + SubGhzTestViewSubmenu, + SubGhzTestViewStatic, + SubGhzTestViewCarrier, + SubGhzTestViewPacket, + SubGhzTestViewWidget, + SubGhzTestViewPopup, +} SubGhzTestView; diff --git a/applications/debug/subghz_test/images/DolphinCommon_56x48.png b/applications/debug/subghz_test/images/DolphinCommon_56x48.png new file mode 100644 index 0000000000000000000000000000000000000000..089aaed83507431993a76ca25d32fdd9664c1c84 GIT binary patch literal 1416 zcmaJ>eNYr-7(dh;KXS5&nWVIBjS_NizYg|x=Pr^vz*7zxJO|P-dw2IeZq?gec9-rD zoPZchQ_6}yP{Slc4I!!28K==nodOJ_nsCY-(wOq2uZbLx!rlYU{KIi)_Wj!D_j`WN z^FGgREXdEDF)ewT&1Re7Tj(uBvlG44lnH3;I%IzsO|z`*Vr!`uv?9QOwgs{#Ld+Ki zC9n_zxxBOkx@@+IwMwAaD)#3Ik`}gun2kLe))Crfb7e+#AgzHGCc+X$b>qJuIf`S7 z?8b}I{ghw#z>uiaLknQh@LJUrqHcVYS3v97F^OZN zCe|7^J|?QzUx0Zu17e(=CM1fYFpjtLk|a4~$g}e?hGH0!VoBOT&<=s(1ct%J9~?O} z$)jW_dkX9yTX~%W*i_IM%0{ z7EmP^_pKn`<5>E(SixgJU};7`)7Hidp&+DLnizsebUk}_-GfgbN^il9b`v)f+ z{o5Zry)d<7`fHQ^uw_;+x>mcPw0&8iW69x{k92O{Q}`yFdH=5d$pbf49w1&NS)G+vhr6y}5TMsofQirRDUmKilk5=(KGouJ{H9hW=$X zgi;)vI!jl!_4H3jD(?Jz=8By|i47I&tKA1y9{nfp;_|FxKBDNWp{hN9hJ1nU?z%J6 z?>UxyzWvO}Pgc~rCZ#5%Eq+_hNS~bBdiGlT&f%%e`hHjSySR2=JuK2^+%;$R3#Wz~ z=e_mfqW23bPa0fhe)HdE5+GelU&!jS3ckUZOQ)CC5?mo zo=tzG_4|RuvPUO|mhCwA>y)1c%SWC%a4?a-x|J*?ch~+n=R7o@>p6J2dE=$stKZmK z-xoTRwET2^Wu)&1U7!Ebw!!D?x`xwQX3pMnrRwCT?`4GHt4&?|cIiI{_^XYp-np>6 xE^lPSXzOYCC4X`6tl@OB1M5_S7jml-Y~(TPp{aTIejNKZ`m*!Atyxdk{0EAy49frj literal 0 HcmV?d00001 diff --git a/applications/debug/subghz_test/protocol/math.c b/applications/debug/subghz_test/protocol/math.c new file mode 100644 index 000000000000..24202ad1c628 --- /dev/null +++ b/applications/debug/subghz_test/protocol/math.c @@ -0,0 +1,244 @@ +#include "math.h" + +uint64_t subghz_protocol_blocks_reverse_key(uint64_t key, uint8_t bit_count) { + uint64_t reverse_key = 0; + for(uint8_t i = 0; i < bit_count; i++) { + reverse_key = reverse_key << 1 | bit_read(key, i); + } + return reverse_key; +} + +uint8_t subghz_protocol_blocks_get_parity(uint64_t key, uint8_t bit_count) { + uint8_t parity = 0; + for(uint8_t i = 0; i < bit_count; i++) { + parity += bit_read(key, i); + } + return parity & 0x01; +} + +uint8_t subghz_protocol_blocks_crc4( + uint8_t const message[], + size_t size, + uint8_t polynomial, + uint8_t init) { + uint8_t remainder = init << 4; // LSBs are unused + uint8_t poly = polynomial << 4; + uint8_t bit; + + while(size--) { + remainder ^= *message++; + for(bit = 0; bit < 8; bit++) { + if(remainder & 0x80) { + remainder = (remainder << 1) ^ poly; + } else { + remainder = (remainder << 1); + } + } + } + return remainder >> 4 & 0x0f; // discard the LSBs +} + +uint8_t subghz_protocol_blocks_crc7( + uint8_t const message[], + size_t size, + uint8_t polynomial, + uint8_t init) { + uint8_t remainder = init << 1; // LSB is unused + uint8_t poly = polynomial << 1; + + for(size_t byte = 0; byte < size; ++byte) { + remainder ^= message[byte]; + for(uint8_t bit = 0; bit < 8; ++bit) { + if(remainder & 0x80) { + remainder = (remainder << 1) ^ poly; + } else { + remainder = (remainder << 1); + } + } + } + return remainder >> 1 & 0x7f; // discard the LSB +} + +uint8_t subghz_protocol_blocks_crc8( + uint8_t const message[], + size_t size, + uint8_t polynomial, + uint8_t init) { + uint8_t remainder = init; + + for(size_t byte = 0; byte < size; ++byte) { + remainder ^= message[byte]; + for(uint8_t bit = 0; bit < 8; ++bit) { + if(remainder & 0x80) { + remainder = (remainder << 1) ^ polynomial; + } else { + remainder = (remainder << 1); + } + } + } + return remainder; +} + +uint8_t subghz_protocol_blocks_crc8le( + uint8_t const message[], + size_t size, + uint8_t polynomial, + uint8_t init) { + uint8_t remainder = subghz_protocol_blocks_reverse_key(init, 8); + polynomial = subghz_protocol_blocks_reverse_key(polynomial, 8); + + for(size_t byte = 0; byte < size; ++byte) { + remainder ^= message[byte]; + for(uint8_t bit = 0; bit < 8; ++bit) { + if(remainder & 1) { + remainder = (remainder >> 1) ^ polynomial; + } else { + remainder = (remainder >> 1); + } + } + } + return remainder; +} + +uint16_t subghz_protocol_blocks_crc16lsb( + uint8_t const message[], + size_t size, + uint16_t polynomial, + uint16_t init) { + uint16_t remainder = init; + + for(size_t byte = 0; byte < size; ++byte) { + remainder ^= message[byte]; + for(uint8_t bit = 0; bit < 8; ++bit) { + if(remainder & 1) { + remainder = (remainder >> 1) ^ polynomial; + } else { + remainder = (remainder >> 1); + } + } + } + return remainder; +} + +uint16_t subghz_protocol_blocks_crc16( + uint8_t const message[], + size_t size, + uint16_t polynomial, + uint16_t init) { + uint16_t remainder = init; + + for(size_t byte = 0; byte < size; ++byte) { + remainder ^= message[byte] << 8; + for(uint8_t bit = 0; bit < 8; ++bit) { + if(remainder & 0x8000) { + remainder = (remainder << 1) ^ polynomial; + } else { + remainder = (remainder << 1); + } + } + } + return remainder; +} + +uint8_t subghz_protocol_blocks_lfsr_digest8( + uint8_t const message[], + size_t size, + uint8_t gen, + uint8_t key) { + uint8_t sum = 0; + for(size_t byte = 0; byte < size; ++byte) { + uint8_t data = message[byte]; + for(int i = 7; i >= 0; --i) { + // XOR key into sum if data bit is set + if((data >> i) & 1) sum ^= key; + + // roll the key right (actually the LSB is dropped here) + // and apply the gen (needs to include the dropped LSB as MSB) + if(key & 1) + key = (key >> 1) ^ gen; + else + key = (key >> 1); + } + } + return sum; +} + +uint8_t subghz_protocol_blocks_lfsr_digest8_reflect( + uint8_t const message[], + size_t size, + uint8_t gen, + uint8_t key) { + uint8_t sum = 0; + // Process message from last byte to first byte (reflected) + for(int byte = size - 1; byte >= 0; --byte) { + uint8_t data = message[byte]; + // Process individual bits of each byte (reflected) + for(uint8_t i = 0; i < 8; ++i) { + // XOR key into sum if data bit is set + if((data >> i) & 1) { + sum ^= key; + } + + // roll the key left (actually the LSB is dropped here) + // and apply the gen (needs to include the dropped lsb as MSB) + if(key & 0x80) + key = (key << 1) ^ gen; + else + key = (key << 1); + } + } + return sum; +} + +uint16_t subghz_protocol_blocks_lfsr_digest16( + uint8_t const message[], + size_t size, + uint16_t gen, + uint16_t key) { + uint16_t sum = 0; + for(size_t byte = 0; byte < size; ++byte) { + uint8_t data = message[byte]; + for(int8_t i = 7; i >= 0; --i) { + // if data bit is set then xor with key + if((data >> i) & 1) sum ^= key; + + // roll the key right (actually the LSB is dropped here) + // and apply the gen (needs to include the dropped LSB as MSB) + if(key & 1) + key = (key >> 1) ^ gen; + else + key = (key >> 1); + } + } + return sum; +} + +uint8_t subghz_protocol_blocks_add_bytes(uint8_t const message[], size_t size) { + uint32_t result = 0; + for(size_t i = 0; i < size; ++i) { + result += message[i]; + } + return (uint8_t)result; +} + +uint8_t subghz_protocol_blocks_parity8(uint8_t byte) { + byte ^= byte >> 4; + byte &= 0xf; + return (0x6996 >> byte) & 1; +} + +uint8_t subghz_protocol_blocks_parity_bytes(uint8_t const message[], size_t size) { + uint8_t result = 0; + for(size_t i = 0; i < size; ++i) { + result ^= subghz_protocol_blocks_parity8(message[i]); + } + return result; +} + +uint8_t subghz_protocol_blocks_xor_bytes(uint8_t const message[], size_t size) { + uint8_t result = 0; + for(size_t i = 0; i < size; ++i) { + result ^= message[i]; + } + return result; +} \ No newline at end of file diff --git a/applications/debug/subghz_test/protocol/math.h b/applications/debug/subghz_test/protocol/math.h new file mode 100644 index 000000000000..dcea3da5faf0 --- /dev/null +++ b/applications/debug/subghz_test/protocol/math.h @@ -0,0 +1,222 @@ +#pragma once + +#include +#include +#include + +#define bit_read(value, bit) (((value) >> (bit)) & 0x01) +#define bit_set(value, bit) \ + ({ \ + __typeof__(value) _one = (1); \ + (value) |= (_one << (bit)); \ + }) +#define bit_clear(value, bit) \ + ({ \ + __typeof__(value) _one = (1); \ + (value) &= ~(_one << (bit)); \ + }) +#define bit_write(value, bit, bitvalue) (bitvalue ? bit_set(value, bit) : bit_clear(value, bit)) +#define DURATION_DIFF(x, y) (((x) < (y)) ? ((y) - (x)) : ((x) - (y))) + +#ifdef __cplusplus +extern "C" { +#endif + +/** Flip the data bitwise + * + * @param key In data + * @param bit_count number of data bits + * + * @return Reverse data + */ +uint64_t subghz_protocol_blocks_reverse_key(uint64_t key, uint8_t bit_count); + +/** Get parity the data bitwise + * + * @param key In data + * @param bit_count number of data bits + * + * @return parity + */ +uint8_t subghz_protocol_blocks_get_parity(uint64_t key, uint8_t bit_count); + +/** CRC-4 + * + * @param message array of bytes to check + * @param size number of bytes in message + * @param polynomial CRC polynomial + * @param init starting crc value + * + * @return CRC value + */ +uint8_t subghz_protocol_blocks_crc4( + uint8_t const message[], + size_t size, + uint8_t polynomial, + uint8_t init); + +/** CRC-7 + * + * @param message array of bytes to check + * @param size number of bytes in message + * @param polynomial CRC polynomial + * @param init starting crc value + * + * @return CRC value + */ +uint8_t subghz_protocol_blocks_crc7( + uint8_t const message[], + size_t size, + uint8_t polynomial, + uint8_t init); + +/** Generic Cyclic Redundancy Check CRC-8. Example polynomial: 0x31 = x8 + x5 + + * x4 + 1 (x8 is implicit) Example polynomial: 0x80 = x8 + x7 (a normal + * bit-by-bit parity XOR) + * + * @param message array of bytes to check + * @param size number of bytes in message + * @param polynomial byte is from x^7 to x^0 (x^8 is implicitly one) + * @param init starting crc value + * + * @return CRC value + */ +uint8_t subghz_protocol_blocks_crc8( + uint8_t const message[], + size_t size, + uint8_t polynomial, + uint8_t init); + +/** "Little-endian" Cyclic Redundancy Check CRC-8 LE Input and output are + * reflected, i.e. least significant bit is shifted in first + * + * @param message array of bytes to check + * @param size number of bytes in message + * @param polynomial CRC polynomial + * @param init starting crc value + * + * @return CRC value + */ +uint8_t subghz_protocol_blocks_crc8le( + uint8_t const message[], + size_t size, + uint8_t polynomial, + uint8_t init); + +/** CRC-16 LSB. Input and output are reflected, i.e. least significant bit is + * shifted in first. Note that poly and init already need to be reflected + * + * @param message array of bytes to check + * @param size number of bytes in message + * @param polynomial CRC polynomial + * @param init starting crc value + * + * @return CRC value + */ +uint16_t subghz_protocol_blocks_crc16lsb( + uint8_t const message[], + size_t size, + uint16_t polynomial, + uint16_t init); + +/** CRC-16 + * + * @param message array of bytes to check + * @param size number of bytes in message + * @param polynomial CRC polynomial + * @param init starting crc value + * + * @return CRC value + */ +uint16_t subghz_protocol_blocks_crc16( + uint8_t const message[], + size_t size, + uint16_t polynomial, + uint16_t init); + +/** Digest-8 by "LFSR-based Toeplitz hash" + * + * @param message bytes of message data + * @param size number of bytes to digest + * @param gen key stream generator, needs to includes the MSB if the + * LFSR is rolling + * @param key initial key + * + * @return digest value + */ +uint8_t subghz_protocol_blocks_lfsr_digest8( + uint8_t const message[], + size_t size, + uint8_t gen, + uint8_t key); + +/** Digest-8 by "LFSR-based Toeplitz hash", byte reflect, bit reflect + * + * @param message bytes of message data + * @param size number of bytes to digest + * @param gen key stream generator, needs to includes the MSB if the + * LFSR is rolling + * @param key initial key + * + * @return digest value + */ +uint8_t subghz_protocol_blocks_lfsr_digest8_reflect( + uint8_t const message[], + size_t size, + uint8_t gen, + uint8_t key); + +/** Digest-16 by "LFSR-based Toeplitz hash" + * + * @param message bytes of message data + * @param size number of bytes to digest + * @param gen key stream generator, needs to includes the MSB if the + * LFSR is rolling + * @param key initial key + * + * @return digest value + */ +uint16_t subghz_protocol_blocks_lfsr_digest16( + uint8_t const message[], + size_t size, + uint16_t gen, + uint16_t key); + +/** Compute Addition of a number of bytes + * + * @param message bytes of message data + * @param size number of bytes to sum + * + * @return summation value + */ +uint8_t subghz_protocol_blocks_add_bytes(uint8_t const message[], size_t size); + +/** Compute bit parity of a single byte (8 bits) + * + * @param byte single byte to check + * + * @return 1 odd parity, 0 even parity + */ +uint8_t subghz_protocol_blocks_parity8(uint8_t byte); + +/** Compute bit parity of a number of bytes + * + * @param message bytes of message data + * @param size number of bytes to sum + * + * @return 1 odd parity, 0 even parity + */ +uint8_t subghz_protocol_blocks_parity_bytes(uint8_t const message[], size_t size); + +/** Compute XOR (byte-wide parity) of a number of bytes + * + * @param message bytes of message data + * @param size number of bytes to sum + * + * @return summation value, per bit-position 1 odd parity, 0 even parity + */ +uint8_t subghz_protocol_blocks_xor_bytes(uint8_t const message[], size_t size); + +#ifdef __cplusplus +} +#endif diff --git a/lib/subghz/protocols/princeton_for_testing.c b/applications/debug/subghz_test/protocol/princeton_for_testing.c similarity index 99% rename from lib/subghz/protocols/princeton_for_testing.c rename to applications/debug/subghz_test/protocol/princeton_for_testing.c index 478d14cdfcaf..334a8241bbe3 100644 --- a/lib/subghz/protocols/princeton_for_testing.c +++ b/applications/debug/subghz_test/protocol/princeton_for_testing.c @@ -1,7 +1,7 @@ #include "princeton_for_testing.h" #include -#include "../blocks/math.h" +#include "math.h" /* * Help diff --git a/lib/subghz/protocols/princeton_for_testing.h b/applications/debug/subghz_test/protocol/princeton_for_testing.h similarity index 97% rename from lib/subghz/protocols/princeton_for_testing.h rename to applications/debug/subghz_test/protocol/princeton_for_testing.h index 07a37ec5f7f5..7b4201d38a9e 100644 --- a/lib/subghz/protocols/princeton_for_testing.h +++ b/applications/debug/subghz_test/protocol/princeton_for_testing.h @@ -1,6 +1,8 @@ #pragma once -#include "base.h" +//#include "base.h" +#include +#include /** SubGhzDecoderPrinceton anonymous type */ typedef struct SubGhzDecoderPrinceton SubGhzDecoderPrinceton; diff --git a/applications/debug/subghz_test/scenes/subghz_test_scene.c b/applications/debug/subghz_test/scenes/subghz_test_scene.c new file mode 100644 index 000000000000..ff439ef0f8db --- /dev/null +++ b/applications/debug/subghz_test/scenes/subghz_test_scene.c @@ -0,0 +1,30 @@ +#include "../subghz_test_app_i.h" + +// Generate scene on_enter handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter, +void (*const subghz_test_scene_on_enter_handlers[])(void*) = { +#include "subghz_test_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_event handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event, +bool (*const subghz_test_scene_on_event_handlers[])(void* context, SceneManagerEvent event) = { +#include "subghz_test_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_exit handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit, +void (*const subghz_test_scene_on_exit_handlers[])(void* context) = { +#include "subghz_test_scene_config.h" +}; +#undef ADD_SCENE + +// Initialize scene handlers configuration structure +const SceneManagerHandlers subghz_test_scene_handlers = { + .on_enter_handlers = subghz_test_scene_on_enter_handlers, + .on_event_handlers = subghz_test_scene_on_event_handlers, + .on_exit_handlers = subghz_test_scene_on_exit_handlers, + .scene_num = SubGhzTestSceneNum, +}; diff --git a/applications/debug/subghz_test/scenes/subghz_test_scene.h b/applications/debug/subghz_test/scenes/subghz_test_scene.h new file mode 100644 index 000000000000..0e6e06481b53 --- /dev/null +++ b/applications/debug/subghz_test/scenes/subghz_test_scene.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +// Generate scene id and total number +#define ADD_SCENE(prefix, name, id) SubGhzTestScene##id, +typedef enum { +#include "subghz_test_scene_config.h" + SubGhzTestSceneNum, +} SubGhzTestScene; +#undef ADD_SCENE + +extern const SceneManagerHandlers subghz_test_scene_handlers; + +// Generate scene on_enter handlers declaration +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*); +#include "subghz_test_scene_config.h" +#undef ADD_SCENE + +// Generate scene on_event handlers declaration +#define ADD_SCENE(prefix, name, id) \ + bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event); +#include "subghz_test_scene_config.h" +#undef ADD_SCENE + +// Generate scene on_exit handlers declaration +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context); +#include "subghz_test_scene_config.h" +#undef ADD_SCENE diff --git a/applications/debug/subghz_test/scenes/subghz_test_scene_about.c b/applications/debug/subghz_test/scenes/subghz_test_scene_about.c new file mode 100644 index 000000000000..64263d738877 --- /dev/null +++ b/applications/debug/subghz_test/scenes/subghz_test_scene_about.c @@ -0,0 +1,66 @@ +#include "../subghz_test_app_i.h" + +void subghz_test_scene_about_widget_callback(GuiButtonType result, InputType type, void* context) { + SubGhzTestApp* app = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(app->view_dispatcher, result); + } +} + +void subghz_test_scene_about_on_enter(void* context) { + SubGhzTestApp* app = context; + + FuriString* temp_str; + temp_str = furi_string_alloc(); + furi_string_printf(temp_str, "\e#%s\n", "Information"); + + furi_string_cat_printf(temp_str, "Version: %s\n", SUBGHZ_TEST_VERSION_APP); + furi_string_cat_printf(temp_str, "Developed by: %s\n", SUBGHZ_TEST_DEVELOPED); + furi_string_cat_printf(temp_str, "Github: %s\n\n", SUBGHZ_TEST_GITHUB); + + furi_string_cat_printf(temp_str, "\e#%s\n", "Description"); + furi_string_cat_printf( + temp_str, + "This application is designed\nto test the functionality of the\nbuilt-in CC1101 module.\n\n"); + + widget_add_text_box_element( + app->widget, + 0, + 0, + 128, + 14, + AlignCenter, + AlignBottom, + "\e#\e! \e!\n", + false); + widget_add_text_box_element( + app->widget, + 0, + 2, + 128, + 14, + AlignCenter, + AlignBottom, + "\e#\e! Sub-Ghz Test \e!\n", + false); + widget_add_text_scroll_element(app->widget, 0, 16, 128, 50, furi_string_get_cstr(temp_str)); + furi_string_free(temp_str); + + view_dispatcher_switch_to_view(app->view_dispatcher, SubGhzTestViewWidget); +} + +bool subghz_test_scene_about_on_event(void* context, SceneManagerEvent event) { + SubGhzTestApp* app = context; + bool consumed = false; + UNUSED(app); + UNUSED(event); + + return consumed; +} + +void subghz_test_scene_about_on_exit(void* context) { + SubGhzTestApp* app = context; + + // Clear views + widget_reset(app->widget); +} diff --git a/applications/debug/subghz_test/scenes/subghz_test_scene_carrier.c b/applications/debug/subghz_test/scenes/subghz_test_scene_carrier.c new file mode 100644 index 000000000000..41ff5c8c6e19 --- /dev/null +++ b/applications/debug/subghz_test/scenes/subghz_test_scene_carrier.c @@ -0,0 +1,29 @@ +#include "../subghz_test_app_i.h" + +void subghz_test_scene_carrier_callback(SubGhzTestCarrierEvent event, void* context) { + furi_assert(context); + SubGhzTestApp* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, event); +} + +void subghz_test_scene_carrier_on_enter(void* context) { + SubGhzTestApp* app = context; + subghz_test_carrier_set_callback( + app->subghz_test_carrier, subghz_test_scene_carrier_callback, app); + view_dispatcher_switch_to_view(app->view_dispatcher, SubGhzTestViewCarrier); +} + +bool subghz_test_scene_carrier_on_event(void* context, SceneManagerEvent event) { + SubGhzTestApp* app = context; + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubGhzTestCarrierEventOnlyRx) { + scene_manager_next_scene(app->scene_manager, SubGhzTestSceneShowOnlyRx); + return true; + } + } + return false; +} + +void subghz_test_scene_carrier_on_exit(void* context) { + UNUSED(context); +} diff --git a/applications/debug/subghz_test/scenes/subghz_test_scene_config.h b/applications/debug/subghz_test/scenes/subghz_test_scene_config.h new file mode 100644 index 000000000000..80a42c3761a0 --- /dev/null +++ b/applications/debug/subghz_test/scenes/subghz_test_scene_config.h @@ -0,0 +1,6 @@ +ADD_SCENE(subghz_test, start, Start) +ADD_SCENE(subghz_test, about, About) +ADD_SCENE(subghz_test, carrier, Carrier) +ADD_SCENE(subghz_test, packet, Packet) +ADD_SCENE(subghz_test, static, Static) +ADD_SCENE(subghz_test, show_only_rx, ShowOnlyRx) diff --git a/applications/debug/subghz_test/scenes/subghz_test_scene_packet.c b/applications/debug/subghz_test/scenes/subghz_test_scene_packet.c new file mode 100644 index 000000000000..b43a4d0cb39b --- /dev/null +++ b/applications/debug/subghz_test/scenes/subghz_test_scene_packet.c @@ -0,0 +1,29 @@ +#include "../subghz_test_app_i.h" + +void subghz_test_scene_packet_callback(SubGhzTestPacketEvent event, void* context) { + furi_assert(context); + SubGhzTestApp* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, event); +} + +void subghz_test_scene_packet_on_enter(void* context) { + SubGhzTestApp* app = context; + subghz_test_packet_set_callback( + app->subghz_test_packet, subghz_test_scene_packet_callback, app); + view_dispatcher_switch_to_view(app->view_dispatcher, SubGhzTestViewPacket); +} + +bool subghz_test_scene_packet_on_event(void* context, SceneManagerEvent event) { + SubGhzTestApp* app = context; + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubGhzTestPacketEventOnlyRx) { + scene_manager_next_scene(app->scene_manager, SubGhzTestSceneShowOnlyRx); + return true; + } + } + return false; +} + +void subghz_test_scene_packet_on_exit(void* context) { + UNUSED(context); +} diff --git a/applications/debug/subghz_test/scenes/subghz_test_scene_show_only_rx.c b/applications/debug/subghz_test/scenes/subghz_test_scene_show_only_rx.c new file mode 100644 index 000000000000..3d5a54355c3d --- /dev/null +++ b/applications/debug/subghz_test/scenes/subghz_test_scene_show_only_rx.c @@ -0,0 +1,49 @@ +#include "../subghz_test_app_i.h" +#include + +void subghz_test_scene_show_only_rx_popup_callback(void* context) { + SubGhzTestApp* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, SubGhzTestCustomEventSceneShowOnlyRX); +} + +void subghz_test_scene_show_only_rx_on_enter(void* context) { + SubGhzTestApp* app = context; + + // Setup view + Popup* popup = app->popup; + + const char* header_text = "Transmission is blocked"; + const char* message_text = "Transmission on\nthis frequency is\nrestricted in\nyour region"; + if(!furi_hal_region_is_provisioned()) { + header_text = "Firmware update needed"; + message_text = "Please update\nfirmware before\nusing this feature\nflipp.dev/upd"; + } + + popup_set_header(popup, header_text, 63, 3, AlignCenter, AlignTop); + popup_set_text(popup, message_text, 0, 17, AlignLeft, AlignTop); + popup_set_icon(popup, 72, 17, &I_DolphinCommon_56x48); + + popup_set_timeout(popup, 1500); + popup_set_context(popup, app); + popup_set_callback(popup, subghz_test_scene_show_only_rx_popup_callback); + popup_enable_timeout(popup); + view_dispatcher_switch_to_view(app->view_dispatcher, SubGhzTestViewPopup); +} + +bool subghz_test_scene_show_only_rx_on_event(void* context, SceneManagerEvent event) { + SubGhzTestApp* app = context; + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubGhzTestCustomEventSceneShowOnlyRX) { + scene_manager_previous_scene(app->scene_manager); + return true; + } + } + return false; +} + +void subghz_test_scene_show_only_rx_on_exit(void* context) { + SubGhzTestApp* app = context; + Popup* popup = app->popup; + + popup_reset(popup); +} diff --git a/applications/debug/subghz_test/scenes/subghz_test_scene_start.c b/applications/debug/subghz_test/scenes/subghz_test_scene_start.c new file mode 100644 index 000000000000..cf3b08163d2d --- /dev/null +++ b/applications/debug/subghz_test/scenes/subghz_test_scene_start.c @@ -0,0 +1,77 @@ +#include "../subghz_test_app_i.h" + +typedef enum { + SubmenuIndexSubGhzTestCarrier, + SubmenuIndexSubGhzTestPacket, + SubmenuIndexSubGhzTestStatic, + SubmenuIndexSubGhzTestAbout, +} SubmenuIndex; + +void subghz_test_scene_start_submenu_callback(void* context, uint32_t index) { + SubGhzTestApp* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, index); +} + +void subghz_test_scene_start_on_enter(void* context) { + SubGhzTestApp* app = context; + Submenu* submenu = app->submenu; + + submenu_add_item( + submenu, + "Carrier", + SubmenuIndexSubGhzTestCarrier, + subghz_test_scene_start_submenu_callback, + app); + submenu_add_item( + submenu, + "Packet", + SubmenuIndexSubGhzTestPacket, + subghz_test_scene_start_submenu_callback, + app); + submenu_add_item( + submenu, + "Static", + SubmenuIndexSubGhzTestStatic, + subghz_test_scene_start_submenu_callback, + app); + submenu_add_item( + submenu, + "About", + SubmenuIndexSubGhzTestAbout, + subghz_test_scene_start_submenu_callback, + app); + + submenu_set_selected_item( + submenu, scene_manager_get_scene_state(app->scene_manager, SubGhzTestSceneStart)); + + view_dispatcher_switch_to_view(app->view_dispatcher, SubGhzTestViewSubmenu); +} + +bool subghz_test_scene_start_on_event(void* context, SceneManagerEvent event) { + SubGhzTestApp* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexSubGhzTestAbout) { + scene_manager_next_scene(app->scene_manager, SubGhzTestSceneAbout); + consumed = true; + } else if(event.event == SubmenuIndexSubGhzTestCarrier) { + scene_manager_next_scene(app->scene_manager, SubGhzTestSceneCarrier); + consumed = true; + } else if(event.event == SubmenuIndexSubGhzTestPacket) { + scene_manager_next_scene(app->scene_manager, SubGhzTestScenePacket); + consumed = true; + } else if(event.event == SubmenuIndexSubGhzTestStatic) { + scene_manager_next_scene(app->scene_manager, SubGhzTestSceneStatic); + consumed = true; + } + scene_manager_set_scene_state(app->scene_manager, SubGhzTestSceneStart, event.event); + } + + return consumed; +} + +void subghz_test_scene_start_on_exit(void* context) { + SubGhzTestApp* app = context; + submenu_reset(app->submenu); +} diff --git a/applications/debug/subghz_test/scenes/subghz_test_scene_static.c b/applications/debug/subghz_test/scenes/subghz_test_scene_static.c new file mode 100644 index 000000000000..a008d2438ffd --- /dev/null +++ b/applications/debug/subghz_test/scenes/subghz_test_scene_static.c @@ -0,0 +1,29 @@ +#include "../subghz_test_app_i.h" + +void subghz_test_scene_static_callback(SubGhzTestStaticEvent event, void* context) { + furi_assert(context); + SubGhzTestApp* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, event); +} + +void subghz_test_scene_static_on_enter(void* context) { + SubGhzTestApp* app = context; + subghz_test_static_set_callback( + app->subghz_test_static, subghz_test_scene_static_callback, app); + view_dispatcher_switch_to_view(app->view_dispatcher, SubGhzTestViewStatic); +} + +bool subghz_test_scene_static_on_event(void* context, SceneManagerEvent event) { + SubGhzTestApp* app = context; + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubGhzTestStaticEventOnlyRx) { + scene_manager_next_scene(app->scene_manager, SubGhzTestSceneShowOnlyRx); + return true; + } + } + return false; +} + +void subghz_test_scene_static_on_exit(void* context) { + UNUSED(context); +} diff --git a/applications/debug/subghz_test/subghz_test_10px.png b/applications/debug/subghz_test/subghz_test_10px.png new file mode 100644 index 0000000000000000000000000000000000000000..10dac0ecaac608aba6d445bc5fef45d8cc1efff4 GIT binary patch literal 181 zcmeAS@N?(olHy`uVBq!ia0vp^AT}2V8<6ZZI=>f4F%}28J29*~C-V}>VM%xNb!1@J z*w6hZkrl}2EbxddW? +#include + +static bool subghz_test_app_custom_event_callback(void* context, uint32_t event) { + furi_assert(context); + SubGhzTestApp* app = context; + return scene_manager_handle_custom_event(app->scene_manager, event); +} + +static bool subghz_test_app_back_event_callback(void* context) { + furi_assert(context); + SubGhzTestApp* app = context; + return scene_manager_handle_back_event(app->scene_manager); +} + +static void subghz_test_app_tick_event_callback(void* context) { + furi_assert(context); + SubGhzTestApp* app = context; + scene_manager_handle_tick_event(app->scene_manager); +} + +SubGhzTestApp* subghz_test_app_alloc() { + SubGhzTestApp* app = malloc(sizeof(SubGhzTestApp)); + + // GUI + app->gui = furi_record_open(RECORD_GUI); + + // View Dispatcher + app->view_dispatcher = view_dispatcher_alloc(); + app->scene_manager = scene_manager_alloc(&subghz_test_scene_handlers, app); + view_dispatcher_enable_queue(app->view_dispatcher); + + view_dispatcher_set_event_callback_context(app->view_dispatcher, app); + view_dispatcher_set_custom_event_callback( + app->view_dispatcher, subghz_test_app_custom_event_callback); + view_dispatcher_set_navigation_event_callback( + app->view_dispatcher, subghz_test_app_back_event_callback); + view_dispatcher_set_tick_event_callback( + app->view_dispatcher, subghz_test_app_tick_event_callback, 100); + + view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); + + // Open Notification record + app->notifications = furi_record_open(RECORD_NOTIFICATION); + + // SubMenu + app->submenu = submenu_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, SubGhzTestViewSubmenu, submenu_get_view(app->submenu)); + + // Widget + app->widget = widget_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, SubGhzTestViewWidget, widget_get_view(app->widget)); + + // Popup + app->popup = popup_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, SubGhzTestViewPopup, popup_get_view(app->popup)); + + // Carrier Test Module + app->subghz_test_carrier = subghz_test_carrier_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, + SubGhzTestViewCarrier, + subghz_test_carrier_get_view(app->subghz_test_carrier)); + + // Packet Test + app->subghz_test_packet = subghz_test_packet_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, + SubGhzTestViewPacket, + subghz_test_packet_get_view(app->subghz_test_packet)); + + // Static send + app->subghz_test_static = subghz_test_static_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, + SubGhzTestViewStatic, + subghz_test_static_get_view(app->subghz_test_static)); + + scene_manager_next_scene(app->scene_manager, SubGhzTestSceneStart); + + return app; +} + +void subghz_test_app_free(SubGhzTestApp* app) { + furi_assert(app); + + // Submenu + view_dispatcher_remove_view(app->view_dispatcher, SubGhzTestViewSubmenu); + submenu_free(app->submenu); + + // Widget + view_dispatcher_remove_view(app->view_dispatcher, SubGhzTestViewWidget); + widget_free(app->widget); + + // Popup + view_dispatcher_remove_view(app->view_dispatcher, SubGhzTestViewPopup); + popup_free(app->popup); + + // Carrier Test + view_dispatcher_remove_view(app->view_dispatcher, SubGhzTestViewCarrier); + subghz_test_carrier_free(app->subghz_test_carrier); + + // Packet Test + view_dispatcher_remove_view(app->view_dispatcher, SubGhzTestViewPacket); + subghz_test_packet_free(app->subghz_test_packet); + + // Static + view_dispatcher_remove_view(app->view_dispatcher, SubGhzTestViewStatic); + subghz_test_static_free(app->subghz_test_static); + + // View dispatcher + view_dispatcher_free(app->view_dispatcher); + scene_manager_free(app->scene_manager); + + // Notifications + furi_record_close(RECORD_NOTIFICATION); + app->notifications = NULL; + + // Close records + furi_record_close(RECORD_GUI); + + free(app); +} + +int32_t subghz_test_app(void* p) { + UNUSED(p); + SubGhzTestApp* subghz_test_app = subghz_test_app_alloc(); + + view_dispatcher_run(subghz_test_app->view_dispatcher); + + subghz_test_app_free(subghz_test_app); + + return 0; +} diff --git a/applications/debug/subghz_test/subghz_test_app_i.c b/applications/debug/subghz_test/subghz_test_app_i.c new file mode 100644 index 000000000000..0ec6635a0ebd --- /dev/null +++ b/applications/debug/subghz_test/subghz_test_app_i.c @@ -0,0 +1,5 @@ +#include "subghz_test_app_i.h" + +#include + +#define TAG "SubGhzTest" diff --git a/applications/debug/subghz_test/subghz_test_app_i.h b/applications/debug/subghz_test/subghz_test_app_i.h new file mode 100644 index 000000000000..c96f9c4ee4c0 --- /dev/null +++ b/applications/debug/subghz_test/subghz_test_app_i.h @@ -0,0 +1,32 @@ +#pragma once + +#include "helpers/subghz_test_types.h" +#include "helpers/subghz_test_event.h" + +#include "scenes/subghz_test_scene.h" +#include +#include +#include +#include +#include +#include +#include + +#include "views/subghz_test_static.h" +#include "views/subghz_test_carrier.h" +#include "views/subghz_test_packet.h" + +typedef struct SubGhzTestApp SubGhzTestApp; + +struct SubGhzTestApp { + Gui* gui; + ViewDispatcher* view_dispatcher; + SceneManager* scene_manager; + NotificationApp* notifications; + Submenu* submenu; + Widget* widget; + Popup* popup; + SubGhzTestStatic* subghz_test_static; + SubGhzTestCarrier* subghz_test_carrier; + SubGhzTestPacket* subghz_test_packet; +}; diff --git a/applications/main/subghz/views/subghz_test_carrier.c b/applications/debug/subghz_test/views/subghz_test_carrier.c similarity index 98% rename from applications/main/subghz/views/subghz_test_carrier.c rename to applications/debug/subghz_test/views/subghz_test_carrier.c index 254a4127bc4f..53e309b7c98c 100644 --- a/applications/main/subghz/views/subghz_test_carrier.c +++ b/applications/debug/subghz_test/views/subghz_test_carrier.c @@ -1,6 +1,6 @@ #include "subghz_test_carrier.h" -#include "../subghz_i.h" -#include "../helpers/subghz_testing.h" +#include "../subghz_test_app_i.h" +#include "../helpers/subghz_test_frequency.h" #include #include diff --git a/applications/main/subghz/views/subghz_test_carrier.h b/applications/debug/subghz_test/views/subghz_test_carrier.h similarity index 100% rename from applications/main/subghz/views/subghz_test_carrier.h rename to applications/debug/subghz_test/views/subghz_test_carrier.h diff --git a/applications/main/subghz/views/subghz_test_packet.c b/applications/debug/subghz_test/views/subghz_test_packet.c similarity index 98% rename from applications/main/subghz/views/subghz_test_packet.c rename to applications/debug/subghz_test/views/subghz_test_packet.c index bc2c474b513f..bab83ab5b579 100644 --- a/applications/main/subghz/views/subghz_test_packet.c +++ b/applications/debug/subghz_test/views/subghz_test_packet.c @@ -1,6 +1,6 @@ #include "subghz_test_packet.h" -#include "../subghz_i.h" -#include "../helpers/subghz_testing.h" +#include "../subghz_test_app_i.h" +#include "../helpers/subghz_test_frequency.h" #include #include @@ -8,7 +8,7 @@ #include #include #include -#include +#include "../protocol/princeton_for_testing.h" #define SUBGHZ_TEST_PACKET_COUNT 500 diff --git a/applications/main/subghz/views/subghz_test_packet.h b/applications/debug/subghz_test/views/subghz_test_packet.h similarity index 100% rename from applications/main/subghz/views/subghz_test_packet.h rename to applications/debug/subghz_test/views/subghz_test_packet.h diff --git a/applications/main/subghz/views/subghz_test_static.c b/applications/debug/subghz_test/views/subghz_test_static.c similarity index 98% rename from applications/main/subghz/views/subghz_test_static.c rename to applications/debug/subghz_test/views/subghz_test_static.c index 197af21fb5f7..6764fd5ca9fe 100644 --- a/applications/main/subghz/views/subghz_test_static.c +++ b/applications/debug/subghz_test/views/subghz_test_static.c @@ -1,6 +1,6 @@ #include "subghz_test_static.h" -#include "../subghz_i.h" -#include "../helpers/subghz_testing.h" +#include "../subghz_test_app_i.h" +#include "../helpers/subghz_test_frequency.h" #include #include @@ -8,7 +8,7 @@ #include #include #include -#include +#include "../protocol/princeton_for_testing.h" #define TAG "SubGhzTestStatic" diff --git a/applications/main/subghz/views/subghz_test_static.h b/applications/debug/subghz_test/views/subghz_test_static.h similarity index 100% rename from applications/main/subghz/views/subghz_test_static.h rename to applications/debug/subghz_test/views/subghz_test_static.h diff --git a/applications/debug/unit_tests/infrared/infrared_test.c b/applications/debug/unit_tests/infrared/infrared_test.c index 2bcb95da8e5b..b2acad470e69 100644 --- a/applications/debug/unit_tests/infrared/infrared_test.c +++ b/applications/debug/unit_tests/infrared/infrared_test.c @@ -425,6 +425,7 @@ MU_TEST(infrared_test_decoder_mixed) { infrared_test_run_decoder(InfraredProtocolSamsung32, 1); infrared_test_run_decoder(InfraredProtocolSIRC, 3); infrared_test_run_decoder(InfraredProtocolKaseikyo, 1); + infrared_test_run_decoder(InfraredProtocolRCA, 1); } MU_TEST(infrared_test_decoder_nec) { @@ -499,6 +500,15 @@ MU_TEST(infrared_test_decoder_kaseikyo) { infrared_test_run_decoder(InfraredProtocolKaseikyo, 6); } +MU_TEST(infrared_test_decoder_rca) { + infrared_test_run_decoder(InfraredProtocolRCA, 1); + infrared_test_run_decoder(InfraredProtocolRCA, 2); + infrared_test_run_decoder(InfraredProtocolRCA, 3); + infrared_test_run_decoder(InfraredProtocolRCA, 4); + infrared_test_run_decoder(InfraredProtocolRCA, 5); + infrared_test_run_decoder(InfraredProtocolRCA, 6); +} + MU_TEST(infrared_test_encoder_decoder_all) { infrared_test_run_encoder_decoder(InfraredProtocolNEC, 1); infrared_test_run_encoder_decoder(InfraredProtocolNECext, 1); @@ -509,6 +519,7 @@ MU_TEST(infrared_test_encoder_decoder_all) { infrared_test_run_encoder_decoder(InfraredProtocolRC5, 1); infrared_test_run_encoder_decoder(InfraredProtocolSIRC, 1); infrared_test_run_encoder_decoder(InfraredProtocolKaseikyo, 1); + infrared_test_run_encoder_decoder(InfraredProtocolRCA, 1); } MU_TEST_SUITE(infrared_test) { @@ -527,6 +538,7 @@ MU_TEST_SUITE(infrared_test) { MU_RUN_TEST(infrared_test_decoder_samsung32); MU_RUN_TEST(infrared_test_decoder_necext1); MU_RUN_TEST(infrared_test_decoder_kaseikyo); + MU_RUN_TEST(infrared_test_decoder_rca); MU_RUN_TEST(infrared_test_decoder_mixed); MU_RUN_TEST(infrared_test_encoder_decoder_all); } diff --git a/applications/debug/unit_tests/nfc/nfc_test.c b/applications/debug/unit_tests/nfc/nfc_test.c index 8e557a1fad83..2ea4159e6080 100644 --- a/applications/debug/unit_tests/nfc/nfc_test.c +++ b/applications/debug/unit_tests/nfc/nfc_test.c @@ -26,6 +26,12 @@ #define NFC_TEST_4_BYTE_BUILD_SIGNAL_TIM_MAX (110) #define NFC_TEST_16_BYTE_BUILD_SIGNAL_TIM_MAX (440) +// Maximum allowed time for buffer preparation to fit 500us nt message timeout +#define NFC_TEST_4_BYTE_BUILD_BUFFER_TIM_MAX (150) +#define NFC_TEST_16_BYTE_BUILD_BUFFER_TIM_MAX (640) +#define NFC_TEST_4_BYTE_BUILD_SIGNAL_TIM_MAX (110) +#define NFC_TEST_16_BYTE_BUILD_SIGNAL_TIM_MAX (440) + typedef struct { Storage* storage; } NfcTest; diff --git a/applications/debug/unit_tests/nfc/nfc_test_old.c b/applications/debug/unit_tests/nfc/nfc_test_old.c index 22c2c9798bd3..83e44fe9db6d 100644 --- a/applications/debug/unit_tests/nfc/nfc_test_old.c +++ b/applications/debug/unit_tests/nfc/nfc_test_old.c @@ -27,6 +27,12 @@ // #define NFC_TEST_DATA_MAX_LEN 18 // #define NFC_TETS_TIMINGS_MAX_LEN 1350 +// // Maximum allowed time for buffer preparation to fit 500us nt message timeout +// #define NFC_TEST_4_BYTE_BUILD_BUFFER_TIM_MAX (150) +// #define NFC_TEST_16_BYTE_BUILD_BUFFER_TIM_MAX (640) +// #define NFC_TEST_4_BYTE_BUILD_SIGNAL_TIM_MAX (110) +// #define NFC_TEST_16_BYTE_BUILD_SIGNAL_TIM_MAX (440) + // typedef struct { // Storage* storage; // NfcaSignal* signal; @@ -89,13 +95,13 @@ // static bool nfc_test_digital_signal_test_encode( // const char* file_name, -// uint32_t encode_max_time, +// uint32_t build_signal_max_time_us, +// uint32_t build_buffer_max_time_us, // uint32_t timing_tolerance, // uint32_t timings_sum_tolerance) { // furi_assert(nfc_test); // bool success = false; -// uint32_t time = 0; // uint32_t dut_timings_sum = 0; // uint32_t ref_timings_sum = 0; // uint8_t parity[10] = {}; @@ -109,17 +115,37 @@ // // Encode signal // FURI_CRITICAL_ENTER(); -// time = DWT->CYCCNT; +// uint32_t time_start = DWT->CYCCNT; + // nfca_signal_encode( // nfc_test->signal, nfc_test->test_data, nfc_test->test_data_len * 8, parity); + +// uint32_t time_signal = +// (DWT->CYCCNT - time_start) / furi_hal_cortex_instructions_per_microsecond(); + +// time_start = DWT->CYCCNT; + // digital_signal_prepare_arr(nfc_test->signal->tx_signal); -// time = (DWT->CYCCNT - time) / furi_hal_cortex_instructions_per_microsecond(); + +// uint32_t time_buffer = +// (DWT->CYCCNT - time_start) / furi_hal_cortex_instructions_per_microsecond(); // FURI_CRITICAL_EXIT(); // // Check timings -// if(time > encode_max_time) { +// if(time_signal > build_signal_max_time_us) { +// FURI_LOG_E( +// TAG, +// "Build signal time: %ld us while accepted value: %ld us", +// time_signal, +// build_signal_max_time_us); +// break; +// } +// if(time_buffer > build_buffer_max_time_us) { // FURI_LOG_E( -// TAG, "Encoding time: %ld us while accepted value: %ld us", time, encode_max_time); +// TAG, +// "Build buffer time: %ld us while accepted value: %ld us", +// time_buffer, +// build_buffer_max_time_us); // break; // } @@ -156,7 +182,16 @@ // break; // } -// FURI_LOG_I(TAG, "Encoding time: %ld us. Acceptable time: %ld us", time, encode_max_time); +// FURI_LOG_I( +// TAG, +// "Build signal time: %ld us. Acceptable time: %ld us", +// time_signal, +// build_signal_max_time_us); +// FURI_LOG_I( +// TAG, +// "Build buffer time: %ld us. Acceptable time: %ld us", +// time_buffer, +// build_buffer_max_time_us); // FURI_LOG_I( // TAG, // "Timings sum difference: %ld [1/64MHZ]. Acceptable difference: %ld [1/64MHz]", @@ -171,11 +206,19 @@ // MU_TEST(nfc_digital_signal_test) { // mu_assert( // nfc_test_digital_signal_test_encode( -// NFC_TEST_RESOURCES_DIR NFC_TEST_SIGNAL_SHORT_FILE, 500, 1, 37), +// NFC_TEST_RESOURCES_DIR NFC_TEST_SIGNAL_SHORT_FILE, +// NFC_TEST_4_BYTE_BUILD_SIGNAL_TIM_MAX, +// NFC_TEST_4_BYTE_BUILD_BUFFER_TIM_MAX, +// 1, +// 37), // "NFC short digital signal test failed\r\n"); // mu_assert( // nfc_test_digital_signal_test_encode( -// NFC_TEST_RESOURCES_DIR NFC_TEST_SIGNAL_LONG_FILE, 2000, 1, 37), +// NFC_TEST_RESOURCES_DIR NFC_TEST_SIGNAL_LONG_FILE, +// NFC_TEST_16_BYTE_BUILD_SIGNAL_TIM_MAX, +// NFC_TEST_16_BYTE_BUILD_BUFFER_TIM_MAX, +// 1, +// 37), // "NFC long digital signal test failed\r\n"); // } @@ -404,9 +447,9 @@ // // Reference block data // uint8_t block_data[16] = {}; // memset(block_data, 0xff, sizeof(block_data)); -// uint16_t total_blocks = mifare_classic_get_total_block_num(type); +// uint16_t total_blocks = mf_classic_get_total_block_num(type); // for(size_t i = 1; i < total_blocks; i++) { -// if(mifare_classic_is_sector_trailer(i)) { +// if(mf_classic_is_sector_trailer(i)) { // mu_assert( // memcmp(mf_data->block[i].value, sector_trailer, 16) == 0, // "Failed sector trailer compare"); @@ -456,7 +499,7 @@ // "manufacturer_block assert failed\r\n"); // // Check other blocks // for(size_t i = 1; i < total_blocks; i++) { -// if(mifare_classic_is_sector_trailer(i)) { +// if(mf_classic_is_sector_trailer(i)) { // mu_assert( // memcmp(mf_data->block[i].value, sector_trailer, 16) == 0, // "Failed sector trailer compare"); @@ -472,12 +515,12 @@ // nfc_keys->dev_data.nfc_data.uid_len = uid_len; // memcpy(nfc_keys->dev_data.nfc_data.uid, uid, uid_len); // mu_assert(nfc_device_load_key_cache(nfc_keys), "Failed to load key cache"); -// uint8_t total_sec = mifare_classic_get_total_sectors_num(type); +// uint8_t total_sec = mf_classic_get_total_sectors_num(type); // uint8_t default_key[6] = {}; // memset(default_key, 0xff, 6); // for(size_t i = 0; i < total_sec; i++) { // MfClassicSectorTrailer* sec_tr = -// mifare_classic_get_sector_trailer_by_sector(&nfc_keys->dev_data.mf_classic_data, i); +// mf_classic_get_sector_trailer_by_sector(&nfc_keys->dev_data.mf_classic_data, i); // mu_assert(memcmp(sec_tr->key_a, default_key, 6) == 0, "Failed key compare"); // mu_assert(memcmp(sec_tr->key_b, default_key, 6) == 0, "Failed key compare"); // } @@ -529,4 +572,4 @@ // int run_minunit_test_nfc() { // MU_RUN_SUITE(nfc); // return MU_EXIT_CODE; -// } +// } \ No newline at end of file diff --git a/applications/drivers/subghz/application.fam b/applications/drivers/subghz/application.fam index aaf0e1bd94d5..2ee114833bb5 100644 --- a/applications/drivers/subghz/application.fam +++ b/applications/drivers/subghz/application.fam @@ -4,5 +4,6 @@ App( targets=["f7"], entry_point="subghz_device_cc1101_ext_ep", requires=["subghz"], + sdk_headers=["cc1101_ext/cc1101_ext_interconnect.h"], fap_libs=["hwdrivers"], ) diff --git a/applications/drivers/subghz/cc1101_ext/cc1101_ext.c b/applications/drivers/subghz/cc1101_ext/cc1101_ext.c index 896b9bd2f605..594a74a01506 100644 --- a/applications/drivers/subghz/cc1101_ext/cc1101_ext.c +++ b/applications/drivers/subghz/cc1101_ext/cc1101_ext.c @@ -87,6 +87,7 @@ static bool subghz_device_cc1101_ext_check_init() { subghz_device_cc1101_ext->state = SubGhzDeviceCC1101ExtStateIdle; bool ret = false; + CC1101Status cc1101_status = {0}; furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle); FuriHalCortexTimer timer = furi_hal_cortex_timer_get(100 * 1000); @@ -94,16 +95,34 @@ static bool subghz_device_cc1101_ext_check_init() { // Reset furi_hal_gpio_init( subghz_device_cc1101_ext->g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow); - cc1101_reset(subghz_device_cc1101_ext->spi_bus_handle); - cc1101_write_reg( + furi_hal_gpio_init( + subghz_device_cc1101_ext->spi_bus_handle->miso, + GpioModeInput, + GpioPullUp, + GpioSpeedLow); + + cc1101_status = cc1101_reset(subghz_device_cc1101_ext->spi_bus_handle); + if(cc1101_status.CHIP_RDYn != 0) { + //timeout or error + break; + } + cc1101_status = cc1101_write_reg( subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG0, CC1101IocfgHighImpedance); - + if(cc1101_status.CHIP_RDYn != 0) { + //timeout or error + break; + } // Prepare GD0 for power on self test furi_hal_gpio_init( - subghz_device_cc1101_ext->g0_pin, GpioModeInput, GpioPullNo, GpioSpeedLow); + subghz_device_cc1101_ext->g0_pin, GpioModeInput, GpioPullUp, GpioSpeedLow); // GD0 low - cc1101_write_reg(subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG0, CC1101IocfgHW); + cc1101_status = cc1101_write_reg( + subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG0, CC1101IocfgHW); + if(cc1101_status.CHIP_RDYn != 0) { + //timeout or error + break; + } while(furi_hal_gpio_read(subghz_device_cc1101_ext->g0_pin) != false) { if(furi_hal_cortex_timer_is_expired(timer)) { //timeout @@ -116,10 +135,16 @@ static bool subghz_device_cc1101_ext_check_init() { } // GD0 high - cc1101_write_reg( + furi_hal_gpio_init( + subghz_device_cc1101_ext->g0_pin, GpioModeInput, GpioPullDown, GpioSpeedLow); + cc1101_status = cc1101_write_reg( subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG0, CC1101IocfgHW | CC1101_IOCFG_INV); + if(cc1101_status.CHIP_RDYn != 0) { + //timeout or error + break; + } while(furi_hal_gpio_read(subghz_device_cc1101_ext->g0_pin) != true) { if(furi_hal_cortex_timer_is_expired(timer)) { //timeout @@ -132,17 +157,21 @@ static bool subghz_device_cc1101_ext_check_init() { } // Reset GD0 to floating state - cc1101_write_reg( + cc1101_status = cc1101_write_reg( subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG0, CC1101IocfgHighImpedance); + if(cc1101_status.CHIP_RDYn != 0) { + //timeout or error + break; + } furi_hal_gpio_init( subghz_device_cc1101_ext->g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow); - // RF switches - furi_hal_gpio_init(&gpio_rf_sw_0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); - cc1101_write_reg(subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG2, CC1101IocfgHW); - // Go to sleep - cc1101_shutdown(subghz_device_cc1101_ext->spi_bus_handle); + cc1101_status = cc1101_shutdown(subghz_device_cc1101_ext->spi_bus_handle); + if(cc1101_status.CHIP_RDYn != 0) { + //timeout or error + break; + } ret = true; } while(false); @@ -152,6 +181,8 @@ static bool subghz_device_cc1101_ext_check_init() { FURI_LOG_I(TAG, "Init OK"); } else { FURI_LOG_E(TAG, "Init failed"); + furi_hal_gpio_init( + subghz_device_cc1101_ext->g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow); } return ret; } diff --git a/applications/examples/example_thermo/README.md b/applications/examples/example_thermo/README.md index 08240a1f8fa6..d298de64309e 100644 --- a/applications/examples/example_thermo/README.md +++ b/applications/examples/example_thermo/README.md @@ -18,7 +18,7 @@ Before launching the application, connect the sensor to Flipper's external GPIO In order to launch this demo, follow the steps below: 1. Make sure your Flipper has an SD card installed. 2. Connect your Flipper to the computer via a USB cable. -3. Run `./fbt launch_app APPSRC=example_thermo` in your terminal emulator of choice. +3. Run `./fbt launch APPSRC=example_thermo` in your terminal emulator of choice. ## Changing the data pin It is possible to use other GPIO pin as a 1-Wire data pin. In order to change it, set the `THERMO_GPIO_PIN` macro to any of the options listed below: diff --git a/applications/external/picopass/picopass_device.c b/applications/external/picopass/picopass_device.c index 53778cfb322a..de43b0bb7c54 100644 --- a/applications/external/picopass/picopass_device.c +++ b/applications/external/picopass/picopass_device.c @@ -16,6 +16,7 @@ PicopassDevice* picopass_device_alloc() { PicopassDevice* picopass_dev = malloc(sizeof(PicopassDevice)); picopass_dev->dev_data.pacs.legacy = false; picopass_dev->dev_data.pacs.se_enabled = false; + picopass_dev->dev_data.pacs.elite_kdf = false; picopass_dev->dev_data.pacs.pin_length = 0; picopass_dev->storage = furi_record_open(RECORD_STORAGE); picopass_dev->dialogs = furi_record_open(RECORD_DIALOGS); @@ -77,6 +78,7 @@ static bool picopass_device_save_file( break; } } + // TODO: Add elite if(!flipper_format_write_comment_cstr(file, "Picopass blocks")) break; bool block_saved = true; @@ -256,6 +258,7 @@ void picopass_device_data_clear(PicopassDeviceData* dev_data) { } dev_data->pacs.legacy = false; dev_data->pacs.se_enabled = false; + dev_data->pacs.elite_kdf = false; dev_data->pacs.pin_length = 0; } diff --git a/applications/external/picopass/picopass_device.h b/applications/external/picopass/picopass_device.h index 7fc35ebda151..b45df346cf26 100644 --- a/applications/external/picopass/picopass_device.h +++ b/applications/external/picopass/picopass_device.h @@ -62,6 +62,7 @@ typedef struct { bool sio; bool biometrics; uint8_t key[8]; + bool elite_kdf; uint8_t pin_length; PicopassEncryption encryption; uint8_t credential[8]; diff --git a/applications/external/picopass/picopass_worker.c b/applications/external/picopass/picopass_worker.c index e671552c5cb0..6301704ca8bd 100644 --- a/applications/external/picopass/picopass_worker.c +++ b/applications/external/picopass/picopass_worker.c @@ -550,6 +550,7 @@ void picopass_worker_elite_dict_attack(PicopassWorker* picopass_worker) { if(err == ERR_NONE) { FURI_LOG_I(TAG, "Found key"); memcpy(pacs->key, key, PICOPASS_BLOCK_LEN); + pacs->elite_kdf = elite; err = picopass_read_card(AA1); if(err != ERR_NONE) { FURI_LOG_E(TAG, "picopass_read_card error %d", err); @@ -720,7 +721,7 @@ void picopass_worker_write_key(PicopassWorker* picopass_worker) { uint8_t* oldKey = AA1[PICOPASS_KD_BLOCK_INDEX].data; uint8_t newKey[PICOPASS_BLOCK_LEN] = {0}; - loclass_iclass_calc_div_key(csn, pacs->key, newKey, false); + loclass_iclass_calc_div_key(csn, pacs->key, newKey, pacs->elite_kdf); if((fuses & 0x80) == 0x80) { FURI_LOG_D(TAG, "Plain write for personalized mode key change"); diff --git a/applications/external/picopass/scenes/picopass_scene_key_menu.c b/applications/external/picopass/scenes/picopass_scene_key_menu.c index 8aac6cb2491a..15a32ff4418d 100644 --- a/applications/external/picopass/scenes/picopass_scene_key_menu.c +++ b/applications/external/picopass/scenes/picopass_scene_key_menu.c @@ -60,24 +60,28 @@ bool picopass_scene_key_menu_on_event(void* context, SceneManagerEvent event) { scene_manager_set_scene_state( picopass->scene_manager, PicopassSceneKeyMenu, SubmenuIndexWriteStandard); memcpy(picopass->dev->dev_data.pacs.key, picopass_iclass_key, PICOPASS_BLOCK_LEN); + picopass->dev->dev_data.pacs.elite_kdf = false; scene_manager_next_scene(picopass->scene_manager, PicopassSceneWriteKey); consumed = true; } else if(event.event == SubmenuIndexWriteiCE) { scene_manager_set_scene_state( picopass->scene_manager, PicopassSceneKeyMenu, SubmenuIndexWriteiCE); memcpy(picopass->dev->dev_data.pacs.key, picopass_xice_key, PICOPASS_BLOCK_LEN); + picopass->dev->dev_data.pacs.elite_kdf = true; scene_manager_next_scene(picopass->scene_manager, PicopassSceneWriteKey); consumed = true; } else if(event.event == SubmenuIndexWriteiCL) { scene_manager_set_scene_state( - picopass->scene_manager, PicopassSceneKeyMenu, SubmenuIndexWriteiCE); + picopass->scene_manager, PicopassSceneKeyMenu, SubmenuIndexWriteiCL); memcpy(picopass->dev->dev_data.pacs.key, picopass_xicl_key, PICOPASS_BLOCK_LEN); + picopass->dev->dev_data.pacs.elite_kdf = false; scene_manager_next_scene(picopass->scene_manager, PicopassSceneWriteKey); consumed = true; } else if(event.event == SubmenuIndexWriteiCS) { scene_manager_set_scene_state( - picopass->scene_manager, PicopassSceneKeyMenu, SubmenuIndexWriteiCE); + picopass->scene_manager, PicopassSceneKeyMenu, SubmenuIndexWriteiCS); memcpy(picopass->dev->dev_data.pacs.key, picopass_xics_key, PICOPASS_BLOCK_LEN); + picopass->dev->dev_data.pacs.elite_kdf = false; scene_manager_next_scene(picopass->scene_manager, PicopassSceneWriteKey); consumed = true; } diff --git a/applications/external/weather_station/protocols/oregon3.c b/applications/external/weather_station/protocols/oregon3.c index a211c5ad326f..bd35c2fd576f 100644 --- a/applications/external/weather_station/protocols/oregon3.c +++ b/applications/external/weather_station/protocols/oregon3.c @@ -116,9 +116,11 @@ static ManchesterEvent level_and_duration_to_event(bool level, uint32_t duration static uint8_t oregon3_sensor_id_var_bits(uint16_t sensor_id) { switch(sensor_id) { case ID_THGR221: - default: // nibbles: temp + hum + '0' return (4 + 2 + 1) * 4; + default: + FURI_LOG_D(TAG, "Unsupported sensor id 0x%x", sensor_id); + return 0; } } @@ -198,10 +200,8 @@ void ws_protocol_decoder_oregon3_feed(void* context, bool level, uint32_t durati oregon3_sensor_id_var_bits(OREGON3_SENSOR_ID(instance->generic.data)); if(!instance->var_bits) { - // sensor is not supported, stop decoding, but showing the decoded fixed part + // sensor is not supported, stop decoding instance->decoder.parser_step = Oregon3DecoderStepReset; - if(instance->base.callback) - instance->base.callback(&instance->base, instance->base.context); } else { instance->decoder.parser_step = Oregon3DecoderStepVarData; } diff --git a/applications/main/application.fam b/applications/main/application.fam index e2b3dd437765..a1c4a06804fd 100644 --- a/applications/main/application.fam +++ b/applications/main/application.fam @@ -13,5 +13,20 @@ App( # "bad_usb", # "u2f", # "archive", + # "main_apps_on_start", + ], +) + +App( + appid="main_apps_on_start", + name="On start hooks", + apptype=FlipperAppType.METAPACKAGE, + provides=[ + "ibutton_start", + "onewire_start", + "subghz_start", + "infrared_start", + "lfrfid_start", + "nfc_start", ], ) diff --git a/applications/main/archive/helpers/archive_browser.c b/applications/main/archive/helpers/archive_browser.c index 70137d6944d5..51457fe81fe7 100644 --- a/applications/main/archive/helpers/archive_browser.c +++ b/applications/main/archive/helpers/archive_browser.c @@ -64,8 +64,20 @@ static void if(!is_last) { archive_add_file_item(browser, is_folder, furi_string_get_cstr(item_path)); } else { + bool load_again = false; with_view_model( - browser->view, ArchiveBrowserViewModel * model, { model->list_loading = false; }, true); + browser->view, + ArchiveBrowserViewModel * model, + { + model->list_loading = false; + if(archive_is_file_list_load_required(model)) { + load_again = true; + } + }, + true); + if(load_again) { + archive_file_array_load(browser, 0); + } } } @@ -111,6 +123,26 @@ bool archive_is_item_in_array(ArchiveBrowserViewModel* model, uint32_t idx) { return true; } +bool archive_is_file_list_load_required(ArchiveBrowserViewModel* model) { + size_t array_size = files_array_size(model->files); + + if((model->list_loading) || (array_size >= model->item_cnt)) { + return false; + } + + if((model->array_offset > 0) && + (model->item_idx < (model->array_offset + FILE_LIST_BUF_LEN / 4))) { + return true; + } + + if(((model->array_offset + array_size) < model->item_cnt) && + (model->item_idx > (int32_t)(model->array_offset + array_size - FILE_LIST_BUF_LEN / 4))) { + return true; + } + + return false; +} + void archive_update_offset(ArchiveBrowserView* browser) { furi_assert(browser); diff --git a/applications/main/archive/helpers/archive_browser.h b/applications/main/archive/helpers/archive_browser.h index 09ffea1f9c88..5e66a3dbbcbb 100644 --- a/applications/main/archive/helpers/archive_browser.h +++ b/applications/main/archive/helpers/archive_browser.h @@ -64,6 +64,7 @@ inline bool archive_is_known_app(ArchiveFileTypeEnum type) { } bool archive_is_item_in_array(ArchiveBrowserViewModel* model, uint32_t idx); +bool archive_is_file_list_load_required(ArchiveBrowserViewModel* model); void archive_update_offset(ArchiveBrowserView* browser); void archive_update_focus(ArchiveBrowserView* browser, const char* target); diff --git a/applications/main/archive/scenes/archive_scene_browser.c b/applications/main/archive/scenes/archive_scene_browser.c index e02f7622a6da..370830a00185 100644 --- a/applications/main/archive/scenes/archive_scene_browser.c +++ b/applications/main/archive/scenes/archive_scene_browser.c @@ -5,13 +5,14 @@ #include "../helpers/archive_browser.h" #include "../views/archive_browser_view.h" #include "archive/scenes/archive_scene.h" +#include #define TAG "ArchiveSceneBrowser" #define SCENE_STATE_DEFAULT (0) #define SCENE_STATE_NEED_REFRESH (1) -const char* archive_get_flipper_app_name(ArchiveFileTypeEnum file_type) { +static const char* archive_get_flipper_app_name(ArchiveFileTypeEnum file_type) { switch(file_type) { case ArchiveFileTypeIButton: return "iButton"; diff --git a/applications/main/archive/views/archive_browser_view.c b/applications/main/archive/views/archive_browser_view.c index 3c2f13215403..ba147f74c8cf 100644 --- a/applications/main/archive/views/archive_browser_view.c +++ b/applications/main/archive/views/archive_browser_view.c @@ -248,24 +248,10 @@ View* archive_browser_get_view(ArchiveBrowserView* browser) { return browser->view; } -static bool is_file_list_load_required(ArchiveBrowserViewModel* model) { - size_t array_size = files_array_size(model->files); - - if((model->list_loading) || (array_size >= model->item_cnt)) { - return false; - } - - if((model->array_offset > 0) && - (model->item_idx < (model->array_offset + FILE_LIST_BUF_LEN / 4))) { - return true; +static void file_list_rollover(ArchiveBrowserViewModel* model) { + if(!model->list_loading && files_array_size(model->files) < model->item_cnt) { + files_array_reset(model->files); } - - if(((model->array_offset + array_size) < model->item_cnt) && - (model->item_idx > (int32_t)(model->array_offset + array_size - FILE_LIST_BUF_LEN / 4))) { - return true; - } - - return false; } static bool archive_view_input(InputEvent* event, void* context) { @@ -347,12 +333,13 @@ static bool archive_view_input(InputEvent* event, void* context) { if(model->item_idx < scroll_speed) { model->button_held_for_ticks = 0; model->item_idx = model->item_cnt - 1; + file_list_rollover(model); } else { model->item_idx = ((model->item_idx - scroll_speed) + model->item_cnt) % model->item_cnt; } - if(is_file_list_load_required(model)) { + if(archive_is_file_list_load_required(model)) { model->list_loading = true; browser->callback(ArchiveBrowserEventLoadPrevItems, browser->context); } @@ -366,10 +353,11 @@ static bool archive_view_input(InputEvent* event, void* context) { if(model->item_idx + scroll_speed >= count) { model->button_held_for_ticks = 0; model->item_idx = 0; + file_list_rollover(model); } else { model->item_idx = (model->item_idx + scroll_speed) % model->item_cnt; } - if(is_file_list_load_required(model)) { + if(archive_is_file_list_load_required(model)) { model->list_loading = true; browser->callback(ArchiveBrowserEventLoadNextItems, browser->context); } diff --git a/applications/main/bad_usb/application.fam b/applications/main/bad_usb/application.fam index 2442dd3aa0fb..5c42c9fa3f17 100644 --- a/applications/main/bad_usb/application.fam +++ b/applications/main/bad_usb/application.fam @@ -1,15 +1,12 @@ App( appid="bad_usb", name="Bad USB", - apptype=FlipperAppType.APP, + apptype=FlipperAppType.MENUEXTERNAL, entry_point="bad_usb_app", - cdefines=["APP_BAD_USB"], - requires=[ - "gui", - "dialogs", - ], stack_size=2 * 1024, icon="A_BadUsb_14", order=70, fap_libs=["assets"], + fap_icon="icon.png", + fap_category="USB", ) diff --git a/applications/main/bad_usb/icon.png b/applications/main/bad_usb/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..037474aa3bc9c2e1aca79a68483e69980432bcf5 GIT binary patch literal 576 zcmV-G0>AxEX>4Tx04R}tkv&MmKpe$i(`rSk4t5Z6$WWau6cusQDionYs1;guFuC*#nlvOW zE{=k0!NHHks)LKOt`4q(Aou~|=;Wm6A|?JWDYS_3;J6>}?mh0_0Yan9G%FATG`(u3 z5^*t;T@{0`5D-8=V(6BcWz0!Z5}xDh9zMR_MR}I@xj#prnzI<-6NzV;VOEJZh^IHJ z2Iqa^Fe}O`@j3ChNf#u3C`-Nm{=@yu+qV-Xlle$#1U1~DPPFA zta9Gstd(o5bx;1nP)=W2<~q$0B(R7jND!f*h7!uCB1)@HiiH&I$36VRj$a~|Laq`R zITlcX2HEk0|H1EWt^DMKn-q!zT`#u%F$x5Cfo9#dzmILZc>?&Kfh)c3uQY&}Ptxmc zEph}5Yy%h9ZB5w&E_Z;TCqp)6NAlAY@_FF>jJ_!g4Bi60Yi@6?eVjf3Y3eF@0~{Oz zV+G1y_jq?tXK(+WY4!I5C=YUpXXIhH00006VoOIv0RI600RN!9r;`8x010qNS#tmY z3ljhU3ljkVnw%H_000McNliru<^lu`HWXkp{t5s906j@WK~xyijZi@f05Awj>HlAL zr$MwDdI>{Qf+U53tOUR#xOeyy)jcQo#JNRv)7r6DVVK|+*(cmT+R+EbO(O#X#REG4 O00005OriujUt-p2+p8kXl9tpG9lUcLq-^x45JRS1+%E^do6+pY)OCI_kBL^ z^L^j<-uGRTsW5+e-$PrRKtwBnona~L!R4zM%2+9EyT(WuJ-NWa6x8ydq_(isQtPy6tyorO zq|Q%50XGn7)bDn&0_mr)pe_lYB{PnpL5k?4FtgEw=5jnhH42S_z%nCI9dEUf#rij< zo#BeY9HQtUaop$gDSYV)j<@4VtyYT@DqN+KLxx-kup;f3v%*?QBBY@Qf`w;1BEzw$ zq)AtDUXj8uh@;cuB4e9XXNBqG!$jZ`f-4mS{yZJ{nMLRlGLP$o z&vS(7TiC@9&vd3g)Ss{yRIHkb)1 zFQmau+rd`A+C>M2DTx<=?TqzByCmfDN|o5gGH`3vtc!UTqp%DWuAGI+7KEf!lP1Ow zTxLDv2CM*8XQG$|%N7B1ITy#5z_tbywn?K&*97;QsRbFtjhq$2=`TQr+*}jS*%%kZ z@(r+YE4_?MlrtVIH2ddM&^j z3>C_SP=T|FKAH#Fc35Q!%eL7VSfl`IlG+zlp(+KTP|tPoIRKPf{BZbmXt;Fmp2eoa z=S8mz5}v!L&@W_z0{~7Ed}fru#mq1QESx|*95vss`9+B!VY?YvnE3@kkPZ9m_EQDD zo0G0r^jGDbj;@KRzF|7DF+QPsAT_=%=TyR5UgFYU%UaaQa>d>TXHU<*>!%xcU+9SL zXh0u@jf{;RAH&u?#ZxZsoEYwU?ZJKO{!m!Xmp9dEG2!a&suQu*%1_G^8qdYVY|g42 zJJbwr8j53&{&sgw=9Qtmz@f=YS^39WE+h`eHQAf#H=8ncp3FG2Tcy_2=e|;`v)W?T)HzCD&GN>rbh;(bdimjkF(hwtI`7 zerqbMDEpoKVP*39o$Cr>+P?TWw(k_SdfV;JtNYxS1F}cQ>eIUKom1~?75P%ENV#B?PR&Lb*-5QGoBgi((fy> zb5lo|zbC^ttl*oL9*K&DZ;zKf1!V$)EQ^!AVMt4BA~b3Z`s~uggI|53j7Es1vYx4_ z=I9e!lEzKzS2UPnkpqF_t8X7v6MqhT(E8rj<6Re5{q*aBxZXxZxlTB_{+~gr?QQAB NWXLPjcjUa=@GmQdSu_9u literal 0 HcmV?d00001 diff --git a/applications/main/ibutton/application.fam b/applications/main/ibutton/application.fam index 06968bba48f6..a8faa629cea2 100644 --- a/applications/main/ibutton/application.fam +++ b/applications/main/ibutton/application.fam @@ -1,25 +1,21 @@ App( appid="ibutton", name="iButton", - apptype=FlipperAppType.APP, + apptype=FlipperAppType.MENUEXTERNAL, targets=["f7"], entry_point="ibutton_app", - cdefines=["APP_IBUTTON"], - requires=[ - "gui", - "dialogs", - ], - provides=["ibutton_start"], icon="A_iButton_14", stack_size=2 * 1024, order=60, fap_libs=["assets"], + fap_icon="icon.png", + fap_category="iButton", ) App( appid="ibutton_start", apptype=FlipperAppType.STARTUP, + targets=["f7"], entry_point="ibutton_on_system_start", - requires=["ibutton"], order=60, ) diff --git a/applications/main/ibutton/icon.png b/applications/main/ibutton/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..2fdaf123a657c00c9c84632ca3c151674e451ae1 GIT binary patch literal 304 zcmeAS@N?(olHy`uVBq!ia0vp^AT}2xkYHHq`AGmsv7|ftIx;Y9?C1WI$O_~uBzpw; zGB8xBF)%c=FfjZA3N^f7U???UV0e|lz+g3lfkC`r&aOZkpafHrx4R1i<>&pI=m5)bW_|craZ$KesPZ!4!j_b)kjvx52z42i= z^Wk##wtdVzTiGS{99;2>!TC2M!yZeXz}?LkD}l;YOI#yLQW8s2t&)pUffR$0fsvuE zfvK*cNr<75m9c@9v4ysQft7*5`ikN&C>nC}Q!>*kp&E>VdO{3LtqcsU49p-Jly36? Qy~)7f>FVdQ&MBb@0C$~I0{{R3 literal 0 HcmV?d00001 diff --git a/applications/main/ibutton/scenes/ibutton_scene_delete_confirm.c b/applications/main/ibutton/scenes/ibutton_scene_delete_confirm.c index 587cb748cd4e..b293af952cef 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_delete_confirm.c +++ b/applications/main/ibutton/scenes/ibutton_scene_delete_confirm.c @@ -12,15 +12,15 @@ void ibutton_scene_delete_confirm_on_enter(void* context) { widget_add_button_element( widget, GuiButtonTypeRight, "Delete", ibutton_widget_callback, context); - furi_string_printf(tmp, "Delete %s?", ibutton->key_name); - widget_add_string_element( - widget, 128 / 2, 0, AlignCenter, AlignTop, FontPrimary, furi_string_get_cstr(tmp)); + furi_string_printf(tmp, "\e#Delete %s?\e#", ibutton->key_name); + widget_add_text_box_element( + widget, 0, 0, 128, 23, AlignCenter, AlignCenter, furi_string_get_cstr(tmp), false); furi_string_reset(tmp); ibutton_protocols_render_brief_data(ibutton->protocols, key, tmp); widget_add_string_multiline_element( - widget, 128 / 2, 16, AlignCenter, AlignTop, FontSecondary, furi_string_get_cstr(tmp)); + widget, 128 / 2, 24, AlignCenter, AlignTop, FontSecondary, furi_string_get_cstr(tmp)); view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewWidget); furi_string_free(tmp); diff --git a/applications/main/infrared/application.fam b/applications/main/infrared/application.fam index e5483e9ffa91..b78b088a7277 100644 --- a/applications/main/infrared/application.fam +++ b/applications/main/infrared/application.fam @@ -1,25 +1,21 @@ App( appid="infrared", name="Infrared", - apptype=FlipperAppType.APP, + apptype=FlipperAppType.MENUEXTERNAL, entry_point="infrared_app", targets=["f7"], - cdefines=["APP_INFRARED"], - requires=[ - "gui", - "dialogs", - ], - provides=["infrared_start"], icon="A_Infrared_14", stack_size=3 * 1024, order=40, fap_libs=["assets"], + fap_icon="icon.png", + fap_category="Infrared", ) App( appid="infrared_start", apptype=FlipperAppType.STARTUP, + targets=["f7"], entry_point="infrared_on_system_start", - requires=["infrared"], order=20, ) diff --git a/applications/main/infrared/icon.png b/applications/main/infrared/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..22c986180a2bed76dbe4ff439df1cf9177533c32 GIT binary patch literal 305 zcmeAS@N?(olHy`uVBq!ia0vp^AT}2xkYHHq`AGmsv7|ftIx;Y9?C1WI$O_~uBzpw; zGB8xBF)%c=FfjZA3N^f7U???UV0e|lz+g3lfkC`r&aOZkpafHrx4R1i<>&pI=m5)bWC*+s&X`qmbr;B3<$Ms~3f`-KX%+5*7 zhxan`%;z`w!#>%c-@wM^z<~n{3>VXQv+hhNs0FH5Epd$~Nl7e8wMs5Z1yT$~21bUu z2Bx}(CLxAKR>lTa#unNJ237_J>nn=CplHa=PsvQHglaGb>IpG01*)?$HiBr_e$xf$ PHwFezS3j3^P6<>&pI=m5)bWZjP>yH&963)5S4_<9hOs!iI<>&pI=m5)b(dHL6nbwD9yPZ!4!j_b)k${QZ;XFmLn zjqNsD+YPq1J8W%_*aXBie!OR3*tC!PwU_7Q9H4U564!{5l*E!$tK_0oAjM#0U}UIk zV5)0q5@Kj%Wo%$&Y@uynU}a#izM}XGiiX_$l+3hBs0L%8o)7~QD^p9LQiz6svOM}g O4Gf;HelF{r5}E+GUQp8j literal 0 HcmV?d00001 diff --git a/applications/main/onewire/application.fam b/applications/main/onewire/application.fam index 68d4f6716939..3d35abce948f 100644 --- a/applications/main/onewire/application.fam +++ b/applications/main/onewire/application.fam @@ -1,14 +1,6 @@ -App( - appid="onewire", - name="1-Wire", - apptype=FlipperAppType.METAPACKAGE, - provides=["onewire_start"], -) - App( appid="onewire_start", apptype=FlipperAppType.STARTUP, entry_point="onewire_on_system_start", - requires=["onewire"], order=60, ) diff --git a/applications/main/subghz/application.fam b/applications/main/subghz/application.fam index f0dc66e89ccd..4f21cb6c4e90 100644 --- a/applications/main/subghz/application.fam +++ b/applications/main/subghz/application.fam @@ -1,25 +1,21 @@ App( appid="subghz", name="Sub-GHz", - apptype=FlipperAppType.APP, + apptype=FlipperAppType.MENUEXTERNAL, targets=["f7"], entry_point="subghz_app", - cdefines=["APP_SUBGHZ"], - requires=[ - "gui", - "cli", - "dialogs", - ], - provides=["subghz_start"], icon="A_Sub1ghz_14", stack_size=3 * 1024, order=10, + fap_libs=["assets", "hwdrivers"], + fap_icon="icon.png", + fap_category="Sub-GHz", ) App( appid="subghz_start", + targets=["f7"], apptype=FlipperAppType.STARTUP, entry_point="subghz_on_system_start", - requires=["subghz"], order=40, ) diff --git a/applications/main/subghz/helpers/subghz_txrx.c b/applications/main/subghz/helpers/subghz_txrx.c index b911f443459a..cbd47f5e5ee6 100644 --- a/applications/main/subghz/helpers/subghz_txrx.c +++ b/applications/main/subghz/helpers/subghz_txrx.c @@ -8,11 +8,17 @@ static void subghz_txrx_radio_device_power_on(SubGhzTxRx* instance) { UNUSED(instance); - uint8_t attempts = 0; - while(!furi_hal_power_is_otg_enabled() && attempts++ < 5) { - furi_hal_power_enable_otg(); - //CC1101 power-up time - furi_delay_ms(10); + uint8_t attempts = 5; + while(--attempts > 0) { + if(furi_hal_power_enable_otg()) break; + } + if(attempts == 0) { + if(furi_hal_power_get_usb_voltage() < 4.5f) { + FURI_LOG_E( + TAG, + "Error power otg enable. BQ2589 check otg fault = %d", + furi_hal_power_check_otg_fault() ? 1 : 0); + } } } diff --git a/applications/main/subghz/helpers/subghz_types.h b/applications/main/subghz/helpers/subghz_types.h index 8beb7b9ed097..e71c22dd5648 100644 --- a/applications/main/subghz/helpers/subghz_types.h +++ b/applications/main/subghz/helpers/subghz_types.h @@ -80,9 +80,6 @@ typedef enum { SubGhzViewIdFrequencyAnalyzer, SubGhzViewIdReadRAW, - SubGhzViewIdStatic, - SubGhzViewIdTestCarrier, - SubGhzViewIdTestPacket, } SubGhzViewId; /** SubGhz load type file */ diff --git a/applications/main/subghz/icon.png b/applications/main/subghz/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..5a25fdf4ef1c6cf53634aa74675001a3e8c85b7b GIT binary patch literal 299 zcmeAS@N?(olHy`uVBq!ia0vp^AT}2xkYHHq`AGmsv7|ftIx;Y9?C1WI$O_~uBzpw; zGB8xBF)%c=FfjZA3N^f7U???UV0e|lz+g3lfkC`r&aOZkpafHrx4R1i<>&pI=m5)cB{fFDGZlI8yr;B3<$MxhJ?+;A4eL&#) z0Ra}bue?07WhLz78x$BO|L3mq-MMxdP^D^#YeY#(Vo9o1a#1RfVlXl=GSoFN)ipE; zF*LF=Hn1|b&^9ozGB8+QQTzo(LvDUbW?CgwgE3G~h=Hksubmenu, "Test", SubmenuIndexTest, subghz_scene_start_submenu_callback, subghz); - } submenu_set_selected_item( subghz->submenu, scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneStart)); @@ -101,11 +96,6 @@ bool subghz_scene_start_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneFrequencyAnalyzer); dolphin_deed(DolphinDeedSubGhzFrequencyAnalyzer); return true; - } else if(event.event == SubmenuIndexTest) { - scene_manager_set_scene_state( - subghz->scene_manager, SubGhzSceneStart, SubmenuIndexTest); - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneTest); - return true; } else if(event.event == SubmenuIndexShowRegionInfo) { scene_manager_set_scene_state( subghz->scene_manager, SubGhzSceneStart, SubmenuIndexShowRegionInfo); diff --git a/applications/main/subghz/scenes/subghz_scene_test.c b/applications/main/subghz/scenes/subghz_scene_test.c deleted file mode 100644 index 65f9bbdefade..000000000000 --- a/applications/main/subghz/scenes/subghz_scene_test.c +++ /dev/null @@ -1,61 +0,0 @@ -#include "../subghz_i.h" - -enum SubmenuIndex { - SubmenuIndexCarrier, - SubmenuIndexPacket, - SubmenuIndexStatic, -}; - -void subghz_scene_test_submenu_callback(void* context, uint32_t index) { - SubGhz* subghz = context; - view_dispatcher_send_custom_event(subghz->view_dispatcher, index); -} - -void subghz_scene_test_on_enter(void* context) { - SubGhz* subghz = context; - - submenu_add_item( - subghz->submenu, - "Carrier", - SubmenuIndexCarrier, - subghz_scene_test_submenu_callback, - subghz); - submenu_add_item( - subghz->submenu, "Packet", SubmenuIndexPacket, subghz_scene_test_submenu_callback, subghz); - submenu_add_item( - subghz->submenu, "Static", SubmenuIndexStatic, subghz_scene_test_submenu_callback, subghz); - - submenu_set_selected_item( - subghz->submenu, scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneTest)); - - view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdMenu); -} - -bool subghz_scene_test_on_event(void* context, SceneManagerEvent event) { - SubGhz* subghz = context; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == SubmenuIndexCarrier) { - scene_manager_set_scene_state( - subghz->scene_manager, SubGhzSceneTest, SubmenuIndexCarrier); - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneTestCarrier); - return true; - } else if(event.event == SubmenuIndexPacket) { - scene_manager_set_scene_state( - subghz->scene_manager, SubGhzSceneTest, SubmenuIndexPacket); - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneTestPacket); - return true; - } else if(event.event == SubmenuIndexStatic) { - scene_manager_set_scene_state( - subghz->scene_manager, SubGhzSceneTest, SubmenuIndexStatic); - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneTestStatic); - return true; - } - } - return false; -} - -void subghz_scene_test_on_exit(void* context) { - SubGhz* subghz = context; - submenu_reset(subghz->submenu); -} diff --git a/applications/main/subghz/scenes/subghz_scene_test_carrier.c b/applications/main/subghz/scenes/subghz_scene_test_carrier.c deleted file mode 100644 index 9677792ba319..000000000000 --- a/applications/main/subghz/scenes/subghz_scene_test_carrier.c +++ /dev/null @@ -1,30 +0,0 @@ -#include "../subghz_i.h" -#include "../views/subghz_test_carrier.h" - -void subghz_scene_test_carrier_callback(SubGhzTestCarrierEvent event, void* context) { - furi_assert(context); - SubGhz* subghz = context; - view_dispatcher_send_custom_event(subghz->view_dispatcher, event); -} - -void subghz_scene_test_carrier_on_enter(void* context) { - SubGhz* subghz = context; - subghz_test_carrier_set_callback( - subghz->subghz_test_carrier, subghz_scene_test_carrier_callback, subghz); - view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdTestCarrier); -} - -bool subghz_scene_test_carrier_on_event(void* context, SceneManagerEvent event) { - SubGhz* subghz = context; - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == SubGhzTestCarrierEventOnlyRx) { - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx); - return true; - } - } - return false; -} - -void subghz_scene_test_carrier_on_exit(void* context) { - UNUSED(context); -} diff --git a/applications/main/subghz/scenes/subghz_scene_test_packet.c b/applications/main/subghz/scenes/subghz_scene_test_packet.c deleted file mode 100644 index 99f0ab1791fd..000000000000 --- a/applications/main/subghz/scenes/subghz_scene_test_packet.c +++ /dev/null @@ -1,30 +0,0 @@ -#include "../subghz_i.h" -#include "../views/subghz_test_packet.h" - -void subghz_scene_test_packet_callback(SubGhzTestPacketEvent event, void* context) { - furi_assert(context); - SubGhz* subghz = context; - view_dispatcher_send_custom_event(subghz->view_dispatcher, event); -} - -void subghz_scene_test_packet_on_enter(void* context) { - SubGhz* subghz = context; - subghz_test_packet_set_callback( - subghz->subghz_test_packet, subghz_scene_test_packet_callback, subghz); - view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdTestPacket); -} - -bool subghz_scene_test_packet_on_event(void* context, SceneManagerEvent event) { - SubGhz* subghz = context; - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == SubGhzTestPacketEventOnlyRx) { - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx); - return true; - } - } - return false; -} - -void subghz_scene_test_packet_on_exit(void* context) { - UNUSED(context); -} diff --git a/applications/main/subghz/scenes/subghz_scene_test_static.c b/applications/main/subghz/scenes/subghz_scene_test_static.c deleted file mode 100644 index 10e6d02a1da9..000000000000 --- a/applications/main/subghz/scenes/subghz_scene_test_static.c +++ /dev/null @@ -1,30 +0,0 @@ -#include "../subghz_i.h" -#include "../views/subghz_test_static.h" - -void subghz_scene_test_static_callback(SubGhzTestStaticEvent event, void* context) { - furi_assert(context); - SubGhz* subghz = context; - view_dispatcher_send_custom_event(subghz->view_dispatcher, event); -} - -void subghz_scene_test_static_on_enter(void* context) { - SubGhz* subghz = context; - subghz_test_static_set_callback( - subghz->subghz_test_static, subghz_scene_test_static_callback, subghz); - view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdStatic); -} - -bool subghz_scene_test_static_on_event(void* context, SceneManagerEvent event) { - SubGhz* subghz = context; - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == SubGhzTestStaticEventOnlyRx) { - scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx); - return true; - } - } - return false; -} - -void subghz_scene_test_static_on_exit(void* context) { - UNUSED(context); -} diff --git a/applications/main/subghz/subghz.c b/applications/main/subghz/subghz.c index 09963584afcf..e8148798ef4a 100644 --- a/applications/main/subghz/subghz.c +++ b/applications/main/subghz/subghz.c @@ -129,27 +129,6 @@ SubGhz* subghz_alloc() { SubGhzViewIdReadRAW, subghz_read_raw_get_view(subghz->subghz_read_raw)); - // Carrier Test Module - subghz->subghz_test_carrier = subghz_test_carrier_alloc(); - view_dispatcher_add_view( - subghz->view_dispatcher, - SubGhzViewIdTestCarrier, - subghz_test_carrier_get_view(subghz->subghz_test_carrier)); - - // Packet Test - subghz->subghz_test_packet = subghz_test_packet_alloc(); - view_dispatcher_add_view( - subghz->view_dispatcher, - SubGhzViewIdTestPacket, - subghz_test_packet_get_view(subghz->subghz_test_packet)); - - // Static send - subghz->subghz_test_static = subghz_test_static_alloc(); - view_dispatcher_add_view( - subghz->view_dispatcher, - SubGhzViewIdStatic, - subghz_test_static_get_view(subghz->subghz_test_static)); - //init threshold rssi subghz->threshold_rssi = subghz_threshold_rssi_alloc(); @@ -183,18 +162,6 @@ void subghz_free(SubGhz* subghz) { subghz_txrx_stop(subghz->txrx); subghz_txrx_sleep(subghz->txrx); - // Packet Test - view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewIdTestPacket); - subghz_test_packet_free(subghz->subghz_test_packet); - - // Carrier Test - view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewIdTestCarrier); - subghz_test_carrier_free(subghz->subghz_test_carrier); - - // Static - view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewIdStatic); - subghz_test_static_free(subghz->subghz_test_static); - // Receiver view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewIdReceiver); subghz_view_receiver_free(subghz->subghz_receiver); diff --git a/applications/main/subghz/subghz_cli.c b/applications/main/subghz/subghz_cli.c index bc7be507e73f..fe97c8a06713 100644 --- a/applications/main/subghz/subghz_cli.c +++ b/applications/main/subghz/subghz_cli.c @@ -28,12 +28,20 @@ #define SUBGHZ_REGION_FILENAME "/int/.region_data" +#define TAG "SubGhz CLI" + static void subghz_cli_radio_device_power_on() { - uint8_t attempts = 0; - while(!furi_hal_power_is_otg_enabled() && attempts++ < 5) { - furi_hal_power_enable_otg(); - //CC1101 power-up time - furi_delay_ms(10); + uint8_t attempts = 5; + while(--attempts > 0) { + if(furi_hal_power_enable_otg()) break; + } + if(attempts == 0) { + if(furi_hal_power_get_usb_voltage() < 4.5f) { + FURI_LOG_E( + "TAG", + "Error power otg enable. BQ2589 check otg fault = %d", + furi_hal_power_check_otg_fault() ? 1 : 0); + } } } @@ -126,9 +134,9 @@ void subghz_cli_command_rx_carrier(Cli* cli, FuriString* args, void* context) { furi_hal_subghz_sleep(); } -static const SubGhzDevice* subghz_cli_command_get_device(uint32_t device_ind) { +static const SubGhzDevice* subghz_cli_command_get_device(uint32_t* device_ind) { const SubGhzDevice* device = NULL; - switch(device_ind) { + switch(*device_ind) { case 1: subghz_cli_radio_device_power_on(); device = subghz_devices_get_by_name(SUBGHZ_DEVICE_CC1101_EXT_NAME); @@ -138,6 +146,12 @@ static const SubGhzDevice* subghz_cli_command_get_device(uint32_t device_ind) { device = subghz_devices_get_by_name(SUBGHZ_DEVICE_CC1101_INT_NAME); break; } + //check if the device is connected + if(!subghz_devices_is_connect(device)) { + subghz_cli_radio_device_power_off(); + device = subghz_devices_get_by_name(SUBGHZ_DEVICE_CC1101_INT_NAME); + *device_ind = 0; + } return device; } @@ -175,7 +189,7 @@ void subghz_cli_command_tx(Cli* cli, FuriString* args, void* context) { } } subghz_devices_init(); - const SubGhzDevice* device = subghz_cli_command_get_device(device_ind); + const SubGhzDevice* device = subghz_cli_command_get_device(&device_ind); if(!subghz_devices_is_frequency_valid(device, frequency)) { printf( "Frequency must be in " SUBGHZ_FREQUENCY_RANGE_STR " range, not %lu\r\n", frequency); @@ -295,7 +309,7 @@ void subghz_cli_command_rx(Cli* cli, FuriString* args, void* context) { } } subghz_devices_init(); - const SubGhzDevice* device = subghz_cli_command_get_device(device_ind); + const SubGhzDevice* device = subghz_cli_command_get_device(&device_ind); if(!subghz_devices_is_frequency_valid(device, frequency)) { printf( "Frequency must be in " SUBGHZ_FREQUENCY_RANGE_STR " range, not %lu\r\n", frequency); @@ -688,7 +702,7 @@ static void subghz_cli_command_chat(Cli* cli, FuriString* args) { } } subghz_devices_init(); - const SubGhzDevice* device = subghz_cli_command_get_device(device_ind); + const SubGhzDevice* device = subghz_cli_command_get_device(&device_ind); if(!subghz_devices_is_frequency_valid(device, frequency)) { printf( "Frequency must be in " SUBGHZ_FREQUENCY_RANGE_STR " range, not %lu\r\n", frequency); diff --git a/applications/main/subghz/subghz_i.h b/applications/main/subghz/subghz_i.h index fc3404c07e73..9e58f3947dc7 100644 --- a/applications/main/subghz/subghz_i.h +++ b/applications/main/subghz/subghz_i.h @@ -9,10 +9,6 @@ #include "views/subghz_frequency_analyzer.h" #include "views/subghz_read_raw.h" -#include "views/subghz_test_static.h" -#include "views/subghz_test_carrier.h" -#include "views/subghz_test_packet.h" - #include #include #include @@ -64,9 +60,6 @@ struct SubGhz { SubGhzFrequencyAnalyzer* subghz_frequency_analyzer; SubGhzReadRAW* subghz_read_raw; - SubGhzTestStatic* subghz_test_static; - SubGhzTestCarrier* subghz_test_carrier; - SubGhzTestPacket* subghz_test_packet; SubGhzProtocolFlag filter; FuriString* error_str; diff --git a/applications/main/u2f/application.fam b/applications/main/u2f/application.fam index 82010ffb4397..8167e6277b34 100644 --- a/applications/main/u2f/application.fam +++ b/applications/main/u2f/application.fam @@ -1,15 +1,12 @@ App( appid="u2f", name="U2F", - apptype=FlipperAppType.APP, + apptype=FlipperAppType.MENUEXTERNAL, entry_point="u2f_app", - cdefines=["APP_U2F"], - requires=[ - "gui", - "dialogs", - ], stack_size=2 * 1024, icon="A_U2F_14", order=80, fap_libs=["assets"], + fap_category="USB", + fap_icon="icon.png", ) diff --git a/applications/main/u2f/icon.png b/applications/main/u2f/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..fcd87a2ef56d95eb1314c92354f97d37abac184a GIT binary patch literal 583 zcmV-N0=WH&P)EX>4Tx04R}tkv&MmKpe$i(`rSk4t5Z6$WWau6cusQDionYs1;guFuC*#nlvOW zE{=k0!NHHks)LKOt`4q(Aou~|=;Wm6A|?JWDYS_3;J6>}?mh0_0Yan9G%FATG`(u3 z5^*t;T@{0`5D-8=V(6BcWz0!Z5}xDh9zMR_MR}I@xj#prnzI<-6NzV;VOEJZh^IHJ z2Iqa^Fe}O`@j3ChNf#u3C`-Nm{=@yu+qV-Xlle$#1U1~DPPFA zta9Gstd(o5bx;1nP)=W2<~q$0B(R7jND!f*h7!uCB1)@HiiH&I$36VRj$a~|Laq`R zITlcX2HEk0|H1EWt^DMKn-q!zT`#u%F$x5Cfo9#dzmILZc>?&Kfh)c3uQY&}Ptxmc zEph}5Yy%h9ZB5w&E_Z;TCqp)6NAlAY@_FF>jJ_!g4Bi60Yi@6?eVjf3Y3eF@0~{Oz zV+G1y_jq?tXK(+WY4!I5C=YUpXXIhH00006VoOIv00000008+zyMF)x010qNS#tmY z3ljhU3ljkVnw%H_000McNliru<^lu{1uVUoNs|Bo07OYdK~xyijgYww05Avx?TGzX zz7!EC4G1?heldU+2uZR%k^uSL+0?e2taR-}6`h2x#_2kxune}*>oEbW-V;;Yj| — start logging using the current level from the system settings\r\n"); + printf(" — only critical errors and other important messages\r\n"); + printf(" — non-critical errors and warnings including \r\n"); + printf(" — non-critical information including \r\n"); + printf(" — the default system log level (equivalent to )\r\n"); + printf( + " — debug information including (may impact system performance)\r\n"); + printf( + " — system traces including (may impact system performance)\r\n"); } + return false; } void cli_command_log(Cli* cli, FuriString* args, void* context) { @@ -193,12 +200,20 @@ void cli_command_log(Cli* cli, FuriString* args, void* context) { bool restore_log_level = false; if(furi_string_size(args) > 0) { - cli_command_log_level_set_from_string(args); + if(!cli_command_log_level_set_from_string(args)) { + furi_stream_buffer_free(ring); + return; + } restore_log_level = true; } + const char* current_level; + furi_log_level_to_string(furi_log_get_level(), ¤t_level); + printf("Current log level: %s\r\n", current_level); + furi_hal_console_set_tx_callback(cli_command_log_tx_callback, ring); + printf("Use to list available log levels\r\n"); printf("Press CTRL+C to stop...\r\n"); while(!cli_cmd_interrupt_received(cli)) { size_t ret = furi_stream_buffer_receive(ring, buffer, CLI_COMMAND_LOG_BUFFER_SIZE, 50); @@ -444,6 +459,7 @@ void cli_commands_init(Cli* cli) { cli_add_command(cli, "?", CliCommandFlagParallelSafe, cli_command_help, NULL); cli_add_command(cli, "help", CliCommandFlagParallelSafe, cli_command_help, NULL); + cli_add_command(cli, "uptime", CliCommandFlagDefault, cli_command_uptime, NULL); cli_add_command(cli, "date", CliCommandFlagParallelSafe, cli_command_date, NULL); cli_add_command(cli, "log", CliCommandFlagParallelSafe, cli_command_log, NULL); cli_add_command(cli, "sysctl", CliCommandFlagDefault, cli_command_sysctl, NULL); diff --git a/applications/services/desktop/desktop_settings.h b/applications/services/desktop/desktop_settings.h index 7ab39094d161..9b88868a8dc0 100644 --- a/applications/services/desktop/desktop_settings.h +++ b/applications/services/desktop/desktop_settings.h @@ -8,7 +8,7 @@ #include #include -#define DESKTOP_SETTINGS_VER (7) +#define DESKTOP_SETTINGS_VER (8) #define DESKTOP_SETTINGS_PATH INT_PATH(DESKTOP_SETTINGS_FILE_NAME) #define DESKTOP_SETTINGS_MAGIC (0x17) @@ -42,7 +42,6 @@ typedef struct { } PinCode; typedef struct { - bool is_external; char name_or_path[MAX_APP_LENGTH]; } FavoriteApp; diff --git a/applications/services/desktop/scenes/desktop_scene_debug.c b/applications/services/desktop/scenes/desktop_scene_debug.c index a5bd3a6b1e63..866c736abad7 100644 --- a/applications/services/desktop/scenes/desktop_scene_debug.c +++ b/applications/services/desktop/scenes/desktop_scene_debug.c @@ -14,8 +14,6 @@ void desktop_scene_debug_callback(DesktopEvent event, void* context) { void desktop_scene_debug_on_enter(void* context) { Desktop* desktop = (Desktop*)context; - desktop_debug_get_dolphin_data(desktop->debug_view); - desktop_debug_set_callback(desktop->debug_view, desktop_scene_debug_callback, desktop); view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewIdDebug); } @@ -32,24 +30,6 @@ bool desktop_scene_debug_on_event(void* context, SceneManagerEvent event) { dolphin_flush(dolphin); consumed = true; break; - - case DesktopDebugEventDeed: - dolphin_deed(DolphinDeedTestRight); - desktop_debug_get_dolphin_data(desktop->debug_view); - consumed = true; - break; - - case DesktopDebugEventWrongDeed: - dolphin_deed(DolphinDeedTestLeft); - desktop_debug_get_dolphin_data(desktop->debug_view); - consumed = true; - break; - - case DesktopDebugEventSaveState: - dolphin_flush(dolphin); - consumed = true; - break; - default: break; } @@ -60,6 +40,5 @@ bool desktop_scene_debug_on_event(void* context, SceneManagerEvent event) { } void desktop_scene_debug_on_exit(void* context) { - Desktop* desktop = (Desktop*)context; - desktop_debug_reset_screen_idx(desktop->debug_view); + UNUSED(context); } diff --git a/applications/services/desktop/views/desktop_view_debug.c b/applications/services/desktop/views/desktop_view_debug.c index 7a16c08479a4..35c7dc038861 100644 --- a/applications/services/desktop/views/desktop_view_debug.c +++ b/applications/services/desktop/views/desktop_view_debug.c @@ -18,96 +18,71 @@ void desktop_debug_set_callback( } void desktop_debug_render(Canvas* canvas, void* model) { + UNUSED(model); canvas_clear(canvas); - DesktopDebugViewModel* m = model; const Version* ver; char buffer[64]; - static const char* headers[] = {"Device Info:", "Dolphin Info:"}; - canvas_set_color(canvas, ColorBlack); canvas_set_font(canvas, FontPrimary); - canvas_draw_str_aligned( - canvas, 64, 1 + STATUS_BAR_Y_SHIFT, AlignCenter, AlignTop, headers[m->screen]); + + uint32_t uptime = furi_get_tick() / furi_kernel_get_tick_frequency(); + snprintf( + buffer, + sizeof(buffer), + "Uptime: %luh%lum%lus", + uptime / 60 / 60, + uptime / 60 % 60, + uptime % 60); + canvas_draw_str_aligned(canvas, 64, 1 + STATUS_BAR_Y_SHIFT, AlignCenter, AlignTop, buffer); + canvas_set_font(canvas, FontSecondary); - if(m->screen != DesktopViewStatsMeta) { - // Hardware version - const char* my_name = furi_hal_version_get_name_ptr(); - snprintf( - buffer, - sizeof(buffer), - "%d.F%dB%dC%d %s:%s %s", - furi_hal_version_get_hw_version(), - furi_hal_version_get_hw_target(), - furi_hal_version_get_hw_body(), - furi_hal_version_get_hw_connect(), - furi_hal_version_get_hw_region_name(), - furi_hal_region_get_name(), - my_name ? my_name : "Unknown"); - canvas_draw_str(canvas, 0, 19 + STATUS_BAR_Y_SHIFT, buffer); - - ver = furi_hal_version_get_firmware_version(); - const BleGlueC2Info* c2_ver = NULL; + // Hardware version + const char* my_name = furi_hal_version_get_name_ptr(); + snprintf( + buffer, + sizeof(buffer), + "%d.F%dB%dC%d %s:%s %s", + furi_hal_version_get_hw_version(), + furi_hal_version_get_hw_target(), + furi_hal_version_get_hw_body(), + furi_hal_version_get_hw_connect(), + furi_hal_version_get_hw_region_name(), + furi_hal_region_get_name(), + my_name ? my_name : "Unknown"); + canvas_draw_str(canvas, 0, 19 + STATUS_BAR_Y_SHIFT, buffer); + + ver = furi_hal_version_get_firmware_version(); + const BleGlueC2Info* c2_ver = NULL; #ifdef SRV_BT - c2_ver = ble_glue_get_c2_info(); + c2_ver = ble_glue_get_c2_info(); #endif - if(!ver) { //-V1051 - canvas_draw_str(canvas, 0, 30 + STATUS_BAR_Y_SHIFT, "No info"); - return; - } - - snprintf( - buffer, - sizeof(buffer), - "%s [%s]", - version_get_version(ver), - version_get_builddate(ver)); - canvas_draw_str(canvas, 0, 30 + STATUS_BAR_Y_SHIFT, buffer); - - uint16_t api_major, api_minor; - furi_hal_info_get_api_version(&api_major, &api_minor); - snprintf( - buffer, - sizeof(buffer), - "%s%s [%d.%d] %s", - version_get_dirty_flag(ver) ? "[!] " : "", - version_get_githash(ver), - api_major, - api_minor, - c2_ver ? c2_ver->StackTypeString : ""); - canvas_draw_str(canvas, 0, 40 + STATUS_BAR_Y_SHIFT, buffer); - - snprintf( - buffer, sizeof(buffer), "[%d] %s", version_get_target(ver), version_get_gitbranch(ver)); - canvas_draw_str(canvas, 0, 50 + STATUS_BAR_Y_SHIFT, buffer); - - } else { - Dolphin* dolphin = furi_record_open(RECORD_DOLPHIN); - DolphinStats stats = dolphin_stats(dolphin); - furi_record_close(RECORD_DOLPHIN); - - uint32_t current_lvl = stats.level; - uint32_t remaining = dolphin_state_xp_to_levelup(m->icounter); - - canvas_set_font(canvas, FontSecondary); - snprintf(buffer, sizeof(buffer), "Icounter: %lu Butthurt %lu", m->icounter, m->butthurt); - canvas_draw_str(canvas, 5, 19 + STATUS_BAR_Y_SHIFT, buffer); - - snprintf( - buffer, - sizeof(buffer), - "Level: %lu To level up: %lu", - current_lvl, - (remaining == (uint32_t)(-1) ? remaining : 0)); - canvas_draw_str(canvas, 5, 29 + STATUS_BAR_Y_SHIFT, buffer); - - // even if timestamp is uint64_t, it's safe to cast it to uint32_t, because furi_hal_rtc_datetime_to_timestamp only returns uint32_t - snprintf(buffer, sizeof(buffer), "%lu", (uint32_t)m->timestamp); - - canvas_draw_str(canvas, 5, 39 + STATUS_BAR_Y_SHIFT, buffer); - canvas_draw_str(canvas, 0, 49 + STATUS_BAR_Y_SHIFT, "[< >] icounter value [ok] save"); + if(!ver) { //-V1051 + canvas_draw_str(canvas, 0, 30 + STATUS_BAR_Y_SHIFT, "No info"); + return; } + + snprintf( + buffer, sizeof(buffer), "%s [%s]", version_get_version(ver), version_get_builddate(ver)); + canvas_draw_str(canvas, 0, 30 + STATUS_BAR_Y_SHIFT, buffer); + + uint16_t api_major, api_minor; + furi_hal_info_get_api_version(&api_major, &api_minor); + snprintf( + buffer, + sizeof(buffer), + "%s%s [%d.%d] %s", + version_get_dirty_flag(ver) ? "[!] " : "", + version_get_githash(ver), + api_major, + api_minor, + c2_ver ? c2_ver->StackTypeString : ""); + canvas_draw_str(canvas, 0, 40 + STATUS_BAR_Y_SHIFT, buffer); + + snprintf( + buffer, sizeof(buffer), "[%d] %s", version_get_target(ver), version_get_gitbranch(ver)); + canvas_draw_str(canvas, 0, 50 + STATUS_BAR_Y_SHIFT, buffer); } View* desktop_debug_get_view(DesktopDebugView* debug_view) { @@ -115,61 +90,43 @@ View* desktop_debug_get_view(DesktopDebugView* debug_view) { return debug_view->view; } -bool desktop_debug_input(InputEvent* event, void* context) { +static bool desktop_debug_input(InputEvent* event, void* context) { furi_assert(event); furi_assert(context); DesktopDebugView* debug_view = context; - if(event->type != InputTypeShort && event->type != InputTypeRepeat) { - return false; - } - - DesktopViewStatsScreens current = 0; - with_view_model( - debug_view->view, - DesktopDebugViewModel * model, - { -#ifdef SRV_DOLPHIN_STATE_DEBUG - if((event->key == InputKeyDown) || (event->key == InputKeyUp)) { - model->screen = !model->screen; - } -#endif - current = model->screen; - }, - true); - - size_t count = (event->type == InputTypeRepeat) ? 10 : 1; - if(current == DesktopViewStatsMeta) { - if(event->key == InputKeyLeft) { - while(count-- > 0) { - debug_view->callback(DesktopDebugEventWrongDeed, debug_view->context); - } - } else if(event->key == InputKeyRight) { - while(count-- > 0) { - debug_view->callback(DesktopDebugEventDeed, debug_view->context); - } - } else if(event->key == InputKeyOk) { - debug_view->callback(DesktopDebugEventSaveState, debug_view->context); - } else { - return false; - } - } - - if(event->key == InputKeyBack) { + if(event->key == InputKeyBack && event->type == InputTypeShort) { debug_view->callback(DesktopDebugEventExit, debug_view->context); } return true; } +static void desktop_debug_enter(void* context) { + DesktopDebugView* debug_view = context; + furi_timer_start(debug_view->timer, furi_ms_to_ticks(1000)); +} + +static void desktop_debug_exit(void* context) { + DesktopDebugView* debug_view = context; + furi_timer_stop(debug_view->timer); +} +void desktop_debug_timer(void* context) { + DesktopDebugView* debug_view = context; + view_get_model(debug_view->view); + view_commit_model(debug_view->view, true); +} + DesktopDebugView* desktop_debug_alloc() { DesktopDebugView* debug_view = malloc(sizeof(DesktopDebugView)); debug_view->view = view_alloc(); - view_allocate_model(debug_view->view, ViewModelTypeLocking, sizeof(DesktopDebugViewModel)); + debug_view->timer = furi_timer_alloc(desktop_debug_timer, FuriTimerTypePeriodic, debug_view); view_set_context(debug_view->view, debug_view); view_set_draw_callback(debug_view->view, (ViewDrawCallback)desktop_debug_render); view_set_input_callback(debug_view->view, desktop_debug_input); + view_set_enter_callback(debug_view->view, desktop_debug_enter); + view_set_exit_callback(debug_view->view, desktop_debug_exit); return debug_view; } @@ -177,27 +134,7 @@ DesktopDebugView* desktop_debug_alloc() { void desktop_debug_free(DesktopDebugView* debug_view) { furi_assert(debug_view); + furi_timer_free(debug_view->timer); view_free(debug_view->view); free(debug_view); } - -void desktop_debug_get_dolphin_data(DesktopDebugView* debug_view) { - Dolphin* dolphin = furi_record_open(RECORD_DOLPHIN); - DolphinStats stats = dolphin_stats(dolphin); - with_view_model( - debug_view->view, - DesktopDebugViewModel * model, - { - model->icounter = stats.icounter; - model->butthurt = stats.butthurt; - model->timestamp = stats.timestamp; - }, - true); - - furi_record_close(RECORD_DOLPHIN); -} - -void desktop_debug_reset_screen_idx(DesktopDebugView* debug_view) { - with_view_model( - debug_view->view, DesktopDebugViewModel * model, { model->screen = 0; }, true); -} diff --git a/applications/services/desktop/views/desktop_view_debug.h b/applications/services/desktop/views/desktop_view_debug.h index f6af16b2e967..fea0c22a080f 100644 --- a/applications/services/desktop/views/desktop_view_debug.h +++ b/applications/services/desktop/views/desktop_view_debug.h @@ -8,26 +8,13 @@ typedef struct DesktopDebugView DesktopDebugView; typedef void (*DesktopDebugViewCallback)(DesktopEvent event, void* context); -// Debug info -typedef enum { - DesktopViewStatsFw, - DesktopViewStatsMeta, - DesktopViewStatsTotalCount, -} DesktopViewStatsScreens; - struct DesktopDebugView { View* view; + FuriTimer* timer; DesktopDebugViewCallback callback; void* context; }; -typedef struct { - uint32_t icounter; - uint32_t butthurt; - uint64_t timestamp; - DesktopViewStatsScreens screen; -} DesktopDebugViewModel; - void desktop_debug_set_callback( DesktopDebugView* debug_view, DesktopDebugViewCallback callback, @@ -36,7 +23,5 @@ void desktop_debug_set_callback( View* desktop_debug_get_view(DesktopDebugView* debug_view); DesktopDebugView* desktop_debug_alloc(); -void desktop_debug_free(DesktopDebugView* debug_view); -void desktop_debug_get_dolphin_data(DesktopDebugView* debug_view); -void desktop_debug_reset_screen_idx(DesktopDebugView* debug_view); +void desktop_debug_free(DesktopDebugView* debug_view); diff --git a/applications/services/gui/modules/file_browser.c b/applications/services/gui/modules/file_browser.c index c764a1cf7e35..91b03ec8aae6 100644 --- a/applications/services/gui/modules/file_browser.c +++ b/applications/services/gui/modules/file_browser.c @@ -303,6 +303,12 @@ static bool browser_is_list_load_required(FileBrowserModel* model) { return false; } +static void browser_list_rollover(FileBrowserModel* model) { + if(!model->list_loading && items_array_size(model->items) < model->item_cnt) { + items_array_reset(model->items); + } +} + static void browser_update_offset(FileBrowser* browser) { furi_assert(browser); @@ -385,7 +391,7 @@ static void browser_list_load_cb(void* context, uint32_t list_load_offset) { } } }, - true); + false); BrowserItem_t_clear(&back_item); } @@ -425,14 +431,15 @@ static void (browser->hide_ext) && (item.type == BrowserItemTypeFile)); } + // We shouldn't update screen on each item if custom callback is not set + // Otherwise it will cause screen flickering + bool instant_update = (browser->item_callback != NULL); with_view_model( browser->view, FileBrowserModel * model, - { - items_array_push_back(model->items, item); - // TODO: calculate if element is visible - }, - true); + { items_array_push_back(model->items, item); }, + instant_update); + furi_string_free(item.display_name); furi_string_free(item.path); if(item.custom_icon_data) { @@ -440,7 +447,18 @@ static void } } else { with_view_model( - browser->view, FileBrowserModel * model, { model->list_loading = false; }, true); + browser->view, + FileBrowserModel * model, + { + model->list_loading = false; + if(browser_is_list_load_required(model)) { + model->list_loading = true; + int32_t load_offset = CLAMP( + model->item_idx - ITEM_LIST_LEN_MAX / 2, (int32_t)model->item_cnt, 0); + file_browser_worker_load(browser->worker, load_offset, ITEM_LIST_LEN_MAX); + } + }, + true); } } @@ -604,11 +622,13 @@ static bool file_browser_view_input_callback(InputEvent* event, void* context) { if(model->item_idx < scroll_speed) { model->button_held_for_ticks = 0; model->item_idx = model->item_cnt - 1; + browser_list_rollover(model); } else { model->item_idx = ((model->item_idx - scroll_speed) + model->item_cnt) % model->item_cnt; } + if(browser_is_list_load_required(model)) { model->list_loading = true; int32_t load_offset = CLAMP( @@ -622,13 +642,14 @@ static bool file_browser_view_input_callback(InputEvent* event, void* context) { model->button_held_for_ticks += 1; } else if(event->key == InputKeyDown) { - int32_t count = model->item_cnt; - if(model->item_idx + scroll_speed >= count) { + if(model->item_idx + scroll_speed >= (int32_t)model->item_cnt) { model->button_held_for_ticks = 0; model->item_idx = 0; + browser_list_rollover(model); } else { model->item_idx = (model->item_idx + scroll_speed) % model->item_cnt; } + if(browser_is_list_load_required(model)) { model->list_loading = true; int32_t load_offset = CLAMP( diff --git a/applications/services/loader/loader.c b/applications/services/loader/loader.c index ab7876a03661..41c0f95d420b 100644 --- a/applications/services/loader/loader.c +++ b/applications/services/loader/loader.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -11,7 +12,20 @@ #define TAG "Loader" #define LOADER_MAGIC_THREAD_VALUE 0xDEADBEEF -// api + +// helpers + +static const char* loader_find_external_application_by_name(const char* app_name) { + for(size_t i = 0; i < FLIPPER_EXTERNAL_APPS_COUNT; i++) { + if(strcmp(FLIPPER_EXTERNAL_APPS[i].name, app_name) == 0) { + return FLIPPER_EXTERNAL_APPS[i].path; + } + } + + return NULL; +} + +// API LoaderStatus loader_start(Loader* loader, const char* name, const char* args, FuriString* error_message) { @@ -33,17 +47,33 @@ LoaderStatus loader_start_with_gui_error(Loader* loader, const char* name, const FuriString* error_message = furi_string_alloc(); LoaderStatus status = loader_start(loader, name, args, error_message); - // TODO: we have many places where we can emit a double start, ex: desktop, menu - // so i prefer to not show LoaderStatusErrorAppStarted error message for now - if(status == LoaderStatusErrorUnknownApp || status == LoaderStatusErrorInternal) { + if(status == LoaderStatusErrorUnknownApp && + loader_find_external_application_by_name(name) != NULL) { + // Special case for external apps + DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS); + DialogMessage* message = dialog_message_alloc(); + dialog_message_set_header(message, "Update needed", 64, 3, AlignCenter, AlignTop); + dialog_message_set_buttons(message, NULL, NULL, NULL); + dialog_message_set_icon(message, &I_DolphinCommon_56x48, 72, 17); + dialog_message_set_text( + message, "Update firmware\nto run this app", 3, 26, AlignLeft, AlignTop); + dialog_message_show(dialogs, message); + dialog_message_free(message); + furi_record_close(RECORD_DIALOGS); + } else if(status == LoaderStatusErrorUnknownApp || status == LoaderStatusErrorInternal) { + // TODO: we have many places where we can emit a double start, ex: desktop, menu + // so i prefer to not show LoaderStatusErrorAppStarted error message for now DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS); DialogMessage* message = dialog_message_alloc(); dialog_message_set_header(message, "Error", 64, 0, AlignCenter, AlignTop); dialog_message_set_buttons(message, NULL, NULL, NULL); - furi_string_replace(error_message, ":", "\n"); + furi_string_replace(error_message, "/ext/apps/", ""); + furi_string_replace(error_message, ", ", "\n"); + furi_string_replace(error_message, ": ", "\n"); + dialog_message_set_text( - message, furi_string_get_cstr(error_message), 64, 32, AlignCenter, AlignCenter); + message, furi_string_get_cstr(error_message), 64, 35, AlignCenter, AlignCenter); dialog_message_show(dialogs, message); dialog_message_free(message); @@ -268,22 +298,20 @@ static LoaderStatus loader_start_external_app( if(preload_res != FlipperApplicationPreloadStatusSuccess) { const char* err_msg = flipper_application_preload_status_to_string(preload_res); status = loader_make_status_error( - LoaderStatusErrorInternal, error_message, "Preload failed %s: %s", path, err_msg); + LoaderStatusErrorInternal, error_message, "Preload failed, %s: %s", path, err_msg); break; } - FURI_LOG_I(TAG, "Mapping"); FlipperApplicationLoadStatus load_status = flipper_application_map_to_memory(loader->app.fap); if(load_status != FlipperApplicationLoadStatusSuccess) { const char* err_msg = flipper_application_load_status_to_string(load_status); status = loader_make_status_error( - LoaderStatusErrorInternal, error_message, "Load failed %s: %s", path, err_msg); + LoaderStatusErrorInternal, error_message, "Load failed, %s: %s", path, err_msg); break; } FURI_LOG_I(TAG, "Loaded in %zums", (size_t)(furi_get_tick() - start)); - FURI_LOG_I(TAG, "Starting app"); loader->app.thread = flipper_application_alloc_thread(loader->app.fap, args); FuriString* app_name = furi_string_alloc(); @@ -379,7 +407,15 @@ static LoaderStatus loader_do_start_by_name( break; } - // check external apps + // check External Applications + { + const char* path = loader_find_external_application_by_name(name); + if(path) { + name = path; + } + } + + // check Faps { Storage* storage = furi_record_open(RECORD_STORAGE); if(storage_file_exists(storage, name)) { diff --git a/applications/services/loader/loader_applications.c b/applications/services/loader/loader_applications.c index 1801edef9f95..8ae91d76408a 100644 --- a/applications/services/loader/loader_applications.c +++ b/applications/services/loader/loader_applications.c @@ -20,7 +20,7 @@ static int32_t loader_applications_thread(void* p); LoaderApplications* loader_applications_alloc(void (*closed_cb)(void*), void* context) { LoaderApplications* loader_applications = malloc(sizeof(LoaderApplications)); loader_applications->thread = - furi_thread_alloc_ex(TAG, 512, loader_applications_thread, (void*)loader_applications); + furi_thread_alloc_ex(TAG, 768, loader_applications_thread, (void*)loader_applications); loader_applications->closed_cb = closed_cb; loader_applications->context = context; furi_thread_start(loader_applications->thread); @@ -38,6 +38,11 @@ typedef struct { FuriString* fap_path; DialogsApp* dialogs; Storage* storage; + Loader* loader; + + Gui* gui; + ViewHolder* view_holder; + Loading* loading; } LoaderApplicationsApp; static LoaderApplicationsApp* loader_applications_app_alloc() { @@ -45,15 +50,30 @@ static LoaderApplicationsApp* loader_applications_app_alloc() { app->fap_path = furi_string_alloc_set(EXT_PATH("apps")); app->dialogs = furi_record_open(RECORD_DIALOGS); app->storage = furi_record_open(RECORD_STORAGE); + app->loader = furi_record_open(RECORD_LOADER); + + app->gui = furi_record_open(RECORD_GUI); + app->view_holder = view_holder_alloc(); + app->loading = loading_alloc(); + + view_holder_attach_to_gui(app->view_holder, app->gui); + view_holder_set_view(app->view_holder, loading_get_view(app->loading)); + return app; } //-V773 -static void loader_applications_app_free(LoaderApplicationsApp* loader_applications_app) { - furi_assert(loader_applications_app); +static void loader_applications_app_free(LoaderApplicationsApp* app) { + furi_assert(app); + + view_holder_free(app->view_holder); + loading_free(app->loading); + furi_record_close(RECORD_GUI); + + furi_record_close(RECORD_LOADER); furi_record_close(RECORD_DIALOGS); furi_record_close(RECORD_STORAGE); - furi_string_free(loader_applications_app->fap_path); - free(loader_applications_app); + furi_string_free(app->fap_path); + free(app); } static bool loader_applications_item_callback( @@ -96,47 +116,38 @@ static void loader_pubsub_callback(const void* message, void* context) { } } -static void loader_applications_start_app(const char* name) { - // start loading animation - Gui* gui = furi_record_open(RECORD_GUI); - ViewHolder* view_holder = view_holder_alloc(); - Loading* loading = loading_alloc(); - - view_holder_attach_to_gui(view_holder, gui); - view_holder_set_view(view_holder, loading_get_view(loading)); - view_holder_start(view_holder); +static void loader_applications_start_app(LoaderApplicationsApp* app) { + const char* name = furi_string_get_cstr(app->fap_path); // load app FuriThreadId thread_id = furi_thread_get_current_id(); - Loader* loader = furi_record_open(RECORD_LOADER); FuriPubSubSubscription* subscription = - furi_pubsub_subscribe(loader_get_pubsub(loader), loader_pubsub_callback, thread_id); + furi_pubsub_subscribe(loader_get_pubsub(app->loader), loader_pubsub_callback, thread_id); - LoaderStatus status = loader_start_with_gui_error(loader, name, NULL); + LoaderStatus status = loader_start_with_gui_error(app->loader, name, NULL); if(status == LoaderStatusOk) { furi_thread_flags_wait(APPLICATION_STOP_EVENT, FuriFlagWaitAny, FuriWaitForever); } - furi_pubsub_unsubscribe(loader_get_pubsub(loader), subscription); - furi_record_close(RECORD_LOADER); - - // stop loading animation - view_holder_stop(view_holder); - view_holder_free(view_holder); - loading_free(loading); - furi_record_close(RECORD_GUI); + furi_pubsub_unsubscribe(loader_get_pubsub(app->loader), subscription); } static int32_t loader_applications_thread(void* p) { LoaderApplications* loader_applications = p; - LoaderApplicationsApp* loader_applications_app = loader_applications_app_alloc(); + LoaderApplicationsApp* app = loader_applications_app_alloc(); - while(loader_applications_select_app(loader_applications_app)) { - loader_applications_start_app(furi_string_get_cstr(loader_applications_app->fap_path)); + // start loading animation + view_holder_start(app->view_holder); + + while(loader_applications_select_app(app)) { + loader_applications_start_app(app); } - loader_applications_app_free(loader_applications_app); + // stop loading animation + view_holder_stop(app->view_holder); + + loader_applications_app_free(app); if(loader_applications->closed_cb) { loader_applications->closed_cb(loader_applications->context); diff --git a/applications/services/loader/loader_menu.c b/applications/services/loader/loader_menu.c index 28283f85cd20..149fea72c19a 100644 --- a/applications/services/loader/loader_menu.c +++ b/applications/services/loader/loader_menu.c @@ -52,12 +52,18 @@ static void loader_menu_start(const char* name) { furi_record_close(RECORD_LOADER); } -static void loader_menu_callback(void* context, uint32_t index) { +static void loader_menu_apps_callback(void* context, uint32_t index) { UNUSED(context); const char* name = FLIPPER_APPS[index].name; loader_menu_start(name); } +static void loader_menu_external_apps_callback(void* context, uint32_t index) { + UNUSED(context); + const char* path = FLIPPER_EXTERNAL_APPS[index].name; + loader_menu_start(path); +} + static void loader_menu_applications_callback(void* context, uint32_t index) { UNUSED(index); UNUSED(context); @@ -89,13 +95,24 @@ static uint32_t loader_menu_exit(void* context) { static void loader_menu_build_menu(LoaderMenuApp* app, LoaderMenu* menu) { size_t i; + + for(i = 0; i < FLIPPER_EXTERNAL_APPS_COUNT; i++) { + menu_add_item( + app->primary_menu, + FLIPPER_EXTERNAL_APPS[i].name, + FLIPPER_EXTERNAL_APPS[i].icon, + i, + loader_menu_external_apps_callback, + (void*)menu); + } + for(i = 0; i < FLIPPER_APPS_COUNT; i++) { menu_add_item( app->primary_menu, FLIPPER_APPS[i].name, FLIPPER_APPS[i].icon, i, - loader_menu_callback, + loader_menu_apps_callback, (void*)menu); } menu_add_item( diff --git a/applications/services/power/power_service/power.c b/applications/services/power/power_service/power.c index 72dc8f3f1e75..aadb5f46e406 100644 --- a/applications/services/power/power_service/power.c +++ b/applications/services/power/power_service/power.c @@ -117,6 +117,7 @@ static bool power_update_info(Power* power) { info.is_charging = furi_hal_power_is_charging(); info.gauge_is_ok = furi_hal_power_gauge_is_ok(); + info.is_shutdown_requested = furi_hal_power_is_shutdown_requested(); info.charge = furi_hal_power_get_pct(); info.health = furi_hal_power_get_bat_health_pct(); info.capacity_remaining = furi_hal_power_get_battery_remaining_capacity(); @@ -145,7 +146,7 @@ static void power_check_low_battery(Power* power) { } // Check battery charge and vbus voltage - if((power->info.charge == 0) && (power->info.voltage_vbus < 4.0f) && + if((power->info.is_shutdown_requested) && (power->info.voltage_vbus < 4.0f) && power->show_low_bat_level_message) { if(!power->battery_low) { view_dispatcher_send_to_front(power->view_dispatcher); diff --git a/applications/services/power/power_service/power.h b/applications/services/power/power_service/power.h index c7f5d7e35012..fdc5b527a609 100644 --- a/applications/services/power/power_service/power.h +++ b/applications/services/power/power_service/power.h @@ -37,6 +37,7 @@ typedef struct { typedef struct { bool gauge_is_ok; bool is_charging; + bool is_shutdown_requested; float current_charger; float current_gauge; diff --git a/applications/services/storage/storage_external_api.c b/applications/services/storage/storage_external_api.c index 5fcaa59216be..585ded41444a 100644 --- a/applications/services/storage/storage_external_api.c +++ b/applications/services/storage/storage_external_api.c @@ -430,6 +430,20 @@ FS_Error storage_common_rename(Storage* storage, const char* old_path, const cha break; } + if(storage_dir_exists(storage, old_path)) { + FuriString* dir_path = furi_string_alloc_set_str(old_path); + if(!furi_string_end_with_str(dir_path, "/")) { + furi_string_cat_str(dir_path, "/"); + } + const char* dir_path_s = furi_string_get_cstr(dir_path); + if(strncmp(new_path, dir_path_s, strlen(dir_path_s)) == 0) { + error = FSE_INVALID_NAME; + furi_string_free(dir_path); + break; + } + furi_string_free(dir_path); + } + if(storage_file_exists(storage, new_path)) { storage_common_remove(storage, new_path); } diff --git a/applications/settings/about/about.c b/applications/settings/about/about.c index 688103306887..55bd43e5c589 100644 --- a/applications/settings/about/about.c +++ b/applications/settings/about/about.c @@ -82,7 +82,9 @@ static DialogMessageButton icon1_screen(DialogsApp* dialogs, DialogMessage* mess static DialogMessageButton icon2_screen(DialogsApp* dialogs, DialogMessage* message) { DialogMessageButton result; - dialog_message_set_icon(message, &I_Certification2_98x33, 15, 10); + dialog_message_set_icon(message, &I_Certification2_46x33, 15, 10); + dialog_message_set_text( + message, furi_hal_version_get_mic_id(), 63, 27, AlignLeft, AlignCenter); result = dialog_message_show(dialogs, message); dialog_message_set_icon(message, NULL, 0, 0); diff --git a/applications/settings/desktop_settings/scenes/desktop_settings_scene_favorite.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_favorite.c index 698cfae1b814..26e7bc5875b2 100644 --- a/applications/settings/desktop_settings/scenes/desktop_settings_scene_favorite.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_favorite.c @@ -1,11 +1,30 @@ #include "../desktop_settings_app.h" #include "applications.h" #include "desktop_settings_scene.h" +#include #include #include +#define APPS_COUNT (FLIPPER_APPS_COUNT + FLIPPER_EXTERNAL_APPS_COUNT) + +#define EXTERNAL_BROWSER_NAME ("Applications") +#define EXTERNAL_BROWSER_INDEX (APPS_COUNT + 1) + #define EXTERNAL_APPLICATION_NAME ("[External Application]") -#define EXTERNAL_APPLICATION_INDEX (FLIPPER_APPS_COUNT + 1) +#define EXTERNAL_APPLICATION_INDEX (APPS_COUNT + 2) + +#define PRESELECTED_SPECIAL 0xffffffff + +static const char* favorite_fap_get_app_name(size_t i) { + const char* name; + if(i < FLIPPER_APPS_COUNT) { + name = FLIPPER_APPS[i].name; + } else { + name = FLIPPER_EXTERNAL_APPS[i - FLIPPER_APPS_COUNT].name; + } + + return name; +} static bool favorite_fap_selector_item_callback( FuriString* file_path, @@ -13,16 +32,9 @@ static bool favorite_fap_selector_item_callback( uint8_t** icon_ptr, FuriString* item_name) { UNUSED(context); -#ifdef APP_FAP_LOADER Storage* storage = furi_record_open(RECORD_STORAGE); - bool success = fap_loader_load_name_and_icon(file_path, storage, icon_ptr, item_name); + bool success = flipper_application_load_name_and_icon(file_path, storage, icon_ptr, item_name); furi_record_close(RECORD_STORAGE); -#else - UNUSED(file_path); - UNUSED(icon_ptr); - UNUSED(item_name); - bool success = false; -#endif return success; } @@ -45,33 +57,43 @@ void desktop_settings_scene_favorite_on_enter(void* context) { uint32_t primary_favorite = scene_manager_get_scene_state(app->scene_manager, DesktopSettingsAppSceneFavorite); - uint32_t pre_select_item = 0; + uint32_t pre_select_item = PRESELECTED_SPECIAL; FavoriteApp* curr_favorite_app = primary_favorite ? &app->settings.favorite_primary : &app->settings.favorite_secondary; - for(size_t i = 0; i < FLIPPER_APPS_COUNT; i++) { - submenu_add_item( - submenu, - FLIPPER_APPS[i].name, - i, - desktop_settings_scene_favorite_submenu_callback, - app); + for(size_t i = 0; i < APPS_COUNT; i++) { + const char* name = favorite_fap_get_app_name(i); + + submenu_add_item(submenu, name, i, desktop_settings_scene_favorite_submenu_callback, app); // Select favorite item in submenu - if(!curr_favorite_app->is_external && - !strcmp(FLIPPER_APPS[i].name, curr_favorite_app->name_or_path)) { + if(!strcmp(name, curr_favorite_app->name_or_path)) { pre_select_item = i; } } + // Special case: Application browser + submenu_add_item( + submenu, + EXTERNAL_BROWSER_NAME, + EXTERNAL_BROWSER_INDEX, + desktop_settings_scene_favorite_submenu_callback, + app); + + // Special case: Specific application submenu_add_item( submenu, EXTERNAL_APPLICATION_NAME, EXTERNAL_APPLICATION_INDEX, desktop_settings_scene_favorite_submenu_callback, app); - if(curr_favorite_app->is_external) { - pre_select_item = EXTERNAL_APPLICATION_INDEX; + + if(pre_select_item == PRESELECTED_SPECIAL) { + if(curr_favorite_app->name_or_path[0] == '\0') { + pre_select_item = EXTERNAL_BROWSER_INDEX; + } else { + pre_select_item = EXTERNAL_APPLICATION_INDEX; + } } submenu_set_header( @@ -92,7 +114,10 @@ bool desktop_settings_scene_favorite_on_event(void* context, SceneManagerEvent e &app->settings.favorite_secondary; if(event.type == SceneManagerEventTypeCustom) { - if(event.event == EXTERNAL_APPLICATION_INDEX) { + if(event.event == EXTERNAL_BROWSER_INDEX) { + curr_favorite_app->name_or_path[0] = '\0'; + consumed = true; + } else if(event.event == EXTERNAL_APPLICATION_INDEX) { const DialogsFileBrowserOptions browser_options = { .extension = ".fap", .icon = &I_unknown_10px, @@ -110,7 +135,6 @@ bool desktop_settings_scene_favorite_on_event(void* context, SceneManagerEvent e if(dialog_file_browser_show(app->dialogs, temp_path, temp_path, &browser_options)) { submenu_reset(app->submenu); // Prevent menu from being shown when we exiting scene - curr_favorite_app->is_external = true; strncpy( curr_favorite_app->name_or_path, furi_string_get_cstr(temp_path), @@ -118,9 +142,8 @@ bool desktop_settings_scene_favorite_on_event(void* context, SceneManagerEvent e consumed = true; } } else { - curr_favorite_app->is_external = false; - strncpy( - curr_favorite_app->name_or_path, FLIPPER_APPS[event.event].name, MAX_APP_LENGTH); + const char* name = favorite_fap_get_app_name(event.event); + if(name) strncpy(curr_favorite_app->name_or_path, name, MAX_APP_LENGTH); consumed = true; } if(consumed) { diff --git a/applications/settings/power_settings_app/views/battery_info.c b/applications/settings/power_settings_app/views/battery_info.c index d56dfc628598..8add60db5ab9 100644 --- a/applications/settings/power_settings_app/views/battery_info.c +++ b/applications/settings/power_settings_app/views/battery_info.c @@ -54,8 +54,7 @@ static void draw_battery(Canvas* canvas, BatteryInfoModel* data, int x, int y) { (uint32_t)(data->vbus_voltage * 10) % 10, current); } else if(current < -5) { - // Often gauge reports anything in the range 1~5ma as 5ma - // That brings confusion, so we'll treat it as Napping + // 0-5ma deadband snprintf( emote, sizeof(emote), diff --git a/applications/system/updater/util/update_task.c b/applications/system/updater/util/update_task.c index 708d10ce0400..74d752b434b6 100644 --- a/applications/system/updater/util/update_task.c +++ b/applications/system/updater/util/update_task.c @@ -19,7 +19,7 @@ static const char* update_task_stage_descr[] = { [UpdateTaskStageRadioErase] = "Uninstalling radio FW", [UpdateTaskStageRadioWrite] = "Writing radio FW", [UpdateTaskStageRadioInstall] = "Installing radio FW", - [UpdateTaskStageRadioBusy] = "Radio is updating", + [UpdateTaskStageRadioBusy] = "Core 2 busy", [UpdateTaskStageOBValidation] = "Validating opt. bytes", [UpdateTaskStageLfsBackup] = "Backing up LFS", [UpdateTaskStageLfsRestore] = "Restoring LFS", @@ -30,6 +30,191 @@ static const char* update_task_stage_descr[] = { [UpdateTaskStageOBError] = "OB, report", }; +static const struct { + UpdateTaskStage stage; + uint8_t percent_min, percent_max; + const char* descr; +} update_task_error_detail[] = { + { + .stage = UpdateTaskStageReadManifest, + .percent_min = 0, + .percent_max = 13, + .descr = "Wrong Updater HW", + }, + { + .stage = UpdateTaskStageReadManifest, + .percent_min = 14, + .percent_max = 20, + .descr = "Manifest pointer error", + }, + { + .stage = UpdateTaskStageReadManifest, + .percent_min = 21, + .percent_max = 30, + .descr = "Manifest load error", + }, + { + .stage = UpdateTaskStageReadManifest, + .percent_min = 31, + .percent_max = 40, + .descr = "Wrong package version", + }, + { + .stage = UpdateTaskStageReadManifest, + .percent_min = 41, + .percent_max = 50, + .descr = "HW Target mismatch", + }, + { + .stage = UpdateTaskStageReadManifest, + .percent_min = 51, + .percent_max = 60, + .descr = "No DFU file", + }, + { + .stage = UpdateTaskStageReadManifest, + .percent_min = 61, + .percent_max = 80, + .descr = "No Radio file", + }, +#ifndef FURI_RAM_EXEC + { + .stage = UpdateTaskStageLfsBackup, + .percent_min = 0, + .percent_max = 100, + .descr = "FS R/W error", + }, +#else + { + .stage = UpdateTaskStageRadioImageValidate, + .percent_min = 0, + .percent_max = 98, + .descr = "FS Read error", + }, + { + .stage = UpdateTaskStageRadioImageValidate, + .percent_min = 99, + .percent_max = 100, + .descr = "CRC mismatch", + }, + { + .stage = UpdateTaskStageRadioErase, + .percent_min = 0, + .percent_max = 30, + .descr = "Stack remove: cmd error", + }, + { + .stage = UpdateTaskStageRadioErase, + .percent_min = 31, + .percent_max = 100, + .descr = "Stack remove: wait failed", + }, + { + .stage = UpdateTaskStageRadioWrite, + .percent_min = 0, + .percent_max = 100, + .descr = "Stack write: error", + }, + { + .stage = UpdateTaskStageRadioInstall, + .percent_min = 0, + .percent_max = 10, + .descr = "Stack install: cmd error", + }, + { + .stage = UpdateTaskStageRadioInstall, + .percent_min = 11, + .percent_max = 100, + .descr = "Stack install: wait failed", + }, + { + .stage = UpdateTaskStageRadioBusy, + .percent_min = 0, + .percent_max = 10, + .descr = "Failed to start C2", + }, + { + .stage = UpdateTaskStageRadioBusy, + .percent_min = 11, + .percent_max = 20, + .descr = "C2 FUS swich failed", + }, + { + .stage = UpdateTaskStageRadioBusy, + .percent_min = 21, + .percent_max = 30, + .descr = "FUS operation failed", + }, + { + .stage = UpdateTaskStageRadioBusy, + .percent_min = 31, + .percent_max = 100, + .descr = "C2 Stach switch failed", + }, + { + .stage = UpdateTaskStageOBValidation, + .percent_min = 0, + .percent_max = 100, + .descr = "Uncorr. value mismatch", + }, + { + .stage = UpdateTaskStageValidateDFUImage, + .percent_min = 0, + .percent_max = 1, + .descr = "Failed to open DFU file", + }, + { + .stage = UpdateTaskStageValidateDFUImage, + .percent_min = 1, + .percent_max = 97, + .descr = "DFU file read error", + }, + { + .stage = UpdateTaskStageValidateDFUImage, + .percent_min = 98, + .percent_max = 100, + .descr = "DFU file CRC mismatch", + }, + { + .stage = UpdateTaskStageFlashWrite, + .percent_min = 0, + .percent_max = 100, + .descr = "Flash write error", + }, + { + .stage = UpdateTaskStageFlashValidate, + .percent_min = 0, + .percent_max = 100, + .descr = "Flash compare error", + }, +#endif +#ifndef FURI_RAM_EXEC + { + .stage = UpdateTaskStageLfsRestore, + .percent_min = 0, + .percent_max = 100, + .descr = "LFS I/O error", + }, + { + .stage = UpdateTaskStageResourcesUpdate, + .percent_min = 0, + .percent_max = 100, + .descr = "SD card I/O error", + }, +#endif +}; + +static const char* update_task_get_error_message(UpdateTaskStage stage, uint8_t percent) { + for(size_t i = 0; i < COUNT_OF(update_task_error_detail); i++) { + if(update_task_error_detail[i].stage == stage && + percent >= update_task_error_detail[i].percent_min && + percent <= update_task_error_detail[i].percent_max) { + return update_task_error_detail[i].descr; + } + } + return "Unknown error"; +} + typedef struct { UpdateTaskStageGroup group; uint8_t weight; @@ -111,8 +296,9 @@ void update_task_set_progress(UpdateTask* update_task, UpdateTaskStage stage, ui if(stage >= UpdateTaskStageError) { furi_string_printf( update_task->state.status, - "%s #[%d-%d]", - update_task_stage_descr[stage], + "%s\n#[%d-%d]", + update_task_get_error_message( + update_task->state.stage, update_task->state.stage_progress), update_task->state.stage, update_task->state.stage_progress); } else { diff --git a/applications/system/updater/util/update_task_i.h b/applications/system/updater/util/update_task_i.h index 0dbeca5f491c..1b664e57e4c8 100644 --- a/applications/system/updater/util/update_task_i.h +++ b/applications/system/updater/util/update_task_i.h @@ -24,3 +24,8 @@ bool update_task_open_file(UpdateTask* update_task, FuriString* filename); int32_t update_task_worker_flash_writer(void* context); int32_t update_task_worker_backup_restore(void* context); + +#define CHECK_RESULT(x) \ + if(!(x)) { \ + break; \ + } diff --git a/applications/system/updater/util/update_task_worker_backup.c b/applications/system/updater/util/update_task_worker_backup.c index f2c33c2edb45..ef4276fac5ec 100644 --- a/applications/system/updater/util/update_task_worker_backup.c +++ b/applications/system/updater/util/update_task_worker_backup.c @@ -15,11 +15,6 @@ #define TAG "UpdWorkerBackup" -#define CHECK_RESULT(x) \ - if(!(x)) { \ - break; \ - } - static bool update_task_pre_update(UpdateTask* update_task) { bool success = false; FuriString* backup_file_path; diff --git a/applications/system/updater/util/update_task_worker_flasher.c b/applications/system/updater/util/update_task_worker_flasher.c index 5d247746464f..d6dc13e378db 100644 --- a/applications/system/updater/util/update_task_worker_flasher.c +++ b/applications/system/updater/util/update_task_worker_flasher.c @@ -13,11 +13,6 @@ #define TAG "UpdWorkerRAM" -#define CHECK_RESULT(x) \ - if(!(x)) { \ - break; \ - } - #define STM_DFU_VENDOR_ID 0x0483 #define STM_DFU_PRODUCT_ID 0xDF11 /* Written into DFU file by build pipeline */ @@ -137,7 +132,7 @@ static bool update_task_write_stack_data(UpdateTask* update_task) { } static void update_task_wait_for_restart(UpdateTask* update_task) { - update_task_set_progress(update_task, UpdateTaskStageRadioBusy, 10); + update_task_set_progress(update_task, UpdateTaskStageRadioBusy, 70); furi_delay_ms(C2_MODE_SWITCH_TIMEOUT); furi_crash("C2 timeout"); } @@ -153,12 +148,12 @@ static bool update_task_write_stack(UpdateTask* update_task) { manifest->radio_crc); CHECK_RESULT(update_task_write_stack_data(update_task)); - update_task_set_progress(update_task, UpdateTaskStageRadioInstall, 0); + update_task_set_progress(update_task, UpdateTaskStageRadioInstall, 10); CHECK_RESULT( ble_glue_fus_stack_install(manifest->radio_address, 0) != BleGlueCommandResultError); - update_task_set_progress(update_task, UpdateTaskStageRadioInstall, 80); + update_task_set_progress(update_task, UpdateTaskStageProgress, 80); CHECK_RESULT(ble_glue_fus_wait_operation() == BleGlueCommandResultOK); - update_task_set_progress(update_task, UpdateTaskStageRadioInstall, 100); + update_task_set_progress(update_task, UpdateTaskStageProgress, 100); /* ...system will restart here. */ update_task_wait_for_restart(update_task); } while(false); @@ -170,9 +165,9 @@ static bool update_task_remove_stack(UpdateTask* update_task) { FURI_LOG_W(TAG, "Removing stack"); update_task_set_progress(update_task, UpdateTaskStageRadioErase, 30); CHECK_RESULT(ble_glue_fus_stack_delete() != BleGlueCommandResultError); - update_task_set_progress(update_task, UpdateTaskStageRadioErase, 80); + update_task_set_progress(update_task, UpdateTaskStageProgress, 80); CHECK_RESULT(ble_glue_fus_wait_operation() == BleGlueCommandResultOK); - update_task_set_progress(update_task, UpdateTaskStageRadioErase, 100); + update_task_set_progress(update_task, UpdateTaskStageProgress, 100); /* ...system will restart here. */ update_task_wait_for_restart(update_task); } while(false); @@ -180,6 +175,7 @@ static bool update_task_remove_stack(UpdateTask* update_task) { } static bool update_task_manage_radiostack(UpdateTask* update_task) { + update_task_set_progress(update_task, UpdateTaskStageRadioBusy, 10); bool success = false; do { CHECK_RESULT(ble_glue_wait_for_c2_start(FURI_HAL_BT_C2_START_TIMEOUT)); @@ -208,15 +204,17 @@ static bool update_task_manage_radiostack(UpdateTask* update_task) { /* Version or type mismatch. Let's boot to FUS and start updating. */ FURI_LOG_W(TAG, "Restarting to FUS"); furi_hal_rtc_set_flag(FuriHalRtcFlagC2Update); + update_task_set_progress(update_task, UpdateTaskStageProgress, 20); + CHECK_RESULT(furi_hal_bt_ensure_c2_mode(BleGlueC2ModeFUS)); /* ...system will restart here. */ update_task_wait_for_restart(update_task); } } else if(c2_state->mode == BleGlueC2ModeFUS) { /* OK, we're in FUS mode. */ - update_task_set_progress(update_task, UpdateTaskStageRadioBusy, 10); FURI_LOG_W(TAG, "Waiting for FUS to settle"); - ble_glue_fus_wait_operation(); + update_task_set_progress(update_task, UpdateTaskStageProgress, 30); + CHECK_RESULT(ble_glue_fus_wait_operation() == BleGlueCommandResultOK); if(stack_version_match) { /* We can't check StackType with FUS, but partial version matches */ if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagC2Update)) { @@ -230,7 +228,7 @@ static bool update_task_manage_radiostack(UpdateTask* update_task) { /* We might just had the stack installed. * Let's start it up to check its version */ FURI_LOG_W(TAG, "Starting stack to check full version"); - update_task_set_progress(update_task, UpdateTaskStageRadioBusy, 40); + update_task_set_progress(update_task, UpdateTaskStageProgress, 50); CHECK_RESULT(furi_hal_bt_ensure_c2_mode(BleGlueC2ModeStack)); /* ...system will restart here. */ update_task_wait_for_restart(update_task); diff --git a/applications/system/updater/views/updater_main.c b/applications/system/updater/views/updater_main.c index 1199cc882aa7..d32d51b7c0bf 100644 --- a/applications/system/updater/views/updater_main.c +++ b/applications/system/updater/views/updater_main.c @@ -81,16 +81,17 @@ static void updater_main_draw_callback(Canvas* canvas, void* _model) { canvas_set_font(canvas, FontPrimary); if(model->failed) { - canvas_draw_str_aligned(canvas, 42, 16, AlignLeft, AlignTop, "Update Failed!"); + canvas_draw_icon(canvas, 2, 22, &I_Warning_30x23); + canvas_draw_str_aligned(canvas, 40, 9, AlignLeft, AlignTop, "Update Failed!"); canvas_set_font(canvas, FontSecondary); - canvas_draw_str_aligned( - canvas, 42, 32, AlignLeft, AlignTop, furi_string_get_cstr(model->status)); - canvas_draw_icon(canvas, 7, 16, &I_Warning_30x23); + elements_multiline_text_aligned( + canvas, 75, 26, AlignCenter, AlignTop, furi_string_get_cstr(model->status)); + canvas_draw_str_aligned( - canvas, 18, 51, AlignLeft, AlignTop, "to retry, hold to abort"); - canvas_draw_icon(canvas, 7, 50, &I_Ok_btn_9x9); - canvas_draw_icon(canvas, 75, 51, &I_Pin_back_arrow_10x8); + canvas, 18, 55, AlignLeft, AlignTop, "to retry, hold to abort"); + canvas_draw_icon(canvas, 7, 54, &I_Ok_btn_9x9); + canvas_draw_icon(canvas, 75, 55, &I_Pin_back_arrow_10x8); } else { canvas_draw_str_aligned(canvas, 55, 14, AlignLeft, AlignTop, "UPDATING"); canvas_set_font(canvas, FontSecondary); diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_0.png b/assets/dolphin/external/L1_My_dude_128x64/frame_0.png new file mode 100644 index 0000000000000000000000000000000000000000..bf07d03d6e633a1cd9725d181b4970b96d216058 GIT binary patch literal 1615 zcmV-V2C(^wP)#6FpTXP`+4iIOK z)>;Dr$8i7v0N3O=j_bbG?#13XBm=+-*6u}~zt|5405pJ4?;TNOX9GIsi#>6+)}XZp z$8lUAO6}6MgHt*kllFPB2izf`g5ISu-W=jSoB+H>cMq0+XRdgRe!q`RpS@UvF9wJv zdYQz~TU}Iu8r91(pE&y$&P%y#lo`0^-Q(%pbp9-8K7&7RKJtkJ0JNh3xud}Zqd9~} zNh1vMzm}|YU(al8x0rzYO@-i;Og$F>K0Fxz#@o+e&+S?LGWu zfEC$)q;0i4BXVk0OJ+U_@7g1>a^rG1vGQkU|I)Pr+I$@z50Mm_T zS>59TVF1aqq^l)hmMJp*M#6{%%~&M)F`^aF=-M>>;O}1yAbGmC9bUYb2|OF%ffTnr zIfx|}Cl42U@%*@I8DTpwQ)$5cKMVr|2FPB$i_l_~*8pa+fED+>>+$Z7GG)m6z+&LDz%tbM3qaP1oS<=XuUuQw)F?Mi=SnmtBa4 zY}V`nC%fhGnK?AC&oGFGmBS1G@LfCOiD=xT&ow1uR)~J2@u*j2u5>KTAh?`BQ-Igg z>HbCX7p=_)1JK3Jy3$3>09BH-$y_X#+I2+o6Um#oaiV*fnVYsdxrQ^9PZ>h`M8Nfz z)`Jzm-KW1TkC(30*r_a>M|1fDy=rTrYtR_*dJX{wpbM*D0?9%nMj&}u77|m2{wALEu{hGj0CDRSz7OLHgw6~Z= zL&meL@jQDHf##6h-2FT5i?2U)U>ZBP#d_jj#R9o!k@jBD{+j%j0ekv!b9=|dvT{n6 z=91Xq2S2nX)F!C3c5j@M+D8zXry7|(lh{r&25YWU+kpN%LUmP}*qZOH7TyF;d)$xq z&B$0u?<0`%3H+Or^`tkncwVXCDo{DSvAJqq$p|btW;hKeAH7HCI<*e{zJ}}q?lLBB zQ+Dy`>A|)%ephnGSGv_xw!Vc3M-W#Nt{>L{8C#CR~aasBYUxm zF|t)jHJ-#cKhlGW5-D;*HaZ`77QQm>dcw|*h9MdN2W?}uTw?aZIpyzi%E*0R1<#!7 z+d!(o+0>sg7)kkeWZhV9u3V*UD;*>|mWu(T_&;Nly$iA4d~xH=ymGR6o5A_f>8 zcWLqpP6Ggt{}PBkvy7p)si-h2&K5>052=4viQ5_g_2RFA3`5Yy&7k7&3Af8&#=+Ls z25@yUXqUEE1xS`{R=>z5R+nfa3S4afp>u!^jSaF1P{a_lP;%!v0G|ITNErZtocVg6 zONfRIDI>oFcPc;29HAtzPs9%7$i{yIW-B?P$dR(s%>Y*RZY7CNf^~uy?Xxq&As`a} zcQk|+0+B>;7Z2GfAUvWZeCy!IK28Fa(JaJg2Q*Hc5p5X~K_zCmsWPFnSs{Yiw&? z`qGU1F3H24iCD6h8NhDHyr8*D@tho9P2CX$X zj^p=7Q@eES;EYaX(mpTtfV%`#q<2Zi%OUQ=2Y`?09>LQ0%oWS%_q%NR?8O>fGC-8* zWr(47cToZARBx6!xr$Z`m3AWaTu z%*Z(ZqZ82J`ebXn#SysgR0)ZDNX7>^^9XGRBgyCF{B_Xv!GGxt5E)!EDA!KA7j5g+ zk8_4q8DfN|Sm!R*x}-CJ_sT7<)XuB86}?*I)9;v@T%u#b`2{^2VWZNRo77jzsFEB2 z!~s^Y|47^H?jjnso<1YQF%#X9%%_d#8S8_MKT`9p_R@6*8Phlh{VweiFgUJZWd_;? zbDIo20fEPH2Op3OAVs=#wG^Bc$s@N-qbnu5>)^9?cB+eigi#N(1hHatshMK=x`)LW>&DZh@1DWk{2b!m9gpKAyIb zv7>7t>1Jlq)>_LLyQA7kve3#ww!CRhz!`qD{A8UtGp}Fff)uo`4fMfXDc_2KIsQRrS1qX!kCH#z7)iEVIvzmLADTw0UCgU>R2$&%&Z`ibaj? zP1VvfDP?CID3W!&@MMhs4C_&`)|!l;KD`7)6t0SF$=H&NNV$kOfH&%CAFG{rO(M_& zQqoVe=a&k`4YbsxT}RV5SCS&_BZ!Q{_4W3#oYxZ=xIJxW%|pr#U;NM-P#d7y+r10h z$K@Q<>K7fW8ksed%AMp4)>t2HAv9tk317XKbW+~bJY(!TA@K?PozwLr3F0PKY2Z7Y zrH_k|HKN6Ptoh9j8cr{oDFKiJcv(8d3PXB``0?9>wi7Eo3J+i|OB0hGvZ$u^9lv0ajqt3B25dwyj=t?#v{D9kS1d3W;vN zBB+`$b_DNX(k?ZB1!s!zIWq(7wAI1rj-Z`M;I^xDk`{i)H3T5%03Fdf;(=#dRE0Z? z|5TXUKo7io-r2~I(osZ+^Xfgn)E49G*$PSL$QB|8B%@n0?kIF++QsAVoboBY(gV&Q z+QMq3WW_-dHU18#j1)VTBhdjk%x3)=hmnkbM+DMfp;_TheI%%F1G#-Jmk}!Abpq?f z2PbdlmD7!W*5+Z|^T5-OuFvT|gs=_BeeJvUazs;tLqvv0_nAhw)+U10*(+260PM+H z3+9b*@0Kw`U?trmSC0ce0l(h_dZ3-SNu@#BL5z|^&!T%HX=LXi_0LA}>I~p^02;*? zL53q}ax?Jqgo<(_VaCDM)(-INq%3SS9cI&~)i1J$)v0^LfZKBbfc(#oG(;RhDW0 zm=;NV610V^;2b-_d>5eIuS)wXF=J;^W&G9A4=_Li@t__exJ!iW#Q1l>$pJJEr1x99 z{*wgF5q8W5qqy7nqtOqbWB}`29~=D%slN(VS-e}9DAW?*dATDw!jqlALjrfG`&m8k zm?sC|3{DSSB;a;C>E@NsmH;mi^ePj@imYMj=yl?|>VFl|N5L}@@%$0FBW<~|Sm_K>Irbo;$CeI2 zu~URed}u}{;K;O8nyohC7!Z6Hki`zXU^k5J06H=DbcLEUe>FUeC%M??PNQ7J?cp&D0!?@ma(w-uDnjg^w?wEo^0;DT1 z!u*K5C4=~xuthWvH%vhy0rpm56c6Wo@#04#*8rM%@V&XuSMze)5+4Pey--pw~f4f5}dy&AoFNb*Wo^hW(QqFSw_NE1F1Q;-P6UITnn z^VQ#-Qfn>mh`Uj1E#*;s_n0UDh`fIY01$1Wwb|HUi3yVPSMHw~(@y{^)2ZRT1{mGv zByXk(@RPyho+wh0XNb+FI5L~N&**-m^JmR%sblI1ATjwg4-M|Pr5UR_eDnlpB9BbB zFu&!THJ`WX+yud#t$4UkfLUnfqsCLgXW?ajim|)ud(rCC;Af%FZWA281<;6E@l6Cy5DoKtvBQ^gwbH|U0-TC*lDAi^ z#IT*9D;Gy5^D#f^`PO01DD!v5;H()&acVwyeI{I<09nl6 zF+ti4E7wHp@Rbu_HMnNrVwPicpA3s)djd#`*h!M98BSuQfuePgOhf?k79b(NTjY$? zF0L3Ojauu|J?Z`^yiKQzvZ3Uxt`lxL@Aui<~>CwOR1v!b6wv?*+Wm1UTU#4R2ju-U2j=&4{PQYer=K^tk9PVD@<= zj>PSSwwYW+>mqH2m$v{;~vF;<`7UK-!tc4BBRABWMpNd5f%8M+TTbf4nvb8Gb8 zqUv1LV{w12$Sh)fyV+X0Jv{@^05m4>K1J^Q*>$_9723SKk*j0o2abQu+~#@zun?hddKfr){{#@zunf-o_V*tk2uMi3?j5*v31 zphG**d=}=3C&7kipCd4Q-N@wbhWRs^$KqnglVHRgk1skzlFV2t00v$Q^NraNv-dxK zCsx*7re9=ocR(wCWD(?`>;Pzt5a(<#n_$?)|lpHw)c)NneV+$Z{Dx%05%p?c+vRUxybw<)d3hxSIM0ke|8Ph3(X*?DU7dXLq7J+a59<_<7YVJml(4c$`pu}7S(H_Cgo{g3K$b$!!2 zz-ZE1JdHESSw2=!ZCXi?k??xu`vjuXUN? zCnCaZe(USuYPU7JCdUf)tm|Nkw3 zIjLF^AOfvJtNCYqQ)>9#TRV?J)IjI$rJIOw|93D`F`)BXsN4BYuO-ha&J#_}(c?$s zai0k6V$BXTe~mU)=yT*MD1}Jdi{aVzwfnr$E28+8Fh@_my?*HU18Dby&{=%H9{>OV M07*qoM6N<$f?iSKcK`qY literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_12.png b/assets/dolphin/external/L1_My_dude_128x64/frame_12.png new file mode 100644 index 0000000000000000000000000000000000000000..19fc985ac866535e616f20dacc7956deb9bf1f9c GIT binary patch literal 1100 zcmV-S1he~zP)6{GXU2BysQ;%f4CM2t^+}6X4*P00%uVMM&b{nE(f!Fhxk>;F$mioiIg6A{ye& zGCs_~B(62NyP-!D7}w{YL^Q;!(GqbE>gZ8qWQ0QC*WQRpql3MR+PRLh?>+(W7KtRQ z2|&Gm#8YHU5t4|4H6g9@;KqeMNN8Ey4(Pd}iy7DZEZUQVNaC;7zZIV$k_doM9Qc}L z9c`w+rTlc!RIw+9KpTgV;nTz{vS> z&|p~hcaIN!QSmVWuz8E4JsDt~9!-FAF>iugu?XTwV{OAVN66Eh7f8Tcu_k=0DXjB@ zxw!D-5>$XRXsz=-;cMruo1m4y@#2Uf>a57b;;R07!do|iH(ojCZ1vc2^>OLyleh2g ze)yU(N`9;P!hA+`^z!21O?h0XEqaYy?qlMXFtfJuIG4gBRZQ$pf***F-vT6@uC92A z_?TGid)8LsQ<{NOXU{Kt0$8tj>86u5ZZqO$zDm;|e ztog6ymGkGU3S!fYhxes64L-Dar{d#Vz{tvV6vSrvHY2tASL&Xf2v)q*u=y>Zg^|X6 zujz8m)jYh#ANe(J3OoU%inA8K5ZBAWy9r<(6do;j6Z=n~r}&gSa85I#OEdvheDfxd zm;e#PhaySZjA&BgTO#{8Km_seijg)?@ztA#GXbKBkI9xW?#h*FA}wCop8-6?ht?8W zq7kt8*sPmdgM%1JjBOhP=%%XqQ>260{qGQ z4HKXz;Hpt$y=nryMf{#vBU_2HtN5>;09K|cIyMa+?{dHuWA?rpa>%i?l7~f;bM$HP z4)ecpF|)xSDKjG0aOHk$)1GjeW51UFmd^pAye;e`esj_0{P_$ZQ4}^wQKL4)ZsKFS zVQ}e{C^4>P{owl`YM9hmZu#T#IMS>6k08m8mLf~CIkk+l;%huf#OdjJrO*G~x=vSv zQdZuZ#4i?oQNTPO-vWALYI)2wu=wTpk0ySp507`e!r^t+Sn~Oq0Iijdk0mF=8^?d) z0-D##rXK%!3xFphi#{^0_>>r}c+v5ZdqNF>iCCEgEkB-3!L?p9d5bx#2edC#ihCvS S04A{j0000$-;dTKl+eq^)-bUFWZzgXyR?K8M!YpCSQWUN`RHdmyCT^5=e$GRRGMc5B32QnsYLopF#kOCv)YsI;%YME-Juzxi+UT0p8vC zcY)^hTsZ)MN3>I^qZ83R-J5qhsPS8CW}Acv5W&a$bHEwjQnq6`0W`yYjBmqrT`uEG z*rEXMEVn0s%Dlz+Qkf6|xXT4kU0Uzs{bO)mA6>Jp7eRM9eyu>{w~SHQ@D>nJfnGm@ z$#+KO4_Vtz0T@vd-5F8iYvof2kYT_c)O0oYpx*cZi3*VA#g#;Or)_41@d1*zfJ`a> z%Zk7mzo(Y9@Q@`v2FTveDG}~Y2FdvJ+%MJjDn-dLup+XT7R8EpkpGeKxxaClp6A7b zHj<5swkx)W-2}1j`E)zzYvFZY0#Cq~ae0R8F1-n? zCIaqbrk@=*la-e|7Nirv8l?i%d`BRWK^sr6w~_>2&o3E6BP~ZKPZ!-{kX4HQAhI|{T`sb`=vtBEg+Mfo}=21lf>*? zEz++Y1FPmWbqdH1iY(qt%V;NwQxw9w?^}%T@p{X+0MIGG6ZL1ZG4ex(rG6G6X1p-l zbFH_8mQz9a6i|7ci`(ZgbIIgwhqjerd@muaaY7`xd~N|+O8>5o#JM{HO$uo}%i@jx zS=+H78uZb8&H=gnQQBJjR)861($1@q)#r-)h1K3a+xAld@NF08`QCw5pnGC8u)`jG zs`0)3jMhc;{Gaqe8HArlm3N`~m=~>|VSK5MWCx4AB>S=oKnroC*m*S@h4(1d>tyva z3(1Jq6px8jfDuzNu0vNN^Ddww8n*_0l4s*_Y4(!xukSqF*zc?Wc+A!N@#x)bTU@@D zTFbKvpzSg5WPE`60Mb%EE8@rX)T7&^+_MVMenu)Whd#gCHo&3MV?ETr#=Fh@cc|Ts5Rchmn39R04Su<;0uR>Vc`}KbVH72e=kJz6Kz4rXRZ#Di* z8xlMotd+O6r``jc6aZ!fZlktmyw$TVGjW4gU95I|i2+VGKEUh89~H_#+pBz#Y*A+KEvtVi}uMpBlP)``a$}ngVc> zwMgM;fwM3oL8L#6@v;@gi5WU1|JPdvtaB4>h4o^3vtXI{*Lx07*qoM6N<$f;c|f6aWAK literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_14.png b/assets/dolphin/external/L1_My_dude_128x64/frame_14.png new file mode 100644 index 0000000000000000000000000000000000000000..9a3a84fff837373f3e503913b6095071d044c33f GIT binary patch literal 1460 zcmV;l1xxygP)AxL1WuIkKPX1RU|H3IM(9i+z9&O$8Zz9^wF+NT%vb zZB|9*Q&fP8a_ODi4sdt!p8_fBsd}Z9a(O%DIywy>qtpAm}OE zuNClo%NW&lF99AE=|2^2skHPywQ% zIMWgCw9Kp^zm(u5AX3WzvLaCA_fj(#7H0|10ixG)>P1Fo z&rOOJcaZ-P`P9#_PJd?Y=VfU)gN%vSeD$(ow}WtNK6O|I%b795HYo=|+@P}^f$Kv{ z?k*>=Bz)0_XG>24vmF8UG1JeElgZ3O9t}Pmz&ikKmRd^A(!)7}G@jmWr4v{qKeDg) z{TBSDc+xe5teR{No@K)`9xeH!IdzZY$6ky<%ddM;I4w)hbONjNM~|i3yR=@%Z9OPR z1Lb~Y>9l=**6%Guulplzq+knM0=(-wHPBNOAu{@A$h~&zo_wm2#^B6gDCzIZ#0f{i5lg|$9Kk~$4M*JlVPYP!1Y~R-cVxsPM7-lD`lVe! zS~6NDb^&le-smr7yj9dXf>b{Ov+o-9X_wv0PpV66?Y{zy2AS=h8hN!kg4AvXo{65d z;q6mYp4lZp^2%A85@sDiYA+#z{24o$=L5CYa^bH_T#0|qI5OqV2k@Y|oI$&t(k7Fz z?h5j$Jv_HOO3SB)*Y^?-y(UE=;%vZ^y=NwUGd8&A9{%1*AT}l?9IN-RQD*`xb`d+I zU&|LRFH9z`)QwJ^ad%v)MiZ|-{Pyr;_ zxC^N5p5-01&hC|dynXBKB$BPXQKjl6kTP~B^a;`IZf0ypC4HWJf#XNIzOWI^_1(}j z|IzrPoO(o}MNzb+Rsp!{kB>nkkGW&?Q;3RC={j;u*1omZ*OMck!|Xdnl0WKy6zS2| zA0LCF*T|D0$+agU;e8BE&R})0+3~(}0C zGfANryU1^?{r-)h)8(H-1ZnVHcPL9FsnE7mpZpql0^t?~!iiVEwkD6e6i_15>I9|e zmzCE^q(fj5ESWW>T$oTPQsDh8>|Fcb0aCy&fSa_P&M_iR+m>pBor{vs*?wonmnrkA z9DsXCO%!A&PG0+*l5kG2A{a8(ezyYPmy^hsCM9yxMr-nnD)e^R#5XcA9wnUV5zi^W zZ1h`SIKmDGt9@#cx#*{y#M&peeN+xGnxF{GPTI)M2wLT$NQLb+lc>dRvdOY6a)53R zPDX^CSy;&&O(Gmus$3_O?B58=Kx^{fyS3Vp>TzWx`L%u?OP@flru+w0?-z}=lz5x~ O0000zkvSgZur`#u4^_xmY;$ErOv@jajJ z4KR;yqW~7`j0oHz>z zC3-U|h2L6|0%QmfVi|aYFY1NgTA~NYvf@fbcv6_*gb%HSFV?+on0OSKuKbfdf+T!; z0+8;tR09D&KsXE8NgcQ0r&#d}G~sja@fheEp}Z7ak=aX3vEm8tUyAu$y#%+BeU+aA zD%^KPcv!6R+u zct$Z}`7@C2?SK37HteyYYDUj~`Q$1k@XSm38eQMlF~N!E$4tC+3LEscZg z)j0u$wkAzB(mlucO!N0x9EUqGytP_SFynP9){|NY0*n?ZWv_QD`cyrwTorQge1NSr z`LAwApK<-3jesI>^WQ}gvXvkb_bq)E+5MV7D+FX~ady%ZLDt?lI=I;5NmR42&1g55 z%taQ*tpR%n%UQn?SA>E{ogyN`O?tQ>)tXzYvBuFR=!1|ug$WBX;=Z*$pvjJg>gf<* zbzL5MfQU6z7qVvPM}g#6{tu&fo|1t)+&5!c5mgs$MV@6faU@;##9wVG(c>>O5w7h3E8?QO%76Q z$K$zvXg5o&Ut#%`u5+6oMpoL9gGS1X(e?FT^+t(U zuAhS5`63g?+$)4{;UA6tqt@yHr0dgH!ZeL}s`bN$qaMtf%&nMX_Ii7xod)hHLpYE6~EyI}QtG&i4N@ff3AAgld(itt-IyX*>PTTrnEZLVyg z|7!RB{50?h?mv5NngUQ`xQZXMLiOA)dVsqF)>x^ecQJrU5AgFOp>sI0*`z&O>E5lV z3xLgT>9K<^VuYTF45_S|hg~Esk@{U2P0_50xI^R0p7o zn8}PWqD+h=V44EaKJ65AwIXoB$9-j|0B#|p&5shLj6^D`T#_*9+N9IZRo=j&lw}@3 zT2R);ql%!#_J~)I+&`sT?GaW8f8Ue;ZJY+0qVO<6LCAC1reeC|!S)C|$2Ga(c*iidap z5-oZLq#EFBn$I=a!cI6X3N!$pkBdH5MZl2k zJTHWKF-OVa&DUGE`tw7nwH6KHsI`8a>#?%F1;YGNuHO71A4whN`QOs1JG@{}oF&Hz zo{*EauHALOdU|qMO{e(bTC$jLQ6D@HYt&$Et+mm3_Z~+pubt8TkSDxs;KBIbO z<9~)6Kgsj|J_B$MabkFxt`URc3&mayO>^Sdsq1JHK=-|Nyi}wWv%SN5a#=QkXae*G zIKAUnMA$K<=ZK7%4!h&u0-sKV>ZDzAa2;6i%yf-$R33OuGM-NbRWH6~q4N$tr^Y=e z!m8=mY_8exbCHcu3SA%O6g~lVN#LS(Oy|s&m_Axl+YA&B4kdx>x1PKjT>hItZpU+` zk3`ny;l#Dx?b9Jy?xK1EaAde5wB~y>!zirt zt-PBxy1P#Rt1+e(D|>kBXFdTW$*E#@$ZJK+8WuaY$LR?G^E^0-&d1#^9lLNX?GD7(CHXb_Y1UIsn%2(z7I2~oxSfxm zm)t9vB%{e=@j8nzALo5m$CYGE@4ODEG0O$KZ}v>T-rD?&p%s%lYIdSzT?^B(Uk^@h zk<5}bi;BbD#tyMP%f>3!05Rz-t|W45cQCZKi*CH^SC zg&C(e5w*!5>ZEoNPsAo!Gyz-}H^!(bFk04m(tNC&*}n&fLTONwWHmC>&DA5-t=9VE z{$FUNs-|Z#?QHVQKyRb67@C#Kjczfs~)$5}HsN!d0jP8f$EsORJOVdy2p!EaB YADMSfJkRd}+5i9m07*qoM6N<$f@&T_hX4Qo literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_17.png b/assets/dolphin/external/L1_My_dude_128x64/frame_17.png new file mode 100644 index 0000000000000000000000000000000000000000..fd910ce5a61c659c7caf0486f2eef29eed874edf GIT binary patch literal 1399 zcmV--1&I2IP)^@RCt{2TiJ5tAPj{0|9@s55>kpHfo^QCyJ|}{F`%PG!+4W6 z#u%-&@dP_@YW^K$3()S0MYqW)$jIqfGnKap>yrBCKzLk(t;1~MN`2K79Hw5WBo*8L_>TGYrLk_G5%x5KG95&m1dfdb4Rap0Pr zy_yHtKS4eP4f(tLsC*&$*k(3?_znPr!bwQvjY@h2>pTx|P8ggb;5EGR&&86`1Y_{; z0W3*baq>8z;?^8*yLBY_Smd9J$E5%`dF>9Dz$0^4fwbwh@~_=&8YO1$0Mj`YbOz}j z*~$XUU(#q?Q&P<>g_lf|0%)AWaS~*lUD4o_Pm>?~yoy`X98o(Q`~RZ=yTxG;lHfB) zuabYSA1UcpZsLo52+{Q zKf;G4f6A|iRE*vD4>xHyS+cl>e2KhW8BzJS=2KK|U2gp6&kVsN59wIOG=3rxy{2WS zN{?S}ong+{@2>{nCY>fdL;k58y|C<5OOr%3!x-p2faMIiBk5Vki6*}pL!`o5cp={e zPDGtS+TgMX!ntLviDf*xzLCw)TI0V3RFMwnP%&fx@5D$yT=P=$PW`;vesD0_pt#~{ z&cJH&Gr`4uQURd~@CFBqP<`HFS(PC34x+hJRon^G3g96hBfA-J)2-s5h>D7VBU|DVAFp`4 zn=g$5M3TQsIul&cs}xF853jsS*7>CXFbFUCtIp*Tt^!5&PL88|N)S=^)qLnj^jpE! zV0Ot%RRR}Y0Gx<*=Tqcp$d`<>6gm^V({DI6^Sz2I8lR~E zl6AD$HO>{3z(aht{NuX!*4lv1qb`8fV?kOZYQBej>lqE_dzxB$2Z`8hO9hZ7xgtRm zWRwb2kq`YvEc|LtH^BFT=W>a&U) z+g07>d<*%%o=*j!7R@>aJc{7GJ5YtPV%GrGcPq2Cs~lEMjE5pe`@YvFZwO`cIN z&HUEd`VMfS304L6kcC0XuXR2KbvNOBRFTj5+kOk6lG!zd3C&BGf$&sXuJ%aSex-b7PU>9^mQdet+OjOIft0rW;yo z4FK9tu9wpLl@fM4;ag?LZav@#CB9sC{21Vir1bvB0AC=b_df>s0@<-!j~@dR%8olG z!;b+r1f6@oOJ1$Dc3l^=*5IkKBRgKYrm*&-V|M%Hx-Pi>X2KE5R0i7{lxPx2>sRl; zOwMEg%URZVYo0eqSv{h`&FZ~VzGg1ojr1BTp*syrJU$Y9Jf8-I>P`2Rf{X2xf~(Dc zECXaSeiddh7M(A>KS3@#19+XfD+wh1X03aST)_ZQXPl0xo|66adWW2P2B6Yo>>cnZ zW|+YMlF_Hp{|aE6jthPT0|0!Uswpx|@id$m{MH)0Dk@#0dwQR{2Kf9@?+M_F1b=>l zyqe+h5!#pVblL}~djdI~0VL(UO5pLF@tk~m@F}A0Zz%%+^Bf?Ginj42V4JEdJ*tEI z4A3WaXcbIlG{d=hPeCO306zcWaeZA)_VJdyuD?G8aFb@zj^vytL283syQETUvzqjb z$7rpseG-_Zx4X0nuN_*lR}_~AZwzok@I6ks6Szv}Xr0Q6BC;gbFZCRtO4%p_oSXz) z@2B@pkpTabVft?aXE^voM3VR@*;?HhV3%`u)S5@!Gay|-}2kI26M$@H(`gdnSJ z+rt1}qbiN=SivwO;B>3fcSUl1oB>9a(Z*Zo^JxN{jBN7H)+clZC|{HWn+vRjJ0*d} zkQ_$s$R?9|1{j&#?{ktvYt60jUEvLW#Bcq+Cl1=)VFvJ4xCh=!SxJ{8ka|Cb)E+cQ zXNno^<)vj}G}AOgH0P)pdSf=w&Ia^8#&un9ul|`NNBqS;3FMTvjMRdOuetfrGsSL5 zm4;g!EgGw0Eotea>7{{v4uB1^l&qj9D``$@1C~CS1GCp}p5&m+fj{T)vYcJ5yvMm* z<=g?Yf}cr_t`FBn-gMRuff-{*A+@0s;L&AQ5=7c4w&B&4j!G-@M%Lxp&|R=Q$e#9# znPKSr0DUnkBeWIG*jlUz2Uv3s z*_H$m2JkAIF_Oayr(1iC1mE(THSZ_}@G2Q`0>+MN$GUm-AK9zJv)-yCaDOMzqZ~C> zqID_w*Tp}?*oBJTPuG$Bge4vqZMWOb0MuzwTIa?`m?a8H@9Z9u{#Em~GeG8S;4!|x zETcIm&18zG4OlNMGkaLYFzpPG*-SFZVgPSXv;yJPOItTv{ah={GLyvwl|jerzo^pL z#W*FYF=Uzhxc5KT$^Ie_pB38f8i>w2Bz zLAH%ZjOm@n`9srNvTrykS{wgXu%)C2bRGJcwyy+j97o@?5b=lQS8aSIE*Ai_$YPRl zmB!LB+QT*Yf-v z;)>u)`@H>S5Dthnxw=i@y{T~=eN|voZ!Jl*#F#rGn07*qo IM6N<$f>4IGLjV8( literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_19.png b/assets/dolphin/external/L1_My_dude_128x64/frame_19.png new file mode 100644 index 0000000000000000000000000000000000000000..d602a01d5b14b4134e49fdd08ca5441ee263c2db GIT binary patch literal 1648 zcmV-$29NoPP)@apD>%ah@N-_?RbO+!zEF&^^l!3Q^igL|9 zr8vM7(*M9pC()2zuS_eXsE4xg^-uL?!5exLp_<`oPT!g@%O0(@4ux1T+lZ(EtsA`} z15j)_Tdo#b<8z;X#)erp4J%u<;bxEiSFaUD+MS&ukw0+2Mv%7I0vCS+vUILAz9sr4 zR?o@i##~6Cls?~R_yMUAqQz4pUqkjRxMTowKwzN^qExlnmiwx9e$77NsMqQ<%Mju* zkZLMekg;JN5@;DW+e~eJt>i>r<7>b=07a%W$c~aos@BMnh?Lj(7FbSE)^$|;fGPo* zPoj39l2A$OWS2?K_!+5x;Fba2Zv574Px0`^T24Z6o(CS|YvpQnx-^1T8=qP)%aNi4 zR5}T9pIf0RS5{{;XEEFd@W5NAtB;!%PLKtQ@wI(^?lTEwAHV{S@ufK#-K{L__yP)C zdt9S_hhy+u3HYAEB+yElD#vp&BB*eHS?QyANtJGAMDXqit;VYR(-OWhuJ@kX2cYUl zgcMSkwV3hxP>0oyHhZdO89$pJVfz_4CGwEzX%uet$k}|#g64k57_9gBv91SYMD&s% z$^KwPI0dkvs6vqzb2hy9V!a1$|D^dDJqPhwfTjKUB%^7;m9nZ{eKsn}Ae46_fxk@b zsPw%Gp6IvA#j-S~hjT|XLpH0qp1J03WRpHj+_}#b*A|NvW8N$|p2~GGR6T ziXH^n2cQ;zgCQUr_ptIRL>!rWOwEm*UBj}zeSj4Pwh$VRPEwzt`dd8~M4#@>Nc!v= z#7Pa(c#;>x2_!GhbVyiYW@}e~>veeKWZC6H9I0mk(!}iJ2*#=iU6BzY#`iu0z&#ec z{w>)5k>`7oRE3q~uWBtz?WUk@#Yeft3B3gmpnlH=Mch`_>Fj47t*tZukSm?oxYx19 z_xk`6>#y!~{W?~(zF|qj{S^2Ljo*9!+X$My{xUMNz$}B!I+0ObW&|5M!O?r~nzZ|C zO&N@g`{PpojI=>ilq8A>UNQh&^uHAO1G|jhTKyyUp$Ftw@b$#a89ZPJ_#ZY{oeK6T zDuEwLeJHQsUf%+%uF=k9c6nUs2p0~(H4dKCMjengXk}l+oBF9ejUFF8_%?#L$d{B` zg{qEW^q#!N_vljP2%o2>e_X37S^wbkWjqN|FE8)Q=k<85;#< zXOUwI@spm_jQ1WrE`Jw5Wq>z;YNvA061@yk7~Mb5e5<2hz7oc<|5c8VQEsfda^p3G zE;IV!8rtR@mgPA$O#1-4%7E7yDtZ`HDy}d-ly8+mUDxd4IWzt);M#4SE4`P%-Lqv= z@fi4CihR6=^oqF})N}A34a5upg+2w6fuyMPW;UGuBV|$3E3l?}YsBAl>izyK;Hk!+ z!DHl^)3nBaYntN(oN;DlX{NXIx%(LSq_m#}s*l0F&eAStB+5XTfJuA-?=@!!D(z!O zirDPN0e%78rb(NuIsItQ?b>~Wvb01TI#twOz4va}Yf`_~ zxwLvo<1)alE&iLhETgS-0x43pk;NI(YDBNz@LCiz-9!H-&ZERCSj&MVgOb-8&Gxx+ z%H2B^99aZU*G4ip6pD=CQ(s@1x?R6 zT5F9A9LGUKL|T>OINtZYdJp!-VHp5lVDDb!`Gfs%5K$xg^xm0;>}(+We6T0Z)*7|e z=s1q|M^d|0c4&((`;=`S>;X6gRM5NC$CE?chm%P6=pWow+B~E@?Yg&7%ANblC2F5X42xK~*cSs>o{rYz ziqY;{v8yW9%I|zU@;bsy5$}`jW{nbMDi6HA_BDgs0>oP^C42NK`wzudr>-^ks17r-WxZ3Yc*Wu)7LR_s3Cj75?purR z^{th%AE{f-qou47t6K8E;=I9Ztu;D5dba4>5|m*8OR?xPZCn+lW?WY2^XBFm7@}iY zYVErmURvY+a&}@r3PtIo^8QCXI31S3Pw zIEJ>!mMn`MUi{%mpeJC3wIi_T&coGXw2;x6X6Tv@P+6yEIbLF6bsqKHt5F&6?=W}^ zRzAV6wXvS^29o(-4J5C)iuR>UOZG@tUU;nvp_;MFzE7_~zwaS4;HcMBc$&8OQP$cG zQZE@jombOXR^c<_M8ez*b_xX+tTCQmrP0Kq$(PnH0=_#z`jd5c@${9f6InANB?nlE zii!6)))&`XeA%uV+L=iNRr;7=pHp_Sdlui(4Z+)z^18d=3cW@0xgi5o#Wy4?uEJf5 z?@$fl1Rb82jNajPrzzb14 z@61xJ$0VygQCs{S53F{?%X(m0RRqz+&lrrg_;)OZJki@Z8SQ|!f!@)u_sJk~tg9Kz z=zYejQjSfV*VRB|zJCycb|xuSdn1LM-46#A=)Y(&a4qwW75XqVP@xHwO<_qs}N!U zWWtsqc>QL8dRIlbv9RJ`Yik2|HyY5ctnUsWxosP@izu-=L7Q2?s|~>1272(=K+6db zL=3?TC3l_!aQVN2lmQUgy8`sNg=pBYGV(j{Yl}}5Oah5~%FR6cHLPCbnO#Yy-3J4B zos6>g$liB%c#5pZIjS+E@2{6Zh_GtfzY;5UCRHAL#}Rfq2_(Yfzx;kDcFFi>4xu=* zNq5Ka4@3Gh@7x_RgdN#n7RYh+E{1O*^qWA>NVuW=&xpM28X5kqW6XL#5fB0-ReACK zfAM%E3EaWZE5`8Z9eH%6Js%mu-HG7rY22#5D-b@zW*zGezfdiSU_$Xvzu?G<9dmrA0V1- zd-UFWn}p*yn$*2k7isV9@4+w5Sshms(tB^mafIt1@R*_iBO)Ga-3LF_9Rm4R5DZ@6 zQ7#?WK&Nd1+Tc-w9ygx{HqhRCtq0hFoW~3Bpq?4>9 z5%Ew~rT{y*f55jZ37)$YltY^(TL4y$h@yNekzR0CKU%vI1)!wTe3n2?X-1bq-v*1- zvu!h1!PP`pfm4oMWSap>zURt3a{?6H88Yj>HW@Q}~Jr2uzcMCu-K*&Pwt@3}T6 z1;`LzaXP4esRX#ILQ^86%Dp*CAp(k zvI8PkZ)q!ffV+~9Wf&b#Y5QF-kTT>C`{q2royn(&Y#%!*L6-bc`?uG@J6-8s0hs>| z>oA-A*8UV=w@7^#T&V;c`I+Zw-RpDJ77$f{6}NU-B3CQ-i2TZ6mJI^E-@M7(4}8%W_odUGzvC{o}j&%`5!zYPZCyEF%Mq|A>#qGJz zIRE0Edl{4!$l3=M#9Egb3vjpd{^-qKMzLO7z$m4kvjA7mS#0$-fVUPr<|zKXivsiz$&zA?F7ce;W2y{1Kk1zvS_iXK3n}cZif9Xjz z2pQHpFu@!TxS~JgcqiuSWKWQgY{!TcK_sb>x1HhL<6=QlW-O}eMwR!+4f3()R zMPqjH0G37cT90RJu6@+?XU3??pH_{zf_%+-F|Z{^T&ES4rLiST%Xk=XJmIZ}{148I0*YM`l~J2tmVB>V9QiBKR}64>C5T|9g+^tG zmRnQPJ;0{{;t6R1rMxG;;PN!Z_13-LT3+G-yc6FMoDyf}Q)&HHOP0#B>CaA34z6$jTvr} z${rz~+g`7>d`PGM+c<6!W&_6YSdx`|fTbTSPw)SO+K3#M`e-Wtfru*5$n6fpW>tSg3Ftp@qPcNGxz^j***ABZyWI%tv)L=|uq zw8;m;0j|Lg@_}%GE3k`v;M)PLOPa8IOT7_Z`7-D&c7^=*x@)5f@QK|gzuX%dz#&eN z@1hkP_=%I`1Dz_sTKwz~QyMt2UX}JPQB=bCx77oC`YRG*W&n3OR zKO(>(tOza2Tq8#qm6EILibfD4*K2`ul55>iuV?f*%SHs4L)!sHbGB)M5*cQ5ju3r- z33iYVJV$}{vzb14iXt3M0T3O)Ll|DMUeQYhE9>Ttj}$P#uG2qz2G;>rQbD8uCDaX` z)1}=?6mjbS)@g&&k$dV0dPzUipA*bq3A+tcBDi6+*A%M9ah#}^1~|?nNd>Rf06l_c z_m?rF&7(Mng%d~|;B{{Uxx^Px+q0BSy(wZ2HGqdaOtIy<&c!Qe-`v&DI87?YnR;Sy zR2KhofK~)~xAj`J$!Q&dlTJLH{&wGhe?0$60rmT9uC;K2dJVfk&FAfUyg0&W|E?5) zr-<)8TPo_f_xBur1g;RgP6S$?s!>jED+ww_c2&y#7A$6DEHjfC8c9B!hYmpAxQnCF^ z3Q80ime!t9z=_i-ZPq-Er_3=*J*$qW(L8eF04GE9iW6w$=2i5ZNwR+~G=ODZriw#J zBZfO(GXJW$b>RRf(IbM=-><<9=_`$$Q50D{I8zaLqBr0q3;pQp_d1EAUVr;8VDzed zHvZ|oLi;|Xb|$gS+5X?hpMs{^raq6l51chDCHl7>+0000@+>tR_foptVg8;1$^}g>N znIq@CSFYbNJ^(yd1o|PH@qw!W++dmaCAb7|Kqk>w;}YOtXhexi0Apm#`xKwD*d1-g z9plf+$9i4K{%#dugzTPQa8tm4j!OUooZ|h!C4f3kGCpt!0WyfW)iJy1tH&z>e-YK= zpRLn-tu|f)=)fZMTZMg!BT_(ioN9ak_+-eN7NZwVHa>ux0wg%y_`oH=6x@i?JI>X0 zyv_0Bdbfj6492a|si9kc>!B#~)_hBdL|}BDx6%#8psNO;wS1Y^GU#kRojd9esP+N= z-ar03a@uuv52N)sUf)~0HGf0`YH0em)?AZwec$(uHtLS?wQ@6EPb=iE?zd%p`d(|k z_PHJ<0wwuzG*{F3qcvOJJc7qQk7)$eIg*Q3ZuLgl_ijqF*n4^c6d|R_{90gH1i_K9 zdg8NpohAMeAXS>2Y^v0 za23(Um+XTxXQTz_@7`MALu*sbaRph7&qdvp(^xACX*9qL7CCqqkwRejP}YsA007`eyZqBC4`*og#I@F+MVJg;uLZYf0iNE^@l4M3yT}{?Tr_}XuIzQ{ zMu*7_;SywR02P>P0FQ&FqNbP2YY|81L{t+s38G-00z3#Hxrb#M7=`{-Sb9HToC30x zNh{Fy!V`=S7(NY*%(0xgt=E!$_twa0e85Npcw<+a%+}-Xq1G2W>-FYSt)h9(AB%e5 z+xsp05i^q1*YymyYOK-x-sdRSh(-$$m_7V!dXPn^@4aUMbpm{|@mEU5-kvy-z!NFH z66OUB&)+pr)@n#y1bTYEr#My3yNO2C6yQk!fd7R^30ke&uNbum;AQ-sds&LU({Y>z z&>~vzA=2zRPojH3g#eikr8eqlpDUk%(@Qu3OCm4}B%#06XxT;76GRIvbpnBS<b7`u=1GuEKZmvU*g0wg16vatNj zimn=F+K5?cjRSBytJHn_|2NE307=IuP$!X-9NdG60Pu9dJ=scuItko;K~ojDctbS+ zPRS+IMMk43R3{rEY4+10+#i) zziaRqAk_+Bq3`FPkz(z&^>Kbo%5I{yf-cX&s@%!}W-_`YEu3~>JRk>!G}hM7CPs z{Gb&CtNL>t7G-$bX#Z;WL@d`x%m z;?9h69vrv|_Ai831+{EH4X>0@9MWp(zi8u*fe!~;09eR=th`&W&mvq^fYJV)mNw-o zcQp_=#z5@_(4XYk1MJMM*?GTQ<<1=E#65tCUj}hw^e*9y?o*}-QVYP!h(`8PE_{sN zKN;U`gNN(~AO=8h1UwC`@}Gj~gv?J^B7s^_t>uJN@p|x*{Q!=pfL(nTBYzZ7ov+UR zlZ3&qg!N8L3Rqc|J_Z$@GCyH@473mcTz0fZM5^3$Ij?0b&qhY z?Q)a@XaxY5^K0PX5GI^CA%_A$)A`uzGw{-*rQv1|z=`Yp4~D)Hrg`D21cspnSRi7m zlG*~a0suSiY5?3yaOmye9+Knp>Efv%1;9z!pXYszrvTd~o_3p;iY^DxB!8cJwRATf)f_Z2=z2zqEa)R{|FmpapKn)GEyB zWA=})PU3&en*#7C;Eb`r>N4Ze_G z_kG`xh;dyP%nUK*`q?%|d{|mZns^rMDYPK0a%D+`Y@RQn^>E^T|T9=jPr4or}nV; zlHVhD0UJcE`!!ht7CAwDfJ}fTP7xm<6JVOij=x2S1h6)HCz(DR(**uPIoscv{jK&| zZ9Y8*d&~r&aZ=r{2~h&9IaPcBfRA-u^;WMn@FG3{WC?hJd-i)0A0QLpAJi43HEh`Q z&E9Xp*ZKiGP>V$srYCUk@2wrhY@ZTrnLz70&$18x6{Y-8!Pk%OFXGpI*L_-k|1A^f z;eYRTOkBI5Sy&k7~+TGyzL!+qbkwFp*`8{94yz6E}cI*~NS;dLfZO8j2?t4W|G z%WDpT>Uu8;Uh-G^Yn2TtUXcJ?^`6SCfLda=IQAqEn<{Nu#&Gl;I0^o0wDkC#>;bIA zZ}pFpp*8C*yuh&~z*>BO_9`%1?t80%Bu6H|jQI63tHJ6vRH_6VcN9E3xVtOImKe?UVsZlHhoh3EZvwyZiTEoA_V|Cjv&(3?AbFxCe=2CGcQG zpEx1`xCXj+E`KsdBmgH|Ng$Ct5`Hbb2asB3DYbcYZ_ntt^Z*`?Ye%t%38(hvvaLCd(^TJaWM^B0yGj}r;kzMjP~~0D?msS=zV+jBz_OGmqFGw ze#*5fi7(L)e#JZUER?uHxDwz!0cJcyjm7K-2v!18e15{b4fI_1d-dJB_y9pXfF?5n z)ShHk{N6qF4nbpFKGyqw%6Wjd+5aT`NTAU@v*T3m-HP5#pr-iLnZ>o#_de4kj0e!7 zUUllde63Uj}>lBpqIK|YIf^A#mJnE-fMUm-xA%f09Lc# z+We|Vj|reX`@Pj=O+uXnO0s%RA02lIU|IW1t$$MzkW8Q!7UH-1d{YvTP67e!lS7-` zB=F$yNzsc5v|9R~`t`CMmBO6|@W$!oz(oRho&ANAlfXp+MBvmU_yPHmyDc)**GB*V N002ovPDHLkV1kz(xQ_q; literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_25.png b/assets/dolphin/external/L1_My_dude_128x64/frame_25.png new file mode 100644 index 0000000000000000000000000000000000000000..832c2bde9f9cda0876517a95f8d7b6f9a7350b11 GIT binary patch literal 1447 zcmV;Y1z7rtP)>{VeT7VyGKIc+FL&vU5>7JE$Zr}}0-i_LMv$kN z$~>1vA!1I8+?|+GYijN|&Vi#?e!SMe-sH|5`bhu=j4+7wc zuOQWx@61H_DP)l5aA%iy5reg5q-Qzlg?Dd0x;#C_;TD=7ZtwPPcAYN~q6!kJD)uFI zA%nIXY8B$*Mv(PGOLl;jkaj7v5xuy6c8!;xcfYE+-rDgEuY2HWRU6@2@$(${d|p@xaN$^2PK{fM+mUm(ywQKA~W9h z%*_>1^f+T!`mZ6PB;51b_joJIc?G;t?^zXmtO7J+MhrVj@^L?zjU;LmN~&E~0#@qK z{CZv2&qk2dN-v9`(y&ny?BG;uKAbP46zK8mI|X3YOD+9-1ypY-KOOznyQwdzQ#oI8 zE&kTyrXPMpz6ID3n*6T>j~Y;?YW>j2cPl_Os(%xZCcis@wPh|Bv{Ddr{tYRBcW+q( zb~>)?tI2>7T~=92umYhZCwf}|Ljg3V;D<8KdS&%ju}}rap{3mkLWlu zgwD!-)IQk)E-Lq2`_%?4$pt;G%7wHaEURXj0<(SEp; z+nW0TGo6poh#(PS6r_CYL3C9TRo=*XZ)@%Zat4^`kSJ({uT}p~&4U|QLbOw85lF9BM4Z$Q_x{l`AFcsB#-rC)fHn?G{;SAfMJ^q0b^l!oppigB zdu|mXWaYod$XY*Add)mvod!N?fL^1oLIMo0{P#H7>Ze`j#ua(KngqWTpqB`k1ha`y zA^$UEmyT-!0WG z=Xstq0i_foB9hCOQa;AKHTYa>&DG#^S-&&ZUV&rAqLqme=_K;=(o`6P$ zXLu6LJO;fgwQ6xDzcQhtCBsqjUe9nYAIj) z1Z*WDUd@l*yl*gugGd*KYZ#@c%#PtyjLq`z_ggL;%ik z*2flF!)CQ`zr6`$@pbfW?@+JNgqmek$lJNz?di_OK=fY+2io2p+2_w{6?;u8gx*~` zeO@=TRfwC7pw^3)yTJNRaCFVP@##UPZR?r_vk|mAo~GnXz>T2R*e!0dOj#Y7=Ch;8ri1y=)C>>p-L_@7pS`+iWqN6S zuFmL8dRhw&`VFN_b}=Nnl7x!gXr}<&!0vRXWlx>-*-S%ppjID zuCWqUn_e>pPoKPtddLqyBHsf10S9kcqw`zWrBc0hr03V;s}%vV(ewJ&gY{x5QVjOg z6a4w!b!{H$p-YCwo;7-(ix#FWkCtmj^jUtcVV=(gHakTi#$nBEdB4U>BxQ_XG(Gf0>~I8V zdH&2QnCE3Vrp=vQtZG{;k0$Sa>psuGGsC?a0nXp2T9#uGGm4CGjuwAb9pe>&En`Ow zFTz(OBJq2W2w=Xt7sTBN8l zLur=tS{^Kq(d+db?gY+OK4+X0FUMy;SHj|-pKDPCna|H#wHLn+8Ap%Dos`cZy)256 z;tyFna!+(V(Wg@ReMqE6k5B~I1xWpZ7#mtgMCVI|W_b8;1VDvyCurVJG{%SK3|^5I zna}G5SzBm)Wgg)OpyjD2A%ku&B3eabYrZGb86Gc>(7S*Zp-+Iule}h~^RcK5kdTkA zgDN#L|3DUd3basfg@3D{(&pB&Qu>=g^4U@OMm#$*-~1wICwL0=JVuW5XxLhxBRb#W zVOb3ziA1W`s}0BVOfRLil&-;wCKfVeGZN;zYJdnV!?^-z_(yYT^qI3TD*~7`Ko5aL z{crbXp*Q@?nqU@R-r7kM=kuz^N~o{3tnLIKj~D{BS3~B zXd!qNEN|!N5zw_K(Exh0=?WL z%Oji=^C?UOkiN|Eph{?XF4DZbL^w^!8oC6a?C)W=;4E{aUlm0^OFNMmY9R<0J$lOL zJ^`Bvk3#X0yMLOJHM{_LVbF?~hEoN0DjBd&UjY1HYoZCB1zfxT#ri3JC4m`Lv{?ef|9_B~ubilGNjASc0A6_3 z#}-_{X10*EvHl0^m)7u#ZttuD;{=#RD$9!*@AhOCE_3{^s0pfndU4ZtYWv5S|r0)bh&#$iZWqwcLePj7<6WH19t-$O=b|&zc zY9Xk1?de!e{EG1{y2E3#?*cqYAJ@*ZHy>TN6bqwRO@=IZb@#4XxHpmMJ#QhBhXA{5 z{UU`d?cI%M-21+Nb^%)U7=3-pO?sqSNBiLto~MPX2!VUv&$27{zJCX(9<`9{60oPF zYuzeUTYu$P5ijsv2$UdX;(N8Hvgq|Y1YqV!NBVmQWS5jzZ2h9|UMv+{ z>4*zxZ+yZXPlL5mRxxfvMupW|ikFUE50H&W)~i7x>n;SQ7A`3|Ypysnwq%d$7n9(H zPw)h}96(!u2K?fpO$yiWE8?Mbt7%QhqH~N|_z19k@f_MbK1gui_bs{onc=|_3#HnC zRgv8Kxc;h;?fpDsN_sTq0Q7nVw4_KPM>K(=D{6jDEu94pAc_210_EXS$|)5%%{ zL}=;!#U(-9c~t^9BgSU+m+c|EGUeL$Vtw!YCcu?tv{0QMHw zCdpm*_EXW`lYdk~+Bvm(SoCVH1I)%uL1I`v28WS3dp(eLAM38CSCa>LDtg&JCq&7r zs?poI(6+tZis69*b0LvKM@zwJHc)%w?t7k;e^9+%# zUWS+D5<;374tao8F0lgE9RRlr(%MVUHE0UL_bI%IDgL8<410jt8Eyr*_|I7(78*X% z`&|FhR@&l0vhppuK738}0NUc71gra(tk8Sp#-VbxSo|ocXR(9<_KTnsterv%XVgOQ zb?Xs7&l!`}mdcazM4Bi$on+O^1KN9P$ z&tVy7%VuOfagaEkzs(5dHn;O(}VB4L)xYQ0000n literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_28.png b/assets/dolphin/external/L1_My_dude_128x64/frame_28.png new file mode 100644 index 0000000000000000000000000000000000000000..94e05f94d9d191742662fcbf308a2eafd80f54df GIT binary patch literal 1529 zcmVoO27YwfGe>VrP3^|=~UF70==pIvy(=oBY5qI`fKMWfR3p0};W&ar2p z+yGWs^=>1m@cvUUg#je=F3@geQ=B44B}xror5Efnj3;?Nz(NMNJMOGx3uOjiEzs!V zY2Lnz1)k#l0KW_n!rhf@;i~B5$qU4RjB`p&VieOEpvpLQg#k%^sW^34{Dy!8&={WL z{Qw09@MQXb^4t(5IRFQz#Y&poMY%NgKV=61P?!W#tX`DXTDdZ`*pFl3{oOHS0H-Vj z^+P6o3UmCB;Y)yoJ^_kMtY0q{leuzHaqvhlBqG-aNuWY4grXQJ~k4S-j^ zEbLymsGQP%UVCo$oIE+WVMpJic=3*S2X|0@1!f*+_ad?zk-oi*^ow|5N74iTi}E>6 z@%|B5&P(SuR0#4GDI!26GADyPexBz2bbNq$YbF{%#S!bOMYZCfhC9Z7?I>J&FM}@w zpx^ZO8bQUjan?AQWa$)R0EjDFo1Zq9F9V33$c2X-4^)T>OOBibO1R6`4QEc1DlnQSTRx30iqHVGt!*_o9;L|Dq1`u&sy2t@koTB9!ChF+eq{_qblI+md5-@^?y@p-z9% z8|zA6?imoF^;Nwvk=jF5?VuMk4Z=Z)hjEvnRv@+D*G^}_7)QAUi&CDsAxK+^rJc)Kgc_IQ3( zNSIw~0kFU6_^1SOfwZE~>^yq_;t3SN{WdQoJ!~jzJEL72Y4>C1| z=sIYLLZzcXxqqKq~|?`k)YNAGB|0+5M8jS5=V?6s(kDJk-VWt z@d)*cpe$&1x!VXRGW0*H+}>O&%e)r-XV$;9_MHQafLifrGLwNdmX!T_iCT}6y?#7+ ztl(X>Fs_Y_&tB3?Bajwk6(ZhJMdzcrfhIrK!{~UL5n%tN48S|b3Cx6N;r#ch%BQGO fJ~bx(hyDKnt&=3EFH=)P00000NkvXXu0mjf(FWoE literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_29.png b/assets/dolphin/external/L1_My_dude_128x64/frame_29.png new file mode 100644 index 0000000000000000000000000000000000000000..1ce384b165cb3b83bcffcc872254ad52ea846971 GIT binary patch literal 1625 zcmV-f2B!ImP)zwVAn!dD4;}R$9&2aKtonwyM?V`X7_9FS&G#)|5625DX3kF(dmAy zx$tqT=Do}U{3Pt~{j>3uhO!{gVrZ6GE$~|%5I)HjRn5I63-}HA=E$F-#07lw0-&gx z?Z#{j><{8Nni zKBX)@YXw>?0B5SwZ>=r^S1Wi$1<*Q&2=g<081#gaX6J6?(f&YH^^em<;KdM;b(m6s zri>PN5!4n=* zw_hdvtoc8VfC5zduqt@Plq!o5t@;f&(H)!6@pu~wNCC7jb0X;44U`v+uc#tanC|L= zO&44R(4t@st9>5A8{aM2&(dbTY4G}IGlAARfE4w54DABSr&qn}4%{>=G*i;%Rxm>2 z;siLMZxDVLI+dZyEe!tdzu!wDGNaEgN`$}g+l1fwO#{cw2Oc!Q9JH)^YwW2~Fj@qO z_RAvjk;IN1UNZC1Od&EqWDcSNRD5l+YByza;HdAf;Fk(|CU4h}jUhf1U=W#6f{L`U zYn<7-eFmJ~4DE_q2F1s5a22E8z*S1Y{h@}T)EbSh-H-II3<#rc_wokU7A~@29TosR z614=c(d{}+lAc$(mrS1*D#)tBLp3@B&8{@C^RS9q0pu)0%>t~0mZvEJM|Q_|qI&hkwwQc8>(o@O10Zc$UoY*c zI&DKv0#S4-1L~KnLE{1qukJuc0-B2>eX{k2m1W=Kz)u7tYg3V)URrdY-Cb1c=x-om zNu>TX@0Wbvw<4o-nGA@p-MbKEEoOu82M0P$hVA zjnFiOU!zQU?MQBm)&{KpNYzuq&Hy$GM4m58$Xe$P@OlKI92Er-Zv83*T|uYXI%x8} zke$x&JA)?4J!mOUgbywFv*wglc8{+W>nOQ5(Engyt1N(L&Z9oO10A#xo-5`h z#Ws>$FZzZ&A-a$V4J&;@_=vpQopNeBU%Nk# zIY!L!?A#;$Gha=5A4r_fa%P2iV<@$~RXeWBl+dGv2q1_P~ zN1s*Dm)^AyStH4{X|cdR{~IW2iqzf(Z?U3L|F~MFkiU-n`H&R0-U*8=nL&u;@K+8$sImo3~pEqCJla|2)}gpcXZ9CcgpN?$7Q# z&oUsEqk9db!iOxt3X`}BXa*oJtQlu!K@6$j_2@s1g7~N?( zBp#wMPWI~2(fHNkEN@e3am17bm;uW84xr{A5ps0LTd@USGy3j*fBt(N{Ymqhjsa#B zfikvQ5h~1o)~rV@g(kG|3|YS_3sz5lKz1>-xTLwR>?kF3kZ(16%hZ&tIH}i-;Q0&*+^oWM>0D=8H3Nx7Mh& zM%Q(He>k;k*AB_(d`#Zw#TkH8Kn1;PW4txQbGV7*i0%=rea~FSG5Y;JHh=bF4?Y+m zTIgj8Lu7Y>I0M2Me4LkMe&X(bNKqskKe~O{crwVt1WmvGk)HBm7 zvW^1ujt&!KY6!HC)efyy{_2*MJO7={?H&_I-}xkXJ&-lX7}*}P@IEJC^=`>zL`pJ1 zM7S576^Bk)2eN986?#GBMAqV+yLe-z834UX%GJ&jW+1JD%agwMempX&>IEL%lANmX zv|36VhiIq)c2xh7cG=xUMxjV;LKI_!ncYWLCtNNf^B#@Ay873ynT1N=QHwBvwngRR zq9>c%4x+E*TKId*AxTviAl;u7-EMb zRLY1%dzN*)sL#|82rH{K0AlsE?rF3V$8P5wuoSD3A}Mz=-J8hvYmG7O+87JVkotKup-mzMghwOI~^ z=$K!n{$0*^)#m*X>@@r+6s7A*qieJ*A(AdUhOzov4jKj5ACd}3BUP}hCG&e57@2S; zvd8hIg>oP?thGn`WaNzfy!NP0BCrBdo1bORFFr8O9U^T2^jWb`1U#pX^YHpbWofbz zc#fV449UovER7w$#)qCjOTY?mN1)N2h23-1kkOgs=#malS-0gmR$-wH9*x}HsLc0I zIJ^d}o*2JNbG`Wur1IYlq^{US`&_0b+tZbmUaL~5CK*4< zTBm{QC8MW%H;rW#J~K}w&CTGXRG>kd<83wa78WhOq<#^MyAxzQ-u9G8U&%TVn-K{$ zz)DmsyyvlQT+8^pUp1sNlL)HxF~dGLALR5ZzN0&WwIv)sZL}|HK2U6Y-@z(7Y;wsPQunqZ$7RWAGEblZ(*~Xd7r94O^cKBFDOt zvv}__R$ckrq;>5EBJ=wPA?RS7Vx>1y$l1L+vA`G_?Q3(Zx+1!X9;H{;VII^Jpuuwl zPhlv{qgzI_enE^Gxgrj@8yP2n8Gy*9J4qq^K38~lvYuS6jfa_?ht?lmUljvn`-W10 zw_yGZF~G{jMvRcbu7jlZOVHFeJzfA=kw1aoW_+Sx5lCcHZsyr%&YL05m=sR@|P)++gv0`UZW&9_Ou-$h7+A|_N|MS0}#7Px@1+qnVhv)#>xxXje za)cAvU=~jszXIu90FnJ(;D5zQMxTv-qDcqn$h-tO8AuT*9e3|Wg-p=_(6@S8zY}%@ zv!`*9v9tQhB6{3z!8`|;SyTl*&0vM&dCah5t=4;(4BUgDr|4}5b9n2DIPpq7p|8-F z90WZT!CY>YLqyhdLcxbRRyGZl6oEUi(ipSpY8OkckP&_tP>Je%_JqtG#`hd_#(^Jo x00}F9!13Y}$2q`@z1aHS!7t9k>i~Zo{{UlA&@B|gyLJEo002ovPDHLkV1k+e_DcW& literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_30.png b/assets/dolphin/external/L1_My_dude_128x64/frame_30.png new file mode 100644 index 0000000000000000000000000000000000000000..8d42b8b482bade89f498e5ed1cae3a82bf89ee26 GIT binary patch literal 1575 zcmV+?2H5$DP)ZS7q4@pXh&b}8Xmfz6By2Q`mvWB6 z$=rd{R(}+ChtR2ri18ub_x*F;-?J z*?^iuOBV2L;G7Tsz8Y15aESw)5~Quboa;$7i42xh0xOiXYa6JRjkk{pYai8Y^FIi5 z02(io|9dk4?%fJ!NISqc)4#+xku5;d)h->jFaY+4 z?A4OIXkQf-K+Hawxu+c9lt>sK9aoR1qUNvFNj%`TrO5a~4seR$F{&J)qvqeiCY%h< z{9O*<5xior)&i;uNA0NjcfvbovjbF8SQWI`BjN}ZMqAC0nSV{09Dw_0jt8BE8tOaM zx7RS)BkWE`;Qngo#WP>D9OPI!SWS7Bv0-IN$FWrhTD#8*B*3{mWAH}9b#Do~148RK zt|*6pzsaG$5;`)S8WS( zobUU7J|5Yr?-6yL(lK?zViPPp7D$^#-o)ePfKB7zO`Q42v_x)CV{?_ibP z=K&Tu-T#`BaL)l)gnQ|edREOSkWL{ix1~9%onR1S$iZ49N*BN?TC|w!oW`YJsn`_q!QD$_`Ej zr5s9`*8Q|<-kr>4i7!M3z)V0nM@8APG9u0@RH|EW?J7~pJW~Eo+4;JzpF$9K)dX9B zi#6Kw4sgLAE}?exwObC9g|Clfe90+1;NGE}L91R_Xmhs9|mXhC3SO<+YVh37=s^@a_pK!LjNTzN2knIA6V)yBcaE>I@yBLa^hy=^P$ zAIgOH54Y0seKiAUbZ(ivrX;HZGnDNylEiY=u-f&;9>LvL(-xPGdD60qj3i>fiaxbi zC)<}4@RBjWykbwm&#Rq)lc)6)UA0!_b~so^&}Z$FWq{cTH2F7L1!}sm>Plk)&sKmxT-KIifNwDR1UD~k_2Mhno_mjbKF1&hb{g>NryQ`H0e%ZO z14}_4Gz3bH`IIIp7BcPN<(dK;axng-*Ox2|?&)!cm zz!c(L{gBdjLfcy@XU8iBKDS;q`IbfI1?AA*akDW%bUmQu+qQPh|cNX=F_f93$n7)VLx#NHGBC z2;M>Masmv>DIiN#(Yoh~$HVEIa$4$lh;{}z)d{54PxYTQV&;m+gP8?BgYEGLJ92bh Ze*l(B5h$^b7i0hc002ovPDHLkV1m%s`g;HX literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_31.png b/assets/dolphin/external/L1_My_dude_128x64/frame_31.png new file mode 100644 index 0000000000000000000000000000000000000000..ac926d7be3120cd6322739b62a89f67b326563c0 GIT binary patch literal 1609 zcmV-P2DbT$P)dSg`=RNpK1QE70NrC`5^|+t?gFVfT+Q#-mc$$_1FjSiRs?WTfQmAWta)ehRX? zpSxEgR~I?T2p}y$cBgW?eYF?p9!rvq$x)@puLlTXb?nbpR2)i@z;{f3yf|%+RmpLC z6;QQs+=O>j33I&bx{f1;7r!CE04e|Au1m7u5z6yCUxhRQ-hBsnG3N_g!Cs?yD**1< z3No~K0IXOgYj?Q&DuPS0c5R{(0(6xqp7B?BBFg3O_JG;(Qv^8W?Hn`){GEjq`=eu3 zbO5C{kzRxdaEjqEx`;4kQe?x`M?8v5ljM)H+dnzd@w_Tin6h59BUJ+WA}5r)v6b~-#ZpJrxyai zn<_m4^@gxBrea9fSI7QL-OfSV_1yV~wdHAjcnHl+&q4W8C zj@w$6%&>48q(n2TZv`1FGO9L6Bnf7}3G}*>li<-Y+UNJm=B`(fEQ&iT;8W3A213JE zS3@`?O81WOj{ugK9VH2+L|2CGMR%K&z(K77qL2(?t;H?RMEeb^8b6s9Zxq&-V&AF&s!sO^#DekPgvXOm&r7daPfbu^ zC|C(8l)qE~(qeiRw!3^S<$$Kkn#J&@y-yUJ{(@9VQ~g z^So@M?D`b~sDyz^AWmDvidHqm>R4?>WRBS5KzqWj>5W^c)Xx7TNbY|Zya_3l8{ucT zbI{%<4^RzQ4_AQm0;dwV+G{~rDlfMOkg5ZZVz>!{n0uLJTN0T zrr@JjG3`88+EJ6xKlM3#*)t{DboX zoPBS}_>|k2gLHuk4_w0I(Su9=q&Zd8+T8UOIf}Nquj~5%RWP^X@$V|dHFv&i2YGeq zLbdy!M{L)x*TK?`?{NQ=i}ECemIcz}K<^S=@MuyzMlZo|f(y^V-`8I~__|oi4XPB4 zz*9F%wZF$06?3-|H#3fB4Q}hs?}}TIiFPDTE5_{(S$GVKUB7)0Ld6K`d^NZvkGr=D z(wr*Dp7Czc&;sXUsp`Ic5=JqFI^P9L_G|@L+Hpqr^ccE&2a;SVH^SF65ANy%tTO%t zc3=3sS5C+Mp8UfKZGE|Q;qJBCRqX?;G(MgL{96S)SI^vc*8i5oo$LdgX#6T@**|5l zNIxPA&P7X*u9tcMZLpsL%`;d%hqkFap#cA3a$AnKb`u`>UBK=Bs=kBwH@*f97u5%b z$B6OGIe>Lyr^8wSP*sq0Klhw;o-!UhFA;;g&Xsy49w3w9o&qZVQ=S1E#<~f#lB;|D zq;X9iK$_e;!Rr309W&2+j?_3(PF0auOY;fm08_{(>~;(;oKcy#cM;+9nw)u_(kWYY zdG%&<0L$Xx>nA{qoAVwiVZ!%B7FBY?oSyhxgbZm95RFwZt33fx_ir_#w6nGASid<2 z)IGY6X%CPA+*PN+>i#oE*5u6V@W|`n1I&RUApqYC7kL%9aVeJ%|6hH? zI!n4r;PQxV9snz5nM4OT0^{F1jE_A4Ha6af(jS~hW?p{)K=@bv8-Shm00000NkvXX Hu0mjfz{LRy literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_32.png b/assets/dolphin/external/L1_My_dude_128x64/frame_32.png new file mode 100644 index 0000000000000000000000000000000000000000..35070eb6b4a23c5e6493389e66a563f9171ae144 GIT binary patch literal 1635 zcmV-p2AuhcP)<$Zr!=JTD$MedqQ_3dNi%@o2Cw&94$|7YAy8wfGLjSn_|)*{!OR@3Z%0F- zV;TH4l;;3hf=fx?j%2X&yRIvBVS1l~qgOT0|4ASKDgPLse=4R8;5UT-5q-Wp+R~kG zroojYfmFaufp>)aod(V&gU1=bs*F|Rzha@rz295^BN0Q&ak#Op`A!+YDW`KZi_Vfq z>ph^nq!UdJUb!>o8!~`X7M`NY5IRjQ5kxU7lhrfuMh2Gwcoe&0ua@MbwAvjV?y?XKCDb5-mxt?7T$dg+OftjZF`WxYWX21-55%u_}M_Nj!kzhypC_!ul{dRbaK{5g)8_&#zMxN-Q)uVr82^AI8lRwNLLUU)Q zFSDJ?L9345p4|Zn5UZYf?vaB-#z9X+My=wZ2R7A)2loN0tZ??&6Fo(X_8V35;l5=ttI5X>$b z+L^0@w2o#3;6APrur=NgtR~8g0%`t}Ri;^VyvC10iUO_(V0r$EIvEL>9)pyUzj02K z)@<0XdLIR{p08g8OCC?}vm$^M2EBWD1$OM!Rs1-<_kI664(39kbe}0y$5>Y6WmUv3f=`$;WyZQjD7Qcfl1IKYMor?E8`3FkR>P1L;(dZ%9$4QG% zCo%r50@n*bfmS7m$9sV!?%efN1$Y+!5LF zBg6B@1*U)A#lJ4{djQP}Kg|dv?~f{<&fj}Kj%DbQZjX`0hjRdHVxI!E0Zs`Okc^-?0hNqc4#-2Tr+2I^I)6IdlzW(3gqb9|u)P$}F>py8kMm_F{ga(uL$ zDkJ;X<`d2VI+1Vib_y%hM#3lJ=~@Kf@~qheF(n5;lt-VR0Bhgu?`R1VeJ7$+EeuO? z(y@p!Oh*9C2sHHXPBDaN_(vB}^K9!mm9O&{WsmA{Is(jK^s3WMNC5lU0M1M{J7#R4`-`6_5;=-tSm^8Ug5H hQ%BVP#(B)l>klc^gV)~j;w%6F002ovPDHLkV1mQPe z&+|NO0ebJPwbpR>-uuTjZ4COXH0BAQEL7IW8mncB&imdeNL0Y*d49cfdV>*JtT51406?MumB=4_~ z{Uu9|1p2NU7V^%nVH9%YgFYM zS-fTk_*Qroqj{ag64mj4jEQr4*j;S|S=T(^gjm5MnK5_t-)TjK#z3!CJE8YGM1K-H zU~Sy&{fHbKA|;hX|4|ut7*ho9KENu$GbM@kz9%P%cu{rZr=m?<1fOObjdYZPNJfNS_v(be^de5W>#dzRm#bBDbb)Mx}Wvp9Y!#dGvK;kV<78@ zf6q=ni|9u0WCu@=paPK`h|}v&2*3{s+)*0%B&xlwGKORJzZ=MuRG+j<`KBk_@!K$) z?METySllzwF(pXtcuv1>ivg-ZH=<$=$yjeQV9n^Hq&5nxbv=&M2wwQnLdyZTbFX07 z{gRp^Rq&RY-sEp3jaPL9HRi_H&oTfqffgR3f?3x+Uf}HwXzz1O;lWL8l7Xa0R}L_v z{D^?9@rEE7M+J2v`&B6VWcaZ{A|78JPsj7sNfU+#i6SF%NXehJrixnoBrNCdz5n+w zVVcL|c@+a#bRLc2E3j(p-Bp&R*PqY9n#Zr8e~zLeNug&0t#K&3WEB$Glb!tlOmOKn zdfr=Wk5!_q>R67-}$5Yk)`j;@yQn>4@U@146^^c<#;_!LTT$Q~8Zoj2DrTci# zV(?HOV3+a-kiPJGbet8>NAeHvcvde$+81p+&(Z7y>{LE3g8p^^*BV*7w<_^?d=#F< zojd+i0TJcjoD5+Sq-FoNtRqrsX;llizG()KCi~Z5F@uLWDmw+u)`D86{iejQjK`$%bQj*OXy^U!B0QK+j|n(3*Ea znwO(|`uFZ5%B;z%LCPbJF#rnYS;PuR28`z?l#dL6%0@@jesmo(>-q!Mx7!J;WBAzs O0000 zim)k8LW|__~{crvasO5}iAg2c`g)_E#-qT05tqUGGNK`mH2+ zH6|MWJwO26%4X5#%7Nkoq5w~feO2s^{avMSdli6UR7?7HC4;9aIcnbjLqGy^;dwLY zi6|?;X_nCeD*@H+TeRqr(u=&0LW>9BOd^@Sy9qOeO|3u5Q?vrm-aRG+bY-ZK@w+?` zlCDMTE-zYAfKy^1&Bp0D8j{PuI|Nq8Pbt7Dg6BXhf))F-V<0+!)=p#;Aq9v`dPl5Y zxl^Q~YRXV~pWcfAm5`1RPyplvP*~+26-8JrWHf6>(6S&UhaS2v1>lR35qNi8=D($} zD{dRv^Y27-j!OmLlV9P^jTsH}o@WE8D!AP_5}#k_UF(xDUh`TwAt6N6}p~M!CLuH7NvS+LGEpnfEHF@Gcnw zvf;A|3z;#heFZTDAhsGizYyZICcHGgeT;5JMQ)R8io1fE15}g%Q8spslTpeJWvG1M z!K)0e1fEJ~;>QOe=+TEo`_9@BpiBn)VzWNYZXJ z_;##TwN%|bN*T26W0az;tX{kR<(*(9>+A$N(d@8(PP0NEnLAzAHQv#(y$j77CqZAQe2i9OgNZ_3Rjbl0Z*M z63G=-F%Pl0-YnNbcdf6vI=}{Y9q*V&4MKmZ)Wa!2i0%rREBPWOO+e%3utgx z0bZ=?{%W_5($OYf;d6B_ibzui1#)S@#;PL!+32Kdl_KK;!aGNaJxs{8Ry2 z14z1;1=0$lO28Fbi;|d zgOos2x@)H?kA&T^+KbHEagQTy6n#7ZeNeLeDkwAb4@El~3ak?84nz~uxt@_OF1P%7 z{91VcB&2s@IzJCjJX`=3WH*Khw9 z;Pn6~STxZ|-s*mK!7B}%P6dxRyya;d&cYP9awa&FDwRPsJ+x_k@}qy#UQcTd?j!J-}+Pe+4Vg;Po6U zql$zA{^zOt`BB^pkh1=#DS>AFmCU?y&hJsdW%;2Ab4K{?9KbuV)8VZEq$uN5Wt_Mi@XckxRT4Kzjq%w&lay1v^?TA55O7oOrist0`v1b mgwH(y7dAIU>yOT(GOu6O;4lu`N0BK2000009HC`cVKj^{g#Zb zqY1MKJu5zyRp%&FlcIXLm8^bPn*% z^lz>GI}<>PSr+&T23S!O@Djm@9FC|Q>&zsIuLyt+ct*`Q&DthMpyfecKN8XbfGAx( zE3KK%v+>G)D{B6g!Q{z^9GHazz&qmI1+K#k)ppnXI}trCeU3(6150q{?DJq9C2P-W z_ci&^*}wY8Iy$aDWAfe#&J3pWZJsLG)`^_;0!yY~(-8=g{0!r$OTbJNO9vN~SUIz@ zech#0ECxVF@^%Mw9cUplG`kb{)d3PfbDmD>t}JQOAV8P40Wkn}zid$rByZ?E&hC^c z`6^PhdT10f1dq>ML0>8zA8$M>f`8@(5AG9b7lw@SIF93q7ASUY^Jd@`jnK8ZYP{NP z9rqAKP7RU6CpZVFDzdCXmbF%_{T-7jyKKXSAgMD7%i!I?p#`L;lQ-_Jir|dQYJHxP zP-);^VqqD3bq;|VDY6t~v2w?u1+^7`;`;#Fy6JU3KJ+)zwgOko(h-KK>c@g5|5+XN zS_DQFL;4vqs3E0nc;)sELC0AE-R&Uq$MX-ZqQr{}QsXP2YI*4x6W>bHKwY)X)cpFf z3$WJrt2nz7E16++O@T6>m$$tOLEe>r{{aJ1l&OZ)pXAr~5X`{9KJ&-*=`lbSvxOn# z0Ehq2m#gR)b|$x#`f8Jq-h&w+Qt_io@efzTgVvr#ej22L z64G|eGALRbK*0^}ktBdd7O4JlvH_PmwZb3`_32hI7`9-clk11sP8!vMSJ-=lNH0JDb5w%6Kt@;Z_} zuMf|!ZXKX&=4<${QqGq0A0d z0y~XRNx?HR5k{H$jr4Cp%8fL(j4bQoS%5^H-9doLkJ7i5{YPYZISP`)tk^}-eo7c1 zlblryB6B|rDNv*J01z#HW}xCe;>;()jo!h!~N!_v8#{ z&ZEhm2J3!AZ#4%%494$Y3Fz`AIZOM$A}BQGs2+Ek0jwafKq>7mu-0MEiJHBT`}8^k zi3Kvj`jG?7D0Ccq*#PO=qW>8udvd6L64OxGGvl9PfZ0HxL9jCrJo=~qRnU6m%Jri< z@i9bgxRn8@65614W9XA{e$|!g!Sx!tW$l*H=O3)jD!XUt?P34`002ovPDHLkV1hI$ B=oSC~ literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_36.png b/assets/dolphin/external/L1_My_dude_128x64/frame_36.png new file mode 100644 index 0000000000000000000000000000000000000000..d2cd0c970c61dea42452df834901ad2a0501a55c GIT binary patch literal 1656 zcmV-;28a2HP)uPiWtMMVeVe+b?pOUj<{4EYp z83`w{KsNfNyhrP^8q1QviEpIIiEiB`+1NR%^eA_Ll?L9)0;|`4EWfJHS6YGtQKey} zunVU#SJj*>b$|}+aE{sE7~?p{@S=1H`1Z-*ASIz(yCe%J4`Eh8TKlCl z4oxOTR7QmpvJMa#Aa$_wTfjL(=6%@aK~+L}U5o={Jc>KmS%J#kGHnjLS$l;n2~=`u zk=s@UU`JR1YPXDQ^PqaqzZ2fTBORbJ;j)x1S>tdrqCY6fj(s)zWgLA-KM7kkkPJ&i zbkoMgMSNt#C#qvae)&(rC>rk=%xapHCTu11oq+qgdmvo9Wxr;1y;53q_YvPoB0^mC3k+pM}p`r^jaejF@q&PeyT_pR^3?NO;+i098DVscmIwK(7KLV6p;*7an|lZNAzQv8TnPZO`Yzpb(xz;@1csv0lYhy8cS4V z{;LvB&-mvv%l|JRVkB!n)^d;QqdNLEc~zx!M(-C?WEHf?vmkpsJ7sv}S7H91;CY@> zO24l6-z!)uw0pjUABdJIFtPdube5*vJgg{(r4kqZ&7KBY?s1^Xj}C{Zl-U{a-3F(a z5bq0ccy$=YQu=lD6?IZin-@FS(9++0=EZI4N*g%c+oT?7gFRt6g6r~1NP8~Ren0;i zBqda*7`qDHhdvZ$!dJ29k#QzG?w=(vSmxpuTfT;15%-DC8w4H zz~^4rBREg7Dyw;56(Z#wM~$4bkeg>UM)y^ccn*Qe% z+x6!-Sc>=x`kx)bq;N9Bt^^AvtWg~z??su^+XoIj%C5I3@++x}tK&VHxOD=h+8_2C z$tNPqVWf`t0#`(wU0+h9cNw2ja)M$6jwR;(%E_vDj>C$*32Wqk#DDuq809IMfmk5z8&Dspmjr6y@P1S;YyX-IuUsit!fhIZ zzcGNNRPaoE1Rjr{&vr+zrbBhV+T40%4xn8tjZevn^us+HF#=~ik3L$ztCmo! z@m&m1sW=z$Rxh_cr)B@yrJxENMMw4WFu=Xq_z+MoPF_|bQkr?cPiV`X#rZj=#Lj&z z1HgfB1NRz4YtQBd99vnxs}qo?fzmozJ@FBF7Iv_9DafcK*y{{w2H+-HbBGSsn2z9C9^ktZR%iAYQHpG>9qTvyfVxNLGtB^= z38OmRxqNuQ1 zd7kG0<2a5XiPf%WWmV*$aU91OWBk>F>a!z{=>~9T;zz{bMX-fVbdHvwsX=09euAof+C}-^BuNnf+t@XMhx*>SPO$ z0C=NeJiKA{kFkIOP{!H43_RJ%7QVX`cp|QV)}2Pq*(<0Nlm#9Oyu>*8aQNAd6H0WCp!rt=9CI!3bI~ROHZORu;Q;VT zy*uC;u@eX$y>?66Qh(XD2)l;@fE%OI@$7Y(|Cai$G6HJNx7zMnO56b8gZHp{AQ9c@ zy-4zOm&`wcuC8VP@I9}E-3E*5nJwO+Gk!z`(E1!L3pD_qDRg;K(9S1S=*0 z?aTW{L45^%21gpDnar&07+HE9D+OAG?q|L1K?Z_X+=}Y`jXszu2CW1-(VU&Qt;!3$ zg4cELliiy>VcUnCv9s21{#QkJ2WKXM{{mLO+gI1(MBkkDBjs%kA1ZJLB&B8;87*^0 zFd&LS2wzbdAE|SxlT3j{O2p_NI?KNF%Nl28q2|(WM-j|QjMYL=GODv*8k4l#RmLi{i7YYE zzP#roStq@YA(^eeZ7WBl~%M@tm=`OE}ROY*d5XY{|TZ!|PN zX@33jL5Rcv()F3jckXB5(IrB@2g*WdXiMA=2B3;c3?N;f3DlNP+RjSn{P{?K+1i0; zJHBN@!(#R?Jz1Fmdg#vfZ2QdfUXoP>l4-qM?pF?QC+F{kR11ir8yHA?Yc&sb7w|^s zTlB9vMJk}I0Lso*!K=goV>~1Koehr}I?RDW*7+d@xbU5T$=*$o0`|?*)O>uAsa literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_38.png b/assets/dolphin/external/L1_My_dude_128x64/frame_38.png new file mode 100644 index 0000000000000000000000000000000000000000..70e56b168bf780745f329c7eabd85a4f48c5ae39 GIT binary patch literal 1650 zcmV-&295cNP)c;^d8YrnSe7xyUx8+fKgNH`1x3R% zt=owcj6aKV2Us!T-A-_d16H7g0XSqGW4Ey-c%mQLb;}Q9&~ZHDK9z#3q&t}OYI;4< z8OQkPkhqS^n{b;_2l!Xujs6|r7-)=7#{iTq0h$74l_SyU>gC~Emodx&RQ~@NAc+&B zpMxb^2?Lz0fGTvcSSLI(x9=eT|qT9Uxbfkd|NZge|1cU+$R7QT_lpl?d*{%uXoe z01?HmSgR#DDjdOzrc;bRt7o?ZSVz4(VC5cFjBw(qAKisyS-|B0(l2u&=u#S%MUpG( z2&WjCL-q1zIso;43#%39k&U||&HOBFr(;z7#EygN01;~09Wh=xxvd<1zk4niTEtUX zGdqEY>j>9J$6;Wrt-^EVAMvQ*??5~fZ9J;_w&yDTD^@HZxc zbUCP4#@O4yiiv{|+^ft}0??;+M{(Qg6E z9AUx_2cTJH6}oQ-Em<{3IVt)jXm-(-0t=7#$kTh{w@P8(Au2?od8Ir=|9x&Y$x z1pG|#cnujj3_1aodCU%QP9VJpXctzJBZ#{I?V{y$Cx{sBl#@OVSl3)47(L?VY$qNB zRifKzI{H7w8R*-i>oM0(oRZ}oUE$4Bz2Dv!hUW5k$5>L1>7 z8Sm){Y6RLP-R$>J|2_zkwh!Dp4W3AyfwV2MAZ5_>dG}Jlp;9I~@0;HINhSS%cJNt5 zo!~U1a?qSK(-+neSH51aanqztD(U|x;I}1$TDFhdWE>xt*g0;?Qz{U-sq4n7iz?jz zYH-^=8u>qxK#c(^ARQxDj3I41cSkeGkp0fu`*TS(cMrhX7uP?ukyOr3iV92nsy0^U zfTZ&5f--9c)*c?(aPPf#eI#RBA6G#0UJkPiA~A&r8RKW=k?JHnN&R~4c}vFCKJEaf zHaZ5>K^xk3hCQm-4fo+?6))pxc97P1+#c7{@|HY9`q&bD7Sy=d@LXFjq~uSVQ`8}{ z&d3>0d+#Z|?ccu&mLi@$S22J^=UED^LuGZWd=Uefy?KM3L02(G>wQj#aNt%5eEh_lb?#)^2& zE}r*VfA1UsH`3OcPFPBeCS_1+R7l%<#-fo`<&>O}aJ?rN@V-%YJEi_-r5b&(mV%PX?!|){I?2puCsFo{c-(BiC>hFrJRk9!Enn#_^!tCxX~93TrERj0vA|1-2}^#ku|8U4P}_}4{pfLTYtPO#b$D(HU&?P7VV wjk%QpsIo1ibb*@(m1C#Uu{^tte_hx318OBM5yM-Wwg3PC07*qoM6N<$g62{mX#fBK literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_39.png b/assets/dolphin/external/L1_My_dude_128x64/frame_39.png new file mode 100644 index 0000000000000000000000000000000000000000..450b4d4f63dbc666d19228fd3223d0ca0c621835 GIT binary patch literal 1028 zcmV+f1pE7mP){-C}4AW%O z6H`hl#u!pcVK<^e+CRn^LI{w4An=3ObTzr9um}!K%1->CHlOJNl=Rlg)~@G)oYy+Q zEGNioXoSS?kpze)

9$$O&zcY9YR~w&q?BeL2bjN@6GxES+45_>u$E0!_+J{6U}m z8bSQud&y5JndW#PWhefildzJx>i*jNwQmYJ0yK;SOLC11GlQr@!RMp< zuoI!*2F?@#b&+23PZWWh=Kvfv1m&NzIC@Avnf#Peh$-RzDtJ@`R^qvP)C5q9mGvR} z41W$Fp%hl)^SXIx)~2|sK6szKI)IjF$t@(8sLi9-J@jGL;dz_`(4?g(-NR43CGvXc z`e*e|BERVXt=Lfn-KUicB~g>NW<8AvrSKpI2}K8>jVNJBX&ig)E1yFCT52@KT4=?c z@6pydv;Lhp{2U-RsfIJ`ixVP|HgZ~}H9gq*iuK(-2WW{-I>l53^giwB=j))!=Q+7@ z08~?2PLM~8@~@6opzB>pevFPk1&oS-i=kHp=sI)WtJZ&{16W0nh0qfo>RgGBb$}ib zSnfsFwF|d70B!yX5ok}dMg(Y5Ug-dofED7hL~UM-&wm1F<|X~HlHP!t2qApUKq65&zJ^>{Wc*xHqR=*9*!C&*>^F~k`J#PqS z=J_TJXa!ybql+Xi!Z3J9;^K9HW3e?h?2ju>JJ2MdaMhsubpKWG>agbH0b8;2vA1@; z?(YKfCaVxlW>1|OQby~W-M>fwJ;1Kd$u%4aFXI2-Gu_|02jLgb=wvR!#eh%ZA`o39 zF;~$p^6-vitZ7;faB;JS@ yDz9ztS}*C(#=>ZSglUmpyZ?%1?}@Knm&PybUz7epZzaC~0000{{JuMJW)BWFJmx-?CD5Vwh3T^Zv(0J zIM4GW1IKX?5s}v9IF8SKuiX!ODaAzL<(WB#xwUgvqz zd7g9}$LAwcyLD~Qj4sENeSX*ja0#eL@75SU4sjn|M0!NG2)4fWT=^L7ej8gp`(X{f zGC-E-^$~k1ADuu3*Q>X-M;t->E|svjhh==CE06GYFxL3mIDZ{-efXz417w7I2G!bm z_p)tK{WND-l_5rWN_6fLtxI0M18Yws{l1HMX2cEN7#1q*9XJlo$fwy~Ve}82FE7H++ zd=b3+qxIFRl_&>@u2Px9?T*qNwlT5J2J@oODlL_z6m9p#0kp}^zFNwm7+uK7 zIb~`_N*|v?M@G$}D(zc(ppHEf5YgI6IhMZe7{q=Qig;0^ zSk~xhsZ?KLCxPH+~}zpD(*lAEy^k-`C1VAKgvZX(-OFS>SSlEDty=OqWp zZoe|9nlN_+^e}0cn!kcGW%yi}0e0Hza5P8o&Lnu-RXSMY>TRJ zhw-0^a2tpK-Sf^y4=Ei*hB&X@^IL5>-pE$SI!BI>IUpI`l4(bwE7LBQzjMl$cv}xN zgLn(;m68<)Mbh{?oH9!6SdL5w&@h|z_c)AY{5v9028+xJcj{x|Ya1xxEh^uNX`f!D z(PLfBS)vzOv#wG%si(F!JCusce+coEvQn(OZ>#Rw0!E zkO^Ck;Eme@#DP#J8!^_5F}HPqPp2U5%J!}To!hpkUuF@j8TyC;S35vz8`$7wgI)rZ zaRjfF+<6Yb} VUEO9qCnW#?002ovPDHLkV1gCk1=0Wj literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_40.png b/assets/dolphin/external/L1_My_dude_128x64/frame_40.png new file mode 100644 index 0000000000000000000000000000000000000000..369200345db3985d5b105b40ed3ba37e3a0ea311 GIT binary patch literal 1225 zcmV;)1UCDLP)WJa;M*fY6M zDWwomx%fMgGLX1<5L1x2cnm26iHlbOE*?V4K;q(6fQyHaGLX1<72x6_qzoi3UIn;# z2q^=Ji&p_I9zx1M;^I|+i-(Xhkhpji;Nl^q3?vQ&{dSz@a}-mM*jQx#o}W9-_h6pR zlURw>wDT+xDfn*36eJcGzn+u3pI`f}_>~HP6uEc(*I)_~8x)|P*REyYdjg-oZ|Hd* z%8b>J@$?fENwcnb{Lk{sgs%)F(B#(QdB)4RJ=6RlO?Ns^BlyZd0!=QGF3#f~?K(F$$n1A2Dkzq5_uBUbD95 zA@jdN0eBL$9gHGR-b~@5%%fEGy+kD5)lCrgO`vA2B1QV=>uBQ;AEWbE7Drk-1*oKW zGAh=Clb;D<##X8Yq5v!M8`T6;&j6AXM^1hu=;$U`X_7ZlyfW~0EdQJbgr)Sq3A7gF zNr()#wO-G9<7Tdp+(uU39<2O()>jpvI&C?t?^}yU1$9aRp6CDD7iznUZ`G&r8Bzc% z2$%EVAd%vEcPT$Fi|F-@@>{6{)zD`A_bI>{%$@Ek>g+su4oT36@7`Fe;db5@G<@+% zyNfSxCoLYW>!?*JFQxo5-VgLExJs`DjR8*-W*g_(B|K! z0FjGYL83*^ypt_%E#>R^=qW;U(YfDO>*TCcD=4JsS~3trcc7f(HH4dN2CKPuHUak= z@@rr(2yf9_Nn2rcJx`-OPydS|elePnHdHwCa3kM3x1aHD43e$er~IVg`TP4MPF zS^iqVG5AB_z_L8!y#C;ZFfpuo`*G4>~WSS^Ty0NPKAC zXX^J5QSp+DQ~<9cw62}BUS70uClo;XC88e%kSBL4KyQb0elqbD>w#Kpr^!REp{;G@ zg^!OY{;UE>zeE)K3@|Eth!R)@UhG`Vg|UOjQQ{H`v( z^w<19Kx7j{72jHK))2*M<%btf&PR*jDOQA{O25#jfZp|Ns1;_`Rx8{t|2!TlKdY5* zK*ac*nIl8I5lF3sXz#TIo(@9ewd*(?FIqo^uP>NvL3@+)t;HYB!`m}}v{JBVfY$h* n_4fbE6}k6CS(bQ^dT90sAA)%(Wh!_*00000NkvXXu0mjfk>5o{ literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_41.png b/assets/dolphin/external/L1_My_dude_128x64/frame_41.png new file mode 100644 index 0000000000000000000000000000000000000000..e0f882268275af59257326019b77b30c145070ac GIT binary patch literal 1256 zcmVP)`t=H?slbjC# zWvK#K$+nUiy>AVI8x`Qaa`6@$R@8?77ML+be*V)YkRv^{neGce2uMTLXBV zB9Wbqo1A~V0#K4iW480N=etq?C^@?zo1d=&9EcMXVC%mEP6l=&ZoT~Ac7z|^E9L*z zAdvRAl4q%1UIW~A9ITM>t`;C(16ViZCFxW|d9u#4l>&H;ZuP$fqj}73!!-bfSKeFm zoruvqj%dSw1$Z`ZA?tMXI3a7E=?Z|`-bgQx#xjkerAe z=Jyam|rt>9DPwSP6wOBEoC z#NBXO5KO57N_l=IN=cw(oQTt$pQ-@fO-B2D3Z?}CfWHRFGMXD-@d?f!&99|3KM5@5 zw^OieTaCm0IdJpe3M)@sQcSA>@S@ZxkFz;vN)Fa)gB4DuAShmP{Yf{wM%vOmC+56ok~CTadwTkJG6gZ@joA z)4AG!8W%CLwb@&s@k8(97NaNQ>3H@zfM&ebFGH4YhgI=B$&ywBNRxAmwC;PIezWtr z%%j&UEPPt}(e>0CKr(z}0m6}Vvl8^4)ls?U@K6BFXxe6GdaL%h1wGCip{%&yo0A_2 z85vKVuFZP`B&W;@f>!dqIiomaEh?>ZV@+V)Zz~8!9>45&0oX{7vAr_SjXM?GzUlo; zr$&?W@oiv5Z)90EDUpV8q7rDqyVB`g`|CMC#7K<<>v)N<6P;f%I|%T)uJKd>MrJ%` ztVYtUkd$sk5TyS)Si1go{$I3epy@#nQ2=dI*5iT0&5kd{_ReFMoCkuytpM7lytP6l z;&#WEVy_9faU+Ak^;U4yINTo-0RSK4e7ev2d4%&R$7Ti421Sj-{W*L>0FlPhffKD3NIfcj{(zL!9B)&@gMXE)cWE74?PAv3eXdYmLtGIjwYkK z2ApMI6j{7WwL?&oq{0Z_)^9>AJ1Q}KfVo=2K5+&GZe2EB?{ZQ zD|T>xoey89{hQALxQ#`FK$GtXQQX*G1&AI)-Z@(H_VTaw$LpEi3idAEQUYp36kN1N zVJ*;V-z;#7SU+ogNf~WX5IpY9UDP5bBM7*8J8C z)Q)B{0@&XN@J!xYxJc-!9i+hN$!IMYBgbLJvC7Sd?S0e$(oJq~ud&h1aGQ&Qt}`kC z>fD*mj-2_bqEiLPUMzYnNCb~KeRCt{2T-&bWAPgk^|9@s5x*So<2H%LCz({D6gy8W7w`r@E zT5Bz()Wdsn$spozAg2&BHSckpLc~da7;oDF8lrWCa|#iM!+6^caQJk9 z!#i|JH!)M2NeR@4db!U;huvbzLPhH(2k3Sfz8d9XGwv z706)-uN`S!_YM5G4j|o8vktI(CwN2$pmwzNeu%sE-)$G;5}nN5lAn%KhzKr%Xn(+t zM8_(7>h}N?qF>WyPYv01_e{YxPLhg&7*+17iq+_q`0;d>#=mHiPK{{iCEWY-HWuY& z$)d>_B3e&mG5kg3?MbJKAX-O6G5nktO@0YOMC*wxhC-Z7A#x=*MC%AIf}eu~qV8ab zXg$G2uvhY75qQmeDqpqM8udj@)Vi||i@4XH{2^20kJl$wJzJBqVqHyg8?HS3b+ zXliKeJ&iGN<1va;zm^MIoRcKqRrEvID{h>1xLiD)&?Fr~>BK9FjT)o4S?!9R0vb4P zgskgPtg$n*uhGHPX}y26j)(5Qr-0dF*mVl4g1#c@y$+A{J#|ass@`mU_NmE{$+rZ7 zV~1MbBj~G(fE&kA+&@qpoJ1MHuwv);x}@`=9qbs>#qq~&2MUs>Evk`UA8gVnXxg1A zoo@{?rn|R`>EY#&}c_Kt%3POxInT$G5--XD}t4Pwxi?V8qfNTVr^U)uR$3&dOS5=$oaVw z*`16Y(f(`WRcrP6kDvxiC9ZOE_hip__+0=zhTLCo(7cw<>~Pr|Ry}t!)Xh2mw4`B9 zV?k*1;dM#S+Pt3ob)`h{9)bW3=^_ZwjN~B*5FG$CB6$b`L&2hSTxP}Q!3@x@2+;vfr-vY-tmCj=KPS!kug?ix*F_~pao_in z)2#8|Ms>eJ2%(kqr<2YMepIWHHcPAg{HZOXmi+Yl67%s=a@V>0dghhHqrGEWlt}8^ z)Ajw-Dw#`0Ey$iE*W{u7t|*co)%-1uFNvr58{kRXk;+3-EI3O~^2K(5Ql+-qvt)-` zwr6kT{3x*|Ngld8K&x^jmF&Uf-B?R<%jcT!Tt15(K$3heD9<}PkI!SAsjqobYw_pB z!fn#h^^hu_m&hHh=Pa4aIv!0*@^bT`WzLRCe*;H-?kxgJPeujTPZ|j;p?!VsvxkA=%<9SZ*{?>D&T&>yhOV=g6zc(MLegX0=xJ)*j28#dy002ov JPDHLkV1iSbhV}pe literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_44.png b/assets/dolphin/external/L1_My_dude_128x64/frame_44.png new file mode 100644 index 0000000000000000000000000000000000000000..f425bcc179405dedfcbf095ce131b75707a636a7 GIT binary patch literal 623 zcmV-#0+9WQP)Hos!R)?YJ15L?jey!PUnW3d2QCjBTVZ%cj}7jHkcMWFgO>x-qa_c<7c zrrmkzL6SWeZc)<$ADB(l^IXO@gnbR96lhmg{`}KNnz9z4klwz4@^2SG{M{bRYfbZY9C-C?eZ? z08<2WutT!*$IDl8>F+Qm(~%xmRsIh!J7u>rGVe1Vb~B$ULNL8q%3tpNVpU*LEk6r) zW}XL4(eJ{&pJm*fOIiTAVkjkjZ~jxolH2d9A||KyVl3rjtzYe{s%B<4KE?n5002ov JPDHLkV1h`J6Q2M8 literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_45.png b/assets/dolphin/external/L1_My_dude_128x64/frame_45.png new file mode 100644 index 0000000000000000000000000000000000000000..b0ea1a7e78c0b590c493451bc16d27dfbd421928 GIT binary patch literal 556 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!3HERU8}DLQk(@Ik;M!Q+`=Ht$S`Y;1Oo%( zJx>?Mkcv5PXGZrm8wjwp-}!&;-uwtJfn#Pj-kl3l?)6d-s*)=yo9v;vw8P`WOdfW@ z01s}#fMW#$jD-vuNfsRq77QYWGA<4>3|$g@N(y`ou0S;c>oUFo?wu76 zg|E)ay31R7w|a7vg$Sp<6~mVVK5zDh?6&#L>=g>d4;X+}Sun_)3^l*K-1VbDYct0W z2KI(|U^l!-(!8>(ZsKyj3BkHTTrvsve}ei%E=zq{_E#C`xQrJJA0)x*Ds-}UKKQrm zQB<(4ifH=N=e66W1l`)E8{~EI@Xd>>k2h|WD4c)sZ}nZxGPSFR_XMS%4tRIXd{@1G zyPCDJQr8|~z0?2qr9U$M?)Ycc<|v*i`pt1HBA1+w-00nQ;o-UdIlmA0?bvZR#614) z^!1;8#baga_}U*O7HU4*Q_0t^^zfu}U4>AY`Q|CwU!T0Fy!*{=!;ed;V(CXuSw$`0 zt-rLl>~2KG`IUUupj%ioWi#iK@kh`xU5^^EHL^RJYD@<);T3K0RYV)<>vqZ literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_46.png b/assets/dolphin/external/L1_My_dude_128x64/frame_46.png new file mode 100644 index 0000000000000000000000000000000000000000..3113ff2e623dbc8f684d790420b396e3e1fd811c GIT binary patch literal 928 zcmV;R17G}!P)}cXvuQxv{iDYrc2Fmz3-sv83^Kk}L(s zc{R{tAn-^9&@$DGkSl=}04;`_3SfadNuCjJ#{_6GTvPz7WbBMP z8oMSyi{YXISS4d;+?kL}&>P2t7zn(+=I(<`%RIA2XqiW}VKoJh!)g!{17^ur#_q8nk~s zPGCO&A3;>SS@CJVmJveqDLwEc8su1!Ie|m;n^b^N?1_)&_Y_QMaYOv503kjQq3;4p zaQigqZvf~=EiX74-El0OCB;hrSouyWz-;XPf>p*S`{)&S_mzIE0!VGOzm@X?zw@mx zI(kxu$r@^Co>S<8L?8^42NDxx@4M2xq6-oe;-h&y4U-2F10-GWcqFLmLP%iW9IGLTJ9^)ozbq8^7tsZY zKp3WK#|5cCbJ0KhXflCtGvG-Cez3%``+Ask;7{>O7_ar67yzPur^Oeri<$h7|7w4UhF^2sml2^GJDY4u zt+kd?>cPK>B|{Mh|6{u!wr_@}4;}|NcpTv14lEgpICvc3;3g~?ia2;2;NT`K8H&h; z_!hZ8tRZCIXmX#1JBA>*zx_pILwp(|5!c|3JDSXlPze0oH)8Ra;N49FtWKP;La1>BDmjs(>qAm(L6zhN&gx66l01a z5)1(p2R;{B=V)J#I?7YUwazEa>$Puc2guem4l4(M`KXiVu`kX);{Zl|=MZ&O{1#gA zcZ#qTQxuWF0bs73{YCG8{X8hwbrnw>#cDo_`pTPxPreqB{li|Y`jX(wTXZZIhrRWj zXx8Gxu;ydbKQ{;?9#-^#&zm~{H`ShbxR~7!4n))moZa7wUpEK9ldZ`k6%(J784;B8=iPR1E%&q@wUcR}x zPm_f3+)zY|4{O=M&sA%!8Q{=l~I- zdp3{r?;ZkNSL2~Q7tKFaSFP_?T@Z)oe)zuC&4Ukb-lcf^6flZ*odj`2zRg&j{*}IG z9U+Pr3cLRcpfHo&_lB<4O4hMk{88TUp}-Dc)m*grjksP7)d@Kkgb|l~S=`9xC1Oa{^>U5YP_=nGpf)e8{Sgi@>j;!EvmqH4 zZ}Gz&AiMY+`O=du8HyF*+q$QT|40YO5U>_c(Q$b2_-YTdV$80iP(#j+h!}E>J{<3j z$69}W4*;8)-E4)7c0IBQtxuwbUCrjf>mYiBl`V7mv^RSq`UHXihxElf^zgU9a-~-CH;5 z>ZX#D_f6ur$bKkbowrW`J)2s#83tQkP5x}+xBjrb;}Z_Ai^f*Z#{syLjvre(!#CQ0 z;{wL6lP!Jx>n#Ajm|65uXvLT8!R?nFZ?zXR0GNmsC*bnz913mphH1B$vwFbz2SXzB Uk+^RXRR91007*qoM6N<$g2xy?&Hw-a literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_48.png b/assets/dolphin/external/L1_My_dude_128x64/frame_48.png new file mode 100644 index 0000000000000000000000000000000000000000..2734e2fcd57ef6b102da9c2a977264694246b63e GIT binary patch literal 1019 zcmVWDt>!^@==SY6v+uI=P?5h$0A%&%c7vK{+G^7KhfbovmUKNs2OGzjjAg382i^-IqbvR!$)z5w{8p+}aJUitM9m7ED2;&qY5^${xQ96Rp!zUljtpe~oNABIa4=K9YB%wMZ zf@Q23^h6Y4L5s@3wE}od@r53ikZaxX81u`S081vcR)#pH*_yNzLD)LrR~!g4wU*%c z@g|_SR>)5>pU5}?B9b$Lk2e9^1b7iWL`?v`J`*4~c!}L+>!r^|#s8=Ypb->gwZnUb z@feOcL?gJutH#&vM;Ad&Pc*;&UzFGDRlZ*P0$;DPhIPLcW@tU~UJpC8&Jt7Q#p;*38*u{_Ldao!k5luxh?n(OCB3fP03H zV5QTwex&(BOhlBq^R1PCRSZ3>n(xv1qp;??`W@iY%$Lt|Qh4z_UZckA{Z`|!ynlpU zC%{Vb(dO%pX_+AR9sxR@C|>@PzzpJBMbI*I1ik(4kSEsk9nW1Rz(^6Sz!C>KpQHIA z3BJAqTi43D8X5A?<5Ux1r;b^y=+(#+e=8qvzL1PGUy9>ocoo$Q&+OxA{!Sm{zO4UU z3no($>?j6H@$`_XiF!pV@4Nkrpok!55OEG0p26f9e;7pc^IO2L7lX~+T?|&#CXz;m zysR|mTivInx0He3d#~=J7`4!G zd*zLYa{uq(OvQkXZ)4utoqiR3*5usLWX6migV%FO$et|gLhF~Tu_He(u7Vnf#=aP~ pp1*pZH+vyUZ;cr<@y_}o@ef@Xp~TjZ6$$_V002ovPDHLkV1g9->bC#@ literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_5.png b/assets/dolphin/external/L1_My_dude_128x64/frame_5.png new file mode 100644 index 0000000000000000000000000000000000000000..df225594910480d7e00543e706d7286736ca814a GIT binary patch literal 1648 zcmV-$29NoPP)6Sc0H6Wfy>~>Boek)iFZRUQT7%Xa z9LI5eD78yv2d8v8ChhZL54ewj3VN5ucw>m);RN74x_hwnoGI}b{e2&s*1cGRF9wJP zdYQn`n_X0Z8r91(cbxqX&P%y6$_!k6_jo!toj(g2&*0A+kKAzpfOZuicQlw_G=}gf zX@o)kYRXFY^~|2_787vKR0vMV)N=vg=E3+Gdo#^oxbdr*<|$Aa5t0lLnH;B;74b!7 zhC+=M;|UC5-Md(OlV$*K$!#vzZbXS(cEQcZJ@>xUGgih6k^2(bmdZ=pN_%?kJ^aT2 zE295M+iH16tMSkrb4@+0;CiW<%CEmP24! z-Qxmb0LinY(h@Ms6q$Y_$A|^ZSS0x|q8ZTW+BE&(zrPqj@^o)Iym&7Ycs9TT>D>0j zAeLO5Jlxrf=f_#g2-|s?N(1hHGYk+IAX|DDp`BG;1DMGI*17Lpk9U8hu`}z5%qcQJ z)bqVD0e2Qg&QxvDcs}ZtxRl;gdAU9vbUpYz*UoFubPe8qo_elKF#ui|U8JX9b|D(F zQL_h}?3Tx8=Fq%8!yq134l@A2ckYZQqURp1*OZJ|A^MTVqh6IM=~$XUa4~_V0I#Rh z{fopeTALdK(8bOw>7r(UDoNU8?ktzubwuJ5$(y-xqI;Q{o3=Z-hBK8<8AAF*!1b5b zgB8HNr_YwhOC>dSDhub)T>L;wZ7p;S8UtSS5MThhunH!SEHq*Sl80p>G1Y9xsAN(1 zSb%;M>Qz>S;MM|0U{Rl^e-%6q)9dj3RYoU`ammwKYn=CM0!NihH-uZL_Ab)iVipY< z&$7nz>`4TgLvnNXzj0q&e(1pT?BEvbIsYma$kj#KdqMka@>>S%>Br6O9T&^WDOs9J zVuuf|v?kOhsI+$PIVZJ`ATm!iGJ7Vmon#EwT&K1H{W(H)Rh!tF?^`Xr37+=2AMKlw zv69|LAjK2-nUnRTFSPT#Qo&WAa(d6^s(B?Nu;iHGG@N|&9i8jcI`sD%vJ3c?F>#x+ zix)@19hK3woKM&QPiEm+!>seZat~KB0suJzq87#FnjS$Igz1AsPS&ZDX}qV)nv0w7rzV8pnW-{eX;_2uXQy1X}PKMt>)5SXFT8iS{$f^de$_(Q&sl z005otr1MWoA*(Wsio1o8%tPuw`v|N;hygqcjs`*%Y2Qej-Y$a~7h78!z}3m1UD{q1 zAepvV{UV!KouZ8>aJ2!1?g2V9Hpm7*5kt_9l3(5f;Q60|lmP(9k*~L2LiE^>BJyA0 zm&(sFM<@vF6R`t1qVfL&W-B?P$dR=3#sJ#nR`hNKiBE#Ikrgq=PWbwlK^7wC|Bi+* zBQvSW_g8yAz(5d)C-nq^yLiYh5&y^~R3*%R8rJKydv}i^?8pYA@LX5VRPdjh%zzL}Zf?EAk;0XeMo$_^z#vfN2Xj!6Ezv}8YiqYG+sihK6XeUDP9Bkw zT5BNSx-I|!;JRGb^?t7PdvG=`$pEl|wP%s$=`Ql-i}XgHt-4la6_C2HYW_g5IS$o*ZHyZUEk+y9Z03GcBH@KkswX?;fnd7Xw5S zy-Z^0tu87+jp|{UPu%?%&P%yA$_(81-Q(%nbp0%7K7)UreB=`s0BBbM@<4+LMstWP z6L`n{)smGO|DBEP787uvsSuVY(keo$Drg16&0ozlKLsiyLXrU@i{rA=T8rif8k1C1 z57byOegZ>S_b%3%ry0Q8a))d6*9->FCshxT&wV`gj8pRk%7Rp0+E-Hk`^@1#1FXpY zt&MrFo+EuT>vDYn<}re|Qi;f_&4Y1c<r@ zIUJVNYph=kAbGmfS^|2lHtNxpEZ~7=EFQ&lWGj?WMwN20F9wi2-P;du+QS4hl;+I= ztQLcl(ehYI$Ju>)nMwm5|6v#)FhI7AY(m>yhBdrnJ+Qo6W6F-m`ABnT_7hoCWPqsW zM{=YFJ>z~i*Kwxut=L)# z$@p+9nDwse*gdwVpNitH-h-b5< zb#@wCx#j}&N1NvDLd*i|M?MLGuzW zTzO>geO~xWYe8*+Dr?u~&^9&#F4k-ERUva`oUwD1?_KNGET?~tP+i3VadOO33f+HX zu4;N8ffkxH!+6mLT0EZ>vpIOz=`uybfG3l-4)xg9xh?#?7C)2Jbip3O}si6&oBWXFwc)KlrK!ivxr$>&T4m=WJbjlf%- z(7rnl{?r`d&Ir8P`!RaS*OjX&pN@O*4YLgNU`IyZ4MDq=#C>PV;Z2-p*ZlOE)EC25 z23nUM9(XQBs<2A=p7l?Mm;+SCtyK)Msx0+DdT((WzOI5Rp}mx#7%j=TmmwvF~-eV*M?*{Gb}^I3i|1x^N#D3*Gix2iA&3(O&TnphzYRw z0Nw+Y&1wf$kr#Ng{fsibh!|jW-XjeFK&LzIK>Bm;4xz#bB$+rlG>lXp()igSunHjt z@N8Hz1a007JO<=7vJqv?nDbZzcn>mYm-bf$NS1BZxX2+^Ctf28Tx|fUiy(~+vI$Vc z5VTOT^Bw@NzZzM?N#6uo7cbe1nP}LMGV&eRsr)S52H;V&cE#&OW-}|5e!}HVCENxO zQS?qPtbnHEikzboBXR07*qoM6N<$f{6X*ApigX literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_My_dude_128x64/frame_7.png b/assets/dolphin/external/L1_My_dude_128x64/frame_7.png new file mode 100644 index 0000000000000000000000000000000000000000..9703809405f7a9cb8e800272d21c3cdb499ede15 GIT binary patch literal 1063 zcmV+?1laqDP)uB2+J9c7@?9a1xv zmeyJ;rL>FRi6sMxi~q2{c3U??(id+BxOh9j#Rx1JNL;)f;9?M#3?wez4sbCDO9m1b zZwE++_=x6Xm}fkRY&d%Df$r;iCg&-l);tkK;9TtSBr;-;+X21|sRGEr%P`+~5*ZN) z^nb4_CFdzdR0o)yTVfCAeB(vWf};EpLs zBtWX5qdS08-tppRLLf{EKIWK$L;}PG5Xr-Ny?F7X5u0ye0-S&JxpdvpA>wB(?ux8R z5{f2Snh)2oMy{SE!w$@VJ)-9Cuif*{AWkGw21FDeW2c(%D^{XLiMhkGM|Qp@n1Vzw z_J~|Rs`%>fNvXA#PsH7*wU+Ws{^h*C=gA*(ao4f6)}l?cHXEAW=YwWb1%bzNctq>7 zgXuefh3VLQIF4(sWZldi;E};(N))ch62!*WTK^ua>oHI1_*HRR>Np$s$YeHU`iaOm zpz)&u^UNP};hMHH{}5aAzXw=_R`S?*TvW60(xG$V=w!je{T|>G%=ah)X}(s);BpT@ z83D~;x2wYt^TxRMB&t)g57+aHn4-lQaG%V&DMTSkW-2pgB>@1S07*2xIJxYlw z0*dRZ1Ga{q0yyM%lU$M7MTs%osI|V#iO*-@Z93kR9XZ#%bpWk)<1Nl;EpBKPP}Utk z#nwLOSHY5E^NNVPah&K@%kvKj;$$=y*Amk^qKp1iC;0xOn+XT)P9`ZH3Qu+fwKFUt z(nKwt;QPnF3B-}1(ycp$waM0c!aSbtm;8U^JVmX;g5M}SbV>iupiCX$gaCcxG5PErrn`)3zYxIjklC-7jMTWSrZw&8*O=qXLN3 z>vgW#1mG)FWMEOpAaot@ zD~=2^xt8Gg^G(R&ULilpd;sMHh)B)~KHh}fCdd~tL(~Mo>oWm@gQxH|n=gKLR{W2e z031O51mo|BLo|z1r8kFW|M5Ikfvp7{T?>*Jkk4 zmzkGeIxH)SBeSw;XK_tCD?1L#9(nyU0Y0(QIrA>2+9dGMN%dsrTQvbZDpJdIagCDY zp_A&d+E4oa?FnFAfxWJ@+K=j$cE5$5UjC|lr`VbRno2{)rQK(=FJDx%W_jtg-j`zK z`Q-^9sW8uu;^3dBmKdEU)h+q#_nHWAFZ1zzJ=O%p^-x_i!!)4h@bj|F@97zR49@m> zXMJW_nLe600AN-KR}(Iy^J!i*`lb`0g85gbkCJRz2rHe~GsnyP-AOS!claGZYQ9y` zX!gN?XNImo(&=1(ruj<@08qK}wUvKW3^Pd0x9I#;X!G6u4)AH_)8{cMxbQVxtH$&F zq;Y88zrv;yK$84y^LfXNOrU$OAUmEY7XL|L1@WUI7#X^P*?xD(6KeX7=Pnaqr3fU@ z#F3rP)qDX3Uf+SWOL8tpg*?o-)CBOHtzJR;HxI*jwT~^{8+r+OG5QzX;-#>${Zf~d0`dw u0I>GOaP<7u`>fdtQF?of*ok-74~l=LoVlqksCsn(0000+eVe-j}>5(obaJkEFX^| zBO^!nlba55fwjXrsR-mCf@Vk!%jb0bRNd!PFKK+?>9+vU0|8L;BF3`l5X~!SQ^SUm8H!-F>&>U9$ z_n!aKCX*&rLT~Y@X~rob*9aI#{EwVJy*@akChecY(lK&9&Uf^BDc*YGQd^F1S!8s~ zuXl-yubsv24ImNB3+eHs`lyL+fMw?!AUB1(YygQSzHI<%5k%6$QUh4#AsrX{?83xY z1aU0!SL+6VzXo_ZnVfM`xcdee#TS6=bGWoW4&j~s2V0+W#y$I&{At$V5m)u^09q3( z;g=rL{&&PHrIe&PS#l!iw9fjiO?mCJk^E-!&F9wQmTZM*j4$uCpNrv0T=C11he}>g9(H+bTaPDgQ5EbmFCoqT;8NZY0*GOJW#W&9D-ux5;|Y?7x9E(WT>1 z@wq1JF^#(M`<#n5@3p#2HUKAtmiSzp8S$m_!{l3v-`W@=_W+|4uPHu9_Kf(NO@Q;$ z=D&$4eLn@XY*l>AbtlmPT4HJW9mU%Qz{IuIM{C`9iZ3C$hDa^HtMP`fryD@3I4|*g zHu zaOQez+g1D$&tl&Q(n>n=M%YRG;?Sn_z6X#fikhUTQJY~m@hQG=aOp{uSXZNd=ye!1 zOlmDl`5V=%_>CaRj`k?dYcohsyhNOuu3b+7vq5_%?@8iki#`-M&)ZW#ZB0$DnF40N zEB>R2pX;ORolZPH&l+<+pAAr&boyR$GdywqXD+aLO?L15uU`T9!^onyY*qZ87^Qg8 w@s>M~2B1XDY=V*>&!$+lS~GczIjRS?fA`L=O_`&tlmGw#07*qoM6N<$f)%(2G5`Po literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L1_My_dude_128x64/meta.txt b/assets/dolphin/external/L1_My_dude_128x64/meta.txt new file mode 100644 index 000000000000..8c326cf42ded --- /dev/null +++ b/assets/dolphin/external/L1_My_dude_128x64/meta.txt @@ -0,0 +1,32 @@ +Filetype: Flipper Animation +Version: 1 + +Width: 128 +Height: 64 +Passive frames: 19 +Active frames: 51 +Frames order: 0 1 2 3 4 5 6 0 1 2 7 8 9 10 11 12 7 8 9 13 14 15 14 13 14 15 7 8 9 16 17 18 13 14 19 20 21 22 23 24 21 25 26 27 28 29 30 31 32 33 32 34 35 36 35 34 37 38 39 40 41 42 43 44 45 46 17 47 48 7 +Active cycles: 1 +Frame rate: 2 +Duration: 3600 +Active cooldown: 7 + +Bubble slots: 1 + +Slot: 0 +X: 41 +Y: 43 +Text: My dude +AlignH: Right +AlignV: Top +StartFrame: 50 +EndFrame: 50 + +Slot: 0 +X: 59 +Y: 43 +Text: My dude +AlignH: Left +AlignV: Top +StartFrame: 54 +EndFrame: 54 \ No newline at end of file diff --git a/assets/dolphin/external/manifest.txt b/assets/dolphin/external/manifest.txt index 55abe0ce8d2f..4e3dbbf1105a 100644 --- a/assets/dolphin/external/manifest.txt +++ b/assets/dolphin/external/manifest.txt @@ -97,6 +97,13 @@ Min butthurt: 0 Max butthurt: 10 Min level: 1 Max level: 3 +Weight: 3 + +Name: L1_My_dude_128x64 +Min butthurt: 0 +Max butthurt: 8 +Min level: 1 +Max level: 3 Weight: 4 Name: L2_Wake_up_128x64 diff --git a/assets/icons/About/Certification2_46x33.png b/assets/icons/About/Certification2_46x33.png new file mode 100644 index 0000000000000000000000000000000000000000..d421b829149518d4d379b03d76881f88706c3e87 GIT binary patch literal 229 zcmeAS@N?(olHy`uVBq!ia0vp^dO)nm!3-oP8fIPqQfvV}A+G=b{|7Qd4_&SUQnNf= z978H@t(g+YcR+!|`Qg9maYoZ4y+u8qcz^6{V@k`gJEQe1Lp5T}_AiC!OOBS>-1;=T zdEV~dE9_2v2<2Pid?=n_o3MCO-A5)qmHYo@Jp3jwB`^7eym+fxoxz8QtS6Qam1Y|! zr_NbyeOvU-CA$l&z7_nH6v>?!`zVuf^AS(s0M|6%%_#=?UdNv8|9>xd*oX c{KsLyP+HH}pmOhIG0>F^p00i_>zopr08YJL$p8QV literal 0 HcmV?d00001 diff --git a/assets/icons/About/Certification2_98x33.png b/assets/icons/About/Certification2_98x33.png deleted file mode 100644 index 49c5581c7523f2956fda218cfa9c048cf1998ef5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2495 zcma)7eN+=y77u<<3c9DF1uNPeM(e@FB$G)pm^lQ^7bZ%SFD0_A?JzSTQ=2gmAE?2J5Xf$#Jm7}N>SV;K-w?O!$Zhp2HA`rt! z^CZW31cr4(VoV~3%@edR3~*>DxWL$h(cSz|`k)YU5s@oohAdtmS;=X1IVKB& zqBJTjL8>BEv@}7fQb}`&1X4@KnY}J8eb=iatwkMFfl-d12T>@5bno-1ON*3OAxXc45=JzXPf}z(--R@i^+f~G#HRartn{9 zC=nD?EHTY7`81Wxv96&@EbdZc6dq01V>(oA9H|_tQ5Z~mjmfCeAc)cEPZtaU(VrQk z@Qh6jz1=tLu zJZl%c1V`&~K{tW+w%ZwSX$k@z4k=^`M5cb+!|R|yv?n)pfGm_K7suc*wM2O!{ZZrt z2BYRC$RV%?<}n!T@{!3779-yV+6_Jk9GLu$M_VRIBq4#Ys@tw&4`C)Q2QeoB`% z;R2c+T{rKuis}uK1x3ovo!8E3&XtEOMfUFLuh*G#YqJ|~=g)sLYSxvk8MnTAcT-_a zRrQuXHEce3zkkuD=YD?Cez?2yQQb{PO4jauX+C{g-JxHO)v(&?9iPYl;K zQ+uu=1A`}ytX)t2)%N4fq6g7U|GpJ+`*$6DQQzy%>HnF!|MjBk6wMp`VP}#|=eMdm zW3QfQ`>Fnr>3$m*gYUXj6D2d({q%uv=0DHxeqn;^#P`QCdsZlt|Kz*M(FaSqs1W=`??1& zmu);-rqAdrXl!qP@Amc04|ly*cW>N{o)ezkOw!CMw0~c7JgrCTE_TGn_kGyfyFIkh zN#D5^8MP#9>7H`slqp|$)3@RG|5#JS__|645+%zr&Nt17(2jq9#}(&|`Q+8^`n?~0 z>@Me84b^>LJiulR#vGSU&zMFYh&<@t&o@UsZ*7VWU0r$M>~p*=35~jvbf>iXyS?9? zI`B}p9$wS&A^Ob53ER%Rx_JE!y0K+qVT9V(d#|-6tWBNFpAzLv$@yYa_ZoN#+Nq#Kx~p6 zI1|4u?Z2nG3f~<#*7fmn + +const BQ27220DMGaugingConfig furi_hal_power_gauge_data_memory_gauging_config = { + .CCT = 1, + .CSYNC = 0, + .EDV_CMP = 0, + .SC = 1, + .FIXED_EDV0 = 1, + .FCC_LIM = 1, + .FC_FOR_VDQ = 1, + .IGNORE_SD = 1, + .SME0 = 0, +}; + +const BQ27220DMData furi_hal_power_gauge_data_memory[] = { + { + .address = BQ27220DMAddressGasGaugingCEDVProfile1GaugingConfig, + .type = BQ27220DMTypePtr16, + .value.u32 = (uint32_t)&furi_hal_power_gauge_data_memory_gauging_config, + }, + { + .address = BQ27220DMAddressGasGaugingCEDVProfile1FullChargeCapacity, + .type = BQ27220DMTypeU16, + .value.u16 = 1300, + }, + { + .address = BQ27220DMAddressGasGaugingCEDVProfile1DesignCapacity, + .type = BQ27220DMTypeU16, + .value.u16 = 1300, + }, + { + .address = BQ27220DMAddressGasGaugingCEDVProfile1EMF, + .type = BQ27220DMTypeU16, + .value.u16 = 3679, + }, + { + .address = BQ27220DMAddressGasGaugingCEDVProfile1C0, + .type = BQ27220DMTypeU16, + .value.u16 = 430, + }, + { + .address = BQ27220DMAddressGasGaugingCEDVProfile1R0, + .type = BQ27220DMTypeU16, + .value.u16 = 334, + }, + { + .address = BQ27220DMAddressGasGaugingCEDVProfile1T0, + .type = BQ27220DMTypeU16, + .value.u16 = 4626, + }, + { + .address = BQ27220DMAddressGasGaugingCEDVProfile1R1, + .type = BQ27220DMTypeU16, + .value.u16 = 408, + }, + { + .address = BQ27220DMAddressGasGaugingCEDVProfile1TC, + .type = BQ27220DMTypeU8, + .value.u8 = 11, + }, + { + .address = BQ27220DMAddressGasGaugingCEDVProfile1C1, + .type = BQ27220DMTypeU8, + .value.u8 = 0, + }, + { + .address = BQ27220DMAddressGasGaugingCEDVProfile1StartDOD0, + .type = BQ27220DMTypeU16, + .value.u16 = 4044, + }, + { + .address = BQ27220DMAddressGasGaugingCEDVProfile1StartDOD10, + .type = BQ27220DMTypeU16, + .value.u16 = 3905, + }, + { + .address = BQ27220DMAddressGasGaugingCEDVProfile1StartDOD20, + .type = BQ27220DMTypeU16, + .value.u16 = 3807, + }, + { + .address = BQ27220DMAddressGasGaugingCEDVProfile1StartDOD30, + .type = BQ27220DMTypeU16, + .value.u16 = 3718, + }, + { + .address = BQ27220DMAddressGasGaugingCEDVProfile1StartDOD40, + .type = BQ27220DMTypeU16, + .value.u16 = 3642, + }, + { + .address = BQ27220DMAddressGasGaugingCEDVProfile1StartDOD50, + .type = BQ27220DMTypeU16, + .value.u16 = 3585, + }, + { + .address = BQ27220DMAddressGasGaugingCEDVProfile1StartDOD60, + .type = BQ27220DMTypeU16, + .value.u16 = 3546, + }, + { + .address = BQ27220DMAddressGasGaugingCEDVProfile1StartDOD70, + .type = BQ27220DMTypeU16, + .value.u16 = 3514, + }, + { + .address = BQ27220DMAddressGasGaugingCEDVProfile1StartDOD80, + .type = BQ27220DMTypeU16, + .value.u16 = 3477, + }, + { + .address = BQ27220DMAddressGasGaugingCEDVProfile1StartDOD90, + .type = BQ27220DMTypeU16, + .value.u16 = 3411, + }, + { + .address = BQ27220DMAddressGasGaugingCEDVProfile1StartDOD100, + .type = BQ27220DMTypeU16, + .value.u16 = 3299, + }, + { + .address = BQ27220DMAddressGasGaugingCEDVProfile1EDV0, + .type = BQ27220DMTypeU16, + .value.u16 = 3300, + }, + { + .address = BQ27220DMAddressGasGaugingCEDVProfile1EDV1, + .type = BQ27220DMTypeU16, + .value.u16 = 3321, + }, + { + .address = BQ27220DMAddressGasGaugingCEDVProfile1EDV2, + .type = BQ27220DMTypeU16, + .value.u16 = 3355, + }, + { + .address = BQ27220DMAddressCalibrationCurrentDeadband, + .type = BQ27220DMTypeU8, + .value.u8 = 1, + }, + { + .address = BQ27220DMAddressConfigurationPowerSleepCurrent, + .type = BQ27220DMTypeI16, + .value.i16 = 1, + }, + { + .type = BQ27220DMTypeEnd, + }, +}; diff --git a/firmware/targets/f18/furi_hal/furi_hal_version_device.c b/firmware/targets/f18/furi_hal/furi_hal_version_device.c index 1b5090b930a8..e038b98d7376 100644 --- a/firmware/targets/f18/furi_hal/furi_hal_version_device.c +++ b/firmware/targets/f18/furi_hal/furi_hal_version_device.c @@ -5,17 +5,21 @@ bool furi_hal_version_do_i_belong_here() { } const char* furi_hal_version_get_model_name() { - return "Komi"; + return "Flipper Nano"; } const char* furi_hal_version_get_model_code() { - return "N/A"; + return "FN.1"; } const char* furi_hal_version_get_fcc_id() { - return "N/A"; + return "Pending"; } const char* furi_hal_version_get_ic_id() { - return "N/A"; + return "Pending"; +} + +const char* furi_hal_version_get_mic_id() { + return "Pending"; } diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index ad0f16aaac31..5f8b00464275 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,+,35.2,, +Version,+,35.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -49,7 +49,6 @@ Header,+,firmware/targets/f7/furi_hal/furi_hal_idle_timer.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_interrupt.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_nfc.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_os.h,, -Header,-,firmware/targets/f7/furi_hal/furi_hal_power_calibration.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_pwm.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_resources.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_rfid.h,, @@ -60,6 +59,7 @@ Header,+,firmware/targets/f7/furi_hal/furi_hal_target_hw.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_uart.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_usb_cdc.h,, Header,+,firmware/targets/f7/platform_specific/intrinsic_export.h,, +Header,+,firmware/targets/f7/platform_specific/math_wrapper.h,, Header,+,firmware/targets/furi_hal_include/f_hal_nfc.h,, Header,+,firmware/targets/furi_hal_include/furi_hal.h,, Header,+,firmware/targets/furi_hal_include/furi_hal_bt.h,, @@ -87,6 +87,7 @@ Header,+,firmware/targets/furi_hal_include/furi_hal_usb_hid_u2f.h,, Header,+,firmware/targets/furi_hal_include/furi_hal_version.h,, Header,+,firmware/targets/furi_hal_include/furi_hal_vibro.h,, Header,+,lib/digital_signal/digital_signal.h,, +Header,+,lib/drivers/cc1101_regs.h,, Header,+,lib/flipper_application/api_hashtable/api_hashtable.h,, Header,+,lib/flipper_application/api_hashtable/compilesort.hpp,, Header,+,lib/flipper_application/flipper_application.h,, @@ -211,6 +212,7 @@ Header,+,lib/subghz/blocks/encoder.h,, Header,+,lib/subghz/blocks/generic.h,, Header,+,lib/subghz/blocks/math.h,, Header,+,lib/subghz/devices/cc1101_configs.h,, +Header,+,lib/subghz/devices/cc1101_int/cc1101_int_interconnect.h,, Header,+,lib/subghz/environment.h,, Header,+,lib/subghz/protocols/raw.h,, Header,+,lib/subghz/receiver.h,, @@ -578,34 +580,34 @@ Function,-,atoll,long long,const char* Function,-,basename,char*,const char* Function,-,bcmp,int,"const void*, const void*, size_t" Function,-,bcopy,void,"const void*, void*, size_t" -Function,-,bit_buffer_alloc,BitBuffer*,size_t -Function,-,bit_buffer_append,void,"BitBuffer*, const BitBuffer*" +Function,+,bit_buffer_alloc,BitBuffer*,size_t +Function,+,bit_buffer_append,void,"BitBuffer*, const BitBuffer*" Function,+,bit_buffer_append_byte,void,"BitBuffer*, uint8_t" -Function,-,bit_buffer_append_bytes,void,"BitBuffer*, const uint8_t*, size_t" -Function,-,bit_buffer_append_right,void,"BitBuffer*, const BitBuffer*, size_t" -Function,-,bit_buffer_copy,void,"BitBuffer*, const BitBuffer*" -Function,-,bit_buffer_copy_bits,void,"BitBuffer*, const uint8_t*, size_t" -Function,-,bit_buffer_copy_bytes,void,"BitBuffer*, const uint8_t*, size_t" -Function,-,bit_buffer_copy_bytes_with_parity,void,"BitBuffer*, const uint8_t*, size_t" -Function,-,bit_buffer_copy_left,void,"BitBuffer*, const BitBuffer*, size_t" -Function,-,bit_buffer_copy_right,void,"BitBuffer*, const BitBuffer*, size_t" -Function,-,bit_buffer_free,void,BitBuffer* -Function,-,bit_buffer_get_byte,uint8_t,"const BitBuffer*, size_t" -Function,-,bit_buffer_get_capacity_bytes,size_t,const BitBuffer* -Function,-,bit_buffer_get_data,const uint8_t*,const BitBuffer* -Function,-,bit_buffer_get_parity,const _Bool*,const BitBuffer* -Function,-,bit_buffer_get_size,size_t,const BitBuffer* -Function,-,bit_buffer_get_size_bytes,size_t,const BitBuffer* -Function,-,bit_buffer_has_partial_byte,_Bool,const BitBuffer* -Function,-,bit_buffer_reset,void,BitBuffer* -Function,-,bit_buffer_set_byte,void,"BitBuffer*, size_t, uint8_t" -Function,-,bit_buffer_set_byte_with_parity,void,"BitBuffer*, size_t, uint8_t, _Bool" -Function,-,bit_buffer_set_size,void,"BitBuffer*, size_t" -Function,-,bit_buffer_set_size_bytes,void,"BitBuffer*, size_t" -Function,-,bit_buffer_starts_with_byte,_Bool,"const BitBuffer*, uint8_t" -Function,-,bit_buffer_write_bytes,void,"const BitBuffer*, void*, size_t" +Function,+,bit_buffer_append_bytes,void,"BitBuffer*, const uint8_t*, size_t" +Function,+,bit_buffer_append_right,void,"BitBuffer*, const BitBuffer*, size_t" +Function,+,bit_buffer_copy,void,"BitBuffer*, const BitBuffer*" +Function,+,bit_buffer_copy_bits,void,"BitBuffer*, const uint8_t*, size_t" +Function,+,bit_buffer_copy_bytes,void,"BitBuffer*, const uint8_t*, size_t" +Function,+,bit_buffer_copy_bytes_with_parity,void,"BitBuffer*, const uint8_t*, size_t" +Function,+,bit_buffer_copy_left,void,"BitBuffer*, const BitBuffer*, size_t" +Function,+,bit_buffer_copy_right,void,"BitBuffer*, const BitBuffer*, size_t" +Function,+,bit_buffer_free,void,BitBuffer* +Function,+,bit_buffer_get_byte,uint8_t,"const BitBuffer*, size_t" +Function,+,bit_buffer_get_capacity_bytes,size_t,const BitBuffer* +Function,+,bit_buffer_get_data,const uint8_t*,const BitBuffer* +Function,+,bit_buffer_get_parity,const _Bool*,const BitBuffer* +Function,+,bit_buffer_get_size,size_t,const BitBuffer* +Function,+,bit_buffer_get_size_bytes,size_t,const BitBuffer* +Function,+,bit_buffer_has_partial_byte,_Bool,const BitBuffer* +Function,+,bit_buffer_reset,void,BitBuffer* +Function,+,bit_buffer_set_byte,void,"BitBuffer*, size_t, uint8_t" +Function,+,bit_buffer_set_byte_with_parity,void,"BitBuffer*, size_t, uint8_t, _Bool" +Function,+,bit_buffer_set_size,void,"BitBuffer*, size_t" +Function,+,bit_buffer_set_size_bytes,void,"BitBuffer*, size_t" +Function,+,bit_buffer_starts_with_byte,_Bool,"const BitBuffer*, uint8_t" +Function,+,bit_buffer_write_bytes,void,"const BitBuffer*, void*, size_t" Function,+,bit_buffer_write_bytes_mid,void,"const BitBuffer*, void*, size_t, size_t" -Function,-,bit_buffer_write_bytes_with_parity,void,"const BitBuffer*, void*, size_t, size_t*" +Function,+,bit_buffer_write_bytes_with_parity,void,"const BitBuffer*, void*, size_t, size_t*" Function,+,bit_lib_add_parity,size_t,"const uint8_t*, size_t, uint8_t*, size_t, uint8_t, uint8_t, BitLibParity" Function,+,bit_lib_copy_bits,void,"uint8_t*, size_t, size_t, const uint8_t*, size_t" Function,+,bit_lib_crc16,uint16_t,"const uint8_t*, size_t, uint16_t, uint16_t, _Bool, _Bool, uint16_t" @@ -1314,12 +1316,13 @@ Function,+,furi_hal_nfc_tx_rx_full,_Bool,FuriHalNfcTxRxContext* Function,-,furi_hal_nfca_set_col_res_data,FHalNfcError,"uint8_t*, uint8_t, uint8_t*, uint8_t" Function,-,furi_hal_os_init,void, Function,+,furi_hal_os_tick,void, +Function,+,furi_hal_power_check_otg_fault,_Bool, Function,+,furi_hal_power_check_otg_status,void, Function,+,furi_hal_power_debug_get,void,"PropertyValueCallback, void*" Function,+,furi_hal_power_disable_external_3_3v,void, Function,+,furi_hal_power_disable_otg,void, Function,+,furi_hal_power_enable_external_3_3v,void, -Function,+,furi_hal_power_enable_otg,void, +Function,+,furi_hal_power_enable_otg,_Bool, Function,+,furi_hal_power_gauge_is_ok,_Bool, Function,+,furi_hal_power_get_bat_health_pct,uint8_t, Function,+,furi_hal_power_get_battery_charge_voltage_limit,float, @@ -1339,6 +1342,7 @@ Function,-,furi_hal_power_insomnia_level,uint16_t, Function,+,furi_hal_power_is_charging,_Bool, Function,+,furi_hal_power_is_charging_done,_Bool, Function,+,furi_hal_power_is_otg_enabled,_Bool, +Function,+,furi_hal_power_is_shutdown_requested,_Bool, Function,+,furi_hal_power_off,void, Function,+,furi_hal_power_reset,void, Function,+,furi_hal_power_set_battery_charge_voltage_limit,void,float @@ -1461,8 +1465,8 @@ Function,+,furi_hal_subghz_rx_pipe_not_empty,_Bool, Function,+,furi_hal_subghz_set_async_mirror_pin,void,const GpioPin* Function,+,furi_hal_subghz_set_frequency,uint32_t,uint32_t Function,+,furi_hal_subghz_set_frequency_and_path,uint32_t,uint32_t -Function,-,furi_hal_subghz_set_path,void,FuriHalSubGhzPath -Function,-,furi_hal_subghz_shutdown,void, +Function,+,furi_hal_subghz_set_path,void,FuriHalSubGhzPath +Function,+,furi_hal_subghz_shutdown,void, Function,+,furi_hal_subghz_sleep,void, Function,+,furi_hal_subghz_start_async_rx,void,"FuriHalSubGhzCaptureCallback, void*" Function,+,furi_hal_subghz_start_async_tx,_Bool,"FuriHalSubGhzAsyncTxCallback, void*" @@ -1504,6 +1508,7 @@ Function,+,furi_hal_version_get_hw_target,uint8_t, Function,+,furi_hal_version_get_hw_timestamp,uint32_t, Function,+,furi_hal_version_get_hw_version,uint8_t, Function,+,furi_hal_version_get_ic_id,const char*, +Function,+,furi_hal_version_get_mic_id,const char*, Function,+,furi_hal_version_get_model_code,const char*, Function,+,furi_hal_version_get_model_name,const char*, Function,+,furi_hal_version_get_name_ptr,const char*, @@ -1521,6 +1526,8 @@ Function,+,furi_kernel_restore_lock,int32_t,int32_t Function,+,furi_kernel_unlock,int32_t, Function,+,furi_log_get_level,FuriLogLevel, Function,-,furi_log_init,void, +Function,+,furi_log_level_from_string,_Bool,"const char*, FuriLogLevel*" +Function,+,furi_log_level_to_string,_Bool,"FuriLogLevel, const char**" Function,+,furi_log_print_format,void,"FuriLogLevel, const char*, const char*, ..." Function,+,furi_log_print_raw_format,void,"FuriLogLevel, const char*, ..." Function,+,furi_log_set_level,void,FuriLogLevel @@ -1827,22 +1834,22 @@ Function,-,islower,int,int Function,-,islower_l,int,"int, locale_t" Function,-,isnan,int,double Function,-,isnanf,int,float -Function,-,iso14443_3a_alloc,Iso14443_3aData*, -Function,-,iso14443_3a_append_crc,void,BitBuffer* -Function,-,iso14443_3a_check_crc,_Bool,const BitBuffer* -Function,-,iso14443_3a_copy,void,"Iso14443_3aData*, const Iso14443_3aData*" -Function,-,iso14443_3a_free,void,Iso14443_3aData* -Function,-,iso14443_3a_get_base_data,const Iso14443_3aData*,const Iso14443_3aData* -Function,-,iso14443_3a_get_cuid,uint32_t,const Iso14443_3aData* -Function,-,iso14443_3a_get_device_name,const char*,"const Iso14443_3aData*, NfcDeviceNameType" -Function,-,iso14443_3a_get_uid,const uint8_t*,"const Iso14443_3aData*, size_t*" -Function,-,iso14443_3a_is_equal,_Bool,"const Iso14443_3aData*, const Iso14443_3aData*" -Function,-,iso14443_3a_load,_Bool,"Iso14443_3aData*, FlipperFormat*, uint32_t" +Function,+,iso14443_3a_alloc,Iso14443_3aData*, +Function,+,iso14443_3a_append_crc,void,BitBuffer* +Function,+,iso14443_3a_check_crc,_Bool,const BitBuffer* +Function,+,iso14443_3a_copy,void,"Iso14443_3aData*, const Iso14443_3aData*" +Function,+,iso14443_3a_free,void,Iso14443_3aData* +Function,+,iso14443_3a_get_base_data,const Iso14443_3aData*,const Iso14443_3aData* +Function,+,iso14443_3a_get_cuid,uint32_t,const Iso14443_3aData* +Function,+,iso14443_3a_get_device_name,const char*,"const Iso14443_3aData*, NfcDeviceNameType" +Function,+,iso14443_3a_get_uid,const uint8_t*,"const Iso14443_3aData*, size_t*" +Function,+,iso14443_3a_is_equal,_Bool,"const Iso14443_3aData*, const Iso14443_3aData*" +Function,+,iso14443_3a_load,_Bool,"Iso14443_3aData*, FlipperFormat*, uint32_t" Function,+,iso14443_3a_poller_read,Iso14443_3aError,"Nfc*, Iso14443_3aData*" -Function,-,iso14443_3a_reset,void,Iso14443_3aData* +Function,+,iso14443_3a_reset,void,Iso14443_3aData* Function,+,iso14443_3a_save,_Bool,"const Iso14443_3aData*, FlipperFormat*" -Function,-,iso14443_3a_trim_crc,void,BitBuffer* -Function,-,iso14443_3a_verify,_Bool,"Iso14443_3aData*, const FuriString*" +Function,+,iso14443_3a_trim_crc,void,BitBuffer* +Function,+,iso14443_3a_verify,_Bool,"Iso14443_3aData*, const FuriString*" Function,+,iso14443_4a_alloc,Iso14443_4aData*, Function,+,iso14443_4a_copy,void,"Iso14443_4aData*, const Iso14443_4aData*" Function,+,iso14443_4a_free,void,Iso14443_4aData* @@ -2046,7 +2053,7 @@ Function,+,mf_classic_get_sector_by_block,uint8_t,uint8_t Function,+,mf_classic_get_sector_trailer_by_sector,MfClassicSectorTrailer*,"const MfClassicData*, uint8_t" Function,+,mf_classic_get_sector_trailer_num_by_block,uint8_t,uint8_t Function,+,mf_classic_get_sector_trailer_num_by_sector,uint8_t,uint8_t -Function,+,mf_classic_get_total_block_num,uint16_t,MfClassicType +Function,-,mf_classic_get_total_block_num,uint16_t,MfClassicType Function,+,mf_classic_get_total_sectors_num,uint8_t,MfClassicType Function,+,mf_classic_get_uid,const uint8_t*,"const MfClassicData*, size_t*" Function,+,mf_classic_is_allowed_access,_Bool,"MfClassicData*, uint8_t, MfClassicKeyType, MfClassicAction" @@ -2056,7 +2063,7 @@ Function,+,mf_classic_is_equal,_Bool,"const MfClassicData*, const MfClassicData* Function,+,mf_classic_is_key_found,_Bool,"const MfClassicData*, uint8_t, MfClassicKeyType" Function,+,mf_classic_is_sector_read,_Bool,"const MfClassicData*, uint8_t" Function,+,mf_classic_is_sector_trailer,_Bool,uint8_t -Function,+,mf_classic_is_value_block,_Bool,"MfClassicData*, uint8_t" +Function,-,mf_classic_is_value_block,_Bool,"MfClassicData*, uint8_t" Function,+,mf_classic_load,_Bool,"MfClassicData*, FlipperFormat*, uint32_t" Function,+,mf_classic_poller_auth,MfClassicError,"Nfc*, uint8_t, MfClassicKey*, MfClassicKeyType, MfClassicAuthContext*" Function,+,mf_classic_poller_change_value,MfClassicError,"Nfc*, uint8_t, MfClassicKey*, MfClassicKeyType, int32_t, int32_t*" @@ -2168,22 +2175,22 @@ Function,-,nfc_iso14443_3a_listener_tx_custom_parity,NfcError,"Nfc*, const BitBu Function,-,nfc_iso14443_3a_sdd_frame,NfcError,"Nfc*, const BitBuffer*, BitBuffer*, uint32_t" Function,-,nfc_iso14443_3a_short_frame,NfcError,"Nfc*, NfcIso14443aShortFrame, BitBuffer*, uint32_t" Function,-,nfc_listener_abort,void,Nfc* -Function,+,nfc_listener_alloc,NfcListener*,"Nfc*, NfcProtocol, const NfcDeviceData*" -Function,+,nfc_listener_free,void,NfcListener* -Function,+,nfc_listener_get_data,const NfcDeviceData*,"NfcListener*, NfcProtocol" +Function,-,nfc_listener_alloc,NfcListener*,"Nfc*, NfcProtocol, const NfcDeviceData*" +Function,-,nfc_listener_free,void,NfcListener* +Function,-,nfc_listener_get_data,const NfcDeviceData*,"NfcListener*, NfcProtocol" Function,-,nfc_listener_set_col_res_data,NfcError,"Nfc*, uint8_t*, uint8_t, uint8_t*, uint8_t" Function,-,nfc_listener_sleep,NfcError,Nfc* -Function,+,nfc_listener_start,void,"NfcListener*, NfcGenericCallback, void*" -Function,+,nfc_listener_stop,void,NfcListener* +Function,-,nfc_listener_start,void,"NfcListener*, NfcGenericCallback, void*" +Function,-,nfc_listener_stop,void,NfcListener* Function,-,nfc_listener_tx,NfcError,"Nfc*, const BitBuffer*" -Function,-,nfc_poller_alloc,NfcPoller*,"Nfc*, NfcProtocol" -Function,-,nfc_poller_detect,_Bool,NfcPoller* -Function,-,nfc_poller_free,void,NfcPoller* -Function,-,nfc_poller_get_data,const NfcDeviceData*,NfcPoller* -Function,-,nfc_poller_start,void,"NfcPoller*, NfcGenericCallback, void*" -Function,-,nfc_poller_stop,void,NfcPoller* -Function,-,nfc_protocol_get_parent,NfcProtocol,NfcProtocol -Function,-,nfc_protocol_has_parent,_Bool,"NfcProtocol, NfcProtocol" +Function,+,nfc_poller_alloc,NfcPoller*,"Nfc*, NfcProtocol" +Function,+,nfc_poller_detect,_Bool,NfcPoller* +Function,+,nfc_poller_free,void,NfcPoller* +Function,+,nfc_poller_get_data,const NfcDeviceData*,NfcPoller* +Function,+,nfc_poller_start,void,"NfcPoller*, NfcGenericCallback, void*" +Function,+,nfc_poller_stop,void,NfcPoller* +Function,+,nfc_protocol_get_parent,NfcProtocol,NfcProtocol +Function,+,nfc_protocol_has_parent,_Bool,"NfcProtocol, NfcProtocol" Function,+,nfc_scanner_alloc,NfcScanner*,Nfc* Function,+,nfc_scanner_free,void,NfcScanner* Function,+,nfc_scanner_start,void,"NfcScanner*, NfcScannerCallback, void*" @@ -2887,6 +2894,7 @@ Function,+,subghz_protocol_decoder_base_get_hash_data,uint8_t,SubGhzProtocolDeco Function,+,subghz_protocol_decoder_base_get_string,_Bool,"SubGhzProtocolDecoderBase*, FuriString*" Function,+,subghz_protocol_decoder_base_serialize,SubGhzProtocolStatus,"SubGhzProtocolDecoderBase*, FlipperFormat*, SubGhzRadioPreset*" Function,-,subghz_protocol_decoder_base_set_decoder_callback,void,"SubGhzProtocolDecoderBase*, SubGhzProtocolDecoderBaseRxCallback, void*" +Function,+,subghz_protocol_decoder_bin_raw_data_input_rssi,void,"SubGhzProtocolDecoderBinRAW*, float" Function,+,subghz_protocol_decoder_raw_alloc,void*,SubGhzEnvironment* Function,+,subghz_protocol_decoder_raw_deserialize,SubGhzProtocolStatus,"void*, FlipperFormat*" Function,+,subghz_protocol_decoder_raw_feed,void,"void*, _Bool, uint32_t" @@ -2898,6 +2906,7 @@ Function,+,subghz_protocol_encoder_raw_deserialize,SubGhzProtocolStatus,"void*, Function,+,subghz_protocol_encoder_raw_free,void,void* Function,+,subghz_protocol_encoder_raw_stop,void,void* Function,+,subghz_protocol_encoder_raw_yield,LevelDuration,void* +Function,+,subghz_protocol_keeloq_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint16_t, const char*, SubGhzRadioPreset*" Function,+,subghz_protocol_raw_file_encoder_worker_set_callback_end,void,"SubGhzProtocolEncoderRAW*, SubGhzProtocolEncoderRAWCallbackEnd, void*" Function,+,subghz_protocol_raw_gen_fff_data,void,"FlipperFormat*, const char*, const char*" Function,+,subghz_protocol_raw_get_sample_write,size_t,SubGhzProtocolDecoderRAW* @@ -2907,6 +2916,8 @@ Function,+,subghz_protocol_raw_save_to_file_stop,void,SubGhzProtocolDecoderRAW* Function,+,subghz_protocol_registry_count,size_t,const SubGhzProtocolRegistry* Function,+,subghz_protocol_registry_get_by_index,const SubGhzProtocol*,"const SubGhzProtocolRegistry*, size_t" Function,+,subghz_protocol_registry_get_by_name,const SubGhzProtocol*,"const SubGhzProtocolRegistry*, const char*" +Function,+,subghz_protocol_secplus_v1_check_fixed,_Bool,uint32_t +Function,+,subghz_protocol_secplus_v2_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint32_t, SubGhzRadioPreset*" Function,+,subghz_receiver_alloc_init,SubGhzReceiver*,SubGhzEnvironment* Function,+,subghz_receiver_decode,void,"SubGhzReceiver*, _Bool, uint32_t" Function,+,subghz_receiver_free,void,SubGhzReceiver* @@ -3496,10 +3507,10 @@ Variable,+,message_sound_off,const NotificationMessage, Variable,+,message_vibro_off,const NotificationMessage, Variable,+,message_vibro_on,const NotificationMessage, Variable,-,nfc_device_iso14443_3a,const NfcDeviceBase, -Variable,+,nfc_device_iso14443_4a,const NfcDeviceBase, +Variable,-,nfc_device_iso14443_4a,const NfcDeviceBase, Variable,-,nfc_device_mf_classic,const NfcDeviceBase, -Variable,+,nfc_device_mf_desfire,const NfcDeviceBase, -Variable,+,nfc_device_mf_ultralight,const NfcDeviceBase, +Variable,-,nfc_device_mf_desfire,const NfcDeviceBase, +Variable,-,nfc_device_mf_ultralight,const NfcDeviceBase, Variable,+,sequence_audiovisual_alert,const NotificationSequence, Variable,+,sequence_blink_blue_10,const NotificationSequence, Variable,+,sequence_blink_blue_100,const NotificationSequence, @@ -3550,6 +3561,7 @@ Variable,+,sequence_single_vibro,const NotificationSequence, Variable,+,sequence_solid_yellow,const NotificationSequence, Variable,+,sequence_success,const NotificationSequence, Variable,+,simple_array_config_uint8_t,const SimpleArrayConfig, +Variable,-,subghz_device_cc1101_int,const SubGhzDevice, Variable,+,subghz_device_cc1101_preset_2fsk_dev2_38khz_async_regs,const uint8_t[], Variable,+,subghz_device_cc1101_preset_2fsk_dev47_6khz_async_regs,const uint8_t[], Variable,+,subghz_device_cc1101_preset_gfsk_9_99kb_async_regs,const uint8_t[], diff --git a/firmware/targets/f7/furi_hal/furi_hal_infrared.c b/firmware/targets/f7/furi_hal/furi_hal_infrared.c index c60db5f20ef2..d3e36c2b5d48 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_infrared.c +++ b/firmware/targets/f7/furi_hal/furi_hal_infrared.c @@ -373,9 +373,6 @@ static void furi_hal_infrared_configure_tim_pwm_tx(uint32_t freq, float duty_cyc LL_TIM_EnableAllOutputs(INFRARED_DMA_TIMER); LL_TIM_DisableIT_UPDATE(INFRARED_DMA_TIMER); LL_TIM_EnableDMAReq_UPDATE(INFRARED_DMA_TIMER); - - NVIC_SetPriority(TIM1_UP_TIM16_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0)); - NVIC_EnableIRQ(TIM1_UP_TIM16_IRQn); } static void furi_hal_infrared_configure_tim_cmgr2_dma_tx(void) { diff --git a/firmware/targets/f7/furi_hal/furi_hal_interrupt.c b/firmware/targets/f7/furi_hal/furi_hal_interrupt.c index b5639d2300c5..c508dac72bf4 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_interrupt.c +++ b/firmware/targets/f7/furi_hal/furi_hal_interrupt.c @@ -62,7 +62,7 @@ const IRQn_Type furi_hal_interrupt_irqn[FuriHalInterruptIdMax] = { __attribute__((always_inline)) static inline void furi_hal_interrupt_call(FuriHalInterruptId index) { - furi_assert(furi_hal_interrupt_isr[index].isr); + furi_check(furi_hal_interrupt_isr[index].isr); furi_hal_interrupt_isr[index].isr(furi_hal_interrupt_isr[index].context); } @@ -127,16 +127,14 @@ void furi_hal_interrupt_set_isr_ex( uint16_t priority, FuriHalInterruptISR isr, void* context) { - furi_assert(index < FuriHalInterruptIdMax); - furi_assert(priority < 15); - furi_assert(furi_hal_interrupt_irqn[index]); + furi_check(index < FuriHalInterruptIdMax); + furi_check(priority <= 15); if(isr) { // Pre ISR set - furi_assert(furi_hal_interrupt_isr[index].isr == NULL); + furi_check(furi_hal_interrupt_isr[index].isr == NULL); } else { // Pre ISR clear - furi_assert(furi_hal_interrupt_isr[index].isr != NULL); furi_hal_interrupt_disable(index); furi_hal_interrupt_clear_pending(index); } diff --git a/firmware/targets/f7/furi_hal/furi_hal_power.c b/firmware/targets/f7/furi_hal/furi_hal_power.c index ec405f1080df..035919d784df 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_power.c +++ b/firmware/targets/f7/furi_hal/furi_hal_power.c @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -37,16 +38,18 @@ typedef struct { volatile uint8_t insomnia; volatile uint8_t suppress_charge; - uint8_t gauge_initialized; - uint8_t charger_initialized; + bool gauge_ok; + bool charger_ok; } FuriHalPower; static volatile FuriHalPower furi_hal_power = { .insomnia = 0, .suppress_charge = 0, + .gauge_ok = false, + .charger_ok = false, }; -#include +extern const BQ27220DMData furi_hal_power_gauge_data_memory[]; void furi_hal_power_init() { #ifdef FURI_HAL_POWER_DEBUG @@ -63,8 +66,13 @@ void furi_hal_power_init() { LL_C2_PWR_SetPowerMode(FURI_HAL_POWER_STOP_MODE); furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); - bq27220_init(&furi_hal_i2c_handle_power, &cedv); - bq25896_init(&furi_hal_i2c_handle_power); + // Find and init gauge + if(bq27220_init(&furi_hal_i2c_handle_power)) { + furi_hal_power.gauge_ok = bq27220_apply_data_memory( + &furi_hal_i2c_handle_power, furi_hal_power_gauge_data_memory); + } + // Find and init charger + furi_hal_power.charger_ok = bq25896_init(&furi_hal_i2c_handle_power); furi_hal_i2c_release(&furi_hal_i2c_handle_power); FURI_LOG_I(TAG, "Init OK"); @@ -78,14 +86,29 @@ bool furi_hal_power_gauge_is_ok() { furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); - if(bq27220_get_battery_status(&furi_hal_i2c_handle_power, &battery_status) == BQ27220_ERROR || - bq27220_get_operation_status(&furi_hal_i2c_handle_power, &operation_status) == - BQ27220_ERROR) { + if(!bq27220_get_battery_status(&furi_hal_i2c_handle_power, &battery_status) || + !bq27220_get_operation_status(&furi_hal_i2c_handle_power, &operation_status)) { ret = false; } else { ret &= battery_status.BATTPRES; ret &= operation_status.INITCOMP; - ret &= (cedv.design_cap == bq27220_get_design_capacity(&furi_hal_i2c_handle_power)); + ret &= furi_hal_power.gauge_ok; + } + + furi_hal_i2c_release(&furi_hal_i2c_handle_power); + + return ret; +} + +bool furi_hal_power_is_shutdown_requested() { + bool ret = false; + + BatteryStatus battery_status; + + furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); + + if(bq27220_get_battery_status(&furi_hal_i2c_handle_power, &battery_status) != BQ27220_ERROR) { + ret = battery_status.SYSDWN; } furi_hal_i2c_release(&furi_hal_i2c_handle_power); @@ -284,10 +307,15 @@ void furi_hal_power_reset() { NVIC_SystemReset(); } -void furi_hal_power_enable_otg() { +bool furi_hal_power_enable_otg() { furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); + bq25896_set_boost_lim(&furi_hal_i2c_handle_power, BoostLim_2150); bq25896_enable_otg(&furi_hal_i2c_handle_power); + furi_delay_ms(30); + bool ret = bq25896_is_otg_enabled(&furi_hal_i2c_handle_power); + bq25896_set_boost_lim(&furi_hal_i2c_handle_power, BoostLim_1400); furi_hal_i2c_release(&furi_hal_i2c_handle_power); + return ret; } void furi_hal_power_disable_otg() { @@ -317,6 +345,13 @@ void furi_hal_power_set_battery_charge_voltage_limit(float voltage) { furi_hal_i2c_release(&furi_hal_i2c_handle_power); } +bool furi_hal_power_check_otg_fault() { + furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); + bool ret = bq25896_check_otg_fault(&furi_hal_i2c_handle_power); + furi_hal_i2c_release(&furi_hal_i2c_handle_power); + return ret; +} + void furi_hal_power_check_otg_status() { furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); if(bq25896_check_otg_fault(&furi_hal_i2c_handle_power)) @@ -564,9 +599,8 @@ void furi_hal_power_debug_get(PropertyValueCallback out, void* context) { const uint32_t ntc_mpct = bq25896_get_ntc_mpct(&furi_hal_i2c_handle_power); - if(bq27220_get_battery_status(&furi_hal_i2c_handle_power, &battery_status) != BQ27220_ERROR && - bq27220_get_operation_status(&furi_hal_i2c_handle_power, &operation_status) != - BQ27220_ERROR) { + if(bq27220_get_battery_status(&furi_hal_i2c_handle_power, &battery_status) && + bq27220_get_operation_status(&furi_hal_i2c_handle_power, &operation_status)) { property_value_out(&property_context, "%lu", 2, "charger", "ntc", ntc_mpct); property_value_out(&property_context, "%d", 2, "gauge", "calmd", operation_status.CALMD); property_value_out(&property_context, "%d", 2, "gauge", "sec", operation_status.SEC); diff --git a/firmware/targets/f7/furi_hal/furi_hal_power_calibration.h b/firmware/targets/f7/furi_hal/furi_hal_power_calibration.h deleted file mode 100644 index 5eb0f938b2e6..000000000000 --- a/firmware/targets/f7/furi_hal/furi_hal_power_calibration.h +++ /dev/null @@ -1,37 +0,0 @@ -const ParamCEDV cedv = { - .cedv_conf.gauge_conf = - { - .CCT = 1, - .CSYNC = 0, - .EDV_CMP = 0, - .SC = 1, - .FIXED_EDV0 = 1, - .FCC_LIM = 1, - .FC_FOR_VDQ = 1, - .IGNORE_SD = 1, - .SME0 = 0, - }, - .full_charge_cap = 2101, - .design_cap = 2101, - .EDV0 = 3300, - .EDV1 = 3321, - .EDV2 = 3355, - .EMF = 3679, - .C0 = 430, - .C1 = 0, - .R1 = 408, - .R0 = 334, - .T0 = 4626, - .TC = 11, - .DOD0 = 4044, - .DOD10 = 3905, - .DOD20 = 3807, - .DOD30 = 3718, - .DOD40 = 3642, - .DOD50 = 3585, - .DOD60 = 3546, - .DOD70 = 3514, - .DOD80 = 3477, - .DOD90 = 3411, - .DOD100 = 3299, -}; diff --git a/firmware/targets/f7/furi_hal/furi_hal_power_config.c b/firmware/targets/f7/furi_hal/furi_hal_power_config.c new file mode 100644 index 000000000000..488edce91eee --- /dev/null +++ b/firmware/targets/f7/furi_hal/furi_hal_power_config.c @@ -0,0 +1,149 @@ +#include + +const BQ27220DMGaugingConfig furi_hal_power_gauge_data_memory_gauging_config = { + .CCT = 1, + .CSYNC = 0, + .EDV_CMP = 0, + .SC = 1, + .FIXED_EDV0 = 1, + .FCC_LIM = 1, + .FC_FOR_VDQ = 1, + .IGNORE_SD = 1, + .SME0 = 0, +}; + +const BQ27220DMData furi_hal_power_gauge_data_memory[] = { + { + .address = BQ27220DMAddressGasGaugingCEDVProfile1GaugingConfig, + .type = BQ27220DMTypePtr16, + .value.u32 = (uint32_t)&furi_hal_power_gauge_data_memory_gauging_config, + }, + { + .address = BQ27220DMAddressGasGaugingCEDVProfile1FullChargeCapacity, + .type = BQ27220DMTypeU16, + .value.u16 = 2100, + }, + { + .address = BQ27220DMAddressGasGaugingCEDVProfile1DesignCapacity, + .type = BQ27220DMTypeU16, + .value.u16 = 2100, + }, + { + .address = BQ27220DMAddressGasGaugingCEDVProfile1EMF, + .type = BQ27220DMTypeU16, + .value.u16 = 3679, + }, + { + .address = BQ27220DMAddressGasGaugingCEDVProfile1C0, + .type = BQ27220DMTypeU16, + .value.u16 = 430, + }, + { + .address = BQ27220DMAddressGasGaugingCEDVProfile1R0, + .type = BQ27220DMTypeU16, + .value.u16 = 334, + }, + { + .address = BQ27220DMAddressGasGaugingCEDVProfile1T0, + .type = BQ27220DMTypeU16, + .value.u16 = 4626, + }, + { + .address = BQ27220DMAddressGasGaugingCEDVProfile1R1, + .type = BQ27220DMTypeU16, + .value.u16 = 408, + }, + { + .address = BQ27220DMAddressGasGaugingCEDVProfile1TC, + .type = BQ27220DMTypeU8, + .value.u8 = 11, + }, + { + .address = BQ27220DMAddressGasGaugingCEDVProfile1C1, + .type = BQ27220DMTypeU8, + .value.u8 = 0, + }, + { + .address = BQ27220DMAddressGasGaugingCEDVProfile1StartDOD0, + .type = BQ27220DMTypeU16, + .value.u16 = 4044, + }, + { + .address = BQ27220DMAddressGasGaugingCEDVProfile1StartDOD10, + .type = BQ27220DMTypeU16, + .value.u16 = 3905, + }, + { + .address = BQ27220DMAddressGasGaugingCEDVProfile1StartDOD20, + .type = BQ27220DMTypeU16, + .value.u16 = 3807, + }, + { + .address = BQ27220DMAddressGasGaugingCEDVProfile1StartDOD30, + .type = BQ27220DMTypeU16, + .value.u16 = 3718, + }, + { + .address = BQ27220DMAddressGasGaugingCEDVProfile1StartDOD40, + .type = BQ27220DMTypeU16, + .value.u16 = 3642, + }, + { + .address = BQ27220DMAddressGasGaugingCEDVProfile1StartDOD50, + .type = BQ27220DMTypeU16, + .value.u16 = 3585, + }, + { + .address = BQ27220DMAddressGasGaugingCEDVProfile1StartDOD60, + .type = BQ27220DMTypeU16, + .value.u16 = 3546, + }, + { + .address = BQ27220DMAddressGasGaugingCEDVProfile1StartDOD70, + .type = BQ27220DMTypeU16, + .value.u16 = 3514, + }, + { + .address = BQ27220DMAddressGasGaugingCEDVProfile1StartDOD80, + .type = BQ27220DMTypeU16, + .value.u16 = 3477, + }, + { + .address = BQ27220DMAddressGasGaugingCEDVProfile1StartDOD90, + .type = BQ27220DMTypeU16, + .value.u16 = 3411, + }, + { + .address = BQ27220DMAddressGasGaugingCEDVProfile1StartDOD100, + .type = BQ27220DMTypeU16, + .value.u16 = 3299, + }, + { + .address = BQ27220DMAddressGasGaugingCEDVProfile1EDV0, + .type = BQ27220DMTypeU16, + .value.u16 = 3300, + }, + { + .address = BQ27220DMAddressGasGaugingCEDVProfile1EDV1, + .type = BQ27220DMTypeU16, + .value.u16 = 3321, + }, + { + .address = BQ27220DMAddressGasGaugingCEDVProfile1EDV2, + .type = BQ27220DMTypeU16, + .value.u16 = 3355, + }, + { + .address = BQ27220DMAddressCalibrationCurrentDeadband, + .type = BQ27220DMTypeU8, + .value.u8 = 1, + }, + { + .address = BQ27220DMAddressConfigurationPowerSleepCurrent, + .type = BQ27220DMTypeI16, + .value.i16 = 1, + }, + { + .type = BQ27220DMTypeEnd, + }, +}; diff --git a/firmware/targets/f7/furi_hal/furi_hal_spi_config.c b/firmware/targets/f7/furi_hal/furi_hal_spi_config.c index 09ac79d2a3c0..757ac23661d3 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_spi_config.c +++ b/firmware/targets/f7/furi_hal/furi_hal_spi_config.c @@ -192,6 +192,52 @@ inline static void furi_hal_spi_bus_r_handle_event_callback( } } +inline static void furi_hal_spi_bus_external_handle_event_callback( + FuriHalSpiBusHandle* handle, + FuriHalSpiBusHandleEvent event, + const LL_SPI_InitTypeDef* preset) { + if(event == FuriHalSpiBusHandleEventInit) { + furi_hal_gpio_write(handle->cs, true); + furi_hal_gpio_init(handle->cs, GpioModeOutputPushPull, GpioPullUp, GpioSpeedVeryHigh); + } else if(event == FuriHalSpiBusHandleEventDeinit) { + furi_hal_gpio_write(handle->cs, true); + furi_hal_gpio_init(handle->cs, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + } else if(event == FuriHalSpiBusHandleEventActivate) { + LL_SPI_Init(handle->bus->spi, (LL_SPI_InitTypeDef*)preset); + LL_SPI_SetRxFIFOThreshold(handle->bus->spi, LL_SPI_RX_FIFO_TH_QUARTER); + LL_SPI_Enable(handle->bus->spi); + + furi_hal_gpio_init_ex( + handle->miso, + GpioModeAltFunctionPushPull, + GpioPullDown, + GpioSpeedVeryHigh, + GpioAltFn5SPI1); + furi_hal_gpio_init_ex( + handle->mosi, + GpioModeAltFunctionPushPull, + GpioPullDown, + GpioSpeedVeryHigh, + GpioAltFn5SPI1); + furi_hal_gpio_init_ex( + handle->sck, + GpioModeAltFunctionPushPull, + GpioPullDown, + GpioSpeedVeryHigh, + GpioAltFn5SPI1); + + furi_hal_gpio_write(handle->cs, false); + } else if(event == FuriHalSpiBusHandleEventDeactivate) { + furi_hal_gpio_write(handle->cs, true); + + furi_hal_gpio_init(handle->miso, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_init(handle->mosi, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_init(handle->sck, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + + LL_SPI_Disable(handle->bus->spi); + } +} + inline static void furi_hal_spi_bus_nfc_handle_event_callback( FuriHalSpiBusHandle* handle, FuriHalSpiBusHandleEvent event, @@ -291,7 +337,8 @@ FuriHalSpiBusHandle furi_hal_spi_bus_handle_nfc = { static void furi_hal_spi_bus_handle_external_event_callback( FuriHalSpiBusHandle* handle, FuriHalSpiBusHandleEvent event) { - furi_hal_spi_bus_r_handle_event_callback(handle, event, &furi_hal_spi_preset_1edge_low_2m); + furi_hal_spi_bus_external_handle_event_callback( + handle, event, &furi_hal_spi_preset_1edge_low_2m); } FuriHalSpiBusHandle furi_hal_spi_bus_handle_external = { diff --git a/firmware/targets/f7/furi_hal/furi_hal_version_device.c b/firmware/targets/f7/furi_hal/furi_hal_version_device.c index c059c2cbe692..be3f4bf3f3c7 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_version_device.c +++ b/firmware/targets/f7/furi_hal/furi_hal_version_device.c @@ -19,3 +19,7 @@ const char* furi_hal_version_get_fcc_id() { const char* furi_hal_version_get_ic_id() { return "27624-FZ"; } + +const char* furi_hal_version_get_mic_id() { + return "210-175991"; +} diff --git a/firmware/targets/f7/platform_specific/intrinsic_export.h b/firmware/targets/f7/platform_specific/intrinsic_export.h index ca343a12862e..d3c7be5e0429 100644 --- a/firmware/targets/f7/platform_specific/intrinsic_export.h +++ b/firmware/targets/f7/platform_specific/intrinsic_export.h @@ -1,3 +1,4 @@ +#pragma once #include #include diff --git a/firmware/targets/f7/platform_specific/math_wrapper.h b/firmware/targets/f7/platform_specific/math_wrapper.h new file mode 100644 index 000000000000..83f5a8b75d3a --- /dev/null +++ b/firmware/targets/f7/platform_specific/math_wrapper.h @@ -0,0 +1,2 @@ +#pragma once +#include \ No newline at end of file diff --git a/firmware/targets/furi_hal_include/furi_hal_power.h b/firmware/targets/furi_hal_include/furi_hal_power.h index 00182fa28615..5edda6ba1974 100644 --- a/firmware/targets/furi_hal_include/furi_hal_power.h +++ b/firmware/targets/furi_hal_include/furi_hal_power.h @@ -34,6 +34,12 @@ void furi_hal_power_init(); */ bool furi_hal_power_gauge_is_ok(); +/** Check if gauge requests system shutdown + * + * @return true if system shutdown requested + */ +bool furi_hal_power_is_shutdown_requested(); + /** Get current insomnia level * * @return insomnia level: 0 - no insomnia, >0 - insomnia, bearer count. @@ -99,12 +105,16 @@ void furi_hal_power_reset(); /** OTG enable */ -void furi_hal_power_enable_otg(); +bool furi_hal_power_enable_otg(); /** OTG disable */ void furi_hal_power_disable_otg(); +/** Check OTG status fault + */ +bool furi_hal_power_check_otg_fault(); + /** Check OTG status and disable it if falt happened */ void furi_hal_power_check_otg_status(); diff --git a/firmware/targets/furi_hal_include/furi_hal_version.h b/firmware/targets/furi_hal_include/furi_hal_version.h index aec4fc787aa4..a9339a6c0eea 100644 --- a/firmware/targets/furi_hal_include/furi_hal_version.h +++ b/firmware/targets/furi_hal_include/furi_hal_version.h @@ -85,6 +85,12 @@ const char* furi_hal_version_get_fcc_id(); */ const char* furi_hal_version_get_ic_id(); +/** Get MIC id + * + * @return MIC id as C-string + */ +const char* furi_hal_version_get_mic_id(); + /** Get OTP version * * @return OTP Version diff --git a/furi/core/check.c b/furi/core/check.c index c5c4ef1a4af3..f7dcfc595902 100644 --- a/furi/core/check.c +++ b/furi/core/check.c @@ -36,7 +36,7 @@ PLACE_IN_SECTION("MB_MEM2") uint32_t __furi_check_registers[13] = {0}; * */ #define RESTORE_REGISTERS_AND_HALT_MCU(debug) \ - register const bool r0 asm("r0") = debug; \ + register bool r0 asm("r0") = debug; \ asm volatile("cbnz r0, with_debugger%= \n" \ "ldr r12, =__furi_check_registers\n" \ "ldm r12, {r0-r11} \n" \ diff --git a/furi/core/log.c b/furi/core/log.c index d910ecf21132..53467ecdb2d7 100644 --- a/furi/core/log.c +++ b/furi/core/log.c @@ -14,6 +14,21 @@ typedef struct { static FuriLogParams furi_log; +typedef struct { + const char* str; + FuriLogLevel level; +} FuriLogLevelDescription; + +static const FuriLogLevelDescription FURI_LOG_LEVEL_DESCRIPTIONS[] = { + {"default", FuriLogLevelDefault}, + {"none", FuriLogLevelNone}, + {"error", FuriLogLevelError}, + {"warn", FuriLogLevelWarn}, + {"info", FuriLogLevelInfo}, + {"debug", FuriLogLevelDebug}, + {"trace", FuriLogLevelTrace}, +}; + void furi_log_init() { // Set default logging parameters furi_log.log_level = FURI_LOG_LEVEL_DEFAULT; @@ -117,3 +132,23 @@ void furi_log_set_timestamp(FuriLogTimestamp timestamp) { furi_assert(timestamp); furi_log.timestamp = timestamp; } + +bool furi_log_level_to_string(FuriLogLevel level, const char** str) { + for(size_t i = 0; i < COUNT_OF(FURI_LOG_LEVEL_DESCRIPTIONS); i++) { + if(level == FURI_LOG_LEVEL_DESCRIPTIONS[i].level) { + *str = FURI_LOG_LEVEL_DESCRIPTIONS[i].str; + return true; + } + } + return false; +} + +bool furi_log_level_from_string(const char* str, FuriLogLevel* level) { + for(size_t i = 0; i < COUNT_OF(FURI_LOG_LEVEL_DESCRIPTIONS); i++) { + if(strcmp(str, FURI_LOG_LEVEL_DESCRIPTIONS[i].str) == 0) { + *level = FURI_LOG_LEVEL_DESCRIPTIONS[i].level; + return true; + } + } + return false; +} \ No newline at end of file diff --git a/furi/core/log.h b/furi/core/log.h index 46ae7f00713f..5d11add9b917 100644 --- a/furi/core/log.h +++ b/furi/core/log.h @@ -7,6 +7,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -87,6 +88,23 @@ void furi_log_set_puts(FuriLogPuts puts); */ void furi_log_set_timestamp(FuriLogTimestamp timestamp); +/** Log level to string + * + * @param[in] level The level + * + * @return The string + */ +bool furi_log_level_to_string(FuriLogLevel level, const char** str); + +/** Log level from string + * + * @param[in] str The string + * @param level The level + * + * @return True if success, False otherwise + */ +bool furi_log_level_from_string(const char* str, FuriLogLevel* level); + /** Log methods * * @param tag The application tag diff --git a/lib/drivers/SConscript b/lib/drivers/SConscript index 3b7ee2401e63..103472ccb35b 100644 --- a/lib/drivers/SConscript +++ b/lib/drivers/SConscript @@ -4,6 +4,9 @@ env.Append( CPPPATH=[ "#/lib/drivers", ], + SDK_HEADERS=[ + File("cc1101_regs.h"), + ], ) diff --git a/lib/drivers/bq25896.c b/lib/drivers/bq25896.c index 4c1d687cb024..76aae5e82369 100644 --- a/lib/drivers/bq25896.c +++ b/lib/drivers/bq25896.c @@ -35,13 +35,15 @@ typedef struct { static bq25896_regs_t bq25896_regs; -void bq25896_init(FuriHalI2cBusHandle* handle) { +bool bq25896_init(FuriHalI2cBusHandle* handle) { + bool result = true; + bq25896_regs.r14.REG_RST = 1; - furi_hal_i2c_write_reg_8( + result &= furi_hal_i2c_write_reg_8( handle, BQ25896_ADDRESS, 0x14, *(uint8_t*)&bq25896_regs.r14, BQ25896_I2C_TIMEOUT); // Readout all registers - furi_hal_i2c_read_mem( + result &= furi_hal_i2c_read_mem( handle, BQ25896_ADDRESS, 0x00, @@ -52,26 +54,34 @@ void bq25896_init(FuriHalI2cBusHandle* handle) { // Poll ADC forever bq25896_regs.r02.CONV_START = 1; bq25896_regs.r02.CONV_RATE = 1; - furi_hal_i2c_write_reg_8( + result &= furi_hal_i2c_write_reg_8( handle, BQ25896_ADDRESS, 0x02, *(uint8_t*)&bq25896_regs.r02, BQ25896_I2C_TIMEOUT); bq25896_regs.r07.WATCHDOG = WatchdogDisable; - furi_hal_i2c_write_reg_8( + result &= furi_hal_i2c_write_reg_8( handle, BQ25896_ADDRESS, 0x07, *(uint8_t*)&bq25896_regs.r07, BQ25896_I2C_TIMEOUT); // OTG power configuration bq25896_regs.r0A.BOOSTV = 0x8; // BOOST Voltage: 5.062V - bq25896_regs.r0A.BOOST_LIM = BOOST_LIM_1400; // BOOST Current limit: 1.4A - furi_hal_i2c_write_reg_8( + bq25896_regs.r0A.BOOST_LIM = BoostLim_1400; // BOOST Current limit: 1.4A + result &= furi_hal_i2c_write_reg_8( handle, BQ25896_ADDRESS, 0x0A, *(uint8_t*)&bq25896_regs.r0A, BQ25896_I2C_TIMEOUT); - furi_hal_i2c_read_mem( + result &= furi_hal_i2c_read_mem( handle, BQ25896_ADDRESS, 0x00, (uint8_t*)&bq25896_regs, sizeof(bq25896_regs), BQ25896_I2C_TIMEOUT); + + return result; +} + +void bq25896_set_boost_lim(FuriHalI2cBusHandle* handle, BoostLim boost_lim) { + bq25896_regs.r0A.BOOST_LIM = boost_lim; + furi_hal_i2c_write_reg_8( + handle, BQ25896_ADDRESS, 0x0A, *(uint8_t*)&bq25896_regs.r0A, BQ25896_I2C_TIMEOUT); } void bq25896_poweroff(FuriHalI2cBusHandle* handle) { diff --git a/lib/drivers/bq25896.h b/lib/drivers/bq25896.h index f3d1d0e0583e..d35625ab3f5e 100644 --- a/lib/drivers/bq25896.h +++ b/lib/drivers/bq25896.h @@ -7,7 +7,10 @@ #include /** Initialize Driver */ -void bq25896_init(FuriHalI2cBusHandle* handle); +bool bq25896_init(FuriHalI2cBusHandle* handle); + +/** Set boost lim*/ +void bq25896_set_boost_lim(FuriHalI2cBusHandle* handle, BoostLim boost_lim); /** Send device into shipping mode */ void bq25896_poweroff(FuriHalI2cBusHandle* handle); diff --git a/lib/drivers/bq25896_reg.h b/lib/drivers/bq25896_reg.h index 3cb3d71402da..a6ca3e1c77ee 100644 --- a/lib/drivers/bq25896_reg.h +++ b/lib/drivers/bq25896_reg.h @@ -159,14 +159,16 @@ typedef struct { #define BOOSTV_128 (1 << 1) #define BOOSTV_64 (1 << 0) -#define BOOST_LIM_500 (0b000) -#define BOOST_LIM_750 (0b001) -#define BOOST_LIM_1200 (0b010) -#define BOOST_LIM_1400 (0b011) -#define BOOST_LIM_1650 (0b100) -#define BOOST_LIM_1875 (0b101) -#define BOOST_LIM_2150 (0b110) -#define BOOST_LIM_RSVD (0b111) +typedef enum { + BoostLim_500 = 0b000, + BoostLim_750 = 0b001, + BoostLim_1200 = 0b010, + BoostLim_1400 = 0b011, + BoostLim_1650 = 0b100, + BoostLim_1875 = 0b101, + BoostLim_2150 = 0b110, + BoostLim_Rsvd = 0b111, +} BoostLim; typedef struct { uint8_t BOOST_LIM : 3; // Boost Mode Current Limit diff --git a/lib/drivers/bq27220.c b/lib/drivers/bq27220.c index f64120fa83ec..92dbfcd6a29a 100644 --- a/lib/drivers/bq27220.c +++ b/lib/drivers/bq27220.c @@ -1,12 +1,16 @@ + #include "bq27220.h" #include "bq27220_reg.h" +#include "bq27220_data_memory.h" + +_Static_assert(sizeof(BQ27220DMGaugingConfig) == 2, "Incorrect structure size"); #include #include #define TAG "Gauge" -uint16_t bq27220_read_word(FuriHalI2cBusHandle* handle, uint8_t address) { +static uint16_t bq27220_read_word(FuriHalI2cBusHandle* handle, uint8_t address) { uint16_t buf = 0; furi_hal_i2c_read_mem( @@ -15,14 +19,14 @@ uint16_t bq27220_read_word(FuriHalI2cBusHandle* handle, uint8_t address) { return buf; } -bool bq27220_control(FuriHalI2cBusHandle* handle, uint16_t control) { +static bool bq27220_control(FuriHalI2cBusHandle* handle, uint16_t control) { bool ret = furi_hal_i2c_write_mem( handle, BQ27220_ADDRESS, CommandControl, (uint8_t*)&control, 2, BQ27220_I2C_TIMEOUT); return ret; } -uint8_t bq27220_get_checksum(uint8_t* data, uint16_t len) { +static uint8_t bq27220_get_checksum(uint8_t* data, uint16_t len) { uint8_t ret = 0; for(uint16_t i = 0; i < len; i++) { ret += data[i]; @@ -30,80 +34,181 @@ uint8_t bq27220_get_checksum(uint8_t* data, uint16_t len) { return 0xFF - ret; } -bool bq27220_set_parameter_u16(FuriHalI2cBusHandle* handle, uint16_t address, uint16_t value) { - bool ret; - uint8_t buffer[4]; +static bool bq27220_parameter_check( + FuriHalI2cBusHandle* handle, + uint16_t address, + uint32_t value, + size_t size, + bool update) { + furi_assert(size == 1 || size == 2 || size == 4); + bool ret = false; + uint8_t buffer[6] = {0}; + uint8_t old_data[4] = {0}; + + do { + buffer[0] = address & 0xFF; + buffer[1] = (address >> 8) & 0xFF; + + for(size_t i = 0; i < size; i++) { + buffer[1 + size - i] = (value >> (i * 8)) & 0xFF; + } - buffer[0] = address & 0xFF; - buffer[1] = (address >> 8) & 0xFF; - buffer[2] = (value >> 8) & 0xFF; - buffer[3] = value & 0xFF; - ret = furi_hal_i2c_write_mem( - handle, BQ27220_ADDRESS, CommandSelectSubclass, buffer, 4, BQ27220_I2C_TIMEOUT); + if(update) { + if(!furi_hal_i2c_write_mem( + handle, + BQ27220_ADDRESS, + CommandSelectSubclass, + buffer, + size + 2, + BQ27220_I2C_TIMEOUT)) { + FURI_LOG_I(TAG, "DM write failed"); + break; + } - furi_delay_us(10000); + furi_delay_us(10000); - uint8_t checksum = bq27220_get_checksum(buffer, 4); - buffer[0] = checksum; - buffer[1] = 6; - ret &= furi_hal_i2c_write_mem( - handle, BQ27220_ADDRESS, CommandMACDataSum, buffer, 2, BQ27220_I2C_TIMEOUT); + uint8_t checksum = bq27220_get_checksum(buffer, size + 2); + buffer[0] = checksum; + buffer[1] = 4 + size; // TODO: why 4? + if(!furi_hal_i2c_write_mem( + handle, BQ27220_ADDRESS, CommandMACDataSum, buffer, 2, BQ27220_I2C_TIMEOUT)) { + FURI_LOG_I(TAG, "CRC write failed"); + break; + } + + furi_delay_us(10000); + ret = true; + } else { + if(!furi_hal_i2c_write_mem( + handle, BQ27220_ADDRESS, CommandSelectSubclass, buffer, 2, BQ27220_I2C_TIMEOUT)) { + FURI_LOG_I(TAG, "DM SelectSubclass for read failed"); + break; + } + + if(!furi_hal_i2c_rx(handle, BQ27220_ADDRESS, old_data, size, BQ27220_I2C_TIMEOUT)) { + FURI_LOG_I(TAG, "DM read failed"); + break; + } + + if(*(uint32_t*)&(old_data[0]) != *(uint32_t*)&(buffer[2])) { + FURI_LOG_W( //-V641 + TAG, + "Data at 0x%04x(%zu): 0x%08lx!=0x%08lx", + address, + size, + *(uint32_t*)&(old_data[0]), + *(uint32_t*)&(buffer[2])); + } else { + ret = true; + } + } + } while(0); - furi_delay_us(10000); return ret; } -bool bq27220_init(FuriHalI2cBusHandle* handle, const ParamCEDV* cedv) { - uint32_t timeout = 100; - uint16_t design_cap = bq27220_get_design_capacity(handle); - if(cedv->design_cap == design_cap) { - FURI_LOG_I(TAG, "Skip battery profile update"); - return true; +static bool bq27220_data_memory_check( + FuriHalI2cBusHandle* handle, + const BQ27220DMData* data_memory, + bool update) { + if(update) { + if(!bq27220_control(handle, Control_ENTER_CFG_UPDATE)) { + FURI_LOG_E(TAG, "ENTER_CFG_UPDATE command failed"); + return false; + }; + + // Wait for enter CFG update mode + uint32_t timeout = 100; + OperationStatus status = {0}; + while((status.CFGUPDATE != true) && (timeout-- > 0)) { + bq27220_get_operation_status(handle, &status); + } + + if(timeout == 0) { + FURI_LOG_E(TAG, "CFGUPDATE mode failed"); + return false; + } } - FURI_LOG_I(TAG, "Start updating battery profile"); - OperationStatus status = {0}; - if(!bq27220_control(handle, Control_ENTER_CFG_UPDATE)) { - FURI_LOG_E(TAG, "Can't configure update"); - return false; - }; - while((status.CFGUPDATE != true) && (timeout-- > 0)) { - bq27220_get_operation_status(handle, &status); + // Process data memory records + bool result = true; + while(data_memory->type != BQ27220DMTypeEnd) { + if(data_memory->type == BQ27220DMTypeWait) { + furi_delay_us(data_memory->value.u32); + } else if(data_memory->type == BQ27220DMTypeU8) { + result &= bq27220_parameter_check( + handle, data_memory->address, data_memory->value.u8, 1, update); + } else if(data_memory->type == BQ27220DMTypeU16) { + result &= bq27220_parameter_check( + handle, data_memory->address, data_memory->value.u16, 2, update); + } else if(data_memory->type == BQ27220DMTypeU32) { + result &= bq27220_parameter_check( + handle, data_memory->address, data_memory->value.u32, 4, update); + } else if(data_memory->type == BQ27220DMTypeI8) { + result &= bq27220_parameter_check( + handle, data_memory->address, data_memory->value.i8, 1, update); + } else if(data_memory->type == BQ27220DMTypeI16) { + result &= bq27220_parameter_check( + handle, data_memory->address, data_memory->value.i16, 2, update); + } else if(data_memory->type == BQ27220DMTypeI32) { + result &= bq27220_parameter_check( + handle, data_memory->address, data_memory->value.i32, 4, update); + } else if(data_memory->type == BQ27220DMTypeF32) { + result &= bq27220_parameter_check( + handle, data_memory->address, data_memory->value.u32, 4, update); + } else if(data_memory->type == BQ27220DMTypePtr8) { + result &= bq27220_parameter_check( + handle, data_memory->address, *(uint8_t*)data_memory->value.u32, 1, update); + } else if(data_memory->type == BQ27220DMTypePtr16) { + result &= bq27220_parameter_check( + handle, data_memory->address, *(uint16_t*)data_memory->value.u32, 2, update); + } else if(data_memory->type == BQ27220DMTypePtr32) { + result &= bq27220_parameter_check( + handle, data_memory->address, *(uint32_t*)data_memory->value.u32, 4, update); + } else { + furi_crash("Invalid DM Type"); + } + data_memory++; } - bq27220_set_parameter_u16(handle, AddressGaugingConfig, cedv->cedv_conf.gauge_conf_raw); - bq27220_set_parameter_u16(handle, AddressFullChargeCapacity, cedv->full_charge_cap); - bq27220_set_parameter_u16(handle, AddressDesignCapacity, cedv->design_cap); - bq27220_set_parameter_u16(handle, AddressEMF, cedv->EMF); - bq27220_set_parameter_u16(handle, AddressC0, cedv->C0); - bq27220_set_parameter_u16(handle, AddressR0, cedv->R0); - bq27220_set_parameter_u16(handle, AddressT0, cedv->T0); - bq27220_set_parameter_u16(handle, AddressR1, cedv->R1); - bq27220_set_parameter_u16(handle, AddressTC, (cedv->TC) << 8 | cedv->C1); - bq27220_set_parameter_u16(handle, AddressStartDOD0, cedv->DOD0); - bq27220_set_parameter_u16(handle, AddressStartDOD10, cedv->DOD10); - bq27220_set_parameter_u16(handle, AddressStartDOD20, cedv->DOD20); - bq27220_set_parameter_u16(handle, AddressStartDOD30, cedv->DOD30); - bq27220_set_parameter_u16(handle, AddressStartDOD40, cedv->DOD40); - bq27220_set_parameter_u16(handle, AddressStartDOD50, cedv->DOD40); - bq27220_set_parameter_u16(handle, AddressStartDOD60, cedv->DOD60); - bq27220_set_parameter_u16(handle, AddressStartDOD70, cedv->DOD70); - bq27220_set_parameter_u16(handle, AddressStartDOD80, cedv->DOD80); - bq27220_set_parameter_u16(handle, AddressStartDOD90, cedv->DOD90); - bq27220_set_parameter_u16(handle, AddressStartDOD100, cedv->DOD100); - bq27220_set_parameter_u16(handle, AddressEDV0, cedv->EDV0); - bq27220_set_parameter_u16(handle, AddressEDV1, cedv->EDV1); - bq27220_set_parameter_u16(handle, AddressEDV2, cedv->EDV2); - - bq27220_control(handle, Control_EXIT_CFG_UPDATE_REINIT); - furi_delay_us(10000); - design_cap = bq27220_get_design_capacity(handle); - if(cedv->design_cap == design_cap) { - FURI_LOG_I(TAG, "Battery profile update success"); - return true; - } else { - FURI_LOG_E(TAG, "Battery profile update failed"); + + // Finalize configuration update + if(update) { + bq27220_control(handle, Control_EXIT_CFG_UPDATE_REINIT); + furi_delay_us(10000); + } + + return result; +} + +bool bq27220_init(FuriHalI2cBusHandle* handle) { + // Request device number(chip PN) + if(!bq27220_control(handle, Control_DEVICE_NUMBER)) { + FURI_LOG_E(TAG, "Device is not present"); + return false; + }; + // Check control response + uint16_t data = 0; + data = bq27220_read_word(handle, CommandControl); + if(data != 0xFF00) { + FURI_LOG_E(TAG, "Invalid control response: %x", data); return false; + }; + + data = bq27220_read_word(handle, CommandMACData); + FURI_LOG_I(TAG, "Device Number %04x", data); + + return data == 0x0220; +} + +bool bq27220_apply_data_memory(FuriHalI2cBusHandle* handle, const BQ27220DMData* data_memory) { + FURI_LOG_I(TAG, "Verifying data memory"); + if(!bq27220_data_memory_check(handle, data_memory, false)) { + FURI_LOG_I(TAG, "Updating data memory"); + bq27220_data_memory_check(handle, data_memory, true); } + FURI_LOG_I(TAG, "Data memory verification complete"); + + return true; } uint16_t bq27220_get_voltage(FuriHalI2cBusHandle* handle) { @@ -114,24 +219,23 @@ int16_t bq27220_get_current(FuriHalI2cBusHandle* handle) { return bq27220_read_word(handle, CommandCurrent); } -uint8_t bq27220_get_battery_status(FuriHalI2cBusHandle* handle, BatteryStatus* battery_status) { +bool bq27220_get_battery_status(FuriHalI2cBusHandle* handle, BatteryStatus* battery_status) { uint16_t data = bq27220_read_word(handle, CommandBatteryStatus); if(data == BQ27220_ERROR) { - return BQ27220_ERROR; + return false; } else { *(uint16_t*)battery_status = data; - return BQ27220_SUCCESS; + return true; } } -uint8_t - bq27220_get_operation_status(FuriHalI2cBusHandle* handle, OperationStatus* operation_status) { +bool bq27220_get_operation_status(FuriHalI2cBusHandle* handle, OperationStatus* operation_status) { uint16_t data = bq27220_read_word(handle, CommandOperationStatus); if(data == BQ27220_ERROR) { - return BQ27220_ERROR; + return false; } else { *(uint16_t*)operation_status = data; - return BQ27220_SUCCESS; + return true; } } diff --git a/lib/drivers/bq27220.h b/lib/drivers/bq27220.h index c822301a4796..ca9e0312e87e 100644 --- a/lib/drivers/bq27220.h +++ b/lib/drivers/bq27220.h @@ -47,60 +47,17 @@ typedef struct { _Static_assert(sizeof(OperationStatus) == 2, "Incorrect structure size"); -typedef struct { - // Low byte, Low bit first - bool CCT : 1; - bool CSYNC : 1; - bool RSVD0 : 1; - bool EDV_CMP : 1; - bool SC : 1; - bool FIXED_EDV0 : 1; - uint8_t RSVD1 : 2; - // High byte, Low bit first - bool FCC_LIM : 1; - bool RSVD2 : 1; - bool FC_FOR_VDQ : 1; - bool IGNORE_SD : 1; - bool SME0 : 1; - uint8_t RSVD3 : 3; -} GaugingConfig; - -_Static_assert(sizeof(GaugingConfig) == 2, "Incorrect structure size"); +typedef struct BQ27220DMData BQ27220DMData; -typedef struct { - union { - GaugingConfig gauge_conf; - uint16_t gauge_conf_raw; - } cedv_conf; - uint16_t full_charge_cap; - uint16_t design_cap; - uint16_t EDV0; - uint16_t EDV1; - uint16_t EDV2; - uint16_t EMF; - uint16_t C0; - uint16_t R0; - uint16_t T0; - uint16_t R1; - uint8_t TC; - uint8_t C1; - uint16_t DOD0; - uint16_t DOD10; - uint16_t DOD20; - uint16_t DOD30; - uint16_t DOD40; - uint16_t DOD50; - uint16_t DOD60; - uint16_t DOD70; - uint16_t DOD80; - uint16_t DOD90; - uint16_t DOD100; -} ParamCEDV; +/** Initialize Driver + * @return true on success, false otherwise + */ +bool bq27220_init(FuriHalI2cBusHandle* handle); /** Initialize Driver * @return true on success, false otherwise */ -bool bq27220_init(FuriHalI2cBusHandle* handle, const ParamCEDV* cedv); +bool bq27220_apply_data_memory(FuriHalI2cBusHandle* handle, const BQ27220DMData* data_memory); /** Get battery voltage in mV or error */ uint16_t bq27220_get_voltage(FuriHalI2cBusHandle* handle); @@ -109,11 +66,10 @@ uint16_t bq27220_get_voltage(FuriHalI2cBusHandle* handle); int16_t bq27220_get_current(FuriHalI2cBusHandle* handle); /** Get battery status */ -uint8_t bq27220_get_battery_status(FuriHalI2cBusHandle* handle, BatteryStatus* battery_status); +bool bq27220_get_battery_status(FuriHalI2cBusHandle* handle, BatteryStatus* battery_status); /** Get operation status */ -uint8_t - bq27220_get_operation_status(FuriHalI2cBusHandle* handle, OperationStatus* operation_status); +bool bq27220_get_operation_status(FuriHalI2cBusHandle* handle, OperationStatus* operation_status); /** Get temperature in units of 0.1°K */ uint16_t bq27220_get_temperature(FuriHalI2cBusHandle* handle); diff --git a/lib/drivers/bq27220_data_memory.h b/lib/drivers/bq27220_data_memory.h new file mode 100644 index 000000000000..ae00be883600 --- /dev/null +++ b/lib/drivers/bq27220_data_memory.h @@ -0,0 +1,84 @@ +#pragma once + +#include +#include + +typedef enum { + BQ27220DMTypeEnd, + BQ27220DMTypeWait, + BQ27220DMTypeU8, + BQ27220DMTypeU16, + BQ27220DMTypeU32, + BQ27220DMTypeI8, + BQ27220DMTypeI16, + BQ27220DMTypeI32, + BQ27220DMTypeF32, + BQ27220DMTypePtr8, + BQ27220DMTypePtr16, + BQ27220DMTypePtr32, +} BQ27220DMType; + +typedef enum { + BQ27220DMAddressGasGaugingCEDVProfile1GaugingConfig = 0x929B, + BQ27220DMAddressGasGaugingCEDVProfile1FullChargeCapacity = 0x929D, + BQ27220DMAddressGasGaugingCEDVProfile1DesignCapacity = 0x929F, + BQ27220DMAddressGasGaugingCEDVProfile1EMF = 0x92A3, + BQ27220DMAddressGasGaugingCEDVProfile1C0 = 0x92A9, + BQ27220DMAddressGasGaugingCEDVProfile1R0 = 0x92AB, + BQ27220DMAddressGasGaugingCEDVProfile1T0 = 0x92AD, + BQ27220DMAddressGasGaugingCEDVProfile1R1 = 0x92AF, + BQ27220DMAddressGasGaugingCEDVProfile1TC = 0x92B1, + BQ27220DMAddressGasGaugingCEDVProfile1C1 = 0x92B2, + BQ27220DMAddressGasGaugingCEDVProfile1EDV0 = 0x92B4, + BQ27220DMAddressGasGaugingCEDVProfile1EDV1 = 0x92B7, + BQ27220DMAddressGasGaugingCEDVProfile1EDV2 = 0x92BA, + BQ27220DMAddressGasGaugingCEDVProfile1StartDOD0 = 0x92BD, + BQ27220DMAddressGasGaugingCEDVProfile1StartDOD10 = 0x92BF, + BQ27220DMAddressGasGaugingCEDVProfile1StartDOD20 = 0x92C1, + BQ27220DMAddressGasGaugingCEDVProfile1StartDOD30 = 0x92C3, + BQ27220DMAddressGasGaugingCEDVProfile1StartDOD40 = 0x92C5, + BQ27220DMAddressGasGaugingCEDVProfile1StartDOD50 = 0x92C7, + BQ27220DMAddressGasGaugingCEDVProfile1StartDOD60 = 0x92C9, + BQ27220DMAddressGasGaugingCEDVProfile1StartDOD70 = 0x92CB, + BQ27220DMAddressGasGaugingCEDVProfile1StartDOD80 = 0x92CD, + BQ27220DMAddressGasGaugingCEDVProfile1StartDOD90 = 0x92CF, + BQ27220DMAddressGasGaugingCEDVProfile1StartDOD100 = 0x92D1, + BQ27220DMAddressCalibrationCurrentDeadband = 0x91DE, + BQ27220DMAddressConfigurationPowerSleepCurrent = 0x9217, + BQ27220DMAddressConfigurationCurrentThresholdsDischargeDetectionThreshold = 0x9228, + BQ27220DMAddressConfigurationDataInitialStandby = 0x923C, +} BQ27220DMAddress; + +typedef struct BQ27220DMData BQ27220DMData; + +struct BQ27220DMData { + uint16_t type; + uint16_t address; + union { + uint8_t u8; + uint16_t u16; + uint32_t u32; + int8_t i8; + int16_t i16; + int32_t i32; + float f32; + } value; +}; + +typedef struct { + // Low byte, Low bit first + const bool CCT : 1; + const bool CSYNC : 1; + const bool RSVD0 : 1; + const bool EDV_CMP : 1; + const bool SC : 1; + const bool FIXED_EDV0 : 1; + const uint8_t RSVD1 : 2; + // High byte, Low bit first + const bool FCC_LIM : 1; + const bool RSVD2 : 1; + const bool FC_FOR_VDQ : 1; + const bool IGNORE_SD : 1; + const bool SME0 : 1; + const uint8_t RSVD3 : 3; +} BQ27220DMGaugingConfig; diff --git a/lib/drivers/bq27220_reg.h b/lib/drivers/bq27220_reg.h index fa81b66eb4ad..2e6e54aabef2 100644 --- a/lib/drivers/bq27220_reg.h +++ b/lib/drivers/bq27220_reg.h @@ -66,28 +66,3 @@ #define Control_EXIT_CFG_UPDATE_REINIT 0x0091 #define Control_EXIT_CFG_UPDATE 0x0092 #define Control_RETURN_TO_ROM 0x0F00 - -#define AddressGaugingConfig 0x929B -#define AddressFullChargeCapacity 0x929D -#define AddressDesignCapacity 0x929F -#define AddressEMF 0x92A3 -#define AddressC0 0x92A9 -#define AddressR0 0x92AB -#define AddressT0 0x92AD -#define AddressR1 0x92AF -#define AddressTC 0x92B1 -#define AddressC1 0x92B2 -#define AddressEDV0 0x92B4 -#define AddressEDV1 0x92B7 -#define AddressEDV2 0x92BA -#define AddressStartDOD0 0x92BD -#define AddressStartDOD10 0x92BF -#define AddressStartDOD20 0x92C1 -#define AddressStartDOD30 0x92C3 -#define AddressStartDOD40 0x92C5 -#define AddressStartDOD50 0x92C7 -#define AddressStartDOD60 0x92C9 -#define AddressStartDOD70 0x92CB -#define AddressStartDOD80 0x92CD -#define AddressStartDOD90 0x92CF -#define AddressStartDOD100 0x92D1 diff --git a/lib/drivers/cc1101.c b/lib/drivers/cc1101.c index d0feb0218785..85d915acdcce 100644 --- a/lib/drivers/cc1101.c +++ b/lib/drivers/cc1101.c @@ -1,14 +1,27 @@ #include "cc1101.h" #include #include +#include + +static bool cc1101_spi_trx(FuriHalSpiBusHandle* handle, uint8_t* tx, uint8_t* rx, uint8_t size) { + FuriHalCortexTimer timer = furi_hal_cortex_timer_get(CC1101_TIMEOUT * 1000); + + while(furi_hal_gpio_read(handle->miso)) { + if(furi_hal_cortex_timer_is_expired(timer)) { + //timeout + return false; + } + } + if(!furi_hal_spi_bus_trx(handle, tx, rx, size, CC1101_TIMEOUT)) return false; + return true; +} CC1101Status cc1101_strobe(FuriHalSpiBusHandle* handle, uint8_t strobe) { uint8_t tx[1] = {strobe}; CC1101Status rx[1] = {0}; + rx[0].CHIP_RDYn = 1; - while(furi_hal_gpio_read(handle->miso)) - ; - furi_hal_spi_bus_trx(handle, tx, (uint8_t*)rx, 1, CC1101_TIMEOUT); + cc1101_spi_trx(handle, tx, (uint8_t*)rx, 1); assert(rx[0].CHIP_RDYn == 0); return rx[0]; @@ -17,10 +30,10 @@ CC1101Status cc1101_strobe(FuriHalSpiBusHandle* handle, uint8_t strobe) { CC1101Status cc1101_write_reg(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t data) { uint8_t tx[2] = {reg, data}; CC1101Status rx[2] = {0}; + rx[0].CHIP_RDYn = 1; + rx[1].CHIP_RDYn = 1; - while(furi_hal_gpio_read(handle->miso)) - ; - furi_hal_spi_bus_trx(handle, tx, (uint8_t*)rx, 2, CC1101_TIMEOUT); + cc1101_spi_trx(handle, tx, (uint8_t*)rx, 2); assert((rx[0].CHIP_RDYn | rx[1].CHIP_RDYn) == 0); return rx[1]; @@ -30,10 +43,9 @@ CC1101Status cc1101_read_reg(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t* assert(sizeof(CC1101Status) == 1); uint8_t tx[2] = {reg | CC1101_READ, 0}; CC1101Status rx[2] = {0}; + rx[0].CHIP_RDYn = 1; - while(furi_hal_gpio_read(handle->miso)) - ; - furi_hal_spi_bus_trx(handle, tx, (uint8_t*)rx, 2, CC1101_TIMEOUT); + cc1101_spi_trx(handle, tx, (uint8_t*)rx, 2); assert((rx[0].CHIP_RDYn) == 0); *data = *(uint8_t*)&rx[1]; @@ -58,40 +70,40 @@ uint8_t cc1101_get_rssi(FuriHalSpiBusHandle* handle) { return rssi; } -void cc1101_reset(FuriHalSpiBusHandle* handle) { - cc1101_strobe(handle, CC1101_STROBE_SRES); +CC1101Status cc1101_reset(FuriHalSpiBusHandle* handle) { + return cc1101_strobe(handle, CC1101_STROBE_SRES); } CC1101Status cc1101_get_status(FuriHalSpiBusHandle* handle) { return cc1101_strobe(handle, CC1101_STROBE_SNOP); } -void cc1101_shutdown(FuriHalSpiBusHandle* handle) { - cc1101_strobe(handle, CC1101_STROBE_SPWD); +CC1101Status cc1101_shutdown(FuriHalSpiBusHandle* handle) { + return cc1101_strobe(handle, CC1101_STROBE_SPWD); } -void cc1101_calibrate(FuriHalSpiBusHandle* handle) { - cc1101_strobe(handle, CC1101_STROBE_SCAL); +CC1101Status cc1101_calibrate(FuriHalSpiBusHandle* handle) { + return cc1101_strobe(handle, CC1101_STROBE_SCAL); } -void cc1101_switch_to_idle(FuriHalSpiBusHandle* handle) { - cc1101_strobe(handle, CC1101_STROBE_SIDLE); +CC1101Status cc1101_switch_to_idle(FuriHalSpiBusHandle* handle) { + return cc1101_strobe(handle, CC1101_STROBE_SIDLE); } -void cc1101_switch_to_rx(FuriHalSpiBusHandle* handle) { - cc1101_strobe(handle, CC1101_STROBE_SRX); +CC1101Status cc1101_switch_to_rx(FuriHalSpiBusHandle* handle) { + return cc1101_strobe(handle, CC1101_STROBE_SRX); } -void cc1101_switch_to_tx(FuriHalSpiBusHandle* handle) { - cc1101_strobe(handle, CC1101_STROBE_STX); +CC1101Status cc1101_switch_to_tx(FuriHalSpiBusHandle* handle) { + return cc1101_strobe(handle, CC1101_STROBE_STX); } -void cc1101_flush_rx(FuriHalSpiBusHandle* handle) { - cc1101_strobe(handle, CC1101_STROBE_SFRX); +CC1101Status cc1101_flush_rx(FuriHalSpiBusHandle* handle) { + return cc1101_strobe(handle, CC1101_STROBE_SFRX); } -void cc1101_flush_tx(FuriHalSpiBusHandle* handle) { - cc1101_strobe(handle, CC1101_STROBE_SFTX); +CC1101Status cc1101_flush_tx(FuriHalSpiBusHandle* handle) { + return cc1101_strobe(handle, CC1101_STROBE_SFTX); } uint32_t cc1101_set_frequency(FuriHalSpiBusHandle* handle, uint32_t value) { @@ -123,12 +135,12 @@ uint32_t cc1101_set_intermediate_frequency(FuriHalSpiBusHandle* handle, uint32_t void cc1101_set_pa_table(FuriHalSpiBusHandle* handle, const uint8_t value[8]) { uint8_t tx[9] = {CC1101_PATABLE | CC1101_BURST}; //-V1009 CC1101Status rx[9] = {0}; + rx[0].CHIP_RDYn = 1; + rx[8].CHIP_RDYn = 1; memcpy(&tx[1], &value[0], 8); - while(furi_hal_gpio_read(handle->miso)) - ; - furi_hal_spi_bus_trx(handle, tx, (uint8_t*)rx, sizeof(rx), CC1101_TIMEOUT); + cc1101_spi_trx(handle, tx, (uint8_t*)rx, sizeof(rx)); assert((rx[0].CHIP_RDYn | rx[8].CHIP_RDYn) == 0); } @@ -139,12 +151,7 @@ uint8_t cc1101_write_fifo(FuriHalSpiBusHandle* handle, const uint8_t* data, uint buff_tx[0] = CC1101_FIFO | CC1101_BURST; memcpy(&buff_tx[1], data, size); - // Start transaction - // Wait IC to become ready - while(furi_hal_gpio_read(handle->miso)) - ; - // Tell IC what we want - furi_hal_spi_bus_trx(handle, buff_tx, (uint8_t*)buff_rx, size + 1, CC1101_TIMEOUT); + cc1101_spi_trx(handle, buff_tx, (uint8_t*)buff_rx, size + 1); return size; } @@ -153,13 +160,7 @@ uint8_t cc1101_read_fifo(FuriHalSpiBusHandle* handle, uint8_t* data, uint8_t* si uint8_t buff_trx[2]; buff_trx[0] = CC1101_FIFO | CC1101_READ | CC1101_BURST; - // Start transaction - // Wait IC to become ready - while(furi_hal_gpio_read(handle->miso)) - ; - - // First byte - packet length - furi_hal_spi_bus_trx(handle, buff_trx, buff_trx, 2, CC1101_TIMEOUT); + cc1101_spi_trx(handle, buff_trx, buff_trx, 2); // Check that the packet is placed in the receive buffer if(buff_trx[1] > 64) { diff --git a/lib/drivers/cc1101.h b/lib/drivers/cc1101.h index af1f15569d1c..d8ee05d5289a 100644 --- a/lib/drivers/cc1101.h +++ b/lib/drivers/cc1101.h @@ -46,8 +46,10 @@ CC1101Status cc1101_read_reg(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t* /** Reset * * @param handle - pointer to FuriHalSpiHandle + * + * @return CC1101Status structure */ -void cc1101_reset(FuriHalSpiBusHandle* handle); +CC1101Status cc1101_reset(FuriHalSpiBusHandle* handle); /** Get status * @@ -60,8 +62,10 @@ CC1101Status cc1101_get_status(FuriHalSpiBusHandle* handle); /** Enable shutdown mode * * @param handle - pointer to FuriHalSpiHandle + * + * @return CC1101Status structure */ -void cc1101_shutdown(FuriHalSpiBusHandle* handle); +CC1101Status cc1101_shutdown(FuriHalSpiBusHandle* handle); /** Get Partnumber * @@ -90,38 +94,46 @@ uint8_t cc1101_get_rssi(FuriHalSpiBusHandle* handle); /** Calibrate oscillator * * @param handle - pointer to FuriHalSpiHandle + * + * @return CC1101Status structure */ -void cc1101_calibrate(FuriHalSpiBusHandle* handle); +CC1101Status cc1101_calibrate(FuriHalSpiBusHandle* handle); /** Switch to idle * * @param handle - pointer to FuriHalSpiHandle */ -void cc1101_switch_to_idle(FuriHalSpiBusHandle* handle); +CC1101Status cc1101_switch_to_idle(FuriHalSpiBusHandle* handle); /** Switch to RX * * @param handle - pointer to FuriHalSpiHandle + * + * @return CC1101Status structure */ -void cc1101_switch_to_rx(FuriHalSpiBusHandle* handle); +CC1101Status cc1101_switch_to_rx(FuriHalSpiBusHandle* handle); /** Switch to TX * * @param handle - pointer to FuriHalSpiHandle + * + * @return CC1101Status structure */ -void cc1101_switch_to_tx(FuriHalSpiBusHandle* handle); +CC1101Status cc1101_switch_to_tx(FuriHalSpiBusHandle* handle); /** Flush RX FIFO * * @param handle - pointer to FuriHalSpiHandle + * + * @return CC1101Status structure */ -void cc1101_flush_rx(FuriHalSpiBusHandle* handle); +CC1101Status cc1101_flush_rx(FuriHalSpiBusHandle* handle); /** Flush TX FIFO * * @param handle - pointer to FuriHalSpiHandle */ -void cc1101_flush_tx(FuriHalSpiBusHandle* handle); +CC1101Status cc1101_flush_tx(FuriHalSpiBusHandle* handle); /** Set Frequency * diff --git a/lib/drivers/cc1101_regs.h b/lib/drivers/cc1101_regs.h index a326dc92ce80..e0aed6bd93c8 100644 --- a/lib/drivers/cc1101_regs.h +++ b/lib/drivers/cc1101_regs.h @@ -14,7 +14,7 @@ extern "C" { #define CC1101_IFDIV 0x400 /* IO Bus constants */ -#define CC1101_TIMEOUT 500 +#define CC1101_TIMEOUT 250 /* Bits and pieces */ #define CC1101_READ (1 << 7) /** Read Bit */ diff --git a/lib/infrared/encoder_decoder/infrared.c b/lib/infrared/encoder_decoder/infrared.c index fcfc5da2b22a..56f2c3f9ee68 100644 --- a/lib/infrared/encoder_decoder/infrared.c +++ b/lib/infrared/encoder_decoder/infrared.c @@ -11,6 +11,7 @@ #include "rc6/infrared_protocol_rc6.h" #include "sirc/infrared_protocol_sirc.h" #include "kaseikyo/infrared_protocol_kaseikyo.h" +#include "rca/infrared_protocol_rca.h" typedef struct { InfraredAlloc alloc; @@ -127,6 +128,20 @@ static const InfraredEncoderDecoder infrared_encoder_decoder[] = { .free = infrared_encoder_kaseikyo_free}, .get_protocol_variant = infrared_protocol_kaseikyo_get_variant, }, + { + .decoder = + {.alloc = infrared_decoder_rca_alloc, + .decode = infrared_decoder_rca_decode, + .reset = infrared_decoder_rca_reset, + .check_ready = infrared_decoder_rca_check_ready, + .free = infrared_decoder_rca_free}, + .encoder = + {.alloc = infrared_encoder_rca_alloc, + .encode = infrared_encoder_rca_encode, + .reset = infrared_encoder_rca_reset, + .free = infrared_encoder_rca_free}, + .get_protocol_variant = infrared_protocol_rca_get_variant, + }, }; static int infrared_find_index_by_protocol(InfraredProtocol protocol); diff --git a/lib/infrared/encoder_decoder/infrared.h b/lib/infrared/encoder_decoder/infrared.h index 3ab46cbbf566..ada449b98317 100644 --- a/lib/infrared/encoder_decoder/infrared.h +++ b/lib/infrared/encoder_decoder/infrared.h @@ -33,6 +33,7 @@ typedef enum { InfraredProtocolSIRC15, InfraredProtocolSIRC20, InfraredProtocolKaseikyo, + InfraredProtocolRCA, InfraredProtocolMAX, } InfraredProtocol; diff --git a/lib/infrared/encoder_decoder/rca/infrared_decoder_rca.c b/lib/infrared/encoder_decoder/rca/infrared_decoder_rca.c new file mode 100644 index 000000000000..b6d02a38c77f --- /dev/null +++ b/lib/infrared/encoder_decoder/rca/infrared_decoder_rca.c @@ -0,0 +1,45 @@ +#include "infrared_protocol_rca_i.h" +#include + +InfraredMessage* infrared_decoder_rca_check_ready(void* ctx) { + return infrared_common_decoder_check_ready(ctx); +} + +bool infrared_decoder_rca_interpret(InfraredCommonDecoder* decoder) { + furi_assert(decoder); + + uint32_t* data = (void*)&decoder->data; + + uint8_t address = (*data & 0xF); + uint8_t command = (*data >> 4) & 0xFF; + uint8_t address_inverse = (*data >> 12) & 0xF; + uint8_t command_inverse = (*data >> 16) & 0xFF; + uint8_t inverse_address_inverse = (uint8_t)~address_inverse & 0xF; + uint8_t inverse_command_inverse = (uint8_t)~command_inverse; + + if((command == inverse_command_inverse) && (address == inverse_address_inverse)) { + decoder->message.protocol = InfraredProtocolRCA; + decoder->message.address = address; + decoder->message.command = command; + decoder->message.repeat = false; + return true; + } + + return false; +} + +void* infrared_decoder_rca_alloc(void) { + return infrared_common_decoder_alloc(&infrared_protocol_rca); +} + +InfraredMessage* infrared_decoder_rca_decode(void* decoder, bool level, uint32_t duration) { + return infrared_common_decode(decoder, level, duration); +} + +void infrared_decoder_rca_free(void* decoder) { + infrared_common_decoder_free(decoder); +} + +void infrared_decoder_rca_reset(void* decoder) { + infrared_common_decoder_reset(decoder); +} diff --git a/lib/infrared/encoder_decoder/rca/infrared_encoder_rca.c b/lib/infrared/encoder_decoder/rca/infrared_encoder_rca.c new file mode 100644 index 000000000000..f0be4a6a9e21 --- /dev/null +++ b/lib/infrared/encoder_decoder/rca/infrared_encoder_rca.c @@ -0,0 +1,37 @@ +#include "infrared_protocol_rca_i.h" + +#include + +void infrared_encoder_rca_reset(void* encoder_ptr, const InfraredMessage* message) { + furi_assert(encoder_ptr); + furi_assert(message); + + InfraredCommonEncoder* encoder = encoder_ptr; + infrared_common_encoder_reset(encoder); + + uint32_t* data = (void*)encoder->data; + + uint8_t address = message->address; + uint8_t address_inverse = ~address; + uint8_t command = message->command; + uint8_t command_inverse = ~command; + + *data = address & 0xF; + *data |= command << 4; + *data |= (address_inverse & 0xF) << 12; + *data |= command_inverse << 16; + + encoder->bits_to_encode = encoder->protocol->databit_len[0]; +} + +void* infrared_encoder_rca_alloc(void) { + return infrared_common_encoder_alloc(&infrared_protocol_rca); +} + +void infrared_encoder_rca_free(void* encoder_ptr) { + infrared_common_encoder_free(encoder_ptr); +} + +InfraredStatus infrared_encoder_rca_encode(void* encoder_ptr, uint32_t* duration, bool* level) { + return infrared_common_encode(encoder_ptr, duration, level); +} diff --git a/lib/infrared/encoder_decoder/rca/infrared_protocol_rca.c b/lib/infrared/encoder_decoder/rca/infrared_protocol_rca.c new file mode 100644 index 000000000000..8e1e76dbd37d --- /dev/null +++ b/lib/infrared/encoder_decoder/rca/infrared_protocol_rca.c @@ -0,0 +1,40 @@ +#include "infrared_protocol_rca_i.h" + +const InfraredCommonProtocolSpec infrared_protocol_rca = { + .timings = + { + .preamble_mark = INFRARED_RCA_PREAMBLE_MARK, + .preamble_space = INFRARED_RCA_PREAMBLE_SPACE, + .bit1_mark = INFRARED_RCA_BIT1_MARK, + .bit1_space = INFRARED_RCA_BIT1_SPACE, + .bit0_mark = INFRARED_RCA_BIT0_MARK, + .bit0_space = INFRARED_RCA_BIT0_SPACE, + .preamble_tolerance = INFRARED_RCA_PREAMBLE_TOLERANCE, + .bit_tolerance = INFRARED_RCA_BIT_TOLERANCE, + .silence_time = INFRARED_RCA_SILENCE, + .min_split_time = INFRARED_RCA_MIN_SPLIT_TIME, + }, + .databit_len[0] = 24, + .no_stop_bit = false, + .decode = infrared_common_decode_pdwm, + .encode = infrared_common_encode_pdwm, + .interpret = infrared_decoder_rca_interpret, + .decode_repeat = NULL, + .encode_repeat = NULL, +}; + +static const InfraredProtocolVariant infrared_protocol_variant_rca = { + .name = "RCA", + .address_length = 4, + .command_length = 8, + .frequency = INFRARED_COMMON_CARRIER_FREQUENCY, + .duty_cycle = INFRARED_COMMON_DUTY_CYCLE, + .repeat_count = INFRARED_RCA_REPEAT_COUNT_MIN, +}; + +const InfraredProtocolVariant* infrared_protocol_rca_get_variant(InfraredProtocol protocol) { + if(protocol == InfraredProtocolRCA) + return &infrared_protocol_variant_rca; + else + return NULL; +} diff --git a/lib/infrared/encoder_decoder/rca/infrared_protocol_rca.h b/lib/infrared/encoder_decoder/rca/infrared_protocol_rca.h new file mode 100644 index 000000000000..d9cae48e48d9 --- /dev/null +++ b/lib/infrared/encoder_decoder/rca/infrared_protocol_rca.h @@ -0,0 +1,30 @@ +#pragma once + +#include "../infrared_i.h" + +/*************************************************************************************************** +* RCA protocol description +* https://www.sbprojects.net/knowledge/ir/rca.php +**************************************************************************************************** +* Preamble Preamble Pulse Distance/Width Pause Preamble Preamble +* mark space Modulation up to period repeat repeat +* mark space +* +* 4000 4000 24 bit ...8000 4000 4000 +* __________ _ _ _ _ _ _ _ _ _ _ _ _ _ ___________ +* ____ __________ _ _ _ __ __ __ _ _ __ __ _ _ ________________ ___________ +* +***************************************************************************************************/ + +void* infrared_decoder_rca_alloc(void); +void infrared_decoder_rca_reset(void* decoder); +void infrared_decoder_rca_free(void* decoder); +InfraredMessage* infrared_decoder_rca_check_ready(void* decoder); +InfraredMessage* infrared_decoder_rca_decode(void* decoder, bool level, uint32_t duration); + +void* infrared_encoder_rca_alloc(void); +InfraredStatus infrared_encoder_rca_encode(void* encoder_ptr, uint32_t* duration, bool* level); +void infrared_encoder_rca_reset(void* encoder_ptr, const InfraredMessage* message); +void infrared_encoder_rca_free(void* encoder_ptr); + +const InfraredProtocolVariant* infrared_protocol_rca_get_variant(InfraredProtocol protocol); diff --git a/lib/infrared/encoder_decoder/rca/infrared_protocol_rca_i.h b/lib/infrared/encoder_decoder/rca/infrared_protocol_rca_i.h new file mode 100644 index 000000000000..9ec4fe3b179b --- /dev/null +++ b/lib/infrared/encoder_decoder/rca/infrared_protocol_rca_i.h @@ -0,0 +1,30 @@ +#pragma once + +#include "../common/infrared_common_i.h" + +#define INFRARED_RCA_PREAMBLE_MARK 4000 +#define INFRARED_RCA_PREAMBLE_SPACE 4000 +#define INFRARED_RCA_BIT1_MARK 500 +#define INFRARED_RCA_BIT1_SPACE 2000 +#define INFRARED_RCA_BIT0_MARK 500 +#define INFRARED_RCA_BIT0_SPACE 1000 +#define INFRARED_RCA_REPEAT_PERIOD 8000 +#define INFRARED_RCA_SILENCE INFRARED_RCA_REPEAT_PERIOD + +#define INFRARED_RCA_MIN_SPLIT_TIME INFRARED_RCA_REPEAT_PAUSE_MIN +#define INFRARED_RCA_REPEAT_PAUSE_MIN 4000 +#define INFRARED_RCA_REPEAT_PAUSE_MAX 150000 +#define INFRARED_RCA_REPEAT_COUNT_MIN 1 +#define INFRARED_RCA_REPEAT_MARK INFRARED_RCA_PREAMBLE_MARK +#define INFRARED_RCA_REPEAT_SPACE INFRARED_RCA_PREAMBLE_SPACE +#define INFRARED_RCA_PREAMBLE_TOLERANCE 200 // us +#define INFRARED_RCA_BIT_TOLERANCE 120 // us + +extern const InfraredCommonProtocolSpec infrared_protocol_rca; + +bool infrared_decoder_rca_interpret(InfraredCommonDecoder* decoder); +InfraredStatus infrared_decoder_rca_decode_repeat(InfraredCommonDecoder* decoder); +InfraredStatus infrared_encoder_rca_encode_repeat( + InfraredCommonEncoder* encoder, + uint32_t* duration, + bool* level); diff --git a/lib/subghz/SConscript b/lib/subghz/SConscript index 2c42a5157f21..82c925c1a312 100644 --- a/lib/subghz/SConscript +++ b/lib/subghz/SConscript @@ -20,6 +20,7 @@ env.Append( File("subghz_setting.h"), File("subghz_protocol_registry.h"), File("devices/cc1101_configs.h"), + File("devices/cc1101_int/cc1101_int_interconnect.h"), ], ) diff --git a/lib/subghz/subghz_protocol_registry.h b/lib/subghz/subghz_protocol_registry.h index 6a27da992597..8e80071b5185 100644 --- a/lib/subghz/subghz_protocol_registry.h +++ b/lib/subghz/subghz_protocol_registry.h @@ -8,6 +8,31 @@ extern "C" { extern const SubGhzProtocolRegistry subghz_protocol_registry; +typedef struct SubGhzProtocolDecoderBinRAW SubGhzProtocolDecoderBinRAW; + +bool subghz_protocol_secplus_v2_create_data( + void* context, + FlipperFormat* flipper_format, + uint32_t serial, + uint8_t btn, + uint32_t cnt, + SubGhzRadioPreset* preset); + +bool subghz_protocol_keeloq_create_data( + void* context, + FlipperFormat* flipper_format, + uint32_t serial, + uint8_t btn, + uint16_t cnt, + const char* manufacture_name, + SubGhzRadioPreset* preset); + +void subghz_protocol_decoder_bin_raw_data_input_rssi( + SubGhzProtocolDecoderBinRAW* instance, + float rssi); + +bool subghz_protocol_secplus_v1_check_fixed(uint32_t fixed); + #ifdef __cplusplus } #endif diff --git a/lib/update_util/update_operation.c b/lib/update_util/update_operation.c index 6e05b0233178..0cecfc016a38 100644 --- a/lib/update_util/update_operation.c +++ b/lib/update_util/update_operation.c @@ -20,7 +20,8 @@ static const char* update_prepare_result_descr[] = { [UpdatePrepareResultManifestInvalid] = "Invalid manifest data", [UpdatePrepareResultStageMissing] = "Missing Stage2 loader", [UpdatePrepareResultStageIntegrityError] = "Corrupted Stage2 loader", - [UpdatePrepareResultManifestPointerError] = "Failed to create update pointer file", + [UpdatePrepareResultManifestPointerCreateError] = "Failed to create update pointer file", + [UpdatePrepareResultManifestPointerCheckError] = "Update pointer file error (corrupted FS?)", [UpdatePrepareResultTargetMismatch] = "Hardware target mismatch", [UpdatePrepareResultOutdatedManifestVersion] = "Update package is too old", [UpdatePrepareResultIntFull] = "Need more free space in internal storage", @@ -142,8 +143,8 @@ UpdatePrepareResult update_operation_prepare(const char* manifest_file_path) { File* file = storage_file_alloc(storage); uint64_t free_int_space; - FuriString* stage_path; - stage_path = furi_string_alloc(); + FuriString* stage_path = furi_string_alloc(); + FuriString* manifest_path_check = furi_string_alloc(); do { if((storage_common_fs_info(storage, STORAGE_INT_PATH_PREFIX, NULL, &free_int_space) != FSE_OK) || @@ -188,7 +189,18 @@ UpdatePrepareResult update_operation_prepare(const char* manifest_file_path) { } if(!update_operation_persist_manifest_path(storage, manifest_file_path)) { - result = UpdatePrepareResultManifestPointerError; + result = UpdatePrepareResultManifestPointerCreateError; + break; + } + + if(!update_operation_get_current_package_manifest_path(storage, manifest_path_check) || + (furi_string_cmpi_str(manifest_path_check, manifest_file_path) != 0)) { + FURI_LOG_E( + "update", + "Manifest pointer check failed: '%s' != '%s'", + furi_string_get_cstr(manifest_path_check), + manifest_file_path); + result = UpdatePrepareResultManifestPointerCheckError; break; } @@ -197,6 +209,7 @@ UpdatePrepareResult update_operation_prepare(const char* manifest_file_path) { } while(false); furi_string_free(stage_path); + furi_string_free(manifest_path_check); storage_file_free(file); update_manifest_free(manifest); diff --git a/lib/update_util/update_operation.h b/lib/update_util/update_operation.h index 65abf8e1504d..8e36b5a1370c 100644 --- a/lib/update_util/update_operation.h +++ b/lib/update_util/update_operation.h @@ -28,7 +28,8 @@ typedef enum { UpdatePrepareResultManifestInvalid, UpdatePrepareResultStageMissing, UpdatePrepareResultStageIntegrityError, - UpdatePrepareResultManifestPointerError, + UpdatePrepareResultManifestPointerCreateError, + UpdatePrepareResultManifestPointerCheckError, UpdatePrepareResultTargetMismatch, UpdatePrepareResultOutdatedManifestVersion, UpdatePrepareResultIntFull, diff --git a/scripts/fbt/appmanifest.py b/scripts/fbt/appmanifest.py index 73e5c777079b..067b4a26f09f 100644 --- a/scripts/fbt/appmanifest.py +++ b/scripts/fbt/appmanifest.py @@ -18,6 +18,7 @@ class FlipperAppType(Enum): SETTINGS = "Settings" STARTUP = "StartupHook" EXTERNAL = "External" + MENUEXTERNAL = "MenuExternal" METAPACKAGE = "Package" PLUGIN = "Plugin" @@ -213,7 +214,7 @@ def __init__( appmgr: AppManager, appnames: List[str], hw_target: str, - message_writer: Callable = None, + message_writer: Callable | None = None, ): self.appmgr = appmgr self.appnames = set(appnames) @@ -324,7 +325,13 @@ def get_apps_cdefs(self): def get_sdk_headers(self): sdk_headers = [] for app in self.apps: - sdk_headers.extend([app._appdir.File(header) for header in app.sdk_headers]) + sdk_headers.extend( + [ + src._appdir.File(header) + for src in [app, *app._plugins] + for header in src.sdk_headers + ] + ) return sdk_headers def get_apps_of_type(self, apptype: FlipperAppType, all_known: bool = False): @@ -367,6 +374,11 @@ class ApplicationsCGenerator: ), } + APP_EXTERNAL_TYPE = ( + "FlipperExternalApplication", + "FLIPPER_EXTERNAL_APPS", + ) + def __init__(self, buildset: AppBuildset, autorun_app: str = ""): self.buildset = buildset self.autorun = autorun_app @@ -387,6 +399,17 @@ def get_app_descr(self, app: FlipperApplication): .icon = {f"&{app.icon}" if app.icon else "NULL"}, .flags = {'|'.join(f"FlipperInternalApplicationFlag{flag}" for flag in app.flags)} }}""" + def get_external_app_descr(self, app: FlipperApplication): + app_path = "/ext/apps" + if app.fap_category: + app_path += f"/{app.fap_category}" + app_path += f"/{app.appid}.fap" + return f""" + {{ + .name = "{app.name}", + .icon = {f"&{app.icon}" if app.icon else "NULL"}, + .path = "{app_path}" }}""" + def generate(self): contents = [ '#include "applications.h"', @@ -418,4 +441,11 @@ def generate(self): ] ) + entry_type, entry_block = self.APP_EXTERNAL_TYPE + external_apps = self.buildset.get_apps_of_type(FlipperAppType.MENUEXTERNAL) + contents.append(f"const {entry_type} {entry_block}[] = {{") + contents.append(",\n".join(map(self.get_external_app_descr, external_apps))) + contents.append("};") + contents.append(f"const size_t {entry_block}_COUNT = COUNT_OF({entry_block});") + return "\n".join(contents) diff --git a/scripts/fbt_tools/fbt_extapps.py b/scripts/fbt_tools/fbt_extapps.py index 69d70021413d..1766d4c44475 100644 --- a/scripts/fbt_tools/fbt_extapps.py +++ b/scripts/fbt_tools/fbt_extapps.py @@ -3,7 +3,7 @@ import pathlib import shutil from dataclasses import dataclass, field -from typing import Optional +from typing import Optional, Dict, List import SCons.Warnings from ansi.color import fg @@ -400,22 +400,26 @@ def generate_embed_app_metadata_actions(source, target, env, for_signature): return Action(actions) -def AddAppLaunchTarget(env, appname, launch_target_name): - deploy_sources, flipp_dist_paths, validators = [], [], [] - run_script_extra_ars = "" +@dataclass +class AppDeploymentComponents: + deploy_sources: Dict[str, object] = field(default_factory=dict) + validators: List[object] = field(default_factory=list) + extra_launch_args: str = "" - def _add_dist_targets(app_artifacts): - validators.append(app_artifacts.validator) + def add_app(self, app_artifacts): for _, ext_path in app_artifacts.dist_entries: - deploy_sources.append(app_artifacts.compact) - flipp_dist_paths.append(f"/ext/{ext_path}") - return app_artifacts + self.deploy_sources[f"/ext/{ext_path}"] = app_artifacts.compact + self.validators.append(app_artifacts.validator) + + +def _gather_app_components(env, appname) -> AppDeploymentComponents: + components = AppDeploymentComponents() def _add_host_app_to_targets(host_app): artifacts_app_to_run = env["EXT_APPS"].get(host_app.appid, None) - _add_dist_targets(artifacts_app_to_run) + components.add_app(artifacts_app_to_run) for plugin in host_app._plugins: - _add_dist_targets(env["EXT_APPS"].get(plugin.appid, None)) + components.add_app(env["EXT_APPS"].get(plugin.appid, None)) artifacts_app_to_run = env.GetExtAppByIdOrPath(appname) if artifacts_app_to_run.app.apptype == FlipperAppType.PLUGIN: @@ -423,26 +427,39 @@ def _add_host_app_to_targets(host_app): host_app = env["APPMGR"].get(artifacts_app_to_run.app.requires[0]) if host_app: - if host_app.apptype == FlipperAppType.EXTERNAL: - _add_host_app_to_targets(host_app) + if host_app.apptype in [ + FlipperAppType.EXTERNAL, + FlipperAppType.MENUEXTERNAL, + ]: + components.add_app(host_app) else: # host app is a built-in app - run_script_extra_ars = f"-a {host_app.name}" - _add_dist_targets(artifacts_app_to_run) + components.add_app(artifacts_app_to_run) + components.extra_launch_args = f"-a {host_app.name}" else: raise UserError("Host app is unknown") else: _add_host_app_to_targets(artifacts_app_to_run.app) + return components - # print(deploy_sources, flipp_dist_paths) - env.PhonyTarget( + +def AddAppLaunchTarget(env, appname, launch_target_name): + components = _gather_app_components(env, appname) + target = env.PhonyTarget( launch_target_name, '${PYTHON3} "${APP_RUN_SCRIPT}" -p ${FLIP_PORT} ${EXTRA_ARGS} -s ${SOURCES} -t ${FLIPPER_FILE_TARGETS}', - source=deploy_sources, - FLIPPER_FILE_TARGETS=flipp_dist_paths, - EXTRA_ARGS=run_script_extra_ars, + source=components.deploy_sources.values(), + FLIPPER_FILE_TARGETS=components.deploy_sources.keys(), + EXTRA_ARGS=components.extra_launch_args, ) - env.Alias(launch_target_name, validators) + env.Alias(launch_target_name, components.validators) + return target + + +def AddAppBuildTarget(env, appname, build_target_name): + components = _gather_app_components(env, appname) + env.Alias(build_target_name, components.validators) + env.Alias(build_target_name, components.deploy_sources.values()) def generate(env, **kw): @@ -471,6 +488,7 @@ def generate(env, **kw): env.AddMethod(BuildAppElf) env.AddMethod(GetExtAppByIdOrPath) env.AddMethod(AddAppLaunchTarget) + env.AddMethod(AddAppBuildTarget) env.Append( BUILDERS={ diff --git a/scripts/fbt_tools/fbt_help.py b/scripts/fbt_tools/fbt_help.py index c7452af98840..68fc2aaf9ff5 100644 --- a/scripts/fbt_tools/fbt_help.py +++ b/scripts/fbt_tools/fbt_help.py @@ -4,15 +4,16 @@ tail_help = """ TASKS: -Building: +Firmware & apps: firmware_all, fw_dist: Build firmware; create distribution package faps, fap_dist: Build all FAP apps - fap_{APPID}, launch_app APPSRC={APPID}: + fap_{APPID}, build APPSRC={APPID}; launch APPSRC={APPID}: Build FAP app with appid={APPID}; upload & start it over USB fap_deploy: Build and upload all FAP apps over USB + Flashing & debugging: flash, flash_blackmagic, jflash: diff --git a/scripts/toolchain/fbtenv.cmd b/scripts/toolchain/fbtenv.cmd index 4ae04e2a2cbf..51708b8c4882 100644 --- a/scripts/toolchain/fbtenv.cmd +++ b/scripts/toolchain/fbtenv.cmd @@ -13,7 +13,7 @@ if not ["%FBT_NOENV%"] == [""] ( exit /b 0 ) -set "FLIPPER_TOOLCHAIN_VERSION=22" +set "FLIPPER_TOOLCHAIN_VERSION=23" if ["%FBT_TOOLCHAIN_PATH%"] == [""] ( set "FBT_TOOLCHAIN_PATH=%FBT_ROOT%" diff --git a/scripts/toolchain/fbtenv.sh b/scripts/toolchain/fbtenv.sh index e5548f488b1b..85d139040b1f 100755 --- a/scripts/toolchain/fbtenv.sh +++ b/scripts/toolchain/fbtenv.sh @@ -4,7 +4,7 @@ # public variables DEFAULT_SCRIPT_PATH="$(pwd -P)"; -FBT_TOOLCHAIN_VERSION="${FBT_TOOLCHAIN_VERSION:-"22"}"; +FBT_TOOLCHAIN_VERSION="${FBT_TOOLCHAIN_VERSION:-"23"}"; if [ -z ${FBT_TOOLCHAIN_PATH+x} ] ; then FBT_TOOLCHAIN_PATH_WAS_SET=0; diff --git a/scripts/ufbt/SConstruct b/scripts/ufbt/SConstruct index 8812a4e55928..9a9e0938c1b8 100644 --- a/scripts/ufbt/SConstruct +++ b/scripts/ufbt/SConstruct @@ -262,6 +262,7 @@ apps_artifacts = appenv["EXT_APPS"] apps_to_build_as_faps = [ FlipperAppType.PLUGIN, FlipperAppType.EXTERNAL, + FlipperAppType.MENUEXTERNAL, ] known_extapps = [ @@ -335,8 +336,10 @@ def ambiguous_app_call(**kw): if app_to_launch: appenv.AddAppLaunchTarget(app_to_launch, "launch") + appenv.AddAppBuildTarget(app_to_launch, "build") else: dist_env.PhonyTarget("launch", Action(ambiguous_app_call, None)) + dist_env.PhonyTarget("build", Action(ambiguous_app_call, None)) # cli handler diff --git a/site_scons/extapps.scons b/site_scons/extapps.scons index 6db0e538dfd4..5c6f18d6884e 100644 --- a/site_scons/extapps.scons +++ b/site_scons/extapps.scons @@ -67,6 +67,7 @@ class FlipperExtAppBuildArtifacts: apps_to_build_as_faps = [ FlipperAppType.PLUGIN, FlipperAppType.EXTERNAL, + FlipperAppType.MENUEXTERNAL, FlipperAppType.DEBUG, ] @@ -113,8 +114,20 @@ extapps.resources_dist = appenv.FapDist(appenv["RESOURCES_ROOT"], []) if appsrc := appenv.subst("$APPSRC"): - appenv.AddAppLaunchTarget(appsrc, "launch_app") + launch_target = appenv.AddAppLaunchTarget(appsrc, "launch") + Alias("launch_app", launch_target) + appenv.PhonyTarget( + "launch_app", + Action( + lambda **kw: warn( + WarningOnByDefault, + "The 'launch_app' target is deprecated. Use 'launch' instead.", + ), + None, + ), + ) + appenv.AddAppBuildTarget(appsrc, "build") # SDK management From cda1089fba9af57ce59204beacedad017f9d8a6b Mon Sep 17 00:00:00 2001 From: RebornedBrain <138568282+RebornedBrain@users.noreply.github.com> Date: Thu, 20 Jul 2023 21:20:49 +0300 Subject: [PATCH 126/149] [FL-3426] "More" button on "Info" scene shows card dump for Ultralight cards (#2905) * Added new scene for Mifare Ultralight This scene will show a full card dump * Replaced 'NotImplemented' scene with new 'CardDump' scene * Moved card_dump scene logic to protocol support * Added CardDump handlers for Ultralight cards * Ultralight data format function added * Implemented _on_event handler for CardDump --- .../mf_ultralight/mf_ultralight.c | 19 ++++++++++++++- .../mf_ultralight/mf_ultralight_render.c | 9 +++++++ .../mf_ultralight/mf_ultralight_render.h | 2 ++ .../protocol_support/nfc_protocol_support.c | 24 +++++++++++++++++++ .../nfc_protocol_support_base.h | 1 + .../nfc_protocol_support_common.h | 1 + .../main/nfc/scenes/nfc_scene_card_dump.c | 16 +++++++++++++ .../main/nfc/scenes/nfc_scene_config.h | 1 + 8 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 applications/main/nfc/scenes/nfc_scene_card_dump.c diff --git a/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c b/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c index 42058451cfc8..00ead03e9fa3 100644 --- a/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c +++ b/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c @@ -35,6 +35,18 @@ static void nfc_scene_info_on_enter_mf_ultralight(NfcApp* instance) { furi_string_free(temp_str); } +static void nfc_scene_card_dump_on_enter_mf_ultralight(NfcApp* instance) { + const NfcDevice* device = instance->nfc_device; + const MfUltralightData* mfu = nfc_device_get_data(device, NfcProtocolMfUltralight); + + furi_string_reset(instance->text_box_store); + nfc_render_mf_ultralight_dump(mfu, instance->text_box_store); + + text_box_set_font(instance->text_box, TextBoxFontHex); + text_box_set_text(instance->text_box, furi_string_get_cstr(instance->text_box_store)); + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewTextBox); +} + static NfcCommand nfc_scene_read_poller_callback_mf_ultralight(NfcGenericEvent event, void* context) { furi_assert(event.protocol == NfcProtocolMfUltralight); @@ -147,7 +159,7 @@ static void nfc_scene_emulate_on_enter_mf_ultralight(NfcApp* instance) { static bool nfc_scene_info_on_event_mf_ultralight(NfcApp* instance, uint32_t event) { if(event == GuiButtonTypeRight) { - scene_manager_next_scene(instance->scene_manager, NfcSceneNotImplemented); + scene_manager_next_scene(instance->scene_manager, NfcSceneCardDump); return true; } @@ -185,6 +197,11 @@ const NfcProtocolSupportBase nfc_protocol_support_mf_ultralight = { .on_enter = nfc_scene_info_on_enter_mf_ultralight, .on_event = nfc_scene_info_on_event_mf_ultralight, }, + .scene_card_dump = + { + .on_enter = nfc_scene_card_dump_on_enter_mf_ultralight, + .on_event = NULL, + }, .scene_read = { .on_enter = nfc_scene_read_on_enter_mf_ultralight, diff --git a/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight_render.c b/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight_render.c index d0f087fd23bf..714db3d532cf 100644 --- a/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight_render.c +++ b/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight_render.c @@ -15,3 +15,12 @@ void nfc_render_mf_ultralight_info( //TODO: Something else? } + +void nfc_render_mf_ultralight_dump(const MfUltralightData* data, FuriString* str) { + for(size_t i = 0; i < data->pages_read; i++) { + const uint8_t* page_data = data->page[i].data; + for(size_t j = 0; j < MF_ULTRALIGHT_PAGE_SIZE; j += 2) { + furi_string_cat_printf(str, "%02X%02X ", page_data[j], page_data[j + 1]); + } + } +} diff --git a/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight_render.h b/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight_render.h index e3c0a69d6fa5..e3924600dd99 100644 --- a/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight_render.h +++ b/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight_render.h @@ -8,3 +8,5 @@ void nfc_render_mf_ultralight_info( const MfUltralightData* data, NfcProtocolFormatType format_type, FuriString* str); + +void nfc_render_mf_ultralight_dump(const MfUltralightData* data, FuriString* str); diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c index cd1c49c611a8..7ceeeee62f29 100644 --- a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c @@ -81,6 +81,24 @@ static void nfc_protocol_support_scene_info_on_exit(NfcApp* instance) { widget_reset(instance->widget); } +static void nfc_protocol_support_scene_card_dump_on_enter(NfcApp* instance) { + const NfcProtocol protocol = nfc_device_get_protocol(instance->nfc_device); + nfc_protocol_support[protocol]->scene_card_dump.on_enter(instance); + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewTextBox); +} + +static bool + nfc_protocol_support_scene_card_dump_on_event(NfcApp* instance, SceneManagerEvent event) { + UNUSED(instance); + UNUSED(event); + return false; +} + +static void nfc_protocol_support_scene_card_dump_on_exit(NfcApp* instance) { + text_box_reset(instance->text_box); + furi_string_reset(instance->text_box_store); +} + // SceneRead static void nfc_protocol_support_scene_read_on_enter(NfcApp* instance) { popup_set_header( @@ -489,6 +507,12 @@ static const NfcProtocolSupportCommonSceneBase .on_event = nfc_protocol_support_scene_info_on_event, .on_exit = nfc_protocol_support_scene_info_on_exit, }, + [NfcProtocolSupportSceneCardDump] = + { + .on_enter = nfc_protocol_support_scene_card_dump_on_enter, + .on_event = nfc_protocol_support_scene_card_dump_on_event, + .on_exit = nfc_protocol_support_scene_card_dump_on_exit, + }, [NfcProtocolSupportSceneRead] = { .on_enter = nfc_protocol_support_scene_read_on_enter, diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_base.h b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_base.h index 37f56f799c4d..5b5d74aff122 100644 --- a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_base.h +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_base.h @@ -20,6 +20,7 @@ typedef struct { const uint32_t features; NfcProtocolSupportSceneBase scene_info; + NfcProtocolSupportSceneBase scene_card_dump; NfcProtocolSupportSceneBase scene_read; NfcProtocolSupportSceneBase scene_read_menu; NfcProtocolSupportSceneBase scene_read_success; diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_common.h b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_common.h index 291e2b01fb6d..50fb3cbde763 100644 --- a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_common.h +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_common.h @@ -23,6 +23,7 @@ typedef enum { NfcProtocolSupportSceneReadSuccess, NfcProtocolSupportSceneSavedMenu, NfcProtocolSupportSceneEmulate, + NfcProtocolSupportSceneCardDump, NfcProtocolSupportSceneCount, } NfcProtocolSupportScene; diff --git a/applications/main/nfc/scenes/nfc_scene_card_dump.c b/applications/main/nfc/scenes/nfc_scene_card_dump.c new file mode 100644 index 000000000000..490bb5b4f8e4 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_card_dump.c @@ -0,0 +1,16 @@ +#include + +#include "../nfc_app_i.h" +#include "../helpers/protocol_support/nfc_protocol_support.h" + +void nfc_scene_card_dump_on_enter(void* context) { + nfc_protocol_support_on_enter(NfcProtocolSupportSceneCardDump, context); +} + +bool nfc_scene_card_dump_on_event(void* context, SceneManagerEvent event) { + return nfc_protocol_support_on_event(NfcProtocolSupportSceneCardDump, context, event); +} + +void nfc_scene_card_dump_on_exit(void* context) { + nfc_protocol_support_on_exit(NfcProtocolSupportSceneCardDump, context); +} \ No newline at end of file diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index c52a7c397aae..c3e7d44993b6 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -18,6 +18,7 @@ ADD_SCENE(nfc, emulate, Emulate) ADD_SCENE(nfc, debug, Debug) ADD_SCENE(nfc, retry_confirm, RetryConfirm) ADD_SCENE(nfc, exit_confirm, ExitConfirm) +ADD_SCENE(nfc, card_dump, CardDump) ADD_SCENE(nfc, mf_ultralight_unlock_menu, MfUltralightUnlockMenu) ADD_SCENE(nfc, mf_ultralight_unlock_warn, MfUltralightUnlockWarn) From 10aff3948f694c3bf8a4b292fadc141632546f99 Mon Sep 17 00:00:00 2001 From: RebornedBrain <138568282+RebornedBrain@users.noreply.github.com> Date: Mon, 24 Jul 2023 17:33:44 +0300 Subject: [PATCH 127/149] [FL-3447] Debug field implementation (#2916) * Field scene added * Moved 'Debug' scene implementation into protocol support layer * Menu index for Field item added * Set proper scene and submenu index for 'Debug' button * Fixed issue when returning from 'Add Manually' screen Previously wrong menu item ('Read') was selected when returning from 'Add Manually', now it returns back properly * Revert "Moved 'Debug' scene implementation into protocol support layer" This reverts commit f73938783d86436b85b15ca88949ab7bd209a149. * Removed 'Adu' menu item * 'Field' button now points to a proper scene * Revert "Menu index for Field item added" This reverts commit ab73494a998b06e3514d5164aa458f622fafbfa7. --- .../main/nfc/scenes/nfc_scene_config.h | 1 + .../main/nfc/scenes/nfc_scene_debug.c | 9 +---- .../main/nfc/scenes/nfc_scene_field.c | 33 +++++++++++++++++++ .../main/nfc/scenes/nfc_scene_start.c | 8 ++--- 4 files changed, 39 insertions(+), 12 deletions(-) create mode 100644 applications/main/nfc/scenes/nfc_scene_field.c diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index c3e7d44993b6..1642aee6d1a8 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -16,6 +16,7 @@ ADD_SCENE(nfc, read_success, ReadSuccess) ADD_SCENE(nfc, read_menu, ReadMenu) ADD_SCENE(nfc, emulate, Emulate) ADD_SCENE(nfc, debug, Debug) +ADD_SCENE(nfc, field, Field) ADD_SCENE(nfc, retry_confirm, RetryConfirm) ADD_SCENE(nfc, exit_confirm, ExitConfirm) ADD_SCENE(nfc, card_dump, CardDump) diff --git a/applications/main/nfc/scenes/nfc_scene_debug.c b/applications/main/nfc/scenes/nfc_scene_debug.c index 85bc901a3429..97592f2e270e 100644 --- a/applications/main/nfc/scenes/nfc_scene_debug.c +++ b/applications/main/nfc/scenes/nfc_scene_debug.c @@ -17,8 +17,6 @@ void nfc_scene_debug_on_enter(void* context) { submenu_add_item( submenu, "Field", SubmenuDebugIndexField, nfc_scene_debug_submenu_callback, nfc); - submenu_add_item( - submenu, "Apdu", SubmenuDebugIndexApdu, nfc_scene_debug_submenu_callback, nfc); submenu_set_selected_item( submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneDebug)); @@ -34,12 +32,7 @@ bool nfc_scene_debug_on_event(void* context, SceneManagerEvent event) { if(event.event == SubmenuDebugIndexField) { scene_manager_set_scene_state( nfc->scene_manager, NfcSceneDebug, SubmenuDebugIndexField); - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); - consumed = true; - } else if(event.event == SubmenuDebugIndexApdu) { - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneDebug, SubmenuDebugIndexApdu); - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + scene_manager_next_scene(nfc->scene_manager, NfcSceneField); consumed = true; } } diff --git a/applications/main/nfc/scenes/nfc_scene_field.c b/applications/main/nfc/scenes/nfc_scene_field.c new file mode 100644 index 000000000000..bd7f3a75cde1 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_field.c @@ -0,0 +1,33 @@ +#include "../nfc_app_i.h" + +void nfc_scene_field_on_enter(void* context) { + NfcApp* nfc = context; + + f_hal_nfc_low_power_mode_stop(); + f_hal_nfc_poller_field_on(); + Popup* popup = nfc->popup; + popup_set_header( + popup, + "Field is on\nDon't leave device\nin this mode for too long.", + 64, + 11, + AlignCenter, + AlignTop); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); + + notification_internal_message(nfc->notifications, &sequence_set_blue_255); +} + +bool nfc_scene_field_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + UNUSED(event); + return false; +} + +void nfc_scene_field_on_exit(void* context) { + NfcApp* nfc = context; + + f_hal_nfc_low_power_mode_start(); + notification_internal_message(nfc->notifications, &sequence_reset_blue); + popup_reset(nfc->popup); +} diff --git a/applications/main/nfc/scenes/nfc_scene_start.c b/applications/main/nfc/scenes/nfc_scene_start.c index 771e9682e084..e03e5e31ada4 100644 --- a/applications/main/nfc/scenes/nfc_scene_start.c +++ b/applications/main/nfc/scenes/nfc_scene_start.c @@ -72,13 +72,13 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(nfc->scene_manager, NfcSceneExtraActions); consumed = true; } else if(event.event == SubmenuIndexAddManually) { - scene_manager_set_scene_state(nfc->scene_manager, NfcSceneStart, NfcSceneSetType); + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneStart, SubmenuIndexAddManually); scene_manager_next_scene(nfc->scene_manager, NfcSceneSetType); consumed = true; } else if(event.event == SubmenuIndexDebug) { - scene_manager_set_scene_state( - nfc->scene_manager, NfcSceneStart, NfcSceneNotImplemented); - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + scene_manager_set_scene_state(nfc->scene_manager, NfcSceneStart, SubmenuIndexDebug); + scene_manager_next_scene(nfc->scene_manager, NfcSceneDebug); consumed = true; } } From 61caa1eed41f2213e0dda3bbd394d8f1854eca2c Mon Sep 17 00:00:00 2001 From: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Date: Tue, 25 Jul 2023 13:41:03 +0300 Subject: [PATCH 128/149] [NFC] NFC-B support (#2918) * Add boilerplate code for ISO14443-4B * Add boilerplate code for ISO14443-3B gui support * Partially working ISO14443-3B activation * Slightly better error handling * Testing NFC-B * More changes for NFC-B * Working NFC-B configuration * Rearrange f_hal_nfc code * Prettify info output * Improve iso-3 poller api * Working NFC-B activation procedure * Implement saving & loading of NFC-B tags * Remove crc calculation from iso14443-3b definition * Remove crc calculation from iso14443-3a definition, add api headers * Update NfcFileFormats.md * Add set_uid method * Load UID inside nfc_device * Temporarily disable UID editing for NFC-B --- .../debug/unit_tests/nfc/nfc_transport.c | 5 +- .../iso14443_3b/iso14443_3b.c | 112 ++++++++++ .../iso14443_3b/iso14443_3b.h | 5 + .../iso14443_3b/iso14443_3b_render.c | 28 +++ .../iso14443_3b/iso14443_3b_render.h | 10 + .../nfc_protocol_support_defs.c | 2 + documentation/file_formats/NfcFileFormats.md | 32 ++- firmware/targets/f7/api_symbols.csv | 28 ++- firmware/targets/f7/furi_hal/f_hal_nfc.c | 196 +++++++++++++----- firmware/targets/furi_hal_include/f_hal_nfc.h | 4 +- lib/nfc/SConscript | 3 + lib/nfc/helpers/bit_buffer.c | 3 + lib/nfc/helpers/iso14443_crc.c | 59 ++++++ lib/nfc/helpers/iso14443_crc.h | 27 +++ lib/nfc/nfc.c | 3 + lib/nfc/nfc.h | 4 +- lib/nfc/nfc_device.c | 57 ++++- lib/nfc/nfc_device.h | 2 + lib/nfc/protocols/iso14443_3a/iso14443_3a.c | 86 ++------ lib/nfc/protocols/iso14443_3a/iso14443_3a.h | 13 +- .../iso14443_3a/iso14443_3a_listener.c | 10 +- .../iso14443_3a/iso14443_3a_listener_i.c | 6 +- .../iso14443_3a/iso14443_3a_poller_i.c | 8 +- lib/nfc/protocols/iso14443_3b/iso14443_3b.c | 145 +++++++++++++ lib/nfc/protocols/iso14443_3b/iso14443_3b.h | 81 ++++++++ .../iso14443_3b/iso14443_3b_poller.c | 122 +++++++++++ .../iso14443_3b/iso14443_3b_poller.h | 30 +++ .../iso14443_3b_poller_defs.h} | 3 +- .../iso14443_3b/iso14443_3b_poller_i.c | 188 +++++++++++++++++ .../iso14443_3b/iso14443_3b_poller_i.h | 51 +++++ lib/nfc/protocols/iso14443_4a/iso14443_4a.c | 9 +- lib/nfc/protocols/iso14443_4a/iso14443_4a.h | 2 + lib/nfc/protocols/mf_classic/mf_classic.c | 7 + lib/nfc/protocols/mf_classic/mf_classic.h | 2 + .../mf_classic/mf_classic_listener.c | 9 +- .../mf_classic/mf_classic_poller_i.c | 20 +- lib/nfc/protocols/mf_desfire/mf_desfire.c | 7 + lib/nfc/protocols/mf_desfire/mf_desfire.h | 2 + .../protocols/mf_ultralight/mf_ultralight.c | 7 + .../protocols/mf_ultralight/mf_ultralight.h | 2 + lib/nfc/protocols/nfc_device_base_i.h | 2 + lib/nfc/protocols/nfc_device_defs.c | 2 + lib/nfc/protocols/nfc_poller_defs.c | 3 + lib/nfc/protocols/nfc_protocol.c | 28 ++- lib/nfc/protocols/nfc_protocol.h | 1 + lib/nfc/protocols/nfcb/nfcb.h | 28 --- lib/nfc/protocols/nfcb/nfcb_poller.c | 97 --------- lib/nfc/protocols/nfcb/nfcb_poller.h | 51 ----- lib/nfc/protocols/nfcb/nfcb_poller_i.c | 6 - 49 files changed, 1245 insertions(+), 363 deletions(-) create mode 100644 applications/main/nfc/helpers/protocol_support/iso14443_3b/iso14443_3b.c create mode 100644 applications/main/nfc/helpers/protocol_support/iso14443_3b/iso14443_3b.h create mode 100644 applications/main/nfc/helpers/protocol_support/iso14443_3b/iso14443_3b_render.c create mode 100644 applications/main/nfc/helpers/protocol_support/iso14443_3b/iso14443_3b_render.h create mode 100644 lib/nfc/helpers/iso14443_crc.c create mode 100644 lib/nfc/helpers/iso14443_crc.h create mode 100644 lib/nfc/protocols/iso14443_3b/iso14443_3b.c create mode 100644 lib/nfc/protocols/iso14443_3b/iso14443_3b.h create mode 100644 lib/nfc/protocols/iso14443_3b/iso14443_3b_poller.c create mode 100644 lib/nfc/protocols/iso14443_3b/iso14443_3b_poller.h rename lib/nfc/protocols/{nfcb/nfcb_poller_i.h => iso14443_3b/iso14443_3b_poller_defs.h} (63%) create mode 100644 lib/nfc/protocols/iso14443_3b/iso14443_3b_poller_i.c create mode 100644 lib/nfc/protocols/iso14443_3b/iso14443_3b_poller_i.h delete mode 100644 lib/nfc/protocols/nfcb/nfcb.h delete mode 100644 lib/nfc/protocols/nfcb/nfcb_poller.c delete mode 100644 lib/nfc/protocols/nfcb/nfcb_poller.h delete mode 100644 lib/nfc/protocols/nfcb/nfcb_poller_i.c diff --git a/applications/debug/unit_tests/nfc/nfc_transport.c b/applications/debug/unit_tests/nfc/nfc_transport.c index fab6693db873..e9084ca20b93 100644 --- a/applications/debug/unit_tests/nfc/nfc_transport.c +++ b/applications/debug/unit_tests/nfc/nfc_transport.c @@ -1,6 +1,7 @@ #ifdef APP_UNIT_TESTS #include +#include #include #include @@ -246,13 +247,13 @@ static void nfc_worker_listener_pass_col_res(Nfc* instance, uint8_t* rx_data, ui if((rx_data[0] == 0x93) && (rx_data[1] == 0x70)) { bit_buffer_set_size_bytes(tx_buffer, 1); bit_buffer_set_byte(tx_buffer, 0, instance->col_res_data.sel_resp[0].sak); - iso14443_3a_append_crc(tx_buffer); + iso14443_crc_append(Iso14443CrcTypeA, tx_buffer); nfc_listener_tx(instance, tx_buffer); processed = true; } else if((rx_data[0] == 0x95) && (rx_data[1] == 0x70)) { bit_buffer_set_size_bytes(tx_buffer, 1); bit_buffer_set_byte(tx_buffer, 0, instance->col_res_data.sel_resp[1].sak); - iso14443_3a_append_crc(tx_buffer); + iso14443_crc_append(Iso14443CrcTypeA, tx_buffer); nfc_listener_tx(instance, tx_buffer); instance->col_res_status = Iso14443_3aColResStatusDone; NfcEvent event = {.type = NfcEventTypeListenerActivated}; diff --git a/applications/main/nfc/helpers/protocol_support/iso14443_3b/iso14443_3b.c b/applications/main/nfc/helpers/protocol_support/iso14443_3b/iso14443_3b.c new file mode 100644 index 000000000000..b2b332aa450a --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/iso14443_3b/iso14443_3b.c @@ -0,0 +1,112 @@ +#include "iso14443_3b.h" +#include "iso14443_3b_render.h" + +#include + +#include "nfc/nfc_app_i.h" + +#include "../nfc_protocol_support_gui_common.h" + +static void nfc_scene_info_on_enter_iso14443_3b(NfcApp* instance) { + const NfcDevice* device = instance->nfc_device; + const Iso14443_3bData* data = nfc_device_get_data(device, NfcProtocolIso14443_3b); + + FuriString* temp_str = furi_string_alloc(); + furi_string_cat_printf( + temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull)); + nfc_render_iso14443_3b_info(data, NfcProtocolFormatTypeFull, temp_str); + + widget_add_text_scroll_element( + instance->widget, 0, 0, 128, 64, furi_string_get_cstr(temp_str)); + + furi_string_free(temp_str); +} + +static NfcCommand + nfc_scene_read_poller_callback_iso14443_3b(NfcGenericEvent event, void* context) { + furi_assert(event.protocol == NfcProtocolIso14443_3b); + + NfcApp* instance = context; + const Iso14443_3bPollerEvent* iso14443_3b_event = event.data; + + if(iso14443_3b_event->type == Iso14443_3bPollerEventTypeReady) { + nfc_device_set_data( + instance->nfc_device, NfcProtocolIso14443_3b, nfc_poller_get_data(instance->poller)); + view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventPollerSuccess); + return NfcCommandStop; + } + + return NfcCommandContinue; +} + +static void nfc_scene_read_on_enter_iso14443_3b(NfcApp* instance) { + nfc_poller_start(instance->poller, nfc_scene_read_poller_callback_iso14443_3b, instance); +} + +static void nfc_scene_read_success_on_enter_iso14443_3b(NfcApp* instance) { + const NfcDevice* device = instance->nfc_device; + const Iso14443_3bData* data = nfc_device_get_data(device, NfcProtocolIso14443_3b); + + FuriString* temp_str = furi_string_alloc(); + furi_string_cat_printf( + temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull)); + nfc_render_iso14443_3b_info(data, NfcProtocolFormatTypeShort, temp_str); + + widget_add_text_scroll_element( + instance->widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); + + furi_string_free(temp_str); +} + +static bool nfc_scene_info_on_event_iso14443_3b(NfcApp* instance, uint32_t event) { + if(event == GuiButtonTypeRight) { + scene_manager_next_scene(instance->scene_manager, NfcSceneNotImplemented); + return true; + } + + return false; +} + +static bool nfc_scene_saved_menu_on_event_iso14443_3b(NfcApp* instance, uint32_t event) { + if(event == SubmenuIndexCommonEdit) { + scene_manager_next_scene(instance->scene_manager, NfcSceneSetUid); + return true; + } + + return false; +} + +const NfcProtocolSupportBase nfc_protocol_support_iso14443_3b = { + .features = NfcProtocolFeatureNone, // TODO: Implement better UID editing, + + .scene_info = + { + .on_enter = nfc_scene_info_on_enter_iso14443_3b, + .on_event = nfc_scene_info_on_event_iso14443_3b, + }, + .scene_read = + { + .on_enter = nfc_scene_read_on_enter_iso14443_3b, + .on_event = NULL, + }, + .scene_read_menu = + { + .on_enter = nfc_protocol_support_common_on_enter_empty, + .on_event = nfc_protocol_support_common_on_event_empty, + }, + .scene_read_success = + { + .on_enter = nfc_scene_read_success_on_enter_iso14443_3b, + .on_event = NULL, + }, + .scene_saved_menu = + { + .on_enter = nfc_protocol_support_common_on_enter_empty, + .on_event = nfc_scene_saved_menu_on_event_iso14443_3b, + }, + .scene_emulate = + { + .on_enter = NULL, + .on_event = NULL, + }, +}; diff --git a/applications/main/nfc/helpers/protocol_support/iso14443_3b/iso14443_3b.h b/applications/main/nfc/helpers/protocol_support/iso14443_3b/iso14443_3b.h new file mode 100644 index 000000000000..bf3caa0c0e31 --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/iso14443_3b/iso14443_3b.h @@ -0,0 +1,5 @@ +#pragma once + +#include "../nfc_protocol_support_base.h" + +extern const NfcProtocolSupportBase nfc_protocol_support_iso14443_3b; diff --git a/applications/main/nfc/helpers/protocol_support/iso14443_3b/iso14443_3b_render.c b/applications/main/nfc/helpers/protocol_support/iso14443_3b/iso14443_3b_render.c new file mode 100644 index 000000000000..c4098d61c25a --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/iso14443_3b/iso14443_3b_render.c @@ -0,0 +1,28 @@ +#include "iso14443_3b_render.h" + +void nfc_render_iso14443_3b_info( + const Iso14443_3bData* data, + NfcProtocolFormatType format_type, + FuriString* str) { + if(format_type == NfcProtocolFormatTypeFull) { + const char iso_type = FURI_BIT(data->protocol_info[1], 0) ? '4' : '3'; + furi_string_cat_printf(str, "ISO 14443-%c (NFC-B)\n", iso_type); + } + + furi_string_cat_printf(str, "UID:"); + + for(size_t i = 0; i < ISO14443_3B_UID_SIZE; i++) { + furi_string_cat_printf(str, " %02X", data->uid[i]); + } + + if(format_type == NfcProtocolFormatTypeFull) { + furi_string_cat_printf(str, "\nApp. data:"); + for(size_t i = 0; i < ISO14443_3B_APP_DATA_SIZE; ++i) { + furi_string_cat_printf(str, " %02X", data->app_data[i]); + } + furi_string_cat_printf(str, "\nProtocol info:"); + for(size_t i = 0; i < ISO14443_3B_PROTOCOL_INFO_SIZE; ++i) { + furi_string_cat_printf(str, " %02X", data->protocol_info[i]); + } + } +} diff --git a/applications/main/nfc/helpers/protocol_support/iso14443_3b/iso14443_3b_render.h b/applications/main/nfc/helpers/protocol_support/iso14443_3b/iso14443_3b_render.h new file mode 100644 index 000000000000..ee50f6acf5a8 --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/iso14443_3b/iso14443_3b_render.h @@ -0,0 +1,10 @@ +#pragma once + +#include + +#include "../nfc_protocol_support_render_common.h" + +void nfc_render_iso14443_3b_info( + const Iso14443_3bData* data, + NfcProtocolFormatType format_type, + FuriString* str); diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_defs.c b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_defs.c index 92a4cd561f65..9771dbe87500 100644 --- a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_defs.c +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_defs.c @@ -1,6 +1,7 @@ #include "nfc_protocol_support_defs.h" #include "iso14443_3a/iso14443_3a.h" +#include "iso14443_3b/iso14443_3b.h" #include "iso14443_4a/iso14443_4a.h" #include "mf_ultralight/mf_ultralight.h" #include "mf_classic/mf_classic.h" @@ -8,6 +9,7 @@ const NfcProtocolSupportBase* nfc_protocol_support[NfcProtocolNum] = { [NfcProtocolIso14443_3a] = &nfc_protocol_support_iso14443_3a, + [NfcProtocolIso14443_3b] = &nfc_protocol_support_iso14443_3b, [NfcProtocolIso14443_4a] = &nfc_protocol_support_iso14443_4a, [NfcProtocolMfUltralight] = &nfc_protocol_support_mf_ultralight, [NfcProtocolMfClassic] = &nfc_protocol_support_mf_classic, diff --git a/documentation/file_formats/NfcFileFormats.md b/documentation/file_formats/NfcFileFormats.md index f3b77c55a99b..f752cdb901b8 100644 --- a/documentation/file_formats/NfcFileFormats.md +++ b/documentation/file_formats/NfcFileFormats.md @@ -6,7 +6,7 @@ Filetype: Flipper NFC device Version: 4 - # Device type can be ISO14443-3A, ISO14443-4A, NTAG/Ultralight, Mifare Classic, Mifare DESFire + # Device type can be ISO14443-3A, ISO14443-3B, ISO14443-4A, NTAG/Ultralight, Mifare Classic, Mifare DESFire Device type: ISO14443-4A # UID is common for all formats UID: 04 48 6A 32 33 58 80 @@ -28,7 +28,7 @@ Version differences: Filetype: Flipper NFC device Version: 4 - # Device type can be ISO14443-3A, ISO14443-4A, NTAG/Ultralight, Mifare Classic, Mifare DESFire + # Device type can be ISO14443-3A, ISO14443-3B, ISO14443-4A, NTAG/Ultralight, Mifare Classic, Mifare DESFire Device type: ISO14443-3A # UID is common for all formats UID: 34 19 6D 41 14 56 E6 @@ -44,13 +44,33 @@ UID must be either 4 or 7 bytes long. ATQA is 2 bytes long. SAK is 1 byte long. Version differences: None, there are no versions yet. +## ISO14443-3B + + Filetype: Flipper NFC device + Version: 4 + # Device type can be ISO14443-3A, ISO14443-3B, ISO14443-4A, NTAG/Ultralight, Mifare Classic, Mifare DESFire + Device type: ISO14443-3B + # UID is common for all formats + UID: 30 1D B3 28 + # ISO14443-3B specific data + Application data: 00 12 34 FF + Protocol info: 11 81 E1 + +### Description + +This file format is used to store the UID, Application data and Protocol info of a ISO14443-3B device. +UID must be 4 bytes long. Application data is 4 bytes long. Protocol info is 3 bytes long. + +Version differences: +None, there are no versions yet. + ## ISO14443-4A ### Example Filetype: Flipper NFC device Version: 4 - # Device type can be ISO14443-3A, ISO14443-4A, NTAG/Ultralight, Mifare Classic, Mifare DESFire + # Device type can be ISO14443-3A, ISO14443-3B, ISO14443-4A, NTAG/Ultralight, Mifare Classic, Mifare DESFire Device type: ISO14443-4A # UID is common for all formats UID: 04 48 6A 32 33 58 80 @@ -74,7 +94,7 @@ None, there are no versions yet. Filetype: Flipper NFC device Version: 4 - # Device type can be ISO14443-3A, ISO14443-4A, NTAG/Ultralight, Mifare Classic, Mifare DESFire + # Device type can be ISO14443-3A, ISO14443-3B, ISO14443-4A, NTAG/Ultralight, Mifare Classic, Mifare DESFire Device type: NTAG/Ultralight # UID is common for all formats UID: 04 85 90 54 12 98 23 @@ -130,7 +150,7 @@ Version differences: Filetype: Flipper NFC device Version: 4 - # Device type can be ISO14443-3A, ISO14443-4A, NTAG/Ultralight, Mifare Classic, Mifare DESFire + # Device type can be ISO14443-3A, ISO14443-3B, ISO14443-4A, NTAG/Ultralight, Mifare Classic, Mifare DESFire Device type: Mifare Classic # UID is common for all formats UID: BA E2 7C 9D @@ -195,7 +215,7 @@ Example: Filetype: Flipper NFC device Version: 4 - # Device type can be ISO14443-3A, ISO14443-4A, NTAG/Ultralight, Mifare Classic, Mifare DESFire + # Device type can be ISO14443-3A, ISO14443-3B, ISO14443-4A, NTAG/Ultralight, Mifare Classic, Mifare DESFire Device type: Mifare DESFire # UID is common for all formats UID: 04 2F 19 0A CD 66 80 diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 5f8b00464275..ac14d1f45744 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -151,6 +151,7 @@ Header,+,lib/music_worker/music_worker.h,, Header,+,lib/nanopb/pb.h,, Header,+,lib/nanopb/pb_decode.h,, Header,+,lib/nanopb/pb_encode.h,, +Header,+,lib/nfc/helpers/iso14443_crc.h,, Header,+,lib/nfc/helpers/nfc_util.h,, Header,+,lib/nfc/nfc.h,, Header,+,lib/nfc/nfc_device.h,, @@ -161,6 +162,8 @@ Header,+,lib/nfc/protocols/iso14443_3a/iso14443_3a.h,, Header,+,lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.h,, Header,+,lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.h,, Header,+,lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_sync_api.h,, +Header,+,lib/nfc/protocols/iso14443_3b/iso14443_3b.h,, +Header,+,lib/nfc/protocols/iso14443_3b/iso14443_3b_poller.h,, Header,+,lib/nfc/protocols/iso14443_4a/iso14443_4a.h,, Header,+,lib/nfc/protocols/iso14443_4a/iso14443_4a_listener.h,, Header,+,lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.h,, @@ -1835,8 +1838,6 @@ Function,-,islower_l,int,"int, locale_t" Function,-,isnan,int,double Function,-,isnanf,int,float Function,+,iso14443_3a_alloc,Iso14443_3aData*, -Function,+,iso14443_3a_append_crc,void,BitBuffer* -Function,+,iso14443_3a_check_crc,_Bool,const BitBuffer* Function,+,iso14443_3a_copy,void,"Iso14443_3aData*, const Iso14443_3aData*" Function,+,iso14443_3a_free,void,Iso14443_3aData* Function,+,iso14443_3a_get_base_data,const Iso14443_3aData*,const Iso14443_3aData* @@ -1848,8 +1849,20 @@ Function,+,iso14443_3a_load,_Bool,"Iso14443_3aData*, FlipperFormat*, uint32_t" Function,+,iso14443_3a_poller_read,Iso14443_3aError,"Nfc*, Iso14443_3aData*" Function,+,iso14443_3a_reset,void,Iso14443_3aData* Function,+,iso14443_3a_save,_Bool,"const Iso14443_3aData*, FlipperFormat*" -Function,+,iso14443_3a_trim_crc,void,BitBuffer* +Function,+,iso14443_3a_set_uid,_Bool,"Iso14443_3aData*, const uint8_t*, size_t" Function,+,iso14443_3a_verify,_Bool,"Iso14443_3aData*, const FuriString*" +Function,+,iso14443_3b_alloc,Iso14443_3bData*, +Function,+,iso14443_3b_copy,void,"Iso14443_3bData*, const Iso14443_3bData*" +Function,+,iso14443_3b_free,void,Iso14443_3bData* +Function,+,iso14443_3b_get_base_data,const Iso14443_3bData*,const Iso14443_3bData* +Function,+,iso14443_3b_get_device_name,const char*,"const Iso14443_3bData*, NfcDeviceNameType" +Function,+,iso14443_3b_get_uid,const uint8_t*,"const Iso14443_3bData*, size_t*" +Function,+,iso14443_3b_is_equal,_Bool,"const Iso14443_3bData*, const Iso14443_3bData*" +Function,+,iso14443_3b_load,_Bool,"Iso14443_3bData*, FlipperFormat*, uint32_t" +Function,+,iso14443_3b_reset,void,Iso14443_3bData* +Function,+,iso14443_3b_save,_Bool,"const Iso14443_3bData*, FlipperFormat*" +Function,+,iso14443_3b_set_uid,_Bool,"Iso14443_3bData*, const uint8_t*, size_t" +Function,+,iso14443_3b_verify,_Bool,"Iso14443_3bData*, const FuriString*" Function,+,iso14443_4a_alloc,Iso14443_4aData*, Function,+,iso14443_4a_copy,void,"Iso14443_4aData*, const Iso14443_4aData*" Function,+,iso14443_4a_free,void,Iso14443_4aData* @@ -1861,7 +1874,11 @@ Function,+,iso14443_4a_is_equal,_Bool,"const Iso14443_4aData*, const Iso14443_4a Function,+,iso14443_4a_load,_Bool,"Iso14443_4aData*, FlipperFormat*, uint32_t" Function,+,iso14443_4a_reset,void,Iso14443_4aData* Function,+,iso14443_4a_save,_Bool,"const Iso14443_4aData*, FlipperFormat*" +Function,+,iso14443_4a_set_uid,_Bool,"Iso14443_4aData*, const uint8_t*, size_t" Function,+,iso14443_4a_verify,_Bool,"Iso14443_4aData*, const FuriString*" +Function,+,iso14443_crc_append,void,"Iso14443CrcType, BitBuffer*" +Function,+,iso14443_crc_check,_Bool,"Iso14443CrcType, const BitBuffer*" +Function,+,iso14443_crc_trim,void,BitBuffer* Function,-,isprint,int,int Function,-,isprint_l,int,"int, locale_t" Function,-,ispunct,int,int @@ -2075,6 +2092,7 @@ Function,+,mf_classic_save,_Bool,"const MfClassicData*, FlipperFormat*" Function,+,mf_classic_set_block_read,void,"MfClassicData*, uint8_t, MfClassicBlock*" Function,+,mf_classic_set_key_found,void,"MfClassicData*, uint8_t, MfClassicKeyType, uint64_t" Function,+,mf_classic_set_key_not_found,void,"MfClassicData*, uint8_t, MfClassicKeyType" +Function,+,mf_classic_set_uid,_Bool,"MfClassicData*, const uint8_t*, size_t" Function,+,mf_classic_value_to_block,void,"int32_t, uint8_t, MfClassicBlock*" Function,+,mf_classic_verify,_Bool,"MfClassicData*, const FuriString*" Function,+,mf_desfire_alloc,MfDesfireData*, @@ -2090,6 +2108,7 @@ Function,+,mf_desfire_is_equal,_Bool,"const MfDesfireData*, const MfDesfireData* Function,+,mf_desfire_load,_Bool,"MfDesfireData*, FlipperFormat*, uint32_t" Function,+,mf_desfire_reset,void,MfDesfireData* Function,+,mf_desfire_save,_Bool,"const MfDesfireData*, FlipperFormat*" +Function,+,mf_desfire_set_uid,_Bool,"MfDesfireData*, const uint8_t*, size_t" Function,+,mf_desfire_verify,_Bool,"MfDesfireData*, const FuriString*" Function,+,mf_ultralight_alloc,MfUltralightData*, Function,+,mf_ultralight_copy,void,"MfUltralightData*, const MfUltralightData*" @@ -2116,6 +2135,7 @@ Function,+,mf_ultralight_poller_read_version,MfUltralightError,"Nfc*, MfUltralig Function,+,mf_ultralight_poller_write_page,MfUltralightError,"Nfc*, uint16_t, MfUltralightPage*" Function,+,mf_ultralight_reset,void,MfUltralightData* Function,+,mf_ultralight_save,_Bool,"const MfUltralightData*, FlipperFormat*" +Function,+,mf_ultralight_set_uid,_Bool,"MfUltralightData*, const uint8_t*, size_t" Function,+,mf_ultralight_verify,_Bool,"MfUltralightData*, const FuriString*" Function,-,mkdtemp,char*,char* Function,-,mkostemp,int,"char*, int" @@ -2170,6 +2190,7 @@ Function,+,nfc_device_reset,void,NfcDevice* Function,+,nfc_device_save,_Bool,"NfcDevice*, const char*" Function,+,nfc_device_set_data,void,"NfcDevice*, NfcProtocol, const NfcDeviceData*" Function,+,nfc_device_set_loading_callback,void,"NfcDevice*, NfcLoadingCallback, void*" +Function,+,nfc_device_set_uid,_Bool,"NfcDevice*, const uint8_t*, size_t" Function,-,nfc_free,void,Nfc* Function,-,nfc_iso14443_3a_listener_tx_custom_parity,NfcError,"Nfc*, const BitBuffer*" Function,-,nfc_iso14443_3a_sdd_frame,NfcError,"Nfc*, const BitBuffer*, BitBuffer*, uint32_t" @@ -3507,6 +3528,7 @@ Variable,+,message_sound_off,const NotificationMessage, Variable,+,message_vibro_off,const NotificationMessage, Variable,+,message_vibro_on,const NotificationMessage, Variable,-,nfc_device_iso14443_3a,const NfcDeviceBase, +Variable,+,nfc_device_iso14443_3b,const NfcDeviceBase, Variable,-,nfc_device_iso14443_4a,const NfcDeviceBase, Variable,-,nfc_device_mf_classic,const NfcDeviceBase, Variable,-,nfc_device_mf_desfire,const NfcDeviceBase, diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc.c b/firmware/targets/f7/furi_hal/f_hal_nfc.c index 70e33bf83376..139edd270722 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfc.c +++ b/firmware/targets/f7/furi_hal/f_hal_nfc.c @@ -299,71 +299,169 @@ FHalNfcError f_hal_nfc_low_power_mode_stop() { } static void f_hal_nfc_configure_poller_common(FuriHalSpiBusHandle* handle) { - st25r3916_change_reg_bits( - handle, ST25R3916_REG_MODE, ST25R3916_REG_MODE_tr_am, ST25R3916_REG_MODE_tr_am_am); - st25r3916_change_reg_bits( - handle, - ST25R3916_REG_TX_DRIVER, - ST25R3916_REG_TX_DRIVER_am_mod_mask, - ST25R3916_REG_TX_DRIVER_am_mod_12percent); + // Disable wake up + st25r3916_clear_reg_bits(handle, ST25R3916_REG_OP_CONTROL, ST25R3916_REG_OP_CONTROL_wu); + // Enable correlator st25r3916_change_reg_bits( handle, - ST25R3916_REG_AUX_MOD, - (ST25R3916_REG_AUX_MOD_dis_reg_am | ST25R3916_REG_AUX_MOD_res_am), - 0x00); + ST25R3916_REG_AUX, + ST25R3916_REG_AUX_dis_corr, + ST25R3916_REG_AUX_dis_corr_correlator); + st25r3916_change_reg_bits(handle, ST25R3916_REG_ANT_TUNE_A, 0xff, 0x82); st25r3916_change_reg_bits(handle, ST25R3916_REG_ANT_TUNE_B, 0xFF, 0x82); - st25r3916_change_reg_bits(handle, ST25R3916_REG_OVERSHOOT_CONF1, 0xff, 0x00); - st25r3916_change_reg_bits(handle, ST25R3916_REG_OVERSHOOT_CONF2, 0xff, 0x00); - st25r3916_change_reg_bits(handle, ST25R3916_REG_UNDERSHOOT_CONF1, 0xff, 0x00); - st25r3916_change_reg_bits(handle, ST25R3916_REG_UNDERSHOOT_CONF2, 0xff, 0x00); + + st25r3916_write_reg(handle, ST25R3916_REG_OVERSHOOT_CONF1, 0x00); + st25r3916_write_reg(handle, ST25R3916_REG_OVERSHOOT_CONF2, 0x00); + st25r3916_write_reg(handle, ST25R3916_REG_UNDERSHOOT_CONF1, 0x00); + st25r3916_write_reg(handle, ST25R3916_REG_UNDERSHOOT_CONF2, 0x00); } +// TODO: Refactor this function to be more modular and readable FHalNfcError f_hal_nfc_set_mode(FHalNfcMode mode, FHalNfcBitrate bitrate) { FHalNfcError error = FHalNfcErrorNone; FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; - if(mode == FHalNfcModeIso14443_3aPoller) { + if(mode == FHalNfcModeIso14443_3aPoller || mode == FHalNfcModeIso14443_3aListener) { + if(mode == FHalNfcModeIso14443_3aPoller) { + // Poller configuration + f_hal_nfc_configure_poller_common(handle); + // Enable ISO14443A mode, OOK modulation + st25r3916_change_reg_bits( + handle, + ST25R3916_REG_MODE, + ST25R3916_REG_MODE_om_mask | ST25R3916_REG_MODE_tr_am, + ST25R3916_REG_MODE_om_iso14443a | ST25R3916_REG_MODE_tr_am_ook); + + // Overshoot protection - is this necessary here? + st25r3916_change_reg_bits(handle, ST25R3916_REG_OVERSHOOT_CONF1, 0xff, 0x40); + st25r3916_change_reg_bits(handle, ST25R3916_REG_OVERSHOOT_CONF2, 0xff, 0x03); + st25r3916_change_reg_bits(handle, ST25R3916_REG_UNDERSHOOT_CONF1, 0xff, 0x40); + st25r3916_change_reg_bits(handle, ST25R3916_REG_UNDERSHOOT_CONF2, 0xff, 0x03); + + } else { + // Listener configuration + f_hal_nfca_listener_init(); + st25r3916_write_reg( + handle, + ST25R3916_REG_OP_CONTROL, + ST25R3916_REG_OP_CONTROL_en | ST25R3916_REG_OP_CONTROL_rx_en | + ST25R3916_REG_OP_CONTROL_en_fd_auto_efd); + st25r3916_write_reg( + handle, ST25R3916_REG_MODE, ST25R3916_REG_MODE_targ_targ | ST25R3916_REG_MODE_om0); + st25r3916_write_reg( + handle, + ST25R3916_REG_PASSIVE_TARGET, + ST25R3916_REG_PASSIVE_TARGET_fdel_2 | ST25R3916_REG_PASSIVE_TARGET_fdel_0 | + ST25R3916_REG_PASSIVE_TARGET_d_ac_ap2p | + ST25R3916_REG_PASSIVE_TARGET_d_212_424_1r); + + st25r3916_write_reg(handle, ST25R3916_REG_MASK_RX_TIMER, 0x02); + } + + if(bitrate == FHalNfcBitrate106) { + // Bitrate-dependent NFC-A settings + + // 1st stage zero = 600kHz, 3rd stage zero = 200 kHz + st25r3916_write_reg(handle, ST25R3916_REG_RX_CONF1, ST25R3916_REG_RX_CONF1_z600k); + // AGC enabled, ratio 3:1, squelch after TX + st25r3916_write_reg( + handle, + ST25R3916_REG_RX_CONF2, + ST25R3916_REG_RX_CONF2_agc6_3 | ST25R3916_REG_RX_CONF2_agc_m | + ST25R3916_REG_RX_CONF2_agc_en | ST25R3916_REG_RX_CONF2_sqm_dyn); + // HF operation, full gain on AM and PM channels + st25r3916_write_reg(handle, ST25R3916_REG_RX_CONF3, 0x00); + // No gain reduction on AM and PM channels + st25r3916_write_reg(handle, ST25R3916_REG_RX_CONF4, 0x00); + // Correlator config + st25r3916_write_reg( + handle, + ST25R3916_REG_CORR_CONF1, + ST25R3916_REG_CORR_CONF1_corr_s0 | ST25R3916_REG_CORR_CONF1_corr_s4 | + ST25R3916_REG_CORR_CONF1_corr_s6); + // Sleep mode disable, 424kHz mode off + st25r3916_write_reg(handle, ST25R3916_REG_CORR_CONF2, 0x00); + } + + } else if(mode == FHalNfcModeIso14443_3bPoller /* TODO: Listener support */) { f_hal_nfc_configure_poller_common(handle); - // Disable wake up - st25r3916_clear_reg_bits(handle, ST25R3916_REG_OP_CONTROL, ST25R3916_REG_OP_CONTROL_wu); - // Enable ISO14443A mode - st25r3916_write_reg(handle, ST25R3916_REG_MODE, ST25R3916_REG_MODE_om_iso14443a); + // Enable ISO14443B mode, AM modulation st25r3916_change_reg_bits( handle, - ST25R3916_REG_AUX, - ST25R3916_REG_AUX_dis_corr, - ST25R3916_REG_AUX_dis_corr_correlator); - st25r3916_change_reg_bits(handle, ST25R3916_REG_OVERSHOOT_CONF1, 0xff, 0x40); - st25r3916_change_reg_bits(handle, ST25R3916_REG_OVERSHOOT_CONF2, 0xff, 0x03); - st25r3916_change_reg_bits(handle, ST25R3916_REG_UNDERSHOOT_CONF1, 0xff, 0x40); - st25r3916_change_reg_bits(handle, ST25R3916_REG_UNDERSHOOT_CONF2, 0xff, 0x03); - } else if(mode == FHalNfcModeIso14443_3aListener) { - f_hal_nfca_listener_init(); - st25r3916_write_reg( - handle, - ST25R3916_REG_OP_CONTROL, - ST25R3916_REG_OP_CONTROL_en | ST25R3916_REG_OP_CONTROL_rx_en | - ST25R3916_REG_OP_CONTROL_en_fd_auto_efd); - st25r3916_write_reg( - handle, ST25R3916_REG_MODE, ST25R3916_REG_MODE_targ_targ | ST25R3916_REG_MODE_om0); - st25r3916_write_reg( + ST25R3916_REG_MODE, + ST25R3916_REG_MODE_om_mask | ST25R3916_REG_MODE_tr_am, + ST25R3916_REG_MODE_om_iso14443b | ST25R3916_REG_MODE_tr_am_am); + + // 10% ASK modulation + st25r3916_change_reg_bits( handle, - ST25R3916_REG_PASSIVE_TARGET, - ST25R3916_REG_PASSIVE_TARGET_fdel_2 | ST25R3916_REG_PASSIVE_TARGET_fdel_0 | - ST25R3916_REG_PASSIVE_TARGET_d_ac_ap2p | - ST25R3916_REG_PASSIVE_TARGET_d_212_424_1r); + ST25R3916_REG_TX_DRIVER, + ST25R3916_REG_TX_DRIVER_am_mod_mask, + ST25R3916_REG_TX_DRIVER_am_mod_10percent); - st25r3916_write_reg(handle, ST25R3916_REG_MASK_RX_TIMER, 0x02); - } + // Use regulator AM, resistive AM disabled + st25r3916_clear_reg_bits( + handle, + ST25R3916_REG_AUX_MOD, + ST25R3916_REG_AUX_MOD_dis_reg_am | ST25R3916_REG_AUX_MOD_res_am); - if(bitrate == FHalNfcBitrate106) { - st25r3916_change_reg_bits(handle, ST25R3916_REG_RX_CONF1, 0xff, 0x08); - st25r3916_change_reg_bits(handle, ST25R3916_REG_RX_CONF2, 0xff, 0x2d); - st25r3916_change_reg_bits(handle, ST25R3916_REG_RX_CONF3, 0xff, 0x00); - st25r3916_change_reg_bits(handle, ST25R3916_REG_RX_CONF4, 0xff, 0x00); - st25r3916_change_reg_bits(handle, ST25R3916_REG_CORR_CONF1, 0xff, 0x51); - st25r3916_change_reg_bits(handle, ST25R3916_REG_CORR_CONF2, 0xff, 0x00); + // EGT = 0 etu + // SOF = 10 etu LOW + 2 etu HIGH + // EOF = 10 etu + st25r3916_change_reg_bits( + handle, + ST25R3916_REG_ISO14443B_1, + ST25R3916_REG_ISO14443B_1_egt_mask | ST25R3916_REG_ISO14443B_1_sof_mask | + ST25R3916_REG_ISO14443B_1_eof, + (0U << ST25R3916_REG_ISO14443B_1_egt_shift) | ST25R3916_REG_ISO14443B_1_sof_0_10etu | + ST25R3916_REG_ISO14443B_1_sof_1_2etu | ST25R3916_REG_ISO14443B_1_eof_10etu); + + // TR1 = 80 / fs + // B' mode off (no_sof & no_eof = 0) + st25r3916_change_reg_bits( + handle, + ST25R3916_REG_ISO14443B_2, + ST25R3916_REG_ISO14443B_2_tr1_mask | ST25R3916_REG_ISO14443B_2_no_sof | + ST25R3916_REG_ISO14443B_2_no_eof, + ST25R3916_REG_ISO14443B_2_tr1_80fs80fs); + + if(bitrate == FHalNfcBitrate106) { + // Bitrate-dependent NFC-B settings + + // 1st stage zero = 60kHz, 3rd stage zero = 200 kHz + st25r3916_write_reg(handle, ST25R3916_REG_RX_CONF1, ST25R3916_REG_RX_CONF1_h200); + + // Enable AGC + // AGC Ratio 6 + // AGC algorithm with RESET (recommended for ISO14443-B) + // AGC operation during complete receive period + // Squelch ratio 6/3 (recommended for ISO14443-B) + // Squelch automatic activation on TX end + st25r3916_write_reg( + handle, + ST25R3916_REG_RX_CONF2, + ST25R3916_REG_RX_CONF2_agc6_3 | ST25R3916_REG_RX_CONF2_agc_alg | + ST25R3916_REG_RX_CONF2_agc_m | ST25R3916_REG_RX_CONF2_agc_en | + ST25R3916_REG_RX_CONF2_pulz_61 | ST25R3916_REG_RX_CONF2_sqm_dyn); + + // HF operation, full gain on AM and PM channels + st25r3916_write_reg(handle, ST25R3916_REG_RX_CONF3, 0x00); + // No gain reduction on AM and PM channels + st25r3916_write_reg(handle, ST25R3916_REG_RX_CONF4, 0x00); + + // Subcarrier end detector enabled + // Subcarrier end detection level = 66% + // BPSK start 33 pilot pulses + // AM & PM summation before digitizing on + st25r3916_write_reg( + handle, + ST25R3916_REG_CORR_CONF1, + ST25R3916_REG_CORR_CONF1_corr_s0 | ST25R3916_REG_CORR_CONF1_corr_s1 | + ST25R3916_REG_CORR_CONF1_corr_s3 | ST25R3916_REG_CORR_CONF1_corr_s4); + // Sleep mode disable, 424kHz mode off + st25r3916_write_reg(handle, ST25R3916_REG_CORR_CONF2, 0x00); + } } return error; diff --git a/firmware/targets/furi_hal_include/f_hal_nfc.h b/firmware/targets/furi_hal_include/f_hal_nfc.h index 9dccf1365319..72563b9d9d6a 100644 --- a/firmware/targets/furi_hal_include/f_hal_nfc.h +++ b/firmware/targets/furi_hal_include/f_hal_nfc.h @@ -44,8 +44,8 @@ typedef enum { FHalNfcModeIso14443_3aPoller, FHalNfcModeIso14443_3aListener, - FHalNfcModeNfcbPoller, - FHalNfcModeNfcbListener, + FHalNfcModeIso14443_3bPoller, + FHalNfcModeIso14443_3bListener, FHalNfcModeNfcfPoller, FHalNfcModeNfcfListener, diff --git a/lib/nfc/SConscript b/lib/nfc/SConscript index fb9d1d3cc5ff..4702c7b96f08 100644 --- a/lib/nfc/SConscript +++ b/lib/nfc/SConscript @@ -13,12 +13,14 @@ env.Append( File("nfc_scanner.h"), # Protocols File("protocols/iso14443_3a/iso14443_3a.h"), + File("protocols/iso14443_3b/iso14443_3b.h"), File("protocols/iso14443_4a/iso14443_4a.h"), File("protocols/mf_ultralight/mf_ultralight.h"), File("protocols/mf_classic/mf_classic.h"), File("protocols/mf_desfire/mf_desfire.h"), # Pollers File("protocols/iso14443_3a/iso14443_3a_poller.h"), + File("protocols/iso14443_3b/iso14443_3b_poller.h"), File("protocols/iso14443_4a/iso14443_4a_poller.h"), File("protocols/mf_ultralight/mf_ultralight_poller.h"), File("protocols/mf_classic/mf_classic_poller.h"), @@ -34,6 +36,7 @@ env.Append( File("protocols/mf_classic/mf_classic_poller_sync_api.h"), # Misc File("helpers/nfc_util.h"), + File("helpers/iso14443_crc.h"), ], ) diff --git a/lib/nfc/helpers/bit_buffer.c b/lib/nfc/helpers/bit_buffer.c index c9c6bd5c980a..566393e784ed 100644 --- a/lib/nfc/helpers/bit_buffer.c +++ b/lib/nfc/helpers/bit_buffer.c @@ -41,6 +41,9 @@ void bit_buffer_reset(BitBuffer* buf) { void bit_buffer_copy(BitBuffer* buf, const BitBuffer* other) { furi_assert(buf); furi_assert(other); + + if(buf == other) return; + furi_assert(buf->capacity_bytes * BITS_IN_BYTE >= other->size_bits); memcpy(buf->data, other->data, bit_buffer_get_size_bytes(other)); diff --git a/lib/nfc/helpers/iso14443_crc.c b/lib/nfc/helpers/iso14443_crc.c new file mode 100644 index 000000000000..72fedb9e7e49 --- /dev/null +++ b/lib/nfc/helpers/iso14443_crc.c @@ -0,0 +1,59 @@ +#include "iso14443_crc.h" + +#include + +#define ISO14443_3A_CRC_INIT (0x6363U) +#define ISO14443_3B_CRC_INIT (0xFFFFU) + +static uint16_t + iso14443_crc_calculate(Iso14443CrcType type, const uint8_t* data, size_t data_size) { + furi_assert(data); + + uint16_t crc; + + if(type == Iso14443CrcTypeA) { + crc = ISO14443_3A_CRC_INIT; + } else if(type == Iso14443CrcTypeB) { + crc = ISO14443_3B_CRC_INIT; + } else { + furi_crash("Wrong ISO14443 CRC type"); + } + + for(size_t i = 0; i < data_size; i++) { + uint8_t byte = data[i]; + byte ^= (uint8_t)(crc & 0xff); + byte ^= byte << 4; + crc = (crc >> 8) ^ (((uint16_t)byte) << 8) ^ (((uint16_t)byte) << 3) ^ (byte >> 4); + } + + return type == Iso14443CrcTypeA ? crc : ~crc; +} + +void iso14443_crc_append(Iso14443CrcType type, BitBuffer* buf) { + const uint8_t* data = bit_buffer_get_data(buf); + const size_t data_size = bit_buffer_get_size_bytes(buf); + + const uint16_t crc = iso14443_crc_calculate(type, data, data_size); + bit_buffer_append_bytes(buf, (const uint8_t*)&crc, ISO14443_CRC_SIZE); +} + +bool iso14443_crc_check(Iso14443CrcType type, const BitBuffer* buf) { + const size_t data_size = bit_buffer_get_size_bytes(buf); + if(data_size <= ISO14443_CRC_SIZE) return false; + + uint16_t crc_received; + bit_buffer_write_bytes_mid( + buf, &crc_received, data_size - ISO14443_CRC_SIZE, ISO14443_CRC_SIZE); + + const uint8_t* data = bit_buffer_get_data(buf); + const uint16_t crc_calc = iso14443_crc_calculate(type, data, data_size - ISO14443_CRC_SIZE); + + return (crc_calc == crc_received); +} + +void iso14443_crc_trim(BitBuffer* buf) { + const size_t data_size = bit_buffer_get_size_bytes(buf); + furi_assert(data_size > ISO14443_CRC_SIZE); + + bit_buffer_set_size_bytes(buf, data_size - ISO14443_CRC_SIZE); +} diff --git a/lib/nfc/helpers/iso14443_crc.h b/lib/nfc/helpers/iso14443_crc.h new file mode 100644 index 000000000000..c9ad5397fc3e --- /dev/null +++ b/lib/nfc/helpers/iso14443_crc.h @@ -0,0 +1,27 @@ +#pragma once + +#include +#include + +#include "bit_buffer.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ISO14443_CRC_SIZE sizeof(uint16_t) + +typedef enum { + Iso14443CrcTypeA, + Iso14443CrcTypeB, +} Iso14443CrcType; + +void iso14443_crc_append(Iso14443CrcType type, BitBuffer* buf); + +bool iso14443_crc_check(Iso14443CrcType type, const BitBuffer* buf); + +void iso14443_crc_trim(BitBuffer* buf); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/nfc.c b/lib/nfc/nfc.c index 1090b412083c..1c4c0d955b1f 100644 --- a/lib/nfc/nfc.c +++ b/lib/nfc/nfc.c @@ -256,6 +256,9 @@ void nfc_config(Nfc* instance, NfcMode mode) { f_hal_nfc_low_power_mode_stop(); f_hal_nfc_set_mode(FHalNfcModeIso14443_3aListener, FHalNfcBitrate106); instance->config_state = NfcConfigurationStateDone; + } else if(mode == NfcModeIso14443_3bPoller) { + f_hal_nfc_set_mode(FHalNfcModeIso14443_3bPoller, FHalNfcBitrate106); + instance->config_state = NfcConfigurationStateDone; } } diff --git a/lib/nfc/nfc.h b/lib/nfc/nfc.h index 797e512ae0d0..bcb7066f3232 100644 --- a/lib/nfc/nfc.h +++ b/lib/nfc/nfc.h @@ -42,8 +42,8 @@ typedef enum { NfcModeIdle, NfcModeIso14443_3aPoller, NfcModeIso14443_3aListener, - NfcModeNfcbPoller, - NfcModeNfcbListener, + NfcModeIso14443_3bPoller, + NfcModeIso14443_3bListener, NfcModeNfcfPoller, NfcModeNfcfListener, NfcModeNfcvPoller, diff --git a/lib/nfc/nfc_device.c b/lib/nfc/nfc_device.c index c7fb3c94d197..62aeb6ab48f0 100644 --- a/lib/nfc/nfc_device.c +++ b/lib/nfc/nfc_device.c @@ -12,6 +12,8 @@ #define NFC_DEVICE_UID_KEY "UID" #define NFC_DEVICE_TYPE_KEY "Device type" +#define NFC_DEVICE_UID_MAX_LEN (10U) + struct NfcDevice { NfcProtocol protocol; NfcDeviceData* protocol_data; @@ -104,6 +106,13 @@ const uint8_t* nfc_device_get_uid(const NfcDevice* instance, size_t* uid_len) { return nfc_devices[instance->protocol]->get_uid(instance->protocol_data, uid_len); } +bool nfc_device_set_uid(NfcDevice* instance, const uint8_t* uid, size_t uid_len) { + furi_assert(instance); + furi_assert(instance->protocol < NfcProtocolNum); + + return nfc_devices[instance->protocol]->set_uid(instance->protocol_data, uid, uid_len); +} + void nfc_device_set_data( NfcDevice* instance, NfcProtocol protocol, @@ -221,6 +230,26 @@ bool nfc_device_save(NfcDevice* instance, const char* path) { return saved; } +static bool nfc_device_load_uid( + FlipperFormat* ff, + uint8_t* uid, + uint32_t* uid_len, + const uint32_t uid_maxlen) { + bool loaded = false; + + do { + uint32_t uid_len_current; + if(!flipper_format_get_value_count(ff, NFC_DEVICE_UID_KEY, &uid_len_current)) break; + if(uid_len_current > uid_maxlen) break; + if(!flipper_format_read_hex(ff, NFC_DEVICE_UID_KEY, uid, uid_len_current)) break; + + *uid_len = uid_len_current; + loaded = true; + } while(false); + + return loaded; +} + static bool nfc_device_load_unified(NfcDevice* instance, FlipperFormat* ff, uint32_t version) { bool loaded = false; @@ -246,17 +275,22 @@ static bool nfc_device_load_unified(NfcDevice* instance, FlipperFormat* ff, uint instance->protocol_data = nfc_devices[protocol]->alloc(); // Load UID - // TODO: move the respective code from ISO14443-3A to here + uint8_t uid[NFC_DEVICE_UID_MAX_LEN]; + uint32_t uid_len; + + if(!nfc_device_load_uid(ff, uid, &uid_len, NFC_DEVICE_UID_MAX_LEN)) break; + if(!nfc_device_set_uid(instance, uid, uid_len)) break; // Load data - if(!nfc_devices[protocol]->load(instance->protocol_data, ff, version)) { - nfc_device_clear(instance); - break; - } + if(!nfc_devices[protocol]->load(instance->protocol_data, ff, version)) break; loaded = true; } while(false); + if(!loaded) { + nfc_device_clear(instance); + } + furi_string_free(temp_str); return loaded; } @@ -277,11 +311,16 @@ static bool nfc_device_load_legacy(NfcDevice* instance, FlipperFormat* ff, uint3 instance->protocol = protocol; instance->protocol_data = nfc_devices[protocol]->alloc(); + // Verify protocol if(nfc_devices[protocol]->verify(instance->protocol_data, temp_str)) { - if(nfc_devices[protocol]->load(instance->protocol_data, ff, version)) { - loaded = true; - break; - } + uint8_t uid[NFC_DEVICE_UID_MAX_LEN]; + uint32_t uid_len; + + // Load data + loaded = nfc_device_load_uid(ff, uid, &uid_len, NFC_DEVICE_UID_MAX_LEN) && + nfc_device_set_uid(instance, uid, uid_len) && + nfc_devices[protocol]->load(instance->protocol_data, ff, version); + break; } nfc_device_clear(instance); diff --git a/lib/nfc/nfc_device.h b/lib/nfc/nfc_device.h index 74ca73eaf6e4..8a37f3064997 100644 --- a/lib/nfc/nfc_device.h +++ b/lib/nfc/nfc_device.h @@ -35,6 +35,8 @@ const char* nfc_device_get_name(const NfcDevice* instance, NfcDeviceNameType nam const uint8_t* nfc_device_get_uid(const NfcDevice* instance, size_t* uid_len); +bool nfc_device_set_uid(NfcDevice* instance, const uint8_t* uid, size_t uid_len); + void nfc_device_set_data( NfcDevice* instance, NfcProtocol protocol, diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a.c b/lib/nfc/protocols/iso14443_3a/iso14443_3a.c index 6ecc0d350644..98fcb6bf03b7 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a.c +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a.c @@ -3,12 +3,10 @@ #include #include -#define ISO14443_3A_CRC_INIT (0x6363) #define ISO14443_3A_PROTOCOL_NAME_LEGACY "UID" #define ISO14443_3A_PROTOCOL_NAME "ISO14443-3A" -#define ISO14443_3A_DEVICE_NAME "Unknown ISO14443-3A Tag" +#define ISO14443_3A_DEVICE_NAME "ISO14443-3A (Unknown)" -#define ISO14443_3A_UID_KEY "UID" #define ISO14443_3A_ATQA_KEY "ATQA" #define ISO14443_3A_SAK_KEY "SAK" @@ -24,6 +22,7 @@ const NfcDeviceBase nfc_device_iso14443_3a = { .is_equal = (NfcDeviceEqual)iso14443_3a_is_equal, .get_name = (NfcDeviceGetName)iso14443_3a_get_device_name, .get_uid = (NfcDeviceGetUid)iso14443_3a_get_uid, + .set_uid = (NfcDeviceSetUid)iso14443_3a_set_uid, .get_base_data = (NfcDeviceGetBaseData)iso14443_3a_get_base_data, }; @@ -62,17 +61,6 @@ bool iso14443_3a_load(Iso14443_3aData* data, FlipperFormat* ff, uint32_t version bool parsed = false; do { - // TODO: Load UID in nfc_device.c - // if(version < NFC_UNIFIED_FORMAT_VERSION) { - uint32_t uid_len = 0; - if(!flipper_format_get_value_count(ff, ISO14443_3A_UID_KEY, &uid_len)) break; - if(!(uid_len == 4 || uid_len == 7)) break; - - data->uid_len = uid_len; - - if(!flipper_format_read_hex(ff, ISO14443_3A_UID_KEY, data->uid, data->uid_len)) break; - // } - // Common to all format versions if(!flipper_format_read_hex(ff, ISO14443_3A_ATQA_KEY, data->atqa, 2)) break; if(!flipper_format_read_hex(ff, ISO14443_3A_SAK_KEY, &data->sak, 1)) break; @@ -133,27 +121,24 @@ const uint8_t* iso14443_3a_get_uid(const Iso14443_3aData* data, size_t* uid_len) return data->uid; } -const Iso14443_3aData* iso14443_3a_get_base_data(const Iso14443_3aData* data) { - UNUSED(data); - furi_crash("No base data"); -} - -static uint16_t iso14443_3a_get_crc(const uint8_t* buff, uint16_t len) { - furi_assert(buff); - furi_assert(len); +bool iso14443_3a_set_uid(Iso14443_3aData* data, const uint8_t* uid, size_t uid_len) { + furi_assert(data); - uint16_t crc = ISO14443_3A_CRC_INIT; - uint8_t byte = 0; + const bool uid_valid = uid_len == ISO14443_3A_UID_4_BYTES || + uid_len == ISO14443_3A_UID_7_BYTES || + uid_len == ISO14443_3A_UID_10_BYTES; - for(uint8_t i = 0; i < len; i++) { - byte = buff[i]; - byte ^= (uint8_t)(crc & 0xff); - byte ^= byte << 4; - crc = (crc >> 8) ^ (((uint16_t)byte) << 8) ^ (((uint16_t)byte) << 3) ^ - (((uint16_t)byte) >> 4); + if(uid_valid) { + memcpy(data->uid, uid, uid_len); + data->uid_len = uid_len; } - return crc; + return uid_valid; +} + +const Iso14443_3aData* iso14443_3a_get_base_data(const Iso14443_3aData* data) { + UNUSED(data); + furi_crash("No base data"); } uint32_t iso14443_3a_get_cuid(const Iso14443_3aData* iso14443_3a_data) { @@ -168,42 +153,3 @@ uint32_t iso14443_3a_get_cuid(const Iso14443_3aData* iso14443_3a_data) { return cuid; } - -void iso14443_3a_append_crc(BitBuffer* buffer) { - furi_assert(buffer); - - const uint8_t* data = bit_buffer_get_data(buffer); - size_t bytes = bit_buffer_get_size_bytes(buffer); - - uint16_t crc = iso14443_3a_get_crc(data, bytes); - uint8_t crc_bytes[2] = {(uint8_t)crc, (uint8_t)(crc >> 8)}; - bit_buffer_append_bytes(buffer, crc_bytes, sizeof(crc_bytes)); -} - -bool iso14443_3a_check_crc(const BitBuffer* buf) { - furi_assert(buf); - - bool crc_ok = false; - do { - const uint8_t* data = bit_buffer_get_data(buf); - size_t bytes = bit_buffer_get_size_bytes(buf); - if(bytes < 3) break; - - uint16_t crc_calc = iso14443_3a_get_crc(data, bytes - 2); - uint8_t crc_start = bit_buffer_get_byte(buf, bytes - 2); - uint8_t crc_end = bit_buffer_get_byte(buf, bytes - 1); - uint16_t crc_received = (crc_end << 8) | crc_start; - crc_ok = (crc_calc == crc_received); - } while(false); - - return crc_ok; -} - -void iso14443_3a_trim_crc(BitBuffer* buf) { - furi_assert(buf); - - size_t bytes = bit_buffer_get_size_bytes(buf); - furi_assert(bytes > 2); - - bit_buffer_set_size_bytes(buf, bytes - 2); -} diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a.h b/lib/nfc/protocols/iso14443_3a/iso14443_3a.h index 46b443acafc7..a899472f160e 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a.h +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a.h @@ -7,7 +7,10 @@ extern "C" { #endif -#define ISO14443_3A_MAX_UID_SIZE (10U) +#define ISO14443_3A_UID_4_BYTES (4U) +#define ISO14443_3A_UID_7_BYTES (7U) +#define ISO14443_3A_UID_10_BYTES (10U) +#define ISO14443_3A_MAX_UID_SIZE ISO14443_3A_UID_10_BYTES #define ISO14443_3A_GUARD_TIME_US (5000) #define ISO14443_3A_FDT_POLL_FC (1620) @@ -81,16 +84,12 @@ const char* iso14443_3a_get_device_name(const Iso14443_3aData* data, NfcDeviceNa const uint8_t* iso14443_3a_get_uid(const Iso14443_3aData* data, size_t* uid_len); +bool iso14443_3a_set_uid(Iso14443_3aData* data, const uint8_t* uid, size_t uid_len); + const Iso14443_3aData* iso14443_3a_get_base_data(const Iso14443_3aData* data); uint32_t iso14443_3a_get_cuid(const Iso14443_3aData* iso14443_3a_data); -void iso14443_3a_append_crc(BitBuffer* buffer); - -bool iso14443_3a_check_crc(const BitBuffer* buf); - -void iso14443_3a_trim_crc(BitBuffer* buf); - #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c b/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c index 96da690cfde6..c6d14cc9187a 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c @@ -1,5 +1,7 @@ #include "iso14443_3a_listener_i.h" -#include "iso14443_3a_listener_defs.h" + +#include "nfc/protocols/nfc_listener_base.h" +#include "nfc/helpers/iso14443_crc.h" #include #include @@ -13,7 +15,7 @@ static bool iso14443_3a_listener_halt_received(BitBuffer* buf) { do { if(bit_buffer_get_size_bytes(buf) != 4) break; - if(!iso14443_3a_check_crc(buf)) break; + if(!iso14443_crc_check(Iso14443CrcTypeA, buf)) break; if(bit_buffer_get_byte(buf, 0) != 0x50) break; if(bit_buffer_get_byte(buf, 1) != 0x00) break; halt_cmd_received = true; @@ -101,10 +103,10 @@ NfcCommand iso14443_3a_listener_run(NfcGenericEvent event, void* context) { command = instance->callback(instance->generic_event, instance->context); } } else { - if(iso14443_3a_check_crc(nfc_event->data.buffer)) { + if(iso14443_crc_check(Iso14443CrcTypeA, nfc_event->data.buffer)) { instance->iso14443_3a_event.type = Iso14443_3aListenerEventTypeReceivedStandardFrame; - iso14443_3a_trim_crc(nfc_event->data.buffer); + iso14443_crc_trim(nfc_event->data.buffer); } else { instance->iso14443_3a_event.type = Iso14443_3aListenerEventTypeReceivedData; } diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener_i.c b/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener_i.c index 4f5f702b6d56..76b3b341a9d4 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener_i.c +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener_i.c @@ -1,5 +1,7 @@ #include "iso14443_3a_listener_i.h" +#include "nfc/helpers/iso14443_crc.h" + #define TAG "Iso14443_3aListener" static Iso14443_3aError iso14443_3a_listener_process_nfc_error(NfcError error) { @@ -66,7 +68,7 @@ Iso14443_3aError iso14443_3a_listener_send_standard_frame( Iso14443_3aError ret = Iso14443_3aErrorNone; do { bit_buffer_copy(instance->tx_buffer, tx_buffer); - iso14443_3a_append_crc(instance->tx_buffer); + iso14443_crc_append(Iso14443CrcTypeA, instance->tx_buffer); NfcError error = nfc_listener_tx(instance->nfc, instance->tx_buffer); if(error != NfcErrorNone) { @@ -77,4 +79,4 @@ Iso14443_3aError iso14443_3a_listener_send_standard_frame( } while(false); return ret; -} \ No newline at end of file +} diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.c b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.c index 90b9169a5866..a98894f3d019 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.c +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.c @@ -2,6 +2,8 @@ #include +#include "nfc/helpers/iso14443_crc.h" + #define TAG "ISO14443_3A" static Iso14443_3aError iso14443_3a_poller_process_error(NfcError error) { @@ -39,7 +41,7 @@ static Iso14443_3aError iso14443_3a_poller_standard_frame_exchange( furi_assert(tx_bytes <= bit_buffer_get_capacity_bytes(instance->tx_buffer) - 2); bit_buffer_copy(instance->tx_buffer, tx_buffer); - iso14443_3a_append_crc(instance->tx_buffer); + iso14443_crc_append(Iso14443CrcTypeA, instance->tx_buffer); Iso14443_3aError ret = Iso14443_3aErrorNone; do { @@ -50,12 +52,12 @@ static Iso14443_3aError iso14443_3a_poller_standard_frame_exchange( } bit_buffer_copy(rx_buffer, instance->rx_buffer); - if(!iso14443_3a_check_crc(instance->rx_buffer)) { + if(!iso14443_crc_check(Iso14443CrcTypeA, instance->rx_buffer)) { ret = Iso14443_3aErrorWrongCrc; break; } - iso14443_3a_trim_crc(rx_buffer); + iso14443_crc_trim(rx_buffer); } while(false); return ret; diff --git a/lib/nfc/protocols/iso14443_3b/iso14443_3b.c b/lib/nfc/protocols/iso14443_3b/iso14443_3b.c new file mode 100644 index 000000000000..2d46da056c3e --- /dev/null +++ b/lib/nfc/protocols/iso14443_3b/iso14443_3b.c @@ -0,0 +1,145 @@ +#include "iso14443_3b.h" + +#include + +#include +#include + +#define ISO14443_3B_PROTOCOL_NAME "ISO14443-3B" +#define ISO14443_3B_DEVICE_NAME "ISO14443-3B (Unknown)" + +#define ISO14443_3B_APP_DATA_KEY "Application data" +#define ISO14443_3B_PROTOCOL_INFO_KEY "Protocol info" + +const NfcDeviceBase nfc_device_iso14443_3b = { + .protocol_name = ISO14443_3B_PROTOCOL_NAME, + .alloc = (NfcDeviceAlloc)iso14443_3b_alloc, + .free = (NfcDeviceFree)iso14443_3b_free, + .reset = (NfcDeviceReset)iso14443_3b_reset, + .copy = (NfcDeviceCopy)iso14443_3b_copy, + .verify = (NfcDeviceVerify)iso14443_3b_verify, + .load = (NfcDeviceLoad)iso14443_3b_load, + .save = (NfcDeviceSave)iso14443_3b_save, + .is_equal = (NfcDeviceEqual)iso14443_3b_is_equal, + .get_name = (NfcDeviceGetName)iso14443_3b_get_device_name, + .get_uid = (NfcDeviceGetUid)iso14443_3b_get_uid, + .set_uid = (NfcDeviceSetUid)iso14443_3b_set_uid, + .get_base_data = (NfcDeviceGetBaseData)iso14443_3b_get_base_data, +}; + +Iso14443_3bData* iso14443_3b_alloc() { + Iso14443_3bData* data = malloc(sizeof(Iso14443_3bData)); + return data; +} + +void iso14443_3b_free(Iso14443_3bData* data) { + furi_assert(data); + + free(data); +} + +void iso14443_3b_reset(Iso14443_3bData* data) { + memset(data, 0, sizeof(Iso14443_3bData)); +} + +void iso14443_3b_copy(Iso14443_3bData* data, const Iso14443_3bData* other) { + furi_assert(data); + furi_assert(other); + + *data = *other; +} + +bool iso14443_3b_verify(Iso14443_3bData* data, const FuriString* device_type) { + UNUSED(data); + UNUSED(device_type); + // TODO: How to distinguish from old ISO14443-3/4a? + return false; +} + +bool iso14443_3b_load(Iso14443_3bData* data, FlipperFormat* ff, uint32_t version) { + furi_assert(data); + + bool parsed = false; + + do { + if(version < NFC_UNIFIED_FORMAT_VERSION) break; + + if(!flipper_format_read_hex( + ff, ISO14443_3B_APP_DATA_KEY, data->app_data, ISO14443_3B_APP_DATA_SIZE)) + break; + if(!flipper_format_read_hex( + ff, + ISO14443_3B_PROTOCOL_INFO_KEY, + data->protocol_info, + ISO14443_3B_PROTOCOL_INFO_SIZE)) + break; + + parsed = true; + } while(false); + + return parsed; +} + +bool iso14443_3b_save(const Iso14443_3bData* data, FlipperFormat* ff) { + furi_assert(data); + + bool saved = false; + + do { + if(!flipper_format_write_comment_cstr(ff, ISO14443_3B_PROTOCOL_NAME " specific data")) + break; + if(!flipper_format_write_hex( + ff, ISO14443_3B_APP_DATA_KEY, data->app_data, ISO14443_3B_APP_DATA_SIZE)) + break; + if(!flipper_format_write_hex( + ff, + ISO14443_3B_PROTOCOL_INFO_KEY, + data->protocol_info, + ISO14443_3B_PROTOCOL_INFO_SIZE)) + break; + saved = true; + } while(false); + + return saved; +} + +bool iso14443_3b_is_equal(const Iso14443_3bData* data, const Iso14443_3bData* other) { + furi_assert(data); + furi_assert(other); + + return memcmp(data, other, sizeof(Iso14443_3bData)) == 0; +} + +const char* iso14443_3b_get_device_name(const Iso14443_3bData* data, NfcDeviceNameType name_type) { + UNUSED(data); + UNUSED(name_type); + + return ISO14443_3B_DEVICE_NAME; +} + +const uint8_t* iso14443_3b_get_uid(const Iso14443_3bData* data, size_t* uid_len) { + furi_assert(data); + + if(uid_len) { + *uid_len = ISO14443_3B_UID_SIZE; + } + + return data->uid; +} + +bool iso14443_3b_set_uid(Iso14443_3bData* data, const uint8_t* uid, size_t uid_len) { + furi_assert(data); + + const bool uid_valid = uid_len == ISO14443_3B_UID_SIZE; + + if(uid_valid) { + memcpy(data->uid, uid, uid_len); + } + + return uid_valid; +} + +const Iso14443_3bData* iso14443_3b_get_base_data(const Iso14443_3bData* data) { + UNUSED(data); + furi_crash("No base data"); +} diff --git a/lib/nfc/protocols/iso14443_3b/iso14443_3b.h b/lib/nfc/protocols/iso14443_3b/iso14443_3b.h new file mode 100644 index 000000000000..f222abd9db2e --- /dev/null +++ b/lib/nfc/protocols/iso14443_3b/iso14443_3b.h @@ -0,0 +1,81 @@ +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define ISO14443_3B_UID_SIZE (4U) +#define ISO14443_3B_APP_DATA_SIZE (4U) +#define ISO14443_3B_PROTOCOL_INFO_SIZE (3U) + +#define ISO14443_3B_GUARD_TIME_US (5000U) +#define ISO14443_3B_FDT_POLL_FC (9000U) +#define ISO14443_3B_FDT_ATTRIB_FC (42000U) +#define ISO14443_3B_POLL_POLL_MIN_US (1280U) + +#define ISO14443_3B_REQB_ALL (1U << 3) + +#define ISO14443_3B_ATTRIB_FRAME_SIZE_32 (0x02) +#define ISO14443_3B_ATTRIB_FRAME_SIZE_40 (0x03) +#define ISO14443_3B_ATTRIB_FRAME_SIZE_48 (0x04) +#define ISO14443_3B_ATTRIB_FRAME_SIZE_64 (0x05) +#define ISO14443_3B_ATTRIB_FRAME_SIZE_96 (0x06) +#define ISO14443_3B_ATTRIB_FRAME_SIZE_128 (0x07) +#define ISO14443_3B_ATTRIB_FRAME_SIZE_256 (0x08) + +typedef enum { + Iso14443_3bErrorNone, + Iso14443_3bErrorNotPresent, + Iso14443_3bErrorColResFailed, + Iso14443_3bErrorBufferOverflow, + Iso14443_3bErrorCommunication, + Iso14443_3bErrorFieldOff, + Iso14443_3bErrorWrongCrc, + Iso14443_3bErrorTimeout, +} Iso14443_3bError; + +typedef struct { + uint8_t flag; + uint8_t uid[ISO14443_3B_UID_SIZE]; + uint8_t app_data[ISO14443_3B_APP_DATA_SIZE]; + uint8_t protocol_info[ISO14443_3B_PROTOCOL_INFO_SIZE]; +} Iso14443_3bAtqB; + +typedef struct { + uint8_t uid[ISO14443_3B_UID_SIZE]; + uint8_t app_data[ISO14443_3B_APP_DATA_SIZE]; + uint8_t protocol_info[ISO14443_3B_PROTOCOL_INFO_SIZE]; +} Iso14443_3bData; + +extern const NfcDeviceBase nfc_device_iso14443_3b; + +Iso14443_3bData* iso14443_3b_alloc(); + +void iso14443_3b_free(Iso14443_3bData* data); + +void iso14443_3b_reset(Iso14443_3bData* data); + +void iso14443_3b_copy(Iso14443_3bData* data, const Iso14443_3bData* other); + +bool iso14443_3b_verify(Iso14443_3bData* data, const FuriString* device_type); + +bool iso14443_3b_load(Iso14443_3bData* data, FlipperFormat* ff, uint32_t version); + +bool iso14443_3b_save(const Iso14443_3bData* data, FlipperFormat* ff); + +bool iso14443_3b_is_equal(const Iso14443_3bData* data, const Iso14443_3bData* other); + +const char* iso14443_3b_get_device_name(const Iso14443_3bData* data, NfcDeviceNameType name_type); + +const uint8_t* iso14443_3b_get_uid(const Iso14443_3bData* data, size_t* uid_len); + +bool iso14443_3b_set_uid(Iso14443_3bData* data, const uint8_t* uid, size_t uid_len); + +const Iso14443_3bData* iso14443_3b_get_base_data(const Iso14443_3bData* data); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller.c b/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller.c new file mode 100644 index 000000000000..4a95197c2c34 --- /dev/null +++ b/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller.c @@ -0,0 +1,122 @@ +#include "iso14443_3b_poller_i.h" + +#include + +#include + +#define TAG "ISO14443_3bPoller" + +const Iso14443_3bData* iso14443_3b_poller_get_data(Iso14443_3bPoller* instance) { + furi_assert(instance); + furi_assert(instance->data); + + return instance->data; +} + +static Iso14443_3bPoller* iso14443_3b_poller_alloc(Nfc* nfc) { + furi_assert(nfc); + + Iso14443_3bPoller* instance = malloc(sizeof(Iso14443_3bPoller)); + instance->nfc = nfc; + instance->tx_buffer = bit_buffer_alloc(ISO14443_3B_POLLER_MAX_BUFFER_SIZE); + instance->rx_buffer = bit_buffer_alloc(ISO14443_3B_POLLER_MAX_BUFFER_SIZE); + + nfc_config(instance->nfc, NfcModeIso14443_3bPoller); + nfc_set_guard_time_us(instance->nfc, ISO14443_3B_GUARD_TIME_US); + nfc_set_fdt_poll_fc(instance->nfc, ISO14443_3B_FDT_POLL_FC); + nfc_set_fdt_poll_poll_us(instance->nfc, ISO14443_3B_POLL_POLL_MIN_US); + instance->data = iso14443_3b_alloc(); + + instance->iso14443_3b_event.data = &instance->iso14443_3b_event_data; + instance->general_event.protocol = NfcProtocolIso14443_3b; + instance->general_event.data = &instance->iso14443_3b_event; + instance->general_event.instance = instance; + + return instance; +} + +static void iso14443_3b_poller_free(Iso14443_3bPoller* instance) { + furi_assert(instance); + + furi_assert(instance->tx_buffer); + furi_assert(instance->rx_buffer); + furi_assert(instance->data); + + bit_buffer_free(instance->tx_buffer); + bit_buffer_free(instance->rx_buffer); + iso14443_3b_free(instance->data); + free(instance); +} + +static void iso14443_3b_poller_set_callback( + Iso14443_3bPoller* instance, + NfcGenericCallback callback, + void* context) { + furi_assert(instance); + furi_assert(callback); + + instance->callback = callback; + instance->context = context; +} + +static NfcCommand iso14443_3b_poller_run(NfcGenericEvent event, void* context) { + furi_assert(context); + furi_assert(event.protocol == NfcProtocolInvalid); + furi_assert(event.data); + + Iso14443_3bPoller* instance = context; + NfcEvent* nfc_event = event.data; + NfcCommand command = NfcCommandContinue; + + if(nfc_event->type == NfcEventTypePollerReady) { + if(instance->state != Iso14443_3bPollerStateActivated) { + Iso14443_3bData data = {}; + Iso14443_3bError error = iso14443_3b_poller_async_activate(instance, &data); + if(error == Iso14443_3bErrorNone) { + instance->iso14443_3b_event.type = Iso14443_3bPollerEventTypeReady; + instance->iso14443_3b_event_data.error = error; + command = instance->callback(instance->general_event, instance->context); + } else { + instance->iso14443_3b_event.type = Iso14443_3bPollerEventTypeError; + instance->iso14443_3b_event_data.error = error; + command = instance->callback(instance->general_event, instance->context); + // Add delay to switch context + furi_delay_ms(100); + } + } else { + instance->iso14443_3b_event.type = Iso14443_3bPollerEventTypeReady; + instance->iso14443_3b_event_data.error = Iso14443_3bErrorNone; + command = instance->callback(instance->general_event, instance->context); + } + } + + return command; +} + +static bool iso14443_3b_poller_detect(NfcGenericEvent event, void* context) { + furi_assert(context); + furi_assert(event.data); + furi_assert(event.instance); + furi_assert(event.protocol = NfcProtocolInvalid); + + bool protocol_detected = false; + Iso14443_3bPoller* instance = context; + NfcEvent* nfc_event = event.data; + furi_assert(instance->state == Iso14443_3bPollerStateIdle); + + if(nfc_event->type == NfcEventTypePollerReady) { + Iso14443_3bError error = iso14443_3b_poller_async_activate(instance, NULL); + protocol_detected = (error == Iso14443_3bErrorNone); + } + + return protocol_detected; +} + +const NfcPollerBase nfc_poller_iso14443_3b = { + .alloc = (NfcPollerAlloc)iso14443_3b_poller_alloc, + .free = (NfcPollerFree)iso14443_3b_poller_free, + .set_callback = (NfcPollerSetCallback)iso14443_3b_poller_set_callback, + .run = (NfcPollerRun)iso14443_3b_poller_run, + .detect = (NfcPollerDetect)iso14443_3b_poller_detect, + .get_data = (NfcPollerGetData)iso14443_3b_poller_get_data, +}; diff --git a/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller.h b/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller.h new file mode 100644 index 000000000000..d25d9dbe9fef --- /dev/null +++ b/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller.h @@ -0,0 +1,30 @@ +#pragma once + +#include "iso14443_3b.h" +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct Iso14443_3bPoller Iso14443_3bPoller; + +typedef enum { + Iso14443_3bPollerEventTypeError, + Iso14443_3bPollerEventTypeReady, +} Iso14443_3bPollerEventType; + +typedef struct { + Iso14443_3bError error; +} Iso14443_3bPollerEventData; + +typedef struct { + Iso14443_3bPollerEventType type; + Iso14443_3bPollerEventData* data; +} Iso14443_3bPollerEvent; + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/nfcb/nfcb_poller_i.h b/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller_defs.h similarity index 63% rename from lib/nfc/protocols/nfcb/nfcb_poller_i.h rename to lib/nfc/protocols/iso14443_3b/iso14443_3b_poller_defs.h index 0a51fc556e24..ba8e6cb18c06 100644 --- a/lib/nfc/protocols/nfcb/nfcb_poller_i.h +++ b/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller_defs.h @@ -1,13 +1,12 @@ #pragma once -#include "nfcb_poller.h" #include #ifdef __cplusplus extern "C" { #endif -extern const NfcPollerBase nfcb_protocol_base; +extern const NfcPollerBase nfc_poller_iso14443_3b; #ifdef __cplusplus } diff --git a/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller_i.c b/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller_i.c new file mode 100644 index 000000000000..d0ce99578e12 --- /dev/null +++ b/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller_i.c @@ -0,0 +1,188 @@ +#include "iso14443_3b_poller_i.h" + +#include + +#define TAG "Iso14443_3bPoller" + +static Iso14443_3bError iso14443_3b_poller_process_error(NfcError error) { + switch(error) { + case NfcErrorNone: + return Iso14443_3bErrorNone; + case NfcErrorTimeout: + return Iso14443_3bErrorTimeout; + default: + return Iso14443_3bErrorNotPresent; + } +} + +static Iso14443_3bError iso14443_3b_poller_prepare_trx(Iso14443_3bPoller* instance) { + furi_assert(instance); + + if(instance->state == Iso14443_3bPollerStateIdle) { + return iso14443_3b_poller_async_activate(instance, NULL); + } + + return Iso14443_3bErrorNone; +} + +static Iso14443_3bError iso14443_3b_poller_frame_exchange( + Iso14443_3bPoller* instance, + const BitBuffer* tx_buffer, + BitBuffer* rx_buffer, + uint32_t fwt) { + furi_assert(instance); + + const size_t tx_bytes = bit_buffer_get_size_bytes(tx_buffer); + furi_assert( + tx_bytes <= bit_buffer_get_capacity_bytes(instance->tx_buffer) - ISO14443_CRC_SIZE); + + bit_buffer_copy(instance->tx_buffer, tx_buffer); + iso14443_crc_append(Iso14443CrcTypeB, instance->tx_buffer); + + Iso14443_3bError ret = Iso14443_3bErrorNone; + + do { + NfcError error = nfc_trx(instance->nfc, instance->tx_buffer, instance->rx_buffer, fwt); + if(error != NfcErrorNone) { + ret = iso14443_3b_poller_process_error(error); + break; + } + + bit_buffer_copy(rx_buffer, instance->rx_buffer); + if(!iso14443_crc_check(Iso14443CrcTypeB, instance->rx_buffer)) { + ret = Iso14443_3bErrorWrongCrc; + break; + } + + iso14443_crc_trim(rx_buffer); + } while(false); + + return ret; +} + +Iso14443_3bError + iso14443_3b_poller_async_activate(Iso14443_3bPoller* instance, Iso14443_3bData* data) { + furi_assert(instance); + furi_assert(instance->nfc); + + iso14443_3b_reset(instance->data); + + Iso14443_3bError ret; + + do { + instance->state = Iso14443_3bPollerStateColResInProgress; + + bit_buffer_reset(instance->tx_buffer); + bit_buffer_reset(instance->rx_buffer); + + // Send REQB + bit_buffer_append_byte(instance->tx_buffer, 0x05); + bit_buffer_append_byte(instance->tx_buffer, 0x00); + bit_buffer_append_byte(instance->tx_buffer, 0x08); + + ret = iso14443_3b_poller_frame_exchange( + instance, instance->tx_buffer, instance->rx_buffer, ISO14443_3B_FDT_POLL_FC); + if(ret != Iso14443_3bErrorNone) { + instance->state = Iso14443_3bPollerStateColResFailed; + break; + } + + if(bit_buffer_get_size_bytes(instance->rx_buffer) != sizeof(Iso14443_3bAtqB)) { + FURI_LOG_D(TAG, "Unexpected REQB response"); + instance->state = Iso14443_3bPollerStateColResFailed; + ret = Iso14443_3bErrorCommunication; + break; + } + + instance->state = Iso14443_3bPollerStateActivationInProgress; + + const Iso14443_3bAtqB* atqb = + (const Iso14443_3bAtqB*)bit_buffer_get_data(instance->rx_buffer); + + memcpy(instance->data->uid, atqb->uid, ISO14443_3B_UID_SIZE); + memcpy(instance->data->app_data, atqb->app_data, ISO14443_3B_APP_DATA_SIZE); + memcpy(instance->data->protocol_info, atqb->protocol_info, ISO14443_3B_PROTOCOL_INFO_SIZE); + + bit_buffer_reset(instance->tx_buffer); + bit_buffer_reset(instance->rx_buffer); + + // Send ATTRIB + bit_buffer_append_byte(instance->tx_buffer, 0x1d); + bit_buffer_append_bytes(instance->tx_buffer, atqb->uid, ISO14443_3B_UID_SIZE); + bit_buffer_append_byte(instance->tx_buffer, 0x00); + bit_buffer_append_byte(instance->tx_buffer, ISO14443_3B_ATTRIB_FRAME_SIZE_256); + bit_buffer_append_byte(instance->tx_buffer, 0x01); + bit_buffer_append_byte(instance->tx_buffer, 0x00); + + ret = iso14443_3b_poller_frame_exchange( + instance, instance->tx_buffer, instance->rx_buffer, ISO14443_3B_FDT_ATTRIB_FC); + if(ret != Iso14443_3bErrorNone) { + instance->state = Iso14443_3bPollerStateActivationFailed; + break; + } + + if(bit_buffer_get_size_bytes(instance->rx_buffer) != 1 || + bit_buffer_get_byte(instance->rx_buffer, 0) != 0) { + FURI_LOG_D(TAG, "Unexpected ATTRIB response"); + instance->state = Iso14443_3bPollerStateActivationFailed; + ret = Iso14443_3bErrorCommunication; + break; + } + + instance->state = Iso14443_3bPollerStateActivated; + + if(data) { + iso14443_3b_copy(data, instance->data); + } + + } while(false); + + return ret; +} + +Iso14443_3bError iso14443_3b_poller_halt(Iso14443_3bPoller* instance) { + furi_assert(instance); + + bit_buffer_reset(instance->tx_buffer); + bit_buffer_reset(instance->rx_buffer); + + bit_buffer_append_byte(instance->tx_buffer, 0x50); + bit_buffer_append_bytes(instance->tx_buffer, instance->data->uid, ISO14443_3B_UID_SIZE); + + Iso14443_3bError ret; + + do { + ret = iso14443_3b_poller_frame_exchange( + instance, instance->tx_buffer, instance->rx_buffer, ISO14443_3B_FDT_POLL_FC); + if(ret != Iso14443_3bErrorNone) { + break; + } + + if(bit_buffer_get_size_bytes(instance->rx_buffer) != sizeof(uint8_t) || + bit_buffer_get_byte(instance->rx_buffer, 0) != 0) { + ret = Iso14443_3bErrorCommunication; + break; + } + + instance->state = Iso14443_3bPollerStateIdle; + } while(false); + + return ret; +} + +Iso14443_3bError iso14443_3b_poller_send_frame( + Iso14443_3bPoller* instance, + const BitBuffer* tx_buffer, + BitBuffer* rx_buffer, + uint32_t fwt) { + Iso14443_3bError ret; + + do { + ret = iso14443_3b_poller_prepare_trx(instance); + if(ret != Iso14443_3bErrorNone) break; + + ret = iso14443_3b_poller_frame_exchange(instance, tx_buffer, rx_buffer, fwt); + } while(false); + + return ret; +} diff --git a/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller_i.h b/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller_i.h new file mode 100644 index 000000000000..898378ac3604 --- /dev/null +++ b/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller_i.h @@ -0,0 +1,51 @@ +#pragma once + +#include "iso14443_3b_poller.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define ISO14443_3B_POLLER_MAX_BUFFER_SIZE (256U) + +typedef enum { + Iso14443_3bPollerStateIdle, + Iso14443_3bPollerStateColResInProgress, + Iso14443_3bPollerStateColResFailed, + Iso14443_3bPollerStateActivationInProgress, + Iso14443_3bPollerStateActivationFailed, + Iso14443_3bPollerStateActivated, +} Iso14443_3bPollerState; + +struct Iso14443_3bPoller { + Nfc* nfc; + Iso14443_3bPollerState state; + Iso14443_3bData* data; + BitBuffer* tx_buffer; + BitBuffer* rx_buffer; + + NfcGenericEvent general_event; + Iso14443_3bPollerEvent iso14443_3b_event; + Iso14443_3bPollerEventData iso14443_3b_event_data; + NfcGenericCallback callback; + void* context; +}; + +const Iso14443_3bData* iso14443_3b_poller_get_data(Iso14443_3bPoller* instance); + +Iso14443_3bError + iso14443_3b_poller_async_activate(Iso14443_3bPoller* instance, Iso14443_3bData* data); + +Iso14443_3bError iso14443_3b_poller_halt(Iso14443_3bPoller* instance); + +Iso14443_3bError iso14443_3b_poller_send_frame( + Iso14443_3bPoller* instance, + const BitBuffer* tx_buffer, + BitBuffer* rx_buffer, + uint32_t fwt); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a.c b/lib/nfc/protocols/iso14443_4a/iso14443_4a.c index 992682931daa..68632af101c2 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a.c +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a.c @@ -3,7 +3,7 @@ #include #define ISO14443_4A_PROTOCOL_NAME "ISO14443-4A" -#define ISO14443_4A_DEVICE_NAME "Unknown ISO14443-4A Tag" +#define ISO14443_4A_DEVICE_NAME "ISO14443-4A (Unknown)" #define ISO14443_4A_ATS_BIT (1U << 5) #define ISO14443_4A_ATS_KEY "ATS" @@ -20,6 +20,7 @@ const NfcDeviceBase nfc_device_iso14443_4a = { .is_equal = (NfcDeviceEqual)iso14443_4a_is_equal, .get_name = (NfcDeviceGetName)iso14443_4a_get_device_name, .get_uid = (NfcDeviceGetUid)iso14443_4a_get_uid, + .set_uid = (NfcDeviceSetUid)iso14443_4a_set_uid, .get_base_data = (NfcDeviceGetBaseData)iso14443_4a_get_base_data, }; @@ -125,6 +126,12 @@ const uint8_t* iso14443_4a_get_uid(const Iso14443_4aData* data, size_t* uid_len) return iso14443_3a_get_uid(data->iso14443_3a_data, uid_len); } +bool iso14443_4a_set_uid(Iso14443_4aData* data, const uint8_t* uid, size_t uid_len) { + furi_assert(data); + + return iso14443_3a_set_uid(data->iso14443_3a_data, uid, uid_len); +} + const Iso14443_3aData* iso14443_4a_get_base_data(const Iso14443_4aData* data) { furi_assert(data); diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a.h b/lib/nfc/protocols/iso14443_4a/iso14443_4a.h index 9b6feb29cc19..75da18ed1ea2 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a.h +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a.h @@ -44,6 +44,8 @@ const char* iso14443_4a_get_device_name(const Iso14443_4aData* data, NfcDeviceNa const uint8_t* iso14443_4a_get_uid(const Iso14443_4aData* data, size_t* uid_len); +bool iso14443_4a_set_uid(Iso14443_4aData* data, const uint8_t* uid, size_t uid_len); + const Iso14443_3aData* iso14443_4a_get_base_data(const Iso14443_4aData* data); // Getters & Tests diff --git a/lib/nfc/protocols/mf_classic/mf_classic.c b/lib/nfc/protocols/mf_classic/mf_classic.c index 1f5c6dc34929..71d3e5147d02 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic.c +++ b/lib/nfc/protocols/mf_classic/mf_classic.c @@ -52,6 +52,7 @@ const NfcDeviceBase nfc_device_mf_classic = { .is_equal = (NfcDeviceEqual)mf_classic_is_equal, .get_name = (NfcDeviceGetName)mf_classic_get_device_name, .get_uid = (NfcDeviceGetUid)mf_classic_get_uid, + .set_uid = (NfcDeviceSetUid)mf_classic_set_uid, .get_base_data = (NfcDeviceGetBaseData)mf_classic_get_base_data, }; @@ -342,6 +343,12 @@ const uint8_t* mf_classic_get_uid(const MfClassicData* data, size_t* uid_len) { return iso14443_3a_get_uid(data->iso14443_3a_data, uid_len); } +bool mf_classic_set_uid(MfClassicData* data, const uint8_t* uid, size_t uid_len) { + furi_assert(data); + + return iso14443_3a_set_uid(data->iso14443_3a_data, uid, uid_len); +} + const Iso14443_3aData* mf_classic_get_base_data(const MfClassicData* data) { furi_assert(data); diff --git a/lib/nfc/protocols/mf_classic/mf_classic.h b/lib/nfc/protocols/mf_classic/mf_classic.h index 0601042dfe53..312cb7ed3618 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic.h +++ b/lib/nfc/protocols/mf_classic/mf_classic.h @@ -157,6 +157,8 @@ const char* mf_classic_get_device_name(const MfClassicData* data, NfcDeviceNameT const uint8_t* mf_classic_get_uid(const MfClassicData* data, size_t* uid_len); +bool mf_classic_set_uid(MfClassicData* data, const uint8_t* uid, size_t uid_len); + const Iso14443_3aData* mf_classic_get_base_data(const MfClassicData* data); bool mf_classic_detect_protocol(Iso14443_3aData* data, MfClassicType* type); diff --git a/lib/nfc/protocols/mf_classic/mf_classic_listener.c b/lib/nfc/protocols/mf_classic/mf_classic_listener.c index 4ca586f56869..bce8d2656475 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_listener.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_listener.c @@ -1,6 +1,9 @@ #include "mf_classic_listener_i.h" -#include "mf_classic_listener_defs.h" -#include + +#include + +#include +#include #include #include @@ -214,7 +217,7 @@ static MfClassicListenerCommand bit_buffer_copy_bytes( instance->tx_plain_buffer, access_block.data, sizeof(MfClassicBlock)); - iso14443_3a_append_crc(instance->tx_plain_buffer); + iso14443_crc_append(Iso14443CrcTypeA, instance->tx_plain_buffer); crypto1_encrypt( instance->crypto, NULL, instance->tx_plain_buffer, instance->tx_encrypted_buffer); iso14443_3a_listener_tx_with_custom_parity( diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c index 6bb6afd3648e..958565f6146d 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c @@ -3,6 +3,8 @@ #include #include +#include + #define TAG "MfCLassicPoller" #define MF_CLASSIC_FWT_FC (60000) @@ -117,7 +119,7 @@ MfClassicError mf_classic_aync_halt(MfClassicPoller* instance) { do { uint8_t halt_cmd[2] = {MF_CLASSIC_CMD_HALT_MSB, MF_CLASSIC_CMD_HALT_LSB}; bit_buffer_copy_bytes(instance->tx_plain_buffer, halt_cmd, sizeof(halt_cmd)); - iso14443_3a_append_crc(instance->tx_plain_buffer); + iso14443_crc_append(Iso14443CrcTypeA, instance->tx_plain_buffer); crypto1_encrypt( instance->crypto, NULL, instance->tx_plain_buffer, instance->tx_encrypted_buffer); @@ -148,7 +150,7 @@ MfClassicError mf_classic_async_read_block( do { uint8_t read_block_cmd[2] = {MF_CLASSIC_CMD_READ_BLOCK, block_num}; bit_buffer_copy_bytes(instance->tx_plain_buffer, read_block_cmd, sizeof(read_block_cmd)); - iso14443_3a_append_crc(instance->tx_plain_buffer); + iso14443_crc_append(Iso14443CrcTypeA, instance->tx_plain_buffer); crypto1_encrypt( instance->crypto, NULL, instance->tx_plain_buffer, instance->tx_encrypted_buffer); @@ -171,13 +173,13 @@ MfClassicError mf_classic_async_read_block( crypto1_decrypt( instance->crypto, instance->rx_encrypted_buffer, instance->rx_plain_buffer); - if(!iso14443_3a_check_crc(instance->rx_plain_buffer)) { + if(!iso14443_crc_check(Iso14443CrcTypeA, instance->rx_plain_buffer)) { FURI_LOG_D(TAG, "CRC error"); ret = MfClassicErrorProtocol; break; } - iso14443_3a_trim_crc(instance->rx_plain_buffer); + iso14443_crc_trim(instance->rx_plain_buffer); bit_buffer_write_bytes(instance->rx_plain_buffer, data->data, sizeof(MfClassicBlock)); } while(false); @@ -194,7 +196,7 @@ MfClassicError mf_classic_async_write_block( do { uint8_t write_block_cmd[2] = {MF_CLASSIC_CMD_WRITE_BLOCK, block_num}; bit_buffer_copy_bytes(instance->tx_plain_buffer, write_block_cmd, sizeof(write_block_cmd)); - iso14443_3a_append_crc(instance->tx_plain_buffer); + iso14443_crc_append(Iso14443CrcTypeA, instance->tx_plain_buffer); crypto1_encrypt( instance->crypto, NULL, instance->tx_plain_buffer, instance->tx_encrypted_buffer); @@ -223,7 +225,7 @@ MfClassicError mf_classic_async_write_block( } bit_buffer_copy_bytes(instance->tx_plain_buffer, data->data, sizeof(MfClassicBlock)); - iso14443_3a_append_crc(instance->tx_plain_buffer); + iso14443_crc_append(Iso14443CrcTypeA, instance->tx_plain_buffer); crypto1_encrypt( instance->crypto, NULL, instance->tx_plain_buffer, instance->tx_encrypted_buffer); @@ -274,7 +276,7 @@ MfClassicError mf_classic_async_value_cmd( } uint8_t value_cmd[2] = {cmd_value, block_num}; bit_buffer_copy_bytes(instance->tx_plain_buffer, value_cmd, sizeof(value_cmd)); - iso14443_3a_append_crc(instance->tx_plain_buffer); + iso14443_crc_append(Iso14443CrcTypeA, instance->tx_plain_buffer); crypto1_encrypt( instance->crypto, NULL, instance->tx_plain_buffer, instance->tx_encrypted_buffer); @@ -305,7 +307,7 @@ MfClassicError mf_classic_async_value_cmd( uint8_t data_arr[4] = {}; memcpy(data_arr, &data, sizeof(int32_t)); bit_buffer_copy_bytes(instance->tx_plain_buffer, data_arr, sizeof(data_arr)); - iso14443_3a_append_crc(instance->tx_plain_buffer); + iso14443_crc_append(Iso14443CrcTypeA, instance->tx_plain_buffer); crypto1_encrypt( instance->crypto, NULL, instance->tx_plain_buffer, instance->tx_encrypted_buffer); @@ -334,7 +336,7 @@ MfClassicError mf_classic_async_value_transfer(MfClassicPoller* instance, uint8_ do { uint8_t transfer_cmd[2] = {MF_CLASSIC_CMD_VALUE_TRANSFER, block_num}; bit_buffer_copy_bytes(instance->tx_plain_buffer, transfer_cmd, sizeof(transfer_cmd)); - iso14443_3a_append_crc(instance->tx_plain_buffer); + iso14443_crc_append(Iso14443CrcTypeA, instance->tx_plain_buffer); crypto1_encrypt( instance->crypto, NULL, instance->tx_plain_buffer, instance->tx_encrypted_buffer); diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire.c b/lib/nfc/protocols/mf_desfire/mf_desfire.c index 0c5709c5b645..ec5c626bc355 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire.c +++ b/lib/nfc/protocols/mf_desfire/mf_desfire.c @@ -16,6 +16,7 @@ const NfcDeviceBase nfc_device_mf_desfire = { .is_equal = (NfcDeviceEqual)mf_desfire_is_equal, .get_name = (NfcDeviceGetName)mf_desfire_get_device_name, .get_uid = (NfcDeviceGetUid)mf_desfire_get_uid, + .set_uid = (NfcDeviceSetUid)mf_desfire_set_uid, .get_base_data = (NfcDeviceGetBaseData)mf_desfire_get_base_data, }; @@ -226,6 +227,12 @@ const uint8_t* mf_desfire_get_uid(const MfDesfireData* data, size_t* uid_len) { return iso14443_4a_get_uid(data->iso14443_4a_data, uid_len); } +bool mf_desfire_set_uid(MfDesfireData* data, const uint8_t* uid, size_t uid_len) { + furi_assert(data); + + return iso14443_4a_set_uid(data->iso14443_4a_data, uid, uid_len); +} + const Iso14443_4aData* mf_desfire_get_base_data(const MfDesfireData* data) { furi_assert(data); diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire.h b/lib/nfc/protocols/mf_desfire/mf_desfire.h index 977c05121458..ae804c151e3d 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire.h +++ b/lib/nfc/protocols/mf_desfire/mf_desfire.h @@ -171,6 +171,8 @@ const char* mf_desfire_get_device_name(const MfDesfireData* data, NfcDeviceNameT const uint8_t* mf_desfire_get_uid(const MfDesfireData* data, size_t* uid_len); +bool mf_desfire_set_uid(MfDesfireData* data, const uint8_t* uid, size_t uid_len); + const Iso14443_4aData* mf_desfire_get_base_data(const MfDesfireData* data); // Getters and tests diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight.c index 9138cc8fae8b..7f068dab7349 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight.c @@ -152,6 +152,7 @@ const NfcDeviceBase nfc_device_mf_ultralight = { .is_equal = (NfcDeviceEqual)mf_ultralight_is_equal, .get_name = (NfcDeviceGetName)mf_ultralight_get_device_name, .get_uid = (NfcDeviceGetUid)mf_ultralight_get_uid, + .set_uid = (NfcDeviceSetUid)mf_ultralight_set_uid, .get_base_data = (NfcDeviceGetBaseData)mf_ultralight_get_base_data, }; @@ -467,6 +468,12 @@ const uint8_t* mf_ultralight_get_uid(const MfUltralightData* data, size_t* uid_l return iso14443_3a_get_uid(data->iso14443_3a_data, uid_len); } +bool mf_ultralight_set_uid(MfUltralightData* data, const uint8_t* uid, size_t uid_len) { + furi_assert(data); + + return iso14443_3a_set_uid(data->iso14443_3a_data, uid, uid_len); +} + const Iso14443_3aData* mf_ultralight_get_base_data(const MfUltralightData* data) { furi_assert(data); diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h index 3df841043ed8..4fca4cda30ce 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h @@ -188,6 +188,8 @@ const char* const uint8_t* mf_ultralight_get_uid(const MfUltralightData* data, size_t* uid_len); +bool mf_ultralight_set_uid(MfUltralightData* data, const uint8_t* uid, size_t uid_len); + const Iso14443_3aData* mf_ultralight_get_base_data(const MfUltralightData* data); MfUltralightType mf_ultralight_get_type_by_version(MfUltralightVersion* version); diff --git a/lib/nfc/protocols/nfc_device_base_i.h b/lib/nfc/protocols/nfc_device_base_i.h index ee6569459bc5..d4212f693435 100644 --- a/lib/nfc/protocols/nfc_device_base_i.h +++ b/lib/nfc/protocols/nfc_device_base_i.h @@ -18,6 +18,7 @@ typedef bool (*NfcDeviceSave)(const NfcDeviceData* data, FlipperFormat* ff); typedef bool (*NfcDeviceEqual)(const NfcDeviceData* data, const NfcDeviceData* other); typedef const char* (*NfcDeviceGetName)(const NfcDeviceData* data, NfcDeviceNameType name_type); typedef const uint8_t* (*NfcDeviceGetUid)(const NfcDeviceData* data, size_t* uid_len); +typedef bool (*NfcDeviceSetUid)(NfcDeviceData* data, const uint8_t* uid, size_t uid_len); typedef const NfcDeviceData* (*NfcDeviceGetBaseData)(const NfcDeviceData* data); typedef struct { @@ -32,6 +33,7 @@ typedef struct { NfcDeviceEqual is_equal; NfcDeviceGetName get_name; NfcDeviceGetUid get_uid; + NfcDeviceSetUid set_uid; NfcDeviceGetBaseData get_base_data; } NfcDeviceBase; diff --git a/lib/nfc/protocols/nfc_device_defs.c b/lib/nfc/protocols/nfc_device_defs.c index 6095206aaff3..49b5031ddf49 100644 --- a/lib/nfc/protocols/nfc_device_defs.c +++ b/lib/nfc/protocols/nfc_device_defs.c @@ -3,6 +3,7 @@ #include "nfc_protocol.h" #include +#include #include #include #include @@ -10,6 +11,7 @@ const NfcDeviceBase* nfc_devices[NfcProtocolNum] = { [NfcProtocolIso14443_3a] = &nfc_device_iso14443_3a, + [NfcProtocolIso14443_3b] = &nfc_device_iso14443_3b, [NfcProtocolIso14443_4a] = &nfc_device_iso14443_4a, [NfcProtocolMfUltralight] = &nfc_device_mf_ultralight, [NfcProtocolMfClassic] = &nfc_device_mf_classic, diff --git a/lib/nfc/protocols/nfc_poller_defs.c b/lib/nfc/protocols/nfc_poller_defs.c index e54320e2bb7b..0c2603b90c4c 100644 --- a/lib/nfc/protocols/nfc_poller_defs.c +++ b/lib/nfc/protocols/nfc_poller_defs.c @@ -1,6 +1,7 @@ #include "nfc_poller_defs.h" #include +#include #include #include #include @@ -8,8 +9,10 @@ const NfcPollerBase* nfc_pollers_api[NfcProtocolNum] = { [NfcProtocolIso14443_3a] = &nfc_poller_iso14443_3a, + [NfcProtocolIso14443_3b] = &nfc_poller_iso14443_3b, [NfcProtocolIso14443_4a] = &nfc_poller_iso14443_4a, [NfcProtocolMfUltralight] = &mf_ultralight_poller, [NfcProtocolMfClassic] = &mf_classic_poller, [NfcProtocolMfDesfire] = &mf_desfire_poller, + /* Add new pollers here */ }; diff --git a/lib/nfc/protocols/nfc_protocol.c b/lib/nfc/protocols/nfc_protocol.c index 8bb96483fab2..a4ea0ba3fc72 100644 --- a/lib/nfc/protocols/nfc_protocol.c +++ b/lib/nfc/protocols/nfc_protocol.c @@ -9,13 +9,21 @@ typedef struct { } NfcProtocolTreeNode; /**************************** Protocol tree structure **************************** - * _________ start ___________________________ - * / | | \ - * _________ iso14443-3a _______ nfc-b nfc-f nfc-v - * / | \ - * iso14443-4a mf ultralight mf classic - * / \ - * mf desfire bank card + * + * (Start) + * | + * +------------------------+-----------+-------+ + * | | | | + * ISO14443-3A ISO14443-3B NFC-F NFC-V + * | + * +---------------+-------------+ + * | | | + * ISO14443-4A Mf Ultralight Mf Classic + * | + * +-----+-----+ + * | | + * Mf Desfire Bank Card + * */ static const NfcProtocol nfc_protocol_iso14443_3a_children_protocol[] = { @@ -34,6 +42,12 @@ static const NfcProtocolTreeNode nfc_protocol_nodes[NfcProtocolNum] = { .children_num = COUNT_OF(nfc_protocol_iso14443_3a_children_protocol), .children_protocol = nfc_protocol_iso14443_3a_children_protocol, }, + [NfcProtocolIso14443_3b] = + { + .parent_protocol = NfcProtocolInvalid, + .children_num = 0, + .children_protocol = NULL, + }, [NfcProtocolIso14443_4a] = { .parent_protocol = NfcProtocolIso14443_3a, diff --git a/lib/nfc/protocols/nfc_protocol.h b/lib/nfc/protocols/nfc_protocol.h index 32ab9dbb1ca4..62f74186ff24 100644 --- a/lib/nfc/protocols/nfc_protocol.h +++ b/lib/nfc/protocols/nfc_protocol.h @@ -8,6 +8,7 @@ extern "C" { typedef enum { NfcProtocolIso14443_3a, + NfcProtocolIso14443_3b, NfcProtocolIso14443_4a, NfcProtocolMfUltralight, NfcProtocolMfClassic, diff --git a/lib/nfc/protocols/nfcb/nfcb.h b/lib/nfc/protocols/nfcb/nfcb.h deleted file mode 100644 index d23d1a6fdb76..000000000000 --- a/lib/nfc/protocols/nfcb/nfcb.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -#define NFCB_UID_MAX_SIZE (7) - -// TODO change values -#define NFCB_GUARD_TIME_US (5000) -#define NFCB_FDT_POLL_FC (1620) -#define NFCB_FDT_LISTEN_FC (1172) -#define NFCB_POLLER_MASK_RX_FS ((NFCB_FDT_LISTEN_FC) / 2) -#define NFCB_POLL_POLL_MIN_US (1100) - -typedef enum { - NfcbErrorNone, - NfcbErrorTimeout, -} NfcbError; - -typedef struct { - uint8_t uid[NFCB_UID_MAX_SIZE]; - uint16_t uid_len; -} NfcbData; - -#ifdef __cplusplus -} -#endif diff --git a/lib/nfc/protocols/nfcb/nfcb_poller.c b/lib/nfc/protocols/nfcb/nfcb_poller.c deleted file mode 100644 index 920dfc5abc5d..000000000000 --- a/lib/nfc/protocols/nfcb/nfcb_poller.c +++ /dev/null @@ -1,97 +0,0 @@ -#include "nfcb_poller.h" - -#include - -#define NFCB_POLLER_BUFER_MAX_SIZE (512) - -typedef enum { - NfcbPollerStateIdle, - NfcbPollerColResInProgress, - NfcbPollerColResFailed, - NfcbPollerActivated, -} NfcbPollerState; - -struct NfcbPoller { - Nfc* nfc; - NfcbPollerState state; - NfcbData* data; - NfcbPollerEventCallback callback; - void* context; -}; - -NfcbPoller* nfcb_poller_alloc(Nfc* nfc) { - NfcbPoller* instance = malloc(sizeof(NfcbPoller)); - instance->nfc = nfc; - - return instance; -} - -void nfcb_poller_free(NfcbPoller* instance) { - furi_assert(instance); - - free(instance); -} - -static NfcCommand nfcb_poller_event_callback(NfcEvent event, void* context) { - furi_assert(context); - UNUSED(event); - - NfcbPoller* instance = context; - furi_assert(instance->callback); - - return NfcCommandContinue; -} - -NfcbError - nfcb_poller_start(NfcbPoller* instance, NfcbPollerEventCallback callback, void* context) { - furi_assert(instance); - - instance->callback = callback; - instance->context = context; - - nfc_start_poller(instance->nfc, nfcb_poller_event_callback, instance); - return NfcbErrorNone; -} - -NfcbError nfcb_poller_get_data(NfcbPoller* instance, NfcbData* data) { - furi_assert(instance); - furi_assert(instance->data); - - *data = *instance->data; - return NfcbErrorNone; -} - -NfcbError nfcb_poller_reset(NfcbPoller* instance) { - furi_assert(instance); - furi_assert(instance->nfc); - furi_assert(instance->data); - - nfc_stop(instance->nfc); - - instance->callback = NULL; - instance->context = NULL; - free(instance->data); - instance->data = NULL; - - return NfcbErrorNone; -} - -NfcbError nfcb_poller_config(NfcbPoller* instance) { - furi_assert(instance); - - // instance->data = malloc(sizeof(NfcbData)); - - nfc_config(instance->nfc, NfcModeNfcbPoller); - nfc_set_guard_time_us(instance->nfc, NFCB_GUARD_TIME_US); - nfc_set_fdt_poll_fc(instance->nfc, NFCB_FDT_POLL_FC); - nfc_set_fdt_poll_poll_us(instance->nfc, NFCB_POLL_POLL_MIN_US); - - return NfcbErrorNone; -} - -NfcbError nfcb_poller_activate(NfcbPoller* instance, NfcbData* data) { - furi_assert(instance); - furi_assert(data); - - return NfcbErrorTimeout; -} diff --git a/lib/nfc/protocols/nfcb/nfcb_poller.h b/lib/nfc/protocols/nfcb/nfcb_poller.h deleted file mode 100644 index cd71df783967..000000000000 --- a/lib/nfc/protocols/nfcb/nfcb_poller.h +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include -#include "nfcb.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct NfcbPoller NfcbPoller; - -typedef enum { - NfcbPollerEventTypeError, - NfcbPollerEventDetected, - NfcbPollerEventTypeReady, -} NfcbPollerEventType; - -typedef struct { - NfcbError error; -} NfcbPollerEventData; - -typedef struct { - NfcbPollerEventType type; - NfcbPollerEventData data; -} NfcbPollerEvent; - -typedef enum { - NfcbPollerCommandContinue = NfcCommandContinue, - NfcbPollerCommandReset = NfcCommandReset, - NfcbPollerCommandStop = NfcCommandStop, -} NfcbPollerCommand; - -typedef NfcbPollerCommand (*NfcbPollerEventCallback)(NfcbPollerEvent* event, void* context); - -NfcbPoller* nfcb_poller_alloc(Nfc* nfc); - -void nfcb_poller_free(NfcbPoller* instance); - -NfcbError nfcb_poller_start(NfcbPoller* instance, NfcbPollerEventCallback callback, void* context); - -NfcbError nfcb_poller_get_data(NfcbPoller* instance, NfcbData* data); - -NfcbError nfcb_poller_reset(NfcbPoller* instance); - -NfcbError nfcb_poller_config(NfcbPoller* instance); - -NfcbError nfcb_poller_activate(NfcbPoller* instance, NfcbData* data); - -#ifdef __cplusplus -} -#endif diff --git a/lib/nfc/protocols/nfcb/nfcb_poller_i.c b/lib/nfc/protocols/nfcb/nfcb_poller_i.c deleted file mode 100644 index 9bd10a6ccddd..000000000000 --- a/lib/nfc/protocols/nfcb/nfcb_poller_i.c +++ /dev/null @@ -1,6 +0,0 @@ -#include "nfcb_poller_i.h" - -const NfcPollerBase nfcb_protocol_base = { - .alloc = NULL, - .free = NULL, -}; \ No newline at end of file From be46e5d0e925453de40c24c377e2d894c55de404 Mon Sep 17 00:00:00 2001 From: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Date: Tue, 25 Jul 2023 15:49:09 +0300 Subject: [PATCH 129/149] Simple Array improvements (#2919) --- .../main/nfc/plugins/supported_cards/opal.c | 2 +- firmware/targets/f7/api_symbols.csv | 2 + lib/nfc/protocols/iso14443_4a/iso14443_4a.c | 4 +- lib/nfc/protocols/iso14443_4a/iso14443_4a_i.c | 4 +- .../iso14443_4a/iso14443_4a_listener_i.c | 2 +- lib/nfc/protocols/mf_desfire/mf_desfire.c | 4 +- lib/nfc/protocols/mf_desfire/mf_desfire_i.c | 15 +-- lib/toolbox/simple_array.c | 11 ++ lib/toolbox/simple_array.h | 100 +++++++++++++++++- 9 files changed, 125 insertions(+), 19 deletions(-) diff --git a/applications/main/nfc/plugins/supported_cards/opal.c b/applications/main/nfc/plugins/supported_cards/opal.c index 824df5523c33..9153c9ccd534 100644 --- a/applications/main/nfc/plugins/supported_cards/opal.c +++ b/applications/main/nfc/plugins/supported_cards/opal.c @@ -135,7 +135,7 @@ static bool opal_parse(const NfcDevice* device, FuriString* parsed_data) { const MfDesfireFileData* file_data = mf_desfire_get_file_data(app, &opal_file_id); if(file_data == NULL) break; - const OpalFile* opal_file = simple_array_cget(file_data->data, 0); + const OpalFile* opal_file = simple_array_cget_data(file_data->data); const uint8_t serial2 = opal_file->serial / 10000000; const uint16_t serial3 = (opal_file->serial / 1000) % 10000; diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index ac14d1f45744..11a7bf5f9c44 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -2667,10 +2667,12 @@ Function,+,sha256_start,void,sha256_context* Function,+,sha256_update,void,"sha256_context*, const unsigned char*, unsigned int" Function,+,simple_array_alloc,SimpleArray*,const SimpleArrayConfig* Function,+,simple_array_cget,const SimpleArrayElement*,"const SimpleArray*, uint32_t" +Function,+,simple_array_cget_data,const SimpleArrayData*,const SimpleArray* Function,+,simple_array_copy,void,"SimpleArray*, const SimpleArray*" Function,+,simple_array_free,void,SimpleArray* Function,+,simple_array_get,SimpleArrayElement*,"SimpleArray*, uint32_t" Function,+,simple_array_get_count,uint32_t,const SimpleArray* +Function,+,simple_array_get_data,SimpleArrayData*,SimpleArray* Function,+,simple_array_init,void,"SimpleArray*, uint32_t" Function,+,simple_array_reset,void,SimpleArray* Function,-,sin,double,double diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a.c b/lib/nfc/protocols/iso14443_4a/iso14443_4a.c index 68632af101c2..24e8886f8999 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a.c +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a.c @@ -80,7 +80,7 @@ bool iso14443_4a_load(Iso14443_4aData* data, FlipperFormat* ff, uint32_t version simple_array_init(data->ats_data, ats_size); if(!flipper_format_read_hex( - ff, ISO14443_4A_ATS_KEY, simple_array_get(data->ats_data, 0), ats_size)) + ff, ISO14443_4A_ATS_KEY, simple_array_get_data(data->ats_data), ats_size)) break; } else { iso14443_4a_ats_fill_default(data->ats_data); @@ -103,7 +103,7 @@ bool iso14443_4a_save(const Iso14443_4aData* data, FlipperFormat* ff) { if(!flipper_format_write_hex( ff, ISO14443_4A_ATS_KEY, - simple_array_cget(data->ats_data, 0), + simple_array_cget_data(data->ats_data), simple_array_get_count(data->ats_data))) break; saved = true; diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_i.c b/lib/nfc/protocols/iso14443_4a/iso14443_4a_i.c index cc0388b4e43b..ae70a81bd584 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_i.c +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_i.c @@ -27,7 +27,7 @@ bool iso14443_4a_ats_parse(SimpleArray* data, const BitBuffer* buf) { if(ats_size != buf_size) break; simple_array_init(data, ats_size); - bit_buffer_write_bytes(buf, simple_array_get(data, 0), ats_size); + bit_buffer_write_bytes(buf, simple_array_get_data(data), ats_size); can_parse = true; } while(false); @@ -38,7 +38,7 @@ bool iso14443_4a_ats_parse(SimpleArray* data, const BitBuffer* buf) { void iso14443_4a_ats_fill_default(SimpleArray* data) { simple_array_init(data, sizeof(Iso14443_4aAtsData)); - Iso14443_4aAtsData* ats_data = simple_array_get(data, 0); + Iso14443_4aAtsData* ats_data = simple_array_get_data(data); ats_data->tl = sizeof(Iso14443_4aAtsData); ats_data->t0 = ISO14443_4A_ATS_T0_TA1_FLAG | ISO14443_4A_ATS_T0_TB1_FLAG | diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_listener_i.c b/lib/nfc/protocols/iso14443_4a/iso14443_4a_listener_i.c index ec604265fcb4..7aaa18548cca 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_listener_i.c +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_listener_i.c @@ -5,7 +5,7 @@ Iso14443_4aError iso14443_4a_listener_send_ats(Iso14443_4aListener* instance, const SimpleArray* data) { bit_buffer_copy_bytes( - instance->tx_buffer, simple_array_cget(data, 0), simple_array_get_count(data)); + instance->tx_buffer, simple_array_cget_data(data), simple_array_get_count(data)); const Iso14443_3aError error = iso14443_3a_listener_send_standard_frame( instance->iso14443_3a_listener, instance->tx_buffer); diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire.c b/lib/nfc/protocols/mf_desfire/mf_desfire.c index ec5c626bc355..976e4b8d6ef6 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire.c +++ b/lib/nfc/protocols/mf_desfire/mf_desfire.c @@ -113,7 +113,7 @@ bool mf_desfire_load(MfDesfireData* data, FlipperFormat* ff, uint32_t version) { if(application_count > 0) { simple_array_init(data->application_ids, application_count); if(!mf_desfire_application_ids_load( - simple_array_get(data->application_ids, 0), application_count, ff)) + simple_array_get_data(data->application_ids), application_count, ff)) break; simple_array_init(data->applications, application_count); @@ -180,7 +180,7 @@ bool mf_desfire_save(const MfDesfireData* data, FlipperFormat* ff) { if(application_count > 0) { if(!mf_desfire_application_ids_save( - simple_array_cget(data->application_ids, 0), application_count, ff)) + simple_array_cget_data(data->application_ids), application_count, ff)) break; for(i = 0; i < application_count; ++i) { diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_i.c b/lib/nfc/protocols/mf_desfire/mf_desfire_i.c index e0ca0a30437c..3907556e89a4 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_i.c +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_i.c @@ -230,7 +230,7 @@ bool mf_desfire_file_data_parse(MfDesfireFileData* data, const BitBuffer* buf) { if(data_size > 0) { simple_array_init(data->data, data_size); - bit_buffer_write_bytes(buf, simple_array_get(data->data, 0), data_size); + bit_buffer_write_bytes(buf, simple_array_get_data(data->data), data_size); } // Success no matter whether there is data or not @@ -454,7 +454,8 @@ bool mf_desfire_file_data_load(MfDesfireFileData* data, const char* prefix, Flip simple_array_init(data->data, data_size); - if(!flipper_format_read_hex(ff, prefix, simple_array_get(data->data, 0), data_size)) break; + if(!flipper_format_read_hex(ff, prefix, simple_array_get_data(data->data), data_size)) + break; success = true; } while(false); @@ -496,7 +497,7 @@ bool mf_desfire_application_load(MfDesfireApplication* data, const char* prefix, if(!mf_desfire_file_count_load(&file_count, prefix, ff)) break; simple_array_init(data->file_ids, file_count); - if(!mf_desfire_file_ids_load(simple_array_get(data->file_ids, 0), file_count, prefix, ff)) + if(!mf_desfire_file_ids_load(simple_array_get_data(data->file_ids), file_count, prefix, ff)) break; simple_array_init(data->file_settings, file_count); @@ -686,9 +687,9 @@ bool mf_desfire_file_data_save( const char* prefix, FlipperFormat* ff) { const uint32_t data_size = simple_array_get_count(data->data); - return data_size > 0 ? - flipper_format_write_hex(ff, prefix, simple_array_cget(data->data, 0), data_size) : - true; + return data_size > 0 ? flipper_format_write_hex( + ff, prefix, simple_array_cget_data(data->data), data_size) : + true; } bool mf_desfire_application_count_save(const uint32_t* data, FlipperFormat* ff) { @@ -725,7 +726,7 @@ bool mf_desfire_application_save( if(i != key_version_count) break; const uint32_t file_count = simple_array_get_count(data->file_ids); - if(!mf_desfire_file_ids_save(simple_array_get(data->file_ids, 0), file_count, prefix, ff)) + if(!mf_desfire_file_ids_save(simple_array_get_data(data->file_ids), file_count, prefix, ff)) break; for(i = 0; i < file_count; ++i) { diff --git a/lib/toolbox/simple_array.c b/lib/toolbox/simple_array.c index 78f7bdf12d38..97550106c03c 100644 --- a/lib/toolbox/simple_array.c +++ b/lib/toolbox/simple_array.c @@ -96,6 +96,17 @@ const SimpleArrayElement* simple_array_cget(const SimpleArray* instance, uint32_ return simple_array_get((SimpleArrayElement*)instance, index); } +SimpleArrayData* simple_array_get_data(SimpleArray* instance) { + furi_assert(instance); + furi_assert(instance->data); + + return instance->data; +} + +const SimpleArrayData* simple_array_cget_data(const SimpleArray* instance) { + return simple_array_get_data((SimpleArray*)instance); +} + const SimpleArrayConfig simple_array_config_uint8_t = { .init = NULL, .copy = NULL, diff --git a/lib/toolbox/simple_array.h b/lib/toolbox/simple_array.h index 1a3538712d9e..b3d070cd74cd 100644 --- a/lib/toolbox/simple_array.h +++ b/lib/toolbox/simple_array.h @@ -1,3 +1,19 @@ +/** + * @file simple_array.h + * + * @brief This file provides a simple (non-type safe) array for elements with + * (optional) in-place construction support. + * + * No append, remove or take operations are supported. + * Instead, the user must call simple_array_init() in order to reserve the memory for n elements. + * In case if init() is specified in the configuration, then the elements are constructed in-place. + * + * To clear all elements from the array, call simple_array_reset(), which will also call reset() + * for each element in case if it was specified in the configuration. This is useful if a custom + * destructor is required for a particular type. Calling simple_array_free() will also result in a + * simple_array_reset() call automatically. + * + */ #pragma once #include @@ -9,35 +25,111 @@ extern "C" { typedef struct SimpleArray SimpleArray; +typedef void SimpleArrayData; typedef void SimpleArrayElement; typedef void (*SimpleArrayInit)(SimpleArrayElement* elem); typedef void (*SimpleArrayReset)(SimpleArrayElement* elem); typedef void (*SimpleArrayCopy)(SimpleArrayElement* elem, const SimpleArrayElement* other); +/** Simple Array configuration structure. Defined per type. */ typedef struct { - SimpleArrayInit init; - SimpleArrayReset reset; - SimpleArrayCopy copy; - const size_t type_size; + SimpleArrayInit init; /**< Initialisation (in-place constructor) method. */ + SimpleArrayReset reset; /**< Reset (custom destructor) method. */ + SimpleArrayCopy copy; /**< Copy (custom copy-constructor) method. */ + const size_t type_size; /** Type size, in bytes. */ } SimpleArrayConfig; +/** + * Allocate a SimpleArray instance with the given configuration. + * + * @param [in] config Pointer to the type-specific configuration + * @return Pointer to the allocated SimpleArray instance + */ SimpleArray* simple_array_alloc(const SimpleArrayConfig* config); +/** + * Free a SimpleArray instance and release its contents. + * + * @param [in] instance Pointer to the SimpleArray instance to be freed + */ void simple_array_free(SimpleArray* instance); +/** + * Initialise a SimpleArray instance by allocating additional space to contain + * the requested number of elements. + * If init() is specified in the config, then it is called for each element, + * otherwise the data is filled with zeroes. + * + * @param [in] instance Pointer to the SimpleArray instance to be init'd + * @param [in] count Number of elements to be allocated and init'd + */ void simple_array_init(SimpleArray* instance, uint32_t count); +/** + * Reset a SimpleArray instance and delete all of its elements. + * If reset() is specified in the config, then it is called for each element, + * otherwise the data is simply free()'d. + * + * @param [in] instance Pointer to the SimpleArray instance to be reset + */ void simple_array_reset(SimpleArray* instance); +/** + * Copy (duplicate) another SimpleArray instance to this one. + * If copy() is specified in the config, then it is called for each element, + * otherwise the data is simply memcpy()'d. + * + * @param [in] instance Pointer to the SimpleArray instance to copy to + * @param [in] other Pointer to the SimpleArray instance to copy from + */ void simple_array_copy(SimpleArray* instance, const SimpleArray* other); +/** + * Get the count of elements currently contained in a SimpleArray instance. + * + * @param [in] instance Pointer to the SimpleArray instance to query the count from + * @return Count of elements contained in the instance + */ uint32_t simple_array_get_count(const SimpleArray* instance); +/** + * Get a pointer to an element contained in a SimpleArray instance. + * + * @param [in] instance Pointer to the SimpleArray instance to get an element from + * @param [in] index Index of the element in question. MUST be less than total element count + * @return Pointer to the element specified by index + */ SimpleArrayElement* simple_array_get(SimpleArray* instance, uint32_t index); +/** + * Get a const pointer to an element contained in a SimpleArray instance. + * + * @param [in] instance Pointer to the SimpleArray instance to get an element from + * @param [in] index Index of the element in question. MUST be less than total element count + * @return Const pointer to the element specified by index + */ const SimpleArrayElement* simple_array_cget(const SimpleArray* instance, uint32_t index); +/** + * Get a pointer to the internal data of a SimpleArray instance. + * + * @param [in] instance Pointer to the SimpleArray instance to get the data of + * @return Pointer to the instance's internal data + */ +SimpleArrayData* simple_array_get_data(SimpleArray* instance); + +/** + * Get a constant pointer to the internal data of a SimpleArray instance. + * + * @param [in] instance Pointer to the SimpleArray instance to get the data of + * @return Constant pointer to the instance's internal data + */ +const SimpleArrayData* simple_array_cget_data(const SimpleArray* instance); + +// Standard preset configurations + +// Preset configuration for a byte(uint8_t) array. extern const SimpleArrayConfig simple_array_config_uint8_t; #ifdef __cplusplus From b09c6d43a637c00e2639820c885fbc84d9241f4f Mon Sep 17 00:00:00 2001 From: RebornedBrain <138568282+RebornedBrain@users.noreply.github.com> Date: Tue, 1 Aug 2023 14:31:30 +0300 Subject: [PATCH 130/149] [FL-3445] Nfc: shadow file support (#2931) * Restore original confirm scene added * Menu item and handler added * Restore done scene added * "Restore Data Changes" will be shown only when shadow file exists * Added nfc_delete_shadow_file to internal API defines * nfc_delete_shadow_file adjustments Now function sets shadow file name internaly before trying to delete * Update nfc_scene_restore_original_confirm.c Now different scene will be shown depending on the result of nfc_delete_shadow_file. When true it will go to success screen, otherwise to start screen. * nfc_set_shadow_file_path now checks if path already point to .shd file * Implemented logic of saving card data to shadow file * Reload card after restoration Now we perfrom nfc card reloading and depending on the result we show 'SavedMenu' if reload was successful or 'FileSelect' scene in other case * Moved file_path adjustments from scene to nfc_load_file Now nfc_load_file checks when there is no shadow file but path points to .shd file, then it replaces extension to .nfc --- .../protocol_support/nfc_protocol_support.c | 29 ++++++++-- .../nfc_protocol_support_gui_common.h | 1 + applications/main/nfc/nfc_app.c | 27 +++++++--- applications/main/nfc/nfc_app_i.h | 2 + .../main/nfc/scenes/nfc_scene_config.h | 2 + .../nfc/scenes/nfc_scene_restore_original.c | 45 ++++++++++++++++ .../nfc_scene_restore_original_confirm.c | 54 +++++++++++++++++++ 7 files changed, 148 insertions(+), 12 deletions(-) create mode 100644 applications/main/nfc/scenes/nfc_scene_restore_original.c create mode 100644 applications/main/nfc/scenes/nfc_scene_restore_original_confirm.c diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c index 7ceeeee62f29..2175404074e1 100644 --- a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c @@ -344,7 +344,14 @@ static void nfc_protocol_support_scene_saved_menu_on_enter(NfcApp* instance) { nfc_protocol_support_common_submenu_callback, instance); - // TODO: Implement restore from shadow file + if(nfc_has_shadow_file(instance)) { + submenu_add_item( + submenu, + "Restore Data Changes", + SubmenuIndexCommonRestore, + nfc_protocol_support_common_submenu_callback, + instance); + } submenu_set_selected_item( instance->submenu, @@ -360,9 +367,10 @@ static bool if(event.type == SceneManagerEventTypeCustom) { scene_manager_set_scene_state(instance->scene_manager, NfcSceneSavedMenu, event.event); - // TODO: Implement restore from shadow file - - if(event.event == SubmenuIndexCommonInfo) { + if(event.event == SubmenuIndexCommonRestore) { + scene_manager_next_scene(instance->scene_manager, NfcSceneRestoreOriginalConfirm); + consumed = true; + } else if(event.event == SubmenuIndexCommonInfo) { scene_manager_next_scene(instance->scene_manager, NfcSceneSupportedCard); consumed = true; } else if(event.event == SubmenuIndexCommonRename) { @@ -489,6 +497,19 @@ static bool static void nfc_protocol_support_scene_emulate_on_exit(NfcApp* instance) { nfc_listener_stop(instance->listener); + + NfcDevice* nfc_stub = nfc_device_alloc(); + NfcProtocol protocol = nfc_device_get_protocol(instance->nfc_device); + const NfcDeviceData* data = nfc_listener_get_data(instance->listener, protocol); + nfc_device_set_data(nfc_stub, protocol, data); + + //TODO: think about nfc_device_is_equal(NfcDevice*,NfcDeviceData*); + if(!nfc_device_is_equal(nfc_stub, instance->nfc_device)) { + nfc_device_set_data(instance->nfc_device, protocol, data); + nfc_save_shadow_file(instance); + } + nfc_device_free(nfc_stub); + nfc_listener_free(instance->listener); // Clear view diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_gui_common.h b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_gui_common.h index 0f1532bd30d5..db14fed5ea04 100644 --- a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_gui_common.h +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_gui_common.h @@ -11,6 +11,7 @@ enum { SubmenuIndexCommonInfo, SubmenuIndexCommonRename, SubmenuIndexCommonDelete, + SubmenuIndexCommonRestore, SubmenuIndexCommonMax, }; diff --git a/applications/main/nfc/nfc_app.c b/applications/main/nfc/nfc_app.c index 5fda1359cb6c..9b35813e1b74 100644 --- a/applications/main/nfc/nfc_app.c +++ b/applications/main/nfc/nfc_app.c @@ -272,7 +272,10 @@ static bool nfc_set_shadow_file_path(FuriString* file_path, FuriString* shadow_f furi_assert(shadow_file_path); bool shadow_file_path_set = false; - if(furi_string_end_with(file_path, NFC_APP_EXTENSION)) { + if(furi_string_end_with(file_path, NFC_APP_SHADOW_EXTENSION)) { + furi_string_set(shadow_file_path, file_path); + shadow_file_path_set = true; + } else if(furi_string_end_with(file_path, NFC_APP_EXTENSION)) { size_t path_len = furi_string_size(file_path); // Cut .nfc furi_string_set_n(shadow_file_path, file_path, 0, path_len - 4); @@ -347,6 +350,10 @@ bool nfc_load_file(NfcApp* instance, FuriString* path, bool show_dialog) { FuriString* load_path = furi_string_alloc(); if(nfc_has_shadow_file_internal(instance, path)) { nfc_set_shadow_file_path(path, load_path); + } else if(furi_string_end_with(path, NFC_APP_SHADOW_EXTENSION)) { + size_t path_len = furi_string_size(path); + furi_string_set_n(load_path, path, 0, path_len - 4); + furi_string_cat_printf(load_path, "%s", NFC_APP_EXTENSION); } else { furi_string_set(load_path, path); } @@ -369,18 +376,22 @@ bool nfc_load_file(NfcApp* instance, FuriString* path, bool show_dialog) { bool nfc_delete(NfcApp* instance) { furi_assert(instance); - bool result = false; - FuriString* shadow_file_path = furi_string_alloc(); - if(nfc_has_shadow_file(instance)) { - nfc_set_shadow_file_path(instance->file_path, shadow_file_path); - storage_simply_remove(instance->storage, furi_string_get_cstr(shadow_file_path)); + nfc_delete_shadow_file(instance); } - result = storage_simply_remove(instance->storage, furi_string_get_cstr(instance->file_path)); + return storage_simply_remove(instance->storage, furi_string_get_cstr(instance->file_path)); +} - furi_string_free(shadow_file_path); +bool nfc_delete_shadow_file(NfcApp* instance) { + furi_assert(instance); + + FuriString* shadow_file_path = furi_string_alloc(); + bool result = nfc_set_shadow_file_path(instance->file_path, shadow_file_path) && + storage_simply_remove(instance->storage, furi_string_get_cstr(shadow_file_path)); + + furi_string_free(shadow_file_path); return result; } diff --git a/applications/main/nfc/nfc_app_i.h b/applications/main/nfc/nfc_app_i.h index 0d1f31abef76..2a7002e60630 100644 --- a/applications/main/nfc/nfc_app_i.h +++ b/applications/main/nfc/nfc_app_i.h @@ -157,6 +157,8 @@ bool nfc_has_shadow_file(NfcApp* instance); bool nfc_save_shadow_file(NfcApp* instance); +bool nfc_delete_shadow_file(NfcApp* instance); + bool nfc_save(NfcApp* instance); bool nfc_delete(NfcApp* instance); diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index 1642aee6d1a8..5dde7ce1e068 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -5,6 +5,8 @@ ADD_SCENE(nfc, save_name, SaveName) ADD_SCENE(nfc, save_success, SaveSuccess) ADD_SCENE(nfc, delete, Delete) ADD_SCENE(nfc, delete_success, DeleteSuccess) +ADD_SCENE(nfc, restore_original_confirm, RestoreOriginalConfirm) +ADD_SCENE(nfc, restore_original, RestoreOriginal) ADD_SCENE(nfc, detect, Detect) ADD_SCENE(nfc, read, Read) diff --git a/applications/main/nfc/scenes/nfc_scene_restore_original.c b/applications/main/nfc/scenes/nfc_scene_restore_original.c new file mode 100644 index 000000000000..612e6041e69e --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_restore_original.c @@ -0,0 +1,45 @@ +#include "../nfc_app_i.h" + +void nfc_scene_restore_original_popup_callback(void* context) { + NfcApp* nfc = context; + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); +} + +void nfc_scene_restore_original_on_enter(void* context) { + NfcApp* nfc = context; + + // Setup view + Popup* popup = nfc->popup; + popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); + popup_set_header(popup, "Original file\nrestored", 13, 22, AlignLeft, AlignBottom); + popup_set_timeout(popup, 1500); + popup_set_context(popup, nfc); + popup_set_callback(popup, nfc_scene_restore_original_popup_callback); + popup_enable_timeout(popup); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); +} + +bool nfc_scene_restore_original_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventViewExit) { + if(nfc_load_file(nfc, nfc->file_path, false)) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneSavedMenu); + } else { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneFileSelect); + } + } + } + return consumed; +} + +void nfc_scene_restore_original_on_exit(void* context) { + NfcApp* nfc = context; + + // Clear view + popup_reset(nfc->popup); +} diff --git a/applications/main/nfc/scenes/nfc_scene_restore_original_confirm.c b/applications/main/nfc/scenes/nfc_scene_restore_original_confirm.c new file mode 100644 index 000000000000..05a673e61ea3 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_restore_original_confirm.c @@ -0,0 +1,54 @@ +#include "../nfc_app_i.h" + +void nfc_scene_restore_original_confirm_dialog_callback(DialogExResult result, void* context) { + NfcApp* nfc = context; + + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); +} + +void nfc_scene_restore_original_confirm_on_enter(void* context) { + NfcApp* nfc = context; + DialogEx* dialog_ex = nfc->dialog_ex; + + dialog_ex_set_header(dialog_ex, "Restore Card Data?", 64, 0, AlignCenter, AlignTop); + dialog_ex_set_icon(dialog_ex, 5, 11, &I_ArrowC_1_36x36); + dialog_ex_set_text( + dialog_ex, "It will be returned\nto its original state.", 47, 21, AlignLeft, AlignTop); + dialog_ex_set_left_button_text(dialog_ex, "Cancel"); + dialog_ex_set_right_button_text(dialog_ex, "Restore"); + dialog_ex_set_context(dialog_ex, nfc); + dialog_ex_set_result_callback(dialog_ex, nfc_scene_restore_original_confirm_dialog_callback); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); +} + +bool nfc_scene_restore_original_confirm_on_event(void* context, SceneManagerEvent event) { + NfcApp* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == DialogExResultRight) { + if(nfc_delete_shadow_file(nfc)) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneRestoreOriginal); + } else { + scene_manager_search_and_switch_to_previous_scene( //TODO: maybe some better handling, for example showing 'Error' scene + nfc->scene_manager, + NfcSceneStart); + } + consumed = true; + } else if(event.event == DialogExResultLeft) { + consumed = scene_manager_previous_scene(nfc->scene_manager); + } + } else if(event.type == SceneManagerEventTypeBack) { + consumed = true; + } + + return consumed; +} + +void nfc_scene_restore_original_confirm_on_exit(void* context) { + NfcApp* nfc = context; + + // Clean view + dialog_ex_reset(nfc->dialog_ex); +} From 480ba84f2dc4662162001609cd17fa124f0d0e33 Mon Sep 17 00:00:00 2001 From: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Date: Wed, 2 Aug 2023 12:52:20 +0300 Subject: [PATCH 131/149] [NFC] ISO15693-3 (NFC-V) Poller (#2936) * Add initial ISO15693-3 support (load and save) * ISO15693-3 poller skeleton implementation * NFC chip configuration for NFC-V * Improve NFC-V chip configuration * Almost working NFC-B card activation * Implement system info * Working NFC-V poller * Read block security as well * Refactor NFC-V code * Improve NFC-V file loading and saving * Improve NFC-V poller code * Improve NFC-V error handling * Finished NFC-V poller implementation * Improve NFC-V poller states and function names * Better equality method for NFC-V * Minor fixes --- .../protocol_support/iso15693_3/iso15693_3.c | 112 ++++++ .../protocol_support/iso15693_3/iso15693_3.h | 5 + .../iso15693_3/iso15693_3_render.c | 63 +++ .../iso15693_3/iso15693_3_render.h | 10 + .../nfc_protocol_support_defs.c | 2 + firmware/targets/f7/api_symbols.csv | 3 + firmware/targets/f7/furi_hal/f_hal_nfc.c | 75 +++- firmware/targets/furi_hal_include/f_hal_nfc.h | 13 +- lib/nfc/helpers/bit_buffer.c | 33 +- lib/nfc/helpers/bit_buffer.h | 20 + lib/nfc/helpers/iso13239_crc.c | 62 +++ lib/nfc/helpers/iso13239_crc.h | 27 ++ lib/nfc/helpers/iso14443_crc.c | 2 - lib/nfc/nfc.c | 20 +- lib/nfc/nfc.h | 12 +- .../iso14443_3a/iso14443_3a_listener.c | 2 +- .../iso14443_3a/iso14443_3a_poller.c | 2 +- .../iso14443_3b/iso14443_3b_poller.c | 2 +- lib/nfc/protocols/iso15693_3/iso15693_3.c | 305 ++++++++++++++ lib/nfc/protocols/iso15693_3/iso15693_3.h | 156 +++++++ lib/nfc/protocols/iso15693_3/iso15693_3_i.c | 212 ++++++++++ lib/nfc/protocols/iso15693_3/iso15693_3_i.h | 38 ++ .../iso15693_3/iso15693_3_listener.c | 0 .../iso15693_3/iso15693_3_listener.h | 9 + .../iso15693_3/iso15693_3_listener_defs.h | 9 + .../iso15693_3/iso15693_3_listener_i.c | 0 .../iso15693_3/iso15693_3_listener_i.h | 9 + .../protocols/iso15693_3/iso15693_3_poller.c | 130 ++++++ .../protocols/iso15693_3/iso15693_3_poller.h | 29 ++ .../iso15693_3/iso15693_3_poller_defs.h | 13 + .../iso15693_3/iso15693_3_poller_i.c | 380 ++++++++++++++++++ .../iso15693_3/iso15693_3_poller_i.h | 72 ++++ lib/nfc/protocols/nfc_device_defs.c | 2 + lib/nfc/protocols/nfc_poller_defs.c | 2 + lib/nfc/protocols/nfc_protocol.c | 16 +- lib/nfc/protocols/nfc_protocol.h | 1 + lib/toolbox/simple_array.c | 12 + lib/toolbox/simple_array.h | 11 + 38 files changed, 1838 insertions(+), 33 deletions(-) create mode 100644 applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3.c create mode 100644 applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3.h create mode 100644 applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3_render.c create mode 100644 applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3_render.h create mode 100644 lib/nfc/helpers/iso13239_crc.c create mode 100644 lib/nfc/helpers/iso13239_crc.h create mode 100644 lib/nfc/protocols/iso15693_3/iso15693_3.c create mode 100644 lib/nfc/protocols/iso15693_3/iso15693_3.h create mode 100644 lib/nfc/protocols/iso15693_3/iso15693_3_i.c create mode 100644 lib/nfc/protocols/iso15693_3/iso15693_3_i.h create mode 100644 lib/nfc/protocols/iso15693_3/iso15693_3_listener.c create mode 100644 lib/nfc/protocols/iso15693_3/iso15693_3_listener.h create mode 100644 lib/nfc/protocols/iso15693_3/iso15693_3_listener_defs.h create mode 100644 lib/nfc/protocols/iso15693_3/iso15693_3_listener_i.c create mode 100644 lib/nfc/protocols/iso15693_3/iso15693_3_listener_i.h create mode 100644 lib/nfc/protocols/iso15693_3/iso15693_3_poller.c create mode 100644 lib/nfc/protocols/iso15693_3/iso15693_3_poller.h create mode 100644 lib/nfc/protocols/iso15693_3/iso15693_3_poller_defs.h create mode 100644 lib/nfc/protocols/iso15693_3/iso15693_3_poller_i.c create mode 100644 lib/nfc/protocols/iso15693_3/iso15693_3_poller_i.h diff --git a/applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3.c b/applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3.c new file mode 100644 index 000000000000..59f0e55a858b --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3.c @@ -0,0 +1,112 @@ +#include "iso15693_3.h" +#include "iso15693_3_render.h" + +#include + +#include "nfc/nfc_app_i.h" + +#include "../nfc_protocol_support_gui_common.h" + +static void nfc_scene_info_on_enter_iso15693_3(NfcApp* instance) { + const NfcDevice* device = instance->nfc_device; + const Iso15693_3Data* data = nfc_device_get_data(device, NfcProtocolIso15693_3); + + FuriString* temp_str = furi_string_alloc(); + furi_string_cat_printf( + temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull)); + nfc_render_iso15693_3_info(data, NfcProtocolFormatTypeFull, temp_str); + + widget_add_text_scroll_element( + instance->widget, 0, 0, 128, 64, furi_string_get_cstr(temp_str)); + + furi_string_free(temp_str); +} + +static NfcCommand nfc_scene_read_poller_callback_iso15693_3(NfcGenericEvent event, void* context) { + furi_assert(event.protocol == NfcProtocolIso15693_3); + + NfcApp* instance = context; + const Iso15693_3PollerEvent* iso15693_3_event = event.data; + + if(iso15693_3_event->type == Iso15693_3PollerEventTypeReady) { + nfc_device_set_data( + instance->nfc_device, NfcProtocolIso15693_3, nfc_poller_get_data(instance->poller)); + view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventPollerSuccess); + return NfcCommandStop; + } + + return NfcCommandContinue; +} + +static void nfc_scene_read_on_enter_iso15693_3(NfcApp* instance) { + UNUSED(instance); + nfc_poller_start(instance->poller, nfc_scene_read_poller_callback_iso15693_3, instance); +} + +static void nfc_scene_read_success_on_enter_iso15693_3(NfcApp* instance) { + const NfcDevice* device = instance->nfc_device; + const Iso15693_3Data* data = nfc_device_get_data(device, NfcProtocolIso15693_3); + + FuriString* temp_str = furi_string_alloc(); + furi_string_cat_printf( + temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull)); + nfc_render_iso15693_3_info(data, NfcProtocolFormatTypeShort, temp_str); + + widget_add_text_scroll_element( + instance->widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); + + furi_string_free(temp_str); +} + +static bool nfc_scene_info_on_event_iso15693_3(NfcApp* instance, uint32_t event) { + if(event == GuiButtonTypeRight) { + scene_manager_next_scene(instance->scene_manager, NfcSceneNotImplemented); + return true; + } + + return false; +} + +static bool nfc_scene_saved_menu_on_event_iso15693_3(NfcApp* instance, uint32_t event) { + if(event == SubmenuIndexCommonEdit) { + scene_manager_next_scene(instance->scene_manager, NfcSceneSetUid); + return true; + } + + return false; +} + +const NfcProtocolSupportBase nfc_protocol_support_iso15693_3 = { + .features = NfcProtocolFeatureNone, // TODO: Implement better UID editing, + + .scene_info = + { + .on_enter = nfc_scene_info_on_enter_iso15693_3, + .on_event = nfc_scene_info_on_event_iso15693_3, + }, + .scene_read = + { + .on_enter = nfc_scene_read_on_enter_iso15693_3, + .on_event = NULL, + }, + .scene_read_menu = + { + .on_enter = nfc_protocol_support_common_on_enter_empty, + .on_event = nfc_protocol_support_common_on_event_empty, + }, + .scene_read_success = + { + .on_enter = nfc_scene_read_success_on_enter_iso15693_3, + .on_event = NULL, + }, + .scene_saved_menu = + { + .on_enter = nfc_protocol_support_common_on_enter_empty, + .on_event = nfc_scene_saved_menu_on_event_iso15693_3, + }, + .scene_emulate = + { + .on_enter = NULL, + .on_event = NULL, + }, +}; diff --git a/applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3.h b/applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3.h new file mode 100644 index 000000000000..a26633ee6103 --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3.h @@ -0,0 +1,5 @@ +#pragma once + +#include "../nfc_protocol_support_base.h" + +extern const NfcProtocolSupportBase nfc_protocol_support_iso15693_3; diff --git a/applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3_render.c b/applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3_render.c new file mode 100644 index 000000000000..76e549df0e7d --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3_render.c @@ -0,0 +1,63 @@ +#include "iso15693_3_render.h" + +#define NFC_RENDER_ISO15693_3_MAX_BYTES (128U) + +void nfc_render_iso15693_3_info( + const Iso15693_3Data* data, + NfcProtocolFormatType format_type, + FuriString* str) { + if(format_type == NfcProtocolFormatTypeFull) { + furi_string_cat(str, "ISO15693-3 (NFC-V)\n"); + } + + furi_string_cat_printf(str, "UID:"); + for(size_t i = 0; i < ISO15693_3_UID_SIZE; i++) { + furi_string_cat_printf(str, " %02X", data->uid[i]); + } + + if(format_type != NfcProtocolFormatTypeFull) return; + + furi_string_push_back(str, '\n'); + + if(data->system_info.flags & ISO15693_3_SYSINFO_FLAG_DSFID) { + furi_string_cat_printf(str, "DSFID: %02X\n", data->system_info.ic_ref); + } + + if(data->system_info.flags & ISO15693_3_SYSINFO_FLAG_AFI) { + furi_string_cat_printf(str, "AFI: %02X\n", data->system_info.afi); + } + + if(data->system_info.flags & ISO15693_3_SYSINFO_FLAG_IC_REF) { + furi_string_cat_printf(str, "IC Reference: %02X\n", data->system_info.ic_ref); + } + + if(data->system_info.flags & ISO15693_3_SYSINFO_FLAG_MEMORY) { + furi_string_cat_printf(str, "Block count: %u\n", data->system_info.block_count); + furi_string_cat_printf(str, "Block size: %u\n", data->system_info.block_size); + + const uint32_t block_data_size = simple_array_get_count(data->block_data); + const uint32_t display_data_size = MIN(block_data_size, NFC_RENDER_ISO15693_3_MAX_BYTES); + + furi_string_cat_printf(str, "Data (%lu bytes):\n", block_data_size); + + const uint32_t block_count = display_data_size / data->system_info.block_size; + + for(uint32_t i = 0; i < block_count; ++i) { + furi_string_cat(str, "\e*"); + + for(uint32_t j = 0; j < data->system_info.block_size; j++) { + const uint8_t byte = *(uint8_t*)simple_array_cget( + data->block_data, i * data->system_info.block_size + j); + furi_string_cat_printf(str, "%02X ", byte); + } + + const uint8_t security = *(uint8_t*)simple_array_cget(data->block_security, i + 1); + furi_string_cat_printf(str, "%s\n", (security & 0x01) ? "[LOCK]" : ""); + } + + if(block_data_size != display_data_size) { + furi_string_cat_printf( + str, "(Data is too big. Showing only the first %lu bytes.)", display_data_size); + } + } +} diff --git a/applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3_render.h b/applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3_render.h new file mode 100644 index 000000000000..bffec5355384 --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3_render.h @@ -0,0 +1,10 @@ +#pragma once + +#include + +#include "../nfc_protocol_support_render_common.h" + +void nfc_render_iso15693_3_info( + const Iso15693_3Data* data, + NfcProtocolFormatType format_type, + FuriString* str); diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_defs.c b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_defs.c index 9771dbe87500..82d910ec5bef 100644 --- a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_defs.c +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_defs.c @@ -3,6 +3,7 @@ #include "iso14443_3a/iso14443_3a.h" #include "iso14443_3b/iso14443_3b.h" #include "iso14443_4a/iso14443_4a.h" +#include "iso15693_3/iso15693_3.h" #include "mf_ultralight/mf_ultralight.h" #include "mf_classic/mf_classic.h" #include "mf_desfire/mf_desfire.h" @@ -11,6 +12,7 @@ const NfcProtocolSupportBase* nfc_protocol_support[NfcProtocolNum] = { [NfcProtocolIso14443_3a] = &nfc_protocol_support_iso14443_3a, [NfcProtocolIso14443_3b] = &nfc_protocol_support_iso14443_3b, [NfcProtocolIso14443_4a] = &nfc_protocol_support_iso14443_4a, + [NfcProtocolIso15693_3] = &nfc_protocol_support_iso15693_3, [NfcProtocolMfUltralight] = &nfc_protocol_support_mf_ultralight, [NfcProtocolMfClassic] = &nfc_protocol_support_mf_classic, [NfcProtocolMfDesfire] = &nfc_protocol_support_mf_desfire, diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 11a7bf5f9c44..74907535ddf1 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -585,6 +585,7 @@ Function,-,bcmp,int,"const void*, const void*, size_t" Function,-,bcopy,void,"const void*, void*, size_t" Function,+,bit_buffer_alloc,BitBuffer*,size_t Function,+,bit_buffer_append,void,"BitBuffer*, const BitBuffer*" +Function,+,bit_buffer_append_bit,void,"BitBuffer*, _Bool" Function,+,bit_buffer_append_byte,void,"BitBuffer*, uint8_t" Function,+,bit_buffer_append_bytes,void,"BitBuffer*, const uint8_t*, size_t" Function,+,bit_buffer_append_right,void,"BitBuffer*, const BitBuffer*, size_t" @@ -596,6 +597,7 @@ Function,+,bit_buffer_copy_left,void,"BitBuffer*, const BitBuffer*, size_t" Function,+,bit_buffer_copy_right,void,"BitBuffer*, const BitBuffer*, size_t" Function,+,bit_buffer_free,void,BitBuffer* Function,+,bit_buffer_get_byte,uint8_t,"const BitBuffer*, size_t" +Function,+,bit_buffer_get_byte_from_bit,uint8_t,"const BitBuffer*, size_t" Function,+,bit_buffer_get_capacity_bytes,size_t,const BitBuffer* Function,+,bit_buffer_get_data,const uint8_t*,const BitBuffer* Function,+,bit_buffer_get_parity,const _Bool*,const BitBuffer* @@ -2674,6 +2676,7 @@ Function,+,simple_array_get,SimpleArrayElement*,"SimpleArray*, uint32_t" Function,+,simple_array_get_count,uint32_t,const SimpleArray* Function,+,simple_array_get_data,SimpleArrayData*,SimpleArray* Function,+,simple_array_init,void,"SimpleArray*, uint32_t" +Function,+,simple_array_is_equal,_Bool,"const SimpleArray*, const SimpleArray*" Function,+,simple_array_reset,void,SimpleArray* Function,-,sin,double,double Function,-,sincos,void,"double, double*, double*" diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc.c b/firmware/targets/f7/furi_hal/f_hal_nfc.c index 139edd270722..f9cca46ff44c 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfc.c +++ b/firmware/targets/f7/furi_hal/f_hal_nfc.c @@ -322,8 +322,8 @@ FHalNfcError f_hal_nfc_set_mode(FHalNfcMode mode, FHalNfcBitrate bitrate) { FHalNfcError error = FHalNfcErrorNone; FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; - if(mode == FHalNfcModeIso14443_3aPoller || mode == FHalNfcModeIso14443_3aListener) { - if(mode == FHalNfcModeIso14443_3aPoller) { + if(mode == FHalNfcModeIso14443aPoller || mode == FHalNfcModeIso14443aListener) { + if(mode == FHalNfcModeIso14443aPoller) { // Poller configuration f_hal_nfc_configure_poller_common(handle); // Enable ISO14443A mode, OOK modulation @@ -384,7 +384,7 @@ FHalNfcError f_hal_nfc_set_mode(FHalNfcMode mode, FHalNfcBitrate bitrate) { st25r3916_write_reg(handle, ST25R3916_REG_CORR_CONF2, 0x00); } - } else if(mode == FHalNfcModeIso14443_3bPoller /* TODO: Listener support */) { + } else if(mode == FHalNfcModeIso14443bPoller /* TODO: Listener support */) { f_hal_nfc_configure_poller_common(handle); // Enable ISO14443B mode, AM modulation st25r3916_change_reg_bits( @@ -462,6 +462,75 @@ FHalNfcError f_hal_nfc_set_mode(FHalNfcMode mode, FHalNfcBitrate bitrate) { // Sleep mode disable, 424kHz mode off st25r3916_write_reg(handle, ST25R3916_REG_CORR_CONF2, 0x00); } + + } else if(mode == FHalNfcModeIso15693Poller || mode == FHalNfcModeIso15693Listener) { + if(mode == FHalNfcModeIso15693Poller) { + // Poller configuration + f_hal_nfc_configure_poller_common(handle); + // Enable Subcarrier Stream mode, OOK modulation + st25r3916_change_reg_bits( + handle, + ST25R3916_REG_MODE, + ST25R3916_REG_MODE_om_mask | ST25R3916_REG_MODE_tr_am, + ST25R3916_REG_MODE_om_subcarrier_stream | ST25R3916_REG_MODE_tr_am_ook); + + // Subcarrier 424 kHz mode + // 8 sub-carrier pulses in report period + st25r3916_write_reg( + handle, + ST25R3916_REG_STREAM_MODE, + ST25R3916_REG_STREAM_MODE_scf_sc424 | ST25R3916_REG_STREAM_MODE_stx_106 | + ST25R3916_REG_STREAM_MODE_scp_8pulses); + + // Use regulator AM, resistive AM disabled + st25r3916_clear_reg_bits( + handle, + ST25R3916_REG_AUX_MOD, + ST25R3916_REG_AUX_MOD_dis_reg_am | ST25R3916_REG_AUX_MOD_res_am); + + } else { + // Listener configuration + f_hal_nfca_listener_init(); + // TODO: Implement listener config + } + + if(bitrate == FHalNfcBitrate26p48) { + // Bitrate-dependent NFC-V settings + + // 1st stage zero = 12 kHz, 3rd stage zero = 80 kHz, low-pass = 600 kHz + st25r3916_write_reg( + handle, + ST25R3916_REG_RX_CONF1, + ST25R3916_REG_RX_CONF1_z12k | ST25R3916_REG_RX_CONF1_h80 | + ST25R3916_REG_RX_CONF1_lp_600khz); + + // Enable AGC + // AGC Ratio 6 + // AGC algorithm with RESET (recommended for ISO15693) + // AGC operation during complete receive period + // Squelch automatic activation on TX end + st25r3916_write_reg( + handle, + ST25R3916_REG_RX_CONF2, + ST25R3916_REG_RX_CONF2_agc6_3 | ST25R3916_REG_RX_CONF2_agc_m | + ST25R3916_REG_RX_CONF2_agc_en | ST25R3916_REG_RX_CONF2_sqm_dyn); + + // HF operation, full gain on AM and PM channels + st25r3916_write_reg(handle, ST25R3916_REG_RX_CONF3, 0x00); + // No gain reduction on AM and PM channels + st25r3916_write_reg(handle, ST25R3916_REG_RX_CONF4, 0x00); + + // Collision detection level 53% + // AM & PM summation before digitizing on + st25r3916_write_reg( + handle, + ST25R3916_REG_CORR_CONF1, + ST25R3916_REG_CORR_CONF1_corr_s0 | ST25R3916_REG_CORR_CONF1_corr_s1 | + ST25R3916_REG_CORR_CONF1_corr_s4); + // 424 kHz subcarrier stream mode on + st25r3916_write_reg( + handle, ST25R3916_REG_CORR_CONF2, ST25R3916_REG_CORR_CONF2_corr_s8); + } } return error; diff --git a/firmware/targets/furi_hal_include/f_hal_nfc.h b/firmware/targets/furi_hal_include/f_hal_nfc.h index 72563b9d9d6a..9c847dc5342d 100644 --- a/firmware/targets/furi_hal_include/f_hal_nfc.h +++ b/firmware/targets/furi_hal_include/f_hal_nfc.h @@ -41,22 +41,23 @@ typedef enum { } FHalNfcError; typedef enum { - FHalNfcModeIso14443_3aPoller, - FHalNfcModeIso14443_3aListener, + FHalNfcModeIso14443aPoller, + FHalNfcModeIso14443aListener, - FHalNfcModeIso14443_3bPoller, - FHalNfcModeIso14443_3bListener, + FHalNfcModeIso14443bPoller, + FHalNfcModeIso14443bListener, FHalNfcModeNfcfPoller, FHalNfcModeNfcfListener, - FHalNfcModeNfcvPoller, - FHalNfcModeNfcvListener, + FHalNfcModeIso15693Poller, + FHalNfcModeIso15693Listener, FHalNfcModeNum, } FHalNfcMode; typedef enum { + FHalNfcBitrate26p48, FHalNfcBitrate106, } FHalNfcBitrate; diff --git a/lib/nfc/helpers/bit_buffer.c b/lib/nfc/helpers/bit_buffer.c index 566393e784ed..3de216d1c453 100644 --- a/lib/nfc/helpers/bit_buffer.c +++ b/lib/nfc/helpers/bit_buffer.c @@ -35,6 +35,7 @@ void bit_buffer_free(BitBuffer* buf) { void bit_buffer_reset(BitBuffer* buf) { furi_assert(buf); + memset(buf->data, 0, buf->capacity_bytes); buf->size_bits = 0; } @@ -212,6 +213,19 @@ uint8_t bit_buffer_get_byte(const BitBuffer* buf, size_t index) { return buf->data[index]; } +uint8_t bit_buffer_get_byte_from_bit(const BitBuffer* buf, size_t index_bits) { + furi_assert(buf); + furi_assert(buf->capacity_bytes * BITS_IN_BYTE > index_bits); + + const size_t byte_index = index_bits / BITS_IN_BYTE; + const size_t bit_offset = index_bits % BITS_IN_BYTE; + + const uint8_t lo = buf->data[byte_index] >> bit_offset; + const uint8_t hi = buf->data[byte_index + 1] << (BITS_IN_BYTE - bit_offset); + + return lo | hi; +} + const uint8_t* bit_buffer_get_data(const BitBuffer* buf) { furi_assert(buf); @@ -227,8 +241,8 @@ const bool* bit_buffer_get_parity(const BitBuffer* buf) { void bit_buffer_set_byte(BitBuffer* buf, size_t index, uint8_t byte) { furi_assert(buf); - size_t size_byted = bit_buffer_get_size_bytes(buf); - furi_assert(size_byted > index); + const size_t size_bytes = bit_buffer_get_size_bytes(buf); + furi_assert(size_bytes > index); buf->data[index] = byte; } @@ -294,3 +308,18 @@ void bit_buffer_append_bytes(BitBuffer* buf, const uint8_t* data, size_t size_by memcpy(&buf->data[buf_size_bytes], data, size_bytes); buf->size_bits += size_bytes * BITS_IN_BYTE; } + +void bit_buffer_append_bit(BitBuffer* buf, bool bit) { + furi_assert(buf); + furi_assert( + bit_buffer_get_size_bytes(buf) <= + (buf->capacity_bytes - (bit_buffer_has_partial_byte(buf) ? 0 : 1))); + + if(bit) { + const size_t byte_index = buf->size_bits / BITS_IN_BYTE; + const size_t bit_offset = (buf->size_bits % BITS_IN_BYTE); + buf->data[byte_index] |= 1U << bit_offset; + } + + buf->size_bits++; +} diff --git a/lib/nfc/helpers/bit_buffer.h b/lib/nfc/helpers/bit_buffer.h index bd5003b71fca..620a873c1de2 100644 --- a/lib/nfc/helpers/bit_buffer.h +++ b/lib/nfc/helpers/bit_buffer.h @@ -202,6 +202,17 @@ size_t bit_buffer_get_size_bytes(const BitBuffer* buf); */ uint8_t bit_buffer_get_byte(const BitBuffer* buf, size_t index); +/** + * Get a byte value starting from the specified bit index in a BitBuffer instance. + * The resulting byte might correspond to a single byte (if the index is a multiple + * of 8), or two overlapping bytes combined. + * The index must be valid (i.e. less than the instance's data size in bits). + * + * @param [in] buf pointer to a BitBuffer instance to be queried + * @param [in] index bit index of the byte in question + */ +uint8_t bit_buffer_get_byte_from_bit(const BitBuffer* buf, size_t index_bits); + /** * Get the pointer to a BitBuffer instance's underlying data. * @@ -300,6 +311,15 @@ void bit_buffer_append_byte(BitBuffer* buf, uint8_t byte); */ void bit_buffer_append_bytes(BitBuffer* buf, const uint8_t* data, size_t size_bytes); +/** + * Append a bit to a BitBuffer instance. + * The destination capacity must be sufficient to accomodate the additional bit. + * + * @param [in,out] buf pointer to a BitBuffer instance to be appended to + * @param [in] bit bit value to be appended + */ +void bit_buffer_append_bit(BitBuffer* buf, bool bit); + #ifdef __cplusplus } #endif diff --git a/lib/nfc/helpers/iso13239_crc.c b/lib/nfc/helpers/iso13239_crc.c new file mode 100644 index 000000000000..c54fbcfb21cc --- /dev/null +++ b/lib/nfc/helpers/iso13239_crc.c @@ -0,0 +1,62 @@ +#include "iso13239_crc.h" + +#include + +#define ISO13239_CRC_INIT_DEFAULT (0xFFFFU) +#define ISO13239_CRC_INIT_PICOPASS (0xE012U) +#define ISO13239_CRC_POLY (0x8408U) + +static uint16_t + iso13239_crc_calculate(Iso13239CrcType type, const uint8_t* data, size_t data_size) { + uint16_t crc; + + if(type == Iso13239CrcTypeDefault) { + crc = ISO13239_CRC_INIT_DEFAULT; + } else if(type == Iso13239CrcTypePicopass) { + crc = ISO13239_CRC_INIT_PICOPASS; + } else { + furi_crash("Wrong ISO13239 CRC type"); + } + + for(size_t i = 0; i < data_size; ++i) { + crc ^= (uint16_t)data[i]; + for(size_t j = 0; j < 8; ++j) { + if(crc & 1U) { + crc = (crc >> 1) ^ ISO13239_CRC_POLY; + } else { + crc >>= 1; + } + } + } + + return type == Iso13239CrcTypePicopass ? crc : ~crc; +} + +void iso13239_crc_append(Iso13239CrcType type, BitBuffer* buf) { + const uint8_t* data = bit_buffer_get_data(buf); + const size_t data_size = bit_buffer_get_size_bytes(buf); + + const uint16_t crc = iso13239_crc_calculate(type, data, data_size); + bit_buffer_append_bytes(buf, (const uint8_t*)&crc, ISO13239_CRC_SIZE); +} + +bool iso13239_crc_check(Iso13239CrcType type, const BitBuffer* buf) { + const size_t data_size = bit_buffer_get_size_bytes(buf); + if(data_size <= ISO13239_CRC_SIZE) return false; + + uint16_t crc_received; + bit_buffer_write_bytes_mid( + buf, &crc_received, data_size - ISO13239_CRC_SIZE, ISO13239_CRC_SIZE); + + const uint8_t* data = bit_buffer_get_data(buf); + const uint16_t crc_calc = iso13239_crc_calculate(type, data, data_size - ISO13239_CRC_SIZE); + + return (crc_calc == crc_received); +} + +void iso13239_crc_trim(BitBuffer* buf) { + const size_t data_size = bit_buffer_get_size_bytes(buf); + furi_assert(data_size > ISO13239_CRC_SIZE); + + bit_buffer_set_size_bytes(buf, data_size - ISO13239_CRC_SIZE); +} diff --git a/lib/nfc/helpers/iso13239_crc.h b/lib/nfc/helpers/iso13239_crc.h new file mode 100644 index 000000000000..7de2cd8a0f6c --- /dev/null +++ b/lib/nfc/helpers/iso13239_crc.h @@ -0,0 +1,27 @@ +#pragma once + +#include +#include + +#include "bit_buffer.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ISO13239_CRC_SIZE sizeof(uint16_t) + +typedef enum { + Iso13239CrcTypeDefault, + Iso13239CrcTypePicopass, +} Iso13239CrcType; + +void iso13239_crc_append(Iso13239CrcType type, BitBuffer* buf); + +bool iso13239_crc_check(Iso13239CrcType type, const BitBuffer* buf); + +void iso13239_crc_trim(BitBuffer* buf); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/helpers/iso14443_crc.c b/lib/nfc/helpers/iso14443_crc.c index 72fedb9e7e49..fda9871aa992 100644 --- a/lib/nfc/helpers/iso14443_crc.c +++ b/lib/nfc/helpers/iso14443_crc.c @@ -7,8 +7,6 @@ static uint16_t iso14443_crc_calculate(Iso14443CrcType type, const uint8_t* data, size_t data_size) { - furi_assert(data); - uint16_t crc; if(type == Iso14443CrcTypeA) { diff --git a/lib/nfc/nfc.c b/lib/nfc/nfc.c index 1c4c0d955b1f..e64c308e7b83 100644 --- a/lib/nfc/nfc.c +++ b/lib/nfc/nfc.c @@ -244,20 +244,28 @@ void nfc_free(Nfc* instance) { f_hal_nfc_release(); } +// TODO: refactor this function (use 2 parameters for mode?) void nfc_config(Nfc* instance, NfcMode mode) { furi_assert(instance); if(mode == NfcModeIdle) { f_hal_nfc_reset_mode(); instance->config_state = NfcConfigurationStateIdle; - } else if(mode == NfcModeIso14443_3aPoller) { - f_hal_nfc_set_mode(FHalNfcModeIso14443_3aPoller, FHalNfcBitrate106); + } else if(mode == NfcModeIso14443aPoller) { + f_hal_nfc_set_mode(FHalNfcModeIso14443aPoller, FHalNfcBitrate106); instance->config_state = NfcConfigurationStateDone; - } else if(mode == NfcModeIso14443_3aListener) { + } else if(mode == NfcModeIso14443aListener) { f_hal_nfc_low_power_mode_stop(); - f_hal_nfc_set_mode(FHalNfcModeIso14443_3aListener, FHalNfcBitrate106); + f_hal_nfc_set_mode(FHalNfcModeIso14443aListener, FHalNfcBitrate106); instance->config_state = NfcConfigurationStateDone; - } else if(mode == NfcModeIso14443_3bPoller) { - f_hal_nfc_set_mode(FHalNfcModeIso14443_3bPoller, FHalNfcBitrate106); + } else if(mode == NfcModeIso14443bPoller) { + f_hal_nfc_set_mode(FHalNfcModeIso14443bPoller, FHalNfcBitrate106); + instance->config_state = NfcConfigurationStateDone; + } else if(mode == NfcModeIso15693Poller) { + f_hal_nfc_set_mode(FHalNfcModeIso15693Poller, FHalNfcBitrate26p48); + instance->config_state = NfcConfigurationStateDone; + } else if(mode == NfcModeIso15693Listener) { + f_hal_nfc_low_power_mode_stop(); + f_hal_nfc_set_mode(FHalNfcModeIso15693Listener, FHalNfcBitrate26p48); instance->config_state = NfcConfigurationStateDone; } } diff --git a/lib/nfc/nfc.h b/lib/nfc/nfc.h index bcb7066f3232..f5a135e17e3e 100644 --- a/lib/nfc/nfc.h +++ b/lib/nfc/nfc.h @@ -40,14 +40,14 @@ typedef NfcCommand (*NfcEventCallback)(NfcEvent event, void* context); typedef enum { NfcModeIdle, - NfcModeIso14443_3aPoller, - NfcModeIso14443_3aListener, - NfcModeIso14443_3bPoller, - NfcModeIso14443_3bListener, + NfcModeIso14443aPoller, + NfcModeIso14443aListener, + NfcModeIso14443bPoller, + NfcModeIso14443bListener, NfcModeNfcfPoller, NfcModeNfcfListener, - NfcModeNfcvPoller, - NfcModeNfcvListener, + NfcModeIso15693Poller, + NfcModeIso15693Listener, } NfcMode; typedef enum { diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c b/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c index c6d14cc9187a..62c805dcabf8 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c @@ -39,7 +39,7 @@ Iso14443_3aListener* iso14443_3a_listener_alloc(Nfc* nfc, const Iso14443_3aData* instance->generic_event.data = &instance->iso14443_3a_event; nfc_set_fdt_listen_fc(instance->nfc, ISO14443_3A_FDT_LISTEN_FC); - nfc_config(instance->nfc, NfcModeIso14443_3aListener); + nfc_config(instance->nfc, NfcModeIso14443aListener); nfc_listener_set_col_res_data( instance->nfc, instance->data->uid, diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.c b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.c index 29ec412d46b1..5772960f49f3 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.c +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.c @@ -21,7 +21,7 @@ static Iso14443_3aPoller* iso14443_3a_poller_alloc(Nfc* nfc) { instance->tx_buffer = bit_buffer_alloc(ISO14443_3A_POLLER_MAX_BUFFER_SIZE); instance->rx_buffer = bit_buffer_alloc(ISO14443_3A_POLLER_MAX_BUFFER_SIZE); - nfc_config(instance->nfc, NfcModeIso14443_3aPoller); + nfc_config(instance->nfc, NfcModeIso14443aPoller); nfc_set_guard_time_us(instance->nfc, ISO14443_3A_GUARD_TIME_US); nfc_set_fdt_poll_fc(instance->nfc, ISO14443_3A_FDT_POLL_FC); nfc_set_fdt_poll_poll_us(instance->nfc, ISO14443_3A_POLL_POLL_MIN_US); diff --git a/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller.c b/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller.c index 4a95197c2c34..bac2d493cc07 100644 --- a/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller.c +++ b/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller.c @@ -21,7 +21,7 @@ static Iso14443_3bPoller* iso14443_3b_poller_alloc(Nfc* nfc) { instance->tx_buffer = bit_buffer_alloc(ISO14443_3B_POLLER_MAX_BUFFER_SIZE); instance->rx_buffer = bit_buffer_alloc(ISO14443_3B_POLLER_MAX_BUFFER_SIZE); - nfc_config(instance->nfc, NfcModeIso14443_3bPoller); + nfc_config(instance->nfc, NfcModeIso14443bPoller); nfc_set_guard_time_us(instance->nfc, ISO14443_3B_GUARD_TIME_US); nfc_set_fdt_poll_fc(instance->nfc, ISO14443_3B_FDT_POLL_FC); nfc_set_fdt_poll_poll_us(instance->nfc, ISO14443_3B_POLL_POLL_MIN_US); diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3.c b/lib/nfc/protocols/iso15693_3/iso15693_3.c new file mode 100644 index 000000000000..612743524609 --- /dev/null +++ b/lib/nfc/protocols/iso15693_3/iso15693_3.c @@ -0,0 +1,305 @@ +#include "iso15693_3.h" + +#include + +#define ISO15693_3_PROTOCOL_NAME "ISO15693-3" +#define ISO15693_3_PROTOCOL_NAME_LEGACY "ISO15693" +#define ISO15693_3_DEVICE_NAME "ISO15693-3 (Unknown)" + +#define ISO15693_3_DSFID_KEY "DSFID" +#define ISO15693_3_AFI_KEY "AFI" +#define ISO15693_3_IC_REF_KEY "IC Reference" +#define ISO15693_3_BLOCK_COUNT_KEY "Block Count" +#define ISO15693_3_BLOCK_SIZE_KEY "Block Size" +#define ISO15693_3_DATA_CONTENT_KEY "Data Content" +#define ISO15693_3_LOCK_BITS_KEY "Lock Bits" +#define ISO15693_3_SECURITY_STATUS_KEY "Security Status" + +const NfcDeviceBase nfc_device_iso15693_3 = { + .protocol_name = ISO15693_3_PROTOCOL_NAME, + .alloc = (NfcDeviceAlloc)iso15693_3_alloc, + .free = (NfcDeviceFree)iso15693_3_free, + .reset = (NfcDeviceReset)iso15693_3_reset, + .copy = (NfcDeviceCopy)iso15693_3_copy, + .verify = (NfcDeviceVerify)iso15693_3_verify, + .load = (NfcDeviceLoad)iso15693_3_load, + .save = (NfcDeviceSave)iso15693_3_save, + .is_equal = (NfcDeviceEqual)iso15693_3_is_equal, + .get_name = (NfcDeviceGetName)iso15693_3_get_device_name, + .get_uid = (NfcDeviceGetUid)iso15693_3_get_uid, + .set_uid = (NfcDeviceSetUid)iso15693_3_set_uid, + .get_base_data = (NfcDeviceGetBaseData)iso15693_3_get_base_data, +}; + +Iso15693_3Data* iso15693_3_alloc() { + Iso15693_3Data* data = malloc(sizeof(Iso15693_3Data)); + + data->block_data = simple_array_alloc(&simple_array_config_uint8_t); + data->block_security = simple_array_alloc(&simple_array_config_uint8_t); + + return data; +} + +void iso15693_3_free(Iso15693_3Data* data) { + furi_assert(data); + + simple_array_free(data->block_data); + simple_array_free(data->block_security); + free(data); +} + +void iso15693_3_reset(Iso15693_3Data* data) { + furi_assert(data); + + memset(data->uid, 0, ISO15693_3_UID_SIZE); + memset(&data->system_info, 0, sizeof(Iso15693_3SystemInfo)); + memset(&data->settings, 0, sizeof(Iso15693_3Settings)); + + simple_array_reset(data->block_data); + simple_array_reset(data->block_security); +} + +void iso15693_3_copy(Iso15693_3Data* data, const Iso15693_3Data* other) { + furi_assert(data); + furi_assert(other); + + memcpy(data->uid, other->uid, ISO15693_3_UID_SIZE); + + data->system_info = other->system_info; + data->settings = other->settings; + + simple_array_copy(data->block_data, other->block_data); + simple_array_copy(data->block_security, other->block_security); +} + +bool iso15693_3_verify(Iso15693_3Data* data, const FuriString* device_type) { + UNUSED(data); + return furi_string_equal(device_type, ISO15693_3_PROTOCOL_NAME_LEGACY); +} + +static inline bool iso15693_3_load_security_legacy(Iso15693_3Data* data, FlipperFormat* ff) { + bool loaded = false; + uint8_t* legacy_data = NULL; + + do { + uint32_t value_count; + if(!flipper_format_get_value_count(ff, ISO15693_3_SECURITY_STATUS_KEY, &value_count)) + break; + if(simple_array_get_count(data->block_security) + 1 != value_count) break; + + legacy_data = malloc(value_count); + if(!flipper_format_read_hex(ff, ISO15693_3_SECURITY_STATUS_KEY, legacy_data, value_count)) + break; + + // First legacy data byte is lock bits + data->settings.lock_bits = legacy_data[0]; + // The rest are block security + memcpy( + &legacy_data[1], + simple_array_get_data(data->block_security), + simple_array_get_count(data->block_security)); + + loaded = true; + } while(false); + + if(legacy_data) free(legacy_data); + + return loaded; +} + +static inline bool iso15693_3_load_security(Iso15693_3Data* data, FlipperFormat* ff) { + bool loaded = false; + + do { + uint32_t value_count; + if(!flipper_format_get_value_count(ff, ISO15693_3_SECURITY_STATUS_KEY, &value_count)) + break; + if(simple_array_get_count(data->block_security) != value_count) break; + if(!flipper_format_read_hex( + ff, + ISO15693_3_SECURITY_STATUS_KEY, + simple_array_get_data(data->block_security), + simple_array_get_count(data->block_security))) + break; + + loaded = true; + } while(false); + + return loaded; +} + +bool iso15693_3_load(Iso15693_3Data* data, FlipperFormat* ff, uint32_t version) { + furi_assert(data); + UNUSED(version); + + bool loaded = false; + + do { + if(flipper_format_key_exist(ff, ISO15693_3_DSFID_KEY)) { + if(!flipper_format_read_hex(ff, ISO15693_3_DSFID_KEY, &data->system_info.dsfid, 1)) + break; + data->system_info.flags |= ISO15693_3_SYSINFO_FLAG_DSFID; + } + + if(flipper_format_key_exist(ff, ISO15693_3_AFI_KEY)) { + if(!flipper_format_read_hex(ff, ISO15693_3_AFI_KEY, &data->system_info.afi, 1)) break; + data->system_info.flags |= ISO15693_3_SYSINFO_FLAG_AFI; + } + + if(flipper_format_key_exist(ff, ISO15693_3_IC_REF_KEY)) { + if(!flipper_format_read_hex(ff, ISO15693_3_IC_REF_KEY, &data->system_info.ic_ref, 1)) + break; + data->system_info.flags |= ISO15693_3_SYSINFO_FLAG_IC_REF; + } + + const bool has_lock_bits = flipper_format_key_exist(ff, ISO15693_3_LOCK_BITS_KEY); + if(has_lock_bits) { + if(!flipper_format_read_hex(ff, ISO15693_3_LOCK_BITS_KEY, &data->settings.lock_bits, 1)) + break; + } + + if(flipper_format_key_exist(ff, ISO15693_3_BLOCK_COUNT_KEY) && + flipper_format_key_exist(ff, ISO15693_3_BLOCK_SIZE_KEY)) { + uint32_t block_count; + if(!flipper_format_read_uint32(ff, ISO15693_3_BLOCK_COUNT_KEY, &block_count, 1)) break; + + data->system_info.block_count = block_count; + data->system_info.flags |= ISO15693_3_SYSINFO_FLAG_MEMORY; + + if(!flipper_format_read_hex( + ff, ISO15693_3_BLOCK_SIZE_KEY, &(data->system_info.block_size), 1)) + break; + + simple_array_init( + data->block_data, data->system_info.block_size * data->system_info.block_count); + + if(!flipper_format_read_hex( + ff, + ISO15693_3_DATA_CONTENT_KEY, + simple_array_get_data(data->block_data), + simple_array_get_count(data->block_data))) + break; + + if(flipper_format_key_exist(ff, ISO15693_3_SECURITY_STATUS_KEY)) { + simple_array_init(data->block_security, data->system_info.block_count); + + const bool security_loaded = has_lock_bits ? + iso15693_3_load_security(data, ff) : + iso15693_3_load_security_legacy(data, ff); + if(!security_loaded) break; + } + } + + loaded = true; + } while(false); + + return loaded; +} + +bool iso15693_3_save(const Iso15693_3Data* data, FlipperFormat* ff) { + furi_assert(data); + + bool saved = false; + + do { + if(data->system_info.flags & ISO15693_3_SYSINFO_FLAG_DSFID) { + if(!flipper_format_write_comment_cstr(ff, "Data Storage Format Identifier")) break; + if(!flipper_format_write_hex(ff, ISO15693_3_DSFID_KEY, &data->system_info.dsfid, 1)) + break; + } + + if(data->system_info.flags & ISO15693_3_SYSINFO_FLAG_AFI) { + if(!flipper_format_write_comment_cstr(ff, "Application Family Identifier")) break; + if(!flipper_format_write_hex(ff, ISO15693_3_AFI_KEY, &data->system_info.afi, 1)) break; + } + + if(data->system_info.flags & ISO15693_3_SYSINFO_FLAG_IC_REF) { + if(!flipper_format_write_comment_cstr(ff, "IC Reference - Vendor specific meaning")) + break; + if(!flipper_format_write_hex(ff, ISO15693_3_IC_REF_KEY, &data->system_info.ic_ref, 1)) + break; + } + + if(!flipper_format_write_comment_cstr(ff, "Lock Bits: 0x01 = DSFID, 0x02 = AFI")) break; + if(!flipper_format_write_hex(ff, ISO15693_3_LOCK_BITS_KEY, &data->settings.lock_bits, 1)) + break; + + if(data->system_info.flags & ISO15693_3_SYSINFO_FLAG_MEMORY) { + const uint32_t block_count = data->system_info.block_count; + if(!flipper_format_write_comment_cstr( + ff, "Number of memory blocks, valid range = 1..256")) + break; + if(!flipper_format_write_uint32(ff, ISO15693_3_BLOCK_COUNT_KEY, &block_count, 1)) + break; + + if(!flipper_format_write_comment_cstr(ff, "Size of a single memory block, usually 4")) + break; + if(!flipper_format_write_hex( + ff, ISO15693_3_BLOCK_SIZE_KEY, &data->system_info.block_size, 1)) + break; + + if(!flipper_format_write_hex( + ff, + ISO15693_3_DATA_CONTENT_KEY, + simple_array_cget_data(data->block_data), + simple_array_get_count(data->block_data))) + break; + + if(!flipper_format_write_comment_cstr( + ff, "Block Security Status: 0x01 = locked, 0x00 = not locked")) + break; + if(!flipper_format_write_hex( + ff, + ISO15693_3_SECURITY_STATUS_KEY, + simple_array_cget_data(data->block_security), + simple_array_get_count(data->block_security))) + break; + } + saved = true; + } while(false); + + return saved; +} + +bool iso15693_3_is_equal(const Iso15693_3Data* data, const Iso15693_3Data* other) { + furi_assert(data); + furi_assert(other); + + return memcmp(data->uid, other->uid, ISO15693_3_UID_SIZE) == 0 && + memcmp(&data->settings, &other->settings, sizeof(Iso15693_3Settings)) == 0 && + memcmp(&data->system_info, &other->system_info, sizeof(Iso15693_3SystemInfo)) == 0 && + simple_array_is_equal(data->block_data, other->block_data) && + simple_array_is_equal(data->block_security, other->block_security); +} + +const char* iso15693_3_get_device_name(const Iso15693_3Data* data, NfcDeviceNameType name_type) { + UNUSED(data); + UNUSED(name_type); + + return ISO15693_3_DEVICE_NAME; +} + +const uint8_t* iso15693_3_get_uid(const Iso15693_3Data* data, size_t* uid_len) { + furi_assert(data); + + if(uid_len) *uid_len = ISO15693_3_UID_SIZE; + return data->uid; +} + +bool iso15693_3_set_uid(Iso15693_3Data* data, const uint8_t* uid, size_t uid_len) { + furi_assert(data); + furi_assert(uid); + + bool uid_valid = uid_len == ISO15693_3_UID_SIZE; + + if(uid_valid) { + memcpy(data->uid, uid, uid_len); + } + + return uid_valid; +} + +const Iso15693_3Data* iso15693_3_get_base_data(const Iso15693_3Data* data) { + UNUSED(data); + furi_crash("No base data"); +} diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3.h b/lib/nfc/protocols/iso15693_3/iso15693_3.h new file mode 100644 index 000000000000..5d11d881db0c --- /dev/null +++ b/lib/nfc/protocols/iso15693_3/iso15693_3.h @@ -0,0 +1,156 @@ +#pragma once + +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define ISO15693_3_UID_SIZE (8U) + +#define ISO15693_3_GUARD_TIME_US (5000U) +#define ISO15693_3_FDT_POLL_FC (4202U) +#define ISO15693_3_POLL_POLL_MIN_US (1500U) + +/* true: modulating releases load, false: modulating adds load resistor to field coil */ +#define ISO15693_3_LOAD_MODULATION_POLARITY (false) + +#define ISO15693_3_FC (13560000.0f) /* MHz */ +#define ISO15693_3_RESP_SUBC1_PULSE_32 (1.0f / (ISO15693_3_FC / 32) / 2.0f) /* 1.1799 µs */ +#define ISO15693_3_RESP_SUBC1_UNMOD_256 (256.0f / ISO15693_3_FC) /* 18.8791 µs */ +#define ISO15693_3_PULSE_DURATION_NS (128.0f * 1000000000.0f / ISO15693_3_FC) + +/* ISO/IEC 15693-3:2019(E) 10.4.12: maximum number of blocks is defined as 256 */ +#define ISO15693_3_BLOCKS_MAX 256 +/* ISO/IEC 15693-3:2019(E) 10.4.12: maximum size of blocks is defined as 32 */ +#define ISO15693_3_BLOCKSIZE_MAX 32 +/* the resulting memory size a card can have */ +#define ISO15693_3_MEMSIZE_MAX (ISO15693_3_BLOCKS_MAX * ISO15693_3_BLOCKSIZE_MAX) +/* ISO/IEC 15693-3:2019(E) 7.1b: standard allows up to 8192, the maxium frame length that we are expected to receive/send is less */ +#define ISO15693_3_FRAMESIZE_MAX (1 + ISO15693_3_MEMSIZE_MAX + ISO15693_3_BLOCKS_MAX) + +#define ISO15693_3_REQ_FLAG_SUBCARRIER_1 (0U << 0) +#define ISO15693_3_REQ_FLAG_SUBCARRIER_2 (1U << 0) +#define ISO15693_3_REQ_FLAG_DATA_RATE_LO (0U << 1) +#define ISO15693_3_REQ_FLAG_DATA_RATE_HI (1U << 1) +#define ISO15693_3_REQ_FLAG_INVENTORY_T4 (0U << 2) +#define ISO15693_3_REQ_FLAG_INVENTORY_T5 (1U << 2) +#define ISO15693_3_REQ_FLAG_EXTENSION (1U << 3) + +#define ISO15693_3_REQ_FLAG_T4_SELECTED (1U << 4) +#define ISO15693_3_REQ_FLAG_T4_ADDRESSED (1U << 5) +#define ISO15693_3_REQ_FLAG_T4_CUSTOM (1U << 6) + +#define ISO15693_3_REQ_FLAG_T5_AFI_PRESENT (1U << 4) +#define ISO15693_3_REQ_FLAG_T5_N_SLOTS_16 (0U << 5) +#define ISO15693_3_REQ_FLAG_T5_N_SLOTS_1 (1U << 5) +#define ISO15693_3_REQ_FLAG_T5_CUSTOM (1U << 6) + +#define ISO15693_3_RESP_FLAG_ERROR (1U << 0) +#define ISO15693_3_RESP_FLAG_EXTENSION (1U << 3) + +#define ISO15693_3_RESP_ERROR_NOT_SUPPORTED (0x01U) +#define ISO15693_3_RESP_ERROR_FORMAT (0x02U) +#define ISO15693_3_RESP_ERROR_OPTION (0x03U) +#define ISO15693_3_RESP_ERROR_UNKNOWN (0x0FU) +#define ISO15693_3_RESP_ERROR_BLOCK_UNAVAILABLE (0x10U) +#define ISO15693_3_RESP_ERROR_BLOCK_ALREADY_LOCKED (0x11U) +#define ISO15693_3_RESP_ERROR_BLOCK_LOCKED (0x12U) +#define ISO15693_3_RESP_ERROR_BLOCK_WRITE (0x13U) +#define ISO15693_3_RESP_ERROR_BLOCK_LOCK (0x14U) +#define ISO15693_3_RESP_ERROR_CUSTOM_START (0xA0U) +#define ISO15693_3_RESP_ERROR_CUSTOM_END (0xDFU) + +#define ISO15693_3_CMD_INVENTORY (0x01U) +#define ISO15693_3_CMD_STAY_QUIET (0x02U) +#define ISO15693_3_CMD_READ_BLOCK (0x20U) +#define ISO15693_3_CMD_WRITE_BLOCK (0x21U) +#define ISO15693_3_CMD_LOCK_BLOCK (0x22U) +#define ISO15693_3_CMD_READ_BLOCKS (0x23U) +#define ISO15693_3_CMD_WRITE_BLOCKS (0x24U) +#define ISO15693_3_CMD_SELECT (0x25U) +#define ISO15693_3_CMD_RESET_TO_READY (0x26U) +#define ISO15693_3_CMD_WRITE_AFI (0x27U) +#define ISO15693_3_CMD_LOCK_AFI (0x28U) +#define ISO15693_3_CMD_WRITE_DSFID (0x29U) +#define ISO15693_3_CMD_LOCK_DSFID (0x2AU) +#define ISO15693_3_CMD_GET_SYS_INFO (0x2BU) +#define ISO15693_3_CMD_GET_BLOCKS_SECURITY (0x2CU) + +#define ISO15693_3_SYSINFO_FLAG_DSFID (1U << 0) +#define ISO15693_3_SYSINFO_FLAG_AFI (1U << 1) +#define ISO15693_3_SYSINFO_FLAG_MEMORY (1U << 2) +#define ISO15693_3_SYSINFO_FLAG_IC_REF (1U << 3) + +#define ISO15693_3_SYSINFO_LOCK_DSFID (1U << 0) +#define ISO15693_3_SYSINFO_LOCK_AFI (1U << 1) + +typedef enum { + Iso15693_3ErrorNone, + Iso15693_3ErrorNotPresent, + Iso15693_3ErrorBufferEmpty, + Iso15693_3ErrorBufferOverflow, + Iso15693_3ErrorFraming, + Iso15693_3ErrorFieldOff, + Iso15693_3ErrorWrongCrc, + Iso15693_3ErrorTimeout, + Iso15693_3ErrorFormat, + Iso15693_3ErrorNotSupported, + Iso15693_3ErrorUnexpectedResponse, + Iso15693_3ErrorInternal, + Iso15693_3ErrorCustom, + Iso15693_3ErrorUnknown, +} Iso15693_3Error; + +typedef struct { + uint8_t flags; + uint8_t dsfid; + uint8_t afi; + uint8_t ic_ref; + uint16_t block_count; + uint8_t block_size; +} Iso15693_3SystemInfo; + +typedef struct { + uint8_t lock_bits; +} Iso15693_3Settings; + +typedef struct { + uint8_t uid[ISO15693_3_UID_SIZE]; + Iso15693_3SystemInfo system_info; + Iso15693_3Settings settings; + SimpleArray* block_data; + SimpleArray* block_security; +} Iso15693_3Data; + +Iso15693_3Data* iso15693_3_alloc(); + +void iso15693_3_free(Iso15693_3Data* data); + +void iso15693_3_reset(Iso15693_3Data* data); + +void iso15693_3_copy(Iso15693_3Data* data, const Iso15693_3Data* other); + +bool iso15693_3_verify(Iso15693_3Data* data, const FuriString* device_type); + +bool iso15693_3_load(Iso15693_3Data* data, FlipperFormat* ff, uint32_t version); + +bool iso15693_3_save(const Iso15693_3Data* data, FlipperFormat* ff); + +bool iso15693_3_is_equal(const Iso15693_3Data* data, const Iso15693_3Data* other); + +const char* iso15693_3_get_device_name(const Iso15693_3Data* data, NfcDeviceNameType name_type); + +const uint8_t* iso15693_3_get_uid(const Iso15693_3Data* data, size_t* uid_len); + +bool iso15693_3_set_uid(Iso15693_3Data* data, const uint8_t* uid, size_t uid_len); + +const Iso15693_3Data* iso15693_3_get_base_data(const Iso15693_3Data* data); + +extern const NfcDeviceBase nfc_device_iso15693_3; + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3_i.c b/lib/nfc/protocols/iso15693_3/iso15693_3_i.c new file mode 100644 index 000000000000..1f3b1352fea4 --- /dev/null +++ b/lib/nfc/protocols/iso15693_3/iso15693_3_i.c @@ -0,0 +1,212 @@ +#include "iso15693_3_i.h" + +bool iso15693_3_error_response_parse(Iso15693_3Error* error, const BitBuffer* buf) { + furi_assert(error); + + if(bit_buffer_get_size_bytes(buf) == 0) { + // YEET! + *error = Iso15693_3ErrorBufferEmpty; + return true; + } + + typedef struct { + uint8_t flags; + uint8_t error; + } ErrorResponseLayout; + + const ErrorResponseLayout* resp = (const ErrorResponseLayout*)bit_buffer_get_data(buf); + + if((resp->flags & ISO15693_3_RESP_FLAG_ERROR) == 0) { + // No error flag is set, the data does not contain an error frame + return false; + } else if(bit_buffer_get_size_bytes(buf) < sizeof(ErrorResponseLayout)) { + // Error bit is set, but not enough data to determine the error + *error = Iso15693_3ErrorUnexpectedResponse; + return true; + } else if( + resp->error >= ISO15693_3_RESP_ERROR_CUSTOM_START && + resp->error <= ISO15693_3_RESP_ERROR_CUSTOM_END) { + // Custom vendor-specific error, must be checked in the respective protocol implementation + *error = Iso15693_3ErrorCustom; + return true; + } + + switch(resp->error) { + case ISO15693_3_RESP_ERROR_NOT_SUPPORTED: + case ISO15693_3_RESP_ERROR_OPTION: + *error = Iso15693_3ErrorNotSupported; + break; + case ISO15693_3_RESP_ERROR_FORMAT: + *error = Iso15693_3ErrorFormat; + break; + case ISO15693_3_RESP_ERROR_BLOCK_UNAVAILABLE: + case ISO15693_3_RESP_ERROR_BLOCK_ALREADY_LOCKED: + case ISO15693_3_RESP_ERROR_BLOCK_LOCKED: + case ISO15693_3_RESP_ERROR_BLOCK_WRITE: + case ISO15693_3_RESP_ERROR_BLOCK_LOCK: + *error = Iso15693_3ErrorInternal; + break; + case ISO15693_3_RESP_ERROR_UNKNOWN: + default: + *error = Iso15693_3ErrorUnknown; + } + + return true; +} + +Iso15693_3Error iso15693_3_inventory_response_parse(uint8_t* data, const BitBuffer* buf) { + furi_assert(data); + + Iso15693_3Error ret = Iso15693_3ErrorNone; + + do { + if(iso15693_3_error_response_parse(&ret, buf)) break; + + typedef struct { + uint8_t flags; + uint8_t dsfid; + uint8_t uid[ISO15693_3_UID_SIZE]; + } InventoryResponseLayout; + + if(bit_buffer_get_size_bytes(buf) != sizeof(InventoryResponseLayout)) { + ret = Iso15693_3ErrorUnexpectedResponse; + break; + } + + const InventoryResponseLayout* resp = + (const InventoryResponseLayout*)bit_buffer_get_data(buf); + // Reverse UID for backward compatibility + for(uint32_t i = 0; i < ISO15693_3_UID_SIZE; ++i) { + data[i] = resp->uid[ISO15693_3_UID_SIZE - i - 1]; + } + + } while(false); + + return ret; +} + +Iso15693_3Error + iso15693_3_system_info_response_parse(Iso15693_3SystemInfo* data, const BitBuffer* buf) { + furi_assert(data); + + Iso15693_3Error ret = Iso15693_3ErrorNone; + + do { + if(iso15693_3_error_response_parse(&ret, buf)) break; + + typedef struct { + uint8_t flags; + uint8_t info_flags; + uint8_t uid[ISO15693_3_UID_SIZE]; + uint8_t extra[]; + } SystemInfoResponseLayout; + + if(bit_buffer_get_size_bytes(buf) < sizeof(SystemInfoResponseLayout)) { + ret = Iso15693_3ErrorUnexpectedResponse; + break; + } + + const SystemInfoResponseLayout* resp = + (const SystemInfoResponseLayout*)bit_buffer_get_data(buf); + + const uint8_t* extra = resp->extra; + const size_t extra_size = (resp->info_flags & ISO15693_3_SYSINFO_FLAG_DSFID ? 1 : 0) + + (resp->info_flags & ISO15693_3_SYSINFO_FLAG_AFI ? 1 : 0) + + (resp->info_flags & ISO15693_3_SYSINFO_FLAG_MEMORY ? 2 : 0) + + (resp->info_flags & ISO15693_3_SYSINFO_FLAG_IC_REF ? 1 : 0); + + if(extra_size != bit_buffer_get_size_bytes(buf) - sizeof(SystemInfoResponseLayout)) { + ret = Iso15693_3ErrorUnexpectedResponse; + break; + } + + data->flags = resp->info_flags; + + if(data->flags & ISO15693_3_SYSINFO_FLAG_DSFID) { + data->dsfid = *extra++; + } + + if(data->flags & ISO15693_3_SYSINFO_FLAG_AFI) { + data->afi = *extra++; + } + + if(data->flags & ISO15693_3_SYSINFO_FLAG_MEMORY) { + // Add 1 to get actual values + data->block_count = *extra++ + 1; + data->block_size = (*extra++ & 0x1F) + 1; + } + + if(data->flags & ISO15693_3_SYSINFO_FLAG_IC_REF) { + data->ic_ref = *extra; + } + + } while(false); + + return ret; +} + +Iso15693_3Error + iso15693_3_read_block_response_parse(uint8_t* data, uint8_t block_size, const BitBuffer* buf) { + furi_assert(data); + + Iso15693_3Error ret = Iso15693_3ErrorNone; + + do { + if(iso15693_3_error_response_parse(&ret, buf)) break; + + typedef struct { + uint8_t flags; + uint8_t block_data[]; + } ReadBlockResponseLayout; + + const size_t buf_size = bit_buffer_get_size_bytes(buf); + const size_t received_block_size = buf_size - sizeof(ReadBlockResponseLayout); + + if(buf_size <= sizeof(ReadBlockResponseLayout) || received_block_size != block_size) { + ret = Iso15693_3ErrorUnexpectedResponse; + break; + } + + const ReadBlockResponseLayout* resp = + (const ReadBlockResponseLayout*)bit_buffer_get_data(buf); + memcpy(data, resp->block_data, received_block_size); + + } while(false); + + return ret; +} + +Iso15693_3Error iso15693_3_get_block_security_response_parse( + uint8_t* data, + uint16_t block_count, + const BitBuffer* buf) { + furi_assert(data); + furi_assert(block_count); + Iso15693_3Error ret = Iso15693_3ErrorNone; + + do { + if(iso15693_3_error_response_parse(&ret, buf)) break; + + typedef struct { + uint8_t flags; + uint8_t block_security[]; + } GetBlockSecurityResponseLayout; + + const size_t buf_size = bit_buffer_get_size_bytes(buf); + const size_t received_block_count = buf_size - sizeof(GetBlockSecurityResponseLayout); + + if(buf_size <= sizeof(GetBlockSecurityResponseLayout) || + received_block_count != block_count) { + ret = Iso15693_3ErrorUnexpectedResponse; + break; + } + + const GetBlockSecurityResponseLayout* resp = + (const GetBlockSecurityResponseLayout*)bit_buffer_get_data(buf); + + memcpy(data, resp->block_security, received_block_count); + + } while(false); + + return ret; +} diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3_i.h b/lib/nfc/protocols/iso15693_3/iso15693_3_i.h new file mode 100644 index 000000000000..4cab9199a807 --- /dev/null +++ b/lib/nfc/protocols/iso15693_3/iso15693_3_i.h @@ -0,0 +1,38 @@ +#pragma once + +#include "iso15693_3.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Check if the buffer contains an error frame and if it does, determine + * the error type. + * NOTE: No changes are done to the result if no error is present. + * + * @param [out] data Pointer to the resulting error value. + * @param [in] buf Data buffer to be checked + * + * @return True if data contains an error frame or is empty, false otherwise + */ +bool iso15693_3_error_response_parse(Iso15693_3Error* error, const BitBuffer* buf); + +Iso15693_3Error iso15693_3_inventory_response_parse(uint8_t* data, const BitBuffer* buf); + +Iso15693_3Error + iso15693_3_system_info_response_parse(Iso15693_3SystemInfo* data, const BitBuffer* buf); + +Iso15693_3Error + iso15693_3_read_block_response_parse(uint8_t* data, uint8_t block_size, const BitBuffer* buf); + +Iso15693_3Error iso15693_3_get_block_security_response_parse( + uint8_t* data, + uint16_t block_count, + const BitBuffer* buf); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3_listener.c b/lib/nfc/protocols/iso15693_3/iso15693_3_listener.c new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3_listener.h b/lib/nfc/protocols/iso15693_3/iso15693_3_listener.h new file mode 100644 index 000000000000..cd74574a9381 --- /dev/null +++ b/lib/nfc/protocols/iso15693_3/iso15693_3_listener.h @@ -0,0 +1,9 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3_listener_defs.h b/lib/nfc/protocols/iso15693_3/iso15693_3_listener_defs.h new file mode 100644 index 000000000000..cd74574a9381 --- /dev/null +++ b/lib/nfc/protocols/iso15693_3/iso15693_3_listener_defs.h @@ -0,0 +1,9 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3_listener_i.c b/lib/nfc/protocols/iso15693_3/iso15693_3_listener_i.c new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3_listener_i.h b/lib/nfc/protocols/iso15693_3/iso15693_3_listener_i.h new file mode 100644 index 000000000000..cd74574a9381 --- /dev/null +++ b/lib/nfc/protocols/iso15693_3/iso15693_3_listener_i.h @@ -0,0 +1,9 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3_poller.c b/lib/nfc/protocols/iso15693_3/iso15693_3_poller.c new file mode 100644 index 000000000000..ce4b084c72da --- /dev/null +++ b/lib/nfc/protocols/iso15693_3/iso15693_3_poller.c @@ -0,0 +1,130 @@ +#include "iso15693_3_poller_i.h" + +#include + +#include + +#define TAG "ISO15693_3Poller" + +const Iso15693_3Data* iso15693_3_poller_get_data(Iso15693_3Poller* instance) { + furi_assert(instance); + furi_assert(instance->data); + + return instance->data; +} + +static Iso15693_3Poller* iso15693_3_poller_alloc(Nfc* nfc) { + furi_assert(nfc); + + Iso15693_3Poller* instance = malloc(sizeof(Iso15693_3Poller)); + instance->nfc = nfc; + instance->tx_buffer = bit_buffer_alloc(ISO15693_3_POLLER_MAX_BUFFER_SIZE); + instance->rx_buffer = bit_buffer_alloc(ISO15693_3_POLLER_MAX_BUFFER_SIZE); + // 4 bits per data bit on transmit + instance->tx_frame_buffer = bit_buffer_alloc(ISO15693_3_POLLER_MAX_BUFFER_SIZE * 4); + // 2 bits per data bit on receive + instance->rx_frame_buffer = bit_buffer_alloc(ISO15693_3_POLLER_MAX_BUFFER_SIZE * 2); + + nfc_config(instance->nfc, NfcModeIso15693Poller); + nfc_set_guard_time_us(instance->nfc, ISO15693_3_GUARD_TIME_US); + nfc_set_fdt_poll_fc(instance->nfc, ISO15693_3_FDT_POLL_FC); + nfc_set_fdt_poll_poll_us(instance->nfc, ISO15693_3_POLL_POLL_MIN_US); + instance->data = iso15693_3_alloc(); + + instance->iso15693_3_event.data = &instance->iso15693_3_event_data; + instance->general_event.protocol = NfcProtocolIso15693_3; + instance->general_event.data = &instance->iso15693_3_event; + instance->general_event.instance = instance; + + return instance; +} + +static void iso15693_3_poller_free(Iso15693_3Poller* instance) { + furi_assert(instance); + + furi_assert(instance->tx_buffer); + furi_assert(instance->rx_buffer); + furi_assert(instance->tx_frame_buffer); + furi_assert(instance->rx_frame_buffer); + furi_assert(instance->data); + + bit_buffer_free(instance->tx_buffer); + bit_buffer_free(instance->rx_buffer); + bit_buffer_free(instance->tx_frame_buffer); + bit_buffer_free(instance->rx_frame_buffer); + iso15693_3_free(instance->data); + free(instance); +} + +static void iso15693_3_poller_set_callback( + Iso15693_3Poller* instance, + NfcGenericCallback callback, + void* context) { + furi_assert(instance); + furi_assert(callback); + + instance->callback = callback; + instance->context = context; +} + +static NfcCommand iso15693_3_poller_run(NfcGenericEvent event, void* context) { + furi_assert(context); + furi_assert(event.protocol == NfcProtocolInvalid); + furi_assert(event.data); + + Iso15693_3Poller* instance = context; + NfcEvent* nfc_event = event.data; + NfcCommand command = NfcCommandContinue; + + if(nfc_event->type == NfcEventTypePollerReady) { + if(instance->state != Iso15693_3PollerStateActivated) { + Iso15693_3Error error = iso15693_3_poller_async_activate(instance, instance->data); + if(error == Iso15693_3ErrorNone) { + instance->iso15693_3_event.type = Iso15693_3PollerEventTypeReady; + instance->iso15693_3_event_data.error = error; + command = instance->callback(instance->general_event, instance->context); + } else { + instance->iso15693_3_event.type = Iso15693_3PollerEventTypeError; + instance->iso15693_3_event_data.error = error; + command = instance->callback(instance->general_event, instance->context); + // Add delay to switch context + furi_delay_ms(100); + } + } else { + instance->iso15693_3_event.type = Iso15693_3PollerEventTypeReady; + instance->iso15693_3_event_data.error = Iso15693_3ErrorNone; + command = instance->callback(instance->general_event, instance->context); + } + } + + return command; +} + +static bool iso15693_3_poller_detect(NfcGenericEvent event, void* context) { + furi_assert(context); + furi_assert(event.data); + furi_assert(event.instance); + furi_assert(event.protocol = NfcProtocolInvalid); + + bool protocol_detected = false; + Iso15693_3Poller* instance = context; + NfcEvent* nfc_event = event.data; + furi_assert(instance->state == Iso15693_3PollerStateIdle); + + if(nfc_event->type == NfcEventTypePollerReady) { + uint8_t uid[ISO15693_3_UID_SIZE]; + Iso15693_3Error error = iso15693_3_poller_async_inventory(instance, uid); + protocol_detected = (error == Iso15693_3ErrorNone); + } + + return protocol_detected; +} + +const NfcPollerBase nfc_poller_iso15693_3 = { + .alloc = (NfcPollerAlloc)iso15693_3_poller_alloc, + .free = (NfcPollerFree)iso15693_3_poller_free, + .set_callback = (NfcPollerSetCallback)iso15693_3_poller_set_callback, + .run = (NfcPollerRun)iso15693_3_poller_run, + .detect = (NfcPollerDetect)iso15693_3_poller_detect, + .get_data = (NfcPollerGetData)iso15693_3_poller_get_data, +}; diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3_poller.h b/lib/nfc/protocols/iso15693_3/iso15693_3_poller.h new file mode 100644 index 000000000000..9d73242f1ad5 --- /dev/null +++ b/lib/nfc/protocols/iso15693_3/iso15693_3_poller.h @@ -0,0 +1,29 @@ +#pragma once + +#include "iso15693_3.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct Iso15693_3Poller Iso15693_3Poller; + +typedef enum { + Iso15693_3PollerEventTypeError, + Iso15693_3PollerEventTypeReady, +} Iso15693_3PollerEventType; + +typedef struct { + Iso15693_3Error error; +} Iso15693_3PollerEventData; + +typedef struct { + Iso15693_3PollerEventType type; + Iso15693_3PollerEventData* data; +} Iso15693_3PollerEvent; + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3_poller_defs.h b/lib/nfc/protocols/iso15693_3/iso15693_3_poller_defs.h new file mode 100644 index 000000000000..0e38908dab1b --- /dev/null +++ b/lib/nfc/protocols/iso15693_3/iso15693_3_poller_defs.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern const NfcPollerBase nfc_poller_iso15693_3; + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3_poller_i.c b/lib/nfc/protocols/iso15693_3/iso15693_3_poller_i.c new file mode 100644 index 000000000000..12aff5759918 --- /dev/null +++ b/lib/nfc/protocols/iso15693_3/iso15693_3_poller_i.c @@ -0,0 +1,380 @@ +#include "iso15693_3_poller_i.h" + +#include + +#define TAG "Iso15693_3Poller" + +#define BITS_IN_BYTE (8) + +#define ISO15693_RESP_SOF_SIZE (5) +#define ISO15693_RESP_EOF_SIZE (5) +#define ISO15693_RESP_SOF_MASK (0x1FU) +#define ISO15693_RESP_SOF_PATTERN (0x17U) +#define ISO15693_RESP_EOF_PATTERN (0x1DU) + +#define ISO15693_RESP_PATTERN_MASK (0x03U) +#define ISO15693_RESP_PATTERN_0 (0x01U) +#define ISO15693_RESP_PATTERN_1 (0x02U) + +#define ISO15693_3_POLLER_NUM_BLOCKS_PER_QUERY (32U) + +static Iso15693_3Error iso15693_3_poller_process_nfc_error(NfcError error) { + switch(error) { + case NfcErrorNone: + return Iso15693_3ErrorNone; + case NfcErrorTimeout: + return Iso15693_3ErrorTimeout; + default: + return Iso15693_3ErrorNotPresent; + } +} + +static Iso15693_3Error iso15693_3_poller_filter_error(Iso15693_3Error error) { + switch(error) { + /* If a particular optional command is not supported, the card might + * respond with a "Not supported" error or not respond at all. + * Therefore, treat these errors as non-critical ones. */ + case Iso15693_3ErrorNotSupported: + case Iso15693_3ErrorTimeout: + return Iso15693_3ErrorNone; + default: + return error; + } +} + +static Iso15693_3Error iso15693_3_poller_prepare_trx(Iso15693_3Poller* instance) { + furi_assert(instance); + + if(instance->state == Iso15693_3PollerStateIdle) { + return iso15693_3_poller_async_activate(instance, NULL); + } + + return Iso15693_3ErrorNone; +} + +static void iso15693_3_poller_encode_byte(uint8_t data, BitBuffer* out) { + static const uint8_t bit_patterns_1_out_of_4[] = {0x02, 0x08, 0x20, 0x80}; + + for(uint32_t i = 0; i < BITS_IN_BYTE; i += (BITS_IN_BYTE) / 4) { + const uint8_t bit_pair = (data >> i) & 0x03; + bit_buffer_append_byte(out, bit_patterns_1_out_of_4[bit_pair]); + } +} + +static void iso15693_3_poller_encode_frame(const BitBuffer* data, BitBuffer* frame_data) { + bit_buffer_append_byte(frame_data, 0x21); // Add SOF 1 out of 4 + + for(size_t i = 0; i < bit_buffer_get_size_bytes(data); ++i) { + iso15693_3_poller_encode_byte(bit_buffer_get_byte(data, i), frame_data); + } + + bit_buffer_append_byte(frame_data, 0x04); // Add EOF +} + +static bool iso15693_3_poller_decode_frame(BitBuffer* data, const BitBuffer* frame_data) { + bool decoded = false; + + do { + if(bit_buffer_get_size(frame_data) == 0) break; + // Check SOF + if((bit_buffer_get_byte(frame_data, 0) & ISO15693_RESP_SOF_MASK) != + ISO15693_RESP_SOF_PATTERN) + break; + + // 2 response bits = 1 data bit + for(uint32_t i = ISO15693_RESP_SOF_SIZE; + i < bit_buffer_get_size(frame_data) - ISO15693_RESP_SOF_SIZE; + i += BITS_IN_BYTE / 4) { + const uint8_t resp_byte = bit_buffer_get_byte_from_bit(frame_data, i); + + // Check EOF + if(resp_byte == ISO15693_RESP_EOF_PATTERN) { + decoded = true; + break; + } + + const uint8_t bit_pattern = resp_byte & ISO15693_RESP_PATTERN_MASK; + + if(bit_pattern == ISO15693_RESP_PATTERN_0) { + bit_buffer_append_bit(data, false); + } else if(bit_pattern == ISO15693_RESP_PATTERN_1) { + bit_buffer_append_bit(data, true); + } else { + break; + } + } + + } while(false); + + return decoded; +} + +static Iso15693_3Error iso15693_3_poller_frame_exchange( + Iso15693_3Poller* instance, + const BitBuffer* tx_buffer, + BitBuffer* rx_buffer, + uint32_t fwt) { + furi_assert(instance); + + Iso15693_3Error ret = Iso15693_3ErrorNone; + + do { + if(bit_buffer_get_size_bytes(tx_buffer) > + bit_buffer_get_capacity_bytes(instance->tx_buffer) - ISO13239_CRC_SIZE) { + ret = Iso15693_3ErrorBufferOverflow; + break; + } + + bit_buffer_copy(instance->tx_buffer, tx_buffer); + iso13239_crc_append(Iso13239CrcTypeDefault, instance->tx_buffer); + + bit_buffer_reset(instance->tx_frame_buffer); + bit_buffer_reset(instance->rx_frame_buffer); + + iso15693_3_poller_encode_frame(instance->tx_buffer, instance->tx_frame_buffer); + + NfcError error = + nfc_trx(instance->nfc, instance->tx_frame_buffer, instance->rx_frame_buffer, fwt); + if(error != NfcErrorNone) { + ret = iso15693_3_poller_process_nfc_error(error); + break; + } + + if(!iso15693_3_poller_decode_frame(instance->rx_buffer, instance->rx_frame_buffer)) { + ret = Iso15693_3ErrorFraming; + break; + } + + if(!iso13239_crc_check(Iso13239CrcTypeDefault, instance->rx_buffer)) { + ret = Iso15693_3ErrorWrongCrc; + break; + } + + iso13239_crc_trim(instance->rx_buffer); + bit_buffer_copy(rx_buffer, instance->rx_buffer); + } while(false); + + return ret; +} + +Iso15693_3Error + iso15693_3_poller_async_activate(Iso15693_3Poller* instance, Iso15693_3Data* data) { + furi_assert(instance); + furi_assert(instance->nfc); + + iso15693_3_reset(data); + + Iso15693_3Error ret; + + do { + instance->state = Iso15693_3PollerStateColResInProgress; + + // Inventory: Mandatory command + ret = iso15693_3_poller_async_inventory(instance, data->uid); + if(ret != Iso15693_3ErrorNone) { + instance->state = Iso15693_3PollerStateColResFailed; + break; + } + + instance->state = Iso15693_3PollerStateActivated; + + // Get system info: Optional command + Iso15693_3SystemInfo* system_info = &data->system_info; + ret = iso15693_3_poller_async_get_system_info(instance, system_info); + if(ret != Iso15693_3ErrorNone) { + ret = iso15693_3_poller_filter_error(ret); + break; + } + + // Read blocks: Optional command + simple_array_init(data->block_data, system_info->block_count * system_info->block_size); + ret = iso15693_3_poller_async_read_blocks( + instance, + simple_array_get_data(data->block_data), + system_info->block_count, + system_info->block_size); + if(ret != Iso15693_3ErrorNone) { + ret = iso15693_3_poller_filter_error(ret); + break; + } + + // Get block security status: Optional command + simple_array_init(data->block_security, system_info->block_count); + + ret = iso15693_3_poller_async_get_blocks_security( + instance, simple_array_get_data(data->block_security), system_info->block_count); + if(ret != Iso15693_3ErrorNone) { + ret = iso15693_3_poller_filter_error(ret); + break; + } + + } while(false); + + return ret; +} + +Iso15693_3Error iso15693_3_poller_async_inventory(Iso15693_3Poller* instance, uint8_t* uid) { + furi_assert(instance); + furi_assert(instance->nfc); + furi_assert(uid); + + bit_buffer_reset(instance->tx_buffer); + bit_buffer_reset(instance->rx_buffer); + + // Send INVENTORY + bit_buffer_append_byte( + instance->tx_buffer, + ISO15693_3_REQ_FLAG_SUBCARRIER_1 | ISO15693_3_REQ_FLAG_DATA_RATE_HI | + ISO15693_3_REQ_FLAG_INVENTORY_T5 | ISO15693_3_REQ_FLAG_T5_N_SLOTS_1); + bit_buffer_append_byte(instance->tx_buffer, ISO15693_3_CMD_INVENTORY); + bit_buffer_append_byte(instance->tx_buffer, 0x00); + + Iso15693_3Error ret; + + do { + ret = iso15693_3_poller_frame_exchange( + instance, instance->tx_buffer, instance->rx_buffer, ISO15693_3_FDT_POLL_FC); + if(ret != Iso15693_3ErrorNone) break; + + ret = iso15693_3_inventory_response_parse(uid, instance->rx_buffer); + } while(false); + + return ret; +} + +Iso15693_3Error iso15693_3_poller_async_get_system_info( + Iso15693_3Poller* instance, + Iso15693_3SystemInfo* data) { + furi_assert(instance); + furi_assert(data); + + bit_buffer_reset(instance->tx_buffer); + bit_buffer_reset(instance->rx_buffer); + + // Send GET SYSTEM INFO + bit_buffer_append_byte( + instance->tx_buffer, ISO15693_3_REQ_FLAG_SUBCARRIER_1 | ISO15693_3_REQ_FLAG_DATA_RATE_HI); + + bit_buffer_append_byte(instance->tx_buffer, ISO15693_3_CMD_GET_SYS_INFO); + + Iso15693_3Error ret; + + do { + ret = iso15693_3_poller_frame_exchange( + instance, instance->tx_buffer, instance->rx_buffer, ISO15693_3_FDT_POLL_FC); + if(ret != Iso15693_3ErrorNone) break; + + ret = iso15693_3_system_info_response_parse(data, instance->rx_buffer); + } while(false); + + return ret; +} + +Iso15693_3Error iso15693_3_poller_async_read_block( + Iso15693_3Poller* instance, + uint8_t* data, + uint8_t block_number, + uint8_t block_size) { + furi_assert(instance); + furi_assert(data); + + bit_buffer_reset(instance->tx_buffer); + bit_buffer_reset(instance->rx_buffer); + + bit_buffer_append_byte( + instance->tx_buffer, ISO15693_3_REQ_FLAG_SUBCARRIER_1 | ISO15693_3_REQ_FLAG_DATA_RATE_HI); + bit_buffer_append_byte(instance->tx_buffer, ISO15693_3_CMD_READ_BLOCK); + bit_buffer_append_byte(instance->tx_buffer, block_number); + + Iso15693_3Error ret; + + do { + ret = iso15693_3_poller_send_frame( + instance, instance->tx_buffer, instance->rx_buffer, ISO15693_3_FDT_POLL_FC); + if(ret != Iso15693_3ErrorNone) break; + + ret = iso15693_3_read_block_response_parse(data, block_size, instance->rx_buffer); + } while(false); + + return ret; +} + +Iso15693_3Error iso15693_3_poller_async_read_blocks( + Iso15693_3Poller* instance, + uint8_t* data, + uint16_t block_count, + uint8_t block_size) { + furi_assert(instance); + furi_assert(data); + furi_assert(block_count); + furi_assert(block_size); + + Iso15693_3Error ret = Iso15693_3ErrorNone; + + for(uint32_t i = 0; i < block_count; ++i) { + ret = iso15693_3_poller_async_read_block(instance, &data[block_size * i], i, block_size); + if(ret != Iso15693_3ErrorNone) break; + } + + return ret; +} + +Iso15693_3Error iso15693_3_poller_async_get_blocks_security( + Iso15693_3Poller* instance, + uint8_t* data, + uint16_t block_count) { + furi_assert(instance); + furi_assert(data); + + // Limit the number of blocks to 32 in a single query + const uint32_t num_queries = block_count / ISO15693_3_POLLER_NUM_BLOCKS_PER_QUERY + + (block_count % ISO15693_3_POLLER_NUM_BLOCKS_PER_QUERY ? 1 : 0); + + Iso15693_3Error ret = Iso15693_3ErrorNone; + + for(uint32_t i = 0; i < num_queries; ++i) { + bit_buffer_reset(instance->tx_buffer); + bit_buffer_reset(instance->rx_buffer); + + bit_buffer_append_byte( + instance->tx_buffer, + ISO15693_3_REQ_FLAG_SUBCARRIER_1 | ISO15693_3_REQ_FLAG_DATA_RATE_HI); + + bit_buffer_append_byte(instance->tx_buffer, ISO15693_3_CMD_GET_BLOCKS_SECURITY); + + const uint8_t start_block_num = i * ISO15693_3_POLLER_NUM_BLOCKS_PER_QUERY; + bit_buffer_append_byte(instance->tx_buffer, start_block_num); + + const uint8_t block_count_per_query = + MIN(block_count - start_block_num, (uint16_t)ISO15693_3_POLLER_NUM_BLOCKS_PER_QUERY); + // Block count byte must be 1 less than the desired count + bit_buffer_append_byte(instance->tx_buffer, block_count_per_query - 1); + + ret = iso15693_3_poller_send_frame( + instance, instance->tx_buffer, instance->rx_buffer, ISO15693_3_FDT_POLL_FC); + if(ret != Iso15693_3ErrorNone) break; + + ret = iso15693_3_get_block_security_response_parse( + &data[start_block_num], block_count_per_query, instance->rx_buffer); + if(ret != Iso15693_3ErrorNone) break; + } + + return ret; +} + +Iso15693_3Error iso15693_3_poller_send_frame( + Iso15693_3Poller* instance, + const BitBuffer* tx_buffer, + BitBuffer* rx_buffer, + uint32_t fwt) { + Iso15693_3Error ret; + + do { + ret = iso15693_3_poller_prepare_trx(instance); + if(ret != Iso15693_3ErrorNone) break; + + ret = iso15693_3_poller_frame_exchange(instance, tx_buffer, rx_buffer, fwt); + } while(false); + + return ret; +} diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3_poller_i.h b/lib/nfc/protocols/iso15693_3/iso15693_3_poller_i.h new file mode 100644 index 000000000000..6b6073132a20 --- /dev/null +++ b/lib/nfc/protocols/iso15693_3/iso15693_3_poller_i.h @@ -0,0 +1,72 @@ +#pragma once + +#include "iso15693_3_poller.h" + +#include "iso15693_3_i.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define ISO15693_3_POLLER_MAX_BUFFER_SIZE (64U) + +typedef enum { + Iso15693_3PollerStateIdle, + Iso15693_3PollerStateColResInProgress, + Iso15693_3PollerStateColResFailed, + Iso15693_3PollerStateActivated, +} Iso15693_3PollerState; + +struct Iso15693_3Poller { + Nfc* nfc; + Iso15693_3PollerState state; + Iso15693_3Data* data; + BitBuffer* tx_buffer; + BitBuffer* rx_buffer; + BitBuffer* tx_frame_buffer; + BitBuffer* rx_frame_buffer; + + NfcGenericEvent general_event; + Iso15693_3PollerEvent iso15693_3_event; + Iso15693_3PollerEventData iso15693_3_event_data; + NfcGenericCallback callback; + void* context; +}; + +const Iso15693_3Data* iso15693_3_poller_get_data(Iso15693_3Poller* instance); + +Iso15693_3Error iso15693_3_poller_async_activate(Iso15693_3Poller* instance, Iso15693_3Data* data); + +Iso15693_3Error iso15693_3_poller_async_inventory(Iso15693_3Poller* instance, uint8_t* uid); + +Iso15693_3Error + iso15693_3_poller_async_get_system_info(Iso15693_3Poller* instance, Iso15693_3SystemInfo* data); + +Iso15693_3Error iso15693_3_poller_async_read_block( + Iso15693_3Poller* instance, + uint8_t* data, + uint8_t block_number, + uint8_t block_size); + +Iso15693_3Error iso15693_3_poller_async_read_blocks( + Iso15693_3Poller* instance, + uint8_t* data, + uint16_t block_count, + uint8_t block_size); + +Iso15693_3Error iso15693_3_poller_async_get_blocks_security( + Iso15693_3Poller* instance, + uint8_t* data, + uint16_t block_count); + +Iso15693_3Error iso15693_3_poller_send_frame( + Iso15693_3Poller* instance, + const BitBuffer* tx_buffer, + BitBuffer* rx_buffer, + uint32_t fwt); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/nfc_device_defs.c b/lib/nfc/protocols/nfc_device_defs.c index 49b5031ddf49..8d1e9f3abe21 100644 --- a/lib/nfc/protocols/nfc_device_defs.c +++ b/lib/nfc/protocols/nfc_device_defs.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -13,6 +14,7 @@ const NfcDeviceBase* nfc_devices[NfcProtocolNum] = { [NfcProtocolIso14443_3a] = &nfc_device_iso14443_3a, [NfcProtocolIso14443_3b] = &nfc_device_iso14443_3b, [NfcProtocolIso14443_4a] = &nfc_device_iso14443_4a, + [NfcProtocolIso15693_3] = &nfc_device_iso15693_3, [NfcProtocolMfUltralight] = &nfc_device_mf_ultralight, [NfcProtocolMfClassic] = &nfc_device_mf_classic, [NfcProtocolMfDesfire] = &nfc_device_mf_desfire, diff --git a/lib/nfc/protocols/nfc_poller_defs.c b/lib/nfc/protocols/nfc_poller_defs.c index 0c2603b90c4c..4de37695b715 100644 --- a/lib/nfc/protocols/nfc_poller_defs.c +++ b/lib/nfc/protocols/nfc_poller_defs.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -11,6 +12,7 @@ const NfcPollerBase* nfc_pollers_api[NfcProtocolNum] = { [NfcProtocolIso14443_3a] = &nfc_poller_iso14443_3a, [NfcProtocolIso14443_3b] = &nfc_poller_iso14443_3b, [NfcProtocolIso14443_4a] = &nfc_poller_iso14443_4a, + [NfcProtocolIso15693_3] = &nfc_poller_iso15693_3, [NfcProtocolMfUltralight] = &mf_ultralight_poller, [NfcProtocolMfClassic] = &mf_classic_poller, [NfcProtocolMfDesfire] = &mf_desfire_poller, diff --git a/lib/nfc/protocols/nfc_protocol.c b/lib/nfc/protocols/nfc_protocol.c index a4ea0ba3fc72..bca4441a0748 100644 --- a/lib/nfc/protocols/nfc_protocol.c +++ b/lib/nfc/protocols/nfc_protocol.c @@ -12,11 +12,11 @@ typedef struct { * * (Start) * | - * +------------------------+-----------+-------+ - * | | | | - * ISO14443-3A ISO14443-3B NFC-F NFC-V - * | - * +---------------+-------------+ + * +------------------------+-----------+---------+ + * | | | | + * ISO14443-3A ISO14443-3B NFC-F ISO15693-3 + * | | + * +---------------+-------------+ SLIX2 * | | | * ISO14443-4A Mf Ultralight Mf Classic * | @@ -54,6 +54,12 @@ static const NfcProtocolTreeNode nfc_protocol_nodes[NfcProtocolNum] = { .children_num = COUNT_OF(nfc_protocol_iso14443_4a_children_protocol), .children_protocol = nfc_protocol_iso14443_4a_children_protocol, }, + [NfcProtocolIso15693_3] = + { + .parent_protocol = NfcProtocolInvalid, + .children_num = 0, + .children_protocol = NULL, + }, [NfcProtocolMfUltralight] = { .parent_protocol = NfcProtocolIso14443_3a, diff --git a/lib/nfc/protocols/nfc_protocol.h b/lib/nfc/protocols/nfc_protocol.h index 62f74186ff24..ee0a021ed0bf 100644 --- a/lib/nfc/protocols/nfc_protocol.h +++ b/lib/nfc/protocols/nfc_protocol.h @@ -10,6 +10,7 @@ typedef enum { NfcProtocolIso14443_3a, NfcProtocolIso14443_3b, NfcProtocolIso14443_4a, + NfcProtocolIso15693_3, NfcProtocolMfUltralight, NfcProtocolMfClassic, NfcProtocolMfDesfire, diff --git a/lib/toolbox/simple_array.c b/lib/toolbox/simple_array.c index 97550106c03c..7aed8e34be3a 100644 --- a/lib/toolbox/simple_array.c +++ b/lib/toolbox/simple_array.c @@ -80,6 +80,18 @@ void simple_array_copy(SimpleArray* instance, const SimpleArray* other) { } } +bool simple_array_is_equal(const SimpleArray* instance, const SimpleArray* other) { + furi_assert(instance); + furi_assert(other); + + // Equal if the same object + if(instance == other) return true; + + return (instance->config == other->config) && (instance->count == other->count) && + ((instance->data == other->data) || (instance->data == NULL) || (other->data == NULL) || + (memcmp(instance->data, other->data, other->count) == 0)); +} + uint32_t simple_array_get_count(const SimpleArray* instance) { furi_assert(instance); return instance->count; diff --git a/lib/toolbox/simple_array.h b/lib/toolbox/simple_array.h index b3d070cd74cd..a608db08d876 100644 --- a/lib/toolbox/simple_array.h +++ b/lib/toolbox/simple_array.h @@ -18,6 +18,7 @@ #include #include +#include #ifdef __cplusplus extern "C" { @@ -85,6 +86,16 @@ void simple_array_reset(SimpleArray* instance); */ void simple_array_copy(SimpleArray* instance, const SimpleArray* other); +/** + * Check if another SimpleArray instance is equal (the same object or holds the + * same data) to this one. + * + * @param [in] instance Pointer to the SimpleArray instance to be compared + * @param [in] other Pointer to the SimpleArray instance to be compared + * @return True if instances are considered equal, false otherwise + */ +bool simple_array_is_equal(const SimpleArray* instance, const SimpleArray* other); + /** * Get the count of elements currently contained in a SimpleArray instance. * From caf642c01e15dc86c756c29110dcaa867583b884 Mon Sep 17 00:00:00 2001 From: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Date: Fri, 4 Aug 2023 16:22:10 +0300 Subject: [PATCH 132/149] Fix NFC14443-3B (NFC-B) poller (#2946) --- lib/nfc/helpers/bit_buffer.c | 1 + .../protocols/iso14443_3b/iso14443_3b_poller.c | 5 ++--- .../protocols/iso14443_3b/iso14443_3b_poller_i.c | 15 +++++---------- 3 files changed, 8 insertions(+), 13 deletions(-) diff --git a/lib/nfc/helpers/bit_buffer.c b/lib/nfc/helpers/bit_buffer.c index 3de216d1c453..7325af135964 100644 --- a/lib/nfc/helpers/bit_buffer.c +++ b/lib/nfc/helpers/bit_buffer.c @@ -36,6 +36,7 @@ void bit_buffer_reset(BitBuffer* buf) { furi_assert(buf); memset(buf->data, 0, buf->capacity_bytes); + memset(buf->parity, 0, buf->capacity_bytes); buf->size_bits = 0; } diff --git a/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller.c b/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller.c index bac2d493cc07..3ea74f60cf94 100644 --- a/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller.c +++ b/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller.c @@ -70,8 +70,7 @@ static NfcCommand iso14443_3b_poller_run(NfcGenericEvent event, void* context) { if(nfc_event->type == NfcEventTypePollerReady) { if(instance->state != Iso14443_3bPollerStateActivated) { - Iso14443_3bData data = {}; - Iso14443_3bError error = iso14443_3b_poller_async_activate(instance, &data); + Iso14443_3bError error = iso14443_3b_poller_async_activate(instance, instance->data); if(error == Iso14443_3bErrorNone) { instance->iso14443_3b_event.type = Iso14443_3bPollerEventTypeReady; instance->iso14443_3b_event_data.error = error; @@ -105,7 +104,7 @@ static bool iso14443_3b_poller_detect(NfcGenericEvent event, void* context) { furi_assert(instance->state == Iso14443_3bPollerStateIdle); if(nfc_event->type == NfcEventTypePollerReady) { - Iso14443_3bError error = iso14443_3b_poller_async_activate(instance, NULL); + Iso14443_3bError error = iso14443_3b_poller_async_activate(instance, instance->data); protocol_detected = (error == Iso14443_3bErrorNone); } diff --git a/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller_i.c b/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller_i.c index d0ce99578e12..35c67c43cdc6 100644 --- a/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller_i.c +++ b/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller_i.c @@ -65,7 +65,7 @@ Iso14443_3bError furi_assert(instance); furi_assert(instance->nfc); - iso14443_3b_reset(instance->data); + iso14443_3b_reset(data); Iso14443_3bError ret; @@ -99,16 +99,16 @@ Iso14443_3bError const Iso14443_3bAtqB* atqb = (const Iso14443_3bAtqB*)bit_buffer_get_data(instance->rx_buffer); - memcpy(instance->data->uid, atqb->uid, ISO14443_3B_UID_SIZE); - memcpy(instance->data->app_data, atqb->app_data, ISO14443_3B_APP_DATA_SIZE); - memcpy(instance->data->protocol_info, atqb->protocol_info, ISO14443_3B_PROTOCOL_INFO_SIZE); + memcpy(data->uid, atqb->uid, ISO14443_3B_UID_SIZE); + memcpy(data->app_data, atqb->app_data, ISO14443_3B_APP_DATA_SIZE); + memcpy(data->protocol_info, atqb->protocol_info, ISO14443_3B_PROTOCOL_INFO_SIZE); bit_buffer_reset(instance->tx_buffer); bit_buffer_reset(instance->rx_buffer); // Send ATTRIB bit_buffer_append_byte(instance->tx_buffer, 0x1d); - bit_buffer_append_bytes(instance->tx_buffer, atqb->uid, ISO14443_3B_UID_SIZE); + bit_buffer_append_bytes(instance->tx_buffer, data->uid, ISO14443_3B_UID_SIZE); bit_buffer_append_byte(instance->tx_buffer, 0x00); bit_buffer_append_byte(instance->tx_buffer, ISO14443_3B_ATTRIB_FRAME_SIZE_256); bit_buffer_append_byte(instance->tx_buffer, 0x01); @@ -130,11 +130,6 @@ Iso14443_3bError } instance->state = Iso14443_3bPollerStateActivated; - - if(data) { - iso14443_3b_copy(data, instance->data); - } - } while(false); return ret; From 10d767c30df2ddc328be79671878f728254ed0de Mon Sep 17 00:00:00 2001 From: gornekich Date: Wed, 9 Aug 2023 14:48:43 +0400 Subject: [PATCH 133/149] [FL-3449] Introduce Felica poller (#2961) * nfc: introduce felica support * nfc: felica chip configuration * felica: fix chip configuration * felica: working poller * nfc: return registers to default values * nfc scanner: detect multiple technologies * felica: fix polling cmd parser * nfc: clean up * felica: more clean up * felica: add UID related comments --- .../helpers/protocol_support/felica/felica.c | 111 +++++++++++++ .../helpers/protocol_support/felica/felica.h | 5 + .../protocol_support/felica/felica_render.c | 19 +++ .../protocol_support/felica/felica_render.h | 10 ++ .../nfc_protocol_support_defs.c | 2 + applications/main/nfc/nfc_app.c | 2 - .../main/nfc/scenes/nfc_scene_delete.c | 1 - .../main/nfc/scenes/nfc_scene_detect.c | 2 + .../nfc/scenes/nfc_scene_select_protocol.c | 1 + firmware/targets/f7/furi_hal/f_hal_nfc.c | 62 ++++++++ .../targets/f7/furi_hal/f_hal_nfc_timer.c | 4 +- firmware/targets/furi_hal_include/f_hal_nfc.h | 2 +- lib/nfc/helpers/felica_crc.c | 52 +++++++ lib/nfc/helpers/felica_crc.h | 22 +++ lib/nfc/nfc.c | 3 + lib/nfc/nfc.h | 2 +- lib/nfc/nfc_scanner.c | 54 +++++-- lib/nfc/protocols/felica/felica.c | 147 ++++++++++++++++++ lib/nfc/protocols/felica/felica.h | 76 +++++++++ lib/nfc/protocols/felica/felica_poller.c | 117 ++++++++++++++ lib/nfc/protocols/felica/felica_poller.h | 30 ++++ lib/nfc/protocols/felica/felica_poller_defs.h | 13 ++ lib/nfc/protocols/felica/felica_poller_i.c | 114 ++++++++++++++ lib/nfc/protocols/felica/felica_poller_i.h | 59 +++++++ lib/nfc/protocols/nfc_device_defs.c | 2 + lib/nfc/protocols/nfc_poller_defs.c | 2 + lib/nfc/protocols/nfc_protocol.c | 8 +- lib/nfc/protocols/nfc_protocol.h | 1 + 28 files changed, 898 insertions(+), 25 deletions(-) create mode 100644 applications/main/nfc/helpers/protocol_support/felica/felica.c create mode 100644 applications/main/nfc/helpers/protocol_support/felica/felica.h create mode 100644 applications/main/nfc/helpers/protocol_support/felica/felica_render.c create mode 100644 applications/main/nfc/helpers/protocol_support/felica/felica_render.h create mode 100644 lib/nfc/helpers/felica_crc.c create mode 100644 lib/nfc/helpers/felica_crc.h create mode 100644 lib/nfc/protocols/felica/felica.c create mode 100644 lib/nfc/protocols/felica/felica.h create mode 100644 lib/nfc/protocols/felica/felica_poller.c create mode 100644 lib/nfc/protocols/felica/felica_poller.h create mode 100644 lib/nfc/protocols/felica/felica_poller_defs.h create mode 100644 lib/nfc/protocols/felica/felica_poller_i.c create mode 100644 lib/nfc/protocols/felica/felica_poller_i.h diff --git a/applications/main/nfc/helpers/protocol_support/felica/felica.c b/applications/main/nfc/helpers/protocol_support/felica/felica.c new file mode 100644 index 000000000000..8c9aae3c73ac --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/felica/felica.c @@ -0,0 +1,111 @@ +#include "felica.h" +#include "felica_render.h" + +#include + +#include "nfc/nfc_app_i.h" + +#include "../nfc_protocol_support_gui_common.h" + +static void nfc_scene_info_on_enter_felica(NfcApp* instance) { + const NfcDevice* device = instance->nfc_device; + const FelicaData* data = nfc_device_get_data(device, NfcProtocolFelica); + + FuriString* temp_str = furi_string_alloc(); + furi_string_cat_printf( + temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull)); + nfc_render_felica_info(data, NfcProtocolFormatTypeFull, temp_str); + + widget_add_text_scroll_element( + instance->widget, 0, 0, 128, 64, furi_string_get_cstr(temp_str)); + + furi_string_free(temp_str); +} + +static NfcCommand nfc_scene_read_poller_callback_felica(NfcGenericEvent event, void* context) { + furi_assert(event.protocol == NfcProtocolFelica); + + NfcApp* instance = context; + const FelicaPollerEvent* felica_event = event.data; + + if(felica_event->type == FelicaPollerEventTypeReady) { + nfc_device_set_data( + instance->nfc_device, NfcProtocolFelica, nfc_poller_get_data(instance->poller)); + view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventPollerSuccess); + return NfcCommandStop; + } + + return NfcCommandContinue; +} + +static void nfc_scene_read_on_enter_felica(NfcApp* instance) { + nfc_poller_start(instance->poller, nfc_scene_read_poller_callback_felica, instance); +} + +static void nfc_scene_read_success_on_enter_felica(NfcApp* instance) { + const NfcDevice* device = instance->nfc_device; + const FelicaData* data = nfc_device_get_data(device, NfcProtocolFelica); + + FuriString* temp_str = furi_string_alloc(); + furi_string_cat_printf( + temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull)); + nfc_render_felica_info(data, NfcProtocolFormatTypeShort, temp_str); + + widget_add_text_scroll_element( + instance->widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); + + furi_string_free(temp_str); +} + +static bool nfc_scene_info_on_event_felica(NfcApp* instance, uint32_t event) { + if(event == GuiButtonTypeRight) { + scene_manager_next_scene(instance->scene_manager, NfcSceneNotImplemented); + return true; + } + + return false; +} + +static bool nfc_scene_saved_menu_on_event_felica(NfcApp* instance, uint32_t event) { + if(event == SubmenuIndexCommonEdit) { + scene_manager_next_scene(instance->scene_manager, NfcSceneSetUid); + return true; + } + + return false; +} + +const NfcProtocolSupportBase nfc_protocol_support_felica = { + .features = NfcProtocolFeatureNone, // TODO: Implement better UID editing, + + .scene_info = + { + .on_enter = nfc_scene_info_on_enter_felica, + .on_event = nfc_scene_info_on_event_felica, + }, + .scene_read = + { + .on_enter = nfc_scene_read_on_enter_felica, + .on_event = NULL, + }, + .scene_read_menu = + { + .on_enter = nfc_protocol_support_common_on_enter_empty, + .on_event = nfc_protocol_support_common_on_event_empty, + }, + .scene_read_success = + { + .on_enter = nfc_scene_read_success_on_enter_felica, + .on_event = NULL, + }, + .scene_saved_menu = + { + .on_enter = nfc_protocol_support_common_on_enter_empty, + .on_event = nfc_scene_saved_menu_on_event_felica, + }, + .scene_emulate = + { + .on_enter = NULL, + .on_event = NULL, + }, +}; diff --git a/applications/main/nfc/helpers/protocol_support/felica/felica.h b/applications/main/nfc/helpers/protocol_support/felica/felica.h new file mode 100644 index 000000000000..e581b6709e7a --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/felica/felica.h @@ -0,0 +1,5 @@ +#pragma once + +#include "../nfc_protocol_support_base.h" + +extern const NfcProtocolSupportBase nfc_protocol_support_felica; diff --git a/applications/main/nfc/helpers/protocol_support/felica/felica_render.c b/applications/main/nfc/helpers/protocol_support/felica/felica_render.c new file mode 100644 index 000000000000..3142b2c6dbf0 --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/felica/felica_render.c @@ -0,0 +1,19 @@ +#include "felica_render.h" + +void nfc_render_felica_info( + const FelicaData* data, + NfcProtocolFormatType format_type, + FuriString* str) { + furi_string_cat_printf(str, "IDm:"); + + for(size_t i = 0; i < FELICA_IDM_SIZE; i++) { + furi_string_cat_printf(str, " %02X", data->idm.data[i]); + } + + if(format_type == NfcProtocolFormatTypeFull) { + furi_string_cat_printf(str, "\nPMm:"); + for(size_t i = 0; i < FELICA_PMM_SIZE; ++i) { + furi_string_cat_printf(str, " %02X", data->pmm.data[i]); + } + } +} diff --git a/applications/main/nfc/helpers/protocol_support/felica/felica_render.h b/applications/main/nfc/helpers/protocol_support/felica/felica_render.h new file mode 100644 index 000000000000..6d9816fc6630 --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/felica/felica_render.h @@ -0,0 +1,10 @@ +#pragma once + +#include + +#include "../nfc_protocol_support_render_common.h" + +void nfc_render_felica_info( + const FelicaData* data, + NfcProtocolFormatType format_type, + FuriString* str); diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_defs.c b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_defs.c index 82d910ec5bef..4b3d15168fc3 100644 --- a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_defs.c +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_defs.c @@ -4,6 +4,7 @@ #include "iso14443_3b/iso14443_3b.h" #include "iso14443_4a/iso14443_4a.h" #include "iso15693_3/iso15693_3.h" +#include "felica/felica.h" #include "mf_ultralight/mf_ultralight.h" #include "mf_classic/mf_classic.h" #include "mf_desfire/mf_desfire.h" @@ -13,6 +14,7 @@ const NfcProtocolSupportBase* nfc_protocol_support[NfcProtocolNum] = { [NfcProtocolIso14443_3b] = &nfc_protocol_support_iso14443_3b, [NfcProtocolIso14443_4a] = &nfc_protocol_support_iso14443_4a, [NfcProtocolIso15693_3] = &nfc_protocol_support_iso15693_3, + [NfcProtocolFelica] = &nfc_protocol_support_felica, [NfcProtocolMfUltralight] = &nfc_protocol_support_mf_ultralight, [NfcProtocolMfClassic] = &nfc_protocol_support_mf_classic, [NfcProtocolMfDesfire] = &nfc_protocol_support_mf_desfire, diff --git a/applications/main/nfc/nfc_app.c b/applications/main/nfc/nfc_app.c index 9b35813e1b74..4240e61f277e 100644 --- a/applications/main/nfc/nfc_app.c +++ b/applications/main/nfc/nfc_app.c @@ -46,7 +46,6 @@ NfcApp* nfc_app_alloc() { instance->view_dispatcher, nfc_back_event_callback); instance->nfc = nfc_alloc(); - instance->scanner = nfc_scanner_alloc(instance->nfc); instance->mf_ul_auth = mf_ultralight_auth_alloc(); @@ -147,7 +146,6 @@ void nfc_app_free(NfcApp* instance) { } nfc_free(instance->nfc); - nfc_scanner_free(instance->scanner); mf_ultralight_auth_free(instance->mf_ul_auth); diff --git a/applications/main/nfc/scenes/nfc_scene_delete.c b/applications/main/nfc/scenes/nfc_scene_delete.c index d36b5fb54bf2..c1a676168ad5 100644 --- a/applications/main/nfc/scenes/nfc_scene_delete.c +++ b/applications/main/nfc/scenes/nfc_scene_delete.c @@ -35,7 +35,6 @@ void nfc_scene_delete_on_enter(void* context) { furi_string_set_str(temp_str, nfc_device_get_name(nfc->nfc_device, NfcDeviceNameTypeFull)); widget_add_string_element( nfc->widget, 64, 34, AlignCenter, AlignTop, FontSecondary, furi_string_get_cstr(temp_str)); - widget_add_string_element(nfc->widget, 64, 44, AlignCenter, AlignTop, FontSecondary, "NFC-A"); furi_string_free(temp_str); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); diff --git a/applications/main/nfc/scenes/nfc_scene_detect.c b/applications/main/nfc/scenes/nfc_scene_detect.c index 1ff5acb3ddf1..5e7fc6528213 100644 --- a/applications/main/nfc/scenes/nfc_scene_detect.c +++ b/applications/main/nfc/scenes/nfc_scene_detect.c @@ -25,6 +25,7 @@ void nfc_scene_detect_on_enter(void* context) { nfc_app_reset_detected_protocols(instance); + instance->scanner = nfc_scanner_alloc(instance->nfc); nfc_scanner_start(instance->scanner, nfc_scene_detect_scan_callback, instance); nfc_blink_detect_start(instance); @@ -53,6 +54,7 @@ void nfc_scene_detect_on_exit(void* context) { NfcApp* instance = context; nfc_scanner_stop(instance->scanner); + nfc_scanner_free(instance->scanner); popup_reset(instance->popup); nfc_blink_stop(instance); diff --git a/applications/main/nfc/scenes/nfc_scene_select_protocol.c b/applications/main/nfc/scenes/nfc_scene_select_protocol.c index fff7ab979964..502f91772097 100644 --- a/applications/main/nfc/scenes/nfc_scene_select_protocol.c +++ b/applications/main/nfc/scenes/nfc_scene_select_protocol.c @@ -21,6 +21,7 @@ void nfc_scene_select_protocol_on_enter(void* context) { } else { prefix = "Read as"; submenu_set_header(submenu, "Multi-protocol card"); + notification_message(instance->notifications, &sequence_single_vibro); } for(size_t i = 0; i < instance->protocols_detected_num; i++) { diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc.c b/firmware/targets/f7/furi_hal/f_hal_nfc.c index f9cca46ff44c..048ccbb9a5c0 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfc.c +++ b/firmware/targets/f7/furi_hal/f_hal_nfc.c @@ -531,6 +531,46 @@ FHalNfcError f_hal_nfc_set_mode(FHalNfcMode mode, FHalNfcBitrate bitrate) { st25r3916_write_reg( handle, ST25R3916_REG_CORR_CONF2, ST25R3916_REG_CORR_CONF2_corr_s8); } + } else if(mode == FHalNfcModeFelicaPoller) { + f_hal_nfc_configure_poller_common(handle); + // Enable Felica mode, AM modulation + st25r3916_change_reg_bits( + handle, + ST25R3916_REG_MODE, + ST25R3916_REG_MODE_om_mask | ST25R3916_REG_MODE_tr_am, + ST25R3916_REG_MODE_om_felica | ST25R3916_REG_MODE_tr_am_am); + + // 10% ASK modulation + st25r3916_change_reg_bits( + handle, + ST25R3916_REG_TX_DRIVER, + ST25R3916_REG_TX_DRIVER_am_mod_mask, + ST25R3916_REG_TX_DRIVER_am_mod_10percent); + + // Use regulator AM, resistive AM disabled + st25r3916_clear_reg_bits( + handle, + ST25R3916_REG_AUX_MOD, + ST25R3916_REG_AUX_MOD_dis_reg_am | ST25R3916_REG_AUX_MOD_res_am); + + st25r3916_change_reg_bits( + handle, + ST25R3916_REG_BIT_RATE, + ST25R3916_REG_BIT_RATE_txrate_mask | ST25R3916_REG_BIT_RATE_rxrate_mask, + ST25R3916_REG_BIT_RATE_txrate_212 | ST25R3916_REG_BIT_RATE_rxrate_212); + + // Receive configuration + st25r3916_write_reg( + handle, + ST25R3916_REG_RX_CONF1, + ST25R3916_REG_RX_CONF1_lp0 | ST25R3916_REG_RX_CONF1_hz_12_80khz); + + // Correlator setup + st25r3916_write_reg( + handle, + ST25R3916_REG_CORR_CONF1, + ST25R3916_REG_CORR_CONF1_corr_s6 | ST25R3916_REG_CORR_CONF1_corr_s4 | + ST25R3916_REG_CORR_CONF1_corr_s3); } return error; @@ -543,7 +583,29 @@ FHalNfcError f_hal_nfc_reset_mode() { st25r3916_direct_cmd(handle, ST25R3916_CMD_STOP); // Set default value in mode register st25r3916_write_reg(handle, ST25R3916_REG_MODE, ST25R3916_REG_MODE_om0); + st25r3916_write_reg(handle, ST25R3916_REG_STREAM_MODE, 0); + st25r3916_clear_reg_bits(handle, ST25R3916_REG_AUX, ST25R3916_REG_AUX_no_crc_rx); + st25r3916_clear_reg_bits( + handle, + ST25R3916_REG_BIT_RATE, + ST25R3916_REG_BIT_RATE_txrate_mask | ST25R3916_REG_BIT_RATE_rxrate_mask); + + // Write default values + st25r3916_write_reg(handle, ST25R3916_REG_RX_CONF1, 0); + st25r3916_write_reg( + handle, + ST25R3916_REG_RX_CONF2, + ST25R3916_REG_RX_CONF2_sqm_dyn | ST25R3916_REG_RX_CONF2_agc_en | + ST25R3916_REG_RX_CONF2_agc_m); + + st25r3916_write_reg( + handle, + ST25R3916_REG_CORR_CONF1, + ST25R3916_REG_CORR_CONF1_corr_s7 | ST25R3916_REG_CORR_CONF1_corr_s4 | + ST25R3916_REG_CORR_CONF1_corr_s1 | ST25R3916_REG_CORR_CONF1_corr_s0); + st25r3916_write_reg(handle, ST25R3916_REG_CORR_CONF2, 0); + f_hal_nfca_listener_deinit(); return error; diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc_timer.c b/firmware/targets/f7/furi_hal/f_hal_nfc_timer.c index f75c51828d05..1055a16d08f3 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfc_timer.c +++ b/firmware/targets/f7/furi_hal/f_hal_nfc_timer.c @@ -44,8 +44,8 @@ static FHalNfcTimerConfig f_hal_nfc_timers[FHalNfcTimerCount] = { .pin = &gpio_ext_pa6, .timer = TIM17, .bus = FuriHalBusTIM17, - .prescaler = 15, - .freq_khz = 4000U, + .prescaler = 31, + .freq_khz = 2000U, .event = FHalNfcEventInternalTypeTimerBlockTxExpired, .irq_id = FuriHalInterruptIdTim1TrgComTim17, .irq_type = TIM1_TRG_COM_TIM17_IRQn, diff --git a/firmware/targets/furi_hal_include/f_hal_nfc.h b/firmware/targets/furi_hal_include/f_hal_nfc.h index 9c847dc5342d..d8cd41141781 100644 --- a/firmware/targets/furi_hal_include/f_hal_nfc.h +++ b/firmware/targets/furi_hal_include/f_hal_nfc.h @@ -47,7 +47,7 @@ typedef enum { FHalNfcModeIso14443bPoller, FHalNfcModeIso14443bListener, - FHalNfcModeNfcfPoller, + FHalNfcModeFelicaPoller, FHalNfcModeNfcfListener, FHalNfcModeIso15693Poller, diff --git a/lib/nfc/helpers/felica_crc.c b/lib/nfc/helpers/felica_crc.c new file mode 100644 index 000000000000..d5e0853a1095 --- /dev/null +++ b/lib/nfc/helpers/felica_crc.c @@ -0,0 +1,52 @@ +#include "felica_crc.h" + +#include + +#define FELICA_CRC_POLY (0x1021U) // Polynomial: x^16 + x^12 + x^5 + 1 +#define FELICA_CRC_INIT (0x0000U) + +uint16_t felica_crc_calculate(const uint8_t* data, size_t length) { + uint16_t crc = FELICA_CRC_INIT; + + for(size_t i = 0; i < length; i++) { + crc ^= ((uint16_t)data[i] << 8); + for(size_t j = 0; j < 8; j++) { + if(crc & 0x8000) { + crc <<= 1; + crc ^= FELICA_CRC_POLY; + } else { + crc <<= 1; + } + } + } + + return (crc << 8) | (crc >> 8); +} + +void felica_crc_append(BitBuffer* buf) { + const uint8_t* data = bit_buffer_get_data(buf); + const size_t data_size = bit_buffer_get_size_bytes(buf); + + const uint16_t crc = felica_crc_calculate(data, data_size); + bit_buffer_append_bytes(buf, (const uint8_t*)&crc, FELICA_CRC_SIZE); +} + +bool felica_crc_check(const BitBuffer* buf) { + const size_t data_size = bit_buffer_get_size_bytes(buf); + if(data_size <= FELICA_CRC_SIZE) return false; + + uint16_t crc_received; + bit_buffer_write_bytes_mid(buf, &crc_received, data_size - FELICA_CRC_SIZE, FELICA_CRC_SIZE); + + const uint8_t* data = bit_buffer_get_data(buf); + const uint16_t crc_calc = felica_crc_calculate(data, data_size - FELICA_CRC_SIZE); + + return (crc_calc == crc_received); +} + +void felica_crc_trim(BitBuffer* buf) { + const size_t data_size = bit_buffer_get_size_bytes(buf); + furi_assert(data_size > FELICA_CRC_SIZE); + + bit_buffer_set_size_bytes(buf, data_size - FELICA_CRC_SIZE); +} diff --git a/lib/nfc/helpers/felica_crc.h b/lib/nfc/helpers/felica_crc.h new file mode 100644 index 000000000000..d1dc29e74db7 --- /dev/null +++ b/lib/nfc/helpers/felica_crc.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include + +#include "bit_buffer.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define FELICA_CRC_SIZE sizeof(uint16_t) + +void felica_crc_append(BitBuffer* buf); + +bool felica_crc_check(const BitBuffer* buf); + +void felica_crc_trim(BitBuffer* buf); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/nfc.c b/lib/nfc/nfc.c index e64c308e7b83..65e041255d9f 100644 --- a/lib/nfc/nfc.c +++ b/lib/nfc/nfc.c @@ -267,6 +267,9 @@ void nfc_config(Nfc* instance, NfcMode mode) { f_hal_nfc_low_power_mode_stop(); f_hal_nfc_set_mode(FHalNfcModeIso15693Listener, FHalNfcBitrate26p48); instance->config_state = NfcConfigurationStateDone; + } else if(mode == NfcModeFelicaPoller) { + f_hal_nfc_set_mode(FHalNfcModeFelicaPoller, FHalNfcBitrate106); + instance->config_state = NfcConfigurationStateDone; } } diff --git a/lib/nfc/nfc.h b/lib/nfc/nfc.h index f5a135e17e3e..b4a023db66b4 100644 --- a/lib/nfc/nfc.h +++ b/lib/nfc/nfc.h @@ -44,7 +44,7 @@ typedef enum { NfcModeIso14443aListener, NfcModeIso14443bPoller, NfcModeIso14443bListener, - NfcModeNfcfPoller, + NfcModeFelicaPoller, NfcModeNfcfListener, NfcModeIso15693Poller, NfcModeIso15693Listener, diff --git a/lib/nfc/nfc_scanner.c b/lib/nfc/nfc_scanner.c index e4c10a919783..f32110be9381 100644 --- a/lib/nfc/nfc_scanner.c +++ b/lib/nfc/nfc_scanner.c @@ -34,10 +34,15 @@ struct NfcScanner { NfcEvent nfc_event; + NfcProtocol first_detected_protocol; + size_t base_protocols_num; size_t base_protocols_idx; NfcProtocol base_protocols[NfcProtocolNum]; + size_t detected_base_protocols_num; + NfcProtocol detected_base_protocols[NfcProtocolNum]; + size_t children_protocols_num; size_t children_protocols_idx; NfcProtocol children_protocols[NfcProtocolNum]; @@ -58,6 +63,7 @@ static void nfc_scanner_reset(NfcScanner* instance) { instance->children_protocols_num = 0; instance->detected_protocols_num = 0; + instance->detected_base_protocols_num = 0; instance->current_protocol = 0; } @@ -72,38 +78,52 @@ void nfc_scanner_state_handler_idle(NfcScanner* instance) { instance->base_protocols_num++; } } - instance->base_protocols_idx = 0; FURI_LOG_D(TAG, "Found %d base protocols", instance->base_protocols_num); + instance->first_detected_protocol = NfcProtocolInvalid; instance->state = NfcScannerStateTryBasePollers; } void nfc_scanner_state_handler_try_base_pollers(NfcScanner* instance) { - instance->current_protocol = instance->base_protocols[instance->base_protocols_idx]; + do { + instance->current_protocol = instance->base_protocols[instance->base_protocols_idx]; - NfcPoller* poller = nfc_poller_alloc(instance->nfc, instance->current_protocol); - bool protocol_detected = nfc_poller_detect(poller); - nfc_poller_free(poller); + if(instance->first_detected_protocol == instance->current_protocol) { + instance->state = NfcScannerStateFindChildrenProtocols; + break; + } - if(protocol_detected) { - instance->detected_protocols[instance->detected_protocols_num] = - instance->current_protocol; - instance->detected_protocols_num++; - } + NfcPoller* poller = nfc_poller_alloc(instance->nfc, instance->current_protocol); + bool protocol_detected = nfc_poller_detect(poller); + nfc_poller_free(poller); + + if(protocol_detected) { + instance->detected_protocols[instance->detected_protocols_num] = + instance->current_protocol; + instance->detected_protocols_num++; + + instance->detected_base_protocols[instance->detected_base_protocols_num] = + instance->current_protocol; + instance->detected_base_protocols_num++; + + if(instance->first_detected_protocol == NfcProtocolInvalid) { + instance->first_detected_protocol = instance->current_protocol; + instance->current_protocol = NfcProtocolInvalid; + } + } - if(instance->detected_protocols_num > 0) { - instance->state = NfcScannerStateFindChildrenProtocols; - } else { instance->base_protocols_idx = (instance->base_protocols_idx + 1) % instance->base_protocols_num; - } + } while(false); } void nfc_scanner_state_handler_find_children_protocols(NfcScanner* instance) { for(size_t i = 0; i < NfcProtocolNum; i++) { - if(nfc_protocol_has_parent(i, instance->current_protocol)) { - instance->children_protocols[instance->children_protocols_num] = i; - instance->children_protocols_num++; + for(size_t j = 0; j < instance->detected_base_protocols_num; j++) { + if(nfc_protocol_has_parent(i, instance->detected_base_protocols[j])) { + instance->children_protocols[instance->children_protocols_num] = i; + instance->children_protocols_num++; + } } } diff --git a/lib/nfc/protocols/felica/felica.c b/lib/nfc/protocols/felica/felica.c new file mode 100644 index 000000000000..de8b88813f35 --- /dev/null +++ b/lib/nfc/protocols/felica/felica.c @@ -0,0 +1,147 @@ +#include "felica.h" + +#include + +#include + +#define FELICA_PROTOCOL_NAME "FeliCa" +#define FELICA_DEVICE_NAME "FeliCa" + +#define FELICA_DATA_FORMAT_VERSION "Data format version" +#define FELICA_MANUFACTURE_ID "Manufacture id" +#define FELICA_MANUFACTURE_PARAMETER "Manufacture parameter" + +static const uint32_t felica_data_format_version = 1; + +const NfcDeviceBase nfc_device_felica = { + .protocol_name = FELICA_PROTOCOL_NAME, + .alloc = (NfcDeviceAlloc)felica_alloc, + .free = (NfcDeviceFree)felica_free, + .reset = (NfcDeviceReset)felica_reset, + .copy = (NfcDeviceCopy)felica_copy, + .verify = (NfcDeviceVerify)felica_verify, + .load = (NfcDeviceLoad)felica_load, + .save = (NfcDeviceSave)felica_save, + .is_equal = (NfcDeviceEqual)felica_is_equal, + .get_name = (NfcDeviceGetName)felica_get_device_name, + .get_uid = (NfcDeviceGetUid)felica_get_uid, + .set_uid = (NfcDeviceSetUid)felica_set_uid, + .get_base_data = (NfcDeviceGetBaseData)felica_get_base_data, +}; + +FelicaData* felica_alloc() { + FelicaData* data = malloc(sizeof(FelicaData)); + return data; +} + +void felica_free(FelicaData* data) { + furi_assert(data); + + free(data); +} + +void felica_reset(FelicaData* data) { + memset(data, 0, sizeof(FelicaData)); +} + +void felica_copy(FelicaData* data, const FelicaData* other) { + furi_assert(data); + furi_assert(other); + + *data = *other; +} + +bool felica_verify(FelicaData* data, const FuriString* device_type) { + UNUSED(data); + UNUSED(device_type); + + return false; +} + +bool felica_load(FelicaData* data, FlipperFormat* ff, uint32_t version) { + furi_assert(data); + + bool parsed = false; + + do { + if(version < NFC_UNIFIED_FORMAT_VERSION) break; + + uint32_t data_format_version = 0; + if(!flipper_format_read_uint32(ff, FELICA_DATA_FORMAT_VERSION, &data_format_version, 1)) + break; + if(data_format_version != felica_data_format_version) break; + if(!flipper_format_read_hex(ff, FELICA_MANUFACTURE_ID, data->idm.data, FELICA_IDM_SIZE)) + break; + if(!flipper_format_read_hex( + ff, FELICA_MANUFACTURE_PARAMETER, data->pmm.data, FELICA_PMM_SIZE)) + break; + + parsed = true; + } while(false); + + return parsed; +} + +bool felica_save(const FelicaData* data, FlipperFormat* ff) { + furi_assert(data); + + bool saved = false; + + do { + if(!flipper_format_write_comment_cstr(ff, FELICA_PROTOCOL_NAME " specific data")) break; + if(!flipper_format_write_uint32( + ff, FELICA_DATA_FORMAT_VERSION, &felica_data_format_version, 1)) + break; + if(!flipper_format_write_hex(ff, FELICA_MANUFACTURE_ID, data->idm.data, FELICA_IDM_SIZE)) + break; + if(!flipper_format_write_hex( + ff, FELICA_MANUFACTURE_PARAMETER, data->pmm.data, FELICA_PMM_SIZE)) + break; + + saved = true; + } while(false); + + return saved; +} + +bool felica_is_equal(const FelicaData* data, const FelicaData* other) { + furi_assert(data); + furi_assert(other); + + return memcmp(data, other, sizeof(FelicaData)) == 0; +} + +const char* felica_get_device_name(const FelicaData* data, NfcDeviceNameType name_type) { + UNUSED(data); + UNUSED(name_type); + + return FELICA_DEVICE_NAME; +} + +const uint8_t* felica_get_uid(const FelicaData* data, size_t* uid_len) { + furi_assert(data); + + // Consider Manufacturer ID as UID + if(uid_len) { + *uid_len = FELICA_IDM_SIZE; + } + + return data->idm.data; +} + +bool felica_set_uid(FelicaData* data, const uint8_t* uid, size_t uid_len) { + furi_assert(data); + + // Consider Manufacturer ID as UID + const bool uid_valid = uid_len == FELICA_IDM_SIZE; + if(uid_valid) { + memcpy(data->idm.data, uid, uid_len); + } + + return uid_valid; +} + +const FelicaData* felica_get_base_data(const FelicaData* data) { + UNUSED(data); + furi_crash("No base data"); +} diff --git a/lib/nfc/protocols/felica/felica.h b/lib/nfc/protocols/felica/felica.h new file mode 100644 index 000000000000..cacd489f013c --- /dev/null +++ b/lib/nfc/protocols/felica/felica.h @@ -0,0 +1,76 @@ +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define FELICA_IDM_SIZE (8U) +#define FELICA_PMM_SIZE (8U) + +#define FELICA_GUARD_TIME_US (20000U) +#define FELICA_FDT_POLL_FC (10000U) +#define FELICA_POLL_POLL_MIN_US (1280U) + +#define FELICA_SYSTEM_CODE_CODE (0xFFFFU) +#define FELICA_TIME_SLOT_1 (0x00U) +#define FELICA_TIME_SLOT_2 (0x01U) +#define FELICA_TIME_SLOT_4 (0x03U) +#define FELICA_TIME_SLOT_8 (0x07U) +#define FELICA_TIME_SLOT_16 (0x0FU) + +typedef enum { + FelicaErrorNone, + FelicaErrorNotPresent, + FelicaErrorColResFailed, + FelicaErrorBufferOverflow, + FelicaErrorCommunication, + FelicaErrorFieldOff, + FelicaErrorWrongCrc, + FelicaErrorTimeout, +} FelicaError; + +typedef struct { + uint8_t data[FELICA_IDM_SIZE]; +} FelicaIDm; + +typedef struct { + uint8_t data[FELICA_PMM_SIZE]; +} FelicaPMm; + +typedef struct { + FelicaIDm idm; + FelicaPMm pmm; +} FelicaData; + +extern const NfcDeviceBase nfc_device_felica; + +FelicaData* felica_alloc(); + +void felica_free(FelicaData* data); + +void felica_reset(FelicaData* data); + +void felica_copy(FelicaData* data, const FelicaData* other); + +bool felica_verify(FelicaData* data, const FuriString* device_type); + +bool felica_load(FelicaData* data, FlipperFormat* ff, uint32_t version); + +bool felica_save(const FelicaData* data, FlipperFormat* ff); + +bool felica_is_equal(const FelicaData* data, const FelicaData* other); + +const char* felica_get_device_name(const FelicaData* data, NfcDeviceNameType name_type); + +const uint8_t* felica_get_uid(const FelicaData* data, size_t* uid_len); + +bool felica_set_uid(FelicaData* data, const uint8_t* uid, size_t uid_len); + +const FelicaData* felica_get_base_data(const FelicaData* data); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/felica/felica_poller.c b/lib/nfc/protocols/felica/felica_poller.c new file mode 100644 index 000000000000..824043aebbaf --- /dev/null +++ b/lib/nfc/protocols/felica/felica_poller.c @@ -0,0 +1,117 @@ +#include "felica_poller_i.h" + +#include + +#include + +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, NfcModeFelicaPoller); + 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); + instance->data = felica_alloc(); + + instance->felica_event.data = &instance->felica_event_data; + instance->general_event.protocol = NfcProtocolFelica; + instance->general_event.data = &instance->felica_event; + instance->general_event.instance = instance; + + 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); + + 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; +} + +static NfcCommand felica_poller_run(NfcGenericEvent event, void* context) { + furi_assert(context); + furi_assert(event.protocol == NfcProtocolInvalid); + furi_assert(event.data); + + FelicaPoller* instance = context; + NfcEvent* nfc_event = event.data; + NfcCommand command = NfcCommandContinue; + + if(nfc_event->type == NfcEventTypePollerReady) { + if(instance->state != FelicaPollerStateActivated) { + FelicaError error = felica_poller_async_activate(instance, instance->data); + if(error == FelicaErrorNone) { + instance->felica_event.type = FelicaPollerEventTypeReady; + instance->felica_event_data.error = error; + command = instance->callback(instance->general_event, instance->context); + } else { + instance->felica_event.type = FelicaPollerEventTypeError; + instance->felica_event_data.error = error; + command = instance->callback(instance->general_event, instance->context); + // Add delay to switch context + furi_delay_ms(100); + } + } else { + instance->felica_event.type = FelicaPollerEventTypeReady; + instance->felica_event_data.error = FelicaErrorNone; + command = instance->callback(instance->general_event, instance->context); + } + } + + return command; +} + +static bool felica_poller_detect(NfcGenericEvent event, void* context) { + furi_assert(context); + furi_assert(event.data); + furi_assert(event.instance); + furi_assert(event.protocol = NfcProtocolInvalid); + + bool protocol_detected = false; + FelicaPoller* instance = context; + NfcEvent* nfc_event = event.data; + furi_assert(instance->state == FelicaPollerStateIdle); + + if(nfc_event->type == NfcEventTypePollerReady) { + FelicaError error = felica_poller_async_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, +}; diff --git a/lib/nfc/protocols/felica/felica_poller.h b/lib/nfc/protocols/felica/felica_poller.h new file mode 100644 index 000000000000..7d0c9525e770 --- /dev/null +++ b/lib/nfc/protocols/felica/felica_poller.h @@ -0,0 +1,30 @@ +#pragma once + +#include "felica.h" +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct FelicaPoller FelicaPoller; + +typedef enum { + FelicaPollerEventTypeError, + FelicaPollerEventTypeReady, +} FelicaPollerEventType; + +typedef struct { + FelicaError error; +} FelicaPollerEventData; + +typedef struct { + FelicaPollerEventType type; + FelicaPollerEventData* data; +} FelicaPollerEvent; + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/felica/felica_poller_defs.h b/lib/nfc/protocols/felica/felica_poller_defs.h new file mode 100644 index 000000000000..fc99dc75219b --- /dev/null +++ b/lib/nfc/protocols/felica/felica_poller_defs.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern const NfcPollerBase nfc_poller_felica; + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/felica/felica_poller_i.c b/lib/nfc/protocols/felica/felica_poller_i.c new file mode 100644 index 000000000000..48dcd2eac82c --- /dev/null +++ b/lib/nfc/protocols/felica/felica_poller_i.c @@ -0,0 +1,114 @@ +#include "felica_poller_i.h" + +#include + +#define TAG "FelicaPoller" + +static FelicaError felica_poller_process_error(NfcError error) { + switch(error) { + case NfcErrorNone: + return FelicaErrorNone; + case NfcErrorTimeout: + return FelicaErrorTimeout; + default: + return FelicaErrorNotPresent; + } +} + +static FelicaError felica_poller_frame_exchange( + FelicaPoller* instance, + const BitBuffer* tx_buffer, + BitBuffer* rx_buffer, + uint32_t fwt) { + furi_assert(instance); + + const size_t tx_bytes = bit_buffer_get_size_bytes(tx_buffer); + furi_assert(tx_bytes <= bit_buffer_get_capacity_bytes(instance->tx_buffer) - FELICA_CRC_SIZE); + + felica_crc_append(instance->tx_buffer); + + FelicaError ret = FelicaErrorNone; + + do { + NfcError error = nfc_trx(instance->nfc, instance->tx_buffer, instance->rx_buffer, fwt); + if(error != NfcErrorNone) { + ret = felica_poller_process_error(error); + break; + } + + bit_buffer_copy(rx_buffer, instance->rx_buffer); + if(!felica_crc_check(instance->rx_buffer)) { + ret = FelicaErrorWrongCrc; + break; + } + + felica_crc_trim(rx_buffer); + } while(false); + + return ret; +} + +FelicaError felica_poller_async_polling( + FelicaPoller* instance, + const FelicaPollerPollingCommand* cmd, + FelicaPollerPollingResponse* resp) { + furi_assert(instance); + furi_assert(cmd); + furi_assert(resp); + + bit_buffer_set_size_bytes(instance->tx_buffer, 2); + // Set frame len + // TODO Set length in felica_poller_frame_exchange() ? + bit_buffer_set_byte(instance->tx_buffer, 0, sizeof(FelicaPollerPollingCommand) + 2); + // Set command code + bit_buffer_set_byte(instance->tx_buffer, 1, FELICA_POLLER_CMD_POLLING_CODE); + // Set other data + bit_buffer_append_bytes( + instance->tx_buffer, (uint8_t*)cmd, sizeof(FelicaPollerPollingCommand)); + + FelicaError error = felica_poller_frame_exchange( + instance, instance->tx_buffer, instance->rx_buffer, FELICA_POLLER_POLLING_FWT); + + if(error == FelicaErrorNone) { + // TODO extract length in felica_poller_frame_exchange() ? + bit_buffer_write_bytes_mid(instance->rx_buffer, resp->idm.data, 2, sizeof(FelicaIDm)); + bit_buffer_write_bytes_mid( + instance->rx_buffer, resp->pmm.data, sizeof(FelicaIDm) + 2, sizeof(FelicaPMm)); + } + + return error; +} + +FelicaError felica_poller_async_activate(FelicaPoller* instance, FelicaData* data) { + furi_assert(instance); + + felica_reset(data); + + FelicaError ret; + + do { + bit_buffer_reset(instance->tx_buffer); + bit_buffer_reset(instance->rx_buffer); + + // Send Polling command + const FelicaPollerPollingCommand polling_cmd = { + .system_code = FELICA_SYSTEM_CODE_CODE, + .request_code = 0, + .time_slot = FELICA_TIME_SLOT_1, + }; + FelicaPollerPollingResponse polling_resp = {}; + + ret = felica_poller_async_polling(instance, &polling_cmd, &polling_resp); + + if(ret != FelicaErrorNone) { + FURI_LOG_T(TAG, "Activation failed error: %d", ret); + break; + } + + data->idm = polling_resp.idm; + data->pmm = polling_resp.pmm; + instance->state = FelicaPollerStateActivated; + } while(false); + + return ret; +} diff --git a/lib/nfc/protocols/felica/felica_poller_i.h b/lib/nfc/protocols/felica/felica_poller_i.h new file mode 100644 index 000000000000..592bfb03bd5a --- /dev/null +++ b/lib/nfc/protocols/felica/felica_poller_i.h @@ -0,0 +1,59 @@ +#pragma once + +#include "felica_poller.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define FELICA_POLLER_MAX_BUFFER_SIZE (256U) + +#define FELICA_POLLER_POLLING_FWT (200000U) + +#define FELICA_POLLER_CMD_POLLING_CODE (0x00U) + +typedef enum { + FelicaPollerStateIdle, + FelicaPollerStateActivated, +} FelicaPollerState; + +struct FelicaPoller { + Nfc* nfc; + FelicaPollerState state; + FelicaData* data; + BitBuffer* tx_buffer; + BitBuffer* rx_buffer; + + NfcGenericEvent general_event; + FelicaPollerEvent felica_event; + FelicaPollerEventData felica_event_data; + NfcGenericCallback callback; + void* context; +}; + +typedef struct { + uint16_t system_code; + uint8_t request_code; + uint8_t time_slot; +} FelicaPollerPollingCommand; + +typedef struct { + FelicaIDm idm; + FelicaPMm pmm; + uint8_t request_data[2]; +} FelicaPollerPollingResponse; + +const FelicaData* felica_poller_get_data(FelicaPoller* instance); + +FelicaError felica_poller_async_polling( + FelicaPoller* instance, + const FelicaPollerPollingCommand* cmd, + FelicaPollerPollingResponse* resp); + +FelicaError felica_poller_async_activate(FelicaPoller* instance, FelicaData* data); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/nfc_device_defs.c b/lib/nfc/protocols/nfc_device_defs.c index 8d1e9f3abe21..e2fa5833f301 100644 --- a/lib/nfc/protocols/nfc_device_defs.c +++ b/lib/nfc/protocols/nfc_device_defs.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -15,6 +16,7 @@ const NfcDeviceBase* nfc_devices[NfcProtocolNum] = { [NfcProtocolIso14443_3b] = &nfc_device_iso14443_3b, [NfcProtocolIso14443_4a] = &nfc_device_iso14443_4a, [NfcProtocolIso15693_3] = &nfc_device_iso15693_3, + [NfcProtocolFelica] = &nfc_device_felica, [NfcProtocolMfUltralight] = &nfc_device_mf_ultralight, [NfcProtocolMfClassic] = &nfc_device_mf_classic, [NfcProtocolMfDesfire] = &nfc_device_mf_desfire, diff --git a/lib/nfc/protocols/nfc_poller_defs.c b/lib/nfc/protocols/nfc_poller_defs.c index 4de37695b715..b4e64611b6d1 100644 --- a/lib/nfc/protocols/nfc_poller_defs.c +++ b/lib/nfc/protocols/nfc_poller_defs.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -13,6 +14,7 @@ const NfcPollerBase* nfc_pollers_api[NfcProtocolNum] = { [NfcProtocolIso14443_3b] = &nfc_poller_iso14443_3b, [NfcProtocolIso14443_4a] = &nfc_poller_iso14443_4a, [NfcProtocolIso15693_3] = &nfc_poller_iso15693_3, + [NfcProtocolFelica] = &nfc_poller_felica, [NfcProtocolMfUltralight] = &mf_ultralight_poller, [NfcProtocolMfClassic] = &mf_classic_poller, [NfcProtocolMfDesfire] = &mf_desfire_poller, diff --git a/lib/nfc/protocols/nfc_protocol.c b/lib/nfc/protocols/nfc_protocol.c index bca4441a0748..f35af7b8e648 100644 --- a/lib/nfc/protocols/nfc_protocol.c +++ b/lib/nfc/protocols/nfc_protocol.c @@ -14,7 +14,7 @@ typedef struct { * | * +------------------------+-----------+---------+ * | | | | - * ISO14443-3A ISO14443-3B NFC-F ISO15693-3 + * ISO14443-3A ISO14443-3B Felica ISO15693-3 * | | * +---------------+-------------+ SLIX2 * | | | @@ -60,6 +60,12 @@ static const NfcProtocolTreeNode nfc_protocol_nodes[NfcProtocolNum] = { .children_num = 0, .children_protocol = NULL, }, + [NfcProtocolFelica] = + { + .parent_protocol = NfcProtocolInvalid, + .children_num = 0, + .children_protocol = NULL, + }, [NfcProtocolMfUltralight] = { .parent_protocol = NfcProtocolIso14443_3a, diff --git a/lib/nfc/protocols/nfc_protocol.h b/lib/nfc/protocols/nfc_protocol.h index ee0a021ed0bf..814075533626 100644 --- a/lib/nfc/protocols/nfc_protocol.h +++ b/lib/nfc/protocols/nfc_protocol.h @@ -11,6 +11,7 @@ typedef enum { NfcProtocolIso14443_3b, NfcProtocolIso14443_4a, NfcProtocolIso15693_3, + NfcProtocolFelica, NfcProtocolMfUltralight, NfcProtocolMfClassic, NfcProtocolMfDesfire, From 49d65c098668bc115a2672c5686a62163698d3ba Mon Sep 17 00:00:00 2001 From: RebornedBrain <138568282+RebornedBrain@users.noreply.github.com> Date: Thu, 10 Aug 2023 16:56:12 +0300 Subject: [PATCH 134/149] Fixed tearing flags for NTAG21x (#2965) * Update nfc.c, iso14443_3a_listener.c, and mf_ultralight_listener.c Added more logging * Removed a lot of unnecessary logs to comply timings * Poller adjusted to read single tearing flag for NTAGs * Fix for proper saving of tear flags * CHECK_TEARING_CMD support for NTAGs According to datasheet NTAG21x don't support this command, but some of them do. Only 02 flag works (3E02), so now tearing command checks if SingleCounter feature is supported by the card, then it can be treated as NTAGxx and only flag=2 can be read * Duplicated gpio call removed * Added TODO for future work * Fix MF Classic emulation --- lib/drivers/st25r3916_reg.c | 1 - lib/nfc/nfc.c | 4 +- .../iso14443_3a/iso14443_3a_listener.c | 4 ++ .../mf_classic/mf_classic_listener.c | 1 + .../protocols/mf_ultralight/mf_ultralight.c | 2 +- .../mf_ultralight/mf_ultralight_listener.c | 53 +++++++++++++++---- .../mf_ultralight/mf_ultralight_poller.c | 6 ++- 7 files changed, 54 insertions(+), 17 deletions(-) diff --git a/lib/drivers/st25r3916_reg.c b/lib/drivers/st25r3916_reg.c index c03937176994..8ac4672383cb 100644 --- a/lib/drivers/st25r3916_reg.c +++ b/lib/drivers/st25r3916_reg.c @@ -133,7 +133,6 @@ void st25r3916_read_pta_mem(FuriHalSpiBusHandle* handle, uint8_t* buff, size_t l st25r3916_reg_tx_byte(handle, ST25R3916_PT_MEM_READ); furi_hal_spi_bus_rx(handle, tmp_buff, length + 1, 200); furi_hal_gpio_write(handle->cs, true); - furi_hal_gpio_write(handle->cs, true); memcpy(buff, tmp_buff + 1, length); } diff --git a/lib/nfc/nfc.c b/lib/nfc/nfc.c index 65e041255d9f..1473875a5f0c 100644 --- a/lib/nfc/nfc.c +++ b/lib/nfc/nfc.c @@ -95,7 +95,6 @@ static int32_t nfc_worker_listener(void* context) { while(true) { FHalNfcEvent event = f_hal_nfc_wait_event(F_HAL_NFC_EVENT_WAIT_FOREVER); if(event & FHalNfcEventAbortRequest) { - FURI_LOG_D(TAG, "Abort request received"); nfc_event.type = NfcEventTypeUserAbort; instance->callback(nfc_event, instance->context); break; @@ -105,7 +104,6 @@ static int32_t nfc_worker_listener(void* context) { instance->callback(nfc_event, instance->context); } if(event & FHalNfcEventFieldOff) { - FURI_LOG_T(TAG, "Field off"); nfc_event.type = NfcEventTypeFieldOff; instance->callback(nfc_event, instance->context); f_hal_nfc_listener_sleep(); @@ -124,7 +122,7 @@ static int32_t nfc_worker_listener(void* context) { if(command == NfcCommandStop) { break; } else if(command == NfcCommandReset) { - f_hal_nfc_listen_reset(); + //f_hal_nfc_listen_reset(); } } } diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c b/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c index 62c805dcabf8..46f3358d3c9d 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c @@ -114,6 +114,10 @@ NfcCommand iso14443_3a_listener_run(NfcGenericEvent event, void* context) { if(instance->callback) { command = instance->callback(instance->generic_event, instance->context); } + + if(command == NfcCommandReset) { + iso14443_3a_listener_sleep(instance); + } } } diff --git a/lib/nfc/protocols/mf_classic/mf_classic_listener.c b/lib/nfc/protocols/mf_classic/mf_classic_listener.c index bce8d2656475..9a375490365e 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_listener.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_listener.c @@ -170,6 +170,7 @@ static MfClassicListenerCommand instance->auth_state = MfClassicListenerAuthStateIdle; instance->state = MfClassicListenerStateAuthComplete; instance->comm_state = MfClassicListenerCommStateEncrypted; + command = MfClassicListenerCommandProcessed; if(instance->callback) { instance->mfc_event.type = MfClassicListenerEventTypeAuthContextFullCollected, diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight.c index 7f068dab7349..cc73c1e2149a 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight.c @@ -367,7 +367,7 @@ bool mf_ultralight_save(const MfUltralightData* data, FlipperFormat* ff) { } furi_string_printf(temp_str, "%s %d", MF_ULTRALIGHT_TEARING_KEY, i); if(!flipper_format_write_hex( - ff, furi_string_get_cstr(temp_str), data->tearing_flag->data, 1)) { + ff, furi_string_get_cstr(temp_str), data->tearing_flag[i].data, 1)) { counters_saved = false; break; } diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c index 41e8b0fd14f9..926f8f97e5db 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c @@ -68,6 +68,8 @@ static bool uint16_t pages_total = instance->data->pages_total; MfUltralightPageReadCommandData read_cmd_data = {}; + FURI_LOG_D(TAG, "CMD_READ"); + if(pages_total < start_page) { mf_ultralight_listener_send_short_resp(instance, MF_ULTRALIGHT_CMD_NACK); instance->state = MfUltraligthListenerStateIdle; @@ -106,6 +108,8 @@ static bool uint8_t start_page = bit_buffer_get_byte(buffer, 1); uint16_t pages_total = instance->data->pages_total; + FURI_LOG_D(TAG, "CMD_WRITE"); + if(pages_total < start_page) { mf_ultralight_listener_send_short_resp(instance, MF_ULTRALIGHT_CMD_NACK); instance->state = MfUltraligthListenerStateIdle; @@ -129,6 +133,8 @@ static bool mf_ultralight_listener_read_version_handler(MfUltralightListener* instance, BitBuffer* buffer) { UNUSED(buffer); + FURI_LOG_D(TAG, "CMD_GET_VERSION"); + bool command_processed = false; if((instance->features & MfUltralightFeatureSupportReadVersion)) { @@ -150,6 +156,8 @@ static bool mf_ultralight_listener_read_signature_handler( BitBuffer* buffer) { UNUSED(buffer); + FURI_LOG_D(TAG, "CMD_READ_SIG"); + bool command_processed = false; if((instance->features & MfUltralightFeatureSupportReadSignature)) { @@ -170,6 +178,8 @@ static bool mf_ultralight_listener_read_counter_handler(MfUltralightListener* instance, BitBuffer* buffer) { bool command_processed = false; + FURI_LOG_D(TAG, "CMD_READ_CNT"); + do { uint8_t counter_num = bit_buffer_get_byte(buffer, 1); if((instance->features & MfUltralightFeatureSupportReadCounter) == 0) break; @@ -179,9 +189,9 @@ static bool } } if(instance->config) { - if(!instance->config->access.nfc_cnt_en) { + /* if(!instance->config->access.nfc_cnt_en) { break; - } + }*/ if(instance->config->access.nfc_cnt_pwd_prot) { if(instance->auth_state != MfUltralightListenerAuthStateSuccess) { break; @@ -208,15 +218,24 @@ static bool mf_ultralight_listener_check_tearing_handler( BitBuffer* buffer) { bool command_processed = false; + FURI_LOG_D(TAG, "CMD_CHECK_TEARING"); + do { uint8_t tearing_flag_num = bit_buffer_get_byte(buffer, 1); - if((instance->features & MfUltralightFeatureSupportCheckTearingFlag) == 0) break; - if(tearing_flag_num > 2) break; - bit_buffer_set_size_bytes(instance->tx_buffer, 1); - bit_buffer_set_byte(instance->tx_buffer, 0, instance->data->tearing_flag->data[0]); - iso14443_3a_listener_send_standard_frame( - instance->iso14443_3a_listener, instance->tx_buffer); - command_processed = true; + if(instance->features & (MfUltralightFeatureSupportCheckTearingFlag | + MfUltralightFeatureSupportSingleCounter)) { + if((instance->features & MfUltralightFeatureSupportSingleCounter) && + (tearing_flag_num != 2)) { + break; + } + + bit_buffer_set_size_bytes(instance->tx_buffer, 1); + bit_buffer_set_byte( + instance->tx_buffer, 0, instance->data->tearing_flag->data[tearing_flag_num]); + iso14443_3a_listener_send_standard_frame( + instance->iso14443_3a_listener, instance->tx_buffer); + command_processed = true; + } } while(false); return command_processed; @@ -226,6 +245,8 @@ static bool mf_ultralight_listener_auth_handler(MfUltralightListener* instance, BitBuffer* buffer) { bool command_processed = false; + FURI_LOG_D(TAG, "CMD_AUTH"); + do { if((instance->features & MfUltralightFeatureSupportAuthentication) == 0) break; @@ -357,14 +378,24 @@ NfcCommand mf_ultralight_listener_run(NfcGenericEvent event, void* context) { for(size_t i = 0; i < COUNT_OF(mf_ultralight_command); i++) { if(bit_buffer_get_size(rx_buffer) != mf_ultralight_command[i].cmd_len_bits) continue; if(bit_buffer_get_byte(rx_buffer, 0) != mf_ultralight_command[i].cmd) continue; - cmd_processed = mf_ultralight_command[i].callback(instance, rx_buffer); - if(cmd_processed) break; + cmd_processed = mf_ultralight_command[i].callback( + instance, rx_buffer); //TODO make commands return enumed status, not just bool + if(cmd_processed) { //to make immediate NACK response when not processed + break; + } } if(!cmd_processed) { mf_ultralight_listener_send_short_resp(instance, MF_ULTRALIGHT_CMD_NACK); instance->state = MfUltraligthListenerStateIdle; instance->auth_state = MfUltralightListenerAuthStateIdle; + command = NfcCommandReset; } + } else if(iso14443_3a_event->type == Iso14443_3aListenerEventTypeReceivedData) { + command = NfcCommandReset; + } else if(iso14443_3a_event->type == Iso14443_3aListenerEventTypeFieldOff) { + command = NfcCommandReset; + } else if(iso14443_3a_event->type == Iso14443_3aListenerEventTypeHalted) { + command = NfcCommandReset; } return command; diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c index 30b6b1e47b31..e23aae5f6172 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c @@ -325,10 +325,14 @@ static NfcCommand mf_ultralight_poller_handler_read_counters(MfUltralightPoller* } static NfcCommand mf_ultralight_poller_handler_read_tearing_flags(MfUltralightPoller* instance) { - if(instance->feature_set & MfUltralightFeatureSupportCheckTearingFlag) { + if(instance->feature_set & + (MfUltralightFeatureSupportCheckTearingFlag | MfUltralightFeatureSupportSingleCounter)) { if(instance->tearing_flag_read == instance->tearing_flag_total) { instance->state = MfUltralightPollerStateTryDefaultPass; } else { + if(instance->feature_set & MfUltralightFeatureSupportSingleCounter) { + instance->tearing_flag_read = 2; + } FURI_LOG_D(TAG, "Reading tearing flag %d", instance->tearing_flag_read); instance->error = mf_ultralight_poller_async_read_tearing_flag( instance, From 643c285c3d93cf686d8bf940221da1d8eeaef2cd Mon Sep 17 00:00:00 2001 From: RebornedBrain <138568282+RebornedBrain@users.noreply.github.com> Date: Fri, 11 Aug 2023 17:06:51 +0300 Subject: [PATCH 135/149] [FL-3446] Feature check adjustment and nesting removal (#2977) * Update nfc.c, iso14443_3a_listener.c, and mf_ultralight_listener.c Added more logging * Removed a lot of unnecessary logs to comply timings * Poller adjusted to read single tearing flag for NTAGs * Fix for proper saving of tear flags * CHECK_TEARING_CMD support for NTAGs According to datasheet NTAG21x don't support this command, but some of them do. Only 02 flag works (3E02), so now tearing command checks if SingleCounter feature is supported by the card, then it can be treated as NTAGxx and only flag=2 can be read * Duplicated gpio call removed * Added TODO for future work * Fix MF Classic emulation * Function mf_ultralight_support_feature added to API This function checks whether current Ultralight instance supports feature, mentioned as a second paramete. * Adjusted listener and poller with new function and removed some nesting --- firmware/targets/f7/api_symbols.csv | 3 +- .../protocols/mf_ultralight/mf_ultralight.c | 4 + .../protocols/mf_ultralight/mf_ultralight.h | 2 + .../mf_ultralight/mf_ultralight_listener.c | 57 +++++++------- .../mf_ultralight/mf_ultralight_poller.c | 75 +++++++++++-------- 5 files changed, 83 insertions(+), 58 deletions(-) diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 74907535ddf1..637718068308 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,+,35.0,, +Version,+,36.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -2138,6 +2138,7 @@ Function,+,mf_ultralight_poller_write_page,MfUltralightError,"Nfc*, uint16_t, Mf Function,+,mf_ultralight_reset,void,MfUltralightData* Function,+,mf_ultralight_save,_Bool,"const MfUltralightData*, FlipperFormat*" Function,+,mf_ultralight_set_uid,_Bool,"MfUltralightData*, const uint8_t*, size_t" +Function,+,mf_ultralight_support_feature,_Bool,"const uint32_t, const uint32_t" Function,+,mf_ultralight_verify,_Bool,"MfUltralightData*, const FuriString*" Function,-,mkdtemp,char*,char* Function,-,mkostemp,int,"char*, int" diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight.c index cc73c1e2149a..578141ce3fc4 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight.c @@ -535,6 +535,10 @@ uint16_t mf_ultralight_get_config_page_num(MfUltralightType type) { return mf_ultralight_features[type].config_page; } +bool mf_ultralight_support_feature(const uint32_t feature_set, const uint32_t features_to_check) { + return (feature_set & features_to_check) != 0; +} + bool mf_ultralight_get_config_page(const MfUltralightData* data, MfUltralightConfigPages** config) { furi_assert(data); furi_assert(config); diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h index 4fca4cda30ce..bad5e0a0536b 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h @@ -200,6 +200,8 @@ uint32_t mf_ultralight_get_feature_support_set(MfUltralightType type); uint16_t mf_ultralight_get_config_page_num(MfUltralightType type); +bool mf_ultralight_support_feature(const uint32_t feature_set, const uint32_t features_to_check); + bool mf_ultralight_get_config_page(const MfUltralightData* data, MfUltralightConfigPages** config); bool mf_ultralight_is_all_data_read(const MfUltralightData* data); diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c index 926f8f97e5db..661a6288116f 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c @@ -137,7 +137,7 @@ static bool bool command_processed = false; - if((instance->features & MfUltralightFeatureSupportReadVersion)) { + if(mf_ultralight_support_feature(instance->features, MfUltralightFeatureSupportReadVersion)) { bit_buffer_copy_bytes( instance->tx_buffer, (uint8_t*)&instance->data->version, sizeof(MfUltralightVersion)); iso14443_3a_listener_send_standard_frame( @@ -160,7 +160,7 @@ static bool mf_ultralight_listener_read_signature_handler( bool command_processed = false; - if((instance->features & MfUltralightFeatureSupportReadSignature)) { + if(mf_ultralight_support_feature(instance->features, MfUltralightFeatureSupportReadSignature)) { bit_buffer_copy_bytes( instance->tx_buffer, instance->data->signature.data, sizeof(MfUltralightSignature)); iso14443_3a_listener_send_standard_frame( @@ -182,16 +182,16 @@ static bool do { uint8_t counter_num = bit_buffer_get_byte(buffer, 1); - if((instance->features & MfUltralightFeatureSupportReadCounter) == 0) break; - if(instance->features & MfUltralightFeatureSupportSingleCounter) { - if(counter_num != 2) { - break; - } - } + if(!mf_ultralight_support_feature( + instance->features, MfUltralightFeatureSupportReadCounter)) + break; + + if(mf_ultralight_support_feature( + instance->features, MfUltralightFeatureSupportSingleCounter) && + (counter_num != 2)) + break; + if(instance->config) { - /* if(!instance->config->access.nfc_cnt_en) { - break; - }*/ if(instance->config->access.nfc_cnt_pwd_prot) { if(instance->auth_state != MfUltralightListenerAuthStateSuccess) { break; @@ -222,20 +222,25 @@ static bool mf_ultralight_listener_check_tearing_handler( do { uint8_t tearing_flag_num = bit_buffer_get_byte(buffer, 1); - if(instance->features & (MfUltralightFeatureSupportCheckTearingFlag | - MfUltralightFeatureSupportSingleCounter)) { - if((instance->features & MfUltralightFeatureSupportSingleCounter) && - (tearing_flag_num != 2)) { - break; - } - - bit_buffer_set_size_bytes(instance->tx_buffer, 1); - bit_buffer_set_byte( - instance->tx_buffer, 0, instance->data->tearing_flag->data[tearing_flag_num]); - iso14443_3a_listener_send_standard_frame( - instance->iso14443_3a_listener, instance->tx_buffer); - command_processed = true; + if(!mf_ultralight_support_feature( + instance->features, + MfUltralightFeatureSupportCheckTearingFlag | + MfUltralightFeatureSupportSingleCounter)) { + break; } + if(mf_ultralight_support_feature( + instance->features, MfUltralightFeatureSupportSingleCounter) && + (tearing_flag_num != 2)) { + break; + } + + bit_buffer_set_size_bytes(instance->tx_buffer, 1); + bit_buffer_set_byte( + instance->tx_buffer, 0, instance->data->tearing_flag->data[tearing_flag_num]); + iso14443_3a_listener_send_standard_frame( + instance->iso14443_3a_listener, instance->tx_buffer); + command_processed = true; + } while(false); return command_processed; @@ -248,7 +253,9 @@ static bool FURI_LOG_D(TAG, "CMD_AUTH"); do { - if((instance->features & MfUltralightFeatureSupportAuthentication) == 0) break; + if(!mf_ultralight_support_feature( + instance->features, MfUltralightFeatureSupportAuthentication)) + break; const uint8_t* rx_data = bit_buffer_get_data(buffer); MfUltralightAuthPassword password = {}; diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c index e23aae5f6172..ead34defc7f1 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c @@ -276,7 +276,8 @@ static NfcCommand mf_ultralight_poller_handler_get_feature_set(MfUltralightPolle static NfcCommand mf_ultralight_poller_handler_read_signature(MfUltralightPoller* instance) { MfUltralightPollerState next_state = MfUltralightPollerStateAuth; - if(instance->feature_set & MfUltralightFeatureSupportReadSignature) { + if(mf_ultralight_support_feature( + instance->feature_set, MfUltralightFeatureSupportReadSignature)) { FURI_LOG_D(TAG, "Reading signature"); instance->error = mf_ultralight_poller_async_read_signature(instance, &instance->data->signature); @@ -293,44 +294,49 @@ static NfcCommand mf_ultralight_poller_handler_read_signature(MfUltralightPoller } static NfcCommand mf_ultralight_poller_handler_read_counters(MfUltralightPoller* instance) { - if(instance->feature_set & MfUltralightFeatureSupportReadCounter) { - if(mf_ultralight_is_counter_configured(instance->data)) { - if(instance->feature_set & MfUltralightFeatureSupportSingleCounter) { - instance->counters_read = 2; - } - if(instance->counters_read == instance->counters_total) { - instance->state = MfUltralightPollerStateReadTearingFlags; - } else { - FURI_LOG_D(TAG, "Reading counter %d", instance->counters_read); - instance->error = mf_ultralight_poller_async_read_counter( - instance, - instance->counters_read, - &instance->data->counter[instance->counters_read]); - if(instance->error != MfUltralightErrorNone) { - FURI_LOG_D(TAG, "Failed to read %d counter", instance->counters_read); - instance->state = MfUltralightPollerStateReadTearingFlags; - } else { - instance->counters_read++; - } - } - } else { + do { + if(!mf_ultralight_support_feature( + instance->feature_set, MfUltralightFeatureSupportReadCounter) || + !mf_ultralight_is_counter_configured(instance->data)) { + FURI_LOG_D(TAG, "Skip reading counters"); instance->state = MfUltralightPollerStateReadTearingFlags; + break; } - } else { - FURI_LOG_D(TAG, "Skip reading counters"); - instance->state = MfUltralightPollerStateReadTearingFlags; - } + + if(instance->counters_read == instance->counters_total) { + instance->state = MfUltralightPollerStateReadTearingFlags; + break; + } + + if(mf_ultralight_support_feature( + instance->feature_set, MfUltralightFeatureSupportSingleCounter)) { + instance->counters_read = 2; + } + + FURI_LOG_D(TAG, "Reading counter %d", instance->counters_read); + instance->error = mf_ultralight_poller_async_read_counter( + instance, instance->counters_read, &instance->data->counter[instance->counters_read]); + if(instance->error != MfUltralightErrorNone) { + FURI_LOG_D(TAG, "Failed to read %d counter", instance->counters_read); + instance->state = MfUltralightPollerStateReadTearingFlags; + } else { + instance->counters_read++; + } + + } while(false); return NfcCommandContinue; } static NfcCommand mf_ultralight_poller_handler_read_tearing_flags(MfUltralightPoller* instance) { - if(instance->feature_set & - (MfUltralightFeatureSupportCheckTearingFlag | MfUltralightFeatureSupportSingleCounter)) { + if(mf_ultralight_support_feature( + instance->feature_set, + MfUltralightFeatureSupportCheckTearingFlag | MfUltralightFeatureSupportSingleCounter)) { if(instance->tearing_flag_read == instance->tearing_flag_total) { instance->state = MfUltralightPollerStateTryDefaultPass; } else { - if(instance->feature_set & MfUltralightFeatureSupportSingleCounter) { + if(mf_ultralight_support_feature( + instance->feature_set, MfUltralightFeatureSupportSingleCounter)) { instance->tearing_flag_read = 2; } FURI_LOG_D(TAG, "Reading tearing flag %d", instance->tearing_flag_read); @@ -355,7 +361,8 @@ static NfcCommand mf_ultralight_poller_handler_read_tearing_flags(MfUltralightPo static NfcCommand mf_ultralight_poller_handler_auth(MfUltralightPoller* instance) { NfcCommand command = NfcCommandContinue; - if(instance->feature_set & MfUltralightFeatureSupportAuthentication) { + if(mf_ultralight_support_feature( + instance->feature_set, MfUltralightFeatureSupportAuthentication)) { instance->mfu_event.type = MfUltralightPollerEventTypeAuthRequest; command = instance->callback(instance->general_event, instance->context); @@ -430,7 +437,11 @@ static NfcCommand mf_ultralight_poller_handler_read_pages(MfUltralightPoller* in } static NfcCommand mf_ultralight_poller_handler_try_default_pass(MfUltralightPoller* instance) { - if(instance->feature_set & MfUltralightFeatureSupportAuthentication) { + do { + if(!mf_ultralight_support_feature( + instance->feature_set, MfUltralightFeatureSupportAuthentication)) + break; + MfUltralightConfigPages* config = NULL; mf_ultralight_get_config_page(instance->data, &config); if(instance->auth_context.auth_success) { @@ -454,7 +465,7 @@ static NfcCommand mf_ultralight_poller_handler_try_default_pass(MfUltralightPoll config->auth0 = instance->pages_read; config->access.prot = true; } - } + } while(false); instance->state = MfUltralightPollerStateReadSuccess; return NfcCommandContinue; From 5fbdf34de7dcd10c7c7ecf4f03531ae9c6b7676e Mon Sep 17 00:00:00 2001 From: RebornedBrain <138568282+RebornedBrain@users.noreply.github.com> Date: Fri, 18 Aug 2023 13:01:02 +0300 Subject: [PATCH 136/149] Ultralight commands fixed and reset is done on the nfc level (#2989) * Update nfc.c, iso14443_3a_listener.c, and mf_ultralight_listener.c Added more logging * Removed a lot of unnecessary logs to comply timings * Poller adjusted to read single tearing flag for NTAGs * Fix for proper saving of tear flags * CHECK_TEARING_CMD support for NTAGs According to datasheet NTAG21x don't support this command, but some of them do. Only 02 flag works (3E02), so now tearing command checks if SingleCounter feature is supported by the card, then it can be treated as NTAGxx and only flag=2 can be read * Duplicated gpio call removed * Added TODO for future work * Fix MF Classic emulation * Function mf_ultralight_support_feature added to API This function checks whether current Ultralight instance supports feature, mentioned as a second paramete. * Adjusted listener and poller with new function and removed some nesting * NFC layer adjustments Changed function call from f_hal_nfc_listener_sleep to nfc_listener_sleep for Field Off event Added new event FHalNfcEventTxEnd where trasmitter state is now changed Reset after rx command processing is now done only when we don't send anything * iso14443_3a_listener cleanup to avoid duplicate calls and race conditions * Added result statuses for mfu commands and command signature changed, now it returns status instead of bool * mf_ultralight_listener_run adjusted to process statuses * Comments adjusted according bits set * Renamed enum type and values --- firmware/targets/f7/furi_hal/f_hal_nfc.c | 2 +- lib/nfc/nfc.c | 11 ++- .../iso14443_3a/iso14443_3a_listener.c | 22 ++---- .../mf_ultralight/mf_ultralight_listener.c | 78 ++++++++++--------- 4 files changed, 56 insertions(+), 57 deletions(-) diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc.c b/firmware/targets/f7/furi_hal/f_hal_nfc.c index 048ccbb9a5c0..45edc63930cf 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfc.c +++ b/firmware/targets/f7/furi_hal/f_hal_nfc.c @@ -364,7 +364,7 @@ FHalNfcError f_hal_nfc_set_mode(FHalNfcMode mode, FHalNfcBitrate bitrate) { // 1st stage zero = 600kHz, 3rd stage zero = 200 kHz st25r3916_write_reg(handle, ST25R3916_REG_RX_CONF1, ST25R3916_REG_RX_CONF1_z600k); - // AGC enabled, ratio 3:1, squelch after TX + // AGC enabled, ratio 6:1, squelch after TX st25r3916_write_reg( handle, ST25R3916_REG_RX_CONF2, diff --git a/lib/nfc/nfc.c b/lib/nfc/nfc.c index 1473875a5f0c..1cbb4c994c1c 100644 --- a/lib/nfc/nfc.c +++ b/lib/nfc/nfc.c @@ -106,13 +106,16 @@ static int32_t nfc_worker_listener(void* context) { if(event & FHalNfcEventFieldOff) { nfc_event.type = NfcEventTypeFieldOff; instance->callback(nfc_event, instance->context); - f_hal_nfc_listener_sleep(); + nfc_listener_sleep(instance); } if(event & FHalNfcEventListenerActive) { f_hal_nfc_listener_disable_auto_col_res(); nfc_event.type = NfcEventTypeListenerActivated; instance->callback(nfc_event, instance->context); } + if(event & FHalNfcEventTxEnd) { + instance->comm_state = NfcCommStateIdle; + } if(event & FHalNfcEventRxEnd) { nfc_event.type = NfcEventTypeRxEnd; f_hal_nfc_poller_rx( @@ -121,8 +124,8 @@ static int32_t nfc_worker_listener(void* context) { command = instance->callback(nfc_event, instance->context); if(command == NfcCommandStop) { break; - } else if(command == NfcCommandReset) { - //f_hal_nfc_listen_reset(); + } else if(command == NfcCommandReset && instance->comm_state != NfcCommStateWaitTxEnd) { + nfc_listener_sleep(instance); } } } @@ -364,6 +367,8 @@ NfcError nfc_listener_tx(Nfc* instance, const BitBuffer* tx_buffer) { if(error != FHalNfcErrorNone) { FURI_LOG_E(TAG, "Failed in listener TX"); ret = nfc_process_hal_error(error); + } else { + instance->comm_state = NfcCommStateWaitTxEnd; } return ret; diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c b/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c index 46f3358d3c9d..16e5ac294dd1 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c @@ -86,22 +86,14 @@ NfcCommand iso14443_3a_listener_run(NfcGenericEvent event, void* context) { NfcEvent* nfc_event = event.data; NfcCommand command = NfcCommandContinue; - if(nfc_event->type == NfcEventTypeFieldOff) { - if(instance->callback) { - instance->iso14443_3a_event.type = Iso14443_3aListenerEventTypeFieldOff; - command = instance->callback(instance->generic_event, instance->context); - } - iso14443_3a_listener_sleep(instance); - } else if(nfc_event->type == NfcEventTypeListenerActivated) { + if(nfc_event->type == NfcEventTypeListenerActivated) { instance->state = Iso14443_3aListenerStateActive; + } else if(nfc_event->type == NfcEventTypeFieldOff) { + command = NfcCommandReset; + instance->state = Iso14443_3aListenerStateIdle; } else if(nfc_event->type == NfcEventTypeRxEnd) { if(iso14443_3a_listener_halt_received(nfc_event->data.buffer)) { - iso14443_3a_listener_sleep(instance); - instance->state = Iso14443_3aListenerStateIdle; - if(instance->callback) { - instance->iso14443_3a_event.type = Iso14443_3aListenerEventTypeHalted; - command = instance->callback(instance->generic_event, instance->context); - } + command = NfcCommandReset; } else { if(iso14443_crc_check(Iso14443CrcTypeA, nfc_event->data.buffer)) { instance->iso14443_3a_event.type = @@ -114,10 +106,6 @@ NfcCommand iso14443_3a_listener_run(NfcGenericEvent event, void* context) { if(instance->callback) { command = instance->callback(instance->generic_event, instance->context); } - - if(command == NfcCommandReset) { - iso14443_3a_listener_sleep(instance); - } } } diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c index 661a6288116f..3ff25dbfa88f 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c @@ -14,7 +14,15 @@ typedef enum { MfUltralightListenerAccessTypeWrite, } MfUltralightListenerAccessType; -typedef bool (*MfUltralightListenerCommandCallback)(MfUltralightListener* instance, BitBuffer* buf); +typedef enum { + MfUltralightCommandNotFound, + MfUltralightCommandProcessed, + MfUltralightCommandNotProcessedNAK, + MfUltralightCommandNotProcessedSilent, +} MfUltralightCommand; + +typedef MfUltralightCommand ( + *MfUltralightListenerCommandCallback)(MfUltralightListener* instance, BitBuffer* buf); typedef struct { uint8_t cmd; @@ -61,14 +69,13 @@ static void mf_ultralight_listener_send_short_resp(MfUltralightListener* instanc iso14443_3a_listener_tx(instance->iso14443_3a_listener, instance->tx_buffer); }; -static bool +static MfUltralightCommand mf_ultralight_listener_read_page_handler(MfUltralightListener* instance, BitBuffer* buffer) { - bool command_processed = false; uint8_t start_page = bit_buffer_get_byte(buffer, 1); uint16_t pages_total = instance->data->pages_total; MfUltralightPageReadCommandData read_cmd_data = {}; - FURI_LOG_D(TAG, "CMD_READ"); + FURI_LOG_D(TAG, "CMD_READ: %d", start_page); if(pages_total < start_page) { mf_ultralight_listener_send_short_resp(instance, MF_ULTRALIGHT_CMD_NACK); @@ -97,14 +104,12 @@ static bool iso14443_3a_listener_send_standard_frame( instance->iso14443_3a_listener, instance->tx_buffer); } - command_processed = true; - return command_processed; + return MfUltralightCommandProcessed; } -static bool +static MfUltralightCommand mf_ultralight_listener_write_page_handler(MfUltralightListener* instance, BitBuffer* buffer) { - bool command_processed = false; uint8_t start_page = bit_buffer_get_byte(buffer, 1); uint16_t pages_total = instance->data->pages_total; @@ -124,19 +129,16 @@ static bool memcpy(instance->data->page[start_page].data, &rx_data[2], sizeof(MfUltralightPage)); mf_ultralight_listener_send_short_resp(instance, MF_ULTRALIGHT_CMD_ACK); } - command_processed = true; - return command_processed; + return MfUltralightCommandProcessed; } -static bool +static MfUltralightCommand mf_ultralight_listener_read_version_handler(MfUltralightListener* instance, BitBuffer* buffer) { UNUSED(buffer); FURI_LOG_D(TAG, "CMD_GET_VERSION"); - bool command_processed = false; - if(mf_ultralight_support_feature(instance->features, MfUltralightFeatureSupportReadVersion)) { bit_buffer_copy_bytes( instance->tx_buffer, (uint8_t*)&instance->data->version, sizeof(MfUltralightVersion)); @@ -146,20 +148,17 @@ static bool iso14443_3a_listener_sleep(instance->iso14443_3a_listener); instance->state = MfUltraligthListenerStateIdle; } - command_processed = true; - return command_processed; + return MfUltralightCommandProcessed; } -static bool mf_ultralight_listener_read_signature_handler( +static MfUltralightCommand mf_ultralight_listener_read_signature_handler( MfUltralightListener* instance, BitBuffer* buffer) { UNUSED(buffer); FURI_LOG_D(TAG, "CMD_READ_SIG"); - bool command_processed = false; - if(mf_ultralight_support_feature(instance->features, MfUltralightFeatureSupportReadSignature)) { bit_buffer_copy_bytes( instance->tx_buffer, instance->data->signature.data, sizeof(MfUltralightSignature)); @@ -169,12 +168,11 @@ static bool mf_ultralight_listener_read_signature_handler( iso14443_3a_listener_sleep(instance->iso14443_3a_listener); instance->state = MfUltraligthListenerStateIdle; } - command_processed = true; - return command_processed; + return MfUltralightCommandProcessed; } -static bool +static MfUltralightCommand mf_ultralight_listener_read_counter_handler(MfUltralightListener* instance, BitBuffer* buffer) { bool command_processed = false; @@ -210,14 +208,16 @@ static bool command_processed = true; } while(false); - return command_processed; + //TODO: Remove command_processed bool and return status directly, but for test it's OK for now + return command_processed ? MfUltralightCommandProcessed : MfUltralightCommandNotProcessedNAK; } -static bool mf_ultralight_listener_check_tearing_handler( +static MfUltralightCommand mf_ultralight_listener_check_tearing_handler( MfUltralightListener* instance, BitBuffer* buffer) { bool command_processed = false; + UNUSED(buffer); FURI_LOG_D(TAG, "CMD_CHECK_TEARING"); do { @@ -243,10 +243,10 @@ static bool mf_ultralight_listener_check_tearing_handler( } while(false); - return command_processed; + return command_processed ? MfUltralightCommandProcessed : MfUltralightCommandNotProcessedNAK; } -static bool +static MfUltralightCommand mf_ultralight_listener_auth_handler(MfUltralightListener* instance, BitBuffer* buffer) { bool command_processed = false; @@ -276,7 +276,8 @@ static bool command_processed = true; } while(false); - return command_processed; + return command_processed ? MfUltralightCommandProcessed : + MfUltralightCommandNotProcessedSilent; } static const MfUltralightListenerCmdHandler mf_ultralight_command[] = { @@ -381,21 +382,26 @@ NfcCommand mf_ultralight_listener_run(NfcGenericEvent event, void* context) { NfcCommand command = NfcCommandContinue; if(iso14443_3a_event->type == Iso14443_3aListenerEventTypeReceivedStandardFrame) { - bool cmd_processed = false; + MfUltralightCommand status = MfUltralightCommandNotFound; + size_t size = bit_buffer_get_size(rx_buffer); + uint8_t cmd = bit_buffer_get_byte(rx_buffer, 0); + for(size_t i = 0; i < COUNT_OF(mf_ultralight_command); i++) { - if(bit_buffer_get_size(rx_buffer) != mf_ultralight_command[i].cmd_len_bits) continue; - if(bit_buffer_get_byte(rx_buffer, 0) != mf_ultralight_command[i].cmd) continue; - cmd_processed = mf_ultralight_command[i].callback( - instance, rx_buffer); //TODO make commands return enumed status, not just bool - if(cmd_processed) { //to make immediate NACK response when not processed - break; - } + if(size != mf_ultralight_command[i].cmd_len_bits) continue; + if(cmd != mf_ultralight_command[i].cmd) continue; + status = mf_ultralight_command[i].callback(instance, rx_buffer); + + if(status != MfUltralightCommandNotFound) break; } - if(!cmd_processed) { - mf_ultralight_listener_send_short_resp(instance, MF_ULTRALIGHT_CMD_NACK); + + if(status != MfUltralightCommandProcessed) { instance->state = MfUltraligthListenerStateIdle; instance->auth_state = MfUltralightListenerAuthStateIdle; command = NfcCommandReset; + + if(status == MfUltralightCommandNotProcessedNAK) { + mf_ultralight_listener_send_short_resp(instance, MF_ULTRALIGHT_CMD_NACK); + } } } else if(iso14443_3a_event->type == Iso14443_3aListenerEventTypeReceivedData) { command = NfcCommandReset; From fe33eac7ba393d4302603a76f5fa4672b93aa876 Mon Sep 17 00:00:00 2001 From: RebornedBrain <138568282+RebornedBrain@users.noreply.github.com> Date: Mon, 21 Aug 2023 20:38:31 +0300 Subject: [PATCH 137/149] Ultralight commands adjustments (#2997) * Update nfc.c, iso14443_3a_listener.c, and mf_ultralight_listener.c Added more logging * Removed a lot of unnecessary logs to comply timings * Poller adjusted to read single tearing flag for NTAGs * Fix for proper saving of tear flags * CHECK_TEARING_CMD support for NTAGs According to datasheet NTAG21x don't support this command, but some of them do. Only 02 flag works (3E02), so now tearing command checks if SingleCounter feature is supported by the card, then it can be treated as NTAGxx and only flag=2 can be read * Duplicated gpio call removed * Added TODO for future work * Fix MF Classic emulation * Function mf_ultralight_support_feature added to API This function checks whether current Ultralight instance supports feature, mentioned as a second paramete. * Adjusted listener and poller with new function and removed some nesting * NFC layer adjustments Changed function call from f_hal_nfc_listener_sleep to nfc_listener_sleep for Field Off event Added new event FHalNfcEventTxEnd where trasmitter state is now changed Reset after rx command processing is now done only when we don't send anything * iso14443_3a_listener cleanup to avoid duplicate calls and race conditions * Added result statuses for mfu commands and command signature changed, now it returns status instead of bool * mf_ultralight_listener_run adjusted to process statuses * Comments adjusted according bits set * Renamed enum type and values * Command adjustments Cleaned up all commands. Read and write commands send their NAKs according to status * f_hal_nfc_listener_tx is now blocking --- firmware/targets/f7/furi_hal/f_hal_nfc.c | 4 +- lib/nfc/nfc.c | 7 +--- .../iso14443_3a/iso14443_3a_listener_i.c | 9 ---- .../mf_ultralight/mf_ultralight_listener.c | 42 +++++++++---------- 4 files changed, 24 insertions(+), 38 deletions(-) diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc.c b/firmware/targets/f7/furi_hal/f_hal_nfc.c index 45edc63930cf..59373f2a4201 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfc.c +++ b/firmware/targets/f7/furi_hal/f_hal_nfc.c @@ -697,7 +697,6 @@ FHalNfcError f_hal_nfc_poller_tx(const uint8_t* tx_data, size_t tx_bits) { FHalNfcError f_hal_nfc_listener_tx(const uint8_t* tx_data, size_t tx_bits) { furi_assert(tx_data); - FHalNfcError err = FHalNfcErrorNone; FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; st25r3916_direct_cmd(handle, ST25R3916_CMD_CLEAR_FIFO); @@ -705,7 +704,8 @@ FHalNfcError f_hal_nfc_listener_tx(const uint8_t* tx_data, size_t tx_bits) { st25r3916_write_fifo(handle, tx_data, tx_bits); st25r3916_direct_cmd(handle, ST25R3916_CMD_TRANSMIT_WITHOUT_CRC); - return err; + bool tx_end = f_hal_nfc_event_wait_for_specific_irq(handle, ST25R3916_IRQ_MASK_TXE, 10); + return tx_end ? FHalNfcErrorNone : FHalNfcErrorCommunicationTimeout; } FHalNfcError f_hal_nfc_poller_rx(uint8_t* rx_data, size_t rx_data_size, size_t* rx_bits) { diff --git a/lib/nfc/nfc.c b/lib/nfc/nfc.c index 1cbb4c994c1c..ea620fe26057 100644 --- a/lib/nfc/nfc.c +++ b/lib/nfc/nfc.c @@ -113,9 +113,6 @@ static int32_t nfc_worker_listener(void* context) { nfc_event.type = NfcEventTypeListenerActivated; instance->callback(nfc_event, instance->context); } - if(event & FHalNfcEventTxEnd) { - instance->comm_state = NfcCommStateIdle; - } if(event & FHalNfcEventRxEnd) { nfc_event.type = NfcEventTypeRxEnd; f_hal_nfc_poller_rx( @@ -124,7 +121,7 @@ static int32_t nfc_worker_listener(void* context) { command = instance->callback(nfc_event, instance->context); if(command == NfcCommandStop) { break; - } else if(command == NfcCommandReset && instance->comm_state != NfcCommStateWaitTxEnd) { + } else if(command == NfcCommandReset) { nfc_listener_sleep(instance); } } @@ -367,8 +364,6 @@ NfcError nfc_listener_tx(Nfc* instance, const BitBuffer* tx_buffer) { if(error != FHalNfcErrorNone) { FURI_LOG_E(TAG, "Failed in listener TX"); ret = nfc_process_hal_error(error); - } else { - instance->comm_state = NfcCommStateWaitTxEnd; } return ret; diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener_i.c b/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener_i.c index 76b3b341a9d4..2c4699aac5ae 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener_i.c +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener_i.c @@ -18,15 +18,6 @@ static Iso14443_3aError iso14443_3a_listener_process_nfc_error(NfcError error) { return ret; } -Iso14443_3aError iso14443_3a_listener_sleep(Iso14443_3aListener* instance) { - furi_assert(instance); - - NfcError error = nfc_listener_sleep(instance->nfc); - instance->state = Iso14443_3aListenerStateIdle; - - return iso14443_3a_listener_process_nfc_error(error); -} - Iso14443_3aError iso14443_3a_listener_tx(Iso14443_3aListener* instance, const BitBuffer* tx_buffer) { furi_assert(instance); diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c index 3ff25dbfa88f..a2a2584c2208 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c @@ -74,16 +74,15 @@ static MfUltralightCommand uint8_t start_page = bit_buffer_get_byte(buffer, 1); uint16_t pages_total = instance->data->pages_total; MfUltralightPageReadCommandData read_cmd_data = {}; + MfUltralightCommand status = MfUltralightCommandNotProcessedNAK; FURI_LOG_D(TAG, "CMD_READ: %d", start_page); if(pages_total < start_page) { - mf_ultralight_listener_send_short_resp(instance, MF_ULTRALIGHT_CMD_NACK); instance->state = MfUltraligthListenerStateIdle; instance->auth_state = MfUltralightListenerAuthStateIdle; } else if(!mf_ultralight_listener_check_access( instance, start_page, MfUltralightListenerAccessTypeRead)) { - mf_ultralight_listener_send_short_resp(instance, MF_ULTRALIGHT_CMD_NACK); instance->state = MfUltraligthListenerStateIdle; instance->auth_state = MfUltralightListenerAuthStateIdle; } else { @@ -103,39 +102,41 @@ static MfUltralightCommand sizeof(MfUltralightPageReadCommandData)); iso14443_3a_listener_send_standard_frame( instance->iso14443_3a_listener, instance->tx_buffer); + status = MfUltralightCommandProcessed; } - return MfUltralightCommandProcessed; + return status; } static MfUltralightCommand mf_ultralight_listener_write_page_handler(MfUltralightListener* instance, BitBuffer* buffer) { uint8_t start_page = bit_buffer_get_byte(buffer, 1); uint16_t pages_total = instance->data->pages_total; + MfUltralightCommand status = MfUltralightCommandNotProcessedNAK; FURI_LOG_D(TAG, "CMD_WRITE"); if(pages_total < start_page) { - mf_ultralight_listener_send_short_resp(instance, MF_ULTRALIGHT_CMD_NACK); instance->state = MfUltraligthListenerStateIdle; instance->auth_state = MfUltralightListenerAuthStateIdle; } else if(!mf_ultralight_listener_check_access( instance, start_page, MfUltralightListenerAccessTypeWrite)) { - mf_ultralight_listener_send_short_resp(instance, MF_ULTRALIGHT_CMD_NACK); instance->state = MfUltraligthListenerStateIdle; instance->auth_state = MfUltralightListenerAuthStateIdle; } else { const uint8_t* rx_data = bit_buffer_get_data(buffer); memcpy(instance->data->page[start_page].data, &rx_data[2], sizeof(MfUltralightPage)); mf_ultralight_listener_send_short_resp(instance, MF_ULTRALIGHT_CMD_ACK); + status = MfUltralightCommandProcessed; } - return MfUltralightCommandProcessed; + return status; } static MfUltralightCommand mf_ultralight_listener_read_version_handler(MfUltralightListener* instance, BitBuffer* buffer) { UNUSED(buffer); + MfUltralightCommand status = MfUltralightCommandNotProcessedSilent; FURI_LOG_D(TAG, "CMD_GET_VERSION"); @@ -144,18 +145,19 @@ static MfUltralightCommand instance->tx_buffer, (uint8_t*)&instance->data->version, sizeof(MfUltralightVersion)); iso14443_3a_listener_send_standard_frame( instance->iso14443_3a_listener, instance->tx_buffer); + status = MfUltralightCommandProcessed; } else { - iso14443_3a_listener_sleep(instance->iso14443_3a_listener); instance->state = MfUltraligthListenerStateIdle; } - return MfUltralightCommandProcessed; + return status; } static MfUltralightCommand mf_ultralight_listener_read_signature_handler( MfUltralightListener* instance, BitBuffer* buffer) { UNUSED(buffer); + MfUltralightCommand status = MfUltralightCommandNotProcessedSilent; FURI_LOG_D(TAG, "CMD_READ_SIG"); @@ -164,17 +166,17 @@ static MfUltralightCommand mf_ultralight_listener_read_signature_handler( instance->tx_buffer, instance->data->signature.data, sizeof(MfUltralightSignature)); iso14443_3a_listener_send_standard_frame( instance->iso14443_3a_listener, instance->tx_buffer); + status = MfUltralightCommandProcessed; } else { - iso14443_3a_listener_sleep(instance->iso14443_3a_listener); instance->state = MfUltraligthListenerStateIdle; } - return MfUltralightCommandProcessed; + return status; } static MfUltralightCommand mf_ultralight_listener_read_counter_handler(MfUltralightListener* instance, BitBuffer* buffer) { - bool command_processed = false; + MfUltralightCommand status = MfUltralightCommandNotProcessedNAK; FURI_LOG_D(TAG, "CMD_READ_CNT"); @@ -205,17 +207,16 @@ static MfUltralightCommand bit_buffer_copy_bytes(instance->tx_buffer, cnt_value, sizeof(cnt_value)); iso14443_3a_listener_send_standard_frame( instance->iso14443_3a_listener, instance->tx_buffer); - command_processed = true; + status = MfUltralightCommandProcessed; } while(false); - //TODO: Remove command_processed bool and return status directly, but for test it's OK for now - return command_processed ? MfUltralightCommandProcessed : MfUltralightCommandNotProcessedNAK; + return status; } static MfUltralightCommand mf_ultralight_listener_check_tearing_handler( MfUltralightListener* instance, BitBuffer* buffer) { - bool command_processed = false; + MfUltralightCommand status = MfUltralightCommandNotProcessedNAK; UNUSED(buffer); FURI_LOG_D(TAG, "CMD_CHECK_TEARING"); @@ -239,16 +240,16 @@ static MfUltralightCommand mf_ultralight_listener_check_tearing_handler( instance->tx_buffer, 0, instance->data->tearing_flag->data[tearing_flag_num]); iso14443_3a_listener_send_standard_frame( instance->iso14443_3a_listener, instance->tx_buffer); - command_processed = true; + status = MfUltralightCommandProcessed; } while(false); - return command_processed ? MfUltralightCommandProcessed : MfUltralightCommandNotProcessedNAK; + return status; } static MfUltralightCommand mf_ultralight_listener_auth_handler(MfUltralightListener* instance, BitBuffer* buffer) { - bool command_processed = false; + MfUltralightCommand status = MfUltralightCommandNotProcessedSilent; FURI_LOG_D(TAG, "CMD_AUTH"); @@ -273,11 +274,10 @@ static MfUltralightCommand iso14443_3a_listener_send_standard_frame( instance->iso14443_3a_listener, instance->tx_buffer); - command_processed = true; + status = MfUltralightCommandProcessed; } while(false); - return command_processed ? MfUltralightCommandProcessed : - MfUltralightCommandNotProcessedSilent; + return status; } static const MfUltralightListenerCmdHandler mf_ultralight_command[] = { From 89b675c9010c78bfa83eb410b0773284661af1b8 Mon Sep 17 00:00:00 2001 From: gornekich Date: Mon, 21 Aug 2023 21:40:19 +0400 Subject: [PATCH 138/149] mf ultralight: fix naming --- .../iso14443_3a/iso14443_3a_listener_i.h | 2 - .../mf_ultralight/mf_ultralight_listener.c | 53 +++++++++---------- 2 files changed, 26 insertions(+), 29 deletions(-) diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener_i.h b/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener_i.h index 56aee01104ab..0113a1cb8924 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener_i.h +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener_i.h @@ -26,8 +26,6 @@ struct Iso14443_3aListener { void* context; }; -Iso14443_3aError iso14443_3a_listener_sleep(Iso14443_3aListener* instance); - Iso14443_3aError iso14443_3a_listener_tx(Iso14443_3aListener* instance, const BitBuffer* tx_buffer); diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c index a2a2584c2208..6e9a86e65aef 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c @@ -74,7 +74,7 @@ static MfUltralightCommand uint8_t start_page = bit_buffer_get_byte(buffer, 1); uint16_t pages_total = instance->data->pages_total; MfUltralightPageReadCommandData read_cmd_data = {}; - MfUltralightCommand status = MfUltralightCommandNotProcessedNAK; + MfUltralightCommand command = MfUltralightCommandNotProcessedNAK; FURI_LOG_D(TAG, "CMD_READ: %d", start_page); @@ -102,17 +102,17 @@ static MfUltralightCommand sizeof(MfUltralightPageReadCommandData)); iso14443_3a_listener_send_standard_frame( instance->iso14443_3a_listener, instance->tx_buffer); - status = MfUltralightCommandProcessed; + command = MfUltralightCommandProcessed; } - return status; + return command; } static MfUltralightCommand mf_ultralight_listener_write_page_handler(MfUltralightListener* instance, BitBuffer* buffer) { uint8_t start_page = bit_buffer_get_byte(buffer, 1); uint16_t pages_total = instance->data->pages_total; - MfUltralightCommand status = MfUltralightCommandNotProcessedNAK; + MfUltralightCommand command = MfUltralightCommandNotProcessedNAK; FURI_LOG_D(TAG, "CMD_WRITE"); @@ -127,16 +127,16 @@ static MfUltralightCommand const uint8_t* rx_data = bit_buffer_get_data(buffer); memcpy(instance->data->page[start_page].data, &rx_data[2], sizeof(MfUltralightPage)); mf_ultralight_listener_send_short_resp(instance, MF_ULTRALIGHT_CMD_ACK); - status = MfUltralightCommandProcessed; + command = MfUltralightCommandProcessed; } - return status; + return command; } static MfUltralightCommand mf_ultralight_listener_read_version_handler(MfUltralightListener* instance, BitBuffer* buffer) { UNUSED(buffer); - MfUltralightCommand status = MfUltralightCommandNotProcessedSilent; + MfUltralightCommand command = MfUltralightCommandNotProcessedSilent; FURI_LOG_D(TAG, "CMD_GET_VERSION"); @@ -145,19 +145,19 @@ static MfUltralightCommand instance->tx_buffer, (uint8_t*)&instance->data->version, sizeof(MfUltralightVersion)); iso14443_3a_listener_send_standard_frame( instance->iso14443_3a_listener, instance->tx_buffer); - status = MfUltralightCommandProcessed; + command = MfUltralightCommandProcessed; } else { instance->state = MfUltraligthListenerStateIdle; } - return status; + return command; } static MfUltralightCommand mf_ultralight_listener_read_signature_handler( MfUltralightListener* instance, BitBuffer* buffer) { UNUSED(buffer); - MfUltralightCommand status = MfUltralightCommandNotProcessedSilent; + MfUltralightCommand command = MfUltralightCommandNotProcessedSilent; FURI_LOG_D(TAG, "CMD_READ_SIG"); @@ -166,17 +166,17 @@ static MfUltralightCommand mf_ultralight_listener_read_signature_handler( instance->tx_buffer, instance->data->signature.data, sizeof(MfUltralightSignature)); iso14443_3a_listener_send_standard_frame( instance->iso14443_3a_listener, instance->tx_buffer); - status = MfUltralightCommandProcessed; + command = MfUltralightCommandProcessed; } else { instance->state = MfUltraligthListenerStateIdle; } - return status; + return command; } static MfUltralightCommand mf_ultralight_listener_read_counter_handler(MfUltralightListener* instance, BitBuffer* buffer) { - MfUltralightCommand status = MfUltralightCommandNotProcessedNAK; + MfUltralightCommand command = MfUltralightCommandNotProcessedNAK; FURI_LOG_D(TAG, "CMD_READ_CNT"); @@ -207,18 +207,17 @@ static MfUltralightCommand bit_buffer_copy_bytes(instance->tx_buffer, cnt_value, sizeof(cnt_value)); iso14443_3a_listener_send_standard_frame( instance->iso14443_3a_listener, instance->tx_buffer); - status = MfUltralightCommandProcessed; + command = MfUltralightCommandProcessed; } while(false); - return status; + return command; } static MfUltralightCommand mf_ultralight_listener_check_tearing_handler( MfUltralightListener* instance, BitBuffer* buffer) { - MfUltralightCommand status = MfUltralightCommandNotProcessedNAK; + MfUltralightCommand command = MfUltralightCommandNotProcessedNAK; - UNUSED(buffer); FURI_LOG_D(TAG, "CMD_CHECK_TEARING"); do { @@ -240,16 +239,16 @@ static MfUltralightCommand mf_ultralight_listener_check_tearing_handler( instance->tx_buffer, 0, instance->data->tearing_flag->data[tearing_flag_num]); iso14443_3a_listener_send_standard_frame( instance->iso14443_3a_listener, instance->tx_buffer); - status = MfUltralightCommandProcessed; + command = MfUltralightCommandProcessed; } while(false); - return status; + return command; } static MfUltralightCommand mf_ultralight_listener_auth_handler(MfUltralightListener* instance, BitBuffer* buffer) { - MfUltralightCommand status = MfUltralightCommandNotProcessedSilent; + MfUltralightCommand command = MfUltralightCommandNotProcessedSilent; FURI_LOG_D(TAG, "CMD_AUTH"); @@ -274,10 +273,10 @@ static MfUltralightCommand iso14443_3a_listener_send_standard_frame( instance->iso14443_3a_listener, instance->tx_buffer); - status = MfUltralightCommandProcessed; + command = MfUltralightCommandProcessed; } while(false); - return status; + return command; } static const MfUltralightListenerCmdHandler mf_ultralight_command[] = { @@ -382,24 +381,24 @@ NfcCommand mf_ultralight_listener_run(NfcGenericEvent event, void* context) { NfcCommand command = NfcCommandContinue; if(iso14443_3a_event->type == Iso14443_3aListenerEventTypeReceivedStandardFrame) { - MfUltralightCommand status = MfUltralightCommandNotFound; + MfUltralightCommand mfu_command = MfUltralightCommandNotFound; size_t size = bit_buffer_get_size(rx_buffer); uint8_t cmd = bit_buffer_get_byte(rx_buffer, 0); for(size_t i = 0; i < COUNT_OF(mf_ultralight_command); i++) { if(size != mf_ultralight_command[i].cmd_len_bits) continue; if(cmd != mf_ultralight_command[i].cmd) continue; - status = mf_ultralight_command[i].callback(instance, rx_buffer); + mfu_command = mf_ultralight_command[i].callback(instance, rx_buffer); - if(status != MfUltralightCommandNotFound) break; + if(mfu_command != MfUltralightCommandNotFound) break; } - if(status != MfUltralightCommandProcessed) { + if(mfu_command != MfUltralightCommandProcessed) { instance->state = MfUltraligthListenerStateIdle; instance->auth_state = MfUltralightListenerAuthStateIdle; command = NfcCommandReset; - if(status == MfUltralightCommandNotProcessedNAK) { + if(mfu_command == MfUltralightCommandNotProcessedNAK) { mf_ultralight_listener_send_short_resp(instance, MF_ULTRALIGHT_CMD_NACK); } } From bcfa9124cf11645c228d618525bb294954bb1c8f Mon Sep 17 00:00:00 2001 From: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Date: Mon, 21 Aug 2023 21:44:29 +0300 Subject: [PATCH 139/149] [NFC] ISO15693-3 (NFC-V) Emulation (#2996) * Implement basic boilerplate for NFC-V listener * Improve listener boilerplate * Better separation between various NFC technologies * Correct formatting * Some minor code improvements * Re-add f_hal_event_start() * Implement basic framework for transparent mode * Implement transparent mode rx for NFC-V * Receiving bytes from reader * Refine chip NFC-V configuration * Implement sending via NFC-V listener * Improve Iso15693Signal code * Add support for low and high data rates * Port Iso15693Signal to DigitalSequence * Rearrange some code * Minimal INVENTORY emulation * Minimal GET_SYSTEM_INFO emulation * Minor NFC-V improvements * Improve error and flag handling * Improve command handlers (draft) * Improve command handlers (final) * Add STAY_QUIET command * Add WRITE_BLOCK command * Add several NFC-V commands * Add multi read and write * Add LOCK_BLOCK command * Add GET_SECURITY command * Select command handlers from array * Implement all of the commands (draft) * Simplify NFC-V request handling * Change GUI emulation logic for NFC-V * Implement single EOF handling * Rework nfcv signal reception (#2998) * nfc: add wait event methos * lib: introduce signal reader library * nfc hal: rework iso15 listener * nfc hal: rework iso 15 reception with signal reader * signal reader: don't enable disable dmamux * lib: move bit buffer to toolbox * signal reader: add polarity config * nfc: rework iso15 frame parser * nfc hal: rework internal events handling * nfc: move iso15 parser to libs * nfc iso15693: move poller encoder and decoder to hal * iso15 parser: check bytes to process * iso15: fix first eof detect * iso15 parser: decrease sampling buffer size * nfc: fix naming --------- Co-authored-by: gornekich --- .../protocol_support/iso15693_3/iso15693_3.c | 38 +- firmware/targets/f7/api_symbols.csv | 23 +- firmware/targets/f7/furi_hal/f_hal_nfc.c | 402 +++------- .../targets/f7/furi_hal/f_hal_nfc_event.c | 6 +- .../targets/f7/furi_hal/f_hal_nfc_felica.c | 63 ++ firmware/targets/f7/furi_hal/f_hal_nfc_i.h | 70 +- firmware/targets/f7/furi_hal/f_hal_nfc_irq.c | 2 +- .../{f_hal_nfca.c => f_hal_nfc_iso14443a.c} | 138 +++- .../targets/f7/furi_hal/f_hal_nfc_iso14443b.c | 102 +++ .../targets/f7/furi_hal/f_hal_nfc_iso15693.c | 434 +++++++++++ .../targets/f7/furi_hal/f_hal_nfc_timer.c | 2 +- firmware/targets/f7/target.json | 1 + firmware/targets/furi_hal_include/f_hal_nfc.h | 47 +- lib/SConscript | 2 + .../presets/nfc/iso15693_signal.c | 196 +++++ .../presets/nfc/iso15693_signal.h | 32 + lib/nfc/helpers/iso13239_crc.h | 2 +- lib/nfc/helpers/iso14443_crc.h | 2 +- lib/nfc/nfc.c | 32 +- lib/nfc/nfc.h | 2 +- lib/nfc/protocols/felica/felica.h | 2 +- lib/nfc/protocols/felica/felica_poller_i.h | 2 +- lib/nfc/protocols/iso14443_3a/iso14443_3a.h | 2 +- .../iso14443_3a/iso14443_3a_poller_i.h | 2 +- lib/nfc/protocols/iso14443_3b/iso14443_3b.h | 2 +- .../iso14443_3b/iso14443_3b_poller_i.h | 2 - lib/nfc/protocols/iso15693_3/iso15693_3.c | 14 + lib/nfc/protocols/iso15693_3/iso15693_3.h | 22 +- lib/nfc/protocols/iso15693_3/iso15693_3_i.c | 44 ++ lib/nfc/protocols/iso15693_3/iso15693_3_i.h | 20 +- .../iso15693_3/iso15693_3_listener.c | 111 +++ .../iso15693_3/iso15693_3_listener.h | 21 + .../iso15693_3/iso15693_3_listener_defs.h | 4 + .../iso15693_3/iso15693_3_listener_i.c | 726 ++++++++++++++++++ .../iso15693_3/iso15693_3_listener_i.h | 43 ++ .../protocols/iso15693_3/iso15693_3_poller.c | 8 - .../iso15693_3/iso15693_3_poller_i.c | 80 +- .../iso15693_3/iso15693_3_poller_i.h | 4 +- lib/nfc/protocols/mf_classic/crypto1.h | 2 +- lib/nfc/protocols/nfc_listener_defs.c | 3 + lib/signal_reader/SConscript | 20 + .../parsers/iso15693/iso15693_parser.c | 334 ++++++++ .../parsers/iso15693/iso15693_parser.h | 42 + lib/signal_reader/signal_reader.c | 289 +++++++ lib/signal_reader/signal_reader.h | 60 ++ lib/{nfc/helpers => toolbox}/bit_buffer.c | 0 lib/{nfc/helpers => toolbox}/bit_buffer.h | 0 47 files changed, 2999 insertions(+), 456 deletions(-) create mode 100644 firmware/targets/f7/furi_hal/f_hal_nfc_felica.c rename firmware/targets/f7/furi_hal/{f_hal_nfca.c => f_hal_nfc_iso14443a.c} (51%) create mode 100644 firmware/targets/f7/furi_hal/f_hal_nfc_iso14443b.c create mode 100644 firmware/targets/f7/furi_hal/f_hal_nfc_iso15693.c create mode 100644 lib/digital_signal/presets/nfc/iso15693_signal.c create mode 100644 lib/digital_signal/presets/nfc/iso15693_signal.h create mode 100644 lib/signal_reader/SConscript create mode 100644 lib/signal_reader/parsers/iso15693/iso15693_parser.c create mode 100644 lib/signal_reader/parsers/iso15693/iso15693_parser.h create mode 100644 lib/signal_reader/signal_reader.c create mode 100644 lib/signal_reader/signal_reader.h rename lib/{nfc/helpers => toolbox}/bit_buffer.c (100%) rename lib/{nfc/helpers => toolbox}/bit_buffer.h (100%) diff --git a/applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3.c b/applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3.c index 59f0e55a858b..57a73cc0ca3f 100644 --- a/applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3.c +++ b/applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3.c @@ -2,6 +2,7 @@ #include "iso15693_3_render.h" #include +#include #include "nfc/nfc_app_i.h" @@ -58,6 +59,38 @@ static void nfc_scene_read_success_on_enter_iso15693_3(NfcApp* instance) { furi_string_free(temp_str); } +static NfcCommand + nfc_scene_emulate_listener_callback_iso15693_3(NfcGenericEvent event, void* context) { + furi_assert(context); + furi_assert(event.protocol == NfcProtocolIso15693_3); + furi_assert(event.data); + + NfcApp* nfc = context; + Iso15693_3ListenerEvent* iso15693_3_event = event.data; + + if(iso15693_3_event->type == Iso15693_3ListenerEventTypeCustomCommand) { + furi_string_cat_printf(nfc->text_box_store, "R:"); + for(size_t i = 0; i < bit_buffer_get_size_bytes(iso15693_3_event->data->buffer); i++) { + furi_string_cat_printf( + nfc->text_box_store, + " %02X", + bit_buffer_get_byte(iso15693_3_event->data->buffer, i)); + } + furi_string_push_back(nfc->text_box_store, '\n'); + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventListenerUpdate); + } + + return NfcCommandContinue; +} + +static void nfc_scene_emulate_on_enter_iso15693_3(NfcApp* instance) { + const Iso15693_3Data* data = nfc_device_get_data(instance->nfc_device, NfcProtocolIso15693_3); + + instance->listener = nfc_listener_alloc(instance->nfc, NfcProtocolIso15693_3, data); + nfc_listener_start( + instance->listener, nfc_scene_emulate_listener_callback_iso15693_3, instance); +} + static bool nfc_scene_info_on_event_iso15693_3(NfcApp* instance, uint32_t event) { if(event == GuiButtonTypeRight) { scene_manager_next_scene(instance->scene_manager, NfcSceneNotImplemented); @@ -77,7 +110,8 @@ static bool nfc_scene_saved_menu_on_event_iso15693_3(NfcApp* instance, uint32_t } const NfcProtocolSupportBase nfc_protocol_support_iso15693_3 = { - .features = NfcProtocolFeatureNone, // TODO: Implement better UID editing, + .features = + NfcProtocolFeatureEmulateFull, // | NfcProtocolFeatureEditUid, // TODO: Implement better UID editing .scene_info = { @@ -106,7 +140,7 @@ const NfcProtocolSupportBase nfc_protocol_support_iso15693_3 = { }, .scene_emulate = { - .on_enter = NULL, + .on_enter = nfc_scene_emulate_on_enter_iso15693_3, .on_event = NULL, }, }; diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 637718068308..2486c0b72cdd 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -182,6 +182,7 @@ Header,+,lib/one_wire/one_wire_host.h,, Header,+,lib/one_wire/one_wire_slave.h,, Header,+,lib/print/wrappers.h,, Header,+,lib/pulse_reader/pulse_reader.h,, +Header,+,lib/signal_reader/signal_reader.h,, Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_adc.h,, Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_bus.h,, Header,+,lib/stm32wb_hal/Inc/stm32wbxx_ll_comp.h,, @@ -870,24 +871,28 @@ Function,-,expm1f,float,float Function,-,expm1l,long double,long double Function,-,f_hal_nfc_abort,FHalNfcError, Function,-,f_hal_nfc_acquire,FHalNfcError, -Function,-,f_hal_nfc_event_start,FHalNfcError, +Function,+,f_hal_nfc_event_start,FHalNfcError, Function,-,f_hal_nfc_init,FHalNfcError, Function,-,f_hal_nfc_is_hal_ready,FHalNfcError, -Function,-,f_hal_nfc_listen_reset,FHalNfcError, -Function,-,f_hal_nfc_listen_start,FHalNfcError, Function,-,f_hal_nfc_listener_disable_auto_col_res,FHalNfcError, +Function,+,f_hal_nfc_listener_reset,FHalNfcError, +Function,+,f_hal_nfc_listener_rx,FHalNfcError,"uint8_t*, size_t, size_t*" +Function,+,f_hal_nfc_listener_rx_start,FHalNfcError, Function,-,f_hal_nfc_listener_sleep,FHalNfcError, +Function,+,f_hal_nfc_listener_start,FHalNfcError, Function,-,f_hal_nfc_listener_tx,FHalNfcError,"const uint8_t*, size_t" +Function,-,f_hal_nfc_listener_wait_event,FHalNfcEvent,uint32_t Function,-,f_hal_nfc_low_power_mode_start,FHalNfcError, Function,-,f_hal_nfc_low_power_mode_stop,FHalNfcError, Function,-,f_hal_nfc_poller_field_on,FHalNfcError, Function,-,f_hal_nfc_poller_rx,FHalNfcError,"uint8_t*, size_t, size_t*" Function,-,f_hal_nfc_poller_tx,FHalNfcError,"const uint8_t*, size_t" Function,-,f_hal_nfc_poller_tx_custom_parity,FHalNfcError,"const uint8_t*, size_t" +Function,-,f_hal_nfc_poller_wait_event,FHalNfcEvent,uint32_t Function,-,f_hal_nfc_release,FHalNfcError, Function,-,f_hal_nfc_reset_mode,FHalNfcError, Function,-,f_hal_nfc_set_mask_receive_timer,void,uint32_t -Function,-,f_hal_nfc_set_mode,FHalNfcError,"FHalNfcMode, FHalNfcBitrate" +Function,+,f_hal_nfc_set_mode,FHalNfcError,"FHalNfcMode, FHalNfcTech" Function,-,f_hal_nfc_timer_block_tx_is_running,_Bool, Function,-,f_hal_nfc_timer_block_tx_start,void,uint32_t Function,-,f_hal_nfc_timer_block_tx_start_us,void,uint32_t @@ -895,9 +900,6 @@ Function,-,f_hal_nfc_timer_block_tx_stop,void, Function,-,f_hal_nfc_timer_fwt_start,void,uint32_t Function,-,f_hal_nfc_timer_fwt_stop,void, Function,-,f_hal_nfc_trx_reset,FHalNfcError, -Function,-,f_hal_nfc_wait_event,FHalNfcEvent,uint32_t -Function,-,f_hal_nfca_listener_deinit,FHalNfcError, -Function,-,f_hal_nfca_listener_init,FHalNfcError, Function,-,f_hal_nfca_listener_tx_custom_parity,FHalNfcError,"const uint8_t*, const _Bool*, size_t" Function,-,f_hal_nfca_receive_sdd_frame,FHalNfcError,"uint8_t*, size_t, size_t*" Function,-,f_hal_nfca_send_sdd_frame,FHalNfcError,"const uint8_t*, size_t" @@ -2668,6 +2670,13 @@ Function,+,sha256_finish,void,"sha256_context*, unsigned char[32]" Function,+,sha256_process,void,sha256_context* Function,+,sha256_start,void,sha256_context* Function,+,sha256_update,void,"sha256_context*, const unsigned char*, unsigned int" +Function,+,signal_reader_alloc,SignalReader*,"const GpioPin*, uint32_t" +Function,+,signal_reader_free,void,SignalReader* +Function,+,signal_reader_set_polarity,void,"SignalReader*, SignalReaderPolarity" +Function,+,signal_reader_set_pull,void,"SignalReader*, GpioPull" +Function,+,signal_reader_set_sample_rate,void,"SignalReader*, SignalReaderTimeUnit, uint32_t" +Function,+,signal_reader_start,void,"SignalReader*, SignalReaderCallback, void*" +Function,+,signal_reader_stop,void,SignalReader* Function,+,simple_array_alloc,SimpleArray*,const SimpleArrayConfig* Function,+,simple_array_cget,const SimpleArrayElement*,"const SimpleArray*, uint32_t" Function,+,simple_array_cget_data,const SimpleArrayData*,const SimpleArray* diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc.c b/firmware/targets/f7/furi_hal/f_hal_nfc.c index 59373f2a4201..3047341ecbe0 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfc.c +++ b/firmware/targets/f7/furi_hal/f_hal_nfc.c @@ -7,7 +7,14 @@ #define TAG "FHalNfc" -static FuriMutex* f_hal_nfc_mutex = NULL; +static const FHalNfcTechBase* f_hal_nfc_tech[FHalNfcTechNum] = { + [FHalNfcTechIso14443a] = &f_hal_nfc_iso14443a, + [FHalNfcTechIso14443b] = &f_hal_nfc_iso14443b, + [FHalNfcTechIso15693] = &f_hal_nfc_iso15693, + [FHalNfcTechFelica] = &f_hal_nfc_felica, +}; + +FHalNfc f_hal_nfc; static FHalNfcError f_hal_nfc_turn_on_osc(FuriHalSpiBusHandle* handle) { FHalNfcError error = FHalNfcErrorNone; @@ -59,9 +66,9 @@ FHalNfcError f_hal_nfc_is_hal_ready() { } FHalNfcError f_hal_nfc_init() { - furi_assert(f_hal_nfc_mutex == NULL); + furi_assert(f_hal_nfc.mutex == NULL); - f_hal_nfc_mutex = furi_mutex_alloc(FuriMutexTypeNormal); + f_hal_nfc.mutex = furi_mutex_alloc(FuriMutexTypeNormal); FHalNfcError error = FHalNfcErrorNone; f_hal_nfc_event_init(); @@ -234,16 +241,16 @@ FHalNfcError f_hal_nfc_init() { } static bool f_hal_nfc_is_mine() { - return (furi_mutex_get_owner(f_hal_nfc_mutex) == furi_thread_get_current_id()); + return (furi_mutex_get_owner(f_hal_nfc.mutex) == furi_thread_get_current_id()); } FHalNfcError f_hal_nfc_acquire() { - furi_check(f_hal_nfc_mutex); + furi_check(f_hal_nfc.mutex); furi_hal_spi_acquire(&furi_hal_spi_bus_handle_nfc); FHalNfcError error = FHalNfcErrorNone; - if(furi_mutex_acquire(f_hal_nfc_mutex, 100) != FuriStatusOk) { + if(furi_mutex_acquire(f_hal_nfc.mutex, 100) != FuriStatusOk) { furi_hal_spi_release(&furi_hal_spi_bus_handle_nfc); error = FHalNfcErrorBusy; } @@ -252,9 +259,9 @@ FHalNfcError f_hal_nfc_acquire() { } FHalNfcError f_hal_nfc_release() { - furi_check(f_hal_nfc_mutex); + furi_check(f_hal_nfc.mutex); furi_check(f_hal_nfc_is_mine()); - furi_check(furi_mutex_release(f_hal_nfc_mutex) == FuriStatusOk); + furi_check(furi_mutex_release(f_hal_nfc.mutex) == FuriStatusOk); furi_hal_spi_release(&furi_hal_spi_bus_handle_nfc); @@ -298,7 +305,7 @@ FHalNfcError f_hal_nfc_low_power_mode_stop() { return error; } -static void f_hal_nfc_configure_poller_common(FuriHalSpiBusHandle* handle) { +static FHalNfcError f_hal_nfc_poller_init_common(FuriHalSpiBusHandle* handle) { // Disable wake up st25r3916_clear_reg_bits(handle, ST25R3916_REG_OP_CONTROL, ST25R3916_REG_OP_CONTROL_wu); // Enable correlator @@ -315,264 +322,41 @@ static void f_hal_nfc_configure_poller_common(FuriHalSpiBusHandle* handle) { st25r3916_write_reg(handle, ST25R3916_REG_OVERSHOOT_CONF2, 0x00); st25r3916_write_reg(handle, ST25R3916_REG_UNDERSHOOT_CONF1, 0x00); st25r3916_write_reg(handle, ST25R3916_REG_UNDERSHOOT_CONF2, 0x00); -} - -// TODO: Refactor this function to be more modular and readable -FHalNfcError f_hal_nfc_set_mode(FHalNfcMode mode, FHalNfcBitrate bitrate) { - FHalNfcError error = FHalNfcErrorNone; - FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; - - if(mode == FHalNfcModeIso14443aPoller || mode == FHalNfcModeIso14443aListener) { - if(mode == FHalNfcModeIso14443aPoller) { - // Poller configuration - f_hal_nfc_configure_poller_common(handle); - // Enable ISO14443A mode, OOK modulation - st25r3916_change_reg_bits( - handle, - ST25R3916_REG_MODE, - ST25R3916_REG_MODE_om_mask | ST25R3916_REG_MODE_tr_am, - ST25R3916_REG_MODE_om_iso14443a | ST25R3916_REG_MODE_tr_am_ook); - - // Overshoot protection - is this necessary here? - st25r3916_change_reg_bits(handle, ST25R3916_REG_OVERSHOOT_CONF1, 0xff, 0x40); - st25r3916_change_reg_bits(handle, ST25R3916_REG_OVERSHOOT_CONF2, 0xff, 0x03); - st25r3916_change_reg_bits(handle, ST25R3916_REG_UNDERSHOOT_CONF1, 0xff, 0x40); - st25r3916_change_reg_bits(handle, ST25R3916_REG_UNDERSHOOT_CONF2, 0xff, 0x03); - - } else { - // Listener configuration - f_hal_nfca_listener_init(); - st25r3916_write_reg( - handle, - ST25R3916_REG_OP_CONTROL, - ST25R3916_REG_OP_CONTROL_en | ST25R3916_REG_OP_CONTROL_rx_en | - ST25R3916_REG_OP_CONTROL_en_fd_auto_efd); - st25r3916_write_reg( - handle, ST25R3916_REG_MODE, ST25R3916_REG_MODE_targ_targ | ST25R3916_REG_MODE_om0); - st25r3916_write_reg( - handle, - ST25R3916_REG_PASSIVE_TARGET, - ST25R3916_REG_PASSIVE_TARGET_fdel_2 | ST25R3916_REG_PASSIVE_TARGET_fdel_0 | - ST25R3916_REG_PASSIVE_TARGET_d_ac_ap2p | - ST25R3916_REG_PASSIVE_TARGET_d_212_424_1r); - - st25r3916_write_reg(handle, ST25R3916_REG_MASK_RX_TIMER, 0x02); - } - if(bitrate == FHalNfcBitrate106) { - // Bitrate-dependent NFC-A settings - - // 1st stage zero = 600kHz, 3rd stage zero = 200 kHz - st25r3916_write_reg(handle, ST25R3916_REG_RX_CONF1, ST25R3916_REG_RX_CONF1_z600k); - // AGC enabled, ratio 6:1, squelch after TX - st25r3916_write_reg( - handle, - ST25R3916_REG_RX_CONF2, - ST25R3916_REG_RX_CONF2_agc6_3 | ST25R3916_REG_RX_CONF2_agc_m | - ST25R3916_REG_RX_CONF2_agc_en | ST25R3916_REG_RX_CONF2_sqm_dyn); - // HF operation, full gain on AM and PM channels - st25r3916_write_reg(handle, ST25R3916_REG_RX_CONF3, 0x00); - // No gain reduction on AM and PM channels - st25r3916_write_reg(handle, ST25R3916_REG_RX_CONF4, 0x00); - // Correlator config - st25r3916_write_reg( - handle, - ST25R3916_REG_CORR_CONF1, - ST25R3916_REG_CORR_CONF1_corr_s0 | ST25R3916_REG_CORR_CONF1_corr_s4 | - ST25R3916_REG_CORR_CONF1_corr_s6); - // Sleep mode disable, 424kHz mode off - st25r3916_write_reg(handle, ST25R3916_REG_CORR_CONF2, 0x00); - } - - } else if(mode == FHalNfcModeIso14443bPoller /* TODO: Listener support */) { - f_hal_nfc_configure_poller_common(handle); - // Enable ISO14443B mode, AM modulation - st25r3916_change_reg_bits( - handle, - ST25R3916_REG_MODE, - ST25R3916_REG_MODE_om_mask | ST25R3916_REG_MODE_tr_am, - ST25R3916_REG_MODE_om_iso14443b | ST25R3916_REG_MODE_tr_am_am); - - // 10% ASK modulation - st25r3916_change_reg_bits( - handle, - ST25R3916_REG_TX_DRIVER, - ST25R3916_REG_TX_DRIVER_am_mod_mask, - ST25R3916_REG_TX_DRIVER_am_mod_10percent); - - // Use regulator AM, resistive AM disabled - st25r3916_clear_reg_bits( - handle, - ST25R3916_REG_AUX_MOD, - ST25R3916_REG_AUX_MOD_dis_reg_am | ST25R3916_REG_AUX_MOD_res_am); - - // EGT = 0 etu - // SOF = 10 etu LOW + 2 etu HIGH - // EOF = 10 etu - st25r3916_change_reg_bits( - handle, - ST25R3916_REG_ISO14443B_1, - ST25R3916_REG_ISO14443B_1_egt_mask | ST25R3916_REG_ISO14443B_1_sof_mask | - ST25R3916_REG_ISO14443B_1_eof, - (0U << ST25R3916_REG_ISO14443B_1_egt_shift) | ST25R3916_REG_ISO14443B_1_sof_0_10etu | - ST25R3916_REG_ISO14443B_1_sof_1_2etu | ST25R3916_REG_ISO14443B_1_eof_10etu); - - // TR1 = 80 / fs - // B' mode off (no_sof & no_eof = 0) - st25r3916_change_reg_bits( - handle, - ST25R3916_REG_ISO14443B_2, - ST25R3916_REG_ISO14443B_2_tr1_mask | ST25R3916_REG_ISO14443B_2_no_sof | - ST25R3916_REG_ISO14443B_2_no_eof, - ST25R3916_REG_ISO14443B_2_tr1_80fs80fs); - - if(bitrate == FHalNfcBitrate106) { - // Bitrate-dependent NFC-B settings - - // 1st stage zero = 60kHz, 3rd stage zero = 200 kHz - st25r3916_write_reg(handle, ST25R3916_REG_RX_CONF1, ST25R3916_REG_RX_CONF1_h200); - - // Enable AGC - // AGC Ratio 6 - // AGC algorithm with RESET (recommended for ISO14443-B) - // AGC operation during complete receive period - // Squelch ratio 6/3 (recommended for ISO14443-B) - // Squelch automatic activation on TX end - st25r3916_write_reg( - handle, - ST25R3916_REG_RX_CONF2, - ST25R3916_REG_RX_CONF2_agc6_3 | ST25R3916_REG_RX_CONF2_agc_alg | - ST25R3916_REG_RX_CONF2_agc_m | ST25R3916_REG_RX_CONF2_agc_en | - ST25R3916_REG_RX_CONF2_pulz_61 | ST25R3916_REG_RX_CONF2_sqm_dyn); - - // HF operation, full gain on AM and PM channels - st25r3916_write_reg(handle, ST25R3916_REG_RX_CONF3, 0x00); - // No gain reduction on AM and PM channels - st25r3916_write_reg(handle, ST25R3916_REG_RX_CONF4, 0x00); - - // Subcarrier end detector enabled - // Subcarrier end detection level = 66% - // BPSK start 33 pilot pulses - // AM & PM summation before digitizing on - st25r3916_write_reg( - handle, - ST25R3916_REG_CORR_CONF1, - ST25R3916_REG_CORR_CONF1_corr_s0 | ST25R3916_REG_CORR_CONF1_corr_s1 | - ST25R3916_REG_CORR_CONF1_corr_s3 | ST25R3916_REG_CORR_CONF1_corr_s4); - // Sleep mode disable, 424kHz mode off - st25r3916_write_reg(handle, ST25R3916_REG_CORR_CONF2, 0x00); - } - - } else if(mode == FHalNfcModeIso15693Poller || mode == FHalNfcModeIso15693Listener) { - if(mode == FHalNfcModeIso15693Poller) { - // Poller configuration - f_hal_nfc_configure_poller_common(handle); - // Enable Subcarrier Stream mode, OOK modulation - st25r3916_change_reg_bits( - handle, - ST25R3916_REG_MODE, - ST25R3916_REG_MODE_om_mask | ST25R3916_REG_MODE_tr_am, - ST25R3916_REG_MODE_om_subcarrier_stream | ST25R3916_REG_MODE_tr_am_ook); - - // Subcarrier 424 kHz mode - // 8 sub-carrier pulses in report period - st25r3916_write_reg( - handle, - ST25R3916_REG_STREAM_MODE, - ST25R3916_REG_STREAM_MODE_scf_sc424 | ST25R3916_REG_STREAM_MODE_stx_106 | - ST25R3916_REG_STREAM_MODE_scp_8pulses); - - // Use regulator AM, resistive AM disabled - st25r3916_clear_reg_bits( - handle, - ST25R3916_REG_AUX_MOD, - ST25R3916_REG_AUX_MOD_dis_reg_am | ST25R3916_REG_AUX_MOD_res_am); - - } else { - // Listener configuration - f_hal_nfca_listener_init(); - // TODO: Implement listener config - } - - if(bitrate == FHalNfcBitrate26p48) { - // Bitrate-dependent NFC-V settings - - // 1st stage zero = 12 kHz, 3rd stage zero = 80 kHz, low-pass = 600 kHz - st25r3916_write_reg( - handle, - ST25R3916_REG_RX_CONF1, - ST25R3916_REG_RX_CONF1_z12k | ST25R3916_REG_RX_CONF1_h80 | - ST25R3916_REG_RX_CONF1_lp_600khz); - - // Enable AGC - // AGC Ratio 6 - // AGC algorithm with RESET (recommended for ISO15693) - // AGC operation during complete receive period - // Squelch automatic activation on TX end - st25r3916_write_reg( - handle, - ST25R3916_REG_RX_CONF2, - ST25R3916_REG_RX_CONF2_agc6_3 | ST25R3916_REG_RX_CONF2_agc_m | - ST25R3916_REG_RX_CONF2_agc_en | ST25R3916_REG_RX_CONF2_sqm_dyn); - - // HF operation, full gain on AM and PM channels - st25r3916_write_reg(handle, ST25R3916_REG_RX_CONF3, 0x00); - // No gain reduction on AM and PM channels - st25r3916_write_reg(handle, ST25R3916_REG_RX_CONF4, 0x00); - - // Collision detection level 53% - // AM & PM summation before digitizing on - st25r3916_write_reg( - handle, - ST25R3916_REG_CORR_CONF1, - ST25R3916_REG_CORR_CONF1_corr_s0 | ST25R3916_REG_CORR_CONF1_corr_s1 | - ST25R3916_REG_CORR_CONF1_corr_s4); - // 424 kHz subcarrier stream mode on - st25r3916_write_reg( - handle, ST25R3916_REG_CORR_CONF2, ST25R3916_REG_CORR_CONF2_corr_s8); - } - } else if(mode == FHalNfcModeFelicaPoller) { - f_hal_nfc_configure_poller_common(handle); - // Enable Felica mode, AM modulation - st25r3916_change_reg_bits( - handle, - ST25R3916_REG_MODE, - ST25R3916_REG_MODE_om_mask | ST25R3916_REG_MODE_tr_am, - ST25R3916_REG_MODE_om_felica | ST25R3916_REG_MODE_tr_am_am); + return FHalNfcErrorNone; +} - // 10% ASK modulation - st25r3916_change_reg_bits( - handle, - ST25R3916_REG_TX_DRIVER, - ST25R3916_REG_TX_DRIVER_am_mod_mask, - ST25R3916_REG_TX_DRIVER_am_mod_10percent); +static FHalNfcError f_hal_nfc_listener_init_common(FuriHalSpiBusHandle* handle) { + UNUSED(handle); + // TODO: Common listener configuration + return FHalNfcErrorNone; +} - // Use regulator AM, resistive AM disabled - st25r3916_clear_reg_bits( - handle, - ST25R3916_REG_AUX_MOD, - ST25R3916_REG_AUX_MOD_dis_reg_am | ST25R3916_REG_AUX_MOD_res_am); +FHalNfcError f_hal_nfc_set_mode(FHalNfcMode mode, FHalNfcTech tech) { + furi_assert(mode < FHalNfcModeNum); + furi_assert(tech < FHalNfcTechNum); - st25r3916_change_reg_bits( - handle, - ST25R3916_REG_BIT_RATE, - ST25R3916_REG_BIT_RATE_txrate_mask | ST25R3916_REG_BIT_RATE_rxrate_mask, - ST25R3916_REG_BIT_RATE_txrate_212 | ST25R3916_REG_BIT_RATE_rxrate_212); + FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; - // Receive configuration - st25r3916_write_reg( - handle, - ST25R3916_REG_RX_CONF1, - ST25R3916_REG_RX_CONF1_lp0 | ST25R3916_REG_RX_CONF1_hz_12_80khz); + FHalNfcError error = FHalNfcErrorNone; - // Correlator setup - st25r3916_write_reg( - handle, - ST25R3916_REG_CORR_CONF1, - ST25R3916_REG_CORR_CONF1_corr_s6 | ST25R3916_REG_CORR_CONF1_corr_s4 | - ST25R3916_REG_CORR_CONF1_corr_s3); + if(mode == FHalNfcModePoller) { + do { + error = f_hal_nfc_poller_init_common(handle); + if(error != FHalNfcErrorNone) break; + error = f_hal_nfc_tech[tech]->poller.init(handle); + } while(false); + + } else if(mode == FHalNfcModeListener) { + do { + error = f_hal_nfc_listener_init_common(handle); + if(error != FHalNfcErrorNone) break; + error = f_hal_nfc_tech[tech]->listener.init(handle); + } while(false); } + f_hal_nfc.mode = mode; + f_hal_nfc.tech = tech; return error; } @@ -584,7 +368,6 @@ FHalNfcError f_hal_nfc_reset_mode() { // Set default value in mode register st25r3916_write_reg(handle, ST25R3916_REG_MODE, ST25R3916_REG_MODE_om0); st25r3916_write_reg(handle, ST25R3916_REG_STREAM_MODE, 0); - st25r3916_clear_reg_bits(handle, ST25R3916_REG_AUX, ST25R3916_REG_AUX_no_crc_rx); st25r3916_clear_reg_bits( handle, @@ -606,7 +389,14 @@ FHalNfcError f_hal_nfc_reset_mode() { ST25R3916_REG_CORR_CONF1_corr_s1 | ST25R3916_REG_CORR_CONF1_corr_s0); st25r3916_write_reg(handle, ST25R3916_REG_CORR_CONF2, 0); - f_hal_nfca_listener_deinit(); + const FHalNfcMode mode = f_hal_nfc.mode; + const FHalNfcTech tech = f_hal_nfc.tech; + + if(mode == FHalNfcModePoller) { + error = f_hal_nfc_tech[tech]->poller.deinit(handle); + } else if(mode == FHalNfcModeListener) { + error = f_hal_nfc_tech[tech]->listener.deinit(handle); + } return error; } @@ -664,11 +454,13 @@ FHalNfcError f_hal_nfc_poller_tx_custom_parity(const uint8_t* tx_data, size_t tx return err; } -FHalNfcError f_hal_nfc_poller_tx(const uint8_t* tx_data, size_t tx_bits) { +FHalNfcError f_hal_nfc_poller_tx_common( + FuriHalSpiBusHandle* handle, + const uint8_t* tx_data, + size_t tx_bits) { furi_assert(tx_data); FHalNfcError err = FHalNfcErrorNone; - FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; // Prepare tx st25r3916_direct_cmd(handle, ST25R3916_CMD_CLEAR_FIFO); @@ -694,25 +486,76 @@ FHalNfcError f_hal_nfc_poller_tx(const uint8_t* tx_data, size_t tx_bits) { return err; } -FHalNfcError f_hal_nfc_listener_tx(const uint8_t* tx_data, size_t tx_bits) { - furi_assert(tx_data); - - FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; +FHalNfcError + f_hal_nfc_common_fifo_tx(FuriHalSpiBusHandle* handle, const uint8_t* tx_data, size_t tx_bits) { + FHalNfcError err = FHalNfcErrorNone; st25r3916_direct_cmd(handle, ST25R3916_CMD_CLEAR_FIFO); - st25r3916_write_fifo(handle, tx_data, tx_bits); st25r3916_direct_cmd(handle, ST25R3916_CMD_TRANSMIT_WITHOUT_CRC); - bool tx_end = f_hal_nfc_event_wait_for_specific_irq(handle, ST25R3916_IRQ_MASK_TXE, 10); - return tx_end ? FHalNfcErrorNone : FHalNfcErrorCommunicationTimeout; + return err; +} + +FHalNfcError f_hal_nfc_poller_tx(const uint8_t* tx_data, size_t tx_bits) { + furi_assert(f_hal_nfc.mode == FHalNfcModePoller); + furi_assert(f_hal_nfc.tech < FHalNfcTechNum); + FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; + + return f_hal_nfc_tech[f_hal_nfc.tech]->poller.tx(handle, tx_data, tx_bits); } FHalNfcError f_hal_nfc_poller_rx(uint8_t* rx_data, size_t rx_data_size, size_t* rx_bits) { - furi_assert(rx_data); - furi_assert(rx_bits); + furi_assert(f_hal_nfc.mode == FHalNfcModePoller); + furi_assert(f_hal_nfc.tech < FHalNfcTechNum); + FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; + + return f_hal_nfc_tech[f_hal_nfc.tech]->poller.rx(handle, rx_data, rx_data_size, rx_bits); +} + +FHalNfcEvent f_hal_nfc_poller_wait_event(uint32_t timeout_ms) { + furi_assert(f_hal_nfc.mode == FHalNfcModePoller); + furi_assert(f_hal_nfc.tech < FHalNfcTechNum); + + return f_hal_nfc_tech[f_hal_nfc.tech]->poller.wait_event(timeout_ms); +} + +FHalNfcEvent f_hal_nfc_listener_wait_event(uint32_t timeout_ms) { + furi_assert(f_hal_nfc.mode == FHalNfcModeListener); + furi_assert(f_hal_nfc.tech < FHalNfcTechNum); + + return f_hal_nfc_tech[f_hal_nfc.tech]->listener.wait_event(timeout_ms); +} + +FHalNfcError f_hal_nfc_listener_tx(const uint8_t* tx_data, size_t tx_bits) { + furi_assert(tx_data); + + furi_assert(f_hal_nfc.mode == FHalNfcModeListener); + furi_assert(f_hal_nfc.tech < FHalNfcTechNum); FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; + return f_hal_nfc_tech[f_hal_nfc.tech]->listener.tx(handle, tx_data, tx_bits); +} + +FHalNfcError f_hal_nfc_common_listener_rx_start(FuriHalSpiBusHandle* handle) { + UNUSED(handle); + /* Empty implementation */ + return FHalNfcErrorNone; +} + +FHalNfcError f_hal_nfc_listener_rx_start() { + furi_assert(f_hal_nfc.mode == FHalNfcModeListener); + furi_assert(f_hal_nfc.tech < FHalNfcTechNum); + + FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; + return f_hal_nfc_tech[f_hal_nfc.tech]->listener.rx_start(handle); +} + +FHalNfcError f_hal_nfc_common_fifo_rx( + FuriHalSpiBusHandle* handle, + uint8_t* rx_data, + size_t rx_data_size, + size_t* rx_bits) { FHalNfcError error = FHalNfcErrorNone; if(!st25r3916_read_fifo(handle, rx_data, rx_data_size, rx_bits)) { @@ -722,6 +565,17 @@ FHalNfcError f_hal_nfc_poller_rx(uint8_t* rx_data, size_t rx_data_size, size_t* return error; } +FHalNfcError f_hal_nfc_listener_rx(uint8_t* rx_data, size_t rx_data_size, size_t* rx_bits) { + furi_assert(rx_data); + furi_assert(rx_bits); + + furi_assert(f_hal_nfc.mode == FHalNfcModeListener); + furi_assert(f_hal_nfc.tech < FHalNfcTechNum); + + FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; + return f_hal_nfc_tech[f_hal_nfc.tech]->listener.rx(handle, rx_data, rx_data_size, rx_bits); +} + FHalNfcError f_hal_nfc_trx_reset() { FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; @@ -730,7 +584,7 @@ FHalNfcError f_hal_nfc_trx_reset() { return FHalNfcErrorNone; } -FHalNfcError f_hal_nfc_listen_start() { +FHalNfcError f_hal_nfc_listener_start() { FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; st25r3916_direct_cmd(handle, ST25R3916_CMD_STOP); @@ -752,7 +606,7 @@ FHalNfcError f_hal_nfc_listen_start() { return FHalNfcErrorNone; } -FHalNfcError f_hal_nfc_listen_reset() { +FHalNfcError f_hal_nfc_listener_reset() { FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; st25r3916_direct_cmd(handle, ST25R3916_CMD_UNMASK_RECEIVE_DATA); diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc_event.c b/firmware/targets/f7/furi_hal/f_hal_nfc_event.c index f28967ffb869..622038fefa4e 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfc_event.c +++ b/firmware/targets/f7/furi_hal/f_hal_nfc_event.c @@ -15,7 +15,7 @@ FHalNfcError f_hal_nfc_event_start() { return FHalNfcErrorNone; } -void f_hal_nfc_set_event(FHalNfcEventInternalType event) { +void f_hal_nfc_event_set(FHalNfcEventInternalType event) { furi_assert(f_hal_nfc_event); furi_assert(f_hal_nfc_event->thread); @@ -23,11 +23,11 @@ void f_hal_nfc_set_event(FHalNfcEventInternalType event) { } FHalNfcError f_hal_nfc_abort() { - f_hal_nfc_set_event(FHalNfcEventInternalTypeAbort); + f_hal_nfc_event_set(FHalNfcEventInternalTypeAbort); return FHalNfcErrorNone; } -FHalNfcEvent f_hal_nfc_wait_event(uint32_t timeout_ms) { +FHalNfcEvent f_hal_nfc_wait_event_common(uint32_t timeout_ms) { furi_assert(f_hal_nfc_event); furi_assert(f_hal_nfc_event->thread); diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc_felica.c b/firmware/targets/f7/furi_hal/f_hal_nfc_felica.c new file mode 100644 index 000000000000..683da8534ee4 --- /dev/null +++ b/firmware/targets/f7/furi_hal/f_hal_nfc_felica.c @@ -0,0 +1,63 @@ +#include "f_hal_nfc_i.h" + +static FHalNfcError f_hal_nfc_felica_poller_init(FuriHalSpiBusHandle* handle) { + // Enable Felica mode, AM modulation + st25r3916_change_reg_bits( + handle, + ST25R3916_REG_MODE, + ST25R3916_REG_MODE_om_mask | ST25R3916_REG_MODE_tr_am, + ST25R3916_REG_MODE_om_felica | ST25R3916_REG_MODE_tr_am_am); + + // 10% ASK modulation + st25r3916_change_reg_bits( + handle, + ST25R3916_REG_TX_DRIVER, + ST25R3916_REG_TX_DRIVER_am_mod_mask, + ST25R3916_REG_TX_DRIVER_am_mod_10percent); + + // Use regulator AM, resistive AM disabled + st25r3916_clear_reg_bits( + handle, + ST25R3916_REG_AUX_MOD, + ST25R3916_REG_AUX_MOD_dis_reg_am | ST25R3916_REG_AUX_MOD_res_am); + + st25r3916_change_reg_bits( + handle, + ST25R3916_REG_BIT_RATE, + ST25R3916_REG_BIT_RATE_txrate_mask | ST25R3916_REG_BIT_RATE_rxrate_mask, + ST25R3916_REG_BIT_RATE_txrate_212 | ST25R3916_REG_BIT_RATE_rxrate_212); + + // Receive configuration + st25r3916_write_reg( + handle, + ST25R3916_REG_RX_CONF1, + ST25R3916_REG_RX_CONF1_lp0 | ST25R3916_REG_RX_CONF1_hz_12_80khz); + + // Correlator setup + st25r3916_write_reg( + handle, + ST25R3916_REG_CORR_CONF1, + ST25R3916_REG_CORR_CONF1_corr_s6 | ST25R3916_REG_CORR_CONF1_corr_s4 | + ST25R3916_REG_CORR_CONF1_corr_s3); + + return FHalNfcErrorNone; +} + +static FHalNfcError f_hal_nfc_felica_poller_deinit(FuriHalSpiBusHandle* handle) { + UNUSED(handle); + + return FHalNfcErrorNone; +} + +const FHalNfcTechBase f_hal_nfc_felica = { + .poller = + { + .init = f_hal_nfc_felica_poller_init, + .deinit = f_hal_nfc_felica_poller_deinit, + .wait_event = f_hal_nfc_wait_event_common, + .tx = f_hal_nfc_poller_tx_common, + .rx = f_hal_nfc_common_fifo_rx, + }, + + .listener = {0}, +}; diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc_i.h b/firmware/targets/f7/furi_hal/f_hal_nfc_i.h index ed06e4c9b8bd..834ac219a399 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfc_i.h +++ b/firmware/targets/f7/furi_hal/f_hal_nfc_i.h @@ -15,22 +15,30 @@ typedef enum { FHalNfcEventInternalTypeIrq = (1U << 1), FHalNfcEventInternalTypeTimerFwtExpired = (1U << 2), FHalNfcEventInternalTypeTimerBlockTxExpired = (1U << 3), + FHalNfcEventInternalTypeTransparentDataReceived = (1U << 4), } FHalNfcEventInternalType; -#define F_HAL_NFC_EVENT_INTERNAL_ALL \ - ((FHalNfcEventInternalTypeAbort | FHalNfcEventInternalTypeIrq | \ - FHalNfcEventInternalTypeTimerFwtExpired | FHalNfcEventInternalTypeTimerBlockTxExpired)) +#define F_HAL_NFC_EVENT_INTERNAL_ALL \ + ((FHalNfcEventInternalTypeAbort | FHalNfcEventInternalTypeIrq | \ + FHalNfcEventInternalTypeTimerFwtExpired | FHalNfcEventInternalTypeTimerBlockTxExpired | \ + FHalNfcEventInternalTypeTransparentDataReceived)) typedef struct { FuriThreadId thread; void* context; } FHalNfcEventInternal; -extern FHalNfcEventInternal* f_hal_nfc; +typedef struct { + FuriMutex* mutex; + FHalNfcMode mode; + FHalNfcTech tech; +} FHalNfc; + +extern FHalNfc f_hal_nfc; void f_hal_nfc_event_init(); -void f_hal_nfc_set_event(FHalNfcEventInternalType event); +void f_hal_nfc_event_set(FHalNfcEventInternalType event); void f_hal_nfc_init_gpio_isr(); @@ -47,6 +55,58 @@ bool f_hal_nfc_event_wait_for_specific_irq( uint32_t mask, uint32_t timeout_ms); +// Common technology methods +FHalNfcEvent f_hal_nfc_wait_event_common(uint32_t timeout_ms); +FHalNfcError f_hal_nfc_common_listener_rx_start(FuriHalSpiBusHandle* handle); +FHalNfcError + f_hal_nfc_common_fifo_tx(FuriHalSpiBusHandle* handle, const uint8_t* tx_data, size_t tx_bits); +FHalNfcError f_hal_nfc_common_fifo_rx( + FuriHalSpiBusHandle* handle, + uint8_t* rx_data, + size_t rx_data_size, + size_t* rx_bits); + +FHalNfcError + f_hal_nfc_poller_tx_common(FuriHalSpiBusHandle* handle, const uint8_t* tx_data, size_t tx_bits); + +// Technology specific API +typedef FHalNfcError (*FHalNfcChipConfig)(FuriHalSpiBusHandle* handle); +typedef FHalNfcError ( + *FHalNfcTx)(FuriHalSpiBusHandle* handle, const uint8_t* tx_data, size_t tx_bits); +typedef FHalNfcError (*FHalNfcRx)( + FuriHalSpiBusHandle* handle, + uint8_t* rx_data, + size_t rx_data_size, + size_t* rx_bits); +typedef FHalNfcEvent (*FHalNfcWaitEvent)(uint32_t timeout_ms); + +typedef struct { + FHalNfcChipConfig init; + FHalNfcChipConfig deinit; + FHalNfcWaitEvent wait_event; + FHalNfcTx tx; + FHalNfcRx rx; +} FHalNfcTechPollerBase; + +typedef struct { + FHalNfcChipConfig init; + FHalNfcChipConfig deinit; + FHalNfcWaitEvent wait_event; + FHalNfcChipConfig rx_start; + FHalNfcTx tx; + FHalNfcRx rx; +} FHalNfcTechListenerBase; + +typedef struct { + FHalNfcTechPollerBase poller; + FHalNfcTechListenerBase listener; +} FHalNfcTechBase; + +extern const FHalNfcTechBase f_hal_nfc_iso14443a; +extern const FHalNfcTechBase f_hal_nfc_iso14443b; +extern const FHalNfcTechBase f_hal_nfc_iso15693; +extern const FHalNfcTechBase f_hal_nfc_felica; + #ifdef __cplusplus } #endif diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc_irq.c b/firmware/targets/f7/furi_hal/f_hal_nfc_irq.c index f51d1370ffce..95f6c4129280 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfc_irq.c +++ b/firmware/targets/f7/furi_hal/f_hal_nfc_irq.c @@ -4,7 +4,7 @@ #include static void f_hal_nfc_int_callback() { - f_hal_nfc_set_event(FHalNfcEventInternalTypeIrq); + f_hal_nfc_event_set(FHalNfcEventInternalTypeIrq); } uint32_t f_hal_nfc_get_irq(FuriHalSpiBusHandle* handle) { diff --git a/firmware/targets/f7/furi_hal/f_hal_nfca.c b/firmware/targets/f7/furi_hal/f_hal_nfc_iso14443a.c similarity index 51% rename from firmware/targets/f7/furi_hal/f_hal_nfca.c rename to firmware/targets/f7/furi_hal/f_hal_nfc_iso14443a.c index fbd705663a16..c80f9c9960cd 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfca.c +++ b/firmware/targets/f7/furi_hal/f_hal_nfc_iso14443a.c @@ -1,15 +1,96 @@ #include #include -#include -#include -#include #include -#define TAG "FuriHalNfcA" +#include + +#define TAG "FuriHalIso14443a" static Iso14443_3aSignal* iso14443_3a_signal = NULL; +static FHalNfcError f_hal_nfc_iso14443a_common_init(FuriHalSpiBusHandle* handle) { + // Common NFC-A settings, 106 kbps + + // 1st stage zero = 600kHz, 3rd stage zero = 200 kHz + st25r3916_write_reg(handle, ST25R3916_REG_RX_CONF1, ST25R3916_REG_RX_CONF1_z600k); + // AGC enabled, ratio 3:1, squelch after TX + st25r3916_write_reg( + handle, + ST25R3916_REG_RX_CONF2, + ST25R3916_REG_RX_CONF2_agc6_3 | ST25R3916_REG_RX_CONF2_agc_m | + ST25R3916_REG_RX_CONF2_agc_en | ST25R3916_REG_RX_CONF2_sqm_dyn); + // HF operation, full gain on AM and PM channels + st25r3916_write_reg(handle, ST25R3916_REG_RX_CONF3, 0x00); + // No gain reduction on AM and PM channels + st25r3916_write_reg(handle, ST25R3916_REG_RX_CONF4, 0x00); + // Correlator config + st25r3916_write_reg( + handle, + ST25R3916_REG_CORR_CONF1, + ST25R3916_REG_CORR_CONF1_corr_s0 | ST25R3916_REG_CORR_CONF1_corr_s4 | + ST25R3916_REG_CORR_CONF1_corr_s6); + // Sleep mode disable, 424kHz mode off + st25r3916_write_reg(handle, ST25R3916_REG_CORR_CONF2, 0x00); + + return FHalNfcErrorNone; +} + +static FHalNfcError f_hal_nfc_iso14443a_poller_init(FuriHalSpiBusHandle* handle) { + // Enable ISO14443A mode, OOK modulation + st25r3916_change_reg_bits( + handle, + ST25R3916_REG_MODE, + ST25R3916_REG_MODE_om_mask | ST25R3916_REG_MODE_tr_am, + ST25R3916_REG_MODE_om_iso14443a | ST25R3916_REG_MODE_tr_am_ook); + + // Overshoot protection - is this necessary here? + st25r3916_change_reg_bits(handle, ST25R3916_REG_OVERSHOOT_CONF1, 0xff, 0x40); + st25r3916_change_reg_bits(handle, ST25R3916_REG_OVERSHOOT_CONF2, 0xff, 0x03); + st25r3916_change_reg_bits(handle, ST25R3916_REG_UNDERSHOOT_CONF1, 0xff, 0x40); + st25r3916_change_reg_bits(handle, ST25R3916_REG_UNDERSHOOT_CONF2, 0xff, 0x03); + + return f_hal_nfc_iso14443a_common_init(handle); +} + +static FHalNfcError f_hal_nfc_iso14443a_poller_deinit(FuriHalSpiBusHandle* handle) { + UNUSED(handle); + return FHalNfcErrorNone; +} + +static FHalNfcError f_hal_nfc_iso14443a_listener_init(FuriHalSpiBusHandle* handle) { + furi_check(iso14443_3a_signal == NULL); + iso14443_3a_signal = iso14443_3a_signal_alloc(&gpio_spi_r_mosi); + + st25r3916_write_reg( + handle, + ST25R3916_REG_OP_CONTROL, + ST25R3916_REG_OP_CONTROL_en | ST25R3916_REG_OP_CONTROL_rx_en | + ST25R3916_REG_OP_CONTROL_en_fd_auto_efd); + st25r3916_write_reg( + handle, ST25R3916_REG_MODE, ST25R3916_REG_MODE_targ_targ | ST25R3916_REG_MODE_om0); + st25r3916_write_reg( + handle, + ST25R3916_REG_PASSIVE_TARGET, + ST25R3916_REG_PASSIVE_TARGET_fdel_2 | ST25R3916_REG_PASSIVE_TARGET_fdel_0 | + ST25R3916_REG_PASSIVE_TARGET_d_ac_ap2p | ST25R3916_REG_PASSIVE_TARGET_d_212_424_1r); + + st25r3916_write_reg(handle, ST25R3916_REG_MASK_RX_TIMER, 0x02); + + return f_hal_nfc_iso14443a_common_init(handle); +} + +static FHalNfcError f_hal_nfc_iso14443a_listener_deinit(FuriHalSpiBusHandle* handle) { + UNUSED(handle); + + if(iso14443_3a_signal) { + iso14443_3a_signal_free(iso14443_3a_signal); + iso14443_3a_signal = NULL; + } + + return FHalNfcErrorNone; +} + FHalNfcError f_hal_nfca_send_short_frame(FHalNfcaShortFrame frame) { FHalNfcError error = FHalNfcErrorNone; @@ -103,23 +184,25 @@ FHalNfcError return error; } -// TODO change this - -FHalNfcError f_hal_nfca_listener_init() { - furi_check(iso14443_3a_signal == NULL); +FHalNfcError f_hal_iso4443a_listener_tx( + FuriHalSpiBusHandle* handle, + const uint8_t* tx_data, + size_t tx_bits) { + FHalNfcError error = FHalNfcErrorNone; - iso14443_3a_signal = iso14443_3a_signal_alloc(&gpio_spi_r_mosi); + do { + error = f_hal_nfc_common_fifo_tx(handle, tx_data, tx_bits); + if(error != FHalNfcErrorNone) break; - return FHalNfcErrorNone; -} + bool tx_end = f_hal_nfc_event_wait_for_specific_irq(handle, ST25R3916_IRQ_MASK_TXE, 10); + if(!tx_end) { + error = FHalNfcErrorCommunicationTimeout; + break; + } -FHalNfcError f_hal_nfca_listener_deinit() { - if(iso14443_3a_signal) { - iso14443_3a_signal_free(iso14443_3a_signal); - iso14443_3a_signal = NULL; - } + } while(false); - return FHalNfcErrorNone; + return error; } FHalNfcError f_hal_nfca_listener_tx_custom_parity( @@ -150,3 +233,24 @@ FHalNfcError f_hal_nfca_listener_tx_custom_parity( // TODO handle field off return FHalNfcErrorNone; } + +const FHalNfcTechBase f_hal_nfc_iso14443a = { + .poller = + { + .init = f_hal_nfc_iso14443a_poller_init, + .deinit = f_hal_nfc_iso14443a_poller_deinit, + .wait_event = f_hal_nfc_wait_event_common, + .tx = f_hal_nfc_poller_tx_common, + .rx = f_hal_nfc_common_fifo_rx, + }, + + .listener = + { + .init = f_hal_nfc_iso14443a_listener_init, + .deinit = f_hal_nfc_iso14443a_listener_deinit, + .wait_event = f_hal_nfc_wait_event_common, + .rx_start = f_hal_nfc_common_listener_rx_start, + .tx = f_hal_iso4443a_listener_tx, + .rx = f_hal_nfc_common_fifo_rx, + }, +}; diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc_iso14443b.c b/firmware/targets/f7/furi_hal/f_hal_nfc_iso14443b.c new file mode 100644 index 000000000000..a66efbfa8144 --- /dev/null +++ b/firmware/targets/f7/furi_hal/f_hal_nfc_iso14443b.c @@ -0,0 +1,102 @@ +#include "f_hal_nfc_i.h" + +static FHalNfcError f_hal_nfc_iso14443b_common_init(FuriHalSpiBusHandle* handle) { + // Common NFC-B settings, 106kbps + + // 1st stage zero = 60kHz, 3rd stage zero = 200 kHz + st25r3916_write_reg(handle, ST25R3916_REG_RX_CONF1, ST25R3916_REG_RX_CONF1_h200); + + // Enable AGC + // AGC Ratio 6 + // AGC algorithm with RESET (recommended for ISO14443-B) + // AGC operation during complete receive period + // Squelch ratio 6/3 (recommended for ISO14443-B) + // Squelch automatic activation on TX end + st25r3916_write_reg( + handle, + ST25R3916_REG_RX_CONF2, + ST25R3916_REG_RX_CONF2_agc6_3 | ST25R3916_REG_RX_CONF2_agc_alg | + ST25R3916_REG_RX_CONF2_agc_m | ST25R3916_REG_RX_CONF2_agc_en | + ST25R3916_REG_RX_CONF2_pulz_61 | ST25R3916_REG_RX_CONF2_sqm_dyn); + + // HF operation, full gain on AM and PM channels + st25r3916_write_reg(handle, ST25R3916_REG_RX_CONF3, 0x00); + // No gain reduction on AM and PM channels + st25r3916_write_reg(handle, ST25R3916_REG_RX_CONF4, 0x00); + + // Subcarrier end detector enabled + // Subcarrier end detection level = 66% + // BPSK start 33 pilot pulses + // AM & PM summation before digitizing on + st25r3916_write_reg( + handle, + ST25R3916_REG_CORR_CONF1, + ST25R3916_REG_CORR_CONF1_corr_s0 | ST25R3916_REG_CORR_CONF1_corr_s1 | + ST25R3916_REG_CORR_CONF1_corr_s3 | ST25R3916_REG_CORR_CONF1_corr_s4); + // Sleep mode disable, 424kHz mode off + st25r3916_write_reg(handle, ST25R3916_REG_CORR_CONF2, 0x00); + + return FHalNfcErrorNone; +} + +static FHalNfcError f_hal_nfc_iso14443b_poller_init(FuriHalSpiBusHandle* handle) { + // Enable ISO14443B mode, AM modulation + st25r3916_change_reg_bits( + handle, + ST25R3916_REG_MODE, + ST25R3916_REG_MODE_om_mask | ST25R3916_REG_MODE_tr_am, + ST25R3916_REG_MODE_om_iso14443b | ST25R3916_REG_MODE_tr_am_am); + + // 10% ASK modulation + st25r3916_change_reg_bits( + handle, + ST25R3916_REG_TX_DRIVER, + ST25R3916_REG_TX_DRIVER_am_mod_mask, + ST25R3916_REG_TX_DRIVER_am_mod_10percent); + + // Use regulator AM, resistive AM disabled + st25r3916_clear_reg_bits( + handle, + ST25R3916_REG_AUX_MOD, + ST25R3916_REG_AUX_MOD_dis_reg_am | ST25R3916_REG_AUX_MOD_res_am); + + // EGT = 0 etu + // SOF = 10 etu LOW + 2 etu HIGH + // EOF = 10 etu + st25r3916_change_reg_bits( + handle, + ST25R3916_REG_ISO14443B_1, + ST25R3916_REG_ISO14443B_1_egt_mask | ST25R3916_REG_ISO14443B_1_sof_mask | + ST25R3916_REG_ISO14443B_1_eof, + (0U << ST25R3916_REG_ISO14443B_1_egt_shift) | ST25R3916_REG_ISO14443B_1_sof_0_10etu | + ST25R3916_REG_ISO14443B_1_sof_1_2etu | ST25R3916_REG_ISO14443B_1_eof_10etu); + + // TR1 = 80 / fs + // B' mode off (no_sof & no_eof = 0) + st25r3916_change_reg_bits( + handle, + ST25R3916_REG_ISO14443B_2, + ST25R3916_REG_ISO14443B_2_tr1_mask | ST25R3916_REG_ISO14443B_2_no_sof | + ST25R3916_REG_ISO14443B_2_no_eof, + ST25R3916_REG_ISO14443B_2_tr1_80fs80fs); + + return f_hal_nfc_iso14443b_common_init(handle); +} + +static FHalNfcError f_hal_nfc_iso14443b_poller_deinit(FuriHalSpiBusHandle* handle) { + UNUSED(handle); + return FHalNfcErrorNone; +} + +const FHalNfcTechBase f_hal_nfc_iso14443b = { + .poller = + { + .init = f_hal_nfc_iso14443b_poller_init, + .deinit = f_hal_nfc_iso14443b_poller_deinit, + .wait_event = f_hal_nfc_wait_event_common, + .tx = f_hal_nfc_poller_tx_common, + .rx = f_hal_nfc_common_fifo_rx, + }, + + .listener = {0}, +}; diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc_iso15693.c b/firmware/targets/f7/furi_hal/f_hal_nfc_iso15693.c new file mode 100644 index 000000000000..9cffba652cfb --- /dev/null +++ b/firmware/targets/f7/furi_hal/f_hal_nfc_iso15693.c @@ -0,0 +1,434 @@ +#include "f_hal_nfc_i.h" + +#include +#include + +#include + +#define F_HAL_NFC_ISO15693_MAX_FRAME_SIZE (1024U) +#define F_HAL_NFC_ISO15693_POLLER_MAX_BUFFER_SIZE (64) + +#define F_HAL_NFC_ISO15693_RESP_SOF_SIZE (5) +#define F_HAL_NFC_ISO15693_RESP_EOF_SIZE (5) +#define F_HAL_NFC_ISO15693_RESP_SOF_MASK (0x1FU) +#define F_HAL_NFC_ISO15693_RESP_SOF_PATTERN (0x17U) +#define F_HAL_NFC_ISO15693_RESP_EOF_PATTERN (0x1DU) + +#define F_HAL_NFC_ISO15693_RESP_PATTERN_MASK (0x03U) +#define F_HAL_NFC_ISO15693_RESP_PATTERN_0 (0x01U) +#define F_HAL_NFC_ISO15693_RESP_PATTERN_1 (0x02U) + +#define BITS_IN_BYTE (8U) + +#define TAG "FuriHalIso15693" + +typedef struct { + Iso15693Signal* signal; + Iso15693Parser* parser; +} FHalNfcIso15693Listener; + +typedef struct { + // 4 bits per data bit on transmit + uint8_t fifo_buf[F_HAL_NFC_ISO15693_POLLER_MAX_BUFFER_SIZE * 4]; + size_t fifo_buf_bits; + uint8_t frame_buf[F_HAL_NFC_ISO15693_POLLER_MAX_BUFFER_SIZE * 2]; + size_t frame_buf_bits; +} FHalNfcIso15693Poller; + +static FHalNfcIso15693Listener* f_hal_nfc_iso15693_listener = NULL; +static FHalNfcIso15693Poller* f_hal_nfc_iso15693_poller = NULL; + +static FHalNfcIso15693Listener* f_hal_nfc_iso15693_listener_alloc() { + FHalNfcIso15693Listener* instance = malloc(sizeof(FHalNfcIso15693Listener)); + + instance->signal = iso15693_signal_alloc(&gpio_spi_r_mosi); + instance->parser = iso15693_parser_alloc(&gpio_spi_r_miso, F_HAL_NFC_ISO15693_MAX_FRAME_SIZE); + + return instance; +} + +static void f_hal_nfc_iso15693_listener_free(FHalNfcIso15693Listener* instance) { + furi_assert(instance); + + iso15693_signal_free(instance->signal); + iso15693_parser_free(instance->parser); + + free(instance); +} + +static FHalNfcIso15693Poller* f_hal_nfc_iso15693_poller_alloc() { + FHalNfcIso15693Poller* instance = malloc(sizeof(FHalNfcIso15693Poller)); + + return instance; +} + +static void f_hal_nfc_iso15693_poller_free(FHalNfcIso15693Poller* instance) { + furi_assert(instance); + + free(instance); +} + +static FHalNfcError f_hal_nfc_iso15693_common_init(FuriHalSpiBusHandle* handle) { + // Common NFC-V settings, 26.48 kbps + + // 1st stage zero = 12 kHz, 3rd stage zero = 80 kHz, low-pass = 600 kHz + st25r3916_write_reg( + handle, + ST25R3916_REG_RX_CONF1, + ST25R3916_REG_RX_CONF1_z12k | ST25R3916_REG_RX_CONF1_h80 | + ST25R3916_REG_RX_CONF1_lp_600khz); + + // Enable AGC + // AGC Ratio 6 + // AGC algorithm with RESET (recommended for ISO15693) + // AGC operation during complete receive period + // Squelch automatic activation on TX end + st25r3916_write_reg( + handle, + ST25R3916_REG_RX_CONF2, + ST25R3916_REG_RX_CONF2_agc6_3 | ST25R3916_REG_RX_CONF2_agc_m | + ST25R3916_REG_RX_CONF2_agc_en | ST25R3916_REG_RX_CONF2_sqm_dyn); + + // HF operation, full gain on AM and PM channels + st25r3916_write_reg(handle, ST25R3916_REG_RX_CONF3, 0x00); + // No gain reduction on AM and PM channels + st25r3916_write_reg(handle, ST25R3916_REG_RX_CONF4, 0x00); + + // Collision detection level 53% + // AM & PM summation before digitizing on + st25r3916_write_reg( + handle, + ST25R3916_REG_CORR_CONF1, + ST25R3916_REG_CORR_CONF1_corr_s0 | ST25R3916_REG_CORR_CONF1_corr_s1 | + ST25R3916_REG_CORR_CONF1_corr_s4); + // 424 kHz subcarrier stream mode on + st25r3916_write_reg(handle, ST25R3916_REG_CORR_CONF2, ST25R3916_REG_CORR_CONF2_corr_s8); + return FHalNfcErrorNone; +} + +static FHalNfcError f_hal_nfc_iso15693_poller_init(FuriHalSpiBusHandle* handle) { + furi_assert(f_hal_nfc_iso15693_poller == NULL); + + f_hal_nfc_iso15693_poller = f_hal_nfc_iso15693_poller_alloc(); + + // Enable Subcarrier Stream mode, OOK modulation + st25r3916_change_reg_bits( + handle, + ST25R3916_REG_MODE, + ST25R3916_REG_MODE_om_mask | ST25R3916_REG_MODE_tr_am, + ST25R3916_REG_MODE_om_subcarrier_stream | ST25R3916_REG_MODE_tr_am_ook); + + // Subcarrier 424 kHz mode + // 8 sub-carrier pulses in report period + st25r3916_write_reg( + handle, + ST25R3916_REG_STREAM_MODE, + ST25R3916_REG_STREAM_MODE_scf_sc424 | ST25R3916_REG_STREAM_MODE_stx_106 | + ST25R3916_REG_STREAM_MODE_scp_8pulses); + + // Use regulator AM, resistive AM disabled + st25r3916_clear_reg_bits( + handle, + ST25R3916_REG_AUX_MOD, + ST25R3916_REG_AUX_MOD_dis_reg_am | ST25R3916_REG_AUX_MOD_res_am); + + return f_hal_nfc_iso15693_common_init(handle); +} + +static FHalNfcError f_hal_nfc_iso15693_poller_deinit(FuriHalSpiBusHandle* handle) { + UNUSED(handle); + furi_assert(f_hal_nfc_iso15693_poller); + + f_hal_nfc_iso15693_poller_free(f_hal_nfc_iso15693_poller); + f_hal_nfc_iso15693_poller = NULL; + + return FHalNfcErrorNone; +} + +static void iso15693_3_poller_encode_frame( + const uint8_t* tx_data, + size_t tx_bits, + uint8_t* frame_buf, + size_t frame_buf_size, + size_t* frame_buf_bits) { + static const uint8_t bit_patterns_1_out_of_4[] = {0x02, 0x08, 0x20, 0x80}; + size_t frame_buf_size_calc = (tx_bits / 2) + 2; + furi_assert(frame_buf_size >= frame_buf_size_calc); + + // Add SOF 1 out of 4 + frame_buf[0] = 0x21; + + size_t byte_pos = 1; + for(size_t i = 0; i < tx_bits / BITS_IN_BYTE; ++i) { + for(size_t j = 0; j < BITS_IN_BYTE; j += (BITS_IN_BYTE) / 4) { + const uint8_t bit_pair = (tx_data[i] >> j) & 0x03; + frame_buf[byte_pos++] = bit_patterns_1_out_of_4[bit_pair]; + } + } + // Add EOF + frame_buf[byte_pos++] = 0x04; + *frame_buf_bits = byte_pos * BITS_IN_BYTE; +} + +static bool iso15693_3_poller_decode_frame( + const uint8_t* buf, + size_t buf_bits, + uint8_t* buf_decoded, + size_t buf_decoded_size, + size_t* buf_decoded_bits) { + bool decoded = false; + size_t bit_pos = 0; + memset(buf_decoded, 0, buf_decoded_size); + + do { + if(buf_bits == 0) break; + // Check SOF + if((buf[0] & F_HAL_NFC_ISO15693_RESP_SOF_MASK) != F_HAL_NFC_ISO15693_RESP_SOF_PATTERN) + break; + + // 2 response bits = 1 data bit + for(uint32_t i = F_HAL_NFC_ISO15693_RESP_SOF_SIZE; + i < buf_bits - F_HAL_NFC_ISO15693_RESP_SOF_SIZE; + i += BITS_IN_BYTE / 4) { + const size_t byte_index = i / BITS_IN_BYTE; + const size_t bit_offset = i % BITS_IN_BYTE; + const uint8_t resp_byte = (buf[byte_index] >> bit_offset) | + (buf[byte_index + 1] << (BITS_IN_BYTE - bit_offset)); + + // Check EOF + if(resp_byte == F_HAL_NFC_ISO15693_RESP_EOF_PATTERN) { + decoded = true; + break; + } + + const uint8_t bit_pattern = resp_byte & F_HAL_NFC_ISO15693_RESP_PATTERN_MASK; + + if(bit_pattern == F_HAL_NFC_ISO15693_RESP_PATTERN_0) { + bit_pos++; + } else if(bit_pattern == F_HAL_NFC_ISO15693_RESP_PATTERN_1) { + buf_decoded[bit_pos / BITS_IN_BYTE] |= 1 << (bit_pos % BITS_IN_BYTE); + bit_pos++; + } else { + break; + } + if(bit_pos / BITS_IN_BYTE > buf_decoded_size) { + break; + } + } + + } while(false); + + if(decoded) { + *buf_decoded_bits = bit_pos; + } + + return decoded; +} + +static FHalNfcError f_hal_nfc_iso15693_poller_tx( + FuriHalSpiBusHandle* handle, + const uint8_t* tx_data, + size_t tx_bits) { + FHalNfcIso15693Poller* instance = f_hal_nfc_iso15693_poller; + iso15693_3_poller_encode_frame( + tx_data, + tx_bits, + instance->frame_buf, + sizeof(instance->frame_buf), + &instance->frame_buf_bits); + return f_hal_nfc_poller_tx_common(handle, instance->frame_buf, instance->frame_buf_bits); +} + +static FHalNfcError f_hal_nfc_iso15693_poller_rx( + FuriHalSpiBusHandle* handle, + uint8_t* rx_data, + size_t rx_data_size, + size_t* rx_bits) { + FHalNfcError error = FHalNfcErrorNone; + FHalNfcIso15693Poller* instance = f_hal_nfc_iso15693_poller; + + do { + error = f_hal_nfc_common_fifo_rx( + handle, instance->fifo_buf, sizeof(instance->fifo_buf), &instance->fifo_buf_bits); + if(error != FHalNfcErrorNone) break; + + if(!iso15693_3_poller_decode_frame( + instance->fifo_buf, + instance->fifo_buf_bits, + instance->frame_buf, + sizeof(instance->frame_buf), + &instance->frame_buf_bits)) { + error = FHalNfcErrorDataFormat; + break; + } + if(rx_data_size < instance->frame_buf_bits / BITS_IN_BYTE) { + error = FHalNfcErrorBufferOverflow; + break; + } + + memcpy(rx_data, instance->frame_buf, instance->frame_buf_bits / BITS_IN_BYTE); + *rx_bits = instance->frame_buf_bits; + } while(false); + + return error; +} + +static FHalNfcError f_hal_nfc_iso15693_listener_init(FuriHalSpiBusHandle* handle) { + furi_assert(f_hal_nfc_iso15693_listener == NULL); + + f_hal_nfc_iso15693_listener = f_hal_nfc_iso15693_listener_alloc(); + + // Set default operation mode + st25r3916_change_reg_bits( + handle, + ST25R3916_REG_MODE, + ST25R3916_REG_MODE_om_mask | ST25R3916_REG_MODE_tr_am, + ST25R3916_REG_MODE_om_targ_nfca | ST25R3916_REG_MODE_tr_am_ook); + + st25r3916_change_reg_bits( + handle, + ST25R3916_REG_OP_CONTROL, + ST25R3916_REG_OP_CONTROL_rx_en, + ST25R3916_REG_OP_CONTROL_rx_en); + + // Enable passive target mode + st25r3916_change_reg_bits( + handle, ST25R3916_REG_MODE, ST25R3916_REG_MODE_targ, ST25R3916_REG_MODE_targ_targ); + + return f_hal_nfc_iso15693_common_init(handle); +} + +static FHalNfcError f_hal_nfc_iso15693_listener_deinit(FuriHalSpiBusHandle* handle) { + UNUSED(handle); + furi_assert(f_hal_nfc_iso15693_listener); + + f_hal_nfc_iso15693_listener_free(f_hal_nfc_iso15693_listener); + f_hal_nfc_iso15693_listener = NULL; + + return FHalNfcErrorNone; +} + +static void f_hal_nfc_iso15693_listener_transparent_mode_enter(FuriHalSpiBusHandle* handle) { + st25r3916_direct_cmd(handle, ST25R3916_CMD_TRANSPARENT_MODE); + + furi_hal_spi_bus_handle_deinit(handle); + f_hal_nfc_deinit_gpio_isr(); +} + +static void f_hal_nfc_iso15693_listener_transparent_mode_exit(FuriHalSpiBusHandle* handle) { + // Configure gpio back to SPI and exit transparent mode + f_hal_nfc_init_gpio_isr(); + furi_hal_spi_bus_handle_init(handle); + + st25r3916_direct_cmd(handle, ST25R3916_CMD_UNMASK_RECEIVE_DATA); +} + +static FHalNfcError + f_hal_nfc_iso15693_listener_tx_transparent(const uint8_t* data, size_t data_size) { + iso15693_signal_tx( + f_hal_nfc_iso15693_listener->signal, Iso15693SignalDataRateHi, data, data_size); + + return FHalNfcErrorNone; +} + +static FHalNfcError f_hal_nfc_iso15693_listener_rx_start(FuriHalSpiBusHandle* handle) { + UNUSED(handle); + return FHalNfcErrorNone; +} + +static void f_hal_nfc_iso15693_parser_callback(Iso15693ParserEvent event, void* context) { + furi_assert(context); + + if(event == Iso15693ParserEventDataReceived) { + FuriThreadId thread_id = context; + furi_thread_flags_set(thread_id, FHalNfcEventInternalTypeTransparentDataReceived); + } +} + +static FHalNfcEvent f_hal_nfc_iso15693_wait_event(uint32_t timeout_ms) { + FHalNfcEvent event = 0; + FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; + + f_hal_nfc_iso15693_listener_transparent_mode_enter(handle); + FuriThreadId thread_id = furi_thread_get_current_id(); + iso15693_parser_start( + f_hal_nfc_iso15693_listener->parser, f_hal_nfc_iso15693_parser_callback, thread_id); + + while(true) { + uint32_t flag = furi_thread_flags_wait( + FHalNfcEventInternalTypeAbort | FHalNfcEventInternalTypeTransparentDataReceived, + FuriFlagWaitAny, + timeout_ms); + furi_thread_flags_clear(flag); + + if(flag & FHalNfcEventInternalTypeAbort) { + event = FHalNfcEventAbortRequest; + break; + } + if(flag & FHalNfcEventInternalTypeTransparentDataReceived) { + if(iso15693_parser_run(f_hal_nfc_iso15693_listener->parser)) { + event = FHalNfcEventRxEnd; + break; + } + } + } + + iso15693_parser_stop(f_hal_nfc_iso15693_listener->parser); + f_hal_nfc_iso15693_listener_transparent_mode_exit(handle); + + return event; +} + +static FHalNfcError f_hal_nfc_iso15693_listener_tx( + FuriHalSpiBusHandle* handle, + const uint8_t* tx_data, + size_t tx_bits) { + furi_assert(f_hal_nfc_iso15693_listener); + + FHalNfcError error = FHalNfcErrorNone; + f_hal_nfc_iso15693_listener_transparent_mode_enter(handle); + + error = f_hal_nfc_iso15693_listener_tx_transparent(tx_data, tx_bits / BITS_IN_BYTE); + + f_hal_nfc_iso15693_listener_transparent_mode_exit(handle); + + return error; +} + +static FHalNfcError f_hal_nfc_iso15693_listener_rx( + FuriHalSpiBusHandle* handle, + uint8_t* rx_data, + size_t rx_data_size, + size_t* rx_bits) { + furi_assert(f_hal_nfc_iso15693_listener); + UNUSED(handle); + + if(rx_data_size < iso15693_parser_get_data_size_bytes(f_hal_nfc_iso15693_listener->parser)) { + return FHalNfcErrorBufferOverflow; + } + + iso15693_parser_get_data(f_hal_nfc_iso15693_listener->parser, rx_data, rx_data_size, rx_bits); + + return FHalNfcErrorNone; +} + +const FHalNfcTechBase f_hal_nfc_iso15693 = { + .poller = + { + .init = f_hal_nfc_iso15693_poller_init, + .deinit = f_hal_nfc_iso15693_poller_deinit, + .wait_event = f_hal_nfc_wait_event_common, + .tx = f_hal_nfc_iso15693_poller_tx, + .rx = f_hal_nfc_iso15693_poller_rx, + }, + + .listener = + { + .init = f_hal_nfc_iso15693_listener_init, + .deinit = f_hal_nfc_iso15693_listener_deinit, + .wait_event = f_hal_nfc_iso15693_wait_event, + .rx_start = f_hal_nfc_iso15693_listener_rx_start, + .tx = f_hal_nfc_iso15693_listener_tx, + .rx = f_hal_nfc_iso15693_listener_rx, + }, +}; diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc_timer.c b/firmware/targets/f7/furi_hal/f_hal_nfc_timer.c index 1055a16d08f3..be6c3b1d59be 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfc_timer.c +++ b/firmware/targets/f7/furi_hal/f_hal_nfc_timer.c @@ -57,7 +57,7 @@ static void f_hal_nfc_timer_irq_callback(void* context) { FHalNfcTimerConfig* timer = context; if(LL_TIM_IsActiveFlag_UPDATE(timer->timer)) { LL_TIM_ClearFlag_UPDATE(timer->timer); - f_hal_nfc_set_event(timer->event); + f_hal_nfc_event_set(timer->event); furi_hal_gpio_write(timer->pin, false); } } diff --git a/firmware/targets/f7/target.json b/firmware/targets/f7/target.json index 0c083b68ddba..f58200c4688d 100644 --- a/firmware/targets/f7/target.json +++ b/firmware/targets/f7/target.json @@ -30,6 +30,7 @@ "nfc", "digital_signal", "pulse_reader", + "signal_reader", "microtar", "usb_stm32", "st25rfal002", diff --git a/firmware/targets/furi_hal_include/f_hal_nfc.h b/firmware/targets/furi_hal_include/f_hal_nfc.h index d8cd41141781..f7af6c19df91 100644 --- a/firmware/targets/furi_hal_include/f_hal_nfc.h +++ b/firmware/targets/furi_hal_include/f_hal_nfc.h @@ -38,28 +38,24 @@ typedef enum { FHalNfcErrorIsrTimeout, FHalNfcErrorCommunicationTimeout, FHalNfcErrorBufferOverflow, + FHalNfcErrorDataFormat, } FHalNfcError; typedef enum { - FHalNfcModeIso14443aPoller, - FHalNfcModeIso14443aListener, - - FHalNfcModeIso14443bPoller, - FHalNfcModeIso14443bListener, - - FHalNfcModeFelicaPoller, - FHalNfcModeNfcfListener, - - FHalNfcModeIso15693Poller, - FHalNfcModeIso15693Listener, + FHalNfcModePoller, + FHalNfcModeListener, FHalNfcModeNum, } FHalNfcMode; typedef enum { - FHalNfcBitrate26p48, - FHalNfcBitrate106, -} FHalNfcBitrate; + FHalNfcTechIso14443a, + FHalNfcTechIso14443b, + FHalNfcTechIso15693, + FHalNfcTechFelica, + + FHalNfcTechNum, +} FHalNfcTech; typedef enum { FHalNfcaShortFrameAllReq, @@ -97,7 +93,7 @@ FHalNfcError f_hal_nfc_low_power_mode_stop(); * * @return FHalNfcError */ -FHalNfcError f_hal_nfc_set_mode(FHalNfcMode mode, FHalNfcBitrate bitrate); +FHalNfcError f_hal_nfc_set_mode(FHalNfcMode mode, FHalNfcTech tech); FHalNfcError f_hal_nfc_reset_mode(); @@ -112,7 +108,9 @@ FHalNfcError f_hal_nfc_acquire(); FHalNfcError f_hal_nfc_release(); -FHalNfcError f_hal_nfc_event_start(); +FHalNfcEvent f_hal_nfc_poller_wait_event(uint32_t timeout_ms); + +FHalNfcEvent f_hal_nfc_listener_wait_event(uint32_t timeout_ms); FHalNfcError f_hal_nfc_poller_tx(const uint8_t* tx_data, size_t tx_bits); @@ -122,19 +120,23 @@ FHalNfcError f_hal_nfc_poller_rx(uint8_t* rx_data, size_t rx_data_size, size_t* FHalNfcError f_hal_nfc_listener_tx(const uint8_t* tx_data, size_t tx_bits); -FHalNfcError f_hal_nfc_trx_reset(); +FHalNfcError f_hal_nfc_listener_rx_start(); -FHalNfcError f_hal_nfc_listen_start(); +FHalNfcError f_hal_nfc_listener_rx(uint8_t* rx_data, size_t rx_data_size, size_t* rx_bits); -FHalNfcError f_hal_nfc_listen_reset(); +FHalNfcError f_hal_nfc_listener_start(); + +FHalNfcError f_hal_nfc_listener_reset(); FHalNfcError f_hal_nfc_listener_sleep(); FHalNfcError f_hal_nfc_listener_disable_auto_col_res(); +FHalNfcError f_hal_nfc_trx_reset(); + FHalNfcError f_hal_nfc_abort(); -FHalNfcEvent f_hal_nfc_wait_event(uint32_t timeout_ms); +FHalNfcError f_hal_nfc_event_start(); void f_hal_nfc_timer_fwt_start(uint32_t time_fc); @@ -158,11 +160,6 @@ FHalNfcError f_hal_nfca_send_sdd_frame(const uint8_t* tx_data, size_t tx_bits); FHalNfcError f_hal_nfca_receive_sdd_frame(uint8_t* rx_data, size_t rx_data_size, size_t* rx_bits); -// TODO virtual methods? -FHalNfcError f_hal_nfca_listener_init(); - -FHalNfcError f_hal_nfca_listener_deinit(); - FHalNfcError furi_hal_nfca_set_col_res_data(uint8_t* uid, uint8_t uid_len, uint8_t* atqa, uint8_t sak); diff --git a/lib/SConscript b/lib/SConscript index ab78c6ea4d44..9dfa35671a3b 100644 --- a/lib/SConscript +++ b/lib/SConscript @@ -5,6 +5,7 @@ env.Append( Dir("app-scened-template"), Dir("digital_signal"), Dir("pulse_reader"), + Dir("signal_reader"), Dir("drivers"), Dir("flipper_format"), Dir("infrared"), @@ -97,6 +98,7 @@ libs = env.BuildModules( "nfc", "digital_signal", "pulse_reader", + "signal_reader", "appframe", "misc", "lfrfid", diff --git a/lib/digital_signal/presets/nfc/iso15693_signal.c b/lib/digital_signal/presets/nfc/iso15693_signal.c new file mode 100644 index 000000000000..d140c7593c68 --- /dev/null +++ b/lib/digital_signal/presets/nfc/iso15693_signal.c @@ -0,0 +1,196 @@ +#include "iso15693_signal.h" + +#include + +#define BITS_IN_BYTE (8U) + +#define ISO15693_SIGNAL_COEFF_HI (1U) +#define ISO15693_SIGNAL_COEFF_LO (4U) + +#define ISO15693_SIGNAL_ZERO_EDGES (16U) +#define ISO15693_SIGNAL_ONE_EDGES (ISO15693_SIGNAL_ZERO_EDGES + 1U) +#define ISO15693_SIGNAL_EOF_EDGES (64U) +#define ISO15693_SIGNAL_SOF_EDGES (ISO15693_SIGNAL_EOF_EDGES + 1U) +#define ISO15693_SIGNAL_EDGES (1350U) + +#define ISO15693_SIGNAL_FC (13.56e6) +#define ISO15693_SIGNAL_FC_16 (16.0e11 / ISO15693_SIGNAL_FC) +#define ISO15693_SIGNAL_FC_256 (256.0e11 / ISO15693_SIGNAL_FC) +#define ISO15693_SIGNAL_FC_768 (768.0e11 / ISO15693_SIGNAL_FC) + +typedef enum { + Iso15693SignalIndexSof, + Iso15693SignalIndexEof, + Iso15693SignalIndexOne, + Iso15693SignalIndexZero, + Iso15693SignalIndexNum, +} Iso15693SignalIndex; + +typedef DigitalSignal* Iso15693SignalBank[Iso15693SignalIndexNum]; + +struct Iso15693Signal { + DigitalSequence* tx_sequence; + Iso15693SignalBank banks[Iso15693SignalDataRateNum]; +}; + +// Add an unmodulated signal for the length of Fc / 256 * k (where k = 1 or 4) +static void iso15693_add_silence(DigitalSignal* signal, Iso15693SignalDataRate data_rate) { + const uint32_t k = data_rate == Iso15693SignalDataRateHi ? ISO15693_SIGNAL_COEFF_HI : + ISO15693_SIGNAL_COEFF_LO; + digital_signal_add_pulse(signal, ISO15693_SIGNAL_FC_256 * k, false); +} + +// Add 8 * k subcarrier pulses of Fc / 16 (where k = 1 or 4) +static void iso15693_add_subcarrier(DigitalSignal* signal, Iso15693SignalDataRate data_rate) { + const uint32_t k = data_rate == Iso15693SignalDataRateHi ? ISO15693_SIGNAL_COEFF_HI : + ISO15693_SIGNAL_COEFF_LO; + for(uint32_t i = 0; i < ISO15693_SIGNAL_ZERO_EDGES * k; ++i) { + digital_signal_add_pulse(signal, ISO15693_SIGNAL_FC_16, !(i % 2)); + } +} + +static void iso15693_add_bit(DigitalSignal* signal, Iso15693SignalDataRate data_rate, bool bit) { + if(bit) { + iso15693_add_silence(signal, data_rate); + iso15693_add_subcarrier(signal, data_rate); + } else { + iso15693_add_subcarrier(signal, data_rate); + iso15693_add_silence(signal, data_rate); + } +} + +static inline void iso15693_add_sof(DigitalSignal* signal, Iso15693SignalDataRate data_rate) { + for(uint32_t i = 0; i < ISO15693_SIGNAL_FC_768 / ISO15693_SIGNAL_FC_256; ++i) { + iso15693_add_silence(signal, data_rate); + } + + for(uint32_t i = 0; i < ISO15693_SIGNAL_FC_768 / ISO15693_SIGNAL_FC_256; ++i) { + iso15693_add_subcarrier(signal, data_rate); + } + + iso15693_add_bit(signal, data_rate, true); +} + +static inline void iso15693_add_eof(DigitalSignal* signal, Iso15693SignalDataRate data_rate) { + iso15693_add_bit(signal, data_rate, false); + + for(uint32_t i = 0; i < ISO15693_SIGNAL_FC_768 / ISO15693_SIGNAL_FC_256; ++i) { + iso15693_add_subcarrier(signal, data_rate); + } + + for(uint32_t i = 0; i < ISO15693_SIGNAL_FC_768 / ISO15693_SIGNAL_FC_256; ++i) { + iso15693_add_silence(signal, data_rate); + } +} + +static inline uint32_t + iso15693_get_sequence_index(Iso15693SignalIndex index, Iso15693SignalDataRate data_rate) { + return index + data_rate * Iso15693SignalIndexNum; +} + +static inline void + iso15693_add_byte(Iso15693Signal* instance, Iso15693SignalDataRate data_rate, uint8_t byte) { + for(size_t i = 0; i < BITS_IN_BYTE; i++) { + const uint8_t bit = byte & (1U << i); + digital_sequence_add( + instance->tx_sequence, + iso15693_get_sequence_index( + bit ? Iso15693SignalIndexOne : Iso15693SignalIndexZero, data_rate)); + } +} + +static inline void iso15693_signal_encode( + Iso15693Signal* instance, + Iso15693SignalDataRate data_rate, + const uint8_t* tx_data, + size_t tx_data_size) { + digital_sequence_add( + instance->tx_sequence, iso15693_get_sequence_index(Iso15693SignalIndexSof, data_rate)); + + for(size_t i = 0; i < tx_data_size; i++) { + iso15693_add_byte(instance, data_rate, tx_data[i]); + } + + digital_sequence_add( + instance->tx_sequence, iso15693_get_sequence_index(Iso15693SignalIndexEof, data_rate)); +} + +static void iso15693_signal_bank_fill(Iso15693Signal* instance, Iso15693SignalDataRate data_rate) { + const uint32_t k = data_rate == Iso15693SignalDataRateHi ? ISO15693_SIGNAL_COEFF_HI : + ISO15693_SIGNAL_COEFF_LO; + DigitalSignal** bank = instance->banks[data_rate]; + + // FIXME: possibly a couple of wasted edges when k > 1 + bank[Iso15693SignalIndexSof] = digital_signal_alloc(ISO15693_SIGNAL_SOF_EDGES * k); + bank[Iso15693SignalIndexEof] = digital_signal_alloc(ISO15693_SIGNAL_EOF_EDGES * k); + bank[Iso15693SignalIndexOne] = digital_signal_alloc(ISO15693_SIGNAL_ONE_EDGES * k); + bank[Iso15693SignalIndexZero] = digital_signal_alloc(ISO15693_SIGNAL_ZERO_EDGES * k); + + iso15693_add_sof(bank[Iso15693SignalIndexSof], data_rate); + iso15693_add_eof(bank[Iso15693SignalIndexEof], data_rate); + iso15693_add_bit(bank[Iso15693SignalIndexOne], data_rate, true); + iso15693_add_bit(bank[Iso15693SignalIndexZero], data_rate, false); +} + +static void + iso15693_signal_bank_clear(Iso15693Signal* instance, Iso15693SignalDataRate data_rate) { + DigitalSignal** bank = instance->banks[data_rate]; + + for(uint32_t i = 0; i < Iso15693SignalIndexNum; ++i) { + digital_signal_free(bank[i]); + } +} + +static void + iso15693_signal_bank_register(Iso15693Signal* instance, Iso15693SignalDataRate data_rate) { + for(uint32_t i = 0; i < Iso15693SignalIndexNum; ++i) { + digital_sequence_set_signal( + instance->tx_sequence, + iso15693_get_sequence_index(i, data_rate), + instance->banks[data_rate][i]); + } +} + +Iso15693Signal* iso15693_signal_alloc(const GpioPin* pin) { + furi_assert(pin); + + Iso15693Signal* instance = malloc(sizeof(Iso15693Signal)); + + instance->tx_sequence = digital_sequence_alloc(BITS_IN_BYTE * 255 + 2, pin); + + for(uint32_t i = 0; i < Iso15693SignalDataRateNum; ++i) { + iso15693_signal_bank_fill(instance, i); + iso15693_signal_bank_register(instance, i); + } + + return instance; +} + +void iso15693_signal_free(Iso15693Signal* instance) { + furi_assert(instance); + + digital_sequence_free(instance->tx_sequence); + + for(uint32_t i = 0; i < Iso15693SignalDataRateNum; ++i) { + iso15693_signal_bank_clear(instance, i); + } + + free(instance); +} + +void iso15693_signal_tx( + Iso15693Signal* instance, + Iso15693SignalDataRate data_rate, + const uint8_t* tx_data, + size_t tx_data_size) { + furi_assert(instance); + furi_assert(data_rate < Iso15693SignalDataRateNum); + furi_assert(tx_data); + furi_assert(tx_data_size / BITS_IN_BYTE); + + FURI_CRITICAL_ENTER(); + digital_sequence_clear(instance->tx_sequence); + iso15693_signal_encode(instance, data_rate, tx_data, tx_data_size); + digital_sequence_send(instance->tx_sequence); + FURI_CRITICAL_EXIT(); +} diff --git a/lib/digital_signal/presets/nfc/iso15693_signal.h b/lib/digital_signal/presets/nfc/iso15693_signal.h new file mode 100644 index 000000000000..e5f2c3ca7fb2 --- /dev/null +++ b/lib/digital_signal/presets/nfc/iso15693_signal.h @@ -0,0 +1,32 @@ +#pragma once + +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct Iso15693Signal Iso15693Signal; + +typedef enum { + Iso15693SignalDataRateHi, + Iso15693SignalDataRateLo, + Iso15693SignalDataRateNum, +} Iso15693SignalDataRate; + +Iso15693Signal* iso15693_signal_alloc(const GpioPin* pin); + +void iso15693_signal_free(Iso15693Signal* instance); + +void iso15693_signal_tx( + Iso15693Signal* instance, + Iso15693SignalDataRate data_rate, + const uint8_t* tx_data, + size_t tx_data_size); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/helpers/iso13239_crc.h b/lib/nfc/helpers/iso13239_crc.h index 7de2cd8a0f6c..c71ec6befe49 100644 --- a/lib/nfc/helpers/iso13239_crc.h +++ b/lib/nfc/helpers/iso13239_crc.h @@ -3,7 +3,7 @@ #include #include -#include "bit_buffer.h" +#include #ifdef __cplusplus extern "C" { diff --git a/lib/nfc/helpers/iso14443_crc.h b/lib/nfc/helpers/iso14443_crc.h index c9ad5397fc3e..14a63841e71f 100644 --- a/lib/nfc/helpers/iso14443_crc.h +++ b/lib/nfc/helpers/iso14443_crc.h @@ -3,7 +3,7 @@ #include #include -#include "bit_buffer.h" +#include #ifdef __cplusplus extern "C" { diff --git a/lib/nfc/nfc.c b/lib/nfc/nfc.c index ea620fe26057..e8b5f502b021 100644 --- a/lib/nfc/nfc.c +++ b/lib/nfc/nfc.c @@ -12,7 +12,7 @@ typedef enum { NfcStateIdle, NfcStateFieldOn, - NfcStateListenStarted, + NfcStateListenerStarted, NfcStatePollerReady, NfcStatePollerReset, } NfcState; @@ -82,8 +82,8 @@ static int32_t nfc_worker_listener(void* context) { furi_assert(instance->callback); furi_assert(instance->config_state == NfcConfigurationStateDone); - f_hal_nfc_listen_start(); - instance->state = NfcStateListenStarted; + f_hal_nfc_listener_start(); + instance->state = NfcStateListenerStarted; f_hal_nfc_event_start(); @@ -93,15 +93,17 @@ static int32_t nfc_worker_listener(void* context) { NfcCommand command = NfcCommandContinue; while(true) { - FHalNfcEvent event = f_hal_nfc_wait_event(F_HAL_NFC_EVENT_WAIT_FOREVER); + FHalNfcEvent event = f_hal_nfc_listener_wait_event(F_HAL_NFC_EVENT_WAIT_FOREVER); if(event & FHalNfcEventAbortRequest) { nfc_event.type = NfcEventTypeUserAbort; instance->callback(nfc_event, instance->context); break; } if(event & FHalNfcEventFieldOn) { + // FURI_LOG_D(TAG, "Field ON"); nfc_event.type = NfcEventTypeFieldOn; instance->callback(nfc_event, instance->context); + f_hal_nfc_listener_rx_start(); } if(event & FHalNfcEventFieldOff) { nfc_event.type = NfcEventTypeFieldOff; @@ -115,7 +117,7 @@ static int32_t nfc_worker_listener(void* context) { } if(event & FHalNfcEventRxEnd) { nfc_event.type = NfcEventTypeRxEnd; - f_hal_nfc_poller_rx( + f_hal_nfc_listener_rx( instance->rx_buffer, sizeof(instance->rx_buffer), &instance->rx_bits); bit_buffer_copy_bits(event_data.buffer, instance->rx_buffer, instance->rx_bits); command = instance->callback(nfc_event, instance->context); @@ -147,7 +149,7 @@ bool nfc_worker_poller_start_handler(Nfc* instance) { f_hal_nfc_poller_field_on(); if(instance->guard_time_us) { f_hal_nfc_timer_block_tx_start_us(instance->guard_time_us); - FHalNfcEvent event = f_hal_nfc_wait_event(F_HAL_NFC_EVENT_WAIT_FOREVER); + FHalNfcEvent event = f_hal_nfc_poller_wait_event(F_HAL_NFC_EVENT_WAIT_FOREVER); furi_assert(event & FHalNfcEventTimerBlockTxExpired); } instance->poller_state = NfcPollerStateReady; @@ -231,7 +233,7 @@ Nfc* nfc_alloc() { void nfc_free(Nfc* instance) { furi_assert(instance); // TODO REWORK!!! - if(instance->state == NfcStateListenStarted) { + if(instance->state == NfcStateListenerStarted) { f_hal_nfc_abort(); furi_thread_join(instance->worker_thread); } @@ -249,24 +251,24 @@ void nfc_config(Nfc* instance, NfcMode mode) { f_hal_nfc_reset_mode(); instance->config_state = NfcConfigurationStateIdle; } else if(mode == NfcModeIso14443aPoller) { - f_hal_nfc_set_mode(FHalNfcModeIso14443aPoller, FHalNfcBitrate106); + f_hal_nfc_set_mode(FHalNfcModePoller, FHalNfcTechIso14443a); instance->config_state = NfcConfigurationStateDone; } else if(mode == NfcModeIso14443aListener) { f_hal_nfc_low_power_mode_stop(); - f_hal_nfc_set_mode(FHalNfcModeIso14443aListener, FHalNfcBitrate106); + f_hal_nfc_set_mode(FHalNfcModeListener, FHalNfcTechIso14443a); instance->config_state = NfcConfigurationStateDone; } else if(mode == NfcModeIso14443bPoller) { - f_hal_nfc_set_mode(FHalNfcModeIso14443bPoller, FHalNfcBitrate106); + f_hal_nfc_set_mode(FHalNfcModePoller, FHalNfcTechIso14443b); instance->config_state = NfcConfigurationStateDone; } else if(mode == NfcModeIso15693Poller) { - f_hal_nfc_set_mode(FHalNfcModeIso15693Poller, FHalNfcBitrate26p48); + f_hal_nfc_set_mode(FHalNfcModePoller, FHalNfcTechIso15693); instance->config_state = NfcConfigurationStateDone; } else if(mode == NfcModeIso15693Listener) { f_hal_nfc_low_power_mode_stop(); - f_hal_nfc_set_mode(FHalNfcModeIso15693Listener, FHalNfcBitrate26p48); + f_hal_nfc_set_mode(FHalNfcModeListener, FHalNfcTechIso15693); instance->config_state = NfcConfigurationStateDone; } else if(mode == NfcModeFelicaPoller) { - f_hal_nfc_set_mode(FHalNfcModeFelicaPoller, FHalNfcBitrate106); + f_hal_nfc_set_mode(FHalNfcModePoller, FHalNfcTechFelica); instance->config_state = NfcConfigurationStateDone; } } @@ -347,7 +349,7 @@ void nfc_stop(Nfc* instance) { NfcError nfc_listener_sleep(Nfc* instance) { furi_assert(instance); - furi_assert(instance->state == NfcStateListenStarted); + furi_assert(instance->state == NfcStateListenerStarted); f_hal_nfc_listener_sleep(); @@ -374,7 +376,7 @@ static NfcError nfc_poller_trx_state_machine(Nfc* instance, uint32_t fwt_fc) { NfcError error = NfcErrorNone; while(true) { - event = f_hal_nfc_wait_event(F_HAL_NFC_EVENT_WAIT_FOREVER); + event = f_hal_nfc_poller_wait_event(F_HAL_NFC_EVENT_WAIT_FOREVER); if(event & FHalNfcEventTimerBlockTxExpired) { if(instance->comm_state == NfcCommStateWaitBlockTxTimer) { instance->comm_state = NfcCommStateReadyTx; diff --git a/lib/nfc/nfc.h b/lib/nfc/nfc.h index b4a023db66b4..0c7e63e96e55 100644 --- a/lib/nfc/nfc.h +++ b/lib/nfc/nfc.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #ifdef __cplusplus extern "C" { diff --git a/lib/nfc/protocols/felica/felica.h b/lib/nfc/protocols/felica/felica.h index cacd489f013c..bd305b932601 100644 --- a/lib/nfc/protocols/felica/felica.h +++ b/lib/nfc/protocols/felica/felica.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #ifdef __cplusplus diff --git a/lib/nfc/protocols/felica/felica_poller_i.h b/lib/nfc/protocols/felica/felica_poller_i.h index 592bfb03bd5a..d458c9bb4628 100644 --- a/lib/nfc/protocols/felica/felica_poller_i.h +++ b/lib/nfc/protocols/felica/felica_poller_i.h @@ -2,7 +2,7 @@ #include "felica_poller.h" -#include +#include #ifdef __cplusplus extern "C" { diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a.h b/lib/nfc/protocols/iso14443_3a/iso14443_3a.h index a899472f160e..ca7e4d9c0fcc 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a.h +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #ifdef __cplusplus diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.h b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.h index 99a2372bc96e..08483eb0009c 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.h +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.h @@ -2,7 +2,7 @@ #include "iso14443_3a_poller.h" -#include +#include #ifdef __cplusplus extern "C" { diff --git a/lib/nfc/protocols/iso14443_3b/iso14443_3b.h b/lib/nfc/protocols/iso14443_3b/iso14443_3b.h index f222abd9db2e..b9b88788829a 100644 --- a/lib/nfc/protocols/iso14443_3b/iso14443_3b.h +++ b/lib/nfc/protocols/iso14443_3b/iso14443_3b.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #ifdef __cplusplus diff --git a/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller_i.h b/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller_i.h index 898378ac3604..ce42eb40ed35 100644 --- a/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller_i.h +++ b/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller_i.h @@ -2,8 +2,6 @@ #include "iso14443_3b_poller.h" -#include - #ifdef __cplusplus extern "C" { #endif diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3.c b/lib/nfc/protocols/iso15693_3/iso15693_3.c index 612743524609..a776e6f1a680 100644 --- a/lib/nfc/protocols/iso15693_3/iso15693_3.c +++ b/lib/nfc/protocols/iso15693_3/iso15693_3.c @@ -303,3 +303,17 @@ const Iso15693_3Data* iso15693_3_get_base_data(const Iso15693_3Data* data) { UNUSED(data); furi_crash("No base data"); } + +bool iso15693_3_is_block_locked(const Iso15693_3Data* data, uint8_t block_num) { + furi_assert(data); + furi_assert(block_num < data->system_info.block_count); + + return *(const uint8_t*)simple_array_cget(data->block_security, block_num); +} + +void iso15693_3_set_block_locked(Iso15693_3Data* data, uint8_t block_num, bool locked) { + furi_assert(data); + furi_assert(block_num < data->system_info.block_count); + + *(uint8_t*)simple_array_get(data->block_security, block_num) = locked ? 1 : 0; +} diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3.h b/lib/nfc/protocols/iso15693_3/iso15693_3.h index 5d11d881db0c..870a3c19cad5 100644 --- a/lib/nfc/protocols/iso15693_3/iso15693_3.h +++ b/lib/nfc/protocols/iso15693_3/iso15693_3.h @@ -12,6 +12,7 @@ extern "C" { #define ISO15693_3_GUARD_TIME_US (5000U) #define ISO15693_3_FDT_POLL_FC (4202U) +#define ISO15693_3_FDT_LISTEN_FC (4320U) #define ISO15693_3_POLL_POLL_MIN_US (1500U) /* true: modulating releases load, false: modulating adds load resistor to field coil */ @@ -41,13 +42,14 @@ extern "C" { #define ISO15693_3_REQ_FLAG_T4_SELECTED (1U << 4) #define ISO15693_3_REQ_FLAG_T4_ADDRESSED (1U << 5) -#define ISO15693_3_REQ_FLAG_T4_CUSTOM (1U << 6) +#define ISO15693_3_REQ_FLAG_T4_OPTION (1U << 6) #define ISO15693_3_REQ_FLAG_T5_AFI_PRESENT (1U << 4) #define ISO15693_3_REQ_FLAG_T5_N_SLOTS_16 (0U << 5) #define ISO15693_3_REQ_FLAG_T5_N_SLOTS_1 (1U << 5) -#define ISO15693_3_REQ_FLAG_T5_CUSTOM (1U << 6) +#define ISO15693_3_REQ_FLAG_T5_OPTION (1U << 6) +#define ISO15693_3_RESP_FLAG_NONE (0U) #define ISO15693_3_RESP_FLAG_ERROR (1U << 0) #define ISO15693_3_RESP_FLAG_EXTENSION (1U << 3) @@ -63,13 +65,16 @@ extern "C" { #define ISO15693_3_RESP_ERROR_CUSTOM_START (0xA0U) #define ISO15693_3_RESP_ERROR_CUSTOM_END (0xDFU) +#define ISO15693_3_CMD_MANDATORY_START (0x01U) #define ISO15693_3_CMD_INVENTORY (0x01U) #define ISO15693_3_CMD_STAY_QUIET (0x02U) +#define ISO15693_3_CMD_MANDATORY_RFU (0x03U) +#define ISO15693_3_CMD_OPTIONAL_START (0x20U) #define ISO15693_3_CMD_READ_BLOCK (0x20U) #define ISO15693_3_CMD_WRITE_BLOCK (0x21U) #define ISO15693_3_CMD_LOCK_BLOCK (0x22U) -#define ISO15693_3_CMD_READ_BLOCKS (0x23U) -#define ISO15693_3_CMD_WRITE_BLOCKS (0x24U) +#define ISO15693_3_CMD_READ_MULTI_BLOCKS (0x23U) +#define ISO15693_3_CMD_WRITE_MULTI_BLOCKS (0x24U) #define ISO15693_3_CMD_SELECT (0x25U) #define ISO15693_3_CMD_RESET_TO_READY (0x26U) #define ISO15693_3_CMD_WRITE_AFI (0x27U) @@ -78,6 +83,7 @@ extern "C" { #define ISO15693_3_CMD_LOCK_DSFID (0x2AU) #define ISO15693_3_CMD_GET_SYS_INFO (0x2BU) #define ISO15693_3_CMD_GET_BLOCKS_SECURITY (0x2CU) +#define ISO15693_3_CMD_OPTIONAL_RFU (0x2DU) #define ISO15693_3_SYSINFO_FLAG_DSFID (1U << 0) #define ISO15693_3_SYSINFO_FLAG_AFI (1U << 1) @@ -149,6 +155,14 @@ bool iso15693_3_set_uid(Iso15693_3Data* data, const uint8_t* uid, size_t uid_len const Iso15693_3Data* iso15693_3_get_base_data(const Iso15693_3Data* data); +// Getters and tests + +bool iso15693_3_is_block_locked(const Iso15693_3Data* data, uint8_t block_num); + +// Setters + +void iso15693_3_set_block_locked(Iso15693_3Data* data, uint8_t block_num, bool locked); + extern const NfcDeviceBase nfc_device_iso15693_3; #ifdef __cplusplus diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3_i.c b/lib/nfc/protocols/iso15693_3/iso15693_3_i.c index 1f3b1352fea4..c75d19261584 100644 --- a/lib/nfc/protocols/iso15693_3/iso15693_3_i.c +++ b/lib/nfc/protocols/iso15693_3/iso15693_3_i.c @@ -210,3 +210,47 @@ Iso15693_3Error iso15693_3_get_block_security_response_parse( return ret; } + +void iso15693_3_append_uid(const Iso15693_3Data* data, BitBuffer* buf) { + for(size_t i = 0; i < ISO15693_3_UID_SIZE; ++i) { + // Reverse the UID + bit_buffer_append_byte(buf, data->uid[ISO15693_3_UID_SIZE - i - 1]); + } +} + +void iso15693_3_append_block(const Iso15693_3Data* data, uint8_t block_num, BitBuffer* buf) { + furi_assert(block_num < data->system_info.block_count); + + const uint32_t block_offset = block_num * data->system_info.block_size; + const uint8_t* block_data = simple_array_cget(data->block_data, block_offset); + + bit_buffer_append_bytes(buf, block_data, data->system_info.block_size); +} + +void iso15693_3_set_block_data( + Iso15693_3Data* data, + uint8_t block_num, + const uint8_t* block_data, + size_t block_data_size) { + furi_assert(block_num < data->system_info.block_count); + furi_assert(block_data_size == data->system_info.block_size); + + const uint32_t block_offset = block_num * data->system_info.block_size; + uint8_t* block = simple_array_get(data->block_data, block_offset); + + memcpy(block, block_data, block_data_size); +} + +void iso15693_3_append_block_security( + const Iso15693_3Data* data, + uint8_t block_num, + BitBuffer* buf) { + bit_buffer_append_byte(buf, *(uint8_t*)simple_array_cget(data->block_security, block_num)); +} + +bool iso15693_3_is_equal_uid(const Iso15693_3Data* data, const uint8_t* uid) { + for(size_t i = 0; i < ISO15693_3_UID_SIZE; ++i) { + if(data->uid[i] != uid[ISO15693_3_UID_SIZE - i - 1]) return false; + } + return true; +} diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3_i.h b/lib/nfc/protocols/iso15693_3/iso15693_3_i.h index 4cab9199a807..01280e180822 100644 --- a/lib/nfc/protocols/iso15693_3/iso15693_3_i.h +++ b/lib/nfc/protocols/iso15693_3/iso15693_3_i.h @@ -2,7 +2,7 @@ #include "iso15693_3.h" -#include +#include #ifdef __cplusplus extern "C" { @@ -33,6 +33,24 @@ Iso15693_3Error iso15693_3_get_block_security_response_parse( uint16_t block_count, const BitBuffer* buf); +void iso15693_3_append_uid(const Iso15693_3Data* data, BitBuffer* buf); + +void iso15693_3_append_block(const Iso15693_3Data* data, uint8_t block_num, BitBuffer* buf); + +void iso15693_3_set_block_data( + Iso15693_3Data* data, + uint8_t block_num, + const uint8_t* block_data, + size_t block_data_size); + +void iso15693_3_append_block_security( + const Iso15693_3Data* data, + uint8_t block_num, + BitBuffer* buf); + +// NOTE: the uid parameter has reversed byte order with respect to data +bool iso15693_3_is_equal_uid(const Iso15693_3Data* data, const uint8_t* uid); + #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3_listener.c b/lib/nfc/protocols/iso15693_3/iso15693_3_listener.c index e69de29bb2d1..c47734310b14 100644 --- a/lib/nfc/protocols/iso15693_3/iso15693_3_listener.c +++ b/lib/nfc/protocols/iso15693_3/iso15693_3_listener.c @@ -0,0 +1,111 @@ +#include "iso15693_3_listener_i.h" + +#include + +#include +#include +#include + +#define TAG "Iso15693_3Listener" + +#define ISO15693_3_LISTENER_BUFFER_SIZE (64U) + +Iso15693_3Listener* iso15693_3_listener_alloc(Nfc* nfc, const Iso15693_3Data* data) { + furi_assert(nfc); + + Iso15693_3Listener* instance = malloc(sizeof(Iso15693_3Listener)); + instance->nfc = nfc; + instance->data = iso15693_3_alloc(); + iso15693_3_copy(instance->data, data); + + instance->tx_buffer = bit_buffer_alloc(ISO15693_3_LISTENER_BUFFER_SIZE); + + instance->iso15693_3_event.data = &instance->iso15693_3_event_data; + instance->generic_event.protocol = NfcProtocolIso15693_3; + instance->generic_event.instance = instance; + instance->generic_event.data = &instance->iso15693_3_event; + + nfc_set_fdt_listen_fc(instance->nfc, ISO15693_3_FDT_LISTEN_FC); + nfc_config(instance->nfc, NfcModeIso15693Listener); + + return instance; +} + +void iso15693_3_listener_free(Iso15693_3Listener* instance) { + furi_assert(instance); + + bit_buffer_free(instance->tx_buffer); + iso15693_3_free(instance->data); + + free(instance); +} + +void iso15693_3_listener_set_callback( + Iso15693_3Listener* instance, + NfcGenericCallback callback, + void* context) { + furi_assert(instance); + + instance->callback = callback; + instance->context = context; +} + +const Iso15693_3Data* iso15693_3_listener_get_data(Iso15693_3Listener* instance) { + furi_assert(instance); + furi_assert(instance->data); + + return instance->data; +} + +NfcCommand iso15693_3_listener_run(NfcGenericEvent event, void* context) { + furi_assert(context); + furi_assert(event.protocol == NfcProtocolInvalid); + furi_assert(event.data); + + Iso15693_3Listener* instance = context; + NfcEvent* nfc_event = event.data; + NfcCommand command = NfcCommandContinue; + + if(nfc_event->type == NfcEventTypeFieldOn) { + iso15693_3_listener_ready(instance); + } else if(nfc_event->type == NfcEventTypeFieldOff) { + if(instance->callback) { + instance->iso15693_3_event.type = Iso15693_3ListenerEventTypeFieldOff; + command = instance->callback(instance->generic_event, instance->context); + } + iso15693_3_listener_sleep(instance); + } else if(nfc_event->type == NfcEventTypeRxEnd) { + BitBuffer* request_buf = nfc_event->data.buffer; + if(iso13239_crc_check(Iso13239CrcTypeDefault, request_buf)) { + iso13239_crc_trim(request_buf); + const Iso15693_3Error error = + iso15693_3_listener_process_request(instance, request_buf); + if(error == Iso15693_3ErrorNotSupported) { + instance->iso15693_3_event.type = Iso15693_3ListenerEventTypeCustomCommand; + command = instance->callback(instance->generic_event, instance->context); + } + } else if(bit_buffer_get_size(request_buf) == 0) { + // Special case: Single EOF + if(instance->session_state.wait_for_eof) { + iso15693_3_listener_send_frame(instance, instance->tx_buffer); + instance->session_state.wait_for_eof = false; + } else if(instance->callback) { + instance->iso15693_3_event.type = Iso15693_3ListenerEventTypeSingleEof; + command = instance->callback(instance->generic_event, instance->context); + } + } else { + FURI_LOG_D( + TAG, "Wrong CRC, buffer size: %zu", bit_buffer_get_size(nfc_event->data.buffer)); + } + } + + return command; +} + +const NfcListenerBase nfc_listener_iso15693_3 = { + .alloc = (NfcListenerAlloc)iso15693_3_listener_alloc, + .free = (NfcListenerFree)iso15693_3_listener_free, + .set_callback = (NfcListenerSetCallback)iso15693_3_listener_set_callback, + .get_data = (NfcListenerGetData)iso15693_3_listener_get_data, + .run = (NfcListenerRun)iso15693_3_listener_run, +}; diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3_listener.h b/lib/nfc/protocols/iso15693_3/iso15693_3_listener.h index cd74574a9381..c69d18db4e7f 100644 --- a/lib/nfc/protocols/iso15693_3/iso15693_3_listener.h +++ b/lib/nfc/protocols/iso15693_3/iso15693_3_listener.h @@ -1,9 +1,30 @@ #pragma once +#include + +#include "iso15693_3.h" + #ifdef __cplusplus extern "C" { #endif +typedef struct Iso15693_3Listener Iso15693_3Listener; + +typedef enum { + Iso15693_3ListenerEventTypeFieldOff, + Iso15693_3ListenerEventTypeCustomCommand, + Iso15693_3ListenerEventTypeSingleEof, +} Iso15693_3ListenerEventType; + +typedef struct { + BitBuffer* buffer; +} Iso15693_3ListenerEventData; + +typedef struct { + Iso15693_3ListenerEventType type; + Iso15693_3ListenerEventData* data; +} Iso15693_3ListenerEvent; + #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3_listener_defs.h b/lib/nfc/protocols/iso15693_3/iso15693_3_listener_defs.h index cd74574a9381..0543b6f9299a 100644 --- a/lib/nfc/protocols/iso15693_3/iso15693_3_listener_defs.h +++ b/lib/nfc/protocols/iso15693_3/iso15693_3_listener_defs.h @@ -1,9 +1,13 @@ #pragma once +#include + #ifdef __cplusplus extern "C" { #endif +extern const NfcListenerBase nfc_listener_iso15693_3; + #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3_listener_i.c b/lib/nfc/protocols/iso15693_3/iso15693_3_listener_i.c index e69de29bb2d1..ad7e33d00c90 100644 --- a/lib/nfc/protocols/iso15693_3/iso15693_3_listener_i.c +++ b/lib/nfc/protocols/iso15693_3/iso15693_3_listener_i.c @@ -0,0 +1,726 @@ +#include "iso15693_3_listener_i.h" + +#include + +#define TAG "Iso15693_3Listener" + +typedef Iso15693_3Error (*Iso15693_3RequestHandler)( + Iso15693_3Listener* instance, + const uint8_t* data, + size_t data_size, + uint8_t flags); + +static Iso15693_3Error iso15693_3_listener_inventory_handler( + Iso15693_3Listener* instance, + const uint8_t* data, + size_t data_size, + uint8_t flags) { + Iso15693_3Error error = Iso15693_3ErrorNone; + + do { + const bool afi_flag = flags & ISO15693_3_REQ_FLAG_T5_AFI_PRESENT; + const size_t data_size_min = sizeof(uint8_t) * (afi_flag ? 2 : 1); + + if(data_size < data_size_min) { + error = Iso15693_3ErrorFormat; + break; + } + + if(afi_flag) { + const uint8_t afi = *data++; + // When AFI flag is set, ignore non-matching requests + if(afi != instance->data->system_info.afi) break; + } + + const uint8_t mask_len = *data++; + const size_t data_size_required = data_size_min + mask_len; + + if(data_size != data_size_required) { + error = Iso15693_3ErrorFormat; + break; + } + + if(mask_len != 0) { + // TODO: Take mask_len and mask_value into account (if present) + } + + bit_buffer_append_byte(instance->tx_buffer, instance->data->system_info.dsfid); // DSFID + iso15693_3_append_uid(instance->data, instance->tx_buffer); // UID + } while(false); + + instance->session_state.no_reply = (error != Iso15693_3ErrorNone); + return error; +} + +static Iso15693_3Error iso15693_3_listener_stay_quiet_handler( + Iso15693_3Listener* instance, + const uint8_t* data, + size_t data_size, + uint8_t flags) { + UNUSED(data); + UNUSED(data_size); + UNUSED(flags); + + instance->state = Iso15693_3ListenerStateQuiet; + instance->session_state.no_reply = true; + return Iso15693_3ErrorNone; +} + +static Iso15693_3Error iso15693_3_listener_read_block_handler( + Iso15693_3Listener* instance, + const uint8_t* data, + size_t data_size, + uint8_t flags) { + Iso15693_3Error error = Iso15693_3ErrorNone; + + do { + typedef struct { + uint8_t block_num; + } Iso15693_3ReadBlockRequestLayout; + + const Iso15693_3ReadBlockRequestLayout* request = + (const Iso15693_3ReadBlockRequestLayout*)data; + + if(data_size != sizeof(Iso15693_3ReadBlockRequestLayout)) { + error = Iso15693_3ErrorFormat; + break; + } + + const uint32_t block_index = request->block_num; + const uint32_t block_count_max = instance->data->system_info.block_count; + + if(block_index >= block_count_max) { + error = Iso15693_3ErrorInternal; + break; + } + + if(flags & ISO15693_3_REQ_FLAG_T4_OPTION) { + iso15693_3_append_block_security( + instance->data, block_index, instance->tx_buffer); // Block security (optional) + } + + iso15693_3_append_block(instance->data, block_index, instance->tx_buffer); // Block data + } while(false); + + return error; +} + +static Iso15693_3Error iso15693_3_listener_write_block_handler( + Iso15693_3Listener* instance, + const uint8_t* data, + size_t data_size, + uint8_t flags) { + Iso15693_3Error error = Iso15693_3ErrorNone; + + do { + typedef struct { + uint8_t block_num; + uint8_t block_data[]; + } Iso15693_3WriteBlockRequestLayout; + + const Iso15693_3WriteBlockRequestLayout* request = + (const Iso15693_3WriteBlockRequestLayout*)data; + + instance->session_state.wait_for_eof = flags & ISO15693_3_REQ_FLAG_T4_OPTION; + + if(data_size <= sizeof(Iso15693_3WriteBlockRequestLayout)) { + error = Iso15693_3ErrorFormat; + break; + } + + const uint32_t block_index = request->block_num; + const uint32_t block_count_max = instance->data->system_info.block_count; + const uint32_t block_size_max = instance->data->system_info.block_size; + const size_t block_size_received = data_size - sizeof(Iso15693_3WriteBlockRequestLayout); + + if(block_index >= block_count_max) { + error = Iso15693_3ErrorInternal; + break; + } else if(block_size_received != block_size_max) { + error = Iso15693_3ErrorInternal; + break; + } else if(iso15693_3_is_block_locked(instance->data, block_index)) { + error = Iso15693_3ErrorInternal; + break; + } + + iso15693_3_set_block_data( + instance->data, block_index, request->block_data, block_size_received); + } while(false); + + return error; +} + +static Iso15693_3Error iso15693_3_listener_lock_block_handler( + Iso15693_3Listener* instance, + const uint8_t* data, + size_t data_size, + uint8_t flags) { + Iso15693_3Error error = Iso15693_3ErrorNone; + + do { + typedef struct { + uint8_t block_num; + } Iso15693_3LockBlockRequestLayout; + + const Iso15693_3LockBlockRequestLayout* request = + (const Iso15693_3LockBlockRequestLayout*)data; + + instance->session_state.wait_for_eof = flags & ISO15693_3_REQ_FLAG_T4_OPTION; + + if(data_size != sizeof(Iso15693_3LockBlockRequestLayout)) { + error = Iso15693_3ErrorFormat; + break; + } + + const uint32_t block_index = request->block_num; + const uint32_t block_count_max = instance->data->system_info.block_count; + + if(block_index >= block_count_max) { + error = Iso15693_3ErrorInternal; + break; + } else if(iso15693_3_is_block_locked(instance->data, block_index)) { + error = Iso15693_3ErrorInternal; + break; + } + + iso15693_3_set_block_locked(instance->data, block_index, true); + } while(false); + + return error; +} + +static Iso15693_3Error iso15693_3_listener_read_multi_blocks_handler( + Iso15693_3Listener* instance, + const uint8_t* data, + size_t data_size, + uint8_t flags) { + Iso15693_3Error error = Iso15693_3ErrorNone; + + do { + typedef struct { + uint8_t first_block_num; + uint8_t block_count; + } Iso15693_3ReadMultiBlocksRequestLayout; + + const Iso15693_3ReadMultiBlocksRequestLayout* request = + (const Iso15693_3ReadMultiBlocksRequestLayout*)data; + + if(data_size != sizeof(Iso15693_3ReadMultiBlocksRequestLayout)) { + error = Iso15693_3ErrorFormat; + break; + } + + const uint32_t block_index_start = request->first_block_num; + const uint32_t block_index_end = block_index_start + request->block_count; + + const uint32_t block_count = request->block_count + 1; + const uint32_t block_count_max = instance->data->system_info.block_count; + const uint32_t block_count_available = block_count_max - block_index_start; + + if(block_count > block_count_available) { + error = Iso15693_3ErrorInternal; + break; + } + + for(uint32_t i = block_index_start; i <= block_index_end; ++i) { + if(flags & ISO15693_3_REQ_FLAG_T4_OPTION) { + iso15693_3_append_block_security( + instance->data, i, instance->tx_buffer); // Block security (optional) + } + iso15693_3_append_block(instance->data, i, instance->tx_buffer); // Block data + } + } while(false); + + return error; +} + +static Iso15693_3Error iso15693_3_listener_write_multi_blocks_handler( + Iso15693_3Listener* instance, + const uint8_t* data, + size_t data_size, + uint8_t flags) { + Iso15693_3Error error = Iso15693_3ErrorNone; + + do { + typedef struct { + uint8_t first_block_num; + uint8_t block_count; + uint8_t block_data[]; + } Iso15693_3WriteMultiBlocksRequestLayout; + + const Iso15693_3WriteMultiBlocksRequestLayout* request = + (const Iso15693_3WriteMultiBlocksRequestLayout*)data; + + instance->session_state.wait_for_eof = flags & ISO15693_3_REQ_FLAG_T4_OPTION; + + if(data_size <= sizeof(Iso15693_3WriteMultiBlocksRequestLayout)) { + error = Iso15693_3ErrorFormat; + break; + } + + const uint32_t block_index_start = request->first_block_num; + const uint32_t block_index_end = block_index_start + request->block_count; + + const uint32_t block_count = request->block_count + 1; + const uint32_t block_count_max = instance->data->system_info.block_count; + const uint32_t block_count_available = block_count_max - block_index_start; + + const size_t block_data_size = data_size - sizeof(Iso15693_3WriteMultiBlocksRequestLayout); + const size_t block_size = block_data_size / block_count; + const size_t block_size_max = instance->data->system_info.block_size; + + if(block_count > block_count_available) { + error = Iso15693_3ErrorInternal; + break; + } else if(block_size != block_size_max) { + error = Iso15693_3ErrorInternal; + break; + } + + for(uint32_t i = block_index_start; i <= block_index_end; ++i) { + if(iso15693_3_is_block_locked(instance->data, i)) { + error = Iso15693_3ErrorInternal; + break; + } + } + + if(error != Iso15693_3ErrorNone) break; + + for(uint32_t i = block_index_start; i < block_count + request->first_block_num; ++i) { + const uint8_t* block_data = &request->block_data[block_size * i]; + iso15693_3_set_block_data(instance->data, i, block_data, block_size); + } + } while(false); + + return error; +} + +static Iso15693_3Error iso15693_3_listener_select_handler( + Iso15693_3Listener* instance, + const uint8_t* data, + size_t data_size, + uint8_t flags) { + UNUSED(data); + UNUSED(data_size); + + Iso15693_3Error error = Iso15693_3ErrorNone; + + do { + if(!(flags & ISO15693_3_REQ_FLAG_T4_ADDRESSED)) { + instance->session_state.no_reply = true; + error = Iso15693_3ErrorUnknown; + break; + } + + instance->state = Iso15693_3ListenerStateSelected; + } while(false); + + return error; +} + +static Iso15693_3Error iso15693_3_listener_reset_to_ready_handler( + Iso15693_3Listener* instance, + const uint8_t* data, + size_t data_size, + uint8_t flags) { + UNUSED(data); + UNUSED(data_size); + UNUSED(flags); + + instance->state = Iso15693_3ListenerStateReady; + return Iso15693_3ErrorNone; +} + +static Iso15693_3Error iso15693_3_listener_write_afi_handler( + Iso15693_3Listener* instance, + const uint8_t* data, + size_t data_size, + uint8_t flags) { + Iso15693_3Error error = Iso15693_3ErrorNone; + + do { + typedef struct { + uint8_t afi; + } Iso15693_3WriteAfiRequestLayout; + + const Iso15693_3WriteAfiRequestLayout* request = + (const Iso15693_3WriteAfiRequestLayout*)data; + + instance->session_state.wait_for_eof = flags & ISO15693_3_REQ_FLAG_T4_OPTION; + + if(data_size <= sizeof(Iso15693_3WriteAfiRequestLayout)) { + error = Iso15693_3ErrorFormat; + break; + } else if(instance->data->system_info.flags & ISO15693_3_SYSINFO_LOCK_AFI) { + error = Iso15693_3ErrorInternal; + break; + } + + instance->data->system_info.afi = request->afi; + } while(false); + + return error; +} + +static Iso15693_3Error iso15693_3_listener_lock_afi_handler( + Iso15693_3Listener* instance, + const uint8_t* data, + size_t data_size, + uint8_t flags) { + UNUSED(data); + UNUSED(data_size); + + Iso15693_3Error error = Iso15693_3ErrorNone; + + do { + instance->session_state.wait_for_eof = flags & ISO15693_3_REQ_FLAG_T4_OPTION; + + if(instance->data->system_info.flags & ISO15693_3_SYSINFO_LOCK_AFI) { + error = Iso15693_3ErrorInternal; + break; + } + + instance->data->system_info.flags |= ISO15693_3_SYSINFO_LOCK_AFI; + } while(false); + + return error; +} + +static Iso15693_3Error iso15693_3_listener_write_dsfid_handler( + Iso15693_3Listener* instance, + const uint8_t* data, + size_t data_size, + uint8_t flags) { + Iso15693_3Error error = Iso15693_3ErrorNone; + + do { + typedef struct { + uint8_t dsfid; + } Iso15693_3WriteDsfidRequestLayout; + + const Iso15693_3WriteDsfidRequestLayout* request = + (const Iso15693_3WriteDsfidRequestLayout*)data; + + instance->session_state.wait_for_eof = flags & ISO15693_3_REQ_FLAG_T4_OPTION; + + if(data_size <= sizeof(Iso15693_3WriteDsfidRequestLayout)) { + error = Iso15693_3ErrorFormat; + break; + } else if(instance->data->system_info.flags & ISO15693_3_SYSINFO_LOCK_DSFID) { + error = Iso15693_3ErrorInternal; + break; + } + + instance->data->system_info.dsfid = request->dsfid; + } while(false); + + return error; +} + +static Iso15693_3Error iso15693_3_listener_lock_dsfid_handler( + Iso15693_3Listener* instance, + const uint8_t* data, + size_t data_size, + uint8_t flags) { + UNUSED(data); + UNUSED(data_size); + + Iso15693_3Error error = Iso15693_3ErrorNone; + + do { + instance->session_state.wait_for_eof = flags & ISO15693_3_REQ_FLAG_T4_OPTION; + + if(instance->data->system_info.flags & ISO15693_3_SYSINFO_LOCK_DSFID) { + error = Iso15693_3ErrorInternal; + break; + } + + instance->data->system_info.flags |= ISO15693_3_SYSINFO_LOCK_DSFID; + } while(false); + + return error; +} + +static Iso15693_3Error iso15693_3_listener_get_system_info_handler( + Iso15693_3Listener* instance, + const uint8_t* data, + size_t data_size, + uint8_t flags) { + UNUSED(data); + UNUSED(data_size); + UNUSED(flags); + + Iso15693_3Error error = Iso15693_3ErrorNone; + + do { + const uint8_t system_flags = instance->data->system_info.flags; + bit_buffer_append_byte(instance->tx_buffer, system_flags); // System info flags + + iso15693_3_append_uid(instance->data, instance->tx_buffer); // UID + + if(system_flags & ISO15693_3_SYSINFO_FLAG_DSFID) { + bit_buffer_append_byte(instance->tx_buffer, instance->data->system_info.dsfid); + } + if(system_flags & ISO15693_3_SYSINFO_FLAG_AFI) { + bit_buffer_append_byte(instance->tx_buffer, instance->data->system_info.afi); + } + if(system_flags & ISO15693_3_SYSINFO_FLAG_MEMORY) { + const uint8_t memory_info[2] = { + instance->data->system_info.block_count - 1, + instance->data->system_info.block_size - 1, + }; + bit_buffer_append_bytes(instance->tx_buffer, memory_info, COUNT_OF(memory_info)); + } + if(system_flags & ISO15693_3_SYSINFO_FLAG_IC_REF) { + bit_buffer_append_byte(instance->tx_buffer, instance->data->system_info.ic_ref); + } + + } while(false); + + return error; +} + +static Iso15693_3Error iso15693_3_listener_get_multi_blocks_security_handler( + Iso15693_3Listener* instance, + const uint8_t* data, + size_t data_size, + uint8_t flags) { + UNUSED(flags); + + Iso15693_3Error error = Iso15693_3ErrorNone; + + do { + typedef struct { + uint8_t first_block_num; + uint8_t block_count; + } Iso15693_3GetMultiBlocksSecurityRequestLayout; + + const Iso15693_3GetMultiBlocksSecurityRequestLayout* request = + (const Iso15693_3GetMultiBlocksSecurityRequestLayout*)data; + + if(data_size < sizeof(Iso15693_3GetMultiBlocksSecurityRequestLayout)) { + error = Iso15693_3ErrorFormat; + break; + } + + const uint32_t block_index_start = request->first_block_num; + const uint32_t block_index_end = block_index_start + request->block_count; + + const uint32_t block_count_max = instance->data->system_info.block_count; + + if(block_index_end >= block_count_max) { + error = Iso15693_3ErrorInternal; + break; + } + + for(uint32_t i = block_index_start; i <= block_index_end; ++i) { + bit_buffer_append_byte( + instance->tx_buffer, iso15693_3_is_block_locked(instance->data, i) ? 1 : 0); + } + } while(false); + + return error; +} + +static const Iso15693_3RequestHandler iso15693_3_request_handlers[] = { + // Mandatory commands + iso15693_3_listener_inventory_handler, + iso15693_3_listener_stay_quiet_handler, + // Optional commands + iso15693_3_listener_read_block_handler, + iso15693_3_listener_write_block_handler, + iso15693_3_listener_lock_block_handler, + iso15693_3_listener_read_multi_blocks_handler, + iso15693_3_listener_write_multi_blocks_handler, + iso15693_3_listener_select_handler, + iso15693_3_listener_reset_to_ready_handler, + iso15693_3_listener_write_afi_handler, + iso15693_3_listener_lock_afi_handler, + iso15693_3_listener_write_dsfid_handler, + iso15693_3_listener_lock_dsfid_handler, + iso15693_3_listener_get_system_info_handler, + iso15693_3_listener_get_multi_blocks_security_handler, +}; + +static inline Iso15693_3Error iso15693_3_listener_handle_request( + Iso15693_3Listener* instance, + const uint8_t* data, + size_t data_size, + uint8_t command, + uint8_t flags) { + Iso15693_3Error error = Iso15693_3ErrorNone; + + do { + uint8_t command_index; + + if(command < ISO15693_3_CMD_MANDATORY_RFU) { + command_index = command - ISO15693_3_CMD_MANDATORY_START; + } else if(command >= ISO15693_3_CMD_OPTIONAL_START && command < ISO15693_3_CMD_OPTIONAL_RFU) { + command_index = command - ISO15693_3_CMD_MANDATORY_START - + ISO15693_3_CMD_OPTIONAL_START + ISO15693_3_CMD_MANDATORY_RFU; + } else { + error = Iso15693_3ErrorNotSupported; + break; + } + + bit_buffer_reset(instance->tx_buffer); + bit_buffer_append_byte(instance->tx_buffer, ISO15693_3_RESP_FLAG_NONE); + + error = iso15693_3_request_handlers[command_index](instance, data, data_size, flags); + + Iso15693_3ListenerSessionState* session_state = &instance->session_state; + + // Several commands may not require an answer + if(session_state->no_reply) { + session_state->no_reply = false; + error = Iso15693_3ErrorNone; + break; + } + + // TODO: Move it to a separate function + if(error != Iso15693_3ErrorNone) { + bit_buffer_reset(instance->tx_buffer); + bit_buffer_append_byte(instance->tx_buffer, ISO15693_3_RESP_FLAG_ERROR); + bit_buffer_append_byte(instance->tx_buffer, ISO15693_3_RESP_ERROR_UNKNOWN); + } + + if(!session_state->wait_for_eof) { + error = iso15693_3_listener_send_frame(instance, instance->tx_buffer); + } + + } while(false); + + return error; +} + +Iso15693_3Error iso15693_3_listener_ready(Iso15693_3Listener* instance) { + furi_assert(instance); + instance->state = Iso15693_3ListenerStateReady; + return Iso15693_3ErrorNone; +} + +Iso15693_3Error iso15693_3_listener_sleep(Iso15693_3Listener* instance) { + furi_assert(instance); + instance->state = Iso15693_3ListenerStateIdle; + return Iso15693_3ErrorNone; +} + +static Iso15693_3Error iso15693_3_listener_process_nfc_error(NfcError error) { + Iso15693_3Error ret = Iso15693_3ErrorNone; + + if(error == NfcErrorNone) { + ret = Iso15693_3ErrorNone; + } else if(error == NfcErrorTimeout) { + ret = Iso15693_3ErrorTimeout; + } else { + ret = Iso15693_3ErrorFieldOff; + } + + return ret; +} + +Iso15693_3Error + iso15693_3_listener_send_frame(Iso15693_3Listener* instance, const BitBuffer* tx_buffer) { + furi_assert(instance); + furi_assert(tx_buffer); + + bit_buffer_copy(instance->tx_buffer, tx_buffer); + iso13239_crc_append(Iso13239CrcTypeDefault, instance->tx_buffer); + + NfcError error = nfc_listener_tx(instance->nfc, instance->tx_buffer); + return iso15693_3_listener_process_nfc_error(error); +} + +Iso15693_3Error + iso15693_3_listener_process_request(Iso15693_3Listener* instance, const BitBuffer* rx_buffer) { + Iso15693_3Error error = Iso15693_3ErrorNone; + + do { + typedef struct { + uint8_t flags; + uint8_t command; + uint8_t data[]; + } Iso15693_3RequestLayout; + + const size_t buf_size = bit_buffer_get_size_bytes(rx_buffer); + const size_t buf_size_min = sizeof(Iso15693_3RequestLayout); + + if(buf_size < buf_size_min) { + error = Iso15693_3ErrorFormat; + break; + } + + const Iso15693_3RequestLayout* request = + (const Iso15693_3RequestLayout*)bit_buffer_get_data(rx_buffer); + + const bool inventory_flag = request->flags & ISO15693_3_REQ_FLAG_INVENTORY_T5; + + if(!inventory_flag) { + const bool selected_mode = request->flags & ISO15693_3_REQ_FLAG_T4_SELECTED; + const bool addressed_mode = request->flags & ISO15693_3_REQ_FLAG_T4_ADDRESSED; + + if(selected_mode && addressed_mode) { + // A request mode can be either addressed or selected, but not both + break; + } else if(instance->state == Iso15693_3ListenerStateQuiet) { + // If the card is quiet, ignore non-addressed commands + if(!addressed_mode) break; + } else if(instance->state != Iso15693_3ListenerStateSelected) { + // If the card is not selected, ignore selected commands + if(selected_mode) break; + } + + const uint8_t* data; + size_t data_size; + + if(addressed_mode) { + // In addressed mode, UID must be included in each command + const size_t buf_size_min_addr = buf_size_min + ISO15693_3_UID_SIZE; + + if(buf_size < buf_size_min_addr) { + error = Iso15693_3ErrorFormat; + break; + } else if(!iso15693_3_is_equal_uid(instance->data, request->data)) { + // In addressed mode, ignore all commands with non-matching UID + if(instance->state == Iso15693_3ListenerStateSelected && + request->command == ISO15693_3_CMD_SELECT) { + // Special case, reset to ready on reception of a + // SELECT command with non-matching UID + // TODO: Find a neater way to do this? + instance->state = Iso15693_3ListenerStateReady; + } + break; + } + + data = &request->data[ISO15693_3_UID_SIZE]; + data_size = buf_size - buf_size_min_addr; + + } else { + data = request->data; + data_size = buf_size - buf_size_min; + } + + error = iso15693_3_listener_handle_request( + instance, data, data_size, request->command, request->flags); + + } else { + // If the card is quiet, ignore INVENTORY commands + if(instance->state == Iso15693_3ListenerStateQuiet) { + break; + } + + // Only the INVENTORY command is allowed with this flag set + if(request->command != ISO15693_3_CMD_INVENTORY) { + error = Iso15693_3ErrorUnknown; + break; + } + + error = iso15693_3_listener_handle_request( + instance, request->data, buf_size - buf_size_min, request->command, request->flags); + } + + } while(false); + + return error; +} diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3_listener_i.h b/lib/nfc/protocols/iso15693_3/iso15693_3_listener_i.h index cd74574a9381..e6ecdfb35a1c 100644 --- a/lib/nfc/protocols/iso15693_3/iso15693_3_listener_i.h +++ b/lib/nfc/protocols/iso15693_3/iso15693_3_listener_i.h @@ -1,9 +1,52 @@ #pragma once +#include + +#include "iso15693_3_listener.h" + +#include "iso15693_3_i.h" + #ifdef __cplusplus extern "C" { #endif +typedef enum { + Iso15693_3ListenerStateIdle, + Iso15693_3ListenerStateReady, + Iso15693_3ListenerStateSelected, + Iso15693_3ListenerStateQuiet, +} Iso15693_3ListenerState; + +typedef struct { + bool wait_for_eof; + bool no_reply; +} Iso15693_3ListenerSessionState; + +struct Iso15693_3Listener { + Nfc* nfc; + Iso15693_3Data* data; + Iso15693_3ListenerState state; + Iso15693_3ListenerSessionState session_state; + + BitBuffer* tx_buffer; + + NfcGenericEvent generic_event; + Iso15693_3ListenerEvent iso15693_3_event; + Iso15693_3ListenerEventData iso15693_3_event_data; + NfcGenericCallback callback; + void* context; +}; + +Iso15693_3Error iso15693_3_listener_ready(Iso15693_3Listener* instance); + +Iso15693_3Error iso15693_3_listener_sleep(Iso15693_3Listener* instance); + +Iso15693_3Error + iso15693_3_listener_send_frame(Iso15693_3Listener* instance, const BitBuffer* tx_buffer); + +Iso15693_3Error + iso15693_3_listener_process_request(Iso15693_3Listener* instance, const BitBuffer* rx_buffer); + #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3_poller.c b/lib/nfc/protocols/iso15693_3/iso15693_3_poller.c index ce4b084c72da..ffe27bc78459 100644 --- a/lib/nfc/protocols/iso15693_3/iso15693_3_poller.c +++ b/lib/nfc/protocols/iso15693_3/iso15693_3_poller.c @@ -20,10 +20,6 @@ static Iso15693_3Poller* iso15693_3_poller_alloc(Nfc* nfc) { instance->nfc = nfc; instance->tx_buffer = bit_buffer_alloc(ISO15693_3_POLLER_MAX_BUFFER_SIZE); instance->rx_buffer = bit_buffer_alloc(ISO15693_3_POLLER_MAX_BUFFER_SIZE); - // 4 bits per data bit on transmit - instance->tx_frame_buffer = bit_buffer_alloc(ISO15693_3_POLLER_MAX_BUFFER_SIZE * 4); - // 2 bits per data bit on receive - instance->rx_frame_buffer = bit_buffer_alloc(ISO15693_3_POLLER_MAX_BUFFER_SIZE * 2); nfc_config(instance->nfc, NfcModeIso15693Poller); nfc_set_guard_time_us(instance->nfc, ISO15693_3_GUARD_TIME_US); @@ -44,14 +40,10 @@ static void iso15693_3_poller_free(Iso15693_3Poller* instance) { furi_assert(instance->tx_buffer); furi_assert(instance->rx_buffer); - furi_assert(instance->tx_frame_buffer); - furi_assert(instance->rx_frame_buffer); furi_assert(instance->data); bit_buffer_free(instance->tx_buffer); bit_buffer_free(instance->rx_buffer); - bit_buffer_free(instance->tx_frame_buffer); - bit_buffer_free(instance->rx_frame_buffer); iso15693_3_free(instance->data); free(instance); } diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3_poller_i.c b/lib/nfc/protocols/iso15693_3/iso15693_3_poller_i.c index 12aff5759918..23a053608c66 100644 --- a/lib/nfc/protocols/iso15693_3/iso15693_3_poller_i.c +++ b/lib/nfc/protocols/iso15693_3/iso15693_3_poller_i.c @@ -6,16 +6,6 @@ #define BITS_IN_BYTE (8) -#define ISO15693_RESP_SOF_SIZE (5) -#define ISO15693_RESP_EOF_SIZE (5) -#define ISO15693_RESP_SOF_MASK (0x1FU) -#define ISO15693_RESP_SOF_PATTERN (0x17U) -#define ISO15693_RESP_EOF_PATTERN (0x1DU) - -#define ISO15693_RESP_PATTERN_MASK (0x03U) -#define ISO15693_RESP_PATTERN_0 (0x01U) -#define ISO15693_RESP_PATTERN_1 (0x02U) - #define ISO15693_3_POLLER_NUM_BLOCKS_PER_QUERY (32U) static Iso15693_3Error iso15693_3_poller_process_nfc_error(NfcError error) { @@ -52,63 +42,6 @@ static Iso15693_3Error iso15693_3_poller_prepare_trx(Iso15693_3Poller* instance) return Iso15693_3ErrorNone; } -static void iso15693_3_poller_encode_byte(uint8_t data, BitBuffer* out) { - static const uint8_t bit_patterns_1_out_of_4[] = {0x02, 0x08, 0x20, 0x80}; - - for(uint32_t i = 0; i < BITS_IN_BYTE; i += (BITS_IN_BYTE) / 4) { - const uint8_t bit_pair = (data >> i) & 0x03; - bit_buffer_append_byte(out, bit_patterns_1_out_of_4[bit_pair]); - } -} - -static void iso15693_3_poller_encode_frame(const BitBuffer* data, BitBuffer* frame_data) { - bit_buffer_append_byte(frame_data, 0x21); // Add SOF 1 out of 4 - - for(size_t i = 0; i < bit_buffer_get_size_bytes(data); ++i) { - iso15693_3_poller_encode_byte(bit_buffer_get_byte(data, i), frame_data); - } - - bit_buffer_append_byte(frame_data, 0x04); // Add EOF -} - -static bool iso15693_3_poller_decode_frame(BitBuffer* data, const BitBuffer* frame_data) { - bool decoded = false; - - do { - if(bit_buffer_get_size(frame_data) == 0) break; - // Check SOF - if((bit_buffer_get_byte(frame_data, 0) & ISO15693_RESP_SOF_MASK) != - ISO15693_RESP_SOF_PATTERN) - break; - - // 2 response bits = 1 data bit - for(uint32_t i = ISO15693_RESP_SOF_SIZE; - i < bit_buffer_get_size(frame_data) - ISO15693_RESP_SOF_SIZE; - i += BITS_IN_BYTE / 4) { - const uint8_t resp_byte = bit_buffer_get_byte_from_bit(frame_data, i); - - // Check EOF - if(resp_byte == ISO15693_RESP_EOF_PATTERN) { - decoded = true; - break; - } - - const uint8_t bit_pattern = resp_byte & ISO15693_RESP_PATTERN_MASK; - - if(bit_pattern == ISO15693_RESP_PATTERN_0) { - bit_buffer_append_bit(data, false); - } else if(bit_pattern == ISO15693_RESP_PATTERN_1) { - bit_buffer_append_bit(data, true); - } else { - break; - } - } - - } while(false); - - return decoded; -} - static Iso15693_3Error iso15693_3_poller_frame_exchange( Iso15693_3Poller* instance, const BitBuffer* tx_buffer, @@ -128,23 +61,12 @@ static Iso15693_3Error iso15693_3_poller_frame_exchange( bit_buffer_copy(instance->tx_buffer, tx_buffer); iso13239_crc_append(Iso13239CrcTypeDefault, instance->tx_buffer); - bit_buffer_reset(instance->tx_frame_buffer); - bit_buffer_reset(instance->rx_frame_buffer); - - iso15693_3_poller_encode_frame(instance->tx_buffer, instance->tx_frame_buffer); - - NfcError error = - nfc_trx(instance->nfc, instance->tx_frame_buffer, instance->rx_frame_buffer, fwt); + NfcError error = nfc_trx(instance->nfc, instance->tx_buffer, instance->rx_buffer, fwt); if(error != NfcErrorNone) { ret = iso15693_3_poller_process_nfc_error(error); break; } - if(!iso15693_3_poller_decode_frame(instance->rx_buffer, instance->rx_frame_buffer)) { - ret = Iso15693_3ErrorFraming; - break; - } - if(!iso13239_crc_check(Iso13239CrcTypeDefault, instance->rx_buffer)) { ret = Iso15693_3ErrorWrongCrc; break; diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3_poller_i.h b/lib/nfc/protocols/iso15693_3/iso15693_3_poller_i.h index 6b6073132a20..154ee684c97c 100644 --- a/lib/nfc/protocols/iso15693_3/iso15693_3_poller_i.h +++ b/lib/nfc/protocols/iso15693_3/iso15693_3_poller_i.h @@ -4,7 +4,7 @@ #include "iso15693_3_i.h" -#include +#include #ifdef __cplusplus extern "C" { @@ -25,8 +25,6 @@ struct Iso15693_3Poller { Iso15693_3Data* data; BitBuffer* tx_buffer; BitBuffer* rx_buffer; - BitBuffer* tx_frame_buffer; - BitBuffer* rx_frame_buffer; NfcGenericEvent general_event; Iso15693_3PollerEvent iso15693_3_event; diff --git a/lib/nfc/protocols/mf_classic/crypto1.h b/lib/nfc/protocols/mf_classic/crypto1.h index 4273ac82c5b5..f2bdb272b0e6 100644 --- a/lib/nfc/protocols/mf_classic/crypto1.h +++ b/lib/nfc/protocols/mf_classic/crypto1.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #ifdef __cplusplus extern "C" { diff --git a/lib/nfc/protocols/nfc_listener_defs.c b/lib/nfc/protocols/nfc_listener_defs.c index 0a44454f0934..094757f0832c 100644 --- a/lib/nfc/protocols/nfc_listener_defs.c +++ b/lib/nfc/protocols/nfc_listener_defs.c @@ -2,12 +2,15 @@ #include #include +#include #include #include const NfcListenerBase* nfc_listeners_api[NfcProtocolNum] = { [NfcProtocolIso14443_3a] = &nfc_listener_iso14443_3a, + [NfcProtocolIso14443_3b] = NULL, [NfcProtocolIso14443_4a] = &nfc_listener_iso14443_4a, + [NfcProtocolIso15693_3] = &nfc_listener_iso15693_3, [NfcProtocolMfUltralight] = &mf_ultralight_listener, [NfcProtocolMfClassic] = &mf_classic_listener, [NfcProtocolMfDesfire] = NULL, diff --git a/lib/signal_reader/SConscript b/lib/signal_reader/SConscript new file mode 100644 index 000000000000..ea7314420189 --- /dev/null +++ b/lib/signal_reader/SConscript @@ -0,0 +1,20 @@ +Import("env") + +env.Append( + CPPPATH=[ + "#/lib/signal_reader", + ], + SDK_HEADERS=[ + File("signal_reader.h"), + ], +) + +libenv = env.Clone(FW_LIB_NAME="signal_reader") +libenv.ApplyLibFlags() +libenv.Append(CCFLAGS=["-O3", "-funroll-loops", "-Ofast"]) + +sources = libenv.GlobRecursive("*.c*") + +lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) +libenv.Install("${LIB_DIST_DIR}", lib) +Return("lib") diff --git a/lib/signal_reader/parsers/iso15693/iso15693_parser.c b/lib/signal_reader/parsers/iso15693/iso15693_parser.c new file mode 100644 index 000000000000..80652e57b08c --- /dev/null +++ b/lib/signal_reader/parsers/iso15693/iso15693_parser.c @@ -0,0 +1,334 @@ +#include "iso15693_parser.h" + +#include + +#include + +#define ISO15693_PARSER_BITSTREAM_BUFF_SIZE (8) +#define ISO15693_PARSER_BITRATE_F64MHZ (603U) + +#define TAG "Iso15693Parser" + +typedef enum { + Iso15693ParserStateParseSoF, + Iso15693ParserStateParse1OutOf4, + Iso15693ParserStateParse1OutOf256, + + Iso15693ParserStateNum, +} Iso15693ParserState; + +struct Iso15693Parser { + Iso15693ParserState state; + + SignalReader* signal_reader; + + uint8_t bitstream_buff[ISO15693_PARSER_BITSTREAM_BUFF_SIZE]; + size_t bitstream_idx; + uint8_t last_byte; + + bool signal_detected; + bool bit_offset_calculated; + uint8_t bit_offset; + size_t byte_idx; + size_t bytes_to_process; + + uint8_t next_byte; + uint16_t next_byte_part; + bool zero_found; + + BitBuffer* parsed_frame; + bool frame_parsed; + + Iso15693ParserCallback callback; + void* context; +}; + +typedef enum { + Iso15693ParserCommandProcessed, + Iso15693ParserCommandWaitData, + Iso15693ParserCommandFail, + Iso15693ParserCommandSuccess, +} Iso15693ParserCommand; + +typedef Iso15693ParserCommand (*Iso15693ParserStateHandler)(Iso15693Parser* instance); + +Iso15693Parser* iso15693_parser_alloc(const GpioPin* pin, size_t max_frame_size) { + Iso15693Parser* instance = malloc(sizeof(Iso15693Parser)); + instance->parsed_frame = bit_buffer_alloc(max_frame_size); + + instance->signal_reader = signal_reader_alloc(pin, ISO15693_PARSER_BITSTREAM_BUFF_SIZE); + signal_reader_set_sample_rate( + instance->signal_reader, SignalReaderTimeUnit64Mhz, ISO15693_PARSER_BITRATE_F64MHZ); + signal_reader_set_pull(instance->signal_reader, GpioPullDown); + signal_reader_set_polarity(instance->signal_reader, SignalReaderPolarityInverted); + + return instance; +} + +void iso15693_parser_free(Iso15693Parser* instance) { + furi_assert(instance); + + bit_buffer_free(instance->parsed_frame); + signal_reader_free(instance->signal_reader); + free(instance); +} + +void iso15693_parser_reset(Iso15693Parser* instance) { + furi_assert(instance); + + instance->state = Iso15693ParserStateParseSoF; + memset(instance->bitstream_buff, 0x00, sizeof(instance->bitstream_buff)); + instance->bitstream_idx = 0; + + instance->next_byte = 0; + instance->next_byte_part = 0; + + instance->bit_offset = 0; + instance->byte_idx = 0; + instance->bytes_to_process = 0; + instance->signal_detected = false; + instance->bit_offset_calculated = false; + + instance->last_byte = 0x00; + instance->zero_found = false; + + bit_buffer_reset(instance->parsed_frame); + instance->frame_parsed = false; +} + +static void signal_reader_callback(SignalReaderEvent event, void* context) { + furi_assert(context); + furi_assert(event.data->data); + furi_assert(event.data->len == ISO15693_PARSER_BITSTREAM_BUFF_SIZE / 2); + + Iso15693Parser* instance = context; + furi_assert(instance->callback); + + if(!instance->signal_detected) { + size_t i = 0; + for(i = 0; i < event.data->len; i++) { + if(event.data->data[i] != 0x00) { + break; + } + } + if(i != event.data->len) { + memcpy(instance->bitstream_buff, &event.data->data[i], event.data->len - i); + instance->bytes_to_process = event.data->len - i; + instance->signal_detected = true; + } + } else { + memcpy( + &instance->bitstream_buff[instance->bytes_to_process], + event.data->data, + event.data->len); + instance->bytes_to_process += event.data->len; + } + if(instance->bytes_to_process >= ISO15693_PARSER_BITSTREAM_BUFF_SIZE / 4) { + instance->callback(Iso15693ParserEventDataReceived, instance->context); + } +} + +static void iso15693_parser_start_signal_reader(Iso15693Parser* instance) { + iso15693_parser_reset(instance); + signal_reader_start(instance->signal_reader, signal_reader_callback, instance); +} + +void iso15693_parser_start( + Iso15693Parser* instance, + Iso15693ParserCallback callback, + void* context) { + furi_assert(instance); + furi_assert(callback); + + instance->callback = callback; + instance->context = context; + iso15693_parser_start_signal_reader(instance); +} + +void iso15693_parser_stop(Iso15693Parser* instance) { + furi_assert(instance); + + signal_reader_stop(instance->signal_reader); +} +static void iso15693_parser_prepare_buff(Iso15693Parser* instance) { + if(!instance->bit_offset_calculated) { + for(size_t i = 0; i < 8; i++) { + if(FURI_BIT(instance->bitstream_buff[0], i)) { + instance->bit_offset = i; + break; + } + } + if(instance->bit_offset == 7) { + if(FURI_BIT(instance->bitstream_buff[1], 0) == 1) { + instance->bit_offset = 0; + for(size_t i = 0; i < instance->bytes_to_process - 1; i++) { + instance->bitstream_buff[i] = instance->bitstream_buff[i + 1]; + instance->bytes_to_process--; + } + } + } else { + if(FURI_BIT(instance->bitstream_buff[0], instance->bit_offset + 1) == 1) { + instance->bit_offset++; + } + } + + for(size_t i = 0; i < instance->bytes_to_process - 1; i++) { + instance->bitstream_buff[i] = + (instance->bitstream_buff[i] >> instance->bit_offset) | + (instance->bitstream_buff[i + 1] << (8 - instance->bit_offset)); + } + instance->last_byte = instance->bitstream_buff[instance->bytes_to_process - 1]; + instance->bytes_to_process--; + instance->bit_offset_calculated = true; + } else { + for(size_t i = 0; i < instance->bytes_to_process; i++) { + uint8_t next_byte = instance->bitstream_buff[i]; + instance->bitstream_buff[i] = (instance->last_byte >> instance->bit_offset) | + (next_byte << (8 - instance->bit_offset)); + instance->last_byte = next_byte; + } + } +} + +static Iso15693ParserCommand iso15693_parser_parse_sof(Iso15693Parser* instance) { + Iso15693ParserCommand command = Iso15693ParserCommandProcessed; + const uint8_t sof_1_out_of_4 = 0x21; + const uint8_t sof_1_out_of_256 = 0x81; + const uint8_t eof = 0x01; + + if(instance->bitstream_buff[0] == sof_1_out_of_4) { + instance->state = Iso15693ParserStateParse1OutOf4; + instance->byte_idx = 1; + } else if(instance->bitstream_buff[0] == sof_1_out_of_256) { + instance->state = Iso15693ParserStateParse1OutOf256; + instance->byte_idx = 1; + } else if(instance->bitstream_buff[0] == eof) { + instance->frame_parsed = true; + command = Iso15693ParserCommandSuccess; + } else { + command = Iso15693ParserCommandFail; + } + + return command; +} + +static Iso15693ParserCommand iso15693_parser_parse_1_out_of_4(Iso15693Parser* instance) { + Iso15693ParserCommand command = Iso15693ParserCommandWaitData; + const uint8_t bit_patterns_1_out_of_4[] = {0x02, 0x08, 0x20, 0x80}; + const uint8_t eof = 0x04; + + for(size_t i = instance->byte_idx; i < instance->bytes_to_process; i++) { + // Check EoF + if(instance->next_byte_part == 0) { + if(instance->bitstream_buff[i] == eof) { + instance->frame_parsed = true; + command = Iso15693ParserCommandSuccess; + break; + } + } + + // Check next pattern + size_t j = 0; + for(j = 0; j < COUNT_OF(bit_patterns_1_out_of_4); j++) { + if(instance->bitstream_buff[i] == bit_patterns_1_out_of_4[j]) { + instance->next_byte |= j << (instance->next_byte_part * 2); + instance->next_byte_part++; + if(instance->next_byte_part == 4) { + instance->next_byte_part = 0; + bit_buffer_append_byte(instance->parsed_frame, instance->next_byte); + instance->next_byte = 0; + } + break; + } + } + if(j == COUNT_OF(bit_patterns_1_out_of_4)) { + command = Iso15693ParserCommandFail; + break; + } + } + instance->bytes_to_process = 0; + instance->byte_idx = 0; + + return command; +} + +static Iso15693ParserCommand iso15693_parser_parse_1_out_of_256(Iso15693Parser* instance) { + Iso15693ParserCommand command = Iso15693ParserCommandWaitData; + const uint8_t eof = 0x04; + + for(size_t i = instance->byte_idx; i < instance->bytes_to_process; i++) { + // Check EoF + if(instance->next_byte_part == 0) { + if(instance->bitstream_buff[i] == eof) { + instance->frame_parsed = true; + command = Iso15693ParserCommandSuccess; + break; + } + } + + if(instance->zero_found) { + if(instance->bitstream_buff[i] != 0x00) { + command = Iso15693ParserCommandFail; + break; + } + } else { + if(instance->bitstream_buff[i] != 0x00) { + for(size_t j = 0; j < 8; j++) { + if(FURI_BIT(instance->bitstream_buff[i], j) == 1) { + bit_buffer_append_byte( + instance->parsed_frame, instance->next_byte_part * 4 + j / 2); + } + } + } + } + instance->next_byte_part = (instance->next_byte_part + 1) % 64; + } + instance->bytes_to_process = 0; + instance->byte_idx = 0; + + return command; +} + +static const Iso15693ParserStateHandler iso15693_parser_state_handlers[Iso15693ParserStateNum] = { + [Iso15693ParserStateParseSoF] = iso15693_parser_parse_sof, + [Iso15693ParserStateParse1OutOf4] = iso15693_parser_parse_1_out_of_4, + [Iso15693ParserStateParse1OutOf256] = iso15693_parser_parse_1_out_of_256, +}; + +bool iso15693_parser_run(Iso15693Parser* instance) { + if(instance->bytes_to_process) { + iso15693_parser_prepare_buff(instance); + + Iso15693ParserCommand command = Iso15693ParserCommandProcessed; + while(command == Iso15693ParserCommandProcessed) { + command = iso15693_parser_state_handlers[instance->state](instance); + } + + if(command == Iso15693ParserCommandFail) { + FURI_LOG_D(TAG, "Frame parse failed"); + iso15693_parser_stop(instance); + iso15693_parser_start_signal_reader(instance); + } + } + + return instance->frame_parsed; +} + +size_t iso15693_parser_get_data_size_bytes(Iso15693Parser* instance) { + furi_assert(instance); + + return bit_buffer_get_size_bytes(instance->parsed_frame); +} + +void iso15693_parser_get_data( + Iso15693Parser* instance, + uint8_t* buff, + size_t buff_size, + size_t* data_bits) { + furi_assert(instance); + furi_assert(buff); + furi_assert(data_bits); + + bit_buffer_write_bytes(instance->parsed_frame, buff, buff_size); + *data_bits = bit_buffer_get_size(instance->parsed_frame); +} diff --git a/lib/signal_reader/parsers/iso15693/iso15693_parser.h b/lib/signal_reader/parsers/iso15693/iso15693_parser.h new file mode 100644 index 000000000000..3017a96d79ac --- /dev/null +++ b/lib/signal_reader/parsers/iso15693/iso15693_parser.h @@ -0,0 +1,42 @@ +#pragma once + +#include "../../signal_reader.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct Iso15693Parser Iso15693Parser; + +typedef enum { + Iso15693ParserEventDataReceived, +} Iso15693ParserEvent; + +typedef void (*Iso15693ParserCallback)(Iso15693ParserEvent event, void* context); + +Iso15693Parser* iso15693_parser_alloc(const GpioPin* pin, size_t max_frame_size); + +void iso15693_parser_free(Iso15693Parser* instance); + +void iso15693_parser_reset(Iso15693Parser* instance); + +void iso15693_parser_start( + Iso15693Parser* instance, + Iso15693ParserCallback callback, + void* context); + +void iso15693_parser_stop(Iso15693Parser* instance); + +bool iso15693_parser_run(Iso15693Parser* instance); + +size_t iso15693_parser_get_data_size_bytes(Iso15693Parser* instance); + +void iso15693_parser_get_data( + Iso15693Parser* instance, + uint8_t* buff, + size_t buff_size, + size_t* data_bits); + +#ifdef __cplusplus +} +#endif diff --git a/lib/signal_reader/signal_reader.c b/lib/signal_reader/signal_reader.c new file mode 100644 index 000000000000..b6758eebd605 --- /dev/null +++ b/lib/signal_reader/signal_reader.c @@ -0,0 +1,289 @@ +#include "signal_reader.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#define SIGNAL_READER_DMA DMA2 + +#define SIGNAL_READER_CAPTURE_TIM (TIM16) +#define SIGNAL_READER_CAPTURE_TIM_CHANNEL LL_TIM_CHANNEL_CH1 + +#define SIGNAL_READER_DMA_GPIO LL_DMA_CHANNEL_2 +#define SIGNAL_READER_DMA_GPIO_IRQ FuriHalInterruptIdDma2Ch2 +#define SIGNAL_READER_DMA_GPIO_DEF SIGNAL_READER_DMA, SIGNAL_READER_DMA_GPIO + +#define SIGNAL_READER_DMA_CNT_SYNC LL_DMA_CHANNEL_5 +#define SIGNAL_READER_DMA_CNT_SYNC_IRQ FuriHalInterruptIdDma2Ch5 +#define SIGNAL_READER_DMA_CNT_SYNC_DEF SIGNAL_READER_DMA, SIGNAL_READER_DMA_CNT_SYNC + +struct SignalReader { + size_t buffer_size; + const GpioPin* pin; + GpioPull pull; + SignalReaderPolarity polarity; + uint16_t* gpio_buffer; + uint8_t* bitstream_buffer; + + uint32_t tim_cnt_compensation; + uint32_t tim_arr; + + SignalReaderEvent event; + SignalReaderEventData event_data; + + SignalReaderCallback callback; + void* context; +}; + +#define GPIO_PIN_MAP(pin, prefix) \ + (((pin) == (LL_GPIO_PIN_0)) ? prefix##0 : \ + ((pin) == (LL_GPIO_PIN_1)) ? prefix##1 : \ + ((pin) == (LL_GPIO_PIN_2)) ? prefix##2 : \ + ((pin) == (LL_GPIO_PIN_3)) ? prefix##3 : \ + ((pin) == (LL_GPIO_PIN_4)) ? prefix##4 : \ + ((pin) == (LL_GPIO_PIN_5)) ? prefix##5 : \ + ((pin) == (LL_GPIO_PIN_6)) ? prefix##6 : \ + ((pin) == (LL_GPIO_PIN_7)) ? prefix##7 : \ + ((pin) == (LL_GPIO_PIN_8)) ? prefix##8 : \ + ((pin) == (LL_GPIO_PIN_9)) ? prefix##9 : \ + ((pin) == (LL_GPIO_PIN_10)) ? prefix##10 : \ + ((pin) == (LL_GPIO_PIN_11)) ? prefix##11 : \ + ((pin) == (LL_GPIO_PIN_12)) ? prefix##12 : \ + ((pin) == (LL_GPIO_PIN_13)) ? prefix##13 : \ + ((pin) == (LL_GPIO_PIN_14)) ? prefix##14 : \ + prefix##15) + +#define GET_DMAMUX_EXTI_LINE(pin) GPIO_PIN_MAP(pin, LL_DMAMUX_REQ_GEN_EXTI_LINE) + +SignalReader* signal_reader_alloc(const GpioPin* gpio_pin, uint32_t size) { + SignalReader* instance = malloc(sizeof(SignalReader)); + + instance->pin = gpio_pin; + instance->pull = GpioPullNo; + + instance->buffer_size = size; + instance->gpio_buffer = malloc(sizeof(uint16_t) * size * 8); + instance->bitstream_buffer = malloc(size); + + instance->event.data = &instance->event_data; + + return instance; +} + +void signal_reader_free(SignalReader* instance) { + furi_assert(instance); + furi_assert(instance->gpio_buffer); + furi_assert(instance->bitstream_buffer); + + free(instance->gpio_buffer); + free(instance->bitstream_buffer); + free(instance); +} + +void signal_reader_set_pull(SignalReader* instance, GpioPull pull) { + furi_assert(instance); + + instance->pull = pull; +} + +void signal_reader_set_polarity(SignalReader* instance, SignalReaderPolarity polarity) { + furi_assert(instance); + + instance->polarity = polarity; +} + +void signal_reader_set_sample_rate( + SignalReader* instance, + SignalReaderTimeUnit time_unit, + uint32_t time) { + furi_assert(instance); + UNUSED(time_unit); + + instance->tim_arr = time; +} + +static void furi_hal_sw_digital_pin_dma_rx_isr(void* context) { + SignalReader* instance = context; + + uint16_t* gpio_buff_start = NULL; + uint8_t* bitstream_buff_start = NULL; + + if(LL_DMA_IsActiveFlag_HT2(SIGNAL_READER_DMA)) { + LL_DMA_ClearFlag_HT2(SIGNAL_READER_DMA); + instance->event.type = SignalReaderEventTypeHalfBufferFilled; + gpio_buff_start = instance->gpio_buffer; + bitstream_buff_start = instance->bitstream_buffer; + + if(instance->callback) { + furi_assert(gpio_buff_start); + furi_assert(bitstream_buff_start); + + for(size_t i = 0; i < instance->buffer_size * 4; i++) { + if((i % 8) == 0) { + bitstream_buff_start[i / 8] = 0; + } + uint8_t bit = 0; + if(instance->polarity == SignalReaderPolarityNormal) { + bit = (gpio_buff_start[i] & instance->pin->pin) == instance->pin->pin; + } else { + bit = (gpio_buff_start[i] & instance->pin->pin) == 0; + } + bitstream_buff_start[i / 8] |= bit << (i % 8); + } + instance->event_data.data = bitstream_buff_start; + instance->event_data.len = instance->buffer_size / 2; + instance->callback(instance->event, instance->context); + } + } + if(LL_DMA_IsActiveFlag_TC2(SIGNAL_READER_DMA)) { + LL_DMA_ClearFlag_TC2(SIGNAL_READER_DMA); + instance->event.type = SignalReaderEventTypeFullBufferFilled; + gpio_buff_start = &instance->gpio_buffer[instance->buffer_size * 4]; + bitstream_buff_start = &instance->bitstream_buffer[instance->buffer_size / 2]; + + if(instance->callback) { + furi_assert(gpio_buff_start); + furi_assert(bitstream_buff_start); + + for(size_t i = 0; i < instance->buffer_size * 4; i++) { + if((i % 8) == 0) { + bitstream_buff_start[i / 8] = 0; + } + uint8_t bit = 0; + if(instance->polarity == SignalReaderPolarityNormal) { + bit = (gpio_buff_start[i] & instance->pin->pin) == instance->pin->pin; + } else { + bit = (gpio_buff_start[i] & instance->pin->pin) == 0; + } + bitstream_buff_start[i / 8] |= bit << (i % 8); + } + instance->event_data.data = bitstream_buff_start; + instance->event_data.len = instance->buffer_size / 2; + instance->callback(instance->event, instance->context); + } + } +} + +void signal_reader_start(SignalReader* instance, SignalReaderCallback callback, void* context) { + furi_assert(instance); + furi_assert(callback); + + instance->callback = callback; + instance->context = context; + + // EXTI delay compensation + instance->tim_cnt_compensation = 9; + + furi_hal_bus_enable(FuriHalBusTIM16); + + // Capture timer config + LL_TIM_SetPrescaler(SIGNAL_READER_CAPTURE_TIM, 0); + LL_TIM_SetCounterMode(SIGNAL_READER_CAPTURE_TIM, LL_TIM_COUNTERMODE_UP); + LL_TIM_SetAutoReload(SIGNAL_READER_CAPTURE_TIM, instance->tim_arr); + LL_TIM_SetClockDivision(SIGNAL_READER_CAPTURE_TIM, LL_TIM_CLOCKDIVISION_DIV1); + + LL_TIM_DisableARRPreload(SIGNAL_READER_CAPTURE_TIM); + LL_TIM_SetClockSource(SIGNAL_READER_CAPTURE_TIM, LL_TIM_CLOCKSOURCE_INTERNAL); + + // Configure TIM channel CC1 + LL_TIM_OC_InitTypeDef TIM_OC_InitStruct = {}; + TIM_OC_InitStruct.OCMode = LL_TIM_OCMODE_FROZEN; + TIM_OC_InitStruct.OCState = LL_TIM_OCSTATE_DISABLE; + TIM_OC_InitStruct.OCNState = LL_TIM_OCSTATE_DISABLE; + TIM_OC_InitStruct.CompareValue = (instance->tim_arr / 2); + TIM_OC_InitStruct.OCPolarity = LL_TIM_OCPOLARITY_HIGH; + LL_TIM_OC_Init( + SIGNAL_READER_CAPTURE_TIM, SIGNAL_READER_CAPTURE_TIM_CHANNEL, &TIM_OC_InitStruct); + LL_TIM_OC_DisableFast(SIGNAL_READER_CAPTURE_TIM, SIGNAL_READER_CAPTURE_TIM_CHANNEL); + + LL_TIM_SetTriggerOutput(SIGNAL_READER_CAPTURE_TIM, LL_TIM_TRGO_RESET); + LL_TIM_DisableMasterSlaveMode(SIGNAL_READER_CAPTURE_TIM); + + // Start + LL_TIM_GenerateEvent_UPDATE(SIGNAL_READER_CAPTURE_TIM); + + /* We need the EXTI to be configured as interrupt generating line, but no ISR registered */ + furi_hal_gpio_init( + instance->pin, GpioModeInterruptRiseFall, instance->pull, GpioSpeedVeryHigh); + furi_delay_ms(10); + + /* Set DMAMUX request generation signal ID on specified DMAMUX channel */ + LL_DMAMUX_SetRequestSignalID( + DMAMUX1, LL_DMAMUX_REQ_GEN_0, GET_DMAMUX_EXTI_LINE(instance->pin->pin)); + /* Set the polarity of the signal on which the DMA request is generated */ + LL_DMAMUX_SetRequestGenPolarity(DMAMUX1, LL_DMAMUX_REQ_GEN_0, LL_DMAMUX_REQ_GEN_POL_RISING); + /* Set the number of DMA requests that will be authorized after a generation event */ + LL_DMAMUX_SetGenRequestNb(DMAMUX1, LL_DMAMUX_REQ_GEN_0, 1); + + // Configure DMA Sync + LL_DMA_SetMemoryAddress( + SIGNAL_READER_DMA_CNT_SYNC_DEF, (uint32_t)&instance->tim_cnt_compensation); + LL_DMA_SetPeriphAddress( + SIGNAL_READER_DMA_CNT_SYNC_DEF, (uint32_t) & (SIGNAL_READER_CAPTURE_TIM->CNT)); + LL_DMA_ConfigTransfer( + SIGNAL_READER_DMA_CNT_SYNC_DEF, + LL_DMA_DIRECTION_MEMORY_TO_PERIPH | LL_DMA_MODE_CIRCULAR | LL_DMA_PERIPH_NOINCREMENT | + LL_DMA_MEMORY_NOINCREMENT | LL_DMA_PDATAALIGN_HALFWORD | LL_DMA_MDATAALIGN_HALFWORD | + LL_DMA_PRIORITY_VERYHIGH); + LL_DMA_SetDataLength(SIGNAL_READER_DMA_CNT_SYNC_DEF, 1); + LL_DMA_SetPeriphRequest(SIGNAL_READER_DMA_CNT_SYNC_DEF, LL_DMAMUX_REQ_GENERATOR0); + + // Configure DMA Rx pin + LL_DMA_SetMemoryAddress(SIGNAL_READER_DMA_GPIO_DEF, (uint32_t)instance->gpio_buffer); + LL_DMA_SetPeriphAddress(SIGNAL_READER_DMA_GPIO_DEF, (uint32_t) & (instance->pin->port->IDR)); + LL_DMA_ConfigTransfer( + SIGNAL_READER_DMA_GPIO_DEF, + LL_DMA_DIRECTION_PERIPH_TO_MEMORY | LL_DMA_MODE_CIRCULAR | LL_DMA_PERIPH_NOINCREMENT | + LL_DMA_MEMORY_INCREMENT | LL_DMA_PDATAALIGN_HALFWORD | LL_DMA_MDATAALIGN_HALFWORD | + LL_DMA_PRIORITY_HIGH); + LL_DMA_SetDataLength(SIGNAL_READER_DMA_GPIO_DEF, instance->buffer_size * 8); + LL_DMA_SetPeriphRequest(SIGNAL_READER_DMA_GPIO_DEF, LL_DMAMUX_REQ_TIM16_CH1); + + // Configure DMA Channel CC1 + LL_TIM_EnableDMAReq_CC1(SIGNAL_READER_CAPTURE_TIM); + LL_TIM_CC_EnableChannel(SIGNAL_READER_CAPTURE_TIM, SIGNAL_READER_CAPTURE_TIM_CHANNEL); + + // Start DMA irq, higher priority than normal + furi_hal_interrupt_set_isr_ex( + SIGNAL_READER_DMA_GPIO_IRQ, 14, furi_hal_sw_digital_pin_dma_rx_isr, instance); + + // Start DMA Sync timer + LL_DMA_EnableChannel(SIGNAL_READER_DMA_CNT_SYNC_DEF); + LL_DMAMUX_EnableRequestGen(DMAMUX1, LL_DMAMUX_REQ_GEN_0); + + // Start DMA Rx pin + LL_DMA_EnableChannel(SIGNAL_READER_DMA_GPIO_DEF); + // Strat timer + LL_TIM_SetCounter(SIGNAL_READER_CAPTURE_TIM, 0); + LL_TIM_EnableCounter(SIGNAL_READER_CAPTURE_TIM); + + // Need to clear flags before enabling DMA !!!! + if(LL_DMA_IsActiveFlag_TC2(SIGNAL_READER_DMA)) LL_DMA_ClearFlag_TC1(SIGNAL_READER_DMA); + if(LL_DMA_IsActiveFlag_TE2(SIGNAL_READER_DMA)) LL_DMA_ClearFlag_TE1(SIGNAL_READER_DMA); + LL_DMA_EnableIT_TC(SIGNAL_READER_DMA_GPIO_DEF); + LL_DMA_EnableIT_HT(SIGNAL_READER_DMA_GPIO_DEF); +} + +void signal_reader_stop(SignalReader* instance) { + furi_assert(instance); + + furi_hal_interrupt_set_isr(SIGNAL_READER_DMA_GPIO_IRQ, NULL, NULL); + + // Deinit DMA Rx pin + LL_DMA_DeInit(SIGNAL_READER_DMA_GPIO_DEF); + // Deinit DMA Sync timer + LL_DMA_DeInit(SIGNAL_READER_DMA_CNT_SYNC_DEF); + + furi_hal_bus_disable(FuriHalBusTIM16); + + memset(instance->gpio_buffer, 0, sizeof(uint16_t) * instance->buffer_size * 8); + memset(instance->bitstream_buffer, 0, instance->buffer_size); +} diff --git a/lib/signal_reader/signal_reader.h b/lib/signal_reader/signal_reader.h new file mode 100644 index 000000000000..2213465c37c2 --- /dev/null +++ b/lib/signal_reader/signal_reader.h @@ -0,0 +1,60 @@ +#pragma once + +#include +#include +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + SignalReaderEventTypeHalfBufferFilled, + SignalReaderEventTypeFullBufferFilled, +} SignalReaderEventType; + +typedef struct { + uint8_t* data; + size_t len; +} SignalReaderEventData; + +typedef struct { + SignalReaderEventType type; + SignalReaderEventData* data; +} SignalReaderEvent; + +typedef enum { + SignalReaderTimeUnit64Mhz, +} SignalReaderTimeUnit; + +typedef enum { + SignalReaderPolarityNormal, + SignalReaderPolarityInverted, +} SignalReaderPolarity; + +typedef void (*SignalReaderCallback)(SignalReaderEvent event, void* context); + +typedef struct SignalReader SignalReader; + +SignalReader* signal_reader_alloc(const GpioPin* gpio_pin, uint32_t size); + +void signal_reader_free(SignalReader* instance); + +void signal_reader_set_pull(SignalReader* instance, GpioPull pull); + +void signal_reader_set_polarity(SignalReader* instance, SignalReaderPolarity polarity); + +void signal_reader_set_sample_rate( + SignalReader* instance, + SignalReaderTimeUnit time_unit, + uint32_t time); + +void signal_reader_start(SignalReader* instance, SignalReaderCallback callback, void* context); + +void signal_reader_stop(SignalReader* instance); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/helpers/bit_buffer.c b/lib/toolbox/bit_buffer.c similarity index 100% rename from lib/nfc/helpers/bit_buffer.c rename to lib/toolbox/bit_buffer.c diff --git a/lib/nfc/helpers/bit_buffer.h b/lib/toolbox/bit_buffer.h similarity index 100% rename from lib/nfc/helpers/bit_buffer.h rename to lib/toolbox/bit_buffer.h From d87bd747a0bd23ea56a18e3f8dc6f5ff1651cc47 Mon Sep 17 00:00:00 2001 From: RebornedBrain <138568282+RebornedBrain@users.noreply.github.com> Date: Tue, 22 Aug 2023 19:50:05 +0300 Subject: [PATCH 140/149] INCR_CNT command added for Ultralight and READ_CNT fixed for NTAGs (#3001) * Adjusted READ_CNT function to check nfc_cnt_en for NTAG * INCR_CNT command added for Ultralight * IncrValue is now taken using MfUltralightCounter union --- .../protocols/mf_ultralight/mf_ultralight.h | 2 + .../mf_ultralight/mf_ultralight_listener.c | 51 +++++++++++++++++-- 2 files changed, 49 insertions(+), 4 deletions(-) diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h index bad5e0a0536b..c4378d78aa49 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h @@ -14,12 +14,14 @@ extern "C" { #define MF_ULTRALIGHT_CMD_WRITE_PAGE (0xA2) #define MF_ULTRALIGTH_CMD_READ_SIG (0x3C) #define MF_ULTRALIGHT_CMD_READ_CNT (0x39) +#define MF_ULTRALIGHT_CMD_INCR_CNT (0xA5) #define MF_ULTRALIGHT_CMD_CHECK_TEARING (0x3E) #define MF_ULTRALIGHT_CMD_AUTH (0x1B) #define MF_ULTRALIGHT_CMD_ACK (0x0A) #define MF_ULTRALIGHT_CMD_NACK (0x00) +#define MF_ULTRALIGHT_MAX_CNTR_VAL (0x00FFFFFF) #define MF_ULTRALIGHT_MAX_PAGE_NUM (510) #define MF_ULTRALIGHT_PAGE_SIZE (4U) #define MF_ULTRALIGHT_SIGNATURE_SIZE (32) diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c index 6e9a86e65aef..f80ab2794b30 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c @@ -187,17 +187,18 @@ static MfUltralightCommand break; if(mf_ultralight_support_feature( - instance->features, MfUltralightFeatureSupportSingleCounter) && - (counter_num != 2)) - break; + instance->features, MfUltralightFeatureSupportSingleCounter)) { + if(instance->config == NULL) break; + + if(!instance->config->access.nfc_cnt_en || counter_num != 2) break; - if(instance->config) { if(instance->config->access.nfc_cnt_pwd_prot) { if(instance->auth_state != MfUltralightListenerAuthStateSuccess) { break; } } } + if(counter_num > 2) break; uint8_t cnt_value[3] = { (instance->data->counter[counter_num].counter >> 0) & 0xff, @@ -213,6 +214,43 @@ static MfUltralightCommand return command; } +static MfUltralightCommand mf_ultralight_listener_increase_counter_handler( + MfUltralightListener* instance, + BitBuffer* buffer) { + MfUltralightCommand command = MfUltralightCommandNotProcessedNAK; + + FURI_LOG_D(TAG, "CMD_INCR_CNT"); + + do { + if(!mf_ultralight_support_feature( + instance->features, MfUltralightFeatureSupportIncCounter)) { + command = MfUltralightCommandNotProcessedSilent; + break; + } + + uint8_t counter_num = bit_buffer_get_byte(buffer, 1); + if(counter_num > 2) break; + + if(instance->data->counter[counter_num].counter == MF_ULTRALIGHT_MAX_CNTR_VAL) { + command = MfUltralightCommandProcessed; + break; + } + + MfUltralightCounter buf_counter = {}; + bit_buffer_write_bytes_mid(buffer, buf_counter.data, 2, sizeof(buf_counter.data)); + uint32_t incr_value = buf_counter.counter; + + if(instance->data->counter[counter_num].counter + incr_value > MF_ULTRALIGHT_MAX_CNTR_VAL) + break; + + instance->data->counter[counter_num].counter += incr_value; + mf_ultralight_listener_send_short_resp(instance, MF_ULTRALIGHT_CMD_ACK); + command = MfUltralightCommandProcessed; + } while(false); + + return command; +} + static MfUltralightCommand mf_ultralight_listener_check_tearing_handler( MfUltralightListener* instance, BitBuffer* buffer) { @@ -315,6 +353,11 @@ static const MfUltralightListenerCmdHandler mf_ultralight_command[] = { .cmd_len_bits = 5 * 8, .callback = mf_ultralight_listener_auth_handler, }, + { + .cmd = MF_ULTRALIGHT_CMD_INCR_CNT, + .cmd_len_bits = 6 * 8, + .callback = mf_ultralight_listener_increase_counter_handler, + }, }; static void mf_ultralight_listener_prepare_emulation(MfUltralightListener* instance) { From 079b74d09e9bf9fb314ba35c6ca3396874ed459e Mon Sep 17 00:00:00 2001 From: gornekich Date: Mon, 28 Aug 2023 13:58:39 +0400 Subject: [PATCH 141/149] [FL-3444], [FL-3448] MFC Poller improvements (#3016) * nfc: introduce user dict for simplier modifying * nfc app: add mfc keys scene * nfc app: add mf classic keys list scene * nfc: implement user dict delete scene * nfc tests: add mf dict tests * mf classic: fix dict attack * mfc: update card start * mfc: introduce new MfClassicKeyCache * nfc app: correct scene switches * nfc: fix key cache reading * nfc app: add write and update scenes * nfc app: rework mfc update * nfc app: rework mfc write to initial card * nfc app: introduce plaintain plugin * mf classic: rework write state machine * mfc: rework generic card detected and lost events * nfc: mfc update initial fixes * mf classic: add read with keys to sync api * mf classic: rework dict attack * nfc app: new dict attack * mfc: rework dict attack view * mfc: fix incorrect key byte order * nfc: fix card detect and loss * nfc: fix mf dict reopen * mf classic: rework read state machine * nfc plugins: rework troika parser * nfc plugins: rework plaintain parser * mfc: fix block type, mfc detection * nfc: fix all plugins * nfc: add todo for key cache handilng --- applications/debug/unit_tests/application.fam | 1 + applications/debug/unit_tests/nfc/nfc_test.c | 78 +- applications/main/nfc/application.fam | 14 + .../main/nfc/helpers/mf_classic_key_cache.c | 211 ++++++ .../main/nfc/helpers/mf_classic_key_cache.h | 31 + applications/main/nfc/helpers/mf_dict.c | 189 ++--- applications/main/nfc/helpers/mf_dict.h | 52 +- applications/main/nfc/helpers/mf_user_dict.c | 74 ++ applications/main/nfc/helpers/mf_user_dict.h | 23 + .../main/nfc/helpers/nfc_custom_event.h | 15 +- .../protocol_support/mf_classic/mf_classic.c | 87 ++- .../protocol_support/nfc_protocol_support.c | 19 +- .../nfc_protocol_support_base.h | 1 + applications/main/nfc/nfc_app.c | 17 +- applications/main/nfc/nfc_app_i.h | 19 +- .../nfc/plugins/supported_cards/plantain.c | 216 ++++++ .../main/nfc/plugins/supported_cards/troika.c | 39 +- .../nfc/plugins/supported_cards/two_cities.c | 185 +++++ .../main/nfc/scenes/nfc_scene_config.h | 12 + .../nfc/scenes/nfc_scene_delete_success.c | 14 +- .../main/nfc/scenes/nfc_scene_extra_actions.c | 38 +- .../scenes/nfc_scene_mf_classic_dict_attack.c | 288 +++++--- .../nfc/scenes/nfc_scene_mf_classic_keys.c | 90 +++ .../scenes/nfc_scene_mf_classic_keys_add.c | 61 ++ .../scenes/nfc_scene_mf_classic_keys_delete.c | 77 ++ .../scenes/nfc_scene_mf_classic_keys_list.c | 51 ++ ...nfc_scene_mf_classic_keys_warn_duplicate.c | 49 ++ .../nfc_scene_mf_classic_update_initial.c | 144 ++++ ..._scene_mf_classic_update_initial_success.c | 43 ++ .../nfc_scene_mf_classic_write_initial.c | 146 ++++ .../nfc_scene_mf_classic_write_initial_fail.c | 62 ++ ...c_scene_mf_classic_write_initial_success.c | 43 ++ .../scenes/nfc_scene_mf_classic_wrong_card.c | 57 ++ .../main/nfc/scenes/nfc_scene_save_success.c | 17 +- applications/main/nfc/views/dict_attack.c | 222 +++--- applications/main/nfc/views/dict_attack.h | 48 +- firmware/targets/f7/api_symbols.csv | 4 +- lib/nfc/protocols/mf_classic/mf_classic.c | 46 +- lib/nfc/protocols/mf_classic/mf_classic.h | 10 +- .../protocols/mf_classic/mf_classic_poller.c | 697 ++++++++++++++---- .../protocols/mf_classic/mf_classic_poller.h | 73 +- .../mf_classic/mf_classic_poller_i.c | 2 +- .../mf_classic/mf_classic_poller_i.h | 80 +- .../mf_classic/mf_classic_poller_sync_api.c | 118 ++- .../mf_classic/mf_classic_poller_sync_api.h | 3 + 45 files changed, 3002 insertions(+), 764 deletions(-) create mode 100644 applications/main/nfc/helpers/mf_classic_key_cache.c create mode 100644 applications/main/nfc/helpers/mf_classic_key_cache.h create mode 100644 applications/main/nfc/helpers/mf_user_dict.c create mode 100644 applications/main/nfc/helpers/mf_user_dict.h create mode 100644 applications/main/nfc/plugins/supported_cards/plantain.c create mode 100644 applications/main/nfc/plugins/supported_cards/two_cities.c create mode 100644 applications/main/nfc/scenes/nfc_scene_mf_classic_keys.c create mode 100644 applications/main/nfc/scenes/nfc_scene_mf_classic_keys_add.c create mode 100644 applications/main/nfc/scenes/nfc_scene_mf_classic_keys_delete.c create mode 100644 applications/main/nfc/scenes/nfc_scene_mf_classic_keys_list.c create mode 100644 applications/main/nfc/scenes/nfc_scene_mf_classic_keys_warn_duplicate.c create mode 100644 applications/main/nfc/scenes/nfc_scene_mf_classic_update_initial.c create mode 100644 applications/main/nfc/scenes/nfc_scene_mf_classic_update_initial_success.c create mode 100644 applications/main/nfc/scenes/nfc_scene_mf_classic_write_initial.c create mode 100644 applications/main/nfc/scenes/nfc_scene_mf_classic_write_initial_fail.c create mode 100644 applications/main/nfc/scenes/nfc_scene_mf_classic_write_initial_success.c create mode 100644 applications/main/nfc/scenes/nfc_scene_mf_classic_wrong_card.c diff --git a/applications/debug/unit_tests/application.fam b/applications/debug/unit_tests/application.fam index 949bb3fc292b..6f150e285ab9 100644 --- a/applications/debug/unit_tests/application.fam +++ b/applications/debug/unit_tests/application.fam @@ -4,6 +4,7 @@ App( entry_point="unit_tests_on_system_start", cdefines=["APP_UNIT_TESTS"], provides=["delay_test"], + requires=["nfc"], order=100, ) diff --git a/applications/debug/unit_tests/nfc/nfc_test.c b/applications/debug/unit_tests/nfc/nfc_test.c index 2ea4159e6080..8500d46c9b3a 100644 --- a/applications/debug/unit_tests/nfc/nfc_test.c +++ b/applications/debug/unit_tests/nfc/nfc_test.c @@ -12,6 +12,8 @@ #include #include +#include + #include #include "../minunit.h" @@ -19,18 +21,7 @@ #define TAG "NfcTest" #define NFC_TEST_NFC_DEV_PATH EXT_PATH("unit_tests/nfc/nfc_device_test.nfc") - -// Maximum allowed time for buffer preparation to fit 500us nt message timeout -#define NFC_TEST_4_BYTE_BUILD_BUFFER_TIM_MAX (150) -#define NFC_TEST_16_BYTE_BUILD_BUFFER_TIM_MAX (640) -#define NFC_TEST_4_BYTE_BUILD_SIGNAL_TIM_MAX (110) -#define NFC_TEST_16_BYTE_BUILD_SIGNAL_TIM_MAX (440) - -// Maximum allowed time for buffer preparation to fit 500us nt message timeout -#define NFC_TEST_4_BYTE_BUILD_BUFFER_TIM_MAX (150) -#define NFC_TEST_16_BYTE_BUILD_BUFFER_TIM_MAX (640) -#define NFC_TEST_4_BYTE_BUILD_SIGNAL_TIM_MAX (110) -#define NFC_TEST_16_BYTE_BUILD_SIGNAL_TIM_MAX (440) +#define MF_CLASSIC_DICT_UNIT_TEST_PATH EXT_PATH("unit_tests/mf_dict.nfc") typedef struct { Storage* storage; @@ -432,6 +423,67 @@ static void mf_classic_value_block() { nfc_free(poller); } +MU_TEST(mf_classic_dict_test) { + Storage* storage = furi_record_open(RECORD_STORAGE); + if(storage_common_stat(storage, MF_CLASSIC_DICT_UNIT_TEST_PATH, NULL) == FSE_OK) { + mu_assert( + storage_simply_remove(storage, MF_CLASSIC_DICT_UNIT_TEST_PATH), + "Remove test dict failed"); + } + + MfDict* dict = mf_dict_alloc(MfDictTypeUnitTest); + mu_assert(dict != NULL, "mf_dict_alloc() failed"); + + size_t dict_keys_total = mf_dict_get_total_keys(dict); + mu_assert(dict_keys_total == 0, "mf_dict_keys_total() failed"); + + const uint32_t test_key_num = 30; + MfClassicKey* key_arr_ref = malloc(test_key_num * sizeof(MfClassicKey)); + for(size_t i = 0; i < test_key_num; i++) { + furi_hal_random_fill_buf(key_arr_ref[i].data, sizeof(MfClassicKey)); + mu_assert(mf_dict_add_key(dict, &key_arr_ref[i]), "add key failed"); + + size_t dict_keys_total = mf_dict_get_total_keys(dict); + mu_assert(dict_keys_total == (i + 1), "mf_dict_keys_total() failed"); + } + + mf_dict_free(dict); + + dict = mf_dict_alloc(MfDictTypeUnitTest); + mu_assert(dict != NULL, "mf_dict_alloc() failed"); + + dict_keys_total = mf_dict_get_total_keys(dict); + mu_assert(dict_keys_total == test_key_num, "mf_dict_keys_total() failed"); + + MfClassicKey key_dut = {}; + size_t key_idx = 0; + while(mf_dict_get_next_key(dict, &key_dut)) { + mu_assert( + memcmp(key_arr_ref[key_idx].data, key_dut.data, sizeof(MfClassicKey)) == 0, + "Loaded key data mismatch"); + key_idx++; + } + + uint32_t delete_keys_idx[] = {1, 3, 9, 11, 19, 27}; + + for(size_t i = 0; i < COUNT_OF(delete_keys_idx); i++) { + MfClassicKey* key = &key_arr_ref[delete_keys_idx[i]]; + mu_assert(mf_dict_is_key_present(dict, key), "mf_dict_is_key_present() failed"); + mu_assert(mf_dict_delete_key(dict, key), "mf_dict_delete_key() failed"); + } + + dict_keys_total = mf_dict_get_total_keys(dict); + mu_assert( + dict_keys_total == test_key_num - COUNT_OF(delete_keys_idx), + "mf_dict_keys_total() failed"); + + mf_dict_free(dict); + free(key_arr_ref); + + mu_assert( + storage_simply_remove(storage, MF_CLASSIC_DICT_UNIT_TEST_PATH), "Remove test dict failed"); +} + MU_TEST_SUITE(nfc) { nfc_test_alloc(); @@ -471,6 +523,8 @@ MU_TEST_SUITE(nfc) { MU_RUN_TEST(mf_classic_write); MU_RUN_TEST(mf_classic_value_block); + MU_RUN_TEST(mf_classic_dict_test); + nfc_test_free(); } diff --git a/applications/main/nfc/application.fam b/applications/main/nfc/application.fam index 2d96f99c2799..27b11d8da06f 100644 --- a/applications/main/nfc/application.fam +++ b/applications/main/nfc/application.fam @@ -38,6 +38,20 @@ App( requires=["nfc"], ) +App( + appid="plantain_parser", + apptype=FlipperAppType.PLUGIN, + entry_point="plantain_plugin_ep", + requires=["nfc"], +) + +App( + appid="two_cities_parser", + apptype=FlipperAppType.PLUGIN, + entry_point="two_cities_plugin_ep", + requires=["nfc"], +) + # App( # appid="nfc_start", # apptype=FlipperAppType.STARTUP, diff --git a/applications/main/nfc/helpers/mf_classic_key_cache.c b/applications/main/nfc/helpers/mf_classic_key_cache.c new file mode 100644 index 000000000000..ef6a0f6bcaa6 --- /dev/null +++ b/applications/main/nfc/helpers/mf_classic_key_cache.c @@ -0,0 +1,211 @@ +#include "mf_classic_key_cache.h" + +#include +#include + +#define NFC_APP_KEYS_EXTENSION ".keys" +#define NFC_APP_KEY_CACHE_FOLDER "/ext/nfc/.cache" + +static const char* mf_classic_key_cache_file_header = "Flipper NFC keys"; +static const uint32_t mf_classic_key_cache_file_version = 1; + +struct MfClassicKeyCache { + MfClassicDeviceKeys keys; + MfClassicKeyType current_key_type; + uint8_t current_sector; +}; + +static void nfc_get_key_cache_file_path(const uint8_t* uid, size_t uid_len, FuriString* path) { + furi_string_printf(path, "%s/", NFC_APP_KEY_CACHE_FOLDER); + for(size_t i = 0; i < uid_len; i++) { + furi_string_cat_printf(path, "%02X", uid[i]); + } + furi_string_cat_printf(path, "%s", NFC_APP_KEYS_EXTENSION); +} + +MfClassicKeyCache* mf_classic_key_cache_alloc() { + MfClassicKeyCache* instance = malloc(sizeof(MfClassicKeyCache)); + + return instance; +} + +void mf_classic_key_cache_free(MfClassicKeyCache* instance) { + furi_assert(instance); + + free(instance); +} + +bool mf_classic_key_cache_save(MfClassicKeyCache* instance, const MfClassicData* data) { + UNUSED(instance); + furi_assert(data); + + size_t uid_len = 0; + const uint8_t* uid = mf_classic_get_uid(data, &uid_len); + FuriString* file_path = furi_string_alloc(); + nfc_get_key_cache_file_path(uid, uid_len, file_path); + + Storage* storage = furi_record_open(RECORD_STORAGE); + FlipperFormat* ff = flipper_format_buffered_file_alloc(storage); + + FuriString* temp_str = furi_string_alloc(); + bool save_success = false; + do { + if(!storage_simply_mkdir(storage, NFC_APP_KEY_CACHE_FOLDER)) break; + if(!storage_simply_remove(storage, furi_string_get_cstr(file_path))) break; + if(!flipper_format_buffered_file_open_always(ff, furi_string_get_cstr(file_path))) break; + + if(!flipper_format_write_header_cstr( + ff, mf_classic_key_cache_file_header, mf_classic_key_cache_file_version)) + break; + if(!flipper_format_write_string_cstr( + ff, "Mifare Classic type", mf_classic_get_device_name(data, NfcDeviceNameTypeShort))) + break; + if(!flipper_format_write_hex_uint64(ff, "Key A map", &data->key_a_mask, 1)) break; + if(!flipper_format_write_hex_uint64(ff, "Key B map", &data->key_b_mask, 1)) break; + + uint8_t sector_num = mf_classic_get_total_sectors_num(data->type); + bool key_save_success = true; + for(size_t i = 0; (i < sector_num) && (key_save_success); i++) { + MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(data, i); + if(FURI_BIT(data->key_a_mask, i)) { + furi_string_printf(temp_str, "Key A sector %d", i); + key_save_success = flipper_format_write_hex( + ff, furi_string_get_cstr(temp_str), sec_tr->key_a.data, sizeof(MfClassicKey)); + } + if(!key_save_success) break; + if(FURI_BIT(data->key_b_mask, i)) { + furi_string_printf(temp_str, "Key B sector %d", i); + key_save_success = flipper_format_write_hex( + ff, furi_string_get_cstr(temp_str), sec_tr->key_b.data, sizeof(MfClassicKey)); + } + } + save_success = key_save_success; + } while(false); + + flipper_format_free(ff); + furi_string_free(temp_str); + furi_string_free(file_path); + furi_record_close(RECORD_STORAGE); + + return save_success; +} + +bool mf_classic_key_cache_load(MfClassicKeyCache* instance, const uint8_t* uid, size_t uid_len) { + furi_assert(instance); + furi_assert(uid); + + FuriString* file_path = furi_string_alloc(); + nfc_get_key_cache_file_path(uid, uid_len, file_path); + + Storage* storage = furi_record_open(RECORD_STORAGE); + FlipperFormat* ff = flipper_format_buffered_file_alloc(storage); + + FuriString* temp_str = furi_string_alloc(); + bool load_success = false; + do { + if(!flipper_format_buffered_file_open_existing(ff, furi_string_get_cstr(file_path))) break; + + uint32_t version = 0; + if(!flipper_format_read_header(ff, temp_str, &version)) break; + if(furi_string_cmp_str(temp_str, mf_classic_key_cache_file_header)) break; + if(version != mf_classic_key_cache_file_version) break; + + if(!flipper_format_read_hex_uint64(ff, "Key A map", &instance->keys.key_a_mask, 1)) break; + if(!flipper_format_read_hex_uint64(ff, "Key B map", &instance->keys.key_b_mask, 1)) break; + + bool key_read_success = true; + for(size_t i = 0; (i < MF_CLASSIC_TOTAL_SECTORS_MAX) && (key_read_success); i++) { + if(FURI_BIT(instance->keys.key_a_mask, i)) { + furi_string_printf(temp_str, "Key A sector %d", i); + key_read_success = flipper_format_read_hex( + ff, + furi_string_get_cstr(temp_str), + instance->keys.key_a[i].data, + sizeof(MfClassicKey)); + } + if(!key_read_success) break; + if(FURI_BIT(instance->keys.key_b_mask, i)) { + furi_string_printf(temp_str, "Key B sector %d", i); + key_read_success = flipper_format_read_hex( + ff, + furi_string_get_cstr(temp_str), + instance->keys.key_b[i].data, + sizeof(MfClassicKey)); + } + } + load_success = key_read_success; + load_success = true; + } while(false); + + flipper_format_buffered_file_close(ff); + flipper_format_free(ff); + furi_string_free(temp_str); + furi_string_free(file_path); + furi_record_close(RECORD_STORAGE); + + return load_success; +} + +void mf_classic_key_cache_load_from_data(MfClassicKeyCache* instance, const MfClassicData* data) { + furi_assert(instance); + furi_assert(data); + + mf_classic_key_cache_reset(instance); + instance->keys.key_a_mask = data->key_a_mask; + instance->keys.key_b_mask = data->key_b_mask; + for(size_t i = 0; i < MF_CLASSIC_TOTAL_SECTORS_MAX; i++) { + MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(data, i); + + if(FURI_BIT(data->key_a_mask, i)) { + instance->keys.key_a[i] = sec_tr->key_a; + } + if(FURI_BIT(data->key_b_mask, i)) { + instance->keys.key_b[i] = sec_tr->key_b; + } + } +} + +bool mf_classic_key_cahce_get_next_key( + MfClassicKeyCache* instance, + uint8_t* sector_num, + MfClassicKey* key, + MfClassicKeyType* key_type) { + furi_assert(instance); + furi_assert(sector_num); + furi_assert(key); + furi_assert(key_type); + + bool next_key_found = false; + for(uint8_t i = instance->current_sector; i < MF_CLASSIC_TOTAL_SECTORS_MAX; i++) { + if(FURI_BIT(instance->keys.key_a_mask, i)) { + FURI_BIT_CLEAR(instance->keys.key_a_mask, i); + *key = instance->keys.key_a[i]; + *key_type = MfClassicKeyTypeA; + *sector_num = i; + + next_key_found = true; + break; + } + if(FURI_BIT(instance->keys.key_b_mask, i)) { + FURI_BIT_CLEAR(instance->keys.key_b_mask, i); + *key = instance->keys.key_b[i]; + *key_type = MfClassicKeyTypeB; + *sector_num = i; + + next_key_found = true; + instance->current_sector = i; + break; + } + } + + return next_key_found; +} + +void mf_classic_key_cache_reset(MfClassicKeyCache* instance) { + furi_assert(instance); + + instance->current_key_type = MfClassicKeyTypeA; + instance->current_sector = 0; + instance->keys.key_a_mask = 0; + instance->keys.key_b_mask = 0; +} diff --git a/applications/main/nfc/helpers/mf_classic_key_cache.h b/applications/main/nfc/helpers/mf_classic_key_cache.h new file mode 100644 index 000000000000..407c6e28bd42 --- /dev/null +++ b/applications/main/nfc/helpers/mf_classic_key_cache.h @@ -0,0 +1,31 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct MfClassicKeyCache MfClassicKeyCache; + +MfClassicKeyCache* mf_classic_key_cache_alloc(); + +void mf_classic_key_cache_free(MfClassicKeyCache* instance); + +bool mf_classic_key_cache_load(MfClassicKeyCache* instance, const uint8_t* uid, size_t uid_len); + +void mf_classic_key_cache_load_from_data(MfClassicKeyCache* instance, const MfClassicData* data); + +bool mf_classic_key_cahce_get_next_key( + MfClassicKeyCache* instance, + uint8_t* sector_num, + MfClassicKey* key, + MfClassicKeyType* key_type); + +bool mf_classic_key_cache_save(MfClassicKeyCache* instance, const MfClassicData* data); + +void mf_classic_key_cache_reset(MfClassicKeyCache* instance); + +#ifdef __cplusplus +} +#endif diff --git a/applications/main/nfc/helpers/mf_dict.c b/applications/main/nfc/helpers/mf_dict.c index 71a4a23c61a3..094dc0e27614 100644 --- a/applications/main/nfc/helpers/mf_dict.c +++ b/applications/main/nfc/helpers/mf_dict.c @@ -5,8 +5,8 @@ #include -#define MF_CLASSIC_DICT_FLIPPER_PATH EXT_PATH("nfc/assets/mf_classic_dict.nfc") -#define MF_CLASSIC_DICT_USER_PATH EXT_PATH("nfc/assets/mf_dict_user.nfc") +#define MF_CLASSIC_DICT_USER_PATH EXT_PATH("nfc/assets/mf_classic_dict_user.nfc") +#define MF_CLASSIC_DICT_SYSTEM_PATH EXT_PATH("nfc/assets/mf_classic_dict.nfc") #define MF_CLASSIC_DICT_UNIT_TEST_PATH EXT_PATH("unit_tests/mf_dict.nfc") #define TAG "MfDict" @@ -18,18 +18,36 @@ struct MfDict { uint32_t total_keys; }; +typedef struct { + const char* path; + FS_OpenMode open_mode; +} MfDictFile; + +static const MfDictFile mf_dict_file[MfDictTypeNum] = { + [MfDictTypeUser] = + { + .path = MF_CLASSIC_DICT_USER_PATH, + .open_mode = FSOM_OPEN_ALWAYS, + }, + [MfDictTypeSystem] = + { + .path = MF_CLASSIC_DICT_SYSTEM_PATH, + .open_mode = FSOM_OPEN_EXISTING, + }, + [MfDictTypeUnitTest] = + { + .path = MF_CLASSIC_DICT_UNIT_TEST_PATH, + .open_mode = FSOM_OPEN_ALWAYS, + }, +}; + bool mf_dict_check_presence(MfDictType dict_type) { + furi_assert(dict_type < MfDictTypeNum); + Storage* storage = furi_record_open(RECORD_STORAGE); - bool dict_present = false; - if(dict_type == MfDictTypeSystem) { - dict_present = storage_common_stat(storage, MF_CLASSIC_DICT_FLIPPER_PATH, NULL) == FSE_OK; - } else if(dict_type == MfDictTypeUser) { - dict_present = storage_common_stat(storage, MF_CLASSIC_DICT_USER_PATH, NULL) == FSE_OK; - } else if(dict_type == MfDictTypeUnitTest) { - dict_present = storage_common_stat(storage, MF_CLASSIC_DICT_UNIT_TEST_PATH, NULL) == - FSE_OK; - } + const char* path = mf_dict_file[dict_type].path; + bool dict_present = storage_common_stat(storage, path, NULL) == FSE_OK; furi_record_close(RECORD_STORAGE); @@ -37,6 +55,8 @@ bool mf_dict_check_presence(MfDictType dict_type) { } MfDict* mf_dict_alloc(MfDictType dict_type) { + furi_assert(dict_type < MfDictTypeNum); + MfDict* dict = malloc(sizeof(MfDict)); Storage* storage = furi_record_open(RECORD_STORAGE); dict->stream = buffered_file_stream_alloc(storage); @@ -44,30 +64,13 @@ MfDict* mf_dict_alloc(MfDictType dict_type) { bool dict_loaded = false; do { - if(dict_type == MfDictTypeSystem) { - if(!buffered_file_stream_open( - dict->stream, - MF_CLASSIC_DICT_FLIPPER_PATH, - FSAM_READ_WRITE, - FSOM_OPEN_EXISTING)) { - buffered_file_stream_close(dict->stream); - break; - } - } else if(dict_type == MfDictTypeUser) { - if(!buffered_file_stream_open( - dict->stream, MF_CLASSIC_DICT_USER_PATH, FSAM_READ_WRITE, FSOM_OPEN_ALWAYS)) { - buffered_file_stream_close(dict->stream); - break; - } - } else if(dict_type == MfDictTypeUnitTest) { - if(!buffered_file_stream_open( - dict->stream, - MF_CLASSIC_DICT_UNIT_TEST_PATH, - FSAM_READ_WRITE, - FSOM_OPEN_ALWAYS)) { - buffered_file_stream_close(dict->stream); - break; - } + if(!buffered_file_stream_open( + dict->stream, + mf_dict_file[dict_type].path, + FSAM_READ_WRITE, + mf_dict_file[dict_type].open_mode)) { + buffered_file_stream_close(dict->stream); + break; } // Check for new line ending @@ -124,7 +127,7 @@ void mf_dict_free(MfDict* dict) { free(dict); } -static void mf_dict_int_to_str(uint8_t* key_int, FuriString* key_str) { +static void mf_dict_int_to_str(const uint8_t* key_int, FuriString* key_str) { furi_string_reset(key_str); for(size_t i = 0; i < 6; i++) { furi_string_cat_printf(key_str, "%02X", key_int[i]); @@ -155,7 +158,7 @@ bool mf_dict_rewind(MfDict* dict) { return stream_rewind(dict->stream); } -bool mf_dict_get_next_key_str(MfDict* dict, FuriString* key) { +static bool mf_dict_get_next_key_str(MfDict* dict, FuriString* key) { furi_assert(dict); furi_assert(dict->stream); @@ -188,7 +191,7 @@ bool mf_dict_get_next_key(MfDict* dict, MfClassicKey* key) { return key_read; } -bool mf_dict_is_key_present_str(MfDict* dict, FuriString* key) { +static bool mf_dict_is_key_present_str(MfDict* dict, FuriString* key) { furi_assert(dict); furi_assert(dict->stream); @@ -210,17 +213,17 @@ bool mf_dict_is_key_present_str(MfDict* dict, FuriString* key) { return key_found; } -bool mf_dict_is_key_present(MfDict* dict, uint8_t* key) { +bool mf_dict_is_key_present(MfDict* dict, const MfClassicKey* key) { FuriString* temp_key; temp_key = furi_string_alloc(); - mf_dict_int_to_str(key, temp_key); + mf_dict_int_to_str(key->data, temp_key); bool key_found = mf_dict_is_key_present_str(dict, temp_key); furi_string_free(temp_key); return key_found; } -bool mf_dict_add_key_str(MfDict* dict, FuriString* key) { +static bool mf_dict_add_key_str(MfDict* dict, FuriString* key) { furi_assert(dict); furi_assert(dict->stream); @@ -238,113 +241,37 @@ bool mf_dict_add_key_str(MfDict* dict, FuriString* key) { return key_added; } -bool mf_dict_add_key(MfDict* dict, uint8_t* key) { +bool mf_dict_add_key(MfDict* dict, const MfClassicKey* key) { furi_assert(dict); furi_assert(dict->stream); FuriString* temp_key; temp_key = furi_string_alloc(); - mf_dict_int_to_str(key, temp_key); + mf_dict_int_to_str(key->data, temp_key); bool key_added = mf_dict_add_key_str(dict, temp_key); furi_string_free(temp_key); return key_added; } -bool mf_dict_get_key_at_index_str(MfDict* dict, FuriString* key, uint32_t target) { - furi_assert(dict); - furi_assert(dict->stream); - - FuriString* next_line; - uint32_t index = 0; - next_line = furi_string_alloc(); - furi_string_reset(key); - - bool key_found = false; - while(!key_found) { - if(!stream_read_line(dict->stream, next_line)) break; - if(furi_string_get_char(next_line, 0) == '#') continue; - if(furi_string_size(next_line) != NFC_MF_CLASSIC_KEY_LEN) continue; - if(index++ != target) continue; - furi_string_set_n(key, next_line, 0, 12); - key_found = true; - } - - furi_string_free(next_line); - return key_found; -} - -bool mf_dict_get_key_at_index(MfDict* dict, uint64_t* key, uint32_t target) { - furi_assert(dict); - furi_assert(dict->stream); - - FuriString* temp_key; - temp_key = furi_string_alloc(); - bool key_found = mf_dict_get_key_at_index_str(dict, temp_key, target); - if(key_found) { - mf_dict_str_to_int(temp_key, key); - } - furi_string_free(temp_key); - return key_found; -} - -bool mf_dict_find_index_str(MfDict* dict, FuriString* key, uint32_t* target) { +bool mf_dict_delete_key(MfDict* dict, const MfClassicKey* key) { furi_assert(dict); furi_assert(dict->stream); - FuriString* next_line; - next_line = furi_string_alloc(); - - bool key_found = false; - uint32_t index = 0; - stream_rewind(dict->stream); - while(!key_found) { //-V654 - if(!stream_read_line(dict->stream, next_line)) break; - if(furi_string_get_char(next_line, 0) == '#') continue; - if(furi_string_size(next_line) != NFC_MF_CLASSIC_KEY_LEN) continue; - furi_string_left(next_line, 12); - if(!furi_string_equal(key, next_line)) continue; - key_found = true; - *target = index; - } - - furi_string_free(next_line); - return key_found; -} - -bool mf_dict_find_index(MfDict* dict, uint8_t* key, uint32_t* target) { - furi_assert(dict); - furi_assert(dict->stream); - - FuriString* temp_key; - temp_key = furi_string_alloc(); - mf_dict_int_to_str(key, temp_key); - bool key_found = mf_dict_find_index_str(dict, temp_key, target); - - furi_string_free(temp_key); - return key_found; -} - -bool mf_dict_delete_index(MfDict* dict, uint32_t target) { - furi_assert(dict); - furi_assert(dict->stream); - - FuriString* next_line; - next_line = furi_string_alloc(); - uint32_t index = 0; - bool key_removed = false; + MfClassicKey temp_key = {}; + + mf_dict_rewind(dict); while(!key_removed) { - if(!stream_read_line(dict->stream, next_line)) break; - if(furi_string_get_char(next_line, 0) == '#') continue; - if(furi_string_size(next_line) != NFC_MF_CLASSIC_KEY_LEN) continue; - if(index++ != target) continue; - stream_seek(dict->stream, -NFC_MF_CLASSIC_KEY_LEN, StreamOffsetFromCurrent); - if(!stream_delete(dict->stream, NFC_MF_CLASSIC_KEY_LEN)) break; - dict->total_keys--; - key_removed = true; + if(!mf_dict_get_next_key(dict, &temp_key)) break; + if(memcmp(temp_key.data, key->data, sizeof(MfClassicKey)) == 0) { + stream_seek(dict->stream, -NFC_MF_CLASSIC_KEY_LEN, StreamOffsetFromCurrent); + if(!stream_delete(dict->stream, NFC_MF_CLASSIC_KEY_LEN)) break; + dict->total_keys--; + key_removed = true; + } } + mf_dict_rewind(dict); - furi_string_free(next_line); return key_removed; } diff --git a/applications/main/nfc/helpers/mf_dict.h b/applications/main/nfc/helpers/mf_dict.h index b1725f549262..33c6f32e7420 100644 --- a/applications/main/nfc/helpers/mf_dict.h +++ b/applications/main/nfc/helpers/mf_dict.h @@ -15,6 +15,8 @@ typedef enum { MfDictTypeUser, MfDictTypeSystem, MfDictTypeUnitTest, + + MfDictTypeNum, } MfDictType; typedef struct MfDict MfDict; @@ -51,57 +53,13 @@ uint32_t mf_dict_get_total_keys(MfDict* dict); */ bool mf_dict_rewind(MfDict* dict); -bool mf_dict_is_key_present(MfDict* dict, uint8_t* key); - -bool mf_dict_is_key_present_str(MfDict* dict, FuriString* key); +bool mf_dict_is_key_present(MfDict* dict, const MfClassicKey* key); bool mf_dict_get_next_key(MfDict* dict, MfClassicKey* key); -bool mf_dict_get_next_key_str(MfDict* dict, FuriString* key); - -/** Get key at target offset as uint64_t - * - * @param dict MfDict instance - * @param[out] key Pointer to the uint64_t key - * @param[in] target Target offset from current position - * - * @return true on success - */ -bool mf_dict_get_key_at_index(MfDict* dict, uint64_t* key, uint32_t target); - -/** Get key at target offset as string_t - * - * @param dict MfDict instance - * @param[out] key Found key destination buffer - * @param[in] target Target offset from current position - * - * @return true on success - */ -bool mf_dict_get_key_at_index_str(MfDict* dict, FuriString* key, uint32_t target); - -bool mf_dict_add_key(MfDict* dict, uint8_t* key); +bool mf_dict_add_key(MfDict* dict, const MfClassicKey* key); -/** Add string representation of the key - * - * @param dict MfDict instance - * @param[in] key String representation of the key - * - * @return true on success - */ -bool mf_dict_add_key_str(MfDict* dict, FuriString* key); - -bool mf_dict_find_index(MfDict* dict, uint8_t* key, uint32_t* target); - -bool mf_dict_find_index_str(MfDict* dict, FuriString* key, uint32_t* target); - -/** Delete key at target offset - * - * @param dict MfDict instance - * @param[in] target Target offset from current position - * - * @return true on success - */ -bool mf_dict_delete_index(MfDict* dict, uint32_t target); +bool mf_dict_delete_key(MfDict* dict, const MfClassicKey* key); #ifdef __cplusplus } diff --git a/applications/main/nfc/helpers/mf_user_dict.c b/applications/main/nfc/helpers/mf_user_dict.c new file mode 100644 index 000000000000..3fefe9274624 --- /dev/null +++ b/applications/main/nfc/helpers/mf_user_dict.c @@ -0,0 +1,74 @@ +#include "mf_user_dict.h" + +#include + +struct MfUserDict { + size_t keys_num; + MfClassicKey* keys_arr; +}; + +MfUserDict* mf_user_dict_alloc(size_t max_keys_to_load) { + MfUserDict* instance = malloc(sizeof(MfUserDict)); + + MfDict* dict = mf_dict_alloc(MfDictTypeUser); + furi_assert(dict); + + size_t dict_keys_num = mf_dict_get_total_keys(dict); + instance->keys_num = MIN(max_keys_to_load, dict_keys_num); + + if(instance->keys_num > 0) { + instance->keys_arr = malloc(instance->keys_num * sizeof(MfClassicKey)); + for(size_t i = 0; i < instance->keys_num; i++) { + bool key_loaded = mf_dict_get_next_key(dict, &instance->keys_arr[i]); + furi_assert(key_loaded); + } + } + mf_dict_free(dict); + + return instance; +} + +void mf_user_dict_free(MfUserDict* instance) { + furi_assert(instance); + + if(instance->keys_num > 0) { + free(instance->keys_arr); + } + free(instance); +} + +size_t mf_user_dict_get_keys_cnt(MfUserDict* instance) { + furi_assert(instance); + + return instance->keys_num; +} + +void mf_user_dict_get_key_str(MfUserDict* instance, uint32_t index, FuriString* str) { + furi_assert(instance); + furi_assert(str); + furi_assert(index < instance->keys_num); + furi_assert(instance->keys_arr); + + furi_string_reset(str); + for(size_t i = 0; i < sizeof(MfClassicKey); i++) { + furi_string_cat_printf(str, "%02X", instance->keys_arr[index].data[i]); + } +} + +bool mf_user_dict_delete_key(MfUserDict* instance, uint32_t index) { + furi_assert(instance); + furi_assert(index < instance->keys_num); + furi_assert(instance->keys_arr); + + MfDict* dict = mf_dict_alloc(MfDictTypeUser); + furi_assert(dict); + + bool key_delete_success = mf_dict_delete_key(dict, &instance->keys_arr[index]); + mf_dict_free(dict); + + if(key_delete_success) { + instance->keys_num--; + } + + return key_delete_success; +} diff --git a/applications/main/nfc/helpers/mf_user_dict.h b/applications/main/nfc/helpers/mf_user_dict.h new file mode 100644 index 000000000000..74a9a40ff899 --- /dev/null +++ b/applications/main/nfc/helpers/mf_user_dict.h @@ -0,0 +1,23 @@ +#pragma once + +#include "mf_dict.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct MfUserDict MfUserDict; + +MfUserDict* mf_user_dict_alloc(size_t max_keys_to_load); + +void mf_user_dict_free(MfUserDict* instance); + +size_t mf_user_dict_get_keys_cnt(MfUserDict* instance); + +void mf_user_dict_get_key_str(MfUserDict* instance, uint32_t index, FuriString* str); + +bool mf_user_dict_delete_key(MfUserDict* instance, uint32_t index); + +#ifdef __cplusplus +} +#endif diff --git a/applications/main/nfc/helpers/nfc_custom_event.h b/applications/main/nfc/helpers/nfc_custom_event.h index fb94cb334d69..93c39d4b51cd 100644 --- a/applications/main/nfc/helpers/nfc_custom_event.h +++ b/applications/main/nfc/helpers/nfc_custom_event.h @@ -7,23 +7,20 @@ typedef enum { // Mf classic dict attack events NfcCustomEventDictAttackComplete, NfcCustomEventDictAttackSkip, - NfcCustomEventDictAttackCardDetected, - NfcCustomEventDictAttackCardNotDetected, - NfcCustomEventDictAttackFoundKeyA, - NfcCustomEventDictAttackFoundKeyB, - NfcCustomEventDictAttackNewSector, - NfcCustomEventDictAttackNewKeyBatch, - NfcCustomEventDictAttackKeyAttackStart, - NfcCustomEventDictAttackKeyAttackStop, - NfcCustomEventDictAttackKeyAttackNextSector, + NfcCustomEventDictAttackDataUpdate, + + NfcCustomEventCardDetected, + NfcCustomEventCardLost, NfcCustomEventViewExit, NfcCustomEventWorkerExit, NfcCustomEventWorkerUpdate, + NfcCustomEventWrongCard, NfcCustomEventTimerExpired, NfcCustomEventByteInputDone, NfcCustomEventTextInputDone, NfcCustomEventDictAttackDone, + NfcCustomEventRpcLoad, NfcCustomEventRpcSessionClose, diff --git a/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c b/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c index f25432f13fa1..feef09e5340c 100644 --- a/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c +++ b/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c @@ -7,6 +7,8 @@ #include "../nfc_protocol_support_gui_common.h" +#define TAG "MfClassicApp" + enum { SubmenuIndexDetectReader = SubmenuIndexCommonMax, SubmenuIndexWrite, @@ -39,27 +41,70 @@ static NfcCommand nfc_scene_read_poller_callback_mf_classic(NfcGenericEvent even furi_assert(event.protocol == NfcProtocolMfClassic); NfcApp* instance = context; - const MfClassicPollerEvent* mf_classic_event = event.data; - - // TODO: Implement read mf_classic using key cache - if(mf_classic_event->type == MfClassicPollerEventTypeReadComplete) { - const MfClassicData* mf_classic_data = nfc_poller_get_data(instance->poller); - nfc_device_set_data(instance->nfc_device, NfcProtocolMfClassic, mf_classic_data); - - const NfcCustomEvent custom_event = mf_classic_is_card_read(mf_classic_data) ? - NfcCustomEventPollerSuccess : - NfcCustomEventPollerIncomplete; + const MfClassicPollerEvent* mfc_event = event.data; + NfcCommand command = NfcCommandContinue; + + if(mfc_event->type == MfClassicPollerEventTypeRequestMode) { + nfc_device_set_data( + instance->nfc_device, NfcProtocolMfClassic, nfc_poller_get_data(instance->poller)); + size_t uid_len = 0; + const uint8_t* uid = nfc_device_get_uid(instance->nfc_device, &uid_len); + if(mf_classic_key_cache_load(instance->mfc_key_cache, uid, uid_len)) { + FURI_LOG_I(TAG, "Key cache found"); + mfc_event->data->poller_mode.mode = MfClassicPollerModeRead; + } else { + FURI_LOG_I(TAG, "Key cache not found"); + view_dispatcher_send_custom_event( + instance->view_dispatcher, NfcCustomEventPollerIncomplete); + command = NfcCommandStop; + } + } else if(mfc_event->type == MfClassicPollerEventTypeRequestReadSector) { + uint8_t sector_num = 0; + MfClassicKey key = {}; + MfClassicKeyType key_type = MfClassicKeyTypeA; + if(mf_classic_key_cahce_get_next_key( + instance->mfc_key_cache, §or_num, &key, &key_type)) { + mfc_event->data->read_sector_request_data.sector_num = sector_num; + mfc_event->data->read_sector_request_data.key = key; + mfc_event->data->read_sector_request_data.key_type = key_type; + mfc_event->data->read_sector_request_data.key_provided = true; + } else { + mfc_event->data->read_sector_request_data.key_provided = false; + } + } else if(mfc_event->type == MfClassicPollerEventTypeSuccess) { + nfc_device_set_data( + instance->nfc_device, NfcProtocolMfClassic, nfc_poller_get_data(instance->poller)); + const MfClassicData* mfc_data = + nfc_device_get_data(instance->nfc_device, NfcProtocolMfClassic); + NfcCustomEvent custom_event = mf_classic_is_card_read(mfc_data) ? + NfcCustomEventPollerSuccess : + NfcCustomEventPollerIncomplete; view_dispatcher_send_custom_event(instance->view_dispatcher, custom_event); - return NfcCommandStop; + command = NfcCommandStop; } - return NfcCommandContinue; + return command; } static void nfc_scene_read_on_enter_mf_classic(NfcApp* instance) { + mf_classic_key_cache_reset(instance->mfc_key_cache); nfc_poller_start(instance->poller, nfc_scene_read_poller_callback_mf_classic, instance); } +static bool nfc_scene_read_on_event_mf_classic(NfcApp* instance, uint32_t event) { + if(event == NfcCustomEventPollerIncomplete) { + const MfClassicData* mfc_data = nfc_poller_get_data(instance->poller); + if(mf_classic_is_card_read(mfc_data)) { + view_dispatcher_send_custom_event( + instance->view_dispatcher, NfcCustomEventPollerSuccess); + } else { + scene_manager_next_scene(instance->scene_manager, NfcSceneMfClassicDictAttack); + } + } + + return true; +} + static void nfc_scene_read_menu_on_enter_mf_classic(NfcApp* instance) { Submenu* submenu = instance->submenu; const MfClassicData* data = nfc_device_get_data(instance->nfc_device, NfcProtocolMfClassic); @@ -144,13 +189,13 @@ static bool nfc_scene_saved_menu_on_event_mf_classic(NfcApp* instance, uint32_t bool consumed = false; if(event == SubmenuIndexDetectReader) { - scene_manager_next_scene(instance->scene_manager, NfcSceneNotImplemented); + scene_manager_next_scene(instance->scene_manager, NfcSceneMfClassicDetectReader); consumed = true; } else if(event == SubmenuIndexWrite) { - scene_manager_next_scene(instance->scene_manager, NfcSceneNotImplemented); + scene_manager_next_scene(instance->scene_manager, NfcSceneMfClassicWriteInitial); consumed = true; } else if(event == SubmenuIndexUpdate) { - scene_manager_next_scene(instance->scene_manager, NfcSceneNotImplemented); + scene_manager_next_scene(instance->scene_manager, NfcSceneMfClassicUpdateInitial); consumed = true; } @@ -168,7 +213,7 @@ const NfcProtocolSupportBase nfc_protocol_support_mf_classic = { .scene_read = { .on_enter = nfc_scene_read_on_enter_mf_classic, - .on_event = NULL, + .on_event = nfc_scene_read_on_event_mf_classic, }, .scene_read_menu = { @@ -185,7 +230,9 @@ const NfcProtocolSupportBase nfc_protocol_support_mf_classic = { .on_enter = nfc_scene_saved_menu_on_enter_mf_classic, .on_event = nfc_scene_saved_menu_on_event_mf_classic, }, - .scene_emulate = { - .on_enter = nfc_scene_emulate_on_enter_mf_classic, - .on_event = NULL, - }}; + .scene_emulate = + { + .on_enter = nfc_scene_emulate_on_enter_mf_classic, + .on_event = NULL, + }, +}; diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c index 2175404074e1..866e7d2ef586 100644 --- a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c @@ -127,11 +127,20 @@ static bool nfc_protocol_support_scene_read_on_event(NfcApp* instance, SceneMana dolphin_deed(DolphinDeedNfcReadSuccess); consumed = true; } else if(event.event == NfcCustomEventPollerIncomplete) { - nfc_supported_cards_read(instance->nfc_device, instance->nfc); - - view_dispatcher_send_custom_event( - instance->view_dispatcher, NfcCustomEventPollerSuccess); - consumed = true; + bool card_read = nfc_supported_cards_read(instance->nfc_device, instance->nfc); + if(card_read) { + notification_message(instance->notifications, &sequence_success); + scene_manager_next_scene(instance->scene_manager, NfcSceneReadSuccess); + dolphin_deed(DolphinDeedNfcReadSuccess); + consumed = true; + } else { + const NfcProtocol protocol = + instance->protocols_detected[instance->protocols_detected_idx]; + if(nfc_protocol_support[protocol]->scene_read.on_event) { + consumed = + nfc_protocol_support[protocol]->scene_read.on_event(instance, event.event); + } + } } else if(event.event == NfcCustomEventPollerFailure) { if(scene_manager_has_previous_scene(instance->scene_manager, NfcSceneDetect)) { scene_manager_search_and_switch_to_previous_scene( diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_base.h b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_base.h index 5b5d74aff122..f152b99f49b0 100644 --- a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_base.h +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_base.h @@ -26,4 +26,5 @@ typedef struct { NfcProtocolSupportSceneBase scene_read_success; NfcProtocolSupportSceneBase scene_saved_menu; NfcProtocolSupportSceneBase scene_emulate; + // TODO Add scene save to save mf classic key cache } NfcProtocolSupportBase; diff --git a/applications/main/nfc/nfc_app.c b/applications/main/nfc/nfc_app.c index 4240e61f277e..f37d42a64820 100644 --- a/applications/main/nfc/nfc_app.c +++ b/applications/main/nfc/nfc_app.c @@ -48,6 +48,7 @@ NfcApp* nfc_app_alloc() { instance->nfc = nfc_alloc(); instance->mf_ul_auth = mf_ultralight_auth_alloc(); + instance->mfc_key_cache = mf_classic_key_cache_alloc(); // Nfc device instance->nfc_device = nfc_device_alloc(); @@ -107,6 +108,7 @@ NfcApp* nfc_app_alloc() { instance->view_dispatcher, NfcViewWidget, widget_get_view(instance->widget)); // Dict attack + instance->dict_attack = dict_attack_alloc(); view_dispatcher_add_view( instance->view_dispatcher, NfcViewDictAttack, dict_attack_get_view(instance->dict_attack)); @@ -148,6 +150,7 @@ void nfc_app_free(NfcApp* instance) { nfc_free(instance->nfc); mf_ultralight_auth_free(instance->mf_ul_auth); + mf_classic_key_cache_free(instance->mfc_key_cache); // Nfc device nfc_device_free(instance->nfc_device); @@ -244,7 +247,7 @@ void nfc_blink_stop(NfcApp* nfc) { notification_message(nfc->notifications, &sequence_blink_stop); } -void nfc_make_app_folder(NfcApp* instance) { +void nfc_make_app_folders(NfcApp* instance) { furi_assert(instance); if(!storage_simply_mkdir(instance->storage, NFC_APP_FOLDER)) { @@ -262,6 +265,13 @@ bool nfc_save_file(NfcApp* instance, FuriString* path) { dialog_message_show_storage_error(instance->dialogs, "Cannot save\nkey file"); } + // TODO move this to protocol support save scene + if(nfc_device_get_protocol(instance->nfc_device) == NfcProtocolMfClassic) { + mf_classic_key_cache_save( + instance->mfc_key_cache, + nfc_device_get_data(instance->nfc_device, NfcProtocolMfClassic)); + } + return result; } @@ -313,9 +323,10 @@ static bool nfc_save_internal(NfcApp* instance, const char* extension) { bool result = false; - nfc_make_app_folder(instance); + nfc_make_app_folders(instance); - if(furi_string_end_with(instance->file_path, NFC_APP_EXTENSION)) { + if(furi_string_end_with(instance->file_path, NFC_APP_EXTENSION) || + (furi_string_end_with(instance->file_path, NFC_APP_SHADOW_EXTENSION))) { size_t filename_start = furi_string_search_rchar(instance->file_path, '/'); furi_string_left(instance->file_path, filename_start); } diff --git a/applications/main/nfc/nfc_app_i.h b/applications/main/nfc/nfc_app_i.h index 2a7002e60630..90666f317161 100644 --- a/applications/main/nfc/nfc_app_i.h +++ b/applications/main/nfc/nfc_app_i.h @@ -23,12 +23,15 @@ #include #include "views/dict_attack.h" #include "views/detect_reader.h" +#include "views/dict_attack.h" #include #include "helpers/nfc_custom_event.h" #include "helpers/mf_ultralight_auth.h" #include "helpers/mf_dict.h" #include "helpers/mfkey32_logger.h" +#include "helpers/mf_user_dict.h" +#include "helpers/mf_classic_key_cache.h" #include #include @@ -61,7 +64,7 @@ #define NFC_APP_SHADOW_EXTENSION ".shd" #define NFC_APP_MFKEY32_LOGS_FILE_NAME ".mfkey32.log" -#define NFC_APP_MFKEY32_LOGS_FILE_PATH NFC_APP_FOLDER "/" NFC_APP_MFKEY32_LOGS_FILE_NAME +#define NFC_APP_MFKEY32_LOGS_FILE_PATH (NFC_APP_FOLDER "/" NFC_APP_MFKEY32_LOGS_FILE_NAME) typedef enum { NfcRpcStateIdle, @@ -71,10 +74,14 @@ typedef enum { typedef struct { MfDict* dict; - uint32_t total_keys; - uint32_t current_key; + uint8_t sectors_total; + uint8_t sectors_read; uint8_t current_sector; - MfClassicType type; + uint8_t keys_found; + size_t dict_keys_total; + size_t dict_keys_current; + bool is_key_attack; + uint8_t key_attack_current_sector; } NfcMfClassicDictAttackContext; struct NfcApp { @@ -105,8 +112,8 @@ struct NfcApp { ByteInput* byte_input; TextBox* text_box; Widget* widget; - DictAttack* dict_attack; DetectReader* detect_reader; + DictAttack* dict_attack; Nfc* nfc; NfcPoller* poller; @@ -116,6 +123,8 @@ struct NfcApp { MfUltralightAuth* mf_ul_auth; NfcMfClassicDictAttackContext mf_dict_context; Mfkey32Logger* mfkey32_logger; + MfUserDict* mf_user_dict; + MfClassicKeyCache* mfc_key_cache; NfcDevice* nfc_device; Iso14443_3aData* iso14443_3a_edit_data; diff --git a/applications/main/nfc/plugins/supported_cards/plantain.c b/applications/main/nfc/plugins/supported_cards/plantain.c new file mode 100644 index 000000000000..25f53e2ece23 --- /dev/null +++ b/applications/main/nfc/plugins/supported_cards/plantain.c @@ -0,0 +1,216 @@ +#include "nfc_supported_card_plugin.h" + +#include + +#include +#include +#include + +#define TAG "Plantain" + +typedef struct { + uint64_t a; + uint64_t b; +} MfClassicKeyPair; + +typedef struct { + const MfClassicKeyPair* keys; + uint32_t data_sector; +} PlantainCardConfig; + +static const MfClassicKeyPair plantain_1k_keys[] = { + {.a = 0xffffffffffff, .b = 0xffffffffffff}, + {.a = 0xffffffffffff, .b = 0xffffffffffff}, + {.a = 0xffffffffffff, .b = 0xffffffffffff}, + {.a = 0xffffffffffff, .b = 0xffffffffffff}, + {.a = 0xe56ac127dd45, .b = 0x19fc84a3784b}, + {.a = 0x77dabc9825e1, .b = 0x9764fec3154a}, + {.a = 0xffffffffffff, .b = 0xffffffffffff}, + {.a = 0xffffffffffff, .b = 0xffffffffffff}, + {.a = 0x26973ea74321, .b = 0xd27058c6e2c7}, + {.a = 0xeb0a8ff88ade, .b = 0x578a9ada41e3}, + {.a = 0xea0fd73cb149, .b = 0x29c35fa068fb}, + {.a = 0xc76bf71a2509, .b = 0x9ba241db3f56}, + {.a = 0xacffffffffff, .b = 0x71f3a315ad26}, + {.a = 0xffffffffffff, .b = 0xffffffffffff}, + {.a = 0xffffffffffff, .b = 0xffffffffffff}, + {.a = 0xffffffffffff, .b = 0xffffffffffff}, +}; + +static const MfClassicKeyPair plantain_4k_keys[] = { + {.a = 0xffffffffffff, .b = 0xffffffffffff}, {.a = 0xffffffffffff, .b = 0xffffffffffff}, + {.a = 0xffffffffffff, .b = 0xffffffffffff}, {.a = 0xffffffffffff, .b = 0xffffffffffff}, + {.a = 0xe56ac127dd45, .b = 0x19fc84a3784b}, {.a = 0x77dabc9825e1, .b = 0x9764fec3154a}, + {.a = 0xffffffffffff, .b = 0xffffffffffff}, {.a = 0xffffffffffff, .b = 0xffffffffffff}, + {.a = 0x26973ea74321, .b = 0xd27058c6e2c7}, {.a = 0xeb0a8ff88ade, .b = 0x578a9ada41e3}, + {.a = 0xea0fd73cb149, .b = 0x29c35fa068fb}, {.a = 0xc76bf71a2509, .b = 0x9ba241db3f56}, + {.a = 0xacffffffffff, .b = 0x71f3a315ad26}, {.a = 0xffffffffffff, .b = 0xffffffffffff}, + {.a = 0xffffffffffff, .b = 0xffffffffffff}, {.a = 0xffffffffffff, .b = 0xffffffffffff}, + {.a = 0x72f96bdd3714, .b = 0x462225cd34cf}, {.a = 0x044ce1872bc3, .b = 0x8c90c70cff4a}, + {.a = 0xbc2d1791dec1, .b = 0xca96a487de0b}, {.a = 0x8791b2ccb5c4, .b = 0xc956c3b80da3}, + {.a = 0x8e26e45e7d65, .b = 0x8e65b3af7d22}, {.a = 0x0f318130ed18, .b = 0x0c420a20e056}, + {.a = 0x045ceca15535, .b = 0x31bec3d9e510}, {.a = 0x9d993c5d4ef4, .b = 0x86120e488abf}, + {.a = 0xc65d4eaa645b, .b = 0xb69d40d1a439}, {.a = 0x3a8a139c20b4, .b = 0x8818a9c5d406}, + {.a = 0xbaff3053b496, .b = 0x4b7cb25354d3}, {.a = 0x7413b599c4ea, .b = 0xb0a2AAF3A1BA}, + {.a = 0x0ce7cd2cc72b, .b = 0xfa1fbb3f0f1f}, {.a = 0x0be5fac8b06a, .b = 0x6f95887a4fd3}, + {.a = 0x0eb23cc8110b, .b = 0x04dc35277635}, {.a = 0xbc4580b7f20b, .b = 0xd0a4131fb290}, + {.a = 0x7a396f0d633d, .b = 0xad2bdc097023}, {.a = 0xa3faa6daff67, .b = 0x7600e889adf9}, + {.a = 0xfd8705e721b0, .b = 0x296fc317a513}, {.a = 0x22052b480d11, .b = 0xe19504c39461}, + {.a = 0xa7141147d430, .b = 0xff16014fefc7}, {.a = 0x8a8d88151a00, .b = 0x038b5f9b5a2a}, + {.a = 0xb27addfb64b0, .b = 0x152fd0c420a7}, {.a = 0x7259fa0197c6, .b = 0x5583698df085}, +}; + +static bool plantain_get_card_config(PlantainCardConfig* config, MfClassicType type) { + bool success = true; + + if(type == MfClassicType1k) { + config->data_sector = 8; + config->keys = plantain_1k_keys; + } else if(type == MfClassicType4k) { + config->data_sector = 8; + config->keys = plantain_4k_keys; + } else { + success = false; + } + + return success; +} + +static bool plantain_verify_type(Nfc* nfc, MfClassicType type) { + bool verified = false; + + do { + PlantainCardConfig cfg = {}; + if(!plantain_get_card_config(&cfg, type)) break; + + const uint8_t block_num = mf_classic_get_first_block_num_of_sector(cfg.data_sector); + FURI_LOG_D(TAG, "Verifying sector %lu", cfg.data_sector); + + MfClassicKey key = {0}; + nfc_util_num2bytes(cfg.keys[cfg.data_sector].a, COUNT_OF(key.data), key.data); + + MfClassicAuthContext auth_context; + MfClassicError error = + mf_classic_poller_auth(nfc, block_num, &key, MfClassicKeyTypeA, &auth_context); + if(error != MfClassicErrorNone) { + FURI_LOG_D(TAG, "Failed to read block %u: %d", block_num, error); + break; + } + + verified = true; + } while(false); + + return verified; +} + +static bool plantain_verify(Nfc* nfc) { + return plantain_verify_type(nfc, MfClassicType1k) || + plantain_verify_type(nfc, MfClassicType4k); +} + +static bool plantain_read(Nfc* nfc, NfcDevice* device) { + furi_assert(nfc); + furi_assert(device); + + bool is_read = false; + + MfClassicData* data = mf_classic_alloc(); + nfc_device_copy_data(device, NfcProtocolMfClassic, data); + + do { + if(!mf_classic_detect_protocol(data->iso14443_3a_data, &data->type)) break; + + PlantainCardConfig cfg = {}; + if(!plantain_get_card_config(&cfg, data->type)) break; + + MfClassicDeviceKeys keys = {}; + for(size_t i = 0; i < mf_classic_get_total_sectors_num(data->type); i++) { + nfc_util_num2bytes(cfg.keys[i].a, sizeof(MfClassicKey), keys.key_a[i].data); + nfc_util_num2bytes(cfg.keys[i].b, sizeof(MfClassicKey), keys.key_b[i].data); + } + keys.key_a_mask = 0xFFFFFFFFFFFFFFFFU; + keys.key_b_mask = 0xFFFFFFFFFFFFFFFFU; + + MfClassicError error = mf_classic_poller_read(nfc, &keys, data); + if(error != MfClassicErrorNone) { + FURI_LOG_W(TAG, "Failed to read data"); + break; + } + + nfc_device_set_data(device, NfcProtocolMfClassic, data); + + is_read = true; + } while(false); + + mf_classic_free(data); + + return is_read; +} + +static bool plantain_parse(const NfcDevice* device, FuriString* parsed_data) { + furi_assert(device); + + const MfClassicData* data = nfc_device_get_data(device, NfcProtocolMfClassic); + + bool parsed = false; + + do { + // Verify card type + PlantainCardConfig cfg = {}; + if(!plantain_get_card_config(&cfg, data->type)) break; + + // Verify key + const MfClassicSectorTrailer* sec_tr = + mf_classic_get_sector_trailer_by_sector(data, cfg.data_sector); + + const uint64_t key = nfc_util_bytes2num(sec_tr->key_a.data, COUNT_OF(sec_tr->key_a.data)); + if(key != cfg.keys[cfg.data_sector].a) break; + + // Point to block 0 of sector 4, value 0 + const uint8_t* temp_ptr = data->block[16].data; + // Read first 4 bytes of block 0 of sector 4 from last to first and convert them to uint32_t + // 38 18 00 00 becomes 00 00 18 38, and equals to 6200 decimal + uint32_t balance = + ((temp_ptr[3] << 24) | (temp_ptr[2] << 16) | (temp_ptr[1] << 8) | temp_ptr[0]) / 100; + // Read card number + // Point to block 0 of sector 0, value 0 + temp_ptr = data->block[0].data; + // Read first 7 bytes of block 0 of sector 0 from last to first and convert them to uint64_t + // 04 31 16 8A 23 5C 80 becomes 80 5C 23 8A 16 31 04, and equals to 36130104729284868 decimal + uint8_t card_number_arr[7]; + for(size_t i = 0; i < 7; i++) { + card_number_arr[i] = temp_ptr[6 - i]; + } + // Copy card number to uint64_t + uint64_t card_number = 0; + for(size_t i = 0; i < 7; i++) { + card_number = (card_number << 8) | card_number_arr[i]; + } + + furi_string_printf( + parsed_data, "\e#Plantain\nN:%llu-\nBalance:%lu\n", card_number, balance); + parsed = true; + } while(false); + + return parsed; +} + +/* Actual implementation of app<>plugin interface */ +static const NfcSupportedCardsPlugin plantain_plugin = { + .protocol = NfcProtocolMfClassic, + .verify = plantain_verify, + .read = plantain_read, + .parse = plantain_parse, +}; + +/* Plugin descriptor to comply with basic plugin specification */ +static const FlipperAppPluginDescriptor plantain_plugin_descriptor = { + .appid = NFC_SUPPORTED_CARD_PLUGIN_APP_ID, + .ep_api_version = NFC_SUPPORTED_CARD_PLUGIN_API_VERSION, + .entry_point = &plantain_plugin, +}; + +/* Plugin entry point - must return a pointer to const descriptor */ +const FlipperAppPluginDescriptor* plantain_plugin_ep() { + return &plantain_plugin_descriptor; +} diff --git a/applications/main/nfc/plugins/supported_cards/troika.c b/applications/main/nfc/plugins/supported_cards/troika.c index 3b7cd60b0f95..a1134ff6225c 100644 --- a/applications/main/nfc/plugins/supported_cards/troika.c +++ b/applications/main/nfc/plugins/supported_cards/troika.c @@ -80,7 +80,7 @@ static bool troika_verify_type(Nfc* nfc, MfClassicType type) { bool verified = false; do { - TroikaCardConfig cfg; + TroikaCardConfig cfg = {}; if(!troika_get_card_config(&cfg, type)) break; const uint8_t block_num = mf_classic_get_first_block_num_of_sector(cfg.data_sector); @@ -119,34 +119,23 @@ static bool troika_read(Nfc* nfc, NfcDevice* device) { do { if(!mf_classic_detect_protocol(data->iso14443_3a_data, &data->type)) break; - TroikaCardConfig cfg; + TroikaCardConfig cfg = {}; if(!troika_get_card_config(&cfg, data->type)) break; - MfClassicKey key = {0}; - nfc_util_num2bytes(cfg.keys[cfg.data_sector].a, COUNT_OF(key.data), key.data); - - const uint8_t block_num_start = mf_classic_get_first_block_num_of_sector(cfg.data_sector); - const uint8_t block_num_end = block_num_start + 2; - - uint8_t block_num; - for(block_num = block_num_start; block_num < block_num_end; ++block_num) { - MfClassicBlock block; - MfClassicError error; - - error = mf_classic_poller_read_block(nfc, block_num, &key, MfClassicKeyTypeA, &block); - - if(error != MfClassicErrorNone) { - FURI_LOG_D(TAG, "Failed to read block %u: %d", block_num, error); - break; - } - - mf_classic_set_block_read(data, block_num, &block); + MfClassicDeviceKeys keys = {}; + for(size_t i = 0; i < mf_classic_get_total_sectors_num(data->type); i++) { + nfc_util_num2bytes(cfg.keys[i].a, sizeof(MfClassicKey), keys.key_a[i].data); + nfc_util_num2bytes(cfg.keys[i].b, sizeof(MfClassicKey), keys.key_b[i].data); } + keys.key_a_mask = 0xFFFFFFFFFFFFFFFFU; + keys.key_b_mask = 0xFFFFFFFFFFFFFFFFU; - if(block_num != block_num_end) break; + MfClassicError error = mf_classic_poller_read(nfc, &keys, data); + if(error != MfClassicErrorNone) { + FURI_LOG_W(TAG, "Failed to read data"); + break; + } - mf_classic_set_key_found( - data, cfg.data_sector, MfClassicKeyTypeA, cfg.keys[cfg.data_sector].a); nfc_device_set_data(device, NfcProtocolMfClassic, data); is_read = true; @@ -166,7 +155,7 @@ static bool troika_parse(const NfcDevice* device, FuriString* parsed_data) { do { // Verify card type - TroikaCardConfig cfg; + TroikaCardConfig cfg = {}; if(!troika_get_card_config(&cfg, data->type)) break; // Verify key diff --git a/applications/main/nfc/plugins/supported_cards/two_cities.c b/applications/main/nfc/plugins/supported_cards/two_cities.c new file mode 100644 index 000000000000..530d62ad9570 --- /dev/null +++ b/applications/main/nfc/plugins/supported_cards/two_cities.c @@ -0,0 +1,185 @@ +#include "nfc_supported_card_plugin.h" + +#include + +#include +#include +#include + +#define TAG "TwoCities" + +typedef struct { + uint64_t a; + uint64_t b; +} MfClassicKeyPair; + +static const MfClassicKeyPair two_cities_4k_keys[] = { + {.a = 0xffffffffffff, .b = 0xffffffffffff}, {.a = 0xffffffffffff, .b = 0xffffffffffff}, + {.a = 0x2aa05ed1856f, .b = 0xeaac88e5dc99}, {.a = 0x2aa05ed1856f, .b = 0xeaac88e5dc99}, + {.a = 0xe56ac127dd45, .b = 0x19fc84a3784b}, {.a = 0x77dabc9825e1, .b = 0x9764fec3154a}, + {.a = 0x2aa05ed1856f, .b = 0xeaac88e5dc99}, {.a = 0xffffffffffff, .b = 0xffffffffffff}, + {.a = 0xa73f5dc1d333, .b = 0xe35173494a81}, {.a = 0x69a32f1c2f19, .b = 0x6b8bd9860763}, + {.a = 0xea0fd73cb149, .b = 0x29c35fa068fb}, {.a = 0xc76bf71a2509, .b = 0x9ba241db3f56}, + {.a = 0xacffffffffff, .b = 0x71f3a315ad26}, {.a = 0xffffffffffff, .b = 0xffffffffffff}, + {.a = 0xffffffffffff, .b = 0xffffffffffff}, {.a = 0x2aa05ed1856f, .b = 0xeaac88e5dc99}, + {.a = 0x72f96bdd3714, .b = 0x462225cd34cf}, {.a = 0x044ce1872bc3, .b = 0x8c90c70cff4a}, + {.a = 0xbc2d1791dec1, .b = 0xca96a487de0b}, {.a = 0x8791b2ccb5c4, .b = 0xc956c3b80da3}, + {.a = 0x8e26e45e7d65, .b = 0x8e65b3af7d22}, {.a = 0x0f318130ed18, .b = 0x0c420a20e056}, + {.a = 0x045ceca15535, .b = 0x31bec3d9e510}, {.a = 0x9d993c5d4ef4, .b = 0x86120e488abf}, + {.a = 0xc65d4eaa645b, .b = 0xb69d40d1a439}, {.a = 0x3a8a139c20b4, .b = 0x8818a9c5d406}, + {.a = 0xbaff3053b496, .b = 0x4b7cb25354d3}, {.a = 0x7413b599c4ea, .b = 0xb0a2AAF3A1BA}, + {.a = 0x0ce7cd2cc72b, .b = 0xfa1fbb3f0f1f}, {.a = 0x0be5fac8b06a, .b = 0x6f95887a4fd3}, + {.a = 0x26973ea74321, .b = 0xd27058c6e2c7}, {.a = 0xeb0a8ff88ade, .b = 0x578a9ada41e3}, + {.a = 0x7a396f0d633d, .b = 0xad2bdc097023}, {.a = 0xa3faa6daff67, .b = 0x7600e889adf9}, + {.a = 0x2aa05ed1856f, .b = 0xeaac88e5dc99}, {.a = 0x2aa05ed1856f, .b = 0xeaac88e5dc99}, + {.a = 0xa7141147d430, .b = 0xff16014fefc7}, {.a = 0x8a8d88151a00, .b = 0x038b5f9b5a2a}, + {.a = 0xb27addfb64b0, .b = 0x152fd0c420a7}, {.a = 0x7259fa0197c6, .b = 0x5583698df085}, +}; + +bool two_cities_verify(Nfc* nfc) { + bool verified = false; + + do { + const uint8_t verify_sector = 4; + uint8_t block_num = mf_classic_get_first_block_num_of_sector(verify_sector); + FURI_LOG_D(TAG, "Verifying sector %u", verify_sector); + + MfClassicKey key = {}; + nfc_util_num2bytes(two_cities_4k_keys[verify_sector].a, COUNT_OF(key.data), key.data); + + MfClassicError error = + mf_classic_poller_auth(nfc, block_num, &key, MfClassicKeyTypeA, NULL); + if(error != MfClassicErrorNone) { + FURI_LOG_D(TAG, "Failed to read block %u: %d", block_num, error); + break; + } + + verified = true; + } while(false); + + return verified; +} + +static bool two_cities_read(Nfc* nfc, NfcDevice* device) { + furi_assert(nfc); + furi_assert(device); + + bool is_read = false; + + MfClassicData* data = mf_classic_alloc(); + nfc_device_copy_data(device, NfcProtocolMfClassic, data); + + do { + if(!mf_classic_detect_protocol(data->iso14443_3a_data, &data->type)) break; + + MfClassicDeviceKeys keys = {}; + for(size_t i = 0; i < mf_classic_get_total_sectors_num(data->type); i++) { + nfc_util_num2bytes(two_cities_4k_keys[i].a, sizeof(MfClassicKey), keys.key_a[i].data); + nfc_util_num2bytes(two_cities_4k_keys[i].b, sizeof(MfClassicKey), keys.key_b[i].data); + } + keys.key_a_mask = 0xFFFFFFFFFFFFFFFFU; + keys.key_b_mask = 0xFFFFFFFFFFFFFFFFU; + + MfClassicError error = mf_classic_poller_read(nfc, &keys, data); + if(error != MfClassicErrorNone) { + FURI_LOG_W(TAG, "Failed to read data"); + break; + } + + nfc_device_set_data(device, NfcProtocolMfClassic, data); + + is_read = true; + } while(false); + + mf_classic_free(data); + + return is_read; +} + +static bool two_cities_parse(const NfcDevice* device, FuriString* parsed_data) { + furi_assert(device); + + const MfClassicData* data = nfc_device_get_data(device, NfcProtocolMfClassic); + + bool parsed = false; + + do { + // Verify key + MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(data, 4); + uint64_t key = nfc_util_bytes2num(sec_tr->key_a.data, 6); + if(key != two_cities_4k_keys[4].a) return false; + + // ===== + // PLANTAIN + // ===== + + // Point to block 0 of sector 4, value 0 + const uint8_t* temp_ptr = data->block[16].data; + // Read first 4 bytes of block 0 of sector 4 from last to first and convert them to uint32_t + // 38 18 00 00 becomes 00 00 18 38, and equals to 6200 decimal + uint32_t balance = + ((temp_ptr[3] << 24) | (temp_ptr[2] << 16) | (temp_ptr[1] << 8) | temp_ptr[0]) / 100; + // Read card number + // Point to block 0 of sector 0, value 0 + temp_ptr = data->block[0].data; + // Read first 7 bytes of block 0 of sector 0 from last to first and convert them to uint64_t + // 04 31 16 8A 23 5C 80 becomes 80 5C 23 8A 16 31 04, and equals to 36130104729284868 decimal + uint8_t card_number_arr[7]; + for(size_t i = 0; i < 7; i++) { + card_number_arr[i] = temp_ptr[6 - i]; + } + // Copy card number to uint64_t + uint64_t card_number = 0; + for(size_t i = 0; i < 7; i++) { + card_number = (card_number << 8) | card_number_arr[i]; + } + + // ===== + // --PLANTAIN-- + // ===== + // TROIKA + // ===== + + const uint8_t* troika_temp_ptr = &data->block[33].data[5]; + uint16_t troika_balance = ((troika_temp_ptr[0] << 8) | troika_temp_ptr[1]) / 25; + troika_temp_ptr = &data->block[32].data[2]; + uint32_t troika_number = 0; + for(size_t i = 0; i < 4; i++) { + troika_number <<= 8; + troika_number |= troika_temp_ptr[i]; + } + troika_number >>= 4; + + furi_string_printf( + parsed_data, + "\e#Troika+Plantain\nPN: %llu-\nPB: %lu rur.\nTN: %lu\nTB: %u rur.\n", + card_number, + balance, + troika_number, + troika_balance); + + parsed = true; + } while(false); + + return parsed; +} + +/* Actual implementation of app<>plugin interface */ +static const NfcSupportedCardsPlugin two_cities_plugin = { + .protocol = NfcProtocolMfClassic, + .verify = two_cities_verify, + .read = two_cities_read, + .parse = two_cities_parse, +}; + +/* Plugin descriptor to comply with basic plugin specification */ +static const FlipperAppPluginDescriptor two_cities_plugin_descriptor = { + .appid = NFC_SUPPORTED_CARD_PLUGIN_APP_ID, + .ep_api_version = NFC_SUPPORTED_CARD_PLUGIN_API_VERSION, + .entry_point = &two_cities_plugin, +}; + +/* Plugin entry point - must return a pointer to const descriptor */ +const FlipperAppPluginDescriptor* two_cities_plugin_ep() { + return &two_cities_plugin_descriptor; +} diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index 5dde7ce1e068..2d6b4975b53d 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -35,6 +35,18 @@ ADD_SCENE(nfc, mf_classic_dict_attack, MfClassicDictAttack) ADD_SCENE(nfc, mf_classic_detect_reader, MfClassicDetectReader) ADD_SCENE(nfc, mf_classic_mfkey_nonces_info, MfClassicMfkeyNoncesInfo) ADD_SCENE(nfc, mf_classic_mfkey_complete, MfClassicMfkeyComplete) +ADD_SCENE(nfc, mf_classic_update_initial, MfClassicUpdateInitial) +ADD_SCENE(nfc, mf_classic_update_initial_success, MfClassicUpdateInitialSuccess) +ADD_SCENE(nfc, mf_classic_write_initial, MfClassicWriteInitial) +ADD_SCENE(nfc, mf_classic_write_initial_success, MfClassicWriteInitialSuccess) +ADD_SCENE(nfc, mf_classic_write_initial_fail, MfClassicWriteInitialFail) +ADD_SCENE(nfc, mf_classic_wrong_card, MfClassicWrongCard) + +ADD_SCENE(nfc, mf_classic_keys, MfClassicKeys) +ADD_SCENE(nfc, mf_classic_keys_list, MfClassicKeysList) +ADD_SCENE(nfc, mf_classic_keys_delete, MfClassicKeysDelete) +ADD_SCENE(nfc, mf_classic_keys_add, MfClassicKeysAdd) +ADD_SCENE(nfc, mf_classic_keys_warn_duplicate, MfClassicKeysWarnDuplicate) ADD_SCENE(nfc, set_type, SetType) ADD_SCENE(nfc, set_sak, SetSak) diff --git a/applications/main/nfc/scenes/nfc_scene_delete_success.c b/applications/main/nfc/scenes/nfc_scene_delete_success.c index 934e53bf1637..f0c22eec4d58 100644 --- a/applications/main/nfc/scenes/nfc_scene_delete_success.c +++ b/applications/main/nfc/scenes/nfc_scene_delete_success.c @@ -25,13 +25,13 @@ bool nfc_scene_delete_success_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == NfcCustomEventViewExit) { - // if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneMfClassicKeys)) { - // consumed = scene_manager_search_and_switch_to_previous_scene( - // nfc->scene_manager, NfcSceneMfClassicKeys); - // } else { - consumed = scene_manager_search_and_switch_to_previous_scene( - nfc->scene_manager, NfcSceneFileSelect); - // } + if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneMfClassicKeys)) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneMfClassicKeys); + } else { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneFileSelect); + } } } return consumed; diff --git a/applications/main/nfc/scenes/nfc_scene_extra_actions.c b/applications/main/nfc/scenes/nfc_scene_extra_actions.c index 455afb06300a..d9b49749c804 100644 --- a/applications/main/nfc/scenes/nfc_scene_extra_actions.c +++ b/applications/main/nfc/scenes/nfc_scene_extra_actions.c @@ -7,62 +7,66 @@ enum SubmenuIndex { }; void nfc_scene_extra_actions_submenu_callback(void* context, uint32_t index) { - NfcApp* nfc = context; + NfcApp* instance = context; - view_dispatcher_send_custom_event(nfc->view_dispatcher, index); + view_dispatcher_send_custom_event(instance->view_dispatcher, index); } void nfc_scene_extra_actions_on_enter(void* context) { - NfcApp* nfc = context; - Submenu* submenu = nfc->submenu; + NfcApp* instance = context; + Submenu* submenu = instance->submenu; submenu_add_item( submenu, "Read Specific Card Type", SubmenuIndexReadCardType, nfc_scene_extra_actions_submenu_callback, - nfc); + instance); submenu_add_item( submenu, "Mifare Classic Keys", SubmenuIndexMfClassicKeys, nfc_scene_extra_actions_submenu_callback, - nfc); + instance); submenu_add_item( submenu, "Unlock NTAG/Ultralight", SubmenuIndexMfUltralightUnlock, nfc_scene_extra_actions_submenu_callback, - nfc); + instance); submenu_set_selected_item( - submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneExtraActions)); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); + submenu, scene_manager_get_scene_state(instance->scene_manager, NfcSceneExtraActions)); + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewMenu); } bool nfc_scene_extra_actions_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + NfcApp* instance = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubmenuIndexMfClassicKeys) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented); + if(mf_dict_check_presence(MfDictTypeSystem)) { + scene_manager_next_scene(instance->scene_manager, NfcSceneMfClassicKeys); + } else { + scene_manager_previous_scene(instance->scene_manager); + } consumed = true; } else if(event.event == SubmenuIndexMfUltralightUnlock) { - mf_ultralight_auth_reset(nfc->mf_ul_auth); - scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockMenu); + mf_ultralight_auth_reset(instance->mf_ul_auth); + scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightUnlockMenu); consumed = true; } else if(event.event == SubmenuIndexReadCardType) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneSelectProtocol); + scene_manager_next_scene(instance->scene_manager, NfcSceneSelectProtocol); consumed = true; } - scene_manager_set_scene_state(nfc->scene_manager, NfcSceneExtraActions, event.event); + scene_manager_set_scene_state(instance->scene_manager, NfcSceneExtraActions, event.event); } return consumed; } void nfc_scene_extra_actions_on_exit(void* context) { - NfcApp* nfc = context; + NfcApp* instance = context; - submenu_reset(nfc->submenu); + submenu_reset(instance->submenu); } diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c index 24a29a95cd08..839b674c03a3 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c @@ -6,9 +6,8 @@ #define TAG "NfcMfClassicDictAttack" typedef enum { - DictAttackStateIdle, DictAttackStateUserDictInProgress, - DictAttackStateFlipperDictInProgress, + DictAttackStateSystemDictInProgress, } DictAttackState; NfcCommand nfc_dict_attack_worker_callback(NfcGenericEvent event, void* context) { @@ -20,194 +19,241 @@ NfcCommand nfc_dict_attack_worker_callback(NfcGenericEvent event, void* context) NfcCommand command = NfcCommandContinue; MfClassicPollerEvent* mfc_event = event.data; - NfcApp* nfc_app = context; - if(mfc_event->type == MfClassicPollerEventTypeStart) { - nfc_app->mf_dict_context.type = mfc_event->data->start_data.type; + NfcApp* instance = context; + if(mfc_event->type == MfClassicPollerEventTypeCardDetected) { + view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventCardDetected); + } else if(mfc_event->type == MfClassicPollerEventTypeCardLost) { + view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventCardLost); + } else if(mfc_event->type == MfClassicPollerEventTypeRequestMode) { + const MfClassicData* mfc_data = + nfc_device_get_data(instance->nfc_device, NfcProtocolMfClassic); + mfc_event->data->poller_mode.mode = MfClassicPollerModeDictAttack; + mfc_event->data->poller_mode.data = mfc_data; + instance->mf_dict_context.sectors_total = mf_classic_get_total_sectors_num(mfc_data->type); + mf_classic_get_read_sectors_and_keys( + mfc_data, + &instance->mf_dict_context.sectors_read, + &instance->mf_dict_context.keys_found); view_dispatcher_send_custom_event( - nfc_app->view_dispatcher, NfcCustomEventDictAttackCardDetected); - } else if(mfc_event->type == MfClassicPollerEventTypeCardDetected) { - view_dispatcher_send_custom_event( - nfc_app->view_dispatcher, NfcCustomEventDictAttackCardDetected); - } else if(mfc_event->type == MfClassicPollerEventTypeCardNotDetected) { - view_dispatcher_send_custom_event( - nfc_app->view_dispatcher, NfcCustomEventDictAttackCardNotDetected); + instance->view_dispatcher, NfcCustomEventDictAttackDataUpdate); } else if(mfc_event->type == MfClassicPollerEventTypeRequestKey) { MfClassicKey key = {}; - if(mf_dict_get_next_key(nfc_app->mf_dict_context.dict, &key)) { + if(mf_dict_get_next_key(instance->mf_dict_context.dict, &key)) { mfc_event->data->key_request_data.key = key; mfc_event->data->key_request_data.key_provided = true; - nfc_app->mf_dict_context.current_key++; - if(nfc_app->mf_dict_context.current_key % 10 == 0) { + instance->mf_dict_context.dict_keys_current++; + if(instance->mf_dict_context.dict_keys_current % 10 == 0) { view_dispatcher_send_custom_event( - nfc_app->view_dispatcher, NfcCustomEventDictAttackNewKeyBatch); + instance->view_dispatcher, NfcCustomEventDictAttackDataUpdate); } } else { mfc_event->data->key_request_data.key_provided = false; } - } else if(mfc_event->type == MfClassicPollerEventTypeNewSector) { + } else if(mfc_event->type == MfClassicPollerEventTypeDataUpdate) { + MfClassicPollerEventDataUpdate* data_update = &mfc_event->data->data_update; + instance->mf_dict_context.sectors_read = data_update->sectors_read; + instance->mf_dict_context.keys_found = data_update->keys_found; + instance->mf_dict_context.current_sector = data_update->current_sector; view_dispatcher_send_custom_event( - nfc_app->view_dispatcher, NfcCustomEventDictAttackNewSector); - mf_dict_rewind(nfc_app->mf_dict_context.dict); - nfc_app->mf_dict_context.current_key = 0; + instance->view_dispatcher, NfcCustomEventDictAttackDataUpdate); + } else if(mfc_event->type == MfClassicPollerEventTypeNextSector) { + mf_dict_rewind(instance->mf_dict_context.dict); + instance->mf_dict_context.dict_keys_current = 0; + instance->mf_dict_context.current_sector = + mfc_event->data->next_sector_data.current_sector; + view_dispatcher_send_custom_event( + instance->view_dispatcher, NfcCustomEventDictAttackDataUpdate); } else if(mfc_event->type == MfClassicPollerEventTypeFoundKeyA) { view_dispatcher_send_custom_event( - nfc_app->view_dispatcher, NfcCustomEventDictAttackFoundKeyA); + instance->view_dispatcher, NfcCustomEventDictAttackDataUpdate); } else if(mfc_event->type == MfClassicPollerEventTypeFoundKeyB) { view_dispatcher_send_custom_event( - nfc_app->view_dispatcher, NfcCustomEventDictAttackFoundKeyB); + instance->view_dispatcher, NfcCustomEventDictAttackDataUpdate); } else if(mfc_event->type == MfClassicPollerEventTypeKeyAttackStart) { - nfc_app->mf_dict_context.current_sector = mfc_event->data->key_attack_data.start_sector; + instance->mf_dict_context.key_attack_current_sector = + mfc_event->data->key_attack_data.current_sector; + instance->mf_dict_context.is_key_attack = true; view_dispatcher_send_custom_event( - nfc_app->view_dispatcher, NfcCustomEventDictAttackKeyAttackStart); + instance->view_dispatcher, NfcCustomEventDictAttackDataUpdate); } else if(mfc_event->type == MfClassicPollerEventTypeKeyAttackStop) { - mf_dict_rewind(nfc_app->mf_dict_context.dict); - nfc_app->mf_dict_context.current_key = 0; - view_dispatcher_send_custom_event( - nfc_app->view_dispatcher, NfcCustomEventDictAttackKeyAttackStop); - } else if(mfc_event->type == MfClassicPollerEventTypeKeyAttackNextSector) { + mf_dict_rewind(instance->mf_dict_context.dict); + instance->mf_dict_context.is_key_attack = false; + instance->mf_dict_context.dict_keys_current = 0; view_dispatcher_send_custom_event( - nfc_app->view_dispatcher, NfcCustomEventDictAttackKeyAttackNextSector); - } else if(mfc_event->type == MfClassicPollerEventTypeReadComplete) { + instance->view_dispatcher, NfcCustomEventDictAttackDataUpdate); + } else if(mfc_event->type == MfClassicPollerEventTypeSuccess) { + const MfClassicData* mfc_data = nfc_poller_get_data(instance->poller); + nfc_device_set_data(instance->nfc_device, NfcProtocolMfClassic, mfc_data); view_dispatcher_send_custom_event( - nfc_app->view_dispatcher, NfcCustomEventDictAttackComplete); + instance->view_dispatcher, NfcCustomEventDictAttackComplete); command = NfcCommandStop; } return command; } -void nfc_dict_attack_dict_attack_result_callback(void* context) { +void nfc_dict_attack_dict_attack_result_callback(DictAttackEvent event, void* context) { furi_assert(context); - NfcApp* nfc = context; - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventDictAttackSkip); -} - -static void nfc_scene_mf_classic_dict_attack_update_view(NfcApp* nfc) { - const MfClassicData* data = nfc_device_get_data(nfc->nfc_device, NfcProtocolMfClassic); - uint8_t sectors_read = 0; - uint8_t keys_found = 0; + NfcApp* instance = context; - // Calculate found keys and read sectors - mf_classic_get_read_sectors_and_keys(data, §ors_read, &keys_found); - dict_attack_set_keys_found(nfc->dict_attack, keys_found); - dict_attack_set_sector_read(nfc->dict_attack, sectors_read); + if(event == DictAttackEventSkipPressed) { + view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventDictAttackSkip); + } } -static void nfc_scene_mf_classic_dict_attack_prepare_view(NfcApp* nfc, DictAttackState state) { - const MfClassicData* data = nfc_device_get_data(nfc->nfc_device, NfcProtocolMfClassic); +static void nfc_scene_mf_classic_dict_attack_update_view(NfcApp* instance) { + NfcMfClassicDictAttackContext* mfc_dict = &instance->mf_dict_context; - // Identify scene state - if(state == DictAttackStateIdle) { - if(mf_dict_check_presence(MfDictTypeUser)) { - state = DictAttackStateUserDictInProgress; - nfc->mf_dict_context.dict = mf_dict_alloc(MfDictTypeUser); - } else { - state = DictAttackStateFlipperDictInProgress; - nfc->mf_dict_context.dict = mf_dict_alloc(MfDictTypeSystem); - } - nfc->mf_dict_context.total_keys = mf_dict_get_total_keys(nfc->mf_dict_context.dict); - nfc->mf_dict_context.current_key = 0; - } else if(state == DictAttackStateUserDictInProgress) { - state = DictAttackStateFlipperDictInProgress; + if(mfc_dict->is_key_attack) { + dict_attack_set_key_attack(instance->dict_attack, mfc_dict->key_attack_current_sector); + } else { + dict_attack_reset_key_attack(instance->dict_attack); + dict_attack_set_sectors_total(instance->dict_attack, mfc_dict->sectors_total); + dict_attack_set_sectors_read(instance->dict_attack, mfc_dict->sectors_read); + dict_attack_set_keys_found(instance->dict_attack, mfc_dict->keys_found); + dict_attack_set_current_dict_key(instance->dict_attack, mfc_dict->dict_keys_current); + dict_attack_set_current_sector(instance->dict_attack, mfc_dict->current_sector); } +} - // Setup view +static void nfc_scene_mf_classic_dict_attack_prepare_view(NfcApp* instance) { + uint32_t state = + scene_manager_get_scene_state(instance->scene_manager, NfcSceneMfClassicDictAttack); if(state == DictAttackStateUserDictInProgress) { - dict_attack_set_header(nfc->dict_attack, "MF Classic User Dictionary"); + do { + if(!mf_dict_check_presence(MfDictTypeUser)) { + state = DictAttackStateSystemDictInProgress; + break; + } + + instance->mf_dict_context.dict = mf_dict_alloc(MfDictTypeUser); + if(mf_dict_get_total_keys(instance->mf_dict_context.dict) == 0) { + mf_dict_free(instance->mf_dict_context.dict); + state = DictAttackStateSystemDictInProgress; + break; + } + + dict_attack_set_header(instance->dict_attack, "MF Classic User Dictionary"); + } while(false); } - if(state == DictAttackStateFlipperDictInProgress) { - dict_attack_set_header(nfc->dict_attack, "MF Classic System Dictionary"); + if(state == DictAttackStateSystemDictInProgress) { + instance->mf_dict_context.dict = mf_dict_alloc(MfDictTypeSystem); + dict_attack_set_header(instance->dict_attack, "MF Classic System Dictionary"); } - scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfClassicDictAttack, state); - dict_attack_set_callback(nfc->dict_attack, nfc_dict_attack_dict_attack_result_callback, nfc); - dict_attack_set_current_sector(nfc->dict_attack, 0); - dict_attack_set_card_detected(nfc->dict_attack, data->type); - dict_attack_set_total_dict_keys(nfc->dict_attack, nfc->mf_dict_context.total_keys); - nfc_scene_mf_classic_dict_attack_update_view(nfc); + instance->mf_dict_context.dict_keys_total = + mf_dict_get_total_keys(instance->mf_dict_context.dict); + dict_attack_set_total_dict_keys( + instance->dict_attack, instance->mf_dict_context.dict_keys_total); + instance->mf_dict_context.dict_keys_current = 0; + + dict_attack_set_callback( + instance->dict_attack, nfc_dict_attack_dict_attack_result_callback, instance); + nfc_scene_mf_classic_dict_attack_update_view(instance); + + scene_manager_set_scene_state(instance->scene_manager, NfcSceneMfClassicDictAttack, state); } void nfc_scene_mf_classic_dict_attack_on_enter(void* context) { - NfcApp* nfc = context; - nfc_scene_mf_classic_dict_attack_prepare_view(nfc, DictAttackStateIdle); - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDictAttack); - nfc_blink_read_start(nfc); - notification_message(nfc->notifications, &sequence_display_backlight_enforce_on); - - nfc->poller = nfc_poller_alloc(nfc->nfc, NfcProtocolMfClassic); - nfc_poller_start(nfc->poller, nfc_dict_attack_worker_callback, nfc); + NfcApp* instance = context; + + scene_manager_set_scene_state( + instance->scene_manager, NfcSceneMfClassicDictAttack, DictAttackStateUserDictInProgress); + nfc_scene_mf_classic_dict_attack_prepare_view(instance); + dict_attack_set_card_state(instance->dict_attack, true); + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewDictAttack); + nfc_blink_read_start(instance); + notification_message(instance->notifications, &sequence_display_backlight_enforce_on); + + instance->poller = nfc_poller_alloc(instance->nfc, NfcProtocolMfClassic); + nfc_poller_start(instance->poller, nfc_dict_attack_worker_callback, instance); } bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + NfcApp* instance = context; bool consumed = false; uint32_t state = - scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicDictAttack); + scene_manager_get_scene_state(instance->scene_manager, NfcSceneMfClassicDictAttack); if(event.type == SceneManagerEventTypeCustom) { if(event.event == NfcCustomEventDictAttackComplete) { if(state == DictAttackStateUserDictInProgress) { - nfc_scene_mf_classic_dict_attack_prepare_view(nfc, state); + nfc_poller_stop(instance->poller); + nfc_poller_free(instance->poller); + mf_dict_free(instance->mf_dict_context.dict); + scene_manager_set_scene_state( + instance->scene_manager, + NfcSceneMfClassicDictAttack, + DictAttackStateSystemDictInProgress); + nfc_scene_mf_classic_dict_attack_prepare_view(instance); + instance->poller = nfc_poller_alloc(instance->nfc, NfcProtocolMfClassic); + nfc_poller_start(instance->poller, nfc_dict_attack_worker_callback, instance); consumed = true; } else { - notification_message(nfc->notifications, &sequence_success); - scene_manager_next_scene(nfc->scene_manager, NfcSceneReadSuccess); + notification_message(instance->notifications, &sequence_success); + scene_manager_next_scene(instance->scene_manager, NfcSceneReadSuccess); dolphin_deed(DolphinDeedNfcReadSuccess); consumed = true; } - } else if(event.event == NfcCustomEventDictAttackCardDetected) { - dict_attack_set_card_detected(nfc->dict_attack, nfc->mf_dict_context.type); - consumed = true; - } else if(event.event == NfcCustomEventDictAttackCardNotDetected) { - dict_attack_set_card_removed(nfc->dict_attack); - consumed = true; - } else if(event.event == NfcCustomEventDictAttackFoundKeyA) { - dict_attack_inc_keys_found(nfc->dict_attack); + } else if(event.event == NfcCustomEventCardDetected) { + dict_attack_set_card_state(instance->dict_attack, true); consumed = true; - } else if(event.event == NfcCustomEventDictAttackFoundKeyB) { - dict_attack_inc_keys_found(nfc->dict_attack); - consumed = true; - } else if(event.event == NfcCustomEventDictAttackNewSector) { - nfc_device_set_data( - nfc->nfc_device, NfcProtocolMfClassic, nfc_poller_get_data(nfc->poller)); - nfc_scene_mf_classic_dict_attack_update_view(nfc); - dict_attack_inc_current_sector(nfc->dict_attack); - consumed = true; - } else if(event.event == NfcCustomEventDictAttackNewKeyBatch) { - nfc_device_set_data( - nfc->nfc_device, NfcProtocolMfClassic, nfc_poller_get_data(nfc->poller)); - nfc_scene_mf_classic_dict_attack_update_view(nfc); - dict_attack_inc_current_dict_key(nfc->dict_attack, 10); + } else if(event.event == NfcCustomEventCardLost) { + dict_attack_set_card_state(instance->dict_attack, false); consumed = true; + } else if(event.event == NfcCustomEventDictAttackDataUpdate) { + nfc_scene_mf_classic_dict_attack_update_view(instance); } else if(event.event == NfcCustomEventDictAttackSkip) { + const MfClassicData* mfc_data = nfc_poller_get_data(instance->poller); + nfc_device_set_data(instance->nfc_device, NfcProtocolMfClassic, mfc_data); if(state == DictAttackStateUserDictInProgress) { - nfc_poller_stop(nfc->poller); + nfc_poller_stop(instance->poller); + nfc_poller_free(instance->poller); + mf_dict_free(instance->mf_dict_context.dict); + scene_manager_set_scene_state( + instance->scene_manager, + NfcSceneMfClassicDictAttack, + DictAttackStateSystemDictInProgress); + nfc_scene_mf_classic_dict_attack_prepare_view(instance); + instance->poller = nfc_poller_alloc(instance->nfc, NfcProtocolMfClassic); + nfc_poller_start(instance->poller, nfc_dict_attack_worker_callback, instance); consumed = true; - } else if(state == DictAttackStateFlipperDictInProgress) { - nfc_poller_stop(nfc->poller); + } else if(state == DictAttackStateSystemDictInProgress) { + notification_message(instance->notifications, &sequence_success); + scene_manager_next_scene(instance->scene_manager, NfcSceneReadSuccess); + dolphin_deed(DolphinDeedNfcReadSuccess); consumed = true; } - } else if(event.event == NfcCustomEventDictAttackKeyAttackStart) { - dict_attack_set_key_attack( - nfc->dict_attack, true, nfc->mf_dict_context.current_sector); - } else if(event.event == NfcCustomEventDictAttackKeyAttackStop) { - dict_attack_set_key_attack(nfc->dict_attack, false, 0); - } else if(event.event == NfcCustomEventDictAttackKeyAttackNextSector) { - dict_attack_inc_key_attack_current_sector(nfc->dict_attack); } } else if(event.type == SceneManagerEventTypeBack) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm); + scene_manager_next_scene(instance->scene_manager, NfcSceneExitConfirm); consumed = true; } return consumed; } void nfc_scene_mf_classic_dict_attack_on_exit(void* context) { - NfcApp* nfc = context; + NfcApp* instance = context; + + nfc_poller_stop(instance->poller); + nfc_poller_free(instance->poller); + + dict_attack_reset(instance->dict_attack); + scene_manager_set_scene_state( + instance->scene_manager, NfcSceneMfClassicDictAttack, DictAttackStateUserDictInProgress); + + mf_dict_free(instance->mf_dict_context.dict); - nfc_poller_stop(nfc->poller); - nfc_poller_free(nfc->poller); + instance->mf_dict_context.current_sector = 0; + instance->mf_dict_context.sectors_total = 0; + instance->mf_dict_context.sectors_read = 0; + instance->mf_dict_context.current_sector = 0; + instance->mf_dict_context.keys_found = 0; + instance->mf_dict_context.dict_keys_total = 0; + instance->mf_dict_context.dict_keys_current = 0; + instance->mf_dict_context.is_key_attack = false; + instance->mf_dict_context.key_attack_current_sector = 0; - nfc_blink_stop(nfc); - notification_message(nfc->notifications, &sequence_display_backlight_enforce_auto); + nfc_blink_stop(instance); + notification_message(instance->notifications, &sequence_display_backlight_enforce_auto); } diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_keys.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys.c new file mode 100644 index 000000000000..08491e0bb252 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys.c @@ -0,0 +1,90 @@ +#include "../nfc_app_i.h" + +#define NFC_SCENE_MF_CLASSIC_KEYS_MAX (100) + +void nfc_scene_mf_classic_keys_widget_callback(GuiButtonType result, InputType type, void* context) { + NfcApp* instance = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(instance->view_dispatcher, result); + } +} + +void nfc_scene_mf_classic_keys_on_enter(void* context) { + NfcApp* instance = context; + + // Load flipper dict keys total + MfDict* dict = mf_dict_alloc(MfDictTypeSystem); + furi_assert(dict); + uint32_t flipper_dict_keys_total = mf_dict_get_total_keys(dict); + mf_dict_free(dict); + + // Load user dict keys total + uint32_t user_dict_keys_total = 0; + dict = mf_dict_alloc(MfDictTypeUser); + furi_assert(dict); + user_dict_keys_total = mf_dict_get_total_keys(dict); + mf_dict_free(dict); + + FuriString* temp_str = furi_string_alloc(); + widget_add_string_element( + instance->widget, 0, 0, AlignLeft, AlignTop, FontPrimary, "MIFARE Classic Keys"); + furi_string_printf(temp_str, "System dict: %lu", flipper_dict_keys_total); + widget_add_string_element( + instance->widget, + 0, + 20, + AlignLeft, + AlignTop, + FontSecondary, + furi_string_get_cstr(temp_str)); + furi_string_printf(temp_str, "User dict: %lu", user_dict_keys_total); + widget_add_string_element( + instance->widget, + 0, + 32, + AlignLeft, + AlignTop, + FontSecondary, + furi_string_get_cstr(temp_str)); + widget_add_icon_element(instance->widget, 87, 13, &I_Keychain_39x36); + widget_add_button_element( + instance->widget, + GuiButtonTypeCenter, + "Add", + nfc_scene_mf_classic_keys_widget_callback, + instance); + if(user_dict_keys_total > 0) { + widget_add_button_element( + instance->widget, + GuiButtonTypeRight, + "List", + nfc_scene_mf_classic_keys_widget_callback, + instance); + } + furi_string_free(temp_str); + + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewWidget); +} + +bool nfc_scene_mf_classic_keys_on_event(void* context, SceneManagerEvent event) { + NfcApp* instance = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeCenter) { + scene_manager_next_scene(instance->scene_manager, NfcSceneMfClassicKeysAdd); + consumed = true; + } else if(event.event == GuiButtonTypeRight) { + scene_manager_next_scene(instance->scene_manager, NfcSceneMfClassicKeysList); + consumed = true; + } + } + + return consumed; +} + +void nfc_scene_mf_classic_keys_on_exit(void* context) { + NfcApp* instance = context; + + widget_reset(instance->widget); +} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_add.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_add.c new file mode 100644 index 000000000000..77c9f88097a8 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_add.c @@ -0,0 +1,61 @@ +#include "../nfc_app_i.h" + +void nfc_scene_mf_classic_keys_add_byte_input_callback(void* context) { + NfcApp* instance = context; + + view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventByteInputDone); +} + +void nfc_scene_mf_classic_keys_add_on_enter(void* context) { + NfcApp* instance = context; + + // Setup view + ByteInput* byte_input = instance->byte_input; + byte_input_set_header_text(byte_input, "Enter the key in hex"); + byte_input_set_result_callback( + byte_input, + nfc_scene_mf_classic_keys_add_byte_input_callback, + NULL, + instance, + instance->byte_input_store, + sizeof(MfClassicKey)); + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewByteInput); +} + +bool nfc_scene_mf_classic_keys_add_on_event(void* context, SceneManagerEvent event) { + NfcApp* instance = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventByteInputDone) { + // Add key to dict + MfDict* dict = mf_dict_alloc(MfDictTypeUser); + furi_assert(dict); + + MfClassicKey key = {}; + memcpy(key.data, instance->byte_input_store, sizeof(MfClassicKey)); + if(mf_dict_is_key_present(dict, &key)) { + scene_manager_next_scene( + instance->scene_manager, NfcSceneMfClassicKeysWarnDuplicate); + } else if(mf_dict_add_key(dict, &key)) { + scene_manager_next_scene(instance->scene_manager, NfcSceneSaveSuccess); + dolphin_deed(DolphinDeedNfcMfcAdd); + } else { + scene_manager_previous_scene(instance->scene_manager); + } + + mf_dict_free(dict); + consumed = true; + } + } + + return consumed; +} + +void nfc_scene_mf_classic_keys_add_on_exit(void* context) { + NfcApp* instance = context; + + // Clear view + byte_input_set_result_callback(instance->byte_input, NULL, NULL, NULL, NULL, 0); + byte_input_set_header_text(instance->byte_input, ""); +} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_delete.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_delete.c new file mode 100644 index 000000000000..b245a2a552d6 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_delete.c @@ -0,0 +1,77 @@ +#include "../nfc_app_i.h" + +void nfc_scene_mf_classic_keys_delete_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + NfcApp* instance = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(instance->view_dispatcher, result); + } +} + +void nfc_scene_mf_classic_keys_delete_on_enter(void* context) { + NfcApp* instance = context; + + uint32_t key_index = + scene_manager_get_scene_state(instance->scene_manager, NfcSceneMfClassicKeysDelete); + FuriString* key_str = furi_string_alloc(); + + widget_add_string_element( + instance->widget, 64, 0, AlignCenter, AlignTop, FontPrimary, "Delete this key?"); + widget_add_button_element( + instance->widget, + GuiButtonTypeLeft, + "Cancel", + nfc_scene_mf_classic_keys_delete_widget_callback, + instance); + widget_add_button_element( + instance->widget, + GuiButtonTypeRight, + "Delete", + nfc_scene_mf_classic_keys_delete_widget_callback, + instance); + + mf_user_dict_get_key_str(instance->mf_user_dict, key_index, key_str); + widget_add_string_element( + instance->widget, + 64, + 32, + AlignCenter, + AlignCenter, + FontSecondary, + furi_string_get_cstr(key_str)); + + furi_string_free(key_str); + + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewWidget); +} + +bool nfc_scene_mf_classic_keys_delete_on_event(void* context, SceneManagerEvent event) { + NfcApp* instance = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeRight) { + uint32_t key_index = scene_manager_get_scene_state( + instance->scene_manager, NfcSceneMfClassicKeysDelete); + if(mf_user_dict_delete_key(instance->mf_user_dict, key_index)) { + scene_manager_next_scene(instance->scene_manager, NfcSceneDeleteSuccess); + } else { + scene_manager_previous_scene(instance->scene_manager); + } + } else if(event.event == GuiButtonTypeLeft) { + scene_manager_previous_scene(instance->scene_manager); + } + consumed = true; + } + + return consumed; +} + +void nfc_scene_mf_classic_keys_delete_on_exit(void* context) { + NfcApp* instance = context; + + mf_user_dict_free(instance->mf_user_dict); + widget_reset(instance->widget); +} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_list.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_list.c new file mode 100644 index 000000000000..7370c06840e9 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_list.c @@ -0,0 +1,51 @@ +#include "../nfc_app_i.h" + +#define NFC_SCENE_MF_CLASSIC_KEYS_LIST_MAX (100) + +void nfc_scene_mf_classic_keys_list_submenu_callback(void* context, uint32_t index) { + NfcApp* instance = context; + + view_dispatcher_send_custom_event(instance->view_dispatcher, index); +} + +void nfc_scene_mf_classic_keys_list_on_enter(void* context) { + NfcApp* instance = context; + + instance->mf_user_dict = mf_user_dict_alloc(NFC_SCENE_MF_CLASSIC_KEYS_LIST_MAX); + + submenu_set_header(instance->submenu, "Select key to delete:"); + FuriString* temp_str = furi_string_alloc(); + for(size_t i = 0; i < mf_user_dict_get_keys_cnt(instance->mf_user_dict); i++) { + mf_user_dict_get_key_str(instance->mf_user_dict, i, temp_str); + submenu_add_item( + instance->submenu, + furi_string_get_cstr(temp_str), + i, + nfc_scene_mf_classic_keys_list_submenu_callback, + instance); + } + furi_string_free(temp_str); + + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewMenu); +} + +bool nfc_scene_mf_classic_keys_list_on_event(void* context, SceneManagerEvent event) { + NfcApp* instance = context; + + bool consumed = false; + if(event.type == SceneManagerEventTypeCustom) { + scene_manager_set_scene_state( + instance->scene_manager, NfcSceneMfClassicKeysDelete, event.event); + scene_manager_next_scene(instance->scene_manager, NfcSceneMfClassicKeysDelete); + } else if(event.type == SceneManagerEventTypeBack) { + mf_user_dict_free(instance->mf_user_dict); + } + + return consumed; +} + +void nfc_scene_mf_classic_keys_list_on_exit(void* context) { + NfcApp* instance = context; + + submenu_reset(instance->submenu); +} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_warn_duplicate.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_warn_duplicate.c new file mode 100644 index 000000000000..991c956c1c00 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_warn_duplicate.c @@ -0,0 +1,49 @@ +#include "../nfc_app_i.h" + +void nfc_scene_mf_classic_keys_warn_duplicate_popup_callback(void* context) { + NfcApp* instance = context; + + view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventViewExit); +} + +void nfc_scene_mf_classic_keys_warn_duplicate_on_enter(void* context) { + NfcApp* instance = context; + + // Setup view + Popup* popup = instance->popup; + popup_set_icon(popup, 72, 16, &I_DolphinCommon_56x48); + popup_set_header(popup, "Key already exists!", 64, 3, AlignCenter, AlignTop); + popup_set_text( + popup, + "Please enter a\n" + "different key.", + 4, + 24, + AlignLeft, + AlignTop); + popup_set_timeout(popup, 1500); + popup_set_context(popup, instance); + popup_set_callback(popup, nfc_scene_mf_classic_keys_warn_duplicate_popup_callback); + popup_enable_timeout(popup); + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup); +} + +bool nfc_scene_mf_classic_keys_warn_duplicate_on_event(void* context, SceneManagerEvent event) { + NfcApp* instance = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventViewExit) { + consumed = scene_manager_search_and_switch_to_previous_scene( + instance->scene_manager, NfcSceneMfClassicKeysAdd); + } + } + + return consumed; +} + +void nfc_scene_mf_classic_keys_warn_duplicate_on_exit(void* context) { + NfcApp* instance = context; + + popup_reset(instance->popup); +} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_update_initial.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_update_initial.c new file mode 100644 index 000000000000..89aa13bcca3a --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_update_initial.c @@ -0,0 +1,144 @@ +#include "../nfc_app_i.h" + +#include + +enum { + NfcSceneMfClassicUpdateInitialStateCardSearch, + NfcSceneMfClassicUpdateInitialStateCardFound, +}; + +NfcCommand nfc_mf_classic_update_initial_worker_callback(NfcGenericEvent event, void* context) { + furi_assert(context); + furi_assert(event.data); + furi_assert(event.protocol == NfcProtocolMfClassic); + + NfcCommand command = NfcCommandContinue; + const MfClassicPollerEvent* mfc_event = event.data; + NfcApp* instance = context; + + if(mfc_event->type == MfClassicPollerEventTypeCardDetected) { + view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventCardDetected); + } else if(mfc_event->type == MfClassicPollerEventTypeCardLost) { + view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventCardLost); + } else if(mfc_event->type == MfClassicPollerEventTypeRequestMode) { + const MfClassicData* updated_data = nfc_poller_get_data(instance->poller); + const MfClassicData* old_data = + nfc_device_get_data(instance->nfc_device, NfcProtocolMfClassic); + if(iso14443_3a_is_equal(updated_data->iso14443_3a_data, old_data->iso14443_3a_data)) { + mfc_event->data->poller_mode.mode = MfClassicPollerModeRead; + } else { + view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventWrongCard); + command = NfcCommandStop; + } + } else if(mfc_event->type == MfClassicPollerEventTypeRequestReadSector) { + uint8_t sector_num = 0; + MfClassicKey key = {}; + MfClassicKeyType key_type = MfClassicKeyTypeA; + if(mf_classic_key_cahce_get_next_key( + instance->mfc_key_cache, §or_num, &key, &key_type)) { + mfc_event->data->read_sector_request_data.sector_num = sector_num; + mfc_event->data->read_sector_request_data.key = key; + mfc_event->data->read_sector_request_data.key_type = key_type; + mfc_event->data->read_sector_request_data.key_provided = true; + } else { + mfc_event->data->read_sector_request_data.key_provided = false; + } + } else if(mfc_event->type == MfClassicPollerEventTypeSuccess) { + const MfClassicData* updated_data = nfc_poller_get_data(instance->poller); + nfc_device_set_data(instance->nfc_device, NfcProtocolMfClassic, updated_data); + view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventWorkerExit); + command = NfcCommandStop; + } + + return command; +} + +static void nfc_scene_mf_classic_update_initial_setup_view(NfcApp* instance) { + Popup* popup = instance->popup; + popup_reset(popup); + uint32_t state = + scene_manager_get_scene_state(instance->scene_manager, NfcSceneMfClassicUpdateInitial); + + if(state == NfcSceneMfClassicUpdateInitialStateCardSearch) { + popup_set_text( + instance->popup, "Apply the initial\ncard only", 128, 32, AlignRight, AlignCenter); + popup_set_icon(instance->popup, 0, 8, &I_NFC_manual_60x50); + } else { + popup_set_header(popup, "Updating\nDon't move...", 52, 32, AlignLeft, AlignCenter); + popup_set_icon(popup, 12, 23, &A_Loading_24); + } + + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup); +} + +void nfc_scene_mf_classic_update_initial_on_enter(void* context) { + NfcApp* instance = context; + dolphin_deed(DolphinDeedNfcEmulate); + + const MfClassicData* mfc_data = + nfc_device_get_data(instance->nfc_device, NfcProtocolMfClassic); + mf_classic_key_cache_load_from_data(instance->mfc_key_cache, mfc_data); + + scene_manager_set_scene_state( + instance->scene_manager, + NfcSceneMfClassicUpdateInitial, + NfcSceneMfClassicUpdateInitialStateCardSearch); + nfc_scene_mf_classic_update_initial_setup_view(instance); + + // Setup and start worker + instance->poller = nfc_poller_alloc(instance->nfc, NfcProtocolMfClassic); + nfc_poller_start(instance->poller, nfc_mf_classic_update_initial_worker_callback, instance); + nfc_blink_emulate_start(instance); +} + +bool nfc_scene_mf_classic_update_initial_on_event(void* context, SceneManagerEvent event) { + NfcApp* instance = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventCardDetected) { + scene_manager_set_scene_state( + instance->scene_manager, + NfcSceneMfClassicUpdateInitial, + NfcSceneMfClassicUpdateInitialStateCardFound); + nfc_scene_mf_classic_update_initial_setup_view(instance); + consumed = true; + } else if(event.event == NfcCustomEventCardLost) { + scene_manager_set_scene_state( + instance->scene_manager, + NfcSceneMfClassicUpdateInitial, + NfcSceneMfClassicUpdateInitialStateCardSearch); + nfc_scene_mf_classic_update_initial_setup_view(instance); + consumed = true; + } else if(event.event == NfcCustomEventWrongCard) { + scene_manager_next_scene(instance->scene_manager, NfcSceneMfClassicWrongCard); + consumed = true; + } else if(event.event == NfcCustomEventWorkerExit) { + if(nfc_save_shadow_file(instance)) { + scene_manager_next_scene( + instance->scene_manager, NfcSceneMfClassicUpdateInitialSuccess); + } else { + scene_manager_next_scene(instance->scene_manager, NfcSceneMfClassicWrongCard); + consumed = true; + } + } + } + + return consumed; +} + +void nfc_scene_mf_classic_update_initial_on_exit(void* context) { + NfcApp* instance = context; + + nfc_poller_stop(instance->poller); + nfc_poller_free(instance->poller); + + scene_manager_set_scene_state( + instance->scene_manager, + NfcSceneMfClassicUpdateInitial, + NfcSceneMfClassicUpdateInitialStateCardSearch); + // Clear view + popup_reset(instance->popup); + + nfc_blink_stop(instance); +} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_update_initial_success.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_update_initial_success.c new file mode 100644 index 000000000000..02e307b01baa --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_update_initial_success.c @@ -0,0 +1,43 @@ +#include "../nfc_app_i.h" + +void nfc_scene_mf_classic_update_initial_success_popup_callback(void* context) { + NfcApp* instance = context; + view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventViewExit); +} + +void nfc_scene_mf_classic_update_initial_success_on_enter(void* context) { + NfcApp* instance = context; + dolphin_deed(DolphinDeedNfcSave); + + notification_message(instance->notifications, &sequence_success); + + Popup* popup = instance->popup; + popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); + popup_set_header(popup, "Updated!", 11, 20, AlignLeft, AlignBottom); + popup_set_timeout(popup, 1500); + popup_set_context(popup, instance); + popup_set_callback(popup, nfc_scene_mf_classic_update_initial_success_popup_callback); + popup_enable_timeout(popup); + + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup); +} + +bool nfc_scene_mf_classic_update_initial_success_on_event(void* context, SceneManagerEvent event) { + NfcApp* instance = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventViewExit) { + consumed = scene_manager_search_and_switch_to_previous_scene( + instance->scene_manager, NfcSceneSavedMenu); + } + } + return consumed; +} + +void nfc_scene_mf_classic_update_initial_success_on_exit(void* context) { + NfcApp* instance = context; + + // Clear view + popup_reset(instance->popup); +} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_write_initial.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_write_initial.c new file mode 100644 index 000000000000..4ff65b834dd2 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_write_initial.c @@ -0,0 +1,146 @@ +#include "../nfc_app_i.h" + +#include + +enum { + NfcSceneMfClassicWriteInitialStateCardSearch, + NfcSceneMfClassicWriteInitialStateCardFound, +}; + +NfcCommand + nfc_scene_mf_classic_write_initial_worker_callback(NfcGenericEvent event, void* context) { + furi_assert(context); + furi_assert(event.data); + furi_assert(event.protocol == NfcProtocolMfClassic); + + NfcCommand command = NfcCommandContinue; + NfcApp* instance = context; + MfClassicPollerEvent* mfc_event = event.data; + const MfClassicData* write_data = + nfc_device_get_data(instance->nfc_device, NfcProtocolMfClassic); + + if(mfc_event->type == MfClassicPollerEventTypeCardDetected) { + view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventCardDetected); + } else if(mfc_event->type == MfClassicPollerEventTypeCardLost) { + view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventCardLost); + } else if(mfc_event->type == MfClassicPollerEventTypeRequestMode) { + const MfClassicData* tag_data = nfc_poller_get_data(instance->poller); + if(iso14443_3a_is_equal(tag_data->iso14443_3a_data, write_data->iso14443_3a_data)) { + mfc_event->data->poller_mode.mode = MfClassicPollerModeWrite; + } else { + view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventWrongCard); + command = NfcCommandStop; + } + } else if(mfc_event->type == MfClassicPollerEventTypeRequestSectorTrailer) { + uint8_t sector = mfc_event->data->sec_tr_data.sector_num; + uint8_t sec_tr = mf_classic_get_sector_trailer_num_by_sector(sector); + if(mf_classic_is_block_read(write_data, sec_tr)) { + mfc_event->data->sec_tr_data.sector_trailer = write_data->block[sec_tr]; + mfc_event->data->sec_tr_data.sector_trailer_provided = true; + } else { + mfc_event->data->sec_tr_data.sector_trailer_provided = false; + } + } else if(mfc_event->type == MfClassicPollerEventTypeRequestWriteBlock) { + uint8_t block_num = mfc_event->data->write_block_data.block_num; + if(mf_classic_is_block_read(write_data, block_num)) { + mfc_event->data->write_block_data.write_block = write_data->block[block_num]; + mfc_event->data->write_block_data.write_block_provided = true; + } else { + mfc_event->data->write_block_data.write_block_provided = false; + } + } else if(mfc_event->type == MfClassicPollerEventTypeSuccess) { + view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventPollerSuccess); + command = NfcCommandStop; + } else if(mfc_event->type == MfClassicPollerEventTypeFail) { + view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventPollerFailure); + command = NfcCommandStop; + } + return command; +} + +static void nfc_scene_mf_classic_write_initial_setup_view(NfcApp* instance) { + Popup* popup = instance->popup; + popup_reset(popup); + uint32_t state = + scene_manager_get_scene_state(instance->scene_manager, NfcSceneMfClassicWriteInitial); + + if(state == NfcSceneMfClassicWriteInitialStateCardSearch) { + popup_set_text( + instance->popup, "Apply the initial\ncard only", 128, 32, AlignRight, AlignCenter); + popup_set_icon(instance->popup, 0, 8, &I_NFC_manual_60x50); + } else { + popup_set_header(popup, "Writing\nDon't move...", 52, 32, AlignLeft, AlignCenter); + popup_set_icon(popup, 12, 23, &A_Loading_24); + } + + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup); +} + +void nfc_scene_mf_classic_write_initial_on_enter(void* context) { + NfcApp* instance = context; + dolphin_deed(DolphinDeedNfcEmulate); + + scene_manager_set_scene_state( + instance->scene_manager, + NfcSceneMfClassicWriteInitial, + NfcSceneMfClassicWriteInitialStateCardSearch); + nfc_scene_mf_classic_write_initial_setup_view(instance); + + // Setup and start worker + instance->poller = nfc_poller_alloc(instance->nfc, NfcProtocolMfClassic); + nfc_poller_start( + instance->poller, nfc_scene_mf_classic_write_initial_worker_callback, instance); + + nfc_blink_emulate_start(instance); +} + +bool nfc_scene_mf_classic_write_initial_on_event(void* context, SceneManagerEvent event) { + NfcApp* instance = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventCardDetected) { + scene_manager_set_scene_state( + instance->scene_manager, + NfcSceneMfClassicWriteInitial, + NfcSceneMfClassicWriteInitialStateCardFound); + nfc_scene_mf_classic_write_initial_setup_view(instance); + consumed = true; + } else if(event.event == NfcCustomEventCardLost) { + scene_manager_set_scene_state( + instance->scene_manager, + NfcSceneMfClassicWriteInitial, + NfcSceneMfClassicWriteInitialStateCardSearch); + nfc_scene_mf_classic_write_initial_setup_view(instance); + consumed = true; + } else if(event.event == NfcCustomEventWrongCard) { + scene_manager_next_scene(instance->scene_manager, NfcSceneMfClassicWrongCard); + consumed = true; + } else if(event.event == NfcCustomEventPollerSuccess) { + scene_manager_next_scene( + instance->scene_manager, NfcSceneMfClassicWriteInitialSuccess); + consumed = true; + } else if(event.event == NfcCustomEventPollerFailure) { + scene_manager_next_scene(instance->scene_manager, NfcSceneMfClassicWriteInitialFail); + consumed = true; + } + } + + return consumed; +} + +void nfc_scene_mf_classic_write_initial_on_exit(void* context) { + NfcApp* instance = context; + + nfc_poller_stop(instance->poller); + nfc_poller_free(instance->poller); + + scene_manager_set_scene_state( + instance->scene_manager, + NfcSceneMfClassicWriteInitial, + NfcSceneMfClassicWriteInitialStateCardSearch); + // Clear view + popup_reset(instance->popup); + + nfc_blink_stop(instance); +} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_write_initial_fail.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_write_initial_fail.c new file mode 100644 index 000000000000..f85e5a80c3f8 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_write_initial_fail.c @@ -0,0 +1,62 @@ +#include "../nfc_app_i.h" + +void nfc_scene_mf_classic_write_initial_fail_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + NfcApp* instance = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(instance->view_dispatcher, result); + } +} + +void nfc_scene_mf_classic_write_initial_fail_on_enter(void* context) { + NfcApp* instance = context; + Widget* widget = instance->widget; + + notification_message(instance->notifications, &sequence_error); + + widget_add_icon_element(widget, 72, 17, &I_DolphinCommon_56x48); + widget_add_string_element( + widget, 7, 4, AlignLeft, AlignTop, FontPrimary, "Writing gone wrong!"); + widget_add_string_multiline_element( + widget, + 7, + 17, + AlignLeft, + AlignTop, + FontSecondary, + "Not all sectors\nwere written\ncorrectly."); + + widget_add_button_element( + widget, + GuiButtonTypeLeft, + "Finish", + nfc_scene_mf_classic_write_initial_fail_widget_callback, + instance); + + // Setup and start worker + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewWidget); +} + +bool nfc_scene_mf_classic_write_initial_fail_on_event(void* context, SceneManagerEvent event) { + NfcApp* instance = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeLeft) { + consumed = scene_manager_search_and_switch_to_previous_scene( + instance->scene_manager, NfcSceneSavedMenu); + } + } else if(event.type == SceneManagerEventTypeBack) { + consumed = scene_manager_search_and_switch_to_previous_scene( + instance->scene_manager, NfcSceneSavedMenu); + } + return consumed; +} + +void nfc_scene_mf_classic_write_initial_fail_on_exit(void* context) { + NfcApp* instance = context; + + widget_reset(instance->widget); +} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_write_initial_success.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_write_initial_success.c new file mode 100644 index 000000000000..acb75cd2e9f8 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_write_initial_success.c @@ -0,0 +1,43 @@ +#include "../nfc_app_i.h" + +void nfc_scene_mf_classic_write_initial_success_popup_callback(void* context) { + NfcApp* instance = context; + view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventViewExit); +} + +void nfc_scene_mf_classic_write_initial_success_on_enter(void* context) { + NfcApp* instance = context; + dolphin_deed(DolphinDeedNfcSave); + + notification_message(instance->notifications, &sequence_success); + + Popup* popup = instance->popup; + popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); + popup_set_header(popup, "Successfully\nwritten", 13, 22, AlignLeft, AlignBottom); + popup_set_timeout(popup, 1500); + popup_set_context(popup, instance); + popup_set_callback(popup, nfc_scene_mf_classic_write_initial_success_popup_callback); + popup_enable_timeout(popup); + + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup); +} + +bool nfc_scene_mf_classic_write_initial_success_on_event(void* context, SceneManagerEvent event) { + NfcApp* instance = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventViewExit) { + consumed = scene_manager_search_and_switch_to_previous_scene( + instance->scene_manager, NfcSceneSavedMenu); + } + } + return consumed; +} + +void nfc_scene_mf_classic_write_initial_success_on_exit(void* context) { + NfcApp* instance = context; + + // Clear view + popup_reset(instance->popup); +} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_wrong_card.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_wrong_card.c new file mode 100644 index 000000000000..50025048af43 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_wrong_card.c @@ -0,0 +1,57 @@ +#include "../nfc_app_i.h" + +void nfc_scene_mf_classic_wrong_card_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + NfcApp* instance = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(instance->view_dispatcher, result); + } +} + +void nfc_scene_mf_classic_wrong_card_on_enter(void* context) { + NfcApp* instance = context; + Widget* widget = instance->widget; + + notification_message(instance->notifications, &sequence_error); + + widget_add_icon_element(widget, 73, 17, &I_DolphinCommon_56x48); + widget_add_string_element( + widget, 3, 4, AlignLeft, AlignTop, FontPrimary, "This is wrong card"); + widget_add_string_multiline_element( + widget, + 4, + 17, + AlignLeft, + AlignTop, + FontSecondary, + "Data management\nis only possible\nwith initial card"); + widget_add_button_element( + widget, + GuiButtonTypeLeft, + "Retry", + nfc_scene_mf_classic_wrong_card_widget_callback, + instance); + + // Setup and start worker + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewWidget); +} + +bool nfc_scene_mf_classic_wrong_card_on_event(void* context, SceneManagerEvent event) { + NfcApp* instance = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeLeft) { + consumed = scene_manager_previous_scene(instance->scene_manager); + } + } + return consumed; +} + +void nfc_scene_mf_classic_wrong_card_on_exit(void* context) { + NfcApp* instance = context; + + widget_reset(instance->widget); +} \ No newline at end of file diff --git a/applications/main/nfc/scenes/nfc_scene_save_success.c b/applications/main/nfc/scenes/nfc_scene_save_success.c index 106bcf94ffd7..0cb26c0d45af 100644 --- a/applications/main/nfc/scenes/nfc_scene_save_success.c +++ b/applications/main/nfc/scenes/nfc_scene_save_success.c @@ -25,16 +25,13 @@ bool nfc_scene_save_success_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == NfcCustomEventViewExit) { - // if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneMfClassicKeys)) { - // consumed = scene_manager_search_and_switch_to_previous_scene( - // nfc->scene_manager, NfcSceneMfClassicKeys); - // } else if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSavedMenu)) { - // consumed = scene_manager_search_and_switch_to_previous_scene( - // nfc->scene_manager, NfcSceneSavedMenu); - // } else { - consumed = scene_manager_search_and_switch_to_another_scene( - nfc->scene_manager, NfcSceneFileSelect); - // } + if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneMfClassicKeys)) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc->scene_manager, NfcSceneMfClassicKeys); + } else { + consumed = scene_manager_search_and_switch_to_another_scene( + nfc->scene_manager, NfcSceneFileSelect); + } } } return consumed; diff --git a/applications/main/nfc/views/dict_attack.c b/applications/main/nfc/views/dict_attack.c index 8f4bd063e8b8..b4a21bc57e13 100644 --- a/applications/main/nfc/views/dict_attack.c +++ b/applications/main/nfc/views/dict_attack.c @@ -2,42 +2,34 @@ #include -typedef enum { - DictAttackStateRead, - DictAttackStateCardRemoved, -} DictAttackState; - struct DictAttack { View* view; DictAttackCallback callback; void* context; - bool card_present; }; typedef struct { - DictAttackState state; - MfClassicType type; FuriString* header; + bool card_detected; uint8_t sectors_total; uint8_t sectors_read; - uint8_t sector_current; - uint8_t keys_total; + uint8_t current_sector; uint8_t keys_found; - uint16_t dict_keys_total; - uint16_t dict_keys_current; + size_t dict_keys_total; + size_t dict_keys_current; bool is_key_attack; uint8_t key_attack_current_sector; } DictAttackViewModel; static void dict_attack_draw_callback(Canvas* canvas, void* model) { DictAttackViewModel* m = model; - if(m->state == DictAttackStateCardRemoved) { + if(!m->card_detected) { canvas_set_font(canvas, FontPrimary); canvas_draw_str_aligned(canvas, 64, 4, AlignCenter, AlignTop, "Lost the tag!"); canvas_set_font(canvas, FontSecondary); elements_multiline_text_aligned( canvas, 64, 23, AlignCenter, AlignTop, "Make sure the tag is\npositioned correctly."); - } else if(m->state == DictAttackStateRead) { + } else { char draw_str[32] = {}; canvas_set_font(canvas, FontSecondary); canvas_draw_str_aligned( @@ -49,14 +41,14 @@ static void dict_attack_draw_callback(Canvas* canvas, void* model) { "Reuse key check for sector: %d", m->key_attack_current_sector); } else { - snprintf(draw_str, sizeof(draw_str), "Unlocking sector: %d", m->sector_current); + snprintf(draw_str, sizeof(draw_str), "Unlocking sector: %d", m->current_sector); } canvas_draw_str_aligned(canvas, 0, 10, AlignLeft, AlignTop, draw_str); float dict_progress = m->dict_keys_total == 0 ? 0 : (float)(m->dict_keys_current) / (float)(m->dict_keys_total); float progress = m->sectors_total == 0 ? 0 : - ((float)(m->sector_current) + dict_progress) / + ((float)(m->current_sector) + dict_progress) / (float)(m->sectors_total); if(progress > 1.0) { progress = 1.0; @@ -70,7 +62,8 @@ static void dict_attack_draw_callback(Canvas* canvas, void* model) { } elements_progress_bar_with_text(canvas, 0, 20, 128, dict_progress, draw_str); canvas_set_font(canvas, FontSecondary); - snprintf(draw_str, sizeof(draw_str), "Keys found: %d/%d", m->keys_found, m->keys_total); + snprintf( + draw_str, sizeof(draw_str), "Keys found: %d/%d", m->keys_found, m->sectors_total * 2); canvas_draw_str_aligned(canvas, 0, 33, AlignLeft, AlignTop, draw_str); snprintf( draw_str, sizeof(draw_str), "Sectors Read: %d/%d", m->sectors_read, m->sectors_total); @@ -80,55 +73,56 @@ static void dict_attack_draw_callback(Canvas* canvas, void* model) { } static bool dict_attack_input_callback(InputEvent* event, void* context) { - DictAttack* dict_attack = context; + DictAttack* instance = context; bool consumed = false; + if(event->type == InputTypeShort && event->key == InputKeyOk) { - if(dict_attack->callback) { - dict_attack->callback(dict_attack->context); + if(instance->callback) { + instance->callback(DictAttackEventSkipPressed, instance->context); } consumed = true; } + return consumed; } DictAttack* dict_attack_alloc() { - DictAttack* dict_attack = malloc(sizeof(DictAttack)); - dict_attack->view = view_alloc(); - view_allocate_model(dict_attack->view, ViewModelTypeLocking, sizeof(DictAttackViewModel)); - view_set_draw_callback(dict_attack->view, dict_attack_draw_callback); - view_set_input_callback(dict_attack->view, dict_attack_input_callback); - view_set_context(dict_attack->view, dict_attack); + DictAttack* instance = malloc(sizeof(DictAttack)); + instance->view = view_alloc(); + view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(DictAttackViewModel)); + view_set_draw_callback(instance->view, dict_attack_draw_callback); + view_set_input_callback(instance->view, dict_attack_input_callback); + view_set_context(instance->view, instance); with_view_model( - dict_attack->view, + instance->view, DictAttackViewModel * model, { model->header = furi_string_alloc(); }, false); - return dict_attack; + + return instance; } -void dict_attack_free(DictAttack* dict_attack) { - furi_assert(dict_attack); +void dict_attack_free(DictAttack* instance) { + furi_assert(instance); + with_view_model( - dict_attack->view, - DictAttackViewModel * model, - { furi_string_free(model->header); }, - false); - view_free(dict_attack->view); - free(dict_attack); + instance->view, DictAttackViewModel * model, { furi_string_free(model->header); }, false); + + view_free(instance->view); + free(instance); } -void dict_attack_reset(DictAttack* dict_attack) { - furi_assert(dict_attack); +void dict_attack_reset(DictAttack* instance) { + furi_assert(instance); + with_view_model( - dict_attack->view, + instance->view, DictAttackViewModel * model, { - model->state = DictAttackStateRead; - model->type = MfClassicType1k; + model->card_detected = false; model->sectors_total = 0; model->sectors_read = 0; - model->sector_current = 0; - model->keys_total = 0; + model->current_sector = 0; model->keys_found = 0; model->dict_keys_total = 0; model->dict_keys_current = 0; @@ -138,152 +132,108 @@ void dict_attack_reset(DictAttack* dict_attack) { false); } -View* dict_attack_get_view(DictAttack* dict_attack) { - furi_assert(dict_attack); - return dict_attack->view; +View* dict_attack_get_view(DictAttack* instance) { + furi_assert(instance); + + return instance->view; } -void dict_attack_set_callback(DictAttack* dict_attack, DictAttackCallback callback, void* context) { - furi_assert(dict_attack); +void dict_attack_set_callback(DictAttack* instance, DictAttackCallback callback, void* context) { + furi_assert(instance); furi_assert(callback); - dict_attack->callback = callback; - dict_attack->context = context; + + instance->callback = callback; + instance->context = context; } -void dict_attack_set_header(DictAttack* dict_attack, const char* header) { - furi_assert(dict_attack); +void dict_attack_set_header(DictAttack* instance, const char* header) { + furi_assert(instance); furi_assert(header); with_view_model( - dict_attack->view, + instance->view, DictAttackViewModel * model, { furi_string_set(model->header, header); }, true); } -void dict_attack_set_card_detected(DictAttack* dict_attack, MfClassicType type) { - furi_assert(dict_attack); - dict_attack->card_present = true; +void dict_attack_set_card_state(DictAttack* instance, bool detected) { + furi_assert(instance); + with_view_model( - dict_attack->view, - DictAttackViewModel * model, - { - model->state = DictAttackStateRead; - model->sectors_total = mf_classic_get_total_sectors_num(type); - model->keys_total = model->sectors_total * 2; - }, - true); + instance->view, DictAttackViewModel * model, { model->card_detected = detected; }, true); } -void dict_attack_set_card_removed(DictAttack* dict_attack) { - furi_assert(dict_attack); - dict_attack->card_present = false; +void dict_attack_set_sectors_total(DictAttack* instance, uint8_t sectors_total) { + furi_assert(instance); + with_view_model( - dict_attack->view, + instance->view, DictAttackViewModel * model, - { model->state = DictAttackStateCardRemoved; }, + { model->sectors_total = sectors_total; }, true); } -bool dict_attack_get_card_state(DictAttack* dict_attack) { - furi_assert(dict_attack); - return dict_attack->card_present; -} +void dict_attack_set_sectors_read(DictAttack* instance, uint8_t sectors_read) { + furi_assert(instance); -void dict_attack_set_sector_read(DictAttack* dict_attack, uint8_t sec_read) { - furi_assert(dict_attack); with_view_model( - dict_attack->view, DictAttackViewModel * model, { model->sectors_read = sec_read; }, true); + instance->view, DictAttackViewModel * model, { model->sectors_read = sectors_read; }, true); } -void dict_attack_set_keys_found(DictAttack* dict_attack, uint8_t keys_found) { - furi_assert(dict_attack); - with_view_model( - dict_attack->view, DictAttackViewModel * model, { model->keys_found = keys_found; }, true); -} +void dict_attack_set_keys_found(DictAttack* instance, uint8_t keys_found) { + furi_assert(instance); -void dict_attack_set_current_sector(DictAttack* dict_attack, uint8_t curr_sec) { - furi_assert(dict_attack); with_view_model( - dict_attack->view, - DictAttackViewModel * model, - { - model->sector_current = curr_sec; - model->dict_keys_current = 0; - }, - true); + instance->view, DictAttackViewModel * model, { model->keys_found = keys_found; }, true); } -void dict_attack_inc_current_sector(DictAttack* dict_attack) { - furi_assert(dict_attack); - with_view_model( - dict_attack->view, - DictAttackViewModel * model, - { - if(model->sector_current < model->sectors_total) { - model->sector_current++; - model->dict_keys_current = 0; - } - }, - true); -} +void dict_attack_set_current_sector(DictAttack* instance, uint8_t current_sector) { + furi_assert(instance); -void dict_attack_inc_keys_found(DictAttack* dict_attack) { - furi_assert(dict_attack); with_view_model( - dict_attack->view, + instance->view, DictAttackViewModel * model, - { - if(model->keys_found < model->keys_total) { - model->keys_found++; - } - }, + { model->current_sector = current_sector; }, true); } -void dict_attack_set_total_dict_keys(DictAttack* dict_attack, uint16_t dict_keys_total) { - furi_assert(dict_attack); +void dict_attack_set_total_dict_keys(DictAttack* instance, size_t dict_keys_total) { + furi_assert(instance); + with_view_model( - dict_attack->view, + instance->view, DictAttackViewModel * model, { model->dict_keys_total = dict_keys_total; }, true); } -void dict_attack_inc_current_dict_key(DictAttack* dict_attack, uint16_t keys_tried) { - furi_assert(dict_attack); +void dict_attack_set_current_dict_key(DictAttack* instance, size_t cur_key_num) { + furi_assert(instance); + with_view_model( - dict_attack->view, + instance->view, DictAttackViewModel * model, - { - if(model->dict_keys_current + keys_tried < model->dict_keys_total) { - model->dict_keys_current += keys_tried; - } - }, + { model->dict_keys_current = cur_key_num; }, true); } -void dict_attack_set_key_attack(DictAttack* dict_attack, bool is_key_attack, uint8_t sector) { - furi_assert(dict_attack); +void dict_attack_set_key_attack(DictAttack* instance, uint8_t sector) { + furi_assert(instance); + with_view_model( - dict_attack->view, + instance->view, DictAttackViewModel * model, { - model->is_key_attack = is_key_attack; + model->is_key_attack = true; model->key_attack_current_sector = sector; }, true); } -void dict_attack_inc_key_attack_current_sector(DictAttack* dict_attack) { - furi_assert(dict_attack); +void dict_attack_reset_key_attack(DictAttack* instance) { + furi_assert(instance); + with_view_model( - dict_attack->view, - DictAttackViewModel * model, - { - if(model->key_attack_current_sector < model->sectors_total) { - model->key_attack_current_sector++; - } - }, - true); + instance->view, DictAttackViewModel * model, { model->is_key_attack = false; }, true); } diff --git a/applications/main/nfc/views/dict_attack.h b/applications/main/nfc/views/dict_attack.h index 940fb74e9685..54a0220fe590 100644 --- a/applications/main/nfc/views/dict_attack.h +++ b/applications/main/nfc/views/dict_attack.h @@ -1,46 +1,50 @@ #pragma once + #include #include -#include -#include +#ifdef __cplusplus +extern "C" { +#endif typedef struct DictAttack DictAttack; -typedef void (*DictAttackCallback)(void* context); - -DictAttack* dict_attack_alloc(); +typedef enum { + DictAttackEventSkipPressed, +} DictAttackEvent; -void dict_attack_free(DictAttack* dict_attack); +typedef void (*DictAttackCallback)(DictAttackEvent event, void* context); -void dict_attack_reset(DictAttack* dict_attack); +DictAttack* dict_attack_alloc(); -View* dict_attack_get_view(DictAttack* dict_attack); +void dict_attack_free(DictAttack* instance); -void dict_attack_set_callback(DictAttack* dict_attack, DictAttackCallback callback, void* context); +void dict_attack_reset(DictAttack* instance); -void dict_attack_set_header(DictAttack* dict_attack, const char* header); +View* dict_attack_get_view(DictAttack* instance); -void dict_attack_set_card_detected(DictAttack* dict_attack, MfClassicType type); +void dict_attack_set_callback(DictAttack* instance, DictAttackCallback callback, void* context); -void dict_attack_set_card_removed(DictAttack* dict_attack); +void dict_attack_set_header(DictAttack* instance, const char* header); -bool dict_attack_get_card_state(DictAttack* dict_attack); +void dict_attack_set_card_state(DictAttack* instance, bool detected); -void dict_attack_set_sector_read(DictAttack* dict_attack, uint8_t sec_read); +void dict_attack_set_sectors_total(DictAttack* instance, uint8_t sectors_total); -void dict_attack_set_keys_found(DictAttack* dict_attack, uint8_t keys_found); +void dict_attack_set_sectors_read(DictAttack* instance, uint8_t sectors_read); -void dict_attack_set_current_sector(DictAttack* dict_attack, uint8_t curr_sec); +void dict_attack_set_keys_found(DictAttack* instance, uint8_t keys_found); -void dict_attack_inc_current_sector(DictAttack* dict_attack); +void dict_attack_set_current_sector(DictAttack* instance, uint8_t curr_sec); -void dict_attack_inc_keys_found(DictAttack* dict_attack); +void dict_attack_set_total_dict_keys(DictAttack* instance, size_t dict_keys_total); -void dict_attack_set_total_dict_keys(DictAttack* dict_attack, uint16_t dict_keys_total); +void dict_attack_set_current_dict_key(DictAttack* instance, size_t cur_key_num); -void dict_attack_inc_current_dict_key(DictAttack* dict_attack, uint16_t keys_tried); +void dict_attack_set_key_attack(DictAttack* instance, uint8_t sector); -void dict_attack_set_key_attack(DictAttack* dict_attack, bool is_key_attack, uint8_t sector); +void dict_attack_reset_key_attack(DictAttack* instance); -void dict_attack_inc_key_attack_current_sector(DictAttack* dict_attack); \ No newline at end of file +#ifdef __cplusplus +} +#endif diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 2486c0b72cdd..62bf6b0b8376 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,+,36.0,, +Version,+,35.2,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -2078,6 +2078,7 @@ Function,-,mf_classic_get_total_block_num,uint16_t,MfClassicType Function,+,mf_classic_get_total_sectors_num,uint8_t,MfClassicType Function,+,mf_classic_get_uid,const uint8_t*,"const MfClassicData*, size_t*" Function,+,mf_classic_is_allowed_access,_Bool,"MfClassicData*, uint8_t, MfClassicKeyType, MfClassicAction" +Function,+,mf_classic_is_allowed_access_data_block,_Bool,"MfClassicSectorTrailer*, uint8_t, MfClassicKeyType, MfClassicAction" Function,+,mf_classic_is_block_read,_Bool,"const MfClassicData*, uint8_t" Function,+,mf_classic_is_card_read,_Bool,const MfClassicData* Function,+,mf_classic_is_equal,_Bool,"const MfClassicData*, const MfClassicData*" @@ -2088,6 +2089,7 @@ Function,-,mf_classic_is_value_block,_Bool,"MfClassicData*, uint8_t" Function,+,mf_classic_load,_Bool,"MfClassicData*, FlipperFormat*, uint32_t" Function,+,mf_classic_poller_auth,MfClassicError,"Nfc*, uint8_t, MfClassicKey*, MfClassicKeyType, MfClassicAuthContext*" Function,+,mf_classic_poller_change_value,MfClassicError,"Nfc*, uint8_t, MfClassicKey*, MfClassicKeyType, int32_t, int32_t*" +Function,+,mf_classic_poller_read,MfClassicError,"Nfc*, const MfClassicDeviceKeys*, MfClassicData*" Function,+,mf_classic_poller_read_block,MfClassicError,"Nfc*, uint8_t, MfClassicKey*, MfClassicKeyType, MfClassicBlock*" Function,+,mf_classic_poller_read_value,MfClassicError,"Nfc*, uint8_t, MfClassicKey*, MfClassicKeyType, int32_t*" Function,+,mf_classic_poller_write_block,MfClassicError,"Nfc*, uint8_t, MfClassicKey*, MfClassicKeyType, MfClassicBlock*" diff --git a/lib/nfc/protocols/mf_classic/mf_classic.c b/lib/nfc/protocols/mf_classic/mf_classic.c index 71d3e5147d02..ad9a8551f470 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic.c +++ b/lib/nfc/protocols/mf_classic/mf_classic.c @@ -370,32 +370,29 @@ bool mf_classic_detect_protocol(Iso14443_3aData* data, MfClassicType* type) { uint8_t atqa1 = data->atqa[1]; uint8_t sak = data->sak; bool mf_classic_detected = false; + MfClassicType tmp_type = MfClassicTypeMini; - if((atqa0 = 0x44) || (atqa0 = 0x44)) { - if((sak == 0x08) || (sak = 0x88)) { - if(type) { - *type = MfClassicType1k; - } + if((atqa0 == 0x44) || (atqa0 == 0x04)) { + if((sak == 0x08) || (sak == 0x88)) { + tmp_type = MfClassicType1k; mf_classic_detected = true; } else if(sak == 0x09) { - if(type) { - *type = MfClassicTypeMini; - } + tmp_type = MfClassicTypeMini; mf_classic_detected = true; } } else if((atqa0 == 0x01) && (atqa1 == 0x0f) && (sak == 0x01)) { // Skylender support - if(type) { - *type = MfClassicType1k; - } + tmp_type = MfClassicType1k; mf_classic_detected = true; } else if(((atqa0 == 0x42) || (atqa0 == 0x02)) && (sak == 0x18)) { - if(*type) { - *type = MfClassicType4k; - } + tmp_type = MfClassicType4k; mf_classic_detected = true; } + if(type) { + *type = tmp_type; + } + return mf_classic_detected; } @@ -673,13 +670,13 @@ static bool mf_classic_is_allowed_access_sector_trailer( return true; } -static bool mf_classic_is_allowed_access_data_block( - MfClassicData* data, +bool mf_classic_is_allowed_access_data_block( + MfClassicSectorTrailer* sec_tr, uint8_t block_num, MfClassicKeyType key_type, MfClassicAction action) { - uint8_t sector_num = mf_classic_get_sector_by_block(block_num); - MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(data, sector_num); + furi_assert(sec_tr); + uint8_t* access_bits_arr = sec_tr->access_bits.data; if(block_num == 0 && action == MfClassicActionDataWrite) { @@ -755,8 +752,10 @@ bool mf_classic_is_allowed_access( access_allowed = mf_classic_is_allowed_access_sector_trailer(data, block_num, key_type, action); } else { + uint8_t sector_num = mf_classic_get_sector_by_block(block_num); + MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(data, sector_num); access_allowed = - mf_classic_is_allowed_access_data_block(data, block_num, key_type, action); + mf_classic_is_allowed_access_data_block(sec_tr, block_num, key_type, action); } return access_allowed; @@ -765,11 +764,14 @@ bool mf_classic_is_allowed_access( bool mf_classic_is_value_block(MfClassicData* data, uint8_t block_num) { furi_assert(data); + uint8_t sector_num = mf_classic_get_sector_by_block(block_num); + MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(data, sector_num); + // Check if key A can write, if it can, it's transport configuration, not data block return !mf_classic_is_allowed_access_data_block( - data, block_num, MfClassicKeyTypeA, MfClassicActionDataWrite) && + sec_tr, block_num, MfClassicKeyTypeA, MfClassicActionDataWrite) && (mf_classic_is_allowed_access_data_block( - data, block_num, MfClassicKeyTypeB, MfClassicActionDataInc) || + sec_tr, block_num, MfClassicKeyTypeB, MfClassicActionDataInc) || mf_classic_is_allowed_access_data_block( - data, block_num, MfClassicKeyTypeB, MfClassicActionDataDec)); + sec_tr, block_num, MfClassicKeyTypeB, MfClassicActionDataDec)); } diff --git a/lib/nfc/protocols/mf_classic/mf_classic.h b/lib/nfc/protocols/mf_classic/mf_classic.h index 312cb7ed3618..47a8649af661 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic.h +++ b/lib/nfc/protocols/mf_classic/mf_classic.h @@ -120,10 +120,10 @@ typedef struct { } MfClassicSectorTrailer; typedef struct { - MfClassicKey key_a[MF_CLASSIC_TOTAL_SECTORS_MAX]; - MfClassicKey key_b[MF_CLASSIC_TOTAL_SECTORS_MAX]; uint64_t key_a_mask; + MfClassicKey key_a[MF_CLASSIC_TOTAL_SECTORS_MAX]; uint64_t key_b_mask; + MfClassicKey key_b[MF_CLASSIC_TOTAL_SECTORS_MAX]; } MfClassicDeviceKeys; typedef struct { @@ -217,6 +217,12 @@ void mf_classic_get_read_sectors_and_keys( bool mf_classic_is_card_read(const MfClassicData* data); +bool mf_classic_is_allowed_access_data_block( + MfClassicSectorTrailer* sec_tr, + uint8_t block_num, + MfClassicKeyType key_type, + MfClassicAction action); + bool mf_classic_is_allowed_access( MfClassicData* data, uint8_t block_num, diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller.c b/lib/nfc/protocols/mf_classic/mf_classic_poller.c index 0d11dc2574a2..b8def569b54f 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller.c @@ -50,82 +50,315 @@ void mf_classic_poller_free(MfClassicPoller* instance) { free(instance); } -NfcCommand mf_classic_poller_handler_idle(MfClassicPoller* instance) { +static NfcCommand mf_classic_poller_handle_data_update(MfClassicPoller* instance) { + MfClassicPollerEventDataUpdate* data_update = &instance->mfc_event_data.data_update; + + mf_classic_get_read_sectors_and_keys( + instance->data, &data_update->sectors_read, &data_update->keys_found); + data_update->current_sector = instance->mode_ctx.dict_attack_ctx.current_sector; + instance->mfc_event.type = MfClassicPollerEventTypeDataUpdate; + return instance->callback(instance->general_event, instance->context); +} + +NfcCommand mf_classic_poller_handler_start(MfClassicPoller* instance) { + NfcCommand command = NfcCommandContinue; + iso14443_3a_copy( instance->data->iso14443_3a_data, iso14443_3a_poller_get_data(instance->iso14443_3a_poller)); + mf_classic_detect_protocol(instance->data->iso14443_3a_data, &instance->data->type); + instance->sectors_total = mf_classic_get_total_sectors_num(instance->data->type); + + memset(&instance->mode_ctx, 0, sizeof(MfClassicPollerModeContext)); + + instance->mfc_event.type = MfClassicPollerEventTypeRequestMode; + command = instance->callback(instance->general_event, instance->context); + + if(instance->mfc_event_data.poller_mode.mode == MfClassicPollerModeDictAttack) { + mf_classic_copy(instance->data, instance->mfc_event_data.poller_mode.data); + instance->state = MfClassicPollerStateRequestKey; + } else if(instance->mfc_event_data.poller_mode.mode == MfClassicPollerModeRead) { + instance->state = MfClassicPollerStateRequestReadSector; + } else if(instance->mfc_event_data.poller_mode.mode == MfClassicPollerModeWrite) { + instance->state = MfClassicPollerStateRequestSectorTrailer; + } else { + furi_crash("Invalid mode selected"); + } + + return command; +} + +NfcCommand mf_classic_poller_handler_request_sector_trailer(MfClassicPoller* instance) { NfcCommand command = NfcCommandContinue; + MfClassicPollerWriteContext* write_ctx = &instance->mode_ctx.write_ctx; - if(mf_classic_detect_protocol(instance->data->iso14443_3a_data, &instance->data->type)) { - if(instance->card_state == MfClassicCardStateNotDetected) { - instance->card_state = MfClassicCardStateDetected; - instance->mfc_event.type = MfClassicPollerEventTypeCardDetected; - command = instance->callback(instance->general_event, instance->context); + if(write_ctx->current_sector == instance->sectors_total) { + instance->state = MfClassicPollerStateSuccess; + } else { + instance->mfc_event.type = MfClassicPollerEventTypeRequestSectorTrailer; + instance->mfc_event_data.sec_tr_data.sector_num = write_ctx->current_sector; + command = instance->callback(instance->general_event, instance->context); + if(instance->mfc_event_data.sec_tr_data.sector_trailer_provided) { + instance->state = MfClassicPollerStateCheckWriteConditions; + memcpy( + &write_ctx->sec_tr, + &instance->mfc_event_data.sec_tr_data.sector_trailer, + sizeof(MfClassicSectorTrailer)); + write_ctx->current_block = + MAX(1, mf_classic_get_first_block_num_of_sector(write_ctx->current_sector)); + + } else { + write_ctx->current_sector++; } - instance->state = instance->prev_state; } return command; } -NfcCommand mf_classic_poller_handler_start(MfClassicPoller* instance) { +NfcCommand mf_classic_handler_check_write_conditions(MfClassicPoller* instance) { NfcCommand command = NfcCommandContinue; - instance->sectors_read = 0; - instance->sectors_total = mf_classic_get_total_sectors_num(instance->data->type); + MfClassicPollerWriteContext* write_ctx = &instance->mode_ctx.write_ctx; + MfClassicSectorTrailer* sec_tr = &write_ctx->sec_tr; - instance->mfc_event_data.start_data.type = instance->data->type; - command = instance->callback(instance->general_event, instance->context); + do { + // Check last block in sector to write + uint8_t sec_tr_block_num = + mf_classic_get_sector_trailer_num_by_sector(write_ctx->current_sector); + if(write_ctx->current_block == sec_tr_block_num) { + write_ctx->current_sector++; + instance->state = MfClassicPollerStateRequestSectorTrailer; + break; + } + + // Check write and read access + if(mf_classic_is_allowed_access_data_block( + sec_tr, write_ctx->current_block, MfClassicKeyTypeA, MfClassicActionDataWrite)) { + write_ctx->key_type_write = MfClassicKeyTypeA; + } else if(mf_classic_is_allowed_access_data_block( + sec_tr, + write_ctx->current_block, + MfClassicKeyTypeB, + MfClassicActionDataWrite)) { + write_ctx->key_type_write = MfClassicKeyTypeB; + } else { + FURI_LOG_D(TAG, "Not allowed to write block %d", write_ctx->current_block); + write_ctx->current_block++; + break; + } + + if(mf_classic_is_allowed_access_data_block( + sec_tr, + write_ctx->current_block, + write_ctx->key_type_write, + MfClassicActionDataRead)) { + write_ctx->key_type_read = write_ctx->key_type_write; + } else { + write_ctx->key_type_read = write_ctx->key_type_write == MfClassicKeyTypeA ? + MfClassicKeyTypeB : + MfClassicKeyTypeA; + if(!mf_classic_is_allowed_access_data_block( + sec_tr, + write_ctx->current_block, + write_ctx->key_type_read, + MfClassicActionDataRead)) { + FURI_LOG_D(TAG, "Not allowed to read block %d", write_ctx->current_block); + write_ctx->current_block++; + break; + } + } - instance->prev_state = MfClassicPollerStateStart; - instance->state = MfClassicPollerStateNewSector; + write_ctx->need_halt_before_write = + (write_ctx->key_type_read != write_ctx->key_type_write); + instance->state = MfClassicPollerStateReadBlock; + } while(false); return command; } -NfcCommand mf_classic_poller_handler_new_sector(MfClassicPoller* instance) { +NfcCommand mf_classic_poller_handler_read_block(MfClassicPoller* instance) { NfcCommand command = NfcCommandContinue; + MfClassicPollerWriteContext* write_ctx = &instance->mode_ctx.write_ctx; + + MfClassicKey* auth_key = write_ctx->key_type_read == MfClassicKeyTypeA ? + &write_ctx->sec_tr.key_a : + &write_ctx->sec_tr.key_b; + MfClassicError error = MfClassicErrorNone; + + do { + // Authenticate to sector + error = mf_classic_async_auth( + instance, write_ctx->current_block, auth_key, write_ctx->key_type_read, NULL); + if(error != MfClassicErrorNone) { + FURI_LOG_D(TAG, "Failed to auth to block %d", write_ctx->current_block); + instance->state = MfClassicPollerStateFail; + break; + } - if(instance->read_mode == MfClassicReadModeKeyReuse) { - instance->key_reuse_sector++; - if(instance->key_reuse_sector == instance->sectors_total) { - instance->read_mode = MfClassicReadModeDictAttack; - instance->mfc_event.type = MfClassicPollerEventTypeKeyAttackStop; - command = instance->callback(instance->general_event, instance->context); - } else if(mf_classic_is_sector_read(instance->data, instance->sectors_read)) { - instance->mfc_event.type = MfClassicPollerEventTypeKeyAttackNextSector; - command = instance->callback(instance->general_event, instance->context); - } else { - instance->state = MfClassicPollerStateAuthKeyA; - instance->mfc_event.type = MfClassicPollerEventTypeKeyAttackNextSector; - command = instance->callback(instance->general_event, instance->context); + // Read block from tag + error = + mf_classic_async_read_block(instance, write_ctx->current_block, &write_ctx->tag_block); + if(error != MfClassicErrorNone) { + FURI_LOG_D(TAG, "Failed to read block %d", write_ctx->current_block); + instance->state = MfClassicPollerStateFail; + break; + } + + if(write_ctx->need_halt_before_write) { + mf_classic_async_halt(instance); + } + instance->state = MfClassicPollerStateWriteBlock; + } while(false); + + return command; +} + +NfcCommand mf_classic_poller_handler_write_block(MfClassicPoller* instance) { + NfcCommand command = NfcCommandContinue; + + MfClassicPollerWriteContext* write_ctx = &instance->mode_ctx.write_ctx; + MfClassicKey* auth_key = write_ctx->key_type_write == MfClassicKeyTypeA ? + &write_ctx->sec_tr.key_a : + &write_ctx->sec_tr.key_b; + MfClassicError error = MfClassicErrorNone; + + do { + // Request block to write + instance->mfc_event.type = MfClassicPollerEventTypeRequestWriteBlock; + instance->mfc_event_data.write_block_data.block_num = write_ctx->current_block; + command = instance->callback(instance->general_event, instance->context); + if(!instance->mfc_event_data.write_block_data.write_block_provided) break; + + // Compare tag and saved block + if(memcmp( + write_ctx->tag_block.data, + instance->mfc_event_data.write_block_data.write_block.data, + sizeof(MfClassicBlock)) == 0) { + FURI_LOG_D(TAG, "Block %d is equal. Skip writing", write_ctx->current_block); + break; + } + + // Reauth if necessary + if(write_ctx->need_halt_before_write) { + error = mf_classic_async_auth( + instance, write_ctx->current_block, auth_key, write_ctx->key_type_write, NULL); + if(error != MfClassicErrorNone) { + FURI_LOG_D( + TAG, "Failed to auth to block %d for writing", write_ctx->current_block); + instance->state = MfClassicPollerStateFail; + break; + } + } + + // Write block + error = mf_classic_async_write_block( + instance, + write_ctx->current_block, + &instance->mfc_event_data.write_block_data.write_block); + if(error != MfClassicErrorNone) { + FURI_LOG_D(TAG, "Failed to write block %d", write_ctx->current_block); + instance->state = MfClassicPollerStateFail; + break; } + + } while(false); + + mf_classic_async_halt(instance); + write_ctx->current_block++; + instance->state = MfClassicPollerStateCheckWriteConditions; + + return command; +} + +NfcCommand mf_classic_poller_handler_request_read_sector(MfClassicPoller* instance) { + NfcCommand command = NfcCommandContinue; + + MfClassicPollerReadContext* sec_read_ctx = &instance->mode_ctx.read_ctx; + MfClassicPollerEventDataReadSectorRequest* sec_read = + &instance->mfc_event_data.read_sector_request_data; + instance->mfc_event.type = MfClassicPollerEventTypeRequestReadSector; + command = instance->callback(instance->general_event, instance->context); + + if(!sec_read->key_provided) { + instance->state = MfClassicPollerStateSuccess; } else { - if(instance->sectors_read == instance->sectors_total) { - instance->state = MfClassicPollerStateReadComplete; - } else if(mf_classic_is_sector_read(instance->data, instance->sectors_read)) { - instance->sectors_read++; - instance->mfc_event.type = MfClassicPollerEventTypeNewSector; - command = instance->callback(instance->general_event, instance->context); + sec_read_ctx->current_sector = sec_read->sector_num; + sec_read_ctx->key = sec_read->key; + sec_read_ctx->key_type = sec_read->key_type; + sec_read_ctx->current_block = + mf_classic_get_first_block_num_of_sector(sec_read->sector_num); + sec_read_ctx->auth_passed = false; + instance->state = MfClassicPollerStateReadSectorBlocks; + } + + return command; +} + +NfcCommand mf_classic_poller_handler_request_read_sector_blocks(MfClassicPoller* instance) { + NfcCommand command = NfcCommandContinue; + + MfClassicPollerReadContext* sec_read_ctx = &instance->mode_ctx.read_ctx; + + do { + MfClassicError error = MfClassicErrorNone; + + if(!sec_read_ctx->auth_passed) { + uint64_t key = nfc_util_bytes2num(sec_read_ctx->key.data, sizeof(MfClassicKey)); + FURI_LOG_D( + TAG, + "Auth to block %d with key %c: %06llx", + sec_read_ctx->current_block, + sec_read_ctx->key_type == MfClassicKeyTypeA ? 'A' : 'B', + key); + error = mf_classic_async_auth( + instance, + sec_read_ctx->current_block, + &sec_read_ctx->key, + sec_read_ctx->key_type, + NULL); + if(error != MfClassicErrorNone) break; + + sec_read_ctx->auth_passed = true; + if(!mf_classic_is_key_found( + instance->data, sec_read_ctx->current_sector, sec_read_ctx->key_type)) { + mf_classic_set_key_found( + instance->data, sec_read_ctx->current_sector, sec_read_ctx->key_type, key); + } + } + if(mf_classic_is_block_read(instance->data, sec_read_ctx->current_block)) break; + + FURI_LOG_D(TAG, "Reading block %d", sec_read_ctx->current_block); + MfClassicBlock read_block = {}; + error = mf_classic_async_read_block(instance, sec_read_ctx->current_block, &read_block); + if(error == MfClassicErrorNone) { + mf_classic_set_block_read(instance->data, sec_read_ctx->current_block, &read_block); } else { - instance->state = MfClassicPollerStateRequestKey; + mf_classic_async_halt(instance); + sec_read_ctx->auth_passed = false; } + } while(false); + + uint8_t sec_tr_num = mf_classic_get_sector_trailer_num_by_sector(sec_read_ctx->current_sector); + sec_read_ctx->current_block++; + if(sec_read_ctx->current_block > sec_tr_num) { + mf_classic_async_halt(instance); + instance->state = MfClassicPollerStateRequestReadSector; } - instance->prev_state = instance->state; return command; } NfcCommand mf_classic_poller_handler_request_key(MfClassicPoller* instance) { NfcCommand command = NfcCommandContinue; + MfClassicPollerDictAttackContext* dict_attack_ctx = &instance->mode_ctx.dict_attack_ctx; - instance->mfc_event_data.key_request_data.sector_num = instance->sectors_read; + instance->mfc_event.type = MfClassicPollerEventTypeRequestKey; command = instance->callback(instance->general_event, instance->context); if(instance->mfc_event_data.key_request_data.key_provided) { - instance->current_key = instance->mfc_event_data.key_request_data.key; + dict_attack_ctx->current_key = instance->mfc_event_data.key_request_data.key; instance->state = MfClassicPollerStateAuthKeyA; } else { - instance->state = MfClassicPollerStateNewSector; + instance->state = MfClassicPollerStateNextSector; } return command; @@ -133,47 +366,31 @@ NfcCommand mf_classic_poller_handler_request_key(MfClassicPoller* instance) { NfcCommand mf_classic_poller_handler_auth_a(MfClassicPoller* instance) { NfcCommand command = NfcCommandContinue; + MfClassicPollerDictAttackContext* dict_attack_ctx = &instance->mode_ctx.dict_attack_ctx; - uint8_t sector = 0; - if(instance->read_mode == MfClassicReadModeKeyReuse) { - sector = instance->key_reuse_sector; - } else { - sector = instance->sectors_read; - } - - if(mf_classic_is_key_found(instance->data, sector, MfClassicKeyTypeA)) { - instance->prev_state = instance->state; + if(mf_classic_is_key_found( + instance->data, dict_attack_ctx->current_sector, MfClassicKeyTypeA)) { instance->state = MfClassicPollerStateAuthKeyB; } else { - uint8_t block = mf_classic_get_first_block_num_of_sector(sector); - uint64_t key = nfc_util_bytes2num(instance->current_key.data, 6); + uint8_t block = mf_classic_get_first_block_num_of_sector(dict_attack_ctx->current_sector); + uint64_t key = nfc_util_bytes2num(dict_attack_ctx->current_key.data, sizeof(MfClassicKey)); FURI_LOG_D(TAG, "Auth to block %d with key A: %06llx", block, key); MfClassicError error = mf_classic_async_auth( - instance, block, &instance->current_key, MfClassicKeyTypeA, NULL); + instance, block, &dict_attack_ctx->current_key, MfClassicKeyTypeA, NULL); if(error == MfClassicErrorNone) { FURI_LOG_I(TAG, "Key A found"); - mf_classic_set_key_found(instance->data, sector, MfClassicKeyTypeA, key); - if(instance->read_mode != MfClassicReadModeKeyReuse) { - if(sector < instance->sectors_total - 1) { - instance->read_mode = MfClassicReadModeKeyReuse; - instance->key_reuse_sector = sector; - instance->mfc_event.type = MfClassicPollerEventTypeKeyAttackStart; - instance->mfc_event_data.key_attack_data.start_sector = - instance->key_reuse_sector; - command = instance->callback(instance->general_event, instance->context); - } - } - instance->mfc_event.type = MfClassicPollerEventTypeFoundKeyA; - command = instance->callback(instance->general_event, instance->context); - instance->prev_state = instance->state; + mf_classic_set_key_found( + instance->data, dict_attack_ctx->current_sector, MfClassicKeyTypeA, key); + + command = mf_classic_poller_handle_data_update(instance); + dict_attack_ctx->current_key_type = MfClassicKeyTypeA; + dict_attack_ctx->current_block = block; + dict_attack_ctx->auth_passed = true; instance->state = MfClassicPollerStateReadSector; } else { - if(instance->read_mode == MfClassicReadModeKeyReuse) { - instance->state = MfClassicPollerStateAuthKeyB; - } else { - instance->state = MfClassicPollerStateRequestKey; - } + mf_classic_async_halt(instance); + instance->state = MfClassicPollerStateAuthKeyB; } } @@ -182,100 +399,308 @@ NfcCommand mf_classic_poller_handler_auth_a(MfClassicPoller* instance) { NfcCommand mf_classic_poller_handler_auth_b(MfClassicPoller* instance) { NfcCommand command = NfcCommandContinue; + MfClassicPollerDictAttackContext* dict_attack_ctx = &instance->mode_ctx.dict_attack_ctx; - uint8_t sector = 0; - if(instance->read_mode == MfClassicReadModeKeyReuse) { - sector = instance->key_reuse_sector; - } else { - sector = instance->sectors_read; - } - - if(mf_classic_is_key_found(instance->data, sector, MfClassicKeyTypeB)) { - instance->state = MfClassicPollerStateNewSector; + if(mf_classic_is_key_found( + instance->data, dict_attack_ctx->current_sector, MfClassicKeyTypeB)) { + if(mf_classic_is_key_found( + instance->data, dict_attack_ctx->current_sector, MfClassicKeyTypeA)) { + instance->state = MfClassicPollerStateNextSector; + } else { + instance->state = MfClassicPollerStateRequestKey; + } } else { - uint8_t block = mf_classic_get_first_block_num_of_sector(sector); - uint64_t key = nfc_util_bytes2num(instance->current_key.data, 6); + uint8_t block = mf_classic_get_first_block_num_of_sector(dict_attack_ctx->current_sector); + uint64_t key = nfc_util_bytes2num(dict_attack_ctx->current_key.data, sizeof(MfClassicKey)); FURI_LOG_D(TAG, "Auth to block %d with key B: %06llx", block, key); MfClassicError error = mf_classic_async_auth( - instance, block, &instance->current_key, MfClassicKeyTypeB, NULL); + instance, block, &dict_attack_ctx->current_key, MfClassicKeyTypeB, NULL); if(error == MfClassicErrorNone) { - FURI_LOG_D(TAG, "Key B found"); - instance->mfc_event.type = MfClassicPollerEventTypeFoundKeyB; - mf_classic_set_key_found(instance->data, sector, MfClassicKeyTypeB, key); - if(instance->read_mode != MfClassicReadModeKeyReuse) { - if(sector < instance->sectors_total - 1) { - instance->read_mode = MfClassicReadModeKeyReuse; - instance->key_reuse_sector = sector; - - instance->mfc_event.type = MfClassicPollerEventTypeKeyAttackStart; - instance->mfc_event_data.key_attack_data.start_sector = - instance->key_reuse_sector; - command = instance->callback(instance->general_event, instance->context); - } - } - command = instance->callback(instance->general_event, instance->context); + FURI_LOG_I(TAG, "Key B found"); + mf_classic_set_key_found( + instance->data, dict_attack_ctx->current_sector, MfClassicKeyTypeB, key); + + command = mf_classic_poller_handle_data_update(instance); + dict_attack_ctx->current_key_type = MfClassicKeyTypeB; + dict_attack_ctx->current_block = block; + + dict_attack_ctx->auth_passed = true; instance->state = MfClassicPollerStateReadSector; } else { - if(instance->read_mode == MfClassicReadModeKeyReuse) { - instance->state = MfClassicPollerStateNewSector; - } else { - instance->state = MfClassicPollerStateRequestKey; - } + mf_classic_async_halt(instance); + instance->state = MfClassicPollerStateRequestKey; } } - instance->prev_state = instance->state; + + return command; +} + +NfcCommand mf_classic_poller_handler_next_sector(MfClassicPoller* instance) { + NfcCommand command = NfcCommandContinue; + MfClassicPollerDictAttackContext* dict_attack_ctx = &instance->mode_ctx.dict_attack_ctx; + + dict_attack_ctx->current_sector++; + if(dict_attack_ctx->current_sector == instance->sectors_total) { + instance->state = MfClassicPollerStateSuccess; + } else { + instance->mfc_event.type = MfClassicPollerEventTypeNextSector; + instance->mfc_event_data.next_sector_data.current_sector = dict_attack_ctx->current_sector; + command = instance->callback(instance->general_event, instance->context); + instance->state = MfClassicPollerStateRequestKey; + } return command; } NfcCommand mf_classic_poller_handler_read_sector(MfClassicPoller* instance) { NfcCommand command = NfcCommandContinue; + MfClassicPollerDictAttackContext* dict_attack_ctx = &instance->mode_ctx.dict_attack_ctx; - uint8_t block_start = mf_classic_get_first_block_num_of_sector(instance->sectors_read); - uint8_t total_blocks = mf_classic_get_blocks_num_in_sector(instance->sectors_read); + MfClassicError error = MfClassicErrorNone; + uint8_t block_num = dict_attack_ctx->current_block; MfClassicBlock block = {}; - for(size_t i = block_start; i < block_start + total_blocks; i++) { - FURI_LOG_D(TAG, "Reding block %d", i); - if(mf_classic_is_block_read(instance->data, i)) continue; - MfClassicError error = mf_classic_async_read_block(instance, i, &block); + do { + if(mf_classic_is_block_read(instance->data, block_num)) break; + + if(!dict_attack_ctx->auth_passed) { + error = mf_classic_async_auth( + instance, + block_num, + &dict_attack_ctx->current_key, + dict_attack_ctx->current_key_type, + NULL); + if(error != MfClassicErrorNone) { + instance->state = MfClassicPollerStateNextSector; + FURI_LOG_W(TAG, "Failed to re-auth. Go to next sector"); + break; + } + } + + FURI_LOG_D(TAG, "Reading block %d", block_num); + error = mf_classic_async_read_block(instance, block_num, &block); + + if(error != MfClassicErrorNone) { + mf_classic_async_halt(instance); + dict_attack_ctx->auth_passed = false; + FURI_LOG_D(TAG, "Failed to read block %d", block_num); + } else { + mf_classic_set_block_read(instance->data, block_num, &block); + } + } while(false); + + uint8_t sec_tr_block_num = + mf_classic_get_sector_trailer_num_by_sector(dict_attack_ctx->current_sector); + dict_attack_ctx->current_block++; + if(dict_attack_ctx->current_block > sec_tr_block_num) { + mf_classic_poller_handle_data_update(instance); + + mf_classic_async_halt(instance); + dict_attack_ctx->auth_passed = false; + + if(dict_attack_ctx->current_sector == instance->sectors_total) { + instance->state = MfClassicPollerStateNextSector; + } else { + dict_attack_ctx->reuse_key_sector = dict_attack_ctx->current_sector; + instance->mfc_event.type = MfClassicPollerEventTypeKeyAttackStart; + instance->mfc_event_data.key_attack_data.current_sector = + dict_attack_ctx->reuse_key_sector; + command = instance->callback(instance->general_event, instance->context); + instance->state = MfClassicPollerStateKeyReuseStart; + } + } + + return command; +} + +NfcCommand mf_classic_poller_handler_key_reuse_start(MfClassicPoller* instance) { + NfcCommand command = NfcCommandContinue; + MfClassicPollerDictAttackContext* dict_attack_ctx = &instance->mode_ctx.dict_attack_ctx; + + if(dict_attack_ctx->current_key_type == MfClassicKeyTypeA) { + dict_attack_ctx->current_key_type = MfClassicKeyTypeB; + instance->state = MfClassicPollerStateKeyReuseAuthKeyB; + } else { + dict_attack_ctx->reuse_key_sector++; + if(dict_attack_ctx->reuse_key_sector > instance->sectors_total) { + instance->mfc_event.type = MfClassicPollerEventTypeKeyAttackStop; + command = instance->callback(instance->general_event, instance->context); + instance->state = MfClassicPollerStateRequestKey; + } else { + instance->mfc_event.type = MfClassicPollerEventTypeKeyAttackStart; + instance->mfc_event_data.key_attack_data.current_sector = + dict_attack_ctx->reuse_key_sector; + command = instance->callback(instance->general_event, instance->context); + + dict_attack_ctx->current_key_type = MfClassicKeyTypeA; + instance->state = MfClassicPollerStateKeyReuseAuthKeyA; + } + } + + return command; +} + +NfcCommand mf_classic_poller_handler_key_reuse_auth_key_a(MfClassicPoller* instance) { + NfcCommand command = NfcCommandContinue; + MfClassicPollerDictAttackContext* dict_attack_ctx = &instance->mode_ctx.dict_attack_ctx; + + if(mf_classic_is_key_found( + instance->data, dict_attack_ctx->reuse_key_sector, MfClassicKeyTypeA)) { + instance->state = MfClassicPollerStateKeyReuseStart; + } else { + uint8_t block = + mf_classic_get_first_block_num_of_sector(dict_attack_ctx->reuse_key_sector); + uint64_t key = nfc_util_bytes2num(dict_attack_ctx->current_key.data, sizeof(MfClassicKey)); + FURI_LOG_D(TAG, "Key attack auth to block %d with key A: %06llx", block, key); + + MfClassicError error = mf_classic_async_auth( + instance, block, &dict_attack_ctx->current_key, MfClassicKeyTypeA, NULL); if(error == MfClassicErrorNone) { - mf_classic_set_block_read(instance->data, i, &block); + FURI_LOG_I(TAG, "Key A found"); + mf_classic_set_key_found( + instance->data, dict_attack_ctx->reuse_key_sector, MfClassicKeyTypeA, key); + + command = mf_classic_poller_handle_data_update(instance); + dict_attack_ctx->current_key_type = MfClassicKeyTypeA; + dict_attack_ctx->current_block = block; + dict_attack_ctx->auth_passed = true; + instance->state = MfClassicPollerStateKeyReuseReadSector; } else { - FURI_LOG_D(TAG, "Failed to read %d block", i); - break; + mf_classic_async_halt(instance); + dict_attack_ctx->auth_passed = false; + instance->state = MfClassicPollerStateKeyReuseStart; } } - instance->prev_state = instance->state; - if(instance->prev_state == MfClassicPollerStateAuthKeyA) { - instance->state = MfClassicPollerStateAuthKeyB; + return command; +} + +NfcCommand mf_classic_poller_handler_key_reuse_auth_key_b(MfClassicPoller* instance) { + NfcCommand command = NfcCommandContinue; + MfClassicPollerDictAttackContext* dict_attack_ctx = &instance->mode_ctx.dict_attack_ctx; + + if(mf_classic_is_key_found( + instance->data, dict_attack_ctx->reuse_key_sector, MfClassicKeyTypeB)) { + instance->state = MfClassicPollerStateKeyReuseStart; } else { - instance->state = MfClassicPollerStateNewSector; + uint8_t block = + mf_classic_get_first_block_num_of_sector(dict_attack_ctx->reuse_key_sector); + uint64_t key = nfc_util_bytes2num(dict_attack_ctx->current_key.data, sizeof(MfClassicKey)); + FURI_LOG_D(TAG, "Key attack auth to block %d with key B: %06llx", block, key); + + MfClassicError error = mf_classic_async_auth( + instance, block, &dict_attack_ctx->current_key, MfClassicKeyTypeB, NULL); + if(error == MfClassicErrorNone) { + FURI_LOG_I(TAG, "Key B found"); + mf_classic_set_key_found( + instance->data, dict_attack_ctx->reuse_key_sector, MfClassicKeyTypeB, key); + + command = mf_classic_poller_handle_data_update(instance); + dict_attack_ctx->current_key_type = MfClassicKeyTypeB; + dict_attack_ctx->current_block = block; + + dict_attack_ctx->auth_passed = true; + instance->state = MfClassicPollerStateKeyReuseReadSector; + } else { + mf_classic_async_halt(instance); + dict_attack_ctx->auth_passed = false; + instance->state = MfClassicPollerStateKeyReuseStart; + } } return command; } -NfcCommand mf_classic_poller_handler_read_complete(MfClassicPoller* instance) { +NfcCommand mf_classic_poller_handler_key_reuse_read_sector(MfClassicPoller* instance) { NfcCommand command = NfcCommandContinue; - instance->mfc_event.type = MfClassicPollerEventTypeReadComplete; + MfClassicPollerDictAttackContext* dict_attack_ctx = &instance->mode_ctx.dict_attack_ctx; + + MfClassicError error = MfClassicErrorNone; + uint8_t block_num = dict_attack_ctx->current_block; + MfClassicBlock block = {}; + + do { + if(mf_classic_is_block_read(instance->data, block_num)) break; + + if(!dict_attack_ctx->auth_passed) { + error = mf_classic_async_auth( + instance, + block_num, + &dict_attack_ctx->current_key, + dict_attack_ctx->current_key_type, + NULL); + if(error != MfClassicErrorNone) { + instance->state = MfClassicPollerStateKeyReuseStart; + break; + } + } + + FURI_LOG_D(TAG, "Reading block %d", block_num); + error = mf_classic_async_read_block(instance, block_num, &block); + + if(error != MfClassicErrorNone) { + mf_classic_async_halt(instance); + dict_attack_ctx->auth_passed = false; + FURI_LOG_D(TAG, "Failed to read block %d", block_num); + } else { + mf_classic_set_block_read(instance->data, block_num, &block); + } + } while(false); + + uint8_t sec_tr_block_num = + mf_classic_get_sector_trailer_num_by_sector(dict_attack_ctx->reuse_key_sector); + dict_attack_ctx->current_block++; + if(dict_attack_ctx->current_block > sec_tr_block_num) { + mf_classic_async_halt(instance); + dict_attack_ctx->auth_passed = false; + + mf_classic_poller_handle_data_update(instance); + instance->state = MfClassicPollerStateKeyReuseStart; + } + + return command; +} + +NfcCommand mf_classic_poller_handler_success(MfClassicPoller* instance) { + NfcCommand command = NfcCommandContinue; + instance->mfc_event.type = MfClassicPollerEventTypeSuccess; + command = instance->callback(instance->general_event, instance->context); + + return command; +} + +NfcCommand mf_classic_poller_handler_fail(MfClassicPoller* instance) { + NfcCommand command = NfcCommandContinue; + instance->mfc_event.type = MfClassicPollerEventTypeFail; command = instance->callback(instance->general_event, instance->context); + instance->state = MfClassicPollerStateStart; return command; } static const MfClassicPollerReadHandler mf_classic_poller_dict_attack_handler[MfClassicPollerStateNum] = { - [MfClassicPollerStateIdle] = mf_classic_poller_handler_idle, [MfClassicPollerStateStart] = mf_classic_poller_handler_start, - [MfClassicPollerStateNewSector] = mf_classic_poller_handler_new_sector, + [MfClassicPollerStateRequestSectorTrailer] = + mf_classic_poller_handler_request_sector_trailer, + [MfClassicPollerStateCheckWriteConditions] = mf_classic_handler_check_write_conditions, + [MfClassicPollerStateReadBlock] = mf_classic_poller_handler_read_block, + [MfClassicPollerStateWriteBlock] = mf_classic_poller_handler_write_block, + [MfClassicPollerStateNextSector] = mf_classic_poller_handler_next_sector, [MfClassicPollerStateRequestKey] = mf_classic_poller_handler_request_key, + [MfClassicPollerStateRequestReadSector] = mf_classic_poller_handler_request_read_sector, + [MfClassicPollerStateReadSectorBlocks] = + mf_classic_poller_handler_request_read_sector_blocks, [MfClassicPollerStateAuthKeyA] = mf_classic_poller_handler_auth_a, [MfClassicPollerStateAuthKeyB] = mf_classic_poller_handler_auth_b, [MfClassicPollerStateReadSector] = mf_classic_poller_handler_read_sector, - [MfClassicPollerStateReadComplete] = mf_classic_poller_handler_read_complete, + [MfClassicPollerStateKeyReuseStart] = mf_classic_poller_handler_key_reuse_start, + [MfClassicPollerStateKeyReuseAuthKeyA] = mf_classic_poller_handler_key_reuse_auth_key_a, + [MfClassicPollerStateKeyReuseAuthKeyB] = mf_classic_poller_handler_key_reuse_auth_key_b, + [MfClassicPollerStateKeyReuseReadSector] = mf_classic_poller_handler_key_reuse_read_sector, + [MfClassicPollerStateSuccess] = mf_classic_poller_handler_success, + [MfClassicPollerStateFail] = mf_classic_poller_handler_fail, }; NfcCommand mf_classic_poller_run(NfcGenericEvent event, void* context) { @@ -287,25 +712,19 @@ NfcCommand mf_classic_poller_run(NfcGenericEvent event, void* context) { Iso14443_3aPollerEvent* iso14443_3a_event = event.data; NfcCommand command = NfcCommandContinue; - UNUSED(mf_classic_poller_dict_attack_handler); if(iso14443_3a_event->type == Iso14443_3aPollerEventTypeReady) { - // TODO: Temporary measure - iso14443_3a_copy( - instance->data->iso14443_3a_data, - iso14443_3a_poller_get_data(instance->iso14443_3a_poller)); - instance->mfc_event.type = MfClassicPollerEventTypeReadComplete; - command = instance->callback(instance->general_event, instance->context); - - // command = mf_classic_poller_dict_attack_handler[instance->state](instance); - // } else if(iso14443_3a_event->type == Iso14443_3aPollerEventTypeError) { - // if(iso14443_3a_event->data->error == Iso14443_3aErrorNotPresent) { - // if(instance->card_state == MfClassicCardStateDetected) { - // instance->card_state = MfClassicCardStateNotDetected; - // instance->mfc_event.type = MfClassicPollerEventTypeCardNotDetected; - // command = instance->callback(instance->general_event, instance->context); - // instance->state = MfClassicPollerStateIdle; - // } - // } + if(instance->card_state == MfClassicCardStateLost) { + instance->card_state = MfClassicCardStateDetected; + instance->mfc_event.type = MfClassicPollerEventTypeCardDetected; + instance->callback(instance->general_event, instance->context); + } + command = mf_classic_poller_dict_attack_handler[instance->state](instance); + } else if(iso14443_3a_event->type == Iso14443_3aPollerEventTypeError) { + if(instance->card_state == MfClassicCardStateDetected) { + instance->card_state = MfClassicCardStateLost; + instance->mfc_event.type = MfClassicPollerEventTypeCardLost; + command = instance->callback(instance->general_event, instance->context); + } } return command; diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller.h b/lib/nfc/protocols/mf_classic/mf_classic_poller.h index 4e2ae68ed633..da1f3c3dce54 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller.h +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller.h @@ -10,38 +10,93 @@ extern "C" { typedef struct MfClassicPoller MfClassicPoller; typedef enum { - MfClassicPollerEventTypeStart, + // Start event + MfClassicPollerEventTypeRequestMode, + + // Read with key cache events + MfClassicPollerEventTypeRequestReadSector, + + // Write events + MfClassicPollerEventTypeRequestSectorTrailer, + MfClassicPollerEventTypeRequestWriteBlock, + + // Dictionary attack events MfClassicPollerEventTypeRequestKey, - MfClassicPollerEventTypeNewSector, + MfClassicPollerEventTypeNextSector, + MfClassicPollerEventTypeDataUpdate, MfClassicPollerEventTypeFoundKeyA, MfClassicPollerEventTypeFoundKeyB, - MfClassicPollerEventTypeCardDetected, MfClassicPollerEventTypeCardNotDetected, MfClassicPollerEventTypeKeyAttackStart, MfClassicPollerEventTypeKeyAttackStop, MfClassicPollerEventTypeKeyAttackNextSector, - MfClassicPollerEventTypeReadComplete, + + // Common events + MfClassicPollerEventTypeCardDetected, + MfClassicPollerEventTypeCardLost, + MfClassicPollerEventTypeSuccess, + MfClassicPollerEventTypeFail, } MfClassicPollerEventType; +typedef enum { + MfClassicPollerModeRead, + MfClassicPollerModeWrite, + MfClassicPollerModeDictAttack, +} MfClassicPollerMode; + typedef struct { - MfClassicType type; -} MfClassicPollerEventDataStart; + MfClassicPollerMode mode; + const MfClassicData* data; +} MfClassicPollerEventDataRequestMode; + +typedef struct { + uint8_t current_sector; +} MfClassicPollerEventDataDictAttackNextSector; + +typedef struct { + uint8_t sectors_read; + uint8_t keys_found; + uint8_t current_sector; +} MfClassicPollerEventDataUpdate; typedef struct { - uint8_t sector_num; MfClassicKey key; bool key_provided; } MfClassicPollerEventDataKeyRequest; typedef struct { - uint8_t start_sector; + uint8_t sector_num; + MfClassicKey key; + MfClassicKeyType key_type; + bool key_provided; +} MfClassicPollerEventDataReadSectorRequest; + +typedef struct { + uint8_t sector_num; + MfClassicBlock sector_trailer; + bool sector_trailer_provided; +} MfClassicPollerEventDataSectorTrailerRequest; + +typedef struct { + uint8_t block_num; + MfClassicBlock write_block; + bool write_block_provided; +} MfClassicPollerEventDataWriteBlockRequest; + +typedef struct { + uint8_t current_sector; } MfClassicPollerEventKeyAttackData; typedef union { MfClassicError error; - MfClassicPollerEventDataStart start_data; + MfClassicPollerEventDataRequestMode poller_mode; + MfClassicPollerEventDataDictAttackNextSector next_sector_data; MfClassicPollerEventDataKeyRequest key_request_data; + MfClassicPollerEventDataUpdate data_update; + MfClassicPollerEventDataReadSectorRequest read_sector_request_data; MfClassicPollerEventKeyAttackData key_attack_data; + MfClassicPollerEventDataSectorTrailerRequest sec_tr_data; + MfClassicPollerEventDataWriteBlockRequest write_block_data; } MfClassicPollerEventData; typedef struct { diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c index 958565f6146d..58e8358f9dac 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c @@ -112,7 +112,7 @@ MfClassicError mf_classic_async_auth( return ret; } -MfClassicError mf_classic_aync_halt(MfClassicPoller* instance) { +MfClassicError mf_classic_async_halt(MfClassicPoller* instance) { MfClassicError ret = MfClassicErrorNone; Iso14443_3aError error = Iso14443_3aErrorNone; diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h index 812865675386..a8d5a056d53b 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h @@ -15,41 +15,83 @@ typedef enum { } MfClassicAuthState; typedef enum { - MfClassicCardStateNotDetected, MfClassicCardStateDetected, + MfClassicCardStateLost, } MfClassicCardState; -typedef enum { - MfClassicReadModeDictAttack, - MfClassicReadModeKeyReuse, -} MfClassicReadMode; - typedef enum { MfClassicPollerStateStart, - MfClassicPollerStateIdle, - MfClassicPollerStateNewSector, + + // Write states + MfClassicPollerStateRequestSectorTrailer, + MfClassicPollerStateCheckWriteConditions, + MfClassicPollerStateReadBlock, + MfClassicPollerStateWriteBlock, + + // Read states + MfClassicPollerStateRequestReadSector, + MfClassicPollerStateReadSectorBlocks, + + // Dict attack states + MfClassicPollerStateNextSector, MfClassicPollerStateRequestKey, + MfClassicPollerStateReadSector, MfClassicPollerStateAuthKeyA, MfClassicPollerStateAuthKeyB, - MfClassicPollerStateReadSector, - MfClassicPollerStateReadComplete, + MfClassicPollerStateKeyReuseStart, + MfClassicPollerStateKeyReuseAuthKeyA, + MfClassicPollerStateKeyReuseAuthKeyB, + MfClassicPollerStateKeyReuseReadSector, + MfClassicPollerStateSuccess, + MfClassicPollerStateFail, MfClassicPollerStateNum, } MfClassicPollerState; +typedef struct { + uint8_t current_sector; + MfClassicSectorTrailer sec_tr; + uint8_t current_block; + MfClassicKeyType key_type_read; + MfClassicKeyType key_type_write; + bool need_halt_before_write; + MfClassicBlock tag_block; +} MfClassicPollerWriteContext; + +typedef struct { + uint8_t current_sector; + MfClassicKey current_key; + MfClassicKeyType current_key_type; + bool auth_passed; + uint8_t current_block; + uint8_t reuse_key_sector; +} MfClassicPollerDictAttackContext; + +typedef struct { + uint8_t current_sector; + uint16_t current_block; + MfClassicKeyType key_type; + MfClassicKey key; + bool auth_passed; +} MfClassicPollerReadContext; + +typedef union { + MfClassicPollerWriteContext write_ctx; + MfClassicPollerDictAttackContext dict_attack_ctx; + MfClassicPollerReadContext read_ctx; + +} MfClassicPollerModeContext; + struct MfClassicPoller { Iso14443_3aPoller* iso14443_3a_poller; MfClassicPollerState state; - MfClassicPollerState prev_state; MfClassicAuthState auth_state; MfClassicCardState card_state; - MfClassicReadMode read_mode; - MfClassicKey current_key; - uint8_t sectors_read; - uint8_t key_reuse_sector; uint8_t sectors_total; + MfClassicPollerModeContext mode_ctx; + Crypto1* crypto; BitBuffer* tx_plain_buffer; BitBuffer* tx_encrypted_buffer; @@ -94,12 +136,18 @@ typedef struct { int32_t new_value; } MfClassicChangeValueContext; +typedef struct { + MfClassicDeviceKeys keys; + uint8_t current_sector; +} MfClassicReadContext; + typedef union { MfClassicAuthContext auth_context; MfClassicReadBlockContext read_block_context; MfClassicWriteBlockContext write_block_context; MfClassicReadValueContext read_value_context; MfClassicChangeValueContext change_value_context; + MfClassicReadContext read_context; } MfClassicPollerContextData; MfClassicError mf_classic_process_error(Iso14443_3aError error); @@ -115,7 +163,7 @@ MfClassicError mf_classic_async_auth( MfClassicKeyType key_type, MfClassicAuthContext* data); -MfClassicError mf_classic_aync_halt(MfClassicPoller* instance); +MfClassicError mf_classic_async_halt(MfClassicPoller* instance); MfClassicError mf_classic_async_read_block(MfClassicPoller* instance, uint8_t block_num, MfClassicBlock* data); diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.c b/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.c index a787a43258b7..21db8cd6ae9b 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.c @@ -56,7 +56,7 @@ static MfClassicError mf_classic_poller_read_block_handler( poller, data->read_block_context.block_num, &data->read_block_context.block); if(error != MfClassicErrorNone) break; - error = mf_classic_aync_halt(poller); + error = mf_classic_async_halt(poller); if(error != MfClassicErrorNone) break; } while(false); @@ -82,7 +82,7 @@ static MfClassicError mf_classic_poller_write_block_handler( poller, data->write_block_context.block_num, &data->write_block_context.block); if(error != MfClassicErrorNone) break; - error = mf_classic_aync_halt(poller); + error = mf_classic_async_halt(poller); if(error != MfClassicErrorNone) break; } while(false); @@ -113,7 +113,7 @@ static MfClassicError mf_classic_poller_read_value_handler( break; } - error = mf_classic_aync_halt(poller); + error = mf_classic_async_halt(poller); if(error != MfClassicErrorNone) break; } while(false); @@ -149,7 +149,7 @@ static MfClassicError mf_classic_poller_change_value_handler( error = mf_classic_async_read_block(poller, data->change_value_context.block_num, &block); if(error != MfClassicErrorNone) break; - error = mf_classic_aync_halt(poller); + error = mf_classic_async_halt(poller); if(error != MfClassicErrorNone) break; if(!mf_classic_block_to_value(&block, &data->change_value_context.new_value, NULL)) { @@ -350,3 +350,113 @@ MfClassicError mf_classic_poller_change_value( return error; } + +static bool mf_classic_poller_read_get_next_key( + MfClassicReadContext* read_ctx, + uint8_t* sector_num, + MfClassicKey* key, + MfClassicKeyType* key_type) { + bool next_key_found = false; + + for(uint8_t i = read_ctx->current_sector; i < MF_CLASSIC_TOTAL_SECTORS_MAX; i++) { + if(FURI_BIT(read_ctx->keys.key_a_mask, i)) { + FURI_BIT_CLEAR(read_ctx->keys.key_a_mask, i); + *key = read_ctx->keys.key_a[i]; + *key_type = MfClassicKeyTypeA; + *sector_num = i; + + next_key_found = true; + break; + } + if(FURI_BIT(read_ctx->keys.key_b_mask, i)) { + FURI_BIT_CLEAR(read_ctx->keys.key_b_mask, i); + *key = read_ctx->keys.key_b[i]; + *key_type = MfClassicKeyTypeB; + *sector_num = i; + + next_key_found = true; + read_ctx->current_sector = i; + break; + } + } + + return next_key_found; +} + +NfcCommand mf_classic_poller_read_callback(NfcGenericEvent event, void* context) { + furi_assert(context); + furi_assert(event.data); + furi_assert(event.protocol == NfcProtocolMfClassic); + + NfcCommand command = NfcCommandContinue; + MfClassicPollerContext* poller_context = context; + MfClassicPollerEvent* mfc_event = event.data; + + if(mfc_event->type == MfClassicPollerEventTypeCardLost) { + poller_context->error = MfClassicErrorNotPresent; + command = NfcCommandStop; + } else if(mfc_event->type == MfClassicPollerEventTypeRequestMode) { + mfc_event->data->poller_mode.mode = MfClassicPollerModeRead; + } else if(mfc_event->type == MfClassicPollerEventTypeRequestReadSector) { + MfClassicPollerEventDataReadSectorRequest* req_data = + &mfc_event->data->read_sector_request_data; + MfClassicKey key = {}; + MfClassicKeyType key_type = MfClassicKeyTypeA; + uint8_t sector_num = 0; + if(mf_classic_poller_read_get_next_key( + &poller_context->data.read_context, §or_num, &key, &key_type)) { + req_data->sector_num = sector_num; + req_data->key = key; + req_data->key_type = key_type; + req_data->key_provided = true; + } else { + req_data->key_provided = false; + } + } else if(mfc_event->type == MfClassicPollerEventTypeSuccess) { + command = NfcCommandStop; + } + + if(command == NfcCommandStop) { + furi_thread_flags_set(poller_context->thread_id, MF_CLASSIC_POLLER_COMPLETE_EVENT); + } + + return command; +} + +MfClassicError + mf_classic_poller_read(Nfc* nfc, const MfClassicDeviceKeys* keys, MfClassicData* data) { + furi_assert(nfc); + furi_assert(keys); + furi_assert(data); + + MfClassicError error = MfClassicErrorNone; + MfClassicPollerContext poller_context = {}; + poller_context.thread_id = furi_thread_get_current_id(); + poller_context.data.read_context.keys = *keys; + + NfcPoller* poller = nfc_poller_alloc(nfc, NfcProtocolMfClassic); + nfc_poller_start(poller, mf_classic_poller_read_callback, &poller_context); + furi_thread_flags_wait(MF_CLASSIC_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); + furi_thread_flags_clear(MF_CLASSIC_POLLER_COMPLETE_EVENT); + + nfc_poller_stop(poller); + + if(poller_context.error != MfClassicErrorNone) { + error = poller_context.error; + } else { + const MfClassicData* mfc_data = nfc_poller_get_data(poller); + uint8_t sectors_read = 0; + uint8_t keys_found = 0; + + mf_classic_get_read_sectors_and_keys(mfc_data, §ors_read, &keys_found); + if((sectors_read > 0) || (keys_found > 0)) { + mf_classic_copy(data, mfc_data); + } else { + error = MfClassicErrorNotPresent; + } + } + + nfc_poller_free(poller); + + return error; +} diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.h b/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.h index bf0ef05f7d2f..58c3b96f852a 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.h +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.h @@ -43,6 +43,9 @@ MfClassicError mf_classic_poller_change_value( int32_t data, int32_t* new_value); +MfClassicError + mf_classic_poller_read(Nfc* nfc, const MfClassicDeviceKeys* keys, MfClassicData* data); + #ifdef __cplusplus } #endif From 5e1e3ffc5cc8749f62021bf3d7b7dee24e749755 Mon Sep 17 00:00:00 2001 From: RebornedBrain <138568282+RebornedBrain@users.noreply.github.com> Date: Tue, 29 Aug 2023 14:50:05 +0300 Subject: [PATCH 142/149] [FL-3573] MFU ASCII mirror handling (#3019) * Update nfc.c, iso14443_3a_listener.c, and mf_ultralight_listener.c Added more logging * Removed a lot of unnecessary logs to comply timings * Poller adjusted to read single tearing flag for NTAGs * Fix for proper saving of tear flags * CHECK_TEARING_CMD support for NTAGs According to datasheet NTAG21x don't support this command, but some of them do. Only 02 flag works (3E02), so now tearing command checks if SingleCounter feature is supported by the card, then it can be treated as NTAGxx and only flag=2 can be read * Duplicated gpio call removed * Added TODO for future work * Fix MF Classic emulation * Function mf_ultralight_support_feature added to API This function checks whether current Ultralight instance supports feature, mentioned as a second paramete. * Adjusted listener and poller with new function and removed some nesting * NFC layer adjustments Changed function call from f_hal_nfc_listener_sleep to nfc_listener_sleep for Field Off event Added new event FHalNfcEventTxEnd where trasmitter state is now changed Reset after rx command processing is now done only when we don't send anything * iso14443_3a_listener cleanup to avoid duplicate calls and race conditions * Added result statuses for mfu commands and command signature changed, now it returns status instead of bool * mf_ultralight_listener_run adjusted to process statuses * Comments adjusted according bits set * Renamed enum type and values * Command adjustments Cleaned up all commands. Read and write commands send their NAKs according to status * f_hal_nfc_listener_tx is now blocking * Adjusted READ_CNT function to check nfc_cnt_en for NTAG * INCR_CNT command added for Ultralight * IncrValue is now taken using MfUltralightCounter union * Update api_symbols.csv * New struct for mirror mode added * Mirror mode implementation added * Moved mirror implementation to a separate file mf_ultralight_listener_i.c * Adjustments according to PR comments --- firmware/targets/f7/api_symbols.csv | 2 +- .../mf_ultralight/mf_ultralight_listener.c | 12 +- .../mf_ultralight/mf_ultralight_listener_i.c | 164 ++++++++++++++++++ .../mf_ultralight/mf_ultralight_listener_i.h | 16 ++ 4 files changed, 192 insertions(+), 2 deletions(-) create mode 100644 lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.c diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 62bf6b0b8376..1948b85e5e5b 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,+,35.2,, +Version,+,36.1,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c index f80ab2794b30..8eb2d542de16 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c @@ -86,6 +86,8 @@ static MfUltralightCommand instance->state = MfUltraligthListenerStateIdle; instance->auth_state = MfUltralightListenerAuthStateIdle; } else { + mf_ultralight_mirror_read_prepare(start_page, instance); + uint16_t config_page = mf_ultralight_get_config_page_num(instance->data->type); for(size_t i = 0; i < 4; i++) { bool hide_data = @@ -93,9 +95,14 @@ static MfUltralightCommand if(hide_data) { memset(read_cmd_data.page[i].data, 0, sizeof(MfUltralightPage)); } else { - read_cmd_data.page[i] = instance->data->page[(start_page + i) % pages_total]; + uint8_t current_page = start_page + i; + read_cmd_data.page[i] = instance->data->page[current_page % pages_total]; + + mf_ultralight_mirror_read_handler( + current_page, read_cmd_data.page[i].data, instance); } } + bit_buffer_copy_bytes( instance->tx_buffer, (uint8_t*)&read_cmd_data, @@ -364,6 +371,7 @@ static void mf_ultralight_listener_prepare_emulation(MfUltralightListener* insta MfUltralightData* data = instance->data; instance->features = mf_ultralight_get_feature_support_set(data->type); mf_ultralight_get_config_page(data, &instance->config); + mf_ultraligt_mirror_prepare_emulation(instance); } MfUltralightListener* mf_ultralight_listener_alloc( @@ -372,6 +380,7 @@ MfUltralightListener* mf_ultralight_listener_alloc( furi_assert(iso14443_3a_listener); MfUltralightListener* instance = malloc(sizeof(MfUltralightListener)); + instance->mirror.ascii_mirror_data = furi_string_alloc(); instance->iso14443_3a_listener = iso14443_3a_listener; instance->data = mf_ultralight_alloc(); mf_ultralight_copy(instance->data, data); @@ -392,6 +401,7 @@ void mf_ultralight_listener_free(MfUltralightListener* instance) { furi_assert(instance->tx_buffer); bit_buffer_free(instance->tx_buffer); + furi_string_free(instance->mirror.ascii_mirror_data); mf_ultralight_free(instance->data); free(instance); } diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.c new file mode 100644 index 000000000000..20f433322242 --- /dev/null +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.c @@ -0,0 +1,164 @@ +#include "mf_ultralight_listener_i.h" + +#include + +static MfUltralightMirrorConf mf_ultralight_mirror_check_mode( + const MfUltralightConfigPages* const config, + const MfUltralightListenerAuthState auth_state) { + MfUltralightMirrorConf mirror_mode = config->mirror.mirror_conf; + + if(mirror_mode == MfUltralightMirrorNone || mirror_mode == MfUltralightMirrorUid) + return mirror_mode; + + if(!config->access.nfc_cnt_en || + (config->access.nfc_cnt_pwd_prot && auth_state != MfUltralightListenerAuthStateSuccess)) { + mirror_mode = mirror_mode == MfUltralightMirrorCounter ? MfUltralightMirrorNone : + MfUltralightMirrorUid; + } + return mirror_mode; +} + +static bool mf_ultralight_mirror_check_boundaries(MfUltralightListener* instance) { + const MfUltralightConfigPages* const conf = instance->config; + + uint8_t last_user_page = mf_ultralight_get_config_page_num(instance->data->type) - 2; + + uint8_t max_page_offset = 0; + uint8_t max_byte_offset = 2; + + MfUltralightMirrorConf mode = mf_ultralight_mirror_check_mode(conf, instance->auth_state); + + bool result = false; + bool again = false; + do { + if(mode == MfUltralightMirrorNone) { + break; + } else if(mode == MfUltralightMirrorUid) { + max_page_offset = 3; + } else if(mode == MfUltralightMirrorCounter) { + max_page_offset = 1; + } else if(mode == MfUltralightMirrorUidCounter) { + max_page_offset = 5; + max_byte_offset = 3; + } + + instance->mirror.actual_mode = mode; + + if(conf->mirror_page <= 3) break; + if(conf->mirror_page < last_user_page - max_page_offset) { + result = true; + break; + } + if(conf->mirror_page == last_user_page - max_page_offset) { + result = (conf->mirror.mirror_byte <= max_byte_offset); + break; + } + + if(conf->mirror_page > last_user_page - max_page_offset && + mode == MfUltralightMirrorUidCounter) { + mode = MfUltralightMirrorUid; + again = true; + } + } while(again); + + return result; +} + +static bool mf_ultralight_mirror_enabled(MfUltralightListener* instance) { + bool mirror_enabled = false; + if(mf_ultralight_support_feature(instance->features, MfUltralightFeatureSupportAsciiMirror) && + (instance->config != NULL) && mf_ultralight_mirror_check_boundaries(instance)) { + mirror_enabled = true; + } + instance->mirror.enabled = mirror_enabled; + return instance->mirror.enabled; +} + +static uint8_t mf_ultralight_get_mirror_data_size(MfUltralightMirrorConf mode) { + switch(mode) { + case MfUltralightMirrorUid: + return 14; + case MfUltralightMirrorCounter: + return 6; + case MfUltralightMirrorUidCounter: + return 21; + default: + return 0; + } +} + +static uint8_t mf_ultralight_get_mirror_last_page(MfUltralightListener* instance) { + uint8_t strSize = mf_ultralight_get_mirror_data_size(instance->mirror.actual_mode); + return (instance->config->mirror_page + 1U + strSize / 4); +} + +static uint8_t mf_ultralight_get_ascii_offset(uint8_t start_page, MfUltralightListener* instance) { + uint8_t start_offset = 0; + if(instance->config->mirror.mirror_conf == MfUltralightMirrorCounter) start_offset = 15; + + uint8_t ascii_offset = start_offset; + + if(start_page > instance->config->mirror_page) + ascii_offset = (start_page - instance->config->mirror_page) * 4 - + instance->config->mirror.mirror_byte + start_offset; + + return ascii_offset; +} + +static uint8_t mf_ultralight_get_ascii_end(MfUltralightMirrorConf mode) { + return (mode == MfUltralightMirrorUid) ? 14 : 21; +} + +static uint8_t mf_ultralight_get_byte_offset( + uint8_t current_page, + const MfUltralightConfigPages* const config) { + return (current_page > config->mirror_page) ? 0 : config->mirror.mirror_byte; +} + +static void mf_ultraligt_format_mirror_data( + FuriString* str, + const uint8_t* const data, + const uint8_t data_len) { + for(uint8_t i = 0; i < data_len; i++) furi_string_cat_printf(str, "%02X", data[i]); +} + +void mf_ultralight_mirror_read_prepare(uint8_t start_page, MfUltralightListener* instance) { + if(mf_ultralight_mirror_enabled(instance)) { + instance->mirror.ascii_offset = mf_ultralight_get_ascii_offset(start_page, instance); + instance->mirror.ascii_end = mf_ultralight_get_ascii_end(instance->mirror.actual_mode); + + instance->mirror.mirror_last_page = mf_ultralight_get_mirror_last_page(instance); + } +} + +void mf_ultralight_mirror_read_handler( + uint8_t mirror_page_num, + uint8_t* dest, + MfUltralightListener* instance) { + if(instance->mirror.enabled && mirror_page_num >= instance->config->mirror_page && + mirror_page_num <= instance->mirror.mirror_last_page) { + uint8_t byte_offset = mf_ultralight_get_byte_offset(mirror_page_num, instance->config); + + uint8_t ascii_offset = instance->mirror.ascii_offset; + uint8_t ascii_end = instance->mirror.ascii_end; + uint8_t* source = (uint8_t*)furi_string_get_cstr(instance->mirror.ascii_mirror_data); + for(uint8_t j = byte_offset; (j < 4) && (ascii_offset < ascii_end); j++) { + dest[j] = source[ascii_offset]; + ascii_offset++; + } + } +} + +void mf_ultraligt_mirror_prepare_emulation(MfUltralightListener* instance) { + mf_ultraligt_format_mirror_data( + instance->mirror.ascii_mirror_data, + instance->data->iso14443_3a_data->uid, + instance->data->iso14443_3a_data->uid_len); + + furi_string_push_back(instance->mirror.ascii_mirror_data, 'x'); + + mf_ultraligt_format_mirror_data( + instance->mirror.ascii_mirror_data, + instance->data->counter[2].data, + sizeof(instance->data->counter[2].data)); +} \ No newline at end of file diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h index 10aaec982833..eb188041f6a6 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h @@ -17,6 +17,15 @@ typedef enum { MfUltraligthListenerStateIdle, } MfUltraligthListenerState; +typedef struct { + uint8_t enabled; + uint8_t ascii_offset; + uint8_t ascii_end; + uint8_t mirror_last_page; + MfUltralightMirrorConf actual_mode; + FuriString* ascii_mirror_data; +} MfUltralightMirrorMode; + struct MfUltralightListener { Iso14443_3aListener* iso14443_3a_listener; MfUltralightListenerAuthState auth_state; @@ -31,9 +40,16 @@ struct MfUltralightListener { MfUltralightListenerEvent mfu_event; MfUltralightListenerEventData mfu_event_data; NfcGenericCallback callback; + MfUltralightMirrorMode mirror; void* context; }; +void mf_ultraligt_mirror_prepare_emulation(MfUltralightListener* instance); +void mf_ultralight_mirror_read_prepare(uint8_t start_page, MfUltralightListener* instance); +void mf_ultralight_mirror_read_handler( + uint8_t mirror_page_num, + uint8_t* dest, + MfUltralightListener* instance); #ifdef __cplusplus } #endif From 5e0dc8cb55b622d6b77a1ed2e0d1490c81507457 Mon Sep 17 00:00:00 2001 From: gornekich Date: Wed, 30 Aug 2023 13:52:43 +0400 Subject: [PATCH 143/149] [FL-3568] Signal reader optimization (#3022) * signal reader: add trigger config * nfc: remove old cli commands * nfc: setup test bench * signal reader: working trigger * iso15 parser: more optimization * iso15: add profiling * iso15 parser: config signal reader trigger * iso15 parser: more optimizations * nfc: remove profiling * iso15 parser: fix incorrect single eof handling * iso15 hal: code clean up --- applications/main/nfc/application.fam | 16 +- applications/main/nfc/nfc_cli.c | 216 +++++------------- firmware/targets/f7/api_symbols.csv | 3 +- .../targets/f7/furi_hal/f_hal_nfc_iso15693.c | 4 +- .../parsers/iso15693/iso15693_parser.c | 173 ++++++-------- lib/signal_reader/signal_reader.c | 39 +++- lib/signal_reader/signal_reader.h | 7 + 7 files changed, 178 insertions(+), 280 deletions(-) diff --git a/applications/main/nfc/application.fam b/applications/main/nfc/application.fam index 27b11d8da06f..25a232056ce0 100644 --- a/applications/main/nfc/application.fam +++ b/applications/main/nfc/application.fam @@ -9,7 +9,7 @@ App( "gui", "dialogs", ], - # provides=["nfc_start"], + provides=["nfc_start"], icon="A_NFC_14", stack_size=5 * 1024, order=30, @@ -52,10 +52,10 @@ App( requires=["nfc"], ) -# App( -# appid="nfc_start", -# apptype=FlipperAppType.STARTUP, -# entry_point="nfc_on_system_start", -# requires=["nfc"], -# order=30, -# ) +App( + appid="nfc_start", + apptype=FlipperAppType.STARTUP, + entry_point="nfc_on_system_start", + requires=["nfc"], + order=30, +) diff --git a/applications/main/nfc/nfc_cli.c b/applications/main/nfc/nfc_cli.c index 320cd94bf7dd..818a27ec18de 100644 --- a/applications/main/nfc/nfc_cli.c +++ b/applications/main/nfc/nfc_cli.c @@ -4,8 +4,15 @@ #include #include -#include -#include +#include +#include +#include +#include + +#include +#include + +#define FLAG_EVENT (1 << 10) static void nfc_cli_print_usage() { printf("Usage:\r\n"); @@ -19,155 +26,72 @@ static void nfc_cli_print_usage() { } } -static void nfc_cli_check(Cli* cli, FuriString* args) { - UNUSED(args); - UNUSED(cli); -} +static void f_hal_nfc_iso15693_listener_transparent_mode_enter(FuriHalSpiBusHandle* handle) { + st25r3916_direct_cmd(handle, ST25R3916_CMD_TRANSPARENT_MODE); -static void nfc_cli_detect(Cli* cli, FuriString* args) { - UNUSED(args); - // Check if nfc worker is not busy - if(furi_hal_nfc_is_busy()) { - printf("Nfc is busy\r\n"); - return; - } - - FuriHalNfcDevData dev_data = {}; - bool cmd_exit = false; - furi_hal_nfc_exit_sleep(); - printf("Detecting nfc...\r\nPress Ctrl+C to abort\r\n"); - while(!cmd_exit) { - cmd_exit |= cli_cmd_interrupt_received(cli); - if(furi_hal_nfc_detect(&dev_data, 400)) { - printf("Found: %s ", nfc_get_dev_type(dev_data.type)); - printf("UID length: %d, UID:", dev_data.uid_len); - for(size_t i = 0; i < dev_data.uid_len; i++) { - printf("%02X", dev_data.uid[i]); - } - printf("\r\n"); - break; - } - furi_hal_nfc_sleep(); - furi_delay_ms(50); - } - furi_hal_nfc_sleep(); + furi_hal_spi_bus_handle_deinit(handle); + f_hal_nfc_deinit_gpio_isr(); } -static void nfc_cli_emulate(Cli* cli, FuriString* args) { - UNUSED(args); - // Check if nfc worker is not busy - if(furi_hal_nfc_is_busy()) { - printf("Nfc is busy\r\n"); - return; - } +static void f_hal_nfc_iso15693_listener_transparent_mode_exit(FuriHalSpiBusHandle* handle) { + // Configure gpio back to SPI and exit transparent mode + f_hal_nfc_init_gpio_isr(); + furi_hal_spi_bus_handle_init(handle); - furi_hal_nfc_exit_sleep(); - printf("Emulating NFC-A Type: T2T UID: 36 9C E7 B1 0A C1 34 SAK: 00 ATQA: 00/44\r\n"); - printf("Press Ctrl+C to abort\r\n"); - - FuriHalNfcDevData params = { - .uid = {0x36, 0x9C, 0xe7, 0xb1, 0x0A, 0xC1, 0x34}, - .uid_len = 7, - .atqa = {0x44, 0x00}, - .sak = 0x00, - .type = FuriHalNfcTypeA, - }; - - while(!cli_cmd_interrupt_received(cli)) { - if(furi_hal_nfc_listen(params.uid, params.uid_len, params.atqa, params.sak, false, 100)) { - printf("Reader detected\r\n"); - furi_hal_nfc_sleep(); - } - furi_delay_ms(50); - } - furi_hal_nfc_sleep(); + st25r3916_direct_cmd(handle, ST25R3916_CMD_UNMASK_RECEIVE_DATA); } -static void nfc_cli_field(Cli* cli, FuriString* args) { - UNUSED(args); - // Check if nfc worker is not busy - if(furi_hal_nfc_is_busy()) { - printf("Nfc is busy\r\n"); - return; - } - - furi_hal_nfc_exit_sleep(); - furi_hal_nfc_field_on(); - - printf("Field is on. Don't leave device in this mode for too long.\r\n"); - printf("Press Ctrl+C to abort\r\n"); +static void f_hal_nfc_iso15693_parser_callback(Iso15693ParserEvent event, void* context) { + furi_assert(context); - while(!cli_cmd_interrupt_received(cli)) { - furi_delay_ms(50); + if(event == Iso15693ParserEventDataReceived) { + FuriThreadId thread_id = context; + furi_thread_flags_set(thread_id, FLAG_EVENT); } - - furi_hal_nfc_field_off(); - furi_hal_nfc_sleep(); } -static void nfc_cli_apdu(Cli* cli, FuriString* args) { +// TODO remove this test command +static void nfc_cli_check(Cli* cli, FuriString* args) { + UNUSED(args); UNUSED(cli); - if(furi_hal_nfc_is_busy()) { - printf("Nfc is busy\r\n"); - return; + FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; + uint8_t data[100] = {}; + size_t bits = 0; + + Nfc* nfc = nfc_alloc(); + f_hal_nfc_low_power_mode_stop(); + f_hal_nfc_set_mode(FHalNfcModeListener, FHalNfcTechIso15693); + f_hal_nfc_iso15693_listener_transparent_mode_enter(handle); + Iso15693Parser* instance = iso15693_parser_alloc(&gpio_spi_r_miso, 1024); + + FuriThreadId thread_id = furi_thread_get_current_id(); + furi_thread_set_current_priority(FuriThreadPriorityHighest); + iso15693_parser_start(instance, f_hal_nfc_iso15693_parser_callback, thread_id); + + while(true) { + uint32_t flag = furi_thread_flags_wait(FLAG_EVENT, FuriFlagWaitAny, FuriWaitForever); + furi_thread_flags_clear(flag); + + if(flag & FLAG_EVENT) { + if(iso15693_parser_run(instance)) { + iso15693_parser_get_data(instance, data, sizeof(data), &bits); + break; + } + } } - furi_hal_nfc_exit_sleep(); - FuriString* data = NULL; - data = furi_string_alloc(); - FuriHalNfcTxRxContext tx_rx = {}; - FuriHalNfcDevData dev_data = {}; - uint8_t* req_buffer = NULL; - uint8_t* resp_buffer = NULL; - size_t apdu_size = 0; - size_t resp_size = 0; + for(size_t i = 0; i < bits / 8; i++) { + printf("%02X ", data[i]); + } + printf("\r\n"); - do { - if(!args_read_string_and_trim(args, data)) { - printf( - "Use like `nfc apdu 00a404000e325041592e5359532e444446303100 00a4040008a0000003010102` \r\n"); - break; - } + iso15693_parser_stop(instance); + f_hal_nfc_iso15693_listener_transparent_mode_exit(handle); - printf("detecting tag\r\n"); - if(!furi_hal_nfc_detect(&dev_data, 300)) { - printf("Failed to detect tag\r\n"); - break; - } - do { - apdu_size = furi_string_size(data) / 2; - req_buffer = malloc(apdu_size); - hex_chars_to_uint8(furi_string_get_cstr(data), req_buffer); - - memcpy(tx_rx.tx_data, req_buffer, apdu_size); - tx_rx.tx_bits = apdu_size * 8; - tx_rx.tx_rx_type = FuriHalNfcTxRxTypeDefault; - - printf("Sending APDU:%s to Tag\r\n", furi_string_get_cstr(data)); - if(!furi_hal_nfc_tx_rx(&tx_rx, 300)) { - printf("Failed to tx_rx\r\n"); - break; - } - resp_size = (tx_rx.rx_bits / 8) * 2; - if(!resp_size) { - printf("No response\r\n"); - break; - } - resp_buffer = malloc(resp_size); - uint8_to_hex_chars(tx_rx.rx_data, resp_buffer, resp_size); - resp_buffer[resp_size] = 0; - printf("Response: %s\r\n", resp_buffer); - free(req_buffer); - free(resp_buffer); - req_buffer = NULL; - resp_buffer = NULL; - } while(args_read_string_and_trim(args, data)); - } while(false); - - free(req_buffer); - free(resp_buffer); - furi_string_free(data); - furi_hal_nfc_sleep(); + iso15693_parser_free(instance); + f_hal_nfc_reset_mode(); + f_hal_nfc_low_power_mode_start(); + nfc_free(nfc); } static void nfc_cli(Cli* cli, FuriString* args, void* context) { @@ -184,26 +108,6 @@ static void nfc_cli(Cli* cli, FuriString* args, void* context) { nfc_cli_check(cli, args); break; } - if(furi_string_cmp_str(cmd, "detect") == 0) { - nfc_cli_detect(cli, args); - break; - } - if(furi_string_cmp_str(cmd, "emulate") == 0) { - nfc_cli_emulate(cli, args); - 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); - break; - } - } nfc_cli_print_usage(); } while(false); diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 1948b85e5e5b..95e8eab74318 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,+,36.1,, +Version,+,35.3,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -2677,6 +2677,7 @@ Function,+,signal_reader_free,void,SignalReader* Function,+,signal_reader_set_polarity,void,"SignalReader*, SignalReaderPolarity" Function,+,signal_reader_set_pull,void,"SignalReader*, GpioPull" Function,+,signal_reader_set_sample_rate,void,"SignalReader*, SignalReaderTimeUnit, uint32_t" +Function,+,signal_reader_set_trigger,void,"SignalReader*, SignalReaderTrigger" Function,+,signal_reader_start,void,"SignalReader*, SignalReaderCallback, void*" Function,+,signal_reader_stop,void,SignalReader* Function,+,simple_array_alloc,SimpleArray*,const SimpleArrayConfig* diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc_iso15693.c b/firmware/targets/f7/furi_hal/f_hal_nfc_iso15693.c index 9cffba652cfb..fbaaa08985d7 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfc_iso15693.c +++ b/firmware/targets/f7/furi_hal/f_hal_nfc_iso15693.c @@ -363,6 +363,7 @@ static FHalNfcEvent f_hal_nfc_iso15693_wait_event(uint32_t timeout_ms) { if(flag & FHalNfcEventInternalTypeAbort) { event = FHalNfcEventAbortRequest; + f_hal_nfc_iso15693_listener_transparent_mode_exit(handle); break; } if(flag & FHalNfcEventInternalTypeTransparentDataReceived) { @@ -372,9 +373,7 @@ static FHalNfcEvent f_hal_nfc_iso15693_wait_event(uint32_t timeout_ms) { } } } - iso15693_parser_stop(f_hal_nfc_iso15693_listener->parser); - f_hal_nfc_iso15693_listener_transparent_mode_exit(handle); return event; } @@ -386,7 +385,6 @@ static FHalNfcError f_hal_nfc_iso15693_listener_tx( furi_assert(f_hal_nfc_iso15693_listener); FHalNfcError error = FHalNfcErrorNone; - f_hal_nfc_iso15693_listener_transparent_mode_enter(handle); error = f_hal_nfc_iso15693_listener_tx_transparent(tx_data, tx_bits / BITS_IN_BYTE); diff --git a/lib/signal_reader/parsers/iso15693/iso15693_parser.c b/lib/signal_reader/parsers/iso15693/iso15693_parser.c index 80652e57b08c..6fbe91a4c22d 100644 --- a/lib/signal_reader/parsers/iso15693/iso15693_parser.c +++ b/lib/signal_reader/parsers/iso15693/iso15693_parser.c @@ -4,21 +4,27 @@ #include -#define ISO15693_PARSER_BITSTREAM_BUFF_SIZE (8) +#define ISO15693_PARSER_SIGNAL_READER_BUFF_SIZE (2) +#define ISO15693_PARSER_BITSTREAM_BUFF_SIZE (32) #define ISO15693_PARSER_BITRATE_F64MHZ (603U) #define TAG "Iso15693Parser" typedef enum { Iso15693ParserStateParseSoF, - Iso15693ParserStateParse1OutOf4, - Iso15693ParserStateParse1OutOf256, - - Iso15693ParserStateNum, + Iso15693ParserStateParseFrame, } Iso15693ParserState; +typedef enum { + Iso15693ParserMode1OutOf4, + Iso15693ParserMode1OutOf256, + + Iso15693ParserModeNum, +} Iso15693ParserMode; + struct Iso15693Parser { Iso15693ParserState state; + Iso15693ParserMode mode; SignalReader* signal_reader; @@ -37,6 +43,7 @@ struct Iso15693Parser { bool zero_found; BitBuffer* parsed_frame; + bool eof_received; bool frame_parsed; Iso15693ParserCallback callback; @@ -56,11 +63,12 @@ Iso15693Parser* iso15693_parser_alloc(const GpioPin* pin, size_t max_frame_size) Iso15693Parser* instance = malloc(sizeof(Iso15693Parser)); instance->parsed_frame = bit_buffer_alloc(max_frame_size); - instance->signal_reader = signal_reader_alloc(pin, ISO15693_PARSER_BITSTREAM_BUFF_SIZE); + instance->signal_reader = signal_reader_alloc(pin, ISO15693_PARSER_SIGNAL_READER_BUFF_SIZE); signal_reader_set_sample_rate( instance->signal_reader, SignalReaderTimeUnit64Mhz, ISO15693_PARSER_BITRATE_F64MHZ); signal_reader_set_pull(instance->signal_reader, GpioPullDown); signal_reader_set_polarity(instance->signal_reader, SignalReaderPolarityInverted); + signal_reader_set_trigger(instance->signal_reader, SignalReaderTriggerRisingFallingEdge); return instance; } @@ -77,6 +85,7 @@ void iso15693_parser_reset(Iso15693Parser* instance) { furi_assert(instance); instance->state = Iso15693ParserStateParseSoF; + instance->mode = Iso15693ParserMode1OutOf4; memset(instance->bitstream_buff, 0x00, sizeof(instance->bitstream_buff)); instance->bitstream_idx = 0; @@ -91,6 +100,7 @@ void iso15693_parser_reset(Iso15693Parser* instance) { instance->last_byte = 0x00; instance->zero_found = false; + instance->eof_received = false; bit_buffer_reset(instance->parsed_frame); instance->frame_parsed = false; @@ -99,32 +109,46 @@ void iso15693_parser_reset(Iso15693Parser* instance) { static void signal_reader_callback(SignalReaderEvent event, void* context) { furi_assert(context); furi_assert(event.data->data); - furi_assert(event.data->len == ISO15693_PARSER_BITSTREAM_BUFF_SIZE / 2); + furi_assert(event.data->len == ISO15693_PARSER_SIGNAL_READER_BUFF_SIZE / 2); Iso15693Parser* instance = context; furi_assert(instance->callback); - if(!instance->signal_detected) { - size_t i = 0; - for(i = 0; i < event.data->len; i++) { - if(event.data->data[i] != 0x00) { - break; - } - } - if(i != event.data->len) { - memcpy(instance->bitstream_buff, &event.data->data[i], event.data->len - i); - instance->bytes_to_process = event.data->len - i; - instance->signal_detected = true; + const uint8_t sof_1_out_of_4 = 0x21; + const uint8_t sof_1_out_of_256 = 0x81; + const uint8_t eof_single = 0x01; + const uint8_t eof = 0x04; + + if(instance->state == Iso15693ParserStateParseSoF) { + if(event.data->data[0] == sof_1_out_of_4) { + instance->mode = Iso15693ParserMode1OutOf4; + instance->state = Iso15693ParserStateParseFrame; + } else if(event.data->data[0] == sof_1_out_of_256) { + instance->mode = Iso15693ParserMode1OutOf256; + instance->state = Iso15693ParserStateParseFrame; + } else if(event.data->data[0] == eof_single) { + instance->eof_received = true; + instance->callback(Iso15693ParserEventDataReceived, instance->context); } } else { - memcpy( - &instance->bitstream_buff[instance->bytes_to_process], - event.data->data, - event.data->len); - instance->bytes_to_process += event.data->len; - } - if(instance->bytes_to_process >= ISO15693_PARSER_BITSTREAM_BUFF_SIZE / 4) { - instance->callback(Iso15693ParserEventDataReceived, instance->context); + if(instance->mode == Iso15693ParserMode1OutOf4) { + if(event.data->data[0] == eof) { + instance->eof_received = true; + instance->callback(Iso15693ParserEventDataReceived, instance->context); + } else { + instance->bitstream_buff[instance->bytes_to_process] = event.data->data[0]; + instance->bytes_to_process++; + if(instance->bytes_to_process == ISO15693_PARSER_BITSTREAM_BUFF_SIZE) { + instance->callback(Iso15693ParserEventDataReceived, instance->context); + } + } + } else { + instance->bitstream_buff[instance->bytes_to_process] = event.data->data[0]; + instance->bytes_to_process++; + if(instance->bytes_to_process == ISO15693_PARSER_BITSTREAM_BUFF_SIZE) { + instance->callback(Iso15693ParserEventDataReceived, instance->context); + } + } } } @@ -150,83 +174,12 @@ void iso15693_parser_stop(Iso15693Parser* instance) { signal_reader_stop(instance->signal_reader); } -static void iso15693_parser_prepare_buff(Iso15693Parser* instance) { - if(!instance->bit_offset_calculated) { - for(size_t i = 0; i < 8; i++) { - if(FURI_BIT(instance->bitstream_buff[0], i)) { - instance->bit_offset = i; - break; - } - } - if(instance->bit_offset == 7) { - if(FURI_BIT(instance->bitstream_buff[1], 0) == 1) { - instance->bit_offset = 0; - for(size_t i = 0; i < instance->bytes_to_process - 1; i++) { - instance->bitstream_buff[i] = instance->bitstream_buff[i + 1]; - instance->bytes_to_process--; - } - } - } else { - if(FURI_BIT(instance->bitstream_buff[0], instance->bit_offset + 1) == 1) { - instance->bit_offset++; - } - } - - for(size_t i = 0; i < instance->bytes_to_process - 1; i++) { - instance->bitstream_buff[i] = - (instance->bitstream_buff[i] >> instance->bit_offset) | - (instance->bitstream_buff[i + 1] << (8 - instance->bit_offset)); - } - instance->last_byte = instance->bitstream_buff[instance->bytes_to_process - 1]; - instance->bytes_to_process--; - instance->bit_offset_calculated = true; - } else { - for(size_t i = 0; i < instance->bytes_to_process; i++) { - uint8_t next_byte = instance->bitstream_buff[i]; - instance->bitstream_buff[i] = (instance->last_byte >> instance->bit_offset) | - (next_byte << (8 - instance->bit_offset)); - instance->last_byte = next_byte; - } - } -} - -static Iso15693ParserCommand iso15693_parser_parse_sof(Iso15693Parser* instance) { - Iso15693ParserCommand command = Iso15693ParserCommandProcessed; - const uint8_t sof_1_out_of_4 = 0x21; - const uint8_t sof_1_out_of_256 = 0x81; - const uint8_t eof = 0x01; - - if(instance->bitstream_buff[0] == sof_1_out_of_4) { - instance->state = Iso15693ParserStateParse1OutOf4; - instance->byte_idx = 1; - } else if(instance->bitstream_buff[0] == sof_1_out_of_256) { - instance->state = Iso15693ParserStateParse1OutOf256; - instance->byte_idx = 1; - } else if(instance->bitstream_buff[0] == eof) { - instance->frame_parsed = true; - command = Iso15693ParserCommandSuccess; - } else { - command = Iso15693ParserCommandFail; - } - - return command; -} static Iso15693ParserCommand iso15693_parser_parse_1_out_of_4(Iso15693Parser* instance) { Iso15693ParserCommand command = Iso15693ParserCommandWaitData; const uint8_t bit_patterns_1_out_of_4[] = {0x02, 0x08, 0x20, 0x80}; - const uint8_t eof = 0x04; - - for(size_t i = instance->byte_idx; i < instance->bytes_to_process; i++) { - // Check EoF - if(instance->next_byte_part == 0) { - if(instance->bitstream_buff[i] == eof) { - instance->frame_parsed = true; - command = Iso15693ParserCommandSuccess; - break; - } - } + for(size_t i = 0; i < instance->bytes_to_process; i++) { // Check next pattern size_t j = 0; for(j = 0; j < COUNT_OF(bit_patterns_1_out_of_4); j++) { @@ -246,8 +199,15 @@ static Iso15693ParserCommand iso15693_parser_parse_1_out_of_4(Iso15693Parser* in break; } } + + if(command != Iso15693ParserCommandFail) { + if(instance->eof_received) { + command = Iso15693ParserCommandSuccess; + instance->frame_parsed = true; + } + } + instance->bytes_to_process = 0; - instance->byte_idx = 0; return command; } @@ -289,19 +249,18 @@ static Iso15693ParserCommand iso15693_parser_parse_1_out_of_256(Iso15693Parser* return command; } -static const Iso15693ParserStateHandler iso15693_parser_state_handlers[Iso15693ParserStateNum] = { - [Iso15693ParserStateParseSoF] = iso15693_parser_parse_sof, - [Iso15693ParserStateParse1OutOf4] = iso15693_parser_parse_1_out_of_4, - [Iso15693ParserStateParse1OutOf256] = iso15693_parser_parse_1_out_of_256, +static const Iso15693ParserStateHandler iso15693_parser_state_handlers[Iso15693ParserModeNum] = { + [Iso15693ParserMode1OutOf4] = iso15693_parser_parse_1_out_of_4, + [Iso15693ParserMode1OutOf256] = iso15693_parser_parse_1_out_of_256, }; bool iso15693_parser_run(Iso15693Parser* instance) { - if(instance->bytes_to_process) { - iso15693_parser_prepare_buff(instance); - + if((instance->state == Iso15693ParserStateParseSoF) && (instance->eof_received)) { + instance->frame_parsed = true; + } else if(instance->bytes_to_process) { Iso15693ParserCommand command = Iso15693ParserCommandProcessed; while(command == Iso15693ParserCommandProcessed) { - command = iso15693_parser_state_handlers[instance->state](instance); + command = iso15693_parser_state_handlers[instance->mode](instance); } if(command == Iso15693ParserCommandFail) { diff --git a/lib/signal_reader/signal_reader.c b/lib/signal_reader/signal_reader.c index b6758eebd605..43f6486c4808 100644 --- a/lib/signal_reader/signal_reader.c +++ b/lib/signal_reader/signal_reader.c @@ -21,6 +21,10 @@ #define SIGNAL_READER_DMA_GPIO_IRQ FuriHalInterruptIdDma2Ch2 #define SIGNAL_READER_DMA_GPIO_DEF SIGNAL_READER_DMA, SIGNAL_READER_DMA_GPIO +#define SIGNAL_READER_DMA_TRIGGER LL_DMA_CHANNEL_3 +#define SIGNAL_READER_DMA_TRIGGER_IRQ FuriHalInterruptIdDma2Ch3 +#define SIGNAL_READER_DMA_TRIGGER_DEF SIGNAL_READER_DMA, SIGNAL_READER_DMA_TRIGGER + #define SIGNAL_READER_DMA_CNT_SYNC LL_DMA_CHANNEL_5 #define SIGNAL_READER_DMA_CNT_SYNC_IRQ FuriHalInterruptIdDma2Ch5 #define SIGNAL_READER_DMA_CNT_SYNC_DEF SIGNAL_READER_DMA, SIGNAL_READER_DMA_CNT_SYNC @@ -30,8 +34,11 @@ struct SignalReader { const GpioPin* pin; GpioPull pull; SignalReaderPolarity polarity; + SignalReaderTrigger trigger; + uint16_t* gpio_buffer; uint8_t* bitstream_buffer; + uint32_t cnt_en; uint32_t tim_cnt_compensation; uint32_t tim_arr; @@ -110,6 +117,12 @@ void signal_reader_set_sample_rate( instance->tim_arr = time; } +void signal_reader_set_trigger(SignalReader* instance, SignalReaderTrigger trigger) { + furi_assert(instance); + + instance->trigger = trigger; +} + static void furi_hal_sw_digital_pin_dma_rx_isr(void* context) { SignalReader* instance = context; @@ -181,6 +194,8 @@ void signal_reader_start(SignalReader* instance, SignalReaderCallback callback, // EXTI delay compensation instance->tim_cnt_compensation = 9; + instance->cnt_en = SIGNAL_READER_CAPTURE_TIM->CR1; + instance->cnt_en |= TIM_CR1_CEN; furi_hal_bus_enable(FuriHalBusTIM16); @@ -236,6 +251,17 @@ void signal_reader_start(SignalReader* instance, SignalReaderCallback callback, LL_DMA_SetDataLength(SIGNAL_READER_DMA_CNT_SYNC_DEF, 1); LL_DMA_SetPeriphRequest(SIGNAL_READER_DMA_CNT_SYNC_DEF, LL_DMAMUX_REQ_GENERATOR0); + // Configure DMA Sync + LL_DMA_SetMemoryAddress(SIGNAL_READER_DMA_TRIGGER_DEF, (uint32_t)&instance->cnt_en); + LL_DMA_SetPeriphAddress( + SIGNAL_READER_DMA_TRIGGER_DEF, (uint32_t) & (SIGNAL_READER_CAPTURE_TIM->CR1)); + LL_DMA_ConfigTransfer( + SIGNAL_READER_DMA_TRIGGER_DEF, + LL_DMA_DIRECTION_MEMORY_TO_PERIPH | LL_DMA_PERIPH_NOINCREMENT | LL_DMA_MEMORY_NOINCREMENT | + LL_DMA_PDATAALIGN_HALFWORD | LL_DMA_MDATAALIGN_HALFWORD | LL_DMA_PRIORITY_VERYHIGH); + LL_DMA_SetDataLength(SIGNAL_READER_DMA_TRIGGER_DEF, 1); + LL_DMA_SetPeriphRequest(SIGNAL_READER_DMA_TRIGGER_DEF, LL_DMAMUX_REQ_GENERATOR0); + // Configure DMA Rx pin LL_DMA_SetMemoryAddress(SIGNAL_READER_DMA_GPIO_DEF, (uint32_t)instance->gpio_buffer); LL_DMA_SetPeriphAddress(SIGNAL_READER_DMA_GPIO_DEF, (uint32_t) & (instance->pin->port->IDR)); @@ -257,14 +283,18 @@ void signal_reader_start(SignalReader* instance, SignalReaderCallback callback, // Start DMA Sync timer LL_DMA_EnableChannel(SIGNAL_READER_DMA_CNT_SYNC_DEF); - LL_DMAMUX_EnableRequestGen(DMAMUX1, LL_DMAMUX_REQ_GEN_0); // Start DMA Rx pin LL_DMA_EnableChannel(SIGNAL_READER_DMA_GPIO_DEF); // Strat timer LL_TIM_SetCounter(SIGNAL_READER_CAPTURE_TIM, 0); - LL_TIM_EnableCounter(SIGNAL_READER_CAPTURE_TIM); + if(instance->trigger == SignalReaderTriggerNone) { + LL_TIM_EnableCounter(SIGNAL_READER_CAPTURE_TIM); + } else { + LL_DMA_EnableChannel(SIGNAL_READER_DMA_TRIGGER_DEF); + } + LL_DMAMUX_EnableRequestGen(DMAMUX1, LL_DMAMUX_REQ_GEN_0); // Need to clear flags before enabling DMA !!!! if(LL_DMA_IsActiveFlag_TC2(SIGNAL_READER_DMA)) LL_DMA_ClearFlag_TC1(SIGNAL_READER_DMA); if(LL_DMA_IsActiveFlag_TE2(SIGNAL_READER_DMA)) LL_DMA_ClearFlag_TE1(SIGNAL_READER_DMA); @@ -281,9 +311,8 @@ void signal_reader_stop(SignalReader* instance) { LL_DMA_DeInit(SIGNAL_READER_DMA_GPIO_DEF); // Deinit DMA Sync timer LL_DMA_DeInit(SIGNAL_READER_DMA_CNT_SYNC_DEF); + // Deinit DMA Trigger timer + LL_DMA_DeInit(SIGNAL_READER_DMA_TRIGGER_DEF); furi_hal_bus_disable(FuriHalBusTIM16); - - memset(instance->gpio_buffer, 0, sizeof(uint16_t) * instance->buffer_size * 8); - memset(instance->bitstream_buffer, 0, instance->buffer_size); } diff --git a/lib/signal_reader/signal_reader.h b/lib/signal_reader/signal_reader.h index 2213465c37c2..be18f295a448 100644 --- a/lib/signal_reader/signal_reader.h +++ b/lib/signal_reader/signal_reader.h @@ -34,6 +34,11 @@ typedef enum { SignalReaderPolarityInverted, } SignalReaderPolarity; +typedef enum { + SignalReaderTriggerNone, + SignalReaderTriggerRisingFallingEdge, +} SignalReaderTrigger; + typedef void (*SignalReaderCallback)(SignalReaderEvent event, void* context); typedef struct SignalReader SignalReader; @@ -51,6 +56,8 @@ void signal_reader_set_sample_rate( SignalReaderTimeUnit time_unit, uint32_t time); +void signal_reader_set_trigger(SignalReader* instance, SignalReaderTrigger trigger); + void signal_reader_start(SignalReader* instance, SignalReaderCallback callback, void* context); void signal_reader_stop(SignalReader* instance); From ac9d9cd060fe58b64871b739af4a8f180a82745d Mon Sep 17 00:00:00 2001 From: gornekich Date: Thu, 31 Aug 2023 19:40:18 +0400 Subject: [PATCH 144/149] Improve Iso15 emulation (#3029) * nfc hal: move listener start to iso14 config * nfc hal: don't exit from transparent mode in iso15 emulation --- firmware/targets/f7/furi_hal/f_hal_nfc.c | 35 ++++----------- .../targets/f7/furi_hal/f_hal_nfc_iso14443a.c | 16 +++++++ .../targets/f7/furi_hal/f_hal_nfc_iso15693.c | 45 ++++++++++--------- lib/digital_signal/digital_signal.c | 3 ++ .../presets/nfc/iso15693_signal.c | 1 + lib/signal_reader/signal_reader.c | 1 - 6 files changed, 51 insertions(+), 50 deletions(-) diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc.c b/firmware/targets/f7/furi_hal/f_hal_nfc.c index 3047341ecbe0..55ee43452c90 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfc.c +++ b/firmware/targets/f7/furi_hal/f_hal_nfc.c @@ -365,6 +365,14 @@ FHalNfcError f_hal_nfc_reset_mode() { FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; st25r3916_direct_cmd(handle, ST25R3916_CMD_STOP); + + const FHalNfcMode mode = f_hal_nfc.mode; + const FHalNfcTech tech = f_hal_nfc.tech; + if(mode == FHalNfcModePoller) { + error = f_hal_nfc_tech[tech]->poller.deinit(handle); + } else if(mode == FHalNfcModeListener) { + error = f_hal_nfc_tech[tech]->listener.deinit(handle); + } // Set default value in mode register st25r3916_write_reg(handle, ST25R3916_REG_MODE, ST25R3916_REG_MODE_om0); st25r3916_write_reg(handle, ST25R3916_REG_STREAM_MODE, 0); @@ -389,15 +397,6 @@ FHalNfcError f_hal_nfc_reset_mode() { ST25R3916_REG_CORR_CONF1_corr_s1 | ST25R3916_REG_CORR_CONF1_corr_s0); st25r3916_write_reg(handle, ST25R3916_REG_CORR_CONF2, 0); - const FHalNfcMode mode = f_hal_nfc.mode; - const FHalNfcTech tech = f_hal_nfc.tech; - - if(mode == FHalNfcModePoller) { - error = f_hal_nfc_tech[tech]->poller.deinit(handle); - } else if(mode == FHalNfcModeListener) { - error = f_hal_nfc_tech[tech]->listener.deinit(handle); - } - return error; } @@ -585,24 +584,6 @@ FHalNfcError f_hal_nfc_trx_reset() { } FHalNfcError f_hal_nfc_listener_start() { - FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; - - st25r3916_direct_cmd(handle, ST25R3916_CMD_STOP); - uint32_t interrupts = - (/*ST25R3916_IRQ_MASK_FWL | ST25R3916_IRQ_MASK_TXE |*/ ST25R3916_IRQ_MASK_RXS /*| - ST25R3916_IRQ_MASK_RXE | ST25R3916_IRQ_MASK_PAR | ST25R3916_IRQ_MASK_CRC | - ST25R3916_IRQ_MASK_ERR1 | ST25R3916_IRQ_MASK_ERR2 | ST25R3916_IRQ_MASK_EON | - ST25R3916_IRQ_MASK_EOF | ST25R3916_IRQ_MASK_WU_A_X | ST25R3916_IRQ_MASK_WU_A*/); - // Clear interrupts - // FURI_LOG_I("LISTEN START", "%lX", interrupts); - st25r3916_get_irq(handle); - // Enable interrupts - st25r3916_mask_irq(handle, interrupts); - // Enable auto collision resolution - st25r3916_clear_reg_bits( - handle, ST25R3916_REG_PASSIVE_TARGET, ST25R3916_REG_PASSIVE_TARGET_d_106_ac_a); - st25r3916_direct_cmd(handle, ST25R3916_CMD_GOTO_SENSE); - return FHalNfcErrorNone; } diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc_iso14443a.c b/firmware/targets/f7/furi_hal/f_hal_nfc_iso14443a.c index c80f9c9960cd..20886a84d69d 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfc_iso14443a.c +++ b/firmware/targets/f7/furi_hal/f_hal_nfc_iso14443a.c @@ -77,6 +77,22 @@ static FHalNfcError f_hal_nfc_iso14443a_listener_init(FuriHalSpiBusHandle* handl st25r3916_write_reg(handle, ST25R3916_REG_MASK_RX_TIMER, 0x02); + st25r3916_direct_cmd(handle, ST25R3916_CMD_STOP); + uint32_t interrupts = + (/*ST25R3916_IRQ_MASK_FWL | ST25R3916_IRQ_MASK_TXE |*/ ST25R3916_IRQ_MASK_RXS /*| + ST25R3916_IRQ_MASK_RXE | ST25R3916_IRQ_MASK_PAR | ST25R3916_IRQ_MASK_CRC | + ST25R3916_IRQ_MASK_ERR1 | ST25R3916_IRQ_MASK_ERR2 | ST25R3916_IRQ_MASK_EON | + ST25R3916_IRQ_MASK_EOF | ST25R3916_IRQ_MASK_WU_A_X | ST25R3916_IRQ_MASK_WU_A*/); + // Clear interrupts + // FURI_LOG_I("LISTEN START", "%lX", interrupts); + st25r3916_get_irq(handle); + // Enable interrupts + st25r3916_mask_irq(handle, interrupts); + // Enable auto collision resolution + st25r3916_clear_reg_bits( + handle, ST25R3916_REG_PASSIVE_TARGET, ST25R3916_REG_PASSIVE_TARGET_d_106_ac_a); + st25r3916_direct_cmd(handle, ST25R3916_CMD_GOTO_SENSE); + return f_hal_nfc_iso14443a_common_init(handle); } diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc_iso15693.c b/firmware/targets/f7/furi_hal/f_hal_nfc_iso15693.c index fbaaa08985d7..9cf088e5fd3a 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfc_iso15693.c +++ b/firmware/targets/f7/furi_hal/f_hal_nfc_iso15693.c @@ -273,6 +273,21 @@ static FHalNfcError f_hal_nfc_iso15693_poller_rx( return error; } +static void f_hal_nfc_iso15693_listener_transparent_mode_enter(FuriHalSpiBusHandle* handle) { + st25r3916_direct_cmd(handle, ST25R3916_CMD_TRANSPARENT_MODE); + + furi_hal_spi_bus_handle_deinit(handle); + f_hal_nfc_deinit_gpio_isr(); +} + +static void f_hal_nfc_iso15693_listener_transparent_mode_exit(FuriHalSpiBusHandle* handle) { + // Configure gpio back to SPI and exit transparent mode + f_hal_nfc_init_gpio_isr(); + furi_hal_spi_bus_handle_init(handle); + + st25r3916_direct_cmd(handle, ST25R3916_CMD_UNMASK_RECEIVE_DATA); +} + static FHalNfcError f_hal_nfc_iso15693_listener_init(FuriHalSpiBusHandle* handle) { furi_assert(f_hal_nfc_iso15693_listener == NULL); @@ -295,34 +310,24 @@ static FHalNfcError f_hal_nfc_iso15693_listener_init(FuriHalSpiBusHandle* handle st25r3916_change_reg_bits( handle, ST25R3916_REG_MODE, ST25R3916_REG_MODE_targ, ST25R3916_REG_MODE_targ_targ); - return f_hal_nfc_iso15693_common_init(handle); + FHalNfcError error = f_hal_nfc_iso15693_common_init(handle); + + f_hal_nfc_iso15693_listener_transparent_mode_enter(handle); + + return error; } static FHalNfcError f_hal_nfc_iso15693_listener_deinit(FuriHalSpiBusHandle* handle) { - UNUSED(handle); furi_assert(f_hal_nfc_iso15693_listener); + f_hal_nfc_iso15693_listener_transparent_mode_exit(handle); + f_hal_nfc_iso15693_listener_free(f_hal_nfc_iso15693_listener); f_hal_nfc_iso15693_listener = NULL; return FHalNfcErrorNone; } -static void f_hal_nfc_iso15693_listener_transparent_mode_enter(FuriHalSpiBusHandle* handle) { - st25r3916_direct_cmd(handle, ST25R3916_CMD_TRANSPARENT_MODE); - - furi_hal_spi_bus_handle_deinit(handle); - f_hal_nfc_deinit_gpio_isr(); -} - -static void f_hal_nfc_iso15693_listener_transparent_mode_exit(FuriHalSpiBusHandle* handle) { - // Configure gpio back to SPI and exit transparent mode - f_hal_nfc_init_gpio_isr(); - furi_hal_spi_bus_handle_init(handle); - - st25r3916_direct_cmd(handle, ST25R3916_CMD_UNMASK_RECEIVE_DATA); -} - static FHalNfcError f_hal_nfc_iso15693_listener_tx_transparent(const uint8_t* data, size_t data_size) { iso15693_signal_tx( @@ -347,9 +352,7 @@ static void f_hal_nfc_iso15693_parser_callback(Iso15693ParserEvent event, void* static FHalNfcEvent f_hal_nfc_iso15693_wait_event(uint32_t timeout_ms) { FHalNfcEvent event = 0; - FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; - f_hal_nfc_iso15693_listener_transparent_mode_enter(handle); FuriThreadId thread_id = furi_thread_get_current_id(); iso15693_parser_start( f_hal_nfc_iso15693_listener->parser, f_hal_nfc_iso15693_parser_callback, thread_id); @@ -363,7 +366,6 @@ static FHalNfcEvent f_hal_nfc_iso15693_wait_event(uint32_t timeout_ms) { if(flag & FHalNfcEventInternalTypeAbort) { event = FHalNfcEventAbortRequest; - f_hal_nfc_iso15693_listener_transparent_mode_exit(handle); break; } if(flag & FHalNfcEventInternalTypeTransparentDataReceived) { @@ -382,14 +384,13 @@ static FHalNfcError f_hal_nfc_iso15693_listener_tx( FuriHalSpiBusHandle* handle, const uint8_t* tx_data, size_t tx_bits) { + UNUSED(handle); furi_assert(f_hal_nfc_iso15693_listener); FHalNfcError error = FHalNfcErrorNone; error = f_hal_nfc_iso15693_listener_tx_transparent(tx_data, tx_bits / BITS_IN_BYTE); - f_hal_nfc_iso15693_listener_transparent_mode_exit(handle); - return error; } diff --git a/lib/digital_signal/digital_signal.c b/lib/digital_signal/digital_signal.c index 25adb878b78e..0a5e1eb76a68 100644 --- a/lib/digital_signal/digital_signal.c +++ b/lib/digital_signal/digital_signal.c @@ -645,6 +645,9 @@ bool digital_sequence_send(DigitalSequence* sequence) { FURI_CRITICAL_EXIT(); digital_sequence_finish(sequence); + // TODO reconfig GPIO to initial state + furi_hal_gpio_write(sequence->gpio, false); + return true; } diff --git a/lib/digital_signal/presets/nfc/iso15693_signal.c b/lib/digital_signal/presets/nfc/iso15693_signal.c index d140c7593c68..7e8e2571d190 100644 --- a/lib/digital_signal/presets/nfc/iso15693_signal.c +++ b/lib/digital_signal/presets/nfc/iso15693_signal.c @@ -192,5 +192,6 @@ void iso15693_signal_tx( digital_sequence_clear(instance->tx_sequence); iso15693_signal_encode(instance, data_rate, tx_data, tx_data_size); digital_sequence_send(instance->tx_sequence); + FURI_CRITICAL_EXIT(); } diff --git a/lib/signal_reader/signal_reader.c b/lib/signal_reader/signal_reader.c index 43f6486c4808..7c4d0bae7ed3 100644 --- a/lib/signal_reader/signal_reader.c +++ b/lib/signal_reader/signal_reader.c @@ -228,7 +228,6 @@ void signal_reader_start(SignalReader* instance, SignalReaderCallback callback, /* We need the EXTI to be configured as interrupt generating line, but no ISR registered */ furi_hal_gpio_init( instance->pin, GpioModeInterruptRiseFall, instance->pull, GpioSpeedVeryHigh); - furi_delay_ms(10); /* Set DMAMUX request generation signal ID on specified DMAMUX channel */ LL_DMAMUX_SetRequestSignalID( From ad042e8aa5271ff8f29d5bcc69e7e5b1f963f7bb Mon Sep 17 00:00:00 2001 From: RebornedBrain <138568282+RebornedBrain@users.noreply.github.com> Date: Thu, 31 Aug 2023 19:59:41 +0300 Subject: [PATCH 145/149] [FL-3574] Ultralight composite command handling (#3028) * Added callback on FieldOff event from 14443 to mfu * Moved command enum and callback type to _i.h file * Added context for composite command to mfu_listener * Functions for composite commands processing added * Composite commands processing logic added * Added COMP_WRITE command implementation * Patch with some fixes --- .../iso14443_3a/iso14443_3a_listener.c | 10 ++- .../iso14443_4a/iso14443_4a_listener.c | 4 +- .../mf_classic/mf_classic_listener.c | 1 + .../protocols/mf_ultralight/mf_ultralight.h | 1 + .../mf_ultralight/mf_ultralight_listener.c | 90 ++++++++++++++----- .../mf_ultralight/mf_ultralight_listener_i.c | 22 +++++ .../mf_ultralight/mf_ultralight_listener_i.h | 26 ++++++ lib/nfc/protocols/nfc_generic_event.h | 1 + 8 files changed, 131 insertions(+), 24 deletions(-) diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c b/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c index 16e5ac294dd1..7fcc6815a471 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c @@ -89,10 +89,18 @@ NfcCommand iso14443_3a_listener_run(NfcGenericEvent event, void* context) { if(nfc_event->type == NfcEventTypeListenerActivated) { instance->state = Iso14443_3aListenerStateActive; } else if(nfc_event->type == NfcEventTypeFieldOff) { - command = NfcCommandReset; instance->state = Iso14443_3aListenerStateIdle; + if(instance->callback) { + instance->iso14443_3a_event.type = Iso14443_3aListenerEventTypeFieldOff; + instance->callback(instance->generic_event, instance->context); + } + command = NfcCommandReset; } else if(nfc_event->type == NfcEventTypeRxEnd) { if(iso14443_3a_listener_halt_received(nfc_event->data.buffer)) { + if(instance->callback) { + instance->iso14443_3a_event.type = Iso14443_3aListenerEventTypeHalted; + instance->callback(instance->generic_event, instance->context); + } command = NfcCommandReset; } else { if(iso14443_crc_check(Iso14443CrcTypeA, nfc_event->data.buffer)) { diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_listener.c b/lib/nfc/protocols/iso14443_4a/iso14443_4a_listener.c index 4bb413090ea4..546fc4fbf1d0 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_listener.c +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_listener.c @@ -70,7 +70,7 @@ static NfcCommand iso14443_4a_listener_run(NfcGenericEvent event, void* context) bit_buffer_get_byte(rx_buffer, 0) == ISO14443_4A_CMD_READ_ATS) { if(iso14443_4a_listener_send_ats(instance, instance->data->ats_data) != Iso14443_4aErrorNone) { - command = NfcCommandStop; + command = NfcCommandContinue; } else { instance->state = Iso14443_4aListenerStateActive; } @@ -87,7 +87,7 @@ static NfcCommand iso14443_4a_listener_run(NfcGenericEvent event, void* context) iso14443_3a_event->type == Iso14443_3aListenerEventTypeHalted || iso14443_3a_event->type == Iso14443_3aListenerEventTypeFieldOff) { instance->state = Iso14443_4aListenerStateIdle; - command = NfcCommandStop; + command = NfcCommandContinue; } return command; diff --git a/lib/nfc/protocols/mf_classic/mf_classic_listener.c b/lib/nfc/protocols/mf_classic/mf_classic_listener.c index 9a375490365e..ebb9f40ba69a 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_listener.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_listener.c @@ -533,6 +533,7 @@ NfcCommand mf_classic_listener_run(NfcGenericEvent event, void* context) { if(iso3_event->type == Iso14443_3aListenerEventTypeFieldOff) { mf_classic_listener_reset_state(instance); + command = NfcCommandReset; } else if( (iso3_event->type == Iso14443_3aListenerEventTypeReceivedData) || (iso3_event->type == Iso14443_3aListenerEventTypeReceivedStandardFrame)) { diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h index c4378d78aa49..e88007025c0f 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h @@ -11,6 +11,7 @@ extern "C" { #define MF_ULTRALIGHT_CMD_GET_VERSION (0x60) #define MF_ULTRALIGHT_CMD_READ_PAGE (0x30) #define MF_ULTRALIGHT_CMD_SECTOR_SELECT (0xC2) +#define MF_ULTRALIGHT_CMD_COMP_WRITE (0xA0) #define MF_ULTRALIGHT_CMD_WRITE_PAGE (0xA2) #define MF_ULTRALIGTH_CMD_READ_SIG (0x3C) #define MF_ULTRALIGHT_CMD_READ_CNT (0x39) diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c index 8eb2d542de16..9bf3868b1bf5 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c @@ -14,16 +14,6 @@ typedef enum { MfUltralightListenerAccessTypeWrite, } MfUltralightListenerAccessType; -typedef enum { - MfUltralightCommandNotFound, - MfUltralightCommandProcessed, - MfUltralightCommandNotProcessedNAK, - MfUltralightCommandNotProcessedSilent, -} MfUltralightCommand; - -typedef MfUltralightCommand ( - *MfUltralightListenerCommandCallback)(MfUltralightListener* instance, BitBuffer* buf); - typedef struct { uint8_t cmd; size_t cmd_len_bits; @@ -324,6 +314,53 @@ static MfUltralightCommand return command; } +static MfUltralightCommand + mf_ultralight_comp_write_handler_p2(MfUltralightListener* instance, BitBuffer* buffer) { + MfUltralightCommand command = MfUltralightCommandNotProcessedNAK; + FURI_LOG_D(TAG, "CMD_CM_WR_2"); + + do { + if(bit_buffer_get_size_bytes(buffer) != 16) break; + + const uint8_t* rx_data = bit_buffer_get_data(buffer); + uint8_t start_page = instance->composite_cmd.data; + memcpy(instance->data->page[start_page].data, &rx_data[0], sizeof(MfUltralightPage)); + mf_ultralight_listener_send_short_resp(instance, MF_ULTRALIGHT_CMD_ACK); + + command = MfUltralightCommandProcessed; + } while(false); + + return command; +} + +static MfUltralightCommand + mf_ultralight_comp_write_handler_p1(MfUltralightListener* instance, BitBuffer* buffer) { + MfUltralightCommand command = MfUltralightCommandNotProcessedSilent; + + FURI_LOG_D(TAG, "CMD_CM_WR_1"); + + do { + if(!mf_ultralight_support_feature( + instance->features, MfUltralightFeatureSupportCompatibleWrite)) + break; + + uint8_t start_page = bit_buffer_get_byte(buffer, 1); + uint16_t pages_total = instance->data->pages_total; + + if(start_page < 2 || start_page > pages_total) { + command = MfUltralightCommandNotProcessedNAK; + break; + } + + instance->composite_cmd.data = start_page; + mf_ultralight_listener_send_short_resp(instance, MF_ULTRALIGHT_CMD_ACK); + command = MfUltralightCommandProcessed; + mf_ultralight_composite_command_set_next(instance, mf_ultralight_comp_write_handler_p2); + } while(false); + + return command; +} + static const MfUltralightListenerCmdHandler mf_ultralight_command[] = { { .cmd = MF_ULTRALIGHT_CMD_READ_PAGE, @@ -365,6 +402,11 @@ static const MfUltralightListenerCmdHandler mf_ultralight_command[] = { .cmd_len_bits = 6 * 8, .callback = mf_ultralight_listener_increase_counter_handler, }, + { + .cmd = MF_ULTRALIGHT_CMD_COMP_WRITE, + .cmd_len_bits = 2 * 8, + .callback = mf_ultralight_comp_write_handler_p1, + }, }; static void mf_ultralight_listener_prepare_emulation(MfUltralightListener* instance) { @@ -385,6 +427,7 @@ MfUltralightListener* mf_ultralight_listener_alloc( instance->data = mf_ultralight_alloc(); mf_ultralight_copy(instance->data, data); mf_ultralight_listener_prepare_emulation(instance); + mf_ultralight_composite_command_reset(instance); instance->tx_buffer = bit_buffer_alloc(MF_ULTRALIGHT_LISTENER_MAX_TX_BUFF_SIZE); instance->mfu_event.data = &instance->mfu_event_data; @@ -438,14 +481,17 @@ NfcCommand mf_ultralight_listener_run(NfcGenericEvent event, void* context) { size_t size = bit_buffer_get_size(rx_buffer); uint8_t cmd = bit_buffer_get_byte(rx_buffer, 0); - for(size_t i = 0; i < COUNT_OF(mf_ultralight_command); i++) { - if(size != mf_ultralight_command[i].cmd_len_bits) continue; - if(cmd != mf_ultralight_command[i].cmd) continue; - mfu_command = mf_ultralight_command[i].callback(instance, rx_buffer); + if(mf_ultralight_composite_command_in_progress(instance)) { + mfu_command = mf_ultralight_composite_command_run(instance, rx_buffer); + } else { + for(size_t i = 0; i < COUNT_OF(mf_ultralight_command); i++) { + if(size != mf_ultralight_command[i].cmd_len_bits) continue; + if(cmd != mf_ultralight_command[i].cmd) continue; + mfu_command = mf_ultralight_command[i].callback(instance, rx_buffer); - if(mfu_command != MfUltralightCommandNotFound) break; + if(mfu_command != MfUltralightCommandNotFound) break; + } } - if(mfu_command != MfUltralightCommandProcessed) { instance->state = MfUltraligthListenerStateIdle; instance->auth_state = MfUltralightListenerAuthStateIdle; @@ -455,11 +501,13 @@ NfcCommand mf_ultralight_listener_run(NfcGenericEvent event, void* context) { mf_ultralight_listener_send_short_resp(instance, MF_ULTRALIGHT_CMD_NACK); } } - } else if(iso14443_3a_event->type == Iso14443_3aListenerEventTypeReceivedData) { - command = NfcCommandReset; - } else if(iso14443_3a_event->type == Iso14443_3aListenerEventTypeFieldOff) { - command = NfcCommandReset; - } else if(iso14443_3a_event->type == Iso14443_3aListenerEventTypeHalted) { + } else if( + iso14443_3a_event->type == Iso14443_3aListenerEventTypeReceivedData || + iso14443_3a_event->type == Iso14443_3aListenerEventTypeFieldOff || + iso14443_3a_event->type == Iso14443_3aListenerEventTypeHalted) { + // TODO generic state reset ? + mf_ultralight_composite_command_reset(instance); + instance->auth_state = MfUltralightListenerAuthStateIdle; command = NfcCommandReset; } diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.c index 20f433322242..43e54309e362 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.c @@ -161,4 +161,26 @@ void mf_ultraligt_mirror_prepare_emulation(MfUltralightListener* instance) { instance->mirror.ascii_mirror_data, instance->data->counter[2].data, sizeof(instance->data->counter[2].data)); +} + +bool mf_ultralight_composite_command_in_progress(MfUltralightListener* instance) { + return (instance->composite_cmd.callback != NULL); +} + +MfUltralightCommand + mf_ultralight_composite_command_run(MfUltralightListener* instance, BitBuffer* buffer) { + MfUltralightCommand command = (instance->composite_cmd.callback)(instance, buffer); + mf_ultralight_composite_command_reset(instance); + return command; +} + +void mf_ultralight_composite_command_reset(MfUltralightListener* instance) { + instance->composite_cmd.callback = NULL; + instance->composite_cmd.data = 0; +} + +void mf_ultralight_composite_command_set_next( + MfUltralightListener* instance, + const MfUltralightListenerCommandCallback handler) { + instance->composite_cmd.callback = handler; } \ No newline at end of file diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h index eb188041f6a6..ce6d0d8b9e08 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h @@ -17,6 +17,23 @@ typedef enum { MfUltraligthListenerStateIdle, } MfUltraligthListenerState; +typedef enum { + MfUltralightCommandNotFound, + MfUltralightCommandProcessed, + MfUltralightCommandNotProcessedNAK, + MfUltralightCommandNotProcessedSilent, +} MfUltralightCommand; + +typedef MfUltralightCommand ( + *MfUltralightListenerCommandCallback)(MfUltralightListener* instance, BitBuffer* buf); + +typedef uint8_t MfUltralightListenerCompositeCommandData; + +typedef struct { + MfUltralightListenerCompositeCommandData data; + MfUltralightListenerCommandCallback callback; +} MfUltralightListenerCompositeCommandContext; + typedef struct { uint8_t enabled; uint8_t ascii_offset; @@ -41,6 +58,7 @@ struct MfUltralightListener { MfUltralightListenerEventData mfu_event_data; NfcGenericCallback callback; MfUltralightMirrorMode mirror; + MfUltralightListenerCompositeCommandContext composite_cmd; void* context; }; @@ -50,6 +68,14 @@ void mf_ultralight_mirror_read_handler( uint8_t mirror_page_num, uint8_t* dest, MfUltralightListener* instance); + +void mf_ultralight_composite_command_set_next( + MfUltralightListener* instance, + const MfUltralightListenerCommandCallback handler); +void mf_ultralight_composite_command_reset(MfUltralightListener* instance); +bool mf_ultralight_composite_command_in_progress(MfUltralightListener* instance); +MfUltralightCommand + mf_ultralight_composite_command_run(MfUltralightListener* instance, BitBuffer* buffer); #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/nfc_generic_event.h b/lib/nfc/protocols/nfc_generic_event.h index 64c7939d00d1..cee465eb8a2c 100644 --- a/lib/nfc/protocols/nfc_generic_event.h +++ b/lib/nfc/protocols/nfc_generic_event.h @@ -14,6 +14,7 @@ typedef void NfcGenericEventData; typedef struct { NfcProtocol protocol; NfcGenericInstance* instance; + // TODO change to event NfcGenericEventData* data; } NfcGenericEvent; From 2ad34a725717193dd8f0f5acf2a129d53a2b496f Mon Sep 17 00:00:00 2001 From: gornekich Date: Fri, 1 Sep 2023 15:45:12 +0400 Subject: [PATCH 146/149] [FL-3571] BitBuffer and generic listener optimization (#3026) * nfc: rework bit buffer to save parity in packed format * nfc: rework protocol data allocation for listeners * nfc: rework data allocation in generic listener * nfc device: rework get data --- .../main/nfc/scenes/nfc_scene_generate_info.c | 2 +- .../nfc_scene_mf_classic_detect_reader.c | 2 +- firmware/targets/f7/api_symbols.csv | 19 +++++----- .../targets/f7/furi_hal/f_hal_nfc_iso14443a.c | 2 +- firmware/targets/furi_hal_include/f_hal_nfc.h | 2 +- .../presets/nfc/iso14443_3a_signal.c | 7 ++-- .../presets/nfc/iso14443_3a_signal.h | 2 +- lib/nfc/nfc.c | 2 +- lib/nfc/nfc_device.c | 30 +-------------- lib/nfc/nfc_device.h | 2 - lib/nfc/nfc_device_i.c | 37 +++++++++++++++++++ lib/nfc/nfc_device_i.h | 21 +++++++++++ lib/nfc/nfc_listener.c | 23 +++++++----- lib/nfc/protocols/felica/felica.c | 2 +- lib/nfc/protocols/felica/felica.h | 2 +- lib/nfc/protocols/iso14443_3a/iso14443_3a.c | 2 +- lib/nfc/protocols/iso14443_3a/iso14443_3a.h | 2 +- .../iso14443_3a/iso14443_3a_listener.c | 6 +-- lib/nfc/protocols/iso14443_3b/iso14443_3b.c | 2 +- lib/nfc/protocols/iso14443_3b/iso14443_3b.h | 2 +- lib/nfc/protocols/iso14443_4a/iso14443_4a.c | 2 +- lib/nfc/protocols/iso14443_4a/iso14443_4a.h | 2 +- .../iso14443_4a/iso14443_4a_listener.c | 9 ++--- lib/nfc/protocols/iso15693_3/iso15693_3.c | 2 +- lib/nfc/protocols/iso15693_3/iso15693_3.h | 2 +- .../iso15693_3/iso15693_3_listener.c | 6 +-- lib/nfc/protocols/mf_classic/mf_classic.c | 2 +- lib/nfc/protocols/mf_classic/mf_classic.h | 2 +- .../mf_classic/mf_classic_listener.c | 4 +- lib/nfc/protocols/mf_desfire/mf_desfire.c | 2 +- lib/nfc/protocols/mf_desfire/mf_desfire.h | 2 +- .../protocols/mf_ultralight/mf_ultralight.c | 2 +- .../protocols/mf_ultralight/mf_ultralight.h | 2 +- .../mf_ultralight/mf_ultralight_listener.c | 6 +-- lib/nfc/protocols/nfc_device_base_i.h | 2 +- lib/nfc/protocols/nfc_listener_base.h | 2 +- lib/toolbox/bit_buffer.c | 26 +++++++++---- lib/toolbox/bit_buffer.h | 2 +- 38 files changed, 140 insertions(+), 106 deletions(-) create mode 100644 lib/nfc/nfc_device_i.c create mode 100644 lib/nfc/nfc_device_i.h diff --git a/applications/main/nfc/scenes/nfc_scene_generate_info.c b/applications/main/nfc/scenes/nfc_scene_generate_info.c index 1e6db818fd94..c4f86ff4a6db 100644 --- a/applications/main/nfc/scenes/nfc_scene_generate_info.c +++ b/applications/main/nfc/scenes/nfc_scene_generate_info.c @@ -17,7 +17,7 @@ void nfc_scene_generate_info_on_enter(void* context) { furi_assert((protocol == NfcProtocolMfUltralight) || (protocol == NfcProtocolMfClassic)); const Iso14443_3aData* iso14443_3a_data = - nfc_device_get_base_data(instance->nfc_device, protocol); + nfc_device_get_data(instance->nfc_device, NfcProtocolIso14443_3a); // Setup dialog view Widget* widget = instance->widget; diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_detect_reader.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_detect_reader.c index 756544faf2ff..cc0ff4692d93 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_detect_reader.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_detect_reader.c @@ -61,7 +61,7 @@ void nfc_scene_mf_classic_detect_reader_on_enter(void* context) { } const Iso14443_3aData* iso3_data = - nfc_device_get_base_data(instance->nfc_device, NfcProtocolMfClassic); + nfc_device_get_data(instance->nfc_device, NfcProtocolIso14443_3a); uint32_t cuid = iso14443_3a_get_cuid(iso3_data); instance->mfkey32_logger = mfkey32_logger_alloc(cuid); diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 95e8eab74318..5573f3479f4d 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,+,35.3,, +Version,+,38.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -601,7 +601,7 @@ Function,+,bit_buffer_get_byte,uint8_t,"const BitBuffer*, size_t" Function,+,bit_buffer_get_byte_from_bit,uint8_t,"const BitBuffer*, size_t" Function,+,bit_buffer_get_capacity_bytes,size_t,const BitBuffer* Function,+,bit_buffer_get_data,const uint8_t*,const BitBuffer* -Function,+,bit_buffer_get_parity,const _Bool*,const BitBuffer* +Function,+,bit_buffer_get_parity,const uint8_t*,const BitBuffer* Function,+,bit_buffer_get_size,size_t,const BitBuffer* Function,+,bit_buffer_get_size_bytes,size_t,const BitBuffer* Function,+,bit_buffer_has_partial_byte,_Bool,const BitBuffer* @@ -900,7 +900,7 @@ Function,-,f_hal_nfc_timer_block_tx_stop,void, Function,-,f_hal_nfc_timer_fwt_start,void,uint32_t Function,-,f_hal_nfc_timer_fwt_stop,void, Function,-,f_hal_nfc_trx_reset,FHalNfcError, -Function,-,f_hal_nfca_listener_tx_custom_parity,FHalNfcError,"const uint8_t*, const _Bool*, size_t" +Function,-,f_hal_nfca_listener_tx_custom_parity,FHalNfcError,"const uint8_t*, const uint8_t*, size_t" Function,-,f_hal_nfca_receive_sdd_frame,FHalNfcError,"uint8_t*, size_t, size_t*" Function,-,f_hal_nfca_send_sdd_frame,FHalNfcError,"const uint8_t*, size_t" Function,-,f_hal_nfca_send_short_frame,FHalNfcError,FHalNfcaShortFrame @@ -1844,7 +1844,7 @@ Function,-,isnanf,int,float Function,+,iso14443_3a_alloc,Iso14443_3aData*, Function,+,iso14443_3a_copy,void,"Iso14443_3aData*, const Iso14443_3aData*" Function,+,iso14443_3a_free,void,Iso14443_3aData* -Function,+,iso14443_3a_get_base_data,const Iso14443_3aData*,const Iso14443_3aData* +Function,+,iso14443_3a_get_base_data,Iso14443_3aData*,const Iso14443_3aData* Function,+,iso14443_3a_get_cuid,uint32_t,const Iso14443_3aData* Function,+,iso14443_3a_get_device_name,const char*,"const Iso14443_3aData*, NfcDeviceNameType" Function,+,iso14443_3a_get_uid,const uint8_t*,"const Iso14443_3aData*, size_t*" @@ -1858,7 +1858,7 @@ Function,+,iso14443_3a_verify,_Bool,"Iso14443_3aData*, const FuriString*" Function,+,iso14443_3b_alloc,Iso14443_3bData*, Function,+,iso14443_3b_copy,void,"Iso14443_3bData*, const Iso14443_3bData*" Function,+,iso14443_3b_free,void,Iso14443_3bData* -Function,+,iso14443_3b_get_base_data,const Iso14443_3bData*,const Iso14443_3bData* +Function,+,iso14443_3b_get_base_data,Iso14443_3bData*,const Iso14443_3bData* Function,+,iso14443_3b_get_device_name,const char*,"const Iso14443_3bData*, NfcDeviceNameType" Function,+,iso14443_3b_get_uid,const uint8_t*,"const Iso14443_3bData*, size_t*" Function,+,iso14443_3b_is_equal,_Bool,"const Iso14443_3bData*, const Iso14443_3bData*" @@ -1870,7 +1870,7 @@ Function,+,iso14443_3b_verify,_Bool,"Iso14443_3bData*, const FuriString*" Function,+,iso14443_4a_alloc,Iso14443_4aData*, Function,+,iso14443_4a_copy,void,"Iso14443_4aData*, const Iso14443_4aData*" Function,+,iso14443_4a_free,void,Iso14443_4aData* -Function,+,iso14443_4a_get_base_data,const Iso14443_3aData*,const Iso14443_4aData* +Function,+,iso14443_4a_get_base_data,Iso14443_3aData*,const Iso14443_4aData* Function,+,iso14443_4a_get_device_name,const char*,"const Iso14443_4aData*, NfcDeviceNameType" Function,+,iso14443_4a_get_uid,const uint8_t*,"const Iso14443_4aData*, size_t*" Function,+,iso14443_4a_is_ats_supported,_Bool,const Iso14443_4aData* @@ -2065,7 +2065,7 @@ Function,+,mf_classic_block_to_value,_Bool,"const MfClassicBlock*, int32_t*, uin Function,+,mf_classic_copy,void,"MfClassicData*, const MfClassicData*" Function,+,mf_classic_detect_protocol,_Bool,"Iso14443_3aData*, MfClassicType*" Function,+,mf_classic_free,void,MfClassicData* -Function,+,mf_classic_get_base_data,const Iso14443_3aData*,const MfClassicData* +Function,+,mf_classic_get_base_data,Iso14443_3aData*,const MfClassicData* Function,+,mf_classic_get_blocks_num_in_sector,uint8_t,uint8_t Function,+,mf_classic_get_device_name,const char*,"const MfClassicData*, NfcDeviceNameType" Function,+,mf_classic_get_first_block_num_of_sector,uint8_t,uint8_t @@ -2105,7 +2105,7 @@ Function,+,mf_desfire_alloc,MfDesfireData*, Function,+,mf_desfire_copy,void,"MfDesfireData*, const MfDesfireData*" Function,+,mf_desfire_free,void,MfDesfireData* Function,+,mf_desfire_get_application,const MfDesfireApplication*,"const MfDesfireData*, const MfDesfireApplicationId*" -Function,+,mf_desfire_get_base_data,const Iso14443_4aData*,const MfDesfireData* +Function,+,mf_desfire_get_base_data,Iso14443_4aData*,const MfDesfireData* Function,+,mf_desfire_get_device_name,const char*,"const MfDesfireData*, NfcDeviceNameType" Function,+,mf_desfire_get_file_data,const MfDesfireFileData*,"const MfDesfireApplication*, const MfDesfireFileId*" Function,+,mf_desfire_get_file_settings,const MfDesfireFileSettings*,"const MfDesfireApplication*, const MfDesfireFileId*" @@ -2120,7 +2120,7 @@ Function,+,mf_ultralight_alloc,MfUltralightData*, Function,+,mf_ultralight_copy,void,"MfUltralightData*, const MfUltralightData*" Function,+,mf_ultralight_detect_protocol,_Bool,const Iso14443_3aData* Function,+,mf_ultralight_free,void,MfUltralightData* -Function,+,mf_ultralight_get_base_data,const Iso14443_3aData*,const MfUltralightData* +Function,+,mf_ultralight_get_base_data,Iso14443_3aData*,const MfUltralightData* Function,+,mf_ultralight_get_config_page,_Bool,"const MfUltralightData*, MfUltralightConfigPages**" Function,+,mf_ultralight_get_config_page_num,uint16_t,MfUltralightType Function,+,mf_ultralight_get_device_name,const char*,"const MfUltralightData*, NfcDeviceNameType" @@ -2185,7 +2185,6 @@ Function,+,nfc_device_alloc,NfcDevice*, Function,+,nfc_device_clear,void,NfcDevice* Function,+,nfc_device_copy_data,void,"const NfcDevice*, NfcProtocol, NfcDeviceData*" Function,+,nfc_device_free,void,NfcDevice* -Function,+,nfc_device_get_base_data,const NfcDeviceData*,"const NfcDevice*, NfcProtocol" Function,+,nfc_device_get_data,const NfcDeviceData*,"const NfcDevice*, NfcProtocol" Function,+,nfc_device_get_name,const char*,"const NfcDevice*, NfcDeviceNameType" Function,+,nfc_device_get_protocol,NfcProtocol,const NfcDevice* diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc_iso14443a.c b/firmware/targets/f7/furi_hal/f_hal_nfc_iso14443a.c index 20886a84d69d..34617d1ac3cc 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfc_iso14443a.c +++ b/firmware/targets/f7/furi_hal/f_hal_nfc_iso14443a.c @@ -223,7 +223,7 @@ FHalNfcError f_hal_iso4443a_listener_tx( FHalNfcError f_hal_nfca_listener_tx_custom_parity( const uint8_t* tx_data, - const bool* tx_parity, + const uint8_t* tx_parity, size_t tx_bits) { furi_assert(tx_data); furi_assert(tx_parity); diff --git a/firmware/targets/furi_hal_include/f_hal_nfc.h b/firmware/targets/furi_hal_include/f_hal_nfc.h index f7af6c19df91..e29992a6f0d8 100644 --- a/firmware/targets/furi_hal_include/f_hal_nfc.h +++ b/firmware/targets/furi_hal_include/f_hal_nfc.h @@ -165,7 +165,7 @@ FHalNfcError FHalNfcError f_hal_nfca_listener_tx_custom_parity( const uint8_t* tx_data, - const bool* tx_parity, + const uint8_t* tx_parity, size_t tx_bits); #ifdef __cplusplus diff --git a/lib/digital_signal/presets/nfc/iso14443_3a_signal.c b/lib/digital_signal/presets/nfc/iso14443_3a_signal.c index a255b235356b..b57ab767aa89 100644 --- a/lib/digital_signal/presets/nfc/iso14443_3a_signal.c +++ b/lib/digital_signal/presets/nfc/iso14443_3a_signal.c @@ -54,7 +54,7 @@ static void iso14443_3a_add_byte(Iso14443_3aSignal* instance, uint8_t byte, bool static void iso14443_3a_signal_encode( Iso14443_3aSignal* instance, const uint8_t* tx_data, - const bool* tx_parity, + const uint8_t* tx_parity, size_t tx_bits) { furi_assert(instance); furi_assert(tx_data); @@ -75,7 +75,8 @@ static void iso14443_3a_signal_encode( } } else { for(size_t i = 0; i < tx_bits / 8; i++) { - iso14443_3a_add_byte(instance, tx_data[i], tx_parity[i]); + bool parity = FURI_BIT(tx_parity[i / 8], i % 8); + iso14443_3a_add_byte(instance, tx_data[i], parity); } } } @@ -109,7 +110,7 @@ void iso14443_3a_signal_free(Iso14443_3aSignal* instance) { void iso14443_3a_signal_tx( Iso14443_3aSignal* instance, const uint8_t* tx_data, - const bool* tx_parity, + const uint8_t* tx_parity, size_t tx_bits) { furi_assert(instance); furi_assert(tx_data); diff --git a/lib/digital_signal/presets/nfc/iso14443_3a_signal.h b/lib/digital_signal/presets/nfc/iso14443_3a_signal.h index 7da00567f93c..3abec139c675 100644 --- a/lib/digital_signal/presets/nfc/iso14443_3a_signal.h +++ b/lib/digital_signal/presets/nfc/iso14443_3a_signal.h @@ -18,7 +18,7 @@ void iso14443_3a_signal_free(Iso14443_3aSignal* instance); void iso14443_3a_signal_tx( Iso14443_3aSignal* instance, const uint8_t* tx_data, - const bool* tx_parity, + const uint8_t* tx_parity, size_t tx_bits); #ifdef __cplusplus diff --git a/lib/nfc/nfc.c b/lib/nfc/nfc.c index e8b5f502b021..2073ee9dad2c 100644 --- a/lib/nfc/nfc.c +++ b/lib/nfc/nfc.c @@ -600,7 +600,7 @@ NfcError nfc_iso14443_3a_listener_tx_custom_parity(Nfc* instance, const BitBuffe FHalNfcError error = FHalNfcErrorNone; const uint8_t* tx_data = bit_buffer_get_data(tx_buffer); - const bool* tx_parity = bit_buffer_get_parity(tx_buffer); + const uint8_t* tx_parity = bit_buffer_get_parity(tx_buffer); size_t tx_bits = bit_buffer_get_size(tx_buffer); error = f_hal_nfca_listener_tx_custom_parity(tx_data, tx_parity, tx_bits); diff --git a/lib/nfc/nfc_device.c b/lib/nfc/nfc_device.c index 62aeb6ab48f0..4e4250964936 100644 --- a/lib/nfc/nfc_device.c +++ b/lib/nfc/nfc_device.c @@ -1,4 +1,4 @@ -#include "nfc_device.h" +#include "nfc_device_i.h" #include #include @@ -14,14 +14,6 @@ #define NFC_DEVICE_UID_MAX_LEN (10U) -struct NfcDevice { - NfcProtocol protocol; - NfcDeviceData* protocol_data; - - NfcLoadingCallback loading_callback; - void* loading_callback_context; -}; - NfcDevice* nfc_device_alloc() { NfcDevice* instance = malloc(sizeof(NfcDevice)); instance->protocol = NfcProtocolInvalid; @@ -65,25 +57,7 @@ NfcProtocol nfc_device_get_protocol(const NfcDevice* instance) { } const NfcDeviceData* nfc_device_get_data(const NfcDevice* instance, NfcProtocol protocol) { - furi_assert(instance); - furi_assert(protocol < NfcProtocolNum); - - if(instance->protocol != protocol) { - furi_crash(NFC_DEV_TYPE_ERROR); - } - - return instance->protocol_data; -} - -const NfcDeviceData* nfc_device_get_base_data(const NfcDevice* instance, NfcProtocol protocol) { - furi_assert(instance); - furi_assert(protocol < NfcProtocolNum); - - if(instance->protocol != protocol) { - furi_crash(NFC_DEV_TYPE_ERROR); - } - - return nfc_devices[protocol]->get_base_data(instance->protocol_data); + return nfc_device_get_data_ptr(instance, protocol); } const char* nfc_device_get_protocol_name(NfcProtocol protocol) { diff --git a/lib/nfc/nfc_device.h b/lib/nfc/nfc_device.h index 8a37f3064997..5a9bf1c03712 100644 --- a/lib/nfc/nfc_device.h +++ b/lib/nfc/nfc_device.h @@ -27,8 +27,6 @@ NfcProtocol nfc_device_get_protocol(const NfcDevice* instance); const NfcDeviceData* nfc_device_get_data(const NfcDevice* instance, NfcProtocol protocol); -const NfcDeviceData* nfc_device_get_base_data(const NfcDevice* instance, NfcProtocol protocol); - const char* nfc_device_get_protocol_name(NfcProtocol protocol); const char* nfc_device_get_name(const NfcDevice* instance, NfcDeviceNameType name_type); diff --git a/lib/nfc/nfc_device_i.c b/lib/nfc/nfc_device_i.c new file mode 100644 index 000000000000..e98b04251e36 --- /dev/null +++ b/lib/nfc/nfc_device_i.c @@ -0,0 +1,37 @@ +#include "nfc_device_i.h" +#include "protocols/nfc_device_defs.h" + +#include + +static NfcDeviceData* + nfc_device_search_base_protocol_data(const NfcDevice* instance, NfcProtocol protocol) { + NfcProtocol protocol_tmp = instance->protocol; + NfcDeviceData* dev_data_tmp = instance->protocol_data; + + while(true) { + dev_data_tmp = nfc_devices[protocol_tmp]->get_base_data(dev_data_tmp); + protocol_tmp = nfc_protocol_get_parent(protocol_tmp); + if(protocol_tmp == protocol) { + break; + } + } + + return dev_data_tmp; +} + +NfcDeviceData* nfc_device_get_data_ptr(const NfcDevice* instance, NfcProtocol protocol) { + furi_assert(instance); + furi_assert(protocol < NfcProtocolNum); + + NfcDeviceData* dev_data = NULL; + + if(instance->protocol == protocol) { + dev_data = instance->protocol_data; + } else if(nfc_protocol_has_parent(instance->protocol, protocol)) { + dev_data = nfc_device_search_base_protocol_data(instance, protocol); + } else { + furi_crash("Incorrect protocol"); + } + + return dev_data; +} diff --git a/lib/nfc/nfc_device_i.h b/lib/nfc/nfc_device_i.h new file mode 100644 index 000000000000..437d77ad4c77 --- /dev/null +++ b/lib/nfc/nfc_device_i.h @@ -0,0 +1,21 @@ +#pragma once + +#include "nfc_device.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct NfcDevice { + NfcProtocol protocol; + NfcDeviceData* protocol_data; + + NfcLoadingCallback loading_callback; + void* loading_callback_context; +}; + +NfcDeviceData* nfc_device_get_data_ptr(const NfcDevice* instance, NfcProtocol protocol); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/nfc_listener.c b/lib/nfc/nfc_listener.c index a5e5051e7b33..b73f9f69bfcf 100644 --- a/lib/nfc/nfc_listener.c +++ b/lib/nfc/nfc_listener.c @@ -1,13 +1,12 @@ #include "nfc_listener.h" #include -#include +#include #include typedef struct NfcListenerListElement { NfcProtocol protocol; - const NfcDeviceData* data; NfcGenericInstance* listener; const NfcListenerBase* listener_api; struct NfcListenerListElement* child; @@ -22,12 +21,13 @@ struct NfcListener { NfcProtocol protocol; Nfc* nfc; NfcListenerList list; + NfcDevice* nfc_dev; }; -static void nfc_listener_list_alloc(NfcListener* instance, const NfcDeviceData* data) { +static void nfc_listener_list_alloc(NfcListener* instance) { instance->list.head = malloc(sizeof(NfcListenerListElement)); instance->list.head->protocol = instance->protocol; - instance->list.head->data = data; + instance->list.head->listener_api = nfc_listeners_api[instance->protocol]; instance->list.head->child = NULL; instance->list.tail = instance->list.head; @@ -39,8 +39,6 @@ static void nfc_listener_list_alloc(NfcListener* instance, const NfcDeviceData* NfcListenerListElement* parent = malloc(sizeof(NfcListenerListElement)); parent->protocol = parent_protocol; - parent->data = - nfc_devices[instance->list.head->protocol]->get_base_data(instance->list.head->data); parent->listener_api = nfc_listeners_api[parent_protocol]; parent->child = instance->list.head; @@ -49,12 +47,13 @@ static void nfc_listener_list_alloc(NfcListener* instance, const NfcDeviceData* // Allocate listener instances NfcListenerListElement* iter = instance->list.head; - iter->listener = iter->listener_api->alloc(instance->nfc, iter->data); + NfcDeviceData* data_tmp = nfc_device_get_data_ptr(instance->nfc_dev, iter->protocol); + iter->listener = iter->listener_api->alloc(instance->nfc, data_tmp); do { if(iter->child == NULL) break; - iter->child->listener = - iter->child->listener_api->alloc(iter->listener, iter->child->data); + data_tmp = nfc_device_get_data_ptr(instance->nfc_dev, iter->child->protocol); + iter->child->listener = iter->child->listener_api->alloc(iter->listener, data_tmp); iter->listener_api->set_callback( iter->listener, iter->child->listener_api->run, iter->child->listener); @@ -63,6 +62,7 @@ static void nfc_listener_list_alloc(NfcListener* instance, const NfcDeviceData* } static void nfc_listener_list_free(NfcListener* instance) { + // Free listener instances do { instance->list.head->listener_api->free(instance->list.head->listener); NfcListenerListElement* child = instance->list.head->child; @@ -81,7 +81,9 @@ NfcListener* nfc_listener_alloc(Nfc* nfc, NfcProtocol protocol, const NfcDeviceD NfcListener* instance = malloc(sizeof(NfcListener)); instance->nfc = nfc; instance->protocol = protocol; - nfc_listener_list_alloc(instance, data); + instance->nfc_dev = nfc_device_alloc(); + nfc_device_set_data(instance->nfc_dev, protocol, data); + nfc_listener_list_alloc(instance); return instance; } @@ -90,6 +92,7 @@ void nfc_listener_free(NfcListener* instance) { furi_assert(instance); nfc_listener_list_free(instance); + nfc_device_free(instance->nfc_dev); free(instance); } diff --git a/lib/nfc/protocols/felica/felica.c b/lib/nfc/protocols/felica/felica.c index de8b88813f35..4b7c91fb64e0 100644 --- a/lib/nfc/protocols/felica/felica.c +++ b/lib/nfc/protocols/felica/felica.c @@ -141,7 +141,7 @@ bool felica_set_uid(FelicaData* data, const uint8_t* uid, size_t uid_len) { return uid_valid; } -const FelicaData* felica_get_base_data(const FelicaData* data) { +FelicaData* felica_get_base_data(const FelicaData* data) { UNUSED(data); furi_crash("No base data"); } diff --git a/lib/nfc/protocols/felica/felica.h b/lib/nfc/protocols/felica/felica.h index bd305b932601..671a7220de25 100644 --- a/lib/nfc/protocols/felica/felica.h +++ b/lib/nfc/protocols/felica/felica.h @@ -69,7 +69,7 @@ const uint8_t* felica_get_uid(const FelicaData* data, size_t* uid_len); bool felica_set_uid(FelicaData* data, const uint8_t* uid, size_t uid_len); -const FelicaData* felica_get_base_data(const FelicaData* data); +FelicaData* felica_get_base_data(const FelicaData* data); #ifdef __cplusplus } diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a.c b/lib/nfc/protocols/iso14443_3a/iso14443_3a.c index 98fcb6bf03b7..612a5976b493 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a.c +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a.c @@ -136,7 +136,7 @@ bool iso14443_3a_set_uid(Iso14443_3aData* data, const uint8_t* uid, size_t uid_l return uid_valid; } -const Iso14443_3aData* iso14443_3a_get_base_data(const Iso14443_3aData* data) { +Iso14443_3aData* iso14443_3a_get_base_data(const Iso14443_3aData* data) { UNUSED(data); furi_crash("No base data"); } diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a.h b/lib/nfc/protocols/iso14443_3a/iso14443_3a.h index ca7e4d9c0fcc..1f4834f02d39 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a.h +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a.h @@ -86,7 +86,7 @@ const uint8_t* iso14443_3a_get_uid(const Iso14443_3aData* data, size_t* uid_len) bool iso14443_3a_set_uid(Iso14443_3aData* data, const uint8_t* uid, size_t uid_len); -const Iso14443_3aData* iso14443_3a_get_base_data(const Iso14443_3aData* data); +Iso14443_3aData* iso14443_3a_get_base_data(const Iso14443_3aData* data); uint32_t iso14443_3a_get_cuid(const Iso14443_3aData* iso14443_3a_data); diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c b/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c index 7fcc6815a471..5a144091f6a4 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c @@ -24,13 +24,12 @@ static bool iso14443_3a_listener_halt_received(BitBuffer* buf) { return halt_cmd_received; } -Iso14443_3aListener* iso14443_3a_listener_alloc(Nfc* nfc, const Iso14443_3aData* data) { +Iso14443_3aListener* iso14443_3a_listener_alloc(Nfc* nfc, Iso14443_3aData* data) { furi_assert(nfc); Iso14443_3aListener* instance = malloc(sizeof(Iso14443_3aListener)); instance->nfc = nfc; - instance->data = iso14443_3a_alloc(); - iso14443_3a_copy(instance->data, data); + instance->data = data; instance->tx_buffer = bit_buffer_alloc(ISO14443_3A_LISTENER_MAX_BUFFER_SIZE); instance->iso14443_3a_event.data = &instance->iso14443_3a_event_data; @@ -56,7 +55,6 @@ void iso14443_3a_listener_free(Iso14443_3aListener* instance) { furi_assert(instance->tx_buffer); bit_buffer_free(instance->tx_buffer); - iso14443_3a_free(instance->data); free(instance); } diff --git a/lib/nfc/protocols/iso14443_3b/iso14443_3b.c b/lib/nfc/protocols/iso14443_3b/iso14443_3b.c index 2d46da056c3e..ca12a6acd423 100644 --- a/lib/nfc/protocols/iso14443_3b/iso14443_3b.c +++ b/lib/nfc/protocols/iso14443_3b/iso14443_3b.c @@ -139,7 +139,7 @@ bool iso14443_3b_set_uid(Iso14443_3bData* data, const uint8_t* uid, size_t uid_l return uid_valid; } -const Iso14443_3bData* iso14443_3b_get_base_data(const Iso14443_3bData* data) { +Iso14443_3bData* iso14443_3b_get_base_data(const Iso14443_3bData* data) { UNUSED(data); furi_crash("No base data"); } diff --git a/lib/nfc/protocols/iso14443_3b/iso14443_3b.h b/lib/nfc/protocols/iso14443_3b/iso14443_3b.h index b9b88788829a..5bea83dcdf47 100644 --- a/lib/nfc/protocols/iso14443_3b/iso14443_3b.h +++ b/lib/nfc/protocols/iso14443_3b/iso14443_3b.h @@ -74,7 +74,7 @@ const uint8_t* iso14443_3b_get_uid(const Iso14443_3bData* data, size_t* uid_len) bool iso14443_3b_set_uid(Iso14443_3bData* data, const uint8_t* uid, size_t uid_len); -const Iso14443_3bData* iso14443_3b_get_base_data(const Iso14443_3bData* data); +Iso14443_3bData* iso14443_3b_get_base_data(const Iso14443_3bData* data); #ifdef __cplusplus } diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a.c b/lib/nfc/protocols/iso14443_4a/iso14443_4a.c index 24e8886f8999..ef562b695101 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a.c +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a.c @@ -132,7 +132,7 @@ bool iso14443_4a_set_uid(Iso14443_4aData* data, const uint8_t* uid, size_t uid_l return iso14443_3a_set_uid(data->iso14443_3a_data, uid, uid_len); } -const Iso14443_3aData* iso14443_4a_get_base_data(const Iso14443_4aData* data) { +Iso14443_3aData* iso14443_4a_get_base_data(const Iso14443_4aData* data) { furi_assert(data); return data->iso14443_3a_data; diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a.h b/lib/nfc/protocols/iso14443_4a/iso14443_4a.h index 75da18ed1ea2..3c2d62760deb 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a.h +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a.h @@ -46,7 +46,7 @@ const uint8_t* iso14443_4a_get_uid(const Iso14443_4aData* data, size_t* uid_len) bool iso14443_4a_set_uid(Iso14443_4aData* data, const uint8_t* uid, size_t uid_len); -const Iso14443_3aData* iso14443_4a_get_base_data(const Iso14443_4aData* data); +Iso14443_3aData* iso14443_4a_get_base_data(const Iso14443_4aData* data); // Getters & Tests diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_listener.c b/lib/nfc/protocols/iso14443_4a/iso14443_4a_listener.c index 546fc4fbf1d0..f8544271403b 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_listener.c +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_listener.c @@ -7,15 +7,13 @@ #define ISO14443_4A_LISTENER_BUF_SIZE (256U) -static Iso14443_4aListener* iso14443_4a_listener_alloc( - Iso14443_3aListener* iso14443_3a_listener, - const Iso14443_4aData* data) { +static Iso14443_4aListener* + iso14443_4a_listener_alloc(Iso14443_3aListener* iso14443_3a_listener, Iso14443_4aData* data) { furi_assert(iso14443_3a_listener); Iso14443_4aListener* instance = malloc(sizeof(Iso14443_4aListener)); instance->iso14443_3a_listener = iso14443_3a_listener; - instance->data = iso14443_4a_alloc(); - iso14443_4a_copy(instance->data, data); + instance->data = data; instance->tx_buffer = bit_buffer_alloc(ISO14443_4A_LISTENER_BUF_SIZE); @@ -33,7 +31,6 @@ static void iso14443_4a_listener_free(Iso14443_4aListener* instance) { furi_assert(instance->tx_buffer); bit_buffer_free(instance->tx_buffer); - iso14443_4a_free(instance->data); free(instance); } diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3.c b/lib/nfc/protocols/iso15693_3/iso15693_3.c index a776e6f1a680..cecb1a8aaa3b 100644 --- a/lib/nfc/protocols/iso15693_3/iso15693_3.c +++ b/lib/nfc/protocols/iso15693_3/iso15693_3.c @@ -299,7 +299,7 @@ bool iso15693_3_set_uid(Iso15693_3Data* data, const uint8_t* uid, size_t uid_len return uid_valid; } -const Iso15693_3Data* iso15693_3_get_base_data(const Iso15693_3Data* data) { +Iso15693_3Data* iso15693_3_get_base_data(const Iso15693_3Data* data) { UNUSED(data); furi_crash("No base data"); } diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3.h b/lib/nfc/protocols/iso15693_3/iso15693_3.h index 870a3c19cad5..99417ecac493 100644 --- a/lib/nfc/protocols/iso15693_3/iso15693_3.h +++ b/lib/nfc/protocols/iso15693_3/iso15693_3.h @@ -153,7 +153,7 @@ const uint8_t* iso15693_3_get_uid(const Iso15693_3Data* data, size_t* uid_len); bool iso15693_3_set_uid(Iso15693_3Data* data, const uint8_t* uid, size_t uid_len); -const Iso15693_3Data* iso15693_3_get_base_data(const Iso15693_3Data* data); +Iso15693_3Data* iso15693_3_get_base_data(const Iso15693_3Data* data); // Getters and tests diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3_listener.c b/lib/nfc/protocols/iso15693_3/iso15693_3_listener.c index c47734310b14..3b7a39899f82 100644 --- a/lib/nfc/protocols/iso15693_3/iso15693_3_listener.c +++ b/lib/nfc/protocols/iso15693_3/iso15693_3_listener.c @@ -10,13 +10,12 @@ #define ISO15693_3_LISTENER_BUFFER_SIZE (64U) -Iso15693_3Listener* iso15693_3_listener_alloc(Nfc* nfc, const Iso15693_3Data* data) { +Iso15693_3Listener* iso15693_3_listener_alloc(Nfc* nfc, Iso15693_3Data* data) { furi_assert(nfc); Iso15693_3Listener* instance = malloc(sizeof(Iso15693_3Listener)); instance->nfc = nfc; - instance->data = iso15693_3_alloc(); - iso15693_3_copy(instance->data, data); + instance->data = data; instance->tx_buffer = bit_buffer_alloc(ISO15693_3_LISTENER_BUFFER_SIZE); @@ -35,7 +34,6 @@ void iso15693_3_listener_free(Iso15693_3Listener* instance) { furi_assert(instance); bit_buffer_free(instance->tx_buffer); - iso15693_3_free(instance->data); free(instance); } diff --git a/lib/nfc/protocols/mf_classic/mf_classic.c b/lib/nfc/protocols/mf_classic/mf_classic.c index ad9a8551f470..5724d8aea8bd 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic.c +++ b/lib/nfc/protocols/mf_classic/mf_classic.c @@ -349,7 +349,7 @@ bool mf_classic_set_uid(MfClassicData* data, const uint8_t* uid, size_t uid_len) return iso14443_3a_set_uid(data->iso14443_3a_data, uid, uid_len); } -const Iso14443_3aData* mf_classic_get_base_data(const MfClassicData* data) { +Iso14443_3aData* mf_classic_get_base_data(const MfClassicData* data) { furi_assert(data); return data->iso14443_3a_data; diff --git a/lib/nfc/protocols/mf_classic/mf_classic.h b/lib/nfc/protocols/mf_classic/mf_classic.h index 47a8649af661..1965a0884542 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic.h +++ b/lib/nfc/protocols/mf_classic/mf_classic.h @@ -159,7 +159,7 @@ const uint8_t* mf_classic_get_uid(const MfClassicData* data, size_t* uid_len); bool mf_classic_set_uid(MfClassicData* data, const uint8_t* uid, size_t uid_len); -const Iso14443_3aData* mf_classic_get_base_data(const MfClassicData* data); +Iso14443_3aData* mf_classic_get_base_data(const MfClassicData* data); bool mf_classic_detect_protocol(Iso14443_3aData* data, MfClassicType* type); diff --git a/lib/nfc/protocols/mf_classic/mf_classic_listener.c b/lib/nfc/protocols/mf_classic/mf_classic_listener.c index ebb9f40ba69a..e9000bba02b9 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_listener.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_listener.c @@ -585,8 +585,7 @@ MfClassicListener* mf_classic_listener_alloc(Iso14443_3aListener* iso14443_3a_listener, MfClassicData* data) { MfClassicListener* instance = malloc(sizeof(MfClassicListener)); instance->iso14443_3a_listener = iso14443_3a_listener; - instance->data = mf_classic_alloc(); - mf_classic_copy(instance->data, data); + instance->data = data; mf_classic_listener_prepare_emulation(instance); instance->crypto = crypto1_alloc(); @@ -610,7 +609,6 @@ void mf_classic_listener_free(MfClassicListener* instance) { furi_assert(instance->tx_encrypted_buffer); furi_assert(instance->tx_plain_buffer); - mf_classic_free(instance->data); crypto1_free(instance->crypto); bit_buffer_free(instance->rx_plain_buffer); bit_buffer_free(instance->tx_encrypted_buffer); diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire.c b/lib/nfc/protocols/mf_desfire/mf_desfire.c index 976e4b8d6ef6..4483f95db145 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire.c +++ b/lib/nfc/protocols/mf_desfire/mf_desfire.c @@ -233,7 +233,7 @@ bool mf_desfire_set_uid(MfDesfireData* data, const uint8_t* uid, size_t uid_len) return iso14443_4a_set_uid(data->iso14443_4a_data, uid, uid_len); } -const Iso14443_4aData* mf_desfire_get_base_data(const MfDesfireData* data) { +Iso14443_4aData* mf_desfire_get_base_data(const MfDesfireData* data) { furi_assert(data); return data->iso14443_4a_data; diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire.h b/lib/nfc/protocols/mf_desfire/mf_desfire.h index ae804c151e3d..4d09dc851033 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire.h +++ b/lib/nfc/protocols/mf_desfire/mf_desfire.h @@ -173,7 +173,7 @@ const uint8_t* mf_desfire_get_uid(const MfDesfireData* data, size_t* uid_len); bool mf_desfire_set_uid(MfDesfireData* data, const uint8_t* uid, size_t uid_len); -const Iso14443_4aData* mf_desfire_get_base_data(const MfDesfireData* data); +Iso14443_4aData* mf_desfire_get_base_data(const MfDesfireData* data); // Getters and tests diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight.c index 578141ce3fc4..2d0774c4d902 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight.c @@ -474,7 +474,7 @@ bool mf_ultralight_set_uid(MfUltralightData* data, const uint8_t* uid, size_t ui return iso14443_3a_set_uid(data->iso14443_3a_data, uid, uid_len); } -const Iso14443_3aData* mf_ultralight_get_base_data(const MfUltralightData* data) { +Iso14443_3aData* mf_ultralight_get_base_data(const MfUltralightData* data) { furi_assert(data); return data->iso14443_3a_data; diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h index e88007025c0f..0727adc07064 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h @@ -193,7 +193,7 @@ const uint8_t* mf_ultralight_get_uid(const MfUltralightData* data, size_t* uid_l bool mf_ultralight_set_uid(MfUltralightData* data, const uint8_t* uid, size_t uid_len); -const Iso14443_3aData* mf_ultralight_get_base_data(const MfUltralightData* data); +Iso14443_3aData* mf_ultralight_get_base_data(const MfUltralightData* data); MfUltralightType mf_ultralight_get_type_by_version(MfUltralightVersion* version); diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c index 9bf3868b1bf5..d8472094ffc1 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c @@ -418,14 +418,13 @@ static void mf_ultralight_listener_prepare_emulation(MfUltralightListener* insta MfUltralightListener* mf_ultralight_listener_alloc( Iso14443_3aListener* iso14443_3a_listener, - const MfUltralightData* data) { + MfUltralightData* data) { furi_assert(iso14443_3a_listener); MfUltralightListener* instance = malloc(sizeof(MfUltralightListener)); instance->mirror.ascii_mirror_data = furi_string_alloc(); instance->iso14443_3a_listener = iso14443_3a_listener; - instance->data = mf_ultralight_alloc(); - mf_ultralight_copy(instance->data, data); + instance->data = data; mf_ultralight_listener_prepare_emulation(instance); mf_ultralight_composite_command_reset(instance); instance->tx_buffer = bit_buffer_alloc(MF_ULTRALIGHT_LISTENER_MAX_TX_BUFF_SIZE); @@ -445,7 +444,6 @@ void mf_ultralight_listener_free(MfUltralightListener* instance) { bit_buffer_free(instance->tx_buffer); furi_string_free(instance->mirror.ascii_mirror_data); - mf_ultralight_free(instance->data); free(instance); } diff --git a/lib/nfc/protocols/nfc_device_base_i.h b/lib/nfc/protocols/nfc_device_base_i.h index d4212f693435..99b0f1d23532 100644 --- a/lib/nfc/protocols/nfc_device_base_i.h +++ b/lib/nfc/protocols/nfc_device_base_i.h @@ -19,7 +19,7 @@ typedef bool (*NfcDeviceEqual)(const NfcDeviceData* data, const NfcDeviceData* o typedef const char* (*NfcDeviceGetName)(const NfcDeviceData* data, NfcDeviceNameType name_type); typedef const uint8_t* (*NfcDeviceGetUid)(const NfcDeviceData* data, size_t* uid_len); typedef bool (*NfcDeviceSetUid)(NfcDeviceData* data, const uint8_t* uid, size_t uid_len); -typedef const NfcDeviceData* (*NfcDeviceGetBaseData)(const NfcDeviceData* data); +typedef NfcDeviceData* (*NfcDeviceGetBaseData)(const NfcDeviceData* data); typedef struct { const char* protocol_name; diff --git a/lib/nfc/protocols/nfc_listener_base.h b/lib/nfc/protocols/nfc_listener_base.h index 52eaea49505b..8336b60e29ed 100644 --- a/lib/nfc/protocols/nfc_listener_base.h +++ b/lib/nfc/protocols/nfc_listener_base.h @@ -8,7 +8,7 @@ extern "C" { #endif typedef NfcGenericInstance* ( - *NfcListenerAlloc)(NfcGenericInstance* base_listener, const NfcDeviceData* data); + *NfcListenerAlloc)(NfcGenericInstance* base_listener, NfcDeviceData* data); typedef void (*NfcListenerFree)(NfcGenericInstance* instance); typedef void (*NfcListenerSetCallback)( diff --git a/lib/toolbox/bit_buffer.c b/lib/toolbox/bit_buffer.c index 7325af135964..cac949cd62b5 100644 --- a/lib/toolbox/bit_buffer.c +++ b/lib/toolbox/bit_buffer.c @@ -6,7 +6,7 @@ struct BitBuffer { uint8_t* data; - bool* parity; + uint8_t* parity; size_t capacity_bytes; size_t size_bits; }; @@ -17,7 +17,8 @@ BitBuffer* bit_buffer_alloc(size_t capacity_bytes) { BitBuffer* buf = malloc(sizeof(BitBuffer)); buf->data = malloc(capacity_bytes); - buf->parity = malloc(capacity_bytes); + size_t parity_buf_size = (capacity_bytes + BITS_IN_BYTE - 1) / BITS_IN_BYTE; + buf->parity = malloc(parity_buf_size); buf->capacity_bytes = capacity_bytes; buf->size_bits = 0; @@ -36,7 +37,8 @@ void bit_buffer_reset(BitBuffer* buf) { furi_assert(buf); memset(buf->data, 0, buf->capacity_bytes); - memset(buf->parity, 0, buf->capacity_bytes); + size_t parity_buf_size = (buf->capacity_bytes + BITS_IN_BYTE - 1) / BITS_IN_BYTE; + memset(buf->parity, 0, parity_buf_size); buf->size_bits = 0; } @@ -109,8 +111,14 @@ void bit_buffer_copy_bytes_with_parity(BitBuffer* buf, const uint8_t* data, size (bit_processed % BITS_IN_BYTE); buf->data[curr_byte] |= data[bit_processed / BITS_IN_BYTE + 1] << (BITS_IN_BYTE - bit_processed % BITS_IN_BYTE); - buf->parity[curr_byte] = + uint8_t bit = FURI_BIT(data[bit_processed / BITS_IN_BYTE + 1], bit_processed % BITS_IN_BYTE); + + if(bit_processed % BITS_IN_BYTE) { + buf->parity[curr_byte / BITS_IN_BYTE] = bit; + } else { + buf->parity[curr_byte / BITS_IN_BYTE] |= bit << (bit_processed % BITS_IN_BYTE); + } bit_processed += BITS_IN_BYTE + 1; curr_byte++; } @@ -145,7 +153,7 @@ void bit_buffer_write_bytes_with_parity( uint8_t* bitstream = dest; for(size_t i = 0; i < buf_size_bytes; i++) { - next_par_bit = buf->parity[i]; + next_par_bit = FURI_BIT(buf->parity[i / BITS_IN_BYTE], i % BITS_IN_BYTE); if(curr_bit_pos % BITS_IN_BYTE == 0) { bitstream[curr_bit_pos / BITS_IN_BYTE] = buf->data[i]; curr_bit_pos += BITS_IN_BYTE; @@ -233,7 +241,7 @@ const uint8_t* bit_buffer_get_data(const BitBuffer* buf) { return buf->data; } -const bool* bit_buffer_get_parity(const BitBuffer* buf) { +const uint8_t* bit_buffer_get_parity(const BitBuffer* buf) { furi_assert(buf); return buf->parity; @@ -253,7 +261,11 @@ void bit_buffer_set_byte_with_parity(BitBuffer* buff, size_t index, uint8_t byte furi_assert(buff->size_bits / BITS_IN_BYTE > index); buff->data[index] = byte; - buff->parity[index] = parity; + if((index % BITS_IN_BYTE) == 0) { + buff->parity[index / BITS_IN_BYTE] = parity; + } else { + buff->parity[index / BITS_IN_BYTE] |= parity << (index % BITS_IN_BYTE); + } } void bit_buffer_set_size(BitBuffer* buf, size_t new_size) { diff --git a/lib/toolbox/bit_buffer.h b/lib/toolbox/bit_buffer.h index 620a873c1de2..5c50e729c605 100644 --- a/lib/toolbox/bit_buffer.h +++ b/lib/toolbox/bit_buffer.h @@ -227,7 +227,7 @@ const uint8_t* bit_buffer_get_data(const BitBuffer* buf); * @param [in] buf pointer to a BitBuffer instance to be queried * @return pointer to the underlying data */ -const bool* bit_buffer_get_parity(const BitBuffer* buf); +const uint8_t* bit_buffer_get_parity(const BitBuffer* buf); // Setters From 68f1027f77241531495e916cdb0fc4e2f341e22b Mon Sep 17 00:00:00 2001 From: RebornedBrain <138568282+RebornedBrain@users.noreply.github.com> Date: Wed, 6 Sep 2023 16:44:34 +0300 Subject: [PATCH 147/149] [FL-3574] SECTOR_SELECT command implementation (#3045) * Added callback on FieldOff event from 14443 to mfu * Moved command enum and callback type to _i.h file * Added context for composite command to mfu_listener * Functions for composite commands processing added * Composite commands processing logic added * Added COMP_WRITE command implementation * Patch with some fixes * New mfu command result added for composite commands * Added variable for storing sector for SECTOR_SELECT cmd * Implemented proper way of reset for composite cmds * SECTOR_SELECT implementation added * Adjust naming for PR * Update api_symbols.csv, nfc.h, and mf_ultralight_listener.c --- .../debug/unit_tests/nfc/nfc_transport.c | 2 +- firmware/targets/f7/api_symbols.csv | 3 +- lib/nfc/nfc.c | 15 +++++- lib/nfc/nfc.h | 3 ++ .../mf_ultralight/mf_ultralight_listener.c | 50 ++++++++++++++++++- .../mf_ultralight/mf_ultralight_listener_i.h | 2 + 6 files changed, 70 insertions(+), 5 deletions(-) diff --git a/applications/debug/unit_tests/nfc/nfc_transport.c b/applications/debug/unit_tests/nfc/nfc_transport.c index e9084ca20b93..c91c8b95873b 100644 --- a/applications/debug/unit_tests/nfc/nfc_transport.c +++ b/applications/debug/unit_tests/nfc/nfc_transport.c @@ -334,7 +334,7 @@ void nfc_start_listener(Nfc* instance, NfcEventCallback callback, void* context) furi_thread_start(instance->worker_thread); } -NfcError nfc_listener_sleep(Nfc* instance) { +NfcError nfc_listener_reset(Nfc* instance) { furi_assert(instance); furi_assert(poller_queue); diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 5573f3479f4d..90ad35b921e0 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,+,38.0,, +Version,+,38.1,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -2205,6 +2205,7 @@ Function,-,nfc_listener_abort,void,Nfc* Function,-,nfc_listener_alloc,NfcListener*,"Nfc*, NfcProtocol, const NfcDeviceData*" Function,-,nfc_listener_free,void,NfcListener* Function,-,nfc_listener_get_data,const NfcDeviceData*,"NfcListener*, NfcProtocol" +Function,-,nfc_listener_reset,NfcError,Nfc* Function,-,nfc_listener_set_col_res_data,NfcError,"Nfc*, uint8_t*, uint8_t, uint8_t*, uint8_t" Function,-,nfc_listener_sleep,NfcError,Nfc* Function,-,nfc_listener_start,void,"NfcListener*, NfcGenericCallback, void*" diff --git a/lib/nfc/nfc.c b/lib/nfc/nfc.c index 2073ee9dad2c..a416fb07ab4d 100644 --- a/lib/nfc/nfc.c +++ b/lib/nfc/nfc.c @@ -108,7 +108,7 @@ static int32_t nfc_worker_listener(void* context) { if(event & FHalNfcEventFieldOff) { nfc_event.type = NfcEventTypeFieldOff; instance->callback(nfc_event, instance->context); - nfc_listener_sleep(instance); + nfc_listener_reset(instance); } if(event & FHalNfcEventListenerActive) { f_hal_nfc_listener_disable_auto_col_res(); @@ -124,6 +124,8 @@ static int32_t nfc_worker_listener(void* context) { if(command == NfcCommandStop) { break; } else if(command == NfcCommandReset) { + nfc_listener_reset(instance); + } else if(command == NfcCommandSleep) { nfc_listener_sleep(instance); } } @@ -347,7 +349,7 @@ void nfc_stop(Nfc* instance) { furi_thread_join(instance->worker_thread); } -NfcError nfc_listener_sleep(Nfc* instance) { +NfcError nfc_listener_reset(Nfc* instance) { furi_assert(instance); furi_assert(instance->state == NfcStateListenerStarted); @@ -356,6 +358,15 @@ NfcError nfc_listener_sleep(Nfc* instance) { return NfcErrorNone; } +NfcError nfc_listener_sleep(Nfc* instance) { + furi_assert(instance); + furi_assert(instance->state == NfcStateListenerStarted); + + f_hal_nfc_listener_reset(); + + return NfcErrorNone; +} + NfcError nfc_listener_tx(Nfc* instance, const BitBuffer* tx_buffer) { furi_assert(instance); furi_assert(tx_buffer); diff --git a/lib/nfc/nfc.h b/lib/nfc/nfc.h index 0c7e63e96e55..d7aa4be0b3ee 100644 --- a/lib/nfc/nfc.h +++ b/lib/nfc/nfc.h @@ -34,6 +34,7 @@ typedef enum { NfcCommandContinue, NfcCommandReset, NfcCommandStop, + NfcCommandSleep, } NfcCommand; typedef NfcCommand (*NfcEventCallback)(NfcEvent event, void* context); @@ -92,6 +93,8 @@ void nfc_start_poller(Nfc* instance, NfcEventCallback callback, void* context); void nfc_start_listener(Nfc* instance, NfcEventCallback callback, void* context); +NfcError nfc_listener_reset(Nfc* instance); + NfcError nfc_listener_sleep(Nfc* instance); void nfc_listener_abort(Nfc* instance); diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c index d8472094ffc1..8ff2f1e0ab88 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c @@ -361,6 +361,45 @@ static MfUltralightCommand return command; } +static MfUltralightCommand + mf_ultralight_sector_select_handler_p2(MfUltralightListener* instance, BitBuffer* buffer) { + MfUltralightCommand command = MfUltralightCommandNotProcessedNAK; + UNUSED(instance); + UNUSED(buffer); + FURI_LOG_D(TAG, "CMD_SEC_SEL_2"); + + do { + if(bit_buffer_get_size_bytes(buffer) != 4) break; + uint8_t sector = bit_buffer_get_byte(buffer, 0); + if(sector == 0xFF) break; + + instance->sector = sector; + command = MfUltralightCommandProcessedSilent; + } while(false); + + return command; +} + +static MfUltralightCommand + mf_ultralight_sector_select_handler_p1(MfUltralightListener* instance, BitBuffer* buffer) { + MfUltralightCommand command = MfUltralightCommandNotProcessedNAK; + UNUSED(buffer); + FURI_LOG_D(TAG, "CMD_SEC_SEL_1"); + + do { + if(!mf_ultralight_support_feature( + instance->features, MfUltralightFeatureSupportSectorSelect) && + bit_buffer_get_byte(buffer, 1) == 0xFF) + break; + + command = MfUltralightCommandProcessed; + mf_ultralight_listener_send_short_resp(instance, MF_ULTRALIGHT_CMD_ACK); + mf_ultralight_composite_command_set_next(instance, mf_ultralight_sector_select_handler_p2); + } while(false); + + return command; +} + static const MfUltralightListenerCmdHandler mf_ultralight_command[] = { { .cmd = MF_ULTRALIGHT_CMD_READ_PAGE, @@ -402,6 +441,11 @@ static const MfUltralightListenerCmdHandler mf_ultralight_command[] = { .cmd_len_bits = 6 * 8, .callback = mf_ultralight_listener_increase_counter_handler, }, + { + .cmd = MF_ULTRALIGHT_CMD_SECTOR_SELECT, + .cmd_len_bits = 2 * 8, + .callback = mf_ultralight_sector_select_handler_p1, + }, { .cmd = MF_ULTRALIGHT_CMD_COMP_WRITE, .cmd_len_bits = 2 * 8, @@ -427,6 +471,7 @@ MfUltralightListener* mf_ultralight_listener_alloc( instance->data = data; mf_ultralight_listener_prepare_emulation(instance); mf_ultralight_composite_command_reset(instance); + instance->sector = 0; instance->tx_buffer = bit_buffer_alloc(MF_ULTRALIGHT_LISTENER_MAX_TX_BUFF_SIZE); instance->mfu_event.data = &instance->mfu_event_data; @@ -490,7 +535,9 @@ NfcCommand mf_ultralight_listener_run(NfcGenericEvent event, void* context) { if(mfu_command != MfUltralightCommandNotFound) break; } } - if(mfu_command != MfUltralightCommandProcessed) { + if(mfu_command == MfUltralightCommandProcessedSilent) { + command = NfcCommandSleep; + } else if(mfu_command != MfUltralightCommandProcessed) { instance->state = MfUltraligthListenerStateIdle; instance->auth_state = MfUltralightListenerAuthStateIdle; command = NfcCommandReset; @@ -505,6 +552,7 @@ NfcCommand mf_ultralight_listener_run(NfcGenericEvent event, void* context) { iso14443_3a_event->type == Iso14443_3aListenerEventTypeHalted) { // TODO generic state reset ? mf_ultralight_composite_command_reset(instance); + instance->sector = 0; instance->auth_state = MfUltralightListenerAuthStateIdle; command = NfcCommandReset; } diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h index ce6d0d8b9e08..ac390a800e29 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.h @@ -20,6 +20,7 @@ typedef enum { typedef enum { MfUltralightCommandNotFound, MfUltralightCommandProcessed, + MfUltralightCommandProcessedSilent, MfUltralightCommandNotProcessedNAK, MfUltralightCommandNotProcessedSilent, } MfUltralightCommand; @@ -57,6 +58,7 @@ struct MfUltralightListener { MfUltralightListenerEvent mfu_event; MfUltralightListenerEventData mfu_event_data; NfcGenericCallback callback; + uint8_t sector; MfUltralightMirrorMode mirror; MfUltralightListenerCompositeCommandContext composite_cmd; void* context; From 35aebe463b570422752f4a07ea37fecfccc1aa68 Mon Sep 17 00:00:00 2001 From: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Date: Wed, 6 Sep 2023 15:16:56 +0000 Subject: [PATCH 148/149] [NFC] SLIX Protocol Support (#3034) * Implement basic SLIX protocol support (Save and Load) * Implement SLIX listener skeleton code * Implement SLIX NXP sysinfo and read signature * Implement SLIX protocol detection * Implement SLIX poller * Improve SLIX file handling * Add SLIX command defines * Implement listener RANDOM_VALUE command * Simplify request handlers code * Implement listener ENABLE_PRIVACY command * Simplify handler code * Simplify request handlers code once more * Refactor SLIX code, add SET_PASSWORD * Implement listener WRITE_PASSWORD command * Implement handler override via handler table * Improve ISO15693 parser error handlng * Improve ISO standard command override API * Cleanup ISO15693 listener code * Remove unused code * Improve Slix password handling * Improve SLIX api * Do not answer any requests after an incorrect password * Implement standard command overrides for SLIX * Improve SLIX overrides * Unify SLIX request handlers into a table * Do not allocate data inside slix listener * Improve method naming * Simplify SLIX protocol data structures * Fix logical error * Improve lock bits handling for ISO15693-3 and SLIX * Implement PROTECT_PAGE command * Improve SLIX lock bits handling * Implement SLIX counter feature * Update comment * Update comment once more * Improve SLIX and ISO15693-3 rendering * Minor rendering changes --------- Co-authored-by: gornekich --- .../iso15693_3/iso15693_3_render.c | 43 +- .../iso15693_3/iso15693_3_render.h | 4 + .../nfc_protocol_support_defs.c | 2 + .../nfc/helpers/protocol_support/slix/slix.c | 141 ++++ .../nfc/helpers/protocol_support/slix/slix.h | 5 + .../protocol_support/slix/slix_render.c | 81 +++ .../protocol_support/slix/slix_render.h | 7 + lib/nfc/protocols/iso15693_3/iso15693_3.c | 65 +- lib/nfc/protocols/iso15693_3/iso15693_3.h | 49 +- .../iso15693_3/iso15693_3_device_defs.h | 13 + lib/nfc/protocols/iso15693_3/iso15693_3_i.c | 7 + lib/nfc/protocols/iso15693_3/iso15693_3_i.h | 2 + .../iso15693_3/iso15693_3_listener.c | 47 +- .../iso15693_3/iso15693_3_listener_i.c | 338 +++++++--- .../iso15693_3/iso15693_3_listener_i.h | 28 +- lib/nfc/protocols/nfc_device_defs.c | 4 +- lib/nfc/protocols/nfc_listener_defs.c | 2 + lib/nfc/protocols/nfc_poller_defs.c | 2 + lib/nfc/protocols/nfc_protocol.c | 16 +- lib/nfc/protocols/nfc_protocol.h | 1 + lib/nfc/protocols/slix/slix.c | 433 ++++++++++++ lib/nfc/protocols/slix/slix.h | 146 +++++ lib/nfc/protocols/slix/slix_device_defs.h | 13 + lib/nfc/protocols/slix/slix_i.c | 127 ++++ lib/nfc/protocols/slix/slix_i.h | 86 +++ lib/nfc/protocols/slix/slix_listener.c | 79 +++ lib/nfc/protocols/slix/slix_listener.h | 29 + lib/nfc/protocols/slix/slix_listener_defs.h | 13 + lib/nfc/protocols/slix/slix_listener_i.c | 617 ++++++++++++++++++ lib/nfc/protocols/slix/slix_listener_i.h | 37 ++ lib/nfc/protocols/slix/slix_poller.c | 154 +++++ lib/nfc/protocols/slix/slix_poller.h | 29 + lib/nfc/protocols/slix/slix_poller_defs.h | 13 + lib/nfc/protocols/slix/slix_poller_i.c | 69 ++ lib/nfc/protocols/slix/slix_poller_i.h | 48 ++ .../parsers/iso15693/iso15693_parser.c | 12 +- 36 files changed, 2588 insertions(+), 174 deletions(-) create mode 100644 applications/main/nfc/helpers/protocol_support/slix/slix.c create mode 100644 applications/main/nfc/helpers/protocol_support/slix/slix.h create mode 100644 applications/main/nfc/helpers/protocol_support/slix/slix_render.c create mode 100644 applications/main/nfc/helpers/protocol_support/slix/slix_render.h create mode 100644 lib/nfc/protocols/iso15693_3/iso15693_3_device_defs.h create mode 100644 lib/nfc/protocols/slix/slix.c create mode 100644 lib/nfc/protocols/slix/slix.h create mode 100644 lib/nfc/protocols/slix/slix_device_defs.h create mode 100644 lib/nfc/protocols/slix/slix_i.c create mode 100644 lib/nfc/protocols/slix/slix_i.h create mode 100644 lib/nfc/protocols/slix/slix_listener.c create mode 100644 lib/nfc/protocols/slix/slix_listener.h create mode 100644 lib/nfc/protocols/slix/slix_listener_defs.h create mode 100644 lib/nfc/protocols/slix/slix_listener_i.c create mode 100644 lib/nfc/protocols/slix/slix_listener_i.h create mode 100644 lib/nfc/protocols/slix/slix_poller.c create mode 100644 lib/nfc/protocols/slix/slix_poller.h create mode 100644 lib/nfc/protocols/slix/slix_poller_defs.h create mode 100644 lib/nfc/protocols/slix/slix_poller_i.c create mode 100644 lib/nfc/protocols/slix/slix_poller_i.h diff --git a/applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3_render.c b/applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3_render.c index 76e549df0e7d..8df5d644ca42 100644 --- a/applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3_render.c +++ b/applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3_render.c @@ -10,15 +10,33 @@ void nfc_render_iso15693_3_info( furi_string_cat(str, "ISO15693-3 (NFC-V)\n"); } + nfc_render_iso15693_3_header(data, str); + + if(format_type != NfcProtocolFormatTypeFull) return; + + furi_string_push_back(str, '\n'); + + nfc_render_iso15693_3_main_info(data, str); +} + +void nfc_render_iso15693_3_header(const Iso15693_3Data* data, FuriString* str) { furi_string_cat_printf(str, "UID:"); + for(size_t i = 0; i < ISO15693_3_UID_SIZE; i++) { furi_string_cat_printf(str, " %02X", data->uid[i]); } - if(format_type != NfcProtocolFormatTypeFull) return; + if(data->system_info.flags & ISO15693_3_SYSINFO_FLAG_MEMORY) { + const uint16_t block_count = data->system_info.block_count; + const uint8_t block_size = data->system_info.block_size; - furi_string_push_back(str, '\n'); + furi_string_cat_printf(str, "Memory: %u bytes\n", block_count * block_size); + furi_string_cat_printf(str, "(%u blocks x %u bytes)", block_count, block_size); + } +} +void nfc_render_iso15693_3_main_info(const Iso15693_3Data* data, FuriString* str) { + furi_string_cat(str, "\e#General info\n"); if(data->system_info.flags & ISO15693_3_SYSINFO_FLAG_DSFID) { furi_string_cat_printf(str, "DSFID: %02X\n", data->system_info.ic_ref); } @@ -31,17 +49,26 @@ void nfc_render_iso15693_3_info( furi_string_cat_printf(str, "IC Reference: %02X\n", data->system_info.ic_ref); } + furi_string_cat(str, "\e#Lock bits\n"); + + if(data->system_info.flags & ISO15693_3_SYSINFO_FLAG_DSFID) { + furi_string_cat_printf( + str, "DSFID: %s locked\n", data->settings.lock_bits.dsfid ? "" : "not"); + } + + if(data->system_info.flags & ISO15693_3_SYSINFO_FLAG_AFI) { + furi_string_cat_printf( + str, "AFI: %s locked\n", data->settings.lock_bits.dsfid ? "" : "not"); + } + if(data->system_info.flags & ISO15693_3_SYSINFO_FLAG_MEMORY) { - furi_string_cat_printf(str, "Block count: %u\n", data->system_info.block_count); - furi_string_cat_printf(str, "Block size: %u\n", data->system_info.block_size); + furi_string_cat(str, "\e#Memory data\n\e*--------------------\n"); const uint32_t block_data_size = simple_array_get_count(data->block_data); const uint32_t display_data_size = MIN(block_data_size, NFC_RENDER_ISO15693_3_MAX_BYTES); - - furi_string_cat_printf(str, "Data (%lu bytes):\n", block_data_size); - const uint32_t block_count = display_data_size / data->system_info.block_size; + // TODO: Improve hex data display for(uint32_t i = 0; i < block_count; ++i) { furi_string_cat(str, "\e*"); @@ -52,7 +79,7 @@ void nfc_render_iso15693_3_info( } const uint8_t security = *(uint8_t*)simple_array_cget(data->block_security, i + 1); - furi_string_cat_printf(str, "%s\n", (security & 0x01) ? "[LOCK]" : ""); + furi_string_cat_printf(str, "| %s\n", (security & 0x01) ? "[LOCK]" : ""); } if(block_data_size != display_data_size) { diff --git a/applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3_render.h b/applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3_render.h index bffec5355384..d9d64f97103c 100644 --- a/applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3_render.h +++ b/applications/main/nfc/helpers/protocol_support/iso15693_3/iso15693_3_render.h @@ -8,3 +8,7 @@ void nfc_render_iso15693_3_info( const Iso15693_3Data* data, NfcProtocolFormatType format_type, FuriString* str); + +void nfc_render_iso15693_3_header(const Iso15693_3Data* data, FuriString* str); + +void nfc_render_iso15693_3_main_info(const Iso15693_3Data* data, FuriString* str); diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_defs.c b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_defs.c index 4b3d15168fc3..549b06b2b300 100644 --- a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_defs.c +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support_defs.c @@ -8,6 +8,7 @@ #include "mf_ultralight/mf_ultralight.h" #include "mf_classic/mf_classic.h" #include "mf_desfire/mf_desfire.h" +#include "slix/slix.h" const NfcProtocolSupportBase* nfc_protocol_support[NfcProtocolNum] = { [NfcProtocolIso14443_3a] = &nfc_protocol_support_iso14443_3a, @@ -18,5 +19,6 @@ const NfcProtocolSupportBase* nfc_protocol_support[NfcProtocolNum] = { [NfcProtocolMfUltralight] = &nfc_protocol_support_mf_ultralight, [NfcProtocolMfClassic] = &nfc_protocol_support_mf_classic, [NfcProtocolMfDesfire] = &nfc_protocol_support_mf_desfire, + [NfcProtocolSlix] = &nfc_protocol_support_slix, /* Add new protocols here */ }; diff --git a/applications/main/nfc/helpers/protocol_support/slix/slix.c b/applications/main/nfc/helpers/protocol_support/slix/slix.c new file mode 100644 index 000000000000..e027e53b0092 --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/slix/slix.c @@ -0,0 +1,141 @@ +#include "slix.h" +#include "slix_render.h" + +#include +#include + +#include "nfc/nfc_app_i.h" + +#include "../nfc_protocol_support_gui_common.h" + +static void nfc_scene_info_on_enter_slix(NfcApp* instance) { + const NfcDevice* device = instance->nfc_device; + const SlixData* data = nfc_device_get_data(device, NfcProtocolSlix); + + FuriString* temp_str = furi_string_alloc(); + furi_string_cat_printf( + temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull)); + nfc_render_slix_info(data, NfcProtocolFormatTypeFull, temp_str); + + widget_add_text_scroll_element( + instance->widget, 0, 0, 128, 64, furi_string_get_cstr(temp_str)); + + furi_string_free(temp_str); +} + +static NfcCommand nfc_scene_read_poller_callback_slix(NfcGenericEvent event, void* context) { + furi_assert(event.protocol == NfcProtocolSlix); + + NfcApp* instance = context; + const SlixPollerEvent* slix_event = event.data; + + if(slix_event->type == SlixPollerEventTypeReady) { + nfc_device_set_data( + instance->nfc_device, NfcProtocolSlix, nfc_poller_get_data(instance->poller)); + view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventPollerSuccess); + return NfcCommandStop; + } + + return NfcCommandContinue; +} + +static void nfc_scene_read_on_enter_slix(NfcApp* instance) { + nfc_poller_start(instance->poller, nfc_scene_read_poller_callback_slix, instance); +} + +static void nfc_scene_read_success_on_enter_slix(NfcApp* instance) { + const NfcDevice* device = instance->nfc_device; + const SlixData* data = nfc_device_get_data(device, NfcProtocolSlix); + + FuriString* temp_str = furi_string_alloc(); + furi_string_cat_printf( + temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull)); + nfc_render_slix_info(data, NfcProtocolFormatTypeShort, temp_str); + + widget_add_text_scroll_element( + instance->widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); + + furi_string_free(temp_str); +} + +static NfcCommand nfc_scene_emulate_listener_callback_slix(NfcGenericEvent event, void* context) { + furi_assert(context); + furi_assert(event.protocol == NfcProtocolSlix); + furi_assert(event.data); + + NfcApp* nfc = context; + SlixListenerEvent* slix_event = event.data; + + if(slix_event->type == SlixListenerEventTypeCustomCommand) { + furi_string_cat_printf(nfc->text_box_store, "R:"); + for(size_t i = 0; i < bit_buffer_get_size_bytes(slix_event->data->buffer); i++) { + furi_string_cat_printf( + nfc->text_box_store, " %02X", bit_buffer_get_byte(slix_event->data->buffer, i)); + } + furi_string_push_back(nfc->text_box_store, '\n'); + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventListenerUpdate); + } + + return NfcCommandContinue; +} + +static void nfc_scene_emulate_on_enter_slix(NfcApp* instance) { + const SlixData* data = nfc_device_get_data(instance->nfc_device, NfcProtocolSlix); + + instance->listener = nfc_listener_alloc(instance->nfc, NfcProtocolSlix, data); + nfc_listener_start(instance->listener, nfc_scene_emulate_listener_callback_slix, instance); +} + +static bool nfc_scene_info_on_event_slix(NfcApp* instance, uint32_t event) { + if(event == GuiButtonTypeRight) { + scene_manager_next_scene(instance->scene_manager, NfcSceneNotImplemented); + return true; + } + + return false; +} + +static bool nfc_scene_saved_menu_on_event_slix(NfcApp* instance, uint32_t event) { + if(event == SubmenuIndexCommonEdit) { + scene_manager_next_scene(instance->scene_manager, NfcSceneSetUid); + return true; + } + + return false; +} + +const NfcProtocolSupportBase nfc_protocol_support_slix = { + .features = + NfcProtocolFeatureEmulateFull, // | NfcProtocolFeatureEditUid, // TODO: Implement better UID editing + + .scene_info = + { + .on_enter = nfc_scene_info_on_enter_slix, + .on_event = nfc_scene_info_on_event_slix, + }, + .scene_read = + { + .on_enter = nfc_scene_read_on_enter_slix, + .on_event = NULL, + }, + .scene_read_menu = + { + .on_enter = nfc_protocol_support_common_on_enter_empty, + .on_event = nfc_protocol_support_common_on_event_empty, + }, + .scene_read_success = + { + .on_enter = nfc_scene_read_success_on_enter_slix, + .on_event = NULL, + }, + .scene_saved_menu = + { + .on_enter = nfc_protocol_support_common_on_enter_empty, + .on_event = nfc_scene_saved_menu_on_event_slix, + }, + .scene_emulate = + { + .on_enter = nfc_scene_emulate_on_enter_slix, + .on_event = NULL, + }, +}; diff --git a/applications/main/nfc/helpers/protocol_support/slix/slix.h b/applications/main/nfc/helpers/protocol_support/slix/slix.h new file mode 100644 index 000000000000..9c7504ebafa2 --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/slix/slix.h @@ -0,0 +1,5 @@ +#pragma once + +#include "../nfc_protocol_support_base.h" + +extern const NfcProtocolSupportBase nfc_protocol_support_slix; diff --git a/applications/main/nfc/helpers/protocol_support/slix/slix_render.c b/applications/main/nfc/helpers/protocol_support/slix/slix_render.c new file mode 100644 index 000000000000..0cbaec05615a --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/slix/slix_render.c @@ -0,0 +1,81 @@ +#include "slix_render.h" + +#include "../iso15693_3/iso15693_3_render.h" + +void nfc_render_slix_info(const SlixData* data, NfcProtocolFormatType format_type, FuriString* str) { + if(format_type == NfcProtocolFormatTypeFull) { + furi_string_cat_printf(str, "%s\n", slix_get_device_name(data, NfcDeviceNameTypeFull)); + } + + const Iso15693_3Data* iso15693_3_data = slix_get_base_data(data); + + nfc_render_iso15693_3_header(iso15693_3_data, str); + + if(format_type != NfcProtocolFormatTypeFull) return; + const SlixType slix_type = slix_get_type(data); + + furi_string_cat(str, "\n\e#Passwords\n"); + + static const char* slix_password_names[] = { + "Read", + "Write", + "Privacy", + "Destroy", + "EAS/AFI", + }; + + for(uint32_t i = 0; i < SlixPasswordTypeCount; ++i) { + if(slix_type_supports_password(slix_type, i)) { + furi_string_cat_printf( + str, "%s : %08lX\n", slix_password_names[i], data->passwords[i]); + } + } + + furi_string_cat(str, "\e#Lock bits\n"); + + if(slix_type_has_features(slix_type, SLIX_TYPE_FEATURE_EAS)) { + furi_string_cat_printf( + str, "EAS: %s locked\n", data->system_info.lock_bits.eas ? "" : "not"); + } + + if(slix_type_has_features(slix_type, SLIX_TYPE_FEATURE_PROTECTION)) { + furi_string_cat_printf( + str, "PPL: %s locked\n", data->system_info.lock_bits.ppl ? "" : "not"); + + const SlixProtection protection = data->system_info.protection; + + furi_string_cat(str, "\e#Page protection\n"); + furi_string_cat_printf(str, "Pointer: H >= %02X\n", protection.pointer); + + const char* rh = (protection.condition & SLIX_PP_CONDITION_RH) ? "" : "un"; + const char* rl = (protection.condition & SLIX_PP_CONDITION_RL) ? "" : "un"; + + const char* wh = (protection.condition & SLIX_PP_CONDITION_WH) ? "" : "un"; + const char* wl = (protection.condition & SLIX_PP_CONDITION_WL) ? "" : "un"; + + furi_string_cat_printf(str, "R: H %sprotec. L %sprotec.\n", rh, rl); + furi_string_cat_printf(str, "W: H %sprotec. L %sprotec.\n", wh, wl); + } + + if(slix_type_has_features(slix_type, SLIX_TYPE_FEATURE_PRIVACY)) { + furi_string_cat(str, "\e#Privacy\n"); + furi_string_cat_printf(str, "Privacy mode: %sabled\n", data->privacy ? "en" : "dis"); + } + + if(slix_type_has_features(slix_type, SLIX_TYPE_FEATURE_SIGNATURE)) { + furi_string_cat(str, "\e#Signature\n"); + for(uint32_t i = 0; i < 4; ++i) { + furi_string_cat_printf(str, "%02X ", data->signature[i]); + } + + furi_string_cat(str, "[ ... ]"); + + for(uint32_t i = 0; i < 3; ++i) { + furi_string_cat_printf(str, " %02X", data->signature[sizeof(SlixSignature) - i - 1]); + } + } + + furi_string_cat(str, "\n\e#ISO15693-3 data\n"); + + nfc_render_iso15693_3_main_info(iso15693_3_data, str); +} diff --git a/applications/main/nfc/helpers/protocol_support/slix/slix_render.h b/applications/main/nfc/helpers/protocol_support/slix/slix_render.h new file mode 100644 index 000000000000..98ae6dc97fd8 --- /dev/null +++ b/applications/main/nfc/helpers/protocol_support/slix/slix_render.h @@ -0,0 +1,7 @@ +#pragma once + +#include + +#include "../nfc_protocol_support_render_common.h" + +void nfc_render_slix_info(const SlixData* data, NfcProtocolFormatType format_type, FuriString* str); diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3.c b/lib/nfc/protocols/iso15693_3/iso15693_3.c index cecb1a8aaa3b..adc9c9558c49 100644 --- a/lib/nfc/protocols/iso15693_3/iso15693_3.c +++ b/lib/nfc/protocols/iso15693_3/iso15693_3.c @@ -1,4 +1,5 @@ #include "iso15693_3.h" +#include "iso15693_3_device_defs.h" #include @@ -6,13 +7,17 @@ #define ISO15693_3_PROTOCOL_NAME_LEGACY "ISO15693" #define ISO15693_3_DEVICE_NAME "ISO15693-3 (Unknown)" +#define ISO15693_3_LOCK_DSFID_LEGACY (1U << 0) +#define ISO15693_3_LOCK_AFI_LEGACY (1U << 1) + #define ISO15693_3_DSFID_KEY "DSFID" #define ISO15693_3_AFI_KEY "AFI" #define ISO15693_3_IC_REF_KEY "IC Reference" #define ISO15693_3_BLOCK_COUNT_KEY "Block Count" #define ISO15693_3_BLOCK_SIZE_KEY "Block Size" #define ISO15693_3_DATA_CONTENT_KEY "Data Content" -#define ISO15693_3_LOCK_BITS_KEY "Lock Bits" +#define ISO15693_3_LOCK_DSFID_KEY "Lock DSFID" +#define ISO15693_3_LOCK_AFI_KEY "Lock AFI" #define ISO15693_3_SECURITY_STATUS_KEY "Security Status" const NfcDeviceBase nfc_device_iso15693_3 = { @@ -92,7 +97,9 @@ static inline bool iso15693_3_load_security_legacy(Iso15693_3Data* data, Flipper break; // First legacy data byte is lock bits - data->settings.lock_bits = legacy_data[0]; + data->settings.lock_bits.dsfid = legacy_data[0] & ISO15693_3_LOCK_DSFID_LEGACY; + data->settings.lock_bits.afi = legacy_data[0] & ISO15693_3_LOCK_AFI_LEGACY; + // The rest are block security memcpy( &legacy_data[1], @@ -152,10 +159,13 @@ bool iso15693_3_load(Iso15693_3Data* data, FlipperFormat* ff, uint32_t version) data->system_info.flags |= ISO15693_3_SYSINFO_FLAG_IC_REF; } - const bool has_lock_bits = flipper_format_key_exist(ff, ISO15693_3_LOCK_BITS_KEY); + const bool has_lock_bits = flipper_format_key_exist(ff, ISO15693_3_LOCK_DSFID_KEY) && + flipper_format_key_exist(ff, ISO15693_3_LOCK_AFI_KEY); if(has_lock_bits) { - if(!flipper_format_read_hex(ff, ISO15693_3_LOCK_BITS_KEY, &data->settings.lock_bits, 1)) + Iso15693_3LockBits* lock_bits = &data->settings.lock_bits; + if(!flipper_format_read_bool(ff, ISO15693_3_LOCK_DSFID_KEY, &lock_bits->dsfid, 1)) break; + if(!flipper_format_read_bool(ff, ISO15693_3_LOCK_AFI_KEY, &lock_bits->afi, 1)) break; } if(flipper_format_key_exist(ff, ISO15693_3_BLOCK_COUNT_KEY) && @@ -202,6 +212,9 @@ bool iso15693_3_save(const Iso15693_3Data* data, FlipperFormat* ff) { bool saved = false; do { + if(!flipper_format_write_comment_cstr(ff, ISO15693_3_PROTOCOL_NAME " specific data")) + break; + if(data->system_info.flags & ISO15693_3_SYSINFO_FLAG_DSFID) { if(!flipper_format_write_comment_cstr(ff, "Data Storage Format Identifier")) break; if(!flipper_format_write_hex(ff, ISO15693_3_DSFID_KEY, &data->system_info.dsfid, 1)) @@ -220,8 +233,12 @@ bool iso15693_3_save(const Iso15693_3Data* data, FlipperFormat* ff) { break; } - if(!flipper_format_write_comment_cstr(ff, "Lock Bits: 0x01 = DSFID, 0x02 = AFI")) break; - if(!flipper_format_write_hex(ff, ISO15693_3_LOCK_BITS_KEY, &data->settings.lock_bits, 1)) + if(!flipper_format_write_comment_cstr(ff, "Lock Bits")) break; + if(!flipper_format_write_bool( + ff, ISO15693_3_LOCK_DSFID_KEY, &data->settings.lock_bits.dsfid, 1)) + break; + if(!flipper_format_write_bool( + ff, ISO15693_3_LOCK_AFI_KEY, &data->settings.lock_bits.afi, 1)) break; if(data->system_info.flags & ISO15693_3_SYSINFO_FLAG_MEMORY) { @@ -232,7 +249,8 @@ bool iso15693_3_save(const Iso15693_3Data* data, FlipperFormat* ff) { if(!flipper_format_write_uint32(ff, ISO15693_3_BLOCK_COUNT_KEY, &block_count, 1)) break; - if(!flipper_format_write_comment_cstr(ff, "Size of a single memory block, usually 4")) + if(!flipper_format_write_comment_cstr( + ff, "Size of a single memory block, valid range = 01...20 (hex)")) break; if(!flipper_format_write_hex( ff, ISO15693_3_BLOCK_SIZE_KEY, &data->system_info.block_size, 1)) @@ -246,7 +264,7 @@ bool iso15693_3_save(const Iso15693_3Data* data, FlipperFormat* ff) { break; if(!flipper_format_write_comment_cstr( - ff, "Block Security Status: 0x01 = locked, 0x00 = not locked")) + ff, "Block Security Status: 01 = locked, 00 = not locked")) break; if(!flipper_format_write_hex( ff, @@ -304,16 +322,35 @@ Iso15693_3Data* iso15693_3_get_base_data(const Iso15693_3Data* data) { furi_crash("No base data"); } -bool iso15693_3_is_block_locked(const Iso15693_3Data* data, uint8_t block_num) { +bool iso15693_3_is_block_locked(const Iso15693_3Data* data, uint8_t block_index) { + furi_assert(data); + furi_assert(block_index < data->system_info.block_count); + + return *(const uint8_t*)simple_array_cget(data->block_security, block_index); +} + +uint8_t iso15693_3_get_manufacturer_id(const Iso15693_3Data* data) { + furi_assert(data); + + return data->uid[1]; +} + +uint16_t iso15693_3_get_block_count(const Iso15693_3Data* data) { + furi_assert(data); + + return data->system_info.block_count; +} + +uint8_t iso15693_3_get_block_size(const Iso15693_3Data* data) { furi_assert(data); - furi_assert(block_num < data->system_info.block_count); - return *(const uint8_t*)simple_array_cget(data->block_security, block_num); + return data->system_info.block_size; } -void iso15693_3_set_block_locked(Iso15693_3Data* data, uint8_t block_num, bool locked) { +const uint8_t* iso15693_3_get_block_data(const Iso15693_3Data* data, uint8_t block_index) { furi_assert(data); - furi_assert(block_num < data->system_info.block_count); + furi_assert(data->system_info.block_count > block_index); - *(uint8_t*)simple_array_get(data->block_security, block_num) = locked ? 1 : 0; + return (const uint8_t*)simple_array_cget( + data->block_data, block_index * data->system_info.block_size); } diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3.h b/lib/nfc/protocols/iso15693_3/iso15693_3.h index 99417ecac493..5d4158ab9e3c 100644 --- a/lib/nfc/protocols/iso15693_3/iso15693_3.h +++ b/lib/nfc/protocols/iso15693_3/iso15693_3.h @@ -1,7 +1,7 @@ #pragma once -#include - +#include +#include #include #ifdef __cplusplus @@ -15,23 +15,6 @@ extern "C" { #define ISO15693_3_FDT_LISTEN_FC (4320U) #define ISO15693_3_POLL_POLL_MIN_US (1500U) -/* true: modulating releases load, false: modulating adds load resistor to field coil */ -#define ISO15693_3_LOAD_MODULATION_POLARITY (false) - -#define ISO15693_3_FC (13560000.0f) /* MHz */ -#define ISO15693_3_RESP_SUBC1_PULSE_32 (1.0f / (ISO15693_3_FC / 32) / 2.0f) /* 1.1799 µs */ -#define ISO15693_3_RESP_SUBC1_UNMOD_256 (256.0f / ISO15693_3_FC) /* 18.8791 µs */ -#define ISO15693_3_PULSE_DURATION_NS (128.0f * 1000000000.0f / ISO15693_3_FC) - -/* ISO/IEC 15693-3:2019(E) 10.4.12: maximum number of blocks is defined as 256 */ -#define ISO15693_3_BLOCKS_MAX 256 -/* ISO/IEC 15693-3:2019(E) 10.4.12: maximum size of blocks is defined as 32 */ -#define ISO15693_3_BLOCKSIZE_MAX 32 -/* the resulting memory size a card can have */ -#define ISO15693_3_MEMSIZE_MAX (ISO15693_3_BLOCKS_MAX * ISO15693_3_BLOCKSIZE_MAX) -/* ISO/IEC 15693-3:2019(E) 7.1b: standard allows up to 8192, the maxium frame length that we are expected to receive/send is less */ -#define ISO15693_3_FRAMESIZE_MAX (1 + ISO15693_3_MEMSIZE_MAX + ISO15693_3_BLOCKS_MAX) - #define ISO15693_3_REQ_FLAG_SUBCARRIER_1 (0U << 0) #define ISO15693_3_REQ_FLAG_SUBCARRIER_2 (1U << 0) #define ISO15693_3_REQ_FLAG_DATA_RATE_LO (0U << 1) @@ -84,26 +67,29 @@ extern "C" { #define ISO15693_3_CMD_GET_SYS_INFO (0x2BU) #define ISO15693_3_CMD_GET_BLOCKS_SECURITY (0x2CU) #define ISO15693_3_CMD_OPTIONAL_RFU (0x2DU) +#define ISO15693_3_CMD_CUSTOM_START (0xA0U) + +#define ISO15693_3_MANDATORY_COUNT (ISO15693_3_CMD_MANDATORY_RFU - ISO15693_3_CMD_MANDATORY_START) +#define ISO15693_3_OPTIONAL_COUNT (ISO15693_3_CMD_OPTIONAL_RFU - ISO15693_3_CMD_OPTIONAL_START) #define ISO15693_3_SYSINFO_FLAG_DSFID (1U << 0) #define ISO15693_3_SYSINFO_FLAG_AFI (1U << 1) #define ISO15693_3_SYSINFO_FLAG_MEMORY (1U << 2) #define ISO15693_3_SYSINFO_FLAG_IC_REF (1U << 3) -#define ISO15693_3_SYSINFO_LOCK_DSFID (1U << 0) -#define ISO15693_3_SYSINFO_LOCK_AFI (1U << 1) - typedef enum { Iso15693_3ErrorNone, Iso15693_3ErrorNotPresent, Iso15693_3ErrorBufferEmpty, Iso15693_3ErrorBufferOverflow, - Iso15693_3ErrorFraming, Iso15693_3ErrorFieldOff, Iso15693_3ErrorWrongCrc, Iso15693_3ErrorTimeout, Iso15693_3ErrorFormat, + Iso15693_3ErrorIgnore, Iso15693_3ErrorNotSupported, + Iso15693_3ErrorUidMismatch, + Iso15693_3ErrorFullyHandled, Iso15693_3ErrorUnexpectedResponse, Iso15693_3ErrorInternal, Iso15693_3ErrorCustom, @@ -120,7 +106,12 @@ typedef struct { } Iso15693_3SystemInfo; typedef struct { - uint8_t lock_bits; + bool dsfid; + bool afi; +} Iso15693_3LockBits; + +typedef struct { + Iso15693_3LockBits lock_bits; } Iso15693_3Settings; typedef struct { @@ -157,13 +148,15 @@ Iso15693_3Data* iso15693_3_get_base_data(const Iso15693_3Data* data); // Getters and tests -bool iso15693_3_is_block_locked(const Iso15693_3Data* data, uint8_t block_num); +bool iso15693_3_is_block_locked(const Iso15693_3Data* data, uint8_t block_index); + +uint8_t iso15693_3_get_manufacturer_id(const Iso15693_3Data* data); -// Setters +uint16_t iso15693_3_get_block_count(const Iso15693_3Data* data); -void iso15693_3_set_block_locked(Iso15693_3Data* data, uint8_t block_num, bool locked); +uint8_t iso15693_3_get_block_size(const Iso15693_3Data* data); -extern const NfcDeviceBase nfc_device_iso15693_3; +const uint8_t* iso15693_3_get_block_data(const Iso15693_3Data* data, uint8_t block_index); #ifdef __cplusplus } diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3_device_defs.h b/lib/nfc/protocols/iso15693_3/iso15693_3_device_defs.h new file mode 100644 index 000000000000..dffa137b8d20 --- /dev/null +++ b/lib/nfc/protocols/iso15693_3/iso15693_3_device_defs.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern const NfcDeviceBase nfc_device_iso15693_3; + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3_i.c b/lib/nfc/protocols/iso15693_3/iso15693_3_i.c index c75d19261584..3d8d95c3a1d0 100644 --- a/lib/nfc/protocols/iso15693_3/iso15693_3_i.c +++ b/lib/nfc/protocols/iso15693_3/iso15693_3_i.c @@ -227,6 +227,13 @@ void iso15693_3_append_block(const Iso15693_3Data* data, uint8_t block_num, BitB bit_buffer_append_bytes(buf, block_data, data->system_info.block_size); } +void iso15693_3_set_block_locked(Iso15693_3Data* data, uint8_t block_index, bool locked) { + furi_assert(data); + furi_assert(block_index < data->system_info.block_count); + + *(uint8_t*)simple_array_get(data->block_security, block_index) = locked ? 1 : 0; +} + void iso15693_3_set_block_data( Iso15693_3Data* data, uint8_t block_num, diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3_i.h b/lib/nfc/protocols/iso15693_3/iso15693_3_i.h index 01280e180822..253bda7f5985 100644 --- a/lib/nfc/protocols/iso15693_3/iso15693_3_i.h +++ b/lib/nfc/protocols/iso15693_3/iso15693_3_i.h @@ -37,6 +37,8 @@ void iso15693_3_append_uid(const Iso15693_3Data* data, BitBuffer* buf); void iso15693_3_append_block(const Iso15693_3Data* data, uint8_t block_num, BitBuffer* buf); +void iso15693_3_set_block_locked(Iso15693_3Data* data, uint8_t block_index, bool locked); + void iso15693_3_set_block_data( Iso15693_3Data* data, uint8_t block_num, diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3_listener.c b/lib/nfc/protocols/iso15693_3/iso15693_3_listener.c index 3b7a39899f82..cd03d482babb 100644 --- a/lib/nfc/protocols/iso15693_3/iso15693_3_listener.c +++ b/lib/nfc/protocols/iso15693_3/iso15693_3_listener.c @@ -64,32 +64,33 @@ NfcCommand iso15693_3_listener_run(NfcGenericEvent event, void* context) { NfcEvent* nfc_event = event.data; NfcCommand command = NfcCommandContinue; - if(nfc_event->type == NfcEventTypeFieldOn) { - iso15693_3_listener_ready(instance); - } else if(nfc_event->type == NfcEventTypeFieldOff) { - if(instance->callback) { - instance->iso15693_3_event.type = Iso15693_3ListenerEventTypeFieldOff; - command = instance->callback(instance->generic_event, instance->context); - } - iso15693_3_listener_sleep(instance); - } else if(nfc_event->type == NfcEventTypeRxEnd) { - BitBuffer* request_buf = nfc_event->data.buffer; - if(iso13239_crc_check(Iso13239CrcTypeDefault, request_buf)) { - iso13239_crc_trim(request_buf); - const Iso15693_3Error error = - iso15693_3_listener_process_request(instance, request_buf); + if(nfc_event->type == NfcEventTypeRxEnd) { + BitBuffer* rx_buffer = nfc_event->data.buffer; + + if(iso13239_crc_check(Iso13239CrcTypeDefault, rx_buffer)) { + iso13239_crc_trim(rx_buffer); + + const Iso15693_3Error error = iso15693_3_listener_process_request(instance, rx_buffer); + if(error == Iso15693_3ErrorNotSupported) { - instance->iso15693_3_event.type = Iso15693_3ListenerEventTypeCustomCommand; - command = instance->callback(instance->generic_event, instance->context); + if(instance->callback) { + instance->iso15693_3_event.type = Iso15693_3ListenerEventTypeCustomCommand; + instance->iso15693_3_event.data->buffer = rx_buffer; + command = instance->callback(instance->generic_event, instance->context); + } + + } else if(error == Iso15693_3ErrorUidMismatch) { + iso15693_3_listener_process_uid_mismatch(instance, rx_buffer); } - } else if(bit_buffer_get_size(request_buf) == 0) { + + } else if(bit_buffer_get_size(rx_buffer) == 0) { // Special case: Single EOF - if(instance->session_state.wait_for_eof) { - iso15693_3_listener_send_frame(instance, instance->tx_buffer); - instance->session_state.wait_for_eof = false; - } else if(instance->callback) { - instance->iso15693_3_event.type = Iso15693_3ListenerEventTypeSingleEof; - command = instance->callback(instance->generic_event, instance->context); + const Iso15693_3Error error = iso15693_3_listener_process_single_eof(instance); + if(error == Iso15693_3ErrorUnexpectedResponse) { + if(instance->callback) { + instance->iso15693_3_event.type = Iso15693_3ListenerEventTypeSingleEof; + command = instance->callback(instance->generic_event, instance->context); + } } } else { FURI_LOG_D( diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3_listener_i.c b/lib/nfc/protocols/iso15693_3/iso15693_3_listener_i.c index ad7e33d00c90..7bb3359dad40 100644 --- a/lib/nfc/protocols/iso15693_3/iso15693_3_listener_i.c +++ b/lib/nfc/protocols/iso15693_3/iso15693_3_listener_i.c @@ -10,6 +10,41 @@ typedef Iso15693_3Error (*Iso15693_3RequestHandler)( size_t data_size, uint8_t flags); +typedef struct { + Iso15693_3RequestHandler mandatory[ISO15693_3_MANDATORY_COUNT]; + Iso15693_3RequestHandler optional[ISO15693_3_OPTIONAL_COUNT]; +} Iso15693_3ListenerHandlerTable; + +static Iso15693_3Error + iso15693_3_listener_extension_handler(Iso15693_3Listener* instance, uint32_t command, ...) { + Iso15693_3Error error = Iso15693_3ErrorNone; + + do { + if(instance->extension_table == NULL) break; + + Iso15693_3ExtensionHandler handler = NULL; + + if(command < ISO15693_3_CMD_MANDATORY_RFU) { + const Iso15693_3ExtensionHandler* mandatory = instance->extension_table->mandatory; + handler = mandatory[command - ISO15693_3_CMD_MANDATORY_START]; + } else if(command >= ISO15693_3_CMD_OPTIONAL_START && command < ISO15693_3_CMD_OPTIONAL_RFU) { + const Iso15693_3ExtensionHandler* optional = instance->extension_table->optional; + handler = optional[command - ISO15693_3_CMD_OPTIONAL_START]; + } + + if(handler == NULL) break; + + va_list args; + va_start(args, command); + + error = handler(instance->extension_context, args); + + va_end(args); + + } while(false); + return error; +} + static Iso15693_3Error iso15693_3_listener_inventory_handler( Iso15693_3Listener* instance, const uint8_t* data, @@ -44,11 +79,13 @@ static Iso15693_3Error iso15693_3_listener_inventory_handler( // TODO: Take mask_len and mask_value into account (if present) } + error = iso15693_3_listener_extension_handler(instance, ISO15693_3_CMD_INVENTORY); + if(error != Iso15693_3ErrorNone) break; + bit_buffer_append_byte(instance->tx_buffer, instance->data->system_info.dsfid); // DSFID iso15693_3_append_uid(instance->data, instance->tx_buffer); // UID } while(false); - instance->session_state.no_reply = (error != Iso15693_3ErrorNone); return error; } @@ -62,8 +99,7 @@ static Iso15693_3Error iso15693_3_listener_stay_quiet_handler( UNUSED(flags); instance->state = Iso15693_3ListenerStateQuiet; - instance->session_state.no_reply = true; - return Iso15693_3ErrorNone; + return Iso15693_3ErrorIgnore; } static Iso15693_3Error iso15693_3_listener_read_block_handler( @@ -94,6 +130,10 @@ static Iso15693_3Error iso15693_3_listener_read_block_handler( break; } + error = iso15693_3_listener_extension_handler( + instance, ISO15693_3_CMD_READ_BLOCK, block_index); + if(error != Iso15693_3ErrorNone) break; + if(flags & ISO15693_3_REQ_FLAG_T4_OPTION) { iso15693_3_append_block_security( instance->data, block_index, instance->tx_buffer); // Block security (optional) @@ -144,6 +184,10 @@ static Iso15693_3Error iso15693_3_listener_write_block_handler( break; } + error = iso15693_3_listener_extension_handler( + instance, ISO15693_3_CMD_WRITE_BLOCK, block_index, request->block_data); + if(error != Iso15693_3ErrorNone) break; + iso15693_3_set_block_data( instance->data, block_index, request->block_data, block_size_received); } while(false); @@ -184,6 +228,10 @@ static Iso15693_3Error iso15693_3_listener_lock_block_handler( break; } + error = iso15693_3_listener_extension_handler( + instance, ISO15693_3_CMD_LOCK_BLOCK, block_index); + if(error != Iso15693_3ErrorNone) break; + iso15693_3_set_block_locked(instance->data, block_index, true); } while(false); @@ -223,6 +271,13 @@ static Iso15693_3Error iso15693_3_listener_read_multi_blocks_handler( break; } + error = iso15693_3_listener_extension_handler( + instance, + ISO15693_3_CMD_READ_MULTI_BLOCKS, + (uint32_t)block_index_start, + (uint32_t)block_index_end); + if(error != Iso15693_3ErrorNone) break; + for(uint32_t i = block_index_start; i <= block_index_end; ++i) { if(flags & ISO15693_3_REQ_FLAG_T4_OPTION) { iso15693_3_append_block_security( @@ -278,6 +333,10 @@ static Iso15693_3Error iso15693_3_listener_write_multi_blocks_handler( break; } + error = iso15693_3_listener_extension_handler( + instance, ISO15693_3_CMD_WRITE_MULTI_BLOCKS, block_index_start, block_index_end); + if(error != Iso15693_3ErrorNone) break; + for(uint32_t i = block_index_start; i <= block_index_end; ++i) { if(iso15693_3_is_block_locked(instance->data, i)) { error = Iso15693_3ErrorInternal; @@ -308,8 +367,7 @@ static Iso15693_3Error iso15693_3_listener_select_handler( do { if(!(flags & ISO15693_3_REQ_FLAG_T4_ADDRESSED)) { - instance->session_state.no_reply = true; - error = Iso15693_3ErrorUnknown; + error = Iso15693_3ErrorFormat; break; } @@ -352,11 +410,14 @@ static Iso15693_3Error iso15693_3_listener_write_afi_handler( if(data_size <= sizeof(Iso15693_3WriteAfiRequestLayout)) { error = Iso15693_3ErrorFormat; break; - } else if(instance->data->system_info.flags & ISO15693_3_SYSINFO_LOCK_AFI) { + } else if(instance->data->settings.lock_bits.afi) { error = Iso15693_3ErrorInternal; break; } + error = iso15693_3_listener_extension_handler(instance, ISO15693_3_CMD_WRITE_AFI); + if(error != Iso15693_3ErrorNone) break; + instance->data->system_info.afi = request->afi; } while(false); @@ -376,12 +437,17 @@ static Iso15693_3Error iso15693_3_listener_lock_afi_handler( do { instance->session_state.wait_for_eof = flags & ISO15693_3_REQ_FLAG_T4_OPTION; - if(instance->data->system_info.flags & ISO15693_3_SYSINFO_LOCK_AFI) { + Iso15693_3LockBits* lock_bits = &instance->data->settings.lock_bits; + + if(lock_bits->afi) { error = Iso15693_3ErrorInternal; break; } - instance->data->system_info.flags |= ISO15693_3_SYSINFO_LOCK_AFI; + error = iso15693_3_listener_extension_handler(instance, ISO15693_3_CMD_LOCK_AFI); + if(error != Iso15693_3ErrorNone) break; + + lock_bits->afi = true; } while(false); return error; @@ -407,11 +473,14 @@ static Iso15693_3Error iso15693_3_listener_write_dsfid_handler( if(data_size <= sizeof(Iso15693_3WriteDsfidRequestLayout)) { error = Iso15693_3ErrorFormat; break; - } else if(instance->data->system_info.flags & ISO15693_3_SYSINFO_LOCK_DSFID) { + } else if(instance->data->settings.lock_bits.dsfid) { error = Iso15693_3ErrorInternal; break; } + error = iso15693_3_listener_extension_handler(instance, ISO15693_3_CMD_WRITE_DSFID); + if(error != Iso15693_3ErrorNone) break; + instance->data->system_info.dsfid = request->dsfid; } while(false); @@ -431,12 +500,17 @@ static Iso15693_3Error iso15693_3_listener_lock_dsfid_handler( do { instance->session_state.wait_for_eof = flags & ISO15693_3_REQ_FLAG_T4_OPTION; - if(instance->data->system_info.flags & ISO15693_3_SYSINFO_LOCK_DSFID) { + Iso15693_3LockBits* lock_bits = &instance->data->settings.lock_bits; + + if(lock_bits->dsfid) { error = Iso15693_3ErrorInternal; break; } - instance->data->system_info.flags |= ISO15693_3_SYSINFO_LOCK_DSFID; + error = iso15693_3_listener_extension_handler(instance, ISO15693_3_CMD_LOCK_DSFID); + if(error != Iso15693_3ErrorNone) break; + + lock_bits->dsfid = true; } while(false); return error; @@ -523,27 +597,31 @@ static Iso15693_3Error iso15693_3_listener_get_multi_blocks_security_handler( return error; } -static const Iso15693_3RequestHandler iso15693_3_request_handlers[] = { - // Mandatory commands - iso15693_3_listener_inventory_handler, - iso15693_3_listener_stay_quiet_handler, - // Optional commands - iso15693_3_listener_read_block_handler, - iso15693_3_listener_write_block_handler, - iso15693_3_listener_lock_block_handler, - iso15693_3_listener_read_multi_blocks_handler, - iso15693_3_listener_write_multi_blocks_handler, - iso15693_3_listener_select_handler, - iso15693_3_listener_reset_to_ready_handler, - iso15693_3_listener_write_afi_handler, - iso15693_3_listener_lock_afi_handler, - iso15693_3_listener_write_dsfid_handler, - iso15693_3_listener_lock_dsfid_handler, - iso15693_3_listener_get_system_info_handler, - iso15693_3_listener_get_multi_blocks_security_handler, +const Iso15693_3ListenerHandlerTable iso15693_3_handler_table = { + .mandatory = + { + iso15693_3_listener_inventory_handler, + iso15693_3_listener_stay_quiet_handler, + }, + .optional = + { + iso15693_3_listener_read_block_handler, + iso15693_3_listener_write_block_handler, + iso15693_3_listener_lock_block_handler, + iso15693_3_listener_read_multi_blocks_handler, + iso15693_3_listener_write_multi_blocks_handler, + iso15693_3_listener_select_handler, + iso15693_3_listener_reset_to_ready_handler, + iso15693_3_listener_write_afi_handler, + iso15693_3_listener_lock_afi_handler, + iso15693_3_listener_write_dsfid_handler, + iso15693_3_listener_lock_dsfid_handler, + iso15693_3_listener_get_system_info_handler, + iso15693_3_listener_get_multi_blocks_security_handler, + }, }; -static inline Iso15693_3Error iso15693_3_listener_handle_request( +static Iso15693_3Error iso15693_3_listener_handle_standard_request( Iso15693_3Listener* instance, const uint8_t* data, size_t data_size, @@ -552,14 +630,15 @@ static inline Iso15693_3Error iso15693_3_listener_handle_request( Iso15693_3Error error = Iso15693_3ErrorNone; do { - uint8_t command_index; + Iso15693_3RequestHandler handler = NULL; if(command < ISO15693_3_CMD_MANDATORY_RFU) { - command_index = command - ISO15693_3_CMD_MANDATORY_START; + handler = iso15693_3_handler_table.mandatory[command - ISO15693_3_CMD_MANDATORY_START]; } else if(command >= ISO15693_3_CMD_OPTIONAL_START && command < ISO15693_3_CMD_OPTIONAL_RFU) { - command_index = command - ISO15693_3_CMD_MANDATORY_START - - ISO15693_3_CMD_OPTIONAL_START + ISO15693_3_CMD_MANDATORY_RFU; - } else { + handler = iso15693_3_handler_table.optional[command - ISO15693_3_CMD_OPTIONAL_START]; + } + + if(handler == NULL) { error = Iso15693_3ErrorNotSupported; break; } @@ -567,17 +646,16 @@ static inline Iso15693_3Error iso15693_3_listener_handle_request( bit_buffer_reset(instance->tx_buffer); bit_buffer_append_byte(instance->tx_buffer, ISO15693_3_RESP_FLAG_NONE); - error = iso15693_3_request_handlers[command_index](instance, data, data_size, flags); - - Iso15693_3ListenerSessionState* session_state = &instance->session_state; + error = handler(instance, data, data_size, flags); - // Several commands may not require an answer - if(session_state->no_reply) { - session_state->no_reply = false; + // The request was fully handled in the protocol extension, no further action necessary + if(error == Iso15693_3ErrorFullyHandled) { error = Iso15693_3ErrorNone; - break; } + // Several commands may not require an answer + if(error == Iso15693_3ErrorFormat || error == Iso15693_3ErrorIgnore) break; + // TODO: Move it to a separate function if(error != Iso15693_3ErrorNone) { bit_buffer_reset(instance->tx_buffer); @@ -585,6 +663,8 @@ static inline Iso15693_3Error iso15693_3_listener_handle_request( bit_buffer_append_byte(instance->tx_buffer, ISO15693_3_RESP_ERROR_UNKNOWN); } + Iso15693_3ListenerSessionState* session_state = &instance->session_state; + if(!session_state->wait_for_eof) { error = iso15693_3_listener_send_frame(instance, instance->tx_buffer); } @@ -594,15 +674,52 @@ static inline Iso15693_3Error iso15693_3_listener_handle_request( return error; } -Iso15693_3Error iso15693_3_listener_ready(Iso15693_3Listener* instance) { +static inline Iso15693_3Error iso15693_3_listener_handle_custom_request( + Iso15693_3Listener* instance, + const uint8_t* data, + size_t data_size) { + Iso15693_3Error error; + + do { + typedef struct { + uint8_t manufacturer; + uint8_t extra[]; + } Iso15693_3CustomRequestLayout; + + if(data_size < sizeof(Iso15693_3CustomRequestLayout)) { + error = Iso15693_3ErrorFormat; + break; + } + + const Iso15693_3CustomRequestLayout* request = (const Iso15693_3CustomRequestLayout*)data; + + if(request->manufacturer != iso15693_3_get_manufacturer_id(instance->data)) { + error = Iso15693_3ErrorIgnore; + break; + } + + // This error code will trigger the CustomCommand listener event + error = Iso15693_3ErrorNotSupported; + } while(false); + + return error; +} + +Iso15693_3Error iso15693_3_listener_set_extension_handler_table( + Iso15693_3Listener* instance, + const Iso15693_3ExtensionHandlerTable* table, + void* context) { furi_assert(instance); - instance->state = Iso15693_3ListenerStateReady; + furi_assert(context); + + instance->extension_table = table; + instance->extension_context = context; return Iso15693_3ErrorNone; } -Iso15693_3Error iso15693_3_listener_sleep(Iso15693_3Listener* instance) { +Iso15693_3Error iso15693_3_listener_ready(Iso15693_3Listener* instance) { furi_assert(instance); - instance->state = Iso15693_3ListenerStateIdle; + instance->state = Iso15693_3ListenerStateReady; return Iso15693_3ErrorNone; } @@ -654,73 +771,114 @@ Iso15693_3Error const Iso15693_3RequestLayout* request = (const Iso15693_3RequestLayout*)bit_buffer_get_data(rx_buffer); - const bool inventory_flag = request->flags & ISO15693_3_REQ_FLAG_INVENTORY_T5; + Iso15693_3ListenerSessionState* session_state = &instance->session_state; - if(!inventory_flag) { - const bool selected_mode = request->flags & ISO15693_3_REQ_FLAG_T4_SELECTED; - const bool addressed_mode = request->flags & ISO15693_3_REQ_FLAG_T4_ADDRESSED; + if((request->flags & ISO15693_3_REQ_FLAG_INVENTORY_T5) == 0) { + session_state->selected = request->flags & ISO15693_3_REQ_FLAG_T4_SELECTED; + session_state->addressed = request->flags & ISO15693_3_REQ_FLAG_T4_ADDRESSED; - if(selected_mode && addressed_mode) { + if(session_state->selected && session_state->addressed) { // A request mode can be either addressed or selected, but not both + error = Iso15693_3ErrorUnknown; break; } else if(instance->state == Iso15693_3ListenerStateQuiet) { // If the card is quiet, ignore non-addressed commands - if(!addressed_mode) break; + if(session_state->addressed) { + error = Iso15693_3ErrorIgnore; + break; + } } else if(instance->state != Iso15693_3ListenerStateSelected) { // If the card is not selected, ignore selected commands - if(selected_mode) break; + if(session_state->selected) { + error = Iso15693_3ErrorIgnore; + break; + } + } + } else { + // If the card is quiet, ignore inventory commands + if(instance->state == Iso15693_3ListenerStateQuiet) { + error = Iso15693_3ErrorIgnore; + break; } - const uint8_t* data; - size_t data_size; + session_state->selected = false; + session_state->addressed = false; + } - if(addressed_mode) { - // In addressed mode, UID must be included in each command - const size_t buf_size_min_addr = buf_size_min + ISO15693_3_UID_SIZE; + if(request->command >= ISO15693_3_CMD_CUSTOM_START) { + // Custom commands are properly handled in the protocol-specific top-level poller + error = iso15693_3_listener_handle_custom_request( + instance, request->data, buf_size - buf_size_min); + break; + } - if(buf_size < buf_size_min_addr) { - error = Iso15693_3ErrorFormat; - break; - } else if(!iso15693_3_is_equal_uid(instance->data, request->data)) { - // In addressed mode, ignore all commands with non-matching UID - if(instance->state == Iso15693_3ListenerStateSelected && - request->command == ISO15693_3_CMD_SELECT) { - // Special case, reset to ready on reception of a - // SELECT command with non-matching UID - // TODO: Find a neater way to do this? - instance->state = Iso15693_3ListenerStateReady; - } - break; - } + const uint8_t* data; + size_t data_size; - data = &request->data[ISO15693_3_UID_SIZE]; - data_size = buf_size - buf_size_min_addr; + if(session_state->addressed) { + // In addressed mode, UID must be included in each command + const size_t buf_size_min_addr = buf_size_min + ISO15693_3_UID_SIZE; - } else { - data = request->data; - data_size = buf_size - buf_size_min; + if(buf_size < buf_size_min_addr) { + error = Iso15693_3ErrorFormat; + break; + } else if(!iso15693_3_is_equal_uid(instance->data, request->data)) { + error = Iso15693_3ErrorUidMismatch; + break; } - error = iso15693_3_listener_handle_request( - instance, data, data_size, request->command, request->flags); + data = &request->data[ISO15693_3_UID_SIZE]; + data_size = buf_size - buf_size_min_addr; } else { - // If the card is quiet, ignore INVENTORY commands - if(instance->state == Iso15693_3ListenerStateQuiet) { - break; - } + data = request->data; + data_size = buf_size - buf_size_min; + } - // Only the INVENTORY command is allowed with this flag set - if(request->command != ISO15693_3_CMD_INVENTORY) { - error = Iso15693_3ErrorUnknown; - break; - } + error = iso15693_3_listener_handle_standard_request( + instance, data, data_size, request->command, request->flags); + + } while(false); - error = iso15693_3_listener_handle_request( - instance, request->data, buf_size - buf_size_min, request->command, request->flags); + return error; +} + +Iso15693_3Error iso15693_3_listener_process_single_eof(Iso15693_3Listener* instance) { + Iso15693_3Error error = Iso15693_3ErrorNone; + + do { + if(!instance->session_state.wait_for_eof) { + error = Iso15693_3ErrorUnexpectedResponse; + break; } + instance->session_state.wait_for_eof = false; + + error = iso15693_3_listener_send_frame(instance, instance->tx_buffer); } while(false); return error; } + +Iso15693_3Error iso15693_3_listener_process_uid_mismatch( + Iso15693_3Listener* instance, + const BitBuffer* rx_buffer) { + Iso15693_3Error error = Iso15693_3ErrorNone; + + // No checks, assuming they have been made beforehand + typedef struct { + uint8_t flags; + uint8_t command; + } Iso15693_3RequestLayout; + + const Iso15693_3RequestLayout* request = + (const Iso15693_3RequestLayout*)bit_buffer_get_data(rx_buffer); + + if(request->command == ISO15693_3_CMD_SELECT) { + if(instance->state == Iso15693_3ListenerStateSelected) { + error = iso15693_3_listener_ready(instance); + } + } + + return error; +} diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3_listener_i.h b/lib/nfc/protocols/iso15693_3/iso15693_3_listener_i.h index e6ecdfb35a1c..a9e0822bff9a 100644 --- a/lib/nfc/protocols/iso15693_3/iso15693_3_listener_i.h +++ b/lib/nfc/protocols/iso15693_3/iso15693_3_listener_i.h @@ -11,23 +11,29 @@ extern "C" { #endif typedef enum { - Iso15693_3ListenerStateIdle, Iso15693_3ListenerStateReady, Iso15693_3ListenerStateSelected, Iso15693_3ListenerStateQuiet, } Iso15693_3ListenerState; typedef struct { + bool selected; + bool addressed; bool wait_for_eof; - bool no_reply; } Iso15693_3ListenerSessionState; +typedef Iso15693_3Error (*Iso15693_3ExtensionHandler)(void* context, va_list args); + +typedef struct { + Iso15693_3ExtensionHandler mandatory[ISO15693_3_MANDATORY_COUNT]; + Iso15693_3ExtensionHandler optional[ISO15693_3_OPTIONAL_COUNT]; +} Iso15693_3ExtensionHandlerTable; + struct Iso15693_3Listener { Nfc* nfc; Iso15693_3Data* data; Iso15693_3ListenerState state; Iso15693_3ListenerSessionState session_state; - BitBuffer* tx_buffer; NfcGenericEvent generic_event; @@ -35,11 +41,17 @@ struct Iso15693_3Listener { Iso15693_3ListenerEventData iso15693_3_event_data; NfcGenericCallback callback; void* context; + + const Iso15693_3ExtensionHandlerTable* extension_table; + void* extension_context; }; -Iso15693_3Error iso15693_3_listener_ready(Iso15693_3Listener* instance); +Iso15693_3Error iso15693_3_listener_set_extension_handler_table( + Iso15693_3Listener* instance, + const Iso15693_3ExtensionHandlerTable* table, + void* context); -Iso15693_3Error iso15693_3_listener_sleep(Iso15693_3Listener* instance); +Iso15693_3Error iso15693_3_listener_ready(Iso15693_3Listener* instance); Iso15693_3Error iso15693_3_listener_send_frame(Iso15693_3Listener* instance, const BitBuffer* tx_buffer); @@ -47,6 +59,12 @@ Iso15693_3Error Iso15693_3Error iso15693_3_listener_process_request(Iso15693_3Listener* instance, const BitBuffer* rx_buffer); +Iso15693_3Error iso15693_3_listener_process_single_eof(Iso15693_3Listener* instance); + +Iso15693_3Error iso15693_3_listener_process_uid_mismatch( + Iso15693_3Listener* instance, + const BitBuffer* rx_buffer); + #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/nfc_device_defs.c b/lib/nfc/protocols/nfc_device_defs.c index e2fa5833f301..6c44601cd256 100644 --- a/lib/nfc/protocols/nfc_device_defs.c +++ b/lib/nfc/protocols/nfc_device_defs.c @@ -5,11 +5,12 @@ #include #include #include -#include +#include #include #include #include #include +#include const NfcDeviceBase* nfc_devices[NfcProtocolNum] = { [NfcProtocolIso14443_3a] = &nfc_device_iso14443_3a, @@ -20,5 +21,6 @@ const NfcDeviceBase* nfc_devices[NfcProtocolNum] = { [NfcProtocolMfUltralight] = &nfc_device_mf_ultralight, [NfcProtocolMfClassic] = &nfc_device_mf_classic, [NfcProtocolMfDesfire] = &nfc_device_mf_desfire, + [NfcProtocolSlix] = &nfc_device_slix, /* Add new protocols here */ }; diff --git a/lib/nfc/protocols/nfc_listener_defs.c b/lib/nfc/protocols/nfc_listener_defs.c index 094757f0832c..d0ccd6bbb8f5 100644 --- a/lib/nfc/protocols/nfc_listener_defs.c +++ b/lib/nfc/protocols/nfc_listener_defs.c @@ -5,6 +5,7 @@ #include #include #include +#include const NfcListenerBase* nfc_listeners_api[NfcProtocolNum] = { [NfcProtocolIso14443_3a] = &nfc_listener_iso14443_3a, @@ -14,4 +15,5 @@ const NfcListenerBase* nfc_listeners_api[NfcProtocolNum] = { [NfcProtocolMfUltralight] = &mf_ultralight_listener, [NfcProtocolMfClassic] = &mf_classic_listener, [NfcProtocolMfDesfire] = NULL, + [NfcProtocolSlix] = &nfc_listener_slix, }; diff --git a/lib/nfc/protocols/nfc_poller_defs.c b/lib/nfc/protocols/nfc_poller_defs.c index b4e64611b6d1..2ad5cdc38311 100644 --- a/lib/nfc/protocols/nfc_poller_defs.c +++ b/lib/nfc/protocols/nfc_poller_defs.c @@ -8,6 +8,7 @@ #include #include #include +#include const NfcPollerBase* nfc_pollers_api[NfcProtocolNum] = { [NfcProtocolIso14443_3a] = &nfc_poller_iso14443_3a, @@ -18,5 +19,6 @@ const NfcPollerBase* nfc_pollers_api[NfcProtocolNum] = { [NfcProtocolMfUltralight] = &mf_ultralight_poller, [NfcProtocolMfClassic] = &mf_classic_poller, [NfcProtocolMfDesfire] = &mf_desfire_poller, + [NfcProtocolSlix] = &nfc_poller_slix, /* Add new pollers here */ }; diff --git a/lib/nfc/protocols/nfc_protocol.c b/lib/nfc/protocols/nfc_protocol.c index f35af7b8e648..80d176aff9cb 100644 --- a/lib/nfc/protocols/nfc_protocol.c +++ b/lib/nfc/protocols/nfc_protocol.c @@ -16,7 +16,7 @@ typedef struct { * | | | | * ISO14443-3A ISO14443-3B Felica ISO15693-3 * | | - * +---------------+-------------+ SLIX2 + * +---------------+-------------+ SLIX * | | | * ISO14443-4A Mf Ultralight Mf Classic * | @@ -35,6 +35,10 @@ static const NfcProtocol nfc_protocol_iso14443_4a_children_protocol[] = { NfcProtocolMfDesfire, }; +static const NfcProtocol nfc_protocol_iso15693_3_children_protocol[] = { + NfcProtocolSlix, +}; + static const NfcProtocolTreeNode nfc_protocol_nodes[NfcProtocolNum] = { [NfcProtocolIso14443_3a] = { @@ -57,8 +61,8 @@ static const NfcProtocolTreeNode nfc_protocol_nodes[NfcProtocolNum] = { [NfcProtocolIso15693_3] = { .parent_protocol = NfcProtocolInvalid, - .children_num = 0, - .children_protocol = NULL, + .children_num = COUNT_OF(nfc_protocol_iso15693_3_children_protocol), + .children_protocol = nfc_protocol_iso15693_3_children_protocol, }, [NfcProtocolFelica] = { @@ -84,6 +88,12 @@ static const NfcProtocolTreeNode nfc_protocol_nodes[NfcProtocolNum] = { .children_num = 0, .children_protocol = NULL, }, + [NfcProtocolSlix] = + { + .parent_protocol = NfcProtocolIso15693_3, + .children_num = 0, + .children_protocol = NULL, + }, }; NfcProtocol nfc_protocol_get_parent(NfcProtocol protocol) { diff --git a/lib/nfc/protocols/nfc_protocol.h b/lib/nfc/protocols/nfc_protocol.h index 814075533626..f54435a81552 100644 --- a/lib/nfc/protocols/nfc_protocol.h +++ b/lib/nfc/protocols/nfc_protocol.h @@ -15,6 +15,7 @@ typedef enum { NfcProtocolMfUltralight, NfcProtocolMfClassic, NfcProtocolMfDesfire, + NfcProtocolSlix, /* Add new protocols here */ NfcProtocolNum, diff --git a/lib/nfc/protocols/slix/slix.c b/lib/nfc/protocols/slix/slix.c new file mode 100644 index 000000000000..12dc6750dd16 --- /dev/null +++ b/lib/nfc/protocols/slix/slix.c @@ -0,0 +1,433 @@ +#include "slix_i.h" +#include "slix_device_defs.h" + +#include +#include + +#define SLIX_PROTOCOL_NAME "SLIX" +#define SLIX_DEVICE_NAME "SLIX" + +#define SLIX_TYPE_SLIX_SLIX2 (0x01U) +#define SLIX_TYPE_SLIX_S (0x02U) +#define SLIX_TYPE_SLIX_L (0x03U) + +#define SLIX_TYPE_INDICATOR_SLIX (0x02U) +#define SLIX_TYPE_INDICATOR_SLIX2 (0x01U) + +#define SLIX_PASSWORD_READ_KEY "Password Read" +#define SLIX_PASSWORD_WRITE_KEY "Password Write" +#define SLIX_PASSWORD_PRIVACY_KEY "Password Privacy" +#define SLIX_PASSWORD_DESTROY_KEY "Password Destroy" +#define SLIX_PASSWORD_EAS_KEY "Password EAS" +#define SLIX_SIGNATURE_KEY "Signature" +#define SLIX_PRIVACY_MODE_KEY "Privacy Mode" +#define SLIX_PROTECTION_POINTER_KEY "Protection Pointer" +#define SLIX_PROTECTION_CONDITION_KEY "Protection Condition" +#define SLIX_LOCK_EAS_KEY "Lock EAS" +#define SLIX_LOCK_PPL_KEY "Lock PPL" + +typedef struct { + uint8_t iso15693_3[2]; + uint8_t icode_type; + union { + struct { + uint8_t unused_1 : 3; + uint8_t type_indicator : 2; + uint8_t unused_2 : 3; + }; + uint8_t serial_num[5]; + }; +} SlixUidLayout; + +const NfcDeviceBase nfc_device_slix = { + .protocol_name = SLIX_PROTOCOL_NAME, + .alloc = (NfcDeviceAlloc)slix_alloc, + .free = (NfcDeviceFree)slix_free, + .reset = (NfcDeviceReset)slix_reset, + .copy = (NfcDeviceCopy)slix_copy, + .verify = (NfcDeviceVerify)slix_verify, + .load = (NfcDeviceLoad)slix_load, + .save = (NfcDeviceSave)slix_save, + .is_equal = (NfcDeviceEqual)slix_is_equal, + .get_name = (NfcDeviceGetName)slix_get_device_name, + .get_uid = (NfcDeviceGetUid)slix_get_uid, + .set_uid = (NfcDeviceSetUid)slix_set_uid, + .get_base_data = (NfcDeviceGetBaseData)slix_get_base_data, +}; + +static const char* slix_nfc_device_name[] = { + [SlixTypeSlix] = SLIX_DEVICE_NAME, + [SlixTypeSlixS] = SLIX_DEVICE_NAME "-S", + [SlixTypeSlixL] = SLIX_DEVICE_NAME "-L", + [SlixTypeSlix2] = SLIX_DEVICE_NAME "2", +}; + +static const SlixTypeFeatures slix_type_features[] = { + [SlixTypeSlix] = SLIX_TYPE_FEATURES_SLIX, + [SlixTypeSlixS] = SLIX_TYPE_FEATURES_SLIX_S, + [SlixTypeSlixL] = SLIX_TYPE_FEATURES_SLIX_L, + [SlixTypeSlix2] = SLIX_TYPE_FEATURES_SLIX2, +}; + +typedef struct { + const char* key; + SlixTypeFeatures feature_flag; + SlixPassword default_value; +} SlixPasswordConfig; + +static const SlixPasswordConfig slix_password_configs[] = { + [SlixPasswordTypeRead] = {SLIX_PASSWORD_READ_KEY, SLIX_TYPE_FEATURE_READ, 0x00000000U}, + [SlixPasswordTypeWrite] = {SLIX_PASSWORD_WRITE_KEY, SLIX_TYPE_FEATURE_WRITE, 0x00000000U}, + [SlixPasswordTypePrivacy] = {SLIX_PASSWORD_PRIVACY_KEY, SLIX_TYPE_FEATURE_PRIVACY, 0xFFFFFFFFU}, + [SlixPasswordTypeDestroy] = {SLIX_PASSWORD_DESTROY_KEY, SLIX_TYPE_FEATURE_DESTROY, 0xFFFFFFFFU}, + [SlixPasswordTypeEasAfi] = {SLIX_PASSWORD_EAS_KEY, SLIX_TYPE_FEATURE_EAS, 0x00000000U}, +}; + +static void slix_password_set_defaults(SlixPassword* passwords) { + for(uint32_t i = 0; i < COUNT_OF(slix_password_configs); ++i) { + passwords[i] = slix_password_configs[i].default_value; + } +} + +SlixData* slix_alloc() { + SlixData* data = malloc(sizeof(SlixData)); + + data->iso15693_3_data = iso15693_3_alloc(); + slix_password_set_defaults(data->passwords); + + return data; +} + +void slix_free(SlixData* data) { + furi_assert(data); + + iso15693_3_free(data->iso15693_3_data); + + free(data); +} + +void slix_reset(SlixData* data) { + furi_assert(data); + + iso15693_3_reset(data->iso15693_3_data); + slix_password_set_defaults(data->passwords); + + memset(&data->system_info, 0, sizeof(SlixSystemInfo)); + memset(data->signature, 0, sizeof(SlixSignature)); + + data->privacy = false; +} + +void slix_copy(SlixData* data, const SlixData* other) { + furi_assert(data); + furi_assert(other); + + iso15693_3_copy(data->iso15693_3_data, other->iso15693_3_data); + + memcpy(data->passwords, other->passwords, sizeof(SlixPassword) * SlixPasswordTypeCount); + memcpy(data->signature, other->signature, sizeof(SlixSignature)); + + data->system_info = other->system_info; + data->privacy = other->privacy; +} + +bool slix_verify(SlixData* data, const FuriString* device_type) { + UNUSED(data); + UNUSED(device_type); + // No backward compatibility, unified format only + return false; +} + +static bool slix_load_passwords(SlixPassword* passwords, SlixType slix_type, FlipperFormat* ff) { + bool ret = true; + + for(uint32_t i = 0; i < COUNT_OF(slix_password_configs); ++i) { + const SlixPasswordConfig* password_config = &slix_password_configs[i]; + + if(!slix_type_has_features(slix_type, password_config->feature_flag)) continue; + if(!flipper_format_key_exist(ff, password_config->key)) { + passwords[i] = password_config->default_value; + continue; + } + if(!flipper_format_read_hex( + ff, password_config->key, (uint8_t*)&passwords[i], sizeof(SlixPassword))) { + ret = false; + break; + } + } + + return ret; +} + +bool slix_load(SlixData* data, FlipperFormat* ff, uint32_t version) { + furi_assert(data); + + bool loaded = false; + + do { + if(!iso15693_3_load(data->iso15693_3_data, ff, version)) break; + + const SlixType slix_type = slix_get_type(data); + if(slix_type >= SlixTypeCount) break; + + if(!slix_load_passwords(data->passwords, slix_type, ff)) break; + + if(slix_type_has_features(slix_type, SLIX_TYPE_FEATURE_SIGNATURE)) { + if(flipper_format_key_exist(ff, SLIX_SIGNATURE_KEY)) { + if(!flipper_format_read_hex( + ff, SLIX_SIGNATURE_KEY, data->signature, SLIX_SIGNATURE_SIZE)) + break; + } + } + + if(slix_type_has_features(slix_type, SLIX_TYPE_FEATURE_PRIVACY)) { + if(flipper_format_key_exist(ff, SLIX_PRIVACY_MODE_KEY)) { + if(!flipper_format_read_bool(ff, SLIX_PRIVACY_MODE_KEY, &data->privacy, 1)) break; + } + } + + if(slix_type_has_features(slix_type, SLIX_TYPE_FEATURE_PROTECTION)) { + SlixProtection* protection = &data->system_info.protection; + if(flipper_format_key_exist(ff, SLIX_PROTECTION_POINTER_KEY) && + flipper_format_key_exist(ff, SLIX_PROTECTION_CONDITION_KEY)) { + if(!flipper_format_read_hex( + ff, SLIX_PROTECTION_POINTER_KEY, &protection->pointer, 1)) + break; + if(!flipper_format_read_hex( + ff, SLIX_PROTECTION_CONDITION_KEY, &protection->condition, 1)) + break; + } + } + + if(slix_type_has_features(slix_type, SLIX_TYPE_FEATURE_EAS)) { + if(flipper_format_key_exist(ff, SLIX_LOCK_EAS_KEY)) { + SlixLockBits* lock_bits = &data->system_info.lock_bits; + if(!flipper_format_read_bool(ff, SLIX_LOCK_EAS_KEY, &lock_bits->eas, 1)) break; + } + } + + if(slix_type_has_features(slix_type, SLIX_TYPE_FEATURE_PROTECTION)) { + if(flipper_format_key_exist(ff, SLIX_LOCK_PPL_KEY)) { + SlixLockBits* lock_bits = &data->system_info.lock_bits; + if(!flipper_format_read_bool(ff, SLIX_LOCK_PPL_KEY, &lock_bits->ppl, 1)) break; + } + } + + loaded = true; + } while(false); + + return loaded; +} + +static bool + slix_save_passwords(const SlixPassword* passwords, SlixType slix_type, FlipperFormat* ff) { + bool ret = true; + + for(uint32_t i = 0; i < COUNT_OF(slix_password_configs); ++i) { + const SlixPasswordConfig* password_config = &slix_password_configs[i]; + + if(!slix_type_has_features(slix_type, password_config->feature_flag)) continue; + if(!flipper_format_write_hex( + ff, password_config->key, (uint8_t*)&passwords[i], sizeof(SlixPassword))) { + ret = false; + break; + } + } + + return ret; +} + +bool slix_save(const SlixData* data, FlipperFormat* ff) { + furi_assert(data); + + bool saved = false; + + do { + const SlixType slix_type = slix_get_type(data); + if(slix_type >= SlixTypeCount) break; + + if(!iso15693_3_save(data->iso15693_3_data, ff)) break; + if(!flipper_format_write_comment_cstr(ff, SLIX_PROTOCOL_NAME " specific data")) break; + + if(!flipper_format_write_comment_cstr( + ff, + "Passwords are optional. If a password is omitted, a default value will be used")) + break; + + if(!slix_save_passwords(data->passwords, slix_type, ff)) break; + + if(slix_type_has_features(slix_type, SLIX_TYPE_FEATURE_SIGNATURE)) { + if(!flipper_format_write_comment_cstr( + ff, + "This is the card's secp128r1 elliptic curve signature. It can not be calculated without knowing NXP's private key.")) + break; + if(!flipper_format_write_hex( + ff, SLIX_SIGNATURE_KEY, data->signature, SLIX_SIGNATURE_SIZE)) + break; + } + + if(slix_type_has_features(slix_type, SLIX_TYPE_FEATURE_PRIVACY)) { + if(!flipper_format_write_bool(ff, SLIX_PRIVACY_MODE_KEY, &data->privacy, 1)) break; + } + + if(slix_type_has_features(slix_type, SLIX_TYPE_FEATURE_PROTECTION)) { + const SlixProtection* protection = &data->system_info.protection; + if(!flipper_format_write_comment_cstr(ff, "Protection pointer configuration")) break; + if(!flipper_format_write_hex( + ff, SLIX_PROTECTION_POINTER_KEY, &protection->pointer, sizeof(uint8_t))) + break; + if(!flipper_format_write_hex( + ff, SLIX_PROTECTION_CONDITION_KEY, &protection->condition, sizeof(uint8_t))) + break; + } + + if(slix_type_has_features(slix_type, SLIX_TYPE_FEATURE_EAS) || + slix_type_has_features(slix_type, SLIX_TYPE_FEATURE_PROTECTION)) { + if(!flipper_format_write_comment_cstr(ff, "SLIX Lock Bits")) break; + } + + if(slix_type_has_features(slix_type, SLIX_TYPE_FEATURE_EAS)) { + const SlixLockBits* lock_bits = &data->system_info.lock_bits; + if(!flipper_format_write_bool(ff, SLIX_LOCK_EAS_KEY, &lock_bits->eas, 1)) break; + } + + if(slix_type_has_features(slix_type, SLIX_TYPE_FEATURE_PROTECTION)) { + const SlixLockBits* lock_bits = &data->system_info.lock_bits; + if(!flipper_format_write_bool(ff, SLIX_LOCK_PPL_KEY, &lock_bits->ppl, 1)) break; + } + + saved = true; + } while(false); + + return saved; +} + +bool slix_is_equal(const SlixData* data, const SlixData* other) { + return iso15693_3_is_equal(data->iso15693_3_data, other->iso15693_3_data) && + memcmp(&data->system_info, &other->system_info, sizeof(SlixSystemInfo)) == 0 && + memcmp( + data->passwords, other->passwords, sizeof(SlixPassword) * SlixPasswordTypeCount) == + 0 && + memcmp(&data->signature, &other->signature, sizeof(SlixSignature)) == 0 && + data->privacy == other->privacy; +} + +const char* slix_get_device_name(const SlixData* data, NfcDeviceNameType name_type) { + UNUSED(name_type); + + const SlixType slix_type = slix_get_type(data); + furi_assert(slix_type < SlixTypeCount); + + return slix_nfc_device_name[slix_type]; +} + +const uint8_t* slix_get_uid(const SlixData* data, size_t* uid_len) { + return iso15693_3_get_uid(data->iso15693_3_data, uid_len); +} + +bool slix_set_uid(SlixData* data, const uint8_t* uid, size_t uid_len) { + furi_assert(data); + + return iso15693_3_set_uid(data->iso15693_3_data, uid, uid_len); +} + +const Iso15693_3Data* slix_get_base_data(const SlixData* data) { + furi_assert(data); + + return data->iso15693_3_data; +} + +SlixType slix_get_type(const SlixData* data) { + SlixType type = SlixTypeCount; + + do { + if(iso15693_3_get_manufacturer_id(data->iso15693_3_data) != SLIX_NXP_MANUFACTURER_CODE) + break; + + const SlixUidLayout* uid = (const SlixUidLayout*)data->iso15693_3_data->uid; + + if(uid->icode_type == SLIX_TYPE_SLIX_SLIX2) { + if(uid->type_indicator == SLIX_TYPE_INDICATOR_SLIX) { + type = SlixTypeSlix; + } else if(uid->type_indicator == SLIX_TYPE_INDICATOR_SLIX2) { + type = SlixTypeSlix2; + } + } else if(uid->icode_type == SLIX_TYPE_SLIX_S) { + type = SlixTypeSlixS; + } else if(uid->icode_type == SLIX_TYPE_SLIX_L) { + type = SlixTypeSlixL; + } + + } while(false); + + return type; +} + +SlixPassword slix_get_password(const SlixData* data, SlixPasswordType password_type) { + furi_assert(data); + furi_assert(password_type < SlixPasswordTypeCount); + + return data->passwords[password_type]; +} + +uint16_t slix_get_counter(const SlixData* data) { + furi_assert(data); + const SlixCounter* counter = (const SlixCounter*)iso15693_3_get_block_data( + data->iso15693_3_data, SLIX_COUNTER_BLOCK_NUM); + + return counter->value; +} + +bool slix_is_privacy_mode(const SlixData* data) { + furi_assert(data); + + return data->privacy; +} + +bool slix_is_block_protected( + const SlixData* data, + SlixPasswordType password_type, + uint8_t block_num) { + furi_assert(data); + furi_assert(password_type < SlixPasswordTypeCount); + + bool ret = false; + + do { + if(password_type != SlixPasswordTypeRead && password_type != SlixPasswordTypeWrite) break; + if(block_num >= iso15693_3_get_block_count(data->iso15693_3_data)) break; + if(block_num == SLIX_COUNTER_BLOCK_NUM) break; + + const bool high = block_num >= data->system_info.protection.pointer; + const bool read = password_type == SlixPasswordTypeRead; + + const uint8_t condition = high ? (read ? SLIX_PP_CONDITION_RH : SLIX_PP_CONDITION_WH) : + (read ? SLIX_PP_CONDITION_RL : SLIX_PP_CONDITION_WL); + + ret = data->system_info.protection.condition & condition; + } while(false); + + return ret; +} + +bool slix_is_counter_increment_protected(const SlixData* data) { + furi_assert(data); + + const SlixCounter* counter = (const SlixCounter*)iso15693_3_get_block_data( + data->iso15693_3_data, SLIX_COUNTER_BLOCK_NUM); + + return counter->protection != 0; +} + +bool slix_type_has_features(SlixType slix_type, SlixTypeFeatures features) { + furi_assert(slix_type < SlixTypeCount); + + return (slix_type_features[slix_type] & features) == features; +} + +bool slix_type_supports_password(SlixType slix_type, SlixPasswordType password_type) { + furi_assert(slix_type < SlixTypeCount); + furi_assert(password_type < SlixPasswordTypeCount); + + return slix_type_features[slix_type] & slix_password_configs[password_type].feature_flag; +} diff --git a/lib/nfc/protocols/slix/slix.h b/lib/nfc/protocols/slix/slix.h new file mode 100644 index 000000000000..f6c1453c5ddd --- /dev/null +++ b/lib/nfc/protocols/slix/slix.h @@ -0,0 +1,146 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define SLIX_BLOCK_SIZE (4U) +#define SLIX_SIGNATURE_SIZE (32U) + +#define SLIX_COUNTER_BLOCK_NUM (79U) + +#define SLIX_PP_CONDITION_RL (1U << 0) +#define SLIX_PP_CONDITION_WL (1U << 1) +#define SLIX_PP_CONDITION_RH (1U << 4) +#define SLIX_PP_CONDITION_WH (1U << 5) + +#define SLIX_FEATURE_FLAG_UM_PP (1UL << 0) +#define SLIX_FEATURE_FLAG_COUNTER (1UL << 1) +#define SLIX_FEATURE_FLAG_EAS_ID (1UL << 2) +#define SLIX_FEATURE_FLAG_EAS_PP (1UL << 3) +#define SLIX_FEATURE_FLAG_AFI_PP (1UL << 4) +#define SLIX_FEATURE_FLAG_INVENTORY_READ_EXT (1UL << 5) +#define SLIX_FEATURE_FLAG_EAS_IR (1UL << 6) +#define SLIX_FEATURE_FLAG_ORIGINALITY_SIG (1UL << 8) +#define SLIX_FEATURE_FLAG_ORIGINALITY_SIG_PP (1UL << 9) +#define SLIX_FEATURE_FLAG_PERSISTENT_QUIET (1UL << 10) +#define SLIX_FEATURE_FLAG_PRIVACY (1UL << 12) +#define SLIX_FEATURE_FLAG_DESTROY (1UL << 13) +#define SLIX_FEATURE_EXT (1UL << 31) + +#define SLIX_TYPE_FEATURE_READ (1U << 0) +#define SLIX_TYPE_FEATURE_WRITE (1U << 1) +#define SLIX_TYPE_FEATURE_PRIVACY (1U << 2) +#define SLIX_TYPE_FEATURE_DESTROY (1U << 3) +#define SLIX_TYPE_FEATURE_EAS (1U << 4) +#define SLIX_TYPE_FEATURE_SIGNATURE (1U << 5) +#define SLIX_TYPE_FEATURE_PROTECTION (1U << 6) + +typedef uint32_t SlixTypeFeatures; + +typedef enum { + SlixErrorNone, + SlixErrorTimeout, + SlixErrorFormat, + SlixErrorNotSupported, + SlixErrorInternal, + SlixErrorWrongPassword, + SlixErrorUidMismatch, + SlixErrorUnknown, +} SlixError; + +typedef enum { + SlixTypeSlix, + SlixTypeSlixS, + SlixTypeSlixL, + SlixTypeSlix2, + SlixTypeCount, +} SlixType; + +typedef enum { + SlixPasswordTypeRead, + SlixPasswordTypeWrite, + SlixPasswordTypePrivacy, + SlixPasswordTypeDestroy, + SlixPasswordTypeEasAfi, + SlixPasswordTypeCount, +} SlixPasswordType; + +typedef uint32_t SlixPassword; +typedef uint8_t SlixSignature[SLIX_SIGNATURE_SIZE]; +typedef bool SlixPrivacy; + +typedef struct { + uint8_t pointer; + uint8_t condition; +} SlixProtection; + +typedef struct { + bool eas; + bool ppl; +} SlixLockBits; + +typedef struct { + SlixProtection protection; + SlixLockBits lock_bits; +} SlixSystemInfo; + +typedef struct { + Iso15693_3Data* iso15693_3_data; + SlixSystemInfo system_info; + SlixSignature signature; + SlixPassword passwords[SlixPasswordTypeCount]; + SlixPrivacy privacy; +} SlixData; + +SlixData* slix_alloc(); + +void slix_free(SlixData* data); + +void slix_reset(SlixData* data); + +void slix_copy(SlixData* data, const SlixData* other); + +bool slix_verify(SlixData* data, const FuriString* device_type); + +bool slix_load(SlixData* data, FlipperFormat* ff, uint32_t version); + +bool slix_save(const SlixData* data, FlipperFormat* ff); + +bool slix_is_equal(const SlixData* data, const SlixData* other); + +const char* slix_get_device_name(const SlixData* data, NfcDeviceNameType name_type); + +const uint8_t* slix_get_uid(const SlixData* data, size_t* uid_len); + +bool slix_set_uid(SlixData* data, const uint8_t* uid, size_t uid_len); + +const Iso15693_3Data* slix_get_base_data(const SlixData* data); + +// Getters and tests + +SlixType slix_get_type(const SlixData* data); + +SlixPassword slix_get_password(const SlixData* data, SlixPasswordType password_type); + +uint16_t slix_get_counter(const SlixData* data); + +bool slix_is_privacy_mode(const SlixData* data); + +bool slix_is_block_protected( + const SlixData* data, + SlixPasswordType password_type, + uint8_t block_num); + +bool slix_is_counter_increment_protected(const SlixData* data); + +// Static methods +bool slix_type_has_features(SlixType slix_type, SlixTypeFeatures features); + +bool slix_type_supports_password(SlixType slix_type, SlixPasswordType password_type); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/slix/slix_device_defs.h b/lib/nfc/protocols/slix/slix_device_defs.h new file mode 100644 index 000000000000..90d826afcb12 --- /dev/null +++ b/lib/nfc/protocols/slix/slix_device_defs.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern const NfcDeviceBase nfc_device_slix; + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/slix/slix_i.c b/lib/nfc/protocols/slix/slix_i.c new file mode 100644 index 000000000000..97d66484c01b --- /dev/null +++ b/lib/nfc/protocols/slix/slix_i.c @@ -0,0 +1,127 @@ +#include "slix_i.h" + +#include + +bool slix_error_response_parse(SlixError* error, const BitBuffer* buf) { + Iso15693_3Error iso15693_3_error; + const bool ret = iso15693_3_error_response_parse(&iso15693_3_error, buf); + + if(ret) { + *error = slix_process_iso15693_3_error(iso15693_3_error); + } + + return ret; +} + +SlixError slix_process_iso15693_3_error(Iso15693_3Error iso15693_3_error) { + switch(iso15693_3_error) { + case Iso15693_3ErrorNone: + return SlixErrorNone; + case Iso15693_3ErrorTimeout: + return SlixErrorTimeout; + case Iso15693_3ErrorFormat: + return SlixErrorFormat; + case Iso15693_3ErrorInternal: + return SlixErrorInternal; + default: + return SlixErrorUnknown; + } +} + +SlixError slix_get_nxp_system_info_response_parse(SlixData* data, const BitBuffer* buf) { + furi_assert(data); + SlixError error = SlixErrorNone; + + do { + if(slix_error_response_parse(&error, buf)) break; + + typedef struct { + uint8_t flags; + uint8_t pp_pointer; + uint8_t pp_condition; + uint8_t lock_bits; + uint32_t feature_flags; + } SlixGetNxpSystemInfoResponseLayout; + + const size_t size_received = bit_buffer_get_size_bytes(buf); + const size_t size_required = sizeof(SlixGetNxpSystemInfoResponseLayout); + + if(size_received != size_required) { + error = SlixErrorFormat; + break; + } + + const SlixGetNxpSystemInfoResponseLayout* response = + (const SlixGetNxpSystemInfoResponseLayout*)bit_buffer_get_data(buf); + + SlixProtection* protection = &data->system_info.protection; + protection->pointer = response->pp_pointer; + protection->condition = response->pp_condition; + + Iso15693_3LockBits* iso15693_3_lock_bits = &data->iso15693_3_data->settings.lock_bits; + iso15693_3_lock_bits->dsfid = response->lock_bits & SLIX_LOCK_BITS_DSFID; + iso15693_3_lock_bits->afi = response->lock_bits & SLIX_LOCK_BITS_AFI; + + SlixLockBits* slix_lock_bits = &data->system_info.lock_bits; + slix_lock_bits->eas = response->lock_bits & SLIX_LOCK_BITS_EAS; + slix_lock_bits->ppl = response->lock_bits & SLIX_LOCK_BITS_PPL; + + } while(false); + + return error; +} + +SlixError slix_read_signature_response_parse(SlixSignature data, const BitBuffer* buf) { + SlixError error = SlixErrorNone; + + do { + if(slix_error_response_parse(&error, buf)) break; + + typedef struct { + uint8_t flags; + uint8_t signature[SLIX_SIGNATURE_SIZE]; + } SlixReadSignatureResponseLayout; + + const size_t size_received = bit_buffer_get_size_bytes(buf); + const size_t size_required = sizeof(SlixReadSignatureResponseLayout); + + if(size_received != size_required) { + error = SlixErrorFormat; + break; + } + + const SlixReadSignatureResponseLayout* response = + (const SlixReadSignatureResponseLayout*)bit_buffer_get_data(buf); + + memcpy(data, response->signature, sizeof(SlixSignature)); + } while(false); + + return error; +} + +void slix_set_password(SlixData* data, SlixPasswordType password_type, SlixPassword password) { + furi_assert(data); + furi_assert(password_type < SlixPasswordTypeCount); + + data->passwords[password_type] = password; +} + +void slix_set_privacy_mode(SlixData* data, bool set) { + furi_assert(data); + + data->privacy = set; +} + +void slix_increment_counter(SlixData* data) { + furi_assert(data); + + const uint8_t* block_data = + iso15693_3_get_block_data(data->iso15693_3_data, SLIX_COUNTER_BLOCK_NUM); + + SlixCounter counter; + memcpy(counter.bytes, block_data, SLIX_BLOCK_SIZE); + counter.value += 1; + + iso15693_3_set_block_data( + data->iso15693_3_data, SLIX_COUNTER_BLOCK_NUM, counter.bytes, sizeof(SlixCounter)); +} diff --git a/lib/nfc/protocols/slix/slix_i.h b/lib/nfc/protocols/slix/slix_i.h new file mode 100644 index 000000000000..b5e445f31d0e --- /dev/null +++ b/lib/nfc/protocols/slix/slix_i.h @@ -0,0 +1,86 @@ +#pragma once + +#include "slix.h" + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define SLIX_NXP_MANUFACTURER_CODE (0x04U) + +#define SLIX_LOCK_BITS_AFI (1U << 0) +#define SLIX_LOCK_BITS_EAS (1U << 1) +#define SLIX_LOCK_BITS_DSFID (1U << 2) +#define SLIX_LOCK_BITS_PPL (1U << 3) + +#define SLIX_CMD_CUSTOM_START (0xA2U) +#define SLIX_CMD_SET_EAS (0xA2U) +#define SLIX_CMD_RESET_EAS (0xA3U) +#define SLIX_CMD_LOCK_EAS (0xA4U) +#define SLIX_CMD_EAS_ALARM (0xA5U) +#define SLIX_CMD_PASSWORD_PROTECT_EAS_AFI (0xA6U) +#define SLIX_CMD_WRITE_EAS_ID (0xA7U) +#define SLIX_CMD_GET_NXP_SYSTEM_INFORMATION (0xABU) +#define SLIX_CMD_INVENTORY_PAGE_READ (0xB0U) +#define SLIX_CMD_INVENTORY_PAGE_READ_FAST (0xB1U) +#define SLIX_CMD_GET_RANDOM_NUMBER (0xB2U) +#define SLIX_CMD_SET_PASSWORD (0xB3U) +#define SLIX_CMD_WRITE_PASSWORD (0xB4U) +#define SLIX_CMD_64_BIT_PASSWORD_PROTECTION (0xB5U) +#define SLIX_CMD_PROTECT_PAGE (0xB6U) +#define SLIX_CMD_LOCK_PAGE_PROTECTION_CONDITION (0xB7U) +#define SLIX_CMD_DESTROY (0xB9U) +#define SLIX_CMD_ENABLE_PRIVACY (0xBAU) +#define SLIX_CMD_STAY_QUIET_PERSISTENT (0xBCU) +#define SLIX_CMD_READ_SIGNATURE (0xBDU) +#define SLIX_CMD_CUSTOM_END (0xBEU) +#define SLIX_CMD_CUSTOM_COUNT (SLIX_CMD_CUSTOM_END - SLIX_CMD_CUSTOM_START) + +#define SLIX_TYPE_FEATURES_SLIX (SLIX_TYPE_FEATURE_EAS) +#define SLIX_TYPE_FEATURES_SLIX_S \ + (SLIX_TYPE_FEATURE_READ | SLIX_TYPE_FEATURE_WRITE | SLIX_TYPE_FEATURE_PRIVACY | \ + SLIX_TYPE_FEATURE_DESTROY | SLIX_TYPE_FEATURE_EAS) +#define SLIX_TYPE_FEATURES_SLIX_L \ + (SLIX_TYPE_FEATURE_PRIVACY | SLIX_TYPE_FEATURE_DESTROY | SLIX_TYPE_FEATURE_EAS) +#define SLIX_TYPE_FEATURES_SLIX2 \ + (SLIX_TYPE_FEATURE_READ | SLIX_TYPE_FEATURE_WRITE | SLIX_TYPE_FEATURE_PRIVACY | \ + SLIX_TYPE_FEATURE_DESTROY | SLIX_TYPE_FEATURE_EAS | SLIX_TYPE_FEATURE_SIGNATURE | \ + SLIX_TYPE_FEATURE_PROTECTION) + +#define SLIX2_FEATURE_FLAGS \ + (SLIX_FEATURE_FLAG_UM_PP | SLIX_FEATURE_FLAG_COUNTER | SLIX_FEATURE_FLAG_EAS_ID | \ + SLIX_FEATURE_FLAG_EAS_PP | SLIX_FEATURE_FLAG_AFI_PP | SLIX_FEATURE_FLAG_INVENTORY_READ_EXT | \ + SLIX_FEATURE_FLAG_EAS_IR | SLIX_FEATURE_FLAG_ORIGINALITY_SIG | \ + SLIX_FEATURE_FLAG_PERSISTENT_QUIET | SLIX_FEATURE_FLAG_PRIVACY | SLIX_FEATURE_FLAG_DESTROY) + +typedef union { + struct { + uint16_t value; + uint8_t reserved; + uint8_t protection; + }; + uint8_t bytes[SLIX_BLOCK_SIZE]; +} SlixCounter; + +// Same behaviour as iso15693_3_error_response_parse +bool slix_error_response_parse(SlixError* error, const BitBuffer* buf); + +SlixError slix_process_iso15693_3_error(Iso15693_3Error iso15693_3_error); + +SlixError slix_get_nxp_system_info_response_parse(SlixData* data, const BitBuffer* buf); + +SlixError slix_read_signature_response_parse(SlixSignature data, const BitBuffer* buf); + +// Setters +void slix_set_password(SlixData* data, SlixPasswordType password_type, SlixPassword password); + +void slix_set_privacy_mode(SlixData* data, bool set); + +void slix_increment_counter(SlixData* data); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/slix/slix_listener.c b/lib/nfc/protocols/slix/slix_listener.c new file mode 100644 index 000000000000..f65892deea6b --- /dev/null +++ b/lib/nfc/protocols/slix/slix_listener.c @@ -0,0 +1,79 @@ +#include "slix_listener_i.h" + +#include +#include + +#define TAG "SlixListener" + +#define SLIX_LISTENER_BUF_SIZE (64U) + +static SlixListener* slix_listener_alloc(Iso15693_3Listener* iso15693_3_listener, SlixData* data) { + furi_assert(iso15693_3_listener); + + SlixListener* instance = malloc(sizeof(SlixListener)); + instance->iso15693_3_listener = iso15693_3_listener; + instance->data = data; + + instance->tx_buffer = bit_buffer_alloc(SLIX_LISTENER_BUF_SIZE); + + instance->slix_event.data = &instance->slix_event_data; + instance->generic_event.protocol = NfcProtocolSlix; + instance->generic_event.instance = instance; + instance->generic_event.data = &instance->slix_event; + + slix_listener_init_iso15693_3_extensions(instance); + + return instance; +} + +static void slix_listener_free(SlixListener* instance) { + furi_assert(instance); + furi_assert(instance->data); + furi_assert(instance->tx_buffer); + + bit_buffer_free(instance->tx_buffer); + free(instance); +} + +static void + slix_listener_set_callback(SlixListener* instance, NfcGenericCallback callback, void* context) { + furi_assert(instance); + + instance->callback = callback; + instance->context = context; +} + +static const SlixData* slix_listener_get_data(SlixListener* instance) { + furi_assert(instance); + furi_assert(instance->data); + + return instance->data; +} + +static NfcCommand slix_listener_run(NfcGenericEvent event, void* context) { + furi_assert(context); + furi_assert(event.protocol == NfcProtocolIso15693_3); + furi_assert(event.data); + + SlixListener* instance = context; + Iso15693_3ListenerEvent* iso15693_3_event = event.data; + BitBuffer* rx_buffer = iso15693_3_event->data->buffer; + NfcCommand command = NfcCommandContinue; + + if(iso15693_3_event->type == Iso15693_3ListenerEventTypeCustomCommand) { + const SlixError error = slix_listener_process_request(instance, rx_buffer); + if(error == SlixErrorWrongPassword) { + command = NfcCommandStop; + } + } + + return command; +} + +const NfcListenerBase nfc_listener_slix = { + .alloc = (NfcListenerAlloc)slix_listener_alloc, + .free = (NfcListenerFree)slix_listener_free, + .set_callback = (NfcListenerSetCallback)slix_listener_set_callback, + .get_data = (NfcListenerGetData)slix_listener_get_data, + .run = (NfcListenerRun)slix_listener_run, +}; diff --git a/lib/nfc/protocols/slix/slix_listener.h b/lib/nfc/protocols/slix/slix_listener.h new file mode 100644 index 000000000000..7b8518a5bb71 --- /dev/null +++ b/lib/nfc/protocols/slix/slix_listener.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +#include "slix.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct SlixListener SlixListener; + +typedef enum { + SlixListenerEventTypeFieldOff, + SlixListenerEventTypeCustomCommand, +} SlixListenerEventType; + +typedef struct { + BitBuffer* buffer; +} SlixListenerEventData; + +typedef struct { + SlixListenerEventType type; + SlixListenerEventData* data; +} SlixListenerEvent; + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/slix/slix_listener_defs.h b/lib/nfc/protocols/slix/slix_listener_defs.h new file mode 100644 index 000000000000..415c284830ca --- /dev/null +++ b/lib/nfc/protocols/slix/slix_listener_defs.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern const NfcListenerBase nfc_listener_slix; + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/slix/slix_listener_i.c b/lib/nfc/protocols/slix/slix_listener_i.c new file mode 100644 index 000000000000..4f075fd3f5df --- /dev/null +++ b/lib/nfc/protocols/slix/slix_listener_i.c @@ -0,0 +1,617 @@ +#include "slix_listener_i.h" + +#include + +#include + +#define TAG "SlixListener" + +typedef SlixError (*SlixRequestHandler)( + SlixListener* instance, + const uint8_t* data, + size_t data_size, + uint8_t flags); + +// Helper functions + +static bool + slix_listener_is_password_lock_enabled(SlixListener* instance, SlixPasswordType password_type) { + return !instance->session_state.password_match[password_type]; +} + +static SlixPasswordType slix_listener_get_password_type_by_id(uint8_t id) { + uint32_t type; + + for(type = 0; type < SlixPasswordTypeCount; ++type) { + if(id >> type == 0x01U) break; + } + + return type; +} + +static SlixPassword + slix_listener_unxor_password(const SlixPassword password_xored, uint16_t random) { + return password_xored ^ ((SlixPassword)random << 16 | random); +} + +static SlixError slix_listener_set_password( + SlixListener* instance, + SlixPasswordType password_type, + SlixPassword password) { + SlixError error = SlixErrorNone; + + do { + if(password_type >= SlixPasswordTypeCount) { + error = SlixErrorInternal; + break; + } + + SlixData* slix_data = instance->data; + + if(!slix_type_supports_password(slix_get_type(slix_data), password_type)) { + error = SlixErrorNotSupported; + break; + } + + SlixListenerSessionState* session_state = &instance->session_state; + session_state->password_match[password_type] = + (password == slix_get_password(slix_data, password_type)); + + if(!session_state->password_match[password_type]) { + error = SlixErrorWrongPassword; + break; + } + } while(false); + + return error; +} + +static SlixError slix_listener_write_password( + SlixListener* instance, + SlixPasswordType password_type, + SlixPassword password) { + SlixError error = SlixErrorNone; + + do { + if(password_type >= SlixPasswordTypeCount) { + error = SlixErrorInternal; + break; + } + + SlixData* slix_data = instance->data; + + if(!slix_type_supports_password(slix_get_type(slix_data), password_type)) { + error = SlixErrorNotSupported; + break; + } + + SlixListenerSessionState* session_state = &instance->session_state; + + if(session_state->password_match[password_type]) { + // TODO: check for password lock + slix_set_password(slix_data, password_type, password); + // Require another SET_PASSWORD command with the new password + session_state->password_match[password_type] = false; + } else { + error = SlixErrorWrongPassword; + break; + } + } while(false); + + return error; +} + +// Custom SLIX request handlers +static SlixError slix_listener_default_handler( + SlixListener* instance, + const uint8_t* data, + size_t data_size, + uint8_t flags) { + UNUSED(instance); + UNUSED(data); + UNUSED(data_size); + UNUSED(flags); + + // Empty placeholder handler + return SlixErrorNotSupported; +} + +static SlixError slix_listener_get_nxp_system_info_handler( + SlixListener* instance, + const uint8_t* data, + size_t data_size, + uint8_t flags) { + UNUSED(data); + UNUSED(data_size); + UNUSED(flags); + + const SlixData* slix_data = instance->data; + const Iso15693_3Data* iso15693_data = instance->data->iso15693_3_data; + + const SlixProtection* protection = &slix_data->system_info.protection; + bit_buffer_append_byte(instance->tx_buffer, protection->pointer); + bit_buffer_append_byte(instance->tx_buffer, protection->condition); + + uint8_t lock_bits = 0; + if(iso15693_data->settings.lock_bits.dsfid) { + lock_bits |= SLIX_LOCK_BITS_DSFID; + } + if(iso15693_data->settings.lock_bits.afi) { + lock_bits |= SLIX_LOCK_BITS_AFI; + } + if(slix_data->system_info.lock_bits.eas) { + lock_bits |= SLIX_LOCK_BITS_EAS; + } + if(slix_data->system_info.lock_bits.ppl) { + lock_bits |= SLIX_LOCK_BITS_PPL; + } + bit_buffer_append_byte(instance->tx_buffer, lock_bits); + + const uint32_t feature_flags = SLIX2_FEATURE_FLAGS; + bit_buffer_append_bytes(instance->tx_buffer, (uint8_t*)&feature_flags, sizeof(uint32_t)); + + return SlixErrorNone; +} + +static SlixError slix_listener_get_random_number_handler( + SlixListener* instance, + const uint8_t* data, + size_t data_size, + uint8_t flags) { + UNUSED(data); + UNUSED(data_size); + UNUSED(flags); + + SlixListenerSessionState* session_state = &instance->session_state; + session_state->random = furi_hal_random_get(); + bit_buffer_append_bytes( + instance->tx_buffer, (uint8_t*)&session_state->random, sizeof(uint16_t)); + + return SlixErrorNone; +} + +static SlixError slix_listener_set_password_handler( + SlixListener* instance, + const uint8_t* data, + size_t data_size, + uint8_t flags) { + UNUSED(flags); + SlixError error = SlixErrorNone; + + do { +#pragma pack(push, 1) + typedef struct { + uint8_t password_id; + SlixPassword password_xored; + } SlixSetPasswordRequestLayout; +#pragma pack(pop) + + if(data_size != sizeof(SlixSetPasswordRequestLayout)) { + error = SlixErrorFormat; + break; + } + + const SlixSetPasswordRequestLayout* request = (const SlixSetPasswordRequestLayout*)data; + const SlixPasswordType password_type = + slix_listener_get_password_type_by_id(request->password_id); + const SlixPassword password_received = + slix_listener_unxor_password(request->password_xored, instance->session_state.random); + + error = slix_listener_set_password(instance, password_type, password_received); + if(error != SlixErrorNone) break; + + if(password_type == SlixPasswordTypePrivacy) { + slix_set_privacy_mode(instance->data, false); + } + } while(false); + + return error; +} + +static SlixError slix_listener_write_password_handler( + SlixListener* instance, + const uint8_t* data, + size_t data_size, + uint8_t flags) { + UNUSED(flags); + SlixError error = SlixErrorNone; + + do { +#pragma pack(push, 1) + typedef struct { + uint8_t password_id; + SlixPassword password; + } SlixWritePasswordRequestLayout; +#pragma pack(pop) + + if(data_size != sizeof(SlixWritePasswordRequestLayout)) { + error = SlixErrorFormat; + break; + } + + const SlixWritePasswordRequestLayout* request = + (const SlixWritePasswordRequestLayout*)data; + const SlixPasswordType password_type = + slix_listener_get_password_type_by_id(request->password_id); + + error = slix_listener_write_password(instance, password_type, request->password); + if(error != SlixErrorNone) break; + + } while(false); + + return error; +} + +static SlixError slix_listener_protect_page_handler( + SlixListener* instance, + const uint8_t* data, + size_t data_size, + uint8_t flags) { + UNUSED(flags); + SlixError error = SlixErrorNone; + + do { + typedef struct { + uint8_t pointer; + uint8_t condition; + } SlixProtectPageRequestLayout; + + if(data_size != sizeof(SlixProtectPageRequestLayout)) { + error = SlixErrorFormat; + break; + } + + SlixData* slix_data = instance->data; + + if(slix_data->system_info.lock_bits.ppl) { + error = SlixErrorInternal; + break; + } + + const SlixListenerSessionState* session_state = &instance->session_state; + if(!session_state->password_match[SlixPasswordTypeRead] || + !session_state->password_match[SlixPasswordTypeWrite]) { + error = SlixErrorInternal; + break; + } + + const SlixProtectPageRequestLayout* request = (const SlixProtectPageRequestLayout*)data; + + if(request->pointer >= SLIX_COUNTER_BLOCK_NUM) { + error = SlixErrorInternal; + break; + } + + SlixProtection* protection = &slix_data->system_info.protection; + + protection->pointer = request->pointer; + protection->condition = request->condition; + } while(false); + + return error; +} + +static SlixError slix_listener_enable_privacy_handler( + SlixListener* instance, + const uint8_t* data, + size_t data_size, + uint8_t flags) { + UNUSED(flags); + SlixError error = SlixErrorNone; + + do { + typedef struct { + SlixPassword password_xored; + } SlixEnablePrivacyRequestLayout; + + if(data_size != sizeof(SlixEnablePrivacyRequestLayout)) { + error = SlixErrorFormat; + break; + } + + const SlixEnablePrivacyRequestLayout* request = + (const SlixEnablePrivacyRequestLayout*)data; + + const SlixPassword password_received = + slix_listener_unxor_password(request->password_xored, instance->session_state.random); + + error = slix_listener_set_password(instance, SlixPasswordTypePrivacy, password_received); + if(error != SlixErrorNone) break; + + slix_set_privacy_mode(instance->data, true); + } while(false); + + return error; +} + +static SlixError slix_listener_read_signature_handler( + SlixListener* instance, + const uint8_t* data, + size_t data_size, + uint8_t flags) { + UNUSED(data); + UNUSED(data_size); + UNUSED(flags); + + bit_buffer_append_bytes(instance->tx_buffer, instance->data->signature, sizeof(SlixSignature)); + return SlixErrorNone; +} + +// Custom SLIX commands handler table +static const SlixRequestHandler slix_request_handler_table[SLIX_CMD_CUSTOM_COUNT] = { + slix_listener_default_handler, // SLIX_CMD_SET_EAS (0xA2U) + slix_listener_default_handler, // SLIX_CMD_RESET_EAS (0xA3U) + slix_listener_default_handler, // SLIX_CMD_LOCK_EAS (0xA4U) + slix_listener_default_handler, // SLIX_CMD_EAS_ALARM (0xA5U) + slix_listener_default_handler, // SLIX_CMD_PASSWORD_PROTECT_EAS_AFI (0xA6U) + slix_listener_default_handler, // SLIX_CMD_WRITE_EAS_ID (0xA7U) + slix_listener_default_handler, // UNUSED (0xA8U) + slix_listener_default_handler, // UNUSED (0xA9U) + slix_listener_default_handler, // UNUSED (0xAAU) + slix_listener_get_nxp_system_info_handler, + slix_listener_default_handler, // UNUSED (0xACU) + slix_listener_default_handler, // UNUSED (0xADU) + slix_listener_default_handler, // UNUSED (0xAEU) + slix_listener_default_handler, // UNUSED (0xAFU) + slix_listener_default_handler, // SLIX_CMD_INVENTORY_PAGE_READ (0xB0U) + slix_listener_default_handler, // SLIX_CMD_INVENTORY_PAGE_READ_FAST (0xB1U) + slix_listener_get_random_number_handler, + slix_listener_set_password_handler, + slix_listener_write_password_handler, + slix_listener_default_handler, // SLIX_CMD_64_BIT_PASSWORD_PROTECTION (0xB5U) + slix_listener_protect_page_handler, + slix_listener_default_handler, // SLIX_CMD_LOCK_PAGE_PROTECTION_CONDITION (0xB7U) + slix_listener_default_handler, // UNUSED (0xB8U) + slix_listener_default_handler, // SLIX_CMD_DESTROY (0xB9U) + slix_listener_enable_privacy_handler, + slix_listener_default_handler, // UNUSED (0xBBU) + slix_listener_default_handler, // SLIX_CMD_STAY_QUIET_PERSISTENT (0xBCU) + slix_listener_read_signature_handler, +}; + +// ISO15693-3 Protocol extension handlers + +static Iso15693_3Error + slix_listener_iso15693_3_inventory_extension_handler(SlixListener* instance, va_list args) { + UNUSED(args); + + return instance->data->privacy ? Iso15693_3ErrorIgnore : Iso15693_3ErrorNone; +} + +static Iso15693_3Error + slix_iso15693_3_read_block_extension_handler(SlixListener* instance, va_list args) { + Iso15693_3Error error = Iso15693_3ErrorNone; + + do { + const uint32_t block_num = va_arg(args, uint32_t); + // SLIX Counter has no read protection + if(block_num == SLIX_COUNTER_BLOCK_NUM) break; + + if(slix_is_block_protected(instance->data, SlixPasswordTypeRead, block_num)) { + if(slix_listener_is_password_lock_enabled(instance, SlixPasswordTypeRead)) { + error = Iso15693_3ErrorInternal; + break; + } + } + } while(false); + + return error; +} + +static Iso15693_3Error + slix_listener_iso15693_3_write_block_extension_handler(SlixListener* instance, va_list args) { + Iso15693_3Error error = Iso15693_3ErrorNone; + + do { + const uint32_t block_num = va_arg(args, uint32_t); + + if(block_num == SLIX_COUNTER_BLOCK_NUM) { + const uint32_t counter = *(va_arg(args, uint32_t*)); + if(counter == 0x00000001U) { + if(slix_is_counter_increment_protected(instance->data) && + slix_listener_is_password_lock_enabled(instance, SlixPasswordTypeRead)) { + error = Iso15693_3ErrorInternal; + break; + } + slix_increment_counter(instance->data); + error = Iso15693_3ErrorFullyHandled; + break; + } + } else if(slix_is_block_protected(instance->data, SlixPasswordTypeRead, block_num)) { + if(slix_listener_is_password_lock_enabled(instance, SlixPasswordTypeRead)) { + error = Iso15693_3ErrorInternal; + break; + } + } + + if(slix_is_block_protected(instance->data, SlixPasswordTypeWrite, block_num)) { + if(slix_listener_is_password_lock_enabled(instance, SlixPasswordTypeWrite)) { + error = Iso15693_3ErrorInternal; + break; + } + } + + } while(false); + + return error; +} + +static Iso15693_3Error + slix_listener_iso15693_3_lock_block_extension_handler(SlixListener* instance, va_list args) { + Iso15693_3Error error = Iso15693_3ErrorNone; + + do { + const uint32_t block_num = va_arg(args, uint32_t); + + // SLIX counter cannot be locked + if(block_num == SLIX_COUNTER_BLOCK_NUM) { + error = Iso15693_3ErrorInternal; + break; + } + + if(slix_is_block_protected(instance->data, SlixPasswordTypeRead, block_num)) { + if(slix_listener_is_password_lock_enabled(instance, SlixPasswordTypeRead)) { + error = Iso15693_3ErrorInternal; + break; + } + } + + if(slix_is_block_protected(instance->data, SlixPasswordTypeWrite, block_num)) { + if(slix_listener_is_password_lock_enabled(instance, SlixPasswordTypeWrite)) { + error = Iso15693_3ErrorInternal; + break; + } + } + + } while(false); + + return error; +} + +static Iso15693_3Error slix_listener_iso15693_3_read_multi_block_extension_handler( + SlixListener* instance, + va_list args) { + Iso15693_3Error error = Iso15693_3ErrorNone; + + const uint32_t block_index_start = va_arg(args, uint32_t); + const uint32_t block_index_end = va_arg(args, uint32_t); + + for(uint32_t i = block_index_start; i <= block_index_end; ++i) { + // SLIX Counter has no read protection + if(i == SLIX_COUNTER_BLOCK_NUM) continue; + + if(slix_is_block_protected(instance->data, SlixPasswordTypeRead, i)) { + if(slix_listener_is_password_lock_enabled(instance, SlixPasswordTypeRead)) { + error = Iso15693_3ErrorInternal; + break; + } + } + } + + return error; +} + +static Iso15693_3Error slix_listener_iso15693_3_write_multi_block_extension_handler( + SlixListener* instance, + va_list args) { + UNUSED(instance); + UNUSED(args); + // No mention of this command in SLIX docs, assuming not supported + return Iso15693_3ErrorNotSupported; +} + +static Iso15693_3Error slix_listener_iso15693_3_write_lock_afi_extension_handler( + SlixListener* instance, + va_list args) { + UNUSED(args); + + return slix_listener_is_password_lock_enabled(instance, SlixPasswordTypeEasAfi) ? + Iso15693_3ErrorInternal : + Iso15693_3ErrorNone; +} + +// Extended ISO15693-3 standard commands handler table (NULL = no extension) +static const Iso15693_3ExtensionHandlerTable slix_iso15693_extension_handler_table = { + .mandatory = + { + (Iso15693_3ExtensionHandler)slix_listener_iso15693_3_inventory_extension_handler, + (Iso15693_3ExtensionHandler)NULL // ISO15693_3_CMD_STAY_QUIET (0x02U) + }, + .optional = + { + (Iso15693_3ExtensionHandler)slix_iso15693_3_read_block_extension_handler, + (Iso15693_3ExtensionHandler)slix_listener_iso15693_3_write_block_extension_handler, + (Iso15693_3ExtensionHandler)slix_listener_iso15693_3_lock_block_extension_handler, + (Iso15693_3ExtensionHandler)slix_listener_iso15693_3_read_multi_block_extension_handler, + (Iso15693_3ExtensionHandler) + slix_listener_iso15693_3_write_multi_block_extension_handler, + (Iso15693_3ExtensionHandler)NULL, // ISO15693_3_CMD_SELECT (0x25U) + (Iso15693_3ExtensionHandler)NULL, // ISO15693_3_CMD_RESET_TO_READY (0x26U) + (Iso15693_3ExtensionHandler)slix_listener_iso15693_3_write_lock_afi_extension_handler, + (Iso15693_3ExtensionHandler)slix_listener_iso15693_3_write_lock_afi_extension_handler, + (Iso15693_3ExtensionHandler)NULL, // ISO15693_3_CMD_WRITE_DSFID (0x29U) + (Iso15693_3ExtensionHandler)NULL, // ISO15693_3_CMD_LOCK_DSFID (0x2AU) + (Iso15693_3ExtensionHandler)NULL, // ISO15693_3_CMD_GET_SYS_INFO (0x2BU) + (Iso15693_3ExtensionHandler)NULL, // ISO15693_3_CMD_GET_BLOCKS_SECURITY (0x2CU) + }, +}; + +SlixError slix_listener_init_iso15693_3_extensions(SlixListener* instance) { + iso15693_3_listener_set_extension_handler_table( + instance->iso15693_3_listener, &slix_iso15693_extension_handler_table, instance); + return SlixErrorNone; +} + +SlixError slix_listener_process_request(SlixListener* instance, const BitBuffer* rx_buffer) { + SlixError error = SlixErrorNone; + + do { + typedef struct { + uint8_t flags; + uint8_t command; + uint8_t manufacturer; + uint8_t data[]; + } SlixRequestLayout; + + const size_t buf_size = bit_buffer_get_size_bytes(rx_buffer); + + if(buf_size < sizeof(SlixRequestLayout)) { + error = SlixErrorFormat; + break; + } + + const SlixRequestLayout* request = + (const SlixRequestLayout*)bit_buffer_get_data(rx_buffer); + + const bool addressed_mode = instance->iso15693_3_listener->session_state.addressed; + + const size_t uid_field_size = addressed_mode ? ISO15693_3_UID_SIZE : 0; + const size_t buf_size_min = sizeof(SlixRequestLayout) + uid_field_size; + + if(buf_size < buf_size_min) { + error = SlixErrorFormat; + break; + } + + if(addressed_mode) { + if(!iso15693_3_is_equal_uid(instance->data->iso15693_3_data, request->data)) { + error = SlixErrorUidMismatch; + break; + } + } + + const uint8_t command = request->command; + const bool is_valid_slix_command = command >= SLIX_CMD_CUSTOM_START && + command < SLIX_CMD_CUSTOM_END; + if(!is_valid_slix_command) { + error = SlixErrorNotSupported; + break; + } + + bit_buffer_reset(instance->tx_buffer); + bit_buffer_append_byte(instance->tx_buffer, ISO15693_3_RESP_FLAG_NONE); + + const uint8_t* request_data = &request->data[uid_field_size]; + const size_t request_data_size = buf_size - buf_size_min; + + SlixRequestHandler handler = slix_request_handler_table[command - SLIX_CMD_CUSTOM_START]; + error = handler(instance, request_data, request_data_size, request->flags); + + // It's a trick! Send no reply. + if(error == SlixErrorFormat || error == SlixErrorWrongPassword || + error == SlixErrorNotSupported) + break; + + if(error != SlixErrorNone) { + bit_buffer_reset(instance->tx_buffer); + bit_buffer_append_byte(instance->tx_buffer, ISO15693_3_RESP_FLAG_ERROR); + bit_buffer_append_byte(instance->tx_buffer, ISO15693_3_RESP_ERROR_UNKNOWN); + } + + const Iso15693_3Error iso15693_error = + iso15693_3_listener_send_frame(instance->iso15693_3_listener, instance->tx_buffer); + error = slix_process_iso15693_3_error(iso15693_error); + } while(false); + + return error; +} diff --git a/lib/nfc/protocols/slix/slix_listener_i.h b/lib/nfc/protocols/slix/slix_listener_i.h new file mode 100644 index 000000000000..ce059c5a675e --- /dev/null +++ b/lib/nfc/protocols/slix/slix_listener_i.h @@ -0,0 +1,37 @@ +#pragma once + +#include + +#include "slix_listener.h" +#include "slix_i.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + uint16_t random; + bool password_match[SlixPasswordTypeCount]; +} SlixListenerSessionState; + +struct SlixListener { + Iso15693_3Listener* iso15693_3_listener; + SlixData* data; + SlixListenerSessionState session_state; + + BitBuffer* tx_buffer; + + NfcGenericEvent generic_event; + SlixListenerEvent slix_event; + SlixListenerEventData slix_event_data; + NfcGenericCallback callback; + void* context; +}; + +SlixError slix_listener_init_iso15693_3_extensions(SlixListener* instance); + +SlixError slix_listener_process_request(SlixListener* instance, const BitBuffer* rx_buffer); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/slix/slix_poller.c b/lib/nfc/protocols/slix/slix_poller.c new file mode 100644 index 000000000000..8950fe303c4e --- /dev/null +++ b/lib/nfc/protocols/slix/slix_poller.c @@ -0,0 +1,154 @@ +#include "slix_poller_i.h" + +#include + +#include + +#define TAG "SlixPoller" + +#define SLIX_POLLER_BUF_SIZE (64U) + +typedef NfcCommand (*SlixPollerStateHandler)(SlixPoller* instance); + +const SlixData* slix_poller_get_data(SlixPoller* instance) { + furi_assert(instance); + + return instance->data; +} + +static SlixPoller* slix_poller_alloc(Iso15693_3Poller* iso15693_3_poller) { + SlixPoller* instance = malloc(sizeof(SlixPoller)); + instance->iso15693_3_poller = iso15693_3_poller; + instance->data = slix_alloc(); + instance->tx_buffer = bit_buffer_alloc(SLIX_POLLER_BUF_SIZE); + instance->rx_buffer = bit_buffer_alloc(SLIX_POLLER_BUF_SIZE); + + instance->slix_event.data = &instance->slix_event_data; + + instance->general_event.protocol = NfcProtocolSlix; + instance->general_event.data = &instance->slix_event; + instance->general_event.instance = instance; + + return instance; +} + +static void slix_poller_free(SlixPoller* instance) { + furi_assert(instance); + + slix_free(instance->data); + bit_buffer_free(instance->tx_buffer); + bit_buffer_free(instance->rx_buffer); + free(instance); +} + +static NfcCommand slix_poller_handler_idle(SlixPoller* instance) { + iso15693_3_copy( + instance->data->iso15693_3_data, iso15693_3_poller_get_data(instance->iso15693_3_poller)); + + instance->poller_state = SlixPollerStateGetNxpSysInfo; + return NfcCommandContinue; +} + +static NfcCommand slix_poller_handler_get_nfc_system_info(SlixPoller* instance) { + instance->error = + slix_poller_async_get_nxp_system_info(instance, &instance->data->system_info); + if(instance->error == SlixErrorNone) { + instance->poller_state = SlixPollerStateReadSignature; + } else { + instance->poller_state = SlixPollerStateError; + } + + return NfcCommandContinue; +} + +static NfcCommand slix_poller_handler_read_signature(SlixPoller* instance) { + instance->error = slix_poller_async_read_signature(instance, &instance->data->signature); + if(instance->error == SlixErrorNone) { + instance->poller_state = SlixPollerStateReady; + } else { + instance->poller_state = SlixPollerStateError; + } + + return NfcCommandContinue; +} + +static NfcCommand slix_poller_handler_error(SlixPoller* instance) { + instance->slix_event_data.error = instance->error; + NfcCommand command = instance->callback(instance->general_event, instance->context); + instance->poller_state = SlixPollerStateIdle; + return command; +} + +static NfcCommand slix_poller_handler_ready(SlixPoller* instance) { + instance->slix_event.type = SlixPollerEventTypeReady; + NfcCommand command = instance->callback(instance->general_event, instance->context); + return command; +} + +static const SlixPollerStateHandler slix_poller_state_handler[SlixPollerStateNum] = { + [SlixPollerStateIdle] = slix_poller_handler_idle, + [SlixPollerStateError] = slix_poller_handler_error, + [SlixPollerStateGetNxpSysInfo] = slix_poller_handler_get_nfc_system_info, + [SlixPollerStateReadSignature] = slix_poller_handler_read_signature, + [SlixPollerStateReady] = slix_poller_handler_ready, +}; + +static void + slix_poller_set_callback(SlixPoller* instance, NfcGenericCallback callback, void* context) { + furi_assert(instance); + furi_assert(callback); + + instance->callback = callback; + instance->context = context; +} + +static NfcCommand slix_poller_run(NfcGenericEvent event, void* context) { + furi_assert(event.protocol == NfcProtocolIso15693_3); + + SlixPoller* instance = context; + furi_assert(instance); + furi_assert(instance->callback); + + Iso15693_3PollerEvent* iso15693_3_event = event.data; + furi_assert(iso15693_3_event); + + NfcCommand command = NfcCommandContinue; + + if(iso15693_3_event->type == Iso15693_3PollerEventTypeReady) { + command = slix_poller_state_handler[instance->poller_state](instance); + } else if(iso15693_3_event->type == Iso15693_3PollerEventTypeError) { + instance->slix_event.type = SlixPollerEventTypeError; + command = instance->callback(instance->general_event, instance->context); + } + + return command; +} + +static bool slix_poller_detect(NfcGenericEvent event, void* context) { + furi_assert(event.protocol == NfcProtocolIso15693_3); + + const SlixPoller* instance = context; + furi_assert(instance); + + const Iso15693_3PollerEvent* iso15693_3_event = event.data; + furi_assert(iso15693_3_event); + iso15693_3_copy( + instance->data->iso15693_3_data, iso15693_3_poller_get_data(instance->iso15693_3_poller)); + + bool protocol_detected = false; + + if(iso15693_3_event->type == Iso15693_3PollerEventTypeReady) { + protocol_detected = slix_get_type(instance->data) < SlixTypeCount; + } + + return protocol_detected; +} + +const NfcPollerBase nfc_poller_slix = { + .alloc = (NfcPollerAlloc)slix_poller_alloc, + .free = (NfcPollerFree)slix_poller_free, + .set_callback = (NfcPollerSetCallback)slix_poller_set_callback, + .run = (NfcPollerRun)slix_poller_run, + .detect = (NfcPollerDetect)slix_poller_detect, + .get_data = (NfcPollerGetData)slix_poller_get_data, +}; diff --git a/lib/nfc/protocols/slix/slix_poller.h b/lib/nfc/protocols/slix/slix_poller.h new file mode 100644 index 000000000000..f4c7214de4f5 --- /dev/null +++ b/lib/nfc/protocols/slix/slix_poller.h @@ -0,0 +1,29 @@ +#pragma once + +#include "slix.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct SlixPoller SlixPoller; + +typedef enum { + SlixPollerEventTypeError, + SlixPollerEventTypeReady, +} SlixPollerEventType; + +typedef struct { + SlixError error; +} SlixPollerEventData; + +typedef struct { + SlixPollerEventType type; + SlixPollerEventData* data; +} SlixPollerEvent; + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/slix/slix_poller_defs.h b/lib/nfc/protocols/slix/slix_poller_defs.h new file mode 100644 index 000000000000..f619ad179d5d --- /dev/null +++ b/lib/nfc/protocols/slix/slix_poller_defs.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern const NfcPollerBase nfc_poller_slix; + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/slix/slix_poller_i.c b/lib/nfc/protocols/slix/slix_poller_i.c new file mode 100644 index 000000000000..a36e7694a4f3 --- /dev/null +++ b/lib/nfc/protocols/slix/slix_poller_i.c @@ -0,0 +1,69 @@ +#include "slix_poller_i.h" + +#include + +#include "slix_i.h" + +#define TAG "SlixPoller" + +static void slix_poller_prepare_request(SlixPoller* instance, uint8_t command) { + bit_buffer_reset(instance->tx_buffer); + bit_buffer_reset(instance->rx_buffer); + + bit_buffer_append_byte( + instance->tx_buffer, + ISO15693_3_REQ_FLAG_SUBCARRIER_1 | ISO15693_3_REQ_FLAG_DATA_RATE_HI | + ISO15693_3_REQ_FLAG_T4_ADDRESSED); + bit_buffer_append_byte(instance->tx_buffer, command); + bit_buffer_append_byte(instance->tx_buffer, SLIX_NXP_MANUFACTURER_CODE); + + iso15693_3_append_uid(instance->data->iso15693_3_data, instance->tx_buffer); +} + +SlixError slix_poller_send_frame( + SlixPoller* instance, + const BitBuffer* tx_buffer, + BitBuffer* rx_buffer, + uint32_t fwt) { + furi_assert(instance); + + const Iso15693_3Error iso15693_3_error = + iso15693_3_poller_send_frame(instance->iso15693_3_poller, tx_buffer, rx_buffer, fwt); + return slix_process_iso15693_3_error(iso15693_3_error); +} + +SlixError slix_poller_async_get_nxp_system_info(SlixPoller* instance, SlixSystemInfo* data) { + furi_assert(instance); + furi_assert(data); + + slix_poller_prepare_request(instance, SLIX_CMD_GET_NXP_SYSTEM_INFORMATION); + + SlixError error = SlixErrorNone; + + do { + error = slix_poller_send_frame( + instance, instance->tx_buffer, instance->rx_buffer, ISO15693_3_FDT_POLL_FC); + if(error != SlixErrorNone) break; + error = slix_get_nxp_system_info_response_parse(instance->data, instance->rx_buffer); + } while(false); + + return error; +} + +SlixError slix_poller_async_read_signature(SlixPoller* instance, SlixSignature* data) { + furi_assert(instance); + furi_assert(data); + + slix_poller_prepare_request(instance, SLIX_CMD_READ_SIGNATURE); + + SlixError error = SlixErrorNone; + + do { + error = slix_poller_send_frame( + instance, instance->tx_buffer, instance->rx_buffer, ISO15693_3_FDT_POLL_FC * 2); + if(error != SlixErrorNone) break; + error = slix_read_signature_response_parse(instance->data->signature, instance->rx_buffer); + } while(false); + + return error; +} diff --git a/lib/nfc/protocols/slix/slix_poller_i.h b/lib/nfc/protocols/slix/slix_poller_i.h new file mode 100644 index 000000000000..c6a8a3c33efa --- /dev/null +++ b/lib/nfc/protocols/slix/slix_poller_i.h @@ -0,0 +1,48 @@ +#pragma once + +#include + +#include "slix_poller.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + SlixPollerStateIdle, + SlixPollerStateGetNxpSysInfo, + SlixPollerStateReadSignature, + SlixPollerStateReady, + SlixPollerStateError, + SlixPollerStateNum, +} SlixPollerState; + +struct SlixPoller { + Iso15693_3Poller* iso15693_3_poller; + SlixData* data; + SlixPollerState poller_state; + SlixError error; + + BitBuffer* tx_buffer; + BitBuffer* rx_buffer; + + SlixPollerEventData slix_event_data; + SlixPollerEvent slix_event; + NfcGenericEvent general_event; + NfcGenericCallback callback; + void* context; +}; + +SlixError slix_poller_send_frame( + SlixPoller* instance, + const BitBuffer* tx_data, + BitBuffer* rx_data, + uint32_t fwt); + +SlixError slix_poller_async_get_nxp_system_info(SlixPoller* instance, SlixSystemInfo* data); + +SlixError slix_poller_async_read_signature(SlixPoller* instance, SlixSignature* data); + +#ifdef __cplusplus +} +#endif diff --git a/lib/signal_reader/parsers/iso15693/iso15693_parser.c b/lib/signal_reader/parsers/iso15693/iso15693_parser.c index 6fbe91a4c22d..4021e4ef98bf 100644 --- a/lib/signal_reader/parsers/iso15693/iso15693_parser.c +++ b/lib/signal_reader/parsers/iso15693/iso15693_parser.c @@ -13,6 +13,7 @@ typedef enum { Iso15693ParserStateParseSoF, Iso15693ParserStateParseFrame, + Iso15693ParserStateFail, } Iso15693ParserState; typedef enum { @@ -129,6 +130,10 @@ static void signal_reader_callback(SignalReaderEvent event, void* context) { } else if(event.data->data[0] == eof_single) { instance->eof_received = true; instance->callback(Iso15693ParserEventDataReceived, instance->context); + } else { + // TODO: Better garbage input handling + instance->state = Iso15693ParserStateFail; + instance->callback(Iso15693ParserEventDataReceived, instance->context); } } else { if(instance->mode == Iso15693ParserMode1OutOf4) { @@ -255,7 +260,10 @@ static const Iso15693ParserStateHandler iso15693_parser_state_handlers[Iso15693P }; bool iso15693_parser_run(Iso15693Parser* instance) { - if((instance->state == Iso15693ParserStateParseSoF) && (instance->eof_received)) { + if(instance->state == Iso15693ParserStateFail) { + iso15693_parser_stop(instance); + iso15693_parser_start_signal_reader(instance); + } else if((instance->state == Iso15693ParserStateParseSoF) && (instance->eof_received)) { instance->frame_parsed = true; } else if(instance->bytes_to_process) { Iso15693ParserCommand command = Iso15693ParserCommandProcessed; @@ -264,9 +272,9 @@ bool iso15693_parser_run(Iso15693Parser* instance) { } if(command == Iso15693ParserCommandFail) { - FURI_LOG_D(TAG, "Frame parse failed"); iso15693_parser_stop(instance); iso15693_parser_start_signal_reader(instance); + FURI_LOG_D(TAG, "Frame parse failed"); } } From de0ed43df82f86660aa8ec3820b8bd386381bbdb Mon Sep 17 00:00:00 2001 From: gornekich Date: Thu, 7 Sep 2023 13:43:09 +0400 Subject: [PATCH 149/149] [FL-3572] Nfc API cleanup (#3049) * nfc hal: remove unused functions * nfc: remove nfc_sleep from public API * nfc: rename technology specific API * nfc hal: move col res disable to nfca specific hal * nfc: store mode in nfc instance * nfc: common start and stop * nfc hal: deinit iso14443a poller * nfc app: fix detect reader craches * mf classic: change detect algorythm * nfc hal: make sleep virtual * nfc: make it compile * nfc: introduce NfcSleep command * nfc: fix naming * nfc: check nfc hal mutex --- .../debug/unit_tests/nfc/nfc_transport.c | 33 ++- .../protocol_support/mf_classic/mf_classic.c | 2 +- .../nfc_scene_mf_classic_detect_reader.c | 7 +- .../nfc_scene_mf_classic_mfkey_complete.c | 2 +- firmware/targets/f18/api_symbols.csv | 2 +- firmware/targets/f7/api_symbols.csv | 43 ++-- firmware/targets/f7/furi_hal/f_hal_nfc.c | 81 +------ .../targets/f7/furi_hal/f_hal_nfc_event.c | 2 +- firmware/targets/f7/furi_hal/f_hal_nfc_i.h | 5 +- .../targets/f7/furi_hal/f_hal_nfc_iso14443a.c | 101 +++++++-- .../targets/f7/furi_hal/f_hal_nfc_iso15693.c | 14 +- .../targets/f7/furi_hal/f_hal_nfc_timer.c | 1 + firmware/targets/furi_hal_include/f_hal_nfc.h | 33 ++- lib/nfc/nfc.c | 198 ++++++++---------- lib/nfc/nfc.h | 69 +++--- lib/nfc/nfc_listener.c | 4 +- lib/nfc/nfc_poller.c | 4 +- lib/nfc/protocols/felica/felica_poller.c | 2 +- lib/nfc/protocols/felica/felica_poller_i.c | 3 +- .../iso14443_3a/iso14443_3a_listener.c | 8 +- .../iso14443_3a/iso14443_3a_listener_i.c | 2 +- .../iso14443_3a/iso14443_3a_poller.c | 2 +- .../iso14443_3a/iso14443_3a_poller_i.c | 13 +- .../iso14443_3b/iso14443_3b_poller.c | 2 +- .../iso14443_3b/iso14443_3b_poller_i.c | 3 +- .../iso15693_3/iso15693_3_listener.c | 2 +- .../protocols/iso15693_3/iso15693_3_poller.c | 2 +- .../iso15693_3/iso15693_3_poller_i.c | 3 +- .../mf_classic/mf_classic_listener.c | 6 +- .../mf_classic/mf_classic_listener_i.h | 1 + .../protocols/mf_classic/mf_classic_poller.c | 21 +- .../mf_classic/mf_classic_poller_i.c | 2 - .../mf_classic/mf_classic_poller_i.h | 2 + .../mf_ultralight/mf_ultralight_listener.c | 6 +- 34 files changed, 335 insertions(+), 346 deletions(-) diff --git a/applications/debug/unit_tests/nfc/nfc_transport.c b/applications/debug/unit_tests/nfc/nfc_transport.c index c91c8b95873b..c0201483bcd2 100644 --- a/applications/debug/unit_tests/nfc/nfc_transport.c +++ b/applications/debug/unit_tests/nfc/nfc_transport.c @@ -125,9 +125,10 @@ void nfc_free(Nfc* instance) { free(instance); } -void nfc_config(Nfc* instance, NfcMode mode) { +void nfc_config(Nfc* instance, NfcMode mode, NfcTech tech) { UNUSED(instance); UNUSED(mode); + UNUSED(tech); } void nfc_set_fdt_poll_fc(Nfc* instance, uint32_t fdt_poll_fc) { @@ -155,7 +156,7 @@ void nfc_set_guard_time_us(Nfc* instance, uint32_t guard_time_us) { UNUSED(guard_time_us); } -NfcError nfc_listener_set_col_res_data( +NfcError nfc_iso14443a_listener_set_col_res_data( Nfc* instance, uint8_t* uid, uint8_t uid_len, @@ -334,17 +335,6 @@ void nfc_start_listener(Nfc* instance, NfcEventCallback callback, void* context) furi_thread_start(instance->worker_thread); } -NfcError nfc_listener_reset(Nfc* instance) { - furi_assert(instance); - furi_assert(poller_queue); - - instance->col_res_status = Iso14443_3aColResStatusIdle; - NfcMessage message = {.type = NfcMessageTypeTimeout}; - furi_message_queue_put(poller_queue, &message, FuriWaitForever); - - return NfcErrorNone; -} - void nfc_listener_abort(Nfc* instance) { furi_assert(instance); @@ -391,11 +381,12 @@ NfcError nfc_listener_tx(Nfc* instance, const BitBuffer* tx_buffer) { return NfcErrorNone; } -NfcError nfc_iso14443_3a_listener_tx_custom_parity(Nfc* instance, const BitBuffer* tx_buffer) { +NfcError nfc_iso14443a_listener_tx_custom_parity(Nfc* instance, const BitBuffer* tx_buffer) { return nfc_listener_tx(instance, tx_buffer); } -NfcError nfc_trx(Nfc* instance, const BitBuffer* tx_buffer, BitBuffer* rx_buffer, uint32_t fwt) { +NfcError + nfc_poller_trx(Nfc* instance, const BitBuffer* tx_buffer, BitBuffer* rx_buffer, uint32_t fwt) { furi_assert(instance); furi_assert(tx_buffer); furi_assert(rx_buffer); @@ -427,17 +418,17 @@ NfcError nfc_trx(Nfc* instance, const BitBuffer* tx_buffer, BitBuffer* rx_buffer return error; } -NfcError nfc_trx_custom_parity( +NfcError nfc_iso14443a_poller_trx_custom_parity( Nfc* instance, const BitBuffer* tx_buffer, BitBuffer* rx_buffer, uint32_t fwt) { - return nfc_trx(instance, tx_buffer, rx_buffer, fwt); + return nfc_poller_trx(instance, tx_buffer, rx_buffer, fwt); } // Technology specific API -NfcError nfc_iso14443_3a_short_frame( +NfcError nfc_iso14443a_poller_trx_short_frame( Nfc* instance, NfcIso14443aShortFrame frame, BitBuffer* rx_buffer, @@ -448,19 +439,19 @@ NfcError nfc_iso14443_3a_short_frame( bit_buffer_set_size(tx_buffer, 7); bit_buffer_set_byte(tx_buffer, 0, 0x52); - NfcError error = nfc_trx(instance, tx_buffer, rx_buffer, fwt); + NfcError error = nfc_poller_trx(instance, tx_buffer, rx_buffer, fwt); bit_buffer_free(tx_buffer); return error; } -NfcError nfc_iso14443_3a_sdd_frame( +NfcError nfc_iso14443a_poller_trx_sdd_frame( Nfc* instance, const BitBuffer* tx_buffer, BitBuffer* rx_buffer, uint32_t fwt) { - return nfc_trx(instance, tx_buffer, rx_buffer, fwt); + return nfc_poller_trx(instance, tx_buffer, rx_buffer, fwt); } #endif diff --git a/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c b/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c index feef09e5340c..7665ec6b9876 100644 --- a/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c +++ b/applications/main/nfc/helpers/protocol_support/mf_classic/mf_classic.c @@ -177,7 +177,7 @@ static bool nfc_scene_info_on_event_mf_classic(NfcApp* instance, uint32_t event) static bool nfc_scene_read_menu_on_event_mf_classic(NfcApp* instance, uint32_t event) { if(event == SubmenuIndexDetectReader) { - scene_manager_next_scene(instance->scene_manager, NfcSceneNotImplemented); + scene_manager_next_scene(instance->scene_manager, NfcSceneMfClassicDetectReader); dolphin_deed(DolphinDeedNfcDetectReader); return true; } diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_detect_reader.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_detect_reader.c index cc0ff4692d93..ecb81094d7c4 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_detect_reader.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_detect_reader.c @@ -116,8 +116,11 @@ bool nfc_scene_mf_classic_detect_reader_on_event(void* context, SceneManagerEven consumed = true; } } else if(event.type == SceneManagerEventTypeBack) { - nfc_listener_stop(instance->listener); - nfc_listener_free(instance->listener); + size_t nonces_pairs = 2 * mfkey32_logger_get_params_num(instance->mfkey32_logger); + if(nonces_pairs < NFC_SCENE_DETECT_READER_PAIR_NONCES_MAX) { + nfc_listener_stop(instance->listener); + nfc_listener_free(instance->listener); + } mfkey32_logger_free(instance->mfkey32_logger); } diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_mfkey_complete.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_mfkey_complete.c index 26c7aa918f78..8e07043e25b8 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_mfkey_complete.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_mfkey_complete.c @@ -42,7 +42,7 @@ bool nfc_scene_mf_classic_mfkey_complete_on_event(void* context, SceneManagerEve consumed = scene_manager_search_and_switch_to_previous_scene( instance->scene_manager, NfcSceneStart); } - } else if(event.event == SceneManagerEventTypeBack) { + } else if(event.type == SceneManagerEventTypeBack) { const uint32_t prev_scenes[] = {NfcSceneSavedMenu, NfcSceneStart}; consumed = scene_manager_search_and_switch_to_previous_scene_one_of( instance->scene_manager, prev_scenes, COUNT_OF(prev_scenes)); diff --git a/firmware/targets/f18/api_symbols.csv b/firmware/targets/f18/api_symbols.csv index bc75d365cc23..f26b424f8e54 100644 --- a/firmware/targets/f18/api_symbols.csv +++ b/firmware/targets/f18/api_symbols.csv @@ -1120,7 +1120,7 @@ Function,-,furi_hal_mpu_init,void, Function,+,furi_hal_mpu_protect_disable,void,FuriHalMpuRegion Function,+,furi_hal_mpu_protect_no_access,void,"FuriHalMpuRegion, uint32_t, FuriHalMPURegionSize" Function,+,furi_hal_mpu_protect_read_only,void,"FuriHalMpuRegion, uint32_t, FuriHalMPURegionSize" -Function,-,furi_hal_nfca_set_col_res_data,FHalNfcError,"uint8_t*, uint8_t, uint8_t*, uint8_t" +Function,-,f_hal_nfc_iso14443a_listener_set_col_res_data,FHalNfcError,"uint8_t*, uint8_t, uint8_t*, uint8_t" Function,-,furi_hal_os_init,void, Function,+,furi_hal_os_tick,void, Function,+,furi_hal_power_check_otg_fault,_Bool, diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 90ad35b921e0..e7fa9038024a 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,+,38.1,, +Version,+,41.8,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -874,12 +874,16 @@ Function,-,f_hal_nfc_acquire,FHalNfcError, Function,+,f_hal_nfc_event_start,FHalNfcError, Function,-,f_hal_nfc_init,FHalNfcError, Function,-,f_hal_nfc_is_hal_ready,FHalNfcError, -Function,-,f_hal_nfc_listener_disable_auto_col_res,FHalNfcError, -Function,+,f_hal_nfc_listener_reset,FHalNfcError, +Function,-,f_hal_nfc_iso14443a_listener_set_col_res_data,FHalNfcError,"uint8_t*, uint8_t, uint8_t*, uint8_t" +Function,-,f_hal_nfc_iso14443a_listener_tx_custom_parity,FHalNfcError,"const uint8_t*, const uint8_t*, size_t" +Function,-,f_hal_nfc_iso14443a_poller_trx_short_frame,FHalNfcError,FHalNfcaShortFrame +Function,-,f_hal_nfc_iso14443a_poller_tx_custom_parity,FHalNfcError,"const uint8_t*, size_t" +Function,-,f_hal_nfc_iso14443a_rx_sdd_frame,FHalNfcError,"uint8_t*, size_t, size_t*" +Function,-,f_hal_nfc_iso14443a_tx_sdd_frame,FHalNfcError,"const uint8_t*, size_t" +Function,-,f_hal_nfc_listener_enable_rx,FHalNfcError, +Function,-,f_hal_nfc_listener_idle,FHalNfcError, Function,+,f_hal_nfc_listener_rx,FHalNfcError,"uint8_t*, size_t, size_t*" -Function,+,f_hal_nfc_listener_rx_start,FHalNfcError, Function,-,f_hal_nfc_listener_sleep,FHalNfcError, -Function,+,f_hal_nfc_listener_start,FHalNfcError, Function,-,f_hal_nfc_listener_tx,FHalNfcError,"const uint8_t*, size_t" Function,-,f_hal_nfc_listener_wait_event,FHalNfcEvent,uint32_t Function,-,f_hal_nfc_low_power_mode_start,FHalNfcError, @@ -887,11 +891,9 @@ Function,-,f_hal_nfc_low_power_mode_stop,FHalNfcError, Function,-,f_hal_nfc_poller_field_on,FHalNfcError, Function,-,f_hal_nfc_poller_rx,FHalNfcError,"uint8_t*, size_t, size_t*" Function,-,f_hal_nfc_poller_tx,FHalNfcError,"const uint8_t*, size_t" -Function,-,f_hal_nfc_poller_tx_custom_parity,FHalNfcError,"const uint8_t*, size_t" Function,-,f_hal_nfc_poller_wait_event,FHalNfcEvent,uint32_t Function,-,f_hal_nfc_release,FHalNfcError, Function,-,f_hal_nfc_reset_mode,FHalNfcError, -Function,-,f_hal_nfc_set_mask_receive_timer,void,uint32_t Function,+,f_hal_nfc_set_mode,FHalNfcError,"FHalNfcMode, FHalNfcTech" Function,-,f_hal_nfc_timer_block_tx_is_running,_Bool, Function,-,f_hal_nfc_timer_block_tx_start,void,uint32_t @@ -900,10 +902,6 @@ Function,-,f_hal_nfc_timer_block_tx_stop,void, Function,-,f_hal_nfc_timer_fwt_start,void,uint32_t Function,-,f_hal_nfc_timer_fwt_stop,void, Function,-,f_hal_nfc_trx_reset,FHalNfcError, -Function,-,f_hal_nfca_listener_tx_custom_parity,FHalNfcError,"const uint8_t*, const uint8_t*, size_t" -Function,-,f_hal_nfca_receive_sdd_frame,FHalNfcError,"uint8_t*, size_t, size_t*" -Function,-,f_hal_nfca_send_sdd_frame,FHalNfcError,"const uint8_t*, size_t" -Function,-,f_hal_nfca_send_short_frame,FHalNfcError,FHalNfcaShortFrame Function,-,fabs,double,double Function,-,fabsf,float,float Function,-,fabsl,long double,long double @@ -1320,7 +1318,6 @@ Function,+,furi_hal_nfc_stop,void, Function,+,furi_hal_nfc_stop_cmd,void, Function,+,furi_hal_nfc_tx_rx,_Bool,"FuriHalNfcTxRxContext*, uint16_t" Function,+,furi_hal_nfc_tx_rx_full,_Bool,FuriHalNfcTxRxContext* -Function,-,furi_hal_nfca_set_col_res_data,FHalNfcError,"uint8_t*, uint8_t, uint8_t*, uint8_t" Function,-,furi_hal_os_init,void, Function,+,furi_hal_os_tick,void, Function,+,furi_hal_power_check_otg_fault,_Bool, @@ -2179,8 +2176,8 @@ Function,-,nextafterl,long double,"long double, long double" Function,-,nexttoward,double,"double, long double" Function,-,nexttowardf,float,"float, long double" Function,-,nexttowardl,long double,"long double, long double" -Function,-,nfc_alloc,Nfc*, -Function,-,nfc_config,void,"Nfc*, NfcMode" +Function,+,nfc_alloc,Nfc*, +Function,+,nfc_config,void,"Nfc*, NfcMode, NfcTech" Function,+,nfc_device_alloc,NfcDevice*, Function,+,nfc_device_clear,void,NfcDevice* Function,+,nfc_device_copy_data,void,"const NfcDevice*, NfcProtocol, NfcDeviceData*" @@ -2198,16 +2195,14 @@ Function,+,nfc_device_set_data,void,"NfcDevice*, NfcProtocol, const NfcDeviceDat Function,+,nfc_device_set_loading_callback,void,"NfcDevice*, NfcLoadingCallback, void*" Function,+,nfc_device_set_uid,_Bool,"NfcDevice*, const uint8_t*, size_t" Function,-,nfc_free,void,Nfc* -Function,-,nfc_iso14443_3a_listener_tx_custom_parity,NfcError,"Nfc*, const BitBuffer*" -Function,-,nfc_iso14443_3a_sdd_frame,NfcError,"Nfc*, const BitBuffer*, BitBuffer*, uint32_t" -Function,-,nfc_iso14443_3a_short_frame,NfcError,"Nfc*, NfcIso14443aShortFrame, BitBuffer*, uint32_t" -Function,-,nfc_listener_abort,void,Nfc* +Function,-,nfc_iso14443a_listener_set_col_res_data,NfcError,"Nfc*, uint8_t*, uint8_t, uint8_t*, uint8_t" +Function,-,nfc_iso14443a_listener_tx_custom_parity,NfcError,"Nfc*, const BitBuffer*" +Function,-,nfc_iso14443a_poller_trx_custom_parity,NfcError,"Nfc*, const BitBuffer*, BitBuffer*, uint32_t" +Function,-,nfc_iso14443a_poller_trx_sdd_frame,NfcError,"Nfc*, const BitBuffer*, BitBuffer*, uint32_t" +Function,-,nfc_iso14443a_poller_trx_short_frame,NfcError,"Nfc*, NfcIso14443aShortFrame, BitBuffer*, uint32_t" Function,-,nfc_listener_alloc,NfcListener*,"Nfc*, NfcProtocol, const NfcDeviceData*" Function,-,nfc_listener_free,void,NfcListener* Function,-,nfc_listener_get_data,const NfcDeviceData*,"NfcListener*, NfcProtocol" -Function,-,nfc_listener_reset,NfcError,Nfc* -Function,-,nfc_listener_set_col_res_data,NfcError,"Nfc*, uint8_t*, uint8_t, uint8_t*, uint8_t" -Function,-,nfc_listener_sleep,NfcError,Nfc* Function,-,nfc_listener_start,void,"NfcListener*, NfcGenericCallback, void*" Function,-,nfc_listener_stop,void,NfcListener* Function,-,nfc_listener_tx,NfcError,"Nfc*, const BitBuffer*" @@ -2217,6 +2212,7 @@ Function,+,nfc_poller_free,void,NfcPoller* Function,+,nfc_poller_get_data,const NfcDeviceData*,NfcPoller* Function,+,nfc_poller_start,void,"NfcPoller*, NfcGenericCallback, void*" Function,+,nfc_poller_stop,void,NfcPoller* +Function,+,nfc_poller_trx,NfcError,"Nfc*, const BitBuffer*, BitBuffer*, uint32_t" Function,+,nfc_protocol_get_parent,NfcProtocol,NfcProtocol Function,+,nfc_protocol_has_parent,_Bool,"NfcProtocol, NfcProtocol" Function,+,nfc_scanner_alloc,NfcScanner*,Nfc* @@ -2228,11 +2224,8 @@ Function,-,nfc_set_fdt_poll_fc,void,"Nfc*, uint32_t" Function,-,nfc_set_fdt_poll_poll_us,void,"Nfc*, uint32_t" Function,-,nfc_set_guard_time_us,void,"Nfc*, uint32_t" Function,-,nfc_set_mask_receive_time_fc,void,"Nfc*, uint32_t" -Function,-,nfc_start_listener,void,"Nfc*, NfcEventCallback, void*" -Function,-,nfc_start_poller,void,"Nfc*, NfcEventCallback, void*" +Function,+,nfc_start,void,"Nfc*, NfcEventCallback, void*" Function,-,nfc_stop,void,Nfc* -Function,-,nfc_trx,NfcError,"Nfc*, const BitBuffer*, BitBuffer*, uint32_t" -Function,-,nfc_trx_custom_parity,NfcError,"Nfc*, const BitBuffer*, BitBuffer*, uint32_t" Function,+,nfc_util_bytes2num,uint64_t,"const uint8_t*, uint8_t" Function,+,nfc_util_even_parity32,uint8_t,uint32_t Function,+,nfc_util_num2bytes,void,"uint64_t, uint8_t, uint8_t*" diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc.c b/firmware/targets/f7/furi_hal/f_hal_nfc.c index 55ee43452c90..999fc7268f4d 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfc.c +++ b/firmware/targets/f7/furi_hal/f_hal_nfc.c @@ -411,7 +411,6 @@ FHalNfcError f_hal_nfc_poller_field_on() { ST25R3916_REG_OP_CONTROL_tx_en)) { // Set min guard time st25r3916_write_reg(handle, ST25R3916_REG_FIELD_ON_GT, 0); - // st25r3916_direct_cmd(handle, ST25R3916_CMD_INITIAL_RF_COLLISION); // Enable tx rx st25r3916_set_reg_bits( handle, @@ -422,37 +421,6 @@ FHalNfcError f_hal_nfc_poller_field_on() { return error; } -FHalNfcError f_hal_nfc_poller_tx_custom_parity(const uint8_t* tx_data, size_t tx_bits) { - furi_assert(tx_data); - - // TODO common code for f_hal_nfc_poller_tx - - FHalNfcError err = FHalNfcErrorNone; - FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; - - // Prepare tx - st25r3916_direct_cmd(handle, ST25R3916_CMD_CLEAR_FIFO); - st25r3916_clear_reg_bits( - handle, ST25R3916_REG_TIMER_EMV_CONTROL, ST25R3916_REG_TIMER_EMV_CONTROL_nrt_emv); - st25r3916_change_reg_bits( - handle, - ST25R3916_REG_ISO14443A_NFC, - (ST25R3916_REG_ISO14443A_NFC_no_tx_par | ST25R3916_REG_ISO14443A_NFC_no_rx_par), - (ST25R3916_REG_ISO14443A_NFC_no_tx_par | ST25R3916_REG_ISO14443A_NFC_no_rx_par)); - uint32_t interrupts = - (ST25R3916_IRQ_MASK_FWL | ST25R3916_IRQ_MASK_TXE | ST25R3916_IRQ_MASK_RXS | - ST25R3916_IRQ_MASK_RXE | ST25R3916_IRQ_MASK_PAR | ST25R3916_IRQ_MASK_CRC | - ST25R3916_IRQ_MASK_ERR1 | ST25R3916_IRQ_MASK_ERR2 | ST25R3916_IRQ_MASK_NRE); - // Clear interrupts - st25r3916_get_irq(handle); - // Enable interrupts - st25r3916_mask_irq(handle, ~interrupts); - - st25r3916_write_fifo(handle, tx_data, tx_bits); - st25r3916_direct_cmd(handle, ST25R3916_CMD_TRANSMIT_WITHOUT_CRC); - return err; -} - FHalNfcError f_hal_nfc_poller_tx_common( FuriHalSpiBusHandle* handle, const uint8_t* tx_data, @@ -536,20 +504,6 @@ FHalNfcError f_hal_nfc_listener_tx(const uint8_t* tx_data, size_t tx_bits) { return f_hal_nfc_tech[f_hal_nfc.tech]->listener.tx(handle, tx_data, tx_bits); } -FHalNfcError f_hal_nfc_common_listener_rx_start(FuriHalSpiBusHandle* handle) { - UNUSED(handle); - /* Empty implementation */ - return FHalNfcErrorNone; -} - -FHalNfcError f_hal_nfc_listener_rx_start() { - furi_assert(f_hal_nfc.mode == FHalNfcModeListener); - furi_assert(f_hal_nfc.tech < FHalNfcTechNum); - - FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; - return f_hal_nfc_tech[f_hal_nfc.tech]->listener.rx_start(handle); -} - FHalNfcError f_hal_nfc_common_fifo_rx( FuriHalSpiBusHandle* handle, uint8_t* rx_data, @@ -583,41 +537,28 @@ FHalNfcError f_hal_nfc_trx_reset() { return FHalNfcErrorNone; } -FHalNfcError f_hal_nfc_listener_start() { - return FHalNfcErrorNone; -} +FHalNfcError f_hal_nfc_listener_sleep() { + furi_assert(f_hal_nfc.mode == FHalNfcModeListener); + furi_assert(f_hal_nfc.tech < FHalNfcTechNum); -FHalNfcError f_hal_nfc_listener_reset() { FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; - st25r3916_direct_cmd(handle, ST25R3916_CMD_UNMASK_RECEIVE_DATA); - - return FHalNfcErrorNone; + return f_hal_nfc_tech[f_hal_nfc.tech]->listener.sleep(handle); } -FHalNfcError f_hal_nfc_listener_sleep() { - FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; +FHalNfcError f_hal_nfc_listener_idle() { + furi_assert(f_hal_nfc.mode == FHalNfcModeListener); + furi_assert(f_hal_nfc.tech < FHalNfcTechNum); - // Enable auto collision resolution - st25r3916_clear_reg_bits( - handle, ST25R3916_REG_PASSIVE_TARGET, ST25R3916_REG_PASSIVE_TARGET_d_106_ac_a); - st25r3916_direct_cmd(handle, ST25R3916_CMD_STOP); - st25r3916_direct_cmd(handle, ST25R3916_CMD_GOTO_SLEEP); + FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; - return FHalNfcErrorNone; + return f_hal_nfc_tech[f_hal_nfc.tech]->listener.idle(handle); } -FHalNfcError f_hal_nfc_listener_disable_auto_col_res() { +FHalNfcError f_hal_nfc_listener_enable_rx() { FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; - st25r3916_set_reg_bits( - handle, ST25R3916_REG_PASSIVE_TARGET, ST25R3916_REG_PASSIVE_TARGET_d_106_ac_a); + st25r3916_direct_cmd(handle, ST25R3916_CMD_UNMASK_RECEIVE_DATA); return FHalNfcErrorNone; } - -void f_hal_nfc_set_mask_receive_timer(uint32_t time_fc) { - FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; - - st25r3916_write_reg(handle, ST25R3916_REG_MASK_RX_TIMER, time_fc); -} diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc_event.c b/firmware/targets/f7/furi_hal/f_hal_nfc_event.c index 622038fefa4e..d4876f126ff0 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfc_event.c +++ b/firmware/targets/f7/furi_hal/f_hal_nfc_event.c @@ -66,7 +66,7 @@ FHalNfcEvent f_hal_nfc_wait_event_common(uint32_t timeout_ms) { event |= FHalNfcEventListenerActive; } if(irq & ST25R3916_IRQ_MASK_WU_A_X) { - event |= FHalNfcEventListenerActiveA; + event |= FHalNfcEventListenerActive; } } if(event_flag & FHalNfcEventInternalTypeTimerFwtExpired) { diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc_i.h b/firmware/targets/f7/furi_hal/f_hal_nfc_i.h index 834ac219a399..d61fff1327dd 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfc_i.h +++ b/firmware/targets/f7/furi_hal/f_hal_nfc_i.h @@ -79,6 +79,8 @@ typedef FHalNfcError (*FHalNfcRx)( size_t rx_data_size, size_t* rx_bits); typedef FHalNfcEvent (*FHalNfcWaitEvent)(uint32_t timeout_ms); +typedef FHalNfcError (*FHalNfcSleep)(FuriHalSpiBusHandle* handle); +typedef FHalNfcError (*FHalNfcIdle)(FuriHalSpiBusHandle* handle); typedef struct { FHalNfcChipConfig init; @@ -92,9 +94,10 @@ typedef struct { FHalNfcChipConfig init; FHalNfcChipConfig deinit; FHalNfcWaitEvent wait_event; - FHalNfcChipConfig rx_start; FHalNfcTx tx; FHalNfcRx rx; + FHalNfcSleep sleep; + FHalNfcIdle idle; } FHalNfcTechListenerBase; typedef struct { diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc_iso14443a.c b/firmware/targets/f7/furi_hal/f_hal_nfc_iso14443a.c index 34617d1ac3cc..f04f05ae0171 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfc_iso14443a.c +++ b/firmware/targets/f7/furi_hal/f_hal_nfc_iso14443a.c @@ -54,7 +54,12 @@ static FHalNfcError f_hal_nfc_iso14443a_poller_init(FuriHalSpiBusHandle* handle) } static FHalNfcError f_hal_nfc_iso14443a_poller_deinit(FuriHalSpiBusHandle* handle) { - UNUSED(handle); + st25r3916_change_reg_bits( + handle, + ST25R3916_REG_ISO14443A_NFC, + (ST25R3916_REG_ISO14443A_NFC_no_tx_par | ST25R3916_REG_ISO14443A_NFC_no_rx_par), + (ST25R3916_REG_ISO14443A_NFC_no_tx_par_off | ST25R3916_REG_ISO14443A_NFC_no_rx_par_off)); + return FHalNfcErrorNone; } @@ -79,15 +84,15 @@ static FHalNfcError f_hal_nfc_iso14443a_listener_init(FuriHalSpiBusHandle* handl st25r3916_direct_cmd(handle, ST25R3916_CMD_STOP); uint32_t interrupts = - (/*ST25R3916_IRQ_MASK_FWL | ST25R3916_IRQ_MASK_TXE |*/ ST25R3916_IRQ_MASK_RXS /*| + (ST25R3916_IRQ_MASK_FWL | ST25R3916_IRQ_MASK_TXE | ST25R3916_IRQ_MASK_RXS | ST25R3916_IRQ_MASK_RXE | ST25R3916_IRQ_MASK_PAR | ST25R3916_IRQ_MASK_CRC | - ST25R3916_IRQ_MASK_ERR1 | ST25R3916_IRQ_MASK_ERR2 | ST25R3916_IRQ_MASK_EON | - ST25R3916_IRQ_MASK_EOF | ST25R3916_IRQ_MASK_WU_A_X | ST25R3916_IRQ_MASK_WU_A*/); + ST25R3916_IRQ_MASK_ERR1 | ST25R3916_IRQ_MASK_ERR2 | ST25R3916_IRQ_MASK_NRE | + ST25R3916_IRQ_MASK_EON | ST25R3916_IRQ_MASK_EOF | ST25R3916_IRQ_MASK_WU_A_X | + ST25R3916_IRQ_MASK_WU_A); // Clear interrupts - // FURI_LOG_I("LISTEN START", "%lX", interrupts); st25r3916_get_irq(handle); // Enable interrupts - st25r3916_mask_irq(handle, interrupts); + st25r3916_mask_irq(handle, ~interrupts); // Enable auto collision resolution st25r3916_clear_reg_bits( handle, ST25R3916_REG_PASSIVE_TARGET, ST25R3916_REG_PASSIVE_TARGET_d_106_ac_a); @@ -107,7 +112,19 @@ static FHalNfcError f_hal_nfc_iso14443a_listener_deinit(FuriHalSpiBusHandle* han return FHalNfcErrorNone; } -FHalNfcError f_hal_nfca_send_short_frame(FHalNfcaShortFrame frame) { +static FHalNfcEvent f_hal_nfc_iso14443_3a_listener_wait_event(uint32_t timeout_ms) { + FHalNfcEvent event = f_hal_nfc_wait_event_common(timeout_ms); + FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; + + if(event & FHalNfcEventListenerActive) { + st25r3916_set_reg_bits( + handle, ST25R3916_REG_PASSIVE_TARGET, ST25R3916_REG_PASSIVE_TARGET_d_106_ac_a); + } + + return event; +} + +FHalNfcError f_hal_nfc_iso14443a_poller_trx_short_frame(FHalNfcaShortFrame frame) { FHalNfcError error = FHalNfcErrorNone; FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; @@ -138,7 +155,7 @@ FHalNfcError f_hal_nfca_send_short_frame(FHalNfcaShortFrame frame) { return error; } -FHalNfcError f_hal_nfca_send_sdd_frame(const uint8_t* tx_data, size_t tx_bits) { +FHalNfcError f_hal_nfc_iso14443a_tx_sdd_frame(const uint8_t* tx_data, size_t tx_bits) { FHalNfcError error = FHalNfcErrorNone; // TODO Set anticollision parameters error = f_hal_nfc_poller_tx(tx_data, tx_bits); @@ -146,7 +163,8 @@ FHalNfcError f_hal_nfca_send_sdd_frame(const uint8_t* tx_data, size_t tx_bits) { return error; } -FHalNfcError f_hal_nfca_receive_sdd_frame(uint8_t* rx_data, size_t rx_data_size, size_t* rx_bits) { +FHalNfcError + f_hal_nfc_iso14443a_rx_sdd_frame(uint8_t* rx_data, size_t rx_data_size, size_t* rx_bits) { FHalNfcError error = FHalNfcErrorNone; UNUSED(rx_data); UNUSED(rx_bits); @@ -158,8 +176,42 @@ FHalNfcError f_hal_nfca_receive_sdd_frame(uint8_t* rx_data, size_t rx_data_size, return error; } -FHalNfcError - furi_hal_nfca_set_col_res_data(uint8_t* uid, uint8_t uid_len, uint8_t* atqa, uint8_t sak) { +FHalNfcError f_hal_nfc_iso14443a_poller_tx_custom_parity(const uint8_t* tx_data, size_t tx_bits) { + furi_assert(tx_data); + + // TODO common code for f_hal_nfc_poller_tx + + FHalNfcError err = FHalNfcErrorNone; + FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; + + // Prepare tx + st25r3916_direct_cmd(handle, ST25R3916_CMD_CLEAR_FIFO); + st25r3916_clear_reg_bits( + handle, ST25R3916_REG_TIMER_EMV_CONTROL, ST25R3916_REG_TIMER_EMV_CONTROL_nrt_emv); + st25r3916_change_reg_bits( + handle, + ST25R3916_REG_ISO14443A_NFC, + (ST25R3916_REG_ISO14443A_NFC_no_tx_par | ST25R3916_REG_ISO14443A_NFC_no_rx_par), + (ST25R3916_REG_ISO14443A_NFC_no_tx_par | ST25R3916_REG_ISO14443A_NFC_no_rx_par)); + uint32_t interrupts = + (ST25R3916_IRQ_MASK_FWL | ST25R3916_IRQ_MASK_TXE | ST25R3916_IRQ_MASK_RXS | + ST25R3916_IRQ_MASK_RXE | ST25R3916_IRQ_MASK_PAR | ST25R3916_IRQ_MASK_CRC | + ST25R3916_IRQ_MASK_ERR1 | ST25R3916_IRQ_MASK_ERR2 | ST25R3916_IRQ_MASK_NRE); + // Clear interrupts + st25r3916_get_irq(handle); + // Enable interrupts + st25r3916_mask_irq(handle, ~interrupts); + + st25r3916_write_fifo(handle, tx_data, tx_bits); + st25r3916_direct_cmd(handle, ST25R3916_CMD_TRANSMIT_WITHOUT_CRC); + return err; +} + +FHalNfcError f_hal_nfc_iso14443a_listener_set_col_res_data( + uint8_t* uid, + uint8_t uid_len, + uint8_t* atqa, + uint8_t sak) { furi_assert(uid); furi_assert(atqa); UNUSED(uid_len); @@ -221,7 +273,7 @@ FHalNfcError f_hal_iso4443a_listener_tx( return error; } -FHalNfcError f_hal_nfca_listener_tx_custom_parity( +FHalNfcError f_hal_nfc_iso14443a_listener_tx_custom_parity( const uint8_t* tx_data, const uint8_t* tx_parity, size_t tx_bits) { @@ -250,6 +302,26 @@ FHalNfcError f_hal_nfca_listener_tx_custom_parity( return FHalNfcErrorNone; } +FHalNfcError f_hal_iso14443_3a_listener_sleep(FuriHalSpiBusHandle* handle) { + // Enable auto collision resolution + st25r3916_clear_reg_bits( + handle, ST25R3916_REG_PASSIVE_TARGET, ST25R3916_REG_PASSIVE_TARGET_d_106_ac_a); + st25r3916_direct_cmd(handle, ST25R3916_CMD_STOP); + st25r3916_direct_cmd(handle, ST25R3916_CMD_GOTO_SLEEP); + + return FHalNfcErrorNone; +} + +FHalNfcError f_hal_iso14443_3a_listener_idle(FuriHalSpiBusHandle* handle) { + // Enable auto collision resolution + st25r3916_clear_reg_bits( + handle, ST25R3916_REG_PASSIVE_TARGET, ST25R3916_REG_PASSIVE_TARGET_d_106_ac_a); + st25r3916_direct_cmd(handle, ST25R3916_CMD_STOP); + st25r3916_direct_cmd(handle, ST25R3916_CMD_GOTO_SENSE); + + return FHalNfcErrorNone; +} + const FHalNfcTechBase f_hal_nfc_iso14443a = { .poller = { @@ -264,9 +336,10 @@ const FHalNfcTechBase f_hal_nfc_iso14443a = { { .init = f_hal_nfc_iso14443a_listener_init, .deinit = f_hal_nfc_iso14443a_listener_deinit, - .wait_event = f_hal_nfc_wait_event_common, - .rx_start = f_hal_nfc_common_listener_rx_start, + .wait_event = f_hal_nfc_iso14443_3a_listener_wait_event, .tx = f_hal_iso4443a_listener_tx, .rx = f_hal_nfc_common_fifo_rx, + .sleep = f_hal_iso14443_3a_listener_sleep, + .idle = f_hal_iso14443_3a_listener_idle, }, }; diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc_iso15693.c b/firmware/targets/f7/furi_hal/f_hal_nfc_iso15693.c index 9cf088e5fd3a..d8e7739ffb4f 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfc_iso15693.c +++ b/firmware/targets/f7/furi_hal/f_hal_nfc_iso15693.c @@ -336,11 +336,6 @@ static FHalNfcError return FHalNfcErrorNone; } -static FHalNfcError f_hal_nfc_iso15693_listener_rx_start(FuriHalSpiBusHandle* handle) { - UNUSED(handle); - return FHalNfcErrorNone; -} - static void f_hal_nfc_iso15693_parser_callback(Iso15693ParserEvent event, void* context) { furi_assert(context); @@ -411,6 +406,12 @@ static FHalNfcError f_hal_nfc_iso15693_listener_rx( return FHalNfcErrorNone; } +FHalNfcError f_hal_iso15693_listener_sleep(FuriHalSpiBusHandle* handle) { + UNUSED(handle); + + return FHalNfcErrorNone; +} + const FHalNfcTechBase f_hal_nfc_iso15693 = { .poller = { @@ -426,8 +427,9 @@ const FHalNfcTechBase f_hal_nfc_iso15693 = { .init = f_hal_nfc_iso15693_listener_init, .deinit = f_hal_nfc_iso15693_listener_deinit, .wait_event = f_hal_nfc_iso15693_wait_event, - .rx_start = f_hal_nfc_iso15693_listener_rx_start, .tx = f_hal_nfc_iso15693_listener_tx, .rx = f_hal_nfc_iso15693_listener_rx, + .sleep = f_hal_iso15693_listener_sleep, + .idle = f_hal_iso15693_listener_sleep, }, }; diff --git a/firmware/targets/f7/furi_hal/f_hal_nfc_timer.c b/firmware/targets/f7/furi_hal/f_hal_nfc_timer.c index be6c3b1d59be..2339f1dc0b7e 100644 --- a/firmware/targets/f7/furi_hal/f_hal_nfc_timer.c +++ b/firmware/targets/f7/furi_hal/f_hal_nfc_timer.c @@ -87,6 +87,7 @@ static void f_hal_nfc_timer_init(FHalNfcTimer timer) { } static void f_hal_nfc_timer_deinit(FHalNfcTimer timer) { + LL_TIM_ClearFlag_UPDATE(f_hal_nfc_timers[timer].timer); furi_hal_interrupt_set_isr(f_hal_nfc_timers[timer].irq_id, NULL, NULL); NVIC_DisableIRQ(f_hal_nfc_timers[timer].irq_type); f_hal_nfc_timers[timer].is_configured = false; diff --git a/firmware/targets/furi_hal_include/f_hal_nfc.h b/firmware/targets/furi_hal_include/f_hal_nfc.h index e29992a6f0d8..7cf04bd35a89 100644 --- a/firmware/targets/furi_hal_include/f_hal_nfc.h +++ b/firmware/targets/furi_hal_include/f_hal_nfc.h @@ -55,6 +55,7 @@ typedef enum { FHalNfcTechFelica, FHalNfcTechNum, + FHalNfcTechInvalid, } FHalNfcTech; typedef enum { @@ -114,23 +115,17 @@ FHalNfcEvent f_hal_nfc_listener_wait_event(uint32_t timeout_ms); FHalNfcError f_hal_nfc_poller_tx(const uint8_t* tx_data, size_t tx_bits); -FHalNfcError f_hal_nfc_poller_tx_custom_parity(const uint8_t* tx_data, size_t tx_bits); - FHalNfcError f_hal_nfc_poller_rx(uint8_t* rx_data, size_t rx_data_size, size_t* rx_bits); FHalNfcError f_hal_nfc_listener_tx(const uint8_t* tx_data, size_t tx_bits); -FHalNfcError f_hal_nfc_listener_rx_start(); - FHalNfcError f_hal_nfc_listener_rx(uint8_t* rx_data, size_t rx_data_size, size_t* rx_bits); -FHalNfcError f_hal_nfc_listener_start(); - -FHalNfcError f_hal_nfc_listener_reset(); - FHalNfcError f_hal_nfc_listener_sleep(); -FHalNfcError f_hal_nfc_listener_disable_auto_col_res(); +FHalNfcError f_hal_nfc_listener_idle(); + +FHalNfcError f_hal_nfc_listener_enable_rx(); FHalNfcError f_hal_nfc_trx_reset(); @@ -150,20 +145,24 @@ void f_hal_nfc_timer_block_tx_stop(); bool f_hal_nfc_timer_block_tx_is_running(); -void f_hal_nfc_set_mask_receive_timer(uint32_t time_fc); - /******************* NFCA specific API *******************/ -FHalNfcError f_hal_nfca_send_short_frame(FHalNfcaShortFrame frame); - -FHalNfcError f_hal_nfca_send_sdd_frame(const uint8_t* tx_data, size_t tx_bits); +FHalNfcError f_hal_nfc_iso14443a_poller_trx_short_frame(FHalNfcaShortFrame frame); -FHalNfcError f_hal_nfca_receive_sdd_frame(uint8_t* rx_data, size_t rx_data_size, size_t* rx_bits); +FHalNfcError f_hal_nfc_iso14443a_tx_sdd_frame(const uint8_t* tx_data, size_t tx_bits); FHalNfcError - furi_hal_nfca_set_col_res_data(uint8_t* uid, uint8_t uid_len, uint8_t* atqa, uint8_t sak); + f_hal_nfc_iso14443a_rx_sdd_frame(uint8_t* rx_data, size_t rx_data_size, size_t* rx_bits); + +FHalNfcError f_hal_nfc_iso14443a_listener_set_col_res_data( + uint8_t* uid, + uint8_t uid_len, + uint8_t* atqa, + uint8_t sak); + +FHalNfcError f_hal_nfc_iso14443a_poller_tx_custom_parity(const uint8_t* tx_data, size_t tx_bits); -FHalNfcError f_hal_nfca_listener_tx_custom_parity( +FHalNfcError f_hal_nfc_iso14443a_listener_tx_custom_parity( const uint8_t* tx_data, const uint8_t* tx_parity, size_t tx_bits); diff --git a/lib/nfc/nfc.c b/lib/nfc/nfc.c index a416fb07ab4d..f4a58236d662 100644 --- a/lib/nfc/nfc.c +++ b/lib/nfc/nfc.c @@ -11,10 +11,7 @@ typedef enum { NfcStateIdle, - NfcStateFieldOn, - NfcStateListenerStarted, - NfcStatePollerReady, - NfcStatePollerReset, + NfcStateRunning, } NfcState; typedef enum { @@ -47,6 +44,8 @@ struct Nfc { NfcPollerState poller_state; NfcCommState comm_state; NfcConfigurationState config_state; + NfcMode mode; + uint32_t fdt_listen_fc; uint32_t mask_rx_time_fc; uint32_t fdt_poll_fc; @@ -63,6 +62,25 @@ struct Nfc { FuriThread* worker_thread; }; +typedef bool (*NfcWorkerPollerStateHandler)(Nfc* instance); + +static const FHalNfcTech nfc_tech_table[NfcModeNum][NfcTechNum] = { + [NfcModePoller] = + { + [NfcTechIso14443a] = FHalNfcTechIso14443a, + [NfcTechIso14443b] = FHalNfcTechIso14443b, + [NfcTechIso15693] = FHalNfcTechIso15693, + [NfcTechFelica] = FHalNfcTechFelica, + }, + [NfcModeListener] = + { + [NfcTechIso14443a] = FHalNfcTechIso14443a, + [NfcTechIso14443b] = FHalNfcTechInvalid, + [NfcTechIso15693] = FHalNfcTechIso15693, + [NfcTechFelica] = FHalNfcTechInvalid, + }, +}; + static NfcError nfc_process_hal_error(FHalNfcError error) { NfcError err = NfcErrorNone; @@ -82,8 +100,7 @@ static int32_t nfc_worker_listener(void* context) { furi_assert(instance->callback); furi_assert(instance->config_state == NfcConfigurationStateDone); - f_hal_nfc_listener_start(); - instance->state = NfcStateListenerStarted; + instance->state = NfcStateRunning; f_hal_nfc_event_start(); @@ -100,18 +117,16 @@ static int32_t nfc_worker_listener(void* context) { break; } if(event & FHalNfcEventFieldOn) { - // FURI_LOG_D(TAG, "Field ON"); nfc_event.type = NfcEventTypeFieldOn; instance->callback(nfc_event, instance->context); - f_hal_nfc_listener_rx_start(); } if(event & FHalNfcEventFieldOff) { nfc_event.type = NfcEventTypeFieldOff; instance->callback(nfc_event, instance->context); - nfc_listener_reset(instance); + f_hal_nfc_listener_idle(); } + // TODO maybe remove? if(event & FHalNfcEventListenerActive) { - f_hal_nfc_listener_disable_auto_col_res(); nfc_event.type = NfcEventTypeListenerActivated; instance->callback(nfc_event, instance->context); } @@ -124,24 +139,22 @@ static int32_t nfc_worker_listener(void* context) { if(command == NfcCommandStop) { break; } else if(command == NfcCommandReset) { - nfc_listener_reset(instance); + f_hal_nfc_listener_enable_rx(); } else if(command == NfcCommandSleep) { - nfc_listener_sleep(instance); + f_hal_nfc_listener_sleep(); } } } - nfc_config(instance, NfcModeIdle); + f_hal_nfc_reset_mode(); + instance->config_state = NfcConfigurationStateIdle; + bit_buffer_free(event_data.buffer); f_hal_nfc_low_power_mode_start(); - return 0; } -typedef bool (*NfcWorkerPollerStateHandler)(Nfc* instance); - bool nfc_worker_poller_idle_handler(Nfc* instance) { - f_hal_nfc_low_power_mode_stop(); instance->poller_state = NfcPollerStateStart; return false; @@ -176,13 +189,16 @@ bool nfc_worker_poller_ready_handler(Nfc* instance) { bool nfc_worker_poller_reset_handler(Nfc* instance) { f_hal_nfc_low_power_mode_start(); furi_delay_ms(100); + f_hal_nfc_low_power_mode_stop(); instance->poller_state = NfcPollerStateIdle; return false; } bool nfc_worker_poller_stop_handler(Nfc* instance) { - nfc_config(instance, NfcModeIdle); + f_hal_nfc_reset_mode(); + instance->config_state = NfcConfigurationStateIdle; + f_hal_nfc_low_power_mode_start(); instance->poller_state = NfcPollerStateIdle; @@ -202,6 +218,7 @@ static int32_t nfc_worker_poller(void* context) { Nfc* instance = context; furi_assert(instance->callback); + instance->state = NfcStateRunning; instance->poller_state = NfcPollerStateIdle; f_hal_nfc_event_start(); @@ -215,7 +232,7 @@ static int32_t nfc_worker_poller(void* context) { } Nfc* nfc_alloc() { - furi_assert(f_hal_nfc_acquire() == FHalNfcErrorNone); + furi_check(f_hal_nfc_acquire() == FHalNfcErrorNone); Nfc* instance = malloc(sizeof(Nfc)); instance->state = NfcStateIdle; @@ -234,58 +251,30 @@ Nfc* nfc_alloc() { void nfc_free(Nfc* instance) { furi_assert(instance); - // TODO REWORK!!! - if(instance->state == NfcStateListenerStarted) { - f_hal_nfc_abort(); - furi_thread_join(instance->worker_thread); - } - furi_thread_free(instance->worker_thread); - f_hal_nfc_low_power_mode_start(); + furi_assert(instance->state == NfcStateIdle); + furi_thread_free(instance->worker_thread); free(instance); + f_hal_nfc_release(); } -// TODO: refactor this function (use 2 parameters for mode?) -void nfc_config(Nfc* instance, NfcMode mode) { +void nfc_config(Nfc* instance, NfcMode mode, NfcTech tech) { furi_assert(instance); - if(mode == NfcModeIdle) { - f_hal_nfc_reset_mode(); - instance->config_state = NfcConfigurationStateIdle; - } else if(mode == NfcModeIso14443aPoller) { - f_hal_nfc_set_mode(FHalNfcModePoller, FHalNfcTechIso14443a); - instance->config_state = NfcConfigurationStateDone; - } else if(mode == NfcModeIso14443aListener) { - f_hal_nfc_low_power_mode_stop(); - f_hal_nfc_set_mode(FHalNfcModeListener, FHalNfcTechIso14443a); - instance->config_state = NfcConfigurationStateDone; - } else if(mode == NfcModeIso14443bPoller) { - f_hal_nfc_set_mode(FHalNfcModePoller, FHalNfcTechIso14443b); - instance->config_state = NfcConfigurationStateDone; - } else if(mode == NfcModeIso15693Poller) { - f_hal_nfc_set_mode(FHalNfcModePoller, FHalNfcTechIso15693); - instance->config_state = NfcConfigurationStateDone; - } else if(mode == NfcModeIso15693Listener) { - f_hal_nfc_low_power_mode_stop(); - f_hal_nfc_set_mode(FHalNfcModeListener, FHalNfcTechIso15693); - instance->config_state = NfcConfigurationStateDone; - } else if(mode == NfcModeFelicaPoller) { - f_hal_nfc_set_mode(FHalNfcModePoller, FHalNfcTechFelica); - instance->config_state = NfcConfigurationStateDone; - } -} + furi_assert(mode < NfcModeNum); + furi_assert(tech < NfcTechNum); + furi_assert(instance->config_state == NfcConfigurationStateIdle); -NfcError nfc_listener_set_col_res_data( - Nfc* instance, - uint8_t* uid, - uint8_t uid_len, - uint8_t* atqa, - uint8_t sak) { - furi_assert(instance); + FHalNfcTech hal_tech = nfc_tech_table[mode][tech]; + if(hal_tech == FHalNfcTechInvalid) { + furi_crash("Unsupported mode for given tech"); + } + FHalNfcMode hal_mode = (mode == NfcModePoller) ? FHalNfcModePoller : FHalNfcModeListener; + f_hal_nfc_low_power_mode_stop(); + f_hal_nfc_set_mode(hal_mode, hal_tech); - FHalNfcError error = furi_hal_nfca_set_col_res_data(uid, uid_len, atqa, sak); - instance->comm_state = NfcCommStateIdle; - return nfc_process_hal_error(error); + instance->mode = mode; + instance->config_state = NfcConfigurationStateDone; } void nfc_set_fdt_poll_fc(Nfc* instance, uint32_t fdt_poll_fc) { @@ -313,7 +302,7 @@ void nfc_set_mask_receive_time_fc(Nfc* instance, uint32_t mask_rx_time_fc) { instance->mask_rx_time_fc = mask_rx_time_fc; } -void nfc_start_poller(Nfc* instance, NfcEventCallback callback, void* context) { +void nfc_start(Nfc* instance, NfcEventCallback callback, void* context) { furi_assert(instance); furi_assert(instance->worker_thread); furi_assert(callback); @@ -321,50 +310,25 @@ void nfc_start_poller(Nfc* instance, NfcEventCallback callback, void* context) { instance->callback = callback; instance->context = context; - furi_thread_set_callback(instance->worker_thread, nfc_worker_poller); - furi_thread_start(instance->worker_thread); - instance->comm_state = NfcCommStateIdle; -} - -void nfc_start_listener(Nfc* instance, NfcEventCallback callback, void* context) { - furi_assert(instance); - furi_assert(instance->worker_thread); - furi_assert(callback); - - instance->callback = callback; - instance->context = context; - furi_thread_set_callback(instance->worker_thread, nfc_worker_listener); + if(instance->mode == NfcModePoller) { + furi_thread_set_callback(instance->worker_thread, nfc_worker_poller); + } else { + furi_thread_set_callback(instance->worker_thread, nfc_worker_listener); + } furi_thread_start(instance->worker_thread); instance->comm_state = NfcCommStateIdle; } -void nfc_listener_abort(Nfc* instance) { - furi_assert(instance); - f_hal_nfc_abort(); - furi_thread_join(instance->worker_thread); -} - void nfc_stop(Nfc* instance) { furi_assert(instance); - furi_thread_join(instance->worker_thread); -} - -NfcError nfc_listener_reset(Nfc* instance) { - furi_assert(instance); - furi_assert(instance->state == NfcStateListenerStarted); - - f_hal_nfc_listener_sleep(); - - return NfcErrorNone; -} - -NfcError nfc_listener_sleep(Nfc* instance) { - furi_assert(instance); - furi_assert(instance->state == NfcStateListenerStarted); + furi_assert(instance->state == NfcStateRunning); - f_hal_nfc_listener_reset(); + if(instance->mode == NfcModeListener) { + f_hal_nfc_abort(); + } + furi_thread_join(instance->worker_thread); - return NfcErrorNone; + instance->state = NfcStateIdle; } NfcError nfc_listener_tx(Nfc* instance, const BitBuffer* tx_buffer) { @@ -387,6 +351,7 @@ static NfcError nfc_poller_trx_state_machine(Nfc* instance, uint32_t fwt_fc) { NfcError error = NfcErrorNone; while(true) { + // TODO sanity timeout check event = f_hal_nfc_poller_wait_event(F_HAL_NFC_EVENT_WAIT_FOREVER); if(event & FHalNfcEventTimerBlockTxExpired) { if(instance->comm_state == NfcCommStateWaitBlockTxTimer) { @@ -432,7 +397,7 @@ static NfcError nfc_poller_trx_state_machine(Nfc* instance, uint32_t fwt_fc) { return error; } -NfcError nfc_trx_custom_parity( +NfcError nfc_iso14443a_poller_trx_custom_parity( Nfc* instance, const BitBuffer* tx_buffer, BitBuffer* rx_buffer, @@ -449,7 +414,8 @@ NfcError nfc_trx_custom_parity( f_hal_nfc_trx_reset(); bit_buffer_write_bytes_with_parity( tx_buffer, instance->tx_buffer, sizeof(instance->tx_buffer), &instance->tx_bits); - error = f_hal_nfc_poller_tx_custom_parity(instance->tx_buffer, instance->tx_bits); + error = + f_hal_nfc_iso14443a_poller_tx_custom_parity(instance->tx_buffer, instance->tx_bits); if(error != FHalNfcErrorNone) { FURI_LOG_E(TAG, "Failed in poller TX"); ret = nfc_process_hal_error(error); @@ -476,7 +442,8 @@ NfcError nfc_trx_custom_parity( return ret; } -NfcError nfc_trx(Nfc* instance, const BitBuffer* tx_buffer, BitBuffer* rx_buffer, uint32_t fwt) { +NfcError + nfc_poller_trx(Nfc* instance, const BitBuffer* tx_buffer, BitBuffer* rx_buffer, uint32_t fwt) { furi_assert(instance); furi_assert(tx_buffer); furi_assert(rx_buffer); @@ -515,7 +482,20 @@ NfcError nfc_trx(Nfc* instance, const BitBuffer* tx_buffer, BitBuffer* rx_buffer return ret; } -NfcError nfc_iso14443_3a_short_frame( +NfcError nfc_iso14443a_listener_set_col_res_data( + Nfc* instance, + uint8_t* uid, + uint8_t uid_len, + uint8_t* atqa, + uint8_t sak) { + furi_assert(instance); + + FHalNfcError error = f_hal_nfc_iso14443a_listener_set_col_res_data(uid, uid_len, atqa, sak); + instance->comm_state = NfcCommStateIdle; + return nfc_process_hal_error(error); +} + +NfcError nfc_iso14443a_poller_trx_short_frame( Nfc* instance, NfcIso14443aShortFrame frame, BitBuffer* rx_buffer, @@ -533,7 +513,7 @@ NfcError nfc_iso14443_3a_short_frame( FHalNfcError error = FHalNfcErrorNone; do { f_hal_nfc_trx_reset(); - error = f_hal_nfca_send_short_frame(short_frame); + error = f_hal_nfc_iso14443a_poller_trx_short_frame(short_frame); if(error != FHalNfcErrorNone) { FURI_LOG_E(TAG, "Failed in poller TX"); ret = nfc_process_hal_error(error); @@ -560,7 +540,7 @@ NfcError nfc_iso14443_3a_short_frame( return ret; } -NfcError nfc_iso14443_3a_sdd_frame( +NfcError nfc_iso14443a_poller_trx_sdd_frame( Nfc* instance, const BitBuffer* tx_buffer, BitBuffer* rx_buffer, @@ -575,7 +555,7 @@ NfcError nfc_iso14443_3a_sdd_frame( FHalNfcError error = FHalNfcErrorNone; do { f_hal_nfc_trx_reset(); - error = f_hal_nfca_send_sdd_frame( + error = f_hal_nfc_iso14443a_tx_sdd_frame( bit_buffer_get_data(tx_buffer), bit_buffer_get_size(tx_buffer)); if(error != FHalNfcErrorNone) { FURI_LOG_E(TAG, "Failed in poller TX"); @@ -603,7 +583,7 @@ NfcError nfc_iso14443_3a_sdd_frame( return ret; } -NfcError nfc_iso14443_3a_listener_tx_custom_parity(Nfc* instance, const BitBuffer* tx_buffer) { +NfcError nfc_iso14443a_listener_tx_custom_parity(Nfc* instance, const BitBuffer* tx_buffer) { furi_assert(instance); furi_assert(tx_buffer); @@ -614,7 +594,7 @@ NfcError nfc_iso14443_3a_listener_tx_custom_parity(Nfc* instance, const BitBuffe const uint8_t* tx_parity = bit_buffer_get_parity(tx_buffer); size_t tx_bits = bit_buffer_get_size(tx_buffer); - error = f_hal_nfca_listener_tx_custom_parity(tx_data, tx_parity, tx_bits); + error = f_hal_nfc_iso14443a_listener_tx_custom_parity(tx_data, tx_parity, tx_bits); ret = nfc_process_hal_error(error); return ret; diff --git a/lib/nfc/nfc.h b/lib/nfc/nfc.h index d7aa4be0b3ee..6fdb88d7ccfa 100644 --- a/lib/nfc/nfc.h +++ b/lib/nfc/nfc.h @@ -40,17 +40,21 @@ typedef enum { typedef NfcCommand (*NfcEventCallback)(NfcEvent event, void* context); typedef enum { - NfcModeIdle, - NfcModeIso14443aPoller, - NfcModeIso14443aListener, - NfcModeIso14443bPoller, - NfcModeIso14443bListener, - NfcModeFelicaPoller, - NfcModeNfcfListener, - NfcModeIso15693Poller, - NfcModeIso15693Listener, + NfcModePoller, + NfcModeListener, + + NfcModeNum, } NfcMode; +typedef enum { + NfcTechIso14443a, + NfcTechIso14443b, + NfcTechIso15693, + NfcTechFelica, + + NfcTechNum, +} NfcTech; + typedef enum { NfcErrorNone, NfcErrorInternal, @@ -70,7 +74,7 @@ Nfc* nfc_alloc(); void nfc_free(Nfc* instance); -void nfc_config(Nfc* instance, NfcMode mode); +void nfc_config(Nfc* instance, NfcMode mode, NfcTech tech); void nfc_set_fdt_poll_fc(Nfc* instance, uint32_t fdt_poll_fc); @@ -82,22 +86,7 @@ void nfc_set_fdt_poll_poll_us(Nfc* instance, uint32_t fdt_poll_poll_us); void nfc_set_guard_time_us(Nfc* instance, uint32_t guard_time_us); -NfcError nfc_listener_set_col_res_data( - Nfc* instance, - uint8_t* uid, - uint8_t uid_len, - uint8_t* atqa, - uint8_t sak); - -void nfc_start_poller(Nfc* instance, NfcEventCallback callback, void* context); - -void nfc_start_listener(Nfc* instance, NfcEventCallback callback, void* context); - -NfcError nfc_listener_reset(Nfc* instance); - -NfcError nfc_listener_sleep(Nfc* instance); - -void nfc_listener_abort(Nfc* instance); +void nfc_start(Nfc* instance, NfcEventCallback callback, void* context); void nfc_stop(Nfc* instance); @@ -105,29 +94,37 @@ void nfc_stop(Nfc* instance); NfcError nfc_listener_tx(Nfc* instance, const BitBuffer* tx_buffer); -NfcError nfc_trx_custom_parity( - Nfc* instance, - const BitBuffer* tx_buffer, - BitBuffer* rx_buffer, - uint32_t fwt); - -NfcError nfc_trx(Nfc* instance, const BitBuffer* tx_buffer, BitBuffer* rx_buffer, uint32_t fwt); +NfcError + nfc_poller_trx(Nfc* instance, const BitBuffer* tx_buffer, BitBuffer* rx_buffer, uint32_t fwt); // Technology specific API -NfcError nfc_iso14443_3a_short_frame( +NfcError nfc_iso14443a_listener_set_col_res_data( + Nfc* instance, + uint8_t* uid, + uint8_t uid_len, + uint8_t* atqa, + uint8_t sak); + +NfcError nfc_iso14443a_poller_trx_short_frame( Nfc* instance, NfcIso14443aShortFrame frame, BitBuffer* rx_buffer, uint32_t fwt); -NfcError nfc_iso14443_3a_sdd_frame( +NfcError nfc_iso14443a_poller_trx_sdd_frame( Nfc* instance, const BitBuffer* tx_buffer, BitBuffer* rx_buffer, uint32_t fwt); -NfcError nfc_iso14443_3a_listener_tx_custom_parity(Nfc* instance, const BitBuffer* tx_buffer); +NfcError nfc_iso14443a_listener_tx_custom_parity(Nfc* instance, const BitBuffer* tx_buffer); + +NfcError nfc_iso14443a_poller_trx_custom_parity( + Nfc* instance, + const BitBuffer* tx_buffer, + BitBuffer* rx_buffer, + uint32_t fwt); #ifdef __cplusplus } diff --git a/lib/nfc/nfc_listener.c b/lib/nfc/nfc_listener.c index b73f9f69bfcf..68dafdbde765 100644 --- a/lib/nfc/nfc_listener.c +++ b/lib/nfc/nfc_listener.c @@ -120,13 +120,13 @@ void nfc_listener_start(NfcListener* instance, NfcGenericCallback callback, void NfcListenerListElement* tail_element = instance->list.tail; tail_element->listener_api->set_callback(tail_element->listener, callback, context); - nfc_start_listener(instance->nfc, nfc_listener_start_callback, instance); + nfc_start(instance->nfc, nfc_listener_start_callback, instance); } void nfc_listener_stop(NfcListener* instance) { furi_assert(instance); - nfc_listener_abort(instance->nfc); + nfc_stop(instance->nfc); } const NfcDeviceData* nfc_listener_get_data(NfcListener* instance, NfcProtocol protocol) { diff --git a/lib/nfc/nfc_poller.c b/lib/nfc/nfc_poller.c index f1963c0d22c6..ca572aaca77c 100644 --- a/lib/nfc/nfc_poller.c +++ b/lib/nfc/nfc_poller.c @@ -124,7 +124,7 @@ void nfc_poller_start(NfcPoller* instance, NfcGenericCallback callback, void* co tail_poller->poller_api->set_callback(tail_poller->poller, callback, context); instance->session_state = NfcPollerSessionStateActive; - nfc_start_poller(instance->nfc, nfc_poller_start_callback, instance); + nfc_start(instance->nfc, nfc_poller_start_callback, instance); } void nfc_poller_stop(NfcPoller* instance) { @@ -189,7 +189,7 @@ bool nfc_poller_detect(NfcPoller* instance) { iter->poller_api->set_callback(iter->poller, nfc_poller_detect_tail_callback, instance); } - nfc_start_poller(instance->nfc, nfc_poller_detect_callback, instance); + nfc_start(instance->nfc, nfc_poller_detect_callback, instance); nfc_stop(instance->nfc); // TODO hard to understand diff --git a/lib/nfc/protocols/felica/felica_poller.c b/lib/nfc/protocols/felica/felica_poller.c index 824043aebbaf..d4ef85dbbc0a 100644 --- a/lib/nfc/protocols/felica/felica_poller.c +++ b/lib/nfc/protocols/felica/felica_poller.c @@ -19,7 +19,7 @@ static FelicaPoller* felica_poller_alloc(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, NfcModeFelicaPoller); + 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); diff --git a/lib/nfc/protocols/felica/felica_poller_i.c b/lib/nfc/protocols/felica/felica_poller_i.c index 48dcd2eac82c..7e9bb42bae27 100644 --- a/lib/nfc/protocols/felica/felica_poller_i.c +++ b/lib/nfc/protocols/felica/felica_poller_i.c @@ -30,7 +30,8 @@ static FelicaError felica_poller_frame_exchange( FelicaError ret = FelicaErrorNone; do { - NfcError error = nfc_trx(instance->nfc, instance->tx_buffer, instance->rx_buffer, fwt); + NfcError error = + nfc_poller_trx(instance->nfc, instance->tx_buffer, instance->rx_buffer, fwt); if(error != NfcErrorNone) { ret = felica_poller_process_error(error); break; diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c b/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c index 5a144091f6a4..1caa98f1bcf2 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.c @@ -38,8 +38,8 @@ Iso14443_3aListener* iso14443_3a_listener_alloc(Nfc* nfc, Iso14443_3aData* data) instance->generic_event.data = &instance->iso14443_3a_event; nfc_set_fdt_listen_fc(instance->nfc, ISO14443_3A_FDT_LISTEN_FC); - nfc_config(instance->nfc, NfcModeIso14443aListener); - nfc_listener_set_col_res_data( + nfc_config(instance->nfc, NfcModeListener, NfcTechIso14443a); + nfc_iso14443a_listener_set_col_res_data( instance->nfc, instance->data->uid, instance->data->uid_len, @@ -92,14 +92,14 @@ NfcCommand iso14443_3a_listener_run(NfcGenericEvent event, void* context) { instance->iso14443_3a_event.type = Iso14443_3aListenerEventTypeFieldOff; instance->callback(instance->generic_event, instance->context); } - command = NfcCommandReset; + command = NfcCommandSleep; } else if(nfc_event->type == NfcEventTypeRxEnd) { if(iso14443_3a_listener_halt_received(nfc_event->data.buffer)) { if(instance->callback) { instance->iso14443_3a_event.type = Iso14443_3aListenerEventTypeHalted; instance->callback(instance->generic_event, instance->context); } - command = NfcCommandReset; + command = NfcCommandSleep; } else { if(iso14443_crc_check(Iso14443CrcTypeA, nfc_event->data.buffer)) { instance->iso14443_3a_event.type = diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener_i.c b/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener_i.c index 2c4699aac5ae..46501503ceec 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener_i.c +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_listener_i.c @@ -40,7 +40,7 @@ Iso14443_3aError iso14443_3a_listener_tx_with_custom_parity( furi_assert(tx_buffer); Iso14443_3aError ret = Iso14443_3aErrorNone; - NfcError error = nfc_iso14443_3a_listener_tx_custom_parity(instance->nfc, tx_buffer); + NfcError error = nfc_iso14443a_listener_tx_custom_parity(instance->nfc, tx_buffer); if(error != NfcErrorNone) { FURI_LOG_W(TAG, "Tx error: %d", error); ret = iso14443_3a_listener_process_nfc_error(error); diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.c b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.c index 5772960f49f3..65f0ae629d12 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.c +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.c @@ -21,7 +21,7 @@ static Iso14443_3aPoller* iso14443_3a_poller_alloc(Nfc* nfc) { instance->tx_buffer = bit_buffer_alloc(ISO14443_3A_POLLER_MAX_BUFFER_SIZE); instance->rx_buffer = bit_buffer_alloc(ISO14443_3A_POLLER_MAX_BUFFER_SIZE); - nfc_config(instance->nfc, NfcModeIso14443aPoller); + nfc_config(instance->nfc, NfcModePoller, NfcTechIso14443a); nfc_set_guard_time_us(instance->nfc, ISO14443_3A_GUARD_TIME_US); nfc_set_fdt_poll_fc(instance->nfc, ISO14443_3A_FDT_POLL_FC); nfc_set_fdt_poll_poll_us(instance->nfc, ISO14443_3A_POLL_POLL_MIN_US); diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.c b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.c index a98894f3d019..16bead746bd3 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.c +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.c @@ -45,7 +45,8 @@ static Iso14443_3aError iso14443_3a_poller_standard_frame_exchange( Iso14443_3aError ret = Iso14443_3aErrorNone; do { - NfcError error = nfc_trx(instance->nfc, instance->tx_buffer, instance->rx_buffer, fwt); + NfcError error = + nfc_poller_trx(instance->nfc, instance->tx_buffer, instance->rx_buffer, fwt); if(error != NfcErrorNone) { ret = iso14443_3a_poller_process_error(error); break; @@ -70,7 +71,7 @@ Iso14443_3aError iso14443_3a_poller_check_presence(Iso14443_3aPoller* instance) NfcError error = NfcErrorNone; Iso14443_3aError ret = Iso14443_3aErrorNone; do { - error = nfc_iso14443_3a_short_frame( + error = nfc_iso14443a_poller_trx_short_frame( instance->nfc, NfcIso14443aShortFrameSensReq, instance->rx_buffer, @@ -128,7 +129,7 @@ Iso14443_3aError iso14443_3a_poller_async_activate( bool activated = false; do { - error = nfc_iso14443_3a_short_frame( + error = nfc_iso14443a_poller_trx_short_frame( instance->nfc, NfcIso14443aShortFrameSensReq, instance->rx_buffer, @@ -163,7 +164,7 @@ Iso14443_3aError iso14443_3a_poller_async_activate( 0, ISO14443_3A_POLLER_SEL_CMD(instance->col_res.cascade_level)); bit_buffer_set_byte(instance->tx_buffer, 1, ISO14443_3A_POLLER_SEL_PAR(2, 0)); - error = nfc_iso14443_3a_sdd_frame( + error = nfc_iso14443a_poller_trx_sdd_frame( instance->nfc, instance->tx_buffer, instance->rx_buffer, @@ -266,7 +267,7 @@ Iso14443_3aError iso14443_3a_poller_txrx_custom_parity( ret = iso14443_3a_poller_prepare_trx(instance); if(ret != Iso14443_3aErrorNone) break; - error = nfc_trx_custom_parity(instance->nfc, tx_buffer, rx_buffer, fwt); + error = nfc_iso14443a_poller_trx_custom_parity(instance->nfc, tx_buffer, rx_buffer, fwt); if(error != NfcErrorNone) { ret = iso14443_3a_poller_process_error(error); break; @@ -292,7 +293,7 @@ Iso14443_3aError iso14443_3a_poller_txrx( ret = iso14443_3a_poller_prepare_trx(instance); if(ret != Iso14443_3aErrorNone) break; - error = nfc_trx(instance->nfc, tx_buffer, rx_buffer, fwt); + error = nfc_poller_trx(instance->nfc, tx_buffer, rx_buffer, fwt); if(error != NfcErrorNone) { ret = iso14443_3a_poller_process_error(error); break; diff --git a/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller.c b/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller.c index 3ea74f60cf94..2ec9ec6a6fbc 100644 --- a/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller.c +++ b/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller.c @@ -21,7 +21,7 @@ static Iso14443_3bPoller* iso14443_3b_poller_alloc(Nfc* nfc) { instance->tx_buffer = bit_buffer_alloc(ISO14443_3B_POLLER_MAX_BUFFER_SIZE); instance->rx_buffer = bit_buffer_alloc(ISO14443_3B_POLLER_MAX_BUFFER_SIZE); - nfc_config(instance->nfc, NfcModeIso14443bPoller); + nfc_config(instance->nfc, NfcModePoller, NfcTechIso14443b); nfc_set_guard_time_us(instance->nfc, ISO14443_3B_GUARD_TIME_US); nfc_set_fdt_poll_fc(instance->nfc, ISO14443_3B_FDT_POLL_FC); nfc_set_fdt_poll_poll_us(instance->nfc, ISO14443_3B_POLL_POLL_MIN_US); diff --git a/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller_i.c b/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller_i.c index 35c67c43cdc6..e3ca07deab7d 100644 --- a/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller_i.c +++ b/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller_i.c @@ -42,7 +42,8 @@ static Iso14443_3bError iso14443_3b_poller_frame_exchange( Iso14443_3bError ret = Iso14443_3bErrorNone; do { - NfcError error = nfc_trx(instance->nfc, instance->tx_buffer, instance->rx_buffer, fwt); + NfcError error = + nfc_poller_trx(instance->nfc, instance->tx_buffer, instance->rx_buffer, fwt); if(error != NfcErrorNone) { ret = iso14443_3b_poller_process_error(error); break; diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3_listener.c b/lib/nfc/protocols/iso15693_3/iso15693_3_listener.c index cd03d482babb..2ead83ce560d 100644 --- a/lib/nfc/protocols/iso15693_3/iso15693_3_listener.c +++ b/lib/nfc/protocols/iso15693_3/iso15693_3_listener.c @@ -25,7 +25,7 @@ Iso15693_3Listener* iso15693_3_listener_alloc(Nfc* nfc, Iso15693_3Data* data) { instance->generic_event.data = &instance->iso15693_3_event; nfc_set_fdt_listen_fc(instance->nfc, ISO15693_3_FDT_LISTEN_FC); - nfc_config(instance->nfc, NfcModeIso15693Listener); + nfc_config(instance->nfc, NfcModeListener, NfcTechIso15693); return instance; } diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3_poller.c b/lib/nfc/protocols/iso15693_3/iso15693_3_poller.c index ffe27bc78459..3447e2f0fb89 100644 --- a/lib/nfc/protocols/iso15693_3/iso15693_3_poller.c +++ b/lib/nfc/protocols/iso15693_3/iso15693_3_poller.c @@ -21,7 +21,7 @@ static Iso15693_3Poller* iso15693_3_poller_alloc(Nfc* nfc) { instance->tx_buffer = bit_buffer_alloc(ISO15693_3_POLLER_MAX_BUFFER_SIZE); instance->rx_buffer = bit_buffer_alloc(ISO15693_3_POLLER_MAX_BUFFER_SIZE); - nfc_config(instance->nfc, NfcModeIso15693Poller); + nfc_config(instance->nfc, NfcModePoller, NfcTechIso15693); nfc_set_guard_time_us(instance->nfc, ISO15693_3_GUARD_TIME_US); nfc_set_fdt_poll_fc(instance->nfc, ISO15693_3_FDT_POLL_FC); nfc_set_fdt_poll_poll_us(instance->nfc, ISO15693_3_POLL_POLL_MIN_US); diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3_poller_i.c b/lib/nfc/protocols/iso15693_3/iso15693_3_poller_i.c index 23a053608c66..8b8d8cee04b9 100644 --- a/lib/nfc/protocols/iso15693_3/iso15693_3_poller_i.c +++ b/lib/nfc/protocols/iso15693_3/iso15693_3_poller_i.c @@ -61,7 +61,8 @@ static Iso15693_3Error iso15693_3_poller_frame_exchange( bit_buffer_copy(instance->tx_buffer, tx_buffer); iso13239_crc_append(Iso13239CrcTypeDefault, instance->tx_buffer); - NfcError error = nfc_trx(instance->nfc, instance->tx_buffer, instance->rx_buffer, fwt); + NfcError error = + nfc_poller_trx(instance->nfc, instance->tx_buffer, instance->rx_buffer, fwt); if(error != NfcErrorNone) { ret = iso15693_3_poller_process_nfc_error(error); break; diff --git a/lib/nfc/protocols/mf_classic/mf_classic_listener.c b/lib/nfc/protocols/mf_classic/mf_classic_listener.c index e9000bba02b9..feda949ce4f9 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_listener.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_listener.c @@ -44,7 +44,7 @@ static MfClassicListenerCommand if(bit_buffer_get_byte(buff, 1) == MF_CLASSIC_CMD_HALT_LSB) { mf_classic_listener_reset_state(instance); - command = MfClassicListenerCommandSilent; + command = MfClassicListenerCommandSleep; } return command; @@ -533,7 +533,7 @@ NfcCommand mf_classic_listener_run(NfcGenericEvent event, void* context) { if(iso3_event->type == Iso14443_3aListenerEventTypeFieldOff) { mf_classic_listener_reset_state(instance); - command = NfcCommandReset; + command = NfcCommandSleep; } else if( (iso3_event->type == Iso14443_3aListenerEventTypeReceivedData) || (iso3_event->type == Iso14443_3aListenerEventTypeReceivedStandardFrame)) { @@ -573,6 +573,8 @@ NfcCommand mf_classic_listener_run(NfcGenericEvent event, void* context) { mf_classic_listener_send_short_frame(instance, MF_CLASSIC_CMD_NACK); } else if(mfc_command == MfClassicListenerCommandSilent) { command = NfcCommandReset; + } else if(mfc_command == MfClassicListenerCommandSleep) { + command = NfcCommandSleep; } } else if(iso3_event->type == Iso14443_3aListenerEventTypeHalted) { mf_classic_listener_reset_state(instance); diff --git a/lib/nfc/protocols/mf_classic/mf_classic_listener_i.h b/lib/nfc/protocols/mf_classic/mf_classic_listener_i.h index 4507ac8c0951..9ad834dd871b 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_listener_i.h +++ b/lib/nfc/protocols/mf_classic/mf_classic_listener_i.h @@ -14,6 +14,7 @@ typedef enum { MfClassicListenerCommandAck, MfClassicListenerCommandNack, MfClassicListenerCommandSilent, + MfClassicListenerCommandSleep, } MfClassicListenerCommand; typedef enum { diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller.c b/lib/nfc/protocols/mf_classic/mf_classic_poller.c index b8def569b54f..5ff7b41f4237 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller.c @@ -738,19 +738,18 @@ bool mf_classic_poller_detect(NfcGenericEvent event, void* context) { Iso14443_3aPoller* iso3_poller = event.instance; Iso14443_3aPollerEvent* iso14443_3a_event = event.data; bool detected = false; + const uint8_t auth_cmd[] = {MF_CLASSIC_CMD_AUTH_KEY_A, 0}; + BitBuffer* tx_buffer = bit_buffer_alloc(COUNT_OF(auth_cmd)); + bit_buffer_copy_bytes(tx_buffer, auth_cmd, COUNT_OF(auth_cmd)); + BitBuffer* rx_buffer = bit_buffer_alloc(sizeof(MfClassicNt)); if(iso14443_3a_event->type == Iso14443_3aPollerEventTypeReady) { - const Iso14443_3aData* iso3_data = iso14443_3a_poller_get_data(iso3_poller); - uint8_t atqa0 = iso3_data->atqa[0]; - uint8_t atqa1 = iso3_data->atqa[1]; - uint8_t sak = iso3_data->sak; - if((atqa0 == 0x44 || atqa0 == 0x04) && (sak == 0x08 || sak == 0x88 || sak == 0x09)) { - detected = true; - } else if((atqa0 == 0x01) && (atqa1 == 0x0F) && (sak == 0x01)) { - //skylanders support - detected = true; - } else if((atqa0 == 0x42 || atqa0 == 0x02) && (sak == 0x18)) { - detected = true; + Iso14443_3aError error = iso14443_3a_poller_send_standard_frame( + iso3_poller, tx_buffer, rx_buffer, MF_CLASSIC_FWT_FC); + if(error == Iso14443_3aErrorWrongCrc) { + if(bit_buffer_get_size_bytes(rx_buffer) == sizeof(MfClassicNt)) { + detected = true; + } } } diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c index 58e8358f9dac..7f84ee5c2792 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c @@ -7,8 +7,6 @@ #define TAG "MfCLassicPoller" -#define MF_CLASSIC_FWT_FC (60000) - MfClassicError mf_classic_process_error(Iso14443_3aError error) { MfClassicError ret = MfClassicErrorNone; diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h index a8d5a056d53b..48d80392e857 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h @@ -9,6 +9,8 @@ extern "C" { #endif +#define MF_CLASSIC_FWT_FC (60000) + typedef enum { MfClassicAuthStateIdle, MfClassicAuthStatePassed, diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c index 8ff2f1e0ab88..97d8376a1fae 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c @@ -536,11 +536,11 @@ NfcCommand mf_ultralight_listener_run(NfcGenericEvent event, void* context) { } } if(mfu_command == MfUltralightCommandProcessedSilent) { - command = NfcCommandSleep; + command = NfcCommandReset; } else if(mfu_command != MfUltralightCommandProcessed) { instance->state = MfUltraligthListenerStateIdle; instance->auth_state = MfUltralightListenerAuthStateIdle; - command = NfcCommandReset; + command = NfcCommandSleep; if(mfu_command == MfUltralightCommandNotProcessedNAK) { mf_ultralight_listener_send_short_resp(instance, MF_ULTRALIGHT_CMD_NACK); @@ -554,7 +554,7 @@ NfcCommand mf_ultralight_listener_run(NfcGenericEvent event, void* context) { mf_ultralight_composite_command_reset(instance); instance->sector = 0; instance->auth_state = MfUltralightListenerAuthStateIdle; - command = NfcCommandReset; + command = NfcCommandSleep; } return command;