From bf8fd71c00be90015811b9e6b13b88d0e7b1d5ee Mon Sep 17 00:00:00 2001 From: gornekich Date: Fri, 4 Nov 2022 11:01:44 +0400 Subject: [PATCH] NFC magic cards support (#1966) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * nfc magic: introduce nfc app to work with magic cards * nfc: add nfc device functions to API * nfc magic: add bacis scenes * nfc magic: add wrong card and write confirm scenes * nfc magic: introduce magic lib * nfc magic: write magic lib * nfc magic: add write commands to magic lib * nfc magic: work on worker * furi_hal_nfc: add bits data exchage method to API * nfc magic: rework with new API * nfc magic: add check and wipe scenes * nfc magic: add icons, gui fixes * nfc: format python src Co-authored-by: あく --- .../plugins/nfc_magic/application.fam | 20 ++ .../nfc_magic/assets/DolphinCommon_56x48.png | Bin 0 -> 1416 bytes .../nfc_magic/assets/DolphinNice_96x59.png | Bin 0 -> 2459 bytes .../plugins/nfc_magic/assets/Loading_24.png | Bin 0 -> 3649 bytes .../nfc_magic/assets/NFC_manual_60x50.png | Bin 0 -> 3804 bytes .../plugins/nfc_magic/lib/magic/magic.c | 214 ++++++++++++++++++ .../plugins/nfc_magic/lib/magic/magic.h | 15 ++ applications/plugins/nfc_magic/nfc_magic.c | 169 ++++++++++++++ applications/plugins/nfc_magic/nfc_magic.h | 3 + applications/plugins/nfc_magic/nfc_magic_i.h | 77 +++++++ .../plugins/nfc_magic/nfc_magic_worker.c | 174 ++++++++++++++ .../plugins/nfc_magic/nfc_magic_worker.h | 38 ++++ .../plugins/nfc_magic/nfc_magic_worker_i.h | 24 ++ .../nfc_magic/scenes/nfc_magic_scene.c | 30 +++ .../nfc_magic/scenes/nfc_magic_scene.h | 29 +++ .../nfc_magic/scenes/nfc_magic_scene_check.c | 87 +++++++ .../nfc_magic/scenes/nfc_magic_scene_config.h | 12 + .../scenes/nfc_magic_scene_file_select.c | 34 +++ .../scenes/nfc_magic_scene_magic_info.c | 45 ++++ .../scenes/nfc_magic_scene_not_magic.c | 44 ++++ .../nfc_magic/scenes/nfc_magic_scene_start.c | 61 +++++ .../scenes/nfc_magic_scene_success.c | 42 ++++ .../nfc_magic/scenes/nfc_magic_scene_wipe.c | 90 ++++++++ .../scenes/nfc_magic_scene_wipe_fail.c | 41 ++++ .../nfc_magic/scenes/nfc_magic_scene_write.c | 90 ++++++++ .../scenes/nfc_magic_scene_write_confirm.c | 64 ++++++ .../scenes/nfc_magic_scene_write_fail.c | 58 +++++ .../scenes/nfc_magic_scene_wrong_card.c | 53 +++++ firmware/targets/f7/api_symbols.csv | 121 ++++++++++ firmware/targets/f7/furi_hal/furi_hal_nfc.c | 11 + .../targets/furi_hal_include/furi_hal_nfc.h | 10 + lib/ST25RFAL002/include/rfal_rf.h | 9 + .../source/st25r3916/rfal_rfst25r3916.c | 17 ++ lib/nfc/SConscript | 3 + lib/nfc/nfc_device.h | 8 + 35 files changed, 1693 insertions(+) create mode 100644 applications/plugins/nfc_magic/application.fam create mode 100644 applications/plugins/nfc_magic/assets/DolphinCommon_56x48.png create mode 100644 applications/plugins/nfc_magic/assets/DolphinNice_96x59.png create mode 100644 applications/plugins/nfc_magic/assets/Loading_24.png create mode 100644 applications/plugins/nfc_magic/assets/NFC_manual_60x50.png create mode 100644 applications/plugins/nfc_magic/lib/magic/magic.c create mode 100644 applications/plugins/nfc_magic/lib/magic/magic.h create mode 100644 applications/plugins/nfc_magic/nfc_magic.c create mode 100644 applications/plugins/nfc_magic/nfc_magic.h create mode 100644 applications/plugins/nfc_magic/nfc_magic_i.h create mode 100644 applications/plugins/nfc_magic/nfc_magic_worker.c create mode 100644 applications/plugins/nfc_magic/nfc_magic_worker.h create mode 100644 applications/plugins/nfc_magic/nfc_magic_worker_i.h create mode 100644 applications/plugins/nfc_magic/scenes/nfc_magic_scene.c create mode 100644 applications/plugins/nfc_magic/scenes/nfc_magic_scene.h create mode 100644 applications/plugins/nfc_magic/scenes/nfc_magic_scene_check.c create mode 100644 applications/plugins/nfc_magic/scenes/nfc_magic_scene_config.h create mode 100644 applications/plugins/nfc_magic/scenes/nfc_magic_scene_file_select.c create mode 100644 applications/plugins/nfc_magic/scenes/nfc_magic_scene_magic_info.c create mode 100644 applications/plugins/nfc_magic/scenes/nfc_magic_scene_not_magic.c create mode 100644 applications/plugins/nfc_magic/scenes/nfc_magic_scene_start.c create mode 100644 applications/plugins/nfc_magic/scenes/nfc_magic_scene_success.c create mode 100644 applications/plugins/nfc_magic/scenes/nfc_magic_scene_wipe.c create mode 100644 applications/plugins/nfc_magic/scenes/nfc_magic_scene_wipe_fail.c create mode 100644 applications/plugins/nfc_magic/scenes/nfc_magic_scene_write.c create mode 100644 applications/plugins/nfc_magic/scenes/nfc_magic_scene_write_confirm.c create mode 100644 applications/plugins/nfc_magic/scenes/nfc_magic_scene_write_fail.c create mode 100644 applications/plugins/nfc_magic/scenes/nfc_magic_scene_wrong_card.c diff --git a/applications/plugins/nfc_magic/application.fam b/applications/plugins/nfc_magic/application.fam new file mode 100644 index 000000000..f09d65c90 --- /dev/null +++ b/applications/plugins/nfc_magic/application.fam @@ -0,0 +1,20 @@ +App( + appid="nfc_magic", + name="Nfc Magic", + apptype=FlipperAppType.EXTERNAL, + entry_point="nfc_magic_app", + requires=[ + "storage", + "gui", + ], + stack_size=4 * 1024, + order=30, + fap_icon="../../../assets/icons/Archive/125_10px.png", + fap_category="Tools", + fap_private_libs=[ + Lib( + name="magic", + ), + ], + fap_icon_assets="assets", +) diff --git a/applications/plugins/nfc_magic/assets/DolphinCommon_56x48.png b/applications/plugins/nfc_magic/assets/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/plugins/nfc_magic/assets/DolphinNice_96x59.png b/applications/plugins/nfc_magic/assets/DolphinNice_96x59.png new file mode 100644 index 0000000000000000000000000000000000000000..a299d3630239b4486e249cc501872bed5996df3b GIT binary patch literal 2459 zcmbVO3s4i+8V(M(gEFORwSrA`4O0uPn|M|5y* zB*aMDxC&7(gP9JN;POOi-9khrC>Z9YJs2U!LnVcQEEC0fDtKo&ILlzb30%M}3J^;~ zv7RzcsilOs4Mq@tD*&R;!LMSk2A~{(`HK9|hQBqEX)3sQr9Je6SZU*F-^fD-p+~Hs; zHLkO%v?>ZoxEv+F#whudr%615FkA0DYR0tMEo}3OOY#xecLWe>xV?u5KtSmC^ z7)Fmj6gjfKstiEV-*Cxbbb+&rRWuI_rBJ)ybs_f1Rn&f2>q3pYwI^|J(hdn{j{0EZIm_F zpIyIWLsRUgOItR-dUbVd|6Zo=_BU_Tj4|{{jxO#=JH4o8er(5{!nZD_j4}MH&zh~9 zVLC~y(0-D6GO0ghZD8BYzP?o{>22~lT6^d@X{SwQ8vrNY-PPIMajIwC)`s14Ep72@ zeq7YOzM`?U{+W)ocXBr`eSOcpk?Rxc=ou5&)fWW|pD};-Z0mvk9}=&`Rb&y<77W~a z(>6YM;6Y5aIU~JKZ}mQZynKHiSTQ#Bczn@&jTiN^?vPJ(jhm7cXLx0oum5P$`TceG zU+wR;OO^)8CVlnM)5p$CO&e94KJt>HccCaHGusmW_b`T6m| z-R6V6Db1pErTot?^d22ojm+2>_)FbD`_+WbDGMx9f@hO27maS2`csiV(D&Fs`PS2& zvrq18du_&zXID(!KIxsU$)iuTYuZ?zmYiP&n&i@Be{IdbS-jA2c0QAlu5NXQv_0K< z3Hvs4eeu6B7yD&CNT~gIkMV&UkRU=V!iQ(+_(O&u^ah$+s{_yn(yBYeD40HeU{xGsIT6W Zfq!wOp!QR4Q+~K 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 LTALIbyM_M?u*zuP literal 0 HcmV?d00001 diff --git a/applications/plugins/nfc_magic/assets/NFC_manual_60x50.png b/applications/plugins/nfc_magic/assets/NFC_manual_60x50.png new file mode 100644 index 0000000000000000000000000000000000000000..787c0bcfe01755f4dcadcdce004a1a0fcfb06f41 GIT binary patch literal 3804 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 IrsqTc1+$%)k^lez literal 0 HcmV?d00001 diff --git a/applications/plugins/nfc_magic/lib/magic/magic.c b/applications/plugins/nfc_magic/lib/magic/magic.c new file mode 100644 index 000000000..3cfca748b --- /dev/null +++ b/applications/plugins/nfc_magic/lib/magic/magic.c @@ -0,0 +1,214 @@ +#include "magic.h" + +#include + +#define TAG "Magic" + +#define MAGIC_CMD_WUPA (0x40) +#define MAGIC_CMD_WIPE (0x41) +#define MAGIC_CMD_READ (0x43) +#define MAGIC_CMD_WRITE (0x43) + +#define MAGIC_MIFARE_READ_CMD (0x30) +#define MAGIC_MIFARE_WRITE_CMD (0xA0) + +#define MAGIC_ACK (0x0A) + +#define MAGIC_BUFFER_SIZE (32) + +bool magic_wupa() { + bool magic_activated = false; + uint8_t tx_data[MAGIC_BUFFER_SIZE] = {}; + uint8_t rx_data[MAGIC_BUFFER_SIZE] = {}; + uint16_t rx_len = 0; + 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( + tx_data, + 7, + 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(20)); + if(ret != FuriHalNfcReturnIncompleteByte) break; + if(rx_len != 4) break; + if(rx_data[0] != MAGIC_ACK) break; + 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 write_cmd_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_WRITE; + 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(20)); + if(ret != FuriHalNfcReturnIncompleteByte) break; + if(rx_len != 4) break; + if(rx_data[0] != MAGIC_ACK) break; + + 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) { + furi_assert(data); + + bool read_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_MIFARE_READ_CMD; + tx_data[1] = block_num; + ret = furi_hal_nfc_ll_txrx_bits( + tx_data, + 2 * 8, + rx_data, + sizeof(rx_data), + &rx_len, + FURI_HAL_NFC_LL_TXRX_FLAGS_AGC_ON, + furi_hal_nfc_ll_ms2fc(20)); + + if(ret != FuriHalNfcReturnOk) break; + if(rx_len != 16 * 8) break; + memcpy(data->value, rx_data, sizeof(data->value)); + 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) { + furi_assert(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 { + tx_data[0] = MAGIC_MIFARE_WRITE_CMD; + tx_data[1] = block_num; + ret = furi_hal_nfc_ll_txrx_bits( + tx_data, + 2 * 8, + rx_data, + sizeof(rx_data), + &rx_len, + FURI_HAL_NFC_LL_TXRX_FLAGS_AGC_ON | FURI_HAL_NFC_LL_TXRX_FLAGS_CRC_RX_KEEP, + furi_hal_nfc_ll_ms2fc(20)); + if(ret != FuriHalNfcReturnIncompleteByte) break; + if(rx_len != 4) break; + if(rx_data[0] != MAGIC_ACK) break; + + memcpy(tx_data, data->value, sizeof(data->value)); + ret = furi_hal_nfc_ll_txrx_bits( + tx_data, + 16 * 8, + rx_data, + sizeof(rx_data), + &rx_len, + FURI_HAL_NFC_LL_TXRX_FLAGS_AGC_ON | FURI_HAL_NFC_LL_TXRX_FLAGS_CRC_RX_KEEP, + furi_hal_nfc_ll_ms2fc(20)); + if(ret != FuriHalNfcReturnIncompleteByte) break; + if(rx_len != 4) break; + if(rx_data[0] != MAGIC_ACK) break; + + 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_start_sleep(); +} diff --git a/applications/plugins/nfc_magic/lib/magic/magic.h b/applications/plugins/nfc_magic/lib/magic/magic.h new file mode 100644 index 000000000..64c60a0a7 --- /dev/null +++ b/applications/plugins/nfc_magic/lib/magic/magic.h @@ -0,0 +1,15 @@ +#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/plugins/nfc_magic/nfc_magic.c b/applications/plugins/nfc_magic/nfc_magic.c new file mode 100644 index 000000000..38eecba6a --- /dev/null +++ b/applications/plugins/nfc_magic/nfc_magic.c @@ -0,0 +1,169 @@ +#include "nfc_magic_i.h" + +bool nfc_magic_custom_event_callback(void* context, uint32_t event) { + furi_assert(context); + NfcMagic* nfc_magic = context; + return scene_manager_handle_custom_event(nfc_magic->scene_manager, event); +} + +bool nfc_magic_back_event_callback(void* context) { + furi_assert(context); + NfcMagic* nfc_magic = context; + return scene_manager_handle_back_event(nfc_magic->scene_manager); +} + +void nfc_magic_tick_event_callback(void* context) { + furi_assert(context); + NfcMagic* nfc_magic = context; + scene_manager_handle_tick_event(nfc_magic->scene_manager); +} + +void nfc_magic_show_loading_popup(void* context, bool show) { + NfcMagic* nfc_magic = 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_magic->view_dispatcher, NfcMagicViewLoading); + } else { + // Restore default timer priority + vTaskPrioritySet(timer_task, configTIMER_TASK_PRIORITY); + } +} + +NfcMagic* nfc_magic_alloc() { + NfcMagic* nfc_magic = malloc(sizeof(NfcMagic)); + + nfc_magic->worker = nfc_magic_worker_alloc(); + nfc_magic->view_dispatcher = view_dispatcher_alloc(); + nfc_magic->scene_manager = scene_manager_alloc(&nfc_magic_scene_handlers, nfc_magic); + view_dispatcher_enable_queue(nfc_magic->view_dispatcher); + view_dispatcher_set_event_callback_context(nfc_magic->view_dispatcher, nfc_magic); + view_dispatcher_set_custom_event_callback( + nfc_magic->view_dispatcher, nfc_magic_custom_event_callback); + view_dispatcher_set_navigation_event_callback( + nfc_magic->view_dispatcher, nfc_magic_back_event_callback); + view_dispatcher_set_tick_event_callback( + nfc_magic->view_dispatcher, nfc_magic_tick_event_callback, 100); + + // Nfc device + nfc_magic->nfc_dev = nfc_device_alloc(); + + // Open GUI record + nfc_magic->gui = furi_record_open(RECORD_GUI); + view_dispatcher_attach_to_gui( + nfc_magic->view_dispatcher, nfc_magic->gui, ViewDispatcherTypeFullscreen); + + // Open Notification record + nfc_magic->notifications = furi_record_open(RECORD_NOTIFICATION); + + // Submenu + nfc_magic->submenu = submenu_alloc(); + view_dispatcher_add_view( + nfc_magic->view_dispatcher, NfcMagicViewMenu, submenu_get_view(nfc_magic->submenu)); + + // Popup + nfc_magic->popup = popup_alloc(); + view_dispatcher_add_view( + nfc_magic->view_dispatcher, NfcMagicViewPopup, popup_get_view(nfc_magic->popup)); + + // Loading + nfc_magic->loading = loading_alloc(); + view_dispatcher_add_view( + nfc_magic->view_dispatcher, NfcMagicViewLoading, loading_get_view(nfc_magic->loading)); + + // Text Input + nfc_magic->text_input = text_input_alloc(); + view_dispatcher_add_view( + nfc_magic->view_dispatcher, + NfcMagicViewTextInput, + text_input_get_view(nfc_magic->text_input)); + + // Custom Widget + nfc_magic->widget = widget_alloc(); + view_dispatcher_add_view( + nfc_magic->view_dispatcher, NfcMagicViewWidget, widget_get_view(nfc_magic->widget)); + + return nfc_magic; +} + +void nfc_magic_free(NfcMagic* nfc_magic) { + furi_assert(nfc_magic); + + // Nfc device + nfc_device_free(nfc_magic->nfc_dev); + + // Submenu + view_dispatcher_remove_view(nfc_magic->view_dispatcher, NfcMagicViewMenu); + submenu_free(nfc_magic->submenu); + + // Popup + view_dispatcher_remove_view(nfc_magic->view_dispatcher, NfcMagicViewPopup); + popup_free(nfc_magic->popup); + + // Loading + view_dispatcher_remove_view(nfc_magic->view_dispatcher, NfcMagicViewLoading); + loading_free(nfc_magic->loading); + + // TextInput + view_dispatcher_remove_view(nfc_magic->view_dispatcher, NfcMagicViewTextInput); + text_input_free(nfc_magic->text_input); + + // Custom Widget + view_dispatcher_remove_view(nfc_magic->view_dispatcher, NfcMagicViewWidget); + widget_free(nfc_magic->widget); + + // Worker + nfc_magic_worker_stop(nfc_magic->worker); + nfc_magic_worker_free(nfc_magic->worker); + + // View Dispatcher + view_dispatcher_free(nfc_magic->view_dispatcher); + + // Scene Manager + scene_manager_free(nfc_magic->scene_manager); + + // GUI + furi_record_close(RECORD_GUI); + nfc_magic->gui = NULL; + + // Notifications + furi_record_close(RECORD_NOTIFICATION); + nfc_magic->notifications = NULL; + + free(nfc_magic); +} + +static const NotificationSequence nfc_magic_sequence_blink_start_blue = { + &message_blink_start_10, + &message_blink_set_color_blue, + &message_do_not_reset, + NULL, +}; + +static const NotificationSequence nfc_magic_sequence_blink_stop = { + &message_blink_stop, + NULL, +}; + +void nfc_magic_blink_start(NfcMagic* nfc_magic) { + notification_message(nfc_magic->notifications, &nfc_magic_sequence_blink_start_blue); +} + +void nfc_magic_blink_stop(NfcMagic* nfc_magic) { + notification_message(nfc_magic->notifications, &nfc_magic_sequence_blink_stop); +} + +int32_t nfc_magic_app(void* p) { + UNUSED(p); + NfcMagic* nfc_magic = nfc_magic_alloc(); + + scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneStart); + + view_dispatcher_run(nfc_magic->view_dispatcher); + + nfc_magic_free(nfc_magic); + + return 0; +} diff --git a/applications/plugins/nfc_magic/nfc_magic.h b/applications/plugins/nfc_magic/nfc_magic.h new file mode 100644 index 000000000..1abf1371e --- /dev/null +++ b/applications/plugins/nfc_magic/nfc_magic.h @@ -0,0 +1,3 @@ +#pragma once + +typedef struct NfcMagic NfcMagic; diff --git a/applications/plugins/nfc_magic/nfc_magic_i.h b/applications/plugins/nfc_magic/nfc_magic_i.h new file mode 100644 index 000000000..01b300826 --- /dev/null +++ b/applications/plugins/nfc_magic/nfc_magic_i.h @@ -0,0 +1,77 @@ +#pragma once + +#include "nfc_magic.h" +#include "nfc_magic_worker.h" + +#include "lib/magic/magic.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "scenes/nfc_magic_scene.h" + +#include +#include + +#include +#include "nfc_magic_icons.h" + +enum NfcMagicCustomEvent { + // Reserve first 100 events for button types and indexes, starting from 0 + NfcMagicCustomEventReserved = 100, + + NfcMagicCustomEventViewExit, + NfcMagicCustomEventWorkerExit, + NfcMagicCustomEventByteInputDone, + NfcMagicCustomEventTextInputDone, +}; + +struct NfcMagic { + NfcMagicWorker* worker; + ViewDispatcher* view_dispatcher; + Gui* gui; + NotificationApp* notifications; + SceneManager* scene_manager; + // NfcMagicDevice* dev; + NfcDevice* nfc_dev; + + FuriString* text_box_store; + + // Common Views + Submenu* submenu; + Popup* popup; + Loading* loading; + TextInput* text_input; + Widget* widget; +}; + +typedef enum { + NfcMagicViewMenu, + NfcMagicViewPopup, + NfcMagicViewLoading, + NfcMagicViewTextInput, + NfcMagicViewWidget, +} NfcMagicView; + +NfcMagic* nfc_magic_alloc(); + +void nfc_magic_text_store_set(NfcMagic* nfc_magic, const char* text, ...); + +void nfc_magic_text_store_clear(NfcMagic* nfc_magic); + +void nfc_magic_blink_start(NfcMagic* nfc_magic); + +void nfc_magic_blink_stop(NfcMagic* nfc_magic); + +void nfc_magic_show_loading_popup(void* context, bool show); diff --git a/applications/plugins/nfc_magic/nfc_magic_worker.c b/applications/plugins/nfc_magic/nfc_magic_worker.c new file mode 100644 index 000000000..0623211e2 --- /dev/null +++ b/applications/plugins/nfc_magic/nfc_magic_worker.c @@ -0,0 +1,174 @@ +#include "nfc_magic_worker_i.h" + +#include "lib/magic/magic.h" + +#define TAG "NfcMagicWorker" + +static void + nfc_magic_worker_change_state(NfcMagicWorker* nfc_magic_worker, NfcMagicWorkerState state) { + furi_assert(nfc_magic_worker); + + nfc_magic_worker->state = state; +} + +NfcMagicWorker* nfc_magic_worker_alloc() { + NfcMagicWorker* nfc_magic_worker = malloc(sizeof(NfcMagicWorker)); + + // Worker thread attributes + nfc_magic_worker->thread = furi_thread_alloc(); + furi_thread_set_name(nfc_magic_worker->thread, "NfcMagicWorker"); + furi_thread_set_stack_size(nfc_magic_worker->thread, 8192); + furi_thread_set_callback(nfc_magic_worker->thread, nfc_magic_worker_task); + furi_thread_set_context(nfc_magic_worker->thread, nfc_magic_worker); + + nfc_magic_worker->callback = NULL; + nfc_magic_worker->context = NULL; + + nfc_magic_worker_change_state(nfc_magic_worker, NfcMagicWorkerStateReady); + + return nfc_magic_worker; +} + +void nfc_magic_worker_free(NfcMagicWorker* nfc_magic_worker) { + furi_assert(nfc_magic_worker); + + furi_thread_free(nfc_magic_worker->thread); + free(nfc_magic_worker); +} + +void nfc_magic_worker_stop(NfcMagicWorker* nfc_magic_worker) { + furi_assert(nfc_magic_worker); + + nfc_magic_worker_change_state(nfc_magic_worker, NfcMagicWorkerStateStop); + furi_thread_join(nfc_magic_worker->thread); +} + +void nfc_magic_worker_start( + NfcMagicWorker* nfc_magic_worker, + NfcMagicWorkerState state, + NfcDeviceData* dev_data, + NfcMagicWorkerCallback callback, + void* context) { + furi_assert(nfc_magic_worker); + furi_assert(dev_data); + + nfc_magic_worker->callback = callback; + nfc_magic_worker->context = context; + nfc_magic_worker->dev_data = dev_data; + nfc_magic_worker_change_state(nfc_magic_worker, state); + furi_thread_start(nfc_magic_worker->thread); +} + +int32_t nfc_magic_worker_task(void* context) { + NfcMagicWorker* nfc_magic_worker = context; + + if(nfc_magic_worker->state == NfcMagicWorkerStateCheck) { + 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 == NfcMagicWorkerStateWipe) { + nfc_magic_worker_wipe(nfc_magic_worker); + } + + nfc_magic_worker_change_state(nfc_magic_worker, NfcMagicWorkerStateReady); + + return 0; +} + +void nfc_magic_worker_write(NfcMagicWorker* nfc_magic_worker) { + bool card_found_notified = false; + FuriHalNfcDevData nfc_data = {}; + MfClassicData* src_data = &nfc_magic_worker->dev_data->mf_classic_data; + + 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, "Not Magic card"); + nfc_magic_worker->callback( + NfcMagicWorkerEventWrongCard, nfc_magic_worker->context); + break; + } + if(!magic_data_access_cmd()) { + FURI_LOG_E(TAG, "Not 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); + 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; + } + } + furi_delay_ms(300); + } + magic_deactivate(); +} + +void nfc_magic_worker_check(NfcMagicWorker* nfc_magic_worker) { + bool card_found_notified = false; + + while(nfc_magic_worker->state == NfcMagicWorkerStateCheck) { + if(magic_wupa()) { + 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; + } else { + 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_wipe(NfcMagicWorker* nfc_magic_worker) { + MfClassicBlock block; + memset(&block, 0, sizeof(MfClassicBlock)); + block.value[0] = 0x01; + block.value[1] = 0x02; + block.value[2] = 0x03; + block.value[3] = 0x04; + block.value[4] = 0x04; + block.value[5] = 0x08; + block.value[6] = 0x04; + + 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); + magic_deactivate(); + break; + } + magic_deactivate(); +} diff --git a/applications/plugins/nfc_magic/nfc_magic_worker.h b/applications/plugins/nfc_magic/nfc_magic_worker.h new file mode 100644 index 000000000..9d29bb3a8 --- /dev/null +++ b/applications/plugins/nfc_magic/nfc_magic_worker.h @@ -0,0 +1,38 @@ +#pragma once + +#include + +typedef struct NfcMagicWorker NfcMagicWorker; + +typedef enum { + NfcMagicWorkerStateReady, + + NfcMagicWorkerStateCheck, + NfcMagicWorkerStateWrite, + NfcMagicWorkerStateWipe, + + NfcMagicWorkerStateStop, +} NfcMagicWorkerState; + +typedef enum { + NfcMagicWorkerEventSuccess, + NfcMagicWorkerEventFail, + NfcMagicWorkerEventCardDetected, + NfcMagicWorkerEventNoCardDetected, + NfcMagicWorkerEventWrongCard, +} NfcMagicWorkerEvent; + +typedef bool (*NfcMagicWorkerCallback)(NfcMagicWorkerEvent event, void* context); + +NfcMagicWorker* nfc_magic_worker_alloc(); + +void nfc_magic_worker_free(NfcMagicWorker* nfc_magic_worker); + +void nfc_magic_worker_stop(NfcMagicWorker* nfc_magic_worker); + +void nfc_magic_worker_start( + NfcMagicWorker* nfc_magic_worker, + NfcMagicWorkerState state, + NfcDeviceData* dev_data, + NfcMagicWorkerCallback callback, + void* context); diff --git a/applications/plugins/nfc_magic/nfc_magic_worker_i.h b/applications/plugins/nfc_magic/nfc_magic_worker_i.h new file mode 100644 index 000000000..0cde2e712 --- /dev/null +++ b/applications/plugins/nfc_magic/nfc_magic_worker_i.h @@ -0,0 +1,24 @@ +#pragma once + +#include + +#include "nfc_magic_worker.h" + +struct NfcMagicWorker { + FuriThread* thread; + + NfcDeviceData* dev_data; + + NfcMagicWorkerCallback callback; + void* context; + + NfcMagicWorkerState state; +}; + +int32_t nfc_magic_worker_task(void* context); + +void nfc_magic_worker_check(NfcMagicWorker* nfc_magic_worker); + +void nfc_magic_worker_write(NfcMagicWorker* nfc_magic_worker); + +void nfc_magic_worker_wipe(NfcMagicWorker* nfc_magic_worker); diff --git a/applications/plugins/nfc_magic/scenes/nfc_magic_scene.c b/applications/plugins/nfc_magic/scenes/nfc_magic_scene.c new file mode 100644 index 000000000..520ef2a9d --- /dev/null +++ b/applications/plugins/nfc_magic/scenes/nfc_magic_scene.c @@ -0,0 +1,30 @@ +#include "nfc_magic_scene.h" + +// Generate scene on_enter handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter, +void (*const nfc_magic_on_enter_handlers[])(void*) = { +#include "nfc_magic_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_magic_on_event_handlers[])(void* context, SceneManagerEvent event) = { +#include "nfc_magic_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_magic_on_exit_handlers[])(void* context) = { +#include "nfc_magic_scene_config.h" +}; +#undef ADD_SCENE + +// Initialize scene handlers configuration structure +const SceneManagerHandlers nfc_magic_scene_handlers = { + .on_enter_handlers = nfc_magic_on_enter_handlers, + .on_event_handlers = nfc_magic_on_event_handlers, + .on_exit_handlers = nfc_magic_on_exit_handlers, + .scene_num = NfcMagicSceneNum, +}; diff --git a/applications/plugins/nfc_magic/scenes/nfc_magic_scene.h b/applications/plugins/nfc_magic/scenes/nfc_magic_scene.h new file mode 100644 index 000000000..f1e9f715d --- /dev/null +++ b/applications/plugins/nfc_magic/scenes/nfc_magic_scene.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +// Generate scene id and total number +#define ADD_SCENE(prefix, name, id) NfcMagicScene##id, +typedef enum { +#include "nfc_magic_scene_config.h" + NfcMagicSceneNum, +} NfcMagicScene; +#undef ADD_SCENE + +extern const SceneManagerHandlers nfc_magic_scene_handlers; + +// Generate scene on_enter handlers declaration +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*); +#include "nfc_magic_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_magic_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_magic_scene_config.h" +#undef ADD_SCENE diff --git a/applications/plugins/nfc_magic/scenes/nfc_magic_scene_check.c b/applications/plugins/nfc_magic/scenes/nfc_magic_scene_check.c new file mode 100644 index 000000000..d51797242 --- /dev/null +++ b/applications/plugins/nfc_magic/scenes/nfc_magic_scene_check.c @@ -0,0 +1,87 @@ +#include "../nfc_magic_i.h" + +enum { + NfcMagicSceneCheckStateCardSearch, + NfcMagicSceneCheckStateCardFound, +}; + +bool nfc_magic_check_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_check_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, NfcMagicSceneCheck); + + if(state == NfcMagicSceneCheckStateCardSearch) { + 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); + } else { + popup_set_icon(popup, 12, 23, &I_Loading_24); + popup_set_header(popup, "Checking\nDon't move...", 52, 32, AlignLeft, AlignCenter); + } + + view_dispatcher_switch_to_view(nfc_magic->view_dispatcher, NfcMagicViewPopup); +} + +void nfc_magic_scene_check_on_enter(void* context) { + NfcMagic* nfc_magic = context; + + scene_manager_set_scene_state( + nfc_magic->scene_manager, NfcMagicSceneCheck, NfcMagicSceneCheckStateCardSearch); + nfc_magic_scene_check_setup_view(nfc_magic); + + // Setup and start worker + nfc_magic_worker_start( + nfc_magic->worker, + NfcMagicWorkerStateCheck, + &nfc_magic->nfc_dev->dev_data, + nfc_magic_check_worker_callback, + nfc_magic); + nfc_magic_blink_start(nfc_magic); +} + +bool nfc_magic_scene_check_on_event(void* context, SceneManagerEvent event) { + NfcMagic* nfc_magic = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcMagicWorkerEventSuccess) { + scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneMagicInfo); + consumed = true; + } else if(event.event == NfcMagicWorkerEventWrongCard) { + scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneNotMagic); + consumed = true; + } else if(event.event == NfcMagicWorkerEventCardDetected) { + scene_manager_set_scene_state( + nfc_magic->scene_manager, NfcMagicSceneCheck, NfcMagicSceneCheckStateCardFound); + nfc_magic_scene_check_setup_view(nfc_magic); + consumed = true; + } else if(event.event == NfcMagicWorkerEventNoCardDetected) { + scene_manager_set_scene_state( + nfc_magic->scene_manager, NfcMagicSceneCheck, NfcMagicSceneCheckStateCardSearch); + nfc_magic_scene_check_setup_view(nfc_magic); + consumed = true; + } + } + return consumed; +} + +void nfc_magic_scene_check_on_exit(void* context) { + NfcMagic* nfc_magic = context; + + nfc_magic_worker_stop(nfc_magic->worker); + scene_manager_set_scene_state( + nfc_magic->scene_manager, NfcMagicSceneCheck, NfcMagicSceneCheckStateCardSearch); + // Clear view + popup_reset(nfc_magic->popup); + + nfc_magic_blink_stop(nfc_magic); +} diff --git a/applications/plugins/nfc_magic/scenes/nfc_magic_scene_config.h b/applications/plugins/nfc_magic/scenes/nfc_magic_scene_config.h new file mode 100644 index 000000000..557e26914 --- /dev/null +++ b/applications/plugins/nfc_magic/scenes/nfc_magic_scene_config.h @@ -0,0 +1,12 @@ +ADD_SCENE(nfc_magic, start, Start) +ADD_SCENE(nfc_magic, file_select, FileSelect) +ADD_SCENE(nfc_magic, write_confirm, WriteConfirm) +ADD_SCENE(nfc_magic, wrong_card, WrongCard) +ADD_SCENE(nfc_magic, write, Write) +ADD_SCENE(nfc_magic, write_fail, WriteFail) +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, wipe, Wipe) +ADD_SCENE(nfc_magic, wipe_fail, WipeFail) diff --git a/applications/plugins/nfc_magic/scenes/nfc_magic_scene_file_select.c b/applications/plugins/nfc_magic/scenes/nfc_magic_scene_file_select.c new file mode 100644 index 000000000..a19237ed4 --- /dev/null +++ b/applications/plugins/nfc_magic/scenes/nfc_magic_scene_file_select.c @@ -0,0 +1,34 @@ +#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); +} + +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); + + if(nfc_file_select(nfc_magic->nfc_dev)) { + if(nfc_magic_scene_file_select_is_file_suitable(nfc_magic->nfc_dev)) { + scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneWriteConfirm); + } else { + scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneWrongCard); + } + } else { + scene_manager_previous_scene(nfc_magic->scene_manager); + } +} + +bool nfc_magic_scene_file_select_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + UNUSED(event); + return false; +} + +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); +} diff --git a/applications/plugins/nfc_magic/scenes/nfc_magic_scene_magic_info.c b/applications/plugins/nfc_magic/scenes/nfc_magic_scene_magic_info.c new file mode 100644 index 000000000..e9b226b3a --- /dev/null +++ b/applications/plugins/nfc_magic/scenes/nfc_magic_scene_magic_info.c @@ -0,0 +1,45 @@ +#include "../nfc_magic_i.h" + +void nfc_magic_scene_magic_info_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_magic_info_on_enter(void* context) { + NfcMagic* nfc_magic = context; + Widget* widget = nfc_magic->widget; + + 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_button_element( + widget, GuiButtonTypeLeft, "Retry", nfc_magic_scene_magic_info_widget_callback, nfc_magic); + + // Setup and start worker + view_dispatcher_switch_to_view(nfc_magic->view_dispatcher, NfcMagicViewWidget); +} + +bool nfc_magic_scene_magic_info_on_event(void* context, SceneManagerEvent event) { + NfcMagic* nfc_magic = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeLeft) { + consumed = scene_manager_previous_scene(nfc_magic->scene_manager); + } + } + return consumed; +} + +void nfc_magic_scene_magic_info_on_exit(void* context) { + NfcMagic* nfc_magic = context; + + widget_reset(nfc_magic->widget); +} diff --git a/applications/plugins/nfc_magic/scenes/nfc_magic_scene_not_magic.c b/applications/plugins/nfc_magic/scenes/nfc_magic_scene_not_magic.c new file mode 100644 index 000000000..b87f7f383 --- /dev/null +++ b/applications/plugins/nfc_magic/scenes/nfc_magic_scene_not_magic.c @@ -0,0 +1,44 @@ +#include "../nfc_magic_i.h" + +void nfc_magic_scene_not_magic_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_not_magic_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, 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_add_button_element( + widget, GuiButtonTypeLeft, "Retry", nfc_magic_scene_not_magic_widget_callback, nfc_magic); + + // Setup and start worker + view_dispatcher_switch_to_view(nfc_magic->view_dispatcher, NfcMagicViewWidget); +} + +bool nfc_magic_scene_not_magic_on_event(void* context, SceneManagerEvent event) { + NfcMagic* nfc_magic = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeLeft) { + consumed = scene_manager_previous_scene(nfc_magic->scene_manager); + } + } + return consumed; +} + +void nfc_magic_scene_not_magic_on_exit(void* context) { + NfcMagic* nfc_magic = context; + + widget_reset(nfc_magic->widget); +} diff --git a/applications/plugins/nfc_magic/scenes/nfc_magic_scene_start.c b/applications/plugins/nfc_magic/scenes/nfc_magic_scene_start.c new file mode 100644 index 000000000..f2984443f --- /dev/null +++ b/applications/plugins/nfc_magic/scenes/nfc_magic_scene_start.c @@ -0,0 +1,61 @@ +#include "../nfc_magic_i.h" +enum SubmenuIndex { + SubmenuIndexCheck, + SubmenuIndexWriteGen1A, + SubmenuIndexWipe, +}; + +void nfc_magic_scene_start_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_start_on_enter(void* context) { + NfcMagic* nfc_magic = context; + + Submenu* submenu = nfc_magic->submenu; + submenu_add_item( + submenu, + "Check Magic Tag", + SubmenuIndexCheck, + nfc_magic_scene_start_submenu_callback, + nfc_magic); + submenu_add_item( + submenu, + "Write Gen1A", + SubmenuIndexWriteGen1A, + 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)); + view_dispatcher_switch_to_view(nfc_magic->view_dispatcher, NfcMagicViewMenu); +} + +bool nfc_magic_scene_start_on_event(void* context, SceneManagerEvent event) { + NfcMagic* nfc_magic = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexCheck) { + scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneCheck); + consumed = true; + } else if(event.event == SubmenuIndexWriteGen1A) { + 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, NfcMagicSceneStart, event.event); + } + + return consumed; +} + +void nfc_magic_scene_start_on_exit(void* context) { + NfcMagic* nfc_magic = context; + submenu_reset(nfc_magic->submenu); +} diff --git a/applications/plugins/nfc_magic/scenes/nfc_magic_scene_success.c b/applications/plugins/nfc_magic/scenes/nfc_magic_scene_success.c new file mode 100644 index 000000000..37441e80e --- /dev/null +++ b/applications/plugins/nfc_magic/scenes/nfc_magic_scene_success.c @@ -0,0 +1,42 @@ +#include "../nfc_magic_i.h" + +void nfc_magic_scene_success_popup_callback(void* context) { + NfcMagic* nfc_magic = context; + view_dispatcher_send_custom_event(nfc_magic->view_dispatcher, NfcMagicCustomEventViewExit); +} + +void nfc_magic_scene_success_on_enter(void* context) { + NfcMagic* nfc_magic = context; + + notification_message(nfc_magic->notifications, &sequence_success); + + Popup* popup = nfc_magic->popup; + popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); + popup_set_header(popup, "Success!", 10, 20, AlignLeft, AlignBottom); + popup_set_timeout(popup, 1500); + popup_set_context(popup, nfc_magic); + popup_set_callback(popup, nfc_magic_scene_success_popup_callback); + popup_enable_timeout(popup); + + view_dispatcher_switch_to_view(nfc_magic->view_dispatcher, NfcMagicViewPopup); +} + +bool nfc_magic_scene_success_on_event(void* context, SceneManagerEvent event) { + NfcMagic* nfc_magic = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcMagicCustomEventViewExit) { + consumed = scene_manager_search_and_switch_to_previous_scene( + nfc_magic->scene_manager, NfcMagicSceneStart); + } + } + return consumed; +} + +void nfc_magic_scene_success_on_exit(void* context) { + NfcMagic* nfc_magic = context; + + // Clear view + popup_reset(nfc_magic->popup); +} diff --git a/applications/plugins/nfc_magic/scenes/nfc_magic_scene_wipe.c b/applications/plugins/nfc_magic/scenes/nfc_magic_scene_wipe.c new file mode 100644 index 000000000..1ca194286 --- /dev/null +++ b/applications/plugins/nfc_magic/scenes/nfc_magic_scene_wipe.c @@ -0,0 +1,90 @@ +#include "../nfc_magic_i.h" + +enum { + NfcMagicSceneWipeStateCardSearch, + NfcMagicSceneWipeStateCardFound, +}; + +bool nfc_magic_wipe_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_wipe_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, NfcMagicSceneWipe); + + 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); + } else { + popup_set_icon(popup, 12, 23, &I_Loading_24); + popup_set_header(popup, "Wiping\nDon't move...", 52, 32, AlignLeft, AlignCenter); + } + + view_dispatcher_switch_to_view(nfc_magic->view_dispatcher, NfcMagicViewPopup); +} + +void nfc_magic_scene_wipe_on_enter(void* context) { + NfcMagic* nfc_magic = context; + + scene_manager_set_scene_state( + nfc_magic->scene_manager, NfcMagicSceneWipe, NfcMagicSceneWipeStateCardSearch); + nfc_magic_scene_wipe_setup_view(nfc_magic); + + // Setup and start worker + nfc_magic_worker_start( + nfc_magic->worker, + NfcMagicWorkerStateWipe, + &nfc_magic->nfc_dev->dev_data, + nfc_magic_wipe_worker_callback, + nfc_magic); + nfc_magic_blink_start(nfc_magic); +} + +bool nfc_magic_scene_wipe_on_event(void* context, SceneManagerEvent event) { + NfcMagic* nfc_magic = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcMagicWorkerEventSuccess) { + scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneSuccess); + consumed = true; + } else if(event.event == NfcMagicWorkerEventFail) { + scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneWipeFail); + consumed = true; + } else if(event.event == NfcMagicWorkerEventWrongCard) { + scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneNotMagic); + consumed = true; + } else if(event.event == NfcMagicWorkerEventCardDetected) { + scene_manager_set_scene_state( + nfc_magic->scene_manager, NfcMagicSceneWipe, NfcMagicSceneWipeStateCardFound); + nfc_magic_scene_wipe_setup_view(nfc_magic); + consumed = true; + } else if(event.event == NfcMagicWorkerEventNoCardDetected) { + scene_manager_set_scene_state( + nfc_magic->scene_manager, NfcMagicSceneWipe, NfcMagicSceneWipeStateCardSearch); + nfc_magic_scene_wipe_setup_view(nfc_magic); + consumed = true; + } + } + return consumed; +} + +void nfc_magic_scene_wipe_on_exit(void* context) { + NfcMagic* nfc_magic = context; + + nfc_magic_worker_stop(nfc_magic->worker); + scene_manager_set_scene_state( + nfc_magic->scene_manager, NfcMagicSceneWipe, NfcMagicSceneWipeStateCardSearch); + // Clear view + popup_reset(nfc_magic->popup); + + nfc_magic_blink_stop(nfc_magic); +} diff --git a/applications/plugins/nfc_magic/scenes/nfc_magic_scene_wipe_fail.c b/applications/plugins/nfc_magic/scenes/nfc_magic_scene_wipe_fail.c new file mode 100644 index 000000000..828b65e6c --- /dev/null +++ b/applications/plugins/nfc_magic/scenes/nfc_magic_scene_wipe_fail.c @@ -0,0 +1,41 @@ +#include "../nfc_magic_i.h" + +void nfc_magic_scene_wipe_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_wipe_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, 73, 17, &I_DolphinCommon_56x48); + widget_add_string_element(widget, 3, 4, AlignLeft, AlignTop, FontPrimary, "Wipe failed"); + widget_add_button_element( + widget, GuiButtonTypeLeft, "Retry", nfc_magic_scene_wipe_fail_widget_callback, nfc_magic); + + // Setup and start worker + view_dispatcher_switch_to_view(nfc_magic->view_dispatcher, NfcMagicViewWidget); +} + +bool nfc_magic_scene_wipe_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_previous_scene(nfc_magic->scene_manager); + } + } + return consumed; +} + +void nfc_magic_scene_wipe_fail_on_exit(void* context) { + NfcMagic* nfc_magic = context; + + widget_reset(nfc_magic->widget); +} diff --git a/applications/plugins/nfc_magic/scenes/nfc_magic_scene_write.c b/applications/plugins/nfc_magic/scenes/nfc_magic_scene_write.c new file mode 100644 index 000000000..c3e6f962a --- /dev/null +++ b/applications/plugins/nfc_magic/scenes/nfc_magic_scene_write.c @@ -0,0 +1,90 @@ +#include "../nfc_magic_i.h" + +enum { + NfcMagicSceneWriteStateCardSearch, + NfcMagicSceneWriteStateCardFound, +}; + +bool nfc_magic_write_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_write_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, NfcMagicSceneWrite); + + if(state == NfcMagicSceneWriteStateCardSearch) { + popup_set_text( + nfc_magic->popup, "Apply card to\nthe 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_write_on_enter(void* context) { + NfcMagic* nfc_magic = context; + + scene_manager_set_scene_state( + nfc_magic->scene_manager, NfcMagicSceneWrite, NfcMagicSceneWriteStateCardSearch); + nfc_magic_scene_write_setup_view(nfc_magic); + + // Setup and start worker + nfc_magic_worker_start( + nfc_magic->worker, + NfcMagicWorkerStateWrite, + &nfc_magic->nfc_dev->dev_data, + nfc_magic_write_worker_callback, + nfc_magic); + nfc_magic_blink_start(nfc_magic); +} + +bool nfc_magic_scene_write_on_event(void* context, SceneManagerEvent event) { + NfcMagic* nfc_magic = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcMagicWorkerEventSuccess) { + scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneSuccess); + consumed = true; + } else if(event.event == NfcMagicWorkerEventFail) { + scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneWriteFail); + consumed = true; + } else if(event.event == NfcMagicWorkerEventWrongCard) { + scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneNotMagic); + consumed = true; + } else if(event.event == NfcMagicWorkerEventCardDetected) { + scene_manager_set_scene_state( + nfc_magic->scene_manager, NfcMagicSceneWrite, NfcMagicSceneWriteStateCardFound); + nfc_magic_scene_write_setup_view(nfc_magic); + consumed = true; + } else if(event.event == NfcMagicWorkerEventNoCardDetected) { + scene_manager_set_scene_state( + nfc_magic->scene_manager, NfcMagicSceneWrite, NfcMagicSceneWriteStateCardSearch); + nfc_magic_scene_write_setup_view(nfc_magic); + consumed = true; + } + } + return consumed; +} + +void nfc_magic_scene_write_on_exit(void* context) { + NfcMagic* nfc_magic = context; + + nfc_magic_worker_stop(nfc_magic->worker); + scene_manager_set_scene_state( + nfc_magic->scene_manager, NfcMagicSceneWrite, NfcMagicSceneWriteStateCardSearch); + // Clear view + popup_reset(nfc_magic->popup); + + nfc_magic_blink_stop(nfc_magic); +} diff --git a/applications/plugins/nfc_magic/scenes/nfc_magic_scene_write_confirm.c b/applications/plugins/nfc_magic/scenes/nfc_magic_scene_write_confirm.c new file mode 100644 index 000000000..d31c1c194 --- /dev/null +++ b/applications/plugins/nfc_magic/scenes/nfc_magic_scene_write_confirm.c @@ -0,0 +1,64 @@ +#include "../nfc_magic_i.h" + +void nfc_magic_scene_write_confirm_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_write_confirm_on_enter(void* context) { + NfcMagic* nfc_magic = context; + Widget* widget = nfc_magic->widget; + + widget_add_string_element(widget, 3, 0, AlignLeft, AlignTop, FontPrimary, "Risky operation"); + widget_add_text_box_element( + widget, + 0, + 13, + 128, + 54, + AlignLeft, + AlignTop, + "Writing to this card will change manufacturer block. On some cards it may not be rewritten", + false); + widget_add_button_element( + widget, + GuiButtonTypeCenter, + "Continue", + nfc_magic_scene_write_confirm_widget_callback, + nfc_magic); + widget_add_button_element( + widget, + GuiButtonTypeLeft, + "Back", + nfc_magic_scene_write_confirm_widget_callback, + nfc_magic); + + // Setup and start worker + view_dispatcher_switch_to_view(nfc_magic->view_dispatcher, NfcMagicViewWidget); +} + +bool nfc_magic_scene_write_confirm_on_event(void* context, SceneManagerEvent event) { + NfcMagic* nfc_magic = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeLeft) { + consumed = scene_manager_previous_scene(nfc_magic->scene_manager); + } else if(event.event == GuiButtonTypeCenter) { + scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneWrite); + consumed = true; + } + } + return consumed; +} + +void nfc_magic_scene_write_confirm_on_exit(void* context) { + NfcMagic* nfc_magic = context; + + widget_reset(nfc_magic->widget); +} diff --git a/applications/plugins/nfc_magic/scenes/nfc_magic_scene_write_fail.c b/applications/plugins/nfc_magic/scenes/nfc_magic_scene_write_fail.c new file mode 100644 index 000000000..8a465bf61 --- /dev/null +++ b/applications/plugins/nfc_magic/scenes/nfc_magic_scene_write_fail.c @@ -0,0 +1,58 @@ +#include "../nfc_magic_i.h" + +void nfc_magic_scene_write_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_write_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, "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_magic_scene_write_fail_widget_callback, nfc_magic); + + // Setup and start worker + view_dispatcher_switch_to_view(nfc_magic->view_dispatcher, NfcMagicViewWidget); +} + +bool nfc_magic_scene_write_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_write_fail_on_exit(void* context) { + NfcMagic* nfc_magic = context; + + widget_reset(nfc_magic->widget); +} diff --git a/applications/plugins/nfc_magic/scenes/nfc_magic_scene_wrong_card.c b/applications/plugins/nfc_magic/scenes/nfc_magic_scene_wrong_card.c new file mode 100644 index 000000000..69bf9eb50 --- /dev/null +++ b/applications/plugins/nfc_magic/scenes/nfc_magic_scene_wrong_card.c @@ -0,0 +1,53 @@ +#include "../nfc_magic_i.h" + +void nfc_magic_scene_wrong_card_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_wrong_card_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, 73, 17, &I_DolphinCommon_56x48); + widget_add_string_element( + widget, 1, 4, AlignLeft, AlignTop, FontPrimary, "This is wrong card"); + widget_add_string_multiline_element( + widget, + 1, + 17, + AlignLeft, + AlignTop, + FontSecondary, + "Writing is supported\nonly for 4 bytes UID\nMifare CLassic 1k"); + widget_add_button_element( + widget, GuiButtonTypeLeft, "Retry", nfc_magic_scene_wrong_card_widget_callback, nfc_magic); + + // Setup and start worker + view_dispatcher_switch_to_view(nfc_magic->view_dispatcher, NfcMagicViewWidget); +} + +bool nfc_magic_scene_wrong_card_on_event(void* context, SceneManagerEvent event) { + NfcMagic* nfc_magic = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeLeft) { + consumed = scene_manager_previous_scene(nfc_magic->scene_manager); + } + } + return consumed; +} + +void nfc_magic_scene_wrong_card_on_exit(void* context) { + NfcMagic* nfc_magic = context; + + widget_reset(nfc_magic->widget); +} diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 65e6f4857..0c10258f7 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -148,6 +148,7 @@ Header,+,lib/libusb_stm32/inc/usbd_core.h,, Header,+,lib/mbedtls/include/mbedtls/des.h,, Header,+,lib/mbedtls/include/mbedtls/sha1.h,, Header,+,lib/micro-ecc/uECC.h,, +Header,+,lib/nfc/nfc_device.h,, Header,+,lib/one_wire/ibutton/ibutton_worker.h,, Header,+,lib/one_wire/maxim_crc.h,, Header,+,lib/one_wire/one_wire_device.h,, @@ -668,6 +669,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,-,ctermid,char*,char* Function,-,ctime,char*,const time_t* Function,-,ctime_r,char*,"const time_t*, char*" @@ -750,6 +759,8 @@ Function,+,elements_text_box,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t, 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 @@ -1161,6 +1172,7 @@ Function,+,furi_hal_nfc_ll_set_fdt_poll,void,uint32_t Function,+,furi_hal_nfc_ll_set_guard_time,void,uint32_t Function,+,furi_hal_nfc_ll_set_mode,FuriHalNfcReturn,"FuriHalNfcMode, FuriHalNfcBitrate, FuriHalNfcBitrate" Function,+,furi_hal_nfc_ll_txrx,FuriHalNfcReturn,"uint8_t*, uint16_t, uint8_t*, uint16_t, uint16_t*, uint32_t, uint32_t" +Function,+,furi_hal_nfc_ll_txrx_bits,FuriHalNfcReturn,"uint8_t*, uint16_t, uint8_t*, uint16_t, uint16_t*, uint32_t, uint32_t" Function,+,furi_hal_nfc_ll_txrx_off,void, Function,+,furi_hal_nfc_ll_txrx_on,void, Function,+,furi_hal_nfc_sleep,void, @@ -1806,6 +1818,100 @@ 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*, MfClassicAuthContext*, uint64_t" +Function,-,mf_classic_auth_init_context,void,"MfClassicAuthContext*, uint8_t" +Function,-,mf_classic_authenticate,_Bool,"FuriHalNfcTxRxContext*, uint8_t, uint64_t, MfClassicKey" +Function,-,mf_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 +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_emulator,_Bool,"MfClassicEmulator*, FuriHalNfcTxRxContext*" +Function,-,mf_classic_get_classic_type,MfClassicType,"int8_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_sectors_num,uint8_t,MfClassicType +Function,-,mf_classic_get_type_str,const char*,MfClassicType +Function,-,mf_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_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_update_card,uint8_t,"FuriHalNfcTxRxContext*, MfClassicData*" +Function,-,mf_classic_write_block,_Bool,"FuriHalNfcTxRxContext*, MfClassicBlock*, uint8_t, MfClassicKey, uint64_t" +Function,-,mf_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*" +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_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,-,mkdtemp,char*,char* Function,-,mkostemp,int,"char*, int" Function,-,mkostemps,int,"char*, int, int" @@ -1829,6 +1935,19 @@ 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,-,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" @@ -1913,6 +2032,7 @@ Function,+,power_reboot,void,PowerBootMode Function,+,powf,float,"float, float" Function,-,powl,long double,"long double, long double" Function,-,printf,int,"const char*, ..." +Function,-,prng_successor,uint32_t,"uint32_t, uint32_t" Function,+,protocol_dict_alloc,ProtocolDict*,"const ProtocolBase**, size_t" Function,+,protocol_dict_decoders_feed,ProtocolId,"ProtocolDict*, _Bool, uint32_t" Function,+,protocol_dict_decoders_feed_by_feature,ProtocolId,"ProtocolDict*, uint32_t, _Bool, uint32_t" @@ -2129,6 +2249,7 @@ Function,-,rfalT1TPollerRall,ReturnCode,"const uint8_t*, uint8_t*, uint16_t, uin Function,-,rfalT1TPollerRid,ReturnCode,rfalT1TRidRes* Function,-,rfalT1TPollerWrite,ReturnCode,"const uint8_t*, uint8_t, uint8_t" Function,-,rfalTransceiveBitsBlockingTx,ReturnCode,"uint8_t*, uint16_t, uint8_t*, uint16_t, uint16_t*, uint32_t, uint32_t" +Function,-,rfalTransceiveBitsBlockingTxRx,ReturnCode,"uint8_t*, uint16_t, uint8_t*, uint16_t, uint16_t*, uint32_t, uint32_t" Function,-,rfalTransceiveBlockingRx,ReturnCode, Function,-,rfalTransceiveBlockingTx,ReturnCode,"uint8_t*, uint16_t, uint8_t*, uint16_t, uint16_t*, uint32_t, uint32_t" Function,-,rfalTransceiveBlockingTxRx,ReturnCode,"uint8_t*, uint16_t, uint8_t*, uint16_t, uint16_t*, uint32_t, uint32_t" diff --git a/firmware/targets/f7/furi_hal/furi_hal_nfc.c b/firmware/targets/f7/furi_hal/furi_hal_nfc.c index 3ebf4f82b..2d27313ae 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_nfc.c +++ b/firmware/targets/f7/furi_hal/furi_hal_nfc.c @@ -786,6 +786,17 @@ FuriHalNfcReturn furi_hal_nfc_ll_txrx( return rfalTransceiveBlockingTxRx(txBuf, txBufLen, rxBuf, rxBufLen, actLen, flags, fwt); } +FuriHalNfcReturn furi_hal_nfc_ll_txrx_bits( + uint8_t* txBuf, + uint16_t txBufLen, + uint8_t* rxBuf, + uint16_t rxBufLen, + uint16_t* actLen, + uint32_t flags, + uint32_t fwt) { + return rfalTransceiveBitsBlockingTxRx(txBuf, txBufLen, rxBuf, rxBufLen, actLen, flags, fwt); +} + void furi_hal_nfc_ll_poll() { rfalWorker(); } \ No newline at end of file diff --git a/firmware/targets/furi_hal_include/furi_hal_nfc.h b/firmware/targets/furi_hal_include/furi_hal_nfc.h index 90d968fea..d3f6de602 100644 --- a/firmware/targets/furi_hal_include/furi_hal_nfc.h +++ b/firmware/targets/furi_hal_include/furi_hal_nfc.h @@ -398,6 +398,7 @@ void furi_hal_nfc_ll_txrx_on(); void furi_hal_nfc_ll_txrx_off(); +// TODO rework all pollers with furi_hal_nfc_ll_txrx_bits FuriHalNfcReturn furi_hal_nfc_ll_txrx( uint8_t* txBuf, uint16_t txBufLen, @@ -407,6 +408,15 @@ FuriHalNfcReturn furi_hal_nfc_ll_txrx( uint32_t flags, uint32_t fwt); +FuriHalNfcReturn furi_hal_nfc_ll_txrx_bits( + uint8_t* txBuf, + uint16_t txBufLen, + uint8_t* rxBuf, + uint16_t rxBufLen, + uint16_t* actLen, + uint32_t flags, + uint32_t fwt); + void furi_hal_nfc_ll_poll(); #ifdef __cplusplus diff --git a/lib/ST25RFAL002/include/rfal_rf.h b/lib/ST25RFAL002/include/rfal_rf.h index e1b864830..35e9a4454 100644 --- a/lib/ST25RFAL002/include/rfal_rf.h +++ b/lib/ST25RFAL002/include/rfal_rf.h @@ -1496,6 +1496,15 @@ ReturnCode rfalTransceiveBlockingTxRx( uint32_t flags, uint32_t fwt); +ReturnCode rfalTransceiveBitsBlockingTxRx( + uint8_t* txBuf, + uint16_t txBufLen, + uint8_t* rxBuf, + uint16_t rxBufLen, + uint16_t* actLen, + uint32_t flags, + uint32_t fwt); + ReturnCode rfalTransceiveBitsBlockingTx( uint8_t* txBuf, uint16_t txBufLen, diff --git a/lib/ST25RFAL002/source/st25r3916/rfal_rfst25r3916.c b/lib/ST25RFAL002/source/st25r3916/rfal_rfst25r3916.c index 9ad35bcb6..0bad67a6d 100644 --- a/lib/ST25RFAL002/source/st25r3916/rfal_rfst25r3916.c +++ b/lib/ST25RFAL002/source/st25r3916/rfal_rfst25r3916.c @@ -1607,6 +1607,23 @@ ReturnCode rfalTransceiveBlockingTxRx( return ret; } +ReturnCode rfalTransceiveBitsBlockingTxRx( + uint8_t* txBuf, + uint16_t txBufLen, + uint8_t* rxBuf, + uint16_t rxBufLen, + uint16_t* actLen, + uint32_t flags, + uint32_t fwt) { + ReturnCode ret; + + EXIT_ON_ERR( + ret, rfalTransceiveBitsBlockingTx(txBuf, txBufLen, rxBuf, rxBufLen, actLen, flags, fwt)); + ret = rfalTransceiveBlockingRx(); + + return ret; +} + /*******************************************************************************/ static ReturnCode rfalRunTransceiveWorker(void) { if(gRFAL.state == RFAL_STATE_TXRX) { diff --git a/lib/nfc/SConscript b/lib/nfc/SConscript index 657f3a9e5..c6b70a677 100644 --- a/lib/nfc/SConscript +++ b/lib/nfc/SConscript @@ -4,6 +4,9 @@ env.Append( CPPPATH=[ "#/lib/nfc", ], + SDK_HEADERS=[ + File("#/lib/nfc/nfc_device.h"), + ], ) libenv = env.Clone(FW_LIB_NAME="nfc") diff --git a/lib/nfc/nfc_device.h b/lib/nfc/nfc_device.h index 6cac72c6b..c8e8517ae 100644 --- a/lib/nfc/nfc_device.h +++ b/lib/nfc/nfc_device.h @@ -12,6 +12,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + #define NFC_DEV_NAME_MAX_LEN 22 #define NFC_READER_DATA_MAX_SIZE 64 #define NFC_DICT_KEY_BATCH_SIZE 50 @@ -101,3 +105,7 @@ bool nfc_device_delete(NfcDevice* dev, bool use_load_path); bool nfc_device_restore(NfcDevice* dev, bool use_load_path); void nfc_device_set_loading_callback(NfcDevice* dev, NfcLoadingCallback callback, void* context); + +#ifdef __cplusplus +} +#endif