Temporarily backport app updates from apps repo

This commit is contained in:
Willy-JL
2023-11-12 11:06:02 +00:00
parent 79e7f491fe
commit e309fa8a88
1498 changed files with 1325977 additions and 20227 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 308 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 304 B

View File

@@ -1,6 +1,6 @@
App(
appid="nfc_magic",
name="NFC Magic",
name="Nfc Magic",
apptype=FlipperAppType.EXTERNAL,
targets=["f7"],
entry_point="nfc_magic_app",
@@ -9,7 +9,9 @@ App(
"gui",
],
stack_size=4 * 1024,
fap_icon="Nfc_10px.png",
fap_description="Application for writing to NFC tags with modifiable sector 0",
fap_version="1.1",
fap_icon="125_10px.png",
fap_category="NFC",
fap_private_libs=[
Lib(

View File

@@ -0,0 +1,14 @@
#pragma once
typedef enum {
// Reserve first 100 events for button types and indexes, starting from 0
NfcMagicCustomEventReserved = 100,
NfcMagicCustomEventViewExit,
NfcMagicCustomEventCardDetected,
NfcMagicCustomEventCardLost,
NfcMagicCustomEventWorkerSuccess,
NfcMagicCustomEventWorkerFail,
} NfcMagicCustomEvent;

View File

@@ -1,145 +0,0 @@
#include "classic_gen1.h"
#include <furi_hal_nfc.h>
#define TAG "Magic"
#define MAGIC_CMD_WUPA (0x40)
#define MAGIC_CMD_ACCESS (0x43)
#define MAGIC_MIFARE_READ_CMD (0x30)
#define MAGIC_MIFARE_WRITE_CMD (0xA0)
#define MAGIC_ACK (0x0A)
#define MAGIC_BUFFER_SIZE (32)
bool magic_gen1_wupa() {
bool magic_activated = false;
uint8_t tx_data[MAGIC_BUFFER_SIZE] = {};
uint8_t rx_data[MAGIC_BUFFER_SIZE] = {};
uint16_t rx_len = 0;
FuriHalNfcReturn ret = 0;
do {
// Start communication
tx_data[0] = MAGIC_CMD_WUPA;
ret = furi_hal_nfc_ll_txrx_bits(
tx_data,
7,
rx_data,
sizeof(rx_data),
&rx_len,
FURI_HAL_NFC_LL_TXRX_FLAGS_CRC_TX_MANUAL | FURI_HAL_NFC_LL_TXRX_FLAGS_AGC_ON |
FURI_HAL_NFC_LL_TXRX_FLAGS_CRC_RX_KEEP,
furi_hal_nfc_ll_ms2fc(20));
if(ret != FuriHalNfcReturnIncompleteByte) break;
if(rx_len != 4) break;
if(rx_data[0] != MAGIC_ACK) break;
magic_activated = true;
} while(false);
return magic_activated;
}
bool magic_gen1_data_access_cmd() {
bool write_cmd_success = false;
uint8_t tx_data[MAGIC_BUFFER_SIZE] = {};
uint8_t rx_data[MAGIC_BUFFER_SIZE] = {};
uint16_t rx_len = 0;
FuriHalNfcReturn ret = 0;
do {
tx_data[0] = MAGIC_CMD_ACCESS;
ret = furi_hal_nfc_ll_txrx_bits(
tx_data,
8,
rx_data,
sizeof(rx_data),
&rx_len,
FURI_HAL_NFC_LL_TXRX_FLAGS_CRC_TX_MANUAL | FURI_HAL_NFC_LL_TXRX_FLAGS_AGC_ON |
FURI_HAL_NFC_LL_TXRX_FLAGS_CRC_RX_KEEP,
furi_hal_nfc_ll_ms2fc(20));
if(ret != FuriHalNfcReturnIncompleteByte) break;
if(rx_len != 4) break;
if(rx_data[0] != MAGIC_ACK) break;
write_cmd_success = true;
} while(false);
return write_cmd_success;
}
bool magic_gen1_read_block(uint8_t block_num, MfClassicBlock* data) {
furi_assert(data);
bool read_success = false;
uint8_t tx_data[MAGIC_BUFFER_SIZE] = {};
uint8_t rx_data[MAGIC_BUFFER_SIZE] = {};
uint16_t rx_len = 0;
FuriHalNfcReturn ret = 0;
do {
tx_data[0] = MAGIC_MIFARE_READ_CMD;
tx_data[1] = block_num;
ret = furi_hal_nfc_ll_txrx_bits(
tx_data,
2 * 8,
rx_data,
sizeof(rx_data),
&rx_len,
FURI_HAL_NFC_LL_TXRX_FLAGS_AGC_ON,
furi_hal_nfc_ll_ms2fc(20));
if(ret != FuriHalNfcReturnOk) break;
if(rx_len != 16 * 8) break;
memcpy(data->value, rx_data, sizeof(data->value));
read_success = true;
} while(false);
return read_success;
}
bool magic_gen1_write_blk(uint8_t block_num, MfClassicBlock* data) {
furi_assert(data);
bool write_success = false;
uint8_t tx_data[MAGIC_BUFFER_SIZE] = {};
uint8_t rx_data[MAGIC_BUFFER_SIZE] = {};
uint16_t rx_len = 0;
FuriHalNfcReturn ret = 0;
do {
tx_data[0] = MAGIC_MIFARE_WRITE_CMD;
tx_data[1] = block_num;
ret = furi_hal_nfc_ll_txrx_bits(
tx_data,
2 * 8,
rx_data,
sizeof(rx_data),
&rx_len,
FURI_HAL_NFC_LL_TXRX_FLAGS_AGC_ON | FURI_HAL_NFC_LL_TXRX_FLAGS_CRC_RX_KEEP,
furi_hal_nfc_ll_ms2fc(20));
if(ret != FuriHalNfcReturnIncompleteByte) break;
if(rx_len != 4) break;
if(rx_data[0] != MAGIC_ACK) break;
memcpy(tx_data, data->value, sizeof(data->value));
ret = furi_hal_nfc_ll_txrx_bits(
tx_data,
16 * 8,
rx_data,
sizeof(rx_data),
&rx_len,
FURI_HAL_NFC_LL_TXRX_FLAGS_AGC_ON | FURI_HAL_NFC_LL_TXRX_FLAGS_CRC_RX_KEEP,
furi_hal_nfc_ll_ms2fc(20));
if(ret != FuriHalNfcReturnIncompleteByte) break;
if(rx_len != 4) break;
if(rx_data[0] != MAGIC_ACK) break;
write_success = true;
} while(false);
return write_success;
}

View File

@@ -1,11 +0,0 @@
#pragma once
#include <lib/nfc/protocols/mifare_classic.h>
bool magic_gen1_wupa();
bool magic_gen1_read_block(uint8_t block_num, MfClassicBlock* data);
bool magic_gen1_data_access_cmd();
bool magic_gen1_write_blk(uint8_t block_num, MfClassicBlock* data);

View File

@@ -1,33 +0,0 @@
#include "common.h"
#include <furi_hal_nfc.h>
#define REQA (0x26)
#define CL1_PREFIX (0x93)
#define SELECT (0x70)
#define MAGIC_BUFFER_SIZE (32)
bool magic_activate() {
FuriHalNfcReturn ret = 0;
// Setup nfc poller
furi_hal_nfc_exit_sleep();
furi_hal_nfc_ll_txrx_on();
furi_hal_nfc_ll_poll();
ret = furi_hal_nfc_ll_set_mode(
FuriHalNfcModePollNfca, FuriHalNfcBitrate106, FuriHalNfcBitrate106);
if(ret != FuriHalNfcReturnOk) return false;
furi_hal_nfc_ll_set_fdt_listen(FURI_HAL_NFC_LL_FDT_LISTEN_NFCA_POLLER);
furi_hal_nfc_ll_set_fdt_poll(FURI_HAL_NFC_LL_FDT_POLL_NFCA_POLLER);
furi_hal_nfc_ll_set_error_handling(FuriHalNfcErrorHandlingNfc);
furi_hal_nfc_ll_set_guard_time(FURI_HAL_NFC_LL_GT_NFCA);
return true;
}
void magic_deactivate() {
furi_hal_nfc_ll_txrx_off();
furi_hal_nfc_sleep();
}

View File

@@ -1,19 +0,0 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
typedef enum {
MagicTypeClassicGen1,
MagicTypeClassicDirectWrite,
MagicTypeClassicAPDU,
MagicTypeUltralightGen1,
MagicTypeUltralightDirectWrite,
MagicTypeUltralightC_Gen1,
MagicTypeUltralightC_DirectWrite,
MagicTypeGen4,
} MagicType;
bool magic_activate();
void magic_deactivate();

View File

@@ -1,199 +0,0 @@
#include "gen4.h"
#include <furi_hal_nfc.h>
#include <stdlib.h>
#define TAG "Magic"
#define MAGIC_CMD_PREFIX (0xCF)
#define MAGIC_CMD_GET_CFG (0xC6)
#define MAGIC_CMD_WRITE (0xCD)
#define MAGIC_CMD_READ (0xCE)
#define MAGIC_CMD_SET_CFG (0xF0)
#define MAGIC_CMD_FUSE_CFG (0xF1)
#define MAGIC_CMD_SET_PWD (0xFE)
#define MAGIC_BUFFER_SIZE (40)
const uint8_t MAGIC_DEFAULT_CONFIG[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x09, 0x78, 0x00, 0x91, 0x02, 0xDA, 0xBC, 0x19, 0x10, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x04, 0x00, 0x08, 0x00
};
const uint8_t MAGIC_DEFAULT_BLOCK0[] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x04, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
const uint8_t MAGIC_EMPTY_BLOCK[16] = { 0 };
const uint8_t MAGIC_DEFAULT_SECTOR_TRAILER[] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x80, 0x69, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
static bool magic_gen4_is_block_num_trailer(uint8_t n) {
n++;
if (n < 32 * 4) {
return (n % 4 == 0);
}
return (n % 16 == 0);
}
bool magic_gen4_get_cfg(uint32_t pwd, uint8_t* config) {
bool is_valid_config_len = false;
uint8_t tx_data[MAGIC_BUFFER_SIZE] = {};
uint8_t rx_data[MAGIC_BUFFER_SIZE] = {};
uint16_t rx_len = 0;
FuriHalNfcReturn ret = 0;
do {
// Start communication
tx_data[0] = MAGIC_CMD_PREFIX;
tx_data[1] = (uint8_t)(pwd >> 24);
tx_data[2] = (uint8_t)(pwd >> 16);
tx_data[3] = (uint8_t)(pwd >> 8);
tx_data[4] = (uint8_t)pwd;
tx_data[5] = MAGIC_CMD_GET_CFG;
ret = furi_hal_nfc_ll_txrx(
tx_data,
6,
rx_data,
sizeof(rx_data),
&rx_len,
FURI_HAL_NFC_TXRX_DEFAULT,
furi_hal_nfc_ll_ms2fc(20));
if(ret != FuriHalNfcReturnOk) break;
if(rx_len != 30 && rx_len != 32) break;
memcpy(config, rx_data, rx_len);
is_valid_config_len = true;
} while(false);
return is_valid_config_len;
}
bool magic_gen4_set_cfg(uint32_t pwd, const uint8_t* config, uint8_t config_length, bool fuse) {
bool write_success = false;
uint8_t tx_data[MAGIC_BUFFER_SIZE] = {};
uint8_t rx_data[MAGIC_BUFFER_SIZE] = {};
uint16_t rx_len = 0;
FuriHalNfcReturn ret = 0;
do {
// Start communication
tx_data[0] = MAGIC_CMD_PREFIX;
tx_data[1] = (uint8_t)(pwd >> 24);
tx_data[2] = (uint8_t)(pwd >> 16);
tx_data[3] = (uint8_t)(pwd >> 8);
tx_data[4] = (uint8_t)pwd;
tx_data[5] = fuse ? MAGIC_CMD_FUSE_CFG : MAGIC_CMD_SET_CFG;
memcpy(tx_data + 6, config, config_length);
ret = furi_hal_nfc_ll_txrx(
tx_data,
6 + config_length,
rx_data,
sizeof(rx_data),
&rx_len,
FURI_HAL_NFC_TXRX_DEFAULT,
furi_hal_nfc_ll_ms2fc(20));
if(ret != FuriHalNfcReturnOk) break;
if(rx_len != 2) break;
write_success = true;
} while(false);
return write_success;
}
bool magic_gen4_set_pwd(uint32_t old_pwd, uint32_t new_pwd) {
bool change_success = false;
uint8_t tx_data[MAGIC_BUFFER_SIZE] = {};
uint8_t rx_data[MAGIC_BUFFER_SIZE] = {};
uint16_t rx_len = 0;
FuriHalNfcReturn ret = 0;
do {
// Start communication
tx_data[0] = MAGIC_CMD_PREFIX;
tx_data[1] = (uint8_t)(old_pwd >> 24);
tx_data[2] = (uint8_t)(old_pwd >> 16);
tx_data[3] = (uint8_t)(old_pwd >> 8);
tx_data[4] = (uint8_t)old_pwd;
tx_data[5] = MAGIC_CMD_SET_PWD;
tx_data[6] = (uint8_t)(new_pwd >> 24);
tx_data[7] = (uint8_t)(new_pwd >> 16);
tx_data[8] = (uint8_t)(new_pwd >> 8);
tx_data[9] = (uint8_t)new_pwd;
ret = furi_hal_nfc_ll_txrx(
tx_data,
10,
rx_data,
sizeof(rx_data),
&rx_len,
FURI_HAL_NFC_TXRX_DEFAULT,
furi_hal_nfc_ll_ms2fc(20));
FURI_LOG_I(TAG, "ret %d, len %d", ret, rx_len);
if(ret != FuriHalNfcReturnOk) break;
if(rx_len != 2) break;
change_success = true;
} while(false);
return change_success;
}
bool magic_gen4_write_blk(uint32_t pwd, uint8_t block_num, const uint8_t* data) {
bool write_success = false;
uint8_t tx_data[MAGIC_BUFFER_SIZE] = {};
uint8_t rx_data[MAGIC_BUFFER_SIZE] = {};
uint16_t rx_len = 0;
FuriHalNfcReturn ret = 0;
do {
// Start communication
tx_data[0] = MAGIC_CMD_PREFIX;
tx_data[1] = (uint8_t)(pwd >> 24);
tx_data[2] = (uint8_t)(pwd >> 16);
tx_data[3] = (uint8_t)(pwd >> 8);
tx_data[4] = (uint8_t)pwd;
tx_data[5] = MAGIC_CMD_WRITE;
tx_data[6] = block_num;
memcpy(tx_data + 7, data, 16);
ret = furi_hal_nfc_ll_txrx(
tx_data,
23,
rx_data,
sizeof(rx_data),
&rx_len,
FURI_HAL_NFC_TXRX_DEFAULT,
furi_hal_nfc_ll_ms2fc(200));
if(ret != FuriHalNfcReturnOk) break;
if(rx_len != 2) break;
write_success = true;
} while(false);
return write_success;
}
bool magic_gen4_wipe(uint32_t pwd) {
if(!magic_gen4_set_cfg(pwd, MAGIC_DEFAULT_CONFIG, sizeof(MAGIC_DEFAULT_CONFIG), false)) {
FURI_LOG_E(TAG, "Set config failed");
return false;
}
if(!magic_gen4_write_blk(pwd, 0, MAGIC_DEFAULT_BLOCK0)) {
FURI_LOG_E(TAG, "Block 0 write failed");
return false;
}
for(size_t i = 1; i < 64; i++) {
const uint8_t* block = magic_gen4_is_block_num_trailer(i) ? MAGIC_DEFAULT_SECTOR_TRAILER : MAGIC_EMPTY_BLOCK;
if(!magic_gen4_write_blk(pwd, i, block)) {
FURI_LOG_E(TAG, "Block %d write failed", i);
return false;
}
}
for(size_t i = 65; i < 256; i++) {
if(!magic_gen4_write_blk(pwd, i, MAGIC_EMPTY_BLOCK)) {
FURI_LOG_E(TAG, "Block %d write failed", i);
return false;
}
}
return true;
}

View File

@@ -1,48 +0,0 @@
#pragma once
#include <lib/nfc/protocols/mifare_classic.h>
#define MAGIC_GEN4_DEFAULT_PWD 0x00000000
#define MAGIC_GEN4_CONFIG_LEN 32
#define NFCID1_SINGLE_SIZE 4
#define NFCID1_DOUBLE_SIZE 7
#define NFCID1_TRIPLE_SIZE 10
typedef enum {
MagicGen4UIDLengthSingle = 0x00,
MagicGen4UIDLengthDouble = 0x01,
MagicGen4UIDLengthTriple = 0x02
} MagicGen4UIDLength;
typedef enum {
MagicGen4UltralightModeUL_EV1 = 0x00,
MagicGen4UltralightModeNTAG = 0x01,
MagicGen4UltralightModeUL_C = 0x02,
MagicGen4UltralightModeUL = 0x03
} MagicGen4UltralightMode;
typedef enum {
// for writing original (shadow) data
MagicGen4ShadowModePreWrite = 0x00,
// written data can be read once before restored to original
MagicGen4ShadowModeRestore = 0x01,
// written data is discarded
MagicGen4ShadowModeIgnore = 0x02,
// apparently for UL?
MagicGen4ShadowModeHighSpeedIgnore = 0x03
} MagicGen4ShadowMode;
bool magic_gen4_get_cfg(uint32_t pwd, uint8_t* config);
bool magic_gen4_set_cfg(uint32_t pwd, const uint8_t* config, uint8_t config_length, bool fuse);
bool magic_gen4_set_pwd(uint32_t old_pwd, uint32_t new_pwd);
bool magic_gen4_read_blk(uint32_t pwd, uint8_t block_num, uint8_t* data);
bool magic_gen4_write_blk(uint32_t pwd, uint8_t block_num, const uint8_t* data);
bool magic_gen4_wipe(uint32_t pwd);
void magic_gen4_deactivate();

View File

@@ -0,0 +1,150 @@
#include "nfc_magic_scanner.h"
#include "protocols/gen1a/gen1a_poller.h"
#include "protocols/gen4/gen4_poller.h"
#include <nfc/nfc_poller.h>
#include <furi/furi.h>
typedef enum {
NfcMagicScannerSessionStateIdle,
NfcMagicScannerSessionStateActive,
NfcMagicScannerSessionStateStopRequest,
} NfcMagicScannerSessionState;
struct NfcMagicScanner {
Nfc* nfc;
NfcMagicScannerSessionState session_state;
NfcMagicProtocol current_protocol;
uint32_t gen4_password;
bool magic_protocol_detected;
NfcMagicScannerCallback callback;
void* context;
FuriThread* scan_worker;
};
static const NfcProtocol nfc_magic_scanner_not_magic_protocols[] = {
NfcProtocolIso14443_3b,
NfcProtocolIso15693_3,
NfcProtocolFelica,
};
static void nfc_magic_scanner_reset(NfcMagicScanner* instance) {
instance->session_state = NfcMagicScannerSessionStateIdle;
instance->current_protocol = NfcMagicProtocolGen1;
}
NfcMagicScanner* nfc_magic_scanner_alloc(Nfc* nfc) {
furi_assert(nfc);
NfcMagicScanner* instance = malloc(sizeof(NfcMagicScanner));
instance->nfc = nfc;
return instance;
}
void nfc_magic_scanner_free(NfcMagicScanner* instance) {
furi_assert(instance);
free(instance);
}
void nfc_magic_scanner_set_gen4_password(NfcMagicScanner* instance, uint32_t password) {
furi_assert(instance);
instance->gen4_password = password;
}
static int32_t nfc_magic_scanner_worker(void* context) {
furi_assert(context);
NfcMagicScanner* instance = context;
furi_assert(instance->session_state == NfcMagicScannerSessionStateActive);
while(instance->session_state == NfcMagicScannerSessionStateActive) {
if(instance->current_protocol == NfcMagicProtocolGen1) {
instance->magic_protocol_detected = gen1a_poller_detect(instance->nfc);
} else if(instance->current_protocol == NfcMagicProtocolGen4) {
Gen4PollerError error = gen4_poller_detect(instance->nfc, instance->gen4_password);
if(error == Gen4PollerErrorProtocol) {
NfcMagicScannerEvent event = {
.type = NfcMagicScannerEventTypeDetectedNotMagic,
};
instance->callback(event, instance->context);
break;
} else {
instance->magic_protocol_detected = (error == Gen4PollerErrorNone);
}
}
if(instance->magic_protocol_detected) {
NfcMagicScannerEvent event = {
.type = NfcMagicScannerEventTypeDetected,
.data.protocol = instance->current_protocol,
};
instance->callback(event, instance->context);
break;
}
if(instance->current_protocol == NfcMagicProtocolNum - 1) {
bool not_magic_protocol_detected = false;
for(size_t i = 0; i < COUNT_OF(nfc_magic_scanner_not_magic_protocols); i++) {
NfcProtocol protocol = nfc_magic_scanner_not_magic_protocols[i];
NfcPoller* poller = nfc_poller_alloc(instance->nfc, protocol);
not_magic_protocol_detected = nfc_poller_detect(poller);
nfc_poller_free(poller);
if(not_magic_protocol_detected) {
break;
}
}
if(not_magic_protocol_detected) {
NfcMagicScannerEvent event = {
.type = NfcMagicScannerEventTypeDetectedNotMagic,
};
instance->callback(event, instance->context);
break;
}
}
instance->current_protocol = (instance->current_protocol + 1) % NfcMagicProtocolNum;
}
nfc_magic_scanner_reset(instance);
return 0;
}
void nfc_magic_scanner_start(
NfcMagicScanner* instance,
NfcMagicScannerCallback callback,
void* context) {
furi_assert(instance);
furi_assert(callback);
instance->callback = callback;
instance->context = context;
instance->scan_worker = furi_thread_alloc();
furi_thread_set_name(instance->scan_worker, "NfcMagicScanWorker");
furi_thread_set_context(instance->scan_worker, instance);
furi_thread_set_stack_size(instance->scan_worker, 4 * 1024);
furi_thread_set_callback(instance->scan_worker, nfc_magic_scanner_worker);
furi_thread_start(instance->scan_worker);
instance->session_state = NfcMagicScannerSessionStateActive;
}
void nfc_magic_scanner_stop(NfcMagicScanner* instance) {
furi_assert(instance);
instance->session_state = NfcMagicScannerSessionStateStopRequest;
furi_thread_join(instance->scan_worker);
instance->session_state = NfcMagicScannerSessionStateIdle;
furi_thread_free(instance->scan_worker);
instance->scan_worker = NULL;
instance->callback = NULL;
instance->context = NULL;
}

View File

@@ -0,0 +1,44 @@
#pragma once
#include <nfc/nfc.h>
#include "protocols/nfc_magic_protocols.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
NfcMagicScannerEventTypeDetected,
NfcMagicScannerEventTypeDetectedNotMagic,
NfcMagicScannerEventTypeNotDetected,
} NfcMagicScannerEventType;
typedef struct {
NfcMagicProtocol protocol;
} NfcMagicScannerEventData;
typedef struct {
NfcMagicScannerEventType type;
NfcMagicScannerEventData data;
} NfcMagicScannerEvent;
typedef void (*NfcMagicScannerCallback)(NfcMagicScannerEvent event, void* context);
typedef struct NfcMagicScanner NfcMagicScanner;
NfcMagicScanner* nfc_magic_scanner_alloc(Nfc* nfc);
void nfc_magic_scanner_free(NfcMagicScanner* instance);
void nfc_magic_scanner_set_gen4_password(NfcMagicScanner* instance, uint32_t password);
void nfc_magic_scanner_start(
NfcMagicScanner* instance,
NfcMagicScannerCallback callback,
void* context);
void nfc_magic_scanner_stop(NfcMagicScanner* instance);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,279 @@
#include "gen1a_poller_i.h"
#include <nfc/protocols/iso14443_3a/iso14443_3a.h>
#include <nfc/protocols/iso14443_3a/iso14443_3a_poller.h>
#include <nfc/helpers/nfc_data_generator.h>
#include <furi/furi.h>
#define GEN1A_POLLER_THREAD_FLAG_DETECTED (1U << 0)
typedef NfcCommand (*Gen1aPollerStateHandler)(Gen1aPoller* instance);
typedef struct {
Nfc* nfc;
BitBuffer* tx_buffer;
BitBuffer* rx_buffer;
FuriThreadId thread_id;
bool detected;
} Gen1aPollerDetectContext;
Gen1aPoller* gen1a_poller_alloc(Nfc* nfc) {
furi_assert(nfc);
Gen1aPoller* instance = malloc(sizeof(Gen1aPoller));
instance->nfc = nfc;
nfc_config(instance->nfc, NfcModePoller, NfcTechIso14443a);
nfc_set_guard_time_us(instance->nfc, ISO14443_3A_GUARD_TIME_US);
nfc_set_fdt_poll_fc(instance->nfc, ISO14443_3A_FDT_POLL_FC);
nfc_set_fdt_poll_poll_us(instance->nfc, ISO14443_3A_POLL_POLL_MIN_US);
instance->tx_buffer = bit_buffer_alloc(GEN1A_POLLER_MAX_BUFFER_SIZE);
instance->rx_buffer = bit_buffer_alloc(GEN1A_POLLER_MAX_BUFFER_SIZE);
instance->mfc_device = nfc_device_alloc();
instance->gen1a_event.data = &instance->gen1a_event_data;
return instance;
}
void gen1a_poller_free(Gen1aPoller* instance) {
furi_assert(instance);
bit_buffer_free(instance->tx_buffer);
bit_buffer_free(instance->rx_buffer);
nfc_device_free(instance->mfc_device);
free(instance);
}
NfcCommand gen1a_poller_detect_callback(NfcEvent event, void* context) {
furi_assert(context);
NfcCommand command = NfcCommandStop;
Gen1aPollerDetectContext* gen1a_poller_detect_ctx = context;
if(event.type == NfcEventTypePollerReady) {
do {
bit_buffer_set_size(gen1a_poller_detect_ctx->tx_buffer, 7);
bit_buffer_set_byte(gen1a_poller_detect_ctx->tx_buffer, 0, 0x40);
NfcError error = nfc_poller_trx(
gen1a_poller_detect_ctx->nfc,
gen1a_poller_detect_ctx->tx_buffer,
gen1a_poller_detect_ctx->rx_buffer,
GEN1A_POLLER_MAX_FWT);
if(error != NfcErrorNone) break;
if(bit_buffer_get_size(gen1a_poller_detect_ctx->rx_buffer) != 4) break;
if(bit_buffer_get_byte(gen1a_poller_detect_ctx->rx_buffer, 0) != 0x0A) break;
gen1a_poller_detect_ctx->detected = true;
} while(false);
}
furi_thread_flags_set(gen1a_poller_detect_ctx->thread_id, GEN1A_POLLER_THREAD_FLAG_DETECTED);
return command;
}
bool gen1a_poller_detect(Nfc* nfc) {
furi_assert(nfc);
nfc_config(nfc, NfcModePoller, NfcTechIso14443a);
nfc_set_guard_time_us(nfc, ISO14443_3A_GUARD_TIME_US);
nfc_set_fdt_poll_fc(nfc, ISO14443_3A_FDT_POLL_FC);
nfc_set_fdt_poll_poll_us(nfc, ISO14443_3A_POLL_POLL_MIN_US);
Gen1aPollerDetectContext gen1a_poller_detect_ctx = {};
gen1a_poller_detect_ctx.nfc = nfc;
gen1a_poller_detect_ctx.tx_buffer = bit_buffer_alloc(GEN1A_POLLER_MAX_BUFFER_SIZE);
gen1a_poller_detect_ctx.rx_buffer = bit_buffer_alloc(GEN1A_POLLER_MAX_BUFFER_SIZE);
gen1a_poller_detect_ctx.thread_id = furi_thread_get_current_id();
gen1a_poller_detect_ctx.detected = false;
nfc_start(nfc, gen1a_poller_detect_callback, &gen1a_poller_detect_ctx);
uint32_t flags = furi_thread_flags_wait(
GEN1A_POLLER_THREAD_FLAG_DETECTED, FuriFlagWaitAny, FuriWaitForever);
if(flags & GEN1A_POLLER_THREAD_FLAG_DETECTED) {
furi_thread_flags_clear(GEN1A_POLLER_THREAD_FLAG_DETECTED);
}
nfc_stop(nfc);
bit_buffer_free(gen1a_poller_detect_ctx.tx_buffer);
bit_buffer_free(gen1a_poller_detect_ctx.rx_buffer);
return gen1a_poller_detect_ctx.detected;
}
static void gen1a_poller_reset(Gen1aPoller* instance) {
instance->current_block = 0;
nfc_data_generator_fill_data(NfcDataGeneratorTypeMfClassic1k_4b, instance->mfc_device);
}
NfcCommand gen1a_poller_idle_handler(Gen1aPoller* instance) {
NfcCommand command = NfcCommandContinue;
gen1a_poller_reset(instance);
Gen1aPollerError error = gen1a_poller_wupa(instance);
if(error == Gen1aPollerErrorNone) {
instance->state = Gen1aPollerStateRequestMode;
instance->gen1a_event.type = Gen1aPollerEventTypeDetected;
command = instance->callback(instance->gen1a_event, instance->context);
}
return command;
}
NfcCommand gen1a_poller_request_mode_handler(Gen1aPoller* instance) {
NfcCommand command = NfcCommandContinue;
instance->gen1a_event.type = Gen1aPollerEventTypeRequestMode;
command = instance->callback(instance->gen1a_event, instance->context);
if(instance->gen1a_event_data.request_mode.mode == Gen1aPollerModeWipe) {
instance->state = Gen1aPollerStateWipe;
} else {
instance->state = Gen1aPollerStateWriteDataRequest;
}
return command;
}
NfcCommand gen1a_poller_wipe_handler(Gen1aPoller* instance) {
NfcCommand command = NfcCommandContinue;
Gen1aPollerError error = Gen1aPollerErrorNone;
const MfClassicData* mfc_data =
nfc_device_get_data(instance->mfc_device, NfcProtocolMfClassic);
uint16_t total_block_num = mf_classic_get_total_block_num(mfc_data->type);
if(instance->current_block == total_block_num) {
instance->state = Gen1aPollerStateSuccess;
} else {
do {
if(instance->current_block == 0) {
error = gen1a_poller_data_access(instance);
if(error != Gen1aPollerErrorNone) {
instance->state = Gen1aPollerStateFail;
break;
}
}
error = gen1a_poller_write_block(
instance, instance->current_block, &mfc_data->block[instance->current_block]);
if(error != Gen1aPollerErrorNone) {
instance->state = Gen1aPollerStateFail;
break;
}
instance->current_block++;
} while(false);
}
return command;
}
NfcCommand gen1a_poller_write_data_request_handler(Gen1aPoller* instance) {
NfcCommand command = NfcCommandContinue;
instance->gen1a_event.type = Gen1aPollerEventTypeRequestDataToWrite;
command = instance->callback(instance->gen1a_event, instance->context);
instance->state = Gen1aPollerStateWrite;
return command;
}
NfcCommand gen1a_poller_write_handler(Gen1aPoller* instance) {
NfcCommand command = NfcCommandContinue;
Gen1aPollerError error = Gen1aPollerErrorNone;
const MfClassicData* mfc_data = instance->gen1a_event_data.data_to_write.mfc_data;
uint16_t total_block_num = mf_classic_get_total_block_num(mfc_data->type);
if(instance->current_block == total_block_num) {
instance->state = Gen1aPollerStateSuccess;
} else {
do {
if(instance->current_block == 0) {
error = gen1a_poller_data_access(instance);
if(error != Gen1aPollerErrorNone) {
instance->state = Gen1aPollerStateFail;
break;
}
}
error = gen1a_poller_write_block(
instance, instance->current_block, &mfc_data->block[instance->current_block]);
if(error != Gen1aPollerErrorNone) {
instance->state = Gen1aPollerStateFail;
break;
}
instance->current_block++;
} while(false);
}
return command;
}
NfcCommand gen1a_poller_success_handler(Gen1aPoller* instance) {
NfcCommand command = NfcCommandContinue;
instance->gen1a_event.type = Gen1aPollerEventTypeSuccess;
command = instance->callback(instance->gen1a_event, instance->context);
instance->state = Gen1aPollerStateIdle;
return command;
}
NfcCommand gen1a_poller_fail_handler(Gen1aPoller* instance) {
NfcCommand command = NfcCommandContinue;
instance->gen1a_event.type = Gen1aPollerEventTypeFail;
command = instance->callback(instance->gen1a_event, instance->context);
instance->state = Gen1aPollerStateIdle;
return command;
}
static const Gen1aPollerStateHandler gen1a_poller_state_handlers[Gen1aPollerStateNum] = {
[Gen1aPollerStateIdle] = gen1a_poller_idle_handler,
[Gen1aPollerStateRequestMode] = gen1a_poller_request_mode_handler,
[Gen1aPollerStateWipe] = gen1a_poller_wipe_handler,
[Gen1aPollerStateWriteDataRequest] = gen1a_poller_write_data_request_handler,
[Gen1aPollerStateWrite] = gen1a_poller_write_handler,
[Gen1aPollerStateSuccess] = gen1a_poller_success_handler,
[Gen1aPollerStateFail] = gen1a_poller_fail_handler,
};
NfcCommand gen1a_poller_run(NfcEvent event, void* context) {
NfcCommand command = NfcCommandContinue;
Gen1aPoller* instance = context;
if(event.type == NfcEventTypePollerReady) {
command = gen1a_poller_state_handlers[instance->state](instance);
}
if(instance->session_state == Gen1aPollerSessionStateStopRequest) {
command = NfcCommandStop;
}
return command;
}
void gen1a_poller_start(Gen1aPoller* instance, Gen1aPollerCallback callback, void* context) {
furi_assert(instance);
furi_assert(callback);
instance->callback = callback;
instance->context = context;
instance->session_state = Gen1aPollerSessionStateStarted;
nfc_start(instance->nfc, gen1a_poller_run, instance);
}
void gen1a_poller_stop(Gen1aPoller* instance) {
furi_assert(instance);
instance->session_state = Gen1aPollerSessionStateStopRequest;
nfc_stop(instance->nfc);
instance->session_state = Gen1aPollerSessionStateIdle;
}

View File

@@ -0,0 +1,59 @@
#pragma once
#include <nfc/nfc.h>
#include <nfc/protocols/nfc_generic_event.h>
#include <nfc/protocols/mf_classic/mf_classic.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
Gen1aPollerEventTypeDetected,
Gen1aPollerEventTypeRequestMode,
Gen1aPollerEventTypeRequestDataToWrite,
Gen1aPollerEventTypeSuccess,
Gen1aPollerEventTypeFail,
} Gen1aPollerEventType;
typedef enum {
Gen1aPollerModeWipe,
Gen1aPollerModeWrite,
} Gen1aPollerMode;
typedef struct {
Gen1aPollerMode mode;
} Gen1aPollerEventDataRequestMode;
typedef struct {
const MfClassicData* mfc_data;
} Gen1aPollerEventDataRequestDataToWrite;
typedef union {
Gen1aPollerEventDataRequestMode request_mode;
Gen1aPollerEventDataRequestDataToWrite data_to_write;
} Gen1aPollerEventData;
typedef struct {
Gen1aPollerEventType type;
Gen1aPollerEventData* data;
} Gen1aPollerEvent;
typedef NfcCommand (*Gen1aPollerCallback)(Gen1aPollerEvent event, void* context);
typedef struct Gen1aPoller Gen1aPoller;
bool gen1a_poller_detect(Nfc* nfc);
Gen1aPoller* gen1a_poller_alloc(Nfc* nfc);
void gen1a_poller_free(Gen1aPoller* instance);
void gen1a_poller_start(Gen1aPoller* instance, Gen1aPollerCallback callback, void* context);
void gen1a_poller_stop(Gen1aPoller* instance);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,132 @@
#include "gen1a_poller_i.h"
#include <nfc/helpers/iso14443_crc.h>
#include <furi/furi.h>
static Gen1aPollerError gen1a_poller_process_nfc_error(NfcError error) {
Gen1aPollerError ret = Gen1aPollerErrorNone;
if(error == NfcErrorNone) {
ret = Gen1aPollerErrorNone;
} else if(error == NfcErrorTimeout) {
ret = Gen1aPollerErrorTimeout;
} else {
ret = Gen1aPollerErrorNotPresent;
}
return ret;
}
Gen1aPollerError gen1a_poller_wupa(Gen1aPoller* instance) {
furi_assert(instance);
Gen1aPollerError ret = Gen1aPollerErrorNone;
bit_buffer_reset(instance->tx_buffer);
do {
bit_buffer_set_size(instance->tx_buffer, 7);
bit_buffer_set_byte(instance->tx_buffer, 0, 0x40);
NfcError error = nfc_poller_trx(
instance->nfc, instance->tx_buffer, instance->rx_buffer, GEN1A_POLLER_MAX_FWT);
if(error != NfcErrorNone) {
ret = gen1a_poller_process_nfc_error(error);
break;
}
if(bit_buffer_get_size(instance->rx_buffer) != 4) {
ret = Gen1aPollerErrorProtocol;
break;
}
if(bit_buffer_get_byte(instance->rx_buffer, 0) != 0x0A) {
ret = Gen1aPollerErrorProtocol;
break;
}
} while(false);
return ret;
}
Gen1aPollerError gen1a_poller_data_access(Gen1aPoller* instance) {
furi_assert(instance);
Gen1aPollerError ret = Gen1aPollerErrorNone;
bit_buffer_reset(instance->tx_buffer);
do {
bit_buffer_set_size(instance->tx_buffer, 8);
bit_buffer_set_byte(instance->tx_buffer, 0, 0x43);
NfcError error = nfc_poller_trx(
instance->nfc, instance->tx_buffer, instance->rx_buffer, GEN1A_POLLER_MAX_FWT);
if(error != NfcErrorNone) {
ret = gen1a_poller_process_nfc_error(error);
break;
}
if(bit_buffer_get_size(instance->rx_buffer) != 4) {
ret = Gen1aPollerErrorProtocol;
break;
}
if(bit_buffer_get_byte(instance->rx_buffer, 0) != 0x0A) {
ret = Gen1aPollerErrorProtocol;
break;
}
} while(false);
return ret;
}
Gen1aPollerError gen1a_poller_write_block(
Gen1aPoller* instance,
uint8_t block_num,
const MfClassicBlock* block) {
furi_assert(instance);
furi_assert(block);
Gen1aPollerError ret = Gen1aPollerErrorNone;
bit_buffer_reset(instance->tx_buffer);
do {
bit_buffer_append_byte(instance->tx_buffer, 0xA0);
bit_buffer_append_byte(instance->tx_buffer, block_num);
iso14443_crc_append(Iso14443CrcTypeA, instance->tx_buffer);
NfcError error = nfc_poller_trx(
instance->nfc, instance->tx_buffer, instance->rx_buffer, GEN1A_POLLER_MAX_FWT);
if(error != NfcErrorNone) {
ret = gen1a_poller_process_nfc_error(error);
break;
}
if(bit_buffer_get_size(instance->rx_buffer) != 4) {
ret = Gen1aPollerErrorProtocol;
break;
}
if(bit_buffer_get_byte(instance->rx_buffer, 0) != 0x0A) {
ret = Gen1aPollerErrorProtocol;
break;
}
bit_buffer_copy_bytes(instance->tx_buffer, block->data, sizeof(MfClassicBlock));
iso14443_crc_append(Iso14443CrcTypeA, instance->tx_buffer);
error = nfc_poller_trx(
instance->nfc, instance->tx_buffer, instance->rx_buffer, GEN1A_POLLER_MAX_FWT);
if(error != NfcErrorNone) {
ret = gen1a_poller_process_nfc_error(error);
break;
}
if(bit_buffer_get_size(instance->rx_buffer) != 4) {
ret = Gen1aPollerErrorProtocol;
break;
}
if(bit_buffer_get_byte(instance->rx_buffer, 0) != 0x0A) {
ret = Gen1aPollerErrorProtocol;
break;
}
} while(false);
return ret;
}

View File

@@ -0,0 +1,67 @@
#pragma once
#include "gen1a_poller.h"
#include <nfc/protocols/nfc_generic_event.h>
#include <nfc/nfc_device.h>
#include <nfc/protocols/mf_classic/mf_classic.h>
#ifdef __cplusplus
extern "C" {
#endif
#define GEN1A_POLLER_MAX_BUFFER_SIZE (64U)
#define GEN1A_POLLER_MAX_FWT (60000U)
typedef enum {
Gen1aPollerErrorNone,
Gen1aPollerErrorTimeout,
Gen1aPollerErrorNotPresent,
Gen1aPollerErrorProtocol,
} Gen1aPollerError;
typedef enum {
Gen1aPollerStateIdle,
Gen1aPollerStateRequestMode,
Gen1aPollerStateWipe,
Gen1aPollerStateWriteDataRequest,
Gen1aPollerStateWrite,
Gen1aPollerStateSuccess,
Gen1aPollerStateFail,
Gen1aPollerStateNum,
} Gen1aPollerState;
typedef enum {
Gen1aPollerSessionStateIdle,
Gen1aPollerSessionStateStarted,
Gen1aPollerSessionStateStopRequest,
} Gen1aPollerSessionState;
struct Gen1aPoller {
Nfc* nfc;
Gen1aPollerState state;
Gen1aPollerSessionState session_state;
uint16_t current_block;
NfcDevice* mfc_device;
BitBuffer* tx_buffer;
BitBuffer* rx_buffer;
Gen1aPollerEvent gen1a_event;
Gen1aPollerEventData gen1a_event_data;
Gen1aPollerCallback callback;
void* context;
};
Gen1aPollerError gen1a_poller_wupa(Gen1aPoller* instance);
Gen1aPollerError gen1a_poller_data_access(Gen1aPoller* instance);
Gen1aPollerError
gen1a_poller_write_block(Gen1aPoller* instance, uint8_t block_num, const MfClassicBlock* block);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,533 @@
#include "gen4_poller_i.h"
#include <nfc/protocols/iso14443_3a/iso14443_3a.h>
#include <nfc/protocols/iso14443_3a/iso14443_3a_poller.h>
#include <nfc/helpers/nfc_util.h>
#include <nfc/nfc_poller.h>
#include <furi/furi.h>
#define GEN4_POLLER_THREAD_FLAG_DETECTED (1U << 0)
typedef NfcCommand (*Gen4PollerStateHandler)(Gen4Poller* instance);
typedef struct {
NfcPoller* poller;
uint32_t password;
BitBuffer* tx_buffer;
BitBuffer* rx_buffer;
FuriThreadId thread_id;
Gen4PollerError error;
} Gen4PollerDetectContext;
static const uint8_t gen4_poller_default_config[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
0x00, 0x09, 0x78, 0x00, 0x91, 0x02, 0xDA,
0xBC, 0x19, 0x10, 0x10, 0x11, 0x12, 0x13,
0x14, 0x15, 0x16, 0x04, 0x00, 0x08, 0x00};
static const uint8_t gen4_poller_default_block_0[GEN4_POLLER_BLOCK_SIZE] =
{0x00, 0x01, 0x02, 0x03, 0x04, 0x04, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static const uint8_t gen4_poller_default_empty_block[GEN4_POLLER_BLOCK_SIZE] = {0};
static const uint8_t gen4_poller_default_sector_trailer_block[GEN4_POLLER_BLOCK_SIZE] =
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x80, 0x69, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
static bool gen4_poller_is_sector_trailer(uint8_t block_num) {
uint8_t sec_tr_block_num = 0;
if(block_num < 128) {
sec_tr_block_num = block_num | 0x03;
} else {
sec_tr_block_num = block_num | 0x0f;
}
return block_num == sec_tr_block_num;
}
Gen4Poller* gen4_poller_alloc(Nfc* nfc) {
furi_assert(nfc);
Gen4Poller* instance = malloc(sizeof(Gen4Poller));
instance->poller = nfc_poller_alloc(nfc, NfcProtocolIso14443_3a);
instance->gen4_event.data = &instance->gen4_event_data;
instance->tx_buffer = bit_buffer_alloc(GEN4_POLLER_MAX_BUFFER_SIZE);
instance->rx_buffer = bit_buffer_alloc(GEN4_POLLER_MAX_BUFFER_SIZE);
return instance;
}
void gen4_poller_free(Gen4Poller* instance) {
furi_assert(instance);
nfc_poller_free(instance->poller);
bit_buffer_free(instance->tx_buffer);
bit_buffer_free(instance->rx_buffer);
free(instance);
}
void gen4_poller_set_password(Gen4Poller* instance, uint32_t password) {
furi_assert(instance);
instance->password = password;
}
NfcCommand gen4_poller_detect_callback(NfcGenericEvent event, void* context) {
furi_assert(context);
furi_assert(event.protocol == NfcProtocolIso14443_3a);
furi_assert(event.instance);
furi_assert(event.event_data);
NfcCommand command = NfcCommandStop;
Gen4PollerDetectContext* gen4_poller_detect_ctx = context;
Iso14443_3aPoller* iso3_poller = event.instance;
Iso14443_3aPollerEvent* iso3_event = event.event_data;
gen4_poller_detect_ctx->error = Gen4PollerErrorTimeout;
if(iso3_event->type == Iso14443_3aPollerEventTypeReady) {
do {
bit_buffer_append_byte(gen4_poller_detect_ctx->tx_buffer, GEN4_CMD_PREFIX);
uint8_t pwd_arr[4] = {};
nfc_util_num2bytes(gen4_poller_detect_ctx->password, COUNT_OF(pwd_arr), pwd_arr);
bit_buffer_append_bytes(gen4_poller_detect_ctx->tx_buffer, pwd_arr, COUNT_OF(pwd_arr));
bit_buffer_append_byte(gen4_poller_detect_ctx->tx_buffer, GEN4_CMD_GET_CFG);
Iso14443_3aError error = iso14443_3a_poller_send_standard_frame(
iso3_poller,
gen4_poller_detect_ctx->tx_buffer,
gen4_poller_detect_ctx->rx_buffer,
GEN4_POLLER_MAX_FWT);
if(error != Iso14443_3aErrorNone) {
gen4_poller_detect_ctx->error = Gen4PollerErrorProtocol;
break;
}
size_t rx_bytes = bit_buffer_get_size_bytes(gen4_poller_detect_ctx->rx_buffer);
if((rx_bytes != 30) && (rx_bytes != 32)) {
gen4_poller_detect_ctx->error = Gen4PollerErrorProtocol;
break;
}
gen4_poller_detect_ctx->error = Gen4PollerErrorNone;
} while(false);
} else if(iso3_event->type == Iso14443_3aPollerEventTypeError) {
gen4_poller_detect_ctx->error = Gen4PollerErrorTimeout;
}
furi_thread_flags_set(gen4_poller_detect_ctx->thread_id, GEN4_POLLER_THREAD_FLAG_DETECTED);
return command;
}
Gen4PollerError gen4_poller_detect(Nfc* nfc, uint32_t password) {
furi_assert(nfc);
Gen4PollerDetectContext gen4_poller_detect_ctx = {};
gen4_poller_detect_ctx.poller = nfc_poller_alloc(nfc, NfcProtocolIso14443_3a);
gen4_poller_detect_ctx.password = password;
gen4_poller_detect_ctx.tx_buffer = bit_buffer_alloc(GEN4_POLLER_MAX_BUFFER_SIZE);
gen4_poller_detect_ctx.rx_buffer = bit_buffer_alloc(GEN4_POLLER_MAX_BUFFER_SIZE);
gen4_poller_detect_ctx.thread_id = furi_thread_get_current_id();
gen4_poller_detect_ctx.error = Gen4PollerErrorNone;
nfc_poller_start(
gen4_poller_detect_ctx.poller, gen4_poller_detect_callback, &gen4_poller_detect_ctx);
uint32_t flags =
furi_thread_flags_wait(GEN4_POLLER_THREAD_FLAG_DETECTED, FuriFlagWaitAny, FuriWaitForever);
if(flags & GEN4_POLLER_THREAD_FLAG_DETECTED) {
furi_thread_flags_clear(GEN4_POLLER_THREAD_FLAG_DETECTED);
}
nfc_poller_stop(gen4_poller_detect_ctx.poller);
nfc_poller_free(gen4_poller_detect_ctx.poller);
bit_buffer_free(gen4_poller_detect_ctx.tx_buffer);
bit_buffer_free(gen4_poller_detect_ctx.rx_buffer);
return gen4_poller_detect_ctx.error;
}
NfcCommand gen4_poller_idle_handler(Gen4Poller* instance) {
NfcCommand command = NfcCommandContinue;
instance->current_block = 0;
memset(instance->config, 0, sizeof(instance->config));
instance->gen4_event.type = Gen4PollerEventTypeCardDetected;
command = instance->callback(instance->gen4_event, instance->context);
instance->state = Gen4PollerStateRequestMode;
return command;
}
NfcCommand gen4_poller_request_mode_handler(Gen4Poller* instance) {
NfcCommand command = NfcCommandContinue;
instance->gen4_event.type = Gen4PollerEventTypeRequestMode;
command = instance->callback(instance->gen4_event, instance->context);
if(instance->gen4_event_data.request_mode.mode == Gen4PollerModeWipe) {
instance->state = Gen4PollerStateWipe;
} else if(instance->gen4_event_data.request_mode.mode == Gen4PollerModeWrite) {
instance->state = Gen4PollerStateRequestWriteData;
} else if(instance->gen4_event_data.request_mode.mode == Gen4PollerModeSetPassword) {
instance->state = Gen4PollerStateChangePassword;
} else {
instance->state = Gen4PollerStateFail;
}
return command;
}
NfcCommand gen4_poller_wipe_handler(Gen4Poller* instance) {
NfcCommand command = NfcCommandContinue;
do {
Gen4PollerError error = Gen4PollerErrorNone;
if(instance->current_block == 0) {
error = gen4_poller_set_config(
instance,
instance->password,
gen4_poller_default_config,
sizeof(gen4_poller_default_config),
false);
if(error != Gen4PollerErrorNone) {
FURI_LOG_D(TAG, "Failed to set default config: %d", error);
instance->state = Gen4PollerStateFail;
break;
}
error = gen4_poller_write_block(
instance, instance->password, instance->current_block, gen4_poller_default_block_0);
if(error != Gen4PollerErrorNone) {
FURI_LOG_D(TAG, "Failed to write 0 block: %d", error);
instance->state = Gen4PollerStateFail;
break;
}
} else if(instance->current_block < GEN4_POLLER_BLOCKS_TOTAL) {
const uint8_t* block = gen4_poller_is_sector_trailer(instance->current_block) ?
gen4_poller_default_sector_trailer_block :
gen4_poller_default_empty_block;
error = gen4_poller_write_block(
instance, instance->password, instance->current_block, block);
if(error != Gen4PollerErrorNone) {
FURI_LOG_D(TAG, "Failed to write %d block: %d", instance->current_block, error);
instance->state = Gen4PollerStateFail;
break;
}
} else {
instance->state = Gen4PollerStateSuccess;
break;
}
instance->current_block++;
} while(false);
return command;
}
NfcCommand gen4_poller_request_write_data_handler(Gen4Poller* instance) {
NfcCommand command = NfcCommandContinue;
instance->gen4_event.type = Gen4PollerEventTypeRequestDataToWrite;
command = instance->callback(instance->gen4_event, instance->context);
instance->protocol = instance->gen4_event_data.request_data.protocol;
instance->data = instance->gen4_event_data.request_data.data;
if((instance->protocol == NfcProtocolMfClassic) ||
(instance->protocol == NfcProtocolMfUltralight)) {
instance->state = Gen4PollerStateWrite;
} else {
FURI_LOG_E(TAG, "Unsupported protocol");
instance->state = Gen4PollerStateFail;
}
return command;
}
static NfcCommand gen4_poller_write_mf_classic(Gen4Poller* instance) {
NfcCommand command = NfcCommandContinue;
do {
const MfClassicData* mfc_data = instance->data;
const Iso14443_3aData* iso3_data = mfc_data->iso14443_3a_data;
if(instance->current_block == 0) {
instance->config[0] = 0x00;
instance->total_blocks = mf_classic_get_total_block_num(mfc_data->type);
if(iso3_data->uid_len == 4) {
instance->config[1] = Gen4PollerUIDLengthSingle;
} else if(iso3_data->uid_len == 7) {
instance->config[1] = Gen4PollerUIDLengthDouble;
} else {
FURI_LOG_E(TAG, "Unsupported UID len: %d", iso3_data->uid_len);
instance->state = Gen4PollerStateFail;
break;
}
instance->config[6] = Gen4PollerShadowModeIgnore;
instance->config[24] = iso3_data->atqa[0];
instance->config[25] = iso3_data->atqa[1];
instance->config[26] = iso3_data->sak;
instance->config[27] = 0x00;
instance->config[28] = instance->total_blocks;
instance->config[29] = 0x01;
Gen4PollerError error = gen4_poller_set_config(
instance, instance->password, instance->config, sizeof(instance->config), false);
if(error != Gen4PollerErrorNone) {
FURI_LOG_D(TAG, "Failed to write config: %d", error);
instance->state = Gen4PollerStateFail;
break;
}
}
if(instance->current_block < instance->total_blocks) {
FURI_LOG_D(TAG, "Writing block %d", instance->current_block);
Gen4PollerError error = gen4_poller_write_block(
instance,
instance->password,
instance->current_block,
mfc_data->block[instance->current_block].data);
if(error != Gen4PollerErrorNone) {
FURI_LOG_D(TAG, "Failed to write %d block: %d", instance->current_block, error);
instance->state = Gen4PollerStateFail;
break;
}
} else {
instance->state = Gen4PollerStateSuccess;
break;
}
instance->current_block++;
} while(false);
return command;
}
static NfcCommand gen4_poller_write_mf_ultralight(Gen4Poller* instance) {
NfcCommand command = NfcCommandContinue;
do {
const MfUltralightData* mfu_data = instance->data;
const Iso14443_3aData* iso3_data = mfu_data->iso14443_3a_data;
if(instance->current_block == 0) {
instance->total_blocks = 64;
instance->config[0] = 0x01;
switch(mfu_data->type) {
case MfUltralightTypeNTAG203:
case MfUltralightTypeNTAG213:
case MfUltralightTypeNTAG215:
case MfUltralightTypeNTAG216:
case MfUltralightTypeNTAGI2C1K:
case MfUltralightTypeNTAGI2C2K:
case MfUltralightTypeNTAGI2CPlus1K:
case MfUltralightTypeNTAGI2CPlus2K:
instance->config[27] = Gen4PollerUltralightModeNTAG;
instance->total_blocks = 64 * 2;
break;
case MfUltralightTypeUL11:
case MfUltralightTypeUL21:
// UL-C?
// UL?
default:
instance->config[27] = Gen4PollerUltralightModeUL_EV1;
break;
}
if(iso3_data->uid_len == 4) {
instance->config[1] = Gen4PollerUIDLengthSingle;
} else if(iso3_data->uid_len == 7) {
instance->config[1] = Gen4PollerUIDLengthDouble;
} else {
FURI_LOG_E(TAG, "Unsupported UID len: %d", iso3_data->uid_len);
instance->state = Gen4PollerStateFail;
break;
}
instance->config[6] = Gen4PollerShadowModeHighSpeedIgnore;
instance->config[24] = iso3_data->atqa[0];
instance->config[25] = iso3_data->atqa[1];
instance->config[26] = iso3_data->sak;
instance->config[27] = 0x00;
instance->config[28] = instance->total_blocks;
instance->config[29] = 0x01;
Gen4PollerError error = gen4_poller_set_config(
instance, instance->password, instance->config, sizeof(instance->config), false);
if(error != Gen4PollerErrorNone) {
FURI_LOG_D(TAG, "Failed to write config: %d", error);
instance->state = Gen4PollerStateFail;
break;
}
}
if(instance->current_block < mfu_data->pages_read) {
FURI_LOG_D(
TAG, "Writing page %zu / %zu", instance->current_block, mfu_data->pages_read);
Gen4PollerError error = gen4_poller_write_block(
instance,
instance->password,
instance->current_block,
mfu_data->page[instance->current_block].data);
if(error != Gen4PollerErrorNone) {
FURI_LOG_D(TAG, "Failed to write %d page: %d", instance->current_block, error);
instance->state = Gen4PollerStateFail;
break;
}
instance->current_block++;
} else {
uint8_t block[GEN4_POLLER_BLOCK_SIZE] = {};
bool write_success = true;
for(size_t i = 0; i < 8; i++) {
memcpy(block, &mfu_data->signature.data[i * 4], 4); //-V1086
Gen4PollerError error =
gen4_poller_write_block(instance, instance->password, 0xF2 + i, block);
if(error != Gen4PollerErrorNone) {
write_success = false;
break;
}
}
if(!write_success) {
FURI_LOG_E(TAG, "Failed to write Signature");
instance->state = Gen4PollerStateFail;
break;
}
block[0] = mfu_data->version.header;
block[1] = mfu_data->version.vendor_id;
block[2] = mfu_data->version.prod_type;
block[3] = mfu_data->version.prod_subtype;
Gen4PollerError error =
gen4_poller_write_block(instance, instance->password, 0xFA, block);
if(error != Gen4PollerErrorNone) {
FURI_LOG_E(TAG, "Failed to write 1st part Version");
instance->state = Gen4PollerStateFail;
break;
}
block[0] = mfu_data->version.prod_ver_major;
block[1] = mfu_data->version.prod_ver_minor;
block[2] = mfu_data->version.storage_size;
block[3] = mfu_data->version.protocol_type;
error = gen4_poller_write_block(instance, instance->password, 0xFB, block);
if(error != Gen4PollerErrorNone) {
FURI_LOG_E(TAG, "Failed to write 2nd part Version");
instance->state = Gen4PollerStateFail;
break;
}
instance->state = Gen4PollerStateSuccess;
}
} while(false);
return command;
}
NfcCommand gen4_poller_write_handler(Gen4Poller* instance) {
NfcCommand command = NfcCommandContinue;
memcpy(instance->config, gen4_poller_default_config, sizeof(gen4_poller_default_config));
uint8_t password_arr[4] = {};
nfc_util_num2bytes(instance->password, sizeof(password_arr), password_arr);
memcpy(&instance->config[2], password_arr, sizeof(password_arr));
memset(&instance->config[7], 0, 17);
if(instance->protocol == NfcProtocolMfClassic) {
command = gen4_poller_write_mf_classic(instance);
} else if(instance->protocol == NfcProtocolMfUltralight) {
command = gen4_poller_write_mf_ultralight(instance);
} else {
furi_crash("Unsupported protocol to write");
}
return command;
}
NfcCommand gen4_poller_change_password_handler(Gen4Poller* instance) {
NfcCommand command = NfcCommandContinue;
do {
instance->gen4_event.type = Gen4PollerEventTypeRequestNewPassword;
command = instance->callback(instance->gen4_event, instance->context);
if(command != NfcCommandContinue) break;
uint32_t new_password = instance->gen4_event_data.request_password.password;
Gen4PollerError error =
gen4_poller_change_password(instance, instance->password, new_password);
if(error != Gen4PollerErrorNone) {
FURI_LOG_E(TAG, "Failed to change password: %d", error);
instance->state = Gen4PollerStateFail;
break;
}
instance->password = new_password;
instance->state = Gen4PollerStateSuccess;
} while(false);
return command;
}
NfcCommand gen4_poller_success_handler(Gen4Poller* instance) {
NfcCommand command = NfcCommandContinue;
instance->gen4_event.type = Gen4PollerEventTypeSuccess;
command = instance->callback(instance->gen4_event, instance->context);
if(command != NfcCommandStop) {
furi_delay_ms(100);
}
return command;
}
NfcCommand gen4_poller_fail_handler(Gen4Poller* instance) {
NfcCommand command = NfcCommandContinue;
instance->gen4_event.type = Gen4PollerEventTypeFail;
command = instance->callback(instance->gen4_event, instance->context);
if(command != NfcCommandStop) {
furi_delay_ms(100);
}
return command;
}
static const Gen4PollerStateHandler gen4_poller_state_handlers[Gen4PollerStateNum] = {
[Gen4PollerStateIdle] = gen4_poller_idle_handler,
[Gen4PollerStateRequestMode] = gen4_poller_request_mode_handler,
[Gen4PollerStateRequestWriteData] = gen4_poller_request_write_data_handler,
[Gen4PollerStateWrite] = gen4_poller_write_handler,
[Gen4PollerStateWipe] = gen4_poller_wipe_handler,
[Gen4PollerStateChangePassword] = gen4_poller_change_password_handler,
[Gen4PollerStateSuccess] = gen4_poller_success_handler,
[Gen4PollerStateFail] = gen4_poller_fail_handler,
};
static NfcCommand gen4_poller_callback(NfcGenericEvent event, void* context) {
furi_assert(context);
furi_assert(event.protocol == NfcProtocolIso14443_3a);
furi_assert(event.event_data);
furi_assert(event.instance);
NfcCommand command = NfcCommandContinue;
Gen4Poller* instance = context;
instance->iso3_poller = event.instance;
Iso14443_3aPollerEvent* iso3_event = event.event_data;
if(iso3_event->type == Iso14443_3aPollerEventTypeReady) {
command = gen4_poller_state_handlers[instance->state](instance);
}
return command;
}
void gen4_poller_start(Gen4Poller* instance, Gen4PollerCallback callback, void* context) {
furi_assert(instance);
furi_assert(callback);
instance->callback = callback;
instance->context = context;
nfc_poller_start(instance->poller, gen4_poller_callback, instance);
}
void gen4_poller_stop(Gen4Poller* instance) {
furi_assert(instance);
nfc_poller_stop(instance->poller);
}

View File

@@ -0,0 +1,84 @@
#pragma once
#include <nfc/nfc.h>
#include <nfc/protocols/nfc_protocol.h>
#include <nfc/protocols/mf_classic/mf_classic.h>
#include <nfc/protocols/mf_ultralight/mf_ultralight.h>
#ifdef __cplusplus
extern "C" {
#endif
#define GEN4_CMD_PREFIX (0xCF)
#define GEN4_CMD_GET_CFG (0xC6)
#define GEN4_CMD_WRITE (0xCD)
#define GEN4_CMD_READ (0xCE)
#define GEN4_CMD_SET_CFG (0xF0)
#define GEN4_CMD_FUSE_CFG (0xF1)
#define GEN4_CMD_SET_PWD (0xFE)
typedef enum {
Gen4PollerErrorNone,
Gen4PollerErrorTimeout,
Gen4PollerErrorProtocol,
} Gen4PollerError;
typedef enum {
Gen4PollerEventTypeCardDetected,
Gen4PollerEventTypeRequestMode,
Gen4PollerEventTypeRequestDataToWrite,
Gen4PollerEventTypeRequestNewPassword,
Gen4PollerEventTypeSuccess,
Gen4PollerEventTypeFail,
} Gen4PollerEventType;
typedef enum {
Gen4PollerModeWipe,
Gen4PollerModeWrite,
Gen4PollerModeSetPassword,
} Gen4PollerMode;
typedef struct {
Gen4PollerMode mode;
} Gen4PollerEventDataRequestMode;
typedef struct {
NfcProtocol protocol;
const NfcDeviceData* data;
} Gen4PollerEventDataRequestDataToWrite;
typedef struct {
uint32_t password;
} Gen4PollerEventDataRequestNewPassword;
typedef union {
Gen4PollerEventDataRequestMode request_mode;
Gen4PollerEventDataRequestDataToWrite request_data;
Gen4PollerEventDataRequestNewPassword request_password;
} Gen4PollerEventData;
typedef struct {
Gen4PollerEventType type;
Gen4PollerEventData* data;
} Gen4PollerEvent;
typedef NfcCommand (*Gen4PollerCallback)(Gen4PollerEvent event, void* context);
typedef struct Gen4Poller Gen4Poller;
Gen4PollerError gen4_poller_detect(Nfc* nfc, uint32_t password);
Gen4Poller* gen4_poller_alloc(Nfc* nfc);
void gen4_poller_free(Gen4Poller* instance);
void gen4_poller_set_password(Gen4Poller* instance, uint32_t password);
void gen4_poller_start(Gen4Poller* instance, Gen4PollerCallback callback, void* context);
void gen4_poller_stop(Gen4Poller* instance);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,129 @@
#include "gen4_poller_i.h"
#include <nfc/protocols/iso14443_3a/iso14443_3a_poller.h>
#include <nfc/helpers/nfc_util.h>
#define GEN4_CMD_PREFIX (0xCF)
#define GEN4_CMD_GET_CFG (0xC6)
#define GEN4_CMD_WRITE (0xCD)
#define GEN4_CMD_READ (0xCE)
#define GEN4_CMD_SET_CFG (0xF0)
#define GEN4_CMD_FUSE_CFG (0xF1)
#define GEN4_CMD_SET_PWD (0xFE)
static Gen4PollerError gen4_poller_process_error(Iso14443_3aError error) {
Gen4PollerError ret = Gen4PollerErrorNone;
if(error == Iso14443_3aErrorNone) {
ret = Gen4PollerErrorNone;
} else {
ret = Gen4PollerErrorTimeout;
}
return ret;
}
Gen4PollerError gen4_poller_set_config(
Gen4Poller* instance,
uint32_t password,
const uint8_t* config,
size_t config_size,
bool fuse) {
Gen4PollerError ret = Gen4PollerErrorNone;
bit_buffer_reset(instance->tx_buffer);
do {
uint8_t password_arr[4] = {};
nfc_util_num2bytes(password, COUNT_OF(password_arr), password_arr);
bit_buffer_append_byte(instance->tx_buffer, GEN4_CMD_PREFIX);
bit_buffer_append_bytes(instance->tx_buffer, password_arr, COUNT_OF(password_arr));
uint8_t fuse_config = fuse ? GEN4_CMD_FUSE_CFG : GEN4_CMD_SET_CFG;
bit_buffer_append_byte(instance->tx_buffer, fuse_config);
bit_buffer_append_bytes(instance->tx_buffer, config, config_size);
Iso14443_3aError error = iso14443_3a_poller_send_standard_frame(
instance->iso3_poller, instance->tx_buffer, instance->rx_buffer, GEN4_POLLER_MAX_FWT);
if(error != Iso14443_3aErrorNone) {
ret = gen4_poller_process_error(error);
break;
}
size_t rx_bytes = bit_buffer_get_size_bytes(instance->rx_buffer);
if(rx_bytes != 2) {
ret = Gen4PollerErrorProtocol;
break;
}
} while(false);
return ret;
}
Gen4PollerError gen4_poller_write_block(
Gen4Poller* instance,
uint32_t password,
uint8_t block_num,
const uint8_t* data) {
Gen4PollerError ret = Gen4PollerErrorNone;
bit_buffer_reset(instance->tx_buffer);
do {
uint8_t password_arr[4] = {};
nfc_util_num2bytes(password, COUNT_OF(password_arr), password_arr);
bit_buffer_append_byte(instance->tx_buffer, GEN4_CMD_PREFIX);
bit_buffer_append_bytes(instance->tx_buffer, password_arr, COUNT_OF(password_arr));
bit_buffer_append_byte(instance->tx_buffer, GEN4_CMD_WRITE);
bit_buffer_append_byte(instance->tx_buffer, block_num);
bit_buffer_append_bytes(instance->tx_buffer, data, GEN4_POLLER_BLOCK_SIZE);
Iso14443_3aError error = iso14443_3a_poller_send_standard_frame(
instance->iso3_poller, instance->tx_buffer, instance->rx_buffer, GEN4_POLLER_MAX_FWT);
if(error != Iso14443_3aErrorNone) {
ret = gen4_poller_process_error(error);
break;
}
size_t rx_bytes = bit_buffer_get_size_bytes(instance->rx_buffer);
if(rx_bytes != 2) {
ret = Gen4PollerErrorProtocol;
break;
}
} while(false);
return ret;
}
Gen4PollerError
gen4_poller_change_password(Gen4Poller* instance, uint32_t pwd_current, uint32_t pwd_new) {
Gen4PollerError ret = Gen4PollerErrorNone;
bit_buffer_reset(instance->tx_buffer);
do {
uint8_t password_arr[4] = {};
nfc_util_num2bytes(pwd_current, COUNT_OF(password_arr), password_arr);
bit_buffer_append_byte(instance->tx_buffer, GEN4_CMD_PREFIX);
bit_buffer_append_bytes(instance->tx_buffer, password_arr, COUNT_OF(password_arr));
bit_buffer_append_byte(instance->tx_buffer, GEN4_CMD_SET_PWD);
nfc_util_num2bytes(pwd_new, COUNT_OF(password_arr), password_arr);
bit_buffer_append_bytes(instance->tx_buffer, password_arr, COUNT_OF(password_arr));
Iso14443_3aError error = iso14443_3a_poller_send_standard_frame(
instance->iso3_poller, instance->tx_buffer, instance->rx_buffer, GEN4_POLLER_MAX_FWT);
if(error != Iso14443_3aErrorNone) {
ret = gen4_poller_process_error(error);
break;
}
size_t rx_bytes = bit_buffer_get_size_bytes(instance->rx_buffer);
if(rx_bytes != 2) {
ret = Gen4PollerErrorProtocol;
break;
}
} while(false);
return ret;
}

View File

@@ -0,0 +1,101 @@
#pragma once
#include "gen4_poller.h"
#include <nfc/nfc_poller.h>
#include <nfc/protocols/iso14443_3a/iso14443_3a_poller.h>
#define TAG "Gen4Poller"
#ifdef __cplusplus
extern "C" {
#endif
#define GEN4_POLLER_MAX_BUFFER_SIZE (64U)
#define GEN4_POLLER_MAX_FWT (200000U)
#define GEN4_POLLER_BLOCK_SIZE (16)
#define GEN4_POLLER_BLOCKS_TOTAL (256)
#define GEN4_POLLER_CONFIG_SIZE_MAX (30)
typedef enum {
Gen4PollerUIDLengthSingle = 0x00,
Gen4PollerUIDLengthDouble = 0x01,
Gen4PollerUIDLengthTriple = 0x02
} Gen4PollerUIDLength;
typedef enum {
Gen4PollerUltralightModeUL_EV1 = 0x00,
Gen4PollerUltralightModeNTAG = 0x01,
Gen4PollerUltralightModeUL_C = 0x02,
Gen4PollerUltralightModeUL = 0x03
} Gen4PollerUltralightMode;
typedef enum {
// for writing original (shadow) data
Gen4PollerShadowModePreWrite = 0x00,
// written data can be read once before restored to original
Gen4PollerShadowModeRestore = 0x01,
// written data is discarded
Gen4PollerShadowModeIgnore = 0x02,
// apparently for UL?
Gen4PollerShadowModeHighSpeedIgnore = 0x03
} Gen4PollerShadowMode;
typedef enum {
Gen4PollerStateIdle,
Gen4PollerStateRequestMode,
Gen4PollerStateRequestWriteData,
Gen4PollerStateWrite,
Gen4PollerStateWipe,
Gen4PollerStateChangePassword,
Gen4PollerStateSuccess,
Gen4PollerStateFail,
Gen4PollerStateNum,
} Gen4PollerState;
struct Gen4Poller {
NfcPoller* poller;
Iso14443_3aPoller* iso3_poller;
Gen4PollerState state;
uint32_t password;
BitBuffer* tx_buffer;
BitBuffer* rx_buffer;
uint16_t current_block;
uint16_t total_blocks;
NfcProtocol protocol;
const NfcDeviceData* data;
uint32_t new_password;
uint8_t config[GEN4_POLLER_CONFIG_SIZE_MAX];
Gen4PollerEvent gen4_event;
Gen4PollerEventData gen4_event_data;
Gen4PollerCallback callback;
void* context;
};
Gen4PollerError gen4_poller_set_config(
Gen4Poller* instance,
uint32_t password,
const uint8_t* config,
size_t config_size,
bool fuse);
Gen4PollerError gen4_poller_write_block(
Gen4Poller* instance,
uint32_t password,
uint8_t block_num,
const uint8_t* data);
Gen4PollerError
gen4_poller_change_password(Gen4Poller* instance, uint32_t pwd_current, uint32_t pwd_new);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,14 @@
#include "nfc_magic_protocols.h"
#include <furi/furi.h>
static const char* nfc_magic_protocol_names[NfcMagicProtocolNum] = {
[NfcMagicProtocolGen1] = "Classic Gen 1A/B",
[NfcMagicProtocolGen4] = "Gen 4 GTU",
};
const char* nfc_magic_protocols_get_name(NfcMagicProtocol protocol) {
furi_assert(protocol < NfcMagicProtocolNum);
return nfc_magic_protocol_names[protocol];
}

View File

@@ -0,0 +1,19 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
NfcMagicProtocolGen1,
NfcMagicProtocolGen4,
NfcMagicProtocolNum,
NfcMagicProtocolInvalid,
} NfcMagicProtocol;
const char* nfc_magic_protocols_get_name(NfcMagicProtocol protocol);
#ifdef __cplusplus
}
#endif

View File

@@ -1,23 +0,0 @@
#include "types.h"
const char* nfc_magic_type(MagicType type) {
if(type == MagicTypeClassicGen1) {
return "Classic Gen 1A/B";
} else if(type == MagicTypeClassicDirectWrite) {
return "Classic DirectWrite";
} else if(type == MagicTypeClassicAPDU) {
return "Classic APDU";
} else if(type == MagicTypeUltralightGen1) {
return "Ultralight Gen 1";
} else if(type == MagicTypeUltralightDirectWrite) {
return "Ultralight DirectWrite";
} else if(type == MagicTypeUltralightC_Gen1) {
return "Ultralight-C Gen 1";
} else if(type == MagicTypeUltralightC_DirectWrite) {
return "Ultralight-C DirectWrite";
} else if(type == MagicTypeGen4) {
return "Gen 4 GTU";
} else {
return "Unknown";
}
}

View File

@@ -1,5 +0,0 @@
#pragma once
#include "common.h"
const char* nfc_magic_type(MagicType type);

View File

@@ -1,183 +0,0 @@
#include "nfc_magic_i.h"
bool nfc_magic_custom_event_callback(void* context, uint32_t event) {
furi_assert(context);
NfcMagic* nfc_magic = context;
return scene_manager_handle_custom_event(nfc_magic->scene_manager, event);
}
bool nfc_magic_back_event_callback(void* context) {
furi_assert(context);
NfcMagic* nfc_magic = context;
return scene_manager_handle_back_event(nfc_magic->scene_manager);
}
void nfc_magic_tick_event_callback(void* context) {
furi_assert(context);
NfcMagic* nfc_magic = context;
scene_manager_handle_tick_event(nfc_magic->scene_manager);
}
void nfc_magic_show_loading_popup(void* context, bool show) {
NfcMagic* nfc_magic = context;
if(show) {
// Raise timer priority so that animations can play
furi_timer_set_thread_priority(FuriTimerThreadPriorityElevated);
view_dispatcher_switch_to_view(nfc_magic->view_dispatcher, NfcMagicViewLoading);
} else {
// Restore default timer priority
furi_timer_set_thread_priority(FuriTimerThreadPriorityNormal);
}
}
NfcMagic* nfc_magic_alloc() {
NfcMagic* nfc_magic = malloc(sizeof(NfcMagic));
nfc_magic->worker = nfc_magic_worker_alloc();
nfc_magic->view_dispatcher = view_dispatcher_alloc();
nfc_magic->scene_manager = scene_manager_alloc(&nfc_magic_scene_handlers, nfc_magic);
view_dispatcher_enable_queue(nfc_magic->view_dispatcher);
view_dispatcher_set_event_callback_context(nfc_magic->view_dispatcher, nfc_magic);
view_dispatcher_set_custom_event_callback(
nfc_magic->view_dispatcher, nfc_magic_custom_event_callback);
view_dispatcher_set_navigation_event_callback(
nfc_magic->view_dispatcher, nfc_magic_back_event_callback);
view_dispatcher_set_tick_event_callback(
nfc_magic->view_dispatcher, nfc_magic_tick_event_callback, 100);
// Nfc device
nfc_magic->dev = malloc(sizeof(NfcMagicDevice));
nfc_magic->source_dev = nfc_device_alloc();
furi_string_set(nfc_magic->source_dev->folder, NFC_APP_FOLDER);
// Open GUI record
nfc_magic->gui = furi_record_open(RECORD_GUI);
view_dispatcher_attach_to_gui(
nfc_magic->view_dispatcher, nfc_magic->gui, ViewDispatcherTypeFullscreen);
// Open Notification record
nfc_magic->notifications = furi_record_open(RECORD_NOTIFICATION);
// Submenu
nfc_magic->submenu = submenu_alloc();
view_dispatcher_add_view(
nfc_magic->view_dispatcher, NfcMagicViewMenu, submenu_get_view(nfc_magic->submenu));
// Popup
nfc_magic->popup = popup_alloc();
view_dispatcher_add_view(
nfc_magic->view_dispatcher, NfcMagicViewPopup, popup_get_view(nfc_magic->popup));
// Loading
nfc_magic->loading = loading_alloc();
view_dispatcher_add_view(
nfc_magic->view_dispatcher, NfcMagicViewLoading, loading_get_view(nfc_magic->loading));
// Text Input
nfc_magic->text_input = text_input_alloc();
view_dispatcher_add_view(
nfc_magic->view_dispatcher,
NfcMagicViewTextInput,
text_input_get_view(nfc_magic->text_input));
// Byte Input
nfc_magic->byte_input = byte_input_alloc();
view_dispatcher_add_view(
nfc_magic->view_dispatcher,
NfcMagicViewByteInput,
byte_input_get_view(nfc_magic->byte_input));
// Custom Widget
nfc_magic->widget = widget_alloc();
view_dispatcher_add_view(
nfc_magic->view_dispatcher, NfcMagicViewWidget, widget_get_view(nfc_magic->widget));
return nfc_magic;
}
void nfc_magic_free(NfcMagic* nfc_magic) {
furi_assert(nfc_magic);
// Nfc device
free(nfc_magic->dev);
nfc_device_free(nfc_magic->source_dev);
// Submenu
view_dispatcher_remove_view(nfc_magic->view_dispatcher, NfcMagicViewMenu);
submenu_free(nfc_magic->submenu);
// Popup
view_dispatcher_remove_view(nfc_magic->view_dispatcher, NfcMagicViewPopup);
popup_free(nfc_magic->popup);
// Loading
view_dispatcher_remove_view(nfc_magic->view_dispatcher, NfcMagicViewLoading);
loading_free(nfc_magic->loading);
// Text Input
view_dispatcher_remove_view(nfc_magic->view_dispatcher, NfcMagicViewTextInput);
text_input_free(nfc_magic->text_input);
// Byte Input
view_dispatcher_remove_view(nfc_magic->view_dispatcher, NfcMagicViewByteInput);
byte_input_free(nfc_magic->byte_input);
// Custom Widget
view_dispatcher_remove_view(nfc_magic->view_dispatcher, NfcMagicViewWidget);
widget_free(nfc_magic->widget);
// Worker
nfc_magic_worker_stop(nfc_magic->worker);
nfc_magic_worker_free(nfc_magic->worker);
// View Dispatcher
view_dispatcher_free(nfc_magic->view_dispatcher);
// Scene Manager
scene_manager_free(nfc_magic->scene_manager);
// GUI
furi_record_close(RECORD_GUI);
nfc_magic->gui = NULL;
// Notifications
furi_record_close(RECORD_NOTIFICATION);
nfc_magic->notifications = NULL;
free(nfc_magic);
}
static const NotificationSequence nfc_magic_sequence_blink_start_cyan = {
&message_blink_start_10,
&message_blink_set_color_cyan,
&message_do_not_reset,
NULL,
};
static const NotificationSequence nfc_magic_sequence_blink_stop = {
&message_blink_stop,
NULL,
};
void nfc_magic_blink_start(NfcMagic* nfc_magic) {
notification_message(nfc_magic->notifications, &nfc_magic_sequence_blink_start_cyan);
}
void nfc_magic_blink_stop(NfcMagic* nfc_magic) {
notification_message(nfc_magic->notifications, &nfc_magic_sequence_blink_stop);
}
int32_t nfc_magic_app(void* p) {
UNUSED(p);
NfcMagic* nfc_magic = nfc_magic_alloc();
scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneStart);
view_dispatcher_run(nfc_magic->view_dispatcher);
magic_deactivate();
nfc_magic_free(nfc_magic);
return 0;
}

View File

@@ -1,5 +0,0 @@
#pragma once
typedef struct NfcMagicDevice NfcMagicDevice;
typedef struct NfcMagic NfcMagic;

View File

@@ -0,0 +1,289 @@
#include "nfc_magic_app_i.h"
bool nfc_magic_app_custom_event_callback(void* context, uint32_t event) {
furi_assert(context);
NfcMagicApp* instance = context;
return scene_manager_handle_custom_event(instance->scene_manager, event);
}
bool nfc_magic_app_back_event_callback(void* context) {
furi_assert(context);
NfcMagicApp* instance = context;
return scene_manager_handle_back_event(instance->scene_manager);
}
void nfc_magic_app_tick_event_callback(void* context) {
furi_assert(context);
NfcMagicApp* instance = context;
scene_manager_handle_tick_event(instance->scene_manager);
}
void nfc_magic_app_show_loading_popup(void* context, bool show) {
NfcMagicApp* instance = context;
if(show) {
// Raise timer priority so that animations can play
furi_timer_set_thread_priority(FuriTimerThreadPriorityElevated);
view_dispatcher_switch_to_view(instance->view_dispatcher, NfcMagicAppViewLoading);
} else {
// Restore default timer priority
furi_timer_set_thread_priority(FuriTimerThreadPriorityNormal);
}
}
NfcMagicApp* nfc_magic_app_alloc() {
NfcMagicApp* instance = malloc(sizeof(NfcMagicApp));
instance->view_dispatcher = view_dispatcher_alloc();
instance->scene_manager = scene_manager_alloc(&nfc_magic_scene_handlers, instance);
view_dispatcher_enable_queue(instance->view_dispatcher);
view_dispatcher_set_event_callback_context(instance->view_dispatcher, instance);
view_dispatcher_set_custom_event_callback(
instance->view_dispatcher, nfc_magic_app_custom_event_callback);
view_dispatcher_set_navigation_event_callback(
instance->view_dispatcher, nfc_magic_app_back_event_callback);
view_dispatcher_set_tick_event_callback(
instance->view_dispatcher, nfc_magic_app_tick_event_callback, 100);
// Nfc device
instance->source_dev = nfc_device_alloc();
nfc_device_set_loading_callback(
instance->source_dev, nfc_magic_app_show_loading_popup, instance);
instance->file_path = furi_string_alloc_set(NFC_APP_FOLDER);
instance->file_name = furi_string_alloc();
// Open GUI record
instance->gui = furi_record_open(RECORD_GUI);
view_dispatcher_attach_to_gui(
instance->view_dispatcher, instance->gui, ViewDispatcherTypeFullscreen);
// Open Notification record
instance->notifications = furi_record_open(RECORD_NOTIFICATION);
// Open Dialogs
instance->dialogs = furi_record_open(RECORD_DIALOGS);
// Open Storage
instance->storage = furi_record_open(RECORD_STORAGE);
// Submenu
instance->submenu = submenu_alloc();
view_dispatcher_add_view(
instance->view_dispatcher, NfcMagicAppViewMenu, submenu_get_view(instance->submenu));
// Popup
instance->popup = popup_alloc();
view_dispatcher_add_view(
instance->view_dispatcher, NfcMagicAppViewPopup, popup_get_view(instance->popup));
// Loading
instance->loading = loading_alloc();
view_dispatcher_add_view(
instance->view_dispatcher, NfcMagicAppViewLoading, loading_get_view(instance->loading));
// Text Input
instance->text_input = text_input_alloc();
view_dispatcher_add_view(
instance->view_dispatcher,
NfcMagicAppViewTextInput,
text_input_get_view(instance->text_input));
// Byte Input
instance->byte_input = byte_input_alloc();
view_dispatcher_add_view(
instance->view_dispatcher,
NfcMagicAppViewByteInput,
byte_input_get_view(instance->byte_input));
// Custom Widget
instance->widget = widget_alloc();
view_dispatcher_add_view(
instance->view_dispatcher, NfcMagicAppViewWidget, widget_get_view(instance->widget));
instance->nfc = nfc_alloc();
instance->scanner = nfc_magic_scanner_alloc(instance->nfc);
return instance;
}
void nfc_magic_app_free(NfcMagicApp* instance) {
furi_assert(instance);
// Nfc device
nfc_device_free(instance->source_dev);
furi_string_free(instance->file_name);
furi_string_free(instance->file_path);
// Submenu
view_dispatcher_remove_view(instance->view_dispatcher, NfcMagicAppViewMenu);
submenu_free(instance->submenu);
// Popup
view_dispatcher_remove_view(instance->view_dispatcher, NfcMagicAppViewPopup);
popup_free(instance->popup);
// Loading
view_dispatcher_remove_view(instance->view_dispatcher, NfcMagicAppViewLoading);
loading_free(instance->loading);
// Text Input
view_dispatcher_remove_view(instance->view_dispatcher, NfcMagicAppViewTextInput);
text_input_free(instance->text_input);
// Byte Input
view_dispatcher_remove_view(instance->view_dispatcher, NfcMagicAppViewByteInput);
byte_input_free(instance->byte_input);
// Custom Widget
view_dispatcher_remove_view(instance->view_dispatcher, NfcMagicAppViewWidget);
widget_free(instance->widget);
// View Dispatcher
view_dispatcher_free(instance->view_dispatcher);
// Scene Manager
scene_manager_free(instance->scene_manager);
// GUI
furi_record_close(RECORD_GUI);
instance->gui = NULL;
// Notifications
furi_record_close(RECORD_NOTIFICATION);
instance->notifications = NULL;
// Dialogs
furi_record_close(RECORD_DIALOGS);
instance->dialogs = NULL;
// Storage
furi_record_close(RECORD_STORAGE);
instance->storage = NULL;
nfc_magic_scanner_free(instance->scanner);
nfc_free(instance->nfc);
free(instance);
}
static const NotificationSequence nfc_magic_sequence_blink_start_cyan = {
&message_blink_start_10,
&message_blink_set_color_cyan,
&message_do_not_reset,
NULL,
};
static const NotificationSequence nfc_magic_sequence_blink_stop = {
&message_blink_stop,
NULL,
};
void nfc_magic_app_blink_start(NfcMagicApp* instance) {
notification_message(instance->notifications, &nfc_magic_sequence_blink_start_cyan);
}
void nfc_magic_app_blink_stop(NfcMagicApp* instance) {
notification_message(instance->notifications, &nfc_magic_sequence_blink_stop);
}
static bool nfc_magic_set_shadow_file_path(FuriString* file_path, FuriString* shadow_file_path) {
furi_assert(file_path);
furi_assert(shadow_file_path);
bool shadow_file_path_set = false;
if(furi_string_end_with(file_path, NFC_APP_SHADOW_EXTENSION)) {
furi_string_set(shadow_file_path, file_path);
shadow_file_path_set = true;
} else if(furi_string_end_with(file_path, NFC_APP_EXTENSION)) {
size_t path_len = furi_string_size(file_path);
// Cut .nfc
furi_string_set_n(shadow_file_path, file_path, 0, path_len - 4);
furi_string_cat_printf(shadow_file_path, "%s", NFC_APP_SHADOW_EXTENSION);
shadow_file_path_set = true;
}
return shadow_file_path_set;
}
static bool nfc_magic_has_shadow_file_internal(NfcMagicApp* instance, FuriString* path) {
furi_assert(path);
bool has_shadow_file = false;
FuriString* shadow_file_path = furi_string_alloc();
do {
if(furi_string_empty(path)) break;
if(!nfc_magic_set_shadow_file_path(path, shadow_file_path)) break;
has_shadow_file =
storage_common_exists(instance->storage, furi_string_get_cstr(shadow_file_path));
} while(false);
furi_string_free(shadow_file_path);
return has_shadow_file;
}
bool nfc_magic_load_file(NfcMagicApp* instance, FuriString* path, bool show_dialog) {
furi_assert(instance);
furi_assert(path);
bool result = false;
FuriString* load_path = furi_string_alloc();
if(nfc_magic_has_shadow_file_internal(instance, path)) {
nfc_magic_set_shadow_file_path(path, load_path);
} else if(furi_string_end_with(path, NFC_APP_SHADOW_EXTENSION)) {
size_t path_len = furi_string_size(path);
furi_string_set_n(load_path, path, 0, path_len - 4);
furi_string_cat_printf(load_path, "%s", NFC_APP_EXTENSION);
} else {
furi_string_set(load_path, path);
}
result = nfc_device_load(instance->source_dev, furi_string_get_cstr(load_path));
if(result) {
path_extract_filename(load_path, instance->file_name, true);
}
if((!result) && (show_dialog)) {
dialog_message_show_storage_error(instance->dialogs, "Cannot load\nkey file");
}
furi_string_free(load_path);
return result;
}
bool nfc_magic_load_from_file_select(NfcMagicApp* instance) {
furi_assert(instance);
DialogsFileBrowserOptions browser_options;
dialog_file_browser_set_basic_options(&browser_options, NFC_APP_EXTENSION, &I_Nfc_10px);
browser_options.base_path = NFC_APP_FOLDER;
browser_options.hide_dot_files = true;
// Input events and views are managed by file_browser
bool result = dialog_file_browser_show(
instance->dialogs, instance->file_path, instance->file_path, &browser_options);
if(result) {
result = nfc_magic_load_file(instance, instance->file_path, true);
}
return result;
}
int32_t nfc_magic_app(void* p) {
UNUSED(p);
NfcMagicApp* instance = nfc_magic_app_alloc();
scene_manager_next_scene(instance->scene_manager, NfcMagicSceneStart);
view_dispatcher_run(instance->view_dispatcher);
nfc_magic_app_free(instance);
return 0;
}

View File

@@ -0,0 +1,5 @@
#pragma once
typedef struct NfcMagicAppDevice NfcMagicAppDevice;
typedef struct NfcMagicApp NfcMagicApp;

View File

@@ -0,0 +1,103 @@
#pragma once
#include "nfc_magic_app.h"
#include "helpers/nfc_magic_custom_events.h"
#include <furi.h>
#include <gui/gui.h>
#include <gui/view_dispatcher.h>
#include <gui/scene_manager.h>
#include <notification/notification_messages.h>
#include <gui/modules/submenu.h>
#include <gui/modules/popup.h>
#include <gui/modules/loading.h>
#include <gui/modules/text_input.h>
#include <gui/modules/byte_input.h>
#include <gui/modules/widget.h>
#include <input/input.h>
#include "scenes/nfc_magic_scene.h"
#include <storage/storage.h>
#include <dialogs/dialogs.h>
#include <lib/toolbox/path.h>
#include "nfc_magic_icons.h"
#include <assets_icons.h>
#include <nfc/nfc.h>
#include <nfc/nfc_device.h>
#include "lib/magic/nfc_magic_scanner.h"
#include "lib/magic/protocols/nfc_magic_protocols.h"
#include "lib/magic/protocols/gen1a/gen1a_poller.h"
#include "lib/magic/protocols/gen4/gen4_poller.h"
#define NFC_APP_FOLDER ANY_PATH("nfc")
#define NFC_APP_EXTENSION ".nfc"
#define NFC_APP_SHADOW_EXTENSION ".shd"
#define NFC_MAGIC_APP_BYTE_INPUT_STORE_SIZE (4)
enum NfcMagicAppCustomEvent {
// Reserve first 100 events for button types and indexes, starting from 0
NfcMagicAppCustomEventReserved = 100,
NfcMagicAppCustomEventViewExit,
NfcMagicAppCustomEventWorkerExit,
NfcMagicAppCustomEventByteInputDone,
NfcMagicAppCustomEventTextInputDone,
};
struct NfcMagicApp {
ViewDispatcher* view_dispatcher;
Gui* gui;
NotificationApp* notifications;
DialogsApp* dialogs;
Storage* storage;
SceneManager* scene_manager;
NfcDevice* source_dev;
FuriString* file_name;
FuriString* file_path;
Nfc* nfc;
NfcMagicProtocol protocol;
NfcMagicScanner* scanner;
Gen1aPoller* gen1a_poller;
Gen4Poller* gen4_poller;
uint32_t gen4_password;
uint32_t gen4_password_new;
FuriString* text_box_store;
uint8_t byte_input_store[NFC_MAGIC_APP_BYTE_INPUT_STORE_SIZE];
// Common Views
Submenu* submenu;
Popup* popup;
Loading* loading;
TextInput* text_input;
ByteInput* byte_input;
Widget* widget;
};
typedef enum {
NfcMagicAppViewMenu,
NfcMagicAppViewPopup,
NfcMagicAppViewLoading,
NfcMagicAppViewTextInput,
NfcMagicAppViewByteInput,
NfcMagicAppViewWidget,
} NfcMagicAppView;
void nfc_magic_app_blink_start(NfcMagicApp* nfc_magic);
void nfc_magic_app_blink_stop(NfcMagicApp* nfc_magic);
void nfc_magic_app_show_loading_popup(void* context, bool show);
bool nfc_magic_load_from_file_select(NfcMagicApp* instance);

View File

@@ -1,95 +0,0 @@
#pragma once
#include "nfc_magic.h"
#include "nfc_magic_worker.h"
#include "lib/magic/common.h"
#include "lib/magic/types.h"
#include "lib/magic/classic_gen1.h"
#include "lib/magic/gen4.h"
#include <furi.h>
#include <gui/gui.h>
#include <gui/view_dispatcher.h>
#include <gui/scene_manager.h>
#include <notification/notification_messages.h>
#include <gui/modules/submenu.h>
#include <gui/modules/popup.h>
#include <gui/modules/loading.h>
#include <gui/modules/text_input.h>
#include <gui/modules/byte_input.h>
#include <gui/modules/widget.h>
#include <input/input.h>
#include "scenes/nfc_magic_scene.h"
#include <storage/storage.h>
#include <lib/toolbox/path.h>
#include <lib/nfc/nfc_device.h>
#include "nfc_magic_icons.h"
#include <assets_icons.h>
#define NFC_APP_FOLDER EXT_PATH("nfc")
enum NfcMagicCustomEvent {
// Reserve first 100 events for button types and indexes, starting from 0
NfcMagicCustomEventReserved = 100,
NfcMagicCustomEventViewExit,
NfcMagicCustomEventWorkerExit,
NfcMagicCustomEventByteInputDone,
NfcMagicCustomEventTextInputDone,
};
struct NfcMagicDevice {
MagicType type;
uint32_t cuid;
uint8_t uid_len;
uint32_t password;
};
struct NfcMagic {
NfcMagicWorker* worker;
ViewDispatcher* view_dispatcher;
Gui* gui;
NotificationApp* notifications;
SceneManager* scene_manager;
struct NfcMagicDevice* dev;
NfcDevice* source_dev;
uint32_t new_password;
FuriString* text_box_store;
// Common Views
Submenu* submenu;
Popup* popup;
Loading* loading;
TextInput* text_input;
ByteInput* byte_input;
Widget* widget;
};
typedef enum {
NfcMagicViewMenu,
NfcMagicViewPopup,
NfcMagicViewLoading,
NfcMagicViewTextInput,
NfcMagicViewByteInput,
NfcMagicViewWidget,
} NfcMagicView;
NfcMagic* nfc_magic_alloc();
void nfc_magic_text_store_set(NfcMagic* nfc_magic, const char* text, ...);
void nfc_magic_text_store_clear(NfcMagic* nfc_magic);
void nfc_magic_blink_start(NfcMagic* nfc_magic);
void nfc_magic_blink_stop(NfcMagic* nfc_magic);
void nfc_magic_show_loading_popup(void* context, bool show);

View File

@@ -1,483 +0,0 @@
#include "nfc_magic_worker_i.h"
#include "nfc_magic_i.h"
#include "lib/magic/common.h"
#include "lib/magic/classic_gen1.h"
#include "lib/magic/gen4.h"
#define TAG "NfcMagicWorker"
static void
nfc_magic_worker_change_state(NfcMagicWorker* nfc_magic_worker, NfcMagicWorkerState state) {
furi_assert(nfc_magic_worker);
nfc_magic_worker->state = state;
}
NfcMagicWorker* nfc_magic_worker_alloc() {
NfcMagicWorker* nfc_magic_worker = malloc(sizeof(NfcMagicWorker));
// Worker thread attributes
nfc_magic_worker->thread =
furi_thread_alloc_ex("NfcMagicWorker", 8192, nfc_magic_worker_task, nfc_magic_worker);
nfc_magic_worker->callback = NULL;
nfc_magic_worker->context = NULL;
nfc_magic_worker_change_state(nfc_magic_worker, NfcMagicWorkerStateReady);
return nfc_magic_worker;
}
void nfc_magic_worker_free(NfcMagicWorker* nfc_magic_worker) {
furi_assert(nfc_magic_worker);
furi_thread_free(nfc_magic_worker->thread);
free(nfc_magic_worker);
}
void nfc_magic_worker_stop(NfcMagicWorker* nfc_magic_worker) {
furi_assert(nfc_magic_worker);
nfc_magic_worker_change_state(nfc_magic_worker, NfcMagicWorkerStateStop);
furi_thread_join(nfc_magic_worker->thread);
}
void nfc_magic_worker_start(
NfcMagicWorker* nfc_magic_worker,
NfcMagicWorkerState state,
NfcMagicDevice* magic_dev,
NfcDeviceData* dev_data,
uint32_t new_password,
NfcMagicWorkerCallback callback,
void* context) {
furi_assert(nfc_magic_worker);
furi_assert(magic_dev);
furi_assert(dev_data);
furi_hal_nfc_deinit();
furi_hal_nfc_init();
nfc_magic_worker->callback = callback;
nfc_magic_worker->context = context;
nfc_magic_worker->magic_dev = magic_dev;
nfc_magic_worker->dev_data = dev_data;
nfc_magic_worker->new_password = new_password;
nfc_magic_worker_change_state(nfc_magic_worker, state);
furi_thread_start(nfc_magic_worker->thread);
}
int32_t nfc_magic_worker_task(void* context) {
NfcMagicWorker* nfc_magic_worker = context;
if(nfc_magic_worker->state == NfcMagicWorkerStateCheck) {
nfc_magic_worker_check(nfc_magic_worker);
} else if(nfc_magic_worker->state == NfcMagicWorkerStateWrite) {
nfc_magic_worker_write(nfc_magic_worker);
} else if(nfc_magic_worker->state == NfcMagicWorkerStateRekey) {
nfc_magic_worker_rekey(nfc_magic_worker);
} else if(nfc_magic_worker->state == NfcMagicWorkerStateWipe) {
nfc_magic_worker_wipe(nfc_magic_worker);
}
nfc_magic_worker_change_state(nfc_magic_worker, NfcMagicWorkerStateReady);
return 0;
}
void nfc_magic_worker_write(NfcMagicWorker* nfc_magic_worker) {
bool card_found_notified = false;
bool done = false;
FuriHalNfcDevData nfc_data = {};
NfcMagicDevice* magic_dev = nfc_magic_worker->magic_dev;
NfcDeviceData* dev_data = nfc_magic_worker->dev_data;
NfcProtocol dev_protocol = dev_data->protocol;
while(nfc_magic_worker->state == NfcMagicWorkerStateWrite) {
do {
if(magic_dev->type == MagicTypeClassicGen1) {
if(furi_hal_nfc_detect(&nfc_data, 200)) {
magic_deactivate();
magic_activate();
if(!magic_gen1_wupa()) {
FURI_LOG_E(TAG, "No card response to WUPA (not a magic card)");
nfc_magic_worker->callback(
NfcMagicWorkerEventWrongCard, nfc_magic_worker->context);
done = true;
break;
}
magic_deactivate();
}
magic_activate();
if(magic_gen1_wupa()) {
magic_gen1_data_access_cmd();
MfClassicData* mfc_data = &dev_data->mf_classic_data;
for(size_t i = 0; i < 64; i++) {
FURI_LOG_D(TAG, "Writing block %d", i);
if(!magic_gen1_write_blk(i, &mfc_data->block[i])) {
FURI_LOG_E(TAG, "Failed to write %d block", i);
done = true;
nfc_magic_worker->callback(
NfcMagicWorkerEventFail, nfc_magic_worker->context);
break;
}
}
done = true;
nfc_magic_worker->callback(
NfcMagicWorkerEventSuccess, nfc_magic_worker->context);
break;
}
} else if(magic_dev->type == MagicTypeGen4) {
if(furi_hal_nfc_detect(&nfc_data, 200)) {
uint8_t gen4_config[28];
uint32_t password = magic_dev->password;
uint32_t cuid;
if(dev_protocol == NfcDeviceProtocolMifareClassic) {
gen4_config[0] = 0x00;
gen4_config[27] = 0x00;
} else if(dev_protocol == NfcDeviceProtocolMifareUl) {
MfUltralightData* mf_ul_data = &dev_data->mf_ul_data;
gen4_config[0] = 0x01;
switch(mf_ul_data->type) {
case MfUltralightTypeUL11:
case MfUltralightTypeUL21:
// UL-C?
// UL?
default:
gen4_config[27] = MagicGen4UltralightModeUL_EV1;
break;
case MfUltralightTypeNTAG203:
case MfUltralightTypeNTAG213:
case MfUltralightTypeNTAG215:
case MfUltralightTypeNTAG216:
case MfUltralightTypeNTAGI2C1K:
case MfUltralightTypeNTAGI2C2K:
case MfUltralightTypeNTAGI2CPlus1K:
case MfUltralightTypeNTAGI2CPlus2K:
gen4_config[27] = MagicGen4UltralightModeNTAG;
break;
}
}
if(dev_data->nfc_data.uid_len == 4) {
gen4_config[1] = MagicGen4UIDLengthSingle;
} else if(dev_data->nfc_data.uid_len == 7) {
gen4_config[1] = MagicGen4UIDLengthDouble;
} else {
FURI_LOG_E(TAG, "Unexpected UID length %d", dev_data->nfc_data.uid_len);
nfc_magic_worker->callback(
NfcMagicWorkerEventFail, nfc_magic_worker->context);
done = true;
break;
}
gen4_config[2] = (uint8_t)(password >> 24);
gen4_config[3] = (uint8_t)(password >> 16);
gen4_config[4] = (uint8_t)(password >> 8);
gen4_config[5] = (uint8_t)password;
if(dev_protocol == NfcDeviceProtocolMifareUl) {
gen4_config[6] = MagicGen4ShadowModeHighSpeedIgnore;
} else {
gen4_config[6] = MagicGen4ShadowModeIgnore;
}
gen4_config[7] = 0x00;
memset(gen4_config + 8, 0, 16);
gen4_config[24] = dev_data->nfc_data.atqa[0];
gen4_config[25] = dev_data->nfc_data.atqa[1];
gen4_config[26] = dev_data->nfc_data.sak;
furi_hal_nfc_sleep();
furi_hal_nfc_activate_nfca(200, &cuid);
if(!magic_gen4_set_cfg(password, gen4_config, sizeof(gen4_config), false)) {
nfc_magic_worker->callback(
NfcMagicWorkerEventFail, nfc_magic_worker->context);
done = true;
break;
}
if(dev_protocol == NfcDeviceProtocolMifareClassic) {
MfClassicData* mfc_data = &dev_data->mf_classic_data;
size_t block_count = 64;
if(mfc_data->type == MfClassicType4k) block_count = 256;
for(size_t i = 0; i < block_count; i++) {
FURI_LOG_D(TAG, "Writing block %d", i);
if(!magic_gen4_write_blk(password, i, mfc_data->block[i].value)) {
FURI_LOG_E(TAG, "Failed to write %d block", i);
nfc_magic_worker->callback(
NfcMagicWorkerEventFail, nfc_magic_worker->context);
done = true;
break;
}
}
} else if(dev_protocol == NfcDeviceProtocolMifareUl) {
MfUltralightData* mf_ul_data = &dev_data->mf_ul_data;
for(size_t i = 0; (i * 4) < mf_ul_data->data_read; i++) {
size_t data_offset = i * 4;
FURI_LOG_D(
TAG,
"Writing page %zu (%zu/%u)",
i,
data_offset,
mf_ul_data->data_read);
uint8_t* block = mf_ul_data->data + data_offset;
if(!magic_gen4_write_blk(password, i, block)) {
FURI_LOG_E(TAG, "Failed to write %zu page", i);
nfc_magic_worker->callback(
NfcMagicWorkerEventFail, nfc_magic_worker->context);
done = true;
break;
}
}
uint8_t buffer[16] = {0};
for(size_t i = 0; i < 8; i++) {
memcpy(buffer, &mf_ul_data->signature[i * 4], 4); //-V1086
if(!magic_gen4_write_blk(password, 0xF2 + i, buffer)) {
FURI_LOG_E(TAG, "Failed to write signature block %d", i);
nfc_magic_worker->callback(
NfcMagicWorkerEventFail, nfc_magic_worker->context);
done = true;
break;
}
}
buffer[0] = mf_ul_data->version.header;
buffer[1] = mf_ul_data->version.vendor_id;
buffer[2] = mf_ul_data->version.prod_type;
buffer[3] = mf_ul_data->version.prod_subtype;
if(!magic_gen4_write_blk(password, 0xFA, buffer)) {
FURI_LOG_E(TAG, "Failed to write version block 0");
nfc_magic_worker->callback(
NfcMagicWorkerEventFail, nfc_magic_worker->context);
done = true;
break;
}
buffer[0] = mf_ul_data->version.prod_ver_major;
buffer[1] = mf_ul_data->version.prod_ver_minor;
buffer[2] = mf_ul_data->version.storage_size;
buffer[3] = mf_ul_data->version.protocol_type;
if(!magic_gen4_write_blk(password, 0xFB, buffer)) {
FURI_LOG_E(TAG, "Failed to write version block 1");
nfc_magic_worker->callback(
NfcMagicWorkerEventFail, nfc_magic_worker->context);
done = true;
break;
}
}
nfc_magic_worker->callback(
NfcMagicWorkerEventSuccess, nfc_magic_worker->context);
done = true;
break;
}
}
} while(false);
if(done) break;
if(card_found_notified) {
nfc_magic_worker->callback(
NfcMagicWorkerEventNoCardDetected, nfc_magic_worker->context);
card_found_notified = false;
}
furi_delay_ms(300);
}
magic_deactivate();
}
void nfc_magic_worker_check(NfcMagicWorker* nfc_magic_worker) {
FuriHalNfcDevData nfc_data = {};
NfcMagicDevice* magic_dev = nfc_magic_worker->magic_dev;
bool card_found_notified = false;
uint8_t gen4_config[MAGIC_GEN4_CONFIG_LEN];
while(nfc_magic_worker->state == NfcMagicWorkerStateCheck) {
magic_activate();
if(magic_gen1_wupa()) {
magic_dev->type = MagicTypeClassicGen1;
if(!card_found_notified) {
nfc_magic_worker->callback(
NfcMagicWorkerEventCardDetected, nfc_magic_worker->context);
card_found_notified = true;
}
if(furi_hal_nfc_detect(&nfc_data, 200)) {
magic_dev->cuid = nfc_data.cuid;
magic_dev->uid_len = nfc_data.uid_len;
} else {
// wrong BCC
magic_dev->uid_len = 4;
}
nfc_magic_worker->callback(NfcMagicWorkerEventSuccess, nfc_magic_worker->context);
break;
} else {
magic_deactivate();
magic_activate();
if(furi_hal_nfc_detect(&nfc_data, 200)) {
magic_dev->cuid = nfc_data.cuid;
magic_dev->uid_len = nfc_data.uid_len;
if(magic_gen4_get_cfg(magic_dev->password, gen4_config)) {
magic_dev->type = MagicTypeGen4;
if(!card_found_notified) {
nfc_magic_worker->callback(
NfcMagicWorkerEventCardDetected, nfc_magic_worker->context);
card_found_notified = true;
}
nfc_magic_worker->callback(
NfcMagicWorkerEventSuccess, nfc_magic_worker->context);
} else {
nfc_magic_worker->callback(
NfcMagicWorkerEventWrongCard, nfc_magic_worker->context);
card_found_notified = true;
}
break;
} else {
if(card_found_notified) {
nfc_magic_worker->callback(
NfcMagicWorkerEventNoCardDetected, nfc_magic_worker->context);
card_found_notified = false;
}
}
}
magic_deactivate();
furi_delay_ms(300);
}
magic_deactivate();
}
void nfc_magic_worker_rekey(NfcMagicWorker* nfc_magic_worker) {
NfcMagicDevice* magic_dev = nfc_magic_worker->magic_dev;
bool card_found_notified = false;
if(magic_dev->type != MagicTypeGen4) {
nfc_magic_worker->callback(NfcMagicWorkerEventCardDetected, nfc_magic_worker->context);
return;
}
while(nfc_magic_worker->state == NfcMagicWorkerStateRekey) {
magic_activate();
uint32_t cuid;
furi_hal_nfc_activate_nfca(200, &cuid);
if(cuid != magic_dev->cuid) {
if(card_found_notified) {
nfc_magic_worker->callback(
NfcMagicWorkerEventNoCardDetected, nfc_magic_worker->context);
card_found_notified = false;
}
continue;
}
nfc_magic_worker->callback(NfcMagicWorkerEventCardDetected, nfc_magic_worker->context);
card_found_notified = true;
if(magic_gen4_set_pwd(magic_dev->password, nfc_magic_worker->new_password)) {
magic_dev->password = nfc_magic_worker->new_password;
nfc_magic_worker->callback(NfcMagicWorkerEventSuccess, nfc_magic_worker->context);
break;
}
if(card_found_notified) { //-V547
nfc_magic_worker->callback(
NfcMagicWorkerEventNoCardDetected, nfc_magic_worker->context);
card_found_notified = false;
}
furi_delay_ms(300);
}
magic_deactivate();
}
void nfc_magic_worker_wipe(NfcMagicWorker* nfc_magic_worker) {
NfcMagicDevice* magic_dev = nfc_magic_worker->magic_dev;
bool card_found_notified = false;
bool card_wiped = false;
MfClassicBlock block;
memset(&block, 0, sizeof(MfClassicBlock));
MfClassicBlock empty_block;
memset(&empty_block, 0, sizeof(MfClassicBlock));
MfClassicBlock trailer_block;
memset(&trailer_block, 0xff, sizeof(MfClassicBlock));
block.value[0] = 0x01;
block.value[1] = 0x02;
block.value[2] = 0x03;
block.value[3] = 0x04;
block.value[4] = 0x04;
block.value[5] = 0x08;
block.value[6] = 0x04;
trailer_block.value[7] = 0x07;
trailer_block.value[8] = 0x80;
trailer_block.value[9] = 0x69;
while(nfc_magic_worker->state == NfcMagicWorkerStateWipe) {
do {
magic_deactivate();
furi_delay_ms(300);
if(!magic_activate()) break;
if(magic_dev->type == MagicTypeClassicGen1) {
if(!magic_gen1_wupa()) break;
if(!card_found_notified) {
nfc_magic_worker->callback(
NfcMagicWorkerEventCardDetected, nfc_magic_worker->context);
card_found_notified = true;
}
if(!magic_gen1_data_access_cmd()) break;
if(!magic_gen1_write_blk(0, &block)) break;
for(size_t i = 1; i < 64; i++) {
FURI_LOG_D(TAG, "Wiping block %d", i);
bool success = false;
if((i | 0x03) == i) {
success = magic_gen1_write_blk(i, &trailer_block);
} else {
success = magic_gen1_write_blk(i, &empty_block);
}
if(!success) {
FURI_LOG_E(TAG, "Failed to write %d block", i);
nfc_magic_worker->callback(
NfcMagicWorkerEventFail, nfc_magic_worker->context);
break;
}
}
card_wiped = true;
nfc_magic_worker->callback(NfcMagicWorkerEventSuccess, nfc_magic_worker->context);
} else if(magic_dev->type == MagicTypeGen4) {
uint32_t cuid;
if(!furi_hal_nfc_activate_nfca(200, &cuid)) break;
if(cuid != magic_dev->cuid) break;
if(!card_found_notified) {
nfc_magic_worker->callback(
NfcMagicWorkerEventCardDetected, nfc_magic_worker->context);
card_found_notified = true;
}
if(!magic_gen4_wipe(magic_dev->password)) break;
card_wiped = true;
nfc_magic_worker->callback(NfcMagicWorkerEventSuccess, nfc_magic_worker->context);
}
} while(false);
if(card_wiped) break;
if(card_found_notified) {
nfc_magic_worker->callback(
NfcMagicWorkerEventNoCardDetected, nfc_magic_worker->context);
card_found_notified = false;
}
}
magic_deactivate();
}

View File

@@ -1,42 +0,0 @@
#pragma once
#include <lib/nfc/nfc_device.h>
#include "nfc_magic.h"
typedef struct NfcMagicWorker NfcMagicWorker;
typedef enum {
NfcMagicWorkerStateReady,
NfcMagicWorkerStateCheck,
NfcMagicWorkerStateWrite,
NfcMagicWorkerStateRekey,
NfcMagicWorkerStateWipe,
NfcMagicWorkerStateStop,
} NfcMagicWorkerState;
typedef enum {
NfcMagicWorkerEventSuccess,
NfcMagicWorkerEventFail,
NfcMagicWorkerEventCardDetected,
NfcMagicWorkerEventNoCardDetected,
NfcMagicWorkerEventWrongCard,
} NfcMagicWorkerEvent;
typedef bool (*NfcMagicWorkerCallback)(NfcMagicWorkerEvent event, void* context);
NfcMagicWorker* nfc_magic_worker_alloc();
void nfc_magic_worker_free(NfcMagicWorker* nfc_magic_worker);
void nfc_magic_worker_stop(NfcMagicWorker* nfc_magic_worker);
void nfc_magic_worker_start(
NfcMagicWorker* nfc_magic_worker,
NfcMagicWorkerState state,
NfcMagicDevice* magic_dev,
NfcDeviceData* dev_data,
uint32_t new_password,
NfcMagicWorkerCallback callback,
void* context);

View File

@@ -1,29 +0,0 @@
#pragma once
#include <furi.h>
#include "nfc_magic_worker.h"
#include "lib/magic/common.h"
struct NfcMagicWorker {
FuriThread* thread;
NfcMagicDevice* magic_dev;
NfcDeviceData* dev_data;
uint32_t new_password;
NfcMagicWorkerCallback callback;
void* context;
NfcMagicWorkerState state;
};
int32_t nfc_magic_worker_task(void* context);
void nfc_magic_worker_check(NfcMagicWorker* nfc_magic_worker);
void nfc_magic_worker_write(NfcMagicWorker* nfc_magic_worker);
void nfc_magic_worker_rekey(NfcMagicWorker* nfc_magic_worker);
void nfc_magic_worker_wipe(NfcMagicWorker* nfc_magic_worker);

View File

@@ -1,50 +0,0 @@
#include "../nfc_magic_i.h"
enum SubmenuIndex {
SubmenuIndexWrite,
SubmenuIndexWipe,
};
void nfc_magic_scene_actions_submenu_callback(void* context, uint32_t index) {
NfcMagic* nfc_magic = context;
view_dispatcher_send_custom_event(nfc_magic->view_dispatcher, index);
}
void nfc_magic_scene_actions_on_enter(void* context) {
NfcMagic* nfc_magic = context;
Submenu* submenu = nfc_magic->submenu;
submenu_add_item(
submenu, "Write", SubmenuIndexWrite, nfc_magic_scene_actions_submenu_callback, nfc_magic);
submenu_add_item(
submenu, "Wipe", SubmenuIndexWipe, nfc_magic_scene_actions_submenu_callback, nfc_magic);
submenu_set_selected_item(
submenu, scene_manager_get_scene_state(nfc_magic->scene_manager, NfcMagicSceneActions));
view_dispatcher_switch_to_view(nfc_magic->view_dispatcher, NfcMagicViewMenu);
}
bool nfc_magic_scene_actions_on_event(void* context, SceneManagerEvent event) {
NfcMagic* nfc_magic = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubmenuIndexWrite) {
scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneFileSelect);
consumed = true;
} else if(event.event == SubmenuIndexWipe) {
scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneWipe);
consumed = true;
}
scene_manager_set_scene_state(nfc_magic->scene_manager, NfcMagicSceneActions, event.event);
} else if(event.type == SceneManagerEventTypeBack) {
consumed = scene_manager_search_and_switch_to_previous_scene(
nfc_magic->scene_manager, NfcMagicSceneStart);
}
return consumed;
}
void nfc_magic_scene_actions_on_exit(void* context) {
NfcMagic* nfc_magic = context;
submenu_reset(nfc_magic->submenu);
}

