mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2025-01-03 18:59:43 +03:00
Merge branch 'ofw_dev' into dev
This commit is contained in:
commit
a64c9534e2
36
SConstruct
36
SConstruct
@ -172,17 +172,19 @@ Alias("fap_dist", fap_dist)
|
|||||||
|
|
||||||
fap_deploy = distenv.PhonyTarget(
|
fap_deploy = distenv.PhonyTarget(
|
||||||
"fap_deploy",
|
"fap_deploy",
|
||||||
[
|
Action(
|
||||||
[
|
[
|
||||||
"${PYTHON3}",
|
[
|
||||||
"${FBT_SCRIPT_DIR}/storage.py",
|
"${PYTHON3}",
|
||||||
"-p",
|
"${FBT_SCRIPT_DIR}/storage.py",
|
||||||
"${FLIP_PORT}",
|
"-p",
|
||||||
"send",
|
"${FLIP_PORT}",
|
||||||
"${SOURCE}",
|
"send",
|
||||||
"/ext/apps",
|
"${SOURCE}",
|
||||||
|
"/ext/apps",
|
||||||
|
]
|
||||||
]
|
]
|
||||||
],
|
),
|
||||||
source=firmware_env.Dir(("${RESOURCES_ROOT}/apps")),
|
source=firmware_env.Dir(("${RESOURCES_ROOT}/apps")),
|
||||||
)
|
)
|
||||||
Depends(fap_deploy, firmware_env["FW_RESOURCES_MANIFEST"])
|
Depends(fap_deploy, firmware_env["FW_RESOURCES_MANIFEST"])
|
||||||
@ -261,7 +263,7 @@ distenv.PhonyTarget(
|
|||||||
distenv.PhonyTarget(
|
distenv.PhonyTarget(
|
||||||
"debug_other_blackmagic",
|
"debug_other_blackmagic",
|
||||||
"${GDBPYCOM}",
|
"${GDBPYCOM}",
|
||||||
GDBOPTS="${GDBOPTS_BASE} ${GDBOPTS_BLACKMAGIC}",
|
GDBOPTS="${GDBOPTS_BASE} ${GDBOPTS_BLACKMAGIC}",
|
||||||
GDBREMOTE="${BLACKMAGIC_ADDR}",
|
GDBREMOTE="${BLACKMAGIC_ADDR}",
|
||||||
GDBPYOPTS=debug_other_opts,
|
GDBPYOPTS=debug_other_opts,
|
||||||
)
|
)
|
||||||
@ -276,13 +278,13 @@ distenv.PhonyTarget(
|
|||||||
# Linter
|
# Linter
|
||||||
distenv.PhonyTarget(
|
distenv.PhonyTarget(
|
||||||
"lint",
|
"lint",
|
||||||
"${PYTHON3} ${FBT_SCRIPT_DIR}/lint.py check ${LINT_SOURCES}",
|
[["${PYTHON3}", "${FBT_SCRIPT_DIR}/lint.py", "check", "${LINT_SOURCES}"]],
|
||||||
LINT_SOURCES=[n.srcnode() for n in firmware_env["LINT_SOURCES"]],
|
LINT_SOURCES=[n.srcnode() for n in firmware_env["LINT_SOURCES"]],
|
||||||
)
|
)
|
||||||
|
|
||||||
distenv.PhonyTarget(
|
distenv.PhonyTarget(
|
||||||
"format",
|
"format",
|
||||||
"${PYTHON3} ${FBT_SCRIPT_DIR}/lint.py format ${LINT_SOURCES}",
|
[["${PYTHON3}", "${FBT_SCRIPT_DIR}/lint.py", "format", "${LINT_SOURCES}"]],
|
||||||
LINT_SOURCES=[n.srcnode() for n in firmware_env["LINT_SOURCES"]],
|
LINT_SOURCES=[n.srcnode() for n in firmware_env["LINT_SOURCES"]],
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -323,10 +325,14 @@ distenv.PhonyTarget(
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Start Flipper CLI via PySerial's miniterm
|
# Start Flipper CLI via PySerial's miniterm
|
||||||
distenv.PhonyTarget("cli", "${PYTHON3} ${FBT_SCRIPT_DIR}/serial_cli.py -p ${FLIP_PORT}")
|
distenv.PhonyTarget(
|
||||||
|
"cli", [["${PYTHON3}", "${FBT_SCRIPT_DIR}/serial_cli.py", "-p", "${FLIP_PORT}"]]
|
||||||
|
)
|
||||||
|
|
||||||
# Update WiFi devboard firmware
|
# Update WiFi devboard firmware
|
||||||
distenv.PhonyTarget("devboard_flash", "${PYTHON3} ${FBT_SCRIPT_DIR}/wifi_board.py")
|
distenv.PhonyTarget(
|
||||||
|
"devboard_flash", [["${PYTHON3}", "${FBT_SCRIPT_DIR}/wifi_board.py"]]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# Find blackmagic probe
|
# Find blackmagic probe
|
||||||
@ -361,5 +367,5 @@ distenv.Alias("vscode_dist", vscode_dist)
|
|||||||
# Configure shell with build tools
|
# Configure shell with build tools
|
||||||
distenv.PhonyTarget(
|
distenv.PhonyTarget(
|
||||||
"env",
|
"env",
|
||||||
"@echo $( ${FBT_SCRIPT_DIR}/toolchain/fbtenv.sh $)",
|
"@echo $( ${FBT_SCRIPT_DIR.abspath}/toolchain/fbtenv.sh $)",
|
||||||
)
|
)
|
||||||
|
@ -4,7 +4,6 @@ App(
|
|||||||
apptype=FlipperAppType.DEBUG,
|
apptype=FlipperAppType.DEBUG,
|
||||||
targets=["f7"],
|
targets=["f7"],
|
||||||
entry_point="accessor_app",
|
entry_point="accessor_app",
|
||||||
cdefines=["APP_ACCESSOR"],
|
|
||||||
requires=["gui"],
|
requires=["gui"],
|
||||||
stack_size=4 * 1024,
|
stack_size=4 * 1024,
|
||||||
order=40,
|
order=40,
|
||||||
|
@ -3,7 +3,6 @@ App(
|
|||||||
name="Battery Test",
|
name="Battery Test",
|
||||||
apptype=FlipperAppType.DEBUG,
|
apptype=FlipperAppType.DEBUG,
|
||||||
entry_point="battery_test_app",
|
entry_point="battery_test_app",
|
||||||
cdefines=["APP_BATTERY_TEST"],
|
|
||||||
requires=[
|
requires=[
|
||||||
"gui",
|
"gui",
|
||||||
"power",
|
"power",
|
||||||
|
@ -3,7 +3,6 @@ App(
|
|||||||
name="Blink Test",
|
name="Blink Test",
|
||||||
apptype=FlipperAppType.DEBUG,
|
apptype=FlipperAppType.DEBUG,
|
||||||
entry_point="blink_test_app",
|
entry_point="blink_test_app",
|
||||||
cdefines=["APP_BLINK"],
|
|
||||||
requires=["gui"],
|
requires=["gui"],
|
||||||
stack_size=1 * 1024,
|
stack_size=1 * 1024,
|
||||||
order=10,
|
order=10,
|
||||||
|
@ -3,7 +3,6 @@ App(
|
|||||||
name="CCID Debug",
|
name="CCID Debug",
|
||||||
apptype=FlipperAppType.DEBUG,
|
apptype=FlipperAppType.DEBUG,
|
||||||
entry_point="ccid_test_app",
|
entry_point="ccid_test_app",
|
||||||
cdefines=["CCID_TEST"],
|
|
||||||
requires=[
|
requires=[
|
||||||
"gui",
|
"gui",
|
||||||
],
|
],
|
||||||
|
@ -3,7 +3,6 @@ App(
|
|||||||
name="Crash Test",
|
name="Crash Test",
|
||||||
apptype=FlipperAppType.DEBUG,
|
apptype=FlipperAppType.DEBUG,
|
||||||
entry_point="crash_test_app",
|
entry_point="crash_test_app",
|
||||||
cdefines=["APP_CRASH_TEST"],
|
|
||||||
requires=["gui"],
|
requires=["gui"],
|
||||||
stack_size=1 * 1024,
|
stack_size=1 * 1024,
|
||||||
fap_category="Debug",
|
fap_category="Debug",
|
||||||
|
@ -3,7 +3,6 @@ App(
|
|||||||
name="Display Test",
|
name="Display Test",
|
||||||
apptype=FlipperAppType.DEBUG,
|
apptype=FlipperAppType.DEBUG,
|
||||||
entry_point="display_test_app",
|
entry_point="display_test_app",
|
||||||
cdefines=["APP_DISPLAY_TEST"],
|
|
||||||
requires=["gui"],
|
requires=["gui"],
|
||||||
fap_libs=["misc"],
|
fap_libs=["misc"],
|
||||||
stack_size=1 * 1024,
|
stack_size=1 * 1024,
|
||||||
|
@ -3,7 +3,6 @@ App(
|
|||||||
name="File Browser Test",
|
name="File Browser Test",
|
||||||
apptype=FlipperAppType.DEBUG,
|
apptype=FlipperAppType.DEBUG,
|
||||||
entry_point="file_browser_app",
|
entry_point="file_browser_app",
|
||||||
cdefines=["APP_FILE_BROWSER_TEST"],
|
|
||||||
requires=["gui"],
|
requires=["gui"],
|
||||||
stack_size=2 * 1024,
|
stack_size=2 * 1024,
|
||||||
order=150,
|
order=150,
|
||||||
|
@ -3,7 +3,6 @@ App(
|
|||||||
name="Keypad Test",
|
name="Keypad Test",
|
||||||
apptype=FlipperAppType.DEBUG,
|
apptype=FlipperAppType.DEBUG,
|
||||||
entry_point="keypad_test_app",
|
entry_point="keypad_test_app",
|
||||||
cdefines=["APP_KEYPAD_TEST"],
|
|
||||||
requires=["gui"],
|
requires=["gui"],
|
||||||
stack_size=1 * 1024,
|
stack_size=1 * 1024,
|
||||||
order=30,
|
order=30,
|
||||||
|
@ -3,7 +3,6 @@ App(
|
|||||||
name="Locale Test",
|
name="Locale Test",
|
||||||
apptype=FlipperAppType.DEBUG,
|
apptype=FlipperAppType.DEBUG,
|
||||||
entry_point="locale_test_app",
|
entry_point="locale_test_app",
|
||||||
cdefines=["APP_LOCALE"],
|
|
||||||
requires=["gui", "locale"],
|
requires=["gui", "locale"],
|
||||||
stack_size=2 * 1024,
|
stack_size=2 * 1024,
|
||||||
order=70,
|
order=70,
|
||||||
|
@ -3,7 +3,6 @@ App(
|
|||||||
name="Text Box Test",
|
name="Text Box Test",
|
||||||
apptype=FlipperAppType.DEBUG,
|
apptype=FlipperAppType.DEBUG,
|
||||||
entry_point="text_box_test_app",
|
entry_point="text_box_test_app",
|
||||||
cdefines=["APP_TEXT_BOX_TEST"],
|
|
||||||
requires=["gui"],
|
requires=["gui"],
|
||||||
stack_size=1 * 1024,
|
stack_size=1 * 1024,
|
||||||
order=140,
|
order=140,
|
||||||
|
@ -3,7 +3,6 @@ App(
|
|||||||
name="UART Echo",
|
name="UART Echo",
|
||||||
apptype=FlipperAppType.DEBUG,
|
apptype=FlipperAppType.DEBUG,
|
||||||
entry_point="uart_echo_app",
|
entry_point="uart_echo_app",
|
||||||
cdefines=["APP_UART_ECHO"],
|
|
||||||
requires=["gui"],
|
requires=["gui"],
|
||||||
stack_size=2 * 1024,
|
stack_size=2 * 1024,
|
||||||
order=70,
|
order=70,
|
||||||
|
@ -3,18 +3,29 @@
|
|||||||
#include <furi.h>
|
#include <furi.h>
|
||||||
#include "../minunit.h"
|
#include "../minunit.h"
|
||||||
|
|
||||||
void test_furi_create_open() {
|
#define TEST_RECORD_NAME "test/holding"
|
||||||
// 1. Create record
|
|
||||||
uint8_t test_data = 0;
|
|
||||||
furi_record_create("test/holding", (void*)&test_data);
|
|
||||||
|
|
||||||
// 2. Open it
|
void test_furi_create_open() {
|
||||||
void* record = furi_record_open("test/holding");
|
// Test that record does not exist
|
||||||
|
mu_check(furi_record_exists(TEST_RECORD_NAME) == false);
|
||||||
|
|
||||||
|
// Create record
|
||||||
|
uint8_t test_data = 0;
|
||||||
|
furi_record_create(TEST_RECORD_NAME, (void*)&test_data);
|
||||||
|
|
||||||
|
// Test that record exists
|
||||||
|
mu_check(furi_record_exists(TEST_RECORD_NAME) == true);
|
||||||
|
|
||||||
|
// Open it
|
||||||
|
void* record = furi_record_open(TEST_RECORD_NAME);
|
||||||
mu_assert_pointers_eq(record, &test_data);
|
mu_assert_pointers_eq(record, &test_data);
|
||||||
|
|
||||||
// 3. Close it
|
// Close it
|
||||||
furi_record_close("test/holding");
|
furi_record_close(TEST_RECORD_NAME);
|
||||||
|
|
||||||
// 4. Clean up
|
// Clean up
|
||||||
furi_record_destroy("test/holding");
|
furi_record_destroy(TEST_RECORD_NAME);
|
||||||
|
|
||||||
|
// Test that record does not exist
|
||||||
|
mu_check(furi_record_exists(TEST_RECORD_NAME) == false);
|
||||||
}
|
}
|
||||||
|
@ -81,6 +81,7 @@ __attribute__((unused)) static void (*minunit_teardown)(void) = NULL;
|
|||||||
|
|
||||||
void minunit_print_progress(void);
|
void minunit_print_progress(void);
|
||||||
void minunit_print_fail(const char* error);
|
void minunit_print_fail(const char* error);
|
||||||
|
void minunit_printf_warning(const char* format, ...);
|
||||||
|
|
||||||
/* Definitions */
|
/* Definitions */
|
||||||
#define MU_TEST(method_name) static void method_name(void)
|
#define MU_TEST(method_name) static void method_name(void)
|
||||||
@ -150,6 +151,10 @@ void minunit_print_fail(const char* error);
|
|||||||
minunit_end_proc_timer - minunit_proc_timer);)
|
minunit_end_proc_timer - minunit_proc_timer);)
|
||||||
#define MU_EXIT_CODE minunit_fail
|
#define MU_EXIT_CODE minunit_fail
|
||||||
|
|
||||||
|
/* Warnings */
|
||||||
|
#define mu_warn(message) \
|
||||||
|
MU__SAFE_BLOCK(minunit_printf_warning("%s:%d: %s", __FILE__, __LINE__, message);)
|
||||||
|
|
||||||
/* Assertions */
|
/* Assertions */
|
||||||
#define mu_check(test) \
|
#define mu_check(test) \
|
||||||
MU__SAFE_BLOCK( \
|
MU__SAFE_BLOCK( \
|
||||||
|
@ -7,10 +7,10 @@
|
|||||||
#include <nfc/nfc_poller.h>
|
#include <nfc/nfc_poller.h>
|
||||||
#include <nfc/nfc_listener.h>
|
#include <nfc/nfc_listener.h>
|
||||||
#include <nfc/protocols/iso14443_3a/iso14443_3a.h>
|
#include <nfc/protocols/iso14443_3a/iso14443_3a.h>
|
||||||
#include <nfc/protocols/iso14443_3a/iso14443_3a_poller_sync_api.h>
|
#include <nfc/protocols/iso14443_3a/iso14443_3a_poller_sync.h>
|
||||||
#include <nfc/protocols/mf_ultralight/mf_ultralight.h>
|
#include <nfc/protocols/mf_ultralight/mf_ultralight.h>
|
||||||
#include <nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.h>
|
#include <nfc/protocols/mf_ultralight/mf_ultralight_poller_sync.h>
|
||||||
#include <nfc/protocols/mf_classic/mf_classic_poller_sync_api.h>
|
#include <nfc/protocols/mf_classic/mf_classic_poller_sync.h>
|
||||||
|
|
||||||
#include <nfc/helpers/nfc_dict.h>
|
#include <nfc/helpers/nfc_dict.h>
|
||||||
#include <nfc/nfc.h>
|
#include <nfc/nfc.h>
|
||||||
@ -182,8 +182,8 @@ MU_TEST(iso14443_3a_reader) {
|
|||||||
|
|
||||||
Iso14443_3aData iso14443_3a_poller_data = {};
|
Iso14443_3aData iso14443_3a_poller_data = {};
|
||||||
mu_assert(
|
mu_assert(
|
||||||
iso14443_3a_poller_read(poller, &iso14443_3a_poller_data) == Iso14443_3aErrorNone,
|
iso14443_3a_poller_sync_read(poller, &iso14443_3a_poller_data) == Iso14443_3aErrorNone,
|
||||||
"iso14443_3a_poller_read() failed");
|
"iso14443_3a_poller_sync_read() failed");
|
||||||
|
|
||||||
nfc_listener_stop(iso3_listener);
|
nfc_listener_stop(iso3_listener);
|
||||||
mu_assert(
|
mu_assert(
|
||||||
@ -203,15 +203,26 @@ static void mf_ultralight_reader_test(const char* path) {
|
|||||||
NfcDevice* nfc_device = nfc_device_alloc();
|
NfcDevice* nfc_device = nfc_device_alloc();
|
||||||
mu_assert(nfc_device_load(nfc_device, path), "nfc_device_load() failed\r\n");
|
mu_assert(nfc_device_load(nfc_device, path), "nfc_device_load() failed\r\n");
|
||||||
|
|
||||||
NfcListener* mfu_listener = nfc_listener_alloc(
|
MfUltralightData* data =
|
||||||
listener,
|
(MfUltralightData*)nfc_device_get_data(nfc_device, NfcProtocolMfUltralight);
|
||||||
NfcProtocolMfUltralight,
|
|
||||||
nfc_device_get_data(nfc_device, NfcProtocolMfUltralight));
|
uint32_t features = mf_ultralight_get_feature_support_set(data->type);
|
||||||
|
bool pwd_supported =
|
||||||
|
mf_ultralight_support_feature(features, MfUltralightFeatureSupportPasswordAuth);
|
||||||
|
uint8_t pwd_num = mf_ultralight_get_pwd_page_num(data->type);
|
||||||
|
const uint8_t zero_pwd[4] = {0, 0, 0, 0};
|
||||||
|
|
||||||
|
if(pwd_supported && !memcmp(data->page[pwd_num].data, zero_pwd, sizeof(zero_pwd))) {
|
||||||
|
data->pages_read -= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
NfcListener* mfu_listener = nfc_listener_alloc(listener, NfcProtocolMfUltralight, data);
|
||||||
|
|
||||||
nfc_listener_start(mfu_listener, NULL, NULL);
|
nfc_listener_start(mfu_listener, NULL, NULL);
|
||||||
|
|
||||||
MfUltralightData* mfu_data = mf_ultralight_alloc();
|
MfUltralightData* mfu_data = mf_ultralight_alloc();
|
||||||
MfUltralightError error = mf_ultralight_poller_read_card(poller, mfu_data);
|
MfUltralightError error = mf_ultralight_poller_sync_read_card(poller, mfu_data);
|
||||||
mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_read_card() failed");
|
mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_sync_read_card() failed");
|
||||||
|
|
||||||
nfc_listener_stop(mfu_listener);
|
nfc_listener_stop(mfu_listener);
|
||||||
nfc_listener_free(mfu_listener);
|
nfc_listener_free(mfu_listener);
|
||||||
@ -259,8 +270,8 @@ MU_TEST(ntag_213_locked_reader) {
|
|||||||
nfc_listener_start(mfu_listener, NULL, NULL);
|
nfc_listener_start(mfu_listener, NULL, NULL);
|
||||||
|
|
||||||
MfUltralightData* mfu_data = mf_ultralight_alloc();
|
MfUltralightData* mfu_data = mf_ultralight_alloc();
|
||||||
MfUltralightError error = mf_ultralight_poller_read_card(poller, mfu_data);
|
MfUltralightError error = mf_ultralight_poller_sync_read_card(poller, mfu_data);
|
||||||
mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_read_card() failed");
|
mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_sync_read_card() failed");
|
||||||
|
|
||||||
nfc_listener_stop(mfu_listener);
|
nfc_listener_stop(mfu_listener);
|
||||||
nfc_listener_free(mfu_listener);
|
nfc_listener_free(mfu_listener);
|
||||||
@ -297,8 +308,8 @@ static void mf_ultralight_write() {
|
|||||||
MfUltralightData* mfu_data = mf_ultralight_alloc();
|
MfUltralightData* mfu_data = mf_ultralight_alloc();
|
||||||
|
|
||||||
// Initial read
|
// Initial read
|
||||||
MfUltralightError error = mf_ultralight_poller_read_card(poller, mfu_data);
|
MfUltralightError error = mf_ultralight_poller_sync_read_card(poller, mfu_data);
|
||||||
mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_read_card() failed");
|
mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_sync_read_card() failed");
|
||||||
|
|
||||||
mu_assert(
|
mu_assert(
|
||||||
mf_ultralight_is_equal(mfu_data, nfc_device_get_data(nfc_device, NfcProtocolMfUltralight)),
|
mf_ultralight_is_equal(mfu_data, nfc_device_get_data(nfc_device, NfcProtocolMfUltralight)),
|
||||||
@ -310,13 +321,13 @@ static void mf_ultralight_write() {
|
|||||||
FURI_LOG_D(TAG, "Writing page %d", i);
|
FURI_LOG_D(TAG, "Writing page %d", i);
|
||||||
furi_hal_random_fill_buf(page.data, sizeof(MfUltralightPage));
|
furi_hal_random_fill_buf(page.data, sizeof(MfUltralightPage));
|
||||||
mfu_data->page[i] = page;
|
mfu_data->page[i] = page;
|
||||||
error = mf_ultralight_poller_write_page(poller, i, &page);
|
error = mf_ultralight_poller_sync_write_page(poller, i, &page);
|
||||||
mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_write_page() failed");
|
mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_sync_write_page() failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verification read
|
// Verification read
|
||||||
error = mf_ultralight_poller_read_card(poller, mfu_data);
|
error = mf_ultralight_poller_sync_read_card(poller, mfu_data);
|
||||||
mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_read_card() failed");
|
mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_sync_read_card() failed");
|
||||||
|
|
||||||
nfc_listener_stop(mfu_listener);
|
nfc_listener_stop(mfu_listener);
|
||||||
const MfUltralightData* mfu_listener_data =
|
const MfUltralightData* mfu_listener_data =
|
||||||
@ -344,7 +355,7 @@ static void mf_classic_reader() {
|
|||||||
MfClassicBlock block = {};
|
MfClassicBlock block = {};
|
||||||
MfClassicKey key = {.data = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}};
|
MfClassicKey key = {.data = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}};
|
||||||
|
|
||||||
mf_classic_poller_read_block(poller, 0, &key, MfClassicKeyTypeA, &block);
|
mf_classic_poller_sync_read_block(poller, 0, &key, MfClassicKeyTypeA, &block);
|
||||||
|
|
||||||
nfc_listener_stop(mfc_listener);
|
nfc_listener_stop(mfc_listener);
|
||||||
nfc_listener_free(mfc_listener);
|
nfc_listener_free(mfc_listener);
|
||||||
@ -372,8 +383,8 @@ static void mf_classic_write() {
|
|||||||
furi_hal_random_fill_buf(block_write.data, sizeof(MfClassicBlock));
|
furi_hal_random_fill_buf(block_write.data, sizeof(MfClassicBlock));
|
||||||
MfClassicKey key = {.data = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}};
|
MfClassicKey key = {.data = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}};
|
||||||
|
|
||||||
mf_classic_poller_write_block(poller, 1, &key, MfClassicKeyTypeA, &block_write);
|
mf_classic_poller_sync_write_block(poller, 1, &key, MfClassicKeyTypeA, &block_write);
|
||||||
mf_classic_poller_read_block(poller, 1, &key, MfClassicKeyTypeA, &block_read);
|
mf_classic_poller_sync_read_block(poller, 1, &key, MfClassicKeyTypeA, &block_read);
|
||||||
|
|
||||||
nfc_listener_stop(mfc_listener);
|
nfc_listener_stop(mfc_listener);
|
||||||
nfc_listener_free(mfc_listener);
|
nfc_listener_free(mfc_listener);
|
||||||
@ -402,16 +413,18 @@ static void mf_classic_value_block() {
|
|||||||
mf_classic_value_to_block(value, 1, &block_write);
|
mf_classic_value_to_block(value, 1, &block_write);
|
||||||
|
|
||||||
MfClassicError error = MfClassicErrorNone;
|
MfClassicError error = MfClassicErrorNone;
|
||||||
error = mf_classic_poller_write_block(poller, 1, &key, MfClassicKeyTypeA, &block_write);
|
error = mf_classic_poller_sync_write_block(poller, 1, &key, MfClassicKeyTypeA, &block_write);
|
||||||
mu_assert(error == MfClassicErrorNone, "Write failed");
|
mu_assert(error == MfClassicErrorNone, "Write failed");
|
||||||
|
|
||||||
int32_t data = 200;
|
int32_t data = 200;
|
||||||
int32_t new_value = 0;
|
int32_t new_value = 0;
|
||||||
error = mf_classic_poller_change_value(poller, 1, &key, MfClassicKeyTypeA, data, &new_value);
|
error =
|
||||||
|
mf_classic_poller_sync_change_value(poller, 1, &key, MfClassicKeyTypeA, data, &new_value);
|
||||||
mu_assert(error == MfClassicErrorNone, "Value increment failed");
|
mu_assert(error == MfClassicErrorNone, "Value increment failed");
|
||||||
mu_assert(new_value == value + data, "Value not match");
|
mu_assert(new_value == value + data, "Value not match");
|
||||||
|
|
||||||
error = mf_classic_poller_change_value(poller, 1, &key, MfClassicKeyTypeA, -data, &new_value);
|
error =
|
||||||
|
mf_classic_poller_sync_change_value(poller, 1, &key, MfClassicKeyTypeA, -data, &new_value);
|
||||||
mu_assert(error == MfClassicErrorNone, "Value decrement failed");
|
mu_assert(error == MfClassicErrorNone, "Value decrement failed");
|
||||||
mu_assert(new_value == value, "Value not match");
|
mu_assert(new_value == value, "Value not match");
|
||||||
|
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
Filetype: Flipper SubGhz Key File
|
||||||
|
Version: 1
|
||||||
|
Frequency: 433920000
|
||||||
|
Preset: FuriHalSubGhzPresetOok270Async
|
||||||
|
Protocol: Mastercode
|
||||||
|
Bit: 36
|
||||||
|
Key: 00 00 00 0B 7E 00 3C 08
|
@ -0,0 +1,6 @@
|
|||||||
|
Filetype: Flipper SubGhz RAW File
|
||||||
|
Version: 1
|
||||||
|
Frequency: 433920000
|
||||||
|
Preset: FuriHalSubGhzPresetOok270Async
|
||||||
|
Protocol: RAW
|
||||||
|
RAW_Data: 10389 -66 405095 -102 207 -106 1165 -130 963739 -1232 899 -2250 2003 -1190 2017 -1202 911 -2256 2021 -1162 2045 -1134 2047 -1164 2047 -1138 2031 -1180 2039 -1182 949 -2190 995 -2214 961 -2228 963 -2198 963 -2214 977 -2212 975 -2210 975 -2208 971 -2200 963 -2210 993 -2184 2075 -1130 2051 -1142 2055 -1136 2047 -1178 965 -2236 933 -2220 975 -2184 999 -2222 967 -2208 969 -2214 979 -2202 2027 -1156 975 -2242 943 -16080 2023 -1162 967 -2220 2057 -1114 2061 -1124 1007 -2242 2025 -1134 2055 -1168 2017 -1138 2075 -1134 2053 -1136 2075 -1130 979 -2214 979 -2174 999 -2182 1001 -2204 977 -2206 1003 -2188 979 -2176 999 -2182 1009 -2176 1009 -2176 1001 -2212 2029 -1116 2091 -1102 2109 -1092 2095 -1126 1001 -2150 1011 -2180 1011 -2180 1009 -2178 1009 -2172 1009 -2166 1001 -2198 2065 -1136 975 -2220 971 -16018 2097 -1166 951 -2240 2009 -1186 2011 -1160 979 -2208 2035 -1134 2053 -1138 2061 -1158 2045 -1152 2029 -1152 2051 -1166 963 -2188 993 -2222 951 -2214 963 -2220 965 -2212 979 -2212 977 -2180 1003 -2202 965 -2218 975 -2216 967 -2188 2061 -1124 2083 -1126 2071 -1130 2059 -1134 993 -2188 979 -2240 947 -2204 979 -2214 971 -2214 973 -2210 971 -2206 2053 -1130 979 -2216 969 -16056 2053 -1134 1001 -2224 2021 -1150 2051 -1154 953 -2240 2045 -1146 2023 -1168 2033 -1144 2065 -1146 2055 -1130 2071 -1160 961 -2192 973 -2190 1005 -2214 975 -2206 967 -2206 975 -2206 967 -2208 975 -2212 967 -2212 979 -2218 977 -2178 2063 -1156 2035 -1160 2061 -1126 2065 -1130 981 -2186 1003 -2210 977 -2208 973 -2202 977 -2200 965 -2248 943 -2206 2039 -1190 941 -48536 65 -7254 263 -68 363 -102 131 -232 263 -264 751 -230 225 -822 397 -634 231 -268 263 -134 267 -64 867 -132 305 -138 67 -100 331 -98 891 -66 455 -66 531 -100 299 -134 897 -98 693 -132 291 -132 333 -98 337 -68 331
|
@ -139,7 +139,7 @@ static bool write_file_13DA(Storage* storage, const char* path) {
|
|||||||
File* file = storage_file_alloc(storage);
|
File* file = storage_file_alloc(storage);
|
||||||
bool result = false;
|
bool result = false;
|
||||||
if(storage_file_open(file, path, FSAM_WRITE, FSOM_CREATE_ALWAYS)) {
|
if(storage_file_open(file, path, FSAM_WRITE, FSOM_CREATE_ALWAYS)) {
|
||||||
result = storage_file_write(file, "13DA", 4) == 4;
|
result = (storage_file_write(file, "13DA", 4) == 4);
|
||||||
}
|
}
|
||||||
storage_file_close(file);
|
storage_file_close(file);
|
||||||
storage_file_free(file);
|
storage_file_free(file);
|
||||||
|
@ -115,6 +115,66 @@ MU_TEST(storage_file_open_close) {
|
|||||||
furi_record_close(RECORD_STORAGE);
|
furi_record_close(RECORD_STORAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool storage_file_read_write_test(File* file, uint8_t* data, size_t test_size) {
|
||||||
|
const char* filename = UNIT_TESTS_PATH("storage_chunk.test");
|
||||||
|
|
||||||
|
// fill with pattern
|
||||||
|
for(size_t i = 0; i < test_size; i++) {
|
||||||
|
data[i] = (i % 113);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool result = false;
|
||||||
|
do {
|
||||||
|
if(!storage_file_open(file, filename, FSAM_WRITE, FSOM_CREATE_ALWAYS)) break;
|
||||||
|
if(test_size != storage_file_write(file, data, test_size)) break;
|
||||||
|
storage_file_close(file);
|
||||||
|
|
||||||
|
// reset data
|
||||||
|
memset(data, 0, test_size);
|
||||||
|
|
||||||
|
if(!storage_file_open(file, filename, FSAM_READ, FSOM_OPEN_EXISTING)) break;
|
||||||
|
if(test_size != storage_file_read(file, data, test_size)) break;
|
||||||
|
storage_file_close(file);
|
||||||
|
|
||||||
|
// check that data is correct
|
||||||
|
for(size_t i = 0; i < test_size; i++) {
|
||||||
|
if(data[i] != (i % 113)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result = true;
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
MU_TEST(storage_file_read_write_64k) {
|
||||||
|
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||||
|
File* file = storage_file_alloc(storage);
|
||||||
|
|
||||||
|
size_t size_1k = 1024;
|
||||||
|
size_t size_64k = size_1k + size_1k * 63;
|
||||||
|
size_t size_65k = size_64k + size_1k;
|
||||||
|
size_t size_max = size_65k + 8;
|
||||||
|
|
||||||
|
size_t max_ram_block = memmgr_heap_get_max_free_block();
|
||||||
|
|
||||||
|
if(max_ram_block < size_max) {
|
||||||
|
mu_warn("Not enough RAM for >64k block test");
|
||||||
|
} else {
|
||||||
|
uint8_t* data = malloc(size_max);
|
||||||
|
mu_check(storage_file_read_write_test(file, data, size_1k));
|
||||||
|
mu_check(storage_file_read_write_test(file, data, size_64k));
|
||||||
|
mu_check(storage_file_read_write_test(file, data, size_65k));
|
||||||
|
mu_check(storage_file_read_write_test(file, data, size_max));
|
||||||
|
free(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
storage_file_free(file);
|
||||||
|
furi_record_close(RECORD_STORAGE);
|
||||||
|
}
|
||||||
|
|
||||||
MU_TEST_SUITE(storage_file) {
|
MU_TEST_SUITE(storage_file) {
|
||||||
storage_file_open_lock_setup();
|
storage_file_open_lock_setup();
|
||||||
MU_RUN_TEST(storage_file_open_close);
|
MU_RUN_TEST(storage_file_open_close);
|
||||||
@ -122,6 +182,10 @@ MU_TEST_SUITE(storage_file) {
|
|||||||
storage_file_open_lock_teardown();
|
storage_file_open_lock_teardown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MU_TEST_SUITE(storage_file_64k) {
|
||||||
|
MU_RUN_TEST(storage_file_read_write_64k);
|
||||||
|
}
|
||||||
|
|
||||||
MU_TEST(storage_dir_open_close) {
|
MU_TEST(storage_dir_open_close) {
|
||||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||||
File* file;
|
File* file;
|
||||||
@ -640,6 +704,7 @@ MU_TEST_SUITE(test_md5_calc_suite) {
|
|||||||
|
|
||||||
int run_minunit_test_storage() {
|
int run_minunit_test_storage() {
|
||||||
MU_RUN_SUITE(storage_file);
|
MU_RUN_SUITE(storage_file);
|
||||||
|
MU_RUN_SUITE(storage_file_64k);
|
||||||
MU_RUN_SUITE(storage_dir);
|
MU_RUN_SUITE(storage_dir);
|
||||||
MU_RUN_SUITE(storage_rename);
|
MU_RUN_SUITE(storage_rename);
|
||||||
MU_RUN_SUITE(test_data_path);
|
MU_RUN_SUITE(test_data_path);
|
||||||
|
@ -324,6 +324,7 @@ bool subghz_hal_async_tx_test_run(SubGhzHalAsyncTxTestType type) {
|
|||||||
furi_hal_subghz_set_frequency_and_path(433920000);
|
furi_hal_subghz_set_frequency_and_path(433920000);
|
||||||
|
|
||||||
if(!furi_hal_subghz_start_async_tx(subghz_hal_async_tx_test_yield, &test)) {
|
if(!furi_hal_subghz_start_async_tx(subghz_hal_async_tx_test_yield, &test)) {
|
||||||
|
mu_warn("SubGHZ transmission is prohibited");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -652,6 +653,13 @@ MU_TEST(subghz_decoder_kinggates_stylo4k_test) {
|
|||||||
"Test decoder " SUBGHZ_PROTOCOL_KINGGATES_STYLO_4K_NAME " error\r\n");
|
"Test decoder " SUBGHZ_PROTOCOL_KINGGATES_STYLO_4K_NAME " error\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MU_TEST(subghz_decoder_mastercode_test) {
|
||||||
|
mu_assert(
|
||||||
|
subghz_decoder_test(
|
||||||
|
EXT_PATH("unit_tests/subghz/mastercode_raw.sub"), SUBGHZ_PROTOCOL_MASTERCODE_NAME),
|
||||||
|
"Test decoder " SUBGHZ_PROTOCOL_MASTERCODE_NAME " error\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
//test encoders
|
//test encoders
|
||||||
MU_TEST(subghz_encoder_princeton_test) {
|
MU_TEST(subghz_encoder_princeton_test) {
|
||||||
mu_assert(
|
mu_assert(
|
||||||
@ -803,6 +811,12 @@ MU_TEST(subghz_encoder_dooya_test) {
|
|||||||
"Test encoder " SUBGHZ_PROTOCOL_DOOYA_NAME " error\r\n");
|
"Test encoder " SUBGHZ_PROTOCOL_DOOYA_NAME " error\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MU_TEST(subghz_encoder_mastercode_test) {
|
||||||
|
mu_assert(
|
||||||
|
subghz_encoder_test(EXT_PATH("unit_tests/subghz/mastercode.sub")),
|
||||||
|
"Test encoder " SUBGHZ_PROTOCOL_MASTERCODE_NAME " error\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
MU_TEST(subghz_random_test) {
|
MU_TEST(subghz_random_test) {
|
||||||
mu_assert(subghz_decode_random_test(TEST_RANDOM_DIR_NAME), "Random test error\r\n");
|
mu_assert(subghz_decode_random_test(TEST_RANDOM_DIR_NAME), "Random test error\r\n");
|
||||||
}
|
}
|
||||||
@ -853,6 +867,7 @@ MU_TEST_SUITE(subghz) {
|
|||||||
MU_RUN_TEST(subghz_decoder_alutech_at_4n_test);
|
MU_RUN_TEST(subghz_decoder_alutech_at_4n_test);
|
||||||
MU_RUN_TEST(subghz_decoder_nice_one_test);
|
MU_RUN_TEST(subghz_decoder_nice_one_test);
|
||||||
MU_RUN_TEST(subghz_decoder_kinggates_stylo4k_test);
|
MU_RUN_TEST(subghz_decoder_kinggates_stylo4k_test);
|
||||||
|
MU_RUN_TEST(subghz_decoder_mastercode_test);
|
||||||
|
|
||||||
MU_RUN_TEST(subghz_encoder_princeton_test);
|
MU_RUN_TEST(subghz_encoder_princeton_test);
|
||||||
MU_RUN_TEST(subghz_encoder_came_test);
|
MU_RUN_TEST(subghz_encoder_came_test);
|
||||||
@ -879,6 +894,7 @@ MU_TEST_SUITE(subghz) {
|
|||||||
MU_RUN_TEST(subghz_encoder_smc5326_test);
|
MU_RUN_TEST(subghz_encoder_smc5326_test);
|
||||||
MU_RUN_TEST(subghz_encoder_holtek_ht12x_test);
|
MU_RUN_TEST(subghz_encoder_holtek_ht12x_test);
|
||||||
MU_RUN_TEST(subghz_encoder_dooya_test);
|
MU_RUN_TEST(subghz_encoder_dooya_test);
|
||||||
|
MU_RUN_TEST(subghz_encoder_mastercode_test);
|
||||||
|
|
||||||
MU_RUN_TEST(subghz_random_test);
|
MU_RUN_TEST(subghz_random_test);
|
||||||
subghz_test_deinit();
|
subghz_test_deinit();
|
||||||
|
@ -78,6 +78,16 @@ void minunit_print_fail(const char* str) {
|
|||||||
printf(_FURI_LOG_CLR_E "%s\r\n" _FURI_LOG_CLR_RESET, str);
|
printf(_FURI_LOG_CLR_E "%s\r\n" _FURI_LOG_CLR_RESET, str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void minunit_printf_warning(const char* format, ...) {
|
||||||
|
FuriString* str = furi_string_alloc();
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
furi_string_vprintf(str, format, args);
|
||||||
|
va_end(args);
|
||||||
|
printf(_FURI_LOG_CLR_W "%s\r\n" _FURI_LOG_CLR_RESET, furi_string_get_cstr(str));
|
||||||
|
furi_string_free(str);
|
||||||
|
}
|
||||||
|
|
||||||
void unit_tests_cli(Cli* cli, FuriString* args, void* context) {
|
void unit_tests_cli(Cli* cli, FuriString* args, void* context) {
|
||||||
UNUSED(cli);
|
UNUSED(cli);
|
||||||
UNUSED(args);
|
UNUSED(args);
|
||||||
|
@ -3,7 +3,6 @@ App(
|
|||||||
name="USB Mouse",
|
name="USB Mouse",
|
||||||
apptype=FlipperAppType.DEBUG,
|
apptype=FlipperAppType.DEBUG,
|
||||||
entry_point="usb_mouse_app",
|
entry_point="usb_mouse_app",
|
||||||
cdefines=["APP_USB_MOUSE"],
|
|
||||||
requires=["gui"],
|
requires=["gui"],
|
||||||
stack_size=1 * 1024,
|
stack_size=1 * 1024,
|
||||||
order=60,
|
order=60,
|
||||||
|
@ -3,7 +3,6 @@ App(
|
|||||||
name="USB Test",
|
name="USB Test",
|
||||||
apptype=FlipperAppType.DEBUG,
|
apptype=FlipperAppType.DEBUG,
|
||||||
entry_point="usb_test_app",
|
entry_point="usb_test_app",
|
||||||
cdefines=["APP_USB_TEST"],
|
|
||||||
requires=["gui"],
|
requires=["gui"],
|
||||||
stack_size=1 * 1024,
|
stack_size=1 * 1024,
|
||||||
order=50,
|
order=50,
|
||||||
|
@ -3,7 +3,6 @@ App(
|
|||||||
name="Vibro Test",
|
name="Vibro Test",
|
||||||
apptype=FlipperAppType.DEBUG,
|
apptype=FlipperAppType.DEBUG,
|
||||||
entry_point="vibro_test_app",
|
entry_point="vibro_test_app",
|
||||||
cdefines=["APP_VIBRO_TEST"],
|
|
||||||
requires=["gui"],
|
requires=["gui"],
|
||||||
stack_size=1 * 1024,
|
stack_size=1 * 1024,
|
||||||
order=20,
|
order=20,
|
||||||
|
@ -12,12 +12,12 @@ static bool archive_favorites_read_line(File* file, FuriString* str_result) {
|
|||||||
bool result = false;
|
bool result = false;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
uint16_t read_count = storage_file_read(file, buffer, ARCHIVE_FAV_FILE_BUF_LEN);
|
size_t read_count = storage_file_read(file, buffer, ARCHIVE_FAV_FILE_BUF_LEN);
|
||||||
if(storage_file_get_error(file) != FSE_OK) {
|
if(storage_file_get_error(file) != FSE_OK) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(uint16_t i = 0; i < read_count; i++) {
|
for(size_t i = 0; i < read_count; i++) {
|
||||||
if(buffer[i] == '\n') {
|
if(buffer[i] == '\n') {
|
||||||
uint32_t position = storage_file_tell(file);
|
uint32_t position = storage_file_tell(file);
|
||||||
if(storage_file_get_error(file) != FSE_OK) {
|
if(storage_file_get_error(file) != FSE_OK) {
|
||||||
|
@ -174,22 +174,21 @@ void ibutton_free(iButton* ibutton) {
|
|||||||
free(ibutton);
|
free(ibutton);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ibutton_load_key(iButton* ibutton) {
|
bool ibutton_load_key(iButton* ibutton, bool show_error) {
|
||||||
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewLoading);
|
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewLoading);
|
||||||
|
|
||||||
const bool success = ibutton_protocols_load(
|
const bool success = ibutton_protocols_load(
|
||||||
ibutton->protocols, ibutton->key, furi_string_get_cstr(ibutton->file_path));
|
ibutton->protocols, ibutton->key, furi_string_get_cstr(ibutton->file_path));
|
||||||
|
|
||||||
if(!success) {
|
if(success) {
|
||||||
dialog_message_show_storage_error(ibutton->dialogs, "Cannot load\nkey file");
|
|
||||||
|
|
||||||
} else {
|
|
||||||
FuriString* tmp = furi_string_alloc();
|
FuriString* tmp = furi_string_alloc();
|
||||||
|
|
||||||
path_extract_filename(ibutton->file_path, tmp, true);
|
path_extract_filename(ibutton->file_path, tmp, true);
|
||||||
strncpy(ibutton->key_name, furi_string_get_cstr(tmp), IBUTTON_KEY_NAME_SIZE);
|
strncpy(ibutton->key_name, furi_string_get_cstr(tmp), IBUTTON_KEY_NAME_SIZE);
|
||||||
|
|
||||||
furi_string_free(tmp);
|
furi_string_free(tmp);
|
||||||
|
} else if(show_error) {
|
||||||
|
dialog_message_show_storage_error(ibutton->dialogs, "Cannot load\nkey file");
|
||||||
}
|
}
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
@ -210,7 +209,7 @@ bool ibutton_select_and_load_key(iButton* ibutton) {
|
|||||||
if(!dialog_file_browser_show(
|
if(!dialog_file_browser_show(
|
||||||
ibutton->dialogs, ibutton->file_path, ibutton->file_path, &browser_options))
|
ibutton->dialogs, ibutton->file_path, ibutton->file_path, &browser_options))
|
||||||
break;
|
break;
|
||||||
success = ibutton_load_key(ibutton);
|
success = ibutton_load_key(ibutton, true);
|
||||||
} while(!success);
|
} while(!success);
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
@ -283,7 +282,7 @@ int32_t ibutton_app(void* arg) {
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
furi_string_set(ibutton->file_path, (const char*)arg);
|
furi_string_set(ibutton->file_path, (const char*)arg);
|
||||||
key_loaded = ibutton_load_key(ibutton);
|
key_loaded = ibutton_load_key(ibutton, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,7 +90,7 @@ typedef enum {
|
|||||||
} iButtonNotificationMessage;
|
} iButtonNotificationMessage;
|
||||||
|
|
||||||
bool ibutton_select_and_load_key(iButton* ibutton);
|
bool ibutton_select_and_load_key(iButton* ibutton);
|
||||||
bool ibutton_load_key(iButton* ibutton);
|
bool ibutton_load_key(iButton* ibutton, bool show_error);
|
||||||
bool ibutton_save_key(iButton* ibutton);
|
bool ibutton_save_key(iButton* ibutton);
|
||||||
bool ibutton_delete_key(iButton* ibutton);
|
bool ibutton_delete_key(iButton* ibutton);
|
||||||
void ibutton_reset_key(iButton* ibutton);
|
void ibutton_reset_key(iButton* ibutton);
|
||||||
|
@ -43,7 +43,7 @@ bool ibutton_scene_add_value_on_event(void* context, SceneManagerEvent event) {
|
|||||||
} else if(event.type == SceneManagerEventTypeBack) {
|
} else if(event.type == SceneManagerEventTypeBack) {
|
||||||
// User cancelled editing, reload the key from storage
|
// User cancelled editing, reload the key from storage
|
||||||
if(scene_manager_has_previous_scene(scene_manager, iButtonSceneSavedKeyMenu)) {
|
if(scene_manager_has_previous_scene(scene_manager, iButtonSceneSavedKeyMenu)) {
|
||||||
if(!ibutton_load_key(ibutton)) {
|
if(!ibutton_load_key(ibutton, true)) {
|
||||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||||
scene_manager, iButtonSceneStart);
|
scene_manager, iButtonSceneStart);
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ bool ibutton_scene_rpc_on_event(void* context, SceneManagerEvent event) {
|
|||||||
if(event.event == iButtonCustomEventRpcLoadFile) {
|
if(event.event == iButtonCustomEventRpcLoadFile) {
|
||||||
bool result = false;
|
bool result = false;
|
||||||
|
|
||||||
if(ibutton_load_key(ibutton)) {
|
if(ibutton_load_key(ibutton, false)) {
|
||||||
popup_set_text(popup, ibutton->key_name, 82, 32, AlignCenter, AlignTop);
|
popup_set_text(popup, ibutton->key_name, 82, 32, AlignCenter, AlignTop);
|
||||||
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewPopup);
|
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewPopup);
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
#include <nfc/nfc_device.h>
|
#include <nfc/nfc_device.h>
|
||||||
#include <nfc/helpers/nfc_util.h>
|
#include <nfc/helpers/nfc_util.h>
|
||||||
#include <nfc/protocols/mf_classic/mf_classic_poller_sync_api.h>
|
#include <nfc/protocols/mf_classic/mf_classic_poller_sync.h>
|
||||||
|
|
||||||
#define TAG "Plantain"
|
#define TAG "Plantain"
|
||||||
|
|
||||||
@ -91,7 +91,7 @@ static bool plantain_verify_type(Nfc* nfc, MfClassicType type) {
|
|||||||
|
|
||||||
MfClassicAuthContext auth_context;
|
MfClassicAuthContext auth_context;
|
||||||
MfClassicError error =
|
MfClassicError error =
|
||||||
mf_classic_poller_auth(nfc, block_num, &key, MfClassicKeyTypeA, &auth_context);
|
mf_classic_poller_sync_auth(nfc, block_num, &key, MfClassicKeyTypeA, &auth_context);
|
||||||
if(error != MfClassicErrorNone) {
|
if(error != MfClassicErrorNone) {
|
||||||
FURI_LOG_D(TAG, "Failed to read block %u: %d", block_num, error);
|
FURI_LOG_D(TAG, "Failed to read block %u: %d", block_num, error);
|
||||||
break;
|
break;
|
||||||
@ -119,7 +119,7 @@ static bool plantain_read(Nfc* nfc, NfcDevice* device) {
|
|||||||
|
|
||||||
do {
|
do {
|
||||||
MfClassicType type = MfClassicTypeMini;
|
MfClassicType type = MfClassicTypeMini;
|
||||||
MfClassicError error = mf_classic_poller_detect_type(nfc, &type);
|
MfClassicError error = mf_classic_poller_sync_detect_type(nfc, &type);
|
||||||
if(error != MfClassicErrorNone) break;
|
if(error != MfClassicErrorNone) break;
|
||||||
|
|
||||||
data->type = type;
|
data->type = type;
|
||||||
@ -134,7 +134,7 @@ static bool plantain_read(Nfc* nfc, NfcDevice* device) {
|
|||||||
FURI_BIT_SET(keys.key_b_mask, i);
|
FURI_BIT_SET(keys.key_b_mask, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
error = mf_classic_poller_read(nfc, &keys, data);
|
error = mf_classic_poller_sync_read(nfc, &keys, data);
|
||||||
if(error != MfClassicErrorNone) {
|
if(error != MfClassicErrorNone) {
|
||||||
FURI_LOG_W(TAG, "Failed to read data");
|
FURI_LOG_W(TAG, "Failed to read data");
|
||||||
break;
|
break;
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
#include <nfc/nfc_device.h>
|
#include <nfc/nfc_device.h>
|
||||||
#include <nfc/helpers/nfc_util.h>
|
#include <nfc/helpers/nfc_util.h>
|
||||||
#include <nfc/protocols/mf_classic/mf_classic_poller_sync_api.h>
|
#include <nfc/protocols/mf_classic/mf_classic_poller_sync.h>
|
||||||
|
|
||||||
#define TAG "Troika"
|
#define TAG "Troika"
|
||||||
|
|
||||||
@ -91,7 +91,7 @@ static bool troika_verify_type(Nfc* nfc, MfClassicType type) {
|
|||||||
|
|
||||||
MfClassicAuthContext auth_context;
|
MfClassicAuthContext auth_context;
|
||||||
MfClassicError error =
|
MfClassicError error =
|
||||||
mf_classic_poller_auth(nfc, block_num, &key, MfClassicKeyTypeA, &auth_context);
|
mf_classic_poller_sync_auth(nfc, block_num, &key, MfClassicKeyTypeA, &auth_context);
|
||||||
if(error != MfClassicErrorNone) {
|
if(error != MfClassicErrorNone) {
|
||||||
FURI_LOG_D(TAG, "Failed to read block %u: %d", block_num, error);
|
FURI_LOG_D(TAG, "Failed to read block %u: %d", block_num, error);
|
||||||
break;
|
break;
|
||||||
@ -118,7 +118,7 @@ static bool troika_read(Nfc* nfc, NfcDevice* device) {
|
|||||||
|
|
||||||
do {
|
do {
|
||||||
MfClassicType type = MfClassicTypeMini;
|
MfClassicType type = MfClassicTypeMini;
|
||||||
MfClassicError error = mf_classic_poller_detect_type(nfc, &type);
|
MfClassicError error = mf_classic_poller_sync_detect_type(nfc, &type);
|
||||||
if(error != MfClassicErrorNone) break;
|
if(error != MfClassicErrorNone) break;
|
||||||
|
|
||||||
data->type = type;
|
data->type = type;
|
||||||
@ -136,7 +136,7 @@ static bool troika_read(Nfc* nfc, NfcDevice* device) {
|
|||||||
FURI_BIT_SET(keys.key_b_mask, i);
|
FURI_BIT_SET(keys.key_b_mask, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
error = mf_classic_poller_read(nfc, &keys, data);
|
error = mf_classic_poller_sync_read(nfc, &keys, data);
|
||||||
if(error != MfClassicErrorNone) {
|
if(error != MfClassicErrorNone) {
|
||||||
FURI_LOG_W(TAG, "Failed to read data");
|
FURI_LOG_W(TAG, "Failed to read data");
|
||||||
break;
|
break;
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
#include <nfc/nfc_device.h>
|
#include <nfc/nfc_device.h>
|
||||||
#include <nfc/helpers/nfc_util.h>
|
#include <nfc/helpers/nfc_util.h>
|
||||||
#include <nfc/protocols/mf_classic/mf_classic_poller_sync_api.h>
|
#include <nfc/protocols/mf_classic/mf_classic_poller_sync.h>
|
||||||
|
|
||||||
#define TAG "TwoCities"
|
#define TAG "TwoCities"
|
||||||
|
|
||||||
@ -49,7 +49,7 @@ bool two_cities_verify(Nfc* nfc) {
|
|||||||
|
|
||||||
MfClassicAuthContext auth_ctx = {};
|
MfClassicAuthContext auth_ctx = {};
|
||||||
MfClassicError error =
|
MfClassicError error =
|
||||||
mf_classic_poller_auth(nfc, block_num, &key, MfClassicKeyTypeA, &auth_ctx);
|
mf_classic_poller_sync_auth(nfc, block_num, &key, MfClassicKeyTypeA, &auth_ctx);
|
||||||
if(error != MfClassicErrorNone) {
|
if(error != MfClassicErrorNone) {
|
||||||
FURI_LOG_D(TAG, "Failed to read block %u: %d", block_num, error);
|
FURI_LOG_D(TAG, "Failed to read block %u: %d", block_num, error);
|
||||||
break;
|
break;
|
||||||
@ -72,7 +72,7 @@ static bool two_cities_read(Nfc* nfc, NfcDevice* device) {
|
|||||||
|
|
||||||
do {
|
do {
|
||||||
MfClassicType type = MfClassicTypeMini;
|
MfClassicType type = MfClassicTypeMini;
|
||||||
MfClassicError error = mf_classic_poller_detect_type(nfc, &type);
|
MfClassicError error = mf_classic_poller_sync_detect_type(nfc, &type);
|
||||||
if(error != MfClassicErrorNone) break;
|
if(error != MfClassicErrorNone) break;
|
||||||
|
|
||||||
data->type = type;
|
data->type = type;
|
||||||
@ -84,7 +84,7 @@ static bool two_cities_read(Nfc* nfc, NfcDevice* device) {
|
|||||||
FURI_BIT_SET(keys.key_b_mask, i);
|
FURI_BIT_SET(keys.key_b_mask, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
error = mf_classic_poller_read(nfc, &keys, data);
|
error = mf_classic_poller_sync_read(nfc, &keys, data);
|
||||||
if(error != MfClassicErrorNone) {
|
if(error != MfClassicErrorNone) {
|
||||||
FURI_LOG_W(TAG, "Failed to read data");
|
FURI_LOG_W(TAG, "Failed to read data");
|
||||||
break;
|
break;
|
||||||
|
@ -444,7 +444,7 @@ static bool notification_load_settings(NotificationApp* app) {
|
|||||||
storage_file_open(file, NOTIFICATION_SETTINGS_PATH, FSAM_READ, FSOM_OPEN_EXISTING);
|
storage_file_open(file, NOTIFICATION_SETTINGS_PATH, FSAM_READ, FSOM_OPEN_EXISTING);
|
||||||
|
|
||||||
if(fs_result) {
|
if(fs_result) {
|
||||||
uint16_t bytes_count = storage_file_read(file, &settings, settings_size);
|
size_t bytes_count = storage_file_read(file, &settings, settings_size);
|
||||||
|
|
||||||
if(bytes_count != settings_size) {
|
if(bytes_count != settings_size) {
|
||||||
fs_result = false;
|
fs_result = false;
|
||||||
@ -488,7 +488,7 @@ static bool notification_save_settings(NotificationApp* app) {
|
|||||||
storage_file_open(file, NOTIFICATION_SETTINGS_PATH, FSAM_WRITE, FSOM_CREATE_ALWAYS);
|
storage_file_open(file, NOTIFICATION_SETTINGS_PATH, FSAM_WRITE, FSOM_CREATE_ALWAYS);
|
||||||
|
|
||||||
if(fs_result) {
|
if(fs_result) {
|
||||||
uint16_t bytes_count = storage_file_write(file, &settings, settings_size);
|
size_t bytes_count = storage_file_write(file, &settings, settings_size);
|
||||||
|
|
||||||
if(bytes_count != settings_size) {
|
if(bytes_count != settings_size) {
|
||||||
fs_result = false;
|
fs_result = false;
|
||||||
|
@ -466,7 +466,7 @@ static void rpc_system_storage_write_process(const PB_Main* request, void* conte
|
|||||||
request->content.storage_write_request.file.data->size) {
|
request->content.storage_write_request.file.data->size) {
|
||||||
uint8_t* buffer = request->content.storage_write_request.file.data->bytes;
|
uint8_t* buffer = request->content.storage_write_request.file.data->bytes;
|
||||||
size_t buffer_size = request->content.storage_write_request.file.data->size;
|
size_t buffer_size = request->content.storage_write_request.file.data->size;
|
||||||
uint16_t written_size = storage_file_write(file, buffer, buffer_size);
|
size_t written_size = storage_file_write(file, buffer, buffer_size);
|
||||||
fs_operation_success = (written_size == buffer_size);
|
fs_operation_success = (written_size == buffer_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,6 +165,13 @@ typedef struct {
|
|||||||
* @param total_space pointer to total space value
|
* @param total_space pointer to total space value
|
||||||
* @param free_space pointer to free space value
|
* @param free_space pointer to free space value
|
||||||
* @return FS_Error error info
|
* @return FS_Error error info
|
||||||
|
*
|
||||||
|
* @var FS_Common_Api::equivalent_path
|
||||||
|
* @brief Test whether two paths are equivalent (e.g differing case on a case-insensitive fs)
|
||||||
|
* @param path1 first path to be compared
|
||||||
|
* @param path2 second path to be compared
|
||||||
|
* @param truncate if set to true, compare only up to the path1's length
|
||||||
|
* @return true if path1 and path2 are considered equivalent
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
FS_Error (*const stat)(void* context, const char* path, FileInfo* fileinfo);
|
FS_Error (*const stat)(void* context, const char* path, FileInfo* fileinfo);
|
||||||
@ -175,6 +182,7 @@ typedef struct {
|
|||||||
const char* fs_path,
|
const char* fs_path,
|
||||||
uint64_t* total_space,
|
uint64_t* total_space,
|
||||||
uint64_t* free_space);
|
uint64_t* free_space);
|
||||||
|
bool (*const equivalent_path)(const char* path1, const char* path2);
|
||||||
} FS_Common_Api;
|
} FS_Common_Api;
|
||||||
|
|
||||||
/** Full filesystem api structure */
|
/** Full filesystem api structure */
|
||||||
|
@ -1,4 +1,9 @@
|
|||||||
|
/**
|
||||||
|
* @file storage.h
|
||||||
|
* @brief APIs for working with storages, directories and files.
|
||||||
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "filesystem_api_defines.h"
|
#include "filesystem_api_defines.h"
|
||||||
#include "storage_sd_api.h"
|
#include "storage_sd_api.h"
|
||||||
@ -23,43 +28,62 @@ extern "C" {
|
|||||||
|
|
||||||
typedef struct Storage Storage;
|
typedef struct Storage Storage;
|
||||||
|
|
||||||
/** Allocates and initializes a file descriptor
|
/**
|
||||||
* @return File*
|
* @brief Allocate and initialize a file instance.
|
||||||
|
*
|
||||||
|
* @param storage pointer to a storage API instance.
|
||||||
|
* @return pointer to the created instance.
|
||||||
*/
|
*/
|
||||||
File* storage_file_alloc(Storage* storage);
|
File* storage_file_alloc(Storage* storage);
|
||||||
|
|
||||||
/** Frees the file descriptor. Closes the file if it was open.
|
/**
|
||||||
|
* @brief Free the file instance.
|
||||||
|
*
|
||||||
|
* If the file was open, calling this function will close it automatically.
|
||||||
|
* @param file pointer to the file instance to be freed.
|
||||||
*/
|
*/
|
||||||
void storage_file_free(File* file);
|
void storage_file_free(File* file);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enumeration of events emitted by the storage through the PubSub system.
|
||||||
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
StorageEventTypeCardMount,
|
StorageEventTypeCardMount, /**< SD card was mounted. */
|
||||||
StorageEventTypeCardUnmount,
|
StorageEventTypeCardUnmount, /**< SD card was unmounted. */
|
||||||
StorageEventTypeCardMountError,
|
StorageEventTypeCardMountError, /**< An error occurred during mounting of an SD card. */
|
||||||
StorageEventTypeFileClose,
|
StorageEventTypeFileClose, /**< A file was closed. */
|
||||||
StorageEventTypeDirClose,
|
StorageEventTypeDirClose, /**< A directory was closed. */
|
||||||
} StorageEventType;
|
} StorageEventType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Storage event (passed to the PubSub callback).
|
||||||
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
StorageEventType type;
|
StorageEventType type; /**< Type of the event. */
|
||||||
} StorageEvent;
|
} StorageEvent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get storage pubsub.
|
* @brief Get the storage pubsub instance.
|
||||||
|
*
|
||||||
* Storage will send StorageEvent messages.
|
* Storage will send StorageEvent messages.
|
||||||
* @param storage
|
*
|
||||||
* @return FuriPubSub*
|
* @param storage pointer to a storage API instance.
|
||||||
|
* @return pointer to the pubsub instance.
|
||||||
*/
|
*/
|
||||||
FuriPubSub* storage_get_pubsub(Storage* storage);
|
FuriPubSub* storage_get_pubsub(Storage* storage);
|
||||||
|
|
||||||
/******************* File Functions *******************/
|
/******************* File Functions *******************/
|
||||||
|
|
||||||
/** Opens an existing file or create a new one.
|
/**
|
||||||
* @param file pointer to file object.
|
* @brief Open an existing file or create a new one.
|
||||||
* @param path path to file
|
*
|
||||||
* @param access_mode access mode from FS_AccessMode
|
* @warning The calling code MUST call storage_file_close() even if the open operation had failed.
|
||||||
|
*
|
||||||
|
* @param file pointer to the file instance to be opened.
|
||||||
|
* @param path pointer to a zero-terminated string containing the path to the file to be opened.
|
||||||
|
* @param access_mode access mode from FS_AccessMode.
|
||||||
* @param open_mode open mode from FS_OpenMode
|
* @param open_mode open mode from FS_OpenMode
|
||||||
* @return success flag. You need to close the file even if the open operation failed.
|
* @return true if the file was successfully opened, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool storage_file_open(
|
bool storage_file_open(
|
||||||
File* file,
|
File* file,
|
||||||
@ -67,202 +91,267 @@ bool storage_file_open(
|
|||||||
FS_AccessMode access_mode,
|
FS_AccessMode access_mode,
|
||||||
FS_OpenMode open_mode);
|
FS_OpenMode open_mode);
|
||||||
|
|
||||||
/** Close the file.
|
/**
|
||||||
* @param file pointer to a file object, the file object will be freed.
|
* @brief Close the file.
|
||||||
* @return success flag
|
*
|
||||||
|
* @param file pointer to the file instance to be closed.
|
||||||
|
* @return true if the file was successfully closed, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool storage_file_close(File* file);
|
bool storage_file_close(File* file);
|
||||||
|
|
||||||
/** Tells if the file is open
|
/**
|
||||||
* @param file pointer to a file object
|
* @brief Check whether the file is open.
|
||||||
* @return bool true if file is open
|
*
|
||||||
|
* @param file pointer to the file instance in question.
|
||||||
|
* @return true if the file is open, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool storage_file_is_open(File* file);
|
bool storage_file_is_open(File* file);
|
||||||
|
|
||||||
/** Tells if the file is a directory
|
/**
|
||||||
* @param file pointer to a file object
|
* @brief Check whether a file instance represents a directory.
|
||||||
* @return bool true if file is a directory
|
*
|
||||||
|
* @param file pointer to the file instance in question.
|
||||||
|
* @return true if the file instance represents a directory, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool storage_file_is_dir(File* file);
|
bool storage_file_is_dir(File* file);
|
||||||
|
|
||||||
/** Reads bytes from a file into a buffer
|
/**
|
||||||
* @param file pointer to file object.
|
* @brief Read bytes from a file into a buffer.
|
||||||
* @param buff pointer to a buffer, for reading
|
*
|
||||||
* @param bytes_to_read how many bytes to read. Must be less than or equal to the size of the buffer.
|
* @param file pointer to the file instance to read from.
|
||||||
* @return uint16_t how many bytes were actually read
|
* @param buff pointer to the buffer to be filled with read data.
|
||||||
|
* @param bytes_to_read number of bytes to read. Must be less than or equal to the size of the buffer.
|
||||||
|
* @return actual number of bytes read (may be fewer than requested).
|
||||||
*/
|
*/
|
||||||
uint16_t storage_file_read(File* file, void* buff, uint16_t bytes_to_read);
|
size_t storage_file_read(File* file, void* buff, size_t bytes_to_read);
|
||||||
|
|
||||||
/** Writes bytes from a buffer to a file
|
/**
|
||||||
* @param file pointer to file object.
|
* @brief Write bytes from a buffer to a file.
|
||||||
* @param buff pointer to buffer, for writing
|
*
|
||||||
* @param bytes_to_write how many bytes to write. Must be less than or equal to the size of the buffer.
|
* @param file pointer to the file instance to write into.
|
||||||
* @return uint16_t how many bytes were actually written
|
* @param buff pointer to the buffer containing the data to be written.
|
||||||
|
* @param bytes_to_write number of bytes to write. Must be less than or equal to the size of the buffer.
|
||||||
|
* @return actual number of bytes written (may be fewer than requested).
|
||||||
*/
|
*/
|
||||||
uint16_t storage_file_write(File* file, const void* buff, uint16_t bytes_to_write);
|
size_t storage_file_write(File* file, const void* buff, size_t bytes_to_write);
|
||||||
|
|
||||||
/** Moves the r/w pointer
|
/**
|
||||||
* @param file pointer to file object.
|
* @brief Change the current access position in a file.
|
||||||
* @param offset offset to move the r/w pointer
|
*
|
||||||
* @param from_start set an offset from the start or from the current position
|
* @param file pointer to the file instance in question.
|
||||||
|
* @param offset access position offset (meaning depends on from_start parameter).
|
||||||
|
* @param from_start if true, set the access position relative to the file start, otherwise relative to the current position.
|
||||||
* @return success flag
|
* @return success flag
|
||||||
*/
|
*/
|
||||||
bool storage_file_seek(File* file, uint32_t offset, bool from_start);
|
bool storage_file_seek(File* file, uint32_t offset, bool from_start);
|
||||||
|
|
||||||
/** Gets the position of the r/w pointer
|
/**
|
||||||
* @param file pointer to file object.
|
* @brief Get the current access position.
|
||||||
* @return uint64_t position of the r/w pointer
|
*
|
||||||
|
* @param file pointer to the file instance in question.
|
||||||
|
* @return current access position.
|
||||||
*/
|
*/
|
||||||
uint64_t storage_file_tell(File* file);
|
uint64_t storage_file_tell(File* file);
|
||||||
|
|
||||||
/** Truncates the file size to the current position of the r/w pointer
|
/**
|
||||||
* @param file pointer to file object.
|
* @brief Truncate the file size to the current access position.
|
||||||
* @return bool success flag
|
*
|
||||||
|
* @param file pointer to the file instance to be truncated.
|
||||||
|
* @return true if the file was successfully truncated, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool storage_file_truncate(File* file);
|
bool storage_file_truncate(File* file);
|
||||||
|
|
||||||
/** Gets the size of the file
|
/**
|
||||||
* @param file pointer to file object.
|
* @brief Get the file size.
|
||||||
* @return uint64_t size of the file
|
*
|
||||||
|
* @param file pointer to the file instance in question.
|
||||||
|
* @return size of the file, in bytes.
|
||||||
*/
|
*/
|
||||||
uint64_t storage_file_size(File* file);
|
uint64_t storage_file_size(File* file);
|
||||||
|
|
||||||
/** Writes file cache to storage
|
/**
|
||||||
* @param file pointer to file object.
|
* @brief Synchronise the file cache with the actual storage.
|
||||||
* @return bool success flag
|
*
|
||||||
|
* @param file pointer to the file instance in question.
|
||||||
|
* @return true if the file was successfully synchronised, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool storage_file_sync(File* file);
|
bool storage_file_sync(File* file);
|
||||||
|
|
||||||
/** Checks that the r/w pointer is at the end of the file
|
/**
|
||||||
* @param file pointer to file object.
|
* @brief Check whether the current access position is at the end of the file.
|
||||||
* @return bool success flag
|
*
|
||||||
|
* @param file pointer to a file instance in question.
|
||||||
|
* @return bool true if the current access position is at the end of the file, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool storage_file_eof(File* file);
|
bool storage_file_eof(File* file);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Check that file exists
|
* @brief Check whether a file exists.
|
||||||
*
|
*
|
||||||
* @param storage
|
* @param storage pointer to a storage API instance.
|
||||||
* @param path
|
* @param path pointer to a zero-terminated string containing the path to the file in question.
|
||||||
* @return true if file exists
|
* @return true if the file exists, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool storage_file_exists(Storage* storage, const char* path);
|
bool storage_file_exists(Storage* storage, const char* path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Copy data from one opened file to another opened file
|
* @brief Copy data from a source file to the destination file.
|
||||||
* Size bytes will be copied from current position of source file to current position of destination file
|
*
|
||||||
|
* Both files must be opened prior to calling this function.
|
||||||
|
*
|
||||||
|
* The requested amount of bytes will be copied from the current access position
|
||||||
|
* in the source file to the current access position in the destination file.
|
||||||
*
|
*
|
||||||
* @param source source file
|
* @param source pointer to a source file instance.
|
||||||
* @param destination destination file
|
* @param destination pointer to a destination file instance.
|
||||||
* @param size size of data to copy
|
* @param size data size to be copied, in bytes.
|
||||||
* @return bool success flag
|
* @return true if the data was successfully copied, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool storage_file_copy_to_file(File* source, File* destination, uint32_t size);
|
bool storage_file_copy_to_file(File* source, File* destination, size_t size);
|
||||||
|
|
||||||
/******************* Dir Functions *******************/
|
/******************* Directory Functions *******************/
|
||||||
|
|
||||||
/** Opens a directory to get objects from it
|
/**
|
||||||
* @param app pointer to the api
|
* @brief Open a directory.
|
||||||
* @param file pointer to file object.
|
*
|
||||||
* @param path path to directory
|
* Opening a directory is necessary to be able to read its contents with storage_dir_read().
|
||||||
* @return bool success flag. You need to close the directory even if the open operation failed.
|
*
|
||||||
|
* @warning The calling code MUST call storage_dir_close() even if the open operation had failed.
|
||||||
|
*
|
||||||
|
* @param file pointer to a file instance representing the directory in question.
|
||||||
|
* @param path pointer to a zero-terminated string containing the path of the directory in question.
|
||||||
|
* @return true if the directory was successfully opened, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool storage_dir_open(File* file, const char* path);
|
bool storage_dir_open(File* file, const char* path);
|
||||||
|
|
||||||
/** Close the directory. Also free file handle structure and point it to the NULL.
|
/**
|
||||||
* @param file pointer to a file object.
|
* @brief Close the directory.
|
||||||
* @return bool success flag
|
*
|
||||||
|
* @param file pointer to a file instance representing the directory in question.
|
||||||
|
* @return true if the directory was successfully closed, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool storage_dir_close(File* file);
|
bool storage_dir_close(File* file);
|
||||||
|
|
||||||
/** Reads the next object in the directory
|
/**
|
||||||
* @param file pointer to file object.
|
* @brief Get the next item in the directory.
|
||||||
* @param fileinfo pointer to the read FileInfo, may be NULL
|
*
|
||||||
* @param name pointer to name buffer, may be NULL
|
* If the next object does not exist, this function returns false as well
|
||||||
* @param name_length name buffer length
|
* and sets the file error id to FSE_NOT_EXIST.
|
||||||
* @return success flag (if the next object does not exist, it also returns false and sets the file error id to FSE_NOT_EXIST)
|
*
|
||||||
|
* @param file pointer to a file instance representing the directory in question.
|
||||||
|
* @param fileinfo pointer to the FileInfo structure to contain the info (may be NULL).
|
||||||
|
* @param name pointer to the buffer to contain the name (may be NULL).
|
||||||
|
* @param name_length maximum capacity of the name buffer, in bytes.
|
||||||
|
* @return true if the next item was successfully read, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool storage_dir_read(File* file, FileInfo* fileinfo, char* name, uint16_t name_length);
|
bool storage_dir_read(File* file, FileInfo* fileinfo, char* name, uint16_t name_length);
|
||||||
|
|
||||||
/** Rewinds the read pointer to first item in the directory
|
/**
|
||||||
* @param file pointer to file object.
|
* @brief Change the access position to first item in the directory.
|
||||||
* @return bool success flag
|
*
|
||||||
|
* @param file pointer to a file instance representing the directory in question.
|
||||||
|
* @return true if the access position was successfully changed, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool storage_dir_rewind(File* file);
|
bool storage_dir_rewind(File* file);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Check that dir exists
|
* @brief Check whether a directory exists.
|
||||||
*
|
*
|
||||||
* @param storage
|
* @param storage pointer to a storage API instance.
|
||||||
* @param path
|
* @param path pointer to a zero-terminated string containing the path of the directory in question.
|
||||||
* @return bool
|
* @return true if the directory exists, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool storage_dir_exists(Storage* storage, const char* path);
|
bool storage_dir_exists(Storage* storage, const char* path);
|
||||||
|
|
||||||
/******************* Common Functions *******************/
|
/******************* Common Functions *******************/
|
||||||
|
|
||||||
/** Retrieves unix timestamp of last access
|
/**
|
||||||
|
* @brief Get the last access time in UNIX format.
|
||||||
*
|
*
|
||||||
* @param storage The storage instance
|
* @param storage pointer to a storage API instance.
|
||||||
* @param path path to file/directory
|
* @param path pointer to a zero-terminated string containing the path of the item in question.
|
||||||
* @param timestamp the timestamp pointer
|
* @param timestamp pointer to a value to contain the timestamp.
|
||||||
*
|
* @return FSE_OK if the timestamp has been successfully received, any other error code on failure.
|
||||||
* @return FS_Error operation result
|
|
||||||
*/
|
*/
|
||||||
FS_Error storage_common_timestamp(Storage* storage, const char* path, uint32_t* timestamp);
|
FS_Error storage_common_timestamp(Storage* storage, const char* path, uint32_t* timestamp);
|
||||||
|
|
||||||
/** Retrieves information about a file/directory
|
/**
|
||||||
* @param app pointer to the api
|
* @brief Get information about a file or a directory.
|
||||||
* @param path path to file/directory
|
*
|
||||||
* @param fileinfo pointer to the read FileInfo, may be NULL
|
* @param storage pointer to a storage API instance.
|
||||||
* @return FS_Error operation result
|
* @param path pointer to a zero-terminated string containing the path of the item in question.
|
||||||
|
* @param fileinfo pointer to the FileInfo structure to contain the info (may be NULL).
|
||||||
|
* @return FSE_OK if the info has been successfully received, any other error code on failure.
|
||||||
*/
|
*/
|
||||||
FS_Error storage_common_stat(Storage* storage, const char* path, FileInfo* fileinfo);
|
FS_Error storage_common_stat(Storage* storage, const char* path, FileInfo* fileinfo);
|
||||||
|
|
||||||
/** Removes a file/directory from the repository, the directory must be empty and the file/directory must not be open
|
/**
|
||||||
* @param app pointer to the api
|
* @brief Remove a file or a directory.
|
||||||
* @param path
|
*
|
||||||
* @return FS_Error operation result
|
* The directory must be empty.
|
||||||
|
* The file or the directory must NOT be open.
|
||||||
|
*
|
||||||
|
* @param storage pointer to a storage API instance.
|
||||||
|
* @param path pointer to a zero-terminated string containing the path of the item to be removed.
|
||||||
|
* @return FSE_OK if the file or directory has been successfully removed, any other error code on failure.
|
||||||
*/
|
*/
|
||||||
FS_Error storage_common_remove(Storage* storage, const char* path);
|
FS_Error storage_common_remove(Storage* storage, const char* path);
|
||||||
|
|
||||||
/** Renames file/directory, file/directory must not be open. Will overwrite existing file.
|
/**
|
||||||
* @param app pointer to the api
|
* @brief Rename a file or a directory.
|
||||||
* @param old_path old path
|
*
|
||||||
* @param new_path new path
|
* The file or the directory must NOT be open.
|
||||||
* @return FS_Error operation result
|
* Will overwrite the destination file if it already exists.
|
||||||
|
*
|
||||||
|
* Renaming a regular file to itself does nothing and always succeeds.
|
||||||
|
* Renaming a directory to itself or to a subdirectory of itself always fails.
|
||||||
|
*
|
||||||
|
* @param storage pointer to a storage API instance.
|
||||||
|
* @param old_path pointer to a zero-terminated string containing the source path.
|
||||||
|
* @param new_path pointer to a zero-terminated string containing the destination path.
|
||||||
|
* @return FSE_OK if the file or directory has been successfully renamed, any other error code on failure.
|
||||||
*/
|
*/
|
||||||
FS_Error storage_common_rename(Storage* storage, const char* old_path, const char* new_path);
|
FS_Error storage_common_rename(Storage* storage, const char* old_path, const char* new_path);
|
||||||
|
|
||||||
/** Copy file, file must not be open
|
/**
|
||||||
* @param app pointer to the api
|
* @brief Copy the file to a new location.
|
||||||
* @param old_path old path
|
*
|
||||||
* @param new_path new path
|
* The file must NOT be open at the time of calling this function.
|
||||||
* @return FS_Error operation result
|
*
|
||||||
|
* @param storage pointer to a storage API instance.
|
||||||
|
* @param old_path pointer to a zero-terminated string containing the source path.
|
||||||
|
* @param new_path pointer to a zero-terminated string containing the destination path.
|
||||||
|
* @return FSE_OK if the file has been successfully copied, any other error code on failure.
|
||||||
*/
|
*/
|
||||||
FS_Error storage_common_copy(Storage* storage, const char* old_path, const char* new_path);
|
FS_Error storage_common_copy(Storage* storage, const char* old_path, const char* new_path);
|
||||||
|
|
||||||
/** Copy one folder contents into another with rename of all conflicting files
|
/**
|
||||||
* @param app pointer to the api
|
* @brief Copy the contents of one directory into another and rename all conflicting files.
|
||||||
* @param old_path old path
|
*
|
||||||
* @param new_path new path
|
* @param storage pointer to a storage API instance.
|
||||||
* @return FS_Error operation result
|
* @param old_path pointer to a zero-terminated string containing the source path.
|
||||||
|
* @param new_path pointer to a zero-terminated string containing the destination path.
|
||||||
|
* @return FSE_OK if the directories have been successfully merged, any other error code on failure.
|
||||||
*/
|
*/
|
||||||
FS_Error storage_common_merge(Storage* storage, const char* old_path, const char* new_path);
|
FS_Error storage_common_merge(Storage* storage, const char* old_path, const char* new_path);
|
||||||
|
|
||||||
/** Creates a directory
|
/**
|
||||||
* @param app pointer to the api
|
* @brief Create a directory.
|
||||||
* @param path directory path
|
*
|
||||||
* @return FS_Error operation result
|
* @param storage pointer to a storage API instance.
|
||||||
|
* @param fs_path pointer to a zero-terminated string containing the directory path.
|
||||||
|
* @return FSE_OK if the directory has been successfully created, any other error code on failure.
|
||||||
*/
|
*/
|
||||||
FS_Error storage_common_mkdir(Storage* storage, const char* path);
|
FS_Error storage_common_mkdir(Storage* storage, const char* path);
|
||||||
|
|
||||||
/** Gets general information about the storage
|
/**
|
||||||
* @param app pointer to the api
|
* @brief Get the general information about the storage.
|
||||||
* @param fs_path the path to the storage of interest
|
*
|
||||||
* @param total_space pointer to total space record, will be filled
|
* @param storage pointer to a storage API instance.
|
||||||
* @param free_space pointer to free space record, will be filled
|
* @param fs_path pointer to a zero-terminated string containing the path to the storage question.
|
||||||
* @return FS_Error operation result
|
* @param total_space pointer to the value to contain the total capacity, in bytes.
|
||||||
|
* @param free_space pointer to the value to contain the available space, in bytes.
|
||||||
|
* @return FSE_OK if the information has been successfully received, any other error code on failure.
|
||||||
*/
|
*/
|
||||||
FS_Error storage_common_fs_info(
|
FS_Error storage_common_fs_info(
|
||||||
Storage* storage,
|
Storage* storage,
|
||||||
@ -271,150 +360,242 @@ FS_Error storage_common_fs_info(
|
|||||||
uint64_t* free_space);
|
uint64_t* free_space);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Parse aliases in path and replace them with real path
|
* @brief Parse aliases in a path and replace them with the real path.
|
||||||
* Also will create special folders if they are not exist
|
*
|
||||||
|
* Necessary special directories will be created automatically if they did not exist.
|
||||||
*
|
*
|
||||||
* @param storage
|
* @param storage pointer to a storage API instance.
|
||||||
* @param path
|
* @param path pointer to a zero-terminated string containing the path in question.
|
||||||
* @return bool
|
* @return true if the path was successfully resolved, false otherwise.
|
||||||
*/
|
*/
|
||||||
void storage_common_resolve_path_and_ensure_app_directory(Storage* storage, FuriString* path);
|
void storage_common_resolve_path_and_ensure_app_directory(Storage* storage, FuriString* path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Move content of one folder to another, with rename of all conflicting files.
|
* @brief Move the contents of source folder to destination one and rename all conflicting files.
|
||||||
* Source folder will be deleted if the migration is successful.
|
*
|
||||||
|
* Source folder will be deleted if the migration was successful.
|
||||||
*
|
*
|
||||||
* @param storage
|
* @param storage pointer to a storage API instance.
|
||||||
* @param source
|
* @param source pointer to a zero-terminated string containing the source path.
|
||||||
* @param dest
|
* @param dest pointer to a zero-terminated string containing the destination path.
|
||||||
* @return FS_Error
|
* @return FSE_OK if the migration was successfull completed, any other error code on failure.
|
||||||
*/
|
*/
|
||||||
FS_Error storage_common_migrate(Storage* storage, const char* source, const char* dest);
|
FS_Error storage_common_migrate(Storage* storage, const char* source, const char* dest);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Check that file or dir exists
|
* @brief Check whether a file or a directory exists.
|
||||||
*
|
*
|
||||||
* @param storage
|
* @param storage pointer to a storage API instance.
|
||||||
* @param path
|
* @param path pointer to a zero-terminated string containing the path in question.
|
||||||
* @return bool
|
* @return true if a file or a directory exists, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool storage_common_exists(Storage* storage, const char* path);
|
bool storage_common_exists(Storage* storage, const char* path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check whether two paths are equivalent.
|
||||||
|
*
|
||||||
|
* This function will resolve aliases and apply filesystem-specific
|
||||||
|
* rules to determine whether the two given paths are equivalent.
|
||||||
|
*
|
||||||
|
* Examples:
|
||||||
|
* - /int/text and /ext/test -> false (Different storages),
|
||||||
|
* - /int/Test and /int/test -> false (Case-sensitive storage),
|
||||||
|
* - /ext/Test and /ext/test -> true (Case-insensitive storage).
|
||||||
|
*
|
||||||
|
* If the truncate parameter is set to true, the second path will be
|
||||||
|
* truncated to be no longer than the first one. It is useful to determine
|
||||||
|
* whether path2 is a subdirectory of path1.
|
||||||
|
*
|
||||||
|
* @param storage pointer to a storage API instance.
|
||||||
|
* @param path1 pointer to a zero-terminated string containing the first path.
|
||||||
|
* @param path2 pointer to a zero-terminated string containing the second path.
|
||||||
|
* @param truncate whether to truncate path2 to be no longer than path1.
|
||||||
|
* @return true if paths are equivalent, false otherwise.
|
||||||
|
*/
|
||||||
|
bool storage_common_equivalent_path(
|
||||||
|
Storage* storage,
|
||||||
|
const char* path1,
|
||||||
|
const char* path2,
|
||||||
|
bool truncate);
|
||||||
|
|
||||||
/******************* Error Functions *******************/
|
/******************* Error Functions *******************/
|
||||||
|
|
||||||
/** Retrieves the error text from the error id
|
/**
|
||||||
* @param error_id error id
|
* @brief Get the textual description of a numeric error identifer.
|
||||||
* @return const char* error text
|
*
|
||||||
|
* @param error_id numeric identifier of the error in question.
|
||||||
|
* @return pointer to a statically allocated zero-terminated string containing the respective error text.
|
||||||
*/
|
*/
|
||||||
const char* storage_error_get_desc(FS_Error error_id);
|
const char* storage_error_get_desc(FS_Error error_id);
|
||||||
|
|
||||||
/** Retrieves the error id from the file object
|
/**
|
||||||
* @param file pointer to file object. Pointer must not point to NULL. YOU CANNOT RETRIEVE THE ERROR ID IF THE FILE HAS BEEN CLOSED
|
* @brief Get the numeric error identifier from a file instance.
|
||||||
* @return FS_Error error id
|
*
|
||||||
|
* @warning It is not possible to get the error identifier after the file has been closed.
|
||||||
|
*
|
||||||
|
* @param file pointer to the file instance in question (must NOT be NULL).
|
||||||
|
* @return numeric identifier of the last error associated with the file instance.
|
||||||
*/
|
*/
|
||||||
FS_Error storage_file_get_error(File* file);
|
FS_Error storage_file_get_error(File* file);
|
||||||
|
|
||||||
/** Retrieves the internal (storage-specific) error id from the file object
|
/**
|
||||||
* @param file pointer to file object. Pointer must not point to NULL. YOU CANNOT RETRIEVE THE INTERNAL ERROR ID IF THE FILE HAS BEEN CLOSED
|
* @brief Get the internal (storage-specific) numeric error identifier from a file instance.
|
||||||
* @return FS_Error error id
|
*
|
||||||
|
* @warning It is not possible to get the internal error identifier after the file has been closed.
|
||||||
|
*
|
||||||
|
* @param file pointer to the file instance in question (must NOT be NULL).
|
||||||
|
* @return numeric identifier of the last internal error associated with the file instance.
|
||||||
*/
|
*/
|
||||||
int32_t storage_file_get_internal_error(File* file);
|
int32_t storage_file_get_internal_error(File* file);
|
||||||
|
|
||||||
/** Retrieves the error text from the file object
|
/**
|
||||||
* @param file pointer to file object. Pointer must not point to NULL. YOU CANNOT RETRIEVE THE ERROR TEXT IF THE FILE HAS BEEN CLOSED
|
* @brief Get the textual description of a the last error associated with a file instance.
|
||||||
* @return const char* error text
|
*
|
||||||
|
* @warning It is not possible to get the error text after the file has been closed.
|
||||||
|
*
|
||||||
|
* @param file pointer to the file instance in question (must NOT be NULL).
|
||||||
|
* @return pointer to a statically allocated zero-terminated string containing the respective error text.
|
||||||
*/
|
*/
|
||||||
const char* storage_file_get_error_desc(File* file);
|
const char* storage_file_get_error_desc(File* file);
|
||||||
|
|
||||||
/******************* SD Card Functions *******************/
|
/******************* SD Card Functions *******************/
|
||||||
|
|
||||||
/** Formats SD Card
|
/**
|
||||||
* @param api pointer to the api
|
* @brief Format the SD Card.
|
||||||
* @return FS_Error operation result
|
*
|
||||||
|
* @param storage pointer to a storage API instance.
|
||||||
|
* @return FSE_OK if the card was successfully formatted, any other error code on failure.
|
||||||
*/
|
*/
|
||||||
FS_Error storage_sd_format(Storage* api);
|
FS_Error storage_sd_format(Storage* storage);
|
||||||
|
|
||||||
/** Will unmount the SD card.
|
/**
|
||||||
* Will return FSE_NOT_READY if the SD card is not mounted.
|
* @brief Unmount the SD card.
|
||||||
* Will return FSE_DENIED if there are open files on the SD card.
|
*
|
||||||
* @param api pointer to the api
|
* These return values have special meaning:
|
||||||
* @return FS_Error operation result
|
* - FSE_NOT_READY if the SD card is not mounted.
|
||||||
|
* - FSE_DENIED if there are open files on the SD card.
|
||||||
|
*
|
||||||
|
* @param storage pointer to a storage API instance.
|
||||||
|
* @return FSE_OK if the card was successfully formatted, any other error code on failure.
|
||||||
*/
|
*/
|
||||||
FS_Error storage_sd_unmount(Storage* api);
|
FS_Error storage_sd_unmount(Storage* storage);
|
||||||
|
|
||||||
/** Will mount the SD card
|
/**
|
||||||
* @param api pointer to the api
|
* @brief Mount the SD card.
|
||||||
* @return FS_Error operation result
|
*
|
||||||
|
* @param storage pointer to a storage API instance.
|
||||||
|
* @return FSE_OK if the card was successfully mounted, any other error code on failure.
|
||||||
*/
|
*/
|
||||||
FS_Error storage_sd_mount(Storage* api);
|
FS_Error storage_sd_mount(Storage* storage);
|
||||||
|
|
||||||
/** Retrieves SD card information
|
/**
|
||||||
* @param api pointer to the api
|
* @brief Get SD card information.
|
||||||
* @param info pointer to the info
|
*
|
||||||
* @return FS_Error operation result
|
* @param storage pointer to a storage API instance.
|
||||||
|
* @param info pointer to the info object to contain the requested information.
|
||||||
|
* @return FSE_OK if the info was successfully received, any other error code on failure.
|
||||||
*/
|
*/
|
||||||
FS_Error storage_sd_info(Storage* api, SDInfo* info);
|
FS_Error storage_sd_info(Storage* storage, SDInfo* info);
|
||||||
|
|
||||||
/** Retrieves SD card status
|
/**
|
||||||
* @param api pointer to the api
|
* @brief Get SD card status.
|
||||||
* @return FS_Error operation result
|
*
|
||||||
|
* @param storage pointer to a storage API instance.
|
||||||
|
* @return storage status in the form of a numeric error identifier.
|
||||||
*/
|
*/
|
||||||
FS_Error storage_sd_status(Storage* api);
|
FS_Error storage_sd_status(Storage* storage);
|
||||||
|
|
||||||
/******************* Internal LFS Functions *******************/
|
/******************* Internal LFS Functions *******************/
|
||||||
|
|
||||||
typedef void (*Storage_name_converter)(FuriString*);
|
typedef void (*Storage_name_converter)(FuriString*);
|
||||||
|
|
||||||
/** Backs up internal storage to a tar archive
|
/**
|
||||||
* @param api pointer to the api
|
* @brief Back up the internal storage contents to a *.tar archive.
|
||||||
* @param dstname destination archive path
|
*
|
||||||
* @return FS_Error operation result
|
* @param storage pointer to a storage API instance.
|
||||||
|
* @param dstname pointer to a zero-terminated string containing the archive file path.
|
||||||
|
* @return FSE_OK if the storage was successfully backed up, any other error code on failure.
|
||||||
*/
|
*/
|
||||||
FS_Error storage_int_backup(Storage* api, const char* dstname);
|
FS_Error storage_int_backup(Storage* storage, const char* dstname);
|
||||||
|
|
||||||
/** Restores internal storage from a tar archive
|
/**
|
||||||
* @param api pointer to the api
|
* @brief Restore the internal storage contents from a *.tar archive.
|
||||||
* @param dstname archive path
|
*
|
||||||
* @param converter pointer to filename conversion function, may be NULL
|
* @param storage pointer to a storage API instance.
|
||||||
* @return FS_Error operation result
|
* @param dstname pointer to a zero-terminated string containing the archive file path.
|
||||||
|
* @param converter pointer to a filename conversion function (may be NULL).
|
||||||
|
* @return FSE_OK if the storage was successfully restored, any other error code on failure.
|
||||||
*/
|
*/
|
||||||
FS_Error storage_int_restore(Storage* api, const char* dstname, Storage_name_converter converter);
|
FS_Error storage_int_restore(Storage* api, const char* dstname, Storage_name_converter converter);
|
||||||
|
|
||||||
/***************** Simplified Functions ******************/
|
/***************** Simplified Functions ******************/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes a file/directory, the directory must be empty and the file/directory must not be open
|
* @brief Remove a file or a directory.
|
||||||
* @param storage pointer to the api
|
*
|
||||||
* @param path
|
* The following conditions must be met:
|
||||||
* @return true on success or if file/dir is not exist
|
* - the directory must be empty.
|
||||||
|
* - the file or the directory must NOT be open.
|
||||||
|
*
|
||||||
|
* @param storage pointer to a storage API instance.
|
||||||
|
* @param path pointer to a zero-terminated string containing the item path.
|
||||||
|
* @return true on success or if the item does not exist, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool storage_simply_remove(Storage* storage, const char* path);
|
bool storage_simply_remove(Storage* storage, const char* path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Recursively removes a file/directory, the directory can be not empty
|
* @brief Recursively remove a file or a directory.
|
||||||
* @param storage pointer to the api
|
*
|
||||||
* @param path
|
* Unlike storage_simply_remove(), the directory does not need to be empty.
|
||||||
* @return true on success or if file/dir is not exist
|
*
|
||||||
|
* @param storage pointer to a storage API instance.
|
||||||
|
* @param path pointer to a zero-terminated string containing the item path.
|
||||||
|
* @return true on success or if the item does not exist, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool storage_simply_remove_recursive(Storage* storage, const char* path);
|
bool storage_simply_remove_recursive(Storage* storage, const char* path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a directory
|
* @brief Create a directory.
|
||||||
* @param storage
|
*
|
||||||
* @param path
|
* @param storage pointer to a storage API instance.
|
||||||
* @return true on success or if directory is already exist
|
* @param path pointer to a zero-terminated string containing the directory path.
|
||||||
|
* @return true on success or if directory does already exist, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool storage_simply_mkdir(Storage* storage, const char* path);
|
bool storage_simply_mkdir(Storage* storage, const char* path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get next free filename.
|
* @brief Get the next free filename in a directory.
|
||||||
|
*
|
||||||
|
* Usage example:
|
||||||
|
* ```c
|
||||||
|
* FuriString* file_name = furi_string_alloc();
|
||||||
|
* Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||||
|
*
|
||||||
|
* storage_get_next_filename(storage,
|
||||||
|
* "/ext/test",
|
||||||
|
* "cookies",
|
||||||
|
* ".yum",
|
||||||
|
* 20);
|
||||||
|
*
|
||||||
|
* furi_record_close(RECORD_STORAGE);
|
||||||
|
*
|
||||||
|
* use_file_name(file_name);
|
||||||
|
*
|
||||||
|
* furi_string_free(file_name);
|
||||||
|
* ```
|
||||||
|
* Possible file_name values after calling storage_get_next_filename():
|
||||||
|
* "cookies", "cookies1", "cookies2", ... etc depending on whether any of
|
||||||
|
* these files have already existed in the directory.
|
||||||
|
*
|
||||||
|
* @note If the resulting next file name length is greater than set by the max_len
|
||||||
|
* parameter, the original filename will be returned instead.
|
||||||
*
|
*
|
||||||
* @param storage
|
* @param storage pointer to a storage API instance.
|
||||||
* @param dirname
|
* @param dirname pointer to a zero-terminated string containing the directory path.
|
||||||
* @param filename
|
* @param filename pointer to a zero-terminated string containing the file name.
|
||||||
* @param fileextension
|
* @param fileextension pointer to a zero-terminated string containing the file extension.
|
||||||
* @param nextfilename return name
|
* @param nextfilename pointer to a dynamic string containing the resulting file name.
|
||||||
* @param max_len max len name
|
* @param max_len maximum length of the new name.
|
||||||
*/
|
*/
|
||||||
void storage_get_next_filename(
|
void storage_get_next_filename(
|
||||||
Storage* storage,
|
Storage* storage,
|
||||||
|
@ -198,15 +198,15 @@ static void storage_cli_read(Cli* cli, FuriString* path) {
|
|||||||
File* file = storage_file_alloc(api);
|
File* file = storage_file_alloc(api);
|
||||||
|
|
||||||
if(storage_file_open(file, furi_string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) {
|
if(storage_file_open(file, furi_string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) {
|
||||||
const uint16_t buffer_size = 128;
|
const size_t buffer_size = 128;
|
||||||
uint16_t read_size = 0;
|
size_t read_size = 0;
|
||||||
uint8_t* data = malloc(buffer_size);
|
uint8_t* data = malloc(buffer_size);
|
||||||
|
|
||||||
printf("Size: %lu\r\n", (uint32_t)storage_file_size(file));
|
printf("Size: %lu\r\n", (uint32_t)storage_file_size(file));
|
||||||
|
|
||||||
do {
|
do {
|
||||||
read_size = storage_file_read(file, data, buffer_size);
|
read_size = storage_file_read(file, data, buffer_size);
|
||||||
for(uint16_t i = 0; i < read_size; i++) {
|
for(size_t i = 0; i < read_size; i++) {
|
||||||
printf("%c", data[i]);
|
printf("%c", data[i]);
|
||||||
}
|
}
|
||||||
} while(read_size > 0);
|
} while(read_size > 0);
|
||||||
@ -227,7 +227,7 @@ static void storage_cli_write(Cli* cli, FuriString* path) {
|
|||||||
Storage* api = furi_record_open(RECORD_STORAGE);
|
Storage* api = furi_record_open(RECORD_STORAGE);
|
||||||
File* file = storage_file_alloc(api);
|
File* file = storage_file_alloc(api);
|
||||||
|
|
||||||
const uint16_t buffer_size = 512;
|
const size_t buffer_size = 512;
|
||||||
uint8_t* buffer = malloc(buffer_size);
|
uint8_t* buffer = malloc(buffer_size);
|
||||||
|
|
||||||
if(storage_file_open(file, furi_string_get_cstr(path), FSAM_WRITE, FSOM_OPEN_APPEND)) {
|
if(storage_file_open(file, furi_string_get_cstr(path), FSAM_WRITE, FSOM_OPEN_APPEND)) {
|
||||||
@ -239,10 +239,10 @@ static void storage_cli_write(Cli* cli, FuriString* path) {
|
|||||||
uint8_t symbol = cli_getc(cli);
|
uint8_t symbol = cli_getc(cli);
|
||||||
|
|
||||||
if(symbol == CliSymbolAsciiETX) {
|
if(symbol == CliSymbolAsciiETX) {
|
||||||
uint16_t write_size = read_index % buffer_size;
|
size_t write_size = read_index % buffer_size;
|
||||||
|
|
||||||
if(write_size > 0) {
|
if(write_size > 0) {
|
||||||
uint16_t written_size = storage_file_write(file, buffer, write_size);
|
size_t written_size = storage_file_write(file, buffer, write_size);
|
||||||
|
|
||||||
if(written_size != write_size) {
|
if(written_size != write_size) {
|
||||||
storage_cli_print_error(storage_file_get_error(file));
|
storage_cli_print_error(storage_file_get_error(file));
|
||||||
@ -257,7 +257,7 @@ static void storage_cli_write(Cli* cli, FuriString* path) {
|
|||||||
read_index++;
|
read_index++;
|
||||||
|
|
||||||
if(((read_index % buffer_size) == 0)) {
|
if(((read_index % buffer_size) == 0)) {
|
||||||
uint16_t written_size = storage_file_write(file, buffer, buffer_size);
|
size_t written_size = storage_file_write(file, buffer, buffer_size);
|
||||||
|
|
||||||
if(written_size != buffer_size) {
|
if(written_size != buffer_size) {
|
||||||
storage_cli_print_error(storage_file_get_error(file));
|
storage_cli_print_error(storage_file_get_error(file));
|
||||||
@ -289,7 +289,7 @@ static void storage_cli_read_chunks(Cli* cli, FuriString* path, FuriString* args
|
|||||||
} else if(storage_file_open(file, furi_string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) {
|
} else if(storage_file_open(file, furi_string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) {
|
||||||
uint64_t file_size = storage_file_size(file);
|
uint64_t file_size = storage_file_size(file);
|
||||||
|
|
||||||
printf("Size: %lu\r\n", (uint32_t)file_size);
|
printf("Size: %llu\r\n", file_size);
|
||||||
|
|
||||||
if(buffer_size) {
|
if(buffer_size) {
|
||||||
uint8_t* data = malloc(buffer_size);
|
uint8_t* data = malloc(buffer_size);
|
||||||
@ -297,8 +297,8 @@ static void storage_cli_read_chunks(Cli* cli, FuriString* path, FuriString* args
|
|||||||
printf("\r\nReady?\r\n");
|
printf("\r\nReady?\r\n");
|
||||||
cli_getc(cli);
|
cli_getc(cli);
|
||||||
|
|
||||||
uint16_t read_size = storage_file_read(file, data, buffer_size);
|
size_t read_size = storage_file_read(file, data, buffer_size);
|
||||||
for(uint16_t i = 0; i < read_size; i++) {
|
for(size_t i = 0; i < read_size; i++) {
|
||||||
putchar(data[i]);
|
putchar(data[i]);
|
||||||
}
|
}
|
||||||
file_size -= read_size;
|
file_size -= read_size;
|
||||||
@ -335,7 +335,7 @@ static void storage_cli_write_chunk(Cli* cli, FuriString* path, FuriString* args
|
|||||||
|
|
||||||
size_t read_bytes = cli_read(cli, buffer, buffer_size);
|
size_t read_bytes = cli_read(cli, buffer, buffer_size);
|
||||||
|
|
||||||
uint16_t written_size = storage_file_write(file, buffer, read_bytes);
|
size_t written_size = storage_file_write(file, buffer, read_bytes);
|
||||||
|
|
||||||
if(written_size != buffer_size) {
|
if(written_size != buffer_size) {
|
||||||
storage_cli_print_error(storage_file_get_error(file));
|
storage_cli_print_error(storage_file_get_error(file));
|
||||||
|
@ -139,7 +139,7 @@ bool storage_file_close(File* file) {
|
|||||||
return S_RETURN_BOOL;
|
return S_RETURN_BOOL;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t storage_file_read(File* file, void* buff, uint16_t bytes_to_read) {
|
static uint16_t storage_file_read_underlying(File* file, void* buff, uint16_t bytes_to_read) {
|
||||||
if(bytes_to_read == 0) {
|
if(bytes_to_read == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -159,7 +159,8 @@ uint16_t storage_file_read(File* file, void* buff, uint16_t bytes_to_read) {
|
|||||||
return S_RETURN_UINT16;
|
return S_RETURN_UINT16;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t storage_file_write(File* file, const void* buff, uint16_t bytes_to_write) {
|
static uint16_t
|
||||||
|
storage_file_write_underlying(File* file, const void* buff, uint16_t bytes_to_write) {
|
||||||
if(bytes_to_write == 0) {
|
if(bytes_to_write == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -179,6 +180,40 @@ uint16_t storage_file_write(File* file, const void* buff, uint16_t bytes_to_writ
|
|||||||
return S_RETURN_UINT16;
|
return S_RETURN_UINT16;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t storage_file_read(File* file, void* buff, size_t to_read) {
|
||||||
|
size_t total = 0;
|
||||||
|
|
||||||
|
const size_t max_chunk = UINT16_MAX;
|
||||||
|
do {
|
||||||
|
const size_t chunk = MIN((to_read - total), max_chunk);
|
||||||
|
size_t read = storage_file_read_underlying(file, buff + total, chunk);
|
||||||
|
total += read;
|
||||||
|
|
||||||
|
if(storage_file_get_error(file) != FSE_OK || read != chunk) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while(total != to_read);
|
||||||
|
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t storage_file_write(File* file, const void* buff, size_t to_write) {
|
||||||
|
size_t total = 0;
|
||||||
|
|
||||||
|
const size_t max_chunk = UINT16_MAX;
|
||||||
|
do {
|
||||||
|
const size_t chunk = MIN((to_write - total), max_chunk);
|
||||||
|
size_t written = storage_file_write_underlying(file, buff + total, chunk);
|
||||||
|
total += written;
|
||||||
|
|
||||||
|
if(storage_file_get_error(file) != FSE_OK || written != chunk) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while(total != to_write);
|
||||||
|
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
bool storage_file_seek(File* file, uint32_t offset, bool from_start) {
|
bool storage_file_seek(File* file, uint32_t offset, bool from_start) {
|
||||||
S_FILE_API_PROLOGUE;
|
S_FILE_API_PROLOGUE;
|
||||||
S_API_PROLOGUE;
|
S_API_PROLOGUE;
|
||||||
@ -252,7 +287,7 @@ bool storage_file_exists(Storage* storage, const char* path) {
|
|||||||
return exist;
|
return exist;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool storage_file_copy_to_file(File* source, File* destination, uint32_t size) {
|
bool storage_file_copy_to_file(File* source, File* destination, size_t size) {
|
||||||
uint8_t* buffer = malloc(FILE_BUFFER_SIZE);
|
uint8_t* buffer = malloc(FILE_BUFFER_SIZE);
|
||||||
|
|
||||||
while(size) {
|
while(size) {
|
||||||
@ -431,17 +466,22 @@ FS_Error storage_common_rename(Storage* storage, const char* old_path, const cha
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(storage_dir_exists(storage, old_path)) {
|
if(storage_dir_exists(storage, old_path)) {
|
||||||
FuriString* dir_path = furi_string_alloc_set_str(old_path);
|
// Cannot overwrite a file with a directory
|
||||||
if(!furi_string_end_with_str(dir_path, "/")) {
|
if(storage_file_exists(storage, new_path)) {
|
||||||
furi_string_cat_str(dir_path, "/");
|
|
||||||
}
|
|
||||||
const char* dir_path_s = furi_string_get_cstr(dir_path);
|
|
||||||
if(strncmp(new_path, dir_path_s, strlen(dir_path_s)) == 0) {
|
|
||||||
error = FSE_INVALID_NAME;
|
error = FSE_INVALID_NAME;
|
||||||
furi_string_free(dir_path);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
furi_string_free(dir_path);
|
|
||||||
|
// Cannot rename a directory to itself or to a nested directory
|
||||||
|
if(storage_common_equivalent_path(storage, old_path, new_path, true)) {
|
||||||
|
error = FSE_INVALID_NAME;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Renaming a regular file to itself does nothing and always succeeds
|
||||||
|
} else if(storage_common_equivalent_path(storage, old_path, new_path, false)) {
|
||||||
|
error = FSE_OK;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(storage_file_exists(storage, new_path)) {
|
if(storage_file_exists(storage, new_path)) {
|
||||||
@ -742,6 +782,27 @@ bool storage_common_exists(Storage* storage, const char* path) {
|
|||||||
return storage_common_stat(storage, path, &file_info) == FSE_OK;
|
return storage_common_stat(storage, path, &file_info) == FSE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool storage_common_equivalent_path(
|
||||||
|
Storage* storage,
|
||||||
|
const char* path1,
|
||||||
|
const char* path2,
|
||||||
|
bool truncate) {
|
||||||
|
S_API_PROLOGUE;
|
||||||
|
|
||||||
|
SAData data = {
|
||||||
|
.cequivpath = {
|
||||||
|
.path1 = path1,
|
||||||
|
.path2 = path2,
|
||||||
|
.truncate = truncate,
|
||||||
|
.thread_id = furi_thread_get_current_id(),
|
||||||
|
}};
|
||||||
|
|
||||||
|
S_API_MESSAGE(StorageCommandCommonEquivalentPath);
|
||||||
|
S_API_EPILOGUE;
|
||||||
|
|
||||||
|
return S_RETURN_BOOL;
|
||||||
|
}
|
||||||
|
|
||||||
/****************** ERROR ******************/
|
/****************** ERROR ******************/
|
||||||
|
|
||||||
const char* storage_error_get_desc(FS_Error error_id) {
|
const char* storage_error_get_desc(FS_Error error_id) {
|
||||||
|
@ -69,6 +69,13 @@ typedef struct {
|
|||||||
FuriThreadId thread_id;
|
FuriThreadId thread_id;
|
||||||
} SADataCResolvePath;
|
} SADataCResolvePath;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char* path1;
|
||||||
|
const char* path2;
|
||||||
|
bool truncate;
|
||||||
|
FuriThreadId thread_id;
|
||||||
|
} SADataCEquivPath;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
} SADataError;
|
} SADataError;
|
||||||
@ -99,6 +106,7 @@ typedef union {
|
|||||||
SADataCStat cstat;
|
SADataCStat cstat;
|
||||||
SADataCFSInfo cfsinfo;
|
SADataCFSInfo cfsinfo;
|
||||||
SADataCResolvePath cresolvepath;
|
SADataCResolvePath cresolvepath;
|
||||||
|
SADataCEquivPath cequivpath;
|
||||||
|
|
||||||
SADataError error;
|
SADataError error;
|
||||||
|
|
||||||
@ -142,6 +150,7 @@ typedef enum {
|
|||||||
StorageCommandSDStatus,
|
StorageCommandSDStatus,
|
||||||
StorageCommandCommonResolvePath,
|
StorageCommandCommonResolvePath,
|
||||||
StorageCommandSDMount,
|
StorageCommandSDMount,
|
||||||
|
StorageCommandCommonEquivalentPath,
|
||||||
} StorageCommand;
|
} StorageCommand;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -98,6 +98,12 @@ static FS_Error storage_get_data(Storage* app, FuriString* path, StorageData** s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void storage_path_trim_trailing_slashes(FuriString* path) {
|
||||||
|
while(furi_string_end_with(path, "/")) {
|
||||||
|
furi_string_left(path, furi_string_size(path) - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/******************* File Functions *******************/
|
/******************* File Functions *******************/
|
||||||
|
|
||||||
bool storage_process_file_open(
|
bool storage_process_file_open(
|
||||||
@ -357,6 +363,8 @@ static FS_Error storage_process_common_remove(Storage* app, FuriString* path) {
|
|||||||
FS_Error ret = storage_get_data(app, path, &storage);
|
FS_Error ret = storage_get_data(app, path, &storage);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
if(ret != FSE_OK) break;
|
||||||
|
|
||||||
if(storage_path_already_open(path, storage)) {
|
if(storage_path_already_open(path, storage)) {
|
||||||
ret = FSE_ALREADY_OPEN;
|
ret = FSE_ALREADY_OPEN;
|
||||||
break;
|
break;
|
||||||
@ -398,6 +406,31 @@ static FS_Error storage_process_common_fs_info(
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
storage_process_common_equivalent_path(Storage* app, FuriString* path1, FuriString* path2) {
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
|
do {
|
||||||
|
const StorageType storage_type1 = storage_get_type_by_path(path1);
|
||||||
|
const StorageType storage_type2 = storage_get_type_by_path(path2);
|
||||||
|
|
||||||
|
// Paths on different storages are of course not equal
|
||||||
|
if(storage_type1 != storage_type2) break;
|
||||||
|
|
||||||
|
StorageData* storage;
|
||||||
|
const FS_Error status = storage_get_data(app, path1, &storage);
|
||||||
|
|
||||||
|
if(status != FSE_OK) break;
|
||||||
|
|
||||||
|
FS_CALL(
|
||||||
|
storage,
|
||||||
|
common.equivalent_path(furi_string_get_cstr(path1), furi_string_get_cstr(path2)));
|
||||||
|
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/****************** Raw SD API ******************/
|
/****************** Raw SD API ******************/
|
||||||
// TODO FL-3521: think about implementing a custom storage API to split that kind of api linkage
|
// TODO FL-3521: think about implementing a custom storage API to split that kind of api linkage
|
||||||
#include "storages/storage_ext.h"
|
#include "storages/storage_ext.h"
|
||||||
@ -649,6 +682,23 @@ void storage_process_message_internal(Storage* app, StorageMessage* message) {
|
|||||||
app, message->data->cresolvepath.path, message->data->cresolvepath.thread_id, true);
|
app, message->data->cresolvepath.path, message->data->cresolvepath.thread_id, true);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case StorageCommandCommonEquivalentPath: {
|
||||||
|
FuriString* path1 = furi_string_alloc_set(message->data->cequivpath.path1);
|
||||||
|
FuriString* path2 = furi_string_alloc_set(message->data->cequivpath.path2);
|
||||||
|
storage_path_trim_trailing_slashes(path1);
|
||||||
|
storage_path_trim_trailing_slashes(path2);
|
||||||
|
storage_process_alias(app, path1, message->data->cequivpath.thread_id, false);
|
||||||
|
storage_process_alias(app, path2, message->data->cequivpath.thread_id, false);
|
||||||
|
if(message->data->cequivpath.truncate) {
|
||||||
|
furi_string_left(path2, furi_string_size(path1));
|
||||||
|
}
|
||||||
|
message->return_data->bool_value =
|
||||||
|
storage_process_common_equivalent_path(app, path1, path2);
|
||||||
|
furi_string_free(path1);
|
||||||
|
furi_string_free(path2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// SD operations
|
// SD operations
|
||||||
case StorageCommandSDFormat:
|
case StorageCommandSDFormat:
|
||||||
message->return_data->error_value = storage_process_sd_format(app);
|
message->return_data->error_value = storage_process_sd_format(app);
|
||||||
|
@ -596,6 +596,16 @@ static FS_Error storage_ext_common_fs_info(
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool storage_ext_common_equivalent_path(const char* path1, const char* path2) {
|
||||||
|
#ifdef FURI_RAM_EXEC
|
||||||
|
UNUSED(path1);
|
||||||
|
UNUSED(path2);
|
||||||
|
return false;
|
||||||
|
#else
|
||||||
|
return strcasecmp(path1, path2) == 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/******************* Init Storage *******************/
|
/******************* Init Storage *******************/
|
||||||
static const FS_Api fs_api = {
|
static const FS_Api fs_api = {
|
||||||
.file =
|
.file =
|
||||||
@ -624,6 +634,7 @@ static const FS_Api fs_api = {
|
|||||||
.mkdir = storage_ext_common_mkdir,
|
.mkdir = storage_ext_common_mkdir,
|
||||||
.remove = storage_ext_common_remove,
|
.remove = storage_ext_common_remove,
|
||||||
.fs_info = storage_ext_common_fs_info,
|
.fs_info = storage_ext_common_fs_info,
|
||||||
|
.equivalent_path = storage_ext_common_equivalent_path,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -686,6 +686,10 @@ static FS_Error storage_int_common_fs_info(
|
|||||||
return storage_int_parse_error(result);
|
return storage_int_parse_error(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool storage_int_common_equivalent_path(const char* path1, const char* path2) {
|
||||||
|
return strcmp(path1, path2) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
/******************* Init Storage *******************/
|
/******************* Init Storage *******************/
|
||||||
static const FS_Api fs_api = {
|
static const FS_Api fs_api = {
|
||||||
.file =
|
.file =
|
||||||
@ -714,6 +718,7 @@ static const FS_Api fs_api = {
|
|||||||
.mkdir = storage_int_common_mkdir,
|
.mkdir = storage_int_common_mkdir,
|
||||||
.remove = storage_int_common_remove,
|
.remove = storage_int_common_remove,
|
||||||
.fs_info = storage_int_common_fs_info,
|
.fs_info = storage_int_common_fs_info,
|
||||||
|
.equivalent_path = storage_int_common_equivalent_path,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ static bool storage_settings_scene_bench_write(
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
storage_settings_scene_bench_read(Storage* api, uint16_t size, uint8_t* data, uint32_t* speed) {
|
storage_settings_scene_bench_read(Storage* api, size_t size, uint8_t* data, uint32_t* speed) {
|
||||||
File* file = storage_file_alloc(api);
|
File* file = storage_file_alloc(api);
|
||||||
bool result = true;
|
bool result = true;
|
||||||
*speed = -1;
|
*speed = -1;
|
||||||
@ -82,7 +82,7 @@ static void storage_settings_scene_benchmark(StorageSettings* app) {
|
|||||||
bench_data[i] = (uint8_t)i;
|
bench_data[i] = (uint8_t)i;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t bench_size[BENCH_COUNT] = {1, 8, 32, 256, 512, 1024};
|
size_t bench_size[BENCH_COUNT] = {1, 8, 32, 256, 512, 1024};
|
||||||
uint32_t bench_w_speed[BENCH_COUNT] = {0, 0, 0, 0, 0, 0};
|
uint32_t bench_w_speed[BENCH_COUNT] = {0, 0, 0, 0, 0, 0};
|
||||||
uint32_t bench_r_speed[BENCH_COUNT] = {0, 0, 0, 0, 0, 0};
|
uint32_t bench_r_speed[BENCH_COUNT] = {0, 0, 0, 0, 0, 0};
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ static bool update_task_write_stack_data(UpdateTask* update_task) {
|
|||||||
|
|
||||||
update_task_set_progress(update_task, UpdateTaskStageRadioWrite, 0);
|
update_task_set_progress(update_task, UpdateTaskStageRadioWrite, 0);
|
||||||
uint8_t* fw_block = malloc(FLASH_PAGE_SIZE);
|
uint8_t* fw_block = malloc(FLASH_PAGE_SIZE);
|
||||||
uint16_t bytes_read = 0;
|
size_t bytes_read = 0;
|
||||||
uint32_t element_offs = 0;
|
uint32_t element_offs = 0;
|
||||||
|
|
||||||
while(element_offs < stack_size) {
|
while(element_offs < stack_size) {
|
||||||
|
@ -32,7 +32,7 @@ Only two parameters are mandatory: **_appid_** and **_apptype_**. Others are opt
|
|||||||
- **name**: name displayed in menus.
|
- **name**: name displayed in menus.
|
||||||
- **entry_point**: C function to be used as the application's entry point. Note that C++ function names are mangled, so you need to wrap them in `extern "C"` to use them as entry points.
|
- **entry_point**: C function to be used as the application's entry point. Note that C++ function names are mangled, so you need to wrap them in `extern "C"` to use them as entry points.
|
||||||
- **flags**: internal flags for system apps. Do not use.
|
- **flags**: internal flags for system apps. Do not use.
|
||||||
- **cdefines**: C preprocessor definitions to declare globally for other apps when the current application is included in the active build configuration.
|
- **cdefines**: C preprocessor definitions to declare globally for other apps when the current application is included in the active build configuration. **For external applications**: specified definitions are used when building the application itself.
|
||||||
- **requires**: list of application IDs to include in the build configuration when the current application is referenced in the list of applications to build.
|
- **requires**: list of application IDs to include in the build configuration when the current application is referenced in the list of applications to build.
|
||||||
- **conflicts**: list of application IDs with which the current application conflicts. If any of them is found in the constructed application list, **`fbt`** will abort the firmware build process.
|
- **conflicts**: list of application IDs with which the current application conflicts. If any of them is found in the constructed application list, **`fbt`** will abort the firmware build process.
|
||||||
- **provides**: functionally identical to **_requires_** field.
|
- **provides**: functionally identical to **_requires_** field.
|
||||||
|
@ -219,7 +219,7 @@ AddPostAction(fwelf, fwenv["APPBUILD_DUMP"])
|
|||||||
AddPostAction(
|
AddPostAction(
|
||||||
fwelf,
|
fwelf,
|
||||||
Action(
|
Action(
|
||||||
'${PYTHON3} "${BIN_SIZE_SCRIPT}" elf ${TARGET}',
|
[["${PYTHON3}", "${BIN_SIZE_SCRIPT}", "elf", "${TARGET}"]],
|
||||||
"Firmware size",
|
"Firmware size",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@ -229,7 +229,7 @@ fwhex = fwenv["FW_HEX"] = fwenv.HEXBuilder("${FIRMWARE_BUILD_CFG}")
|
|||||||
fwbin = fwenv["FW_BIN"] = fwenv.BINBuilder("${FIRMWARE_BUILD_CFG}")
|
fwbin = fwenv["FW_BIN"] = fwenv.BINBuilder("${FIRMWARE_BUILD_CFG}")
|
||||||
AddPostAction(
|
AddPostAction(
|
||||||
fwbin,
|
fwbin,
|
||||||
Action('@${PYTHON3} "${BIN_SIZE_SCRIPT}" bin ${TARGET}'),
|
Action([["@${PYTHON3}", "${BIN_SIZE_SCRIPT}", "bin", "${TARGET}"]]),
|
||||||
)
|
)
|
||||||
|
|
||||||
fwdfu = fwenv["FW_DFU"] = fwenv.DFUBuilder("${FIRMWARE_BUILD_CFG}")
|
fwdfu = fwenv["FW_DFU"] = fwenv.DFUBuilder("${FIRMWARE_BUILD_CFG}")
|
||||||
|
@ -122,17 +122,10 @@ FuriStatus furi_timer_stop(FuriTimer* instance) {
|
|||||||
furi_assert(instance);
|
furi_assert(instance);
|
||||||
|
|
||||||
TimerHandle_t hTimer = (TimerHandle_t)instance;
|
TimerHandle_t hTimer = (TimerHandle_t)instance;
|
||||||
FuriStatus stat;
|
|
||||||
|
|
||||||
if(xTimerIsTimerActive(hTimer) == pdFALSE) {
|
furi_check(xTimerStop(hTimer, portMAX_DELAY) == pdPASS);
|
||||||
stat = FuriStatusErrorResource;
|
|
||||||
} else {
|
|
||||||
furi_check(xTimerStop(hTimer, portMAX_DELAY) == pdPASS);
|
|
||||||
stat = FuriStatusOk;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return execution status */
|
return FuriStatusOk;
|
||||||
return (stat);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t furi_timer_is_running(FuriTimer* instance) {
|
uint32_t furi_timer_is_running(FuriTimer* instance) {
|
||||||
|
@ -32,6 +32,9 @@ FuriTimer* furi_timer_alloc(FuriTimerCallback func, FuriTimerType type, void* co
|
|||||||
void furi_timer_free(FuriTimer* instance);
|
void furi_timer_free(FuriTimer* instance);
|
||||||
|
|
||||||
/** Start timer
|
/** Start timer
|
||||||
|
*
|
||||||
|
* @warning This is asynchronous call, real operation will happen as soon as
|
||||||
|
* timer service process this request.
|
||||||
*
|
*
|
||||||
* @param instance The pointer to FuriTimer instance
|
* @param instance The pointer to FuriTimer instance
|
||||||
* @param[in] ticks The interval in ticks
|
* @param[in] ticks The interval in ticks
|
||||||
@ -41,6 +44,9 @@ void furi_timer_free(FuriTimer* instance);
|
|||||||
FuriStatus furi_timer_start(FuriTimer* instance, uint32_t ticks);
|
FuriStatus furi_timer_start(FuriTimer* instance, uint32_t ticks);
|
||||||
|
|
||||||
/** Restart timer with previous timeout value
|
/** Restart timer with previous timeout value
|
||||||
|
*
|
||||||
|
* @warning This is asynchronous call, real operation will happen as soon as
|
||||||
|
* timer service process this request.
|
||||||
*
|
*
|
||||||
* @param instance The pointer to FuriTimer instance
|
* @param instance The pointer to FuriTimer instance
|
||||||
* @param[in] ticks The interval in ticks
|
* @param[in] ticks The interval in ticks
|
||||||
@ -50,6 +56,9 @@ FuriStatus furi_timer_start(FuriTimer* instance, uint32_t ticks);
|
|||||||
FuriStatus furi_timer_restart(FuriTimer* instance, uint32_t ticks);
|
FuriStatus furi_timer_restart(FuriTimer* instance, uint32_t ticks);
|
||||||
|
|
||||||
/** Stop timer
|
/** Stop timer
|
||||||
|
*
|
||||||
|
* @warning This is asynchronous call, real operation will happen as soon as
|
||||||
|
* timer service process this request.
|
||||||
*
|
*
|
||||||
* @param instance The pointer to FuriTimer instance
|
* @param instance The pointer to FuriTimer instance
|
||||||
*
|
*
|
||||||
@ -58,6 +67,10 @@ FuriStatus furi_timer_restart(FuriTimer* instance, uint32_t ticks);
|
|||||||
FuriStatus furi_timer_stop(FuriTimer* instance);
|
FuriStatus furi_timer_stop(FuriTimer* instance);
|
||||||
|
|
||||||
/** Is timer running
|
/** Is timer running
|
||||||
|
*
|
||||||
|
* @warning This cal may and will return obsolete timer state if timer
|
||||||
|
* commands are still in the queue. Please read FreeRTOS timer
|
||||||
|
* documentation first.
|
||||||
*
|
*
|
||||||
* @param instance The pointer to FuriTimer instance
|
* @param instance The pointer to FuriTimer instance
|
||||||
*
|
*
|
||||||
|
@ -6,6 +6,8 @@ env.Append(
|
|||||||
],
|
],
|
||||||
SDK_HEADERS=[
|
SDK_HEADERS=[
|
||||||
File("cc1101_regs.h"),
|
File("cc1101_regs.h"),
|
||||||
|
File("st25r3916_reg.h"),
|
||||||
|
File("st25r3916.h"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -101,7 +101,7 @@ static bool elf_read_string_from_offset(ELFFile* elf, off_t offset, FuriString*
|
|||||||
buffer[ELF_NAME_BUFFER_LEN] = 0;
|
buffer[ELF_NAME_BUFFER_LEN] = 0;
|
||||||
|
|
||||||
while(true) {
|
while(true) {
|
||||||
uint16_t read = storage_file_read(elf->fd, buffer, ELF_NAME_BUFFER_LEN);
|
size_t read = storage_file_read(elf->fd, buffer, ELF_NAME_BUFFER_LEN);
|
||||||
furi_string_cat(name, buffer);
|
furi_string_cat(name, buffer);
|
||||||
if(strlen(buffer) < ELF_NAME_BUFFER_LEN) {
|
if(strlen(buffer) < ELF_NAME_BUFFER_LEN) {
|
||||||
result = true;
|
result = true;
|
||||||
|
@ -396,7 +396,7 @@ bool music_worker_load_rtttl_from_file(MusicWorker* instance, const char* file_p
|
|||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
|
|
||||||
uint16_t ret = 0;
|
size_t ret = 0;
|
||||||
do {
|
do {
|
||||||
uint8_t buffer[65] = {0};
|
uint8_t buffer[65] = {0};
|
||||||
ret = storage_file_read(file, buffer, sizeof(buffer) - 1);
|
ret = storage_file_read(file, buffer, sizeof(buffer) - 1);
|
||||||
|
@ -36,9 +36,9 @@ env.Append(
|
|||||||
File("protocols/mf_ultralight/mf_ultralight_listener.h"),
|
File("protocols/mf_ultralight/mf_ultralight_listener.h"),
|
||||||
File("protocols/mf_classic/mf_classic_listener.h"),
|
File("protocols/mf_classic/mf_classic_listener.h"),
|
||||||
# Sync API
|
# Sync API
|
||||||
File("protocols/iso14443_3a/iso14443_3a_poller_sync_api.h"),
|
File("protocols/iso14443_3a/iso14443_3a_poller_sync.h"),
|
||||||
File("protocols/mf_ultralight/mf_ultralight_poller_sync_api.h"),
|
File("protocols/mf_ultralight/mf_ultralight_poller_sync.h"),
|
||||||
File("protocols/mf_classic/mf_classic_poller_sync_api.h"),
|
File("protocols/mf_classic/mf_classic_poller_sync.h"),
|
||||||
# Misc
|
# Misc
|
||||||
File("helpers/nfc_util.h"),
|
File("helpers/nfc_util.h"),
|
||||||
File("helpers/iso14443_crc.h"),
|
File("helpers/iso14443_crc.h"),
|
||||||
|
@ -28,6 +28,9 @@ struct NfcPoller {
|
|||||||
NfcPollerList list;
|
NfcPollerList list;
|
||||||
NfcPollerSessionState session_state;
|
NfcPollerSessionState session_state;
|
||||||
bool protocol_detected;
|
bool protocol_detected;
|
||||||
|
|
||||||
|
NfcGenericCallbackEx callback;
|
||||||
|
void* context;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void nfc_poller_list_alloc(NfcPoller* instance) {
|
static void nfc_poller_list_alloc(NfcPoller* instance) {
|
||||||
@ -127,6 +130,75 @@ void nfc_poller_start(NfcPoller* instance, NfcGenericCallback callback, void* co
|
|||||||
nfc_start(instance->nfc, nfc_poller_start_callback, instance);
|
nfc_start(instance->nfc, nfc_poller_start_callback, instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static NfcCommand nfc_poller_start_ex_tail_callback(NfcGenericEvent event, void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
furi_assert(event.protocol != NfcProtocolInvalid);
|
||||||
|
|
||||||
|
NfcPoller* instance = context;
|
||||||
|
NfcCommand command = NfcCommandContinue;
|
||||||
|
|
||||||
|
NfcGenericEventEx poller_event = {
|
||||||
|
.poller = instance->list.tail->poller,
|
||||||
|
.parent_event_data = event.event_data,
|
||||||
|
};
|
||||||
|
|
||||||
|
command = instance->callback(poller_event, instance->context);
|
||||||
|
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NfcCommand nfc_poller_start_ex_head_callback(NfcEvent event, void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
|
||||||
|
NfcCommand command = NfcCommandContinue;
|
||||||
|
NfcPoller* instance = context;
|
||||||
|
|
||||||
|
NfcProtocol parent_protocol = nfc_protocol_get_parent(instance->protocol);
|
||||||
|
|
||||||
|
if(parent_protocol == NfcProtocolInvalid) {
|
||||||
|
NfcGenericEventEx poller_event = {
|
||||||
|
.poller = instance->list.tail->poller,
|
||||||
|
.parent_event_data = &event,
|
||||||
|
};
|
||||||
|
|
||||||
|
command = instance->callback(poller_event, instance->context);
|
||||||
|
} else {
|
||||||
|
NfcGenericEvent poller_event = {
|
||||||
|
.protocol = NfcProtocolInvalid,
|
||||||
|
.instance = instance->nfc,
|
||||||
|
.event_data = &event,
|
||||||
|
};
|
||||||
|
NfcPollerListElement* head_poller = instance->list.head;
|
||||||
|
command = head_poller->poller_api->run(poller_event, head_poller->poller);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(instance->session_state == NfcPollerSessionStateStopRequest) {
|
||||||
|
command = NfcCommandStop;
|
||||||
|
}
|
||||||
|
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfc_poller_start_ex(NfcPoller* instance, NfcGenericCallbackEx callback, void* context) {
|
||||||
|
furi_assert(instance);
|
||||||
|
furi_assert(callback);
|
||||||
|
furi_assert(instance->session_state == NfcPollerSessionStateIdle);
|
||||||
|
|
||||||
|
instance->callback = callback;
|
||||||
|
instance->context = context;
|
||||||
|
|
||||||
|
NfcProtocol parent_protocol = nfc_protocol_get_parent(instance->protocol);
|
||||||
|
if(parent_protocol != NfcProtocolInvalid) {
|
||||||
|
NfcPollerListElement* iter = instance->list.head;
|
||||||
|
while(iter->protocol != parent_protocol) iter = iter->child;
|
||||||
|
|
||||||
|
iter->poller_api->set_callback(iter->poller, nfc_poller_start_ex_tail_callback, instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
instance->session_state = NfcPollerSessionStateActive;
|
||||||
|
nfc_start(instance->nfc, nfc_poller_start_ex_head_callback, instance);
|
||||||
|
}
|
||||||
|
|
||||||
void nfc_poller_stop(NfcPoller* instance) {
|
void nfc_poller_stop(NfcPoller* instance) {
|
||||||
furi_assert(instance);
|
furi_assert(instance);
|
||||||
furi_assert(instance->nfc);
|
furi_assert(instance->nfc);
|
||||||
|
@ -26,6 +26,31 @@ extern "C" {
|
|||||||
*/
|
*/
|
||||||
typedef struct NfcPoller NfcPoller;
|
typedef struct NfcPoller NfcPoller;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Extended generic Nfc event type.
|
||||||
|
*
|
||||||
|
* An extended generic Nfc event contains protocol poller and it's parent protocol event data.
|
||||||
|
* If protocol has no parent, then events are produced by Nfc instance.
|
||||||
|
*
|
||||||
|
* The parent_event_data field is protocol-specific and should be cast to the appropriate type before use.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
NfcGenericInstance* poller; /**< Pointer to the protocol poller. */
|
||||||
|
NfcGenericEventData*
|
||||||
|
parent_event_data /**< Pointer to the protocol's parent poller event data. */;
|
||||||
|
} NfcGenericEventEx;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Extended generic Nfc event callback type.
|
||||||
|
*
|
||||||
|
* A function of this type must be passed as the callback parameter upon extended start of a poller.
|
||||||
|
*
|
||||||
|
* @param [in] event Nfc extended generic event, passed by value, complete with protocol type and data.
|
||||||
|
* @param [in,out] context pointer to the user-specific context (set when starting a poller/listener instance).
|
||||||
|
* @returns the command which the event producer must execute.
|
||||||
|
*/
|
||||||
|
typedef NfcCommand (*NfcGenericCallbackEx)(NfcGenericEventEx event, void* context);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Allocate an NfcPoller instance.
|
* @brief Allocate an NfcPoller instance.
|
||||||
*
|
*
|
||||||
@ -57,6 +82,18 @@ void nfc_poller_free(NfcPoller* instance);
|
|||||||
*/
|
*/
|
||||||
void nfc_poller_start(NfcPoller* instance, NfcGenericCallback callback, void* context);
|
void nfc_poller_start(NfcPoller* instance, NfcGenericCallback callback, void* context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Start an NfcPoller instance in extended mode.
|
||||||
|
*
|
||||||
|
* When nfc poller is started in extended mode, callback will be called with parent protocol events
|
||||||
|
* and protocol instance. This mode enables to make custom poller state machines.
|
||||||
|
*
|
||||||
|
* @param[in,out] instance pointer to the instance to be started.
|
||||||
|
* @param[in] callback pointer to a user-defined callback function which will receive events.
|
||||||
|
* @param[in] context pointer to a user-specific context (will be passed to the callback).
|
||||||
|
*/
|
||||||
|
void nfc_poller_start_ex(NfcPoller* instance, NfcGenericCallbackEx callback, void* context);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Stop an NfcPoller instance.
|
* @brief Stop an NfcPoller instance.
|
||||||
*
|
*
|
||||||
|
@ -66,7 +66,7 @@ static NfcCommand felica_poller_run(NfcGenericEvent event, void* context) {
|
|||||||
|
|
||||||
if(nfc_event->type == NfcEventTypePollerReady) {
|
if(nfc_event->type == NfcEventTypePollerReady) {
|
||||||
if(instance->state != FelicaPollerStateActivated) {
|
if(instance->state != FelicaPollerStateActivated) {
|
||||||
FelicaError error = felica_poller_async_activate(instance, instance->data);
|
FelicaError error = felica_poller_activate(instance, instance->data);
|
||||||
if(error == FelicaErrorNone) {
|
if(error == FelicaErrorNone) {
|
||||||
instance->felica_event.type = FelicaPollerEventTypeReady;
|
instance->felica_event.type = FelicaPollerEventTypeReady;
|
||||||
instance->felica_event_data.error = error;
|
instance->felica_event_data.error = error;
|
||||||
@ -100,7 +100,7 @@ static bool felica_poller_detect(NfcGenericEvent event, void* context) {
|
|||||||
furi_assert(instance->state == FelicaPollerStateIdle);
|
furi_assert(instance->state == FelicaPollerStateIdle);
|
||||||
|
|
||||||
if(nfc_event->type == NfcEventTypePollerReady) {
|
if(nfc_event->type == NfcEventTypePollerReady) {
|
||||||
FelicaError error = felica_poller_async_activate(instance, instance->data);
|
FelicaError error = felica_poller_activate(instance, instance->data);
|
||||||
protocol_detected = (error == FelicaErrorNone);
|
protocol_detected = (error == FelicaErrorNone);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,22 +9,50 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief FelicaPoller opaque type definition.
|
||||||
|
*/
|
||||||
typedef struct FelicaPoller FelicaPoller;
|
typedef struct FelicaPoller FelicaPoller;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enumeration of possible Felica poller event types.
|
||||||
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
FelicaPollerEventTypeError,
|
FelicaPollerEventTypeError, /**< The card was activated by the poller. */
|
||||||
FelicaPollerEventTypeReady,
|
FelicaPollerEventTypeReady, /**< An error occured during activation procedure. */
|
||||||
} FelicaPollerEventType;
|
} FelicaPollerEventType;
|
||||||
|
|
||||||
typedef struct {
|
/**
|
||||||
FelicaError error;
|
* @brief Felica poller event data.
|
||||||
|
*/
|
||||||
|
typedef union {
|
||||||
|
FelicaError error; /**< Error code indicating card activation fail reason. */
|
||||||
} FelicaPollerEventData;
|
} FelicaPollerEventData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief FelicaPoller poller event structure.
|
||||||
|
*
|
||||||
|
* Upon emission of an event, an instance of this struct will be passed to the callback.
|
||||||
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
FelicaPollerEventType type;
|
FelicaPollerEventType type; /**< Type of emmitted event. */
|
||||||
FelicaPollerEventData* data;
|
FelicaPollerEventData* data; /**< Pointer to event specific data. */
|
||||||
} FelicaPollerEvent;
|
} FelicaPollerEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Perform collision resolution procedure.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* Perfoms the collision resolution procedure as defined in FeliCa standars. The data
|
||||||
|
* field will be filled with Felica data on success.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @param[out] data pointer to the Felica data structure to be filled.
|
||||||
|
* @return FelicaErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
FelicaError felica_poller_activate(FelicaPoller* instance, FelicaData* data);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -49,7 +49,7 @@ static FelicaError felica_poller_frame_exchange(
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
FelicaError felica_poller_async_polling(
|
FelicaError felica_poller_polling(
|
||||||
FelicaPoller* instance,
|
FelicaPoller* instance,
|
||||||
const FelicaPollerPollingCommand* cmd,
|
const FelicaPollerPollingCommand* cmd,
|
||||||
FelicaPollerPollingResponse* resp) {
|
FelicaPollerPollingResponse* resp) {
|
||||||
@ -93,7 +93,7 @@ FelicaError felica_poller_async_polling(
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
FelicaError felica_poller_async_activate(FelicaPoller* instance, FelicaData* data) {
|
FelicaError felica_poller_activate(FelicaPoller* instance, FelicaData* data) {
|
||||||
furi_assert(instance);
|
furi_assert(instance);
|
||||||
|
|
||||||
felica_reset(data);
|
felica_reset(data);
|
||||||
@ -112,7 +112,7 @@ FelicaError felica_poller_async_activate(FelicaPoller* instance, FelicaData* dat
|
|||||||
};
|
};
|
||||||
FelicaPollerPollingResponse polling_resp = {};
|
FelicaPollerPollingResponse polling_resp = {};
|
||||||
|
|
||||||
ret = felica_poller_async_polling(instance, &polling_cmd, &polling_resp);
|
ret = felica_poller_polling(instance, &polling_cmd, &polling_resp);
|
||||||
|
|
||||||
if(ret != FelicaErrorNone) {
|
if(ret != FelicaErrorNone) {
|
||||||
FURI_LOG_T(TAG, "Activation failed error: %d", ret);
|
FURI_LOG_T(TAG, "Activation failed error: %d", ret);
|
||||||
|
@ -48,13 +48,11 @@ typedef struct {
|
|||||||
|
|
||||||
const FelicaData* felica_poller_get_data(FelicaPoller* instance);
|
const FelicaData* felica_poller_get_data(FelicaPoller* instance);
|
||||||
|
|
||||||
FelicaError felica_poller_async_polling(
|
FelicaError felica_poller_polling(
|
||||||
FelicaPoller* instance,
|
FelicaPoller* instance,
|
||||||
const FelicaPollerPollingCommand* cmd,
|
const FelicaPollerPollingCommand* cmd,
|
||||||
FelicaPollerPollingResponse* resp);
|
FelicaPollerPollingResponse* resp);
|
||||||
|
|
||||||
FelicaError felica_poller_async_activate(FelicaPoller* instance, FelicaData* data);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -72,7 +72,7 @@ static NfcCommand iso14443_3a_poller_run(NfcGenericEvent event, void* context) {
|
|||||||
if(nfc_event->type == NfcEventTypePollerReady) {
|
if(nfc_event->type == NfcEventTypePollerReady) {
|
||||||
if(instance->state != Iso14443_3aPollerStateActivated) {
|
if(instance->state != Iso14443_3aPollerStateActivated) {
|
||||||
Iso14443_3aData data = {};
|
Iso14443_3aData data = {};
|
||||||
Iso14443_3aError error = iso14443_3a_poller_async_activate(instance, &data);
|
Iso14443_3aError error = iso14443_3a_poller_activate(instance, &data);
|
||||||
if(error == Iso14443_3aErrorNone) {
|
if(error == Iso14443_3aErrorNone) {
|
||||||
instance->state = Iso14443_3aPollerStateActivated;
|
instance->state = Iso14443_3aPollerStateActivated;
|
||||||
instance->iso14443_3a_event.type = Iso14443_3aPollerEventTypeReady;
|
instance->iso14443_3a_event.type = Iso14443_3aPollerEventTypeReady;
|
||||||
@ -111,7 +111,7 @@ static bool iso14443_3a_poller_detect(NfcGenericEvent event, void* context) {
|
|||||||
furi_assert(instance->state == Iso14443_3aPollerStateIdle);
|
furi_assert(instance->state == Iso14443_3aPollerStateIdle);
|
||||||
|
|
||||||
if(nfc_event->type == NfcEventTypePollerReady) {
|
if(nfc_event->type == NfcEventTypePollerReady) {
|
||||||
Iso14443_3aError error = iso14443_3a_poller_async_activate(instance, NULL);
|
Iso14443_3aError error = iso14443_3a_poller_activate(instance, NULL);
|
||||||
protocol_detected = (error == Iso14443_3aErrorNone);
|
protocol_detected = (error == Iso14443_3aErrorNone);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,34 +9,137 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Iso14443_3aPoller opaque type definition.
|
||||||
|
*/
|
||||||
typedef struct Iso14443_3aPoller Iso14443_3aPoller;
|
typedef struct Iso14443_3aPoller Iso14443_3aPoller;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enumeration of possible Iso14443_3a poller event types.
|
||||||
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
Iso14443_3aPollerEventTypeError,
|
Iso14443_3aPollerEventTypeError, /**< The card was activated by the poller. */
|
||||||
Iso14443_3aPollerEventTypeReady,
|
Iso14443_3aPollerEventTypeReady, /**< An error occured during activation procedure. */
|
||||||
} Iso14443_3aPollerEventType;
|
} Iso14443_3aPollerEventType;
|
||||||
|
|
||||||
typedef struct {
|
/**
|
||||||
Iso14443_3aError error;
|
* @brief Iso14443_3a poller event data.
|
||||||
|
*/
|
||||||
|
typedef union {
|
||||||
|
Iso14443_3aError error; /**< Error code indicating card activation fail reason. */
|
||||||
} Iso14443_3aPollerEventData;
|
} Iso14443_3aPollerEventData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Iso14443_3a poller event structure.
|
||||||
|
*
|
||||||
|
* Upon emission of an event, an instance of this struct will be passed to the callback.
|
||||||
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Iso14443_3aPollerEventType type;
|
Iso14443_3aPollerEventType type; /**< Type of emmitted event. */
|
||||||
Iso14443_3aPollerEventData* data;
|
Iso14443_3aPollerEventData* data; /**< Pointer to event specific data. */
|
||||||
} Iso14443_3aPollerEvent;
|
} Iso14443_3aPollerEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Transmit and receive Iso14443_3a frames in poller mode.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* The rx_buffer will be filled with any data received as a response to data
|
||||||
|
* sent from tx_buffer, with a timeout defined by the fwt parameter.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @param[in] tx_buffer pointer to the buffer containing the data to be transmitted.
|
||||||
|
* @param[out] rx_buffer pointer to the buffer to be filled with received data.
|
||||||
|
* @param[in] fwt frame wait time (response timeout), in carrier cycles.
|
||||||
|
* @return Iso14443_3aErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
Iso14443_3aError iso14443_3a_poller_txrx(
|
Iso14443_3aError iso14443_3a_poller_txrx(
|
||||||
Iso14443_3aPoller* instance,
|
Iso14443_3aPoller* instance,
|
||||||
const BitBuffer* tx_buffer,
|
const BitBuffer* tx_buffer,
|
||||||
BitBuffer* rx_buffer,
|
BitBuffer* rx_buffer,
|
||||||
uint32_t fwt);
|
uint32_t fwt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Transmit and receive Iso14443_3a standard frames in poller mode.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* The rx_buffer will be filled with any data received as a response to data
|
||||||
|
* sent from tx_buffer, with a timeout defined by the fwt parameter.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @param[in] tx_buffer pointer to the buffer containing the data to be transmitted.
|
||||||
|
* @param[out] rx_buffer pointer to the buffer to be filled with received data.
|
||||||
|
* @param[in] fwt frame wait time (response timeout), in carrier cycles.
|
||||||
|
* @return Iso14443_3aErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
Iso14443_3aError iso14443_3a_poller_send_standard_frame(
|
Iso14443_3aError iso14443_3a_poller_send_standard_frame(
|
||||||
Iso14443_3aPoller* instance,
|
Iso14443_3aPoller* instance,
|
||||||
const BitBuffer* tx_buffer,
|
const BitBuffer* tx_buffer,
|
||||||
BitBuffer* rx_buffer,
|
BitBuffer* rx_buffer,
|
||||||
uint32_t fwt);
|
uint32_t fwt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Transmit and receive Iso14443_3a frames with custom parity bits in poller mode.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* The rx_buffer will be filled with any data received as a response to data
|
||||||
|
* sent from tx_buffer, with a timeout defined by the fwt parameter.
|
||||||
|
*
|
||||||
|
* Custom parity bits must be set in the tx_buffer. The rx_buffer will contain
|
||||||
|
* the received data with the parity bits.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @param[in] tx_buffer pointer to the buffer containing the data to be transmitted.
|
||||||
|
* @param[out] rx_buffer pointer to the buffer to be filled with received data.
|
||||||
|
* @param[in] fwt frame wait time (response timeout), in carrier cycles.
|
||||||
|
* @return Iso14443_3aErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
Iso14443_3aError iso14443_3a_poller_txrx_custom_parity(
|
||||||
|
Iso14443_3aPoller* instance,
|
||||||
|
const BitBuffer* tx_buffer,
|
||||||
|
BitBuffer* rx_buffer,
|
||||||
|
uint32_t fwt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks presence of Iso14443_3a complient card.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @return Iso14443_3aErrorNone if card is present, an error code otherwise.
|
||||||
|
*/
|
||||||
|
Iso14443_3aError iso14443_3a_poller_check_presence(Iso14443_3aPoller* instance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Perform collision resolution procedure.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* Perfoms the collision resolution procedure as defined in Iso14443-3a. The iso14443_3a_data
|
||||||
|
* field will be filled with Iso14443-3a data on success.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @param[out] iso14443_3a_data pointer to the Iso14443_3a data structure to be filled.
|
||||||
|
* @return Iso14443_3aErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
Iso14443_3aError
|
||||||
|
iso14443_3a_poller_activate(Iso14443_3aPoller* instance, Iso14443_3aData* iso14443_3a_data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send HALT command to the card.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* Halts card and changes internal Iso14443_3aPoller state to Idle.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @return Iso14443_3aErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
Iso14443_3aError iso14443_3a_poller_halt(Iso14443_3aPoller* instance);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -94,9 +94,8 @@ Iso14443_3aError iso14443_3a_poller_halt(Iso14443_3aPoller* instance) {
|
|||||||
return Iso14443_3aErrorNone;
|
return Iso14443_3aErrorNone;
|
||||||
}
|
}
|
||||||
|
|
||||||
Iso14443_3aError iso14443_3a_poller_async_activate(
|
Iso14443_3aError
|
||||||
Iso14443_3aPoller* instance,
|
iso14443_3a_poller_activate(Iso14443_3aPoller* instance, Iso14443_3aData* iso14443_3a_data) {
|
||||||
Iso14443_3aData* iso14443_3a_data) {
|
|
||||||
furi_assert(instance);
|
furi_assert(instance);
|
||||||
furi_assert(instance->nfc);
|
furi_assert(instance->nfc);
|
||||||
furi_assert(instance->tx_buffer);
|
furi_assert(instance->tx_buffer);
|
||||||
|
@ -39,15 +39,9 @@ typedef enum {
|
|||||||
Iso14443_3aPollerStateActivated,
|
Iso14443_3aPollerStateActivated,
|
||||||
} Iso14443_3aPollerState;
|
} Iso14443_3aPollerState;
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
Iso14443_3aPollerConfigStateIdle,
|
|
||||||
Iso14443_3aPollerConfigStateDone,
|
|
||||||
} Iso14443_3aPollerConfigState;
|
|
||||||
|
|
||||||
struct Iso14443_3aPoller {
|
struct Iso14443_3aPoller {
|
||||||
Nfc* nfc;
|
Nfc* nfc;
|
||||||
Iso14443_3aPollerState state;
|
Iso14443_3aPollerState state;
|
||||||
Iso14443_3aPollerConfigState config_state;
|
|
||||||
Iso14443_3aPollerColRes col_res;
|
Iso14443_3aPollerColRes col_res;
|
||||||
Iso14443_3aData* data;
|
Iso14443_3aData* data;
|
||||||
BitBuffer* tx_buffer;
|
BitBuffer* tx_buffer;
|
||||||
@ -62,20 +56,6 @@ struct Iso14443_3aPoller {
|
|||||||
|
|
||||||
const Iso14443_3aData* iso14443_3a_poller_get_data(Iso14443_3aPoller* instance);
|
const Iso14443_3aData* iso14443_3a_poller_get_data(Iso14443_3aPoller* instance);
|
||||||
|
|
||||||
Iso14443_3aError iso14443_3a_poller_check_presence(Iso14443_3aPoller* instance);
|
|
||||||
|
|
||||||
Iso14443_3aError iso14443_3a_poller_async_activate(
|
|
||||||
Iso14443_3aPoller* instance,
|
|
||||||
Iso14443_3aData* iso14443_3a_data);
|
|
||||||
|
|
||||||
Iso14443_3aError iso14443_3a_poller_halt(Iso14443_3aPoller* instance);
|
|
||||||
|
|
||||||
Iso14443_3aError iso14443_3a_poller_txrx_custom_parity(
|
|
||||||
Iso14443_3aPoller* instance,
|
|
||||||
const BitBuffer* tx_buffer,
|
|
||||||
BitBuffer* rx_buffer,
|
|
||||||
uint32_t fwt);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#include "iso14443_3a_poller_sync_api.h"
|
#include "iso14443_3a_poller_sync.h"
|
||||||
|
|
||||||
#include "iso14443_3a_poller_i.h"
|
#include "iso14443_3a_poller_i.h"
|
||||||
#include <nfc/nfc_poller.h>
|
#include <nfc/nfc_poller.h>
|
||||||
@ -34,7 +34,7 @@ NfcCommand iso14443_3a_poller_read_callback(NfcGenericEvent event, void* context
|
|||||||
return NfcCommandStop;
|
return NfcCommandStop;
|
||||||
}
|
}
|
||||||
|
|
||||||
Iso14443_3aError iso14443_3a_poller_read(Nfc* nfc, Iso14443_3aData* iso14443_3a_data) {
|
Iso14443_3aError iso14443_3a_poller_sync_read(Nfc* nfc, Iso14443_3aData* iso14443_3a_data) {
|
||||||
furi_assert(nfc);
|
furi_assert(nfc);
|
||||||
furi_assert(iso14443_3a_data);
|
furi_assert(iso14443_3a_data);
|
||||||
|
|
@ -7,7 +7,7 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Iso14443_3aError iso14443_3a_poller_read(Nfc* nfc, Iso14443_3aData* iso14443_3a_data);
|
Iso14443_3aError iso14443_3a_poller_sync_read(Nfc* nfc, Iso14443_3aData* iso14443_3a_data);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
@ -70,7 +70,7 @@ static NfcCommand iso14443_3b_poller_run(NfcGenericEvent event, void* context) {
|
|||||||
|
|
||||||
if(nfc_event->type == NfcEventTypePollerReady) {
|
if(nfc_event->type == NfcEventTypePollerReady) {
|
||||||
if(instance->state != Iso14443_3bPollerStateActivated) {
|
if(instance->state != Iso14443_3bPollerStateActivated) {
|
||||||
Iso14443_3bError error = iso14443_3b_poller_async_activate(instance, instance->data);
|
Iso14443_3bError error = iso14443_3b_poller_activate(instance, instance->data);
|
||||||
if(error == Iso14443_3bErrorNone) {
|
if(error == Iso14443_3bErrorNone) {
|
||||||
instance->iso14443_3b_event.type = Iso14443_3bPollerEventTypeReady;
|
instance->iso14443_3b_event.type = Iso14443_3bPollerEventTypeReady;
|
||||||
instance->iso14443_3b_event_data.error = error;
|
instance->iso14443_3b_event_data.error = error;
|
||||||
@ -104,7 +104,7 @@ static bool iso14443_3b_poller_detect(NfcGenericEvent event, void* context) {
|
|||||||
furi_assert(instance->state == Iso14443_3bPollerStateIdle);
|
furi_assert(instance->state == Iso14443_3bPollerStateIdle);
|
||||||
|
|
||||||
if(nfc_event->type == NfcEventTypePollerReady) {
|
if(nfc_event->type == NfcEventTypePollerReady) {
|
||||||
Iso14443_3bError error = iso14443_3b_poller_async_activate(instance, instance->data);
|
Iso14443_3bError error = iso14443_3b_poller_activate(instance, instance->data);
|
||||||
protocol_detected = (error == Iso14443_3bErrorNone);
|
protocol_detected = (error == Iso14443_3bErrorNone);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,22 +9,81 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Iso14443_3bPoller opaque type definition.
|
||||||
|
*/
|
||||||
typedef struct Iso14443_3bPoller Iso14443_3bPoller;
|
typedef struct Iso14443_3bPoller Iso14443_3bPoller;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enumeration of possible Iso14443_3b poller event types.
|
||||||
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
Iso14443_3bPollerEventTypeError,
|
Iso14443_3bPollerEventTypeError, /**< The card was activated by the poller. */
|
||||||
Iso14443_3bPollerEventTypeReady,
|
Iso14443_3bPollerEventTypeReady, /**< An error occured during activation procedure. */
|
||||||
} Iso14443_3bPollerEventType;
|
} Iso14443_3bPollerEventType;
|
||||||
|
|
||||||
typedef struct {
|
/**
|
||||||
Iso14443_3bError error;
|
* @brief Iso14443_3b poller event data.
|
||||||
|
*/
|
||||||
|
typedef union {
|
||||||
|
Iso14443_3bError error; /**< Error code indicating card activation fail reason. */
|
||||||
} Iso14443_3bPollerEventData;
|
} Iso14443_3bPollerEventData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Iso14443_3b poller event structure.
|
||||||
|
*
|
||||||
|
* Upon emission of an event, an instance of this struct will be passed to the callback.
|
||||||
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Iso14443_3bPollerEventType type;
|
Iso14443_3bPollerEventType type; /**< Type of emmitted event. */
|
||||||
Iso14443_3bPollerEventData* data;
|
Iso14443_3bPollerEventData* data; /**< Pointer to event specific data. */
|
||||||
} Iso14443_3bPollerEvent;
|
} Iso14443_3bPollerEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Transmit and receive Iso14443_3b frames in poller mode.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* The rx_buffer will be filled with any data received as a response to data
|
||||||
|
* sent from tx_buffer, with a timeout defined by the fwt parameter.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @param[in] tx_buffer pointer to the buffer containing the data to be transmitted.
|
||||||
|
* @param[out] rx_buffer pointer to the buffer to be filled with received data.
|
||||||
|
* @param[in] fwt frame wait time (response timeout), in carrier cycles.
|
||||||
|
* @return Iso14443_3bErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
Iso14443_3bError iso14443_3b_poller_send_frame(
|
||||||
|
Iso14443_3bPoller* instance,
|
||||||
|
const BitBuffer* tx_buffer,
|
||||||
|
BitBuffer* rx_buffer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Perform collision resolution procedure.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* Perfoms the collision resolution procedure as defined in Iso14443-3b. The data
|
||||||
|
* field will be filled with Iso14443-3b data on success.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @param[out] data pointer to the Iso14443_3b data structure to be filled.
|
||||||
|
* @return Iso14443_3bErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
Iso14443_3bError iso14443_3b_poller_activate(Iso14443_3bPoller* instance, Iso14443_3bData* data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send HALT command to the card.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* Halts card and changes internal Iso14443_3bPoller state to Idle.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @return Iso14443_3bErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
Iso14443_3bError iso14443_3b_poller_halt(Iso14443_3bPoller* instance);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -21,7 +21,7 @@ static Iso14443_3bError iso14443_3b_poller_prepare_trx(Iso14443_3bPoller* instan
|
|||||||
furi_assert(instance);
|
furi_assert(instance);
|
||||||
|
|
||||||
if(instance->state == Iso14443_3bPollerStateIdle) {
|
if(instance->state == Iso14443_3bPollerStateIdle) {
|
||||||
return iso14443_3b_poller_async_activate(instance, NULL);
|
return iso14443_3b_poller_activate(instance, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Iso14443_3bErrorNone;
|
return Iso14443_3bErrorNone;
|
||||||
@ -63,8 +63,7 @@ static Iso14443_3bError iso14443_3b_poller_frame_exchange(
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
Iso14443_3bError
|
Iso14443_3bError iso14443_3b_poller_activate(Iso14443_3bPoller* instance, Iso14443_3bData* data) {
|
||||||
iso14443_3b_poller_async_activate(Iso14443_3bPoller* instance, Iso14443_3bData* data) {
|
|
||||||
furi_assert(instance);
|
furi_assert(instance);
|
||||||
furi_assert(instance->nfc);
|
furi_assert(instance->nfc);
|
||||||
|
|
||||||
|
@ -34,16 +34,6 @@ struct Iso14443_3bPoller {
|
|||||||
|
|
||||||
const Iso14443_3bData* iso14443_3b_poller_get_data(Iso14443_3bPoller* instance);
|
const Iso14443_3bData* iso14443_3b_poller_get_data(Iso14443_3bPoller* instance);
|
||||||
|
|
||||||
Iso14443_3bError
|
|
||||||
iso14443_3b_poller_async_activate(Iso14443_3bPoller* instance, Iso14443_3bData* data);
|
|
||||||
|
|
||||||
Iso14443_3bError iso14443_3b_poller_halt(Iso14443_3bPoller* instance);
|
|
||||||
|
|
||||||
Iso14443_3bError iso14443_3b_poller_send_frame(
|
|
||||||
Iso14443_3bPoller* instance,
|
|
||||||
const BitBuffer* tx_buffer,
|
|
||||||
BitBuffer* rx_buffer);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
#include <nfc/protocols/iso14443_3a/iso14443_3a.h>
|
#include <nfc/protocols/iso14443_3a/iso14443_3a.h>
|
||||||
|
|
||||||
|
#include <lib/toolbox/simple_array.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
@ -28,7 +30,19 @@ typedef enum {
|
|||||||
Iso14443_4aFrameOptionCid,
|
Iso14443_4aFrameOptionCid,
|
||||||
} Iso14443_4aFrameOption;
|
} Iso14443_4aFrameOption;
|
||||||
|
|
||||||
typedef struct Iso14443_4aData Iso14443_4aData;
|
typedef struct {
|
||||||
|
uint8_t tl;
|
||||||
|
uint8_t t0;
|
||||||
|
uint8_t ta_1;
|
||||||
|
uint8_t tb_1;
|
||||||
|
uint8_t tc_1;
|
||||||
|
SimpleArray* t1_tk;
|
||||||
|
} Iso14443_4aAtsData;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Iso14443_3aData* iso14443_3a_data;
|
||||||
|
Iso14443_4aAtsData ats_data;
|
||||||
|
} Iso14443_4aData;
|
||||||
|
|
||||||
// Virtual methods
|
// Virtual methods
|
||||||
|
|
||||||
|
@ -2,8 +2,6 @@
|
|||||||
|
|
||||||
#include "iso14443_4a.h"
|
#include "iso14443_4a.h"
|
||||||
|
|
||||||
#include <lib/toolbox/simple_array.h>
|
|
||||||
|
|
||||||
#define ISO14443_4A_CMD_READ_ATS (0xE0)
|
#define ISO14443_4A_CMD_READ_ATS (0xE0)
|
||||||
|
|
||||||
// ATS bit definitions
|
// ATS bit definitions
|
||||||
@ -23,20 +21,6 @@
|
|||||||
#define ISO14443_4A_ATS_TC1_NAD (1U << 0)
|
#define ISO14443_4A_ATS_TC1_NAD (1U << 0)
|
||||||
#define ISO14443_4A_ATS_TC1_CID (1U << 1)
|
#define ISO14443_4A_ATS_TC1_CID (1U << 1)
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint8_t tl;
|
|
||||||
uint8_t t0;
|
|
||||||
uint8_t ta_1;
|
|
||||||
uint8_t tb_1;
|
|
||||||
uint8_t tc_1;
|
|
||||||
SimpleArray* t1_tk;
|
|
||||||
} Iso14443_4aAtsData;
|
|
||||||
|
|
||||||
struct Iso14443_4aData {
|
|
||||||
Iso14443_3aData* iso14443_3a_data;
|
|
||||||
Iso14443_4aAtsData ats_data;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool iso14443_4a_ats_parse(Iso14443_4aAtsData* data, const BitBuffer* buf);
|
bool iso14443_4a_ats_parse(Iso14443_4aAtsData* data, const BitBuffer* buf);
|
||||||
|
|
||||||
Iso14443_4aError iso14443_4a_process_error(Iso14443_3aError error);
|
Iso14443_4aError iso14443_4a_process_error(Iso14443_3aError error);
|
||||||
|
@ -55,8 +55,7 @@ static NfcCommand iso14443_4a_poller_handler_idle(Iso14443_4aPoller* instance) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static NfcCommand iso14443_4a_poller_handler_read_ats(Iso14443_4aPoller* instance) {
|
static NfcCommand iso14443_4a_poller_handler_read_ats(Iso14443_4aPoller* instance) {
|
||||||
Iso14443_4aError error =
|
Iso14443_4aError error = iso14443_4a_poller_read_ats(instance, &instance->data->ats_data);
|
||||||
iso14443_4a_poller_async_read_ats(instance, &instance->data->ats_data);
|
|
||||||
if(error == Iso14443_4aErrorNone) {
|
if(error == Iso14443_4aErrorNone) {
|
||||||
FURI_LOG_D(TAG, "Read ATS success");
|
FURI_LOG_D(TAG, "Read ATS success");
|
||||||
instance->poller_state = Iso14443_4aPollerStateReady;
|
instance->poller_state = Iso14443_4aPollerStateReady;
|
||||||
|
@ -8,22 +8,80 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Iso14443_4aPoller opaque type definition.
|
||||||
|
*/
|
||||||
typedef struct Iso14443_4aPoller Iso14443_4aPoller;
|
typedef struct Iso14443_4aPoller Iso14443_4aPoller;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enumeration of possible Iso14443_4a poller event types.
|
||||||
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
Iso14443_4aPollerEventTypeError,
|
Iso14443_4aPollerEventTypeError, /**< The card was activated by the poller. */
|
||||||
Iso14443_4aPollerEventTypeReady,
|
Iso14443_4aPollerEventTypeReady, /**< An error occured during activation procedure. */
|
||||||
} Iso14443_4aPollerEventType;
|
} Iso14443_4aPollerEventType;
|
||||||
|
|
||||||
typedef struct {
|
/**
|
||||||
Iso14443_4aError error;
|
* @brief Iso14443_4a poller event data.
|
||||||
|
*/
|
||||||
|
typedef union {
|
||||||
|
Iso14443_4aError error; /**< Error code indicating card activation fail reason. */
|
||||||
} Iso14443_4aPollerEventData;
|
} Iso14443_4aPollerEventData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Iso14443_4a poller event structure.
|
||||||
|
*
|
||||||
|
* Upon emission of an event, an instance of this struct will be passed to the callback.
|
||||||
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Iso14443_4aPollerEventType type;
|
Iso14443_4aPollerEventType type; /**< Type of emmitted event. */
|
||||||
Iso14443_4aPollerEventData* data;
|
Iso14443_4aPollerEventData* data; /**< Pointer to event specific data. */
|
||||||
} Iso14443_4aPollerEvent;
|
} Iso14443_4aPollerEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Transmit and receive Iso14443_4a blocks in poller mode.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* The rx_buffer will be filled with any data received as a response to data
|
||||||
|
* sent from tx_buffer. The fwt parameter is calculated during activation procedure.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @param[in] tx_buffer pointer to the buffer containing the data to be transmitted.
|
||||||
|
* @param[out] rx_buffer pointer to the buffer to be filled with received data.
|
||||||
|
* @return Iso14443_4aErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
Iso14443_4aError iso14443_4a_poller_send_block(
|
||||||
|
Iso14443_4aPoller* instance,
|
||||||
|
const BitBuffer* tx_buffer,
|
||||||
|
BitBuffer* rx_buffer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send HALT command to the card.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* Halts card and changes internal Iso14443_4aPoller state to Idle.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @return Iso14443_4aErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
Iso14443_4aError iso14443_4a_poller_halt(Iso14443_4aPoller* instance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read Answer To Select (ATS) from the card.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* Send Request Answer To Select (RATS) command to the card and parse the response.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @param[out] data pointer to the buffer to be filled with ATS data.
|
||||||
|
* @return Iso14443_4aErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
Iso14443_4aError
|
||||||
|
iso14443_4a_poller_read_ats(Iso14443_4aPoller* instance, Iso14443_4aAtsData* data);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -18,7 +18,7 @@ Iso14443_4aError iso14443_4a_poller_halt(Iso14443_4aPoller* instance) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Iso14443_4aError
|
Iso14443_4aError
|
||||||
iso14443_4a_poller_async_read_ats(Iso14443_4aPoller* instance, Iso14443_4aAtsData* data) {
|
iso14443_4a_poller_read_ats(Iso14443_4aPoller* instance, Iso14443_4aAtsData* data) {
|
||||||
furi_assert(instance);
|
furi_assert(instance);
|
||||||
|
|
||||||
bit_buffer_reset(instance->tx_buffer);
|
bit_buffer_reset(instance->tx_buffer);
|
||||||
|
@ -45,16 +45,6 @@ struct Iso14443_4aPoller {
|
|||||||
|
|
||||||
const Iso14443_4aData* iso14443_4a_poller_get_data(Iso14443_4aPoller* instance);
|
const Iso14443_4aData* iso14443_4a_poller_get_data(Iso14443_4aPoller* instance);
|
||||||
|
|
||||||
Iso14443_4aError iso14443_4a_poller_halt(Iso14443_4aPoller* instance);
|
|
||||||
|
|
||||||
Iso14443_4aError
|
|
||||||
iso14443_4a_poller_async_read_ats(Iso14443_4aPoller* instance, Iso14443_4aAtsData* data);
|
|
||||||
|
|
||||||
Iso14443_4aError iso14443_4a_poller_send_block(
|
|
||||||
Iso14443_4aPoller* instance,
|
|
||||||
const BitBuffer* tx_buffer,
|
|
||||||
BitBuffer* rx_buffer);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -8,22 +8,66 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Iso14443_4bPoller opaque type definition.
|
||||||
|
*/
|
||||||
typedef struct Iso14443_4bPoller Iso14443_4bPoller;
|
typedef struct Iso14443_4bPoller Iso14443_4bPoller;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enumeration of possible Iso14443_4b poller event types.
|
||||||
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
Iso14443_4bPollerEventTypeError,
|
Iso14443_4bPollerEventTypeError, /**< The card was activated by the poller. */
|
||||||
Iso14443_4bPollerEventTypeReady,
|
Iso14443_4bPollerEventTypeReady, /**< An error occured during activation procedure. */
|
||||||
} Iso14443_4bPollerEventType;
|
} Iso14443_4bPollerEventType;
|
||||||
|
|
||||||
typedef struct {
|
/**
|
||||||
Iso14443_4bError error;
|
* @brief Iso14443_4b poller event data.
|
||||||
|
*/
|
||||||
|
typedef union {
|
||||||
|
Iso14443_4bError error; /**< Error code indicating card activation fail reason. */
|
||||||
} Iso14443_4bPollerEventData;
|
} Iso14443_4bPollerEventData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Iso14443_4b poller event structure.
|
||||||
|
*
|
||||||
|
* Upon emission of an event, an instance of this struct will be passed to the callback.
|
||||||
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Iso14443_4bPollerEventType type;
|
Iso14443_4bPollerEventType type; /**< Type of emmitted event. */
|
||||||
Iso14443_4bPollerEventData* data;
|
Iso14443_4bPollerEventData* data; /**< Pointer to event specific data. */
|
||||||
} Iso14443_4bPollerEvent;
|
} Iso14443_4bPollerEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Transmit and receive Iso14443_4b blocks in poller mode.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* The rx_buffer will be filled with any data received as a response to data
|
||||||
|
* sent from tx_buffer. The fwt parameter is calculated during activation procedure.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @param[in] tx_buffer pointer to the buffer containing the data to be transmitted.
|
||||||
|
* @param[out] rx_buffer pointer to the buffer to be filled with received data.
|
||||||
|
* @return Iso14443_4bErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
Iso14443_4bError iso14443_4b_poller_send_block(
|
||||||
|
Iso14443_4bPoller* instance,
|
||||||
|
const BitBuffer* tx_buffer,
|
||||||
|
BitBuffer* rx_buffer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send HALT command to the card.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* Halts card and changes internal Iso14443_4aPoller state to Idle.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @return Iso14443_4bErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
Iso14443_4bError iso14443_4b_poller_halt(Iso14443_4bPoller* instance);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -42,13 +42,6 @@ struct Iso14443_4bPoller {
|
|||||||
|
|
||||||
const Iso14443_4bData* iso14443_4b_poller_get_data(Iso14443_4bPoller* instance);
|
const Iso14443_4bData* iso14443_4b_poller_get_data(Iso14443_4bPoller* instance);
|
||||||
|
|
||||||
Iso14443_4bError iso14443_4b_poller_halt(Iso14443_4bPoller* instance);
|
|
||||||
|
|
||||||
Iso14443_4bError iso14443_4b_poller_send_block(
|
|
||||||
Iso14443_4bPoller* instance,
|
|
||||||
const BitBuffer* tx_buffer,
|
|
||||||
BitBuffer* rx_buffer);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -70,7 +70,7 @@ static NfcCommand iso15693_3_poller_run(NfcGenericEvent event, void* context) {
|
|||||||
|
|
||||||
if(nfc_event->type == NfcEventTypePollerReady) {
|
if(nfc_event->type == NfcEventTypePollerReady) {
|
||||||
if(instance->state != Iso15693_3PollerStateActivated) {
|
if(instance->state != Iso15693_3PollerStateActivated) {
|
||||||
Iso15693_3Error error = iso15693_3_poller_async_activate(instance, instance->data);
|
Iso15693_3Error error = iso15693_3_poller_activate(instance, instance->data);
|
||||||
if(error == Iso15693_3ErrorNone) {
|
if(error == Iso15693_3ErrorNone) {
|
||||||
instance->iso15693_3_event.type = Iso15693_3PollerEventTypeReady;
|
instance->iso15693_3_event.type = Iso15693_3PollerEventTypeReady;
|
||||||
instance->iso15693_3_event_data.error = error;
|
instance->iso15693_3_event_data.error = error;
|
||||||
@ -105,7 +105,7 @@ static bool iso15693_3_poller_detect(NfcGenericEvent event, void* context) {
|
|||||||
|
|
||||||
if(nfc_event->type == NfcEventTypePollerReady) {
|
if(nfc_event->type == NfcEventTypePollerReady) {
|
||||||
uint8_t uid[ISO15693_3_UID_SIZE];
|
uint8_t uid[ISO15693_3_UID_SIZE];
|
||||||
Iso15693_3Error error = iso15693_3_poller_async_inventory(instance, uid);
|
Iso15693_3Error error = iso15693_3_poller_inventory(instance, uid);
|
||||||
protocol_detected = (error == Iso15693_3ErrorNone);
|
protocol_detected = (error == Iso15693_3ErrorNone);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,22 +8,142 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Iso15693_3Poller opaque type definition.
|
||||||
|
*/
|
||||||
typedef struct Iso15693_3Poller Iso15693_3Poller;
|
typedef struct Iso15693_3Poller Iso15693_3Poller;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enumeration of possible Iso15693_3 poller event types.
|
||||||
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
Iso15693_3PollerEventTypeError,
|
Iso15693_3PollerEventTypeError, /**< The card was activated by the poller. */
|
||||||
Iso15693_3PollerEventTypeReady,
|
Iso15693_3PollerEventTypeReady, /**< An error occured during activation procedure. */
|
||||||
} Iso15693_3PollerEventType;
|
} Iso15693_3PollerEventType;
|
||||||
|
|
||||||
typedef struct {
|
/**
|
||||||
Iso15693_3Error error;
|
* @brief Iso15693_3 poller event data.
|
||||||
|
*/
|
||||||
|
typedef union {
|
||||||
|
Iso15693_3Error error; /**< Error code indicating card activation fail reason. */
|
||||||
} Iso15693_3PollerEventData;
|
} Iso15693_3PollerEventData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Iso15693_3 poller event structure.
|
||||||
|
*
|
||||||
|
* Upon emission of an event, an instance of this struct will be passed to the callback.
|
||||||
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Iso15693_3PollerEventType type;
|
Iso15693_3PollerEventType type; /**< Type of emmitted event. */
|
||||||
Iso15693_3PollerEventData* data;
|
Iso15693_3PollerEventData* data; /**< Pointer to event specific data. */
|
||||||
} Iso15693_3PollerEvent;
|
} Iso15693_3PollerEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Transmit and receive Iso15693_3 frames in poller mode.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* The rx_buffer will be filled with any data received as a response to data
|
||||||
|
* sent from tx_buffer, with a timeout defined by the fwt parameter.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @param[in] tx_buffer pointer to the buffer containing the data to be transmitted.
|
||||||
|
* @param[out] rx_buffer pointer to the buffer to be filled with received data.
|
||||||
|
* @param[in] fwt frame wait time (response timeout), in carrier cycles.
|
||||||
|
* @return Iso15693_3ErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
Iso15693_3Error iso15693_3_poller_send_frame(
|
||||||
|
Iso15693_3Poller* instance,
|
||||||
|
const BitBuffer* tx_buffer,
|
||||||
|
BitBuffer* rx_buffer,
|
||||||
|
uint32_t fwt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Perform activation procedure.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* Perfoms the activation procedure as defined in Iso15693_3. The data
|
||||||
|
* field will be filled with Iso15693_3Data data on success.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @param[out] data pointer to the Iso15693_3 data structure to be filled.
|
||||||
|
* @return Iso15693_3ErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
Iso15693_3Error iso15693_3_poller_activate(Iso15693_3Poller* instance, Iso15693_3Data* data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send invertory command and parse response.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @param[out] uid pointer to the buffer to be filled with the UID.
|
||||||
|
* @return Iso15693_3ErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
Iso15693_3Error iso15693_3_poller_inventory(Iso15693_3Poller* instance, uint8_t* uid);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send get system info command and parse response.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @param[out] data pointer to the Iso15693_3SystemInfo structure to be filled.
|
||||||
|
* @return Iso15693_3ErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
Iso15693_3Error
|
||||||
|
iso15693_3_poller_get_system_info(Iso15693_3Poller* instance, Iso15693_3SystemInfo* data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read Iso15693_3 block.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @param[out] data pointer to the buffer to be filled with the block data.
|
||||||
|
* @param[in] block_number block number to be read.
|
||||||
|
* @param[in] block_size size of the block to be read.
|
||||||
|
* @return Iso15693_3ErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
Iso15693_3Error iso15693_3_poller_read_block(
|
||||||
|
Iso15693_3Poller* instance,
|
||||||
|
uint8_t* data,
|
||||||
|
uint8_t block_number,
|
||||||
|
uint8_t block_size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read multiple Iso15693_3 blocks.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @param[out] data pointer to the buffer to be filled with the block data.
|
||||||
|
* @param[in] block_count number of blocks to be read.
|
||||||
|
* @param[in] block_size size of the blocks to be read.
|
||||||
|
* @return Iso15693_3ErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
Iso15693_3Error iso15693_3_poller_read_blocks(
|
||||||
|
Iso15693_3Poller* instance,
|
||||||
|
uint8_t* data,
|
||||||
|
uint16_t block_count,
|
||||||
|
uint8_t block_size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get Iso15693_3 block security status.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @param[out] data pointer to the buffer to be filled with the block security status.
|
||||||
|
* @param[in] block_count block security number to be read.
|
||||||
|
* @return Iso15693_3ErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
Iso15693_3Error iso15693_3_poller_get_blocks_security(
|
||||||
|
Iso15693_3Poller* instance,
|
||||||
|
uint8_t* data,
|
||||||
|
uint16_t block_count);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -36,7 +36,7 @@ static Iso15693_3Error iso15693_3_poller_prepare_trx(Iso15693_3Poller* instance)
|
|||||||
furi_assert(instance);
|
furi_assert(instance);
|
||||||
|
|
||||||
if(instance->state == Iso15693_3PollerStateIdle) {
|
if(instance->state == Iso15693_3PollerStateIdle) {
|
||||||
return iso15693_3_poller_async_activate(instance, NULL);
|
return iso15693_3_poller_activate(instance, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Iso15693_3ErrorNone;
|
return Iso15693_3ErrorNone;
|
||||||
@ -80,8 +80,7 @@ static Iso15693_3Error iso15693_3_poller_frame_exchange(
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
Iso15693_3Error
|
Iso15693_3Error iso15693_3_poller_activate(Iso15693_3Poller* instance, Iso15693_3Data* data) {
|
||||||
iso15693_3_poller_async_activate(Iso15693_3Poller* instance, Iso15693_3Data* data) {
|
|
||||||
furi_assert(instance);
|
furi_assert(instance);
|
||||||
furi_assert(instance->nfc);
|
furi_assert(instance->nfc);
|
||||||
|
|
||||||
@ -93,7 +92,7 @@ Iso15693_3Error
|
|||||||
instance->state = Iso15693_3PollerStateColResInProgress;
|
instance->state = Iso15693_3PollerStateColResInProgress;
|
||||||
|
|
||||||
// Inventory: Mandatory command
|
// Inventory: Mandatory command
|
||||||
ret = iso15693_3_poller_async_inventory(instance, data->uid);
|
ret = iso15693_3_poller_inventory(instance, data->uid);
|
||||||
if(ret != Iso15693_3ErrorNone) {
|
if(ret != Iso15693_3ErrorNone) {
|
||||||
instance->state = Iso15693_3PollerStateColResFailed;
|
instance->state = Iso15693_3PollerStateColResFailed;
|
||||||
break;
|
break;
|
||||||
@ -103,7 +102,7 @@ Iso15693_3Error
|
|||||||
|
|
||||||
// Get system info: Optional command
|
// Get system info: Optional command
|
||||||
Iso15693_3SystemInfo* system_info = &data->system_info;
|
Iso15693_3SystemInfo* system_info = &data->system_info;
|
||||||
ret = iso15693_3_poller_async_get_system_info(instance, system_info);
|
ret = iso15693_3_poller_get_system_info(instance, system_info);
|
||||||
if(ret != Iso15693_3ErrorNone) {
|
if(ret != Iso15693_3ErrorNone) {
|
||||||
ret = iso15693_3_poller_filter_error(ret);
|
ret = iso15693_3_poller_filter_error(ret);
|
||||||
break;
|
break;
|
||||||
@ -111,7 +110,7 @@ Iso15693_3Error
|
|||||||
|
|
||||||
// Read blocks: Optional command
|
// Read blocks: Optional command
|
||||||
simple_array_init(data->block_data, system_info->block_count * system_info->block_size);
|
simple_array_init(data->block_data, system_info->block_count * system_info->block_size);
|
||||||
ret = iso15693_3_poller_async_read_blocks(
|
ret = iso15693_3_poller_read_blocks(
|
||||||
instance,
|
instance,
|
||||||
simple_array_get_data(data->block_data),
|
simple_array_get_data(data->block_data),
|
||||||
system_info->block_count,
|
system_info->block_count,
|
||||||
@ -124,7 +123,7 @@ Iso15693_3Error
|
|||||||
// Get block security status: Optional command
|
// Get block security status: Optional command
|
||||||
simple_array_init(data->block_security, system_info->block_count);
|
simple_array_init(data->block_security, system_info->block_count);
|
||||||
|
|
||||||
ret = iso15693_3_poller_async_get_blocks_security(
|
ret = iso15693_3_poller_get_blocks_security(
|
||||||
instance, simple_array_get_data(data->block_security), system_info->block_count);
|
instance, simple_array_get_data(data->block_security), system_info->block_count);
|
||||||
if(ret != Iso15693_3ErrorNone) {
|
if(ret != Iso15693_3ErrorNone) {
|
||||||
ret = iso15693_3_poller_filter_error(ret);
|
ret = iso15693_3_poller_filter_error(ret);
|
||||||
@ -136,7 +135,7 @@ Iso15693_3Error
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
Iso15693_3Error iso15693_3_poller_async_inventory(Iso15693_3Poller* instance, uint8_t* uid) {
|
Iso15693_3Error iso15693_3_poller_inventory(Iso15693_3Poller* instance, uint8_t* uid) {
|
||||||
furi_assert(instance);
|
furi_assert(instance);
|
||||||
furi_assert(instance->nfc);
|
furi_assert(instance->nfc);
|
||||||
furi_assert(uid);
|
furi_assert(uid);
|
||||||
@ -165,9 +164,8 @@ Iso15693_3Error iso15693_3_poller_async_inventory(Iso15693_3Poller* instance, ui
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
Iso15693_3Error iso15693_3_poller_async_get_system_info(
|
Iso15693_3Error
|
||||||
Iso15693_3Poller* instance,
|
iso15693_3_poller_get_system_info(Iso15693_3Poller* instance, Iso15693_3SystemInfo* data) {
|
||||||
Iso15693_3SystemInfo* data) {
|
|
||||||
furi_assert(instance);
|
furi_assert(instance);
|
||||||
furi_assert(data);
|
furi_assert(data);
|
||||||
|
|
||||||
@ -193,7 +191,7 @@ Iso15693_3Error iso15693_3_poller_async_get_system_info(
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
Iso15693_3Error iso15693_3_poller_async_read_block(
|
Iso15693_3Error iso15693_3_poller_read_block(
|
||||||
Iso15693_3Poller* instance,
|
Iso15693_3Poller* instance,
|
||||||
uint8_t* data,
|
uint8_t* data,
|
||||||
uint8_t block_number,
|
uint8_t block_number,
|
||||||
@ -222,7 +220,7 @@ Iso15693_3Error iso15693_3_poller_async_read_block(
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
Iso15693_3Error iso15693_3_poller_async_read_blocks(
|
Iso15693_3Error iso15693_3_poller_read_blocks(
|
||||||
Iso15693_3Poller* instance,
|
Iso15693_3Poller* instance,
|
||||||
uint8_t* data,
|
uint8_t* data,
|
||||||
uint16_t block_count,
|
uint16_t block_count,
|
||||||
@ -235,14 +233,14 @@ Iso15693_3Error iso15693_3_poller_async_read_blocks(
|
|||||||
Iso15693_3Error ret = Iso15693_3ErrorNone;
|
Iso15693_3Error ret = Iso15693_3ErrorNone;
|
||||||
|
|
||||||
for(uint32_t i = 0; i < block_count; ++i) {
|
for(uint32_t i = 0; i < block_count; ++i) {
|
||||||
ret = iso15693_3_poller_async_read_block(instance, &data[block_size * i], i, block_size);
|
ret = iso15693_3_poller_read_block(instance, &data[block_size * i], i, block_size);
|
||||||
if(ret != Iso15693_3ErrorNone) break;
|
if(ret != Iso15693_3ErrorNone) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
Iso15693_3Error iso15693_3_poller_async_get_blocks_security(
|
Iso15693_3Error iso15693_3_poller_get_blocks_security(
|
||||||
Iso15693_3Poller* instance,
|
Iso15693_3Poller* instance,
|
||||||
uint8_t* data,
|
uint8_t* data,
|
||||||
uint16_t block_count) {
|
uint16_t block_count) {
|
||||||
|
@ -35,36 +35,6 @@ struct Iso15693_3Poller {
|
|||||||
|
|
||||||
const Iso15693_3Data* iso15693_3_poller_get_data(Iso15693_3Poller* instance);
|
const Iso15693_3Data* iso15693_3_poller_get_data(Iso15693_3Poller* instance);
|
||||||
|
|
||||||
Iso15693_3Error iso15693_3_poller_async_activate(Iso15693_3Poller* instance, Iso15693_3Data* data);
|
|
||||||
|
|
||||||
Iso15693_3Error iso15693_3_poller_async_inventory(Iso15693_3Poller* instance, uint8_t* uid);
|
|
||||||
|
|
||||||
Iso15693_3Error
|
|
||||||
iso15693_3_poller_async_get_system_info(Iso15693_3Poller* instance, Iso15693_3SystemInfo* data);
|
|
||||||
|
|
||||||
Iso15693_3Error iso15693_3_poller_async_read_block(
|
|
||||||
Iso15693_3Poller* instance,
|
|
||||||
uint8_t* data,
|
|
||||||
uint8_t block_number,
|
|
||||||
uint8_t block_size);
|
|
||||||
|
|
||||||
Iso15693_3Error iso15693_3_poller_async_read_blocks(
|
|
||||||
Iso15693_3Poller* instance,
|
|
||||||
uint8_t* data,
|
|
||||||
uint16_t block_count,
|
|
||||||
uint8_t block_size);
|
|
||||||
|
|
||||||
Iso15693_3Error iso15693_3_poller_async_get_blocks_security(
|
|
||||||
Iso15693_3Poller* instance,
|
|
||||||
uint8_t* data,
|
|
||||||
uint16_t block_count);
|
|
||||||
|
|
||||||
Iso15693_3Error iso15693_3_poller_send_frame(
|
|
||||||
Iso15693_3Poller* instance,
|
|
||||||
const BitBuffer* tx_buffer,
|
|
||||||
BitBuffer* rx_buffer,
|
|
||||||
uint32_t fwt);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -85,7 +85,7 @@ NfcCommand mf_classic_poller_handler_detect_type(MfClassicPoller* instance) {
|
|||||||
iso14443_3a_copy(
|
iso14443_3a_copy(
|
||||||
instance->data->iso14443_3a_data,
|
instance->data->iso14443_3a_data,
|
||||||
iso14443_3a_poller_get_data(instance->iso14443_3a_poller));
|
iso14443_3a_poller_get_data(instance->iso14443_3a_poller));
|
||||||
MfClassicError error = mf_classic_async_get_nt(instance, 254, MfClassicKeyTypeA, NULL);
|
MfClassicError error = mf_classic_poller_get_nt(instance, 254, MfClassicKeyTypeA, NULL);
|
||||||
if(error == MfClassicErrorNone) {
|
if(error == MfClassicErrorNone) {
|
||||||
instance->data->type = MfClassicType4k;
|
instance->data->type = MfClassicType4k;
|
||||||
instance->state = MfClassicPollerStateStart;
|
instance->state = MfClassicPollerStateStart;
|
||||||
@ -95,7 +95,7 @@ NfcCommand mf_classic_poller_handler_detect_type(MfClassicPoller* instance) {
|
|||||||
instance->current_type_check = MfClassicType1k;
|
instance->current_type_check = MfClassicType1k;
|
||||||
}
|
}
|
||||||
} else if(instance->current_type_check == MfClassicType1k) {
|
} else if(instance->current_type_check == MfClassicType1k) {
|
||||||
MfClassicError error = mf_classic_async_get_nt(instance, 62, MfClassicKeyTypeA, NULL);
|
MfClassicError error = mf_classic_poller_get_nt(instance, 62, MfClassicKeyTypeA, NULL);
|
||||||
if(error == MfClassicErrorNone) {
|
if(error == MfClassicErrorNone) {
|
||||||
instance->data->type = MfClassicType1k;
|
instance->data->type = MfClassicType1k;
|
||||||
FURI_LOG_D(TAG, "1K detected");
|
FURI_LOG_D(TAG, "1K detected");
|
||||||
@ -234,7 +234,7 @@ NfcCommand mf_classic_poller_handler_read_block(MfClassicPoller* instance) {
|
|||||||
|
|
||||||
do {
|
do {
|
||||||
// Authenticate to sector
|
// Authenticate to sector
|
||||||
error = mf_classic_async_auth(
|
error = mf_classic_poller_auth(
|
||||||
instance, write_ctx->current_block, auth_key, write_ctx->key_type_read, NULL);
|
instance, write_ctx->current_block, auth_key, write_ctx->key_type_read, NULL);
|
||||||
if(error != MfClassicErrorNone) {
|
if(error != MfClassicErrorNone) {
|
||||||
FURI_LOG_D(TAG, "Failed to auth to block %d", write_ctx->current_block);
|
FURI_LOG_D(TAG, "Failed to auth to block %d", write_ctx->current_block);
|
||||||
@ -243,8 +243,8 @@ NfcCommand mf_classic_poller_handler_read_block(MfClassicPoller* instance) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Read block from tag
|
// Read block from tag
|
||||||
error =
|
error = mf_classic_poller_read_block(
|
||||||
mf_classic_async_read_block(instance, write_ctx->current_block, &write_ctx->tag_block);
|
instance, write_ctx->current_block, &write_ctx->tag_block);
|
||||||
if(error != MfClassicErrorNone) {
|
if(error != MfClassicErrorNone) {
|
||||||
FURI_LOG_D(TAG, "Failed to read block %d", write_ctx->current_block);
|
FURI_LOG_D(TAG, "Failed to read block %d", write_ctx->current_block);
|
||||||
instance->state = MfClassicPollerStateFail;
|
instance->state = MfClassicPollerStateFail;
|
||||||
@ -252,11 +252,11 @@ NfcCommand mf_classic_poller_handler_read_block(MfClassicPoller* instance) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(write_ctx->is_value_block) {
|
if(write_ctx->is_value_block) {
|
||||||
mf_classic_async_halt(instance);
|
mf_classic_poller_halt(instance);
|
||||||
instance->state = MfClassicPollerStateWriteValueBlock;
|
instance->state = MfClassicPollerStateWriteValueBlock;
|
||||||
} else {
|
} else {
|
||||||
if(write_ctx->need_halt_before_write) {
|
if(write_ctx->need_halt_before_write) {
|
||||||
mf_classic_async_halt(instance);
|
mf_classic_poller_halt(instance);
|
||||||
}
|
}
|
||||||
instance->state = MfClassicPollerStateWriteBlock;
|
instance->state = MfClassicPollerStateWriteBlock;
|
||||||
}
|
}
|
||||||
@ -292,7 +292,7 @@ NfcCommand mf_classic_poller_handler_write_block(MfClassicPoller* instance) {
|
|||||||
|
|
||||||
// Reauth if necessary
|
// Reauth if necessary
|
||||||
if(write_ctx->need_halt_before_write) {
|
if(write_ctx->need_halt_before_write) {
|
||||||
error = mf_classic_async_auth(
|
error = mf_classic_poller_auth(
|
||||||
instance, write_ctx->current_block, auth_key, write_ctx->key_type_write, NULL);
|
instance, write_ctx->current_block, auth_key, write_ctx->key_type_write, NULL);
|
||||||
if(error != MfClassicErrorNone) {
|
if(error != MfClassicErrorNone) {
|
||||||
FURI_LOG_D(
|
FURI_LOG_D(
|
||||||
@ -303,7 +303,7 @@ NfcCommand mf_classic_poller_handler_write_block(MfClassicPoller* instance) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Write block
|
// Write block
|
||||||
error = mf_classic_async_write_block(
|
error = mf_classic_poller_write_block(
|
||||||
instance,
|
instance,
|
||||||
write_ctx->current_block,
|
write_ctx->current_block,
|
||||||
&instance->mfc_event_data.write_block_data.write_block);
|
&instance->mfc_event_data.write_block_data.write_block);
|
||||||
@ -315,7 +315,7 @@ NfcCommand mf_classic_poller_handler_write_block(MfClassicPoller* instance) {
|
|||||||
|
|
||||||
} while(false);
|
} while(false);
|
||||||
|
|
||||||
mf_classic_async_halt(instance);
|
mf_classic_poller_halt(instance);
|
||||||
write_ctx->current_block++;
|
write_ctx->current_block++;
|
||||||
instance->state = MfClassicPollerStateCheckWriteConditions;
|
instance->state = MfClassicPollerStateCheckWriteConditions;
|
||||||
|
|
||||||
@ -403,18 +403,18 @@ NfcCommand mf_classic_poller_handler_write_value_block(MfClassicPoller* instance
|
|||||||
&write_ctx->sec_tr.key_b;
|
&write_ctx->sec_tr.key_b;
|
||||||
|
|
||||||
MfClassicError error =
|
MfClassicError error =
|
||||||
mf_classic_async_auth(instance, write_ctx->current_block, key, auth_key_type, NULL);
|
mf_classic_poller_auth(instance, write_ctx->current_block, key, auth_key_type, NULL);
|
||||||
if(error != MfClassicErrorNone) break;
|
if(error != MfClassicErrorNone) break;
|
||||||
|
|
||||||
error = mf_classic_async_value_cmd(instance, write_ctx->current_block, value_cmd, diff);
|
error = mf_classic_poller_value_cmd(instance, write_ctx->current_block, value_cmd, diff);
|
||||||
if(error != MfClassicErrorNone) break;
|
if(error != MfClassicErrorNone) break;
|
||||||
|
|
||||||
error = mf_classic_async_value_transfer(instance, write_ctx->current_block);
|
error = mf_classic_poller_value_transfer(instance, write_ctx->current_block);
|
||||||
if(error != MfClassicErrorNone) break;
|
if(error != MfClassicErrorNone) break;
|
||||||
|
|
||||||
} while(false);
|
} while(false);
|
||||||
|
|
||||||
mf_classic_async_halt(instance);
|
mf_classic_poller_halt(instance);
|
||||||
write_ctx->is_value_block = false;
|
write_ctx->is_value_block = false;
|
||||||
write_ctx->current_block++;
|
write_ctx->current_block++;
|
||||||
instance->state = MfClassicPollerStateCheckWriteConditions;
|
instance->state = MfClassicPollerStateCheckWriteConditions;
|
||||||
@ -462,7 +462,7 @@ NfcCommand mf_classic_poller_handler_request_read_sector_blocks(MfClassicPoller*
|
|||||||
sec_read_ctx->current_block,
|
sec_read_ctx->current_block,
|
||||||
sec_read_ctx->key_type == MfClassicKeyTypeA ? 'A' : 'B',
|
sec_read_ctx->key_type == MfClassicKeyTypeA ? 'A' : 'B',
|
||||||
key);
|
key);
|
||||||
error = mf_classic_async_auth(
|
error = mf_classic_poller_auth(
|
||||||
instance,
|
instance,
|
||||||
sec_read_ctx->current_block,
|
sec_read_ctx->current_block,
|
||||||
&sec_read_ctx->key,
|
&sec_read_ctx->key,
|
||||||
@ -481,7 +481,7 @@ NfcCommand mf_classic_poller_handler_request_read_sector_blocks(MfClassicPoller*
|
|||||||
|
|
||||||
FURI_LOG_D(TAG, "Reading block %d", sec_read_ctx->current_block);
|
FURI_LOG_D(TAG, "Reading block %d", sec_read_ctx->current_block);
|
||||||
MfClassicBlock read_block = {};
|
MfClassicBlock read_block = {};
|
||||||
error = mf_classic_async_read_block(instance, sec_read_ctx->current_block, &read_block);
|
error = mf_classic_poller_read_block(instance, sec_read_ctx->current_block, &read_block);
|
||||||
if(error == MfClassicErrorNone) {
|
if(error == MfClassicErrorNone) {
|
||||||
mf_classic_set_block_read(instance->data, sec_read_ctx->current_block, &read_block);
|
mf_classic_set_block_read(instance->data, sec_read_ctx->current_block, &read_block);
|
||||||
if(sec_read_ctx->key_type == MfClassicKeyTypeA) {
|
if(sec_read_ctx->key_type == MfClassicKeyTypeA) {
|
||||||
@ -489,7 +489,7 @@ NfcCommand mf_classic_poller_handler_request_read_sector_blocks(MfClassicPoller*
|
|||||||
instance, sec_read_ctx->current_block, &read_block);
|
instance, sec_read_ctx->current_block, &read_block);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mf_classic_async_halt(instance);
|
mf_classic_poller_halt(instance);
|
||||||
sec_read_ctx->auth_passed = false;
|
sec_read_ctx->auth_passed = false;
|
||||||
}
|
}
|
||||||
} while(false);
|
} while(false);
|
||||||
@ -497,7 +497,7 @@ NfcCommand mf_classic_poller_handler_request_read_sector_blocks(MfClassicPoller*
|
|||||||
uint8_t sec_tr_num = mf_classic_get_sector_trailer_num_by_sector(sec_read_ctx->current_sector);
|
uint8_t sec_tr_num = mf_classic_get_sector_trailer_num_by_sector(sec_read_ctx->current_sector);
|
||||||
sec_read_ctx->current_block++;
|
sec_read_ctx->current_block++;
|
||||||
if(sec_read_ctx->current_block > sec_tr_num) {
|
if(sec_read_ctx->current_block > sec_tr_num) {
|
||||||
mf_classic_async_halt(instance);
|
mf_classic_poller_halt(instance);
|
||||||
instance->state = MfClassicPollerStateRequestReadSector;
|
instance->state = MfClassicPollerStateRequestReadSector;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -532,7 +532,7 @@ NfcCommand mf_classic_poller_handler_auth_a(MfClassicPoller* instance) {
|
|||||||
uint64_t key = nfc_util_bytes2num(dict_attack_ctx->current_key.data, sizeof(MfClassicKey));
|
uint64_t key = nfc_util_bytes2num(dict_attack_ctx->current_key.data, sizeof(MfClassicKey));
|
||||||
FURI_LOG_D(TAG, "Auth to block %d with key A: %06llx", block, key);
|
FURI_LOG_D(TAG, "Auth to block %d with key A: %06llx", block, key);
|
||||||
|
|
||||||
MfClassicError error = mf_classic_async_auth(
|
MfClassicError error = mf_classic_poller_auth(
|
||||||
instance, block, &dict_attack_ctx->current_key, MfClassicKeyTypeA, NULL);
|
instance, block, &dict_attack_ctx->current_key, MfClassicKeyTypeA, NULL);
|
||||||
if(error == MfClassicErrorNone) {
|
if(error == MfClassicErrorNone) {
|
||||||
FURI_LOG_I(TAG, "Key A found");
|
FURI_LOG_I(TAG, "Key A found");
|
||||||
@ -545,7 +545,7 @@ NfcCommand mf_classic_poller_handler_auth_a(MfClassicPoller* instance) {
|
|||||||
dict_attack_ctx->auth_passed = true;
|
dict_attack_ctx->auth_passed = true;
|
||||||
instance->state = MfClassicPollerStateReadSector;
|
instance->state = MfClassicPollerStateReadSector;
|
||||||
} else {
|
} else {
|
||||||
mf_classic_async_halt(instance);
|
mf_classic_poller_halt(instance);
|
||||||
instance->state = MfClassicPollerStateAuthKeyB;
|
instance->state = MfClassicPollerStateAuthKeyB;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -570,7 +570,7 @@ NfcCommand mf_classic_poller_handler_auth_b(MfClassicPoller* instance) {
|
|||||||
uint64_t key = nfc_util_bytes2num(dict_attack_ctx->current_key.data, sizeof(MfClassicKey));
|
uint64_t key = nfc_util_bytes2num(dict_attack_ctx->current_key.data, sizeof(MfClassicKey));
|
||||||
FURI_LOG_D(TAG, "Auth to block %d with key B: %06llx", block, key);
|
FURI_LOG_D(TAG, "Auth to block %d with key B: %06llx", block, key);
|
||||||
|
|
||||||
MfClassicError error = mf_classic_async_auth(
|
MfClassicError error = mf_classic_poller_auth(
|
||||||
instance, block, &dict_attack_ctx->current_key, MfClassicKeyTypeB, NULL);
|
instance, block, &dict_attack_ctx->current_key, MfClassicKeyTypeB, NULL);
|
||||||
if(error == MfClassicErrorNone) {
|
if(error == MfClassicErrorNone) {
|
||||||
FURI_LOG_I(TAG, "Key B found");
|
FURI_LOG_I(TAG, "Key B found");
|
||||||
@ -584,7 +584,7 @@ NfcCommand mf_classic_poller_handler_auth_b(MfClassicPoller* instance) {
|
|||||||
dict_attack_ctx->auth_passed = true;
|
dict_attack_ctx->auth_passed = true;
|
||||||
instance->state = MfClassicPollerStateReadSector;
|
instance->state = MfClassicPollerStateReadSector;
|
||||||
} else {
|
} else {
|
||||||
mf_classic_async_halt(instance);
|
mf_classic_poller_halt(instance);
|
||||||
instance->state = MfClassicPollerStateRequestKey;
|
instance->state = MfClassicPollerStateRequestKey;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -621,7 +621,7 @@ NfcCommand mf_classic_poller_handler_read_sector(MfClassicPoller* instance) {
|
|||||||
if(mf_classic_is_block_read(instance->data, block_num)) break;
|
if(mf_classic_is_block_read(instance->data, block_num)) break;
|
||||||
|
|
||||||
if(!dict_attack_ctx->auth_passed) {
|
if(!dict_attack_ctx->auth_passed) {
|
||||||
error = mf_classic_async_auth(
|
error = mf_classic_poller_auth(
|
||||||
instance,
|
instance,
|
||||||
block_num,
|
block_num,
|
||||||
&dict_attack_ctx->current_key,
|
&dict_attack_ctx->current_key,
|
||||||
@ -635,10 +635,10 @@ NfcCommand mf_classic_poller_handler_read_sector(MfClassicPoller* instance) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FURI_LOG_D(TAG, "Reading block %d", block_num);
|
FURI_LOG_D(TAG, "Reading block %d", block_num);
|
||||||
error = mf_classic_async_read_block(instance, block_num, &block);
|
error = mf_classic_poller_read_block(instance, block_num, &block);
|
||||||
|
|
||||||
if(error != MfClassicErrorNone) {
|
if(error != MfClassicErrorNone) {
|
||||||
mf_classic_async_halt(instance);
|
mf_classic_poller_halt(instance);
|
||||||
dict_attack_ctx->auth_passed = false;
|
dict_attack_ctx->auth_passed = false;
|
||||||
FURI_LOG_D(TAG, "Failed to read block %d", block_num);
|
FURI_LOG_D(TAG, "Failed to read block %d", block_num);
|
||||||
} else {
|
} else {
|
||||||
@ -655,7 +655,7 @@ NfcCommand mf_classic_poller_handler_read_sector(MfClassicPoller* instance) {
|
|||||||
if(dict_attack_ctx->current_block > sec_tr_block_num) {
|
if(dict_attack_ctx->current_block > sec_tr_block_num) {
|
||||||
mf_classic_poller_handle_data_update(instance);
|
mf_classic_poller_handle_data_update(instance);
|
||||||
|
|
||||||
mf_classic_async_halt(instance);
|
mf_classic_poller_halt(instance);
|
||||||
dict_attack_ctx->auth_passed = false;
|
dict_attack_ctx->auth_passed = false;
|
||||||
|
|
||||||
if(dict_attack_ctx->current_sector == instance->sectors_total) {
|
if(dict_attack_ctx->current_sector == instance->sectors_total) {
|
||||||
@ -713,7 +713,7 @@ NfcCommand mf_classic_poller_handler_key_reuse_auth_key_a(MfClassicPoller* insta
|
|||||||
uint64_t key = nfc_util_bytes2num(dict_attack_ctx->current_key.data, sizeof(MfClassicKey));
|
uint64_t key = nfc_util_bytes2num(dict_attack_ctx->current_key.data, sizeof(MfClassicKey));
|
||||||
FURI_LOG_D(TAG, "Key attack auth to block %d with key A: %06llx", block, key);
|
FURI_LOG_D(TAG, "Key attack auth to block %d with key A: %06llx", block, key);
|
||||||
|
|
||||||
MfClassicError error = mf_classic_async_auth(
|
MfClassicError error = mf_classic_poller_auth(
|
||||||
instance, block, &dict_attack_ctx->current_key, MfClassicKeyTypeA, NULL);
|
instance, block, &dict_attack_ctx->current_key, MfClassicKeyTypeA, NULL);
|
||||||
if(error == MfClassicErrorNone) {
|
if(error == MfClassicErrorNone) {
|
||||||
FURI_LOG_I(TAG, "Key A found");
|
FURI_LOG_I(TAG, "Key A found");
|
||||||
@ -726,7 +726,7 @@ NfcCommand mf_classic_poller_handler_key_reuse_auth_key_a(MfClassicPoller* insta
|
|||||||
dict_attack_ctx->auth_passed = true;
|
dict_attack_ctx->auth_passed = true;
|
||||||
instance->state = MfClassicPollerStateKeyReuseReadSector;
|
instance->state = MfClassicPollerStateKeyReuseReadSector;
|
||||||
} else {
|
} else {
|
||||||
mf_classic_async_halt(instance);
|
mf_classic_poller_halt(instance);
|
||||||
dict_attack_ctx->auth_passed = false;
|
dict_attack_ctx->auth_passed = false;
|
||||||
instance->state = MfClassicPollerStateKeyReuseStart;
|
instance->state = MfClassicPollerStateKeyReuseStart;
|
||||||
}
|
}
|
||||||
@ -748,7 +748,7 @@ NfcCommand mf_classic_poller_handler_key_reuse_auth_key_b(MfClassicPoller* insta
|
|||||||
uint64_t key = nfc_util_bytes2num(dict_attack_ctx->current_key.data, sizeof(MfClassicKey));
|
uint64_t key = nfc_util_bytes2num(dict_attack_ctx->current_key.data, sizeof(MfClassicKey));
|
||||||
FURI_LOG_D(TAG, "Key attack auth to block %d with key B: %06llx", block, key);
|
FURI_LOG_D(TAG, "Key attack auth to block %d with key B: %06llx", block, key);
|
||||||
|
|
||||||
MfClassicError error = mf_classic_async_auth(
|
MfClassicError error = mf_classic_poller_auth(
|
||||||
instance, block, &dict_attack_ctx->current_key, MfClassicKeyTypeB, NULL);
|
instance, block, &dict_attack_ctx->current_key, MfClassicKeyTypeB, NULL);
|
||||||
if(error == MfClassicErrorNone) {
|
if(error == MfClassicErrorNone) {
|
||||||
FURI_LOG_I(TAG, "Key B found");
|
FURI_LOG_I(TAG, "Key B found");
|
||||||
@ -762,7 +762,7 @@ NfcCommand mf_classic_poller_handler_key_reuse_auth_key_b(MfClassicPoller* insta
|
|||||||
dict_attack_ctx->auth_passed = true;
|
dict_attack_ctx->auth_passed = true;
|
||||||
instance->state = MfClassicPollerStateKeyReuseReadSector;
|
instance->state = MfClassicPollerStateKeyReuseReadSector;
|
||||||
} else {
|
} else {
|
||||||
mf_classic_async_halt(instance);
|
mf_classic_poller_halt(instance);
|
||||||
dict_attack_ctx->auth_passed = false;
|
dict_attack_ctx->auth_passed = false;
|
||||||
instance->state = MfClassicPollerStateKeyReuseStart;
|
instance->state = MfClassicPollerStateKeyReuseStart;
|
||||||
}
|
}
|
||||||
@ -783,7 +783,7 @@ NfcCommand mf_classic_poller_handler_key_reuse_read_sector(MfClassicPoller* inst
|
|||||||
if(mf_classic_is_block_read(instance->data, block_num)) break;
|
if(mf_classic_is_block_read(instance->data, block_num)) break;
|
||||||
|
|
||||||
if(!dict_attack_ctx->auth_passed) {
|
if(!dict_attack_ctx->auth_passed) {
|
||||||
error = mf_classic_async_auth(
|
error = mf_classic_poller_auth(
|
||||||
instance,
|
instance,
|
||||||
block_num,
|
block_num,
|
||||||
&dict_attack_ctx->current_key,
|
&dict_attack_ctx->current_key,
|
||||||
@ -796,10 +796,10 @@ NfcCommand mf_classic_poller_handler_key_reuse_read_sector(MfClassicPoller* inst
|
|||||||
}
|
}
|
||||||
|
|
||||||
FURI_LOG_D(TAG, "Reading block %d", block_num);
|
FURI_LOG_D(TAG, "Reading block %d", block_num);
|
||||||
error = mf_classic_async_read_block(instance, block_num, &block);
|
error = mf_classic_poller_read_block(instance, block_num, &block);
|
||||||
|
|
||||||
if(error != MfClassicErrorNone) {
|
if(error != MfClassicErrorNone) {
|
||||||
mf_classic_async_halt(instance);
|
mf_classic_poller_halt(instance);
|
||||||
dict_attack_ctx->auth_passed = false;
|
dict_attack_ctx->auth_passed = false;
|
||||||
FURI_LOG_D(TAG, "Failed to read block %d", block_num);
|
FURI_LOG_D(TAG, "Failed to read block %d", block_num);
|
||||||
} else {
|
} else {
|
||||||
@ -814,7 +814,7 @@ NfcCommand mf_classic_poller_handler_key_reuse_read_sector(MfClassicPoller* inst
|
|||||||
mf_classic_get_sector_trailer_num_by_sector(dict_attack_ctx->reuse_key_sector);
|
mf_classic_get_sector_trailer_num_by_sector(dict_attack_ctx->reuse_key_sector);
|
||||||
dict_attack_ctx->current_block++;
|
dict_attack_ctx->current_block++;
|
||||||
if(dict_attack_ctx->current_block > sec_tr_block_num) {
|
if(dict_attack_ctx->current_block > sec_tr_block_num) {
|
||||||
mf_classic_async_halt(instance);
|
mf_classic_poller_halt(instance);
|
||||||
dict_attack_ctx->auth_passed = false;
|
dict_attack_ctx->auth_passed = false;
|
||||||
|
|
||||||
mf_classic_poller_handle_data_update(instance);
|
mf_classic_poller_handle_data_update(instance);
|
||||||
|
@ -7,103 +7,274 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief MfClassicPoller opaque type definition.
|
||||||
|
*/
|
||||||
typedef struct MfClassicPoller MfClassicPoller;
|
typedef struct MfClassicPoller MfClassicPoller;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enumeration of possible MfClassic poller event types.
|
||||||
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
// Start event
|
MfClassicPollerEventTypeRequestMode, /**< Poller requests to fill the mode. */
|
||||||
MfClassicPollerEventTypeRequestMode,
|
|
||||||
|
|
||||||
// Read with key cache events
|
MfClassicPollerEventTypeRequestReadSector, /**< Poller requests data to read sector. */
|
||||||
MfClassicPollerEventTypeRequestReadSector,
|
|
||||||
|
|
||||||
// Write events
|
MfClassicPollerEventTypeRequestSectorTrailer, /**< Poller requests sector trailer for writing block. */
|
||||||
MfClassicPollerEventTypeRequestSectorTrailer,
|
MfClassicPollerEventTypeRequestWriteBlock, /**< Poller requests data to write block. */
|
||||||
MfClassicPollerEventTypeRequestWriteBlock,
|
|
||||||
|
|
||||||
// Dictionary attack events
|
MfClassicPollerEventTypeRequestKey, /**< Poller requests key for sector authentication. */
|
||||||
MfClassicPollerEventTypeRequestKey,
|
MfClassicPollerEventTypeNextSector, /**< Poller switches to next sector during dictionary attack. */
|
||||||
MfClassicPollerEventTypeNextSector,
|
MfClassicPollerEventTypeDataUpdate, /**< Poller updates data. */
|
||||||
MfClassicPollerEventTypeDataUpdate,
|
MfClassicPollerEventTypeFoundKeyA, /**< Poller found key A. */
|
||||||
MfClassicPollerEventTypeFoundKeyA,
|
MfClassicPollerEventTypeFoundKeyB, /**< Poller found key B. */
|
||||||
MfClassicPollerEventTypeFoundKeyB,
|
MfClassicPollerEventTypeKeyAttackStart, /**< Poller starts key attack. */
|
||||||
MfClassicPollerEventTypeCardNotDetected,
|
MfClassicPollerEventTypeKeyAttackStop, /**< Poller stops key attack. */
|
||||||
MfClassicPollerEventTypeKeyAttackStart,
|
MfClassicPollerEventTypeKeyAttackNextSector, /**< Poller switches to next sector during key attack. */
|
||||||
MfClassicPollerEventTypeKeyAttackStop,
|
|
||||||
MfClassicPollerEventTypeKeyAttackNextSector,
|
|
||||||
|
|
||||||
// Common events
|
MfClassicPollerEventTypeCardDetected, /**< Poller detected card. */
|
||||||
MfClassicPollerEventTypeCardDetected,
|
MfClassicPollerEventTypeCardLost, /**< Poller lost card. */
|
||||||
MfClassicPollerEventTypeCardLost,
|
MfClassicPollerEventTypeSuccess, /**< Poller succeeded. */
|
||||||
MfClassicPollerEventTypeSuccess,
|
MfClassicPollerEventTypeFail, /**< Poller failed. */
|
||||||
MfClassicPollerEventTypeFail,
|
|
||||||
} MfClassicPollerEventType;
|
} MfClassicPollerEventType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief MfClassic poller mode.
|
||||||
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
MfClassicPollerModeRead,
|
MfClassicPollerModeRead, /**< Poller reading mode. */
|
||||||
MfClassicPollerModeWrite,
|
MfClassicPollerModeWrite, /**< Poller writing mode. */
|
||||||
MfClassicPollerModeDictAttack,
|
MfClassicPollerModeDictAttack, /**< Poller dictionary attack mode. */
|
||||||
} MfClassicPollerMode;
|
} MfClassicPollerMode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief MfClassic poller request mode event data.
|
||||||
|
*
|
||||||
|
* This instance of this structure must be filled on MfClassicPollerEventTypeRequestMode event.
|
||||||
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
MfClassicPollerMode mode;
|
MfClassicPollerMode mode; /**< Mode to be used by poller. */
|
||||||
const MfClassicData* data;
|
const MfClassicData* data; /**< Data to be used by poller. */
|
||||||
} MfClassicPollerEventDataRequestMode;
|
} MfClassicPollerEventDataRequestMode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief MfClassic poller next sector event data.
|
||||||
|
*
|
||||||
|
* The instance of this structure is filled by poller and passed with
|
||||||
|
* MfClassicPollerEventTypeNextSector event.
|
||||||
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t current_sector;
|
uint8_t current_sector; /**< Current sector number. */
|
||||||
} MfClassicPollerEventDataDictAttackNextSector;
|
} MfClassicPollerEventDataDictAttackNextSector;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief MfClassic poller update event data.
|
||||||
|
*
|
||||||
|
* The instance of this structure is filled by poller and passed with
|
||||||
|
* MfClassicPollerEventTypeDataUpdate event.
|
||||||
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t sectors_read;
|
uint8_t sectors_read; /**< Number of sectors read. */
|
||||||
uint8_t keys_found;
|
uint8_t keys_found; /**< Number of keys found. */
|
||||||
uint8_t current_sector;
|
uint8_t current_sector; /**< Current sector number. */
|
||||||
} MfClassicPollerEventDataUpdate;
|
} MfClassicPollerEventDataUpdate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief MfClassic poller key request event data.
|
||||||
|
*
|
||||||
|
* The instance of this structure must be filled on MfClassicPollerEventTypeRequestKey event.
|
||||||
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
MfClassicKey key;
|
MfClassicKey key; /**< Key to be used by poller. */
|
||||||
bool key_provided;
|
bool key_provided; /**< Flag indicating if key is provided. */
|
||||||
} MfClassicPollerEventDataKeyRequest;
|
} MfClassicPollerEventDataKeyRequest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief MfClassic poller read sector request event data.
|
||||||
|
*
|
||||||
|
* The instance of this structure must be filled on MfClassicPollerEventTypeRequestReadSector event.
|
||||||
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t sector_num;
|
uint8_t sector_num; /**< Sector number to be read. */
|
||||||
MfClassicKey key;
|
MfClassicKey key; /**< Key to be used by poller. */
|
||||||
MfClassicKeyType key_type;
|
MfClassicKeyType key_type; /**< Key type to be used by poller. */
|
||||||
bool key_provided;
|
bool key_provided; /**< Flag indicating if key is provided. */
|
||||||
} MfClassicPollerEventDataReadSectorRequest;
|
} MfClassicPollerEventDataReadSectorRequest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief MfClassic poller sector trailer request event data.
|
||||||
|
*
|
||||||
|
* The instance of this structure must be filled on MfClassicPollerEventTypeRequestSectorTrailer event.
|
||||||
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t sector_num;
|
uint8_t sector_num; /**< Sector number to be read. */
|
||||||
MfClassicBlock sector_trailer;
|
MfClassicBlock sector_trailer; /**< Sector trailer to be used by poller. */
|
||||||
bool sector_trailer_provided;
|
bool sector_trailer_provided; /**< Flag indicating if sector trailer is provided. */
|
||||||
} MfClassicPollerEventDataSectorTrailerRequest;
|
} MfClassicPollerEventDataSectorTrailerRequest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief MfClassic poller write block request event data.
|
||||||
|
*
|
||||||
|
* The instance of this structure must be filled on MfClassicPollerEventTypeRequestWriteBlock event.
|
||||||
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t block_num;
|
uint8_t block_num; /**< Block number to be written. */
|
||||||
MfClassicBlock write_block;
|
MfClassicBlock write_block; /**< Block to be written. */
|
||||||
bool write_block_provided;
|
bool write_block_provided; /**< Flag indicating if block is provided. */
|
||||||
} MfClassicPollerEventDataWriteBlockRequest;
|
} MfClassicPollerEventDataWriteBlockRequest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief MfClassic poller key attack event data.
|
||||||
|
*
|
||||||
|
* The instance of this structure is filled by poller and passed with
|
||||||
|
* MfClassicPollerEventTypeKeyAttackNextSector event.
|
||||||
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t current_sector;
|
uint8_t current_sector; /**< Current sector number. */
|
||||||
} MfClassicPollerEventKeyAttackData;
|
} MfClassicPollerEventKeyAttackData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief MfClassic poller event data.
|
||||||
|
*/
|
||||||
typedef union {
|
typedef union {
|
||||||
MfClassicError error;
|
MfClassicError error; /**< Error code on MfClassicPollerEventTypeFail event. */
|
||||||
MfClassicPollerEventDataRequestMode poller_mode;
|
MfClassicPollerEventDataRequestMode poller_mode; /**< Poller mode context. */
|
||||||
MfClassicPollerEventDataDictAttackNextSector next_sector_data;
|
MfClassicPollerEventDataDictAttackNextSector next_sector_data; /**< Next sector context. */
|
||||||
MfClassicPollerEventDataKeyRequest key_request_data;
|
MfClassicPollerEventDataKeyRequest key_request_data; /**< Key request context. */
|
||||||
MfClassicPollerEventDataUpdate data_update;
|
MfClassicPollerEventDataUpdate data_update; /**< Data update context. */
|
||||||
MfClassicPollerEventDataReadSectorRequest read_sector_request_data;
|
MfClassicPollerEventDataReadSectorRequest
|
||||||
MfClassicPollerEventKeyAttackData key_attack_data;
|
read_sector_request_data; /**< Read sector request context. */
|
||||||
MfClassicPollerEventDataSectorTrailerRequest sec_tr_data;
|
MfClassicPollerEventKeyAttackData key_attack_data; /**< Key attack context. */
|
||||||
MfClassicPollerEventDataWriteBlockRequest write_block_data;
|
MfClassicPollerEventDataSectorTrailerRequest sec_tr_data; /**< Sector trailer request context. */
|
||||||
|
MfClassicPollerEventDataWriteBlockRequest write_block_data; /**< Write block request context. */
|
||||||
} MfClassicPollerEventData;
|
} MfClassicPollerEventData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief MfClassic poller event.
|
||||||
|
*
|
||||||
|
* Upon emission of an event, an instance of this struct will be passed to the callback.
|
||||||
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
MfClassicPollerEventType type;
|
MfClassicPollerEventType type; /**< Event type. */
|
||||||
MfClassicPollerEventData* data;
|
MfClassicPollerEventData* data; /**< Pointer to event specific data. */
|
||||||
} MfClassicPollerEvent;
|
} MfClassicPollerEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Collect tag nonce during authentication.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* Starts authentication procedure and collects tag nonce.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @param[in] block_num block number for authentication.
|
||||||
|
* @param[in] key_type key type to be used for authentication.
|
||||||
|
* @param[out] nt pointer to the MfClassicNt structure to be filled with nonce data.
|
||||||
|
* @return MfClassicErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
MfClassicError mf_classic_poller_get_nt(
|
||||||
|
MfClassicPoller* instance,
|
||||||
|
uint8_t block_num,
|
||||||
|
MfClassicKeyType key_type,
|
||||||
|
MfClassicNt* nt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Perform authentication.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* Perform authentication as specified in Mf Classic protocol. Initialize crypto state for futher
|
||||||
|
* communication with the tag.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @param[in] block_num block number for authentication.
|
||||||
|
* @param[in] key key to be used for authentication.
|
||||||
|
* @param[in] key_type key type to be used for authentication.
|
||||||
|
* @param[out] data pointer to MfClassicAuthContext structure to be filled with authentication data.
|
||||||
|
* @return MfClassicErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
MfClassicError mf_classic_poller_auth(
|
||||||
|
MfClassicPoller* instance,
|
||||||
|
uint8_t block_num,
|
||||||
|
MfClassicKey* key,
|
||||||
|
MfClassicKeyType key_type,
|
||||||
|
MfClassicAuthContext* data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Halt the tag.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* Halt the tag and reset crypto state of the poller.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @return MfClassicErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
MfClassicError mf_classic_poller_halt(MfClassicPoller* instance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read block from tag.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @param[in] block_num block number to be read.
|
||||||
|
* @param[out] data pointer to the MfClassicBlock structure to be filled with block data.
|
||||||
|
* @return MfClassicErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
MfClassicError mf_classic_poller_read_block(
|
||||||
|
MfClassicPoller* instance,
|
||||||
|
uint8_t block_num,
|
||||||
|
MfClassicBlock* data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Write block to tag.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @param[in] block_num block number to be written.
|
||||||
|
* @param[in] data pointer to the MfClassicBlock structure to be written.
|
||||||
|
* @return MfClassicErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
MfClassicError mf_classic_poller_write_block(
|
||||||
|
MfClassicPoller* instance,
|
||||||
|
uint8_t block_num,
|
||||||
|
MfClassicBlock* data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Perform value command on tag.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* Perform Increment, Decrement or Restore command on tag. The result is stored in internal transfer
|
||||||
|
* block of the tag. Use mf_classic_poller_value_transfer to transfer the result to the tag.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @param[in] block_num block number to be used for value command.
|
||||||
|
* @param[in] cmd value command to be performed.
|
||||||
|
* @param[in] data value to be used for value command.
|
||||||
|
* @return MfClassicErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
MfClassicError mf_classic_poller_value_cmd(
|
||||||
|
MfClassicPoller* instance,
|
||||||
|
uint8_t block_num,
|
||||||
|
MfClassicValueCommand cmd,
|
||||||
|
int32_t data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Transfer internal transfer block to tag.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* Transfer internal transfer block to tag. The block is filled by mf_classic_poller_value_cmd.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @param[in] block_num block number to be used for value command.
|
||||||
|
* @return MfClassicErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
MfClassicError mf_classic_poller_value_transfer(MfClassicPoller* instance, uint8_t block_num);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -33,7 +33,7 @@ MfClassicError mf_classic_process_error(Iso14443_3aError error) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
MfClassicError mf_classic_async_get_nt(
|
MfClassicError mf_classic_poller_get_nt(
|
||||||
MfClassicPoller* instance,
|
MfClassicPoller* instance,
|
||||||
uint8_t block_num,
|
uint8_t block_num,
|
||||||
MfClassicKeyType key_type,
|
MfClassicKeyType key_type,
|
||||||
@ -69,7 +69,7 @@ MfClassicError mf_classic_async_get_nt(
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
MfClassicError mf_classic_async_auth(
|
MfClassicError mf_classic_poller_auth(
|
||||||
MfClassicPoller* instance,
|
MfClassicPoller* instance,
|
||||||
uint8_t block_num,
|
uint8_t block_num,
|
||||||
MfClassicKey* key,
|
MfClassicKey* key,
|
||||||
@ -84,7 +84,7 @@ MfClassicError mf_classic_async_auth(
|
|||||||
iso14443_3a_poller_get_data(instance->iso14443_3a_poller));
|
iso14443_3a_poller_get_data(instance->iso14443_3a_poller));
|
||||||
|
|
||||||
MfClassicNt nt = {};
|
MfClassicNt nt = {};
|
||||||
ret = mf_classic_async_get_nt(instance, block_num, key_type, &nt);
|
ret = mf_classic_poller_get_nt(instance, block_num, key_type, &nt);
|
||||||
if(ret != MfClassicErrorNone) break;
|
if(ret != MfClassicErrorNone) break;
|
||||||
if(data) {
|
if(data) {
|
||||||
data->nt = nt;
|
data->nt = nt;
|
||||||
@ -130,7 +130,7 @@ MfClassicError mf_classic_async_auth(
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
MfClassicError mf_classic_async_halt(MfClassicPoller* instance) {
|
MfClassicError mf_classic_poller_halt(MfClassicPoller* instance) {
|
||||||
MfClassicError ret = MfClassicErrorNone;
|
MfClassicError ret = MfClassicErrorNone;
|
||||||
Iso14443_3aError error = Iso14443_3aErrorNone;
|
Iso14443_3aError error = Iso14443_3aErrorNone;
|
||||||
|
|
||||||
@ -158,7 +158,7 @@ MfClassicError mf_classic_async_halt(MfClassicPoller* instance) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
MfClassicError mf_classic_async_read_block(
|
MfClassicError mf_classic_poller_read_block(
|
||||||
MfClassicPoller* instance,
|
MfClassicPoller* instance,
|
||||||
uint8_t block_num,
|
uint8_t block_num,
|
||||||
MfClassicBlock* data) {
|
MfClassicBlock* data) {
|
||||||
@ -204,7 +204,7 @@ MfClassicError mf_classic_async_read_block(
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
MfClassicError mf_classic_async_write_block(
|
MfClassicError mf_classic_poller_write_block(
|
||||||
MfClassicPoller* instance,
|
MfClassicPoller* instance,
|
||||||
uint8_t block_num,
|
uint8_t block_num,
|
||||||
MfClassicBlock* data) {
|
MfClassicBlock* data) {
|
||||||
@ -275,7 +275,7 @@ MfClassicError mf_classic_async_write_block(
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
MfClassicError mf_classic_async_value_cmd(
|
MfClassicError mf_classic_poller_value_cmd(
|
||||||
MfClassicPoller* instance,
|
MfClassicPoller* instance,
|
||||||
uint8_t block_num,
|
uint8_t block_num,
|
||||||
MfClassicValueCommand cmd,
|
MfClassicValueCommand cmd,
|
||||||
@ -345,7 +345,7 @@ MfClassicError mf_classic_async_value_cmd(
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
MfClassicError mf_classic_async_value_transfer(MfClassicPoller* instance, uint8_t block_num) {
|
MfClassicError mf_classic_poller_value_transfer(MfClassicPoller* instance, uint8_t block_num) {
|
||||||
MfClassicError ret = MfClassicErrorNone;
|
MfClassicError ret = MfClassicErrorNone;
|
||||||
Iso14443_3aError error = Iso14443_3aErrorNone;
|
Iso14443_3aError error = Iso14443_3aErrorNone;
|
||||||
|
|
||||||
|
@ -169,37 +169,6 @@ MfClassicPoller* mf_classic_poller_alloc(Iso14443_3aPoller* iso14443_3a_poller);
|
|||||||
|
|
||||||
void mf_classic_poller_free(MfClassicPoller* instance);
|
void mf_classic_poller_free(MfClassicPoller* instance);
|
||||||
|
|
||||||
MfClassicError mf_classic_async_get_nt(
|
|
||||||
MfClassicPoller* instance,
|
|
||||||
uint8_t block_num,
|
|
||||||
MfClassicKeyType key_type,
|
|
||||||
MfClassicNt* nt);
|
|
||||||
|
|
||||||
MfClassicError mf_classic_async_auth(
|
|
||||||
MfClassicPoller* instance,
|
|
||||||
uint8_t block_num,
|
|
||||||
MfClassicKey* key,
|
|
||||||
MfClassicKeyType key_type,
|
|
||||||
MfClassicAuthContext* data);
|
|
||||||
|
|
||||||
MfClassicError mf_classic_async_halt(MfClassicPoller* instance);
|
|
||||||
|
|
||||||
MfClassicError
|
|
||||||
mf_classic_async_read_block(MfClassicPoller* instance, uint8_t block_num, MfClassicBlock* data);
|
|
||||||
|
|
||||||
MfClassicError mf_classic_async_write_block(
|
|
||||||
MfClassicPoller* instance,
|
|
||||||
uint8_t block_num,
|
|
||||||
MfClassicBlock* data);
|
|
||||||
|
|
||||||
MfClassicError mf_classic_async_value_cmd(
|
|
||||||
MfClassicPoller* instance,
|
|
||||||
uint8_t block_num,
|
|
||||||
MfClassicValueCommand cmd,
|
|
||||||
int32_t data);
|
|
||||||
|
|
||||||
MfClassicError mf_classic_async_value_transfer(MfClassicPoller* instance, uint8_t block_num);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
#include "mf_classic_poller_sync.h"
|
||||||
#include "mf_classic_poller_i.h"
|
#include "mf_classic_poller_i.h"
|
||||||
|
|
||||||
#include <nfc/nfc_poller.h>
|
#include <nfc/nfc_poller.h>
|
||||||
@ -32,7 +33,7 @@ typedef MfClassicError (
|
|||||||
static MfClassicError mf_classic_poller_collect_nt_handler(
|
static MfClassicError mf_classic_poller_collect_nt_handler(
|
||||||
MfClassicPoller* poller,
|
MfClassicPoller* poller,
|
||||||
MfClassicPollerContextData* data) {
|
MfClassicPollerContextData* data) {
|
||||||
return mf_classic_async_get_nt(
|
return mf_classic_poller_get_nt(
|
||||||
poller,
|
poller,
|
||||||
data->collect_nt_context.block,
|
data->collect_nt_context.block,
|
||||||
data->collect_nt_context.key_type,
|
data->collect_nt_context.key_type,
|
||||||
@ -41,7 +42,7 @@ static MfClassicError mf_classic_poller_collect_nt_handler(
|
|||||||
|
|
||||||
static MfClassicError
|
static MfClassicError
|
||||||
mf_classic_poller_auth_handler(MfClassicPoller* poller, MfClassicPollerContextData* data) {
|
mf_classic_poller_auth_handler(MfClassicPoller* poller, MfClassicPollerContextData* data) {
|
||||||
return mf_classic_async_auth(
|
return mf_classic_poller_auth(
|
||||||
poller,
|
poller,
|
||||||
data->auth_context.block_num,
|
data->auth_context.block_num,
|
||||||
&data->auth_context.key,
|
&data->auth_context.key,
|
||||||
@ -55,7 +56,7 @@ static MfClassicError mf_classic_poller_read_block_handler(
|
|||||||
MfClassicError error = MfClassicErrorNone;
|
MfClassicError error = MfClassicErrorNone;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
error = mf_classic_async_auth(
|
error = mf_classic_poller_auth(
|
||||||
poller,
|
poller,
|
||||||
data->read_block_context.block_num,
|
data->read_block_context.block_num,
|
||||||
&data->read_block_context.key,
|
&data->read_block_context.key,
|
||||||
@ -63,11 +64,11 @@ static MfClassicError mf_classic_poller_read_block_handler(
|
|||||||
NULL);
|
NULL);
|
||||||
if(error != MfClassicErrorNone) break;
|
if(error != MfClassicErrorNone) break;
|
||||||
|
|
||||||
error = mf_classic_async_read_block(
|
error = mf_classic_poller_read_block(
|
||||||
poller, data->read_block_context.block_num, &data->read_block_context.block);
|
poller, data->read_block_context.block_num, &data->read_block_context.block);
|
||||||
if(error != MfClassicErrorNone) break;
|
if(error != MfClassicErrorNone) break;
|
||||||
|
|
||||||
error = mf_classic_async_halt(poller);
|
error = mf_classic_poller_halt(poller);
|
||||||
if(error != MfClassicErrorNone) break;
|
if(error != MfClassicErrorNone) break;
|
||||||
|
|
||||||
} while(false);
|
} while(false);
|
||||||
@ -81,7 +82,7 @@ static MfClassicError mf_classic_poller_write_block_handler(
|
|||||||
MfClassicError error = MfClassicErrorNone;
|
MfClassicError error = MfClassicErrorNone;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
error = mf_classic_async_auth(
|
error = mf_classic_poller_auth(
|
||||||
poller,
|
poller,
|
||||||
data->read_block_context.block_num,
|
data->read_block_context.block_num,
|
||||||
&data->read_block_context.key,
|
&data->read_block_context.key,
|
||||||
@ -89,11 +90,11 @@ static MfClassicError mf_classic_poller_write_block_handler(
|
|||||||
NULL);
|
NULL);
|
||||||
if(error != MfClassicErrorNone) break;
|
if(error != MfClassicErrorNone) break;
|
||||||
|
|
||||||
error = mf_classic_async_write_block(
|
error = mf_classic_poller_write_block(
|
||||||
poller, data->write_block_context.block_num, &data->write_block_context.block);
|
poller, data->write_block_context.block_num, &data->write_block_context.block);
|
||||||
if(error != MfClassicErrorNone) break;
|
if(error != MfClassicErrorNone) break;
|
||||||
|
|
||||||
error = mf_classic_async_halt(poller);
|
error = mf_classic_poller_halt(poller);
|
||||||
if(error != MfClassicErrorNone) break;
|
if(error != MfClassicErrorNone) break;
|
||||||
|
|
||||||
} while(false);
|
} while(false);
|
||||||
@ -107,7 +108,7 @@ static MfClassicError mf_classic_poller_read_value_handler(
|
|||||||
MfClassicError error = MfClassicErrorNone;
|
MfClassicError error = MfClassicErrorNone;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
error = mf_classic_async_auth(
|
error = mf_classic_poller_auth(
|
||||||
poller,
|
poller,
|
||||||
data->read_value_context.block_num,
|
data->read_value_context.block_num,
|
||||||
&data->read_value_context.key,
|
&data->read_value_context.key,
|
||||||
@ -116,7 +117,7 @@ static MfClassicError mf_classic_poller_read_value_handler(
|
|||||||
if(error != MfClassicErrorNone) break;
|
if(error != MfClassicErrorNone) break;
|
||||||
|
|
||||||
MfClassicBlock block = {};
|
MfClassicBlock block = {};
|
||||||
error = mf_classic_async_read_block(poller, data->read_value_context.block_num, &block);
|
error = mf_classic_poller_read_block(poller, data->read_value_context.block_num, &block);
|
||||||
if(error != MfClassicErrorNone) break;
|
if(error != MfClassicErrorNone) break;
|
||||||
|
|
||||||
if(!mf_classic_block_to_value(&block, &data->read_value_context.value, NULL)) {
|
if(!mf_classic_block_to_value(&block, &data->read_value_context.value, NULL)) {
|
||||||
@ -124,7 +125,7 @@ static MfClassicError mf_classic_poller_read_value_handler(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
error = mf_classic_async_halt(poller);
|
error = mf_classic_poller_halt(poller);
|
||||||
if(error != MfClassicErrorNone) break;
|
if(error != MfClassicErrorNone) break;
|
||||||
|
|
||||||
} while(false);
|
} while(false);
|
||||||
@ -138,7 +139,7 @@ static MfClassicError mf_classic_poller_change_value_handler(
|
|||||||
MfClassicError error = MfClassicErrorNone;
|
MfClassicError error = MfClassicErrorNone;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
error = mf_classic_async_auth(
|
error = mf_classic_poller_auth(
|
||||||
poller,
|
poller,
|
||||||
data->change_value_context.block_num,
|
data->change_value_context.block_num,
|
||||||
&data->change_value_context.key,
|
&data->change_value_context.key,
|
||||||
@ -146,21 +147,21 @@ static MfClassicError mf_classic_poller_change_value_handler(
|
|||||||
NULL);
|
NULL);
|
||||||
if(error != MfClassicErrorNone) break;
|
if(error != MfClassicErrorNone) break;
|
||||||
|
|
||||||
error = mf_classic_async_value_cmd(
|
error = mf_classic_poller_value_cmd(
|
||||||
poller,
|
poller,
|
||||||
data->change_value_context.block_num,
|
data->change_value_context.block_num,
|
||||||
data->change_value_context.value_cmd,
|
data->change_value_context.value_cmd,
|
||||||
data->change_value_context.data);
|
data->change_value_context.data);
|
||||||
if(error != MfClassicErrorNone) break;
|
if(error != MfClassicErrorNone) break;
|
||||||
|
|
||||||
error = mf_classic_async_value_transfer(poller, data->change_value_context.block_num);
|
error = mf_classic_poller_value_transfer(poller, data->change_value_context.block_num);
|
||||||
if(error != MfClassicErrorNone) break;
|
if(error != MfClassicErrorNone) break;
|
||||||
|
|
||||||
MfClassicBlock block = {};
|
MfClassicBlock block = {};
|
||||||
error = mf_classic_async_read_block(poller, data->change_value_context.block_num, &block);
|
error = mf_classic_poller_read_block(poller, data->change_value_context.block_num, &block);
|
||||||
if(error != MfClassicErrorNone) break;
|
if(error != MfClassicErrorNone) break;
|
||||||
|
|
||||||
error = mf_classic_async_halt(poller);
|
error = mf_classic_poller_halt(poller);
|
||||||
if(error != MfClassicErrorNone) break;
|
if(error != MfClassicErrorNone) break;
|
||||||
|
|
||||||
if(!mf_classic_block_to_value(&block, &data->change_value_context.new_value, NULL)) {
|
if(!mf_classic_block_to_value(&block, &data->change_value_context.new_value, NULL)) {
|
||||||
@ -182,16 +183,14 @@ static const MfClassicPollerCmdHandler mf_classic_poller_cmd_handlers[MfClassicP
|
|||||||
[MfClassicPollerCmdTypeChangeValue] = mf_classic_poller_change_value_handler,
|
[MfClassicPollerCmdTypeChangeValue] = mf_classic_poller_change_value_handler,
|
||||||
};
|
};
|
||||||
|
|
||||||
static NfcCommand mf_classic_poller_cmd_callback(NfcGenericEvent event, void* context) {
|
static NfcCommand mf_classic_poller_cmd_callback(NfcGenericEventEx event, void* context) {
|
||||||
furi_assert(event.instance);
|
furi_assert(event.poller);
|
||||||
furi_assert(event.protocol == NfcProtocolIso14443_3a);
|
furi_assert(event.parent_event_data);
|
||||||
furi_assert(event.event_data);
|
|
||||||
furi_assert(context);
|
furi_assert(context);
|
||||||
|
|
||||||
MfClassicPollerContext* poller_context = context;
|
MfClassicPollerContext* poller_context = context;
|
||||||
Iso14443_3aPollerEvent* iso14443_3a_event = event.event_data;
|
Iso14443_3aPollerEvent* iso14443_3a_event = event.parent_event_data;
|
||||||
Iso14443_3aPoller* iso14443_3a_poller = event.instance;
|
MfClassicPoller* mfc_poller = event.poller;
|
||||||
MfClassicPoller* mfc_poller = mf_classic_poller_alloc(iso14443_3a_poller);
|
|
||||||
|
|
||||||
if(iso14443_3a_event->type == Iso14443_3aPollerEventTypeReady) {
|
if(iso14443_3a_event->type == Iso14443_3aPollerEventTypeReady) {
|
||||||
poller_context->error = mf_classic_poller_cmd_handlers[poller_context->cmd_type](
|
poller_context->error = mf_classic_poller_cmd_handlers[poller_context->cmd_type](
|
||||||
@ -202,8 +201,6 @@ static NfcCommand mf_classic_poller_cmd_callback(NfcGenericEvent event, void* co
|
|||||||
|
|
||||||
furi_thread_flags_set(poller_context->thread_id, MF_CLASSIC_POLLER_COMPLETE_EVENT);
|
furi_thread_flags_set(poller_context->thread_id, MF_CLASSIC_POLLER_COMPLETE_EVENT);
|
||||||
|
|
||||||
mf_classic_poller_free(mfc_poller);
|
|
||||||
|
|
||||||
return NfcCommandStop;
|
return NfcCommandStop;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,8 +209,8 @@ static MfClassicError mf_classic_poller_cmd_execute(Nfc* nfc, MfClassicPollerCon
|
|||||||
|
|
||||||
poller_ctx->thread_id = furi_thread_get_current_id();
|
poller_ctx->thread_id = furi_thread_get_current_id();
|
||||||
|
|
||||||
NfcPoller* poller = nfc_poller_alloc(nfc, NfcProtocolIso14443_3a);
|
NfcPoller* poller = nfc_poller_alloc(nfc, NfcProtocolMfClassic);
|
||||||
nfc_poller_start(poller, mf_classic_poller_cmd_callback, poller_ctx);
|
nfc_poller_start_ex(poller, mf_classic_poller_cmd_callback, poller_ctx);
|
||||||
furi_thread_flags_wait(MF_CLASSIC_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever);
|
furi_thread_flags_wait(MF_CLASSIC_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever);
|
||||||
furi_thread_flags_clear(MF_CLASSIC_POLLER_COMPLETE_EVENT);
|
furi_thread_flags_clear(MF_CLASSIC_POLLER_COMPLETE_EVENT);
|
||||||
|
|
||||||
@ -223,7 +220,7 @@ static MfClassicError mf_classic_poller_cmd_execute(Nfc* nfc, MfClassicPollerCon
|
|||||||
return poller_ctx->error;
|
return poller_ctx->error;
|
||||||
}
|
}
|
||||||
|
|
||||||
MfClassicError mf_classic_poller_collect_nt(
|
MfClassicError mf_classic_poller_sync_collect_nt(
|
||||||
Nfc* nfc,
|
Nfc* nfc,
|
||||||
uint8_t block_num,
|
uint8_t block_num,
|
||||||
MfClassicKeyType key_type,
|
MfClassicKeyType key_type,
|
||||||
@ -247,7 +244,7 @@ MfClassicError mf_classic_poller_collect_nt(
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
MfClassicError mf_classic_poller_auth(
|
MfClassicError mf_classic_poller_sync_auth(
|
||||||
Nfc* nfc,
|
Nfc* nfc,
|
||||||
uint8_t block_num,
|
uint8_t block_num,
|
||||||
MfClassicKey* key,
|
MfClassicKey* key,
|
||||||
@ -274,7 +271,7 @@ MfClassicError mf_classic_poller_auth(
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
MfClassicError mf_classic_poller_read_block(
|
MfClassicError mf_classic_poller_sync_read_block(
|
||||||
Nfc* nfc,
|
Nfc* nfc,
|
||||||
uint8_t block_num,
|
uint8_t block_num,
|
||||||
MfClassicKey* key,
|
MfClassicKey* key,
|
||||||
@ -300,7 +297,7 @@ MfClassicError mf_classic_poller_read_block(
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
MfClassicError mf_classic_poller_write_block(
|
MfClassicError mf_classic_poller_sync_write_block(
|
||||||
Nfc* nfc,
|
Nfc* nfc,
|
||||||
uint8_t block_num,
|
uint8_t block_num,
|
||||||
MfClassicKey* key,
|
MfClassicKey* key,
|
||||||
@ -323,7 +320,7 @@ MfClassicError mf_classic_poller_write_block(
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
MfClassicError mf_classic_poller_read_value(
|
MfClassicError mf_classic_poller_sync_read_value(
|
||||||
Nfc* nfc,
|
Nfc* nfc,
|
||||||
uint8_t block_num,
|
uint8_t block_num,
|
||||||
MfClassicKey* key,
|
MfClassicKey* key,
|
||||||
@ -349,7 +346,7 @@ MfClassicError mf_classic_poller_read_value(
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
MfClassicError mf_classic_poller_change_value(
|
MfClassicError mf_classic_poller_sync_change_value(
|
||||||
Nfc* nfc,
|
Nfc* nfc,
|
||||||
uint8_t block_num,
|
uint8_t block_num,
|
||||||
MfClassicKey* key,
|
MfClassicKey* key,
|
||||||
@ -461,7 +458,7 @@ NfcCommand mf_classic_poller_read_callback(NfcGenericEvent event, void* context)
|
|||||||
}
|
}
|
||||||
|
|
||||||
MfClassicError
|
MfClassicError
|
||||||
mf_classic_poller_read(Nfc* nfc, const MfClassicDeviceKeys* keys, MfClassicData* data) {
|
mf_classic_poller_sync_read(Nfc* nfc, const MfClassicDeviceKeys* keys, MfClassicData* data) {
|
||||||
furi_assert(nfc);
|
furi_assert(nfc);
|
||||||
furi_assert(keys);
|
furi_assert(keys);
|
||||||
furi_assert(data);
|
furi_assert(data);
|
||||||
@ -498,7 +495,7 @@ MfClassicError
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
MfClassicError mf_classic_poller_detect_type(Nfc* nfc, MfClassicType* type) {
|
MfClassicError mf_classic_poller_sync_detect_type(Nfc* nfc, MfClassicType* type) {
|
||||||
furi_assert(nfc);
|
furi_assert(nfc);
|
||||||
furi_assert(type);
|
furi_assert(type);
|
||||||
|
|
||||||
@ -512,7 +509,7 @@ MfClassicError mf_classic_poller_detect_type(Nfc* nfc, MfClassicType* type) {
|
|||||||
|
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
for(i = 0; i < COUNT_OF(mf_classic_verify_block); i++) {
|
for(i = 0; i < COUNT_OF(mf_classic_verify_block); i++) {
|
||||||
error = mf_classic_poller_collect_nt(
|
error = mf_classic_poller_sync_collect_nt(
|
||||||
nfc, mf_classic_verify_block[MfClassicTypeNum - i - 1], MfClassicKeyTypeA, NULL);
|
nfc, mf_classic_verify_block[MfClassicTypeNum - i - 1], MfClassicKeyTypeA, NULL);
|
||||||
if(error == MfClassicErrorNone) {
|
if(error == MfClassicErrorNone) {
|
||||||
*type = MfClassicTypeNum - i - 1;
|
*type = MfClassicTypeNum - i - 1;
|
@ -7,41 +7,41 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
MfClassicError mf_classic_poller_collect_nt(
|
MfClassicError mf_classic_poller_sync_collect_nt(
|
||||||
Nfc* nfc,
|
Nfc* nfc,
|
||||||
uint8_t block_num,
|
uint8_t block_num,
|
||||||
MfClassicKeyType key_type,
|
MfClassicKeyType key_type,
|
||||||
MfClassicNt* nt);
|
MfClassicNt* nt);
|
||||||
|
|
||||||
MfClassicError mf_classic_poller_auth(
|
MfClassicError mf_classic_poller_sync_auth(
|
||||||
Nfc* nfc,
|
Nfc* nfc,
|
||||||
uint8_t block_num,
|
uint8_t block_num,
|
||||||
MfClassicKey* key,
|
MfClassicKey* key,
|
||||||
MfClassicKeyType key_type,
|
MfClassicKeyType key_type,
|
||||||
MfClassicAuthContext* data);
|
MfClassicAuthContext* data);
|
||||||
|
|
||||||
MfClassicError mf_classic_poller_read_block(
|
MfClassicError mf_classic_poller_sync_read_block(
|
||||||
Nfc* nfc,
|
Nfc* nfc,
|
||||||
uint8_t block_num,
|
uint8_t block_num,
|
||||||
MfClassicKey* key,
|
MfClassicKey* key,
|
||||||
MfClassicKeyType key_type,
|
MfClassicKeyType key_type,
|
||||||
MfClassicBlock* data);
|
MfClassicBlock* data);
|
||||||
|
|
||||||
MfClassicError mf_classic_poller_write_block(
|
MfClassicError mf_classic_poller_sync_write_block(
|
||||||
Nfc* nfc,
|
Nfc* nfc,
|
||||||
uint8_t block_num,
|
uint8_t block_num,
|
||||||
MfClassicKey* key,
|
MfClassicKey* key,
|
||||||
MfClassicKeyType key_type,
|
MfClassicKeyType key_type,
|
||||||
MfClassicBlock* data);
|
MfClassicBlock* data);
|
||||||
|
|
||||||
MfClassicError mf_classic_poller_read_value(
|
MfClassicError mf_classic_poller_sync_read_value(
|
||||||
Nfc* nfc,
|
Nfc* nfc,
|
||||||
uint8_t block_num,
|
uint8_t block_num,
|
||||||
MfClassicKey* key,
|
MfClassicKey* key,
|
||||||
MfClassicKeyType key_type,
|
MfClassicKeyType key_type,
|
||||||
int32_t* value);
|
int32_t* value);
|
||||||
|
|
||||||
MfClassicError mf_classic_poller_change_value(
|
MfClassicError mf_classic_poller_sync_change_value(
|
||||||
Nfc* nfc,
|
Nfc* nfc,
|
||||||
uint8_t block_num,
|
uint8_t block_num,
|
||||||
MfClassicKey* key,
|
MfClassicKey* key,
|
||||||
@ -49,10 +49,10 @@ MfClassicError mf_classic_poller_change_value(
|
|||||||
int32_t data,
|
int32_t data,
|
||||||
int32_t* new_value);
|
int32_t* new_value);
|
||||||
|
|
||||||
MfClassicError mf_classic_poller_detect_type(Nfc* nfc, MfClassicType* type);
|
MfClassicError mf_classic_poller_sync_detect_type(Nfc* nfc, MfClassicType* type);
|
||||||
|
|
||||||
MfClassicError
|
MfClassicError
|
||||||
mf_classic_poller_read(Nfc* nfc, const MfClassicDeviceKeys* keys, MfClassicData* data);
|
mf_classic_poller_sync_read(Nfc* nfc, const MfClassicDeviceKeys* keys, MfClassicData* data);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
@ -201,7 +201,7 @@ bool mf_desfire_file_settings_parse(MfDesfireFileSettings* data, const BitBuffer
|
|||||||
|
|
||||||
data->value.lo_limit = layout.value.lo_limit;
|
data->value.lo_limit = layout.value.lo_limit;
|
||||||
data->value.hi_limit = layout.value.hi_limit;
|
data->value.hi_limit = layout.value.hi_limit;
|
||||||
data->value.limited_credit_value = layout.value.hi_limit;
|
data->value.limited_credit_value = layout.value.limited_credit_value;
|
||||||
data->value.limited_credit_enabled = layout.value.limited_credit_enabled;
|
data->value.limited_credit_enabled = layout.value.limited_credit_enabled;
|
||||||
|
|
||||||
} else if(
|
} else if(
|
||||||
|
@ -61,7 +61,7 @@ static NfcCommand mf_desfire_poller_handler_idle(MfDesfirePoller* instance) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static NfcCommand mf_desfire_poller_handler_read_version(MfDesfirePoller* instance) {
|
static NfcCommand mf_desfire_poller_handler_read_version(MfDesfirePoller* instance) {
|
||||||
instance->error = mf_desfire_poller_async_read_version(instance, &instance->data->version);
|
instance->error = mf_desfire_poller_read_version(instance, &instance->data->version);
|
||||||
if(instance->error == MfDesfireErrorNone) {
|
if(instance->error == MfDesfireErrorNone) {
|
||||||
FURI_LOG_D(TAG, "Read version success");
|
FURI_LOG_D(TAG, "Read version success");
|
||||||
instance->state = MfDesfirePollerStateReadFreeMemory;
|
instance->state = MfDesfirePollerStateReadFreeMemory;
|
||||||
@ -75,8 +75,7 @@ static NfcCommand mf_desfire_poller_handler_read_version(MfDesfirePoller* instan
|
|||||||
}
|
}
|
||||||
|
|
||||||
static NfcCommand mf_desfire_poller_handler_read_free_memory(MfDesfirePoller* instance) {
|
static NfcCommand mf_desfire_poller_handler_read_free_memory(MfDesfirePoller* instance) {
|
||||||
instance->error =
|
instance->error = mf_desfire_poller_read_free_memory(instance, &instance->data->free_memory);
|
||||||
mf_desfire_poller_async_read_free_memory(instance, &instance->data->free_memory);
|
|
||||||
if(instance->error == MfDesfireErrorNone) {
|
if(instance->error == MfDesfireErrorNone) {
|
||||||
FURI_LOG_D(TAG, "Read free memory success");
|
FURI_LOG_D(TAG, "Read free memory success");
|
||||||
instance->state = MfDesfirePollerStateReadMasterKeySettings;
|
instance->state = MfDesfirePollerStateReadMasterKeySettings;
|
||||||
@ -91,7 +90,7 @@ static NfcCommand mf_desfire_poller_handler_read_free_memory(MfDesfirePoller* in
|
|||||||
|
|
||||||
static NfcCommand mf_desfire_poller_handler_read_master_key_settings(MfDesfirePoller* instance) {
|
static NfcCommand mf_desfire_poller_handler_read_master_key_settings(MfDesfirePoller* instance) {
|
||||||
instance->error =
|
instance->error =
|
||||||
mf_desfire_poller_async_read_key_settings(instance, &instance->data->master_key_settings);
|
mf_desfire_poller_read_key_settings(instance, &instance->data->master_key_settings);
|
||||||
if(instance->error == MfDesfireErrorNone) {
|
if(instance->error == MfDesfireErrorNone) {
|
||||||
FURI_LOG_D(TAG, "Read master key settings success");
|
FURI_LOG_D(TAG, "Read master key settings success");
|
||||||
instance->state = MfDesfirePollerStateReadMasterKeyVersion;
|
instance->state = MfDesfirePollerStateReadMasterKeyVersion;
|
||||||
@ -105,7 +104,7 @@ static NfcCommand mf_desfire_poller_handler_read_master_key_settings(MfDesfirePo
|
|||||||
}
|
}
|
||||||
|
|
||||||
static NfcCommand mf_desfire_poller_handler_read_master_key_version(MfDesfirePoller* instance) {
|
static NfcCommand mf_desfire_poller_handler_read_master_key_version(MfDesfirePoller* instance) {
|
||||||
instance->error = mf_desfire_poller_async_read_key_versions(
|
instance->error = mf_desfire_poller_read_key_versions(
|
||||||
instance,
|
instance,
|
||||||
instance->data->master_key_versions,
|
instance->data->master_key_versions,
|
||||||
instance->data->master_key_settings.max_keys);
|
instance->data->master_key_settings.max_keys);
|
||||||
@ -123,7 +122,7 @@ static NfcCommand mf_desfire_poller_handler_read_master_key_version(MfDesfirePol
|
|||||||
|
|
||||||
static NfcCommand mf_desfire_poller_handler_read_application_ids(MfDesfirePoller* instance) {
|
static NfcCommand mf_desfire_poller_handler_read_application_ids(MfDesfirePoller* instance) {
|
||||||
instance->error =
|
instance->error =
|
||||||
mf_desfire_poller_async_read_application_ids(instance, instance->data->application_ids);
|
mf_desfire_poller_read_application_ids(instance, instance->data->application_ids);
|
||||||
if(instance->error == MfDesfireErrorNone) {
|
if(instance->error == MfDesfireErrorNone) {
|
||||||
FURI_LOG_D(TAG, "Read application ids success");
|
FURI_LOG_D(TAG, "Read application ids success");
|
||||||
instance->state = MfDesfirePollerStateReadApplications;
|
instance->state = MfDesfirePollerStateReadApplications;
|
||||||
@ -137,7 +136,7 @@ static NfcCommand mf_desfire_poller_handler_read_application_ids(MfDesfirePoller
|
|||||||
}
|
}
|
||||||
|
|
||||||
static NfcCommand mf_desfire_poller_handler_read_applications(MfDesfirePoller* instance) {
|
static NfcCommand mf_desfire_poller_handler_read_applications(MfDesfirePoller* instance) {
|
||||||
instance->error = mf_desfire_poller_async_read_applications(
|
instance->error = mf_desfire_poller_read_applications(
|
||||||
instance, instance->data->application_ids, instance->data->applications);
|
instance, instance->data->application_ids, instance->data->applications);
|
||||||
if(instance->error == MfDesfireErrorNone) {
|
if(instance->error == MfDesfireErrorNone) {
|
||||||
FURI_LOG_D(TAG, "Read applications success");
|
FURI_LOG_D(TAG, "Read applications success");
|
||||||
@ -227,7 +226,7 @@ static bool mf_desfire_poller_detect(NfcGenericEvent event, void* context) {
|
|||||||
|
|
||||||
if(iso14443_4a_event->type == Iso14443_4aPollerEventTypeReady) {
|
if(iso14443_4a_event->type == Iso14443_4aPollerEventTypeReady) {
|
||||||
MfDesfireVersion version = {};
|
MfDesfireVersion version = {};
|
||||||
const MfDesfireError error = mf_desfire_poller_async_read_version(instance, &version);
|
const MfDesfireError error = mf_desfire_poller_read_version(instance, &version);
|
||||||
protocol_detected = (error == MfDesfireErrorNone);
|
protocol_detected = (error == MfDesfireErrorNone);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,24 +8,267 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief MfDesfirePoller opaque type definition.
|
||||||
|
*/
|
||||||
typedef struct MfDesfirePoller MfDesfirePoller;
|
typedef struct MfDesfirePoller MfDesfirePoller;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enumeration of possible MfDesfire poller event types.
|
||||||
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
MfDesfirePollerEventTypeReadSuccess,
|
MfDesfirePollerEventTypeReadSuccess, /**< Card was read successfully. */
|
||||||
MfDesfirePollerEventTypeReadFailed,
|
MfDesfirePollerEventTypeReadFailed, /**< Poller failed to read card. */
|
||||||
} MfDesfirePollerEventType;
|
} MfDesfirePollerEventType;
|
||||||
|
|
||||||
typedef struct {
|
/**
|
||||||
union {
|
* @brief MfDesfire poller event data.
|
||||||
MfDesfireError error;
|
*/
|
||||||
};
|
typedef union {
|
||||||
|
MfDesfireError error; /**< Error code indicating card reading fail reason. */
|
||||||
} MfDesfirePollerEventData;
|
} MfDesfirePollerEventData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief MfDesfire poller event structure.
|
||||||
|
*
|
||||||
|
* Upon emission of an event, an instance of this struct will be passed to the callback.
|
||||||
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
MfDesfirePollerEventType type;
|
MfDesfirePollerEventType type; /**< Type of emmitted event. */
|
||||||
MfDesfirePollerEventData* data;
|
MfDesfirePollerEventData* data; /**< Pointer to event specific data. */
|
||||||
} MfDesfirePollerEvent;
|
} MfDesfirePollerEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Transmit and receive MfDesfire chunks in poller mode.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* The rx_buffer will be filled with any data received as a response to data
|
||||||
|
* sent from tx_buffer, with a timeout defined by the fwt parameter.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @param[in] tx_buffer pointer to the buffer containing the data to be transmitted.
|
||||||
|
* @param[out] rx_buffer pointer to the buffer to be filled with received data.
|
||||||
|
* @return MfDesfireErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
MfDesfireError mf_desfire_send_chunks(
|
||||||
|
MfDesfirePoller* instance,
|
||||||
|
const BitBuffer* tx_buffer,
|
||||||
|
BitBuffer* rx_buffer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read MfDesfire card version.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @param[out] data pointer to the MfDesfireVersion structure to be filled with version data.
|
||||||
|
* @return MfDesfireErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
MfDesfireError mf_desfire_poller_read_version(MfDesfirePoller* instance, MfDesfireVersion* data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read free memory available on MfDesfire card.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @param[out] data pointer to the MfDesfireFreeMemory structure to be filled with free memory data.
|
||||||
|
* @return MfDesfireErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
MfDesfireError
|
||||||
|
mf_desfire_poller_read_free_memory(MfDesfirePoller* instance, MfDesfireFreeMemory* data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read key settings on MfDesfire card.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @param[out] data pointer to the MfDesfireKeySettings structure to be filled with key settings data.
|
||||||
|
* @return MfDesfireErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
MfDesfireError
|
||||||
|
mf_desfire_poller_read_key_settings(MfDesfirePoller* instance, MfDesfireKeySettings* data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read key versions on MfDesfire card.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @param[out] data pointer to the SimpleArray structure to be filled with key versions data.
|
||||||
|
* @param[in] count number of key versions to read.
|
||||||
|
* @return MfDesfireErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
MfDesfireError mf_desfire_poller_read_key_versions(
|
||||||
|
MfDesfirePoller* instance,
|
||||||
|
SimpleArray* data,
|
||||||
|
uint32_t count);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read applications IDs on MfDesfire card.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @param[out] data pointer to the SimpleArray structure to be filled with application ids data.
|
||||||
|
* @return MfDesfireErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
MfDesfireError
|
||||||
|
mf_desfire_poller_read_application_ids(MfDesfirePoller* instance, SimpleArray* data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Select application on MfDesfire card.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @param[in] id pointer to the MfDesfireApplicationId structure with application id to select.
|
||||||
|
* @return MfDesfireErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
MfDesfireError mf_desfire_poller_select_application(
|
||||||
|
MfDesfirePoller* instance,
|
||||||
|
const MfDesfireApplicationId* id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read file IDs for selected application on MfDesfire card.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @param[out] data pointer to the SimpleArray structure to be filled with file ids data.
|
||||||
|
* @return MfDesfireErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
MfDesfireError mf_desfire_poller_read_file_ids(MfDesfirePoller* instance, SimpleArray* data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read file settings on MfDesfire card.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @param[in] id file id to read settings for.
|
||||||
|
* @param[out] data pointer to the MfDesfireFileSettings structure to be filled with file settings data.
|
||||||
|
* @return MfDesfireErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
MfDesfireError mf_desfire_poller_read_file_settings(
|
||||||
|
MfDesfirePoller* instance,
|
||||||
|
MfDesfireFileId id,
|
||||||
|
MfDesfireFileSettings* data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read multiple file settings on MfDesfire card.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @param[in] file_ids pointer to the SimpleArray structure array with file ids to read settings for.
|
||||||
|
* @param[out] data pointer to the SimpleArray structure array to be filled with file settings data.
|
||||||
|
* @return MfDesfireErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
MfDesfireError mf_desfire_poller_read_file_settings_multi(
|
||||||
|
MfDesfirePoller* instance,
|
||||||
|
const SimpleArray* file_ids,
|
||||||
|
SimpleArray* data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read file data on MfDesfire card.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @param[in] id file id to read data from.
|
||||||
|
* @param[in] offset offset in bytes to start reading from.
|
||||||
|
* @param[in] size number of bytes to read.
|
||||||
|
* @param[out] data pointer to the MfDesfireFileData structure to be filled with file data.
|
||||||
|
* @return MfDesfireErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
MfDesfireError mf_desfire_poller_read_file_data(
|
||||||
|
MfDesfirePoller* instance,
|
||||||
|
MfDesfireFileId id,
|
||||||
|
uint32_t offset,
|
||||||
|
size_t size,
|
||||||
|
MfDesfireFileData* data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read file value on MfDesfire card.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @param[in] id file id to read value from.
|
||||||
|
* @param[out] data pointer to the MfDesfireFileData structure to be filled with file value.
|
||||||
|
* @return MfDesfireErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
MfDesfireError mf_desfire_poller_read_file_value(
|
||||||
|
MfDesfirePoller* instance,
|
||||||
|
MfDesfireFileId id,
|
||||||
|
MfDesfireFileData* data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read file records on MfDesfire card.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @param[in] id file id to read data from.
|
||||||
|
* @param[in] offset offset in bytes to start reading from.
|
||||||
|
* @param[in] size number of bytes to read.
|
||||||
|
* @param[out] data pointer to the MfDesfireFileData structure to be filled with file records data.
|
||||||
|
* @return MfDesfireErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
MfDesfireError mf_desfire_poller_read_file_records(
|
||||||
|
MfDesfirePoller* instance,
|
||||||
|
MfDesfireFileId id,
|
||||||
|
uint32_t offset,
|
||||||
|
size_t size,
|
||||||
|
MfDesfireFileData* data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read data from multiple files on MfDesfire card.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @param[in] file_ids pointer to the SimpleArray structure array with files ids to read data from.
|
||||||
|
* @param[in] file_settings pointer to the SimpleArray structure array with files settings to read data from.
|
||||||
|
* @param[out] data pointer to the SimpleArray structure array to be filled with files data.
|
||||||
|
* @return MfDesfireErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
MfDesfireError mf_desfire_poller_read_file_data_multi(
|
||||||
|
MfDesfirePoller* instance,
|
||||||
|
const SimpleArray* file_ids,
|
||||||
|
const SimpleArray* file_settings,
|
||||||
|
SimpleArray* data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read application data for selected application on MfDesfire card.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @param[out] data pointer to the MfDesfireApplication structure to be filled with application data.
|
||||||
|
* @return MfDesfireErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
MfDesfireError
|
||||||
|
mf_desfire_poller_read_application(MfDesfirePoller* instance, MfDesfireApplication* data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read multiple applications data on MfDesfire card.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @param[in] app_ids pointer to the SimpleArray structure array with application ids to read data from.
|
||||||
|
* @param[out] data pointer to the SimpleArray structure array to be filled with applications data.
|
||||||
|
* @return MfDesfireErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
MfDesfireError mf_desfire_poller_read_applications(
|
||||||
|
MfDesfirePoller* instance,
|
||||||
|
const SimpleArray* app_ids,
|
||||||
|
SimpleArray* data);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -74,8 +74,7 @@ MfDesfireError mf_desfire_send_chunks(
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
MfDesfireError
|
MfDesfireError mf_desfire_poller_read_version(MfDesfirePoller* instance, MfDesfireVersion* data) {
|
||||||
mf_desfire_poller_async_read_version(MfDesfirePoller* instance, MfDesfireVersion* data) {
|
|
||||||
furi_assert(instance);
|
furi_assert(instance);
|
||||||
|
|
||||||
bit_buffer_reset(instance->input_buffer);
|
bit_buffer_reset(instance->input_buffer);
|
||||||
@ -97,7 +96,7 @@ MfDesfireError
|
|||||||
}
|
}
|
||||||
|
|
||||||
MfDesfireError
|
MfDesfireError
|
||||||
mf_desfire_poller_async_read_free_memory(MfDesfirePoller* instance, MfDesfireFreeMemory* data) {
|
mf_desfire_poller_read_free_memory(MfDesfirePoller* instance, MfDesfireFreeMemory* data) {
|
||||||
furi_assert(instance);
|
furi_assert(instance);
|
||||||
|
|
||||||
bit_buffer_reset(instance->input_buffer);
|
bit_buffer_reset(instance->input_buffer);
|
||||||
@ -118,9 +117,8 @@ MfDesfireError
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
MfDesfireError mf_desfire_poller_async_read_key_settings(
|
MfDesfireError
|
||||||
MfDesfirePoller* instance,
|
mf_desfire_poller_read_key_settings(MfDesfirePoller* instance, MfDesfireKeySettings* data) {
|
||||||
MfDesfireKeySettings* data) {
|
|
||||||
furi_assert(instance);
|
furi_assert(instance);
|
||||||
|
|
||||||
bit_buffer_reset(instance->input_buffer);
|
bit_buffer_reset(instance->input_buffer);
|
||||||
@ -141,7 +139,7 @@ MfDesfireError mf_desfire_poller_async_read_key_settings(
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
MfDesfireError mf_desfire_poller_async_read_key_versions(
|
MfDesfireError mf_desfire_poller_read_key_versions(
|
||||||
MfDesfirePoller* instance,
|
MfDesfirePoller* instance,
|
||||||
SimpleArray* data,
|
SimpleArray* data,
|
||||||
uint32_t count) {
|
uint32_t count) {
|
||||||
@ -172,7 +170,7 @@ MfDesfireError mf_desfire_poller_async_read_key_versions(
|
|||||||
}
|
}
|
||||||
|
|
||||||
MfDesfireError
|
MfDesfireError
|
||||||
mf_desfire_poller_async_read_application_ids(MfDesfirePoller* instance, SimpleArray* data) {
|
mf_desfire_poller_read_application_ids(MfDesfirePoller* instance, SimpleArray* data) {
|
||||||
furi_assert(instance);
|
furi_assert(instance);
|
||||||
|
|
||||||
bit_buffer_reset(instance->input_buffer);
|
bit_buffer_reset(instance->input_buffer);
|
||||||
@ -203,7 +201,7 @@ MfDesfireError
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
MfDesfireError mf_desfire_poller_async_select_application(
|
MfDesfireError mf_desfire_poller_select_application(
|
||||||
MfDesfirePoller* instance,
|
MfDesfirePoller* instance,
|
||||||
const MfDesfireApplicationId* id) {
|
const MfDesfireApplicationId* id) {
|
||||||
furi_assert(instance);
|
furi_assert(instance);
|
||||||
@ -219,8 +217,7 @@ MfDesfireError mf_desfire_poller_async_select_application(
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
MfDesfireError
|
MfDesfireError mf_desfire_poller_read_file_ids(MfDesfirePoller* instance, SimpleArray* data) {
|
||||||
mf_desfire_poller_async_read_file_ids(MfDesfirePoller* instance, SimpleArray* data) {
|
|
||||||
furi_assert(instance);
|
furi_assert(instance);
|
||||||
|
|
||||||
bit_buffer_reset(instance->input_buffer);
|
bit_buffer_reset(instance->input_buffer);
|
||||||
@ -250,7 +247,7 @@ MfDesfireError
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
MfDesfireError mf_desfire_poller_async_read_file_settings(
|
MfDesfireError mf_desfire_poller_read_file_settings(
|
||||||
MfDesfirePoller* instance,
|
MfDesfirePoller* instance,
|
||||||
MfDesfireFileId id,
|
MfDesfireFileId id,
|
||||||
MfDesfireFileSettings* data) {
|
MfDesfireFileSettings* data) {
|
||||||
@ -275,7 +272,7 @@ MfDesfireError mf_desfire_poller_async_read_file_settings(
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
MfDesfireError mf_desfire_poller_async_read_file_settings_multi(
|
MfDesfireError mf_desfire_poller_read_file_settings_multi(
|
||||||
MfDesfirePoller* instance,
|
MfDesfirePoller* instance,
|
||||||
const SimpleArray* file_ids,
|
const SimpleArray* file_ids,
|
||||||
SimpleArray* data) {
|
SimpleArray* data) {
|
||||||
@ -290,15 +287,14 @@ MfDesfireError mf_desfire_poller_async_read_file_settings_multi(
|
|||||||
|
|
||||||
for(uint32_t i = 0; i < file_id_count; ++i) {
|
for(uint32_t i = 0; i < file_id_count; ++i) {
|
||||||
const MfDesfireFileId file_id = *(const MfDesfireFileId*)simple_array_cget(file_ids, i);
|
const MfDesfireFileId file_id = *(const MfDesfireFileId*)simple_array_cget(file_ids, i);
|
||||||
error = mf_desfire_poller_async_read_file_settings(
|
error = mf_desfire_poller_read_file_settings(instance, file_id, simple_array_get(data, i));
|
||||||
instance, file_id, simple_array_get(data, i));
|
|
||||||
if(error != MfDesfireErrorNone) break;
|
if(error != MfDesfireErrorNone) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
MfDesfireError mf_desfire_poller_async_read_file_data(
|
MfDesfireError mf_desfire_poller_read_file_data(
|
||||||
MfDesfirePoller* instance,
|
MfDesfirePoller* instance,
|
||||||
MfDesfireFileId id,
|
MfDesfireFileId id,
|
||||||
uint32_t offset,
|
uint32_t offset,
|
||||||
@ -327,7 +323,7 @@ MfDesfireError mf_desfire_poller_async_read_file_data(
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
MfDesfireError mf_desfire_poller_async_read_file_value(
|
MfDesfireError mf_desfire_poller_read_file_value(
|
||||||
MfDesfirePoller* instance,
|
MfDesfirePoller* instance,
|
||||||
MfDesfireFileId id,
|
MfDesfireFileId id,
|
||||||
MfDesfireFileData* data) {
|
MfDesfireFileData* data) {
|
||||||
@ -352,7 +348,7 @@ MfDesfireError mf_desfire_poller_async_read_file_value(
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
MfDesfireError mf_desfire_poller_async_read_file_records(
|
MfDesfireError mf_desfire_poller_read_file_records(
|
||||||
MfDesfirePoller* instance,
|
MfDesfirePoller* instance,
|
||||||
MfDesfireFileId id,
|
MfDesfireFileId id,
|
||||||
uint32_t offset,
|
uint32_t offset,
|
||||||
@ -381,7 +377,7 @@ MfDesfireError mf_desfire_poller_async_read_file_records(
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
MfDesfireError mf_desfire_poller_async_read_file_data_multi(
|
MfDesfireError mf_desfire_poller_read_file_data_multi(
|
||||||
MfDesfirePoller* instance,
|
MfDesfirePoller* instance,
|
||||||
const SimpleArray* file_ids,
|
const SimpleArray* file_ids,
|
||||||
const SimpleArray* file_settings,
|
const SimpleArray* file_settings,
|
||||||
@ -404,14 +400,14 @@ MfDesfireError mf_desfire_poller_async_read_file_data_multi(
|
|||||||
MfDesfireFileData* file_data = simple_array_get(data, i);
|
MfDesfireFileData* file_data = simple_array_get(data, i);
|
||||||
|
|
||||||
if(file_type == MfDesfireFileTypeStandard || file_type == MfDesfireFileTypeBackup) {
|
if(file_type == MfDesfireFileTypeStandard || file_type == MfDesfireFileTypeBackup) {
|
||||||
error = mf_desfire_poller_async_read_file_data(
|
error = mf_desfire_poller_read_file_data(
|
||||||
instance, file_id, 0, file_settings_cur->data.size, file_data);
|
instance, file_id, 0, file_settings_cur->data.size, file_data);
|
||||||
} else if(file_type == MfDesfireFileTypeValue) {
|
} else if(file_type == MfDesfireFileTypeValue) {
|
||||||
error = mf_desfire_poller_async_read_file_value(instance, file_id, file_data);
|
error = mf_desfire_poller_read_file_value(instance, file_id, file_data);
|
||||||
} else if(
|
} else if(
|
||||||
file_type == MfDesfireFileTypeLinearRecord ||
|
file_type == MfDesfireFileTypeLinearRecord ||
|
||||||
file_type == MfDesfireFileTypeCyclicRecord) {
|
file_type == MfDesfireFileTypeCyclicRecord) {
|
||||||
error = mf_desfire_poller_async_read_file_records(
|
error = mf_desfire_poller_read_file_records(
|
||||||
instance, file_id, 0, file_settings_cur->data.size, file_data);
|
instance, file_id, 0, file_settings_cur->data.size, file_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -421,30 +417,29 @@ MfDesfireError mf_desfire_poller_async_read_file_data_multi(
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
MfDesfireError mf_desfire_poller_async_read_application(
|
MfDesfireError
|
||||||
MfDesfirePoller* instance,
|
mf_desfire_poller_read_application(MfDesfirePoller* instance, MfDesfireApplication* data) {
|
||||||
MfDesfireApplication* data) {
|
|
||||||
furi_assert(instance);
|
furi_assert(instance);
|
||||||
furi_assert(data);
|
furi_assert(data);
|
||||||
|
|
||||||
MfDesfireError error;
|
MfDesfireError error;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
error = mf_desfire_poller_async_read_key_settings(instance, &data->key_settings);
|
error = mf_desfire_poller_read_key_settings(instance, &data->key_settings);
|
||||||
if(error != MfDesfireErrorNone) break;
|
if(error != MfDesfireErrorNone) break;
|
||||||
|
|
||||||
error = mf_desfire_poller_async_read_key_versions(
|
error = mf_desfire_poller_read_key_versions(
|
||||||
instance, data->key_versions, data->key_settings.max_keys);
|
instance, data->key_versions, data->key_settings.max_keys);
|
||||||
if(error != MfDesfireErrorNone) break;
|
if(error != MfDesfireErrorNone) break;
|
||||||
|
|
||||||
error = mf_desfire_poller_async_read_file_ids(instance, data->file_ids);
|
error = mf_desfire_poller_read_file_ids(instance, data->file_ids);
|
||||||
if(error != MfDesfireErrorNone) break;
|
if(error != MfDesfireErrorNone) break;
|
||||||
|
|
||||||
error = mf_desfire_poller_async_read_file_settings_multi(
|
error = mf_desfire_poller_read_file_settings_multi(
|
||||||
instance, data->file_ids, data->file_settings);
|
instance, data->file_ids, data->file_settings);
|
||||||
if(error != MfDesfireErrorNone) break;
|
if(error != MfDesfireErrorNone) break;
|
||||||
|
|
||||||
error = mf_desfire_poller_async_read_file_data_multi(
|
error = mf_desfire_poller_read_file_data_multi(
|
||||||
instance, data->file_ids, data->file_settings, data->file_data);
|
instance, data->file_ids, data->file_settings, data->file_data);
|
||||||
if(error != MfDesfireErrorNone) break;
|
if(error != MfDesfireErrorNone) break;
|
||||||
|
|
||||||
@ -453,7 +448,7 @@ MfDesfireError mf_desfire_poller_async_read_application(
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
MfDesfireError mf_desfire_poller_async_read_applications(
|
MfDesfireError mf_desfire_poller_read_applications(
|
||||||
MfDesfirePoller* instance,
|
MfDesfirePoller* instance,
|
||||||
const SimpleArray* app_ids,
|
const SimpleArray* app_ids,
|
||||||
SimpleArray* data) {
|
SimpleArray* data) {
|
||||||
@ -468,12 +463,11 @@ MfDesfireError mf_desfire_poller_async_read_applications(
|
|||||||
|
|
||||||
for(uint32_t i = 0; i < app_id_count; ++i) {
|
for(uint32_t i = 0; i < app_id_count; ++i) {
|
||||||
do {
|
do {
|
||||||
error = mf_desfire_poller_async_select_application(
|
error = mf_desfire_poller_select_application(instance, simple_array_cget(app_ids, i));
|
||||||
instance, simple_array_cget(app_ids, i));
|
|
||||||
if(error != MfDesfireErrorNone) break;
|
if(error != MfDesfireErrorNone) break;
|
||||||
|
|
||||||
MfDesfireApplication* current_app = simple_array_get(data, i);
|
MfDesfireApplication* current_app = simple_array_get(data, i);
|
||||||
error = mf_desfire_poller_async_read_application(instance, current_app);
|
error = mf_desfire_poller_read_application(instance, current_app);
|
||||||
|
|
||||||
} while(false);
|
} while(false);
|
||||||
}
|
}
|
||||||
|
@ -49,78 +49,6 @@ MfDesfireError mf_desfire_process_error(Iso14443_4aError error);
|
|||||||
|
|
||||||
const MfDesfireData* mf_desfire_poller_get_data(MfDesfirePoller* instance);
|
const MfDesfireData* mf_desfire_poller_get_data(MfDesfirePoller* instance);
|
||||||
|
|
||||||
MfDesfireError mf_desfire_send_chunks(
|
|
||||||
MfDesfirePoller* instance,
|
|
||||||
const BitBuffer* tx_buffer,
|
|
||||||
BitBuffer* rx_buffer);
|
|
||||||
|
|
||||||
MfDesfireError
|
|
||||||
mf_desfire_poller_async_read_version(MfDesfirePoller* instance, MfDesfireVersion* data);
|
|
||||||
|
|
||||||
MfDesfireError
|
|
||||||
mf_desfire_poller_async_read_free_memory(MfDesfirePoller* instance, MfDesfireFreeMemory* data);
|
|
||||||
|
|
||||||
MfDesfireError mf_desfire_poller_async_read_key_settings(
|
|
||||||
MfDesfirePoller* instance,
|
|
||||||
MfDesfireKeySettings* data);
|
|
||||||
|
|
||||||
MfDesfireError mf_desfire_poller_async_read_key_versions(
|
|
||||||
MfDesfirePoller* instance,
|
|
||||||
SimpleArray* data,
|
|
||||||
uint32_t count);
|
|
||||||
|
|
||||||
MfDesfireError
|
|
||||||
mf_desfire_poller_async_read_application_ids(MfDesfirePoller* instance, SimpleArray* data);
|
|
||||||
|
|
||||||
MfDesfireError mf_desfire_poller_async_select_application(
|
|
||||||
MfDesfirePoller* instance,
|
|
||||||
const MfDesfireApplicationId* id);
|
|
||||||
|
|
||||||
MfDesfireError mf_desfire_poller_async_read_file_ids(MfDesfirePoller* instance, SimpleArray* data);
|
|
||||||
|
|
||||||
MfDesfireError mf_desfire_poller_async_read_file_settings(
|
|
||||||
MfDesfirePoller* instance,
|
|
||||||
MfDesfireFileId id,
|
|
||||||
MfDesfireFileSettings* data);
|
|
||||||
|
|
||||||
MfDesfireError mf_desfire_poller_async_read_file_settings_multi(
|
|
||||||
MfDesfirePoller* instance,
|
|
||||||
const SimpleArray* file_ids,
|
|
||||||
SimpleArray* data);
|
|
||||||
|
|
||||||
MfDesfireError mf_desfire_poller_async_read_file_data(
|
|
||||||
MfDesfirePoller* instance,
|
|
||||||
MfDesfireFileId id,
|
|
||||||
uint32_t offset,
|
|
||||||
size_t size,
|
|
||||||
MfDesfireFileData* data);
|
|
||||||
|
|
||||||
MfDesfireError mf_desfire_poller_async_read_file_value(
|
|
||||||
MfDesfirePoller* instance,
|
|
||||||
MfDesfireFileId id,
|
|
||||||
MfDesfireFileData* data);
|
|
||||||
|
|
||||||
MfDesfireError mf_desfire_poller_async_read_file_records(
|
|
||||||
MfDesfirePoller* instance,
|
|
||||||
MfDesfireFileId id,
|
|
||||||
uint32_t offset,
|
|
||||||
size_t size,
|
|
||||||
MfDesfireFileData* data);
|
|
||||||
|
|
||||||
MfDesfireError mf_desfire_poller_async_read_file_data_multi(
|
|
||||||
MfDesfirePoller* instance,
|
|
||||||
const SimpleArray* file_ids,
|
|
||||||
const SimpleArray* file_settings,
|
|
||||||
SimpleArray* data);
|
|
||||||
|
|
||||||
MfDesfireError
|
|
||||||
mf_desfire_poller_async_read_application(MfDesfirePoller* instance, MfDesfireApplication* data);
|
|
||||||
|
|
||||||
MfDesfireError mf_desfire_poller_async_read_applications(
|
|
||||||
MfDesfirePoller* instance,
|
|
||||||
const SimpleArray* app_ids,
|
|
||||||
SimpleArray* data);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -122,7 +122,7 @@ static MfUltralightCommand
|
|||||||
uint16_t pages_total = instance->data->pages_total;
|
uint16_t pages_total = instance->data->pages_total;
|
||||||
MfUltralightCommand command = MfUltralightCommandNotProcessedNAK;
|
MfUltralightCommand command = MfUltralightCommandNotProcessedNAK;
|
||||||
|
|
||||||
FURI_LOG_D(TAG, "CMD_READ: %d", start_page);
|
FURI_LOG_T(TAG, "CMD_READ: %d", start_page);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
bool do_i2c_check = mf_ultralight_is_i2c_tag(instance->data->type);
|
bool do_i2c_check = mf_ultralight_is_i2c_tag(instance->data->type);
|
||||||
@ -154,7 +154,7 @@ static MfUltralightCommand
|
|||||||
static MfUltralightCommand
|
static MfUltralightCommand
|
||||||
mf_ultralight_listener_fast_read_handler(MfUltralightListener* instance, BitBuffer* buffer) {
|
mf_ultralight_listener_fast_read_handler(MfUltralightListener* instance, BitBuffer* buffer) {
|
||||||
MfUltralightCommand command = MfUltralightCommandNotProcessedSilent;
|
MfUltralightCommand command = MfUltralightCommandNotProcessedSilent;
|
||||||
FURI_LOG_D(TAG, "CMD_FAST_READ");
|
FURI_LOG_T(TAG, "CMD_FAST_READ");
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if(!mf_ultralight_support_feature(instance->features, MfUltralightFeatureSupportFastRead))
|
if(!mf_ultralight_support_feature(instance->features, MfUltralightFeatureSupportFastRead))
|
||||||
@ -206,7 +206,7 @@ static MfUltralightCommand
|
|||||||
uint16_t pages_total = instance->data->pages_total;
|
uint16_t pages_total = instance->data->pages_total;
|
||||||
MfUltralightCommand command = MfUltralightCommandNotProcessedNAK;
|
MfUltralightCommand command = MfUltralightCommandNotProcessedNAK;
|
||||||
|
|
||||||
FURI_LOG_D(TAG, "CMD_WRITE");
|
FURI_LOG_T(TAG, "CMD_WRITE");
|
||||||
|
|
||||||
do {
|
do {
|
||||||
bool do_i2c_check = mf_ultralight_is_i2c_tag(instance->data->type);
|
bool do_i2c_check = mf_ultralight_is_i2c_tag(instance->data->type);
|
||||||
@ -235,7 +235,7 @@ static MfUltralightCommand
|
|||||||
static MfUltralightCommand
|
static MfUltralightCommand
|
||||||
mf_ultralight_listener_fast_write_handler(MfUltralightListener* instance, BitBuffer* buffer) {
|
mf_ultralight_listener_fast_write_handler(MfUltralightListener* instance, BitBuffer* buffer) {
|
||||||
MfUltralightCommand command = MfUltralightCommandNotProcessedSilent;
|
MfUltralightCommand command = MfUltralightCommandNotProcessedSilent;
|
||||||
FURI_LOG_D(TAG, "CMD_FAST_WRITE");
|
FURI_LOG_T(TAG, "CMD_FAST_WRITE");
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if(!mf_ultralight_support_feature(instance->features, MfUltralightFeatureSupportFastWrite))
|
if(!mf_ultralight_support_feature(instance->features, MfUltralightFeatureSupportFastWrite))
|
||||||
@ -261,7 +261,7 @@ static MfUltralightCommand
|
|||||||
UNUSED(buffer);
|
UNUSED(buffer);
|
||||||
MfUltralightCommand command = MfUltralightCommandNotProcessedSilent;
|
MfUltralightCommand command = MfUltralightCommandNotProcessedSilent;
|
||||||
|
|
||||||
FURI_LOG_D(TAG, "CMD_GET_VERSION");
|
FURI_LOG_T(TAG, "CMD_GET_VERSION");
|
||||||
|
|
||||||
if(mf_ultralight_support_feature(instance->features, MfUltralightFeatureSupportReadVersion)) {
|
if(mf_ultralight_support_feature(instance->features, MfUltralightFeatureSupportReadVersion)) {
|
||||||
bit_buffer_copy_bytes(
|
bit_buffer_copy_bytes(
|
||||||
@ -280,7 +280,7 @@ static MfUltralightCommand mf_ultralight_listener_read_signature_handler(
|
|||||||
UNUSED(buffer);
|
UNUSED(buffer);
|
||||||
MfUltralightCommand command = MfUltralightCommandNotProcessedSilent;
|
MfUltralightCommand command = MfUltralightCommandNotProcessedSilent;
|
||||||
|
|
||||||
FURI_LOG_D(TAG, "CMD_READ_SIG");
|
FURI_LOG_T(TAG, "CMD_READ_SIG");
|
||||||
|
|
||||||
if(mf_ultralight_support_feature(instance->features, MfUltralightFeatureSupportReadSignature)) {
|
if(mf_ultralight_support_feature(instance->features, MfUltralightFeatureSupportReadSignature)) {
|
||||||
bit_buffer_copy_bytes(
|
bit_buffer_copy_bytes(
|
||||||
@ -297,7 +297,7 @@ static MfUltralightCommand
|
|||||||
mf_ultralight_listener_read_counter_handler(MfUltralightListener* instance, BitBuffer* buffer) {
|
mf_ultralight_listener_read_counter_handler(MfUltralightListener* instance, BitBuffer* buffer) {
|
||||||
MfUltralightCommand command = MfUltralightCommandNotProcessedNAK;
|
MfUltralightCommand command = MfUltralightCommandNotProcessedNAK;
|
||||||
|
|
||||||
FURI_LOG_D(TAG, "CMD_READ_CNT");
|
FURI_LOG_T(TAG, "CMD_READ_CNT");
|
||||||
|
|
||||||
do {
|
do {
|
||||||
uint8_t counter_num = bit_buffer_get_byte(buffer, 1);
|
uint8_t counter_num = bit_buffer_get_byte(buffer, 1);
|
||||||
@ -338,7 +338,7 @@ static MfUltralightCommand mf_ultralight_listener_increase_counter_handler(
|
|||||||
BitBuffer* buffer) {
|
BitBuffer* buffer) {
|
||||||
MfUltralightCommand command = MfUltralightCommandNotProcessedNAK;
|
MfUltralightCommand command = MfUltralightCommandNotProcessedNAK;
|
||||||
|
|
||||||
FURI_LOG_D(TAG, "CMD_INCR_CNT");
|
FURI_LOG_T(TAG, "CMD_INCR_CNT");
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if(!mf_ultralight_support_feature(
|
if(!mf_ultralight_support_feature(
|
||||||
@ -374,7 +374,7 @@ static MfUltralightCommand mf_ultralight_listener_check_tearing_handler(
|
|||||||
BitBuffer* buffer) {
|
BitBuffer* buffer) {
|
||||||
MfUltralightCommand command = MfUltralightCommandNotProcessedNAK;
|
MfUltralightCommand command = MfUltralightCommandNotProcessedNAK;
|
||||||
|
|
||||||
FURI_LOG_D(TAG, "CMD_CHECK_TEARING");
|
FURI_LOG_T(TAG, "CMD_CHECK_TEARING");
|
||||||
|
|
||||||
do {
|
do {
|
||||||
uint8_t tearing_flag_num = bit_buffer_get_byte(buffer, 1);
|
uint8_t tearing_flag_num = bit_buffer_get_byte(buffer, 1);
|
||||||
@ -410,7 +410,7 @@ static MfUltralightCommand
|
|||||||
MfUltralightCommand command = MfUltralightCommandNotProcessedSilent;
|
MfUltralightCommand command = MfUltralightCommandNotProcessedSilent;
|
||||||
UNUSED(instance);
|
UNUSED(instance);
|
||||||
UNUSED(buffer);
|
UNUSED(buffer);
|
||||||
FURI_LOG_D(TAG, "CMD_VCSL");
|
FURI_LOG_T(TAG, "CMD_VCSL");
|
||||||
do {
|
do {
|
||||||
if(!mf_ultralight_support_feature(instance->features, MfUltralightFeatureSupportVcsl))
|
if(!mf_ultralight_support_feature(instance->features, MfUltralightFeatureSupportVcsl))
|
||||||
break;
|
break;
|
||||||
@ -432,7 +432,7 @@ static MfUltralightCommand
|
|||||||
mf_ultralight_listener_auth_handler(MfUltralightListener* instance, BitBuffer* buffer) {
|
mf_ultralight_listener_auth_handler(MfUltralightListener* instance, BitBuffer* buffer) {
|
||||||
MfUltralightCommand command = MfUltralightCommandNotProcessedNAK;
|
MfUltralightCommand command = MfUltralightCommandNotProcessedNAK;
|
||||||
|
|
||||||
FURI_LOG_D(TAG, "CMD_AUTH");
|
FURI_LOG_T(TAG, "CMD_AUTH");
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if(!mf_ultralight_support_feature(
|
if(!mf_ultralight_support_feature(
|
||||||
@ -474,7 +474,7 @@ static MfUltralightCommand
|
|||||||
static MfUltralightCommand
|
static MfUltralightCommand
|
||||||
mf_ultralight_comp_write_handler_p2(MfUltralightListener* instance, BitBuffer* buffer) {
|
mf_ultralight_comp_write_handler_p2(MfUltralightListener* instance, BitBuffer* buffer) {
|
||||||
MfUltralightCommand command = MfUltralightCommandNotProcessedNAK;
|
MfUltralightCommand command = MfUltralightCommandNotProcessedNAK;
|
||||||
FURI_LOG_D(TAG, "CMD_CM_WR_2");
|
FURI_LOG_T(TAG, "CMD_CM_WR_2");
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if(bit_buffer_get_size_bytes(buffer) != 16) break;
|
if(bit_buffer_get_size_bytes(buffer) != 16) break;
|
||||||
@ -492,7 +492,7 @@ static MfUltralightCommand
|
|||||||
mf_ultralight_comp_write_handler_p1(MfUltralightListener* instance, BitBuffer* buffer) {
|
mf_ultralight_comp_write_handler_p1(MfUltralightListener* instance, BitBuffer* buffer) {
|
||||||
MfUltralightCommand command = MfUltralightCommandNotProcessedSilent;
|
MfUltralightCommand command = MfUltralightCommandNotProcessedSilent;
|
||||||
|
|
||||||
FURI_LOG_D(TAG, "CMD_CM_WR_1");
|
FURI_LOG_T(TAG, "CMD_CM_WR_1");
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if(!mf_ultralight_support_feature(
|
if(!mf_ultralight_support_feature(
|
||||||
@ -532,7 +532,7 @@ static MfUltralightCommand
|
|||||||
MfUltralightCommand command = MfUltralightCommandNotProcessedNAK;
|
MfUltralightCommand command = MfUltralightCommandNotProcessedNAK;
|
||||||
UNUSED(instance);
|
UNUSED(instance);
|
||||||
UNUSED(buffer);
|
UNUSED(buffer);
|
||||||
FURI_LOG_D(TAG, "CMD_SEC_SEL_2");
|
FURI_LOG_T(TAG, "CMD_SEC_SEL_2");
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if(bit_buffer_get_size_bytes(buffer) != 4) break;
|
if(bit_buffer_get_size_bytes(buffer) != 4) break;
|
||||||
@ -550,7 +550,7 @@ static MfUltralightCommand
|
|||||||
mf_ultralight_sector_select_handler_p1(MfUltralightListener* instance, BitBuffer* buffer) {
|
mf_ultralight_sector_select_handler_p1(MfUltralightListener* instance, BitBuffer* buffer) {
|
||||||
MfUltralightCommand command = MfUltralightCommandNotProcessedNAK;
|
MfUltralightCommand command = MfUltralightCommandNotProcessedNAK;
|
||||||
UNUSED(buffer);
|
UNUSED(buffer);
|
||||||
FURI_LOG_D(TAG, "CMD_SEC_SEL_1");
|
FURI_LOG_T(TAG, "CMD_SEC_SEL_1");
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if(!mf_ultralight_support_feature(
|
if(!mf_ultralight_support_feature(
|
||||||
|
@ -230,7 +230,7 @@ static NfcCommand mf_ultralight_poller_handler_idle(MfUltralightPoller* instance
|
|||||||
}
|
}
|
||||||
|
|
||||||
static NfcCommand mf_ultralight_poller_handler_read_version(MfUltralightPoller* instance) {
|
static NfcCommand mf_ultralight_poller_handler_read_version(MfUltralightPoller* instance) {
|
||||||
instance->error = mf_ultralight_poller_async_read_version(instance, &instance->data->version);
|
instance->error = mf_ultralight_poller_read_version(instance, &instance->data->version);
|
||||||
if(instance->error == MfUltralightErrorNone) {
|
if(instance->error == MfUltralightErrorNone) {
|
||||||
FURI_LOG_D(TAG, "Read version success");
|
FURI_LOG_D(TAG, "Read version success");
|
||||||
instance->data->type = mf_ultralight_get_type_by_version(&instance->data->version);
|
instance->data->type = mf_ultralight_get_type_by_version(&instance->data->version);
|
||||||
@ -245,7 +245,7 @@ static NfcCommand mf_ultralight_poller_handler_read_version(MfUltralightPoller*
|
|||||||
}
|
}
|
||||||
|
|
||||||
static NfcCommand mf_ultralight_poller_handler_check_ultralight_c(MfUltralightPoller* instance) {
|
static NfcCommand mf_ultralight_poller_handler_check_ultralight_c(MfUltralightPoller* instance) {
|
||||||
instance->error = mf_ultralight_poller_async_authenticate(instance);
|
instance->error = mf_ultralight_poller_authenticate(instance);
|
||||||
if(instance->error == MfUltralightErrorNone) {
|
if(instance->error == MfUltralightErrorNone) {
|
||||||
FURI_LOG_D(TAG, "Ultralight C detected");
|
FURI_LOG_D(TAG, "Ultralight C detected");
|
||||||
instance->data->type = MfUltralightTypeMfulC;
|
instance->data->type = MfUltralightTypeMfulC;
|
||||||
@ -260,7 +260,7 @@ static NfcCommand mf_ultralight_poller_handler_check_ultralight_c(MfUltralightPo
|
|||||||
|
|
||||||
static NfcCommand mf_ultralight_poller_handler_check_ntag_203(MfUltralightPoller* instance) {
|
static NfcCommand mf_ultralight_poller_handler_check_ntag_203(MfUltralightPoller* instance) {
|
||||||
MfUltralightPageReadCommandData data = {};
|
MfUltralightPageReadCommandData data = {};
|
||||||
instance->error = mf_ultralight_poller_async_read_page(instance, 41, &data);
|
instance->error = mf_ultralight_poller_read_page(instance, 41, &data);
|
||||||
if(instance->error == MfUltralightErrorNone) {
|
if(instance->error == MfUltralightErrorNone) {
|
||||||
FURI_LOG_D(TAG, "NTAG203 detected");
|
FURI_LOG_D(TAG, "NTAG203 detected");
|
||||||
instance->data->type = MfUltralightTypeNTAG203;
|
instance->data->type = MfUltralightTypeNTAG203;
|
||||||
@ -294,7 +294,7 @@ static NfcCommand mf_ultralight_poller_handler_read_signature(MfUltralightPoller
|
|||||||
instance->feature_set, MfUltralightFeatureSupportReadSignature)) {
|
instance->feature_set, MfUltralightFeatureSupportReadSignature)) {
|
||||||
FURI_LOG_D(TAG, "Reading signature");
|
FURI_LOG_D(TAG, "Reading signature");
|
||||||
instance->error =
|
instance->error =
|
||||||
mf_ultralight_poller_async_read_signature(instance, &instance->data->signature);
|
mf_ultralight_poller_read_signature(instance, &instance->data->signature);
|
||||||
if(instance->error != MfUltralightErrorNone) {
|
if(instance->error != MfUltralightErrorNone) {
|
||||||
FURI_LOG_D(TAG, "Read signature failed");
|
FURI_LOG_D(TAG, "Read signature failed");
|
||||||
next_state = MfUltralightPollerStateReadFailed;
|
next_state = MfUltralightPollerStateReadFailed;
|
||||||
@ -337,7 +337,7 @@ static NfcCommand mf_ultralight_poller_handler_read_counters(MfUltralightPoller*
|
|||||||
}
|
}
|
||||||
|
|
||||||
FURI_LOG_D(TAG, "Reading counter %d", instance->counters_read);
|
FURI_LOG_D(TAG, "Reading counter %d", instance->counters_read);
|
||||||
instance->error = mf_ultralight_poller_async_read_counter(
|
instance->error = mf_ultralight_poller_read_counter(
|
||||||
instance, instance->counters_read, &instance->data->counter[instance->counters_read]);
|
instance, instance->counters_read, &instance->data->counter[instance->counters_read]);
|
||||||
if(instance->error != MfUltralightErrorNone) {
|
if(instance->error != MfUltralightErrorNone) {
|
||||||
FURI_LOG_D(TAG, "Failed to read %d counter", instance->counters_read);
|
FURI_LOG_D(TAG, "Failed to read %d counter", instance->counters_read);
|
||||||
@ -363,7 +363,7 @@ static NfcCommand mf_ultralight_poller_handler_read_tearing_flags(MfUltralightPo
|
|||||||
if(single_counter) instance->tearing_flag_read = 2;
|
if(single_counter) instance->tearing_flag_read = 2;
|
||||||
|
|
||||||
FURI_LOG_D(TAG, "Reading tearing flag %d", instance->tearing_flag_read);
|
FURI_LOG_D(TAG, "Reading tearing flag %d", instance->tearing_flag_read);
|
||||||
instance->error = mf_ultralight_poller_async_read_tearing_flag(
|
instance->error = mf_ultralight_poller_read_tearing_flag(
|
||||||
instance,
|
instance,
|
||||||
instance->tearing_flag_read,
|
instance->tearing_flag_read,
|
||||||
&instance->data->tearing_flag[instance->tearing_flag_read]);
|
&instance->data->tearing_flag[instance->tearing_flag_read]);
|
||||||
@ -396,8 +396,7 @@ static NfcCommand mf_ultralight_poller_handler_auth(MfUltralightPoller* instance
|
|||||||
uint32_t pass = nfc_util_bytes2num(
|
uint32_t pass = nfc_util_bytes2num(
|
||||||
instance->auth_context.password.data, sizeof(MfUltralightAuthPassword));
|
instance->auth_context.password.data, sizeof(MfUltralightAuthPassword));
|
||||||
FURI_LOG_D(TAG, "Trying to authenticate with password %08lX", pass);
|
FURI_LOG_D(TAG, "Trying to authenticate with password %08lX", pass);
|
||||||
instance->error =
|
instance->error = mf_ultralight_poller_auth_pwd(instance, &instance->auth_context);
|
||||||
mf_ultralight_poller_async_auth_pwd(instance, &instance->auth_context);
|
|
||||||
if(instance->error == MfUltralightErrorNone) {
|
if(instance->error == MfUltralightErrorNone) {
|
||||||
FURI_LOG_D(TAG, "Auth success");
|
FURI_LOG_D(TAG, "Auth success");
|
||||||
instance->auth_context.auth_success = true;
|
instance->auth_context.auth_success = true;
|
||||||
@ -428,13 +427,13 @@ static NfcCommand mf_ultralight_poller_handler_read_pages(MfUltralightPoller* in
|
|||||||
if(mf_ultralight_poller_ntag_i2c_addr_lin_to_tag(
|
if(mf_ultralight_poller_ntag_i2c_addr_lin_to_tag(
|
||||||
instance, start_page, §or, &tag, &pages_left)) {
|
instance, start_page, §or, &tag, &pages_left)) {
|
||||||
instance->error =
|
instance->error =
|
||||||
mf_ultralight_poller_async_read_page_from_sector(instance, sector, tag, &data);
|
mf_ultralight_poller_read_page_from_sector(instance, sector, tag, &data);
|
||||||
} else {
|
} else {
|
||||||
FURI_LOG_D(TAG, "Failed to calculate sector and tag from %d page", start_page);
|
FURI_LOG_D(TAG, "Failed to calculate sector and tag from %d page", start_page);
|
||||||
instance->error = MfUltralightErrorProtocol;
|
instance->error = MfUltralightErrorProtocol;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
instance->error = mf_ultralight_poller_async_read_page(instance, start_page, &data);
|
instance->error = mf_ultralight_poller_read_page(instance, start_page, &data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(instance->error == MfUltralightErrorNone) {
|
if(instance->error == MfUltralightErrorNone) {
|
||||||
@ -478,8 +477,7 @@ static NfcCommand mf_ultralight_poller_handler_try_default_pass(MfUltralightPoll
|
|||||||
MF_ULTRALIGHT_DEFAULT_PASSWORD,
|
MF_ULTRALIGHT_DEFAULT_PASSWORD,
|
||||||
sizeof(MfUltralightAuthPassword),
|
sizeof(MfUltralightAuthPassword),
|
||||||
instance->auth_context.password.data);
|
instance->auth_context.password.data);
|
||||||
instance->error =
|
instance->error = mf_ultralight_poller_auth_pwd(instance, &instance->auth_context);
|
||||||
mf_ultralight_poller_async_auth_pwd(instance, &instance->auth_context);
|
|
||||||
if(instance->error == MfUltralightErrorNone) {
|
if(instance->error == MfUltralightErrorNone) {
|
||||||
FURI_LOG_D(TAG, "Default password detected");
|
FURI_LOG_D(TAG, "Default password detected");
|
||||||
nfc_util_num2bytes(
|
nfc_util_num2bytes(
|
||||||
@ -487,6 +485,7 @@ static NfcCommand mf_ultralight_poller_handler_try_default_pass(MfUltralightPoll
|
|||||||
sizeof(MfUltralightAuthPassword),
|
sizeof(MfUltralightAuthPassword),
|
||||||
config->password.data);
|
config->password.data);
|
||||||
config->pack = instance->auth_context.pack;
|
config->pack = instance->auth_context.pack;
|
||||||
|
instance->auth_context.auth_success = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -496,6 +495,9 @@ static NfcCommand mf_ultralight_poller_handler_try_default_pass(MfUltralightPoll
|
|||||||
// original card
|
// original card
|
||||||
config->auth0 = instance->pages_read;
|
config->auth0 = instance->pages_read;
|
||||||
config->access.prot = true;
|
config->access.prot = true;
|
||||||
|
} else if(!instance->auth_context.auth_success) {
|
||||||
|
instance->pages_read -= 2;
|
||||||
|
instance->data->pages_read -= 2;
|
||||||
}
|
}
|
||||||
} while(false);
|
} while(false);
|
||||||
|
|
||||||
@ -572,8 +574,7 @@ static bool mf_ultralight_poller_detect(NfcGenericEvent event, void* context) {
|
|||||||
|
|
||||||
if(iso14443_3a_event->type == Iso14443_3aPollerEventTypeReady) {
|
if(iso14443_3a_event->type == Iso14443_3aPollerEventTypeReady) {
|
||||||
MfUltralightPageReadCommandData read_page_cmd_data = {};
|
MfUltralightPageReadCommandData read_page_cmd_data = {};
|
||||||
MfUltralightError error =
|
MfUltralightError error = mf_ultralight_poller_read_page(instance, 0, &read_page_cmd_data);
|
||||||
mf_ultralight_poller_async_read_page(instance, 0, &read_page_cmd_data);
|
|
||||||
protocol_detected = (error == MfUltralightErrorNone);
|
protocol_detected = (error == MfUltralightErrorNone);
|
||||||
iso14443_3a_poller_halt(instance->iso14443_3a_poller);
|
iso14443_3a_poller_halt(instance->iso14443_3a_poller);
|
||||||
}
|
}
|
||||||
|
@ -7,35 +7,181 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief MfUltralightPoller opaque type definition.
|
||||||
|
*/
|
||||||
typedef struct MfUltralightPoller MfUltralightPoller;
|
typedef struct MfUltralightPoller MfUltralightPoller;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enumeration of possible MfUltralight poller event types.
|
||||||
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
MfUltralightPollerEventTypeAuthRequest,
|
MfUltralightPollerEventTypeAuthRequest, /**< Poller requests to fill authentication context. */
|
||||||
MfUltralightPollerEventTypeAuthSuccess,
|
MfUltralightPollerEventTypeAuthSuccess, /**< Authentication succeeded. */
|
||||||
MfUltralightPollerEventTypeAuthFailed,
|
MfUltralightPollerEventTypeAuthFailed, /**< Authentication failed. */
|
||||||
MfUltralightPollerEventTypeReadSuccess,
|
MfUltralightPollerEventTypeReadSuccess, /**< Poller read card successfully. */
|
||||||
MfUltralightPollerEventTypeReadFailed,
|
MfUltralightPollerEventTypeReadFailed, /**< Poller failed to read card. */
|
||||||
} MfUltralightPollerEventType;
|
} MfUltralightPollerEventType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief MfUltralight poller authentication context.
|
||||||
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
MfUltralightAuthPassword password;
|
MfUltralightAuthPassword password; /**< Password to be used for authentication. */
|
||||||
MfUltralightAuthPack pack;
|
MfUltralightAuthPack pack; /**< Pack received on successfull authentication. */
|
||||||
bool auth_success;
|
bool auth_success; /**< Set to true if authentication succeeded, false otherwise. */
|
||||||
bool skip_auth;
|
bool skip_auth; /**< Set to true if authentication should be skipped, false otherwise. */
|
||||||
} MfUltralightPollerAuthContext;
|
} MfUltralightPollerAuthContext;
|
||||||
|
|
||||||
typedef struct {
|
/**
|
||||||
union {
|
* @brief MfUltralight poller event data.
|
||||||
MfUltralightPollerAuthContext auth_context;
|
*/
|
||||||
MfUltralightError error;
|
typedef union {
|
||||||
};
|
MfUltralightPollerAuthContext auth_context; /**< Authentication context. */
|
||||||
|
MfUltralightError error; /**< Error code indicating reading fail reason. */
|
||||||
} MfUltralightPollerEventData;
|
} MfUltralightPollerEventData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief MfUltralight poller event structure.
|
||||||
|
*
|
||||||
|
* Upon emission of an event, an instance of this struct will be passed to the callback.
|
||||||
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
MfUltralightPollerEventType type;
|
MfUltralightPollerEventType type; /**< Type of emmitted event. */
|
||||||
MfUltralightPollerEventData* data;
|
MfUltralightPollerEventData* data; /**< Pointer to event specific data. */
|
||||||
} MfUltralightPollerEvent;
|
} MfUltralightPollerEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Perform authentication with password.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @param[in, out] data pointer to the authentication context.
|
||||||
|
* @return MfUltralightErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
MfUltralightError mf_ultralight_poller_auth_pwd(
|
||||||
|
MfUltralightPoller* instance,
|
||||||
|
MfUltralightPollerAuthContext* data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Start authentication procedure.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* This function now is used only to identify Mf Ultralight C cards.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @return MfUltralightErrorNone if card supports authentication command, an error code on otherwise.
|
||||||
|
*/
|
||||||
|
MfUltralightError mf_ultralight_poller_authenticate(MfUltralightPoller* instance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read page from card.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* Send read command and parse response. The response on this command is data of 4 pages starting
|
||||||
|
* from the page specified in the command.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @param[in] start_page page number to be read.
|
||||||
|
* @param[out] data pointer to the MfUltralightPageReadCommandData structure to be filled with page data.
|
||||||
|
* @return MfUltralightErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
MfUltralightError mf_ultralight_poller_read_page(
|
||||||
|
MfUltralightPoller* instance,
|
||||||
|
uint8_t start_page,
|
||||||
|
MfUltralightPageReadCommandData* data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read page from sector.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* This command should be used for NTAGI2C tags.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @param[in] sector sector number to be read.
|
||||||
|
* @param[in] tag tag number to be read.
|
||||||
|
* @param[out] data pointer to the MfUltralightPageReadCommandData structure to be filled with page data.
|
||||||
|
* @return MfUltralightErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
MfUltralightError mf_ultralight_poller_read_page_from_sector(
|
||||||
|
MfUltralightPoller* instance,
|
||||||
|
uint8_t sector,
|
||||||
|
uint8_t tag,
|
||||||
|
MfUltralightPageReadCommandData* data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Write page to card.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @param[in] page page number to be written.
|
||||||
|
* @param[in] data pointer to the MfUltralightPage structure to be written.
|
||||||
|
* @return MfUltralightErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
MfUltralightError mf_ultralight_poller_write_page(
|
||||||
|
MfUltralightPoller* instance,
|
||||||
|
uint8_t page,
|
||||||
|
const MfUltralightPage* data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read version from card.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @param[out] data pointer to the MfUltralightVersion structure to be filled.
|
||||||
|
* @return MfUltralightErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
MfUltralightError
|
||||||
|
mf_ultralight_poller_read_version(MfUltralightPoller* instance, MfUltralightVersion* data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read signature from card.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @param[out] data pointer to the MfUltralightSignature structure to be filled.
|
||||||
|
* @return MfUltralightErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
MfUltralightError
|
||||||
|
mf_ultralight_poller_read_signature(MfUltralightPoller* instance, MfUltralightSignature* data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read counter from card.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @param[in] counter_num counter number to be read.
|
||||||
|
* @param[out] data pointer to the MfUltralightCounter structure to be filled.
|
||||||
|
* @return MfUltralightErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
MfUltralightError mf_ultralight_poller_read_counter(
|
||||||
|
MfUltralightPoller* instance,
|
||||||
|
uint8_t counter_num,
|
||||||
|
MfUltralightCounter* data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read tearing flag from card.
|
||||||
|
*
|
||||||
|
* Must ONLY be used inside the callback function.
|
||||||
|
*
|
||||||
|
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||||
|
* @param[in] tearing_falg_num tearing flag number to be read.
|
||||||
|
* @param[out] data pointer to the MfUltralightTearingFlag structure to be filled.
|
||||||
|
* @return MfUltralightErrorNone on success, an error code on failure.
|
||||||
|
*/
|
||||||
|
MfUltralightError mf_ultralight_poller_read_tearing_flag(
|
||||||
|
MfUltralightPoller* instance,
|
||||||
|
uint8_t tearing_falg_num,
|
||||||
|
MfUltralightTearingFlag* data);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -30,7 +30,7 @@ MfUltralightError mf_ultralight_process_error(Iso14443_3aError error) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
MfUltralightError mf_ultralight_poller_async_auth_pwd(
|
MfUltralightError mf_ultralight_poller_auth_pwd(
|
||||||
MfUltralightPoller* instance,
|
MfUltralightPoller* instance,
|
||||||
MfUltralightPollerAuthContext* data) {
|
MfUltralightPollerAuthContext* data) {
|
||||||
uint8_t auth_cmd[5] = {MF_ULTRALIGHT_CMD_PWD_AUTH}; //-V1009
|
uint8_t auth_cmd[5] = {MF_ULTRALIGHT_CMD_PWD_AUTH}; //-V1009
|
||||||
@ -59,7 +59,7 @@ MfUltralightError mf_ultralight_poller_async_auth_pwd(
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
MfUltralightError mf_ultralight_poller_async_authenticate(MfUltralightPoller* instance) {
|
MfUltralightError mf_ultralight_poller_authenticate(MfUltralightPoller* instance) {
|
||||||
uint8_t auth_cmd[2] = {MF_ULTRALIGHT_CMD_AUTH, 0x00};
|
uint8_t auth_cmd[2] = {MF_ULTRALIGHT_CMD_AUTH, 0x00};
|
||||||
bit_buffer_copy_bytes(instance->tx_buffer, auth_cmd, sizeof(auth_cmd));
|
bit_buffer_copy_bytes(instance->tx_buffer, auth_cmd, sizeof(auth_cmd));
|
||||||
|
|
||||||
@ -86,7 +86,7 @@ MfUltralightError mf_ultralight_poller_async_authenticate(MfUltralightPoller* in
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
MfUltralightError mf_ultralight_poller_async_read_page_from_sector(
|
MfUltralightError mf_ultralight_poller_read_page_from_sector(
|
||||||
MfUltralightPoller* instance,
|
MfUltralightPoller* instance,
|
||||||
uint8_t sector,
|
uint8_t sector,
|
||||||
uint8_t tag,
|
uint8_t tag,
|
||||||
@ -122,13 +122,13 @@ MfUltralightError mf_ultralight_poller_async_read_page_from_sector(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = mf_ultralight_poller_async_read_page(instance, tag, data);
|
ret = mf_ultralight_poller_read_page(instance, tag, data);
|
||||||
} while(false);
|
} while(false);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
MfUltralightError mf_ultralight_poller_async_read_page(
|
MfUltralightError mf_ultralight_poller_read_page(
|
||||||
MfUltralightPoller* instance,
|
MfUltralightPoller* instance,
|
||||||
uint8_t start_page,
|
uint8_t start_page,
|
||||||
MfUltralightPageReadCommandData* data) {
|
MfUltralightPageReadCommandData* data) {
|
||||||
@ -158,10 +158,10 @@ MfUltralightError mf_ultralight_poller_async_read_page(
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
MfUltralightError mf_ultralight_poller_async_write_page(
|
MfUltralightError mf_ultralight_poller_write_page(
|
||||||
MfUltralightPoller* instance,
|
MfUltralightPoller* instance,
|
||||||
uint8_t page,
|
uint8_t page,
|
||||||
MfUltralightPage* data) {
|
const MfUltralightPage* data) {
|
||||||
MfUltralightError ret = MfUltralightErrorNone;
|
MfUltralightError ret = MfUltralightErrorNone;
|
||||||
Iso14443_3aError error = Iso14443_3aErrorNone;
|
Iso14443_3aError error = Iso14443_3aErrorNone;
|
||||||
|
|
||||||
@ -191,9 +191,8 @@ MfUltralightError mf_ultralight_poller_async_write_page(
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
MfUltralightError mf_ultralight_poller_async_read_version(
|
MfUltralightError
|
||||||
MfUltralightPoller* instance,
|
mf_ultralight_poller_read_version(MfUltralightPoller* instance, MfUltralightVersion* data) {
|
||||||
MfUltralightVersion* data) {
|
|
||||||
MfUltralightError ret = MfUltralightErrorNone;
|
MfUltralightError ret = MfUltralightErrorNone;
|
||||||
Iso14443_3aError error = Iso14443_3aErrorNone;
|
Iso14443_3aError error = Iso14443_3aErrorNone;
|
||||||
|
|
||||||
@ -221,9 +220,8 @@ MfUltralightError mf_ultralight_poller_async_read_version(
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
MfUltralightError mf_ultralight_poller_async_read_signature(
|
MfUltralightError
|
||||||
MfUltralightPoller* instance,
|
mf_ultralight_poller_read_signature(MfUltralightPoller* instance, MfUltralightSignature* data) {
|
||||||
MfUltralightSignature* data) {
|
|
||||||
MfUltralightError ret = MfUltralightErrorNone;
|
MfUltralightError ret = MfUltralightErrorNone;
|
||||||
Iso14443_3aError error = Iso14443_3aErrorNone;
|
Iso14443_3aError error = Iso14443_3aErrorNone;
|
||||||
|
|
||||||
@ -249,7 +247,7 @@ MfUltralightError mf_ultralight_poller_async_read_signature(
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
MfUltralightError mf_ultralight_poller_async_read_counter(
|
MfUltralightError mf_ultralight_poller_read_counter(
|
||||||
MfUltralightPoller* instance,
|
MfUltralightPoller* instance,
|
||||||
uint8_t counter_num,
|
uint8_t counter_num,
|
||||||
MfUltralightCounter* data) {
|
MfUltralightCounter* data) {
|
||||||
@ -278,7 +276,7 @@ MfUltralightError mf_ultralight_poller_async_read_counter(
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
MfUltralightError mf_ultralight_poller_async_read_tearing_flag(
|
MfUltralightError mf_ultralight_poller_read_tearing_flag(
|
||||||
MfUltralightPoller* instance,
|
MfUltralightPoller* instance,
|
||||||
uint8_t tearing_falg_num,
|
uint8_t tearing_falg_num,
|
||||||
MfUltralightTearingFlag* data) {
|
MfUltralightTearingFlag* data) {
|
||||||
|
@ -103,46 +103,6 @@ bool mf_ultralight_poller_ntag_i2c_addr_lin_to_tag(
|
|||||||
uint8_t* tag,
|
uint8_t* tag,
|
||||||
uint8_t* pages_left);
|
uint8_t* pages_left);
|
||||||
|
|
||||||
MfUltralightError mf_ultralight_poller_async_auth_pwd(
|
|
||||||
MfUltralightPoller* instance,
|
|
||||||
MfUltralightPollerAuthContext* data);
|
|
||||||
|
|
||||||
MfUltralightError mf_ultralight_poller_async_authenticate(MfUltralightPoller* instance);
|
|
||||||
|
|
||||||
MfUltralightError mf_ultralight_poller_async_read_page(
|
|
||||||
MfUltralightPoller* instance,
|
|
||||||
uint8_t start_page,
|
|
||||||
MfUltralightPageReadCommandData* data);
|
|
||||||
|
|
||||||
MfUltralightError mf_ultralight_poller_async_read_page_from_sector(
|
|
||||||
MfUltralightPoller* instance,
|
|
||||||
uint8_t sector,
|
|
||||||
uint8_t tag,
|
|
||||||
MfUltralightPageReadCommandData* data);
|
|
||||||
|
|
||||||
MfUltralightError mf_ultralight_poller_async_write_page(
|
|
||||||
MfUltralightPoller* instance,
|
|
||||||
uint8_t page,
|
|
||||||
MfUltralightPage* data);
|
|
||||||
|
|
||||||
MfUltralightError mf_ultralight_poller_async_read_version(
|
|
||||||
MfUltralightPoller* instance,
|
|
||||||
MfUltralightVersion* data);
|
|
||||||
|
|
||||||
MfUltralightError mf_ultralight_poller_async_read_signature(
|
|
||||||
MfUltralightPoller* instance,
|
|
||||||
MfUltralightSignature* data);
|
|
||||||
|
|
||||||
MfUltralightError mf_ultralight_poller_async_read_counter(
|
|
||||||
MfUltralightPoller* instance,
|
|
||||||
uint8_t counter_num,
|
|
||||||
MfUltralightCounter* data);
|
|
||||||
|
|
||||||
MfUltralightError mf_ultralight_poller_async_read_tearing_flag(
|
|
||||||
MfUltralightPoller* instance,
|
|
||||||
uint8_t tearing_falg_num,
|
|
||||||
MfUltralightTearingFlag* data);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
#include "mf_ultralight_poller_sync.h"
|
||||||
#include "mf_ultralight_poller_i.h"
|
#include "mf_ultralight_poller_i.h"
|
||||||
|
|
||||||
#include <nfc/nfc_poller.h>
|
#include <nfc/nfc_poller.h>
|
||||||
@ -31,40 +32,39 @@ typedef MfUltralightError (*MfUltralightPollerCmdHandler)(
|
|||||||
MfUltralightError mf_ultralight_poller_read_page_handler(
|
MfUltralightError mf_ultralight_poller_read_page_handler(
|
||||||
MfUltralightPoller* poller,
|
MfUltralightPoller* poller,
|
||||||
MfUltralightPollerContextData* data) {
|
MfUltralightPollerContextData* data) {
|
||||||
return mf_ultralight_poller_async_read_page(
|
return mf_ultralight_poller_read_page(poller, data->read_cmd.start_page, &data->read_cmd.data);
|
||||||
poller, data->read_cmd.start_page, &data->read_cmd.data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MfUltralightError mf_ultralight_poller_write_page_handler(
|
MfUltralightError mf_ultralight_poller_write_page_handler(
|
||||||
MfUltralightPoller* poller,
|
MfUltralightPoller* poller,
|
||||||
MfUltralightPollerContextData* data) {
|
MfUltralightPollerContextData* data) {
|
||||||
return mf_ultralight_poller_async_write_page(
|
return mf_ultralight_poller_write_page(
|
||||||
poller, data->write_cmd.page_to_write, &data->write_cmd.page);
|
poller, data->write_cmd.page_to_write, &data->write_cmd.page);
|
||||||
}
|
}
|
||||||
|
|
||||||
MfUltralightError mf_ultralight_poller_read_version_handler(
|
MfUltralightError mf_ultralight_poller_read_version_handler(
|
||||||
MfUltralightPoller* poller,
|
MfUltralightPoller* poller,
|
||||||
MfUltralightPollerContextData* data) {
|
MfUltralightPollerContextData* data) {
|
||||||
return mf_ultralight_poller_async_read_version(poller, &data->version);
|
return mf_ultralight_poller_read_version(poller, &data->version);
|
||||||
}
|
}
|
||||||
|
|
||||||
MfUltralightError mf_ultralight_poller_read_signature_handler(
|
MfUltralightError mf_ultralight_poller_read_signature_handler(
|
||||||
MfUltralightPoller* poller,
|
MfUltralightPoller* poller,
|
||||||
MfUltralightPollerContextData* data) {
|
MfUltralightPollerContextData* data) {
|
||||||
return mf_ultralight_poller_async_read_signature(poller, &data->signature);
|
return mf_ultralight_poller_read_signature(poller, &data->signature);
|
||||||
}
|
}
|
||||||
|
|
||||||
MfUltralightError mf_ultralight_poller_read_counter_handler(
|
MfUltralightError mf_ultralight_poller_read_counter_handler(
|
||||||
MfUltralightPoller* poller,
|
MfUltralightPoller* poller,
|
||||||
MfUltralightPollerContextData* data) {
|
MfUltralightPollerContextData* data) {
|
||||||
return mf_ultralight_poller_async_read_counter(
|
return mf_ultralight_poller_read_counter(
|
||||||
poller, data->counter_cmd.counter_num, &data->counter_cmd.data);
|
poller, data->counter_cmd.counter_num, &data->counter_cmd.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
MfUltralightError mf_ultralight_poller_read_tearing_flag_handler(
|
MfUltralightError mf_ultralight_poller_read_tearing_flag_handler(
|
||||||
MfUltralightPoller* poller,
|
MfUltralightPoller* poller,
|
||||||
MfUltralightPollerContextData* data) {
|
MfUltralightPollerContextData* data) {
|
||||||
return mf_ultralight_poller_async_read_tearing_flag(
|
return mf_ultralight_poller_read_tearing_flag(
|
||||||
poller, data->tearing_flag_cmd.tearing_flag_num, &data->tearing_flag_cmd.data);
|
poller, data->tearing_flag_cmd.tearing_flag_num, &data->tearing_flag_cmd.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,16 +79,14 @@ static const MfUltralightPollerCmdHandler
|
|||||||
mf_ultralight_poller_read_tearing_flag_handler,
|
mf_ultralight_poller_read_tearing_flag_handler,
|
||||||
};
|
};
|
||||||
|
|
||||||
static NfcCommand mf_ultralight_poller_cmd_callback(NfcGenericEvent event, void* context) {
|
static NfcCommand mf_ultralight_poller_cmd_callback(NfcGenericEventEx event, void* context) {
|
||||||
furi_assert(event.instance);
|
furi_assert(event.poller);
|
||||||
furi_assert(event.protocol == NfcProtocolIso14443_3a);
|
furi_assert(event.parent_event_data);
|
||||||
furi_assert(event.event_data);
|
|
||||||
furi_assert(context);
|
furi_assert(context);
|
||||||
|
|
||||||
MfUltralightPollerContext* poller_context = context;
|
MfUltralightPollerContext* poller_context = context;
|
||||||
Iso14443_3aPollerEvent* iso14443_3a_event = event.event_data;
|
Iso14443_3aPollerEvent* iso14443_3a_event = event.parent_event_data;
|
||||||
Iso14443_3aPoller* iso14443_3a_poller = event.instance;
|
MfUltralightPoller* mfu_poller = event.poller;
|
||||||
MfUltralightPoller* mfu_poller = mf_ultralight_poller_alloc(iso14443_3a_poller);
|
|
||||||
|
|
||||||
if(iso14443_3a_event->type == Iso14443_3aPollerEventTypeReady) {
|
if(iso14443_3a_event->type == Iso14443_3aPollerEventTypeReady) {
|
||||||
poller_context->error = mf_ultralight_poller_cmd_handlers[poller_context->cmd_type](
|
poller_context->error = mf_ultralight_poller_cmd_handlers[poller_context->cmd_type](
|
||||||
@ -99,8 +97,6 @@ static NfcCommand mf_ultralight_poller_cmd_callback(NfcGenericEvent event, void*
|
|||||||
|
|
||||||
furi_thread_flags_set(poller_context->thread_id, MF_ULTRALIGHT_POLLER_COMPLETE_EVENT);
|
furi_thread_flags_set(poller_context->thread_id, MF_ULTRALIGHT_POLLER_COMPLETE_EVENT);
|
||||||
|
|
||||||
mf_ultralight_poller_free(mfu_poller);
|
|
||||||
|
|
||||||
return NfcCommandStop;
|
return NfcCommandStop;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,8 +106,8 @@ static MfUltralightError
|
|||||||
|
|
||||||
poller_ctx->thread_id = furi_thread_get_current_id();
|
poller_ctx->thread_id = furi_thread_get_current_id();
|
||||||
|
|
||||||
NfcPoller* poller = nfc_poller_alloc(nfc, NfcProtocolIso14443_3a);
|
NfcPoller* poller = nfc_poller_alloc(nfc, NfcProtocolMfUltralight);
|
||||||
nfc_poller_start(poller, mf_ultralight_poller_cmd_callback, poller_ctx);
|
nfc_poller_start_ex(poller, mf_ultralight_poller_cmd_callback, poller_ctx);
|
||||||
furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever);
|
furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever);
|
||||||
furi_thread_flags_clear(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT);
|
furi_thread_flags_clear(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT);
|
||||||
|
|
||||||
@ -121,7 +117,8 @@ static MfUltralightError
|
|||||||
return poller_ctx->error;
|
return poller_ctx->error;
|
||||||
}
|
}
|
||||||
|
|
||||||
MfUltralightError mf_ultralight_poller_read_page(Nfc* nfc, uint16_t page, MfUltralightPage* data) {
|
MfUltralightError
|
||||||
|
mf_ultralight_poller_sync_read_page(Nfc* nfc, uint16_t page, MfUltralightPage* data) {
|
||||||
furi_assert(nfc);
|
furi_assert(nfc);
|
||||||
furi_assert(data);
|
furi_assert(data);
|
||||||
|
|
||||||
@ -140,7 +137,7 @@ MfUltralightError mf_ultralight_poller_read_page(Nfc* nfc, uint16_t page, MfUltr
|
|||||||
}
|
}
|
||||||
|
|
||||||
MfUltralightError
|
MfUltralightError
|
||||||
mf_ultralight_poller_write_page(Nfc* nfc, uint16_t page, MfUltralightPage* data) {
|
mf_ultralight_poller_sync_write_page(Nfc* nfc, uint16_t page, MfUltralightPage* data) {
|
||||||
furi_assert(nfc);
|
furi_assert(nfc);
|
||||||
furi_assert(data);
|
furi_assert(data);
|
||||||
|
|
||||||
@ -158,7 +155,7 @@ MfUltralightError
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
MfUltralightError mf_ultralight_poller_read_version(Nfc* nfc, MfUltralightVersion* data) {
|
MfUltralightError mf_ultralight_poller_sync_read_version(Nfc* nfc, MfUltralightVersion* data) {
|
||||||
furi_assert(nfc);
|
furi_assert(nfc);
|
||||||
furi_assert(data);
|
furi_assert(data);
|
||||||
|
|
||||||
@ -175,7 +172,7 @@ MfUltralightError mf_ultralight_poller_read_version(Nfc* nfc, MfUltralightVersio
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
MfUltralightError mf_ultralight_poller_read_signature(Nfc* nfc, MfUltralightSignature* data) {
|
MfUltralightError mf_ultralight_poller_sync_read_signature(Nfc* nfc, MfUltralightSignature* data) {
|
||||||
furi_assert(nfc);
|
furi_assert(nfc);
|
||||||
furi_assert(data);
|
furi_assert(data);
|
||||||
|
|
||||||
@ -192,8 +189,10 @@ MfUltralightError mf_ultralight_poller_read_signature(Nfc* nfc, MfUltralightSign
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
MfUltralightError
|
MfUltralightError mf_ultralight_poller_sync_read_counter(
|
||||||
mf_ultralight_poller_read_counter(Nfc* nfc, uint8_t counter_num, MfUltralightCounter* data) {
|
Nfc* nfc,
|
||||||
|
uint8_t counter_num,
|
||||||
|
MfUltralightCounter* data) {
|
||||||
furi_assert(nfc);
|
furi_assert(nfc);
|
||||||
furi_assert(data);
|
furi_assert(data);
|
||||||
|
|
||||||
@ -211,7 +210,7 @@ MfUltralightError
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
MfUltralightError mf_ultralight_poller_read_tearing_flag(
|
MfUltralightError mf_ultralight_poller_sync_read_tearing_flag(
|
||||||
Nfc* nfc,
|
Nfc* nfc,
|
||||||
uint8_t flag_num,
|
uint8_t flag_num,
|
||||||
MfUltralightTearingFlag* data) {
|
MfUltralightTearingFlag* data) {
|
||||||
@ -261,7 +260,7 @@ static NfcCommand mf_ultralight_poller_read_callback(NfcGenericEvent event, void
|
|||||||
return command;
|
return command;
|
||||||
}
|
}
|
||||||
|
|
||||||
MfUltralightError mf_ultralight_poller_read_card(Nfc* nfc, MfUltralightData* data) {
|
MfUltralightError mf_ultralight_poller_sync_read_card(Nfc* nfc, MfUltralightData* data) {
|
||||||
furi_assert(nfc);
|
furi_assert(nfc);
|
||||||
furi_assert(data);
|
furi_assert(data);
|
||||||
|
|
34
lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync.h
Normal file
34
lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "mf_ultralight.h"
|
||||||
|
#include <nfc/nfc.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
MfUltralightError
|
||||||
|
mf_ultralight_poller_sync_read_page(Nfc* nfc, uint16_t page, MfUltralightPage* data);
|
||||||
|
|
||||||
|
MfUltralightError
|
||||||
|
mf_ultralight_poller_sync_write_page(Nfc* nfc, uint16_t page, MfUltralightPage* data);
|
||||||
|
|
||||||
|
MfUltralightError mf_ultralight_poller_sync_read_version(Nfc* nfc, MfUltralightVersion* data);
|
||||||
|
|
||||||
|
MfUltralightError mf_ultralight_poller_sync_read_signature(Nfc* nfc, MfUltralightSignature* data);
|
||||||
|
|
||||||
|
MfUltralightError mf_ultralight_poller_sync_read_counter(
|
||||||
|
Nfc* nfc,
|
||||||
|
uint8_t counter_num,
|
||||||
|
MfUltralightCounter* data);
|
||||||
|
|
||||||
|
MfUltralightError mf_ultralight_poller_sync_read_tearing_flag(
|
||||||
|
Nfc* nfc,
|
||||||
|
uint8_t flag_num,
|
||||||
|
MfUltralightTearingFlag* data);
|
||||||
|
|
||||||
|
MfUltralightError mf_ultralight_poller_sync_read_card(Nfc* nfc, MfUltralightData* data);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
@ -1,30 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "mf_ultralight.h"
|
|
||||||
#include <nfc/nfc.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
MfUltralightError mf_ultralight_poller_read_page(Nfc* nfc, uint16_t page, MfUltralightPage* data);
|
|
||||||
|
|
||||||
MfUltralightError mf_ultralight_poller_write_page(Nfc* nfc, uint16_t page, MfUltralightPage* data);
|
|
||||||
|
|
||||||
MfUltralightError mf_ultralight_poller_read_version(Nfc* nfc, MfUltralightVersion* data);
|
|
||||||
|
|
||||||
MfUltralightError mf_ultralight_poller_read_signature(Nfc* nfc, MfUltralightSignature* data);
|
|
||||||
|
|
||||||
MfUltralightError
|
|
||||||
mf_ultralight_poller_read_counter(Nfc* nfc, uint8_t counter_num, MfUltralightCounter* data);
|
|
||||||
|
|
||||||
MfUltralightError mf_ultralight_poller_read_tearing_flag(
|
|
||||||
Nfc* nfc,
|
|
||||||
uint8_t flag_num,
|
|
||||||
MfUltralightTearingFlag* data);
|
|
||||||
|
|
||||||
MfUltralightError mf_ultralight_poller_read_card(Nfc* nfc, MfUltralightData* data);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
@ -61,9 +61,9 @@
|
|||||||
* | |
|
* | |
|
||||||
* +- protocol_name_listener_defs.h |
|
* +- protocol_name_listener_defs.h |
|
||||||
* |
|
* |
|
||||||
* +- protocol_name_sync_api.h |
|
* +- protocol_name_sync.h |
|
||||||
* | |- add for synchronous API support
|
* | |- add for synchronous API support
|
||||||
* +- protocol_name_sync_api.c |
|
* +- protocol_name_sync.c |
|
||||||
* |
|
* |
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
@ -83,8 +83,8 @@
|
|||||||
* | protocol_name_listener.h | Protocol-specific listener and associated functions declarations. Optional, needed for emulation support. |
|
* | protocol_name_listener.h | Protocol-specific listener and associated functions declarations. Optional, needed for emulation support. |
|
||||||
* | protocol_name_listener.c | Implementation of functions declared in `protocol_name_listener.h`. Optional, needed for emulation support. |
|
* | protocol_name_listener.c | Implementation of functions declared in `protocol_name_listener.h`. Optional, needed for emulation support. |
|
||||||
* | protocol_name_listener_defs.h | Declarations for use by the NfcListener library. See nfc_listener_base.h for more info. Optional, needed for emulation support. |
|
* | protocol_name_listener_defs.h | Declarations for use by the NfcListener library. See nfc_listener_base.h for more info. Optional, needed for emulation support. |
|
||||||
* | protocol_name_sync_api.h | Synchronous API declarations. (See below for sync API explanation). Optional.|
|
* | protocol_name_sync.h | Synchronous API declarations. (See below for sync API explanation). Optional.|
|
||||||
* | protocol_name_sync_api.c | Synchronous API implementation. Optional. |
|
* | protocol_name_sync.c | Synchronous API implementation. Optional. |
|
||||||
*
|
*
|
||||||
* ## 3 Implement the code
|
* ## 3 Implement the code
|
||||||
*
|
*
|
||||||
@ -145,7 +145,7 @@
|
|||||||
* `protocol_name_poller_defs` structure under the appropriate index.
|
* `protocol_name_poller_defs` structure under the appropriate index.
|
||||||
* 5. (Optional) If emulation support was implemented, do the step 4, but for the listener.
|
* 5. (Optional) If emulation support was implemented, do the step 4, but for the listener.
|
||||||
* 6. Add `protocol_name.h`, `protocol_name_poller.h`, and optionally, `protocol_name_listener.h`
|
* 6. Add `protocol_name.h`, `protocol_name_poller.h`, and optionally, `protocol_name_listener.h`
|
||||||
* and `protocol_name_sync_api.h` into the `SDK_HEADERS` list in the SConscript file.
|
* and `protocol_name_sync.h` into the `SDK_HEADERS` list in the SConscript file.
|
||||||
* This will export the protocol's types and functions for use by the applications.
|
* This will export the protocol's types and functions for use by the applications.
|
||||||
* 7. Done!
|
* 7. Done!
|
||||||
*
|
*
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user