fetch wplugins
@ -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,
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <lib/nfc_protocols/mifare_ultralight.h>
|
||||
#include <lib/nfc_protocols/mifare_classic.h>
|
||||
#include <lib/nfc_protocols/mifare_desfire.h>
|
||||
#include <lib/nfc_protocols/nfca.h>
|
||||
|
||||
#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] = {};
|
||||
|
@ -19,6 +19,7 @@ typedef enum {
|
||||
NfcWorkerStateReadMifareUltralight,
|
||||
NfcWorkerStateEmulateMifareUltralight,
|
||||
NfcWorkerStateReadMifareClassic,
|
||||
NfcWorkerStateEmulateMifareClassic,
|
||||
NfcWorkerStateReadMifareDesfire,
|
||||
// Transition
|
||||
NfcWorkerStateStop,
|
||||
|
@ -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)
|
||||
|
64
applications/nfc/scenes/nfc_scene_emulate_mifare_classic.c
Normal file
@ -0,0 +1,64 @@
|
||||
#include "../nfc_i.h"
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
#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);
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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};
|
||||
|
@ -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;
|
||||
|
BIN
assets/icons/MainMenu/TouchTunes_14/frame_00_delay-0.04s.png
Normal file
After Width: | Height: | Size: 470 B |
BIN
assets/icons/MainMenu/TouchTunes_14/frame_01_delay-0.04s.png
Normal file
After Width: | Height: | Size: 411 B |
BIN
assets/icons/MainMenu/TouchTunes_14/frame_02_delay-0.04s.png
Normal file
After Width: | Height: | Size: 411 B |
BIN
assets/icons/MainMenu/TouchTunes_14/frame_03_delay-0.04s.png
Normal file
After Width: | Height: | Size: 411 B |
BIN
assets/icons/MainMenu/TouchTunes_14/frame_04_delay-0.04s.png
Normal file
After Width: | Height: | Size: 401 B |
BIN
assets/icons/MainMenu/TouchTunes_14/frame_05_delay-0.04s.png
Normal file
After Width: | Height: | Size: 397 B |
BIN
assets/icons/MainMenu/TouchTunes_14/frame_06_delay-0.04s.png
Normal file
After Width: | Height: | Size: 400 B |
BIN
assets/icons/MainMenu/TouchTunes_14/frame_07_delay-0.04s.png
Normal file
After Width: | Height: | Size: 404 B |
BIN
assets/icons/MainMenu/TouchTunes_14/frame_08_delay-0.04s.png
Normal file
After Width: | Height: | Size: 414 B |
BIN
assets/icons/MainMenu/TouchTunes_14/frame_09_delay-0.04s.png
Normal file
After Width: | Height: | Size: 427 B |
BIN
assets/icons/MainMenu/TouchTunes_14/frame_10_delay-0.04s.png
Normal file
After Width: | Height: | Size: 427 B |
BIN
assets/icons/MainMenu/TouchTunes_14/frame_11_delay-0.04s.png
Normal file
After Width: | Height: | Size: 426 B |
BIN
assets/icons/MainMenu/TouchTunes_14/frame_12_delay-0.04s.png
Normal file
After Width: | Height: | Size: 431 B |
BIN
assets/icons/MainMenu/TouchTunes_14/frame_13_delay-0.04s.png
Normal file
After Width: | Height: | Size: 424 B |
BIN
assets/icons/MainMenu/TouchTunes_14/frame_14_delay-0.04s.png
Normal file
After Width: | Height: | Size: 424 B |
BIN
assets/icons/MainMenu/TouchTunes_14/frame_15_delay-0.04s.png
Normal file
After Width: | Height: | Size: 424 B |
BIN
assets/icons/MainMenu/TouchTunes_14/frame_16_delay-0.04s.png
Normal file
After Width: | Height: | Size: 424 B |
BIN
assets/icons/MainMenu/TouchTunes_14/frame_17_delay-0.04s.png
Normal file
After Width: | Height: | Size: 426 B |
BIN
assets/icons/MainMenu/TouchTunes_14/frame_18_delay-0.04s.png
Normal file
After Width: | Height: | Size: 418 B |
BIN
assets/icons/MainMenu/TouchTunes_14/frame_19_delay-0.04s.png
Normal file
After Width: | Height: | Size: 419 B |
BIN
assets/icons/MainMenu/TouchTunes_14/frame_20_delay-0.04s.png
Normal file
After Width: | Height: | Size: 425 B |
BIN
assets/icons/MainMenu/TouchTunes_14/frame_21_delay-0.04s.png
Normal file
After Width: | Height: | Size: 415 B |
BIN
assets/icons/MainMenu/TouchTunes_14/frame_22_delay-0.04s.png
Normal file
After Width: | Height: | Size: 405 B |
BIN
assets/icons/MainMenu/TouchTunes_14/frame_23_delay-0.04s.png
Normal file
After Width: | Height: | Size: 394 B |
BIN
assets/icons/MainMenu/TouchTunes_14/frame_24_delay-0.04s.png
Normal file
After Width: | Height: | Size: 401 B |
BIN
assets/icons/MainMenu/TouchTunes_14/frame_25_delay-0.04s.png
Normal file
After Width: | Height: | Size: 401 B |
BIN
assets/icons/MainMenu/TouchTunes_14/frame_26_delay-0.04s.png
Normal file
After Width: | Height: | Size: 404 B |
BIN
assets/icons/MainMenu/TouchTunes_14/frame_27_delay-0.04s.png
Normal file
After Width: | Height: | Size: 410 B |
BIN
assets/icons/MainMenu/TouchTunes_14/frame_28_delay-0.04s.png
Normal file
After Width: | Height: | Size: 411 B |
BIN
assets/icons/MainMenu/TouchTunes_14/frame_29_delay-0.04s.png
Normal file
After Width: | Height: | Size: 411 B |
1
assets/icons/MainMenu/TouchTunes_14/frame_rate
Normal file
@ -0,0 +1 @@
|
||||
3
|
BIN
assets/icons/MainMenu/UniversalRemote_14/frame_1.png
Normal file
After Width: | Height: | Size: 170 B |
BIN
assets/icons/MainMenu/UniversalRemote_14/frame_2.png
Normal file
After Width: | Height: | Size: 165 B |
BIN
assets/icons/MainMenu/UniversalRemote_14/frame_3.png
Normal file
After Width: | Height: | Size: 171 B |
BIN
assets/icons/MainMenu/UniversalRemote_14/frame_4.png
Normal file
After Width: | Height: | Size: 168 B |
BIN
assets/icons/MainMenu/UniversalRemote_14/frame_5.png
Normal file
After Width: | Height: | Size: 169 B |
BIN
assets/icons/MainMenu/UniversalRemote_14/frame_6.png
Normal file
After Width: | Height: | Size: 165 B |
BIN
assets/icons/MainMenu/UniversalRemote_14/frame_7.png
Normal file
After Width: | Height: | Size: 166 B |
@ -1,9 +1,12 @@
|
||||
#include "furi_hal_nfc.h"
|
||||
#include <st25r3916.h>
|
||||
#include <st25r3916_irq.h>
|
||||
#include <rfal_rf.h>
|
||||
#include <furi.h>
|
||||
#include <m-string.h>
|
||||
#include <lib/nfc_protocols/nfca.h>
|
||||
|
||||
#include <lib/digital_signal/digital_signal.h>
|
||||
#include <furi_hal_delay.h>
|
||||
|
||||
#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 {
|
||||
|
@ -10,6 +10,8 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <lib/nfc_protocols/nfca.h>
|
||||
|
||||
#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
|
||||
|
173
lib/digital_signal/digital_signal.c
Normal file
@ -0,0 +1,173 @@
|
||||
#include "digital_signal.h"
|
||||
|
||||
#include <furi.h>
|
||||
#include <stm32wbxx_ll_dma.h>
|
||||
#include <stm32wbxx_ll_tim.h>
|
||||
#include <math.h>
|
||||
|
||||
#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;
|
||||
}
|
28
lib/digital_signal/digital_signal.h
Normal file
@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <furi_hal_gpio.h>
|
||||
|
||||
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);
|
@ -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
|
||||
|
@ -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++) {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -1,11 +1,17 @@
|
||||
#include "nfca.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <furi.h>
|
||||
|
||||
#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))));
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,14 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <lib/digital_signal/digital_signal.h>
|
||||
|
||||
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);
|
||||
|