View File

@@ -0,0 +1,108 @@
#include "../nfc_magic_app_i.h"
enum {
NfcMagicSceneChangeKeyStateCardSearch,
NfcMagicSceneChangeKeyStateCardFound,
};
NfcCommand nfc_mafic_scene_change_key_gen4_poller_callback(Gen4PollerEvent event, void* context) {
NfcMagicApp* instance = context;
furi_assert(event.data);
NfcCommand command = NfcCommandContinue;
if(event.type == Gen4PollerEventTypeCardDetected) {
view_dispatcher_send_custom_event(
instance->view_dispatcher, NfcMagicCustomEventCardDetected);
} else if(event.type == Gen4PollerEventTypeRequestMode) {
event.data->request_mode.mode = Gen4PollerModeSetPassword;
} else if(event.type == Gen4PollerEventTypeRequestNewPassword) {
event.data->request_password.password = instance->gen4_password_new;
} else if(event.type == Gen4PollerEventTypeSuccess) {
view_dispatcher_send_custom_event(
instance->view_dispatcher, NfcMagicCustomEventWorkerSuccess);
command = NfcCommandStop;
} else if(event.type == Gen4PollerEventTypeFail) {
view_dispatcher_send_custom_event(
instance->view_dispatcher, NfcMagicCustomEventWorkerFail);
command = NfcCommandStop;
}
return command;
}
static void nfc_magic_scene_change_key_setup_view(NfcMagicApp* instance) {
Popup* popup = instance->popup;
popup_reset(popup);
uint32_t state =
scene_manager_get_scene_state(instance->scene_manager, NfcMagicSceneChangeKey);
if(state == NfcMagicSceneChangeKeyStateCardSearch) {
popup_set_icon(instance->popup, 0, 8, &I_NFC_manual_60x50);
popup_set_text(
instance->popup, "Apply the\nsame card\nto the back", 128, 32, AlignRight, AlignCenter);
} else {
popup_set_icon(popup, 12, 23, &I_Loading_24);
popup_set_header(popup, "Writing\nDon't move...", 52, 32, AlignLeft, AlignCenter);
}
view_dispatcher_switch_to_view(instance->view_dispatcher, NfcMagicAppViewPopup);
}
void nfc_magic_scene_change_key_on_enter(void* context) {
NfcMagicApp* instance = context;
scene_manager_set_scene_state(
instance->scene_manager, NfcMagicSceneChangeKey, NfcMagicSceneChangeKeyStateCardSearch);
nfc_magic_scene_change_key_setup_view(instance);
nfc_magic_app_blink_start(instance);
instance->gen4_poller = gen4_poller_alloc(instance->nfc);
gen4_poller_start(
instance->gen4_poller, nfc_mafic_scene_change_key_gen4_poller_callback, instance);
}
bool nfc_magic_scene_change_key_on_event(void* context, SceneManagerEvent event) {
NfcMagicApp* instance = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == NfcMagicCustomEventCardDetected) {
scene_manager_set_scene_state(
instance->scene_manager,
NfcMagicSceneChangeKey,
NfcMagicSceneChangeKeyStateCardFound);
nfc_magic_scene_change_key_setup_view(instance);
consumed = true;
} else if(event.event == NfcMagicCustomEventCardLost) {
scene_manager_set_scene_state(
instance->scene_manager,
NfcMagicSceneChangeKey,
NfcMagicSceneChangeKeyStateCardSearch);
nfc_magic_scene_change_key_setup_view(instance);
consumed = true;
} else if(event.event == NfcMagicCustomEventWorkerSuccess) {
scene_manager_next_scene(instance->scene_manager, NfcMagicSceneSuccess);
consumed = true;
} else if(event.event == NfcMagicCustomEventWorkerFail) {
scene_manager_next_scene(instance->scene_manager, NfcMagicSceneChangeKeyFail);
consumed = true;
}
}
return consumed;
}
void nfc_magic_scene_change_key_on_exit(void* context) {
NfcMagicApp* instance = context;
gen4_poller_stop(instance->gen4_poller);
gen4_poller_free(instance->gen4_poller);
scene_manager_set_scene_state(
instance->scene_manager, NfcMagicSceneChangeKey, NfcMagicSceneChangeKeyStateCardSearch);
// Clear view
popup_reset(instance->popup);
nfc_magic_app_blink_stop(instance);
}

