mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2025-12-12 12:42:30 +04:00
Merge branch 'fz-dev' into dev
This commit is contained in:
2
.github/CODEOWNERS
vendored
2
.github/CODEOWNERS
vendored
@@ -76,7 +76,7 @@
|
|||||||
/lib/microtar/ @skotopes @DrZlo13 @hedger
|
/lib/microtar/ @skotopes @DrZlo13 @hedger
|
||||||
/lib/mlib/ @skotopes @DrZlo13 @hedger
|
/lib/mlib/ @skotopes @DrZlo13 @hedger
|
||||||
/lib/nanopb/ @skotopes @DrZlo13 @hedger
|
/lib/nanopb/ @skotopes @DrZlo13 @hedger
|
||||||
/lib/nfc_protocols/ @skotopes @DrZlo13 @hedger @gornekich
|
/lib/nfc/ @skotopes @DrZlo13 @hedger @gornekich
|
||||||
/lib/one_wire/ @skotopes @DrZlo13 @hedger
|
/lib/one_wire/ @skotopes @DrZlo13 @hedger
|
||||||
/lib/qrcode/ @skotopes @DrZlo13 @hedger
|
/lib/qrcode/ @skotopes @DrZlo13 @hedger
|
||||||
/lib/subghz/ @skotopes @DrZlo13 @hedger @Skorpionm
|
/lib/subghz/ @skotopes @DrZlo13 @hedger @Skorpionm
|
||||||
|
|||||||
@@ -9,5 +9,6 @@ enum NfcCustomEvent {
|
|||||||
NfcCustomEventByteInputDone,
|
NfcCustomEventByteInputDone,
|
||||||
NfcCustomEventTextInputDone,
|
NfcCustomEventTextInputDone,
|
||||||
NfcCustomEventDictAttackDone,
|
NfcCustomEventDictAttackDone,
|
||||||
|
NfcCustomEventDictAttackSkip,
|
||||||
NfcCustomEventRpcLoad,
|
NfcCustomEventRpcLoad,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -267,67 +267,67 @@ static void nfc_generate_ntag_i2c_plus_2k(NfcDeviceData* data) {
|
|||||||
static const NfcGenerator mf_ul_generator = {
|
static const NfcGenerator mf_ul_generator = {
|
||||||
.name = "Mifare Ultralight",
|
.name = "Mifare Ultralight",
|
||||||
.generator_func = nfc_generate_mf_ul_orig,
|
.generator_func = nfc_generate_mf_ul_orig,
|
||||||
.next_scene = NfcSceneMifareUlMenu};
|
.next_scene = NfcSceneMfUltralightMenu};
|
||||||
|
|
||||||
static const NfcGenerator mf_ul_11_generator = {
|
static const NfcGenerator mf_ul_11_generator = {
|
||||||
.name = "Mifare Ultralight EV1 11",
|
.name = "Mifare Ultralight EV1 11",
|
||||||
.generator_func = nfc_generate_mf_ul_11,
|
.generator_func = nfc_generate_mf_ul_11,
|
||||||
.next_scene = NfcSceneMifareUlMenu};
|
.next_scene = NfcSceneMfUltralightMenu};
|
||||||
|
|
||||||
static const NfcGenerator mf_ul_h11_generator = {
|
static const NfcGenerator mf_ul_h11_generator = {
|
||||||
.name = "Mifare Ultralight EV1 H11",
|
.name = "Mifare Ultralight EV1 H11",
|
||||||
.generator_func = nfc_generate_mf_ul_h11,
|
.generator_func = nfc_generate_mf_ul_h11,
|
||||||
.next_scene = NfcSceneMifareUlMenu};
|
.next_scene = NfcSceneMfUltralightMenu};
|
||||||
|
|
||||||
static const NfcGenerator mf_ul_21_generator = {
|
static const NfcGenerator mf_ul_21_generator = {
|
||||||
.name = "Mifare Ultralight EV1 21",
|
.name = "Mifare Ultralight EV1 21",
|
||||||
.generator_func = nfc_generate_mf_ul_21,
|
.generator_func = nfc_generate_mf_ul_21,
|
||||||
.next_scene = NfcSceneMifareUlMenu};
|
.next_scene = NfcSceneMfUltralightMenu};
|
||||||
|
|
||||||
static const NfcGenerator mf_ul_h21_generator = {
|
static const NfcGenerator mf_ul_h21_generator = {
|
||||||
.name = "Mifare Ultralight EV1 H21",
|
.name = "Mifare Ultralight EV1 H21",
|
||||||
.generator_func = nfc_generate_mf_ul_h21,
|
.generator_func = nfc_generate_mf_ul_h21,
|
||||||
.next_scene = NfcSceneMifareUlMenu};
|
.next_scene = NfcSceneMfUltralightMenu};
|
||||||
|
|
||||||
static const NfcGenerator ntag203_generator = {
|
static const NfcGenerator ntag203_generator = {
|
||||||
.name = "NTAG203",
|
.name = "NTAG203",
|
||||||
.generator_func = nfc_generate_mf_ul_ntag203,
|
.generator_func = nfc_generate_mf_ul_ntag203,
|
||||||
.next_scene = NfcSceneMifareUlMenu};
|
.next_scene = NfcSceneMfUltralightMenu};
|
||||||
|
|
||||||
static const NfcGenerator ntag213_generator = {
|
static const NfcGenerator ntag213_generator = {
|
||||||
.name = "NTAG213",
|
.name = "NTAG213",
|
||||||
.generator_func = nfc_generate_ntag213,
|
.generator_func = nfc_generate_ntag213,
|
||||||
.next_scene = NfcSceneMifareUlMenu};
|
.next_scene = NfcSceneMfUltralightMenu};
|
||||||
|
|
||||||
static const NfcGenerator ntag215_generator = {
|
static const NfcGenerator ntag215_generator = {
|
||||||
.name = "NTAG215",
|
.name = "NTAG215",
|
||||||
.generator_func = nfc_generate_ntag215,
|
.generator_func = nfc_generate_ntag215,
|
||||||
.next_scene = NfcSceneMifareUlMenu};
|
.next_scene = NfcSceneMfUltralightMenu};
|
||||||
|
|
||||||
static const NfcGenerator ntag216_generator = {
|
static const NfcGenerator ntag216_generator = {
|
||||||
.name = "NTAG216",
|
.name = "NTAG216",
|
||||||
.generator_func = nfc_generate_ntag216,
|
.generator_func = nfc_generate_ntag216,
|
||||||
.next_scene = NfcSceneMifareUlMenu};
|
.next_scene = NfcSceneMfUltralightMenu};
|
||||||
|
|
||||||
static const NfcGenerator ntag_i2c_1k_generator = {
|
static const NfcGenerator ntag_i2c_1k_generator = {
|
||||||
.name = "NTAG I2C 1k",
|
.name = "NTAG I2C 1k",
|
||||||
.generator_func = nfc_generate_ntag_i2c_1k,
|
.generator_func = nfc_generate_ntag_i2c_1k,
|
||||||
.next_scene = NfcSceneMifareUlMenu};
|
.next_scene = NfcSceneMfUltralightMenu};
|
||||||
|
|
||||||
static const NfcGenerator ntag_i2c_2k_generator = {
|
static const NfcGenerator ntag_i2c_2k_generator = {
|
||||||
.name = "NTAG I2C 2k",
|
.name = "NTAG I2C 2k",
|
||||||
.generator_func = nfc_generate_ntag_i2c_2k,
|
.generator_func = nfc_generate_ntag_i2c_2k,
|
||||||
.next_scene = NfcSceneMifareUlMenu};
|
.next_scene = NfcSceneMfUltralightMenu};
|
||||||
|
|
||||||
static const NfcGenerator ntag_i2c_plus_1k_generator = {
|
static const NfcGenerator ntag_i2c_plus_1k_generator = {
|
||||||
.name = "NTAG I2C Plus 1k",
|
.name = "NTAG I2C Plus 1k",
|
||||||
.generator_func = nfc_generate_ntag_i2c_plus_1k,
|
.generator_func = nfc_generate_ntag_i2c_plus_1k,
|
||||||
.next_scene = NfcSceneMifareUlMenu};
|
.next_scene = NfcSceneMfUltralightMenu};
|
||||||
|
|
||||||
static const NfcGenerator ntag_i2c_plus_2k_generator = {
|
static const NfcGenerator ntag_i2c_plus_2k_generator = {
|
||||||
.name = "NTAG I2C Plus 2k",
|
.name = "NTAG I2C Plus 2k",
|
||||||
.generator_func = nfc_generate_ntag_i2c_plus_2k,
|
.generator_func = nfc_generate_ntag_i2c_plus_2k,
|
||||||
.next_scene = NfcSceneMifareUlMenu};
|
.next_scene = NfcSceneMfUltralightMenu};
|
||||||
|
|
||||||
const NfcGenerator* const nfc_generators[] = {
|
const NfcGenerator* const nfc_generators[] = {
|
||||||
&mf_ul_generator,
|
&mf_ul_generator,
|
||||||
|
|||||||
@@ -1,53 +0,0 @@
|
|||||||
#include "nfc_mf_classic_dict.h"
|
|
||||||
|
|
||||||
#include <flipper_format/flipper_format.h>
|
|
||||||
#include <lib/toolbox/args.h>
|
|
||||||
|
|
||||||
#define NFC_MF_CLASSIC_DICT_PATH EXT_PATH("nfc/assets/mf_classic_dict.nfc")
|
|
||||||
|
|
||||||
#define NFC_MF_CLASSIC_KEY_LEN (13)
|
|
||||||
|
|
||||||
bool nfc_mf_classic_dict_check_presence(Storage* storage) {
|
|
||||||
furi_assert(storage);
|
|
||||||
return storage_common_stat(storage, NFC_MF_CLASSIC_DICT_PATH, NULL) == FSE_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool nfc_mf_classic_dict_open_file(Stream* stream) {
|
|
||||||
furi_assert(stream);
|
|
||||||
return file_stream_open(stream, NFC_MF_CLASSIC_DICT_PATH, FSAM_READ, FSOM_OPEN_EXISTING);
|
|
||||||
}
|
|
||||||
|
|
||||||
void nfc_mf_classic_dict_close_file(Stream* stream) {
|
|
||||||
furi_assert(stream);
|
|
||||||
file_stream_close(stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool nfc_mf_classic_dict_get_next_key(Stream* stream, uint64_t* key) {
|
|
||||||
furi_assert(stream);
|
|
||||||
furi_assert(key);
|
|
||||||
uint8_t key_byte_tmp = 0;
|
|
||||||
string_t next_line;
|
|
||||||
string_init(next_line);
|
|
||||||
*key = 0;
|
|
||||||
|
|
||||||
bool next_key_read = false;
|
|
||||||
while(!next_key_read) {
|
|
||||||
if(!stream_read_line(stream, next_line)) break;
|
|
||||||
if(string_get_char(next_line, 0) == '#') continue;
|
|
||||||
if(string_size(next_line) != NFC_MF_CLASSIC_KEY_LEN) continue;
|
|
||||||
for(uint8_t i = 0; i < 12; i += 2) {
|
|
||||||
args_char_to_hex(
|
|
||||||
string_get_char(next_line, i), string_get_char(next_line, i + 1), &key_byte_tmp);
|
|
||||||
*key |= (uint64_t)key_byte_tmp << 8 * (5 - i / 2);
|
|
||||||
}
|
|
||||||
next_key_read = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
string_clear(next_line);
|
|
||||||
return next_key_read;
|
|
||||||
}
|
|
||||||
|
|
||||||
void nfc_mf_classic_dict_reset(Stream* stream) {
|
|
||||||
furi_assert(stream);
|
|
||||||
stream_rewind(stream);
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <storage/storage.h>
|
|
||||||
#include <lib/toolbox/stream/file_stream.h>
|
|
||||||
|
|
||||||
bool nfc_mf_classic_dict_check_presence(Storage* storage);
|
|
||||||
|
|
||||||
bool nfc_mf_classic_dict_open_file(Stream* stream);
|
|
||||||
|
|
||||||
void nfc_mf_classic_dict_close_file(Stream* stream);
|
|
||||||
|
|
||||||
bool nfc_mf_classic_dict_get_next_key(Stream* stream, uint64_t* key);
|
|
||||||
|
|
||||||
void nfc_mf_classic_dict_reset(Stream* stream);
|
|
||||||
@@ -13,12 +13,6 @@ bool nfc_back_event_callback(void* context) {
|
|||||||
return scene_manager_handle_back_event(nfc->scene_manager);
|
return scene_manager_handle_back_event(nfc->scene_manager);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_tick_event_callback(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
Nfc* nfc = context;
|
|
||||||
scene_manager_handle_tick_event(nfc->scene_manager);
|
|
||||||
}
|
|
||||||
|
|
||||||
void nfc_rpc_exit_callback(Nfc* nfc) {
|
void nfc_rpc_exit_callback(Nfc* nfc) {
|
||||||
if(nfc->rpc_state == NfcRpcStateEmulating) {
|
if(nfc->rpc_state == NfcRpcStateEmulating) {
|
||||||
// Stop worker
|
// Stop worker
|
||||||
@@ -36,11 +30,12 @@ void nfc_rpc_exit_callback(Nfc* nfc) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nfc_rpc_emulate_callback(NfcWorkerEvent event, void* context) {
|
static bool nfc_rpc_emulate_callback(NfcWorkerEvent event, void* context) {
|
||||||
UNUSED(event);
|
UNUSED(event);
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
nfc->rpc_state = NfcRpcStateEmulated;
|
nfc->rpc_state = NfcRpcStateEmulated;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool nfc_rpc_command_callback(RpcAppSystemEvent event, const char* arg, void* context) {
|
static bool nfc_rpc_command_callback(RpcAppSystemEvent event, const char* arg, void* context) {
|
||||||
@@ -67,20 +62,20 @@ static bool nfc_rpc_command_callback(RpcAppSystemEvent event, const char* arg, v
|
|||||||
if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) {
|
if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) {
|
||||||
nfc_worker_start(
|
nfc_worker_start(
|
||||||
nfc->worker,
|
nfc->worker,
|
||||||
NfcWorkerStateEmulateMifareUltralight,
|
NfcWorkerStateMfUltralightEmulate,
|
||||||
&nfc->dev->dev_data,
|
&nfc->dev->dev_data,
|
||||||
nfc_rpc_emulate_callback,
|
nfc_rpc_emulate_callback,
|
||||||
nfc);
|
nfc);
|
||||||
} else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) {
|
} else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) {
|
||||||
nfc_worker_start(
|
nfc_worker_start(
|
||||||
nfc->worker,
|
nfc->worker,
|
||||||
NfcWorkerStateEmulateMifareClassic,
|
NfcWorkerStateMfClassicEmulate,
|
||||||
&nfc->dev->dev_data,
|
&nfc->dev->dev_data,
|
||||||
nfc_rpc_emulate_callback,
|
nfc_rpc_emulate_callback,
|
||||||
nfc);
|
nfc);
|
||||||
} else {
|
} else {
|
||||||
nfc_worker_start(
|
nfc_worker_start(
|
||||||
nfc->worker, NfcWorkerStateEmulate, &nfc->dev->dev_data, NULL, nfc);
|
nfc->worker, NfcWorkerStateUidEmulate, &nfc->dev->dev_data, NULL, nfc);
|
||||||
}
|
}
|
||||||
nfc->rpc_state = NfcRpcStateEmulating;
|
nfc->rpc_state = NfcRpcStateEmulating;
|
||||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventRpcLoad);
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventRpcLoad);
|
||||||
@@ -102,7 +97,6 @@ Nfc* nfc_alloc() {
|
|||||||
view_dispatcher_set_event_callback_context(nfc->view_dispatcher, nfc);
|
view_dispatcher_set_event_callback_context(nfc->view_dispatcher, nfc);
|
||||||
view_dispatcher_set_custom_event_callback(nfc->view_dispatcher, nfc_custom_event_callback);
|
view_dispatcher_set_custom_event_callback(nfc->view_dispatcher, nfc_custom_event_callback);
|
||||||
view_dispatcher_set_navigation_event_callback(nfc->view_dispatcher, nfc_back_event_callback);
|
view_dispatcher_set_navigation_event_callback(nfc->view_dispatcher, nfc_back_event_callback);
|
||||||
view_dispatcher_set_tick_event_callback(nfc->view_dispatcher, nfc_tick_event_callback, 100);
|
|
||||||
|
|
||||||
// Nfc device
|
// Nfc device
|
||||||
nfc->dev = nfc_device_alloc();
|
nfc->dev = nfc_device_alloc();
|
||||||
@@ -155,7 +149,7 @@ Nfc* nfc_alloc() {
|
|||||||
view_dispatcher_add_view(
|
view_dispatcher_add_view(
|
||||||
nfc->view_dispatcher, NfcViewBankCard, bank_card_get_view(nfc->bank_card));
|
nfc->view_dispatcher, NfcViewBankCard, bank_card_get_view(nfc->bank_card));
|
||||||
|
|
||||||
// Dict Attack
|
// Mifare Classic Dict Attack
|
||||||
nfc->dict_attack = dict_attack_alloc();
|
nfc->dict_attack = dict_attack_alloc();
|
||||||
view_dispatcher_add_view(
|
view_dispatcher_add_view(
|
||||||
nfc->view_dispatcher, NfcViewDictAttack, dict_attack_get_view(nfc->dict_attack));
|
nfc->view_dispatcher, NfcViewDictAttack, dict_attack_get_view(nfc->dict_attack));
|
||||||
@@ -209,7 +203,7 @@ void nfc_free(Nfc* nfc) {
|
|||||||
view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewBankCard);
|
view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewBankCard);
|
||||||
bank_card_free(nfc->bank_card);
|
bank_card_free(nfc->bank_card);
|
||||||
|
|
||||||
// Dict Attack
|
// Mifare Classic Dict Attack
|
||||||
view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewDictAttack);
|
view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewDictAttack);
|
||||||
dict_attack_free(nfc->dict_attack);
|
dict_attack_free(nfc->dict_attack);
|
||||||
|
|
||||||
@@ -301,9 +295,9 @@ int32_t nfc_app(void* p) {
|
|||||||
nfc->view_dispatcher, nfc->gui, ViewDispatcherTypeFullscreen);
|
nfc->view_dispatcher, nfc->gui, ViewDispatcherTypeFullscreen);
|
||||||
if(nfc_device_load(nfc->dev, p, true)) {
|
if(nfc_device_load(nfc->dev, p, true)) {
|
||||||
if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) {
|
if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareUl);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate);
|
||||||
} else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) {
|
} else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareClassic);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate);
|
||||||
} else {
|
} else {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
#include <furi.h>
|
#include <furi.h>
|
||||||
#include <furi_hal.h>
|
#include <furi_hal.h>
|
||||||
#include <cli/cli.h>
|
#include <cli/cli.h>
|
||||||
#include <toolbox/args.h>
|
#include <lib/toolbox/args.h>
|
||||||
|
|
||||||
#include "nfc_types.h"
|
#include <lib/nfc/nfc_types.h>
|
||||||
|
#include <lib/nfc/nfc_device.h>
|
||||||
|
|
||||||
static void nfc_cli_print_usage() {
|
static void nfc_cli_print_usage() {
|
||||||
printf("Usage:\r\n");
|
printf("Usage:\r\n");
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "nfc.h"
|
#include "nfc.h"
|
||||||
#include "nfc_types.h"
|
|
||||||
#include "nfc_worker.h"
|
|
||||||
#include "nfc_device.h"
|
|
||||||
|
|
||||||
#include <furi.h>
|
#include <furi.h>
|
||||||
#include <furi_hal.h>
|
#include <furi_hal.h>
|
||||||
@@ -24,6 +21,11 @@
|
|||||||
#include <gui/modules/text_box.h>
|
#include <gui/modules/text_box.h>
|
||||||
#include <gui/modules/widget.h>
|
#include <gui/modules/widget.h>
|
||||||
|
|
||||||
|
#include <lib/nfc/nfc_types.h>
|
||||||
|
#include <lib/nfc/nfc_worker.h>
|
||||||
|
#include <lib/nfc/nfc_device.h>
|
||||||
|
#include <lib/nfc/helpers/mf_classic_dict.h>
|
||||||
|
|
||||||
#include "views/bank_card.h"
|
#include "views/bank_card.h"
|
||||||
#include "views/dict_attack.h"
|
#include "views/dict_attack.h"
|
||||||
|
|
||||||
@@ -32,8 +34,6 @@
|
|||||||
|
|
||||||
#include "rpc/rpc_app.h"
|
#include "rpc/rpc_app.h"
|
||||||
|
|
||||||
#define NFC_SEND_NOTIFICATION_FALSE (0UL)
|
|
||||||
#define NFC_SEND_NOTIFICATION_TRUE (1UL)
|
|
||||||
#define NFC_TEXT_STORE_SIZE 128
|
#define NFC_TEXT_STORE_SIZE 128
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@@ -56,6 +56,7 @@ struct Nfc {
|
|||||||
|
|
||||||
char text_store[NFC_TEXT_STORE_SIZE + 1];
|
char text_store[NFC_TEXT_STORE_SIZE + 1];
|
||||||
string_t text_box_store;
|
string_t text_box_store;
|
||||||
|
uint8_t byte_input_store[6];
|
||||||
|
|
||||||
void* rpc_ctx;
|
void* rpc_ctx;
|
||||||
NfcRpcState rpc_state;
|
NfcRpcState rpc_state;
|
||||||
|
|||||||
@@ -1,708 +0,0 @@
|
|||||||
#include "nfc_worker_i.h"
|
|
||||||
#include <furi_hal.h>
|
|
||||||
|
|
||||||
#include <platform.h>
|
|
||||||
|
|
||||||
#define TAG "NfcWorker"
|
|
||||||
|
|
||||||
/***************************** NFC Worker API *******************************/
|
|
||||||
|
|
||||||
NfcWorker* nfc_worker_alloc() {
|
|
||||||
NfcWorker* nfc_worker = malloc(sizeof(NfcWorker));
|
|
||||||
|
|
||||||
// Worker thread attributes
|
|
||||||
nfc_worker->thread = furi_thread_alloc();
|
|
||||||
furi_thread_set_name(nfc_worker->thread, "NfcWorker");
|
|
||||||
furi_thread_set_stack_size(nfc_worker->thread, 8192);
|
|
||||||
furi_thread_set_callback(nfc_worker->thread, nfc_worker_task);
|
|
||||||
furi_thread_set_context(nfc_worker->thread, nfc_worker);
|
|
||||||
|
|
||||||
nfc_worker->callback = NULL;
|
|
||||||
nfc_worker->context = NULL;
|
|
||||||
nfc_worker->storage = furi_record_open(RECORD_STORAGE);
|
|
||||||
|
|
||||||
// Initialize rfal
|
|
||||||
while(furi_hal_nfc_is_busy()) {
|
|
||||||
furi_delay_ms(10);
|
|
||||||
}
|
|
||||||
nfc_worker_change_state(nfc_worker, NfcWorkerStateReady);
|
|
||||||
|
|
||||||
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
|
|
||||||
nfc_worker->debug_pcap_worker = nfc_debug_pcap_alloc(nfc_worker->storage);
|
|
||||||
}
|
|
||||||
|
|
||||||
return nfc_worker;
|
|
||||||
}
|
|
||||||
|
|
||||||
void nfc_worker_free(NfcWorker* nfc_worker) {
|
|
||||||
furi_assert(nfc_worker);
|
|
||||||
|
|
||||||
furi_thread_free(nfc_worker->thread);
|
|
||||||
|
|
||||||
furi_record_close(RECORD_STORAGE);
|
|
||||||
|
|
||||||
if(nfc_worker->debug_pcap_worker) nfc_debug_pcap_free(nfc_worker->debug_pcap_worker);
|
|
||||||
|
|
||||||
free(nfc_worker);
|
|
||||||
}
|
|
||||||
|
|
||||||
NfcWorkerState nfc_worker_get_state(NfcWorker* nfc_worker) {
|
|
||||||
return nfc_worker->state;
|
|
||||||
}
|
|
||||||
|
|
||||||
void nfc_worker_start(
|
|
||||||
NfcWorker* nfc_worker,
|
|
||||||
NfcWorkerState state,
|
|
||||||
NfcDeviceData* dev_data,
|
|
||||||
NfcWorkerCallback callback,
|
|
||||||
void* context) {
|
|
||||||
furi_assert(nfc_worker);
|
|
||||||
furi_assert(dev_data);
|
|
||||||
while(furi_hal_nfc_is_busy()) {
|
|
||||||
furi_delay_ms(10);
|
|
||||||
}
|
|
||||||
|
|
||||||
nfc_worker->callback = callback;
|
|
||||||
nfc_worker->context = context;
|
|
||||||
nfc_worker->dev_data = dev_data;
|
|
||||||
nfc_worker_change_state(nfc_worker, state);
|
|
||||||
furi_thread_start(nfc_worker->thread);
|
|
||||||
}
|
|
||||||
|
|
||||||
void nfc_worker_stop(NfcWorker* nfc_worker) {
|
|
||||||
furi_assert(nfc_worker);
|
|
||||||
if(nfc_worker->state == NfcWorkerStateBroken || nfc_worker->state == NfcWorkerStateReady) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
furi_hal_nfc_stop();
|
|
||||||
nfc_worker_change_state(nfc_worker, NfcWorkerStateStop);
|
|
||||||
furi_thread_join(nfc_worker->thread);
|
|
||||||
}
|
|
||||||
|
|
||||||
void nfc_worker_change_state(NfcWorker* nfc_worker, NfcWorkerState state) {
|
|
||||||
nfc_worker->state = state;
|
|
||||||
}
|
|
||||||
|
|
||||||
/***************************** NFC Worker Thread *******************************/
|
|
||||||
|
|
||||||
int32_t nfc_worker_task(void* context) {
|
|
||||||
NfcWorker* nfc_worker = context;
|
|
||||||
|
|
||||||
furi_hal_nfc_exit_sleep();
|
|
||||||
|
|
||||||
if(nfc_worker->state == NfcWorkerStateDetect) {
|
|
||||||
nfc_worker_detect(nfc_worker);
|
|
||||||
} else if(nfc_worker->state == NfcWorkerStateEmulate) {
|
|
||||||
nfc_worker_emulate(nfc_worker);
|
|
||||||
} else if(nfc_worker->state == NfcWorkerStateReadEMVApp) {
|
|
||||||
nfc_worker_read_emv_app(nfc_worker);
|
|
||||||
} else if(nfc_worker->state == NfcWorkerStateReadEMVData) {
|
|
||||||
nfc_worker_read_emv(nfc_worker);
|
|
||||||
} else if(nfc_worker->state == NfcWorkerStateEmulateApdu) {
|
|
||||||
nfc_worker_emulate_apdu(nfc_worker);
|
|
||||||
} else if(nfc_worker->state == NfcWorkerStateReadMifareUltralight) {
|
|
||||||
nfc_worker_read_mifare_ultralight(nfc_worker);
|
|
||||||
} else if(nfc_worker->state == NfcWorkerStateEmulateMifareUltralight) {
|
|
||||||
nfc_worker_emulate_mifare_ul(nfc_worker);
|
|
||||||
} else if(nfc_worker->state == NfcWorkerStateReadMifareClassic) {
|
|
||||||
nfc_worker_mifare_classic_dict_attack(nfc_worker);
|
|
||||||
} else if(nfc_worker->state == NfcWorkerStateEmulateMifareClassic) {
|
|
||||||
nfc_worker_emulate_mifare_classic(nfc_worker);
|
|
||||||
} else if(nfc_worker->state == NfcWorkerStateReadMifareDesfire) {
|
|
||||||
nfc_worker_read_mifare_desfire(nfc_worker);
|
|
||||||
}
|
|
||||||
furi_hal_nfc_sleep();
|
|
||||||
nfc_worker_change_state(nfc_worker, NfcWorkerStateReady);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void nfc_worker_detect(NfcWorker* nfc_worker) {
|
|
||||||
nfc_device_data_clear(nfc_worker->dev_data);
|
|
||||||
NfcDeviceData* dev_data = nfc_worker->dev_data;
|
|
||||||
FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
|
|
||||||
|
|
||||||
while(nfc_worker->state == NfcWorkerStateDetect) {
|
|
||||||
if(furi_hal_nfc_detect(nfc_data, 1000)) {
|
|
||||||
// Process first found device
|
|
||||||
if(nfc_data->type == FuriHalNfcTypeA) {
|
|
||||||
if(mf_ul_check_card_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) {
|
|
||||||
dev_data->protocol = NfcDeviceProtocolMifareUl;
|
|
||||||
} else if(mf_classic_check_card_type(
|
|
||||||
nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) {
|
|
||||||
dev_data->protocol = NfcDeviceProtocolMifareClassic;
|
|
||||||
} else if(mf_df_check_card_type(
|
|
||||||
nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) {
|
|
||||||
dev_data->protocol = NfcDeviceProtocolMifareDesfire;
|
|
||||||
} else if(nfc_data->interface == FuriHalNfcInterfaceIsoDep) {
|
|
||||||
dev_data->protocol = NfcDeviceProtocolEMV;
|
|
||||||
} else {
|
|
||||||
dev_data->protocol = NfcDeviceProtocolUnknown;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Notify caller and exit
|
|
||||||
if(nfc_worker->callback) {
|
|
||||||
nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
furi_hal_nfc_sleep();
|
|
||||||
furi_delay_ms(100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void nfc_worker_emulate(NfcWorker* nfc_worker) {
|
|
||||||
FuriHalNfcTxRxContext tx_rx = {};
|
|
||||||
nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, &tx_rx, true);
|
|
||||||
FuriHalNfcDevData* data = &nfc_worker->dev_data->nfc_data;
|
|
||||||
NfcReaderRequestData* reader_data = &nfc_worker->dev_data->reader_data;
|
|
||||||
|
|
||||||
while(nfc_worker->state == NfcWorkerStateEmulate) {
|
|
||||||
if(furi_hal_nfc_listen(data->uid, data->uid_len, data->atqa, data->sak, true, 100)) {
|
|
||||||
if(furi_hal_nfc_tx_rx(&tx_rx, 100)) {
|
|
||||||
reader_data->size = tx_rx.rx_bits / 8;
|
|
||||||
if(reader_data->size > 0) {
|
|
||||||
memcpy(reader_data->data, tx_rx.rx_data, reader_data->size);
|
|
||||||
if(nfc_worker->callback) {
|
|
||||||
nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
FURI_LOG_E(TAG, "Failed to get reader commands");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void nfc_worker_read_emv_app(NfcWorker* nfc_worker) {
|
|
||||||
FuriHalNfcTxRxContext tx_rx = {};
|
|
||||||
nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, &tx_rx, false);
|
|
||||||
EmvApplication emv_app = {};
|
|
||||||
NfcDeviceData* result = nfc_worker->dev_data;
|
|
||||||
FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
|
|
||||||
nfc_device_data_clear(result);
|
|
||||||
|
|
||||||
while(nfc_worker->state == NfcWorkerStateReadEMVApp) {
|
|
||||||
if(furi_hal_nfc_detect(nfc_data, 1000)) {
|
|
||||||
// Card was found. Check that it supports EMV
|
|
||||||
if(nfc_data->interface == FuriHalNfcInterfaceIsoDep) {
|
|
||||||
result->protocol = NfcDeviceProtocolEMV;
|
|
||||||
if(emv_search_application(&tx_rx, &emv_app)) {
|
|
||||||
// Notify caller and exit
|
|
||||||
result->emv_data.aid_len = emv_app.aid_len;
|
|
||||||
memcpy(result->emv_data.aid, emv_app.aid, emv_app.aid_len);
|
|
||||||
if(nfc_worker->callback) {
|
|
||||||
nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
FURI_LOG_W(TAG, "Card doesn't support EMV");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
FURI_LOG_D(TAG, "Can't find any cards");
|
|
||||||
}
|
|
||||||
furi_hal_nfc_sleep();
|
|
||||||
furi_delay_ms(20);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void nfc_worker_read_emv(NfcWorker* nfc_worker) {
|
|
||||||
FuriHalNfcTxRxContext tx_rx = {};
|
|
||||||
nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, &tx_rx, false);
|
|
||||||
EmvApplication emv_app = {};
|
|
||||||
NfcDeviceData* result = nfc_worker->dev_data;
|
|
||||||
FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
|
|
||||||
nfc_device_data_clear(result);
|
|
||||||
|
|
||||||
while(nfc_worker->state == NfcWorkerStateReadEMVData) {
|
|
||||||
if(furi_hal_nfc_detect(nfc_data, 1000)) {
|
|
||||||
// Card was found. Check that it supports EMV
|
|
||||||
if(nfc_data->interface == FuriHalNfcInterfaceIsoDep) {
|
|
||||||
result->protocol = NfcDeviceProtocolEMV;
|
|
||||||
if(emv_read_bank_card(&tx_rx, &emv_app)) {
|
|
||||||
result->emv_data.number_len = emv_app.card_number_len;
|
|
||||||
memcpy(
|
|
||||||
result->emv_data.number, emv_app.card_number, result->emv_data.number_len);
|
|
||||||
result->emv_data.aid_len = emv_app.aid_len;
|
|
||||||
memcpy(result->emv_data.aid, emv_app.aid, emv_app.aid_len);
|
|
||||||
if(emv_app.name_found) {
|
|
||||||
memcpy(result->emv_data.name, emv_app.name, sizeof(emv_app.name));
|
|
||||||
}
|
|
||||||
if(emv_app.exp_month) {
|
|
||||||
result->emv_data.exp_mon = emv_app.exp_month;
|
|
||||||
result->emv_data.exp_year = emv_app.exp_year;
|
|
||||||
}
|
|
||||||
if(emv_app.country_code) {
|
|
||||||
result->emv_data.country_code = emv_app.country_code;
|
|
||||||
}
|
|
||||||
if(emv_app.currency_code) {
|
|
||||||
result->emv_data.currency_code = emv_app.currency_code;
|
|
||||||
}
|
|
||||||
// Notify caller and exit
|
|
||||||
if(nfc_worker->callback) {
|
|
||||||
nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
FURI_LOG_W(TAG, "Card doesn't support EMV");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
FURI_LOG_D(TAG, "Can't find any cards");
|
|
||||||
}
|
|
||||||
furi_hal_nfc_sleep();
|
|
||||||
furi_delay_ms(20);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void nfc_worker_emulate_apdu(NfcWorker* nfc_worker) {
|
|
||||||
FuriHalNfcTxRxContext tx_rx = {};
|
|
||||||
nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, &tx_rx, true);
|
|
||||||
FuriHalNfcDevData params = {
|
|
||||||
.uid = {0xCF, 0x72, 0xd4, 0x40},
|
|
||||||
.uid_len = 4,
|
|
||||||
.atqa = {0x00, 0x04},
|
|
||||||
.sak = 0x20,
|
|
||||||
.type = FuriHalNfcTypeA,
|
|
||||||
};
|
|
||||||
|
|
||||||
while(nfc_worker->state == NfcWorkerStateEmulateApdu) {
|
|
||||||
if(furi_hal_nfc_listen(params.uid, params.uid_len, params.atqa, params.sak, false, 300)) {
|
|
||||||
FURI_LOG_D(TAG, "POS terminal detected");
|
|
||||||
if(emv_card_emulation(&tx_rx)) {
|
|
||||||
FURI_LOG_D(TAG, "EMV card emulated");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
FURI_LOG_D(TAG, "Can't find reader");
|
|
||||||
}
|
|
||||||
furi_hal_nfc_sleep();
|
|
||||||
furi_delay_ms(20);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void nfc_worker_read_mifare_ultralight(NfcWorker* nfc_worker) {
|
|
||||||
FuriHalNfcTxRxContext tx_rx = {};
|
|
||||||
nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, &tx_rx, false);
|
|
||||||
MfUltralightReader reader = {};
|
|
||||||
MfUltralightData data = {};
|
|
||||||
NfcDeviceData* result = nfc_worker->dev_data;
|
|
||||||
FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
|
|
||||||
|
|
||||||
while(nfc_worker->state == NfcWorkerStateReadMifareUltralight) {
|
|
||||||
if(furi_hal_nfc_detect(nfc_data, 300)) {
|
|
||||||
if(nfc_data->type == FuriHalNfcTypeA &&
|
|
||||||
mf_ul_check_card_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) {
|
|
||||||
FURI_LOG_D(TAG, "Found Mifare Ultralight tag. Start reading");
|
|
||||||
if(mf_ul_read_card(&tx_rx, &reader, &data)) {
|
|
||||||
result->protocol = NfcDeviceProtocolMifareUl;
|
|
||||||
result->mf_ul_data = data;
|
|
||||||
// Notify caller and exit
|
|
||||||
if(nfc_worker->callback) {
|
|
||||||
nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
FURI_LOG_D(TAG, "Failed reading Mifare Ultralight");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
FURI_LOG_W(TAG, "Tag is not Mifare Ultralight");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
FURI_LOG_D(TAG, "Can't find any tags");
|
|
||||||
}
|
|
||||||
furi_hal_nfc_sleep();
|
|
||||||
furi_delay_ms(100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void nfc_worker_emulate_mifare_ul(NfcWorker* nfc_worker) {
|
|
||||||
FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
|
|
||||||
MfUltralightEmulator emulator = {};
|
|
||||||
mf_ul_prepare_emulation(&emulator, &nfc_worker->dev_data->mf_ul_data);
|
|
||||||
while(nfc_worker->state == NfcWorkerStateEmulateMifareUltralight) {
|
|
||||||
mf_ul_reset_emulation(&emulator, true);
|
|
||||||
furi_hal_nfc_emulate_nfca(
|
|
||||||
nfc_data->uid,
|
|
||||||
nfc_data->uid_len,
|
|
||||||
nfc_data->atqa,
|
|
||||||
nfc_data->sak,
|
|
||||||
mf_ul_prepare_emulation_response,
|
|
||||||
&emulator,
|
|
||||||
5000);
|
|
||||||
// Check if data was modified
|
|
||||||
if(emulator.data_changed) {
|
|
||||||
nfc_worker->dev_data->mf_ul_data = emulator.data;
|
|
||||||
if(nfc_worker->callback) {
|
|
||||||
nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
|
|
||||||
}
|
|
||||||
emulator.data_changed = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) {
|
|
||||||
furi_assert(nfc_worker->callback);
|
|
||||||
FuriHalNfcTxRxContext tx_rx_ctx = {};
|
|
||||||
nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, &tx_rx_ctx, false);
|
|
||||||
MfClassicAuthContext auth_ctx = {};
|
|
||||||
MfClassicReader reader = {};
|
|
||||||
uint64_t curr_key = 0;
|
|
||||||
uint16_t curr_sector = 0;
|
|
||||||
uint8_t total_sectors = 0;
|
|
||||||
NfcWorkerEvent event;
|
|
||||||
FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
|
|
||||||
|
|
||||||
// Open dictionary
|
|
||||||
nfc_worker->dict_stream = file_stream_alloc(nfc_worker->storage);
|
|
||||||
if(!nfc_mf_classic_dict_open_file(nfc_worker->dict_stream)) {
|
|
||||||
event = NfcWorkerEventNoDictFound;
|
|
||||||
nfc_worker->callback(event, nfc_worker->context);
|
|
||||||
nfc_mf_classic_dict_close_file(nfc_worker->dict_stream);
|
|
||||||
stream_free(nfc_worker->dict_stream);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Detect Mifare Classic card
|
|
||||||
while(nfc_worker->state == NfcWorkerStateReadMifareClassic) {
|
|
||||||
if(furi_hal_nfc_detect(nfc_data, 300)) {
|
|
||||||
if(mf_classic_get_type(
|
|
||||||
nfc_data->uid,
|
|
||||||
nfc_data->uid_len,
|
|
||||||
nfc_data->atqa[0],
|
|
||||||
nfc_data->atqa[1],
|
|
||||||
nfc_data->sak,
|
|
||||||
&reader)) {
|
|
||||||
total_sectors = mf_classic_get_total_sectors_num(&reader);
|
|
||||||
if(reader.type == MfClassicType1k) {
|
|
||||||
event = NfcWorkerEventDetectedClassic1k;
|
|
||||||
} else {
|
|
||||||
event = NfcWorkerEventDetectedClassic4k;
|
|
||||||
}
|
|
||||||
nfc_worker->callback(event, nfc_worker->context);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
event = NfcWorkerEventNoCardDetected;
|
|
||||||
nfc_worker->callback(event, nfc_worker->context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(nfc_worker->state == NfcWorkerStateReadMifareClassic) {
|
|
||||||
bool card_removed_notified = false;
|
|
||||||
bool card_found_notified = false;
|
|
||||||
// Seek for mifare classic keys
|
|
||||||
for(curr_sector = 0; curr_sector < total_sectors; curr_sector++) {
|
|
||||||
FURI_LOG_I(TAG, "Sector: %d ...", curr_sector);
|
|
||||||
event = NfcWorkerEventNewSector;
|
|
||||||
nfc_worker->callback(event, nfc_worker->context);
|
|
||||||
mf_classic_auth_init_context(&auth_ctx, reader.cuid, curr_sector);
|
|
||||||
bool sector_key_found = false;
|
|
||||||
while(nfc_mf_classic_dict_get_next_key(nfc_worker->dict_stream, &curr_key)) {
|
|
||||||
furi_hal_nfc_sleep();
|
|
||||||
if(furi_hal_nfc_activate_nfca(300, &reader.cuid)) {
|
|
||||||
if(!card_found_notified) {
|
|
||||||
if(reader.type == MfClassicType1k) {
|
|
||||||
event = NfcWorkerEventDetectedClassic1k;
|
|
||||||
} else {
|
|
||||||
event = NfcWorkerEventDetectedClassic4k;
|
|
||||||
}
|
|
||||||
nfc_worker->callback(event, nfc_worker->context);
|
|
||||||
card_found_notified = true;
|
|
||||||
card_removed_notified = false;
|
|
||||||
}
|
|
||||||
FURI_LOG_D(
|
|
||||||
TAG,
|
|
||||||
"Try to auth to sector %d with key %04lx%08lx",
|
|
||||||
curr_sector,
|
|
||||||
(uint32_t)(curr_key >> 32),
|
|
||||||
(uint32_t)curr_key);
|
|
||||||
if(mf_classic_auth_attempt(&tx_rx_ctx, &auth_ctx, curr_key)) {
|
|
||||||
sector_key_found = true;
|
|
||||||
if((auth_ctx.key_a != MF_CLASSIC_NO_KEY) &&
|
|
||||||
(auth_ctx.key_b != MF_CLASSIC_NO_KEY))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Notify that no tag is availalble
|
|
||||||
FURI_LOG_D(TAG, "Can't find tags");
|
|
||||||
if(!card_removed_notified) {
|
|
||||||
event = NfcWorkerEventNoCardDetected;
|
|
||||||
nfc_worker->callback(event, nfc_worker->context);
|
|
||||||
card_removed_notified = true;
|
|
||||||
card_found_notified = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(nfc_worker->state != NfcWorkerStateReadMifareClassic) break;
|
|
||||||
furi_delay_tick(1);
|
|
||||||
}
|
|
||||||
if(nfc_worker->state != NfcWorkerStateReadMifareClassic) break;
|
|
||||||
if(sector_key_found) {
|
|
||||||
// Notify that keys were found
|
|
||||||
if(auth_ctx.key_a != MF_CLASSIC_NO_KEY) {
|
|
||||||
FURI_LOG_I(
|
|
||||||
TAG,
|
|
||||||
"Sector %d key A: %04lx%08lx",
|
|
||||||
curr_sector,
|
|
||||||
(uint32_t)(auth_ctx.key_a >> 32),
|
|
||||||
(uint32_t)auth_ctx.key_a);
|
|
||||||
event = NfcWorkerEventFoundKeyA;
|
|
||||||
nfc_worker->callback(event, nfc_worker->context);
|
|
||||||
}
|
|
||||||
if(auth_ctx.key_b != MF_CLASSIC_NO_KEY) {
|
|
||||||
FURI_LOG_I(
|
|
||||||
TAG,
|
|
||||||
"Sector %d key B: %04lx%08lx",
|
|
||||||
curr_sector,
|
|
||||||
(uint32_t)(auth_ctx.key_b >> 32),
|
|
||||||
(uint32_t)auth_ctx.key_b);
|
|
||||||
event = NfcWorkerEventFoundKeyB;
|
|
||||||
nfc_worker->callback(event, nfc_worker->context);
|
|
||||||
}
|
|
||||||
// Add sectors to read sequence
|
|
||||||
mf_classic_reader_add_sector(&reader, curr_sector, auth_ctx.key_a, auth_ctx.key_b);
|
|
||||||
}
|
|
||||||
nfc_mf_classic_dict_reset(nfc_worker->dict_stream);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(nfc_worker->state == NfcWorkerStateReadMifareClassic) {
|
|
||||||
FURI_LOG_I(TAG, "Found keys to %d sectors. Start reading sectors", reader.sectors_to_read);
|
|
||||||
uint8_t sectors_read =
|
|
||||||
mf_classic_read_card(&tx_rx_ctx, &reader, &nfc_worker->dev_data->mf_classic_data);
|
|
||||||
if(sectors_read) {
|
|
||||||
event = NfcWorkerEventSuccess;
|
|
||||||
nfc_worker->dev_data->protocol = NfcDeviceProtocolMifareClassic;
|
|
||||||
FURI_LOG_I(TAG, "Successfully read %d sectors", sectors_read);
|
|
||||||
} else {
|
|
||||||
event = NfcWorkerEventFail;
|
|
||||||
FURI_LOG_W(TAG, "Failed to read any sector");
|
|
||||||
}
|
|
||||||
nfc_worker->callback(event, nfc_worker->context);
|
|
||||||
}
|
|
||||||
|
|
||||||
nfc_mf_classic_dict_close_file(nfc_worker->dict_stream);
|
|
||||||
stream_free(nfc_worker->dict_stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
void nfc_worker_emulate_mifare_classic(NfcWorker* nfc_worker) {
|
|
||||||
FuriHalNfcTxRxContext tx_rx = {};
|
|
||||||
nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, &tx_rx, true);
|
|
||||||
FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
|
|
||||||
MfClassicEmulator emulator = {
|
|
||||||
.cuid = nfc_util_bytes2num(&nfc_data->uid[nfc_data->uid_len - 4], 4),
|
|
||||||
.data = nfc_worker->dev_data->mf_classic_data,
|
|
||||||
.data_changed = false,
|
|
||||||
};
|
|
||||||
NfcaSignal* nfca_signal = nfca_signal_alloc();
|
|
||||||
tx_rx.nfca_signal = nfca_signal;
|
|
||||||
|
|
||||||
rfal_platform_spi_acquire();
|
|
||||||
|
|
||||||
furi_hal_nfc_listen_start(nfc_data);
|
|
||||||
while(nfc_worker->state == NfcWorkerStateEmulateMifareClassic) {
|
|
||||||
if(furi_hal_nfc_listen_rx(&tx_rx, 300)) {
|
|
||||||
mf_classic_emulator(&emulator, &tx_rx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(emulator.data_changed) {
|
|
||||||
nfc_worker->dev_data->mf_classic_data = emulator.data;
|
|
||||||
if(nfc_worker->callback) {
|
|
||||||
nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
|
|
||||||
}
|
|
||||||
emulator.data_changed = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
nfca_signal_free(nfca_signal);
|
|
||||||
|
|
||||||
rfal_platform_spi_release();
|
|
||||||
}
|
|
||||||
|
|
||||||
void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) {
|
|
||||||
FuriHalNfcTxRxContext tx_rx = {};
|
|
||||||
nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, &tx_rx, false);
|
|
||||||
NfcDeviceData* result = nfc_worker->dev_data;
|
|
||||||
nfc_device_data_clear(result);
|
|
||||||
MifareDesfireData* data = &result->mf_df_data;
|
|
||||||
FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
|
|
||||||
|
|
||||||
while(nfc_worker->state == NfcWorkerStateReadMifareDesfire) {
|
|
||||||
furi_hal_nfc_sleep();
|
|
||||||
if(!furi_hal_nfc_detect(nfc_data, 300)) {
|
|
||||||
furi_delay_ms(100);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
memset(data, 0, sizeof(MifareDesfireData));
|
|
||||||
if(nfc_data->type != FuriHalNfcTypeA ||
|
|
||||||
!mf_df_check_card_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) {
|
|
||||||
FURI_LOG_D(TAG, "Tag is not DESFire");
|
|
||||||
furi_delay_ms(100);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
FURI_LOG_D(TAG, "Found DESFire tag");
|
|
||||||
|
|
||||||
result->protocol = NfcDeviceProtocolMifareDesfire;
|
|
||||||
|
|
||||||
// Get DESFire version
|
|
||||||
tx_rx.tx_bits = 8 * mf_df_prepare_get_version(tx_rx.tx_data);
|
|
||||||
if(!furi_hal_nfc_tx_rx_full(&tx_rx)) {
|
|
||||||
FURI_LOG_W(TAG, "Bad exchange getting version");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if(!mf_df_parse_get_version_response(tx_rx.rx_data, tx_rx.rx_bits / 8, &data->version)) {
|
|
||||||
FURI_LOG_W(TAG, "Bad DESFire GET_VERSION response");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
tx_rx.tx_bits = 8 * mf_df_prepare_get_free_memory(tx_rx.tx_data);
|
|
||||||
if(furi_hal_nfc_tx_rx_full(&tx_rx)) {
|
|
||||||
data->free_memory = malloc(sizeof(MifareDesfireFreeMemory));
|
|
||||||
memset(data->free_memory, 0, sizeof(MifareDesfireFreeMemory));
|
|
||||||
if(!mf_df_parse_get_free_memory_response(
|
|
||||||
tx_rx.rx_data, tx_rx.rx_bits / 8, data->free_memory)) {
|
|
||||||
FURI_LOG_D(TAG, "Bad DESFire GET_FREE_MEMORY response (normal for pre-EV1 cards)");
|
|
||||||
free(data->free_memory);
|
|
||||||
data->free_memory = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tx_rx.tx_bits = 8 * mf_df_prepare_get_key_settings(tx_rx.tx_data);
|
|
||||||
if(!furi_hal_nfc_tx_rx_full(&tx_rx)) {
|
|
||||||
FURI_LOG_D(TAG, "Bad exchange getting key settings");
|
|
||||||
} else {
|
|
||||||
data->master_key_settings = malloc(sizeof(MifareDesfireKeySettings));
|
|
||||||
memset(data->master_key_settings, 0, sizeof(MifareDesfireKeySettings));
|
|
||||||
if(!mf_df_parse_get_key_settings_response(
|
|
||||||
tx_rx.rx_data, tx_rx.rx_bits / 8, data->master_key_settings)) {
|
|
||||||
FURI_LOG_W(TAG, "Bad DESFire GET_KEY_SETTINGS response");
|
|
||||||
free(data->master_key_settings);
|
|
||||||
data->master_key_settings = NULL;
|
|
||||||
} else {
|
|
||||||
MifareDesfireKeyVersion** key_version_head =
|
|
||||||
&data->master_key_settings->key_version_head;
|
|
||||||
for(uint8_t key_id = 0; key_id < data->master_key_settings->max_keys; key_id++) {
|
|
||||||
tx_rx.tx_bits = 8 * mf_df_prepare_get_key_version(tx_rx.tx_data, key_id);
|
|
||||||
if(!furi_hal_nfc_tx_rx_full(&tx_rx)) {
|
|
||||||
FURI_LOG_W(TAG, "Bad exchange getting key version");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
MifareDesfireKeyVersion* key_version = malloc(sizeof(MifareDesfireKeyVersion));
|
|
||||||
memset(key_version, 0, sizeof(MifareDesfireKeyVersion));
|
|
||||||
key_version->id = key_id;
|
|
||||||
if(!mf_df_parse_get_key_version_response(
|
|
||||||
tx_rx.rx_data, tx_rx.rx_bits / 8, key_version)) {
|
|
||||||
FURI_LOG_W(TAG, "Bad DESFire GET_KEY_VERSION response");
|
|
||||||
free(key_version);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
*key_version_head = key_version;
|
|
||||||
key_version_head = &key_version->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tx_rx.tx_bits = 8 * mf_df_prepare_get_application_ids(tx_rx.tx_data);
|
|
||||||
if(!furi_hal_nfc_tx_rx_full(&tx_rx)) {
|
|
||||||
FURI_LOG_W(TAG, "Bad exchange getting application IDs");
|
|
||||||
} else {
|
|
||||||
if(!mf_df_parse_get_application_ids_response(
|
|
||||||
tx_rx.rx_data, tx_rx.rx_bits / 8, &data->app_head)) {
|
|
||||||
FURI_LOG_W(TAG, "Bad DESFire GET_APPLICATION_IDS response");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for(MifareDesfireApplication* app = data->app_head; app; app = app->next) {
|
|
||||||
tx_rx.tx_bits = 8 * mf_df_prepare_select_application(tx_rx.tx_data, app->id);
|
|
||||||
if(!furi_hal_nfc_tx_rx_full(&tx_rx) ||
|
|
||||||
!mf_df_parse_select_application_response(tx_rx.rx_data, tx_rx.rx_bits / 8)) {
|
|
||||||
FURI_LOG_W(TAG, "Bad exchange selecting application");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
tx_rx.tx_bits = 8 * mf_df_prepare_get_key_settings(tx_rx.tx_data);
|
|
||||||
if(!furi_hal_nfc_tx_rx_full(&tx_rx)) {
|
|
||||||
FURI_LOG_W(TAG, "Bad exchange getting key settings");
|
|
||||||
} else {
|
|
||||||
app->key_settings = malloc(sizeof(MifareDesfireKeySettings));
|
|
||||||
memset(app->key_settings, 0, sizeof(MifareDesfireKeySettings));
|
|
||||||
if(!mf_df_parse_get_key_settings_response(
|
|
||||||
tx_rx.rx_data, tx_rx.rx_bits / 8, app->key_settings)) {
|
|
||||||
FURI_LOG_W(TAG, "Bad DESFire GET_KEY_SETTINGS response");
|
|
||||||
free(app->key_settings);
|
|
||||||
app->key_settings = NULL;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
MifareDesfireKeyVersion** key_version_head = &app->key_settings->key_version_head;
|
|
||||||
for(uint8_t key_id = 0; key_id < app->key_settings->max_keys; key_id++) {
|
|
||||||
tx_rx.tx_bits = 8 * mf_df_prepare_get_key_version(tx_rx.tx_data, key_id);
|
|
||||||
if(!furi_hal_nfc_tx_rx_full(&tx_rx)) {
|
|
||||||
FURI_LOG_W(TAG, "Bad exchange getting key version");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
MifareDesfireKeyVersion* key_version = malloc(sizeof(MifareDesfireKeyVersion));
|
|
||||||
memset(key_version, 0, sizeof(MifareDesfireKeyVersion));
|
|
||||||
key_version->id = key_id;
|
|
||||||
if(!mf_df_parse_get_key_version_response(
|
|
||||||
tx_rx.rx_data, tx_rx.rx_bits / 8, key_version)) {
|
|
||||||
FURI_LOG_W(TAG, "Bad DESFire GET_KEY_VERSION response");
|
|
||||||
free(key_version);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
*key_version_head = key_version;
|
|
||||||
key_version_head = &key_version->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tx_rx.tx_bits = 8 * mf_df_prepare_get_file_ids(tx_rx.tx_data);
|
|
||||||
if(!furi_hal_nfc_tx_rx_full(&tx_rx)) {
|
|
||||||
FURI_LOG_W(TAG, "Bad exchange getting file IDs");
|
|
||||||
} else {
|
|
||||||
if(!mf_df_parse_get_file_ids_response(
|
|
||||||
tx_rx.rx_data, tx_rx.rx_bits / 8, &app->file_head)) {
|
|
||||||
FURI_LOG_W(TAG, "Bad DESFire GET_FILE_IDS response");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for(MifareDesfireFile* file = app->file_head; file; file = file->next) {
|
|
||||||
tx_rx.tx_bits = 8 * mf_df_prepare_get_file_settings(tx_rx.tx_data, file->id);
|
|
||||||
if(!furi_hal_nfc_tx_rx_full(&tx_rx)) {
|
|
||||||
FURI_LOG_W(TAG, "Bad exchange getting file settings");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if(!mf_df_parse_get_file_settings_response(
|
|
||||||
tx_rx.rx_data, tx_rx.rx_bits / 8, file)) {
|
|
||||||
FURI_LOG_W(TAG, "Bad DESFire GET_FILE_SETTINGS response");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
switch(file->type) {
|
|
||||||
case MifareDesfireFileTypeStandard:
|
|
||||||
case MifareDesfireFileTypeBackup:
|
|
||||||
tx_rx.tx_bits = 8 * mf_df_prepare_read_data(tx_rx.tx_data, file->id, 0, 0);
|
|
||||||
break;
|
|
||||||
case MifareDesfireFileTypeValue:
|
|
||||||
tx_rx.tx_bits = 8 * mf_df_prepare_get_value(tx_rx.tx_data, file->id);
|
|
||||||
break;
|
|
||||||
case MifareDesfireFileTypeLinearRecord:
|
|
||||||
case MifareDesfireFileTypeCyclicRecord:
|
|
||||||
tx_rx.tx_bits = 8 * mf_df_prepare_read_records(tx_rx.tx_data, file->id, 0, 0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(!furi_hal_nfc_tx_rx_full(&tx_rx)) {
|
|
||||||
FURI_LOG_W(TAG, "Bad exchange reading file %d", file->id);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if(!mf_df_parse_read_data_response(tx_rx.rx_data, tx_rx.rx_bits / 8, file)) {
|
|
||||||
FURI_LOG_W(TAG, "Bad response reading file %d", file->id);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Notify caller and exit
|
|
||||||
if(nfc_worker->callback) {
|
|
||||||
nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "nfc_worker.h"
|
|
||||||
#include "nfc_i.h"
|
|
||||||
|
|
||||||
#include <furi.h>
|
|
||||||
#include <lib/toolbox/stream/file_stream.h>
|
|
||||||
|
|
||||||
#include <lib/nfc_protocols/nfc_util.h>
|
|
||||||
#include <lib/nfc_protocols/emv.h>
|
|
||||||
#include <lib/nfc_protocols/mifare_common.h>
|
|
||||||
#include <lib/nfc_protocols/mifare_ultralight.h>
|
|
||||||
#include <lib/nfc_protocols/mifare_classic.h>
|
|
||||||
#include <lib/nfc_protocols/mifare_desfire.h>
|
|
||||||
#include <lib/nfc_protocols/nfca.h>
|
|
||||||
|
|
||||||
#include "helpers/nfc_mf_classic_dict.h"
|
|
||||||
#include "helpers/nfc_debug_pcap.h"
|
|
||||||
|
|
||||||
struct NfcWorker {
|
|
||||||
FuriThread* thread;
|
|
||||||
Storage* storage;
|
|
||||||
Stream* dict_stream;
|
|
||||||
|
|
||||||
NfcDeviceData* dev_data;
|
|
||||||
|
|
||||||
NfcWorkerCallback callback;
|
|
||||||
void* context;
|
|
||||||
|
|
||||||
NfcWorkerState state;
|
|
||||||
|
|
||||||
NfcDebugPcapWorker* debug_pcap_worker;
|
|
||||||
};
|
|
||||||
|
|
||||||
void nfc_worker_change_state(NfcWorker* nfc_worker, NfcWorkerState state);
|
|
||||||
|
|
||||||
int32_t nfc_worker_task(void* context);
|
|
||||||
|
|
||||||
void nfc_worker_read_emv_app(NfcWorker* nfc_worker);
|
|
||||||
|
|
||||||
void nfc_worker_read_emv(NfcWorker* nfc_worker);
|
|
||||||
|
|
||||||
void nfc_worker_emulate_apdu(NfcWorker* nfc_worker);
|
|
||||||
|
|
||||||
void nfc_worker_detect(NfcWorker* nfc_worker);
|
|
||||||
|
|
||||||
void nfc_worker_emulate(NfcWorker* nfc_worker);
|
|
||||||
|
|
||||||
void nfc_worker_read_mifare_ultralight(NfcWorker* nfc_worker);
|
|
||||||
|
|
||||||
void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker);
|
|
||||||
|
|
||||||
void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker);
|
|
||||||
|
|
||||||
void nfc_worker_emulate_mifare_ul(NfcWorker* nfc_worker);
|
|
||||||
|
|
||||||
void nfc_worker_emulate_mifare_classic(NfcWorker* nfc_worker);
|
|
||||||
@@ -1,90 +0,0 @@
|
|||||||
#include "../nfc_i.h"
|
|
||||||
|
|
||||||
enum SubmenuIndex {
|
|
||||||
SubmenuIndexRunApp,
|
|
||||||
SubmenuIndexChooseScript,
|
|
||||||
SubmenuIndexEmulate,
|
|
||||||
SubmenuIndexSave,
|
|
||||||
};
|
|
||||||
|
|
||||||
void nfc_scene_card_menu_submenu_callback(void* context, uint32_t index) {
|
|
||||||
Nfc* nfc = context;
|
|
||||||
|
|
||||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
void nfc_scene_card_menu_on_enter(void* context) {
|
|
||||||
Nfc* nfc = context;
|
|
||||||
Submenu* submenu = nfc->submenu;
|
|
||||||
|
|
||||||
if(nfc->dev->dev_data.protocol > NfcDeviceProtocolUnknown) {
|
|
||||||
submenu_add_item(
|
|
||||||
submenu,
|
|
||||||
"Run Compatible App",
|
|
||||||
SubmenuIndexRunApp,
|
|
||||||
nfc_scene_card_menu_submenu_callback,
|
|
||||||
nfc);
|
|
||||||
}
|
|
||||||
submenu_add_item(
|
|
||||||
submenu,
|
|
||||||
"Additional reading scripts",
|
|
||||||
SubmenuIndexChooseScript,
|
|
||||||
nfc_scene_card_menu_submenu_callback,
|
|
||||||
nfc);
|
|
||||||
submenu_add_item(
|
|
||||||
submenu, "Emulate UID", SubmenuIndexEmulate, nfc_scene_card_menu_submenu_callback, nfc);
|
|
||||||
submenu_add_item(
|
|
||||||
submenu, "Save UID", SubmenuIndexSave, nfc_scene_card_menu_submenu_callback, nfc);
|
|
||||||
submenu_set_selected_item(
|
|
||||||
nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneCardMenu));
|
|
||||||
|
|
||||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool nfc_scene_card_menu_on_event(void* context, SceneManagerEvent event) {
|
|
||||||
Nfc* nfc = context;
|
|
||||||
bool consumed = false;
|
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
|
||||||
if(event.event == SubmenuIndexRunApp) {
|
|
||||||
scene_manager_set_scene_state(
|
|
||||||
nfc->scene_manager, NfcSceneCardMenu, SubmenuIndexRunApp);
|
|
||||||
if(nfc->dev->dev_data.protocol == NfcDeviceProtocolMifareUl) {
|
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareUl);
|
|
||||||
} else if(nfc->dev->dev_data.protocol == NfcDeviceProtocolMifareDesfire) {
|
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareDesfire);
|
|
||||||
} else if(nfc->dev->dev_data.protocol == NfcDeviceProtocolEMV) {
|
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvApp);
|
|
||||||
} else if(nfc->dev->dev_data.protocol == NfcDeviceProtocolMifareClassic) {
|
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareClassic);
|
|
||||||
}
|
|
||||||
consumed = true;
|
|
||||||
} else if(event.event == SubmenuIndexChooseScript) {
|
|
||||||
scene_manager_set_scene_state(
|
|
||||||
nfc->scene_manager, NfcSceneCardMenu, SubmenuIndexChooseScript);
|
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneScriptsMenu);
|
|
||||||
consumed = true;
|
|
||||||
} else if(event.event == SubmenuIndexEmulate) {
|
|
||||||
scene_manager_set_scene_state(
|
|
||||||
nfc->scene_manager, NfcSceneCardMenu, SubmenuIndexEmulate);
|
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid);
|
|
||||||
consumed = true;
|
|
||||||
} else if(event.event == SubmenuIndexSave) {
|
|
||||||
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneCardMenu, SubmenuIndexSave);
|
|
||||||
nfc->dev->format = NfcDeviceSaveFormatUid;
|
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
|
|
||||||
consumed = true;
|
|
||||||
}
|
|
||||||
} else if(event.type == SceneManagerEventTypeBack) {
|
|
||||||
consumed =
|
|
||||||
scene_manager_search_and_switch_to_previous_scene(nfc->scene_manager, NfcSceneStart);
|
|
||||||
}
|
|
||||||
|
|
||||||
return consumed;
|
|
||||||
}
|
|
||||||
|
|
||||||
void nfc_scene_card_menu_on_exit(void* context) {
|
|
||||||
Nfc* nfc = context;
|
|
||||||
|
|
||||||
submenu_reset(nfc->submenu);
|
|
||||||
}
|
|
||||||
@@ -1,41 +1,40 @@
|
|||||||
ADD_SCENE(nfc, start, Start)
|
ADD_SCENE(nfc, start, Start)
|
||||||
ADD_SCENE(nfc, read_card, ReadCard)
|
ADD_SCENE(nfc, read, Read)
|
||||||
ADD_SCENE(nfc, read_card_success, ReadCardSuccess)
|
|
||||||
ADD_SCENE(nfc, card_menu, CardMenu)
|
|
||||||
ADD_SCENE(nfc, emulate_uid, EmulateUid)
|
|
||||||
ADD_SCENE(nfc, save_name, SaveName)
|
|
||||||
ADD_SCENE(nfc, save_success, SaveSuccess)
|
|
||||||
ADD_SCENE(nfc, file_select, FileSelect)
|
|
||||||
ADD_SCENE(nfc, saved_menu, SavedMenu)
|
ADD_SCENE(nfc, saved_menu, SavedMenu)
|
||||||
|
ADD_SCENE(nfc, extra_actions, ExtraActions)
|
||||||
ADD_SCENE(nfc, set_type, SetType)
|
ADD_SCENE(nfc, set_type, SetType)
|
||||||
ADD_SCENE(nfc, set_sak, SetSak)
|
ADD_SCENE(nfc, set_sak, SetSak)
|
||||||
ADD_SCENE(nfc, set_atqa, SetAtqua)
|
ADD_SCENE(nfc, set_atqa, SetAtqua)
|
||||||
ADD_SCENE(nfc, set_uid, SetUid)
|
ADD_SCENE(nfc, set_uid, SetUid)
|
||||||
ADD_SCENE(nfc, scripts_menu, ScriptsMenu)
|
ADD_SCENE(nfc, generate_info, GenerateInfo)
|
||||||
ADD_SCENE(nfc, read_mifare_ul, ReadMifareUl)
|
ADD_SCENE(nfc, read_card_success, ReadCardSuccess)
|
||||||
ADD_SCENE(nfc, read_mifare_ul_success, ReadMifareUlSuccess)
|
ADD_SCENE(nfc, save_name, SaveName)
|
||||||
ADD_SCENE(nfc, mifare_ul_menu, MifareUlMenu)
|
ADD_SCENE(nfc, save_success, SaveSuccess)
|
||||||
ADD_SCENE(nfc, emulate_mifare_ul, EmulateMifareUl)
|
ADD_SCENE(nfc, file_select, FileSelect)
|
||||||
ADD_SCENE(nfc, read_emv_app, ReadEmvApp)
|
ADD_SCENE(nfc, emulate_uid, EmulateUid)
|
||||||
ADD_SCENE(nfc, read_emv_app_success, ReadEmvAppSuccess)
|
ADD_SCENE(nfc, mf_ultralight_read_success, MfUltralightReadSuccess)
|
||||||
ADD_SCENE(nfc, read_mifare_desfire, ReadMifareDesfire)
|
ADD_SCENE(nfc, mf_ultralight_menu, MfUltralightMenu)
|
||||||
ADD_SCENE(nfc, read_mifare_desfire_success, ReadMifareDesfireSuccess)
|
ADD_SCENE(nfc, mf_ultralight_emulate, MfUltralightEmulate)
|
||||||
ADD_SCENE(nfc, mifare_desfire_menu, MifareDesfireMenu)
|
ADD_SCENE(nfc, mf_desfire_read_success, MfDesfireReadSuccess)
|
||||||
ADD_SCENE(nfc, mifare_desfire_data, MifareDesfireData)
|
ADD_SCENE(nfc, mf_desfire_menu, MfDesfireMenu)
|
||||||
ADD_SCENE(nfc, mifare_desfire_app, MifareDesfireApp)
|
ADD_SCENE(nfc, mf_desfire_data, MfDesfireData)
|
||||||
|
ADD_SCENE(nfc, mf_desfire_app, MfDesfireApp)
|
||||||
|
ADD_SCENE(nfc, mf_classic_read_success, MfClassicReadSuccess)
|
||||||
|
ADD_SCENE(nfc, mf_classic_menu, MfClassicMenu)
|
||||||
|
ADD_SCENE(nfc, mf_classic_emulate, MfClassicEmulate)
|
||||||
|
ADD_SCENE(nfc, mf_classic_keys, MfClassicKeys)
|
||||||
|
ADD_SCENE(nfc, mf_classic_keys_add, MfClassicKeysAdd)
|
||||||
|
ADD_SCENE(nfc, mf_classic_dict_attack, MfClassicDictAttack)
|
||||||
|
ADD_SCENE(nfc, emv_read_success, EmvReadSuccess)
|
||||||
|
ADD_SCENE(nfc, emulate_apdu_sequence, EmulateApduSequence)
|
||||||
ADD_SCENE(nfc, device_info, DeviceInfo)
|
ADD_SCENE(nfc, device_info, DeviceInfo)
|
||||||
ADD_SCENE(nfc, delete, Delete)
|
ADD_SCENE(nfc, delete, Delete)
|
||||||
ADD_SCENE(nfc, delete_success, DeleteSuccess)
|
ADD_SCENE(nfc, delete_success, DeleteSuccess)
|
||||||
ADD_SCENE(nfc, run_emv_app_confirm, RunEmvAppConfirm)
|
|
||||||
ADD_SCENE(nfc, read_emv_data, ReadEmvData)
|
|
||||||
ADD_SCENE(nfc, read_emv_data_success, ReadEmvDataSuccess)
|
|
||||||
ADD_SCENE(nfc, emulate_apdu_sequence, EmulateApduSequence)
|
|
||||||
ADD_SCENE(nfc, restore_original, RestoreOriginal)
|
ADD_SCENE(nfc, restore_original, RestoreOriginal)
|
||||||
ADD_SCENE(nfc, debug, Debug)
|
ADD_SCENE(nfc, debug, Debug)
|
||||||
ADD_SCENE(nfc, field, Field)
|
ADD_SCENE(nfc, field, Field)
|
||||||
ADD_SCENE(nfc, read_mifare_classic, ReadMifareClassic)
|
|
||||||
ADD_SCENE(nfc, emulate_mifare_classic, EmulateMifareClassic)
|
|
||||||
ADD_SCENE(nfc, mifare_classic_menu, MifareClassicMenu)
|
|
||||||
ADD_SCENE(nfc, dict_not_found, DictNotFound)
|
ADD_SCENE(nfc, dict_not_found, DictNotFound)
|
||||||
ADD_SCENE(nfc, rpc, Rpc)
|
ADD_SCENE(nfc, rpc, Rpc)
|
||||||
ADD_SCENE(nfc, generate_info, GenerateInfo)
|
ADD_SCENE(nfc, exit_confirm, ExitConfirm)
|
||||||
|
ADD_SCENE(nfc, retry_confirm, RetryConfirm)
|
||||||
|
ADD_SCENE(nfc, detect_reader, DetectReader)
|
||||||
|
|||||||
143
applications/nfc/scenes/nfc_scene_detect_reader.c
Normal file
143
applications/nfc/scenes/nfc_scene_detect_reader.c
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
#include "../nfc_i.h"
|
||||||
|
#include <dolphin/dolphin.h>
|
||||||
|
|
||||||
|
#define NFC_SCENE_DETECT_READER_LOG_SIZE_MAX (200)
|
||||||
|
|
||||||
|
enum {
|
||||||
|
NfcSceneDetectReaderStateWidget,
|
||||||
|
NfcSceneDetectReaderStateTextBox,
|
||||||
|
};
|
||||||
|
|
||||||
|
bool nfc_detect_reader_worker_callback(NfcWorkerEvent event, void* context) {
|
||||||
|
UNUSED(event);
|
||||||
|
furi_assert(context);
|
||||||
|
Nfc* nfc = context;
|
||||||
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_detect_reader_widget_callback(GuiButtonType result, InputType type, void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
Nfc* nfc = context;
|
||||||
|
if(type == InputTypeShort) {
|
||||||
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_detect_reader_textbox_callback(void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
Nfc* nfc = context;
|
||||||
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add widget with device name or inform that data received
|
||||||
|
static void nfc_scene_detect_reader_widget_config(Nfc* nfc, bool data_received) {
|
||||||
|
Widget* widget = nfc->widget;
|
||||||
|
widget_reset(widget);
|
||||||
|
|
||||||
|
widget_add_icon_element(widget, 0, 14, &I_Reader_detect);
|
||||||
|
widget_add_string_element(
|
||||||
|
widget, 64, 3, AlignCenter, AlignTop, FontSecondary, "Hold near reader");
|
||||||
|
widget_add_string_element(widget, 55, 22, AlignLeft, AlignTop, FontPrimary, "Emulating...");
|
||||||
|
|
||||||
|
if(data_received) {
|
||||||
|
widget_add_button_element(
|
||||||
|
widget, GuiButtonTypeCenter, "Log", nfc_scene_detect_reader_widget_callback, nfc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_detect_reader_on_enter(void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
DOLPHIN_DEED(DolphinDeedNfcEmulate);
|
||||||
|
FuriHalNfcDevData nfc_params = {
|
||||||
|
.uid = {0x36, 0x9C, 0xe7, 0xb1, 0x0A, 0xC1, 0x34},
|
||||||
|
.uid_len = 7,
|
||||||
|
.atqa = {0x44, 0x00},
|
||||||
|
.sak = 0x08,
|
||||||
|
.type = FuriHalNfcTypeA,
|
||||||
|
};
|
||||||
|
nfc->dev->dev_data.nfc_data = nfc_params;
|
||||||
|
|
||||||
|
// Setup Widget
|
||||||
|
nfc_scene_detect_reader_widget_config(nfc, false);
|
||||||
|
// Setup TextBox
|
||||||
|
TextBox* text_box = nfc->text_box;
|
||||||
|
text_box_set_font(text_box, TextBoxFontHex);
|
||||||
|
text_box_set_focus(text_box, TextBoxFocusEnd);
|
||||||
|
string_reset(nfc->text_box_store);
|
||||||
|
|
||||||
|
// Set Widget state and view
|
||||||
|
scene_manager_set_scene_state(
|
||||||
|
nfc->scene_manager, NfcSceneDetectReader, NfcSceneDetectReaderStateWidget);
|
||||||
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
|
||||||
|
// Start worker
|
||||||
|
memset(&nfc->dev->dev_data.reader_data, 0, sizeof(NfcReaderRequestData));
|
||||||
|
nfc_worker_start(
|
||||||
|
nfc->worker,
|
||||||
|
NfcWorkerStateUidEmulate,
|
||||||
|
&nfc->dev->dev_data,
|
||||||
|
nfc_detect_reader_worker_callback,
|
||||||
|
nfc);
|
||||||
|
|
||||||
|
nfc_blink_start(nfc);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nfc_scene_detect_reader_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
NfcReaderRequestData* reader_data = &nfc->dev->dev_data.reader_data;
|
||||||
|
uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneDetectReader);
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
|
if(event.event == NfcCustomEventWorkerExit) {
|
||||||
|
// Add data button to widget if data is received for the first time
|
||||||
|
if(!string_size(nfc->text_box_store)) {
|
||||||
|
nfc_scene_detect_reader_widget_config(nfc, true);
|
||||||
|
}
|
||||||
|
// Update TextBox data
|
||||||
|
if(string_size(nfc->text_box_store) < NFC_SCENE_DETECT_READER_LOG_SIZE_MAX) {
|
||||||
|
string_cat_printf(nfc->text_box_store, "R:");
|
||||||
|
for(uint16_t i = 0; i < reader_data->size; i++) {
|
||||||
|
string_cat_printf(nfc->text_box_store, " %02X", reader_data->data[i]);
|
||||||
|
}
|
||||||
|
string_push_back(nfc->text_box_store, '\n');
|
||||||
|
text_box_set_text(nfc->text_box, string_get_cstr(nfc->text_box_store));
|
||||||
|
}
|
||||||
|
memset(reader_data, 0, sizeof(NfcReaderRequestData));
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == GuiButtonTypeCenter && state == NfcSceneDetectReaderStateWidget) {
|
||||||
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox);
|
||||||
|
scene_manager_set_scene_state(
|
||||||
|
nfc->scene_manager, NfcSceneDetectReader, NfcSceneDetectReaderStateTextBox);
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == NfcCustomEventViewExit && state == NfcSceneDetectReaderStateTextBox) {
|
||||||
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
|
||||||
|
scene_manager_set_scene_state(
|
||||||
|
nfc->scene_manager, NfcSceneDetectReader, NfcSceneDetectReaderStateWidget);
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
} else if(event.type == SceneManagerEventTypeBack) {
|
||||||
|
if(state == NfcSceneDetectReaderStateTextBox) {
|
||||||
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
|
||||||
|
scene_manager_set_scene_state(
|
||||||
|
nfc->scene_manager, NfcSceneDetectReader, NfcSceneDetectReaderStateWidget);
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_detect_reader_on_exit(void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
// Stop worker
|
||||||
|
nfc_worker_stop(nfc->worker);
|
||||||
|
|
||||||
|
// Clear view
|
||||||
|
widget_reset(nfc->widget);
|
||||||
|
text_box_reset(nfc->text_box);
|
||||||
|
string_reset(nfc->text_box_store);
|
||||||
|
|
||||||
|
nfc_blink_stop(nfc);
|
||||||
|
}
|
||||||
@@ -190,7 +190,7 @@ bool nfc_scene_device_info_on_event(void* context, SceneManagerEvent event) {
|
|||||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewBankCard);
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewBankCard);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
} else if(nfc->dev->format == NfcDeviceSaveFormatMifareDesfire) {
|
} else if(nfc->dev->format == NfcDeviceSaveFormatMifareDesfire) {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMifareDesfireData);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireData);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
} else if(state == NfcSceneDeviceInfoData && event.event == NfcCustomEventViewExit) {
|
} else if(state == NfcSceneDeviceInfoData && event.event == NfcCustomEventViewExit) {
|
||||||
|
|||||||
@@ -31,12 +31,9 @@ bool nfc_scene_dict_not_found_on_event(void* context, SceneManagerEvent event) {
|
|||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
if(event.event == NfcCustomEventViewExit) {
|
if(event.event == NfcCustomEventViewExit) {
|
||||||
if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneScriptsMenu)) {
|
if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneExtraActions)) {
|
||||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||||
nfc->scene_manager, NfcSceneScriptsMenu);
|
nfc->scene_manager, NfcSceneExtraActions);
|
||||||
} else if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneCardMenu)) {
|
|
||||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
|
||||||
nfc->scene_manager, NfcSceneCardMenu);
|
|
||||||
} else {
|
} else {
|
||||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||||
nfc->scene_manager, NfcSceneStart);
|
nfc->scene_manager, NfcSceneStart);
|
||||||
|
|||||||
@@ -8,11 +8,12 @@ enum {
|
|||||||
NfcSceneEmulateUidStateTextBox,
|
NfcSceneEmulateUidStateTextBox,
|
||||||
};
|
};
|
||||||
|
|
||||||
void nfc_emulate_uid_worker_callback(NfcWorkerEvent event, void* context) {
|
bool nfc_emulate_uid_worker_callback(NfcWorkerEvent event, void* context) {
|
||||||
UNUSED(event);
|
UNUSED(event);
|
||||||
furi_assert(context);
|
furi_assert(context);
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit);
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_emulate_uid_widget_callback(GuiButtonType result, InputType type, void* context) {
|
void nfc_scene_emulate_uid_widget_callback(GuiButtonType result, InputType type, void* context) {
|
||||||
@@ -76,7 +77,7 @@ void nfc_scene_emulate_uid_on_enter(void* context) {
|
|||||||
memset(&nfc->dev->dev_data.reader_data, 0, sizeof(NfcReaderRequestData));
|
memset(&nfc->dev->dev_data.reader_data, 0, sizeof(NfcReaderRequestData));
|
||||||
nfc_worker_start(
|
nfc_worker_start(
|
||||||
nfc->worker,
|
nfc->worker,
|
||||||
NfcWorkerStateEmulate,
|
NfcWorkerStateUidEmulate,
|
||||||
&nfc->dev->dev_data,
|
&nfc->dev->dev_data,
|
||||||
nfc_emulate_uid_worker_callback,
|
nfc_emulate_uid_worker_callback,
|
||||||
nfc);
|
nfc);
|
||||||
@@ -90,9 +91,7 @@ bool nfc_scene_emulate_uid_on_event(void* context, SceneManagerEvent event) {
|
|||||||
uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneEmulateUid);
|
uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneEmulateUid);
|
||||||
bool consumed = false;
|
bool consumed = false;
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeTick) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
consumed = true;
|
|
||||||
} else if(event.type == SceneManagerEventTypeCustom) {
|
|
||||||
if(event.event == NfcCustomEventWorkerExit) {
|
if(event.event == NfcCustomEventWorkerExit) {
|
||||||
// Add data button to widget if data is received for the first time
|
// Add data button to widget if data is received for the first time
|
||||||
if(!string_size(nfc->text_box_store)) {
|
if(!string_size(nfc->text_box_store)) {
|
||||||
|
|||||||
36
applications/nfc/scenes/nfc_scene_read_emv_data_success.c → applications/nfc/scenes/nfc_scene_emv_read_success.c
Executable file → Normal file
36
applications/nfc/scenes/nfc_scene_read_emv_data_success.c → applications/nfc/scenes/nfc_scene_emv_read_success.c
Executable file → Normal file
@@ -2,7 +2,7 @@
|
|||||||
#include "../helpers/nfc_emv_parser.h"
|
#include "../helpers/nfc_emv_parser.h"
|
||||||
#include <dolphin/dolphin.h>
|
#include <dolphin/dolphin.h>
|
||||||
|
|
||||||
void nfc_scene_read_emv_data_success_widget_callback(
|
void nfc_scene_emv_read_success_widget_callback(
|
||||||
GuiButtonType result,
|
GuiButtonType result,
|
||||||
InputType type,
|
InputType type,
|
||||||
void* context) {
|
void* context) {
|
||||||
@@ -12,7 +12,7 @@ void nfc_scene_read_emv_data_success_widget_callback(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_read_emv_data_success_on_enter(void* context) {
|
void nfc_scene_emv_read_success_on_enter(void* context) {
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
EmvData* emv_data = &nfc->dev->dev_data.emv_data;
|
EmvData* emv_data = &nfc->dev->dev_data.emv_data;
|
||||||
FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data;
|
FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data;
|
||||||
@@ -23,17 +23,9 @@ void nfc_scene_read_emv_data_success_on_enter(void* context) {
|
|||||||
widget_add_frame_element(nfc->widget, 0, 0, 128, 64, 6);
|
widget_add_frame_element(nfc->widget, 0, 0, 128, 64, 6);
|
||||||
// Add buttons
|
// Add buttons
|
||||||
widget_add_button_element(
|
widget_add_button_element(
|
||||||
nfc->widget,
|
nfc->widget, GuiButtonTypeLeft, "Retry", nfc_scene_emv_read_success_widget_callback, nfc);
|
||||||
GuiButtonTypeLeft,
|
|
||||||
"Back",
|
|
||||||
nfc_scene_read_emv_data_success_widget_callback,
|
|
||||||
nfc);
|
|
||||||
widget_add_button_element(
|
widget_add_button_element(
|
||||||
nfc->widget,
|
nfc->widget, GuiButtonTypeRight, "Save", nfc_scene_emv_read_success_widget_callback, nfc);
|
||||||
GuiButtonTypeRight,
|
|
||||||
"Save",
|
|
||||||
nfc_scene_read_emv_data_success_widget_callback,
|
|
||||||
nfc);
|
|
||||||
// Add card name
|
// Add card name
|
||||||
widget_add_string_element(
|
widget_add_string_element(
|
||||||
nfc->widget, 64, 3, AlignCenter, AlignTop, FontSecondary, nfc->dev->dev_data.emv_data.name);
|
nfc->widget, 64, 3, AlignCenter, AlignTop, FontSecondary, nfc->dev->dev_data.emv_data.name);
|
||||||
@@ -103,25 +95,17 @@ void nfc_scene_read_emv_data_success_on_enter(void* context) {
|
|||||||
widget_add_string_element(nfc->widget, 7, 32, AlignLeft, AlignTop, FontSecondary, exp_str);
|
widget_add_string_element(nfc->widget, 7, 32, AlignLeft, AlignTop, FontSecondary, exp_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send notification
|
|
||||||
if(scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadEmvDataSuccess) ==
|
|
||||||
NFC_SEND_NOTIFICATION_TRUE) {
|
|
||||||
notification_message(nfc->notifications, &sequence_success);
|
|
||||||
scene_manager_set_scene_state(
|
|
||||||
nfc->scene_manager, NfcSceneReadEmvDataSuccess, NFC_SEND_NOTIFICATION_FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool nfc_scene_read_emv_data_success_on_event(void* context, SceneManagerEvent event) {
|
bool nfc_scene_emv_read_success_on_event(void* context, SceneManagerEvent event) {
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
bool consumed = false;
|
bool consumed = false;
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
if(event.event == GuiButtonTypeLeft) {
|
if(event.event == GuiButtonTypeLeft) {
|
||||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneRetryConfirm);
|
||||||
nfc->scene_manager, NfcSceneReadEmvAppSuccess);
|
consumed = true;
|
||||||
} else if(event.event == GuiButtonTypeRight) {
|
} else if(event.event == GuiButtonTypeRight) {
|
||||||
// Clear device name
|
// Clear device name
|
||||||
nfc_device_set_name(nfc->dev, "");
|
nfc_device_set_name(nfc->dev, "");
|
||||||
@@ -130,13 +114,13 @@ bool nfc_scene_read_emv_data_success_on_event(void* context, SceneManagerEvent e
|
|||||||
consumed = true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
} else if(event.type == SceneManagerEventTypeBack) {
|
} else if(event.type == SceneManagerEventTypeBack) {
|
||||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm);
|
||||||
nfc->scene_manager, NfcSceneReadEmvAppSuccess);
|
consumed = true;
|
||||||
}
|
}
|
||||||
return consumed;
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_read_emv_data_success_on_exit(void* context) {
|
void nfc_scene_emv_read_success_on_exit(void* context) {
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
// Clear view
|
// Clear view
|
||||||
47
applications/nfc/scenes/nfc_scene_exit_confirm.c
Normal file
47
applications/nfc/scenes/nfc_scene_exit_confirm.c
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
#include "../nfc_i.h"
|
||||||
|
|
||||||
|
void nfc_scene_exit_confirm_dialog_callback(DialogExResult result, void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_exit_confirm_on_enter(void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
DialogEx* dialog_ex = nfc->dialog_ex;
|
||||||
|
|
||||||
|
dialog_ex_set_left_button_text(dialog_ex, "Exit");
|
||||||
|
dialog_ex_set_right_button_text(dialog_ex, "Stay");
|
||||||
|
dialog_ex_set_header(dialog_ex, "Exit to NFC menu?", 64, 11, AlignCenter, AlignTop);
|
||||||
|
dialog_ex_set_text(
|
||||||
|
dialog_ex, "All unsaved data\nwill be lost.", 64, 25, AlignCenter, AlignTop);
|
||||||
|
dialog_ex_set_context(dialog_ex, nfc);
|
||||||
|
dialog_ex_set_result_callback(dialog_ex, nfc_scene_exit_confirm_dialog_callback);
|
||||||
|
|
||||||
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nfc_scene_exit_confirm_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
|
if(event.event == DialogExResultRight) {
|
||||||
|
consumed = scene_manager_previous_scene(nfc->scene_manager);
|
||||||
|
} else if(event.event == DialogExResultLeft) {
|
||||||
|
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||||
|
nfc->scene_manager, NfcSceneStart);
|
||||||
|
}
|
||||||
|
} else if(event.type == SceneManagerEventTypeBack) {
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_exit_confirm_on_exit(void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
// Clean view
|
||||||
|
dialog_ex_reset(nfc->dialog_ex);
|
||||||
|
}
|
||||||
48
applications/nfc/scenes/nfc_scene_extra_actions.c
Normal file
48
applications/nfc/scenes/nfc_scene_extra_actions.c
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
#include "../nfc_i.h"
|
||||||
|
|
||||||
|
enum SubmenuIndex {
|
||||||
|
SubmenuIndexMfClassicKeys,
|
||||||
|
};
|
||||||
|
|
||||||
|
void nfc_scene_extra_actions_submenu_callback(void* context, uint32_t index) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_extra_actions_on_enter(void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
Submenu* submenu = nfc->submenu;
|
||||||
|
|
||||||
|
submenu_add_item(
|
||||||
|
submenu,
|
||||||
|
"Mf Classic Keys",
|
||||||
|
SubmenuIndexMfClassicKeys,
|
||||||
|
nfc_scene_extra_actions_submenu_callback,
|
||||||
|
nfc);
|
||||||
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nfc_scene_extra_actions_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
|
if(event.event == SubmenuIndexMfClassicKeys) {
|
||||||
|
if(mf_classic_dict_check_presence(MfClassicDictTypeFlipper)) {
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicKeys);
|
||||||
|
} else {
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound);
|
||||||
|
}
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneExtraActions, event.event);
|
||||||
|
}
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_extra_actions_on_exit(void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
submenu_reset(nfc->submenu);
|
||||||
|
}
|
||||||
137
applications/nfc/scenes/nfc_scene_mf_classic_dict_attack.c
Normal file
137
applications/nfc/scenes/nfc_scene_mf_classic_dict_attack.c
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
#include "../nfc_i.h"
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
DictAttackStateIdle,
|
||||||
|
DictAttackStateUserDictInProgress,
|
||||||
|
DictAttackStateFlipperDictInProgress,
|
||||||
|
} DictAttackState;
|
||||||
|
|
||||||
|
bool nfc_dict_attack_worker_callback(NfcWorkerEvent event, void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
Nfc* nfc = context;
|
||||||
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, event);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_dict_attack_dict_attack_result_callback(void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
Nfc* nfc = context;
|
||||||
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventDictAttackSkip);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nfc_scene_mf_classic_dict_attack_update_view(Nfc* nfc) {
|
||||||
|
MfClassicData* data = &nfc->dev->dev_data.mf_classic_data;
|
||||||
|
uint8_t sectors_read = 0;
|
||||||
|
uint8_t keys_found = 0;
|
||||||
|
|
||||||
|
// Calculate found keys and read sectors
|
||||||
|
mf_classic_get_read_sectors_and_keys(data, §ors_read, &keys_found);
|
||||||
|
dict_attack_set_keys_found(nfc->dict_attack, keys_found);
|
||||||
|
dict_attack_set_sector_read(nfc->dict_attack, sectors_read);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nfc_scene_mf_classic_dict_attack_prepare_view(Nfc* nfc, DictAttackState state) {
|
||||||
|
MfClassicData* data = &nfc->dev->dev_data.mf_classic_data;
|
||||||
|
NfcWorkerState worker_state = NfcWorkerStateReady;
|
||||||
|
|
||||||
|
// Identify scene state
|
||||||
|
if(state == DictAttackStateIdle) {
|
||||||
|
if(mf_classic_dict_check_presence(MfClassicDictTypeUser)) {
|
||||||
|
state = DictAttackStateUserDictInProgress;
|
||||||
|
} else {
|
||||||
|
state = DictAttackStateFlipperDictInProgress;
|
||||||
|
}
|
||||||
|
} else if(state == DictAttackStateUserDictInProgress) {
|
||||||
|
state = DictAttackStateFlipperDictInProgress;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup view
|
||||||
|
if(state == DictAttackStateUserDictInProgress) {
|
||||||
|
worker_state = NfcWorkerStateMfClassicUserDictAttack;
|
||||||
|
dict_attack_set_header(nfc->dict_attack, "Mf Classic User Dict.");
|
||||||
|
} else if(state == DictAttackStateFlipperDictInProgress) {
|
||||||
|
worker_state = NfcWorkerStateMfClassicFlipperDictAttack;
|
||||||
|
dict_attack_set_header(nfc->dict_attack, "Mf Classic Flipper Dict.");
|
||||||
|
}
|
||||||
|
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfClassicDictAttack, state);
|
||||||
|
dict_attack_set_callback(nfc->dict_attack, nfc_dict_attack_dict_attack_result_callback, nfc);
|
||||||
|
dict_attack_set_current_sector(nfc->dict_attack, 0);
|
||||||
|
dict_attack_set_card_detected(nfc->dict_attack, data->type);
|
||||||
|
nfc_scene_mf_classic_dict_attack_update_view(nfc);
|
||||||
|
nfc_worker_start(
|
||||||
|
nfc->worker, worker_state, &nfc->dev->dev_data, nfc_dict_attack_worker_callback, nfc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_mf_classic_dict_attack_on_enter(void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
nfc_scene_mf_classic_dict_attack_prepare_view(nfc, DictAttackStateIdle);
|
||||||
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDictAttack);
|
||||||
|
nfc_blink_start(nfc);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
MfClassicData* data = &nfc->dev->dev_data.mf_classic_data;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
|
uint32_t state =
|
||||||
|
scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicDictAttack);
|
||||||
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
|
if(event.event == NfcWorkerEventSuccess) {
|
||||||
|
if(state == DictAttackStateUserDictInProgress) {
|
||||||
|
nfc_worker_stop(nfc->worker);
|
||||||
|
nfc_scene_mf_classic_dict_attack_prepare_view(nfc, state);
|
||||||
|
consumed = true;
|
||||||
|
} else {
|
||||||
|
notification_message(nfc->notifications, &sequence_success);
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSuccess);
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
} else if(event.event == NfcWorkerEventAborted) {
|
||||||
|
if(state == DictAttackStateUserDictInProgress) {
|
||||||
|
nfc_scene_mf_classic_dict_attack_prepare_view(nfc, state);
|
||||||
|
consumed = true;
|
||||||
|
} else {
|
||||||
|
notification_message(nfc->notifications, &sequence_success);
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSuccess);
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
} else if(event.event == NfcWorkerEventCardDetected) {
|
||||||
|
dict_attack_set_card_detected(nfc->dict_attack, data->type);
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == NfcWorkerEventNoCardDetected) {
|
||||||
|
dict_attack_set_card_removed(nfc->dict_attack);
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == NfcWorkerEventFoundKeyA) {
|
||||||
|
dict_attack_inc_keys_found(nfc->dict_attack);
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == NfcWorkerEventFoundKeyB) {
|
||||||
|
dict_attack_inc_keys_found(nfc->dict_attack);
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == NfcWorkerEventNewSector) {
|
||||||
|
nfc_scene_mf_classic_dict_attack_update_view(nfc);
|
||||||
|
dict_attack_inc_current_sector(nfc->dict_attack);
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == NfcCustomEventDictAttackSkip) {
|
||||||
|
if(state == DictAttackStateUserDictInProgress) {
|
||||||
|
nfc_worker_stop(nfc->worker);
|
||||||
|
consumed = true;
|
||||||
|
} else if(state == DictAttackStateFlipperDictInProgress) {
|
||||||
|
nfc_worker_stop(nfc->worker);
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(event.type == SceneManagerEventTypeBack) {
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm);
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_mf_classic_dict_attack_on_exit(void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
// Stop worker
|
||||||
|
nfc_worker_stop(nfc->worker);
|
||||||
|
dict_attack_reset(nfc->dict_attack);
|
||||||
|
nfc_blink_stop(nfc);
|
||||||
|
}
|
||||||
@@ -4,51 +4,52 @@
|
|||||||
#define NFC_MF_CLASSIC_DATA_NOT_CHANGED (0UL)
|
#define NFC_MF_CLASSIC_DATA_NOT_CHANGED (0UL)
|
||||||
#define NFC_MF_CLASSIC_DATA_CHANGED (1UL)
|
#define NFC_MF_CLASSIC_DATA_CHANGED (1UL)
|
||||||
|
|
||||||
void nfc_emulate_mifare_classic_worker_callback(NfcWorkerEvent event, void* context) {
|
bool nfc_mf_classic_emulate_worker_callback(NfcWorkerEvent event, void* context) {
|
||||||
UNUSED(event);
|
UNUSED(event);
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
nfc->scene_manager, NfcSceneEmulateMifareClassic, NFC_MF_CLASSIC_DATA_CHANGED);
|
nfc->scene_manager, NfcSceneMfClassicEmulate, NFC_MF_CLASSIC_DATA_CHANGED);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_emulate_mifare_classic_on_enter(void* context) {
|
void nfc_scene_mf_classic_emulate_on_enter(void* context) {
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
DOLPHIN_DEED(DolphinDeedNfcEmulate);
|
DOLPHIN_DEED(DolphinDeedNfcEmulate);
|
||||||
|
|
||||||
// Setup view
|
// Setup view
|
||||||
Popup* popup = nfc->popup;
|
Popup* popup = nfc->popup;
|
||||||
if(strcmp(nfc->dev->dev_name, "")) {
|
if(strcmp(nfc->dev->dev_name, "")) {
|
||||||
nfc_text_store_set(nfc, "%s", nfc->dev->dev_name);
|
nfc_text_store_set(nfc, "Emulating\n%s", nfc->dev->dev_name);
|
||||||
|
} else {
|
||||||
|
nfc_text_store_set(nfc, "Emulating\nMf Classic", nfc->dev->dev_name);
|
||||||
}
|
}
|
||||||
popup_set_icon(popup, 0, 3, &I_RFIDDolphinSend_97x61);
|
popup_set_icon(popup, 0, 3, &I_RFIDDolphinSend_97x61);
|
||||||
popup_set_header(popup, "Emulating\nMf Classic", 56, 31, AlignLeft, AlignTop);
|
popup_set_header(popup, nfc->text_store, 56, 31, AlignLeft, AlignTop);
|
||||||
|
|
||||||
// Setup and start worker
|
// Setup and start worker
|
||||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
|
||||||
nfc_worker_start(
|
nfc_worker_start(
|
||||||
nfc->worker,
|
nfc->worker,
|
||||||
NfcWorkerStateEmulateMifareClassic,
|
NfcWorkerStateMfClassicEmulate,
|
||||||
&nfc->dev->dev_data,
|
&nfc->dev->dev_data,
|
||||||
nfc_emulate_mifare_classic_worker_callback,
|
nfc_mf_classic_emulate_worker_callback,
|
||||||
nfc);
|
nfc);
|
||||||
nfc_blink_start(nfc);
|
nfc_blink_start(nfc);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool nfc_scene_emulate_mifare_classic_on_event(void* context, SceneManagerEvent event) {
|
bool nfc_scene_mf_classic_emulate_on_event(void* context, SceneManagerEvent event) {
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
bool consumed = false;
|
bool consumed = false;
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeTick) {
|
if(event.type == SceneManagerEventTypeBack) {
|
||||||
consumed = true;
|
|
||||||
} else if(event.type == SceneManagerEventTypeBack) {
|
|
||||||
// Stop worker
|
// Stop worker
|
||||||
nfc_worker_stop(nfc->worker);
|
nfc_worker_stop(nfc->worker);
|
||||||
// Check if data changed and save in shadow file
|
// Check if data changed and save in shadow file
|
||||||
if(scene_manager_get_scene_state(nfc->scene_manager, NfcSceneEmulateMifareClassic) ==
|
if(scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicEmulate) ==
|
||||||
NFC_MF_CLASSIC_DATA_CHANGED) {
|
NFC_MF_CLASSIC_DATA_CHANGED) {
|
||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
nfc->scene_manager, NfcSceneEmulateMifareClassic, NFC_MF_CLASSIC_DATA_NOT_CHANGED);
|
nfc->scene_manager, NfcSceneMfClassicEmulate, NFC_MF_CLASSIC_DATA_NOT_CHANGED);
|
||||||
nfc_device_save_shadow(nfc->dev, nfc->dev->dev_name);
|
nfc_device_save_shadow(nfc->dev, nfc->dev->dev_name);
|
||||||
}
|
}
|
||||||
consumed = false;
|
consumed = false;
|
||||||
@@ -56,7 +57,7 @@ bool nfc_scene_emulate_mifare_classic_on_event(void* context, SceneManagerEvent
|
|||||||
return consumed;
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_emulate_mifare_classic_on_exit(void* context) {
|
void nfc_scene_mf_classic_emulate_on_exit(void* context) {
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
// Clear view
|
// Clear view
|
||||||
59
applications/nfc/scenes/nfc_scene_mf_classic_keys.c
Normal file
59
applications/nfc/scenes/nfc_scene_mf_classic_keys.c
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
#include "../nfc_i.h"
|
||||||
|
|
||||||
|
void nfc_scene_mf_classic_keys_widget_callback(GuiButtonType result, InputType type, void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
if(type == InputTypeShort) {
|
||||||
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_mf_classic_keys_on_enter(void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
// Load flipper dict keys total
|
||||||
|
uint32_t flipper_dict_keys_total = 0;
|
||||||
|
MfClassicDict* dict = mf_classic_dict_alloc(MfClassicDictTypeFlipper);
|
||||||
|
if(dict) {
|
||||||
|
flipper_dict_keys_total = mf_classic_dict_get_total_keys(dict);
|
||||||
|
mf_classic_dict_free(dict);
|
||||||
|
}
|
||||||
|
// Load user dict keys total
|
||||||
|
uint32_t user_dict_keys_total = 0;
|
||||||
|
dict = mf_classic_dict_alloc(MfClassicDictTypeUser);
|
||||||
|
if(dict) {
|
||||||
|
user_dict_keys_total = mf_classic_dict_get_total_keys(dict);
|
||||||
|
mf_classic_dict_free(dict);
|
||||||
|
}
|
||||||
|
|
||||||
|
widget_add_string_element(
|
||||||
|
nfc->widget, 0, 0, AlignLeft, AlignTop, FontPrimary, "MF Classic Keys");
|
||||||
|
char temp_str[32];
|
||||||
|
snprintf(temp_str, sizeof(temp_str), "Flipper dict: %ld", flipper_dict_keys_total);
|
||||||
|
widget_add_string_element(nfc->widget, 0, 20, AlignLeft, AlignTop, FontSecondary, temp_str);
|
||||||
|
snprintf(temp_str, sizeof(temp_str), "User dict: %ld", user_dict_keys_total);
|
||||||
|
widget_add_string_element(nfc->widget, 0, 32, AlignLeft, AlignTop, FontSecondary, temp_str);
|
||||||
|
widget_add_button_element(
|
||||||
|
nfc->widget, GuiButtonTypeCenter, "Add", nfc_scene_mf_classic_keys_widget_callback, nfc);
|
||||||
|
|
||||||
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nfc_scene_mf_classic_keys_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
|
if(event.event == GuiButtonTypeCenter) {
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicKeysAdd);
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_mf_classic_keys_on_exit(void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
widget_reset(nfc->widget);
|
||||||
|
}
|
||||||
57
applications/nfc/scenes/nfc_scene_mf_classic_keys_add.c
Normal file
57
applications/nfc/scenes/nfc_scene_mf_classic_keys_add.c
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
#include "../nfc_i.h"
|
||||||
|
|
||||||
|
void nfc_scene_mf_classic_keys_add_byte_input_callback(void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone);
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_mf_classic_keys_add_on_enter(void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
// Setup view
|
||||||
|
ByteInput* byte_input = nfc->byte_input;
|
||||||
|
byte_input_set_header_text(byte_input, "Enter the key in hex");
|
||||||
|
byte_input_set_result_callback(
|
||||||
|
byte_input,
|
||||||
|
nfc_scene_mf_classic_keys_add_byte_input_callback,
|
||||||
|
NULL,
|
||||||
|
nfc,
|
||||||
|
nfc->byte_input_store,
|
||||||
|
6);
|
||||||
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewByteInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nfc_scene_mf_classic_keys_add_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
|
if(event.event == NfcCustomEventByteInputDone) {
|
||||||
|
// Add key to dict
|
||||||
|
bool key_added = false;
|
||||||
|
MfClassicDict* dict = mf_classic_dict_alloc(MfClassicDictTypeUser);
|
||||||
|
if(dict) {
|
||||||
|
if(mf_classic_dict_add_key(dict, nfc->byte_input_store)) {
|
||||||
|
key_added = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(key_added) {
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess);
|
||||||
|
} else {
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound);
|
||||||
|
}
|
||||||
|
mf_classic_dict_free(dict);
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_mf_classic_keys_add_on_exit(void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
// Clear view
|
||||||
|
byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0);
|
||||||
|
byte_input_set_header_text(nfc->byte_input, "");
|
||||||
|
}
|
||||||
22
applications/nfc/scenes/nfc_scene_mifare_ul_menu.c → applications/nfc/scenes/nfc_scene_mf_classic_menu.c
Executable file → Normal file
22
applications/nfc/scenes/nfc_scene_mifare_ul_menu.c → applications/nfc/scenes/nfc_scene_mf_classic_menu.c
Executable file → Normal file
@@ -5,43 +5,43 @@ enum SubmenuIndex {
|
|||||||
SubmenuIndexEmulate,
|
SubmenuIndexEmulate,
|
||||||
};
|
};
|
||||||
|
|
||||||
void nfc_scene_mifare_ul_menu_submenu_callback(void* context, uint32_t index) {
|
void nfc_scene_mf_classic_menu_submenu_callback(void* context, uint32_t index) {
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_mifare_ul_menu_on_enter(void* context) {
|
void nfc_scene_mf_classic_menu_on_enter(void* context) {
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
Submenu* submenu = nfc->submenu;
|
Submenu* submenu = nfc->submenu;
|
||||||
|
|
||||||
submenu_add_item(
|
submenu_add_item(
|
||||||
submenu, "Save", SubmenuIndexSave, nfc_scene_mifare_ul_menu_submenu_callback, nfc);
|
submenu, "Save", SubmenuIndexSave, nfc_scene_mf_classic_menu_submenu_callback, nfc);
|
||||||
submenu_add_item(
|
submenu_add_item(
|
||||||
submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_mifare_ul_menu_submenu_callback, nfc);
|
submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_mf_classic_menu_submenu_callback, nfc);
|
||||||
submenu_set_selected_item(
|
submenu_set_selected_item(
|
||||||
nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareUlMenu));
|
nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicMenu));
|
||||||
|
|
||||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool nfc_scene_mifare_ul_menu_on_event(void* context, SceneManagerEvent event) {
|
bool nfc_scene_mf_classic_menu_on_event(void* context, SceneManagerEvent event) {
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
bool consumed = false;
|
bool consumed = false;
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
if(event.event == SubmenuIndexSave) {
|
if(event.event == SubmenuIndexSave) {
|
||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
nfc->scene_manager, NfcSceneMifareUlMenu, SubmenuIndexSave);
|
nfc->scene_manager, NfcSceneMfClassicMenu, SubmenuIndexSave);
|
||||||
nfc->dev->format = NfcDeviceSaveFormatMifareUl;
|
nfc->dev->format = NfcDeviceSaveFormatMifareClassic;
|
||||||
// Clear device name
|
// Clear device name
|
||||||
nfc_device_set_name(nfc->dev, "");
|
nfc_device_set_name(nfc->dev, "");
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
} else if(event.event == SubmenuIndexEmulate) {
|
} else if(event.event == SubmenuIndexEmulate) {
|
||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
nfc->scene_manager, NfcSceneMifareUlMenu, SubmenuIndexEmulate);
|
nfc->scene_manager, NfcSceneMfClassicMenu, SubmenuIndexEmulate);
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareUl);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
} else if(event.type == SceneManagerEventTypeBack) {
|
} else if(event.type == SceneManagerEventTypeBack) {
|
||||||
@@ -52,7 +52,7 @@ bool nfc_scene_mifare_ul_menu_on_event(void* context, SceneManagerEvent event) {
|
|||||||
return consumed;
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_mifare_ul_menu_on_exit(void* context) {
|
void nfc_scene_mf_classic_menu_on_exit(void* context) {
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
// Clear view
|
// Clear view
|
||||||
104
applications/nfc/scenes/nfc_scene_mf_classic_read_success.c
Normal file
104
applications/nfc/scenes/nfc_scene_mf_classic_read_success.c
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
#include "../nfc_i.h"
|
||||||
|
#include <dolphin/dolphin.h>
|
||||||
|
|
||||||
|
void nfc_scene_mf_classic_read_success_widget_callback(
|
||||||
|
GuiButtonType result,
|
||||||
|
InputType type,
|
||||||
|
void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
if(type == InputTypeShort) {
|
||||||
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_mf_classic_read_success_on_enter(void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
NfcDeviceData* dev_data = &nfc->dev->dev_data;
|
||||||
|
MfClassicData* mf_data = &dev_data->mf_classic_data;
|
||||||
|
string_t str_tmp;
|
||||||
|
string_init(str_tmp);
|
||||||
|
|
||||||
|
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
|
||||||
|
|
||||||
|
// Setup view
|
||||||
|
Widget* widget = nfc->widget;
|
||||||
|
widget_add_button_element(
|
||||||
|
widget, GuiButtonTypeLeft, "Retry", nfc_scene_mf_classic_read_success_widget_callback, nfc);
|
||||||
|
widget_add_button_element(
|
||||||
|
widget, GuiButtonTypeRight, "More", nfc_scene_mf_classic_read_success_widget_callback, nfc);
|
||||||
|
|
||||||
|
if(string_size(nfc->dev->dev_data.parsed_data)) {
|
||||||
|
widget_add_text_box_element(
|
||||||
|
nfc->widget,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
128,
|
||||||
|
32,
|
||||||
|
AlignLeft,
|
||||||
|
AlignTop,
|
||||||
|
string_get_cstr(nfc->dev->dev_data.parsed_data),
|
||||||
|
true);
|
||||||
|
} else {
|
||||||
|
widget_add_string_element(
|
||||||
|
widget,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
AlignLeft,
|
||||||
|
AlignTop,
|
||||||
|
FontSecondary,
|
||||||
|
mf_classic_get_type_str(mf_data->type));
|
||||||
|
widget_add_string_element(
|
||||||
|
widget, 0, 11, AlignLeft, AlignTop, FontSecondary, "ISO 14443-3 (Type A)");
|
||||||
|
string_printf(str_tmp, "UID:");
|
||||||
|
for(size_t i = 0; i < dev_data->nfc_data.uid_len; i++) {
|
||||||
|
string_cat_printf(str_tmp, " %02X", dev_data->nfc_data.uid[i]);
|
||||||
|
}
|
||||||
|
widget_add_string_element(
|
||||||
|
widget, 0, 22, AlignLeft, AlignTop, FontSecondary, string_get_cstr(str_tmp));
|
||||||
|
uint8_t sectors_total = mf_classic_get_total_sectors_num(mf_data->type);
|
||||||
|
uint8_t keys_total = sectors_total * 2;
|
||||||
|
uint8_t keys_found = 0;
|
||||||
|
uint8_t sectors_read = 0;
|
||||||
|
mf_classic_get_read_sectors_and_keys(mf_data, §ors_read, &keys_found);
|
||||||
|
string_printf(str_tmp, "Keys Found: %d/%d", keys_found, keys_total);
|
||||||
|
widget_add_string_element(
|
||||||
|
widget, 0, 33, AlignLeft, AlignTop, FontSecondary, string_get_cstr(str_tmp));
|
||||||
|
string_printf(str_tmp, "Sectors Read: %d/%d", sectors_read, sectors_total);
|
||||||
|
widget_add_string_element(
|
||||||
|
widget, 0, 44, AlignLeft, AlignTop, FontSecondary, string_get_cstr(str_tmp));
|
||||||
|
}
|
||||||
|
|
||||||
|
string_clear(str_tmp);
|
||||||
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nfc_scene_mf_classic_read_success_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
|
if(event.event == GuiButtonTypeLeft) {
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneRetryConfirm);
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == GuiButtonTypeRight) {
|
||||||
|
// Clear device name
|
||||||
|
nfc_device_set_name(nfc->dev, "");
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicMenu);
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
} else if(event.type == SceneManagerEventTypeBack) {
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm);
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_mf_classic_read_success_on_exit(void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
// Clear view
|
||||||
|
widget_reset(nfc->widget);
|
||||||
|
}
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
#include "../nfc_i.h"
|
#include "../nfc_i.h"
|
||||||
|
|
||||||
#define TAG "NfcSceneMifareDesfireApp"
|
#define TAG "NfcSceneMfDesfireApp"
|
||||||
|
|
||||||
enum SubmenuIndex {
|
enum SubmenuIndex {
|
||||||
SubmenuIndexAppInfo,
|
SubmenuIndexAppInfo,
|
||||||
SubmenuIndexDynamic, // dynamic indexes start here
|
SubmenuIndexDynamic, // dynamic indexes start here
|
||||||
};
|
};
|
||||||
|
|
||||||
MifareDesfireApplication* nfc_scene_mifare_desfire_app_get_app(Nfc* nfc) {
|
MifareDesfireApplication* nfc_scene_mf_desfire_app_get_app(Nfc* nfc) {
|
||||||
uint32_t app_idx =
|
uint32_t app_idx = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireApp) >>
|
||||||
scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareDesfireApp) >> 1;
|
1;
|
||||||
MifareDesfireApplication* app = nfc->dev->dev_data.mf_df_data.app_head;
|
MifareDesfireApplication* app = nfc->dev->dev_data.mf_df_data.app_head;
|
||||||
for(uint32_t i = 0; i < app_idx && app; i++) {
|
for(uint32_t i = 0; i < app_idx && app; i++) {
|
||||||
app = app->next;
|
app = app->next;
|
||||||
@@ -17,16 +17,16 @@ MifareDesfireApplication* nfc_scene_mifare_desfire_app_get_app(Nfc* nfc) {
|
|||||||
return app;
|
return app;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_mifare_desfire_app_submenu_callback(void* context, uint32_t index) {
|
void nfc_scene_mf_desfire_app_submenu_callback(void* context, uint32_t index) {
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_mifare_desfire_app_on_enter(void* context) {
|
void nfc_scene_mf_desfire_app_on_enter(void* context) {
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
Submenu* submenu = nfc->submenu;
|
Submenu* submenu = nfc->submenu;
|
||||||
MifareDesfireApplication* app = nfc_scene_mifare_desfire_app_get_app(nfc);
|
MifareDesfireApplication* app = nfc_scene_mf_desfire_app_get_app(nfc);
|
||||||
if(!app) {
|
if(!app) {
|
||||||
popup_set_icon(nfc->popup, 5, 5, &I_WarningDolphin_45x42);
|
popup_set_icon(nfc->popup, 5, 5, &I_WarningDolphin_45x42);
|
||||||
popup_set_header(nfc->popup, "Internal Error!", 55, 12, AlignLeft, AlignBottom);
|
popup_set_header(nfc->popup, "Internal Error!", 55, 12, AlignLeft, AlignBottom);
|
||||||
@@ -45,11 +45,7 @@ void nfc_scene_mifare_desfire_app_on_enter(void* context) {
|
|||||||
text_box_set_font(nfc->text_box, TextBoxFontHex);
|
text_box_set_font(nfc->text_box, TextBoxFontHex);
|
||||||
|
|
||||||
submenu_add_item(
|
submenu_add_item(
|
||||||
submenu,
|
submenu, "App info", SubmenuIndexAppInfo, nfc_scene_mf_desfire_app_submenu_callback, nfc);
|
||||||
"App info",
|
|
||||||
SubmenuIndexAppInfo,
|
|
||||||
nfc_scene_mifare_desfire_app_submenu_callback,
|
|
||||||
nfc);
|
|
||||||
|
|
||||||
uint16_t cap = NFC_TEXT_STORE_SIZE;
|
uint16_t cap = NFC_TEXT_STORE_SIZE;
|
||||||
char* buf = nfc->text_store;
|
char* buf = nfc->text_store;
|
||||||
@@ -65,20 +61,19 @@ void nfc_scene_mifare_desfire_app_on_enter(void* context) {
|
|||||||
char* label = buf;
|
char* label = buf;
|
||||||
cap -= size + 1;
|
cap -= size + 1;
|
||||||
buf += size + 1;
|
buf += size + 1;
|
||||||
submenu_add_item(
|
submenu_add_item(submenu, label, idx++, nfc_scene_mf_desfire_app_submenu_callback, nfc);
|
||||||
submenu, label, idx++, nfc_scene_mifare_desfire_app_submenu_callback, nfc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool nfc_scene_mifare_desfire_app_on_event(void* context, SceneManagerEvent event) {
|
bool nfc_scene_mf_desfire_app_on_event(void* context, SceneManagerEvent event) {
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
bool consumed = false;
|
bool consumed = false;
|
||||||
uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareDesfireApp);
|
uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireApp);
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
MifareDesfireApplication* app = nfc_scene_mifare_desfire_app_get_app(nfc);
|
MifareDesfireApplication* app = nfc_scene_mf_desfire_app_get_app(nfc);
|
||||||
TextBox* text_box = nfc->text_box;
|
TextBox* text_box = nfc->text_box;
|
||||||
string_reset(nfc->text_box_store);
|
string_reset(nfc->text_box_store);
|
||||||
if(event.event == SubmenuIndexAppInfo) {
|
if(event.event == SubmenuIndexAppInfo) {
|
||||||
@@ -95,14 +90,13 @@ bool nfc_scene_mifare_desfire_app_on_event(void* context, SceneManagerEvent even
|
|||||||
mf_df_cat_file(file, nfc->text_box_store);
|
mf_df_cat_file(file, nfc->text_box_store);
|
||||||
}
|
}
|
||||||
text_box_set_text(text_box, string_get_cstr(nfc->text_box_store));
|
text_box_set_text(text_box, string_get_cstr(nfc->text_box_store));
|
||||||
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMifareDesfireApp, state | 1);
|
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfDesfireApp, state | 1);
|
||||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox);
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
} else if(event.type == SceneManagerEventTypeBack) {
|
} else if(event.type == SceneManagerEventTypeBack) {
|
||||||
if(state & 1) {
|
if(state & 1) {
|
||||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
|
||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfDesfireApp, state & ~1);
|
||||||
nfc->scene_manager, NfcSceneMifareDesfireApp, state & ~1);
|
|
||||||
consumed = true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -110,7 +104,7 @@ bool nfc_scene_mifare_desfire_app_on_event(void* context, SceneManagerEvent even
|
|||||||
return consumed;
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_mifare_desfire_app_on_exit(void* context) {
|
void nfc_scene_mf_desfire_app_on_exit(void* context) {
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
// Clear views
|
// Clear views
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#include "../nfc_i.h"
|
#include "../nfc_i.h"
|
||||||
|
|
||||||
#define TAG "NfcSceneMifareDesfireData"
|
#define TAG "NfcSceneMfDesfireData"
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
MifareDesfireDataStateMenu,
|
MifareDesfireDataStateMenu,
|
||||||
@@ -12,16 +12,16 @@ enum SubmenuIndex {
|
|||||||
SubmenuIndexDynamic, // dynamic indexes start here
|
SubmenuIndexDynamic, // dynamic indexes start here
|
||||||
};
|
};
|
||||||
|
|
||||||
void nfc_scene_mifare_desfire_data_submenu_callback(void* context, uint32_t index) {
|
void nfc_scene_mf_desfire_data_submenu_callback(void* context, uint32_t index) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = (Nfc*)context;
|
||||||
|
|
||||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_mifare_desfire_data_on_enter(void* context) {
|
void nfc_scene_mf_desfire_data_on_enter(void* context) {
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
Submenu* submenu = nfc->submenu;
|
Submenu* submenu = nfc->submenu;
|
||||||
uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareDesfireData);
|
uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireData);
|
||||||
MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data;
|
MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data;
|
||||||
|
|
||||||
text_box_set_font(nfc->text_box, TextBoxFontHex);
|
text_box_set_font(nfc->text_box, TextBoxFontHex);
|
||||||
@@ -30,7 +30,7 @@ void nfc_scene_mifare_desfire_data_on_enter(void* context) {
|
|||||||
submenu,
|
submenu,
|
||||||
"Card info",
|
"Card info",
|
||||||
SubmenuIndexCardInfo,
|
SubmenuIndexCardInfo,
|
||||||
nfc_scene_mifare_desfire_data_submenu_callback,
|
nfc_scene_mf_desfire_data_submenu_callback,
|
||||||
nfc);
|
nfc);
|
||||||
|
|
||||||
uint16_t cap = NFC_TEXT_STORE_SIZE;
|
uint16_t cap = NFC_TEXT_STORE_SIZE;
|
||||||
@@ -46,24 +46,23 @@ void nfc_scene_mifare_desfire_data_on_enter(void* context) {
|
|||||||
char* label = buf;
|
char* label = buf;
|
||||||
cap -= size + 1;
|
cap -= size + 1;
|
||||||
buf += size + 1;
|
buf += size + 1;
|
||||||
submenu_add_item(
|
submenu_add_item(submenu, label, idx++, nfc_scene_mf_desfire_data_submenu_callback, nfc);
|
||||||
submenu, label, idx++, nfc_scene_mifare_desfire_data_submenu_callback, nfc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(state >= MifareDesfireDataStateItem) {
|
if(state >= MifareDesfireDataStateItem) {
|
||||||
submenu_set_selected_item(
|
submenu_set_selected_item(
|
||||||
nfc->submenu, state - MifareDesfireDataStateItem + SubmenuIndexDynamic);
|
nfc->submenu, state - MifareDesfireDataStateItem + SubmenuIndexDynamic);
|
||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
nfc->scene_manager, NfcSceneMifareDesfireData, MifareDesfireDataStateMenu);
|
nfc->scene_manager, NfcSceneMfDesfireData, MifareDesfireDataStateMenu);
|
||||||
}
|
}
|
||||||
|
|
||||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool nfc_scene_mifare_desfire_data_on_event(void* context, SceneManagerEvent event) {
|
bool nfc_scene_mf_desfire_data_on_event(void* context, SceneManagerEvent event) {
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
bool consumed = false;
|
bool consumed = false;
|
||||||
uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareDesfireData);
|
uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireData);
|
||||||
MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data;
|
MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data;
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
@@ -75,23 +74,22 @@ bool nfc_scene_mifare_desfire_data_on_event(void* context, SceneManagerEvent eve
|
|||||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox);
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox);
|
||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
nfc->scene_manager,
|
nfc->scene_manager,
|
||||||
NfcSceneMifareDesfireData,
|
NfcSceneMfDesfireData,
|
||||||
MifareDesfireDataStateItem + SubmenuIndexCardInfo);
|
MifareDesfireDataStateItem + SubmenuIndexCardInfo);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
} else {
|
} else {
|
||||||
uint16_t index = event.event - SubmenuIndexDynamic;
|
uint16_t index = event.event - SubmenuIndexDynamic;
|
||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
nfc->scene_manager, NfcSceneMifareDesfireData, MifareDesfireDataStateItem + index);
|
nfc->scene_manager, NfcSceneMfDesfireData, MifareDesfireDataStateItem + index);
|
||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfDesfireApp, index << 1);
|
||||||
nfc->scene_manager, NfcSceneMifareDesfireApp, index << 1);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireApp);
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMifareDesfireApp);
|
|
||||||
consumed = true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
} else if(event.type == SceneManagerEventTypeBack) {
|
} else if(event.type == SceneManagerEventTypeBack) {
|
||||||
if(state >= MifareDesfireDataStateItem) {
|
if(state >= MifareDesfireDataStateItem) {
|
||||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
|
||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
nfc->scene_manager, NfcSceneMifareDesfireData, MifareDesfireDataStateMenu);
|
nfc->scene_manager, NfcSceneMfDesfireData, MifareDesfireDataStateMenu);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -99,7 +97,7 @@ bool nfc_scene_mifare_desfire_data_on_event(void* context, SceneManagerEvent eve
|
|||||||
return consumed;
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_mifare_desfire_data_on_exit(void* context) {
|
void nfc_scene_mf_desfire_data_on_exit(void* context) {
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
// Clear views
|
// Clear views
|
||||||
@@ -4,33 +4,32 @@ enum SubmenuIndex {
|
|||||||
SubmenuIndexSave,
|
SubmenuIndexSave,
|
||||||
};
|
};
|
||||||
|
|
||||||
void nfc_scene_mifare_desfire_menu_submenu_callback(void* context, uint32_t index) {
|
void nfc_scene_mf_desfire_menu_submenu_callback(void* context, uint32_t index) {
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_mifare_desfire_menu_on_enter(void* context) {
|
void nfc_scene_mf_desfire_menu_on_enter(void* context) {
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
Submenu* submenu = nfc->submenu;
|
Submenu* submenu = nfc->submenu;
|
||||||
|
|
||||||
submenu_add_item(
|
submenu_add_item(
|
||||||
submenu, "Save", SubmenuIndexSave, nfc_scene_mifare_desfire_menu_submenu_callback, nfc);
|
submenu, "Save", SubmenuIndexSave, nfc_scene_mf_desfire_menu_submenu_callback, nfc);
|
||||||
submenu_set_selected_item(
|
submenu_set_selected_item(
|
||||||
nfc->submenu,
|
nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireMenu));
|
||||||
scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareDesfireMenu));
|
|
||||||
|
|
||||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool nfc_scene_mifare_desfire_menu_on_event(void* context, SceneManagerEvent event) {
|
bool nfc_scene_mf_desfire_menu_on_event(void* context, SceneManagerEvent event) {
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
bool consumed = false;
|
bool consumed = false;
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
if(event.event == SubmenuIndexSave) {
|
if(event.event == SubmenuIndexSave) {
|
||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
nfc->scene_manager, NfcSceneMifareDesfireMenu, SubmenuIndexSave);
|
nfc->scene_manager, NfcSceneMfDesfireMenu, SubmenuIndexSave);
|
||||||
nfc->dev->format = NfcDeviceSaveFormatMifareDesfire;
|
nfc->dev->format = NfcDeviceSaveFormatMifareDesfire;
|
||||||
// Clear device name
|
// Clear device name
|
||||||
nfc_device_set_name(nfc->dev, "");
|
nfc_device_set_name(nfc->dev, "");
|
||||||
@@ -42,7 +41,7 @@ bool nfc_scene_mifare_desfire_menu_on_event(void* context, SceneManagerEvent eve
|
|||||||
return consumed;
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_mifare_desfire_menu_on_exit(void* context) {
|
void nfc_scene_mf_desfire_menu_on_exit(void* context) {
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
// Clear view
|
// Clear view
|
||||||
@@ -4,22 +4,22 @@
|
|||||||
#define NFC_SCENE_READ_SUCCESS_SHIFT " "
|
#define NFC_SCENE_READ_SUCCESS_SHIFT " "
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
ReadMifareDesfireSuccessStateShowUID,
|
MfDesfireReadSuccessStateShowUID,
|
||||||
ReadMifareDesfireSuccessStateShowData,
|
MfDesfireReadSuccessStateShowData,
|
||||||
};
|
};
|
||||||
|
|
||||||
void nfc_scene_read_mifare_desfire_success_dialog_callback(DialogExResult result, void* context) {
|
void nfc_scene_mf_desfire_read_success_dialog_callback(DialogExResult result, void* context) {
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_read_mifare_desfire_success_on_enter(void* context) {
|
void nfc_scene_mf_desfire_read_success_on_enter(void* context) {
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data;
|
MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data;
|
||||||
DialogEx* dialog_ex = nfc->dialog_ex;
|
DialogEx* dialog_ex = nfc->dialog_ex;
|
||||||
dialog_ex_set_left_button_text(dialog_ex, "Back");
|
dialog_ex_set_left_button_text(dialog_ex, "Retry");
|
||||||
dialog_ex_set_center_button_text(dialog_ex, "Data");
|
dialog_ex_set_center_button_text(dialog_ex, "Data");
|
||||||
dialog_ex_set_right_button_text(dialog_ex, "More");
|
dialog_ex_set_right_button_text(dialog_ex, "More");
|
||||||
dialog_ex_set_icon(dialog_ex, 8, 16, &I_Medium_chip_22x21);
|
dialog_ex_set_icon(dialog_ex, 8, 16, &I_Medium_chip_22x21);
|
||||||
@@ -55,41 +55,40 @@ void nfc_scene_read_mifare_desfire_success_on_enter(void* context) {
|
|||||||
n_files == 1 ? "" : "s");
|
n_files == 1 ? "" : "s");
|
||||||
dialog_ex_set_text(dialog_ex, nfc->text_store, 8, 6, AlignLeft, AlignTop);
|
dialog_ex_set_text(dialog_ex, nfc->text_store, 8, 6, AlignLeft, AlignTop);
|
||||||
dialog_ex_set_context(dialog_ex, nfc);
|
dialog_ex_set_context(dialog_ex, nfc);
|
||||||
dialog_ex_set_result_callback(
|
dialog_ex_set_result_callback(dialog_ex, nfc_scene_mf_desfire_read_success_dialog_callback);
|
||||||
dialog_ex, nfc_scene_read_mifare_desfire_success_dialog_callback);
|
|
||||||
|
|
||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
nfc->scene_manager,
|
nfc->scene_manager, NfcSceneMfDesfireReadSuccess, MfDesfireReadSuccessStateShowUID);
|
||||||
NfcSceneReadMifareDesfireSuccess,
|
|
||||||
ReadMifareDesfireSuccessStateShowUID);
|
|
||||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx);
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool nfc_scene_read_mifare_desfire_success_on_event(void* context, SceneManagerEvent event) {
|
bool nfc_scene_mf_desfire_read_success_on_event(void* context, SceneManagerEvent event) {
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
bool consumed = false;
|
bool consumed = false;
|
||||||
uint32_t state =
|
uint32_t state =
|
||||||
scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadMifareDesfireSuccess);
|
scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireReadSuccess);
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
if(state == ReadMifareDesfireSuccessStateShowUID && event.event == DialogExResultLeft) {
|
if(state == MfDesfireReadSuccessStateShowUID && event.event == DialogExResultLeft) {
|
||||||
scene_manager_previous_scene(nfc->scene_manager);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneRetryConfirm);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
} else if(
|
} else if(state == MfDesfireReadSuccessStateShowUID && event.event == DialogExResultCenter) {
|
||||||
state == ReadMifareDesfireSuccessStateShowUID && event.event == DialogExResultCenter) {
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireData);
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMifareDesfireData);
|
|
||||||
consumed = true;
|
consumed = true;
|
||||||
} else if(state == ReadMifareDesfireSuccessStateShowUID && event.event == DialogExResultRight) {
|
} else if(state == MfDesfireReadSuccessStateShowUID && event.event == DialogExResultRight) {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMifareDesfireMenu);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireMenu);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
} else if(event.type == SceneManagerEventTypeBack) {
|
} else if(event.type == SceneManagerEventTypeBack) {
|
||||||
if(state == ReadMifareDesfireSuccessStateShowData) {
|
if(state == MfDesfireReadSuccessStateShowData) {
|
||||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx);
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx);
|
||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
nfc->scene_manager,
|
nfc->scene_manager,
|
||||||
NfcSceneReadMifareDesfireSuccess,
|
NfcSceneMfDesfireReadSuccess,
|
||||||
ReadMifareDesfireSuccessStateShowUID);
|
MfDesfireReadSuccessStateShowUID);
|
||||||
|
consumed = true;
|
||||||
|
} else {
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -97,7 +96,7 @@ bool nfc_scene_read_mifare_desfire_success_on_event(void* context, SceneManagerE
|
|||||||
return consumed;
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_read_mifare_desfire_success_on_exit(void* context) {
|
void nfc_scene_mf_desfire_read_success_on_exit(void* context) {
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
// Clean dialog
|
// Clean dialog
|
||||||
@@ -4,51 +4,52 @@
|
|||||||
#define NFC_MF_UL_DATA_NOT_CHANGED (0UL)
|
#define NFC_MF_UL_DATA_NOT_CHANGED (0UL)
|
||||||
#define NFC_MF_UL_DATA_CHANGED (1UL)
|
#define NFC_MF_UL_DATA_CHANGED (1UL)
|
||||||
|
|
||||||
void nfc_emulate_mifare_ul_worker_callback(NfcWorkerEvent event, void* context) {
|
bool nfc_mf_ultralight_emulate_worker_callback(NfcWorkerEvent event, void* context) {
|
||||||
UNUSED(event);
|
UNUSED(event);
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
nfc->scene_manager, NfcSceneEmulateMifareUl, NFC_MF_UL_DATA_CHANGED);
|
nfc->scene_manager, NfcSceneMfUltralightEmulate, NFC_MF_UL_DATA_CHANGED);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_emulate_mifare_ul_on_enter(void* context) {
|
void nfc_scene_mf_ultralight_emulate_on_enter(void* context) {
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
DOLPHIN_DEED(DolphinDeedNfcEmulate);
|
DOLPHIN_DEED(DolphinDeedNfcEmulate);
|
||||||
|
|
||||||
// Setup view
|
// Setup view
|
||||||
Popup* popup = nfc->popup;
|
Popup* popup = nfc->popup;
|
||||||
if(strcmp(nfc->dev->dev_name, "")) {
|
if(strcmp(nfc->dev->dev_name, "")) {
|
||||||
nfc_text_store_set(nfc, "%s", nfc->dev->dev_name);
|
nfc_text_store_set(nfc, "Emulating\n%s", nfc->dev->dev_name);
|
||||||
|
} else {
|
||||||
|
nfc_text_store_set(nfc, "Emulating\nMf Ultralight", nfc->dev->dev_name);
|
||||||
}
|
}
|
||||||
popup_set_icon(popup, 0, 3, &I_RFIDDolphinSend_97x61);
|
popup_set_icon(popup, 0, 3, &I_RFIDDolphinSend_97x61);
|
||||||
popup_set_header(popup, "Emulating\nMf Ultralight", 56, 31, AlignLeft, AlignTop);
|
popup_set_header(popup, nfc->text_store, 56, 31, AlignLeft, AlignTop);
|
||||||
|
|
||||||
// Setup and start worker
|
// Setup and start worker
|
||||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
|
||||||
nfc_worker_start(
|
nfc_worker_start(
|
||||||
nfc->worker,
|
nfc->worker,
|
||||||
NfcWorkerStateEmulateMifareUltralight,
|
NfcWorkerStateMfUltralightEmulate,
|
||||||
&nfc->dev->dev_data,
|
&nfc->dev->dev_data,
|
||||||
nfc_emulate_mifare_ul_worker_callback,
|
nfc_mf_ultralight_emulate_worker_callback,
|
||||||
nfc);
|
nfc);
|
||||||
nfc_blink_start(nfc);
|
nfc_blink_start(nfc);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool nfc_scene_emulate_mifare_ul_on_event(void* context, SceneManagerEvent event) {
|
bool nfc_scene_mf_ultralight_emulate_on_event(void* context, SceneManagerEvent event) {
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
bool consumed = false;
|
bool consumed = false;
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeTick) {
|
if(event.type == SceneManagerEventTypeBack) {
|
||||||
consumed = true;
|
|
||||||
} else if(event.type == SceneManagerEventTypeBack) {
|
|
||||||
// Stop worker
|
// Stop worker
|
||||||
nfc_worker_stop(nfc->worker);
|
nfc_worker_stop(nfc->worker);
|
||||||
// Check if data changed and save in shadow file
|
// Check if data changed and save in shadow file
|
||||||
if(scene_manager_get_scene_state(nfc->scene_manager, NfcSceneEmulateMifareUl) ==
|
if(scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightEmulate) ==
|
||||||
NFC_MF_UL_DATA_CHANGED) {
|
NFC_MF_UL_DATA_CHANGED) {
|
||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
nfc->scene_manager, NfcSceneEmulateMifareUl, NFC_MF_UL_DATA_NOT_CHANGED);
|
nfc->scene_manager, NfcSceneMfUltralightEmulate, NFC_MF_UL_DATA_NOT_CHANGED);
|
||||||
nfc_device_save_shadow(nfc->dev, nfc->dev->dev_name);
|
nfc_device_save_shadow(nfc->dev, nfc->dev->dev_name);
|
||||||
}
|
}
|
||||||
consumed = false;
|
consumed = false;
|
||||||
@@ -56,7 +57,7 @@ bool nfc_scene_emulate_mifare_ul_on_event(void* context, SceneManagerEvent event
|
|||||||
return consumed;
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_emulate_mifare_ul_on_exit(void* context) {
|
void nfc_scene_mf_ultralight_emulate_on_exit(void* context) {
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
// Clear view
|
// Clear view
|
||||||
@@ -5,47 +5,47 @@ enum SubmenuIndex {
|
|||||||
SubmenuIndexEmulate,
|
SubmenuIndexEmulate,
|
||||||
};
|
};
|
||||||
|
|
||||||
void nfc_scene_mifare_classic_menu_submenu_callback(void* context, uint32_t index) {
|
void nfc_scene_mf_ultralight_menu_submenu_callback(void* context, uint32_t index) {
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_mifare_classic_menu_on_enter(void* context) {
|
void nfc_scene_mf_ultralight_menu_on_enter(void* context) {
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
Submenu* submenu = nfc->submenu;
|
Submenu* submenu = nfc->submenu;
|
||||||
|
|
||||||
submenu_add_item(
|
submenu_add_item(
|
||||||
submenu, "Save", SubmenuIndexSave, nfc_scene_mifare_classic_menu_submenu_callback, nfc);
|
submenu, "Save", SubmenuIndexSave, nfc_scene_mf_ultralight_menu_submenu_callback, nfc);
|
||||||
submenu_add_item(
|
submenu_add_item(
|
||||||
submenu,
|
submenu,
|
||||||
"Emulate",
|
"Emulate",
|
||||||
SubmenuIndexEmulate,
|
SubmenuIndexEmulate,
|
||||||
nfc_scene_mifare_classic_menu_submenu_callback,
|
nfc_scene_mf_ultralight_menu_submenu_callback,
|
||||||
nfc);
|
nfc);
|
||||||
submenu_set_selected_item(
|
submenu_set_selected_item(
|
||||||
nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareUlMenu));
|
nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightMenu));
|
||||||
|
|
||||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool nfc_scene_mifare_classic_menu_on_event(void* context, SceneManagerEvent event) {
|
bool nfc_scene_mf_ultralight_menu_on_event(void* context, SceneManagerEvent event) {
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
bool consumed = false;
|
bool consumed = false;
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
if(event.event == SubmenuIndexSave) {
|
if(event.event == SubmenuIndexSave) {
|
||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
nfc->scene_manager, NfcSceneMifareUlMenu, SubmenuIndexSave);
|
nfc->scene_manager, NfcSceneMfUltralightMenu, SubmenuIndexSave);
|
||||||
nfc->dev->format = NfcDeviceSaveFormatMifareClassic;
|
nfc->dev->format = NfcDeviceSaveFormatMifareUl;
|
||||||
// Clear device name
|
// Clear device name
|
||||||
nfc_device_set_name(nfc->dev, "");
|
nfc_device_set_name(nfc->dev, "");
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
} else if(event.event == SubmenuIndexEmulate) {
|
} else if(event.event == SubmenuIndexEmulate) {
|
||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
nfc->scene_manager, NfcSceneMifareUlMenu, SubmenuIndexEmulate);
|
nfc->scene_manager, NfcSceneMfUltralightMenu, SubmenuIndexEmulate);
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareClassic);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
} else if(event.type == SceneManagerEventTypeBack) {
|
} else if(event.type == SceneManagerEventTypeBack) {
|
||||||
@@ -56,7 +56,7 @@ bool nfc_scene_mifare_classic_menu_on_event(void* context, SceneManagerEvent eve
|
|||||||
return consumed;
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_mifare_classic_menu_on_exit(void* context) {
|
void nfc_scene_mf_ultralight_menu_on_exit(void* context) {
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
// Clear view
|
// Clear view
|
||||||
@@ -8,19 +8,16 @@ enum {
|
|||||||
ReadMifareUlStateShowData,
|
ReadMifareUlStateShowData,
|
||||||
};
|
};
|
||||||
|
|
||||||
void nfc_scene_read_mifare_ul_success_dialog_callback(DialogExResult result, void* context) {
|
void nfc_scene_mf_ultralight_read_success_dialog_callback(DialogExResult result, void* context) {
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_read_mifare_ul_success_on_enter(void* context) {
|
void nfc_scene_mf_ultralight_read_success_on_enter(void* context) {
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
|
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
|
||||||
|
|
||||||
// Send notification
|
|
||||||
notification_message(nfc->notifications, &sequence_success);
|
|
||||||
|
|
||||||
// Setup dialog view
|
// Setup dialog view
|
||||||
FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data;
|
FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data;
|
||||||
MfUltralightData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data;
|
MfUltralightData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data;
|
||||||
@@ -48,7 +45,7 @@ void nfc_scene_read_mifare_ul_success_on_enter(void* context) {
|
|||||||
data->uid[6]);
|
data->uid[6]);
|
||||||
dialog_ex_set_text(dialog_ex, nfc->text_store, 8, 16, AlignLeft, AlignTop);
|
dialog_ex_set_text(dialog_ex, nfc->text_store, 8, 16, AlignLeft, AlignTop);
|
||||||
dialog_ex_set_context(dialog_ex, nfc);
|
dialog_ex_set_context(dialog_ex, nfc);
|
||||||
dialog_ex_set_result_callback(dialog_ex, nfc_scene_read_mifare_ul_success_dialog_callback);
|
dialog_ex_set_result_callback(dialog_ex, nfc_scene_mf_ultralight_read_success_dialog_callback);
|
||||||
|
|
||||||
// Setup TextBox view
|
// Setup TextBox view
|
||||||
TextBox* text_box = nfc->text_box;
|
TextBox* text_box = nfc->text_box;
|
||||||
@@ -63,34 +60,37 @@ void nfc_scene_read_mifare_ul_success_on_enter(void* context) {
|
|||||||
text_box_set_text(text_box, string_get_cstr(nfc->text_box_store));
|
text_box_set_text(text_box, string_get_cstr(nfc->text_box_store));
|
||||||
|
|
||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
nfc->scene_manager, NfcSceneReadMifareUlSuccess, ReadMifareUlStateShowUID);
|
nfc->scene_manager, NfcSceneMfUltralightReadSuccess, ReadMifareUlStateShowUID);
|
||||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx);
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool nfc_scene_read_mifare_ul_success_on_event(void* context, SceneManagerEvent event) {
|
bool nfc_scene_mf_ultralight_read_success_on_event(void* context, SceneManagerEvent event) {
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
bool consumed = false;
|
bool consumed = false;
|
||||||
uint32_t state =
|
uint32_t state =
|
||||||
scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadMifareUlSuccess);
|
scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightReadSuccess);
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
if(state == ReadMifareUlStateShowUID && event.event == DialogExResultLeft) {
|
if(state == ReadMifareUlStateShowUID && event.event == DialogExResultLeft) {
|
||||||
scene_manager_previous_scene(nfc->scene_manager);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneRetryConfirm);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
} else if(state == ReadMifareUlStateShowUID && event.event == DialogExResultRight) {
|
} else if(state == ReadMifareUlStateShowUID && event.event == DialogExResultRight) {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMifareUlMenu);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightMenu);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
} else if(state == ReadMifareUlStateShowUID && event.event == DialogExResultCenter) {
|
} else if(state == ReadMifareUlStateShowUID && event.event == DialogExResultCenter) {
|
||||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox);
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox);
|
||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
nfc->scene_manager, NfcSceneReadMifareUlSuccess, ReadMifareUlStateShowData);
|
nfc->scene_manager, NfcSceneMfUltralightReadSuccess, ReadMifareUlStateShowData);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
} else if(event.type == SceneManagerEventTypeBack) {
|
} else if(event.type == SceneManagerEventTypeBack) {
|
||||||
if(state == ReadMifareUlStateShowData) {
|
if(state == ReadMifareUlStateShowData) {
|
||||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx);
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx);
|
||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
nfc->scene_manager, NfcSceneReadMifareUlSuccess, ReadMifareUlStateShowUID);
|
nfc->scene_manager, NfcSceneMfUltralightReadSuccess, ReadMifareUlStateShowUID);
|
||||||
|
consumed = true;
|
||||||
|
} else {
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneExitConfirm);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -98,7 +98,7 @@ bool nfc_scene_read_mifare_ul_success_on_event(void* context, SceneManagerEvent
|
|||||||
return consumed;
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_scene_read_mifare_ul_success_on_exit(void* context) {
|
void nfc_scene_mf_ultralight_read_success_on_exit(void* context) {
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
|
|
||||||
// Clean views
|
// Clean views
|
||||||
108
applications/nfc/scenes/nfc_scene_read.c
Normal file
108
applications/nfc/scenes/nfc_scene_read.c
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
#include "../nfc_i.h"
|
||||||
|
#include <dolphin/dolphin.h>
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
NfcSceneReadStateIdle,
|
||||||
|
NfcSceneReadStateDetecting,
|
||||||
|
NfcSceneReadStateReading,
|
||||||
|
} NfcSceneReadState;
|
||||||
|
|
||||||
|
bool nfc_scene_read_worker_callback(NfcWorkerEvent event, void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
bool consumed = false;
|
||||||
|
if(event == NfcWorkerEventReadMfClassicLoadKeyCache) {
|
||||||
|
consumed = nfc_device_load_key_cache(nfc->dev);
|
||||||
|
} else {
|
||||||
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, event);
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_read_set_state(Nfc* nfc, NfcSceneReadState state) {
|
||||||
|
uint32_t curr_state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneRead);
|
||||||
|
if(curr_state != state) {
|
||||||
|
if(state == NfcSceneReadStateDetecting) {
|
||||||
|
popup_set_header(nfc->popup, "Detecting\nNFC card", 90, 24, AlignCenter, AlignTop);
|
||||||
|
popup_set_icon(nfc->popup, 5, 7, &I_NFC_manual);
|
||||||
|
} else if(state == NfcSceneReadStateReading) {
|
||||||
|
popup_set_header(
|
||||||
|
nfc->popup, "Reading card\nDon't move...", 85, 24, AlignCenter, AlignTop);
|
||||||
|
popup_set_icon(nfc->popup, 19, 23, &A_Loading_24);
|
||||||
|
}
|
||||||
|
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneRead, state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_read_on_enter(void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
DOLPHIN_DEED(DolphinDeedNfcRead);
|
||||||
|
|
||||||
|
nfc_device_clear(nfc->dev);
|
||||||
|
// Setup view
|
||||||
|
nfc_scene_read_set_state(nfc, NfcSceneReadStateDetecting);
|
||||||
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
|
||||||
|
// Start worker
|
||||||
|
nfc_worker_start(
|
||||||
|
nfc->worker, NfcWorkerStateRead, &nfc->dev->dev_data, nfc_scene_read_worker_callback, nfc);
|
||||||
|
|
||||||
|
nfc_blink_start(nfc);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nfc_scene_read_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
|
if((event.event == NfcWorkerEventReadUidNfcB) ||
|
||||||
|
(event.event == NfcWorkerEventReadUidNfcF) ||
|
||||||
|
(event.event == NfcWorkerEventReadUidNfcV) ||
|
||||||
|
(event.event == NfcWorkerEventReadUidNfcA)) {
|
||||||
|
notification_message(nfc->notifications, &sequence_success);
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardSuccess);
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == NfcWorkerEventReadMfUltralight) {
|
||||||
|
notification_message(nfc->notifications, &sequence_success);
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadSuccess);
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == NfcWorkerEventReadMfClassicDone) {
|
||||||
|
notification_message(nfc->notifications, &sequence_success);
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSuccess);
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == NfcWorkerEventReadMfDesfire) {
|
||||||
|
notification_message(nfc->notifications, &sequence_success);
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireReadSuccess);
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == NfcWorkerEventReadBankCard) {
|
||||||
|
notification_message(nfc->notifications, &sequence_success);
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmvReadSuccess);
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == NfcWorkerEventReadMfClassicDictAttackRequired) {
|
||||||
|
if(mf_classic_dict_check_presence(MfClassicDictTypeFlipper)) {
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicDictAttack);
|
||||||
|
} else {
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound);
|
||||||
|
}
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == NfcWorkerEventCardDetected) {
|
||||||
|
nfc_scene_read_set_state(nfc, NfcSceneReadStateReading);
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == NfcWorkerEventNoCardDetected) {
|
||||||
|
nfc_scene_read_set_state(nfc, NfcSceneReadStateDetecting);
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_read_on_exit(void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
// Stop worker
|
||||||
|
nfc_worker_stop(nfc->worker);
|
||||||
|
// Clear view
|
||||||
|
popup_reset(nfc->popup);
|
||||||
|
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneRead, NfcSceneReadStateIdle);
|
||||||
|
|
||||||
|
nfc_blink_stop(nfc);
|
||||||
|
}
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
#include "../nfc_i.h"
|
|
||||||
#include <dolphin/dolphin.h>
|
|
||||||
|
|
||||||
void nfc_read_card_worker_callback(NfcWorkerEvent event, void* context) {
|
|
||||||
UNUSED(event);
|
|
||||||
Nfc* nfc = context;
|
|
||||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit);
|
|
||||||
}
|
|
||||||
|
|
||||||
void nfc_scene_read_card_on_enter(void* context) {
|
|
||||||
Nfc* nfc = context;
|
|
||||||
DOLPHIN_DEED(DolphinDeedNfcRead);
|
|
||||||
|
|
||||||
// Setup view
|
|
||||||
Popup* popup = nfc->popup;
|
|
||||||
popup_set_header(popup, "Detecting\nNFC card", 70, 34, AlignLeft, AlignTop);
|
|
||||||
popup_set_icon(popup, 0, 3, &I_RFIDDolphinReceive_97x61);
|
|
||||||
|
|
||||||
// Start worker
|
|
||||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
|
|
||||||
nfc_worker_start(
|
|
||||||
nfc->worker, NfcWorkerStateDetect, &nfc->dev->dev_data, nfc_read_card_worker_callback, nfc);
|
|
||||||
|
|
||||||
nfc_blink_start(nfc);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool nfc_scene_read_card_on_event(void* context, SceneManagerEvent event) {
|
|
||||||
Nfc* nfc = context;
|
|
||||||
bool consumed = false;
|
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
|
||||||
if(event.event == NfcCustomEventWorkerExit) {
|
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardSuccess);
|
|
||||||
consumed = true;
|
|
||||||
}
|
|
||||||
} else if(event.type == SceneManagerEventTypeTick) {
|
|
||||||
consumed = true;
|
|
||||||
}
|
|
||||||
return consumed;
|
|
||||||
}
|
|
||||||
|
|
||||||
void nfc_scene_read_card_on_exit(void* context) {
|
|
||||||
Nfc* nfc = context;
|
|
||||||
|
|
||||||
// Stop worker
|
|
||||||
nfc_worker_stop(nfc->worker);
|
|
||||||
// Clear view
|
|
||||||
popup_reset(nfc->popup);
|
|
||||||
|
|
||||||
nfc_blink_stop(nfc);
|
|
||||||
}
|
|
||||||
@@ -22,9 +22,6 @@ void nfc_scene_read_card_success_on_enter(void* context) {
|
|||||||
string_init(uid_str);
|
string_init(uid_str);
|
||||||
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
|
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
|
||||||
|
|
||||||
// Send notification
|
|
||||||
notification_message(nfc->notifications, &sequence_success);
|
|
||||||
|
|
||||||
// Setup view
|
// Setup view
|
||||||
FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data;
|
FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data;
|
||||||
Widget* widget = nfc->widget;
|
Widget* widget = nfc->widget;
|
||||||
@@ -38,18 +35,12 @@ void nfc_scene_read_card_success_on_enter(void* context) {
|
|||||||
widget, GuiButtonTypeLeft, "Retry", nfc_scene_read_card_success_widget_callback, nfc);
|
widget, GuiButtonTypeLeft, "Retry", nfc_scene_read_card_success_widget_callback, nfc);
|
||||||
if(data->type == FuriHalNfcTypeA) {
|
if(data->type == FuriHalNfcTypeA) {
|
||||||
widget_add_button_element(
|
widget_add_button_element(
|
||||||
widget, GuiButtonTypeRight, "More", nfc_scene_read_card_success_widget_callback, nfc);
|
widget, GuiButtonTypeRight, "Save", nfc_scene_read_card_success_widget_callback, nfc);
|
||||||
widget_add_icon_element(widget, 8, 13, &I_Medium_chip_22x21);
|
widget_add_icon_element(widget, 8, 13, &I_Medium_chip_22x21);
|
||||||
string_cat_printf(data_str, " may be:");
|
|
||||||
widget_add_string_element(
|
widget_add_string_element(
|
||||||
widget, 37, 12, AlignLeft, AlignBottom, FontPrimary, string_get_cstr(data_str));
|
widget, 37, 12, AlignLeft, AlignBottom, FontPrimary, string_get_cstr(data_str));
|
||||||
string_printf(
|
string_printf(
|
||||||
data_str,
|
data_str, "ATQA: %02X%02X\nSAK: %02X", data->atqa[0], data->atqa[1], data->sak);
|
||||||
"%s\nATQA: %02X%02X SAK: %02X",
|
|
||||||
nfc_guess_protocol(nfc->dev->dev_data.protocol),
|
|
||||||
data->atqa[0],
|
|
||||||
data->atqa[1],
|
|
||||||
data->sak);
|
|
||||||
widget_add_string_multiline_element(
|
widget_add_string_multiline_element(
|
||||||
widget, 37, 16, AlignLeft, AlignTop, FontSecondary, string_get_cstr(data_str));
|
widget, 37, 16, AlignLeft, AlignTop, FontSecondary, string_get_cstr(data_str));
|
||||||
widget_add_string_element(
|
widget_add_string_element(
|
||||||
@@ -69,16 +60,15 @@ void nfc_scene_read_card_success_on_enter(void* context) {
|
|||||||
|
|
||||||
bool nfc_scene_read_card_success_on_event(void* context, SceneManagerEvent event) {
|
bool nfc_scene_read_card_success_on_event(void* context, SceneManagerEvent event) {
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data;
|
|
||||||
bool consumed = false;
|
bool consumed = false;
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
if(event.event == GuiButtonTypeLeft) {
|
if(event.event == GuiButtonTypeLeft) {
|
||||||
consumed = scene_manager_previous_scene(nfc->scene_manager);
|
consumed = scene_manager_previous_scene(nfc->scene_manager);
|
||||||
} else if(data->type == FuriHalNfcTypeA && event.event == GuiButtonTypeRight) {
|
} else if(event.event == GuiButtonTypeRight) {
|
||||||
// Clear device name
|
nfc->dev->format = NfcDeviceSaveFormatUid;
|
||||||
nfc_device_set_name(nfc->dev, "");
|
nfc_device_set_name(nfc->dev, "");
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneCardMenu);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,58 +0,0 @@
|
|||||||
#include "../nfc_i.h"
|
|
||||||
#include <dolphin/dolphin.h>
|
|
||||||
|
|
||||||
void nfc_read_emv_app_worker_callback(NfcWorkerEvent event, void* context) {
|
|
||||||
UNUSED(event);
|
|
||||||
Nfc* nfc = context;
|
|
||||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit);
|
|
||||||
}
|
|
||||||
|
|
||||||
void nfc_scene_read_emv_app_on_enter(void* context) {
|
|
||||||
Nfc* nfc = context;
|
|
||||||
DOLPHIN_DEED(DolphinDeedNfcRead);
|
|
||||||
|
|
||||||
// Setup view
|
|
||||||
Popup* popup = nfc->popup;
|
|
||||||
popup_set_header(popup, "Reading\nbank card", 70, 34, AlignLeft, AlignTop);
|
|
||||||
popup_set_icon(popup, 0, 3, &I_RFIDDolphinReceive_97x61);
|
|
||||||
|
|
||||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
|
|
||||||
// Start worker
|
|
||||||
nfc_worker_start(
|
|
||||||
nfc->worker,
|
|
||||||
NfcWorkerStateReadEMVApp,
|
|
||||||
&nfc->dev->dev_data,
|
|
||||||
nfc_read_emv_app_worker_callback,
|
|
||||||
nfc);
|
|
||||||
nfc_blink_start(nfc);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool nfc_scene_read_emv_app_on_event(void* context, SceneManagerEvent event) {
|
|
||||||
Nfc* nfc = context;
|
|
||||||
bool consumed = false;
|
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
|
||||||
if(event.event == NfcCustomEventWorkerExit) {
|
|
||||||
scene_manager_set_scene_state(
|
|
||||||
nfc->scene_manager, NfcSceneReadEmvAppSuccess, NFC_SEND_NOTIFICATION_TRUE);
|
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvAppSuccess);
|
|
||||||
consumed = true;
|
|
||||||
}
|
|
||||||
} else if(event.type == SceneManagerEventTypeTick) {
|
|
||||||
consumed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return consumed;
|
|
||||||
}
|
|
||||||
|
|
||||||
void nfc_scene_read_emv_app_on_exit(void* context) {
|
|
||||||
Nfc* nfc = context;
|
|
||||||
|
|
||||||
// Stop worker
|
|
||||||
nfc_worker_stop(nfc->worker);
|
|
||||||
|
|
||||||
// Clear view
|
|
||||||
popup_reset(nfc->popup);
|
|
||||||
|
|
||||||
nfc_blink_stop(nfc);
|
|
||||||
}
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
#include "../nfc_i.h"
|
|
||||||
#include "../helpers/nfc_emv_parser.h"
|
|
||||||
#include <dolphin/dolphin.h>
|
|
||||||
|
|
||||||
void nfc_scene_read_emv_app_widget_callback(GuiButtonType result, InputType type, void* context) {
|
|
||||||
Nfc* nfc = context;
|
|
||||||
if(type == InputTypeShort) {
|
|
||||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void nfc_scene_read_emv_app_success_on_enter(void* context) {
|
|
||||||
Nfc* nfc = context;
|
|
||||||
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
|
|
||||||
|
|
||||||
// Setup view
|
|
||||||
FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data;
|
|
||||||
EmvData* emv_data = &nfc->dev->dev_data.emv_data;
|
|
||||||
Widget* widget = nfc->widget;
|
|
||||||
widget_add_button_element(
|
|
||||||
widget, GuiButtonTypeLeft, "Retry", nfc_scene_read_emv_app_widget_callback, nfc);
|
|
||||||
widget_add_button_element(
|
|
||||||
widget, GuiButtonTypeRight, "Run app", nfc_scene_read_emv_app_widget_callback, nfc);
|
|
||||||
widget_add_string_element(widget, 36, 5, AlignLeft, AlignTop, FontPrimary, "Found EMV App");
|
|
||||||
widget_add_icon_element(widget, 8, 5, &I_Medium_chip_22x21);
|
|
||||||
// Display UID
|
|
||||||
string_t temp_str;
|
|
||||||
string_init_printf(temp_str, "UID:");
|
|
||||||
for(size_t i = 0; i < nfc_data->uid_len; i++) {
|
|
||||||
string_cat_printf(temp_str, " %02X", nfc_data->uid[i]);
|
|
||||||
}
|
|
||||||
widget_add_string_element(
|
|
||||||
widget, 36, 18, AlignLeft, AlignTop, FontSecondary, string_get_cstr(temp_str));
|
|
||||||
string_reset(temp_str);
|
|
||||||
// Display application
|
|
||||||
string_printf(temp_str, "App: ");
|
|
||||||
string_t aid;
|
|
||||||
string_init(aid);
|
|
||||||
bool aid_found =
|
|
||||||
nfc_emv_parser_get_aid_name(nfc->dev->storage, emv_data->aid, emv_data->aid_len, aid);
|
|
||||||
if(!aid_found) {
|
|
||||||
for(uint8_t i = 0; i < emv_data->aid_len; i++) {
|
|
||||||
string_cat_printf(aid, "%02X", emv_data->aid[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
string_cat(temp_str, aid);
|
|
||||||
widget_add_string_element(
|
|
||||||
widget, 7, 29, AlignLeft, AlignTop, FontSecondary, string_get_cstr(temp_str));
|
|
||||||
string_clear(temp_str);
|
|
||||||
string_clear(aid);
|
|
||||||
|
|
||||||
// Send notification
|
|
||||||
if(scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadEmvAppSuccess) ==
|
|
||||||
NFC_SEND_NOTIFICATION_TRUE) {
|
|
||||||
notification_message(nfc->notifications, &sequence_success);
|
|
||||||
scene_manager_set_scene_state(
|
|
||||||
nfc->scene_manager, NfcSceneReadEmvAppSuccess, NFC_SEND_NOTIFICATION_FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool nfc_scene_read_emv_app_success_on_event(void* context, SceneManagerEvent event) {
|
|
||||||
Nfc* nfc = context;
|
|
||||||
bool consumed = false;
|
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
|
||||||
if(event.event == GuiButtonTypeLeft) {
|
|
||||||
consumed = scene_manager_previous_scene(nfc->scene_manager);
|
|
||||||
} else if(event.event == GuiButtonTypeRight) {
|
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneRunEmvAppConfirm);
|
|
||||||
consumed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return consumed;
|
|
||||||
}
|
|
||||||
|
|
||||||
void nfc_scene_read_emv_app_success_on_exit(void* context) {
|
|
||||||
Nfc* nfc = context;
|
|
||||||
|
|
||||||
// Clear views
|
|
||||||
widget_reset(nfc->widget);
|
|
||||||
}
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
#include "../nfc_i.h"
|
|
||||||
#include <dolphin/dolphin.h>
|
|
||||||
|
|
||||||
void nfc_read_emv_data_worker_callback(NfcWorkerEvent event, void* context) {
|
|
||||||
UNUSED(event);
|
|
||||||
Nfc* nfc = context;
|
|
||||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit);
|
|
||||||
}
|
|
||||||
|
|
||||||
void nfc_scene_read_emv_data_on_enter(void* context) {
|
|
||||||
Nfc* nfc = context;
|
|
||||||
DOLPHIN_DEED(DolphinDeedNfcRead);
|
|
||||||
|
|
||||||
// Setup view
|
|
||||||
Popup* popup = nfc->popup;
|
|
||||||
popup_set_header(popup, "Reading\nbank card", 70, 34, AlignLeft, AlignTop);
|
|
||||||
popup_set_icon(popup, 0, 3, &I_RFIDDolphinReceive_97x61);
|
|
||||||
|
|
||||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
|
|
||||||
// Clear emv data
|
|
||||||
memset(&nfc->dev->dev_data.emv_data, 0, sizeof(nfc->dev->dev_data.emv_data));
|
|
||||||
// Start worker
|
|
||||||
nfc_worker_start(
|
|
||||||
nfc->worker,
|
|
||||||
NfcWorkerStateReadEMVData,
|
|
||||||
&nfc->dev->dev_data,
|
|
||||||
nfc_read_emv_data_worker_callback,
|
|
||||||
nfc);
|
|
||||||
|
|
||||||
nfc_blink_start(nfc);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool nfc_scene_read_emv_data_on_event(void* context, SceneManagerEvent event) {
|
|
||||||
Nfc* nfc = context;
|
|
||||||
bool consumed = false;
|
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
|
||||||
if(event.event == NfcCustomEventWorkerExit) {
|
|
||||||
scene_manager_set_scene_state(
|
|
||||||
nfc->scene_manager, NfcSceneReadEmvDataSuccess, NFC_SEND_NOTIFICATION_TRUE);
|
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvDataSuccess);
|
|
||||||
consumed = true;
|
|
||||||
}
|
|
||||||
} else if(event.type == SceneManagerEventTypeTick) {
|
|
||||||
consumed = true;
|
|
||||||
}
|
|
||||||
return consumed;
|
|
||||||
}
|
|
||||||
|
|
||||||
void nfc_scene_read_emv_data_on_exit(void* context) {
|
|
||||||
Nfc* nfc = context;
|
|
||||||
|
|
||||||
// Stop worker
|
|
||||||
nfc_worker_stop(nfc->worker);
|
|
||||||
// Clear view
|
|
||||||
popup_reset(nfc->popup);
|
|
||||||
|
|
||||||
nfc_blink_stop(nfc);
|
|
||||||
}
|
|
||||||
@@ -1,96 +0,0 @@
|
|||||||
#include "../nfc_i.h"
|
|
||||||
|
|
||||||
enum {
|
|
||||||
NfcSceneReadMifareClassicStateInProgress,
|
|
||||||
NfcSceneReadMifareClassicStateDone,
|
|
||||||
};
|
|
||||||
|
|
||||||
void nfc_read_mifare_classic_worker_callback(NfcWorkerEvent event, void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
Nfc* nfc = context;
|
|
||||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
void nfc_read_mifare_classic_dict_attack_result_callback(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
Nfc* nfc = context;
|
|
||||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventDictAttackDone);
|
|
||||||
}
|
|
||||||
|
|
||||||
void nfc_scene_read_mifare_classic_on_enter(void* context) {
|
|
||||||
Nfc* nfc = context;
|
|
||||||
|
|
||||||
// Setup and start worker
|
|
||||||
memset(&nfc->dev->dev_data.mf_classic_data, 0, sizeof(MfClassicData));
|
|
||||||
dict_attack_set_result_callback(
|
|
||||||
nfc->dict_attack, nfc_read_mifare_classic_dict_attack_result_callback, nfc);
|
|
||||||
scene_manager_set_scene_state(
|
|
||||||
nfc->scene_manager, NfcSceneReadMifareClassic, NfcSceneReadMifareClassicStateInProgress);
|
|
||||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDictAttack);
|
|
||||||
nfc_worker_start(
|
|
||||||
nfc->worker,
|
|
||||||
NfcWorkerStateReadMifareClassic,
|
|
||||||
&nfc->dev->dev_data,
|
|
||||||
nfc_read_mifare_classic_worker_callback,
|
|
||||||
nfc);
|
|
||||||
|
|
||||||
nfc_blink_start(nfc);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool nfc_scene_read_mifare_classic_on_event(void* context, SceneManagerEvent event) {
|
|
||||||
Nfc* nfc = context;
|
|
||||||
bool consumed = false;
|
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeTick) {
|
|
||||||
consumed = true;
|
|
||||||
} else if(event.type == SceneManagerEventTypeCustom) {
|
|
||||||
if(event.event == NfcCustomEventDictAttackDone) {
|
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMifareClassicMenu);
|
|
||||||
consumed = true;
|
|
||||||
} else if(event.event == NfcWorkerEventDetectedClassic1k) {
|
|
||||||
dict_attack_card_detected(nfc->dict_attack, MfClassicType1k);
|
|
||||||
consumed = true;
|
|
||||||
} else if(event.event == NfcWorkerEventDetectedClassic4k) {
|
|
||||||
dict_attack_card_detected(nfc->dict_attack, MfClassicType4k);
|
|
||||||
consumed = true;
|
|
||||||
} else if(event.event == NfcWorkerEventNewSector) {
|
|
||||||
dict_attack_inc_curr_sector(nfc->dict_attack);
|
|
||||||
consumed = true;
|
|
||||||
} else if(event.event == NfcWorkerEventFoundKeyA) {
|
|
||||||
dict_attack_inc_found_key(nfc->dict_attack, MfClassicKeyA);
|
|
||||||
consumed = true;
|
|
||||||
} else if(event.event == NfcWorkerEventFoundKeyB) {
|
|
||||||
dict_attack_inc_found_key(nfc->dict_attack, MfClassicKeyB);
|
|
||||||
consumed = true;
|
|
||||||
} else if(event.event == NfcWorkerEventNoCardDetected) {
|
|
||||||
dict_attack_card_removed(nfc->dict_attack);
|
|
||||||
consumed = true;
|
|
||||||
} else if(event.event == NfcWorkerEventSuccess) {
|
|
||||||
scene_manager_set_scene_state(
|
|
||||||
nfc->scene_manager, NfcSceneReadMifareClassic, NfcSceneReadMifareClassicStateDone);
|
|
||||||
nfc_blink_stop(nfc);
|
|
||||||
notification_message(nfc->notifications, &sequence_success);
|
|
||||||
dict_attack_set_result(nfc->dict_attack, true);
|
|
||||||
consumed = true;
|
|
||||||
} else if(event.event == NfcWorkerEventFail) {
|
|
||||||
scene_manager_set_scene_state(
|
|
||||||
nfc->scene_manager, NfcSceneReadMifareClassic, NfcSceneReadMifareClassicStateDone);
|
|
||||||
nfc_blink_stop(nfc);
|
|
||||||
dict_attack_set_result(nfc->dict_attack, false);
|
|
||||||
consumed = true;
|
|
||||||
} else if(event.event == NfcWorkerEventNoDictFound) {
|
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound);
|
|
||||||
consumed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return consumed;
|
|
||||||
}
|
|
||||||
|
|
||||||
void nfc_scene_read_mifare_classic_on_exit(void* context) {
|
|
||||||
Nfc* nfc = context;
|
|
||||||
// Stop worker
|
|
||||||
nfc_worker_stop(nfc->worker);
|
|
||||||
dict_attack_reset(nfc->dict_attack);
|
|
||||||
|
|
||||||
nfc_blink_stop(nfc);
|
|
||||||
}
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
#include "../nfc_i.h"
|
|
||||||
#include <dolphin/dolphin.h>
|
|
||||||
|
|
||||||
void nfc_read_mifare_desfire_worker_callback(NfcWorkerEvent event, void* context) {
|
|
||||||
UNUSED(event);
|
|
||||||
Nfc* nfc = context;
|
|
||||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit);
|
|
||||||
}
|
|
||||||
|
|
||||||
void nfc_scene_read_mifare_desfire_on_enter(void* context) {
|
|
||||||
Nfc* nfc = context;
|
|
||||||
DOLPHIN_DEED(DolphinDeedNfcRead);
|
|
||||||
|
|
||||||
// Setup view
|
|
||||||
Popup* popup = nfc->popup;
|
|
||||||
popup_set_header(popup, "Reading\nDESFire", 70, 34, AlignLeft, AlignTop);
|
|
||||||
popup_set_icon(popup, 0, 3, &I_RFIDDolphinReceive_97x61);
|
|
||||||
|
|
||||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
|
|
||||||
// Start worker
|
|
||||||
nfc_worker_start(
|
|
||||||
nfc->worker,
|
|
||||||
NfcWorkerStateReadMifareDesfire,
|
|
||||||
&nfc->dev->dev_data,
|
|
||||||
nfc_read_mifare_desfire_worker_callback,
|
|
||||||
nfc);
|
|
||||||
nfc_blink_start(nfc);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool nfc_scene_read_mifare_desfire_on_event(void* context, SceneManagerEvent event) {
|
|
||||||
Nfc* nfc = context;
|
|
||||||
bool consumed = false;
|
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
|
||||||
if(event.event == NfcCustomEventWorkerExit) {
|
|
||||||
notification_message(nfc->notifications, &sequence_success);
|
|
||||||
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
|
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareDesfireSuccess);
|
|
||||||
consumed = true;
|
|
||||||
}
|
|
||||||
} else if(event.type == SceneManagerEventTypeTick) {
|
|
||||||
consumed = true;
|
|
||||||
}
|
|
||||||
return consumed;
|
|
||||||
}
|
|
||||||
|
|
||||||
void nfc_scene_read_mifare_desfire_on_exit(void* context) {
|
|
||||||
Nfc* nfc = context;
|
|
||||||
|
|
||||||
// Stop worker
|
|
||||||
nfc_worker_stop(nfc->worker);
|
|
||||||
// Clear view
|
|
||||||
popup_reset(nfc->popup);
|
|
||||||
|
|
||||||
nfc_blink_stop(nfc);
|
|
||||||
}
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
#include "../nfc_i.h"
|
|
||||||
#include <dolphin/dolphin.h>
|
|
||||||
|
|
||||||
void nfc_read_mifare_ul_worker_callback(NfcWorkerEvent event, void* context) {
|
|
||||||
UNUSED(event);
|
|
||||||
Nfc* nfc = context;
|
|
||||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit);
|
|
||||||
}
|
|
||||||
|
|
||||||
void nfc_scene_read_mifare_ul_on_enter(void* context) {
|
|
||||||
Nfc* nfc = context;
|
|
||||||
DOLPHIN_DEED(DolphinDeedNfcRead);
|
|
||||||
|
|
||||||
// Setup view
|
|
||||||
Popup* popup = nfc->popup;
|
|
||||||
popup_set_header(popup, "Detecting\nultralight", 70, 34, AlignLeft, AlignTop);
|
|
||||||
popup_set_icon(popup, 0, 3, &I_RFIDDolphinReceive_97x61);
|
|
||||||
|
|
||||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
|
|
||||||
// Start worker
|
|
||||||
nfc_worker_start(
|
|
||||||
nfc->worker,
|
|
||||||
NfcWorkerStateReadMifareUltralight,
|
|
||||||
&nfc->dev->dev_data,
|
|
||||||
nfc_read_mifare_ul_worker_callback,
|
|
||||||
nfc);
|
|
||||||
nfc_blink_start(nfc);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool nfc_scene_read_mifare_ul_on_event(void* context, SceneManagerEvent event) {
|
|
||||||
Nfc* nfc = context;
|
|
||||||
bool consumed = false;
|
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
|
||||||
if(event.event == NfcCustomEventWorkerExit) {
|
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareUlSuccess);
|
|
||||||
consumed = true;
|
|
||||||
}
|
|
||||||
} else if(event.type == SceneManagerEventTypeTick) {
|
|
||||||
consumed = true;
|
|
||||||
}
|
|
||||||
return consumed;
|
|
||||||
}
|
|
||||||
|
|
||||||
void nfc_scene_read_mifare_ul_on_exit(void* context) {
|
|
||||||
Nfc* nfc = context;
|
|
||||||
|
|
||||||
// Stop worker
|
|
||||||
nfc_worker_stop(nfc->worker);
|
|
||||||
// Clear view
|
|
||||||
popup_reset(nfc->popup);
|
|
||||||
|
|
||||||
nfc_blink_stop(nfc);
|
|
||||||
}
|
|
||||||
47
applications/nfc/scenes/nfc_scene_retry_confirm.c
Normal file
47
applications/nfc/scenes/nfc_scene_retry_confirm.c
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
#include "../nfc_i.h"
|
||||||
|
|
||||||
|
void nfc_scene_retry_confirm_dialog_callback(DialogExResult result, void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_retry_confirm_on_enter(void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
DialogEx* dialog_ex = nfc->dialog_ex;
|
||||||
|
|
||||||
|
dialog_ex_set_left_button_text(dialog_ex, "Retry");
|
||||||
|
dialog_ex_set_right_button_text(dialog_ex, "Stay");
|
||||||
|
dialog_ex_set_header(dialog_ex, "Retry reading?", 64, 11, AlignCenter, AlignTop);
|
||||||
|
dialog_ex_set_text(
|
||||||
|
dialog_ex, "All unsaved data will be\nlost.", 64, 25, AlignCenter, AlignTop);
|
||||||
|
dialog_ex_set_context(dialog_ex, nfc);
|
||||||
|
dialog_ex_set_result_callback(dialog_ex, nfc_scene_retry_confirm_dialog_callback);
|
||||||
|
|
||||||
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nfc_scene_retry_confirm_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
|
if(event.event == DialogExResultRight) {
|
||||||
|
consumed = scene_manager_previous_scene(nfc->scene_manager);
|
||||||
|
} else if(event.event == DialogExResultLeft) {
|
||||||
|
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||||
|
nfc->scene_manager, NfcSceneRead);
|
||||||
|
}
|
||||||
|
} else if(event.type == SceneManagerEventTypeBack) {
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_retry_confirm_on_exit(void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
// Clean view
|
||||||
|
dialog_ex_reset(nfc->dialog_ex);
|
||||||
|
}
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
#include "../nfc_i.h"
|
|
||||||
|
|
||||||
void nfc_scene_run_emv_app_confirm_dialog_callback(DialogExResult result, void* context) {
|
|
||||||
Nfc* nfc = context;
|
|
||||||
|
|
||||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
void nfc_scene_run_emv_app_confirm_on_enter(void* context) {
|
|
||||||
Nfc* nfc = context;
|
|
||||||
|
|
||||||
DialogEx* dialog_ex = nfc->dialog_ex;
|
|
||||||
dialog_ex_set_left_button_text(dialog_ex, "Back");
|
|
||||||
dialog_ex_set_right_button_text(dialog_ex, "Run");
|
|
||||||
dialog_ex_set_header(dialog_ex, "Run EMV app?", 64, 8, AlignCenter, AlignCenter);
|
|
||||||
dialog_ex_set_text(
|
|
||||||
dialog_ex,
|
|
||||||
"It will try to run card's app\nand detect unencrypted\ndata",
|
|
||||||
64,
|
|
||||||
18,
|
|
||||||
AlignCenter,
|
|
||||||
AlignTop);
|
|
||||||
dialog_ex_set_context(dialog_ex, nfc);
|
|
||||||
dialog_ex_set_result_callback(dialog_ex, nfc_scene_run_emv_app_confirm_dialog_callback);
|
|
||||||
|
|
||||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool nfc_scene_run_emv_app_confirm_on_event(void* context, SceneManagerEvent event) {
|
|
||||||
Nfc* nfc = context;
|
|
||||||
bool consumed = false;
|
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
|
||||||
if(event.event == DialogExResultLeft) {
|
|
||||||
consumed = scene_manager_previous_scene(nfc->scene_manager);
|
|
||||||
} else if(event.event == DialogExResultRight) {
|
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvData);
|
|
||||||
consumed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return consumed;
|
|
||||||
}
|
|
||||||
|
|
||||||
void nfc_scene_run_emv_app_confirm_on_exit(void* context) {
|
|
||||||
Nfc* nfc = context;
|
|
||||||
|
|
||||||
// Clean view
|
|
||||||
dialog_ex_reset(nfc->dialog_ex);
|
|
||||||
}
|
|
||||||
@@ -27,13 +27,9 @@ bool nfc_scene_save_success_on_event(void* context, SceneManagerEvent event) {
|
|||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
if(event.event == NfcCustomEventViewExit) {
|
if(event.event == NfcCustomEventViewExit) {
|
||||||
if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneCardMenu)) {
|
if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneMfDesfireMenu)) {
|
||||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||||
nfc->scene_manager, NfcSceneCardMenu);
|
nfc->scene_manager, NfcSceneMfDesfireMenu);
|
||||||
} else if(scene_manager_has_previous_scene(
|
|
||||||
nfc->scene_manager, NfcSceneMifareDesfireMenu)) {
|
|
||||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
|
||||||
nfc->scene_manager, NfcSceneMifareDesfireMenu);
|
|
||||||
} else {
|
} else {
|
||||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||||
nfc->scene_manager, NfcSceneStart);
|
nfc->scene_manager, NfcSceneStart);
|
||||||
|
|||||||
@@ -61,9 +61,9 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) {
|
|||||||
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneSavedMenu, event.event);
|
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneSavedMenu, event.event);
|
||||||
if(event.event == SubmenuIndexEmulate) {
|
if(event.event == SubmenuIndexEmulate) {
|
||||||
if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) {
|
if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareUl);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate);
|
||||||
} else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) {
|
} else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareClassic);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate);
|
||||||
} else {
|
} else {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,82 +0,0 @@
|
|||||||
#include "../nfc_i.h"
|
|
||||||
|
|
||||||
enum SubmenuIndex {
|
|
||||||
SubmenuIndexBankCard,
|
|
||||||
SubmenuIndexMifareUltralight,
|
|
||||||
SubmenuIdexReadMfClassic,
|
|
||||||
SubmenuIndexMifareDesfire,
|
|
||||||
};
|
|
||||||
|
|
||||||
void nfc_scene_scripts_menu_submenu_callback(void* context, uint32_t index) {
|
|
||||||
Nfc* nfc = context;
|
|
||||||
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
void nfc_scene_scripts_menu_on_enter(void* context) {
|
|
||||||
Nfc* nfc = context;
|
|
||||||
Submenu* submenu = nfc->submenu;
|
|
||||||
|
|
||||||
submenu_add_item(
|
|
||||||
submenu,
|
|
||||||
"Read Bank Card",
|
|
||||||
SubmenuIndexBankCard,
|
|
||||||
nfc_scene_scripts_menu_submenu_callback,
|
|
||||||
nfc);
|
|
||||||
submenu_add_item(
|
|
||||||
submenu,
|
|
||||||
"Read Mifare Ultral/Ntag",
|
|
||||||
SubmenuIndexMifareUltralight,
|
|
||||||
nfc_scene_scripts_menu_submenu_callback,
|
|
||||||
nfc);
|
|
||||||
submenu_add_item(
|
|
||||||
submenu,
|
|
||||||
"Read Mifare Classic",
|
|
||||||
SubmenuIdexReadMfClassic,
|
|
||||||
nfc_scene_scripts_menu_submenu_callback,
|
|
||||||
nfc);
|
|
||||||
submenu_add_item(
|
|
||||||
submenu,
|
|
||||||
"Read Mifare DESFire",
|
|
||||||
SubmenuIndexMifareDesfire,
|
|
||||||
nfc_scene_scripts_menu_submenu_callback,
|
|
||||||
nfc);
|
|
||||||
submenu_set_selected_item(
|
|
||||||
nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneScriptsMenu));
|
|
||||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool nfc_scene_scripts_menu_on_event(void* context, SceneManagerEvent event) {
|
|
||||||
Nfc* nfc = context;
|
|
||||||
bool consumed = false;
|
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
|
||||||
if(event.event == SubmenuIndexBankCard) {
|
|
||||||
scene_manager_set_scene_state(
|
|
||||||
nfc->scene_manager, NfcSceneScriptsMenu, SubmenuIndexBankCard);
|
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvApp);
|
|
||||||
consumed = true;
|
|
||||||
} else if(event.event == SubmenuIndexMifareUltralight) {
|
|
||||||
scene_manager_set_scene_state(
|
|
||||||
nfc->scene_manager, NfcSceneScriptsMenu, SubmenuIndexMifareUltralight);
|
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareUl);
|
|
||||||
consumed = true;
|
|
||||||
} else if(event.event == SubmenuIdexReadMfClassic) {
|
|
||||||
scene_manager_set_scene_state(
|
|
||||||
nfc->scene_manager, NfcSceneScriptsMenu, SubmenuIdexReadMfClassic);
|
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareClassic);
|
|
||||||
consumed = true;
|
|
||||||
} else if(event.event == SubmenuIndexMifareDesfire) {
|
|
||||||
scene_manager_set_scene_state(
|
|
||||||
nfc->scene_manager, NfcSceneScriptsMenu, SubmenuIndexMifareDesfire);
|
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareDesfire);
|
|
||||||
consumed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return consumed;
|
|
||||||
}
|
|
||||||
|
|
||||||
void nfc_scene_scripts_menu_on_exit(void* context) {
|
|
||||||
Nfc* nfc = context;
|
|
||||||
submenu_reset(nfc->submenu);
|
|
||||||
}
|
|
||||||
@@ -2,8 +2,9 @@
|
|||||||
|
|
||||||
enum SubmenuIndex {
|
enum SubmenuIndex {
|
||||||
SubmenuIndexRead,
|
SubmenuIndexRead,
|
||||||
SubmenuIndexRunScript,
|
SubmenuIndexDetectReader,
|
||||||
SubmenuIndexSaved,
|
SubmenuIndexSaved,
|
||||||
|
SubmenuIndexExtraAction,
|
||||||
SubmenuIndexAddManualy,
|
SubmenuIndexAddManualy,
|
||||||
SubmenuIndexDebug,
|
SubmenuIndexDebug,
|
||||||
};
|
};
|
||||||
@@ -18,15 +19,12 @@ void nfc_scene_start_on_enter(void* context) {
|
|||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
Submenu* submenu = nfc->submenu;
|
Submenu* submenu = nfc->submenu;
|
||||||
|
|
||||||
|
submenu_add_item(submenu, "Read", SubmenuIndexRead, nfc_scene_start_submenu_callback, nfc);
|
||||||
submenu_add_item(
|
submenu_add_item(
|
||||||
submenu, "Read Card", SubmenuIndexRead, nfc_scene_start_submenu_callback, nfc);
|
submenu, "Detect Reader", SubmenuIndexDetectReader, nfc_scene_start_submenu_callback, nfc);
|
||||||
submenu_add_item(
|
|
||||||
submenu,
|
|
||||||
"Run Special Action",
|
|
||||||
SubmenuIndexRunScript,
|
|
||||||
nfc_scene_start_submenu_callback,
|
|
||||||
nfc);
|
|
||||||
submenu_add_item(submenu, "Saved", SubmenuIndexSaved, nfc_scene_start_submenu_callback, nfc);
|
submenu_add_item(submenu, "Saved", SubmenuIndexSaved, nfc_scene_start_submenu_callback, nfc);
|
||||||
|
submenu_add_item(
|
||||||
|
submenu, "Extra Actions", SubmenuIndexExtraAction, nfc_scene_start_submenu_callback, nfc);
|
||||||
submenu_add_item(
|
submenu_add_item(
|
||||||
submenu, "Add Manually", SubmenuIndexAddManualy, nfc_scene_start_submenu_callback, nfc);
|
submenu, "Add Manually", SubmenuIndexAddManualy, nfc_scene_start_submenu_callback, nfc);
|
||||||
|
|
||||||
@@ -48,14 +46,17 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) {
|
|||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
if(event.event == SubmenuIndexRead) {
|
if(event.event == SubmenuIndexRead) {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCard);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneRead);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
} else if(event.event == SubmenuIndexRunScript) {
|
} else if(event.event == SubmenuIndexDetectReader) {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneScriptsMenu);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneDetectReader);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
} else if(event.event == SubmenuIndexSaved) {
|
} else if(event.event == SubmenuIndexSaved) {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneFileSelect);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneFileSelect);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
|
} else if(event.event == SubmenuIndexExtraAction) {
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneExtraActions);
|
||||||
|
consumed = true;
|
||||||
} else if(event.event == SubmenuIndexAddManualy) {
|
} else if(event.event == SubmenuIndexAddManualy) {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneSetType);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneSetType);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
|
|||||||
@@ -1,83 +1,60 @@
|
|||||||
#include "dict_attack.h"
|
#include "dict_attack.h"
|
||||||
#include <m-string.h>
|
|
||||||
|
|
||||||
|
#include <m-string.h>
|
||||||
#include <gui/elements.h>
|
#include <gui/elements.h>
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
DictAttackStateSearchCard,
|
DictAttackStateRead,
|
||||||
DictAttackStateSearchKeys,
|
|
||||||
DictAttackStateCardRemoved,
|
DictAttackStateCardRemoved,
|
||||||
DictAttackStateSuccess,
|
|
||||||
DictAttackStateFail,
|
|
||||||
} DictAttackState;
|
} DictAttackState;
|
||||||
|
|
||||||
struct DictAttack {
|
struct DictAttack {
|
||||||
View* view;
|
View* view;
|
||||||
DictAttackResultCallback callback;
|
DictAttackCallback callback;
|
||||||
void* context;
|
void* context;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
DictAttackState state;
|
DictAttackState state;
|
||||||
MfClassicType type;
|
MfClassicType type;
|
||||||
uint8_t current_sector;
|
string_t header;
|
||||||
uint8_t total_sectors;
|
uint8_t sectors_total;
|
||||||
uint8_t keys_a_found;
|
uint8_t sectors_read;
|
||||||
uint8_t keys_a_total;
|
uint8_t sector_current;
|
||||||
uint8_t keys_b_found;
|
uint8_t keys_total;
|
||||||
uint8_t keys_b_total;
|
uint8_t keys_found;
|
||||||
} DictAttackViewModel;
|
} DictAttackViewModel;
|
||||||
|
|
||||||
static void dict_attack_draw_callback(Canvas* canvas, void* model) {
|
static void dict_attack_draw_callback(Canvas* canvas, void* model) {
|
||||||
DictAttackViewModel* m = model;
|
DictAttackViewModel* m = model;
|
||||||
if(m->state == DictAttackStateSearchCard) {
|
if(m->state == DictAttackStateCardRemoved) {
|
||||||
canvas_set_font(canvas, FontPrimary);
|
canvas_set_font(canvas, FontPrimary);
|
||||||
canvas_draw_str_aligned(
|
canvas_draw_str_aligned(canvas, 64, 4, AlignCenter, AlignTop, "Lost the tag!");
|
||||||
canvas, 64, 32, AlignCenter, AlignCenter, "Detecting Mifare Classic");
|
|
||||||
} else if(m->state == DictAttackStateCardRemoved) {
|
|
||||||
canvas_set_font(canvas, FontPrimary);
|
|
||||||
canvas_draw_str_aligned(
|
|
||||||
canvas, 64, 32, AlignCenter, AlignTop, "Place card back to flipper");
|
|
||||||
} else {
|
|
||||||
char draw_str[32];
|
|
||||||
if(m->state == DictAttackStateSearchKeys) {
|
|
||||||
snprintf(
|
|
||||||
draw_str, sizeof(draw_str), "Searching keys for sector %d", m->current_sector);
|
|
||||||
canvas_draw_str_aligned(canvas, 64, 2, AlignCenter, AlignTop, draw_str);
|
|
||||||
} else if(m->state == DictAttackStateSuccess) {
|
|
||||||
canvas_draw_str_aligned(canvas, 64, 2, AlignCenter, AlignTop, "Complete!");
|
|
||||||
elements_button_right(canvas, "More");
|
|
||||||
} else if(m->state == DictAttackStateFail) {
|
|
||||||
canvas_draw_str_aligned(
|
|
||||||
canvas, 64, 2, AlignCenter, AlignTop, "Failed to read any sector");
|
|
||||||
}
|
|
||||||
uint16_t keys_found = m->keys_a_found + m->keys_b_found;
|
|
||||||
uint16_t keys_total = m->keys_a_total + m->keys_b_total;
|
|
||||||
float progress = (float)(m->current_sector) / (float)(m->total_sectors);
|
|
||||||
elements_progress_bar(canvas, 5, 12, 120, progress);
|
|
||||||
canvas_set_font(canvas, FontSecondary);
|
canvas_set_font(canvas, FontSecondary);
|
||||||
snprintf(draw_str, sizeof(draw_str), "Total keys found: %d/%d", keys_found, keys_total);
|
elements_multiline_text_aligned(
|
||||||
canvas_draw_str_aligned(canvas, 1, 23, AlignLeft, AlignTop, draw_str);
|
canvas, 64, 23, AlignCenter, AlignTop, "Make sure the tag is\npositioned correctly.");
|
||||||
|
} else if(m->state == DictAttackStateRead) {
|
||||||
|
char draw_str[32] = {};
|
||||||
|
canvas_set_font(canvas, FontPrimary);
|
||||||
|
canvas_draw_str_aligned(canvas, 64, 2, AlignCenter, AlignTop, string_get_cstr(m->header));
|
||||||
|
canvas_set_font(canvas, FontSecondary);
|
||||||
|
float progress =
|
||||||
|
m->sectors_total == 0 ? 0 : (float)(m->sector_current) / (float)(m->sectors_total);
|
||||||
|
elements_progress_bar(canvas, 5, 15, 120, progress);
|
||||||
|
canvas_set_font(canvas, FontSecondary);
|
||||||
|
snprintf(draw_str, sizeof(draw_str), "Keys found: %d/%d", m->keys_found, m->keys_total);
|
||||||
|
canvas_draw_str_aligned(canvas, 1, 28, AlignLeft, AlignTop, draw_str);
|
||||||
snprintf(
|
snprintf(
|
||||||
draw_str, sizeof(draw_str), "A keys found: %d/%d", m->keys_a_found, m->keys_a_total);
|
draw_str, sizeof(draw_str), "Sectors Read: %d/%d", m->sectors_read, m->sectors_total);
|
||||||
canvas_draw_str_aligned(canvas, 1, 34, AlignLeft, AlignTop, draw_str);
|
canvas_draw_str_aligned(canvas, 1, 40, AlignLeft, AlignTop, draw_str);
|
||||||
snprintf(
|
|
||||||
draw_str, sizeof(draw_str), "B keys found: %d/%d", m->keys_b_found, m->keys_b_total);
|
|
||||||
canvas_draw_str_aligned(canvas, 1, 45, AlignLeft, AlignTop, draw_str);
|
|
||||||
}
|
}
|
||||||
|
elements_button_center(canvas, "Skip");
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool dict_attack_input_callback(InputEvent* event, void* context) {
|
static bool dict_attack_input_callback(InputEvent* event, void* context) {
|
||||||
DictAttack* dict_attack = context;
|
DictAttack* dict_attack = context;
|
||||||
bool consumed = false;
|
bool consumed = false;
|
||||||
DictAttackState state;
|
if(event->type == InputTypeShort && event->key == InputKeyOk) {
|
||||||
with_view_model(
|
|
||||||
dict_attack->view, (DictAttackViewModel * model) {
|
|
||||||
state = model->state;
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
if(state == DictAttackStateSuccess && event->type == InputTypeShort &&
|
|
||||||
event->key == InputKeyRight) {
|
|
||||||
if(dict_attack->callback) {
|
if(dict_attack->callback) {
|
||||||
dict_attack->callback(dict_attack->context);
|
dict_attack->callback(dict_attack->context);
|
||||||
}
|
}
|
||||||
@@ -93,11 +70,21 @@ DictAttack* dict_attack_alloc() {
|
|||||||
view_set_draw_callback(dict_attack->view, dict_attack_draw_callback);
|
view_set_draw_callback(dict_attack->view, dict_attack_draw_callback);
|
||||||
view_set_input_callback(dict_attack->view, dict_attack_input_callback);
|
view_set_input_callback(dict_attack->view, dict_attack_input_callback);
|
||||||
view_set_context(dict_attack->view, dict_attack);
|
view_set_context(dict_attack->view, dict_attack);
|
||||||
|
with_view_model(
|
||||||
|
dict_attack->view, (DictAttackViewModel * model) {
|
||||||
|
string_init(model->header);
|
||||||
|
return false;
|
||||||
|
});
|
||||||
return dict_attack;
|
return dict_attack;
|
||||||
}
|
}
|
||||||
|
|
||||||
void dict_attack_free(DictAttack* dict_attack) {
|
void dict_attack_free(DictAttack* dict_attack) {
|
||||||
furi_assert(dict_attack);
|
furi_assert(dict_attack);
|
||||||
|
with_view_model(
|
||||||
|
dict_attack->view, (DictAttackViewModel * model) {
|
||||||
|
string_clear(model->header);
|
||||||
|
return false;
|
||||||
|
});
|
||||||
view_free(dict_attack->view);
|
view_free(dict_attack->view);
|
||||||
free(dict_attack);
|
free(dict_attack);
|
||||||
}
|
}
|
||||||
@@ -106,8 +93,15 @@ void dict_attack_reset(DictAttack* dict_attack) {
|
|||||||
furi_assert(dict_attack);
|
furi_assert(dict_attack);
|
||||||
with_view_model(
|
with_view_model(
|
||||||
dict_attack->view, (DictAttackViewModel * model) {
|
dict_attack->view, (DictAttackViewModel * model) {
|
||||||
memset(model, 0, sizeof(DictAttackViewModel));
|
model->state = DictAttackStateRead;
|
||||||
return true;
|
model->type = MfClassicType1k;
|
||||||
|
model->sectors_total = 0;
|
||||||
|
model->sectors_read = 0;
|
||||||
|
model->sector_current = 0;
|
||||||
|
model->keys_total = 0;
|
||||||
|
model->keys_found = 0;
|
||||||
|
string_reset(model->header);
|
||||||
|
return false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,78 +110,88 @@ View* dict_attack_get_view(DictAttack* dict_attack) {
|
|||||||
return dict_attack->view;
|
return dict_attack->view;
|
||||||
}
|
}
|
||||||
|
|
||||||
void dict_attack_set_result_callback(
|
void dict_attack_set_callback(DictAttack* dict_attack, DictAttackCallback callback, void* context) {
|
||||||
DictAttack* dict_attack,
|
|
||||||
DictAttackResultCallback callback,
|
|
||||||
void* context) {
|
|
||||||
furi_assert(dict_attack);
|
furi_assert(dict_attack);
|
||||||
furi_assert(callback);
|
furi_assert(callback);
|
||||||
dict_attack->callback = callback;
|
dict_attack->callback = callback;
|
||||||
dict_attack->context = context;
|
dict_attack->context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
void dict_attack_card_detected(DictAttack* dict_attack, MfClassicType type) {
|
void dict_attack_set_header(DictAttack* dict_attack, const char* header) {
|
||||||
furi_assert(dict_attack);
|
furi_assert(dict_attack);
|
||||||
|
furi_assert(header);
|
||||||
|
|
||||||
with_view_model(
|
with_view_model(
|
||||||
dict_attack->view, (DictAttackViewModel * model) {
|
dict_attack->view, (DictAttackViewModel * model) {
|
||||||
model->state = DictAttackStateSearchKeys;
|
string_set_str(model->header, header);
|
||||||
if(type == MfClassicType1k) {
|
|
||||||
model->total_sectors = 16;
|
|
||||||
model->keys_a_total = 16;
|
|
||||||
model->keys_b_total = 16;
|
|
||||||
} else if(type == MfClassicType4k) {
|
|
||||||
model->total_sectors = 40;
|
|
||||||
model->keys_a_total = 40;
|
|
||||||
model->keys_b_total = 40;
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void dict_attack_card_removed(DictAttack* dict_attack) {
|
void dict_attack_set_card_detected(DictAttack* dict_attack, MfClassicType type) {
|
||||||
|
furi_assert(dict_attack);
|
||||||
|
with_view_model(
|
||||||
|
dict_attack->view, (DictAttackViewModel * model) {
|
||||||
|
model->state = DictAttackStateRead;
|
||||||
|
model->sectors_total = mf_classic_get_total_sectors_num(type);
|
||||||
|
model->keys_total = model->sectors_total * 2;
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void dict_attack_set_card_removed(DictAttack* dict_attack) {
|
||||||
furi_assert(dict_attack);
|
furi_assert(dict_attack);
|
||||||
with_view_model(
|
with_view_model(
|
||||||
dict_attack->view, (DictAttackViewModel * model) {
|
dict_attack->view, (DictAttackViewModel * model) {
|
||||||
if(model->state == DictAttackStateSearchKeys) {
|
|
||||||
model->state = DictAttackStateCardRemoved;
|
model->state = DictAttackStateCardRemoved;
|
||||||
} else {
|
return true;
|
||||||
model->state = DictAttackStateSearchCard;
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void dict_attack_set_sector_read(DictAttack* dict_attack, uint8_t sec_read) {
|
||||||
|
furi_assert(dict_attack);
|
||||||
|
with_view_model(
|
||||||
|
dict_attack->view, (DictAttackViewModel * model) {
|
||||||
|
model->sectors_read = sec_read;
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void dict_attack_set_keys_found(DictAttack* dict_attack, uint8_t keys_found) {
|
||||||
|
furi_assert(dict_attack);
|
||||||
|
with_view_model(
|
||||||
|
dict_attack->view, (DictAttackViewModel * model) {
|
||||||
|
model->keys_found = keys_found;
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void dict_attack_set_current_sector(DictAttack* dict_attack, uint8_t curr_sec) {
|
||||||
|
furi_assert(dict_attack);
|
||||||
|
with_view_model(
|
||||||
|
dict_attack->view, (DictAttackViewModel * model) {
|
||||||
|
model->sector_current = curr_sec;
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void dict_attack_inc_current_sector(DictAttack* dict_attack) {
|
||||||
|
furi_assert(dict_attack);
|
||||||
|
with_view_model(
|
||||||
|
dict_attack->view, (DictAttackViewModel * model) {
|
||||||
|
if(model->sector_current < model->sectors_total) {
|
||||||
|
model->sector_current++;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void dict_attack_inc_curr_sector(DictAttack* dict_attack) {
|
void dict_attack_inc_keys_found(DictAttack* dict_attack) {
|
||||||
furi_assert(dict_attack);
|
furi_assert(dict_attack);
|
||||||
with_view_model(
|
with_view_model(
|
||||||
dict_attack->view, (DictAttackViewModel * model) {
|
dict_attack->view, (DictAttackViewModel * model) {
|
||||||
model->current_sector++;
|
if(model->keys_found < model->keys_total) {
|
||||||
return true;
|
model->keys_found++;
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void dict_attack_inc_found_key(DictAttack* dict_attack, MfClassicKey key) {
|
|
||||||
furi_assert(dict_attack);
|
|
||||||
with_view_model(
|
|
||||||
dict_attack->view, (DictAttackViewModel * model) {
|
|
||||||
model->state = DictAttackStateSearchKeys;
|
|
||||||
if(key == MfClassicKeyA) {
|
|
||||||
model->keys_a_found++;
|
|
||||||
} else if(key == MfClassicKeyB) {
|
|
||||||
model->keys_b_found++;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void dict_attack_set_result(DictAttack* dict_attack, bool success) {
|
|
||||||
furi_assert(dict_attack);
|
|
||||||
with_view_model(
|
|
||||||
dict_attack->view, (DictAttackViewModel * model) {
|
|
||||||
if(success) {
|
|
||||||
model->state = DictAttackStateSuccess;
|
|
||||||
} else {
|
|
||||||
model->state = DictAttackStateFail;
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3,11 +3,11 @@
|
|||||||
#include <gui/view.h>
|
#include <gui/view.h>
|
||||||
#include <gui/modules/widget.h>
|
#include <gui/modules/widget.h>
|
||||||
|
|
||||||
#include <lib/nfc_protocols/mifare_classic.h>
|
#include <lib/nfc/protocols/mifare_classic.h>
|
||||||
|
|
||||||
typedef struct DictAttack DictAttack;
|
typedef struct DictAttack DictAttack;
|
||||||
|
|
||||||
typedef void (*DictAttackResultCallback)(void* context);
|
typedef void (*DictAttackCallback)(void* context);
|
||||||
|
|
||||||
DictAttack* dict_attack_alloc();
|
DictAttack* dict_attack_alloc();
|
||||||
|
|
||||||
@@ -17,17 +17,20 @@ void dict_attack_reset(DictAttack* dict_attack);
|
|||||||
|
|
||||||
View* dict_attack_get_view(DictAttack* dict_attack);
|
View* dict_attack_get_view(DictAttack* dict_attack);
|
||||||
|
|
||||||
void dict_attack_set_result_callback(
|
void dict_attack_set_callback(DictAttack* dict_attack, DictAttackCallback callback, void* context);
|
||||||
DictAttack* dict_attack,
|
|
||||||
DictAttackResultCallback callback,
|
|
||||||
void* context);
|
|
||||||
|
|
||||||
void dict_attack_card_detected(DictAttack* dict_attack, MfClassicType type);
|
void dict_attack_set_header(DictAttack* dict_attack, const char* header);
|
||||||
|
|
||||||
void dict_attack_card_removed(DictAttack* dict_attack);
|
void dict_attack_set_card_detected(DictAttack* dict_attack, MfClassicType type);
|
||||||
|
|
||||||
void dict_attack_inc_curr_sector(DictAttack* dict_attack);
|
void dict_attack_set_card_removed(DictAttack* dict_attack);
|
||||||
|
|
||||||
void dict_attack_inc_found_key(DictAttack* dict_attack, MfClassicKey key);
|
void dict_attack_set_sector_read(DictAttack* dict_attack, uint8_t sec_read);
|
||||||
|
|
||||||
void dict_attack_set_result(DictAttack* dict_attack, bool success);
|
void dict_attack_set_keys_found(DictAttack* dict_attack, uint8_t keys_found);
|
||||||
|
|
||||||
|
void dict_attack_set_current_sector(DictAttack* dict_attack, uint8_t curr_sec);
|
||||||
|
|
||||||
|
void dict_attack_inc_current_sector(DictAttack* dict_attack);
|
||||||
|
|
||||||
|
void dict_attack_inc_keys_found(DictAttack* dict_attack);
|
||||||
|
|||||||
@@ -187,7 +187,8 @@ static void spectrum_analyzer_worker_callback(
|
|||||||
uint8_t max_rssi_channel,
|
uint8_t max_rssi_channel,
|
||||||
void* context) {
|
void* context) {
|
||||||
SpectrumAnalyzer* spectrum_analyzer = context;
|
SpectrumAnalyzer* spectrum_analyzer = context;
|
||||||
furi_check(furi_mutex_acquire(spectrum_analyzer->model_mutex, FuriWaitForever) == FuriStatusOk);
|
furi_check(
|
||||||
|
furi_mutex_acquire(spectrum_analyzer->model_mutex, FuriWaitForever) == FuriStatusOk);
|
||||||
|
|
||||||
SpectrumAnalyzerModel* model = (SpectrumAnalyzerModel*)spectrum_analyzer->model;
|
SpectrumAnalyzerModel* model = (SpectrumAnalyzerModel*)spectrum_analyzer->model;
|
||||||
memcpy(model->channel_ss, (uint8_t*)channel_ss, sizeof(uint8_t) * NUM_CHANNELS);
|
memcpy(model->channel_ss, (uint8_t*)channel_ss, sizeof(uint8_t) * NUM_CHANNELS);
|
||||||
@@ -407,8 +408,10 @@ int32_t spectrum_analyzer_app(void* p) {
|
|||||||
FURI_LOG_D("Spectrum", "Main Loop - Wait on queue");
|
FURI_LOG_D("Spectrum", "Main Loop - Wait on queue");
|
||||||
furi_delay_ms(50);
|
furi_delay_ms(50);
|
||||||
|
|
||||||
while(furi_message_queue_get(spectrum_analyzer->event_queue, &input, FuriWaitForever) == FuriStatusOk) {
|
while(furi_message_queue_get(spectrum_analyzer->event_queue, &input, FuriWaitForever) ==
|
||||||
furi_check(furi_mutex_acquire(spectrum_analyzer->model_mutex, FuriWaitForever) == FuriStatusOk);
|
FuriStatusOk) {
|
||||||
|
furi_check(
|
||||||
|
furi_mutex_acquire(spectrum_analyzer->model_mutex, FuriWaitForever) == FuriStatusOk);
|
||||||
|
|
||||||
FURI_LOG_D("Spectrum", "Main Loop - Input: %u", input.key);
|
FURI_LOG_D("Spectrum", "Main Loop - Input: %u", input.key);
|
||||||
|
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ void spectrum_analyzer_worker_set_filter(SpectrumAnalyzerWorker* instance) {
|
|||||||
filter_config[0][1] = 0x6C; /* 196 kHz / .8 = 245 kHz --> 270 kHz */
|
filter_config[0][1] = 0x6C; /* 196 kHz / .8 = 245 kHz --> 270 kHz */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
furi_hal_subghz_load_registers(filter_config);
|
furi_hal_subghz_load_registers((uint8_t*)filter_config);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t spectrum_analyzer_worker_thread(void* context) {
|
static int32_t spectrum_analyzer_worker_thread(void* context) {
|
||||||
@@ -79,7 +79,7 @@ static int32_t spectrum_analyzer_worker_thread(void* context) {
|
|||||||
|
|
||||||
// FURI_LOG_T("SpectrumWorker", "spectrum_analyzer_worker_thread: Worker Loop");
|
// FURI_LOG_T("SpectrumWorker", "spectrum_analyzer_worker_thread: Worker Loop");
|
||||||
furi_hal_subghz_idle();
|
furi_hal_subghz_idle();
|
||||||
furi_hal_subghz_load_registers(radio_config);
|
furi_hal_subghz_load_registers((uint8_t*)radio_config);
|
||||||
|
|
||||||
// TODO: Check filter!
|
// TODO: Check filter!
|
||||||
// spectrum_analyzer_worker_set_filter(instance);
|
// spectrum_analyzer_worker_set_filter(instance);
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "m-string.h"
|
||||||
|
#include <furi.h>
|
||||||
|
#include <furi_hal.h>
|
||||||
|
|
||||||
/** SubGhzNotification state */
|
/** SubGhzNotification state */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SubGhzNotificationStateStarting,
|
SubGhzNotificationStateStarting,
|
||||||
@@ -68,3 +72,12 @@ typedef enum {
|
|||||||
SubGhzViewIdTestCarrier,
|
SubGhzViewIdTestCarrier,
|
||||||
SubGhzViewIdTestPacket,
|
SubGhzViewIdTestPacket,
|
||||||
} SubGhzViewId;
|
} SubGhzViewId;
|
||||||
|
|
||||||
|
struct SubGhzPesetDefinition {
|
||||||
|
string_t name;
|
||||||
|
uint32_t frequency;
|
||||||
|
uint8_t* data;
|
||||||
|
size_t data_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct SubGhzPesetDefinition SubGhzPesetDefinition;
|
||||||
|
|||||||
@@ -48,8 +48,12 @@ bool subghz_scene_need_saving_on_event(void* context, SceneManagerEvent event) {
|
|||||||
} else if(event.event == SubGhzCustomEventSceneExit) {
|
} else if(event.event == SubGhzCustomEventSceneExit) {
|
||||||
if(subghz->txrx->rx_key_state == SubGhzRxKeyStateExit) {
|
if(subghz->txrx->rx_key_state == SubGhzRxKeyStateExit) {
|
||||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
|
subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
|
||||||
subghz->txrx->frequency = subghz_setting_get_default_frequency(subghz->setting);
|
subghz_preset_init(
|
||||||
subghz->txrx->preset = FuriHalSubGhzPresetOok650Async;
|
subghz,
|
||||||
|
"AM650",
|
||||||
|
subghz_setting_get_default_frequency(subghz->setting),
|
||||||
|
NULL,
|
||||||
|
0);
|
||||||
scene_manager_search_and_switch_to_previous_scene(
|
scene_manager_search_and_switch_to_previous_scene(
|
||||||
subghz->scene_manager, SubGhzSceneStart);
|
subghz->scene_manager, SubGhzSceneStart);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -131,8 +131,12 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
|
|||||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving);
|
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving);
|
||||||
} else {
|
} else {
|
||||||
//Restore default setting
|
//Restore default setting
|
||||||
subghz->txrx->frequency = subghz_setting_get_default_frequency(subghz->setting);
|
subghz_preset_init(
|
||||||
subghz->txrx->preset = FuriHalSubGhzPresetOok650Async;
|
subghz,
|
||||||
|
"AM650",
|
||||||
|
subghz_setting_get_default_frequency(subghz->setting),
|
||||||
|
NULL,
|
||||||
|
0);
|
||||||
if(!scene_manager_search_and_switch_to_previous_scene(
|
if(!scene_manager_search_and_switch_to_previous_scene(
|
||||||
subghz->scene_manager, SubGhzSceneSaved)) {
|
subghz->scene_manager, SubGhzSceneSaved)) {
|
||||||
if(!scene_manager_search_and_switch_to_previous_scene(
|
if(!scene_manager_search_and_switch_to_previous_scene(
|
||||||
@@ -202,6 +206,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
|
|||||||
if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) ||
|
if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) ||
|
||||||
(subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) {
|
(subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) {
|
||||||
if(!subghz_tx_start(subghz, subghz->txrx->fff_data)) {
|
if(!subghz_tx_start(subghz, subghz->txrx->fff_data)) {
|
||||||
|
subghz->txrx->rx_key_state = SubGhzRxKeyStateBack;
|
||||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx);
|
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx);
|
||||||
} else {
|
} else {
|
||||||
DOLPHIN_DEED(DolphinDeedSubGhzSend);
|
DOLPHIN_DEED(DolphinDeedSubGhzSend);
|
||||||
@@ -267,13 +272,15 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
|
|||||||
if(subghz_protocol_raw_save_to_file_init(
|
if(subghz_protocol_raw_save_to_file_init(
|
||||||
(SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result,
|
(SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result,
|
||||||
RAW_FILE_NAME,
|
RAW_FILE_NAME,
|
||||||
subghz->txrx->frequency,
|
|
||||||
subghz->txrx->preset)) {
|
subghz->txrx->preset)) {
|
||||||
DOLPHIN_DEED(DolphinDeedSubGhzRawRec);
|
DOLPHIN_DEED(DolphinDeedSubGhzRawRec);
|
||||||
if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) ||
|
if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) ||
|
||||||
(subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) {
|
(subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) {
|
||||||
subghz_begin(subghz, subghz->txrx->preset);
|
subghz_begin(
|
||||||
subghz_rx(subghz, subghz->txrx->frequency);
|
subghz,
|
||||||
|
subghz_setting_get_preset_data_by_name(
|
||||||
|
subghz->setting, string_get_cstr(subghz->txrx->preset->name)));
|
||||||
|
subghz_rx(subghz, subghz->txrx->preset->frequency);
|
||||||
}
|
}
|
||||||
subghz->state_notifications = SubGhzNotificationStateRx;
|
subghz->state_notifications = SubGhzNotificationStateRx;
|
||||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey;
|
subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey;
|
||||||
|
|||||||
@@ -75,8 +75,7 @@ static void subghz_scene_add_to_history_callback(
|
|||||||
string_t str_buff;
|
string_t str_buff;
|
||||||
string_init(str_buff);
|
string_init(str_buff);
|
||||||
|
|
||||||
if(subghz_history_add_to_history(
|
if(subghz_history_add_to_history(subghz->txrx->history, decoder_base, subghz->txrx->preset)) {
|
||||||
subghz->txrx->history, decoder_base, subghz->txrx->frequency, subghz->txrx->preset)) {
|
|
||||||
string_reset(str_buff);
|
string_reset(str_buff);
|
||||||
|
|
||||||
subghz->state_notifications = SubGhzNotificationStateRxDone;
|
subghz->state_notifications = SubGhzNotificationStateRxDone;
|
||||||
@@ -103,8 +102,8 @@ void subghz_scene_receiver_on_enter(void* context) {
|
|||||||
string_init(str_buff);
|
string_init(str_buff);
|
||||||
|
|
||||||
if(subghz->txrx->rx_key_state == SubGhzRxKeyStateIDLE) {
|
if(subghz->txrx->rx_key_state == SubGhzRxKeyStateIDLE) {
|
||||||
subghz->txrx->frequency = subghz_setting_get_default_frequency(subghz->setting);
|
subghz_preset_init(
|
||||||
subghz->txrx->preset = FuriHalSubGhzPresetOok650Async;
|
subghz, "AM650", subghz_setting_get_default_frequency(subghz->setting), NULL, 0);
|
||||||
subghz_history_reset(subghz->txrx->history);
|
subghz_history_reset(subghz->txrx->history);
|
||||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateStart;
|
subghz->txrx->rx_key_state = SubGhzRxKeyStateStart;
|
||||||
}
|
}
|
||||||
@@ -135,8 +134,11 @@ void subghz_scene_receiver_on_enter(void* context) {
|
|||||||
};
|
};
|
||||||
if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) ||
|
if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) ||
|
||||||
(subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) {
|
(subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) {
|
||||||
subghz_begin(subghz, subghz->txrx->preset);
|
subghz_begin(
|
||||||
subghz_rx(subghz, subghz->txrx->frequency);
|
subghz,
|
||||||
|
subghz_setting_get_preset_data_by_name(
|
||||||
|
subghz->setting, string_get_cstr(subghz->txrx->preset->name)));
|
||||||
|
subghz_rx(subghz, subghz->txrx->preset->frequency);
|
||||||
}
|
}
|
||||||
subghz_view_receiver_set_idx_menu(subghz->subghz_receiver, subghz->txrx->idx_menu_chosen);
|
subghz_view_receiver_set_idx_menu(subghz->subghz_receiver, subghz->txrx->idx_menu_chosen);
|
||||||
|
|
||||||
@@ -164,8 +166,12 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) {
|
|||||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving);
|
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving);
|
||||||
} else {
|
} else {
|
||||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
|
subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
|
||||||
subghz->txrx->frequency = subghz_setting_get_default_frequency(subghz->setting);
|
subghz_preset_init(
|
||||||
subghz->txrx->preset = FuriHalSubGhzPresetOok650Async;
|
subghz,
|
||||||
|
"AM650",
|
||||||
|
subghz_setting_get_default_frequency(subghz->setting),
|
||||||
|
NULL,
|
||||||
|
0);
|
||||||
scene_manager_search_and_switch_to_previous_scene(
|
scene_manager_search_and_switch_to_previous_scene(
|
||||||
subghz->scene_manager, SubGhzSceneStart);
|
subghz->scene_manager, SubGhzSceneStart);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,20 +7,6 @@ enum SubGhzSettingIndex {
|
|||||||
SubGhzSettingIndexLock,
|
SubGhzSettingIndexLock,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define PRESET_COUNT 4
|
|
||||||
const char* const preset_text[PRESET_COUNT] = {
|
|
||||||
"AM270",
|
|
||||||
"AM650",
|
|
||||||
"FM238",
|
|
||||||
"FM476",
|
|
||||||
};
|
|
||||||
const uint32_t preset_value[PRESET_COUNT] = {
|
|
||||||
FuriHalSubGhzPresetOok270Async, /** OOK, bandwidth 270kHz, asynchronous */
|
|
||||||
FuriHalSubGhzPresetOok650Async, /** OOK, bandwidth 650kHz, asynchronous */
|
|
||||||
FuriHalSubGhzPreset2FSKDev238Async, /** FM, deviation 2.380371 kHz, asynchronous */
|
|
||||||
FuriHalSubGhzPreset2FSKDev476Async, /** FM, deviation 4.760742 kHz, asynchronous */
|
|
||||||
};
|
|
||||||
|
|
||||||
#define HOPPING_COUNT 2
|
#define HOPPING_COUNT 2
|
||||||
const char* const hopping_text[HOPPING_COUNT] = {
|
const char* const hopping_text[HOPPING_COUNT] = {
|
||||||
"OFF",
|
"OFF",
|
||||||
@@ -31,22 +17,6 @@ const uint32_t hopping_value[HOPPING_COUNT] = {
|
|||||||
SubGhzHopperStateRunnig,
|
SubGhzHopperStateRunnig,
|
||||||
};
|
};
|
||||||
|
|
||||||
uint8_t subghz_scene_receiver_config_uint32_value_index(
|
|
||||||
const uint32_t value,
|
|
||||||
const uint32_t values[],
|
|
||||||
uint8_t values_count) {
|
|
||||||
int64_t last_value = INT64_MIN;
|
|
||||||
uint8_t index = 0;
|
|
||||||
for(uint8_t i = 0; i < values_count; i++) {
|
|
||||||
if((value >= last_value) && (value <= values[i])) {
|
|
||||||
index = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
last_value = values[i];
|
|
||||||
}
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t subghz_scene_receiver_config_next_frequency(const uint32_t value, void* context) {
|
uint8_t subghz_scene_receiver_config_next_frequency(const uint32_t value, void* context) {
|
||||||
furi_assert(context);
|
furi_assert(context);
|
||||||
SubGhz* subghz = context;
|
SubGhz* subghz = context;
|
||||||
@@ -62,6 +32,21 @@ uint8_t subghz_scene_receiver_config_next_frequency(const uint32_t value, void*
|
|||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t subghz_scene_receiver_config_next_preset(const char* preset_name, void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
SubGhz* subghz = context;
|
||||||
|
uint8_t index = 0;
|
||||||
|
for(uint8_t i = 0; i < subghz_setting_get_preset_count(subghz->setting); i++) {
|
||||||
|
if(!strcmp(subghz_setting_get_preset_name(subghz->setting, i), preset_name)) {
|
||||||
|
index = i;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
// index = subghz_setting_get_frequency_default_index(subghz->setting);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t subghz_scene_receiver_config_hopper_value_index(
|
uint8_t subghz_scene_receiver_config_hopper_value_index(
|
||||||
const uint32_t value,
|
const uint32_t value,
|
||||||
const uint32_t values[],
|
const uint32_t values[],
|
||||||
@@ -94,7 +79,7 @@ static void subghz_scene_receiver_config_set_frequency(VariableItem* item) {
|
|||||||
subghz_setting_get_frequency(subghz->setting, index) / 1000000,
|
subghz_setting_get_frequency(subghz->setting, index) / 1000000,
|
||||||
(subghz_setting_get_frequency(subghz->setting, index) % 1000000) / 10000);
|
(subghz_setting_get_frequency(subghz->setting, index) % 1000000) / 10000);
|
||||||
variable_item_set_current_value_text(item, text_buf);
|
variable_item_set_current_value_text(item, text_buf);
|
||||||
subghz->txrx->frequency = subghz_setting_get_frequency(subghz->setting, index);
|
subghz->txrx->preset->frequency = subghz_setting_get_frequency(subghz->setting, index);
|
||||||
} else {
|
} else {
|
||||||
variable_item_set_current_value_index(
|
variable_item_set_current_value_index(
|
||||||
item, subghz_setting_get_frequency_default_index(subghz->setting));
|
item, subghz_setting_get_frequency_default_index(subghz->setting));
|
||||||
@@ -104,9 +89,14 @@ static void subghz_scene_receiver_config_set_frequency(VariableItem* item) {
|
|||||||
static void subghz_scene_receiver_config_set_preset(VariableItem* item) {
|
static void subghz_scene_receiver_config_set_preset(VariableItem* item) {
|
||||||
SubGhz* subghz = variable_item_get_context(item);
|
SubGhz* subghz = variable_item_get_context(item);
|
||||||
uint8_t index = variable_item_get_current_value_index(item);
|
uint8_t index = variable_item_get_current_value_index(item);
|
||||||
|
variable_item_set_current_value_text(
|
||||||
variable_item_set_current_value_text(item, preset_text[index]);
|
item, subghz_setting_get_preset_name(subghz->setting, index));
|
||||||
subghz->txrx->preset = preset_value[index];
|
subghz_preset_init(
|
||||||
|
subghz,
|
||||||
|
subghz_setting_get_preset_name(subghz->setting, index),
|
||||||
|
subghz->txrx->preset->frequency,
|
||||||
|
subghz_setting_get_preset_data(subghz->setting, index),
|
||||||
|
subghz_setting_get_preset_data_size(subghz->setting, index));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void subghz_scene_receiver_config_set_hopping_runing(VariableItem* item) {
|
static void subghz_scene_receiver_config_set_hopping_runing(VariableItem* item) {
|
||||||
@@ -125,7 +115,7 @@ static void subghz_scene_receiver_config_set_hopping_runing(VariableItem* item)
|
|||||||
(VariableItem*)scene_manager_get_scene_state(
|
(VariableItem*)scene_manager_get_scene_state(
|
||||||
subghz->scene_manager, SubGhzSceneReceiverConfig),
|
subghz->scene_manager, SubGhzSceneReceiverConfig),
|
||||||
text_buf);
|
text_buf);
|
||||||
subghz->txrx->frequency = subghz_setting_get_default_frequency(subghz->setting);
|
subghz->txrx->preset->frequency = subghz_setting_get_default_frequency(subghz->setting);
|
||||||
variable_item_set_current_value_index(
|
variable_item_set_current_value_index(
|
||||||
(VariableItem*)scene_manager_get_scene_state(
|
(VariableItem*)scene_manager_get_scene_state(
|
||||||
subghz->scene_manager, SubGhzSceneReceiverConfig),
|
subghz->scene_manager, SubGhzSceneReceiverConfig),
|
||||||
@@ -164,7 +154,8 @@ void subghz_scene_receiver_config_on_enter(void* context) {
|
|||||||
subghz_setting_get_frequency_count(subghz->setting),
|
subghz_setting_get_frequency_count(subghz->setting),
|
||||||
subghz_scene_receiver_config_set_frequency,
|
subghz_scene_receiver_config_set_frequency,
|
||||||
subghz);
|
subghz);
|
||||||
value_index = subghz_scene_receiver_config_next_frequency(subghz->txrx->frequency, subghz);
|
value_index =
|
||||||
|
subghz_scene_receiver_config_next_frequency(subghz->txrx->preset->frequency, subghz);
|
||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
subghz->scene_manager, SubGhzSceneReceiverConfig, (uint32_t)item);
|
subghz->scene_manager, SubGhzSceneReceiverConfig, (uint32_t)item);
|
||||||
variable_item_set_current_value_index(item, value_index);
|
variable_item_set_current_value_index(item, value_index);
|
||||||
@@ -193,13 +184,14 @@ void subghz_scene_receiver_config_on_enter(void* context) {
|
|||||||
item = variable_item_list_add(
|
item = variable_item_list_add(
|
||||||
subghz->variable_item_list,
|
subghz->variable_item_list,
|
||||||
"Modulation:",
|
"Modulation:",
|
||||||
PRESET_COUNT,
|
subghz_setting_get_preset_count(subghz->setting),
|
||||||
subghz_scene_receiver_config_set_preset,
|
subghz_scene_receiver_config_set_preset,
|
||||||
subghz);
|
subghz);
|
||||||
value_index = subghz_scene_receiver_config_uint32_value_index(
|
value_index = subghz_scene_receiver_config_next_preset(
|
||||||
subghz->txrx->preset, preset_value, PRESET_COUNT);
|
string_get_cstr(subghz->txrx->preset->name), subghz);
|
||||||
variable_item_set_current_value_index(item, value_index);
|
variable_item_set_current_value_index(item, value_index);
|
||||||
variable_item_set_current_value_text(item, preset_text[value_index]);
|
variable_item_set_current_value_text(
|
||||||
|
item, subghz_setting_get_preset_name(subghz->setting, value_index));
|
||||||
|
|
||||||
if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) !=
|
if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) !=
|
||||||
SubGhzCustomEventManagerSet) {
|
SubGhzCustomEventManagerSet) {
|
||||||
|
|||||||
@@ -29,10 +29,16 @@ static bool subghz_scene_receiver_info_update_parser(void* context) {
|
|||||||
subghz_protocol_decoder_base_deserialize(
|
subghz_protocol_decoder_base_deserialize(
|
||||||
subghz->txrx->decoder_result,
|
subghz->txrx->decoder_result,
|
||||||
subghz_history_get_raw_data(subghz->txrx->history, subghz->txrx->idx_menu_chosen));
|
subghz_history_get_raw_data(subghz->txrx->history, subghz->txrx->idx_menu_chosen));
|
||||||
subghz->txrx->frequency =
|
|
||||||
subghz_history_get_frequency(subghz->txrx->history, subghz->txrx->idx_menu_chosen);
|
SubGhzPesetDefinition* preset =
|
||||||
subghz->txrx->preset =
|
subghz_history_get_presset(subghz->txrx->history, subghz->txrx->idx_menu_chosen);
|
||||||
subghz_history_get_preset(subghz->txrx->history, subghz->txrx->idx_menu_chosen);
|
subghz_preset_init(
|
||||||
|
subghz,
|
||||||
|
string_get_cstr(preset->name),
|
||||||
|
preset->frequency,
|
||||||
|
preset->data,
|
||||||
|
preset->data_size);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -148,8 +154,11 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event)
|
|||||||
subghz_tx_stop(subghz);
|
subghz_tx_stop(subghz);
|
||||||
}
|
}
|
||||||
if(subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) {
|
if(subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) {
|
||||||
subghz_begin(subghz, subghz->txrx->preset);
|
subghz_begin(
|
||||||
subghz_rx(subghz, subghz->txrx->frequency);
|
subghz,
|
||||||
|
subghz_setting_get_preset_data_by_name(
|
||||||
|
subghz->setting, string_get_cstr(subghz->txrx->preset->name)));
|
||||||
|
subghz_rx(subghz, subghz->txrx->preset->frequency);
|
||||||
}
|
}
|
||||||
if(subghz->txrx->hopper_state == SubGhzHopperStatePause) {
|
if(subghz->txrx->hopper_state == SubGhzHopperStatePause) {
|
||||||
subghz->txrx->hopper_state = SubGhzHopperStateRunnig;
|
subghz->txrx->hopper_state = SubGhzHopperStateRunnig;
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ void subghz_scene_set_seed_bft_on_enter(void* context) {
|
|||||||
SubGhz* subghz = context;
|
SubGhz* subghz = context;
|
||||||
|
|
||||||
// Setup view
|
// Setup view
|
||||||
|
// roguemaster don't steal!!!
|
||||||
ByteInput* byte_input = subghz->byte_input;
|
ByteInput* byte_input = subghz->byte_input;
|
||||||
byte_input_set_header_text(byte_input, "Enter SEED in hex");
|
byte_input_set_header_text(byte_input, "Enter SEED in hex");
|
||||||
byte_input_set_result_callback(
|
byte_input_set_result_callback(
|
||||||
@@ -47,6 +48,7 @@ bool subghz_scene_set_seed_bft_on_event(void* context, SceneManagerEvent event)
|
|||||||
subghz->txrx->transmitter =
|
subghz->txrx->transmitter =
|
||||||
subghz_transmitter_alloc_init(subghz->txrx->environment, "KeeLoq");
|
subghz_transmitter_alloc_init(subghz->txrx->environment, "KeeLoq");
|
||||||
if(subghz->txrx->transmitter) {
|
if(subghz->txrx->transmitter) {
|
||||||
|
subghz_preset_init(subghz, "AM650", 433920000, NULL, 0);
|
||||||
subghz_protocol_keeloq_bft_create_data(
|
subghz_protocol_keeloq_bft_create_data(
|
||||||
subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),
|
subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),
|
||||||
subghz->txrx->fff_data,
|
subghz->txrx->fff_data,
|
||||||
@@ -55,8 +57,7 @@ bool subghz_scene_set_seed_bft_on_event(void* context, SceneManagerEvent event)
|
|||||||
cnt,
|
cnt,
|
||||||
seed,
|
seed,
|
||||||
"BFT",
|
"BFT",
|
||||||
433920000,
|
subghz->txrx->preset);
|
||||||
FuriHalSubGhzPresetOok650Async);
|
|
||||||
|
|
||||||
uint8_t seed_data[sizeof(uint32_t)] = {0};
|
uint8_t seed_data[sizeof(uint32_t)] = {0};
|
||||||
for(size_t i = 0; i < sizeof(uint32_t); i++) {
|
for(size_t i = 0; i < sizeof(uint32_t); i++) {
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ bool subghz_scene_set_seed_faac_433_on_event(void* context, SceneManagerEvent ev
|
|||||||
subghz->txrx->transmitter =
|
subghz->txrx->transmitter =
|
||||||
subghz_transmitter_alloc_init(subghz->txrx->environment, "Faac SLH");
|
subghz_transmitter_alloc_init(subghz->txrx->environment, "Faac SLH");
|
||||||
if(subghz->txrx->transmitter) {
|
if(subghz->txrx->transmitter) {
|
||||||
|
subghz_preset_init(subghz, "AM650", 433920000, NULL, 0);
|
||||||
subghz_protocol_faac_slh_create_data(
|
subghz_protocol_faac_slh_create_data(
|
||||||
subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),
|
subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),
|
||||||
subghz->txrx->fff_data,
|
subghz->txrx->fff_data,
|
||||||
@@ -56,9 +57,8 @@ bool subghz_scene_set_seed_faac_433_on_event(void* context, SceneManagerEvent ev
|
|||||||
(cnt & 0xFFFFF),
|
(cnt & 0xFFFFF),
|
||||||
seed,
|
seed,
|
||||||
"FAAC_SLH",
|
"FAAC_SLH",
|
||||||
433920000,
|
subghz->txrx->preset);
|
||||||
FuriHalSubGhzPresetOok650Async);
|
// rogueemaster dont steal!
|
||||||
|
|
||||||
uint8_t seed_data[sizeof(uint32_t)] = {0};
|
uint8_t seed_data[sizeof(uint32_t)] = {0};
|
||||||
for(size_t i = 0; i < sizeof(uint32_t); i++) {
|
for(size_t i = 0; i < sizeof(uint32_t); i++) {
|
||||||
seed_data[sizeof(uint32_t) - i - 1] = (seed >> i * 8) & 0xFF;
|
seed_data[sizeof(uint32_t) - i - 1] = (seed >> i * 8) & 0xFF;
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ bool subghz_scene_set_seed_faac_868_on_event(void* context, SceneManagerEvent ev
|
|||||||
subghz->txrx->transmitter =
|
subghz->txrx->transmitter =
|
||||||
subghz_transmitter_alloc_init(subghz->txrx->environment, "Faac SLH");
|
subghz_transmitter_alloc_init(subghz->txrx->environment, "Faac SLH");
|
||||||
if(subghz->txrx->transmitter) {
|
if(subghz->txrx->transmitter) {
|
||||||
|
subghz_preset_init(subghz, "AM650", 868350000, NULL, 0);
|
||||||
subghz_protocol_faac_slh_create_data(
|
subghz_protocol_faac_slh_create_data(
|
||||||
subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),
|
subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),
|
||||||
subghz->txrx->fff_data,
|
subghz->txrx->fff_data,
|
||||||
@@ -56,9 +57,8 @@ bool subghz_scene_set_seed_faac_868_on_event(void* context, SceneManagerEvent ev
|
|||||||
(cnt & 0xFFFFF),
|
(cnt & 0xFFFFF),
|
||||||
seed,
|
seed,
|
||||||
"FAAC_SLH",
|
"FAAC_SLH",
|
||||||
868350000,
|
subghz->txrx->preset);
|
||||||
FuriHalSubGhzPresetOok650Async);
|
// roguemastter dont steal!!
|
||||||
|
|
||||||
uint8_t seed_data[sizeof(uint32_t)] = {0};
|
uint8_t seed_data[sizeof(uint32_t)] = {0};
|
||||||
for(size_t i = 0; i < sizeof(uint32_t); i++) {
|
for(size_t i = 0; i < sizeof(uint32_t); i++) {
|
||||||
seed_data[sizeof(uint32_t) - i - 1] = (seed >> i * 8) & 0xFF;
|
seed_data[sizeof(uint32_t) - i - 1] = (seed >> i * 8) & 0xFF;
|
||||||
|
|||||||
@@ -17,12 +17,13 @@ bool subghz_scene_set_type_submenu_gen_data_protocol(
|
|||||||
uint64_t key,
|
uint64_t key,
|
||||||
uint32_t bit,
|
uint32_t bit,
|
||||||
uint32_t frequency,
|
uint32_t frequency,
|
||||||
FuriHalSubGhzPreset preset) {
|
const char* preset_name) {
|
||||||
furi_assert(context);
|
furi_assert(context);
|
||||||
SubGhz* subghz = context;
|
SubGhz* subghz = context;
|
||||||
|
|
||||||
bool res = false;
|
bool res = false;
|
||||||
|
|
||||||
|
subghz_preset_init(subghz, preset_name, frequency, NULL, 0);
|
||||||
subghz->txrx->decoder_result =
|
subghz->txrx->decoder_result =
|
||||||
subghz_receiver_search_decoder_base_by_name(subghz->txrx->receiver, protocol_name);
|
subghz_receiver_search_decoder_base_by_name(subghz->txrx->receiver, protocol_name);
|
||||||
|
|
||||||
@@ -36,7 +37,7 @@ bool subghz_scene_set_type_submenu_gen_data_protocol(
|
|||||||
Stream* fff_data_stream = flipper_format_get_raw_stream(subghz->txrx->fff_data);
|
Stream* fff_data_stream = flipper_format_get_raw_stream(subghz->txrx->fff_data);
|
||||||
stream_clean(fff_data_stream);
|
stream_clean(fff_data_stream);
|
||||||
if(!subghz_protocol_decoder_base_serialize(
|
if(!subghz_protocol_decoder_base_serialize(
|
||||||
subghz->txrx->decoder_result, subghz->txrx->fff_data, frequency, preset)) {
|
subghz->txrx->decoder_result, subghz->txrx->fff_data, subghz->txrx->preset)) {
|
||||||
FURI_LOG_E(TAG, "Unable to serialize");
|
FURI_LOG_E(TAG, "Unable to serialize");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -205,12 +206,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
|
|||||||
case SubmenuIndexPricenton:
|
case SubmenuIndexPricenton:
|
||||||
key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
|
key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
|
||||||
if(subghz_scene_set_type_submenu_gen_data_protocol(
|
if(subghz_scene_set_type_submenu_gen_data_protocol(
|
||||||
subghz,
|
subghz, SUBGHZ_PROTOCOL_PRINCETON_NAME, key, 24, 433920000, "AM650")) {
|
||||||
SUBGHZ_PROTOCOL_PRINCETON_NAME,
|
|
||||||
key,
|
|
||||||
24,
|
|
||||||
433920000,
|
|
||||||
FuriHalSubGhzPresetOok650Async)) {
|
|
||||||
uint32_t te = 400;
|
uint32_t te = 400;
|
||||||
flipper_format_update_uint32(subghz->txrx->fff_data, "TE", (uint32_t*)&te, 1);
|
flipper_format_update_uint32(subghz->txrx->fff_data, "TE", (uint32_t*)&te, 1);
|
||||||
generated_protocol = true;
|
generated_protocol = true;
|
||||||
@@ -219,60 +215,35 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
|
|||||||
case SubmenuIndexNiceFlo12bit:
|
case SubmenuIndexNiceFlo12bit:
|
||||||
key = (key & 0x0000FFF0) | 0x1; //btn 0x1, 0x2, 0x4
|
key = (key & 0x0000FFF0) | 0x1; //btn 0x1, 0x2, 0x4
|
||||||
if(subghz_scene_set_type_submenu_gen_data_protocol(
|
if(subghz_scene_set_type_submenu_gen_data_protocol(
|
||||||
subghz,
|
subghz, SUBGHZ_PROTOCOL_NICE_FLO_NAME, key, 12, 433920000, "AM650")) {
|
||||||
SUBGHZ_PROTOCOL_NICE_FLO_NAME,
|
|
||||||
key,
|
|
||||||
12,
|
|
||||||
433920000,
|
|
||||||
FuriHalSubGhzPresetOok650Async)) {
|
|
||||||
generated_protocol = true;
|
generated_protocol = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SubmenuIndexNiceFlo24bit:
|
case SubmenuIndexNiceFlo24bit:
|
||||||
key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
|
key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
|
||||||
if(subghz_scene_set_type_submenu_gen_data_protocol(
|
if(subghz_scene_set_type_submenu_gen_data_protocol(
|
||||||
subghz,
|
subghz, SUBGHZ_PROTOCOL_NICE_FLO_NAME, key, 24, 433920000, "AM650")) {
|
||||||
SUBGHZ_PROTOCOL_NICE_FLO_NAME,
|
|
||||||
key,
|
|
||||||
24,
|
|
||||||
433920000,
|
|
||||||
FuriHalSubGhzPresetOok650Async)) {
|
|
||||||
generated_protocol = true;
|
generated_protocol = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SubmenuIndexCAME12bit:
|
case SubmenuIndexCAME12bit:
|
||||||
key = (key & 0x0000FFF0) | 0x1; //btn 0x1, 0x2, 0x4
|
key = (key & 0x0000FFF0) | 0x1; //btn 0x1, 0x2, 0x4
|
||||||
if(subghz_scene_set_type_submenu_gen_data_protocol(
|
if(subghz_scene_set_type_submenu_gen_data_protocol(
|
||||||
subghz,
|
subghz, SUBGHZ_PROTOCOL_CAME_NAME, key, 12, 433920000, "AM650")) {
|
||||||
SUBGHZ_PROTOCOL_CAME_NAME,
|
|
||||||
key,
|
|
||||||
12,
|
|
||||||
433920000,
|
|
||||||
FuriHalSubGhzPresetOok650Async)) {
|
|
||||||
generated_protocol = true;
|
generated_protocol = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SubmenuIndexCAME24bit:
|
case SubmenuIndexCAME24bit:
|
||||||
key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
|
key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
|
||||||
if(subghz_scene_set_type_submenu_gen_data_protocol(
|
if(subghz_scene_set_type_submenu_gen_data_protocol(
|
||||||
subghz,
|
subghz, SUBGHZ_PROTOCOL_CAME_NAME, key, 24, 433920000, "AM650")) {
|
||||||
SUBGHZ_PROTOCOL_CAME_NAME,
|
|
||||||
key,
|
|
||||||
24,
|
|
||||||
433920000,
|
|
||||||
FuriHalSubGhzPresetOok650Async)) {
|
|
||||||
generated_protocol = true;
|
generated_protocol = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SubmenuIndexLinear_300_00:
|
case SubmenuIndexLinear_300_00:
|
||||||
key = (key & 0x3FF);
|
key = (key & 0x3FF);
|
||||||
if(subghz_scene_set_type_submenu_gen_data_protocol(
|
if(subghz_scene_set_type_submenu_gen_data_protocol(
|
||||||
subghz,
|
subghz, SUBGHZ_PROTOCOL_LINEAR_NAME, key, 10, 300000000, "AM650")) {
|
||||||
SUBGHZ_PROTOCOL_LINEAR_NAME,
|
|
||||||
key,
|
|
||||||
10,
|
|
||||||
300000000,
|
|
||||||
FuriHalSubGhzPresetOok650Async)) {
|
|
||||||
generated_protocol = true;
|
generated_protocol = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -280,12 +251,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
|
|||||||
key = (key & 0x0FFFFFF0);
|
key = (key & 0x0FFFFFF0);
|
||||||
key = 0x003FFF7200000000 | (key ^ 0xE0E0E0EE);
|
key = 0x003FFF7200000000 | (key ^ 0xE0E0E0EE);
|
||||||
if(subghz_scene_set_type_submenu_gen_data_protocol(
|
if(subghz_scene_set_type_submenu_gen_data_protocol(
|
||||||
subghz,
|
subghz, SUBGHZ_PROTOCOL_CAME_TWEE_NAME, key, 54, 433920000, "AM650")) {
|
||||||
SUBGHZ_PROTOCOL_CAME_TWEE_NAME,
|
|
||||||
key,
|
|
||||||
54,
|
|
||||||
433920000,
|
|
||||||
FuriHalSubGhzPresetOok650Async)) {
|
|
||||||
generated_protocol = true;
|
generated_protocol = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -299,18 +265,15 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
|
|||||||
key = (key & 0x00F0FF00) | 0xF << 16 | 0x40; //btn 0xF, 0xC, 0xA, 0x6 (?)
|
key = (key & 0x00F0FF00) | 0xF << 16 | 0x40; //btn 0xF, 0xC, 0xA, 0x6 (?)
|
||||||
uint64_t rev_key = subghz_protocol_blocks_reverse_key(key, 24);
|
uint64_t rev_key = subghz_protocol_blocks_reverse_key(key, 24);
|
||||||
if(subghz_scene_set_type_submenu_gen_data_protocol(
|
if(subghz_scene_set_type_submenu_gen_data_protocol(
|
||||||
subghz,
|
subghz, SUBGHZ_PROTOCOL_GATE_TX_NAME, rev_key, 24, 433920000, "AM650")) {
|
||||||
SUBGHZ_PROTOCOL_GATE_TX_NAME,
|
|
||||||
rev_key,
|
|
||||||
24,
|
|
||||||
433920000,
|
|
||||||
FuriHalSubGhzPresetOok650Async)) {
|
|
||||||
generated_protocol = true;
|
generated_protocol = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SubmenuIndexDoorHan_433_92:
|
case SubmenuIndexDoorHan_433_92:
|
||||||
subghz->txrx->transmitter = subghz_transmitter_alloc_init(
|
subghz->txrx->transmitter = subghz_transmitter_alloc_init(
|
||||||
subghz->txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME);
|
subghz->txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME);
|
||||||
|
subghz_preset_init(
|
||||||
|
subghz, "AM650", subghz_setting_get_default_frequency(subghz->setting), NULL, 0);
|
||||||
if(subghz->txrx->transmitter) {
|
if(subghz->txrx->transmitter) {
|
||||||
subghz_protocol_keeloq_create_data(
|
subghz_protocol_keeloq_create_data(
|
||||||
subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),
|
subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),
|
||||||
@@ -319,8 +282,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
|
|||||||
0x2,
|
0x2,
|
||||||
0x0003,
|
0x0003,
|
||||||
"DoorHan",
|
"DoorHan",
|
||||||
subghz_setting_get_default_frequency(subghz->setting),
|
subghz->txrx->preset);
|
||||||
FuriHalSubGhzPresetOok650Async);
|
|
||||||
generated_protocol = true;
|
generated_protocol = true;
|
||||||
} else {
|
} else {
|
||||||
generated_protocol = false;
|
generated_protocol = false;
|
||||||
@@ -335,6 +297,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
|
|||||||
case SubmenuIndexDoorHan_315_00:
|
case SubmenuIndexDoorHan_315_00:
|
||||||
subghz->txrx->transmitter = subghz_transmitter_alloc_init(
|
subghz->txrx->transmitter = subghz_transmitter_alloc_init(
|
||||||
subghz->txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME);
|
subghz->txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME);
|
||||||
|
subghz_preset_init(subghz, "AM650", 315000000, NULL, 0);
|
||||||
if(subghz->txrx->transmitter) {
|
if(subghz->txrx->transmitter) {
|
||||||
subghz_protocol_keeloq_create_data(
|
subghz_protocol_keeloq_create_data(
|
||||||
subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),
|
subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),
|
||||||
@@ -343,8 +306,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
|
|||||||
0x2,
|
0x2,
|
||||||
0x0003,
|
0x0003,
|
||||||
"DoorHan",
|
"DoorHan",
|
||||||
315000000,
|
subghz->txrx->preset);
|
||||||
FuriHalSubGhzPresetOok650Async);
|
|
||||||
generated_protocol = true;
|
generated_protocol = true;
|
||||||
} else {
|
} else {
|
||||||
generated_protocol = false;
|
generated_protocol = false;
|
||||||
@@ -366,7 +328,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
|
|||||||
(uint64_t)key << 32 | 0xE6000000,
|
(uint64_t)key << 32 | 0xE6000000,
|
||||||
42,
|
42,
|
||||||
315000000,
|
315000000,
|
||||||
FuriHalSubGhzPresetOok650Async)) {
|
"AM650")) {
|
||||||
generated_protocol = true;
|
generated_protocol = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -380,13 +342,14 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
|
|||||||
(uint64_t)key << 32 | 0xE6000000,
|
(uint64_t)key << 32 | 0xE6000000,
|
||||||
42,
|
42,
|
||||||
390000000,
|
390000000,
|
||||||
FuriHalSubGhzPresetOok650Async)) {
|
"AM650")) {
|
||||||
generated_protocol = true;
|
generated_protocol = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SubmenuIndexSecPlus_v2_310_00:
|
case SubmenuIndexSecPlus_v2_310_00:
|
||||||
subghz->txrx->transmitter = subghz_transmitter_alloc_init(
|
subghz->txrx->transmitter = subghz_transmitter_alloc_init(
|
||||||
subghz->txrx->environment, SUBGHZ_PROTOCOL_SECPLUS_V2_NAME);
|
subghz->txrx->environment, SUBGHZ_PROTOCOL_SECPLUS_V2_NAME);
|
||||||
|
subghz_preset_init(subghz, "AM650", 310000000, NULL, 0);
|
||||||
if(subghz->txrx->transmitter) {
|
if(subghz->txrx->transmitter) {
|
||||||
subghz_protocol_secplus_v2_create_data(
|
subghz_protocol_secplus_v2_create_data(
|
||||||
subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),
|
subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),
|
||||||
@@ -394,8 +357,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
|
|||||||
key,
|
key,
|
||||||
0x68,
|
0x68,
|
||||||
0xE500000,
|
0xE500000,
|
||||||
310000000,
|
subghz->txrx->preset);
|
||||||
FuriHalSubGhzPresetOok650Async);
|
|
||||||
generated_protocol = true;
|
generated_protocol = true;
|
||||||
} else {
|
} else {
|
||||||
generated_protocol = false;
|
generated_protocol = false;
|
||||||
@@ -405,6 +367,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
|
|||||||
case SubmenuIndexSecPlus_v2_315_00:
|
case SubmenuIndexSecPlus_v2_315_00:
|
||||||
subghz->txrx->transmitter = subghz_transmitter_alloc_init(
|
subghz->txrx->transmitter = subghz_transmitter_alloc_init(
|
||||||
subghz->txrx->environment, SUBGHZ_PROTOCOL_SECPLUS_V2_NAME);
|
subghz->txrx->environment, SUBGHZ_PROTOCOL_SECPLUS_V2_NAME);
|
||||||
|
subghz_preset_init(subghz, "AM650", 315000000, NULL, 0);
|
||||||
if(subghz->txrx->transmitter) {
|
if(subghz->txrx->transmitter) {
|
||||||
subghz_protocol_secplus_v2_create_data(
|
subghz_protocol_secplus_v2_create_data(
|
||||||
subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),
|
subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),
|
||||||
@@ -412,8 +375,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
|
|||||||
key,
|
key,
|
||||||
0x68,
|
0x68,
|
||||||
0xE500000,
|
0xE500000,
|
||||||
315000000,
|
subghz->txrx->preset);
|
||||||
FuriHalSubGhzPresetOok650Async);
|
|
||||||
generated_protocol = true;
|
generated_protocol = true;
|
||||||
} else {
|
} else {
|
||||||
generated_protocol = false;
|
generated_protocol = false;
|
||||||
@@ -423,6 +385,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
|
|||||||
case SubmenuIndexSecPlus_v2_390_00:
|
case SubmenuIndexSecPlus_v2_390_00:
|
||||||
subghz->txrx->transmitter = subghz_transmitter_alloc_init(
|
subghz->txrx->transmitter = subghz_transmitter_alloc_init(
|
||||||
subghz->txrx->environment, SUBGHZ_PROTOCOL_SECPLUS_V2_NAME);
|
subghz->txrx->environment, SUBGHZ_PROTOCOL_SECPLUS_V2_NAME);
|
||||||
|
subghz_preset_init(subghz, "AM650", 390000000, NULL, 0);
|
||||||
if(subghz->txrx->transmitter) {
|
if(subghz->txrx->transmitter) {
|
||||||
subghz_protocol_secplus_v2_create_data(
|
subghz_protocol_secplus_v2_create_data(
|
||||||
subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),
|
subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),
|
||||||
@@ -430,8 +393,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
|
|||||||
key,
|
key,
|
||||||
0x68,
|
0x68,
|
||||||
0xE500000,
|
0xE500000,
|
||||||
390000000,
|
subghz->txrx->preset);
|
||||||
FuriHalSubGhzPresetOok650Async);
|
|
||||||
generated_protocol = true;
|
generated_protocol = true;
|
||||||
} else {
|
} else {
|
||||||
generated_protocol = false;
|
generated_protocol = false;
|
||||||
|
|||||||
@@ -204,8 +204,11 @@ SubGhz* subghz_alloc() {
|
|||||||
//init Worker & Protocol & History & KeyBoard
|
//init Worker & Protocol & History & KeyBoard
|
||||||
subghz->lock = SubGhzLockOff;
|
subghz->lock = SubGhzLockOff;
|
||||||
subghz->txrx = malloc(sizeof(SubGhzTxRx));
|
subghz->txrx = malloc(sizeof(SubGhzTxRx));
|
||||||
subghz->txrx->frequency = subghz_setting_get_default_frequency(subghz->setting);
|
subghz->txrx->preset = malloc(sizeof(SubGhzPesetDefinition));
|
||||||
subghz->txrx->preset = FuriHalSubGhzPresetOok650Async;
|
string_init(subghz->txrx->preset->name);
|
||||||
|
subghz_preset_init(
|
||||||
|
subghz, "AM650", subghz_setting_get_default_frequency(subghz->setting), NULL, 0);
|
||||||
|
|
||||||
subghz->txrx->txrx_state = SubGhzTxRxStateSleep;
|
subghz->txrx->txrx_state = SubGhzTxRxStateSleep;
|
||||||
subghz->txrx->hopper_state = SubGhzHopperStateOFF;
|
subghz->txrx->hopper_state = SubGhzHopperStateOFF;
|
||||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
|
subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
|
||||||
@@ -318,6 +321,8 @@ void subghz_free(SubGhz* subghz) {
|
|||||||
subghz_worker_free(subghz->txrx->worker);
|
subghz_worker_free(subghz->txrx->worker);
|
||||||
flipper_format_free(subghz->txrx->fff_data);
|
flipper_format_free(subghz->txrx->fff_data);
|
||||||
subghz_history_free(subghz->txrx->history);
|
subghz_history_free(subghz->txrx->history);
|
||||||
|
string_clear(subghz->txrx->preset->name);
|
||||||
|
free(subghz->txrx->preset);
|
||||||
free(subghz->txrx->secure_data);
|
free(subghz->txrx->secure_data);
|
||||||
free(subghz->txrx);
|
free(subghz->txrx);
|
||||||
|
|
||||||
|
|||||||
@@ -12,8 +12,7 @@ typedef struct {
|
|||||||
string_t item_str;
|
string_t item_str;
|
||||||
FlipperFormat* flipper_string;
|
FlipperFormat* flipper_string;
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
FuriHalSubGhzPreset preset;
|
SubGhzPesetDefinition* preset;
|
||||||
uint32_t frequency;
|
|
||||||
} SubGhzHistoryItem;
|
} SubGhzHistoryItem;
|
||||||
|
|
||||||
ARRAY_DEF(SubGhzHistoryItemArray, SubGhzHistoryItem, M_POD_OPLIST)
|
ARRAY_DEF(SubGhzHistoryItemArray, SubGhzHistoryItem, M_POD_OPLIST)
|
||||||
@@ -46,6 +45,8 @@ void subghz_history_free(SubGhzHistory* instance) {
|
|||||||
for
|
for
|
||||||
M_EACH(item, instance->history->data, SubGhzHistoryItemArray_t) {
|
M_EACH(item, instance->history->data, SubGhzHistoryItemArray_t) {
|
||||||
string_clear(item->item_str);
|
string_clear(item->item_str);
|
||||||
|
string_clear(item->preset->name);
|
||||||
|
free(item->preset);
|
||||||
flipper_format_free(item->flipper_string);
|
flipper_format_free(item->flipper_string);
|
||||||
item->type = 0;
|
item->type = 0;
|
||||||
}
|
}
|
||||||
@@ -57,21 +58,29 @@ void subghz_history_free(SubGhzHistory* instance) {
|
|||||||
uint32_t subghz_history_get_frequency(SubGhzHistory* instance, uint16_t idx) {
|
uint32_t subghz_history_get_frequency(SubGhzHistory* instance, uint16_t idx) {
|
||||||
furi_assert(instance);
|
furi_assert(instance);
|
||||||
SubGhzHistoryItem* item = SubGhzHistoryItemArray_get(instance->history->data, idx);
|
SubGhzHistoryItem* item = SubGhzHistoryItemArray_get(instance->history->data, idx);
|
||||||
return item->frequency;
|
return item->preset->frequency;
|
||||||
}
|
}
|
||||||
|
|
||||||
FuriHalSubGhzPreset subghz_history_get_preset(SubGhzHistory* instance, uint16_t idx) {
|
SubGhzPesetDefinition* subghz_history_get_presset(SubGhzHistory* instance, uint16_t idx) {
|
||||||
furi_assert(instance);
|
furi_assert(instance);
|
||||||
SubGhzHistoryItem* item = SubGhzHistoryItemArray_get(instance->history->data, idx);
|
SubGhzHistoryItem* item = SubGhzHistoryItemArray_get(instance->history->data, idx);
|
||||||
return item->preset;
|
return item->preset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* subghz_history_get_preset(SubGhzHistory* instance, uint16_t idx) {
|
||||||
|
furi_assert(instance);
|
||||||
|
SubGhzHistoryItem* item = SubGhzHistoryItemArray_get(instance->history->data, idx);
|
||||||
|
return string_get_cstr(item->preset->name);
|
||||||
|
}
|
||||||
|
|
||||||
void subghz_history_reset(SubGhzHistory* instance) {
|
void subghz_history_reset(SubGhzHistory* instance) {
|
||||||
furi_assert(instance);
|
furi_assert(instance);
|
||||||
string_reset(instance->tmp_string);
|
string_reset(instance->tmp_string);
|
||||||
for
|
for
|
||||||
M_EACH(item, instance->history->data, SubGhzHistoryItemArray_t) {
|
M_EACH(item, instance->history->data, SubGhzHistoryItemArray_t) {
|
||||||
string_clear(item->item_str);
|
string_clear(item->item_str);
|
||||||
|
string_clear(item->preset->name);
|
||||||
|
free(item->preset);
|
||||||
flipper_format_free(item->flipper_string);
|
flipper_format_free(item->flipper_string);
|
||||||
item->type = 0;
|
item->type = 0;
|
||||||
}
|
}
|
||||||
@@ -130,8 +139,7 @@ void subghz_history_get_text_item_menu(SubGhzHistory* instance, string_t output,
|
|||||||
bool subghz_history_add_to_history(
|
bool subghz_history_add_to_history(
|
||||||
SubGhzHistory* instance,
|
SubGhzHistory* instance,
|
||||||
void* context,
|
void* context,
|
||||||
uint32_t frequency,
|
SubGhzPesetDefinition* preset) {
|
||||||
FuriHalSubGhzPreset preset) {
|
|
||||||
furi_assert(instance);
|
furi_assert(instance);
|
||||||
furi_assert(context);
|
furi_assert(context);
|
||||||
|
|
||||||
@@ -151,13 +159,17 @@ bool subghz_history_add_to_history(
|
|||||||
string_t text;
|
string_t text;
|
||||||
string_init(text);
|
string_init(text);
|
||||||
SubGhzHistoryItem* item = SubGhzHistoryItemArray_push_raw(instance->history->data);
|
SubGhzHistoryItem* item = SubGhzHistoryItemArray_push_raw(instance->history->data);
|
||||||
|
item->preset = malloc(sizeof(SubGhzPesetDefinition));
|
||||||
item->type = decoder_base->protocol->type;
|
item->type = decoder_base->protocol->type;
|
||||||
item->frequency = frequency;
|
item->preset->frequency = preset->frequency;
|
||||||
item->preset = preset;
|
string_init(item->preset->name);
|
||||||
|
string_set(item->preset->name, preset->name);
|
||||||
|
item->preset->data = preset->data;
|
||||||
|
item->preset->data_size = preset->data_size;
|
||||||
|
|
||||||
string_init(item->item_str);
|
string_init(item->item_str);
|
||||||
item->flipper_string = flipper_format_string_alloc();
|
item->flipper_string = flipper_format_string_alloc();
|
||||||
subghz_protocol_decoder_base_serialize(decoder_base, item->flipper_string, frequency, preset);
|
subghz_protocol_decoder_base_serialize(decoder_base, item->flipper_string, preset);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if(!flipper_format_rewind(item->flipper_string)) {
|
if(!flipper_format_rewind(item->flipper_string)) {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include <furi.h>
|
#include <furi.h>
|
||||||
#include <furi_hal.h>
|
#include <furi_hal.h>
|
||||||
#include <lib/flipper_format/flipper_format.h>
|
#include <lib/flipper_format/flipper_format.h>
|
||||||
|
#include "helpers/subghz_types.h"
|
||||||
|
|
||||||
typedef struct SubGhzHistory SubGhzHistory;
|
typedef struct SubGhzHistory SubGhzHistory;
|
||||||
|
|
||||||
@@ -34,13 +35,15 @@ void subghz_history_reset(SubGhzHistory* instance);
|
|||||||
*/
|
*/
|
||||||
uint32_t subghz_history_get_frequency(SubGhzHistory* instance, uint16_t idx);
|
uint32_t subghz_history_get_frequency(SubGhzHistory* instance, uint16_t idx);
|
||||||
|
|
||||||
|
SubGhzPesetDefinition* subghz_history_get_presset(SubGhzHistory* instance, uint16_t idx);
|
||||||
|
|
||||||
/** Get preset to history[idx]
|
/** Get preset to history[idx]
|
||||||
*
|
*
|
||||||
* @param instance - SubGhzHistory instance
|
* @param instance - SubGhzHistory instance
|
||||||
* @param idx - record index
|
* @param idx - record index
|
||||||
* @return preset - FuriHalSubGhzPreset preset
|
* @return preset - preset name
|
||||||
*/
|
*/
|
||||||
FuriHalSubGhzPreset subghz_history_get_preset(SubGhzHistory* instance, uint16_t idx);
|
const char* subghz_history_get_preset(SubGhzHistory* instance, uint16_t idx);
|
||||||
|
|
||||||
/** Get history index write
|
/** Get history index write
|
||||||
*
|
*
|
||||||
@@ -85,15 +88,13 @@ bool subghz_history_get_text_space_left(SubGhzHistory* instance, string_t output
|
|||||||
*
|
*
|
||||||
* @param instance - SubGhzHistory instance
|
* @param instance - SubGhzHistory instance
|
||||||
* @param context - SubGhzProtocolCommon context
|
* @param context - SubGhzProtocolCommon context
|
||||||
* @param frequency - frequency Hz
|
* @param preset - SubGhzPesetDefinition preset
|
||||||
* @param preset - FuriHalSubGhzPreset preset
|
|
||||||
* @return bool;
|
* @return bool;
|
||||||
*/
|
*/
|
||||||
bool subghz_history_add_to_history(
|
bool subghz_history_add_to_history(
|
||||||
SubGhzHistory* instance,
|
SubGhzHistory* instance,
|
||||||
void* context,
|
void* context,
|
||||||
uint32_t frequency,
|
SubGhzPesetDefinition* preset);
|
||||||
FuriHalSubGhzPreset preset);
|
|
||||||
|
|
||||||
/** Get SubGhzProtocolCommonLoad to load into the protocol decoder bin data
|
/** Get SubGhzProtocolCommonLoad to load into the protocol decoder bin data
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
#include "subghz_i.h"
|
#include "subghz_i.h"
|
||||||
|
|
||||||
#include "assets_icons.h"
|
#include "assets_icons.h"
|
||||||
#include "m-string.h"
|
|
||||||
#include "subghz/types.h"
|
#include "subghz/types.h"
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <furi.h>
|
#include <furi.h>
|
||||||
@@ -19,15 +18,31 @@
|
|||||||
|
|
||||||
#define TAG "SubGhz"
|
#define TAG "SubGhz"
|
||||||
|
|
||||||
|
void subghz_preset_init(
|
||||||
|
void* context,
|
||||||
|
const char* preset_name,
|
||||||
|
uint32_t frequency,
|
||||||
|
uint8_t* preset_data,
|
||||||
|
size_t preset_data_size) {
|
||||||
|
furi_assert(context);
|
||||||
|
SubGhz* subghz = context;
|
||||||
|
string_set(subghz->txrx->preset->name, preset_name);
|
||||||
|
subghz->txrx->preset->frequency = frequency;
|
||||||
|
subghz->txrx->preset->data = preset_data;
|
||||||
|
subghz->txrx->preset->data_size = preset_data_size;
|
||||||
|
}
|
||||||
|
|
||||||
bool subghz_set_preset(SubGhz* subghz, const char* preset) {
|
bool subghz_set_preset(SubGhz* subghz, const char* preset) {
|
||||||
if(!strcmp(preset, "FuriHalSubGhzPresetOok270Async")) {
|
if(!strcmp(preset, "FuriHalSubGhzPresetOok270Async")) {
|
||||||
subghz->txrx->preset = FuriHalSubGhzPresetOok270Async;
|
string_set(subghz->txrx->preset->name, "AM270");
|
||||||
} else if(!strcmp(preset, "FuriHalSubGhzPresetOok650Async")) {
|
} else if(!strcmp(preset, "FuriHalSubGhzPresetOok650Async")) {
|
||||||
subghz->txrx->preset = FuriHalSubGhzPresetOok650Async;
|
string_set(subghz->txrx->preset->name, "AM650");
|
||||||
} else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev238Async")) {
|
} else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev238Async")) {
|
||||||
subghz->txrx->preset = FuriHalSubGhzPreset2FSKDev238Async;
|
string_set(subghz->txrx->preset->name, "FM238");
|
||||||
} else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev476Async")) {
|
} else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev476Async")) {
|
||||||
subghz->txrx->preset = FuriHalSubGhzPreset2FSKDev476Async;
|
string_set(subghz->txrx->preset->name, "FM476");
|
||||||
|
} else if(!strcmp(preset, "FuriHalSubGhzPresetCustom")) {
|
||||||
|
string_set(subghz->txrx->preset->name, "CUSTOM");
|
||||||
} else {
|
} else {
|
||||||
FURI_LOG_E(TAG, "Unknown preset");
|
FURI_LOG_E(TAG, "Unknown preset");
|
||||||
return false;
|
return false;
|
||||||
@@ -41,29 +56,19 @@ void subghz_get_frequency_modulation(SubGhz* subghz, string_t frequency, string_
|
|||||||
string_printf(
|
string_printf(
|
||||||
frequency,
|
frequency,
|
||||||
"%03ld.%02ld",
|
"%03ld.%02ld",
|
||||||
subghz->txrx->frequency / 1000000 % 1000,
|
subghz->txrx->preset->frequency / 1000000 % 1000,
|
||||||
subghz->txrx->frequency / 10000 % 100);
|
subghz->txrx->preset->frequency / 10000 % 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(modulation != NULL) {
|
if(modulation != NULL) {
|
||||||
if(subghz->txrx->preset == FuriHalSubGhzPresetOok650Async ||
|
string_printf(modulation, "%0.2s", string_get_cstr(subghz->txrx->preset->name));
|
||||||
subghz->txrx->preset == FuriHalSubGhzPresetOok270Async) {
|
|
||||||
string_set_str(modulation, "AM");
|
|
||||||
} else if(
|
|
||||||
subghz->txrx->preset == FuriHalSubGhzPreset2FSKDev238Async ||
|
|
||||||
subghz->txrx->preset == FuriHalSubGhzPreset2FSKDev476Async) {
|
|
||||||
string_set_str(modulation, "FM");
|
|
||||||
} else {
|
|
||||||
furi_crash("SubGhz: Modulation is incorrect.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void subghz_begin(SubGhz* subghz, FuriHalSubGhzPreset preset) {
|
void subghz_begin(SubGhz* subghz, uint8_t* preset_data) {
|
||||||
furi_assert(subghz);
|
furi_assert(subghz);
|
||||||
furi_hal_subghz_reset();
|
furi_hal_subghz_reset();
|
||||||
furi_hal_subghz_idle();
|
furi_hal_subghz_idle();
|
||||||
furi_hal_subghz_load_preset(preset);
|
furi_hal_subghz_load_custom_preset(preset_data);
|
||||||
furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow);
|
furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow);
|
||||||
subghz->txrx->txrx_state = SubGhzTxRxStateIDLE;
|
subghz->txrx->txrx_state = SubGhzTxRxStateIDLE;
|
||||||
}
|
}
|
||||||
@@ -155,13 +160,21 @@ bool subghz_tx_start(SubGhz* subghz, FlipperFormat* flipper_format) {
|
|||||||
|
|
||||||
if(subghz->txrx->transmitter) {
|
if(subghz->txrx->transmitter) {
|
||||||
if(subghz_transmitter_deserialize(subghz->txrx->transmitter, flipper_format)) {
|
if(subghz_transmitter_deserialize(subghz->txrx->transmitter, flipper_format)) {
|
||||||
if(subghz->txrx->preset) {
|
if(strcmp(string_get_cstr(subghz->txrx->preset->name), "")) {
|
||||||
subghz_begin(subghz, subghz->txrx->preset);
|
subghz_begin(
|
||||||
|
subghz,
|
||||||
|
subghz_setting_get_preset_data_by_name(
|
||||||
|
subghz->setting, string_get_cstr(subghz->txrx->preset->name)));
|
||||||
} else {
|
} else {
|
||||||
subghz_begin(subghz, FuriHalSubGhzPresetOok270Async);
|
FURI_LOG_E(
|
||||||
|
TAG,
|
||||||
|
"Unknown name preset \" %s \"",
|
||||||
|
string_get_cstr(subghz->txrx->preset->name));
|
||||||
|
subghz_begin(
|
||||||
|
subghz, subghz_setting_get_preset_data_by_name(subghz->setting, "AM650"));
|
||||||
}
|
}
|
||||||
if(subghz->txrx->frequency) {
|
if(subghz->txrx->preset->frequency) {
|
||||||
ret = subghz_tx(subghz, subghz->txrx->frequency);
|
ret = subghz_tx(subghz, subghz->txrx->preset->frequency);
|
||||||
} else {
|
} else {
|
||||||
ret = subghz_tx(subghz, 433920000);
|
ret = subghz_tx(subghz, 433920000);
|
||||||
}
|
}
|
||||||
@@ -270,16 +283,38 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) {
|
|||||||
load_key_state = SubGhzLoadKeyStateOnlyRx;
|
load_key_state = SubGhzLoadKeyStateOnlyRx;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
subghz->txrx->frequency = temp_data32;
|
subghz->txrx->preset->frequency = temp_data32;
|
||||||
|
|
||||||
if(!flipper_format_read_string(fff_data_file, "Preset", temp_str)) {
|
if(!flipper_format_read_string(fff_data_file, "Preset", temp_str)) {
|
||||||
FURI_LOG_E(TAG, "Missing Preset");
|
FURI_LOG_E(TAG, "Missing Preset");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!subghz_set_preset(subghz, string_get_cstr(temp_str))) {
|
if(!subghz_set_preset(subghz, string_get_cstr(temp_str))) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!strcmp(string_get_cstr(temp_str), "FuriHalSubGhzPresetCustom")) {
|
||||||
|
//Todo add Custom_preset_module
|
||||||
|
//delete peset if it already exists
|
||||||
|
subghz_setting_delete_custom_preset(
|
||||||
|
subghz->setting, string_get_cstr(subghz->txrx->preset->name));
|
||||||
|
//load custom preset from file
|
||||||
|
if(!subghz_setting_load_custom_preset(
|
||||||
|
subghz->setting, string_get_cstr(subghz->txrx->preset->name), fff_data_file)) {
|
||||||
|
FURI_LOG_E(TAG, "Missing Custom preset");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
size_t preset_index = subghz_setting_get_inx_preset_by_name(
|
||||||
|
subghz->setting, string_get_cstr(subghz->txrx->preset->name));
|
||||||
|
subghz_preset_init(
|
||||||
|
subghz,
|
||||||
|
string_get_cstr(subghz->txrx->preset->name),
|
||||||
|
subghz->txrx->preset->frequency,
|
||||||
|
subghz_setting_get_preset_data(subghz->setting, preset_index),
|
||||||
|
subghz_setting_get_preset_data_size(subghz->setting, preset_index));
|
||||||
|
|
||||||
if(!flipper_format_read_string(fff_data_file, "Protocol", temp_str)) {
|
if(!flipper_format_read_string(fff_data_file, "Protocol", temp_str)) {
|
||||||
FURI_LOG_E(TAG, "Missing Protocol");
|
FURI_LOG_E(TAG, "Missing Protocol");
|
||||||
break;
|
break;
|
||||||
@@ -541,8 +576,8 @@ void subghz_hopper_update(SubGhz* subghz) {
|
|||||||
};
|
};
|
||||||
if(subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) {
|
if(subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) {
|
||||||
subghz_receiver_reset(subghz->txrx->receiver);
|
subghz_receiver_reset(subghz->txrx->receiver);
|
||||||
subghz->txrx->frequency = subghz_setting_get_hopper_frequency(
|
subghz->txrx->preset->frequency = subghz_setting_get_hopper_frequency(
|
||||||
subghz->setting, subghz->txrx->hopper_idx_frequency);
|
subghz->setting, subghz->txrx->hopper_idx_frequency);
|
||||||
subghz_rx(subghz, subghz->txrx->frequency);
|
subghz_rx(subghz, subghz->txrx->preset->frequency);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,8 +11,8 @@
|
|||||||
#include "views/subghz_test_carrier.h"
|
#include "views/subghz_test_carrier.h"
|
||||||
#include "views/subghz_test_packet.h"
|
#include "views/subghz_test_packet.h"
|
||||||
|
|
||||||
#include <furi.h>
|
// #include <furi.h>
|
||||||
#include <furi_hal.h>
|
// #include <furi_hal.h>
|
||||||
#include <gui/gui.h>
|
#include <gui/gui.h>
|
||||||
#include <dialogs/dialogs.h>
|
#include <dialogs/dialogs.h>
|
||||||
#include <gui/scene_manager.h>
|
#include <gui/scene_manager.h>
|
||||||
@@ -57,8 +57,7 @@ struct SubGhzTxRx {
|
|||||||
FlipperFormat* fff_data;
|
FlipperFormat* fff_data;
|
||||||
SecureData* secure_data;
|
SecureData* secure_data;
|
||||||
|
|
||||||
uint32_t frequency;
|
SubGhzPesetDefinition* preset;
|
||||||
FuriHalSubGhzPreset preset;
|
|
||||||
SubGhzHistory* history;
|
SubGhzHistory* history;
|
||||||
uint16_t idx_menu_chosen;
|
uint16_t idx_menu_chosen;
|
||||||
SubGhzTxRxState txrx_state;
|
SubGhzTxRxState txrx_state;
|
||||||
@@ -106,9 +105,15 @@ struct SubGhz {
|
|||||||
void* rpc_ctx;
|
void* rpc_ctx;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void subghz_preset_init(
|
||||||
|
void* context,
|
||||||
|
const char* preset_name,
|
||||||
|
uint32_t frequency,
|
||||||
|
uint8_t* preset_data,
|
||||||
|
size_t preset_data_size);
|
||||||
bool subghz_set_preset(SubGhz* subghz, const char* preset);
|
bool subghz_set_preset(SubGhz* subghz, const char* preset);
|
||||||
void subghz_get_frequency_modulation(SubGhz* subghz, string_t frequency, string_t modulation);
|
void subghz_get_frequency_modulation(SubGhz* subghz, string_t frequency, string_t modulation);
|
||||||
void subghz_begin(SubGhz* subghz, FuriHalSubGhzPreset preset);
|
void subghz_begin(SubGhz* subghz, uint8_t* preset_data);
|
||||||
uint32_t subghz_rx(SubGhz* subghz, uint32_t frequency);
|
uint32_t subghz_rx(SubGhz* subghz, uint32_t frequency);
|
||||||
void subghz_rx_end(SubGhz* subghz);
|
void subghz_rx_end(SubGhz* subghz);
|
||||||
void subghz_sleep(SubGhz* subghz);
|
void subghz_sleep(SubGhz* subghz);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include <furi.h>
|
#include <furi.h>
|
||||||
#include <m-list.h>
|
#include <m-list.h>
|
||||||
#include <lib/flipper_format/flipper_format.h>
|
#include "furi_hal_subghz_configs.h"
|
||||||
|
|
||||||
#define TAG "SubGhzSetting"
|
#define TAG "SubGhzSetting"
|
||||||
|
|
||||||
@@ -50,29 +50,89 @@ static const uint32_t subghz_hopper_frequency_list[] = {
|
|||||||
0,
|
0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
string_t custom_preset_name;
|
||||||
|
uint8_t* custom_preset_data;
|
||||||
|
size_t custom_preset_data_size;
|
||||||
|
} SubGhzSettingCustomPresetItem;
|
||||||
|
|
||||||
|
ARRAY_DEF(SubGhzSettingCustomPresetItemArray, SubGhzSettingCustomPresetItem, M_POD_OPLIST)
|
||||||
|
|
||||||
|
#define M_OPL_SubGhzSettingCustomPresetItemArray_t() \
|
||||||
|
ARRAY_OPLIST(SubGhzSettingCustomPresetItemArray, M_POD_OPLIST)
|
||||||
|
|
||||||
LIST_DEF(FrequencyList, uint32_t)
|
LIST_DEF(FrequencyList, uint32_t)
|
||||||
|
|
||||||
#define M_OPL_FrequencyList_t() LIST_OPLIST(FrequencyList)
|
#define M_OPL_FrequencyList_t() LIST_OPLIST(FrequencyList)
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
SubGhzSettingCustomPresetItemArray_t data;
|
||||||
|
} SubGhzSettingCustomPresetStruct;
|
||||||
|
|
||||||
struct SubGhzSetting {
|
struct SubGhzSetting {
|
||||||
FrequencyList_t frequencies;
|
FrequencyList_t frequencies;
|
||||||
FrequencyList_t hopper_frequencies;
|
FrequencyList_t hopper_frequencies;
|
||||||
|
SubGhzSettingCustomPresetStruct* preset;
|
||||||
};
|
};
|
||||||
|
|
||||||
SubGhzSetting* subghz_setting_alloc(void) {
|
SubGhzSetting* subghz_setting_alloc(void) {
|
||||||
SubGhzSetting* instance = malloc(sizeof(SubGhzSetting));
|
SubGhzSetting* instance = malloc(sizeof(SubGhzSetting));
|
||||||
FrequencyList_init(instance->frequencies);
|
FrequencyList_init(instance->frequencies);
|
||||||
FrequencyList_init(instance->hopper_frequencies);
|
FrequencyList_init(instance->hopper_frequencies);
|
||||||
|
instance->preset = malloc(sizeof(SubGhzSettingCustomPresetStruct));
|
||||||
|
SubGhzSettingCustomPresetItemArray_init(instance->preset->data);
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void subghz_setting_preset_reset(SubGhzSetting* instance) {
|
||||||
|
for
|
||||||
|
M_EACH(item, instance->preset->data, SubGhzSettingCustomPresetItemArray_t) {
|
||||||
|
string_clear(item->custom_preset_name);
|
||||||
|
free(item->custom_preset_data);
|
||||||
|
}
|
||||||
|
SubGhzSettingCustomPresetItemArray_reset(instance->preset->data);
|
||||||
|
}
|
||||||
|
|
||||||
void subghz_setting_free(SubGhzSetting* instance) {
|
void subghz_setting_free(SubGhzSetting* instance) {
|
||||||
furi_assert(instance);
|
furi_assert(instance);
|
||||||
FrequencyList_clear(instance->frequencies);
|
FrequencyList_clear(instance->frequencies);
|
||||||
FrequencyList_clear(instance->hopper_frequencies);
|
FrequencyList_clear(instance->hopper_frequencies);
|
||||||
|
for
|
||||||
|
M_EACH(item, instance->preset->data, SubGhzSettingCustomPresetItemArray_t) {
|
||||||
|
string_clear(item->custom_preset_name);
|
||||||
|
free(item->custom_preset_data);
|
||||||
|
}
|
||||||
|
SubGhzSettingCustomPresetItemArray_clear(instance->preset->data);
|
||||||
|
free(instance->preset);
|
||||||
free(instance);
|
free(instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void subghz_setting_load_default_preset(
|
||||||
|
SubGhzSetting* instance,
|
||||||
|
const char* preset_name,
|
||||||
|
const uint8_t* preset_data,
|
||||||
|
const uint8_t preset_pa_table[8]) {
|
||||||
|
furi_assert(instance);
|
||||||
|
furi_assert(preset_data);
|
||||||
|
uint32_t preset_data_count = 0;
|
||||||
|
SubGhzSettingCustomPresetItem* item =
|
||||||
|
SubGhzSettingCustomPresetItemArray_push_raw(instance->preset->data);
|
||||||
|
|
||||||
|
string_init(item->custom_preset_name);
|
||||||
|
string_set(item->custom_preset_name, preset_name);
|
||||||
|
|
||||||
|
while(preset_data[preset_data_count]) {
|
||||||
|
preset_data_count += 2;
|
||||||
|
}
|
||||||
|
preset_data_count += 2;
|
||||||
|
item->custom_preset_data_size = sizeof(uint8_t) * preset_data_count + sizeof(uint8_t) * 8;
|
||||||
|
item->custom_preset_data = malloc(item->custom_preset_data_size);
|
||||||
|
//load preset register
|
||||||
|
memcpy(&item->custom_preset_data[0], &preset_data[0], preset_data_count);
|
||||||
|
//load pa table
|
||||||
|
memcpy(&item->custom_preset_data[preset_data_count], &preset_pa_table[0], 8);
|
||||||
|
}
|
||||||
|
|
||||||
static void subghz_setting_load_default_region(
|
static void subghz_setting_load_default_region(
|
||||||
SubGhzSetting* instance,
|
SubGhzSetting* instance,
|
||||||
const uint32_t frequencies[],
|
const uint32_t frequencies[],
|
||||||
@@ -81,6 +141,7 @@ static void subghz_setting_load_default_region(
|
|||||||
|
|
||||||
FrequencyList_reset(instance->frequencies);
|
FrequencyList_reset(instance->frequencies);
|
||||||
FrequencyList_reset(instance->hopper_frequencies);
|
FrequencyList_reset(instance->hopper_frequencies);
|
||||||
|
subghz_setting_preset_reset(instance);
|
||||||
|
|
||||||
while(*frequencies) {
|
while(*frequencies) {
|
||||||
FrequencyList_push_back(instance->frequencies, *frequencies);
|
FrequencyList_push_back(instance->frequencies, *frequencies);
|
||||||
@@ -91,6 +152,27 @@ static void subghz_setting_load_default_region(
|
|||||||
FrequencyList_push_back(instance->hopper_frequencies, *hopper_frequencies);
|
FrequencyList_push_back(instance->hopper_frequencies, *hopper_frequencies);
|
||||||
hopper_frequencies++;
|
hopper_frequencies++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
subghz_setting_load_default_preset(
|
||||||
|
instance,
|
||||||
|
"AM270",
|
||||||
|
(uint8_t*)furi_hal_subghz_preset_ook_270khz_async_regs,
|
||||||
|
furi_hal_subghz_preset_ook_async_patable);
|
||||||
|
subghz_setting_load_default_preset(
|
||||||
|
instance,
|
||||||
|
"AM650",
|
||||||
|
(uint8_t*)furi_hal_subghz_preset_ook_650khz_async_regs,
|
||||||
|
furi_hal_subghz_preset_ook_async_patable);
|
||||||
|
subghz_setting_load_default_preset(
|
||||||
|
instance,
|
||||||
|
"FM238",
|
||||||
|
(uint8_t*)furi_hal_subghz_preset_2fsk_dev2_38khz_async_regs,
|
||||||
|
furi_hal_subghz_preset_2fsk_async_patable);
|
||||||
|
subghz_setting_load_default_preset(
|
||||||
|
instance,
|
||||||
|
"FM476",
|
||||||
|
(uint8_t*)furi_hal_subghz_preset_2fsk_dev47_6khz_async_regs,
|
||||||
|
furi_hal_subghz_preset_2fsk_async_patable);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Region check removed
|
// Region check removed
|
||||||
@@ -133,7 +215,7 @@ void subghz_setting_load(SubGhzSetting* instance, const char* file_path) {
|
|||||||
|
|
||||||
// Standard frequencies (optional)
|
// Standard frequencies (optional)
|
||||||
temp_bool = true;
|
temp_bool = true;
|
||||||
flipper_format_read_bool(fff_data_file, "add_standard_frequencies", &temp_bool, 1);
|
flipper_format_read_bool(fff_data_file, "Add_standard_frequencies", &temp_bool, 1);
|
||||||
if(!temp_bool) {
|
if(!temp_bool) {
|
||||||
FURI_LOG_I(TAG, "Removing standard frequencies");
|
FURI_LOG_I(TAG, "Removing standard frequencies");
|
||||||
FrequencyList_reset(instance->frequencies);
|
FrequencyList_reset(instance->frequencies);
|
||||||
@@ -148,7 +230,7 @@ void subghz_setting_load(SubGhzSetting* instance, const char* file_path) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
while(flipper_format_read_uint32(
|
while(flipper_format_read_uint32(
|
||||||
fff_data_file, "frequency", (uint32_t*)&temp_data32, 1)) {
|
fff_data_file, "Frequency", (uint32_t*)&temp_data32, 1)) {
|
||||||
if(furi_hal_subghz_is_frequency_valid(temp_data32)) {
|
if(furi_hal_subghz_is_frequency_valid(temp_data32)) {
|
||||||
FURI_LOG_I(TAG, "Frequency loaded %lu", temp_data32);
|
FURI_LOG_I(TAG, "Frequency loaded %lu", temp_data32);
|
||||||
FrequencyList_push_back(instance->frequencies, temp_data32);
|
FrequencyList_push_back(instance->frequencies, temp_data32);
|
||||||
@@ -163,7 +245,7 @@ void subghz_setting_load(SubGhzSetting* instance, const char* file_path) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
while(flipper_format_read_uint32(
|
while(flipper_format_read_uint32(
|
||||||
fff_data_file, "hopper_frequency", (uint32_t*)&temp_data32, 1)) {
|
fff_data_file, "Hopper_frequency", (uint32_t*)&temp_data32, 1)) {
|
||||||
if(furi_hal_subghz_is_frequency_valid(temp_data32)) {
|
if(furi_hal_subghz_is_frequency_valid(temp_data32)) {
|
||||||
FURI_LOG_I(TAG, "Hopper frequency loaded %lu", temp_data32);
|
FURI_LOG_I(TAG, "Hopper frequency loaded %lu", temp_data32);
|
||||||
FrequencyList_push_back(instance->hopper_frequencies, temp_data32);
|
FrequencyList_push_back(instance->hopper_frequencies, temp_data32);
|
||||||
@@ -177,7 +259,7 @@ void subghz_setting_load(SubGhzSetting* instance, const char* file_path) {
|
|||||||
FURI_LOG_E(TAG, "Rewind error");
|
FURI_LOG_E(TAG, "Rewind error");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(flipper_format_read_uint32(fff_data_file, "default_frequency", &temp_data32, 1)) {
|
if(flipper_format_read_uint32(fff_data_file, "Default_frequency", &temp_data32, 1)) {
|
||||||
for
|
for
|
||||||
M_EACH(frequency, instance->frequencies, FrequencyList_t) {
|
M_EACH(frequency, instance->frequencies, FrequencyList_t) {
|
||||||
*frequency &= FREQUENCY_MASK;
|
*frequency &= FREQUENCY_MASK;
|
||||||
@@ -186,6 +268,18 @@ void subghz_setting_load(SubGhzSetting* instance, const char* file_path) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// custom preset (optional)
|
||||||
|
if(!flipper_format_rewind(fff_data_file)) {
|
||||||
|
FURI_LOG_E(TAG, "Rewind error");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
while(flipper_format_read_string(fff_data_file, "Custom_preset_name", temp_str)) {
|
||||||
|
FURI_LOG_I(TAG, "Custom preset loaded %s", string_get_cstr(temp_str));
|
||||||
|
subghz_setting_load_custom_preset(
|
||||||
|
instance, string_get_cstr(temp_str), fff_data_file);
|
||||||
|
}
|
||||||
|
|
||||||
} while(false);
|
} while(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -210,6 +304,104 @@ size_t subghz_setting_get_hopper_frequency_count(SubGhzSetting* instance) {
|
|||||||
return FrequencyList_size(instance->hopper_frequencies);
|
return FrequencyList_size(instance->hopper_frequencies);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t subghz_setting_get_preset_count(SubGhzSetting* instance) {
|
||||||
|
furi_assert(instance);
|
||||||
|
return SubGhzSettingCustomPresetItemArray_size(instance->preset->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* subghz_setting_get_preset_name(SubGhzSetting* instance, size_t idx) {
|
||||||
|
furi_assert(instance);
|
||||||
|
SubGhzSettingCustomPresetItem* item =
|
||||||
|
SubGhzSettingCustomPresetItemArray_get(instance->preset->data, idx);
|
||||||
|
return string_get_cstr(item->custom_preset_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
int subghz_setting_get_inx_preset_by_name(SubGhzSetting* instance, const char* preset_name) {
|
||||||
|
furi_assert(instance);
|
||||||
|
size_t idx = 0;
|
||||||
|
for
|
||||||
|
M_EACH(item, instance->preset->data, SubGhzSettingCustomPresetItemArray_t) {
|
||||||
|
if(strcmp(string_get_cstr(item->custom_preset_name), preset_name) == 0) {
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
furi_crash("SubGhz: No name preset.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool subghz_setting_load_custom_preset(
|
||||||
|
SubGhzSetting* instance,
|
||||||
|
const char* preset_name,
|
||||||
|
FlipperFormat* fff_data_file) {
|
||||||
|
furi_assert(instance);
|
||||||
|
furi_assert(preset_name);
|
||||||
|
uint32_t temp_data32;
|
||||||
|
SubGhzSettingCustomPresetItem* item =
|
||||||
|
SubGhzSettingCustomPresetItemArray_push_raw(instance->preset->data);
|
||||||
|
string_init(item->custom_preset_name);
|
||||||
|
string_set(item->custom_preset_name, preset_name);
|
||||||
|
do {
|
||||||
|
if(!flipper_format_get_value_count(fff_data_file, "Custom_preset_data", &temp_data32))
|
||||||
|
break;
|
||||||
|
if(!temp_data32 || (temp_data32 % 2)) {
|
||||||
|
FURI_LOG_E(TAG, "Integrity error Custom_preset_data");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
item->custom_preset_data_size = sizeof(uint8_t) * temp_data32;
|
||||||
|
item->custom_preset_data = malloc(item->custom_preset_data_size);
|
||||||
|
if(!flipper_format_read_hex(
|
||||||
|
fff_data_file,
|
||||||
|
"Custom_preset_data",
|
||||||
|
item->custom_preset_data,
|
||||||
|
item->custom_preset_data_size)) {
|
||||||
|
FURI_LOG_E(TAG, "Missing Custom_preset_data");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} while(true);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool subghz_setting_delete_custom_preset(SubGhzSetting* instance, const char* preset_name) {
|
||||||
|
furi_assert(instance);
|
||||||
|
furi_assert(preset_name);
|
||||||
|
SubGhzSettingCustomPresetItemArray_it_t it;
|
||||||
|
SubGhzSettingCustomPresetItemArray_it_last(it, instance->preset->data);
|
||||||
|
while(!SubGhzSettingCustomPresetItemArray_end_p(it)) {
|
||||||
|
SubGhzSettingCustomPresetItem* item = SubGhzSettingCustomPresetItemArray_ref(it);
|
||||||
|
if(strcmp(string_get_cstr(item->custom_preset_name), preset_name) == 0) {
|
||||||
|
string_clear(item->custom_preset_name);
|
||||||
|
free(item->custom_preset_data);
|
||||||
|
SubGhzSettingCustomPresetItemArray_remove(instance->preset->data, it);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
SubGhzSettingCustomPresetItemArray_previous(it);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* subghz_setting_get_preset_data(SubGhzSetting* instance, size_t idx) {
|
||||||
|
furi_assert(instance);
|
||||||
|
SubGhzSettingCustomPresetItem* item =
|
||||||
|
SubGhzSettingCustomPresetItemArray_get(instance->preset->data, idx);
|
||||||
|
return item->custom_preset_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t subghz_setting_get_preset_data_size(SubGhzSetting* instance, size_t idx) {
|
||||||
|
furi_assert(instance);
|
||||||
|
SubGhzSettingCustomPresetItem* item =
|
||||||
|
SubGhzSettingCustomPresetItemArray_get(instance->preset->data, idx);
|
||||||
|
return item->custom_preset_data_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* subghz_setting_get_preset_data_by_name(SubGhzSetting* instance, const char* preset_name) {
|
||||||
|
furi_assert(instance);
|
||||||
|
SubGhzSettingCustomPresetItem* item = SubGhzSettingCustomPresetItemArray_get(
|
||||||
|
instance->preset->data, subghz_setting_get_inx_preset_by_name(instance, preset_name));
|
||||||
|
return item->custom_preset_data;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t subghz_setting_get_frequency(SubGhzSetting* instance, size_t idx) {
|
uint32_t subghz_setting_get_frequency(SubGhzSetting* instance, size_t idx) {
|
||||||
furi_assert(instance);
|
furi_assert(instance);
|
||||||
uint32_t* ret = FrequencyList_get(instance->frequencies, idx);
|
uint32_t* ret = FrequencyList_get(instance->frequencies, idx);
|
||||||
|
|||||||
@@ -4,6 +4,9 @@
|
|||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <furi.h>
|
#include <furi.h>
|
||||||
#include <furi_hal.h>
|
#include <furi_hal.h>
|
||||||
|
#include <lib/flipper_format/flipper_format.h>
|
||||||
|
|
||||||
|
#define SUBGHZ_SETTING_DEFAULT_PRESET_COUNT 4
|
||||||
|
|
||||||
typedef struct SubGhzSetting SubGhzSetting;
|
typedef struct SubGhzSetting SubGhzSetting;
|
||||||
|
|
||||||
@@ -17,6 +20,25 @@ size_t subghz_setting_get_frequency_count(SubGhzSetting* instance);
|
|||||||
|
|
||||||
size_t subghz_setting_get_hopper_frequency_count(SubGhzSetting* instance);
|
size_t subghz_setting_get_hopper_frequency_count(SubGhzSetting* instance);
|
||||||
|
|
||||||
|
size_t subghz_setting_get_preset_count(SubGhzSetting* instance);
|
||||||
|
|
||||||
|
const char* subghz_setting_get_preset_name(SubGhzSetting* instance, size_t idx);
|
||||||
|
|
||||||
|
int subghz_setting_get_inx_preset_by_name(SubGhzSetting* instance, const char* preset_name);
|
||||||
|
|
||||||
|
uint8_t* subghz_setting_get_preset_data(SubGhzSetting* instance, size_t idx);
|
||||||
|
|
||||||
|
size_t subghz_setting_get_preset_data_size(SubGhzSetting* instance, size_t idx);
|
||||||
|
|
||||||
|
uint8_t* subghz_setting_get_preset_data_by_name(SubGhzSetting* instance, const char* preset_name);
|
||||||
|
|
||||||
|
bool subghz_setting_load_custom_preset(
|
||||||
|
SubGhzSetting* instance,
|
||||||
|
const char* preset_name,
|
||||||
|
FlipperFormat* fff_data_file);
|
||||||
|
|
||||||
|
bool subghz_setting_delete_custom_preset(SubGhzSetting* instance, const char* preset_name);
|
||||||
|
|
||||||
uint32_t subghz_setting_get_frequency(SubGhzSetting* instance, size_t idx);
|
uint32_t subghz_setting_get_frequency(SubGhzSetting* instance, size_t idx);
|
||||||
|
|
||||||
uint32_t subghz_setting_get_hopper_frequency(SubGhzSetting* instance, size_t idx);
|
uint32_t subghz_setting_get_hopper_frequency(SubGhzSetting* instance, size_t idx);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
#include <furi_hal.h>
|
#include <furi_hal.h>
|
||||||
#include <applications/storage/storage.h>
|
#include <applications/storage/storage.h>
|
||||||
#include <lib/flipper_format/flipper_format.h>
|
#include <lib/flipper_format/flipper_format.h>
|
||||||
#include <lib/nfc_protocols/nfca.h>
|
#include <lib/nfc/protocols/nfca.h>
|
||||||
#include <lib/digital_signal/digital_signal.h>
|
#include <lib/digital_signal/digital_signal.h>
|
||||||
|
|
||||||
#include <lib/flipper_format/flipper_format_i.h>
|
#include <lib/flipper_format/flipper_format_i.h>
|
||||||
|
|||||||
BIN
assets/icons/NFC/NFC_manual.png
Normal file
BIN
assets/icons/NFC/NFC_manual.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.7 KiB |
BIN
assets/icons/NFC/Reader_detect.png
Normal file
BIN
assets/icons/NFC/Reader_detect.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.7 KiB |
@@ -1,5 +1,5 @@
|
|||||||
V:0
|
V:0
|
||||||
T:1658333443
|
T:1658858949
|
||||||
D:badusb
|
D:badusb
|
||||||
D:dolphin
|
D:dolphin
|
||||||
D:infrared
|
D:infrared
|
||||||
@@ -235,7 +235,7 @@ F:dda1ef895b8a25fde57c874feaaef997:650:subghz/assets/came_atomo
|
|||||||
F:111d2b8df83e27fd889fc5e270297865:3231:subghz/assets/keeloq_mfcodes
|
F:111d2b8df83e27fd889fc5e270297865:3231:subghz/assets/keeloq_mfcodes
|
||||||
F:9214f9c10463b746a27e82ce0b96e040:465:subghz/assets/keeloq_mfcodes_user
|
F:9214f9c10463b746a27e82ce0b96e040:465:subghz/assets/keeloq_mfcodes_user
|
||||||
F:653bd8d349055a41e1152e557d4a52d3:202:subghz/assets/nice_flor_s
|
F:653bd8d349055a41e1152e557d4a52d3:202:subghz/assets/nice_flor_s
|
||||||
F:48c763d616f95e319388e62e0d7cc49f:850:subghz/assets/setting_user
|
F:837b16faadc5ffb657be1718b05f0bbc:1472:subghz/assets/setting_user
|
||||||
F:9a50dd284146dfbd8050a2ade62174d9:266:subghz/assets/universal_rf_map
|
F:9a50dd284146dfbd8050a2ade62174d9:266:subghz/assets/universal_rf_map
|
||||||
D:u2f/assets
|
D:u2f/assets
|
||||||
F:7e11e688e39034bbb9d88410044795e1:365:u2f/assets/cert.der
|
F:7e11e688e39034bbb9d88410044795e1:365:u2f/assets/cert.der
|
||||||
|
|||||||
@@ -2,28 +2,39 @@ Filetype: Flipper SubGhz Setting File
|
|||||||
Version: 1
|
Version: 1
|
||||||
|
|
||||||
# Add All Standard frequencies
|
# Add All Standard frequencies
|
||||||
#add_standard_frequencies: true
|
#Add_standard_frequencies: true
|
||||||
|
|
||||||
# Default Frequency: used as default for "Read" and "Read Raw"
|
# Default Frequency: used as default for "Read" and "Read Raw"
|
||||||
#default_frequency: 433920000
|
#Default_frequency: 433920000
|
||||||
|
|
||||||
# Frequencies used for "Read", "Read Raw" and "Frequency Analyzer" + default ones if enabled in add_standard_frequencies
|
# Frequencies used for "Read", "Read Raw" and "Frequency Analyzer" + default ones if enabled in add_standard_frequencies
|
||||||
frequency: 302757000
|
Frequency: 302757000
|
||||||
frequency: 312000000
|
Frequency: 312000000
|
||||||
frequency: 312100000
|
Frequency: 312100000
|
||||||
frequency: 313850000
|
Frequency: 313850000
|
||||||
frequency: 314000000
|
Frequency: 314000000
|
||||||
frequency: 314350000
|
Frequency: 314350000
|
||||||
frequency: 345000000
|
Frequency: 345000000
|
||||||
frequency: 348000000
|
Frequency: 348000000
|
||||||
frequency: 387000000
|
Frequency: 387000000
|
||||||
frequency: 433220000
|
Frequency: 433220000
|
||||||
frequency: 433889000
|
Frequency: 433889000
|
||||||
frequency: 464000000
|
Frequency: 464000000
|
||||||
frequency: 779000000
|
Frequency: 779000000
|
||||||
frequency: 928000000
|
Frequency: 928000000
|
||||||
|
|
||||||
# Frequencies used for hopping mode (keep this list small or flipper will miss signal) + default ones if enabled in add_standard_frequencies
|
# Frequencies used for hopping mode (keep this list small or flipper will miss signal) + default ones if enabled in add_standard_frequencies
|
||||||
#hopper_frequency: 300000000
|
#Hopper_frequency: 300000000
|
||||||
hopper_frequency: 345000000
|
Hopper_frequency: 345000000
|
||||||
hopper_frequency: 434420000
|
Hopper_frequency: 434420000
|
||||||
|
|
||||||
|
# Custom preset
|
||||||
|
# format for CC1101 "Custom_preset_data:" XX YY XX YY .. 00 00 ZZ ZZ ZZ ZZ ZZ ZZ ZZ ZZ, where: XX-register, YY - register data, 00 00 - end load register, ZZ - 8 byte Pa table register
|
||||||
|
|
||||||
|
#Custom_preset_name: AM_1
|
||||||
|
#Custom_preset_module: CC1101
|
||||||
|
#Custom_preset_data: 02 0D 03 07 08 32 0B 06 14 00 13 00 12 30 11 32 10 17 18 18 19 18 1D 91 1C 00 1B 07 20 FB 22 11 21 B6 00 00 00 C0 00 00 00 00 00 00
|
||||||
|
|
||||||
|
#Custom_preset_name: AM_2
|
||||||
|
#Custom_preset_module: CC1101
|
||||||
|
#Custom_preset_data: 02 0D 03 07 08 32 0B 06 14 00 13 00 12 30 11 32 10 17 18 18 19 18 1D 91 1C 00 1B 07 20 FB 22 11 21 B6 00 00 00 C0 00 00 00 00 00 00
|
||||||
|
|||||||
@@ -186,6 +186,7 @@ fwelf = fwenv["FW_ELF"] = fwenv.Program(
|
|||||||
"subghz",
|
"subghz",
|
||||||
"flipperformat",
|
"flipperformat",
|
||||||
"toolbox",
|
"toolbox",
|
||||||
|
"nfc",
|
||||||
"microtar",
|
"microtar",
|
||||||
"usb_stm32",
|
"usb_stm32",
|
||||||
"st25rfal002",
|
"st25rfal002",
|
||||||
|
|||||||
@@ -100,22 +100,24 @@ void furi_hal_subghz_dump_state() {
|
|||||||
|
|
||||||
void furi_hal_subghz_load_preset(FuriHalSubGhzPreset preset) {
|
void furi_hal_subghz_load_preset(FuriHalSubGhzPreset preset) {
|
||||||
if(preset == FuriHalSubGhzPresetOok650Async) {
|
if(preset == FuriHalSubGhzPresetOok650Async) {
|
||||||
furi_hal_subghz_load_registers(furi_hal_subghz_preset_ook_650khz_async_regs);
|
furi_hal_subghz_load_registers((uint8_t*)furi_hal_subghz_preset_ook_650khz_async_regs);
|
||||||
furi_hal_subghz_load_patable(furi_hal_subghz_preset_ook_async_patable);
|
furi_hal_subghz_load_patable(furi_hal_subghz_preset_ook_async_patable);
|
||||||
} else if(preset == FuriHalSubGhzPresetOok270Async) {
|
} else if(preset == FuriHalSubGhzPresetOok270Async) {
|
||||||
furi_hal_subghz_load_registers(furi_hal_subghz_preset_ook_270khz_async_regs);
|
furi_hal_subghz_load_registers((uint8_t*)furi_hal_subghz_preset_ook_270khz_async_regs);
|
||||||
furi_hal_subghz_load_patable(furi_hal_subghz_preset_ook_async_patable);
|
furi_hal_subghz_load_patable(furi_hal_subghz_preset_ook_async_patable);
|
||||||
} else if(preset == FuriHalSubGhzPreset2FSKDev238Async) {
|
} else if(preset == FuriHalSubGhzPreset2FSKDev238Async) {
|
||||||
furi_hal_subghz_load_registers(furi_hal_subghz_preset_2fsk_dev2_38khz_async_regs);
|
furi_hal_subghz_load_registers(
|
||||||
|
(uint8_t*)furi_hal_subghz_preset_2fsk_dev2_38khz_async_regs);
|
||||||
furi_hal_subghz_load_patable(furi_hal_subghz_preset_2fsk_async_patable);
|
furi_hal_subghz_load_patable(furi_hal_subghz_preset_2fsk_async_patable);
|
||||||
} else if(preset == FuriHalSubGhzPreset2FSKDev476Async) {
|
} else if(preset == FuriHalSubGhzPreset2FSKDev476Async) {
|
||||||
furi_hal_subghz_load_registers(furi_hal_subghz_preset_2fsk_dev47_6khz_async_regs);
|
furi_hal_subghz_load_registers(
|
||||||
|
(uint8_t*)furi_hal_subghz_preset_2fsk_dev47_6khz_async_regs);
|
||||||
furi_hal_subghz_load_patable(furi_hal_subghz_preset_2fsk_async_patable);
|
furi_hal_subghz_load_patable(furi_hal_subghz_preset_2fsk_async_patable);
|
||||||
} else if(preset == FuriHalSubGhzPresetMSK99_97KbAsync) {
|
} else if(preset == FuriHalSubGhzPresetMSK99_97KbAsync) {
|
||||||
furi_hal_subghz_load_registers(furi_hal_subghz_preset_msk_99_97kb_async_regs);
|
furi_hal_subghz_load_registers((uint8_t*)furi_hal_subghz_preset_msk_99_97kb_async_regs);
|
||||||
furi_hal_subghz_load_patable(furi_hal_subghz_preset_msk_async_patable);
|
furi_hal_subghz_load_patable(furi_hal_subghz_preset_msk_async_patable);
|
||||||
} else if(preset == FuriHalSubGhzPresetGFSK9_99KbAsync) {
|
} else if(preset == FuriHalSubGhzPresetGFSK9_99KbAsync) {
|
||||||
furi_hal_subghz_load_registers(furi_hal_subghz_preset_gfsk_9_99kb_async_regs);
|
furi_hal_subghz_load_registers((uint8_t*)furi_hal_subghz_preset_gfsk_9_99kb_async_regs);
|
||||||
furi_hal_subghz_load_patable(furi_hal_subghz_preset_gfsk_async_patable);
|
furi_hal_subghz_load_patable(furi_hal_subghz_preset_gfsk_async_patable);
|
||||||
} else {
|
} else {
|
||||||
furi_crash("SubGhz: Missing config.");
|
furi_crash("SubGhz: Missing config.");
|
||||||
@@ -123,13 +125,44 @@ void furi_hal_subghz_load_preset(FuriHalSubGhzPreset preset) {
|
|||||||
furi_hal_subghz.preset = preset;
|
furi_hal_subghz.preset = preset;
|
||||||
}
|
}
|
||||||
|
|
||||||
void furi_hal_subghz_load_registers(const uint8_t data[][2]) {
|
void furi_hal_subghz_load_custom_preset(uint8_t* preset_data) {
|
||||||
|
//load config
|
||||||
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
|
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
|
||||||
cc1101_reset(&furi_hal_spi_bus_handle_subghz);
|
cc1101_reset(&furi_hal_spi_bus_handle_subghz);
|
||||||
uint32_t i = 0;
|
uint32_t i = 0;
|
||||||
while(data[i][0]) {
|
uint8_t pa[8] = {0};
|
||||||
cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, data[i][0], data[i][1]);
|
while(preset_data[i]) {
|
||||||
i++;
|
cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, preset_data[i], preset_data[i + 1]);
|
||||||
|
i += 2;
|
||||||
|
}
|
||||||
|
furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
|
||||||
|
|
||||||
|
//load pa table
|
||||||
|
memcpy(&pa[0], &preset_data[i + 2], 8);
|
||||||
|
furi_hal_subghz_load_patable(pa);
|
||||||
|
furi_hal_subghz.preset = FuriHalSubGhzPresetCustom;
|
||||||
|
|
||||||
|
//show debug
|
||||||
|
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
|
||||||
|
i = 0;
|
||||||
|
FURI_LOG_D(TAG, "Loading custom preset");
|
||||||
|
while(preset_data[i]) {
|
||||||
|
FURI_LOG_D(TAG, "Reg[%lu]: %02X=%02X", i, preset_data[i], preset_data[i + 1]);
|
||||||
|
i += 2;
|
||||||
|
}
|
||||||
|
for(uint8_t y = i; y < i + 10; y++) {
|
||||||
|
FURI_LOG_D(TAG, "PA[%lu]: %02X", y, preset_data[y]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void furi_hal_subghz_load_registers(uint8_t* data) {
|
||||||
|
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
|
||||||
|
cc1101_reset(&furi_hal_spi_bus_handle_subghz);
|
||||||
|
uint32_t i = 0;
|
||||||
|
while(data[i]) {
|
||||||
|
cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, data[i], data[i + 1]);
|
||||||
|
i += 2;
|
||||||
}
|
}
|
||||||
furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
|
furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include <lib/nfc_protocols/nfca.h>
|
#include <lib/nfc/protocols/nfca.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|||||||
@@ -22,7 +22,8 @@ typedef enum {
|
|||||||
FuriHalSubGhzPreset2FSKDev238Async, /**< FM, deviation 2.380371 kHz, asynchronous */
|
FuriHalSubGhzPreset2FSKDev238Async, /**< FM, deviation 2.380371 kHz, asynchronous */
|
||||||
FuriHalSubGhzPreset2FSKDev476Async, /**< FM, deviation 47.60742 kHz, asynchronous */
|
FuriHalSubGhzPreset2FSKDev476Async, /**< FM, deviation 47.60742 kHz, asynchronous */
|
||||||
FuriHalSubGhzPresetMSK99_97KbAsync, /**< MSK, deviation 47.60742 kHz, 99.97Kb/s, asynchronous */
|
FuriHalSubGhzPresetMSK99_97KbAsync, /**< MSK, deviation 47.60742 kHz, 99.97Kb/s, asynchronous */
|
||||||
FuriHalSubGhzPresetGFSK9_99KbAsync /**< GFSK, deviation 19.042969 kHz, 9.996Kb/s, asynchronous */
|
FuriHalSubGhzPresetGFSK9_99KbAsync, /**< GFSK, deviation 19.042969 kHz, 9.996Kb/s, asynchronous */
|
||||||
|
FuriHalSubGhzPresetCustom, /**Custom Preset*/
|
||||||
} FuriHalSubGhzPreset;
|
} FuriHalSubGhzPreset;
|
||||||
|
|
||||||
/** Switchable Radio Paths */
|
/** Switchable Radio Paths */
|
||||||
@@ -74,11 +75,17 @@ void furi_hal_subghz_dump_state();
|
|||||||
*/
|
*/
|
||||||
void furi_hal_subghz_load_preset(FuriHalSubGhzPreset preset);
|
void furi_hal_subghz_load_preset(FuriHalSubGhzPreset preset);
|
||||||
|
|
||||||
|
/** Load custom registers from preset
|
||||||
|
*
|
||||||
|
* @param preset_data registers to load
|
||||||
|
*/
|
||||||
|
void furi_hal_subghz_load_custom_preset(uint8_t* preset_data);
|
||||||
|
|
||||||
/** Load registers
|
/** Load registers
|
||||||
*
|
*
|
||||||
* @param data Registers data
|
* @param data Registers data
|
||||||
*/
|
*/
|
||||||
void furi_hal_subghz_load_registers(const uint8_t data[][2]);
|
void furi_hal_subghz_load_registers(uint8_t* data);
|
||||||
|
|
||||||
/** Load PATABLE
|
/** Load PATABLE
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -88,6 +88,10 @@ extern "C" {
|
|||||||
#define FURI_BIT(x, n) (((x) >> (n)) & 1)
|
#define FURI_BIT(x, n) (((x) >> (n)) & 1)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef FURI_BIT_SET
|
||||||
|
#define FURI_BIT_SET(x, n) ((x) |= (1 << (n)))
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef FURI_IS_IRQ_MASKED
|
#ifndef FURI_IS_IRQ_MASKED
|
||||||
#define FURI_IS_IRQ_MASKED() (__get_PRIMASK() != 0U)
|
#define FURI_IS_IRQ_MASKED() (__get_PRIMASK() != 0U)
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ libs = env.BuildModules(
|
|||||||
"infrared",
|
"infrared",
|
||||||
"littlefs",
|
"littlefs",
|
||||||
"subghz",
|
"subghz",
|
||||||
|
"nfc",
|
||||||
"appframe",
|
"appframe",
|
||||||
"misc",
|
"misc",
|
||||||
"mbedtls",
|
"mbedtls",
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ env.Append(
|
|||||||
"#/lib/heatshrink",
|
"#/lib/heatshrink",
|
||||||
"#/lib/micro-ecc",
|
"#/lib/micro-ecc",
|
||||||
"#/lib/nanopb",
|
"#/lib/nanopb",
|
||||||
"#/lib/nfc_protocols",
|
|
||||||
"#/lib/u8g2",
|
"#/lib/u8g2",
|
||||||
],
|
],
|
||||||
CPPDEFINES=[
|
CPPDEFINES=[
|
||||||
@@ -24,7 +23,6 @@ sources = []
|
|||||||
libs_recurse = [
|
libs_recurse = [
|
||||||
"digital_signal",
|
"digital_signal",
|
||||||
"micro-ecc",
|
"micro-ecc",
|
||||||
"nfc_protocols",
|
|
||||||
"one_wire",
|
"one_wire",
|
||||||
"u8g2",
|
"u8g2",
|
||||||
"update_util",
|
"update_util",
|
||||||
|
|||||||
16
lib/nfc/SConscript
Normal file
16
lib/nfc/SConscript
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
Import("env")
|
||||||
|
|
||||||
|
env.Append(
|
||||||
|
CPPPATH=[
|
||||||
|
"#/lib/nfc",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
libenv = env.Clone(FW_LIB_NAME="nfc")
|
||||||
|
libenv.ApplyLibFlags()
|
||||||
|
|
||||||
|
sources = libenv.GlobRecursive("*.c*")
|
||||||
|
|
||||||
|
lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources)
|
||||||
|
libenv.Install("${LIB_DIST_DIR}", lib)
|
||||||
|
Return("lib")
|
||||||
148
lib/nfc/helpers/mf_classic_dict.c
Normal file
148
lib/nfc/helpers/mf_classic_dict.c
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
#include "mf_classic_dict.h"
|
||||||
|
|
||||||
|
#include <lib/toolbox/args.h>
|
||||||
|
#include <lib/flipper_format/flipper_format.h>
|
||||||
|
|
||||||
|
#define MF_CLASSIC_DICT_FLIPPER_PATH EXT_PATH("nfc/assets/mf_classic_dict.nfc")
|
||||||
|
#define MF_CLASSIC_DICT_USER_PATH EXT_PATH("nfc/assets/mf_classic_dict_user.nfc")
|
||||||
|
|
||||||
|
#define TAG "MfClassicDict"
|
||||||
|
|
||||||
|
#define NFC_MF_CLASSIC_KEY_LEN (13)
|
||||||
|
|
||||||
|
struct MfClassicDict {
|
||||||
|
Stream* stream;
|
||||||
|
uint32_t total_keys;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool mf_classic_dict_check_presence(MfClassicDictType dict_type) {
|
||||||
|
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||||
|
|
||||||
|
bool dict_present = false;
|
||||||
|
if(dict_type == MfClassicDictTypeFlipper) {
|
||||||
|
dict_present = storage_common_stat(storage, MF_CLASSIC_DICT_FLIPPER_PATH, NULL) == FSE_OK;
|
||||||
|
} else if(dict_type == MfClassicDictTypeUser) {
|
||||||
|
dict_present = storage_common_stat(storage, MF_CLASSIC_DICT_USER_PATH, NULL) == FSE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
furi_record_close(RECORD_STORAGE);
|
||||||
|
|
||||||
|
return dict_present;
|
||||||
|
}
|
||||||
|
|
||||||
|
MfClassicDict* mf_classic_dict_alloc(MfClassicDictType dict_type) {
|
||||||
|
MfClassicDict* dict = malloc(sizeof(MfClassicDict));
|
||||||
|
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||||
|
dict->stream = buffered_file_stream_alloc(storage);
|
||||||
|
furi_record_close(RECORD_STORAGE);
|
||||||
|
|
||||||
|
bool dict_loaded = false;
|
||||||
|
do {
|
||||||
|
if(dict_type == MfClassicDictTypeFlipper) {
|
||||||
|
if(!buffered_file_stream_open(
|
||||||
|
dict->stream, MF_CLASSIC_DICT_FLIPPER_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) {
|
||||||
|
buffered_file_stream_close(dict->stream);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if(dict_type == MfClassicDictTypeUser) {
|
||||||
|
if(!buffered_file_stream_open(
|
||||||
|
dict->stream, MF_CLASSIC_DICT_USER_PATH, FSAM_READ_WRITE, FSOM_OPEN_ALWAYS)) {
|
||||||
|
buffered_file_stream_close(dict->stream);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read total amount of keys
|
||||||
|
string_t next_line;
|
||||||
|
string_init(next_line);
|
||||||
|
while(true) {
|
||||||
|
if(!stream_read_line(dict->stream, next_line)) break;
|
||||||
|
if(string_get_char(next_line, 0) == '#') continue;
|
||||||
|
if(string_size(next_line) != NFC_MF_CLASSIC_KEY_LEN) continue;
|
||||||
|
dict->total_keys++;
|
||||||
|
}
|
||||||
|
string_clear(next_line);
|
||||||
|
stream_rewind(dict->stream);
|
||||||
|
|
||||||
|
dict_loaded = true;
|
||||||
|
FURI_LOG_I(TAG, "Loaded dictionary with %d keys", dict->total_keys);
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
if(!dict_loaded) {
|
||||||
|
buffered_file_stream_close(dict->stream);
|
||||||
|
free(dict);
|
||||||
|
dict = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dict;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mf_classic_dict_free(MfClassicDict* dict) {
|
||||||
|
furi_assert(dict);
|
||||||
|
furi_assert(dict->stream);
|
||||||
|
|
||||||
|
buffered_file_stream_close(dict->stream);
|
||||||
|
stream_free(dict->stream);
|
||||||
|
free(dict);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t mf_classic_dict_get_total_keys(MfClassicDict* dict) {
|
||||||
|
furi_assert(dict);
|
||||||
|
|
||||||
|
return dict->total_keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mf_classic_dict_get_next_key(MfClassicDict* dict, uint64_t* key) {
|
||||||
|
furi_assert(dict);
|
||||||
|
furi_assert(dict->stream);
|
||||||
|
|
||||||
|
uint8_t key_byte_tmp = 0;
|
||||||
|
string_t next_line;
|
||||||
|
string_init(next_line);
|
||||||
|
|
||||||
|
bool key_read = false;
|
||||||
|
*key = 0ULL;
|
||||||
|
while(!key_read) {
|
||||||
|
if(!stream_read_line(dict->stream, next_line)) break;
|
||||||
|
if(string_get_char(next_line, 0) == '#') continue;
|
||||||
|
if(string_size(next_line) != NFC_MF_CLASSIC_KEY_LEN) continue;
|
||||||
|
for(uint8_t i = 0; i < 12; i += 2) {
|
||||||
|
args_char_to_hex(
|
||||||
|
string_get_char(next_line, i), string_get_char(next_line, i + 1), &key_byte_tmp);
|
||||||
|
*key |= (uint64_t)key_byte_tmp << 8 * (5 - i / 2);
|
||||||
|
}
|
||||||
|
key_read = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
string_clear(next_line);
|
||||||
|
return key_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mf_classic_dict_rewind(MfClassicDict* dict) {
|
||||||
|
furi_assert(dict);
|
||||||
|
furi_assert(dict->stream);
|
||||||
|
|
||||||
|
return stream_rewind(dict->stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mf_classic_dict_add_key(MfClassicDict* dict, uint8_t* key) {
|
||||||
|
furi_assert(dict);
|
||||||
|
furi_assert(dict->stream);
|
||||||
|
|
||||||
|
string_t key_str;
|
||||||
|
string_init(key_str);
|
||||||
|
for(size_t i = 0; i < 6; i++) {
|
||||||
|
string_cat_printf(key_str, "%02X", key[i]);
|
||||||
|
}
|
||||||
|
string_cat_printf(key_str, "\n");
|
||||||
|
|
||||||
|
bool key_added = false;
|
||||||
|
do {
|
||||||
|
if(!stream_seek(dict->stream, 0, StreamOffsetFromEnd)) break;
|
||||||
|
if(!stream_insert_string(dict->stream, key_str)) break;
|
||||||
|
key_added = true;
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
string_clear(key_str);
|
||||||
|
return key_added;
|
||||||
|
}
|
||||||
28
lib/nfc/helpers/mf_classic_dict.h
Normal file
28
lib/nfc/helpers/mf_classic_dict.h
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <storage/storage.h>
|
||||||
|
#include <lib/flipper_format/flipper_format.h>
|
||||||
|
#include <lib/toolbox/stream/file_stream.h>
|
||||||
|
#include <lib/toolbox/stream/buffered_file_stream.h>
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
MfClassicDictTypeUser,
|
||||||
|
MfClassicDictTypeFlipper,
|
||||||
|
} MfClassicDictType;
|
||||||
|
|
||||||
|
typedef struct MfClassicDict MfClassicDict;
|
||||||
|
|
||||||
|
bool mf_classic_dict_check_presence(MfClassicDictType dict_type);
|
||||||
|
|
||||||
|
MfClassicDict* mf_classic_dict_alloc(MfClassicDictType dict_type);
|
||||||
|
|
||||||
|
void mf_classic_dict_free(MfClassicDict* dict);
|
||||||
|
|
||||||
|
uint32_t mf_classic_dict_get_total_keys(MfClassicDict* dict);
|
||||||
|
|
||||||
|
bool mf_classic_dict_get_next_key(MfClassicDict* dict, uint64_t* key);
|
||||||
|
|
||||||
|
bool mf_classic_dict_rewind(MfClassicDict* dict);
|
||||||
|
|
||||||
|
bool mf_classic_dict_add_key(MfClassicDict* dict, uint8_t* key);
|
||||||
@@ -3,20 +3,29 @@
|
|||||||
#include "m-string.h"
|
#include "m-string.h"
|
||||||
#include "nfc_types.h"
|
#include "nfc_types.h"
|
||||||
|
|
||||||
#include <toolbox/path.h>
|
#include <lib/toolbox/path.h>
|
||||||
|
#include <lib/toolbox/hex.h>
|
||||||
|
#include <lib/nfc/protocols/nfc_util.h>
|
||||||
#include <flipper_format/flipper_format.h>
|
#include <flipper_format/flipper_format.h>
|
||||||
|
|
||||||
|
#define NFC_DEVICE_KEYS_FOLDER EXT_PATH("nfc/cache")
|
||||||
|
#define NFC_DEVICE_KEYS_EXTENSION ".keys"
|
||||||
|
|
||||||
static const char* nfc_file_header = "Flipper NFC device";
|
static const char* nfc_file_header = "Flipper NFC device";
|
||||||
static const uint32_t nfc_file_version = 2;
|
static const uint32_t nfc_file_version = 2;
|
||||||
|
|
||||||
|
static const char* nfc_keys_file_header = "Flipper NFC keys";
|
||||||
|
static const uint32_t nfc_keys_file_version = 1;
|
||||||
|
|
||||||
// Protocols format versions
|
// Protocols format versions
|
||||||
static const uint32_t nfc_mifare_classic_data_format_version = 1;
|
static const uint32_t nfc_mifare_classic_data_format_version = 2;
|
||||||
|
|
||||||
NfcDevice* nfc_device_alloc() {
|
NfcDevice* nfc_device_alloc() {
|
||||||
NfcDevice* nfc_dev = malloc(sizeof(NfcDevice));
|
NfcDevice* nfc_dev = malloc(sizeof(NfcDevice));
|
||||||
nfc_dev->storage = furi_record_open(RECORD_STORAGE);
|
nfc_dev->storage = furi_record_open(RECORD_STORAGE);
|
||||||
nfc_dev->dialogs = furi_record_open(RECORD_DIALOGS);
|
nfc_dev->dialogs = furi_record_open(RECORD_DIALOGS);
|
||||||
string_init(nfc_dev->load_path);
|
string_init(nfc_dev->load_path);
|
||||||
|
string_init(nfc_dev->dev_data.parsed_data);
|
||||||
return nfc_dev;
|
return nfc_dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,6 +35,7 @@ void nfc_device_free(NfcDevice* nfc_dev) {
|
|||||||
furi_record_close(RECORD_STORAGE);
|
furi_record_close(RECORD_STORAGE);
|
||||||
furi_record_close(RECORD_DIALOGS);
|
furi_record_close(RECORD_DIALOGS);
|
||||||
string_clear(nfc_dev->load_path);
|
string_clear(nfc_dev->load_path);
|
||||||
|
string_clear(nfc_dev->dev_data.parsed_data);
|
||||||
free(nfc_dev);
|
free(nfc_dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -648,6 +658,52 @@ bool nfc_device_load_bank_card_data(FlipperFormat* file, NfcDevice* dev) {
|
|||||||
return parsed;
|
return parsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void nfc_device_write_mifare_classic_block(
|
||||||
|
string_t block_str,
|
||||||
|
MfClassicData* data,
|
||||||
|
uint8_t block_num) {
|
||||||
|
string_reset(block_str);
|
||||||
|
bool is_sec_trailer = mf_classic_is_sector_trailer(block_num);
|
||||||
|
if(is_sec_trailer) {
|
||||||
|
uint8_t sector_num = mf_classic_get_sector_by_block(block_num);
|
||||||
|
MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(data, sector_num);
|
||||||
|
// Write key A
|
||||||
|
for(size_t i = 0; i < sizeof(sec_tr->key_a); i++) {
|
||||||
|
if(mf_classic_is_key_found(data, sector_num, MfClassicKeyA)) {
|
||||||
|
string_cat_printf(block_str, "%02X ", sec_tr->key_a[i]);
|
||||||
|
} else {
|
||||||
|
string_cat_printf(block_str, "?? ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Write Access bytes
|
||||||
|
for(size_t i = 0; i < MF_CLASSIC_ACCESS_BYTES_SIZE; i++) {
|
||||||
|
if(mf_classic_is_block_read(data, block_num)) {
|
||||||
|
string_cat_printf(block_str, "%02X ", sec_tr->access_bits[i]);
|
||||||
|
} else {
|
||||||
|
string_cat_printf(block_str, "?? ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Write key B
|
||||||
|
for(size_t i = 0; i < sizeof(sec_tr->key_b); i++) {
|
||||||
|
if(mf_classic_is_key_found(data, sector_num, MfClassicKeyB)) {
|
||||||
|
string_cat_printf(block_str, "%02X ", sec_tr->key_b[i]);
|
||||||
|
} else {
|
||||||
|
string_cat_printf(block_str, "?? ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Write data block
|
||||||
|
for(size_t i = 0; i < MF_CLASSIC_BLOCK_SIZE; i++) {
|
||||||
|
if(mf_classic_is_block_read(data, block_num)) {
|
||||||
|
string_cat_printf(block_str, "%02X ", data->block[block_num].value[i]);
|
||||||
|
} else {
|
||||||
|
string_cat_printf(block_str, "?? ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
string_strim(block_str);
|
||||||
|
}
|
||||||
|
|
||||||
static bool nfc_device_save_mifare_classic_data(FlipperFormat* file, NfcDevice* dev) {
|
static bool nfc_device_save_mifare_classic_data(FlipperFormat* file, NfcDevice* dev) {
|
||||||
bool saved = false;
|
bool saved = false;
|
||||||
MfClassicData* data = &dev->dev_data.mf_classic_data;
|
MfClassicData* data = &dev->dev_data.mf_classic_data;
|
||||||
@@ -669,23 +725,21 @@ static bool nfc_device_save_mifare_classic_data(FlipperFormat* file, NfcDevice*
|
|||||||
if(!flipper_format_write_uint32(
|
if(!flipper_format_write_uint32(
|
||||||
file, "Data format version", &nfc_mifare_classic_data_format_version, 1))
|
file, "Data format version", &nfc_mifare_classic_data_format_version, 1))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if(!flipper_format_write_comment_cstr(
|
if(!flipper_format_write_comment_cstr(
|
||||||
file, "Key map is the bit mask indicating valid key in each sector"))
|
file, "Mifare Classic blocks, \'??\' means unknown data"))
|
||||||
break;
|
break;
|
||||||
if(!flipper_format_write_hex_uint64(file, "Key A map", &data->key_a_mask, 1)) break;
|
|
||||||
if(!flipper_format_write_hex_uint64(file, "Key B map", &data->key_b_mask, 1)) break;
|
|
||||||
|
|
||||||
if(!flipper_format_write_comment_cstr(file, "Mifare Classic blocks")) break;
|
|
||||||
bool block_saved = true;
|
bool block_saved = true;
|
||||||
|
string_t block_str;
|
||||||
|
string_init(block_str);
|
||||||
for(size_t i = 0; i < blocks; i++) {
|
for(size_t i = 0; i < blocks; i++) {
|
||||||
string_printf(temp_str, "Block %d", i);
|
string_printf(temp_str, "Block %d", i);
|
||||||
if(!flipper_format_write_hex(
|
nfc_device_write_mifare_classic_block(block_str, data, i);
|
||||||
file, string_get_cstr(temp_str), data->block[i].value, 16)) {
|
if(!flipper_format_write_string(file, string_get_cstr(temp_str), block_str)) {
|
||||||
block_saved = false;
|
block_saved = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
string_clear(block_str);
|
||||||
if(!block_saved) break;
|
if(!block_saved) break;
|
||||||
saved = true;
|
saved = true;
|
||||||
} while(false);
|
} while(false);
|
||||||
@@ -694,6 +748,59 @@ static bool nfc_device_save_mifare_classic_data(FlipperFormat* file, NfcDevice*
|
|||||||
return saved;
|
return saved;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void nfc_device_load_mifare_classic_block(
|
||||||
|
string_t block_str,
|
||||||
|
MfClassicData* data,
|
||||||
|
uint8_t block_num) {
|
||||||
|
string_strim(block_str);
|
||||||
|
MfClassicBlock block_tmp = {};
|
||||||
|
bool is_sector_trailer = mf_classic_is_sector_trailer(block_num);
|
||||||
|
uint8_t sector_num = mf_classic_get_sector_by_block(block_num);
|
||||||
|
uint16_t block_unknown_bytes_mask = 0;
|
||||||
|
|
||||||
|
string_strim(block_str);
|
||||||
|
for(size_t i = 0; i < MF_CLASSIC_BLOCK_SIZE; i++) {
|
||||||
|
char hi = string_get_char(block_str, 3 * i);
|
||||||
|
char low = string_get_char(block_str, 3 * i + 1);
|
||||||
|
uint8_t byte = 0;
|
||||||
|
if(hex_chars_to_uint8(hi, low, &byte)) {
|
||||||
|
block_tmp.value[i] = byte;
|
||||||
|
} else {
|
||||||
|
FURI_BIT_SET(block_unknown_bytes_mask, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(block_unknown_bytes_mask == 0xffff) {
|
||||||
|
// All data is unknown, exit
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(is_sector_trailer) {
|
||||||
|
MfClassicSectorTrailer* sec_tr_tmp = (MfClassicSectorTrailer*)&block_tmp;
|
||||||
|
// Load Key A
|
||||||
|
// Key A mask 0b0000000000111111 = 0x003f
|
||||||
|
if((block_unknown_bytes_mask & 0x003f) == 0) {
|
||||||
|
uint64_t key = nfc_util_bytes2num(sec_tr_tmp->key_a, sizeof(sec_tr_tmp->key_a));
|
||||||
|
mf_classic_set_key_found(data, sector_num, MfClassicKeyA, key);
|
||||||
|
}
|
||||||
|
// Load Access Bits
|
||||||
|
// Access bits mask 0b0000001111000000 = 0x03c0
|
||||||
|
if((block_unknown_bytes_mask & 0x03c0) == 0) {
|
||||||
|
mf_classic_set_block_read(data, block_num, &block_tmp);
|
||||||
|
}
|
||||||
|
// Load Key B
|
||||||
|
// Key B mask 0b1111110000000000 = 0xfc00
|
||||||
|
if((block_unknown_bytes_mask & 0xfc00) == 0) {
|
||||||
|
uint64_t key = nfc_util_bytes2num(sec_tr_tmp->key_b, sizeof(sec_tr_tmp->key_b));
|
||||||
|
mf_classic_set_key_found(data, sector_num, MfClassicKeyB, key);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(block_unknown_bytes_mask == 0) {
|
||||||
|
mf_classic_set_block_read(data, block_num, &block_tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static bool nfc_device_load_mifare_classic_data(FlipperFormat* file, NfcDevice* dev) {
|
static bool nfc_device_load_mifare_classic_data(FlipperFormat* file, NfcDevice* dev) {
|
||||||
bool parsed = false;
|
bool parsed = false;
|
||||||
MfClassicData* data = &dev->dev_data.mf_classic_data;
|
MfClassicData* data = &dev->dev_data.mf_classic_data;
|
||||||
@@ -701,6 +808,7 @@ static bool nfc_device_load_mifare_classic_data(FlipperFormat* file, NfcDevice*
|
|||||||
uint32_t data_format_version = 0;
|
uint32_t data_format_version = 0;
|
||||||
string_init(temp_str);
|
string_init(temp_str);
|
||||||
uint16_t data_blocks = 0;
|
uint16_t data_blocks = 0;
|
||||||
|
memset(data, 0, sizeof(MfClassicData));
|
||||||
|
|
||||||
do {
|
do {
|
||||||
// Read Mifare Classic type
|
// Read Mifare Classic type
|
||||||
@@ -715,29 +823,40 @@ static bool nfc_device_load_mifare_classic_data(FlipperFormat* file, NfcDevice*
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool old_format = false;
|
||||||
// Read Mifare Classic format version
|
// Read Mifare Classic format version
|
||||||
if(!flipper_format_read_uint32(file, "Data format version", &data_format_version, 1)) {
|
if(!flipper_format_read_uint32(file, "Data format version", &data_format_version, 1)) {
|
||||||
// Load unread sectors with zero keys access for backward compatability
|
// Load unread sectors with zero keys access for backward compatability
|
||||||
if(!flipper_format_rewind(file)) break;
|
if(!flipper_format_rewind(file)) break;
|
||||||
data->key_a_mask = 0xffffffffffffffff;
|
old_format = true;
|
||||||
data->key_b_mask = 0xffffffffffffffff;
|
|
||||||
} else {
|
} else {
|
||||||
if(data_format_version != nfc_mifare_classic_data_format_version) break;
|
if(data_format_version < nfc_mifare_classic_data_format_version) {
|
||||||
if(!flipper_format_read_hex_uint64(file, "Key A map", &data->key_a_mask, 1)) break;
|
old_format = true;
|
||||||
if(!flipper_format_read_hex_uint64(file, "Key B map", &data->key_b_mask, 1)) break;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read Mifare Classic blocks
|
// Read Mifare Classic blocks
|
||||||
bool block_read = true;
|
bool block_read = true;
|
||||||
|
string_t block_str;
|
||||||
|
string_init(block_str);
|
||||||
for(size_t i = 0; i < data_blocks; i++) {
|
for(size_t i = 0; i < data_blocks; i++) {
|
||||||
string_printf(temp_str, "Block %d", i);
|
string_printf(temp_str, "Block %d", i);
|
||||||
if(!flipper_format_read_hex(
|
if(!flipper_format_read_string(file, string_get_cstr(temp_str), block_str)) {
|
||||||
file, string_get_cstr(temp_str), data->block[i].value, 16)) {
|
|
||||||
block_read = false;
|
block_read = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
nfc_device_load_mifare_classic_block(block_str, data, i);
|
||||||
}
|
}
|
||||||
|
string_clear(block_str);
|
||||||
if(!block_read) break;
|
if(!block_read) break;
|
||||||
|
|
||||||
|
// Set keys and blocks as unknown for backward compatibility
|
||||||
|
if(old_format) {
|
||||||
|
data->key_a_mask = 0ULL;
|
||||||
|
data->key_b_mask = 0ULL;
|
||||||
|
memset(data->block_read_mask, 0, sizeof(data->block_read_mask));
|
||||||
|
}
|
||||||
|
|
||||||
parsed = true;
|
parsed = true;
|
||||||
} while(false);
|
} while(false);
|
||||||
|
|
||||||
@@ -745,6 +864,113 @@ static bool nfc_device_load_mifare_classic_data(FlipperFormat* file, NfcDevice*
|
|||||||
return parsed;
|
return parsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void nfc_device_get_key_cache_file_path(NfcDevice* dev, string_t file_path) {
|
||||||
|
uint8_t* uid = dev->dev_data.nfc_data.uid;
|
||||||
|
uint8_t uid_len = dev->dev_data.nfc_data.uid_len;
|
||||||
|
string_set_str(file_path, NFC_DEVICE_KEYS_FOLDER "/");
|
||||||
|
for(size_t i = 0; i < uid_len; i++) {
|
||||||
|
string_cat_printf(file_path, "%02X", uid[i]);
|
||||||
|
}
|
||||||
|
string_cat_printf(file_path, NFC_DEVICE_KEYS_EXTENSION);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool nfc_device_save_mifare_classic_keys(NfcDevice* dev) {
|
||||||
|
FlipperFormat* file = flipper_format_file_alloc(dev->storage);
|
||||||
|
MfClassicData* data = &dev->dev_data.mf_classic_data;
|
||||||
|
string_t temp_str;
|
||||||
|
string_init(temp_str);
|
||||||
|
|
||||||
|
nfc_device_get_key_cache_file_path(dev, temp_str);
|
||||||
|
bool save_success = false;
|
||||||
|
do {
|
||||||
|
if(!storage_simply_mkdir(dev->storage, NFC_DEVICE_KEYS_FOLDER)) break;
|
||||||
|
if(!storage_simply_remove(dev->storage, string_get_cstr(temp_str))) break;
|
||||||
|
if(!flipper_format_file_open_always(file, string_get_cstr(temp_str))) break;
|
||||||
|
if(!flipper_format_write_header_cstr(file, nfc_keys_file_header, nfc_keys_file_version))
|
||||||
|
break;
|
||||||
|
if(data->type == MfClassicType1k) {
|
||||||
|
if(!flipper_format_write_string_cstr(file, "Mifare Classic type", "1K")) break;
|
||||||
|
} else if(data->type == MfClassicType4k) {
|
||||||
|
if(!flipper_format_write_string_cstr(file, "Mifare Classic type", "4K")) break;
|
||||||
|
}
|
||||||
|
if(!flipper_format_write_hex_uint64(file, "Key A map", &data->key_a_mask, 1)) break;
|
||||||
|
if(!flipper_format_write_hex_uint64(file, "Key B map", &data->key_b_mask, 1)) break;
|
||||||
|
uint8_t sector_num = mf_classic_get_total_sectors_num(data->type);
|
||||||
|
bool key_save_success = true;
|
||||||
|
for(size_t i = 0; (i < sector_num) && (key_save_success); i++) {
|
||||||
|
MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(data, i);
|
||||||
|
if(FURI_BIT(data->key_a_mask, i)) {
|
||||||
|
string_printf(temp_str, "Key A sector %d", i);
|
||||||
|
key_save_success =
|
||||||
|
flipper_format_write_hex(file, string_get_cstr(temp_str), sec_tr->key_a, 6);
|
||||||
|
}
|
||||||
|
if(!key_save_success) break;
|
||||||
|
if(FURI_BIT(data->key_a_mask, i)) {
|
||||||
|
string_printf(temp_str, "Key B sector %d", i);
|
||||||
|
key_save_success =
|
||||||
|
flipper_format_write_hex(file, string_get_cstr(temp_str), sec_tr->key_b, 6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
save_success = key_save_success;
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
flipper_format_free(file);
|
||||||
|
string_clear(temp_str);
|
||||||
|
return save_success;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nfc_device_load_key_cache(NfcDevice* dev) {
|
||||||
|
furi_assert(dev);
|
||||||
|
string_t temp_str;
|
||||||
|
string_init(temp_str);
|
||||||
|
|
||||||
|
MfClassicData* data = &dev->dev_data.mf_classic_data;
|
||||||
|
nfc_device_get_key_cache_file_path(dev, temp_str);
|
||||||
|
FlipperFormat* file = flipper_format_file_alloc(dev->storage);
|
||||||
|
|
||||||
|
bool load_success = false;
|
||||||
|
do {
|
||||||
|
if(storage_common_stat(dev->storage, string_get_cstr(temp_str), NULL) != FSE_OK) break;
|
||||||
|
if(!flipper_format_file_open_existing(file, string_get_cstr(temp_str))) break;
|
||||||
|
uint32_t version = 0;
|
||||||
|
if(!flipper_format_read_header(file, temp_str, &version)) break;
|
||||||
|
if(string_cmp_str(temp_str, nfc_keys_file_header)) break;
|
||||||
|
if(version != nfc_keys_file_version) break;
|
||||||
|
if(!flipper_format_read_string(file, "Mifare Classic type", temp_str)) break;
|
||||||
|
if(!string_cmp_str(temp_str, "1K")) {
|
||||||
|
data->type = MfClassicType1k;
|
||||||
|
} else if(!string_cmp_str(temp_str, "4K")) {
|
||||||
|
data->type = MfClassicType4k;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(!flipper_format_read_hex_uint64(file, "Key A map", &data->key_a_mask, 1)) break;
|
||||||
|
if(!flipper_format_read_hex_uint64(file, "Key B map", &data->key_b_mask, 1)) break;
|
||||||
|
uint8_t sectors = mf_classic_get_total_sectors_num(data->type);
|
||||||
|
bool key_read_success = true;
|
||||||
|
for(size_t i = 0; (i < sectors) && (key_read_success); i++) {
|
||||||
|
MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(data, i);
|
||||||
|
if(FURI_BIT(data->key_a_mask, i)) {
|
||||||
|
string_printf(temp_str, "Key A sector %d", i);
|
||||||
|
key_read_success =
|
||||||
|
flipper_format_read_hex(file, string_get_cstr(temp_str), sec_tr->key_a, 6);
|
||||||
|
}
|
||||||
|
if(!key_read_success) break;
|
||||||
|
if(FURI_BIT(data->key_b_mask, i)) {
|
||||||
|
string_printf(temp_str, "Key B sector %d", i);
|
||||||
|
key_read_success =
|
||||||
|
flipper_format_read_hex(file, string_get_cstr(temp_str), sec_tr->key_b, 6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
load_success = key_read_success;
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
string_clear(temp_str);
|
||||||
|
flipper_format_free(file);
|
||||||
|
|
||||||
|
return load_success;
|
||||||
|
}
|
||||||
|
|
||||||
void nfc_device_set_name(NfcDevice* dev, const char* name) {
|
void nfc_device_set_name(NfcDevice* dev, const char* name) {
|
||||||
furi_assert(dev);
|
furi_assert(dev);
|
||||||
|
|
||||||
@@ -815,7 +1041,10 @@ static bool nfc_device_save_file(
|
|||||||
} else if(dev->format == NfcDeviceSaveFormatBankCard) {
|
} else if(dev->format == NfcDeviceSaveFormatBankCard) {
|
||||||
if(!nfc_device_save_bank_card_data(file, dev)) break;
|
if(!nfc_device_save_bank_card_data(file, dev)) break;
|
||||||
} else if(dev->format == NfcDeviceSaveFormatMifareClassic) {
|
} else if(dev->format == NfcDeviceSaveFormatMifareClassic) {
|
||||||
|
// Save data
|
||||||
if(!nfc_device_save_mifare_classic_data(file, dev)) break;
|
if(!nfc_device_save_mifare_classic_data(file, dev)) break;
|
||||||
|
// Save keys cache
|
||||||
|
if(!nfc_device_save_mifare_classic_keys(dev)) break;
|
||||||
}
|
}
|
||||||
saved = true;
|
saved = true;
|
||||||
} while(0);
|
} while(0);
|
||||||
@@ -954,14 +1183,22 @@ bool nfc_file_select(NfcDevice* dev) {
|
|||||||
void nfc_device_data_clear(NfcDeviceData* dev_data) {
|
void nfc_device_data_clear(NfcDeviceData* dev_data) {
|
||||||
if(dev_data->protocol == NfcDeviceProtocolMifareDesfire) {
|
if(dev_data->protocol == NfcDeviceProtocolMifareDesfire) {
|
||||||
mf_df_clear(&dev_data->mf_df_data);
|
mf_df_clear(&dev_data->mf_df_data);
|
||||||
|
} else if(dev_data->protocol == NfcDeviceProtocolMifareClassic) {
|
||||||
|
memset(&dev_data->mf_classic_data, 0, sizeof(MfClassicData));
|
||||||
|
} else if(dev_data->protocol == NfcDeviceProtocolMifareUl) {
|
||||||
|
memset(&dev_data->mf_ul_data, 0, sizeof(MfUltralightData));
|
||||||
|
} else if(dev_data->protocol == NfcDeviceProtocolEMV) {
|
||||||
|
memset(&dev_data->emv_data, 0, sizeof(EmvData));
|
||||||
}
|
}
|
||||||
|
memset(&dev_data->nfc_data, 0, sizeof(FuriHalNfcDevData));
|
||||||
|
dev_data->protocol = NfcDeviceProtocolUnknown;
|
||||||
|
string_reset(dev_data->parsed_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_device_clear(NfcDevice* dev) {
|
void nfc_device_clear(NfcDevice* dev) {
|
||||||
furi_assert(dev);
|
furi_assert(dev);
|
||||||
|
|
||||||
nfc_device_data_clear(&dev->dev_data);
|
nfc_device_data_clear(&dev->dev_data);
|
||||||
memset(&dev->dev_data, 0, sizeof(dev->dev_data));
|
|
||||||
dev->format = NfcDeviceSaveFormatUid;
|
dev->format = NfcDeviceSaveFormatUid;
|
||||||
string_reset(dev->load_path);
|
string_reset(dev->load_path);
|
||||||
}
|
}
|
||||||
@@ -6,10 +6,10 @@
|
|||||||
#include <dialogs/dialogs.h>
|
#include <dialogs/dialogs.h>
|
||||||
|
|
||||||
#include <furi_hal_nfc.h>
|
#include <furi_hal_nfc.h>
|
||||||
#include <lib/nfc_protocols/emv.h>
|
#include <lib/nfc/protocols/emv.h>
|
||||||
#include <lib/nfc_protocols/mifare_ultralight.h>
|
#include <lib/nfc/protocols/mifare_ultralight.h>
|
||||||
#include <lib/nfc_protocols/mifare_classic.h>
|
#include <lib/nfc/protocols/mifare_classic.h>
|
||||||
#include <lib/nfc_protocols/mifare_desfire.h>
|
#include <lib/nfc/protocols/mifare_desfire.h>
|
||||||
|
|
||||||
#define NFC_DEV_NAME_MAX_LEN 22
|
#define NFC_DEV_NAME_MAX_LEN 22
|
||||||
#define NFC_READER_DATA_MAX_SIZE 64
|
#define NFC_READER_DATA_MAX_SIZE 64
|
||||||
@@ -51,6 +51,7 @@ typedef struct {
|
|||||||
MfClassicData mf_classic_data;
|
MfClassicData mf_classic_data;
|
||||||
MifareDesfireData mf_df_data;
|
MifareDesfireData mf_df_data;
|
||||||
};
|
};
|
||||||
|
string_t parsed_data;
|
||||||
} NfcDeviceData;
|
} NfcDeviceData;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -78,6 +79,8 @@ bool nfc_device_save_shadow(NfcDevice* dev, const char* dev_name);
|
|||||||
|
|
||||||
bool nfc_device_load(NfcDevice* dev, const char* file_path, bool show_dialog);
|
bool nfc_device_load(NfcDevice* dev, const char* file_path, bool show_dialog);
|
||||||
|
|
||||||
|
bool nfc_device_load_key_cache(NfcDevice* dev);
|
||||||
|
|
||||||
bool nfc_file_select(NfcDevice* dev);
|
bool nfc_file_select(NfcDevice* dev);
|
||||||
|
|
||||||
void nfc_device_data_clear(NfcDeviceData* dev);
|
void nfc_device_data_clear(NfcDeviceData* dev);
|
||||||
510
lib/nfc/nfc_worker.c
Normal file
510
lib/nfc/nfc_worker.c
Normal file
@@ -0,0 +1,510 @@
|
|||||||
|
#include "nfc_worker_i.h"
|
||||||
|
#include <furi_hal.h>
|
||||||
|
|
||||||
|
#include <platform.h>
|
||||||
|
#include "parsers/nfc_supported_card.h"
|
||||||
|
|
||||||
|
#define TAG "NfcWorker"
|
||||||
|
|
||||||
|
/***************************** NFC Worker API *******************************/
|
||||||
|
|
||||||
|
NfcWorker* nfc_worker_alloc() {
|
||||||
|
NfcWorker* nfc_worker = malloc(sizeof(NfcWorker));
|
||||||
|
|
||||||
|
// Worker thread attributes
|
||||||
|
nfc_worker->thread = furi_thread_alloc();
|
||||||
|
furi_thread_set_name(nfc_worker->thread, "NfcWorker");
|
||||||
|
furi_thread_set_stack_size(nfc_worker->thread, 8192);
|
||||||
|
furi_thread_set_callback(nfc_worker->thread, nfc_worker_task);
|
||||||
|
furi_thread_set_context(nfc_worker->thread, nfc_worker);
|
||||||
|
|
||||||
|
nfc_worker->callback = NULL;
|
||||||
|
nfc_worker->context = NULL;
|
||||||
|
nfc_worker->storage = furi_record_open(RECORD_STORAGE);
|
||||||
|
|
||||||
|
// Initialize rfal
|
||||||
|
while(furi_hal_nfc_is_busy()) {
|
||||||
|
furi_delay_ms(10);
|
||||||
|
}
|
||||||
|
nfc_worker_change_state(nfc_worker, NfcWorkerStateReady);
|
||||||
|
|
||||||
|
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
|
||||||
|
nfc_worker->debug_pcap_worker = nfc_debug_pcap_alloc(nfc_worker->storage);
|
||||||
|
}
|
||||||
|
|
||||||
|
return nfc_worker;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_worker_free(NfcWorker* nfc_worker) {
|
||||||
|
furi_assert(nfc_worker);
|
||||||
|
|
||||||
|
furi_thread_free(nfc_worker->thread);
|
||||||
|
|
||||||
|
furi_record_close(RECORD_STORAGE);
|
||||||
|
|
||||||
|
if(nfc_worker->debug_pcap_worker) nfc_debug_pcap_free(nfc_worker->debug_pcap_worker);
|
||||||
|
|
||||||
|
free(nfc_worker);
|
||||||
|
}
|
||||||
|
|
||||||
|
NfcWorkerState nfc_worker_get_state(NfcWorker* nfc_worker) {
|
||||||
|
return nfc_worker->state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_worker_start(
|
||||||
|
NfcWorker* nfc_worker,
|
||||||
|
NfcWorkerState state,
|
||||||
|
NfcDeviceData* dev_data,
|
||||||
|
NfcWorkerCallback callback,
|
||||||
|
void* context) {
|
||||||
|
furi_assert(nfc_worker);
|
||||||
|
furi_assert(dev_data);
|
||||||
|
while(furi_hal_nfc_is_busy()) {
|
||||||
|
furi_delay_ms(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
nfc_worker->callback = callback;
|
||||||
|
nfc_worker->context = context;
|
||||||
|
nfc_worker->dev_data = dev_data;
|
||||||
|
nfc_worker_change_state(nfc_worker, state);
|
||||||
|
furi_thread_start(nfc_worker->thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_worker_stop(NfcWorker* nfc_worker) {
|
||||||
|
furi_assert(nfc_worker);
|
||||||
|
if(nfc_worker->state == NfcWorkerStateBroken || nfc_worker->state == NfcWorkerStateReady) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
furi_hal_nfc_stop();
|
||||||
|
nfc_worker_change_state(nfc_worker, NfcWorkerStateStop);
|
||||||
|
furi_thread_join(nfc_worker->thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_worker_change_state(NfcWorker* nfc_worker, NfcWorkerState state) {
|
||||||
|
nfc_worker->state = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************** NFC Worker Thread *******************************/
|
||||||
|
|
||||||
|
int32_t nfc_worker_task(void* context) {
|
||||||
|
NfcWorker* nfc_worker = context;
|
||||||
|
|
||||||
|
furi_hal_nfc_exit_sleep();
|
||||||
|
|
||||||
|
if(nfc_worker->state == NfcWorkerStateRead) {
|
||||||
|
nfc_worker_read(nfc_worker);
|
||||||
|
} else if(nfc_worker->state == NfcWorkerStateUidEmulate) {
|
||||||
|
nfc_worker_emulate_uid(nfc_worker);
|
||||||
|
} else if(nfc_worker->state == NfcWorkerStateEmulateApdu) {
|
||||||
|
nfc_worker_emulate_apdu(nfc_worker);
|
||||||
|
} else if(nfc_worker->state == NfcWorkerStateMfUltralightEmulate) {
|
||||||
|
nfc_worker_emulate_mf_ultralight(nfc_worker);
|
||||||
|
} else if(nfc_worker->state == NfcWorkerStateMfClassicEmulate) {
|
||||||
|
nfc_worker_emulate_mf_classic(nfc_worker);
|
||||||
|
} else if(nfc_worker->state == NfcWorkerStateMfClassicUserDictAttack) {
|
||||||
|
nfc_worker_mf_classic_dict_attack(nfc_worker, MfClassicDictTypeUser);
|
||||||
|
} else if(nfc_worker->state == NfcWorkerStateMfClassicFlipperDictAttack) {
|
||||||
|
nfc_worker_mf_classic_dict_attack(nfc_worker, MfClassicDictTypeFlipper);
|
||||||
|
}
|
||||||
|
furi_hal_nfc_sleep();
|
||||||
|
nfc_worker_change_state(nfc_worker, NfcWorkerStateReady);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool nfc_worker_read_mf_ultralight(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) {
|
||||||
|
bool read_success = false;
|
||||||
|
MfUltralightReader reader = {};
|
||||||
|
MfUltralightData data = {};
|
||||||
|
|
||||||
|
nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, tx_rx, false);
|
||||||
|
do {
|
||||||
|
// Read card
|
||||||
|
if(!furi_hal_nfc_detect(&nfc_worker->dev_data->nfc_data, 200)) break;
|
||||||
|
if(!mf_ul_read_card(tx_rx, &reader, &data)) break;
|
||||||
|
// Copy data
|
||||||
|
nfc_worker->dev_data->mf_ul_data = data;
|
||||||
|
read_success = true;
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
return read_success;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool nfc_worker_read_mf_classic(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) {
|
||||||
|
furi_assert(nfc_worker->callback);
|
||||||
|
bool read_success = false;
|
||||||
|
|
||||||
|
nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, tx_rx, false);
|
||||||
|
do {
|
||||||
|
// Try to read supported card
|
||||||
|
FURI_LOG_I(TAG, "Try read supported card ...");
|
||||||
|
for(size_t i = 0; i < NfcSupportedCardTypeEnd; i++) {
|
||||||
|
if(nfc_supported_card[i].protocol == NfcDeviceProtocolMifareClassic) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(read_success) break;
|
||||||
|
// Try to read card with key cache
|
||||||
|
FURI_LOG_I(TAG, "Search for key cache ...");
|
||||||
|
if(nfc_worker->callback(NfcWorkerEventReadMfClassicLoadKeyCache, nfc_worker->context)) {
|
||||||
|
FURI_LOG_I(TAG, "Load keys cache success. Start reading");
|
||||||
|
uint8_t sectors_read =
|
||||||
|
mf_classic_update_card(tx_rx, &nfc_worker->dev_data->mf_classic_data);
|
||||||
|
uint8_t sectors_total =
|
||||||
|
mf_classic_get_total_sectors_num(nfc_worker->dev_data->mf_classic_data.type);
|
||||||
|
FURI_LOG_I(TAG, "Read %d sectors out of %d total", sectors_read, sectors_total);
|
||||||
|
read_success = (sectors_read == sectors_total);
|
||||||
|
}
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
return read_success;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool nfc_worker_read_mf_desfire(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) {
|
||||||
|
bool read_success = false;
|
||||||
|
MifareDesfireData* data = &nfc_worker->dev_data->mf_df_data;
|
||||||
|
|
||||||
|
nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, tx_rx, false);
|
||||||
|
do {
|
||||||
|
if(!furi_hal_nfc_detect(&nfc_worker->dev_data->nfc_data, 300)) break;
|
||||||
|
if(!mf_df_read_card(tx_rx, data)) break;
|
||||||
|
read_success = true;
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
return read_success;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool nfc_worker_read_bank_card(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) {
|
||||||
|
bool read_success = false;
|
||||||
|
EmvApplication emv_app = {};
|
||||||
|
EmvData* result = &nfc_worker->dev_data->emv_data;
|
||||||
|
|
||||||
|
nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, tx_rx, false);
|
||||||
|
do {
|
||||||
|
// Read card
|
||||||
|
if(!furi_hal_nfc_detect(&nfc_worker->dev_data->nfc_data, 300)) break;
|
||||||
|
if(!emv_read_bank_card(tx_rx, &emv_app)) break;
|
||||||
|
// Copy data
|
||||||
|
// TODO Set EmvData to reader or like in mifare ultralight!
|
||||||
|
result->number_len = emv_app.card_number_len;
|
||||||
|
memcpy(result->number, emv_app.card_number, result->number_len);
|
||||||
|
result->aid_len = emv_app.aid_len;
|
||||||
|
memcpy(result->aid, emv_app.aid, result->aid_len);
|
||||||
|
if(emv_app.name_found) {
|
||||||
|
memcpy(result->name, emv_app.name, sizeof(emv_app.name));
|
||||||
|
}
|
||||||
|
if(emv_app.exp_month) {
|
||||||
|
result->exp_mon = emv_app.exp_month;
|
||||||
|
result->exp_year = emv_app.exp_year;
|
||||||
|
}
|
||||||
|
if(emv_app.country_code) {
|
||||||
|
result->country_code = emv_app.country_code;
|
||||||
|
}
|
||||||
|
if(emv_app.currency_code) {
|
||||||
|
result->currency_code = emv_app.currency_code;
|
||||||
|
}
|
||||||
|
read_success = true;
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
return read_success;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool nfc_worker_read_nfca(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) {
|
||||||
|
FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
|
||||||
|
|
||||||
|
bool card_read = false;
|
||||||
|
furi_hal_nfc_sleep();
|
||||||
|
if(mf_ul_check_card_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) {
|
||||||
|
FURI_LOG_I(TAG, "Mifare Ultralight / NTAG detected");
|
||||||
|
nfc_worker->dev_data->protocol = NfcDeviceProtocolMifareUl;
|
||||||
|
card_read = nfc_worker_read_mf_ultralight(nfc_worker, tx_rx);
|
||||||
|
} else if(mf_classic_check_card_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) {
|
||||||
|
FURI_LOG_I(TAG, "Mifare Classic detected");
|
||||||
|
nfc_worker->dev_data->protocol = NfcDeviceProtocolMifareClassic;
|
||||||
|
nfc_worker->dev_data->mf_classic_data.type =
|
||||||
|
mf_classic_get_classic_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak);
|
||||||
|
card_read = nfc_worker_read_mf_classic(nfc_worker, tx_rx);
|
||||||
|
} else if(mf_df_check_card_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) {
|
||||||
|
FURI_LOG_I(TAG, "Mifare DESFire detected");
|
||||||
|
nfc_worker->dev_data->protocol = NfcDeviceProtocolMifareDesfire;
|
||||||
|
if(!nfc_worker_read_mf_desfire(nfc_worker, tx_rx)) {
|
||||||
|
FURI_LOG_I(TAG, "Unknown card. Save UID");
|
||||||
|
nfc_worker->dev_data->protocol = NfcDeviceProtocolUnknown;
|
||||||
|
}
|
||||||
|
card_read = true;
|
||||||
|
} else if(nfc_data->interface == FuriHalNfcInterfaceIsoDep) {
|
||||||
|
FURI_LOG_I(TAG, "ISO14443-4 card detected");
|
||||||
|
nfc_worker->dev_data->protocol = NfcDeviceProtocolEMV;
|
||||||
|
if(!nfc_worker_read_bank_card(nfc_worker, tx_rx)) {
|
||||||
|
FURI_LOG_I(TAG, "Unknown card. Save UID");
|
||||||
|
nfc_worker->dev_data->protocol = NfcDeviceProtocolUnknown;
|
||||||
|
}
|
||||||
|
card_read = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return card_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_worker_read(NfcWorker* nfc_worker) {
|
||||||
|
furi_assert(nfc_worker);
|
||||||
|
furi_assert(nfc_worker->callback);
|
||||||
|
|
||||||
|
nfc_device_data_clear(nfc_worker->dev_data);
|
||||||
|
NfcDeviceData* dev_data = nfc_worker->dev_data;
|
||||||
|
FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
|
||||||
|
FuriHalNfcTxRxContext tx_rx = {};
|
||||||
|
NfcWorkerEvent event = 0;
|
||||||
|
bool card_not_detected_notified = false;
|
||||||
|
|
||||||
|
while(nfc_worker->state == NfcWorkerStateRead) {
|
||||||
|
if(furi_hal_nfc_detect(nfc_data, 300)) {
|
||||||
|
// Process first found device
|
||||||
|
nfc_worker->callback(NfcWorkerEventCardDetected, nfc_worker->context);
|
||||||
|
card_not_detected_notified = false;
|
||||||
|
if(nfc_data->type == FuriHalNfcTypeA) {
|
||||||
|
if(nfc_worker_read_nfca(nfc_worker, &tx_rx)) {
|
||||||
|
if(dev_data->protocol == NfcDeviceProtocolMifareUl) {
|
||||||
|
event = NfcWorkerEventReadMfUltralight;
|
||||||
|
break;
|
||||||
|
} else if(dev_data->protocol == NfcDeviceProtocolMifareClassic) {
|
||||||
|
event = NfcWorkerEventReadMfClassicDone;
|
||||||
|
break;
|
||||||
|
} else if(dev_data->protocol == NfcDeviceProtocolMifareDesfire) {
|
||||||
|
event = NfcWorkerEventReadMfDesfire;
|
||||||
|
break;
|
||||||
|
} else if(dev_data->protocol == NfcDeviceProtocolEMV) {
|
||||||
|
event = NfcWorkerEventReadBankCard;
|
||||||
|
break;
|
||||||
|
} else if(dev_data->protocol == NfcDeviceProtocolUnknown) {
|
||||||
|
event = NfcWorkerEventReadUidNfcA;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(dev_data->protocol == NfcDeviceProtocolMifareClassic) {
|
||||||
|
event = NfcWorkerEventReadMfClassicDictAttackRequired;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(nfc_data->type == FuriHalNfcTypeB) {
|
||||||
|
event = NfcWorkerEventReadUidNfcB;
|
||||||
|
break;
|
||||||
|
} else if(nfc_data->type == FuriHalNfcTypeF) {
|
||||||
|
event = NfcWorkerEventReadUidNfcF;
|
||||||
|
break;
|
||||||
|
} else if(nfc_data->type == FuriHalNfcTypeV) {
|
||||||
|
event = NfcWorkerEventReadUidNfcV;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(!card_not_detected_notified) {
|
||||||
|
nfc_worker->callback(NfcWorkerEventNoCardDetected, nfc_worker->context);
|
||||||
|
card_not_detected_notified = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
furi_hal_nfc_sleep();
|
||||||
|
furi_delay_ms(100);
|
||||||
|
}
|
||||||
|
// Notify caller and exit
|
||||||
|
if(event > NfcWorkerEventReserved) {
|
||||||
|
nfc_worker->callback(event, nfc_worker->context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_worker_emulate_uid(NfcWorker* nfc_worker) {
|
||||||
|
FuriHalNfcTxRxContext tx_rx = {};
|
||||||
|
nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, &tx_rx, true);
|
||||||
|
FuriHalNfcDevData* data = &nfc_worker->dev_data->nfc_data;
|
||||||
|
NfcReaderRequestData* reader_data = &nfc_worker->dev_data->reader_data;
|
||||||
|
|
||||||
|
while(nfc_worker->state == NfcWorkerStateUidEmulate) {
|
||||||
|
if(furi_hal_nfc_listen(data->uid, data->uid_len, data->atqa, data->sak, true, 100)) {
|
||||||
|
if(furi_hal_nfc_tx_rx(&tx_rx, 100)) {
|
||||||
|
reader_data->size = tx_rx.rx_bits / 8;
|
||||||
|
if(reader_data->size > 0) {
|
||||||
|
memcpy(reader_data->data, tx_rx.rx_data, reader_data->size);
|
||||||
|
if(nfc_worker->callback) {
|
||||||
|
nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
FURI_LOG_E(TAG, "Failed to get reader commands");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_worker_emulate_apdu(NfcWorker* nfc_worker) {
|
||||||
|
FuriHalNfcTxRxContext tx_rx = {};
|
||||||
|
nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, &tx_rx, true);
|
||||||
|
FuriHalNfcDevData params = {
|
||||||
|
.uid = {0xCF, 0x72, 0xd4, 0x40},
|
||||||
|
.uid_len = 4,
|
||||||
|
.atqa = {0x00, 0x04},
|
||||||
|
.sak = 0x20,
|
||||||
|
.type = FuriHalNfcTypeA,
|
||||||
|
};
|
||||||
|
|
||||||
|
while(nfc_worker->state == NfcWorkerStateEmulateApdu) {
|
||||||
|
if(furi_hal_nfc_listen(params.uid, params.uid_len, params.atqa, params.sak, false, 300)) {
|
||||||
|
FURI_LOG_D(TAG, "POS terminal detected");
|
||||||
|
if(emv_card_emulation(&tx_rx)) {
|
||||||
|
FURI_LOG_D(TAG, "EMV card emulated");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
FURI_LOG_D(TAG, "Can't find reader");
|
||||||
|
}
|
||||||
|
furi_hal_nfc_sleep();
|
||||||
|
furi_delay_ms(20);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_worker_emulate_mf_ultralight(NfcWorker* nfc_worker) {
|
||||||
|
FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
|
||||||
|
MfUltralightEmulator emulator = {};
|
||||||
|
mf_ul_prepare_emulation(&emulator, &nfc_worker->dev_data->mf_ul_data);
|
||||||
|
while(nfc_worker->state == NfcWorkerStateMfUltralightEmulate) {
|
||||||
|
mf_ul_reset_emulation(&emulator, true);
|
||||||
|
furi_hal_nfc_emulate_nfca(
|
||||||
|
nfc_data->uid,
|
||||||
|
nfc_data->uid_len,
|
||||||
|
nfc_data->atqa,
|
||||||
|
nfc_data->sak,
|
||||||
|
mf_ul_prepare_emulation_response,
|
||||||
|
&emulator,
|
||||||
|
5000);
|
||||||
|
// Check if data was modified
|
||||||
|
if(emulator.data_changed) {
|
||||||
|
nfc_worker->dev_data->mf_ul_data = emulator.data;
|
||||||
|
if(nfc_worker->callback) {
|
||||||
|
nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
|
||||||
|
}
|
||||||
|
emulator.data_changed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker, MfClassicDictType type) {
|
||||||
|
furi_assert(nfc_worker);
|
||||||
|
furi_assert(nfc_worker->callback);
|
||||||
|
|
||||||
|
MfClassicData* data = &nfc_worker->dev_data->mf_classic_data;
|
||||||
|
uint32_t total_sectors = mf_classic_get_total_sectors_num(data->type);
|
||||||
|
uint64_t key = 0;
|
||||||
|
FuriHalNfcTxRxContext tx_rx = {};
|
||||||
|
bool card_found_notified = true;
|
||||||
|
bool card_removed_notified = false;
|
||||||
|
|
||||||
|
// Load dictionary
|
||||||
|
MfClassicDict* dict = mf_classic_dict_alloc(type);
|
||||||
|
if(!dict) {
|
||||||
|
FURI_LOG_E(TAG, "Dictionary not found");
|
||||||
|
nfc_worker->callback(NfcWorkerEventNoDictFound, nfc_worker->context);
|
||||||
|
mf_classic_dict_free(dict);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
FURI_LOG_D(TAG, "Start Dictionary attack");
|
||||||
|
for(size_t i = 0; i < total_sectors; i++) {
|
||||||
|
FURI_LOG_I(TAG, "Sector %d", i);
|
||||||
|
nfc_worker->callback(NfcWorkerEventNewSector, nfc_worker->context);
|
||||||
|
uint8_t block_num = mf_classic_get_sector_trailer_block_num_by_sector(i);
|
||||||
|
if(mf_classic_is_sector_read(data, i)) continue;
|
||||||
|
bool is_key_a_found = mf_classic_is_key_found(data, i, MfClassicKeyA);
|
||||||
|
bool is_key_b_found = mf_classic_is_key_found(data, i, MfClassicKeyB);
|
||||||
|
while(mf_classic_dict_get_next_key(dict, &key)) {
|
||||||
|
furi_hal_nfc_sleep();
|
||||||
|
if(furi_hal_nfc_activate_nfca(200, NULL)) {
|
||||||
|
furi_hal_nfc_sleep();
|
||||||
|
if(!card_found_notified) {
|
||||||
|
nfc_worker->callback(NfcWorkerEventCardDetected, nfc_worker->context);
|
||||||
|
card_found_notified = true;
|
||||||
|
card_removed_notified = false;
|
||||||
|
}
|
||||||
|
FURI_LOG_D(
|
||||||
|
TAG,
|
||||||
|
"Try to auth to sector %d with key %04lx%08lx",
|
||||||
|
i,
|
||||||
|
(uint32_t)(key >> 32),
|
||||||
|
(uint32_t)key);
|
||||||
|
if(!is_key_a_found) {
|
||||||
|
is_key_a_found = mf_classic_is_key_found(data, i, MfClassicKeyA);
|
||||||
|
if(mf_classic_authenticate(&tx_rx, block_num, key, MfClassicKeyA)) {
|
||||||
|
mf_classic_set_key_found(data, i, MfClassicKeyA, key);
|
||||||
|
nfc_worker->callback(NfcWorkerEventFoundKeyA, nfc_worker->context);
|
||||||
|
}
|
||||||
|
furi_hal_nfc_sleep();
|
||||||
|
}
|
||||||
|
if(!is_key_b_found) {
|
||||||
|
is_key_b_found = mf_classic_is_key_found(data, i, MfClassicKeyB);
|
||||||
|
if(mf_classic_authenticate(&tx_rx, block_num, key, MfClassicKeyB)) {
|
||||||
|
mf_classic_set_key_found(data, i, MfClassicKeyB, key);
|
||||||
|
nfc_worker->callback(NfcWorkerEventFoundKeyB, nfc_worker->context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(is_key_a_found && is_key_b_found) break;
|
||||||
|
if(!((nfc_worker->state == NfcWorkerStateMfClassicUserDictAttack) ||
|
||||||
|
(nfc_worker->state == NfcWorkerStateMfClassicFlipperDictAttack)))
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
if(!card_removed_notified) {
|
||||||
|
nfc_worker->callback(NfcWorkerEventNoCardDetected, nfc_worker->context);
|
||||||
|
card_removed_notified = true;
|
||||||
|
card_found_notified = false;
|
||||||
|
}
|
||||||
|
if(!((nfc_worker->state == NfcWorkerStateMfClassicUserDictAttack) ||
|
||||||
|
(nfc_worker->state == NfcWorkerStateMfClassicFlipperDictAttack)))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!((nfc_worker->state == NfcWorkerStateMfClassicUserDictAttack) ||
|
||||||
|
(nfc_worker->state == NfcWorkerStateMfClassicFlipperDictAttack)))
|
||||||
|
break;
|
||||||
|
mf_classic_read_sector(&tx_rx, data, i);
|
||||||
|
mf_classic_dict_rewind(dict);
|
||||||
|
}
|
||||||
|
mf_classic_dict_free(dict);
|
||||||
|
if((nfc_worker->state == NfcWorkerStateMfClassicUserDictAttack) ||
|
||||||
|
(nfc_worker->state == NfcWorkerStateMfClassicFlipperDictAttack)) {
|
||||||
|
nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
|
||||||
|
} else {
|
||||||
|
nfc_worker->callback(NfcWorkerEventAborted, nfc_worker->context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_worker_emulate_mf_classic(NfcWorker* nfc_worker) {
|
||||||
|
FuriHalNfcTxRxContext tx_rx = {};
|
||||||
|
nfc_debug_pcap_prepare_tx_rx(nfc_worker->debug_pcap_worker, &tx_rx, true);
|
||||||
|
FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
|
||||||
|
MfClassicEmulator emulator = {
|
||||||
|
.cuid = nfc_util_bytes2num(&nfc_data->uid[nfc_data->uid_len - 4], 4),
|
||||||
|
.data = nfc_worker->dev_data->mf_classic_data,
|
||||||
|
.data_changed = false,
|
||||||
|
};
|
||||||
|
NfcaSignal* nfca_signal = nfca_signal_alloc();
|
||||||
|
tx_rx.nfca_signal = nfca_signal;
|
||||||
|
|
||||||
|
rfal_platform_spi_acquire();
|
||||||
|
|
||||||
|
furi_hal_nfc_listen_start(nfc_data);
|
||||||
|
while(nfc_worker->state == NfcWorkerStateMfClassicEmulate) {
|
||||||
|
if(furi_hal_nfc_listen_rx(&tx_rx, 300)) {
|
||||||
|
mf_classic_emulator(&emulator, &tx_rx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(emulator.data_changed) {
|
||||||
|
nfc_worker->dev_data->mf_classic_data = emulator.data;
|
||||||
|
if(nfc_worker->callback) {
|
||||||
|
nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context);
|
||||||
|
}
|
||||||
|
emulator.data_changed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
nfca_signal_free(nfca_signal);
|
||||||
|
|
||||||
|
rfal_platform_spi_release();
|
||||||
|
}
|
||||||
@@ -10,17 +10,15 @@ typedef enum {
|
|||||||
NfcWorkerStateBroken,
|
NfcWorkerStateBroken,
|
||||||
NfcWorkerStateReady,
|
NfcWorkerStateReady,
|
||||||
// Main worker states
|
// Main worker states
|
||||||
NfcWorkerStateDetect,
|
NfcWorkerStateRead,
|
||||||
NfcWorkerStateEmulate,
|
NfcWorkerStateUidEmulate,
|
||||||
NfcWorkerStateReadEMVApp,
|
NfcWorkerStateMfUltralightEmulate,
|
||||||
NfcWorkerStateReadEMVData,
|
NfcWorkerStateMfClassicEmulate,
|
||||||
|
NfcWorkerStateMfClassicUserDictAttack,
|
||||||
|
NfcWorkerStateMfClassicFlipperDictAttack,
|
||||||
|
// Debug
|
||||||
NfcWorkerStateEmulateApdu,
|
NfcWorkerStateEmulateApdu,
|
||||||
NfcWorkerStateField,
|
NfcWorkerStateField,
|
||||||
NfcWorkerStateReadMifareUltralight,
|
|
||||||
NfcWorkerStateEmulateMifareUltralight,
|
|
||||||
NfcWorkerStateReadMifareClassic,
|
|
||||||
NfcWorkerStateEmulateMifareClassic,
|
|
||||||
NfcWorkerStateReadMifareDesfire,
|
|
||||||
// Transition
|
// Transition
|
||||||
NfcWorkerStateStop,
|
NfcWorkerStateStop,
|
||||||
} NfcWorkerState;
|
} NfcWorkerState;
|
||||||
@@ -29,21 +27,33 @@ typedef enum {
|
|||||||
// Reserve first 50 events for application events
|
// Reserve first 50 events for application events
|
||||||
NfcWorkerEventReserved = 50,
|
NfcWorkerEventReserved = 50,
|
||||||
|
|
||||||
|
// Nfc read events
|
||||||
|
NfcWorkerEventReadUidNfcB,
|
||||||
|
NfcWorkerEventReadUidNfcV,
|
||||||
|
NfcWorkerEventReadUidNfcF,
|
||||||
|
NfcWorkerEventReadUidNfcA,
|
||||||
|
NfcWorkerEventReadMfUltralight,
|
||||||
|
NfcWorkerEventReadMfDesfire,
|
||||||
|
NfcWorkerEventReadMfClassicDone,
|
||||||
|
NfcWorkerEventReadMfClassicLoadKeyCache,
|
||||||
|
NfcWorkerEventReadMfClassicDictAttackRequired,
|
||||||
|
NfcWorkerEventReadBankCard,
|
||||||
|
|
||||||
// Nfc worker common events
|
// Nfc worker common events
|
||||||
NfcWorkerEventSuccess,
|
NfcWorkerEventSuccess,
|
||||||
NfcWorkerEventFail,
|
NfcWorkerEventFail,
|
||||||
|
NfcWorkerEventAborted,
|
||||||
|
NfcWorkerEventCardDetected,
|
||||||
NfcWorkerEventNoCardDetected,
|
NfcWorkerEventNoCardDetected,
|
||||||
|
|
||||||
// Mifare Classic events
|
// Mifare Classic events
|
||||||
NfcWorkerEventNoDictFound,
|
NfcWorkerEventNoDictFound,
|
||||||
NfcWorkerEventDetectedClassic1k,
|
|
||||||
NfcWorkerEventDetectedClassic4k,
|
|
||||||
NfcWorkerEventNewSector,
|
NfcWorkerEventNewSector,
|
||||||
NfcWorkerEventFoundKeyA,
|
NfcWorkerEventFoundKeyA,
|
||||||
NfcWorkerEventFoundKeyB,
|
NfcWorkerEventFoundKeyB,
|
||||||
NfcWorkerEventStartReading,
|
|
||||||
} NfcWorkerEvent;
|
} NfcWorkerEvent;
|
||||||
|
|
||||||
typedef void (*NfcWorkerCallback)(NfcWorkerEvent event, void* context);
|
typedef bool (*NfcWorkerCallback)(NfcWorkerEvent event, void* context);
|
||||||
|
|
||||||
NfcWorker* nfc_worker_alloc();
|
NfcWorker* nfc_worker_alloc();
|
||||||
|
|
||||||
48
lib/nfc/nfc_worker_i.h
Executable file
48
lib/nfc/nfc_worker_i.h
Executable file
@@ -0,0 +1,48 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "nfc_worker.h"
|
||||||
|
|
||||||
|
#include <furi.h>
|
||||||
|
#include <lib/toolbox/stream/file_stream.h>
|
||||||
|
|
||||||
|
#include <lib/nfc/protocols/nfc_util.h>
|
||||||
|
#include <lib/nfc/protocols/emv.h>
|
||||||
|
#include <lib/nfc/protocols/mifare_common.h>
|
||||||
|
#include <lib/nfc/protocols/mifare_ultralight.h>
|
||||||
|
#include <lib/nfc/protocols/mifare_classic.h>
|
||||||
|
#include <lib/nfc/protocols/mifare_desfire.h>
|
||||||
|
#include <lib/nfc/protocols/nfca.h>
|
||||||
|
|
||||||
|
#include "helpers/mf_classic_dict.h"
|
||||||
|
#include "helpers/nfc_debug_pcap.h"
|
||||||
|
|
||||||
|
struct NfcWorker {
|
||||||
|
FuriThread* thread;
|
||||||
|
Storage* storage;
|
||||||
|
Stream* dict_stream;
|
||||||
|
|
||||||
|
NfcDeviceData* dev_data;
|
||||||
|
|
||||||
|
NfcWorkerCallback callback;
|
||||||
|
void* context;
|
||||||
|
|
||||||
|
NfcWorkerState state;
|
||||||
|
|
||||||
|
NfcDebugPcapWorker* debug_pcap_worker;
|
||||||
|
};
|
||||||
|
|
||||||
|
void nfc_worker_change_state(NfcWorker* nfc_worker, NfcWorkerState state);
|
||||||
|
|
||||||
|
int32_t nfc_worker_task(void* context);
|
||||||
|
|
||||||
|
void nfc_worker_read(NfcWorker* nfc_worker);
|
||||||
|
|
||||||
|
void nfc_worker_emulate_uid(NfcWorker* nfc_worker);
|
||||||
|
|
||||||
|
void nfc_worker_emulate_mf_ultralight(NfcWorker* nfc_worker);
|
||||||
|
|
||||||
|
void nfc_worker_emulate_mf_classic(NfcWorker* nfc_worker);
|
||||||
|
|
||||||
|
void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker, MfClassicDictType type);
|
||||||
|
|
||||||
|
void nfc_worker_emulate_apdu(NfcWorker* nfc_worker);
|
||||||
12
lib/nfc/parsers/nfc_supported_card.c
Normal file
12
lib/nfc/parsers/nfc_supported_card.c
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#include "nfc_supported_card.h"
|
||||||
|
|
||||||
|
#include "troyka_parser.h"
|
||||||
|
|
||||||
|
NfcSupportedCard nfc_supported_card[NfcSupportedCardTypeEnd] = {
|
||||||
|
[NfcSupportedCardTypeTroyka] = {
|
||||||
|
.protocol = NfcDeviceProtocolMifareClassic,
|
||||||
|
.verify = troyka_parser_verify,
|
||||||
|
.read = troyka_parser_read,
|
||||||
|
.parse = troyka_parser_parse,
|
||||||
|
},
|
||||||
|
};
|
||||||
27
lib/nfc/parsers/nfc_supported_card.h
Normal file
27
lib/nfc/parsers/nfc_supported_card.h
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <furi_hal_nfc.h>
|
||||||
|
#include "../nfc_worker.h"
|
||||||
|
|
||||||
|
#include <m-string.h>
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
NfcSupportedCardTypeTroyka,
|
||||||
|
|
||||||
|
NfcSupportedCardTypeEnd,
|
||||||
|
} NfcSupportedCardType;
|
||||||
|
|
||||||
|
typedef bool (*NfcSupportedCardVerify)(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx);
|
||||||
|
|
||||||
|
typedef bool (*NfcSupportedCardRead)(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx);
|
||||||
|
|
||||||
|
typedef bool (*NfcSupportedCardParse)(NfcWorker* nfc_worker);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
NfcProtocol protocol;
|
||||||
|
NfcSupportedCardVerify verify;
|
||||||
|
NfcSupportedCardRead read;
|
||||||
|
NfcSupportedCardParse parse;
|
||||||
|
} NfcSupportedCard;
|
||||||
|
|
||||||
|
extern NfcSupportedCard nfc_supported_card[NfcSupportedCardTypeEnd];
|
||||||
70
lib/nfc/parsers/troyka_parser.c
Normal file
70
lib/nfc/parsers/troyka_parser.c
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
#include "nfc_supported_card.h"
|
||||||
|
|
||||||
|
#include <gui/modules/widget.h>
|
||||||
|
#include <nfc_worker_i.h>
|
||||||
|
|
||||||
|
static const MfClassicAuthContext troyka_keys[] = {
|
||||||
|
{.sector = 0, .key_a = 0xa0a1a2a3a4a5, .key_b = 0xfbf225dc5d58},
|
||||||
|
{.sector = 1, .key_a = 0xa82607b01c0d, .key_b = 0x2910989b6880},
|
||||||
|
{.sector = 2, .key_a = 0x2aa05ed1856f, .key_b = 0xeaac88e5dc99},
|
||||||
|
{.sector = 3, .key_a = 0x2aa05ed1856f, .key_b = 0xeaac88e5dc99},
|
||||||
|
{.sector = 4, .key_a = 0x73068f118c13, .key_b = 0x2b7f3253fac5},
|
||||||
|
{.sector = 5, .key_a = 0xfbc2793d540b, .key_b = 0xd3a297dc2698},
|
||||||
|
{.sector = 6, .key_a = 0x2aa05ed1856f, .key_b = 0xeaac88e5dc99},
|
||||||
|
{.sector = 7, .key_a = 0xae3d65a3dad4, .key_b = 0x0f1c63013dba},
|
||||||
|
{.sector = 8, .key_a = 0xa73f5dc1d333, .key_b = 0xe35173494a81},
|
||||||
|
{.sector = 9, .key_a = 0x69a32f1c2f19, .key_b = 0x6b8bd9860763},
|
||||||
|
{.sector = 10, .key_a = 0x9becdf3d9273, .key_b = 0xf8493407799d},
|
||||||
|
{.sector = 11, .key_a = 0x08b386463229, .key_b = 0x5efbaecef46b},
|
||||||
|
{.sector = 12, .key_a = 0xcd4c61c26e3d, .key_b = 0x31c7610de3b0},
|
||||||
|
{.sector = 13, .key_a = 0xa82607b01c0d, .key_b = 0x2910989b6880},
|
||||||
|
{.sector = 14, .key_a = 0x0e8f64340ba4, .key_b = 0x4acec1205d75},
|
||||||
|
{.sector = 15, .key_a = 0x2aa05ed1856f, .key_b = 0xeaac88e5dc99},
|
||||||
|
};
|
||||||
|
|
||||||
|
bool troyka_parser_verify(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) {
|
||||||
|
furi_assert(nfc_worker);
|
||||||
|
UNUSED(nfc_worker);
|
||||||
|
|
||||||
|
MfClassicAuthContext auth_ctx = {
|
||||||
|
.key_a = MF_CLASSIC_NO_KEY,
|
||||||
|
.key_b = MF_CLASSIC_NO_KEY,
|
||||||
|
.sector = 8,
|
||||||
|
};
|
||||||
|
return mf_classic_auth_attempt(tx_rx, &auth_ctx, 0xa73f5dc1d333);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool troyka_parser_read(NfcWorker* nfc_worker, FuriHalNfcTxRxContext* tx_rx) {
|
||||||
|
furi_assert(nfc_worker);
|
||||||
|
|
||||||
|
MfClassicReader reader = {};
|
||||||
|
FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
|
||||||
|
mf_classic_get_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak, &reader);
|
||||||
|
for(size_t i = 0; i < COUNT_OF(troyka_keys); i++) {
|
||||||
|
mf_classic_reader_add_sector(
|
||||||
|
&reader, troyka_keys[i].sector, troyka_keys[i].key_a, troyka_keys[i].key_b);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
string_printf(
|
||||||
|
nfc_worker->dev_data->parsed_data,
|
||||||
|
"Troyka Transport card\nNumber: %ld\nBalance: %d rub",
|
||||||
|
number,
|
||||||
|
balance);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
9
lib/nfc/parsers/troyka_parser.h
Normal file
9
lib/nfc/parsers/troyka_parser.h
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "nfc_supported_card.h"
|
||||||
|
|
||||||
|
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);
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user