From 238187730c56b1dc59fd653d7984997e69508278 Mon Sep 17 00:00:00 2001 From: ushastoe Date: Mon, 18 Dec 2023 11:41:54 +0300 Subject: [PATCH 01/11] [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 02/11] 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 03/11] 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 04/11] 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 05/11] 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 06/11] 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 07/11] 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 08/11] 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 09/11] 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 10/11] 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 11/11] 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");