View File

@@ -0,0 +1,54 @@
#include "../nfc_magic_app_i.h"
void nfc_magic_scene_change_key_fail_widget_callback(
GuiButtonType result,
InputType type,
void* context) {
NfcMagicApp* instance = context;
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(instance->view_dispatcher, result);
}
}
void nfc_magic_scene_change_key_fail_on_enter(void* context) {
NfcMagicApp* instance = context;
Widget* widget = instance->widget;
notification_message(instance->notifications, &sequence_error);
widget_add_icon_element(widget, 72, 17, &I_DolphinCommon_56x48);
widget_add_string_element(
widget, 7, 4, AlignLeft, AlignTop, FontPrimary, "Can't change password!");
widget_add_button_element(
widget,
GuiButtonTypeLeft,
"Finish",
nfc_magic_scene_change_key_fail_widget_callback,
instance);
// Setup and start worker
view_dispatcher_switch_to_view(instance->view_dispatcher, NfcMagicAppViewWidget);
}
bool nfc_magic_scene_change_key_fail_on_event(void* context, SceneManagerEvent event) {
NfcMagicApp* instance = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == GuiButtonTypeLeft) {
consumed = scene_manager_search_and_switch_to_previous_scene(
instance->scene_manager, NfcMagicSceneStart);
}
} else if(event.type == SceneManagerEventTypeBack) {
consumed = scene_manager_search_and_switch_to_previous_scene(
instance->scene_manager, NfcMagicSceneStart);
}
return consumed;
}
void nfc_magic_scene_change_key_fail_on_exit(void* context) {
NfcMagicApp* instance = context;
widget_reset(instance->widget);
}

