From ebe1a8f55f22368e7c0f5795d9045b24c300d363 Mon Sep 17 00:00:00 2001 From: Methodius Date: Sat, 16 Dec 2023 23:57:46 +0900 Subject: [PATCH 01/35] parsers cleanup for new api --- applications/main/nfc/plugins/supported_cards/kazan.c | 7 +++---- applications/main/nfc/plugins/supported_cards/metromoney.c | 5 ++--- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/applications/main/nfc/plugins/supported_cards/kazan.c b/applications/main/nfc/plugins/supported_cards/kazan.c index 18e4da1ee..e0179be5b 100644 --- a/applications/main/nfc/plugins/supported_cards/kazan.c +++ b/applications/main/nfc/plugins/supported_cards/kazan.c @@ -250,19 +250,18 @@ static bool kazan_parse(const NfcDevice* device, FuriString* parsed_data) { last_trip.day = block_start_ptr[2]; last_trip.hour = block_start_ptr[3]; last_trip.minute = block_start_ptr[4]; - bool is_last_trip_valid = (block_start_ptr[0] | block_start_ptr[1] | block_start_ptr[0]) && + bool is_last_trip_valid = (block_start_ptr[0] | block_start_ptr[1] | block_start_ptr[2]) && (last_trip.day < 32 && last_trip.month < 12 && last_trip.hour < 24 && last_trip.minute < 60); start_block_num = mf_classic_get_first_block_num_of_sector(balance_sector_number); block_start_ptr = &data->block[start_block_num].data[0]; - const uint32_t trip_counter = (block_start_ptr[3] << 24) | (block_start_ptr[2] << 16) | - (block_start_ptr[1] << 8) | (block_start_ptr[0]); + const uint32_t trip_counter = nfc_util_bytes2num_little_endian(block_start_ptr, 4); size_t uid_len = 0; const uint8_t* uid = mf_classic_get_uid(data, &uid_len); - const uint32_t card_number = (uid[3] << 24) | (uid[2] << 16) | (uid[1] << 8) | (uid[0]); + const uint32_t card_number = nfc_util_bytes2num_little_endian(uid, 4); furi_string_cat_printf( parsed_data, "\e#Kazan transport card\nCard number: %lu\n", card_number); diff --git a/applications/main/nfc/plugins/supported_cards/metromoney.c b/applications/main/nfc/plugins/supported_cards/metromoney.c index 263bbc44e..b094d055a 100644 --- a/applications/main/nfc/plugins/supported_cards/metromoney.c +++ b/applications/main/nfc/plugins/supported_cards/metromoney.c @@ -148,15 +148,14 @@ static bool metromoney_parse(const NfcDevice* device, FuriString* parsed_data) { const uint8_t* block_start_ptr = &data->block[start_block_num + ticket_block_number].data[0]; - uint32_t balance = (block_start_ptr[3] << 24) | (block_start_ptr[2] << 16) | - (block_start_ptr[1] << 8) | (block_start_ptr[0]); + uint32_t balance = nfc_util_bytes2num_little_endian(block_start_ptr, 4); uint32_t balance_lari = balance / 100; uint8_t balance_tetri = balance % 100; size_t uid_len = 0; const uint8_t* uid = mf_classic_get_uid(data, &uid_len); - uint32_t card_number = (uid[3] << 24) | (uid[2] << 16) | (uid[1] << 8) | (uid[0]); + uint32_t card_number = nfc_util_bytes2num_little_endian(uid, 4); furi_string_printf( parsed_data, From c53f5aa5b551b518c6cac2f02a1d8c38782a42f2 Mon Sep 17 00:00:00 2001 From: Methodius Date: Sun, 17 Dec 2023 04:58:07 +0900 Subject: [PATCH 02/35] Zolotaya Korona transport card parser added --- applications/main/nfc/application.fam | 9 + .../plugins/supported_cards/zolotaya_korona.c | 254 ++++++++++++++++++ 2 files changed, 263 insertions(+) create mode 100644 applications/main/nfc/plugins/supported_cards/zolotaya_korona.c diff --git a/applications/main/nfc/application.fam b/applications/main/nfc/application.fam index 4a31458d8..1b999e37e 100644 --- a/applications/main/nfc/application.fam +++ b/applications/main/nfc/application.fam @@ -137,6 +137,15 @@ App( sources=["plugins/supported_cards/mykey.c"], ) +App( + appid="zolotaya_korona_parser", + apptype=FlipperAppType.PLUGIN, + entry_point="zolotaya_korona_plugin_ep", + targets=["f7"], + requires=["nfc"], + sources=["plugins/supported_cards/zolotaya_korona.c"], +) + App( appid="nfc_start", targets=["f7"], diff --git a/applications/main/nfc/plugins/supported_cards/zolotaya_korona.c b/applications/main/nfc/plugins/supported_cards/zolotaya_korona.c new file mode 100644 index 000000000..1c48f967a --- /dev/null +++ b/applications/main/nfc/plugins/supported_cards/zolotaya_korona.c @@ -0,0 +1,254 @@ +/* + * Parser for Zolotaya Korona card (Russia). + * + * Copyright 2023 Leptoptilos + * + * More info about Zolotaya Korona cards: https://github.com/metrodroid/metrodroid/wiki/Zolotaya-Korona + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "core/core_defines.h" +#include "core/string.h" +#include "furi_hal_rtc.h" +#include "nfc_supported_card_plugin.h" + +#include "protocols/mf_classic/mf_classic.h" +#include + +#include +#include +#include +#include +#include + +#define TAG "Zolotaya Korona" + +#define TRIP_SECTOR_NUM (4) +#define PURSE_SECTOR_NUM (6) +#define INFO_SECTOR_NUM (15) + +typedef struct { + uint64_t a; + uint64_t b; +} MfClassicKeyPair; + +// Sector 15 data. Byte [11] contains the mistake. If byte [11] was 0xEF, bytes [1-18] means "ЗАО Золотая Корона" +static const uint8_t info_sector_signature[] = {0xE2, 0x87, 0x80, 0x8E, 0x20, 0x87, 0xAE, + 0xAB, 0xAE, 0xF2, 0xA0, 0xEF, 0x20, 0x8A, + 0xAE, 0xE0, 0xAE, 0xAD, 0xA0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}; + +#define FURI_HAL_RTC_SECONDS_PER_MINUTE 60 +#define FURI_HAL_RTC_SECONDS_PER_HOUR (FURI_HAL_RTC_SECONDS_PER_MINUTE * 60) +#define FURI_HAL_RTC_SECONDS_PER_DAY (FURI_HAL_RTC_SECONDS_PER_HOUR * 24) +#define FURI_HAL_RTC_EPOCH_START_YEAR 1970 + +void timestamp_to_datetime(uint32_t timestamp, FuriHalRtcDateTime* datetime) { + uint32_t days = timestamp / FURI_HAL_RTC_SECONDS_PER_DAY; + uint32_t seconds_in_day = timestamp % FURI_HAL_RTC_SECONDS_PER_DAY; + + datetime->year = FURI_HAL_RTC_EPOCH_START_YEAR; + + while(days >= furi_hal_rtc_get_days_per_year(datetime->year)) { + days -= furi_hal_rtc_get_days_per_year(datetime->year); + (datetime->year)++; + } + + datetime->month = 1; + while(days >= furi_hal_rtc_get_days_per_month( + furi_hal_rtc_is_leap_year(datetime->year), datetime->month)) { + days -= furi_hal_rtc_get_days_per_month( + furi_hal_rtc_is_leap_year(datetime->year), datetime->month); + (datetime->month)++; + } + + datetime->day = days + 1; + datetime->hour = seconds_in_day / FURI_HAL_RTC_SECONDS_PER_HOUR; + datetime->minute = + (seconds_in_day % FURI_HAL_RTC_SECONDS_PER_HOUR) / FURI_HAL_RTC_SECONDS_PER_MINUTE; + datetime->second = seconds_in_day % FURI_HAL_RTC_SECONDS_PER_MINUTE; +} + +uint64_t bytes2num_bcd(const uint8_t* src, uint8_t len_bytes) { + furi_assert(src); + + uint64_t res = 0; + + for(uint8_t i = 0; i < len_bytes; i++) { + res *= 10; + res += src[i] / 16; + res *= 10; + res += src[i] % 16; + } + + return res; +} + +static bool zolotaya_korona_parse(const NfcDevice* device, FuriString* parsed_data) { + furi_assert(device); + + const MfClassicData* data = nfc_device_get_data(device, NfcProtocolMfClassic); + + bool parsed = false; + + do { + // Verify info sector data + const uint8_t start_info_block_number = + mf_classic_get_first_block_num_of_sector(INFO_SECTOR_NUM); + const uint8_t* block_start_ptr = &data->block[start_info_block_number].data[0]; + + bool verified = true; + for(uint8_t i = 0; i < sizeof(info_sector_signature); i++) { + if(i == 16) { + block_start_ptr = &data->block[start_info_block_number + 1].data[0]; + } + if(block_start_ptr[i % 16] != info_sector_signature[i]) { + verified = false; + break; + } + } + + if(!verified) break; + + // Parse data + + // INFO SECTOR + // block 1 + const uint8_t region_number = bytes2num_bcd(block_start_ptr + 10, 1); + + // block 2 + block_start_ptr = &data->block[start_info_block_number + 2].data[4]; + const uint64_t card_number = + bytes2num_bcd(block_start_ptr, 9) * 10 + bytes2num_bcd(block_start_ptr + 9, 1) / 10; + + // TRIP SECTOR + const uint8_t start_trip_block_number = + mf_classic_get_first_block_num_of_sector(TRIP_SECTOR_NUM); + // block 0 + block_start_ptr = &data->block[start_trip_block_number].data[7]; + + const uint8_t status = block_start_ptr[0] % 16; + const uint16_t sequence_number = nfc_util_bytes2num(block_start_ptr + 1, 2); + const uint8_t discount_code = nfc_util_bytes2num(block_start_ptr + 3, 1); + + // block 1: refill block + block_start_ptr = &data->block[start_trip_block_number + 1].data[1]; + + const uint16_t refill_machine_id = nfc_util_bytes2num_little_endian(block_start_ptr, 2); + const uint32_t last_refill_timestamp = + nfc_util_bytes2num_little_endian(block_start_ptr + 2, 4); + const uint32_t last_refill_amount = + nfc_util_bytes2num_little_endian(block_start_ptr + 6, 4); + const uint32_t last_refill_amount_rub = last_refill_amount / 100; + const uint8_t last_refill_amount_kop = last_refill_amount % 100; + const uint16_t refill_counter = nfc_util_bytes2num_little_endian(block_start_ptr + 10, 2); + + FuriHalRtcDateTime last_refill_datetime = {0}; + timestamp_to_datetime(last_refill_timestamp, &last_refill_datetime); + + // block 2: trip block + block_start_ptr = &data->block[start_trip_block_number + 2].data[0]; + const char validator_first_letter = + nfc_util_bytes2num_little_endian(block_start_ptr + 1, 1); + const uint32_t validator_id = bytes2num_bcd(block_start_ptr + 2, 3); + const uint32_t last_trip_timestamp = + nfc_util_bytes2num_little_endian(block_start_ptr + 6, 4); + const uint8_t track_number = nfc_util_bytes2num_little_endian(block_start_ptr + 10, 1); + const uint32_t prev_balance = nfc_util_bytes2num_little_endian(block_start_ptr + 11, 4); + const uint32_t prev_balance_rub = prev_balance / 100; + const uint8_t prev_balance_kop = prev_balance % 100; + + FuriHalRtcDateTime last_trip_datetime = {0}; + timestamp_to_datetime(last_trip_timestamp, &last_trip_datetime); + + // PARSE DATA FROM PURSE SECTOR + const uint8_t start_purse_block_number = + mf_classic_get_first_block_num_of_sector(PURSE_SECTOR_NUM); + block_start_ptr = &data->block[start_purse_block_number].data[0]; + + // block 0 + uint32_t balance = nfc_util_bytes2num_little_endian(block_start_ptr, 4); + + uint32_t balance_rub = balance / 100; + uint8_t balance_kop = balance % 100; + + furi_string_cat_printf( + parsed_data, + "\e#Zolotaya korona\nCard number: %llu\nRegion: %u\nBalance: %lu.%02u RUR\nPrev. balance: %lu.%02u RUR", + card_number, + region_number, + balance_rub, + balance_kop, + prev_balance_rub, + prev_balance_kop); + + furi_string_cat_printf( + parsed_data, + "\nLast refill amount: %lu.%02u RUR\nRefill counter: %u\nLast refill: %u.%02u.%02u %02u:%02u\nRefill machine id: %u", + last_refill_amount_rub, + last_refill_amount_kop, + refill_counter, + last_refill_datetime.day, + last_refill_datetime.month, + last_refill_datetime.year, + last_refill_datetime.hour, + last_refill_datetime.minute, + refill_machine_id); + + furi_string_cat_printf( + parsed_data, + "\nLast trip: %u.%02u.%02u %02u:%02u\nTrack number: %u\nValidator: %c%06lu", + last_trip_datetime.day, + last_trip_datetime.month, + last_trip_datetime.year, + last_trip_datetime.hour, + last_trip_datetime.minute, + track_number, + validator_first_letter, + validator_id); + + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + furi_string_cat_printf( + parsed_data, + "\nStatus: %u\nSequence num: %u\nDiscount code: %u", + status, + sequence_number, + discount_code); + } + + parsed = true; + } while(false); + + return parsed; +} + +/* Actual implementation of app<>plugin interface */ +static const NfcSupportedCardsPlugin zolotaya_korona_plugin = { + .protocol = NfcProtocolMfClassic, + .verify = NULL, + .read = NULL, + .parse = zolotaya_korona_parse, +}; + +/* Plugin descriptor to comply with basic plugin specification */ +static const FlipperAppPluginDescriptor zolotaya_korona_plugin_descriptor = { + .appid = NFC_SUPPORTED_CARD_PLUGIN_APP_ID, + .ep_api_version = NFC_SUPPORTED_CARD_PLUGIN_API_VERSION, + .entry_point = &zolotaya_korona_plugin, +}; + +/* Plugin entry point - must return a pointer to const descriptor */ +const FlipperAppPluginDescriptor* zolotaya_korona_plugin_ep() { + return &zolotaya_korona_plugin_descriptor; +} \ No newline at end of file From 238187730c56b1dc59fd653d7984997e69508278 Mon Sep 17 00:00:00 2001 From: ushastoe Date: Mon, 18 Dec 2023 11:41:54 +0300 Subject: [PATCH 03/35] [IR] change percent on number change percent on number in ir brute --- applications/main/infrared/views/infrared_progress_view.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/applications/main/infrared/views/infrared_progress_view.c b/applications/main/infrared/views/infrared_progress_view.c index 432da7ff1..1f491e4ab 100644 --- a/applications/main/infrared/views/infrared_progress_view.c +++ b/applications/main/infrared/views/infrared_progress_view.c @@ -54,11 +54,11 @@ static void infrared_progress_view_draw_callback(Canvas* canvas, void* _model) { float progress_value = (float)model->progress / model->progress_total; elements_progress_bar(canvas, x + 4, y + 19, width - 7, progress_value); - uint8_t percent_value = 100 * model->progress / model->progress_total; - char percents_string[10] = {0}; - snprintf(percents_string, sizeof(percents_string), "%d%%", percent_value); + char number_string[10] = {0}; + snprintf( + number_string, sizeof(number_string), "%d/%d", model->progress, model->progress_total); elements_multiline_text_aligned( - canvas, x + 33, y + 37, AlignCenter, AlignCenter, percents_string); + canvas, x + 33, y + 37, AlignCenter, AlignCenter, number_string); canvas_draw_icon(canvas, x + 14, y + height - 14, &I_Pin_back_arrow_10x8); canvas_draw_str(canvas, x + 30, y + height - 6, "= stop"); From 7642d67cae89d4f9eed908ea01f514c7e52704c4 Mon Sep 17 00:00:00 2001 From: Andrea Maugeri Date: Mon, 18 Dec 2023 15:30:56 +0100 Subject: [PATCH 04/35] NfcDict Refactoring (#3271) * toolbox(keys_dict): generalize nfc_dict * nfc: rework nfc app and tests * toolbox(keys_dict): improve code readability --- applications/debug/unit_tests/nfc/nfc_test.c | 46 +-- applications/main/nfc/helpers/mf_user_dict.c | 20 +- applications/main/nfc/nfc_app_i.h | 4 +- .../scenes/nfc_scene_mf_classic_dict_attack.c | 29 +- .../nfc/scenes/nfc_scene_mf_classic_keys.c | 16 +- .../scenes/nfc_scene_mf_classic_keys_add.c | 10 +- lib/nfc/SConscript | 1 - lib/nfc/helpers/nfc_dict.c | 270 -------------- lib/nfc/helpers/nfc_dict.h | 103 ------ lib/toolbox/SConscript | 1 + lib/toolbox/keys_dict.c | 335 ++++++++++++++++++ lib/toolbox/keys_dict.h | 103 ++++++ targets/f18/api_symbols.csv | 12 +- targets/f7/api_symbols.csv | 22 +- 14 files changed, 524 insertions(+), 448 deletions(-) delete mode 100644 lib/nfc/helpers/nfc_dict.c delete mode 100644 lib/nfc/helpers/nfc_dict.h create mode 100644 lib/toolbox/keys_dict.c create mode 100644 lib/toolbox/keys_dict.h diff --git a/applications/debug/unit_tests/nfc/nfc_test.c b/applications/debug/unit_tests/nfc/nfc_test.c index 0dcd09046..29b9e80d9 100644 --- a/applications/debug/unit_tests/nfc/nfc_test.c +++ b/applications/debug/unit_tests/nfc/nfc_test.c @@ -12,7 +12,7 @@ #include #include -#include +#include #include #include "../minunit.h" @@ -443,36 +443,36 @@ MU_TEST(mf_classic_dict_test) { "Remove test dict failed"); } - NfcDict* dict = nfc_dict_alloc( - NFC_APP_MF_CLASSIC_DICT_UNIT_TEST_PATH, NfcDictModeOpenAlways, sizeof(MfClassicKey)); - mu_assert(dict != NULL, "nfc_dict_alloc() failed"); + KeysDict* dict = keys_dict_alloc( + NFC_APP_MF_CLASSIC_DICT_UNIT_TEST_PATH, KeysDictModeOpenAlways, sizeof(MfClassicKey)); + mu_assert(dict != NULL, "keys_dict_alloc() failed"); - size_t dict_keys_total = nfc_dict_get_total_keys(dict); - mu_assert(dict_keys_total == 0, "nfc_dict_keys_total() failed"); + size_t dict_keys_total = keys_dict_get_total_keys(dict); + mu_assert(dict_keys_total == 0, "keys_dict_keys_total() failed"); const uint32_t test_key_num = 30; MfClassicKey* key_arr_ref = malloc(test_key_num * sizeof(MfClassicKey)); for(size_t i = 0; i < test_key_num; i++) { furi_hal_random_fill_buf(key_arr_ref[i].data, sizeof(MfClassicKey)); mu_assert( - nfc_dict_add_key(dict, key_arr_ref[i].data, sizeof(MfClassicKey)), "add key failed"); + keys_dict_add_key(dict, key_arr_ref[i].data, sizeof(MfClassicKey)), "add key failed"); - size_t dict_keys_total = nfc_dict_get_total_keys(dict); - mu_assert(dict_keys_total == (i + 1), "nfc_dict_keys_total() failed"); + size_t dict_keys_total = keys_dict_get_total_keys(dict); + mu_assert(dict_keys_total == (i + 1), "keys_dict_keys_total() failed"); } - nfc_dict_free(dict); + keys_dict_free(dict); - dict = nfc_dict_alloc( - NFC_APP_MF_CLASSIC_DICT_UNIT_TEST_PATH, NfcDictModeOpenAlways, sizeof(MfClassicKey)); - mu_assert(dict != NULL, "nfc_dict_alloc() failed"); + dict = keys_dict_alloc( + NFC_APP_MF_CLASSIC_DICT_UNIT_TEST_PATH, KeysDictModeOpenAlways, sizeof(MfClassicKey)); + mu_assert(dict != NULL, "keys_dict_alloc() failed"); - dict_keys_total = nfc_dict_get_total_keys(dict); - mu_assert(dict_keys_total == test_key_num, "nfc_dict_keys_total() failed"); + dict_keys_total = keys_dict_get_total_keys(dict); + mu_assert(dict_keys_total == test_key_num, "keys_dict_keys_total() failed"); MfClassicKey key_dut = {}; size_t key_idx = 0; - while(nfc_dict_get_next_key(dict, key_dut.data, sizeof(MfClassicKey))) { + while(keys_dict_get_next_key(dict, key_dut.data, sizeof(MfClassicKey))) { mu_assert( memcmp(key_arr_ref[key_idx].data, key_dut.data, sizeof(MfClassicKey)) == 0, "Loaded key data mismatch"); @@ -484,19 +484,19 @@ MU_TEST(mf_classic_dict_test) { for(size_t i = 0; i < COUNT_OF(delete_keys_idx); i++) { MfClassicKey* key = &key_arr_ref[delete_keys_idx[i]]; mu_assert( - nfc_dict_is_key_present(dict, key->data, sizeof(MfClassicKey)), - "nfc_dict_is_key_present() failed"); + keys_dict_is_key_present(dict, key->data, sizeof(MfClassicKey)), + "keys_dict_is_key_present() failed"); mu_assert( - nfc_dict_delete_key(dict, key->data, sizeof(MfClassicKey)), - "nfc_dict_delete_key() failed"); + keys_dict_delete_key(dict, key->data, sizeof(MfClassicKey)), + "keys_dict_delete_key() failed"); } - dict_keys_total = nfc_dict_get_total_keys(dict); + dict_keys_total = keys_dict_get_total_keys(dict); mu_assert( dict_keys_total == test_key_num - COUNT_OF(delete_keys_idx), - "nfc_dict_keys_total() failed"); + "keys_dict_keys_total() failed"); - nfc_dict_free(dict); + keys_dict_free(dict); free(key_arr_ref); mu_assert( diff --git a/applications/main/nfc/helpers/mf_user_dict.c b/applications/main/nfc/helpers/mf_user_dict.c index 09f0c1506..1a019cf59 100644 --- a/applications/main/nfc/helpers/mf_user_dict.c +++ b/applications/main/nfc/helpers/mf_user_dict.c @@ -1,6 +1,6 @@ #include "mf_user_dict.h" -#include +#include #include #include @@ -15,22 +15,22 @@ struct MfUserDict { MfUserDict* mf_user_dict_alloc(size_t max_keys_to_load) { MfUserDict* instance = malloc(sizeof(MfUserDict)); - NfcDict* dict = nfc_dict_alloc( - NFC_APP_MF_CLASSIC_DICT_USER_PATH, NfcDictModeOpenAlways, sizeof(MfClassicKey)); + KeysDict* dict = keys_dict_alloc( + NFC_APP_MF_CLASSIC_DICT_USER_PATH, KeysDictModeOpenAlways, sizeof(MfClassicKey)); furi_assert(dict); - size_t dict_keys_num = nfc_dict_get_total_keys(dict); + size_t dict_keys_num = keys_dict_get_total_keys(dict); instance->keys_num = MIN(max_keys_to_load, dict_keys_num); if(instance->keys_num > 0) { instance->keys_arr = malloc(instance->keys_num * sizeof(MfClassicKey)); for(size_t i = 0; i < instance->keys_num; i++) { bool key_loaded = - nfc_dict_get_next_key(dict, instance->keys_arr[i].data, sizeof(MfClassicKey)); + keys_dict_get_next_key(dict, instance->keys_arr[i].data, sizeof(MfClassicKey)); furi_assert(key_loaded); } } - nfc_dict_free(dict); + keys_dict_free(dict); return instance; } @@ -67,13 +67,13 @@ bool mf_user_dict_delete_key(MfUserDict* instance, uint32_t index) { furi_assert(index < instance->keys_num); furi_assert(instance->keys_arr); - NfcDict* dict = nfc_dict_alloc( - NFC_APP_MF_CLASSIC_DICT_USER_PATH, NfcDictModeOpenAlways, sizeof(MfClassicKey)); + KeysDict* dict = keys_dict_alloc( + NFC_APP_MF_CLASSIC_DICT_USER_PATH, KeysDictModeOpenAlways, sizeof(MfClassicKey)); furi_assert(dict); bool key_delete_success = - nfc_dict_delete_key(dict, instance->keys_arr[index].data, sizeof(MfClassicKey)); - nfc_dict_free(dict); + keys_dict_delete_key(dict, instance->keys_arr[index].data, sizeof(MfClassicKey)); + keys_dict_free(dict); if(key_delete_success) { instance->keys_num--; diff --git a/applications/main/nfc/nfc_app_i.h b/applications/main/nfc/nfc_app_i.h index bde87b12b..943d722f8 100644 --- a/applications/main/nfc/nfc_app_i.h +++ b/applications/main/nfc/nfc_app_i.h @@ -52,7 +52,7 @@ #include #include -#include +#include #include #include @@ -80,7 +80,7 @@ typedef enum { } NfcRpcState; typedef struct { - NfcDict* dict; + KeysDict* dict; uint8_t sectors_total; uint8_t sectors_read; uint8_t current_sector; diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c index ff7af9e1e..b6ba1c119 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_dict_attack.c @@ -41,7 +41,8 @@ NfcCommand nfc_dict_attack_worker_callback(NfcGenericEvent event, void* context) instance->view_dispatcher, NfcCustomEventDictAttackDataUpdate); } else if(mfc_event->type == MfClassicPollerEventTypeRequestKey) { MfClassicKey key = {}; - if(nfc_dict_get_next_key(instance->nfc_dict_context.dict, key.data, sizeof(MfClassicKey))) { + if(keys_dict_get_next_key( + instance->nfc_dict_context.dict, key.data, sizeof(MfClassicKey))) { mfc_event->data->key_request_data.key = key; mfc_event->data->key_request_data.key_provided = true; instance->nfc_dict_context.dict_keys_current++; @@ -60,7 +61,7 @@ NfcCommand nfc_dict_attack_worker_callback(NfcGenericEvent event, void* context) view_dispatcher_send_custom_event( instance->view_dispatcher, NfcCustomEventDictAttackDataUpdate); } else if(mfc_event->type == MfClassicPollerEventTypeNextSector) { - nfc_dict_rewind(instance->nfc_dict_context.dict); + keys_dict_rewind(instance->nfc_dict_context.dict); instance->nfc_dict_context.dict_keys_current = 0; instance->nfc_dict_context.current_sector = mfc_event->data->next_sector_data.current_sector; @@ -79,7 +80,7 @@ NfcCommand nfc_dict_attack_worker_callback(NfcGenericEvent event, void* context) view_dispatcher_send_custom_event( instance->view_dispatcher, NfcCustomEventDictAttackDataUpdate); } else if(mfc_event->type == MfClassicPollerEventTypeKeyAttackStop) { - nfc_dict_rewind(instance->nfc_dict_context.dict); + keys_dict_rewind(instance->nfc_dict_context.dict); instance->nfc_dict_context.is_key_attack = false; instance->nfc_dict_context.dict_keys_current = 0; view_dispatcher_send_custom_event( @@ -124,15 +125,15 @@ static void nfc_scene_mf_classic_dict_attack_prepare_view(NfcApp* instance) { scene_manager_get_scene_state(instance->scene_manager, NfcSceneMfClassicDictAttack); if(state == DictAttackStateUserDictInProgress) { do { - if(!nfc_dict_check_presence(NFC_APP_MF_CLASSIC_DICT_USER_PATH)) { + if(!keys_dict_check_presence(NFC_APP_MF_CLASSIC_DICT_USER_PATH)) { state = DictAttackStateSystemDictInProgress; break; } - instance->nfc_dict_context.dict = nfc_dict_alloc( - NFC_APP_MF_CLASSIC_DICT_USER_PATH, NfcDictModeOpenAlways, sizeof(MfClassicKey)); - if(nfc_dict_get_total_keys(instance->nfc_dict_context.dict) == 0) { - nfc_dict_free(instance->nfc_dict_context.dict); + instance->nfc_dict_context.dict = keys_dict_alloc( + NFC_APP_MF_CLASSIC_DICT_USER_PATH, KeysDictModeOpenAlways, sizeof(MfClassicKey)); + if(keys_dict_get_total_keys(instance->nfc_dict_context.dict) == 0) { + keys_dict_free(instance->nfc_dict_context.dict); state = DictAttackStateSystemDictInProgress; break; } @@ -141,13 +142,13 @@ static void nfc_scene_mf_classic_dict_attack_prepare_view(NfcApp* instance) { } while(false); } if(state == DictAttackStateSystemDictInProgress) { - instance->nfc_dict_context.dict = nfc_dict_alloc( - NFC_APP_MF_CLASSIC_DICT_SYSTEM_PATH, NfcDictModeOpenExisting, sizeof(MfClassicKey)); + instance->nfc_dict_context.dict = keys_dict_alloc( + NFC_APP_MF_CLASSIC_DICT_SYSTEM_PATH, KeysDictModeOpenExisting, sizeof(MfClassicKey)); dict_attack_set_header(instance->dict_attack, "MF Classic System Dictionary"); } instance->nfc_dict_context.dict_keys_total = - nfc_dict_get_total_keys(instance->nfc_dict_context.dict); + keys_dict_get_total_keys(instance->nfc_dict_context.dict); dict_attack_set_total_dict_keys( instance->dict_attack, instance->nfc_dict_context.dict_keys_total); instance->nfc_dict_context.dict_keys_current = 0; @@ -185,7 +186,7 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent if(state == DictAttackStateUserDictInProgress) { nfc_poller_stop(instance->poller); nfc_poller_free(instance->poller); - nfc_dict_free(instance->nfc_dict_context.dict); + keys_dict_free(instance->nfc_dict_context.dict); scene_manager_set_scene_state( instance->scene_manager, NfcSceneMfClassicDictAttack, @@ -215,7 +216,7 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent if(instance->nfc_dict_context.is_card_present) { nfc_poller_stop(instance->poller); nfc_poller_free(instance->poller); - nfc_dict_free(instance->nfc_dict_context.dict); + keys_dict_free(instance->nfc_dict_context.dict); scene_manager_set_scene_state( instance->scene_manager, NfcSceneMfClassicDictAttack, @@ -253,7 +254,7 @@ void nfc_scene_mf_classic_dict_attack_on_exit(void* context) { scene_manager_set_scene_state( instance->scene_manager, NfcSceneMfClassicDictAttack, DictAttackStateUserDictInProgress); - nfc_dict_free(instance->nfc_dict_context.dict); + keys_dict_free(instance->nfc_dict_context.dict); instance->nfc_dict_context.current_sector = 0; instance->nfc_dict_context.sectors_total = 0; diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_keys.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys.c index 3106c740a..44f9963af 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_keys.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys.c @@ -14,20 +14,20 @@ void nfc_scene_mf_classic_keys_on_enter(void* context) { // Load flipper dict keys total uint32_t flipper_dict_keys_total = 0; - NfcDict* dict = nfc_dict_alloc( - NFC_APP_MF_CLASSIC_DICT_SYSTEM_PATH, NfcDictModeOpenExisting, sizeof(MfClassicKey)); + KeysDict* dict = keys_dict_alloc( + NFC_APP_MF_CLASSIC_DICT_SYSTEM_PATH, KeysDictModeOpenExisting, sizeof(MfClassicKey)); if(dict) { - flipper_dict_keys_total = nfc_dict_get_total_keys(dict); - nfc_dict_free(dict); + flipper_dict_keys_total = keys_dict_get_total_keys(dict); + keys_dict_free(dict); } // Load user dict keys total uint32_t user_dict_keys_total = 0; - dict = nfc_dict_alloc( - NFC_APP_MF_CLASSIC_DICT_USER_PATH, NfcDictModeOpenAlways, sizeof(MfClassicKey)); + dict = keys_dict_alloc( + NFC_APP_MF_CLASSIC_DICT_USER_PATH, KeysDictModeOpenAlways, sizeof(MfClassicKey)); if(dict) { - user_dict_keys_total = nfc_dict_get_total_keys(dict); - nfc_dict_free(dict); + user_dict_keys_total = keys_dict_get_total_keys(dict); + keys_dict_free(dict); } FuriString* temp_str = furi_string_alloc(); diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_add.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_add.c index 824000343..4111cca81 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_add.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_keys_add.c @@ -29,23 +29,23 @@ bool nfc_scene_mf_classic_keys_add_on_event(void* context, SceneManagerEvent eve if(event.type == SceneManagerEventTypeCustom) { if(event.event == NfcCustomEventByteInputDone) { // Add key to dict - NfcDict* dict = nfc_dict_alloc( - NFC_APP_MF_CLASSIC_DICT_USER_PATH, NfcDictModeOpenAlways, sizeof(MfClassicKey)); + KeysDict* dict = keys_dict_alloc( + NFC_APP_MF_CLASSIC_DICT_USER_PATH, KeysDictModeOpenAlways, sizeof(MfClassicKey)); furi_assert(dict); MfClassicKey key = {}; memcpy(key.data, instance->byte_input_store, sizeof(MfClassicKey)); - if(nfc_dict_is_key_present(dict, key.data, sizeof(MfClassicKey))) { + if(keys_dict_is_key_present(dict, key.data, sizeof(MfClassicKey))) { scene_manager_next_scene( instance->scene_manager, NfcSceneMfClassicKeysWarnDuplicate); - } else if(nfc_dict_add_key(dict, key.data, sizeof(MfClassicKey))) { + } else if(keys_dict_add_key(dict, key.data, sizeof(MfClassicKey))) { scene_manager_next_scene(instance->scene_manager, NfcSceneSaveSuccess); dolphin_deed(DolphinDeedNfcMfcAdd); } else { scene_manager_previous_scene(instance->scene_manager); } - nfc_dict_free(dict); + keys_dict_free(dict); consumed = true; } } diff --git a/lib/nfc/SConscript b/lib/nfc/SConscript index d2cfbe2fb..41332362c 100644 --- a/lib/nfc/SConscript +++ b/lib/nfc/SConscript @@ -48,7 +48,6 @@ env.Append( File("helpers/iso14443_crc.h"), File("helpers/iso13239_crc.h"), File("helpers/nfc_data_generator.h"), - File("helpers/nfc_dict.h"), ], ) diff --git a/lib/nfc/helpers/nfc_dict.c b/lib/nfc/helpers/nfc_dict.c deleted file mode 100644 index d4572a3d6..000000000 --- a/lib/nfc/helpers/nfc_dict.c +++ /dev/null @@ -1,270 +0,0 @@ -#include "nfc_dict.h" - -#include -#include -#include -#include -#include - -#include - -#define TAG "NfcDict" - -struct NfcDict { - Stream* stream; - size_t key_size; - size_t key_size_symbols; - uint32_t total_keys; -}; - -typedef struct { - const char* path; - FS_OpenMode open_mode; -} NfcDictFile; - -bool nfc_dict_check_presence(const char* path) { - furi_assert(path); - - Storage* storage = furi_record_open(RECORD_STORAGE); - - bool dict_present = storage_common_stat(storage, path, NULL) == FSE_OK; - - furi_record_close(RECORD_STORAGE); - - return dict_present; -} - -NfcDict* nfc_dict_alloc(const char* path, NfcDictMode mode, size_t key_size) { - furi_assert(path); - - NfcDict* instance = malloc(sizeof(NfcDict)); - Storage* storage = furi_record_open(RECORD_STORAGE); - instance->stream = buffered_file_stream_alloc(storage); - furi_record_close(RECORD_STORAGE); - - FS_OpenMode open_mode = FSOM_OPEN_EXISTING; - if(mode == NfcDictModeOpenAlways) { - open_mode = FSOM_OPEN_ALWAYS; - } - instance->key_size = key_size; - // Byte = 2 symbols + 1 end of line - instance->key_size_symbols = key_size * 2 + 1; - - bool dict_loaded = false; - do { - if(!buffered_file_stream_open(instance->stream, path, FSAM_READ_WRITE, open_mode)) { - buffered_file_stream_close(instance->stream); - break; - } - - // Check for new line ending - if(!stream_eof(instance->stream)) { - if(!stream_seek(instance->stream, -1, StreamOffsetFromEnd)) break; - uint8_t last_char = 0; - if(stream_read(instance->stream, &last_char, 1) != 1) break; - if(last_char != '\n') { - FURI_LOG_D(TAG, "Adding new line ending"); - if(stream_write_char(instance->stream, '\n') != 1) break; - } - if(!stream_rewind(instance->stream)) break; - } - - // Read total amount of keys - FuriString* next_line; - next_line = furi_string_alloc(); - while(true) { - if(!stream_read_line(instance->stream, next_line)) { - FURI_LOG_T(TAG, "No keys left in dict"); - break; - } - FURI_LOG_T( - TAG, - "Read line: %s, len: %zu", - furi_string_get_cstr(next_line), - furi_string_size(next_line)); - if(furi_string_get_char(next_line, 0) == '#') continue; - if(furi_string_size(next_line) != instance->key_size_symbols) continue; - instance->total_keys++; - } - furi_string_free(next_line); - stream_rewind(instance->stream); - - dict_loaded = true; - FURI_LOG_I(TAG, "Loaded dictionary with %lu keys", instance->total_keys); - } while(false); - - if(!dict_loaded) { - buffered_file_stream_close(instance->stream); - free(instance); - instance = NULL; - } - - return instance; -} - -void nfc_dict_free(NfcDict* instance) { - furi_assert(instance); - furi_assert(instance->stream); - - buffered_file_stream_close(instance->stream); - stream_free(instance->stream); - free(instance); -} - -static void nfc_dict_int_to_str(NfcDict* instance, const uint8_t* key_int, FuriString* key_str) { - furi_string_reset(key_str); - for(size_t i = 0; i < instance->key_size; i++) { - furi_string_cat_printf(key_str, "%02X", key_int[i]); - } -} - -static void nfc_dict_str_to_int(NfcDict* instance, FuriString* key_str, uint64_t* key_int) { - uint8_t key_byte_tmp; - - *key_int = 0ULL; - for(uint8_t i = 0; i < instance->key_size * 2; i += 2) { - args_char_to_hex( - furi_string_get_char(key_str, i), furi_string_get_char(key_str, i + 1), &key_byte_tmp); - *key_int |= (uint64_t)key_byte_tmp << (8 * (instance->key_size - 1 - i / 2)); - } -} - -uint32_t nfc_dict_get_total_keys(NfcDict* instance) { - furi_assert(instance); - - return instance->total_keys; -} - -bool nfc_dict_rewind(NfcDict* instance) { - furi_assert(instance); - furi_assert(instance->stream); - - return stream_rewind(instance->stream); -} - -static bool nfc_dict_get_next_key_str(NfcDict* instance, FuriString* key) { - furi_assert(instance); - furi_assert(instance->stream); - - bool key_read = false; - furi_string_reset(key); - while(!key_read) { - if(!stream_read_line(instance->stream, key)) break; - if(furi_string_get_char(key, 0) == '#') continue; - if(furi_string_size(key) != instance->key_size_symbols) continue; - furi_string_left(key, instance->key_size_symbols - 1); - key_read = true; - } - - return key_read; -} - -bool nfc_dict_get_next_key(NfcDict* instance, uint8_t* key, size_t key_size) { - furi_assert(instance); - furi_assert(instance->stream); - furi_assert(instance->key_size == key_size); - - FuriString* temp_key = furi_string_alloc(); - uint64_t key_int = 0; - bool key_read = nfc_dict_get_next_key_str(instance, temp_key); - if(key_read) { - nfc_dict_str_to_int(instance, temp_key, &key_int); - nfc_util_num2bytes(key_int, key_size, key); - } - furi_string_free(temp_key); - return key_read; -} - -static bool nfc_dict_is_key_present_str(NfcDict* instance, FuriString* key) { - furi_assert(instance); - furi_assert(instance->stream); - - FuriString* next_line; - next_line = furi_string_alloc(); - - bool key_found = false; - stream_rewind(instance->stream); - while(!key_found) { //-V654 - if(!stream_read_line(instance->stream, next_line)) break; - if(furi_string_get_char(next_line, 0) == '#') continue; - if(furi_string_size(next_line) != instance->key_size_symbols) continue; - furi_string_left(next_line, instance->key_size_symbols - 1); - if(!furi_string_equal(key, next_line)) continue; - key_found = true; - } - - furi_string_free(next_line); - return key_found; -} - -bool nfc_dict_is_key_present(NfcDict* instance, const uint8_t* key, size_t key_size) { - furi_assert(instance); - furi_assert(key); - furi_assert(instance->stream); - furi_assert(instance->key_size == key_size); - - FuriString* temp_key = furi_string_alloc(); - nfc_dict_int_to_str(instance, key, temp_key); - bool key_found = nfc_dict_is_key_present_str(instance, temp_key); - furi_string_free(temp_key); - - return key_found; -} - -static bool nfc_dict_add_key_str(NfcDict* instance, FuriString* key) { - furi_assert(instance); - furi_assert(instance->stream); - - furi_string_cat_printf(key, "\n"); - - bool key_added = false; - do { - if(!stream_seek(instance->stream, 0, StreamOffsetFromEnd)) break; - if(!stream_insert_string(instance->stream, key)) break; - instance->total_keys++; - key_added = true; - } while(false); - - furi_string_left(key, instance->key_size_symbols - 1); - return key_added; -} - -bool nfc_dict_add_key(NfcDict* instance, const uint8_t* key, size_t key_size) { - furi_assert(instance); - furi_assert(key); - furi_assert(instance->stream); - furi_assert(instance->key_size == key_size); - - FuriString* temp_key = furi_string_alloc(); - nfc_dict_int_to_str(instance, key, temp_key); - bool key_added = nfc_dict_add_key_str(instance, temp_key); - furi_string_free(temp_key); - - return key_added; -} - -bool nfc_dict_delete_key(NfcDict* instance, const uint8_t* key, size_t key_size) { - furi_assert(instance); - furi_assert(instance->stream); - furi_assert(key); - furi_assert(instance->key_size == key_size); - - bool key_removed = false; - uint8_t* temp_key = malloc(key_size); - - nfc_dict_rewind(instance); - while(!key_removed) { - if(!nfc_dict_get_next_key(instance, temp_key, key_size)) break; - if(memcmp(temp_key, key, key_size) == 0) { - int32_t offset = (-1) * (instance->key_size_symbols); - stream_seek(instance->stream, offset, StreamOffsetFromCurrent); - if(!stream_delete(instance->stream, instance->key_size_symbols)) break; - instance->total_keys--; - key_removed = true; - } - } - nfc_dict_rewind(instance); - free(temp_key); - - return key_removed; -} diff --git a/lib/nfc/helpers/nfc_dict.h b/lib/nfc/helpers/nfc_dict.h deleted file mode 100644 index 80f3ff680..000000000 --- a/lib/nfc/helpers/nfc_dict.h +++ /dev/null @@ -1,103 +0,0 @@ -#pragma once - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum { - NfcDictModeOpenExisting, - NfcDictModeOpenAlways, -} NfcDictMode; - -typedef struct NfcDict NfcDict; - -/** Check dictionary presence - * - * @param path - dictionary path - * - * @return true if dictionary exists, false otherwise -*/ -bool nfc_dict_check_presence(const char* path); - -/** Open or create dictionary - * Depending on mode, dictionary will be opened or created. - * - * @param path - dictionary path - * @param mode - NfcDictMode value - * @param key_size - size of dictionary keys in bytes - * - * @return NfcDict dictionary instance -*/ -NfcDict* nfc_dict_alloc(const char* path, NfcDictMode mode, size_t key_size); - -/** Close dictionary - * - * @param instance - NfcDict dictionary instance -*/ -void nfc_dict_free(NfcDict* instance); - -/** Get total number of keys in dictionary - * - * @param instance - NfcDict dictionary instance - * - * @return total number of keys in dictionary -*/ -uint32_t nfc_dict_get_total_keys(NfcDict* instance); - -/** Rewind dictionary - * - * @param instance - NfcDict dictionary instance - * - * @return true if rewind was successful, false otherwise -*/ -bool nfc_dict_rewind(NfcDict* instance); - -/** Check if key is present in dictionary - * - * @param instance - NfcDict dictionary instance - * @param key - key to check - * @param key_size - size of key in bytes - * - * @return true if key is present, false otherwise -*/ -bool nfc_dict_is_key_present(NfcDict* instance, const uint8_t* key, size_t key_size); - -/** Get next key from dictionary - * This function will return next key from dictionary. If there are no more - * keys, it will return false, and nfc_dict_rewind() should be called. - * - * @param instance - NfcDict dictionary instance - * @param key - buffer to store key - * @param key_size - size of key in bytes - * - * @return true if key was successfully retrieved, false otherwise -*/ -bool nfc_dict_get_next_key(NfcDict* instance, uint8_t* key, size_t key_size); - -/** Add key to dictionary - * - * @param instance - NfcDict dictionary instance - * @param key - key to add - * @param key_size - size of key in bytes - * - * @return true if key was successfully added, false otherwise -*/ -bool nfc_dict_add_key(NfcDict* instance, const uint8_t* key, size_t key_size); - -/** Delete key from dictionary - * - * @param instance - NfcDict dictionary instance - * @param key - key to delete - * @param key_size - size of key in bytes - * - * @return true if key was successfully deleted, false otherwise -*/ -bool nfc_dict_delete_key(NfcDict* instance, const uint8_t* key, size_t key_size); - -#ifdef __cplusplus -} -#endif diff --git a/lib/toolbox/SConscript b/lib/toolbox/SConscript index 14f8de064..121362424 100644 --- a/lib/toolbox/SConscript +++ b/lib/toolbox/SConscript @@ -34,6 +34,7 @@ env.Append( File("hex.h"), File("simple_array.h"), File("bit_buffer.h"), + File("keys_dict.h"), ], ) diff --git a/lib/toolbox/keys_dict.c b/lib/toolbox/keys_dict.c new file mode 100644 index 000000000..30580bf5e --- /dev/null +++ b/lib/toolbox/keys_dict.c @@ -0,0 +1,335 @@ +#include "keys_dict.h" + +#include +#include +#include +#include +#include + +#define TAG "KeysDict" + +struct KeysDict { + Stream* stream; + size_t key_size; + size_t key_size_symbols; + size_t total_keys; +}; + +static inline void keys_dict_add_ending_new_line(KeysDict* instance) { + if(stream_seek(instance->stream, -1, StreamOffsetFromEnd)) { + uint8_t last_char = 0; + + // Check if the last char is new line or add a new line + if(stream_read(instance->stream, &last_char, 1) == 1 && last_char != '\n') { + FURI_LOG_D(TAG, "Adding new line ending"); + stream_write_char(instance->stream, '\n'); + } + + stream_rewind(instance->stream); + } +} + +static bool keys_dict_read_key_line(KeysDict* instance, FuriString* line, bool* is_endfile) { + if(stream_read_line(instance->stream, line) == false) { + *is_endfile = true; + } + + else { + FURI_LOG_T( + TAG, "Read line: %s, len: %zu", furi_string_get_cstr(line), furi_string_size(line)); + + bool is_comment = furi_string_get_char(line, 0) == '#'; + + if(!is_comment) { + furi_string_left(line, instance->key_size_symbols - 1); + } + + bool is_correct_size = furi_string_size(line) == instance->key_size_symbols - 1; + + return !is_comment && is_correct_size; + } + + return false; +} + +bool keys_dict_check_presence(const char* path) { + furi_assert(path); + + Storage* storage = furi_record_open(RECORD_STORAGE); + + bool dict_present = storage_common_stat(storage, path, NULL) == FSE_OK; + + furi_record_close(RECORD_STORAGE); + + return dict_present; +} + +KeysDict* keys_dict_alloc(const char* path, KeysDictMode mode, size_t key_size) { + furi_assert(path); + furi_assert(key_size > 0); + + KeysDict* instance = malloc(sizeof(KeysDict)); + + Storage* storage = furi_record_open(RECORD_STORAGE); + furi_assert(storage); + + instance->stream = buffered_file_stream_alloc(storage); + furi_assert(instance->stream); + + FS_OpenMode open_mode = (mode == KeysDictModeOpenAlways) ? FSOM_OPEN_ALWAYS : + FSOM_OPEN_EXISTING; + + // Byte = 2 symbols + 1 end of line + instance->key_size = key_size; + instance->key_size_symbols = key_size * 2 + 1; + + instance->total_keys = 0; + + bool file_exists = + buffered_file_stream_open(instance->stream, path, FSAM_READ_WRITE, open_mode); + + if(!file_exists) { + buffered_file_stream_close(instance->stream); + } else { + // Eventually add new line character in the last line to avoid skipping keys + keys_dict_add_ending_new_line(instance); + } + + FuriString* line = furi_string_alloc(); + + bool is_endfile = false; + + // In this loop we only count the entries in the file + // We prefer not to load the whole file in memory for space reasons + while(file_exists && !is_endfile) { + bool read_key = keys_dict_read_key_line(instance, line, &is_endfile); + if(read_key) { + instance->total_keys++; + } + } + stream_rewind(instance->stream); + FURI_LOG_I(TAG, "Loaded dictionary with %u keys", instance->total_keys); + + furi_string_free(line); + + return instance; +} + +void keys_dict_free(KeysDict* instance) { + furi_assert(instance); + furi_assert(instance->stream); + + buffered_file_stream_close(instance->stream); + stream_free(instance->stream); + free(instance); + + furi_record_close(RECORD_STORAGE); +} + +static void keys_dict_int_to_str(KeysDict* instance, const uint8_t* key_int, FuriString* key_str) { + furi_assert(instance); + furi_assert(key_str); + furi_assert(key_int); + + furi_string_reset(key_str); + + for(size_t i = 0; i < instance->key_size; i++) + furi_string_cat_printf(key_str, "%02X", key_int[i]); +} + +static void keys_dict_str_to_int(KeysDict* instance, FuriString* key_str, uint64_t* key_int) { + furi_assert(instance); + furi_assert(key_str); + furi_assert(key_int); + + uint8_t key_byte_tmp; + char h, l; + + *key_int = 0ULL; + + for(size_t i = 0; i < instance->key_size_symbols - 1; i += 2) { + h = furi_string_get_char(key_str, i); + l = furi_string_get_char(key_str, i + 1); + + args_char_to_hex(h, l, &key_byte_tmp); + *key_int |= (uint64_t)key_byte_tmp << (8 * (instance->key_size - 1 - i / 2)); + } +} + +size_t keys_dict_get_total_keys(KeysDict* instance) { + furi_assert(instance); + + return instance->total_keys; +} + +bool keys_dict_rewind(KeysDict* instance) { + furi_assert(instance); + furi_assert(instance->stream); + + return stream_rewind(instance->stream); +} + +static bool keys_dict_get_next_key_str(KeysDict* instance, FuriString* key) { + furi_assert(instance); + furi_assert(instance->stream); + furi_assert(key); + + bool key_read = false; + bool is_endfile = false; + + furi_string_reset(key); + + while(!key_read && !is_endfile) key_read = keys_dict_read_key_line(instance, key, &is_endfile); + + return key_read; +} + +bool keys_dict_get_next_key(KeysDict* instance, uint8_t* key, size_t key_size) { + furi_assert(instance); + furi_assert(instance->stream); + furi_assert(instance->key_size == key_size); + furi_assert(key); + + FuriString* temp_key = furi_string_alloc(); + + bool key_read = keys_dict_get_next_key_str(instance, temp_key); + + if(key_read) { + size_t tmp_len = key_size; + uint64_t key_int = 0; + + keys_dict_str_to_int(instance, temp_key, &key_int); + + while(tmp_len--) { + key[tmp_len] = (uint8_t)key_int; + key_int >>= 8; + } + } + + furi_string_free(temp_key); + return key_read; +} + +static bool keys_dict_is_key_present_str(KeysDict* instance, FuriString* key) { + furi_assert(instance); + furi_assert(instance->stream); + furi_assert(key); + + FuriString* line = furi_string_alloc(); + + bool is_endfile = false; + bool line_found = false; + + uint32_t actual_pos = stream_tell(instance->stream); + stream_rewind(instance->stream); + + while(!line_found && !is_endfile) + line_found = // The line is found if the line was read and the key is equal to the line + (keys_dict_read_key_line(instance, line, &is_endfile)) && + (furi_string_equal(key, line)); + + furi_string_free(line); + + // Restore the position of the stream + stream_seek(instance->stream, actual_pos, StreamOffsetFromStart); + + return line_found; +} + +bool keys_dict_is_key_present(KeysDict* instance, const uint8_t* key, size_t key_size) { + furi_assert(instance); + furi_assert(instance->stream); + furi_assert(instance->key_size == key_size); + furi_assert(key); + + FuriString* temp_key = furi_string_alloc(); + + keys_dict_int_to_str(instance, key, temp_key); + bool key_found = keys_dict_is_key_present_str(instance, temp_key); + furi_string_free(temp_key); + + return key_found; +} + +static bool keys_dict_add_key_str(KeysDict* instance, FuriString* key) { + furi_assert(instance); + furi_assert(instance->stream); + furi_assert(key); + + furi_string_cat_str(key, "\n"); + + bool key_added = false; + + uint32_t actual_pos = stream_tell(instance->stream); + + if(stream_seek(instance->stream, 0, StreamOffsetFromEnd) && + stream_insert_string(instance->stream, key)) { + instance->total_keys++; + key_added = true; + } + + stream_seek(instance->stream, actual_pos, StreamOffsetFromStart); + + return key_added; +} + +bool keys_dict_add_key(KeysDict* instance, const uint8_t* key, size_t key_size) { + furi_assert(instance); + furi_assert(instance->stream); + furi_assert(instance->key_size == key_size); + furi_assert(key); + + FuriString* temp_key = furi_string_alloc(); + furi_assert(temp_key); + + keys_dict_int_to_str(instance, key, temp_key); + bool key_added = keys_dict_add_key_str(instance, temp_key); + + FURI_LOG_I(TAG, "Added key %s", furi_string_get_cstr(temp_key)); + + furi_string_free(temp_key); + + return key_added; +} + +bool keys_dict_delete_key(KeysDict* instance, const uint8_t* key, size_t key_size) { + furi_assert(instance); + furi_assert(instance->stream); + furi_assert(instance->key_size == key_size); + furi_assert(key); + + bool key_removed = false; + bool is_endfile = false; + + uint8_t* temp_key = malloc(key_size); + + stream_rewind(instance->stream); + + while(!key_removed && !is_endfile) { + if(!keys_dict_get_next_key(instance, temp_key, key_size)) { + break; + } + + if(memcmp(temp_key, key, key_size) == 0) { + stream_seek(instance->stream, -instance->key_size_symbols, StreamOffsetFromCurrent); + if(stream_delete(instance->stream, instance->key_size_symbols) == false) { + break; + } + instance->total_keys--; + key_removed = true; + } + } + + FuriString* tmp = furi_string_alloc(); + + keys_dict_int_to_str(instance, key, tmp); + + FURI_LOG_I(TAG, "Removed key %s", furi_string_get_cstr(tmp)); + + furi_string_free(tmp); + + stream_rewind(instance->stream); + free(temp_key); + + return key_removed; +} \ No newline at end of file diff --git a/lib/toolbox/keys_dict.h b/lib/toolbox/keys_dict.h new file mode 100644 index 000000000..df6f49344 --- /dev/null +++ b/lib/toolbox/keys_dict.h @@ -0,0 +1,103 @@ +#pragma once + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + KeysDictModeOpenExisting, + KeysDictModeOpenAlways, +} KeysDictMode; + +typedef struct KeysDict KeysDict; + +/** Check if the file list exists + * + * @param path - list path + * + * @return true if list exists, false otherwise +*/ +bool keys_dict_check_presence(const char* path); + +/** Open or create list + * Depending on mode, list will be opened or created. + * + * @param path - Path of the file that contain the list + * @param mode - ListKeysMode value + * @param key_size - Size of each key in bytes + * + * @return Returns KeysDict list instance +*/ +KeysDict* keys_dict_alloc(const char* path, KeysDictMode mode, size_t key_size); + +/** Close list + * + * @param instance - KeysDict list instance +*/ +void keys_dict_free(KeysDict* instance); + +/** Get total number of keys in list + * + * @param instance - KeysDict list instance + * + * @return Returns total number of keys in list +*/ +size_t keys_dict_get_total_keys(KeysDict* instance); + +/** Rewind list + * + * @param instance - KeysDict list instance + * + * @return Returns true if rewind was successful, false otherwise +*/ +bool keys_dict_rewind(KeysDict* instance); + +/** Check if key is present in list + * + * @param instance - KeysDict list instance + * @param key - key to check + * @param key_size - Size of the key in bytes + * + * @return Returns true if key is present, false otherwise +*/ +bool keys_dict_is_key_present(KeysDict* instance, const uint8_t* key, size_t key_size); + +/** Get next key from the list + * This function will return next key from list. If there are no more + * keys, it will return false, and keys_dict_rewind() should be called. + * + * @param instance - KeysDict list instance + * @param key - Array where to store key + * @param key_size - Size of key in bytes + * + * @return Returns true if key was successfully retrieved, false otherwise +*/ +bool keys_dict_get_next_key(KeysDict* instance, uint8_t* key, size_t key_size); + +/** Add key to list + * + * @param instance - KeysDict list instance + * @param key - Key to add + * @param key_size - Size of the key in bytes + * + * @return Returns true if key was successfully added, false otherwise +*/ +bool keys_dict_add_key(KeysDict* instance, const uint8_t* key, size_t key_size); + +/** Delete key from list + * + * @param instance - KeysDict list instance + * @param key - Key to delete + * @param key_size - Size of the key in bytes + * + * @return Returns true if key was successfully deleted, false otherwise +*/ +bool keys_dict_delete_key(KeysDict* instance, const uint8_t* key, size_t key_size); + +#ifdef __cplusplus +} +#endif diff --git a/targets/f18/api_symbols.csv b/targets/f18/api_symbols.csv index c166e78ee..8a5e44c97 100644 --- a/targets/f18/api_symbols.csv +++ b/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,49.3,, +Version,+,50.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -139,6 +139,7 @@ Header,+,lib/toolbox/crc32_calc.h,, Header,+,lib/toolbox/dir_walk.h,, Header,+,lib/toolbox/float_tools.h,, Header,+,lib/toolbox/hex.h,, +Header,+,lib/toolbox/keys_dict.h,, Header,+,lib/toolbox/manchester_decoder.h,, Header,+,lib/toolbox/manchester_encoder.h,, Header,+,lib/toolbox/name_generator.h,, @@ -1592,6 +1593,15 @@ Function,-,j1f,float,float Function,-,jn,double,"int, double" Function,-,jnf,float,"int, float" Function,-,jrand48,long,unsigned short[3] +Function,+,keys_dict_add_key,_Bool,"KeysDict*, const uint8_t*, size_t" +Function,+,keys_dict_alloc,KeysDict*,"const char*, KeysDictMode, size_t" +Function,+,keys_dict_check_presence,_Bool,const char* +Function,+,keys_dict_delete_key,_Bool,"KeysDict*, const uint8_t*, size_t" +Function,+,keys_dict_free,void,KeysDict* +Function,+,keys_dict_get_next_key,_Bool,"KeysDict*, uint8_t*, size_t" +Function,+,keys_dict_get_total_keys,size_t,KeysDict* +Function,+,keys_dict_is_key_present,_Bool,"KeysDict*, const uint8_t*, size_t" +Function,+,keys_dict_rewind,_Bool,KeysDict* Function,-,l64a,char*,long Function,-,labs,long,long Function,-,lcong48,void,unsigned short[7] diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index d47908434..353d511ec 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,49.3,, +Version,+,50.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,, @@ -114,7 +114,6 @@ Header,+,lib/nanopb/pb_encode.h,, Header,+,lib/nfc/helpers/iso13239_crc.h,, Header,+,lib/nfc/helpers/iso14443_crc.h,, Header,+,lib/nfc/helpers/nfc_data_generator.h,, -Header,+,lib/nfc/helpers/nfc_dict.h,, Header,+,lib/nfc/helpers/nfc_util.h,, Header,+,lib/nfc/nfc.h,, Header,+,lib/nfc/nfc_device.h,, @@ -204,6 +203,7 @@ Header,+,lib/toolbox/crc32_calc.h,, Header,+,lib/toolbox/dir_walk.h,, Header,+,lib/toolbox/float_tools.h,, Header,+,lib/toolbox/hex.h,, +Header,+,lib/toolbox/keys_dict.h,, Header,+,lib/toolbox/manchester_decoder.h,, Header,+,lib/toolbox/manchester_encoder.h,, Header,+,lib/toolbox/name_generator.h,, @@ -1967,6 +1967,15 @@ Function,-,j1f,float,float Function,-,jn,double,"int, double" Function,-,jnf,float,"int, float" Function,-,jrand48,long,unsigned short[3] +Function,+,keys_dict_add_key,_Bool,"KeysDict*, const uint8_t*, size_t" +Function,+,keys_dict_alloc,KeysDict*,"const char*, KeysDictMode, size_t" +Function,+,keys_dict_check_presence,_Bool,const char* +Function,+,keys_dict_delete_key,_Bool,"KeysDict*, const uint8_t*, size_t" +Function,+,keys_dict_free,void,KeysDict* +Function,+,keys_dict_get_next_key,_Bool,"KeysDict*, uint8_t*, size_t" +Function,+,keys_dict_get_total_keys,size_t,KeysDict* +Function,+,keys_dict_is_key_present,_Bool,"KeysDict*, const uint8_t*, size_t" +Function,+,keys_dict_rewind,_Bool,KeysDict* Function,-,l64a,char*,long Function,-,labs,long,long Function,-,lcong48,void,unsigned short[7] @@ -2441,15 +2450,6 @@ Function,+,nfc_device_save,_Bool,"NfcDevice*, const char*" Function,+,nfc_device_set_data,void,"NfcDevice*, NfcProtocol, const NfcDeviceData*" Function,+,nfc_device_set_loading_callback,void,"NfcDevice*, NfcLoadingCallback, void*" Function,+,nfc_device_set_uid,_Bool,"NfcDevice*, const uint8_t*, size_t" -Function,+,nfc_dict_add_key,_Bool,"NfcDict*, const uint8_t*, size_t" -Function,+,nfc_dict_alloc,NfcDict*,"const char*, NfcDictMode, size_t" -Function,+,nfc_dict_check_presence,_Bool,const char* -Function,+,nfc_dict_delete_key,_Bool,"NfcDict*, const uint8_t*, size_t" -Function,+,nfc_dict_free,void,NfcDict* -Function,+,nfc_dict_get_next_key,_Bool,"NfcDict*, uint8_t*, size_t" -Function,+,nfc_dict_get_total_keys,uint32_t,NfcDict* -Function,+,nfc_dict_is_key_present,_Bool,"NfcDict*, const uint8_t*, size_t" -Function,+,nfc_dict_rewind,_Bool,NfcDict* Function,+,nfc_felica_listener_set_sensf_res_data,NfcError,"Nfc*, const uint8_t*, const uint8_t, const uint8_t*, const uint8_t" Function,+,nfc_free,void,Nfc* Function,+,nfc_iso14443a_listener_set_col_res_data,NfcError,"Nfc*, uint8_t*, uint8_t, uint8_t*, uint8_t" From 25d24f1e4c8bdcbb618a554707c06855b094d414 Mon Sep 17 00:00:00 2001 From: Evgeny Stepanischev Date: Mon, 18 Dec 2023 21:36:50 +0300 Subject: [PATCH 05/35] Added UTF-8 support to Flipper Zero canvas API (#3297) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Added UTF-8 support to Flipper Zero canvas API * Add unicode example Co-authored-by: あく --- .../example_custom_font/example_custom_font.c | 86 ++++++++++++------- applications/services/gui/canvas.c | 10 +-- 2 files changed, 62 insertions(+), 34 deletions(-) diff --git a/applications/debug/example_custom_font/example_custom_font.c b/applications/debug/example_custom_font/example_custom_font.c index 15eeb5f02..8d85f23c6 100644 --- a/applications/debug/example_custom_font/example_custom_font.c +++ b/applications/debug/example_custom_font/example_custom_font.c @@ -7,35 +7,62 @@ //This arrays contains the font itself. You can use any u8g2 font you want /* -Fontname: -Raccoon-Fixed4x6-Medium-R-Normal--6-60-75-75-P-40-ISO10646-1 -Copyright: -Glyphs: 95/203 -BBX Build Mode: 0 + Fontname: -Misc-Fixed-Medium-R-Normal--6-60-75-75-C-40-ISO10646-1 + Copyright: Public domain font. Share and enjoy. + Glyphs: 191/919 + BBX Build Mode: 0 */ -const uint8_t u8g2_font_tom_thumb_4x6_tr[725] = - "_\0\2\2\2\3\3\4\4\3\6\0\377\5\377\5\0\0\352\1\330\2\270 \5\340\315\0!\6\265\310" - "\254\0\42\6\213\313$\25#\10\227\310\244\241\206\12$\10\227\310\215\70b\2%\10\227\310d\324F\1" - "&\10\227\310(\65R\22'\5\251\313\10(\6\266\310\251\62)\10\226\310\304\224\24\0*\6\217\312\244" - "\16+\7\217\311\245\225\0,\6\212\310)\0-\5\207\312\14.\5\245\310\4/\7\227\310Ve\4\60" - "\7\227\310-k\1\61\6\226\310\255\6\62\10\227\310h\220\312\1\63\11\227\310h\220\62X\0\64\10\227" - "\310$\65b\1\65\10\227\310\214\250\301\2\66\10\227\310\315\221F\0\67\10\227\310\314TF\0\70\10\227" - "\310\214\64\324\10\71\10\227\310\214\64\342\2:\6\255\311\244\0;\7\222\310e\240\0<\10\227\310\246\32" - "d\20=\6\217\311l\60>\11\227\310d\220A*\1\77\10\227\310\314\224a\2@\10\227\310UC\3" - "\1A\10\227\310UC\251\0B\10\227\310\250\264\322\2C\7\227\310\315\32\10D\10\227\310\250d-\0" - "E\10\227\310\214\70\342\0F\10\227\310\214\70b\4G\10\227\310\315\221\222\0H\10\227\310$\65\224\12" - "I\7\227\310\254X\15J\7\227\310\226\252\2K\10\227\310$\265\222\12L\7\227\310\304\346\0M\10\227" - "\310\244\61\224\12N\10\227\310\244q\250\0O\7\227\310UV\5P\10\227\310\250\264b\4Q\10\227\310" - "Uj$\1R\10\227\310\250\64V\1S\10\227\310m\220\301\2T\7\227\310\254\330\2U\7\227\310$" - "W\22V\10\227\310$\253L\0W\10\227\310$\65\206\12X\10\227\310$\325R\1Y\10\227\310$U" - "V\0Z\7\227\310\314T\16[\7\227\310\214X\16\134\10\217\311d\220A\0]\7\227\310\314r\4^" - "\5\213\313\65_\5\207\310\14`\6\212\313\304\0a\7\223\310\310\65\2b\10\227\310D\225\324\2c\7" - "\223\310\315\14\4d\10\227\310\246\245\222\0e\6\223\310\235\2f\10\227\310\246\264b\2g\10\227\307\35" - "\61%\0h\10\227\310D\225\254\0i\6\265\310\244\1j\10\233\307f\30U\5k\10\227\310\304\264T" - "\1l\7\227\310\310\326\0m\7\223\310\11\253\310d\220A*\1\77\11\253\310h\220\62L\0@\7" + "\253\310-\33\10A\10\253\310UC\251\0B\10\253\310\250\264\322\2C\10\253\310U\62U\0D\10\253" + "\310\250d-\0E\10\253\310\214\250\342\0F\10\253\310\214\250b\4G\10\253\310\315\244\222\0H\10\253" + "\310$\65\224\12I\7\253\310\254X\15J\7\253\310\226\252\2K\10\253\310$\265\222\12L\7\253\310\304" + "\346\0M\10\253\310\244\61\224\12N\10\253\310\252\241$\0O\7\253\310UV\5P\10\253\310\250\264b" + "\4Q\10\263\307UV\15\2R\10\253\310\250\264\222\12S\10\253\310m\220\301\2T\7\253\310\254\330\2" + "U\7\253\310$\327\10V\10\253\310$k\244\4W\10\253\310$\65\206\12X\10\253\310$\325R\1Y" + "\10\253\310$UV\0Z\7\253\310\314T\16[\6\352\310\254J\134\11\253\310\304\14\62\210\1]\6\252" + "\310\250j^\5\223\313\65_\5\213\307\14`\6\322\313\304\0a\7\243\310-\225\4b\10\253\310D\225" + "\324\2c\7\243\310\315\14\4d\10\253\310\246\245\222\0e\6\243\310USf\10\253\310\246\264b\2g" + "\10\253\307\255$\27\0h\10\253\310D\225\254\0i\10\253\310e$\323\0j\10\263\307fX.\0k" + "\10\253\310\304\264\222\12l\7\253\310\310\326\0m\10\243\310\244\241T\0n\7\243\310\250d\5o\7\243" + "\310U\252\2p\10\253\307\250\264b\4q\10\253\307-\225d\0r\10\243\310\244\25#\0s\10\243\310" + "\215\14\26\0t\10\253\310\245\25\63\10u\7\243\310$+\11v\7\243\310$\253\2w\10\243\310$\65" + "T\0x\7\243\310\244\62\25y\10\253\307$\225\344\2z\7\243\310\314\224\6{\10\263\307\246$k\20" + "|\6\351\310\14\1}\11\263\307d\20UL\21~\7\224\313%\225\0\0\0\0\4\377\377\4\1\11\253" + "\310\244\261\342\0\4\2\11\253\310\214\250\222\12\4\3\10\253\310\16Y\2\4\4\11\253\310M\225\201\0\4" + "\5\11\253\310m\220\301\2\4\6\10\253\310\254X\15\4\7\11\253\310\244\221b\32\4\10\10\253\310\226\252" + "\2\4\11\11\254\310L\325Z\2\4\12\11\254\310\244\326JK\4\13\11\253\310\250\250\222\12\4\14\10\253" + "\310\312\264\12\4\16\11\263\307\244\32u\2\4\17\11\263\307$\327H\11\4\20\11\253\310UC\251\0\4" + "\21\11\253\310\214\250\322\2\4\22\11\253\310\250\264\322\2\4\23\10\253\310\214\330\4\4\24\11\263\307\254\245" + "\206\12\4\25\11\253\310\214\250\342\0\4\26\12\253\310\244\221\322H\1\4\27\12\253\310h\220\62X\0\4" + "\30\11\253\310\304\64T\14\4\31\11\263\307\315\64T\14\4\32\11\253\310$\265\222\12\4\33\10\253\310-" + "W\0\4\34\11\253\310\244\241\254\0\4\35\11\253\310$\65\224\12\4\36\10\253\310UV\5\4\37\10\253" + "\310\214\344\12\4 \11\253\310\250\264b\4\4!\11\253\310U\62U\0\4\42\10\253\310\254\330\2\4#" + "\11\263\307$\253L\21\4$\12\253\310\245\221FJ\0\4%\11\253\310$\325R\1\4&\10\253\310$" + "\327\10\4'\11\253\310$\225d\1\4(\11\253\310$\65\216\0\4)\12\264\307\244\326#\203\0\4*" + "\13\254\310h\220\201LI\1\4+\12\254\310D\271\324H\1\4,\11\253\310\304\250\322\2\4-\11\253" + "\310h\220\344\2\4.\12\254\310\244\244.\225\0\4/\11\253\310\255\264T\0\4\60\10\243\310-\225\4" + "\4\61\11\253\310\315\221*\0\4\62\11\243\310\14\225\26\0\4\63\10\243\310\214X\2\4\64\11\253\307-" + "\65T\0\4\65\7\243\310US\4\66\11\244\310$S%\1\4\67\11\243\310\254\14\26\0\4\70\11\243" + "\310\244\61T\0\4\71\11\253\310\244\326P\1\4:\10\243\310$\265\12\4;\7\243\310-+\4<\11" + "\243\310\244\241T\0\4=\11\243\310\244\241T\0\4>\10\243\310U\252\2\4\77\10\243\310\214d\5\4" + "@\11\253\307\250\264b\4\4A\10\243\310\315\14\4\4B\10\243\310\254X\1\4C\11\253\307$\225\344" + "\2\4D\12\263\307\305\224T\231\0\4E\10\243\310\244\62\25\4F\11\253\307$k\304\0\4G\11\243" + "\310$\225d\0\4H\10\243\310\244q\4\4I\11\254\307\244\364\310 \4J\12\244\310h SR\0" + "\4K\11\244\310\304\245F\12\4L\11\243\310D\225\26\0\4M\10\243\310H\271\0\4N\12\244\310\244" + "\244\226J\0\4O\10\243\310\255\264\2\4Q\10\253\310\244\326\24\4R\11\263\307D\25U\31\4S\11" + "\253\310\246\64b\4\4T\11\243\310\215\224\201\0\4U\11\243\310\215\14\26\0\4V\11\253\310e$\323" + "\0\4W\11\253\310\244\14d\32\4X\11\263\307fX.\0\4Y\10\244\310\251\326\22\4Z\11\244\310" + "\244\264\322\22\4[\11\253\310D\25U\1\4\134\10\253\310\312\264\12\4^\11\263\307\244\32u\2\4_" + "\11\253\307$k\244\4\4\220\10\253\310\16Y\2\4\221\10\243\310\16\31\1\4\222\11\253\310\251\264b\2" + "\4\223\11\243\310\251\264\22\0\0"; // Screen is 128x64 px static void app_draw_callback(Canvas* canvas, void* ctx) { @@ -43,10 +70,11 @@ static void app_draw_callback(Canvas* canvas, void* ctx) { canvas_clear(canvas); - canvas_set_custom_u8g2_font(canvas, u8g2_font_tom_thumb_4x6_tr); + canvas_set_custom_u8g2_font(canvas, u8g2_font_4x6_t_cyrillic); canvas_draw_str(canvas, 0, 6, "This is a tiny custom font"); canvas_draw_str(canvas, 0, 12, "012345.?! ,:;\"\'@#$%"); + canvas_draw_str(canvas, 0, 18, "И немного юникода"); } static void app_input_callback(InputEvent* input_event, void* ctx) { diff --git a/applications/services/gui/canvas.c b/applications/services/gui/canvas.c index 44adcd939..209c82a82 100644 --- a/applications/services/gui/canvas.c +++ b/applications/services/gui/canvas.c @@ -150,7 +150,7 @@ void canvas_draw_str(Canvas* canvas, uint8_t x, uint8_t y, const char* str) { if(!str) return; x += canvas->offset_x; y += canvas->offset_y; - u8g2_DrawStr(&canvas->fb, x, y, str); + u8g2_DrawUTF8(&canvas->fb, x, y, str); } void canvas_draw_str_aligned( @@ -169,10 +169,10 @@ void canvas_draw_str_aligned( case AlignLeft: break; case AlignRight: - x -= u8g2_GetStrWidth(&canvas->fb, str); + x -= u8g2_GetUTF8Width(&canvas->fb, str); break; case AlignCenter: - x -= (u8g2_GetStrWidth(&canvas->fb, str) / 2); + x -= (u8g2_GetUTF8Width(&canvas->fb, str) / 2); break; default: furi_crash(); @@ -193,13 +193,13 @@ void canvas_draw_str_aligned( break; } - u8g2_DrawStr(&canvas->fb, x, y, str); + u8g2_DrawUTF8(&canvas->fb, x, y, str); } uint16_t canvas_string_width(Canvas* canvas, const char* str) { furi_assert(canvas); if(!str) return 0; - return u8g2_GetStrWidth(&canvas->fb, str); + return u8g2_GetUTF8Width(&canvas->fb, str); } uint8_t canvas_glyph_width(Canvas* canvas, uint16_t symbol) { From 6f6074dc01e1370a64e953c956f6d3cfe41f0d4f Mon Sep 17 00:00:00 2001 From: gornekich Date: Tue, 19 Dec 2023 16:11:35 +0400 Subject: [PATCH 06/35] Keys Dict: fix PVS warnings (#3299) * keys dict: fix PVS warnings * nfc app: suppress PVS warning --- applications/main/nfc/nfc_app.c | 2 +- lib/toolbox/keys_dict.c | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/applications/main/nfc/nfc_app.c b/applications/main/nfc/nfc_app.c index ec528ad9c..bf15161aa 100644 --- a/applications/main/nfc/nfc_app.c +++ b/applications/main/nfc/nfc_app.c @@ -343,7 +343,7 @@ bool nfc_load_file(NfcApp* instance, FuriString* path, bool show_dialog) { nfc_supported_cards_load_cache(instance->nfc_supported_cards); FuriString* load_path = furi_string_alloc(); - if(nfc_has_shadow_file_internal(instance, path)) { + if(nfc_has_shadow_file_internal(instance, path)) { //-V1051 nfc_set_shadow_file_path(path, load_path); } else if(furi_string_end_with(path, NFC_APP_SHADOW_EXTENSION)) { size_t path_len = furi_string_size(path); diff --git a/lib/toolbox/keys_dict.c b/lib/toolbox/keys_dict.c index 30580bf5e..8d6f8c846 100644 --- a/lib/toolbox/keys_dict.c +++ b/lib/toolbox/keys_dict.c @@ -108,7 +108,7 @@ KeysDict* keys_dict_alloc(const char* path, KeysDictMode mode, size_t key_size) } } stream_rewind(instance->stream); - FURI_LOG_I(TAG, "Loaded dictionary with %u keys", instance->total_keys); + FURI_LOG_I(TAG, "Loaded dictionary with %zu keys", instance->total_keys); furi_string_free(line); @@ -299,13 +299,12 @@ bool keys_dict_delete_key(KeysDict* instance, const uint8_t* key, size_t key_siz furi_assert(key); bool key_removed = false; - bool is_endfile = false; uint8_t* temp_key = malloc(key_size); stream_rewind(instance->stream); - while(!key_removed && !is_endfile) { + while(!key_removed) { if(!keys_dict_get_next_key(instance, temp_key, key_size)) { break; } @@ -332,4 +331,4 @@ bool keys_dict_delete_key(KeysDict* instance, const uint8_t* key, size_t key_siz free(temp_key); return key_removed; -} \ No newline at end of file +} From 1e1d9fcb69358c291e65b02e89026966aead3cca Mon Sep 17 00:00:00 2001 From: hedger Date: Tue, 19 Dec 2023 16:43:06 +0400 Subject: [PATCH 07/35] ufbt: changed toolchain environment invocation; updated .gitignore for app template (#3300) --- scripts/fbt/util.py | 21 +++++++++++++ scripts/ufbt/SConstruct | 40 ++++++++++-------------- scripts/ufbt/project_template/.gitignore | 4 ++- scripts/ufbt/site_tools/ufbt_help.py | 6 +++- scripts/ufbt/site_tools/ufbt_state.py | 1 - site_scons/environ.scons | 39 ++++++++--------------- 6 files changed, 58 insertions(+), 53 deletions(-) diff --git a/scripts/fbt/util.py b/scripts/fbt/util.py index fb36ef55a..629467568 100644 --- a/scripts/fbt/util.py +++ b/scripts/fbt/util.py @@ -11,6 +11,27 @@ WINPATHSEP_RE = re.compile(r"\\([^\"'\\]|$)") # Excludes all files ending with ~, usually created by editors as backup files GLOB_FILE_EXCLUSION = ["*~"] +# List of environment variables to proxy to child processes +FORWARDED_ENV_VARIABLES = [ + # CI/CD variables + "WORKFLOW_BRANCH_OR_TAG", + "DIST_SUFFIX", + # Python & other tools + "HOME", + "APPDATA", + "PYTHONHOME", + "PYTHONNOUSERSITE", + "TMP", + "TEMP", + # ccache + "CCACHE_DISABLE", + # Colors for tools + "TERM", + # Toolchain + "FBT_TOOLCHAIN_PATH", + "UFBT_HOME", +] + def tempfile_arg_esc_func(arg): arg = quote_spaces(arg) diff --git a/scripts/ufbt/SConstruct b/scripts/ufbt/SConstruct index 46d663578..2fc170ad9 100644 --- a/scripts/ufbt/SConstruct +++ b/scripts/ufbt/SConstruct @@ -25,33 +25,10 @@ forward_os_env = { "PATH": os.environ["PATH"], } -# Proxying environment to child processes & scripts -variables_to_forward = [ - # CI/CD variables - "WORKFLOW_BRANCH_OR_TAG", - "DIST_SUFFIX", - # Python & other tools - "HOME", - "APPDATA", - "PYTHONHOME", - "PYTHONNOUSERSITE", - "TMP", - "TEMP", - # Colors for tools - "TERM", -] - -if proxy_env := GetOption("proxy_env"): - variables_to_forward.extend(proxy_env.split(",")) - -for env_value_name in variables_to_forward: - if environ_value := os.environ.get(env_value_name, None): - forward_os_env[env_value_name] = environ_value # Core environment init - loads SDK state, sets up paths, etc. core_env = Environment( variables=ufbt_variables, - ENV=forward_os_env, UFBT_STATE_DIR=ufbt_state_dir, UFBT_CURRENT_SDK_DIR=ufbt_current_sdk_dir, UFBT_SCRIPT_DIR=ufbt_script_dir, @@ -69,6 +46,7 @@ core_env.Append(CPPDEFINES=GetOption("extra_defines")) from fbt.appmanifest import FlipperApplication, FlipperAppType from fbt.sdk.cache import SdkCache from fbt.util import ( + FORWARDED_ENV_VARIABLES, path_as_posix, resolve_real_dir_node, single_quote, @@ -76,8 +54,19 @@ from fbt.util import ( wrap_tempfile, ) +variables_to_forward = list(FORWARDED_ENV_VARIABLES) + +if proxy_env := GetOption("proxy_env"): + variables_to_forward.extend(proxy_env.split(",")) + +for env_value_name in variables_to_forward: + if environ_value := os.environ.get(env_value_name, None): + forward_os_env[env_value_name] = environ_value + + # Base environment with all tools loaded from SDK env = core_env.Clone( + ENV=forward_os_env, toolpath=[core_env["FBT_SCRIPT_DIR"].Dir("fbt_tools")], tools=[ "fbt_tweaks", @@ -477,9 +466,12 @@ else: dist_env.PhonyTarget("dolphin_ext", Action(missing_dolphin_folder, None)) +# print(env.Dump()) dist_env.PhonyTarget( "env", - "@echo $( ${FBT_SCRIPT_DIR.abspath}/toolchain/fbtenv.sh $)", + '@echo "FBT_TOOLCHAIN_PATH=' + + forward_os_env["FBT_TOOLCHAIN_PATH"] + + '" source $( "${FBT_SCRIPT_DIR.abspath}/toolchain/fbtenv.sh" $)', ) dist_env.PostConfigureUfbtEnvionment() diff --git a/scripts/ufbt/project_template/.gitignore b/scripts/ufbt/project_template/.gitignore index e2a15a10a..81a8981f7 100644 --- a/scripts/ufbt/project_template/.gitignore +++ b/scripts/ufbt/project_template/.gitignore @@ -1,4 +1,6 @@ dist/* .vscode .clang-format -.editorconfig \ No newline at end of file +.editorconfig +.env +.ufbt diff --git a/scripts/ufbt/site_tools/ufbt_help.py b/scripts/ufbt/site_tools/ufbt_help.py index 1df6a0591..ab20e2f7d 100644 --- a/scripts/ufbt/site_tools/ufbt_help.py +++ b/scripts/ufbt/site_tools/ufbt_help.py @@ -44,7 +44,11 @@ How to create a new application: 4. Run `ufbt launch` to build and upload your application. How to open a shell with toolchain environment and other build tools: - In your shell, type "source `ufbt -s env`". You can also use "." instead of "source". + In your shell, type "eval `ufbt -s env`". + +How to update uFBT SDK: + Run "ufbt update" to fetch latest SDK. + You can also specify branch, target and/or channel options. See "ufbt update -h" for details. """ diff --git a/scripts/ufbt/site_tools/ufbt_state.py b/scripts/ufbt/site_tools/ufbt_state.py index 0038b66a3..d9aa0fd6b 100644 --- a/scripts/ufbt/site_tools/ufbt_state.py +++ b/scripts/ufbt/site_tools/ufbt_state.py @@ -1,6 +1,5 @@ import json import os -import pathlib import sys from functools import reduce diff --git a/site_scons/environ.scons b/site_scons/environ.scons index 74762cb15..ece8de212 100644 --- a/site_scons/environ.scons +++ b/site_scons/environ.scons @@ -1,13 +1,14 @@ -from SCons.Platform import TempFileMunge -from fbt.util import ( - tempfile_arg_esc_func, - single_quote, - wrap_tempfile, - resolve_real_dir_node, -) - -import os import multiprocessing +import os + +from fbt.util import ( + FORWARDED_ENV_VARIABLES, + resolve_real_dir_node, + single_quote, + tempfile_arg_esc_func, + wrap_tempfile, +) +from SCons.Platform import TempFileMunge Import("VAR_ENV") @@ -15,23 +16,9 @@ forward_os_env = { # Import PATH from OS env - scons doesn't do that by default "PATH": os.environ["PATH"], } -# Proxying CI environment to child processes & scripts -variables_to_forward = [ - # CI/CD variables - "WORKFLOW_BRANCH_OR_TAG", - "DIST_SUFFIX", - # Python & other tools - "HOME", - "APPDATA", - "PYTHONHOME", - "PYTHONNOUSERSITE", - "TMP", - "TEMP", - # ccache - "CCACHE_DISABLE", - # Colors for tools - "TERM", -] + +variables_to_forward = list(FORWARDED_ENV_VARIABLES) + if proxy_env := GetOption("proxy_env"): variables_to_forward.extend(proxy_env.split(",")) From 17b122990f35998d412bf2769467e5cd4b192311 Mon Sep 17 00:00:00 2001 From: Skorpionm <85568270+Skorpionm@users.noreply.github.com> Date: Tue, 19 Dec 2023 18:13:37 +0400 Subject: [PATCH 08/35] USART Bridge: added support for software control of DE/RE pins (#3280) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * USART Bridge: added support for software control of DE/RE pins * USART Bridge: fix syntax * UsbUsartBridge: add TODO ticket * UsbUsartBridge: add second TODO ticket * GpioUartBridge: human readable configuration * GpioUartBridge: rename `Soft DE/RE` to `DE/RE Pin` * GpioUartBridge: push pull for DE/RE pin Co-authored-by: あく --- .../gpio/scenes/gpio_scene_usb_uart_config.c | 17 +++++++++ applications/main/gpio/usb_uart_bridge.c | 35 +++++++++++++++++++ applications/main/gpio/usb_uart_bridge.h | 1 + 3 files changed, 53 insertions(+) diff --git a/applications/main/gpio/scenes/gpio_scene_usb_uart_config.c b/applications/main/gpio/scenes/gpio_scene_usb_uart_config.c index e2ab66264..8fcacd403 100644 --- a/applications/main/gpio/scenes/gpio_scene_usb_uart_config.c +++ b/applications/main/gpio/scenes/gpio_scene_usb_uart_config.c @@ -27,6 +27,7 @@ static const uint32_t baudrate_list[] = { 460800, 921600, }; +static const char* software_de_re[] = {"None", "4"}; bool gpio_scene_usb_uart_cfg_on_event(void* context, SceneManagerEvent event) { GpioApp* app = context; @@ -84,6 +85,17 @@ static void line_port_cb(VariableItem* item) { view_dispatcher_send_custom_event(app->view_dispatcher, GpioUsbUartEventConfigSet); } +static void line_software_de_re_cb(VariableItem* item) { + GpioApp* app = variable_item_get_context(item); + furi_assert(app); + uint8_t index = variable_item_get_current_value_index(item); + + variable_item_set_current_value_text(item, software_de_re[index]); + + app->usb_uart_cfg->software_de_re = index; + view_dispatcher_send_custom_event(app->view_dispatcher, GpioUsbUartEventConfigSet); +} + static void line_flow_cb(VariableItem* item) { GpioApp* app = variable_item_get_context(item); furi_assert(app); @@ -155,6 +167,11 @@ void gpio_scene_usb_uart_cfg_on_enter(void* context) { app->var_item_flow = item; line_ensure_flow_invariant(app); + item = variable_item_list_add( + var_item_list, "DE/RE Pin", COUNT_OF(software_de_re), line_software_de_re_cb, app); + variable_item_set_current_value_index(item, app->usb_uart_cfg->software_de_re); + variable_item_set_current_value_text(item, software_de_re[app->usb_uart_cfg->software_de_re]); + variable_item_list_set_selected_item( var_item_list, scene_manager_get_scene_state(app->scene_manager, GpioAppViewUsbUartCfg)); diff --git a/applications/main/gpio/usb_uart_bridge.c b/applications/main/gpio/usb_uart_bridge.c index 9bc759dc8..366c5cdc4 100644 --- a/applications/main/gpio/usb_uart_bridge.c +++ b/applications/main/gpio/usb_uart_bridge.c @@ -6,11 +6,16 @@ #include #include +//TODO: FL-3276 port to new USART API +#include +#include + #define USB_CDC_PKT_LEN CDC_DATA_SZ #define USB_UART_RX_BUF_SIZE (USB_CDC_PKT_LEN * 5) #define USB_CDC_BIT_DTR (1 << 0) #define USB_CDC_BIT_RTS (1 << 1) +#define USB_USART_DE_RE_PIN &gpio_ext_pa4 static const GpioPin* flow_pins[][2] = { {&gpio_ext_pa7, &gpio_ext_pa6}, // 2, 3 @@ -247,6 +252,17 @@ static int32_t usb_uart_worker(void* context) { usb_uart->cfg.flow_pins = usb_uart->cfg_new.flow_pins; events |= WorkerEvtCtrlLineSet; } + if(usb_uart->cfg.software_de_re != usb_uart->cfg_new.software_de_re) { + usb_uart->cfg.software_de_re = usb_uart->cfg_new.software_de_re; + if(usb_uart->cfg.software_de_re != 0) { + furi_hal_gpio_write(USB_USART_DE_RE_PIN, true); + furi_hal_gpio_init( + USB_USART_DE_RE_PIN, GpioModeOutputPushPull, GpioPullNo, GpioSpeedMedium); + } else { + furi_hal_gpio_init( + USB_USART_DE_RE_PIN, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + } + } api_lock_unlock(usb_uart->cfg_lock); } if(events & WorkerEvtLineCfgSet) { @@ -260,6 +276,8 @@ static int32_t usb_uart_worker(void* context) { usb_uart_vcp_deinit(usb_uart, usb_uart->cfg.vcp_ch); usb_uart_serial_deinit(usb_uart, usb_uart->cfg.uart_ch); + furi_hal_gpio_init(USB_USART_DE_RE_PIN, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + if(usb_uart->cfg.flow_pins != 0) { furi_hal_gpio_init_simple(flow_pins[usb_uart->cfg.flow_pins - 1][0], GpioModeAnalog); furi_hal_gpio_init_simple(flow_pins[usb_uart->cfg.flow_pins - 1][1], GpioModeAnalog); @@ -298,7 +316,24 @@ static int32_t usb_uart_tx_thread(void* context) { if(len > 0) { usb_uart->st.tx_cnt += len; + + if(usb_uart->cfg.software_de_re != 0) + furi_hal_gpio_write(USB_USART_DE_RE_PIN, false); + furi_hal_uart_tx(usb_uart->cfg.uart_ch, data, len); + + if(usb_uart->cfg.software_de_re != 0) { + //TODO: FL-3276 port to new USART API + if(usb_uart->cfg.uart_ch == FuriHalUartIdUSART1) { + while(!LL_USART_IsActiveFlag_TC(USART1)) + ; + } else if(usb_uart->cfg.uart_ch == FuriHalUartIdLPUART1) { + while(!LL_LPUART_IsActiveFlag_TC(LPUART1)) + ; + } + + furi_hal_gpio_write(USB_USART_DE_RE_PIN, true); + } } } } diff --git a/applications/main/gpio/usb_uart_bridge.h b/applications/main/gpio/usb_uart_bridge.h index b456c3cc4..ebb103f54 100644 --- a/applications/main/gpio/usb_uart_bridge.h +++ b/applications/main/gpio/usb_uart_bridge.h @@ -11,6 +11,7 @@ typedef struct { uint8_t flow_pins; uint8_t baudrate_mode; uint32_t baudrate; + uint8_t software_de_re; } UsbUartConfig; typedef struct { From bc1fdabce4965ae3ec77eb3fdbcbd5d119800e07 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 20 Dec 2023 01:25:35 +0300 Subject: [PATCH 09/35] its time to enable this one --- assets/dolphin/external/manifest.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/assets/dolphin/external/manifest.txt b/assets/dolphin/external/manifest.txt index 9aaff3c6f..c2583ae5a 100644 --- a/assets/dolphin/external/manifest.txt +++ b/assets/dolphin/external/manifest.txt @@ -203,3 +203,10 @@ Max butthurt: 10 Min level: 3 Max level: 3 Weight: 2 + +Name: L1_New_year_128x64 +Min butthurt: 0 +Max butthurt: 10 +Min level: 1 +Max level: 3 +Weight: 7 From 49b2a4da8a17f0d63a7bc8d6b1c011bea964398f Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Thu, 21 Dec 2023 03:14:23 +0300 Subject: [PATCH 10/35] fix broken texts due to usage of utf8, add proper api --- .../example_custom_font/example_custom_font.c | 6 +- applications/services/gui/canvas.c | 57 +++++++++++++++++++ applications/services/gui/canvas.h | 38 +++++++++++++ targets/f7/api_symbols.csv | 3 + 4 files changed, 101 insertions(+), 3 deletions(-) diff --git a/applications/debug/example_custom_font/example_custom_font.c b/applications/debug/example_custom_font/example_custom_font.c index 8d85f23c6..334aa8aa8 100644 --- a/applications/debug/example_custom_font/example_custom_font.c +++ b/applications/debug/example_custom_font/example_custom_font.c @@ -72,9 +72,9 @@ static void app_draw_callback(Canvas* canvas, void* ctx) { canvas_set_custom_u8g2_font(canvas, u8g2_font_4x6_t_cyrillic); - canvas_draw_str(canvas, 0, 6, "This is a tiny custom font"); - canvas_draw_str(canvas, 0, 12, "012345.?! ,:;\"\'@#$%"); - canvas_draw_str(canvas, 0, 18, "И немного юникода"); + canvas_draw_utf8_str(canvas, 0, 6, "This is a tiny custom font"); + canvas_draw_utf8_str(canvas, 0, 12, "012345.?! ,:;\"\'@#$%"); + canvas_draw_utf8_str(canvas, 0, 18, "И немного юникода"); } static void app_input_callback(InputEvent* input_event, void* ctx) { diff --git a/applications/services/gui/canvas.c b/applications/services/gui/canvas.c index f8f33da9b..3cd35e402 100644 --- a/applications/services/gui/canvas.c +++ b/applications/services/gui/canvas.c @@ -154,6 +154,14 @@ void canvas_set_custom_u8g2_font(Canvas* canvas, const uint8_t* font) { } void canvas_draw_str(Canvas* canvas, uint8_t x, uint8_t y, const char* str) { + furi_assert(canvas); + if(!str) return; + x += canvas->offset_x; + y += canvas->offset_y; + u8g2_DrawStr(&canvas->fb, x, y, str); +} + +void canvas_draw_utf8_str(Canvas* canvas, uint8_t x, uint8_t y, const char* str) { furi_assert(canvas); if(!str) return; x += canvas->offset_x; @@ -173,6 +181,49 @@ void canvas_draw_str_aligned( x += canvas->offset_x; y += canvas->offset_y; + switch(horizontal) { + case AlignLeft: + break; + case AlignRight: + x -= u8g2_GetStrWidth(&canvas->fb, str); + break; + case AlignCenter: + x -= (u8g2_GetStrWidth(&canvas->fb, str) / 2); + break; + default: + furi_crash(); + break; + } + + switch(vertical) { + case AlignTop: + y += u8g2_GetAscent(&canvas->fb); + break; + case AlignBottom: + break; + case AlignCenter: + y += (u8g2_GetAscent(&canvas->fb) / 2); + break; + default: + furi_crash(); + break; + } + + u8g2_DrawStr(&canvas->fb, x, y, str); +} + +void canvas_draw_utf8_str_aligned( + Canvas* canvas, + uint8_t x, + uint8_t y, + Align horizontal, + Align vertical, + const char* str) { + furi_assert(canvas); + if(!str) return; + x += canvas->offset_x; + y += canvas->offset_y; + switch(horizontal) { case AlignLeft: break; @@ -205,6 +256,12 @@ void canvas_draw_str_aligned( } uint16_t canvas_string_width(Canvas* canvas, const char* str) { + furi_assert(canvas); + if(!str) return 0; + return u8g2_GetStrWidth(&canvas->fb, str); +} + +uint16_t canvas_utf8_string_width(Canvas* canvas, const char* str) { furi_assert(canvas); if(!str) return 0; return u8g2_GetUTF8Width(&canvas->fb, str); diff --git a/applications/services/gui/canvas.h b/applications/services/gui/canvas.h index bda730ff2..afed58548 100644 --- a/applications/services/gui/canvas.h +++ b/applications/services/gui/canvas.h @@ -187,6 +187,15 @@ void canvas_set_custom_u8g2_font(Canvas* canvas, const uint8_t* font); */ void canvas_draw_str(Canvas* canvas, uint8_t x, uint8_t y, const char* str); +/** Draw UTF8 string at position of baseline defined by x, y. + * + * @param canvas Canvas instance + * @param x anchor point x coordinate + * @param y anchor point y coordinate + * @param str C-string + */ +void canvas_draw_utf8_str(Canvas* canvas, uint8_t x, uint8_t y, const char* str); + /** Draw aligned string defined by x, y. * * Align calculated from position of baseline, string width and ascent (height @@ -207,6 +216,26 @@ void canvas_draw_str_aligned( Align vertical, const char* str); +/** Draw aligned UTF8 string defined by x, y. + * + * Align calculated from position of baseline, string width and ascent (height + * of the glyphs above the baseline) + * + * @param canvas Canvas instance + * @param x anchor point x coordinate + * @param y anchor point y coordinate + * @param horizontal horizontal alignment + * @param vertical vertical alignment + * @param str C-string + */ +void canvas_draw_utf8_str_aligned( + Canvas* canvas, + uint8_t x, + uint8_t y, + Align horizontal, + Align vertical, + const char* str); + /** Get string width * * @param canvas Canvas instance @@ -216,6 +245,15 @@ void canvas_draw_str_aligned( */ uint16_t canvas_string_width(Canvas* canvas, const char* str); +/** Get UTF8 string width + * + * @param canvas Canvas instance + * @param str C-string + * + * @return width in pixels. + */ +uint16_t canvas_utf8_string_width(Canvas* canvas, const char* str); + /** Get glyph width * * @param canvas Canvas instance diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 3ab58f58d..afce83fe5 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -735,6 +735,8 @@ Function,+,canvas_draw_rframe,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t, Function,+,canvas_draw_str,void,"Canvas*, uint8_t, uint8_t, const char*" Function,+,canvas_draw_str_aligned,void,"Canvas*, uint8_t, uint8_t, Align, Align, const char*" Function,+,canvas_draw_triangle,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t, CanvasDirection" +Function,+,canvas_draw_utf8_str,void,"Canvas*, uint8_t, uint8_t, const char*" +Function,+,canvas_draw_utf8_str_aligned,void,"Canvas*, uint8_t, uint8_t, Align, Align, const char*" Function,+,canvas_draw_xbm,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t, const uint8_t*" Function,+,canvas_get_font_params,const CanvasFontParameters*,"const Canvas*, Font" Function,+,canvas_glyph_width,uint8_t,"Canvas*, uint16_t" @@ -747,6 +749,7 @@ Function,+,canvas_set_custom_u8g2_font,void,"Canvas*, const uint8_t*" Function,+,canvas_set_font,void,"Canvas*, Font" Function,+,canvas_set_font_direction,void,"Canvas*, CanvasDirection" Function,+,canvas_string_width,uint16_t,"Canvas*, const char*" +Function,+,canvas_utf8_string_width,uint16_t,"Canvas*, const char*" Function,+,canvas_width,uint8_t,const Canvas* Function,-,cbrt,double,double Function,-,cbrtf,float,float From 8fa21c49b2ee49aadd28d713f586880469e3bff1 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Thu, 21 Dec 2023 03:16:16 +0300 Subject: [PATCH 11/35] better subghz history element removal by Willy-JL https://github.com/Flipper-XFW/Xtreme-Firmware/commit/c40755f700a89af2b6519e7cd9a5d64f11c95165 --- .../subghz/scenes/subghz_scene_receiver.c | 4 +- applications/main/subghz/subghz_history.c | 27 +++++-------- applications/main/subghz/subghz_history.h | 2 +- applications/main/subghz/views/receiver.c | 38 ++++++++----------- applications/main/subghz/views/receiver.h | 2 +- 5 files changed, 30 insertions(+), 43 deletions(-) diff --git a/applications/main/subghz/scenes/subghz_scene_receiver.c b/applications/main/subghz/scenes/subghz_scene_receiver.c index 9dc48965d..bffff9988 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver.c @@ -249,7 +249,9 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { subghz_view_receiver_disable_draw_callback(subghz->subghz_receiver); subghz_history_delete_item(subghz->history, subghz->idx_menu_chosen); - subghz_view_receiver_delete_element_callback(subghz->subghz_receiver); + subghz_view_receiver_delete_item( + subghz->subghz_receiver, + subghz_view_receiver_get_idx_menu(subghz->subghz_receiver)); subghz_view_receiver_enable_draw_callback(subghz->subghz_receiver); subghz_scene_receiver_update_statusbar(subghz); diff --git a/applications/main/subghz/subghz_history.c b/applications/main/subghz/subghz_history.c index 396e28421..048104f35 100644 --- a/applications/main/subghz/subghz_history.c +++ b/applications/main/subghz/subghz_history.c @@ -89,26 +89,19 @@ void subghz_history_reset(SubGhzHistory* instance) { instance->code_last_hash_data = 0; } -void subghz_history_delete_item(SubGhzHistory* instance, uint16_t item_id) { +void subghz_history_delete_item(SubGhzHistory* instance, uint16_t idx) { furi_assert(instance); - SubGhzHistoryItemArray_it_t it; - //SubGhzHistoryItem* target_item = SubGhzHistoryItemArray_get(instance->history->data, item_id); - SubGhzHistoryItemArray_it_last(it, instance->history->data); - while(!SubGhzHistoryItemArray_end_p(it)) { - SubGhzHistoryItem* item = SubGhzHistoryItemArray_ref(it); - - if(it->index == (size_t)(item_id)) { - furi_string_free(item->item_str); - furi_string_free(item->preset->name); - free(item->preset); - flipper_format_free(item->flipper_string); - item->type = 0; - SubGhzHistoryItemArray_remove(instance->history->data, it); - } - SubGhzHistoryItemArray_previous(it); + if(idx < SubGhzHistoryItemArray_size(instance->history->data)) { + SubGhzHistoryItem* item = SubGhzHistoryItemArray_get(instance->history->data, idx); + furi_string_free(item->item_str); + furi_string_free(item->preset->name); + free(item->preset); + flipper_format_free(item->flipper_string); + item->type = 0; + SubGhzHistoryItemArray_remove_v(instance->history->data, idx, idx + 1); + instance->last_index_write--; } - instance->last_index_write--; } uint16_t subghz_history_get_item(SubGhzHistory* instance) { diff --git a/applications/main/subghz/subghz_history.h b/applications/main/subghz/subghz_history.h index 1b27d52ad..cc63c0259 100644 --- a/applications/main/subghz/subghz_history.h +++ b/applications/main/subghz/subghz_history.h @@ -27,7 +27,7 @@ void subghz_history_free(SubGhzHistory* instance); */ void subghz_history_reset(SubGhzHistory* instance); -void subghz_history_delete_item(SubGhzHistory* instance, uint16_t item_id); +void subghz_history_delete_item(SubGhzHistory* instance, uint16_t idx); /** Get frequency to history[idx] * diff --git a/applications/main/subghz/views/receiver.c b/applications/main/subghz/views/receiver.c index f1d0324fc..98c15dbff 100644 --- a/applications/main/subghz/views/receiver.c +++ b/applications/main/subghz/views/receiver.c @@ -655,40 +655,32 @@ uint16_t subghz_view_receiver_get_idx_menu(SubGhzViewReceiver* subghz_receiver) return idx; } -void subghz_view_receiver_delete_element_callback(SubGhzViewReceiver* subghz_receiver) { +void subghz_view_receiver_delete_item(SubGhzViewReceiver* subghz_receiver, uint16_t idx) { furi_assert(subghz_receiver); with_view_model( subghz_receiver->view, SubGhzViewReceiverModel * model, { - SubGhzReceiverMenuItemArray_it_t it; - // SubGhzReceiverMenuItem* target_item = - // SubGhzReceiverMenuItemArray_get(model->history->data, model->idx); - SubGhzReceiverMenuItemArray_it_last(it, model->history->data); - while(!SubGhzReceiverMenuItemArray_end_p(it)) { - SubGhzReceiverMenuItem* item = SubGhzReceiverMenuItemArray_ref(it); + if(idx < SubGhzReceiverMenuItemArray_size(model->history->data)) { + SubGhzReceiverMenuItem* item = + SubGhzReceiverMenuItemArray_get(model->history->data, idx); + furi_string_free(item->item_str); + furi_string_free(item->time); + item->type = 0; + SubGhzReceiverMenuItemArray_remove_v(model->history->data, idx, idx + 1); - if(it->index == (size_t)(model->idx)) { - furi_string_free(item->item_str); - furi_string_free(item->time); - item->type = 0; - SubGhzReceiverMenuItemArray_remove(model->history->data, it); + if(model->history_item == 5) { + if(model->idx >= 2) { + model->idx = model->history_item - 1; + } } + model->history_item--; - SubGhzReceiverMenuItemArray_previous(it); - } - - if(model->history_item == 5) { - if(model->idx >= 2) { - model->idx = model->history_item - 1; + if(model->idx && (model->idx > idx || model->idx == model->history_item)) { + model->idx--; } } - model->history_item--; - - if(model->idx != 0) { - model->idx--; - } }, true); } diff --git a/applications/main/subghz/views/receiver.h b/applications/main/subghz/views/receiver.h index c280e1de6..f28ed1304 100644 --- a/applications/main/subghz/views/receiver.h +++ b/applications/main/subghz/views/receiver.h @@ -53,7 +53,7 @@ uint16_t subghz_view_receiver_get_idx_menu(SubGhzViewReceiver* subghz_receiver); void subghz_view_receiver_set_idx_menu(SubGhzViewReceiver* subghz_receiver, uint16_t idx); -void subghz_view_receiver_delete_element_callback(SubGhzViewReceiver* subghz_receiver); +void subghz_view_receiver_delete_item(SubGhzViewReceiver* subghz_receiver, uint16_t idx); void subghz_view_receiver_enable_draw_callback(SubGhzViewReceiver* subghz_receiver); From 77f458fb6ea27057962f3767bd54a5bc5253276e Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Thu, 21 Dec 2023 03:17:21 +0300 Subject: [PATCH 12/35] testing subghz dynamic limit based on freeheap + RPC by Willy-JL https://github.com/Flipper-XFW/Xtreme-Firmware/commit/5cd2d3eabe10e303b94e1960f8fa78a7ce45ce40 https://github.com/Flipper-XFW/Xtreme-Firmware/commit/e8d9325bec454603b79b33cef2337110af4e2c99 --- applications/main/subghz/subghz_history.c | 15 +++++++++------ applications/main/subghz/views/receiver.c | 22 ++++++++++++++++++++-- applications/services/rpc/rpc.c | 9 +++++++++ applications/services/rpc/rpc.h | 7 +++++++ targets/f7/api_symbols.csv | 1 + 5 files changed, 46 insertions(+), 8 deletions(-) diff --git a/applications/main/subghz/subghz_history.c b/applications/main/subghz/subghz_history.c index 048104f35..b18df0ee8 100644 --- a/applications/main/subghz/subghz_history.c +++ b/applications/main/subghz/subghz_history.c @@ -1,10 +1,11 @@ #include "subghz_history.h" #include +#include #include -#define SUBGHZ_HISTORY_MAX 55 -#define SUBGHZ_HISTORY_FREE_HEAP 20480 +#define SUBGHZ_HISTORY_MAX 65530 // uint16_t index max, ram limit below +#define SUBGHZ_HISTORY_FREE_HEAP (10240 * (3 - MIN(rpc_get_sessions_count(instance->rpc), 2U))) #define TAG "SubGhzHistory" typedef struct { @@ -29,6 +30,7 @@ struct SubGhzHistory { uint8_t code_last_hash_data; FuriString* tmp_string; SubGhzHistoryStruct* history; + Rpc* rpc; }; SubGhzHistory* subghz_history_alloc(void) { @@ -36,6 +38,7 @@ SubGhzHistory* subghz_history_alloc(void) { instance->tmp_string = furi_string_alloc(); instance->history = malloc(sizeof(SubGhzHistoryStruct)); SubGhzHistoryItemArray_init(instance->history->data); + instance->rpc = furi_record_open(RECORD_RPC); return instance; } @@ -52,6 +55,7 @@ void subghz_history_free(SubGhzHistory* instance) { } SubGhzHistoryItemArray_clear(instance->history->data); free(instance->history); + furi_record_close(RECORD_RPC); free(instance); } @@ -143,15 +147,14 @@ FlipperFormat* subghz_history_get_raw_data(SubGhzHistory* instance, uint16_t idx bool subghz_history_get_text_space_left(SubGhzHistory* instance, FuriString* output) { furi_assert(instance); if(memmgr_get_free_heap() < SUBGHZ_HISTORY_FREE_HEAP) { - if(output != NULL) furi_string_printf(output, " Free heap LOW"); + if(output != NULL) furi_string_printf(output, " Memory is FULL"); return true; } if(instance->last_index_write == SUBGHZ_HISTORY_MAX) { - if(output != NULL) furi_string_printf(output, " Memory is FULL"); + if(output != NULL) furi_string_printf(output, " History is FULL"); return true; } - if(output != NULL) - furi_string_printf(output, "%02u/%02u", instance->last_index_write, SUBGHZ_HISTORY_MAX); + if(output != NULL) furi_string_printf(output, "%02u", instance->last_index_write); return false; } diff --git a/applications/main/subghz/views/receiver.c b/applications/main/subghz/views/receiver.c index 98c15dbff..1d3967edb 100644 --- a/applications/main/subghz/views/receiver.c +++ b/applications/main/subghz/views/receiver.c @@ -383,7 +383,16 @@ void subghz_view_receiver_draw(Canvas* canvas, SubGhzViewReceiverModel* model) { #else canvas_draw_str(canvas, 79, 62, furi_string_get_cstr(model->preset_str)); #endif - canvas_draw_str(canvas, 96, 62, furi_string_get_cstr(model->history_stat_str)); + if(!furi_string_empty(model->history_stat_str)) { + canvas_draw_str_aligned( + canvas, + 114, + 62, + AlignRight, + AlignBottom, + furi_string_get_cstr(model->history_stat_str)); + canvas_draw_icon(canvas, 116, 53, &I_sub1_10px); + } canvas_set_font(canvas, FontSecondary); elements_bold_rounded_frame(canvas, 14, 8, 99, 48); elements_multiline_text(canvas, 65, 26, "To unlock\npress:"); @@ -419,7 +428,16 @@ void subghz_view_receiver_draw(Canvas* canvas, SubGhzViewReceiverModel* model) { #else canvas_draw_str(canvas, 79, 62, furi_string_get_cstr(model->preset_str)); #endif - canvas_draw_str(canvas, 96, 62, furi_string_get_cstr(model->history_stat_str)); + if(!furi_string_empty(model->history_stat_str)) { + canvas_draw_str_aligned( + canvas, + 114, + 62, + AlignRight, + AlignBottom, + furi_string_get_cstr(model->history_stat_str)); + canvas_draw_icon(canvas, 116, 53, &I_sub1_10px); + } } break; } } diff --git a/applications/services/rpc/rpc.c b/applications/services/rpc/rpc.c index 50c4b3608..6d9f31da0 100644 --- a/applications/services/rpc/rpc.c +++ b/applications/services/rpc/rpc.c @@ -87,6 +87,7 @@ struct RpcSession { struct Rpc { FuriMutex* busy_mutex; + size_t sessions_count; }; RpcOwner rpc_session_get_owner(RpcSession* session) { @@ -407,6 +408,8 @@ RpcSession* rpc_session_open(Rpc* rpc, RpcOwner owner) { furi_thread_start(session->thread); + rpc->sessions_count++; + return session; } @@ -414,6 +417,8 @@ void rpc_session_close(RpcSession* session) { furi_assert(session); furi_assert(session->rpc); + session->rpc->sessions_count--; + rpc_session_set_send_bytes_callback(session, NULL); rpc_session_set_close_callback(session, NULL); rpc_session_set_buffer_is_empty_callback(session, NULL); @@ -489,3 +494,7 @@ void rpc_send_and_release_empty(RpcSession* session, uint32_t command_id, PB_Com rpc_send_and_release(session, &message); pb_release(&PB_Main_msg, &message); } + +size_t rpc_get_sessions_count(Rpc* rpc) { + return rpc->sessions_count; +} diff --git a/applications/services/rpc/rpc.h b/applications/services/rpc/rpc.h index 863bca355..b1e7a4d47 100644 --- a/applications/services/rpc/rpc.h +++ b/applications/services/rpc/rpc.h @@ -134,6 +134,13 @@ size_t rpc_session_feed(RpcSession* session, uint8_t* buffer, size_t size, uint3 */ size_t rpc_session_get_available_size(RpcSession* session); +/** Get number of open RPC sessions + * + * @param rpc instance + * @return sessions count + */ +size_t rpc_get_sessions_count(Rpc* rpc); + #ifdef __cplusplus } #endif \ No newline at end of file diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index afce83fe5..0f15dc761 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -2709,6 +2709,7 @@ Function,-,rintl,long double,long double Function,-,round,double,double Function,+,roundf,float,float Function,-,roundl,long double,long double +Function,+,rpc_get_sessions_count,size_t,Rpc* Function,+,rpc_session_close,void,RpcSession* Function,+,rpc_session_feed,size_t,"RpcSession*, uint8_t*, size_t, uint32_t" Function,+,rpc_session_get_available_size,size_t,RpcSession* From eaae5da51914a5ac5132d3540dda81c8a79c158d Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Thu, 21 Dec 2023 03:28:53 +0300 Subject: [PATCH 13/35] faac rcxt add manually (not tested) --- .../main/subghz/helpers/subghz_custom_event.h | 2 + .../subghz/scenes/subghz_scene_set_type.c | 42 +++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/applications/main/subghz/helpers/subghz_custom_event.h b/applications/main/subghz/helpers/subghz_custom_event.h index fec4c66c5..6838b345d 100644 --- a/applications/main/subghz/helpers/subghz_custom_event.h +++ b/applications/main/subghz/helpers/subghz_custom_event.h @@ -27,6 +27,8 @@ typedef enum { SubmenuIndexGibidi433, SubmenuIndexNiceMHouse_433_92, SubmenuIndexJCM_433_92, + SubmenuIndexFAACRCXT_433_92, + SubmenuIndexFAACRCXT_868, SubmenuIndexNormstahl_433_92, SubmenuIndexGSN, SubmenuIndexAprimatic, diff --git a/applications/main/subghz/scenes/subghz_scene_set_type.c b/applications/main/subghz/scenes/subghz_scene_set_type.c index 28db55d75..2d6181851 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_type.c +++ b/applications/main/subghz/scenes/subghz_scene_set_type.c @@ -181,6 +181,18 @@ void subghz_scene_set_type_on_enter(void* context) { SubmenuIndexJCM_433_92, subghz_scene_set_type_submenu_callback, subghz); + submenu_add_item( + subghz->submenu, + "KL: FAAC RC,XT 433MHz", + SubmenuIndexFAACRCXT_433_92, + subghz_scene_set_type_submenu_callback, + subghz); + submenu_add_item( + subghz->submenu, + "KL: FAAC RC,XT 868MHz", + SubmenuIndexFAACRCXT_868, + subghz_scene_set_type_submenu_callback, + subghz); submenu_add_item( subghz->submenu, "KL: Nice Mhouse 433MHz", @@ -744,6 +756,36 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); } break; + case SubmenuIndexFAACRCXT_433_92: + generated_protocol = subghz_txrx_gen_keeloq_protocol( + subghz->txrx, + "AM650", + 433920000, + (key & 0x0000FFFF) | 0x00100000, + 0x2, + 0x0003, + "FAAC_RC,XT"); + if(!generated_protocol) { + furi_string_set( + subghz->error_str, "Function requires\nan SD card with\nfresh databases."); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); + } + break; + case SubmenuIndexFAACRCXT_868: + generated_protocol = subghz_txrx_gen_keeloq_protocol( + subghz->txrx, + "AM650", + 868350000, + (key & 0x0000FFFF) | 0x00100000, + 0x2, + 0x0003, + "FAAC_RC,XT"); + if(!generated_protocol) { + furi_string_set( + subghz->error_str, "Function requires\nan SD card with\nfresh databases."); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); + } + break; case SubmenuIndexNormstahl_433_92: generated_protocol = subghz_txrx_gen_keeloq_protocol( subghz->txrx, "AM650", 433920000, key & 0x00FFFFFF, 0x2, 0x0003, "Normstahl"); From 271ec6cf97077bf0721c1585c47510881048564e Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Thu, 21 Dec 2023 03:37:44 +0300 Subject: [PATCH 14/35] fix readme --- ReadMe.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReadMe.md b/ReadMe.md index e5da572cc..18fcc7c06 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -100,7 +100,7 @@ Also check the [changelog in releases](https://github.com/DarkFlippers/unleashed ### Current modified and new Sub-GHz protocols list: Thanks to Official team (to their SubGHz Developer, Skorp) for implementing decoders for these protocols in OFW. -Keeloq [Not ALL systems supported for decode or emulation yet!] - [Supported manufacturers list](https://0bin.net/paste/VwR2lNJY#WH9vnPgvcp7w6zVKucFCuNREKAcOij8KsJ6vqLfMn3b) +Keeloq [Not ALL systems supported for decode or emulation!] - [Supported manufacturers list](https://pastes.io/raw/unuj9bhe4m) Encoders or sending made by @xMasterX: - Nero Radio 57bit (+ 56bit encoder improvements) From 1acbd84b7c389627a2b060dca80cf229820e7c4f Mon Sep 17 00:00:00 2001 From: amec0e <88857687+amec0e@users.noreply.github.com> Date: Thu, 21 Dec 2023 15:39:57 +0000 Subject: [PATCH 15/35] Update tv.ir New additions --- .../main/infrared/resources/infrared/assets/tv.ir | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/applications/main/infrared/resources/infrared/assets/tv.ir b/applications/main/infrared/resources/infrared/assets/tv.ir index d2164b16d..9e2f13b40 100755 --- a/applications/main/infrared/resources/infrared/assets/tv.ir +++ b/applications/main/infrared/resources/infrared/assets/tv.ir @@ -1,7 +1,7 @@ Filetype: IR library file Version: 1 -# Last Updated 29th Oct, 2023 -# Last Checked 29th Oct, 2023 +# Last Updated 21st Dec, 2023 +# Last Checked 21st Dec, 2023 # name: Power type: parsed @@ -2459,3 +2459,9 @@ type: parsed protocol: NEC address: 38 00 00 00 command: 1C 00 00 00 +# +name: Mute +type: parsed +protocol: NEC +address: 38 00 00 00 +command: 04 00 00 00 From c5a76af1dd316aea4f2d102b08f9d9c73fbbe9bb Mon Sep 17 00:00:00 2001 From: amec0e <88857687+amec0e@users.noreply.github.com> Date: Thu, 21 Dec 2023 15:40:44 +0000 Subject: [PATCH 16/35] Update projectors.ir Updated last checked, no new additions --- .../main/infrared/resources/infrared/assets/projectors.ir | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/main/infrared/resources/infrared/assets/projectors.ir b/applications/main/infrared/resources/infrared/assets/projectors.ir index 2fef79ee4..35c9485da 100644 --- a/applications/main/infrared/resources/infrared/assets/projectors.ir +++ b/applications/main/infrared/resources/infrared/assets/projectors.ir @@ -1,7 +1,7 @@ Filetype: IR library file Version: 1 # Last Updated 1st Oct, 2023 -# Last Checked 1st Oct, 2023 +# Last Checked 21st Dec, 2023 # # TEMP FIX FOR POWER # From cdede67f311586d83b0d87795d0e4af33fb81acf Mon Sep 17 00:00:00 2001 From: amec0e <88857687+amec0e@users.noreply.github.com> Date: Thu, 21 Dec 2023 15:41:08 +0000 Subject: [PATCH 17/35] Update fans.ir New additions --- .../resources/infrared/assets/fans.ir | 40 ++++++++++++++++++- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/applications/main/infrared/resources/infrared/assets/fans.ir b/applications/main/infrared/resources/infrared/assets/fans.ir index 938bc96a6..1c0360a1d 100644 --- a/applications/main/infrared/resources/infrared/assets/fans.ir +++ b/applications/main/infrared/resources/infrared/assets/fans.ir @@ -1,7 +1,7 @@ Filetype: IR library file Version: 1 -#Last Updated 1st Oct, 2023 -#Last Checked 1st Oct, 2023 +#Last Updated 21st Dec, 2023 +#Last Checked 21st Dec, 2023 # name: Power type: raw @@ -2103,3 +2103,39 @@ type: raw frequency: 38000 duty_cycle: 0.33 data: 1330 376 1303 376 460 1192 1331 376 1302 376 459 1191 463 1217 462 1218 1331 376 459 1195 484 1219 460 7907 1300 379 1300 380 456 1223 1300 380 1300 380 456 1224 456 1224 456 1224 1299 380 456 1224 456 1224 456 8166 1299 380 1299 380 456 1224 1299 380 1299 380 456 1224 456 1224 455 1224 1299 380 456 1224 455 1224 456 7909 1299 380 1299 380 455 1224 1299 380 1299 380 456 1224 455 1225 455 1225 1298 381 455 1225 454 1225 455 +# +name: Power +type: raw +frequency: 38000 +duty_cycle: 0.33 +data: 9213 4493 613 530 612 529 613 528 614 526 616 1631 615 1631 615 529 613 528 614 1631 615 1631 615 1632 614 1632 614 529 613 528 614 1632 614 1630 616 527 615 1631 615 528 614 1634 611 527 614 527 615 527 615 1630 616 1635 611 528 614 1632 614 527 615 1634 612 1631 615 1632 614 527 615 39730 9215 2228 617 95835 9215 2231 614 +# +name: Speed_up +type: parsed +protocol: NEC +address: 30 00 00 00 +command: 89 00 00 00 +# +name: Timer +type: raw +frequency: 38000 +duty_cycle: 0.33 +data: 9279 4487 620 526 617 528 614 527 615 527 615 1633 612 1631 614 526 615 527 614 1634 611 1631 614 1633 612 1633 612 529 612 531 610 1633 612 1632 614 528 613 1630 615 1633 613 1632 613 526 615 529 613 527 615 1633 613 1632 614 526 615 526 616 527 615 1632 614 1631 614 1632 614 526 615 39731 9204 2230 614 +# +name: Power +type: raw +frequency: 38000 +duty_cycle: 0.33 +data: 2227 839 757 1597 751 1599 749 829 757 815 750 817 748 814 751 806 749 866 751 836 750 832 754 823 753 819 757 811 754 807 758 799 756 103041 2229 837 749 1605 754 1597 751 826 750 823 753 815 750 812 753 804 751 864 753 834 752 830 756 821 755 818 758 809 756 806 749 808 757 64662 2229 774 749 1558 748 60749 2229 775 748 1559 758 +# +name: Speed_up +type: raw +frequency: 38000 +duty_cycle: 0.33 +data: 2222 843 753 1626 732 1590 758 820 756 817 759 808 757 804 751 806 749 893 724 1603 755 827 748 1595 753 820 756 1578 759 1570 757 827 728 99745 2231 834 752 1601 757 1592 756 821 755 817 759 808 757 805 750 807 758 856 751 1630 728 827 749 1622 726 820 756 1605 732 1570 757 800 755 +# +name: Speed_dn +type: raw +frequency: 38000 +duty_cycle: 0.33 +data: 2221 844 752 1600 758 1591 757 820 756 816 749 817 748 813 752 804 751 1632 758 1596 752 1597 751 1594 754 1585 752 1582 756 806 749 808 757 102464 2224 841 756 1597 751 1599 749 828 748 824 752 815 750 811 754 802 753 1629 750 1604 754 1595 753 1591 757 1583 755 1579 759 804 751 806 749 From 18194b6bb58107a227808389edc6edb95a09d33d Mon Sep 17 00:00:00 2001 From: amec0e <88857687+amec0e@users.noreply.github.com> Date: Thu, 21 Dec 2023 15:41:32 +0000 Subject: [PATCH 18/35] Update audio.ir New additions --- .../resources/infrared/assets/audio.ir | 160 +++++++++++++++++- 1 file changed, 158 insertions(+), 2 deletions(-) diff --git a/applications/main/infrared/resources/infrared/assets/audio.ir b/applications/main/infrared/resources/infrared/assets/audio.ir index 724c7c572..ffa108bc4 100644 --- a/applications/main/infrared/resources/infrared/assets/audio.ir +++ b/applications/main/infrared/resources/infrared/assets/audio.ir @@ -1,7 +1,7 @@ Filetype: IR library file Version: 1 -# Last Updated 1st Sept, 2023 -# Last Checked 1st Oct, 2023 +# Last Updated 21st Dec, 2023 +# Last Checked 21st Dec, 2023 # name: Power type: parsed @@ -3896,3 +3896,159 @@ type: parsed protocol: NECext address: 80 70 00 00 command: C1 3E 00 00 +# +name: Power +type: parsed +protocol: NECext +address: 87 7C 00 00 +command: C8 37 00 00 +# +name: Pause +type: parsed +protocol: NECext +address: 87 7C 00 00 +command: 4A B5 00 00 +# +name: Play +type: parsed +protocol: NECext +address: 87 7C 00 00 +command: 01 FE 00 00 +# +name: Prev +type: parsed +protocol: NECext +address: 87 7C 00 00 +command: 05 FA 00 00 +# +name: Next +type: parsed +protocol: NECext +address: 87 7C 00 00 +command: 06 F9 00 00 +# +name: Power +type: parsed +protocol: NECext +address: 12 34 00 00 +command: 01 FE 00 00 +# +name: Vol_up +type: parsed +protocol: NECext +address: 12 34 00 00 +command: 0A F5 00 00 +# +name: Vol_dn +type: parsed +protocol: NECext +address: 12 34 00 00 +command: 0B F4 00 00 +# +name: Mute +type: parsed +protocol: NECext +address: 12 34 00 00 +command: 09 F6 00 00 +# +name: Power +type: parsed +protocol: NEC +address: 01 00 00 00 +command: 67 00 00 00 +# +name: Next +type: parsed +protocol: NEC +address: 01 00 00 00 +command: 38 00 00 00 +# +name: Vol_up +type: parsed +protocol: NEC +address: 01 00 00 00 +command: 3C 00 00 00 +# +name: Vol_dn +type: parsed +protocol: NEC +address: 01 00 00 00 +command: 3D 00 00 00 +# +name: Mute +type: parsed +protocol: NEC +address: 01 00 00 00 +command: 8C 00 00 00 +# +name: Prev +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 44 00 00 00 +# +name: Vol_dn +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 07 00 00 00 +# +name: Vol_up +type: parsed +protocol: NEC +address: 00 00 00 00 +command: 1C 00 00 00 +# +name: Power +type: raw +frequency: 38000 +duty_cycle: 0.33 +data: 9120 4354 714 1539 660 497 633 499 631 500 630 503 628 503 628 503 629 503 628 503 628 1627 628 1627 628 1627 628 1627 628 1626 628 1627 628 1627 628 1627 628 1627 628 503 628 503 628 503 628 503 628 504 627 503 628 504 627 503 628 1627 628 1628 627 1628 627 1627 628 1627 628 1628 627 40094 9038 2194 628 +# +name: Prev +type: parsed +protocol: NEC +address: 01 00 00 00 +command: 5A 00 00 00 +# +name: Next +type: parsed +protocol: NEC +address: 01 00 00 00 +command: 5B 00 00 00 +# +name: Pause +type: parsed +protocol: NEC +address: 01 00 00 00 +command: B2 00 00 00 +# +name: Pause +type: parsed +protocol: NECext +address: 00 EF 00 00 +command: 11 EE 00 00 +# +name: Pause +type: parsed +protocol: NEC +address: 01 00 00 00 +command: 2C 00 00 00 +# +name: Play +type: parsed +protocol: NEC +address: 01 00 00 00 +command: B2 00 00 00 +# +name: Play +type: parsed +protocol: NECext +address: 00 EF 00 00 +command: 11 EE 00 00 +# +name: Play +type: parsed +protocol: NEC +address: 01 00 00 00 +command: 2C 00 00 00 From 1543170f4cfa4ef23616c7a3d83704107e703919 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Thu, 21 Dec 2023 16:43:11 +0000 Subject: [PATCH 19/35] [FL-3729, FL-3730] Gui: fix string width calculation (#3305) --- applications/services/gui/canvas.c | 8 ++++---- applications/services/gui/canvas_i.h | 2 +- lib/u8g2/u8g2.h | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/applications/services/gui/canvas.c b/applications/services/gui/canvas.c index 209c82a82..c7e7dc355 100644 --- a/applications/services/gui/canvas.c +++ b/applications/services/gui/canvas.c @@ -321,10 +321,10 @@ static void canvas_draw_u8g2_bitmap_int( void canvas_draw_u8g2_bitmap( u8g2_t* u8g2, - u8g2_uint_t x, - u8g2_uint_t y, - u8g2_uint_t w, - u8g2_uint_t h, + uint8_t x, + uint8_t y, + uint8_t w, + uint8_t h, const uint8_t* bitmap, IconRotation rotation) { u8g2_uint_t blen; diff --git a/applications/services/gui/canvas_i.h b/applications/services/gui/canvas_i.h index f3b8f17ad..5f7d69e72 100644 --- a/applications/services/gui/canvas_i.h +++ b/applications/services/gui/canvas_i.h @@ -96,4 +96,4 @@ void canvas_draw_u8g2_bitmap( uint8_t width, uint8_t height, const uint8_t* bitmap, - uint8_t rotation); + IconRotation rotation); diff --git a/lib/u8g2/u8g2.h b/lib/u8g2/u8g2.h index 68611d482..540b7a873 100644 --- a/lib/u8g2/u8g2.h +++ b/lib/u8g2/u8g2.h @@ -67,7 +67,7 @@ Use 16 Bit mode for any display with more than 240 pixel in one direction. */ -//#define U8G2_16BIT +#define U8G2_16BIT /* The following macro switches the library into dynamic display buffer allocation mode. From bcadbc6353961b4a7da8aaf6e8769ee0565ea2ad Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Thu, 21 Dec 2023 19:45:45 +0300 Subject: [PATCH 20/35] Revert "fix broken texts due to usage of utf8, add proper api" This reverts commit 49b2a4da8a17f0d63a7bc8d6b1c011bea964398f. --- .../example_custom_font/example_custom_font.c | 6 +- applications/services/gui/canvas.c | 57 ------------------- applications/services/gui/canvas.h | 38 ------------- targets/f7/api_symbols.csv | 3 - 4 files changed, 3 insertions(+), 101 deletions(-) diff --git a/applications/debug/example_custom_font/example_custom_font.c b/applications/debug/example_custom_font/example_custom_font.c index 334aa8aa8..8d85f23c6 100644 --- a/applications/debug/example_custom_font/example_custom_font.c +++ b/applications/debug/example_custom_font/example_custom_font.c @@ -72,9 +72,9 @@ static void app_draw_callback(Canvas* canvas, void* ctx) { canvas_set_custom_u8g2_font(canvas, u8g2_font_4x6_t_cyrillic); - canvas_draw_utf8_str(canvas, 0, 6, "This is a tiny custom font"); - canvas_draw_utf8_str(canvas, 0, 12, "012345.?! ,:;\"\'@#$%"); - canvas_draw_utf8_str(canvas, 0, 18, "И немного юникода"); + canvas_draw_str(canvas, 0, 6, "This is a tiny custom font"); + canvas_draw_str(canvas, 0, 12, "012345.?! ,:;\"\'@#$%"); + canvas_draw_str(canvas, 0, 18, "И немного юникода"); } static void app_input_callback(InputEvent* input_event, void* ctx) { diff --git a/applications/services/gui/canvas.c b/applications/services/gui/canvas.c index 3cd35e402..f8f33da9b 100644 --- a/applications/services/gui/canvas.c +++ b/applications/services/gui/canvas.c @@ -154,14 +154,6 @@ void canvas_set_custom_u8g2_font(Canvas* canvas, const uint8_t* font) { } void canvas_draw_str(Canvas* canvas, uint8_t x, uint8_t y, const char* str) { - furi_assert(canvas); - if(!str) return; - x += canvas->offset_x; - y += canvas->offset_y; - u8g2_DrawStr(&canvas->fb, x, y, str); -} - -void canvas_draw_utf8_str(Canvas* canvas, uint8_t x, uint8_t y, const char* str) { furi_assert(canvas); if(!str) return; x += canvas->offset_x; @@ -181,49 +173,6 @@ void canvas_draw_str_aligned( x += canvas->offset_x; y += canvas->offset_y; - switch(horizontal) { - case AlignLeft: - break; - case AlignRight: - x -= u8g2_GetStrWidth(&canvas->fb, str); - break; - case AlignCenter: - x -= (u8g2_GetStrWidth(&canvas->fb, str) / 2); - break; - default: - furi_crash(); - break; - } - - switch(vertical) { - case AlignTop: - y += u8g2_GetAscent(&canvas->fb); - break; - case AlignBottom: - break; - case AlignCenter: - y += (u8g2_GetAscent(&canvas->fb) / 2); - break; - default: - furi_crash(); - break; - } - - u8g2_DrawStr(&canvas->fb, x, y, str); -} - -void canvas_draw_utf8_str_aligned( - Canvas* canvas, - uint8_t x, - uint8_t y, - Align horizontal, - Align vertical, - const char* str) { - furi_assert(canvas); - if(!str) return; - x += canvas->offset_x; - y += canvas->offset_y; - switch(horizontal) { case AlignLeft: break; @@ -256,12 +205,6 @@ void canvas_draw_utf8_str_aligned( } uint16_t canvas_string_width(Canvas* canvas, const char* str) { - furi_assert(canvas); - if(!str) return 0; - return u8g2_GetStrWidth(&canvas->fb, str); -} - -uint16_t canvas_utf8_string_width(Canvas* canvas, const char* str) { furi_assert(canvas); if(!str) return 0; return u8g2_GetUTF8Width(&canvas->fb, str); diff --git a/applications/services/gui/canvas.h b/applications/services/gui/canvas.h index afed58548..bda730ff2 100644 --- a/applications/services/gui/canvas.h +++ b/applications/services/gui/canvas.h @@ -187,15 +187,6 @@ void canvas_set_custom_u8g2_font(Canvas* canvas, const uint8_t* font); */ void canvas_draw_str(Canvas* canvas, uint8_t x, uint8_t y, const char* str); -/** Draw UTF8 string at position of baseline defined by x, y. - * - * @param canvas Canvas instance - * @param x anchor point x coordinate - * @param y anchor point y coordinate - * @param str C-string - */ -void canvas_draw_utf8_str(Canvas* canvas, uint8_t x, uint8_t y, const char* str); - /** Draw aligned string defined by x, y. * * Align calculated from position of baseline, string width and ascent (height @@ -216,26 +207,6 @@ void canvas_draw_str_aligned( Align vertical, const char* str); -/** Draw aligned UTF8 string defined by x, y. - * - * Align calculated from position of baseline, string width and ascent (height - * of the glyphs above the baseline) - * - * @param canvas Canvas instance - * @param x anchor point x coordinate - * @param y anchor point y coordinate - * @param horizontal horizontal alignment - * @param vertical vertical alignment - * @param str C-string - */ -void canvas_draw_utf8_str_aligned( - Canvas* canvas, - uint8_t x, - uint8_t y, - Align horizontal, - Align vertical, - const char* str); - /** Get string width * * @param canvas Canvas instance @@ -245,15 +216,6 @@ void canvas_draw_utf8_str_aligned( */ uint16_t canvas_string_width(Canvas* canvas, const char* str); -/** Get UTF8 string width - * - * @param canvas Canvas instance - * @param str C-string - * - * @return width in pixels. - */ -uint16_t canvas_utf8_string_width(Canvas* canvas, const char* str); - /** Get glyph width * * @param canvas Canvas instance diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 0f15dc761..769763f81 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -735,8 +735,6 @@ Function,+,canvas_draw_rframe,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t, Function,+,canvas_draw_str,void,"Canvas*, uint8_t, uint8_t, const char*" Function,+,canvas_draw_str_aligned,void,"Canvas*, uint8_t, uint8_t, Align, Align, const char*" Function,+,canvas_draw_triangle,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t, CanvasDirection" -Function,+,canvas_draw_utf8_str,void,"Canvas*, uint8_t, uint8_t, const char*" -Function,+,canvas_draw_utf8_str_aligned,void,"Canvas*, uint8_t, uint8_t, Align, Align, const char*" Function,+,canvas_draw_xbm,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t, const uint8_t*" Function,+,canvas_get_font_params,const CanvasFontParameters*,"const Canvas*, Font" Function,+,canvas_glyph_width,uint8_t,"Canvas*, uint16_t" @@ -749,7 +747,6 @@ Function,+,canvas_set_custom_u8g2_font,void,"Canvas*, const uint8_t*" Function,+,canvas_set_font,void,"Canvas*, Font" Function,+,canvas_set_font_direction,void,"Canvas*, CanvasDirection" Function,+,canvas_string_width,uint16_t,"Canvas*, const char*" -Function,+,canvas_utf8_string_width,uint16_t,"Canvas*, const char*" Function,+,canvas_width,uint8_t,const Canvas* Function,-,cbrt,double,double Function,-,cbrtf,float,float From 4d56bb4e443146a8d460dbea541e553e5148503f Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Thu, 21 Dec 2023 21:42:17 +0300 Subject: [PATCH 21/35] Revert "testing subghz dynamic limit based on freeheap + RPC" This reverts commit 77f458fb6ea27057962f3767bd54a5bc5253276e. --- applications/main/subghz/subghz_history.c | 15 ++++++--------- applications/main/subghz/views/receiver.c | 22 ++-------------------- applications/services/rpc/rpc.c | 9 --------- applications/services/rpc/rpc.h | 7 ------- targets/f7/api_symbols.csv | 1 - 5 files changed, 8 insertions(+), 46 deletions(-) diff --git a/applications/main/subghz/subghz_history.c b/applications/main/subghz/subghz_history.c index b18df0ee8..048104f35 100644 --- a/applications/main/subghz/subghz_history.c +++ b/applications/main/subghz/subghz_history.c @@ -1,11 +1,10 @@ #include "subghz_history.h" #include -#include #include -#define SUBGHZ_HISTORY_MAX 65530 // uint16_t index max, ram limit below -#define SUBGHZ_HISTORY_FREE_HEAP (10240 * (3 - MIN(rpc_get_sessions_count(instance->rpc), 2U))) +#define SUBGHZ_HISTORY_MAX 55 +#define SUBGHZ_HISTORY_FREE_HEAP 20480 #define TAG "SubGhzHistory" typedef struct { @@ -30,7 +29,6 @@ struct SubGhzHistory { uint8_t code_last_hash_data; FuriString* tmp_string; SubGhzHistoryStruct* history; - Rpc* rpc; }; SubGhzHistory* subghz_history_alloc(void) { @@ -38,7 +36,6 @@ SubGhzHistory* subghz_history_alloc(void) { instance->tmp_string = furi_string_alloc(); instance->history = malloc(sizeof(SubGhzHistoryStruct)); SubGhzHistoryItemArray_init(instance->history->data); - instance->rpc = furi_record_open(RECORD_RPC); return instance; } @@ -55,7 +52,6 @@ void subghz_history_free(SubGhzHistory* instance) { } SubGhzHistoryItemArray_clear(instance->history->data); free(instance->history); - furi_record_close(RECORD_RPC); free(instance); } @@ -147,14 +143,15 @@ FlipperFormat* subghz_history_get_raw_data(SubGhzHistory* instance, uint16_t idx bool subghz_history_get_text_space_left(SubGhzHistory* instance, FuriString* output) { furi_assert(instance); if(memmgr_get_free_heap() < SUBGHZ_HISTORY_FREE_HEAP) { - if(output != NULL) furi_string_printf(output, " Memory is FULL"); + if(output != NULL) furi_string_printf(output, " Free heap LOW"); return true; } if(instance->last_index_write == SUBGHZ_HISTORY_MAX) { - if(output != NULL) furi_string_printf(output, " History is FULL"); + if(output != NULL) furi_string_printf(output, " Memory is FULL"); return true; } - if(output != NULL) furi_string_printf(output, "%02u", instance->last_index_write); + if(output != NULL) + furi_string_printf(output, "%02u/%02u", instance->last_index_write, SUBGHZ_HISTORY_MAX); return false; } diff --git a/applications/main/subghz/views/receiver.c b/applications/main/subghz/views/receiver.c index 1d3967edb..98c15dbff 100644 --- a/applications/main/subghz/views/receiver.c +++ b/applications/main/subghz/views/receiver.c @@ -383,16 +383,7 @@ void subghz_view_receiver_draw(Canvas* canvas, SubGhzViewReceiverModel* model) { #else canvas_draw_str(canvas, 79, 62, furi_string_get_cstr(model->preset_str)); #endif - if(!furi_string_empty(model->history_stat_str)) { - canvas_draw_str_aligned( - canvas, - 114, - 62, - AlignRight, - AlignBottom, - furi_string_get_cstr(model->history_stat_str)); - canvas_draw_icon(canvas, 116, 53, &I_sub1_10px); - } + canvas_draw_str(canvas, 96, 62, furi_string_get_cstr(model->history_stat_str)); canvas_set_font(canvas, FontSecondary); elements_bold_rounded_frame(canvas, 14, 8, 99, 48); elements_multiline_text(canvas, 65, 26, "To unlock\npress:"); @@ -428,16 +419,7 @@ void subghz_view_receiver_draw(Canvas* canvas, SubGhzViewReceiverModel* model) { #else canvas_draw_str(canvas, 79, 62, furi_string_get_cstr(model->preset_str)); #endif - if(!furi_string_empty(model->history_stat_str)) { - canvas_draw_str_aligned( - canvas, - 114, - 62, - AlignRight, - AlignBottom, - furi_string_get_cstr(model->history_stat_str)); - canvas_draw_icon(canvas, 116, 53, &I_sub1_10px); - } + canvas_draw_str(canvas, 96, 62, furi_string_get_cstr(model->history_stat_str)); } break; } } diff --git a/applications/services/rpc/rpc.c b/applications/services/rpc/rpc.c index 6d9f31da0..50c4b3608 100644 --- a/applications/services/rpc/rpc.c +++ b/applications/services/rpc/rpc.c @@ -87,7 +87,6 @@ struct RpcSession { struct Rpc { FuriMutex* busy_mutex; - size_t sessions_count; }; RpcOwner rpc_session_get_owner(RpcSession* session) { @@ -408,8 +407,6 @@ RpcSession* rpc_session_open(Rpc* rpc, RpcOwner owner) { furi_thread_start(session->thread); - rpc->sessions_count++; - return session; } @@ -417,8 +414,6 @@ void rpc_session_close(RpcSession* session) { furi_assert(session); furi_assert(session->rpc); - session->rpc->sessions_count--; - rpc_session_set_send_bytes_callback(session, NULL); rpc_session_set_close_callback(session, NULL); rpc_session_set_buffer_is_empty_callback(session, NULL); @@ -494,7 +489,3 @@ void rpc_send_and_release_empty(RpcSession* session, uint32_t command_id, PB_Com rpc_send_and_release(session, &message); pb_release(&PB_Main_msg, &message); } - -size_t rpc_get_sessions_count(Rpc* rpc) { - return rpc->sessions_count; -} diff --git a/applications/services/rpc/rpc.h b/applications/services/rpc/rpc.h index b1e7a4d47..863bca355 100644 --- a/applications/services/rpc/rpc.h +++ b/applications/services/rpc/rpc.h @@ -134,13 +134,6 @@ size_t rpc_session_feed(RpcSession* session, uint8_t* buffer, size_t size, uint3 */ size_t rpc_session_get_available_size(RpcSession* session); -/** Get number of open RPC sessions - * - * @param rpc instance - * @return sessions count - */ -size_t rpc_get_sessions_count(Rpc* rpc); - #ifdef __cplusplus } #endif \ No newline at end of file diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 769763f81..3ab58f58d 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -2706,7 +2706,6 @@ Function,-,rintl,long double,long double Function,-,round,double,double Function,+,roundf,float,float Function,-,roundl,long double,long double -Function,+,rpc_get_sessions_count,size_t,Rpc* Function,+,rpc_session_close,void,RpcSession* Function,+,rpc_session_feed,size_t,"RpcSession*, uint8_t*, size_t, uint32_t" Function,+,rpc_session_get_available_size,size_t,RpcSession* From 531ba24e9a1af8ff007e72dd976cb66259895bc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Fri, 22 Dec 2023 11:08:46 +0000 Subject: [PATCH 22/35] Rollback #3305 and #3297 fix various rendering issues (#3307) * Revert "[FL-3729, FL-3730] Gui: fix string width calculation (#3305)" * Revert "Added UTF-8 support to Flipper Zero canvas API (#3297)" --- .../example_custom_font/example_custom_font.c | 86 +++++++------------ applications/services/gui/canvas.c | 18 ++-- applications/services/gui/canvas_i.h | 2 +- lib/u8g2/u8g2.h | 2 +- 4 files changed, 40 insertions(+), 68 deletions(-) diff --git a/applications/debug/example_custom_font/example_custom_font.c b/applications/debug/example_custom_font/example_custom_font.c index 8d85f23c6..15eeb5f02 100644 --- a/applications/debug/example_custom_font/example_custom_font.c +++ b/applications/debug/example_custom_font/example_custom_font.c @@ -7,62 +7,35 @@ //This arrays contains the font itself. You can use any u8g2 font you want /* - Fontname: -Misc-Fixed-Medium-R-Normal--6-60-75-75-C-40-ISO10646-1 - Copyright: Public domain font. Share and enjoy. - Glyphs: 191/919 - BBX Build Mode: 0 +Fontname: -Raccoon-Fixed4x6-Medium-R-Normal--6-60-75-75-P-40-ISO10646-1 +Copyright: +Glyphs: 95/203 +BBX Build Mode: 0 */ -const uint8_t u8g2_font_4x6_t_cyrillic[] = - "\277\0\2\2\3\3\2\4\4\4\6\0\377\5\377\5\377\0\356\1\334\2\301 \5\200\315\0!\6\351\310" - "\254\0\42\6\223\313$\25#\12\254\310\244\64T\32*\1$\11\263\307\245\241\301H\11%\10\253\310d" - "\324F\1&\11\254\310\305\24\253\230\2'\5\321\313\10(\7\362\307\251f\0)\10\262\307\304T)\0" - "*\7\253\310\244j\65+\10\253\310\305\264b\2,\6\222\307)\0-\5\213\312\14.\5\311\310\4/" - "\7\253\310Ve\4\60\10\253\310UCU\0\61\7\253\310%Y\15\62\7\253\310\65S\32\63\10\253\310" - "\314\224\301\2\64\10\253\310$\65b\1\65\10\253\310\214\250\301\2\66\7\253\310M\325\2\67\10\253\310\314" - "TF\0\70\7\253\310\255\326\2\71\7\253\310\265\344\2:\6\341\310\304\0;\7\252\307e\250\0<\10" - "\253\310\246\32d\20=\6\233\311l\60>\11\253\310d\220A*\1\77\11\253\310h\220\62L\0@\7" - "\253\310-\33\10A\10\253\310UC\251\0B\10\253\310\250\264\322\2C\10\253\310U\62U\0D\10\253" - "\310\250d-\0E\10\253\310\214\250\342\0F\10\253\310\214\250b\4G\10\253\310\315\244\222\0H\10\253" - "\310$\65\224\12I\7\253\310\254X\15J\7\253\310\226\252\2K\10\253\310$\265\222\12L\7\253\310\304" - "\346\0M\10\253\310\244\61\224\12N\10\253\310\252\241$\0O\7\253\310UV\5P\10\253\310\250\264b" - "\4Q\10\263\307UV\15\2R\10\253\310\250\264\222\12S\10\253\310m\220\301\2T\7\253\310\254\330\2" - "U\7\253\310$\327\10V\10\253\310$k\244\4W\10\253\310$\65\206\12X\10\253\310$\325R\1Y" - "\10\253\310$UV\0Z\7\253\310\314T\16[\6\352\310\254J\134\11\253\310\304\14\62\210\1]\6\252" - "\310\250j^\5\223\313\65_\5\213\307\14`\6\322\313\304\0a\7\243\310-\225\4b\10\253\310D\225" - "\324\2c\7\243\310\315\14\4d\10\253\310\246\245\222\0e\6\243\310USf\10\253\310\246\264b\2g" - "\10\253\307\255$\27\0h\10\253\310D\225\254\0i\10\253\310e$\323\0j\10\263\307fX.\0k" - "\10\253\310\304\264\222\12l\7\253\310\310\326\0m\10\243\310\244\241T\0n\7\243\310\250d\5o\7\243" - "\310U\252\2p\10\253\307\250\264b\4q\10\253\307-\225d\0r\10\243\310\244\25#\0s\10\243\310" - "\215\14\26\0t\10\253\310\245\25\63\10u\7\243\310$+\11v\7\243\310$\253\2w\10\243\310$\65" - "T\0x\7\243\310\244\62\25y\10\253\307$\225\344\2z\7\243\310\314\224\6{\10\263\307\246$k\20" - "|\6\351\310\14\1}\11\263\307d\20UL\21~\7\224\313%\225\0\0\0\0\4\377\377\4\1\11\253" - "\310\244\261\342\0\4\2\11\253\310\214\250\222\12\4\3\10\253\310\16Y\2\4\4\11\253\310M\225\201\0\4" - "\5\11\253\310m\220\301\2\4\6\10\253\310\254X\15\4\7\11\253\310\244\221b\32\4\10\10\253\310\226\252" - "\2\4\11\11\254\310L\325Z\2\4\12\11\254\310\244\326JK\4\13\11\253\310\250\250\222\12\4\14\10\253" - "\310\312\264\12\4\16\11\263\307\244\32u\2\4\17\11\263\307$\327H\11\4\20\11\253\310UC\251\0\4" - "\21\11\253\310\214\250\322\2\4\22\11\253\310\250\264\322\2\4\23\10\253\310\214\330\4\4\24\11\263\307\254\245" - "\206\12\4\25\11\253\310\214\250\342\0\4\26\12\253\310\244\221\322H\1\4\27\12\253\310h\220\62X\0\4" - "\30\11\253\310\304\64T\14\4\31\11\263\307\315\64T\14\4\32\11\253\310$\265\222\12\4\33\10\253\310-" - "W\0\4\34\11\253\310\244\241\254\0\4\35\11\253\310$\65\224\12\4\36\10\253\310UV\5\4\37\10\253" - "\310\214\344\12\4 \11\253\310\250\264b\4\4!\11\253\310U\62U\0\4\42\10\253\310\254\330\2\4#" - "\11\263\307$\253L\21\4$\12\253\310\245\221FJ\0\4%\11\253\310$\325R\1\4&\10\253\310$" - "\327\10\4'\11\253\310$\225d\1\4(\11\253\310$\65\216\0\4)\12\264\307\244\326#\203\0\4*" - "\13\254\310h\220\201LI\1\4+\12\254\310D\271\324H\1\4,\11\253\310\304\250\322\2\4-\11\253" - "\310h\220\344\2\4.\12\254\310\244\244.\225\0\4/\11\253\310\255\264T\0\4\60\10\243\310-\225\4" - "\4\61\11\253\310\315\221*\0\4\62\11\243\310\14\225\26\0\4\63\10\243\310\214X\2\4\64\11\253\307-" - "\65T\0\4\65\7\243\310US\4\66\11\244\310$S%\1\4\67\11\243\310\254\14\26\0\4\70\11\243" - "\310\244\61T\0\4\71\11\253\310\244\326P\1\4:\10\243\310$\265\12\4;\7\243\310-+\4<\11" - "\243\310\244\241T\0\4=\11\243\310\244\241T\0\4>\10\243\310U\252\2\4\77\10\243\310\214d\5\4" - "@\11\253\307\250\264b\4\4A\10\243\310\315\14\4\4B\10\243\310\254X\1\4C\11\253\307$\225\344" - "\2\4D\12\263\307\305\224T\231\0\4E\10\243\310\244\62\25\4F\11\253\307$k\304\0\4G\11\243" - "\310$\225d\0\4H\10\243\310\244q\4\4I\11\254\307\244\364\310 \4J\12\244\310h SR\0" - "\4K\11\244\310\304\245F\12\4L\11\243\310D\225\26\0\4M\10\243\310H\271\0\4N\12\244\310\244" - "\244\226J\0\4O\10\243\310\255\264\2\4Q\10\253\310\244\326\24\4R\11\263\307D\25U\31\4S\11" - "\253\310\246\64b\4\4T\11\243\310\215\224\201\0\4U\11\243\310\215\14\26\0\4V\11\253\310e$\323" - "\0\4W\11\253\310\244\14d\32\4X\11\263\307fX.\0\4Y\10\244\310\251\326\22\4Z\11\244\310" - "\244\264\322\22\4[\11\253\310D\25U\1\4\134\10\253\310\312\264\12\4^\11\263\307\244\32u\2\4_" - "\11\253\307$k\244\4\4\220\10\253\310\16Y\2\4\221\10\243\310\16\31\1\4\222\11\253\310\251\264b\2" - "\4\223\11\243\310\251\264\22\0\0"; +const uint8_t u8g2_font_tom_thumb_4x6_tr[725] = + "_\0\2\2\2\3\3\4\4\3\6\0\377\5\377\5\0\0\352\1\330\2\270 \5\340\315\0!\6\265\310" + "\254\0\42\6\213\313$\25#\10\227\310\244\241\206\12$\10\227\310\215\70b\2%\10\227\310d\324F\1" + "&\10\227\310(\65R\22'\5\251\313\10(\6\266\310\251\62)\10\226\310\304\224\24\0*\6\217\312\244" + "\16+\7\217\311\245\225\0,\6\212\310)\0-\5\207\312\14.\5\245\310\4/\7\227\310Ve\4\60" + "\7\227\310-k\1\61\6\226\310\255\6\62\10\227\310h\220\312\1\63\11\227\310h\220\62X\0\64\10\227" + "\310$\65b\1\65\10\227\310\214\250\301\2\66\10\227\310\315\221F\0\67\10\227\310\314TF\0\70\10\227" + "\310\214\64\324\10\71\10\227\310\214\64\342\2:\6\255\311\244\0;\7\222\310e\240\0<\10\227\310\246\32" + "d\20=\6\217\311l\60>\11\227\310d\220A*\1\77\10\227\310\314\224a\2@\10\227\310UC\3" + "\1A\10\227\310UC\251\0B\10\227\310\250\264\322\2C\7\227\310\315\32\10D\10\227\310\250d-\0" + "E\10\227\310\214\70\342\0F\10\227\310\214\70b\4G\10\227\310\315\221\222\0H\10\227\310$\65\224\12" + "I\7\227\310\254X\15J\7\227\310\226\252\2K\10\227\310$\265\222\12L\7\227\310\304\346\0M\10\227" + "\310\244\61\224\12N\10\227\310\244q\250\0O\7\227\310UV\5P\10\227\310\250\264b\4Q\10\227\310" + "Uj$\1R\10\227\310\250\64V\1S\10\227\310m\220\301\2T\7\227\310\254\330\2U\7\227\310$" + "W\22V\10\227\310$\253L\0W\10\227\310$\65\206\12X\10\227\310$\325R\1Y\10\227\310$U" + "V\0Z\7\227\310\314T\16[\7\227\310\214X\16\134\10\217\311d\220A\0]\7\227\310\314r\4^" + "\5\213\313\65_\5\207\310\14`\6\212\313\304\0a\7\223\310\310\65\2b\10\227\310D\225\324\2c\7" + "\223\310\315\14\4d\10\227\310\246\245\222\0e\6\223\310\235\2f\10\227\310\246\264b\2g\10\227\307\35" + "\61%\0h\10\227\310D\225\254\0i\6\265\310\244\1j\10\233\307f\30U\5k\10\227\310\304\264T" + "\1l\7\227\310\310\326\0m\7\223\310offset_x; y += canvas->offset_y; - u8g2_DrawUTF8(&canvas->fb, x, y, str); + u8g2_DrawStr(&canvas->fb, x, y, str); } void canvas_draw_str_aligned( @@ -169,10 +169,10 @@ void canvas_draw_str_aligned( case AlignLeft: break; case AlignRight: - x -= u8g2_GetUTF8Width(&canvas->fb, str); + x -= u8g2_GetStrWidth(&canvas->fb, str); break; case AlignCenter: - x -= (u8g2_GetUTF8Width(&canvas->fb, str) / 2); + x -= (u8g2_GetStrWidth(&canvas->fb, str) / 2); break; default: furi_crash(); @@ -193,13 +193,13 @@ void canvas_draw_str_aligned( break; } - u8g2_DrawUTF8(&canvas->fb, x, y, str); + u8g2_DrawStr(&canvas->fb, x, y, str); } uint16_t canvas_string_width(Canvas* canvas, const char* str) { furi_assert(canvas); if(!str) return 0; - return u8g2_GetUTF8Width(&canvas->fb, str); + return u8g2_GetStrWidth(&canvas->fb, str); } uint8_t canvas_glyph_width(Canvas* canvas, uint16_t symbol) { @@ -321,10 +321,10 @@ static void canvas_draw_u8g2_bitmap_int( void canvas_draw_u8g2_bitmap( u8g2_t* u8g2, - uint8_t x, - uint8_t y, - uint8_t w, - uint8_t h, + u8g2_uint_t x, + u8g2_uint_t y, + u8g2_uint_t w, + u8g2_uint_t h, const uint8_t* bitmap, IconRotation rotation) { u8g2_uint_t blen; diff --git a/applications/services/gui/canvas_i.h b/applications/services/gui/canvas_i.h index 5f7d69e72..f3b8f17ad 100644 --- a/applications/services/gui/canvas_i.h +++ b/applications/services/gui/canvas_i.h @@ -96,4 +96,4 @@ void canvas_draw_u8g2_bitmap( uint8_t width, uint8_t height, const uint8_t* bitmap, - IconRotation rotation); + uint8_t rotation); diff --git a/lib/u8g2/u8g2.h b/lib/u8g2/u8g2.h index 540b7a873..68611d482 100644 --- a/lib/u8g2/u8g2.h +++ b/lib/u8g2/u8g2.h @@ -67,7 +67,7 @@ Use 16 Bit mode for any display with more than 240 pixel in one direction. */ -#define U8G2_16BIT +//#define U8G2_16BIT /* The following macro switches the library into dynamic display buffer allocation mode. From 283216089145316ae7c5b4fe0c1f42275360c099 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 22 Dec 2023 22:13:28 +0300 Subject: [PATCH 23/35] change log level --- applications/main/subghz/scenes/subghz_scene_receiver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/main/subghz/scenes/subghz_scene_receiver.c b/applications/main/subghz/scenes/subghz_scene_receiver.c index bffff9988..ae092907f 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver.c @@ -136,7 +136,7 @@ static void subghz_scene_add_to_history_callback( furi_string_free(item_time); subghz_rx_key_state_set(subghz, SubGhzRxKeyStateAddKey); } else { - FURI_LOG_I(TAG, "%s protocol ignored", decoder_base->protocol->name); + FURI_LOG_D(TAG, "%s protocol ignored", decoder_base->protocol->name); } } From b84f14386c9f2c111811b031a18a6914f71a3e74 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sun, 24 Dec 2023 03:08:24 +0300 Subject: [PATCH 24/35] subghz option to delete old signals on full memory --- .../subghz/scenes/subghz_scene_receiver.c | 16 ++++++++++++++ .../scenes/subghz_scene_receiver_config.c | 22 +++++++++++++++++++ .../main/subghz/subghz_last_settings.c | 10 +++++++++ .../main/subghz/subghz_last_settings.h | 1 + 4 files changed, 49 insertions(+) diff --git a/applications/main/subghz/scenes/subghz_scene_receiver.c b/applications/main/subghz/scenes/subghz_scene_receiver.c index ae092907f..51063c999 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver.c @@ -112,6 +112,22 @@ static void subghz_scene_add_to_history_callback( uint16_t idx = subghz_history_get_item(history); SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx); + if(subghz->last_settings->delete_old_signals) { + if(subghz_history_get_last_index(subghz->history) >= 54) { + subghz->state_notifications = SubGhzNotificationStateRx; + + subghz_view_receiver_disable_draw_callback(subghz->subghz_receiver); + + subghz_history_delete_item(subghz->history, 0); + subghz_view_receiver_delete_item(subghz->subghz_receiver, 0); + subghz_view_receiver_enable_draw_callback(subghz->subghz_receiver); + + subghz_scene_receiver_update_statusbar(subghz); + subghz->idx_menu_chosen = + subghz_view_receiver_get_idx_menu(subghz->subghz_receiver); + idx--; + } + } if(subghz_history_add_to_history(history, decoder_base, &preset)) { furi_string_reset(item_name); furi_string_reset(item_time); diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_config.c b/applications/main/subghz/scenes/subghz_scene_receiver_config.c index 09c3976cc..f98b33b4f 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_config.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_config.c @@ -13,6 +13,7 @@ enum SubGhzSettingIndex { SubGhzSettingIndexIgnoreMagellan, SubGhzSettingIndexIgnorePrinceton, SubGhzSettingIndexIgnoreNiceFlorS, + SubGhzSettingIndexDeleteOldSignals, SubGhzSettingIndexSound, SubGhzSettingIndexResetToDefault, SubGhzSettingIndexLock, @@ -283,6 +284,15 @@ static void subghz_scene_receiver_config_set_niceflors(VariableItem* item) { subghz_scene_receiver_config_set_ignore_filter(item, SubGhzProtocolFlag_NiceFlorS); } +static void subghz_scene_receiver_config_set_delete_old_signals(VariableItem* item) { + SubGhz* subghz = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + + variable_item_set_current_value_text(item, combobox_text[index]); + + subghz->last_settings->delete_old_signals = index == 1; +} + static void subghz_scene_receiver_config_var_list_enter_callback(void* context, uint32_t index) { furi_assert(context); SubGhz* subghz = context; @@ -314,6 +324,7 @@ static void subghz_scene_receiver_config_var_list_enter_callback(void* context, subghz_txrx_receiver_set_filter(subghz->txrx, subghz->filter); subghz->last_settings->ignore_filter = subghz->ignore_filter; subghz->last_settings->filter = subghz->filter; + subghz->last_settings->delete_old_signals = false; subghz_txrx_speaker_set_state(subghz->txrx, speaker_value[default_index]); @@ -461,6 +472,17 @@ void subghz_scene_receiver_config_on_enter(void* context) { subghz->ignore_filter, SubGhzProtocolFlag_NiceFlorS); variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, combobox_text[value_index]); + + item = variable_item_list_add( + subghz->variable_item_list, + "Delete old signals when memory is full", + COMBO_BOX_COUNT, + subghz_scene_receiver_config_set_delete_old_signals, + subghz); + + value_index = subghz->last_settings->delete_old_signals; + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, combobox_text[value_index]); } // Enable speaker, will send all incoming noises and signals to speaker so you can listen how your remote sounds like :) diff --git a/applications/main/subghz/subghz_last_settings.c b/applications/main/subghz/subghz_last_settings.c index fe072a1ef..07bad225d 100644 --- a/applications/main/subghz/subghz_last_settings.c +++ b/applications/main/subghz/subghz_last_settings.c @@ -19,6 +19,7 @@ #define SUBGHZ_LAST_SETTING_FIELD_IGNORE_FILTER "IgnoreFilter" #define SUBGHZ_LAST_SETTING_FIELD_FILTER "Filter" #define SUBGHZ_LAST_SETTING_FIELD_RSSI_THRESHOLD "RSSI" +#define SUBGHZ_LAST_SETTING_FIELD_DELETE_OLD "DelOldSignals" SubGhzLastSettings* subghz_last_settings_alloc(void) { SubGhzLastSettings* instance = malloc(sizeof(SubGhzLastSettings)); @@ -44,6 +45,7 @@ void subghz_last_settings_load(SubGhzLastSettings* instance, size_t preset_count bool temp_external_module_power_amp = false; bool temp_timestamp_file_names = false; bool temp_enable_hopping = false; + bool temp_delete_old_sig = false; uint32_t temp_ignore_filter = 0; uint32_t temp_filter = 0; float temp_rssi = 0; @@ -106,6 +108,8 @@ void subghz_last_settings_load(SubGhzLastSettings* instance, size_t preset_count 1); filter_was_read = flipper_format_read_uint32( fff_data_file, SUBGHZ_LAST_SETTING_FIELD_FILTER, (uint32_t*)&temp_filter, 1); + flipper_format_read_bool( + fff_data_file, SUBGHZ_LAST_SETTING_FIELD_DELETE_OLD, (bool*)&temp_delete_old_sig, 1); } else { FURI_LOG_E(TAG, "Error open file %s", SUBGHZ_LAST_SETTINGS_PATH); } @@ -156,6 +160,8 @@ void subghz_last_settings_load(SubGhzLastSettings* instance, size_t preset_count instance->timestamp_file_names = temp_timestamp_file_names; + instance->delete_old_signals = temp_delete_old_sig; + // External power amp CC1101 instance->external_module_power_amp = temp_external_module_power_amp; @@ -270,6 +276,10 @@ bool subghz_last_settings_save(SubGhzLastSettings* instance) { file, SUBGHZ_LAST_SETTING_FIELD_FILTER, &instance->filter, 1)) { break; } + if(!flipper_format_insert_or_update_bool( + file, SUBGHZ_LAST_SETTING_FIELD_DELETE_OLD, &instance->delete_old_signals, 1)) { + break; + } saved = true; } while(0); diff --git a/applications/main/subghz/subghz_last_settings.h b/applications/main/subghz/subghz_last_settings.h index b3742d4bf..74dded4b7 100644 --- a/applications/main/subghz/subghz_last_settings.h +++ b/applications/main/subghz/subghz_last_settings.h @@ -30,6 +30,7 @@ typedef struct { uint32_t ignore_filter; uint32_t filter; float rssi; + bool delete_old_signals; } SubGhzLastSettings; SubGhzLastSettings* subghz_last_settings_alloc(void); From 0084443ed7705e6ca25d110b123f139eb20d7616 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Tue, 26 Dec 2023 14:09:10 +0900 Subject: [PATCH 25/35] [FL-3727] RPC: reverse input (#3304) * RPC: reverse input * Assets: sync protobuf --- applications/services/rpc/rpc_gui.c | 126 +++++++++++++++++----------- assets/protobuf | 2 +- 2 files changed, 76 insertions(+), 52 deletions(-) diff --git a/applications/services/rpc/rpc_gui.c b/applications/services/rpc/rpc_gui.c index ca8fc61a4..dd219e2dc 100644 --- a/applications/services/rpc/rpc_gui.c +++ b/applications/services/rpc/rpc_gui.c @@ -5,6 +5,41 @@ #include #include +// Contract assertion +_Static_assert(InputKeyMAX == 6, "InputKeyMAX"); +_Static_assert(InputTypeMAX == 5, "InputTypeMAX"); + +_Static_assert(InputKeyUp == (int32_t)PB_Gui_InputKey_UP, "InputKeyUp != PB_Gui_InputKey_UP"); +_Static_assert( + InputKeyDown == (int32_t)PB_Gui_InputKey_DOWN, + "InputKeyDown != PB_Gui_InputKey_DOWN"); +_Static_assert( + InputKeyRight == (int32_t)PB_Gui_InputKey_RIGHT, + "InputKeyRight != PB_Gui_InputKey_RIGHT"); +_Static_assert( + InputKeyLeft == (int32_t)PB_Gui_InputKey_LEFT, + "InputKeyLeft != PB_Gui_InputKey_LEFT"); +_Static_assert(InputKeyOk == (int32_t)PB_Gui_InputKey_OK, "InputKeyOk != PB_Gui_InputKey_OK"); +_Static_assert( + InputKeyBack == (int32_t)PB_Gui_InputKey_BACK, + "InputKeyBack != PB_Gui_InputKey_BACK"); + +_Static_assert( + InputTypePress == (int32_t)PB_Gui_InputType_PRESS, + "InputTypePress != PB_Gui_InputType_PRESS"); +_Static_assert( + InputTypeRelease == (int32_t)PB_Gui_InputType_RELEASE, + "InputTypeRelease != PB_Gui_InputType_RELEASE"); +_Static_assert( + InputTypeShort == (int32_t)PB_Gui_InputType_SHORT, + "InputTypeShort != PB_Gui_InputType_SHORT"); +_Static_assert( + InputTypeLong == (int32_t)PB_Gui_InputType_LONG, + "InputTypeLong != PB_Gui_InputType_LONG"); +_Static_assert( + InputTypeRepeat == (int32_t)PB_Gui_InputType_REPEAT, + "InputTypeRepeat != PB_Gui_InputType_REPEAT"); + #define TAG "RpcGui" typedef enum { @@ -168,63 +203,20 @@ static void RpcSession* session = rpc_gui->session; furi_assert(session); - InputEvent event; + bool is_valid = (request->content.gui_send_input_event_request.key < (int32_t)InputKeyMAX) && + (request->content.gui_send_input_event_request.type < (int32_t)InputTypeMAX); - bool invalid = false; - - switch(request->content.gui_send_input_event_request.key) { - case PB_Gui_InputKey_UP: - event.key = InputKeyUp; - break; - case PB_Gui_InputKey_DOWN: - event.key = InputKeyDown; - break; - case PB_Gui_InputKey_RIGHT: - event.key = InputKeyRight; - break; - case PB_Gui_InputKey_LEFT: - event.key = InputKeyLeft; - break; - case PB_Gui_InputKey_OK: - event.key = InputKeyOk; - break; - case PB_Gui_InputKey_BACK: - event.key = InputKeyBack; - break; - default: - // Invalid key - invalid = true; - break; - } - - switch(request->content.gui_send_input_event_request.type) { - case PB_Gui_InputType_PRESS: - event.type = InputTypePress; - break; - case PB_Gui_InputType_RELEASE: - event.type = InputTypeRelease; - break; - case PB_Gui_InputType_SHORT: - event.type = InputTypeShort; - break; - case PB_Gui_InputType_LONG: - event.type = InputTypeLong; - break; - case PB_Gui_InputType_REPEAT: - event.type = InputTypeRepeat; - break; - default: - // Invalid type - invalid = true; - break; - } - - if(invalid) { + if(!is_valid) { rpc_send_and_release_empty( session, request->command_id, PB_CommandStatus_ERROR_INVALID_PARAMETERS); return; } + InputEvent event = { + .key = (int32_t)request->content.gui_send_input_event_request.key, + .type = (int32_t)request->content.gui_send_input_event_request.type, + }; + // Event sequence shenanigans event.sequence_source = INPUT_SEQUENCE_SOURCE_SOFTWARE; if(event.type == InputTypePress) { @@ -264,6 +256,29 @@ static void rpc_system_gui_virtual_display_render_callback(Canvas* canvas, void* canvas_draw_xbm(canvas, 0, 0, canvas->width, canvas->height, rpc_gui->virtual_display_buffer); } +static void rpc_system_gui_virtual_display_input_callback(InputEvent* event, void* context) { + furi_assert(event); + furi_assert(event->key < InputKeyMAX); + furi_assert(event->type < InputTypeMAX); + furi_assert(context); + + RpcGuiSystem* rpc_gui = context; + RpcSession* session = rpc_gui->session; + + FURI_LOG_D(TAG, "VirtulDisplay: SendInputEvent"); + + PB_Main rpc_message = { + .command_id = 0, + .command_status = PB_CommandStatus_OK, + .has_next = false, + .which_content = PB_Main_gui_send_input_event_request_tag, + .content.gui_send_input_event_request.key = (int32_t)event->key, + .content.gui_send_input_event_request.type = (int32_t)event->type, + }; + + rpc_send_and_release(session, &rpc_message); +} + static void rpc_system_gui_start_virtual_display_process(const PB_Main* request, void* context) { furi_assert(request); furi_assert(context); @@ -300,6 +315,15 @@ static void rpc_system_gui_start_virtual_display_process(const PB_Main* request, rpc_gui->virtual_display_view_port, rpc_system_gui_virtual_display_render_callback, rpc_gui); + + if(request->content.gui_start_virtual_display_request.send_input) { + FURI_LOG_D(TAG, "VirtulDisplay: input forwarding requested"); + view_port_input_callback_set( + rpc_gui->virtual_display_view_port, + rpc_system_gui_virtual_display_input_callback, + rpc_gui); + } + gui_add_view_port(rpc_gui->gui, rpc_gui->virtual_display_view_port, GuiLayerFullscreen); rpc_send_and_release_empty(session, request->command_id, PB_CommandStatus_OK); diff --git a/assets/protobuf b/assets/protobuf index 23ad19a75..1956b83bb 160000 --- a/assets/protobuf +++ b/assets/protobuf @@ -1 +1 @@ -Subproject commit 23ad19a756649ed9f6677b598e5361c5cce6847b +Subproject commit 1956b83bba99313ee8d8386e5d35d0549341ca26 From c9e3f203140c7ad230ca58d360db394c92c6aeb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Tue, 26 Dec 2023 15:12:17 +0900 Subject: [PATCH 26/35] [FL-3429] About: cn,tw,mx certification information (#3318) --- applications/settings/about/about.c | 87 +++++++++++++----- .../About/CertificationChina0_121x41.png | Bin 0 -> 5314 bytes .../About/CertificationChina1_122x47.png | Bin 0 -> 5215 bytes .../icons/About/CertificationMexico_98x41.png | Bin 0 -> 5219 bytes .../icons/About/CertificationTaiwan_33x32.png | Bin 0 -> 4835 bytes targets/f18/api_symbols.csv | 4 +- .../f18/furi_hal/furi_hal_version_device.c | 8 ++ targets/f7/api_symbols.csv | 4 +- targets/f7/furi_hal/furi_hal_version_device.c | 8 ++ targets/furi_hal_include/furi_hal_version.h | 12 +++ 10 files changed, 96 insertions(+), 27 deletions(-) create mode 100644 assets/icons/About/CertificationChina0_121x41.png create mode 100644 assets/icons/About/CertificationChina1_122x47.png create mode 100644 assets/icons/About/CertificationMexico_98x41.png create mode 100644 assets/icons/About/CertificationTaiwan_33x32.png diff --git a/applications/settings/about/about.c b/applications/settings/about/about.c index dcd7656fc..8f0798d9c 100644 --- a/applications/settings/about/about.c +++ b/applications/settings/about/about.c @@ -11,7 +11,7 @@ typedef DialogMessageButton (*AboutDialogScreen)(DialogsApp* dialogs, DialogMessage* message); -static DialogMessageButton product_screen(DialogsApp* dialogs, DialogMessage* message) { +static DialogMessageButton about_screen_product(DialogsApp* dialogs, DialogMessage* message) { DialogMessageButton result; FuriString* screen_header = furi_string_alloc_printf( @@ -31,8 +31,6 @@ static DialogMessageButton product_screen(DialogsApp* dialogs, DialogMessage* me dialog_message_set_text( message, furi_string_get_cstr(screen_text), 0, 26, AlignLeft, AlignTop); result = dialog_message_show(dialogs, message); - dialog_message_set_header(message, NULL, 0, 0, AlignLeft, AlignTop); - dialog_message_set_text(message, NULL, 0, 0, AlignLeft, AlignTop); furi_string_free(screen_header); furi_string_free(screen_text); @@ -40,7 +38,7 @@ static DialogMessageButton product_screen(DialogsApp* dialogs, DialogMessage* me return result; } -static DialogMessageButton address_screen(DialogsApp* dialogs, DialogMessage* message) { +static DialogMessageButton about_screen_address(DialogsApp* dialogs, DialogMessage* message) { DialogMessageButton result; const char* screen_text = "Flipper Devices Inc\n" @@ -50,12 +48,11 @@ static DialogMessageButton address_screen(DialogsApp* dialogs, DialogMessage* me dialog_message_set_text(message, screen_text, 0, 0, AlignLeft, AlignTop); result = dialog_message_show(dialogs, message); - dialog_message_set_text(message, NULL, 0, 0, AlignLeft, AlignTop); return result; } -static DialogMessageButton compliance_screen(DialogsApp* dialogs, DialogMessage* message) { +static DialogMessageButton about_screen_compliance(DialogsApp* dialogs, DialogMessage* message) { DialogMessageButton result; const char* screen_text = "For all compliance\n" @@ -64,35 +61,71 @@ static DialogMessageButton compliance_screen(DialogsApp* dialogs, DialogMessage* dialog_message_set_text(message, screen_text, 0, 0, AlignLeft, AlignTop); result = dialog_message_show(dialogs, message); - dialog_message_set_text(message, NULL, 0, 0, AlignLeft, AlignTop); return result; } -static DialogMessageButton icon1_screen(DialogsApp* dialogs, DialogMessage* message) { +static DialogMessageButton about_screen_icon1(DialogsApp* dialogs, DialogMessage* message) { DialogMessageButton result; dialog_message_set_icon(message, &I_Certification1_103x56, 13, 0); result = dialog_message_show(dialogs, message); - dialog_message_set_icon(message, NULL, 0, 0); return result; } -static DialogMessageButton icon2_screen(DialogsApp* dialogs, DialogMessage* message) { +static DialogMessageButton about_screen_icon2(DialogsApp* dialogs, DialogMessage* message) { DialogMessageButton result; dialog_message_set_icon(message, &I_Certification2_46x33, 15, 10); dialog_message_set_text( message, furi_hal_version_get_mic_id(), 63, 27, AlignLeft, AlignCenter); result = dialog_message_show(dialogs, message); - dialog_message_set_icon(message, NULL, 0, 0); - dialog_message_set_text(message, NULL, 0, 0, AlignLeft, AlignTop); return result; } -static DialogMessageButton hw_version_screen(DialogsApp* dialogs, DialogMessage* message) { +static DialogMessageButton about_screen_cert_china_0(DialogsApp* dialogs, DialogMessage* message) { + DialogMessageButton result; + + dialog_message_set_icon(message, &I_CertificationChina0_121x41, 3, 3); + result = dialog_message_show(dialogs, message); + + return result; +} + +static DialogMessageButton about_screen_cert_china_1(DialogsApp* dialogs, DialogMessage* message) { + DialogMessageButton result; + + dialog_message_set_icon(message, &I_CertificationChina1_122x47, 3, 3); + dialog_message_set_text( + message, furi_hal_version_get_srrc_id(), 55, 11, AlignLeft, AlignBottom); + result = dialog_message_show(dialogs, message); + + return result; +} + +static DialogMessageButton about_screen_cert_taiwan(DialogsApp* dialogs, DialogMessage* message) { + DialogMessageButton result; + + dialog_message_set_icon(message, &I_CertificationTaiwan_33x32, 3, 10); + dialog_message_set_text( + message, furi_hal_version_get_ncc_id(), 39, 30, AlignLeft, AlignBottom); + result = dialog_message_show(dialogs, message); + + return result; +} + +static DialogMessageButton about_screen_cert_mexico(DialogsApp* dialogs, DialogMessage* message) { + DialogMessageButton result; + + dialog_message_set_icon(message, &I_CertificationMexico_98x41, 17, 4); + result = dialog_message_show(dialogs, message); + + return result; +} + +static DialogMessageButton about_screen_hw_version(DialogsApp* dialogs, DialogMessage* message) { DialogMessageButton result; FuriString* buffer; buffer = furi_string_alloc(); @@ -118,14 +151,12 @@ static DialogMessageButton hw_version_screen(DialogsApp* dialogs, DialogMessage* dialog_message_set_header(message, "HW Version Info:", 0, 0, AlignLeft, AlignTop); dialog_message_set_text(message, furi_string_get_cstr(buffer), 0, 13, AlignLeft, AlignTop); result = dialog_message_show(dialogs, message); - dialog_message_set_text(message, NULL, 0, 0, AlignLeft, AlignTop); - dialog_message_set_header(message, NULL, 0, 0, AlignLeft, AlignTop); furi_string_free(buffer); return result; } -static DialogMessageButton fw_version_screen(DialogsApp* dialogs, DialogMessage* message) { +static DialogMessageButton about_screen_fw_version(DialogsApp* dialogs, DialogMessage* message) { DialogMessageButton result; FuriString* buffer; buffer = furi_string_alloc(); @@ -157,21 +188,23 @@ static DialogMessageButton fw_version_screen(DialogsApp* dialogs, DialogMessage* dialog_message_set_header(message, "FW Version Info:", 0, 0, AlignLeft, AlignTop); dialog_message_set_text(message, furi_string_get_cstr(buffer), 0, 13, AlignLeft, AlignTop); result = dialog_message_show(dialogs, message); - dialog_message_set_text(message, NULL, 0, 0, AlignLeft, AlignTop); - dialog_message_set_header(message, NULL, 0, 0, AlignLeft, AlignTop); furi_string_free(buffer); return result; } const AboutDialogScreen about_screens[] = { - product_screen, - compliance_screen, - address_screen, - icon1_screen, - icon2_screen, - hw_version_screen, - fw_version_screen}; + about_screen_product, + about_screen_compliance, + about_screen_address, + about_screen_icon1, + about_screen_icon2, + about_screen_cert_china_0, + about_screen_cert_china_1, + about_screen_cert_taiwan, + about_screen_cert_mexico, + about_screen_hw_version, + about_screen_fw_version}; int32_t about_settings_app(void* p) { UNUSED(p); @@ -201,6 +234,10 @@ int32_t about_settings_app(void* p) { screen_result = about_screens[screen_index](dialogs, message); + dialog_message_set_icon(message, NULL, 0, 0); + dialog_message_set_header(message, NULL, 0, 0, AlignLeft, AlignTop); + dialog_message_set_text(message, NULL, 0, 0, AlignLeft, AlignTop); + if(screen_result == DialogMessageButtonLeft) { if(screen_index <= 0) { break; diff --git a/assets/icons/About/CertificationChina0_121x41.png b/assets/icons/About/CertificationChina0_121x41.png new file mode 100644 index 0000000000000000000000000000000000000000..1d28577ab3e6a1c35bf658087b953acdd0fa104a GIT binary patch literal 5314 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 literal 0 HcmV?d00001 diff --git a/assets/icons/About/CertificationTaiwan_33x32.png b/assets/icons/About/CertificationTaiwan_33x32.png new file mode 100644 index 0000000000000000000000000000000000000000..bf2bfa21a7b7a7045a87bb2c521e50490f3fcfe9 GIT binary patch literal 4835 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 Date: Tue, 26 Dec 2023 22:49:38 +0300 Subject: [PATCH 27/35] temp fix for subghz keyboard lock actually - furi timer is broken :((((( --- applications/main/subghz/views/receiver.c | 37 ++++++++++++----------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/applications/main/subghz/views/receiver.c b/applications/main/subghz/views/receiver.c index 98c15dbff..1eb4d0460 100644 --- a/applications/main/subghz/views/receiver.c +++ b/applications/main/subghz/views/receiver.c @@ -101,6 +101,24 @@ void subghz_receiver_rssi(SubGhzViewReceiver* instance, float rssi) { true); } +static void subghz_view_receiver_timer_callback(void* context) { + furi_assert(context); + SubGhzViewReceiver* subghz_receiver = context; + with_view_model( + subghz_receiver->view, + SubGhzViewReceiverModel * model, + { model->bar_show = SubGhzViewReceiverBarShowDefault; }, + true); + if(subghz_receiver->lock_count < UNLOCK_CNT) { + subghz_receiver->callback( + SubGhzCustomEventViewReceiverOffDisplay, subghz_receiver->context); + } else { + subghz_receiver->lock = false; + subghz_receiver->callback(SubGhzCustomEventViewReceiverUnlock, subghz_receiver->context); + } + subghz_receiver->lock_count = 0; +} + void subghz_view_receiver_set_lock(SubGhzViewReceiver* subghz_receiver, bool lock) { furi_assert(subghz_receiver); subghz_receiver->lock_count = 0; @@ -112,6 +130,7 @@ void subghz_view_receiver_set_lock(SubGhzViewReceiver* subghz_receiver, bool loc { model->bar_show = SubGhzViewReceiverBarShowLock; }, true); furi_timer_start(subghz_receiver->timer, 1000); + subghz_view_receiver_timer_callback(subghz_receiver); } else { with_view_model( subghz_receiver->view, @@ -424,24 +443,6 @@ void subghz_view_receiver_draw(Canvas* canvas, SubGhzViewReceiverModel* model) { } } -static void subghz_view_receiver_timer_callback(void* context) { - furi_assert(context); - SubGhzViewReceiver* subghz_receiver = context; - with_view_model( - subghz_receiver->view, - SubGhzViewReceiverModel * model, - { model->bar_show = SubGhzViewReceiverBarShowDefault; }, - true); - if(subghz_receiver->lock_count < UNLOCK_CNT) { - subghz_receiver->callback( - SubGhzCustomEventViewReceiverOffDisplay, subghz_receiver->context); - } else { - subghz_receiver->lock = false; - subghz_receiver->callback(SubGhzCustomEventViewReceiverUnlock, subghz_receiver->context); - } - subghz_receiver->lock_count = 0; -} - bool subghz_view_receiver_input(InputEvent* event, void* context) { furi_assert(context); SubGhzViewReceiver* subghz_receiver = context; From 528d29b82deb6e0e206952733330dd9e49a11bc7 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 26 Dec 2023 23:24:57 +0300 Subject: [PATCH 28/35] upd changelog and ac --- CHANGELOG.md | 83 +++++-------------- .../infrared/resources/infrared/assets/ac.ir | 76 +++++++++++++++++ 2 files changed, 99 insertions(+), 60 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e4f19092..62edba5a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,74 +6,37 @@ - Mifare Mini clones reading is broken (original mini working fine) (OFW) - Mifare Classic dict attack fast skip (multiple presses on OK button) causes glitches/incorrect reading (OFW) - EMV simple data parser was removed with protocol with refactoring (OFW) -- Mifare Classic Emulation slow response (unconfirmed) (OFW) - Option to unlock Slix-L (NFC V) with preset or custom password was removed with refactoring (OFW) - NFC CLI was removed with refactoring (OFW) ### Some apps that was made for old nfc stack is now not compatible with the new API and require complete remake: **If you want to help with making this apps work again please send PR to the repo at link below** - Current list of affected apps: https://github.com/xMasterX/all-the-plugins/tree/dev/apps_broken_by_last_refactors - Also in app **Enhanced Sub-GHz Chat** - NFC part was temporarily removed to make app usable, NFC part of the app requires remaking it with new nfc stack
-**API was updated to v49.x** +**API was updated to v50.x** ## New changes -* NFC: Added new parsers for transport cards - Umarsh, Kazan, Moscow, Metromoney(Tbilisi), and fixes for OFW parsers (by @assasinfil and @Leptopt1los) (special thanks for users who provided various dumps of those cards for research) -* NFC: Added simple key name display to UI to fix regression -* NFC: Add keys to mf_classic_dict (by @hnlcory | PR #660) -* NFC: Add Saflok and MyKey KDFs (by @noproto | PR #662) -* NFC: social_moscow parser verification collisions fix (by @Leptopt1los) -* iButton: Fix UI text - protocol name getting out of screen bounds when key name is too large, and other related issues (by @krolchonok | PR #649) -* SubGHz: Fixed feature naming in menu -* SubGHz: Added honeywell protocol [(by @htotoo)](https://github.com/Flipper-XFW/Xtreme-Firmware/commit/ceee551befa0cb8fd8514a4f8a1250fd9e0997ee) -* SubGHz: Add 303.9 Mhz to default frequency list -* SubGHz: Fix Keeloq decoding order bug (random switch to HCS101 or anmotors) -* SubGHz: Fix secplus v1 key display issue -* API: Add new get function for varitemlist (by @Willy-JL) -* Misc code cleanup -* Apps: **Bluetooth Remote / USB Keyboard & Mouse** - `Movie` and `PTT` modes by @hryamzik -* Apps: **BLE Spam app** updated to latest version (New devices support, + Menu by holding Start) (by @Willy-JL) -> (app can be found in builds ` `, `e`, `n`, `r`) -* Apps: **NFC Magic** - Gen4 Actions (option to fix card with broken config) (by @Leptopt1los and @xMasterX) +* NFC: Fix Saflok edge case 0.5% of UIDs got wrong result (by @noproto | PR #668) +* NFC: Zolotaya Korona transport card parser added (by @Leptopt1los) +* NFC: Parsers cleanup for new api (by @Leptopt1los) +* SubGHz: Temp fix for subghz keyboard lock display issue (furi_timer is not working properly) +* SubGHz: Added new option to delete old signals on full memory +* SubGHz: Faac rc/xt add manually (unverified) +* SubGHz: Better subghz history element removal (by @Willy-JL) +* SubGHz: Fix key display newline issue in came atomo * Apps: **Check out Apps updates by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev) -* OFW: NFC fixes -* OFW: nfc: m1k-based Aime (non-AIC) card support -* OFW: SubGhz: fix count bit for detect gate_tx protocol -* OFW: Fixed a zero allocation error when reading an iso15693 nfc tag with no additional blocks. -* OFW: Ntag21x write -* OFW: Mifare Classic nested auth support -* OFW: ST25TB poller refining + write support -* OFW: Libraries cleanup; u2f crypto rework to use mbedtls -* OFW: Add the secret door animation -* OFW: Allows you to use UCS-2 in canvas_glyph_width -* OFW: Mifare Classic fixes -* OFW: NFC: Felica UID emulation -* OFW: 64k does not enough -* OFW: fbt: improvements -* OFW: Various Fixes for 0.95 -* OFW: Add Mastercode SubGHz Protocol -* OFW: Do not remove file when renaming to itself -* OFW: Fix iButton crash on missing file -* OFW: NFC API improvements -* OFW: MF Ultralight no pwd polling adjustment -* OFW: Fix limited_credit_value having wrong value in mf_desfire_file_settings_parse -* OFW: Infrared remote button index support -* OFW: Fix NFC unit tests -* OFW: fix: invariant format of log time data -* OFW: fbt: dist improvements -* OFW: Fix crash when exiting write mode -* OFW: Dolphin: Extreme butthurt loop fix -* OFW: **Furi, FuriHal: remove FreeRTOS headers leaks** -* OFW: fbt: source collection improvements -* OFW: Rename menu items related to dummy mode and sound -* OFW: fbt: SD card resource handling speedup -* OFW: **Furi: cleanup crash use** -* OFW: Allow for larger Infrared remotes -* OFW: **fbt: reworked assets & resources handling** -* OFW: Storage: speedup write_chunk cli command -* OFW: fix crash after st25tb save -* OFW: Fix crash when reading files > 64B -* OFW: NFC RC fixes -* OFW: Fix MF DESFire record file handling -* OFW: **NFC refactoring** (new NFC stack) -> some apps still require very big changes to make them work with new system - see apps that was temporarily removed from this release here: https://github.com/xMasterX/all-the-plugins/tree/dev/apps_broken_by_last_refactors -* OFW: fbt: glob & git improvements -* OFW: FastFAP: human readable error log +* OFW: USART Bridge: added support for software control of DE/RE pins +* OFW: ufbt: changed toolchain environment invocation; updated .gitignore for app template +* OFW: Keys Dict: fix PVS warnings +* OFW: NfcDict Refactoring +* OFW: Add AC's Carrier 42QG5A580SC and AUX YKR-H/006E +* OFW: NFC Plugins loading rework +* OFW: MFC emulation fix +* OFW: nfc_util: little endian bytes2num functions added +* OFW: Add MyKey parser +* OFW: Update CLI MOTD +* OFW: NFC NTAG and ISO14443-3b reading fix +* OFW: FuriHal: RTC register reset API. New factory reset routine that wipes all RTC backup registers content. +* OFW: FuriHal: various GPIO improvements +* OFW: SubGhz: changed the name of the button when sending RAW to SubGHz ---- diff --git a/applications/main/infrared/resources/infrared/assets/ac.ir b/applications/main/infrared/resources/infrared/assets/ac.ir index 22bd473a7..301df5e5e 100644 --- a/applications/main/infrared/resources/infrared/assets/ac.ir +++ b/applications/main/infrared/resources/infrared/assets/ac.ir @@ -807,3 +807,79 @@ type: raw frequency: 38000 duty_cycle: 0.330000 data: 6175 7369 602 1570 602 1570 601 1570 573 1598 574 1598 573 1597 574 1597 574 1598 574 525 574 526 573 526 573 527 572 528 571 529 570 529 570 530 568 1603 568 1627 544 1627 544 1627 544 1628 544 554 545 1627 544 1628 544 555 544 555 544 555 544 555 544 554 544 1627 545 555 544 554 545 1627 544 1627 544 1627 544 1627 544 1627 544 1603 568 1602 569 1603 569 530 569 529 570 529 570 529 570 529 570 529 570 529 570 528 570 1601 571 528 570 1602 570 529 570 528 570 1601 570 1600 571 1601 571 528 571 1601 570 528 570 1601 570 1602 570 529 570 529 570 528 570 1601 570 1601 570 1600 571 1601 571 528 570 1601 570 1601 571 528 571 528 571 529 570 528 571 528 570 1601 571 528 571 528 570 1603 570 529 571 1603 570 529 570 1603 570 529 570 1603 570 529 571 1602 571 1603 570 529 571 1603 570 529 571 1603 570 529 571 1603 570 530 570 7370 570 +# +# Model: AUX YKR-H/006E +# +name: Off +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8957 4502 539 1683 538 1681 540 559 538 559 538 556 541 557 540 1683 538 1682 539 1684 537 1682 539 1681 540 1684 537 1684 537 1682 539 1684 537 558 539 558 539 558 539 558 539 559 538 558 539 1682 539 1681 540 1683 538 557 540 558 539 558 539 557 540 559 538 557 540 557 540 561 536 559 538 558 539 557 540 558 539 558 539 1683 538 558 539 1682 540 557 540 559 538 557 540 557 540 561 536 558 539 559 538 558 539 560 537 557 540 558 539 558 539 558 539 559 538 558 539 1682 539 557 540 558 539 557 540 557 540 558 539 560 537 557 540 557 540 558 539 559 538 557 540 559 538 556 541 558 539 558 539 558 539 556 541 559 538 557 540 558 539 558 539 558 539 557 540 558 539 557 541 557 540 557 540 559 538 558 539 558 539 558 539 558 539 1681 540 557 540 1683 538 558 539 559 538 557 540 559 538 559 538 1683 538 1683 538 1683 538 557 540 558 539 558 540 1683 538 560 563 +# +name: Dh +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8956 4504 536 1684 537 1687 534 559 538 559 538 559 538 560 537 1683 538 1685 536 1682 539 1684 537 1683 538 1684 537 1683 538 1684 537 1683 538 558 539 562 535 559 538 558 539 562 535 560 537 1683 538 1684 537 1683 538 561 536 561 536 561 537 560 537 561 536 558 539 560 537 559 538 560 537 561 536 561 536 563 534 559 538 1684 537 559 538 1684 537 561 536 560 537 560 537 560 537 560 537 560 537 559 538 559 538 559 538 588 509 558 539 559 538 559 538 564 533 1684 537 559 538 560 537 559 538 588 509 563 534 559 538 559 538 558 539 562 535 558 539 561 536 560 537 560 537 559 538 588 509 561 536 560 537 561 536 563 534 561 536 560 537 561 536 1684 537 559 538 559 538 559 538 561 536 560 537 560 537 559 538 561 536 558 539 560 537 1684 537 559 538 1683 538 561 536 561 536 563 534 559 538 558 539 1683 538 1684 537 1684 537 560 537 560 537 1683 538 560 537 560 563 +# +name: Cool_hi +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8957 4502 538 1683 538 1684 537 562 535 560 537 559 538 559 539 1683 538 1682 539 1711 510 1685 536 1683 538 558 539 588 509 557 540 1682 539 557 540 558 539 559 538 559 538 558 539 561 536 1681 540 1682 539 1683 538 559 538 559 538 559 538 561 536 560 537 559 538 558 539 559 538 559 538 559 538 559 538 560 537 560 537 1685 536 560 537 1685 536 560 537 559 538 560 537 560 537 559 538 558 539 559 538 560 537 587 510 562 535 559 538 560 537 557 540 1685 536 559 538 560 537 587 510 588 509 559 538 562 535 560 537 557 540 559 538 557 540 560 537 587 510 560 538 558 539 559 538 559 538 561 536 560 537 560 537 558 540 560 537 559 538 560 537 1683 538 562 535 560 537 559 538 560 537 558 539 559 538 558 539 560 537 560 537 559 538 1683 538 558 539 1684 537 559 538 558 539 559 538 558 539 558 539 1682 539 1684 537 1684 537 1683 538 560 537 558 539 1683 538 1684 564 +# +name: Cool_lo +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8956 4501 539 1682 539 1682 539 559 538 557 540 587 510 558 539 1684 537 1682 539 1682 539 1682 539 1680 541 1682 539 1682 539 1682 539 1681 540 558 539 558 539 558 539 557 540 558 539 557 540 1683 538 1683 538 1683 538 558 539 558 539 558 539 557 540 560 537 560 537 557 540 558 539 557 540 558 539 557 540 560 537 558 539 1681 540 556 541 1684 537 558 539 557 540 559 538 558 539 557 540 558 539 558 539 560 537 559 538 558 539 558 539 557 540 559 538 1685 536 559 538 558 539 587 510 557 540 559 538 559 538 560 537 560 537 558 539 559 538 558 539 559 538 562 535 558 539 557 540 557 540 559 538 559 538 558 539 559 538 558 539 558 539 557 540 1682 539 557 540 558 539 559 538 557 540 558 539 560 537 559 538 557 540 561 536 558 539 1682 539 558 539 1682 539 559 538 557 540 558 539 559 538 559 538 1682 539 1684 537 1683 538 557 540 558 539 558 539 560 537 559 564 +# +name: Heat_hi +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8959 4502 539 1682 539 1682 539 556 541 559 538 558 539 559 538 1680 541 1681 540 1684 537 1683 538 1684 537 557 540 560 537 558 539 1683 538 1682 539 558 539 559 538 559 538 558 539 558 539 1683 538 1681 540 1683 538 559 538 560 537 560 537 559 538 561 536 560 537 559 538 559 538 559 538 559 538 559 538 560 537 557 540 1682 539 557 540 1682 539 559 538 558 539 560 538 558 539 558 539 558 539 558 539 558 539 559 538 559 538 557 540 558 539 558 539 559 538 560 537 1684 537 561 536 557 540 559 538 559 538 557 540 558 539 559 538 560 537 558 539 558 539 559 538 558 539 559 539 559 538 557 540 559 538 557 540 558 540 561 536 558 539 558 539 1683 538 558 539 559 538 557 540 559 538 557 540 558 539 559 538 559 538 558 539 559 538 1681 540 558 539 1684 537 562 535 560 537 559 538 559 538 560 537 1682 539 1682 539 1682 539 1686 535 559 538 1682 539 559 538 1682 565 +# +name: Heat_lo +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8961 4501 539 1681 540 1681 540 559 538 558 539 558 539 557 540 1682 539 1682 539 1681 540 1682 539 1682 539 1683 538 1682 539 1683 538 1682 539 557 540 560 537 558 539 560 537 560 537 558 539 1681 540 1681 540 1682 539 557 540 558 539 561 536 558 539 560 537 558 539 556 541 558 539 558 539 557 540 559 538 558 539 559 538 1684 537 559 538 1682 539 558 539 556 541 559 538 562 535 556 541 558 539 558 539 557 540 558 539 557 540 558 539 559 538 560 537 557 540 557 540 1682 539 558 539 557 540 558 539 559 538 559 538 557 540 558 539 558 539 558 539 558 539 557 540 561 536 558 539 586 511 558 539 557 540 586 511 559 539 556 541 557 540 557 540 1682 539 559 538 558 539 558 539 559 538 558 539 560 537 558 539 559 538 558 539 557 540 1681 540 558 539 1680 541 557 540 557 540 559 538 558 539 559 538 1682 539 1682 539 1682 539 558 539 558 539 1682 539 1682 539 558 565 +# +# Model: Carrier 42QG5A580SC +# +name: Off +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8403 4308 519 1425 518 625 520 1461 485 1427 518 559 517 564 567 1386 518 1429 517 562 597 524 519 1431 517 1430 518 567 516 1426 518 565 517 1429 518 1431 518 1425 519 565 517 1457 485 562 518 1429 519 1424 520 565 516 1426 517 561 519 1430 515 1427 518 563 595 525 518 1428 517 528 489 21085 8424 4296 642 467 568 1400 569 533 569 536 647 1402 569 1395 569 535 568 534 569 1405 566 1397 567 549 568 535 569 1401 567 533 570 1399 571 537 570 534 568 537 567 1397 570 535 571 1401 568 534 567 533 567 1399 567 539 568 1402 569 565 569 532 571 1399 571 1397 569 535 566 1358 489 21085 8401 4318 512 1438 517 573 515 1476 532 1389 516 573 518 609 535 1393 568 1392 516 574 567 528 566 1393 565 1390 516 576 516 1437 517 574 517 1441 516 1445 567 1389 517 578 566 1390 516 578 568 1398 566 1392 515 575 516 1437 516 574 517 1442 567 1425 483 597 515 575 516 1446 514 539 490 +# +name: Dh +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8391 4318 536 1417 518 564 516 1432 517 1428 518 563 518 562 517 1433 516 1428 518 564 519 565 513 1433 517 1430 517 562 518 1463 483 561 517 1430 516 1428 518 563 595 1393 516 559 519 565 514 1425 519 1429 517 569 514 1426 518 566 514 1466 485 562 518 559 518 561 518 1425 519 531 488 21116 8369 4318 569 534 641 1326 640 462 641 465 641 1330 641 1325 639 464 568 534 595 1403 641 1328 641 462 639 467 640 1328 568 536 642 1367 568 531 567 536 569 1398 568 537 542 1432 640 1327 567 532 568 535 567 1400 567 539 567 1399 568 536 568 1402 569 1402 568 1401 567 537 565 1359 487 21117 8392 4294 565 1388 517 575 566 1393 516 1443 514 574 516 573 517 1443 567 1391 515 574 516 577 566 1393 565 1390 566 528 567 1392 516 575 567 1395 565 1390 515 576 568 1391 515 572 566 528 565 1395 565 1393 515 572 564 1391 515 581 563 1389 516 578 513 609 483 576 566 1391 514 538 487 +# +name: Cool_hi +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8424 4292 514 1428 518 559 518 1431 514 1432 517 561 515 566 512 1433 516 1434 516 562 519 562 516 1432 517 1426 518 566 516 1429 517 566 516 1429 518 1428 517 562 516 1467 481 570 517 561 518 565 519 563 515 566 516 567 516 1433 516 1429 514 564 518 561 518 562 519 1428 519 536 562 21009 8478 4280 638 461 641 1328 641 456 642 467 637 1325 643 1326 568 597 568 537 639 1330 641 1327 568 535 640 468 639 1324 568 534 543 1432 566 535 641 494 637 1327 566 532 640 1329 567 1398 640 1327 641 1327 640 1326 642 1328 568 531 568 538 567 1402 567 1406 566 1402 568 532 569 1357 489 21085 8401 4319 565 1394 516 577 567 1396 565 1390 515 574 543 566 516 1441 568 1392 516 575 566 531 566 1393 567 1390 516 576 515 1456 515 579 562 1392 515 1440 515 575 566 1391 516 576 544 569 563 525 516 574 514 606 514 576 514 1439 567 1390 515 575 515 574 570 566 567 1390 515 540 488 +# +name: Cool_lo +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8401 4306 518 1460 483 566 518 1432 517 1430 514 561 516 564 517 1429 518 1430 519 592 485 564 517 1427 517 1432 516 561 545 1430 516 566 518 1462 483 1430 515 568 517 1427 516 566 516 564 517 1430 518 1425 518 559 518 562 518 1426 518 1425 517 593 484 561 516 573 516 1427 517 530 564 21007 8401 4322 642 465 643 1324 643 457 643 458 643 1327 643 1327 641 463 642 461 644 1325 644 1324 643 462 642 483 643 1328 641 460 645 1321 643 458 643 464 641 1325 643 459 644 1327 642 1323 643 461 643 461 642 1347 644 1331 641 463 639 462 641 1327 571 1405 542 1428 670 462 645 1282 562 21007 8402 4317 515 1436 517 606 641 1321 516 1438 517 572 515 578 516 1441 515 1440 516 572 515 575 515 1474 610 1316 515 574 644 1314 516 574 567 1394 640 1316 517 578 639 1319 516 576 517 575 513 1447 641 1315 516 576 515 577 566 1396 514 1440 516 573 518 571 638 456 565 1393 515 538 564 +# +name: Heat_hi +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8399 4307 519 1426 518 560 517 1432 517 1460 485 561 518 558 517 1436 518 1427 518 555 520 561 517 1430 519 1428 516 560 519 1425 518 566 517 1430 516 1432 519 563 519 1425 518 563 515 1429 517 1433 517 1430 516 1432 518 1429 518 568 516 1432 515 1429 519 561 516 567 517 1427 519 533 487 21083 8424 4339 567 536 568 1402 641 493 608 462 545 1431 640 1326 567 532 568 538 640 1331 640 1329 641 536 565 534 641 1329 567 537 639 1329 640 462 642 467 641 1325 568 532 642 1332 640 488 568 534 565 536 566 566 536 567 641 1329 570 535 638 464 569 1401 641 1326 568 534 639 1287 490 21083 8403 4313 567 1390 516 579 514 1441 515 1438 517 575 516 576 568 1393 568 1394 515 606 534 530 515 1441 567 1425 482 576 568 1392 514 578 566 1392 569 1432 515 576 568 1389 517 577 515 1444 515 1437 569 1393 516 1444 566 1389 566 528 567 1394 566 1419 517 575 513 578 515 1440 516 539 490 +# +name: Heat_lo +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8425 4291 542 1401 544 538 542 1404 518 1427 544 534 570 540 516 1434 542 1399 544 539 544 539 541 1403 541 1402 516 570 517 1427 545 566 511 1406 517 1431 542 534 544 1406 543 536 517 567 543 1404 542 1400 595 525 544 1405 542 534 516 1433 516 1428 544 537 544 535 543 1403 542 505 488 21084 8424 4298 566 535 569 1402 567 533 568 537 570 1403 570 1403 565 534 566 537 566 1402 569 1398 569 533 569 538 592 1446 569 535 570 1400 569 567 535 535 568 1437 568 533 568 1398 569 1402 565 533 567 534 569 1403 568 536 569 1402 568 535 567 534 571 1403 568 1415 566 536 571 1362 489 21084 8403 4313 516 1439 517 574 515 1442 515 1441 518 573 516 574 567 1397 514 1440 515 573 516 575 516 1443 515 1439 518 574 516 1440 517 608 535 1396 517 1441 517 579 515 1438 515 576 517 578 568 1390 569 1391 516 575 518 1439 516 573 517 1445 566 1391 516 571 517 572 516 1441 514 543 487 From 5ef6adb9eaffb72632516d82abe5dac1cf781dd7 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 26 Dec 2023 23:29:24 +0300 Subject: [PATCH 29/35] upd changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 62edba5a2..a3b54a4be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ - Also in app **Enhanced Sub-GHz Chat** - NFC part was temporarily removed to make app usable, NFC part of the app requires remaking it with new nfc stack
**API was updated to v50.x** ## New changes +* IR: Updated infrared assets (by @amec0e | PR #677) * NFC: Fix Saflok edge case 0.5% of UIDs got wrong result (by @noproto | PR #668) * NFC: Zolotaya Korona transport card parser added (by @Leptopt1los) * NFC: Parsers cleanup for new api (by @Leptopt1los) From 76ed466eb41a0450aef249223852a7faccfe9a28 Mon Sep 17 00:00:00 2001 From: Eric Betts Date: Wed, 27 Dec 2023 21:03:50 -0800 Subject: [PATCH 30/35] Nfc: HID MFC Plugin (#3312) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- applications/main/nfc/application.fam | 9 ++ .../main/nfc/plugins/supported_cards/hid.c | 153 ++++++++++++++++++ 2 files changed, 162 insertions(+) create mode 100644 applications/main/nfc/plugins/supported_cards/hid.c diff --git a/applications/main/nfc/application.fam b/applications/main/nfc/application.fam index ecb61fe60..4d8cb86c0 100644 --- a/applications/main/nfc/application.fam +++ b/applications/main/nfc/application.fam @@ -101,6 +101,15 @@ App( sources=["plugins/supported_cards/umarsh.c"], ) +App( + appid="hid_parser", + apptype=FlipperAppType.PLUGIN, + entry_point="hid_plugin_ep", + targets=["f7"], + requires=["nfc"], + sources=["plugins/supported_cards/hid.c"], +) + App( appid="nfc_start", targets=["f7"], diff --git a/applications/main/nfc/plugins/supported_cards/hid.c b/applications/main/nfc/plugins/supported_cards/hid.c new file mode 100644 index 000000000..66ced4d0c --- /dev/null +++ b/applications/main/nfc/plugins/supported_cards/hid.c @@ -0,0 +1,153 @@ +#include "nfc_supported_card_plugin.h" + +#include + +#include +#include +#include + +#define TAG "HID" + +static const uint64_t hid_key = 0x484944204953; + +bool hid_verify(Nfc* nfc) { + bool verified = false; + + do { + const uint8_t verify_sector = 1; + uint8_t block_num = mf_classic_get_first_block_num_of_sector(verify_sector); + FURI_LOG_D(TAG, "Verifying sector %u", verify_sector); + + MfClassicKey key = {}; + nfc_util_num2bytes(hid_key, COUNT_OF(key.data), key.data); + + MfClassicAuthContext auth_ctx = {}; + MfClassicError error = + 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; + } + + verified = true; + } while(false); + + return verified; +} + +static bool hid_read(Nfc* nfc, NfcDevice* device) { + furi_assert(nfc); + furi_assert(device); + + bool is_read = false; + + MfClassicData* data = mf_classic_alloc(); + nfc_device_copy_data(device, NfcProtocolMfClassic, data); + + do { + MfClassicType type = MfClassicType1k; + MfClassicError error = mf_classic_poller_sync_detect_type(nfc, &type); + if(error != MfClassicErrorNone) break; + + data->type = type; + MfClassicDeviceKeys keys = {}; + for(size_t i = 0; i < mf_classic_get_total_sectors_num(data->type); i++) { + nfc_util_num2bytes(hid_key, sizeof(MfClassicKey), keys.key_a[i].data); + FURI_BIT_SET(keys.key_a_mask, i); + nfc_util_num2bytes(hid_key, sizeof(MfClassicKey), keys.key_b[i].data); + FURI_BIT_SET(keys.key_b_mask, i); + } + + error = mf_classic_poller_sync_read(nfc, &keys, data); + if(error != MfClassicErrorNone) { + FURI_LOG_W(TAG, "Failed to read data"); + break; + } + + nfc_device_set_data(device, NfcProtocolMfClassic, data); + + is_read = true; + } while(false); + + mf_classic_free(data); + + return is_read; +} + +static uint8_t get_bit_length(const uint8_t* half_block) { + uint8_t bitLength = 0; + uint32_t* halves = (uint32_t*)half_block; + if(halves[0] == 0) { + uint8_t leading0s = __builtin_clz(REVERSE_BYTES_U32(halves[1])); + bitLength = 31 - leading0s; + } else { + uint8_t leading0s = __builtin_clz(REVERSE_BYTES_U32(halves[0])); + bitLength = 63 - leading0s; + } + + return bitLength; +} + +static uint64_t get_pacs_bits(const uint8_t* block, uint8_t bitLength) { + // Remove sentinel bit from credential. Byteswapping to handle array of bytes vs 64bit value + uint64_t sentinel = __builtin_bswap64(1ULL << bitLength); + uint64_t swapped = 0; + memcpy(&swapped, block, sizeof(uint64_t)); + swapped = __builtin_bswap64(swapped ^ sentinel); + FURI_LOG_D(TAG, "PACS: (%d) %016llx", bitLength, swapped); + return swapped; +} + +static bool hid_parse(const NfcDevice* device, FuriString* parsed_data) { + furi_assert(device); + + const MfClassicData* data = nfc_device_get_data(device, NfcProtocolMfClassic); + + bool parsed = false; + + do { + // verify key + const uint8_t verify_sector = 1; + MfClassicSectorTrailer* sec_tr = + mf_classic_get_sector_trailer_by_sector(data, verify_sector); + uint64_t key = nfc_util_bytes2num(sec_tr->key_a.data, 6); + if(key != hid_key) break; + + // Currently doesn't support bit length > 63 + const uint8_t* credential_block = data->block[5].data + 8; + + uint8_t bitLength = get_bit_length(credential_block); + if(bitLength == 0) break; + + uint64_t credential = get_pacs_bits(credential_block, bitLength); + if(credential == 0) break; + + furi_string_printf(parsed_data, "\e#HID Card\n%dbit\n%llx", bitLength, credential); + + parsed = true; + + } while(false); + + return parsed; +} + +/* Actual implementation of app<>plugin interface */ +static const NfcSupportedCardsPlugin hid_plugin = { + .protocol = NfcProtocolMfClassic, + .verify = hid_verify, + .read = hid_read, + .parse = hid_parse, +}; + +/* Plugin descriptor to comply with basic plugin specification */ +static const FlipperAppPluginDescriptor hid_plugin_descriptor = { + .appid = NFC_SUPPORTED_CARD_PLUGIN_APP_ID, + .ep_api_version = NFC_SUPPORTED_CARD_PLUGIN_API_VERSION, + .entry_point = &hid_plugin, +}; + +/* Plugin entry point - must return a pointer to const descriptor */ +const FlipperAppPluginDescriptor* hid_plugin_ep() { + return &hid_plugin_descriptor; +} From f6a38352e88f895154f7ddc751e4a837e4b8a15a Mon Sep 17 00:00:00 2001 From: ry4000 <154689120+ry4000@users.noreply.github.com> Date: Thu, 28 Dec 2023 16:12:13 +1100 Subject: [PATCH 31/35] Update mf_classic_dict.nfc (#3314) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This Commit proposes the addition of the 33 Bandai Namco Passport / Sega Aime Card static access keys that has been available to Members of the Flipper Devices Discord Server; for convenience, they are listed in Sector Key A/B order. Sector 0 Key B has two possible access keys; 019761AA8082 [current Bandai Namco Passports] 574343467632 [Sega Aime Cards / early-edition Bandai Namco Passports] Co-authored-by: あく --- .../resources/nfc/assets/mf_classic_dict.nfc | 37 ++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/applications/main/nfc/resources/nfc/assets/mf_classic_dict.nfc b/applications/main/nfc/resources/nfc/assets/mf_classic_dict.nfc index 85f7193cd..25f750102 100644 --- a/applications/main/nfc/resources/nfc/assets/mf_classic_dict.nfc +++ b/applications/main/nfc/resources/nfc/assets/mf_classic_dict.nfc @@ -1315,4 +1315,39 @@ CE99FBC8BD26 # Volgograd (Russia) Volna transport cards keys 2B787A063D5D -D37C8F1793F7 \ No newline at end of file +D37C8F1793F7 + +# Bandai Namco Passport [fka Banapassport] / Sega Aime Card +6090D00632F5 +019761AA8082 +574343467632 +A99164400748 +62742819AD7C +CC5075E42BA1 +B9DF35A0814C +8AF9C718F23D +58CD5C3673CB +FC80E88EB88C +7A3CDAD7C023 +30424C029001 +024E4E44001F +ECBBFA57C6AD +4757698143BD +1D30972E6485 +F8526D1A8D6D +1300EC8C7E80 +F80A65A87FFA +DEB06ED4AF8E +4AD96BF28190 +000390014D41 +0800F9917CB0 +730050555253 +4146D4A956C4 +131157FBB126 +E69DD9015A43 +337237F254D5 +9A8389F32FBF +7B8FB4A7100B +C8382A233993 +7B304F2A12A6 +FC9418BF788B From 35e74c07d13280dd149bbe61e8c91c00c72d3b91 Mon Sep 17 00:00:00 2001 From: YaBa Date: Thu, 28 Dec 2023 05:23:12 +0000 Subject: [PATCH 32/35] Added NFC plugin; parser for WashCity cards. (#3319) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Added NFC plugin; parser for WashCity cards. * Fixed file to the correct path * Added demo file Demo_WC_20E.nfc * Fixed clang format * fixed typo (balance_cents) * Removed demo file as requested. Co-authored-by: あく --- applications/main/nfc/application.fam | 9 + .../nfc/plugins/supported_cards/washcity.c | 200 ++++++++++++++++++ 2 files changed, 209 insertions(+) create mode 100644 applications/main/nfc/plugins/supported_cards/washcity.c diff --git a/applications/main/nfc/application.fam b/applications/main/nfc/application.fam index 4d8cb86c0..b92d0ebf1 100644 --- a/applications/main/nfc/application.fam +++ b/applications/main/nfc/application.fam @@ -65,6 +65,15 @@ App( sources=["plugins/supported_cards/troika.c"], ) +App( + appid="washcity_parser", + apptype=FlipperAppType.PLUGIN, + entry_point="washcity_plugin_ep", + targets=["f7"], + requires=["nfc"], + sources=["plugins/supported_cards/washcity.c"], +) + App( appid="plantain_parser", apptype=FlipperAppType.PLUGIN, diff --git a/applications/main/nfc/plugins/supported_cards/washcity.c b/applications/main/nfc/plugins/supported_cards/washcity.c new file mode 100644 index 000000000..a0edeef6a --- /dev/null +++ b/applications/main/nfc/plugins/supported_cards/washcity.c @@ -0,0 +1,200 @@ +/* + * Parser for WashCity MarkItaly Card (Europe). + * + * Copyright 2023 Filipe Polido (YaBaPT) + * + * Based on MetroMoney by Leptoptilos + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "nfc_supported_card_plugin.h" + +#include "protocols/mf_classic/mf_classic.h" +#include + +#include +#include +#include +#include + +#define TAG "WashCity" + +typedef struct { + uint64_t a; + uint64_t b; +} MfClassicKeyPair; + +static const MfClassicKeyPair washcity_1k_keys[] = { + {.a = 0xA0A1A2A3A4A5, .b = 0x010155010100}, // Sector 00 + {.a = 0xC78A3D0E1BCD, .b = 0xFFFFFFFFFFFF}, // Sector 01 + {.a = 0xC78A3D0E0000, .b = 0xFFFFFFFFFFFF}, // Sector 02 + {.a = 0xC78A3D0E0000, .b = 0xFFFFFFFFFFFF}, // Sector 03 + {.a = 0xC78A3D0E0000, .b = 0xFFFFFFFFFFFF}, // Sector 04 + {.a = 0xC78A3D0E0000, .b = 0xFFFFFFFFFFFF}, // Sector 05 + {.a = 0xC78A3D0E0000, .b = 0xFFFFFFFFFFFF}, // Sector 06 + {.a = 0xC78A3D0E0000, .b = 0xFFFFFFFFFFFF}, // Sector 07 + {.a = 0xC78A3D0E0000, .b = 0xFFFFFFFFFFFF}, // Sector 08 + {.a = 0x010155010100, .b = 0xFFFFFFFFFFFF}, // Sector 09 + {.a = 0x010155010100, .b = 0xFFFFFFFFFFFF}, // Sector 10 + {.a = 0x010155010100, .b = 0xFFFFFFFFFFFF}, // Sector 11 + {.a = 0x010155010100, .b = 0xFFFFFFFFFFFF}, // Sector 12 + {.a = 0x010155010100, .b = 0xFFFFFFFFFFFF}, // Sector 13 + {.a = 0x010155010100, .b = 0xFFFFFFFFFFFF}, // Sector 14 + {.a = 0x010155010100, .b = 0xFFFFFFFFFFFF}, // Sector 15 +}; + +static bool washcity_verify(Nfc* nfc) { + bool verified = false; + + do { + const uint8_t ticket_sector_number = 0; + const uint8_t ticket_block_number = + mf_classic_get_first_block_num_of_sector(ticket_sector_number) + 1; + FURI_LOG_D(TAG, "Verifying sector %u", ticket_sector_number); + + MfClassicKey key = {0}; + nfc_util_num2bytes(washcity_1k_keys[ticket_sector_number].a, COUNT_OF(key.data), key.data); + + MfClassicAuthContext auth_context; + MfClassicError error = mf_classic_poller_sync_auth( + nfc, ticket_block_number, &key, MfClassicKeyTypeA, &auth_context); + if(error != MfClassicErrorNone) { + FURI_LOG_D(TAG, "Failed to read block %u: %d", ticket_block_number, error); + break; + } + + verified = true; + } while(false); + + return verified; +} + +static bool washcity_read(Nfc* nfc, NfcDevice* device) { + furi_assert(nfc); + furi_assert(device); + + bool is_read = false; + + MfClassicData* data = mf_classic_alloc(); + nfc_device_copy_data(device, NfcProtocolMfClassic, data); + + do { + MfClassicType type = MfClassicTypeMini; + MfClassicError error = mf_classic_poller_sync_detect_type(nfc, &type); + if(error != MfClassicErrorNone) break; + + data->type = type; + if(type != MfClassicType1k) break; + + MfClassicDeviceKeys keys = { + .key_a_mask = 0, + .key_b_mask = 0, + }; + for(size_t i = 0; i < mf_classic_get_total_sectors_num(data->type); i++) { + nfc_util_num2bytes(washcity_1k_keys[i].a, sizeof(MfClassicKey), keys.key_a[i].data); + FURI_BIT_SET(keys.key_a_mask, i); + nfc_util_num2bytes(washcity_1k_keys[i].b, sizeof(MfClassicKey), keys.key_b[i].data); + FURI_BIT_SET(keys.key_b_mask, i); + } + + error = mf_classic_poller_sync_read(nfc, &keys, data); + if(error != MfClassicErrorNone) { + FURI_LOG_W(TAG, "Failed to read data"); + break; + } + + nfc_device_set_data(device, NfcProtocolMfClassic, data); + + is_read = true; + } while(false); + + mf_classic_free(data); + + return is_read; +} + +static bool washcity_parse(const NfcDevice* device, FuriString* parsed_data) { + furi_assert(device); + + const MfClassicData* data = nfc_device_get_data(device, NfcProtocolMfClassic); + + bool parsed = false; + + do { + // Verify key + const uint8_t ticket_sector_number = 1; + const uint8_t ticket_block_number = 0; + + const MfClassicSectorTrailer* sec_tr = + mf_classic_get_sector_trailer_by_sector(data, ticket_sector_number); + + const uint64_t key = nfc_util_bytes2num(sec_tr->key_a.data, COUNT_OF(sec_tr->key_a.data)); + if(key != washcity_1k_keys[ticket_sector_number].a) break; + + // Parse data + const uint8_t start_block_num = + mf_classic_get_first_block_num_of_sector(ticket_sector_number); + + const uint8_t* block_start_ptr = + &data->block[start_block_num + ticket_block_number].data[0]; + + uint32_t balance = nfc_util_bytes2num(block_start_ptr + 2, 2); + + uint32_t balance_eur = balance / 100; + uint8_t balance_cents = balance % 100; + + size_t uid_len = 0; + const uint8_t* uid = mf_classic_get_uid(data, &uid_len); + + // Card Number is printed in HEX (equal to UID) + char card_number[2 * uid_len + 1]; + + for(size_t i = 0; i < uid_len; ++i) { + card_number[2 * i] = "0123456789ABCDEF"[uid[i] >> 4]; + card_number[2 * i + 1] = "0123456789ABCDEF"[uid[i] & 0xF]; + } + + card_number[2 * uid_len] = '\0'; + + furi_string_printf( + parsed_data, + "\e#WashCity\nCard number: %s\nBalance: %lu.%02u EUR", + card_number, + balance_eur, + balance_cents); + parsed = true; + } while(false); + + return parsed; +} + +/* Actual implementation of app<>plugin interface */ +static const NfcSupportedCardsPlugin washcity_plugin = { + .protocol = NfcProtocolMfClassic, + .verify = washcity_verify, + .read = washcity_read, + .parse = washcity_parse, +}; + +/* Plugin descriptor to comply with basic plugin specification */ +static const FlipperAppPluginDescriptor washcity_plugin_descriptor = { + .appid = NFC_SUPPORTED_CARD_PLUGIN_APP_ID, + .ep_api_version = NFC_SUPPORTED_CARD_PLUGIN_API_VERSION, + .entry_point = &washcity_plugin, +}; + +/* Plugin entry point - must return a pointer to const descriptor */ +const FlipperAppPluginDescriptor* washcity_plugin_ep() { + return &washcity_plugin_descriptor; +} \ No newline at end of file From 2a0a54a224523d9f11ee22f2832c5d4e345bfba8 Mon Sep 17 00:00:00 2001 From: Arthur Braghetto Date: Thu, 28 Dec 2023 02:35:01 -0300 Subject: [PATCH 33/35] Add Samsung AC remotes DB93 and AR-EH04 (#3301) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- .../infrared/resources/infrared/assets/ac.ir | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/applications/main/infrared/resources/infrared/assets/ac.ir b/applications/main/infrared/resources/infrared/assets/ac.ir index 201a29305..64d473def 100644 --- a/applications/main/infrared/resources/infrared/assets/ac.ir +++ b/applications/main/infrared/resources/infrared/assets/ac.ir @@ -712,3 +712,79 @@ type: raw frequency: 38000 duty_cycle: 0.330000 data: 8425 4291 542 1401 544 538 542 1404 518 1427 544 534 570 540 516 1434 542 1399 544 539 544 539 541 1403 541 1402 516 570 517 1427 545 566 511 1406 517 1431 542 534 544 1406 543 536 517 567 543 1404 542 1400 595 525 544 1405 542 534 516 1433 516 1428 544 537 544 535 543 1403 542 505 488 21084 8424 4298 566 535 569 1402 567 533 568 537 570 1403 570 1403 565 534 566 537 566 1402 569 1398 569 533 569 538 592 1446 569 535 570 1400 569 567 535 535 568 1437 568 533 568 1398 569 1402 565 533 567 534 569 1403 568 536 569 1402 568 535 567 534 571 1403 568 1415 566 536 571 1362 489 21084 8403 4313 516 1439 517 574 515 1442 515 1441 518 573 516 574 567 1397 514 1440 515 573 516 575 516 1443 515 1439 518 574 516 1440 517 608 535 1396 517 1441 517 579 515 1438 515 576 517 578 568 1390 569 1391 516 575 518 1439 516 573 517 1445 566 1391 516 571 517 572 516 1441 514 543 487 +# +# Model: Samsung DB93 +# +name: Off +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 667 17837 3089 8903 555 445 578 1411 583 442 554 442 529 468 528 468 554 443 554 442 554 444 552 1441 552 472 523 475 522 1473 522 1473 522 475 547 1447 548 1446 548 1446 548 1446 548 1446 548 449 548 450 547 451 546 474 523 476 521 476 521 476 522 476 521 475 546 451 547 450 548 449 548 449 548 449 548 449 548 449 548 449 548 450 547 450 547 451 546 474 523 474 523 476 521 477 520 477 520 477 521 476 521 476 546 450 547 450 547 450 546 450 547 451 546 451 546 1448 546 1472 522 2982 3005 8963 522 1499 495 502 495 502 495 502 496 501 496 501 521 476 522 475 522 475 522 1472 522 475 522 475 522 1473 521 475 522 1473 522 1499 495 1500 494 1500 496 1499 521 1473 522 475 522 475 522 475 522 475 522 475 522 475 522 476 521 475 522 476 521 476 521 476 521 502 495 503 494 503 495 502 495 501 496 501 521 476 522 476 521 476 521 476 521 476 521 476 521 476 521 476 521 476 521 476 521 476 521 503 494 503 494 503 493 504 494 502 495 502 495 502 520 477 520 2984 3003 8966 519 1475 520 477 520 477 520 477 520 478 519 477 520 478 519 479 518 504 493 1502 493 504 493 503 494 503 494 1501 519 1476 518 1475 519 478 519 1476 518 1476 519 1477 517 1501 493 1503 491 1503 493 1502 493 1502 518 479 518 479 518 479 518 1476 518 1477 517 1477 517 504 493 504 493 504 493 531 466 507 490 1529 467 506 491 529 468 1527 492 1502 492 505 493 1502 492 1502 492 505 492 504 493 504 492 505 492 506 491 532 465 532 465 531 467 530 467 530 467 1528 467 1527 492 +# +name: Dh +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 667 17829 3090 8902 556 444 579 1410 584 441 529 468 529 468 554 443 554 442 555 443 553 444 551 1442 551 474 522 475 522 1473 522 475 522 475 547 1448 547 1447 547 1447 547 1447 548 1447 547 449 548 450 547 474 523 474 523 476 521 476 521 476 521 477 521 475 522 476 546 450 547 449 548 449 548 450 547 449 548 450 547 450 547 450 547 451 546 474 523 474 523 474 523 479 518 479 518 479 518 501 496 501 496 477 545 475 522 452 545 474 523 474 523 1472 522 1472 522 1472 522 1472 523 2981 3005 8990 494 1499 495 502 496 501 496 501 496 501 522 475 522 475 522 475 522 475 522 1473 521 475 522 475 522 1473 521 475 522 1473 521 1500 494 1500 495 1499 520 1474 522 1473 522 475 522 475 522 476 521 475 522 476 521 476 521 476 521 476 521 476 521 477 520 503 494 503 494 503 495 502 495 502 520 477 521 476 521 476 521 476 521 476 521 476 521 476 521 476 521 476 521 476 521 476 521 477 520 504 493 503 494 503 494 503 495 502 495 502 495 502 520 477 520 477 520 2984 3003 8966 519 1475 519 477 520 478 519 478 519 478 519 479 518 503 494 505 492 505 492 1503 493 504 493 504 493 504 518 1477 518 1476 518 1476 518 479 518 1477 517 1477 517 1501 493 1504 490 1528 468 1527 468 1527 493 1501 493 504 493 504 493 504 493 1501 493 1502 492 1502 492 504 493 505 491 532 440 556 466 531 467 530 468 530 467 530 467 1527 492 1503 491 505 492 504 493 504 493 505 491 1503 492 505 467 530 492 506 466 557 464 533 464 532 466 1528 467 1528 467 1528 466 1528 491 +# +name: Cool_hi +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 667 17831 3089 8903 581 420 578 1411 583 442 529 468 528 468 554 443 554 442 554 443 553 445 551 1443 550 475 521 475 522 1473 522 475 547 449 548 1447 548 1446 548 1446 548 1446 548 1446 548 449 548 449 548 450 547 473 524 476 521 475 522 476 520 476 522 475 522 475 547 449 549 449 548 449 548 449 548 449 548 449 548 449 548 449 548 449 548 450 547 474 523 474 523 476 521 476 521 476 520 477 521 476 546 451 547 450 547 450 547 449 548 450 547 1447 547 1448 546 1448 546 1472 523 2957 3029 8967 518 1477 517 502 495 501 496 501 521 475 522 475 522 475 522 475 522 475 522 1472 522 474 523 475 522 1473 521 475 522 1472 522 1499 495 1500 495 1499 520 1474 522 1473 521 475 522 475 522 475 522 475 522 475 522 475 522 475 522 475 522 476 521 502 495 502 495 503 494 502 496 501 496 501 521 476 522 476 521 475 522 475 522 476 521 476 521 476 521 476 521 476 521 476 521 476 521 476 521 503 494 503 494 503 494 503 495 502 495 502 520 477 520 476 521 476 521 2984 3003 8965 520 1474 521 477 520 477 520 477 520 477 520 477 520 478 519 504 493 504 493 1502 494 503 494 502 495 1500 520 1475 519 1475 519 1475 519 478 519 1475 519 1476 518 1501 493 1502 492 1503 493 1501 494 1501 518 1476 518 478 519 478 519 478 519 1476 518 1476 518 1477 517 504 493 506 491 506 491 506 491 506 492 505 492 504 493 504 518 481 516 1501 493 504 493 504 493 480 517 1501 493 504 493 504 493 504 493 505 491 532 466 531 466 532 466 1528 467 1527 468 1527 492 1502 492 +# +name: Cool_lo +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 667 17832 3088 8903 575 448 555 1411 583 441 529 468 529 468 554 443 554 442 554 443 553 444 551 1443 550 474 522 475 522 1473 522 475 522 475 547 1447 548 1446 548 1446 548 1446 548 1447 547 449 548 449 548 474 523 474 523 476 521 476 521 476 521 477 521 475 522 475 547 450 548 449 548 450 547 449 548 449 548 450 547 450 547 449 547 451 546 452 545 474 523 474 523 477 520 478 519 477 519 478 520 477 545 452 545 451 547 451 546 474 523 474 523 1450 544 1472 522 1472 522 1472 523 2981 3005 8990 494 1499 495 502 496 501 496 501 521 476 521 475 522 475 522 475 522 475 522 1473 521 475 522 475 522 1473 521 476 521 1473 521 1500 494 1500 495 1499 495 1499 521 1473 522 475 522 475 522 476 521 475 522 476 521 476 521 476 521 476 521 476 521 477 520 503 494 503 494 503 495 502 495 502 520 477 520 476 521 476 521 476 521 476 521 476 521 476 521 476 521 476 521 476 521 477 520 477 520 478 519 503 493 504 493 504 494 503 494 502 519 478 520 477 520 477 520 2984 3003 8966 519 1475 519 477 520 477 520 478 519 478 519 478 519 503 494 504 493 505 492 1503 493 504 493 504 493 503 519 478 519 1476 518 1476 518 478 519 1476 518 1477 517 1501 493 1504 490 1504 490 1503 493 1502 493 1502 517 480 517 504 493 480 517 1477 517 1502 492 1502 492 504 493 504 493 504 493 531 466 531 466 1529 467 1527 467 1527 492 504 493 1502 492 505 492 504 493 505 492 1503 492 505 492 505 492 505 467 557 464 532 441 556 466 532 466 1528 466 1528 491 1503 491 1503 466 +# +name: Heat_hi +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 665 17827 3090 8902 556 444 579 1412 583 441 530 467 529 468 554 442 555 442 554 442 554 444 551 1443 550 473 523 475 522 1472 521 475 523 474 523 1471 549 1446 548 1445 549 1446 548 1445 549 448 549 448 549 449 548 473 523 473 524 475 522 475 522 475 523 475 522 474 548 449 548 449 549 448 549 448 549 448 549 448 549 448 549 449 548 449 548 449 548 450 547 473 524 474 523 476 521 476 521 476 521 476 522 475 547 450 547 450 548 449 548 449 548 1447 547 1447 547 1447 547 1448 546 2957 3030 8962 522 1475 519 501 496 501 497 478 519 500 522 475 522 475 523 474 523 474 523 1472 522 474 523 474 523 1472 522 475 522 1472 522 1499 495 1499 496 1499 496 1498 522 1473 522 474 522 475 522 475 522 474 523 475 522 475 522 475 522 475 522 475 522 475 522 502 495 502 495 502 495 501 496 501 496 501 521 476 522 475 522 475 522 475 522 475 522 475 522 475 522 475 522 475 522 475 522 476 521 476 521 502 495 502 495 502 495 503 495 502 495 501 521 476 521 476 521 2983 3004 8964 521 1474 520 476 521 476 521 477 520 476 521 477 520 477 520 503 494 503 494 1501 494 502 495 502 495 502 520 477 521 1474 520 1474 520 477 520 1474 520 1475 519 1475 519 1500 494 1502 492 1502 493 1501 494 1500 519 478 519 477 520 477 520 1475 519 1475 519 1475 519 478 519 478 519 503 494 505 492 505 492 505 492 1503 493 1502 493 1502 517 1476 518 479 518 479 518 479 518 480 517 479 518 1501 493 504 493 504 493 530 467 531 466 531 467 1527 468 1527 491 1502 493 1501 493 +# +name: Heat_lo +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 668 17822 3064 8902 582 442 555 1413 581 442 528 468 529 494 528 469 502 495 527 470 526 471 525 1468 552 446 550 448 549 1446 548 448 549 448 549 1446 548 1448 546 1471 523 1473 521 1473 521 476 521 475 522 475 547 449 548 449 548 449 548 449 548 449 548 449 548 449 548 449 548 450 547 474 523 474 523 474 523 477 520 477 520 477 520 477 521 476 521 476 546 450 548 450 547 474 523 474 523 450 547 474 523 474 523 452 545 474 523 474 523 474 523 1500 494 1499 495 1499 496 1498 522 2955 3032 8963 521 1472 522 475 522 474 523 475 522 475 522 475 522 475 522 475 522 475 522 1499 495 502 495 502 495 1499 496 501 521 1473 522 1473 522 1472 522 1472 522 1473 521 1473 522 475 522 475 522 502 495 502 495 502 495 503 495 501 496 501 496 501 521 476 521 476 521 476 521 476 521 476 521 476 521 476 521 476 521 476 521 476 521 477 520 504 493 503 494 503 494 503 495 502 495 502 495 502 520 477 521 476 521 476 521 476 521 477 520 477 520 477 520 476 521 477 520 2984 3003 8967 518 1502 492 504 493 504 494 503 494 503 494 503 519 478 519 478 519 478 519 1476 518 478 518 479 518 478 519 478 519 1501 493 1501 493 506 491 1504 491 1527 468 1503 492 1526 493 1501 493 1501 494 1501 493 1501 493 504 493 504 493 504 493 1528 466 1529 466 1528 467 529 468 529 493 504 493 504 493 504 493 1502 492 1502 492 1502 467 529 493 1502 491 533 465 532 465 532 465 531 467 530 467 1528 467 530 467 530 467 530 467 530 467 530 467 1527 467 1528 466 1528 466 1529 492 +# +# Model: Samsung AR-EH04 +# +name: Off +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 663 17769 3057 8901 529 492 527 1434 556 465 529 464 529 464 555 439 555 438 556 438 554 440 553 1435 552 444 549 470 524 1465 524 1466 522 473 522 1467 522 1466 549 1440 549 1440 548 1440 548 445 549 445 549 446 548 447 547 471 523 470 524 471 523 472 522 472 521 473 522 472 522 472 523 472 548 446 549 445 548 446 548 447 547 447 547 446 548 447 547 470 524 471 523 471 523 471 523 471 523 498 496 475 519 498 496 497 498 497 522 472 523 471 524 470 523 471 523 1443 546 1442 547 2947 3023 8935 522 1466 522 471 523 472 522 474 520 498 496 498 496 498 497 497 497 497 523 1466 523 471 523 471 523 1466 523 471 523 1466 522 1467 522 1467 522 1493 495 1493 496 1493 497 497 522 472 523 471 523 471 522 472 522 472 522 472 522 472 522 472 522 472 522 472 522 472 522 472 522 499 495 499 495 499 495 499 495 499 496 498 522 472 523 472 523 471 522 472 522 472 522 472 522 472 522 473 521 473 521 473 521 473 521 473 521 499 495 500 494 499 495 499 496 499 521 2947 3024 8937 521 1467 521 473 521 473 521 472 521 473 521 473 521 473 521 473 521 474 520 1469 520 500 494 500 494 1495 495 500 495 499 520 474 521 1468 520 1468 521 1468 521 1468 521 1468 521 1469 519 1470 518 1495 493 1496 493 500 495 499 520 474 521 1468 520 1469 520 1469 520 473 521 474 520 474 520 475 519 476 518 500 494 502 492 502 491 1497 493 1495 495 499 495 499 520 474 520 475 519 475 519 475 519 475 519 475 519 500 494 501 493 501 493 501 493 501 493 1498 491 1497 519 +# +name: Dh +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 665 17760 3083 8875 553 468 527 1432 584 438 555 439 529 464 555 439 555 438 556 438 555 439 553 1435 552 443 550 470 524 1466 523 471 522 473 521 1467 523 1466 549 1439 549 1440 549 1439 549 445 549 445 549 445 549 446 548 470 524 470 524 471 523 472 522 472 522 473 521 472 522 472 547 447 548 445 549 445 549 445 549 445 549 446 548 445 549 445 549 447 547 470 524 471 523 471 523 471 523 473 521 473 521 473 521 473 521 472 523 472 548 446 548 1441 547 1441 548 1441 547 1441 547 2947 3023 8935 522 1466 522 472 522 474 519 475 519 475 519 474 521 473 546 448 547 448 546 1465 523 449 545 448 546 1466 522 471 523 1467 522 1466 522 1493 495 1493 495 1493 496 1493 522 471 523 471 523 471 523 471 523 471 523 471 523 471 523 472 522 472 522 472 522 472 522 472 522 499 495 498 495 499 496 498 496 498 496 498 522 472 523 471 522 472 522 472 522 472 522 472 522 472 522 472 522 472 522 472 522 473 521 473 521 499 495 500 494 500 495 499 495 499 495 498 522 2947 3023 8937 520 1467 521 473 521 473 521 473 521 473 521 473 521 473 521 474 520 474 520 1495 494 500 494 500 495 500 494 1494 520 1468 521 1467 521 473 521 1468 521 1468 520 1469 519 1469 519 1471 517 1495 494 1495 494 1494 520 474 521 473 521 473 520 1468 521 1468 521 1468 520 474 520 475 519 475 519 500 493 500 494 501 493 501 493 501 493 1495 495 1494 520 474 520 474 520 474 520 475 519 1470 518 475 519 476 518 500 493 501 493 501 493 501 493 1497 492 1497 492 1496 493 1495 518 +# +name: Cool_hi +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 666 17765 3056 8901 529 492 526 1434 556 465 529 464 530 464 555 438 556 438 555 439 554 440 552 1436 551 443 550 470 524 1465 524 471 523 472 522 1467 521 1467 548 1441 549 1440 548 1440 548 445 549 445 549 445 549 446 548 447 547 470 524 471 523 471 523 473 521 472 522 473 521 473 521 473 522 472 548 446 549 446 548 446 548 447 547 447 547 470 524 447 547 471 523 471 523 471 523 471 523 471 523 475 519 498 496 498 496 498 496 497 498 497 523 1466 524 1443 545 1441 548 1442 546 2947 3023 8935 522 1466 522 472 522 472 522 498 496 498 496 498 496 498 496 498 522 472 523 1466 522 471 523 471 523 1466 523 471 523 1466 523 1467 522 1467 521 1493 496 1493 495 1493 497 497 522 472 523 471 523 471 523 472 522 472 522 472 522 472 522 472 522 472 522 472 522 472 522 473 521 499 495 499 495 499 495 499 496 498 496 498 522 472 522 472 523 472 521 472 522 472 522 472 522 472 522 473 521 473 521 473 521 473 521 474 520 500 494 500 494 500 495 500 495 499 521 2947 3024 8937 520 1467 521 473 521 473 521 473 521 473 521 473 521 473 521 474 520 474 520 1469 520 500 494 500 493 1496 494 1494 495 1494 520 1468 520 473 521 1469 519 1468 521 1469 519 1470 519 1470 519 1495 493 1496 493 1495 495 499 520 474 520 474 520 1469 520 1469 519 1469 519 474 520 475 519 500 494 500 494 500 494 502 492 502 492 502 493 501 493 1496 494 500 519 475 520 475 518 1470 519 475 518 476 518 475 519 476 494 525 493 501 493 501 493 1498 491 1498 491 1497 493 1496 518 +# +name: Cool_lo +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 664 17763 3082 8874 553 444 552 1433 583 438 529 464 530 464 555 439 555 438 556 438 555 440 553 1435 552 443 550 470 524 1466 523 472 521 472 522 1467 523 1466 549 1439 549 1439 549 1439 550 444 550 445 549 445 549 447 547 470 524 471 523 471 523 472 522 472 522 473 521 472 523 472 522 471 549 446 549 445 549 446 548 446 548 446 548 446 548 446 548 448 546 471 523 471 523 471 523 471 523 475 519 497 497 474 520 475 520 497 497 496 524 471 524 1465 523 1442 547 1442 547 1442 547 2946 3024 8935 522 1466 522 471 523 474 520 474 520 498 496 474 521 497 522 471 523 471 523 1465 523 471 523 471 523 1466 522 471 523 1466 523 1466 523 1493 495 1493 495 1493 496 1492 523 471 523 471 523 471 523 471 523 471 523 471 523 471 523 472 522 472 522 472 522 472 522 473 521 499 495 499 495 499 496 498 497 498 497 497 523 472 522 471 522 472 522 472 522 472 522 472 522 472 522 472 522 472 522 473 521 473 521 473 521 499 495 499 495 499 496 499 496 498 496 498 522 2946 3024 8937 521 1467 521 472 522 472 522 473 521 473 521 473 521 473 521 474 520 474 520 1495 493 500 494 499 495 499 495 499 496 1493 521 1468 520 473 521 1468 520 1468 521 1468 520 1469 519 1470 518 1495 494 1495 494 1494 495 499 520 473 521 473 521 1468 520 1469 520 1468 521 474 520 474 520 475 519 475 519 476 518 1496 492 1496 494 1495 495 499 520 1469 520 474 520 474 520 474 519 1470 520 474 520 476 518 476 519 477 517 500 494 500 494 503 491 1497 492 1496 493 1495 519 1470 519 +# +name: Heat_hi +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 666 17758 3056 8901 528 493 526 1434 580 441 554 439 529 465 554 439 555 439 555 439 554 440 553 1435 552 443 549 470 524 1465 524 472 522 472 521 1467 523 1467 548 1440 549 1440 548 1440 549 445 549 445 549 446 548 446 548 471 523 471 523 471 523 471 523 473 521 473 521 473 521 473 522 472 547 446 549 446 549 445 548 446 548 446 548 446 548 446 548 447 547 471 523 471 523 471 523 471 523 473 521 474 520 473 521 474 521 473 522 473 546 447 548 1441 548 1442 547 1442 547 1442 546 2948 3021 8936 521 1466 522 472 522 498 496 499 494 476 519 476 519 497 497 497 523 472 522 1466 523 471 523 472 522 1466 522 472 522 1466 522 1467 522 1467 522 1493 494 1495 495 1493 522 472 522 472 522 471 522 472 522 472 522 472 522 472 522 472 522 472 522 472 522 472 522 473 521 473 521 499 495 499 495 499 495 499 496 498 521 473 522 472 523 472 522 472 522 472 522 473 521 472 522 472 522 472 522 473 521 473 521 474 520 473 521 499 495 500 494 500 495 499 495 499 521 2947 3023 8938 520 1468 520 473 521 473 521 473 521 473 521 473 521 473 521 474 520 474 520 1495 494 500 494 500 494 500 495 500 494 1494 520 1468 521 474 520 1468 520 1469 520 1468 520 1469 520 1470 518 1496 493 1496 493 1495 495 499 519 475 520 474 520 1468 520 1469 519 1469 519 474 520 475 519 475 519 476 518 500 494 500 494 1497 492 1497 492 1496 493 1495 519 475 519 475 519 475 519 475 519 475 519 1471 518 476 518 500 494 501 493 501 493 501 493 1498 491 1498 491 1496 518 1472 517 +# +name: Heat_lo +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 664 17757 3057 8901 528 469 550 1434 556 465 553 440 529 465 554 439 555 439 555 438 555 440 553 1435 552 443 550 470 524 1466 522 472 522 472 521 1467 523 1466 549 1440 549 1440 548 1440 548 445 549 445 549 445 549 446 548 470 524 471 523 471 523 471 523 472 522 472 522 473 522 472 523 472 548 446 549 445 550 445 548 446 548 446 548 446 548 446 548 447 547 470 524 471 523 471 523 471 523 471 523 474 519 474 521 474 521 473 522 473 546 447 547 1441 548 1442 546 1442 547 1442 546 2947 3023 8935 522 1466 522 472 522 498 496 498 495 499 496 498 496 498 521 473 522 471 523 1466 522 471 523 471 522 1466 523 471 523 1467 522 1467 522 1467 521 1493 495 1494 496 1493 521 473 522 472 522 471 523 472 522 471 523 472 522 472 522 472 522 472 522 472 522 472 522 472 522 473 521 499 495 499 495 499 495 499 496 498 522 473 522 472 523 471 522 472 522 472 522 472 522 472 522 472 522 472 522 473 521 473 521 473 521 473 521 499 495 500 494 500 495 499 496 498 522 2947 3023 8937 521 1468 520 473 521 473 521 473 521 473 521 473 521 473 521 474 520 474 520 1470 518 500 494 500 494 500 494 500 494 1494 521 1468 521 473 521 1468 520 1468 520 1469 520 1469 520 1470 518 1495 493 1496 493 1495 494 500 519 475 520 474 520 1469 519 1469 520 1469 519 474 520 474 520 475 519 477 517 500 494 1496 493 1496 493 1496 493 500 495 1495 519 475 518 475 519 475 518 476 518 475 519 1470 519 500 494 500 494 501 493 501 493 501 493 1499 490 1497 493 1497 492 1496 518 From 895694c624aac9b63392841e915965a10b5592b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Thu, 28 Dec 2023 19:15:07 +0900 Subject: [PATCH 34/35] Scripts: fix incorrect handling of storage stress test count option (#3321) --- scripts/storage.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/storage.py b/scripts/storage.py index e04eaa7e1..9df2f6c39 100755 --- a/scripts/storage.py +++ b/scripts/storage.py @@ -74,7 +74,7 @@ class Main(App): self.parser_list.set_defaults(func=self.list) self.parser_stress = self.subparsers.add_parser("stress", help="Stress test") - self.parser.add_argument( + self.parser_stress.add_argument( "-c", "--count", type=int, default=10, help="Iteration count" ) self.parser_stress.add_argument("flipper_path", help="Flipper path") From a7b60bf2a610e1a364d26a925f3713c08d16d49c Mon Sep 17 00:00:00 2001 From: gornekich Date: Fri, 29 Dec 2023 07:24:20 +0400 Subject: [PATCH 35/35] MFC emulation fixes (#3324) * mf classic listener: fix write block * nfc: go to idle state instead of sleep * lib nfc: fix documentation --- lib/nfc/nfc.c | 2 +- lib/nfc/protocols/felica/felica_poller.h | 4 ++-- lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.h | 4 ++-- lib/nfc/protocols/iso14443_3b/iso14443_3b_poller.h | 4 ++-- lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.h | 4 ++-- lib/nfc/protocols/iso14443_4b/iso14443_4b_poller.h | 4 ++-- lib/nfc/protocols/iso15693_3/iso15693_3_poller.h | 4 ++-- lib/nfc/protocols/mf_classic/mf_classic_listener.c | 6 +++++- lib/nfc/protocols/mf_classic/mf_classic_listener_i.h | 3 +++ 9 files changed, 21 insertions(+), 14 deletions(-) diff --git a/lib/nfc/nfc.c b/lib/nfc/nfc.c index 6475cce43..22a21c9d2 100644 --- a/lib/nfc/nfc.c +++ b/lib/nfc/nfc.c @@ -150,7 +150,7 @@ static int32_t nfc_worker_listener(void* context) { } else if(command == NfcCommandReset) { furi_hal_nfc_listener_enable_rx(); } else if(command == NfcCommandSleep) { - furi_hal_nfc_listener_sleep(); + furi_hal_nfc_listener_idle(); } } } diff --git a/lib/nfc/protocols/felica/felica_poller.h b/lib/nfc/protocols/felica/felica_poller.h index 45fd9a9a1..b0e6778a0 100644 --- a/lib/nfc/protocols/felica/felica_poller.h +++ b/lib/nfc/protocols/felica/felica_poller.h @@ -18,8 +18,8 @@ typedef struct FelicaPoller FelicaPoller; * @brief Enumeration of possible Felica poller event types. */ typedef enum { - FelicaPollerEventTypeError, /**< The card was activated by the poller. */ - FelicaPollerEventTypeReady, /**< An error occured during activation procedure. */ + FelicaPollerEventTypeError, /**< An error occured during activation procedure. */ + FelicaPollerEventTypeReady, /**< The card was activated by the poller. */ } FelicaPollerEventType; /** diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.h b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.h index 42e4b4bf5..c6649152f 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.h +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.h @@ -18,8 +18,8 @@ typedef struct Iso14443_3aPoller Iso14443_3aPoller; * @brief Enumeration of possible Iso14443_3a poller event types. */ typedef enum { - Iso14443_3aPollerEventTypeError, /**< The card was activated by the poller. */ - Iso14443_3aPollerEventTypeReady, /**< An error occured during activation procedure. */ + Iso14443_3aPollerEventTypeError, /**< An error occured during activation procedure. */ + Iso14443_3aPollerEventTypeReady, /**< The card was activated by the poller. */ } Iso14443_3aPollerEventType; /** diff --git a/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller.h b/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller.h index 940903c1d..cdf8ddf68 100644 --- a/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller.h +++ b/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller.h @@ -18,8 +18,8 @@ typedef struct Iso14443_3bPoller Iso14443_3bPoller; * @brief Enumeration of possible Iso14443_3b poller event types. */ typedef enum { - Iso14443_3bPollerEventTypeError, /**< The card was activated by the poller. */ - Iso14443_3bPollerEventTypeReady, /**< An error occured during activation procedure. */ + Iso14443_3bPollerEventTypeError, /**< An error occured during activation procedure. */ + Iso14443_3bPollerEventTypeReady, /**< The card was activated by the poller. */ } Iso14443_3bPollerEventType; /** diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.h b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.h index 73eb6ef74..fef565e51 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.h +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.h @@ -17,8 +17,8 @@ typedef struct Iso14443_4aPoller Iso14443_4aPoller; * @brief Enumeration of possible Iso14443_4a poller event types. */ typedef enum { - Iso14443_4aPollerEventTypeError, /**< The card was activated by the poller. */ - Iso14443_4aPollerEventTypeReady, /**< An error occured during activation procedure. */ + Iso14443_4aPollerEventTypeError, /**< An error occured during activation procedure. */ + Iso14443_4aPollerEventTypeReady, /**< The card was activated by the poller. */ } Iso14443_4aPollerEventType; /** diff --git a/lib/nfc/protocols/iso14443_4b/iso14443_4b_poller.h b/lib/nfc/protocols/iso14443_4b/iso14443_4b_poller.h index 03b288c07..faccf2f3c 100644 --- a/lib/nfc/protocols/iso14443_4b/iso14443_4b_poller.h +++ b/lib/nfc/protocols/iso14443_4b/iso14443_4b_poller.h @@ -17,8 +17,8 @@ typedef struct Iso14443_4bPoller Iso14443_4bPoller; * @brief Enumeration of possible Iso14443_4b poller event types. */ typedef enum { - Iso14443_4bPollerEventTypeError, /**< The card was activated by the poller. */ - Iso14443_4bPollerEventTypeReady, /**< An error occured during activation procedure. */ + Iso14443_4bPollerEventTypeError, /**< An error occured during activation procedure. */ + Iso14443_4bPollerEventTypeReady, /**< The card was activated by the poller. */ } Iso14443_4bPollerEventType; /** diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3_poller.h b/lib/nfc/protocols/iso15693_3/iso15693_3_poller.h index a187ceace..efe8337af 100644 --- a/lib/nfc/protocols/iso15693_3/iso15693_3_poller.h +++ b/lib/nfc/protocols/iso15693_3/iso15693_3_poller.h @@ -17,8 +17,8 @@ typedef struct Iso15693_3Poller Iso15693_3Poller; * @brief Enumeration of possible Iso15693_3 poller event types. */ typedef enum { - Iso15693_3PollerEventTypeError, /**< The card was activated by the poller. */ - Iso15693_3PollerEventTypeReady, /**< An error occured during activation procedure. */ + Iso15693_3PollerEventTypeError, /**< An error occured during activation procedure. */ + Iso15693_3PollerEventTypeReady, /**< The card was activated by the poller. */ } Iso15693_3PollerEventType; /** diff --git a/lib/nfc/protocols/mf_classic/mf_classic_listener.c b/lib/nfc/protocols/mf_classic/mf_classic_listener.c index bd25aba23..9f6f1f85c 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_listener.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_listener.c @@ -33,6 +33,7 @@ static void mf_classic_listener_reset_state(MfClassicListener* instance) { instance->state = MfClassicListenerStateIdle; instance->cmd_in_progress = false; instance->current_cmd_handler_idx = 0; + instance->write_block = 0; instance->transfer_value = 0; instance->transfer_valid = false; instance->value_cmd = MfClassicValueCommandInvalid; @@ -240,11 +241,13 @@ static MfClassicListenerCommand mf_classic_listener_write_block_first_part_handl uint8_t block_num = bit_buffer_get_byte(buff, 1); if(block_num >= instance->total_block_num) break; + if(block_num == 0) break; uint8_t sector_num = mf_classic_get_sector_by_block(block_num); uint8_t auth_sector_num = mf_classic_get_sector_by_block(auth_ctx->block_num); if(sector_num != auth_sector_num) break; + instance->write_block = block_num; instance->cmd_in_progress = true; instance->current_cmd_handler_idx++; command = MfClassicListenerCommandAck; @@ -265,7 +268,7 @@ static MfClassicListenerCommand mf_classic_listener_write_block_second_part_hand size_t buff_size = bit_buffer_get_size_bytes(buff); if(buff_size != sizeof(MfClassicBlock)) break; - uint8_t block_num = auth_ctx->block_num; + uint8_t block_num = instance->write_block; MfClassicKeyType key_type = auth_ctx->key_type; MfClassicBlock block = instance->data->block[block_num]; @@ -609,6 +612,7 @@ NfcCommand mf_classic_listener_run(NfcGenericEvent event, void* context) { mf_classic_listener_send_short_frame(instance, nack); mf_classic_listener_reset_state(instance); + command = NfcCommandSleep; } else if(mfc_command == MfClassicListenerCommandSilent) { command = NfcCommandReset; } else if(mfc_command == MfClassicListenerCommandSleep) { diff --git a/lib/nfc/protocols/mf_classic/mf_classic_listener_i.h b/lib/nfc/protocols/mf_classic/mf_classic_listener_i.h index 52273be9c..5269743b5 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_listener_i.h +++ b/lib/nfc/protocols/mf_classic/mf_classic_listener_i.h @@ -40,6 +40,9 @@ struct MfClassicListener { Crypto1* crypto; MfClassicAuthContext auth_context; + // Write block context + uint8_t write_block; + // Value operation data int32_t transfer_value; bool transfer_valid;