[FL-2714] New NFC info screens (#1605)
* nfc: add scroll element for info * widget: format lines for scroll text element * widget: fix new line generation * widget: finish element text scroll * nfc: rework ultralight and NTAG info scenes * nfc: rework mf classic info screens * nfc: rework nfca info scenes * nfc: fix mf ultralight navigation * widget: add documentation * nfc: rework bank card infO * nfc: rework device info scene * nfc: fix incorrect atqa order * mf ultralight: remove unused function * widget: add mutex for model protection * widget: fix memory leak * nfc: rework delete scene * nfc: fix selected item in saved menu scene * widget: fix naming in text scroll element * nfc: fix navigation from delete success * nfc: add dictionary icon * widget: fix memory leak
This commit is contained in:
@@ -1217,6 +1217,7 @@ void nfc_device_data_clear(NfcDeviceData* dev_data) {
|
||||
void nfc_device_clear(NfcDevice* dev) {
|
||||
furi_assert(dev);
|
||||
|
||||
nfc_device_set_name(dev, "");
|
||||
nfc_device_data_clear(&dev->dev_data);
|
||||
dev->format = NfcDeviceSaveFormatUid;
|
||||
string_reset(dev->load_path);
|
||||
|
@@ -143,7 +143,7 @@ static bool nfc_worker_read_mf_classic(NfcWorker* nfc_worker, FuriHalNfcTxRxCont
|
||||
if(nfc_supported_card[i].verify(nfc_worker, tx_rx)) {
|
||||
if(nfc_supported_card[i].read(nfc_worker, tx_rx)) {
|
||||
read_success = true;
|
||||
nfc_supported_card[i].parse(nfc_worker);
|
||||
nfc_supported_card[i].parse(nfc_worker->dev_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -11,3 +11,17 @@ NfcSupportedCard nfc_supported_card[NfcSupportedCardTypeEnd] = {
|
||||
.parse = troyka_parser_parse,
|
||||
},
|
||||
};
|
||||
|
||||
bool nfc_supported_card_verify_and_parse(NfcDeviceData* dev_data) {
|
||||
furi_assert(dev_data);
|
||||
|
||||
bool card_parsed = false;
|
||||
for(size_t i = 0; i < COUNT_OF(nfc_supported_card); i++) {
|
||||
if(nfc_supported_card[i].parse(dev_data)) {
|
||||
card_parsed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return card_parsed;
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <furi_hal_nfc.h>
|
||||
#include "../nfc_worker.h"
|
||||
#include "../nfc_device.h"
|
||||
|
||||
#include <m-string.h>
|
||||
|
||||
@@ -15,7 +16,7 @@ typedef bool (*NfcSupportedCardVerify)(NfcWorker* nfc_worker, FuriHalNfcTxRxCont
|
||||
|
||||
typedef bool (*NfcSupportedCardRead)(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx);
|
||||
|
||||
typedef bool (*NfcSupportedCardParse)(NfcWorker* nfc_worker);
|
||||
typedef bool (*NfcSupportedCardParse)(NfcDeviceData* dev_data);
|
||||
|
||||
typedef struct {
|
||||
NfcProtocol protocol;
|
||||
@@ -25,3 +26,5 @@ typedef struct {
|
||||
} NfcSupportedCard;
|
||||
|
||||
extern NfcSupportedCard nfc_supported_card[NfcSupportedCardTypeEnd];
|
||||
|
||||
bool nfc_supported_card_verify_and_parse(NfcDeviceData* dev_data);
|
||||
|
@@ -49,23 +49,31 @@ bool troyka_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) {
|
||||
return mf_classic_read_card(tx_rx, &reader, &nfc_worker->dev_data->mf_classic_data) == 16;
|
||||
}
|
||||
|
||||
bool troyka_parser_parse(NfcWorker* nfc_worker) {
|
||||
MfClassicData* data = &nfc_worker->dev_data->mf_classic_data;
|
||||
uint8_t* temp_ptr = &data->block[8 * 4 + 1].value[5];
|
||||
uint16_t balance = ((temp_ptr[0] << 8) | temp_ptr[1]) / 25;
|
||||
temp_ptr = &data->block[8 * 4].value[3];
|
||||
uint32_t number = 0;
|
||||
for(size_t i = 0; i < 4; i++) {
|
||||
number <<= 8;
|
||||
number |= temp_ptr[i];
|
||||
}
|
||||
number >>= 4;
|
||||
bool troyka_parser_parse(NfcDeviceData* dev_data) {
|
||||
MfClassicData* data = &dev_data->mf_classic_data;
|
||||
bool troyka_parsed = false;
|
||||
|
||||
string_printf(
|
||||
nfc_worker->dev_data->parsed_data,
|
||||
"Troyka Transport card\nNumber: %ld\nBalance: %d rub",
|
||||
number,
|
||||
balance);
|
||||
do {
|
||||
// Verify key
|
||||
MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(data, 8);
|
||||
uint64_t key = nfc_util_bytes2num(sec_tr->key_a, 6);
|
||||
if(key != troyka_keys[8].key_a) break;
|
||||
|
||||
return true;
|
||||
// Parse data
|
||||
uint8_t* temp_ptr = &data->block[8 * 4 + 1].value[5];
|
||||
uint16_t balance = ((temp_ptr[0] << 8) | temp_ptr[1]) / 25;
|
||||
temp_ptr = &data->block[8 * 4].value[3];
|
||||
uint32_t number = 0;
|
||||
for(size_t i = 0; i < 4; i++) {
|
||||
number <<= 8;
|
||||
number |= temp_ptr[i];
|
||||
}
|
||||
number >>= 4;
|
||||
|
||||
string_printf(
|
||||
dev_data->parsed_data, "\e#Troyka\nNum: %ld\nBalance: %d rur.", number, balance);
|
||||
troyka_parsed = true;
|
||||
} while(false);
|
||||
|
||||
return troyka_parsed;
|
||||
}
|
||||
|
@@ -6,4 +6,4 @@ bool troyka_parser_verify(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx);
|
||||
|
||||
bool troyka_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx);
|
||||
|
||||
bool troyka_parser_parse(NfcWorker* nfc_worker);
|
||||
bool troyka_parser_parse(NfcDeviceData* dev_data);
|
||||
|
@@ -191,7 +191,7 @@ bool mf_ultralight_authenticate(FuriHalNfcTxRxContext* tx_rx, uint32_t key, uint
|
||||
}
|
||||
|
||||
if(pack != NULL) {
|
||||
*pack = (tx_rx->rx_data[0] << 8) | tx_rx->rx_data[1];
|
||||
*pack = (tx_rx->rx_data[1] << 8) | tx_rx->rx_data[0];
|
||||
}
|
||||
|
||||
FURI_LOG_I(TAG, "Auth success. Password: %08X. PACK: %04X", key, *pack);
|
||||
@@ -697,48 +697,6 @@ bool mf_ultralight_read_counters(FuriHalNfcTxRxContext* tx_rx, MfUltralightData*
|
||||
return counter_read == (is_single_counter ? 1 : 3);
|
||||
}
|
||||
|
||||
int16_t mf_ultralight_get_authlim(
|
||||
FuriHalNfcTxRxContext* tx_rx,
|
||||
MfUltralightReader* reader,
|
||||
MfUltralightData* data) {
|
||||
mf_ultralight_read_version(tx_rx, reader, data);
|
||||
if(!(reader->supported_features & MfUltralightSupportAuth)) {
|
||||
// No authentication
|
||||
return -2;
|
||||
}
|
||||
|
||||
uint8_t config_pages_index;
|
||||
if(data->type >= MfUltralightTypeUL11 && data->type <= MfUltralightTypeNTAG216) {
|
||||
config_pages_index = reader->pages_to_read - 4;
|
||||
} else if(
|
||||
data->type >= MfUltralightTypeNTAGI2CPlus1K &&
|
||||
data->type <= MfUltralightTypeNTAGI2CPlus1K) {
|
||||
config_pages_index = 0xe3;
|
||||
} else {
|
||||
// No config pages
|
||||
return -2;
|
||||
}
|
||||
|
||||
if(!mf_ultralight_read_pages_direct(tx_rx, config_pages_index, data->data)) {
|
||||
// Config pages are not readable due to protection
|
||||
return -1;
|
||||
}
|
||||
|
||||
MfUltralightConfigPages* config_pages = (MfUltralightConfigPages*)&data->data;
|
||||
if(config_pages->auth0 >= reader->pages_to_read) {
|
||||
// Authentication is not configured
|
||||
return -2;
|
||||
}
|
||||
|
||||
int16_t authlim = config_pages->access.authlim;
|
||||
if(authlim > 0 && data->type >= MfUltralightTypeNTAGI2CPlus1K &&
|
||||
data->type <= MfUltralightTypeNTAGI2CPlus2K) {
|
||||
authlim = 1 << authlim;
|
||||
}
|
||||
|
||||
return authlim;
|
||||
}
|
||||
|
||||
bool mf_ultralight_read_tearing_flags(FuriHalNfcTxRxContext* tx_rx, MfUltralightData* data) {
|
||||
uint8_t flag_read = 0;
|
||||
|
||||
|
@@ -56,13 +56,6 @@ typedef enum {
|
||||
MfUltralightTypeNum,
|
||||
} MfUltralightType;
|
||||
|
||||
typedef enum {
|
||||
MfUltralightAuthLimitUnknown,
|
||||
MfUltralightAuthLimitNotSupported,
|
||||
MfUltralightAuthLimitConfigured,
|
||||
MfUltralightAuthLimitNotConfigured,
|
||||
} MfUltralightAuthLimit;
|
||||
|
||||
typedef enum {
|
||||
MfUltralightSupportNone = 0,
|
||||
MfUltralightSupportFastRead = 1 << 0,
|
||||
@@ -245,11 +238,6 @@ bool mf_ul_prepare_emulation_response(
|
||||
uint32_t* data_type,
|
||||
void* context);
|
||||
|
||||
int16_t mf_ultralight_get_authlim(
|
||||
FuriHalNfcTxRxContext* tx_rx,
|
||||
MfUltralightReader* reader,
|
||||
MfUltralightData* data);
|
||||
|
||||
uint32_t mf_ul_pwdgen_amiibo(FuriHalNfcDevData* data);
|
||||
|
||||
uint32_t mf_ul_pwdgen_xiaomi(FuriHalNfcDevData* data);
|
||||
|
Reference in New Issue
Block a user