View File

@@ -1,89 +1,54 @@
#include "../nfc_magic_i.h"
#include "../nfc_magic_app_i.h"
enum {
NfcMagicSceneCheckStateCardSearch,
NfcMagicSceneCheckStateCardFound,
};
bool nfc_magic_check_worker_callback(NfcMagicWorkerEvent event, void* context) {
void nfc_magic_check_worker_callback(NfcMagicScannerEvent event, void* context) {
furi_assert(context);
NfcMagic* nfc_magic = context;
view_dispatcher_send_custom_event(nfc_magic->view_dispatcher, event);
NfcMagicApp* instance = context;
return true;
}
static void nfc_magic_scene_check_setup_view(NfcMagic* nfc_magic) {
Popup* popup = nfc_magic->popup;
popup_reset(popup);
uint32_t state = scene_manager_get_scene_state(nfc_magic->scene_manager, NfcMagicSceneCheck);
if(state == NfcMagicSceneCheckStateCardSearch) {
popup_set_icon(nfc_magic->popup, 0, 8, &I_NFC_manual_60x50);
popup_set_text(
nfc_magic->popup, "Apply card to\nthe back", 128, 32, AlignRight, AlignCenter);
} else {
popup_set_icon(popup, 12, 23, &I_Loading_24);
popup_set_header(popup, "Checking\nDon't move...", 52, 32, AlignLeft, AlignCenter);
if(event.type == NfcMagicScannerEventTypeDetected) {
instance->protocol = event.data.protocol;
view_dispatcher_send_custom_event(
instance->view_dispatcher, NfcMagicCustomEventWorkerSuccess);
} else if(event.type == NfcMagicScannerEventTypeDetectedNotMagic) {
view_dispatcher_send_custom_event(
instance->view_dispatcher, NfcMagicCustomEventWorkerFail);
}
view_dispatcher_switch_to_view(nfc_magic->view_dispatcher, NfcMagicViewPopup);
}
void nfc_magic_scene_check_on_enter(void* context) {
NfcMagic* nfc_magic = context;
NfcMagicApp* instance = context;
scene_manager_set_scene_state(
nfc_magic->scene_manager, NfcMagicSceneCheck, NfcMagicSceneCheckStateCardSearch);
nfc_magic_scene_check_setup_view(nfc_magic);
popup_set_icon(instance->popup, 0, 8, &I_NFC_manual_60x50);
popup_set_text(instance->popup, "Apply card to\nthe back", 128, 32, AlignRight, AlignCenter);
// Setup and start worker
nfc_magic_worker_start(
nfc_magic->worker,
NfcMagicWorkerStateCheck,
nfc_magic->dev,
&nfc_magic->source_dev->dev_data,
nfc_magic->new_password,
nfc_magic_check_worker_callback,
nfc_magic);
nfc_magic_blink_start(nfc_magic);
nfc_magic_app_blink_start(instance);
nfc_magic_scanner_start(instance->scanner, nfc_magic_check_worker_callback, instance);
view_dispatcher_switch_to_view(instance->view_dispatcher, NfcMagicAppViewPopup);
}
bool nfc_magic_scene_check_on_event(void* context, SceneManagerEvent event) {
NfcMagic* nfc_magic = context;
NfcMagicApp* instance = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == NfcMagicWorkerEventSuccess) {
scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneMagicInfo);
if(event.event == NfcMagicCustomEventWorkerSuccess) {
scene_manager_next_scene(instance->scene_manager, NfcMagicSceneMagicInfo);
consumed = true;
} else if(event.event == NfcMagicWorkerEventWrongCard) {
scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneNotMagic);
consumed = true;
} else if(event.event == NfcMagicWorkerEventCardDetected) {
scene_manager_set_scene_state(
nfc_magic->scene_manager, NfcMagicSceneCheck, NfcMagicSceneCheckStateCardFound);
nfc_magic_scene_check_setup_view(nfc_magic);
consumed = true;
} else if(event.event == NfcMagicWorkerEventNoCardDetected) {
scene_manager_set_scene_state(
nfc_magic->scene_manager, NfcMagicSceneCheck, NfcMagicSceneCheckStateCardSearch);
nfc_magic_scene_check_setup_view(nfc_magic);
} else if(event.event == NfcMagicCustomEventWorkerFail) {
scene_manager_next_scene(instance->scene_manager, NfcMagicSceneNotMagic);
consumed = true;
}
}
return consumed;
}
void nfc_magic_scene_check_on_exit(void* context) {
NfcMagic* nfc_magic = context;
NfcMagicApp* instance = context;
nfc_magic_worker_stop(nfc_magic->worker);
scene_manager_set_scene_state(
nfc_magic->scene_manager, NfcMagicSceneCheck, NfcMagicSceneCheckStateCardSearch);
// Clear view
popup_reset(nfc_magic->popup);
nfc_magic_blink_stop(nfc_magic);
nfc_magic_scanner_stop(instance->scanner);
popup_reset(instance->popup);
nfc_magic_app_blink_stop(instance);
}

