mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2025-12-12 20:49:49 +04:00
Merge branch 'fz-dev' into dev
This commit is contained in:
@@ -7,6 +7,7 @@
|
|||||||
# construction of certain targets behind command-line options.
|
# construction of certain targets behind command-line options.
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
from fbt.util import path_as_posix
|
||||||
|
|
||||||
DefaultEnvironment(tools=[])
|
DefaultEnvironment(tools=[])
|
||||||
|
|
||||||
@@ -200,9 +201,7 @@ firmware_debug = distenv.PhonyTarget(
|
|||||||
source=firmware_env["FW_ELF"],
|
source=firmware_env["FW_ELF"],
|
||||||
GDBOPTS="${GDBOPTS_BASE}",
|
GDBOPTS="${GDBOPTS_BASE}",
|
||||||
GDBREMOTE="${OPENOCD_GDB_PIPE}",
|
GDBREMOTE="${OPENOCD_GDB_PIPE}",
|
||||||
FBT_FAP_DEBUG_ELF_ROOT=firmware_env.subst("$FBT_FAP_DEBUG_ELF_ROOT").replace(
|
FBT_FAP_DEBUG_ELF_ROOT=path_as_posix(firmware_env.subst("$FBT_FAP_DEBUG_ELF_ROOT")),
|
||||||
"\\", "/"
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
distenv.Depends(firmware_debug, firmware_flash)
|
distenv.Depends(firmware_debug, firmware_flash)
|
||||||
|
|
||||||
@@ -212,9 +211,7 @@ distenv.PhonyTarget(
|
|||||||
source=firmware_env["FW_ELF"],
|
source=firmware_env["FW_ELF"],
|
||||||
GDBOPTS="${GDBOPTS_BASE} ${GDBOPTS_BLACKMAGIC}",
|
GDBOPTS="${GDBOPTS_BASE} ${GDBOPTS_BLACKMAGIC}",
|
||||||
GDBREMOTE="${BLACKMAGIC_ADDR}",
|
GDBREMOTE="${BLACKMAGIC_ADDR}",
|
||||||
FBT_FAP_DEBUG_ELF_ROOT=firmware_env.subst("$FBT_FAP_DEBUG_ELF_ROOT").replace(
|
FBT_FAP_DEBUG_ELF_ROOT=path_as_posix(firmware_env.subst("$FBT_FAP_DEBUG_ELF_ROOT")),
|
||||||
"\\", "/"
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Debug alien elf
|
# Debug alien elf
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
#include <lib/nfc/protocols/nfca.h>
|
#include <lib/nfc/protocols/nfca.h>
|
||||||
#include <lib/nfc/helpers/mf_classic_dict.h>
|
#include <lib/nfc/helpers/mf_classic_dict.h>
|
||||||
#include <lib/digital_signal/digital_signal.h>
|
#include <lib/digital_signal/digital_signal.h>
|
||||||
|
#include <lib/nfc/nfc_device.h>
|
||||||
|
#include <applications/main/nfc/helpers/nfc_generators.h>
|
||||||
|
|
||||||
#include <lib/flipper_format/flipper_format_i.h>
|
#include <lib/flipper_format/flipper_format_i.h>
|
||||||
#include <lib/toolbox/stream/file_stream.h>
|
#include <lib/toolbox/stream/file_stream.h>
|
||||||
@@ -17,6 +19,7 @@
|
|||||||
#define NFC_TEST_SIGNAL_SHORT_FILE "nfc_nfca_signal_short.nfc"
|
#define NFC_TEST_SIGNAL_SHORT_FILE "nfc_nfca_signal_short.nfc"
|
||||||
#define NFC_TEST_SIGNAL_LONG_FILE "nfc_nfca_signal_long.nfc"
|
#define NFC_TEST_SIGNAL_LONG_FILE "nfc_nfca_signal_long.nfc"
|
||||||
#define NFC_TEST_DICT_PATH EXT_PATH("unit_tests/mf_classic_dict.nfc")
|
#define NFC_TEST_DICT_PATH EXT_PATH("unit_tests/mf_classic_dict.nfc")
|
||||||
|
#define NFC_TEST_NFC_DEV_PATH EXT_PATH("unit_tests/nfc/nfc_dev_test.nfc")
|
||||||
|
|
||||||
static const char* nfc_test_file_type = "Flipper NFC test";
|
static const char* nfc_test_file_type = "Flipper NFC test";
|
||||||
static const uint32_t nfc_test_file_version = 1;
|
static const uint32_t nfc_test_file_version = 1;
|
||||||
@@ -287,9 +290,203 @@ MU_TEST(mf_classic_dict_load_test) {
|
|||||||
furi_record_close(RECORD_STORAGE);
|
furi_record_close(RECORD_STORAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MU_TEST(nfca_file_test) {
|
||||||
|
NfcDevice* nfc = nfc_device_alloc();
|
||||||
|
mu_assert(nfc != NULL, "nfc_device_data != NULL assert failed\r\n");
|
||||||
|
nfc->format = NfcDeviceSaveFormatUid;
|
||||||
|
|
||||||
|
// Fill the UID, sak, ATQA and type
|
||||||
|
uint8_t uid[7] = {0x04, 0x01, 0x23, 0x45, 0x67, 0x89, 0x00};
|
||||||
|
memcpy(nfc->dev_data.nfc_data.uid, uid, 7);
|
||||||
|
nfc->dev_data.nfc_data.uid_len = 7;
|
||||||
|
|
||||||
|
nfc->dev_data.nfc_data.sak = 0x08;
|
||||||
|
nfc->dev_data.nfc_data.atqa[0] = 0x00;
|
||||||
|
nfc->dev_data.nfc_data.atqa[1] = 0x04;
|
||||||
|
nfc->dev_data.nfc_data.type = FuriHalNfcTypeA;
|
||||||
|
|
||||||
|
// Save the NFC device data to the file
|
||||||
|
mu_assert(
|
||||||
|
nfc_device_save(nfc, NFC_TEST_NFC_DEV_PATH), "nfc_device_save == true assert failed\r\n");
|
||||||
|
nfc_device_free(nfc);
|
||||||
|
|
||||||
|
// Load the NFC device data from the file
|
||||||
|
NfcDevice* nfc_validate = nfc_device_alloc();
|
||||||
|
mu_assert(
|
||||||
|
nfc_device_load(nfc_validate, NFC_TEST_NFC_DEV_PATH, true),
|
||||||
|
"nfc_device_load == true assert failed\r\n");
|
||||||
|
|
||||||
|
// Check the UID, sak, ATQA and type
|
||||||
|
mu_assert(memcmp(nfc_validate->dev_data.nfc_data.uid, uid, 7) == 0, "uid assert failed\r\n");
|
||||||
|
mu_assert(nfc_validate->dev_data.nfc_data.sak == 0x08, "sak == 0x08 assert failed\r\n");
|
||||||
|
mu_assert(
|
||||||
|
nfc_validate->dev_data.nfc_data.atqa[0] == 0x00, "atqa[0] == 0x00 assert failed\r\n");
|
||||||
|
mu_assert(
|
||||||
|
nfc_validate->dev_data.nfc_data.atqa[1] == 0x04, "atqa[1] == 0x04 assert failed\r\n");
|
||||||
|
mu_assert(
|
||||||
|
nfc_validate->dev_data.nfc_data.type == FuriHalNfcTypeA,
|
||||||
|
"type == FuriHalNfcTypeA assert failed\r\n");
|
||||||
|
nfc_device_free(nfc_validate);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mf_classic_generator_test(uint8_t uid_len, MfClassicType type) {
|
||||||
|
NfcDevice* nfc_dev = nfc_device_alloc();
|
||||||
|
mu_assert(nfc_dev != NULL, "nfc_device_data != NULL assert failed\r\n");
|
||||||
|
nfc_dev->format = NfcDeviceSaveFormatMifareClassic;
|
||||||
|
|
||||||
|
// Create a test file
|
||||||
|
nfc_generate_mf_classic(&nfc_dev->dev_data, uid_len, type);
|
||||||
|
|
||||||
|
// Get the uid from generated MFC
|
||||||
|
uint8_t uid[7] = {0};
|
||||||
|
memcpy(uid, nfc_dev->dev_data.nfc_data.uid, uid_len);
|
||||||
|
uint8_t sak = nfc_dev->dev_data.nfc_data.sak;
|
||||||
|
uint8_t atqa[2] = {};
|
||||||
|
memcpy(atqa, nfc_dev->dev_data.nfc_data.atqa, 2);
|
||||||
|
|
||||||
|
MfClassicData* mf_data = &nfc_dev->dev_data.mf_classic_data;
|
||||||
|
// Check the manufacturer block (should be uid[uid_len] + 0xFF[rest])
|
||||||
|
uint8_t manufacturer_block[16] = {0};
|
||||||
|
memcpy(manufacturer_block, nfc_dev->dev_data.mf_classic_data.block[0].value, 16);
|
||||||
|
mu_assert(
|
||||||
|
memcmp(manufacturer_block, uid, uid_len) == 0,
|
||||||
|
"manufacturer_block uid doesn't match the file\r\n");
|
||||||
|
for(uint8_t i = uid_len; i < 16; i++) {
|
||||||
|
mu_assert(
|
||||||
|
manufacturer_block[i] == 0xFF, "manufacturer_block[i] == 0xFF assert failed\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reference sector trailers (should be 0xFF[6] + 0xFF + 0x07 + 0x80 + 0x69 + 0xFF[6])
|
||||||
|
uint8_t sector_trailer[16] = {
|
||||||
|
0xFF,
|
||||||
|
0xFF,
|
||||||
|
0xFF,
|
||||||
|
0xFF,
|
||||||
|
0xFF,
|
||||||
|
0xFF,
|
||||||
|
0xFF,
|
||||||
|
0x07,
|
||||||
|
0x80,
|
||||||
|
0x69,
|
||||||
|
0xFF,
|
||||||
|
0xFF,
|
||||||
|
0xFF,
|
||||||
|
0xFF,
|
||||||
|
0xFF,
|
||||||
|
0xFF};
|
||||||
|
// Reference block data
|
||||||
|
uint8_t block_data[16] = {};
|
||||||
|
memset(block_data, 0xff, sizeof(block_data));
|
||||||
|
uint16_t total_blocks = mf_classic_get_total_block_num(type);
|
||||||
|
for(size_t i = 1; i < total_blocks; i++) {
|
||||||
|
if(mf_classic_is_sector_trailer(i)) {
|
||||||
|
mu_assert(
|
||||||
|
memcmp(mf_data->block[i].value, sector_trailer, 16) == 0,
|
||||||
|
"Failed sector trailer compare");
|
||||||
|
} else {
|
||||||
|
mu_assert(memcmp(mf_data->block[i].value, block_data, 16) == 0, "Failed data compare");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Save the NFC device data to the file
|
||||||
|
mu_assert(
|
||||||
|
nfc_device_save(nfc_dev, NFC_TEST_NFC_DEV_PATH),
|
||||||
|
"nfc_device_save == true assert failed\r\n");
|
||||||
|
// Verify that key cache is saved
|
||||||
|
FuriString* key_cache_name = furi_string_alloc();
|
||||||
|
furi_string_set_str(key_cache_name, "/ext/nfc/cache/");
|
||||||
|
for(size_t i = 0; i < uid_len; i++) {
|
||||||
|
furi_string_cat_printf(key_cache_name, "%02X", uid[i]);
|
||||||
|
}
|
||||||
|
furi_string_cat_printf(key_cache_name, ".keys");
|
||||||
|
mu_assert(
|
||||||
|
storage_common_stat(nfc_dev->storage, furi_string_get_cstr(key_cache_name), NULL) ==
|
||||||
|
FSE_OK,
|
||||||
|
"Key cache file save failed");
|
||||||
|
nfc_device_free(nfc_dev);
|
||||||
|
|
||||||
|
// Load the NFC device data from the file
|
||||||
|
NfcDevice* nfc_validate = nfc_device_alloc();
|
||||||
|
mu_assert(nfc_validate, "Nfc device alloc assert");
|
||||||
|
mu_assert(
|
||||||
|
nfc_device_load(nfc_validate, NFC_TEST_NFC_DEV_PATH, false),
|
||||||
|
"nfc_device_load == true assert failed\r\n");
|
||||||
|
|
||||||
|
// Check the UID, sak, ATQA and type
|
||||||
|
mu_assert(
|
||||||
|
memcmp(nfc_validate->dev_data.nfc_data.uid, uid, uid_len) == 0,
|
||||||
|
"uid compare assert failed\r\n");
|
||||||
|
mu_assert(nfc_validate->dev_data.nfc_data.sak == sak, "sak compare assert failed\r\n");
|
||||||
|
mu_assert(
|
||||||
|
memcmp(nfc_validate->dev_data.nfc_data.atqa, atqa, 2) == 0,
|
||||||
|
"atqa compare assert failed\r\n");
|
||||||
|
mu_assert(
|
||||||
|
nfc_validate->dev_data.nfc_data.type == FuriHalNfcTypeA,
|
||||||
|
"type == FuriHalNfcTypeA assert failed\r\n");
|
||||||
|
|
||||||
|
// Check the manufacturer block
|
||||||
|
mu_assert(
|
||||||
|
memcmp(nfc_validate->dev_data.mf_classic_data.block[0].value, manufacturer_block, 16) == 0,
|
||||||
|
"manufacturer_block assert failed\r\n");
|
||||||
|
// Check other blocks
|
||||||
|
for(size_t i = 1; i < total_blocks; i++) {
|
||||||
|
if(mf_classic_is_sector_trailer(i)) {
|
||||||
|
mu_assert(
|
||||||
|
memcmp(mf_data->block[i].value, sector_trailer, 16) == 0,
|
||||||
|
"Failed sector trailer compare");
|
||||||
|
} else {
|
||||||
|
mu_assert(memcmp(mf_data->block[i].value, block_data, 16) == 0, "Failed data compare");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nfc_device_free(nfc_validate);
|
||||||
|
|
||||||
|
// Check saved key cache
|
||||||
|
NfcDevice* nfc_keys = nfc_device_alloc();
|
||||||
|
mu_assert(nfc_validate, "Nfc device alloc assert");
|
||||||
|
nfc_keys->dev_data.nfc_data.uid_len = uid_len;
|
||||||
|
memcpy(nfc_keys->dev_data.nfc_data.uid, uid, uid_len);
|
||||||
|
mu_assert(nfc_device_load_key_cache(nfc_keys), "Failed to load key cache");
|
||||||
|
uint8_t total_sec = mf_classic_get_total_sectors_num(type);
|
||||||
|
uint8_t default_key[6] = {};
|
||||||
|
memset(default_key, 0xff, 6);
|
||||||
|
for(size_t i = 0; i < total_sec; i++) {
|
||||||
|
MfClassicSectorTrailer* sec_tr =
|
||||||
|
mf_classic_get_sector_trailer_by_sector(&nfc_keys->dev_data.mf_classic_data, i);
|
||||||
|
mu_assert(memcmp(sec_tr->key_a, default_key, 6) == 0, "Failed key compare");
|
||||||
|
mu_assert(memcmp(sec_tr->key_b, default_key, 6) == 0, "Failed key compare");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete key cache file
|
||||||
|
mu_assert(
|
||||||
|
storage_common_remove(nfc_keys->storage, furi_string_get_cstr(key_cache_name)) == FSE_OK,
|
||||||
|
"Failed to remove key cache file");
|
||||||
|
furi_string_free(key_cache_name);
|
||||||
|
nfc_device_free(nfc_keys);
|
||||||
|
}
|
||||||
|
|
||||||
|
MU_TEST(mf_classic_1k_4b_file_test) {
|
||||||
|
mf_classic_generator_test(4, MfClassicType1k);
|
||||||
|
}
|
||||||
|
|
||||||
|
MU_TEST(mf_classic_4k_4b_file_test) {
|
||||||
|
mf_classic_generator_test(4, MfClassicType4k);
|
||||||
|
}
|
||||||
|
|
||||||
|
MU_TEST(mf_classic_1k_7b_file_test) {
|
||||||
|
mf_classic_generator_test(7, MfClassicType1k);
|
||||||
|
}
|
||||||
|
|
||||||
|
MU_TEST(mf_classic_4k_7b_file_test) {
|
||||||
|
mf_classic_generator_test(7, MfClassicType4k);
|
||||||
|
}
|
||||||
|
|
||||||
MU_TEST_SUITE(nfc) {
|
MU_TEST_SUITE(nfc) {
|
||||||
nfc_test_alloc();
|
nfc_test_alloc();
|
||||||
|
|
||||||
|
MU_RUN_TEST(nfca_file_test);
|
||||||
|
MU_RUN_TEST(mf_classic_1k_4b_file_test);
|
||||||
|
MU_RUN_TEST(mf_classic_4k_4b_file_test);
|
||||||
|
MU_RUN_TEST(mf_classic_1k_7b_file_test);
|
||||||
|
MU_RUN_TEST(mf_classic_4k_7b_file_test);
|
||||||
MU_RUN_TEST(nfc_digital_signal_test);
|
MU_RUN_TEST(nfc_digital_signal_test);
|
||||||
MU_RUN_TEST(mf_classic_dict_test);
|
MU_RUN_TEST(mf_classic_dict_test);
|
||||||
MU_RUN_TEST(mf_classic_dict_load_test);
|
MU_RUN_TEST(mf_classic_dict_load_test);
|
||||||
|
|||||||
@@ -314,7 +314,7 @@ static void nfc_generate_ntag_i2c_plus_2k(NfcDeviceData* data) {
|
|||||||
mful->version.storage_size = 0x15;
|
mful->version.storage_size = 0x15;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nfc_generate_mf_classic(NfcDeviceData* data, uint8_t uid_len, MfClassicType type) {
|
void nfc_generate_mf_classic(NfcDeviceData* data, uint8_t uid_len, MfClassicType type) {
|
||||||
nfc_generate_common_start(data);
|
nfc_generate_common_start(data);
|
||||||
nfc_generate_mf_classic_common(data, uid_len, type);
|
nfc_generate_mf_classic_common(data, uid_len, type);
|
||||||
|
|
||||||
@@ -337,6 +337,9 @@ static void nfc_generate_mf_classic(NfcDeviceData* data, uint8_t uid_len, MfClas
|
|||||||
}
|
}
|
||||||
mf_classic_set_block_read(mfc, i, &mfc->block[i]);
|
mf_classic_set_block_read(mfc, i, &mfc->block[i]);
|
||||||
}
|
}
|
||||||
|
// Set SAK to 18
|
||||||
|
data->nfc_data.sak = 0x18;
|
||||||
|
|
||||||
} else if(type == MfClassicType1k) {
|
} else if(type == MfClassicType1k) {
|
||||||
// Set every block to 0xFF
|
// Set every block to 0xFF
|
||||||
for(uint16_t i = 1; i < MF_CLASSIC_1K_TOTAL_SECTORS_NUM * 4; i += 1) {
|
for(uint16_t i = 1; i < MF_CLASSIC_1K_TOTAL_SECTORS_NUM * 4; i += 1) {
|
||||||
@@ -347,6 +350,8 @@ static void nfc_generate_mf_classic(NfcDeviceData* data, uint8_t uid_len, MfClas
|
|||||||
}
|
}
|
||||||
mf_classic_set_block_read(mfc, i, &mfc->block[i]);
|
mf_classic_set_block_read(mfc, i, &mfc->block[i]);
|
||||||
}
|
}
|
||||||
|
// Set SAK to 08
|
||||||
|
data->nfc_data.sak = 0x08;
|
||||||
}
|
}
|
||||||
|
|
||||||
mfc->type = type;
|
mfc->type = type;
|
||||||
|
|||||||
@@ -11,3 +11,5 @@ struct NfcGenerator {
|
|||||||
};
|
};
|
||||||
|
|
||||||
extern const NfcGenerator* const nfc_generators[];
|
extern const NfcGenerator* const nfc_generators[];
|
||||||
|
|
||||||
|
void nfc_generate_mf_classic(NfcDeviceData* data, uint8_t uid_len, MfClassicType type);
|
||||||
|
|||||||
@@ -116,7 +116,9 @@ void nfc_free(Nfc* nfc) {
|
|||||||
// Stop worker
|
// Stop worker
|
||||||
nfc_worker_stop(nfc->worker);
|
nfc_worker_stop(nfc->worker);
|
||||||
// Save data in shadow file
|
// Save data in shadow file
|
||||||
nfc_device_save_shadow(nfc->dev, nfc->dev->dev_name);
|
if(furi_string_size(nfc->dev->load_path)) {
|
||||||
|
nfc_device_save_shadow(nfc->dev, furi_string_get_cstr(nfc->dev->load_path));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if(nfc->rpc_ctx) {
|
if(nfc->rpc_ctx) {
|
||||||
rpc_system_app_send_exited(nfc->rpc_ctx);
|
rpc_system_app_send_exited(nfc->rpc_ctx);
|
||||||
@@ -218,6 +220,13 @@ void nfc_blink_stop(Nfc* nfc) {
|
|||||||
notification_message(nfc->notifications, &sequence_blink_stop);
|
notification_message(nfc->notifications, &sequence_blink_stop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool nfc_save_file(Nfc* nfc) {
|
||||||
|
furi_string_printf(
|
||||||
|
nfc->dev->load_path, "%s/%s%s", NFC_APP_FOLDER, nfc->dev->dev_name, NFC_APP_EXTENSION);
|
||||||
|
bool file_saved = nfc_device_save(nfc->dev, furi_string_get_cstr(nfc->dev->load_path));
|
||||||
|
return file_saved;
|
||||||
|
}
|
||||||
|
|
||||||
void nfc_show_loading_popup(void* context, bool show) {
|
void nfc_show_loading_popup(void* context, bool show) {
|
||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
TaskHandle_t timer_task = xTaskGetHandle(configTIMER_SERVICE_TASK_NAME);
|
TaskHandle_t timer_task = xTaskGetHandle(configTIMER_SERVICE_TASK_NAME);
|
||||||
|
|||||||
@@ -114,4 +114,6 @@ void nfc_blink_detect_start(Nfc* nfc);
|
|||||||
|
|
||||||
void nfc_blink_stop(Nfc* nfc);
|
void nfc_blink_stop(Nfc* nfc);
|
||||||
|
|
||||||
|
bool nfc_save_file(Nfc* nfc);
|
||||||
|
|
||||||
void nfc_show_loading_popup(void* context, bool show);
|
void nfc_show_loading_popup(void* context, bool show);
|
||||||
|
|||||||
@@ -60,3 +60,4 @@ ADD_SCENE(nfc, detect_reader, DetectReader)
|
|||||||
ADD_SCENE(nfc, mfkey_nonces_info, MfkeyNoncesInfo)
|
ADD_SCENE(nfc, mfkey_nonces_info, MfkeyNoncesInfo)
|
||||||
ADD_SCENE(nfc, mfkey_complete, MfkeyComplete)
|
ADD_SCENE(nfc, mfkey_complete, MfkeyComplete)
|
||||||
ADD_SCENE(nfc, nfc_data_info, NfcDataInfo)
|
ADD_SCENE(nfc, nfc_data_info, NfcDataInfo)
|
||||||
|
ADD_SCENE(nfc, read_card_type, ReadCardType)
|
||||||
|
|||||||
@@ -29,9 +29,14 @@ bool nfc_scene_exit_confirm_on_event(void* context, SceneManagerEvent event) {
|
|||||||
if(event.event == DialogExResultRight) {
|
if(event.event == DialogExResultRight) {
|
||||||
consumed = scene_manager_previous_scene(nfc->scene_manager);
|
consumed = scene_manager_previous_scene(nfc->scene_manager);
|
||||||
} else if(event.event == DialogExResultLeft) {
|
} else if(event.event == DialogExResultLeft) {
|
||||||
|
if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneReadCardType)) {
|
||||||
|
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||||
|
nfc->scene_manager, NfcSceneReadCardType);
|
||||||
|
} 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);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else if(event.type == SceneManagerEventTypeBack) {
|
} else if(event.type == SceneManagerEventTypeBack) {
|
||||||
consumed = true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "../nfc_i.h"
|
#include "../nfc_i.h"
|
||||||
|
|
||||||
enum SubmenuIndex {
|
enum SubmenuIndex {
|
||||||
|
SubmenuIndexReadCardType,
|
||||||
SubmenuIndexMfClassicKeys,
|
SubmenuIndexMfClassicKeys,
|
||||||
SubmenuIndexMfUltralightUnlock,
|
SubmenuIndexMfUltralightUnlock,
|
||||||
};
|
};
|
||||||
@@ -15,6 +16,12 @@ void nfc_scene_extra_actions_on_enter(void* context) {
|
|||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
Submenu* submenu = nfc->submenu;
|
Submenu* submenu = nfc->submenu;
|
||||||
|
|
||||||
|
submenu_add_item(
|
||||||
|
submenu,
|
||||||
|
"Read Specific Card Type",
|
||||||
|
SubmenuIndexReadCardType,
|
||||||
|
nfc_scene_extra_actions_submenu_callback,
|
||||||
|
nfc);
|
||||||
submenu_add_item(
|
submenu_add_item(
|
||||||
submenu,
|
submenu,
|
||||||
"Mifare Classic Keys",
|
"Mifare Classic Keys",
|
||||||
@@ -44,9 +51,15 @@ bool nfc_scene_extra_actions_on_event(void* context, SceneManagerEvent event) {
|
|||||||
consumed = true;
|
consumed = true;
|
||||||
} else if(event.event == SubmenuIndexMfUltralightUnlock) {
|
} else if(event.event == SubmenuIndexMfUltralightUnlock) {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockMenu);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockMenu);
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == SubmenuIndexReadCardType) {
|
||||||
|
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneReadCardType, 0);
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardType);
|
||||||
|
consumed = true;
|
||||||
}
|
}
|
||||||
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneExtraActions, event.event);
|
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneExtraActions, event.event);
|
||||||
}
|
}
|
||||||
|
|
||||||
return consumed;
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ void nfc_scene_file_select_on_enter(void* context) {
|
|||||||
Nfc* nfc = context;
|
Nfc* nfc = context;
|
||||||
// Process file_select return
|
// Process file_select return
|
||||||
nfc_device_set_loading_callback(nfc->dev, nfc_show_loading_popup, nfc);
|
nfc_device_set_loading_callback(nfc->dev, nfc_show_loading_popup, nfc);
|
||||||
|
if(!furi_string_size(nfc->dev->load_path)) {
|
||||||
|
furi_string_set_str(nfc->dev->load_path, NFC_APP_FOLDER);
|
||||||
|
}
|
||||||
if(nfc_file_select(nfc->dev)) {
|
if(nfc_file_select(nfc->dev)) {
|
||||||
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneSavedMenu, 0);
|
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneSavedMenu, 0);
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneSavedMenu);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneSavedMenu);
|
||||||
|
|||||||
@@ -48,7 +48,10 @@ bool nfc_scene_mf_classic_emulate_on_event(void* context, SceneManagerEvent even
|
|||||||
NFC_MF_CLASSIC_DATA_CHANGED) {
|
NFC_MF_CLASSIC_DATA_CHANGED) {
|
||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
nfc->scene_manager, NfcSceneMfClassicEmulate, 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);
|
// Save shadow file
|
||||||
|
if(furi_string_size(nfc->dev->load_path)) {
|
||||||
|
nfc_device_save_shadow(nfc->dev, furi_string_get_cstr(nfc->dev->load_path));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
consumed = false;
|
consumed = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ bool nfc_scene_mf_classic_update_on_event(void* context, SceneManagerEvent event
|
|||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
if(event.event == NfcWorkerEventSuccess) {
|
if(event.event == NfcWorkerEventSuccess) {
|
||||||
nfc_worker_stop(nfc->worker);
|
nfc_worker_stop(nfc->worker);
|
||||||
if(nfc_device_save_shadow(nfc->dev, nfc->dev->dev_name)) {
|
if(nfc_device_save_shadow(nfc->dev, furi_string_get_cstr(nfc->dev->load_path))) {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicUpdateSuccess);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicUpdateSuccess);
|
||||||
} else {
|
} else {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicWrongCard);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicWrongCard);
|
||||||
|
|||||||
@@ -48,7 +48,10 @@ bool nfc_scene_mf_ultralight_emulate_on_event(void* context, SceneManagerEvent e
|
|||||||
NFC_MF_UL_DATA_CHANGED) {
|
NFC_MF_UL_DATA_CHANGED) {
|
||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
nfc->scene_manager, NfcSceneMfUltralightEmulate, 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);
|
// Save shadow file
|
||||||
|
if(furi_string_size(nfc->dev->load_path)) {
|
||||||
|
nfc_device_save_shadow(nfc->dev, furi_string_get_cstr(nfc->dev->load_path));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
consumed = false;
|
consumed = false;
|
||||||
}
|
}
|
||||||
|
|||||||
97
applications/main/nfc/scenes/nfc_scene_read_card_type.c
Normal file
97
applications/main/nfc/scenes/nfc_scene_read_card_type.c
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
#include "../nfc_i.h"
|
||||||
|
#include "nfc_worker_i.h"
|
||||||
|
|
||||||
|
enum SubmenuIndex {
|
||||||
|
SubmenuIndexReadMifareClassic,
|
||||||
|
SubmenuIndexReadMifareDesfire,
|
||||||
|
SubmenuIndexReadMfUltralight,
|
||||||
|
SubmenuIndexReadEMV,
|
||||||
|
SubmenuIndexReadNFCA,
|
||||||
|
};
|
||||||
|
|
||||||
|
void nfc_scene_read_card_type_submenu_callback(void* context, uint32_t index) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_read_card_type_on_enter(void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
Submenu* submenu = nfc->submenu;
|
||||||
|
|
||||||
|
submenu_add_item(
|
||||||
|
submenu,
|
||||||
|
"Read Mifare Classic",
|
||||||
|
SubmenuIndexReadMifareClassic,
|
||||||
|
nfc_scene_read_card_type_submenu_callback,
|
||||||
|
nfc);
|
||||||
|
submenu_add_item(
|
||||||
|
submenu,
|
||||||
|
"Read Mifare DESFire",
|
||||||
|
SubmenuIndexReadMifareDesfire,
|
||||||
|
nfc_scene_read_card_type_submenu_callback,
|
||||||
|
nfc);
|
||||||
|
submenu_add_item(
|
||||||
|
submenu,
|
||||||
|
"Read NTAG/Ultralight",
|
||||||
|
SubmenuIndexReadMfUltralight,
|
||||||
|
nfc_scene_read_card_type_submenu_callback,
|
||||||
|
nfc);
|
||||||
|
submenu_add_item(
|
||||||
|
submenu,
|
||||||
|
"Read EMV card",
|
||||||
|
SubmenuIndexReadEMV,
|
||||||
|
nfc_scene_read_card_type_submenu_callback,
|
||||||
|
nfc);
|
||||||
|
submenu_add_item(
|
||||||
|
submenu,
|
||||||
|
"Read NFC-A data",
|
||||||
|
SubmenuIndexReadNFCA,
|
||||||
|
nfc_scene_read_card_type_submenu_callback,
|
||||||
|
nfc);
|
||||||
|
uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadCardType);
|
||||||
|
submenu_set_selected_item(submenu, state);
|
||||||
|
|
||||||
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nfc_scene_read_card_type_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
|
if(event.event == SubmenuIndexReadMifareClassic) {
|
||||||
|
nfc->dev->dev_data.read_mode = NfcReadModeMfClassic;
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneRead);
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
if(event.event == SubmenuIndexReadMifareDesfire) {
|
||||||
|
nfc->dev->dev_data.read_mode = NfcReadModeMfDesfire;
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneRead);
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
if(event.event == SubmenuIndexReadMfUltralight) {
|
||||||
|
nfc->dev->dev_data.read_mode = NfcReadModeMfUltralight;
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneRead);
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
if(event.event == SubmenuIndexReadEMV) {
|
||||||
|
nfc->dev->dev_data.read_mode = NfcReadModeEMV;
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneRead);
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
if(event.event == SubmenuIndexReadNFCA) {
|
||||||
|
nfc->dev->dev_data.read_mode = NfcReadModeNFCA;
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneRead);
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneReadCardType, event.event);
|
||||||
|
}
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_scene_read_card_type_on_exit(void* context) {
|
||||||
|
Nfc* nfc = context;
|
||||||
|
|
||||||
|
submenu_reset(nfc->submenu);
|
||||||
|
}
|
||||||
@@ -62,7 +62,7 @@ bool nfc_scene_save_name_on_event(void* context, SceneManagerEvent event) {
|
|||||||
nfc->dev->dev_data.nfc_data = nfc->dev_edit_data;
|
nfc->dev->dev_data.nfc_data = nfc->dev_edit_data;
|
||||||
}
|
}
|
||||||
strlcpy(nfc->dev->dev_name, nfc->text_store, strlen(nfc->text_store) + 1);
|
strlcpy(nfc->dev->dev_name, nfc->text_store, strlen(nfc->text_store) + 1);
|
||||||
if(nfc_device_save(nfc->dev, nfc->text_store)) {
|
if(nfc_save_file(nfc)) {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess);
|
||||||
if(!scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSavedMenu)) {
|
if(!scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSavedMenu)) {
|
||||||
// Nothing, do not count editing as saving
|
// Nothing, do not count editing as saving
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ bool nfc_scene_set_uid_on_event(void* context, SceneManagerEvent event) {
|
|||||||
if(event.event == NfcCustomEventByteInputDone) {
|
if(event.event == NfcCustomEventByteInputDone) {
|
||||||
if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSavedMenu)) {
|
if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSavedMenu)) {
|
||||||
nfc->dev->dev_data.nfc_data = nfc->dev_edit_data;
|
nfc->dev->dev_data.nfc_data = nfc->dev_edit_data;
|
||||||
if(nfc_device_save(nfc->dev, nfc->dev->dev_name)) {
|
if(nfc_save_file(nfc)) {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
@@ -41,6 +41,7 @@ bool nfc_scene_set_uid_on_event(void* context, SceneManagerEvent event) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return consumed;
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "../nfc_i.h"
|
#include "../nfc_i.h"
|
||||||
|
#include "nfc_worker_i.h"
|
||||||
#include <dolphin/dolphin.h>
|
#include <dolphin/dolphin.h>
|
||||||
|
|
||||||
enum SubmenuIndex {
|
enum SubmenuIndex {
|
||||||
@@ -47,6 +48,7 @@ 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) {
|
||||||
|
nfc->dev->dev_data.read_mode = NfcReadModeAuto;
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneRead);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneRead);
|
||||||
DOLPHIN_DEED(DolphinDeedNfcRead);
|
DOLPHIN_DEED(DolphinDeedNfcRead);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
|
|||||||
@@ -46,23 +46,47 @@ bool subghz_scene_more_raw_on_event(void* context, SceneManagerEvent event) {
|
|||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
if(event.event == SubmenuIndexDelete) {
|
if(event.event == SubmenuIndexDelete) {
|
||||||
|
if(subghz_file_available(subghz)) {
|
||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerNoSet);
|
subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerNoSet);
|
||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
subghz->scene_manager, SubGhzSceneMoreRAW, SubmenuIndexDelete);
|
subghz->scene_manager, SubGhzSceneMoreRAW, SubmenuIndexDelete);
|
||||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneDeleteRAW);
|
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneDeleteRAW);
|
||||||
return true;
|
return true;
|
||||||
|
} else {
|
||||||
|
if(!scene_manager_search_and_switch_to_previous_scene(
|
||||||
|
subghz->scene_manager, SubGhzSceneStart)) {
|
||||||
|
scene_manager_stop(subghz->scene_manager);
|
||||||
|
view_dispatcher_stop(subghz->view_dispatcher);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if(event.event == SubmenuIndexEdit) {
|
} else if(event.event == SubmenuIndexEdit) {
|
||||||
|
if(subghz_file_available(subghz)) {
|
||||||
furi_string_reset(subghz->file_path_tmp);
|
furi_string_reset(subghz->file_path_tmp);
|
||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
subghz->scene_manager, SubGhzSceneMoreRAW, SubmenuIndexEdit);
|
subghz->scene_manager, SubGhzSceneMoreRAW, SubmenuIndexEdit);
|
||||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName);
|
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName);
|
||||||
return true;
|
return true;
|
||||||
|
} else {
|
||||||
|
if(!scene_manager_search_and_switch_to_previous_scene(
|
||||||
|
subghz->scene_manager, SubGhzSceneStart)) {
|
||||||
|
scene_manager_stop(subghz->scene_manager);
|
||||||
|
view_dispatcher_stop(subghz->view_dispatcher);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if(event.event == SubmenuIndexDecode) {
|
} else if(event.event == SubmenuIndexDecode) {
|
||||||
|
if(subghz_file_available(subghz)) {
|
||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
subghz->scene_manager, SubGhzSceneMoreRAW, SubmenuIndexDecode);
|
subghz->scene_manager, SubGhzSceneMoreRAW, SubmenuIndexDecode);
|
||||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneDecodeRAW);
|
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneDecodeRAW);
|
||||||
return true;
|
return true;
|
||||||
|
} else {
|
||||||
|
if(!scene_manager_search_and_switch_to_previous_scene(
|
||||||
|
subghz->scene_manager, SubGhzSceneStart)) {
|
||||||
|
scene_manager_stop(subghz->scene_manager);
|
||||||
|
view_dispatcher_stop(subghz->view_dispatcher);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -210,6 +210,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SubGhzCustomEventViewReadRAWMore:
|
case SubGhzCustomEventViewReadRAWMore:
|
||||||
|
if(subghz_file_available(subghz)) {
|
||||||
if(subghz_scene_read_raw_update_filename(subghz)) {
|
if(subghz_scene_read_raw_update_filename(subghz)) {
|
||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerSet);
|
subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerSet);
|
||||||
@@ -219,11 +220,18 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
|
|||||||
} else {
|
} else {
|
||||||
furi_crash("SubGhz: RAW file name update error.");
|
furi_crash("SubGhz: RAW file name update error.");
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if(!scene_manager_search_and_switch_to_previous_scene(
|
||||||
|
subghz->scene_manager, SubGhzSceneStart)) {
|
||||||
|
scene_manager_stop(subghz->scene_manager);
|
||||||
|
view_dispatcher_stop(subghz->view_dispatcher);
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SubGhzCustomEventViewReadRAWSendStart:
|
case SubGhzCustomEventViewReadRAWSendStart:
|
||||||
|
|
||||||
if(subghz_scene_read_raw_update_filename(subghz)) {
|
if(subghz_file_available(subghz) && subghz_scene_read_raw_update_filename(subghz)) {
|
||||||
//start send
|
//start send
|
||||||
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
||||||
if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
|
if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
|
||||||
@@ -250,6 +258,12 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
|
|||||||
subghz->state_notifications = SubGhzNotificationStateTx;
|
subghz->state_notifications = SubGhzNotificationStateTx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if(!scene_manager_search_and_switch_to_previous_scene(
|
||||||
|
subghz->scene_manager, SubGhzSceneStart)) {
|
||||||
|
scene_manager_stop(subghz->scene_manager);
|
||||||
|
view_dispatcher_stop(subghz->view_dispatcher);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
consumed = true;
|
consumed = true;
|
||||||
break;
|
break;
|
||||||
@@ -326,11 +340,17 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SubGhzCustomEventViewReadRAWSave:
|
case SubGhzCustomEventViewReadRAWSave:
|
||||||
if(subghz_scene_read_raw_update_filename(subghz)) {
|
if(subghz_file_available(subghz) && subghz_scene_read_raw_update_filename(subghz)) {
|
||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerSetRAW);
|
subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerSetRAW);
|
||||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateBack;
|
subghz->txrx->rx_key_state = SubGhzRxKeyStateBack;
|
||||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName);
|
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName);
|
||||||
|
} else {
|
||||||
|
if(!scene_manager_search_and_switch_to_previous_scene(
|
||||||
|
subghz->scene_manager, SubGhzSceneStart)) {
|
||||||
|
scene_manager_stop(subghz->scene_manager);
|
||||||
|
view_dispatcher_stop(subghz->view_dispatcher);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
consumed = true;
|
consumed = true;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -497,6 +497,23 @@ bool subghz_rename_file(SubGhz* subghz) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool subghz_file_available(SubGhz* subghz) {
|
||||||
|
furi_assert(subghz);
|
||||||
|
bool ret = true;
|
||||||
|
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||||
|
|
||||||
|
FS_Error fs_result =
|
||||||
|
storage_common_stat(storage, furi_string_get_cstr(subghz->file_path), NULL);
|
||||||
|
|
||||||
|
if(fs_result != FSE_OK) {
|
||||||
|
dialog_message_show_storage_error(subghz->dialogs, "File not available\n file/directory");
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
furi_record_close(RECORD_STORAGE);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
bool subghz_delete_file(SubGhz* subghz) {
|
bool subghz_delete_file(SubGhz* subghz) {
|
||||||
furi_assert(subghz);
|
furi_assert(subghz);
|
||||||
|
|
||||||
|
|||||||
@@ -153,6 +153,7 @@ bool subghz_save_protocol_to_file(
|
|||||||
const char* dev_file_name);
|
const char* dev_file_name);
|
||||||
bool subghz_load_protocol_from_file(SubGhz* subghz);
|
bool subghz_load_protocol_from_file(SubGhz* subghz);
|
||||||
bool subghz_rename_file(SubGhz* subghz);
|
bool subghz_rename_file(SubGhz* subghz);
|
||||||
|
bool subghz_file_available(SubGhz* subghz);
|
||||||
bool subghz_delete_file(SubGhz* subghz);
|
bool subghz_delete_file(SubGhz* subghz);
|
||||||
void subghz_file_name_clear(SubGhz* subghz);
|
void subghz_file_name_clear(SubGhz* subghz);
|
||||||
bool subghz_path_is_file(FuriString* path);
|
bool subghz_path_is_file(FuriString* path);
|
||||||
|
|||||||
@@ -210,5 +210,5 @@ bool magic_wipe() {
|
|||||||
|
|
||||||
void magic_deactivate() {
|
void magic_deactivate() {
|
||||||
furi_hal_nfc_ll_txrx_off();
|
furi_hal_nfc_ll_txrx_off();
|
||||||
furi_hal_nfc_start_sleep();
|
furi_hal_nfc_sleep();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -167,7 +167,6 @@ void nfc_magic_worker_wipe(NfcMagicWorker* nfc_magic_worker) {
|
|||||||
if(!magic_data_access_cmd()) continue;
|
if(!magic_data_access_cmd()) continue;
|
||||||
if(!magic_write_blk(0, &block)) continue;
|
if(!magic_write_blk(0, &block)) continue;
|
||||||
nfc_magic_worker->callback(NfcMagicWorkerEventSuccess, nfc_magic_worker->context);
|
nfc_magic_worker->callback(NfcMagicWorkerEventSuccess, nfc_magic_worker->context);
|
||||||
magic_deactivate();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
magic_deactivate();
|
magic_deactivate();
|
||||||
|
|||||||
@@ -372,7 +372,7 @@ RpcSession* rpc_session_open(Rpc* rpc) {
|
|||||||
|
|
||||||
session->thread = furi_thread_alloc();
|
session->thread = furi_thread_alloc();
|
||||||
furi_thread_set_name(session->thread, "RpcSessionWorker");
|
furi_thread_set_name(session->thread, "RpcSessionWorker");
|
||||||
furi_thread_set_stack_size(session->thread, 2048);
|
furi_thread_set_stack_size(session->thread, 3072);
|
||||||
furi_thread_set_context(session->thread, session);
|
furi_thread_set_context(session->thread, session);
|
||||||
furi_thread_set_callback(session->thread, rpc_session_worker);
|
furi_thread_set_callback(session->thread, rpc_session_worker);
|
||||||
|
|
||||||
|
|||||||
2
documentation/.gitignore
vendored
Normal file
2
documentation/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
/html
|
||||||
|
/latex
|
||||||
@@ -40,6 +40,7 @@ Only 2 parameters are mandatory: ***appid*** and ***apptype***, others are optio
|
|||||||
* **icon**: Animated icon name from built-in assets to be used when building app as a part of firmware.
|
* **icon**: Animated icon name from built-in assets to be used when building app as a part of firmware.
|
||||||
* **order**: Order of an application within its group when sorting entries in it. The lower the order is, the closer to the start of the list the item is placed. *Used for ordering startup hooks and menu entries.*
|
* **order**: Order of an application within its group when sorting entries in it. The lower the order is, the closer to the start of the list the item is placed. *Used for ordering startup hooks and menu entries.*
|
||||||
* **sdk_headers**: List of C header files from this app's code to include in API definitions for external applications.
|
* **sdk_headers**: List of C header files from this app's code to include in API definitions for external applications.
|
||||||
|
* **targets**: list of strings, target names, which this application is compatible with. If not specified, application is built for all targets. Default value is `["all"]`.
|
||||||
|
|
||||||
|
|
||||||
#### Parameters for external applications
|
#### Parameters for external applications
|
||||||
|
|||||||
@@ -872,12 +872,9 @@ WARN_LOGFILE =
|
|||||||
# Note: If this tag is empty the current directory is searched.
|
# Note: If this tag is empty the current directory is searched.
|
||||||
|
|
||||||
INPUT = applications \
|
INPUT = applications \
|
||||||
core \
|
lib \
|
||||||
lib/infrared \
|
firmware \
|
||||||
lib/subghz \
|
furi
|
||||||
lib/toolbox \
|
|
||||||
lib/onewire \
|
|
||||||
firmware/targets/furi_hal_include
|
|
||||||
|
|
||||||
# This tag can be used to specify the character encoding of the source files
|
# This tag can be used to specify the character encoding of the source files
|
||||||
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
|
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
|
||||||
@@ -930,7 +927,18 @@ RECURSIVE = YES
|
|||||||
# Note that relative paths are relative to the directory from which doxygen is
|
# Note that relative paths are relative to the directory from which doxygen is
|
||||||
# run.
|
# run.
|
||||||
|
|
||||||
EXCLUDE =
|
EXCLUDE = \
|
||||||
|
lib/mlib \
|
||||||
|
lib/STM32CubeWB \
|
||||||
|
lib/littlefs \
|
||||||
|
lib/nanopb \
|
||||||
|
assets/protobuf \
|
||||||
|
lib/libusb_stm32 \
|
||||||
|
lib/FreeRTOS-Kernel \
|
||||||
|
lib/microtar \
|
||||||
|
lib/mbedtls \
|
||||||
|
lib/cxxheaderparser \
|
||||||
|
applications/plugins/dap_link/lib/free-dap
|
||||||
|
|
||||||
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
|
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
|
||||||
# directories that are symbolic links (a Unix file system feature) are excluded
|
# directories that are symbolic links (a Unix file system feature) are excluded
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Key Combos
|
# Key Combos
|
||||||
|
|
||||||
There are times when your flipper feels blue and don't respond to your commands.
|
There are times when your flipper feels blue and doesn't respond to your commands.
|
||||||
In that case you may find this guide useful.
|
In that case, you may find this guide useful.
|
||||||
|
|
||||||
|
|
||||||
## Basic Combos
|
## Basic Combos
|
||||||
@@ -9,7 +9,7 @@ In that case you may find this guide useful.
|
|||||||
|
|
||||||
### Hardware Reset
|
### Hardware Reset
|
||||||
|
|
||||||
- Press `LEFT` and `BACK` and hold for couple seconds
|
- Press `LEFT` and `BACK` and hold for a couple of seconds
|
||||||
- Release `LEFT` and `BACK`
|
- Release `LEFT` and `BACK`
|
||||||
|
|
||||||
This combo performs hardware reset by pulling MCU reset line down.
|
This combo performs hardware reset by pulling MCU reset line down.
|
||||||
@@ -29,7 +29,7 @@ There is 1 case when it's not working:
|
|||||||
- If you have not disconnected USB, then disconnect USB and repeat previous step
|
- If you have not disconnected USB, then disconnect USB and repeat previous step
|
||||||
- Release `BACK` key
|
- Release `BACK` key
|
||||||
|
|
||||||
This combo performs reset by switching SYS power line off and then on.
|
This combo performs a reset by switching SYS power line off and then on.
|
||||||
Main components involved: Keys -> DD6(bq25896, charger)
|
Main components involved: Keys -> DD6(bq25896, charger)
|
||||||
|
|
||||||
There is 1 case when it's not working:
|
There is 1 case when it's not working:
|
||||||
@@ -60,13 +60,13 @@ There is 1 case when it's not working:
|
|||||||
|
|
||||||
### Hardware Reset + Software DFU
|
### Hardware Reset + Software DFU
|
||||||
|
|
||||||
- Press `LEFT` and `BACK` and hold for couple seconds
|
- Press `LEFT` and `BACK` and hold for a couple of seconds
|
||||||
- Release `BACK`
|
- Release `BACK`
|
||||||
- Device will enter DFU with indication (Blue LED + DFU Screen)
|
- Device will enter DFU with indication (Blue LED + DFU Screen)
|
||||||
- Release `LEFT`
|
- Release `LEFT`
|
||||||
|
|
||||||
This combo performs hardware reset by pulling MCU reset line down.
|
This combo performs hardware reset by pulling MCU reset line down.
|
||||||
Then `LEFT` key indicates to boot-loader that DFU mode requested.
|
Then `LEFT` key indicates to boot-loader that DFU mode is requested.
|
||||||
|
|
||||||
There are 2 cases when it's not working:
|
There are 2 cases when it's not working:
|
||||||
|
|
||||||
@@ -76,7 +76,7 @@ There are 2 cases when it's not working:
|
|||||||
|
|
||||||
### Hardware Reset + Hardware DFU
|
### Hardware Reset + Hardware DFU
|
||||||
|
|
||||||
- Press `LEFT` and `BACK` and `OK` and hold for couple seconds
|
- Press `LEFT` and `BACK` and `OK` and hold for a couple of seconds
|
||||||
- Release `BACK` and `LEFT`
|
- Release `BACK` and `LEFT`
|
||||||
- Device will enter DFU without indication
|
- Device will enter DFU without indication
|
||||||
|
|
||||||
@@ -127,8 +127,8 @@ There are 2 cases when it's not working:
|
|||||||
|
|
||||||
If none of the described methods were useful:
|
If none of the described methods were useful:
|
||||||
|
|
||||||
- Ensure battery charged
|
- Ensure the battery charged
|
||||||
- Disconnect battery and connect again (Requires disassembly)
|
- Disconnect the battery and connect again (Requires disassembly)
|
||||||
- Try to Flash device with ST-Link or other programmer that support SWD
|
- Try to Flash device with ST-Link or other programmer that supports SWD
|
||||||
|
|
||||||
If you still here and your device is not working: it's not software issue.
|
If you still here and your device is not working: it's not a software issue.
|
||||||
|
|||||||
@@ -77,6 +77,12 @@ FIRMWARE_APPS = {
|
|||||||
# Debug
|
# Debug
|
||||||
# "debug_apps",
|
# "debug_apps",
|
||||||
],
|
],
|
||||||
|
"unit_tests": [
|
||||||
|
"basic_services",
|
||||||
|
"updater_app",
|
||||||
|
"unit_tests",
|
||||||
|
"nfc",
|
||||||
|
],
|
||||||
"debug_pack": [
|
"debug_pack": [
|
||||||
# Svc
|
# Svc
|
||||||
"basic_services",
|
"basic_services",
|
||||||
|
|||||||
@@ -40,11 +40,11 @@ env = ENV.Clone(
|
|||||||
FW_LIB_OPTS={
|
FW_LIB_OPTS={
|
||||||
"Default": {
|
"Default": {
|
||||||
"CCFLAGS": [
|
"CCFLAGS": [
|
||||||
"-Os",
|
"-Og" if ENV["LIB_DEBUG"] else "-Os",
|
||||||
],
|
],
|
||||||
"CPPDEFINES": [
|
"CPPDEFINES": [
|
||||||
"NDEBUG",
|
"NDEBUG",
|
||||||
"FURI_NDEBUG",
|
"FURI_DEBUG" if ENV["LIB_DEBUG"] else "FURI_NDEBUG",
|
||||||
],
|
],
|
||||||
# You can add other entries named after libraries
|
# You can add other entries named after libraries
|
||||||
# If they are present, they have precedence over Default
|
# If they are present, they have precedence over Default
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
entry,status,name,type,params
|
entry,status,name,type,params
|
||||||
Version,+,7.32,,
|
Version,+,7.41,,
|
||||||
Header,+,applications/services/bt/bt_service/bt.h,,
|
Header,+,applications/services/bt/bt_service/bt.h,,
|
||||||
Header,+,applications/services/cli/cli.h,,
|
Header,+,applications/services/cli/cli.h,,
|
||||||
Header,+,applications/services/cli/cli_vcp.h,,
|
Header,+,applications/services/cli/cli_vcp.h,,
|
||||||
@@ -1865,6 +1865,7 @@ Function,-,mf_classic_get_read_sectors_and_keys,void,"MfClassicData*, uint8_t*,
|
|||||||
Function,-,mf_classic_get_sector_by_block,uint8_t,uint8_t
|
Function,-,mf_classic_get_sector_by_block,uint8_t,uint8_t
|
||||||
Function,-,mf_classic_get_sector_trailer_block_num_by_sector,uint8_t,uint8_t
|
Function,-,mf_classic_get_sector_trailer_block_num_by_sector,uint8_t,uint8_t
|
||||||
Function,-,mf_classic_get_sector_trailer_by_sector,MfClassicSectorTrailer*,"MfClassicData*, uint8_t"
|
Function,-,mf_classic_get_sector_trailer_by_sector,MfClassicSectorTrailer*,"MfClassicData*, uint8_t"
|
||||||
|
Function,-,mf_classic_get_total_block_num,uint16_t,MfClassicType
|
||||||
Function,-,mf_classic_get_total_sectors_num,uint8_t,MfClassicType
|
Function,-,mf_classic_get_total_sectors_num,uint8_t,MfClassicType
|
||||||
Function,-,mf_classic_get_type_str,const char*,MfClassicType
|
Function,-,mf_classic_get_type_str,const char*,MfClassicType
|
||||||
Function,-,mf_classic_is_allowed_access_data_block,_Bool,"MfClassicData*, uint8_t, MfClassicKey, MfClassicAction"
|
Function,-,mf_classic_is_allowed_access_data_block,_Bool,"MfClassicData*, uint8_t, MfClassicKey, MfClassicAction"
|
||||||
|
|||||||
|
@@ -1034,12 +1034,7 @@ static void nfc_device_get_shadow_path(FuriString* orig_path, FuriString* shadow
|
|||||||
furi_string_cat_printf(shadow_path, "%s", NFC_APP_SHADOW_EXTENSION);
|
furi_string_cat_printf(shadow_path, "%s", NFC_APP_SHADOW_EXTENSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool nfc_device_save_file(
|
bool nfc_device_save(NfcDevice* dev, const char* dev_name) {
|
||||||
NfcDevice* dev,
|
|
||||||
const char* dev_name,
|
|
||||||
const char* folder,
|
|
||||||
const char* extension,
|
|
||||||
bool use_load_path) {
|
|
||||||
furi_assert(dev);
|
furi_assert(dev);
|
||||||
|
|
||||||
bool saved = false;
|
bool saved = false;
|
||||||
@@ -1049,19 +1044,10 @@ static bool nfc_device_save_file(
|
|||||||
temp_str = furi_string_alloc();
|
temp_str = furi_string_alloc();
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if(use_load_path && !furi_string_empty(dev->load_path)) {
|
|
||||||
// Get directory name
|
|
||||||
path_extract_dirname(furi_string_get_cstr(dev->load_path), temp_str);
|
|
||||||
// Create nfc directory if necessary
|
|
||||||
if(!storage_simply_mkdir(dev->storage, furi_string_get_cstr(temp_str))) break;
|
|
||||||
// Make path to file to save
|
|
||||||
furi_string_cat_printf(temp_str, "/%s%s", dev_name, extension);
|
|
||||||
} else {
|
|
||||||
// Create nfc directory if necessary
|
// Create nfc directory if necessary
|
||||||
if(!storage_simply_mkdir(dev->storage, NFC_APP_FOLDER)) break;
|
if(!storage_simply_mkdir(dev->storage, NFC_APP_FOLDER)) break;
|
||||||
// First remove nfc device file if it was saved
|
// First remove nfc device file if it was saved
|
||||||
furi_string_printf(temp_str, "%s/%s%s", folder, dev_name, extension);
|
furi_string_printf(temp_str, "%s", dev_name);
|
||||||
}
|
|
||||||
// Open file
|
// Open file
|
||||||
if(!flipper_format_file_open_always(file, furi_string_get_cstr(temp_str))) break;
|
if(!flipper_format_file_open_always(file, furi_string_get_cstr(temp_str))) break;
|
||||||
// Write header
|
// Write header
|
||||||
@@ -1102,13 +1088,19 @@ static bool nfc_device_save_file(
|
|||||||
return saved;
|
return saved;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool nfc_device_save(NfcDevice* dev, const char* dev_name) {
|
bool nfc_device_save_shadow(NfcDevice* dev, const char* path) {
|
||||||
return nfc_device_save_file(dev, dev_name, NFC_APP_FOLDER, NFC_APP_EXTENSION, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool nfc_device_save_shadow(NfcDevice* dev, const char* dev_name) {
|
|
||||||
dev->shadow_file_exist = true;
|
dev->shadow_file_exist = true;
|
||||||
return nfc_device_save_file(dev, dev_name, NFC_APP_FOLDER, NFC_APP_SHADOW_EXTENSION, true);
|
// Replace extension from .nfc to .shd if necessary
|
||||||
|
FuriString* orig_path = furi_string_alloc();
|
||||||
|
furi_string_set_str(orig_path, path);
|
||||||
|
FuriString* shadow_path = furi_string_alloc();
|
||||||
|
nfc_device_get_shadow_path(orig_path, shadow_path);
|
||||||
|
|
||||||
|
bool file_saved = nfc_device_save(dev, furi_string_get_cstr(shadow_path));
|
||||||
|
furi_string_free(orig_path);
|
||||||
|
furi_string_free(shadow_path);
|
||||||
|
|
||||||
|
return file_saved;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool nfc_device_load_data(NfcDevice* dev, FuriString* path, bool show_dialog) {
|
static bool nfc_device_load_data(NfcDevice* dev, FuriString* path, bool show_dialog) {
|
||||||
@@ -1225,7 +1217,7 @@ bool nfc_file_select(NfcDevice* dev) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
bool res =
|
bool res =
|
||||||
dialog_file_browser_show(dev->dialogs, dev->load_path, nfc_app_folder, &browser_options);
|
dialog_file_browser_show(dev->dialogs, dev->load_path, dev->load_path, &browser_options);
|
||||||
|
|
||||||
furi_string_free(nfc_app_folder);
|
furi_string_free(nfc_app_folder);
|
||||||
if(res) {
|
if(res) {
|
||||||
|
|||||||
@@ -51,9 +51,19 @@ typedef struct {
|
|||||||
MfClassicDict* dict;
|
MfClassicDict* dict;
|
||||||
} NfcMfClassicDictAttackData;
|
} NfcMfClassicDictAttackData;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
NfcReadModeAuto,
|
||||||
|
NfcReadModeMfClassic,
|
||||||
|
NfcReadModeMfUltralight,
|
||||||
|
NfcReadModeMfDesfire,
|
||||||
|
NfcReadModeEMV,
|
||||||
|
NfcReadModeNFCA,
|
||||||
|
} NfcReadMode;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
FuriHalNfcDevData nfc_data;
|
FuriHalNfcDevData nfc_data;
|
||||||
NfcProtocol protocol;
|
NfcProtocol protocol;
|
||||||
|
NfcReadMode read_mode;
|
||||||
union {
|
union {
|
||||||
NfcReaderRequestData reader_data;
|
NfcReaderRequestData reader_data;
|
||||||
NfcMfClassicDictAttackData mf_classic_dict_attack_data;
|
NfcMfClassicDictAttackData mf_classic_dict_attack_data;
|
||||||
|
|||||||
@@ -90,7 +90,11 @@ int32_t nfc_worker_task(void* context) {
|
|||||||
furi_hal_nfc_exit_sleep();
|
furi_hal_nfc_exit_sleep();
|
||||||
|
|
||||||
if(nfc_worker->state == NfcWorkerStateRead) {
|
if(nfc_worker->state == NfcWorkerStateRead) {
|
||||||
|
if(nfc_worker->dev_data->read_mode == NfcReadModeAuto) {
|
||||||
nfc_worker_read(nfc_worker);
|
nfc_worker_read(nfc_worker);
|
||||||
|
} else {
|
||||||
|
nfc_worker_read_type(nfc_worker);
|
||||||
|
}
|
||||||
} else if(nfc_worker->state == NfcWorkerStateUidEmulate) {
|
} else if(nfc_worker->state == NfcWorkerStateUidEmulate) {
|
||||||
nfc_worker_emulate_uid(nfc_worker);
|
nfc_worker_emulate_uid(nfc_worker);
|
||||||
} else if(nfc_worker->state == NfcWorkerStateEmulateApdu) {
|
} else if(nfc_worker->state == NfcWorkerStateEmulateApdu) {
|
||||||
@@ -394,6 +398,81 @@ void nfc_worker_read(NfcWorker* nfc_worker) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void nfc_worker_read_type(NfcWorker* nfc_worker) {
|
||||||
|
furi_assert(nfc_worker);
|
||||||
|
furi_assert(nfc_worker->callback);
|
||||||
|
|
||||||
|
NfcReadMode read_mode = nfc_worker->dev_data->read_mode;
|
||||||
|
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)) {
|
||||||
|
FURI_LOG_D(TAG, "Card detected");
|
||||||
|
furi_hal_nfc_sleep();
|
||||||
|
// Process first found device
|
||||||
|
nfc_worker->callback(NfcWorkerEventCardDetected, nfc_worker->context);
|
||||||
|
card_not_detected_notified = false;
|
||||||
|
if(nfc_data->type == FuriHalNfcTypeA) {
|
||||||
|
if(read_mode == NfcReadModeMfClassic) {
|
||||||
|
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);
|
||||||
|
if(nfc_worker_read_mf_classic(nfc_worker, &tx_rx)) {
|
||||||
|
FURI_LOG_D(TAG, "Card read");
|
||||||
|
dev_data->protocol = NfcDeviceProtocolMifareClassic;
|
||||||
|
event = NfcWorkerEventReadMfClassicDone;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
FURI_LOG_D(TAG, "Card read failed");
|
||||||
|
dev_data->protocol = NfcDeviceProtocolMifareClassic;
|
||||||
|
event = NfcWorkerEventReadMfClassicDictAttackRequired;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if(read_mode == NfcReadModeMfUltralight) {
|
||||||
|
FURI_LOG_I(TAG, "Mifare Ultralight / NTAG");
|
||||||
|
nfc_worker->dev_data->protocol = NfcDeviceProtocolMifareUl;
|
||||||
|
if(nfc_worker_read_mf_ultralight(nfc_worker, &tx_rx)) {
|
||||||
|
event = NfcWorkerEventReadMfUltralight;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if(read_mode == NfcReadModeMfDesfire) {
|
||||||
|
nfc_worker->dev_data->protocol = NfcDeviceProtocolMifareDesfire;
|
||||||
|
if(nfc_worker_read_mf_desfire(nfc_worker, &tx_rx)) {
|
||||||
|
event = NfcWorkerEventReadMfDesfire;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if(read_mode == NfcReadModeEMV) {
|
||||||
|
nfc_worker->dev_data->protocol = NfcDeviceProtocolEMV;
|
||||||
|
if(nfc_worker_read_bank_card(nfc_worker, &tx_rx)) {
|
||||||
|
event = NfcWorkerEventReadBankCard;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if(read_mode == NfcReadModeNFCA) {
|
||||||
|
nfc_worker->dev_data->protocol = NfcDeviceProtocolUnknown;
|
||||||
|
event = NfcWorkerEventReadUidNfcA;
|
||||||
|
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) {
|
void nfc_worker_emulate_uid(NfcWorker* nfc_worker) {
|
||||||
FuriHalNfcTxRxContext tx_rx = {};
|
FuriHalNfcTxRxContext tx_rx = {};
|
||||||
FuriHalNfcDevData* data = &nfc_worker->dev_data->nfc_data;
|
FuriHalNfcDevData* data = &nfc_worker->dev_data->nfc_data;
|
||||||
|
|||||||
@@ -35,6 +35,8 @@ int32_t nfc_worker_task(void* context);
|
|||||||
|
|
||||||
void nfc_worker_read(NfcWorker* nfc_worker);
|
void nfc_worker_read(NfcWorker* nfc_worker);
|
||||||
|
|
||||||
|
void nfc_worker_read_type(NfcWorker* nfc_worker);
|
||||||
|
|
||||||
void nfc_worker_emulate_uid(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_ultralight(NfcWorker* nfc_worker);
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ uint8_t mf_classic_get_total_sectors_num(MfClassicType type) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint16_t mf_classic_get_total_block_num(MfClassicType type) {
|
uint16_t mf_classic_get_total_block_num(MfClassicType type) {
|
||||||
if(type == MfClassicType1k) {
|
if(type == MfClassicType1k) {
|
||||||
return 64;
|
return 64;
|
||||||
} else if(type == MfClassicType4k) {
|
} else if(type == MfClassicType4k) {
|
||||||
|
|||||||
@@ -98,6 +98,8 @@ MfClassicType mf_classic_get_classic_type(int8_t ATQA0, uint8_t ATQA1, uint8_t S
|
|||||||
|
|
||||||
uint8_t mf_classic_get_total_sectors_num(MfClassicType type);
|
uint8_t mf_classic_get_total_sectors_num(MfClassicType type);
|
||||||
|
|
||||||
|
uint16_t mf_classic_get_total_block_num(MfClassicType type);
|
||||||
|
|
||||||
uint8_t mf_classic_get_sector_trailer_block_num_by_sector(uint8_t sector);
|
uint8_t mf_classic_get_sector_trailer_block_num_by_sector(uint8_t sector);
|
||||||
|
|
||||||
bool mf_classic_is_sector_trailer(uint8_t block);
|
bool mf_classic_is_sector_trailer(uint8_t block);
|
||||||
|
|||||||
@@ -52,6 +52,8 @@ class FlipperApplication:
|
|||||||
icon: Optional[str] = None
|
icon: Optional[str] = None
|
||||||
order: int = 0
|
order: int = 0
|
||||||
sdk_headers: List[str] = field(default_factory=list)
|
sdk_headers: List[str] = field(default_factory=list)
|
||||||
|
targets: List[str] = field(default_factory=lambda: ["all"])
|
||||||
|
|
||||||
# .fap-specific
|
# .fap-specific
|
||||||
sources: List[str] = field(default_factory=lambda: ["*.c*"])
|
sources: List[str] = field(default_factory=lambda: ["*.c*"])
|
||||||
fap_version: Tuple[int] = field(default_factory=lambda: (0, 1))
|
fap_version: Tuple[int] = field(default_factory=lambda: (0, 1))
|
||||||
@@ -135,8 +137,8 @@ class AppManager:
|
|||||||
raise FlipperManifestException(f"Duplicate app declaration: {app.appid}")
|
raise FlipperManifestException(f"Duplicate app declaration: {app.appid}")
|
||||||
self.known_apps[app.appid] = app
|
self.known_apps[app.appid] = app
|
||||||
|
|
||||||
def filter_apps(self, applist: List[str]):
|
def filter_apps(self, applist: List[str], hw_target: str):
|
||||||
return AppBuildset(self, applist)
|
return AppBuildset(self, applist, hw_target)
|
||||||
|
|
||||||
|
|
||||||
class AppBuilderException(Exception):
|
class AppBuilderException(Exception):
|
||||||
@@ -155,11 +157,13 @@ class AppBuildset:
|
|||||||
FlipperAppType.STARTUP,
|
FlipperAppType.STARTUP,
|
||||||
)
|
)
|
||||||
|
|
||||||
def __init__(self, appmgr: AppManager, appnames: List[str]):
|
def __init__(self, appmgr: AppManager, appnames: List[str], hw_target: str):
|
||||||
self.appmgr = appmgr
|
self.appmgr = appmgr
|
||||||
self.appnames = set(appnames)
|
self.appnames = set(appnames)
|
||||||
|
self.hw_target = hw_target
|
||||||
self._orig_appnames = appnames
|
self._orig_appnames = appnames
|
||||||
self._process_deps()
|
self._process_deps()
|
||||||
|
self._filter_by_target()
|
||||||
self._check_conflicts()
|
self._check_conflicts()
|
||||||
self._check_unsatisfied() # unneeded?
|
self._check_unsatisfied() # unneeded?
|
||||||
self.apps = sorted(
|
self.apps = sorted(
|
||||||
@@ -170,6 +174,16 @@ class AppBuildset:
|
|||||||
def _is_missing_dep(self, dep_name: str):
|
def _is_missing_dep(self, dep_name: str):
|
||||||
return dep_name not in self.appnames
|
return dep_name not in self.appnames
|
||||||
|
|
||||||
|
def _filter_by_target(self):
|
||||||
|
for appname in self.appnames.copy():
|
||||||
|
app = self.appmgr.get(appname)
|
||||||
|
# if app.apptype not in self.BUILTIN_APP_TYPES:
|
||||||
|
if not any(map(lambda t: t in app.targets, ["all", self.hw_target])):
|
||||||
|
print(
|
||||||
|
f"Removing {appname} due to target mismatch (building for {self.hw_target}, app supports {app.targets}"
|
||||||
|
)
|
||||||
|
self.appnames.remove(appname)
|
||||||
|
|
||||||
def _process_deps(self):
|
def _process_deps(self):
|
||||||
while True:
|
while True:
|
||||||
provided = []
|
provided = []
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import SCons
|
import SCons
|
||||||
from SCons.Subst import quote_spaces
|
from SCons.Subst import quote_spaces
|
||||||
from SCons.Errors import StopError
|
from SCons.Errors import StopError
|
||||||
from SCons.Node.FS import _my_normcase
|
|
||||||
|
|
||||||
import re
|
import re
|
||||||
import os
|
import os
|
||||||
@@ -58,3 +57,9 @@ def extract_abs_dir_path(node):
|
|||||||
raise StopError(f"Can't find absolute path for {node.name}")
|
raise StopError(f"Can't find absolute path for {node.name}")
|
||||||
|
|
||||||
return abs_dir_node.abspath
|
return abs_dir_node.abspath
|
||||||
|
|
||||||
|
|
||||||
|
def path_as_posix(path):
|
||||||
|
if SCons.Platform.platform_default() == "win32":
|
||||||
|
return path.replace(os.path.sep, os.path.altsep)
|
||||||
|
return path
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
from SCons.Builder import Builder
|
from SCons.Builder import Builder
|
||||||
from SCons.Action import Action
|
from SCons.Action import Action
|
||||||
from SCons.Warnings import warn, WarningOnByDefault
|
from SCons.Warnings import warn, WarningOnByDefault
|
||||||
import SCons
|
|
||||||
from ansi.color import fg
|
from ansi.color import fg
|
||||||
|
|
||||||
from fbt.appmanifest import (
|
from fbt.appmanifest import (
|
||||||
@@ -33,14 +32,12 @@ def LoadAppManifest(env, entry):
|
|||||||
|
|
||||||
|
|
||||||
def PrepareApplicationsBuild(env):
|
def PrepareApplicationsBuild(env):
|
||||||
appbuild = env["APPBUILD"] = env["APPMGR"].filter_apps(env["APPS"])
|
appbuild = env["APPBUILD"] = env["APPMGR"].filter_apps(
|
||||||
|
env["APPS"], env.subst("f${TARGET_HW}")
|
||||||
|
)
|
||||||
env.Append(
|
env.Append(
|
||||||
SDK_HEADERS=appbuild.get_sdk_headers(),
|
SDK_HEADERS=appbuild.get_sdk_headers(),
|
||||||
)
|
)
|
||||||
env["APPBUILD_DUMP"] = env.Action(
|
|
||||||
DumpApplicationConfig,
|
|
||||||
"\tINFO\t",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def DumpApplicationConfig(target, source, env):
|
def DumpApplicationConfig(target, source, env):
|
||||||
@@ -68,6 +65,10 @@ def generate(env):
|
|||||||
env.AddMethod(PrepareApplicationsBuild)
|
env.AddMethod(PrepareApplicationsBuild)
|
||||||
env.SetDefault(
|
env.SetDefault(
|
||||||
APPMGR=AppManager(),
|
APPMGR=AppManager(),
|
||||||
|
APPBUILD_DUMP=env.Action(
|
||||||
|
DumpApplicationConfig,
|
||||||
|
"\tINFO\t",
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
env.Append(
|
env.Append(
|
||||||
|
|||||||
@@ -41,12 +41,12 @@ def generate(env, **kw):
|
|||||||
"|openocd -c 'gdb_port pipe; log_output ${FBT_DEBUG_DIR}/openocd.log' ${[SINGLEQUOTEFUNC(OPENOCD_OPTS)]}"
|
"|openocd -c 'gdb_port pipe; log_output ${FBT_DEBUG_DIR}/openocd.log' ${[SINGLEQUOTEFUNC(OPENOCD_OPTS)]}"
|
||||||
],
|
],
|
||||||
GDBOPTS_BASE=[
|
GDBOPTS_BASE=[
|
||||||
|
"-ex",
|
||||||
|
"set pagination off",
|
||||||
"-ex",
|
"-ex",
|
||||||
"target extended-remote ${GDBREMOTE}",
|
"target extended-remote ${GDBREMOTE}",
|
||||||
"-ex",
|
"-ex",
|
||||||
"set confirm off",
|
"set confirm off",
|
||||||
"-ex",
|
|
||||||
"set pagination off",
|
|
||||||
],
|
],
|
||||||
GDBOPTS_BLACKMAGIC=[
|
GDBOPTS_BLACKMAGIC=[
|
||||||
"-ex",
|
"-ex",
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import json
|
|||||||
|
|
||||||
from fbt.sdk.collector import SdkCollector
|
from fbt.sdk.collector import SdkCollector
|
||||||
from fbt.sdk.cache import SdkCache
|
from fbt.sdk.cache import SdkCache
|
||||||
|
from fbt.util import path_as_posix
|
||||||
|
|
||||||
|
|
||||||
def ProcessSdkDepends(env, filename):
|
def ProcessSdkDepends(env, filename):
|
||||||
@@ -52,6 +53,8 @@ def prebuild_sdk_create_origin_file(target, source, env):
|
|||||||
|
|
||||||
|
|
||||||
class SdkMeta:
|
class SdkMeta:
|
||||||
|
MAP_FILE_SUBST = "SDK_MAP_FILE_SUBST"
|
||||||
|
|
||||||
def __init__(self, env, tree_builder: "SdkTreeBuilder"):
|
def __init__(self, env, tree_builder: "SdkTreeBuilder"):
|
||||||
self.env = env
|
self.env = env
|
||||||
self.treebuilder = tree_builder
|
self.treebuilder = tree_builder
|
||||||
@@ -67,6 +70,7 @@ class SdkMeta:
|
|||||||
"linker_libs": self.env.subst("${LIBS}"),
|
"linker_libs": self.env.subst("${LIBS}"),
|
||||||
"app_ep_subst": self.env.subst("${APP_ENTRY}"),
|
"app_ep_subst": self.env.subst("${APP_ENTRY}"),
|
||||||
"sdk_path_subst": self.env.subst("${SDK_DIR_SUBST}"),
|
"sdk_path_subst": self.env.subst("${SDK_DIR_SUBST}"),
|
||||||
|
"map_file_subst": self.MAP_FILE_SUBST,
|
||||||
"hardware": self.env.subst("${TARGET_HW}"),
|
"hardware": self.env.subst("${TARGET_HW}"),
|
||||||
}
|
}
|
||||||
with open(json_manifest_path, "wt") as f:
|
with open(json_manifest_path, "wt") as f:
|
||||||
@@ -75,9 +79,9 @@ class SdkMeta:
|
|||||||
def _wrap_scons_vars(self, vars: str):
|
def _wrap_scons_vars(self, vars: str):
|
||||||
expanded_vars = self.env.subst(
|
expanded_vars = self.env.subst(
|
||||||
vars,
|
vars,
|
||||||
target=Entry("dummy"),
|
target=Entry(self.MAP_FILE_SUBST),
|
||||||
)
|
)
|
||||||
return expanded_vars.replace("\\", "/")
|
return path_as_posix(expanded_vars)
|
||||||
|
|
||||||
|
|
||||||
class SdkTreeBuilder:
|
class SdkTreeBuilder:
|
||||||
@@ -142,13 +146,15 @@ class SdkTreeBuilder:
|
|||||||
meta.save_to(self.target[0].path)
|
meta.save_to(self.target[0].path)
|
||||||
|
|
||||||
def build_sdk_file_path(self, orig_path: str) -> str:
|
def build_sdk_file_path(self, orig_path: str) -> str:
|
||||||
return posixpath.normpath(
|
return path_as_posix(
|
||||||
|
posixpath.normpath(
|
||||||
posixpath.join(
|
posixpath.join(
|
||||||
self.SDK_DIR_SUBST,
|
self.SDK_DIR_SUBST,
|
||||||
self.target_sdk_dir_name,
|
self.target_sdk_dir_name,
|
||||||
orig_path,
|
orig_path,
|
||||||
)
|
)
|
||||||
).replace("\\", "/")
|
)
|
||||||
|
)
|
||||||
|
|
||||||
def emitter(self, target, source, env):
|
def emitter(self, target, source, env):
|
||||||
target_folder = target[0]
|
target_folder = target[0]
|
||||||
|
|||||||
@@ -63,6 +63,11 @@ vars.AddVariables(
|
|||||||
help="Enable debug build",
|
help="Enable debug build",
|
||||||
default=True,
|
default=True,
|
||||||
),
|
),
|
||||||
|
BoolVariable(
|
||||||
|
"LIB_DEBUG",
|
||||||
|
help="Enable debug build for libraries",
|
||||||
|
default=False,
|
||||||
|
),
|
||||||
BoolVariable(
|
BoolVariable(
|
||||||
"COMPACT",
|
"COMPACT",
|
||||||
help="Optimize for size",
|
help="Optimize for size",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from SCons.Errors import UserError
|
|
||||||
from SCons.Node import NodeList
|
from SCons.Node import NodeList
|
||||||
|
from SCons.Warnings import warn, WarningOnByDefault
|
||||||
|
|
||||||
|
|
||||||
Import("ENV")
|
Import("ENV")
|
||||||
@@ -80,6 +80,14 @@ if extra_app_list := GetOption("extra_ext_apps"):
|
|||||||
known_extapps.extend(map(appenv["APPMGR"].get, extra_app_list.split(",")))
|
known_extapps.extend(map(appenv["APPMGR"].get, extra_app_list.split(",")))
|
||||||
|
|
||||||
for app in known_extapps:
|
for app in known_extapps:
|
||||||
|
if not any(map(lambda t: t in app.targets, ["all", appenv.subst("f${TARGET_HW}")])):
|
||||||
|
warn(
|
||||||
|
WarningOnByDefault,
|
||||||
|
f"Can't build '{app.name}' (id '{app.appid}'): target mismatch"
|
||||||
|
f" (building for {appenv.subst('f${TARGET_HW}')}, app supports {app.targets}",
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
|
||||||
appenv.BuildAppElf(app)
|
appenv.BuildAppElf(app)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user