From dc246ddb0958b17707b4dad9e8e1609f3517d662 Mon Sep 17 00:00:00 2001 From: Tobias Jost Date: Wed, 15 Nov 2023 08:39:29 +0100 Subject: [PATCH 1/9] Fix limited_credit_value having wrong value in mf_desfire_file_settings_parse (#3204) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: hedger Co-authored-by: あく --- lib/nfc/protocols/mf_desfire/mf_desfire_i.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_i.c b/lib/nfc/protocols/mf_desfire/mf_desfire_i.c index 30313ae2b..129dcdf5e 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_i.c +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_i.c @@ -201,7 +201,7 @@ bool mf_desfire_file_settings_parse(MfDesfireFileSettings* data, const BitBuffer data->value.lo_limit = layout.value.lo_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; } else if( From d0b9a3a4ae7abbb1a0e97616226d2b77d86f08e7 Mon Sep 17 00:00:00 2001 From: RebornedBrain <138568282+RebornedBrain@users.noreply.github.com> Date: Wed, 15 Nov 2023 11:02:35 +0300 Subject: [PATCH 2/9] [NFC] MF Ultralight no pwd polling adjustment (#3207) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Listener log level changed to Trace * Show pages count without pwd pages in case of no auth success * Fixed unit tests Co-authored-by: gornekich Co-authored-by: あく --- applications/debug/unit_tests/nfc/nfc_test.c | 19 +++++++++--- .../mf_ultralight/mf_ultralight_listener.c | 30 +++++++++---------- .../mf_ultralight/mf_ultralight_poller.c | 4 +++ 3 files changed, 34 insertions(+), 19 deletions(-) diff --git a/applications/debug/unit_tests/nfc/nfc_test.c b/applications/debug/unit_tests/nfc/nfc_test.c index 2d647f8ef..ce5a9cb9c 100644 --- a/applications/debug/unit_tests/nfc/nfc_test.c +++ b/applications/debug/unit_tests/nfc/nfc_test.c @@ -203,10 +203,21 @@ static void mf_ultralight_reader_test(const char* path) { NfcDevice* nfc_device = nfc_device_alloc(); mu_assert(nfc_device_load(nfc_device, path), "nfc_device_load() failed\r\n"); - NfcListener* mfu_listener = nfc_listener_alloc( - listener, - NfcProtocolMfUltralight, - nfc_device_get_data(nfc_device, NfcProtocolMfUltralight)); + MfUltralightData* data = + (MfUltralightData*)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); MfUltralightData* mfu_data = mf_ultralight_alloc(); diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c index 70c6f6de2..5bef2a354 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c @@ -122,7 +122,7 @@ static MfUltralightCommand uint16_t pages_total = instance->data->pages_total; MfUltralightCommand command = MfUltralightCommandNotProcessedNAK; - FURI_LOG_D(TAG, "CMD_READ: %d", start_page); + FURI_LOG_T(TAG, "CMD_READ: %d", start_page); do { bool do_i2c_check = mf_ultralight_is_i2c_tag(instance->data->type); @@ -154,7 +154,7 @@ static MfUltralightCommand static MfUltralightCommand mf_ultralight_listener_fast_read_handler(MfUltralightListener* instance, BitBuffer* buffer) { MfUltralightCommand command = MfUltralightCommandNotProcessedSilent; - FURI_LOG_D(TAG, "CMD_FAST_READ"); + FURI_LOG_T(TAG, "CMD_FAST_READ"); do { if(!mf_ultralight_support_feature(instance->features, MfUltralightFeatureSupportFastRead)) @@ -206,7 +206,7 @@ static MfUltralightCommand uint16_t pages_total = instance->data->pages_total; MfUltralightCommand command = MfUltralightCommandNotProcessedNAK; - FURI_LOG_D(TAG, "CMD_WRITE"); + FURI_LOG_T(TAG, "CMD_WRITE"); do { bool do_i2c_check = mf_ultralight_is_i2c_tag(instance->data->type); @@ -235,7 +235,7 @@ static MfUltralightCommand static MfUltralightCommand mf_ultralight_listener_fast_write_handler(MfUltralightListener* instance, BitBuffer* buffer) { MfUltralightCommand command = MfUltralightCommandNotProcessedSilent; - FURI_LOG_D(TAG, "CMD_FAST_WRITE"); + FURI_LOG_T(TAG, "CMD_FAST_WRITE"); do { if(!mf_ultralight_support_feature(instance->features, MfUltralightFeatureSupportFastWrite)) @@ -261,7 +261,7 @@ static MfUltralightCommand UNUSED(buffer); 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)) { bit_buffer_copy_bytes( @@ -280,7 +280,7 @@ static MfUltralightCommand mf_ultralight_listener_read_signature_handler( UNUSED(buffer); 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)) { bit_buffer_copy_bytes( @@ -297,7 +297,7 @@ static MfUltralightCommand mf_ultralight_listener_read_counter_handler(MfUltralightListener* instance, BitBuffer* buffer) { MfUltralightCommand command = MfUltralightCommandNotProcessedNAK; - FURI_LOG_D(TAG, "CMD_READ_CNT"); + FURI_LOG_T(TAG, "CMD_READ_CNT"); do { uint8_t counter_num = bit_buffer_get_byte(buffer, 1); @@ -338,7 +338,7 @@ static MfUltralightCommand mf_ultralight_listener_increase_counter_handler( BitBuffer* buffer) { MfUltralightCommand command = MfUltralightCommandNotProcessedNAK; - FURI_LOG_D(TAG, "CMD_INCR_CNT"); + FURI_LOG_T(TAG, "CMD_INCR_CNT"); do { if(!mf_ultralight_support_feature( @@ -374,7 +374,7 @@ static MfUltralightCommand mf_ultralight_listener_check_tearing_handler( BitBuffer* buffer) { MfUltralightCommand command = MfUltralightCommandNotProcessedNAK; - FURI_LOG_D(TAG, "CMD_CHECK_TEARING"); + FURI_LOG_T(TAG, "CMD_CHECK_TEARING"); do { uint8_t tearing_flag_num = bit_buffer_get_byte(buffer, 1); @@ -410,7 +410,7 @@ static MfUltralightCommand MfUltralightCommand command = MfUltralightCommandNotProcessedSilent; UNUSED(instance); UNUSED(buffer); - FURI_LOG_D(TAG, "CMD_VCSL"); + FURI_LOG_T(TAG, "CMD_VCSL"); do { if(!mf_ultralight_support_feature(instance->features, MfUltralightFeatureSupportVcsl)) break; @@ -432,7 +432,7 @@ static MfUltralightCommand mf_ultralight_listener_auth_handler(MfUltralightListener* instance, BitBuffer* buffer) { MfUltralightCommand command = MfUltralightCommandNotProcessedNAK; - FURI_LOG_D(TAG, "CMD_AUTH"); + FURI_LOG_T(TAG, "CMD_AUTH"); do { if(!mf_ultralight_support_feature( @@ -474,7 +474,7 @@ static MfUltralightCommand static MfUltralightCommand mf_ultralight_comp_write_handler_p2(MfUltralightListener* instance, BitBuffer* buffer) { MfUltralightCommand command = MfUltralightCommandNotProcessedNAK; - FURI_LOG_D(TAG, "CMD_CM_WR_2"); + FURI_LOG_T(TAG, "CMD_CM_WR_2"); do { 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) { MfUltralightCommand command = MfUltralightCommandNotProcessedSilent; - FURI_LOG_D(TAG, "CMD_CM_WR_1"); + FURI_LOG_T(TAG, "CMD_CM_WR_1"); do { if(!mf_ultralight_support_feature( @@ -532,7 +532,7 @@ static MfUltralightCommand MfUltralightCommand command = MfUltralightCommandNotProcessedNAK; UNUSED(instance); UNUSED(buffer); - FURI_LOG_D(TAG, "CMD_SEC_SEL_2"); + FURI_LOG_T(TAG, "CMD_SEC_SEL_2"); do { 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) { MfUltralightCommand command = MfUltralightCommandNotProcessedNAK; UNUSED(buffer); - FURI_LOG_D(TAG, "CMD_SEC_SEL_1"); + FURI_LOG_T(TAG, "CMD_SEC_SEL_1"); do { if(!mf_ultralight_support_feature( diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c index bf0ced38d..4ad7bc147 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c @@ -487,6 +487,7 @@ static NfcCommand mf_ultralight_poller_handler_try_default_pass(MfUltralightPoll sizeof(MfUltralightAuthPassword), config->password.data); config->pack = instance->auth_context.pack; + instance->auth_context.auth_success = true; } } @@ -496,6 +497,9 @@ static NfcCommand mf_ultralight_poller_handler_try_default_pass(MfUltralightPoll // original card config->auth0 = instance->pages_read; config->access.prot = true; + } else if(!instance->auth_context.auth_success) { + instance->pages_read -= 2; + instance->data->pages_read -= 2; } } while(false); From c00776ca2279a86a62c253cfd2c3a910dabd7795 Mon Sep 17 00:00:00 2001 From: gornekich Date: Wed, 15 Nov 2023 12:32:45 +0400 Subject: [PATCH 3/9] [FL-3666] NFC API improvements (#3214) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * drivers: expose st25r3916 driver API * nfc poller: add start with custom callback * mf classic: rework sync API with poller custom start * mf ultralight: rework sync API with poller custom start * iso14443_3a poller: remove unused col res state * nfc: rework nfc poller custom start * mf ultralight: rename sync API * mf classic: rename sync API * iso14443-3a: rename sync API * nfc: remove async prefix in internal functions * nfc: expose internal API * nfc: fix sync api include and docs * targets: fix f18 build * nfc: rework NfcGenericEventEx type * nfc poller: add documentation * iso14443-3a poller: add documentation * felica poller: add documentation * iso14443_3b poller: add documentation * so14443_4a poller: add documentation * iso14443_4b poller: add documentation * iso15693 poller: add documentation * slix poller: add documentation * mf desfire poller: add documentation * mf ultralight poller: fix API and add documentation * mf classic poller: add documentation Co-authored-by: あく --- applications/debug/unit_tests/nfc/nfc_test.c | 44 +-- .../nfc/plugins/supported_cards/plantain.c | 8 +- .../main/nfc/plugins/supported_cards/troika.c | 8 +- .../nfc/plugins/supported_cards/two_cities.c | 8 +- lib/drivers/SConscript | 2 + lib/nfc/SConscript | 6 +- lib/nfc/nfc_poller.c | 72 +++++ lib/nfc/nfc_poller.h | 37 +++ lib/nfc/protocols/felica/felica_poller.c | 4 +- lib/nfc/protocols/felica/felica_poller.h | 40 ++- lib/nfc/protocols/felica/felica_poller_i.c | 6 +- lib/nfc/protocols/felica/felica_poller_i.h | 4 +- .../iso14443_3a/iso14443_3a_poller.c | 4 +- .../iso14443_3a/iso14443_3a_poller.h | 115 ++++++- .../iso14443_3a/iso14443_3a_poller_i.c | 5 +- .../iso14443_3a/iso14443_3a_poller_i.h | 20 -- ...r_sync_api.c => iso14443_3a_poller_sync.c} | 4 +- ...r_sync_api.h => iso14443_3a_poller_sync.h} | 2 +- .../iso14443_3b/iso14443_3b_poller.c | 4 +- .../iso14443_3b/iso14443_3b_poller.h | 71 ++++- .../iso14443_3b/iso14443_3b_poller_i.c | 5 +- .../iso14443_3b/iso14443_3b_poller_i.h | 10 - lib/nfc/protocols/iso14443_4a/iso14443_4a.h | 16 +- lib/nfc/protocols/iso14443_4a/iso14443_4a_i.h | 16 - .../iso14443_4a/iso14443_4a_poller.c | 3 +- .../iso14443_4a/iso14443_4a_poller.h | 70 ++++- .../iso14443_4a/iso14443_4a_poller_i.c | 2 +- .../iso14443_4a/iso14443_4a_poller_i.h | 10 - .../iso14443_4b/iso14443_4b_poller.h | 56 +++- .../iso14443_4b/iso14443_4b_poller_i.h | 7 - .../protocols/iso15693_3/iso15693_3_poller.c | 4 +- .../protocols/iso15693_3/iso15693_3_poller.h | 132 +++++++- .../iso15693_3/iso15693_3_poller_i.c | 28 +- .../iso15693_3/iso15693_3_poller_i.h | 30 -- .../protocols/mf_classic/mf_classic_poller.c | 68 ++--- .../protocols/mf_classic/mf_classic_poller.h | 281 ++++++++++++++---- .../mf_classic/mf_classic_poller_i.c | 16 +- .../mf_classic/mf_classic_poller_i.h | 31 -- ...er_sync_api.c => mf_classic_poller_sync.c} | 69 ++--- ...er_sync_api.h => mf_classic_poller_sync.h} | 16 +- .../protocols/mf_desfire/mf_desfire_poller.c | 15 +- .../protocols/mf_desfire/mf_desfire_poller.h | 259 +++++++++++++++- .../mf_desfire/mf_desfire_poller_i.c | 62 ++-- .../mf_desfire/mf_desfire_poller_i.h | 72 ----- .../mf_ultralight/mf_ultralight_poller.c | 25 +- .../mf_ultralight/mf_ultralight_poller.h | 178 ++++++++++- .../mf_ultralight/mf_ultralight_poller_i.c | 28 +- .../mf_ultralight/mf_ultralight_poller_i.h | 40 --- ...sync_api.c => mf_ultralight_poller_sync.c} | 51 ++-- .../mf_ultralight/mf_ultralight_poller_sync.h | 34 +++ .../mf_ultralight_poller_sync_api.h | 30 -- lib/nfc/protocols/nfc_protocol.h | 10 +- lib/nfc/protocols/slix/slix_poller.c | 7 +- lib/nfc/protocols/slix/slix_poller.h | 68 ++++- lib/nfc/protocols/slix/slix_poller_i.c | 4 +- lib/nfc/protocols/slix/slix_poller_i.h | 10 - lib/nfc/protocols/st25tb/st25tb_poller.c | 4 +- lib/nfc/protocols/st25tb/st25tb_poller.h | 17 ++ lib/nfc/protocols/st25tb/st25tb_poller_i.c | 19 +- lib/nfc/protocols/st25tb/st25tb_poller_i.h | 17 -- targets/f18/api_symbols.csv | 27 +- targets/f7/api_symbols.csv | 116 ++++++-- 62 files changed, 1708 insertions(+), 719 deletions(-) rename lib/nfc/protocols/iso14443_3a/{iso14443_3a_poller_sync_api.c => iso14443_3a_poller_sync.c} (93%) rename lib/nfc/protocols/iso14443_3a/{iso14443_3a_poller_sync_api.h => iso14443_3a_poller_sync.h} (58%) rename lib/nfc/protocols/mf_classic/{mf_classic_poller_sync_api.c => mf_classic_poller_sync.c} (88%) rename lib/nfc/protocols/mf_classic/{mf_classic_poller_sync_api.h => mf_classic_poller_sync.h} (64%) rename lib/nfc/protocols/mf_ultralight/{mf_ultralight_poller_sync_api.c => mf_ultralight_poller_sync.c} (83%) create mode 100644 lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync.h delete mode 100644 lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.h diff --git a/applications/debug/unit_tests/nfc/nfc_test.c b/applications/debug/unit_tests/nfc/nfc_test.c index ce5a9cb9c..0dcd09046 100644 --- a/applications/debug/unit_tests/nfc/nfc_test.c +++ b/applications/debug/unit_tests/nfc/nfc_test.c @@ -7,10 +7,10 @@ #include #include #include -#include +#include #include -#include -#include +#include +#include #include #include @@ -182,8 +182,8 @@ MU_TEST(iso14443_3a_reader) { Iso14443_3aData iso14443_3a_poller_data = {}; mu_assert( - iso14443_3a_poller_read(poller, &iso14443_3a_poller_data) == Iso14443_3aErrorNone, - "iso14443_3a_poller_read() failed"); + iso14443_3a_poller_sync_read(poller, &iso14443_3a_poller_data) == Iso14443_3aErrorNone, + "iso14443_3a_poller_sync_read() failed"); nfc_listener_stop(iso3_listener); mu_assert( @@ -221,8 +221,8 @@ static void mf_ultralight_reader_test(const char* path) { nfc_listener_start(mfu_listener, NULL, NULL); MfUltralightData* mfu_data = mf_ultralight_alloc(); - MfUltralightError error = mf_ultralight_poller_read_card(poller, mfu_data); - mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_read_card() failed"); + MfUltralightError error = mf_ultralight_poller_sync_read_card(poller, mfu_data); + mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_sync_read_card() failed"); nfc_listener_stop(mfu_listener); nfc_listener_free(mfu_listener); @@ -270,8 +270,8 @@ MU_TEST(ntag_213_locked_reader) { nfc_listener_start(mfu_listener, NULL, NULL); MfUltralightData* mfu_data = mf_ultralight_alloc(); - MfUltralightError error = mf_ultralight_poller_read_card(poller, mfu_data); - mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_read_card() failed"); + MfUltralightError error = mf_ultralight_poller_sync_read_card(poller, mfu_data); + mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_sync_read_card() failed"); nfc_listener_stop(mfu_listener); nfc_listener_free(mfu_listener); @@ -308,8 +308,8 @@ static void mf_ultralight_write() { MfUltralightData* mfu_data = mf_ultralight_alloc(); // Initial read - MfUltralightError error = mf_ultralight_poller_read_card(poller, mfu_data); - mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_read_card() failed"); + MfUltralightError error = mf_ultralight_poller_sync_read_card(poller, mfu_data); + mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_sync_read_card() failed"); mu_assert( mf_ultralight_is_equal(mfu_data, nfc_device_get_data(nfc_device, NfcProtocolMfUltralight)), @@ -321,13 +321,13 @@ static void mf_ultralight_write() { FURI_LOG_D(TAG, "Writing page %d", i); furi_hal_random_fill_buf(page.data, sizeof(MfUltralightPage)); mfu_data->page[i] = page; - error = mf_ultralight_poller_write_page(poller, i, &page); - mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_write_page() failed"); + error = mf_ultralight_poller_sync_write_page(poller, i, &page); + mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_sync_write_page() failed"); } // Verification read - error = mf_ultralight_poller_read_card(poller, mfu_data); - mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_read_card() failed"); + error = mf_ultralight_poller_sync_read_card(poller, mfu_data); + mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_sync_read_card() failed"); nfc_listener_stop(mfu_listener); const MfUltralightData* mfu_listener_data = @@ -355,7 +355,7 @@ static void mf_classic_reader() { MfClassicBlock block = {}; 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_free(mfc_listener); @@ -383,8 +383,8 @@ static void mf_classic_write() { furi_hal_random_fill_buf(block_write.data, sizeof(MfClassicBlock)); MfClassicKey key = {.data = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}; - mf_classic_poller_write_block(poller, 1, &key, MfClassicKeyTypeA, &block_write); - mf_classic_poller_read_block(poller, 1, &key, MfClassicKeyTypeA, &block_read); + mf_classic_poller_sync_write_block(poller, 1, &key, MfClassicKeyTypeA, &block_write); + mf_classic_poller_sync_read_block(poller, 1, &key, MfClassicKeyTypeA, &block_read); nfc_listener_stop(mfc_listener); nfc_listener_free(mfc_listener); @@ -413,16 +413,18 @@ static void mf_classic_value_block() { mf_classic_value_to_block(value, 1, &block_write); 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"); int32_t data = 200; 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(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(new_value == value, "Value not match"); diff --git a/applications/main/nfc/plugins/supported_cards/plantain.c b/applications/main/nfc/plugins/supported_cards/plantain.c index cb8c0093d..a21e1cd41 100644 --- a/applications/main/nfc/plugins/supported_cards/plantain.c +++ b/applications/main/nfc/plugins/supported_cards/plantain.c @@ -4,7 +4,7 @@ #include #include -#include +#include #define TAG "Plantain" @@ -91,7 +91,7 @@ static bool plantain_verify_type(Nfc* nfc, MfClassicType type) { MfClassicAuthContext auth_context; 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) { FURI_LOG_D(TAG, "Failed to read block %u: %d", block_num, error); break; @@ -119,7 +119,7 @@ static bool plantain_read(Nfc* nfc, NfcDevice* device) { do { 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; data->type = type; @@ -134,7 +134,7 @@ static bool plantain_read(Nfc* nfc, NfcDevice* device) { 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) { FURI_LOG_W(TAG, "Failed to read data"); break; diff --git a/applications/main/nfc/plugins/supported_cards/troika.c b/applications/main/nfc/plugins/supported_cards/troika.c index d42b977c6..7cf1e4dd8 100644 --- a/applications/main/nfc/plugins/supported_cards/troika.c +++ b/applications/main/nfc/plugins/supported_cards/troika.c @@ -4,7 +4,7 @@ #include #include -#include +#include #define TAG "Troika" @@ -91,7 +91,7 @@ static bool troika_verify_type(Nfc* nfc, MfClassicType type) { MfClassicAuthContext auth_context; 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) { FURI_LOG_D(TAG, "Failed to read block %u: %d", block_num, error); break; @@ -118,7 +118,7 @@ static bool troika_read(Nfc* nfc, NfcDevice* device) { do { 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; data->type = type; @@ -136,7 +136,7 @@ static bool troika_read(Nfc* nfc, NfcDevice* device) { 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) { FURI_LOG_W(TAG, "Failed to read data"); break; diff --git a/applications/main/nfc/plugins/supported_cards/two_cities.c b/applications/main/nfc/plugins/supported_cards/two_cities.c index fb964103e..1748d372d 100644 --- a/applications/main/nfc/plugins/supported_cards/two_cities.c +++ b/applications/main/nfc/plugins/supported_cards/two_cities.c @@ -4,7 +4,7 @@ #include #include -#include +#include #define TAG "TwoCities" @@ -49,7 +49,7 @@ bool two_cities_verify(Nfc* nfc) { MfClassicAuthContext auth_ctx = {}; 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) { FURI_LOG_D(TAG, "Failed to read block %u: %d", block_num, error); break; @@ -72,7 +72,7 @@ static bool two_cities_read(Nfc* nfc, NfcDevice* device) { do { 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; data->type = type; @@ -84,7 +84,7 @@ static bool two_cities_read(Nfc* nfc, NfcDevice* device) { 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) { FURI_LOG_W(TAG, "Failed to read data"); break; diff --git a/lib/drivers/SConscript b/lib/drivers/SConscript index 103472ccb..cf93d4bce 100644 --- a/lib/drivers/SConscript +++ b/lib/drivers/SConscript @@ -6,6 +6,8 @@ env.Append( ], SDK_HEADERS=[ File("cc1101_regs.h"), + File("st25r3916_reg.h"), + File("st25r3916.h"), ], ) diff --git a/lib/nfc/SConscript b/lib/nfc/SConscript index 6c55cf5d2..605a8639d 100644 --- a/lib/nfc/SConscript +++ b/lib/nfc/SConscript @@ -36,9 +36,9 @@ env.Append( File("protocols/mf_ultralight/mf_ultralight_listener.h"), File("protocols/mf_classic/mf_classic_listener.h"), # Sync API - File("protocols/iso14443_3a/iso14443_3a_poller_sync_api.h"), - File("protocols/mf_ultralight/mf_ultralight_poller_sync_api.h"), - File("protocols/mf_classic/mf_classic_poller_sync_api.h"), + File("protocols/iso14443_3a/iso14443_3a_poller_sync.h"), + File("protocols/mf_ultralight/mf_ultralight_poller_sync.h"), + File("protocols/mf_classic/mf_classic_poller_sync.h"), # Misc File("helpers/nfc_util.h"), File("helpers/iso14443_crc.h"), diff --git a/lib/nfc/nfc_poller.c b/lib/nfc/nfc_poller.c index ffe0318a0..48be37d92 100644 --- a/lib/nfc/nfc_poller.c +++ b/lib/nfc/nfc_poller.c @@ -28,6 +28,9 @@ struct NfcPoller { NfcPollerList list; NfcPollerSessionState session_state; bool protocol_detected; + + NfcGenericCallbackEx callback; + void* context; }; 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); } +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) { furi_assert(instance); furi_assert(instance->nfc); diff --git a/lib/nfc/nfc_poller.h b/lib/nfc/nfc_poller.h index 8ae01a8e4..18fbfb388 100644 --- a/lib/nfc/nfc_poller.h +++ b/lib/nfc/nfc_poller.h @@ -26,6 +26,31 @@ extern "C" { */ 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. * @@ -57,6 +82,18 @@ void nfc_poller_free(NfcPoller* instance); */ 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. * diff --git a/lib/nfc/protocols/felica/felica_poller.c b/lib/nfc/protocols/felica/felica_poller.c index 3fc2affed..23b1604e1 100644 --- a/lib/nfc/protocols/felica/felica_poller.c +++ b/lib/nfc/protocols/felica/felica_poller.c @@ -66,7 +66,7 @@ static NfcCommand felica_poller_run(NfcGenericEvent event, void* context) { if(nfc_event->type == NfcEventTypePollerReady) { if(instance->state != FelicaPollerStateActivated) { - FelicaError error = felica_poller_async_activate(instance, instance->data); + FelicaError error = felica_poller_activate(instance, instance->data); if(error == FelicaErrorNone) { instance->felica_event.type = FelicaPollerEventTypeReady; instance->felica_event_data.error = error; @@ -100,7 +100,7 @@ static bool felica_poller_detect(NfcGenericEvent event, void* context) { furi_assert(instance->state == FelicaPollerStateIdle); 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); } diff --git a/lib/nfc/protocols/felica/felica_poller.h b/lib/nfc/protocols/felica/felica_poller.h index 7d0c9525e..45fd9a9a1 100644 --- a/lib/nfc/protocols/felica/felica_poller.h +++ b/lib/nfc/protocols/felica/felica_poller.h @@ -9,22 +9,50 @@ extern "C" { #endif +/** + * @brief FelicaPoller opaque type definition. + */ typedef struct FelicaPoller FelicaPoller; +/** + * @brief Enumeration of possible Felica poller event types. + */ typedef enum { - FelicaPollerEventTypeError, - FelicaPollerEventTypeReady, + FelicaPollerEventTypeError, /**< The card was activated by the poller. */ + FelicaPollerEventTypeReady, /**< An error occured during activation procedure. */ } FelicaPollerEventType; -typedef struct { - FelicaError error; +/** + * @brief Felica poller event data. + */ +typedef union { + FelicaError error; /**< Error code indicating card activation fail reason. */ } FelicaPollerEventData; +/** + * @brief FelicaPoller poller event structure. + * + * Upon emission of an event, an instance of this struct will be passed to the callback. + */ typedef struct { - FelicaPollerEventType type; - FelicaPollerEventData* data; + FelicaPollerEventType type; /**< Type of emmitted event. */ + FelicaPollerEventData* data; /**< Pointer to event specific data. */ } 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 } #endif diff --git a/lib/nfc/protocols/felica/felica_poller_i.c b/lib/nfc/protocols/felica/felica_poller_i.c index d8015fdfa..bfbf150ef 100644 --- a/lib/nfc/protocols/felica/felica_poller_i.c +++ b/lib/nfc/protocols/felica/felica_poller_i.c @@ -49,7 +49,7 @@ static FelicaError felica_poller_frame_exchange( return ret; } -FelicaError felica_poller_async_polling( +FelicaError felica_poller_polling( FelicaPoller* instance, const FelicaPollerPollingCommand* cmd, FelicaPollerPollingResponse* resp) { @@ -93,7 +93,7 @@ FelicaError felica_poller_async_polling( return error; } -FelicaError felica_poller_async_activate(FelicaPoller* instance, FelicaData* data) { +FelicaError felica_poller_activate(FelicaPoller* instance, FelicaData* data) { furi_assert(instance); felica_reset(data); @@ -112,7 +112,7 @@ FelicaError felica_poller_async_activate(FelicaPoller* instance, FelicaData* dat }; 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) { FURI_LOG_T(TAG, "Activation failed error: %d", ret); diff --git a/lib/nfc/protocols/felica/felica_poller_i.h b/lib/nfc/protocols/felica/felica_poller_i.h index e12f01472..3bd4d91f9 100644 --- a/lib/nfc/protocols/felica/felica_poller_i.h +++ b/lib/nfc/protocols/felica/felica_poller_i.h @@ -48,13 +48,11 @@ typedef struct { const FelicaData* felica_poller_get_data(FelicaPoller* instance); -FelicaError felica_poller_async_polling( +FelicaError felica_poller_polling( FelicaPoller* instance, const FelicaPollerPollingCommand* cmd, FelicaPollerPollingResponse* resp); -FelicaError felica_poller_async_activate(FelicaPoller* instance, FelicaData* data); - #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.c b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.c index 880092c33..158250acd 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.c +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.c @@ -72,7 +72,7 @@ static NfcCommand iso14443_3a_poller_run(NfcGenericEvent event, void* context) { if(nfc_event->type == NfcEventTypePollerReady) { if(instance->state != Iso14443_3aPollerStateActivated) { 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) { instance->state = Iso14443_3aPollerStateActivated; 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); 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); } diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.h b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.h index 385cd5225..42e4b4bf5 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.h +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.h @@ -9,34 +9,137 @@ extern "C" { #endif +/** + * @brief Iso14443_3aPoller opaque type definition. + */ typedef struct Iso14443_3aPoller Iso14443_3aPoller; +/** + * @brief Enumeration of possible Iso14443_3a poller event types. + */ typedef enum { - Iso14443_3aPollerEventTypeError, - Iso14443_3aPollerEventTypeReady, + Iso14443_3aPollerEventTypeError, /**< The card was activated by the poller. */ + Iso14443_3aPollerEventTypeReady, /**< An error occured during activation procedure. */ } 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; +/** + * @brief Iso14443_3a poller event structure. + * + * Upon emission of an event, an instance of this struct will be passed to the callback. + */ typedef struct { - Iso14443_3aPollerEventType type; - Iso14443_3aPollerEventData* data; + Iso14443_3aPollerEventType type; /**< Type of emmitted event. */ + Iso14443_3aPollerEventData* data; /**< Pointer to event specific data. */ } 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_3aPoller* instance, const BitBuffer* tx_buffer, BitBuffer* rx_buffer, 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_3aPoller* instance, const BitBuffer* tx_buffer, BitBuffer* rx_buffer, 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 } #endif diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.c b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.c index 3434dc8e3..2be88bc51 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.c +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.c @@ -94,9 +94,8 @@ Iso14443_3aError iso14443_3a_poller_halt(Iso14443_3aPoller* instance) { return Iso14443_3aErrorNone; } -Iso14443_3aError iso14443_3a_poller_async_activate( - Iso14443_3aPoller* instance, - Iso14443_3aData* iso14443_3a_data) { +Iso14443_3aError + iso14443_3a_poller_activate(Iso14443_3aPoller* instance, Iso14443_3aData* iso14443_3a_data) { furi_assert(instance); furi_assert(instance->nfc); furi_assert(instance->tx_buffer); diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.h b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.h index 063ef1556..764f1a6b5 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.h +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.h @@ -39,15 +39,9 @@ typedef enum { Iso14443_3aPollerStateActivated, } Iso14443_3aPollerState; -typedef enum { - Iso14443_3aPollerConfigStateIdle, - Iso14443_3aPollerConfigStateDone, -} Iso14443_3aPollerConfigState; - struct Iso14443_3aPoller { Nfc* nfc; Iso14443_3aPollerState state; - Iso14443_3aPollerConfigState config_state; Iso14443_3aPollerColRes col_res; Iso14443_3aData* data; BitBuffer* tx_buffer; @@ -62,20 +56,6 @@ struct Iso14443_3aPoller { 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 } #endif diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_sync_api.c b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_sync.c similarity index 93% rename from lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_sync_api.c rename to lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_sync.c index 2bab1a881..ea7a6ae15 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_sync_api.c +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_sync.c @@ -1,4 +1,4 @@ -#include "iso14443_3a_poller_sync_api.h" +#include "iso14443_3a_poller_sync.h" #include "iso14443_3a_poller_i.h" #include @@ -34,7 +34,7 @@ NfcCommand iso14443_3a_poller_read_callback(NfcGenericEvent event, void* context 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(iso14443_3a_data); diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_sync_api.h b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_sync.h similarity index 58% rename from lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_sync_api.h rename to lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_sync.h index ed17ff432..72f084d1b 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_sync_api.h +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_sync.h @@ -7,7 +7,7 @@ extern "C" { #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 } diff --git a/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller.c b/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller.c index 9507f28c4..f0c9b67ad 100644 --- a/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller.c +++ b/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller.c @@ -70,7 +70,7 @@ static NfcCommand iso14443_3b_poller_run(NfcGenericEvent event, void* context) { if(nfc_event->type == NfcEventTypePollerReady) { 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) { instance->iso14443_3b_event.type = Iso14443_3bPollerEventTypeReady; 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); 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); } diff --git a/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller.h b/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller.h index d25d9dbe9..940903c1d 100644 --- a/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller.h +++ b/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller.h @@ -9,22 +9,81 @@ extern "C" { #endif +/** + * @brief Iso14443_3bPoller opaque type definition. + */ typedef struct Iso14443_3bPoller Iso14443_3bPoller; +/** + * @brief Enumeration of possible Iso14443_3b poller event types. + */ typedef enum { - Iso14443_3bPollerEventTypeError, - Iso14443_3bPollerEventTypeReady, + Iso14443_3bPollerEventTypeError, /**< The card was activated by the poller. */ + Iso14443_3bPollerEventTypeReady, /**< An error occured during activation procedure. */ } 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; +/** + * @brief Iso14443_3b poller event structure. + * + * Upon emission of an event, an instance of this struct will be passed to the callback. + */ typedef struct { - Iso14443_3bPollerEventType type; - Iso14443_3bPollerEventData* data; + Iso14443_3bPollerEventType type; /**< Type of emmitted event. */ + Iso14443_3bPollerEventData* data; /**< Pointer to event specific data. */ } 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 } #endif diff --git a/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller_i.c b/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller_i.c index 95668ccf2..1ee5237c6 100644 --- a/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller_i.c +++ b/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller_i.c @@ -21,7 +21,7 @@ static Iso14443_3bError iso14443_3b_poller_prepare_trx(Iso14443_3bPoller* instan furi_assert(instance); if(instance->state == Iso14443_3bPollerStateIdle) { - return iso14443_3b_poller_async_activate(instance, NULL); + return iso14443_3b_poller_activate(instance, NULL); } return Iso14443_3bErrorNone; @@ -63,8 +63,7 @@ static Iso14443_3bError iso14443_3b_poller_frame_exchange( return ret; } -Iso14443_3bError - iso14443_3b_poller_async_activate(Iso14443_3bPoller* instance, Iso14443_3bData* data) { +Iso14443_3bError iso14443_3b_poller_activate(Iso14443_3bPoller* instance, Iso14443_3bData* data) { furi_assert(instance); furi_assert(instance->nfc); diff --git a/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller_i.h b/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller_i.h index 5821d6373..2503c2e41 100644 --- a/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller_i.h +++ b/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller_i.h @@ -34,16 +34,6 @@ struct Iso14443_3bPoller { 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 } #endif diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a.h b/lib/nfc/protocols/iso14443_4a/iso14443_4a.h index 9580c1404..df212152d 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a.h +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a.h @@ -2,6 +2,8 @@ #include +#include + #ifdef __cplusplus extern "C" { #endif @@ -28,7 +30,19 @@ typedef enum { Iso14443_4aFrameOptionCid, } 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 diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_i.h b/lib/nfc/protocols/iso14443_4a/iso14443_4a_i.h index e45fb90cc..e5483a6ba 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_i.h +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_i.h @@ -2,8 +2,6 @@ #include "iso14443_4a.h" -#include - #define ISO14443_4A_CMD_READ_ATS (0xE0) // ATS bit definitions @@ -23,20 +21,6 @@ #define ISO14443_4A_ATS_TC1_NAD (1U << 0) #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); Iso14443_4aError iso14443_4a_process_error(Iso14443_3aError error); diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.c b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.c index c07cc6b7f..e20048b50 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.c +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.c @@ -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) { - Iso14443_4aError error = - iso14443_4a_poller_async_read_ats(instance, &instance->data->ats_data); + Iso14443_4aError error = iso14443_4a_poller_read_ats(instance, &instance->data->ats_data); if(error == Iso14443_4aErrorNone) { FURI_LOG_D(TAG, "Read ATS success"); instance->poller_state = Iso14443_4aPollerStateReady; diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.h b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.h index b224299e0..73eb6ef74 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.h +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.h @@ -8,22 +8,80 @@ extern "C" { #endif +/** + * @brief Iso14443_4aPoller opaque type definition. + */ typedef struct Iso14443_4aPoller Iso14443_4aPoller; +/** + * @brief Enumeration of possible Iso14443_4a poller event types. + */ typedef enum { - Iso14443_4aPollerEventTypeError, - Iso14443_4aPollerEventTypeReady, + Iso14443_4aPollerEventTypeError, /**< The card was activated by the poller. */ + Iso14443_4aPollerEventTypeReady, /**< An error occured during activation procedure. */ } 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; +/** + * @brief Iso14443_4a poller event structure. + * + * Upon emission of an event, an instance of this struct will be passed to the callback. + */ typedef struct { - Iso14443_4aPollerEventType type; - Iso14443_4aPollerEventData* data; + Iso14443_4aPollerEventType type; /**< Type of emmitted event. */ + Iso14443_4aPollerEventData* data; /**< Pointer to event specific data. */ } 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 } #endif diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c index 7221e2aa9..938e4e715 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c @@ -18,7 +18,7 @@ Iso14443_4aError iso14443_4a_poller_halt(Iso14443_4aPoller* instance) { } 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); bit_buffer_reset(instance->tx_buffer); diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.h b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.h index ce878cb40..7aae852e4 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.h +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.h @@ -45,16 +45,6 @@ struct Iso14443_4aPoller { 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 } #endif diff --git a/lib/nfc/protocols/iso14443_4b/iso14443_4b_poller.h b/lib/nfc/protocols/iso14443_4b/iso14443_4b_poller.h index e60090c04..03b288c07 100644 --- a/lib/nfc/protocols/iso14443_4b/iso14443_4b_poller.h +++ b/lib/nfc/protocols/iso14443_4b/iso14443_4b_poller.h @@ -8,22 +8,66 @@ extern "C" { #endif +/** + * @brief Iso14443_4bPoller opaque type definition. + */ typedef struct Iso14443_4bPoller Iso14443_4bPoller; +/** + * @brief Enumeration of possible Iso14443_4b poller event types. + */ typedef enum { - Iso14443_4bPollerEventTypeError, - Iso14443_4bPollerEventTypeReady, + Iso14443_4bPollerEventTypeError, /**< The card was activated by the poller. */ + Iso14443_4bPollerEventTypeReady, /**< An error occured during activation procedure. */ } 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; +/** + * @brief Iso14443_4b poller event structure. + * + * Upon emission of an event, an instance of this struct will be passed to the callback. + */ typedef struct { - Iso14443_4bPollerEventType type; - Iso14443_4bPollerEventData* data; + Iso14443_4bPollerEventType type; /**< Type of emmitted event. */ + Iso14443_4bPollerEventData* data; /**< Pointer to event specific data. */ } 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 } #endif diff --git a/lib/nfc/protocols/iso14443_4b/iso14443_4b_poller_i.h b/lib/nfc/protocols/iso14443_4b/iso14443_4b_poller_i.h index bd55c6188..fc9c2632b 100644 --- a/lib/nfc/protocols/iso14443_4b/iso14443_4b_poller_i.h +++ b/lib/nfc/protocols/iso14443_4b/iso14443_4b_poller_i.h @@ -42,13 +42,6 @@ struct Iso14443_4bPoller { 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 } #endif diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3_poller.c b/lib/nfc/protocols/iso15693_3/iso15693_3_poller.c index 9500e1653..cf27b1f3f 100644 --- a/lib/nfc/protocols/iso15693_3/iso15693_3_poller.c +++ b/lib/nfc/protocols/iso15693_3/iso15693_3_poller.c @@ -70,7 +70,7 @@ static NfcCommand iso15693_3_poller_run(NfcGenericEvent event, void* context) { if(nfc_event->type == NfcEventTypePollerReady) { 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) { instance->iso15693_3_event.type = Iso15693_3PollerEventTypeReady; 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) { 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); } diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3_poller.h b/lib/nfc/protocols/iso15693_3/iso15693_3_poller.h index 9d73242f1..a187ceace 100644 --- a/lib/nfc/protocols/iso15693_3/iso15693_3_poller.h +++ b/lib/nfc/protocols/iso15693_3/iso15693_3_poller.h @@ -8,22 +8,142 @@ extern "C" { #endif +/** + * @brief Iso15693_3Poller opaque type definition. + */ typedef struct Iso15693_3Poller Iso15693_3Poller; +/** + * @brief Enumeration of possible Iso15693_3 poller event types. + */ typedef enum { - Iso15693_3PollerEventTypeError, - Iso15693_3PollerEventTypeReady, + Iso15693_3PollerEventTypeError, /**< The card was activated by the poller. */ + Iso15693_3PollerEventTypeReady, /**< An error occured during activation procedure. */ } 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; +/** + * @brief Iso15693_3 poller event structure. + * + * Upon emission of an event, an instance of this struct will be passed to the callback. + */ typedef struct { - Iso15693_3PollerEventType type; - Iso15693_3PollerEventData* data; + Iso15693_3PollerEventType type; /**< Type of emmitted event. */ + Iso15693_3PollerEventData* data; /**< Pointer to event specific data. */ } 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 } #endif diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3_poller_i.c b/lib/nfc/protocols/iso15693_3/iso15693_3_poller_i.c index 8b8d8cee0..917f7dbb8 100644 --- a/lib/nfc/protocols/iso15693_3/iso15693_3_poller_i.c +++ b/lib/nfc/protocols/iso15693_3/iso15693_3_poller_i.c @@ -36,7 +36,7 @@ static Iso15693_3Error iso15693_3_poller_prepare_trx(Iso15693_3Poller* instance) furi_assert(instance); if(instance->state == Iso15693_3PollerStateIdle) { - return iso15693_3_poller_async_activate(instance, NULL); + return iso15693_3_poller_activate(instance, NULL); } return Iso15693_3ErrorNone; @@ -80,8 +80,7 @@ static Iso15693_3Error iso15693_3_poller_frame_exchange( return ret; } -Iso15693_3Error - iso15693_3_poller_async_activate(Iso15693_3Poller* instance, Iso15693_3Data* data) { +Iso15693_3Error iso15693_3_poller_activate(Iso15693_3Poller* instance, Iso15693_3Data* data) { furi_assert(instance); furi_assert(instance->nfc); @@ -93,7 +92,7 @@ Iso15693_3Error instance->state = Iso15693_3PollerStateColResInProgress; // Inventory: Mandatory command - ret = iso15693_3_poller_async_inventory(instance, data->uid); + ret = iso15693_3_poller_inventory(instance, data->uid); if(ret != Iso15693_3ErrorNone) { instance->state = Iso15693_3PollerStateColResFailed; break; @@ -103,7 +102,7 @@ Iso15693_3Error // Get system info: Optional command 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) { ret = iso15693_3_poller_filter_error(ret); break; @@ -111,7 +110,7 @@ Iso15693_3Error // Read blocks: Optional command 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, simple_array_get_data(data->block_data), system_info->block_count, @@ -124,7 +123,7 @@ Iso15693_3Error // Get block security status: Optional command 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); if(ret != Iso15693_3ErrorNone) { ret = iso15693_3_poller_filter_error(ret); @@ -136,7 +135,7 @@ Iso15693_3Error 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->nfc); furi_assert(uid); @@ -165,9 +164,8 @@ Iso15693_3Error iso15693_3_poller_async_inventory(Iso15693_3Poller* instance, ui return ret; } -Iso15693_3Error iso15693_3_poller_async_get_system_info( - Iso15693_3Poller* instance, - Iso15693_3SystemInfo* data) { +Iso15693_3Error + iso15693_3_poller_get_system_info(Iso15693_3Poller* instance, Iso15693_3SystemInfo* data) { furi_assert(instance); furi_assert(data); @@ -193,7 +191,7 @@ Iso15693_3Error iso15693_3_poller_async_get_system_info( return ret; } -Iso15693_3Error iso15693_3_poller_async_read_block( +Iso15693_3Error iso15693_3_poller_read_block( Iso15693_3Poller* instance, uint8_t* data, uint8_t block_number, @@ -222,7 +220,7 @@ Iso15693_3Error iso15693_3_poller_async_read_block( return ret; } -Iso15693_3Error iso15693_3_poller_async_read_blocks( +Iso15693_3Error iso15693_3_poller_read_blocks( Iso15693_3Poller* instance, uint8_t* data, uint16_t block_count, @@ -235,14 +233,14 @@ Iso15693_3Error iso15693_3_poller_async_read_blocks( Iso15693_3Error ret = Iso15693_3ErrorNone; 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; } return ret; } -Iso15693_3Error iso15693_3_poller_async_get_blocks_security( +Iso15693_3Error iso15693_3_poller_get_blocks_security( Iso15693_3Poller* instance, uint8_t* data, uint16_t block_count) { diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3_poller_i.h b/lib/nfc/protocols/iso15693_3/iso15693_3_poller_i.h index 154ee684c..346d0d724 100644 --- a/lib/nfc/protocols/iso15693_3/iso15693_3_poller_i.h +++ b/lib/nfc/protocols/iso15693_3/iso15693_3_poller_i.h @@ -35,36 +35,6 @@ struct Iso15693_3Poller { 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 } #endif diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller.c b/lib/nfc/protocols/mf_classic/mf_classic_poller.c index 3eba6ee56..dbc32a1b5 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller.c @@ -85,7 +85,7 @@ NfcCommand mf_classic_poller_handler_detect_type(MfClassicPoller* instance) { iso14443_3a_copy( instance->data->iso14443_3a_data, 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) { instance->data->type = MfClassicType4k; instance->state = MfClassicPollerStateStart; @@ -95,7 +95,7 @@ NfcCommand mf_classic_poller_handler_detect_type(MfClassicPoller* instance) { 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) { instance->data->type = MfClassicType1k; FURI_LOG_D(TAG, "1K detected"); @@ -234,7 +234,7 @@ NfcCommand mf_classic_poller_handler_read_block(MfClassicPoller* instance) { do { // 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); if(error != MfClassicErrorNone) { 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 - error = - mf_classic_async_read_block(instance, write_ctx->current_block, &write_ctx->tag_block); + error = mf_classic_poller_read_block( + instance, write_ctx->current_block, &write_ctx->tag_block); if(error != MfClassicErrorNone) { FURI_LOG_D(TAG, "Failed to read block %d", write_ctx->current_block); instance->state = MfClassicPollerStateFail; @@ -252,11 +252,11 @@ NfcCommand mf_classic_poller_handler_read_block(MfClassicPoller* instance) { } if(write_ctx->is_value_block) { - mf_classic_async_halt(instance); + mf_classic_poller_halt(instance); instance->state = MfClassicPollerStateWriteValueBlock; } else { if(write_ctx->need_halt_before_write) { - mf_classic_async_halt(instance); + mf_classic_poller_halt(instance); } instance->state = MfClassicPollerStateWriteBlock; } @@ -292,7 +292,7 @@ NfcCommand mf_classic_poller_handler_write_block(MfClassicPoller* instance) { // Reauth if necessary 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); if(error != MfClassicErrorNone) { FURI_LOG_D( @@ -303,7 +303,7 @@ NfcCommand mf_classic_poller_handler_write_block(MfClassicPoller* instance) { } // Write block - error = mf_classic_async_write_block( + error = mf_classic_poller_write_block( instance, write_ctx->current_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); - mf_classic_async_halt(instance); + mf_classic_poller_halt(instance); write_ctx->current_block++; instance->state = MfClassicPollerStateCheckWriteConditions; @@ -403,18 +403,18 @@ NfcCommand mf_classic_poller_handler_write_value_block(MfClassicPoller* instance &write_ctx->sec_tr.key_b; 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; - 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; - 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; } while(false); - mf_classic_async_halt(instance); + mf_classic_poller_halt(instance); write_ctx->is_value_block = false; write_ctx->current_block++; 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->key_type == MfClassicKeyTypeA ? 'A' : 'B', key); - error = mf_classic_async_auth( + error = mf_classic_poller_auth( instance, sec_read_ctx->current_block, &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); 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) { mf_classic_set_block_read(instance->data, sec_read_ctx->current_block, &read_block); 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); } } else { - mf_classic_async_halt(instance); + mf_classic_poller_halt(instance); sec_read_ctx->auth_passed = 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); sec_read_ctx->current_block++; if(sec_read_ctx->current_block > sec_tr_num) { - mf_classic_async_halt(instance); + mf_classic_poller_halt(instance); 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)); 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); if(error == MfClassicErrorNone) { 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; instance->state = MfClassicPollerStateReadSector; } else { - mf_classic_async_halt(instance); + mf_classic_poller_halt(instance); 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)); 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); if(error == MfClassicErrorNone) { 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; instance->state = MfClassicPollerStateReadSector; } else { - mf_classic_async_halt(instance); + mf_classic_poller_halt(instance); 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(!dict_attack_ctx->auth_passed) { - error = mf_classic_async_auth( + error = mf_classic_poller_auth( instance, block_num, &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); - error = mf_classic_async_read_block(instance, block_num, &block); + error = mf_classic_poller_read_block(instance, block_num, &block); if(error != MfClassicErrorNone) { - mf_classic_async_halt(instance); + mf_classic_poller_halt(instance); dict_attack_ctx->auth_passed = false; FURI_LOG_D(TAG, "Failed to read block %d", block_num); } else { @@ -655,7 +655,7 @@ NfcCommand mf_classic_poller_handler_read_sector(MfClassicPoller* instance) { if(dict_attack_ctx->current_block > sec_tr_block_num) { mf_classic_poller_handle_data_update(instance); - mf_classic_async_halt(instance); + mf_classic_poller_halt(instance); dict_attack_ctx->auth_passed = false; 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)); 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); if(error == MfClassicErrorNone) { 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; instance->state = MfClassicPollerStateKeyReuseReadSector; } else { - mf_classic_async_halt(instance); + mf_classic_poller_halt(instance); dict_attack_ctx->auth_passed = false; 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)); 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); if(error == MfClassicErrorNone) { 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; instance->state = MfClassicPollerStateKeyReuseReadSector; } else { - mf_classic_async_halt(instance); + mf_classic_poller_halt(instance); dict_attack_ctx->auth_passed = false; 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(!dict_attack_ctx->auth_passed) { - error = mf_classic_async_auth( + error = mf_classic_poller_auth( instance, block_num, &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); - error = mf_classic_async_read_block(instance, block_num, &block); + error = mf_classic_poller_read_block(instance, block_num, &block); if(error != MfClassicErrorNone) { - mf_classic_async_halt(instance); + mf_classic_poller_halt(instance); dict_attack_ctx->auth_passed = false; FURI_LOG_D(TAG, "Failed to read block %d", block_num); } 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); dict_attack_ctx->current_block++; 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; mf_classic_poller_handle_data_update(instance); diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller.h b/lib/nfc/protocols/mf_classic/mf_classic_poller.h index da1f3c3dc..f05a6800a 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller.h +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller.h @@ -7,103 +7,274 @@ extern "C" { #endif +/** + * @brief MfClassicPoller opaque type definition. + */ typedef struct MfClassicPoller MfClassicPoller; +/** + * @brief Enumeration of possible MfClassic poller event types. + */ typedef enum { - // Start event - MfClassicPollerEventTypeRequestMode, + MfClassicPollerEventTypeRequestMode, /**< Poller requests to fill the mode. */ - // Read with key cache events - MfClassicPollerEventTypeRequestReadSector, + MfClassicPollerEventTypeRequestReadSector, /**< Poller requests data to read sector. */ - // Write events - MfClassicPollerEventTypeRequestSectorTrailer, - MfClassicPollerEventTypeRequestWriteBlock, + MfClassicPollerEventTypeRequestSectorTrailer, /**< Poller requests sector trailer for writing block. */ + MfClassicPollerEventTypeRequestWriteBlock, /**< Poller requests data to write block. */ - // Dictionary attack events - MfClassicPollerEventTypeRequestKey, - MfClassicPollerEventTypeNextSector, - MfClassicPollerEventTypeDataUpdate, - MfClassicPollerEventTypeFoundKeyA, - MfClassicPollerEventTypeFoundKeyB, - MfClassicPollerEventTypeCardNotDetected, - MfClassicPollerEventTypeKeyAttackStart, - MfClassicPollerEventTypeKeyAttackStop, - MfClassicPollerEventTypeKeyAttackNextSector, + MfClassicPollerEventTypeRequestKey, /**< Poller requests key for sector authentication. */ + MfClassicPollerEventTypeNextSector, /**< Poller switches to next sector during dictionary attack. */ + MfClassicPollerEventTypeDataUpdate, /**< Poller updates data. */ + MfClassicPollerEventTypeFoundKeyA, /**< Poller found key A. */ + MfClassicPollerEventTypeFoundKeyB, /**< Poller found key B. */ + MfClassicPollerEventTypeKeyAttackStart, /**< Poller starts key attack. */ + MfClassicPollerEventTypeKeyAttackStop, /**< Poller stops key attack. */ + MfClassicPollerEventTypeKeyAttackNextSector, /**< Poller switches to next sector during key attack. */ - // Common events - MfClassicPollerEventTypeCardDetected, - MfClassicPollerEventTypeCardLost, - MfClassicPollerEventTypeSuccess, - MfClassicPollerEventTypeFail, + MfClassicPollerEventTypeCardDetected, /**< Poller detected card. */ + MfClassicPollerEventTypeCardLost, /**< Poller lost card. */ + MfClassicPollerEventTypeSuccess, /**< Poller succeeded. */ + MfClassicPollerEventTypeFail, /**< Poller failed. */ } MfClassicPollerEventType; +/** + * @brief MfClassic poller mode. + */ typedef enum { - MfClassicPollerModeRead, - MfClassicPollerModeWrite, - MfClassicPollerModeDictAttack, + MfClassicPollerModeRead, /**< Poller reading mode. */ + MfClassicPollerModeWrite, /**< Poller writing mode. */ + MfClassicPollerModeDictAttack, /**< Poller dictionary attack mode. */ } MfClassicPollerMode; +/** + * @brief MfClassic poller request mode event data. + * + * This instance of this structure must be filled on MfClassicPollerEventTypeRequestMode event. + */ typedef struct { - MfClassicPollerMode mode; - const MfClassicData* data; + MfClassicPollerMode mode; /**< Mode to be used by poller. */ + const MfClassicData* data; /**< Data to be used by poller. */ } MfClassicPollerEventDataRequestMode; +/** + * @brief MfClassic poller next sector event data. + * + * The instance of this structure is filled by poller and passed with + * MfClassicPollerEventTypeNextSector event. + */ typedef struct { - uint8_t current_sector; + uint8_t current_sector; /**< Current sector number. */ } MfClassicPollerEventDataDictAttackNextSector; +/** + * @brief MfClassic poller update event data. + * + * The instance of this structure is filled by poller and passed with + * MfClassicPollerEventTypeDataUpdate event. + */ typedef struct { - uint8_t sectors_read; - uint8_t keys_found; - uint8_t current_sector; + uint8_t sectors_read; /**< Number of sectors read. */ + uint8_t keys_found; /**< Number of keys found. */ + uint8_t current_sector; /**< Current sector number. */ } MfClassicPollerEventDataUpdate; +/** + * @brief MfClassic poller key request event data. + * + * The instance of this structure must be filled on MfClassicPollerEventTypeRequestKey event. + */ typedef struct { - MfClassicKey key; - bool key_provided; + MfClassicKey key; /**< Key to be used by poller. */ + bool key_provided; /**< Flag indicating if key is provided. */ } MfClassicPollerEventDataKeyRequest; +/** + * @brief MfClassic poller read sector request event data. + * + * The instance of this structure must be filled on MfClassicPollerEventTypeRequestReadSector event. + */ typedef struct { - uint8_t sector_num; - MfClassicKey key; - MfClassicKeyType key_type; - bool key_provided; + uint8_t sector_num; /**< Sector number to be read. */ + MfClassicKey key; /**< Key to be used by poller. */ + MfClassicKeyType key_type; /**< Key type to be used by poller. */ + bool key_provided; /**< Flag indicating if key is provided. */ } MfClassicPollerEventDataReadSectorRequest; +/** + * @brief MfClassic poller sector trailer request event data. + * + * The instance of this structure must be filled on MfClassicPollerEventTypeRequestSectorTrailer event. + */ typedef struct { - uint8_t sector_num; - MfClassicBlock sector_trailer; - bool sector_trailer_provided; + uint8_t sector_num; /**< Sector number to be read. */ + MfClassicBlock sector_trailer; /**< Sector trailer to be used by poller. */ + bool sector_trailer_provided; /**< Flag indicating if sector trailer is provided. */ } MfClassicPollerEventDataSectorTrailerRequest; +/** + * @brief MfClassic poller write block request event data. + * + * The instance of this structure must be filled on MfClassicPollerEventTypeRequestWriteBlock event. + */ typedef struct { - uint8_t block_num; - MfClassicBlock write_block; - bool write_block_provided; + uint8_t block_num; /**< Block number to be written. */ + MfClassicBlock write_block; /**< Block to be written. */ + bool write_block_provided; /**< Flag indicating if block is provided. */ } MfClassicPollerEventDataWriteBlockRequest; +/** + * @brief MfClassic poller key attack event data. + * + * The instance of this structure is filled by poller and passed with + * MfClassicPollerEventTypeKeyAttackNextSector event. + */ typedef struct { - uint8_t current_sector; + uint8_t current_sector; /**< Current sector number. */ } MfClassicPollerEventKeyAttackData; +/** + * @brief MfClassic poller event data. + */ typedef union { - MfClassicError error; - MfClassicPollerEventDataRequestMode poller_mode; - MfClassicPollerEventDataDictAttackNextSector next_sector_data; - MfClassicPollerEventDataKeyRequest key_request_data; - MfClassicPollerEventDataUpdate data_update; - MfClassicPollerEventDataReadSectorRequest read_sector_request_data; - MfClassicPollerEventKeyAttackData key_attack_data; - MfClassicPollerEventDataSectorTrailerRequest sec_tr_data; - MfClassicPollerEventDataWriteBlockRequest write_block_data; + MfClassicError error; /**< Error code on MfClassicPollerEventTypeFail event. */ + MfClassicPollerEventDataRequestMode poller_mode; /**< Poller mode context. */ + MfClassicPollerEventDataDictAttackNextSector next_sector_data; /**< Next sector context. */ + MfClassicPollerEventDataKeyRequest key_request_data; /**< Key request context. */ + MfClassicPollerEventDataUpdate data_update; /**< Data update context. */ + MfClassicPollerEventDataReadSectorRequest + read_sector_request_data; /**< Read sector request context. */ + MfClassicPollerEventKeyAttackData key_attack_data; /**< Key attack context. */ + MfClassicPollerEventDataSectorTrailerRequest sec_tr_data; /**< Sector trailer request context. */ + MfClassicPollerEventDataWriteBlockRequest write_block_data; /**< Write block request context. */ } MfClassicPollerEventData; +/** + * @brief MfClassic poller event. + * + * Upon emission of an event, an instance of this struct will be passed to the callback. + */ typedef struct { - MfClassicPollerEventType type; - MfClassicPollerEventData* data; + MfClassicPollerEventType type; /**< Event type. */ + MfClassicPollerEventData* data; /**< Pointer to event specific data. */ } 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 } #endif diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c index 7eab4fe3b..4b071815e 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c @@ -33,7 +33,7 @@ MfClassicError mf_classic_process_error(Iso14443_3aError error) { return ret; } -MfClassicError mf_classic_async_get_nt( +MfClassicError mf_classic_poller_get_nt( MfClassicPoller* instance, uint8_t block_num, MfClassicKeyType key_type, @@ -69,7 +69,7 @@ MfClassicError mf_classic_async_get_nt( return ret; } -MfClassicError mf_classic_async_auth( +MfClassicError mf_classic_poller_auth( MfClassicPoller* instance, uint8_t block_num, MfClassicKey* key, @@ -84,7 +84,7 @@ MfClassicError mf_classic_async_auth( iso14443_3a_poller_get_data(instance->iso14443_3a_poller)); 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(data) { data->nt = nt; @@ -130,7 +130,7 @@ MfClassicError mf_classic_async_auth( return ret; } -MfClassicError mf_classic_async_halt(MfClassicPoller* instance) { +MfClassicError mf_classic_poller_halt(MfClassicPoller* instance) { MfClassicError ret = MfClassicErrorNone; Iso14443_3aError error = Iso14443_3aErrorNone; @@ -158,7 +158,7 @@ MfClassicError mf_classic_async_halt(MfClassicPoller* instance) { return ret; } -MfClassicError mf_classic_async_read_block( +MfClassicError mf_classic_poller_read_block( MfClassicPoller* instance, uint8_t block_num, MfClassicBlock* data) { @@ -204,7 +204,7 @@ MfClassicError mf_classic_async_read_block( return ret; } -MfClassicError mf_classic_async_write_block( +MfClassicError mf_classic_poller_write_block( MfClassicPoller* instance, uint8_t block_num, MfClassicBlock* data) { @@ -275,7 +275,7 @@ MfClassicError mf_classic_async_write_block( return ret; } -MfClassicError mf_classic_async_value_cmd( +MfClassicError mf_classic_poller_value_cmd( MfClassicPoller* instance, uint8_t block_num, MfClassicValueCommand cmd, @@ -345,7 +345,7 @@ MfClassicError mf_classic_async_value_cmd( 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; Iso14443_3aError error = Iso14443_3aErrorNone; diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h index c6f4ccf7f..0be42196f 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h @@ -169,37 +169,6 @@ MfClassicPoller* mf_classic_poller_alloc(Iso14443_3aPoller* iso14443_3a_poller); 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 } #endif diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.c b/lib/nfc/protocols/mf_classic/mf_classic_poller_sync.c similarity index 88% rename from lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.c rename to lib/nfc/protocols/mf_classic/mf_classic_poller_sync.c index 8b9fb69f1..69954452a 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_sync.c @@ -1,3 +1,4 @@ +#include "mf_classic_poller_sync.h" #include "mf_classic_poller_i.h" #include @@ -32,7 +33,7 @@ typedef MfClassicError ( static MfClassicError mf_classic_poller_collect_nt_handler( MfClassicPoller* poller, MfClassicPollerContextData* data) { - return mf_classic_async_get_nt( + return mf_classic_poller_get_nt( poller, data->collect_nt_context.block, data->collect_nt_context.key_type, @@ -41,7 +42,7 @@ static MfClassicError mf_classic_poller_collect_nt_handler( static MfClassicError mf_classic_poller_auth_handler(MfClassicPoller* poller, MfClassicPollerContextData* data) { - return mf_classic_async_auth( + return mf_classic_poller_auth( poller, data->auth_context.block_num, &data->auth_context.key, @@ -55,7 +56,7 @@ static MfClassicError mf_classic_poller_read_block_handler( MfClassicError error = MfClassicErrorNone; do { - error = mf_classic_async_auth( + error = mf_classic_poller_auth( poller, data->read_block_context.block_num, &data->read_block_context.key, @@ -63,11 +64,11 @@ static MfClassicError mf_classic_poller_read_block_handler( NULL); 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); if(error != MfClassicErrorNone) break; - error = mf_classic_async_halt(poller); + error = mf_classic_poller_halt(poller); if(error != MfClassicErrorNone) break; } while(false); @@ -81,7 +82,7 @@ static MfClassicError mf_classic_poller_write_block_handler( MfClassicError error = MfClassicErrorNone; do { - error = mf_classic_async_auth( + error = mf_classic_poller_auth( poller, data->read_block_context.block_num, &data->read_block_context.key, @@ -89,11 +90,11 @@ static MfClassicError mf_classic_poller_write_block_handler( NULL); 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); if(error != MfClassicErrorNone) break; - error = mf_classic_async_halt(poller); + error = mf_classic_poller_halt(poller); if(error != MfClassicErrorNone) break; } while(false); @@ -107,7 +108,7 @@ static MfClassicError mf_classic_poller_read_value_handler( MfClassicError error = MfClassicErrorNone; do { - error = mf_classic_async_auth( + error = mf_classic_poller_auth( poller, data->read_value_context.block_num, &data->read_value_context.key, @@ -116,7 +117,7 @@ static MfClassicError mf_classic_poller_read_value_handler( if(error != MfClassicErrorNone) break; 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(!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; } - error = mf_classic_async_halt(poller); + error = mf_classic_poller_halt(poller); if(error != MfClassicErrorNone) break; } while(false); @@ -138,7 +139,7 @@ static MfClassicError mf_classic_poller_change_value_handler( MfClassicError error = MfClassicErrorNone; do { - error = mf_classic_async_auth( + error = mf_classic_poller_auth( poller, data->change_value_context.block_num, &data->change_value_context.key, @@ -146,21 +147,21 @@ static MfClassicError mf_classic_poller_change_value_handler( NULL); if(error != MfClassicErrorNone) break; - error = mf_classic_async_value_cmd( + error = mf_classic_poller_value_cmd( poller, data->change_value_context.block_num, data->change_value_context.value_cmd, data->change_value_context.data); 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; 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; - error = mf_classic_async_halt(poller); + error = mf_classic_poller_halt(poller); if(error != MfClassicErrorNone) break; 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, }; -static NfcCommand mf_classic_poller_cmd_callback(NfcGenericEvent event, void* context) { - furi_assert(event.instance); - furi_assert(event.protocol == NfcProtocolIso14443_3a); - furi_assert(event.event_data); +static NfcCommand mf_classic_poller_cmd_callback(NfcGenericEventEx event, void* context) { + furi_assert(event.poller); + furi_assert(event.parent_event_data); furi_assert(context); MfClassicPollerContext* poller_context = context; - Iso14443_3aPollerEvent* iso14443_3a_event = event.event_data; - Iso14443_3aPoller* iso14443_3a_poller = event.instance; - MfClassicPoller* mfc_poller = mf_classic_poller_alloc(iso14443_3a_poller); + Iso14443_3aPollerEvent* iso14443_3a_event = event.parent_event_data; + MfClassicPoller* mfc_poller = event.poller; if(iso14443_3a_event->type == Iso14443_3aPollerEventTypeReady) { 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); - mf_classic_poller_free(mfc_poller); - 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(); - NfcPoller* poller = nfc_poller_alloc(nfc, NfcProtocolIso14443_3a); - nfc_poller_start(poller, mf_classic_poller_cmd_callback, poller_ctx); + NfcPoller* poller = nfc_poller_alloc(nfc, NfcProtocolMfClassic); + 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_clear(MF_CLASSIC_POLLER_COMPLETE_EVENT); @@ -223,7 +220,7 @@ static MfClassicError mf_classic_poller_cmd_execute(Nfc* nfc, MfClassicPollerCon return poller_ctx->error; } -MfClassicError mf_classic_poller_collect_nt( +MfClassicError mf_classic_poller_sync_collect_nt( Nfc* nfc, uint8_t block_num, MfClassicKeyType key_type, @@ -247,7 +244,7 @@ MfClassicError mf_classic_poller_collect_nt( return error; } -MfClassicError mf_classic_poller_auth( +MfClassicError mf_classic_poller_sync_auth( Nfc* nfc, uint8_t block_num, MfClassicKey* key, @@ -274,7 +271,7 @@ MfClassicError mf_classic_poller_auth( return error; } -MfClassicError mf_classic_poller_read_block( +MfClassicError mf_classic_poller_sync_read_block( Nfc* nfc, uint8_t block_num, MfClassicKey* key, @@ -300,7 +297,7 @@ MfClassicError mf_classic_poller_read_block( return error; } -MfClassicError mf_classic_poller_write_block( +MfClassicError mf_classic_poller_sync_write_block( Nfc* nfc, uint8_t block_num, MfClassicKey* key, @@ -323,7 +320,7 @@ MfClassicError mf_classic_poller_write_block( return error; } -MfClassicError mf_classic_poller_read_value( +MfClassicError mf_classic_poller_sync_read_value( Nfc* nfc, uint8_t block_num, MfClassicKey* key, @@ -349,7 +346,7 @@ MfClassicError mf_classic_poller_read_value( return error; } -MfClassicError mf_classic_poller_change_value( +MfClassicError mf_classic_poller_sync_change_value( Nfc* nfc, uint8_t block_num, MfClassicKey* key, @@ -461,7 +458,7 @@ NfcCommand mf_classic_poller_read_callback(NfcGenericEvent event, void* context) } 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(keys); furi_assert(data); @@ -498,7 +495,7 @@ MfClassicError 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(type); @@ -512,7 +509,7 @@ MfClassicError mf_classic_poller_detect_type(Nfc* nfc, MfClassicType* type) { size_t i = 0; 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); if(error == MfClassicErrorNone) { *type = MfClassicTypeNum - i - 1; diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.h b/lib/nfc/protocols/mf_classic/mf_classic_poller_sync.h similarity index 64% rename from lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.h rename to lib/nfc/protocols/mf_classic/mf_classic_poller_sync.h index 11db291b8..d384e46e4 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.h +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_sync.h @@ -7,41 +7,41 @@ extern "C" { #endif -MfClassicError mf_classic_poller_collect_nt( +MfClassicError mf_classic_poller_sync_collect_nt( Nfc* nfc, uint8_t block_num, MfClassicKeyType key_type, MfClassicNt* nt); -MfClassicError mf_classic_poller_auth( +MfClassicError mf_classic_poller_sync_auth( Nfc* nfc, uint8_t block_num, MfClassicKey* key, MfClassicKeyType key_type, MfClassicAuthContext* data); -MfClassicError mf_classic_poller_read_block( +MfClassicError mf_classic_poller_sync_read_block( Nfc* nfc, uint8_t block_num, MfClassicKey* key, MfClassicKeyType key_type, MfClassicBlock* data); -MfClassicError mf_classic_poller_write_block( +MfClassicError mf_classic_poller_sync_write_block( Nfc* nfc, uint8_t block_num, MfClassicKey* key, MfClassicKeyType key_type, MfClassicBlock* data); -MfClassicError mf_classic_poller_read_value( +MfClassicError mf_classic_poller_sync_read_value( Nfc* nfc, uint8_t block_num, MfClassicKey* key, MfClassicKeyType key_type, int32_t* value); -MfClassicError mf_classic_poller_change_value( +MfClassicError mf_classic_poller_sync_change_value( Nfc* nfc, uint8_t block_num, MfClassicKey* key, @@ -49,10 +49,10 @@ MfClassicError mf_classic_poller_change_value( int32_t data, 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 - 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 } diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c b/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c index 11db021d5..5af033d4c 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c @@ -61,7 +61,7 @@ static NfcCommand mf_desfire_poller_handler_idle(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) { FURI_LOG_D(TAG, "Read version success"); 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) { - instance->error = - mf_desfire_poller_async_read_free_memory(instance, &instance->data->free_memory); + instance->error = mf_desfire_poller_read_free_memory(instance, &instance->data->free_memory); if(instance->error == MfDesfireErrorNone) { FURI_LOG_D(TAG, "Read free memory success"); 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) { 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) { FURI_LOG_D(TAG, "Read master key settings success"); 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) { - instance->error = mf_desfire_poller_async_read_key_versions( + instance->error = mf_desfire_poller_read_key_versions( instance, instance->data->master_key_versions, 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) { 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) { FURI_LOG_D(TAG, "Read application ids success"); 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) { - instance->error = mf_desfire_poller_async_read_applications( + instance->error = mf_desfire_poller_read_applications( instance, instance->data->application_ids, instance->data->applications); if(instance->error == MfDesfireErrorNone) { 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) { 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); } diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_poller.h b/lib/nfc/protocols/mf_desfire/mf_desfire_poller.h index 360b0508f..6ef2f3f68 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_poller.h +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_poller.h @@ -8,24 +8,267 @@ extern "C" { #endif +/** + * @brief MfDesfirePoller opaque type definition. + */ typedef struct MfDesfirePoller MfDesfirePoller; +/** + * @brief Enumeration of possible MfDesfire poller event types. + */ typedef enum { - MfDesfirePollerEventTypeReadSuccess, - MfDesfirePollerEventTypeReadFailed, + MfDesfirePollerEventTypeReadSuccess, /**< Card was read successfully. */ + MfDesfirePollerEventTypeReadFailed, /**< Poller failed to read card. */ } MfDesfirePollerEventType; -typedef struct { - union { - MfDesfireError error; - }; +/** + * @brief MfDesfire poller event data. + */ +typedef union { + MfDesfireError error; /**< Error code indicating card reading fail reason. */ } MfDesfirePollerEventData; +/** + * @brief MfDesfire poller event structure. + * + * Upon emission of an event, an instance of this struct will be passed to the callback. + */ typedef struct { - MfDesfirePollerEventType type; - MfDesfirePollerEventData* data; + MfDesfirePollerEventType type; /**< Type of emmitted event. */ + MfDesfirePollerEventData* data; /**< Pointer to event specific data. */ } 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 } #endif diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c b/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c index 38ae2f466..0b2d84138 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c @@ -74,8 +74,7 @@ MfDesfireError mf_desfire_send_chunks( return error; } -MfDesfireError - mf_desfire_poller_async_read_version(MfDesfirePoller* instance, MfDesfireVersion* data) { +MfDesfireError mf_desfire_poller_read_version(MfDesfirePoller* instance, MfDesfireVersion* data) { furi_assert(instance); bit_buffer_reset(instance->input_buffer); @@ -97,7 +96,7 @@ 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); bit_buffer_reset(instance->input_buffer); @@ -118,9 +117,8 @@ MfDesfireError return error; } -MfDesfireError mf_desfire_poller_async_read_key_settings( - MfDesfirePoller* instance, - MfDesfireKeySettings* data) { +MfDesfireError + mf_desfire_poller_read_key_settings(MfDesfirePoller* instance, MfDesfireKeySettings* data) { furi_assert(instance); bit_buffer_reset(instance->input_buffer); @@ -141,7 +139,7 @@ MfDesfireError mf_desfire_poller_async_read_key_settings( return error; } -MfDesfireError mf_desfire_poller_async_read_key_versions( +MfDesfireError mf_desfire_poller_read_key_versions( MfDesfirePoller* instance, SimpleArray* data, uint32_t count) { @@ -172,7 +170,7 @@ MfDesfireError mf_desfire_poller_async_read_key_versions( } 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); bit_buffer_reset(instance->input_buffer); @@ -203,7 +201,7 @@ MfDesfireError return error; } -MfDesfireError mf_desfire_poller_async_select_application( +MfDesfireError mf_desfire_poller_select_application( MfDesfirePoller* instance, const MfDesfireApplicationId* id) { furi_assert(instance); @@ -219,8 +217,7 @@ MfDesfireError mf_desfire_poller_async_select_application( return error; } -MfDesfireError - mf_desfire_poller_async_read_file_ids(MfDesfirePoller* instance, SimpleArray* data) { +MfDesfireError mf_desfire_poller_read_file_ids(MfDesfirePoller* instance, SimpleArray* data) { furi_assert(instance); bit_buffer_reset(instance->input_buffer); @@ -250,7 +247,7 @@ MfDesfireError return error; } -MfDesfireError mf_desfire_poller_async_read_file_settings( +MfDesfireError mf_desfire_poller_read_file_settings( MfDesfirePoller* instance, MfDesfireFileId id, MfDesfireFileSettings* data) { @@ -275,7 +272,7 @@ MfDesfireError mf_desfire_poller_async_read_file_settings( return error; } -MfDesfireError mf_desfire_poller_async_read_file_settings_multi( +MfDesfireError mf_desfire_poller_read_file_settings_multi( MfDesfirePoller* instance, const SimpleArray* file_ids, 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) { const MfDesfireFileId file_id = *(const MfDesfireFileId*)simple_array_cget(file_ids, i); - error = mf_desfire_poller_async_read_file_settings( - instance, file_id, simple_array_get(data, i)); + error = mf_desfire_poller_read_file_settings(instance, file_id, simple_array_get(data, i)); if(error != MfDesfireErrorNone) break; } return error; } -MfDesfireError mf_desfire_poller_async_read_file_data( +MfDesfireError mf_desfire_poller_read_file_data( MfDesfirePoller* instance, MfDesfireFileId id, uint32_t offset, @@ -327,7 +323,7 @@ MfDesfireError mf_desfire_poller_async_read_file_data( return error; } -MfDesfireError mf_desfire_poller_async_read_file_value( +MfDesfireError mf_desfire_poller_read_file_value( MfDesfirePoller* instance, MfDesfireFileId id, MfDesfireFileData* data) { @@ -352,7 +348,7 @@ MfDesfireError mf_desfire_poller_async_read_file_value( return error; } -MfDesfireError mf_desfire_poller_async_read_file_records( +MfDesfireError mf_desfire_poller_read_file_records( MfDesfirePoller* instance, MfDesfireFileId id, uint32_t offset, @@ -381,7 +377,7 @@ MfDesfireError mf_desfire_poller_async_read_file_records( return error; } -MfDesfireError mf_desfire_poller_async_read_file_data_multi( +MfDesfireError mf_desfire_poller_read_file_data_multi( MfDesfirePoller* instance, const SimpleArray* file_ids, 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); 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); } 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( file_type == MfDesfireFileTypeLinearRecord || 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); } @@ -421,30 +417,29 @@ MfDesfireError mf_desfire_poller_async_read_file_data_multi( return error; } -MfDesfireError mf_desfire_poller_async_read_application( - MfDesfirePoller* instance, - MfDesfireApplication* data) { +MfDesfireError + mf_desfire_poller_read_application(MfDesfirePoller* instance, MfDesfireApplication* data) { furi_assert(instance); furi_assert(data); MfDesfireError error; 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; - error = mf_desfire_poller_async_read_key_versions( + error = mf_desfire_poller_read_key_versions( instance, data->key_versions, data->key_settings.max_keys); 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; - error = mf_desfire_poller_async_read_file_settings_multi( + error = mf_desfire_poller_read_file_settings_multi( instance, data->file_ids, data->file_settings); 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); if(error != MfDesfireErrorNone) break; @@ -453,7 +448,7 @@ MfDesfireError mf_desfire_poller_async_read_application( return error; } -MfDesfireError mf_desfire_poller_async_read_applications( +MfDesfireError mf_desfire_poller_read_applications( MfDesfirePoller* instance, const SimpleArray* app_ids, SimpleArray* data) { @@ -468,12 +463,11 @@ MfDesfireError mf_desfire_poller_async_read_applications( for(uint32_t i = 0; i < app_id_count; ++i) { do { - error = mf_desfire_poller_async_select_application( - instance, simple_array_cget(app_ids, i)); + error = mf_desfire_poller_select_application(instance, simple_array_cget(app_ids, i)); if(error != MfDesfireErrorNone) break; 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); } diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.h b/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.h index abc48d0eb..1c80af36f 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.h +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.h @@ -49,78 +49,6 @@ MfDesfireError mf_desfire_process_error(Iso14443_4aError error); 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 } #endif diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c index 4ad7bc147..86ab68c8b 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c @@ -230,7 +230,7 @@ static NfcCommand mf_ultralight_poller_handler_idle(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) { FURI_LOG_D(TAG, "Read version success"); 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) { - instance->error = mf_ultralight_poller_async_authenticate(instance); + instance->error = mf_ultralight_poller_authenticate(instance); if(instance->error == MfUltralightErrorNone) { FURI_LOG_D(TAG, "Ultralight C detected"); 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) { 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) { FURI_LOG_D(TAG, "NTAG203 detected"); instance->data->type = MfUltralightTypeNTAG203; @@ -294,7 +294,7 @@ static NfcCommand mf_ultralight_poller_handler_read_signature(MfUltralightPoller instance->feature_set, MfUltralightFeatureSupportReadSignature)) { FURI_LOG_D(TAG, "Reading signature"); 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) { FURI_LOG_D(TAG, "Read signature failed"); 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); - 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]); if(instance->error != MfUltralightErrorNone) { 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; 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->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( instance->auth_context.password.data, sizeof(MfUltralightAuthPassword)); FURI_LOG_D(TAG, "Trying to authenticate with password %08lX", pass); - instance->error = - mf_ultralight_poller_async_auth_pwd(instance, &instance->auth_context); + instance->error = mf_ultralight_poller_auth_pwd(instance, &instance->auth_context); if(instance->error == MfUltralightErrorNone) { FURI_LOG_D(TAG, "Auth success"); 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( instance, start_page, §or, &tag, &pages_left)) { 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 { FURI_LOG_D(TAG, "Failed to calculate sector and tag from %d page", start_page); instance->error = MfUltralightErrorProtocol; } } 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) { @@ -478,8 +477,7 @@ static NfcCommand mf_ultralight_poller_handler_try_default_pass(MfUltralightPoll MF_ULTRALIGHT_DEFAULT_PASSWORD, sizeof(MfUltralightAuthPassword), instance->auth_context.password.data); - instance->error = - mf_ultralight_poller_async_auth_pwd(instance, &instance->auth_context); + instance->error = mf_ultralight_poller_auth_pwd(instance, &instance->auth_context); if(instance->error == MfUltralightErrorNone) { FURI_LOG_D(TAG, "Default password detected"); nfc_util_num2bytes( @@ -576,8 +574,7 @@ static bool mf_ultralight_poller_detect(NfcGenericEvent event, void* context) { if(iso14443_3a_event->type == Iso14443_3aPollerEventTypeReady) { MfUltralightPageReadCommandData read_page_cmd_data = {}; - MfUltralightError error = - mf_ultralight_poller_async_read_page(instance, 0, &read_page_cmd_data); + MfUltralightError error = mf_ultralight_poller_read_page(instance, 0, &read_page_cmd_data); protocol_detected = (error == MfUltralightErrorNone); iso14443_3a_poller_halt(instance->iso14443_3a_poller); } diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h index 2d4ef33ea..665d90cb7 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h @@ -7,35 +7,181 @@ extern "C" { #endif +/** + * @brief MfUltralightPoller opaque type definition. + */ typedef struct MfUltralightPoller MfUltralightPoller; +/** + * @brief Enumeration of possible MfUltralight poller event types. + */ typedef enum { - MfUltralightPollerEventTypeAuthRequest, - MfUltralightPollerEventTypeAuthSuccess, - MfUltralightPollerEventTypeAuthFailed, - MfUltralightPollerEventTypeReadSuccess, - MfUltralightPollerEventTypeReadFailed, + MfUltralightPollerEventTypeAuthRequest, /**< Poller requests to fill authentication context. */ + MfUltralightPollerEventTypeAuthSuccess, /**< Authentication succeeded. */ + MfUltralightPollerEventTypeAuthFailed, /**< Authentication failed. */ + MfUltralightPollerEventTypeReadSuccess, /**< Poller read card successfully. */ + MfUltralightPollerEventTypeReadFailed, /**< Poller failed to read card. */ } MfUltralightPollerEventType; +/** + * @brief MfUltralight poller authentication context. + */ typedef struct { - MfUltralightAuthPassword password; - MfUltralightAuthPack pack; - bool auth_success; - bool skip_auth; + MfUltralightAuthPassword password; /**< Password to be used for authentication. */ + MfUltralightAuthPack pack; /**< Pack received on successfull authentication. */ + bool auth_success; /**< Set to true if authentication succeeded, false otherwise. */ + bool skip_auth; /**< Set to true if authentication should be skipped, false otherwise. */ } MfUltralightPollerAuthContext; -typedef struct { - union { - MfUltralightPollerAuthContext auth_context; - MfUltralightError error; - }; +/** + * @brief MfUltralight poller event data. + */ +typedef union { + MfUltralightPollerAuthContext auth_context; /**< Authentication context. */ + MfUltralightError error; /**< Error code indicating reading fail reason. */ } MfUltralightPollerEventData; +/** + * @brief MfUltralight poller event structure. + * + * Upon emission of an event, an instance of this struct will be passed to the callback. + */ typedef struct { - MfUltralightPollerEventType type; - MfUltralightPollerEventData* data; + MfUltralightPollerEventType type; /**< Type of emmitted event. */ + MfUltralightPollerEventData* data; /**< Pointer to event specific data. */ } 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 } #endif diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c index 795b03e65..2d88db3e5 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c @@ -30,7 +30,7 @@ MfUltralightError mf_ultralight_process_error(Iso14443_3aError error) { return ret; } -MfUltralightError mf_ultralight_poller_async_auth_pwd( +MfUltralightError mf_ultralight_poller_auth_pwd( MfUltralightPoller* instance, MfUltralightPollerAuthContext* data) { uint8_t auth_cmd[5] = {MF_ULTRALIGHT_CMD_PWD_AUTH}; //-V1009 @@ -59,7 +59,7 @@ MfUltralightError mf_ultralight_poller_async_auth_pwd( 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}; 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; } -MfUltralightError mf_ultralight_poller_async_read_page_from_sector( +MfUltralightError mf_ultralight_poller_read_page_from_sector( MfUltralightPoller* instance, uint8_t sector, uint8_t tag, @@ -122,13 +122,13 @@ MfUltralightError mf_ultralight_poller_async_read_page_from_sector( break; } - ret = mf_ultralight_poller_async_read_page(instance, tag, data); + ret = mf_ultralight_poller_read_page(instance, tag, data); } while(false); return ret; } -MfUltralightError mf_ultralight_poller_async_read_page( +MfUltralightError mf_ultralight_poller_read_page( MfUltralightPoller* instance, uint8_t start_page, MfUltralightPageReadCommandData* data) { @@ -158,10 +158,10 @@ MfUltralightError mf_ultralight_poller_async_read_page( return ret; } -MfUltralightError mf_ultralight_poller_async_write_page( +MfUltralightError mf_ultralight_poller_write_page( MfUltralightPoller* instance, uint8_t page, - MfUltralightPage* data) { + const MfUltralightPage* data) { MfUltralightError ret = MfUltralightErrorNone; Iso14443_3aError error = Iso14443_3aErrorNone; @@ -191,9 +191,8 @@ MfUltralightError mf_ultralight_poller_async_write_page( return ret; } -MfUltralightError mf_ultralight_poller_async_read_version( - MfUltralightPoller* instance, - MfUltralightVersion* data) { +MfUltralightError + mf_ultralight_poller_read_version(MfUltralightPoller* instance, MfUltralightVersion* data) { MfUltralightError ret = MfUltralightErrorNone; Iso14443_3aError error = Iso14443_3aErrorNone; @@ -221,9 +220,8 @@ MfUltralightError mf_ultralight_poller_async_read_version( return ret; } -MfUltralightError mf_ultralight_poller_async_read_signature( - MfUltralightPoller* instance, - MfUltralightSignature* data) { +MfUltralightError + mf_ultralight_poller_read_signature(MfUltralightPoller* instance, MfUltralightSignature* data) { MfUltralightError ret = MfUltralightErrorNone; Iso14443_3aError error = Iso14443_3aErrorNone; @@ -249,7 +247,7 @@ MfUltralightError mf_ultralight_poller_async_read_signature( return ret; } -MfUltralightError mf_ultralight_poller_async_read_counter( +MfUltralightError mf_ultralight_poller_read_counter( MfUltralightPoller* instance, uint8_t counter_num, MfUltralightCounter* data) { @@ -278,7 +276,7 @@ MfUltralightError mf_ultralight_poller_async_read_counter( return ret; } -MfUltralightError mf_ultralight_poller_async_read_tearing_flag( +MfUltralightError mf_ultralight_poller_read_tearing_flag( MfUltralightPoller* instance, uint8_t tearing_falg_num, MfUltralightTearingFlag* data) { diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h index 13490cf1a..c89402b42 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h @@ -103,46 +103,6 @@ bool mf_ultralight_poller_ntag_i2c_addr_lin_to_tag( uint8_t* tag, 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 } #endif diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync.c similarity index 83% rename from lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c rename to lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync.c index 739df597d..c4833facf 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync.c @@ -1,3 +1,4 @@ +#include "mf_ultralight_poller_sync.h" #include "mf_ultralight_poller_i.h" #include @@ -31,40 +32,39 @@ typedef MfUltralightError (*MfUltralightPollerCmdHandler)( MfUltralightError mf_ultralight_poller_read_page_handler( MfUltralightPoller* poller, MfUltralightPollerContextData* data) { - return mf_ultralight_poller_async_read_page( - poller, data->read_cmd.start_page, &data->read_cmd.data); + return mf_ultralight_poller_read_page(poller, data->read_cmd.start_page, &data->read_cmd.data); } MfUltralightError mf_ultralight_poller_write_page_handler( MfUltralightPoller* poller, 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); } MfUltralightError mf_ultralight_poller_read_version_handler( MfUltralightPoller* poller, 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( MfUltralightPoller* poller, 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( MfUltralightPoller* poller, 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); } MfUltralightError mf_ultralight_poller_read_tearing_flag_handler( MfUltralightPoller* poller, 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); } @@ -79,16 +79,14 @@ static const MfUltralightPollerCmdHandler mf_ultralight_poller_read_tearing_flag_handler, }; -static NfcCommand mf_ultralight_poller_cmd_callback(NfcGenericEvent event, void* context) { - furi_assert(event.instance); - furi_assert(event.protocol == NfcProtocolIso14443_3a); - furi_assert(event.event_data); +static NfcCommand mf_ultralight_poller_cmd_callback(NfcGenericEventEx event, void* context) { + furi_assert(event.poller); + furi_assert(event.parent_event_data); furi_assert(context); MfUltralightPollerContext* poller_context = context; - Iso14443_3aPollerEvent* iso14443_3a_event = event.event_data; - Iso14443_3aPoller* iso14443_3a_poller = event.instance; - MfUltralightPoller* mfu_poller = mf_ultralight_poller_alloc(iso14443_3a_poller); + Iso14443_3aPollerEvent* iso14443_3a_event = event.parent_event_data; + MfUltralightPoller* mfu_poller = event.poller; if(iso14443_3a_event->type == Iso14443_3aPollerEventTypeReady) { 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); - mf_ultralight_poller_free(mfu_poller); - return NfcCommandStop; } @@ -110,8 +106,8 @@ static MfUltralightError poller_ctx->thread_id = furi_thread_get_current_id(); - NfcPoller* poller = nfc_poller_alloc(nfc, NfcProtocolIso14443_3a); - nfc_poller_start(poller, mf_ultralight_poller_cmd_callback, poller_ctx); + NfcPoller* poller = nfc_poller_alloc(nfc, NfcProtocolMfUltralight); + 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_clear(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); @@ -121,7 +117,8 @@ static MfUltralightError 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(data); @@ -140,7 +137,7 @@ MfUltralightError mf_ultralight_poller_read_page(Nfc* nfc, uint16_t page, MfUltr } 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(data); @@ -158,7 +155,7 @@ MfUltralightError 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(data); @@ -175,7 +172,7 @@ MfUltralightError mf_ultralight_poller_read_version(Nfc* nfc, MfUltralightVersio 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(data); @@ -192,8 +189,10 @@ MfUltralightError mf_ultralight_poller_read_signature(Nfc* nfc, MfUltralightSign return error; } -MfUltralightError - mf_ultralight_poller_read_counter(Nfc* nfc, uint8_t counter_num, MfUltralightCounter* data) { +MfUltralightError mf_ultralight_poller_sync_read_counter( + Nfc* nfc, + uint8_t counter_num, + MfUltralightCounter* data) { furi_assert(nfc); furi_assert(data); @@ -211,7 +210,7 @@ MfUltralightError return error; } -MfUltralightError mf_ultralight_poller_read_tearing_flag( +MfUltralightError mf_ultralight_poller_sync_read_tearing_flag( Nfc* nfc, uint8_t flag_num, MfUltralightTearingFlag* data) { @@ -261,7 +260,7 @@ static NfcCommand mf_ultralight_poller_read_callback(NfcGenericEvent event, void 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(data); diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync.h new file mode 100644 index 000000000..ac585aad7 --- /dev/null +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync.h @@ -0,0 +1,34 @@ +#pragma once + +#include "mf_ultralight.h" +#include + +#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 diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.h deleted file mode 100644 index a0124ae09..000000000 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include "mf_ultralight.h" -#include - -#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 diff --git a/lib/nfc/protocols/nfc_protocol.h b/lib/nfc/protocols/nfc_protocol.h index 55aa8a589..ee6345333 100644 --- a/lib/nfc/protocols/nfc_protocol.h +++ b/lib/nfc/protocols/nfc_protocol.h @@ -61,9 +61,9 @@ * | | * +- protocol_name_listener_defs.h | * | - * +- protocol_name_sync_api.h | + * +- protocol_name_sync.h | * | |- 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.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_sync_api.h | Synchronous API declarations. (See below for sync API explanation). Optional.| - * | protocol_name_sync_api.c | Synchronous API implementation. Optional. | + * | protocol_name_sync.h | Synchronous API declarations. (See below for sync API explanation). Optional.| + * | protocol_name_sync.c | Synchronous API implementation. Optional. | * * ## 3 Implement the code * @@ -145,7 +145,7 @@ * `protocol_name_poller_defs` structure under the appropriate index. * 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` - * 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. * 7. Done! * diff --git a/lib/nfc/protocols/slix/slix_poller.c b/lib/nfc/protocols/slix/slix_poller.c index 9731bfc6b..46a171194 100644 --- a/lib/nfc/protocols/slix/slix_poller.c +++ b/lib/nfc/protocols/slix/slix_poller.c @@ -50,8 +50,7 @@ static NfcCommand slix_poller_handler_idle(SlixPoller* instance) { } static NfcCommand slix_poller_handler_get_nfc_system_info(SlixPoller* instance) { - instance->error = - slix_poller_async_get_nxp_system_info(instance, &instance->data->system_info); + instance->error = slix_poller_get_nxp_system_info(instance, &instance->data->system_info); if(instance->error == SlixErrorNone) { instance->poller_state = SlixPollerStateReadSignature; } else { @@ -62,7 +61,7 @@ static NfcCommand slix_poller_handler_get_nfc_system_info(SlixPoller* instance) } static NfcCommand slix_poller_handler_read_signature(SlixPoller* instance) { - instance->error = slix_poller_async_read_signature(instance, &instance->data->signature); + instance->error = slix_poller_read_signature(instance, &instance->data->signature); if(instance->error == SlixErrorNone) { instance->poller_state = SlixPollerStateReady; } else { @@ -141,7 +140,7 @@ static bool slix_poller_detect(NfcGenericEvent event, void* context) { if(iso15693_3_event->type == Iso15693_3PollerEventTypeReady) { if(slix_get_type(instance->data) < SlixTypeCount) { SlixSystemInfo system_info = {}; - SlixError error = slix_poller_async_get_nxp_system_info(instance, &system_info); + SlixError error = slix_poller_get_nxp_system_info(instance, &system_info); protocol_detected = (error == SlixErrorNone); } } diff --git a/lib/nfc/protocols/slix/slix_poller.h b/lib/nfc/protocols/slix/slix_poller.h index f4c7214de..62d60be5f 100644 --- a/lib/nfc/protocols/slix/slix_poller.h +++ b/lib/nfc/protocols/slix/slix_poller.h @@ -8,22 +8,78 @@ extern "C" { #endif +/** + * @brief SlixPoller opaque type definition. + */ typedef struct SlixPoller SlixPoller; +/** + * @brief Enumeration of possible Slix poller event types. + */ typedef enum { - SlixPollerEventTypeError, - SlixPollerEventTypeReady, + SlixPollerEventTypeError, /**< An error occured while reading card. */ + SlixPollerEventTypeReady, /**< The card was successfully read by the poller. */ } SlixPollerEventType; -typedef struct { - SlixError error; +/** + * @brief Slixs poller event data. + */ +typedef union { + SlixError error; /**< Error code indicating card reaing fail reason. */ } SlixPollerEventData; +/** + * @brief Slix poller event structure. + * + * Upon emission of an event, an instance of this struct will be passed to the callback. + */ typedef struct { - SlixPollerEventType type; - SlixPollerEventData* data; + SlixPollerEventType type; /**< Type of emmitted event. */ + SlixPollerEventData* data; /**< Pointer to event specific data. */ } SlixPollerEvent; +/** + * @brief Transmit and receive Slix 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 SlixErrorNone on success, an error code on failure. + */ +SlixError slix_poller_send_frame( + SlixPoller* instance, + const BitBuffer* tx_data, + BitBuffer* rx_data, + uint32_t fwt); + +/** + * @brief Send get nxp 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 SlixSystemInfo structure to be filled. + * @return SlixErrorNone on success, an error code on failure. + */ +SlixError slix_poller_get_nxp_system_info(SlixPoller* instance, SlixSystemInfo* 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 SlixSignature structure to be filled. + * @return SlixErrorNone on success, an error code on failure. + */ +SlixError slix_poller_read_signature(SlixPoller* instance, SlixSignature* data); + #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/slix/slix_poller_i.c b/lib/nfc/protocols/slix/slix_poller_i.c index a36e7694a..6d7bdf377 100644 --- a/lib/nfc/protocols/slix/slix_poller_i.c +++ b/lib/nfc/protocols/slix/slix_poller_i.c @@ -32,7 +32,7 @@ SlixError slix_poller_send_frame( return slix_process_iso15693_3_error(iso15693_3_error); } -SlixError slix_poller_async_get_nxp_system_info(SlixPoller* instance, SlixSystemInfo* data) { +SlixError slix_poller_get_nxp_system_info(SlixPoller* instance, SlixSystemInfo* data) { furi_assert(instance); furi_assert(data); @@ -50,7 +50,7 @@ SlixError slix_poller_async_get_nxp_system_info(SlixPoller* instance, SlixSystem return error; } -SlixError slix_poller_async_read_signature(SlixPoller* instance, SlixSignature* data) { +SlixError slix_poller_read_signature(SlixPoller* instance, SlixSignature* data) { furi_assert(instance); furi_assert(data); diff --git a/lib/nfc/protocols/slix/slix_poller_i.h b/lib/nfc/protocols/slix/slix_poller_i.h index c6a8a3c33..1fda1a7d2 100644 --- a/lib/nfc/protocols/slix/slix_poller_i.h +++ b/lib/nfc/protocols/slix/slix_poller_i.h @@ -33,16 +33,6 @@ struct SlixPoller { void* context; }; -SlixError slix_poller_send_frame( - SlixPoller* instance, - const BitBuffer* tx_data, - BitBuffer* rx_data, - uint32_t fwt); - -SlixError slix_poller_async_get_nxp_system_info(SlixPoller* instance, SlixSystemInfo* data); - -SlixError slix_poller_async_read_signature(SlixPoller* instance, SlixSignature* data); - #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/st25tb/st25tb_poller.c b/lib/nfc/protocols/st25tb/st25tb_poller.c index df659a205..2bc5dd941 100644 --- a/lib/nfc/protocols/st25tb/st25tb_poller.c +++ b/lib/nfc/protocols/st25tb/st25tb_poller.c @@ -71,7 +71,7 @@ static NfcCommand st25tb_poller_run(NfcGenericEvent event, void* context) { if(nfc_event->type == NfcEventTypePollerReady) { if(instance->state != St25tbPollerStateActivated) { - St25tbError error = st25tb_poller_async_activate(instance, instance->data); + St25tbError error = st25tb_poller_activate(instance, instance->data); if(error == St25tbErrorNone) { instance->st25tb_event.type = St25tbPollerEventTypeReady; @@ -106,7 +106,7 @@ static bool st25tb_poller_detect(NfcGenericEvent event, void* context) { furi_assert(instance->state == St25tbPollerStateIdle); if(nfc_event->type == NfcEventTypePollerReady) { - St25tbError error = st25tb_poller_async_initiate(instance, NULL); + St25tbError error = st25tb_poller_initiate(instance, NULL); protocol_detected = (error == St25tbErrorNone); } diff --git a/lib/nfc/protocols/st25tb/st25tb_poller.h b/lib/nfc/protocols/st25tb/st25tb_poller.h index a521b6d5b..d3b85e306 100644 --- a/lib/nfc/protocols/st25tb/st25tb_poller.h +++ b/lib/nfc/protocols/st25tb/st25tb_poller.h @@ -25,6 +25,23 @@ typedef struct { St25tbPollerEventData* data; } St25tbPollerEvent; +St25tbError st25tb_poller_send_frame( + St25tbPoller* instance, + const BitBuffer* tx_buffer, + BitBuffer* rx_buffer, + uint32_t fwt); + +St25tbError st25tb_poller_initiate(St25tbPoller* instance, uint8_t* chip_id); + +St25tbError st25tb_poller_activate(St25tbPoller* instance, St25tbData* data); + +St25tbError st25tb_poller_get_uid(St25tbPoller* instance, uint8_t* uid); + +St25tbError + st25tb_poller_read_block(St25tbPoller* instance, uint32_t* block, uint8_t block_number); + +St25tbError st25tb_poller_halt(St25tbPoller* instance); + #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/st25tb/st25tb_poller_i.c b/lib/nfc/protocols/st25tb/st25tb_poller_i.c index bcbc69382..76c9a8b1f 100644 --- a/lib/nfc/protocols/st25tb/st25tb_poller_i.c +++ b/lib/nfc/protocols/st25tb/st25tb_poller_i.c @@ -22,7 +22,7 @@ static St25tbError st25tb_poller_prepare_trx(St25tbPoller* instance) { furi_assert(instance); if(instance->state == St25tbPollerStateIdle) { - return st25tb_poller_async_activate(instance, NULL); + return st25tb_poller_activate(instance, NULL); } return St25tbErrorNone; @@ -85,7 +85,7 @@ St25tbType st25tb_get_type_from_uid(const uint8_t uid[ST25TB_UID_SIZE]) { } } -St25tbError st25tb_poller_async_initiate(St25tbPoller* instance, uint8_t* chip_id) { +St25tbError st25tb_poller_initiate(St25tbPoller* instance, uint8_t* chip_id) { // Send Initiate() furi_assert(instance); furi_assert(instance->nfc); @@ -117,7 +117,7 @@ St25tbError st25tb_poller_async_initiate(St25tbPoller* instance, uint8_t* chip_i return ret; } -St25tbError st25tb_poller_async_activate(St25tbPoller* instance, St25tbData* data) { +St25tbError st25tb_poller_activate(St25tbPoller* instance, St25tbData* data) { furi_assert(instance); furi_assert(instance->nfc); @@ -126,7 +126,7 @@ St25tbError st25tb_poller_async_activate(St25tbPoller* instance, St25tbData* dat St25tbError ret; do { - ret = st25tb_poller_async_initiate(instance, &data->chip_id); + ret = st25tb_poller_initiate(instance, &data->chip_id); if(ret != St25tbErrorNone) { break; } @@ -162,7 +162,7 @@ St25tbError st25tb_poller_async_activate(St25tbPoller* instance, St25tbData* dat } instance->state = St25tbPollerStateActivated; - ret = st25tb_poller_async_get_uid(instance, data->uid); + ret = st25tb_poller_get_uid(instance, data->uid); if(ret != St25tbErrorNone) { instance->state = St25tbPollerStateActivationFailed; break; @@ -171,7 +171,7 @@ St25tbError st25tb_poller_async_activate(St25tbPoller* instance, St25tbData* dat bool read_blocks = true; for(uint8_t i = 0; i < st25tb_get_block_count(data->type); i++) { - ret = st25tb_poller_async_read_block(instance, &data->blocks[i], i); + ret = st25tb_poller_read_block(instance, &data->blocks[i], i); if(ret != St25tbErrorNone) { read_blocks = false; break; @@ -180,14 +180,13 @@ St25tbError st25tb_poller_async_activate(St25tbPoller* instance, St25tbData* dat if(!read_blocks) { break; } - ret = st25tb_poller_async_read_block( - instance, &data->system_otp_block, ST25TB_SYSTEM_OTP_BLOCK); + ret = st25tb_poller_read_block(instance, &data->system_otp_block, ST25TB_SYSTEM_OTP_BLOCK); } while(false); return ret; } -St25tbError st25tb_poller_async_get_uid(St25tbPoller* instance, uint8_t uid[ST25TB_UID_SIZE]) { +St25tbError st25tb_poller_get_uid(St25tbPoller* instance, uint8_t* uid) { furi_assert(instance); furi_assert(instance->nfc); @@ -221,7 +220,7 @@ St25tbError st25tb_poller_async_get_uid(St25tbPoller* instance, uint8_t uid[ST25 } St25tbError - st25tb_poller_async_read_block(St25tbPoller* instance, uint32_t* block, uint8_t block_number) { + st25tb_poller_read_block(St25tbPoller* instance, uint32_t* block, uint8_t block_number) { furi_assert(instance); furi_assert(instance->nfc); furi_assert(block); diff --git a/lib/nfc/protocols/st25tb/st25tb_poller_i.h b/lib/nfc/protocols/st25tb/st25tb_poller_i.h index 7f38f2d45..27218d7b4 100644 --- a/lib/nfc/protocols/st25tb/st25tb_poller_i.h +++ b/lib/nfc/protocols/st25tb/st25tb_poller_i.h @@ -34,23 +34,6 @@ struct St25tbPoller { const St25tbData* st25tb_poller_get_data(St25tbPoller* instance); -St25tbError st25tb_poller_async_initiate(St25tbPoller* instance, uint8_t* chip_id); - -St25tbError st25tb_poller_async_activate(St25tbPoller* instance, St25tbData* data); - -St25tbError st25tb_poller_async_get_uid(St25tbPoller* instance, uint8_t uid[ST25TB_UID_SIZE]); - -St25tbError - st25tb_poller_async_read_block(St25tbPoller* instance, uint32_t* block, uint8_t block_number); - -St25tbError st25tb_poller_halt(St25tbPoller* instance); - -St25tbError st25tb_poller_send_frame( - St25tbPoller* instance, - const BitBuffer* tx_buffer, - BitBuffer* rx_buffer, - uint32_t fwt); - #ifdef __cplusplus } #endif diff --git a/targets/f18/api_symbols.csv b/targets/f18/api_symbols.csv index 0eadd799d..44829c264 100644 --- a/targets/f18/api_symbols.csv +++ b/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,44.0,, +Version,+,45.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -39,6 +39,8 @@ Header,+,applications/services/storage/storage.h,, Header,+,lib/digital_signal/digital_sequence.h,, Header,+,lib/digital_signal/digital_signal.h,, Header,+,lib/drivers/cc1101_regs.h,, +Header,+,lib/drivers/st25r3916.h,, +Header,+,lib/drivers/st25r3916_reg.h,, Header,+,lib/flipper_application/api_hashtable/api_hashtable.h,, Header,+,lib/flipper_application/api_hashtable/compilesort.hpp,, Header,+,lib/flipper_application/flipper_application.h,, @@ -2045,6 +2047,29 @@ Function,+,srand,void,unsigned Function,-,srand48,void,long Function,-,srandom,void,unsigned Function,+,sscanf,int,"const char*, const char*, ..." +Function,+,st25r3916_change_reg_bits,void,"FuriHalSpiBusHandle*, uint8_t, uint8_t, uint8_t" +Function,+,st25r3916_change_test_reg_bits,void,"FuriHalSpiBusHandle*, uint8_t, uint8_t, uint8_t" +Function,+,st25r3916_check_reg,_Bool,"FuriHalSpiBusHandle*, uint8_t, uint8_t, uint8_t" +Function,+,st25r3916_clear_reg_bits,void,"FuriHalSpiBusHandle*, uint8_t, uint8_t" +Function,+,st25r3916_direct_cmd,void,"FuriHalSpiBusHandle*, uint8_t" +Function,+,st25r3916_get_irq,uint32_t,FuriHalSpiBusHandle* +Function,+,st25r3916_mask_irq,void,"FuriHalSpiBusHandle*, uint32_t" +Function,+,st25r3916_modify_reg,void,"FuriHalSpiBusHandle*, uint8_t, uint8_t, uint8_t" +Function,+,st25r3916_read_burst_regs,void,"FuriHalSpiBusHandle*, uint8_t, uint8_t*, uint8_t" +Function,+,st25r3916_read_fifo,_Bool,"FuriHalSpiBusHandle*, uint8_t*, size_t, size_t*" +Function,+,st25r3916_read_pta_mem,void,"FuriHalSpiBusHandle*, uint8_t*, size_t" +Function,+,st25r3916_read_reg,void,"FuriHalSpiBusHandle*, uint8_t, uint8_t*" +Function,+,st25r3916_read_test_reg,void,"FuriHalSpiBusHandle*, uint8_t, uint8_t*" +Function,+,st25r3916_reg_read_fifo,void,"FuriHalSpiBusHandle*, uint8_t*, size_t" +Function,+,st25r3916_reg_write_fifo,void,"FuriHalSpiBusHandle*, const uint8_t*, size_t" +Function,+,st25r3916_set_reg_bits,void,"FuriHalSpiBusHandle*, uint8_t, uint8_t" +Function,+,st25r3916_write_burst_regs,void,"FuriHalSpiBusHandle*, uint8_t, const uint8_t*, uint8_t" +Function,+,st25r3916_write_fifo,void,"FuriHalSpiBusHandle*, const uint8_t*, size_t" +Function,+,st25r3916_write_pta_mem,void,"FuriHalSpiBusHandle*, const uint8_t*, size_t" +Function,+,st25r3916_write_ptf_mem,void,"FuriHalSpiBusHandle*, const uint8_t*, size_t" +Function,+,st25r3916_write_pttsn_mem,void,"FuriHalSpiBusHandle*, uint8_t*, size_t" +Function,+,st25r3916_write_reg,void,"FuriHalSpiBusHandle*, uint8_t, uint8_t" +Function,+,st25r3916_write_test_reg,void,"FuriHalSpiBusHandle*, uint8_t, uint8_t" Function,+,storage_common_copy,FS_Error,"Storage*, const char*, const char*" Function,+,storage_common_exists,_Bool,"Storage*, const char*" Function,+,storage_common_fs_info,FS_Error,"Storage*, const char*, uint64_t*, uint64_t*" diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 983453195..514f33286 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,44.0,, +Version,+,45.0,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, @@ -40,6 +40,8 @@ Header,+,applications/services/storage/storage.h,, Header,+,lib/digital_signal/digital_sequence.h,, Header,+,lib/digital_signal/digital_signal.h,, Header,+,lib/drivers/cc1101_regs.h,, +Header,+,lib/drivers/st25r3916.h,, +Header,+,lib/drivers/st25r3916_reg.h,, Header,+,lib/flipper_application/api_hashtable/api_hashtable.h,, Header,+,lib/flipper_application/api_hashtable/compilesort.hpp,, Header,+,lib/flipper_application/flipper_application.h,, @@ -117,7 +119,7 @@ Header,+,lib/nfc/nfc_scanner.h,, Header,+,lib/nfc/protocols/iso14443_3a/iso14443_3a.h,, Header,+,lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.h,, Header,+,lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.h,, -Header,+,lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_sync_api.h,, +Header,+,lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_sync.h,, Header,+,lib/nfc/protocols/iso14443_3b/iso14443_3b.h,, Header,+,lib/nfc/protocols/iso14443_3b/iso14443_3b_poller.h,, Header,+,lib/nfc/protocols/iso14443_4a/iso14443_4a.h,, @@ -128,13 +130,13 @@ Header,+,lib/nfc/protocols/iso14443_4b/iso14443_4b_poller.h,, Header,+,lib/nfc/protocols/mf_classic/mf_classic.h,, Header,+,lib/nfc/protocols/mf_classic/mf_classic_listener.h,, Header,+,lib/nfc/protocols/mf_classic/mf_classic_poller.h,, -Header,+,lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.h,, +Header,+,lib/nfc/protocols/mf_classic/mf_classic_poller_sync.h,, Header,+,lib/nfc/protocols/mf_desfire/mf_desfire.h,, Header,+,lib/nfc/protocols/mf_desfire/mf_desfire_poller.h,, Header,+,lib/nfc/protocols/mf_ultralight/mf_ultralight.h,, Header,+,lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.h,, Header,+,lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h,, -Header,+,lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.h,, +Header,+,lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync.h,, Header,+,lib/nfc/protocols/slix/slix.h,, Header,+,lib/nfc/protocols/st25tb/st25tb.h,, Header,+,lib/nfc/protocols/st25tb/st25tb_poller.h,, @@ -1861,9 +1863,13 @@ Function,+,iso14443_3a_get_sak,uint8_t,const Iso14443_3aData* Function,+,iso14443_3a_get_uid,const uint8_t*,"const Iso14443_3aData*, size_t*" Function,+,iso14443_3a_is_equal,_Bool,"const Iso14443_3aData*, const Iso14443_3aData*" Function,+,iso14443_3a_load,_Bool,"Iso14443_3aData*, FlipperFormat*, uint32_t" -Function,+,iso14443_3a_poller_read,Iso14443_3aError,"Nfc*, Iso14443_3aData*" +Function,+,iso14443_3a_poller_activate,Iso14443_3aError,"Iso14443_3aPoller*, Iso14443_3aData*" +Function,+,iso14443_3a_poller_check_presence,Iso14443_3aError,Iso14443_3aPoller* +Function,+,iso14443_3a_poller_halt,Iso14443_3aError,Iso14443_3aPoller* Function,+,iso14443_3a_poller_send_standard_frame,Iso14443_3aError,"Iso14443_3aPoller*, const BitBuffer*, BitBuffer*, uint32_t" +Function,+,iso14443_3a_poller_sync_read,Iso14443_3aError,"Nfc*, Iso14443_3aData*" Function,+,iso14443_3a_poller_txrx,Iso14443_3aError,"Iso14443_3aPoller*, const BitBuffer*, BitBuffer*, uint32_t" +Function,+,iso14443_3a_poller_txrx_custom_parity,Iso14443_3aError,"Iso14443_3aPoller*, const BitBuffer*, BitBuffer*, uint32_t" Function,+,iso14443_3a_reset,void,Iso14443_3aData* Function,+,iso14443_3a_save,_Bool,"const Iso14443_3aData*, FlipperFormat*" Function,+,iso14443_3a_set_atqa,void,"Iso14443_3aData*, const uint8_t[2]" @@ -1882,6 +1888,9 @@ Function,+,iso14443_3b_get_fwt_fc_max,uint32_t,const Iso14443_3bData* Function,+,iso14443_3b_get_uid,const uint8_t*,"const Iso14443_3bData*, size_t*" Function,+,iso14443_3b_is_equal,_Bool,"const Iso14443_3bData*, const Iso14443_3bData*" Function,+,iso14443_3b_load,_Bool,"Iso14443_3bData*, FlipperFormat*, uint32_t" +Function,+,iso14443_3b_poller_activate,Iso14443_3bError,"Iso14443_3bPoller*, Iso14443_3bData*" +Function,+,iso14443_3b_poller_halt,Iso14443_3bError,Iso14443_3bPoller* +Function,+,iso14443_3b_poller_send_frame,Iso14443_3bError,"Iso14443_3bPoller*, const BitBuffer*, BitBuffer*" Function,+,iso14443_3b_reset,void,Iso14443_3bData* Function,+,iso14443_3b_save,_Bool,"const Iso14443_3bData*, FlipperFormat*" Function,+,iso14443_3b_set_uid,_Bool,"Iso14443_3bData*, const uint8_t*, size_t" @@ -1900,6 +1909,9 @@ Function,+,iso14443_4a_get_historical_bytes,const uint8_t*,"const Iso14443_4aDat Function,+,iso14443_4a_get_uid,const uint8_t*,"const Iso14443_4aData*, size_t*" Function,+,iso14443_4a_is_equal,_Bool,"const Iso14443_4aData*, const Iso14443_4aData*" Function,+,iso14443_4a_load,_Bool,"Iso14443_4aData*, FlipperFormat*, uint32_t" +Function,+,iso14443_4a_poller_halt,Iso14443_4aError,Iso14443_4aPoller* +Function,+,iso14443_4a_poller_read_ats,Iso14443_4aError,"Iso14443_4aPoller*, Iso14443_4aAtsData*" +Function,+,iso14443_4a_poller_send_block,Iso14443_4aError,"Iso14443_4aPoller*, const BitBuffer*, BitBuffer*" Function,+,iso14443_4a_reset,void,Iso14443_4aData* Function,+,iso14443_4a_save,_Bool,"const Iso14443_4aData*, FlipperFormat*" Function,+,iso14443_4a_set_uid,_Bool,"Iso14443_4aData*, const uint8_t*, size_t" @@ -1914,6 +1926,8 @@ Function,+,iso14443_4b_get_device_name,const char*,"const Iso14443_4bData*, NfcD Function,+,iso14443_4b_get_uid,const uint8_t*,"const Iso14443_4bData*, size_t*" Function,+,iso14443_4b_is_equal,_Bool,"const Iso14443_4bData*, const Iso14443_4bData*" Function,+,iso14443_4b_load,_Bool,"Iso14443_4bData*, FlipperFormat*, uint32_t" +Function,+,iso14443_4b_poller_halt,Iso14443_4bError,Iso14443_4bPoller* +Function,+,iso14443_4b_poller_send_block,Iso14443_4bError,"Iso14443_4bPoller*, const BitBuffer*, BitBuffer*" Function,+,iso14443_4b_reset,void,Iso14443_4bData* Function,+,iso14443_4b_save,_Bool,"const Iso14443_4bData*, FlipperFormat*" Function,+,iso14443_4b_set_uid,_Bool,"Iso14443_4bData*, const uint8_t*, size_t" @@ -2141,14 +2155,21 @@ Function,+,mf_classic_is_sector_read,_Bool,"const MfClassicData*, uint8_t" Function,+,mf_classic_is_sector_trailer,_Bool,uint8_t Function,+,mf_classic_is_value_block,_Bool,"MfClassicSectorTrailer*, uint8_t" Function,+,mf_classic_load,_Bool,"MfClassicData*, FlipperFormat*, uint32_t" -Function,+,mf_classic_poller_auth,MfClassicError,"Nfc*, uint8_t, MfClassicKey*, MfClassicKeyType, MfClassicAuthContext*" -Function,+,mf_classic_poller_change_value,MfClassicError,"Nfc*, uint8_t, MfClassicKey*, MfClassicKeyType, int32_t, int32_t*" -Function,+,mf_classic_poller_collect_nt,MfClassicError,"Nfc*, uint8_t, MfClassicKeyType, MfClassicNt*" -Function,+,mf_classic_poller_detect_type,MfClassicError,"Nfc*, MfClassicType*" -Function,+,mf_classic_poller_read,MfClassicError,"Nfc*, const MfClassicDeviceKeys*, MfClassicData*" -Function,+,mf_classic_poller_read_block,MfClassicError,"Nfc*, uint8_t, MfClassicKey*, MfClassicKeyType, MfClassicBlock*" -Function,+,mf_classic_poller_read_value,MfClassicError,"Nfc*, uint8_t, MfClassicKey*, MfClassicKeyType, int32_t*" -Function,+,mf_classic_poller_write_block,MfClassicError,"Nfc*, uint8_t, MfClassicKey*, MfClassicKeyType, MfClassicBlock*" +Function,+,mf_classic_poller_auth,MfClassicError,"MfClassicPoller*, uint8_t, MfClassicKey*, MfClassicKeyType, MfClassicAuthContext*" +Function,+,mf_classic_poller_get_nt,MfClassicError,"MfClassicPoller*, uint8_t, MfClassicKeyType, MfClassicNt*" +Function,+,mf_classic_poller_halt,MfClassicError,MfClassicPoller* +Function,+,mf_classic_poller_read_block,MfClassicError,"MfClassicPoller*, uint8_t, MfClassicBlock*" +Function,+,mf_classic_poller_sync_auth,MfClassicError,"Nfc*, uint8_t, MfClassicKey*, MfClassicKeyType, MfClassicAuthContext*" +Function,+,mf_classic_poller_sync_change_value,MfClassicError,"Nfc*, uint8_t, MfClassicKey*, MfClassicKeyType, int32_t, int32_t*" +Function,+,mf_classic_poller_sync_collect_nt,MfClassicError,"Nfc*, uint8_t, MfClassicKeyType, MfClassicNt*" +Function,+,mf_classic_poller_sync_detect_type,MfClassicError,"Nfc*, MfClassicType*" +Function,+,mf_classic_poller_sync_read,MfClassicError,"Nfc*, const MfClassicDeviceKeys*, MfClassicData*" +Function,+,mf_classic_poller_sync_read_block,MfClassicError,"Nfc*, uint8_t, MfClassicKey*, MfClassicKeyType, MfClassicBlock*" +Function,+,mf_classic_poller_sync_read_value,MfClassicError,"Nfc*, uint8_t, MfClassicKey*, MfClassicKeyType, int32_t*" +Function,+,mf_classic_poller_sync_write_block,MfClassicError,"Nfc*, uint8_t, MfClassicKey*, MfClassicKeyType, MfClassicBlock*" +Function,+,mf_classic_poller_value_cmd,MfClassicError,"MfClassicPoller*, uint8_t, MfClassicValueCommand, int32_t" +Function,+,mf_classic_poller_value_transfer,MfClassicError,"MfClassicPoller*, uint8_t" +Function,+,mf_classic_poller_write_block,MfClassicError,"MfClassicPoller*, uint8_t, MfClassicBlock*" Function,+,mf_classic_reset,void,MfClassicData* Function,+,mf_classic_save,_Bool,"const MfClassicData*, FlipperFormat*" Function,+,mf_classic_set_block_read,void,"MfClassicData*, uint8_t, MfClassicBlock*" @@ -2168,8 +2189,24 @@ Function,+,mf_desfire_get_file_settings,const MfDesfireFileSettings*,"const MfDe Function,+,mf_desfire_get_uid,const uint8_t*,"const MfDesfireData*, size_t*" Function,+,mf_desfire_is_equal,_Bool,"const MfDesfireData*, const MfDesfireData*" Function,+,mf_desfire_load,_Bool,"MfDesfireData*, FlipperFormat*, uint32_t" +Function,+,mf_desfire_poller_read_application,MfDesfireError,"MfDesfirePoller*, MfDesfireApplication*" +Function,+,mf_desfire_poller_read_application_ids,MfDesfireError,"MfDesfirePoller*, SimpleArray*" +Function,+,mf_desfire_poller_read_applications,MfDesfireError,"MfDesfirePoller*, const SimpleArray*, SimpleArray*" +Function,+,mf_desfire_poller_read_file_data,MfDesfireError,"MfDesfirePoller*, MfDesfireFileId, uint32_t, size_t, MfDesfireFileData*" +Function,+,mf_desfire_poller_read_file_data_multi,MfDesfireError,"MfDesfirePoller*, const SimpleArray*, const SimpleArray*, SimpleArray*" +Function,+,mf_desfire_poller_read_file_ids,MfDesfireError,"MfDesfirePoller*, SimpleArray*" +Function,+,mf_desfire_poller_read_file_records,MfDesfireError,"MfDesfirePoller*, MfDesfireFileId, uint32_t, size_t, MfDesfireFileData*" +Function,+,mf_desfire_poller_read_file_settings,MfDesfireError,"MfDesfirePoller*, MfDesfireFileId, MfDesfireFileSettings*" +Function,+,mf_desfire_poller_read_file_settings_multi,MfDesfireError,"MfDesfirePoller*, const SimpleArray*, SimpleArray*" +Function,+,mf_desfire_poller_read_file_value,MfDesfireError,"MfDesfirePoller*, MfDesfireFileId, MfDesfireFileData*" +Function,+,mf_desfire_poller_read_free_memory,MfDesfireError,"MfDesfirePoller*, MfDesfireFreeMemory*" +Function,+,mf_desfire_poller_read_key_settings,MfDesfireError,"MfDesfirePoller*, MfDesfireKeySettings*" +Function,+,mf_desfire_poller_read_key_versions,MfDesfireError,"MfDesfirePoller*, SimpleArray*, uint32_t" +Function,+,mf_desfire_poller_read_version,MfDesfireError,"MfDesfirePoller*, MfDesfireVersion*" +Function,+,mf_desfire_poller_select_application,MfDesfireError,"MfDesfirePoller*, const MfDesfireApplicationId*" Function,+,mf_desfire_reset,void,MfDesfireData* Function,+,mf_desfire_save,_Bool,"const MfDesfireData*, FlipperFormat*" +Function,+,mf_desfire_send_chunks,MfDesfireError,"MfDesfirePoller*, const BitBuffer*, BitBuffer*" Function,+,mf_desfire_set_uid,_Bool,"MfDesfireData*, const uint8_t*, size_t" Function,+,mf_desfire_verify,_Bool,"MfDesfireData*, const FuriString*" Function,+,mf_ultralight_alloc,MfUltralightData*, @@ -2190,13 +2227,22 @@ Function,+,mf_ultralight_is_counter_configured,_Bool,const MfUltralightData* Function,+,mf_ultralight_is_equal,_Bool,"const MfUltralightData*, const MfUltralightData*" Function,+,mf_ultralight_is_page_pwd_or_pack,_Bool,"MfUltralightType, uint16_t" Function,+,mf_ultralight_load,_Bool,"MfUltralightData*, FlipperFormat*, uint32_t" -Function,+,mf_ultralight_poller_read_card,MfUltralightError,"Nfc*, MfUltralightData*" -Function,+,mf_ultralight_poller_read_counter,MfUltralightError,"Nfc*, uint8_t, MfUltralightCounter*" -Function,+,mf_ultralight_poller_read_page,MfUltralightError,"Nfc*, uint16_t, MfUltralightPage*" -Function,+,mf_ultralight_poller_read_signature,MfUltralightError,"Nfc*, MfUltralightSignature*" -Function,+,mf_ultralight_poller_read_tearing_flag,MfUltralightError,"Nfc*, uint8_t, MfUltralightTearingFlag*" -Function,+,mf_ultralight_poller_read_version,MfUltralightError,"Nfc*, MfUltralightVersion*" -Function,+,mf_ultralight_poller_write_page,MfUltralightError,"Nfc*, uint16_t, MfUltralightPage*" +Function,+,mf_ultralight_poller_auth_pwd,MfUltralightError,"MfUltralightPoller*, MfUltralightPollerAuthContext*" +Function,+,mf_ultralight_poller_authenticate,MfUltralightError,MfUltralightPoller* +Function,+,mf_ultralight_poller_read_counter,MfUltralightError,"MfUltralightPoller*, uint8_t, MfUltralightCounter*" +Function,+,mf_ultralight_poller_read_page,MfUltralightError,"MfUltralightPoller*, uint8_t, MfUltralightPageReadCommandData*" +Function,+,mf_ultralight_poller_read_page_from_sector,MfUltralightError,"MfUltralightPoller*, uint8_t, uint8_t, MfUltralightPageReadCommandData*" +Function,+,mf_ultralight_poller_read_signature,MfUltralightError,"MfUltralightPoller*, MfUltralightSignature*" +Function,+,mf_ultralight_poller_read_tearing_flag,MfUltralightError,"MfUltralightPoller*, uint8_t, MfUltralightTearingFlag*" +Function,+,mf_ultralight_poller_read_version,MfUltralightError,"MfUltralightPoller*, MfUltralightVersion*" +Function,+,mf_ultralight_poller_sync_read_card,MfUltralightError,"Nfc*, MfUltralightData*" +Function,+,mf_ultralight_poller_sync_read_counter,MfUltralightError,"Nfc*, uint8_t, MfUltralightCounter*" +Function,+,mf_ultralight_poller_sync_read_page,MfUltralightError,"Nfc*, uint16_t, MfUltralightPage*" +Function,+,mf_ultralight_poller_sync_read_signature,MfUltralightError,"Nfc*, MfUltralightSignature*" +Function,+,mf_ultralight_poller_sync_read_tearing_flag,MfUltralightError,"Nfc*, uint8_t, MfUltralightTearingFlag*" +Function,+,mf_ultralight_poller_sync_read_version,MfUltralightError,"Nfc*, MfUltralightVersion*" +Function,+,mf_ultralight_poller_sync_write_page,MfUltralightError,"Nfc*, uint16_t, MfUltralightPage*" +Function,+,mf_ultralight_poller_write_page,MfUltralightError,"MfUltralightPoller*, uint8_t, const MfUltralightPage*" Function,+,mf_ultralight_reset,void,MfUltralightData* Function,+,mf_ultralight_save,_Bool,"const MfUltralightData*, FlipperFormat*" Function,+,mf_ultralight_set_uid,_Bool,"MfUltralightData*, const uint8_t*, size_t" @@ -2290,6 +2336,7 @@ Function,+,nfc_poller_free,void,NfcPoller* Function,+,nfc_poller_get_data,const NfcDeviceData*,const NfcPoller* Function,+,nfc_poller_get_protocol,NfcProtocol,const NfcPoller* Function,+,nfc_poller_start,void,"NfcPoller*, NfcGenericCallback, void*" +Function,+,nfc_poller_start_ex,void,"NfcPoller*, NfcGenericCallbackEx, void*" Function,+,nfc_poller_stop,void,NfcPoller* Function,+,nfc_poller_trx,NfcError,"Nfc*, const BitBuffer*, BitBuffer*, uint32_t" Function,+,nfc_protocol_get_parent,NfcProtocol,NfcProtocol @@ -2608,6 +2655,29 @@ Function,+,srand,void,unsigned Function,-,srand48,void,long Function,-,srandom,void,unsigned Function,+,sscanf,int,"const char*, const char*, ..." +Function,+,st25r3916_change_reg_bits,void,"FuriHalSpiBusHandle*, uint8_t, uint8_t, uint8_t" +Function,+,st25r3916_change_test_reg_bits,void,"FuriHalSpiBusHandle*, uint8_t, uint8_t, uint8_t" +Function,+,st25r3916_check_reg,_Bool,"FuriHalSpiBusHandle*, uint8_t, uint8_t, uint8_t" +Function,+,st25r3916_clear_reg_bits,void,"FuriHalSpiBusHandle*, uint8_t, uint8_t" +Function,+,st25r3916_direct_cmd,void,"FuriHalSpiBusHandle*, uint8_t" +Function,+,st25r3916_get_irq,uint32_t,FuriHalSpiBusHandle* +Function,+,st25r3916_mask_irq,void,"FuriHalSpiBusHandle*, uint32_t" +Function,+,st25r3916_modify_reg,void,"FuriHalSpiBusHandle*, uint8_t, uint8_t, uint8_t" +Function,+,st25r3916_read_burst_regs,void,"FuriHalSpiBusHandle*, uint8_t, uint8_t*, uint8_t" +Function,+,st25r3916_read_fifo,_Bool,"FuriHalSpiBusHandle*, uint8_t*, size_t, size_t*" +Function,+,st25r3916_read_pta_mem,void,"FuriHalSpiBusHandle*, uint8_t*, size_t" +Function,+,st25r3916_read_reg,void,"FuriHalSpiBusHandle*, uint8_t, uint8_t*" +Function,+,st25r3916_read_test_reg,void,"FuriHalSpiBusHandle*, uint8_t, uint8_t*" +Function,+,st25r3916_reg_read_fifo,void,"FuriHalSpiBusHandle*, uint8_t*, size_t" +Function,+,st25r3916_reg_write_fifo,void,"FuriHalSpiBusHandle*, const uint8_t*, size_t" +Function,+,st25r3916_set_reg_bits,void,"FuriHalSpiBusHandle*, uint8_t, uint8_t" +Function,+,st25r3916_write_burst_regs,void,"FuriHalSpiBusHandle*, uint8_t, const uint8_t*, uint8_t" +Function,+,st25r3916_write_fifo,void,"FuriHalSpiBusHandle*, const uint8_t*, size_t" +Function,+,st25r3916_write_pta_mem,void,"FuriHalSpiBusHandle*, const uint8_t*, size_t" +Function,+,st25r3916_write_ptf_mem,void,"FuriHalSpiBusHandle*, const uint8_t*, size_t" +Function,+,st25r3916_write_pttsn_mem,void,"FuriHalSpiBusHandle*, uint8_t*, size_t" +Function,+,st25r3916_write_reg,void,"FuriHalSpiBusHandle*, uint8_t, uint8_t" +Function,+,st25r3916_write_test_reg,void,"FuriHalSpiBusHandle*, uint8_t, uint8_t" Function,+,st25tb_alloc,St25tbData*, Function,+,st25tb_copy,void,"St25tbData*, const St25tbData*" Function,+,st25tb_free,void,St25tbData* @@ -2617,6 +2687,12 @@ Function,+,st25tb_get_device_name,const char*,"const St25tbData*, NfcDeviceNameT Function,+,st25tb_get_uid,const uint8_t*,"const St25tbData*, size_t*" Function,+,st25tb_is_equal,_Bool,"const St25tbData*, const St25tbData*" Function,+,st25tb_load,_Bool,"St25tbData*, FlipperFormat*, uint32_t" +Function,+,st25tb_poller_activate,St25tbError,"St25tbPoller*, St25tbData*" +Function,+,st25tb_poller_get_uid,St25tbError,"St25tbPoller*, uint8_t*" +Function,+,st25tb_poller_halt,St25tbError,St25tbPoller* +Function,+,st25tb_poller_initiate,St25tbError,"St25tbPoller*, uint8_t*" +Function,+,st25tb_poller_read_block,St25tbError,"St25tbPoller*, uint32_t*, uint8_t" +Function,+,st25tb_poller_send_frame,St25tbError,"St25tbPoller*, const BitBuffer*, BitBuffer*, uint32_t" Function,+,st25tb_reset,void,St25tbData* Function,+,st25tb_save,_Bool,"const St25tbData*, FlipperFormat*" Function,+,st25tb_set_uid,_Bool,"St25tbData*, const uint8_t*, size_t" From 615a1479734ecf2e03626153f60dc267800cc429 Mon Sep 17 00:00:00 2001 From: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Date: Wed, 15 Nov 2023 11:45:41 +0300 Subject: [PATCH 4/9] [FL-3608] Fix iButton crash on missing file (#3210) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- applications/main/ibutton/ibutton.c | 13 ++++++------- applications/main/ibutton/ibutton_i.h | 2 +- .../main/ibutton/scenes/ibutton_scene_add_value.c | 2 +- .../main/ibutton/scenes/ibutton_scene_rpc.c | 2 +- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/applications/main/ibutton/ibutton.c b/applications/main/ibutton/ibutton.c index fb6d9dcb5..afd51f7c9 100644 --- a/applications/main/ibutton/ibutton.c +++ b/applications/main/ibutton/ibutton.c @@ -174,22 +174,21 @@ void ibutton_free(iButton* 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); const bool success = ibutton_protocols_load( ibutton->protocols, ibutton->key, furi_string_get_cstr(ibutton->file_path)); - if(!success) { - dialog_message_show_storage_error(ibutton->dialogs, "Cannot load\nkey file"); - - } else { + if(success) { FuriString* tmp = furi_string_alloc(); path_extract_filename(ibutton->file_path, tmp, true); strncpy(ibutton->key_name, furi_string_get_cstr(tmp), IBUTTON_KEY_NAME_SIZE); furi_string_free(tmp); + } else if(show_error) { + dialog_message_show_storage_error(ibutton->dialogs, "Cannot load\nkey file"); } return success; @@ -210,7 +209,7 @@ bool ibutton_select_and_load_key(iButton* ibutton) { if(!dialog_file_browser_show( ibutton->dialogs, ibutton->file_path, ibutton->file_path, &browser_options)) break; - success = ibutton_load_key(ibutton); + success = ibutton_load_key(ibutton, true); } while(!success); return success; @@ -283,7 +282,7 @@ int32_t ibutton_app(void* arg) { } else { furi_string_set(ibutton->file_path, (const char*)arg); - key_loaded = ibutton_load_key(ibutton); + key_loaded = ibutton_load_key(ibutton, true); } } diff --git a/applications/main/ibutton/ibutton_i.h b/applications/main/ibutton/ibutton_i.h index 077b14807..c6a35f888 100644 --- a/applications/main/ibutton/ibutton_i.h +++ b/applications/main/ibutton/ibutton_i.h @@ -90,7 +90,7 @@ typedef enum { } iButtonNotificationMessage; 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_delete_key(iButton* ibutton); void ibutton_reset_key(iButton* ibutton); diff --git a/applications/main/ibutton/scenes/ibutton_scene_add_value.c b/applications/main/ibutton/scenes/ibutton_scene_add_value.c index dc340771b..71b852115 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_add_value.c +++ b/applications/main/ibutton/scenes/ibutton_scene_add_value.c @@ -43,7 +43,7 @@ bool ibutton_scene_add_value_on_event(void* context, SceneManagerEvent event) { } else if(event.type == SceneManagerEventTypeBack) { // User cancelled editing, reload the key from storage 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( scene_manager, iButtonSceneStart); } diff --git a/applications/main/ibutton/scenes/ibutton_scene_rpc.c b/applications/main/ibutton/scenes/ibutton_scene_rpc.c index 7106fefaa..f4f193a47 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_rpc.c +++ b/applications/main/ibutton/scenes/ibutton_scene_rpc.c @@ -26,7 +26,7 @@ bool ibutton_scene_rpc_on_event(void* context, SceneManagerEvent event) { if(event.event == iButtonCustomEventRpcLoadFile) { 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); view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewPopup); From ba074068b0c0c620b6ab13b88c8e294b9d3aaf8d Mon Sep 17 00:00:00 2001 From: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Date: Wed, 15 Nov 2023 11:56:13 +0300 Subject: [PATCH 5/9] [FL-3662] Do not remove file when renaming to itself (#3193) * Do not allow overwriting a file with dir and support renaming file to itself * Fix operator precedence error * Add support for storage-specific path equivalence checks * Fix typo * Fix updater compilation * Update Doxygen comments in storage.h Co-authored-by: Aleksandr Kutuzov --- .../storage/filesystem_api_internal.h | 8 + applications/services/storage/storage.h | 593 ++++++++++++------ .../services/storage/storage_external_api.c | 42 +- .../services/storage/storage_message.h | 9 + .../services/storage/storage_processing.c | 50 ++ .../services/storage/storages/storage_ext.c | 11 + .../services/storage/storages/storage_int.c | 5 + targets/f18/api_symbols.csv | 3 +- targets/f7/api_symbols.csv | 3 +- 9 files changed, 508 insertions(+), 216 deletions(-) diff --git a/applications/services/storage/filesystem_api_internal.h b/applications/services/storage/filesystem_api_internal.h index 967d3bb41..ba98b380e 100644 --- a/applications/services/storage/filesystem_api_internal.h +++ b/applications/services/storage/filesystem_api_internal.h @@ -165,6 +165,13 @@ typedef struct { * @param total_space pointer to total space value * @param free_space pointer to free space value * @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 { FS_Error (*const stat)(void* context, const char* path, FileInfo* fileinfo); @@ -175,6 +182,7 @@ typedef struct { const char* fs_path, uint64_t* total_space, uint64_t* free_space); + bool (*const equivalent_path)(const char* path1, const char* path2); } FS_Common_Api; /** Full filesystem api structure */ diff --git a/applications/services/storage/storage.h b/applications/services/storage/storage.h index 1abc8ed0e..3caa155c7 100644 --- a/applications/services/storage/storage.h +++ b/applications/services/storage/storage.h @@ -1,4 +1,9 @@ +/** + * @file storage.h + * @brief APIs for working with storages, directories and files. + */ #pragma once + #include #include "filesystem_api_defines.h" #include "storage_sd_api.h" @@ -23,43 +28,62 @@ extern "C" { 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); -/** 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); +/** + * @brief Enumeration of events emitted by the storage through the PubSub system. + */ typedef enum { - StorageEventTypeCardMount, - StorageEventTypeCardUnmount, - StorageEventTypeCardMountError, - StorageEventTypeFileClose, - StorageEventTypeDirClose, + StorageEventTypeCardMount, /**< SD card was mounted. */ + StorageEventTypeCardUnmount, /**< SD card was unmounted. */ + StorageEventTypeCardMountError, /**< An error occurred during mounting of an SD card. */ + StorageEventTypeFileClose, /**< A file was closed. */ + StorageEventTypeDirClose, /**< A directory was closed. */ } StorageEventType; +/** + * @brief Storage event (passed to the PubSub callback). + */ typedef struct { - StorageEventType type; + StorageEventType type; /**< Type of the event. */ } StorageEvent; /** - * Get storage pubsub. + * @brief Get the storage pubsub instance. + * * 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); /******************* File Functions *******************/ -/** Opens an existing file or create a new one. - * @param file pointer to file object. - * @param path path to file - * @param access_mode access mode from FS_AccessMode +/** + * @brief Open an existing file or create a new one. + * + * @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 - * @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( File* file, @@ -67,202 +91,267 @@ bool storage_file_open( FS_AccessMode access_mode, FS_OpenMode open_mode); -/** Close the file. - * @param file pointer to a file object, the file object will be freed. - * @return success flag +/** + * @brief Close the file. + * + * @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); -/** Tells if the file is open - * @param file pointer to a file object - * @return bool true if file is open +/** + * @brief Check whether the 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); -/** Tells if the file is a directory - * @param file pointer to a file object - * @return bool true if file is a directory +/** + * @brief Check whether a file instance represents 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); -/** Reads bytes from a file into a buffer - * @param file pointer to file object. - * @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. - * @return uint16_t how many bytes were actually read +/** + * @brief Read bytes from a file into a buffer. + * + * @param file pointer to the file instance to read from. + * @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); -/** Writes bytes from a buffer to a file - * @param file pointer to file object. - * @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. - * @return uint16_t how many bytes were actually written +/** + * @brief Write bytes from a buffer to a file. + * + * @param file pointer to the file instance to write into. + * @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); -/** Moves the r/w pointer - * @param file pointer to file object. - * @param offset offset to move the r/w pointer - * @param from_start set an offset from the start or from the current position +/** + * @brief Change the current access position in a file. + * + * @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 */ 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. - * @return uint64_t position of the r/w pointer +/** + * @brief Get the current access position. + * + * @param file pointer to the file instance in question. + * @return current access position. */ 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. - * @return bool success flag +/** + * @brief Truncate the file size to the current access position. + * + * @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); -/** Gets the size of the file - * @param file pointer to file object. - * @return uint64_t size of the file +/** + * @brief Get the file size. + * + * @param file pointer to the file instance in question. + * @return size of the file, in bytes. */ uint64_t storage_file_size(File* file); -/** Writes file cache to storage - * @param file pointer to file object. - * @return bool success flag +/** + * @brief Synchronise the file cache with the actual storage. + * + * @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); -/** Checks that the r/w pointer is at the end of the file - * @param file pointer to file object. - * @return bool success flag +/** + * @brief Check whether the current access position is at the end of the file. + * + * @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); /** - * @brief Check that file exists + * @brief Check whether a file exists. * - * @param storage - * @param path - * @return true if file exists + * @param storage pointer to a storage API instance. + * @param path pointer to a zero-terminated string containing the path to the file in question. + * @return true if the file exists, false otherwise. */ bool storage_file_exists(Storage* storage, const char* path); /** - * @brief Copy data from one opened file to another opened file - * Size bytes will be copied from current position of source file to current position of destination file + * @brief Copy data from a source file to the 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 destination destination file - * @param size size of data to copy - * @return bool success flag + * @param source pointer to a source file instance. + * @param destination pointer to a destination file instance. + * @param size data size to be copied, in bytes. + * @return true if the data was successfully copied, false otherwise. */ bool storage_file_copy_to_file(File* source, File* destination, uint32_t size); -/******************* Dir Functions *******************/ +/******************* Directory Functions *******************/ -/** Opens a directory to get objects from it - * @param app pointer to the api - * @param file pointer to file object. - * @param path path to directory - * @return bool success flag. You need to close the directory even if the open operation failed. +/** + * @brief Open a directory. + * + * Opening a directory is necessary to be able to read its contents with storage_dir_read(). + * + * @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); -/** Close the directory. Also free file handle structure and point it to the NULL. - * @param file pointer to a file object. - * @return bool success flag +/** + * @brief Close the directory. + * + * @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); -/** Reads the next object in the directory - * @param file pointer to file object. - * @param fileinfo pointer to the read FileInfo, may be NULL - * @param name pointer to name buffer, may be NULL - * @param name_length name buffer length - * @return success flag (if the next object does not exist, it also returns false and sets the file error id to FSE_NOT_EXIST) +/** + * @brief Get the next item in the directory. + * + * If the next object does not exist, this function returns false as well + * 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); -/** Rewinds the read pointer to first item in the directory - * @param file pointer to file object. - * @return bool success flag +/** + * @brief Change the access position to first item in the directory. + * + * @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); /** - * @brief Check that dir exists + * @brief Check whether a directory exists. * - * @param storage - * @param path - * @return bool + * @param storage pointer to a storage API instance. + * @param path pointer to a zero-terminated string containing the path of the directory in question. + * @return true if the directory exists, false otherwise. */ bool storage_dir_exists(Storage* storage, const char* path); /******************* Common Functions *******************/ -/** Retrieves unix timestamp of last access +/** + * @brief Get the last access time in UNIX format. * - * @param storage The storage instance - * @param path path to file/directory - * @param timestamp the timestamp pointer - * - * @return FS_Error operation result + * @param storage pointer to a storage API instance. + * @param path pointer to a zero-terminated string containing the path of the item in question. + * @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. */ 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 - * @param path path to file/directory - * @param fileinfo pointer to the read FileInfo, may be NULL - * @return FS_Error operation result +/** + * @brief Get information about a file or a directory. + * + * @param storage pointer to a storage API instance. + * @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); -/** 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 - * @param path - * @return FS_Error operation result +/** + * @brief Remove a file or a directory. + * + * 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); -/** Renames file/directory, file/directory must not be open. Will overwrite existing file. - * @param app pointer to the api - * @param old_path old path - * @param new_path new path - * @return FS_Error operation result +/** + * @brief Rename a file or a directory. + * + * The file or the directory must NOT be open. + * 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); -/** Copy file, file must not be open - * @param app pointer to the api - * @param old_path old path - * @param new_path new path - * @return FS_Error operation result +/** + * @brief Copy the file to a new location. + * + * The file must NOT be open at the time of calling this function. + * + * @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); -/** Copy one folder contents into another with rename of all conflicting files - * @param app pointer to the api - * @param old_path old path - * @param new_path new path - * @return FS_Error operation result +/** + * @brief Copy the contents of one directory into another and rename all conflicting files. + * + * @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 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); -/** Creates a directory - * @param app pointer to the api - * @param path directory path - * @return FS_Error operation result +/** + * @brief Create a directory. + * + * @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); -/** Gets general information about the storage - * @param app pointer to the api - * @param fs_path the path to the storage of interest - * @param total_space pointer to total space record, will be filled - * @param free_space pointer to free space record, will be filled - * @return FS_Error operation result +/** + * @brief Get the general information about the storage. + * + * @param storage pointer to a storage API instance. + * @param fs_path pointer to a zero-terminated string containing the path to the storage question. + * @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( Storage* storage, @@ -271,150 +360,242 @@ FS_Error storage_common_fs_info( uint64_t* free_space); /** - * @brief Parse aliases in path and replace them with real path - * Also will create special folders if they are not exist + * @brief Parse aliases in a path and replace them with the real path. + * + * Necessary special directories will be created automatically if they did not exist. * - * @param storage - * @param path - * @return bool + * @param storage pointer to a storage API instance. + * @param path pointer to a zero-terminated string containing the path in question. + * @return true if the path was successfully resolved, false otherwise. */ 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. - * Source folder will be deleted if the migration is successful. + * @brief Move the contents of source folder to destination one and rename all conflicting files. + * + * Source folder will be deleted if the migration was successful. * - * @param storage - * @param source - * @param dest - * @return FS_Error + * @param storage pointer to a storage API instance. + * @param source pointer to a zero-terminated string containing the source path. + * @param dest pointer to a zero-terminated string containing the destination path. + * @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); /** - * @brief Check that file or dir exists + * @brief Check whether a file or a directory exists. * - * @param storage - * @param path - * @return bool + * @param storage pointer to a storage API instance. + * @param path pointer to a zero-terminated string containing the path in question. + * @return true if a file or a directory exists, false otherwise. */ 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 *******************/ -/** Retrieves the error text from the error id - * @param error_id error id - * @return const char* error text +/** + * @brief Get the textual description of a numeric error identifer. + * + * @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); -/** 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 - * @return FS_Error error id +/** + * @brief Get the numeric error identifier from a file instance. + * + * @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); -/** 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 - * @return FS_Error error id +/** + * @brief Get the internal (storage-specific) numeric error identifier from a file instance. + * + * @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); -/** 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 - * @return const char* error text +/** + * @brief Get the textual description of a the last error associated with a file instance. + * + * @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); /******************* SD Card Functions *******************/ -/** Formats SD Card - * @param api pointer to the api - * @return FS_Error operation result +/** + * @brief Format 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_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. - * Will return FSE_DENIED if there are open files on the SD card. - * @param api pointer to the api - * @return FS_Error operation result +/** + * @brief Unmount the SD card. + * + * These return values have special meaning: + * - 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 - * @return FS_Error operation result +/** + * @brief Mount the SD card. + * + * @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 - * @param info pointer to the info - * @return FS_Error operation result +/** + * @brief Get SD card information. + * + * @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 - * @return FS_Error operation result +/** + * @brief Get SD card status. + * + * @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 *******************/ typedef void (*Storage_name_converter)(FuriString*); -/** Backs up internal storage to a tar archive - * @param api pointer to the api - * @param dstmane destination archive path - * @return FS_Error operation result +/** + * @brief Back up the internal storage contents to a *.tar archive. + * + * @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 - * @param dstmane archive path - * @param converter pointer to filename conversion function, may be NULL - * @return FS_Error operation result +/** + * @brief Restore the internal storage contents from a *.tar archive. + * + * @param storage pointer to a storage API instance. + * @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); /***************** Simplified Functions ******************/ /** - * Removes a file/directory, the directory must be empty and the file/directory must not be open - * @param storage pointer to the api - * @param path - * @return true on success or if file/dir is not exist + * @brief Remove a file or a directory. + * + * The following conditions must be met: + * - 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); /** - * Recursively removes a file/directory, the directory can be not empty - * @param storage pointer to the api - * @param path - * @return true on success or if file/dir is not exist + * @brief Recursively remove a file or a directory. + * + * Unlike storage_simply_remove(), the directory does not need to be empty. + * + * @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); /** - * Creates a directory - * @param storage - * @param path - * @return true on success or if directory is already exist + * @brief Create a directory. + * + * @param storage pointer to a storage API instance. + * @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); /** - * @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 dirname - * @param filename - * @param fileextension - * @param nextfilename return name - * @param max_len max len name + * @param storage pointer to a storage API instance. + * @param dirname pointer to a zero-terminated string containing the directory path. + * @param filename pointer to a zero-terminated string containing the file name. + * @param fileextension pointer to a zero-terminated string containing the file extension. + * @param nextfilename pointer to a dynamic string containing the resulting file name. + * @param max_len maximum length of the new name. */ void storage_get_next_filename( Storage* storage, diff --git a/applications/services/storage/storage_external_api.c b/applications/services/storage/storage_external_api.c index ed69b49a5..1027d4310 100644 --- a/applications/services/storage/storage_external_api.c +++ b/applications/services/storage/storage_external_api.c @@ -431,17 +431,22 @@ FS_Error storage_common_rename(Storage* storage, const char* old_path, const cha } if(storage_dir_exists(storage, old_path)) { - FuriString* dir_path = furi_string_alloc_set_str(old_path); - if(!furi_string_end_with_str(dir_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) { + // Cannot overwrite a file with a directory + if(storage_file_exists(storage, new_path)) { error = FSE_INVALID_NAME; - furi_string_free(dir_path); 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)) { @@ -742,6 +747,27 @@ bool storage_common_exists(Storage* storage, const char* path) { 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 ******************/ const char* storage_error_get_desc(FS_Error error_id) { diff --git a/applications/services/storage/storage_message.h b/applications/services/storage/storage_message.h index 01bc20380..cd45906d4 100644 --- a/applications/services/storage/storage_message.h +++ b/applications/services/storage/storage_message.h @@ -69,6 +69,13 @@ typedef struct { FuriThreadId thread_id; } SADataCResolvePath; +typedef struct { + const char* path1; + const char* path2; + bool truncate; + FuriThreadId thread_id; +} SADataCEquivPath; + typedef struct { uint32_t id; } SADataError; @@ -99,6 +106,7 @@ typedef union { SADataCStat cstat; SADataCFSInfo cfsinfo; SADataCResolvePath cresolvepath; + SADataCEquivPath cequivpath; SADataError error; @@ -142,6 +150,7 @@ typedef enum { StorageCommandSDStatus, StorageCommandCommonResolvePath, StorageCommandSDMount, + StorageCommandCommonEquivalentPath, } StorageCommand; typedef struct { diff --git a/applications/services/storage/storage_processing.c b/applications/services/storage/storage_processing.c index 00126af6f..9e96765b6 100644 --- a/applications/services/storage/storage_processing.c +++ b/applications/services/storage/storage_processing.c @@ -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 *******************/ 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); do { + if(ret != FSE_OK) break; + if(storage_path_already_open(path, storage)) { ret = FSE_ALREADY_OPEN; break; @@ -398,6 +406,31 @@ static FS_Error storage_process_common_fs_info( 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 ******************/ // TODO FL-3521: think about implementing a custom storage API to split that kind of api linkage #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); 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 case StorageCommandSDFormat: message->return_data->error_value = storage_process_sd_format(app); diff --git a/applications/services/storage/storages/storage_ext.c b/applications/services/storage/storages/storage_ext.c index 4630d99ea..7e617c0ff 100644 --- a/applications/services/storage/storages/storage_ext.c +++ b/applications/services/storage/storages/storage_ext.c @@ -596,6 +596,16 @@ static FS_Error storage_ext_common_fs_info( #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 *******************/ static const FS_Api fs_api = { .file = @@ -624,6 +634,7 @@ static const FS_Api fs_api = { .mkdir = storage_ext_common_mkdir, .remove = storage_ext_common_remove, .fs_info = storage_ext_common_fs_info, + .equivalent_path = storage_ext_common_equivalent_path, }, }; diff --git a/applications/services/storage/storages/storage_int.c b/applications/services/storage/storages/storage_int.c index 2534d47a1..39b092c1d 100644 --- a/applications/services/storage/storages/storage_int.c +++ b/applications/services/storage/storages/storage_int.c @@ -686,6 +686,10 @@ static FS_Error storage_int_common_fs_info( 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 *******************/ static const FS_Api fs_api = { .file = @@ -714,6 +718,7 @@ static const FS_Api fs_api = { .mkdir = storage_int_common_mkdir, .remove = storage_int_common_remove, .fs_info = storage_int_common_fs_info, + .equivalent_path = storage_int_common_equivalent_path, }, }; diff --git a/targets/f18/api_symbols.csv b/targets/f18/api_symbols.csv index 44829c264..8ed8f403c 100644 --- a/targets/f18/api_symbols.csv +++ b/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,45.0,, +Version,+,45.1,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -2071,6 +2071,7 @@ Function,+,st25r3916_write_pttsn_mem,void,"FuriHalSpiBusHandle*, uint8_t*, size_ Function,+,st25r3916_write_reg,void,"FuriHalSpiBusHandle*, uint8_t, uint8_t" Function,+,st25r3916_write_test_reg,void,"FuriHalSpiBusHandle*, uint8_t, uint8_t" Function,+,storage_common_copy,FS_Error,"Storage*, const char*, const char*" +Function,+,storage_common_equivalent_path,_Bool,"Storage*, const char*, const char*, _Bool" Function,+,storage_common_exists,_Bool,"Storage*, const char*" Function,+,storage_common_fs_info,FS_Error,"Storage*, const char*, uint64_t*, uint64_t*" Function,+,storage_common_merge,FS_Error,"Storage*, const char*, const char*" diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 514f33286..64695c2db 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,45.0,, +Version,+,45.1,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, @@ -2698,6 +2698,7 @@ Function,+,st25tb_save,_Bool,"const St25tbData*, FlipperFormat*" Function,+,st25tb_set_uid,_Bool,"St25tbData*, const uint8_t*, size_t" Function,+,st25tb_verify,_Bool,"St25tbData*, const FuriString*" Function,+,storage_common_copy,FS_Error,"Storage*, const char*, const char*" +Function,+,storage_common_equivalent_path,_Bool,"Storage*, const char*, const char*, _Bool" Function,+,storage_common_exists,_Bool,"Storage*, const char*" Function,+,storage_common_fs_info,FS_Error,"Storage*, const char*, uint64_t*, uint64_t*" Function,+,storage_common_merge,FS_Error,"Storage*, const char*, const char*" From a61b5d4b4cd7f11f4b836ba085860f58689905b8 Mon Sep 17 00:00:00 2001 From: Flipper Zelebro <149575765+flipperzelebro@users.noreply.github.com> Date: Wed, 15 Nov 2023 10:04:45 +0100 Subject: [PATCH 6/9] Add Mastercode SubGHz Protocol (#3187) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add Mastercode SubGHz Protocol * Add 2 valid raw files and cleanup code * Add tests to the two Raw Files * Remove extra test & delete comments * Fixes pulse length and shows correct Key Co-authored-by: FlipperZelebro Co-authored-by: あく --- .../unit_tests/subghz/mastercode.sub | 7 + .../unit_tests/subghz/mastercode_raw.sub | 6 + .../debug/unit_tests/subghz/subghz_test.c | 15 + lib/subghz/protocols/mastercode.c | 360 ++++++++++++++++++ lib/subghz/protocols/mastercode.h | 109 ++++++ lib/subghz/protocols/protocol_items.c | 1 + lib/subghz/protocols/protocol_items.h | 1 + 7 files changed, 499 insertions(+) create mode 100644 applications/debug/unit_tests/resources/unit_tests/subghz/mastercode.sub create mode 100644 applications/debug/unit_tests/resources/unit_tests/subghz/mastercode_raw.sub create mode 100644 lib/subghz/protocols/mastercode.c create mode 100644 lib/subghz/protocols/mastercode.h diff --git a/applications/debug/unit_tests/resources/unit_tests/subghz/mastercode.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/mastercode.sub new file mode 100644 index 000000000..f50abbfe8 --- /dev/null +++ b/applications/debug/unit_tests/resources/unit_tests/subghz/mastercode.sub @@ -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 diff --git a/applications/debug/unit_tests/resources/unit_tests/subghz/mastercode_raw.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/mastercode_raw.sub new file mode 100644 index 000000000..69d3f396c --- /dev/null +++ b/applications/debug/unit_tests/resources/unit_tests/subghz/mastercode_raw.sub @@ -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 diff --git a/applications/debug/unit_tests/subghz/subghz_test.c b/applications/debug/unit_tests/subghz/subghz_test.c index 64e0591df..2f2b9e981 100644 --- a/applications/debug/unit_tests/subghz/subghz_test.c +++ b/applications/debug/unit_tests/subghz/subghz_test.c @@ -654,6 +654,13 @@ MU_TEST(subghz_decoder_kinggates_stylo4k_test) { "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 MU_TEST(subghz_encoder_princeton_test) { mu_assert( @@ -805,6 +812,12 @@ MU_TEST(subghz_encoder_dooya_test) { "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_assert(subghz_decode_random_test(TEST_RANDOM_DIR_NAME), "Random test error\r\n"); } @@ -855,6 +868,7 @@ MU_TEST_SUITE(subghz) { MU_RUN_TEST(subghz_decoder_alutech_at_4n_test); MU_RUN_TEST(subghz_decoder_nice_one_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_came_test); @@ -881,6 +895,7 @@ MU_TEST_SUITE(subghz) { MU_RUN_TEST(subghz_encoder_smc5326_test); MU_RUN_TEST(subghz_encoder_holtek_ht12x_test); MU_RUN_TEST(subghz_encoder_dooya_test); + MU_RUN_TEST(subghz_encoder_mastercode_test); MU_RUN_TEST(subghz_random_test); subghz_test_deinit(); diff --git a/lib/subghz/protocols/mastercode.c b/lib/subghz/protocols/mastercode.c new file mode 100644 index 000000000..54ad5bfaa --- /dev/null +++ b/lib/subghz/protocols/mastercode.c @@ -0,0 +1,360 @@ +#include "mastercode.h" + +#include "../blocks/const.h" +#include "../blocks/decoder.h" +#include "../blocks/encoder.h" +#include "../blocks/generic.h" +#include "../blocks/math.h" + +// protocol MASTERCODE Clemsa MV1/MV12 +#define TAG "SubGhzProtocolMastercode" + +#define DIP_P 0b11 //(+) +#define DIP_O 0b10 //(0) +#define DIP_N 0b00 //(-) + +#define DIP_PATTERN "%c%c%c%c%c%c%c%c" + +#define SHOW_DIP_P(dip, check_dip) \ + ((((dip >> 0x0) & 0x3) == check_dip) ? '*' : '_'), \ + ((((dip >> 0x2) & 0x3) == check_dip) ? '*' : '_'), \ + ((((dip >> 0x4) & 0x3) == check_dip) ? '*' : '_'), \ + ((((dip >> 0x6) & 0x3) == check_dip) ? '*' : '_'), \ + ((((dip >> 0x8) & 0x3) == check_dip) ? '*' : '_'), \ + ((((dip >> 0xA) & 0x3) == check_dip) ? '*' : '_'), \ + ((((dip >> 0xC) & 0x3) == check_dip) ? '*' : '_'), \ + ((((dip >> 0xE) & 0x3) == check_dip) ? '*' : '_') + +static const SubGhzBlockConst subghz_protocol_mastercode_const = { + .te_short = 1072, + .te_long = 2145, + .te_delta = 150, + .min_count_bit_for_found = 36, +}; + +struct SubGhzProtocolDecoderMastercode { + SubGhzProtocolDecoderBase base; + SubGhzBlockDecoder decoder; + SubGhzBlockGeneric generic; +}; + +struct SubGhzProtocolEncoderMastercode { + SubGhzProtocolEncoderBase base; + SubGhzProtocolBlockEncoder encoder; + SubGhzBlockGeneric generic; +}; + +typedef enum { + MastercodeDecoderStepReset = 0, + MastercodeDecoderStepSaveDuration, + MastercodeDecoderStepCheckDuration, +} MastercodeDecoderStep; + +const SubGhzProtocolDecoder subghz_protocol_mastercode_decoder = { + .alloc = subghz_protocol_decoder_mastercode_alloc, + .free = subghz_protocol_decoder_mastercode_free, + + .feed = subghz_protocol_decoder_mastercode_feed, + .reset = subghz_protocol_decoder_mastercode_reset, + + .get_hash_data = subghz_protocol_decoder_mastercode_get_hash_data, + .serialize = subghz_protocol_decoder_mastercode_serialize, + .deserialize = subghz_protocol_decoder_mastercode_deserialize, + .get_string = subghz_protocol_decoder_mastercode_get_string, +}; + +const SubGhzProtocolEncoder subghz_protocol_mastercode_encoder = { + .alloc = subghz_protocol_encoder_mastercode_alloc, + .free = subghz_protocol_encoder_mastercode_free, + + .deserialize = subghz_protocol_encoder_mastercode_deserialize, + .stop = subghz_protocol_encoder_mastercode_stop, + .yield = subghz_protocol_encoder_mastercode_yield, +}; + +const SubGhzProtocol subghz_protocol_mastercode = { + .name = SUBGHZ_PROTOCOL_MASTERCODE_NAME, + .type = SubGhzProtocolTypeStatic, + .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | + SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send, + + .decoder = &subghz_protocol_mastercode_decoder, + .encoder = &subghz_protocol_mastercode_encoder, +}; + +void* subghz_protocol_encoder_mastercode_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolEncoderMastercode* instance = malloc(sizeof(SubGhzProtocolEncoderMastercode)); + + instance->base.protocol = &subghz_protocol_mastercode; + instance->generic.protocol_name = instance->base.protocol->name; + + instance->encoder.repeat = 10; + instance->encoder.size_upload = 72; + instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); + instance->encoder.is_running = false; + return instance; +} + +void subghz_protocol_encoder_mastercode_free(void* context) { + furi_assert(context); + SubGhzProtocolEncoderMastercode* instance = context; + free(instance->encoder.upload); + free(instance); +} + +/** + * Generating an upload from data. + * @param instance Pointer to a SubGhzProtocolEncoderMastercode instance + * @return true On success + */ +static bool + subghz_protocol_encoder_mastercode_get_upload(SubGhzProtocolEncoderMastercode* instance) { + furi_assert(instance); + size_t index = 0; + size_t size_upload = (instance->generic.data_count_bit * 2); + if(size_upload > instance->encoder.size_upload) { + FURI_LOG_E(TAG, "Size upload exceeds allocated encoder buffer."); + return false; + } else { + instance->encoder.size_upload = size_upload; + } + + for(uint8_t i = instance->generic.data_count_bit; i > 1; i--) { + if(bit_read(instance->generic.data, i - 1)) { + //send bit 1 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_mastercode_const.te_long); + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_mastercode_const.te_short); + } else { + //send bit 0 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_mastercode_const.te_short); + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_mastercode_const.te_long); + } + } + if(bit_read(instance->generic.data, 0)) { + //send bit 1 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_mastercode_const.te_long); + instance->encoder.upload[index++] = level_duration_make( + false, + (uint32_t)subghz_protocol_mastercode_const.te_short + + subghz_protocol_mastercode_const.te_short * 13); + } else { + //send bit 0 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_mastercode_const.te_short); + instance->encoder.upload[index++] = level_duration_make( + false, + (uint32_t)subghz_protocol_mastercode_const.te_long + + subghz_protocol_mastercode_const.te_short * 13); + } + return true; +} + +SubGhzProtocolStatus + subghz_protocol_encoder_mastercode_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolEncoderMastercode* instance = context; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; + do { + ret = subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_mastercode_const.min_count_bit_for_found); + if(ret != SubGhzProtocolStatusOk) { + break; + } + //optional parameter parameter + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + + if(!subghz_protocol_encoder_mastercode_get_upload(instance)) { + ret = SubGhzProtocolStatusErrorEncoderGetUpload; + break; + } + instance->encoder.is_running = true; + + } while(false); + + return ret; +} + +void subghz_protocol_encoder_mastercode_stop(void* context) { + SubGhzProtocolEncoderMastercode* instance = context; + instance->encoder.is_running = false; +} + +LevelDuration subghz_protocol_encoder_mastercode_yield(void* context) { + SubGhzProtocolEncoderMastercode* instance = context; + + if(instance->encoder.repeat == 0 || !instance->encoder.is_running) { + instance->encoder.is_running = false; + return level_duration_reset(); + } + + LevelDuration ret = instance->encoder.upload[instance->encoder.front]; + + if(++instance->encoder.front == instance->encoder.size_upload) { + instance->encoder.repeat--; + instance->encoder.front = 0; + } + + return ret; +} + +void* subghz_protocol_decoder_mastercode_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolDecoderMastercode* instance = malloc(sizeof(SubGhzProtocolDecoderMastercode)); + instance->base.protocol = &subghz_protocol_mastercode; + instance->generic.protocol_name = instance->base.protocol->name; + return instance; +} + +void subghz_protocol_decoder_mastercode_free(void* context) { + furi_assert(context); + SubGhzProtocolDecoderMastercode* instance = context; + free(instance); +} + +void subghz_protocol_decoder_mastercode_reset(void* context) { + furi_assert(context); + SubGhzProtocolDecoderMastercode* instance = context; + instance->decoder.parser_step = MastercodeDecoderStepReset; +} + +void subghz_protocol_decoder_mastercode_feed(void* context, bool level, uint32_t duration) { + furi_assert(context); + SubGhzProtocolDecoderMastercode* instance = context; + + switch(instance->decoder.parser_step) { + case MastercodeDecoderStepReset: + if((!level) && (DURATION_DIFF(duration, subghz_protocol_mastercode_const.te_short * 15) < + subghz_protocol_mastercode_const.te_delta * 15)) { + instance->decoder.parser_step = MastercodeDecoderStepSaveDuration; + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + } + break; + + case MastercodeDecoderStepSaveDuration: + if(level) { + instance->decoder.te_last = duration; + instance->decoder.parser_step = MastercodeDecoderStepCheckDuration; + } else { + instance->decoder.parser_step = MastercodeDecoderStepReset; + } + break; + + case MastercodeDecoderStepCheckDuration: + if(!level) { + if((DURATION_DIFF( + instance->decoder.te_last, subghz_protocol_mastercode_const.te_short) < + subghz_protocol_mastercode_const.te_delta) && + (DURATION_DIFF(duration, subghz_protocol_mastercode_const.te_long) < + subghz_protocol_mastercode_const.te_delta * 8)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + instance->decoder.parser_step = MastercodeDecoderStepSaveDuration; + } else if( + (DURATION_DIFF( + instance->decoder.te_last, subghz_protocol_mastercode_const.te_long) < + subghz_protocol_mastercode_const.te_delta * 8) && + (DURATION_DIFF(duration, subghz_protocol_mastercode_const.te_short) < + subghz_protocol_mastercode_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + instance->decoder.parser_step = MastercodeDecoderStepSaveDuration; + } else if( + DURATION_DIFF(duration, subghz_protocol_mastercode_const.te_short * 15) < + subghz_protocol_mastercode_const.te_delta * 15) { + if((DURATION_DIFF( + instance->decoder.te_last, subghz_protocol_mastercode_const.te_short) < + subghz_protocol_mastercode_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + } else if((DURATION_DIFF( + instance->decoder.te_last, + subghz_protocol_mastercode_const.te_long) < + subghz_protocol_mastercode_const.te_delta * 8)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + } else { + instance->decoder.parser_step = MastercodeDecoderStepReset; + } + + if(instance->decoder.decode_count_bit == + subghz_protocol_mastercode_const.min_count_bit_for_found) { + instance->generic.data = instance->decoder.decode_data; + instance->generic.data_count_bit = instance->decoder.decode_count_bit; + + if(instance->base.callback) + instance->base.callback(&instance->base, instance->base.context); + } + instance->decoder.parser_step = MastercodeDecoderStepSaveDuration; + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + + } else { + instance->decoder.parser_step = MastercodeDecoderStepReset; + } + } else { + instance->decoder.parser_step = MastercodeDecoderStepReset; + } + break; + } +} + +/** + * Analysis of received data + * @param instance Pointer to a SubGhzBlockGeneric* instance + */ +static void subghz_protocol_mastercode_check_remote_controller(SubGhzBlockGeneric* instance) { + instance->serial = (instance->data >> 4) & 0xFFFF; + instance->btn = (instance->data >> 2 & 0x03); +} + +uint8_t subghz_protocol_decoder_mastercode_get_hash_data(void* context) { + furi_assert(context); + SubGhzProtocolDecoderMastercode* instance = context; + return subghz_protocol_blocks_get_hash_data( + &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); +} + +SubGhzProtocolStatus subghz_protocol_decoder_mastercode_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzRadioPreset* preset) { + furi_assert(context); + SubGhzProtocolDecoderMastercode* instance = context; + return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); +} + +SubGhzProtocolStatus + subghz_protocol_decoder_mastercode_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolDecoderMastercode* instance = context; + return subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_mastercode_const.min_count_bit_for_found); +} + +void subghz_protocol_decoder_mastercode_get_string(void* context, FuriString* output) { + furi_assert(context); + SubGhzProtocolDecoderMastercode* instance = context; + subghz_protocol_mastercode_check_remote_controller(&instance->generic); + furi_string_cat_printf( + output, + "%s %dbit\r\n" + "Key:%llX Btn %X\r\n" + " +: " DIP_PATTERN "\r\n" + " o: " DIP_PATTERN "\r\n" + " -: " DIP_PATTERN "\r\n", + instance->generic.protocol_name, + instance->generic.data_count_bit, + (uint64_t)(instance->generic.data), + instance->generic.btn, + SHOW_DIP_P(instance->generic.serial, DIP_P), + SHOW_DIP_P(instance->generic.serial, DIP_O), + SHOW_DIP_P(instance->generic.serial, DIP_N)); +} diff --git a/lib/subghz/protocols/mastercode.h b/lib/subghz/protocols/mastercode.h new file mode 100644 index 000000000..c5c73db98 --- /dev/null +++ b/lib/subghz/protocols/mastercode.h @@ -0,0 +1,109 @@ +#pragma once + +#include "base.h" + +#define SUBGHZ_PROTOCOL_MASTERCODE_NAME "Mastercode" + +typedef struct SubGhzProtocolDecoderMastercode SubGhzProtocolDecoderMastercode; +typedef struct SubGhzProtocolEncoderMastercode SubGhzProtocolEncoderMastercode; + +extern const SubGhzProtocolDecoder subghz_protocol_mastercode_decoder; +extern const SubGhzProtocolEncoder subghz_protocol_mastercode_encoder; +extern const SubGhzProtocol subghz_protocol_mastercode; + +/** + * Allocate SubGhzProtocolEncoderMastercode. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolEncoderMastercode* pointer to a SubGhzProtocolEncoderMastercode instance + */ +void* subghz_protocol_encoder_mastercode_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolEncoderMastercode. + * @param context Pointer to a SubGhzProtocolEncoderMastercode instance + */ +void subghz_protocol_encoder_mastercode_free(void* context); + +/** + * Deserialize and generating an upload to send. + * @param context Pointer to a SubGhzProtocolEncoderMastercode instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return status + */ +SubGhzProtocolStatus + subghz_protocol_encoder_mastercode_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Forced transmission stop. + * @param context Pointer to a SubGhzProtocolEncoderMastercode instance + */ +void subghz_protocol_encoder_mastercode_stop(void* context); + +/** + * Getting the level and duration of the upload to be loaded into DMA. + * @param context Pointer to a SubGhzProtocolEncoderMastercode instance + * @return LevelDuration + */ +LevelDuration subghz_protocol_encoder_mastercode_yield(void* context); + +/** + * Allocate SubGhzProtocolDecoderMastercode. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolDecoderMastercode* pointer to a SubGhzProtocolDecoderMastercode instance + */ +void* subghz_protocol_decoder_mastercode_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolDecoderMastercode. + * @param context Pointer to a SubGhzProtocolDecoderMastercode instance + */ +void subghz_protocol_decoder_mastercode_free(void* context); + +/** + * Reset decoder SubGhzProtocolDecoderMastercode. + * @param context Pointer to a SubGhzProtocolDecoderMastercode instance + */ +void subghz_protocol_decoder_mastercode_reset(void* context); + +/** + * Parse a raw sequence of levels and durations received from the air. + * @param context Pointer to a SubGhzProtocolDecoderMastercode instance + * @param level Signal level true-high false-low + * @param duration Duration of this level in, us + */ +void subghz_protocol_decoder_mastercode_feed(void* context, bool level, uint32_t duration); + +/** + * Getting the hash sum of the last randomly received parcel. + * @param context Pointer to a SubGhzProtocolDecoderMastercode instance + * @return hash Hash sum + */ +uint8_t subghz_protocol_decoder_mastercode_get_hash_data(void* context); + +/** + * Serialize data SubGhzProtocolDecoderMastercode. + * @param context Pointer to a SubGhzProtocolDecoderMastercode instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param preset The modulation on which the signal was received, SubGhzRadioPreset + * @return status + */ +SubGhzProtocolStatus subghz_protocol_decoder_mastercode_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzRadioPreset* preset); + +/** + * Deserialize data SubGhzProtocolDecoderMastercode. + * @param context Pointer to a SubGhzProtocolDecoderMastercode instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return status + */ +SubGhzProtocolStatus + subghz_protocol_decoder_mastercode_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Getting a textual representation of the received data. + * @param context Pointer to a SubGhzProtocolDecoderMastercode instance + * @param output Resulting text + */ +void subghz_protocol_decoder_mastercode_get_string(void* context, FuriString* output); diff --git a/lib/subghz/protocols/protocol_items.c b/lib/subghz/protocols/protocol_items.c index 74244c5ff..472a354e3 100644 --- a/lib/subghz/protocols/protocol_items.c +++ b/lib/subghz/protocols/protocol_items.c @@ -43,6 +43,7 @@ const SubGhzProtocol* subghz_protocol_registry_items[] = { &subghz_protocol_alutech_at_4n, &subghz_protocol_kinggates_stylo_4k, &subghz_protocol_bin_raw, + &subghz_protocol_mastercode, }; const SubGhzProtocolRegistry subghz_protocol_registry = { diff --git a/lib/subghz/protocols/protocol_items.h b/lib/subghz/protocols/protocol_items.h index f1a28ac9b..c5a090e99 100644 --- a/lib/subghz/protocols/protocol_items.h +++ b/lib/subghz/protocols/protocol_items.h @@ -44,3 +44,4 @@ #include "alutech_at_4n.h" #include "kinggates_stylo_4k.h" #include "bin_raw.h" +#include "mastercode.h" From 457aa5331fe8cbd72d2a17586ff903390f779fe3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Thu, 16 Nov 2023 01:11:05 +0900 Subject: [PATCH 7/9] Various Fixes for 0.95 (#3215) * FuriHal: retry gauge/charger initialization * FuriHal: lower logging level for flash known errata * FuriHal: graceful fail if subghz chip is not working * Furi: issue stop command even if timer is not active, document timer behavior --- furi/core/timer.c | 11 +--- furi/core/timer.h | 13 +++++ targets/f7/furi_hal/furi_hal_flash.c | 2 +- targets/f7/furi_hal/furi_hal_power.c | 33 ++++++++++-- targets/f7/furi_hal/furi_hal_subghz.c | 78 +++++++++++++++++---------- 5 files changed, 95 insertions(+), 42 deletions(-) diff --git a/furi/core/timer.c b/furi/core/timer.c index 17347e5c7..027e4cf40 100644 --- a/furi/core/timer.c +++ b/furi/core/timer.c @@ -122,17 +122,10 @@ FuriStatus furi_timer_stop(FuriTimer* instance) { furi_assert(instance); TimerHandle_t hTimer = (TimerHandle_t)instance; - FuriStatus stat; - if(xTimerIsTimerActive(hTimer) == pdFALSE) { - stat = FuriStatusErrorResource; - } else { - furi_check(xTimerStop(hTimer, portMAX_DELAY) == pdPASS); - stat = FuriStatusOk; - } + furi_check(xTimerStop(hTimer, portMAX_DELAY) == pdPASS); - /* Return execution status */ - return (stat); + return FuriStatusOk; } uint32_t furi_timer_is_running(FuriTimer* instance) { diff --git a/furi/core/timer.h b/furi/core/timer.h index d27ef5025..f8f40c562 100644 --- a/furi/core/timer.h +++ b/furi/core/timer.h @@ -32,6 +32,9 @@ FuriTimer* furi_timer_alloc(FuriTimerCallback func, FuriTimerType type, void* co void furi_timer_free(FuriTimer* instance); /** 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[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); /** 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[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); /** 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 * @@ -58,6 +67,10 @@ FuriStatus furi_timer_restart(FuriTimer* instance, uint32_t ticks); FuriStatus furi_timer_stop(FuriTimer* instance); /** 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 * diff --git a/targets/f7/furi_hal/furi_hal_flash.c b/targets/f7/furi_hal/furi_hal_flash.c index 284d48bf5..7ac7a8bd1 100644 --- a/targets/f7/furi_hal/furi_hal_flash.c +++ b/targets/f7/furi_hal/furi_hal_flash.c @@ -101,7 +101,7 @@ void furi_hal_flash_init() { // WRITE_REG(FLASH->SR, FLASH_SR_OPTVERR); /* Actually, reset all error flags on start */ if(READ_BIT(FLASH->SR, FURI_HAL_FLASH_SR_ERRORS)) { - FURI_LOG_E(TAG, "FLASH->SR 0x%08lX", FLASH->SR); + FURI_LOG_W(TAG, "FLASH->SR 0x%08lX(Known ERRATA)", FLASH->SR); WRITE_REG(FLASH->SR, FURI_HAL_FLASH_SR_ERRORS); } } diff --git a/targets/f7/furi_hal/furi_hal_power.c b/targets/f7/furi_hal/furi_hal_power.c index 119dee81f..9e3a70da7 100644 --- a/targets/f7/furi_hal/furi_hal_power.c +++ b/targets/f7/furi_hal/furi_hal_power.c @@ -71,12 +71,37 @@ void furi_hal_power_init() { furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); // Find and init gauge - if(bq27220_init(&furi_hal_i2c_handle_power)) { - furi_hal_power.gauge_ok = bq27220_apply_data_memory( - &furi_hal_i2c_handle_power, furi_hal_power_gauge_data_memory); + size_t retry = 2; + while(retry > 0) { + furi_hal_power.gauge_ok = bq27220_init(&furi_hal_i2c_handle_power); + if(furi_hal_power.gauge_ok) { + furi_hal_power.gauge_ok = bq27220_apply_data_memory( + &furi_hal_i2c_handle_power, furi_hal_power_gauge_data_memory); + } + if(furi_hal_power.gauge_ok) { + break; + } else { + // Normal startup time is 250ms + // But if we try to access gauge at that stage it will become unresponsive + // 2 seconds timeout needed to restart communication + furi_delay_us(2020202); + } + retry--; } // Find and init charger - furi_hal_power.charger_ok = bq25896_init(&furi_hal_i2c_handle_power); + retry = 2; + while(retry > 0) { + furi_hal_power.charger_ok = bq25896_init(&furi_hal_i2c_handle_power); + if(furi_hal_power.charger_ok) { + break; + } else { + // Most likely I2C communication error + // 2 seconds should be enough for all chips on the line to timeout + // Also timing out here is very abnormal + furi_delay_us(2020202); + } + retry--; + } furi_hal_i2c_release(&furi_hal_i2c_handle_power); FURI_LOG_I(TAG, "Init OK"); diff --git a/targets/f7/furi_hal/furi_hal_subghz.c b/targets/f7/furi_hal/furi_hal_subghz.c index f75146353..a00ca7bf6 100644 --- a/targets/f7/furi_hal/furi_hal_subghz.c +++ b/targets/f7/furi_hal/furi_hal_subghz.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -29,7 +30,7 @@ static uint32_t furi_hal_subghz_debug_gpio_buff[2]; /** SubGhz state */ typedef enum { SubGhzStateInit, /**< Init pending */ - + SubGhzStateBroken, /**< Chip power-on self test failed */ SubGhzStateIdle, /**< Idle, energy save mode */ SubGhzStateAsyncRx, /**< Async RX started */ @@ -69,46 +70,67 @@ const GpioPin* furi_hal_subghz_get_data_gpio() { void furi_hal_subghz_init() { furi_assert(furi_hal_subghz.state == SubGhzStateInit); - furi_hal_subghz.state = SubGhzStateIdle; + furi_hal_subghz.state = SubGhzStateBroken; furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz); - + do { #ifdef FURI_HAL_SUBGHZ_TX_GPIO - furi_hal_gpio_init(&FURI_HAL_SUBGHZ_TX_GPIO, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_init( + &FURI_HAL_SUBGHZ_TX_GPIO, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); #endif - // Reset - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow); - cc1101_reset(&furi_hal_spi_bus_handle_subghz); - cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG0, CC1101IocfgHighImpedance); + // Reset + furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + cc1101_reset(&furi_hal_spi_bus_handle_subghz); + cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG0, CC1101IocfgHighImpedance); - // Prepare GD0 for power on self test - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); + // Prepare GD0 for power on self test + furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); - // GD0 low - cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG0, CC1101IocfgHW); - while(furi_hal_gpio_read(&gpio_cc1101_g0) != false) - ; + // GD0 low + FuriHalCortexTimer timeout = furi_hal_cortex_timer_get(10000); + cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG0, CC1101IocfgHW); + while(furi_hal_gpio_read(&gpio_cc1101_g0) != false && + !furi_hal_cortex_timer_is_expired(timeout)) + ; - // GD0 high - cc1101_write_reg( - &furi_hal_spi_bus_handle_subghz, CC1101_IOCFG0, CC1101IocfgHW | CC1101_IOCFG_INV); - while(furi_hal_gpio_read(&gpio_cc1101_g0) != true) - ; + if(furi_hal_gpio_read(&gpio_cc1101_g0) != false) { + break; + } - // Reset GD0 to floating state - cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG0, CC1101IocfgHighImpedance); - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + // GD0 high + timeout = furi_hal_cortex_timer_get(10000); + cc1101_write_reg( + &furi_hal_spi_bus_handle_subghz, CC1101_IOCFG0, CC1101IocfgHW | CC1101_IOCFG_INV); + while(furi_hal_gpio_read(&gpio_cc1101_g0) != true && + !furi_hal_cortex_timer_is_expired(timeout)) + ; - // RF switches - furi_hal_gpio_init(&gpio_rf_sw_0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); - cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG2, CC1101IocfgHW); + if(furi_hal_gpio_read(&gpio_cc1101_g0) != true) { + break; + } - // Go to sleep - cc1101_shutdown(&furi_hal_spi_bus_handle_subghz); + // Reset GD0 to floating state + cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG0, CC1101IocfgHighImpedance); + furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + + // RF switches + furi_hal_gpio_init(&gpio_rf_sw_0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); + cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG2, CC1101IocfgHW); + + // Go to sleep + cc1101_shutdown(&furi_hal_spi_bus_handle_subghz); + + furi_hal_subghz.state = SubGhzStateIdle; + } while(false); furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz); - FURI_LOG_I(TAG, "Init OK"); + + if(furi_hal_subghz.state == SubGhzStateIdle) { + FURI_LOG_I(TAG, "Init OK"); + } else { + FURI_LOG_E(TAG, "Init Fail"); + } } void furi_hal_subghz_sleep() { From 98d5718ec9e39824745a2ca364f4d06a5a05c828 Mon Sep 17 00:00:00 2001 From: hedger Date: Wed, 15 Nov 2023 20:27:35 +0400 Subject: [PATCH 8/9] fbt: improvements (#3217) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fbt: changed cdefines & lib handling for external apps; added extra checks for app manifest fields; moved around AppsC generator * fbt: commandline fixes for spaces in paths * fbt: fixed stringification for FAP_VERSION * fbt: Removed excessive quoting for gdb * docs: update for cdefines; fbt: typo fix * fbt: enforcing at least 2 components in app version= Co-authored-by: あく --- SConstruct | 36 +++-- applications/debug/accessor/application.fam | 1 - .../debug/battery_test_app/application.fam | 1 - applications/debug/blink_test/application.fam | 1 - applications/debug/ccid_test/application.fam | 1 - applications/debug/crash_test/application.fam | 1 - .../debug/display_test/application.fam | 1 - .../debug/file_browser_test/application.fam | 1 - .../debug/keypad_test/application.fam | 1 - .../debug/locale_test/application.fam | 1 - .../debug/text_box_test/application.fam | 1 - applications/debug/uart_echo/application.fam | 1 - applications/debug/usb_mouse/application.fam | 1 - applications/debug/usb_test/application.fam | 1 - applications/debug/vibro_test/application.fam | 1 - documentation/AppManifests.md | 2 +- firmware.scons | 4 +- scripts/fbt/appmanifest.py | 129 ++++-------------- scripts/fbt_tools/fbt_apps.py | 103 +++++++++++++- scripts/fbt_tools/fbt_extapps.py | 21 ++- scripts/fbt_tools/fbt_sdk.py | 15 +- scripts/fbt_tools/fbt_version.py | 20 ++- scripts/fbt_tools/fwbin.py | 19 ++- scripts/fbt_tools/jflash.py | 13 +- scripts/fbt_tools/objdump.py | 3 +- scripts/fbt_tools/openocd.py | 1 + scripts/fbt_tools/pvsstudio.py | 24 +++- scripts/fbt_tools/strip.py | 3 +- scripts/ufbt/SConstruct | 24 +++- scripts/version.py | 2 +- site_scons/environ.scons | 4 +- 31 files changed, 271 insertions(+), 166 deletions(-) diff --git a/SConstruct b/SConstruct index 97d7e5e5e..a2c5cd9e7 100644 --- a/SConstruct +++ b/SConstruct @@ -172,17 +172,19 @@ Alias("fap_dist", fap_dist) fap_deploy = distenv.PhonyTarget( "fap_deploy", - [ + Action( [ - "${PYTHON3}", - "${FBT_SCRIPT_DIR}/storage.py", - "-p", - "${FLIP_PORT}", - "send", - "${SOURCE}", - "/ext/apps", + [ + "${PYTHON3}", + "${FBT_SCRIPT_DIR}/storage.py", + "-p", + "${FLIP_PORT}", + "send", + "${SOURCE}", + "/ext/apps", + ] ] - ], + ), source=firmware_env.Dir(("${RESOURCES_ROOT}/apps")), ) Depends(fap_deploy, firmware_env["FW_RESOURCES_MANIFEST"]) @@ -261,7 +263,7 @@ distenv.PhonyTarget( distenv.PhonyTarget( "debug_other_blackmagic", "${GDBPYCOM}", - GDBOPTS="${GDBOPTS_BASE} ${GDBOPTS_BLACKMAGIC}", + GDBOPTS="${GDBOPTS_BASE} ${GDBOPTS_BLACKMAGIC}", GDBREMOTE="${BLACKMAGIC_ADDR}", GDBPYOPTS=debug_other_opts, ) @@ -276,13 +278,13 @@ distenv.PhonyTarget( # Linter distenv.PhonyTarget( "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"]], ) distenv.PhonyTarget( "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"]], ) @@ -323,10 +325,14 @@ distenv.PhonyTarget( ) # 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 -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 @@ -361,5 +367,5 @@ distenv.Alias("vscode_dist", vscode_dist) # Configure shell with build tools distenv.PhonyTarget( "env", - "@echo $( ${FBT_SCRIPT_DIR}/toolchain/fbtenv.sh $)", + "@echo $( ${FBT_SCRIPT_DIR.abspath}/toolchain/fbtenv.sh $)", ) diff --git a/applications/debug/accessor/application.fam b/applications/debug/accessor/application.fam index 6b8472711..65a6c8666 100644 --- a/applications/debug/accessor/application.fam +++ b/applications/debug/accessor/application.fam @@ -4,7 +4,6 @@ App( apptype=FlipperAppType.DEBUG, targets=["f7"], entry_point="accessor_app", - cdefines=["APP_ACCESSOR"], requires=["gui"], stack_size=4 * 1024, order=40, diff --git a/applications/debug/battery_test_app/application.fam b/applications/debug/battery_test_app/application.fam index f97d10279..5f4acd83d 100644 --- a/applications/debug/battery_test_app/application.fam +++ b/applications/debug/battery_test_app/application.fam @@ -3,7 +3,6 @@ App( name="Battery Test", apptype=FlipperAppType.DEBUG, entry_point="battery_test_app", - cdefines=["APP_BATTERY_TEST"], requires=[ "gui", "power", diff --git a/applications/debug/blink_test/application.fam b/applications/debug/blink_test/application.fam index c6a8a922a..d7d873fb9 100644 --- a/applications/debug/blink_test/application.fam +++ b/applications/debug/blink_test/application.fam @@ -3,7 +3,6 @@ App( name="Blink Test", apptype=FlipperAppType.DEBUG, entry_point="blink_test_app", - cdefines=["APP_BLINK"], requires=["gui"], stack_size=1 * 1024, order=10, diff --git a/applications/debug/ccid_test/application.fam b/applications/debug/ccid_test/application.fam index e0cbc8d85..ad9076770 100644 --- a/applications/debug/ccid_test/application.fam +++ b/applications/debug/ccid_test/application.fam @@ -3,7 +3,6 @@ App( name="CCID Debug", apptype=FlipperAppType.DEBUG, entry_point="ccid_test_app", - cdefines=["CCID_TEST"], requires=[ "gui", ], diff --git a/applications/debug/crash_test/application.fam b/applications/debug/crash_test/application.fam index 55f62f86d..357efe667 100644 --- a/applications/debug/crash_test/application.fam +++ b/applications/debug/crash_test/application.fam @@ -3,7 +3,6 @@ App( name="Crash Test", apptype=FlipperAppType.DEBUG, entry_point="crash_test_app", - cdefines=["APP_CRASH_TEST"], requires=["gui"], stack_size=1 * 1024, fap_category="Debug", diff --git a/applications/debug/display_test/application.fam b/applications/debug/display_test/application.fam index e8a00d2ae..6a2d9c20c 100644 --- a/applications/debug/display_test/application.fam +++ b/applications/debug/display_test/application.fam @@ -3,7 +3,6 @@ App( name="Display Test", apptype=FlipperAppType.DEBUG, entry_point="display_test_app", - cdefines=["APP_DISPLAY_TEST"], requires=["gui"], fap_libs=["misc"], stack_size=1 * 1024, diff --git a/applications/debug/file_browser_test/application.fam b/applications/debug/file_browser_test/application.fam index 4a401a649..bb08ad2c5 100644 --- a/applications/debug/file_browser_test/application.fam +++ b/applications/debug/file_browser_test/application.fam @@ -3,7 +3,6 @@ App( name="File Browser Test", apptype=FlipperAppType.DEBUG, entry_point="file_browser_app", - cdefines=["APP_FILE_BROWSER_TEST"], requires=["gui"], stack_size=2 * 1024, order=150, diff --git a/applications/debug/keypad_test/application.fam b/applications/debug/keypad_test/application.fam index 6859af26f..90851950b 100644 --- a/applications/debug/keypad_test/application.fam +++ b/applications/debug/keypad_test/application.fam @@ -3,7 +3,6 @@ App( name="Keypad Test", apptype=FlipperAppType.DEBUG, entry_point="keypad_test_app", - cdefines=["APP_KEYPAD_TEST"], requires=["gui"], stack_size=1 * 1024, order=30, diff --git a/applications/debug/locale_test/application.fam b/applications/debug/locale_test/application.fam index e46eeff51..d341122f9 100644 --- a/applications/debug/locale_test/application.fam +++ b/applications/debug/locale_test/application.fam @@ -3,7 +3,6 @@ App( name="Locale Test", apptype=FlipperAppType.DEBUG, entry_point="locale_test_app", - cdefines=["APP_LOCALE"], requires=["gui", "locale"], stack_size=2 * 1024, order=70, diff --git a/applications/debug/text_box_test/application.fam b/applications/debug/text_box_test/application.fam index 3e54df9cc..823c21d06 100644 --- a/applications/debug/text_box_test/application.fam +++ b/applications/debug/text_box_test/application.fam @@ -3,7 +3,6 @@ App( name="Text Box Test", apptype=FlipperAppType.DEBUG, entry_point="text_box_test_app", - cdefines=["APP_TEXT_BOX_TEST"], requires=["gui"], stack_size=1 * 1024, order=140, diff --git a/applications/debug/uart_echo/application.fam b/applications/debug/uart_echo/application.fam index 8863a1a94..7b030bcfa 100644 --- a/applications/debug/uart_echo/application.fam +++ b/applications/debug/uart_echo/application.fam @@ -3,7 +3,6 @@ App( name="UART Echo", apptype=FlipperAppType.DEBUG, entry_point="uart_echo_app", - cdefines=["APP_UART_ECHO"], requires=["gui"], stack_size=2 * 1024, order=70, diff --git a/applications/debug/usb_mouse/application.fam b/applications/debug/usb_mouse/application.fam index 5c4340045..7747613d5 100644 --- a/applications/debug/usb_mouse/application.fam +++ b/applications/debug/usb_mouse/application.fam @@ -3,7 +3,6 @@ App( name="USB Mouse Demo", apptype=FlipperAppType.DEBUG, entry_point="usb_mouse_app", - cdefines=["APP_USB_MOUSE"], requires=["gui"], stack_size=1 * 1024, order=60, diff --git a/applications/debug/usb_test/application.fam b/applications/debug/usb_test/application.fam index 27395c34d..463bb4a26 100644 --- a/applications/debug/usb_test/application.fam +++ b/applications/debug/usb_test/application.fam @@ -3,7 +3,6 @@ App( name="USB Test", apptype=FlipperAppType.DEBUG, entry_point="usb_test_app", - cdefines=["APP_USB_TEST"], requires=["gui"], stack_size=1 * 1024, order=50, diff --git a/applications/debug/vibro_test/application.fam b/applications/debug/vibro_test/application.fam index f7115cc96..c35a7223f 100644 --- a/applications/debug/vibro_test/application.fam +++ b/applications/debug/vibro_test/application.fam @@ -3,7 +3,6 @@ App( name="Vibro Test", apptype=FlipperAppType.DEBUG, entry_point="vibro_test_app", - cdefines=["APP_VIBRO_TEST"], requires=["gui"], stack_size=1 * 1024, order=20, diff --git a/documentation/AppManifests.md b/documentation/AppManifests.md index d190a798b..9afdccb0e 100644 --- a/documentation/AppManifests.md +++ b/documentation/AppManifests.md @@ -32,7 +32,7 @@ Only two parameters are mandatory: **_appid_** and **_apptype_**. Others are opt - **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. - **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. - **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. diff --git a/firmware.scons b/firmware.scons index eca6afc4c..004def9a9 100644 --- a/firmware.scons +++ b/firmware.scons @@ -219,7 +219,7 @@ AddPostAction(fwelf, fwenv["APPBUILD_DUMP"]) AddPostAction( fwelf, Action( - '${PYTHON3} "${BIN_SIZE_SCRIPT}" elf ${TARGET}', + [["${PYTHON3}", "${BIN_SIZE_SCRIPT}", "elf", "${TARGET}"]], "Firmware size", ), ) @@ -229,7 +229,7 @@ fwhex = fwenv["FW_HEX"] = fwenv.HEXBuilder("${FIRMWARE_BUILD_CFG}") fwbin = fwenv["FW_BIN"] = fwenv.BINBuilder("${FIRMWARE_BUILD_CFG}") AddPostAction( fwbin, - Action('@${PYTHON3} "${BIN_SIZE_SCRIPT}" bin ${TARGET}'), + Action([["@${PYTHON3}", "${BIN_SIZE_SCRIPT}", "bin", "${TARGET}"]]), ) fwdfu = fwenv["FW_DFU"] = fwenv.DFUBuilder("${FIRMWARE_BUILD_CFG}") diff --git a/scripts/fbt/appmanifest.py b/scripts/fbt/appmanifest.py index bef4eb02b..d32869b10 100644 --- a/scripts/fbt/appmanifest.py +++ b/scripts/fbt/appmanifest.py @@ -33,6 +33,8 @@ class FlipperAppType(Enum): @dataclass class FlipperApplication: APP_ID_REGEX: ClassVar[re.Pattern] = re.compile(r"^[a-z0-9_]+$") + PRIVATE_FIELD_PREFIX: ClassVar[str] = "_" + APP_MANIFEST_DEFAULT_NAME: ClassVar[str] = "application.fam" @dataclass class ExternallyBuiltFile: @@ -48,8 +50,6 @@ class FlipperApplication: cdefines: List[str] = field(default_factory=list) cincludes: List[str] = field(default_factory=list) - PRIVATE_FIELD_PREFIX = "_" - appid: str apptype: FlipperAppType name: Optional[str] = "" @@ -117,8 +117,10 @@ class FlipperApplication: self.fap_version = tuple(int(v) for v in self.fap_version.split(".")) except ValueError: raise FlipperManifestException( - f"Invalid version string '{self.fap_version}'. Must be in the form 'major.minor'" + f"Invalid version '{self.fap_version}'. Must be in the form 'major.minor'" ) + if len(self.fap_version) < 2: + raise ValueError("Not enough version components") class AppManager: @@ -155,11 +157,20 @@ class AppManager: raise FlipperManifestException( f"App {kw.get('appid')} cannot have fal_embedded set" ) - # Harmless - cdefines for external apps are meaningless - # if apptype == FlipperAppType.EXTERNAL and kw.get("cdefines"): - # raise FlipperManifestException( - # f"External app {kw.get('appid')} must not have 'cdefines' in manifest" - # ) + + if apptype in AppBuildset.dist_app_types: + # For distributing .fap's resources, there's "fap_file_assets" + for app_property in ("resources",): + if kw.get(app_property): + raise FlipperManifestException( + f"App {kw.get('appid')} of type {apptype} cannot have '{app_property}' in manifest" + ) + else: + for app_property in ("fap_extbuild", "fap_private_libs", "fap_icon_assets"): + if kw.get(app_property): + raise FlipperManifestException( + f"App {kw.get('appid')} of type {apptype} must not have '{app_property}' in manifest" + ) def load_manifest(self, app_manifest_path: str, app_dir_node: object): if not os.path.exists(app_manifest_path): @@ -241,12 +252,21 @@ class AppBuildset: FlipperAppType.STARTUP, ) EXTERNAL_APP_TYPES_MAP = { + # AppType -> bool: true if always deploy, false if obey app set FlipperAppType.EXTERNAL: True, FlipperAppType.PLUGIN: True, FlipperAppType.DEBUG: True, FlipperAppType.MENUEXTERNAL: False, } + @classmethod + @property + def dist_app_types(cls): + """Applications that are installed on SD card""" + return list( + entry[0] for entry in cls.EXTERNAL_APP_TYPES_MAP.items() if entry[1] + ) + @staticmethod def print_writer(message): print(message) @@ -432,96 +452,3 @@ class AppBuildset: for source_type in app.sources ) ) - - -class ApplicationsCGenerator: - APP_TYPE_MAP = { - FlipperAppType.SERVICE: ("FlipperInternalApplication", "FLIPPER_SERVICES"), - FlipperAppType.SYSTEM: ("FlipperInternalApplication", "FLIPPER_SYSTEM_APPS"), - FlipperAppType.APP: ("FlipperInternalApplication", "FLIPPER_APPS"), - FlipperAppType.DEBUG: ("FlipperInternalApplication", "FLIPPER_DEBUG_APPS"), - FlipperAppType.SETTINGS: ( - "FlipperInternalApplication", - "FLIPPER_SETTINGS_APPS", - ), - FlipperAppType.STARTUP: ( - "FlipperInternalOnStartHook", - "FLIPPER_ON_SYSTEM_START", - ), - } - - APP_EXTERNAL_TYPE = ( - "FlipperExternalApplication", - "FLIPPER_EXTERNAL_APPS", - ) - - def __init__(self, buildset: AppBuildset, autorun_app: str = ""): - self.buildset = buildset - self.autorun = autorun_app - - def get_app_ep_forward(self, app: FlipperApplication): - if app.apptype == FlipperAppType.STARTUP: - return f"extern void {app.entry_point}();" - return f"extern int32_t {app.entry_point}(void* p);" - - def get_app_descr(self, app: FlipperApplication): - if app.apptype == FlipperAppType.STARTUP: - return app.entry_point - return f""" - {{.app = {app.entry_point}, - .name = "{app.name}", - .appid = "{app.appid}", - .stack_size = {app.stack_size}, - .icon = {f"&{app.icon}" if app.icon else "NULL"}, - .flags = {'|'.join(f"FlipperInternalApplicationFlag{flag}" for flag in app.flags)} }}""" - - def get_external_app_descr(self, app: FlipperApplication): - app_path = "/ext/apps" - if app.fap_category: - app_path += f"/{app.fap_category}" - app_path += f"/{app.appid}.fap" - return f""" - {{ - .name = "{app.name}", - .icon = {f"&{app.icon}" if app.icon else "NULL"}, - .path = "{app_path}" }}""" - - def generate(self): - contents = [ - '#include "applications.h"', - "#include ", - f'const char* FLIPPER_AUTORUN_APP_NAME = "{self.autorun}";', - ] - for apptype in self.APP_TYPE_MAP: - contents.extend( - map(self.get_app_ep_forward, self.buildset.get_apps_of_type(apptype)) - ) - entry_type, entry_block = self.APP_TYPE_MAP[apptype] - contents.append(f"const {entry_type} {entry_block}[] = {{") - contents.append( - ",\n".join( - map(self.get_app_descr, self.buildset.get_apps_of_type(apptype)) - ) - ) - contents.append("};") - contents.append( - f"const size_t {entry_block}_COUNT = COUNT_OF({entry_block});" - ) - - archive_app = self.buildset.get_apps_of_type(FlipperAppType.ARCHIVE) - if archive_app: - contents.extend( - [ - self.get_app_ep_forward(archive_app[0]), - f"const FlipperInternalApplication FLIPPER_ARCHIVE = {self.get_app_descr(archive_app[0])};", - ] - ) - - entry_type, entry_block = self.APP_EXTERNAL_TYPE - external_apps = self.buildset.get_apps_of_type(FlipperAppType.MENUEXTERNAL) - contents.append(f"const {entry_type} {entry_block}[] = {{") - contents.append(",\n".join(map(self.get_external_app_descr, external_apps))) - contents.append("};") - contents.append(f"const size_t {entry_block}_COUNT = COUNT_OF({entry_block});") - - return "\n".join(contents) diff --git a/scripts/fbt_tools/fbt_apps.py b/scripts/fbt_tools/fbt_apps.py index edce194f0..dadf6dc0c 100644 --- a/scripts/fbt_tools/fbt_apps.py +++ b/scripts/fbt_tools/fbt_apps.py @@ -1,25 +1,118 @@ from ansi.color import fg from fbt.appmanifest import ( - ApplicationsCGenerator, AppManager, + AppBuildset, + FlipperApplication, FlipperAppType, FlipperManifestException, ) from SCons.Action import Action from SCons.Builder import Builder from SCons.Errors import StopError -from SCons.Warnings import WarningOnByDefault, warn from SCons.Script import GetOption +from SCons.Warnings import WarningOnByDefault, warn # Adding objects for application management to env # AppManager env["APPMGR"] - loads all manifests; manages list of known apps # AppBuildset env["APPBUILD"] - contains subset of apps, filtered for current config +class ApplicationsCGenerator: + APP_TYPE_MAP = { + FlipperAppType.SERVICE: ("FlipperInternalApplication", "FLIPPER_SERVICES"), + FlipperAppType.SYSTEM: ("FlipperInternalApplication", "FLIPPER_SYSTEM_APPS"), + FlipperAppType.APP: ("FlipperInternalApplication", "FLIPPER_APPS"), + FlipperAppType.DEBUG: ("FlipperInternalApplication", "FLIPPER_DEBUG_APPS"), + FlipperAppType.SETTINGS: ( + "FlipperInternalApplication", + "FLIPPER_SETTINGS_APPS", + ), + FlipperAppType.STARTUP: ( + "FlipperInternalOnStartHook", + "FLIPPER_ON_SYSTEM_START", + ), + } + + APP_EXTERNAL_TYPE = ( + "FlipperExternalApplication", + "FLIPPER_EXTERNAL_APPS", + ) + + def __init__(self, buildset: AppBuildset, autorun_app: str = ""): + self.buildset = buildset + self.autorun = autorun_app + + def get_app_ep_forward(self, app: FlipperApplication): + if app.apptype == FlipperAppType.STARTUP: + return f"extern void {app.entry_point}();" + return f"extern int32_t {app.entry_point}(void* p);" + + def get_app_descr(self, app: FlipperApplication): + if app.apptype == FlipperAppType.STARTUP: + return app.entry_point + return f""" + {{.app = {app.entry_point}, + .name = "{app.name}", + .appid = "{app.appid}", + .stack_size = {app.stack_size}, + .icon = {f"&{app.icon}" if app.icon else "NULL"}, + .flags = {'|'.join(f"FlipperInternalApplicationFlag{flag}" for flag in app.flags)} }}""" + + def get_external_app_descr(self, app: FlipperApplication): + app_path = "/ext/apps" + if app.fap_category: + app_path += f"/{app.fap_category}" + app_path += f"/{app.appid}.fap" + return f""" + {{ + .name = "{app.name}", + .icon = {f"&{app.icon}" if app.icon else "NULL"}, + .path = "{app_path}" }}""" + + def generate(self): + contents = [ + '#include "applications.h"', + "#include ", + f'const char* FLIPPER_AUTORUN_APP_NAME = "{self.autorun}";', + ] + for apptype in self.APP_TYPE_MAP: + contents.extend( + map(self.get_app_ep_forward, self.buildset.get_apps_of_type(apptype)) + ) + entry_type, entry_block = self.APP_TYPE_MAP[apptype] + contents.append(f"const {entry_type} {entry_block}[] = {{") + contents.append( + ",\n".join( + map(self.get_app_descr, self.buildset.get_apps_of_type(apptype)) + ) + ) + contents.append("};") + contents.append( + f"const size_t {entry_block}_COUNT = COUNT_OF({entry_block});" + ) + + archive_app = self.buildset.get_apps_of_type(FlipperAppType.ARCHIVE) + if archive_app: + contents.extend( + [ + self.get_app_ep_forward(archive_app[0]), + f"const FlipperInternalApplication FLIPPER_ARCHIVE = {self.get_app_descr(archive_app[0])};", + ] + ) + + entry_type, entry_block = self.APP_EXTERNAL_TYPE + external_apps = self.buildset.get_apps_of_type(FlipperAppType.MENUEXTERNAL) + contents.append(f"const {entry_type} {entry_block}[] = {{") + contents.append(",\n".join(map(self.get_external_app_descr, external_apps))) + contents.append("};") + contents.append(f"const size_t {entry_block}_COUNT = COUNT_OF({entry_block});") + + return "\n".join(contents) + + def LoadAppManifest(env, entry): try: - APP_MANIFEST_NAME = "application.fam" - manifest_glob = entry.glob(APP_MANIFEST_NAME) + manifest_glob = entry.glob(FlipperApplication.APP_MANIFEST_DEFAULT_NAME) if len(manifest_glob) == 0: try: disk_node = next(filter(lambda d: d.exists(), entry.get_all_rdirs())) @@ -27,7 +120,7 @@ def LoadAppManifest(env, entry): disk_node = entry raise FlipperManifestException( - f"App folder '{disk_node.abspath}': missing manifest ({APP_MANIFEST_NAME})" + f"App folder '{disk_node.abspath}': missing manifest ({FlipperApplication.APP_MANIFEST_DEFAULT_NAME})" ) app_manifest_file_path = manifest_glob[0].rfile().abspath diff --git a/scripts/fbt_tools/fbt_extapps.py b/scripts/fbt_tools/fbt_extapps.py index b88fa7929..a7914c4f8 100644 --- a/scripts/fbt_tools/fbt_extapps.py +++ b/scripts/fbt_tools/fbt_extapps.py @@ -58,7 +58,8 @@ class AppBuilder: ) self.app_env.Append( CPPDEFINES=[ - ("FAP_VERSION", f'"{".".join(map(str, self.app.fap_version))}"') + ("FAP_VERSION", f'\\"{".".join(map(str, self.app.fap_version))}\\"'), + *self.app.cdefines, ], ) self.app_env.VariantDir(self.app_work_dir, self.app._appdir, duplicate=False) @@ -143,8 +144,8 @@ class AppBuilder: self.app._assets_dirs = [self.app._appdir.Dir(self.app.fap_file_assets)] self.app_env.Append( - LIBS=[*self.app.fap_libs, *self.private_libs], - CPPPATH=[self.app_work_dir, self.app._appdir], + LIBS=[*self.app.fap_libs, *self.private_libs, *self.app.fap_libs], + CPPPATH=[self.app_env.Dir(self.app_work_dir), self.app._appdir], ) app_sources = self.app_env.GatherSources( @@ -472,7 +473,19 @@ def AddAppLaunchTarget(env, appname, launch_target_name): components = _gather_app_components(env, appname) target = env.PhonyTarget( launch_target_name, - '${PYTHON3} "${APP_RUN_SCRIPT}" -p ${FLIP_PORT} ${EXTRA_ARGS} -s ${SOURCES} -t ${FLIPPER_FILE_TARGETS}', + [ + [ + "${PYTHON3}", + "${APP_RUN_SCRIPT}", + "-p", + "${FLIP_PORT}", + "${EXTRA_ARGS}", + "-s", + "${SOURCES}", + "-t", + "${FLIPPER_FILE_TARGETS}", + ] + ], source=components.deploy_sources.values(), FLIPPER_FILE_TARGETS=components.deploy_sources.keys(), EXTRA_ARGS=components.extra_launch_args, diff --git a/scripts/fbt_tools/fbt_sdk.py b/scripts/fbt_tools/fbt_sdk.py index 6350f14b8..17acc8cf1 100644 --- a/scripts/fbt_tools/fbt_sdk.py +++ b/scripts/fbt_tools/fbt_sdk.py @@ -285,7 +285,20 @@ def generate(env, **kw): "$SDK_AMALGAMATE_HEADER_COMSTR", ), Action( - "$CC -o $TARGET -E -P $CCFLAGS $_CCCOMCOM $SDK_PP_FLAGS -MMD ${TARGET}.c", + [ + [ + "$CC", + "-o", + "$TARGET", + "-E", + "-P", + "$CCFLAGS", + "$_CCCOMCOM", + "$SDK_PP_FLAGS", + "-MMD", + "${TARGET}.c", + ] + ], "$SDK_AMALGAMATE_PP_COMSTR", ), ], diff --git a/scripts/fbt_tools/fbt_version.py b/scripts/fbt_tools/fbt_version.py index f1a782523..e64167b3d 100644 --- a/scripts/fbt_tools/fbt_version.py +++ b/scripts/fbt_tools/fbt_version.py @@ -19,10 +19,22 @@ def generate(env): BUILDERS={ "VersionBuilder": Builder( action=Action( - '${PYTHON3} "${VERSION_SCRIPT}" generate ' - "-t ${TARGET_HW} -fw-origin ${FIRMWARE_ORIGIN} " - '-o ${TARGET.dir.posix} --dir "${ROOT_DIR}"', - "${VERSIONCOMSTR}", + [ + [ + "${PYTHON3}", + "${VERSION_SCRIPT}", + "generate", + "-t", + "${TARGET_HW}", + "--fw-origin", + "${FIRMWARE_ORIGIN}", + "-o", + "${TARGET.dir.posix}", + "--dir", + "${ROOT_DIR}", + "${VERSIONCOMSTR}", + ] + ] ), emitter=_version_emitter, ), diff --git a/scripts/fbt_tools/fwbin.py b/scripts/fbt_tools/fwbin.py index 06a435b6d..860f83b1b 100644 --- a/scripts/fbt_tools/fwbin.py +++ b/scripts/fbt_tools/fwbin.py @@ -25,7 +25,7 @@ def generate(env): BUILDERS={ "HEXBuilder": Builder( action=Action( - '${OBJCOPY} -O ihex "${SOURCE}" "${TARGET}"', + [["${OBJCOPY}", "-O", "ihex", "${SOURCE}", "${TARGET}"]], "${HEXCOMSTR}", ), suffix=".hex", @@ -33,7 +33,7 @@ def generate(env): ), "BINBuilder": Builder( action=Action( - '${OBJCOPY} -O binary -S "${SOURCE}" "${TARGET}"', + [["${OBJCOPY}", "-O", "binary", "-S", "${SOURCE}", "${TARGET}"]], "${BINCOMSTR}", ), suffix=".bin", @@ -41,7 +41,20 @@ def generate(env): ), "DFUBuilder": Builder( action=Action( - '${PYTHON3} "${BIN2DFU}" -i "${SOURCE}" -o "${TARGET}" -a ${IMAGE_BASE_ADDRESS} -l "Flipper Zero F${TARGET_HW}"', + [ + [ + "${PYTHON3}", + "${BIN2DFU}", + "-i", + "${SOURCE}", + "-o", + "${TARGET}", + "-a", + "${IMAGE_BASE_ADDRESS}", + "-l", + "Flipper Zero F${TARGET_HW}", + ] + ], "${DFUCOMSTR}", ), suffix=".dfu", diff --git a/scripts/fbt_tools/jflash.py b/scripts/fbt_tools/jflash.py index aea7279b6..5eb9f2c19 100644 --- a/scripts/fbt_tools/jflash.py +++ b/scripts/fbt_tools/jflash.py @@ -1,5 +1,6 @@ from SCons.Builder import Builder from SCons.Defaults import Touch +from SCons.Action import Action def generate(env): @@ -9,13 +10,21 @@ def generate(env): "-auto", "-exit", ], - JFLASHCOM="${JFLASH} -openprj${JFLASHPROJECT} -open${SOURCE},${JFLASHADDR} ${JFLASHFLAGS}", ) env.Append( BUILDERS={ "JFlash": Builder( action=[ - "${JFLASHCOM}", + Action( + [ + [ + "${JFLASH}", + "-openprj${JFLASHPROJECT}", + "-open${SOURCE},${JFLASHADDR}", + "${JFLASHFLAGS}", + ] + ] + ), Touch("${TARGET}"), ], ), diff --git a/scripts/fbt_tools/objdump.py b/scripts/fbt_tools/objdump.py index 31f817648..e3dbc6d87 100644 --- a/scripts/fbt_tools/objdump.py +++ b/scripts/fbt_tools/objdump.py @@ -6,13 +6,12 @@ def generate(env): env.SetDefault( OBJDUMP="objdump", OBJDUMPFLAGS=[], - OBJDUMPCOM="$OBJDUMP $OBJDUMPFLAGS -S $SOURCES > $TARGET", ) env.Append( BUILDERS={ "ObjDump": Builder( action=Action( - "${OBJDUMPCOM}", + [["$OBJDUMP", "$OBJDUMPFLAGS", "-S", "$SOURCES", ">", "$TARGET"]], "${OBJDUMPCOMSTR}", ), suffix=".lst", diff --git a/scripts/fbt_tools/openocd.py b/scripts/fbt_tools/openocd.py index 157d798f4..596f5f8a6 100644 --- a/scripts/fbt_tools/openocd.py +++ b/scripts/fbt_tools/openocd.py @@ -5,6 +5,7 @@ from SCons.Defaults import Touch __OPENOCD_BIN = "openocd" +# TODO: FL-3663: rework argument passing to lists _oocd_action = Action( "${OPENOCD} ${OPENOCD_OPTS} ${OPENOCD_COMMAND}", "${OPENOCDCOMSTR}", diff --git a/scripts/fbt_tools/pvsstudio.py b/scripts/fbt_tools/pvsstudio.py index f43db126e..ecf9d4b06 100644 --- a/scripts/fbt_tools/pvsstudio.py +++ b/scripts/fbt_tools/pvsstudio.py @@ -79,7 +79,17 @@ def generate(env): BUILDERS={ "PVSCheck": Builder( action=Action( - '${PVSCHECKBIN} analyze ${PVSOPTIONS} -f "${SOURCE}" -o "${TARGET}"', + [ + [ + "${PVSCHECKBIN}", + "analyze", + "${PVSOPTIONS}", + "-f", + "${SOURCE}", + "-o", + "${TARGET}", + ] + ], "${PVSCHECKCOMSTR}", ), suffix=".log", @@ -92,7 +102,17 @@ def generate(env): # PlogConverter.exe and plog-converter have different behavior Mkdir("${TARGET.dir}") if env["PLATFORM"] == "win32" else None, Action(_set_browser_action, None), - '${PVSCONVBIN} ${PVSCONVOPTIONS} "${SOURCE}" -o "${REPORT_DIR}"', + Action( + [ + [ + "${PVSCONVBIN}", + "${PVSCONVOPTIONS}", + "${SOURCE}", + "-o", + "${REPORT_DIR}", + ] + ] + ), ], "${PVSCONVCOMSTR}", ), diff --git a/scripts/fbt_tools/strip.py b/scripts/fbt_tools/strip.py index ee14fc185..39f3a620c 100644 --- a/scripts/fbt_tools/strip.py +++ b/scripts/fbt_tools/strip.py @@ -6,13 +6,12 @@ def generate(env): env.SetDefault( STRIP="strip", STRIPFLAGS=[], - STRIPCOM="$STRIP $STRIPFLAGS $SOURCES -o $TARGET", ) env.Append( BUILDERS={ "ELFStripper": Builder( action=Action( - "${STRIPCOM}", + [["$STRIP", "$STRIPFLAGS", "$SOURCES", "-o", "$TARGET"]], "${STRIPCOMSTR}", ), suffix=".elf", diff --git a/scripts/ufbt/SConstruct b/scripts/ufbt/SConstruct index 98e6b638f..46d663578 100644 --- a/scripts/ufbt/SConstruct +++ b/scripts/ufbt/SConstruct @@ -325,24 +325,26 @@ else: appenv.PhonyTarget( "cli", - '${PYTHON3} "${FBT_SCRIPT_DIR}/serial_cli.py" -p ${FLIP_PORT}', + [["${PYTHON3}", "${FBT_SCRIPT_DIR}/serial_cli.py", "-p", "${FLIP_PORT}"]], ) # Update WiFi devboard firmware -dist_env.PhonyTarget("devboard_flash", "${PYTHON3} ${FBT_SCRIPT_DIR}/wifi_board.py") +dist_env.PhonyTarget( + "devboard_flash", [["${PYTHON3}", "${FBT_SCRIPT_DIR}/wifi_board.py"]] +) # Linter dist_env.PhonyTarget( "lint", - "${PYTHON3} ${FBT_SCRIPT_DIR}/lint.py check ${LINT_SOURCES}", + [["${PYTHON3}", "${FBT_SCRIPT_DIR}/lint.py", "check", "${LINT_SOURCES}"]], source=original_app_dir.File(".clang-format"), LINT_SOURCES=[original_app_dir], ) dist_env.PhonyTarget( "format", - "${PYTHON3} ${FBT_SCRIPT_DIR}/lint.py format ${LINT_SOURCES}", + [["${PYTHON3}", "${FBT_SCRIPT_DIR}/lint.py", "format", "${LINT_SOURCES}"]], source=original_app_dir.File(".clang-format"), LINT_SOURCES=[original_app_dir], ) @@ -455,7 +457,17 @@ if dolphin_src_dir.exists(): ) dist_env.PhonyTarget( "dolphin_ext", - '${PYTHON3} ${FBT_SCRIPT_DIR}/storage.py -p ${FLIP_PORT} send "${SOURCE}" /ext/dolphin', + [ + [ + "${PYTHON3}", + "${FBT_SCRIPT_DIR}/storage.py", + "-p", + "${FLIP_PORT}", + "send", + "${SOURCE}", + "/ext/dolphin", + ] + ], source=ufbt_build_dir.Dir("dolphin"), ) else: @@ -467,7 +479,7 @@ else: dist_env.PhonyTarget( "env", - "@echo $( ${FBT_SCRIPT_DIR}/toolchain/fbtenv.sh $)", + "@echo $( ${FBT_SCRIPT_DIR.abspath}/toolchain/fbtenv.sh $)", ) dist_env.PostConfigureUfbtEnvionment() diff --git a/scripts/version.py b/scripts/version.py index 4b1c739bc..98b1b7e85 100755 --- a/scripts/version.py +++ b/scripts/version.py @@ -101,7 +101,7 @@ class Main(App): required=True, ) self.parser_generate.add_argument( - "-fw-origin", + "--fw-origin", dest="firmware_origin", type=str, help="firmware origin", diff --git a/site_scons/environ.scons b/site_scons/environ.scons index b638b1018..74762cb15 100644 --- a/site_scons/environ.scons +++ b/site_scons/environ.scons @@ -27,6 +27,8 @@ variables_to_forward = [ "PYTHONNOUSERSITE", "TMP", "TEMP", + # ccache + "CCACHE_DISABLE", # Colors for tools "TERM", ] @@ -62,7 +64,7 @@ coreenv = VAR_ENV.Clone( # Setting up temp file parameters - to overcome command line length limits TEMPFILEARGESCFUNC=tempfile_arg_esc_func, ROOT_DIR=Dir("#"), - FBT_SCRIPT_DIR="${ROOT_DIR}/scripts", + FBT_SCRIPT_DIR=Dir("#/scripts"), ) # If DIST_SUFFIX is set in environment, is has precedence (set by CI) From 4b3e8aba294bf94be4ac7a73873202e3078afb2c Mon Sep 17 00:00:00 2001 From: Sergey Gavrilov Date: Wed, 15 Nov 2023 19:39:27 +0300 Subject: [PATCH 9/9] [FL-3664] 64k does not enough (#3216) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Unit tests: add "exists" to furi_record tests * Unit tests: mu_warn, storage 64k test * Storage: read/write over 64k * Unit tests: moar tests for storage r/w for >64k cases * Apps, libs: replace uint16_t with size_t on storage r/w operations * Unit tests: better data pattern, subghz: warning if transmission is prohibited Co-authored-by: あく --- .../debug/unit_tests/furi/furi_record_test.c | 31 ++++++--- applications/debug/unit_tests/minunit.h | 5 ++ .../debug/unit_tests/storage/dirwalk_test.c | 2 +- .../debug/unit_tests/storage/storage_test.c | 65 +++++++++++++++++++ .../debug/unit_tests/subghz/subghz_test.c | 1 + applications/debug/unit_tests/test_index.c | 10 +++ .../main/archive/helpers/archive_favorites.c | 4 +- applications/main/subghz/subghz_cli.c | 2 +- .../services/notification/notification_app.c | 4 +- applications/services/rpc/rpc_storage.c | 2 +- applications/services/storage/storage.h | 6 +- applications/services/storage/storage_cli.c | 22 +++---- .../services/storage/storage_external_api.c | 41 +++++++++++- .../scenes/storage_settings_scene_benchmark.c | 4 +- .../updater/util/update_task_worker_flasher.c | 2 +- lib/flipper_application/elf/elf_file.c | 2 +- lib/music_worker/music_worker.c | 2 +- lib/toolbox/crc32_calc.c | 2 +- lib/toolbox/md5_calc.c | 4 +- lib/toolbox/saved_struct.c | 6 +- lib/toolbox/stream/file_stream.c | 24 +------ lib/update_util/dfu_file.c | 6 +- lib/update_util/update_operation.c | 2 +- targets/f18/api_symbols.csv | 10 +-- targets/f7/api_symbols.csv | 10 +-- 25 files changed, 188 insertions(+), 81 deletions(-) diff --git a/applications/debug/unit_tests/furi/furi_record_test.c b/applications/debug/unit_tests/furi/furi_record_test.c index 512ddfdc4..236e1efc5 100644 --- a/applications/debug/unit_tests/furi/furi_record_test.c +++ b/applications/debug/unit_tests/furi/furi_record_test.c @@ -3,18 +3,29 @@ #include #include "../minunit.h" -void test_furi_create_open() { - // 1. Create record - uint8_t test_data = 0; - furi_record_create("test/holding", (void*)&test_data); +#define TEST_RECORD_NAME "test/holding" - // 2. Open it - void* record = furi_record_open("test/holding"); +void test_furi_create_open() { + // 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); - // 3. Close it - furi_record_close("test/holding"); + // Close it + furi_record_close(TEST_RECORD_NAME); - // 4. Clean up - furi_record_destroy("test/holding"); + // Clean up + furi_record_destroy(TEST_RECORD_NAME); + + // Test that record does not exist + mu_check(furi_record_exists(TEST_RECORD_NAME) == false); } diff --git a/applications/debug/unit_tests/minunit.h b/applications/debug/unit_tests/minunit.h index 69bfba6d9..083db5a9a 100644 --- a/applications/debug/unit_tests/minunit.h +++ b/applications/debug/unit_tests/minunit.h @@ -81,6 +81,7 @@ __attribute__((unused)) static void (*minunit_teardown)(void) = NULL; void minunit_print_progress(void); void minunit_print_fail(const char* error); +void minunit_printf_warning(const char* format, ...); /* Definitions */ #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);) #define MU_EXIT_CODE minunit_fail +/* Warnings */ +#define mu_warn(message) \ + MU__SAFE_BLOCK(minunit_printf_warning("%s:%d: %s", __FILE__, __LINE__, message);) + /* Assertions */ #define mu_check(test) \ MU__SAFE_BLOCK( \ diff --git a/applications/debug/unit_tests/storage/dirwalk_test.c b/applications/debug/unit_tests/storage/dirwalk_test.c index e0842a7a4..19ac336ff 100644 --- a/applications/debug/unit_tests/storage/dirwalk_test.c +++ b/applications/debug/unit_tests/storage/dirwalk_test.c @@ -139,7 +139,7 @@ static bool write_file_13DA(Storage* storage, const char* path) { File* file = storage_file_alloc(storage); bool result = false; 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_free(file); diff --git a/applications/debug/unit_tests/storage/storage_test.c b/applications/debug/unit_tests/storage/storage_test.c index 13188e5e0..5ea36935b 100644 --- a/applications/debug/unit_tests/storage/storage_test.c +++ b/applications/debug/unit_tests/storage/storage_test.c @@ -115,6 +115,66 @@ MU_TEST(storage_file_open_close) { 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) { storage_file_open_lock_setup(); MU_RUN_TEST(storage_file_open_close); @@ -122,6 +182,10 @@ MU_TEST_SUITE(storage_file) { 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) { Storage* storage = furi_record_open(RECORD_STORAGE); File* file; @@ -640,6 +704,7 @@ MU_TEST_SUITE(test_md5_calc_suite) { int run_minunit_test_storage() { MU_RUN_SUITE(storage_file); + MU_RUN_SUITE(storage_file_64k); MU_RUN_SUITE(storage_dir); MU_RUN_SUITE(storage_rename); MU_RUN_SUITE(test_data_path); diff --git a/applications/debug/unit_tests/subghz/subghz_test.c b/applications/debug/unit_tests/subghz/subghz_test.c index 2f2b9e981..60c7abd03 100644 --- a/applications/debug/unit_tests/subghz/subghz_test.c +++ b/applications/debug/unit_tests/subghz/subghz_test.c @@ -326,6 +326,7 @@ bool subghz_hal_async_tx_test_run(SubGhzHalAsyncTxTestType type) { furi_hal_subghz_set_frequency_and_path(433920000); if(!furi_hal_subghz_start_async_tx(subghz_hal_async_tx_test_yield, &test)) { + mu_warn("SubGHZ transmission is prohibited"); return false; } diff --git a/applications/debug/unit_tests/test_index.c b/applications/debug/unit_tests/test_index.c index 7c1b6b444..d7afaa3c4 100644 --- a/applications/debug/unit_tests/test_index.c +++ b/applications/debug/unit_tests/test_index.c @@ -78,6 +78,16 @@ void minunit_print_fail(const char* 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) { UNUSED(cli); UNUSED(args); diff --git a/applications/main/archive/helpers/archive_favorites.c b/applications/main/archive/helpers/archive_favorites.c index f395ee5a1..682aa6b38 100644 --- a/applications/main/archive/helpers/archive_favorites.c +++ b/applications/main/archive/helpers/archive_favorites.c @@ -12,12 +12,12 @@ static bool archive_favorites_read_line(File* file, FuriString* str_result) { bool result = false; 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) { return false; } - for(uint16_t i = 0; i < read_count; i++) { + for(size_t i = 0; i < read_count; i++) { if(buffer[i] == '\n') { uint32_t position = storage_file_tell(file); if(storage_file_get_error(file) != FSE_OK) { diff --git a/applications/main/subghz/subghz_cli.c b/applications/main/subghz/subghz_cli.c index 0a7b52127..e1b5e8684 100644 --- a/applications/main/subghz/subghz_cli.c +++ b/applications/main/subghz/subghz_cli.c @@ -946,7 +946,7 @@ static void subghz_cli_command(Cli* cli, FuriString* args, void* context) { static bool subghz_on_system_start_istream_read(pb_istream_t* istream, pb_byte_t* buf, size_t count) { File* file = istream->state; - uint16_t ret = storage_file_read(file, buf, count); + size_t ret = storage_file_read(file, buf, count); return (count == ret); } diff --git a/applications/services/notification/notification_app.c b/applications/services/notification/notification_app.c index 5769ced92..9baa738b7 100644 --- a/applications/services/notification/notification_app.c +++ b/applications/services/notification/notification_app.c @@ -444,7 +444,7 @@ static bool notification_load_settings(NotificationApp* app) { storage_file_open(file, NOTIFICATION_SETTINGS_PATH, FSAM_READ, FSOM_OPEN_EXISTING); 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) { 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); 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) { fs_result = false; diff --git a/applications/services/rpc/rpc_storage.c b/applications/services/rpc/rpc_storage.c index ee024b823..913d89f1a 100644 --- a/applications/services/rpc/rpc_storage.c +++ b/applications/services/rpc/rpc_storage.c @@ -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) { uint8_t* buffer = request->content.storage_write_request.file.data->bytes; 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); } diff --git a/applications/services/storage/storage.h b/applications/services/storage/storage.h index 3caa155c7..20a371fc0 100644 --- a/applications/services/storage/storage.h +++ b/applications/services/storage/storage.h @@ -123,7 +123,7 @@ bool storage_file_is_dir(File* file); * @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); /** * @brief Write bytes from a buffer to a file. @@ -133,7 +133,7 @@ uint16_t storage_file_read(File* file, void* buff, uint16_t bytes_to_read); * @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); /** * @brief Change the current access position in a file. @@ -207,7 +207,7 @@ bool storage_file_exists(Storage* storage, const char* path); * @param size data size to be copied, in bytes. * @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); /******************* Directory Functions *******************/ diff --git a/applications/services/storage/storage_cli.c b/applications/services/storage/storage_cli.c index 59489d459..2927022a3 100644 --- a/applications/services/storage/storage_cli.c +++ b/applications/services/storage/storage_cli.c @@ -198,15 +198,15 @@ static void storage_cli_read(Cli* cli, FuriString* path) { File* file = storage_file_alloc(api); if(storage_file_open(file, furi_string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) { - const uint16_t buffer_size = 128; - uint16_t read_size = 0; + const size_t buffer_size = 128; + size_t read_size = 0; uint8_t* data = malloc(buffer_size); printf("Size: %lu\r\n", (uint32_t)storage_file_size(file)); do { 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]); } } while(read_size > 0); @@ -227,7 +227,7 @@ static void storage_cli_write(Cli* cli, FuriString* path) { Storage* api = furi_record_open(RECORD_STORAGE); File* file = storage_file_alloc(api); - const uint16_t buffer_size = 512; + const size_t buffer_size = 512; uint8_t* buffer = malloc(buffer_size); 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); if(symbol == CliSymbolAsciiETX) { - uint16_t write_size = read_index % buffer_size; + size_t write_size = read_index % buffer_size; 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) { storage_cli_print_error(storage_file_get_error(file)); @@ -257,7 +257,7 @@ static void storage_cli_write(Cli* cli, FuriString* path) { read_index++; 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) { 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)) { 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) { 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"); cli_getc(cli); - uint16_t read_size = storage_file_read(file, data, buffer_size); - for(uint16_t i = 0; i < read_size; i++) { + size_t read_size = storage_file_read(file, data, buffer_size); + for(size_t i = 0; i < read_size; i++) { putchar(data[i]); } 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); - 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) { storage_cli_print_error(storage_file_get_error(file)); diff --git a/applications/services/storage/storage_external_api.c b/applications/services/storage/storage_external_api.c index 1027d4310..666090346 100644 --- a/applications/services/storage/storage_external_api.c +++ b/applications/services/storage/storage_external_api.c @@ -139,7 +139,7 @@ bool storage_file_close(File* file) { 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) { return 0; } @@ -159,7 +159,8 @@ uint16_t storage_file_read(File* file, void* buff, uint16_t bytes_to_read) { 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) { 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; } +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) { S_FILE_API_PROLOGUE; S_API_PROLOGUE; @@ -252,7 +287,7 @@ bool storage_file_exists(Storage* storage, const char* path) { 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); while(size) { diff --git a/applications/settings/storage_settings/scenes/storage_settings_scene_benchmark.c b/applications/settings/storage_settings/scenes/storage_settings_scene_benchmark.c index 8359c00be..a5bf1b9d3 100644 --- a/applications/settings/storage_settings/scenes/storage_settings_scene_benchmark.c +++ b/applications/settings/storage_settings/scenes/storage_settings_scene_benchmark.c @@ -44,7 +44,7 @@ static bool storage_settings_scene_bench_write( } 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); bool result = true; *speed = -1; @@ -82,7 +82,7 @@ static void storage_settings_scene_benchmark(StorageSettings* app) { 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_r_speed[BENCH_COUNT] = {0, 0, 0, 0, 0, 0}; diff --git a/applications/system/updater/util/update_task_worker_flasher.c b/applications/system/updater/util/update_task_worker_flasher.c index c56031992..1b4b07900 100644 --- a/applications/system/updater/util/update_task_worker_flasher.c +++ b/applications/system/updater/util/update_task_worker_flasher.c @@ -104,7 +104,7 @@ static bool update_task_write_stack_data(UpdateTask* update_task) { update_task_set_progress(update_task, UpdateTaskStageRadioWrite, 0); uint8_t* fw_block = malloc(FLASH_PAGE_SIZE); - uint16_t bytes_read = 0; + size_t bytes_read = 0; uint32_t element_offs = 0; while(element_offs < stack_size) { diff --git a/lib/flipper_application/elf/elf_file.c b/lib/flipper_application/elf/elf_file.c index b2c9445ff..8a78cca41 100644 --- a/lib/flipper_application/elf/elf_file.c +++ b/lib/flipper_application/elf/elf_file.c @@ -101,7 +101,7 @@ static bool elf_read_string_from_offset(ELFFile* elf, off_t offset, FuriString* buffer[ELF_NAME_BUFFER_LEN] = 0; 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); if(strlen(buffer) < ELF_NAME_BUFFER_LEN) { result = true; diff --git a/lib/music_worker/music_worker.c b/lib/music_worker/music_worker.c index 61fc838f2..279d12673 100644 --- a/lib/music_worker/music_worker.c +++ b/lib/music_worker/music_worker.c @@ -396,7 +396,7 @@ bool music_worker_load_rtttl_from_file(MusicWorker* instance, const char* file_p break; }; - uint16_t ret = 0; + size_t ret = 0; do { uint8_t buffer[65] = {0}; ret = storage_file_read(file, buffer, sizeof(buffer) - 1); diff --git a/lib/toolbox/crc32_calc.c b/lib/toolbox/crc32_calc.c index c0cd169b1..78295167f 100644 --- a/lib/toolbox/crc32_calc.c +++ b/lib/toolbox/crc32_calc.c @@ -14,7 +14,7 @@ uint32_t crc32_calc_file(File* file, const FileCrcProgressCb progress_cb, void* uint32_t file_crc = 0; uint8_t* data_buffer = malloc(CRC_DATA_BUFFER_MAX_LEN); - uint16_t data_buffer_valid_len; + size_t data_buffer_valid_len; uint32_t file_size = storage_file_size(file); diff --git a/lib/toolbox/md5_calc.c b/lib/toolbox/md5_calc.c index b050295a1..7f335a33f 100644 --- a/lib/toolbox/md5_calc.c +++ b/lib/toolbox/md5_calc.c @@ -5,13 +5,13 @@ bool md5_calc_file(File* file, const char* path, unsigned char output[16], FS_Er bool result = storage_file_open(file, path, FSAM_READ, FSOM_OPEN_EXISTING); if(result) { - const uint16_t size_to_read = 512; + const size_t size_to_read = 512; uint8_t* data = malloc(size_to_read); md5_context* md5_ctx = malloc(sizeof(md5_context)); md5_starts(md5_ctx); while(true) { - uint16_t read_size = storage_file_read(file, data, size_to_read); + size_t read_size = storage_file_read(file, data, size_to_read); if(read_size == 0) break; md5_update(md5_ctx, data, read_size); } diff --git a/lib/toolbox/saved_struct.c b/lib/toolbox/saved_struct.c index 02b73f210..2f1c09c8e 100644 --- a/lib/toolbox/saved_struct.c +++ b/lib/toolbox/saved_struct.c @@ -46,7 +46,7 @@ bool saved_struct_save(const char* path, void* data, size_t size, uint8_t magic, header.flags = 0; header.timestamp = 0; - uint16_t bytes_count = storage_file_write(file, &header, sizeof(header)); + size_t bytes_count = storage_file_write(file, &header, sizeof(header)); bytes_count += storage_file_write(file, data, size); if(bytes_count != (size + sizeof(header))) { @@ -79,7 +79,7 @@ bool saved_struct_load(const char* path, void* data, size_t size, uint8_t magic, } if(result) { - uint16_t bytes_count = storage_file_read(file, &header, sizeof(SavedStructHeader)); + size_t bytes_count = storage_file_read(file, &header, sizeof(SavedStructHeader)); bytes_count += storage_file_read(file, data_read, size); if(bytes_count != (sizeof(SavedStructHeader) + size)) { @@ -146,7 +146,7 @@ bool saved_struct_get_payload_size( break; } - uint16_t bytes_count = storage_file_read(file, &header, sizeof(SavedStructHeader)); + size_t bytes_count = storage_file_read(file, &header, sizeof(SavedStructHeader)); if(bytes_count != sizeof(SavedStructHeader)) { FURI_LOG_E(TAG, "Failed to read header"); break; diff --git a/lib/toolbox/stream/file_stream.c b/lib/toolbox/stream/file_stream.c index 095dce472..2b5348b3e 100644 --- a/lib/toolbox/stream/file_stream.c +++ b/lib/toolbox/stream/file_stream.c @@ -134,31 +134,11 @@ static size_t file_stream_size(FileStream* stream) { } static size_t file_stream_write(FileStream* stream, const uint8_t* data, size_t size) { - // TODO FL-3545: cache - size_t need_to_write = size; - while(need_to_write > 0) { - uint16_t was_written = - storage_file_write(stream->file, data + (size - need_to_write), need_to_write); - need_to_write -= was_written; - - if(was_written == 0) break; - } - - return size - need_to_write; + return storage_file_write(stream->file, data, size); } static size_t file_stream_read(FileStream* stream, uint8_t* data, size_t size) { - // TODO FL-3545: cache - size_t need_to_read = size; - while(need_to_read > 0) { - uint16_t was_read = - storage_file_read(stream->file, data + (size - need_to_read), need_to_read); - need_to_read -= was_read; - - if(was_read == 0) break; - } - - return size - need_to_read; + return storage_file_read(stream->file, data, size); } static bool file_stream_delete_and_insert( diff --git a/lib/update_util/dfu_file.c b/lib/update_util/dfu_file.c index eef9f0645..85b661e8e 100644 --- a/lib/update_util/dfu_file.c +++ b/lib/update_util/dfu_file.c @@ -22,7 +22,7 @@ uint8_t dfu_file_validate_headers(File* dfuf, const DfuValidationParams* referen DfuPrefix dfu_prefix = {0}; DfuSuffix dfu_suffix = {0}; - uint16_t bytes_read = 0; + size_t bytes_read = 0; if(!storage_file_is_open(dfuf) || !storage_file_seek(dfuf, 0, true)) { return 0; @@ -90,7 +90,7 @@ static DfuUpdateBlockResult dfu_file_perform_task_for_update_pages( } uint8_t* fw_block = malloc(FLASH_PAGE_SIZE); - uint16_t bytes_read = 0; + size_t bytes_read = 0; uint32_t element_offs = 0; while(element_offs < header->dwElementSize) { @@ -125,7 +125,7 @@ static DfuUpdateBlockResult dfu_file_perform_task_for_update_pages( bool dfu_file_process_targets(const DfuUpdateTask* task, File* dfuf, const uint8_t n_targets) { TargetPrefix target_prefix = {0}; ImageElementHeader image_element = {0}; - uint16_t bytes_read = 0; + size_t bytes_read = 0; if(!storage_file_seek(dfuf, sizeof(DfuPrefix), true)) { return UpdateBlockResult_Failed; diff --git a/lib/update_util/update_operation.c b/lib/update_util/update_operation.c index 0cecfc016..39a7ea075 100644 --- a/lib/update_util/update_operation.c +++ b/lib/update_util/update_operation.c @@ -85,7 +85,7 @@ bool update_operation_get_current_package_manifest_path(Storage* storage, FuriSt upd_file, UPDATE_FILE_POINTER_FN, FSAM_READ, FSOM_OPEN_EXISTING)) { break; } - uint16_t bytes_read = + size_t bytes_read = storage_file_read(upd_file, manifest_name_buffer, UPDATE_MANIFEST_MAX_PATH_LEN); if((bytes_read == 0) || (bytes_read == UPDATE_MANIFEST_MAX_PATH_LEN)) { break; diff --git a/targets/f18/api_symbols.csv b/targets/f18/api_symbols.csv index 8ed8f403c..d861d8511 100644 --- a/targets/f18/api_symbols.csv +++ b/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,45.1,, +Version,+,46.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -1376,7 +1376,7 @@ Function,+,furi_pubsub_subscribe,FuriPubSubSubscription*,"FuriPubSub*, FuriPubSu Function,+,furi_pubsub_unsubscribe,void,"FuriPubSub*, FuriPubSubSubscription*" Function,+,furi_record_close,void,const char* Function,+,furi_record_create,void,"const char*, void*" -Function,-,furi_record_destroy,_Bool,const char* +Function,+,furi_record_destroy,_Bool,const char* Function,+,furi_record_exists,_Bool,const char* Function,-,furi_record_init,void, Function,+,furi_record_open,void*,const char* @@ -2090,7 +2090,7 @@ Function,-,storage_dir_rewind,_Bool,File* Function,+,storage_error_get_desc,const char*,FS_Error Function,+,storage_file_alloc,File*,Storage* Function,+,storage_file_close,_Bool,File* -Function,+,storage_file_copy_to_file,_Bool,"File*, File*, uint32_t" +Function,+,storage_file_copy_to_file,_Bool,"File*, File*, size_t" Function,+,storage_file_eof,_Bool,File* Function,+,storage_file_exists,_Bool,"Storage*, const char*" Function,+,storage_file_free,void,File* @@ -2100,13 +2100,13 @@ Function,-,storage_file_get_internal_error,int32_t,File* Function,+,storage_file_is_dir,_Bool,File* Function,+,storage_file_is_open,_Bool,File* Function,+,storage_file_open,_Bool,"File*, const char*, FS_AccessMode, FS_OpenMode" -Function,+,storage_file_read,uint16_t,"File*, void*, uint16_t" +Function,+,storage_file_read,size_t,"File*, void*, size_t" Function,+,storage_file_seek,_Bool,"File*, uint32_t, _Bool" Function,+,storage_file_size,uint64_t,File* Function,+,storage_file_sync,_Bool,File* Function,+,storage_file_tell,uint64_t,File* Function,+,storage_file_truncate,_Bool,File* -Function,+,storage_file_write,uint16_t,"File*, const void*, uint16_t" +Function,+,storage_file_write,size_t,"File*, const void*, size_t" Function,+,storage_get_next_filename,void,"Storage*, const char*, const char*, const char*, FuriString*, uint8_t" Function,+,storage_get_pubsub,FuriPubSub*,Storage* Function,+,storage_int_backup,FS_Error,"Storage*, const char*" diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 64695c2db..c50db0c77 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,45.1,, +Version,+,46.0,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, @@ -1571,7 +1571,7 @@ Function,+,furi_pubsub_subscribe,FuriPubSubSubscription*,"FuriPubSub*, FuriPubSu Function,+,furi_pubsub_unsubscribe,void,"FuriPubSub*, FuriPubSubSubscription*" Function,+,furi_record_close,void,const char* Function,+,furi_record_create,void,"const char*, void*" -Function,-,furi_record_destroy,_Bool,const char* +Function,+,furi_record_destroy,_Bool,const char* Function,+,furi_record_exists,_Bool,const char* Function,-,furi_record_init,void, Function,+,furi_record_open,void*,const char* @@ -2717,7 +2717,7 @@ Function,-,storage_dir_rewind,_Bool,File* Function,+,storage_error_get_desc,const char*,FS_Error Function,+,storage_file_alloc,File*,Storage* Function,+,storage_file_close,_Bool,File* -Function,+,storage_file_copy_to_file,_Bool,"File*, File*, uint32_t" +Function,+,storage_file_copy_to_file,_Bool,"File*, File*, size_t" Function,+,storage_file_eof,_Bool,File* Function,+,storage_file_exists,_Bool,"Storage*, const char*" Function,+,storage_file_free,void,File* @@ -2727,13 +2727,13 @@ Function,-,storage_file_get_internal_error,int32_t,File* Function,+,storage_file_is_dir,_Bool,File* Function,+,storage_file_is_open,_Bool,File* Function,+,storage_file_open,_Bool,"File*, const char*, FS_AccessMode, FS_OpenMode" -Function,+,storage_file_read,uint16_t,"File*, void*, uint16_t" +Function,+,storage_file_read,size_t,"File*, void*, size_t" Function,+,storage_file_seek,_Bool,"File*, uint32_t, _Bool" Function,+,storage_file_size,uint64_t,File* Function,+,storage_file_sync,_Bool,File* Function,+,storage_file_tell,uint64_t,File* Function,+,storage_file_truncate,_Bool,File* -Function,+,storage_file_write,uint16_t,"File*, const void*, uint16_t" +Function,+,storage_file_write,size_t,"File*, const void*, size_t" Function,+,storage_get_next_filename,void,"Storage*, const char*, const char*, const char*, FuriString*, uint8_t" Function,+,storage_get_pubsub,FuriPubSub*,Storage* Function,+,storage_int_backup,FS_Error,"Storage*, const char*"