View File

@@ -1,18 +1,17 @@
ADD_SCENE(nfc_magic, start, Start)
ADD_SCENE(nfc_magic, key_input, KeyInput)
ADD_SCENE(nfc_magic, actions, Actions)
ADD_SCENE(nfc_magic, gen4_actions, Gen4Actions)
ADD_SCENE(nfc_magic, new_key_input, NewKeyInput)
ADD_SCENE(nfc_magic, file_select, FileSelect)
ADD_SCENE(nfc_magic, write_confirm, WriteConfirm)
ADD_SCENE(nfc_magic, wrong_card, WrongCard)
ADD_SCENE(nfc_magic, write, Write)
ADD_SCENE(nfc_magic, write_fail, WriteFail)
ADD_SCENE(nfc_magic, success, Success)
ADD_SCENE(nfc_magic, check, Check)
ADD_SCENE(nfc_magic, not_magic, NotMagic)
ADD_SCENE(nfc_magic, key_input, KeyInput)
ADD_SCENE(nfc_magic, magic_info, MagicInfo)
ADD_SCENE(nfc_magic, rekey, Rekey)
ADD_SCENE(nfc_magic, rekey_fail, RekeyFail)
ADD_SCENE(nfc_magic, gen1_menu, Gen1Menu)
ADD_SCENE(nfc_magic, gen4_menu, Gen4Menu)
ADD_SCENE(nfc_magic, wipe, Wipe)
ADD_SCENE(nfc_magic, wipe_fail, WipeFail)
ADD_SCENE(nfc_magic, success, Success)
ADD_SCENE(nfc_magic, file_select, FileSelect)
ADD_SCENE(nfc_magic, write_confirm, WriteConfirm)
ADD_SCENE(nfc_magic, write, Write)
ADD_SCENE(nfc_magic, write_fail, WriteFail)
ADD_SCENE(nfc_magic, change_key, ChangeKey)
ADD_SCENE(nfc_magic, change_key_fail, ChangeKeyFail)
ADD_SCENE(nfc_magic, wrong_card, WrongCard)
ADD_SCENE(nfc_magic, not_magic, NotMagic)

