diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 308aa942884..db09f7541c8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -76,8 +76,8 @@ jobs: with: run: | set -e - make -C assets clean - make -C assets + make assets_rebuild assets_manifest + git diff --quiet || ( echo "Assets recompilation required."; exit 255 ) - name: 'Build the firmware in docker' uses: ./.github/actions/docker @@ -117,7 +117,6 @@ jobs: - name: 'Bundle resources' if: ${{ !github.event.pull_request.head.repo.fork }} run: | - ./scripts/assets.py manifest assets/resources tar czpf artifacts/flipper-z-any-resources-${{steps.names.outputs.suffix}}.tgz -C assets resources - name: 'Bundle core2 firmware' diff --git a/Makefile b/Makefile index 02008033dc3..ca3caa22d82 100644 --- a/Makefile +++ b/Makefile @@ -51,6 +51,10 @@ flash: firmware_flash debug: @$(MAKE) -C firmware -j$(NPROCS) debug +.PHONY: debug_other +debug_other: + @$(MAKE) -C firmware -j$(NPROCS) debug_other + .PHONY: blackmagic blackmagic: @$(MAKE) -C firmware -j$(NPROCS) blackmagic @@ -75,7 +79,6 @@ ifeq ($(FORCE), 1) endif @$(MAKE) -C $(PROJECT_ROOT)/firmware -j$(NPROCS) flash - .PHONY: updater updater: @$(MAKE) -C $(PROJECT_ROOT)/firmware -j$(NPROCS) RAM_EXEC=1 all @@ -88,10 +91,22 @@ updater_clean: updater_debug: @$(MAKE) -C $(PROJECT_ROOT)/firmware -j$(NPROCS) RAM_EXEC=1 debug -.PHONY: updater_package -updater_package: firmware_all updater +.PHONY: updater_package_bin +updater_package_bin: firmware_all updater @$(PROJECT_ROOT)/scripts/dist.py copy -t $(TARGET) -p firmware updater -s $(DIST_SUFFIX) --bundlever "$(VERSION_STRING)" +.PHONY: updater_package +updater_package: firmware_all updater assets_manifest + @$(PROJECT_ROOT)/scripts/dist.py copy -t $(TARGET) -p firmware updater -s $(DIST_SUFFIX) -r $(PROJECT_ROOT)/assets/resources --bundlever "$(VERSION_STRING)" + +.PHONY: assets_manifest +assets_manifest: + @$(MAKE) -C $(PROJECT_ROOT)/assets manifest + +.PHONY: assets_rebuild +assets_rebuild: + @$(MAKE) -C $(PROJECT_ROOT)/assets clean all + .PHONY: flash_radio flash_radio: @$(PROJECT_ROOT)/scripts/flash.py core2radio 0x080D7000 $(COPRO_DIR)/stm32wb5x_BLE_Stack_light_fw.bin @@ -110,8 +125,8 @@ flash_radio_fus: .PHONY: flash_radio_fus_please_i_m_not_going_to_complain flash_radio_fus_please_i_m_not_going_to_complain: - @$(PROJECT_ROOT)/scripts/flash.py core2fus 0x080EC000 --statement=AGREE_TO_LOOSE_FLIPPER_FEATURES_THAT_USES_CRYPTO_ENCLAVE $(COPRO_DIR)/stm32wb5x_FUS_fw_for_fus_0_5_3.bin - @$(PROJECT_ROOT)/scripts/flash.py core2fus 0x080EC000 --statement=AGREE_TO_LOOSE_FLIPPER_FEATURES_THAT_USES_CRYPTO_ENCLAVE $(COPRO_DIR)/stm32wb5x_FUS_fw.bin + @$(PROJECT_ROOT)/scripts/flash.py core2fus 0x080EC000 --statement=AGREE_TO_LOSE_FLIPPER_FEATURES_THAT_USE_CRYPTO_ENCLAVE $(COPRO_DIR)/stm32wb5x_FUS_fw_for_fus_0_5_3.bin + @$(PROJECT_ROOT)/scripts/flash.py core2fus 0x080EC000 --statement=AGREE_TO_LOSE_FLIPPER_FEATURES_THAT_USE_CRYPTO_ENCLAVE $(COPRO_DIR)/stm32wb5x_FUS_fw.bin @$(PROJECT_ROOT)/scripts/ob.py set .PHONY: lint diff --git a/applications/applications.c b/applications/applications.c index aba50fee7ef..6b4c6321154 100644 --- a/applications/applications.c +++ b/applications/applications.c @@ -43,6 +43,7 @@ extern int32_t usb_test_app(void* p); extern int32_t vibro_test_app(void* p); extern int32_t bt_hid_app(void* p); extern int32_t battery_test_app(void* p); +extern int32_t text_box_test_app(void* p); // Plugins extern int32_t music_player_app(void* p); @@ -304,6 +305,10 @@ const FlipperApplication FLIPPER_DEBUG_APPS[] = { #ifdef APP_BATTERY_TEST {.app = battery_test_app, .name = "Battery Test", .stack_size = 1024, .icon = NULL}, #endif + +#ifdef APP_TEXT_BOX_TEST + {.app = text_box_test_app, .name = "Text Box Test", .stack_size = 1024, .icon = NULL}, +#endif }; const size_t FLIPPER_DEBUG_APPS_COUNT = COUNT_OF(FLIPPER_DEBUG_APPS); diff --git a/applications/applications.mk b/applications/applications.mk index c6295fd8035..efe6aa425e8 100644 --- a/applications/applications.mk +++ b/applications/applications.mk @@ -165,6 +165,12 @@ CFLAGS += -DAPP_DISPLAY_TEST SRV_GUI = 1 endif +APP_TEXT_BOX_TEST ?= 0 +ifeq ($(APP_TEXT_BOX_TEST), 1) +CFLAGS += -DAPP_TEXT_BOX_TEST +SRV_GUI = 1 +endif + APP_BATTERY_TEST ?= 0 ifeq ($(APP_BATTERY_TEST), 1) CFLAGS += -DAPP_BATTERY_TEST diff --git a/applications/archive/helpers/archive_browser.c b/applications/archive/helpers/archive_browser.c index 10f5ea3e294..6a6ad947739 100644 --- a/applications/archive/helpers/archive_browser.c +++ b/applications/archive/helpers/archive_browser.c @@ -391,14 +391,7 @@ void archive_enter_dir(ArchiveBrowserView* browser, string_t name) { furi_assert(browser); furi_assert(name); - uint8_t browser_depth = 0; - with_view_model( - browser->view, (ArchiveBrowserViewModel * model) { - browser_depth = idx_last_array_size(model->idx_last); - return false; - }); - - if(browser_depth > BROWSER_DEPTH_MAX) { + if(string_size(name) >= (MAX_NAME_LEN - 1)) { return; } diff --git a/applications/archive/helpers/archive_browser.h b/applications/archive/helpers/archive_browser.h index e74357f8d4b..593a9be0db7 100644 --- a/applications/archive/helpers/archive_browser.h +++ b/applications/archive/helpers/archive_browser.h @@ -4,7 +4,6 @@ #define TAB_RIGHT InputKeyRight //default tab swith direction #define FILE_LIST_BUF_LEN 100 -#define BROWSER_DEPTH_MAX 8 static const char* tab_default_paths[] = { [ArchiveTabFavorites] = "/any/favorites", diff --git a/applications/archive/scenes/archive_scene_delete.c b/applications/archive/scenes/archive_scene_delete.c index 04b375107f8..fbcba77733a 100644 --- a/applications/archive/scenes/archive_scene_delete.c +++ b/applications/archive/scenes/archive_scene_delete.c @@ -20,7 +20,7 @@ void archive_scene_delete_on_enter(void* context) { ArchiveApp* app = (ArchiveApp*)context; widget_add_button_element( - app->widget, GuiButtonTypeLeft, "Back", archive_scene_delete_widget_callback, app); + app->widget, GuiButtonTypeLeft, "Cancel", archive_scene_delete_widget_callback, app); widget_add_button_element( app->widget, GuiButtonTypeRight, "Delete", archive_scene_delete_widget_callback, app); @@ -33,7 +33,8 @@ void archive_scene_delete_on_enter(void* context) { char delete_str[64]; snprintf(delete_str, sizeof(delete_str), "\e#Delete %s?\e#", name); - widget_add_text_box_element(app->widget, 0, 0, 128, 23, AlignCenter, AlignCenter, delete_str); + widget_add_text_box_element( + app->widget, 0, 0, 128, 23, AlignCenter, AlignCenter, delete_str, false); view_dispatcher_switch_to_view(app->view_dispatcher, ArchiveViewWidget); } diff --git a/applications/bt/bt_cli.c b/applications/bt/bt_cli.c index 2469e74ebfe..4c68e5976c6 100644 --- a/applications/bt/bt_cli.c +++ b/applications/bt/bt_cli.c @@ -189,6 +189,8 @@ static void bt_cli_print_usage() { } static void bt_cli(Cli* cli, string_t args, void* context) { + furi_record_open("bt"); + string_t cmd; string_init(cmd); BtSettings bt_settings; @@ -235,16 +237,15 @@ static void bt_cli(Cli* cli, string_t args, void* context) { } string_clear(cmd); + furi_record_close("bt"); } void bt_on_system_start() { #ifdef SRV_CLI Cli* cli = furi_record_open("cli"); - furi_record_open("bt"); cli_add_command(cli, "bt", CliCommandFlagDefault, bt_cli, NULL); - furi_record_close("bt"); furi_record_close("cli"); #else UNUSED(bt_cli); #endif -} \ No newline at end of file +} diff --git a/applications/bt/bt_service/bt.c b/applications/bt/bt_service/bt.c index 720f4854143..8ce7f9ce0e3 100755 --- a/applications/bt/bt_service/bt.c +++ b/applications/bt/bt_service/bt.c @@ -320,7 +320,7 @@ int32_t bt_srv() { Bt* bt = bt_alloc(); // Read keys - if(!bt_load_key_storage(bt)) { + if(!bt_keys_storage_load(bt)) { FURI_LOG_W(TAG, "Failed to load bonding keys"); } @@ -365,11 +365,11 @@ int32_t bt_srv() { // Display PIN code bt_pin_code_show(bt, message.data.pin_code); } else if(message.type == BtMessageTypeKeysStorageUpdated) { - bt_save_key_storage(bt); + bt_keys_storage_save(bt); } else if(message.type == BtMessageTypeSetProfile) { bt_change_profile(bt, &message); } else if(message.type == BtMessageTypeForgetBondedDevices) { - bt_delete_key_storage(bt); + bt_keys_storage_delete(bt); } } return 0; diff --git a/applications/bt/bt_service/bt_keys_storage.c b/applications/bt/bt_service/bt_keys_storage.c index 74df10209a3..e4f426c8c0a 100644 --- a/applications/bt/bt_service/bt_keys_storage.c +++ b/applications/bt/bt_service/bt_keys_storage.c @@ -1,46 +1,47 @@ #include "bt_keys_storage.h" + #include -#include +#include -#define BT_KEYS_STORAGE_TAG "bt keys storage" #define BT_KEYS_STORAGE_PATH "/int/bt.keys" +#define BT_KEYS_STORAGE_VERSION (0) +#define BT_KEYS_STORAGE_MAGIC (0x18) -bool bt_load_key_storage(Bt* bt) { +bool bt_keys_storage_load(Bt* bt) { furi_assert(bt); - bool file_loaded = false; + furi_hal_bt_get_key_storage_buff(&bt->bt_keys_addr_start, &bt->bt_keys_size); + furi_hal_bt_nvm_sram_sem_acquire(); + file_loaded = saved_struct_load( + BT_KEYS_STORAGE_PATH, + bt->bt_keys_addr_start, + bt->bt_keys_size, + BT_KEYS_STORAGE_MAGIC, + BT_KEYS_STORAGE_VERSION); + furi_hal_bt_nvm_sram_sem_release(); - FileWorker* file_worker = file_worker_alloc(true); - if(file_worker_open(file_worker, BT_KEYS_STORAGE_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) { - furi_hal_bt_nvm_sram_sem_acquire(); - if(file_worker_read(file_worker, bt->bt_keys_addr_start, bt->bt_keys_size)) { - file_loaded = true; - } - furi_hal_bt_nvm_sram_sem_release(); - } - file_worker_free(file_worker); return file_loaded; } -bool bt_save_key_storage(Bt* bt) { +bool bt_keys_storage_save(Bt* bt) { furi_assert(bt); furi_assert(bt->bt_keys_addr_start); - bool file_saved = false; - FileWorker* file_worker = file_worker_alloc(true); - if(file_worker_open(file_worker, BT_KEYS_STORAGE_PATH, FSAM_WRITE, FSOM_OPEN_ALWAYS)) { - furi_hal_bt_nvm_sram_sem_acquire(); - if(file_worker_write(file_worker, bt->bt_keys_addr_start, bt->bt_keys_size)) { - file_saved = true; - } - furi_hal_bt_nvm_sram_sem_release(); - } - file_worker_free(file_worker); + + furi_hal_bt_nvm_sram_sem_acquire(); + file_saved = saved_struct_save( + BT_KEYS_STORAGE_PATH, + bt->bt_keys_addr_start, + bt->bt_keys_size, + BT_KEYS_STORAGE_MAGIC, + BT_KEYS_STORAGE_VERSION); + furi_hal_bt_nvm_sram_sem_release(); + return file_saved; } -bool bt_delete_key_storage(Bt* bt) { +bool bt_keys_storage_delete(Bt* bt) { furi_assert(bt); bool delete_succeed = false; bool bt_is_active = furi_hal_bt_is_active(); diff --git a/applications/bt/bt_service/bt_keys_storage.h b/applications/bt/bt_service/bt_keys_storage.h index e763e6a7861..68d4476aa20 100644 --- a/applications/bt/bt_service/bt_keys_storage.h +++ b/applications/bt/bt_service/bt_keys_storage.h @@ -2,8 +2,8 @@ #include "bt_i.h" -bool bt_load_key_storage(Bt* bt); +bool bt_keys_storage_load(Bt* bt); -bool bt_save_key_storage(Bt* bt); +bool bt_keys_storage_save(Bt* bt); -bool bt_delete_key_storage(Bt* bt); +bool bt_keys_storage_delete(Bt* bt); diff --git a/applications/bt/bt_settings.c b/applications/bt/bt_settings.c index 7b52321c3f5..dbb2fd05db9 100644 --- a/applications/bt/bt_settings.c +++ b/applications/bt/bt_settings.c @@ -1,50 +1,22 @@ #include "bt_settings.h" + #include -#include +#include -#define TAG "BtSettings" #define BT_SETTINGS_PATH "/int/bt.settings" +#define BT_SETTINGS_VERSION (0) +#define BT_SETTINGS_MAGIC (0x19) bool bt_settings_load(BtSettings* bt_settings) { furi_assert(bt_settings); - bool file_loaded = false; - BtSettings settings = {}; - - FURI_LOG_I(TAG, "Loading settings from \"%s\"", BT_SETTINGS_PATH); - FileWorker* file_worker = file_worker_alloc(true); - if(file_worker_open(file_worker, BT_SETTINGS_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) { - if(file_worker_read(file_worker, &settings, sizeof(settings))) { - file_loaded = true; - } - } - file_worker_free(file_worker); - if(file_loaded) { - FURI_LOG_I(TAG, "Settings load success"); - if(settings.version != BT_SETTINGS_VERSION) { - FURI_LOG_E(TAG, "Settings version mismatch"); - } else { - osKernelLock(); - *bt_settings = settings; - osKernelUnlock(); - } - } else { - FURI_LOG_E(TAG, "Settings load failed"); - } - return file_loaded; + return saved_struct_load( + BT_SETTINGS_PATH, bt_settings, sizeof(BtSettings), BT_SETTINGS_MAGIC, BT_SETTINGS_VERSION); } bool bt_settings_save(BtSettings* bt_settings) { furi_assert(bt_settings); - bool result = false; - FileWorker* file_worker = file_worker_alloc(true); - if(file_worker_open(file_worker, BT_SETTINGS_PATH, FSAM_WRITE, FSOM_OPEN_ALWAYS)) { - if(file_worker_write(file_worker, bt_settings, sizeof(BtSettings))) { - FURI_LOG_I(TAG, "Settings saved to \"%s\"", BT_SETTINGS_PATH); - result = true; - } - } - file_worker_free(file_worker); - return result; + return saved_struct_save( + BT_SETTINGS_PATH, bt_settings, sizeof(BtSettings), BT_SETTINGS_MAGIC, BT_SETTINGS_VERSION); } diff --git a/applications/bt/bt_settings.h b/applications/bt/bt_settings.h index d0a539ea306..1a98668acd6 100644 --- a/applications/bt/bt_settings.h +++ b/applications/bt/bt_settings.h @@ -3,10 +3,7 @@ #include #include -#define BT_SETTINGS_VERSION (0) - typedef struct { - uint8_t version; bool enabled; } BtSettings; diff --git a/applications/debug_tools/text_box_test.c b/applications/debug_tools/text_box_test.c new file mode 100644 index 00000000000..1c7ce18b106 --- /dev/null +++ b/applications/debug_tools/text_box_test.c @@ -0,0 +1,126 @@ +#include +#include +#include +#include + +#define TAG "TextBoxTest" + +static void text_box_center_top_secondary_128x22(Canvas* canvas) { + canvas_draw_frame(canvas, 0, 0, 128, 22); + elements_text_box(canvas, 0, 0, 128, 22, AlignCenter, AlignTop, "secondary font test", false); +} + +static void text_box_right_bottom_bold_128x22(Canvas* canvas) { + canvas_draw_frame(canvas, 0, 0, 128, 22); + elements_text_box( + canvas, 0, 0, 128, 22, AlignRight, AlignBottom, "\e#Bold font test\e#", false); +} + +static void text_box_left_center_mixed_80x50(Canvas* canvas) { + canvas_draw_frame(canvas, 0, 0, 80, 50); + elements_text_box( + canvas, + 0, + 0, + 80, + 50, + AlignLeft, + AlignCenter, + "\e#Never\e# gonna give you up\n\e!Never\e! gonna let you down", + false); +} + +static void text_box_center_center_secondary_110x44(Canvas* canvas) { + canvas_draw_frame(canvas, 4, 20, 110, 30); + elements_text_box( + canvas, + 4, + 20, + 110, + 30, + AlignCenter, + AlignCenter, + "Loooooooooooooo0000000ooong file name from happy 100500 Flipper 0wners", + true); +} + +static void (*text_box_test_render[])(Canvas* canvas) = { + text_box_center_top_secondary_128x22, + text_box_right_bottom_bold_128x22, + text_box_left_center_mixed_80x50, + text_box_center_center_secondary_110x44, +}; + +typedef struct { + uint32_t idx; +} TextBoxTestState; + +static void text_box_test_render_callback(Canvas* canvas, void* ctx) { + TextBoxTestState* state = acquire_mutex((ValueMutex*)ctx, 25); + canvas_clear(canvas); + + text_box_test_render[state->idx](canvas); + + release_mutex((ValueMutex*)ctx, state); +} + +static void text_box_test_input_callback(InputEvent* input_event, void* ctx) { + osMessageQueueId_t event_queue = ctx; + osMessageQueuePut(event_queue, input_event, 0, osWaitForever); +} + +int32_t text_box_test_app(void* p) { + osMessageQueueId_t event_queue = osMessageQueueNew(32, sizeof(InputEvent), NULL); + furi_check(event_queue); + + TextBoxTestState _state = {.idx = 0}; + + ValueMutex state_mutex; + if(!init_mutex(&state_mutex, &_state, sizeof(TextBoxTestState))) { + FURI_LOG_E(TAG, "Cannot create mutex"); + return 0; + } + + ViewPort* view_port = view_port_alloc(); + + view_port_draw_callback_set(view_port, text_box_test_render_callback, &state_mutex); + view_port_input_callback_set(view_port, text_box_test_input_callback, event_queue); + + // Open GUI and register view_port + Gui* gui = furi_record_open("gui"); + gui_add_view_port(gui, view_port, GuiLayerFullscreen); + + uint32_t test_renders_num = SIZEOF_ARRAY(text_box_test_render); + InputEvent event; + while(osMessageQueueGet(event_queue, &event, NULL, osWaitForever) == osOK) { + TextBoxTestState* state = acquire_mutex_block(&state_mutex); + + if(event.type == InputTypeShort) { + if(event.key == InputKeyRight) { + if(state->idx < test_renders_num - 1) { + state->idx++; + } + } else if(event.key == InputKeyLeft) { + if(state->idx > 0) { + state->idx--; + } + } else if(event.key == InputKeyBack) { + release_mutex(&state_mutex, state); + break; + } + } + + release_mutex(&state_mutex, state); + view_port_update(view_port); + } + + // remove & free all stuff created by app + gui_remove_view_port(gui, view_port); + view_port_free(view_port); + osMessageQueueDelete(event_queue); + delete_mutex(&state_mutex); + + furi_record_close("gui"); + + return 0; +} diff --git a/applications/desktop/animations/animation_manager.c b/applications/desktop/animations/animation_manager.c index 4c99724ef69..ea241ec3397 100644 --- a/applications/desktop/animations/animation_manager.c +++ b/applications/desktop/animations/animation_manager.c @@ -161,8 +161,9 @@ void animation_manager_new_idle_process(AnimationManager* animation_manager) { } /* reaction to animation_manager->interact_callback() */ -void animation_manager_interact_process(AnimationManager* animation_manager) { +bool animation_manager_interact_process(AnimationManager* animation_manager) { furi_assert(animation_manager); + bool consumed = true; if(animation_manager->levelup_pending) { animation_manager->levelup_pending = false; @@ -181,7 +182,11 @@ void animation_manager_interact_process(AnimationManager* animation_manager) { if(!blocked) { animation_manager_start_new_idle(animation_manager); } + } else { + consumed = false; } + + return consumed; } static void animation_manager_start_new_idle(AnimationManager* animation_manager) { diff --git a/applications/desktop/animations/animation_manager.h b/applications/desktop/animations/animation_manager.h index 13160c6f2ce..9802c4f1f62 100644 --- a/applications/desktop/animations/animation_manager.h +++ b/applications/desktop/animations/animation_manager.h @@ -130,8 +130,9 @@ void animation_manager_set_interact_callback( * set_new_idle_callback's call. * * @animation_manager instance + * @return true if event was consumed */ -void animation_manager_interact_process(AnimationManager* animation_manager); +bool animation_manager_interact_process(AnimationManager* animation_manager); /** Check if animation loaded * diff --git a/applications/desktop/desktop.c b/applications/desktop/desktop.c index d6c220831a4..1c1ce04f7d8 100644 --- a/applications/desktop/desktop.c +++ b/applications/desktop/desktop.c @@ -117,6 +117,7 @@ static void desktop_auto_lock_inhibit(Desktop* desktop) { } void desktop_lock(Desktop* desktop) { + furi_hal_rtc_set_pin_fails(0); desktop_auto_lock_inhibit(desktop); scene_manager_set_scene_state( desktop->scene_manager, DesktopSceneLocked, SCENE_LOCKED_FIRST_ENTER); diff --git a/applications/desktop/scenes/desktop_scene_main.c b/applications/desktop/scenes/desktop_scene_main.c index 719ba2e4639..f3867adc89b 100644 --- a/applications/desktop/scenes/desktop_scene_main.c +++ b/applications/desktop/scenes/desktop_scene_main.c @@ -116,7 +116,6 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) { } consumed = true; break; - case DesktopAnimationEventCheckAnimation: animation_manager_check_blocking_process(desktop->animation_manager); consumed = true; @@ -126,7 +125,12 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) { consumed = true; break; case DesktopAnimationEventInteractAnimation: - animation_manager_interact_process(desktop->animation_manager); + if(!animation_manager_interact_process(desktop->animation_manager)) { + LoaderStatus status = loader_start(desktop->loader, "Passport", NULL); + if(status != LoaderStatusOk) { + FURI_LOG_E(TAG, "loader_start failed: %d", status); + } + } consumed = true; break; case DesktopLockedEventUpdate: diff --git a/applications/desktop/views/desktop_events.h b/applications/desktop/views/desktop_events.h index f38a5417066..94d2cc9857c 100644 --- a/applications/desktop/views/desktop_events.h +++ b/applications/desktop/views/desktop_events.h @@ -6,7 +6,7 @@ typedef enum { DesktopMainEventOpenFavorite, DesktopMainEventOpenMenu, DesktopMainEventOpenDebug, - DesktopMainEventRightShort, + DesktopMainEventOpenPassport, /**< Broken, don't use it */ DesktopLockedEventUnlocked, DesktopLockedEventUpdate, diff --git a/applications/desktop/views/desktop_view_main.c b/applications/desktop/views/desktop_view_main.c index 091b0855a35..b912d3ea54a 100644 --- a/applications/desktop/views/desktop_view_main.c +++ b/applications/desktop/views/desktop_view_main.c @@ -46,7 +46,7 @@ bool desktop_main_input(InputEvent* event, void* context) { } else if(event->key == InputKeyLeft) { main_view->callback(DesktopMainEventOpenFavorite, main_view->context); } else if(event->key == InputKeyRight) { - main_view->callback(DesktopMainEventRightShort, main_view->context); + main_view->callback(DesktopMainEventOpenPassport, main_view->context); } } else if(event->type == InputTypeLong) { if(event->key == InputKeyDown) { diff --git a/applications/gui/elements.c b/applications/gui/elements.c index 289e4d8e05c..58b446038d2 100644 --- a/applications/gui/elements.c +++ b/applications/gui/elements.c @@ -197,7 +197,11 @@ static size_t uint16_t len_px = canvas_string_width(canvas, string_get_cstr(str)); uint8_t px_left = 0; if(horizontal == AlignCenter) { - px_left = canvas_width(canvas) - (x - len_px / 2); + if(x > (canvas_width(canvas) / 2)) { + px_left = (canvas_width(canvas) - x) * 2; + } else { + px_left = x * 2; + } } else if(horizontal == AlignLeft) { px_left = canvas_width(canvas) - x; } else if(horizontal == AlignRight) { @@ -208,13 +212,13 @@ static size_t if(len_px > px_left) { uint8_t excess_symbols_approximately = - ((float)len_px - px_left) / ((float)len_px / text_size); + roundf((float)(len_px - px_left) / ((float)len_px / (float)text_size)); // reduce to 5 to be sure dash fit, and next line will be at least 5 symbols long - excess_symbols_approximately = MAX(excess_symbols_approximately, 5); - if(text_size > (excess_symbols_approximately + 5)) { - result = text_size - excess_symbols_approximately - 5; + if(excess_symbols_approximately > 0) { + excess_symbols_approximately = MAX(excess_symbols_approximately, 5); + result = text_size - excess_symbols_approximately - 1; } else { - result = text_size - 1; + result = text_size; } } else { result = text_size; @@ -258,12 +262,17 @@ void elements_multiline_text_aligned( if((start[chars_fit] == '\n') || (start[chars_fit] == 0)) { string_init_printf(line, "%.*s", chars_fit, start); + } else if((y + font_height) > canvas_height(canvas)) { + string_init_printf(line, "%.*s...\n", chars_fit, start); } else { string_init_printf(line, "%.*s-\n", chars_fit, start); } canvas_draw_str_aligned(canvas, x, y, horizontal, vertical, string_get_cstr(line)); string_clear(line); y += font_height; + if(y > canvas_height(canvas)) { + break; + } start += chars_fit; start += start[0] == '\n' ? 1 : 0; @@ -547,7 +556,8 @@ void elements_text_box( uint8_t height, Align horizontal, Align vertical, - const char* text) { + const char* text, + bool strip_to_dots) { furi_assert(canvas); ElementTextBoxLine line[ELEMENTS_MAX_LINES_NUM]; @@ -571,6 +581,7 @@ void elements_text_box( uint8_t total_height_default = 0; uint16_t i = 0; bool full_text_processed = false; + uint16_t dots_width = canvas_string_width(canvas, "..."); canvas_set_font(canvas, FontSecondary); @@ -663,31 +674,29 @@ void elements_text_box( } // Set vertical alignment for all lines - if(full_text_processed) { - if(total_height_default < height) { - if(vertical == AlignTop) { - line[0].y = y + line[0].height; - } else if(vertical == AlignCenter) { - line[0].y = y + line[0].height + (height - total_height_default) / 2; - } else if(vertical == AlignBottom) { - line[0].y = y + line[0].height + (height - total_height_default); - } - if(line_num > 1) { - for(uint8_t i = 1; i < line_num; i++) { - line[i].y = line[i - 1].y + line[i - 1].leading_default; - } - } - } else if(line_num > 1) { - uint8_t free_pixel_num = height - total_height_min; - uint8_t fill_pixel = 0; - uint8_t j = 1; + if(total_height_default < height) { + if(vertical == AlignTop) { line[0].y = y + line[0].height; - while(fill_pixel < free_pixel_num) { - line[j].y = line[j - 1].y + line[j - 1].leading_min + 1; - fill_pixel++; - j = j % (line_num - 1) + 1; + } else if(vertical == AlignCenter) { + line[0].y = y + line[0].height + (height - total_height_default) / 2; + } else if(vertical == AlignBottom) { + line[0].y = y + line[0].height + (height - total_height_default); + } + if(line_num > 1) { + for(uint8_t i = 1; i < line_num; i++) { + line[i].y = line[i - 1].y + line[i - 1].leading_default; } } + } else if(line_num > 1) { + uint8_t free_pixel_num = height - total_height_min; + uint8_t fill_pixel = 0; + uint8_t j = 1; + line[0].y = y + line[0].height; + while(fill_pixel < free_pixel_num) { + line[j].y = line[j - 1].y + line[j - 1].leading_min + 1; + fill_pixel++; + j = j % (line_num - 1) + 1; + } } // Draw line by line @@ -733,10 +742,17 @@ void elements_text_box( canvas_draw_glyph(canvas, line[i].x, line[i].y, line[i].text[j]); canvas_invert_color(canvas); } else { + if((i == line_num - 1) && strip_to_dots) { + uint8_t next_symbol_width = canvas_glyph_width(canvas, line[i].text[j]); + if(line[i].x + next_symbol_width + dots_width > x + width) { + canvas_draw_str(canvas, line[i].x, line[i].y, "..."); + break; + } + } canvas_draw_glyph(canvas, line[i].x, line[i].y, line[i].text[j]); } line[i].x += canvas_glyph_width(canvas, line[i].text[j]); } } canvas_set_font(canvas, FontSecondary); -} \ No newline at end of file +} diff --git a/applications/gui/elements.h b/applications/gui/elements.h index 33b5fc666eb..2b8b8d3f2b7 100644 --- a/applications/gui/elements.h +++ b/applications/gui/elements.h @@ -194,17 +194,18 @@ void elements_string_fit_width(Canvas* canvas, string_t string, uint8_t width); /** Draw text box element * - * @param canvas Canvas instance - * @param x x coordinate - * @param y y coordinate - * @param width width to fit text - * @param height height to fit text - * @param horizontal Align instance - * @param vertical Align instance - * @param[in] text Formatted text. The following formats are available: - * "\e#Bold text\e#" - bold font is used - * "\e*Monospaced text\e*" - monospaced font is used - * "\e#Inversed text\e#" - white text on black background + * @param canvas Canvas instance + * @param x x coordinate + * @param y y coordinate + * @param width width to fit text + * @param height height to fit text + * @param horizontal Align instance + * @param vertical Align instance + * @param[in] text Formatted text. The following formats are available: + * "\e#Bold text\e#" - bold font is used + * "\e*Monospaced text\e*" - monospaced font is used + * "\e#Inversed text\e#" - white text on black background + * @param strip_to_dots Strip text to ... if does not fit to width */ void elements_text_box( Canvas* canvas, @@ -214,7 +215,8 @@ void elements_text_box( uint8_t height, Align horizontal, Align vertical, - const char* text); + const char* text, + bool strip_to_dots); #ifdef __cplusplus } diff --git a/applications/gui/gui.c b/applications/gui/gui.c index 69f0e2488db..9ecfdebbf96 100644 --- a/applications/gui/gui.c +++ b/applications/gui/gui.c @@ -314,6 +314,7 @@ void gui_add_view_port(Gui* gui, ViewPort* view_port, GuiLayer layer) { view_port_gui_set(view_port, gui); gui_unlock(gui); + // Request redraw gui_update(gui); } @@ -322,7 +323,6 @@ void gui_remove_view_port(Gui* gui, ViewPort* view_port) { furi_assert(view_port); gui_lock(gui); - view_port_gui_set(view_port, NULL); ViewPortArray_it_t it; for(size_t i = 0; i < GuiLayerMAX; i++) { @@ -335,12 +335,13 @@ void gui_remove_view_port(Gui* gui, ViewPort* view_port) { } } } - if(gui->ongoing_input_view_port == view_port) { gui->ongoing_input_view_port = NULL; } - gui_unlock(gui); + + // Request redraw + gui_update(gui); } void gui_view_port_send_to_front(Gui* gui, ViewPort* view_port) { @@ -367,6 +368,9 @@ void gui_view_port_send_to_front(Gui* gui, ViewPort* view_port) { // Return to the top ViewPortArray_push_back(gui->layers[layer], view_port); gui_unlock(gui); + + // Request redraw + gui_update(gui); } void gui_view_port_send_to_back(Gui* gui, ViewPort* view_port) { @@ -393,6 +397,9 @@ void gui_view_port_send_to_back(Gui* gui, ViewPort* view_port) { // Return to the top ViewPortArray_push_at(gui->layers[layer], 0, view_port); gui_unlock(gui); + + // Request redraw + gui_update(gui); } void gui_add_framebuffer_callback(Gui* gui, GuiCanvasCommitCallback callback, void* context) { @@ -401,11 +408,11 @@ void gui_add_framebuffer_callback(Gui* gui, GuiCanvasCommitCallback callback, vo const CanvasCallbackPair p = {callback, context}; gui_lock(gui); - furi_assert(CanvasCallbackPairArray_count(gui->canvas_callback_pair, p) == 0); CanvasCallbackPairArray_push_back(gui->canvas_callback_pair, p); - gui_unlock(gui); + + // Request redraw gui_update(gui); } @@ -415,10 +422,8 @@ void gui_remove_framebuffer_callback(Gui* gui, GuiCanvasCommitCallback callback, const CanvasCallbackPair p = {callback, context}; gui_lock(gui); - furi_assert(CanvasCallbackPairArray_count(gui->canvas_callback_pair, p) == 1); CanvasCallbackPairArray_remove_val(gui->canvas_callback_pair, p); - gui_unlock(gui); } @@ -429,9 +434,12 @@ size_t gui_get_framebuffer_size(Gui* gui) { void gui_set_lockdown(Gui* gui, bool lockdown) { furi_assert(gui); + gui_lock(gui); gui->lockdown = lockdown; gui_unlock(gui); + + // Request redraw gui_update(gui); } diff --git a/applications/gui/modules/widget.c b/applications/gui/modules/widget.c old mode 100755 new mode 100644 index 09729ee65fe..8d7acb013e8 --- a/applications/gui/modules/widget.c +++ b/applications/gui/modules/widget.c @@ -154,10 +154,11 @@ void widget_add_text_box_element( uint8_t height, Align horizontal, Align vertical, - const char* text) { + const char* text, + bool strip_to_dots) { furi_assert(widget); - WidgetElement* text_box_element = - widget_element_text_box_create(x, y, width, height, horizontal, vertical, text); + WidgetElement* text_box_element = widget_element_text_box_create( + x, y, width, height, horizontal, vertical, text, strip_to_dots); widget_add_element(widget, text_box_element); } diff --git a/applications/gui/modules/widget.h b/applications/gui/modules/widget.h index 98a89435127..55af59d7c0c 100755 --- a/applications/gui/modules/widget.h +++ b/applications/gui/modules/widget.h @@ -81,17 +81,18 @@ void widget_add_string_element( /** Add Text Box Element * - * @param widget Widget instance - * @param x x coordinate - * @param y y coordinate - * @param width width to fit text - * @param height height to fit text - * @param horizontal Align instance - * @param vertical Align instance - * @param[in] text Formatted text. The following formats are available: - * "\e#Bold text\e#" - bold font is used - * "\e*Monospaced text\e*" - monospaced font is used - * "\e#Inversed text\e#" - white text on black background + * @param widget Widget instance + * @param x x coordinate + * @param y y coordinate + * @param width width to fit text + * @param height height to fit text + * @param horizontal Align instance + * @param vertical Align instance + * @param[in] text Formatted text. The following formats are available: + * "\e#Bold text\e#" - bold font is used + * "\e*Monospaced text\e*" - monospaced font is used + * "\e#Inversed text\e#" - white text on black background + * @param strip_to_dots Strip text to ... if does not fit to width */ void widget_add_text_box_element( Widget* widget, @@ -101,7 +102,8 @@ void widget_add_text_box_element( uint8_t height, Align horizontal, Align vertical, - const char* text); + const char* text, + bool strip_to_dots); /** Add Button Element * diff --git a/applications/gui/modules/widget_elements/widget_element_i.h b/applications/gui/modules/widget_elements/widget_element_i.h index d7b4e4634d5..bcbd4afdbc8 100755 --- a/applications/gui/modules/widget_elements/widget_element_i.h +++ b/applications/gui/modules/widget_elements/widget_element_i.h @@ -60,7 +60,8 @@ WidgetElement* widget_element_text_box_create( uint8_t height, Align horizontal, Align vertical, - const char* text); + const char* text, + bool strip_to_dots); /** Create button element */ WidgetElement* widget_element_button_create( diff --git a/applications/gui/modules/widget_elements/widget_element_text_box.c b/applications/gui/modules/widget_elements/widget_element_text_box.c index a4dee5f6cf6..4750f8f8fcf 100644 --- a/applications/gui/modules/widget_elements/widget_element_text_box.c +++ b/applications/gui/modules/widget_elements/widget_element_text_box.c @@ -10,6 +10,7 @@ typedef struct { Align horizontal; Align vertical; string_t text; + bool strip_to_dots; } GuiTextBoxModel; static void gui_text_box_draw(Canvas* canvas, WidgetElement* element) { @@ -26,7 +27,8 @@ static void gui_text_box_draw(Canvas* canvas, WidgetElement* element) { model->height, model->horizontal, model->vertical, - string_get_cstr(model->text)); + string_get_cstr(model->text), + model->strip_to_dots); } } @@ -46,7 +48,8 @@ WidgetElement* widget_element_text_box_create( uint8_t height, Align horizontal, Align vertical, - const char* text) { + const char* text, + bool strip_to_dots) { furi_assert(text); // Allocate and init model @@ -58,6 +61,7 @@ WidgetElement* widget_element_text_box_create( model->horizontal = horizontal; model->vertical = vertical; string_init_set_str(model->text, text); + model->strip_to_dots = strip_to_dots; // Allocate and init Element WidgetElement* gui_string = malloc(sizeof(WidgetElement)); diff --git a/applications/ibutton/scene/ibutton_scene_delete_confirm.cpp b/applications/ibutton/scene/ibutton_scene_delete_confirm.cpp index 1c96b4dfe49..8e782e33014 100755 --- a/applications/ibutton/scene/ibutton_scene_delete_confirm.cpp +++ b/applications/ibutton/scene/ibutton_scene_delete_confirm.cpp @@ -21,7 +21,7 @@ void iButtonSceneDeleteConfirm::on_enter(iButtonApp* app) { app->set_text_store("\e#Delete %s?\e#", ibutton_key_get_name_p(key)); widget_add_text_box_element( - widget, 0, 0, 128, 27, AlignCenter, AlignCenter, app->get_text_store()); + widget, 0, 0, 128, 27, AlignCenter, AlignCenter, app->get_text_store(), false); widget_add_button_element(widget, GuiButtonTypeLeft, "Cancel", widget_callback, app); widget_add_button_element(widget, GuiButtonTypeRight, "Delete", widget_callback, app); diff --git a/applications/ibutton/scene/ibutton_scene_info.cpp b/applications/ibutton/scene/ibutton_scene_info.cpp index ae39774f835..e51b2095f51 100755 --- a/applications/ibutton/scene/ibutton_scene_info.cpp +++ b/applications/ibutton/scene/ibutton_scene_info.cpp @@ -9,7 +9,7 @@ void iButtonSceneInfo::on_enter(iButtonApp* app) { app->set_text_store("%s", ibutton_key_get_name_p(key)); widget_add_text_box_element( - widget, 0, 0, 128, 28, AlignCenter, AlignCenter, app->get_text_store()); + widget, 0, 0, 128, 28, AlignCenter, AlignCenter, app->get_text_store(), false); switch(ibutton_key_get_type(key)) { case iButtonKeyDS1990: diff --git a/applications/ibutton/scene/ibutton_scene_read_key_menu.cpp b/applications/ibutton/scene/ibutton_scene_read_key_menu.cpp index b77572249fd..215eb76f65d 100644 --- a/applications/ibutton/scene/ibutton_scene_read_key_menu.cpp +++ b/applications/ibutton/scene/ibutton_scene_read_key_menu.cpp @@ -2,9 +2,9 @@ #include "../ibutton_app.h" typedef enum { - SubmenuIndexWrite, - SubmenuIndexEmulate, SubmenuIndexSave, + SubmenuIndexEmulate, + SubmenuIndexWrite, } SubmenuIndex; static void submenu_callback(void* context, uint32_t index) { @@ -22,11 +22,11 @@ void iButtonSceneReadKeyMenu::on_enter(iButtonApp* app) { iButtonAppViewManager* view_manager = app->get_view_manager(); Submenu* submenu = view_manager->get_submenu(); + submenu_add_item(submenu, "Save", SubmenuIndexSave, submenu_callback, app); + submenu_add_item(submenu, "Emulate", SubmenuIndexEmulate, submenu_callback, app); if(ibutton_key_get_type(app->get_key()) == iButtonKeyDS1990) { submenu_add_item(submenu, "Write", SubmenuIndexWrite, submenu_callback, app); } - submenu_add_item(submenu, "Save", SubmenuIndexSave, submenu_callback, app); - submenu_add_item(submenu, "Emulate", SubmenuIndexEmulate, submenu_callback, app); submenu_set_selected_item(submenu, submenu_item_selected); view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewSubmenu); @@ -62,4 +62,4 @@ void iButtonSceneReadKeyMenu::on_exit(iButtonApp* app) { Submenu* submenu = view->get_submenu(); submenu_reset(submenu); -} \ No newline at end of file +} diff --git a/applications/infrared/infrared_app.cpp b/applications/infrared/infrared_app.cpp index 35d814dc648..c9a7ee4f750 100644 --- a/applications/infrared/infrared_app.cpp +++ b/applications/infrared/infrared_app.cpp @@ -14,14 +14,17 @@ int32_t InfraredApp::run(void* args) { if(args) { std::string path = static_cast(args); std::string remote_name(path, path.find_last_of('/') + 1, path.size()); - remote_name.erase(remote_name.find_last_of('.')); - path.erase(path.find_last_of('/')); - bool result = remote_manager.load(path, remote_name); - if(result) { - current_scene = InfraredApp::Scene::Remote; - } else { - printf("Failed to load remote \'%s\'\r\n", remote_name.c_str()); - return -1; + auto last_dot = remote_name.find_last_of('.'); + if(last_dot != std::string::npos) { + remote_name.erase(last_dot); + path.erase(path.find_last_of('/')); + bool result = remote_manager.load(path, remote_name); + if(result) { + current_scene = InfraredApp::Scene::Remote; + } else { + printf("Failed to load remote \'%s\'\r\n", remote_name.c_str()); + return -1; + } } } @@ -49,12 +52,14 @@ int32_t InfraredApp::run(void* args) { InfraredApp::InfraredApp() { furi_check(InfraredAppRemoteManager::max_button_name_length < get_text_store_size()); notification = static_cast(furi_record_open("notification")); + dialogs = static_cast(furi_record_open("dialogs")); infrared_worker = infrared_worker_alloc(); } InfraredApp::~InfraredApp() { infrared_worker_free(infrared_worker); furi_record_close("notification"); + furi_record_close("dialogs"); for(auto& [key, scene] : scenes) delete scene; } @@ -248,6 +253,10 @@ void InfraredApp::notify_blink_green() { notification_message(notification, &sequence); } +DialogsApp* InfraredApp::get_dialogs() { + return dialogs; +} + void InfraredApp::notify_green_on() { notification_message(notification, &sequence_set_only_green_255); } diff --git a/applications/infrared/infrared_app.h b/applications/infrared/infrared_app.h index 39897272a28..f1580402be0 100644 --- a/applications/infrared/infrared_app.h +++ b/applications/infrared/infrared_app.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include "scene/infrared_app_scene.h" @@ -228,6 +229,9 @@ class InfraredApp { /** Blink green light */ void notify_blink_green(); + /** Get Dialogs instance */ + DialogsApp* get_dialogs(); + /** Text input callback * * @param context - context to pass to callback @@ -286,6 +290,8 @@ class InfraredApp { /** Notification instance */ NotificationApp* notification; + /** Dialogs instance */ + DialogsApp* dialogs; /** View manager instance */ InfraredAppViewManager view_manager; /** Remote manager instance */ diff --git a/applications/infrared/infrared_app_brute_force.cpp b/applications/infrared/infrared_app_brute_force.cpp index 24be4d3ecec..2910a3998d9 100644 --- a/applications/infrared/infrared_app_brute_force.cpp +++ b/applications/infrared/infrared_app_brute_force.cpp @@ -5,7 +5,6 @@ #include #include #include -#include void InfraredAppBruteForce::add_record(int index, const char* name) { records[name].index = index; diff --git a/applications/infrared/infrared_app_remote_manager.cpp b/applications/infrared/infrared_app_remote_manager.cpp index 9fbef84febc..4fd64553269 100644 --- a/applications/infrared/infrared_app_remote_manager.cpp +++ b/applications/infrared/infrared_app_remote_manager.cpp @@ -1,4 +1,3 @@ -#include #include #include "infrared_app_remote_manager.h" #include "infrared/helpers/infrared_parser.h" @@ -22,26 +21,34 @@ std::string InfraredAppRemoteManager::make_full_name( } std::string InfraredAppRemoteManager::find_vacant_remote_name(const std::string& name) { - bool exist = true; - FileWorkerCpp file_worker; - - if(!file_worker.is_file_exist( - make_full_name(InfraredApp::infrared_directory, name).c_str(), &exist)) { - return std::string(); - } else if(!exist) { - return name; - } + std::string result_name; + Storage* storage = static_cast(furi_record_open("storage")); - /* if suggested name is occupied, try another one (name2, name3, etc) */ - uint32_t i = 1; - bool file_worker_result = false; - std::string new_name; - do { - new_name = make_full_name(InfraredApp::infrared_directory, name + std::to_string(++i)); - file_worker_result = file_worker.is_file_exist(new_name.c_str(), &exist); - } while(file_worker_result && exist); + FS_Error error = storage_common_stat( + storage, make_full_name(InfraredApp::infrared_directory, name).c_str(), NULL); + + if(error == FSE_NOT_EXIST) { + result_name = name; + } else if(error != FSE_OK) { + result_name = std::string(); + } else { + /* if suggested name is occupied, try another one (name2, name3, etc) */ + uint32_t i = 1; + std::string new_name; + do { + new_name = make_full_name(InfraredApp::infrared_directory, name + std::to_string(++i)); + error = storage_common_stat(storage, new_name.c_str(), NULL); + } while(error == FSE_OK); + + if(error == FSE_NOT_EXIST) { + result_name = name + std::to_string(i); + } else { + result_name = std::string(); + } + } - return !exist ? name + std::to_string(i) : std::string(); + furi_record_close("storage"); + return result_name; } bool InfraredAppRemoteManager::add_button(const char* button_name, const InfraredAppSignal& signal) { @@ -84,12 +91,14 @@ const InfraredAppSignal& InfraredAppRemoteManager::get_button_data(size_t index) } bool InfraredAppRemoteManager::delete_remote() { - bool result; - FileWorkerCpp file_worker; - result = file_worker.remove(make_full_name(remote->path, remote->name).c_str()); + Storage* storage = static_cast(furi_record_open("storage")); + FS_Error error = + storage_common_remove(storage, make_full_name(remote->path, remote->name).c_str()); reset_remote(); - return result; + + furi_record_close("storage"); + return (error == FSE_OK || error == FSE_NOT_EXIST); } void InfraredAppRemoteManager::reset_remote() { @@ -129,14 +138,15 @@ bool InfraredAppRemoteManager::rename_remote(const char* str) { return false; } - FileWorkerCpp file_worker; + Storage* storage = static_cast(furi_record_open("storage")); + std::string old_filename = make_full_name(remote->path, remote->name); std::string new_filename = make_full_name(remote->path, new_name); - bool result = file_worker.rename(old_filename.c_str(), new_filename.c_str()); - + FS_Error error = storage_common_rename(storage, old_filename.c_str(), new_filename.c_str()); remote->name = new_name; - return result; + furi_record_close("storage"); + return (error == FSE_OK || error == FSE_EXIST); } bool InfraredAppRemoteManager::rename_button(uint32_t index, const char* str) { @@ -155,11 +165,10 @@ size_t InfraredAppRemoteManager::get_number_of_buttons() { bool InfraredAppRemoteManager::store(void) { bool result = false; - FileWorkerCpp file_worker; + Storage* storage = static_cast(furi_record_open("storage")); - if(!file_worker.mkdir(InfraredApp::infrared_directory)) return false; + if(!storage_simply_mkdir(storage, InfraredApp::infrared_directory)) return false; - Storage* storage = static_cast(furi_record_open("storage")); FlipperFormat* ff = flipper_format_file_alloc(storage); FURI_LOG_I( diff --git a/applications/infrared/scene/infrared_app_scene_edit.cpp b/applications/infrared/scene/infrared_app_scene_edit.cpp index 73e9153e94e..5a2ae72fff8 100644 --- a/applications/infrared/scene/infrared_app_scene_edit.cpp +++ b/applications/infrared/scene/infrared_app_scene_edit.cpp @@ -23,9 +23,9 @@ void InfraredAppSceneEdit::on_enter(InfraredApp* app) { InfraredAppViewManager* view_manager = app->get_view_manager(); Submenu* submenu = view_manager->get_submenu(); - submenu_add_item(submenu, "Add Key", SubmenuIndexAddKey, submenu_callback, app); - submenu_add_item(submenu, "Rename Key", SubmenuIndexRenameKey, submenu_callback, app); - submenu_add_item(submenu, "Delete Key", SubmenuIndexDeleteKey, submenu_callback, app); + submenu_add_item(submenu, "Add Button", SubmenuIndexAddKey, submenu_callback, app); + submenu_add_item(submenu, "Rename Button", SubmenuIndexRenameKey, submenu_callback, app); + submenu_add_item(submenu, "Delete Button", SubmenuIndexDeleteKey, submenu_callback, app); submenu_add_item(submenu, "Rename Remote", SubmenuIndexRenameRemote, submenu_callback, app); submenu_add_item(submenu, "Delete Remote", SubmenuIndexDeleteRemote, submenu_callback, app); submenu_set_selected_item(submenu, submenu_item_selected); diff --git a/applications/infrared/scene/infrared_app_scene_edit_delete.cpp b/applications/infrared/scene/infrared_app_scene_edit_delete.cpp index 0818b6fb8a6..d49acec528d 100644 --- a/applications/infrared/scene/infrared_app_scene_edit_delete.cpp +++ b/applications/infrared/scene/infrared_app_scene_edit_delete.cpp @@ -51,7 +51,7 @@ void InfraredAppSceneEditDelete::on_enter(InfraredApp* app) { dialog_ex_set_text(dialog_ex, app->get_text_store(0), 64, 31, AlignCenter, AlignCenter); dialog_ex_set_icon(dialog_ex, 0, 0, NULL); - dialog_ex_set_left_button_text(dialog_ex, "Back"); + dialog_ex_set_left_button_text(dialog_ex, "Cancel"); dialog_ex_set_right_button_text(dialog_ex, "Delete"); dialog_ex_set_result_callback(dialog_ex, dialog_result_callback); dialog_ex_set_context(dialog_ex, app); diff --git a/applications/infrared/scene/infrared_app_scene_edit_key_select.cpp b/applications/infrared/scene/infrared_app_scene_edit_key_select.cpp index 7f94fb15252..49142c212be 100644 --- a/applications/infrared/scene/infrared_app_scene_edit_key_select.cpp +++ b/applications/infrared/scene/infrared_app_scene_edit_key_select.cpp @@ -16,8 +16,9 @@ void InfraredAppSceneEditKeySelect::on_enter(InfraredApp* app) { Submenu* submenu = view_manager->get_submenu(); int item_number = 0; - const char* header = - app->get_edit_action() == InfraredApp::EditAction::Rename ? "Rename key:" : "Delete key:"; + const char* header = app->get_edit_action() == InfraredApp::EditAction::Rename ? + "Rename Button:" : + "Delete Button:"; submenu_set_header(submenu, header); auto remote_manager = app->get_remote_manager(); diff --git a/applications/infrared/scene/infrared_app_scene_edit_rename.cpp b/applications/infrared/scene/infrared_app_scene_edit_rename.cpp index 0bdd90ac832..dc63c64b11b 100644 --- a/applications/infrared/scene/infrared_app_scene_edit_rename.cpp +++ b/applications/infrared/scene/infrared_app_scene_edit_rename.cpp @@ -14,7 +14,7 @@ void InfraredAppSceneEditRename::on_enter(InfraredApp* app) { strncpy(buffer_str, button_name.c_str(), max_len); buffer_str[max_len + 1] = 0; enter_name_length = max_len; - text_input_set_header_text(text_input, "Name the key"); + text_input_set_header_text(text_input, "Name the button"); } else { auto remote_name = remote_manager->get_remote_name(); strncpy(app->get_text_store(0), remote_name.c_str(), app->get_text_store_size()); diff --git a/applications/infrared/scene/infrared_app_scene_learn_enter_name.cpp b/applications/infrared/scene/infrared_app_scene_learn_enter_name.cpp index e0f2ebd13bd..0f148e8076b 100644 --- a/applications/infrared/scene/infrared_app_scene_learn_enter_name.cpp +++ b/applications/infrared/scene/infrared_app_scene_learn_enter_name.cpp @@ -20,7 +20,7 @@ void InfraredAppSceneLearnEnterName::on_enter(InfraredApp* app) { app->set_text_store(0, "RAW_%d", raw_signal.timings_cnt); } - text_input_set_header_text(text_input, "Name the key"); + text_input_set_header_text(text_input, "Name the button"); text_input_set_result_callback( text_input, InfraredApp::text_input_callback, diff --git a/applications/infrared/scene/infrared_app_scene_learn_success.cpp b/applications/infrared/scene/infrared_app_scene_learn_success.cpp index 61d60ab5988..b620a5edd79 100644 --- a/applications/infrared/scene/infrared_app_scene_learn_success.cpp +++ b/applications/infrared/scene/infrared_app_scene_learn_success.cpp @@ -1,5 +1,4 @@ #include -#include #include #include @@ -88,13 +87,8 @@ bool InfraredAppSceneLearnSuccess::on_event(InfraredApp* app, InfraredAppEvent* break; case DialogExResultRight: { consumed = true; - FileWorkerCpp file_worker; if(!button_pressed) { - if(file_worker.check_errors()) { - app->switch_to_next_scene(InfraredApp::Scene::LearnEnterName); - } else { - app->switch_to_previous_scene(); - } + app->switch_to_next_scene(InfraredApp::Scene::LearnEnterName); } break; } diff --git a/applications/infrared/scene/infrared_app_scene_remote_list.cpp b/applications/infrared/scene/infrared_app_scene_remote_list.cpp index defebf76748..95ef2e4112d 100644 --- a/applications/infrared/scene/infrared_app_scene_remote_list.cpp +++ b/applications/infrared/scene/infrared_app_scene_remote_list.cpp @@ -1,12 +1,10 @@ #include "../infrared_app.h" #include "infrared/infrared_app_event.h" #include -#include void InfraredAppSceneRemoteList::on_enter(InfraredApp* app) { furi_assert(app); - FileWorkerCpp file_worker; bool result = false; bool file_select_result; auto remote_manager = app->get_remote_manager(); @@ -15,13 +13,15 @@ void InfraredAppSceneRemoteList::on_enter(InfraredApp* app) { last_selected_remote.size() ? last_selected_remote.c_str() : nullptr; auto filename_ts = std::make_unique(InfraredAppRemoteManager::max_remote_name_length); + DialogsApp* dialogs = app->get_dialogs(); InfraredAppViewManager* view_manager = app->get_view_manager(); ButtonMenu* button_menu = view_manager->get_button_menu(); button_menu_reset(button_menu); view_manager->switch_to(InfraredAppViewManager::ViewId::ButtonMenu); - file_select_result = file_worker.file_select( + file_select_result = dialog_file_select_show( + dialogs, InfraredApp::infrared_directory, InfraredApp::infrared_extension, filename_ts->text, diff --git a/applications/input/input_cli.c b/applications/input/input_cli.c index eb510f6c7fe..00591a75c01 100644 --- a/applications/input/input_cli.c +++ b/applications/input/input_cli.c @@ -24,19 +24,15 @@ static void input_cli_dump(Cli* cli, string_t args, Input* input) { FuriPubSubSubscription* input_subscription = furi_pubsub_subscribe(input->event_pubsub, input_cli_dump_events_callback, input_queue); - bool stop = false; InputEvent input_event; - while(!stop) { + printf("Press CTRL+C to stop\r\n"); + while(!cli_cmd_interrupt_received(cli)) { if(osMessageQueueGet(input_queue, &input_event, NULL, 100) == osOK) { printf( "key: %s type: %s\r\n", input_get_key_name(input_event.key), input_get_type_name(input_event.type)); } - - if(cli_cmd_interrupt_received(cli)) { - stop = true; - } } furi_pubsub_unsubscribe(input->event_pubsub, input_subscription); diff --git a/applications/lfrfid/scene/lfrfid_app_scene_read_menu.cpp b/applications/lfrfid/scene/lfrfid_app_scene_read_menu.cpp index ce0461f9220..76c91230654 100644 --- a/applications/lfrfid/scene/lfrfid_app_scene_read_menu.cpp +++ b/applications/lfrfid/scene/lfrfid_app_scene_read_menu.cpp @@ -1,17 +1,17 @@ #include "lfrfid_app_scene_read_menu.h" typedef enum { - SubmenuWrite, SubmenuSave, SubmenuEmulate, + SubmenuWrite, } SubmenuIndex; void LfRfidAppSceneReadKeyMenu::on_enter(LfRfidApp* app, bool need_restore) { auto submenu = app->view_controller.get(); - submenu->add_item("Write", SubmenuWrite, submenu_callback, app); submenu->add_item("Save", SubmenuSave, submenu_callback, app); submenu->add_item("Emulate", SubmenuEmulate, submenu_callback, app); + submenu->add_item("Write", SubmenuWrite, submenu_callback, app); if(need_restore) { submenu->set_selected_item(submenu_item_selected); diff --git a/applications/loader/loader.c b/applications/loader/loader.c index dafe255a38b..3882647efdb 100644 --- a/applications/loader/loader.c +++ b/applications/loader/loader.c @@ -92,7 +92,7 @@ const FlipperApplication* loader_find_application_by_name(const char* name) { application = loader_find_application_by_name_in_list( name, FLIPPER_SYSTEM_APPS, FLIPPER_SYSTEM_APPS_COUNT); } - if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug) && !application) { + if(!application) { application = loader_find_application_by_name_in_list( name, FLIPPER_DEBUG_APPS, FLIPPER_DEBUG_APPS_COUNT); } @@ -239,26 +239,11 @@ static void loader_thread_state_callback(FuriThreadState thread_state, void* con event.type = LoaderEventTypeApplicationStarted; furi_pubsub_publish(loader_instance->pubsub, &event); furi_hal_power_insomnia_enter(); - - // Snapshot current memory usage - instance->free_heap_size = memmgr_get_free_heap(); } else if(thread_state == FuriThreadStateStopped) { - /* - * Current Leak Sanitizer assumes that memory is allocated and freed - * inside one thread. Timers are allocated in one task, but freed in - * Timer-Task thread, and xTimerDelete() just put command to queue. - * To avoid some bad cases there are few fixes: - * 1) delay for Timer to process commands - * 2) there are 'heap diff' which shows difference in heap before task - * started and after task completed. In process of leakage monitoring - * both values should be taken into account. - */ - furi_hal_delay_ms(20); - int heap_diff = instance->free_heap_size - memmgr_get_free_heap(); FURI_LOG_I( TAG, - "Application thread stopped. Heap allocation balance: %d. Thread allocation balance: %d.", - heap_diff, + "Application thread stopped. Free heap: %d. Thread allocation balance: %d.", + memmgr_get_free_heap(), furi_thread_get_heap_size(instance->application_thread)); if(loader_instance->application_arguments) { @@ -455,18 +440,17 @@ void loader_update_menu() { } int32_t loader_srv(void* p) { - FURI_LOG_I(TAG, "Starting"); + FURI_LOG_I(TAG, "Executing system start hooks"); + for(size_t i = 0; i < FLIPPER_ON_SYSTEM_START_COUNT; i++) { + FLIPPER_ON_SYSTEM_START[i](); + } + FURI_LOG_I(TAG, "Starting"); loader_instance = loader_alloc(); loader_build_menu(); loader_build_submenu(); - // Call on start hooks - for(size_t i = 0; i < FLIPPER_ON_SYSTEM_START_COUNT; i++) { - FLIPPER_ON_SYSTEM_START[i](); - } - FURI_LOG_I(TAG, "Started"); furi_record_create("loader", loader_instance); diff --git a/applications/loader/loader_i.h b/applications/loader/loader_i.h index a8b8bfc0918..4c937b94248 100644 --- a/applications/loader/loader_i.h +++ b/applications/loader/loader_i.h @@ -30,7 +30,6 @@ struct Loader { Submenu* debug_menu; Submenu* settings_menu; - size_t free_heap_size; volatile uint8_t lock_count; FuriPubSub* pubsub; diff --git a/applications/nfc/nfc.c b/applications/nfc/nfc.c index a249f85e782..4660b344fca 100755 --- a/applications/nfc/nfc.c +++ b/applications/nfc/nfc.c @@ -3,19 +3,19 @@ bool nfc_custom_event_callback(void* context, uint32_t event) { furi_assert(context); - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; return scene_manager_handle_custom_event(nfc->scene_manager, event); } bool nfc_back_event_callback(void* context) { furi_assert(context); - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; return scene_manager_handle_back_event(nfc->scene_manager); } void nfc_tick_event_callback(void* context) { furi_assert(context); - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; scene_manager_handle_tick_event(nfc->scene_manager); } @@ -169,11 +169,16 @@ int32_t nfc_app(void* p) { char* args = p; // Check argument and run corresponding scene - if((*args != '\0') && nfc_device_load(nfc->dev, p)) { - if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { - scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareUl); + if((*args != '\0')) { + if(nfc_device_load(nfc->dev, p)) { + if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareUl); + } else { + scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); + } } else { - scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); + // Exit app + view_dispatcher_stop(nfc->view_dispatcher); } } else { scene_manager_next_scene(nfc->scene_manager, NfcSceneStart); diff --git a/applications/nfc/nfc_cli.c b/applications/nfc/nfc_cli.c index 98024e7daf2..52c971ef4a1 100755 --- a/applications/nfc/nfc_cli.c +++ b/applications/nfc/nfc_cli.c @@ -16,40 +16,35 @@ static void nfc_cli_print_usage() { } } -void nfc_cli_detect(Cli* cli, string_t args) { +static void nfc_cli_detect(Cli* cli, string_t args) { // Check if nfc worker is not busy if(furi_hal_nfc_is_busy()) { printf("Nfc is busy\r\n"); return; } - rfalNfcDevice* dev_list; - uint8_t dev_cnt = 0; + + FuriHalNfcDevData dev_data = {}; bool cmd_exit = false; furi_hal_nfc_exit_sleep(); printf("Detecting nfc...\r\nPress Ctrl+C to abort\r\n"); while(!cmd_exit) { cmd_exit |= cli_cmd_interrupt_received(cli); - cmd_exit |= furi_hal_nfc_detect(&dev_list, &dev_cnt, 400, true); - if(dev_cnt > 0) { - printf("Found %d devices\r\n", dev_cnt); - for(uint8_t i = 0; i < dev_cnt; i++) { - printf("%d found: %s ", i + 1, nfc_get_rfal_type(dev_list[i].type)); - if(dev_list[i].type == RFAL_NFC_LISTEN_TYPE_NFCA) { - printf("type: %s, ", nfc_get_nfca_type(dev_list[i].dev.nfca.type)); - } - printf("UID length: %d, UID:", dev_list[i].nfcidLen); - for(uint8_t j = 0; j < dev_list[i].nfcidLen; j++) { - printf("%02X", dev_list[i].nfcid[j]); - } - printf("\r\n"); + if(furi_hal_nfc_detect(&dev_data, 400)) { + printf("found: %s ", nfc_get_dev_type(dev_data.type)); + printf("UID length: %d, UID:", dev_data.uid_len); + for(size_t i = 0; i < dev_data.uid_len; i++) { + printf("%02X", dev_data.uid[i]); } + printf("\r\n"); + break; } + furi_hal_nfc_sleep(); osDelay(50); } - furi_hal_nfc_deactivate(); + furi_hal_nfc_sleep(); } -void nfc_cli_emulate(Cli* cli, string_t args) { +static void nfc_cli_emulate(Cli* cli, string_t args) { // Check if nfc worker is not busy if(furi_hal_nfc_is_busy()) { printf("Nfc is busy\r\n"); @@ -60,26 +55,25 @@ void nfc_cli_emulate(Cli* cli, string_t args) { printf("Emulating NFC-A Type: T2T UID: 36 9C E7 B1 0A C1 34 SAK: 00 ATQA: 00/44\r\n"); printf("Press Ctrl+C to abort\r\n"); - NfcDeviceCommonData params = { + FuriHalNfcDevData params = { .uid = {0x36, 0x9C, 0xe7, 0xb1, 0x0A, 0xC1, 0x34}, .uid_len = 7, .atqa = {0x44, 0x00}, .sak = 0x00, - .device = NfcDeviceNfca, - .protocol = NfcDeviceProtocolMifareUl, + .type = FuriHalNfcTypeA, }; while(!cli_cmd_interrupt_received(cli)) { if(furi_hal_nfc_listen(params.uid, params.uid_len, params.atqa, params.sak, false, 100)) { printf("Reader detected\r\n"); - furi_hal_nfc_deactivate(); + furi_hal_nfc_sleep(); } osDelay(50); } - furi_hal_nfc_deactivate(); + furi_hal_nfc_sleep(); } -void nfc_cli_field(Cli* cli, string_t args) { +static void nfc_cli_field(Cli* cli, string_t args) { // Check if nfc worker is not busy if(furi_hal_nfc_is_busy()) { printf("Nfc is busy\r\n"); @@ -97,7 +91,7 @@ void nfc_cli_field(Cli* cli, string_t args) { } furi_hal_nfc_field_off(); - furi_hal_nfc_deactivate(); + furi_hal_nfc_sleep(); } static void nfc_cli(Cli* cli, string_t args, void* context) { diff --git a/applications/nfc/nfc_device.c b/applications/nfc/nfc_device.c index 954a48cd192..c3e6bdd46ff 100644 --- a/applications/nfc/nfc_device.c +++ b/applications/nfc/nfc_device.c @@ -41,31 +41,31 @@ static void nfc_device_prepare_format_string(NfcDevice* dev, string_t format_str static bool nfc_device_parse_format_string(NfcDevice* dev, string_t format_string) { if(string_start_with_str_p(format_string, "UID")) { dev->format = NfcDeviceSaveFormatUid; - dev->dev_data.nfc_data.protocol = NfcDeviceProtocolUnknown; + dev->dev_data.protocol = NfcDeviceProtocolUnknown; return true; } if(string_start_with_str_p(format_string, "Bank card")) { dev->format = NfcDeviceSaveFormatBankCard; - dev->dev_data.nfc_data.protocol = NfcDeviceProtocolEMV; + dev->dev_data.protocol = NfcDeviceProtocolEMV; return true; } // Check Mifare Ultralight types for(MfUltralightType type = MfUltralightTypeUnknown; type < MfUltralightTypeNum; type++) { - if(string_start_with_str_p(format_string, nfc_mf_ul_type(type, true))) { + if(string_equal_str_p(format_string, nfc_mf_ul_type(type, true))) { dev->format = NfcDeviceSaveFormatMifareUl; - dev->dev_data.nfc_data.protocol = NfcDeviceProtocolMifareUl; + dev->dev_data.protocol = NfcDeviceProtocolMifareUl; dev->dev_data.mf_ul_data.type = type; return true; } } if(string_start_with_str_p(format_string, "Mifare Classic")) { dev->format = NfcDeviceSaveFormatMifareClassic; - dev->dev_data.nfc_data.protocol = NfcDeviceProtocolMifareClassic; + dev->dev_data.protocol = NfcDeviceProtocolMifareClassic; return true; } if(string_start_with_str_p(format_string, "Mifare DESFire")) { dev->format = NfcDeviceSaveFormatMifareDesfire; - dev->dev_data.nfc_data.protocol = NfcDeviceProtocolMifareDesfire; + dev->dev_data.protocol = NfcDeviceProtocolMifareDesfire; return true; } return false; @@ -73,7 +73,7 @@ static bool nfc_device_parse_format_string(NfcDevice* dev, string_t format_strin static bool nfc_device_save_mifare_ul_data(FlipperFormat* file, NfcDevice* dev) { bool saved = false; - MifareUlData* data = &dev->dev_data.mf_ul_data; + MfUltralightData* data = &dev->dev_data.mf_ul_data; string_t temp_str; string_init(temp_str); @@ -122,7 +122,7 @@ static bool nfc_device_save_mifare_ul_data(FlipperFormat* file, NfcDevice* dev) bool nfc_device_load_mifare_ul_data(FlipperFormat* file, NfcDevice* dev) { bool parsed = false; - MifareUlData* data = &dev->dev_data.mf_ul_data; + MfUltralightData* data = &dev->dev_data.mf_ul_data; string_t temp_str; string_init(temp_str); @@ -548,7 +548,7 @@ bool nfc_device_load_mifare_df_data(FlipperFormat* file, NfcDevice* dev) { static bool nfc_device_save_bank_card_data(FlipperFormat* file, NfcDevice* dev) { bool saved = false; - NfcEmvData* data = &dev->dev_data.emv_data; + EmvData* data = &dev->dev_data.emv_data; uint32_t data_temp = 0; do { @@ -577,8 +577,8 @@ static bool nfc_device_save_bank_card_data(FlipperFormat* file, NfcDevice* dev) bool nfc_device_load_bank_card_data(FlipperFormat* file, NfcDevice* dev) { bool parsed = false; - NfcEmvData* data = &dev->dev_data.emv_data; - memset(data, 0, sizeof(NfcEmvData)); + EmvData* data = &dev->dev_data.emv_data; + memset(data, 0, sizeof(EmvData)); uint32_t data_cnt = 0; string_t temp_str; string_init(temp_str); @@ -700,7 +700,7 @@ static bool nfc_device_save_file( bool saved = false; FlipperFormat* file = flipper_format_file_alloc(dev->storage); - NfcDeviceCommonData* data = &dev->dev_data.nfc_data; + FuriHalNfcDevData* data = &dev->dev_data.nfc_data; string_t temp_str; string_init(temp_str); @@ -758,7 +758,7 @@ bool nfc_device_save_shadow(NfcDevice* dev, const char* dev_name) { static bool nfc_device_load_data(NfcDevice* dev, string_t path) { bool parsed = false; FlipperFormat* file = flipper_format_file_alloc(dev->storage); - NfcDeviceCommonData* data = &dev->dev_data.nfc_data; + FuriHalNfcDevData* data = &dev->dev_data.nfc_data; uint32_t data_cnt = 0; string_t temp_str; string_init(temp_str); @@ -789,6 +789,7 @@ static bool nfc_device_load_data(NfcDevice* dev, string_t path) { if(!nfc_device_parse_format_string(dev, temp_str)) break; // Read and parse UID, ATQA and SAK if(!flipper_format_get_value_count(file, "UID", &data_cnt)) break; + if(!(data_cnt == 4 || data_cnt == 7)) break; data->uid_len = data_cnt; if(!flipper_format_read_hex(file, "UID", data->uid, data->uid_len)) break; if(!flipper_format_read_hex(file, "ATQA", data->atqa, 2)) break; @@ -863,7 +864,7 @@ bool nfc_file_select(NfcDevice* dev) { } void nfc_device_data_clear(NfcDeviceData* dev_data) { - if(dev_data->nfc_data.protocol == NfcDeviceProtocolMifareDesfire) { + if(dev_data->protocol == NfcDeviceProtocolMifareDesfire) { mf_df_clear(&dev_data->mf_df_data); } } diff --git a/applications/nfc/nfc_device.h b/applications/nfc/nfc_device.h index 78b2fe4cefc..215f637fa46 100644 --- a/applications/nfc/nfc_device.h +++ b/applications/nfc/nfc_device.h @@ -5,6 +5,8 @@ #include #include +#include +#include #include #include #include @@ -17,13 +19,6 @@ #define NFC_APP_EXTENSION ".nfc" #define NFC_APP_SHADOW_EXTENSION ".shd" -typedef enum { - NfcDeviceNfca, - NfcDeviceNfcb, - NfcDeviceNfcf, - NfcDeviceNfcv, -} NfcDeviceType; - typedef enum { NfcDeviceProtocolUnknown, NfcDeviceProtocolEMV, @@ -40,38 +35,18 @@ typedef enum { NfcDeviceSaveFormatMifareDesfire, } NfcDeviceSaveFormat; -typedef struct { - uint8_t uid_len; - uint8_t uid[10]; - uint8_t atqa[2]; - uint8_t sak; - NfcDeviceType device; - NfcProtocol protocol; -} NfcDeviceCommonData; - -typedef struct { - char name[32]; - uint8_t aid[16]; - uint16_t aid_len; - uint8_t number[10]; - uint8_t number_len; - uint8_t exp_mon; - uint8_t exp_year; - uint16_t country_code; - uint16_t currency_code; -} NfcEmvData; - typedef struct { uint8_t data[NFC_READER_DATA_MAX_SIZE]; uint16_t size; } NfcReaderRequestData; typedef struct { - NfcDeviceCommonData nfc_data; + FuriHalNfcDevData nfc_data; + NfcProtocol protocol; NfcReaderRequestData reader_data; union { - NfcEmvData emv_data; - MifareUlData mf_ul_data; + EmvData emv_data; + MfUltralightData mf_ul_data; MfClassicData mf_classic_data; MifareDesfireData mf_df_data; }; diff --git a/applications/nfc/nfc_i.h b/applications/nfc/nfc_i.h index 34b9b9069c0..51ea82e6c74 100755 --- a/applications/nfc/nfc_i.h +++ b/applications/nfc/nfc_i.h @@ -40,7 +40,7 @@ struct Nfc { NotificationApp* notifications; SceneManager* scene_manager; NfcDevice* dev; - NfcDeviceCommonData dev_edit_data; + FuriHalNfcDevData dev_edit_data; char text_store[NFC_TEXT_STORE_SIZE + 1]; string_t text_box_store; diff --git a/applications/nfc/nfc_types.c b/applications/nfc/nfc_types.c index 6cd424457e1..1b67284c404 100644 --- a/applications/nfc/nfc_types.c +++ b/applications/nfc/nfc_types.c @@ -1,48 +1,14 @@ #include "nfc_types.h" -const char* nfc_get_rfal_type(rfalNfcDevType type) { - if(type == RFAL_NFC_LISTEN_TYPE_NFCA) { +const char* nfc_get_dev_type(FuriHalNfcType type) { + if(type == FuriHalNfcTypeA) { return "NFC-A"; - } else if(type == RFAL_NFC_LISTEN_TYPE_NFCB) { + } else if(type == FuriHalNfcTypeB) { return "NFC-B"; - } else if(type == RFAL_NFC_LISTEN_TYPE_NFCF) { + } else if(type == FuriHalNfcTypeF) { return "NFC-F"; - } else if(type == RFAL_NFC_LISTEN_TYPE_NFCV) { + } else if(type == FuriHalNfcTypeV) { return "NFC-V"; - } else if(type == RFAL_NFC_LISTEN_TYPE_ST25TB) { - return "NFC-ST25TB"; - } else if(type == RFAL_NFC_LISTEN_TYPE_AP2P) { - return "NFC-AP2P"; - } else { - return "Unknown"; - } -} - -const char* nfc_get_dev_type(NfcDeviceType type) { - if(type == NfcDeviceNfca) { - return "NFC-A"; - } else if(type == NfcDeviceNfcb) { - return "NFC-B"; - } else if(type == NfcDeviceNfcf) { - return "NFC-F"; - } else if(type == NfcDeviceNfcv) { - return "NFC-V"; - } else { - return "Unknown"; - } -} - -const char* nfc_get_nfca_type(rfalNfcaListenDeviceType type) { - if(type == RFAL_NFCA_T1T) { - return "T1T"; - } else if(type == RFAL_NFCA_T2T) { - return "T2T"; - } else if(type == RFAL_NFCA_T4T) { - return "T4T"; - } else if(type == RFAL_NFCA_NFCDEP) { - return "NFCDEP"; - } else if(type == RFAL_NFCA_T4T_NFCDEP) { - return "T4T_NFCDEP"; } else { return "Unknown"; } diff --git a/applications/nfc/nfc_types.h b/applications/nfc/nfc_types.h index 267934d63d2..fb53ce7c25b 100644 --- a/applications/nfc/nfc_types.h +++ b/applications/nfc/nfc_types.h @@ -1,16 +1,8 @@ #pragma once -#include "st_errno.h" -#include "rfal_nfc.h" +#include "nfc_device.h" -#include -#include "nfc_worker.h" - -const char* nfc_get_rfal_type(rfalNfcDevType type); - -const char* nfc_get_dev_type(NfcDeviceType type); - -const char* nfc_get_nfca_type(rfalNfcaListenDeviceType type); +const char* nfc_get_dev_type(FuriHalNfcType type); const char* nfc_guess_protocol(NfcProtocol protocol); diff --git a/applications/nfc/nfc_worker.c b/applications/nfc/nfc_worker.c index a925a8d734d..132483943db 100644 --- a/applications/nfc/nfc_worker.c +++ b/applications/nfc/nfc_worker.c @@ -2,7 +2,8 @@ #include #include -#include +#include +#include #include #include #include @@ -94,22 +95,20 @@ int32_t nfc_worker_task(void* context) { nfc_worker_emulate(nfc_worker); } else if(nfc_worker->state == NfcWorkerStateReadEMVApp) { nfc_worker_read_emv_app(nfc_worker); - } else if(nfc_worker->state == NfcWorkerStateReadEMV) { + } else if(nfc_worker->state == NfcWorkerStateReadEMVData) { nfc_worker_read_emv(nfc_worker); } else if(nfc_worker->state == NfcWorkerStateEmulateApdu) { nfc_worker_emulate_apdu(nfc_worker); - } else if(nfc_worker->state == NfcWorkerStateReadMifareUl) { - nfc_worker_read_mifare_ul(nfc_worker); - } else if(nfc_worker->state == NfcWorkerStateEmulateMifareUl) { + } else if(nfc_worker->state == NfcWorkerStateReadMifareUltralight) { + nfc_worker_read_mifare_ultralight(nfc_worker); + } else if(nfc_worker->state == NfcWorkerStateEmulateMifareUltralight) { nfc_worker_emulate_mifare_ul(nfc_worker); } else if(nfc_worker->state == NfcWorkerStateReadMifareClassic) { nfc_worker_mifare_classic_dict_attack(nfc_worker); } else if(nfc_worker->state == NfcWorkerStateReadMifareDesfire) { nfc_worker_read_mifare_desfire(nfc_worker); - } else if(nfc_worker->state == NfcWorkerStateField) { - nfc_worker_field(nfc_worker); } - furi_hal_nfc_deactivate(); + furi_hal_nfc_sleep(); nfc_worker_change_state(nfc_worker, NfcWorkerStateReady); furi_hal_power_insomnia_exit(); @@ -117,579 +116,225 @@ int32_t nfc_worker_task(void* context) { } void nfc_worker_detect(NfcWorker* nfc_worker) { - rfalNfcDevice* dev_list; - rfalNfcDevice* dev; - uint8_t dev_cnt; nfc_device_data_clear(nfc_worker->dev_data); - NfcDeviceCommonData* result = &nfc_worker->dev_data->nfc_data; + NfcDeviceData* dev_data = nfc_worker->dev_data; + FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; while(nfc_worker->state == NfcWorkerStateDetect) { - if(furi_hal_nfc_detect(&dev_list, &dev_cnt, 1000, true)) { + if(furi_hal_nfc_detect(nfc_data, 1000)) { // Process first found device - dev = &dev_list[0]; - result->uid_len = dev->nfcidLen; - memcpy(result->uid, dev->nfcid, dev->nfcidLen); - if(dev->type == RFAL_NFC_LISTEN_TYPE_NFCA) { - result->device = NfcDeviceNfca; - result->atqa[0] = dev->dev.nfca.sensRes.anticollisionInfo; - result->atqa[1] = dev->dev.nfca.sensRes.platformInfo; - result->sak = dev->dev.nfca.selRes.sak; - if(mf_ul_check_card_type( - dev->dev.nfca.sensRes.anticollisionInfo, - dev->dev.nfca.sensRes.platformInfo, - dev->dev.nfca.selRes.sak)) { - result->protocol = NfcDeviceProtocolMifareUl; + if(nfc_data->type == FuriHalNfcTypeA) { + if(mf_ul_check_card_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) { + dev_data->protocol = NfcDeviceProtocolMifareUl; } else if(mf_classic_check_card_type( - dev->dev.nfca.sensRes.anticollisionInfo, - dev->dev.nfca.sensRes.platformInfo, - dev->dev.nfca.selRes.sak)) { - result->protocol = NfcDeviceProtocolMifareClassic; + nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) { + dev_data->protocol = NfcDeviceProtocolMifareClassic; } else if(mf_df_check_card_type( - dev->dev.nfca.sensRes.anticollisionInfo, - dev->dev.nfca.sensRes.platformInfo, - dev->dev.nfca.selRes.sak)) { - result->protocol = NfcDeviceProtocolMifareDesfire; - } else if(dev->rfInterface == RFAL_NFC_INTERFACE_ISODEP) { - result->protocol = NfcDeviceProtocolEMV; + nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) { + dev_data->protocol = NfcDeviceProtocolMifareDesfire; + } else if(nfc_data->interface == FuriHalNfcInterfaceIsoDep) { + dev_data->protocol = NfcDeviceProtocolEMV; } else { - result->protocol = NfcDeviceProtocolUnknown; + dev_data->protocol = NfcDeviceProtocolUnknown; } - } else if(dev->type == RFAL_NFC_LISTEN_TYPE_NFCB) { - result->device = NfcDeviceNfcb; - } else if(dev->type == RFAL_NFC_LISTEN_TYPE_NFCF) { - result->device = NfcDeviceNfcf; - } else if(dev->type == RFAL_NFC_LISTEN_TYPE_NFCV) { - result->device = NfcDeviceNfcv; } + // Notify caller and exit if(nfc_worker->callback) { nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); } break; } + furi_hal_nfc_sleep(); osDelay(100); } } -bool nfc_worker_emulate_uid_callback( - uint8_t* buff_rx, - uint16_t buff_rx_len, - uint8_t* buff_tx, - uint16_t* buff_tx_len, - uint32_t* data_type, - void* context) { - furi_assert(context); - NfcWorker* nfc_worker = context; +void nfc_worker_emulate(NfcWorker* nfc_worker) { + FuriHalNfcTxRxContext tx_rx = {}; + FuriHalNfcDevData* data = &nfc_worker->dev_data->nfc_data; NfcReaderRequestData* reader_data = &nfc_worker->dev_data->reader_data; - reader_data->size = buff_rx_len / 8; - if(reader_data->size > 0) { - memcpy(reader_data->data, buff_rx, reader_data->size); - if(nfc_worker->callback) { - nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); - } - } - return true; -} -void nfc_worker_emulate(NfcWorker* nfc_worker) { - NfcDeviceCommonData* data = &nfc_worker->dev_data->nfc_data; while(nfc_worker->state == NfcWorkerStateEmulate) { - furi_hal_nfc_emulate_nfca( - data->uid, - data->uid_len, - data->atqa, - data->sak, - nfc_worker_emulate_uid_callback, - nfc_worker, - 1000); + if(furi_hal_nfc_listen(data->uid, data->uid_len, data->atqa, data->sak, true, 100)) { + if(furi_hal_nfc_tx_rx(&tx_rx, 100)) { + reader_data->size = tx_rx.rx_bits / 8; + if(reader_data->size > 0) { + memcpy(reader_data->data, tx_rx.rx_data, reader_data->size); + if(nfc_worker->callback) { + nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); + } + } + } else { + FURI_LOG_E(TAG, "Failed to get reader commands"); + } + } } } void nfc_worker_read_emv_app(NfcWorker* nfc_worker) { - ReturnCode err; - rfalNfcDevice* dev_list; + FuriHalNfcTxRxContext tx_rx = {}; EmvApplication emv_app = {}; - uint8_t dev_cnt = 0; - uint8_t tx_buff[255] = {}; - uint16_t tx_len = 0; - uint8_t* rx_buff; - uint16_t* rx_len; NfcDeviceData* result = nfc_worker->dev_data; + FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; nfc_device_data_clear(result); while(nfc_worker->state == NfcWorkerStateReadEMVApp) { - memset(&emv_app, 0, sizeof(emv_app)); - if(furi_hal_nfc_detect(&dev_list, &dev_cnt, 1000, false)) { + if(furi_hal_nfc_detect(nfc_data, 1000)) { // Card was found. Check that it supports EMV - if(dev_list[0].rfInterface == RFAL_NFC_INTERFACE_ISODEP) { - result->nfc_data.uid_len = dev_list[0].dev.nfca.nfcId1Len; - result->nfc_data.atqa[0] = dev_list[0].dev.nfca.sensRes.anticollisionInfo; - result->nfc_data.atqa[1] = dev_list[0].dev.nfca.sensRes.platformInfo; - result->nfc_data.sak = dev_list[0].dev.nfca.selRes.sak; - memcpy( - result->nfc_data.uid, dev_list[0].dev.nfca.nfcId1, result->nfc_data.uid_len); - result->nfc_data.protocol = NfcDeviceProtocolEMV; - - FURI_LOG_D(TAG, "Send select PPSE command"); - tx_len = emv_prepare_select_ppse(tx_buff); - err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false); - if(err != ERR_NONE) { - FURI_LOG_D(TAG, "Error during selection PPSE request: %d", err); - furi_hal_nfc_deactivate(); - continue; - } - FURI_LOG_D(TAG, "Select PPSE response received. Start parsing response"); - if(emv_decode_ppse_response(rx_buff, *rx_len, &emv_app)) { - FURI_LOG_D(TAG, "Select PPSE responce parced"); + if(nfc_data->interface == FuriHalNfcInterfaceIsoDep) { + result->protocol = NfcDeviceProtocolEMV; + if(emv_search_application(&tx_rx, &emv_app)) { // Notify caller and exit result->emv_data.aid_len = emv_app.aid_len; memcpy(result->emv_data.aid, emv_app.aid, emv_app.aid_len); if(nfc_worker->callback) { nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); } - break; - } else { - FURI_LOG_D(TAG, "Can't find pay application"); - furi_hal_nfc_deactivate(); - continue; } } else { - // Can't find EMV card FURI_LOG_W(TAG, "Card doesn't support EMV"); - furi_hal_nfc_deactivate(); } } else { - // Can't find EMV card FURI_LOG_D(TAG, "Can't find any cards"); - furi_hal_nfc_deactivate(); } + furi_hal_nfc_sleep(); osDelay(20); } } void nfc_worker_read_emv(NfcWorker* nfc_worker) { - ReturnCode err; - rfalNfcDevice* dev_list; + FuriHalNfcTxRxContext tx_rx = {}; EmvApplication emv_app = {}; - uint8_t dev_cnt = 0; - uint8_t tx_buff[255] = {}; - uint16_t tx_len = 0; - uint8_t* rx_buff; - uint16_t* rx_len; NfcDeviceData* result = nfc_worker->dev_data; + FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; nfc_device_data_clear(result); - while(nfc_worker->state == NfcWorkerStateReadEMV) { - memset(&emv_app, 0, sizeof(emv_app)); - if(furi_hal_nfc_detect(&dev_list, &dev_cnt, 1000, false)) { + while(nfc_worker->state == NfcWorkerStateReadEMVData) { + if(furi_hal_nfc_detect(nfc_data, 1000)) { // Card was found. Check that it supports EMV - if(dev_list[0].rfInterface == RFAL_NFC_INTERFACE_ISODEP) { - result->nfc_data.uid_len = dev_list[0].dev.nfca.nfcId1Len; - result->nfc_data.atqa[0] = dev_list[0].dev.nfca.sensRes.anticollisionInfo; - result->nfc_data.atqa[1] = dev_list[0].dev.nfca.sensRes.platformInfo; - result->nfc_data.sak = dev_list[0].dev.nfca.selRes.sak; - memcpy( - result->nfc_data.uid, dev_list[0].dev.nfca.nfcId1, result->nfc_data.uid_len); - result->nfc_data.protocol = NfcDeviceProtocolEMV; - - FURI_LOG_D(TAG, "Send select PPSE command"); - tx_len = emv_prepare_select_ppse(tx_buff); - err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false); - if(err != ERR_NONE) { - FURI_LOG_D(TAG, "Error during selection PPSE request: %d", err); - furi_hal_nfc_deactivate(); - continue; - } - FURI_LOG_D(TAG, "Select PPSE response received. Start parsing response"); - if(emv_decode_ppse_response(rx_buff, *rx_len, &emv_app)) { - FURI_LOG_D(TAG, "Select PPSE responce parced"); + if(nfc_data->interface == FuriHalNfcInterfaceIsoDep) { + result->protocol = NfcDeviceProtocolEMV; + if(emv_read_bank_card(&tx_rx, &emv_app)) { + result->emv_data.number_len = emv_app.card_number_len; + memcpy( + result->emv_data.number, emv_app.card_number, result->emv_data.number_len); result->emv_data.aid_len = emv_app.aid_len; memcpy(result->emv_data.aid, emv_app.aid, emv_app.aid_len); - } else { - FURI_LOG_D(TAG, "Can't find pay application"); - furi_hal_nfc_deactivate(); - continue; - } - FURI_LOG_D(TAG, "Starting application ..."); - tx_len = emv_prepare_select_app(tx_buff, &emv_app); - err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false); - if(err != ERR_NONE) { - FURI_LOG_D(TAG, "Error during application selection request: %d", err); - furi_hal_nfc_deactivate(); - continue; - } - FURI_LOG_D(TAG, "Select application response received. Start parsing response"); - if(emv_decode_select_app_response(rx_buff, *rx_len, &emv_app)) { - FURI_LOG_D(TAG, "Card name: %s", emv_app.name); - memcpy(result->emv_data.name, emv_app.name, sizeof(emv_app.name)); - } else if(emv_app.pdol.size > 0) { - FURI_LOG_D(TAG, "Can't find card name, but PDOL is present."); - } else { - FURI_LOG_D(TAG, "Can't find card name or PDOL"); - furi_hal_nfc_deactivate(); - continue; - } - FURI_LOG_D(TAG, "Starting Get Processing Options command ..."); - tx_len = emv_prepare_get_proc_opt(tx_buff, &emv_app); - err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false); - if(err != ERR_NONE) { - FURI_LOG_D(TAG, "Error during Get Processing Options command: %d", err); - furi_hal_nfc_deactivate(); - continue; - } - if(emv_decode_get_proc_opt(rx_buff, *rx_len, &emv_app)) { - FURI_LOG_D(TAG, "Card number parsed"); - result->emv_data.number_len = emv_app.card_number_len; - memcpy(result->emv_data.number, emv_app.card_number, emv_app.card_number_len); + if(emv_app.name_found) { + memcpy(result->emv_data.name, emv_app.name, sizeof(emv_app.name)); + } + if(emv_app.exp_month) { + result->emv_data.exp_mon = emv_app.exp_month; + result->emv_data.exp_year = emv_app.exp_year; + } + if(emv_app.country_code) { + result->emv_data.country_code = emv_app.country_code; + } + if(emv_app.currency_code) { + result->emv_data.currency_code = emv_app.currency_code; + } // Notify caller and exit if(nfc_worker->callback) { nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); } break; - } else { - // Mastercard doesn't give PAN / card number as GPO response - // Iterate over all files found in application - bool pan_found = false; - for(uint8_t i = 0; (i < emv_app.afl.size) && !pan_found; i += 4) { - uint8_t sfi = emv_app.afl.data[i] >> 3; - uint8_t record_start = emv_app.afl.data[i + 1]; - uint8_t record_end = emv_app.afl.data[i + 2]; - - // Iterate over all records in file - for(uint8_t record = record_start; record <= record_end; ++record) { - tx_len = emv_prepare_read_sfi_record(tx_buff, sfi, record); - err = furi_hal_nfc_data_exchange( - tx_buff, tx_len, &rx_buff, &rx_len, false); - if(err != ERR_NONE) { - FURI_LOG_D( - TAG, - "Error reading application sfi %d, record %d", - sfi, - record); - } - if(emv_decode_read_sfi_record(rx_buff, *rx_len, &emv_app)) { - pan_found = true; - break; - } - } - } - if(pan_found) { - FURI_LOG_D(TAG, "Card PAN found"); - result->emv_data.number_len = emv_app.card_number_len; - memcpy( - result->emv_data.number, - emv_app.card_number, - result->emv_data.number_len); - if(emv_app.exp_month) { - result->emv_data.exp_mon = emv_app.exp_month; - result->emv_data.exp_year = emv_app.exp_year; - } - if(emv_app.country_code) { - result->emv_data.country_code = emv_app.country_code; - } - if(emv_app.currency_code) { - result->emv_data.currency_code = emv_app.currency_code; - } - // Notify caller and exit - if(nfc_worker->callback) { - nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); - } - break; - } else { - FURI_LOG_D(TAG, "Can't read card number"); - } - furi_hal_nfc_deactivate(); } } else { - // Can't find EMV card FURI_LOG_W(TAG, "Card doesn't support EMV"); - furi_hal_nfc_deactivate(); } } else { - // Can't find EMV card FURI_LOG_D(TAG, "Can't find any cards"); - furi_hal_nfc_deactivate(); } + furi_hal_nfc_sleep(); osDelay(20); } } void nfc_worker_emulate_apdu(NfcWorker* nfc_worker) { - ReturnCode err; - uint8_t tx_buff[255] = {}; - uint16_t tx_len = 0; - uint8_t* rx_buff; - uint16_t* rx_len; - NfcDeviceCommonData params = { + FuriHalNfcTxRxContext tx_rx = {}; + FuriHalNfcDevData params = { .uid = {0xCF, 0x72, 0xd4, 0x40}, .uid_len = 4, .atqa = {0x00, 0x04}, .sak = 0x20, - .device = NfcDeviceNfca, - .protocol = NfcDeviceProtocolEMV, + .type = FuriHalNfcTypeA, }; - // Test RX data - const uint8_t debug_rx[] = { - 0xba, 0x0b, 0xba, 0xba, 0x20, 0x00, 0x02, 0x28, 0xde, 0xad, 0xbe, 0xef, 0x00, 0xca, 0xca, - 0xca, 0xfe, 0xfa, 0xce, 0x14, 0x88, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, - 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0xba, - 0x0b, 0xba, 0xba, 0x20, 0x00, 0x02, 0x28, 0xde, 0xad, 0xbe, 0xef, 0x00, 0xca, 0xca, 0xca, - 0xfe, 0xfa, 0xce, 0x14, 0x88, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, - 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0xba, 0x0b, - 0xba, 0xba, 0x20, 0x00, 0x02, 0x28, 0xde, 0xad, 0xbe, 0xef, 0x00, 0xca, 0xca, 0xca, 0xfe, - 0xfa, 0xce, 0x14, 0x88, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, - 0xbb, 0xcc, 0xdd, 0xee, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0xba, 0x0b, 0xba, - 0xba, 0x20, 0x00, 0x02, 0x28, 0xde, 0xad, 0xbe, 0xef, 0x00, 0xca, 0xca, 0xca, 0xfe, 0xfa, - 0xce, 0x14, 0x88, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, - 0xcc, 0xdd, 0xee, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0xba, 0x0b, 0xba, 0xba, - 0x20, 0x00, 0x02, 0x28, 0xde, 0xad, 0xbe, 0xef, 0x00, 0xca, 0xca, 0xca, 0xfe, 0xfa, 0xce, - 0x14, 0x88, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, - 0xdd, 0xee, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0xba, 0x0b, 0xba, 0xba, 0x20, - 0x00, 0x02, 0x28, 0xde, 0xad, 0xbe, 0xef, 0x00, 0xca, 0xca, 0xca, 0xfe, 0xfa, 0xce, 0x14, - 0x88, 0x00}; - // Test TX data - const uint8_t debug_tx[] = { - 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xff, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, - 0x10, 0x14, 0x88, 0x02, 0x28, 0x00, 0x00, 0xca, 0xca, 0x00, 0xc0, 0xc0, 0x00, 0xde, 0xad, - 0xbe, 0xef, 0xce, 0xee, 0xec, 0xca, 0xfe, 0xba, 0xba, 0xb0, 0xb0, 0xac, 0xdc, 0x11, 0x12, - 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xff, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, - 0x14, 0x88, 0x02, 0x28, 0x00, 0x00, 0xca, 0xca, 0x00, 0xc0, 0xc0, 0x00, 0xde, 0xad, 0xbe, - 0xef, 0xce, 0xee, 0xec, 0xca, 0xfe, 0xba, 0xba, 0xb0, 0xb0, 0xac, 0xdc, 0x11, 0x12, 0x34, - 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xff, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x14, - 0x88, 0x02, 0x28, 0x00, 0x00, 0xca, 0xca, 0x00, 0xc0, 0xc0, 0x00, 0xde, 0xad, 0xbe, 0xef, - 0xce, 0xee, 0xec, 0xca, 0xfe, 0xba, 0xba, 0xb0, 0xb0, 0xac, 0xdc, 0x11, 0x12, 0x34, 0x56, - 0x78, 0x9a, 0xbc, 0xde, 0xff, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x14, 0x88, - 0x02, 0x28, 0x00, 0x00, 0xca, 0xca, 0x00, 0xc0, 0xc0, 0x00, 0xde, 0xad, 0xbe, 0xef, 0xce, - 0xee, 0xec, 0xca, 0xfe, 0xba, 0xba, 0xb0, 0xb0, 0xac, 0xdc, 0x11, 0x12, 0x34, 0x56, 0x78, - 0x9a, 0xbc, 0xde, 0xff, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x14, 0x88, 0x02, - 0x28, 0x00, 0x00, 0xca, 0xca, 0x00, 0xc0, 0xc0, 0x00, 0xde, 0xad, 0xbe, 0xef, 0xce, 0xee, - 0xec, 0xca, 0xfe, 0xba, 0xba, 0xb0, 0xb0, 0xac, 0xdc, 0x11, 0x12, 0x34, 0x56, 0x78, 0x9a, - 0xbc, 0xde, 0xff, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x14, 0x88, 0x02, 0x28, - 0x00, 0x00}; while(nfc_worker->state == NfcWorkerStateEmulateApdu) { if(furi_hal_nfc_listen(params.uid, params.uid_len, params.atqa, params.sak, false, 300)) { FURI_LOG_D(TAG, "POS terminal detected"); - // Read data from POS terminal - err = furi_hal_nfc_data_exchange(NULL, 0, &rx_buff, &rx_len, false); - if(err == ERR_NONE) { - FURI_LOG_D(TAG, "Received Select PPSE"); - } else { - FURI_LOG_D(TAG, "Error in 1st data exchange: select PPSE"); - furi_hal_nfc_deactivate(); - continue; + if(emv_card_emulation(&tx_rx)) { + FURI_LOG_D(TAG, "EMV card emulated"); } - FURI_LOG_D(TAG, "Transive SELECT PPSE ANS"); - tx_len = emv_select_ppse_ans(tx_buff); - err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false); - if(err == ERR_NONE) { - FURI_LOG_D(TAG, "Received Select APP"); - } else { - FURI_LOG_D(TAG, "Error in 2nd data exchange: select APP"); - furi_hal_nfc_deactivate(); - continue; - } - - FURI_LOG_D(TAG, "Transive SELECT APP ANS"); - tx_len = emv_select_app_ans(tx_buff); - err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false); - if(err == ERR_NONE) { - FURI_LOG_D(TAG, "Received PDOL"); - } else { - FURI_LOG_D(TAG, "Error in 3rd data exchange: receive PDOL"); - furi_hal_nfc_deactivate(); - continue; - } - - FURI_LOG_D(TAG, "Transive PDOL ANS"); - tx_len = emv_get_proc_opt_ans(tx_buff); - err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false); - if(err == ERR_NONE) { - FURI_LOG_D(TAG, "Transive PDOL ANS"); - } else { - FURI_LOG_D(TAG, "Error in 4rd data exchange: Transive PDOL ANS"); - furi_hal_nfc_deactivate(); - continue; - } - - if(*rx_len != sizeof(debug_rx) || memcmp(rx_buff, debug_rx, sizeof(debug_rx))) { - FURI_LOG_D(TAG, "Failed long message test"); - } else { - FURI_LOG_D(TAG, "Correct debug message received"); - tx_len = sizeof(debug_tx); - err = furi_hal_nfc_data_exchange( - (uint8_t*)debug_tx, tx_len, &rx_buff, &rx_len, false); - if(err == ERR_NONE) { - FURI_LOG_D(TAG, "Transive Debug message"); - } - } - furi_hal_nfc_deactivate(); } else { FURI_LOG_D(TAG, "Can't find reader"); } + furi_hal_nfc_sleep(); osDelay(20); } } -void nfc_worker_read_mifare_ul(NfcWorker* nfc_worker) { - ReturnCode err; - rfalNfcDevice* dev_list; - uint8_t dev_cnt = 0; - uint8_t tx_buff[255] = {}; - uint16_t tx_len = 0; - uint8_t* rx_buff; - uint16_t* rx_len; - MifareUlDevice mf_ul_read; +void nfc_worker_read_mifare_ultralight(NfcWorker* nfc_worker) { + FuriHalNfcTxRxContext tx_rx = {}; + MfUltralightReader reader = {}; + MfUltralightData data = {}; NfcDeviceData* result = nfc_worker->dev_data; - nfc_device_data_clear(result); - - while(nfc_worker->state == NfcWorkerStateReadMifareUl) { - furi_hal_nfc_deactivate(); - memset(&mf_ul_read, 0, sizeof(mf_ul_read)); - if(furi_hal_nfc_detect(&dev_list, &dev_cnt, 300, false)) { - if(dev_list[0].type == RFAL_NFC_LISTEN_TYPE_NFCA && - mf_ul_check_card_type( - dev_list[0].dev.nfca.sensRes.anticollisionInfo, - dev_list[0].dev.nfca.sensRes.platformInfo, - dev_list[0].dev.nfca.selRes.sak)) { - // Get Mifare Ultralight version - FURI_LOG_D(TAG, "Found Mifare Ultralight tag. Reading tag version"); - tx_len = mf_ul_prepare_get_version(tx_buff); - err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false); - if(err == ERR_NONE) { - mf_ul_parse_get_version_response(rx_buff, &mf_ul_read); - FURI_LOG_D( - TAG, - "Mifare Ultralight Type: %d, Pages: %d", - mf_ul_read.data.type, - mf_ul_read.pages_to_read); - FURI_LOG_D(TAG, "Reading signature ..."); - tx_len = mf_ul_prepare_read_signature(tx_buff); - if(furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false)) { - FURI_LOG_D(TAG, "Failed reading signature"); - memset(mf_ul_read.data.signature, 0, sizeof(mf_ul_read.data.signature)); - } else { - mf_ul_parse_read_signature_response(rx_buff, &mf_ul_read); - } - } else if(err == ERR_TIMEOUT) { - FURI_LOG_D( - TAG, - "Card doesn't respond to GET VERSION command. Setting default read parameters"); - err = ERR_NONE; - mf_ul_set_default_version(&mf_ul_read); - // Reinit device - furi_hal_nfc_deactivate(); - if(!furi_hal_nfc_detect(&dev_list, &dev_cnt, 300, false)) { - FURI_LOG_D(TAG, "Lost connection. Restarting search"); - continue; - } - } else { - FURI_LOG_D( - TAG, "Error getting Mifare Ultralight version. Error code: %d", err); - continue; - } - - if(mf_ul_read.support_fast_read) { - FURI_LOG_D(TAG, "Reading pages ..."); - tx_len = mf_ul_prepare_fast_read(tx_buff, 0x00, mf_ul_read.pages_to_read - 1); - if(furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false)) { - FURI_LOG_D(TAG, "Failed reading pages"); - continue; - } else { - mf_ul_parse_fast_read_response( - rx_buff, 0x00, mf_ul_read.pages_to_read - 1, &mf_ul_read); - } - - FURI_LOG_D(TAG, "Reading 3 counters ..."); - for(uint8_t i = 0; i < 3; i++) { - tx_len = mf_ul_prepare_read_cnt(tx_buff, i); - if(furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false)) { - FURI_LOG_W(TAG, "Failed reading Counter %d", i); - mf_ul_read.data.counter[i] = 0; - } else { - mf_ul_parse_read_cnt_response(rx_buff, i, &mf_ul_read); - } - } - - FURI_LOG_D(TAG, "Checking tearing flags ..."); - for(uint8_t i = 0; i < 3; i++) { - tx_len = mf_ul_prepare_check_tearing(tx_buff, i); - if(furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false)) { - FURI_LOG_D(TAG, "Error checking tearing flag %d", i); - mf_ul_read.data.tearing[i] = MF_UL_TEARING_FLAG_DEFAULT; - } else { - mf_ul_parse_check_tearing_response(rx_buff, i, &mf_ul_read); - } + FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; + + while(nfc_worker->state == NfcWorkerStateReadMifareUltralight) { + if(furi_hal_nfc_detect(nfc_data, 300)) { + if(nfc_data->type == FuriHalNfcTypeA && + mf_ul_check_card_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) { + FURI_LOG_D(TAG, "Found Mifare Ultralight tag. Start reading"); + if(mf_ul_read_card(&tx_rx, &reader, &data)) { + result->protocol = NfcDeviceProtocolMifareUl; + result->mf_ul_data = data; + // Notify caller and exit + if(nfc_worker->callback) { + nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); } + break; } else { - // READ card with READ command (4 pages at a time) - for(uint8_t page = 0; page < mf_ul_read.pages_to_read; page += 4) { - FURI_LOG_D(TAG, "Reading pages %d - %d ...", page, page + 3); - tx_len = mf_ul_prepare_read(tx_buff, page); - if(furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false)) { - FURI_LOG_D(TAG, "Read pages %d - %d failed", page, page + 3); - continue; - } else { - mf_ul_parse_read_response(rx_buff, page, &mf_ul_read); - } - } + FURI_LOG_D(TAG, "Failed reading Mifare Ultralight"); } - - // Fill result data - result->nfc_data.uid_len = dev_list[0].dev.nfca.nfcId1Len; - result->nfc_data.atqa[0] = dev_list[0].dev.nfca.sensRes.anticollisionInfo; - result->nfc_data.atqa[1] = dev_list[0].dev.nfca.sensRes.platformInfo; - result->nfc_data.sak = dev_list[0].dev.nfca.selRes.sak; - result->nfc_data.protocol = NfcDeviceProtocolMifareUl; - memcpy( - result->nfc_data.uid, dev_list[0].dev.nfca.nfcId1, result->nfc_data.uid_len); - result->mf_ul_data = mf_ul_read.data; - - // Notify caller and exit - if(nfc_worker->callback) { - nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); - } - break; } else { - FURI_LOG_W(TAG, "Tag does not support Mifare Ultralight"); + FURI_LOG_W(TAG, "Tag is not Mifare Ultralight"); } } else { FURI_LOG_D(TAG, "Can't find any tags"); } + furi_hal_nfc_sleep(); osDelay(100); } } void nfc_worker_emulate_mifare_ul(NfcWorker* nfc_worker) { - NfcDeviceCommonData* nfc_common = &nfc_worker->dev_data->nfc_data; - MifareUlDevice mf_ul_emulate; - mf_ul_prepare_emulation(&mf_ul_emulate, &nfc_worker->dev_data->mf_ul_data); - while(nfc_worker->state == NfcWorkerStateEmulateMifareUl) { + FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; + MfUltralightEmulator emulator = {}; + mf_ul_prepare_emulation(&emulator, &nfc_worker->dev_data->mf_ul_data); + while(nfc_worker->state == NfcWorkerStateEmulateMifareUltralight) { furi_hal_nfc_emulate_nfca( - nfc_common->uid, - nfc_common->uid_len, - nfc_common->atqa, - nfc_common->sak, + nfc_data->uid, + nfc_data->uid_len, + nfc_data->atqa, + nfc_data->sak, mf_ul_prepare_emulation_response, - &mf_ul_emulate, + &emulator, 5000); // Check if data was modified - if(mf_ul_emulate.data_changed) { - nfc_worker->dev_data->mf_ul_data = mf_ul_emulate.data; + if(emulator.data_changed) { + nfc_worker->dev_data->mf_ul_data = emulator.data; if(nfc_worker->callback) { nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); } - mf_ul_emulate.data_changed = false; + emulator.data_changed = false; } } } void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) { furi_assert(nfc_worker->callback); - rfalNfcDevice* dev_list; - rfalNfcDevice* dev; - NfcDeviceCommonData* nfc_common; - uint8_t dev_cnt = 0; FuriHalNfcTxRxContext tx_rx_ctx = {}; MfClassicAuthContext auth_ctx = {}; MfClassicReader reader = {}; @@ -697,6 +342,7 @@ void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) { uint16_t curr_sector = 0; uint8_t total_sectors = 0; NfcWorkerEvent event; + FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; // Open dictionary nfc_worker->dict_stream = file_stream_alloc(nfc_worker->storage); @@ -710,14 +356,13 @@ void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) { // Detect Mifare Classic card while(nfc_worker->state == NfcWorkerStateReadMifareClassic) { - if(furi_hal_nfc_detect(&dev_list, &dev_cnt, 300, false)) { - dev = &dev_list[0]; + if(furi_hal_nfc_detect(nfc_data, 300)) { if(mf_classic_get_type( - dev->nfcid, - dev->nfcidLen, - dev->dev.nfca.sensRes.anticollisionInfo, - dev->dev.nfca.sensRes.platformInfo, - dev->dev.nfca.selRes.sak, + nfc_data->uid, + nfc_data->uid_len, + nfc_data->atqa[0], + nfc_data->atqa[1], + nfc_data->sak, &reader)) { total_sectors = mf_classic_get_total_sectors_num(&reader); if(reader.type == MfClassicType1k) { @@ -745,7 +390,7 @@ void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) { mf_classic_auth_init_context(&auth_ctx, reader.cuid, curr_sector); bool sector_key_found = false; while(nfc_mf_classic_dict_get_next_key(nfc_worker->dict_stream, &curr_key)) { - furi_hal_nfc_deactivate(); + furi_hal_nfc_sleep(); if(furi_hal_nfc_activate_nfca(300, &reader.cuid)) { if(!card_found_notified) { if(reader.type == MfClassicType1k) { @@ -817,15 +462,8 @@ void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) { uint8_t sectors_read = mf_classic_read_card(&tx_rx_ctx, &reader, &nfc_worker->dev_data->mf_classic_data); if(sectors_read) { - dev = &dev_list[0]; - nfc_common = &nfc_worker->dev_data->nfc_data; - nfc_common->uid_len = dev->dev.nfca.nfcId1Len; - nfc_common->atqa[0] = dev->dev.nfca.sensRes.anticollisionInfo; - nfc_common->atqa[1] = dev->dev.nfca.sensRes.platformInfo; - nfc_common->sak = dev->dev.nfca.selRes.sak; - nfc_common->protocol = NfcDeviceProtocolMifareClassic; - memcpy(nfc_common->uid, dev->dev.nfca.nfcId1, nfc_common->uid_len); event = NfcWorkerEventSuccess; + nfc_worker->dev_data->protocol = NfcDeviceProtocolMifareClassic; FURI_LOG_I(TAG, "Successfully read %d sectors", sectors_read); } else { event = NfcWorkerEventFail; @@ -838,42 +476,8 @@ void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) { stream_free(nfc_worker->dict_stream); } -ReturnCode nfc_exchange_full( - uint8_t* tx_buff, - uint16_t tx_len, - uint8_t* rx_buff, - uint16_t rx_cap, - uint16_t* rx_len) { - ReturnCode err; - uint8_t* part_buff; - uint16_t* part_len; - - err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &part_buff, &part_len, false); - if(*part_len > rx_cap) { - return ERR_OVERRUN; - } - memcpy(rx_buff, part_buff, *part_len); - *rx_len = *part_len; - while(err == ERR_NONE && rx_buff[0] == 0xAF) { - err = furi_hal_nfc_data_exchange(rx_buff, 1, &part_buff, &part_len, false); - if(*part_len > rx_cap - *rx_len) { - return ERR_OVERRUN; - } - if(*part_len == 0) { - return ERR_PROTO; - } - memcpy(rx_buff + *rx_len, part_buff + 1, *part_len - 1); - *rx_buff = *part_buff; - *rx_len += *part_len - 1; - } - - return err; -} - void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) { ReturnCode err; - rfalNfcDevice* dev_list; - uint8_t dev_cnt = 0; uint8_t tx_buff[64] = {}; uint16_t tx_len = 0; uint8_t rx_buff[512] = {}; @@ -881,19 +485,17 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) { NfcDeviceData* result = nfc_worker->dev_data; nfc_device_data_clear(result); MifareDesfireData* data = &result->mf_df_data; + FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data; while(nfc_worker->state == NfcWorkerStateReadMifareDesfire) { - furi_hal_nfc_deactivate(); - if(!furi_hal_nfc_detect(&dev_list, &dev_cnt, 300, false)) { + furi_hal_nfc_sleep(); + if(!furi_hal_nfc_detect(nfc_data, 300)) { osDelay(100); continue; } memset(data, 0, sizeof(MifareDesfireData)); - if(dev_list[0].type != RFAL_NFC_LISTEN_TYPE_NFCA || - !mf_df_check_card_type( - dev_list[0].dev.nfca.sensRes.anticollisionInfo, - dev_list[0].dev.nfca.sensRes.platformInfo, - dev_list[0].dev.nfca.selRes.sak)) { + if(nfc_data->type != FuriHalNfcTypeA || + !mf_df_check_card_type(nfc_data->atqa[0], nfc_data->atqa[1], nfc_data->sak)) { FURI_LOG_D(TAG, "Tag is not DESFire"); osDelay(100); continue; @@ -901,18 +503,11 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) { FURI_LOG_D(TAG, "Found DESFire tag"); - // Fill non-DESFire result data - result->nfc_data.uid_len = dev_list[0].dev.nfca.nfcId1Len; - result->nfc_data.atqa[0] = dev_list[0].dev.nfca.sensRes.anticollisionInfo; - result->nfc_data.atqa[1] = dev_list[0].dev.nfca.sensRes.platformInfo; - result->nfc_data.sak = dev_list[0].dev.nfca.selRes.sak; - result->nfc_data.device = NfcDeviceNfca; - result->nfc_data.protocol = NfcDeviceProtocolMifareDesfire; - memcpy(result->nfc_data.uid, dev_list[0].dev.nfca.nfcId1, result->nfc_data.uid_len); + result->protocol = NfcDeviceProtocolMifareDesfire; // Get DESFire version tx_len = mf_df_prepare_get_version(tx_buff); - err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); + err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); if(err != ERR_NONE) { FURI_LOG_W(TAG, "Bad exchange getting version, err: %d", err); continue; @@ -923,7 +518,7 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) { } tx_len = mf_df_prepare_get_free_memory(tx_buff); - err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); + err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); if(err == ERR_NONE) { data->free_memory = malloc(sizeof(MifareDesfireFreeMemory)); memset(data->free_memory, 0, sizeof(MifareDesfireFreeMemory)); @@ -935,7 +530,7 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) { } tx_len = mf_df_prepare_get_key_settings(tx_buff); - err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); + err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); if(err != ERR_NONE) { FURI_LOG_D(TAG, "Bad exchange getting key settings, err: %d", err); } else { @@ -951,7 +546,8 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) { &data->master_key_settings->key_version_head; for(uint8_t key_id = 0; key_id < data->master_key_settings->max_keys; key_id++) { tx_len = mf_df_prepare_get_key_version(tx_buff, key_id); - err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); + err = + furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); if(err != ERR_NONE) { FURI_LOG_W(TAG, "Bad exchange getting key version, err: %d", err); continue; @@ -970,7 +566,7 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) { } tx_len = mf_df_prepare_get_application_ids(tx_buff); - err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); + err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); if(err != ERR_NONE) { FURI_LOG_W(TAG, "Bad exchange getting application IDs, err: %d", err); } else { @@ -981,13 +577,13 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) { for(MifareDesfireApplication* app = data->app_head; app; app = app->next) { tx_len = mf_df_prepare_select_application(tx_buff, app->id); - err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); + err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); if(!mf_df_parse_select_application_response(rx_buff, rx_len)) { FURI_LOG_W(TAG, "Bad exchange selecting application, err: %d", err); continue; } tx_len = mf_df_prepare_get_key_settings(tx_buff); - err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); + err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); if(err != ERR_NONE) { FURI_LOG_W(TAG, "Bad exchange getting key settings, err: %d", err); } else { @@ -1002,7 +598,8 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) { MifareDesfireKeyVersion** key_version_head = &app->key_settings->key_version_head; for(uint8_t key_id = 0; key_id < app->key_settings->max_keys; key_id++) { tx_len = mf_df_prepare_get_key_version(tx_buff, key_id); - err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); + err = furi_hal_nfc_exchange_full( + tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); if(err != ERR_NONE) { FURI_LOG_W(TAG, "Bad exchange getting key version, err: %d", err); continue; @@ -1021,7 +618,7 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) { } tx_len = mf_df_prepare_get_file_ids(tx_buff); - err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); + err = furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); if(err != ERR_NONE) { FURI_LOG_W(TAG, "Bad exchange getting file IDs, err: %d", err); } else { @@ -1032,7 +629,8 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) { for(MifareDesfireFile* file = app->file_head; file; file = file->next) { tx_len = mf_df_prepare_get_file_settings(tx_buff, file->id); - err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); + err = + furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); if(err != ERR_NONE) { FURI_LOG_W(TAG, "Bad exchange getting file settings, err: %d", err); continue; @@ -1054,7 +652,8 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) { tx_len = mf_df_prepare_read_records(tx_buff, file->id, 0, 0); break; } - err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); + err = + furi_hal_nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); if(err != ERR_NONE) { FURI_LOG_W(TAG, "Bad exchange reading file %d, err: %d", file->id, err); continue; @@ -1073,11 +672,3 @@ void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) { break; } } - -void nfc_worker_field(NfcWorker* nfc_worker) { - furi_hal_nfc_field_on(); - while(nfc_worker->state == NfcWorkerStateField) { - osDelay(50); - } - furi_hal_nfc_field_off(); -} diff --git a/applications/nfc/nfc_worker.h b/applications/nfc/nfc_worker.h index a0a5ae83d64..1933a79b7fe 100755 --- a/applications/nfc/nfc_worker.h +++ b/applications/nfc/nfc_worker.h @@ -13,11 +13,11 @@ typedef enum { NfcWorkerStateDetect, NfcWorkerStateEmulate, NfcWorkerStateReadEMVApp, - NfcWorkerStateReadEMV, + NfcWorkerStateReadEMVData, NfcWorkerStateEmulateApdu, NfcWorkerStateField, - NfcWorkerStateReadMifareUl, - NfcWorkerStateEmulateMifareUl, + NfcWorkerStateReadMifareUltralight, + NfcWorkerStateEmulateMifareUltralight, NfcWorkerStateReadMifareClassic, NfcWorkerStateReadMifareDesfire, // Transition diff --git a/applications/nfc/nfc_worker_i.h b/applications/nfc/nfc_worker_i.h index bba983fc420..a6f937f7d50 100755 --- a/applications/nfc/nfc_worker_i.h +++ b/applications/nfc/nfc_worker_i.h @@ -4,19 +4,8 @@ #include "nfc_worker.h" #include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include - struct NfcWorker { FuriThread* thread; Storage* storage; @@ -44,9 +33,7 @@ void nfc_worker_detect(NfcWorker* nfc_worker); void nfc_worker_emulate(NfcWorker* nfc_worker); -void nfc_worker_field(NfcWorker* nfc_worker); - -void nfc_worker_read_mifare_ul(NfcWorker* nfc_worker); +void nfc_worker_read_mifare_ultralight(NfcWorker* nfc_worker); void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker); diff --git a/applications/nfc/scenes/nfc_scene_card_menu.c b/applications/nfc/scenes/nfc_scene_card_menu.c index 03497958d8b..b78624097d4 100755 --- a/applications/nfc/scenes/nfc_scene_card_menu.c +++ b/applications/nfc/scenes/nfc_scene_card_menu.c @@ -17,7 +17,7 @@ void nfc_scene_card_menu_on_enter(void* context) { Nfc* nfc = context; Submenu* submenu = nfc->submenu; - if(nfc->dev->dev_data.nfc_data.protocol > NfcDeviceProtocolUnknown) { + if(nfc->dev->dev_data.protocol > NfcDeviceProtocolUnknown) { submenu_add_item( submenu, "Run Compatible App", @@ -49,13 +49,13 @@ bool nfc_scene_card_menu_on_event(void* context, SceneManagerEvent event) { if(event.event == SubmenuIndexRunApp) { scene_manager_set_scene_state( nfc->scene_manager, NfcSceneCardMenu, SubmenuIndexRunApp); - if(nfc->dev->dev_data.nfc_data.protocol == NfcDeviceProtocolMifareUl) { + if(nfc->dev->dev_data.protocol == NfcDeviceProtocolMifareUl) { scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareUl); - } else if(nfc->dev->dev_data.nfc_data.protocol == NfcDeviceProtocolMifareDesfire) { + } else if(nfc->dev->dev_data.protocol == NfcDeviceProtocolMifareDesfire) { scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareDesfire); - } else if(nfc->dev->dev_data.nfc_data.protocol == NfcDeviceProtocolEMV) { + } else if(nfc->dev->dev_data.protocol == NfcDeviceProtocolEMV) { scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvApp); - } else if(nfc->dev->dev_data.nfc_data.protocol == NfcDeviceProtocolMifareClassic) { + } else if(nfc->dev->dev_data.protocol == NfcDeviceProtocolMifareClassic) { scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareClassic); } consumed = true; diff --git a/applications/nfc/scenes/nfc_scene_config.h b/applications/nfc/scenes/nfc_scene_config.h index c66725b95cb..6b5d5d10c6f 100755 --- a/applications/nfc/scenes/nfc_scene_config.h +++ b/applications/nfc/scenes/nfc_scene_config.h @@ -2,7 +2,6 @@ ADD_SCENE(nfc, start, Start) ADD_SCENE(nfc, read_card, ReadCard) ADD_SCENE(nfc, read_card_success, ReadCardSuccess) ADD_SCENE(nfc, card_menu, CardMenu) -ADD_SCENE(nfc, not_implemented, NotImplemented) ADD_SCENE(nfc, emulate_uid, EmulateUid) ADD_SCENE(nfc, save_name, SaveName) ADD_SCENE(nfc, save_success, SaveSuccess) diff --git a/applications/nfc/scenes/nfc_scene_debug.c b/applications/nfc/scenes/nfc_scene_debug.c index a8f1e686f8f..ed079c2ed9a 100644 --- a/applications/nfc/scenes/nfc_scene_debug.c +++ b/applications/nfc/scenes/nfc_scene_debug.c @@ -6,13 +6,13 @@ enum SubmenuDebugIndex { }; void nfc_scene_debug_submenu_callback(void* context, uint32_t index) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_debug_on_enter(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; Submenu* submenu = nfc->submenu; submenu_add_item( @@ -28,7 +28,7 @@ void nfc_scene_debug_on_enter(void* context) { } bool nfc_scene_debug_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -48,7 +48,7 @@ bool nfc_scene_debug_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_debug_on_exit(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; submenu_reset(nfc->submenu); } diff --git a/applications/nfc/scenes/nfc_scene_delete.c b/applications/nfc/scenes/nfc_scene_delete.c index 2661d1667dc..e8ba3e440f0 100755 --- a/applications/nfc/scenes/nfc_scene_delete.c +++ b/applications/nfc/scenes/nfc_scene_delete.c @@ -1,29 +1,29 @@ #include "../nfc_i.h" void nfc_scene_delete_widget_callback(GuiButtonType result, InputType type, void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } } void nfc_scene_delete_on_enter(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; // Setup Custom Widget view - char delete_str[64]; - snprintf(delete_str, sizeof(delete_str), "\e#Delete %s?\e#", nfc->dev->dev_name); - widget_add_text_box_element(nfc->widget, 0, 0, 128, 23, AlignCenter, AlignCenter, delete_str); + char temp_str[64]; + snprintf(temp_str, sizeof(temp_str), "\e#Delete %s?\e#", nfc->dev->dev_name); + widget_add_text_box_element( + nfc->widget, 0, 0, 128, 23, AlignCenter, AlignCenter, temp_str, false); widget_add_button_element( nfc->widget, GuiButtonTypeLeft, "Back", nfc_scene_delete_widget_callback, nfc); widget_add_button_element( nfc->widget, GuiButtonTypeRight, "Delete", nfc_scene_delete_widget_callback, nfc); - char uid_str[32]; - NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data; + FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; if(data->uid_len == 4) { snprintf( - uid_str, - sizeof(uid_str), + temp_str, + sizeof(temp_str), "UID: %02X %02X %02X %02X", data->uid[0], data->uid[1], @@ -31,8 +31,8 @@ void nfc_scene_delete_on_enter(void* context) { data->uid[3]); } else if(data->uid_len == 7) { snprintf( - uid_str, - sizeof(uid_str), + temp_str, + sizeof(temp_str), "UID: %02X %02X %02X %02X %02X %02X %02X", data->uid[0], data->uid[1], @@ -42,12 +42,13 @@ void nfc_scene_delete_on_enter(void* context) { data->uid[5], data->uid[6]); } - widget_add_string_element(nfc->widget, 64, 23, AlignCenter, AlignTop, FontSecondary, uid_str); + widget_add_string_element(nfc->widget, 64, 23, AlignCenter, AlignTop, FontSecondary, temp_str); const char* protocol_name = NULL; - if(data->protocol == NfcDeviceProtocolEMV) { - protocol_name = nfc_guess_protocol(data->protocol); - } else if(data->protocol == NfcDeviceProtocolMifareUl) { + NfcProtocol protocol = nfc->dev->dev_data.protocol; + if(protocol == NfcDeviceProtocolEMV) { + protocol_name = nfc_guess_protocol(protocol); + } else if(protocol == NfcDeviceProtocolMifareUl) { protocol_name = nfc_mf_ul_type(nfc->dev->dev_data.mf_ul_data.type, false); } if(protocol_name) { @@ -56,18 +57,17 @@ void nfc_scene_delete_on_enter(void* context) { } // TODO change dinamically widget_add_string_element(nfc->widget, 118, 33, AlignRight, AlignTop, FontSecondary, "NFC-A"); - char sak_str[16]; - snprintf(sak_str, sizeof(sak_str), "SAK: %02X", data->sak); - widget_add_string_element(nfc->widget, 10, 43, AlignLeft, AlignTop, FontSecondary, sak_str); - char atqa_str[16]; - snprintf(atqa_str, sizeof(atqa_str), "ATQA: %02X%02X", data->atqa[0], data->atqa[1]); - widget_add_string_element(nfc->widget, 118, 43, AlignRight, AlignTop, FontSecondary, atqa_str); + snprintf(temp_str, sizeof(temp_str), "SAK: %02X", data->sak); + widget_add_string_element(nfc->widget, 10, 43, AlignLeft, AlignTop, FontSecondary, temp_str); + snprintf(temp_str, sizeof(temp_str), "ATQA: %02X%02X", data->atqa[0], data->atqa[1]); + widget_add_string_element(nfc->widget, 118, 43, AlignRight, AlignTop, FontSecondary, temp_str); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); } bool nfc_scene_delete_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; + bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { if(event.event == GuiButtonTypeLeft) { @@ -79,14 +79,14 @@ bool nfc_scene_delete_on_event(void* context, SceneManagerEvent event) { scene_manager_search_and_switch_to_previous_scene( nfc->scene_manager, NfcSceneStart); } - return true; + consumed = true; } } - return false; + return consumed; } void nfc_scene_delete_on_exit(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; widget_reset(nfc->widget); } diff --git a/applications/nfc/scenes/nfc_scene_delete_success.c b/applications/nfc/scenes/nfc_scene_delete_success.c index 1392fa9e09d..a52c40d867e 100755 --- a/applications/nfc/scenes/nfc_scene_delete_success.c +++ b/applications/nfc/scenes/nfc_scene_delete_success.c @@ -1,12 +1,12 @@ #include "../nfc_i.h" void nfc_scene_delete_success_popup_callback(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); } void nfc_scene_delete_success_on_enter(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; // Setup view Popup* popup = nfc->popup; @@ -20,27 +20,21 @@ void nfc_scene_delete_success_on_enter(void* context) { } bool nfc_scene_delete_success_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; + bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { if(event.event == NfcCustomEventViewExit) { - return scene_manager_search_and_switch_to_previous_scene( + consumed = scene_manager_search_and_switch_to_previous_scene( nfc->scene_manager, NfcSceneStart); } } - return false; + return consumed; } void nfc_scene_delete_success_on_exit(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; // Clear view - Popup* popup = nfc->popup; - popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom); - popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop); - popup_set_icon(popup, 0, 0, NULL); - popup_set_callback(popup, NULL); - popup_set_context(popup, NULL); - popup_set_timeout(popup, 0); - popup_disable_timeout(popup); -} + popup_reset(nfc->popup); +} \ No newline at end of file diff --git a/applications/nfc/scenes/nfc_scene_device_info.c b/applications/nfc/scenes/nfc_scene_device_info.c index d408e555df8..10851e860b9 100644 --- a/applications/nfc/scenes/nfc_scene_device_info.c +++ b/applications/nfc/scenes/nfc_scene_device_info.c @@ -36,19 +36,19 @@ void nfc_scene_device_info_on_enter(void* context) { (nfc->dev->format == NfcDeviceSaveFormatBankCard); // Setup Custom Widget view widget_add_text_box_element( - nfc->widget, 0, 0, 128, 22, AlignCenter, AlignTop, nfc->dev->dev_name); + nfc->widget, 0, 0, 128, 22, AlignCenter, AlignTop, nfc->dev->dev_name, false); widget_add_button_element( nfc->widget, GuiButtonTypeLeft, "Back", nfc_scene_device_info_widget_callback, nfc); if(data_display_supported) { widget_add_button_element( nfc->widget, GuiButtonTypeRight, "Data", nfc_scene_device_info_widget_callback, nfc); } - char uid_str[32]; - NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data; + char temp_str[32]; + FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; if(data->uid_len == 4) { snprintf( - uid_str, - sizeof(uid_str), + temp_str, + sizeof(temp_str), "UID: %02X %02X %02X %02X", data->uid[0], data->uid[1], @@ -56,8 +56,8 @@ void nfc_scene_device_info_on_enter(void* context) { data->uid[3]); } else if(data->uid_len == 7) { snprintf( - uid_str, - sizeof(uid_str), + temp_str, + sizeof(temp_str), "UID: %02X %02X %02X %02X %02X %02X %02X", data->uid[0], data->uid[1], @@ -67,15 +67,15 @@ void nfc_scene_device_info_on_enter(void* context) { data->uid[5], data->uid[6]); } - widget_add_string_element(nfc->widget, 64, 21, AlignCenter, AlignTop, FontSecondary, uid_str); + widget_add_string_element(nfc->widget, 64, 21, AlignCenter, AlignTop, FontSecondary, temp_str); const char* protocol_name = NULL; - if(data->protocol == NfcDeviceProtocolEMV || - data->protocol == NfcDeviceProtocolMifareDesfire) { - protocol_name = nfc_guess_protocol(data->protocol); - } else if(data->protocol == NfcDeviceProtocolMifareUl) { + NfcProtocol protocol = nfc->dev->dev_data.protocol; + if(protocol == NfcDeviceProtocolEMV || protocol == NfcDeviceProtocolMifareDesfire) { + protocol_name = nfc_guess_protocol(protocol); + } else if(protocol == NfcDeviceProtocolMifareUl) { protocol_name = nfc_mf_ul_type(nfc->dev->dev_data.mf_ul_data.type, false); - } else if(data->protocol == NfcDeviceProtocolMifareClassic) { + } else if(protocol == NfcDeviceProtocolMifareClassic) { protocol_name = nfc_mf_classic_type(nfc->dev->dev_data.mf_classic_data.type); } if(protocol_name) { @@ -84,12 +84,10 @@ void nfc_scene_device_info_on_enter(void* context) { } // TODO change dinamically widget_add_string_element(nfc->widget, 118, 32, AlignRight, AlignTop, FontSecondary, "NFC-A"); - char sak_str[16]; - snprintf(sak_str, sizeof(sak_str), "SAK: %02X", data->sak); - widget_add_string_element(nfc->widget, 10, 42, AlignLeft, AlignTop, FontSecondary, sak_str); - char atqa_str[16]; - snprintf(atqa_str, sizeof(atqa_str), "ATQA: %02X%02X", data->atqa[0], data->atqa[1]); - widget_add_string_element(nfc->widget, 118, 42, AlignRight, AlignTop, FontSecondary, atqa_str); + snprintf(temp_str, sizeof(temp_str), "SAK: %02X", data->sak); + widget_add_string_element(nfc->widget, 10, 42, AlignLeft, AlignTop, FontSecondary, temp_str); + snprintf(temp_str, sizeof(temp_str), "ATQA: %02X%02X", data->atqa[0], data->atqa[1]); + widget_add_string_element(nfc->widget, 118, 42, AlignRight, AlignTop, FontSecondary, temp_str); // Setup Data View if(nfc->dev->format == NfcDeviceSaveFormatUid) { @@ -99,7 +97,7 @@ void nfc_scene_device_info_on_enter(void* context) { dialog_ex_set_context(dialog_ex, nfc); dialog_ex_set_result_callback(dialog_ex, nfc_scene_device_info_dialog_callback); } else if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { - MifareUlData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data; + MfUltralightData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data; TextBox* text_box = nfc->text_box; text_box_set_font(text_box, TextBoxFontHex); for(uint16_t i = 0; i < mf_ul_data->data_size; i += 2) { @@ -130,7 +128,7 @@ void nfc_scene_device_info_on_enter(void* context) { widget_add_string_element( nfc->widget, 64, 17, AlignCenter, AlignBottom, FontSecondary, nfc->text_store); } else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) { - NfcEmvData* emv_data = &nfc->dev->dev_data.emv_data; + EmvData* emv_data = &nfc->dev->dev_data.emv_data; BankCard* bank_card = nfc->bank_card; bank_card_set_name(bank_card, emv_data->name); bank_card_set_number(bank_card, emv_data->number, emv_data->number_len); @@ -212,21 +210,16 @@ bool nfc_scene_device_info_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_device_info_on_exit(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; - // Clear Custom Widget + // Clear views widget_reset(nfc->widget); - if(nfc->dev->format == NfcDeviceSaveFormatUid) { - // Clear Dialog - DialogEx* dialog_ex = nfc->dialog_ex; - dialog_ex_reset(dialog_ex); + dialog_ex_reset(nfc->dialog_ex); } else if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { - // Clear TextBox text_box_reset(nfc->text_box); string_reset(nfc->text_box_store); } else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) { - // Clear Bank Card bank_card_clear(nfc->bank_card); } } diff --git a/applications/nfc/scenes/nfc_scene_emulate_apdu_sequence.c b/applications/nfc/scenes/nfc_scene_emulate_apdu_sequence.c index 1a87ea58305..4f9626e9bd2 100644 --- a/applications/nfc/scenes/nfc_scene_emulate_apdu_sequence.c +++ b/applications/nfc/scenes/nfc_scene_emulate_apdu_sequence.c @@ -1,36 +1,34 @@ #include "../nfc_i.h" void nfc_scene_emulate_apdu_sequence_on_enter(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; // Setup view Popup* popup = nfc->popup; - popup_set_header(popup, "Run APDU reader", 64, 31, AlignCenter, AlignTop); // Setup and start worker - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); nfc_worker_start(nfc->worker, NfcWorkerStateEmulateApdu, &nfc->dev->dev_data, NULL, nfc); } bool nfc_scene_emulate_apdu_sequence_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; + bool consumed = false; if(event.type == SceneManagerEventTypeTick) { notification_message(nfc->notifications, &sequence_blink_blue_10); - return true; + consumed = true; } - return false; + + return consumed; } void nfc_scene_emulate_apdu_sequence_on_exit(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; // Stop worker nfc_worker_stop(nfc->worker); - // Clear view - Popup* popup = nfc->popup; - popup_reset(popup); + popup_reset(nfc->popup); } diff --git a/applications/nfc/scenes/nfc_scene_emulate_mifare_ul.c b/applications/nfc/scenes/nfc_scene_emulate_mifare_ul.c index 68225f33f85..871ca636432 100755 --- a/applications/nfc/scenes/nfc_scene_emulate_mifare_ul.c +++ b/applications/nfc/scenes/nfc_scene_emulate_mifare_ul.c @@ -5,13 +5,14 @@ #define NFC_MF_UL_DATA_CHANGED (1UL) void nfc_emulate_mifare_ul_worker_callback(NfcWorkerEvent event, void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; + scene_manager_set_scene_state( nfc->scene_manager, NfcSceneEmulateMifareUl, NFC_MF_UL_DATA_CHANGED); } void nfc_scene_emulate_mifare_ul_on_enter(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; DOLPHIN_DEED(DolphinDeedNfcEmulate); // Setup view @@ -26,14 +27,14 @@ void nfc_scene_emulate_mifare_ul_on_enter(void* context) { view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); nfc_worker_start( nfc->worker, - NfcWorkerStateEmulateMifareUl, + NfcWorkerStateEmulateMifareUltralight, &nfc->dev->dev_data, nfc_emulate_mifare_ul_worker_callback, nfc); } bool nfc_scene_emulate_mifare_ul_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeTick) { @@ -55,11 +56,8 @@ bool nfc_scene_emulate_mifare_ul_on_event(void* context, SceneManagerEvent event } void nfc_scene_emulate_mifare_ul_on_exit(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; // Clear view - Popup* popup = nfc->popup; - popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom); - popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop); - popup_set_icon(popup, 0, 0, NULL); + popup_reset(nfc->popup); } diff --git a/applications/nfc/scenes/nfc_scene_emulate_uid.c b/applications/nfc/scenes/nfc_scene_emulate_uid.c index 027a325de41..58ac138e7ef 100755 --- a/applications/nfc/scenes/nfc_scene_emulate_uid.c +++ b/applications/nfc/scenes/nfc_scene_emulate_uid.c @@ -1,6 +1,8 @@ #include "../nfc_i.h" #include +#define NFC_SCENE_EMULATE_UID_LOG_SIZE_MAX (200) + enum { NfcSceneEmulateUidStateWidget, NfcSceneEmulateUidStateTextBox, @@ -28,14 +30,14 @@ void nfc_emulate_uid_textbox_callback(void* context) { // Add widget with device name or inform that data received static void nfc_scene_emulate_uid_widget_config(Nfc* nfc, bool data_received) { - NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data; + FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; Widget* widget = nfc->widget; widget_reset(widget); string_t info_str; string_init(info_str); widget_add_icon_element(widget, 0, 3, &I_RFIDDolphinSend_97x61); - widget_add_string_element(widget, 56, 32, AlignLeft, AlignTop, FontPrimary, "Emulating UID"); + widget_add_string_element(widget, 89, 32, AlignCenter, AlignTop, FontPrimary, "Emulating UID"); if(strcmp(nfc->dev->dev_name, "")) { string_printf(info_str, "%s", nfc->dev->dev_name); } else { @@ -45,7 +47,7 @@ static void nfc_scene_emulate_uid_widget_config(Nfc* nfc, bool data_received) { } string_strim(info_str); widget_add_text_box_element( - widget, 56, 43, 70, 21, AlignLeft, AlignTop, string_get_cstr(info_str)); + widget, 56, 43, 70, 21, AlignCenter, AlignTop, string_get_cstr(info_str), true); string_clear(info_str); if(data_received) { widget_add_button_element( @@ -95,13 +97,15 @@ bool nfc_scene_emulate_uid_on_event(void* context, SceneManagerEvent event) { nfc_scene_emulate_uid_widget_config(nfc, true); } // Update TextBox data - string_cat_printf(nfc->text_box_store, "R:"); - for(uint16_t i = 0; i < reader_data->size; i++) { - string_cat_printf(nfc->text_box_store, " %02X", reader_data->data[i]); + if(string_size(nfc->text_box_store) < NFC_SCENE_EMULATE_UID_LOG_SIZE_MAX) { + string_cat_printf(nfc->text_box_store, "R:"); + for(uint16_t i = 0; i < reader_data->size; i++) { + string_cat_printf(nfc->text_box_store, " %02X", reader_data->data[i]); + } + string_push_back(nfc->text_box_store, '\n'); + text_box_set_text(nfc->text_box, string_get_cstr(nfc->text_box_store)); } - string_push_back(nfc->text_box_store, '\n'); memset(reader_data, 0, sizeof(NfcReaderRequestData)); - text_box_set_text(nfc->text_box, string_get_cstr(nfc->text_box_store)); consumed = true; } else if(event.event == GuiButtonTypeCenter && state == NfcSceneEmulateUidStateWidget) { view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); diff --git a/applications/nfc/scenes/nfc_scene_field.c b/applications/nfc/scenes/nfc_scene_field.c index 36670387640..31cf74b8e75 100644 --- a/applications/nfc/scenes/nfc_scene_field.c +++ b/applications/nfc/scenes/nfc_scene_field.c @@ -1,7 +1,7 @@ #include "../nfc_i.h" void nfc_scene_field_on_enter(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; furi_hal_nfc_field_on(); @@ -23,12 +23,9 @@ bool nfc_scene_field_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_field_on_exit(void* context) { - Nfc* nfc = (Nfc*)context; - - notification_internal_message(nfc->notifications, &sequence_reset_blue); - - Popup* popup = nfc->popup; - popup_reset(popup); + Nfc* nfc = context; furi_hal_nfc_field_off(); + notification_internal_message(nfc->notifications, &sequence_reset_blue); + popup_reset(nfc->popup); } diff --git a/applications/nfc/scenes/nfc_scene_file_select.c b/applications/nfc/scenes/nfc_scene_file_select.c index 010e807ef8f..a8126456f2d 100755 --- a/applications/nfc/scenes/nfc_scene_file_select.c +++ b/applications/nfc/scenes/nfc_scene_file_select.c @@ -1,7 +1,7 @@ #include "../nfc_i.h" void nfc_scene_file_select_on_enter(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; // Process file_select return if(nfc_file_select(nfc->dev)) { scene_manager_next_scene(nfc->scene_manager, NfcSceneSavedMenu); diff --git a/applications/nfc/scenes/nfc_scene_mifare_desfire_app.c b/applications/nfc/scenes/nfc_scene_mifare_desfire_app.c index e68d46d1f79..0974c062cea 100644 --- a/applications/nfc/scenes/nfc_scene_mifare_desfire_app.c +++ b/applications/nfc/scenes/nfc_scene_mifare_desfire_app.c @@ -18,13 +18,13 @@ MifareDesfireApplication* nfc_scene_mifare_desfire_app_get_app(Nfc* nfc) { } void nfc_scene_mifare_desfire_app_submenu_callback(void* context, uint32_t index) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_mifare_desfire_app_on_enter(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; Submenu* submenu = nfc->submenu; MifareDesfireApplication* app = nfc_scene_mifare_desfire_app_get_app(nfc); if(!app) { @@ -73,7 +73,8 @@ void nfc_scene_mifare_desfire_app_on_enter(void* context) { } bool nfc_scene_mifare_desfire_app_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; + bool consumed = false; uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareDesfireApp); if(event.type == SceneManagerEventTypeCustom) { @@ -96,24 +97,24 @@ bool nfc_scene_mifare_desfire_app_on_event(void* context, SceneManagerEvent even text_box_set_text(text_box, string_get_cstr(nfc->text_box_store)); scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMifareDesfireApp, state | 1); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); - return true; + consumed = true; } else if(event.type == SceneManagerEventTypeBack) { if(state & 1) { view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); scene_manager_set_scene_state( nfc->scene_manager, NfcSceneMifareDesfireApp, state & ~1); - return true; + consumed = true; } } - return false; + return consumed; } void nfc_scene_mifare_desfire_app_on_exit(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; + // Clear views text_box_reset(nfc->text_box); string_reset(nfc->text_box_store); - submenu_reset(nfc->submenu); } diff --git a/applications/nfc/scenes/nfc_scene_mifare_desfire_data.c b/applications/nfc/scenes/nfc_scene_mifare_desfire_data.c index c34d7af1719..3eb23fc27f0 100644 --- a/applications/nfc/scenes/nfc_scene_mifare_desfire_data.c +++ b/applications/nfc/scenes/nfc_scene_mifare_desfire_data.c @@ -19,7 +19,7 @@ void nfc_scene_mifare_desfire_data_submenu_callback(void* context, uint32_t inde } void nfc_scene_mifare_desfire_data_on_enter(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; Submenu* submenu = nfc->submenu; uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareDesfireData); MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data; @@ -61,7 +61,8 @@ void nfc_scene_mifare_desfire_data_on_enter(void* context) { } bool nfc_scene_mifare_desfire_data_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; + bool consumed = false; uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareDesfireData); MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data; @@ -76,7 +77,7 @@ bool nfc_scene_mifare_desfire_data_on_event(void* context, SceneManagerEvent eve nfc->scene_manager, NfcSceneMifareDesfireData, MifareDesfireDataStateItem + SubmenuIndexCardInfo); - return true; + consumed = true; } else { uint16_t index = event.event - SubmenuIndexDynamic; scene_manager_set_scene_state( @@ -84,25 +85,25 @@ bool nfc_scene_mifare_desfire_data_on_event(void* context, SceneManagerEvent eve scene_manager_set_scene_state( nfc->scene_manager, NfcSceneMifareDesfireApp, index << 1); scene_manager_next_scene(nfc->scene_manager, NfcSceneMifareDesfireApp); - return true; + consumed = true; } } else if(event.type == SceneManagerEventTypeBack) { if(state >= MifareDesfireDataStateItem) { view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); scene_manager_set_scene_state( nfc->scene_manager, NfcSceneMifareDesfireData, MifareDesfireDataStateMenu); - return true; + consumed = true; } } - return false; + return consumed; } void nfc_scene_mifare_desfire_data_on_exit(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; + // Clear views text_box_reset(nfc->text_box); string_reset(nfc->text_box_store); - submenu_reset(nfc->submenu); } diff --git a/applications/nfc/scenes/nfc_scene_mifare_desfire_menu.c b/applications/nfc/scenes/nfc_scene_mifare_desfire_menu.c index 9aa68a43053..f6171c8b9a3 100644 --- a/applications/nfc/scenes/nfc_scene_mifare_desfire_menu.c +++ b/applications/nfc/scenes/nfc_scene_mifare_desfire_menu.c @@ -5,13 +5,13 @@ enum SubmenuIndex { }; void nfc_scene_mifare_desfire_menu_submenu_callback(void* context, uint32_t index) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_mifare_desfire_menu_on_enter(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; Submenu* submenu = nfc->submenu; submenu_add_item( @@ -24,7 +24,8 @@ void nfc_scene_mifare_desfire_menu_on_enter(void* context) { } bool nfc_scene_mifare_desfire_menu_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; + bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubmenuIndexSave) { @@ -34,15 +35,16 @@ bool nfc_scene_mifare_desfire_menu_on_event(void* context, SceneManagerEvent eve // Clear device name nfc_device_set_name(nfc->dev, ""); scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); - return true; + consumed = true; } } - return false; + return consumed; } void nfc_scene_mifare_desfire_menu_on_exit(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; + // Clear view submenu_reset(nfc->submenu); } diff --git a/applications/nfc/scenes/nfc_scene_mifare_ul_menu.c b/applications/nfc/scenes/nfc_scene_mifare_ul_menu.c index 0e2aaf99709..0099f1a0b03 100755 --- a/applications/nfc/scenes/nfc_scene_mifare_ul_menu.c +++ b/applications/nfc/scenes/nfc_scene_mifare_ul_menu.c @@ -6,13 +6,13 @@ enum SubmenuIndex { }; void nfc_scene_mifare_ul_menu_submenu_callback(void* context, uint32_t index) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_mifare_ul_menu_on_enter(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; Submenu* submenu = nfc->submenu; submenu_add_item( @@ -26,7 +26,8 @@ void nfc_scene_mifare_ul_menu_on_enter(void* context) { } bool nfc_scene_mifare_ul_menu_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; + bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubmenuIndexSave) { @@ -36,23 +37,24 @@ bool nfc_scene_mifare_ul_menu_on_event(void* context, SceneManagerEvent event) { // Clear device name nfc_device_set_name(nfc->dev, ""); scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); - return true; + consumed = true; } else if(event.event == SubmenuIndexEmulate) { scene_manager_set_scene_state( nfc->scene_manager, NfcSceneMifareUlMenu, SubmenuIndexEmulate); scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareUl); - return true; + consumed = true; } } else if(event.type == SceneManagerEventTypeBack) { - return scene_manager_search_and_switch_to_previous_scene( - nfc->scene_manager, NfcSceneStart); + consumed = + scene_manager_search_and_switch_to_previous_scene(nfc->scene_manager, NfcSceneStart); } - return false; + return consumed; } void nfc_scene_mifare_ul_menu_on_exit(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; + // Clear view submenu_reset(nfc->submenu); } diff --git a/applications/nfc/scenes/nfc_scene_not_implemented.c b/applications/nfc/scenes/nfc_scene_not_implemented.c deleted file mode 100644 index 3167f9c0a9d..00000000000 --- a/applications/nfc/scenes/nfc_scene_not_implemented.c +++ /dev/null @@ -1,42 +0,0 @@ -#include "../nfc_i.h" - -void nfc_scene_not_implemented_dialog_callback(DialogExResult result, void* context) { - Nfc* nfc = (Nfc*)context; - - view_dispatcher_send_custom_event(nfc->view_dispatcher, result); -} - -void nfc_scene_not_implemented_on_enter(void* context) { - Nfc* nfc = (Nfc*)context; - - // TODO Set data from worker - DialogEx* dialog_ex = nfc->dialog_ex; - dialog_ex_set_left_button_text(dialog_ex, "Back"); - dialog_ex_set_header(dialog_ex, "Not implemented", 60, 24, AlignCenter, AlignCenter); - dialog_ex_set_context(dialog_ex, nfc); - dialog_ex_set_result_callback(dialog_ex, nfc_scene_not_implemented_dialog_callback); - - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); -} - -bool nfc_scene_not_implemented_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = (Nfc*)context; - - if(event.type == SceneManagerEventTypeCustom) { - if(event.event == DialogExResultLeft) { - return scene_manager_previous_scene(nfc->scene_manager); - } - } - return false; -} - -void nfc_scene_not_implemented_on_exit(void* context) { - Nfc* nfc = (Nfc*)context; - - DialogEx* dialog_ex = nfc->dialog_ex; - dialog_ex_set_header(dialog_ex, NULL, 0, 0, AlignCenter, AlignCenter); - dialog_ex_set_text(dialog_ex, NULL, 0, 0, AlignCenter, AlignTop); - dialog_ex_set_left_button_text(dialog_ex, NULL); - dialog_ex_set_result_callback(dialog_ex, NULL); - dialog_ex_set_context(dialog_ex, NULL); -} diff --git a/applications/nfc/scenes/nfc_scene_read_card.c b/applications/nfc/scenes/nfc_scene_read_card.c index 72a6e4f229d..4d151c08ee6 100755 --- a/applications/nfc/scenes/nfc_scene_read_card.c +++ b/applications/nfc/scenes/nfc_scene_read_card.c @@ -2,12 +2,12 @@ #include void nfc_read_card_worker_callback(NfcWorkerEvent event, void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit); } void nfc_scene_read_card_on_enter(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; DOLPHIN_DEED(DolphinDeedNfcRead); // Setup view @@ -22,29 +22,26 @@ void nfc_scene_read_card_on_enter(void* context) { } bool nfc_scene_read_card_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; + bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { if(event.event == NfcCustomEventWorkerExit) { scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardSuccess); - return true; + consumed = true; } } else if(event.type == SceneManagerEventTypeTick) { notification_message(nfc->notifications, &sequence_blink_blue_10); - return true; + consumed = true; } - return false; + return consumed; } void nfc_scene_read_card_on_exit(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; // Stop worker nfc_worker_stop(nfc->worker); - // Clear view - Popup* popup = nfc->popup; - popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom); - popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop); - popup_set_icon(popup, 0, 0, NULL); + popup_reset(nfc->popup); } diff --git a/applications/nfc/scenes/nfc_scene_read_card_success.c b/applications/nfc/scenes/nfc_scene_read_card_success.c index 260dccefa38..c0a865bca70 100755 --- a/applications/nfc/scenes/nfc_scene_read_card_success.c +++ b/applications/nfc/scenes/nfc_scene_read_card_success.c @@ -7,13 +7,15 @@ void nfc_scene_read_card_success_widget_callback( void* context) { furi_assert(context); Nfc* nfc = context; + if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } } void nfc_scene_read_card_success_on_enter(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; + string_t data_str; string_t uid_str; string_init(data_str); @@ -24,9 +26,9 @@ void nfc_scene_read_card_success_on_enter(void* context) { notification_message(nfc->notifications, &sequence_success); // Setup view - NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data; + FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; Widget* widget = nfc->widget; - string_set_str(data_str, nfc_get_dev_type(data->device)); + string_set_str(data_str, nfc_get_dev_type(data->type)); string_set_str(uid_str, "UID:"); for(uint8_t i = 0; i < data->uid_len; i++) { string_cat_printf(uid_str, " %02X", data->uid[i]); @@ -34,7 +36,7 @@ void nfc_scene_read_card_success_on_enter(void* context) { widget_add_button_element( widget, GuiButtonTypeLeft, "Retry", nfc_scene_read_card_success_widget_callback, nfc); - if(data->device == NfcDeviceNfca) { + if(data->type == FuriHalNfcTypeA) { widget_add_button_element( widget, GuiButtonTypeRight, "More", nfc_scene_read_card_success_widget_callback, nfc); widget_add_icon_element(widget, 8, 13, &I_Medium_chip_22x21); @@ -44,7 +46,7 @@ void nfc_scene_read_card_success_on_enter(void* context) { string_printf( data_str, "%s\nATQA: %02X%02X SAK: %02X", - nfc_guess_protocol(data->protocol), + nfc_guess_protocol(nfc->dev->dev_data.protocol), data->atqa[0], data->atqa[1], data->sak); @@ -66,14 +68,14 @@ void nfc_scene_read_card_success_on_enter(void* context) { } bool nfc_scene_read_card_success_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = (Nfc*)context; - NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data; + Nfc* nfc = context; + FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { if(event.event == GuiButtonTypeLeft) { consumed = scene_manager_previous_scene(nfc->scene_manager); - } else if(data->device == NfcDeviceNfca && event.event == GuiButtonTypeRight) { + } else if(data->type == FuriHalNfcTypeA && event.event == GuiButtonTypeRight) { // Clear device name nfc_device_set_name(nfc->dev, ""); scene_manager_next_scene(nfc->scene_manager, NfcSceneCardMenu); @@ -84,6 +86,8 @@ bool nfc_scene_read_card_success_on_event(void* context, SceneManagerEvent event } void nfc_scene_read_card_success_on_exit(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; + + // Clear view widget_reset(nfc->widget); } diff --git a/applications/nfc/scenes/nfc_scene_read_emv_app.c b/applications/nfc/scenes/nfc_scene_read_emv_app.c index a2f0a3259ff..f0192cb9a2a 100755 --- a/applications/nfc/scenes/nfc_scene_read_emv_app.c +++ b/applications/nfc/scenes/nfc_scene_read_emv_app.c @@ -2,12 +2,12 @@ #include void nfc_read_emv_app_worker_callback(NfcWorkerEvent event, void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit); } void nfc_scene_read_emv_app_on_enter(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; DOLPHIN_DEED(DolphinDeedNfcRead); // Setup view @@ -26,31 +26,30 @@ void nfc_scene_read_emv_app_on_enter(void* context) { } bool nfc_scene_read_emv_app_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; + bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { if(event.event == NfcCustomEventWorkerExit) { scene_manager_set_scene_state( nfc->scene_manager, NfcSceneReadEmvAppSuccess, NFC_SEND_NOTIFICATION_TRUE); scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvAppSuccess); - return true; + consumed = true; } } else if(event.type == SceneManagerEventTypeTick) { notification_message(nfc->notifications, &sequence_blink_blue_10); - return true; + consumed = true; } - return false; + + return consumed; } void nfc_scene_read_emv_app_on_exit(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; // Stop worker nfc_worker_stop(nfc->worker); // Clear view - Popup* popup = nfc->popup; - popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom); - popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop); - popup_set_icon(popup, 0, 0, NULL); + popup_reset(nfc->popup); } diff --git a/applications/nfc/scenes/nfc_scene_read_emv_app_success.c b/applications/nfc/scenes/nfc_scene_read_emv_app_success.c index 057dd59e35b..b9bc5ba40d0 100755 --- a/applications/nfc/scenes/nfc_scene_read_emv_app_success.c +++ b/applications/nfc/scenes/nfc_scene_read_emv_app_success.c @@ -2,27 +2,38 @@ #include "../helpers/nfc_emv_parser.h" #include -#define NFC_SCENE_READ_SUCCESS_SHIFT " " - -void nfc_scene_read_emv_app_success_dialog_callback(DialogExResult result, void* context) { - Nfc* nfc = (Nfc*)context; - - view_dispatcher_send_custom_event(nfc->view_dispatcher, result); +void nfc_scene_read_emv_app_widget_callback(GuiButtonType result, InputType type, void* context) { + Nfc* nfc = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(nfc->view_dispatcher, result); + } } void nfc_scene_read_emv_app_success_on_enter(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; DOLPHIN_DEED(DolphinDeedNfcReadSuccess); // Setup view - NfcDeviceCommonData* nfc_data = &nfc->dev->dev_data.nfc_data; - NfcEmvData* emv_data = &nfc->dev->dev_data.emv_data; - DialogEx* dialog_ex = nfc->dialog_ex; - dialog_ex_set_left_button_text(dialog_ex, "Retry"); - dialog_ex_set_right_button_text(dialog_ex, "Run app"); - dialog_ex_set_header(dialog_ex, "Found EMV App", 36, 8, AlignLeft, AlignCenter); - dialog_ex_set_icon(dialog_ex, 8, 13, &I_Medium_chip_22x21); - // Display UID and AID + FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data; + EmvData* emv_data = &nfc->dev->dev_data.emv_data; + Widget* widget = nfc->widget; + widget_add_button_element( + widget, GuiButtonTypeLeft, "Retry", nfc_scene_read_emv_app_widget_callback, nfc); + widget_add_button_element( + widget, GuiButtonTypeRight, "Run app", nfc_scene_read_emv_app_widget_callback, nfc); + widget_add_string_element(widget, 36, 5, AlignLeft, AlignTop, FontPrimary, "Found EMV App"); + widget_add_icon_element(widget, 8, 5, &I_Medium_chip_22x21); + // Display UID + string_t temp_str; + string_init_printf(temp_str, "UID:"); + for(size_t i = 0; i < nfc_data->uid_len; i++) { + string_cat_printf(temp_str, " %02X", nfc_data->uid[i]); + } + widget_add_string_element( + widget, 36, 18, AlignLeft, AlignTop, FontSecondary, string_get_cstr(temp_str)); + string_reset(temp_str); + // Display application + string_printf(temp_str, "App: "); string_t aid; string_init(aid); bool aid_found = @@ -32,19 +43,11 @@ void nfc_scene_read_emv_app_success_on_enter(void* context) { string_cat_printf(aid, "%02X", emv_data->aid[i]); } } - nfc_text_store_set( - nfc, - NFC_SCENE_READ_SUCCESS_SHIFT "UID: %02X %02X %02X %02X \n" NFC_SCENE_READ_SUCCESS_SHIFT - "Application:\n%s", - nfc_data->uid[0], - nfc_data->uid[1], - nfc_data->uid[2], - nfc_data->uid[3], - string_get_cstr(aid)); + string_cat(temp_str, aid); + widget_add_string_element( + widget, 7, 29, AlignLeft, AlignTop, FontSecondary, string_get_cstr(temp_str)); + string_clear(temp_str); string_clear(aid); - dialog_ex_set_text(dialog_ex, nfc->text_store, 8, 16, AlignLeft, AlignTop); - dialog_ex_set_context(dialog_ex, nfc); - dialog_ex_set_result_callback(dialog_ex, nfc_scene_read_emv_app_success_dialog_callback); // Send notification if(scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadEmvAppSuccess) == @@ -54,32 +57,27 @@ void nfc_scene_read_emv_app_success_on_enter(void* context) { nfc->scene_manager, NfcSceneReadEmvAppSuccess, NFC_SEND_NOTIFICATION_FALSE); } - view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); } bool nfc_scene_read_emv_app_success_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; + bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { - if(event.event == DialogExResultLeft) { - return scene_manager_previous_scene(nfc->scene_manager); - } else if(event.event == DialogExResultRight) { + if(event.event == GuiButtonTypeLeft) { + consumed = scene_manager_previous_scene(nfc->scene_manager); + } else if(event.event == GuiButtonTypeRight) { scene_manager_next_scene(nfc->scene_manager, NfcSceneRunEmvAppConfirm); - return true; + consumed = true; } } - return false; + return consumed; } void nfc_scene_read_emv_app_success_on_exit(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; - DialogEx* dialog_ex = nfc->dialog_ex; - dialog_ex_set_header(dialog_ex, NULL, 0, 0, AlignCenter, AlignCenter); - dialog_ex_set_text(dialog_ex, NULL, 0, 0, AlignCenter, AlignTop); - dialog_ex_set_icon(dialog_ex, 0, 0, NULL); - dialog_ex_set_left_button_text(dialog_ex, NULL); - dialog_ex_set_right_button_text(dialog_ex, NULL); - dialog_ex_set_result_callback(dialog_ex, NULL); - dialog_ex_set_context(dialog_ex, NULL); + // Clear views + widget_reset(nfc->widget); } diff --git a/applications/nfc/scenes/nfc_scene_read_emv_data.c b/applications/nfc/scenes/nfc_scene_read_emv_data.c index 37442c333cf..b72c873e4b4 100755 --- a/applications/nfc/scenes/nfc_scene_read_emv_data.c +++ b/applications/nfc/scenes/nfc_scene_read_emv_data.c @@ -2,12 +2,12 @@ #include void nfc_read_emv_data_worker_callback(NfcWorkerEvent event, void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit); } void nfc_scene_read_emv_data_on_enter(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; DOLPHIN_DEED(DolphinDeedNfcRead); // Setup view @@ -21,38 +21,35 @@ void nfc_scene_read_emv_data_on_enter(void* context) { // Start worker nfc_worker_start( nfc->worker, - NfcWorkerStateReadEMV, + NfcWorkerStateReadEMVData, &nfc->dev->dev_data, nfc_read_emv_data_worker_callback, nfc); } bool nfc_scene_read_emv_data_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; + bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { if(event.event == NfcCustomEventWorkerExit) { scene_manager_set_scene_state( nfc->scene_manager, NfcSceneReadEmvDataSuccess, NFC_SEND_NOTIFICATION_TRUE); scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvDataSuccess); - return true; + consumed = true; } } else if(event.type == SceneManagerEventTypeTick) { notification_message(nfc->notifications, &sequence_blink_blue_10); - return true; + consumed = true; } - return false; + return consumed; } void nfc_scene_read_emv_data_on_exit(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; // Stop worker nfc_worker_stop(nfc->worker); - // Clear view - Popup* popup = nfc->popup; - popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom); - popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop); - popup_set_icon(popup, 0, 0, NULL); + popup_reset(nfc->popup); } diff --git a/applications/nfc/scenes/nfc_scene_read_emv_data_success.c b/applications/nfc/scenes/nfc_scene_read_emv_data_success.c index 78078d05b90..275e9b86e1a 100755 --- a/applications/nfc/scenes/nfc_scene_read_emv_data_success.c +++ b/applications/nfc/scenes/nfc_scene_read_emv_data_success.c @@ -6,16 +6,16 @@ void nfc_scene_read_emv_data_success_widget_callback( GuiButtonType result, InputType type, void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } } void nfc_scene_read_emv_data_success_on_enter(void* context) { - Nfc* nfc = (Nfc*)context; - NfcEmvData* emv_data = &nfc->dev->dev_data.emv_data; - NfcDeviceCommonData* nfc_data = &nfc->dev->dev_data.nfc_data; + Nfc* nfc = context; + EmvData* emv_data = &nfc->dev->dev_data.emv_data; + FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data; DOLPHIN_DEED(DolphinDeedNfcReadSuccess); // Setup Custom Widget view @@ -78,25 +78,23 @@ void nfc_scene_read_emv_data_success_on_enter(void* context) { string_clear(disp_currency); } string_clear(currency_name); + char temp_str[32]; // Add ATQA - char atqa_str[16]; - snprintf(atqa_str, sizeof(atqa_str), "ATQA: %02X%02X", nfc_data->atqa[0], nfc_data->atqa[1]); - widget_add_string_element(nfc->widget, 121, 32, AlignRight, AlignTop, FontSecondary, atqa_str); + snprintf(temp_str, sizeof(temp_str), "ATQA: %02X%02X", nfc_data->atqa[0], nfc_data->atqa[1]); + widget_add_string_element(nfc->widget, 121, 32, AlignRight, AlignTop, FontSecondary, temp_str); // Add UID - char uid_str[32]; snprintf( - uid_str, - sizeof(uid_str), + temp_str, + sizeof(temp_str), "UID: %02X %02X %02X %02X", nfc_data->uid[0], nfc_data->uid[1], nfc_data->uid[2], nfc_data->uid[3]); - widget_add_string_element(nfc->widget, 7, 42, AlignLeft, AlignTop, FontSecondary, uid_str); + widget_add_string_element(nfc->widget, 7, 42, AlignLeft, AlignTop, FontSecondary, temp_str); // Add SAK - char sak_str[16]; - snprintf(sak_str, sizeof(sak_str), "SAK: %02X", nfc_data->sak); - widget_add_string_element(nfc->widget, 121, 42, AlignRight, AlignTop, FontSecondary, sak_str); + snprintf(temp_str, sizeof(temp_str), "SAK: %02X", nfc_data->sak); + widget_add_string_element(nfc->widget, 121, 42, AlignRight, AlignTop, FontSecondary, temp_str); // Add expiration date if(emv_data->exp_mon) { char exp_str[16]; @@ -117,28 +115,30 @@ void nfc_scene_read_emv_data_success_on_enter(void* context) { } bool nfc_scene_read_emv_data_success_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; + bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { if(event.event == GuiButtonTypeLeft) { - return scene_manager_search_and_switch_to_previous_scene( + consumed = scene_manager_search_and_switch_to_previous_scene( nfc->scene_manager, NfcSceneReadEmvAppSuccess); } else if(event.event == GuiButtonTypeRight) { // Clear device name nfc_device_set_name(nfc->dev, ""); nfc->dev->format = NfcDeviceSaveFormatBankCard; scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); - return true; + consumed = true; } } else if(event.type == SceneManagerEventTypeBack) { - return scene_manager_search_and_switch_to_previous_scene( + consumed = scene_manager_search_and_switch_to_previous_scene( nfc->scene_manager, NfcSceneReadEmvAppSuccess); } - return false; + return consumed; } void nfc_scene_read_emv_data_success_on_exit(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; + // Clear view widget_reset(nfc->widget); } diff --git a/applications/nfc/scenes/nfc_scene_read_mifare_desfire.c b/applications/nfc/scenes/nfc_scene_read_mifare_desfire.c index 1a0b3524614..ebd7289b911 100644 --- a/applications/nfc/scenes/nfc_scene_read_mifare_desfire.c +++ b/applications/nfc/scenes/nfc_scene_read_mifare_desfire.c @@ -2,12 +2,12 @@ #include void nfc_read_mifare_desfire_worker_callback(NfcWorkerEvent event, void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit); } void nfc_scene_read_mifare_desfire_on_enter(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; DOLPHIN_DEED(DolphinDeedNfcRead); // Setup view @@ -26,31 +26,28 @@ void nfc_scene_read_mifare_desfire_on_enter(void* context) { } bool nfc_scene_read_mifare_desfire_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; + bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { if(event.event == NfcCustomEventWorkerExit) { notification_message(nfc->notifications, &sequence_success); scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareDesfireSuccess); - return true; + consumed = true; } } else if(event.type == SceneManagerEventTypeTick) { notification_message(nfc->notifications, &sequence_blink_blue_10); DOLPHIN_DEED(DolphinDeedNfcReadSuccess); - return true; + consumed = true; } - return false; + return consumed; } void nfc_scene_read_mifare_desfire_on_exit(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; // Stop worker nfc_worker_stop(nfc->worker); - // Clear view - Popup* popup = nfc->popup; - popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom); - popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop); - popup_set_icon(popup, 0, 0, NULL); + popup_reset(nfc->popup); } diff --git a/applications/nfc/scenes/nfc_scene_read_mifare_desfire_success.c b/applications/nfc/scenes/nfc_scene_read_mifare_desfire_success.c index 995869bf775..17f62e4118d 100644 --- a/applications/nfc/scenes/nfc_scene_read_mifare_desfire_success.c +++ b/applications/nfc/scenes/nfc_scene_read_mifare_desfire_success.c @@ -9,13 +9,13 @@ enum { }; void nfc_scene_read_mifare_desfire_success_dialog_callback(DialogExResult result, void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } void nfc_scene_read_mifare_desfire_success_on_enter(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data; DialogEx* dialog_ex = nfc->dialog_ex; @@ -67,9 +67,9 @@ void nfc_scene_read_mifare_desfire_success_on_enter(void* context) { bool nfc_scene_read_mifare_desfire_success_on_event(void* context, SceneManagerEvent event) { Nfc* nfc = context; + bool consumed = false; uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadMifareDesfireSuccess); - bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { if(state == ReadMifareDesfireSuccessStateShowUID && event.event == DialogExResultLeft) { @@ -98,9 +98,8 @@ bool nfc_scene_read_mifare_desfire_success_on_event(void* context, SceneManagerE } void nfc_scene_read_mifare_desfire_success_on_exit(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; // Clean dialog - DialogEx* dialog_ex = nfc->dialog_ex; - dialog_ex_reset(dialog_ex); + dialog_ex_reset(nfc->dialog_ex); } diff --git a/applications/nfc/scenes/nfc_scene_read_mifare_ul.c b/applications/nfc/scenes/nfc_scene_read_mifare_ul.c index ce6d160e5b8..8903e2c433e 100755 --- a/applications/nfc/scenes/nfc_scene_read_mifare_ul.c +++ b/applications/nfc/scenes/nfc_scene_read_mifare_ul.c @@ -19,7 +19,7 @@ void nfc_scene_read_mifare_ul_on_enter(void* context) { // Start worker nfc_worker_start( nfc->worker, - NfcWorkerStateReadMifareUl, + NfcWorkerStateReadMifareUltralight, &nfc->dev->dev_data, nfc_read_mifare_ul_worker_callback, nfc); @@ -43,6 +43,7 @@ bool nfc_scene_read_mifare_ul_on_event(void* context, SceneManagerEvent event) { void nfc_scene_read_mifare_ul_on_exit(void* context) { Nfc* nfc = context; + // Stop worker nfc_worker_stop(nfc->worker); // Clear view diff --git a/applications/nfc/scenes/nfc_scene_read_mifare_ul_success.c b/applications/nfc/scenes/nfc_scene_read_mifare_ul_success.c index 603ad54ae7b..5bcf15894ca 100755 --- a/applications/nfc/scenes/nfc_scene_read_mifare_ul_success.c +++ b/applications/nfc/scenes/nfc_scene_read_mifare_ul_success.c @@ -9,21 +9,21 @@ enum { }; void nfc_scene_read_mifare_ul_success_dialog_callback(DialogExResult result, void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } void nfc_scene_read_mifare_ul_success_on_enter(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; DOLPHIN_DEED(DolphinDeedNfcReadSuccess); // Send notification notification_message(nfc->notifications, &sequence_success); // Setup dialog view - NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data; - MifareUlData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data; + FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; + MfUltralightData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data; DialogEx* dialog_ex = nfc->dialog_ex; dialog_ex_set_left_button_text(dialog_ex, "Retry"); dialog_ex_set_right_button_text(dialog_ex, "More"); @@ -69,9 +69,9 @@ void nfc_scene_read_mifare_ul_success_on_enter(void* context) { bool nfc_scene_read_mifare_ul_success_on_event(void* context, SceneManagerEvent event) { Nfc* nfc = context; + bool consumed = false; uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadMifareUlSuccess); - bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { if(state == ReadMifareUlStateShowUID && event.event == DialogExResultLeft) { @@ -99,14 +99,10 @@ bool nfc_scene_read_mifare_ul_success_on_event(void* context, SceneManagerEvent } void nfc_scene_read_mifare_ul_success_on_exit(void* context) { - Nfc* nfc = (Nfc*)context; - - // Clean dialog - DialogEx* dialog_ex = nfc->dialog_ex; - dialog_ex_reset(dialog_ex); + Nfc* nfc = context; - // Clean TextBox - TextBox* text_box = nfc->text_box; - text_box_reset(text_box); + // Clean views + dialog_ex_reset(nfc->dialog_ex); + text_box_reset(nfc->text_box); string_reset(nfc->text_box_store); } diff --git a/applications/nfc/scenes/nfc_scene_restore_original.c b/applications/nfc/scenes/nfc_scene_restore_original.c index 8ddac366169..40b59b9eb4f 100644 --- a/applications/nfc/scenes/nfc_scene_restore_original.c +++ b/applications/nfc/scenes/nfc_scene_restore_original.c @@ -1,12 +1,12 @@ #include "../nfc_i.h" void nfc_scene_restore_original_popup_callback(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); } void nfc_scene_restore_original_on_enter(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; // Setup view Popup* popup = nfc->popup; @@ -20,7 +20,7 @@ void nfc_scene_restore_original_on_enter(void* context) { } bool nfc_scene_restore_original_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -32,15 +32,8 @@ bool nfc_scene_restore_original_on_event(void* context, SceneManagerEvent event) } void nfc_scene_restore_original_on_exit(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; // Clear view - Popup* popup = nfc->popup; - popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom); - popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop); - popup_set_icon(popup, 0, 0, NULL); - popup_set_callback(popup, NULL); - popup_set_context(popup, NULL); - popup_set_timeout(popup, 0); - popup_disable_timeout(popup); + popup_reset(nfc->popup); } diff --git a/applications/nfc/scenes/nfc_scene_run_emv_app_confirm.c b/applications/nfc/scenes/nfc_scene_run_emv_app_confirm.c index d9948d4e5cb..5ee9f442ccd 100755 --- a/applications/nfc/scenes/nfc_scene_run_emv_app_confirm.c +++ b/applications/nfc/scenes/nfc_scene_run_emv_app_confirm.c @@ -1,15 +1,13 @@ #include "../nfc_i.h" -#define NFC_SCENE_READ_SUCCESS_SHIFT " " - void nfc_scene_run_emv_app_confirm_dialog_callback(DialogExResult result, void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } void nfc_scene_run_emv_app_confirm_on_enter(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; DialogEx* dialog_ex = nfc->dialog_ex; dialog_ex_set_left_button_text(dialog_ex, "Back"); @@ -29,28 +27,23 @@ void nfc_scene_run_emv_app_confirm_on_enter(void* context) { } bool nfc_scene_run_emv_app_confirm_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; + bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { if(event.event == DialogExResultLeft) { - return scene_manager_previous_scene(nfc->scene_manager); + consumed = scene_manager_previous_scene(nfc->scene_manager); } else if(event.event == DialogExResultRight) { scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvData); - return true; + consumed = true; } } - return false; + return consumed; } void nfc_scene_run_emv_app_confirm_on_exit(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; - DialogEx* dialog_ex = nfc->dialog_ex; - dialog_ex_set_header(dialog_ex, NULL, 0, 0, AlignCenter, AlignCenter); - dialog_ex_set_text(dialog_ex, NULL, 0, 0, AlignCenter, AlignTop); - dialog_ex_set_icon(dialog_ex, 0, 0, NULL); - dialog_ex_set_left_button_text(dialog_ex, NULL); - dialog_ex_set_right_button_text(dialog_ex, NULL); - dialog_ex_set_result_callback(dialog_ex, NULL); - dialog_ex_set_context(dialog_ex, NULL); + // Clean view + dialog_ex_reset(nfc->dialog_ex); } diff --git a/applications/nfc/scenes/nfc_scene_save_name.c b/applications/nfc/scenes/nfc_scene_save_name.c index aa05c8a6b2c..e95c97eb427 100755 --- a/applications/nfc/scenes/nfc_scene_save_name.c +++ b/applications/nfc/scenes/nfc_scene_save_name.c @@ -3,13 +3,13 @@ #include void nfc_scene_save_name_text_input_callback(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventTextInputDone); } void nfc_scene_save_name_on_enter(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; // Setup view TextInput* text_input = nfc->text_input; @@ -37,7 +37,8 @@ void nfc_scene_save_name_on_enter(void* context) { } bool nfc_scene_save_name_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; + bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { if(event.event == NfcCustomEventTextInputDone) { @@ -50,18 +51,18 @@ bool nfc_scene_save_name_on_event(void* context, SceneManagerEvent event) { strlcpy(nfc->dev->dev_name, nfc->text_store, strlen(nfc->text_store) + 1); if(nfc_device_save(nfc->dev, nfc->text_store)) { scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess); - return true; + consumed = true; } else { - return scene_manager_search_and_switch_to_previous_scene( + consumed = scene_manager_search_and_switch_to_previous_scene( nfc->scene_manager, NfcSceneStart); } } } - return false; + return consumed; } void nfc_scene_save_name_on_exit(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; // Clear view void* validator_context = text_input_get_validator_callback_context(nfc->text_input); diff --git a/applications/nfc/scenes/nfc_scene_save_success.c b/applications/nfc/scenes/nfc_scene_save_success.c index b1a84003c9a..985897a6d89 100644 --- a/applications/nfc/scenes/nfc_scene_save_success.c +++ b/applications/nfc/scenes/nfc_scene_save_success.c @@ -2,12 +2,12 @@ #include void nfc_scene_save_success_popup_callback(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); } void nfc_scene_save_success_on_enter(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; DOLPHIN_DEED(DolphinDeedNfcSave); // Setup view @@ -22,7 +22,7 @@ void nfc_scene_save_success_on_enter(void* context) { } bool nfc_scene_save_success_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -47,15 +47,8 @@ bool nfc_scene_save_success_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_save_success_on_exit(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; // Clear view - Popup* popup = nfc->popup; - popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom); - popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop); - popup_set_icon(popup, 0, 0, NULL); - popup_set_callback(popup, NULL); - popup_set_context(popup, NULL); - popup_set_timeout(popup, 0); - popup_disable_timeout(popup); + popup_reset(nfc->popup); } diff --git a/applications/nfc/scenes/nfc_scene_saved_menu.c b/applications/nfc/scenes/nfc_scene_saved_menu.c index 14eb4ca262a..e0489c157df 100644 --- a/applications/nfc/scenes/nfc_scene_saved_menu.c +++ b/applications/nfc/scenes/nfc_scene_saved_menu.c @@ -9,13 +9,13 @@ enum SubmenuIndex { }; void nfc_scene_saved_menu_submenu_callback(void* context, uint32_t index) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_saved_menu_on_enter(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; Submenu* submenu = nfc->submenu; if(nfc->dev->format == NfcDeviceSaveFormatUid || @@ -56,7 +56,7 @@ void nfc_scene_saved_menu_on_enter(void* context) { } bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -92,7 +92,7 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_saved_menu_on_exit(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; submenu_reset(nfc->submenu); } diff --git a/applications/nfc/scenes/nfc_scene_set_atqa.c b/applications/nfc/scenes/nfc_scene_set_atqa.c index 85a70fe8d03..f2100aa196b 100755 --- a/applications/nfc/scenes/nfc_scene_set_atqa.c +++ b/applications/nfc/scenes/nfc_scene_set_atqa.c @@ -1,13 +1,13 @@ #include "../nfc_i.h" void nfc_scene_set_atqa_byte_input_callback(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); } void nfc_scene_set_atqa_on_enter(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; // Setup view ByteInput* byte_input = nfc->byte_input; @@ -23,19 +23,20 @@ void nfc_scene_set_atqa_on_enter(void* context) { } bool nfc_scene_set_atqa_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; + bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { if(event.event == NfcCustomEventByteInputDone) { scene_manager_next_scene(nfc->scene_manager, NfcSceneSetUid); - return true; + consumed = true; } } - return false; + return consumed; } void nfc_scene_set_atqa_on_exit(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; // Clear view byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0); diff --git a/applications/nfc/scenes/nfc_scene_set_sak.c b/applications/nfc/scenes/nfc_scene_set_sak.c index 11cfcf4670c..3c88f350465 100755 --- a/applications/nfc/scenes/nfc_scene_set_sak.c +++ b/applications/nfc/scenes/nfc_scene_set_sak.c @@ -1,13 +1,13 @@ #include "../nfc_i.h" void nfc_scene_set_sak_byte_input_callback(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); } void nfc_scene_set_sak_on_enter(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; // Setup view ByteInput* byte_input = nfc->byte_input; @@ -23,19 +23,20 @@ void nfc_scene_set_sak_on_enter(void* context) { } bool nfc_scene_set_sak_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; + bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { if(event.event == NfcCustomEventByteInputDone) { scene_manager_next_scene(nfc->scene_manager, NfcSceneSetAtqua); - return true; + consumed = true; } } - return false; + return consumed; } void nfc_scene_set_sak_on_exit(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; // Clear view byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0); diff --git a/applications/nfc/scenes/nfc_scene_set_type.c b/applications/nfc/scenes/nfc_scene_set_type.c index 0e6624bdaef..0dbb4f7ea83 100755 --- a/applications/nfc/scenes/nfc_scene_set_type.c +++ b/applications/nfc/scenes/nfc_scene_set_type.c @@ -6,13 +6,13 @@ enum SubmenuIndex { }; void nfc_scene_set_type_submenu_callback(void* context, uint32_t index) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_set_type_on_enter(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; Submenu* submenu = nfc->submenu; // Clear device name nfc_device_set_name(nfc->dev, ""); @@ -24,26 +24,27 @@ void nfc_scene_set_type_on_enter(void* context) { } bool nfc_scene_set_type_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; + bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubmenuIndexNFCA7) { nfc->dev->dev_data.nfc_data.uid_len = 7; nfc->dev->format = NfcDeviceSaveFormatUid; scene_manager_next_scene(nfc->scene_manager, NfcSceneSetSak); - return true; + consumed = true; } else if(event.event == SubmenuIndexNFCA4) { nfc->dev->dev_data.nfc_data.uid_len = 4; nfc->dev->format = NfcDeviceSaveFormatUid; scene_manager_next_scene(nfc->scene_manager, NfcSceneSetSak); - return true; + consumed = true; } } - return false; + return consumed; } void nfc_scene_set_type_on_exit(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; submenu_reset(nfc->submenu); } diff --git a/applications/nfc/scenes/nfc_scene_set_uid.c b/applications/nfc/scenes/nfc_scene_set_uid.c index c59501294bb..6fe807cedcb 100755 --- a/applications/nfc/scenes/nfc_scene_set_uid.c +++ b/applications/nfc/scenes/nfc_scene_set_uid.c @@ -2,13 +2,13 @@ #include void nfc_scene_set_uid_byte_input_callback(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); } void nfc_scene_set_uid_on_enter(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; // Setup view ByteInput* byte_input = nfc->byte_input; @@ -26,19 +26,20 @@ void nfc_scene_set_uid_on_enter(void* context) { bool nfc_scene_set_uid_on_event(void* context, SceneManagerEvent event) { Nfc* nfc = (Nfc*)context; + bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { if(event.event == NfcCustomEventByteInputDone) { DOLPHIN_DEED(DolphinDeedNfcAdd); scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); - return true; + consumed = true; } } - return false; + return consumed; } void nfc_scene_set_uid_on_exit(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; // Clear view byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0); diff --git a/applications/nfc/scenes/nfc_scene_start.c b/applications/nfc/scenes/nfc_scene_start.c index 2be7775b345..d64aa76e37c 100644 --- a/applications/nfc/scenes/nfc_scene_start.c +++ b/applications/nfc/scenes/nfc_scene_start.c @@ -9,13 +9,13 @@ enum SubmenuIndex { }; void nfc_scene_start_submenu_callback(void* context, uint32_t index) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_start_on_enter(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; Submenu* submenu = nfc->submenu; submenu_add_item( @@ -43,7 +43,7 @@ void nfc_scene_start_on_enter(void* context) { } bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -70,7 +70,7 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_start_on_exit(void* context) { - Nfc* nfc = (Nfc*)context; + Nfc* nfc = context; submenu_reset(nfc->submenu); } diff --git a/applications/notification/notification.h b/applications/notification/notification.h index 10a32976b7c..b73efad20a9 100644 --- a/applications/notification/notification.h +++ b/applications/notification/notification.h @@ -59,6 +59,8 @@ typedef enum { NotificationMessageTypeForceSpeakerVolumeSetting, NotificationMessageTypeForceVibroSetting, NotificationMessageTypeForceDisplayBrightnessSetting, + + NotificationMessageTypeLedBrightnessSettingApply, } NotificationMessageType; typedef struct { diff --git a/applications/notification/notification_app.c b/applications/notification/notification_app.c index 1e2e2dde9c7..75be20b1617 100644 --- a/applications/notification/notification_app.c +++ b/applications/notification/notification_app.c @@ -212,18 +212,21 @@ void notification_process_notification_message( // store and send on delay or after seq led_active = true; led_values[0] = notification_message->data.led.value; + app->led[0].value_last[LayerNotification] = led_values[0]; reset_mask |= reset_red_mask; break; case NotificationMessageTypeLedGreen: // store and send on delay or after seq led_active = true; led_values[1] = notification_message->data.led.value; + app->led[1].value_last[LayerNotification] = led_values[1]; reset_mask |= reset_green_mask; break; case NotificationMessageTypeLedBlue: // store and send on delay or after seq led_active = true; led_values[2] = notification_message->data.led.value; + app->led[2].value_last[LayerNotification] = led_values[2]; reset_mask |= reset_blue_mask; break; case NotificationMessageTypeVibro: @@ -273,6 +276,16 @@ void notification_process_notification_message( case NotificationMessageTypeForceDisplayBrightnessSetting: display_brightness_setting = notification_message->data.forced_settings.display_brightness; + break; + case NotificationMessageTypeLedBrightnessSettingApply: + led_active = true; + for(uint8_t i = 0; i < NOTIFICATION_LED_COUNT; i++) { + led_values[i] = app->led[i].value_last[LayerNotification]; + } + reset_mask |= reset_red_mask; + reset_mask |= reset_green_mask; + reset_mask |= reset_blue_mask; + break; } notification_message_index++; notification_message = (*message->sequence)[notification_message_index]; @@ -316,23 +329,33 @@ void notification_process_internal_message(NotificationApp* app, NotificationApp app, notification_message->data.led.value)); break; case NotificationMessageTypeLedRed: + app->led[0].value_last[LayerInternal] = notification_message->data.led.value; notification_apply_internal_led_layer( &app->led[0], notification_settings_get_rgb_led_brightness( app, notification_message->data.led.value)); break; case NotificationMessageTypeLedGreen: + app->led[1].value_last[LayerInternal] = notification_message->data.led.value; notification_apply_internal_led_layer( &app->led[1], notification_settings_get_rgb_led_brightness( app, notification_message->data.led.value)); break; case NotificationMessageTypeLedBlue: + app->led[2].value_last[LayerInternal] = notification_message->data.led.value; notification_apply_internal_led_layer( &app->led[2], notification_settings_get_rgb_led_brightness( app, notification_message->data.led.value)); break; + case NotificationMessageTypeLedBrightnessSettingApply: + for(uint8_t i = 0; i < NOTIFICATION_LED_COUNT; i++) { + uint8_t new_val = notification_settings_get_rgb_led_brightness( + app, app->led[i].value_last[LayerInternal]); + notification_apply_internal_led_layer(&app->led[i], new_val); + } + break; default: break; } diff --git a/applications/notification/notification_app.h b/applications/notification/notification_app.h index 2c41bc823a5..b56b7e3b7eb 100644 --- a/applications/notification/notification_app.h +++ b/applications/notification/notification_app.h @@ -25,6 +25,7 @@ typedef enum { } NotificationLedLayerIndex; typedef struct { + uint8_t value_last[LayerMAX]; uint8_t value[LayerMAX]; NotificationLedLayerIndex index; Light light; diff --git a/applications/notification/notification_settings_app.c b/applications/notification/notification_settings_app.c index 1522628d1ff..e7a57aa6138 100644 --- a/applications/notification/notification_settings_app.c +++ b/applications/notification/notification_settings_app.c @@ -82,12 +82,22 @@ static void screen_changed(VariableItem* item) { notification_message(app->notification, &sequence_display_on); } +const NotificationMessage apply_message = { + .type = NotificationMessageTypeLedBrightnessSettingApply, +}; +const NotificationSequence apply_sequence = { + &apply_message, + NULL, +}; + static void led_changed(VariableItem* item) { NotificationAppSettings* app = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); variable_item_set_current_value_text(item, backlight_text[index]); app->notification->settings.led_brightness = backlight_value[index]; + notification_message(app->notification, &apply_sequence); + notification_internal_message(app->notification, &apply_sequence); notification_message(app->notification, &sequence_blink_white_100); } diff --git a/applications/power/power_service/power.c b/applications/power/power_service/power.c old mode 100755 new mode 100644 index 8c2ecd1785c..5f7eeb84713 --- a/applications/power/power_service/power.c +++ b/applications/power/power_service/power.c @@ -12,14 +12,19 @@ void power_draw_battery_callback(Canvas* canvas, void* context) { furi_assert(context); Power* power = context; canvas_draw_icon(canvas, 0, 1, &I_Battery_26x8); - canvas_draw_box(canvas, 2, 3, (power->info.charge + 4) / 5, 4); - if(power->state == PowerStateCharging) { - canvas_set_bitmap_mode(canvas, 1); - canvas_set_color(canvas, ColorWhite); - canvas_draw_icon(canvas, 8, 0, &I_Charging_lightning_mask_9x10); - canvas_set_color(canvas, ColorBlack); - canvas_draw_icon(canvas, 8, 0, &I_Charging_lightning_9x10); - canvas_set_bitmap_mode(canvas, 0); + + if(power->info.gauge_is_ok) { + canvas_draw_box(canvas, 2, 3, (power->info.charge + 4) / 5, 4); + if(power->state == PowerStateCharging) { + canvas_set_bitmap_mode(canvas, 1); + canvas_set_color(canvas, ColorWhite); + canvas_draw_icon(canvas, 8, 0, &I_Charging_lightning_mask_9x10); + canvas_set_color(canvas, ColorBlack); + canvas_draw_icon(canvas, 8, 0, &I_Charging_lightning_9x10); + canvas_set_bitmap_mode(canvas, 0); + } + } else { + canvas_draw_box(canvas, 8, 4, 8, 2); } } @@ -119,6 +124,7 @@ static void power_check_charging_state(Power* power) { static bool power_update_info(Power* power) { PowerInfo info; + info.gauge_is_ok = furi_hal_power_gauge_is_ok(); info.charge = furi_hal_power_get_pct(); info.health = furi_hal_power_get_bat_health_pct(); info.capacity_remaining = furi_hal_power_get_battery_remaining_capacity(); @@ -140,6 +146,10 @@ static bool power_update_info(Power* power) { } static void power_check_low_battery(Power* power) { + if(!power->info.gauge_is_ok) { + return; + } + // Check battery charge and vbus voltage if((power->info.charge == 0) && (power->info.voltage_vbus < 4.0f) && power->show_low_bat_level_message) { diff --git a/applications/power/power_service/power.h b/applications/power/power_service/power.h index 92cca6f7230..c32c31b3319 100644 --- a/applications/power/power_service/power.h +++ b/applications/power/power_service/power.h @@ -29,6 +29,8 @@ typedef struct { } PowerEvent; typedef struct { + bool gauge_is_ok; + float current_charger; float current_gauge; diff --git a/applications/subghz/scenes/subghz_scene_delete.c b/applications/subghz/scenes/subghz_scene_delete.c index dee161142be..83d6d4751ed 100644 --- a/applications/subghz/scenes/subghz_scene_delete.c +++ b/applications/subghz/scenes/subghz_scene_delete.c @@ -49,7 +49,7 @@ bool subghz_scene_delete_on_event(void* context, SceneManagerEvent event) { SubGhz* subghz = context; if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubGhzCustomEventSceneDelete) { - strncpy(subghz->file_name_tmp, subghz->file_name, SUBGHZ_MAX_LEN_NAME); + strncpy(subghz->file_path_tmp, subghz->file_path, SUBGHZ_MAX_LEN_NAME); if(subghz_delete_file(subghz)) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneDeleteSuccess); } else { diff --git a/applications/subghz/scenes/subghz_scene_delete_raw.c b/applications/subghz/scenes/subghz_scene_delete_raw.c index df57926c9d8..03f0eb81ba1 100644 --- a/applications/subghz/scenes/subghz_scene_delete_raw.c +++ b/applications/subghz/scenes/subghz_scene_delete_raw.c @@ -21,10 +21,15 @@ void subghz_scene_delete_raw_on_enter(void* context) { string_init(frequency_str); string_init(modulation_str); - char delete_str[64]; - snprintf(delete_str, sizeof(delete_str), "\e#Delete %s?\e#", subghz->file_name); + char delete_str[SUBGHZ_MAX_LEN_NAME + 16]; + string_t file_name; + string_init(file_name); + path_extract_filename_no_ext(subghz->file_path, file_name); + snprintf(delete_str, sizeof(delete_str), "\e#Delete %s?\e#", string_get_cstr(file_name)); + string_clear(file_name); + widget_add_text_box_element( - subghz->widget, 0, 0, 128, 23, AlignCenter, AlignCenter, delete_str); + subghz->widget, 0, 0, 128, 23, AlignCenter, AlignCenter, delete_str, false); widget_add_string_element( subghz->widget, 38, 25, AlignLeft, AlignTop, FontSecondary, "RAW signal"); @@ -56,7 +61,7 @@ bool subghz_scene_delete_raw_on_event(void* context, SceneManagerEvent event) { SubGhz* subghz = context; if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubGhzCustomEventSceneDeleteRAW) { - strncpy(subghz->file_name_tmp, subghz->file_name, SUBGHZ_MAX_LEN_NAME); + strncpy(subghz->file_path_tmp, subghz->file_path, SUBGHZ_MAX_LEN_NAME); if(subghz_delete_file(subghz)) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneDeleteSuccess); } else { diff --git a/applications/subghz/scenes/subghz_scene_more_raw.c b/applications/subghz/scenes/subghz_scene_more_raw.c index 76f9234a15c..54bd0815852 100644 --- a/applications/subghz/scenes/subghz_scene_more_raw.c +++ b/applications/subghz/scenes/subghz_scene_more_raw.c @@ -45,7 +45,7 @@ bool subghz_scene_more_raw_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneDeleteRAW); return true; } else if(event.event == SubmenuIndexEdit) { - memset(subghz->file_name_tmp, 0, sizeof(subghz->file_name_tmp)); + memset(subghz->file_path_tmp, 0, sizeof(subghz->file_path_tmp)); scene_manager_set_scene_state( subghz->scene_manager, SubGhzSceneMoreRAW, SubmenuIndexEdit); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName); diff --git a/applications/subghz/scenes/subghz_scene_need_saving.c b/applications/subghz/scenes/subghz_scene_need_saving.c index 1d17976b366..ae76fbb171d 100644 --- a/applications/subghz/scenes/subghz_scene_need_saving.c +++ b/applications/subghz/scenes/subghz_scene_need_saving.c @@ -48,6 +48,8 @@ bool subghz_scene_need_saving_on_event(void* context, SceneManagerEvent event) { } else if(event.event == SubGhzCustomEventSceneExit) { if(subghz->txrx->rx_key_state == SubGhzRxKeyStateExit) { subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; + subghz->txrx->frequency = subghz_setting_get_default_frequency(subghz->setting); + subghz->txrx->preset = FuriHalSubGhzPresetOok650Async; scene_manager_search_and_switch_to_previous_scene( subghz->scene_manager, SubGhzSceneStart); } else { diff --git a/applications/subghz/scenes/subghz_scene_read_raw.c b/applications/subghz/scenes/subghz_scene_read_raw.c index 10248c357b1..257b3f0c988 100644 --- a/applications/subghz/scenes/subghz_scene_read_raw.c +++ b/applications/subghz/scenes/subghz_scene_read_raw.c @@ -23,8 +23,7 @@ bool subghz_scene_read_raw_update_filename(SubGhz* subghz) { break; } - path_extract_filename_no_ext(string_get_cstr(temp_str), temp_str); - strncpy(subghz->file_name, string_get_cstr(temp_str), SUBGHZ_MAX_LEN_NAME); + strncpy(subghz->file_path, string_get_cstr(temp_str), SUBGHZ_MAX_LEN_NAME); ret = true; } while(false); @@ -66,19 +65,23 @@ void subghz_scene_read_raw_callback_end_tx(void* context) { void subghz_scene_read_raw_on_enter(void* context) { SubGhz* subghz = context; + string_t file_name; + string_init(file_name); switch(subghz->txrx->rx_key_state) { case SubGhzRxKeyStateBack: subghz_read_raw_set_status(subghz->subghz_read_raw, SubGhzReadRAWStatusIDLE, ""); break; case SubGhzRxKeyStateRAWLoad: + path_extract_filename_no_ext(subghz->file_path, file_name); subghz_read_raw_set_status( - subghz->subghz_read_raw, SubGhzReadRAWStatusLoadKeyTX, subghz->file_name); + subghz->subghz_read_raw, SubGhzReadRAWStatusLoadKeyTX, string_get_cstr(file_name)); subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; break; case SubGhzRxKeyStateRAWSave: + path_extract_filename_no_ext(subghz->file_path, file_name); subghz_read_raw_set_status( - subghz->subghz_read_raw, SubGhzReadRAWStatusSaveKey, subghz->file_name); + subghz->subghz_read_raw, SubGhzReadRAWStatusSaveKey, string_get_cstr(file_name)); subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; break; default: @@ -86,14 +89,14 @@ void subghz_scene_read_raw_on_enter(void* context) { subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; break; } - + string_clear(file_name); subghz_scene_read_raw_update_statusbar(subghz); //set callback view raw subghz_read_raw_set_callback(subghz->subghz_read_raw, subghz_scene_read_raw_callback, subghz); - subghz->txrx->decoder_result = - subghz_receiver_search_decoder_base_by_name(subghz->txrx->receiver, "RAW"); + subghz->txrx->decoder_result = subghz_receiver_search_decoder_base_by_name( + subghz->txrx->receiver, SUBGHZ_PROTOCOL_RAW_NAME); furi_assert(subghz->txrx->decoder_result); //set filter RAW feed @@ -230,9 +233,15 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { }; subghz_protocol_raw_save_to_file_stop( (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result); - subghz_protocol_raw_gen_fff_data(subghz->txrx->fff_data, RAW_FILE_NAME); - subghz->state_notifications = SubGhzNotificationStateIDLE; + string_t temp_str; + string_init(temp_str); + string_printf( + temp_str, "%s/%s%s", SUBGHZ_RAW_FOLDER, RAW_FILE_NAME, SUBGHZ_APP_EXTENSION); + subghz_protocol_raw_gen_fff_data(subghz->txrx->fff_data, string_get_cstr(temp_str)); + string_clear(temp_str); + + subghz->state_notifications = SubGhzNotificationStateIDLE; subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey; return true; diff --git a/applications/subghz/scenes/subghz_scene_receiver.c b/applications/subghz/scenes/subghz_scene_receiver.c index 7183410b2aa..0fb073521d0 100644 --- a/applications/subghz/scenes/subghz_scene_receiver.c +++ b/applications/subghz/scenes/subghz_scene_receiver.c @@ -71,7 +71,10 @@ void subghz_scene_receiver_on_enter(void* context) { string_init(str_buff); if(subghz->txrx->rx_key_state == SubGhzRxKeyStateIDLE) { + subghz->txrx->frequency = subghz_setting_get_default_frequency(subghz->setting); + subghz->txrx->preset = FuriHalSubGhzPresetOok650Async; subghz_history_reset(subghz->txrx->history); + subghz->txrx->rx_key_state = SubGhzRxKeyStateStart; } //Load history to receiver @@ -120,8 +123,6 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { subghz_sleep(subghz); }; subghz->txrx->hopper_state = SubGhzHopperStateOFF; - subghz->txrx->frequency = subghz_setting_get_default_frequency(subghz->setting); - subghz->txrx->preset = FuriHalSubGhzPresetOok650Async; subghz->txrx->idx_menu_chosen = 0; subghz_receiver_set_rx_callback(subghz->txrx->receiver, NULL, subghz); @@ -129,6 +130,9 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { subghz->txrx->rx_key_state = SubGhzRxKeyStateExit; scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving); } else { + subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; + subghz->txrx->frequency = subghz_setting_get_default_frequency(subghz->setting); + subghz->txrx->preset = FuriHalSubGhzPresetOok650Async; scene_manager_search_and_switch_to_previous_scene( subghz->scene_manager, SubGhzSceneStart); } diff --git a/applications/subghz/scenes/subghz_scene_save_name.c b/applications/subghz/scenes/subghz_scene_save_name.c index 539eb166a3a..617709cc739 100644 --- a/applications/subghz/scenes/subghz_scene_save_name.c +++ b/applications/subghz/scenes/subghz_scene_save_name.c @@ -4,6 +4,8 @@ #include #include +#define MAX_TEXT_INPUT_LEN 22 + void subghz_scene_save_name_text_input_callback(void* context) { furi_assert(context); SubGhz* subghz = context; @@ -17,50 +19,65 @@ void subghz_scene_save_name_on_enter(void* context) { TextInput* text_input = subghz->text_input; bool dev_name_empty = false; - if(!strcmp(subghz->file_name, "")) { - set_random_name(subghz->file_name, sizeof(subghz->file_name)); + string_t file_name; + string_init(file_name); + + if(!strcmp(subghz->file_path, "")) { + char file_name_buf[SUBGHZ_MAX_LEN_NAME] = {0}; + set_random_name(file_name_buf, SUBGHZ_MAX_LEN_NAME); + string_set(file_name, file_name_buf); + strncpy(subghz->file_dir, SUBGHZ_APP_FOLDER, SUBGHZ_MAX_LEN_NAME); //highlighting the entire filename by default dev_name_empty = true; } else { - strncpy(subghz->file_name_tmp, subghz->file_name, SUBGHZ_MAX_LEN_NAME); + strncpy(subghz->file_path_tmp, subghz->file_path, SUBGHZ_MAX_LEN_NAME); + path_extract_dirname(subghz->file_path, file_name); + strncpy(subghz->file_dir, string_get_cstr(file_name), SUBGHZ_MAX_LEN_NAME); + path_extract_filename_no_ext(subghz->file_path, file_name); if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) != SubGhzCustomEventManagerNoSet) { subghz_get_next_name_file(subghz, SUBGHZ_MAX_LEN_NAME); + path_extract_filename_no_ext(subghz->file_path, file_name); if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) == SubGhzCustomEventManagerSetRAW) { dev_name_empty = true; } } } - + strncpy(subghz->file_path, string_get_cstr(file_name), SUBGHZ_MAX_LEN_NAME); text_input_set_header_text(text_input, "Name signal"); text_input_set_result_callback( text_input, subghz_scene_save_name_text_input_callback, subghz, - subghz->file_name, - SUBGHZ_MAX_LEN_NAME + 1, // buffer size + subghz->file_path, + MAX_TEXT_INPUT_LEN, // buffer size dev_name_empty); - ValidatorIsFile* validator_is_file = validator_is_file_alloc_init( - SUBGHZ_APP_FOLDER, - SUBGHZ_APP_EXTENSION, - (dev_name_empty) ? (NULL) : (subghz->file_name_tmp)); + ValidatorIsFile* validator_is_file = + validator_is_file_alloc_init(subghz->file_dir, SUBGHZ_APP_EXTENSION, NULL); text_input_set_validator(text_input, validator_is_file_callback, validator_is_file); + string_clear(file_name); + view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdTextInput); } bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) { SubGhz* subghz = context; if(event.type == SceneManagerEventTypeBack) { - strncpy(subghz->file_name, subghz->file_name_tmp, SUBGHZ_MAX_LEN_NAME); + strncpy(subghz->file_path, subghz->file_path_tmp, SUBGHZ_MAX_LEN_NAME); scene_manager_previous_scene(subghz->scene_manager); return true; } else if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubGhzCustomEventSceneSaveName) { - if(strcmp(subghz->file_name, "")) { - if(strcmp(subghz->file_name_tmp, "")) { + if(strcmp(subghz->file_path, "")) { + string_t temp_str; + string_init_printf( + temp_str, "%s/%s%s", subghz->file_dir, subghz->file_path, SUBGHZ_APP_EXTENSION); + strncpy(subghz->file_path, string_get_cstr(temp_str), SUBGHZ_MAX_LEN_NAME); + string_clear(temp_str); + if(strcmp(subghz->file_path_tmp, "")) { if(!subghz_rename_file(subghz)) { return false; } @@ -68,7 +85,7 @@ bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) { if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneSetType) != SubGhzCustomEventManagerNoSet) { subghz_save_protocol_to_file( - subghz, subghz->txrx->fff_data, subghz->file_name); + subghz, subghz->txrx->fff_data, subghz->file_path); scene_manager_set_scene_state( subghz->scene_manager, SubGhzSceneSetType, @@ -78,13 +95,13 @@ bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) { subghz, subghz_history_get_raw_data( subghz->txrx->history, subghz->txrx->idx_menu_chosen), - subghz->file_name); + subghz->file_path); } } if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) != SubGhzCustomEventManagerNoSet) { - subghz_protocol_raw_gen_fff_data(subghz->txrx->fff_data, subghz->file_name); + subghz_protocol_raw_gen_fff_data(subghz->txrx->fff_data, subghz->file_path); scene_manager_set_scene_state( subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerNoSet); } else { diff --git a/applications/subghz/scenes/subghz_scene_save_success.c b/applications/subghz/scenes/subghz_scene_save_success.c index cfd2c0bdf05..53cd93ce134 100644 --- a/applications/subghz/scenes/subghz_scene_save_success.c +++ b/applications/subghz/scenes/subghz_scene_save_success.c @@ -32,6 +32,7 @@ bool subghz_scene_save_success_on_event(void* context, SceneManagerEvent event) subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWSave; if(!scene_manager_search_and_switch_to_previous_scene( subghz->scene_manager, SubGhzSceneReadRAW)) { + subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; if(!scene_manager_search_and_switch_to_previous_scene( subghz->scene_manager, SubGhzSceneSaved)) { scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaved); diff --git a/applications/subghz/scenes/subghz_scene_transmitter.c b/applications/subghz/scenes/subghz_scene_transmitter.c index 36d8480c6e6..927686908c6 100644 --- a/applications/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/subghz/scenes/subghz_scene_transmitter.c @@ -108,6 +108,8 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { void subghz_scene_transmitter_on_exit(void* context) { SubGhz* subghz = context; - + //Restore default setting + subghz->txrx->frequency = subghz_setting_get_default_frequency(subghz->setting); + subghz->txrx->preset = FuriHalSubGhzPresetOok650Async; subghz->state_notifications = SubGhzNotificationStateIDLE; } diff --git a/applications/subghz/subghz.c b/applications/subghz/subghz.c index 5a59d89bb1e..f597adde895 100644 --- a/applications/subghz/subghz.c +++ b/applications/subghz/subghz.c @@ -242,8 +242,8 @@ void subghz_free(SubGhz* subghz) { subghz->notifications = NULL; // About birds - furi_assert(subghz->file_name[SUBGHZ_MAX_LEN_NAME] == 0); - furi_assert(subghz->file_name_tmp[SUBGHZ_MAX_LEN_NAME] == 0); + furi_assert(subghz->file_path[SUBGHZ_MAX_LEN_NAME] == 0); + furi_assert(subghz->file_path_tmp[SUBGHZ_MAX_LEN_NAME] == 0); // The rest free(subghz); @@ -260,12 +260,8 @@ int32_t subghz_app(void* p) { // Check argument and run corresponding scene if(p) { if(subghz_key_load(subghz, p)) { - string_t filename; - string_init(filename); + strncpy(subghz->file_path, p, SUBGHZ_MAX_LEN_NAME); - path_extract_filename_no_ext(p, filename); - strncpy(subghz->file_name, string_get_cstr(filename), SUBGHZ_MAX_LEN_NAME); - string_clear(filename); if((!strcmp(subghz->txrx->decoder_result->protocol->name, "RAW"))) { //Load Raw TX subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWLoad; diff --git a/applications/subghz/subghz_i.c b/applications/subghz/subghz_i.c index 60938d17592..ff22b42995d 100644 --- a/applications/subghz/subghz_i.c +++ b/applications/subghz/subghz_i.c @@ -13,7 +13,6 @@ #include #include #include -#include #define TAG "SubGhz" @@ -190,8 +189,8 @@ void subghz_tx_stop(SubGhz* subghz) { //if protocol dynamic then we save the last upload if((subghz->txrx->decoder_result->protocol->type == SubGhzProtocolTypeDynamic) && - (strcmp(subghz->file_name, ""))) { - subghz_save_protocol_to_file(subghz, subghz->txrx->fff_data, subghz->file_name); + (strcmp(subghz->file_path, ""))) { + subghz_save_protocol_to_file(subghz, subghz->txrx->fff_data, subghz->file_path); } subghz_idle(subghz); notification_message(subghz->notifications, &sequence_reset_red); @@ -277,12 +276,7 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path) { } if(!strcmp(string_get_cstr(temp_str), "RAW")) { //if RAW - string_t file_name; - string_init(file_name); - path_extract_filename_no_ext(file_path, file_name); - subghz_protocol_raw_gen_fff_data(subghz->txrx->fff_data, string_get_cstr(file_name)); - string_clear(file_name); - + subghz_protocol_raw_gen_fff_data(subghz->txrx->fff_data, file_path); } else { stream_copy_full( flipper_format_get_raw_stream(fff_data_file), @@ -329,19 +323,41 @@ bool subghz_get_next_name_file(SubGhz* subghz, uint8_t max_len) { Storage* storage = furi_record_open("storage"); string_t temp_str; + string_t file_name; + string_t file_path; + string_init(temp_str); + string_init(file_name); + string_init(file_path); + bool res = false; - if(strcmp(subghz->file_name, "")) { + if(strcmp(subghz->file_path, "")) { //get the name of the next free file + path_extract_filename_no_ext(subghz->file_path, file_name); + path_extract_dirname(subghz->file_path, file_path); + storage_get_next_filename( - storage, SUBGHZ_RAW_FOLDER, subghz->file_name, SUBGHZ_APP_EXTENSION, temp_str, max_len); + storage, + string_get_cstr(file_path), + string_get_cstr(file_name), + SUBGHZ_APP_EXTENSION, + file_name, + max_len); - strncpy(subghz->file_name, string_get_cstr(temp_str), SUBGHZ_MAX_LEN_NAME); + string_printf( + temp_str, + "%s/%s%s", + string_get_cstr(file_path), + string_get_cstr(file_name), + SUBGHZ_APP_EXTENSION); + strncpy(subghz->file_path, string_get_cstr(temp_str), SUBGHZ_MAX_LEN_NAME); res = true; } string_clear(temp_str); + string_clear(file_path); + string_clear(file_name); furi_record_close("storage"); return res; @@ -350,44 +366,40 @@ bool subghz_get_next_name_file(SubGhz* subghz, uint8_t max_len) { bool subghz_save_protocol_to_file( SubGhz* subghz, FlipperFormat* flipper_format, - const char* dev_name) { + const char* dev_file_name) { furi_assert(subghz); furi_assert(flipper_format); - furi_assert(dev_name); + furi_assert(dev_file_name); Storage* storage = furi_record_open("storage"); Stream* flipper_format_stream = flipper_format_get_raw_stream(flipper_format); - string_t dev_file_name; - string_init(dev_file_name); bool saved = false; + string_t file_dir; + string_init(file_dir); + path_extract_dirname(dev_file_name, file_dir); do { //removing additional fields flipper_format_delete_key(flipper_format, "Repeat"); flipper_format_delete_key(flipper_format, "Manufacture"); // Create subghz folder directory if necessary - if(!storage_simply_mkdir(storage, SUBGHZ_APP_FOLDER)) { + if(!storage_simply_mkdir(storage, string_get_cstr(file_dir))) { dialog_message_show_storage_error(subghz->dialogs, "Cannot create\nfolder"); break; } - // First remove subghz device file if it was saved - string_printf(dev_file_name, "%s/%s%s", SUBGHZ_APP_FOLDER, dev_name, SUBGHZ_APP_EXTENSION); - - if(!storage_simply_remove(storage, string_get_cstr(dev_file_name))) { + if(!storage_simply_remove(storage, dev_file_name)) { break; } //ToDo check Write stream_seek(flipper_format_stream, 0, StreamOffsetFromStart); - stream_save_to_file( - flipper_format_stream, storage, string_get_cstr(dev_file_name), FSOM_CREATE_ALWAYS); + stream_save_to_file(flipper_format_stream, storage, dev_file_name, FSOM_CREATE_ALWAYS); saved = true; } while(0); - - string_clear(dev_file_name); + string_clear(file_dir); furi_record_close("storage"); return saved; } @@ -395,26 +407,26 @@ bool subghz_save_protocol_to_file( bool subghz_load_protocol_from_file(SubGhz* subghz) { furi_assert(subghz); - string_t file_name; - string_init(file_name); + string_t file_path; + string_init(file_path); // Input events and views are managed by file_select bool res = dialog_file_select_show( subghz->dialogs, SUBGHZ_APP_FOLDER, SUBGHZ_APP_EXTENSION, - subghz->file_name, - sizeof(subghz->file_name), + subghz->file_path, + sizeof(subghz->file_path), NULL); if(res) { string_printf( - file_name, "%s/%s%s", SUBGHZ_APP_FOLDER, subghz->file_name, SUBGHZ_APP_EXTENSION); - - res = subghz_key_load(subghz, string_get_cstr(file_name)); + file_path, "%s/%s%s", SUBGHZ_APP_FOLDER, subghz->file_path, SUBGHZ_APP_EXTENSION); + strncpy(subghz->file_path, string_get_cstr(file_path), SUBGHZ_MAX_LEN_NAME); + res = subghz_key_load(subghz, subghz->file_path); } - string_clear(file_name); + string_clear(file_path); return res; } @@ -422,29 +434,18 @@ bool subghz_load_protocol_from_file(SubGhz* subghz) { bool subghz_rename_file(SubGhz* subghz) { furi_assert(subghz); bool ret = true; - string_t old_path; - string_t new_path; Storage* storage = furi_record_open("storage"); - string_init_printf( - old_path, "%s/%s%s", SUBGHZ_APP_FOLDER, subghz->file_name_tmp, SUBGHZ_APP_EXTENSION); - - string_init_printf( - new_path, "%s/%s%s", SUBGHZ_APP_FOLDER, subghz->file_name, SUBGHZ_APP_EXTENSION); - - if(string_cmp(old_path, new_path) != 0) { + if(strcmp(subghz->file_path_tmp, subghz->file_path)) { FS_Error fs_result = - storage_common_rename(storage, string_get_cstr(old_path), string_get_cstr(new_path)); + storage_common_rename(storage, subghz->file_path_tmp, subghz->file_path); if(fs_result != FSE_OK) { dialog_message_show_storage_error(subghz->dialogs, "Cannot rename\n file/directory"); ret = false; } } - - string_clear(old_path); - string_clear(new_path); furi_record_close("storage"); return ret; @@ -454,10 +455,7 @@ bool subghz_delete_file(SubGhz* subghz) { furi_assert(subghz); Storage* storage = furi_record_open("storage"); - string_t file_path; - string_init_printf( - file_path, "%s/%s%s", SUBGHZ_APP_FOLDER, subghz->file_name_tmp, SUBGHZ_APP_EXTENSION); - bool result = storage_simply_remove(storage, string_get_cstr(file_path)); + bool result = storage_simply_remove(storage, subghz->file_path_tmp); furi_record_close("storage"); subghz_file_name_clear(subghz); @@ -467,8 +465,8 @@ bool subghz_delete_file(SubGhz* subghz) { void subghz_file_name_clear(SubGhz* subghz) { furi_assert(subghz); - memset(subghz->file_name, 0, sizeof(subghz->file_name)); - memset(subghz->file_name_tmp, 0, sizeof(subghz->file_name_tmp)); + memset(subghz->file_path, 0, sizeof(subghz->file_path)); + memset(subghz->file_path_tmp, 0, sizeof(subghz->file_path_tmp)); } uint32_t subghz_random_serial(void) { diff --git a/applications/subghz/subghz_i.h b/applications/subghz/subghz_i.h index b2ce806c350..37d0d6ef60f 100644 --- a/applications/subghz/subghz_i.h +++ b/applications/subghz/subghz_i.h @@ -33,8 +33,9 @@ #include "subghz_setting.h" #include +#include -#define SUBGHZ_MAX_LEN_NAME 40 +#define SUBGHZ_MAX_LEN_NAME 250 /** SubGhzNotification state */ typedef enum { @@ -66,6 +67,7 @@ typedef enum { SubGhzRxKeyStateNoSave, SubGhzRxKeyStateNeedSave, SubGhzRxKeyStateBack, + SubGhzRxKeyStateStart, SubGhzRxKeyStateAddKey, SubGhzRxKeyStateExit, SubGhzRxKeyStateRAWLoad, @@ -116,8 +118,10 @@ struct SubGhz { TextInput* text_input; Widget* widget; DialogsApp* dialogs; - char file_name[SUBGHZ_MAX_LEN_NAME + 1]; - char file_name_tmp[SUBGHZ_MAX_LEN_NAME + 1]; + char file_path[SUBGHZ_MAX_LEN_NAME + 1]; + char file_path_tmp[SUBGHZ_MAX_LEN_NAME + 1]; + //ToDo you can get rid of it, you need to refactor text input to return the path to the folder + char file_dir[SUBGHZ_MAX_LEN_NAME + 1]; SubGhzNotificationState state_notifications; SubGhzViewReceiver* subghz_receiver; @@ -163,7 +167,7 @@ bool subghz_get_next_name_file(SubGhz* subghz, uint8_t max_len); bool subghz_save_protocol_to_file( SubGhz* subghz, FlipperFormat* flipper_format, - const char* dev_name); + const char* dev_file_name); bool subghz_load_protocol_from_file(SubGhz* subghz); bool subghz_rename_file(SubGhz* subghz); bool subghz_delete_file(SubGhz* subghz); diff --git a/applications/subghz/views/subghz_read_raw.c b/applications/subghz/views/subghz_read_raw.c index c5b1f09b492..bf6abc8c707 100644 --- a/applications/subghz/views/subghz_read_raw.c +++ b/applications/subghz/views/subghz_read_raw.c @@ -236,7 +236,15 @@ void subghz_read_raw_draw(Canvas* canvas, SubGhzReadRAWModel* model) { elements_button_center(canvas, "Send"); elements_button_right(canvas, "More"); elements_text_box( - canvas, 4, 12, 110, 44, AlignCenter, AlignCenter, string_get_cstr(model->file_name)); + canvas, + 4, + 20, + 110, + 30, + AlignCenter, + AlignCenter, + string_get_cstr(model->file_name), + true); break; case SubGhzReadRAWStatusTX: diff --git a/applications/updater/scenes/updater_scene_main.c b/applications/updater/scenes/updater_scene_main.c index d7b28a9db5d..31a212e7341 100644 --- a/applications/updater/scenes/updater_scene_main.c +++ b/applications/updater/scenes/updater_scene_main.c @@ -73,7 +73,7 @@ bool updater_scene_main_on_event(void* context, SceneManagerEvent event) { case UpdaterCustomEventRetryUpdate: if(!update_task_is_running(updater->update_task) && - (update_task_get_state(updater->update_task)->stage != UpdateTaskStageComplete)) + (update_task_get_state(updater->update_task)->stage != UpdateTaskStageCompleted)) update_task_start(updater->update_task); consumed = true; break; diff --git a/applications/updater/util/update_task.c b/applications/updater/util/update_task.c index 8ca5aad2116..197d42f5d3c 100644 --- a/applications/updater/util/update_task.c +++ b/applications/updater/util/update_task.c @@ -19,7 +19,8 @@ static const char* update_task_stage_descr[] = { [UpdateTaskStageRadioCommit] = "Applying radio stack", [UpdateTaskStageLfsBackup] = "Backing up LFS", [UpdateTaskStageLfsRestore] = "Restoring LFS", - [UpdateTaskStageComplete] = "Complete", + [UpdateTaskStageResourcesUpdate] = "Updating resources", + [UpdateTaskStageCompleted] = "Completed!", [UpdateTaskStageError] = "Error", }; diff --git a/applications/updater/util/update_task.h b/applications/updater/util/update_task.h index 32dea989ca0..2325824cb02 100644 --- a/applications/updater/util/update_task.h +++ b/applications/updater/util/update_task.h @@ -23,7 +23,8 @@ typedef enum { UpdateTaskStageRadioCommit, UpdateTaskStageLfsBackup, UpdateTaskStageLfsRestore, - UpdateTaskStageComplete, + UpdateTaskStageResourcesUpdate, + UpdateTaskStageCompleted, UpdateTaskStageError, } UpdateTaskStage; diff --git a/applications/updater/util/update_task_workers.c b/applications/updater/util/update_task_workers.c index fb1e86becbe..d0abbc18e7e 100644 --- a/applications/updater/util/update_task_workers.c +++ b/applications/updater/util/update_task_workers.c @@ -8,6 +8,7 @@ #include #include #include +#include #define CHECK_RESULT(x) \ if(!(x)) { \ @@ -19,6 +20,8 @@ /* Written into DFU file by build pipeline */ #define FLIPPER_ZERO_DFU_DEVICE_CODE 0xFFFF +#define EXT_PATH "/ext" + static const DfuValidationParams flipper_dfu_params = { .device = FLIPPER_ZERO_DFU_DEVICE_CODE, .product = STM_DFU_PRODUCT_ID, @@ -85,7 +88,7 @@ int32_t update_task_worker_flash_writer(void* context) { CHECK_RESULT(dfu_file_process_targets(&page_task, update_task->file, valid_targets)); } - update_task_set_progress(update_task, UpdateTaskStageComplete, 100); + update_task_set_progress(update_task, UpdateTaskStageCompleted, 100); furi_hal_rtc_set_boot_mode(FuriHalRtcBootModePostUpdate); @@ -99,6 +102,94 @@ int32_t update_task_worker_flash_writer(void* context) { return success ? UPDATE_TASK_NOERR : UPDATE_TASK_FAILED; } +static bool update_task_pre_update(UpdateTask* update_task) { + bool success = false; + string_t backup_file_path; + string_init(backup_file_path); + path_concat( + string_get_cstr(update_task->update_path), LFS_BACKUP_DEFAULT_FILENAME, backup_file_path); + + update_task->state.total_stages = 1; + update_task_set_progress(update_task, UpdateTaskStageLfsBackup, 0); + furi_hal_rtc_set_boot_mode(FuriHalRtcBootModeNormal); // to avoid bootloops + if((success = lfs_backup_create(update_task->storage, string_get_cstr(backup_file_path)))) { + furi_hal_rtc_set_boot_mode(FuriHalRtcBootModeUpdate); + } + + string_clear(backup_file_path); + return success; +} + +typedef struct { + UpdateTask* update_task; + int32_t total_files, processed_files; +} TarUnpackProgress; + +static bool update_task_resource_unpack_cb(const char* name, bool is_directory, void* context) { + UNUSED(name); + UNUSED(is_directory); + TarUnpackProgress* unpack_progress = context; + unpack_progress->processed_files++; + update_task_set_progress( + unpack_progress->update_task, + UpdateTaskStageProgress, + unpack_progress->processed_files * 100 / (unpack_progress->total_files + 1)); + return true; +} + +static bool update_task_post_update(UpdateTask* update_task) { + bool success = false; + + string_t file_path; + string_init(file_path); + + update_task->state.total_stages = 2; + + do { + CHECK_RESULT(update_task_parse_manifest(update_task)); + path_concat( + string_get_cstr(update_task->update_path), LFS_BACKUP_DEFAULT_FILENAME, file_path); + + bool unpack_resources = !string_empty_p(update_task->manifest->resource_bundle); + if(unpack_resources) { + update_task->state.total_stages++; + } + + update_task_set_progress(update_task, UpdateTaskStageLfsRestore, 0); + furi_hal_rtc_set_boot_mode(FuriHalRtcBootModeNormal); + + CHECK_RESULT(lfs_backup_unpack(update_task->storage, string_get_cstr(file_path))); + + if(unpack_resources) { + TarUnpackProgress progress = { + .update_task = update_task, + .total_files = 0, + .processed_files = 0, + }; + update_task_set_progress(update_task, UpdateTaskStageResourcesUpdate, 0); + + path_concat( + string_get_cstr(update_task->update_path), + string_get_cstr(update_task->manifest->resource_bundle), + file_path); + + TarArchive* archive = tar_archive_alloc(update_task->storage); + tar_archive_set_file_callback(archive, update_task_resource_unpack_cb, &progress); + success = tar_archive_open(archive, string_get_cstr(file_path), TAR_OPEN_MODE_READ); + if(success) { + progress.total_files = tar_archive_get_entries_count(archive); + if(progress.total_files > 0) { + tar_archive_unpack_to(archive, EXT_PATH); + } + } + tar_archive_free(archive); + } + } while(false); + + string_clear(file_path); + return success; +} + int32_t update_task_worker_backup_restore(void* context) { furi_assert(context); UpdateTask* update_task = context; @@ -112,37 +203,22 @@ int32_t update_task_worker_backup_restore(void* context) { } update_task->state.current_stage_idx = 0; - update_task->state.total_stages = 1; if(!update_operation_get_current_package_path(update_task->storage, update_task->update_path)) { return UPDATE_TASK_FAILED; } - string_t backup_file_path; - string_init(backup_file_path); - path_concat( - string_get_cstr(update_task->update_path), LFS_BACKUP_DEFAULT_FILENAME, backup_file_path); - if(boot_mode == FuriHalRtcBootModePreUpdate) { - update_task_set_progress(update_task, UpdateTaskStageLfsBackup, 0); - furi_hal_rtc_set_boot_mode(FuriHalRtcBootModeNormal); // to avoid bootloops - if((success = - lfs_backup_create(update_task->storage, string_get_cstr(backup_file_path)))) { - furi_hal_rtc_set_boot_mode(FuriHalRtcBootModeUpdate); - } + success = update_task_pre_update(update_task); } else if(boot_mode == FuriHalRtcBootModePostUpdate) { - update_task_set_progress(update_task, UpdateTaskStageLfsRestore, 0); - furi_hal_rtc_set_boot_mode(FuriHalRtcBootModeNormal); - success = lfs_backup_unpack(update_task->storage, string_get_cstr(backup_file_path)); + success = update_task_post_update(update_task); } if(success) { - update_task_set_progress(update_task, UpdateTaskStageComplete, 100); + update_task_set_progress(update_task, UpdateTaskStageCompleted, 100); } else { update_task_set_progress(update_task, UpdateTaskStageError, update_task->state.progress); } - string_clear(backup_file_path); - return success ? UPDATE_TASK_NOERR : UPDATE_TASK_FAILED; -} +} \ No newline at end of file diff --git a/assets/.gitignore b/assets/.gitignore index 3f30e22763c..0a0acede9c1 100644 --- a/assets/.gitignore +++ b/assets/.gitignore @@ -1 +1 @@ -/headers \ No newline at end of file +/headers diff --git a/assets/Makefile b/assets/Makefile index 91cc0671335..19d148fdbfa 100644 --- a/assets/Makefile +++ b/assets/Makefile @@ -3,11 +3,11 @@ PROJECT_ROOT = $(abspath $(dir $(abspath $(firstword $(MAKEFILE_LIST))))..) include $(PROJECT_ROOT)/assets/assets.mk .PHONY: all -all: icons protobuf dolphin +all: icons protobuf dolphin manifest -$(ASSETS): $(ASSETS_SOURCES) $(ASSETS_COMPILLER) +$(ASSETS): $(ASSETS_SOURCES) $(ASSETS_COMPILER) @echo "\tASSETS\t\t" $@ - @$(ASSETS_COMPILLER) icons "$(ASSETS_SOURCE_DIR)" "$(ASSETS_COMPILED_DIR)" + @$(ASSETS_COMPILER) icons "$(ASSETS_SOURCE_DIR)" "$(ASSETS_COMPILED_DIR)" .PHONY: icons icons: $(ASSETS) @@ -22,11 +22,15 @@ protobuf: $(PROTOBUF) $(DOLPHIN_EXTERNAL_OUTPUT_DIR): $(DOLPHIN_SOURCE_DIR) @echo "\tDOLPHIN blocking" - @$(ASSETS_COMPILLER) dolphin -s dolphin_blocking "$(DOLPHIN_SOURCE_DIR)/blocking" "$(DOLPHIN_INTERNAL_OUTPUT_DIR)" + @$(ASSETS_COMPILER) dolphin -s dolphin_blocking "$(DOLPHIN_SOURCE_DIR)/blocking" "$(DOLPHIN_INTERNAL_OUTPUT_DIR)" @echo "\tDOLPHIN internal" - @$(ASSETS_COMPILLER) dolphin -s dolphin_internal "$(DOLPHIN_SOURCE_DIR)/internal" "$(DOLPHIN_INTERNAL_OUTPUT_DIR)" + @$(ASSETS_COMPILER) dolphin -s dolphin_internal "$(DOLPHIN_SOURCE_DIR)/internal" "$(DOLPHIN_INTERNAL_OUTPUT_DIR)" @echo "\tDOLPHIN external" - @$(ASSETS_COMPILLER) dolphin "$(DOLPHIN_SOURCE_DIR)/external" "$(DOLPHIN_EXTERNAL_OUTPUT_DIR)" + @$(ASSETS_COMPILER) dolphin "$(DOLPHIN_SOURCE_DIR)/external" "$(DOLPHIN_EXTERNAL_OUTPUT_DIR)" + +.PHONY: manifest +manifest: + $(ASSETS_COMPILER) manifest $(RESOURCES_DIR) .PHONY: dolphin dolphin: $(DOLPHIN_EXTERNAL_OUTPUT_DIR) diff --git a/assets/assets.mk b/assets/assets.mk index 55783ec8bba..18e0a244c93 100644 --- a/assets/assets.mk +++ b/assets/assets.mk @@ -1,11 +1,15 @@ ASSETS_DIR := $(PROJECT_ROOT)/assets -ASSETS_COMPILLER := $(PROJECT_ROOT)/scripts/assets.py +ASSETS_COMPILER := $(PROJECT_ROOT)/scripts/assets.py ASSETS_COMPILED_DIR := $(ASSETS_DIR)/compiled ASSETS_SOURCE_DIR := $(ASSETS_DIR)/icons ASSETS_SOURCES += $(shell find $(ASSETS_SOURCE_DIR) -type f -iname '*.png' -or -iname 'frame_rate') ASSETS += $(ASSETS_COMPILED_DIR)/assets_icons.c +RESOURCES_DIR := $(ASSETS_DIR)/resources +RESOURCES_MANIFEST := $(RESOURCES_DIR)/Manifest +RESOURCES_FILES := $(shell find $(RESOURCES_DIR) ! -name Manifest -type f) + DOLPHIN_SOURCE_DIR := $(ASSETS_DIR)/dolphin DOLPHIN_INTERNAL_OUTPUT_DIR := $(ASSETS_COMPILED_DIR) DOLPHIN_EXTERNAL_OUTPUT_DIR := $(ASSETS_DIR)/resources/dolphin diff --git a/assets/compiled/assets_dolphin_blocking.c b/assets/compiled/assets_dolphin_blocking.c index d2b9b297b61..a1ec14b421c 100644 --- a/assets/compiled/assets_dolphin_blocking.c +++ b/assets/compiled/assets_dolphin_blocking.c @@ -156,19 +156,19 @@ const BubbleAnimation BA_L0_SdOk_128x51 = { const uint8_t _A_L0_Url_128x51_0[] = { - 0x1,0x0,0x33,0x1,0x0,0x78,0x3,0xc0,0x1e,0x0,0xf8,0x7,0xfc,0x0,0x33,0xf0,0x75,0x60,0x1,0xe5,0x7f,0x7,0xde,0x4e,0x49,0x49,0xb9,0x3,0xfc,0x16,0xf0,0x38,0x80,0x3f,0x28,0x10,0x40,0x7f,0x58,0x27,0x10,0x32,0x7d,0xd0,0x32,0xd9,0x8,0x20,0x3f,0x32,0x80,0xff,0x7,0xee,0x2,0xc7,0x10,0x1f,0xe2,0x7f,0xc1,0xfe,0xf,0xf0,0x7f,0x83,0xd6,0xe,0xf,0x29,0xf0,0x20,0x60,0x30,0x1d,0x40,0x10,0x8e,0x63,0xff,0xfc,0xff,0x1,0xe3,0x47,0x7,0x9c,0x90,0x1e,0x7a,0xf,0xfe,0x3b,0xf7,0x7f,0xc0,0x6b,0xa9,0x1c,0x7d,0xcc,0xcf,0x49,0xce,0xe0,0xe6,0x60,0x9d,0xb,0xff,0xef,0xee,0xf,0x1d,0xe5,0x22,0x53,0x25,0xa4,0xeb,0x2a,0x52,0x2d,0x2c,0x13,0xe1,0xbf,0xfe,0xfb,0xc1,0xe3,0x8f,0x7,0x95,0xe7,0x48,0xf,0x1d,0xe8,0x3c,0xbf,0xe0,0xf2,0xcf,0x3,0xca,0x12,0xf,0x2c,0x28,0x3c,0x7b,0xf1,0xfe,0xf8,0x3c,0x7b,0xd7,0xe,0x3c,0xe6,0x63,0xa5,0xe7,0x72,0x63,0x30,0x30,0x78,0xfb,0xfb,0xc5,0xf1,0x0,0x89,0x64,0x40,0x3,0x42,0x1,0x90,0x3c,0x7f,0xe0,0xf2,0x3f,0x88,0x3d,0xf8,0x2,0xd1,0x0,0x8a,0x7e,0x81,0xe3,0xbf,0x7,0xe9,0x7c,0xc1,0xf9,0xbf,0x7,0xc7,0xe1,0xb4,0x30,0x1a,0x5,0xff,0xff,0xe7,0x7,0xbc,0x18,0x4,0x30,0x25,0xf8,0xff,0xb8,0x60,0xf7,0x81,0x80,0x85,0x7e,0x2d,0xf1,0xc0,0x3,0xef,0xe0,0xff,0x18,0x38,0x3d,0xf8,0x78,0x98,0x40,0x3c,0xbf,0xf0,0xfb,0xf0,0x3d,0xa4,0x74,0xa8,0xc0,0x3c,0xe3,0xf7,0xc0,0x7b,0xca,0xa7,0x0,0xf3,0x9f,0xde,0x1,0xef,0x1a,0xbc,0x3,0xce,0xfe,0xf,0x80,0xfa,0xff,0xc1,0xf0,0x3f,0x51,0x0,0x97,0xf4,0x1f,0x7,0xf5,0x7,0xf8,0x3e,0x60,0xeb,0xf2,0x7,0xdf,0xf9,0xbe,0x5e,0x0,0x79,0x4f,0xc1,0xed,0xfc,0x5,0x8,0x25,0x80,0x1e,0x0,0xf0,0x7,0x80,0x24 + 0x1,0x0,0x2d,0x1,0x0,0x78,0x3,0xc0,0x1e,0x0,0xf8,0x7,0xfc,0x0,0x33,0xf0,0x75,0x60,0x1,0xe5,0x7f,0x7,0xde,0x4e,0x49,0x49,0xb9,0x3,0xfc,0x16,0xf0,0x38,0x80,0x3f,0x28,0x10,0x40,0x7f,0x58,0x27,0x10,0x32,0x7d,0xd0,0x32,0xd9,0x8,0x20,0x3f,0x32,0x80,0xff,0x7,0xee,0x2,0xc7,0x10,0x1f,0xe2,0x7f,0xc1,0xfe,0xf,0xf0,0x7d,0x7e,0x1,0x89,0x4,0x7,0x9c,0x1c,0x1e,0x71,0xca,0xc,0x16,0x1,0x8,0x7,0x94,0xa,0x81,0xff,0xfc,0xff,0x1,0xe5,0xba,0x91,0x40,0x41,0xe5,0x2,0x0,0x8e,0x83,0xff,0x8e,0xfd,0x83,0xcb,0xe5,0x22,0xba,0xc3,0xb9,0xd2,0x4c,0x96,0x3a,0x7,0xd0,0xbf,0xfe,0xfe,0xe0,0xf2,0x9f,0x58,0xb2,0xb1,0x29,0x4c,0x97,0x23,0x52,0x81,0x7c,0x37,0xff,0xdf,0x78,0x3c,0xaf,0x52,0x20,0x78,0xfa,0x41,0xeb,0xff,0x7,0xa4,0x8c,0x3e,0x5a,0x4c,0x80,0x3c,0xbb,0xf1,0xfe,0xf8,0x3c,0xbf,0x92,0x1b,0xad,0x3b,0x9d,0x98,0xf0,0xf,0xc4,0x1e,0x3e,0xfe,0xf1,0xfd,0x22,0x5,0xc1,0x0,0x8,0xc,0x41,0xe3,0xff,0x7,0x98,0x0,0x41,0xed,0xc0,0x16,0x88,0xbc,0xc0,0x10,0xf,0x1d,0xf8,0x3f,0x4b,0xea,0xf,0xad,0xf8,0x3e,0x3f,0xd,0xa1,0x80,0xd0,0x2f,0xff,0xff,0x38,0x3d,0xe0,0xc5,0x2,0x5f,0x8f,0xfb,0x86,0xf,0x78,0x1b,0xc4,0xba,0xd,0xf1,0xc0,0x3,0xef,0xe0,0xff,0x18,0x38,0x3d,0xf8,0x78,0x98,0x40,0x3c,0xbf,0xf0,0xfb,0xf0,0x3d,0xa4,0x74,0xa8,0xc0,0x3c,0xe3,0xf7,0xc0,0x7b,0xca,0xa7,0x0,0xf3,0x9f,0xde,0x1,0xef,0x1a,0xbc,0x3,0xce,0xfe,0xf,0x80,0xfa,0xff,0xc1,0xf0,0x3f,0x51,0x0,0x97,0xf4,0x1f,0x7,0xf5,0x7,0xf8,0x3e,0x60,0xeb,0xf2,0x7,0xdf,0xf9,0xbe,0x5e,0x0,0x79,0x4f,0xc1,0xed,0xfc,0x5,0x8,0x25,0x80,0x1e,0x0,0xf0,0x7,0x80,0x24 }; const uint8_t _A_L0_Url_128x51_1[] = { - 0x1,0x0,0x33,0x1,0x0,0x78,0x3,0xc0,0x1e,0x0,0xf8,0x7,0xfc,0x0,0x33,0xf0,0x75,0x60,0x1,0xe5,0x7f,0x7,0xde,0x4e,0x49,0x49,0xb9,0x3,0xfc,0x16,0xf0,0x38,0x80,0x3f,0x28,0x10,0x40,0x7f,0x58,0x27,0x10,0x32,0x7d,0xd0,0x32,0xd9,0x8,0x20,0x3f,0x32,0x80,0xff,0x7,0xee,0x2,0xc7,0x10,0x1f,0xe2,0x7f,0xc1,0xfe,0xf,0xf0,0x7f,0x83,0xd6,0x3f,0xfc,0x7,0x8c,0xf8,0x10,0x30,0x18,0xe,0xa0,0x8,0x47,0x31,0xff,0xf9,0xfe,0x60,0xf1,0xa3,0x83,0xce,0x48,0xf,0x3d,0x7,0xfe,0x77,0xee,0xbf,0xe0,0x35,0xd4,0x8e,0x3e,0xe6,0x67,0xa4,0xe7,0x70,0x73,0x30,0x4e,0x87,0xff,0xdb,0xdf,0x7,0x8e,0xf2,0x91,0x29,0x92,0xd2,0x75,0x95,0x29,0x16,0x96,0x9,0xf0,0xff,0xfd,0xb7,0xe0,0xf1,0xc7,0x83,0xca,0xf3,0xa4,0x7,0x8e,0xf4,0x1e,0x5f,0xe0,0x79,0x67,0x81,0xe5,0x9,0x7,0x96,0x14,0x1e,0x37,0xf8,0xfd,0xfc,0x1e,0x3d,0xeb,0x87,0x1e,0x73,0x31,0xd2,0xf3,0xb9,0x31,0x98,0x18,0x3c,0x7d,0xf7,0xe2,0xf8,0x80,0x44,0xb2,0x20,0x1,0xa1,0x0,0xc8,0x1e,0x3f,0xf0,0x79,0x1f,0xc4,0x1e,0xfc,0x1,0x68,0x80,0x5,0x3f,0x40,0xf1,0x27,0x8,0x3f,0xb,0xe6,0xf,0xcd,0xf0,0x3e,0x3f,0xd,0xa1,0x80,0xaf,0xc7,0xfb,0x9f,0x7,0xbc,0x18,0x4,0x30,0x25,0xf8,0xfe,0xe1,0xe0,0xf7,0x81,0x80,0x85,0x7e,0x5e,0x78,0x1d,0xf8,0x1f,0x4a,0xf1,0x8f,0xc7,0x2f,0x80,0xf6,0xe1,0xe2,0x61,0x0,0xf2,0xff,0xcf,0xef,0x0,0xf6,0x91,0xd2,0xa3,0x0,0xf3,0xbf,0xdc,0x1,0xef,0x2a,0x9c,0x3,0xcf,0xff,0x60,0x7,0xbc,0x6a,0xf0,0xf,0x4b,0x8,0x7f,0xac,0x63,0xfd,0x20,0x9,0x7f,0x41,0xf0,0x7f,0x50,0x7f,0x83,0xe6,0xe,0xbf,0x20,0x7d,0xff,0x9b,0xe5,0xe0,0x7,0x94,0xfc,0x1e,0xdf,0xc0,0x50,0x82,0x58,0x1,0xe0,0xf,0x0,0x78,0x2,0x40 + 0x1,0x0,0x2d,0x1,0x0,0x78,0x3,0xc0,0x1e,0x0,0xf8,0x7,0xfc,0x0,0x33,0xf0,0x75,0x60,0x1,0xe5,0x7f,0x7,0xde,0x4e,0x49,0x49,0xb9,0x3,0xfc,0x16,0xf0,0x38,0x80,0x3f,0x28,0x10,0x40,0x7f,0x58,0x27,0x10,0x32,0x7d,0xd0,0x32,0xd9,0x8,0x20,0x3f,0x32,0x80,0xff,0x7,0xee,0x2,0xc7,0x10,0x1f,0xe2,0x7f,0xc1,0xfe,0xf,0xf0,0x7d,0x7e,0x1,0x89,0x4,0x7,0x9c,0x7f,0xf8,0xf,0x28,0xe5,0x6,0xb,0x0,0x84,0x3,0xca,0x5,0x40,0xff,0xf9,0xfe,0x60,0xf2,0xdd,0x48,0xa0,0x20,0xf2,0x81,0x0,0x47,0x41,0xff,0x9d,0xfb,0x81,0xe5,0xf2,0x91,0x5d,0x61,0xdc,0xe9,0x26,0x4b,0x1d,0x3,0xe8,0x7f,0xfd,0xbd,0xf0,0x79,0x4f,0xac,0x59,0x58,0x94,0xa6,0x4b,0x91,0xa9,0x40,0xbe,0x1f,0xff,0xb6,0xfc,0x1e,0x57,0xa9,0x10,0x3c,0x7d,0x20,0xf5,0xff,0x3,0xd2,0x46,0x1f,0x2d,0x26,0x40,0x1e,0x57,0xf8,0xfd,0xfc,0x1e,0x5f,0xc9,0xd,0xd6,0x9d,0xce,0xcc,0x78,0x7,0xe2,0xf,0x1f,0x7d,0xf8,0xfe,0x91,0x2,0xe0,0x80,0x4,0x6,0x20,0xf1,0xff,0x83,0xcc,0x0,0x20,0xf6,0xe0,0xb,0x44,0x5e,0x60,0x8,0x7,0x89,0x38,0x41,0xf8,0x5f,0x50,0x7d,0x6f,0x81,0xf1,0xf8,0x6d,0xc,0x5,0x7e,0x3f,0xdc,0xf8,0x3d,0xe0,0xc5,0x2,0x5f,0x8f,0xee,0x1e,0xf,0x78,0x1b,0xc4,0x97,0xe3,0xe7,0x81,0xdf,0x81,0xf4,0xaf,0x18,0xfc,0x72,0xf8,0xf,0x6e,0x1e,0x26,0x10,0xf,0x2f,0xfc,0xfe,0xf0,0xf,0x69,0x1d,0x2a,0x30,0xf,0x3b,0xfd,0xc0,0x1e,0xf2,0xa9,0xc0,0x3c,0xff,0xf6,0x0,0x7b,0xc6,0xaf,0x0,0xf4,0xb0,0x87,0xfa,0xc6,0x3f,0xd2,0x0,0x97,0xf4,0x1f,0x7,0xf5,0x7,0xf8,0x3e,0x60,0xeb,0xf2,0x7,0xdf,0xf9,0xbe,0x5e,0x0,0x79,0x4f,0xc1,0xed,0xfc,0x5,0x8,0x25,0x80,0x1e,0x0,0xf0,0x7,0x80,0x24 }; const uint8_t _A_L0_Url_128x51_2[] = { - 0x1,0x0,0x2e,0x1,0x0,0x78,0x3,0xc0,0x1e,0x0,0xf8,0x7,0xfc,0x0,0x33,0xf0,0x75,0x60,0x1,0xe5,0x7f,0x7,0xde,0x4e,0x49,0x49,0xb9,0x3,0xfc,0x16,0xf0,0x38,0x80,0x3f,0x28,0x10,0x40,0x7f,0x58,0x27,0x10,0x32,0x7d,0xd0,0x32,0xd9,0x8,0x20,0x3f,0x32,0x80,0xff,0x7,0xee,0x2,0xc7,0x10,0x1f,0xe2,0x7f,0xc1,0xfe,0xf,0xf0,0x7f,0x83,0xe6,0x7c,0x8,0x18,0xc,0x7,0x50,0x4,0x23,0x98,0x83,0xd2,0x8e,0xf,0x39,0x20,0x3c,0xf4,0x1f,0xf8,0xff,0xf2,0xff,0x80,0xd7,0x52,0x38,0xfb,0x99,0x9e,0x93,0x9d,0xc1,0xcc,0xc1,0x3a,0x1f,0xff,0x3f,0xcc,0x1e,0x3b,0xca,0x44,0xa6,0x4b,0x49,0xd6,0x54,0xa4,0x5a,0x58,0x27,0xc3,0xff,0x3b,0xf7,0x3,0xc7,0x1e,0xf,0x2b,0xce,0x90,0x1e,0x3b,0xd0,0x79,0x7b,0x7b,0xe0,0xf1,0xcf,0x3,0xca,0x12,0xf,0x2c,0x28,0x3c,0xa2,0xdb,0xf0,0x78,0xf7,0xae,0x1c,0x79,0xcc,0xc7,0x4b,0xce,0xe4,0xc6,0x60,0x60,0xf1,0xf7,0x6f,0x8b,0xe2,0x1,0x12,0xc8,0x80,0x6,0x84,0x3,0x2f,0x85,0xff,0xff,0x7e,0x3f,0x98,0x3d,0xf8,0x17,0xf0,0x1,0x27,0xe8,0x1e,0x23,0xe1,0x7,0xea,0x78,0x43,0xfe,0xf,0x7f,0xc2,0xe8,0x60,0x2b,0xf1,0xff,0x4,0x4,0x1e,0xd0,0x60,0x10,0xc0,0x97,0xe2,0xf,0x98,0x18,0x8,0x57,0xe5,0xfd,0xcf,0x83,0xed,0x1e,0x3f,0xb8,0x78,0x3d,0xf8,0x78,0x98,0x40,0x3c,0xbc,0xf0,0x3b,0xf0,0x3d,0xa4,0x74,0xa8,0xc0,0x3c,0xa3,0xf1,0xcb,0xe0,0x3d,0xe5,0x53,0x80,0x79,0x7f,0xe7,0xf7,0x80,0x7b,0xc6,0xaf,0x0,0xf3,0xbf,0xdc,0x3,0xfb,0xff,0xb0,0xf,0xf0,0x0,0x36,0x12,0xfe,0x0,0x6,0xc6,0x7f,0xc2,0x1,0x3,0xfc,0x1e,0xd0,0x75,0xf9,0x3,0xef,0xfc,0xdf,0x2f,0x0,0x3c,0xa7,0xe0,0xf6,0xfe,0x2,0x84,0x12,0xc0,0xf,0x0,0x78,0x3,0xc0,0x12 + 0x1,0x0,0x29,0x1,0x0,0x78,0x3,0xc0,0x1e,0x0,0xf8,0x7,0xfc,0x0,0x33,0xf0,0x75,0x60,0x1,0xe5,0x7f,0x7,0xde,0x4e,0x49,0x49,0xb9,0x3,0xfc,0x16,0xf0,0x38,0x80,0x3f,0x28,0x10,0x40,0x7f,0x58,0x27,0x10,0x32,0x7d,0xd0,0x32,0xd9,0x8,0x20,0x3f,0x32,0x80,0xff,0x7,0xee,0x2,0xc7,0x10,0x1f,0xe2,0x7f,0xc1,0xfe,0xf,0xf0,0x7d,0x7e,0x1,0x89,0x4,0x7,0xc4,0x72,0x83,0x5,0x80,0x42,0x1,0xe5,0x2,0xa0,0x3,0xd7,0x75,0x22,0x80,0x83,0xca,0x4,0x1,0x1d,0x7,0xfe,0x3f,0xfc,0x7,0x97,0xca,0x45,0x75,0x87,0x73,0xa4,0x99,0x2c,0x74,0xf,0xa1,0xff,0xf3,0xfc,0xc1,0xe5,0x3e,0xb1,0x65,0x62,0x52,0x99,0x2e,0x46,0xa5,0x2,0xf8,0x7f,0xe7,0x7e,0xe0,0x79,0x5e,0xa4,0x40,0xf1,0xf4,0x83,0xd7,0xdb,0xdf,0x7,0x9c,0x8c,0x3e,0x5a,0x4c,0x80,0x3c,0xe2,0xdb,0xf0,0x79,0x7f,0x24,0x37,0x5a,0x77,0x3b,0x31,0xe0,0x1f,0x88,0x3c,0x7d,0xdb,0xe3,0xfa,0x44,0xb,0x82,0x0,0x10,0x18,0xfc,0x2f,0xff,0xfb,0xf2,0x7d,0x1,0xed,0xc0,0xbf,0x80,0x9,0x5f,0x40,0xf1,0x1f,0x8,0x3f,0x53,0xc2,0x1f,0xf0,0x7b,0xfe,0x17,0x43,0x1,0x5f,0x8f,0xf8,0xde,0x60,0x4,0x83,0x14,0x9,0x7e,0x20,0xf9,0x81,0xbc,0x49,0x7e,0x3f,0xdc,0xf8,0x3e,0xd1,0xe3,0xfb,0x87,0x83,0xdf,0x87,0x89,0x84,0x3,0xcb,0xcf,0x3,0xbf,0x3,0xda,0x47,0x4a,0x8c,0x3,0xca,0x3f,0x1c,0xbe,0x3,0xde,0x55,0x38,0x7,0x97,0xfe,0x7f,0x78,0x7,0xbc,0x6a,0xf0,0xf,0x3b,0xfd,0xc0,0x3f,0xbf,0xfb,0x0,0xff,0x0,0x3,0x61,0x2f,0xe0,0x0,0x6c,0x67,0xfc,0x20,0x10,0x3f,0xc1,0xed,0x7,0x5f,0x90,0x3e,0xff,0xcd,0xf2,0xf0,0x3,0xca,0x7e,0xf,0x6f,0xe0,0x28,0x41,0x2c,0x0,0xf0,0x7,0x80,0x3c,0x1,0x20 }; const uint8_t _A_L0_Url_128x51_3[] = { - 0x1,0x0,0x31,0x1,0x0,0x78,0x3,0xc0,0x1e,0x0,0xf8,0x7,0xfc,0x0,0x33,0xf0,0x75,0x60,0x1,0xe5,0x7f,0x7,0xde,0x4e,0x49,0x49,0xb9,0x3,0xfc,0x16,0xf0,0x38,0x80,0x3f,0x28,0x10,0x40,0x7f,0x58,0x27,0x10,0x32,0x7d,0xd0,0x32,0xd9,0x8,0x20,0x3f,0x32,0x80,0xff,0x7,0xee,0x2,0xc7,0x10,0x1f,0xe2,0x7f,0xc1,0xfe,0xf,0xf0,0x7f,0x83,0xe6,0x7c,0x8,0x18,0xc,0x7,0x50,0x4,0x23,0x98,0x83,0xd2,0x8e,0xf,0x39,0x20,0x3c,0xf4,0x1f,0xf8,0x38,0x3c,0x70,0x1a,0xea,0x47,0x1f,0x73,0x33,0xd2,0x73,0xb8,0x39,0x98,0x27,0x43,0xff,0xf9,0xfe,0x3,0xc7,0x79,0x48,0x94,0xc9,0x69,0x3a,0xca,0x94,0x8b,0x4b,0x4,0xf8,0x7f,0xf1,0xdf,0xb0,0x78,0xe3,0xc1,0xe5,0x79,0xd2,0x3,0xc7,0x7a,0xf,0x1b,0xff,0xef,0xee,0xf,0x1c,0xf0,0x3c,0xa1,0x20,0xf2,0xc2,0x83,0xc7,0x7f,0x1d,0xf7,0x83,0xc7,0xbd,0x70,0xe3,0xce,0x66,0x3a,0x5e,0x77,0x26,0x33,0x3,0x7,0x8f,0xbf,0xdc,0x5f,0x10,0x8,0x96,0x44,0x0,0x34,0x20,0x19,0x7c,0x3b,0xff,0xfe,0xf1,0xfc,0xc1,0xef,0xc0,0xef,0xdf,0xc0,0x22,0x9f,0xa0,0x78,0xef,0xc1,0xfd,0xff,0xf,0xf8,0x3e,0x3f,0xb,0xa1,0x80,0xd0,0x37,0xff,0xf3,0x78,0x83,0xda,0xc,0x2,0x18,0x16,0x80,0x1f,0x50,0x30,0x10,0xaf,0xc6,0xff,0xff,0xf3,0x83,0xed,0x7e,0x3f,0xee,0x18,0x3d,0xf8,0x78,0x98,0x40,0x3c,0xbf,0x38,0x0,0x7b,0xc8,0xe9,0x51,0x80,0x79,0x41,0xe0,0xe0,0xf8,0x95,0x4e,0x1,0xe5,0xff,0x87,0xdf,0x81,0xef,0x1a,0xbc,0x3,0xce,0x3f,0x7c,0xf,0xec,0xfe,0xf0,0x3f,0xcf,0xfd,0xfc,0x1e,0xe5,0xf5,0x0,0x8,0x3d,0xcf,0xea,0x20,0x20,0x7f,0x83,0xda,0xe,0xbf,0x20,0x7d,0xff,0x9b,0xe5,0xe0,0x7,0x94,0xfc,0x1e,0xdf,0xc0,0x50,0x82,0x58,0x1,0xe0,0xf,0x0,0x78,0x2,0x40 + 0x1,0x0,0x2a,0x1,0x0,0x78,0x3,0xc0,0x1e,0x0,0xf8,0x7,0xfc,0x0,0x33,0xf0,0x75,0x60,0x1,0xe5,0x7f,0x7,0xde,0x4e,0x49,0x49,0xb9,0x3,0xfc,0x16,0xf0,0x38,0x80,0x3f,0x28,0x10,0x40,0x7f,0x58,0x27,0x10,0x32,0x7d,0xd0,0x32,0xd9,0x8,0x20,0x3f,0x32,0x80,0xff,0x7,0xee,0x2,0xc7,0x10,0x1f,0xe2,0x7f,0xc1,0xfe,0xf,0xf0,0x7d,0x7e,0x1,0x89,0x4,0x7,0xc4,0x72,0x83,0x5,0x80,0x42,0x1,0xe5,0x2,0xa0,0x3,0xd7,0x75,0x22,0x80,0x83,0xca,0x4,0x1,0x1d,0x7,0xfe,0xe,0xf,0x3f,0x94,0x8a,0xeb,0xe,0xe7,0x49,0x32,0x58,0xe8,0x1f,0x43,0xff,0xf9,0xfe,0x3,0xca,0x7d,0x62,0xca,0xc4,0xa5,0x32,0x5c,0x8d,0x4a,0x5,0xf0,0xff,0xe3,0xbf,0x60,0xf2,0xbd,0x48,0x81,0xe3,0xe9,0x7,0xa5,0xff,0xf7,0xf7,0x7,0x9c,0x8c,0x3e,0x5a,0x4c,0x80,0x3c,0xb7,0xf1,0xdf,0x78,0x3c,0xbf,0x92,0x1b,0xad,0x3b,0x9d,0x98,0xf0,0xf,0xc4,0x1e,0x3e,0xff,0x71,0xfd,0x22,0x5,0xc1,0x0,0x8,0xc,0x7e,0x1d,0xff,0xff,0x79,0x3e,0x80,0xf6,0xe0,0x77,0xef,0xe0,0x11,0x57,0xd0,0x3c,0x77,0xe0,0xfe,0xff,0x87,0xfc,0x1f,0x1f,0x85,0xd0,0xc0,0x68,0x1b,0xff,0xf9,0xbc,0xc0,0x9,0x6,0x28,0x16,0x80,0x1f,0x50,0x37,0x89,0x74,0x2f,0xff,0xff,0x38,0x3e,0xd7,0xe3,0xfe,0xe1,0x83,0xdf,0x87,0x89,0x84,0x3,0xcb,0xf3,0x80,0x7,0xbc,0x8e,0x95,0x18,0x7,0x94,0x1e,0xe,0xf,0x89,0x54,0xe0,0x1e,0x5f,0xf8,0x7d,0xf8,0x1e,0xf1,0xab,0xc0,0x3c,0xe3,0xf7,0xc0,0xfe,0xcf,0xef,0x3,0xfc,0xff,0xdf,0xc1,0xee,0x5f,0x50,0x0,0x83,0xdc,0xfe,0xa2,0x2,0x7,0xf8,0x3d,0xa0,0xeb,0xf2,0x7,0xdf,0xf9,0xbe,0x5e,0x0,0x79,0x4f,0xc1,0xed,0xfc,0x5,0x8,0x25,0x80,0x1e,0x0,0xf0,0x7,0x80,0x24 }; diff --git a/assets/compiled/protobuf_version.h b/assets/compiled/protobuf_version.h index 53e0b73bf7f..0459d12060e 100644 --- a/assets/compiled/protobuf_version.h +++ b/assets/compiled/protobuf_version.h @@ -1,3 +1,3 @@ #pragma once #define PROTOBUF_MAJOR_VERSION 0 -#define PROTOBUF_MINOR_VERSION 5 +#define PROTOBUF_MINOR_VERSION 6 diff --git a/assets/dolphin/blocking/L0_Url_128x51/frame_0.png b/assets/dolphin/blocking/L0_Url_128x51/frame_0.png index 276f70e577b..5d4b5cf2e22 100644 Binary files a/assets/dolphin/blocking/L0_Url_128x51/frame_0.png and b/assets/dolphin/blocking/L0_Url_128x51/frame_0.png differ diff --git a/assets/dolphin/blocking/L0_Url_128x51/frame_1.png b/assets/dolphin/blocking/L0_Url_128x51/frame_1.png index 07adf2e75b2..69f1fb36598 100644 Binary files a/assets/dolphin/blocking/L0_Url_128x51/frame_1.png and b/assets/dolphin/blocking/L0_Url_128x51/frame_1.png differ diff --git a/assets/dolphin/blocking/L0_Url_128x51/frame_2.png b/assets/dolphin/blocking/L0_Url_128x51/frame_2.png index 9abf98d8b3a..855e7450e53 100644 Binary files a/assets/dolphin/blocking/L0_Url_128x51/frame_2.png and b/assets/dolphin/blocking/L0_Url_128x51/frame_2.png differ diff --git a/assets/dolphin/blocking/L0_Url_128x51/frame_3.png b/assets/dolphin/blocking/L0_Url_128x51/frame_3.png index 7609c001767..9e9a7940581 100644 Binary files a/assets/dolphin/blocking/L0_Url_128x51/frame_3.png and b/assets/dolphin/blocking/L0_Url_128x51/frame_3.png differ diff --git a/assets/dolphin/blocking/L0_Url_128x51/meta.txt b/assets/dolphin/blocking/L0_Url_128x51/meta.txt index 2c8d9871cec..f1c9925ed04 100644 --- a/assets/dolphin/blocking/L0_Url_128x51/meta.txt +++ b/assets/dolphin/blocking/L0_Url_128x51/meta.txt @@ -11,4 +11,4 @@ Frame rate: 2 Duration: 0 Active cooldown: 0 -Bubble slots: 0 +Bubble slots: 0 \ No newline at end of file diff --git a/assets/resources/Manifest b/assets/resources/Manifest new file mode 100644 index 00000000000..12773c00af7 --- /dev/null +++ b/assets/resources/Manifest @@ -0,0 +1,240 @@ +V:0 +T:1650389893 +D:badusb +D:dolphin +D:infrared +D:nfc +D:subghz +D:u2f +F:bb8ffef2d052f171760ce3dc5220cbad:1591:badusb/demo_macos.txt +F:e538ad2ce5a06ec45e1b5b24824901b1:1552:badusb/demo_windows.txt +D:dolphin/L1_Boxing_128x64 +D:dolphin/L1_Cry_128x64 +D:dolphin/L1_Furippa1_128x64 +D:dolphin/L1_Laptop_128x51 +D:dolphin/L1_Leaving_sad_128x64 +D:dolphin/L1_Mad_fist_128x64 +D:dolphin/L1_Read_books_128x64 +D:dolphin/L1_Recording_128x51 +D:dolphin/L1_Sleep_128x64 +D:dolphin/L1_Waves_128x50 +D:dolphin/L2_Furippa2_128x64 +D:dolphin/L2_Hacking_pc_128x64 +D:dolphin/L2_Soldering_128x64 +D:dolphin/L3_Furippa3_128x64 +D:dolphin/L3_Hijack_radio_128x64 +D:dolphin/L3_Lab_research_128x54 +F:d1148ab5354eaf4fa7f959589d840932:1563:dolphin/manifest.txt +F:d37be8444102ec5cde5fe3a85d55b57d:481:dolphin/L1_Boxing_128x64/frame_0.bm +F:54fb07443bc153ded9589b74d23b4263:461:dolphin/L1_Boxing_128x64/frame_1.bm +F:e007afe130d699c715b99ce8e5b407bd:531:dolphin/L1_Boxing_128x64/frame_2.bm +F:a999a9a6c76c66158f1aa5ccb56de7c9:437:dolphin/L1_Boxing_128x64/frame_3.bm +F:ec6af9cb451ab16c0fa62e95e8134b49:459:dolphin/L1_Boxing_128x64/frame_4.bm +F:2aa0c1e7bf1131b9dc172aa595ec01f2:450:dolphin/L1_Boxing_128x64/frame_5.bm +F:bbc8f750d17d156438c5cfe1122ec7f4:442:dolphin/L1_Boxing_128x64/frame_6.bm +F:f6e51ada3e3285e330714dab5b4277dd:418:dolphin/L1_Boxing_128x64/meta.txt +F:ab33a6f37209541f3db938d1cfe1706f:889:dolphin/L1_Cry_128x64/frame_0.bm +F:1b3fdeb404af0f7402caa5a5e091a8f8:911:dolphin/L1_Cry_128x64/frame_1.bm +F:4db644b173af72f3d371d2bd81f76b05:910:dolphin/L1_Cry_128x64/frame_2.bm +F:cd4c0ef67a8e514edecd9600242db068:923:dolphin/L1_Cry_128x64/frame_3.bm +F:ee02e9589e0714d3e2bc0d93aa294ccb:894:dolphin/L1_Cry_128x64/frame_4.bm +F:7703a7d9745d13b45d73ce4b86b4cdc8:940:dolphin/L1_Cry_128x64/frame_5.bm +F:ee6de6a0ed903317c4948cb445e0a9a8:915:dolphin/L1_Cry_128x64/frame_6.bm +F:a3892e45826c66f48d3d64fb81521446:934:dolphin/L1_Cry_128x64/frame_7.bm +F:680b12cc4dad722d6583b7e710bfc297:516:dolphin/L1_Cry_128x64/meta.txt +F:4911eaa7cb84ced19e5dea2af51b91a5:294:dolphin/L1_Furippa1_128x64/frame_0.bm +F:5669bee57c7b3d93a1665dd87fd5372a:325:dolphin/L1_Furippa1_128x64/frame_1.bm +F:80b48a77682b853e6236cd1c89083e6f:465:dolphin/L1_Furippa1_128x64/frame_10.bm +F:9d8ea10bf3d3831cb4a94957dc0b41c6:698:dolphin/L1_Furippa1_128x64/frame_11.bm +F:2dbb3125ea63550906fba8f7ec7b1da3:541:dolphin/L1_Furippa1_128x64/frame_12.bm +F:6a06b718957dca9caa63a4f3baa73abb:584:dolphin/L1_Furippa1_128x64/frame_13.bm +F:5450bf16c3d2fceaf5e6ea585b7ef7c1:610:dolphin/L1_Furippa1_128x64/frame_14.bm +F:535c0eca62703eb7df36f17334a6191b:719:dolphin/L1_Furippa1_128x64/frame_15.bm +F:7c03af85ade9b791755f3a4d106c2b7c:458:dolphin/L1_Furippa1_128x64/frame_16.bm +F:41b8fea16ad8705f4594e6119eade395:400:dolphin/L1_Furippa1_128x64/frame_17.bm +F:2db7fd3da5208a8e41902ae27cf41702:333:dolphin/L1_Furippa1_128x64/frame_18.bm +F:7e47428442e0f04959fc6afde979936e:351:dolphin/L1_Furippa1_128x64/frame_2.bm +F:0eb187078f169d7a852e97ecf430aea0:324:dolphin/L1_Furippa1_128x64/frame_3.bm +F:967c402971a442a5bf28eba804bb3ff4:387:dolphin/L1_Furippa1_128x64/frame_4.bm +F:175cb930fba0fc86f54a3a109b741708:390:dolphin/L1_Furippa1_128x64/frame_5.bm +F:f8c3ee1ab657549d1d00c1c72d8d2ff5:407:dolphin/L1_Furippa1_128x64/frame_6.bm +F:4911eaa7cb84ced19e5dea2af51b91a5:294:dolphin/L1_Furippa1_128x64/frame_7.bm +F:8f649ff34b224f4e564644a4494c54ed:283:dolphin/L1_Furippa1_128x64/frame_8.bm +F:3ec3c40d26bf8d3e691b1335d20d4ec0:312:dolphin/L1_Furippa1_128x64/frame_9.bm +F:ebe088426d184cf6651288accd21add6:241:dolphin/L1_Furippa1_128x64/meta.txt +F:d02fdfd1a3b89da00d2acf32bd09da80:555:dolphin/L1_Laptop_128x51/frame_0.bm +F:7e29ea503d41023fa3895d15458f106d:557:dolphin/L1_Laptop_128x51/frame_1.bm +F:eb55e0629de873f537d8412ced528eb4:560:dolphin/L1_Laptop_128x51/frame_2.bm +F:1516472ab3c140dd5bd4d089caa44747:556:dolphin/L1_Laptop_128x51/frame_3.bm +F:61172f89cf0a17bd7f978edccdeed166:560:dolphin/L1_Laptop_128x51/frame_4.bm +F:9d54913928c7e9477b6b8a43f3767621:554:dolphin/L1_Laptop_128x51/frame_5.bm +F:5243d6272bbb213e9c17af07ee011402:553:dolphin/L1_Laptop_128x51/frame_6.bm +F:aa68e0f28f117891ba0f4d7613224fc6:560:dolphin/L1_Laptop_128x51/frame_7.bm +F:9ef1935ab29fe70bbc517f4b602547d7:403:dolphin/L1_Laptop_128x51/meta.txt +F:6ce34e62c5bf4764a4163101afe63e60:514:dolphin/L1_Leaving_sad_128x64/frame_0.bm +F:19a0e0c518d222d91d24b8712ab6bb80:526:dolphin/L1_Leaving_sad_128x64/frame_1.bm +F:837bfb424c8d8a3bfbda7d6a28ba5a5c:316:dolphin/L1_Leaving_sad_128x64/frame_10.bm +F:1a69b6f63a96e0958837ea8b21db3966:294:dolphin/L1_Leaving_sad_128x64/frame_11.bm +F:c3ea827593a4563d544dfb7e99d73885:322:dolphin/L1_Leaving_sad_128x64/frame_12.bm +F:1e3842669191fe9599f830ac133e0751:542:dolphin/L1_Leaving_sad_128x64/frame_2.bm +F:9161660e6827bd776a15eefa2a8add19:557:dolphin/L1_Leaving_sad_128x64/frame_3.bm +F:d01a79fdb4f84397d82bf9927aeb71e0:488:dolphin/L1_Leaving_sad_128x64/frame_4.bm +F:316e30ef319c080fab2a79c21e526319:469:dolphin/L1_Leaving_sad_128x64/frame_5.bm +F:09a812d59b60b5fe7724057daa14ad60:499:dolphin/L1_Leaving_sad_128x64/frame_6.bm +F:9eb07b76cc864a0ce2918d68e41d4500:486:dolphin/L1_Leaving_sad_128x64/frame_7.bm +F:cf8c4cc4abbd700b096037b7ebfd0e31:403:dolphin/L1_Leaving_sad_128x64/frame_8.bm +F:889728ded689203aa82193e573912d18:317:dolphin/L1_Leaving_sad_128x64/frame_9.bm +F:2bff1f09ad1e9059a60e08990ca1d414:477:dolphin/L1_Leaving_sad_128x64/meta.txt +F:c31a882e95ed5c69fd63226db2188710:520:dolphin/L1_Mad_fist_128x64/frame_0.bm +F:740326828f6ba6e29373943ba835e77f:540:dolphin/L1_Mad_fist_128x64/frame_1.bm +F:0c9693dda040fd73ca6d773a10924bd8:542:dolphin/L1_Mad_fist_128x64/frame_10.bm +F:425c1d101debd1e9502db2628640b704:505:dolphin/L1_Mad_fist_128x64/frame_11.bm +F:aa576f7dbd14ec682f6c50314165fb14:501:dolphin/L1_Mad_fist_128x64/frame_12.bm +F:712335eabefb8c7bb7fb2f4301419c10:500:dolphin/L1_Mad_fist_128x64/frame_13.bm +F:b6e11711ea4dcc2e64f267d888f91baf:515:dolphin/L1_Mad_fist_128x64/frame_2.bm +F:61bdd22a2b1e67efe093b6acf7dfadce:538:dolphin/L1_Mad_fist_128x64/frame_3.bm +F:20ae06a3ce7a07656e578edb024e2b3f:512:dolphin/L1_Mad_fist_128x64/frame_4.bm +F:45cf2bd55365a7328df39fe98a496cc9:519:dolphin/L1_Mad_fist_128x64/frame_5.bm +F:4b8840eebb3a4a1ead69a7130816047e:524:dolphin/L1_Mad_fist_128x64/frame_6.bm +F:0de4497a5fbf80cc93e523465c5e3122:515:dolphin/L1_Mad_fist_128x64/frame_7.bm +F:32d8ddeb19bfa415fe283666b1e323a2:517:dolphin/L1_Mad_fist_128x64/frame_8.bm +F:a42a0578c2d0411500fb3485a3beb536:526:dolphin/L1_Mad_fist_128x64/frame_9.bm +F:10a521c78168a5928c859494e2a61cd2:349:dolphin/L1_Mad_fist_128x64/meta.txt +F:61565b7be9a69a60ce2dbae0273df347:653:dolphin/L1_Read_books_128x64/frame_0.bm +F:cf5a2d423540e3af37e789d70c9c1fbf:653:dolphin/L1_Read_books_128x64/frame_1.bm +F:c91935861979d024e6637b8810889878:650:dolphin/L1_Read_books_128x64/frame_2.bm +F:0c007a30f396f3e7a0ded2b24080357d:646:dolphin/L1_Read_books_128x64/frame_3.bm +F:323a52816dd79d6d3186f451e26e06ad:650:dolphin/L1_Read_books_128x64/frame_4.bm +F:494f27958f4cea9b94d09cf27725c5cd:652:dolphin/L1_Read_books_128x64/frame_5.bm +F:a6a7491fe80255e1745c9f293da52805:646:dolphin/L1_Read_books_128x64/frame_6.bm +F:238497e6643fd491cd6002e98c615c05:647:dolphin/L1_Read_books_128x64/frame_7.bm +F:300651e8f53d9a29ae38d4b9292c73cf:643:dolphin/L1_Read_books_128x64/frame_8.bm +F:3d9568deeff646b677092902a98f9ceb:325:dolphin/L1_Read_books_128x64/meta.txt +F:2aba555567ab70cff003ded4138c6721:663:dolphin/L1_Recording_128x51/frame_0.bm +F:8456c6e86825957e5662e2f08eb6c116:657:dolphin/L1_Recording_128x51/frame_1.bm +F:2e4a1aca5afa5a6ab254884210875eb4:629:dolphin/L1_Recording_128x51/frame_10.bm +F:9f1cf96598e3d935879b1d0c97705778:659:dolphin/L1_Recording_128x51/frame_11.bm +F:409abfeca974e5649affcd1faafea988:628:dolphin/L1_Recording_128x51/frame_2.bm +F:66b2a5abf05acbf79f9943e01b8b8cec:654:dolphin/L1_Recording_128x51/frame_3.bm +F:d55c5ed28c2ff48f42ab30b420d64fa3:662:dolphin/L1_Recording_128x51/frame_4.bm +F:2ce12d8cfdd953c9dadb9459c580a320:622:dolphin/L1_Recording_128x51/frame_5.bm +F:da631e3837fcdf3ee9e6abdf17fb764b:664:dolphin/L1_Recording_128x51/frame_6.bm +F:604a7cdac2491c9bc2e88b9e91c99dcc:626:dolphin/L1_Recording_128x51/frame_7.bm +F:fc94649dc98244dd9a0ab7fe62721d3c:663:dolphin/L1_Recording_128x51/frame_8.bm +F:b2475ab8ee26cbd9a403ee603520bd35:661:dolphin/L1_Recording_128x51/frame_9.bm +F:a7c2b3b420706712149cc2426c68df4f:219:dolphin/L1_Recording_128x51/meta.txt +F:9858fd34b55cebcb9be50c5710212a13:580:dolphin/L1_Sleep_128x64/frame_0.bm +F:e47ef8c846083b8fde028b1724861444:589:dolphin/L1_Sleep_128x64/frame_1.bm +F:9749bd05b47fd07cc3a41ab201f86bf4:582:dolphin/L1_Sleep_128x64/frame_2.bm +F:edf11266b20b846ace622e41cd36906b:597:dolphin/L1_Sleep_128x64/frame_3.bm +F:8fbb96a9d809d85fa6bad931fe4e6fe2:510:dolphin/L1_Sleep_128x64/meta.txt +F:283b41f1b2c581c510ff176293b7288a:443:dolphin/L1_Waves_128x50/frame_0.bm +F:c9fc5127e1d8a4217b6b177716725ba0:448:dolphin/L1_Waves_128x50/frame_1.bm +F:8e0797bf26d5d8d3cbeb99798c222b80:463:dolphin/L1_Waves_128x50/frame_2.bm +F:da02b1deb3119b31f2b8f182d5bf3242:472:dolphin/L1_Waves_128x50/frame_3.bm +F:8e6fb4133acbda7e5bb9adad0aed306c:620:dolphin/L1_Waves_128x50/meta.txt +F:be80d2fa903e3250b69c063a1eef0621:350:dolphin/L2_Furippa2_128x64/frame_0.bm +F:9e628f5e154f12d6c57b13befed1f5f6:385:dolphin/L2_Furippa2_128x64/frame_1.bm +F:80b48a77682b853e6236cd1c89083e6f:465:dolphin/L2_Furippa2_128x64/frame_10.bm +F:9d8ea10bf3d3831cb4a94957dc0b41c6:698:dolphin/L2_Furippa2_128x64/frame_11.bm +F:2dbb3125ea63550906fba8f7ec7b1da3:541:dolphin/L2_Furippa2_128x64/frame_12.bm +F:6a06b718957dca9caa63a4f3baa73abb:584:dolphin/L2_Furippa2_128x64/frame_13.bm +F:5450bf16c3d2fceaf5e6ea585b7ef7c1:610:dolphin/L2_Furippa2_128x64/frame_14.bm +F:e3c92103f403857b502081d3b058e53a:740:dolphin/L2_Furippa2_128x64/frame_15.bm +F:432669d796bbf7be1d14f5b7db036a92:533:dolphin/L2_Furippa2_128x64/frame_16.bm +F:53485c6b465c80a1ce8ddf03c4976039:451:dolphin/L2_Furippa2_128x64/frame_17.bm +F:333b75b16c088428a28259c931630fb9:397:dolphin/L2_Furippa2_128x64/frame_18.bm +F:ed02d68380382361f3f01cbf01d13b0c:402:dolphin/L2_Furippa2_128x64/frame_2.bm +F:b0ba042d7b60dc5681182b1d4005f0a2:374:dolphin/L2_Furippa2_128x64/frame_3.bm +F:518a84fa5a4e9e7f84246d5d82e87f15:440:dolphin/L2_Furippa2_128x64/frame_4.bm +F:9b7b0ae6f4f55d30cb43b0465216aa25:449:dolphin/L2_Furippa2_128x64/frame_5.bm +F:03b153949b0dae2efe1fc5f0dc57a0ef:466:dolphin/L2_Furippa2_128x64/frame_6.bm +F:be80d2fa903e3250b69c063a1eef0621:350:dolphin/L2_Furippa2_128x64/frame_7.bm +F:a8433f451cf3efc4ce2fb04a38c1f84f:319:dolphin/L2_Furippa2_128x64/frame_8.bm +F:d32a11bf9779d57191c1e59fe69cf83d:317:dolphin/L2_Furippa2_128x64/frame_9.bm +F:ebe088426d184cf6651288accd21add6:241:dolphin/L2_Furippa2_128x64/meta.txt +F:af4ec0085c29732085c51b18dc97bc27:543:dolphin/L2_Hacking_pc_128x64/frame_0.bm +F:eb141965fb6fb9f8b28766bac92abe1a:545:dolphin/L2_Hacking_pc_128x64/frame_1.bm +F:f7b33d3541dab08aaf4e8375e262b982:548:dolphin/L2_Hacking_pc_128x64/frame_2.bm +F:03634d90c54fd235aa76c0f9f794c80b:608:dolphin/L2_Hacking_pc_128x64/frame_3.bm +F:4c77406302f3fb74f8bdba568097082a:609:dolphin/L2_Hacking_pc_128x64/frame_4.bm +F:b0d1783358094534ac95b3455124d5fe:409:dolphin/L2_Hacking_pc_128x64/meta.txt +F:584c92e6fb15e99389b84d567e6d4d02:699:dolphin/L2_Soldering_128x64/frame_0.bm +F:3fa01b93460379204b6d14f43573b4f3:688:dolphin/L2_Soldering_128x64/frame_1.bm +F:6fad29757d4b7231b1d0ec53d0529b45:699:dolphin/L2_Soldering_128x64/frame_10.bm +F:e82c83e5a03abf4f6a1efd0a0f1ca33a:689:dolphin/L2_Soldering_128x64/frame_2.bm +F:7f9f310e22ef85af225dd1aefa2c47ba:689:dolphin/L2_Soldering_128x64/frame_3.bm +F:1ff31af6f90f07c0cdfa3283f52a5adc:693:dolphin/L2_Soldering_128x64/frame_4.bm +F:1a8f25aff949860cc6ffc79b4f48d5dd:696:dolphin/L2_Soldering_128x64/frame_5.bm +F:dbaa75feb8aebaf9b1cc5201c29952b8:712:dolphin/L2_Soldering_128x64/frame_6.bm +F:ee356bd981fba90c402d8e08d3015792:732:dolphin/L2_Soldering_128x64/frame_7.bm +F:09d5c5a685df606562d407bb9dac798e:705:dolphin/L2_Soldering_128x64/frame_8.bm +F:5451816e73bad029b3b9f3f55d294582:698:dolphin/L2_Soldering_128x64/frame_9.bm +F:c38ffad11987faf5ba6e363ead705e78:319:dolphin/L2_Soldering_128x64/meta.txt +F:2e083023ab65d1f99bba71f9aae6db9a:398:dolphin/L3_Furippa3_128x64/frame_0.bm +F:8cf20e07d84fd6a1157ba932beca70ea:438:dolphin/L3_Furippa3_128x64/frame_1.bm +F:018344c951691b7b1d77c1c6729d3e42:559:dolphin/L3_Furippa3_128x64/frame_10.bm +F:07008e2508064ab7a8467802472a9803:728:dolphin/L3_Furippa3_128x64/frame_11.bm +F:2dbb3125ea63550906fba8f7ec7b1da3:541:dolphin/L3_Furippa3_128x64/frame_12.bm +F:6a06b718957dca9caa63a4f3baa73abb:584:dolphin/L3_Furippa3_128x64/frame_13.bm +F:5450bf16c3d2fceaf5e6ea585b7ef7c1:610:dolphin/L3_Furippa3_128x64/frame_14.bm +F:e333224a4bed87b606df57a252ed4887:741:dolphin/L3_Furippa3_128x64/frame_15.bm +F:a20a6abfbd66fc3f92c66adacc4444a3:559:dolphin/L3_Furippa3_128x64/frame_16.bm +F:c1e051dce6b90e4f69b4792d0356a6b3:492:dolphin/L3_Furippa3_128x64/frame_17.bm +F:377f3621507c6590120cbc1c8ca92999:445:dolphin/L3_Furippa3_128x64/frame_18.bm +F:81f09c0fcd2bddb8a107a199e7149230:463:dolphin/L3_Furippa3_128x64/frame_2.bm +F:ed7fd1ada1070493462c1899f7372baf:424:dolphin/L3_Furippa3_128x64/frame_3.bm +F:e5fb2cdc4e08d6abff3191d37a1007ed:499:dolphin/L3_Furippa3_128x64/frame_4.bm +F:923a05250e5a93c7db7bbbf48448d164:504:dolphin/L3_Furippa3_128x64/frame_5.bm +F:1e9628db28a9a908c4a4b24cb16c5d20:521:dolphin/L3_Furippa3_128x64/frame_6.bm +F:2e083023ab65d1f99bba71f9aae6db9a:398:dolphin/L3_Furippa3_128x64/frame_7.bm +F:f1ec6e12daba9490f9e2e0e308ae3f83:419:dolphin/L3_Furippa3_128x64/frame_8.bm +F:106997120ad4cd23bd51e6f26bd7d74d:435:dolphin/L3_Furippa3_128x64/frame_9.bm +F:ebe088426d184cf6651288accd21add6:241:dolphin/L3_Furippa3_128x64/meta.txt +F:42970030123b2468984785fea7c60318:524:dolphin/L3_Hijack_radio_128x64/frame_0.bm +F:491c6d8ef21e48ca0f6b5fbd269c820b:527:dolphin/L3_Hijack_radio_128x64/frame_1.bm +F:ff499c8716c5f7fc1110a5ee82bda20c:550:dolphin/L3_Hijack_radio_128x64/frame_10.bm +F:ee39d82d6efc6a6992d19b6d75a6c509:572:dolphin/L3_Hijack_radio_128x64/frame_11.bm +F:5d14e8cb9d67bf8f597d6c749d07a135:539:dolphin/L3_Hijack_radio_128x64/frame_12.bm +F:9461004b75a34a36097668159c4cabe6:579:dolphin/L3_Hijack_radio_128x64/frame_13.bm +F:c925d4b1dff9c81463944cf930d7da8d:526:dolphin/L3_Hijack_radio_128x64/frame_2.bm +F:f98ed80cfab3a94b580be81654401c89:529:dolphin/L3_Hijack_radio_128x64/frame_3.bm +F:97ba548c27732be9e05fb8f7be8204ce:571:dolphin/L3_Hijack_radio_128x64/frame_4.bm +F:524932eb2391057fc1dea7237c7086e3:574:dolphin/L3_Hijack_radio_128x64/frame_5.bm +F:8eb9672f719926ac9c4c158575f388cd:524:dolphin/L3_Hijack_radio_128x64/frame_6.bm +F:7ca93fbab93bc278d4a11089d624a07b:655:dolphin/L3_Hijack_radio_128x64/frame_7.bm +F:37b4368f0b7235f3a7347bf499541666:645:dolphin/L3_Hijack_radio_128x64/frame_8.bm +F:ea9c3d7bab4756c2916369d5e130fa71:611:dolphin/L3_Hijack_radio_128x64/frame_9.bm +F:8583743f18a12ff647d3478e7aebdad6:230:dolphin/L3_Hijack_radio_128x64/meta.txt +F:f5f02a9df03bba734bdb7ed3297795f0:611:dolphin/L3_Lab_research_128x54/frame_0.bm +F:8f9655ad286464159443922d00e45620:614:dolphin/L3_Lab_research_128x54/frame_1.bm +F:7793b1bc107d4ea2e311e92dc16bf946:576:dolphin/L3_Lab_research_128x54/frame_10.bm +F:f24b8409f9dc770f3845424fe0ab489e:585:dolphin/L3_Lab_research_128x54/frame_11.bm +F:4ea93c4482dac43f40b67cc308f21e6d:571:dolphin/L3_Lab_research_128x54/frame_12.bm +F:cf3bb68dc78c568db22f37057a9fdd66:615:dolphin/L3_Lab_research_128x54/frame_13.bm +F:79719219aaebc95ea525def9173cabf5:618:dolphin/L3_Lab_research_128x54/frame_2.bm +F:05572cfd756704acd6ce9d6c15d03fc0:608:dolphin/L3_Lab_research_128x54/frame_3.bm +F:a26604a0d5427d5cf62a7a911a68b16c:615:dolphin/L3_Lab_research_128x54/frame_4.bm +F:9edc345fe53017970f93dc680818e63e:618:dolphin/L3_Lab_research_128x54/frame_5.bm +F:cf3bb68dc78c568db22f37057a9fdd66:615:dolphin/L3_Lab_research_128x54/frame_6.bm +F:5442895c85f769349288aa3df0990f9d:585:dolphin/L3_Lab_research_128x54/frame_7.bm +F:33b8fde22f34ef556b64b77164bc19b0:578:dolphin/L3_Lab_research_128x54/frame_8.bm +F:f267f0654781049ca323b11bb4375519:581:dolphin/L3_Lab_research_128x54/frame_9.bm +F:41106c0cbc5144f151b2b2d3daaa0527:727:dolphin/L3_Lab_research_128x54/meta.txt +D:infrared/assets +F:5b16e1a59daf3ef1d0fc95b3b5596d67:74300:infrared/assets/tv.ir +D:nfc/assets +F:c6826a621d081d68309e4be424d3d974:4715:nfc/assets/aid.nfc +F:86efbebdf41bb6bf15cc51ef88f069d5:2565:nfc/assets/country_code.nfc +F:41b4f08774249014cb8d3dffa5f5c07d:1757:nfc/assets/currency_code.nfc +F:c60e862919731b0bd538a1001bbc1098:17453:nfc/assets/mf_classic_dict.nfc +D:subghz/assets +F:dda1ef895b8a25fde57c874feaaef997:650:subghz/assets/came_atomo +F:610a0ffa2479a874f2060eb2348104c5:2712:subghz/assets/keeloq_mfcodes +F:9214f9c10463b746a27e82ce0b96e040:465:subghz/assets/keeloq_mfcodes_user +F:653bd8d349055a41e1152e557d4a52d3:202:subghz/assets/nice_flor_s +F:00e967e5c558e44a0651bb821d5cf1d0:414:subghz/assets/setting_frequency_analyzer_user +F:16e8c7cb4a13f26ea55b2b0a59f9cc7a:554:subghz/assets/setting_user +D:u2f/assets +F:7e11e688e39034bbb9d88410044795e1:365:u2f/assets/cert.der +F:f60b88c20ed479ed9684e249f7134618:264:u2f/assets/cert_key.u2f diff --git a/core/furi/memmgr_heap.c b/core/furi/memmgr_heap.c index 9455371e7c0..8544092eb52 100644 --- a/core/furi/memmgr_heap.c +++ b/core/furi/memmgr_heap.c @@ -171,7 +171,16 @@ size_t memmgr_heap_get_thread_memory(osThreadId_t thread_id) { !MemmgrHeapAllocDict_end_p(alloc_dict_it); MemmgrHeapAllocDict_next(alloc_dict_it)) { MemmgrHeapAllocDict_itref_t* data = MemmgrHeapAllocDict_ref(alloc_dict_it); - leftovers += data->value; + if(data->key != 0) { + uint8_t* puc = (uint8_t*)data->key; + puc -= xHeapStructSize; + BlockLink_t* pxLink = (void*)puc; + + if((pxLink->xBlockSize & xBlockAllocatedBit) != 0 && + pxLink->pxNextFreeBlock == NULL) { + leftovers += data->value; + } + } } } memmgr_heap_thread_trace_depth--; diff --git a/core/furi/thread.c b/core/furi/thread.c index ee86f62eb5b..a2898c1a6d0 100644 --- a/core/furi/thread.c +++ b/core/furi/thread.c @@ -45,6 +45,7 @@ static void furi_thread_body(void* context) { thread->ret = thread->callback(thread->context); if(thread->heap_trace_enabled == true) { + osDelay(33); thread->heap_size = memmgr_heap_get_thread_memory(thread_id); memmgr_heap_disable_thread_trace(thread_id); } diff --git a/firmware/targets/f7/Inc/FreeRTOSConfig.h b/firmware/targets/f7/Inc/FreeRTOSConfig.h index f0944cb7640..c3b2117c5a8 100644 --- a/firmware/targets/f7/Inc/FreeRTOSConfig.h +++ b/firmware/targets/f7/Inc/FreeRTOSConfig.h @@ -18,7 +18,7 @@ extern uint32_t SystemCoreClock; #define configUSE_IDLE_HOOK 0 #define configUSE_TICK_HOOK 0 #define configCPU_CLOCK_HZ (SystemCoreClock) -#define configTICK_RATE_HZ ((TickType_t)1024) +#define configTICK_RATE_HZ ((TickType_t)1000) #define configMAX_PRIORITIES (56) #define configMINIMAL_STACK_SIZE ((uint16_t)128) diff --git a/firmware/targets/f7/Src/main.c b/firmware/targets/f7/Src/main.c index 2e3bf04ff8b..1865f8d128a 100644 --- a/firmware/targets/f7/Src/main.c +++ b/firmware/targets/f7/Src/main.c @@ -6,32 +6,31 @@ #define TAG "Main" -#ifdef FURI_RAM_EXEC -int main() { - // Initialize FURI layer - furi_init(); - - // Flipper critical FURI HAL - furi_hal_init_early(); +static const osThreadAttr_t init_thread_attr = { + .name = "Init", + .stack_size = 4096, +}; +void init_task() { // Flipper FURI HAL furi_hal_init(); // Init flipper flipper_init(); - furi_run(); - - while(1) { - } + osThreadExit(); } -#else + int main() { // Initialize FURI layer furi_init(); // Flipper critical FURI HAL furi_hal_init_early(); + +#ifdef FURI_RAM_EXEC + osThreadNew(init_task, NULL, &init_thread_attr); +#else furi_hal_light_sequence("RGB"); // Delay is for button sampling @@ -52,25 +51,24 @@ int main() { furi_hal_power_reset(); } else { furi_hal_light_sequence("rgb G"); - - // Flipper FURI HAL - furi_hal_init(); - - // Init flipper - flipper_init(); - - furi_run(); + osThreadNew(init_task, NULL, &init_thread_attr); } +#endif - while(1) { - } + // Run Kernel + furi_run(); + + furi_crash("Kernel is Dead"); } -#endif void Error_Handler(void) { furi_crash("ErrorHandler"); } +void abort() { + furi_crash("AbortHandler"); +} + #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number diff --git a/firmware/targets/f7/furi_hal/furi_hal.c b/firmware/targets/f7/furi_hal/furi_hal.c index a2e78bfe375..b3362ba88ea 100644 --- a/firmware/targets/f7/furi_hal/furi_hal.c +++ b/firmware/targets/f7/furi_hal/furi_hal.c @@ -10,6 +10,8 @@ void furi_hal_init_early() { furi_hal_clock_init_early(); furi_hal_delay_init(); + furi_hal_os_init(); + furi_hal_resources_init_early(); furi_hal_spi_init_early(); @@ -75,9 +77,6 @@ void furi_hal_init() { furi_hal_bt_init(); furi_hal_compress_icon_init(); - // FreeRTOS glue - furi_hal_os_init(); - // FatFS driver initialization MX_FATFS_Init(); FURI_LOG_I(TAG, "FATFS OK"); diff --git a/firmware/targets/f7/furi_hal/furi_hal_clock.c b/firmware/targets/f7/furi_hal/furi_hal_clock.c index ca5e56497d7..0226442204a 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_clock.c +++ b/firmware/targets/f7/furi_hal/furi_hal_clock.c @@ -9,13 +9,15 @@ #define TAG "FuriHalClock" -#define TICK_INT_PRIORITY 0U +#define CPU_CLOCK_HZ_EARLY 4000000 +#define CPU_CLOCK_HZ_MAIN 64000000 +#define TICK_INT_PRIORITY 15U #define HS_CLOCK_IS_READY() (LL_RCC_HSE_IsReady() && LL_RCC_HSI_IsReady()) #define LS_CLOCK_IS_READY() (LL_RCC_LSE_IsReady() && LL_RCC_LSI1_IsReady()) void furi_hal_clock_init_early() { - LL_Init1msTick(4000000); - LL_SetSystemCoreClock(4000000); + LL_SetSystemCoreClock(CPU_CLOCK_HZ_EARLY); + LL_Init1msTick(SystemCoreClock); LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA); LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB); @@ -27,6 +29,8 @@ void furi_hal_clock_init_early() { LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI1); LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_SPI2); + LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_LPTIM2); + LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1); LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C3); } @@ -47,7 +51,7 @@ void furi_hal_clock_deinit_early() { } void furi_hal_clock_init() { - /* Prepare Flash memory for 64mHz system clock */ + /* Prepare Flash memory for 64MHz system clock */ LL_FLASH_SetLatency(LL_FLASH_LATENCY_3); while(LL_FLASH_GetLatency() != LL_FLASH_LATENCY_3) ; @@ -116,12 +120,13 @@ void furi_hal_clock_init() { ; /* Update CMSIS variable (which can be updated also through SystemCoreClockUpdate function) */ - LL_SetSystemCoreClock(64000000); + LL_SetSystemCoreClock(CPU_CLOCK_HZ_MAIN); /* Update the time base */ - LL_InitTick(64000000, 1000); + LL_Init1msTick(SystemCoreClock); LL_SYSTICK_EnableIT(); - NVIC_SetPriority(SysTick_IRQn, TICK_INT_PRIORITY); + NVIC_SetPriority( + SysTick_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), TICK_INT_PRIORITY, 0)); NVIC_EnableIRQ(SysTick_IRQn); LL_RCC_SetUSARTClockSource(LL_RCC_USART1_CLKSOURCE_PCLK2); @@ -175,7 +180,6 @@ void furi_hal_clock_init() { // APB1 GRP2 LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_LPUART1); - LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_LPTIM2); // APB2 // LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_ADC); @@ -217,3 +221,11 @@ void furi_hal_clock_switch_to_pll() { while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL) ; } + +void furi_hal_clock_suspend_tick() { + CLEAR_BIT(SysTick->CTRL, SysTick_CTRL_ENABLE_Msk); +} + +void furi_hal_clock_resume_tick() { + SET_BIT(SysTick->CTRL, SysTick_CTRL_ENABLE_Msk); +} diff --git a/firmware/targets/f7/furi_hal/furi_hal_clock.h b/firmware/targets/f7/furi_hal/furi_hal_clock.h index 0a1099acbd7..9cb11db4b98 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_clock.h +++ b/firmware/targets/f7/furi_hal/furi_hal_clock.h @@ -14,3 +14,9 @@ void furi_hal_clock_switch_to_hsi(); /** Switch to PLL clock */ void furi_hal_clock_switch_to_pll(); + +/** Stop SysTick counter without resetting */ +void furi_hal_clock_suspend_tick(); + +/** Continue SysTick counter operation */ +void furi_hal_clock_resume_tick(); diff --git a/firmware/targets/f7/furi_hal/furi_hal_delay.c b/firmware/targets/f7/furi_hal/furi_hal_delay.c index 94ef7865619..99636230962 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_delay.c +++ b/firmware/targets/f7/furi_hal/furi_hal_delay.c @@ -6,8 +6,6 @@ #define TAG "FuriHalDelay" -static volatile uint32_t tick_cnt = 0; - void furi_hal_delay_init() { CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; @@ -18,12 +16,8 @@ uint32_t furi_hal_delay_instructions_per_microsecond() { return SystemCoreClock / 1000000; } -void furi_hal_tick(void) { - tick_cnt++; -} - uint32_t furi_hal_get_tick(void) { - return tick_cnt; + return osKernelGetTickCount(); } uint32_t furi_hal_ms_to_ticks(float milliseconds) { diff --git a/firmware/targets/f7/furi_hal/furi_hal_idle_timer.h b/firmware/targets/f7/furi_hal/furi_hal_idle_timer.h new file mode 100644 index 00000000000..61afd631c85 --- /dev/null +++ b/firmware/targets/f7/furi_hal/furi_hal_idle_timer.h @@ -0,0 +1,55 @@ +#pragma once + +#include +#include +#include +#include + +// Timer used for tickless idle +#define FURI_HAL_IDLE_TIMER_MAX 0xFFFF +#define FURI_HAL_IDLE_TIMER LPTIM2 +#define FURI_HAL_IDLE_TIMER_IRQ LPTIM2_IRQn + +static inline void furi_hal_idle_timer_init() { + // Configure clock source + LL_RCC_SetLPTIMClockSource(LL_RCC_LPTIM2_CLKSOURCE_LSE); + // Set interrupt priority and enable them + NVIC_SetPriority( + FURI_HAL_IDLE_TIMER_IRQ, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 15, 0)); + NVIC_EnableIRQ(FURI_HAL_IDLE_TIMER_IRQ); +} + +static inline void furi_hal_idle_timer_start(uint32_t count) { + count--; + // Enable timer + LL_LPTIM_Enable(FURI_HAL_IDLE_TIMER); + while(!LL_LPTIM_IsEnabled(FURI_HAL_IDLE_TIMER)) + ; + + // Enable compare match interrupt + LL_LPTIM_EnableIT_CMPM(FURI_HAL_IDLE_TIMER); + + // Set compare, autoreload and start counter + // Include some marging to workaround ARRM behaviour + LL_LPTIM_SetCompare(FURI_HAL_IDLE_TIMER, count - 3); + LL_LPTIM_SetAutoReload(FURI_HAL_IDLE_TIMER, count); + LL_LPTIM_StartCounter(FURI_HAL_IDLE_TIMER, LL_LPTIM_OPERATING_MODE_ONESHOT); +} + +static inline void furi_hal_idle_timer_reset() { + // Hard reset timer + // THE ONLY RELIABLE WAY to stop it according to errata + LL_LPTIM_DeInit(FURI_HAL_IDLE_TIMER); + // Prevent IRQ handler call + NVIC_ClearPendingIRQ(FURI_HAL_IDLE_TIMER_IRQ); +} + +static inline uint32_t furi_hal_idle_timer_get_cnt() { + uint32_t counter = LL_LPTIM_GetCounter(FURI_HAL_IDLE_TIMER); + uint32_t counter_shadow = LL_LPTIM_GetCounter(FURI_HAL_IDLE_TIMER); + while(counter != counter_shadow) { + counter = counter_shadow; + counter_shadow = LL_LPTIM_GetCounter(FURI_HAL_IDLE_TIMER); + } + return counter; +} diff --git a/firmware/targets/f7/furi_hal/furi_hal_interrupt.c b/firmware/targets/f7/furi_hal/furi_hal_interrupt.c index e9fc023b001..d122fbc73e5 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_interrupt.c +++ b/firmware/targets/f7/furi_hal/furi_hal_interrupt.c @@ -1,5 +1,6 @@ #include "furi_hal_interrupt.h" #include "furi_hal_delay.h" +#include "furi_hal_os.h" #include @@ -249,7 +250,7 @@ extern void HW_IPCC_Tx_Handler(); extern void HW_IPCC_Rx_Handler(); void SysTick_Handler(void) { - furi_hal_tick(); + furi_hal_os_tick(); } void USB_LP_IRQHandler(void) { @@ -264,4 +265,4 @@ void IPCC_C1_TX_IRQHandler(void) { void IPCC_C1_RX_IRQHandler(void) { HW_IPCC_Rx_Handler(); -} \ No newline at end of file +} diff --git a/firmware/targets/f7/furi_hal/furi_hal_nfc.c b/firmware/targets/f7/furi_hal/furi_hal_nfc.c index b29c5026c98..bf9ea18c482 100755 --- a/firmware/targets/f7/furi_hal/furi_hal_nfc.c +++ b/firmware/targets/f7/furi_hal/furi_hal_nfc.c @@ -48,13 +48,12 @@ void furi_hal_nfc_exit_sleep() { rfalLowPowerModeStop(); } -bool furi_hal_nfc_detect( - rfalNfcDevice** dev_list, - uint8_t* dev_cnt, - uint32_t timeout, - bool deactivate) { - furi_assert(dev_list); - furi_assert(dev_cnt); +bool furi_hal_nfc_detect(FuriHalNfcDevData* nfc_data, uint32_t timeout) { + furi_assert(nfc_data); + + rfalNfcDevice* dev_list = NULL; + uint8_t dev_cnt = 0; + bool detected = false; rfalLowPowerModeStop(); rfalNfcState state = rfalNfcGetState(); @@ -77,9 +76,13 @@ bool furi_hal_nfc_detect( uint32_t start = DWT->CYCCNT; rfalNfcDiscover(¶ms); - while(state != RFAL_NFC_STATE_ACTIVATED) { + while(true) { rfalNfcWorker(); state = rfalNfcGetState(); + if(state == RFAL_NFC_STATE_ACTIVATED) { + detected = true; + break; + } FURI_LOG_T(TAG, "Current state %d", state); if(state == RFAL_NFC_STATE_POLL_ACTIVATION) { start = DWT->CYCCNT; @@ -91,16 +94,42 @@ bool furi_hal_nfc_detect( if(DWT->CYCCNT - start > timeout * clocks_in_ms) { rfalNfcDeactivate(true); FURI_LOG_T(TAG, "Timeout"); - return false; + break; } - osThreadYield(); + osDelay(1); } - rfalNfcGetDevicesFound(dev_list, dev_cnt); - if(deactivate) { - rfalNfcDeactivate(false); - rfalLowPowerModeStart(); + rfalNfcGetDevicesFound(&dev_list, &dev_cnt); + if(detected) { + if(dev_list[0].type == RFAL_NFC_LISTEN_TYPE_NFCA) { + nfc_data->type = FuriHalNfcTypeA; + nfc_data->atqa[0] = dev_list[0].dev.nfca.sensRes.anticollisionInfo; + nfc_data->atqa[1] = dev_list[0].dev.nfca.sensRes.platformInfo; + nfc_data->sak = dev_list[0].dev.nfca.selRes.sak; + uint8_t* cuid_start = dev_list[0].nfcid; + if(dev_list[0].nfcidLen == 7) { + cuid_start = &dev_list[0].nfcid[3]; + } + nfc_data->cuid = (cuid_start[0] << 24) | (cuid_start[1] << 16) | (cuid_start[2] << 8) | + (cuid_start[3]); + } else if(dev_list[0].type == RFAL_NFC_LISTEN_TYPE_NFCB) { + nfc_data->type = FuriHalNfcTypeB; + } else if(dev_list[0].type == RFAL_NFC_LISTEN_TYPE_NFCF) { + nfc_data->type = FuriHalNfcTypeF; + } else if(dev_list[0].type == RFAL_NFC_LISTEN_TYPE_NFCV) { + nfc_data->type = FuriHalNfcTypeV; + } + if(dev_list[0].rfInterface == RFAL_NFC_INTERFACE_RF) { + nfc_data->interface = FuriHalNfcInterfaceRf; + } else if(dev_list[0].rfInterface == RFAL_NFC_INTERFACE_ISODEP) { + nfc_data->interface = FuriHalNfcInterfaceIsoDep; + } else if(dev_list[0].rfInterface == RFAL_NFC_INTERFACE_NFCDEP) { + nfc_data->interface = FuriHalNfcInterfaceNfcDep; + } + nfc_data->uid_len = dev_list[0].nfcidLen; + memcpy(nfc_data->uid, dev_list[0].nfcid, nfc_data->uid_len); } - return true; + + return detected; } bool furi_hal_nfc_activate_nfca(uint32_t timeout, uint32_t* cuid) { @@ -201,7 +230,7 @@ bool furi_hal_nfc_listen( rfalNfcDeactivate(true); return false; } - osThreadYield(); + osDelay(1); } return true; } @@ -326,12 +355,6 @@ bool furi_hal_nfc_emulate_nfca( return true; } -bool furi_hal_nfc_get_first_frame(uint8_t** rx_buff, uint16_t** rx_len) { - ReturnCode ret = - rfalNfcDataExchangeStart(NULL, 0, rx_buff, rx_len, 0, RFAL_TXRX_FLAGS_DEFAULT); - return ret == ERR_NONE; -} - ReturnCode furi_hal_nfc_data_exchange( uint8_t* tx_buff, uint16_t tx_len, @@ -370,6 +393,22 @@ ReturnCode furi_hal_nfc_data_exchange( return ret; } +static uint32_t furi_hal_nfc_tx_rx_get_flag(FuriHalNfcTxRxType type) { + uint32_t flags = 0; + + if(type == FuriHalNfcTxRxTypeRxNoCrc) { + flags = RFAL_TXRX_FLAGS_CRC_RX_KEEP; + } else if(type == FuriHalNfcTxRxTypeRxKeepPar) { + flags = RFAL_TXRX_FLAGS_CRC_TX_MANUAL | RFAL_TXRX_FLAGS_CRC_RX_KEEP | + RFAL_TXRX_FLAGS_PAR_RX_KEEP; + } else if(type == FuriHalNfcTxRxTypeRaw) { + flags = RFAL_TXRX_FLAGS_CRC_TX_MANUAL | RFAL_TXRX_FLAGS_CRC_RX_KEEP | + RFAL_TXRX_FLAGS_PAR_RX_KEEP | RFAL_TXRX_FLAGS_PAR_TX_NONE; + } + + return flags; +} + static uint16_t furi_hal_nfc_data_and_parity_to_bitstream( uint8_t* data, uint16_t len, @@ -420,8 +459,8 @@ uint16_t furi_hal_nfc_bitstream_to_data_and_parity( return curr_byte; } -bool furi_hal_nfc_tx_rx(FuriHalNfcTxRxContext* tx_rx_ctx) { - furi_assert(tx_rx_ctx); +bool furi_hal_nfc_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_t timeout_ms) { + furi_assert(tx_rx); ReturnCode ret; rfalNfcState state = RFAL_NFC_STATE_ACTIVATED; @@ -431,26 +470,18 @@ bool furi_hal_nfc_tx_rx(FuriHalNfcTxRxContext* tx_rx_ctx) { uint16_t* temp_rx_bits = NULL; // Prepare data for FIFO if necessary - if(tx_rx_ctx->tx_rx_type == FURI_HAL_NFC_TXRX_RAW) { + uint32_t flags = furi_hal_nfc_tx_rx_get_flag(tx_rx->tx_rx_type); + if(tx_rx->tx_rx_type == FuriHalNfcTxRxTypeRaw) { temp_tx_bits = furi_hal_nfc_data_and_parity_to_bitstream( - tx_rx_ctx->tx_data, tx_rx_ctx->tx_bits / 8, tx_rx_ctx->tx_parity, temp_tx_buff); + tx_rx->tx_data, tx_rx->tx_bits / 8, tx_rx->tx_parity, temp_tx_buff); ret = rfalNfcDataExchangeCustomStart( - temp_tx_buff, - temp_tx_bits, - &temp_rx_buff, - &temp_rx_bits, - RFAL_FWT_NONE, - tx_rx_ctx->tx_rx_type); + temp_tx_buff, temp_tx_bits, &temp_rx_buff, &temp_rx_bits, RFAL_FWT_NONE, flags); } else { ret = rfalNfcDataExchangeCustomStart( - tx_rx_ctx->tx_data, - tx_rx_ctx->tx_bits, - &temp_rx_buff, - &temp_rx_bits, - RFAL_FWT_NONE, - tx_rx_ctx->tx_rx_type); + tx_rx->tx_data, tx_rx->tx_bits, &temp_rx_buff, &temp_rx_bits, RFAL_FWT_NONE, flags); } if(ret != ERR_NONE) { + FURI_LOG_E(TAG, "Failed to start data exchange"); return false; } uint32_t start = DWT->CYCCNT; @@ -459,28 +490,64 @@ bool furi_hal_nfc_tx_rx(FuriHalNfcTxRxContext* tx_rx_ctx) { state = rfalNfcGetState(); ret = rfalNfcDataExchangeGetStatus(); if(ret == ERR_BUSY) { - if(DWT->CYCCNT - start > 4 * clocks_in_ms) { + if(DWT->CYCCNT - start > timeout_ms * clocks_in_ms) { + FURI_LOG_D(TAG, "Timeout during data exchange"); return false; } continue; } else { start = DWT->CYCCNT; } - taskYIELD(); + osDelay(1); } - if(tx_rx_ctx->tx_rx_type == FURI_HAL_NFC_TXRX_RAW) { - tx_rx_ctx->rx_bits = - 8 * furi_hal_nfc_bitstream_to_data_and_parity( - temp_rx_buff, *temp_rx_bits, tx_rx_ctx->rx_data, tx_rx_ctx->rx_parity); + if(tx_rx->tx_rx_type == FuriHalNfcTxRxTypeRaw) { + tx_rx->rx_bits = 8 * furi_hal_nfc_bitstream_to_data_and_parity( + temp_rx_buff, *temp_rx_bits, tx_rx->rx_data, tx_rx->rx_parity); } else { - memcpy(tx_rx_ctx->rx_data, temp_rx_buff, *temp_rx_bits / 8); + memcpy(tx_rx->rx_data, temp_rx_buff, MIN(*temp_rx_bits / 8, FURI_HAL_NFC_DATA_BUFF_SIZE)); + tx_rx->rx_bits = *temp_rx_bits; } return true; } -void furi_hal_nfc_deactivate() { +ReturnCode furi_hal_nfc_exchange_full( + uint8_t* tx_buff, + uint16_t tx_len, + uint8_t* rx_buff, + uint16_t rx_cap, + uint16_t* rx_len) { + ReturnCode err; + uint8_t* part_buff; + uint16_t* part_len_bits; + uint16_t part_len_bytes; + + err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &part_buff, &part_len_bits, false); + part_len_bytes = *part_len_bits / 8; + if(part_len_bytes > rx_cap) { + return ERR_OVERRUN; + } + memcpy(rx_buff, part_buff, part_len_bytes); + *rx_len = part_len_bytes; + while(err == ERR_NONE && rx_buff[0] == 0xAF) { + err = furi_hal_nfc_data_exchange(rx_buff, 1, &part_buff, &part_len_bits, false); + part_len_bytes = *part_len_bits / 8; + if(part_len_bytes > rx_cap - *rx_len) { + return ERR_OVERRUN; + } + if(part_len_bytes == 0) { + return ERR_PROTO; + } + memcpy(rx_buff + *rx_len, part_buff + 1, part_len_bytes - 1); + *rx_buff = *part_buff; + *rx_len += part_len_bytes - 1; + } + + return err; +} + +void furi_hal_nfc_sleep() { rfalNfcDeactivate(false); rfalLowPowerModeStart(); } diff --git a/firmware/targets/f7/furi_hal/furi_hal_os.c b/firmware/targets/f7/furi_hal/furi_hal_os.c index 6ef5a9f4d17..e282645bc41 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_os.c +++ b/firmware/targets/f7/furi_hal/furi_hal_os.c @@ -1,17 +1,22 @@ #include -#include +#include #include +#include +#include #include #include #define TAG "FuriHalOs" -#define FURI_HAL_OS_CLK_FREQUENCY 32768 -#define FURI_HAL_OS_TICK_PER_SECOND 1024 -#define FURI_HAL_OS_CLK_PER_TICK (FURI_HAL_OS_CLK_FREQUENCY / FURI_HAL_OS_TICK_PER_SECOND) -#define FURI_HAL_OS_TICK_PER_EPOCH (FURI_HAL_OS_TIMER_MAX / FURI_HAL_OS_CLK_PER_TICK) -#define FURI_HAL_OS_MAX_SLEEP (FURI_HAL_OS_TICK_PER_EPOCH - 1) +#define FURI_HAL_IDLE_TIMER_CLK_HZ 32768 +#define FURI_HAL_OS_TICK_HZ configTICK_RATE_HZ + +#define FURI_HAL_OS_IDLE_CNT_TO_TICKS(x) ((x * FURI_HAL_OS_TICK_HZ) / FURI_HAL_IDLE_TIMER_CLK_HZ) +#define FURI_HAL_OS_TICKS_TO_IDLE_CNT(x) ((x * FURI_HAL_IDLE_TIMER_CLK_HZ) / FURI_HAL_OS_TICK_HZ) + +#define FURI_HAL_IDLE_TIMER_TICK_PER_EPOCH (FURI_HAL_OS_IDLE_CNT_TO_TICKS(FURI_HAL_IDLE_TIMER_MAX)) +#define FURI_HAL_OS_MAX_SLEEP (FURI_HAL_IDLE_TIMER_TICK_PER_EPOCH - 1) #ifdef FURI_HAL_OS_DEBUG #include @@ -30,48 +35,37 @@ void furi_hal_os_timer_callback() { extern void xPortSysTickHandler(); -volatile uint32_t furi_hal_os_skew = 0; +static volatile uint32_t furi_hal_os_skew = 0; void furi_hal_os_init() { - LL_DBGMCU_APB1_GRP2_FreezePeriph(LL_DBGMCU_APB1_GRP2_LPTIM2_STOP); - - furi_hal_os_timer_init(); - furi_hal_os_timer_continuous(FURI_HAL_OS_CLK_PER_TICK); + furi_hal_idle_timer_init(); #ifdef FURI_HAL_OS_DEBUG LL_GPIO_SetPinMode(LED_SLEEP_PORT, LED_SLEEP_PIN, LL_GPIO_MODE_OUTPUT); LL_GPIO_SetPinMode(LED_TICK_PORT, LED_TICK_PIN, LL_GPIO_MODE_OUTPUT); LL_GPIO_SetPinMode(LED_SECOND_PORT, LED_SECOND_PIN, LL_GPIO_MODE_OUTPUT); osTimerId_t second_timer = osTimerNew(furi_hal_os_timer_callback, osTimerPeriodic, NULL, NULL); - osTimerStart(second_timer, FURI_HAL_OS_TICK_PER_SECOND); + osTimerStart(second_timer, FURI_HAL_OS_TICK_HZ); #endif FURI_LOG_I(TAG, "Init OK"); } -void LPTIM2_IRQHandler(void) { - // Autoreload - if(LL_LPTIM_IsActiveFlag_ARRM(FURI_HAL_OS_TIMER)) { - LL_LPTIM_ClearFLAG_ARRM(FURI_HAL_OS_TIMER); - if(xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) { +void furi_hal_os_tick() { + if(xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) { #ifdef FURI_HAL_OS_DEBUG - LL_GPIO_TogglePin(LED_TICK_PORT, LED_TICK_PIN); + LL_GPIO_TogglePin(LED_TICK_PORT, LED_TICK_PIN); #endif - xPortSysTickHandler(); - } - } - if(LL_LPTIM_IsActiveFlag_CMPM(FURI_HAL_OS_TIMER)) { - LL_LPTIM_ClearFLAG_CMPM(FURI_HAL_OS_TIMER); + xPortSysTickHandler(); } } static inline uint32_t furi_hal_os_sleep(TickType_t expected_idle_ticks) { // Stop ticks - furi_hal_os_timer_reset(); - LL_SYSTICK_DisableIT(); + furi_hal_clock_suspend_tick(); // Start wakeup timer - furi_hal_os_timer_single(expected_idle_ticks * FURI_HAL_OS_CLK_PER_TICK); + furi_hal_idle_timer_start(FURI_HAL_OS_TICKS_TO_IDLE_CNT(expected_idle_ticks)); #ifdef FURI_HAL_OS_DEBUG LL_GPIO_ResetOutputPin(LED_SLEEP_PORT, LED_SLEEP_PIN); @@ -85,21 +79,19 @@ static inline uint32_t furi_hal_os_sleep(TickType_t expected_idle_ticks) { #endif // Calculate how much time we spent in the sleep - uint32_t after_cnt = furi_hal_os_timer_get_cnt() + furi_hal_os_skew; - uint32_t after_tick = after_cnt / FURI_HAL_OS_CLK_PER_TICK; - furi_hal_os_skew = after_cnt % FURI_HAL_OS_CLK_PER_TICK; + uint32_t after_cnt = furi_hal_idle_timer_get_cnt() + furi_hal_os_skew; + uint32_t after_tick = FURI_HAL_OS_IDLE_CNT_TO_TICKS(after_cnt); + furi_hal_os_skew = after_cnt - (after_cnt / after_tick); - bool cmpm = LL_LPTIM_IsActiveFlag_CMPM(FURI_HAL_OS_TIMER); - bool arrm = LL_LPTIM_IsActiveFlag_ARRM(FURI_HAL_OS_TIMER); + bool cmpm = LL_LPTIM_IsActiveFlag_CMPM(FURI_HAL_IDLE_TIMER); + bool arrm = LL_LPTIM_IsActiveFlag_ARRM(FURI_HAL_IDLE_TIMER); if(cmpm && arrm) after_tick += expected_idle_ticks; // Prepare tick timer for new round - furi_hal_os_timer_reset(); + furi_hal_idle_timer_reset(); // Resume ticks - LL_SYSTICK_EnableIT(); - furi_hal_os_timer_continuous(FURI_HAL_OS_CLK_PER_TICK); - + furi_hal_clock_resume_tick(); return after_tick; } @@ -109,7 +101,7 @@ void vPortSuppressTicksAndSleep(TickType_t expected_idle_ticks) { return; } - // Limit mount of ticks to maximum that timer can count + // Limit amount of ticks to maximum that timer can count if(expected_idle_ticks > FURI_HAL_OS_MAX_SLEEP) { expected_idle_ticks = FURI_HAL_OS_MAX_SLEEP; } @@ -125,14 +117,9 @@ void vPortSuppressTicksAndSleep(TickType_t expected_idle_ticks) { // Sleep and track how much ticks we spent sleeping uint32_t completed_ticks = furi_hal_os_sleep(expected_idle_ticks); - // Notify system about time spent in sleep if(completed_ticks > 0) { - if(completed_ticks > expected_idle_ticks) { - vTaskStepTick(expected_idle_ticks); - } else { - vTaskStepTick(completed_ticks); - } + vTaskStepTick(MIN(completed_ticks, expected_idle_ticks)); } // Reenable IRQ diff --git a/firmware/targets/f7/furi_hal/furi_hal_os.h b/firmware/targets/f7/furi_hal/furi_hal_os.h index 0b3d15806c7..e13b2c258c8 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_os.h +++ b/firmware/targets/f7/furi_hal/furi_hal_os.h @@ -11,6 +11,10 @@ extern "C" { */ void furi_hal_os_init(); +/* Advance OS tick counter + */ +void furi_hal_os_tick(); + #ifdef __cplusplus } -#endif \ No newline at end of file +#endif diff --git a/firmware/targets/f7/furi_hal/furi_hal_os_timer.h b/firmware/targets/f7/furi_hal/furi_hal_os_timer.h deleted file mode 100644 index dd01ac60a53..00000000000 --- a/firmware/targets/f7/furi_hal/furi_hal_os_timer.h +++ /dev/null @@ -1,69 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -// Timer used for system ticks -#define FURI_HAL_OS_TIMER_MAX 0xFFFF -#define FURI_HAL_OS_TIMER_REG_LOAD_DLY 0x1 -#define FURI_HAL_OS_TIMER LPTIM2 -#define FURI_HAL_OS_TIMER_IRQ LPTIM2_IRQn - -static inline void furi_hal_os_timer_init() { - // Configure clock source - LL_RCC_SetLPTIMClockSource(LL_RCC_LPTIM2_CLKSOURCE_LSE); - // Set interrupt priority and enable them - NVIC_SetPriority( - FURI_HAL_OS_TIMER_IRQ, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 15, 0)); - NVIC_EnableIRQ(FURI_HAL_OS_TIMER_IRQ); -} - -static inline void furi_hal_os_timer_continuous(uint32_t count) { - count--; - // Enable timer - LL_LPTIM_Enable(FURI_HAL_OS_TIMER); - while(!LL_LPTIM_IsEnabled(FURI_HAL_OS_TIMER)) - ; - - // Enable rutoreload match interrupt - LL_LPTIM_EnableIT_ARRM(FURI_HAL_OS_TIMER); - - // Set autoreload and start counter - LL_LPTIM_SetAutoReload(FURI_HAL_OS_TIMER, count); - LL_LPTIM_StartCounter(FURI_HAL_OS_TIMER, LL_LPTIM_OPERATING_MODE_CONTINUOUS); -} - -static inline void furi_hal_os_timer_single(uint32_t count) { - count--; - // Enable timer - LL_LPTIM_Enable(FURI_HAL_OS_TIMER); - while(!LL_LPTIM_IsEnabled(FURI_HAL_OS_TIMER)) - ; - - // Enable compare match interrupt - LL_LPTIM_EnableIT_CMPM(FURI_HAL_OS_TIMER); - - // Set compare, autoreload and start counter - // Include some marging to workaround ARRM behaviour - LL_LPTIM_SetCompare(FURI_HAL_OS_TIMER, count - 3); - LL_LPTIM_SetAutoReload(FURI_HAL_OS_TIMER, count); - LL_LPTIM_StartCounter(FURI_HAL_OS_TIMER, LL_LPTIM_OPERATING_MODE_ONESHOT); -} - -static inline void furi_hal_os_timer_reset() { - // Hard reset timer - // THE ONLY RELIABLEWAY to stop it according to errata - LL_LPTIM_DeInit(FURI_HAL_OS_TIMER); -} - -static inline uint32_t furi_hal_os_timer_get_cnt() { - uint32_t counter = LL_LPTIM_GetCounter(FURI_HAL_OS_TIMER); - uint32_t counter_shadow = LL_LPTIM_GetCounter(FURI_HAL_OS_TIMER); - while(counter != counter_shadow) { - counter = counter_shadow; - counter_shadow = LL_LPTIM_GetCounter(FURI_HAL_OS_TIMER); - } - return counter; -} diff --git a/firmware/targets/f7/furi_hal/furi_hal_power.c b/firmware/targets/f7/furi_hal/furi_hal_power.c index e5060536d75..2b78c7f0b2c 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_power.c +++ b/firmware/targets/f7/furi_hal/furi_hal_power.c @@ -21,6 +21,9 @@ typedef struct { volatile uint8_t insomnia; volatile uint8_t deep_insomnia; volatile uint8_t suppress_charge; + + uint8_t gauge_initialized; + uint8_t charger_initialized; } FuriHalPower; static volatile FuriHalPower furi_hal_power = { @@ -84,6 +87,29 @@ void furi_hal_power_init() { FURI_LOG_I(TAG, "Init OK"); } +bool furi_hal_power_gauge_is_ok() { + bool ret = true; + + BatteryStatus battery_status; + OperationStatus operation_status; + + furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); + + if(bq27220_get_battery_status(&furi_hal_i2c_handle_power, &battery_status) == BQ27220_ERROR || + bq27220_get_operation_status(&furi_hal_i2c_handle_power, &operation_status) == + BQ27220_ERROR) { + ret = false; + } else { + ret &= battery_status.BATTPRES; + ret &= operation_status.INITCOMP; + ret &= (cedv.design_cap == bq27220_get_design_capacity(&furi_hal_i2c_handle_power)); + } + + furi_hal_i2c_release(&furi_hal_i2c_handle_power); + + return ret; +} + uint16_t furi_hal_power_insomnia_level() { return furi_hal_power.insomnia; } @@ -315,10 +341,9 @@ void furi_hal_power_dump_state() { } else { // Operation status register printf( - "bq27220: CALMD: %d, SEC0: %d, SEC1: %d, EDV2: %d, VDQ: %d, INITCOMP: %d, SMTH: %d, BTPINT: %d, CFGUPDATE: %d\r\n", + "bq27220: CALMD: %d, SEC: %d, EDV2: %d, VDQ: %d, INITCOMP: %d, SMTH: %d, BTPINT: %d, CFGUPDATE: %d\r\n", operation_status.CALMD, - operation_status.SEC0, - operation_status.SEC1, + operation_status.SEC, operation_status.EDV2, operation_status.VDQ, operation_status.INITCOMP, diff --git a/firmware/targets/furi_hal_include/furi_hal_delay.h b/firmware/targets/furi_hal_include/furi_hal_delay.h index f34a7053073..8d88a4c1d9b 100644 --- a/firmware/targets/furi_hal_include/furi_hal_delay.h +++ b/firmware/targets/furi_hal_include/furi_hal_delay.h @@ -18,11 +18,6 @@ void furi_hal_delay_init(); /** Get instructions per microsecond count */ uint32_t furi_hal_delay_instructions_per_microsecond(); -/** Increase tick counter. - * Should be called from SysTick ISR - */ -void furi_hal_tick(void); - /** Get current tick counter * * System uptime, may overflow. diff --git a/firmware/targets/furi_hal_include/furi_hal_nfc.h b/firmware/targets/furi_hal_include/furi_hal_nfc.h index edccab76bc3..20a4690028b 100755 --- a/firmware/targets/furi_hal_include/furi_hal_nfc.h +++ b/firmware/targets/furi_hal_include/furi_hal_nfc.h @@ -15,32 +15,31 @@ extern "C" { #endif #define FURI_HAL_NFC_UID_MAX_LEN 10 -#define FURI_HAL_NFC_DATA_BUFF_SIZE (64) +#define FURI_HAL_NFC_DATA_BUFF_SIZE (256) #define FURI_HAL_NFC_PARITY_BUFF_SIZE (FURI_HAL_NFC_DATA_BUFF_SIZE / 8) #define FURI_HAL_NFC_TXRX_DEFAULT \ ((uint32_t)RFAL_TXRX_FLAGS_CRC_TX_AUTO | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_REMV | \ - (uint32_t)RFAL_TXRX_FLAGS_NFCIP1_OFF | (uint32_t)RFAL_TXRX_FLAGS_AGC_ON | \ - (uint32_t)RFAL_TXRX_FLAGS_PAR_RX_REMV | (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_AUTO | \ - (uint32_t)RFAL_TXRX_FLAGS_NFCV_FLAG_AUTO) + (uint32_t)RFAL_TXRX_FLAGS_PAR_RX_REMV | (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_AUTO) #define FURI_HAL_NFC_TX_DEFAULT_RX_NO_CRC \ ((uint32_t)RFAL_TXRX_FLAGS_CRC_TX_AUTO | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_KEEP | \ - (uint32_t)RFAL_TXRX_FLAGS_NFCIP1_OFF | (uint32_t)RFAL_TXRX_FLAGS_AGC_ON | \ - (uint32_t)RFAL_TXRX_FLAGS_PAR_RX_REMV | (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_AUTO | \ - (uint32_t)RFAL_TXRX_FLAGS_NFCV_FLAG_AUTO) + (uint32_t)RFAL_TXRX_FLAGS_PAR_RX_REMV | (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_AUTO) #define FURI_HAL_NFC_TXRX_WITH_PAR \ ((uint32_t)RFAL_TXRX_FLAGS_CRC_TX_MANUAL | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_KEEP | \ - (uint32_t)RFAL_TXRX_FLAGS_NFCIP1_OFF | (uint32_t)RFAL_TXRX_FLAGS_AGC_ON | \ - (uint32_t)RFAL_TXRX_FLAGS_PAR_RX_KEEP | (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_AUTO | \ - (uint32_t)RFAL_TXRX_FLAGS_NFCV_FLAG_AUTO) + (uint32_t)RFAL_TXRX_FLAGS_PAR_RX_KEEP | (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_AUTO) #define FURI_HAL_NFC_TXRX_RAW \ ((uint32_t)RFAL_TXRX_FLAGS_CRC_TX_MANUAL | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_KEEP | \ - (uint32_t)RFAL_TXRX_FLAGS_NFCIP1_OFF | (uint32_t)RFAL_TXRX_FLAGS_AGC_ON | \ - (uint32_t)RFAL_TXRX_FLAGS_PAR_RX_KEEP | (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_NONE | \ - (uint32_t)RFAL_TXRX_FLAGS_NFCV_FLAG_AUTO) + (uint32_t)RFAL_TXRX_FLAGS_PAR_RX_KEEP | (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_NONE) + +typedef enum { + FuriHalNfcTxRxTypeDefault, + FuriHalNfcTxRxTypeRxNoCrc, + FuriHalNfcTxRxTypeRxKeepPar, + FuriHalNfcTxRxTypeRaw, +} FuriHalNfcTxRxType; typedef bool (*FuriHalNfcEmulateCallback)( uint8_t* buff_rx, @@ -50,6 +49,29 @@ typedef bool (*FuriHalNfcEmulateCallback)( uint32_t* flags, void* context); +typedef enum { + FuriHalNfcTypeA, + FuriHalNfcTypeB, + FuriHalNfcTypeF, + FuriHalNfcTypeV, +} FuriHalNfcType; + +typedef enum { + FuriHalNfcInterfaceRf, + FuriHalNfcInterfaceIsoDep, + FuriHalNfcInterfaceNfcDep, +} FuriHalNfcInterface; + +typedef struct { + FuriHalNfcType type; + FuriHalNfcInterface interface; + uint8_t uid_len; + uint8_t uid[10]; + uint32_t cuid; + uint8_t atqa[2]; + uint8_t sak; +} FuriHalNfcDevData; + typedef struct { uint8_t tx_data[FURI_HAL_NFC_DATA_BUFF_SIZE]; uint8_t tx_parity[FURI_HAL_NFC_PARITY_BUFF_SIZE]; @@ -57,7 +79,7 @@ typedef struct { uint8_t rx_data[FURI_HAL_NFC_DATA_BUFF_SIZE]; uint8_t rx_parity[FURI_HAL_NFC_PARITY_BUFF_SIZE]; uint16_t rx_bits; - uint32_t tx_rx_type; + FuriHalNfcTxRxType tx_rx_type; } FuriHalNfcTxRxContext; /** Init nfc @@ -95,11 +117,7 @@ void furi_hal_nfc_exit_sleep(); * * @return true on success */ -bool furi_hal_nfc_detect( - rfalNfcDevice** dev_list, - uint8_t* dev_cnt, - uint32_t timeout, - bool deactivate); +bool furi_hal_nfc_detect(FuriHalNfcDevData* nfc_data, uint32_t timeout); /** Activate NFC-A tag * @@ -138,15 +156,6 @@ bool furi_hal_nfc_emulate_nfca( void* context, uint32_t timeout); -/** Get first command from reader after activation in emulation mode - * - * @param rx_buff pointer to receive buffer - * @param rx_len receive buffer length - * - * @return true on success - */ -bool furi_hal_nfc_get_first_frame(uint8_t** rx_buff, uint16_t** rx_len); - /** NFC data exchange * * @param tx_buff transmit buffer @@ -170,11 +179,28 @@ ReturnCode furi_hal_nfc_data_exchange( * * @return true on success */ -bool furi_hal_nfc_tx_rx(FuriHalNfcTxRxContext* tx_rx_ctx); +bool furi_hal_nfc_tx_rx(FuriHalNfcTxRxContext* tx_rx, uint16_t timeout_ms); + +/** NFC data full exhange + * + * @param tx_buff transmit buffer + * @param tx_len transmit buffer length + * @param rx_buff receive buffer + * @param rx_cap receive buffer capacity + * @param rx_len receive buffer length + * + * @return ST ReturnCode + */ +ReturnCode furi_hal_nfc_exchange_full( + uint8_t* tx_buff, + uint16_t tx_len, + uint8_t* rx_buff, + uint16_t rx_cap, + uint16_t* rx_len); /** NFC deactivate and start sleep */ -void furi_hal_nfc_deactivate(); +void furi_hal_nfc_sleep(); void furi_hal_nfc_stop(); diff --git a/firmware/targets/furi_hal_include/furi_hal_power.h b/firmware/targets/furi_hal_include/furi_hal_power.h index c55e3804526..717f6570649 100644 --- a/firmware/targets/furi_hal_include/furi_hal_power.h +++ b/firmware/targets/furi_hal_include/furi_hal_power.h @@ -19,10 +19,20 @@ typedef enum { FuriHalPowerICFuelGauge, } FuriHalPowerIC; -/** Initialize drivers - */ +/** Initialize drivers */ void furi_hal_power_init(); +/** Check if gauge is ok + * + * Verifies that: + * - gauge is alive + * - correct profile loaded + * - self diagnostic status is good + * + * @return true if gauge is ok + */ +bool furi_hal_power_gauge_is_ok(); + /** Get current insomnia level * * @return insomnia level: 0 - no insomnia, >0 - insomnia, bearer count. diff --git a/lib/ST25RFAL002/source/rfal_isoDep.c b/lib/ST25RFAL002/source/rfal_isoDep.c index 4f0cff58a53..77e67521dcd 100644 --- a/lib/ST25RFAL002/source/rfal_isoDep.c +++ b/lib/ST25RFAL002/source/rfal_isoDep.c @@ -3015,7 +3015,7 @@ ReturnCode rfalIsoDepGetApduTransceiveStatus(void) { } /* Update output param rxLen */ - *gIsoDep.APDUParam.rxLen = gIsoDep.APDURxPos; + *gIsoDep.APDUParam.rxLen = gIsoDep.APDURxPos * 8; /* Wait for following I-Block or APDU TxRx has finished */ return ((ret == ERR_AGAIN) ? ERR_BUSY : ERR_NONE); diff --git a/lib/ST25RFAL002/source/rfal_nfc.c b/lib/ST25RFAL002/source/rfal_nfc.c index a4a6094d5ad..9040b7f9d2a 100755 --- a/lib/ST25RFAL002/source/rfal_nfc.c +++ b/lib/ST25RFAL002/source/rfal_nfc.c @@ -725,9 +725,14 @@ ReturnCode rfalNfcDataExchangeCustomStart( { /*******************************************************************************/ case RFAL_NFC_INTERFACE_RF: - ctx.rxBuf = gNfcDev.rxBuf.rfBuf, ctx.rxBufLen = sizeof(gNfcDev.rxBuf.rfBuf), - ctx.rxRcvdLen = &gNfcDev.rxLen, ctx.txBuf = txData, ctx.txBufLen = txDataLen, - ctx.flags = flags, ctx.fwt = fwt, *rxData = (uint8_t*)gNfcDev.rxBuf.rfBuf; + ctx.rxBuf = gNfcDev.rxBuf.rfBuf; + ctx.rxBufLen = 8 * sizeof(gNfcDev.rxBuf.rfBuf); + ctx.rxRcvdLen = &gNfcDev.rxLen; + ctx.txBuf = txData; + ctx.txBufLen = txDataLen; + ctx.flags = flags; + ctx.fwt = fwt; + *rxData = (uint8_t*)gNfcDev.rxBuf.rfBuf; *rvdLen = (uint16_t*)&gNfcDev.rxLen; err = rfalStartTransceive(&ctx); break; @@ -736,13 +741,14 @@ ReturnCode rfalNfcDataExchangeCustomStart( /*******************************************************************************/ case RFAL_NFC_INTERFACE_ISODEP: { rfalIsoDepApduTxRxParam isoDepTxRx; + uint16_t tx_bytes = txDataLen / 8; - if(txDataLen > sizeof(gNfcDev.txBuf.isoDepBuf.apdu)) { + if(tx_bytes > sizeof(gNfcDev.txBuf.isoDepBuf.apdu)) { return ERR_NOMEM; } - if(txDataLen > 0U) { - ST_MEMCPY((uint8_t*)gNfcDev.txBuf.isoDepBuf.apdu, txData, txDataLen); + if(tx_bytes > 0U) { + ST_MEMCPY((uint8_t*)gNfcDev.txBuf.isoDepBuf.apdu, txData, tx_bytes); } isoDepTxRx.DID = RFAL_ISODEP_NO_DID; @@ -751,7 +757,7 @@ ReturnCode rfalNfcDataExchangeCustomStart( isoDepTxRx.dFWT = gNfcDev.activeDev->proto.isoDep.info.dFWT; isoDepTxRx.FWT = gNfcDev.activeDev->proto.isoDep.info.FWT; isoDepTxRx.txBuf = &gNfcDev.txBuf.isoDepBuf; - isoDepTxRx.txBufLen = txDataLen; + isoDepTxRx.txBufLen = tx_bytes; isoDepTxRx.rxBuf = &gNfcDev.rxBuf.isoDepBuf; isoDepTxRx.rxLen = &gNfcDev.rxLen; isoDepTxRx.tmpBuf = &gNfcDev.tmpBuf.isoDepBuf; diff --git a/lib/drivers/bq27220.h b/lib/drivers/bq27220.h index 71773cb5acc..c822301a479 100644 --- a/lib/drivers/bq27220.h +++ b/lib/drivers/bq27220.h @@ -28,22 +28,25 @@ typedef struct { bool FD : 1; // Full-discharge is detected } BatteryStatus; +_Static_assert(sizeof(BatteryStatus) == 2, "Incorrect structure size"); + typedef struct { // Low byte, Low bit first - bool CALMD : 1; - bool SEC0 : 1; - bool SEC1 : 1; - bool EDV2 : 1; - bool VDQ : 1; - bool INITCOMP : 1; - bool SMTH : 1; - bool BTPINT : 1; + bool CALMD : 1; /**< Calibration mode enabled */ + uint8_t SEC : 2; /**< Current security access */ + bool EDV2 : 1; /**< EDV2 threshold exceeded */ + bool VDQ : 1; /**< Indicates if Current discharge cycle is NOT qualified or qualified for an FCC updated */ + bool INITCOMP : 1; /**< gauge initialization is complete */ + bool SMTH : 1; /**< RemainingCapacity is scaled by smooth engine */ + bool BTPINT : 1; /**< BTP threshold has been crossed */ // High byte, Low bit first uint8_t RSVD1 : 2; - bool CFGUPDATE : 1; + bool CFGUPDATE : 1; /**< Gauge is in CONFIG UPDATE mode */ uint8_t RSVD0 : 5; } OperationStatus; +_Static_assert(sizeof(OperationStatus) == 2, "Incorrect structure size"); + typedef struct { // Low byte, Low bit first bool CCT : 1; @@ -62,6 +65,8 @@ typedef struct { uint8_t RSVD3 : 3; } GaugingConfig; +_Static_assert(sizeof(GaugingConfig) == 2, "Incorrect structure size"); + typedef struct { union { GaugingConfig gauge_conf; diff --git a/lib/nfc_protocols/emv_decoder.c b/lib/nfc_protocols/emv.c similarity index 55% rename from lib/nfc_protocols/emv_decoder.c rename to lib/nfc_protocols/emv.c index e63a6e968fc..6756981b6ce 100644 --- a/lib/nfc_protocols/emv_decoder.c +++ b/lib/nfc_protocols/emv.c @@ -1,4 +1,8 @@ -#include "emv_decoder.h" +#include "emv.h" + +#include + +#define TAG "Emv" const PDOLValue pdol_term_info = {0x9F59, {0xC8, 0x80, 0x00}}; // Terminal transaction information const PDOLValue pdol_term_type = {0x9F5A, {0x00}}; // Terminal transaction type @@ -69,19 +73,6 @@ static bool emv_decode_search_tag_u16_r(uint16_t tag, uint8_t* buff, uint16_t* i return false; } -uint16_t emv_prepare_select_ppse(uint8_t* dest) { - const uint8_t emv_select_ppse[] = { - 0x00, 0xA4, // SELECT ppse - 0x04, 0x00, // P1:By name, P2: empty - 0x0e, // Lc: Data length - 0x32, 0x50, 0x41, 0x59, 0x2e, 0x53, 0x59, // Data string: - 0x53, 0x2e, 0x44, 0x44, 0x46, 0x30, 0x31, // 2PAY.SYS.DDF01 (PPSE) - 0x00 // Le - }; - memcpy(dest, emv_select_ppse, sizeof(emv_select_ppse)); - return sizeof(emv_select_ppse); -} - bool emv_decode_ppse_response(uint8_t* buff, uint16_t len, EmvApplication* app) { uint16_t i = 0; bool app_aid_found = false; @@ -89,7 +80,7 @@ bool emv_decode_ppse_response(uint8_t* buff, uint16_t len, EmvApplication* app) while(i < len) { if(buff[i] == EMV_TAG_APP_TEMPLATE) { uint8_t app_len = buff[++i]; - for(uint16_t j = i; j < i + app_len; j++) { + for(uint16_t j = i; j < MIN(i + app_len, len - 1); j++) { if(buff[j] == EMV_TAG_AID) { app_aid_found = true; app->aid_len = buff[j + 1]; @@ -105,41 +96,89 @@ bool emv_decode_ppse_response(uint8_t* buff, uint16_t len, EmvApplication* app) return app_aid_found; } -uint16_t emv_prepare_select_app(uint8_t* dest, EmvApplication* app) { - const uint8_t emv_select_header[] = { - 0x00, - 0xA4, // SELECT application - 0x04, - 0x00 // P1:By name, P2:First or only occurence +bool emv_select_ppse(FuriHalNfcTxRxContext* tx_rx, EmvApplication* app) { + bool app_aid_found = false; + const uint8_t emv_select_ppse_cmd[] = { + 0x00, 0xA4, // SELECT ppse + 0x04, 0x00, // P1:By name, P2: empty + 0x0e, // Lc: Data length + 0x32, 0x50, 0x41, 0x59, 0x2e, 0x53, 0x59, // Data string: + 0x53, 0x2e, 0x44, 0x44, 0x46, 0x30, 0x31, // 2PAY.SYS.DDF01 (PPSE) + 0x00 // Le }; - uint16_t size = sizeof(emv_select_header); - // Copy header - memcpy(dest, emv_select_header, size); - // Copy AID - dest[size++] = app->aid_len; - memcpy(&dest[size], app->aid, app->aid_len); - size += app->aid_len; - dest[size++] = 0; - return size; + + memcpy(tx_rx->tx_data, emv_select_ppse_cmd, sizeof(emv_select_ppse_cmd)); + tx_rx->tx_bits = sizeof(emv_select_ppse_cmd) * 8; + tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault; + + FURI_LOG_D(TAG, "Send select PPSE"); + if(furi_hal_nfc_tx_rx(tx_rx, 300)) { + if(emv_decode_ppse_response(tx_rx->rx_data, tx_rx->rx_bits / 8, app)) { + app_aid_found = true; + } else { + FURI_LOG_E(TAG, "Failed to parse application"); + } + } else { + FURI_LOG_E(TAG, "Failed select PPSE"); + } + + return app_aid_found; } -bool emv_decode_select_app_response(uint8_t* buff, uint16_t len, EmvApplication* app) { +static bool emv_decode_select_app_response(uint8_t* buff, uint16_t len, EmvApplication* app) { uint16_t i = 0; - bool found_name = false; + bool decode_success = false; while(i < len) { if(buff[i] == EMV_TAG_CARD_NAME) { uint8_t name_len = buff[i + 1]; emv_parse_TLV((uint8_t*)app->name, buff, &i); app->name[name_len] = '\0'; - found_name = true; + app->name_found = true; + decode_success = true; } else if(((buff[i] << 8) | buff[i + 1]) == EMV_TAG_PDOL) { i++; app->pdol.size = emv_parse_TLV(app->pdol.data, buff, &i); + decode_success = true; } i++; } - return found_name; + + return decode_success; +} + +bool emv_select_app(FuriHalNfcTxRxContext* tx_rx, EmvApplication* app) { + bool select_app_success = false; + const uint8_t emv_select_header[] = { + 0x00, + 0xA4, // SELECT application + 0x04, + 0x00 // P1:By name, P2:First or only occurence + }; + uint16_t size = sizeof(emv_select_header); + + // Copy header + memcpy(tx_rx->tx_data, emv_select_header, size); + // Copy AID + tx_rx->tx_data[size++] = app->aid_len; + memcpy(&tx_rx->tx_data[size], app->aid, app->aid_len); + size += app->aid_len; + tx_rx->tx_data[size++] = 0x00; + tx_rx->tx_bits = size * 8; + tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault; + + FURI_LOG_D(TAG, "Start application"); + if(furi_hal_nfc_tx_rx(tx_rx, 300)) { + if(emv_decode_select_app_response(tx_rx->rx_data, tx_rx->rx_bits / 8, app)) { + select_app_success = true; + } else { + FURI_LOG_E(TAG, "Failed to read PAN or PDOL"); + } + } else { + FURI_LOG_E(TAG, "Failed to start application"); + } + + return select_app_success; } static uint16_t emv_prepare_pdol(APDU* dest, APDU* src) { @@ -175,53 +214,56 @@ static uint16_t emv_prepare_pdol(APDU* dest, APDU* src) { return dest->size; } -uint16_t emv_prepare_get_proc_opt(uint8_t* dest, EmvApplication* app) { - // Get processing option header - const uint8_t emv_gpo_header[] = {0x80, 0xA8, 0x00, 0x00}; - uint16_t size = sizeof(emv_gpo_header); - // Copy header - memcpy(dest, emv_gpo_header, size); - APDU pdol_data = {0, {0}}; - // Prepare and copy pdol parameters - emv_prepare_pdol(&pdol_data, &app->pdol); - dest[size++] = 0x02 + pdol_data.size; - dest[size++] = 0x83; - dest[size++] = pdol_data.size; - memcpy(dest + size, pdol_data.data, pdol_data.size); - size += pdol_data.size; - dest[size++] = 0; - return size; -} +static bool emv_decode_get_proc_opt(uint8_t* buff, uint16_t len, EmvApplication* app) { + bool card_num_read = false; -bool emv_decode_get_proc_opt(uint8_t* buff, uint16_t len, EmvApplication* app) { for(uint16_t i = 0; i < len; i++) { if(buff[i] == EMV_TAG_CARD_NUM) { app->card_number_len = 8; memcpy(app->card_number, &buff[i + 2], app->card_number_len); - return true; + card_num_read = true; } else if(buff[i] == EMV_TAG_AFL) { app->afl.size = emv_parse_TLV(app->afl.data, buff, &i); } } - return false; + + return card_num_read; } -uint16_t emv_prepare_read_sfi_record(uint8_t* dest, uint8_t sfi, uint8_t record_num) { - const uint8_t sfi_param = (sfi << 3) | (1 << 2); - const uint8_t emv_sfi_header[] = { - 0x00, - 0xB2, // READ RECORD - record_num, - sfi_param, // P1:record_number and P2:SFI - 0x00 // Le - }; - uint16_t size = sizeof(emv_sfi_header); - memcpy(dest, emv_sfi_header, size); - return size; +static bool emv_get_processing_options(FuriHalNfcTxRxContext* tx_rx, EmvApplication* app) { + bool card_num_read = false; + const uint8_t emv_gpo_header[] = {0x80, 0xA8, 0x00, 0x00}; + uint16_t size = sizeof(emv_gpo_header); + + // Copy header + memcpy(tx_rx->tx_data, emv_gpo_header, size); + APDU pdol_data = {0, {0}}; + // Prepare and copy pdol parameters + emv_prepare_pdol(&pdol_data, &app->pdol); + tx_rx->tx_data[size++] = 0x02 + pdol_data.size; + tx_rx->tx_data[size++] = 0x83; + tx_rx->tx_data[size++] = pdol_data.size; + memcpy(tx_rx->tx_data + size, pdol_data.data, pdol_data.size); + size += pdol_data.size; + tx_rx->tx_data[size++] = 0; + tx_rx->tx_bits = size * 8; + tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault; + + FURI_LOG_D(TAG, "Get proccessing options"); + if(furi_hal_nfc_tx_rx(tx_rx, 300)) { + if(emv_decode_get_proc_opt(tx_rx->rx_data, tx_rx->rx_bits / 8, app)) { + card_num_read = true; + } + } else { + FURI_LOG_E(TAG, "Failed to get processing options"); + } + + return card_num_read; } -bool emv_decode_read_sfi_record(uint8_t* buff, uint16_t len, EmvApplication* app) { +static bool emv_decode_read_sfi_record(uint8_t* buff, uint16_t len, EmvApplication* app) { bool pan_parsed = false; + for(uint16_t i = 0; i < len; i++) { if(buff[i] == EMV_TAG_PAN) { if(buff[i + 1] == 8 || buff[i + 1] == 10) { @@ -240,20 +282,118 @@ bool emv_decode_read_sfi_record(uint8_t* buff, uint16_t len, EmvApplication* app i += 2; } } + return pan_parsed; } -uint16_t emv_select_ppse_ans(uint8_t* buff) { - memcpy(buff, select_ppse_ans, sizeof(select_ppse_ans)); - return sizeof(select_ppse_ans); +static bool emv_read_sfi_record( + FuriHalNfcTxRxContext* tx_rx, + EmvApplication* app, + uint8_t sfi, + uint8_t record_num) { + bool card_num_read = false; + uint8_t sfi_param = (sfi << 3) | (1 << 2); + uint8_t emv_sfi_header[] = { + 0x00, + 0xB2, // READ RECORD + record_num, // P1:record_number + sfi_param, // P2:SFI + 0x00 // Le + }; + + memcpy(tx_rx->tx_data, emv_sfi_header, sizeof(emv_sfi_header)); + tx_rx->tx_bits = sizeof(emv_sfi_header) * 8; + tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault; + + if(furi_hal_nfc_tx_rx(tx_rx, 300)) { + if(emv_decode_read_sfi_record(tx_rx->rx_data, tx_rx->rx_bits / 8, app)) { + card_num_read = true; + } + } else { + FURI_LOG_E(TAG, "Failed to read SFI record %d", record_num); + } + + return card_num_read; +} + +static bool emv_read_files(FuriHalNfcTxRxContext* tx_rx, EmvApplication* app) { + bool card_num_read = false; + + if(app->afl.size == 0) { + return false; + } + + FURI_LOG_D(TAG, "Search PAN in SFI"); + // Iterate through all files + for(size_t i = 0; i < app->afl.size; i += 4) { + uint8_t sfi = app->afl.data[i] >> 3; + uint8_t record_start = app->afl.data[i + 1]; + uint8_t record_end = app->afl.data[i + 2]; + // Iterate through all records in file + for(uint8_t record = record_start; record <= record_end; ++record) { + card_num_read |= emv_read_sfi_record(tx_rx, app, sfi, record); + } + } + + return card_num_read; +} + +bool emv_search_application(FuriHalNfcTxRxContext* tx_rx, EmvApplication* emv_app) { + furi_assert(tx_rx); + furi_assert(emv_app); + memset(emv_app, 0, sizeof(EmvApplication)); + + return emv_select_ppse(tx_rx, emv_app); } -uint16_t emv_select_app_ans(uint8_t* buff) { - memcpy(buff, select_app_ans, sizeof(select_app_ans)); - return sizeof(select_app_ans); +bool emv_read_bank_card(FuriHalNfcTxRxContext* tx_rx, EmvApplication* emv_app) { + furi_assert(tx_rx); + furi_assert(emv_app); + bool card_num_read = false; + memset(emv_app, 0, sizeof(EmvApplication)); + + do { + if(!emv_select_ppse(tx_rx, emv_app)) break; + if(!emv_select_app(tx_rx, emv_app)) break; + if(emv_get_processing_options(tx_rx, emv_app)) { + card_num_read = true; + } else { + card_num_read = emv_read_files(tx_rx, emv_app); + } + } while(false); + + return card_num_read; } -uint16_t emv_get_proc_opt_ans(uint8_t* buff) { - memcpy(buff, pdol_ans, sizeof(pdol_ans)); - return sizeof(pdol_ans); +bool emv_card_emulation(FuriHalNfcTxRxContext* tx_rx) { + furi_assert(tx_rx); + bool emulation_complete = false; + memset(tx_rx, 0, sizeof(FuriHalNfcTxRxContext)); + + do { + FURI_LOG_D(TAG, "Read select PPSE command"); + if(!furi_hal_nfc_tx_rx(tx_rx, 300)) break; + + memcpy(tx_rx->tx_data, select_ppse_ans, sizeof(select_ppse_ans)); + tx_rx->tx_bits = sizeof(select_ppse_ans) * 8; + tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault; + FURI_LOG_D(TAG, "Send select PPSE answer and read select App command"); + if(!furi_hal_nfc_tx_rx(tx_rx, 300)) break; + + memcpy(tx_rx->tx_data, select_app_ans, sizeof(select_app_ans)); + tx_rx->tx_bits = sizeof(select_app_ans) * 8; + tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault; + FURI_LOG_D(TAG, "Send select App answer and read get PDOL command"); + if(!furi_hal_nfc_tx_rx(tx_rx, 300)) break; + + memcpy(tx_rx->tx_data, pdol_ans, sizeof(pdol_ans)); + tx_rx->tx_bits = sizeof(pdol_ans) * 8; + tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault; + FURI_LOG_D(TAG, "Send get PDOL answer"); + if(!furi_hal_nfc_tx_rx(tx_rx, 300)) break; + + emulation_complete = true; + } while(false); + + return emulation_complete; } diff --git a/lib/nfc_protocols/emv.h b/lib/nfc_protocols/emv.h new file mode 100755 index 00000000000..b5a0c574f07 --- /dev/null +++ b/lib/nfc_protocols/emv.h @@ -0,0 +1,87 @@ +#pragma once + +#include + +#define MAX_APDU_LEN 255 + +#define EMV_TAG_APP_TEMPLATE 0x61 +#define EMV_TAG_AID 0x4F +#define EMV_TAG_PRIORITY 0x87 +#define EMV_TAG_PDOL 0x9F38 +#define EMV_TAG_CARD_NAME 0x50 +#define EMV_TAG_FCI 0xBF0C +#define EMV_TAG_LOG_CTRL 0x9F4D +#define EMV_TAG_CARD_NUM 0x57 +#define EMV_TAG_PAN 0x5A +#define EMV_TAG_AFL 0x94 +#define EMV_TAG_EXP_DATE 0x5F24 +#define EMV_TAG_COUNTRY_CODE 0x5F28 +#define EMV_TAG_CURRENCY_CODE 0x9F42 +#define EMV_TAG_CARDHOLDER_NAME 0x5F20 + +typedef struct { + char name[32]; + uint8_t aid[16]; + uint16_t aid_len; + uint8_t number[10]; + uint8_t number_len; + uint8_t exp_mon; + uint8_t exp_year; + uint16_t country_code; + uint16_t currency_code; +} EmvData; + +typedef struct { + uint16_t tag; + uint8_t data[]; +} PDOLValue; + +typedef struct { + uint8_t size; + uint8_t data[MAX_APDU_LEN]; +} APDU; + +typedef struct { + uint8_t priority; + uint8_t aid[16]; + uint8_t aid_len; + char name[32]; + bool name_found; + uint8_t card_number[10]; + uint8_t card_number_len; + uint8_t exp_month; + uint8_t exp_year; + uint16_t country_code; + uint16_t currency_code; + APDU pdol; + APDU afl; +} EmvApplication; + +/** Read bank card data + * @note Search EMV Application, start it, try to read AID, PAN, card name, + * expiration date, currency and country codes + * + * @param tx_rx FuriHalNfcTxRxContext instance + * @param emv_app EmvApplication instance + * + * @return true on success + */ +bool emv_read_bank_card(FuriHalNfcTxRxContext* tx_rx, EmvApplication* emv_app); + +/** Search for EMV Application + * + * @param tx_rx FuriHalNfcTxRxContext instance + * @param emv_app EmvApplication instance + * + * @return true on success + */ +bool emv_search_application(FuriHalNfcTxRxContext* tx_rx, EmvApplication* emv_app); + +/** Emulate bank card + * @note Answer to application selection and PDOL + * + * @param tx_rx FuriHalNfcTxRxContext instance + * + * @return true on success + */ +bool emv_card_emulation(FuriHalNfcTxRxContext* tx_rx); diff --git a/lib/nfc_protocols/emv_decoder.h b/lib/nfc_protocols/emv_decoder.h deleted file mode 100755 index 7328ee79d97..00000000000 --- a/lib/nfc_protocols/emv_decoder.h +++ /dev/null @@ -1,67 +0,0 @@ -#pragma once - -#include -#include -#include - -#define MAX_APDU_LEN 255 - -#define EMV_TAG_APP_TEMPLATE 0x61 -#define EMV_TAG_AID 0x4F -#define EMV_TAG_PRIORITY 0x87 -#define EMV_TAG_PDOL 0x9F38 -#define EMV_TAG_CARD_NAME 0x50 -#define EMV_TAG_FCI 0xBF0C -#define EMV_TAG_LOG_CTRL 0x9F4D -#define EMV_TAG_CARD_NUM 0x57 -#define EMV_TAG_PAN 0x5A -#define EMV_TAG_AFL 0x94 -#define EMV_TAG_EXP_DATE 0x5F24 -#define EMV_TAG_COUNTRY_CODE 0x5F28 -#define EMV_TAG_CURRENCY_CODE 0x9F42 -#define EMV_TAG_CARDHOLDER_NAME 0x5F20 - -typedef struct { - uint16_t tag; - uint8_t data[]; -} PDOLValue; - -extern const PDOLValue* const pdol_values[]; - -typedef struct { - uint8_t size; - uint8_t data[MAX_APDU_LEN]; -} APDU; - -typedef struct { - uint8_t priority; - uint8_t aid[16]; - uint8_t aid_len; - char name[32]; - uint8_t card_number[10]; - uint8_t card_number_len; - uint8_t exp_month; - uint8_t exp_year; - uint16_t country_code; - uint16_t currency_code; - APDU pdol; - APDU afl; -} EmvApplication; - -/* Terminal emulation */ -uint16_t emv_prepare_select_ppse(uint8_t* dest); -bool emv_decode_ppse_response(uint8_t* buff, uint16_t len, EmvApplication* app); - -uint16_t emv_prepare_select_app(uint8_t* dest, EmvApplication* app); -bool emv_decode_select_app_response(uint8_t* buff, uint16_t len, EmvApplication* app); - -uint16_t emv_prepare_get_proc_opt(uint8_t* dest, EmvApplication* app); -bool emv_decode_get_proc_opt(uint8_t* buff, uint16_t len, EmvApplication* app); - -uint16_t emv_prepare_read_sfi_record(uint8_t* dest, uint8_t sfi, uint8_t record_num); -bool emv_decode_read_sfi_record(uint8_t* buff, uint16_t len, EmvApplication* app); - -/* Card emulation */ -uint16_t emv_select_ppse_ans(uint8_t* buff); -uint16_t emv_select_app_ans(uint8_t* buff); -uint16_t emv_get_proc_opt_ans(uint8_t* buff); diff --git a/lib/nfc_protocols/mifare_classic.c b/lib/nfc_protocols/mifare_classic.c index 65408e78e2e..c738accc972 100644 --- a/lib/nfc_protocols/mifare_classic.c +++ b/lib/nfc_protocols/mifare_classic.c @@ -116,17 +116,15 @@ static bool mf_classic_auth( tx_rx->tx_data[0] = MF_CLASSIC_AUTH_KEY_B_CMD; } tx_rx->tx_data[1] = block; - tx_rx->tx_rx_type = FURI_HAL_NFC_TX_DEFAULT_RX_NO_CRC; + tx_rx->tx_rx_type = FuriHalNfcTxRxTypeRxNoCrc; tx_rx->tx_bits = 2 * 8; - if(!furi_hal_nfc_tx_rx(tx_rx)) break; + if(!furi_hal_nfc_tx_rx(tx_rx, 5)) break; uint32_t nt = (uint32_t)nfc_util_bytes2num(tx_rx->rx_data, 4); crypto1_init(crypto, key); crypto1_word(crypto, nt ^ cuid, 0); uint8_t nr[4] = {}; - // uint8_t parity = 0; nfc_util_num2bytes(prng_successor(DWT->CYCCNT, 32), 4, nr); - // uint8_t nr_ar[8] = {}; for(uint8_t i = 0; i < 4; i++) { tx_rx->tx_data[i] = crypto1_byte(crypto, nr[i], 0) ^ nr[i]; tx_rx->tx_parity[0] |= @@ -140,9 +138,9 @@ static bool mf_classic_auth( (((crypto1_filter(crypto->odd) ^ nfc_util_odd_parity8(nt & 0xff)) & 0x01) << (7 - i)); } - tx_rx->tx_rx_type = FURI_HAL_NFC_TXRX_RAW; + tx_rx->tx_rx_type = FuriHalNfcTxRxTypeRaw; tx_rx->tx_bits = 8 * 8; - if(!furi_hal_nfc_tx_rx(tx_rx)) break; + if(!furi_hal_nfc_tx_rx(tx_rx, 5)) break; if(tx_rx->rx_bits == 32) { crypto1_word(crypto, 0, 0); auth_success = true; @@ -178,7 +176,7 @@ bool mf_classic_auth_attempt( } if(need_halt) { - furi_hal_nfc_deactivate(); + furi_hal_nfc_sleep(); furi_hal_nfc_activate_nfca(300, &auth_ctx->cuid); } @@ -220,9 +218,9 @@ bool mf_classic_read_block( ((crypto1_filter(crypto->odd) ^ nfc_util_odd_parity8(plain_cmd[i])) & 0x01) << (7 - i); } tx_rx->tx_bits = 4 * 9; - tx_rx->tx_rx_type = FURI_HAL_NFC_TXRX_RAW; + tx_rx->tx_rx_type = FuriHalNfcTxRxTypeRaw; - if(furi_hal_nfc_tx_rx(tx_rx)) { + if(furi_hal_nfc_tx_rx(tx_rx, 50)) { if(tx_rx->rx_bits == 8 * 18) { for(uint8_t i = 0; i < 18; i++) { block->value[i] = crypto1_byte(crypto, 0, 0) ^ tx_rx->rx_data[i]; @@ -248,7 +246,7 @@ bool mf_classic_read_sector( uint8_t first_block; bool sector_read = false; - furi_hal_nfc_deactivate(); + furi_hal_nfc_sleep(); do { // Activate card if(!furi_hal_nfc_activate_nfca(200, &cuid)) break; diff --git a/lib/nfc_protocols/mifare_common.c b/lib/nfc_protocols/mifare_common.c new file mode 100644 index 00000000000..0be24b512c0 --- /dev/null +++ b/lib/nfc_protocols/mifare_common.c @@ -0,0 +1,17 @@ +#include "mifare_common.h" + +MifareType mifare_common_get_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK) { + MifareType type = MifareTypeUnknown; + + if((ATQA0 == 0x44) && (ATQA1 == 0x00) && (SAK == 0x00)) { + type = MifareTypeUltralight; + } else if( + ((ATQA0 == 0x44 || ATQA0 == 0x04) && (SAK == 0x08)) || + ((ATQA0 == 0x42 || ATQA0 == 0x02) && (SAK == 0x18))) { + type = MifareTypeClassic; + } else if(ATQA0 == 0x44 && ATQA1 == 0x03 && SAK == 0x20) { + type = MifareTypeDesfire; + } + + return type; +} diff --git a/lib/nfc_protocols/mifare_common.h b/lib/nfc_protocols/mifare_common.h new file mode 100644 index 00000000000..2b694d9068a --- /dev/null +++ b/lib/nfc_protocols/mifare_common.h @@ -0,0 +1,12 @@ +#pragma once + +#include + +typedef enum { + MifareTypeUnknown, + MifareTypeUltralight, + MifareTypeClassic, + MifareTypeDesfire, +} MifareType; + +MifareType mifare_common_get_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK); diff --git a/lib/nfc_protocols/mifare_ultralight.c b/lib/nfc_protocols/mifare_ultralight.c index c9311124e6d..31ac8e77ff1 100644 --- a/lib/nfc_protocols/mifare_ultralight.c +++ b/lib/nfc_protocols/mifare_ultralight.c @@ -1,6 +1,7 @@ #include "mifare_ultralight.h" #include -#include + +#define TAG "MfUltralight" bool mf_ul_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK) { if((ATQA0 == 0x44) && (ATQA1 == 0x00) && (SAK == 0x00)) { @@ -9,187 +10,204 @@ bool mf_ul_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK) { return false; } -uint16_t mf_ul_prepare_get_version(uint8_t* dest) { - dest[0] = MF_UL_GET_VERSION_CMD; - return 1; +static void mf_ul_set_default_version(MfUltralightReader* reader, MfUltralightData* data) { + data->type = MfUltralightTypeUnknown; + reader->pages_to_read = 16; + reader->support_fast_read = false; } -void mf_ul_parse_get_version_response(uint8_t* buff, MifareUlDevice* mf_ul_read) { - MfUltralightVersion* version = (MfUltralightVersion*)buff; - memcpy(&mf_ul_read->data.version, version, sizeof(MfUltralightVersion)); - if(version->storage_size == 0x0B || version->storage_size == 0x00) { - mf_ul_read->data.type = MfUltralightTypeUL11; - mf_ul_read->pages_to_read = 20; - mf_ul_read->support_fast_read = true; - } else if(version->storage_size == 0x0E) { - mf_ul_read->data.type = MfUltralightTypeUL21; - mf_ul_read->pages_to_read = 41; - mf_ul_read->support_fast_read = true; - } else if(version->storage_size == 0x0F) { - mf_ul_read->data.type = MfUltralightTypeNTAG213; - mf_ul_read->pages_to_read = 45; - mf_ul_read->support_fast_read = false; - } else if(version->storage_size == 0x11) { - mf_ul_read->data.type = MfUltralightTypeNTAG215; - mf_ul_read->pages_to_read = 135; - mf_ul_read->support_fast_read = false; - } else if(version->storage_size == 0x13) { - mf_ul_read->data.type = MfUltralightTypeNTAG216; - mf_ul_read->pages_to_read = 231; - mf_ul_read->support_fast_read = false; - } else { - mf_ul_set_default_version(mf_ul_read); - } -} +bool mf_ultralight_read_version( + FuriHalNfcTxRxContext* tx_rx, + MfUltralightReader* reader, + MfUltralightData* data) { + bool version_read = false; -void mf_ul_set_default_version(MifareUlDevice* mf_ul_read) { - mf_ul_read->data.type = MfUltralightTypeUnknown; - mf_ul_read->pages_to_read = 16; - mf_ul_read->support_fast_read = false; -} + do { + FURI_LOG_D(TAG, "Reading version"); + tx_rx->tx_data[0] = MF_UL_GET_VERSION_CMD; + tx_rx->tx_bits = 8; + tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault; + if(!furi_hal_nfc_tx_rx(tx_rx, 50)) { + FURI_LOG_D(TAG, "Failed reading version"); + mf_ul_set_default_version(reader, data); + furi_hal_nfc_sleep(); + furi_hal_nfc_activate_nfca(300, NULL); + break; + } + MfUltralightVersion* version = (MfUltralightVersion*)tx_rx->rx_data; + data->version = *version; + if(version->storage_size == 0x0B || version->storage_size == 0x00) { + data->type = MfUltralightTypeUL11; + reader->pages_to_read = 20; + reader->support_fast_read = true; + } else if(version->storage_size == 0x0E) { + data->type = MfUltralightTypeUL21; + reader->pages_to_read = 41; + reader->support_fast_read = true; + } else if(version->storage_size == 0x0F) { + data->type = MfUltralightTypeNTAG213; + reader->pages_to_read = 45; + reader->support_fast_read = false; + } else if(version->storage_size == 0x11) { + data->type = MfUltralightTypeNTAG215; + reader->pages_to_read = 135; + reader->support_fast_read = false; + } else if(version->storage_size == 0x13) { + data->type = MfUltralightTypeNTAG216; + reader->pages_to_read = 231; + reader->support_fast_read = false; + } else { + mf_ul_set_default_version(reader, data); + break; + } + version_read = true; + } while(false); -uint16_t mf_ul_prepare_read(uint8_t* dest, uint8_t start_page) { - dest[0] = MF_UL_READ_CMD; - dest[1] = start_page; - return 2; + return version_read; } -void mf_ul_parse_read_response(uint8_t* buff, uint16_t page_addr, MifareUlDevice* mf_ul_read) { - uint8_t pages_read = 4; - uint8_t page_read_count = mf_ul_read->pages_read + pages_read; - if(page_read_count > mf_ul_read->pages_to_read) { - pages_read -= page_read_count - mf_ul_read->pages_to_read; +bool mf_ultralight_read_pages( + FuriHalNfcTxRxContext* tx_rx, + MfUltralightReader* reader, + MfUltralightData* data) { + uint8_t pages_read_cnt = 0; + + for(size_t i = 0; i < reader->pages_to_read; i += 4) { + FURI_LOG_D(TAG, "Reading pages %d - %d", i, i + 3); + tx_rx->tx_data[0] = MF_UL_READ_CMD; + tx_rx->tx_data[1] = i; + tx_rx->tx_bits = 16; + tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault; + if(!furi_hal_nfc_tx_rx(tx_rx, 50)) { + FURI_LOG_D(TAG, "Failed to read pages %d - %d", i, i + 3); + break; + } + if(i + 4 <= reader->pages_to_read) { + pages_read_cnt = 4; + } else { + pages_read_cnt = reader->pages_to_read - reader->pages_read; + } + reader->pages_read += pages_read_cnt; + data->data_size = reader->pages_read * 4; + memcpy(&data->data[i * 4], tx_rx->rx_data, pages_read_cnt * 4); } - mf_ul_read->pages_read += pages_read; - mf_ul_read->data.data_size = mf_ul_read->pages_read * 4; - memcpy(&mf_ul_read->data.data[page_addr * 4], buff, pages_read * 4); -} -uint16_t mf_ul_prepare_fast_read(uint8_t* dest, uint8_t start_page, uint8_t end_page) { - dest[0] = MF_UL_FAST_READ_CMD; - dest[1] = start_page; - dest[2] = end_page; - return 3; + return reader->pages_read == reader->pages_to_read; } -void mf_ul_parse_fast_read_response( - uint8_t* buff, - uint8_t start_page, - uint8_t end_page, - MifareUlDevice* mf_ul_read) { - mf_ul_read->pages_read = end_page - start_page + 1; - mf_ul_read->data.data_size = mf_ul_read->pages_read * 4; - memcpy(mf_ul_read->data.data, buff, mf_ul_read->data.data_size); -} +bool mf_ultralight_fast_read_pages( + FuriHalNfcTxRxContext* tx_rx, + MfUltralightReader* reader, + MfUltralightData* data) { + FURI_LOG_D(TAG, "Reading pages 0 - %d", reader->pages_to_read); + tx_rx->tx_data[0] = MF_UL_FAST_READ_CMD; + tx_rx->tx_data[1] = 0; + tx_rx->tx_data[2] = reader->pages_to_read - 1; + tx_rx->tx_bits = 24; + tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault; + if(furi_hal_nfc_tx_rx(tx_rx, 50)) { + reader->pages_read = reader->pages_to_read; + data->data_size = reader->pages_read * 4; + memcpy(data->data, tx_rx->rx_data, data->data_size); + } else { + FURI_LOG_D(TAG, "Failed to read pages 0 - %d", reader->pages_to_read); + } -uint16_t mf_ul_prepare_read_signature(uint8_t* dest) { - dest[0] = MF_UL_READ_SIG; - dest[1] = 0; - return 2; + return reader->pages_read == reader->pages_to_read; } -void mf_ul_parse_read_signature_response(uint8_t* buff, MifareUlDevice* mf_ul_read) { - memcpy(mf_ul_read->data.signature, buff, sizeof(mf_ul_read->data.signature)); -} +bool mf_ultralight_read_signature(FuriHalNfcTxRxContext* tx_rx, MfUltralightData* data) { + bool signature_read = false; -uint16_t mf_ul_prepare_read_cnt(uint8_t* dest, uint8_t cnt_index) { - if(cnt_index > 2) { - return 0; + FURI_LOG_D(TAG, "Reading signature"); + tx_rx->tx_data[0] = MF_UL_READ_SIG; + tx_rx->tx_data[1] = 0; + tx_rx->tx_bits = 16; + tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault; + if(furi_hal_nfc_tx_rx(tx_rx, 50)) { + memcpy(data->signature, tx_rx->rx_data, sizeof(data->signature)); + signature_read = true; + } else { + FURI_LOG_D(TAG, "Failed redaing signature"); } - dest[0] = MF_UL_READ_CNT; - dest[1] = cnt_index; - return 2; -} -void mf_ul_parse_read_cnt_response(uint8_t* buff, uint8_t cnt_index, MifareUlDevice* mf_ul_read) { - // Reverse LSB sequence - if(cnt_index < 3) { - mf_ul_read->data.counter[cnt_index] = (buff[2] << 16) | (buff[1] << 8) | (buff[0]); - } + return signature_read; } -uint16_t mf_ul_prepare_inc_cnt(uint8_t* dest, uint8_t cnt_index, uint32_t value) { - if(cnt_index > 2) { - return 0; - } - dest[0] = MF_UL_INC_CNT; - dest[1] = cnt_index; - dest[2] = (uint8_t)value; - dest[3] = (uint8_t)(value >> 8); - dest[4] = (uint8_t)(value >> 16); - dest[5] = 0; - return 6; -} +bool mf_ultralight_read_counters(FuriHalNfcTxRxContext* tx_rx, MfUltralightData* data) { + uint8_t counter_read = 0; -uint16_t mf_ul_prepare_check_tearing(uint8_t* dest, uint8_t cnt_index) { - if(cnt_index > 2) { - return 0; + FURI_LOG_D(TAG, "Reading counters"); + for(size_t i = 0; i < 3; i++) { + tx_rx->tx_data[0] = MF_UL_READ_CNT; + tx_rx->rx_data[1] = i; + tx_rx->tx_bits = 16; + tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault; + if(!furi_hal_nfc_tx_rx(tx_rx, 50)) { + FURI_LOG_D(TAG, "Failed to read %d counter", i); + break; + } + data->counter[i] = (tx_rx->rx_data[2] << 16) | (tx_rx->rx_data[1] << 8) | + tx_rx->rx_data[0]; + counter_read++; } - dest[0] = MF_UL_CHECK_TEARING; - dest[1] = cnt_index; - return 2; -} -void mf_ul_parse_check_tearing_response( - uint8_t* buff, - uint8_t cnt_index, - MifareUlDevice* mf_ul_read) { - if(cnt_index < 2) { - mf_ul_read->data.tearing[cnt_index] = buff[0]; - } + return counter_read == 2; } -uint16_t mf_ul_prepare_write(uint8_t* dest, uint16_t page_addr, uint32_t data) { - if(page_addr < 2) { - return 0; +bool mf_ultralight_read_tearing_flags(FuriHalNfcTxRxContext* tx_rx, MfUltralightData* data) { + uint8_t flag_read = 0; + + FURI_LOG_D(TAG, "Reading tearing flags"); + for(size_t i = 0; i < 3; i++) { + tx_rx->tx_data[0] = MF_UL_CHECK_TEARING; + tx_rx->rx_data[1] = i; + tx_rx->tx_bits = 16; + tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault; + if(!furi_hal_nfc_tx_rx(tx_rx, 50)) { + FURI_LOG_D(TAG, "Failed to read %d tearing flag", i); + break; + } + data->tearing[i] = tx_rx->rx_data[0]; + flag_read++; } - dest[0] = MF_UL_WRITE; - dest[1] = page_addr; - dest[2] = (uint8_t)(data >> 24); - dest[3] = (uint8_t)(data >> 16); - dest[4] = (uint8_t)(data >> 8); - dest[5] = (uint8_t)data; - return 6; + + return flag_read == 2; } -void mf_ul_prepare_emulation(MifareUlDevice* mf_ul_emulate, MifareUlData* data) { - mf_ul_emulate->data = *data; - mf_ul_emulate->auth_data = NULL; - mf_ul_emulate->data_changed = false; - mf_ul_emulate->comp_write_cmd_started = false; - if(data->version.storage_size == 0) { - mf_ul_emulate->data.type = MfUltralightTypeUnknown; - mf_ul_emulate->support_fast_read = false; - } else if(data->version.storage_size == 0x0B) { - mf_ul_emulate->data.type = MfUltralightTypeUL11; - mf_ul_emulate->support_fast_read = true; - } else if(data->version.storage_size == 0x0E) { - mf_ul_emulate->data.type = MfUltralightTypeUL21; - mf_ul_emulate->support_fast_read = true; - } else if(data->version.storage_size == 0x0F) { - mf_ul_emulate->data.type = MfUltralightTypeNTAG213; - mf_ul_emulate->support_fast_read = true; - } else if(data->version.storage_size == 0x11) { - mf_ul_emulate->data.type = MfUltralightTypeNTAG215; - mf_ul_emulate->support_fast_read = true; - } else if(data->version.storage_size == 0x13) { - mf_ul_emulate->data.type = MfUltralightTypeNTAG216; - mf_ul_emulate->support_fast_read = true; - } +bool mf_ul_read_card( + FuriHalNfcTxRxContext* tx_rx, + MfUltralightReader* reader, + MfUltralightData* data) { + furi_assert(tx_rx); + furi_assert(reader); + furi_assert(data); - if(mf_ul_emulate->data.type >= MfUltralightTypeNTAG213) { - uint16_t pwd_page = (data->data_size / 4) - 2; - mf_ul_emulate->auth_data = (MifareUlAuthData*)&data->data[pwd_page * 4]; + bool card_read = false; + + // Read Mifare Ultralight version + if(mf_ultralight_read_version(tx_rx, reader, data)) { + // Read Signature + mf_ultralight_read_signature(tx_rx, data); + } + // Read data blocks + if(reader->support_fast_read) { + mf_ultralight_read_counters(tx_rx, data); + mf_ultralight_read_tearing_flags(tx_rx, data); } + card_read = mf_ultralight_read_pages(tx_rx, reader, data); + + return card_read; } -void mf_ul_protect_auth_data_on_read_command( +// TODO rework +static void mf_ul_protect_auth_data_on_read_command( uint8_t* tx_buff, uint8_t start_page, uint8_t end_page, - MifareUlDevice* mf_ul_emulate) { - if(mf_ul_emulate->data.type >= MfUltralightTypeNTAG213) { - uint8_t pwd_page = (mf_ul_emulate->data.data_size / 4) - 2; + MfUltralightEmulator* emulator) { + if(emulator->data.type >= MfUltralightTypeNTAG213) { + uint8_t pwd_page = (emulator->data.data_size / 4) - 2; uint8_t pack_page = pwd_page + 1; if((start_page <= pwd_page) && (end_page >= pwd_page)) { memset(&tx_buff[(pwd_page - start_page) * 4], 0, 4); @@ -200,6 +218,31 @@ void mf_ul_protect_auth_data_on_read_command( } } +void mf_ul_prepare_emulation(MfUltralightEmulator* emulator, MfUltralightData* data) { + emulator->data = *data; + emulator->auth_data = NULL; + emulator->data_changed = false; + emulator->comp_write_cmd_started = false; + if(data->type == MfUltralightTypeUnknown) { + emulator->support_fast_read = false; + } else if(data->type == MfUltralightTypeUL11) { + emulator->support_fast_read = true; + } else if(data->type == MfUltralightTypeUL21) { + emulator->support_fast_read = true; + } else if(data->type == MfUltralightTypeNTAG213) { + emulator->support_fast_read = false; + } else if(data->type == MfUltralightTypeNTAG215) { + emulator->support_fast_read = false; + } else if(data->type == MfUltralightTypeNTAG216) { + emulator->support_fast_read = false; + } + + if(data->type >= MfUltralightTypeNTAG213) { + uint16_t pwd_page = (data->data_size / 4) - 2; + emulator->auth_data = (MfUltralightAuth*)&data->data[pwd_page * 4]; + } +} + bool mf_ul_prepare_emulation_response( uint8_t* buff_rx, uint16_t buff_rx_len, @@ -208,30 +251,30 @@ bool mf_ul_prepare_emulation_response( uint32_t* data_type, void* context) { furi_assert(context); - MifareUlDevice* mf_ul_emulate = context; + MfUltralightEmulator* emulator = context; uint8_t cmd = buff_rx[0]; - uint16_t page_num = mf_ul_emulate->data.data_size / 4; + uint16_t page_num = emulator->data.data_size / 4; uint16_t tx_bytes = 0; uint16_t tx_bits = 0; bool command_parsed = false; // Check composite commands - if(mf_ul_emulate->comp_write_cmd_started) { + if(emulator->comp_write_cmd_started) { // Compatibility write is the only one composit command if(buff_rx_len == 16) { - memcpy(&mf_ul_emulate->data.data[mf_ul_emulate->comp_write_page_addr * 4], buff_rx, 4); - mf_ul_emulate->data_changed = true; + memcpy(&emulator->data.data[emulator->comp_write_page_addr * 4], buff_rx, 4); + emulator->data_changed = true; // Send ACK message buff_tx[0] = 0x0A; tx_bits = 4; *data_type = FURI_HAL_NFC_TXRX_RAW; command_parsed = true; } - mf_ul_emulate->comp_write_cmd_started = false; + emulator->comp_write_cmd_started = false; } else if(cmd == MF_UL_GET_VERSION_CMD) { - if(mf_ul_emulate->data.type != MfUltralightTypeUnknown) { - tx_bytes = sizeof(mf_ul_emulate->data.version); - memcpy(buff_tx, &mf_ul_emulate->data.version, tx_bytes); + if(emulator->data.type != MfUltralightTypeUnknown) { + tx_bytes = sizeof(emulator->data.version); + memcpy(buff_tx, &emulator->data.version, tx_bytes); *data_type = FURI_HAL_NFC_TXRX_DEFAULT; command_parsed = true; } @@ -242,28 +285,24 @@ bool mf_ul_prepare_emulation_response( if(start_page + 4 > page_num) { // Handle roll-over mechanism uint8_t end_pages_num = page_num - start_page; - memcpy(buff_tx, &mf_ul_emulate->data.data[start_page * 4], end_pages_num * 4); - memcpy( - &buff_tx[end_pages_num * 4], - mf_ul_emulate->data.data, - (4 - end_pages_num) * 4); + memcpy(buff_tx, &emulator->data.data[start_page * 4], end_pages_num * 4); + memcpy(&buff_tx[end_pages_num * 4], emulator->data.data, (4 - end_pages_num) * 4); } else { - memcpy(buff_tx, &mf_ul_emulate->data.data[start_page * 4], tx_bytes); + memcpy(buff_tx, &emulator->data.data[start_page * 4], tx_bytes); } mf_ul_protect_auth_data_on_read_command( - buff_tx, start_page, (start_page + 4), mf_ul_emulate); + buff_tx, start_page, (start_page + 4), emulator); *data_type = FURI_HAL_NFC_TXRX_DEFAULT; command_parsed = true; } } else if(cmd == MF_UL_FAST_READ_CMD) { - if(mf_ul_emulate->support_fast_read) { + if(emulator->support_fast_read) { uint8_t start_page = buff_rx[1]; uint8_t end_page = buff_rx[2]; if((start_page < page_num) && (end_page < page_num) && (start_page < (end_page + 1))) { tx_bytes = ((end_page + 1) - start_page) * 4; - memcpy(buff_tx, &mf_ul_emulate->data.data[start_page * 4], tx_bytes); - mf_ul_protect_auth_data_on_read_command( - buff_tx, start_page, end_page, mf_ul_emulate); + memcpy(buff_tx, &emulator->data.data[start_page * 4], tx_bytes); + mf_ul_protect_auth_data_on_read_command(buff_tx, start_page, end_page, emulator); *data_type = FURI_HAL_NFC_TXRX_DEFAULT; command_parsed = true; } @@ -271,8 +310,8 @@ bool mf_ul_prepare_emulation_response( } else if(cmd == MF_UL_WRITE) { uint8_t write_page = buff_rx[1]; if((write_page > 1) && (write_page < page_num - 2)) { - memcpy(&mf_ul_emulate->data.data[write_page * 4], &buff_rx[2], 4); - mf_ul_emulate->data_changed = true; + memcpy(&emulator->data.data[write_page * 4], &buff_rx[2], 4); + emulator->data_changed = true; // ACK buff_tx[0] = 0x0A; tx_bits = 4; @@ -282,8 +321,8 @@ bool mf_ul_prepare_emulation_response( } else if(cmd == MF_UL_COMP_WRITE) { uint8_t write_page = buff_rx[1]; if((write_page > 1) && (write_page < page_num - 2)) { - mf_ul_emulate->comp_write_cmd_started = true; - mf_ul_emulate->comp_write_page_addr = write_page; + emulator->comp_write_cmd_started = true; + emulator->comp_write_page_addr = write_page; // ACK buff_tx[0] = 0x0A; tx_bits = 4; @@ -293,9 +332,9 @@ bool mf_ul_prepare_emulation_response( } else if(cmd == MF_UL_READ_CNT) { uint8_t cnt_num = buff_rx[1]; if(cnt_num < 3) { - buff_tx[0] = mf_ul_emulate->data.counter[cnt_num] >> 16; - buff_tx[1] = mf_ul_emulate->data.counter[cnt_num] >> 8; - buff_tx[2] = mf_ul_emulate->data.counter[cnt_num]; + buff_tx[0] = emulator->data.counter[cnt_num] >> 16; + buff_tx[1] = emulator->data.counter[cnt_num] >> 8; + buff_tx[2] = emulator->data.counter[cnt_num]; tx_bytes = 3; *data_type = FURI_HAL_NFC_TXRX_DEFAULT; command_parsed = true; @@ -303,9 +342,9 @@ bool mf_ul_prepare_emulation_response( } else if(cmd == MF_UL_INC_CNT) { uint8_t cnt_num = buff_rx[1]; uint32_t inc = (buff_rx[2] | (buff_rx[3] << 8) | (buff_rx[4] << 16)); - if((cnt_num < 3) && (mf_ul_emulate->data.counter[cnt_num] + inc < 0x00FFFFFF)) { - mf_ul_emulate->data.counter[cnt_num] += inc; - mf_ul_emulate->data_changed = true; + if((cnt_num < 3) && (emulator->data.counter[cnt_num] + inc < 0x00FFFFFF)) { + emulator->data.counter[cnt_num] += inc; + emulator->data_changed = true; // ACK buff_tx[0] = 0x0A; tx_bits = 4; @@ -313,14 +352,14 @@ bool mf_ul_prepare_emulation_response( command_parsed = true; } } else if(cmd == MF_UL_AUTH) { - if(mf_ul_emulate->data.type >= MfUltralightTypeNTAG213) { - if(memcmp(&buff_rx[1], mf_ul_emulate->auth_data->pwd, 4) == 0) { - buff_tx[0] = mf_ul_emulate->auth_data->pack.raw[0]; - buff_tx[1] = mf_ul_emulate->auth_data->pack.raw[1]; + if(emulator->data.type >= MfUltralightTypeNTAG213) { + if(memcmp(&buff_rx[1], emulator->auth_data->pwd, 4) == 0) { + buff_tx[0] = emulator->auth_data->pack.raw[0]; + buff_tx[1] = emulator->auth_data->pack.raw[1]; tx_bytes = 2; *data_type = FURI_HAL_NFC_TXRX_DEFAULT; command_parsed = true; - } else if(!mf_ul_emulate->auth_data->pack.value) { + } else if(!emulator->auth_data->pack.value) { buff_tx[0] = 0x80; buff_tx[1] = 0x80; tx_bytes = 2; @@ -331,15 +370,15 @@ bool mf_ul_prepare_emulation_response( } else if(cmd == MF_UL_READ_SIG) { // Check 2nd byte = 0x00 - RFU if(buff_rx[1] == 0x00) { - tx_bytes = sizeof(mf_ul_emulate->data.signature); - memcpy(buff_tx, mf_ul_emulate->data.signature, tx_bytes); + tx_bytes = sizeof(emulator->data.signature); + memcpy(buff_tx, emulator->data.signature, tx_bytes); *data_type = FURI_HAL_NFC_TXRX_DEFAULT; command_parsed = true; } } else if(cmd == MF_UL_CHECK_TEARING) { uint8_t cnt_num = buff_rx[1]; if(cnt_num < 3) { - buff_tx[0] = mf_ul_emulate->data.tearing[cnt_num]; + buff_tx[0] = emulator->data.tearing[cnt_num]; tx_bytes = 1; *data_type = FURI_HAL_NFC_TXRX_DEFAULT; command_parsed = true; diff --git a/lib/nfc_protocols/mifare_ultralight.h b/lib/nfc_protocols/mifare_ultralight.h index 84447c5decd..b554b75b584 100644 --- a/lib/nfc_protocols/mifare_ultralight.h +++ b/lib/nfc_protocols/mifare_ultralight.h @@ -1,8 +1,6 @@ #pragma once -#include -#include -#include +#include #define MF_UL_MAX_DUMP_SIZE 1024 @@ -62,7 +60,7 @@ typedef struct { uint8_t tearing[3]; uint16_t data_size; uint8_t data[MF_UL_MAX_DUMP_SIZE]; -} MifareUlData; +} MfUltralightData; typedef struct { uint8_t pwd[4]; @@ -70,52 +68,53 @@ typedef struct { uint8_t raw[2]; uint16_t value; } pack; -} MifareUlAuthData; +} MfUltralightAuth; typedef struct { uint8_t pages_to_read; uint8_t pages_read; bool support_fast_read; +} MfUltralightReader; + +typedef struct { + MfUltralightData data; + bool support_fast_read; bool data_changed; - MifareUlData data; - MifareUlAuthData* auth_data; bool comp_write_cmd_started; uint8_t comp_write_page_addr; -} MifareUlDevice; + MfUltralightAuth* auth_data; +} MfUltralightEmulator; bool mf_ul_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK); -uint16_t mf_ul_prepare_get_version(uint8_t* dest); -void mf_ul_parse_get_version_response(uint8_t* buff, MifareUlDevice* mf_ul_read); -void mf_ul_set_default_version(MifareUlDevice* mf_ul_read); +bool mf_ultralight_read_version( + FuriHalNfcTxRxContext* tx_rx, + MfUltralightReader* reader, + MfUltralightData* data); -uint16_t mf_ul_prepare_read_signature(uint8_t* dest); -void mf_ul_parse_read_signature_response(uint8_t* buff, MifareUlDevice* mf_ul_read); +bool mf_ultralight_read_pages( + FuriHalNfcTxRxContext* tx_rx, + MfUltralightReader* reader, + MfUltralightData* data); -uint16_t mf_ul_prepare_read_cnt(uint8_t* dest, uint8_t cnt_index); -void mf_ul_parse_read_cnt_response(uint8_t* buff, uint8_t cnt_index, MifareUlDevice* mf_ul_read); +bool mf_ultralight_fast_read_pages( + FuriHalNfcTxRxContext* tx_rx, + MfUltralightReader* reader, + MfUltralightData* data); -uint16_t mf_ul_prepare_inc_cnt(uint8_t* dest, uint8_t cnt_index, uint32_t value); +bool mf_ultralight_read_signature(FuriHalNfcTxRxContext* tx_rx, MfUltralightData* data); -uint16_t mf_ul_prepare_check_tearing(uint8_t* dest, uint8_t cnt_index); -void mf_ul_parse_check_tearing_response( - uint8_t* buff, - uint8_t cnt_index, - MifareUlDevice* mf_ul_read); +bool mf_ultralight_read_counters(FuriHalNfcTxRxContext* tx_rx, MfUltralightData* data); -uint16_t mf_ul_prepare_read(uint8_t* dest, uint8_t start_page); -void mf_ul_parse_read_response(uint8_t* buff, uint16_t page_addr, MifareUlDevice* mf_ul_read); +bool mf_ultralight_read_tearing_flags(FuriHalNfcTxRxContext* tx_rx, MfUltralightData* data); -uint16_t mf_ul_prepare_fast_read(uint8_t* dest, uint8_t start_page, uint8_t end_page); -void mf_ul_parse_fast_read_response( - uint8_t* buff, - uint8_t start_page, - uint8_t end_page, - MifareUlDevice* mf_ul_read); +bool mf_ul_read_card( + FuriHalNfcTxRxContext* tx_rx, + MfUltralightReader* reader, + MfUltralightData* data); -uint16_t mf_ul_prepare_write(uint8_t* dest, uint16_t page_addr, uint32_t data); +void mf_ul_prepare_emulation(MfUltralightEmulator* emulator, MfUltralightData* data); -void mf_ul_prepare_emulation(MifareUlDevice* mf_ul_emulate, MifareUlData* data); bool mf_ul_prepare_emulation_response( uint8_t* buff_rx, uint16_t buff_rx_len, diff --git a/lib/subghz/protocols/raw.c b/lib/subghz/protocols/raw.c index 0e68a937eaf..111f45366b8 100644 --- a/lib/subghz/protocols/raw.c +++ b/lib/subghz/protocols/raw.c @@ -293,24 +293,19 @@ static bool subghz_protocol_encoder_raw_worker_init(SubGhzProtocolEncoderRAW* in return instance->is_runing; } -void subghz_protocol_raw_gen_fff_data(FlipperFormat* flipper_format, const char* file_name) { - string_t temp_str; - string_init(temp_str); +void subghz_protocol_raw_gen_fff_data(FlipperFormat* flipper_format, const char* file_path) { do { stream_clean(flipper_format_get_raw_stream(flipper_format)); if(!flipper_format_write_string_cstr(flipper_format, "Protocol", "RAW")) { FURI_LOG_E(TAG, "Unable to add Protocol"); break; } - string_printf(temp_str, "%s/%s%s", SUBGHZ_APP_FOLDER, file_name, SUBGHZ_APP_EXTENSION); - if(!flipper_format_write_string_cstr( - flipper_format, "File_name", string_get_cstr(temp_str))) { + if(!flipper_format_write_string_cstr(flipper_format, "File_name", file_path)) { FURI_LOG_E(TAG, "Unable to add File_name"); break; } } while(false); - string_clear(temp_str); } bool subghz_protocol_encoder_raw_deserialize(void* context, FlipperFormat* flipper_format) { diff --git a/lib/subghz/protocols/raw.h b/lib/subghz/protocols/raw.h index febad6f7a4a..9e4931f9acb 100644 --- a/lib/subghz/protocols/raw.h +++ b/lib/subghz/protocols/raw.h @@ -113,9 +113,9 @@ void subghz_protocol_raw_file_encoder_worker_set_callback_end( /** * File generation for RAW work. * @param flipper_format Pointer to a FlipperFormat instance - * @param file_name File name + * @param file_path File path */ -void subghz_protocol_raw_gen_fff_data(FlipperFormat* flipper_format, const char* file_name); +void subghz_protocol_raw_gen_fff_data(FlipperFormat* flipper_format, const char* file_path); /** * Deserialize and generating an upload to send. diff --git a/lib/subghz/subghz_file_encoder_worker.c b/lib/subghz/subghz_file_encoder_worker.c index ca763d70082..91538e1f2ea 100644 --- a/lib/subghz/subghz_file_encoder_worker.c +++ b/lib/subghz/subghz_file_encoder_worker.c @@ -167,7 +167,10 @@ static int32_t subghz_file_encoder_worker_thread(void* context) { } //waiting for the end of the transfer FURI_LOG_I(TAG, "End read file"); - + while(!furi_hal_subghz_is_async_tx_complete() && instance->worker_running) { + osDelay(5); + } + FURI_LOG_I(TAG, "End transmission"); while(instance->worker_running) { if(instance->worker_stoping) { if(instance->callback_end) instance->callback_end(instance->context_end); diff --git a/lib/toolbox/tar/tar_archive.c b/lib/toolbox/tar/tar_archive.c index 7be68bd8f64..e3cc1818ecc 100644 --- a/lib/toolbox/tar/tar_archive.c +++ b/lib/toolbox/tar/tar_archive.c @@ -15,6 +15,8 @@ typedef struct TarArchive { Storage* storage; mtar_t tar; + tar_unpack_file_cb unpack_cb; + void* unpack_cb_context; } TarArchive; /* API WRAPPER */ @@ -51,6 +53,7 @@ TarArchive* tar_archive_alloc(Storage* storage) { furi_check(storage); TarArchive* archive = malloc(sizeof(TarArchive)); archive->storage = storage; + archive->unpack_cb = NULL; return archive; } @@ -92,6 +95,28 @@ void tar_archive_free(TarArchive* archive) { } } +void tar_archive_set_file_callback(TarArchive* archive, tar_unpack_file_cb callback, void* context) { + furi_assert(archive); + archive->unpack_cb = callback; + archive->unpack_cb_context = context; +} + +static int tar_archive_entry_counter(mtar_t* tar, const mtar_header_t* header, void* param) { + UNUSED(tar); + UNUSED(header); + int32_t* counter = param; + (*counter)++; + return 0; +} + +int32_t tar_archive_get_entries_count(TarArchive* archive) { + int32_t counter = 0; + if(mtar_foreach(&archive->tar, tar_archive_entry_counter, &counter) != MTAR_ESUCCESS) { + counter = -1; + } + return counter; +} + bool tar_archive_dir_add_element(TarArchive* archive, const char* dirpath) { furi_assert(archive); return (mtar_write_dir_header(&archive->tar, dirpath) == MTAR_ESUCCESS); @@ -142,14 +167,25 @@ typedef struct { static int archive_extract_foreach_cb(mtar_t* tar, const mtar_header_t* header, void* param) { TarArchiveDirectoryOpParams* op_params = param; + TarArchive* archive = op_params->archive; string_t fname; + bool skip_entry = false; + if(archive->unpack_cb) { + skip_entry = !archive->unpack_cb( + header->name, header->type == MTAR_TDIR, archive->unpack_cb_context); + } + + if(skip_entry) { + FURI_LOG_W(TAG, "filter: skipping entry \"%s\"", header->name); + return 0; + } + if(header->type == MTAR_TDIR) { string_init(fname); path_concat(op_params->work_dir, header->name, fname); - bool create_res = - storage_simply_mkdir(op_params->archive->storage, string_get_cstr(fname)); + bool create_res = storage_simply_mkdir(archive->storage, string_get_cstr(fname)); string_clear(fname); return create_res ? 0 : -1; } @@ -162,7 +198,7 @@ static int archive_extract_foreach_cb(mtar_t* tar, const mtar_header_t* header, string_init(fname); path_concat(op_params->work_dir, header->name, fname); FURI_LOG_I(TAG, "Extracting %d bytes to '%s'", header->size, header->name); - File* out_file = storage_file_alloc(op_params->archive->storage); + File* out_file = storage_file_alloc(archive->storage); uint8_t* readbuf = malloc(FILE_BLOCK_SIZE); bool failed = false; @@ -303,4 +339,4 @@ bool tar_archive_add_dir(TarArchive* archive, const char* fs_full_path, const ch free(name); storage_file_free(directory); return success; -} \ No newline at end of file +} diff --git a/lib/toolbox/tar/tar_archive.h b/lib/toolbox/tar/tar_archive.h index fe3e248ea8c..a8976181fb3 100644 --- a/lib/toolbox/tar/tar_archive.h +++ b/lib/toolbox/tar/tar_archive.h @@ -34,6 +34,13 @@ bool tar_archive_add_file( bool tar_archive_add_dir(TarArchive* archive, const char* fs_full_path, const char* path_prefix); +int32_t tar_archive_get_entries_count(TarArchive* archive); + +/* Optional per-entry callback on unpacking - return false to skip entry */ +typedef bool (*tar_unpack_file_cb)(const char* name, bool is_directory, void* context); + +void tar_archive_set_file_callback(TarArchive* archive, tar_unpack_file_cb callback, void* context); + /* Low-level API */ bool tar_archive_dir_add_element(TarArchive* archive, const char* dirpath); diff --git a/lib/update_util/update_manifest.c b/lib/update_util/update_manifest.c index 2ae52f17746..3d9ec9c398d 100644 --- a/lib/update_util/update_manifest.c +++ b/lib/update_util/update_manifest.c @@ -4,12 +4,24 @@ #include #include +#define MANIFEST_KEY_INFO "Info" +#define MANIFEST_KEY_TARGET "Target" +#define MANIFEST_KEY_LOADER_FILE "Loader" +#define MANIFEST_KEY_LOADER_CRC "Loader CRC" +#define MANIFEST_KEY_DFU_FILE "Firmware" +#define MANIFEST_KEY_RADIO_FILE "Radio" +#define MANIFEST_KEY_RADIO_ADDRESS "Radio address" +#define MANIFEST_KEY_RADIO_VERSION "Radio version" +#define MANIFEST_KEY_RADIO_CRC "Radio CRC" +#define MANIFEST_KEY_ASSETS_FILE "Resources" + UpdateManifest* update_manifest_alloc() { UpdateManifest* update_manifest = malloc(sizeof(UpdateManifest)); string_init(update_manifest->version); string_init(update_manifest->firmware_dfu_image); string_init(update_manifest->radio_image); string_init(update_manifest->staged_loader_file); + string_init(update_manifest->resource_bundle); update_manifest->target = 0; update_manifest->valid = false; return update_manifest; @@ -21,6 +33,7 @@ void update_manifest_free(UpdateManifest* update_manifest) { string_clear(update_manifest->firmware_dfu_image); string_clear(update_manifest->radio_image); string_clear(update_manifest->staged_loader_file); + string_clear(update_manifest->resource_bundle); free(update_manifest); } @@ -36,21 +49,47 @@ static bool string_init(filetype); update_manifest->valid = flipper_format_read_header(flipper_file, filetype, &version) && - flipper_format_read_string(flipper_file, "Info", update_manifest->version) && - flipper_format_read_uint32(flipper_file, "Target", &update_manifest->target, 1) && - flipper_format_read_string(flipper_file, "Loader", update_manifest->staged_loader_file) && + flipper_format_read_string(flipper_file, MANIFEST_KEY_INFO, update_manifest->version) && + flipper_format_read_uint32( + flipper_file, MANIFEST_KEY_TARGET, &update_manifest->target, 1) && + flipper_format_read_string( + flipper_file, MANIFEST_KEY_LOADER_FILE, update_manifest->staged_loader_file) && flipper_format_read_hex( flipper_file, - "Loader CRC", + MANIFEST_KEY_LOADER_CRC, (uint8_t*)&update_manifest->staged_loader_crc, sizeof(uint32_t)); string_clear(filetype); - /* Optional fields - we can have dfu, radio, or both */ - flipper_format_read_string(flipper_file, "Firmware", update_manifest->firmware_dfu_image); - flipper_format_read_string(flipper_file, "Radio", update_manifest->radio_image); - flipper_format_read_hex( - flipper_file, "Radio address", (uint8_t*)&update_manifest->radio_address, sizeof(uint32_t)); + if(update_manifest->valid) { + /* Optional fields - we can have dfu, radio, or both */ + flipper_format_read_string( + flipper_file, MANIFEST_KEY_DFU_FILE, update_manifest->firmware_dfu_image); + flipper_format_read_string( + flipper_file, MANIFEST_KEY_RADIO_FILE, update_manifest->radio_image); + flipper_format_read_hex( + flipper_file, + MANIFEST_KEY_RADIO_ADDRESS, + (uint8_t*)&update_manifest->radio_address, + sizeof(uint32_t)); + flipper_format_read_hex( + flipper_file, + MANIFEST_KEY_RADIO_VERSION, + (uint8_t*)&update_manifest->radio_version, + sizeof(uint32_t)); + flipper_format_read_hex( + flipper_file, + MANIFEST_KEY_RADIO_CRC, + (uint8_t*)&update_manifest->radio_crc, + sizeof(uint32_t)); + flipper_format_read_string( + flipper_file, MANIFEST_KEY_ASSETS_FILE, update_manifest->resource_bundle); + + update_manifest->valid = + (!string_empty_p(update_manifest->firmware_dfu_image) || + !string_empty_p(update_manifest->radio_image) || + !string_empty_p(update_manifest->resource_bundle)); + } return update_manifest->valid; } @@ -83,4 +122,4 @@ bool update_manifest_init_mem( flipper_format_free(flipper_file); return update_manifest->valid; -} +} \ No newline at end of file diff --git a/lib/update_util/update_manifest.h b/lib/update_util/update_manifest.h index 7b60f58a24b..7d4757c4b5c 100644 --- a/lib/update_util/update_manifest.h +++ b/lib/update_util/update_manifest.h @@ -21,6 +21,9 @@ typedef struct { string_t firmware_dfu_image; string_t radio_image; uint32_t radio_address; + uint32_t radio_version; + uint32_t radio_crc; + string_t resource_bundle; bool valid; } UpdateManifest; diff --git a/make/rules.mk b/make/rules.mk index e907b0eb8ea..32e525b64ff 100644 --- a/make/rules.mk +++ b/make/rules.mk @@ -86,7 +86,6 @@ $(OBJ_DIR)/upload: $(OBJ_DIR)/$(PROJECT).bin dfu-util -d 0483:df11 -D $(OBJ_DIR)/$(PROJECT).bin -a 0 -s $(FLASH_ADDRESS) $(DFU_OPTIONS) touch $@ - .PHONY: flash flash: $(OBJ_DIR)/flash diff --git a/scripts/assets.py b/scripts/assets.py index 3d45564609e..bb7b493d6e4 100755 --- a/scripts/assets.py +++ b/scripts/assets.py @@ -203,15 +203,12 @@ def manifest(self): manifest_file = os.path.join(directory_path, "Manifest") old_manifest = Manifest() if os.path.exists(manifest_file): - self.logger.info( - f"old manifest is present, loading for compare and removing file" - ) + self.logger.info("old manifest is present, loading for compare") old_manifest.load(manifest_file) - os.unlink(manifest_file) self.logger.info(f'Creating new Manifest for directory "{directory_path}"') new_manifest = Manifest() new_manifest.create(directory_path) - new_manifest.save(manifest_file) + self.logger.info(f"Comparing new manifest with old") only_in_old, changed, only_in_new = Manifest.compare(old_manifest, new_manifest) for record in only_in_old: @@ -220,6 +217,12 @@ def manifest(self): self.logger.info(f"Changed: {record}") for record in only_in_new: self.logger.info(f"Only in new: {record}") + if any((only_in_old, changed, only_in_new)): + self.logger.warning("Manifests are different, updating") + new_manifest.save(manifest_file) + else: + self.logger.info("Manifest is up-to-date!") + self.logger.info(f"Complete") return 0 diff --git a/scripts/dist.py b/scripts/dist.py index 172ecc01be7..de1a02c8a8e 100755 --- a/scripts/dist.py +++ b/scripts/dist.py @@ -18,6 +18,7 @@ def init(self): self.parser_copy.add_argument("-t", dest="target", required=True) self.parser_copy.add_argument("-p", dest="projects", nargs="+", required=True) self.parser_copy.add_argument("-s", dest="suffix", required=True) + self.parser_copy.add_argument("-r", dest="resources", required=False) self.parser_copy.add_argument( "--bundlever", dest="version", @@ -78,11 +79,18 @@ def copy(self): self.args.version, "-t", self.args.target, - "-dfu", + "--dfu", self.get_dist_filepath(self.get_project_filename("firmware", "dfu")), - "-stage", + "--stage", self.get_dist_filepath(self.get_project_filename("updater", "bin")), ] + if self.args.resources: + bundle_args.extend( + ( + "-r", + self.args.resources, + ) + ) self.logger.info( f"Use this directory to self-update your Flipper:\n\t{bundle_dir}" ) diff --git a/scripts/flash.py b/scripts/flash.py index 170d4311876..cc5c5e1790f 100755 --- a/scripts/flash.py +++ b/scripts/flash.py @@ -8,7 +8,7 @@ from flipper.app import App from flipper.cube import CubeProgrammer -STATEMENT = "AGREE_TO_LOOSE_FLIPPER_FEATURES_THAT_USES_CRYPTO_ENCLAVE" +STATEMENT = "AGREE_TO_LOSE_FLIPPER_FEATURES_THAT_USE_CRYPTO_ENCLAVE" class Main(App): diff --git a/scripts/flipper/assets/manifest.py b/scripts/flipper/assets/manifest.py index c2962e7c392..103f07b6b9f 100644 --- a/scripts/flipper/assets/manifest.py +++ b/scripts/flipper/assets/manifest.py @@ -18,10 +18,10 @@ def fromLine(line): def toLine(self): raise NotImplementedError - def _unpack(self, manifest, key, type): + def _unpack(self, manifest, key, nodetype): key, value = manifest.readline().split(":", 1) assert key == key - return type(value) + return nodetype(value) MANIFEST_TAGS_RECORDS = {} @@ -94,7 +94,7 @@ def __init__(self, path: str, md5: str, size: int): @staticmethod def fromLine(line): data = line.split(":", 3) - return ManifestRecordFile(data[2], data[0], data[1]) + return ManifestRecordFile(data[2], data[0], int(data[1])) def toLine(self): return f"{self.tag}:{self.md5}:{self.size}:{self.path}\n" @@ -133,7 +133,7 @@ def addDirectory(self, path): def addFile(self, path, md5, size): self.records.append(ManifestRecordFile(path, md5, size)) - def create(self, directory_path): + def create(self, directory_path, ignore_files=["Manifest"]): for root, dirs, files in os.walk(directory_path): relative_root = root.replace(directory_path, "", 1) if relative_root.startswith("/"): @@ -141,13 +141,16 @@ def create(self, directory_path): # process directories for dir in dirs: relative_dir_path = os.path.join(relative_root, dir) - self.logger.info(f'Adding directory: "{relative_dir_path}"') + self.logger.debug(f'Adding directory: "{relative_dir_path}"') self.addDirectory(relative_dir_path) # Process files for file in files: relative_file_path = os.path.join(relative_root, file) + if file in ignore_files: + self.logger.info(f'Skipping file "{relative_file_path}"') + continue full_file_path = os.path.join(root, file) - self.logger.info(f'Adding file: "{relative_file_path}"') + self.logger.debug(f'Adding file: "{relative_file_path}"') self.addFile( relative_file_path, file_md5(full_file_path), @@ -155,7 +158,7 @@ def create(self, directory_path): ) def toFsTree(self): - root = FsNode("", FsNode.Type.Directory) + root = FsNode("", FsNode.NodeType.Directory) for record in self.records: if isinstance(record, ManifestRecordDirectory): root.addDirectory(record.path) diff --git a/scripts/flipper/utils/fstree.py b/scripts/flipper/utils/fstree.py index c42b4aa6300..206a1d997fb 100644 --- a/scripts/flipper/utils/fstree.py +++ b/scripts/flipper/utils/fstree.py @@ -3,13 +3,13 @@ class FsNode: - class Type(Enum): + class NodeType(Enum): File = 0 Directory = 1 - def __init__(self, name: str, type: "FsNode.Type", **kwargs): + def __init__(self, name: str, nodetype: "FsNode.Type", **kwargs): self.name = name - self.type = type + self.nodetype = nodetype self.data = kwargs self.parent = None self.children = OrderedDict() @@ -25,7 +25,7 @@ def addDirectory(self, path): parent_node = self.traverse(fragments) if not parent_node: raise Exception(f"No parent node found for: {path}") - parent_node.addChild(FsNode(name, FsNode.Type.Directory)) + parent_node.addChild(FsNode(name, FsNode.NodeType.Directory)) def addFile(self, path, md5, size): fragments = path.split("/") @@ -34,7 +34,7 @@ def addFile(self, path, md5, size): parent_node = self.traverse(fragments) if not parent_node: raise Exception(f"No parent node found for: {path}") - parent_node.addChild(FsNode(name, FsNode.Type.File, md5=md5, size=size)) + parent_node.addChild(FsNode(name, FsNode.NodeType.File, md5=md5, size=size)) def getChild(self, name): return self.children[name] @@ -58,19 +58,37 @@ def getPath(self): def dump(self): ret = {} ret["name"] = (self.name,) - ret["type"] = (self.type,) + ret["type"] = (self.nodetype,) ret["path"] = (self.getPath(),) if len(self.children): ret["children"] = [node.dump() for node in self.children.values()] return ret +def walk_nodes(node: FsNode): + yield node + for child in node.children.values(): + yield from walk_nodes(child) + + +# Returns filenames: [only_in_left], [changed], [only_in_right] def compare_fs_trees(left: FsNode, right: FsNode): # import pprint # pprint.pprint(left.dump()) # pprint.pprint(right.dump()) + left_dict = dict((node.getPath(), node) for node in walk_nodes(left)) + right_dict = dict((node.getPath(), node) for node in walk_nodes(right)) + + left_names = set(left_dict.keys()) + right_names = set(right_dict.keys()) + common_names = left_names.intersection(right_names) - only_in_left = [] - changed = [] - only_in_right = [] - return [], [], [] + return ( + list(left_names - right_names), + list( + name + for name in common_names + if left_dict[name].data != right_dict[name].data + ), + list(right_names - left_names), + ) diff --git a/scripts/update.py b/scripts/update.py index 7e49aad09ad..25ae2733a6c 100755 --- a/scripts/update.py +++ b/scripts/update.py @@ -3,12 +3,20 @@ from flipper.app import App from flipper.utils.fff import FlipperFormatFile from os.path import basename, join, exists -from os import makedirs +import os import shutil import zlib +import tarfile class Main(App): + UPDATE_MANIFEST_NAME = "update.fuf" + + # No compression, plain tar + RESOURCE_TAR_MODE = "w:" + RESOURCE_TAR_FORMAT = tarfile.USTAR_FORMAT + RESOURCE_FILE_NAME = "resources.tar" + def init(self): self.subparsers = self.parser.add_subparsers(help="sub-command help") @@ -20,11 +28,17 @@ def init(self): self.parser_generate.add_argument("-d", dest="directory", required=True) self.parser_generate.add_argument("-v", dest="version", required=True) self.parser_generate.add_argument("-t", dest="target", required=True) - self.parser_generate.add_argument("-dfu", dest="dfu", required=True) - self.parser_generate.add_argument("-stage", dest="stage", required=True) - self.parser_generate.add_argument("-radio", dest="radiobin", required=False) + self.parser_generate.add_argument("--dfu", dest="dfu", required=False) + self.parser_generate.add_argument("-r", dest="resources", required=False) + self.parser_generate.add_argument("--stage", dest="stage", required=True) + self.parser_generate.add_argument( + "--radio", dest="radiobin", default="", required=False + ) self.parser_generate.add_argument( - "-radioaddr", dest="radioaddr", required=False + "--radioaddr", dest="radioaddr", required=False + ) + self.parser_generate.add_argument( + "--radiover", dest="radioversion", required=False ) self.parser_generate.set_defaults(func=self.generate) @@ -32,12 +46,23 @@ def init(self): def generate(self): stage_basename = basename(self.args.stage) dfu_basename = basename(self.args.dfu) + radiobin_basename = basename(self.args.radiobin) + resources_basename = "" if not exists(self.args.directory): - makedirs(self.args.directory) + os.makedirs(self.args.directory) shutil.copyfile(self.args.stage, join(self.args.directory, stage_basename)) shutil.copyfile(self.args.dfu, join(self.args.directory, dfu_basename)) + if radiobin_basename: + shutil.copyfile( + self.args.radiobin, join(self.args.directory, radiobin_basename) + ) + if self.args.resources: + resources_basename = self.RESOURCE_FILE_NAME + self.package_resources( + self.args.resources, join(self.args.directory, resources_basename) + ) file = FlipperFormatFile() file.setHeader("Flipper firmware upgrade configuration", 1) @@ -47,12 +72,24 @@ def generate(self): file.writeComment("little-endian hex!") file.writeKey("Loader CRC", self.int2ffhex(self.crc(self.args.stage))) file.writeKey("Firmware", dfu_basename) - file.writeKey("Radio", self.args.radiobin or "") + file.writeKey("Radio", radiobin_basename or "") file.writeKey("Radio address", self.int2ffhex(self.args.radioaddr or 0)) - file.save("%s/update.fuf" % self.args.directory) + file.writeKey("Radio version", self.int2ffhex(self.args.radioversion or 0)) + if radiobin_basename: + file.writeKey("Radio CRC", self.int2ffhex(self.crc(self.args.radiobin))) + else: + file.writeKey("Radio CRC", self.int2ffhex(0)) + file.writeKey("Resources", resources_basename) + file.save(join(self.args.directory, self.UPDATE_MANIFEST_NAME)) return 0 + def package_resources(self, srcdir: str, dst_name: str): + with tarfile.open( + dst_name, self.RESOURCE_TAR_MODE, format=self.RESOURCE_TAR_FORMAT + ) as tarball: + tarball.add(srcdir, arcname="") + @staticmethod def int2ffhex(value: int): hexstr = "%08X" % value