From 4760c1c5ce0a0f3ac622b6b9b6eb09be1d43636b Mon Sep 17 00:00:00 2001 From: r3df0xx Date: Wed, 18 May 2022 17:23:59 +0300 Subject: [PATCH] fetch wplugins --- applications/applications.c | 32 ++-- applications/nfc/nfc_worker.c | 23 +++ applications/nfc/nfc_worker.h | 1 + applications/nfc/scenes/nfc_scene_config.h | 1 + .../scenes/nfc_scene_emulate_mifare_classic.c | 64 +++++++ .../nfc/scenes/nfc_scene_saved_menu.c | 12 +- assets/compiled/assets_icons.c | 74 ++++---- assets/compiled/assets_icons.h | 1 + .../TouchTunes_14/frame_00_delay-0.04s.png | Bin 0 -> 470 bytes .../TouchTunes_14/frame_01_delay-0.04s.png | Bin 0 -> 411 bytes .../TouchTunes_14/frame_02_delay-0.04s.png | Bin 0 -> 411 bytes .../TouchTunes_14/frame_03_delay-0.04s.png | Bin 0 -> 411 bytes .../TouchTunes_14/frame_04_delay-0.04s.png | Bin 0 -> 401 bytes .../TouchTunes_14/frame_05_delay-0.04s.png | Bin 0 -> 397 bytes .../TouchTunes_14/frame_06_delay-0.04s.png | Bin 0 -> 400 bytes .../TouchTunes_14/frame_07_delay-0.04s.png | Bin 0 -> 404 bytes .../TouchTunes_14/frame_08_delay-0.04s.png | Bin 0 -> 414 bytes .../TouchTunes_14/frame_09_delay-0.04s.png | Bin 0 -> 427 bytes .../TouchTunes_14/frame_10_delay-0.04s.png | Bin 0 -> 427 bytes .../TouchTunes_14/frame_11_delay-0.04s.png | Bin 0 -> 426 bytes .../TouchTunes_14/frame_12_delay-0.04s.png | Bin 0 -> 431 bytes .../TouchTunes_14/frame_13_delay-0.04s.png | Bin 0 -> 424 bytes .../TouchTunes_14/frame_14_delay-0.04s.png | Bin 0 -> 424 bytes .../TouchTunes_14/frame_15_delay-0.04s.png | Bin 0 -> 424 bytes .../TouchTunes_14/frame_16_delay-0.04s.png | Bin 0 -> 424 bytes .../TouchTunes_14/frame_17_delay-0.04s.png | Bin 0 -> 426 bytes .../TouchTunes_14/frame_18_delay-0.04s.png | Bin 0 -> 418 bytes .../TouchTunes_14/frame_19_delay-0.04s.png | Bin 0 -> 419 bytes .../TouchTunes_14/frame_20_delay-0.04s.png | Bin 0 -> 425 bytes .../TouchTunes_14/frame_21_delay-0.04s.png | Bin 0 -> 415 bytes .../TouchTunes_14/frame_22_delay-0.04s.png | Bin 0 -> 405 bytes .../TouchTunes_14/frame_23_delay-0.04s.png | Bin 0 -> 394 bytes .../TouchTunes_14/frame_24_delay-0.04s.png | Bin 0 -> 401 bytes .../TouchTunes_14/frame_25_delay-0.04s.png | Bin 0 -> 401 bytes .../TouchTunes_14/frame_26_delay-0.04s.png | Bin 0 -> 404 bytes .../TouchTunes_14/frame_27_delay-0.04s.png | Bin 0 -> 410 bytes .../TouchTunes_14/frame_28_delay-0.04s.png | Bin 0 -> 411 bytes .../TouchTunes_14/frame_29_delay-0.04s.png | Bin 0 -> 411 bytes .../icons/MainMenu/TouchTunes_14/frame_rate | 1 + .../MainMenu/UniversalRemote_14/frame_1.png | Bin 0 -> 170 bytes .../MainMenu/UniversalRemote_14/frame_2.png | Bin 0 -> 165 bytes .../MainMenu/UniversalRemote_14/frame_3.png | Bin 0 -> 171 bytes .../MainMenu/UniversalRemote_14/frame_4.png | Bin 0 -> 168 bytes .../MainMenu/UniversalRemote_14/frame_5.png | Bin 0 -> 169 bytes .../MainMenu/UniversalRemote_14/frame_6.png | Bin 0 -> 165 bytes .../MainMenu/UniversalRemote_14/frame_7.png | Bin 0 -> 166 bytes firmware/targets/f7/furi_hal/furi_hal_nfc.c | 89 ++++++++- .../targets/furi_hal_include/furi_hal_nfc.h | 5 + lib/digital_signal/digital_signal.c | 173 ++++++++++++++++++ lib/digital_signal/digital_signal.h | 28 +++ lib/lib.mk | 5 + lib/nfc_protocols/crypto1.c | 2 +- lib/nfc_protocols/crypto1.h | 2 +- lib/nfc_protocols/mifare_classic.c | 115 ++++++++++++ lib/nfc_protocols/mifare_classic.h | 8 + lib/nfc_protocols/nfca.c | 72 ++++++++ lib/nfc_protocols/nfca.h | 14 ++ 57 files changed, 664 insertions(+), 58 deletions(-) create mode 100644 applications/nfc/scenes/nfc_scene_emulate_mifare_classic.c create mode 100644 assets/icons/MainMenu/TouchTunes_14/frame_00_delay-0.04s.png create mode 100644 assets/icons/MainMenu/TouchTunes_14/frame_01_delay-0.04s.png create mode 100644 assets/icons/MainMenu/TouchTunes_14/frame_02_delay-0.04s.png create mode 100644 assets/icons/MainMenu/TouchTunes_14/frame_03_delay-0.04s.png create mode 100644 assets/icons/MainMenu/TouchTunes_14/frame_04_delay-0.04s.png create mode 100644 assets/icons/MainMenu/TouchTunes_14/frame_05_delay-0.04s.png create mode 100644 assets/icons/MainMenu/TouchTunes_14/frame_06_delay-0.04s.png create mode 100644 assets/icons/MainMenu/TouchTunes_14/frame_07_delay-0.04s.png create mode 100644 assets/icons/MainMenu/TouchTunes_14/frame_08_delay-0.04s.png create mode 100644 assets/icons/MainMenu/TouchTunes_14/frame_09_delay-0.04s.png create mode 100644 assets/icons/MainMenu/TouchTunes_14/frame_10_delay-0.04s.png create mode 100644 assets/icons/MainMenu/TouchTunes_14/frame_11_delay-0.04s.png create mode 100644 assets/icons/MainMenu/TouchTunes_14/frame_12_delay-0.04s.png create mode 100644 assets/icons/MainMenu/TouchTunes_14/frame_13_delay-0.04s.png create mode 100644 assets/icons/MainMenu/TouchTunes_14/frame_14_delay-0.04s.png create mode 100644 assets/icons/MainMenu/TouchTunes_14/frame_15_delay-0.04s.png create mode 100644 assets/icons/MainMenu/TouchTunes_14/frame_16_delay-0.04s.png create mode 100644 assets/icons/MainMenu/TouchTunes_14/frame_17_delay-0.04s.png create mode 100644 assets/icons/MainMenu/TouchTunes_14/frame_18_delay-0.04s.png create mode 100644 assets/icons/MainMenu/TouchTunes_14/frame_19_delay-0.04s.png create mode 100644 assets/icons/MainMenu/TouchTunes_14/frame_20_delay-0.04s.png create mode 100644 assets/icons/MainMenu/TouchTunes_14/frame_21_delay-0.04s.png create mode 100644 assets/icons/MainMenu/TouchTunes_14/frame_22_delay-0.04s.png create mode 100644 assets/icons/MainMenu/TouchTunes_14/frame_23_delay-0.04s.png create mode 100644 assets/icons/MainMenu/TouchTunes_14/frame_24_delay-0.04s.png create mode 100644 assets/icons/MainMenu/TouchTunes_14/frame_25_delay-0.04s.png create mode 100644 assets/icons/MainMenu/TouchTunes_14/frame_26_delay-0.04s.png create mode 100644 assets/icons/MainMenu/TouchTunes_14/frame_27_delay-0.04s.png create mode 100644 assets/icons/MainMenu/TouchTunes_14/frame_28_delay-0.04s.png create mode 100644 assets/icons/MainMenu/TouchTunes_14/frame_29_delay-0.04s.png create mode 100644 assets/icons/MainMenu/TouchTunes_14/frame_rate create mode 100644 assets/icons/MainMenu/UniversalRemote_14/frame_1.png create mode 100644 assets/icons/MainMenu/UniversalRemote_14/frame_2.png create mode 100644 assets/icons/MainMenu/UniversalRemote_14/frame_3.png create mode 100644 assets/icons/MainMenu/UniversalRemote_14/frame_4.png create mode 100644 assets/icons/MainMenu/UniversalRemote_14/frame_5.png create mode 100644 assets/icons/MainMenu/UniversalRemote_14/frame_6.png create mode 100644 assets/icons/MainMenu/UniversalRemote_14/frame_7.png create mode 100644 lib/digital_signal/digital_signal.c create mode 100644 lib/digital_signal/digital_signal.h diff --git a/applications/applications.c b/applications/applications.c index a4e81a88d..e1e58c327 100644 --- a/applications/applications.c +++ b/applications/applications.c @@ -230,6 +230,22 @@ const FlipperApplication FLIPPER_APPS[] = { .flags = FlipperApplicationFlagDefault}, #endif +#ifdef APP_UNIVERSALRF + {.app = universal_rf_remote_app, + .name = "Universal SubGHz", + .stack_size = 2048, + .icon = &A_UniversalRemote_14, + .flags = FlipperApplicationFlagDefault}, +#endif + +#ifdef APP_JUKEBOX + {.app = jukebox_app, + .name = "Jukebox", + .stack_size = 2048, + .icon = &A_TouchTunes_14, + .flags = FlipperApplicationFlagDefault}, +#endif + #ifdef APP_LF_RFID {.app = lfrfid_app, .name = "125 kHz RFID", @@ -358,14 +374,6 @@ const FlipperApplication FLIPPER_PLUGINS[] = { }, #endif -#ifdef APP_JUKEBOX - {.app = jukebox_app, - .name = "Jukebox", - .stack_size = 2048, - .icon = &A_UniversalRemote_14, - .flags = FlipperApplicationFlagDefault}, -#endif - #ifdef APP_MUSIC_PLAYER {.app = music_player_app, .name = "Music Player", @@ -394,14 +402,6 @@ const FlipperApplication FLIPPER_PLUGINS[] = { {.app = tetris_game_app, .name = "Tetris Game", .stack_size = 1024, .icon = NULL}, #endif -#ifdef APP_UNIVERSALRF - {.app = universal_rf_remote_app, - .name = "Universal SubGHz", - .stack_size = 2048, - .icon = &A_UniversalRemote_14, - .flags = FlipperApplicationFlagDefault}, -#endif - {.app = wav_player_app, .name = "Wav Player", .stack_size = 4096, diff --git a/applications/nfc/nfc_worker.c b/applications/nfc/nfc_worker.c index 6b3c8f092..9016763df 100644 --- a/applications/nfc/nfc_worker.c +++ b/applications/nfc/nfc_worker.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "helpers/nfc_mf_classic_dict.h" @@ -104,6 +105,8 @@ int32_t nfc_worker_task(void* context) { nfc_worker_emulate_mifare_ul(nfc_worker); } else if(nfc_worker->state == NfcWorkerStateReadMifareClassic) { nfc_worker_mifare_classic_dict_attack(nfc_worker); + } else if(nfc_worker->state == NfcWorkerStateEmulateMifareClassic) { + nfc_worker_emulate_mifare_classic(nfc_worker); } else if(nfc_worker->state == NfcWorkerStateReadMifareDesfire) { nfc_worker_read_mifare_desfire(nfc_worker); } @@ -474,6 +477,26 @@ void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) { stream_free(nfc_worker->dict_stream); } +void nfc_worker_emulate_mifare_classic(NfcWorker* nfc_worker) { + FuriHalNfcTxRxContext tx_rx; + FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; + MfClassicEmulator emulator = { + .cuid = nfc_util_bytes2num(&nfc_data->uid[nfc_data->uid_len - 4], 4), + .data = nfc_worker->dev_data->mf_classic_data, + }; + NfcaSignal* nfca_signal = nfca_signal_alloc(); + tx_rx.nfca_signal = nfca_signal; + + while(nfc_worker->state == NfcWorkerStateEmulateMifareClassic) { + if(furi_hal_nfc_listen( + nfc_data->uid, nfc_data->uid_len, nfc_data->atqa, nfc_data->sak, true, 4000)) { + mf_classic_emulator(&emulator, &tx_rx); + } + } + + nfca_signal_free(nfca_signal); +} + void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) { ReturnCode err; uint8_t tx_buff[64] = {}; diff --git a/applications/nfc/nfc_worker.h b/applications/nfc/nfc_worker.h index 1933a79b7..a68f42d72 100755 --- a/applications/nfc/nfc_worker.h +++ b/applications/nfc/nfc_worker.h @@ -19,6 +19,7 @@ typedef enum { NfcWorkerStateReadMifareUltralight, NfcWorkerStateEmulateMifareUltralight, NfcWorkerStateReadMifareClassic, + NfcWorkerStateEmulateMifareClassic, NfcWorkerStateReadMifareDesfire, // Transition NfcWorkerStateStop, diff --git a/applications/nfc/scenes/nfc_scene_config.h b/applications/nfc/scenes/nfc_scene_config.h index 6b5d5d10c..45e78aed2 100755 --- a/applications/nfc/scenes/nfc_scene_config.h +++ b/applications/nfc/scenes/nfc_scene_config.h @@ -34,4 +34,5 @@ ADD_SCENE(nfc, restore_original, RestoreOriginal) ADD_SCENE(nfc, debug, Debug) ADD_SCENE(nfc, field, Field) ADD_SCENE(nfc, read_mifare_classic, ReadMifareClassic) +ADD_SCENE(nfc, emulate_mifare_classic, EmulateMifareClassic) ADD_SCENE(nfc, dict_not_found, DictNotFound) diff --git a/applications/nfc/scenes/nfc_scene_emulate_mifare_classic.c b/applications/nfc/scenes/nfc_scene_emulate_mifare_classic.c new file mode 100644 index 000000000..2b8478175 --- /dev/null +++ b/applications/nfc/scenes/nfc_scene_emulate_mifare_classic.c @@ -0,0 +1,64 @@ +#include "../nfc_i.h" +#include + +#define NFC_MF_CLASSIC_DATA_NOT_CHANGED (0UL) +#define NFC_MF_CLASSIC_DATA_CHANGED (1UL) + +void nfc_emulate_mifare_classic_worker_callback(NfcWorkerEvent event, void* context) { + UNUSED(event); + Nfc* nfc = context; + + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneEmulateMifareUl, NFC_MF_CLASSIC_DATA_CHANGED); +} + +void nfc_scene_emulate_mifare_classic_on_enter(void* context) { + Nfc* nfc = context; + DOLPHIN_DEED(DolphinDeedNfcEmulate); + + // Setup view + Popup* popup = nfc->popup; + if(strcmp(nfc->dev->dev_name, "")) { + nfc_text_store_set(nfc, "%s", nfc->dev->dev_name); + } + popup_set_icon(popup, 0, 3, &I_RFIDDolphinSend_97x61); + popup_set_header(popup, "Emulating\nMf Classic", 56, 31, AlignLeft, AlignTop); + + // Setup and start worker + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); + nfc_worker_start( + nfc->worker, + NfcWorkerStateEmulateMifareClassic, + &nfc->dev->dev_data, + nfc_emulate_mifare_classic_worker_callback, + nfc); +} + +bool nfc_scene_emulate_mifare_classic_on_event(void* context, SceneManagerEvent event) { + Nfc* nfc = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeTick) { + notification_message(nfc->notifications, &sequence_blink_blue_10); + consumed = true; + } else 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, NfcSceneEmulateMifareUl) == + NFC_MF_CLASSIC_DATA_CHANGED) { + scene_manager_set_scene_state( + nfc->scene_manager, NfcSceneEmulateMifareUl, NFC_MF_CLASSIC_DATA_NOT_CHANGED); + nfc_device_save_shadow(nfc->dev, nfc->dev->dev_name); + } + consumed = false; + } + return consumed; +} + +void nfc_scene_emulate_mifare_classic_on_exit(void* context) { + Nfc* nfc = context; + + // Clear view + popup_reset(nfc->popup); +} diff --git a/applications/nfc/scenes/nfc_scene_saved_menu.c b/applications/nfc/scenes/nfc_scene_saved_menu.c index e0489c157..1b435ccd1 100644 --- a/applications/nfc/scenes/nfc_scene_saved_menu.c +++ b/applications/nfc/scenes/nfc_scene_saved_menu.c @@ -27,13 +27,11 @@ void nfc_scene_saved_menu_on_enter(void* context) { SubmenuIndexEmulate, nfc_scene_saved_menu_submenu_callback, nfc); - } else if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { + } else if( + nfc->dev->format == NfcDeviceSaveFormatMifareUl || + nfc->dev->format == NfcDeviceSaveFormatMifareClassic) { submenu_add_item( - submenu, - "Emulate Ultralight", - SubmenuIndexEmulate, - nfc_scene_saved_menu_submenu_callback, - nfc); + submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_saved_menu_submenu_callback, nfc); } submenu_add_item( submenu, "Edit UID and Name", SubmenuIndexEdit, nfc_scene_saved_menu_submenu_callback, nfc); @@ -64,6 +62,8 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { if(event.event == SubmenuIndexEmulate) { if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareUl); + } else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareClassic); } else { scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); } diff --git a/assets/compiled/assets_icons.c b/assets/compiled/assets_icons.c index 566a22fd4..4992c7d96 100644 --- a/assets/compiled/assets_icons.c +++ b/assets/compiled/assets_icons.c @@ -452,43 +452,52 @@ const uint8_t _A_Tamagotchi_14_4[] = {0x00,0xF0,0x03,0x08,0x06,0x04,0x0C,0x04,0x const uint8_t _A_Tamagotchi_14_5[] = {0x00,0xF0,0x03,0x08,0x06,0x04,0x0C,0x04,0x0C,0xF2,0x19,0x5A,0x1A,0xA9,0x32,0x49,0x33,0xF1,0x31,0x01,0x30,0x52,0x39,0x02,0x18,0x0C,0x0E,0xF0,0x07,}; const uint8_t* const _A_Tamagotchi_14[] = {_A_Tamagotchi_14_0,_A_Tamagotchi_14_1,_A_Tamagotchi_14_2,_A_Tamagotchi_14_3,_A_Tamagotchi_14_4,_A_Tamagotchi_14_5}; +const uint8_t _A_TouchTunes_14_0[] = {0x00,0x60,0x01,0xF8,0x07,0xF8,0x07,0x08,0x04,0x18,0x02,0x08,0x04,0x04,0x08,0x0C,0x0C,0x18,0x04,0x10,0x02,0x98,0x06,0xF8,0x07,0xF8,0x07,0x80,0x01,}; +const uint8_t _A_TouchTunes_14_1[] = {0x00,0x60,0x01,0xF8,0x07,0xF8,0x07,0x08,0x04,0x18,0x02,0x08,0x04,0x04,0x08,0x0C,0x0C,0x18,0x04,0x10,0x02,0x98,0x06,0xF8,0x07,0xF8,0x07,0x80,0x01,}; +const uint8_t _A_TouchTunes_14_2[] = {0x00,0x60,0x01,0xF8,0x07,0xF8,0x07,0x08,0x04,0x18,0x02,0x08,0x04,0x04,0x08,0x0C,0x0C,0x18,0x04,0x10,0x02,0x98,0x06,0xF8,0x07,0xF8,0x07,0x80,0x01,}; +const uint8_t _A_TouchTunes_14_3[] = {0x01,0x00,0x1a,0x00,0xd0,0x40,0x7f,0x10,0x70,0x08,0xc2,0x20,0x91,0x08,0x10,0x0c,0x60,0x90,0x88,0x64,0x32,0x30,0x09,0x2c,0xc4,0x18,0x26,0x78,0x08,0x08,}; +const uint8_t _A_TouchTunes_14_4[] = {0x00,0x40,0x01,0xF8,0x07,0xF8,0x07,0x18,0x04,0x10,0x06,0x08,0x04,0x0C,0x0C,0x08,0x04,0x18,0x02,0x10,0x06,0xD8,0x06,0xF8,0x07,0xF8,0x07,0x00,0x00,}; +const uint8_t _A_TouchTunes_14_5[] = {0x00,0x00,0x00,0xF0,0x07,0xF8,0x07,0x18,0x04,0x18,0x06,0x10,0x02,0x08,0x04,0x08,0x04,0x10,0x02,0x18,0x06,0xD8,0x06,0xF8,0x07,0xF0,0x03,0x00,0x00,}; +const uint8_t _A_TouchTunes_14_6[] = {0x00,0x00,0x01,0xF0,0x03,0xF8,0x07,0x18,0x04,0x10,0x02,0x18,0x04,0x0C,0x0C,0x08,0x04,0x18,0x02,0x10,0x02,0xF8,0x06,0xF8,0x07,0xF0,0x07,0x00,0x00,}; +const uint8_t _A_TouchTunes_14_7[] = {0x00,0x00,0x00,0xF8,0x07,0xF8,0x07,0x00,0x04,0x10,0x04,0x08,0x04,0x0C,0x0C,0x0C,0x0C,0x18,0x04,0x00,0x04,0xD8,0x06,0xF8,0x07,0xF0,0x03,0x00,0x00,}; +const uint8_t _A_TouchTunes_14_8[] = {0x00,0x00,0x00,0xF0,0x07,0xF8,0x07,0x18,0x04,0x08,0x04,0x0C,0x0C,0x0A,0x1C,0x0E,0x18,0x08,0x0C,0x48,0x00,0xD8,0x06,0xF8,0x07,0xF0,0x03,0x40,0x00,}; +const uint8_t _A_TouchTunes_14_9[] = {0x00,0x20,0x02,0xF8,0x07,0xF8,0x07,0x08,0x04,0x00,0x04,0x0C,0x0C,0x0B,0x34,0x0E,0x1C,0x0C,0x0C,0xE0,0x01,0xD8,0x06,0xF8,0x07,0xF8,0x07,0x00,0x00,}; +const uint8_t _A_TouchTunes_14_10[] = {0x00,0xA0,0x02,0xF8,0x07,0xF8,0x07,0x00,0x04,0x08,0x00,0x0C,0x0C,0x0B,0x34,0x0A,0x14,0x0C,0x0C,0xF0,0x01,0x98,0x05,0xF8,0x07,0xF8,0x07,0x40,0x00,}; +const uint8_t _A_TouchTunes_14_11[] = {0x00,0xA0,0x01,0xF8,0x07,0xF8,0x07,0x00,0x00,0x00,0x00,0x0E,0x0C,0x0A,0x34,0x0B,0x14,0x0C,0x0C,0xE0,0x01,0x98,0x05,0xF8,0x07,0xD8,0x07,0x60,0x00,}; +const uint8_t _A_TouchTunes_14_12[] = {0x00,0xA0,0x02,0xF8,0x07,0xF8,0x07,0x00,0x04,0x04,0x00,0x0C,0x0C,0x0A,0x14,0x0A,0x1C,0x0C,0x0C,0xE0,0x01,0x98,0x05,0xF8,0x07,0xD8,0x07,0x60,0x00,}; +const uint8_t _A_TouchTunes_14_13[] = {0x00,0x60,0x02,0xF8,0x07,0xF8,0x07,0x00,0x04,0x04,0x08,0x0C,0x0C,0x0A,0x34,0x0A,0x14,0x0C,0x0C,0xE8,0x05,0x98,0x05,0xF8,0x07,0xF8,0x07,0x80,0x00,}; +const uint8_t _A_TouchTunes_14_14[] = {0x00,0x60,0x02,0xF8,0x07,0xF8,0x07,0x00,0x04,0x04,0x08,0x0C,0x0C,0x0A,0x34,0x0A,0x14,0x0C,0x0C,0xE8,0x05,0x98,0x05,0xF8,0x07,0xF8,0x07,0x80,0x00,}; +const uint8_t _A_TouchTunes_14_15[] = {0x00,0x60,0x02,0xF8,0x07,0xF8,0x07,0x00,0x04,0x04,0x08,0x0C,0x0C,0x0A,0x34,0x0A,0x14,0x0C,0x0C,0xE8,0x05,0x98,0x05,0xF8,0x07,0xF8,0x07,0x80,0x00,}; +const uint8_t _A_TouchTunes_14_16[] = {0x00,0x60,0x02,0xF8,0x07,0xF8,0x07,0x00,0x04,0x04,0x08,0x0C,0x0C,0x0A,0x34,0x0A,0x14,0x0C,0x0C,0xE8,0x05,0x98,0x05,0xF8,0x07,0xF8,0x07,0x80,0x00,}; +const uint8_t _A_TouchTunes_14_17[] = {0x00,0xA0,0x01,0xF8,0x07,0xF8,0x07,0x00,0x00,0x04,0x08,0x0C,0x0C,0x0A,0x14,0x0A,0x1C,0x0C,0x0C,0xE0,0x01,0x98,0x06,0xF8,0x07,0xD8,0x07,0x60,0x00,}; +const uint8_t _A_TouchTunes_14_18[] = {0x00,0x20,0x02,0xF8,0x07,0xF8,0x07,0x08,0x04,0x08,0x04,0x0E,0x0C,0x0A,0x34,0x0B,0x14,0x0C,0x0C,0xE4,0x03,0xD8,0x06,0xF8,0x07,0xF8,0x07,0x00,0x00,}; +const uint8_t _A_TouchTunes_14_19[] = {0x00,0x00,0x00,0xF0,0x07,0xF8,0x07,0x18,0x04,0x04,0x08,0x0E,0x1C,0x0B,0x34,0x0A,0x14,0x0C,0x0C,0xE0,0x03,0xF8,0x06,0xF8,0x07,0xF0,0x07,0x00,0x00,}; +const uint8_t _A_TouchTunes_14_20[] = {0x00,0x00,0x01,0xF0,0x03,0xF8,0x07,0x18,0x04,0x04,0x00,0x0C,0x0C,0x0B,0x34,0x0B,0x34,0x0C,0x0C,0xE0,0x05,0xF8,0x06,0xF8,0x07,0xF0,0x03,0x00,0x00,}; +const uint8_t _A_TouchTunes_14_21[] = {0x00,0x00,0x00,0xF8,0x07,0xF8,0x07,0x10,0x00,0x08,0x04,0x0C,0x0C,0x0C,0x0C,0x0E,0x0C,0x08,0x04,0x88,0x04,0xF0,0x02,0xF8,0x07,0xF0,0x03,0x00,0x00,}; +const uint8_t _A_TouchTunes_14_22[] = {0x00,0x00,0x00,0xF8,0x07,0xF8,0x07,0x00,0x00,0x18,0x04,0x08,0x04,0x0C,0x0C,0x08,0x04,0x08,0x04,0x00,0x04,0xD8,0x02,0xF8,0x07,0xF0,0x03,0x00,0x00,}; +const uint8_t _A_TouchTunes_14_23[] = {0x01,0x00,0x14,0x00,0xa0,0x40,0x7f,0x10,0x70,0x08,0x81,0xc6,0x21,0x02,0x84,0x41,0x00,0x2a,0x09,0x1e,0xc4,0x18,0x26,0xa0,}; +const uint8_t _A_TouchTunes_14_24[] = {0x01,0x00,0x17,0x00,0x90,0x40,0xbf,0x10,0x70,0x08,0xc2,0x20,0x91,0x08,0x14,0x62,0x0c,0x05,0x10,0x3a,0xe6,0x20,0xa1,0x33,0xa0,0x40,0x00,}; +const uint8_t _A_TouchTunes_14_25[] = {0x01,0x00,0x1a,0x00,0xb0,0x40,0x7f,0x10,0x70,0x08,0xc2,0x20,0x91,0x88,0x34,0x62,0x04,0x05,0x10,0x39,0x40,0xa2,0x10,0x6c,0xc4,0x14,0x26,0x78,0x08,0x00,}; +const uint8_t _A_TouchTunes_14_26[] = {0x00,0x60,0x01,0xF8,0x07,0xF8,0x07,0x08,0x04,0x10,0x06,0x08,0x04,0x0C,0x0C,0x08,0x04,0x18,0x02,0x10,0x06,0x98,0x04,0xF8,0x07,0xF8,0x07,0x80,0x02,}; +const uint8_t _A_TouchTunes_14_27[] = {0x00,0x60,0x01,0xF8,0x07,0xF8,0x07,0x08,0x04,0x18,0x02,0x08,0x04,0x04,0x08,0x0C,0x0C,0x18,0x04,0x10,0x02,0x98,0x06,0xF8,0x07,0xF8,0x07,0x80,0x01,}; +const uint8_t _A_TouchTunes_14_28[] = {0x00,0x60,0x01,0xF8,0x07,0xF8,0x07,0x08,0x04,0x18,0x02,0x08,0x04,0x04,0x08,0x0C,0x0C,0x18,0x04,0x10,0x02,0x98,0x06,0xF8,0x07,0xF8,0x07,0x80,0x01,}; +const uint8_t _A_TouchTunes_14_29[] = {0x00,0x60,0x01,0xF8,0x07,0xF8,0x07,0x08,0x04,0x18,0x02,0x08,0x04,0x04,0x08,0x0C,0x0C,0x18,0x04,0x10,0x02,0x98,0x06,0xF8,0x07,0xF8,0x07,0x80,0x01,}; +const uint8_t* const _A_TouchTunes_14[] = {_A_TouchTunes_14_0,_A_TouchTunes_14_1,_A_TouchTunes_14_2,_A_TouchTunes_14_3,_A_TouchTunes_14_4,_A_TouchTunes_14_5,_A_TouchTunes_14_6,_A_TouchTunes_14_7,_A_TouchTunes_14_8,_A_TouchTunes_14_9,_A_TouchTunes_14_10,_A_TouchTunes_14_11,_A_TouchTunes_14_12,_A_TouchTunes_14_13,_A_TouchTunes_14_14,_A_TouchTunes_14_15,_A_TouchTunes_14_16,_A_TouchTunes_14_17,_A_TouchTunes_14_18,_A_TouchTunes_14_19,_A_TouchTunes_14_20,_A_TouchTunes_14_21,_A_TouchTunes_14_22,_A_TouchTunes_14_23,_A_TouchTunes_14_24,_A_TouchTunes_14_25,_A_TouchTunes_14_26,_A_TouchTunes_14_27,_A_TouchTunes_14_28,_A_TouchTunes_14_29}; + const uint8_t _A_U2F_14_0[] = {0x00,0x00,0x00,0x00,0x00,0xE0,0x01,0x10,0x02,0x08,0x04,0xFE,0x1F,0x01,0x20,0xD5,0x2D,0x55,0x25,0x15,0x2D,0x95,0x24,0xDD,0x25,0x01,0x20,0xFE,0x1F,}; const uint8_t _A_U2F_14_1[] = {0x00,0x00,0x00,0xE0,0x01,0x10,0x02,0x08,0x04,0x08,0x04,0xFE,0x1F,0x01,0x20,0xD5,0x2D,0x55,0x25,0x15,0x2D,0x95,0x24,0xDD,0x25,0x01,0x20,0xFE,0x1F,}; const uint8_t _A_U2F_14_2[] = {0x00,0xE0,0x01,0x10,0x02,0x08,0x04,0x08,0x04,0x08,0x00,0xFE,0x1F,0x01,0x20,0xD5,0x2D,0x55,0x25,0x15,0x2D,0x95,0x24,0xDD,0x25,0x01,0x20,0xFE,0x1F,}; const uint8_t _A_U2F_14_3[] = {0x00,0x00,0x00,0xE0,0x01,0x10,0x02,0x08,0x04,0x08,0x04,0xFE,0x1F,0x01,0x20,0xD5,0x2D,0x55,0x25,0x15,0x2D,0x95,0x24,0xDD,0x25,0x01,0x20,0xFE,0x1F,}; const uint8_t* const _A_U2F_14[] = {_A_U2F_14_0,_A_U2F_14_1,_A_U2F_14_2,_A_U2F_14_3}; -const uint8_t _A_UniversalRemote_14_0[] = {0x00,0x60,0x01,0xF8,0x07,0xF8,0x07,0x08,0x04,0x18,0x02,0x08,0x04,0x04,0x08,0x0C,0x0C,0x18,0x04,0x10,0x02,0x98,0x06,0xF8,0x07,0xF8,0x07,0x80,0x01,}; -const uint8_t _A_UniversalRemote_14_1[] = {0x00,0x60,0x01,0xF8,0x07,0xF8,0x07,0x08,0x04,0x18,0x02,0x08,0x04,0x04,0x08,0x0C,0x0C,0x18,0x04,0x10,0x02,0x98,0x06,0xF8,0x07,0xF8,0x07,0x80,0x01,}; -const uint8_t _A_UniversalRemote_14_2[] = {0x00,0x60,0x01,0xF8,0x07,0xF8,0x07,0x08,0x04,0x18,0x02,0x08,0x04,0x04,0x08,0x0C,0x0C,0x18,0x04,0x10,0x02,0x98,0x06,0xF8,0x07,0xF8,0x07,0x80,0x01,}; -const uint8_t _A_UniversalRemote_14_3[] = {0x01,0x00,0x1a,0x00,0xd0,0x40,0x7f,0x10,0x70,0x08,0xc2,0x20,0x91,0x08,0x10,0x0c,0x60,0x90,0x88,0x64,0x32,0x30,0x09,0x2c,0xc4,0x18,0x26,0x78,0x08,0x08,}; -const uint8_t _A_UniversalRemote_14_4[] = {0x00,0x40,0x01,0xF8,0x07,0xF8,0x07,0x18,0x04,0x10,0x06,0x08,0x04,0x0C,0x0C,0x08,0x04,0x18,0x02,0x10,0x06,0xD8,0x06,0xF8,0x07,0xF8,0x07,0x00,0x00,}; -const uint8_t _A_UniversalRemote_14_5[] = {0x00,0x00,0x00,0xF0,0x07,0xF8,0x07,0x18,0x04,0x18,0x06,0x10,0x02,0x08,0x04,0x08,0x04,0x10,0x02,0x18,0x06,0xD8,0x06,0xF8,0x07,0xF0,0x03,0x00,0x00,}; -const uint8_t _A_UniversalRemote_14_6[] = {0x00,0x00,0x01,0xF0,0x03,0xF8,0x07,0x18,0x04,0x10,0x02,0x18,0x04,0x0C,0x0C,0x08,0x04,0x18,0x02,0x10,0x02,0xF8,0x06,0xF8,0x07,0xF0,0x07,0x00,0x00,}; -const uint8_t _A_UniversalRemote_14_7[] = {0x00,0x00,0x00,0xF8,0x07,0xF8,0x07,0x00,0x04,0x10,0x04,0x08,0x04,0x0C,0x0C,0x0C,0x0C,0x18,0x04,0x00,0x04,0xD8,0x06,0xF8,0x07,0xF0,0x03,0x00,0x00,}; -const uint8_t _A_UniversalRemote_14_8[] = {0x00,0x00,0x00,0xF0,0x07,0xF8,0x07,0x18,0x04,0x08,0x04,0x0C,0x0C,0x0A,0x1C,0x0E,0x18,0x08,0x0C,0x48,0x00,0xD8,0x06,0xF8,0x07,0xF0,0x03,0x40,0x00,}; -const uint8_t _A_UniversalRemote_14_9[] = {0x00,0x20,0x02,0xF8,0x07,0xF8,0x07,0x08,0x04,0x00,0x04,0x0C,0x0C,0x0B,0x34,0x0E,0x1C,0x0C,0x0C,0xE0,0x01,0xD8,0x06,0xF8,0x07,0xF8,0x07,0x00,0x00,}; -const uint8_t _A_UniversalRemote_14_10[] = {0x00,0xA0,0x02,0xF8,0x07,0xF8,0x07,0x00,0x04,0x08,0x00,0x0C,0x0C,0x0B,0x34,0x0A,0x14,0x0C,0x0C,0xF0,0x01,0x98,0x05,0xF8,0x07,0xF8,0x07,0x40,0x00,}; -const uint8_t _A_UniversalRemote_14_11[] = {0x00,0xA0,0x01,0xF8,0x07,0xF8,0x07,0x00,0x00,0x00,0x00,0x0E,0x0C,0x0A,0x34,0x0B,0x14,0x0C,0x0C,0xE0,0x01,0x98,0x05,0xF8,0x07,0xD8,0x07,0x60,0x00,}; -const uint8_t _A_UniversalRemote_14_12[] = {0x00,0xA0,0x02,0xF8,0x07,0xF8,0x07,0x00,0x04,0x04,0x00,0x0C,0x0C,0x0A,0x14,0x0A,0x1C,0x0C,0x0C,0xE0,0x01,0x98,0x05,0xF8,0x07,0xD8,0x07,0x60,0x00,}; -const uint8_t _A_UniversalRemote_14_13[] = {0x00,0x60,0x02,0xF8,0x07,0xF8,0x07,0x00,0x04,0x04,0x08,0x0C,0x0C,0x0A,0x34,0x0A,0x14,0x0C,0x0C,0xE8,0x05,0x98,0x05,0xF8,0x07,0xF8,0x07,0x80,0x00,}; -const uint8_t _A_UniversalRemote_14_14[] = {0x00,0x60,0x02,0xF8,0x07,0xF8,0x07,0x00,0x04,0x04,0x08,0x0C,0x0C,0x0A,0x34,0x0A,0x14,0x0C,0x0C,0xE8,0x05,0x98,0x05,0xF8,0x07,0xF8,0x07,0x80,0x00,}; -const uint8_t _A_UniversalRemote_14_15[] = {0x00,0x60,0x02,0xF8,0x07,0xF8,0x07,0x00,0x04,0x04,0x08,0x0C,0x0C,0x0A,0x34,0x0A,0x14,0x0C,0x0C,0xE8,0x05,0x98,0x05,0xF8,0x07,0xF8,0x07,0x80,0x00,}; -const uint8_t _A_UniversalRemote_14_16[] = {0x00,0x60,0x02,0xF8,0x07,0xF8,0x07,0x00,0x04,0x04,0x08,0x0C,0x0C,0x0A,0x34,0x0A,0x14,0x0C,0x0C,0xE8,0x05,0x98,0x05,0xF8,0x07,0xF8,0x07,0x80,0x00,}; -const uint8_t _A_UniversalRemote_14_17[] = {0x00,0xA0,0x01,0xF8,0x07,0xF8,0x07,0x00,0x00,0x04,0x08,0x0C,0x0C,0x0A,0x14,0x0A,0x1C,0x0C,0x0C,0xE0,0x01,0x98,0x06,0xF8,0x07,0xD8,0x07,0x60,0x00,}; -const uint8_t _A_UniversalRemote_14_18[] = {0x00,0x20,0x02,0xF8,0x07,0xF8,0x07,0x08,0x04,0x08,0x04,0x0E,0x0C,0x0A,0x34,0x0B,0x14,0x0C,0x0C,0xE4,0x03,0xD8,0x06,0xF8,0x07,0xF8,0x07,0x00,0x00,}; -const uint8_t _A_UniversalRemote_14_19[] = {0x00,0x00,0x00,0xF0,0x07,0xF8,0x07,0x18,0x04,0x04,0x08,0x0E,0x1C,0x0B,0x34,0x0A,0x14,0x0C,0x0C,0xE0,0x03,0xF8,0x06,0xF8,0x07,0xF0,0x07,0x00,0x00,}; -const uint8_t _A_UniversalRemote_14_20[] = {0x00,0x00,0x01,0xF0,0x03,0xF8,0x07,0x18,0x04,0x04,0x00,0x0C,0x0C,0x0B,0x34,0x0B,0x34,0x0C,0x0C,0xE0,0x05,0xF8,0x06,0xF8,0x07,0xF0,0x03,0x00,0x00,}; -const uint8_t _A_UniversalRemote_14_21[] = {0x00,0x00,0x00,0xF8,0x07,0xF8,0x07,0x10,0x00,0x08,0x04,0x0C,0x0C,0x0C,0x0C,0x0E,0x0C,0x08,0x04,0x88,0x04,0xF0,0x02,0xF8,0x07,0xF0,0x03,0x00,0x00,}; -const uint8_t _A_UniversalRemote_14_22[] = {0x00,0x00,0x00,0xF8,0x07,0xF8,0x07,0x00,0x00,0x18,0x04,0x08,0x04,0x0C,0x0C,0x08,0x04,0x08,0x04,0x00,0x04,0xD8,0x02,0xF8,0x07,0xF0,0x03,0x00,0x00,}; -const uint8_t _A_UniversalRemote_14_23[] = {0x01,0x00,0x14,0x00,0xa0,0x40,0x7f,0x10,0x70,0x08,0x81,0xc6,0x21,0x02,0x84,0x41,0x00,0x2a,0x09,0x1e,0xc4,0x18,0x26,0xa0,}; -const uint8_t _A_UniversalRemote_14_24[] = {0x01,0x00,0x17,0x00,0x90,0x40,0xbf,0x10,0x70,0x08,0xc2,0x20,0x91,0x08,0x14,0x62,0x0c,0x05,0x10,0x3a,0xe6,0x20,0xa1,0x33,0xa0,0x40,0x00,}; -const uint8_t _A_UniversalRemote_14_25[] = {0x01,0x00,0x1a,0x00,0xb0,0x40,0x7f,0x10,0x70,0x08,0xc2,0x20,0x91,0x88,0x34,0x62,0x04,0x05,0x10,0x39,0x40,0xa2,0x10,0x6c,0xc4,0x14,0x26,0x78,0x08,0x00,}; -const uint8_t _A_UniversalRemote_14_26[] = {0x00,0x60,0x01,0xF8,0x07,0xF8,0x07,0x08,0x04,0x10,0x06,0x08,0x04,0x0C,0x0C,0x08,0x04,0x18,0x02,0x10,0x06,0x98,0x04,0xF8,0x07,0xF8,0x07,0x80,0x02,}; -const uint8_t _A_UniversalRemote_14_27[] = {0x00,0x60,0x01,0xF8,0x07,0xF8,0x07,0x08,0x04,0x18,0x02,0x08,0x04,0x04,0x08,0x0C,0x0C,0x18,0x04,0x10,0x02,0x98,0x06,0xF8,0x07,0xF8,0x07,0x80,0x01,}; -const uint8_t _A_UniversalRemote_14_28[] = {0x00,0x60,0x01,0xF8,0x07,0xF8,0x07,0x08,0x04,0x18,0x02,0x08,0x04,0x04,0x08,0x0C,0x0C,0x18,0x04,0x10,0x02,0x98,0x06,0xF8,0x07,0xF8,0x07,0x80,0x01,}; -const uint8_t _A_UniversalRemote_14_29[] = {0x00,0x60,0x01,0xF8,0x07,0xF8,0x07,0x08,0x04,0x18,0x02,0x08,0x04,0x04,0x08,0x0C,0x0C,0x18,0x04,0x10,0x02,0x98,0x06,0xF8,0x07,0xF8,0x07,0x80,0x01,}; -const uint8_t* const _A_UniversalRemote_14[] = {_A_UniversalRemote_14_0,_A_UniversalRemote_14_1,_A_UniversalRemote_14_2,_A_UniversalRemote_14_3,_A_UniversalRemote_14_4,_A_UniversalRemote_14_5,_A_UniversalRemote_14_6,_A_UniversalRemote_14_7,_A_UniversalRemote_14_8,_A_UniversalRemote_14_9,_A_UniversalRemote_14_10,_A_UniversalRemote_14_11,_A_UniversalRemote_14_12,_A_UniversalRemote_14_13,_A_UniversalRemote_14_14,_A_UniversalRemote_14_15,_A_UniversalRemote_14_16,_A_UniversalRemote_14_17,_A_UniversalRemote_14_18,_A_UniversalRemote_14_19,_A_UniversalRemote_14_20,_A_UniversalRemote_14_21,_A_UniversalRemote_14_22,_A_UniversalRemote_14_23,_A_UniversalRemote_14_24,_A_UniversalRemote_14_25,_A_UniversalRemote_14_26,_A_UniversalRemote_14_27,_A_UniversalRemote_14_28,_A_UniversalRemote_14_29}; +const uint8_t _A_UniversalRemote_14_0[] = {0x01,0x00,0x17,0x00,0xe0,0x40,0x24,0x10,0x1f,0x04,0x04,0x0e,0x20,0x31,0x8b,0x46,0xa2,0xb2,0xa0,0x08,0x81,0x44,0x1a,0xa1,0x51,0x0c,0x88,}; +const uint8_t _A_UniversalRemote_14_1[] = {0x01,0x00,0x17,0x00,0xe0,0x40,0x3c,0x10,0x10,0x08,0x81,0xc4,0x06,0x31,0x68,0xd4,0x56,0x54,0x01,0x10,0x28,0x83,0x56,0x41,0x01,0x0c,0x88,}; +const uint8_t _A_UniversalRemote_14_2[] = {0x01,0x00,0x17,0x00,0xe0,0x40,0x24,0x10,0x1f,0x04,0x04,0x0e,0x20,0x31,0x8b,0x46,0xa2,0xb3,0xa0,0x08,0x81,0x44,0x1a,0xa1,0x51,0x0c,0x88,}; +const uint8_t _A_UniversalRemote_14_3[] = {0x01,0x00,0x17,0x00,0xe0,0x40,0x24,0x10,0x1f,0x04,0x04,0x0e,0x20,0x31,0x8b,0x46,0xa2,0xb2,0xa0,0x08,0x81,0x44,0x1a,0xa0,0x11,0x0c,0x88,}; +const uint8_t _A_UniversalRemote_14_4[] = {0x01,0x00,0x17,0x00,0xe0,0x40,0x24,0x10,0x1f,0x04,0x04,0x0e,0x20,0x31,0x8b,0x46,0xa2,0xf2,0xa0,0x08,0x81,0x44,0x1a,0xa1,0x51,0x0c,0x88,}; +const uint8_t _A_UniversalRemote_14_5[] = {0x01,0x00,0x17,0x00,0xe0,0x40,0x3c,0x10,0x10,0x08,0x81,0xc4,0x06,0x31,0x68,0xd4,0x56,0x54,0x01,0x10,0x28,0x83,0x56,0x41,0x01,0x0c,0x88,}; +const uint8_t _A_UniversalRemote_14_6[] = {0x01,0x00,0x17,0x00,0xe0,0x40,0x24,0x10,0x1f,0x04,0x04,0x0e,0x20,0x31,0xfb,0x46,0xfe,0xb2,0xb0,0x08,0x81,0x44,0x1a,0xa1,0x51,0x0c,0x88,}; +const uint8_t* const _A_UniversalRemote_14[] = {_A_UniversalRemote_14_0,_A_UniversalRemote_14_1,_A_UniversalRemote_14_2,_A_UniversalRemote_14_3,_A_UniversalRemote_14_4,_A_UniversalRemote_14_5,_A_UniversalRemote_14_6}; const uint8_t _A_iButton_14_0[] = {0x00,0x00,0x1C,0x00,0x3E,0x00,0x35,0x80,0x3A,0x78,0x15,0x84,0x0A,0x32,0x05,0x49,0x02,0x85,0x02,0x85,0x02,0x49,0x02,0x32,0x01,0x84,0x00,0x78,0x00,}; const uint8_t _A_iButton_14_1[] = {0x00,0x00,0x00,0x00,0x38,0x00,0x26,0x80,0x21,0xE0,0x10,0x38,0x0D,0x6C,0x03,0x56,0x01,0x2B,0x01,0x97,0x00,0x4D,0x00,0x21,0x00,0x1E,0x00,0x00,0x00,}; @@ -823,8 +832,9 @@ const Icon A_Power_14 = {.width=14,.height=14,.frame_count=1,.frame_rate=3,.fram const Icon A_Settings_14 = {.width=14,.height=14,.frame_count=10,.frame_rate=3,.frames=_A_Settings_14}; const Icon A_Sub1ghz_14 = {.width=14,.height=14,.frame_count=6,.frame_rate=3,.frames=_A_Sub1ghz_14}; const Icon A_Tamagotchi_14 = {.width=14,.height=14,.frame_count=6,.frame_rate=3,.frames=_A_Tamagotchi_14}; +const Icon A_TouchTunes_14 = {.width=14,.height=14,.frame_count=30,.frame_rate=3,.frames=_A_TouchTunes_14}; const Icon A_U2F_14 = {.width=14,.height=14,.frame_count=4,.frame_rate=3,.frames=_A_U2F_14}; -const Icon A_UniversalRemote_14 = {.width=14,.height=14,.frame_count=30,.frame_rate=3,.frames=_A_UniversalRemote_14}; +const Icon A_UniversalRemote_14 = {.width=14,.height=14,.frame_count=7,.frame_rate=3,.frames=_A_UniversalRemote_14}; const Icon A_iButton_14 = {.width=14,.height=14,.frame_count=7,.frame_rate=3,.frames=_A_iButton_14}; const Icon I_Detailed_chip_17x13 = {.width=17,.height=13,.frame_count=1,.frame_rate=0,.frames=_I_Detailed_chip_17x13}; const Icon I_Medium_chip_22x21 = {.width=22,.height=21,.frame_count=1,.frame_rate=0,.frames=_I_Medium_chip_22x21}; diff --git a/assets/compiled/assets_icons.h b/assets/compiled/assets_icons.h index 94de03f1b..c824d97fc 100644 --- a/assets/compiled/assets_icons.h +++ b/assets/compiled/assets_icons.h @@ -109,6 +109,7 @@ extern const Icon A_Power_14; extern const Icon A_Settings_14; extern const Icon A_Sub1ghz_14; extern const Icon A_Tamagotchi_14; +extern const Icon A_TouchTunes_14; extern const Icon A_U2F_14; extern const Icon A_UniversalRemote_14; extern const Icon A_iButton_14; diff --git a/assets/icons/MainMenu/TouchTunes_14/frame_00_delay-0.04s.png b/assets/icons/MainMenu/TouchTunes_14/frame_00_delay-0.04s.png new file mode 100644 index 0000000000000000000000000000000000000000..d6c97146d818a4eb321bfdc31bb1e4823502294c GIT binary patch literal 470 zcmeAS@N?(olHy`uVBq!ia0vp^d?3sLBp9rei+F()OS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1wdT{9RM#0%!^3bX-AFeQ1ryD-F@2(Wt#qtYOxn1c`=+>W)9>T8Sv76t0@EFj@bBU==g} z#k-p;nsnwJIO(`us6>?gXponqfkq8qVa>GfXPZ8Yg|OP5`L6#%zP9v_X1w#a-^-JK zS{~Zx*0(Az^YyC7g{GcMPQL2cac-KRpy277rbR1l7}||a&YUNEg-!1n$^K^oaDR8A6{26`zZuLQCH&4rH({emZfX>w~ag8WR&d<$F z%`0JW_jFSzN-fT;N=;G7&r`@KDJdwn($`O|O3zHw11i#oNIocd1q>1fRgl({#FA92 zCk1w@};-9yoko1c=IR*74K_qw1Ypaup{ LS3j3^P614Ba#1H&(%P{RubhEf9thF1wdT{9RM#0%!^3bX-AFeQ1ryD-F@2(Wt#qtYOxn1c`=+>W)9>T8Sv76t0@EFj@bBU==g} z#k-p;nsnwJIO(`us6>?gXponqfkq8qVa>GfXPZ8Yg|OP5`L6#%zP9v_X1w#a-^-JK zS{~Zx*0(Az^YyC7g{GcMPQL2cac-KRpy277rbR1l7}||a&YUNEg-!1n$^K^oaDR8A6{26`zZuLQCH&4rH({emZfX-Ddag8WRNi0dV zN-jzTQVd20Mn<{@rn-hEAqJ*a#>Q5rrrHJuRzURm)jbpqx%nxXX_dG&c&`ge0%~CJ MboFyt=akR{00vu%od5s; literal 0 HcmV?d00001 diff --git a/assets/icons/MainMenu/TouchTunes_14/frame_02_delay-0.04s.png b/assets/icons/MainMenu/TouchTunes_14/frame_02_delay-0.04s.png new file mode 100644 index 0000000000000000000000000000000000000000..479fbd58b591c8277f06ec1225ee29ee095c8564 GIT binary patch literal 411 zcmeAS@N?(olHy`uVBq!ia0vp^d?3sLBp9rei+F()OS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1wdT{9RM#0%!^3bX-AFeQ1ryD-F@2(Wt#qtYOxn1c`=+>W)9>T8Sv76t0@EFj@bBU==g} z#k-p;nsnwJIO(`us6>?gXponqfkq8qVa>GfXPZ8Yg|OP5`L6#%zP9v_X1w#a-^-JK zS{~Zx*0(Az^YyC7g{GcMPQL2cac-KRpy277rbR1l7}||a&YUNEg-!1n$^K^oaDR8A6{26`zZuLQCH&4rH({emZfX-Ddag8WRNi0dV zN-jzTQVd20Mn<{@rn-hEAqJ*a#>Q5rrrHJuRzURm)jbpqx%nxXX_dG&c&`ge0%~CJ MboFyt=akR{00vu%od5s; literal 0 HcmV?d00001 diff --git a/assets/icons/MainMenu/TouchTunes_14/frame_03_delay-0.04s.png b/assets/icons/MainMenu/TouchTunes_14/frame_03_delay-0.04s.png new file mode 100644 index 0000000000000000000000000000000000000000..1ece97a6f2ea99c186f3abaf446df51e4131a8ed GIT binary patch literal 411 zcmeAS@N?(olHy`uVBq!ia0vp^d?3sLBp9rei+F()OS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1wdT{9RM#0%!^3bX-AFeQ1ryD&U4#Q3R0P7x@y*we)^gyXvDxs6^ zX1}o7BUm1N#M;7y%TXZdv!qIUvy78f{Net`#(VSiE#6u$DLTO$_B-0-X?9wz`5}MZ z;y*?G?|Frm&7SrxcUI*ZId-0TtCW?d-R|hKdAa7?@fa8(W#0Y8x0>0nz7I_fRzC=BH$)RpQp*y)GyTsDZ)L L)z4*}Q$iB}Q}~Lk literal 0 HcmV?d00001 diff --git a/assets/icons/MainMenu/TouchTunes_14/frame_04_delay-0.04s.png b/assets/icons/MainMenu/TouchTunes_14/frame_04_delay-0.04s.png new file mode 100644 index 0000000000000000000000000000000000000000..d85fa6ebca3cf45527524850e696081f1aadb738 GIT binary patch literal 401 zcmeAS@N?(olHy`uVBq!ia0vp^d?3sLBp9rei+F()OS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1wdT{9RM#0%!^3bX-AFeQ1ryD&U4#Q3R0P7x?H)6>N`%O z`W>G#!(83(tc_vbs!5w}xfq3Ityp_PqK$8tfy&~l_yb8%ORsc080_lbw%+>5?ej+} z_WW7lyr*9M`Gn^WZ5-dbl`}kUs(<6Cx9{TC?`A+ps+PD$l%ynG literal 0 HcmV?d00001 diff --git a/assets/icons/MainMenu/TouchTunes_14/frame_05_delay-0.04s.png b/assets/icons/MainMenu/TouchTunes_14/frame_05_delay-0.04s.png new file mode 100644 index 0000000000000000000000000000000000000000..1f5ff11cbc23d74343a5b6a6ad1dc61b9d44f0e3 GIT binary patch literal 397 zcmeAS@N?(olHy`uVBq!ia0vp^d?3sLBp9rei+F()OS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1wdT{9RM#0%!^3bX-AFeQ1ryD&U4#Q3R0P7x?H)zif>gyXtyzadw%0|SdY@A86qt*!O}0-w0Fop=2)T@w7q znTu0nlACX0X{Je1*Y2VjvC~TV9&BcgW17?8uG*Mi$S9s+F3D1qy*6}vaYx-g1GDTj z#b;`pU$k33S(sn2*1KU-+(FibVhygG!g^Y~yR>q)ce_hGKF7!F_y5`Pgo(*Ji)}YN z4Dk;%c_~tGhPD5$cZ0o+pMK_3ZMH(716500BT7;dOH!?pi&B9UgOP!ek*w=Pi8W=oX{an^LB{Ts5*Ts1t literal 0 HcmV?d00001 diff --git a/assets/icons/MainMenu/TouchTunes_14/frame_06_delay-0.04s.png b/assets/icons/MainMenu/TouchTunes_14/frame_06_delay-0.04s.png new file mode 100644 index 0000000000000000000000000000000000000000..8fbf8625c14e9522cbcf2bbaf5a9c59a43c2ae08 GIT binary patch literal 400 zcmeAS@N?(olHy`uVBq!ia0vp^d?3sLBp9rei+F()OS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1wdT{9RM#0%!^3bX-AFeQ1ryD&U4#Q3R0P7x?H!_&nvgyXtyzdm=f1B3hgjr%1Lpc_?7Tq814Ba#1H&(%P{RubhEf9thF1wdT{9RM#0%!^3bX-AFeQ1ryD&U4#Q3R0P7x?H$J50zgyXvH`TeUM3mF_f_UqqW{Z8psp3jt|FX|ia>_0qz z#r6rVGw&x=Xm+}uI`Q^Yzj=(Lf4aroQ_|DbSLt5aFhhNZ-!Yb)PZnK|YCdm#Tliiz z=l_&#JG)PGw}~w&oahjAWaR>DTe$}XbIMq)ZpyxkT+Z`% zS7Lrh(npK`C)RECFP|`9syEoq;puLLqxM!Udb;y1?RtRjR4s9hC`m~yNwrEYN(E93 zMg~Skx(24Yh9)5frdGzrR;H%f1_o9@^!e326b-rgDVb@NxHWjM3rYfNVDNPHb6Mw< G&;$TK5sjVz literal 0 HcmV?d00001 diff --git a/assets/icons/MainMenu/TouchTunes_14/frame_08_delay-0.04s.png b/assets/icons/MainMenu/TouchTunes_14/frame_08_delay-0.04s.png new file mode 100644 index 0000000000000000000000000000000000000000..f3724bbde1a247fc66caf5a56bf8b2facbd30303 GIT binary patch literal 414 zcmeAS@N?(olHy`uVBq!ia0vp^d?3sLBp9rei+F()OS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1wdT{9RM#0%!^3bX-AFeQ1ryD&U4#Q3R0P7x@y%+tj&gyXvISw+640GR_1=ljPMMcixK%siJl!}OJ>4P*F2 z3AWkF2HeKVjBbUOHy)gE)cmKkLEX#QoHw3}�D?c`#+yfep4kI+1-V7N$JPl8^fG z_t*08ZijC(i_}h%W|*vQyQ;6(o~dVFXZBMzUMYvmEbEMpugKUqZCghlo1mxmNu!lP zf`tvyq4hgV?xuC+9G@AR&dAzwID2CSucCqQ27ZQXQgz$DIQc)X5|swJShd78q9i4; zB-JXpC>2OC7#SED=^B{o8k&R{m|7VdTbY__8yHvt(dSq9P&DM`r(~v8;@053E+`48 Ofx*+&&t;ucLK6U|y@bmE literal 0 HcmV?d00001 diff --git a/assets/icons/MainMenu/TouchTunes_14/frame_09_delay-0.04s.png b/assets/icons/MainMenu/TouchTunes_14/frame_09_delay-0.04s.png new file mode 100644 index 0000000000000000000000000000000000000000..ff34450d944f74517bd986e51df5c6c683462183 GIT binary patch literal 427 zcmeAS@N?(olHy`uVBq!ia0vp^d?3sLBp9rei+F()OS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1wdT{9RM#0%!^3bX-AFeQ1ryD&U4#Q3R0P7x@y+0(@_gyXvISwpYG0SpWmrauwZaa-FVd!$3xs;sD3tKaWt|zHpXfhvfE;SNCUFZeA&Ec%_TRt6bt-1zFmJ+ z)RcX1gQK0omPAixH{#i)<&;glJzGZ z8kMb+TfP?PeAN=yh?11Vl2ohYqEsNoU}Ruqq-$WRYiJT;U}|M-Y-MVyZD3#pM4w;X eL(!0%pOTqYiCcsBx}YSW1_n=8KbLh*2~7Yaw3eL! literal 0 HcmV?d00001 diff --git a/assets/icons/MainMenu/TouchTunes_14/frame_10_delay-0.04s.png b/assets/icons/MainMenu/TouchTunes_14/frame_10_delay-0.04s.png new file mode 100644 index 0000000000000000000000000000000000000000..2b61340cba323b443891bfc2d1a29d61f781c469 GIT binary patch literal 427 zcmeAS@N?(olHy`uVBq!ia0vp^d?3sLBp9rei+F()OS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1wdT{9RM#0%!^3bX-AFeQ1ryD&U4#Q3R0P7x@y+0(@_gyXvId3$cgLYan-&(FPo@kf1n&=j3b5jS$;Is@I_ zyJ^NX98Fkorb|UK=U?vef+@o5_O%(;ZF_!^C9j&{lw`nx4>ICg+!wySd~TWJO|ym$ z9~nWxbR8wDm>6M&k2f36ZTkL+;m(T;#|1`j*LWK~u*&~>xay*fYZJqgbIX>#I_h|- zpmB+5_H&bicdNJ;d|ZH#L1(v+uUO_QmvAUQh^kMk%5tsu7Rnpp-G5=sg<#@m8q$=fq@keeSUQh eMMG|WN@iLmZVle+f|7t57(8A5T-G@yGywp`fS8s5 literal 0 HcmV?d00001 diff --git a/assets/icons/MainMenu/TouchTunes_14/frame_11_delay-0.04s.png b/assets/icons/MainMenu/TouchTunes_14/frame_11_delay-0.04s.png new file mode 100644 index 0000000000000000000000000000000000000000..9420c763fffc590092d0d55b554f30feeceb6cd8 GIT binary patch literal 426 zcmeAS@N?(olHy`uVBq!ia0vp^d?3sLBp9rei+F()OS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1wdT{9RM#0%!^3bX-AFeQ1ryD&U4#Q3R0P7x@y$*;`j_m2`=xLvC`eLVAarIT5gpD*Z)hk@=M~ldAUB-)a1K z_oN?}{N<^Feb1z;gADFOoz>kR?|=JPO4uFiKWn$XDHpEX?!fg*UACUj>mOqvyOZ9L zBT1D&*Q=JeMwFx^mZVxG7o`Fz1|tI_BV7YiT|<))15+zwV=GfrZ36=14Ba#1H&(%P{RubhEf9thF1wdT{9RM#0%!^3bX-AFeQ1ryD&U4#Q3R0P7x@y-P6S}gyXvEIYaH1LK%h!&;P%F7w7uw(pRaJz)3n{_YXc2 zzQMEUw~^aZ<`Yw&uH#W-lhojBE;(BLuB&9?AD;I=a{RegS#P+su<`Ko$Qqq@*VjCI z?o_p2L21|Gj*dWcC8Om#dEc%~-t_Nl0ng)y&hd8d-|qEI__XQr?h~noCmiHNQoDXH zzIs-y?%cX<(}Q=&PF25AH8*m4Q}fc7Z{EKy+@5DsD>mJ1pSG#^tj@5_4qU6GdG}wl z`ok>r$H{H-rWJNTFQ}HdMwFx^mZVxG7o`Fz1|tI_BV7YiT|<))15+zwV=GfrZ36=< jAo~339*TzC{FKbJO57T}*99d3H86O(`njxgN@xNAcITV8 literal 0 HcmV?d00001 diff --git a/assets/icons/MainMenu/TouchTunes_14/frame_13_delay-0.04s.png b/assets/icons/MainMenu/TouchTunes_14/frame_13_delay-0.04s.png new file mode 100644 index 0000000000000000000000000000000000000000..e9527fa833491eff3316cd410a901508344f1179 GIT binary patch literal 424 zcmeAS@N?(olHy`uVBq!ia0vp^d?3sLBp9rei+F()OS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1wdT{9RM#0%!^3bX-AFeQ1ryD&U4#Q3R0P7x@y!PCVtgyXvExrJWLg)$5e-q-K478E>YXwcD-nITfczWM0B z2i!l5y3M+i&u*}7EC`I;wcz0)d3}p!qbKPRe{M~0+Qal%aCb$8{gLY@|4#e4g72lV zv&)&^9UXOYf~=d1I1U%NC0;C(EV`~Ia<=GFe!^w{X}*Esu}neXS2gd+9lu`vqcZO9 zyyX|x_|JFR_4CI5DNQeLGVZ&*J9lwxxc<7j&AR>UokanPtUs^z*^4XxV^n$V14Ba#1H&(%P{RubhEf9thF1wdT{9RM#0%!^3bX-AFeQ1ryD&U4#Q3R0P7x@y!PCVtgyXvExrJWLg)$5e-q-K478E>YXwcD-nITfczWM0B z2i!l5y3M+i&u*}7EC`I;wcz0)d3}p!qbKPRe{M~0+Qal%aCb$8{gLY@|4#e4g72lV zv&)&^9UXOYf~=d1I1U%NC0;C(EV`~Ia<=GFe!^w{X}*Esu}neXS2gd+9lu`vqcZO9 zyyX|x_|JFR_4CI5DNQeLGVZ&*J9lwxxc<7j&AR>UokanPtUs^z*^4XxV^n$V14Ba#1H&(%P{RubhEf9thF1wdT{9RM#0%!^3bX-AFeQ1ryD&U4#Q3R0P7x@y!PCVtgyXvExrJWLg)$5e-q-K478E>YXwcD-nITfczWM0B z2i!l5y3M+i&u*}7EC`I;wcz0)d3}p!qbKPRe{M~0+Qal%aCb$8{gLY@|4#e4g72lV zv&)&^9UXOYf~=d1I1U%NC0;C(EV`~Ia<=GFe!^w{X}*Esu}neXS2gd+9lu`vqcZO9 zyyX|x_|JFR_4CI5DNQeLGVZ&*J9lwxxc<7j&AR>UokanPtUs^z*^4XxV^n$V14Ba#1H&(%P{RubhEf9thF1wdT{9RM#0%!^3bX-AFeQ1ryD&U4#Q3R0P7x@y!PCVtgyXvExrJWLg)$5e-q-K478E>YXwcD-nITfczWM0B z2i!l5y3M+i&u*}7EC`I;wcz0)d3}p!qbKPRe{M~0+Qal%aCb$8{gLY@|4#e4g72lV zv&)&^9UXOYf~=d1I1U%NC0;C(EV`~Ia<=GFe!^w{X}*Esu}neXS2gd+9lu`vqcZO9 zyyX|x_|JFR_4CI5DNQeLGVZ&*J9lwxxc<7j&AR>UokanPtUs^z*^4XxV^n$V14Ba#1H&(%P{RubhEf9thF1wdT{9RM#0%!^3bX-AFeQ1ryD&U4#Q3R0P7x@y$YVmxV$pEMJR$-=0RQDmEJEGEez`JuDH25=U{}d1EyNU3=Kf%IJ?Y|` z8Q3lcbiHbcYeY#(Vo9o1a#1RfVlXl=GSW3L)ipE;F)+0cptHiCrdtFcxPy>UftDnm{r-UW|_-&5! literal 0 HcmV?d00001 diff --git a/assets/icons/MainMenu/TouchTunes_14/frame_18_delay-0.04s.png b/assets/icons/MainMenu/TouchTunes_14/frame_18_delay-0.04s.png new file mode 100644 index 0000000000000000000000000000000000000000..2109273f0538a073ab31357ea73ca5d6ef928442 GIT binary patch literal 418 zcmeAS@N?(olHy`uVBq!ia0vp^d?3sLBp9rei+F()OS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1wdT{9RM#0%!^3bX-AFeQ1ryD&U4#Q3R0P7x@y%G1R$gyXvE*@a%ri3|)6-v8hDPlrb)T@IPZ3eYKokH`;F`Tf204uo4&4o)<4s-CmB5xGVNXGem-K)sAc8lE8^e}bhT=U zYeY#(Vo9o1a#1RfVlXl=GSW3L)ipE;F)+0cptHiCr TdtFcxPy>UftDnm{r-UW|SWb=} literal 0 HcmV?d00001 diff --git a/assets/icons/MainMenu/TouchTunes_14/frame_19_delay-0.04s.png b/assets/icons/MainMenu/TouchTunes_14/frame_19_delay-0.04s.png new file mode 100644 index 0000000000000000000000000000000000000000..0c7e9eaa9acfc11c5ba98495c64feb772ce07b6b GIT binary patch literal 419 zcmeAS@N?(olHy`uVBq!ia0vp^d?3sLBp9rei+F()OS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1wdT{9RM#0%!^3bX-AFeQ1ryD&U4#Q3R0P7x@y+SA1`gyVYX`Hfsn4h#(s|MyKkFe^%?g-v|vx2(=%w-zmb zF|&#({=mX*3zjajJmSg1&Z>N(&H1I&9I5{=AB(fiS`@nF)J6x!i)fnra&uSOL-JSNBjf;M1& literal 0 HcmV?d00001 diff --git a/assets/icons/MainMenu/TouchTunes_14/frame_20_delay-0.04s.png b/assets/icons/MainMenu/TouchTunes_14/frame_20_delay-0.04s.png new file mode 100644 index 0000000000000000000000000000000000000000..4c283af6cc3dd76ef888f62b770519219a2d79d2 GIT binary patch literal 425 zcmeAS@N?(olHy`uVBq!ia0vp^d?3sLBp9rei+F()OS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1wdT{9RM#0%!^3bX-AFeQ1ryD&U4#Q3R0P7x@y(bL5-gyXtypCLD6B7?*IxsN?wc6q!sk~os2$QBu)`>(0~ zLHXSxH#OCygu+0tSFgG^Y1E#oJy&q=SKIe30u>qx(^z>D%>0?x|6?dQFgZ;r(d&Ia z_ugCLcdePCPH1JQHGaSLV!>m*BfJmP#Pl|P%G`ANDdT^uGQC}ES?XIhZT;}TyM(P^jg7!02l4F2+--9u6g;Q}?C*+$5EIK(@i=1M}oG>y=+$ zUJ3;|UbVzEq9i4;B-JXpC>2OC7#SED=^B{o8k&R{m|7VdTbY__8yHvt(dSq9P&DM` ar(~v8;@053E+`48fx*+&&t;ucLK6UXX_27- literal 0 HcmV?d00001 diff --git a/assets/icons/MainMenu/TouchTunes_14/frame_21_delay-0.04s.png b/assets/icons/MainMenu/TouchTunes_14/frame_21_delay-0.04s.png new file mode 100644 index 0000000000000000000000000000000000000000..750aec1627b2bcb3a822647a39c185312a4276f8 GIT binary patch literal 415 zcmeAS@N?(olHy`uVBq!ia0vp^d?3sLBp9rei+F()OS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1wdT{9RM#0%!^3bX-AFeQ1ryD&U4#Q3R0P7x@y+|$J|gyXvIxs6;+0U`|#@1J&^(qYiFd#jb_Wc>>QzI#*k zFHABq`NGCq&d1WOAn;bLiQUh+*8hVm*A}K5JR1&tHDb2gtt)Y${l=||4-QKT;w>KB z%st@nK6ci!m7i@Tp4{kVNG=!QnR+I>p-NAbP27V)sOfNk*jXvTYrcU^uS%r9)LeUL zw$hF3YPRX5Jz>A^zf%0z>HPcI_EXNAW6Tu)ug^HDWX8O2x{C8O)?mIIpp#WgTq814Ba#1H&(%P{RubhEf9thF1wdT{9RM#0%!^3bX-AFeQ1ryD&U4#Q3R0P7x?H*VDx@gyXvIxxHD30vH-DKK8xB9Tc-g_6}=$yn_|%uRTue zFQrAo+w+vFrYigsQ8Bryc<%m(xz}XdrEUsX+U>9UQLE1p5xVhq?^Uj~*7w)v|986O zKYLeXdD5FT<{WRP3D3|eXAxU0^XX#Kfd|*xzU4Y3gykhhpW`_4Xw9lQ-8T&Srng)^ z9sKoi{=3CKXHWc?_3LkmtbHh7>9TWe6$~!5#&P9~w%i0dRJFu4q9i4;B-JXpC>2OC z7#SED=^B{o8k&R{m|7VdTbY__8yHvt(dSq9P&DM`r(~v8;@053E+`48fx*+&&t;uc GLK6TW7K_OM literal 0 HcmV?d00001 diff --git a/assets/icons/MainMenu/TouchTunes_14/frame_23_delay-0.04s.png b/assets/icons/MainMenu/TouchTunes_14/frame_23_delay-0.04s.png new file mode 100644 index 0000000000000000000000000000000000000000..17007aad5b72394efd0dc44c1695aa84df0dbba8 GIT binary patch literal 394 zcmeAS@N?(olHy`uVBq!ia0vp^d?3sLBp9rei+F()OS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1wdT{9RM#0%!^3bX-AFeQ1ryD&U4#Q3R0P7x?H$RT|6Y<(mnr^A%=$9Fa`m*%uN!`D-e>!} zB&zh{QtgRLxescKOyrM!rQKXPsvQH#I3=5T~HEG1B0ilpUXO@geCx6DTF`( literal 0 HcmV?d00001 diff --git a/assets/icons/MainMenu/TouchTunes_14/frame_24_delay-0.04s.png b/assets/icons/MainMenu/TouchTunes_14/frame_24_delay-0.04s.png new file mode 100644 index 0000000000000000000000000000000000000000..4c03a8101928e3271e518ca78035200e788ad972 GIT binary patch literal 401 zcmeAS@N?(olHy`uVBq!ia0vp^d?3sLBp9rei+F()OS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1wdT{9RM#0%!^3bX-AFeQ1ryD&U4#Q3R0P7x?H)6>Nq6`gxmuO$_jb>;+NNMOnR8l6h2;5yokve>Wxd+das69i$e*y^XWk!`dFlSFXuI3z zwuWB@1~RWYr&~>Y<(+mtC-HU(OVCZna5bi<&p3|z&b)o^z=HX1%a@;LuRq;C{mkv3 zukRMu&vsj_!BW_o^yJpP#no%l{xExO(qWTKIK2kwNYxV8h?11Vl2ohYqEsNoU}Ruq zq-$WRYiJT;U}|M-Y-MVyZD3#pM4w;XL(!0%pOTqYiCcsBx}YSW1_n=8KbLh*2~7a5 C2#f>( literal 0 HcmV?d00001 diff --git a/assets/icons/MainMenu/TouchTunes_14/frame_25_delay-0.04s.png b/assets/icons/MainMenu/TouchTunes_14/frame_25_delay-0.04s.png new file mode 100644 index 0000000000000000000000000000000000000000..334498adcefb0195df99757781c744a567450337 GIT binary patch literal 401 zcmeAS@N?(olHy`uVBq!ia0vp^d?3sLBp9rei+F()OS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1wdT{9RM#0%!^3bX-AFeQ1ryD&U4#Q3R0P7x?H)6>N54HEbeSUg?YOYrz7>ylu^-mseD<8D|KFNtYrh9~{>#rQTgEIC z-Z4?1tLv!3hBMJyK5csT)S&U?LnohUcOK45IkM%rcSPUqg}&TfTX+^w=Pi8W=oX{an^LB{Ts5 DS00MI literal 0 HcmV?d00001 diff --git a/assets/icons/MainMenu/TouchTunes_14/frame_26_delay-0.04s.png b/assets/icons/MainMenu/TouchTunes_14/frame_26_delay-0.04s.png new file mode 100644 index 0000000000000000000000000000000000000000..b203dc30275055bbe87d8475ad1ffff70af7a57e GIT binary patch literal 404 zcmeAS@N?(olHy`uVBq!ia0vp^d?3sLBp9rei+F()OS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1wdT{9RM#0%!^3bX-AFeQ1ryD&U4#Q3R0P7x?H$J50zgyXvIS;MSD2@DMvrzglTm1(G4RlVT5VRch;`v<+f z0s0AH=O1JVd&#z}n-=87@keWkv(dh%zZdnLW}lJX^WodqhW(GWKL7q^qwwE9uV&`Y zFVquE4&1io>7w)%(==ah;yUu?GH=c$Tf<6W1rtld*E#IFbM7uzyY8^VudT?`_UhM_ zE86lc>g3ksB|ZoiGV~L2k)2+yT&^$q|5>y?lk&ab2%tMvOI#yLQW8s2t&)pUffR$0 zfsv7}fvK*cNr-`|m9epvsj0SsffW#aesvE;LvDUbW?Cg~4c_a5l7Jc*JYD@<);T3K F0RT@yh=2e9 literal 0 HcmV?d00001 diff --git a/assets/icons/MainMenu/TouchTunes_14/frame_27_delay-0.04s.png b/assets/icons/MainMenu/TouchTunes_14/frame_27_delay-0.04s.png new file mode 100644 index 0000000000000000000000000000000000000000..3e17c6c76ba81c56c52edd21147e6b1d5e692607 GIT binary patch literal 410 zcmeAS@N?(olHy`uVBq!ia0vp^d?3sLBp9rei+F()OS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1wdT{9RM#0%!^3bX-AFeQ1ryD&U4#Q3R0P7x@y$kW9!gyXvIS;MSD2@(wt)mMHhe-*%S@Tf0G$y-*NCi4#h zdmG$ea&FpT&21%BBFdt;RK(GssYdqE51se3S>MWqurk-k-!G7?|N2LAZ~L3?{^u{| z^d$Gngx(0LmpaKffBJ@;=TDZL+`4$TUr_wL zY3<7_r`&%2eV=4r&9T2Hl~VV(HR@!P$Jx|~{9$%au$)14Ba#1H&(%P{RubhEf9thF1wdT{9RM#0%!^3bX-AFeQ1ryD-F@2(Wt#qtYOxn1c`=+>W)9>T8Sv76t0@EFj@bBU==g} z#k-p;nsnwJIO(`us6>?gXponqfkq8qVa>GfXPZ8Yg|OP5`L6#%zP9v_X1w#a-^-JK zS{~Zx*0(Az^YyC7g{GcMPQL2cac-KRpy277rbR1l7}||a&YUNEg-!1n$^K^oaDR8A6{26`zZuLQCH&4rH({emZfX-Ddag8WRNi0dV zN-jzTQVd20Mn<{@rn-hEAqJ*a#>Q5rrrHJuRzURm)jbpqx%nxXX_dG&c&`ge0%~CJ MboFyt=akR{00vu%od5s; literal 0 HcmV?d00001 diff --git a/assets/icons/MainMenu/TouchTunes_14/frame_29_delay-0.04s.png b/assets/icons/MainMenu/TouchTunes_14/frame_29_delay-0.04s.png new file mode 100644 index 0000000000000000000000000000000000000000..479fbd58b591c8277f06ec1225ee29ee095c8564 GIT binary patch literal 411 zcmeAS@N?(olHy`uVBq!ia0vp^d?3sLBp9rei+F()OS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1wdT{9RM#0%!^3bX-AFeQ1ryD-F@2(Wt#qtYOxn1c`=+>W)9>T8Sv76t0@EFj@bBU==g} z#k-p;nsnwJIO(`us6>?gXponqfkq8qVa>GfXPZ8Yg|OP5`L6#%zP9v_X1w#a-^-JK zS{~Zx*0(Az^YyC7g{GcMPQL2cac-KRpy277rbR1l7}||a&YUNEg-!1n$^K^oaDR8A6{26`zZuLQCH&4rH({emZfX-Ddag8WRNi0dV zN-jzTQVd20Mn<{@rn-hEAqJ*a#>Q5rrrHJuRzURm)jbpqx%nxXX_dG&c&`ge0%~CJ MboFyt=akR{00vu%od5s; literal 0 HcmV?d00001 diff --git a/assets/icons/MainMenu/TouchTunes_14/frame_rate b/assets/icons/MainMenu/TouchTunes_14/frame_rate new file mode 100644 index 000000000..e440e5c84 --- /dev/null +++ b/assets/icons/MainMenu/TouchTunes_14/frame_rate @@ -0,0 +1 @@ +3 \ No newline at end of file diff --git a/assets/icons/MainMenu/UniversalRemote_14/frame_1.png b/assets/icons/MainMenu/UniversalRemote_14/frame_1.png new file mode 100644 index 0000000000000000000000000000000000000000..8d135853f5ec8f6905074e662b76e8d2bdd4535b GIT binary patch literal 170 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh1|;P@bT0xa#^NA%Cx&(BWL^R}DV{ElAsQ36 zPO|1ZV8G$bd+P7{H-0W0H#4oi^d6~6;+WK;pv1uNO!DO0T9!xIDu1PfUK=WxLI)A-h;@|GLAog4MsTe0*o-BgT3T7g19- SlLmdKI;Vst0H}aDT>t<8 literal 0 HcmV?d00001 diff --git a/assets/icons/MainMenu/UniversalRemote_14/frame_3.png b/assets/icons/MainMenu/UniversalRemote_14/frame_3.png new file mode 100644 index 0000000000000000000000000000000000000000..c64bad5f2f2f43005e57613bf0acf6e743a64c90 GIT binary patch literal 171 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh1|;P@bT0xa#^NA%Cx&(BWL^R}sh%#5AsQ3s zPV(eCpuoeNd*y$9Wz{05iNP7qCFZcIvjrU3rn0i~+KWjHjQ)+ML>GG>@0)R>cf0SJ zyFm-HMbFuXKI~b$YhsIaPI|b%ME;Cviq-JoMr6)F8KJa%}03m2|J2P TGp2k4TFBt(>gTe~DWM4fkSaY6 literal 0 HcmV?d00001 diff --git a/assets/icons/MainMenu/UniversalRemote_14/frame_4.png b/assets/icons/MainMenu/UniversalRemote_14/frame_4.png new file mode 100644 index 0000000000000000000000000000000000000000..efd7181f0a36490d555a6e16df3bf2c457d592f2 GIT binary patch literal 168 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh1|;P@bT0xa#^NA%Cx&(BWL^R}NuDl_AsQ36 zP735ZpupkG{qbM;yL|>NTh8g+{C$LJtCR|-qYDGW8N*Aa6Io8$CTvRCnp<+hE&cu0 z!o1+-F!5`1mu<+3o$gh!i0wp3{)ylxUAfV<4X+E-_S+r*UJ$Y|zhIkujl7+h)rISO QfVMGsy85}Sb4q9e00DD6_y7O^ literal 0 HcmV?d00001 diff --git a/assets/icons/MainMenu/UniversalRemote_14/frame_5.png b/assets/icons/MainMenu/UniversalRemote_14/frame_5.png new file mode 100644 index 0000000000000000000000000000000000000000..300f00128d067e358fc954204533468eb5efd495 GIT binary patch literal 169 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh1|;P@bT0xa#^NA%Cx&(BWL^R}$(}BbAsQ36 zPO{`~duFbQL9S`u-Lk+<4WXrnW^n{sChumK=w57N>#ps$@6P(ZD&ynqR>F>=Ql-zl QfYvd1y85}Sb4q9e0N5=zEdT%j literal 0 HcmV?d00001 diff --git a/assets/icons/MainMenu/UniversalRemote_14/frame_6.png b/assets/icons/MainMenu/UniversalRemote_14/frame_6.png new file mode 100644 index 0000000000000000000000000000000000000000..24c349ead5a777f2be43ed17b96ef15b58e20cc4 GIT binary patch literal 165 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh1|;P@bT0xa#^NA%Cx&(BWL^R}@t!V@AsQ36 z208K_FyLUi{J(zY++7mOubN1zCm$4=GO2|{g^}T?@f(${Qtdejsb^2cY4?2FmdKI;Vst0H}aDT>t<8 literal 0 HcmV?d00001 diff --git a/assets/icons/MainMenu/UniversalRemote_14/frame_7.png b/assets/icons/MainMenu/UniversalRemote_14/frame_7.png new file mode 100644 index 0000000000000000000000000000000000000000..d41a66495a6bc1e308e97112671d73ddc495f5e4 GIT binary patch literal 166 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh1|;P@bT0xa#^NA%Cx&(BWL^R}37#&FAsQ2p z208K_FyL_7{J(zY+=y9hQTdOrga|f?c^+D@ih*HakDtmUg`d1PKHj+RYIsm+@?P!2 z@Z#pE-mEgQ>$C2yRah2~V0M-Bm&nd$nQ7Jyo)-3Nl~>N2viR!liTkDdEL8s-*gX$u O7lWs(pUXO@geCx08#~tk literal 0 HcmV?d00001 diff --git a/firmware/targets/f7/furi_hal/furi_hal_nfc.c b/firmware/targets/f7/furi_hal/furi_hal_nfc.c index 768a4bac7..e6b27573d 100755 --- a/firmware/targets/f7/furi_hal/furi_hal_nfc.c +++ b/firmware/targets/f7/furi_hal/furi_hal_nfc.c @@ -1,9 +1,12 @@ #include "furi_hal_nfc.h" #include +#include #include #include #include -#include + +#include +#include #define TAG "FuriHalNfc" @@ -394,6 +397,80 @@ ReturnCode furi_hal_nfc_data_exchange( return ret; } +static bool furi_hal_nfc_transparent_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_t timeout_ms) { + furi_assert(tx_rx->nfca_signal); + + platformDisableIrqCallback(); + + bool ret = false; + + // Start transparent mode + st25r3916ExecuteCommand(ST25R3916_CMD_TRANSPARENT_MODE); + // Reconfigure gpio + furi_hal_spi_bus_handle_deinit(&furi_hal_spi_bus_handle_nfc); + furi_hal_gpio_init(&gpio_spi_r_sck, GpioModeInput, GpioPullUp, GpioSpeedLow); + furi_hal_gpio_init(&gpio_spi_r_miso, GpioModeInput, GpioPullUp, GpioSpeedLow); + furi_hal_gpio_init(&gpio_nfc_cs, GpioModeInput, GpioPullUp, GpioSpeedLow); + furi_hal_gpio_init(&gpio_spi_r_mosi, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); + furi_hal_gpio_write(&gpio_spi_r_mosi, false); + + // Send signal + nfca_signal_encode(tx_rx->nfca_signal, tx_rx->tx_data, tx_rx->tx_bits / 8, tx_rx->tx_parity); + digital_signal_send(tx_rx->nfca_signal->tx_signal, &gpio_spi_r_mosi); + 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); + st25r3916ExecuteCommand(ST25R3916_CMD_UNMASK_RECEIVE_DATA); + + // Manually wait for interrupt + furi_hal_gpio_init(&gpio_rfid_pull, GpioModeInput, GpioPullDown, GpioSpeedVeryHigh); + st25r3916ClearAndEnableInterrupts(ST25R3916_IRQ_MASK_RXE); + + uint32_t irq = 0; + uint8_t rxe = 0; + uint32_t start = DWT->CYCCNT; + while(true) { + if(furi_hal_gpio_read(&gpio_rfid_pull) == true) { + st25r3916ReadRegister(ST25R3916_REG_IRQ_MAIN, &rxe); + if(rxe & (1 << 4)) { + irq = 1; + break; + } + } + uint32_t timeout = DWT->CYCCNT - start; + if(timeout / furi_hal_delay_instructions_per_microsecond() > timeout_ms * 1000) { + FURI_LOG_D(TAG, "Interrupt waiting timeout"); + break; + } + } + if(irq) { + uint8_t fifo_stat[2]; + st25r3916ReadMultipleRegisters( + ST25R3916_REG_FIFO_STATUS1, fifo_stat, ST25R3916_FIFO_STATUS_LEN); + uint16_t len = + ((((uint16_t)fifo_stat[1] & ST25R3916_REG_FIFO_STATUS2_fifo_b_mask) >> + ST25R3916_REG_FIFO_STATUS2_fifo_b_shift) + << RFAL_BITS_IN_BYTE); + len |= (((uint16_t)fifo_stat[0]) & 0x00FFU); + uint8_t rx[100]; + st25r3916ReadFifo(rx, len); + + tx_rx->rx_bits = len * 8; + memcpy(tx_rx->rx_data, rx, len); + + ret = true; + } else { + FURI_LOG_E(TAG, "Timeout error"); + ret = false; + } + + st25r3916ClearInterrupts(); + platformEnableIrqCallback(); + + return ret; +} + static uint32_t furi_hal_nfc_tx_rx_get_flag(FuriHalNfcTxRxType type) { uint32_t flags = 0; @@ -405,6 +482,9 @@ static uint32_t furi_hal_nfc_tx_rx_get_flag(FuriHalNfcTxRxType type) { } else if(type == FuriHalNfcTxRxTypeRaw) { flags = RFAL_TXRX_FLAGS_CRC_TX_MANUAL | RFAL_TXRX_FLAGS_CRC_RX_KEEP | RFAL_TXRX_FLAGS_PAR_RX_KEEP | RFAL_TXRX_FLAGS_PAR_TX_NONE; + } else if(type == FuriHalNfcTxRxTypeRxRaw) { + flags = RFAL_TXRX_FLAGS_CRC_TX_MANUAL | RFAL_TXRX_FLAGS_CRC_RX_KEEP | + RFAL_TXRX_FLAGS_PAR_RX_KEEP | RFAL_TXRX_FLAGS_PAR_TX_NONE; } return flags; @@ -470,6 +550,10 @@ bool furi_hal_nfc_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_t timeout_ms) { uint8_t* temp_rx_buff = NULL; uint16_t* temp_rx_bits = NULL; + if(tx_rx->tx_rx_type == FuriHalNfcTxRxTransparent) { + return furi_hal_nfc_transparent_tx_rx(tx_rx, timeout_ms); + } + // Prepare data for FIFO if necessary uint32_t flags = furi_hal_nfc_tx_rx_get_flag(tx_rx->tx_rx_type); if(tx_rx->tx_rx_type == FuriHalNfcTxRxTypeRaw) { @@ -502,7 +586,8 @@ bool furi_hal_nfc_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_t timeout_ms) { osDelay(1); } - if(tx_rx->tx_rx_type == FuriHalNfcTxRxTypeRaw) { + if(tx_rx->tx_rx_type == FuriHalNfcTxRxTypeRaw || + tx_rx->tx_rx_type == FuriHalNfcTxRxTypeRxRaw) { tx_rx->rx_bits = 8 * furi_hal_nfc_bitstream_to_data_and_parity( temp_rx_buff, *temp_rx_bits, tx_rx->rx_data, tx_rx->rx_parity); } else { diff --git a/firmware/targets/furi_hal_include/furi_hal_nfc.h b/firmware/targets/furi_hal_include/furi_hal_nfc.h index 20a469002..860db80de 100755 --- a/firmware/targets/furi_hal_include/furi_hal_nfc.h +++ b/firmware/targets/furi_hal_include/furi_hal_nfc.h @@ -10,6 +10,8 @@ #include #include +#include + #ifdef __cplusplus extern "C" { #endif @@ -39,6 +41,8 @@ typedef enum { FuriHalNfcTxRxTypeRxNoCrc, FuriHalNfcTxRxTypeRxKeepPar, FuriHalNfcTxRxTypeRaw, + FuriHalNfcTxRxTypeRxRaw, + FuriHalNfcTxRxTransparent, } FuriHalNfcTxRxType; typedef bool (*FuriHalNfcEmulateCallback)( @@ -80,6 +84,7 @@ typedef struct { uint8_t rx_parity[FURI_HAL_NFC_PARITY_BUFF_SIZE]; uint16_t rx_bits; FuriHalNfcTxRxType tx_rx_type; + NfcaSignal* nfca_signal; } FuriHalNfcTxRxContext; /** Init nfc diff --git a/lib/digital_signal/digital_signal.c b/lib/digital_signal/digital_signal.c new file mode 100644 index 000000000..b9be3b602 --- /dev/null +++ b/lib/digital_signal/digital_signal.c @@ -0,0 +1,173 @@ +#include "digital_signal.h" + +#include +#include +#include +#include + +#define F_TIM (64000000.0) +#define T_TIM (1.0 / F_TIM) + +#define MAX_ARR_BUFF_SIZE (10000) + +// TODO rework with dynamic allocation +static uint32_t digital_signal_arr_buff[MAX_ARR_BUFF_SIZE]; + +DigitalSignal* digital_signal_alloc(uint32_t max_edges_cnt) { + DigitalSignal* signal = malloc(sizeof(DigitalSignal)); + signal->start_level = true; + signal->edges_max_cnt = max_edges_cnt; + signal->edge_timings = malloc(max_edges_cnt * sizeof(float)); + signal->edge_cnt = 0; + + return signal; +} + +void digital_signal_free(DigitalSignal* signal) { + furi_assert(signal); + + free(signal->edge_timings); + free(signal); +} + +bool digital_signal_append(DigitalSignal* signal_a, DigitalSignal* signal_b) { + furi_assert(signal_a); + furi_assert(signal_b); + + if(signal_a->edges_max_cnt < signal_a->edge_cnt + signal_b->edge_cnt) { + return false; + } + + bool end_level = signal_a->start_level ^ !(signal_a->edge_cnt % 2); + uint8_t start_copy = 0; + if(end_level == signal_b->start_level) { + if(signal_a->edge_cnt) { + signal_a->edge_timings[signal_a->edge_cnt - 1] += signal_b->edge_timings[0]; + } else { + signal_a->edge_timings[signal_a->edge_cnt] += signal_b->edge_timings[0]; + } + start_copy += 1; + } + memcpy( + &signal_a->edge_timings[signal_a->edge_cnt], + &signal_b->edge_timings[start_copy], + (signal_b->edge_cnt - start_copy) * sizeof(float)); + signal_a->edge_cnt += signal_b->edge_cnt - start_copy; + + return true; +} + +bool digital_signal_get_start_level(DigitalSignal* signal) { + furi_assert(signal); + + return signal->start_level; +} + +uint32_t digital_signal_get_edges_cnt(DigitalSignal* signal) { + furi_assert(signal); + + return signal->edge_cnt; +} + +float digital_signal_get_edge(DigitalSignal* signal, uint32_t edge_num) { + furi_assert(signal); + furi_assert(edge_num < signal->edge_cnt); + + return signal->edge_timings[edge_num]; +} + +static void digital_signal_prepare_arr(DigitalSignal* signal, uint32_t* arr) { + float t_signal = 0; + float t_current = 0; + float r = 0; + float r_int = 0; + float r_dec = 0; + + for(size_t i = 0; i < signal->edge_cnt - 1; i++) { + t_signal += signal->edge_timings[i]; + r = (t_signal - t_current) / T_TIM; + r_dec = modff(r, &r_int); + if(r_dec < 0.5f) { + arr[i] = (uint32_t)r_int - 1; + } else { + arr[i] = (uint32_t)r_int; + } + t_current += (arr[i] + 1) * T_TIM; + } +} + +bool digital_signal_send(DigitalSignal* signal, const GpioPin* gpio) { + furi_assert(signal); + furi_assert(gpio); + + // Configure gpio as output + furi_hal_gpio_init(gpio, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); + + // Init gpio buffer and DMA channel + uint16_t gpio_reg = gpio->port->ODR; + uint16_t gpio_buff[2]; + if(signal->start_level) { + gpio_buff[0] = gpio_reg | gpio->pin; + gpio_buff[1] = gpio_reg & ~(gpio->pin); + } else { + gpio_buff[0] = gpio_reg & ~(gpio->pin); + gpio_buff[1] = gpio_reg | gpio->pin; + } + LL_DMA_InitTypeDef dma_config = {}; + dma_config.MemoryOrM2MDstAddress = (uint32_t)gpio_buff; + dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (gpio->port->ODR); + dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; + dma_config.Mode = LL_DMA_MODE_CIRCULAR; + dma_config.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; + dma_config.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; + dma_config.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_HALFWORD; + dma_config.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_HALFWORD; + dma_config.NbData = 2; + dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; + dma_config.Priority = LL_DMA_PRIORITY_VERYHIGH; + LL_DMA_Init(DMA1, LL_DMA_CHANNEL_1, &dma_config); + LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_1, 2); + LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1); + + // Init timer arr register buffer and DMA channel + digital_signal_prepare_arr(signal, digital_signal_arr_buff); + dma_config.MemoryOrM2MDstAddress = (uint32_t)digital_signal_arr_buff; + dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (TIM2->ARR); + dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; + dma_config.Mode = LL_DMA_MODE_NORMAL; + dma_config.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; + dma_config.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; + dma_config.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; + dma_config.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; + dma_config.NbData = signal->edge_cnt - 2; + dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; + dma_config.Priority = LL_DMA_PRIORITY_HIGH; + LL_DMA_Init(DMA1, LL_DMA_CHANNEL_2, &dma_config); + LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_2, signal->edge_cnt - 2); + LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2); + + // Set up 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, 10); + LL_TIM_SetCounter(TIM2, 0); + LL_TIM_EnableUpdateEvent(TIM2); + LL_TIM_EnableDMAReq_UPDATE(TIM2); + + // Start transactions + LL_TIM_GenerateEvent_UPDATE(TIM2); // Do we really need it? + LL_TIM_EnableCounter(TIM2); + + while(!LL_DMA_IsActiveFlag_TC2(DMA1)) + ; + + LL_DMA_ClearFlag_TC1(DMA1); + LL_DMA_ClearFlag_TC2(DMA1); + LL_TIM_DisableCounter(TIM2); + LL_TIM_SetCounter(TIM2, 0); + LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_1); + LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_2); + + return true; +} diff --git a/lib/digital_signal/digital_signal.h b/lib/digital_signal/digital_signal.h new file mode 100644 index 000000000..3b3ad77f7 --- /dev/null +++ b/lib/digital_signal/digital_signal.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include +#include + +#include + +typedef struct { + bool start_level; + uint32_t edge_cnt; + uint32_t edges_max_cnt; + float* edge_timings; +} DigitalSignal; + +DigitalSignal* digital_signal_alloc(uint32_t max_edges_cnt); + +void digital_signal_free(DigitalSignal* signal); + +bool digital_signal_append(DigitalSignal* signal_a, DigitalSignal* signal_b); + +bool digital_signal_get_start_level(DigitalSignal* signal); + +uint32_t digital_signal_get_edges_cnt(DigitalSignal* signal); + +float digital_signal_get_edge(DigitalSignal* signal, uint32_t edge_num); + +bool digital_signal_send(DigitalSignal* signal, const GpioPin* gpio); diff --git a/lib/lib.mk b/lib/lib.mk index cb58fadeb..43f4a1a25 100644 --- a/lib/lib.mk +++ b/lib/lib.mk @@ -95,6 +95,11 @@ C_SOURCES += $(wildcard $(LIB_DIR)/toolbox/*/*.c) CPP_SOURCES += $(wildcard $(LIB_DIR)/toolbox/*.cpp) CPP_SOURCES += $(wildcard $(LIB_DIR)/toolbox/*/*.cpp) +# Digital signal +CFLAGS += -I$(LIB_DIR)/digital_signal +C_SOURCES += $(wildcard $(LIB_DIR)/digital_signal/*.c) + + # USB Stack CFLAGS += -I$(LIB_DIR)/libusb_stm32/inc C_SOURCES += $(LIB_DIR)/libusb_stm32/src/usbd_stm32wb55_devfs.c diff --git a/lib/nfc_protocols/crypto1.c b/lib/nfc_protocols/crypto1.c index 469b0de09..f08164ba9 100644 --- a/lib/nfc_protocols/crypto1.c +++ b/lib/nfc_protocols/crypto1.c @@ -58,7 +58,7 @@ uint8_t crypto1_byte(Crypto1* crypto1, uint8_t in, int is_encrypted) { return out; } -uint8_t crypto1_word(Crypto1* crypto1, uint32_t in, int is_encrypted) { +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++) { diff --git a/lib/nfc_protocols/crypto1.h b/lib/nfc_protocols/crypto1.h index aaa2470c7..07b39c22c 100644 --- a/lib/nfc_protocols/crypto1.h +++ b/lib/nfc_protocols/crypto1.h @@ -16,7 +16,7 @@ uint8_t crypto1_bit(Crypto1* crypto1, uint8_t in, int is_encrypted); uint8_t crypto1_byte(Crypto1* crypto1, uint8_t in, int is_encrypted); -uint8_t crypto1_word(Crypto1* crypto1, uint32_t in, int is_encrypted); +uint32_t crypto1_word(Crypto1* crypto1, uint32_t in, int is_encrypted); uint32_t crypto1_filter(uint32_t in); diff --git a/lib/nfc_protocols/mifare_classic.c b/lib/nfc_protocols/mifare_classic.c index ace37bff3..087fc74c9 100644 --- a/lib/nfc_protocols/mifare_classic.c +++ b/lib/nfc_protocols/mifare_classic.c @@ -311,3 +311,118 @@ uint8_t mf_classic_read_card( return sectors_read; } + +bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_rx) { + furi_assert(emulator); + furi_assert(tx_rx); + + // Get first frame + tx_rx->tx_bits = 0; + tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault; + furi_hal_nfc_tx_rx(tx_rx, 300); + + // TODO support all commands + uint8_t cmd = tx_rx->rx_data[0]; + if(!(cmd == 0x60 || cmd == 0x61)) { + FURI_LOG_E(TAG, "Unsupported command"); + return false; + } + uint8_t block = tx_rx->rx_data[1]; + uint64_t key = 0; + // TODO Now works only for 1k!!! + uint8_t sector_trailer_block = block | 0x03; + MfClassicSectorTrailer* sector_trailer = + (MfClassicSectorTrailer*)emulator->data.block[sector_trailer_block].value; + if(cmd & 0x01) { + key = nfc_util_bytes2num(sector_trailer->key_b, 6); + } else { + key = nfc_util_bytes2num(sector_trailer->key_a, 6); + } + + uint32_t nonce = prng_successor(DWT->CYCCNT, 32); + 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); + crypto1_word(&emulator->crypto, emulator->cuid ^ nonce, 0); + + memcpy(tx_rx->tx_data, nt, sizeof(nt)); + tx_rx->tx_bits = sizeof(nt) * 8; + tx_rx->tx_rx_type = FuriHalNfcTxRxTypeRxRaw; + if(!furi_hal_nfc_tx_rx(tx_rx, 500)) { + FURI_LOG_E(TAG, "Error in 1st data exchange"); + return false; + } + + if(tx_rx->rx_bits != 64) { + FURI_LOG_E(TAG, "Incorrect nr + ar"); + return false; + } + + 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_E(TAG, "Wrong AUTH! %08X != %08X", cardRr, prng_successor(nonce, 64)); + // Don't send NACK, as tag don't send it + return false; + } + + uint32_t ans = prng_successor(nonce, 96); + uint8_t responce[4] = {}; + nfc_util_num2bytes(ans, 4, responce); + tx_rx->tx_parity[0] = 0; + for(uint8_t i = 0; i < 4; i++) { + tx_rx->tx_data[i] = crypto1_byte(&emulator->crypto, 0, 0) ^ responce[i]; + tx_rx->tx_parity[0] |= + (((crypto1_filter(emulator->crypto.odd) ^ nfc_util_odd_parity8(responce[i])) & 0x01) + << (7 - (i & 0x0007))); + } + + tx_rx->tx_bits = 8 * 4; + tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent; + + if(!furi_hal_nfc_tx_rx(tx_rx, 500)) { + FURI_LOG_E(TAG, "Error in 2nd data exchange"); + return false; + } + + uint8_t decrypted_cmd[4] = {}; + for(uint8_t i = 0; i < 4; i++) { + decrypted_cmd[i] = crypto1_byte(&emulator->crypto, 0, 0) ^ tx_rx->rx_data[i]; + } + + // FURI_LOG_I(TAG, "Decrypted: %02X %02X", decrypted_cmd[0], decrypted_cmd[1]); + if(decrypted_cmd[0] != 0x30) { + FURI_LOG_W(TAG, "Not read command"); + return false; + } + uint16_t block_num = decrypted_cmd[1]; + + // Send 0 block + uint8_t block_data[18] = {}; + memcpy(block_data, emulator->data.block[block_num].value, MF_CLASSIC_BLOCK_SIZE); + nfca_append_crc16(block_data, 16); + tx_rx->tx_parity[0] = 0; + tx_rx->tx_parity[1] = 0; + tx_rx->tx_parity[2] = 0; + + for(uint8_t i = 0; i < 18; i++) { + tx_rx->tx_data[i] = crypto1_byte(&emulator->crypto, 0, 0) ^ block_data[i]; + tx_rx->tx_parity[i >> 3] |= + (((crypto1_filter(emulator->crypto.odd) ^ nfc_util_odd_parity8(block_data[i])) & 0x01) + << (7 - (i & 0x0007))); + } + + tx_rx->tx_bits = 18 * 8; + tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent; + + if(!furi_hal_nfc_tx_rx(tx_rx, 500)) { + FURI_LOG_E(TAG, "Error in Block emulation data exchange"); + return false; + } + + return false; +} diff --git a/lib/nfc_protocols/mifare_classic.h b/lib/nfc_protocols/mifare_classic.h index fa778b771..bfb0918c2 100644 --- a/lib/nfc_protocols/mifare_classic.h +++ b/lib/nfc_protocols/mifare_classic.h @@ -65,6 +65,12 @@ typedef struct { MfClassicSectorReader sector_reader[MF_CLASSIC_SECTORS_MAX]; } MfClassicReader; +typedef struct { + uint32_t cuid; + Crypto1 crypto; + MfClassicData data; +} MfClassicEmulator; + bool mf_classic_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK); bool mf_classic_get_type( @@ -100,3 +106,5 @@ uint8_t mf_classic_read_card( FuriHalNfcTxRxContext* tx_rx, MfClassicReader* reader, MfClassicData* data); + +bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_rx); diff --git a/lib/nfc_protocols/nfca.c b/lib/nfc_protocols/nfca.c index 81a6ddfcc..1ee584067 100755 --- a/lib/nfc_protocols/nfca.c +++ b/lib/nfc_protocols/nfca.c @@ -1,11 +1,17 @@ #include "nfca.h" #include #include +#include #define NFCA_CMD_RATS (0xE0U) #define NFCA_CRC_INIT (0x6363) +#define NFCA_F_SIG (13560000.0) +#define NFCA_T_SIG (1.0 / NFCA_F_SIG) + +#define NFCA_SIGNAL_MAX_EDGES (1500) + typedef struct { uint8_t cmd; uint8_t param; @@ -53,3 +59,69 @@ bool nfca_emulation_handler( 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] = 8 * NFCA_T_SIG; + } + signal->edge_timings[7] = 9 * 8 * NFCA_T_SIG; + signal->edge_cnt = 8; + } else { + signal->start_level = false; + signal->edge_timings[0] = 8 * 8 * NFCA_T_SIG; + for(size_t i = 1; i < 9; i++) { + signal->edge_timings[i] = 8 * NFCA_T_SIG; + } + 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); + free(nfca_signal); +} + +void nfca_signal_encode(NfcaSignal* nfca_signal, uint8_t* data, uint16_t len, 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 = false; + // Start of frame + digital_signal_append(nfca_signal->tx_signal, nfca_signal->one); + for(size_t i = 0; i < len; i++) { + nfca_add_byte(nfca_signal, data[i], parity[i / 8] & (1 << (7 - (i & 0x07)))); + } +} diff --git a/lib/nfc_protocols/nfca.h b/lib/nfc_protocols/nfca.h index 73e2e65e0..48d980328 100644 --- a/lib/nfc_protocols/nfca.h +++ b/lib/nfc_protocols/nfca.h @@ -3,6 +3,14 @@ #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); @@ -12,3 +20,9 @@ bool nfca_emulation_handler( 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 len, uint8_t* parity);