View File

@@ -1,66 +1,51 @@
#include "../nfc_magic_i.h"
#include "../nfc_magic_app_i.h"
#include <nfc/protocols/mf_classic/mf_classic.h>
static bool nfc_magic_scene_file_select_is_file_suitable(NfcMagic* nfc_magic) {
NfcDevice* nfc_dev = nfc_magic->source_dev;
if(nfc_dev->format == NfcDeviceSaveFormatMifareClassic) {
switch(nfc_magic->dev->type) {
case MagicTypeClassicGen1:
case MagicTypeClassicDirectWrite:
case MagicTypeClassicAPDU:
if((nfc_dev->dev_data.mf_classic_data.type != MfClassicType1k) ||
(nfc_dev->dev_data.nfc_data.uid_len != nfc_magic->dev->uid_len)) {
return false;
static bool nfc_magic_scene_file_select_is_file_suitable(NfcMagicApp* instance) {
NfcProtocol protocol = nfc_device_get_protocol(instance->source_dev);
size_t uid_len = 0;
nfc_device_get_uid(instance->source_dev, &uid_len);
bool suitable = false;
if(instance->protocol == NfcMagicProtocolGen1) {
if((uid_len == 4) && (protocol == NfcProtocolMfClassic)) {
const MfClassicData* mfc_data =
nfc_device_get_data(instance->source_dev, NfcProtocolMfClassic);
if(mfc_data->type == MfClassicType1k) {
suitable = true;
}
return true;
case MagicTypeGen4:
return true;
default:
return false;
}
} else if(
(nfc_dev->format == NfcDeviceSaveFormatMifareUl) &&
(nfc_dev->dev_data.nfc_data.uid_len == 7)) {
switch(nfc_magic->dev->type) {
case MagicTypeUltralightGen1:
case MagicTypeUltralightDirectWrite:
case MagicTypeUltralightC_Gen1:
case MagicTypeUltralightC_DirectWrite:
case MagicTypeGen4:
switch(nfc_dev->dev_data.mf_ul_data.type) {
case MfUltralightTypeNTAGI2C1K:
case MfUltralightTypeNTAGI2C2K:
case MfUltralightTypeNTAGI2CPlus1K:
case MfUltralightTypeNTAGI2CPlus2K:
return false;
default:
return true;
} else if(instance->protocol == NfcMagicProtocolGen4) {
if(protocol == NfcProtocolMfClassic) {
suitable = true;
} else if(protocol == NfcProtocolMfUltralight) {
const MfUltralightData* mfu_data =
nfc_device_get_data(instance->source_dev, NfcProtocolMfUltralight);
const Iso14443_3aData* iso3_data = mfu_data->iso14443_3a_data;
if(iso3_data->uid_len == 7) {
MfUltralightType mfu_type = mfu_data->type;
suitable = (mfu_type != MfUltralightTypeNTAGI2C1K) &&
(mfu_type != MfUltralightTypeNTAGI2C2K) &&
(mfu_type != MfUltralightTypeNTAGI2CPlus1K) &&
(mfu_type != MfUltralightTypeNTAGI2CPlus2K);
}
default:
return false;
}
}
return false;
return suitable;
}
void nfc_magic_scene_file_select_on_enter(void* context) {
NfcMagic* nfc_magic = context;
// Process file_select return
nfc_device_set_loading_callback(
nfc_magic->source_dev, nfc_magic_show_loading_popup, nfc_magic);
NfcMagicApp* instance = context;
if(!furi_string_size(nfc_magic->source_dev->load_path)) {
furi_string_set_str(nfc_magic->source_dev->load_path, NFC_APP_FOLDER);
}
if(nfc_file_select(nfc_magic->source_dev)) {
if(nfc_magic_scene_file_select_is_file_suitable(nfc_magic)) {
scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneWriteConfirm);
if(nfc_magic_load_from_file_select(instance)) {
if(nfc_magic_scene_file_select_is_file_suitable(instance)) {
scene_manager_next_scene(instance->scene_manager, NfcMagicSceneWriteConfirm);
} else {
scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneWrongCard);
scene_manager_next_scene(instance->scene_manager, NfcMagicSceneWrongCard);
}
} else {
scene_manager_previous_scene(nfc_magic->scene_manager);
scene_manager_previous_scene(instance->scene_manager);
}
}
@@ -71,6 +56,5 @@ bool nfc_magic_scene_file_select_on_event(void* context, SceneManagerEvent event
}
void nfc_magic_scene_file_select_on_exit(void* context) {
NfcMagic* nfc_magic = context;
nfc_device_set_loading_callback(nfc_magic->source_dev, NULL, nfc_magic);
UNUSED(context);
}

View File

@@ -0,0 +1,53 @@
#include "../nfc_magic_app_i.h"
enum SubmenuIndex {
SubmenuIndexWrite,
SubmenuIndexWipe,
};
void nfc_magic_scene_gen1_menu_submenu_callback(void* context, uint32_t index) {
NfcMagicApp* instance = context;
view_dispatcher_send_custom_event(instance->view_dispatcher, index);
}
void nfc_magic_scene_gen1_menu_on_enter(void* context) {
NfcMagicApp* instance = context;
Submenu* submenu = instance->submenu;
submenu_add_item(
submenu, "Write", SubmenuIndexWrite, nfc_magic_scene_gen1_menu_submenu_callback, instance);
submenu_add_item(
submenu, "Wipe", SubmenuIndexWipe, nfc_magic_scene_gen1_menu_submenu_callback, instance);
submenu_set_selected_item(
submenu, scene_manager_get_scene_state(instance->scene_manager, NfcMagicSceneGen4Menu));
view_dispatcher_switch_to_view(instance->view_dispatcher, NfcMagicAppViewMenu);
}
bool nfc_magic_scene_gen1_menu_on_event(void* context, SceneManagerEvent event) {
NfcMagicApp* instance = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubmenuIndexWrite) {
scene_manager_next_scene(instance->scene_manager, NfcMagicSceneFileSelect);
consumed = true;
} else if(event.event == SubmenuIndexWipe) {
scene_manager_next_scene(instance->scene_manager, NfcMagicSceneWipe);
consumed = true;
}
scene_manager_set_scene_state(instance->scene_manager, NfcMagicSceneGen4Menu, event.event);
} else if(event.type == SceneManagerEventTypeBack) {
consumed = scene_manager_search_and_switch_to_previous_scene(
instance->scene_manager, NfcMagicSceneStart);
}
return consumed;
}
void nfc_magic_scene_gen1_menu_on_exit(void* context) {
NfcMagicApp* instance = context;
submenu_reset(instance->submenu);
}

View File

@@ -1,70 +0,0 @@
#include "../nfc_magic_i.h"
enum SubmenuIndex {
SubmenuIndexWrite,
SubmenuIndexChangePassword,
SubmenuIndexWipe,
};
void nfc_magic_scene_gen4_actions_submenu_callback(void* context, uint32_t index) {
NfcMagic* nfc_magic = context;
view_dispatcher_send_custom_event(nfc_magic->view_dispatcher, index);
}
void nfc_magic_scene_gen4_actions_on_enter(void* context) {
NfcMagic* nfc_magic = context;
Submenu* submenu = nfc_magic->submenu;
submenu_add_item(
submenu,
"Write",
SubmenuIndexWrite,
nfc_magic_scene_gen4_actions_submenu_callback,
nfc_magic);
submenu_add_item(
submenu,
"Change password",
SubmenuIndexChangePassword,
nfc_magic_scene_gen4_actions_submenu_callback,
nfc_magic);
submenu_add_item(
submenu,
"Wipe",
SubmenuIndexWipe,
nfc_magic_scene_gen4_actions_submenu_callback,
nfc_magic);
submenu_set_selected_item(
submenu,
scene_manager_get_scene_state(nfc_magic->scene_manager, NfcMagicSceneGen4Actions));
view_dispatcher_switch_to_view(nfc_magic->view_dispatcher, NfcMagicViewMenu);
}
bool nfc_magic_scene_gen4_actions_on_event(void* context, SceneManagerEvent event) {
NfcMagic* nfc_magic = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubmenuIndexWrite) {
scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneFileSelect);
consumed = true;
} else if(event.event == SubmenuIndexChangePassword) {
scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneNewKeyInput);
consumed = true;
} else if(event.event == SubmenuIndexWipe) {
scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneWipe);
consumed = true;
}
scene_manager_set_scene_state(
nfc_magic->scene_manager, NfcMagicSceneGen4Actions, event.event);
} else if(event.type == SceneManagerEventTypeBack) {
consumed = scene_manager_search_and_switch_to_previous_scene(
nfc_magic->scene_manager, NfcMagicSceneStart);
}
return consumed;
}
void nfc_magic_scene_gen4_actions_on_exit(void* context) {
NfcMagic* nfc_magic = context;
submenu_reset(nfc_magic->submenu);
}

View File

@@ -0,0 +1,63 @@
#include "../nfc_magic_app_i.h"
enum SubmenuIndex {
SubmenuIndexWrite,
SubmenuIndexChangePassword,
SubmenuIndexWipe,
};
void nfc_magic_scene_gen4_menu_submenu_callback(void* context, uint32_t index) {
NfcMagicApp* instance = context;
view_dispatcher_send_custom_event(instance->view_dispatcher, index);
}
void nfc_magic_scene_gen4_menu_on_enter(void* context) {
NfcMagicApp* instance = context;
Submenu* submenu = instance->submenu;
submenu_add_item(
submenu, "Write", SubmenuIndexWrite, nfc_magic_scene_gen4_menu_submenu_callback, instance);
submenu_add_item(
submenu,
"Change password",
SubmenuIndexChangePassword,
nfc_magic_scene_gen4_menu_submenu_callback,
instance);
submenu_add_item(
submenu, "Wipe", SubmenuIndexWipe, nfc_magic_scene_gen4_menu_submenu_callback, instance);
submenu_set_selected_item(
submenu, scene_manager_get_scene_state(instance->scene_manager, NfcMagicSceneGen4Menu));
view_dispatcher_switch_to_view(instance->view_dispatcher, NfcMagicAppViewMenu);
}
bool nfc_magic_scene_gen4_menu_on_event(void* context, SceneManagerEvent event) {
NfcMagicApp* instance = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubmenuIndexWrite) {
scene_manager_next_scene(instance->scene_manager, NfcMagicSceneFileSelect);
consumed = true;
} else if(event.event == SubmenuIndexChangePassword) {
scene_manager_next_scene(instance->scene_manager, NfcMagicSceneKeyInput);
consumed = true;
} else if(event.event == SubmenuIndexWipe) {
scene_manager_next_scene(instance->scene_manager, NfcMagicSceneWipe);
consumed = true;
}
scene_manager_set_scene_state(instance->scene_manager, NfcMagicSceneGen4Menu, event.event);
} else if(event.type == SceneManagerEventTypeBack) {
consumed = scene_manager_search_and_switch_to_previous_scene(
instance->scene_manager, NfcMagicSceneStart);
}
return consumed;
}
void nfc_magic_scene_gen4_menu_on_exit(void* context) {
NfcMagicApp* instance = context;
submenu_reset(instance->submenu);
}

View File

@@ -1,35 +1,45 @@
#include "../nfc_magic_i.h"
#include "../nfc_magic_app_i.h"
#include <nfc/helpers/nfc_util.h>
void nfc_magic_scene_key_input_byte_input_callback(void* context) {
NfcMagic* nfc_magic = context;
NfcMagicApp* instance = context;
view_dispatcher_send_custom_event(
nfc_magic->view_dispatcher, NfcMagicCustomEventByteInputDone);
instance->view_dispatcher, NfcMagicAppCustomEventByteInputDone);
}
void nfc_magic_scene_key_input_on_enter(void* context) {
NfcMagic* nfc_magic = context;
NfcMagicApp* instance = context;
// Setup view
ByteInput* byte_input = nfc_magic->byte_input;
ByteInput* byte_input = instance->byte_input;
byte_input_set_header_text(byte_input, "Enter the password in hex");
byte_input_set_result_callback(
byte_input,
nfc_magic_scene_key_input_byte_input_callback,
NULL,
nfc_magic,
(uint8_t*)&nfc_magic->dev->password,
4);
view_dispatcher_switch_to_view(nfc_magic->view_dispatcher, NfcMagicViewByteInput);
instance,
instance->byte_input_store,
NFC_MAGIC_APP_BYTE_INPUT_STORE_SIZE);
view_dispatcher_switch_to_view(instance->view_dispatcher, NfcMagicAppViewByteInput);
}
bool nfc_magic_scene_key_input_on_event(void* context, SceneManagerEvent event) {
NfcMagic* nfc_magic = context;
NfcMagicApp* instance = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == NfcMagicCustomEventByteInputDone) {
scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneCheck);
if(event.event == NfcMagicAppCustomEventByteInputDone) {
if(scene_manager_has_previous_scene(instance->scene_manager, NfcMagicSceneGen4Menu)) {
instance->gen4_password_new = nfc_util_bytes2num(
instance->byte_input_store, NFC_MAGIC_APP_BYTE_INPUT_STORE_SIZE);
scene_manager_next_scene(instance->scene_manager, NfcMagicSceneChangeKey);
} else {
instance->gen4_password = nfc_util_bytes2num(
instance->byte_input_store, NFC_MAGIC_APP_BYTE_INPUT_STORE_SIZE);
scene_manager_next_scene(instance->scene_manager, NfcMagicSceneCheck);
}
consumed = true;
}
}
@@ -37,9 +47,9 @@ bool nfc_magic_scene_key_input_on_event(void* context, SceneManagerEvent event)
}
void nfc_magic_scene_key_input_on_exit(void* context) {
NfcMagic* nfc_magic = context;
NfcMagicApp* instance = context;
// Clear view
byte_input_set_result_callback(nfc_magic->byte_input, NULL, NULL, NULL, NULL, 0);
byte_input_set_header_text(nfc_magic->byte_input, "");
byte_input_set_result_callback(instance->byte_input, NULL, NULL, NULL, NULL, 0);
byte_input_set_header_text(instance->byte_input, "");
}

View File

@@ -1,50 +1,54 @@
#include "../nfc_magic_i.h"
#include "../lib/magic/types.h"
#include "../nfc_magic_app_i.h"
void nfc_magic_scene_magic_info_widget_callback(
GuiButtonType result,
InputType type,
void* context) {
NfcMagic* nfc_magic = context;
NfcMagicApp* instance = context;
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(nfc_magic->view_dispatcher, result);
view_dispatcher_send_custom_event(instance->view_dispatcher, result);
}
}
void nfc_magic_scene_magic_info_on_enter(void* context) {
NfcMagic* nfc_magic = context;
Widget* widget = nfc_magic->widget;
const char* card_type = nfc_magic_type(nfc_magic->dev->type);
NfcMagicApp* instance = context;
Widget* widget = instance->widget;
notification_message(nfc_magic->notifications, &sequence_success);
notification_message(instance->notifications, &sequence_success);
widget_add_icon_element(widget, 73, 17, &I_DolphinCommon_56x48);
widget_add_string_element(
widget, 3, 4, AlignLeft, AlignTop, FontPrimary, "Magic card detected");
widget_add_string_element(widget, 3, 17, AlignLeft, AlignTop, FontSecondary, card_type);
widget_add_string_element(
widget,
3,
17,
AlignLeft,
AlignTop,
FontSecondary,
nfc_magic_protocols_get_name(instance->protocol));
widget_add_button_element(
widget, GuiButtonTypeLeft, "Retry", nfc_magic_scene_magic_info_widget_callback, nfc_magic);
widget, GuiButtonTypeLeft, "Retry", nfc_magic_scene_magic_info_widget_callback, instance);
widget_add_button_element(
widget, GuiButtonTypeRight, "More", nfc_magic_scene_magic_info_widget_callback, nfc_magic);
widget, GuiButtonTypeRight, "More", nfc_magic_scene_magic_info_widget_callback, instance);
// Setup and start worker
view_dispatcher_switch_to_view(nfc_magic->view_dispatcher, NfcMagicViewWidget);
view_dispatcher_switch_to_view(instance->view_dispatcher, NfcMagicAppViewWidget);
}
bool nfc_magic_scene_magic_info_on_event(void* context, SceneManagerEvent event) {
NfcMagic* nfc_magic = context;
NfcMagicApp* instance = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == GuiButtonTypeLeft) {
consumed = scene_manager_previous_scene(nfc_magic->scene_manager);
consumed = scene_manager_previous_scene(instance->scene_manager);
} else if(event.event == GuiButtonTypeRight) {
MagicType type = nfc_magic->dev->type;
if(type == MagicTypeGen4) {
scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneGen4Actions);
if(instance->protocol == NfcMagicProtocolGen1) {
scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen1Menu);
consumed = true;
} else {
scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneActions);
scene_manager_next_scene(instance->scene_manager, NfcMagicSceneGen4Menu);
consumed = true;
}
}
@@ -53,7 +57,7 @@ bool nfc_magic_scene_magic_info_on_event(void* context, SceneManagerEvent event)
}
void nfc_magic_scene_magic_info_on_exit(void* context) {
NfcMagic* nfc_magic = context;
NfcMagicApp* instance = context;
widget_reset(nfc_magic->widget);
widget_reset(instance->widget);
}

View File

@@ -1,45 +0,0 @@
#include "../nfc_magic_i.h"
void nfc_magic_scene_new_key_input_byte_input_callback(void* context) {
NfcMagic* nfc_magic = context;
view_dispatcher_send_custom_event(
nfc_magic->view_dispatcher, NfcMagicCustomEventByteInputDone);
}
void nfc_magic_scene_new_key_input_on_enter(void* context) {
NfcMagic* nfc_magic = context;
// Setup view
ByteInput* byte_input = nfc_magic->byte_input;
byte_input_set_header_text(byte_input, "Enter the password in hex");
byte_input_set_result_callback(
byte_input,
nfc_magic_scene_new_key_input_byte_input_callback,
NULL,
nfc_magic,
(uint8_t*)&nfc_magic->new_password,
4);
view_dispatcher_switch_to_view(nfc_magic->view_dispatcher, NfcMagicViewByteInput);
}
bool nfc_magic_scene_new_key_input_on_event(void* context, SceneManagerEvent event) {
NfcMagic* nfc_magic = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == NfcMagicCustomEventByteInputDone) {
scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneRekey);
consumed = true;
}
}
return consumed;
}
void nfc_magic_scene_new_key_input_on_exit(void* context) {
NfcMagic* nfc_magic = context;
// Clear view
byte_input_set_result_callback(nfc_magic->byte_input, NULL, NULL, NULL, NULL, 0);
byte_input_set_header_text(nfc_magic->byte_input, "");
}

View File

@@ -1,43 +1,43 @@
#include "../nfc_magic_i.h"
#include "../nfc_magic_app_i.h"
void nfc_magic_scene_not_magic_widget_callback(GuiButtonType result, InputType type, void* context) {
NfcMagic* nfc_magic = context;
NfcMagicApp* instance = context;
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(nfc_magic->view_dispatcher, result);
view_dispatcher_send_custom_event(instance->view_dispatcher, result);
}
}
void nfc_magic_scene_not_magic_on_enter(void* context) {
NfcMagic* nfc_magic = context;
Widget* widget = nfc_magic->widget;
NfcMagicApp* instance = context;
Widget* widget = instance->widget;
notification_message(nfc_magic->notifications, &sequence_error);
notification_message(instance->notifications, &sequence_error);
widget_add_string_element(
widget, 3, 4, AlignLeft, AlignTop, FontPrimary, "This is wrong card");
widget_add_string_multiline_element(
widget, 4, 17, AlignLeft, AlignTop, FontSecondary, "Not magic or unsupported\ncard");
widget_add_button_element(
widget, GuiButtonTypeLeft, "Retry", nfc_magic_scene_not_magic_widget_callback, nfc_magic);
widget, GuiButtonTypeLeft, "Retry", nfc_magic_scene_not_magic_widget_callback, instance);
// Setup and start worker
view_dispatcher_switch_to_view(nfc_magic->view_dispatcher, NfcMagicViewWidget);
view_dispatcher_switch_to_view(instance->view_dispatcher, NfcMagicAppViewWidget);
}
bool nfc_magic_scene_not_magic_on_event(void* context, SceneManagerEvent event) {
NfcMagic* nfc_magic = context;
NfcMagicApp* instance = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == GuiButtonTypeLeft) {
consumed = scene_manager_previous_scene(nfc_magic->scene_manager);
consumed = scene_manager_previous_scene(instance->scene_manager);
}
}
return consumed;
}
void nfc_magic_scene_not_magic_on_exit(void* context) {
NfcMagic* nfc_magic = context;
NfcMagicApp* instance = context;
widget_reset(nfc_magic->widget);
widget_reset(instance->widget);
}

View File

@@ -1,95 +0,0 @@
#include "../nfc_magic_i.h"
enum {
NfcMagicSceneRekeyStateCardSearch,
NfcMagicSceneRekeyStateCardFound,
};
bool nfc_magic_rekey_worker_callback(NfcMagicWorkerEvent event, void* context) {
furi_assert(context);
NfcMagic* nfc_magic = context;
view_dispatcher_send_custom_event(nfc_magic->view_dispatcher, event);
return true;
}
static void nfc_magic_scene_rekey_setup_view(NfcMagic* nfc_magic) {
Popup* popup = nfc_magic->popup;
popup_reset(popup);
uint32_t state = scene_manager_get_scene_state(nfc_magic->scene_manager, NfcMagicSceneRekey);
if(state == NfcMagicSceneRekeyStateCardSearch) {
popup_set_text(
nfc_magic->popup,
"Apply the\nsame card\nto the back",
128,
32,
AlignRight,
AlignCenter);
popup_set_icon(nfc_magic->popup, 0, 8, &I_NFC_manual_60x50);
} else {
popup_set_icon(popup, 12, 23, &I_Loading_24);
popup_set_header(popup, "Writing\nDon't move...", 52, 32, AlignLeft, AlignCenter);
}
view_dispatcher_switch_to_view(nfc_magic->view_dispatcher, NfcMagicViewPopup);
}
void nfc_magic_scene_rekey_on_enter(void* context) {
NfcMagic* nfc_magic = context;
scene_manager_set_scene_state(
nfc_magic->scene_manager, NfcMagicSceneRekey, NfcMagicSceneRekeyStateCardSearch);
nfc_magic_scene_rekey_setup_view(nfc_magic);
// Setup and start worker
nfc_magic_worker_start(
nfc_magic->worker,
NfcMagicWorkerStateRekey,
nfc_magic->dev,
&nfc_magic->source_dev->dev_data,
nfc_magic->new_password,
nfc_magic_rekey_worker_callback,
nfc_magic);
nfc_magic_blink_start(nfc_magic);
}
bool nfc_magic_scene_rekey_on_event(void* context, SceneManagerEvent event) {
NfcMagic* nfc_magic = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == NfcMagicWorkerEventSuccess) {
nfc_magic->dev->password = nfc_magic->new_password;
scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneSuccess);
consumed = true;
} else if(event.event == NfcMagicWorkerEventFail) {
scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneRekeyFail);
consumed = true;
} else if(event.event == NfcMagicWorkerEventCardDetected) {
scene_manager_set_scene_state(
nfc_magic->scene_manager, NfcMagicSceneRekey, NfcMagicSceneRekeyStateCardFound);
nfc_magic_scene_rekey_setup_view(nfc_magic);
consumed = true;
} else if(event.event == NfcMagicWorkerEventNoCardDetected) {
scene_manager_set_scene_state(
nfc_magic->scene_manager, NfcMagicSceneRekey, NfcMagicSceneRekeyStateCardSearch);
nfc_magic_scene_rekey_setup_view(nfc_magic);
consumed = true;
}
}
return consumed;
}
void nfc_magic_scene_rekey_on_exit(void* context) {
NfcMagic* nfc_magic = context;
nfc_magic_worker_stop(nfc_magic->worker);
scene_manager_set_scene_state(
nfc_magic->scene_manager, NfcMagicSceneRekey, NfcMagicSceneRekeyStateCardSearch);
// Clear view
popup_reset(nfc_magic->popup);
nfc_magic_blink_stop(nfc_magic);
}

View File

@@ -1,50 +0,0 @@
#include "../nfc_magic_i.h"
void nfc_magic_scene_rekey_fail_widget_callback(
GuiButtonType result,
InputType type,
void* context) {
NfcMagic* nfc_magic = context;
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(nfc_magic->view_dispatcher, result);
}
}
void nfc_magic_scene_rekey_fail_on_enter(void* context) {
NfcMagic* nfc_magic = context;
Widget* widget = nfc_magic->widget;
notification_message(nfc_magic->notifications, &sequence_error);
widget_add_icon_element(widget, 72, 17, &I_DolphinCommon_56x48);
widget_add_string_element(
widget, 7, 4, AlignLeft, AlignTop, FontPrimary, "Can't change password!");
widget_add_button_element(
widget, GuiButtonTypeLeft, "Finish", nfc_magic_scene_rekey_fail_widget_callback, nfc_magic);
// Setup and start worker
view_dispatcher_switch_to_view(nfc_magic->view_dispatcher, NfcMagicViewWidget);
}
bool nfc_magic_scene_rekey_fail_on_event(void* context, SceneManagerEvent event) {
NfcMagic* nfc_magic = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == GuiButtonTypeLeft) {
consumed = scene_manager_search_and_switch_to_previous_scene(
nfc_magic->scene_manager, NfcMagicSceneStart);
}
} else if(event.type == SceneManagerEventTypeBack) {
consumed = scene_manager_search_and_switch_to_previous_scene(
nfc_magic->scene_manager, NfcMagicSceneStart);
}
return consumed;
}
void nfc_magic_scene_rekey_fail_on_exit(void* context) {
NfcMagic* nfc_magic = context;
widget_reset(nfc_magic->widget);
}

View File

@@ -1,49 +1,51 @@
#include "../nfc_magic_i.h"
#include "../nfc_magic_app_i.h"
enum SubmenuIndex {
SubmenuIndexCheck,
SubmenuIndexAuthenticateGen4,
};
void nfc_magic_scene_start_submenu_callback(void* context, uint32_t index) {
NfcMagic* nfc_magic = context;
view_dispatcher_send_custom_event(nfc_magic->view_dispatcher, index);
NfcMagicApp* instance = context;
view_dispatcher_send_custom_event(instance->view_dispatcher, index);
}
void nfc_magic_scene_start_on_enter(void* context) {
NfcMagic* nfc_magic = context;
NfcMagicApp* instance = context;
Submenu* submenu = nfc_magic->submenu;
Submenu* submenu = instance->submenu;
submenu_add_item(
submenu,
"Check Magic Tag",
SubmenuIndexCheck,
nfc_magic_scene_start_submenu_callback,
nfc_magic);
instance);
submenu_add_item(
submenu,
"Authenticate Gen4",
SubmenuIndexAuthenticateGen4,
nfc_magic_scene_start_submenu_callback,
nfc_magic);
instance);
instance->gen4_password = 0;
submenu_set_selected_item(
submenu, scene_manager_get_scene_state(nfc_magic->scene_manager, NfcMagicSceneStart));
view_dispatcher_switch_to_view(nfc_magic->view_dispatcher, NfcMagicViewMenu);
submenu, scene_manager_get_scene_state(instance->scene_manager, NfcMagicSceneStart));
view_dispatcher_switch_to_view(instance->view_dispatcher, NfcMagicAppViewMenu);
}
bool nfc_magic_scene_start_on_event(void* context, SceneManagerEvent event) {
NfcMagic* nfc_magic = context;
NfcMagicApp* instance = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubmenuIndexCheck) {
nfc_magic->dev->password = MAGIC_GEN4_DEFAULT_PWD;
scene_manager_set_scene_state(
nfc_magic->scene_manager, NfcMagicSceneStart, SubmenuIndexCheck);
scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneCheck);
instance->scene_manager, NfcMagicSceneStart, SubmenuIndexCheck);
scene_manager_next_scene(instance->scene_manager, NfcMagicSceneCheck);
consumed = true;
} else if(event.event == SubmenuIndexAuthenticateGen4) {
scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneKeyInput);
scene_manager_next_scene(instance->scene_manager, NfcMagicSceneKeyInput);
}
}
@@ -51,6 +53,7 @@ bool nfc_magic_scene_start_on_event(void* context, SceneManagerEvent event) {
}
void nfc_magic_scene_start_on_exit(void* context) {
NfcMagic* nfc_magic = context;
submenu_reset(nfc_magic->submenu);
NfcMagicApp* instance = context;
submenu_reset(instance->submenu);
}

View File

@@ -1,42 +1,42 @@
#include "../nfc_magic_i.h"
#include "../nfc_magic_app_i.h"
void nfc_magic_scene_success_popup_callback(void* context) {
NfcMagic* nfc_magic = context;
view_dispatcher_send_custom_event(nfc_magic->view_dispatcher, NfcMagicCustomEventViewExit);
NfcMagicApp* instance = context;
view_dispatcher_send_custom_event(instance->view_dispatcher, NfcMagicAppCustomEventViewExit);
}
void nfc_magic_scene_success_on_enter(void* context) {
NfcMagic* nfc_magic = context;
NfcMagicApp* instance = context;
notification_message(nfc_magic->notifications, &sequence_success);
notification_message(instance->notifications, &sequence_success);
Popup* popup = nfc_magic->popup;
Popup* popup = instance->popup;
popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59);
popup_set_header(popup, "Success!", 10, 20, AlignLeft, AlignBottom);
popup_set_timeout(popup, 1500);
popup_set_context(popup, nfc_magic);
popup_set_context(popup, instance);
popup_set_callback(popup, nfc_magic_scene_success_popup_callback);
popup_enable_timeout(popup);
view_dispatcher_switch_to_view(nfc_magic->view_dispatcher, NfcMagicViewPopup);
view_dispatcher_switch_to_view(instance->view_dispatcher, NfcMagicAppViewPopup);
}
bool nfc_magic_scene_success_on_event(void* context, SceneManagerEvent event) {
NfcMagic* nfc_magic = context;
NfcMagicApp* instance = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == NfcMagicCustomEventViewExit) {
if(event.event == NfcMagicAppCustomEventViewExit) {
consumed = scene_manager_search_and_switch_to_previous_scene(
nfc_magic->scene_manager, NfcMagicSceneStart);
instance->scene_manager, NfcMagicSceneStart);
}
}
return consumed;
}
void nfc_magic_scene_success_on_exit(void* context) {
NfcMagic* nfc_magic = context;
NfcMagicApp* instance = context;
// Clear view
popup_reset(nfc_magic->popup);
popup_reset(instance->popup);
}

View File

@@ -1,97 +1,136 @@
#include "../nfc_magic_i.h"
#include "../nfc_magic_app_i.h"
enum {
NfcMagicSceneWipeStateCardSearch,
NfcMagicSceneWipeStateCardFound,
};
bool nfc_magic_wipe_worker_callback(NfcMagicWorkerEvent event, void* context) {
furi_assert(context);
NfcCommand nfc_mafic_scene_wipe_gen1_poller_callback(Gen1aPollerEvent event, void* context) {
NfcMagicApp* instance = context;
furi_assert(event.data);
NfcMagic* nfc_magic = context;
view_dispatcher_send_custom_event(nfc_magic->view_dispatcher, event);
NfcCommand command = NfcCommandContinue;
return true;
if(event.type == Gen1aPollerEventTypeDetected) {
view_dispatcher_send_custom_event(
instance->view_dispatcher, NfcMagicCustomEventCardDetected);
} else if(event.type == Gen1aPollerEventTypeRequestMode) {
event.data->request_mode.mode = Gen1aPollerModeWipe;
} else if(event.type == Gen1aPollerEventTypeSuccess) {
view_dispatcher_send_custom_event(
instance->view_dispatcher, NfcMagicCustomEventWorkerSuccess);
command = NfcCommandStop;
} else if(event.type == Gen1aPollerEventTypeFail) {
view_dispatcher_send_custom_event(
instance->view_dispatcher, NfcMagicCustomEventWorkerFail);
command = NfcCommandStop;
}
return command;
}
static void nfc_magic_scene_wipe_setup_view(NfcMagic* nfc_magic) {
Popup* popup = nfc_magic->popup;
NfcCommand nfc_mafic_scene_wipe_gen4_poller_callback(Gen4PollerEvent event, void* context) {
NfcMagicApp* instance = context;
NfcCommand command = NfcCommandContinue;
if(event.type == Gen4PollerEventTypeCardDetected) {
view_dispatcher_send_custom_event(
instance->view_dispatcher, NfcMagicCustomEventCardDetected);
} else if(event.type == Gen4PollerEventTypeRequestMode) {
event.data->request_mode.mode = Gen4PollerModeWipe;
} else if(event.type == Gen4PollerEventTypeSuccess) {
view_dispatcher_send_custom_event(
instance->view_dispatcher, NfcMagicCustomEventWorkerSuccess);
command = NfcCommandStop;
} else if(event.type == Gen4PollerEventTypeFail) {
view_dispatcher_send_custom_event(
instance->view_dispatcher, NfcMagicCustomEventWorkerFail);
command = NfcCommandStop;
}
return command;
}
static void nfc_magic_scene_wipe_setup_view(NfcMagicApp* instance) {
Popup* popup = instance->popup;
popup_reset(popup);
uint32_t state = scene_manager_get_scene_state(nfc_magic->scene_manager, NfcMagicSceneWipe);
uint32_t state = scene_manager_get_scene_state(instance->scene_manager, NfcMagicSceneWipe);
if(state == NfcMagicSceneWipeStateCardSearch) {
popup_set_icon(nfc_magic->popup, 0, 8, &I_NFC_manual_60x50);
popup_set_icon(instance->popup, 0, 8, &I_NFC_manual_60x50);
popup_set_text(
nfc_magic->popup,
"Apply the\nsame card\nto the back",
128,
32,
AlignRight,
AlignCenter);
instance->popup, "Apply the\nsame card\nto the back", 128, 32, AlignRight, AlignCenter);
} else {
popup_set_icon(popup, 12, 23, &I_Loading_24);
popup_set_header(popup, "Wiping\nDon't move...", 52, 32, AlignLeft, AlignCenter);
}
view_dispatcher_switch_to_view(nfc_magic->view_dispatcher, NfcMagicViewPopup);
view_dispatcher_switch_to_view(instance->view_dispatcher, NfcMagicAppViewPopup);
}
void nfc_magic_scene_wipe_on_enter(void* context) {
NfcMagic* nfc_magic = context;
NfcMagicApp* instance = context;
scene_manager_set_scene_state(
nfc_magic->scene_manager, NfcMagicSceneWipe, NfcMagicSceneWipeStateCardSearch);
nfc_magic_scene_wipe_setup_view(nfc_magic);
instance->scene_manager, NfcMagicSceneWipe, NfcMagicSceneWipeStateCardSearch);
nfc_magic_scene_wipe_setup_view(instance);
// Setup and start worker
nfc_magic_worker_start(
nfc_magic->worker,
NfcMagicWorkerStateWipe,
nfc_magic->dev,
&nfc_magic->source_dev->dev_data,
nfc_magic->new_password,
nfc_magic_wipe_worker_callback,
nfc_magic);
nfc_magic_blink_start(nfc_magic);
nfc_magic_app_blink_start(instance);
if(instance->protocol == NfcMagicProtocolGen1) {
instance->gen1a_poller = gen1a_poller_alloc(instance->nfc);
gen1a_poller_start(
instance->gen1a_poller, nfc_mafic_scene_wipe_gen1_poller_callback, instance);
} else {
instance->gen4_poller = gen4_poller_alloc(instance->nfc);
gen4_poller_set_password(instance->gen4_poller, instance->gen4_password);
gen4_poller_start(
instance->gen4_poller, nfc_mafic_scene_wipe_gen4_poller_callback, instance);
}
}
bool nfc_magic_scene_wipe_on_event(void* context, SceneManagerEvent event) {
NfcMagic* nfc_magic = context;
NfcMagicApp* instance = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == NfcMagicWorkerEventSuccess) {
scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneSuccess);
consumed = true;
} else if(event.event == NfcMagicWorkerEventFail) {
scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneWipeFail);
consumed = true;
} else if(event.event == NfcMagicWorkerEventWrongCard) {
scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneNotMagic);
consumed = true;
} else if(event.event == NfcMagicWorkerEventCardDetected) {
if(event.event == NfcMagicCustomEventCardDetected) {
scene_manager_set_scene_state(
nfc_magic->scene_manager, NfcMagicSceneWipe, NfcMagicSceneWipeStateCardFound);
nfc_magic_scene_wipe_setup_view(nfc_magic);
instance->scene_manager, NfcMagicSceneWipe, NfcMagicSceneWipeStateCardFound);
nfc_magic_scene_wipe_setup_view(instance);
consumed = true;
} else if(event.event == NfcMagicWorkerEventNoCardDetected) {
} else if(event.event == NfcMagicCustomEventCardLost) {
scene_manager_set_scene_state(
nfc_magic->scene_manager, NfcMagicSceneWipe, NfcMagicSceneWipeStateCardSearch);
nfc_magic_scene_wipe_setup_view(nfc_magic);
instance->scene_manager, NfcMagicSceneWipe, NfcMagicSceneWipeStateCardSearch);
nfc_magic_scene_wipe_setup_view(instance);
consumed = true;
} else if(event.event == NfcMagicCustomEventWorkerSuccess) {
scene_manager_next_scene(instance->scene_manager, NfcMagicSceneSuccess);
consumed = true;
} else if(event.event == NfcMagicCustomEventWorkerFail) {
scene_manager_next_scene(instance->scene_manager, NfcMagicSceneWipeFail);
consumed = true;
}
}
return consumed;
}
void nfc_magic_scene_wipe_on_exit(void* context) {
NfcMagic* nfc_magic = context;
NfcMagicApp* instance = context;
nfc_magic_worker_stop(nfc_magic->worker);
if(instance->protocol == NfcMagicProtocolGen1) {
gen1a_poller_stop(instance->gen1a_poller);
gen1a_poller_free(instance->gen1a_poller);
} else {
gen4_poller_stop(instance->gen4_poller);
gen4_poller_free(instance->gen4_poller);
}
scene_manager_set_scene_state(
nfc_magic->scene_manager, NfcMagicSceneWipe, NfcMagicSceneWipeStateCardSearch);
instance->scene_manager, NfcMagicSceneWipe, NfcMagicSceneWipeStateCardSearch);
// Clear view
popup_reset(nfc_magic->popup);
popup_reset(instance->popup);
nfc_magic_blink_stop(nfc_magic);
nfc_magic_app_blink_stop(instance);
}

View File

@@ -1,41 +1,43 @@
#include "../nfc_magic_i.h"
#include "../nfc_magic_app_i.h"
void nfc_magic_scene_wipe_fail_widget_callback(GuiButtonType result, InputType type, void* context) {
NfcMagic* nfc_magic = context;
NfcMagicApp* instance = context;
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(nfc_magic->view_dispatcher, result);
view_dispatcher_send_custom_event(instance->view_dispatcher, result);
}
}
void nfc_magic_scene_wipe_fail_on_enter(void* context) {
NfcMagic* nfc_magic = context;
Widget* widget = nfc_magic->widget;
NfcMagicApp* instance = context;
notification_message(nfc_magic->notifications, &sequence_error);
Widget* widget = instance->widget;
notification_message(instance->notifications, &sequence_error);
widget_add_icon_element(widget, 73, 17, &I_DolphinCommon_56x48);
widget_add_string_element(widget, 3, 4, AlignLeft, AlignTop, FontPrimary, "Wipe failed");
widget_add_button_element(
widget, GuiButtonTypeLeft, "Retry", nfc_magic_scene_wipe_fail_widget_callback, nfc_magic);
widget, GuiButtonTypeLeft, "Retry", nfc_magic_scene_wipe_fail_widget_callback, instance);
// Setup and start worker
view_dispatcher_switch_to_view(nfc_magic->view_dispatcher, NfcMagicViewWidget);
view_dispatcher_switch_to_view(instance->view_dispatcher, NfcMagicAppViewWidget);
}
bool nfc_magic_scene_wipe_fail_on_event(void* context, SceneManagerEvent event) {
NfcMagic* nfc_magic = context;
NfcMagicApp* instance = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == GuiButtonTypeLeft) {
consumed = scene_manager_previous_scene(nfc_magic->scene_manager);
consumed = scene_manager_previous_scene(instance->scene_manager);
}
}
return consumed;
}
void nfc_magic_scene_wipe_fail_on_exit(void* context) {
NfcMagic* nfc_magic = context;
NfcMagicApp* instance = context;
widget_reset(nfc_magic->widget);
widget_reset(instance->widget);
}

View File

@@ -1,97 +1,144 @@
#include "../nfc_magic_i.h"
#include "../nfc_magic_app_i.h"
enum {
NfcMagicSceneWriteStateCardSearch,
NfcMagicSceneWriteStateCardFound,
};
bool nfc_magic_write_worker_callback(NfcMagicWorkerEvent event, void* context) {
furi_assert(context);
NfcCommand nfc_mafic_scene_write_gen1_poller_callback(Gen1aPollerEvent event, void* context) {
NfcMagicApp* instance = context;
furi_assert(event.data);
NfcMagic* nfc_magic = context;
view_dispatcher_send_custom_event(nfc_magic->view_dispatcher, event);
NfcCommand command = NfcCommandContinue;
return true;
if(event.type == Gen1aPollerEventTypeDetected) {
view_dispatcher_send_custom_event(
instance->view_dispatcher, NfcMagicCustomEventCardDetected);
} else if(event.type == Gen1aPollerEventTypeRequestMode) {
event.data->request_mode.mode = Gen1aPollerModeWrite;
} else if(event.type == Gen1aPollerEventTypeRequestDataToWrite) {
const MfClassicData* mfc_data =
nfc_device_get_data(instance->source_dev, NfcProtocolMfClassic);
event.data->data_to_write.mfc_data = mfc_data;
} else if(event.type == Gen1aPollerEventTypeSuccess) {
view_dispatcher_send_custom_event(
instance->view_dispatcher, NfcMagicCustomEventWorkerSuccess);
command = NfcCommandStop;
} else if(event.type == Gen1aPollerEventTypeFail) {
view_dispatcher_send_custom_event(
instance->view_dispatcher, NfcMagicCustomEventWorkerFail);
command = NfcCommandStop;
}
return command;
}
static void nfc_magic_scene_write_setup_view(NfcMagic* nfc_magic) {
Popup* popup = nfc_magic->popup;
NfcCommand nfc_mafic_scene_write_gen4_poller_callback(Gen4PollerEvent event, void* context) {
NfcMagicApp* instance = context;
furi_assert(event.data);
NfcCommand command = NfcCommandContinue;
if(event.type == Gen4PollerEventTypeCardDetected) {
view_dispatcher_send_custom_event(
instance->view_dispatcher, NfcMagicCustomEventCardDetected);
} else if(event.type == Gen4PollerEventTypeRequestMode) {
event.data->request_mode.mode = Gen4PollerModeWrite;
} else if(event.type == Gen4PollerEventTypeRequestDataToWrite) {
NfcProtocol protocol = nfc_device_get_protocol(instance->source_dev);
event.data->request_data.protocol = protocol;
event.data->request_data.data = nfc_device_get_data(instance->source_dev, protocol);
} else if(event.type == Gen4PollerEventTypeSuccess) {
view_dispatcher_send_custom_event(
instance->view_dispatcher, NfcMagicCustomEventWorkerSuccess);
command = NfcCommandStop;
} else if(event.type == Gen4PollerEventTypeFail) {
view_dispatcher_send_custom_event(
instance->view_dispatcher, NfcMagicCustomEventWorkerFail);
command = NfcCommandStop;
}
return command;
}
static void nfc_magic_scene_write_setup_view(NfcMagicApp* instance) {
Popup* popup = instance->popup;
popup_reset(popup);
uint32_t state = scene_manager_get_scene_state(nfc_magic->scene_manager, NfcMagicSceneWrite);
uint32_t state = scene_manager_get_scene_state(instance->scene_manager, NfcMagicSceneWrite);
if(state == NfcMagicSceneWriteStateCardSearch) {
popup_set_icon(instance->popup, 0, 8, &I_NFC_manual_60x50);
popup_set_text(
nfc_magic->popup,
"Apply the\nsame card\nto the back",
128,
32,
AlignRight,
AlignCenter);
popup_set_icon(nfc_magic->popup, 0, 8, &I_NFC_manual_60x50);
instance->popup, "Apply the\nsame card\nto the back", 128, 32, AlignRight, AlignCenter);
} else {
popup_set_icon(popup, 12, 23, &I_Loading_24);
popup_set_header(popup, "Writing\nDon't move...", 52, 32, AlignLeft, AlignCenter);
}
view_dispatcher_switch_to_view(nfc_magic->view_dispatcher, NfcMagicViewPopup);
view_dispatcher_switch_to_view(instance->view_dispatcher, NfcMagicAppViewPopup);
}
void nfc_magic_scene_write_on_enter(void* context) {
NfcMagic* nfc_magic = context;
NfcMagicApp* instance = context;
scene_manager_set_scene_state(
nfc_magic->scene_manager, NfcMagicSceneWrite, NfcMagicSceneWriteStateCardSearch);
nfc_magic_scene_write_setup_view(nfc_magic);
instance->scene_manager, NfcMagicSceneWrite, NfcMagicSceneWriteStateCardSearch);
nfc_magic_scene_write_setup_view(instance);
// Setup and start worker
nfc_magic_worker_start(
nfc_magic->worker,
NfcMagicWorkerStateWrite,
nfc_magic->dev,
&nfc_magic->source_dev->dev_data,
nfc_magic->new_password,
nfc_magic_write_worker_callback,
nfc_magic);
nfc_magic_blink_start(nfc_magic);
nfc_magic_app_blink_start(instance);
if(instance->protocol == NfcMagicProtocolGen1) {
instance->gen1a_poller = gen1a_poller_alloc(instance->nfc);
gen1a_poller_start(
instance->gen1a_poller, nfc_mafic_scene_write_gen1_poller_callback, instance);
} else {
instance->gen4_poller = gen4_poller_alloc(instance->nfc);
gen4_poller_start(
instance->gen4_poller, nfc_mafic_scene_write_gen4_poller_callback, instance);
}
}
bool nfc_magic_scene_write_on_event(void* context, SceneManagerEvent event) {
NfcMagic* nfc_magic = context;
NfcMagicApp* instance = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == NfcMagicWorkerEventSuccess) {
scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneSuccess);
consumed = true;
} else if(event.event == NfcMagicWorkerEventFail) {
scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneWriteFail);
consumed = true;
} else if(event.event == NfcMagicWorkerEventWrongCard) {
scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneNotMagic);
consumed = true;
} else if(event.event == NfcMagicWorkerEventCardDetected) {
if(event.event == NfcMagicCustomEventCardDetected) {
scene_manager_set_scene_state(
nfc_magic->scene_manager, NfcMagicSceneWrite, NfcMagicSceneWriteStateCardFound);
nfc_magic_scene_write_setup_view(nfc_magic);
instance->scene_manager, NfcMagicSceneWrite, NfcMagicSceneWriteStateCardFound);
nfc_magic_scene_write_setup_view(instance);
consumed = true;
} else if(event.event == NfcMagicWorkerEventNoCardDetected) {
} else if(event.event == NfcMagicCustomEventCardLost) {
scene_manager_set_scene_state(
nfc_magic->scene_manager, NfcMagicSceneWrite, NfcMagicSceneWriteStateCardSearch);
nfc_magic_scene_write_setup_view(nfc_magic);
instance->scene_manager, NfcMagicSceneWrite, NfcMagicSceneWriteStateCardSearch);
nfc_magic_scene_write_setup_view(instance);
consumed = true;
} else if(event.event == NfcMagicCustomEventWorkerSuccess) {
scene_manager_next_scene(instance->scene_manager, NfcMagicSceneSuccess);
consumed = true;
} else if(event.event == NfcMagicCustomEventWorkerFail) {
scene_manager_next_scene(instance->scene_manager, NfcMagicSceneWriteFail);
consumed = true;
}
}
return consumed;
}
void nfc_magic_scene_write_on_exit(void* context) {
NfcMagic* nfc_magic = context;
NfcMagicApp* instance = context;
nfc_magic_worker_stop(nfc_magic->worker);
if(instance->protocol == NfcMagicProtocolGen1) {
gen1a_poller_stop(instance->gen1a_poller);
gen1a_poller_free(instance->gen1a_poller);
} else {
gen4_poller_stop(instance->gen4_poller);
gen4_poller_free(instance->gen4_poller);
}
scene_manager_set_scene_state(
nfc_magic->scene_manager, NfcMagicSceneWrite, NfcMagicSceneWriteStateCardSearch);
instance->scene_manager, NfcMagicSceneWrite, NfcMagicSceneWriteStateCardSearch);
// Clear view
popup_reset(nfc_magic->popup);
popup_reset(instance->popup);
nfc_magic_blink_stop(nfc_magic);
nfc_magic_app_blink_stop(instance);
}

View File

@@ -1,18 +1,19 @@
#include "../nfc_magic_i.h"
#include "../nfc_magic_app_i.h"
void nfc_magic_scene_write_confirm_widget_callback(
GuiButtonType result,
InputType type,
void* context) {
NfcMagic* nfc_magic = context;
NfcMagicApp* instance = context;
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(nfc_magic->view_dispatcher, result);
view_dispatcher_send_custom_event(instance->view_dispatcher, result);
}
}
void nfc_magic_scene_write_confirm_on_enter(void* context) {
NfcMagic* nfc_magic = context;
Widget* widget = nfc_magic->widget;
NfcMagicApp* instance = context;
Widget* widget = instance->widget;
widget_add_string_element(widget, 3, 0, AlignLeft, AlignTop, FontPrimary, "Risky operation");
widget_add_text_box_element(
@@ -30,27 +31,23 @@ void nfc_magic_scene_write_confirm_on_enter(void* context) {
GuiButtonTypeCenter,
"Continue",
nfc_magic_scene_write_confirm_widget_callback,
nfc_magic);
instance);
widget_add_button_element(
widget,
GuiButtonTypeLeft,
"Back",
nfc_magic_scene_write_confirm_widget_callback,
nfc_magic);
widget, GuiButtonTypeLeft, "Back", nfc_magic_scene_write_confirm_widget_callback, instance);
// Setup and start worker
view_dispatcher_switch_to_view(nfc_magic->view_dispatcher, NfcMagicViewWidget);
view_dispatcher_switch_to_view(instance->view_dispatcher, NfcMagicAppViewWidget);
}
bool nfc_magic_scene_write_confirm_on_event(void* context, SceneManagerEvent event) {
NfcMagic* nfc_magic = context;
NfcMagicApp* instance = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == GuiButtonTypeLeft) {
consumed = scene_manager_previous_scene(nfc_magic->scene_manager);
consumed = scene_manager_previous_scene(instance->scene_manager);
} else if(event.event == GuiButtonTypeCenter) {
scene_manager_next_scene(nfc_magic->scene_manager, NfcMagicSceneWrite);
scene_manager_next_scene(instance->scene_manager, NfcMagicSceneWrite);
consumed = true;
}
}
@@ -58,7 +55,7 @@ bool nfc_magic_scene_write_confirm_on_event(void* context, SceneManagerEvent eve
}
void nfc_magic_scene_write_confirm_on_exit(void* context) {
NfcMagic* nfc_magic = context;
NfcMagicApp* instance = context;
widget_reset(nfc_magic->widget);
widget_reset(instance->widget);
}

View File

@@ -1,20 +1,20 @@
#include "../nfc_magic_i.h"
#include "../nfc_magic_app_i.h"
void nfc_magic_scene_write_fail_widget_callback(
GuiButtonType result,
InputType type,
void* context) {
NfcMagic* nfc_magic = context;
NfcMagicApp* instance = context;
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(nfc_magic->view_dispatcher, result);
view_dispatcher_send_custom_event(instance->view_dispatcher, result);
}
}
void nfc_magic_scene_write_fail_on_enter(void* context) {
NfcMagic* nfc_magic = context;
Widget* widget = nfc_magic->widget;
NfcMagicApp* instance = context;
Widget* widget = instance->widget;
notification_message(nfc_magic->notifications, &sequence_error);
notification_message(instance->notifications, &sequence_error);
widget_add_icon_element(widget, 72, 17, &I_DolphinCommon_56x48);
widget_add_string_element(
@@ -29,30 +29,30 @@ void nfc_magic_scene_write_fail_on_enter(void* context) {
"Not all sectors\nwere written\ncorrectly.");
widget_add_button_element(
widget, GuiButtonTypeLeft, "Finish", nfc_magic_scene_write_fail_widget_callback, nfc_magic);
widget, GuiButtonTypeLeft, "Finish", nfc_magic_scene_write_fail_widget_callback, instance);
// Setup and start worker
view_dispatcher_switch_to_view(nfc_magic->view_dispatcher, NfcMagicViewWidget);
view_dispatcher_switch_to_view(instance->view_dispatcher, NfcMagicAppViewWidget);
}
bool nfc_magic_scene_write_fail_on_event(void* context, SceneManagerEvent event) {
NfcMagic* nfc_magic = context;
NfcMagicApp* instance = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == GuiButtonTypeLeft) {
consumed = scene_manager_search_and_switch_to_previous_scene(
nfc_magic->scene_manager, NfcMagicSceneStart);
instance->scene_manager, NfcMagicSceneStart);
}
} else if(event.type == SceneManagerEventTypeBack) {
consumed = scene_manager_search_and_switch_to_previous_scene(
nfc_magic->scene_manager, NfcMagicSceneStart);
instance->scene_manager, NfcMagicSceneStart);
}
return consumed;
}
void nfc_magic_scene_write_fail_on_exit(void* context) {
NfcMagic* nfc_magic = context;
NfcMagicApp* instance = context;
widget_reset(nfc_magic->widget);
widget_reset(instance->widget);
}

View File

@@ -1,20 +1,20 @@
#include "../nfc_magic_i.h"
#include "../nfc_magic_app_i.h"
void nfc_magic_scene_wrong_card_widget_callback(
GuiButtonType result,
InputType type,
void* context) {
NfcMagic* nfc_magic = context;
NfcMagicApp* instance = context;
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(nfc_magic->view_dispatcher, result);
view_dispatcher_send_custom_event(instance->view_dispatcher, result);
}
}
void nfc_magic_scene_wrong_card_on_enter(void* context) {
NfcMagic* nfc_magic = context;
Widget* widget = nfc_magic->widget;
NfcMagicApp* instance = context;
Widget* widget = instance->widget;
notification_message(nfc_magic->notifications, &sequence_error);
notification_message(instance->notifications, &sequence_error);
widget_add_icon_element(widget, 73, 17, &I_DolphinCommon_56x48);
widget_add_string_element(
@@ -28,26 +28,26 @@ void nfc_magic_scene_wrong_card_on_enter(void* context) {
FontSecondary,
"Writing this file is\nnot supported for\nthis magic card.");
widget_add_button_element(
widget, GuiButtonTypeLeft, "Retry", nfc_magic_scene_wrong_card_widget_callback, nfc_magic);
widget, GuiButtonTypeLeft, "Retry", nfc_magic_scene_wrong_card_widget_callback, instance);
// Setup and start worker
view_dispatcher_switch_to_view(nfc_magic->view_dispatcher, NfcMagicViewWidget);
view_dispatcher_switch_to_view(instance->view_dispatcher, NfcMagicAppViewWidget);
}
bool nfc_magic_scene_wrong_card_on_event(void* context, SceneManagerEvent event) {
NfcMagic* nfc_magic = context;
NfcMagicApp* instance = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == GuiButtonTypeLeft) {
consumed = scene_manager_previous_scene(nfc_magic->scene_manager);
consumed = scene_manager_previous_scene(instance->scene_manager);
}
}
return consumed;
}
void nfc_magic_scene_wrong_card_on_exit(void* context) {
NfcMagic* nfc_magic = context;
NfcMagicApp* instance = context;
widget_reset(nfc_magic->widget);
widget_reset(instance->widget);
}